adapter-types
Advanced tools
+78
-47
@@ -291,2 +291,54 @@ /** | ||
| /** | ||
| * Adapter Factory | ||
| * | ||
| * Factory function for creating CLI adapters from configuration. | ||
| */ | ||
| /** | ||
| * Creates a CLI adapter from configuration | ||
| */ | ||
| declare function createAdapter(config: AdapterFactoryConfig): CLIAdapter; | ||
| /** | ||
| * Adapter Registry | ||
| * | ||
| * Registry for managing CLI adapters. | ||
| */ | ||
| /** | ||
| * Registry of available CLI adapters | ||
| */ | ||
| declare class AdapterRegistry { | ||
| private adapters; | ||
| /** | ||
| * Register an adapter | ||
| */ | ||
| register(adapter: CLIAdapter): void; | ||
| /** | ||
| * Get adapter for type | ||
| */ | ||
| get(adapterType: string): CLIAdapter | undefined; | ||
| /** | ||
| * Check if adapter exists for type | ||
| */ | ||
| has(adapterType: string): boolean; | ||
| /** | ||
| * Unregister an adapter | ||
| */ | ||
| unregister(adapterType: string): boolean; | ||
| /** | ||
| * List all registered adapter types | ||
| */ | ||
| list(): string[]; | ||
| /** | ||
| * Get all adapters | ||
| */ | ||
| all(): CLIAdapter[]; | ||
| /** | ||
| * Clear all adapters | ||
| */ | ||
| clear(): void; | ||
| } | ||
| /** | ||
| * Base CLI Adapter | ||
@@ -338,3 +390,6 @@ * | ||
| /** | ||
| * Default input formatting - just return as-is | ||
| * Default input formatting — strip ANSI escape codes from input text. | ||
| * Newlines are preserved (pty-manager handles them natively). | ||
| * Transport-specific formatting (e.g., tmux newline collapsing) is | ||
| * handled by the transport layer, not the adapter. | ||
| */ | ||
@@ -361,53 +416,29 @@ formatInput(message: string): string; | ||
| /** | ||
| * Adapter Registry | ||
| * Output Sanitizer | ||
| * | ||
| * Registry for managing CLI adapters. | ||
| * Utilities for cleaning terminal output — stripping ANSI escape codes, | ||
| * TUI chrome, box-drawing characters, and other noise that interferes | ||
| * with text processing. | ||
| * | ||
| * Used by both pty-manager and tmux-manager for stall detection, task | ||
| * completion detection, and output capture. Also used by the workflow | ||
| * executor to clean step results before interpolating into subsequent tasks. | ||
| */ | ||
| /** | ||
| * Registry of available CLI adapters | ||
| */ | ||
| declare class AdapterRegistry { | ||
| private adapters; | ||
| /** | ||
| * Register an adapter | ||
| */ | ||
| register(adapter: CLIAdapter): void; | ||
| /** | ||
| * Get adapter for type | ||
| */ | ||
| get(adapterType: string): CLIAdapter | undefined; | ||
| /** | ||
| * Check if adapter exists for type | ||
| */ | ||
| has(adapterType: string): boolean; | ||
| /** | ||
| * Unregister an adapter | ||
| */ | ||
| unregister(adapterType: string): boolean; | ||
| /** | ||
| * List all registered adapter types | ||
| */ | ||
| list(): string[]; | ||
| /** | ||
| * Get all adapters | ||
| */ | ||
| all(): CLIAdapter[]; | ||
| /** | ||
| * Clear all adapters | ||
| */ | ||
| clear(): void; | ||
| interface SanitizeOptions { | ||
| /** Strip ANSI escape codes (SGR, cursor, etc). Default: true */ | ||
| stripAnsi?: boolean; | ||
| /** Strip TUI box-drawing and decorative Unicode. Default: true */ | ||
| stripTuiChrome?: boolean; | ||
| /** Strip OSC/DCS sequences (hyperlinks, window titles). Default: true */ | ||
| stripOsc?: boolean; | ||
| /** Collapse multiple blank lines to at most 2. Default: true */ | ||
| collapseBlankLines?: boolean; | ||
| /** Truncate to last N characters. 0 = no limit. Default: 0 */ | ||
| maxLength?: number; | ||
| } | ||
| /** | ||
| * Adapter Factory | ||
| * | ||
| * Factory function for creating CLI adapters from configuration. | ||
| * Sanitize terminal output for text processing. | ||
| */ | ||
| declare function sanitizeOutput(raw: string, options?: SanitizeOptions): string; | ||
| /** | ||
| * Creates a CLI adapter from configuration | ||
| */ | ||
| declare function createAdapter(config: AdapterFactoryConfig): CLIAdapter; | ||
| export { type AdapterFactoryConfig, AdapterRegistry, type AutoResponseRule, BaseCLIAdapter, type BlockingPromptDetection, type BlockingPromptType, type CLIAdapter, type LoginDetection, type MessageType, type ParsedOutput, type SpawnConfig, type ToolRunningInfo, createAdapter }; | ||
| export { type AdapterFactoryConfig, AdapterRegistry, type AutoResponseRule, BaseCLIAdapter, type BlockingPromptDetection, type BlockingPromptType, type CLIAdapter, type LoginDetection, type MessageType, type ParsedOutput, type SanitizeOptions, type SpawnConfig, type ToolRunningInfo, createAdapter, sanitizeOutput }; |
+78
-47
@@ -291,2 +291,54 @@ /** | ||
| /** | ||
| * Adapter Factory | ||
| * | ||
| * Factory function for creating CLI adapters from configuration. | ||
| */ | ||
| /** | ||
| * Creates a CLI adapter from configuration | ||
| */ | ||
| declare function createAdapter(config: AdapterFactoryConfig): CLIAdapter; | ||
| /** | ||
| * Adapter Registry | ||
| * | ||
| * Registry for managing CLI adapters. | ||
| */ | ||
| /** | ||
| * Registry of available CLI adapters | ||
| */ | ||
| declare class AdapterRegistry { | ||
| private adapters; | ||
| /** | ||
| * Register an adapter | ||
| */ | ||
| register(adapter: CLIAdapter): void; | ||
| /** | ||
| * Get adapter for type | ||
| */ | ||
| get(adapterType: string): CLIAdapter | undefined; | ||
| /** | ||
| * Check if adapter exists for type | ||
| */ | ||
| has(adapterType: string): boolean; | ||
| /** | ||
| * Unregister an adapter | ||
| */ | ||
| unregister(adapterType: string): boolean; | ||
| /** | ||
| * List all registered adapter types | ||
| */ | ||
| list(): string[]; | ||
| /** | ||
| * Get all adapters | ||
| */ | ||
| all(): CLIAdapter[]; | ||
| /** | ||
| * Clear all adapters | ||
| */ | ||
| clear(): void; | ||
| } | ||
| /** | ||
| * Base CLI Adapter | ||
@@ -338,3 +390,6 @@ * | ||
| /** | ||
| * Default input formatting - just return as-is | ||
| * Default input formatting — strip ANSI escape codes from input text. | ||
| * Newlines are preserved (pty-manager handles them natively). | ||
| * Transport-specific formatting (e.g., tmux newline collapsing) is | ||
| * handled by the transport layer, not the adapter. | ||
| */ | ||
@@ -361,53 +416,29 @@ formatInput(message: string): string; | ||
| /** | ||
| * Adapter Registry | ||
| * Output Sanitizer | ||
| * | ||
| * Registry for managing CLI adapters. | ||
| * Utilities for cleaning terminal output — stripping ANSI escape codes, | ||
| * TUI chrome, box-drawing characters, and other noise that interferes | ||
| * with text processing. | ||
| * | ||
| * Used by both pty-manager and tmux-manager for stall detection, task | ||
| * completion detection, and output capture. Also used by the workflow | ||
| * executor to clean step results before interpolating into subsequent tasks. | ||
| */ | ||
| /** | ||
| * Registry of available CLI adapters | ||
| */ | ||
| declare class AdapterRegistry { | ||
| private adapters; | ||
| /** | ||
| * Register an adapter | ||
| */ | ||
| register(adapter: CLIAdapter): void; | ||
| /** | ||
| * Get adapter for type | ||
| */ | ||
| get(adapterType: string): CLIAdapter | undefined; | ||
| /** | ||
| * Check if adapter exists for type | ||
| */ | ||
| has(adapterType: string): boolean; | ||
| /** | ||
| * Unregister an adapter | ||
| */ | ||
| unregister(adapterType: string): boolean; | ||
| /** | ||
| * List all registered adapter types | ||
| */ | ||
| list(): string[]; | ||
| /** | ||
| * Get all adapters | ||
| */ | ||
| all(): CLIAdapter[]; | ||
| /** | ||
| * Clear all adapters | ||
| */ | ||
| clear(): void; | ||
| interface SanitizeOptions { | ||
| /** Strip ANSI escape codes (SGR, cursor, etc). Default: true */ | ||
| stripAnsi?: boolean; | ||
| /** Strip TUI box-drawing and decorative Unicode. Default: true */ | ||
| stripTuiChrome?: boolean; | ||
| /** Strip OSC/DCS sequences (hyperlinks, window titles). Default: true */ | ||
| stripOsc?: boolean; | ||
| /** Collapse multiple blank lines to at most 2. Default: true */ | ||
| collapseBlankLines?: boolean; | ||
| /** Truncate to last N characters. 0 = no limit. Default: 0 */ | ||
| maxLength?: number; | ||
| } | ||
| /** | ||
| * Adapter Factory | ||
| * | ||
| * Factory function for creating CLI adapters from configuration. | ||
| * Sanitize terminal output for text processing. | ||
| */ | ||
| declare function sanitizeOutput(raw: string, options?: SanitizeOptions): string; | ||
| /** | ||
| * Creates a CLI adapter from configuration | ||
| */ | ||
| declare function createAdapter(config: AdapterFactoryConfig): CLIAdapter; | ||
| export { type AdapterFactoryConfig, AdapterRegistry, type AutoResponseRule, BaseCLIAdapter, type BlockingPromptDetection, type BlockingPromptType, type CLIAdapter, type LoginDetection, type MessageType, type ParsedOutput, type SpawnConfig, type ToolRunningInfo, createAdapter }; | ||
| export { type AdapterFactoryConfig, AdapterRegistry, type AutoResponseRule, BaseCLIAdapter, type BlockingPromptDetection, type BlockingPromptType, type CLIAdapter, type LoginDetection, type MessageType, type ParsedOutput, type SanitizeOptions, type SpawnConfig, type ToolRunningInfo, createAdapter, sanitizeOutput }; |
+123
-60
@@ -25,3 +25,4 @@ "use strict"; | ||
| BaseCLIAdapter: () => BaseCLIAdapter, | ||
| createAdapter: () => createAdapter | ||
| createAdapter: () => createAdapter, | ||
| sanitizeOutput: () => sanitizeOutput | ||
| }); | ||
@@ -31,3 +32,3 @@ module.exports = __toCommonJS(index_exports); | ||
| // src/base-adapter.ts | ||
| var import_child_process = require("child_process"); | ||
| var import_node_child_process = require("child_process"); | ||
| var BaseCLIAdapter = class { | ||
@@ -70,3 +71,6 @@ /** | ||
| let stripped = this.stripAnsi(output); | ||
| stripped = stripped.replace(/[│╭╰╮╯─═╌║╔╗╚╝╠╣╦╩╬┌┐└┘├┤┬┴┼●○❯❮▶◀⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏⏺←→↑↓]/g, " "); | ||
| stripped = stripped.replace( | ||
| /[│╭╰╮╯─═╌║╔╗╚╝╠╣╦╩╬┌┐└┘├┤┬┴┼●○❯❮▶◀⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏⏺←→↑↓]/g, | ||
| " " | ||
| ); | ||
| stripped = stripped.replace(/ {2,}/g, " "); | ||
@@ -123,3 +127,5 @@ const loginDetection = this.detectLogin(output); | ||
| } | ||
| if (/\[y\/n\]|\(y\/n\)|\[Y\/n\]|\[y\/N\]|\(Y\)es\/\(N\)o|Yes\/No\??/i.test(stripped)) { | ||
| if (/\[y\/n\]|\(y\/n\)|\[Y\/n\]|\[y\/N\]|\(Y\)es\/\(N\)o|Yes\/No\??/i.test( | ||
| stripped | ||
| )) { | ||
| return { | ||
@@ -146,3 +152,5 @@ detected: true, | ||
| } | ||
| if (/press enter|hit enter|enter to (confirm|continue|proceed)|press return/i.test(stripped)) { | ||
| if (/press enter|hit enter|enter to (confirm|continue|proceed)|press return/i.test( | ||
| stripped | ||
| )) { | ||
| return { | ||
@@ -186,6 +194,9 @@ detected: true, | ||
| /** | ||
| * Default input formatting - just return as-is | ||
| * Default input formatting — strip ANSI escape codes from input text. | ||
| * Newlines are preserved (pty-manager handles them natively). | ||
| * Transport-specific formatting (e.g., tmux newline collapsing) is | ||
| * handled by the transport layer, not the adapter. | ||
| */ | ||
| formatInput(message) { | ||
| return message; | ||
| return message.replace(/\x1b\[[0-9;]*[a-zA-Z]/g, "").replace(/\\u001b\[[0-9;]*[a-zA-Z]/g, "").trim(); | ||
| } | ||
@@ -199,3 +210,3 @@ /** | ||
| try { | ||
| const proc = (0, import_child_process.spawn)(command, ["--version"], { | ||
| const proc = (0, import_node_child_process.spawn)(command, ["--version"], { | ||
| shell: true, | ||
@@ -261,4 +272,10 @@ timeout: 5e3 | ||
| const withSpaces = str.replace(/\x1b\[\d*C/g, " "); | ||
| const withoutOsc = withSpaces.replace(/\x1b\](?:[^\x07\x1b]|\x1b[^\\])*(?:\x07|\x1b\\)/g, ""); | ||
| const withoutDcs = withoutOsc.replace(/\x1bP(?:[^\x1b]|\x1b[^\\])*\x1b\\/g, ""); | ||
| const withoutOsc = withSpaces.replace( | ||
| /\x1b\](?:[^\x07\x1b]|\x1b[^\\])*(?:\x07|\x1b\\)/g, | ||
| "" | ||
| ); | ||
| const withoutDcs = withoutOsc.replace( | ||
| /\x1bP(?:[^\x1b]|\x1b[^\\])*\x1b\\/g, | ||
| "" | ||
| ); | ||
| return withoutDcs.replace(/\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])/g, ""); | ||
@@ -268,49 +285,2 @@ } | ||
| // src/adapter-registry.ts | ||
| var AdapterRegistry = class { | ||
| adapters = /* @__PURE__ */ new Map(); | ||
| /** | ||
| * Register an adapter | ||
| */ | ||
| register(adapter) { | ||
| this.adapters.set(adapter.adapterType, adapter); | ||
| } | ||
| /** | ||
| * Get adapter for type | ||
| */ | ||
| get(adapterType) { | ||
| return this.adapters.get(adapterType); | ||
| } | ||
| /** | ||
| * Check if adapter exists for type | ||
| */ | ||
| has(adapterType) { | ||
| return this.adapters.has(adapterType); | ||
| } | ||
| /** | ||
| * Unregister an adapter | ||
| */ | ||
| unregister(adapterType) { | ||
| return this.adapters.delete(adapterType); | ||
| } | ||
| /** | ||
| * List all registered adapter types | ||
| */ | ||
| list() { | ||
| return Array.from(this.adapters.keys()); | ||
| } | ||
| /** | ||
| * Get all adapters | ||
| */ | ||
| all() { | ||
| return Array.from(this.adapters.values()); | ||
| } | ||
| /** | ||
| * Clear all adapters | ||
| */ | ||
| clear() { | ||
| this.adapters.clear(); | ||
| } | ||
| }; | ||
| // src/adapter-factory.ts | ||
@@ -399,3 +369,5 @@ function createAdapter(config) { | ||
| const stripped = this.stripAnsi(output); | ||
| return this.adapterConfig.readyIndicators.some((pattern) => pattern.test(stripped)); | ||
| return this.adapterConfig.readyIndicators.some( | ||
| (pattern) => pattern.test(stripped) | ||
| ); | ||
| } | ||
@@ -434,5 +406,95 @@ detectExit(output) { | ||
| getPromptPattern() { | ||
| return this.adapterConfig.promptPattern || /[\$#>]\s*$/m; | ||
| return this.adapterConfig.promptPattern || /[$#>]\s*$/m; | ||
| } | ||
| }; | ||
| // src/adapter-registry.ts | ||
| var AdapterRegistry = class { | ||
| adapters = /* @__PURE__ */ new Map(); | ||
| /** | ||
| * Register an adapter | ||
| */ | ||
| register(adapter) { | ||
| this.adapters.set(adapter.adapterType, adapter); | ||
| } | ||
| /** | ||
| * Get adapter for type | ||
| */ | ||
| get(adapterType) { | ||
| return this.adapters.get(adapterType); | ||
| } | ||
| /** | ||
| * Check if adapter exists for type | ||
| */ | ||
| has(adapterType) { | ||
| return this.adapters.has(adapterType); | ||
| } | ||
| /** | ||
| * Unregister an adapter | ||
| */ | ||
| unregister(adapterType) { | ||
| return this.adapters.delete(adapterType); | ||
| } | ||
| /** | ||
| * List all registered adapter types | ||
| */ | ||
| list() { | ||
| return Array.from(this.adapters.keys()); | ||
| } | ||
| /** | ||
| * Get all adapters | ||
| */ | ||
| all() { | ||
| return Array.from(this.adapters.values()); | ||
| } | ||
| /** | ||
| * Clear all adapters | ||
| */ | ||
| clear() { | ||
| this.adapters.clear(); | ||
| } | ||
| }; | ||
| // src/output-sanitizer.ts | ||
| var DEFAULT_OPTIONS = { | ||
| stripAnsi: true, | ||
| stripTuiChrome: true, | ||
| stripOsc: true, | ||
| collapseBlankLines: true, | ||
| maxLength: 0 | ||
| }; | ||
| function sanitizeOutput(raw, options) { | ||
| const opts = { ...DEFAULT_OPTIONS, ...options }; | ||
| let result = raw; | ||
| if (opts.stripOsc) { | ||
| result = result.replace( | ||
| /\x1b\](?:[^\x07\x1b]|\x1b[^\\])*(?:\x07|\x1b\\)/g, | ||
| "" | ||
| ); | ||
| result = result.replace(/\x1bP(?:[^\x1b]|\x1b[^\\])*\x1b\\/g, ""); | ||
| } | ||
| if (opts.stripAnsi) { | ||
| result = result.replace(/\x1b\[\d*[CDABGdEF]/g, " "); | ||
| result = result.replace(/\x1b\[\d*(?:;\d+)?[Hf]/g, " "); | ||
| result = result.replace(/\x1b\[\d*[JK]/g, " "); | ||
| result = result.replace(/\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])/g, ""); | ||
| result = result.replace(/\\u001b\[[0-9;]*[a-zA-Z]/g, ""); | ||
| result = result.replace(/[\x00-\x08\x0b-\x1f\x7f]/g, ""); | ||
| } | ||
| if (opts.stripTuiChrome) { | ||
| result = result.replace( | ||
| /[│╭╰╮╯─═╌║╔╗╚╝╠╣╦╩╬┌┐└┘├┤┬┴┼●○❯❮▶◀⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏⣾⣽⣻⢿⡿⣟⣯⣷✻✶✳✢⏺←→↑↓⬆⬇◆◇▪▫■□▲△▼▽◈⟨⟩⌘⏎⏏⌫⌦⇧⇪⌥▐▛▜▝▘]/g, | ||
| " " | ||
| ); | ||
| result = result.replace(/\xa0/g, " "); | ||
| result = result.replace(/ {2,}/g, " "); | ||
| } | ||
| if (opts.collapseBlankLines) { | ||
| result = result.replace(/\n{3,}/g, "\n\n"); | ||
| } | ||
| if (opts.maxLength > 0 && result.length > opts.maxLength) { | ||
| result = result.slice(-opts.maxLength); | ||
| } | ||
| return result.trim(); | ||
| } | ||
| // Annotate the CommonJS export names for ESM import in node: | ||
@@ -442,4 +504,5 @@ 0 && (module.exports = { | ||
| BaseCLIAdapter, | ||
| createAdapter | ||
| createAdapter, | ||
| sanitizeOutput | ||
| }); | ||
| //# sourceMappingURL=index.js.map |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"sources":["../src/index.ts","../src/base-adapter.ts","../src/adapter-registry.ts","../src/adapter-factory.ts"],"sourcesContent":["/**\n * adapter-types\n *\n * Shared adapter interface, base class, registry, and types\n * for pty-manager, tmux-manager, and coding-agent-adapters.\n */\n\n// Adapter interface and classes\nexport type { CLIAdapter } from './adapter-interface.js';\nexport { BaseCLIAdapter } from './base-adapter.js';\nexport { AdapterRegistry } from './adapter-registry.js';\nexport { createAdapter } from './adapter-factory.js';\n\n// Types\nexport type {\n // Message types\n MessageType,\n\n // Spawn configuration\n SpawnConfig,\n\n // Adapter output types\n ParsedOutput,\n LoginDetection,\n\n // Blocking prompt types\n BlockingPromptType,\n BlockingPromptDetection,\n AutoResponseRule,\n\n // Tool running detection\n ToolRunningInfo,\n\n // Factory types\n AdapterFactoryConfig,\n} from './types.js';\n","/**\n * Base CLI Adapter\n *\n * Abstract base class with common functionality for CLI adapters.\n */\n\nimport { spawn } from 'child_process';\nimport type { CLIAdapter } from './adapter-interface.js';\nimport type {\n SpawnConfig,\n ParsedOutput,\n LoginDetection,\n BlockingPromptDetection,\n AutoResponseRule,\n} from './types.js';\n\n/**\n * Abstract base class for CLI adapters with common functionality\n */\nexport abstract class BaseCLIAdapter implements CLIAdapter {\n abstract readonly adapterType: string;\n abstract readonly displayName: string;\n\n /**\n * Auto-response rules for handling known blocking prompts.\n * Subclasses should override this to add CLI-specific rules.\n */\n readonly autoResponseRules: AutoResponseRule[] = [];\n\n /**\n * Whether this CLI uses TUI menus requiring arrow-key navigation.\n * Defaults to false; coding agent adapters override to true.\n */\n readonly usesTuiMenus: boolean = false;\n\n abstract getCommand(): string;\n abstract getArgs(config: SpawnConfig): string[];\n abstract getEnv(config: SpawnConfig): Record<string, string>;\n abstract detectLogin(output: string): LoginDetection;\n abstract detectReady(output: string): boolean;\n abstract parseOutput(output: string): ParsedOutput | null;\n abstract getPromptPattern(): RegExp;\n\n /**\n * Default exit detection - look for common exit patterns\n */\n detectExit(output: string): { exited: boolean; code?: number; error?: string } {\n if (output.includes('Process exited with code')) {\n const match = output.match(/Process exited with code (\\d+)/);\n return {\n exited: true,\n code: match ? parseInt(match[1], 10) : 1,\n };\n }\n\n if (output.includes('Command not found') || output.includes('command not found')) {\n return {\n exited: true,\n code: 127,\n error: 'Command not found',\n };\n }\n\n return { exited: false };\n }\n\n /**\n * Default blocking prompt detection - looks for common prompt patterns.\n * Subclasses should override for CLI-specific detection.\n */\n detectBlockingPrompt(output: string): BlockingPromptDetection {\n let stripped = this.stripAnsi(output);\n\n // Strip TUI box-drawing/chrome characters so patterns work for ink/React CLIs\n stripped = stripped.replace(/[│╭╰╮╯─═╌║╔╗╚╝╠╣╦╩╬┌┐└┘├┤┬┴┼●○❯❮▶◀⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏⏺←→↑↓]/g, ' ');\n stripped = stripped.replace(/ {2,}/g, ' ');\n\n // Check for login/auth first (highest priority)\n const loginDetection = this.detectLogin(output);\n if (loginDetection.required) {\n return {\n detected: true,\n type: 'login',\n prompt: loginDetection.instructions,\n url: loginDetection.url,\n canAutoRespond: false,\n instructions: loginDetection.instructions,\n };\n }\n\n // Check for common update prompts\n if (/update (available|now|ready)/i.test(stripped) && /\\[y\\/n\\]/i.test(stripped)) {\n return {\n detected: true,\n type: 'update',\n prompt: 'Update available',\n options: ['y', 'n'],\n suggestedResponse: 'n',\n canAutoRespond: true,\n instructions: 'CLI update available - auto-declining to continue',\n };\n }\n\n // Check for terms of service / license acceptance\n if (/accept.*(terms|license|agreement)/i.test(stripped) && /\\[y\\/n\\]/i.test(stripped)) {\n return {\n detected: true,\n type: 'tos',\n prompt: 'Terms/license acceptance required',\n options: ['y', 'n'],\n canAutoRespond: false,\n instructions: 'Please accept the terms of service manually',\n };\n }\n\n // Check for model/version selection\n if (/choose.*model|select.*model|which model/i.test(stripped)) {\n return {\n detected: true,\n type: 'model_select',\n prompt: 'Model selection required',\n canAutoRespond: false,\n instructions: 'Please select a model',\n };\n }\n\n // Check for project/workspace selection\n if (/choose.*(project|workspace)|select.*(project|workspace)/i.test(stripped)) {\n return {\n detected: true,\n type: 'project_select',\n prompt: 'Project/workspace selection required',\n canAutoRespond: false,\n instructions: 'Please select a project or workspace',\n };\n }\n\n // Check for generic y/n prompts\n if (/\\[y\\/n\\]|\\(y\\/n\\)|\\[Y\\/n\\]|\\[y\\/N\\]|\\(Y\\)es\\/\\(N\\)o|Yes\\/No\\??/i.test(stripped)) {\n return {\n detected: true,\n type: 'unknown',\n prompt: stripped.slice(-200),\n options: ['y', 'n'],\n canAutoRespond: false,\n instructions: 'Confirmation prompt detected',\n };\n }\n\n // Check for numbered menu prompts\n if (/^\\s*[›>]?\\s*[1-9]\\.\\s+\\w+/m.test(stripped) && /\\?\\s*$/m.test(stripped)) {\n const optionMatches = stripped.match(/[›>]?\\s*([1-9])\\.\\s+([^\\n]+)/g);\n const options = optionMatches\n ? optionMatches.map((m) => m.replace(/^[›>\\s]*/, '').trim())\n : [];\n\n return {\n detected: true,\n type: 'unknown',\n prompt: stripped.slice(-300),\n options: options.length > 0 ? options : undefined,\n canAutoRespond: false,\n instructions: 'Menu selection prompt detected',\n };\n }\n\n // Check for \"Enter to confirm\" style prompts\n if (/press enter|hit enter|enter to (confirm|continue|proceed)|press return/i.test(stripped)) {\n return {\n detected: true,\n type: 'unknown',\n prompt: stripped.slice(-200),\n suggestedResponse: '\\n',\n canAutoRespond: false,\n instructions: 'Enter/confirm prompt detected',\n };\n }\n\n // Check for trust/permission prompts\n if (/trust|allow|permission|grant access/i.test(stripped) && /\\?\\s*$/m.test(stripped)) {\n return {\n detected: true,\n type: 'permission',\n prompt: stripped.slice(-200),\n canAutoRespond: false,\n instructions: 'Permission/trust prompt detected',\n };\n }\n\n // Fallback: any line ending with ?\n const lines = stripped.split('\\n').filter((l) => l.trim());\n const lastLine = lines[lines.length - 1] || '';\n if (/\\?\\s*$/.test(lastLine) && lastLine.length < 200) {\n return {\n detected: true,\n type: 'unknown',\n prompt: lastLine.trim(),\n canAutoRespond: false,\n instructions: 'Question prompt detected',\n };\n }\n\n return { detected: false };\n }\n\n /**\n * Default task completion detection — delegates to detectReady().\n */\n detectTaskComplete(output: string): boolean {\n return this.detectReady(output);\n }\n\n /**\n * Default input formatting - just return as-is\n */\n formatInput(message: string): string {\n return message;\n }\n\n /**\n * Validate CLI installation by running --version or --help\n */\n async validateInstallation(): Promise<{ installed: boolean; version?: string; error?: string }> {\n return new Promise((resolve) => {\n const command = this.getCommand();\n\n try {\n const proc = spawn(command, ['--version'], {\n shell: true,\n timeout: 5000,\n });\n\n let output = '';\n\n proc.stdout?.on('data', (data) => {\n output += data.toString();\n });\n\n proc.stderr?.on('data', (data) => {\n output += data.toString();\n });\n\n proc.on('close', (code) => {\n if (code === 0) {\n const versionMatch = output.match(/(\\d+\\.\\d+\\.\\d+)/);\n resolve({\n installed: true,\n version: versionMatch ? versionMatch[1] : undefined,\n });\n } else {\n resolve({\n installed: false,\n error: `Command exited with code ${code}`,\n });\n }\n });\n\n proc.on('error', (err) => {\n resolve({\n installed: false,\n error: err.message,\n });\n });\n } catch (err) {\n resolve({\n installed: false,\n error: err instanceof Error ? err.message : 'Unknown error',\n });\n }\n });\n }\n\n /**\n * Helper to check if output contains a question\n */\n protected containsQuestion(output: string): boolean {\n const questionPatterns = [\n /\\?$/m,\n /would you like/i,\n /do you want/i,\n /should I/i,\n /shall I/i,\n /please (choose|select|confirm)/i,\n /\\(y\\/n\\)/i,\n /\\[y\\/N\\]/i,\n /\\[Y\\/n\\]/i,\n ];\n\n return questionPatterns.some((pattern) => pattern.test(output));\n }\n\n /**\n * Helper to strip ANSI escape codes from output\n */\n protected stripAnsi(str: string): string {\n // Replace cursor-forward sequences with spaces before stripping\n const withSpaces = str.replace(/\\x1b\\[\\d*C/g, ' ');\n // Strip OSC sequences\n const withoutOsc = withSpaces.replace(/\\x1b\\](?:[^\\x07\\x1b]|\\x1b[^\\\\])*(?:\\x07|\\x1b\\\\)/g, '');\n // Strip DCS sequences\n const withoutDcs = withoutOsc.replace(/\\x1bP(?:[^\\x1b]|\\x1b[^\\\\])*\\x1b\\\\/g, '');\n // eslint-disable-next-line no-control-regex\n return withoutDcs.replace(/\\x1B(?:[@-Z\\\\-_]|\\[[0-?]*[ -/]*[@-~])/g, '');\n }\n}\n","/**\n * Adapter Registry\n *\n * Registry for managing CLI adapters.\n */\n\nimport type { CLIAdapter } from './adapter-interface.js';\n\n/**\n * Registry of available CLI adapters\n */\nexport class AdapterRegistry {\n private adapters: Map<string, CLIAdapter> = new Map();\n\n /**\n * Register an adapter\n */\n register(adapter: CLIAdapter): void {\n this.adapters.set(adapter.adapterType, adapter);\n }\n\n /**\n * Get adapter for type\n */\n get(adapterType: string): CLIAdapter | undefined {\n return this.adapters.get(adapterType);\n }\n\n /**\n * Check if adapter exists for type\n */\n has(adapterType: string): boolean {\n return this.adapters.has(adapterType);\n }\n\n /**\n * Unregister an adapter\n */\n unregister(adapterType: string): boolean {\n return this.adapters.delete(adapterType);\n }\n\n /**\n * List all registered adapter types\n */\n list(): string[] {\n return Array.from(this.adapters.keys());\n }\n\n /**\n * Get all adapters\n */\n all(): CLIAdapter[] {\n return Array.from(this.adapters.values());\n }\n\n /**\n * Clear all adapters\n */\n clear(): void {\n this.adapters.clear();\n }\n}\n","/**\n * Adapter Factory\n *\n * Factory function for creating CLI adapters from configuration.\n */\n\nimport type { CLIAdapter } from './adapter-interface.js';\nimport { BaseCLIAdapter } from './base-adapter.js';\nimport type {\n SpawnConfig,\n ParsedOutput,\n LoginDetection,\n BlockingPromptDetection,\n AutoResponseRule,\n AdapterFactoryConfig,\n} from './types.js';\n\n/**\n * Creates a CLI adapter from configuration\n */\nexport function createAdapter(config: AdapterFactoryConfig): CLIAdapter {\n return new ConfiguredAdapter(config);\n}\n\n/**\n * Adapter implementation created from configuration\n */\nclass ConfiguredAdapter extends BaseCLIAdapter {\n readonly adapterType: string;\n readonly displayName: string;\n readonly autoResponseRules: AutoResponseRule[];\n\n constructor(private adapterConfig: AdapterFactoryConfig) {\n super();\n this.adapterType = adapterConfig.command.replace(/[^a-zA-Z0-9]/g, '-');\n this.displayName = adapterConfig.command;\n this.autoResponseRules = this.buildAutoResponseRules();\n }\n\n private buildAutoResponseRules(): AutoResponseRule[] {\n if (!this.adapterConfig.blockingPrompts) {\n return [];\n }\n\n return this.adapterConfig.blockingPrompts\n .filter((p) => p.autoResponse !== undefined)\n .map((p) => ({\n pattern: p.pattern,\n type: p.type,\n response: p.autoResponse!,\n description: p.description || `Auto-respond to ${p.type} prompt`,\n safe: p.safe !== false,\n }));\n }\n\n getCommand(): string {\n return this.adapterConfig.command;\n }\n\n getArgs(config: SpawnConfig): string[] {\n if (typeof this.adapterConfig.args === 'function') {\n return this.adapterConfig.args(config);\n }\n return this.adapterConfig.args || [];\n }\n\n getEnv(config: SpawnConfig): Record<string, string> {\n if (typeof this.adapterConfig.env === 'function') {\n return this.adapterConfig.env(config);\n }\n return this.adapterConfig.env || {};\n }\n\n detectLogin(output: string): LoginDetection {\n if (!this.adapterConfig.loginDetection) {\n return { required: false };\n }\n\n const { patterns, extractUrl, extractInstructions } = this.adapterConfig.loginDetection;\n const stripped = this.stripAnsi(output);\n\n for (const pattern of patterns) {\n if (pattern.test(stripped)) {\n return {\n required: true,\n type: 'browser',\n url: extractUrl?.(stripped) || undefined,\n instructions: extractInstructions?.(stripped) || 'Authentication required',\n };\n }\n }\n\n return { required: false };\n }\n\n detectBlockingPrompt(output: string): BlockingPromptDetection {\n // First check config-defined blocking prompts\n if (this.adapterConfig.blockingPrompts) {\n const stripped = this.stripAnsi(output);\n\n for (const prompt of this.adapterConfig.blockingPrompts) {\n if (prompt.pattern.test(stripped)) {\n return {\n detected: true,\n type: prompt.type,\n prompt: stripped.slice(-200),\n suggestedResponse: prompt.autoResponse,\n canAutoRespond: prompt.autoResponse !== undefined && prompt.safe !== false,\n instructions: prompt.description,\n };\n }\n }\n }\n\n // Fall back to base implementation\n return super.detectBlockingPrompt(output);\n }\n\n detectReady(output: string): boolean {\n if (!this.adapterConfig.readyIndicators || this.adapterConfig.readyIndicators.length === 0) {\n // Default: ready after any output\n return output.length > 10;\n }\n\n const stripped = this.stripAnsi(output);\n return this.adapterConfig.readyIndicators.some((pattern) => pattern.test(stripped));\n }\n\n detectExit(output: string): { exited: boolean; code?: number; error?: string } {\n if (this.adapterConfig.exitIndicators) {\n for (const indicator of this.adapterConfig.exitIndicators) {\n const match = output.match(indicator.pattern);\n if (match) {\n const code = indicator.codeExtractor?.(match) ?? 1;\n return { exited: true, code };\n }\n }\n }\n\n // Fall back to base implementation\n return super.detectExit(output);\n }\n\n parseOutput(output: string): ParsedOutput | null {\n if (this.adapterConfig.parseOutput) {\n return this.adapterConfig.parseOutput(output);\n }\n\n // Default parsing\n const cleaned = this.stripAnsi(output).trim();\n if (!cleaned) return null;\n\n return {\n type: 'response',\n content: cleaned,\n isComplete: true,\n isQuestion: this.containsQuestion(cleaned),\n };\n }\n\n formatInput(message: string): string {\n if (this.adapterConfig.formatInput) {\n return this.adapterConfig.formatInput(message);\n }\n return message;\n }\n\n getPromptPattern(): RegExp {\n return this.adapterConfig.promptPattern || /[\\$#>]\\s*$/m;\n }\n}\n"],"mappings":"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","names":[]} | ||
| {"version":3,"sources":["../src/index.ts","../src/base-adapter.ts","../src/adapter-factory.ts","../src/adapter-registry.ts","../src/output-sanitizer.ts"],"sourcesContent":["/**\n * adapter-types\n *\n * Shared adapter interface, base class, registry, and types\n * for pty-manager, tmux-manager, and coding-agent-adapters.\n */\n\nexport { createAdapter } from './adapter-factory.js';\n// Adapter interface and classes\nexport type { CLIAdapter } from './adapter-interface.js';\nexport { AdapterRegistry } from './adapter-registry.js';\nexport { BaseCLIAdapter } from './base-adapter.js';\n\n// Output sanitization\nexport { sanitizeOutput } from './output-sanitizer.js';\nexport type { SanitizeOptions } from './output-sanitizer.js';\n\n// Types\nexport type {\n // Factory types\n AdapterFactoryConfig,\n AutoResponseRule,\n BlockingPromptDetection,\n // Blocking prompt types\n BlockingPromptType,\n LoginDetection,\n // Message types\n MessageType,\n // Adapter output types\n ParsedOutput,\n // Spawn configuration\n SpawnConfig,\n // Tool running detection\n ToolRunningInfo,\n} from './types.js';\n","/**\n * Base CLI Adapter\n *\n * Abstract base class with common functionality for CLI adapters.\n */\n\nimport { spawn } from 'node:child_process';\nimport type { CLIAdapter } from './adapter-interface.js';\nimport type {\n AutoResponseRule,\n BlockingPromptDetection,\n LoginDetection,\n ParsedOutput,\n SpawnConfig,\n} from './types.js';\n\n/**\n * Abstract base class for CLI adapters with common functionality\n */\nexport abstract class BaseCLIAdapter implements CLIAdapter {\n abstract readonly adapterType: string;\n abstract readonly displayName: string;\n\n /**\n * Auto-response rules for handling known blocking prompts.\n * Subclasses should override this to add CLI-specific rules.\n */\n readonly autoResponseRules: AutoResponseRule[] = [];\n\n /**\n * Whether this CLI uses TUI menus requiring arrow-key navigation.\n * Defaults to false; coding agent adapters override to true.\n */\n readonly usesTuiMenus: boolean = false;\n\n abstract getCommand(): string;\n abstract getArgs(config: SpawnConfig): string[];\n abstract getEnv(config: SpawnConfig): Record<string, string>;\n abstract detectLogin(output: string): LoginDetection;\n abstract detectReady(output: string): boolean;\n abstract parseOutput(output: string): ParsedOutput | null;\n abstract getPromptPattern(): RegExp;\n\n /**\n * Default exit detection - look for common exit patterns\n */\n detectExit(output: string): {\n exited: boolean;\n code?: number;\n error?: string;\n } {\n if (output.includes('Process exited with code')) {\n const match = output.match(/Process exited with code (\\d+)/);\n return {\n exited: true,\n code: match ? parseInt(match[1], 10) : 1,\n };\n }\n\n if (\n output.includes('Command not found') ||\n output.includes('command not found')\n ) {\n return {\n exited: true,\n code: 127,\n error: 'Command not found',\n };\n }\n\n return { exited: false };\n }\n\n /**\n * Default blocking prompt detection - looks for common prompt patterns.\n * Subclasses should override for CLI-specific detection.\n */\n detectBlockingPrompt(output: string): BlockingPromptDetection {\n let stripped = this.stripAnsi(output);\n\n // Strip TUI box-drawing/chrome characters so patterns work for ink/React CLIs\n stripped = stripped.replace(\n /[│╭╰╮╯─═╌║╔╗╚╝╠╣╦╩╬┌┐└┘├┤┬┴┼●○❯❮▶◀⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏⏺←→↑↓]/g,\n ' '\n );\n stripped = stripped.replace(/ {2,}/g, ' ');\n\n // Check for login/auth first (highest priority)\n const loginDetection = this.detectLogin(output);\n if (loginDetection.required) {\n return {\n detected: true,\n type: 'login',\n prompt: loginDetection.instructions,\n url: loginDetection.url,\n canAutoRespond: false,\n instructions: loginDetection.instructions,\n };\n }\n\n // Check for common update prompts\n if (\n /update (available|now|ready)/i.test(stripped) &&\n /\\[y\\/n\\]/i.test(stripped)\n ) {\n return {\n detected: true,\n type: 'update',\n prompt: 'Update available',\n options: ['y', 'n'],\n suggestedResponse: 'n',\n canAutoRespond: true,\n instructions: 'CLI update available - auto-declining to continue',\n };\n }\n\n // Check for terms of service / license acceptance\n if (\n /accept.*(terms|license|agreement)/i.test(stripped) &&\n /\\[y\\/n\\]/i.test(stripped)\n ) {\n return {\n detected: true,\n type: 'tos',\n prompt: 'Terms/license acceptance required',\n options: ['y', 'n'],\n canAutoRespond: false,\n instructions: 'Please accept the terms of service manually',\n };\n }\n\n // Check for model/version selection\n if (/choose.*model|select.*model|which model/i.test(stripped)) {\n return {\n detected: true,\n type: 'model_select',\n prompt: 'Model selection required',\n canAutoRespond: false,\n instructions: 'Please select a model',\n };\n }\n\n // Check for project/workspace selection\n if (\n /choose.*(project|workspace)|select.*(project|workspace)/i.test(stripped)\n ) {\n return {\n detected: true,\n type: 'project_select',\n prompt: 'Project/workspace selection required',\n canAutoRespond: false,\n instructions: 'Please select a project or workspace',\n };\n }\n\n // Check for generic y/n prompts\n if (\n /\\[y\\/n\\]|\\(y\\/n\\)|\\[Y\\/n\\]|\\[y\\/N\\]|\\(Y\\)es\\/\\(N\\)o|Yes\\/No\\??/i.test(\n stripped\n )\n ) {\n return {\n detected: true,\n type: 'unknown',\n prompt: stripped.slice(-200),\n options: ['y', 'n'],\n canAutoRespond: false,\n instructions: 'Confirmation prompt detected',\n };\n }\n\n // Check for numbered menu prompts\n if (\n /^\\s*[›>]?\\s*[1-9]\\.\\s+\\w+/m.test(stripped) &&\n /\\?\\s*$/m.test(stripped)\n ) {\n const optionMatches = stripped.match(/[›>]?\\s*([1-9])\\.\\s+([^\\n]+)/g);\n const options = optionMatches\n ? optionMatches.map((m) => m.replace(/^[›>\\s]*/, '').trim())\n : [];\n\n return {\n detected: true,\n type: 'unknown',\n prompt: stripped.slice(-300),\n options: options.length > 0 ? options : undefined,\n canAutoRespond: false,\n instructions: 'Menu selection prompt detected',\n };\n }\n\n // Check for \"Enter to confirm\" style prompts\n if (\n /press enter|hit enter|enter to (confirm|continue|proceed)|press return/i.test(\n stripped\n )\n ) {\n return {\n detected: true,\n type: 'unknown',\n prompt: stripped.slice(-200),\n suggestedResponse: '\\n',\n canAutoRespond: false,\n instructions: 'Enter/confirm prompt detected',\n };\n }\n\n // Check for trust/permission prompts\n if (\n /trust|allow|permission|grant access/i.test(stripped) &&\n /\\?\\s*$/m.test(stripped)\n ) {\n return {\n detected: true,\n type: 'permission',\n prompt: stripped.slice(-200),\n canAutoRespond: false,\n instructions: 'Permission/trust prompt detected',\n };\n }\n\n // Fallback: any line ending with ?\n const lines = stripped.split('\\n').filter((l) => l.trim());\n const lastLine = lines[lines.length - 1] || '';\n if (/\\?\\s*$/.test(lastLine) && lastLine.length < 200) {\n return {\n detected: true,\n type: 'unknown',\n prompt: lastLine.trim(),\n canAutoRespond: false,\n instructions: 'Question prompt detected',\n };\n }\n\n return { detected: false };\n }\n\n /**\n * Default task completion detection — delegates to detectReady().\n */\n detectTaskComplete(output: string): boolean {\n return this.detectReady(output);\n }\n\n /**\n * Default input formatting — strip ANSI escape codes from input text.\n * Newlines are preserved (pty-manager handles them natively).\n * Transport-specific formatting (e.g., tmux newline collapsing) is\n * handled by the transport layer, not the adapter.\n */\n formatInput(message: string): string {\n // eslint-disable-next-line no-control-regex\n return message\n .replace(/\\x1b\\[[0-9;]*[a-zA-Z]/g, '')\n .replace(/\\\\u001b\\[[0-9;]*[a-zA-Z]/g, '')\n .trim();\n }\n\n /**\n * Validate CLI installation by running --version or --help\n */\n async validateInstallation(): Promise<{\n installed: boolean;\n version?: string;\n error?: string;\n }> {\n return new Promise((resolve) => {\n const command = this.getCommand();\n\n try {\n const proc = spawn(command, ['--version'], {\n shell: true,\n timeout: 5000,\n });\n\n let output = '';\n\n proc.stdout?.on('data', (data) => {\n output += data.toString();\n });\n\n proc.stderr?.on('data', (data) => {\n output += data.toString();\n });\n\n proc.on('close', (code) => {\n if (code === 0) {\n const versionMatch = output.match(/(\\d+\\.\\d+\\.\\d+)/);\n resolve({\n installed: true,\n version: versionMatch ? versionMatch[1] : undefined,\n });\n } else {\n resolve({\n installed: false,\n error: `Command exited with code ${code}`,\n });\n }\n });\n\n proc.on('error', (err) => {\n resolve({\n installed: false,\n error: err.message,\n });\n });\n } catch (err) {\n resolve({\n installed: false,\n error: err instanceof Error ? err.message : 'Unknown error',\n });\n }\n });\n }\n\n /**\n * Helper to check if output contains a question\n */\n protected containsQuestion(output: string): boolean {\n const questionPatterns = [\n /\\?$/m,\n /would you like/i,\n /do you want/i,\n /should I/i,\n /shall I/i,\n /please (choose|select|confirm)/i,\n /\\(y\\/n\\)/i,\n /\\[y\\/N\\]/i,\n /\\[Y\\/n\\]/i,\n ];\n\n return questionPatterns.some((pattern) => pattern.test(output));\n }\n\n /**\n * Helper to strip ANSI escape codes from output\n */\n protected stripAnsi(str: string): string {\n // Replace cursor-forward sequences with spaces before stripping\n const withSpaces = str.replace(/\\x1b\\[\\d*C/g, ' ');\n // Strip OSC sequences\n const withoutOsc = withSpaces.replace(\n /\\x1b\\](?:[^\\x07\\x1b]|\\x1b[^\\\\])*(?:\\x07|\\x1b\\\\)/g,\n ''\n );\n // Strip DCS sequences\n const withoutDcs = withoutOsc.replace(\n /\\x1bP(?:[^\\x1b]|\\x1b[^\\\\])*\\x1b\\\\/g,\n ''\n );\n // eslint-disable-next-line no-control-regex\n return withoutDcs.replace(/\\x1B(?:[@-Z\\\\-_]|\\[[0-?]*[ -/]*[@-~])/g, '');\n }\n}\n","/**\n * Adapter Factory\n *\n * Factory function for creating CLI adapters from configuration.\n */\n\nimport type { CLIAdapter } from './adapter-interface.js';\nimport { BaseCLIAdapter } from './base-adapter.js';\nimport type {\n AdapterFactoryConfig,\n AutoResponseRule,\n BlockingPromptDetection,\n LoginDetection,\n ParsedOutput,\n SpawnConfig,\n} from './types.js';\n\n/**\n * Creates a CLI adapter from configuration\n */\nexport function createAdapter(config: AdapterFactoryConfig): CLIAdapter {\n return new ConfiguredAdapter(config);\n}\n\n/**\n * Adapter implementation created from configuration\n */\nclass ConfiguredAdapter extends BaseCLIAdapter {\n readonly adapterType: string;\n readonly displayName: string;\n readonly autoResponseRules: AutoResponseRule[];\n\n constructor(private adapterConfig: AdapterFactoryConfig) {\n super();\n this.adapterType = adapterConfig.command.replace(/[^a-zA-Z0-9]/g, '-');\n this.displayName = adapterConfig.command;\n this.autoResponseRules = this.buildAutoResponseRules();\n }\n\n private buildAutoResponseRules(): AutoResponseRule[] {\n if (!this.adapterConfig.blockingPrompts) {\n return [];\n }\n\n return this.adapterConfig.blockingPrompts\n .filter((p) => p.autoResponse !== undefined)\n .map((p) => ({\n pattern: p.pattern,\n type: p.type,\n response: p.autoResponse!,\n description: p.description || `Auto-respond to ${p.type} prompt`,\n safe: p.safe !== false,\n }));\n }\n\n getCommand(): string {\n return this.adapterConfig.command;\n }\n\n getArgs(config: SpawnConfig): string[] {\n if (typeof this.adapterConfig.args === 'function') {\n return this.adapterConfig.args(config);\n }\n return this.adapterConfig.args || [];\n }\n\n getEnv(config: SpawnConfig): Record<string, string> {\n if (typeof this.adapterConfig.env === 'function') {\n return this.adapterConfig.env(config);\n }\n return this.adapterConfig.env || {};\n }\n\n detectLogin(output: string): LoginDetection {\n if (!this.adapterConfig.loginDetection) {\n return { required: false };\n }\n\n const { patterns, extractUrl, extractInstructions } =\n this.adapterConfig.loginDetection;\n const stripped = this.stripAnsi(output);\n\n for (const pattern of patterns) {\n if (pattern.test(stripped)) {\n return {\n required: true,\n type: 'browser',\n url: extractUrl?.(stripped) || undefined,\n instructions:\n extractInstructions?.(stripped) || 'Authentication required',\n };\n }\n }\n\n return { required: false };\n }\n\n detectBlockingPrompt(output: string): BlockingPromptDetection {\n // First check config-defined blocking prompts\n if (this.adapterConfig.blockingPrompts) {\n const stripped = this.stripAnsi(output);\n\n for (const prompt of this.adapterConfig.blockingPrompts) {\n if (prompt.pattern.test(stripped)) {\n return {\n detected: true,\n type: prompt.type,\n prompt: stripped.slice(-200),\n suggestedResponse: prompt.autoResponse,\n canAutoRespond:\n prompt.autoResponse !== undefined && prompt.safe !== false,\n instructions: prompt.description,\n };\n }\n }\n }\n\n // Fall back to base implementation\n return super.detectBlockingPrompt(output);\n }\n\n detectReady(output: string): boolean {\n if (\n !this.adapterConfig.readyIndicators ||\n this.adapterConfig.readyIndicators.length === 0\n ) {\n // Default: ready after any output\n return output.length > 10;\n }\n\n const stripped = this.stripAnsi(output);\n return this.adapterConfig.readyIndicators.some((pattern) =>\n pattern.test(stripped)\n );\n }\n\n detectExit(output: string): {\n exited: boolean;\n code?: number;\n error?: string;\n } {\n if (this.adapterConfig.exitIndicators) {\n for (const indicator of this.adapterConfig.exitIndicators) {\n const match = output.match(indicator.pattern);\n if (match) {\n const code = indicator.codeExtractor?.(match) ?? 1;\n return { exited: true, code };\n }\n }\n }\n\n // Fall back to base implementation\n return super.detectExit(output);\n }\n\n parseOutput(output: string): ParsedOutput | null {\n if (this.adapterConfig.parseOutput) {\n return this.adapterConfig.parseOutput(output);\n }\n\n // Default parsing\n const cleaned = this.stripAnsi(output).trim();\n if (!cleaned) return null;\n\n return {\n type: 'response',\n content: cleaned,\n isComplete: true,\n isQuestion: this.containsQuestion(cleaned),\n };\n }\n\n formatInput(message: string): string {\n if (this.adapterConfig.formatInput) {\n return this.adapterConfig.formatInput(message);\n }\n return message;\n }\n\n getPromptPattern(): RegExp {\n return this.adapterConfig.promptPattern || /[$#>]\\s*$/m;\n }\n}\n","/**\n * Adapter Registry\n *\n * Registry for managing CLI adapters.\n */\n\nimport type { CLIAdapter } from './adapter-interface.js';\n\n/**\n * Registry of available CLI adapters\n */\nexport class AdapterRegistry {\n private adapters: Map<string, CLIAdapter> = new Map();\n\n /**\n * Register an adapter\n */\n register(adapter: CLIAdapter): void {\n this.adapters.set(adapter.adapterType, adapter);\n }\n\n /**\n * Get adapter for type\n */\n get(adapterType: string): CLIAdapter | undefined {\n return this.adapters.get(adapterType);\n }\n\n /**\n * Check if adapter exists for type\n */\n has(adapterType: string): boolean {\n return this.adapters.has(adapterType);\n }\n\n /**\n * Unregister an adapter\n */\n unregister(adapterType: string): boolean {\n return this.adapters.delete(adapterType);\n }\n\n /**\n * List all registered adapter types\n */\n list(): string[] {\n return Array.from(this.adapters.keys());\n }\n\n /**\n * Get all adapters\n */\n all(): CLIAdapter[] {\n return Array.from(this.adapters.values());\n }\n\n /**\n * Clear all adapters\n */\n clear(): void {\n this.adapters.clear();\n }\n}\n","/**\n * Output Sanitizer\n *\n * Utilities for cleaning terminal output — stripping ANSI escape codes,\n * TUI chrome, box-drawing characters, and other noise that interferes\n * with text processing.\n *\n * Used by both pty-manager and tmux-manager for stall detection, task\n * completion detection, and output capture. Also used by the workflow\n * executor to clean step results before interpolating into subsequent tasks.\n */\n\nexport interface SanitizeOptions {\n /** Strip ANSI escape codes (SGR, cursor, etc). Default: true */\n stripAnsi?: boolean;\n /** Strip TUI box-drawing and decorative Unicode. Default: true */\n stripTuiChrome?: boolean;\n /** Strip OSC/DCS sequences (hyperlinks, window titles). Default: true */\n stripOsc?: boolean;\n /** Collapse multiple blank lines to at most 2. Default: true */\n collapseBlankLines?: boolean;\n /** Truncate to last N characters. 0 = no limit. Default: 0 */\n maxLength?: number;\n}\n\nconst DEFAULT_OPTIONS: Required<SanitizeOptions> = {\n stripAnsi: true,\n stripTuiChrome: true,\n stripOsc: true,\n collapseBlankLines: true,\n maxLength: 0,\n};\n\n/**\n * Sanitize terminal output for text processing.\n */\nexport function sanitizeOutput(\n raw: string,\n options?: SanitizeOptions\n): string {\n const opts = { ...DEFAULT_OPTIONS, ...options };\n let result = raw;\n\n if (opts.stripOsc) {\n // Strip OSC sequences (Operating System Command)\n result = result.replace(\n /\\x1b\\](?:[^\\x07\\x1b]|\\x1b[^\\\\])*(?:\\x07|\\x1b\\\\)/g,\n ''\n );\n // Strip DCS sequences (Device Control String)\n result = result.replace(/\\x1bP(?:[^\\x1b]|\\x1b[^\\\\])*\\x1b\\\\/g, '');\n }\n\n if (opts.stripAnsi) {\n // Replace cursor movement with spaces to preserve word boundaries\n result = result.replace(/\\x1b\\[\\d*[CDABGdEF]/g, ' ');\n result = result.replace(/\\x1b\\[\\d*(?:;\\d+)?[Hf]/g, ' ');\n result = result.replace(/\\x1b\\[\\d*[JK]/g, ' ');\n // Strip remaining ANSI escape sequences\n // eslint-disable-next-line no-control-regex\n result = result.replace(/\\x1B(?:[@-Z\\\\-_]|\\[[0-?]*[ -/]*[@-~])/g, '');\n // Strip JSON-escaped ANSI (from serialized output)\n result = result.replace(/\\\\u001b\\[[0-9;]*[a-zA-Z]/g, '');\n // Strip bare control characters (except tab and newline)\n // eslint-disable-next-line no-control-regex\n result = result.replace(/[\\x00-\\x08\\x0b-\\x1f\\x7f]/g, '');\n }\n\n if (opts.stripTuiChrome) {\n // Strip TUI box-drawing, spinner, and decorative Unicode\n result = result.replace(\n /[│╭╰╮╯─═╌║╔╗╚╝╠╣╦╩╬┌┐└┘├┤┬┴┼●○❯❮▶◀⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏⣾⣽⣻⢿⡿⣟⣯⣷✻✶✳✢⏺←→↑↓⬆⬇◆◇▪▫■□▲△▼▽◈⟨⟩⌘⏎⏏⌫⌦⇧⇪⌥▐▛▜▝▘]/g,\n ' '\n );\n // Normalize non-breaking spaces\n result = result.replace(/\\xa0/g, ' ');\n // Collapse multiple spaces\n result = result.replace(/ {2,}/g, ' ');\n }\n\n if (opts.collapseBlankLines) {\n result = result.replace(/\\n{3,}/g, '\\n\\n');\n }\n\n if (opts.maxLength > 0 && result.length > opts.maxLength) {\n result = result.slice(-opts.maxLength);\n }\n\n return result.trim();\n}\n"],"mappings":"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","names":[]} |
+119
-57
@@ -40,3 +40,6 @@ // src/base-adapter.ts | ||
| let stripped = this.stripAnsi(output); | ||
| stripped = stripped.replace(/[│╭╰╮╯─═╌║╔╗╚╝╠╣╦╩╬┌┐└┘├┤┬┴┼●○❯❮▶◀⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏⏺←→↑↓]/g, " "); | ||
| stripped = stripped.replace( | ||
| /[│╭╰╮╯─═╌║╔╗╚╝╠╣╦╩╬┌┐└┘├┤┬┴┼●○❯❮▶◀⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏⏺←→↑↓]/g, | ||
| " " | ||
| ); | ||
| stripped = stripped.replace(/ {2,}/g, " "); | ||
@@ -93,3 +96,5 @@ const loginDetection = this.detectLogin(output); | ||
| } | ||
| if (/\[y\/n\]|\(y\/n\)|\[Y\/n\]|\[y\/N\]|\(Y\)es\/\(N\)o|Yes\/No\??/i.test(stripped)) { | ||
| if (/\[y\/n\]|\(y\/n\)|\[Y\/n\]|\[y\/N\]|\(Y\)es\/\(N\)o|Yes\/No\??/i.test( | ||
| stripped | ||
| )) { | ||
| return { | ||
@@ -116,3 +121,5 @@ detected: true, | ||
| } | ||
| if (/press enter|hit enter|enter to (confirm|continue|proceed)|press return/i.test(stripped)) { | ||
| if (/press enter|hit enter|enter to (confirm|continue|proceed)|press return/i.test( | ||
| stripped | ||
| )) { | ||
| return { | ||
@@ -156,6 +163,9 @@ detected: true, | ||
| /** | ||
| * Default input formatting - just return as-is | ||
| * Default input formatting — strip ANSI escape codes from input text. | ||
| * Newlines are preserved (pty-manager handles them natively). | ||
| * Transport-specific formatting (e.g., tmux newline collapsing) is | ||
| * handled by the transport layer, not the adapter. | ||
| */ | ||
| formatInput(message) { | ||
| return message; | ||
| return message.replace(/\x1b\[[0-9;]*[a-zA-Z]/g, "").replace(/\\u001b\[[0-9;]*[a-zA-Z]/g, "").trim(); | ||
| } | ||
@@ -230,4 +240,10 @@ /** | ||
| const withSpaces = str.replace(/\x1b\[\d*C/g, " "); | ||
| const withoutOsc = withSpaces.replace(/\x1b\](?:[^\x07\x1b]|\x1b[^\\])*(?:\x07|\x1b\\)/g, ""); | ||
| const withoutDcs = withoutOsc.replace(/\x1bP(?:[^\x1b]|\x1b[^\\])*\x1b\\/g, ""); | ||
| const withoutOsc = withSpaces.replace( | ||
| /\x1b\](?:[^\x07\x1b]|\x1b[^\\])*(?:\x07|\x1b\\)/g, | ||
| "" | ||
| ); | ||
| const withoutDcs = withoutOsc.replace( | ||
| /\x1bP(?:[^\x1b]|\x1b[^\\])*\x1b\\/g, | ||
| "" | ||
| ); | ||
| return withoutDcs.replace(/\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])/g, ""); | ||
@@ -237,49 +253,2 @@ } | ||
| // src/adapter-registry.ts | ||
| var AdapterRegistry = class { | ||
| adapters = /* @__PURE__ */ new Map(); | ||
| /** | ||
| * Register an adapter | ||
| */ | ||
| register(adapter) { | ||
| this.adapters.set(adapter.adapterType, adapter); | ||
| } | ||
| /** | ||
| * Get adapter for type | ||
| */ | ||
| get(adapterType) { | ||
| return this.adapters.get(adapterType); | ||
| } | ||
| /** | ||
| * Check if adapter exists for type | ||
| */ | ||
| has(adapterType) { | ||
| return this.adapters.has(adapterType); | ||
| } | ||
| /** | ||
| * Unregister an adapter | ||
| */ | ||
| unregister(adapterType) { | ||
| return this.adapters.delete(adapterType); | ||
| } | ||
| /** | ||
| * List all registered adapter types | ||
| */ | ||
| list() { | ||
| return Array.from(this.adapters.keys()); | ||
| } | ||
| /** | ||
| * Get all adapters | ||
| */ | ||
| all() { | ||
| return Array.from(this.adapters.values()); | ||
| } | ||
| /** | ||
| * Clear all adapters | ||
| */ | ||
| clear() { | ||
| this.adapters.clear(); | ||
| } | ||
| }; | ||
| // src/adapter-factory.ts | ||
@@ -368,3 +337,5 @@ function createAdapter(config) { | ||
| const stripped = this.stripAnsi(output); | ||
| return this.adapterConfig.readyIndicators.some((pattern) => pattern.test(stripped)); | ||
| return this.adapterConfig.readyIndicators.some( | ||
| (pattern) => pattern.test(stripped) | ||
| ); | ||
| } | ||
@@ -403,10 +374,101 @@ detectExit(output) { | ||
| getPromptPattern() { | ||
| return this.adapterConfig.promptPattern || /[\$#>]\s*$/m; | ||
| return this.adapterConfig.promptPattern || /[$#>]\s*$/m; | ||
| } | ||
| }; | ||
| // src/adapter-registry.ts | ||
| var AdapterRegistry = class { | ||
| adapters = /* @__PURE__ */ new Map(); | ||
| /** | ||
| * Register an adapter | ||
| */ | ||
| register(adapter) { | ||
| this.adapters.set(adapter.adapterType, adapter); | ||
| } | ||
| /** | ||
| * Get adapter for type | ||
| */ | ||
| get(adapterType) { | ||
| return this.adapters.get(adapterType); | ||
| } | ||
| /** | ||
| * Check if adapter exists for type | ||
| */ | ||
| has(adapterType) { | ||
| return this.adapters.has(adapterType); | ||
| } | ||
| /** | ||
| * Unregister an adapter | ||
| */ | ||
| unregister(adapterType) { | ||
| return this.adapters.delete(adapterType); | ||
| } | ||
| /** | ||
| * List all registered adapter types | ||
| */ | ||
| list() { | ||
| return Array.from(this.adapters.keys()); | ||
| } | ||
| /** | ||
| * Get all adapters | ||
| */ | ||
| all() { | ||
| return Array.from(this.adapters.values()); | ||
| } | ||
| /** | ||
| * Clear all adapters | ||
| */ | ||
| clear() { | ||
| this.adapters.clear(); | ||
| } | ||
| }; | ||
| // src/output-sanitizer.ts | ||
| var DEFAULT_OPTIONS = { | ||
| stripAnsi: true, | ||
| stripTuiChrome: true, | ||
| stripOsc: true, | ||
| collapseBlankLines: true, | ||
| maxLength: 0 | ||
| }; | ||
| function sanitizeOutput(raw, options) { | ||
| const opts = { ...DEFAULT_OPTIONS, ...options }; | ||
| let result = raw; | ||
| if (opts.stripOsc) { | ||
| result = result.replace( | ||
| /\x1b\](?:[^\x07\x1b]|\x1b[^\\])*(?:\x07|\x1b\\)/g, | ||
| "" | ||
| ); | ||
| result = result.replace(/\x1bP(?:[^\x1b]|\x1b[^\\])*\x1b\\/g, ""); | ||
| } | ||
| if (opts.stripAnsi) { | ||
| result = result.replace(/\x1b\[\d*[CDABGdEF]/g, " "); | ||
| result = result.replace(/\x1b\[\d*(?:;\d+)?[Hf]/g, " "); | ||
| result = result.replace(/\x1b\[\d*[JK]/g, " "); | ||
| result = result.replace(/\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])/g, ""); | ||
| result = result.replace(/\\u001b\[[0-9;]*[a-zA-Z]/g, ""); | ||
| result = result.replace(/[\x00-\x08\x0b-\x1f\x7f]/g, ""); | ||
| } | ||
| if (opts.stripTuiChrome) { | ||
| result = result.replace( | ||
| /[│╭╰╮╯─═╌║╔╗╚╝╠╣╦╩╬┌┐└┘├┤┬┴┼●○❯❮▶◀⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏⣾⣽⣻⢿⡿⣟⣯⣷✻✶✳✢⏺←→↑↓⬆⬇◆◇▪▫■□▲△▼▽◈⟨⟩⌘⏎⏏⌫⌦⇧⇪⌥▐▛▜▝▘]/g, | ||
| " " | ||
| ); | ||
| result = result.replace(/\xa0/g, " "); | ||
| result = result.replace(/ {2,}/g, " "); | ||
| } | ||
| if (opts.collapseBlankLines) { | ||
| result = result.replace(/\n{3,}/g, "\n\n"); | ||
| } | ||
| if (opts.maxLength > 0 && result.length > opts.maxLength) { | ||
| result = result.slice(-opts.maxLength); | ||
| } | ||
| return result.trim(); | ||
| } | ||
| export { | ||
| AdapterRegistry, | ||
| BaseCLIAdapter, | ||
| createAdapter | ||
| createAdapter, | ||
| sanitizeOutput | ||
| }; | ||
| //# sourceMappingURL=index.mjs.map |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"sources":["../src/base-adapter.ts","../src/adapter-registry.ts","../src/adapter-factory.ts"],"sourcesContent":["/**\n * Base CLI Adapter\n *\n * Abstract base class with common functionality for CLI adapters.\n */\n\nimport { spawn } from 'child_process';\nimport type { CLIAdapter } from './adapter-interface.js';\nimport type {\n SpawnConfig,\n ParsedOutput,\n LoginDetection,\n BlockingPromptDetection,\n AutoResponseRule,\n} from './types.js';\n\n/**\n * Abstract base class for CLI adapters with common functionality\n */\nexport abstract class BaseCLIAdapter implements CLIAdapter {\n abstract readonly adapterType: string;\n abstract readonly displayName: string;\n\n /**\n * Auto-response rules for handling known blocking prompts.\n * Subclasses should override this to add CLI-specific rules.\n */\n readonly autoResponseRules: AutoResponseRule[] = [];\n\n /**\n * Whether this CLI uses TUI menus requiring arrow-key navigation.\n * Defaults to false; coding agent adapters override to true.\n */\n readonly usesTuiMenus: boolean = false;\n\n abstract getCommand(): string;\n abstract getArgs(config: SpawnConfig): string[];\n abstract getEnv(config: SpawnConfig): Record<string, string>;\n abstract detectLogin(output: string): LoginDetection;\n abstract detectReady(output: string): boolean;\n abstract parseOutput(output: string): ParsedOutput | null;\n abstract getPromptPattern(): RegExp;\n\n /**\n * Default exit detection - look for common exit patterns\n */\n detectExit(output: string): { exited: boolean; code?: number; error?: string } {\n if (output.includes('Process exited with code')) {\n const match = output.match(/Process exited with code (\\d+)/);\n return {\n exited: true,\n code: match ? parseInt(match[1], 10) : 1,\n };\n }\n\n if (output.includes('Command not found') || output.includes('command not found')) {\n return {\n exited: true,\n code: 127,\n error: 'Command not found',\n };\n }\n\n return { exited: false };\n }\n\n /**\n * Default blocking prompt detection - looks for common prompt patterns.\n * Subclasses should override for CLI-specific detection.\n */\n detectBlockingPrompt(output: string): BlockingPromptDetection {\n let stripped = this.stripAnsi(output);\n\n // Strip TUI box-drawing/chrome characters so patterns work for ink/React CLIs\n stripped = stripped.replace(/[│╭╰╮╯─═╌║╔╗╚╝╠╣╦╩╬┌┐└┘├┤┬┴┼●○❯❮▶◀⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏⏺←→↑↓]/g, ' ');\n stripped = stripped.replace(/ {2,}/g, ' ');\n\n // Check for login/auth first (highest priority)\n const loginDetection = this.detectLogin(output);\n if (loginDetection.required) {\n return {\n detected: true,\n type: 'login',\n prompt: loginDetection.instructions,\n url: loginDetection.url,\n canAutoRespond: false,\n instructions: loginDetection.instructions,\n };\n }\n\n // Check for common update prompts\n if (/update (available|now|ready)/i.test(stripped) && /\\[y\\/n\\]/i.test(stripped)) {\n return {\n detected: true,\n type: 'update',\n prompt: 'Update available',\n options: ['y', 'n'],\n suggestedResponse: 'n',\n canAutoRespond: true,\n instructions: 'CLI update available - auto-declining to continue',\n };\n }\n\n // Check for terms of service / license acceptance\n if (/accept.*(terms|license|agreement)/i.test(stripped) && /\\[y\\/n\\]/i.test(stripped)) {\n return {\n detected: true,\n type: 'tos',\n prompt: 'Terms/license acceptance required',\n options: ['y', 'n'],\n canAutoRespond: false,\n instructions: 'Please accept the terms of service manually',\n };\n }\n\n // Check for model/version selection\n if (/choose.*model|select.*model|which model/i.test(stripped)) {\n return {\n detected: true,\n type: 'model_select',\n prompt: 'Model selection required',\n canAutoRespond: false,\n instructions: 'Please select a model',\n };\n }\n\n // Check for project/workspace selection\n if (/choose.*(project|workspace)|select.*(project|workspace)/i.test(stripped)) {\n return {\n detected: true,\n type: 'project_select',\n prompt: 'Project/workspace selection required',\n canAutoRespond: false,\n instructions: 'Please select a project or workspace',\n };\n }\n\n // Check for generic y/n prompts\n if (/\\[y\\/n\\]|\\(y\\/n\\)|\\[Y\\/n\\]|\\[y\\/N\\]|\\(Y\\)es\\/\\(N\\)o|Yes\\/No\\??/i.test(stripped)) {\n return {\n detected: true,\n type: 'unknown',\n prompt: stripped.slice(-200),\n options: ['y', 'n'],\n canAutoRespond: false,\n instructions: 'Confirmation prompt detected',\n };\n }\n\n // Check for numbered menu prompts\n if (/^\\s*[›>]?\\s*[1-9]\\.\\s+\\w+/m.test(stripped) && /\\?\\s*$/m.test(stripped)) {\n const optionMatches = stripped.match(/[›>]?\\s*([1-9])\\.\\s+([^\\n]+)/g);\n const options = optionMatches\n ? optionMatches.map((m) => m.replace(/^[›>\\s]*/, '').trim())\n : [];\n\n return {\n detected: true,\n type: 'unknown',\n prompt: stripped.slice(-300),\n options: options.length > 0 ? options : undefined,\n canAutoRespond: false,\n instructions: 'Menu selection prompt detected',\n };\n }\n\n // Check for \"Enter to confirm\" style prompts\n if (/press enter|hit enter|enter to (confirm|continue|proceed)|press return/i.test(stripped)) {\n return {\n detected: true,\n type: 'unknown',\n prompt: stripped.slice(-200),\n suggestedResponse: '\\n',\n canAutoRespond: false,\n instructions: 'Enter/confirm prompt detected',\n };\n }\n\n // Check for trust/permission prompts\n if (/trust|allow|permission|grant access/i.test(stripped) && /\\?\\s*$/m.test(stripped)) {\n return {\n detected: true,\n type: 'permission',\n prompt: stripped.slice(-200),\n canAutoRespond: false,\n instructions: 'Permission/trust prompt detected',\n };\n }\n\n // Fallback: any line ending with ?\n const lines = stripped.split('\\n').filter((l) => l.trim());\n const lastLine = lines[lines.length - 1] || '';\n if (/\\?\\s*$/.test(lastLine) && lastLine.length < 200) {\n return {\n detected: true,\n type: 'unknown',\n prompt: lastLine.trim(),\n canAutoRespond: false,\n instructions: 'Question prompt detected',\n };\n }\n\n return { detected: false };\n }\n\n /**\n * Default task completion detection — delegates to detectReady().\n */\n detectTaskComplete(output: string): boolean {\n return this.detectReady(output);\n }\n\n /**\n * Default input formatting - just return as-is\n */\n formatInput(message: string): string {\n return message;\n }\n\n /**\n * Validate CLI installation by running --version or --help\n */\n async validateInstallation(): Promise<{ installed: boolean; version?: string; error?: string }> {\n return new Promise((resolve) => {\n const command = this.getCommand();\n\n try {\n const proc = spawn(command, ['--version'], {\n shell: true,\n timeout: 5000,\n });\n\n let output = '';\n\n proc.stdout?.on('data', (data) => {\n output += data.toString();\n });\n\n proc.stderr?.on('data', (data) => {\n output += data.toString();\n });\n\n proc.on('close', (code) => {\n if (code === 0) {\n const versionMatch = output.match(/(\\d+\\.\\d+\\.\\d+)/);\n resolve({\n installed: true,\n version: versionMatch ? versionMatch[1] : undefined,\n });\n } else {\n resolve({\n installed: false,\n error: `Command exited with code ${code}`,\n });\n }\n });\n\n proc.on('error', (err) => {\n resolve({\n installed: false,\n error: err.message,\n });\n });\n } catch (err) {\n resolve({\n installed: false,\n error: err instanceof Error ? err.message : 'Unknown error',\n });\n }\n });\n }\n\n /**\n * Helper to check if output contains a question\n */\n protected containsQuestion(output: string): boolean {\n const questionPatterns = [\n /\\?$/m,\n /would you like/i,\n /do you want/i,\n /should I/i,\n /shall I/i,\n /please (choose|select|confirm)/i,\n /\\(y\\/n\\)/i,\n /\\[y\\/N\\]/i,\n /\\[Y\\/n\\]/i,\n ];\n\n return questionPatterns.some((pattern) => pattern.test(output));\n }\n\n /**\n * Helper to strip ANSI escape codes from output\n */\n protected stripAnsi(str: string): string {\n // Replace cursor-forward sequences with spaces before stripping\n const withSpaces = str.replace(/\\x1b\\[\\d*C/g, ' ');\n // Strip OSC sequences\n const withoutOsc = withSpaces.replace(/\\x1b\\](?:[^\\x07\\x1b]|\\x1b[^\\\\])*(?:\\x07|\\x1b\\\\)/g, '');\n // Strip DCS sequences\n const withoutDcs = withoutOsc.replace(/\\x1bP(?:[^\\x1b]|\\x1b[^\\\\])*\\x1b\\\\/g, '');\n // eslint-disable-next-line no-control-regex\n return withoutDcs.replace(/\\x1B(?:[@-Z\\\\-_]|\\[[0-?]*[ -/]*[@-~])/g, '');\n }\n}\n","/**\n * Adapter Registry\n *\n * Registry for managing CLI adapters.\n */\n\nimport type { CLIAdapter } from './adapter-interface.js';\n\n/**\n * Registry of available CLI adapters\n */\nexport class AdapterRegistry {\n private adapters: Map<string, CLIAdapter> = new Map();\n\n /**\n * Register an adapter\n */\n register(adapter: CLIAdapter): void {\n this.adapters.set(adapter.adapterType, adapter);\n }\n\n /**\n * Get adapter for type\n */\n get(adapterType: string): CLIAdapter | undefined {\n return this.adapters.get(adapterType);\n }\n\n /**\n * Check if adapter exists for type\n */\n has(adapterType: string): boolean {\n return this.adapters.has(adapterType);\n }\n\n /**\n * Unregister an adapter\n */\n unregister(adapterType: string): boolean {\n return this.adapters.delete(adapterType);\n }\n\n /**\n * List all registered adapter types\n */\n list(): string[] {\n return Array.from(this.adapters.keys());\n }\n\n /**\n * Get all adapters\n */\n all(): CLIAdapter[] {\n return Array.from(this.adapters.values());\n }\n\n /**\n * Clear all adapters\n */\n clear(): void {\n this.adapters.clear();\n }\n}\n","/**\n * Adapter Factory\n *\n * Factory function for creating CLI adapters from configuration.\n */\n\nimport type { CLIAdapter } from './adapter-interface.js';\nimport { BaseCLIAdapter } from './base-adapter.js';\nimport type {\n SpawnConfig,\n ParsedOutput,\n LoginDetection,\n BlockingPromptDetection,\n AutoResponseRule,\n AdapterFactoryConfig,\n} from './types.js';\n\n/**\n * Creates a CLI adapter from configuration\n */\nexport function createAdapter(config: AdapterFactoryConfig): CLIAdapter {\n return new ConfiguredAdapter(config);\n}\n\n/**\n * Adapter implementation created from configuration\n */\nclass ConfiguredAdapter extends BaseCLIAdapter {\n readonly adapterType: string;\n readonly displayName: string;\n readonly autoResponseRules: AutoResponseRule[];\n\n constructor(private adapterConfig: AdapterFactoryConfig) {\n super();\n this.adapterType = adapterConfig.command.replace(/[^a-zA-Z0-9]/g, '-');\n this.displayName = adapterConfig.command;\n this.autoResponseRules = this.buildAutoResponseRules();\n }\n\n private buildAutoResponseRules(): AutoResponseRule[] {\n if (!this.adapterConfig.blockingPrompts) {\n return [];\n }\n\n return this.adapterConfig.blockingPrompts\n .filter((p) => p.autoResponse !== undefined)\n .map((p) => ({\n pattern: p.pattern,\n type: p.type,\n response: p.autoResponse!,\n description: p.description || `Auto-respond to ${p.type} prompt`,\n safe: p.safe !== false,\n }));\n }\n\n getCommand(): string {\n return this.adapterConfig.command;\n }\n\n getArgs(config: SpawnConfig): string[] {\n if (typeof this.adapterConfig.args === 'function') {\n return this.adapterConfig.args(config);\n }\n return this.adapterConfig.args || [];\n }\n\n getEnv(config: SpawnConfig): Record<string, string> {\n if (typeof this.adapterConfig.env === 'function') {\n return this.adapterConfig.env(config);\n }\n return this.adapterConfig.env || {};\n }\n\n detectLogin(output: string): LoginDetection {\n if (!this.adapterConfig.loginDetection) {\n return { required: false };\n }\n\n const { patterns, extractUrl, extractInstructions } = this.adapterConfig.loginDetection;\n const stripped = this.stripAnsi(output);\n\n for (const pattern of patterns) {\n if (pattern.test(stripped)) {\n return {\n required: true,\n type: 'browser',\n url: extractUrl?.(stripped) || undefined,\n instructions: extractInstructions?.(stripped) || 'Authentication required',\n };\n }\n }\n\n return { required: false };\n }\n\n detectBlockingPrompt(output: string): BlockingPromptDetection {\n // First check config-defined blocking prompts\n if (this.adapterConfig.blockingPrompts) {\n const stripped = this.stripAnsi(output);\n\n for (const prompt of this.adapterConfig.blockingPrompts) {\n if (prompt.pattern.test(stripped)) {\n return {\n detected: true,\n type: prompt.type,\n prompt: stripped.slice(-200),\n suggestedResponse: prompt.autoResponse,\n canAutoRespond: prompt.autoResponse !== undefined && prompt.safe !== false,\n instructions: prompt.description,\n };\n }\n }\n }\n\n // Fall back to base implementation\n return super.detectBlockingPrompt(output);\n }\n\n detectReady(output: string): boolean {\n if (!this.adapterConfig.readyIndicators || this.adapterConfig.readyIndicators.length === 0) {\n // Default: ready after any output\n return output.length > 10;\n }\n\n const stripped = this.stripAnsi(output);\n return this.adapterConfig.readyIndicators.some((pattern) => pattern.test(stripped));\n }\n\n detectExit(output: string): { exited: boolean; code?: number; error?: string } {\n if (this.adapterConfig.exitIndicators) {\n for (const indicator of this.adapterConfig.exitIndicators) {\n const match = output.match(indicator.pattern);\n if (match) {\n const code = indicator.codeExtractor?.(match) ?? 1;\n return { exited: true, code };\n }\n }\n }\n\n // Fall back to base implementation\n return super.detectExit(output);\n }\n\n parseOutput(output: string): ParsedOutput | null {\n if (this.adapterConfig.parseOutput) {\n return this.adapterConfig.parseOutput(output);\n }\n\n // Default parsing\n const cleaned = this.stripAnsi(output).trim();\n if (!cleaned) return null;\n\n return {\n type: 'response',\n content: cleaned,\n isComplete: true,\n isQuestion: this.containsQuestion(cleaned),\n };\n }\n\n formatInput(message: string): string {\n if (this.adapterConfig.formatInput) {\n return this.adapterConfig.formatInput(message);\n }\n return message;\n }\n\n getPromptPattern(): RegExp {\n return this.adapterConfig.promptPattern || /[\\$#>]\\s*$/m;\n }\n}\n"],"mappings":"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","names":[]} | ||
| {"version":3,"sources":["../src/base-adapter.ts","../src/adapter-factory.ts","../src/adapter-registry.ts","../src/output-sanitizer.ts"],"sourcesContent":["/**\n * Base CLI Adapter\n *\n * Abstract base class with common functionality for CLI adapters.\n */\n\nimport { spawn } from 'node:child_process';\nimport type { CLIAdapter } from './adapter-interface.js';\nimport type {\n AutoResponseRule,\n BlockingPromptDetection,\n LoginDetection,\n ParsedOutput,\n SpawnConfig,\n} from './types.js';\n\n/**\n * Abstract base class for CLI adapters with common functionality\n */\nexport abstract class BaseCLIAdapter implements CLIAdapter {\n abstract readonly adapterType: string;\n abstract readonly displayName: string;\n\n /**\n * Auto-response rules for handling known blocking prompts.\n * Subclasses should override this to add CLI-specific rules.\n */\n readonly autoResponseRules: AutoResponseRule[] = [];\n\n /**\n * Whether this CLI uses TUI menus requiring arrow-key navigation.\n * Defaults to false; coding agent adapters override to true.\n */\n readonly usesTuiMenus: boolean = false;\n\n abstract getCommand(): string;\n abstract getArgs(config: SpawnConfig): string[];\n abstract getEnv(config: SpawnConfig): Record<string, string>;\n abstract detectLogin(output: string): LoginDetection;\n abstract detectReady(output: string): boolean;\n abstract parseOutput(output: string): ParsedOutput | null;\n abstract getPromptPattern(): RegExp;\n\n /**\n * Default exit detection - look for common exit patterns\n */\n detectExit(output: string): {\n exited: boolean;\n code?: number;\n error?: string;\n } {\n if (output.includes('Process exited with code')) {\n const match = output.match(/Process exited with code (\\d+)/);\n return {\n exited: true,\n code: match ? parseInt(match[1], 10) : 1,\n };\n }\n\n if (\n output.includes('Command not found') ||\n output.includes('command not found')\n ) {\n return {\n exited: true,\n code: 127,\n error: 'Command not found',\n };\n }\n\n return { exited: false };\n }\n\n /**\n * Default blocking prompt detection - looks for common prompt patterns.\n * Subclasses should override for CLI-specific detection.\n */\n detectBlockingPrompt(output: string): BlockingPromptDetection {\n let stripped = this.stripAnsi(output);\n\n // Strip TUI box-drawing/chrome characters so patterns work for ink/React CLIs\n stripped = stripped.replace(\n /[│╭╰╮╯─═╌║╔╗╚╝╠╣╦╩╬┌┐└┘├┤┬┴┼●○❯❮▶◀⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏⏺←→↑↓]/g,\n ' '\n );\n stripped = stripped.replace(/ {2,}/g, ' ');\n\n // Check for login/auth first (highest priority)\n const loginDetection = this.detectLogin(output);\n if (loginDetection.required) {\n return {\n detected: true,\n type: 'login',\n prompt: loginDetection.instructions,\n url: loginDetection.url,\n canAutoRespond: false,\n instructions: loginDetection.instructions,\n };\n }\n\n // Check for common update prompts\n if (\n /update (available|now|ready)/i.test(stripped) &&\n /\\[y\\/n\\]/i.test(stripped)\n ) {\n return {\n detected: true,\n type: 'update',\n prompt: 'Update available',\n options: ['y', 'n'],\n suggestedResponse: 'n',\n canAutoRespond: true,\n instructions: 'CLI update available - auto-declining to continue',\n };\n }\n\n // Check for terms of service / license acceptance\n if (\n /accept.*(terms|license|agreement)/i.test(stripped) &&\n /\\[y\\/n\\]/i.test(stripped)\n ) {\n return {\n detected: true,\n type: 'tos',\n prompt: 'Terms/license acceptance required',\n options: ['y', 'n'],\n canAutoRespond: false,\n instructions: 'Please accept the terms of service manually',\n };\n }\n\n // Check for model/version selection\n if (/choose.*model|select.*model|which model/i.test(stripped)) {\n return {\n detected: true,\n type: 'model_select',\n prompt: 'Model selection required',\n canAutoRespond: false,\n instructions: 'Please select a model',\n };\n }\n\n // Check for project/workspace selection\n if (\n /choose.*(project|workspace)|select.*(project|workspace)/i.test(stripped)\n ) {\n return {\n detected: true,\n type: 'project_select',\n prompt: 'Project/workspace selection required',\n canAutoRespond: false,\n instructions: 'Please select a project or workspace',\n };\n }\n\n // Check for generic y/n prompts\n if (\n /\\[y\\/n\\]|\\(y\\/n\\)|\\[Y\\/n\\]|\\[y\\/N\\]|\\(Y\\)es\\/\\(N\\)o|Yes\\/No\\??/i.test(\n stripped\n )\n ) {\n return {\n detected: true,\n type: 'unknown',\n prompt: stripped.slice(-200),\n options: ['y', 'n'],\n canAutoRespond: false,\n instructions: 'Confirmation prompt detected',\n };\n }\n\n // Check for numbered menu prompts\n if (\n /^\\s*[›>]?\\s*[1-9]\\.\\s+\\w+/m.test(stripped) &&\n /\\?\\s*$/m.test(stripped)\n ) {\n const optionMatches = stripped.match(/[›>]?\\s*([1-9])\\.\\s+([^\\n]+)/g);\n const options = optionMatches\n ? optionMatches.map((m) => m.replace(/^[›>\\s]*/, '').trim())\n : [];\n\n return {\n detected: true,\n type: 'unknown',\n prompt: stripped.slice(-300),\n options: options.length > 0 ? options : undefined,\n canAutoRespond: false,\n instructions: 'Menu selection prompt detected',\n };\n }\n\n // Check for \"Enter to confirm\" style prompts\n if (\n /press enter|hit enter|enter to (confirm|continue|proceed)|press return/i.test(\n stripped\n )\n ) {\n return {\n detected: true,\n type: 'unknown',\n prompt: stripped.slice(-200),\n suggestedResponse: '\\n',\n canAutoRespond: false,\n instructions: 'Enter/confirm prompt detected',\n };\n }\n\n // Check for trust/permission prompts\n if (\n /trust|allow|permission|grant access/i.test(stripped) &&\n /\\?\\s*$/m.test(stripped)\n ) {\n return {\n detected: true,\n type: 'permission',\n prompt: stripped.slice(-200),\n canAutoRespond: false,\n instructions: 'Permission/trust prompt detected',\n };\n }\n\n // Fallback: any line ending with ?\n const lines = stripped.split('\\n').filter((l) => l.trim());\n const lastLine = lines[lines.length - 1] || '';\n if (/\\?\\s*$/.test(lastLine) && lastLine.length < 200) {\n return {\n detected: true,\n type: 'unknown',\n prompt: lastLine.trim(),\n canAutoRespond: false,\n instructions: 'Question prompt detected',\n };\n }\n\n return { detected: false };\n }\n\n /**\n * Default task completion detection — delegates to detectReady().\n */\n detectTaskComplete(output: string): boolean {\n return this.detectReady(output);\n }\n\n /**\n * Default input formatting — strip ANSI escape codes from input text.\n * Newlines are preserved (pty-manager handles them natively).\n * Transport-specific formatting (e.g., tmux newline collapsing) is\n * handled by the transport layer, not the adapter.\n */\n formatInput(message: string): string {\n // eslint-disable-next-line no-control-regex\n return message\n .replace(/\\x1b\\[[0-9;]*[a-zA-Z]/g, '')\n .replace(/\\\\u001b\\[[0-9;]*[a-zA-Z]/g, '')\n .trim();\n }\n\n /**\n * Validate CLI installation by running --version or --help\n */\n async validateInstallation(): Promise<{\n installed: boolean;\n version?: string;\n error?: string;\n }> {\n return new Promise((resolve) => {\n const command = this.getCommand();\n\n try {\n const proc = spawn(command, ['--version'], {\n shell: true,\n timeout: 5000,\n });\n\n let output = '';\n\n proc.stdout?.on('data', (data) => {\n output += data.toString();\n });\n\n proc.stderr?.on('data', (data) => {\n output += data.toString();\n });\n\n proc.on('close', (code) => {\n if (code === 0) {\n const versionMatch = output.match(/(\\d+\\.\\d+\\.\\d+)/);\n resolve({\n installed: true,\n version: versionMatch ? versionMatch[1] : undefined,\n });\n } else {\n resolve({\n installed: false,\n error: `Command exited with code ${code}`,\n });\n }\n });\n\n proc.on('error', (err) => {\n resolve({\n installed: false,\n error: err.message,\n });\n });\n } catch (err) {\n resolve({\n installed: false,\n error: err instanceof Error ? err.message : 'Unknown error',\n });\n }\n });\n }\n\n /**\n * Helper to check if output contains a question\n */\n protected containsQuestion(output: string): boolean {\n const questionPatterns = [\n /\\?$/m,\n /would you like/i,\n /do you want/i,\n /should I/i,\n /shall I/i,\n /please (choose|select|confirm)/i,\n /\\(y\\/n\\)/i,\n /\\[y\\/N\\]/i,\n /\\[Y\\/n\\]/i,\n ];\n\n return questionPatterns.some((pattern) => pattern.test(output));\n }\n\n /**\n * Helper to strip ANSI escape codes from output\n */\n protected stripAnsi(str: string): string {\n // Replace cursor-forward sequences with spaces before stripping\n const withSpaces = str.replace(/\\x1b\\[\\d*C/g, ' ');\n // Strip OSC sequences\n const withoutOsc = withSpaces.replace(\n /\\x1b\\](?:[^\\x07\\x1b]|\\x1b[^\\\\])*(?:\\x07|\\x1b\\\\)/g,\n ''\n );\n // Strip DCS sequences\n const withoutDcs = withoutOsc.replace(\n /\\x1bP(?:[^\\x1b]|\\x1b[^\\\\])*\\x1b\\\\/g,\n ''\n );\n // eslint-disable-next-line no-control-regex\n return withoutDcs.replace(/\\x1B(?:[@-Z\\\\-_]|\\[[0-?]*[ -/]*[@-~])/g, '');\n }\n}\n","/**\n * Adapter Factory\n *\n * Factory function for creating CLI adapters from configuration.\n */\n\nimport type { CLIAdapter } from './adapter-interface.js';\nimport { BaseCLIAdapter } from './base-adapter.js';\nimport type {\n AdapterFactoryConfig,\n AutoResponseRule,\n BlockingPromptDetection,\n LoginDetection,\n ParsedOutput,\n SpawnConfig,\n} from './types.js';\n\n/**\n * Creates a CLI adapter from configuration\n */\nexport function createAdapter(config: AdapterFactoryConfig): CLIAdapter {\n return new ConfiguredAdapter(config);\n}\n\n/**\n * Adapter implementation created from configuration\n */\nclass ConfiguredAdapter extends BaseCLIAdapter {\n readonly adapterType: string;\n readonly displayName: string;\n readonly autoResponseRules: AutoResponseRule[];\n\n constructor(private adapterConfig: AdapterFactoryConfig) {\n super();\n this.adapterType = adapterConfig.command.replace(/[^a-zA-Z0-9]/g, '-');\n this.displayName = adapterConfig.command;\n this.autoResponseRules = this.buildAutoResponseRules();\n }\n\n private buildAutoResponseRules(): AutoResponseRule[] {\n if (!this.adapterConfig.blockingPrompts) {\n return [];\n }\n\n return this.adapterConfig.blockingPrompts\n .filter((p) => p.autoResponse !== undefined)\n .map((p) => ({\n pattern: p.pattern,\n type: p.type,\n response: p.autoResponse!,\n description: p.description || `Auto-respond to ${p.type} prompt`,\n safe: p.safe !== false,\n }));\n }\n\n getCommand(): string {\n return this.adapterConfig.command;\n }\n\n getArgs(config: SpawnConfig): string[] {\n if (typeof this.adapterConfig.args === 'function') {\n return this.adapterConfig.args(config);\n }\n return this.adapterConfig.args || [];\n }\n\n getEnv(config: SpawnConfig): Record<string, string> {\n if (typeof this.adapterConfig.env === 'function') {\n return this.adapterConfig.env(config);\n }\n return this.adapterConfig.env || {};\n }\n\n detectLogin(output: string): LoginDetection {\n if (!this.adapterConfig.loginDetection) {\n return { required: false };\n }\n\n const { patterns, extractUrl, extractInstructions } =\n this.adapterConfig.loginDetection;\n const stripped = this.stripAnsi(output);\n\n for (const pattern of patterns) {\n if (pattern.test(stripped)) {\n return {\n required: true,\n type: 'browser',\n url: extractUrl?.(stripped) || undefined,\n instructions:\n extractInstructions?.(stripped) || 'Authentication required',\n };\n }\n }\n\n return { required: false };\n }\n\n detectBlockingPrompt(output: string): BlockingPromptDetection {\n // First check config-defined blocking prompts\n if (this.adapterConfig.blockingPrompts) {\n const stripped = this.stripAnsi(output);\n\n for (const prompt of this.adapterConfig.blockingPrompts) {\n if (prompt.pattern.test(stripped)) {\n return {\n detected: true,\n type: prompt.type,\n prompt: stripped.slice(-200),\n suggestedResponse: prompt.autoResponse,\n canAutoRespond:\n prompt.autoResponse !== undefined && prompt.safe !== false,\n instructions: prompt.description,\n };\n }\n }\n }\n\n // Fall back to base implementation\n return super.detectBlockingPrompt(output);\n }\n\n detectReady(output: string): boolean {\n if (\n !this.adapterConfig.readyIndicators ||\n this.adapterConfig.readyIndicators.length === 0\n ) {\n // Default: ready after any output\n return output.length > 10;\n }\n\n const stripped = this.stripAnsi(output);\n return this.adapterConfig.readyIndicators.some((pattern) =>\n pattern.test(stripped)\n );\n }\n\n detectExit(output: string): {\n exited: boolean;\n code?: number;\n error?: string;\n } {\n if (this.adapterConfig.exitIndicators) {\n for (const indicator of this.adapterConfig.exitIndicators) {\n const match = output.match(indicator.pattern);\n if (match) {\n const code = indicator.codeExtractor?.(match) ?? 1;\n return { exited: true, code };\n }\n }\n }\n\n // Fall back to base implementation\n return super.detectExit(output);\n }\n\n parseOutput(output: string): ParsedOutput | null {\n if (this.adapterConfig.parseOutput) {\n return this.adapterConfig.parseOutput(output);\n }\n\n // Default parsing\n const cleaned = this.stripAnsi(output).trim();\n if (!cleaned) return null;\n\n return {\n type: 'response',\n content: cleaned,\n isComplete: true,\n isQuestion: this.containsQuestion(cleaned),\n };\n }\n\n formatInput(message: string): string {\n if (this.adapterConfig.formatInput) {\n return this.adapterConfig.formatInput(message);\n }\n return message;\n }\n\n getPromptPattern(): RegExp {\n return this.adapterConfig.promptPattern || /[$#>]\\s*$/m;\n }\n}\n","/**\n * Adapter Registry\n *\n * Registry for managing CLI adapters.\n */\n\nimport type { CLIAdapter } from './adapter-interface.js';\n\n/**\n * Registry of available CLI adapters\n */\nexport class AdapterRegistry {\n private adapters: Map<string, CLIAdapter> = new Map();\n\n /**\n * Register an adapter\n */\n register(adapter: CLIAdapter): void {\n this.adapters.set(adapter.adapterType, adapter);\n }\n\n /**\n * Get adapter for type\n */\n get(adapterType: string): CLIAdapter | undefined {\n return this.adapters.get(adapterType);\n }\n\n /**\n * Check if adapter exists for type\n */\n has(adapterType: string): boolean {\n return this.adapters.has(adapterType);\n }\n\n /**\n * Unregister an adapter\n */\n unregister(adapterType: string): boolean {\n return this.adapters.delete(adapterType);\n }\n\n /**\n * List all registered adapter types\n */\n list(): string[] {\n return Array.from(this.adapters.keys());\n }\n\n /**\n * Get all adapters\n */\n all(): CLIAdapter[] {\n return Array.from(this.adapters.values());\n }\n\n /**\n * Clear all adapters\n */\n clear(): void {\n this.adapters.clear();\n }\n}\n","/**\n * Output Sanitizer\n *\n * Utilities for cleaning terminal output — stripping ANSI escape codes,\n * TUI chrome, box-drawing characters, and other noise that interferes\n * with text processing.\n *\n * Used by both pty-manager and tmux-manager for stall detection, task\n * completion detection, and output capture. Also used by the workflow\n * executor to clean step results before interpolating into subsequent tasks.\n */\n\nexport interface SanitizeOptions {\n /** Strip ANSI escape codes (SGR, cursor, etc). Default: true */\n stripAnsi?: boolean;\n /** Strip TUI box-drawing and decorative Unicode. Default: true */\n stripTuiChrome?: boolean;\n /** Strip OSC/DCS sequences (hyperlinks, window titles). Default: true */\n stripOsc?: boolean;\n /** Collapse multiple blank lines to at most 2. Default: true */\n collapseBlankLines?: boolean;\n /** Truncate to last N characters. 0 = no limit. Default: 0 */\n maxLength?: number;\n}\n\nconst DEFAULT_OPTIONS: Required<SanitizeOptions> = {\n stripAnsi: true,\n stripTuiChrome: true,\n stripOsc: true,\n collapseBlankLines: true,\n maxLength: 0,\n};\n\n/**\n * Sanitize terminal output for text processing.\n */\nexport function sanitizeOutput(\n raw: string,\n options?: SanitizeOptions\n): string {\n const opts = { ...DEFAULT_OPTIONS, ...options };\n let result = raw;\n\n if (opts.stripOsc) {\n // Strip OSC sequences (Operating System Command)\n result = result.replace(\n /\\x1b\\](?:[^\\x07\\x1b]|\\x1b[^\\\\])*(?:\\x07|\\x1b\\\\)/g,\n ''\n );\n // Strip DCS sequences (Device Control String)\n result = result.replace(/\\x1bP(?:[^\\x1b]|\\x1b[^\\\\])*\\x1b\\\\/g, '');\n }\n\n if (opts.stripAnsi) {\n // Replace cursor movement with spaces to preserve word boundaries\n result = result.replace(/\\x1b\\[\\d*[CDABGdEF]/g, ' ');\n result = result.replace(/\\x1b\\[\\d*(?:;\\d+)?[Hf]/g, ' ');\n result = result.replace(/\\x1b\\[\\d*[JK]/g, ' ');\n // Strip remaining ANSI escape sequences\n // eslint-disable-next-line no-control-regex\n result = result.replace(/\\x1B(?:[@-Z\\\\-_]|\\[[0-?]*[ -/]*[@-~])/g, '');\n // Strip JSON-escaped ANSI (from serialized output)\n result = result.replace(/\\\\u001b\\[[0-9;]*[a-zA-Z]/g, '');\n // Strip bare control characters (except tab and newline)\n // eslint-disable-next-line no-control-regex\n result = result.replace(/[\\x00-\\x08\\x0b-\\x1f\\x7f]/g, '');\n }\n\n if (opts.stripTuiChrome) {\n // Strip TUI box-drawing, spinner, and decorative Unicode\n result = result.replace(\n /[│╭╰╮╯─═╌║╔╗╚╝╠╣╦╩╬┌┐└┘├┤┬┴┼●○❯❮▶◀⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏⣾⣽⣻⢿⡿⣟⣯⣷✻✶✳✢⏺←→↑↓⬆⬇◆◇▪▫■□▲△▼▽◈⟨⟩⌘⏎⏏⌫⌦⇧⇪⌥▐▛▜▝▘]/g,\n ' '\n );\n // Normalize non-breaking spaces\n result = result.replace(/\\xa0/g, ' ');\n // Collapse multiple spaces\n result = result.replace(/ {2,}/g, ' ');\n }\n\n if (opts.collapseBlankLines) {\n result = result.replace(/\\n{3,}/g, '\\n\\n');\n }\n\n if (opts.maxLength > 0 && result.length > opts.maxLength) {\n result = result.slice(-opts.maxLength);\n }\n\n return result.trim();\n}\n"],"mappings":";AAMA,SAAS,aAAa;AAaf,IAAe,iBAAf,MAAoD;AAAA;AAAA;AAAA;AAAA;AAAA,EAQhD,oBAAwC,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA,EAMzC,eAAwB;AAAA;AAAA;AAAA;AAAA,EAajC,WAAW,QAIT;AACA,QAAI,OAAO,SAAS,0BAA0B,GAAG;AAC/C,YAAM,QAAQ,OAAO,MAAM,gCAAgC;AAC3D,aAAO;AAAA,QACL,QAAQ;AAAA,QACR,MAAM,QAAQ,SAAS,MAAM,CAAC,GAAG,EAAE,IAAI;AAAA,MACzC;AAAA,IACF;AAEA,QACE,OAAO,SAAS,mBAAmB,KACnC,OAAO,SAAS,mBAAmB,GACnC;AACA,aAAO;AAAA,QACL,QAAQ;AAAA,QACR,MAAM;AAAA,QACN,OAAO;AAAA,MACT;AAAA,IACF;AAEA,WAAO,EAAE,QAAQ,MAAM;AAAA,EACzB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,qBAAqB,QAAyC;AAC5D,QAAI,WAAW,KAAK,UAAU,MAAM;AAGpC,eAAW,SAAS;AAAA,MAClB;AAAA,MACA;AAAA,IACF;AACA,eAAW,SAAS,QAAQ,UAAU,GAAG;AAGzC,UAAM,iBAAiB,KAAK,YAAY,MAAM;AAC9C,QAAI,eAAe,UAAU;AAC3B,aAAO;AAAA,QACL,UAAU;AAAA,QACV,MAAM;AAAA,QACN,QAAQ,eAAe;AAAA,QACvB,KAAK,eAAe;AAAA,QACpB,gBAAgB;AAAA,QAChB,cAAc,eAAe;AAAA,MAC/B;AAAA,IACF;AAGA,QACE,gCAAgC,KAAK,QAAQ,KAC7C,YAAY,KAAK,QAAQ,GACzB;AACA,aAAO;AAAA,QACL,UAAU;AAAA,QACV,MAAM;AAAA,QACN,QAAQ;AAAA,QACR,SAAS,CAAC,KAAK,GAAG;AAAA,QAClB,mBAAmB;AAAA,QACnB,gBAAgB;AAAA,QAChB,cAAc;AAAA,MAChB;AAAA,IACF;AAGA,QACE,qCAAqC,KAAK,QAAQ,KAClD,YAAY,KAAK,QAAQ,GACzB;AACA,aAAO;AAAA,QACL,UAAU;AAAA,QACV,MAAM;AAAA,QACN,QAAQ;AAAA,QACR,SAAS,CAAC,KAAK,GAAG;AAAA,QAClB,gBAAgB;AAAA,QAChB,cAAc;AAAA,MAChB;AAAA,IACF;AAGA,QAAI,2CAA2C,KAAK,QAAQ,GAAG;AAC7D,aAAO;AAAA,QACL,UAAU;AAAA,QACV,MAAM;AAAA,QACN,QAAQ;AAAA,QACR,gBAAgB;AAAA,QAChB,cAAc;AAAA,MAChB;AAAA,IACF;AAGA,QACE,2DAA2D,KAAK,QAAQ,GACxE;AACA,aAAO;AAAA,QACL,UAAU;AAAA,QACV,MAAM;AAAA,QACN,QAAQ;AAAA,QACR,gBAAgB;AAAA,QAChB,cAAc;AAAA,MAChB;AAAA,IACF;AAGA,QACE,kEAAkE;AAAA,MAChE;AAAA,IACF,GACA;AACA,aAAO;AAAA,QACL,UAAU;AAAA,QACV,MAAM;AAAA,QACN,QAAQ,SAAS,MAAM,IAAI;AAAA,QAC3B,SAAS,CAAC,KAAK,GAAG;AAAA,QAClB,gBAAgB;AAAA,QAChB,cAAc;AAAA,MAChB;AAAA,IACF;AAGA,QACE,6BAA6B,KAAK,QAAQ,KAC1C,UAAU,KAAK,QAAQ,GACvB;AACA,YAAM,gBAAgB,SAAS,MAAM,+BAA+B;AACpE,YAAM,UAAU,gBACZ,cAAc,IAAI,CAAC,MAAM,EAAE,QAAQ,YAAY,EAAE,EAAE,KAAK,CAAC,IACzD,CAAC;AAEL,aAAO;AAAA,QACL,UAAU;AAAA,QACV,MAAM;AAAA,QACN,QAAQ,SAAS,MAAM,IAAI;AAAA,QAC3B,SAAS,QAAQ,SAAS,IAAI,UAAU;AAAA,QACxC,gBAAgB;AAAA,QAChB,cAAc;AAAA,MAChB;AAAA,IACF;AAGA,QACE,0EAA0E;AAAA,MACxE;AAAA,IACF,GACA;AACA,aAAO;AAAA,QACL,UAAU;AAAA,QACV,MAAM;AAAA,QACN,QAAQ,SAAS,MAAM,IAAI;AAAA,QAC3B,mBAAmB;AAAA,QACnB,gBAAgB;AAAA,QAChB,cAAc;AAAA,MAChB;AAAA,IACF;AAGA,QACE,uCAAuC,KAAK,QAAQ,KACpD,UAAU,KAAK,QAAQ,GACvB;AACA,aAAO;AAAA,QACL,UAAU;AAAA,QACV,MAAM;AAAA,QACN,QAAQ,SAAS,MAAM,IAAI;AAAA,QAC3B,gBAAgB;AAAA,QAChB,cAAc;AAAA,MAChB;AAAA,IACF;AAGA,UAAM,QAAQ,SAAS,MAAM,IAAI,EAAE,OAAO,CAAC,MAAM,EAAE,KAAK,CAAC;AACzD,UAAM,WAAW,MAAM,MAAM,SAAS,CAAC,KAAK;AAC5C,QAAI,SAAS,KAAK,QAAQ,KAAK,SAAS,SAAS,KAAK;AACpD,aAAO;AAAA,QACL,UAAU;AAAA,QACV,MAAM;AAAA,QACN,QAAQ,SAAS,KAAK;AAAA,QACtB,gBAAgB;AAAA,QAChB,cAAc;AAAA,MAChB;AAAA,IACF;AAEA,WAAO,EAAE,UAAU,MAAM;AAAA,EAC3B;AAAA;AAAA;AAAA;AAAA,EAKA,mBAAmB,QAAyB;AAC1C,WAAO,KAAK,YAAY,MAAM;AAAA,EAChC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,YAAY,SAAyB;AAEnC,WAAO,QACJ,QAAQ,0BAA0B,EAAE,EACpC,QAAQ,6BAA6B,EAAE,EACvC,KAAK;AAAA,EACV;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,uBAIH;AACD,WAAO,IAAI,QAAQ,CAAC,YAAY;AAC9B,YAAM,UAAU,KAAK,WAAW;AAEhC,UAAI;AACF,cAAM,OAAO,MAAM,SAAS,CAAC,WAAW,GAAG;AAAA,UACzC,OAAO;AAAA,UACP,SAAS;AAAA,QACX,CAAC;AAED,YAAI,SAAS;AAEb,aAAK,QAAQ,GAAG,QAAQ,CAAC,SAAS;AAChC,oBAAU,KAAK,SAAS;AAAA,QAC1B,CAAC;AAED,aAAK,QAAQ,GAAG,QAAQ,CAAC,SAAS;AAChC,oBAAU,KAAK,SAAS;AAAA,QAC1B,CAAC;AAED,aAAK,GAAG,SAAS,CAAC,SAAS;AACzB,cAAI,SAAS,GAAG;AACd,kBAAM,eAAe,OAAO,MAAM,iBAAiB;AACnD,oBAAQ;AAAA,cACN,WAAW;AAAA,cACX,SAAS,eAAe,aAAa,CAAC,IAAI;AAAA,YAC5C,CAAC;AAAA,UACH,OAAO;AACL,oBAAQ;AAAA,cACN,WAAW;AAAA,cACX,OAAO,4BAA4B,IAAI;AAAA,YACzC,CAAC;AAAA,UACH;AAAA,QACF,CAAC;AAED,aAAK,GAAG,SAAS,CAAC,QAAQ;AACxB,kBAAQ;AAAA,YACN,WAAW;AAAA,YACX,OAAO,IAAI;AAAA,UACb,CAAC;AAAA,QACH,CAAC;AAAA,MACH,SAAS,KAAK;AACZ,gBAAQ;AAAA,UACN,WAAW;AAAA,UACX,OAAO,eAAe,QAAQ,IAAI,UAAU;AAAA,QAC9C,CAAC;AAAA,MACH;AAAA,IACF,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKU,iBAAiB,QAAyB;AAClD,UAAM,mBAAmB;AAAA,MACvB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAEA,WAAO,iBAAiB,KAAK,CAAC,YAAY,QAAQ,KAAK,MAAM,CAAC;AAAA,EAChE;AAAA;AAAA;AAAA;AAAA,EAKU,UAAU,KAAqB;AAEvC,UAAM,aAAa,IAAI,QAAQ,eAAe,GAAG;AAEjD,UAAM,aAAa,WAAW;AAAA,MAC5B;AAAA,MACA;AAAA,IACF;AAEA,UAAM,aAAa,WAAW;AAAA,MAC5B;AAAA,MACA;AAAA,IACF;AAEA,WAAO,WAAW,QAAQ,0CAA0C,EAAE;AAAA,EACxE;AACF;;;AC7UO,SAAS,cAAc,QAA0C;AACtE,SAAO,IAAI,kBAAkB,MAAM;AACrC;AAKA,IAAM,oBAAN,cAAgC,eAAe;AAAA,EAK7C,YAAoB,eAAqC;AACvD,UAAM;AADY;AAElB,SAAK,cAAc,cAAc,QAAQ,QAAQ,iBAAiB,GAAG;AACrE,SAAK,cAAc,cAAc;AACjC,SAAK,oBAAoB,KAAK,uBAAuB;AAAA,EACvD;AAAA,EATS;AAAA,EACA;AAAA,EACA;AAAA,EASD,yBAA6C;AACnD,QAAI,CAAC,KAAK,cAAc,iBAAiB;AACvC,aAAO,CAAC;AAAA,IACV;AAEA,WAAO,KAAK,cAAc,gBACvB,OAAO,CAAC,MAAM,EAAE,iBAAiB,MAAS,EAC1C,IAAI,CAAC,OAAO;AAAA,MACX,SAAS,EAAE;AAAA,MACX,MAAM,EAAE;AAAA,MACR,UAAU,EAAE;AAAA,MACZ,aAAa,EAAE,eAAe,mBAAmB,EAAE,IAAI;AAAA,MACvD,MAAM,EAAE,SAAS;AAAA,IACnB,EAAE;AAAA,EACN;AAAA,EAEA,aAAqB;AACnB,WAAO,KAAK,cAAc;AAAA,EAC5B;AAAA,EAEA,QAAQ,QAA+B;AACrC,QAAI,OAAO,KAAK,cAAc,SAAS,YAAY;AACjD,aAAO,KAAK,cAAc,KAAK,MAAM;AAAA,IACvC;AACA,WAAO,KAAK,cAAc,QAAQ,CAAC;AAAA,EACrC;AAAA,EAEA,OAAO,QAA6C;AAClD,QAAI,OAAO,KAAK,cAAc,QAAQ,YAAY;AAChD,aAAO,KAAK,cAAc,IAAI,MAAM;AAAA,IACtC;AACA,WAAO,KAAK,cAAc,OAAO,CAAC;AAAA,EACpC;AAAA,EAEA,YAAY,QAAgC;AAC1C,QAAI,CAAC,KAAK,cAAc,gBAAgB;AACtC,aAAO,EAAE,UAAU,MAAM;AAAA,IAC3B;AAEA,UAAM,EAAE,UAAU,YAAY,oBAAoB,IAChD,KAAK,cAAc;AACrB,UAAM,WAAW,KAAK,UAAU,MAAM;AAEtC,eAAW,WAAW,UAAU;AAC9B,UAAI,QAAQ,KAAK,QAAQ,GAAG;AAC1B,eAAO;AAAA,UACL,UAAU;AAAA,UACV,MAAM;AAAA,UACN,KAAK,aAAa,QAAQ,KAAK;AAAA,UAC/B,cACE,sBAAsB,QAAQ,KAAK;AAAA,QACvC;AAAA,MACF;AAAA,IACF;AAEA,WAAO,EAAE,UAAU,MAAM;AAAA,EAC3B;AAAA,EAEA,qBAAqB,QAAyC;AAE5D,QAAI,KAAK,cAAc,iBAAiB;AACtC,YAAM,WAAW,KAAK,UAAU,MAAM;AAEtC,iBAAW,UAAU,KAAK,cAAc,iBAAiB;AACvD,YAAI,OAAO,QAAQ,KAAK,QAAQ,GAAG;AACjC,iBAAO;AAAA,YACL,UAAU;AAAA,YACV,MAAM,OAAO;AAAA,YACb,QAAQ,SAAS,MAAM,IAAI;AAAA,YAC3B,mBAAmB,OAAO;AAAA,YAC1B,gBACE,OAAO,iBAAiB,UAAa,OAAO,SAAS;AAAA,YACvD,cAAc,OAAO;AAAA,UACvB;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAGA,WAAO,MAAM,qBAAqB,MAAM;AAAA,EAC1C;AAAA,EAEA,YAAY,QAAyB;AACnC,QACE,CAAC,KAAK,cAAc,mBACpB,KAAK,cAAc,gBAAgB,WAAW,GAC9C;AAEA,aAAO,OAAO,SAAS;AAAA,IACzB;AAEA,UAAM,WAAW,KAAK,UAAU,MAAM;AACtC,WAAO,KAAK,cAAc,gBAAgB;AAAA,MAAK,CAAC,YAC9C,QAAQ,KAAK,QAAQ;AAAA,IACvB;AAAA,EACF;AAAA,EAEA,WAAW,QAIT;AACA,QAAI,KAAK,cAAc,gBAAgB;AACrC,iBAAW,aAAa,KAAK,cAAc,gBAAgB;AACzD,cAAM,QAAQ,OAAO,MAAM,UAAU,OAAO;AAC5C,YAAI,OAAO;AACT,gBAAM,OAAO,UAAU,gBAAgB,KAAK,KAAK;AACjD,iBAAO,EAAE,QAAQ,MAAM,KAAK;AAAA,QAC9B;AAAA,MACF;AAAA,IACF;AAGA,WAAO,MAAM,WAAW,MAAM;AAAA,EAChC;AAAA,EAEA,YAAY,QAAqC;AAC/C,QAAI,KAAK,cAAc,aAAa;AAClC,aAAO,KAAK,cAAc,YAAY,MAAM;AAAA,IAC9C;AAGA,UAAM,UAAU,KAAK,UAAU,MAAM,EAAE,KAAK;AAC5C,QAAI,CAAC,QAAS,QAAO;AAErB,WAAO;AAAA,MACL,MAAM;AAAA,MACN,SAAS;AAAA,MACT,YAAY;AAAA,MACZ,YAAY,KAAK,iBAAiB,OAAO;AAAA,IAC3C;AAAA,EACF;AAAA,EAEA,YAAY,SAAyB;AACnC,QAAI,KAAK,cAAc,aAAa;AAClC,aAAO,KAAK,cAAc,YAAY,OAAO;AAAA,IAC/C;AACA,WAAO;AAAA,EACT;AAAA,EAEA,mBAA2B;AACzB,WAAO,KAAK,cAAc,iBAAiB;AAAA,EAC7C;AACF;;;AC3KO,IAAM,kBAAN,MAAsB;AAAA,EACnB,WAAoC,oBAAI,IAAI;AAAA;AAAA;AAAA;AAAA,EAKpD,SAAS,SAA2B;AAClC,SAAK,SAAS,IAAI,QAAQ,aAAa,OAAO;AAAA,EAChD;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,aAA6C;AAC/C,WAAO,KAAK,SAAS,IAAI,WAAW;AAAA,EACtC;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,aAA8B;AAChC,WAAO,KAAK,SAAS,IAAI,WAAW;AAAA,EACtC;AAAA;AAAA;AAAA;AAAA,EAKA,WAAW,aAA8B;AACvC,WAAO,KAAK,SAAS,OAAO,WAAW;AAAA,EACzC;AAAA;AAAA;AAAA;AAAA,EAKA,OAAiB;AACf,WAAO,MAAM,KAAK,KAAK,SAAS,KAAK,CAAC;AAAA,EACxC;AAAA;AAAA;AAAA;AAAA,EAKA,MAAoB;AAClB,WAAO,MAAM,KAAK,KAAK,SAAS,OAAO,CAAC;AAAA,EAC1C;AAAA;AAAA;AAAA;AAAA,EAKA,QAAc;AACZ,SAAK,SAAS,MAAM;AAAA,EACtB;AACF;;;ACrCA,IAAM,kBAA6C;AAAA,EACjD,WAAW;AAAA,EACX,gBAAgB;AAAA,EAChB,UAAU;AAAA,EACV,oBAAoB;AAAA,EACpB,WAAW;AACb;AAKO,SAAS,eACd,KACA,SACQ;AACR,QAAM,OAAO,EAAE,GAAG,iBAAiB,GAAG,QAAQ;AAC9C,MAAI,SAAS;AAEb,MAAI,KAAK,UAAU;AAEjB,aAAS,OAAO;AAAA,MACd;AAAA,MACA;AAAA,IACF;AAEA,aAAS,OAAO,QAAQ,sCAAsC,EAAE;AAAA,EAClE;AAEA,MAAI,KAAK,WAAW;AAElB,aAAS,OAAO,QAAQ,wBAAwB,GAAG;AACnD,aAAS,OAAO,QAAQ,2BAA2B,GAAG;AACtD,aAAS,OAAO,QAAQ,kBAAkB,GAAG;AAG7C,aAAS,OAAO,QAAQ,0CAA0C,EAAE;AAEpE,aAAS,OAAO,QAAQ,6BAA6B,EAAE;AAGvD,aAAS,OAAO,QAAQ,6BAA6B,EAAE;AAAA,EACzD;AAEA,MAAI,KAAK,gBAAgB;AAEvB,aAAS,OAAO;AAAA,MACd;AAAA,MACA;AAAA,IACF;AAEA,aAAS,OAAO,QAAQ,SAAS,GAAG;AAEpC,aAAS,OAAO,QAAQ,UAAU,GAAG;AAAA,EACvC;AAEA,MAAI,KAAK,oBAAoB;AAC3B,aAAS,OAAO,QAAQ,WAAW,MAAM;AAAA,EAC3C;AAEA,MAAI,KAAK,YAAY,KAAK,OAAO,SAAS,KAAK,WAAW;AACxD,aAAS,OAAO,MAAM,CAAC,KAAK,SAAS;AAAA,EACvC;AAEA,SAAO,OAAO,KAAK;AACrB;","names":[]} |
+3
-2
| { | ||
| "name": "adapter-types", | ||
| "version": "0.1.0", | ||
| "version": "0.2.0", | ||
| "description": "Shared adapter interface, base class, and types for PTY/tmux session managers", | ||
@@ -37,3 +37,4 @@ "main": "dist/index.js", | ||
| "tsup": "^8.0.0", | ||
| "typescript": "^5.7.2" | ||
| "typescript": "^5.7.2", | ||
| "vitest": "^3.1.1" | ||
| }, | ||
@@ -40,0 +41,0 @@ "engines": { |
128959
15.09%1386
12.68%4
33.33%