🚀 Socket Launch Week Day 4:Socket MCP Adds Org Alerts, Threat Feed Review, and Package Inspection.Learn more
Sign In

adapter-types

Package Overview
Dependencies
Maintainers
1
Versions
3
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

adapter-types - npm Package Compare versions

Comparing version
0.1.0
to
0.2.0
+78
-47
dist/index.d.mts

@@ -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 };

@@ -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 };

@@ -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":[]}

@@ -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":"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","names":[]}
{
"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": {