@theclawlab/pai 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/types.ts","../src/config-manager.ts","../src/session-manager.ts","../src/input-resolver.ts","../src/output-formatter.ts","../src/sanitize.ts","../src/llm-client.ts","../src/tools/bash-exec.ts","../src/tool-registry.ts","../src/commands/chat.ts","../src/embedding-client.ts","../src/embed-model-resolver.ts","../src/embedding-models.ts","../src/embed-io.ts","../src/commands/embed.ts","../src/commands/model.ts","../src/help.ts"],"sourcesContent":["import { Command } from 'commander';\nimport { readFileSync } from 'node:fs';\nimport { join, dirname } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { handleChatCommand } from './commands/chat.js';\nimport { handleEmbedCommand } from './commands/embed.js';\nimport { handleModelList, handleModelConfig, handleModelDefault, handleModelLogin } from './commands/model.js';\nimport { installHelp, addSubcommandExamples } from './help.js';\nimport type { ChatOptions, EmbedOptions, ModelConfigOptions } from './types.js';\n\n// Gracefully handle EPIPE (e.g. `pai embed \"x\" | head` or broken pipe)\nprocess.stdout.on('error', (err: NodeJS.ErrnoException) => {\n if (err.code === 'EPIPE') process.exit(0);\n throw err;\n});\nprocess.stderr.on('error', (err: NodeJS.ErrnoException) => {\n if (err.code === 'EPIPE') process.exit(0);\n throw err;\n});\n\n// Get package.json info for version\nconst __dirname = dirname(fileURLToPath(import.meta.url));\nconst packageJson = JSON.parse(\n readFileSync(join(__dirname, '../package.json'), 'utf8')\n);\n\n// Read pi-ai version\nlet piAiVersion = 'unknown';\ntry {\n const piAiPkg = JSON.parse(\n readFileSync(join(__dirname, '../node_modules/@mariozechner/pi-ai/package.json'), 'utf8')\n );\n piAiVersion = piAiPkg.version;\n} catch {\n // pi-ai package.json not found\n}\n\nconst versionString = `pai ${packageJson.version} (pi-ai ${piAiVersion}, Node ${process.version})`;\n\nconst program = new Command();\n\nprogram\n .name('pai')\n .description('PAI - A Unix-style CLI tool for interacting with LLMs')\n .version(versionString)\n .showHelpAfterError(true)\n .configureOutput({\n writeErr: (str) => process.stderr.write(str),\n writeOut: (str) => process.stdout.write(str),\n });\n\nprogram.exitOverride();\n\n// Install help system (examples + --verbose support)\ninstallHelp(program);\n\n// Chat command\nconst chatCmd = program\n .command('chat')\n .description('Chat with an LLM')\n .argument('[prompt]', 'User message (or use stdin/--input-file)')\n .option('--config <path>', 'Config file path')\n .option('--session <path>', 'Session file path (JSONL)')\n .option('--system <text>', 'System instruction')\n .option('--system-file <path>', 'System instruction from file')\n .option('--input-file <path>', 'User input from file')\n .option('--image <path...>', 'Image file(s) to include')\n .option('--provider <name>', 'Provider name')\n .option('--model <name>', 'Model name')\n .option('--temperature <number>', 'Temperature (0-2)', parseFloat)\n .option('--max-tokens <number>', 'Max tokens', parseInt)\n .option('--stream', 'Enable streaming output')\n .option('--no-append', 'Do not append to session file')\n .option('--json', 'Output progress as NDJSON')\n .option('--quiet', 'Suppress progress output')\n .option('--log <path>', 'Log file path (Markdown)')\n .option('--max-turns <number>', 'Max tool-call turns (default: 100)', parseInt)\n .option('--dry-run', 'Show resolved config without calling LLM')\n .action(async (prompt: string | undefined, options: ChatOptions) => {\n await handleChatCommand(prompt, options);\n });\naddSubcommandExamples(chatCmd, 'chat');\n\n// Embed command\nconst embedCmd = program\n .command('embed')\n .description('Generate text embeddings')\n .argument('[text]', 'Text to embed (or use stdin/--input-file)')\n .option('--provider <name>', 'Provider name')\n .option('--model <name>', 'Embedding model name')\n .option('--config <path>', 'Config file path')\n .option('--json', 'Output as JSON')\n .option('--quiet', 'Suppress progress output')\n .option('--batch', 'Enable batch embedding mode (input is JSON string array)')\n .option('--input-file <path>', 'Read input from file')\n .action(async (text: string | undefined, options: EmbedOptions) => {\n await handleEmbedCommand(text, options);\n });\naddSubcommandExamples(embedCmd, 'embed');\n\n// Model list command\nconst modelCommand = program\n .command('model')\n .description('Manage model configurations');\n\nmodelCommand\n .command('list')\n .description('List providers and models')\n .option('--config <path>', 'Config file path')\n .option('--all', 'Show all supported providers')\n .option('--json', 'Output as JSON')\n .action(async (options: ModelConfigOptions) => {\n await handleModelList(options);\n });\naddSubcommandExamples(modelCommand.commands.find(c => c.name() === 'list')!, 'list');\n\n// Model config command\nmodelCommand\n .command('config')\n .description('Configure providers')\n .option('--config <path>', 'Config file path')\n .option('--add', 'Add or update provider')\n .option('--update', 'Update fields on an existing provider')\n .option('--delete', 'Delete provider')\n .option('--show', 'Show provider configuration')\n .option('--name <name>', 'Provider name')\n .option('--provider <type>', 'Provider type')\n .option('--set <key=value...>', 'Set configuration values')\n .option('--default', 'Set as default provider (with --add or --update)')\n .option('--json', 'Output as JSON')\n .action(async (options: ModelConfigOptions) => {\n await handleModelConfig(options);\n });\naddSubcommandExamples(modelCommand.commands.find(c => c.name() === 'config')!, 'config');\n// Model login command (OAuth providers)\nmodelCommand\n .command('login')\n .description('Login to an OAuth provider (github-copilot, anthropic, google-gemini-cli, etc.)')\n .option('--config <path>', 'Config file path')\n .option('--name <name>', 'Provider name')\n .action(async (options: ModelConfigOptions) => {\n await handleModelLogin(options);\n });\naddSubcommandExamples(modelCommand.commands.find(c => c.name() === 'login')!, 'login');\n\n// Model default command (view/set default provider)\nmodelCommand\n .command('default')\n .description('View or set the default provider')\n .option('--config <path>', 'Config file path')\n .option('--name <name>', 'Provider name to set as default')\n .option('--embed-provider <name>', 'Set default embed provider')\n .option('--embed-model <model>', 'Set default embed model')\n .option('--json', 'Output as JSON')\n .action(async (options: ModelConfigOptions) => {\n await handleModelDefault(options);\n });\naddSubcommandExamples(modelCommand.commands.find(c => c.name() === 'default')!, 'default');\n\n// Error handling for unknown commands\nprogram.on('command:*', () => {\n process.stderr.write(`Invalid command: ${program.args.join(' ')}\\nSee --help for available commands.\\n`);\n process.exit(2);\n});\n\n// Parse arguments\n(async () => {\n try {\n await program.parseAsync(process.argv);\n } catch (err) {\n // commander throws CommanderError on exitOverride\n if (err && typeof err === 'object' && 'exitCode' in err) {\n const exitCode = (err as { exitCode: number }).exitCode;\n // Map commander's exit code 1 (argument errors) to 2 per spec\n process.exitCode = exitCode === 1 ? 2 : exitCode;\n } else {\n process.stderr.write(`Error: ${err instanceof Error ? err.message : String(err)}\\n`);\n process.exitCode = 2;\n }\n }\n})();\n\n\n","/**\r\n * Core type definitions for PAI CLI tool\r\n */\r\n\r\n// ============================================================================\r\n// Configuration Types\r\n// ============================================================================\r\n\r\nexport interface ProviderConfig {\r\n name: string;\r\n apiKey?: string;\r\n models?: string[];\r\n defaultModel?: string;\r\n temperature?: number;\r\n maxTokens?: number;\r\n /** pi-ai API type, e.g. 'openai-responses', 'azure-openai-responses', 'anthropic-messages' */\r\n api?: string;\r\n /** Base URL for custom/self-hosted endpoints */\r\n baseUrl?: string;\r\n /** Whether the model supports reasoning/thinking */\r\n reasoning?: boolean;\r\n /** Input modalities: ['text'] or ['text', 'image'] */\r\n input?: string[];\r\n /** Context window size in tokens */\r\n contextWindow?: number;\r\n /** Provider-specific options (e.g. azureApiVersion, azureDeploymentName) */\r\n providerOptions?: Record<string, any>;\r\n /** OAuth credentials (for OAuth-based providers like github-copilot, anthropic, etc.) */\r\n oauth?: OAuthCredentialStore;\r\n}\r\n\r\nexport interface OAuthCredentialStore {\r\n refresh: string;\r\n access: string;\r\n expires: number;\r\n /** Extra provider-specific fields (e.g. enterpriseUrl, projectId, accountId) */\r\n [key: string]: unknown;\r\n}\r\n\r\nexport interface PAIConfig {\r\n schema_version: string;\r\n defaultProvider?: string;\r\n defaultEmbedProvider?: string;\r\n defaultEmbedModel?: string;\r\n providers: ProviderConfig[];\r\n}\r\n\r\n// ============================================================================\r\n// Message Types (Session File)\r\n// ============================================================================\r\n\r\nexport type MessageRole = 'system' | 'user' | 'assistant' | 'tool';\r\n\r\nexport type MessageContent = string | object | any[];\r\n\r\nexport interface Message {\r\n role: MessageRole;\r\n content: MessageContent;\r\n name?: string; // For tool messages\r\n tool_call_id?: string; // For tool responses\r\n timestamp?: string; // ISO8601 timestamp\r\n id?: string; // Optional message ID\r\n}\r\n\r\n// ============================================================================\r\n// Tool Types\r\n// ============================================================================\r\n\r\nexport interface Tool {\r\n name: string;\r\n description: string;\r\n parameters: object; // JSON Schema\r\n handler: (args: any) => Promise<any>;\r\n}\r\n\r\nexport interface ToolCall {\r\n id: string;\r\n name: string;\r\n arguments: any;\r\n}\r\n\r\n// ============================================================================\r\n// LLM Client Types\r\n// ============================================================================\r\n\r\nexport interface LLMClientConfig {\r\n provider: string;\r\n model: string;\r\n apiKey: string;\r\n temperature?: number | undefined;\r\n maxTokens?: number | undefined;\r\n stream?: boolean | undefined;\r\n /** pi-ai API type for custom models */\r\n api?: string | undefined;\r\n /** Base URL for custom/self-hosted endpoints */\r\n baseUrl?: string | undefined;\r\n /** Whether the model supports reasoning */\r\n reasoning?: boolean | undefined;\r\n /** Input modalities */\r\n input?: string[] | undefined;\r\n /** Context window size */\r\n contextWindow?: number | undefined;\r\n /** Provider-specific options passed through to pi-ai */\r\n providerOptions?: Record<string, any> | undefined;\r\n}\r\n\r\nexport interface LLMResponse {\r\n content: string;\r\n toolCalls?: ToolCall[];\r\n finishReason: string;\r\n usage?: {\r\n input: number;\r\n output: number;\r\n cost?: { total: number };\r\n };\r\n}\r\n\r\n// ============================================================================\r\n// CLI Option Types\r\n// ============================================================================\r\n\r\nexport interface CLIOptions {\r\n config?: string;\r\n json?: boolean;\r\n quiet?: boolean;\r\n}\r\n\r\nexport interface EmbedOptions extends CLIOptions {\r\n provider?: string;\r\n model?: string;\r\n inputFile?: string;\r\n batch?: boolean;\r\n}\r\n\r\nexport interface ChatOptions extends CLIOptions {\r\n session?: string;\r\n system?: string;\r\n systemFile?: string;\r\n inputFile?: string;\r\n image?: string[];\r\n provider?: string;\r\n model?: string;\r\n temperature?: number;\r\n maxTokens?: number;\r\n stream?: boolean;\r\n log?: string;\r\n append?: boolean; // Commander.js: --no-append sets this to false\r\n dryRun?: boolean;\r\n maxTurns?: number; // Max tool-call turns\r\n}\r\n\r\nexport interface ModelConfigOptions extends CLIOptions {\r\n add?: boolean;\r\n update?: boolean;\r\n delete?: boolean;\r\n show?: boolean;\r\n all?: boolean;\r\n name?: string;\r\n provider?: string;\r\n set?: string[];\r\n default?: boolean;\r\n embedProvider?: string;\r\n embedModel?: string;\r\n}\r\n\r\n// ============================================================================\r\n// bash_exec Tool Types\r\n// ============================================================================\r\n\r\nexport interface BashExecArgs {\r\n command: string;\r\n cwd?: string;\r\n}\r\n\r\nexport interface BashExecResult {\r\n stdout: string;\r\n stderr: string;\r\n exitCode: number;\r\n}\r\n\r\n// ============================================================================\r\n// Output Formatter Types\r\n// ============================================================================\r\n\r\nexport interface OutputEvent {\r\n type: 'start' | 'chunk' | 'tool_call' | 'tool_result' | 'complete' | 'error';\r\n data: any;\r\n timestamp?: number;\r\n}\r\n\r\n// ============================================================================\r\n// Input Resolver Types\r\n// ============================================================================\r\n\r\nexport interface InputSource {\r\n message?: string | undefined; // CLI argument\r\n stdin?: boolean | undefined;\r\n file?: string | undefined;\r\n images?: string[] | undefined;\r\n}\r\n\r\n// ============================================================================\r\n// Error Types\r\n// ============================================================================\r\n\r\nexport enum ExitCode {\r\n SUCCESS = 0,\r\n PARAMETER_ERROR = 1,\r\n RUNTIME_ERROR = 2,\r\n API_ERROR = 3,\r\n IO_ERROR = 4,\r\n}\r\n\r\nexport class PAIError extends Error {\r\n constructor(\r\n message: string,\r\n public exitCode: ExitCode,\r\n public context?: Record<string, any>\r\n ) {\r\n super(message);\r\n this.name = 'PAIError';\r\n }\r\n}\r\n","import { readFile, writeFile, mkdir } from 'node:fs/promises';\r\nimport { existsSync } from 'node:fs';\r\nimport { dirname, join } from 'node:path';\r\nimport { homedir } from 'node:os';\r\nimport type { PAIConfig, ProviderConfig, CLIOptions, ExitCode } from './types.js';\r\nimport { PAIError } from './types.js';\r\n\r\nconst DEFAULT_SCHEMA_VERSION = '1.0.0';\r\n\r\nexport class ConfigurationManager {\r\n private configPath: string;\r\n\r\n constructor(options: CLIOptions = {}) {\r\n // Priority: --config > PAI_CONFIG env > ~/.config/pai/default.json\r\n this.configPath =\r\n options.config ||\r\n process.env.PAI_CONFIG ||\r\n join(homedir(), '.config', 'pai', 'default.json');\r\n }\r\n\r\n /**\r\n * Load configuration from file\r\n * Returns default config if file doesn't exist\r\n */\r\n async loadConfig(): Promise<PAIConfig> {\r\n if (!existsSync(this.configPath)) {\r\n return this.getDefaultConfig();\r\n }\r\n\r\n try {\r\n const content = await readFile(this.configPath, 'utf-8');\r\n const config = JSON.parse(content) as PAIConfig;\r\n\r\n // Validate schema_version exists\r\n if (!config.schema_version) {\r\n throw new PAIError(\r\n 'Config file is missing schema_version field',\r\n 4 as ExitCode,\r\n { path: this.configPath }\r\n );\r\n }\r\n\r\n // Validate providers field exists and is an array\r\n if (!config.providers) {\r\n throw new PAIError(\r\n 'Config file is missing providers field',\r\n 4 as ExitCode,\r\n { path: this.configPath }\r\n );\r\n }\r\n\r\n if (!Array.isArray(config.providers)) {\r\n throw new PAIError(\r\n 'Config file providers field must be an array',\r\n 4 as ExitCode,\r\n { path: this.configPath }\r\n );\r\n }\r\n\r\n return config;\r\n } catch (error) {\r\n if (error instanceof PAIError) {\r\n throw error;\r\n }\r\n\r\n if (error instanceof SyntaxError) {\r\n throw new PAIError(\r\n 'Config file is malformed',\r\n 4 as ExitCode,\r\n { path: this.configPath, error: error.message }\r\n );\r\n }\r\n\r\n throw new PAIError(\r\n 'Failed to read config file',\r\n 4 as ExitCode,\r\n { path: this.configPath, error: String(error) }\r\n );\r\n }\r\n }\r\n\r\n /**\r\n * Save configuration to file\r\n * Creates directory if needed\r\n */\r\n async saveConfig(config: PAIConfig): Promise<void> {\r\n // Ensure schema_version is present\r\n if (!config.schema_version) {\r\n config.schema_version = DEFAULT_SCHEMA_VERSION;\r\n }\r\n\r\n try {\r\n // Create directory if it doesn't exist\r\n const dir = dirname(this.configPath);\r\n if (!existsSync(dir)) {\r\n await mkdir(dir, { recursive: true });\r\n }\r\n\r\n // Write config file with formatting\r\n const content = JSON.stringify(config, null, 2);\r\n await writeFile(this.configPath, content, 'utf-8');\r\n } catch (error) {\r\n throw new PAIError(\r\n 'Failed to write config file',\r\n 4 as ExitCode,\r\n { path: this.configPath, error: String(error) }\r\n );\r\n }\r\n }\r\n\r\n /**\r\n * Get provider configuration by name\r\n * Throws error if not found\r\n */\r\n async getProvider(name?: string): Promise<ProviderConfig> {\r\n const config = await this.loadConfig();\r\n\r\n // Use specified name or default provider\r\n const providerName = name || config.defaultProvider;\r\n\r\n if (!providerName) {\r\n throw new PAIError(\r\n 'No provider specified and no default provider configured',\r\n 1 as ExitCode,\r\n { configPath: this.configPath }\r\n );\r\n }\r\n\r\n const provider = config.providers.find((p) => p.name === providerName);\r\n\r\n if (!provider) {\r\n throw new PAIError(\r\n `Provider not found: ${providerName}`,\r\n 1 as ExitCode,\r\n { provider: providerName, configPath: this.configPath }\r\n );\r\n }\r\n\r\n return provider;\r\n }\r\n\r\n /**\r\n * Add or update a provider configuration\r\n */\r\n async addProvider(provider: ProviderConfig): Promise<void> {\r\n const config = await this.loadConfig();\r\n\r\n // Find existing provider index\r\n const existingIndex = config.providers.findIndex(\r\n (p) => p.name === provider.name\r\n );\r\n\r\n if (existingIndex >= 0) {\r\n // Update existing provider\r\n config.providers[existingIndex] = provider;\r\n } else {\r\n // Add new provider\r\n config.providers.push(provider);\r\n }\r\n\r\n await this.saveConfig(config);\r\n }\r\n\r\n /**\r\n * Patch an existing provider configuration (merge fields)\r\n */\r\n async updateProvider(name: string, updates: Record<string, any>): Promise<void> {\r\n const config = await this.loadConfig();\r\n\r\n const existingIndex = config.providers.findIndex((p) => p.name === name);\r\n\r\n if (existingIndex < 0) {\r\n throw new PAIError(\r\n `Provider not found: ${name}`,\r\n 1 as ExitCode,\r\n { provider: name, configPath: this.configPath }\r\n );\r\n }\r\n\r\n // Deep merge updates into existing config\r\n const existing = config.providers[existingIndex]!;\r\n for (const [key, value] of Object.entries(updates)) {\r\n if (key === 'name') continue; // Don't allow renaming\r\n if (typeof value === 'object' && value !== null && !Array.isArray(value) &&\r\n typeof (existing as any)[key] === 'object' && (existing as any)[key] !== null) {\r\n // Merge nested objects (e.g. providerOptions)\r\n (existing as any)[key] = { ...(existing as any)[key], ...value };\r\n } else {\r\n (existing as any)[key] = value;\r\n }\r\n }\r\n\r\n config.providers[existingIndex] = existing;\r\n await this.saveConfig(config);\r\n }\r\n\r\n /**\r\n * Set the default provider\r\n */\r\n async setDefaultProvider(name: string): Promise<void> {\r\n const config = await this.loadConfig();\r\n\r\n // Verify provider exists\r\n const exists = config.providers.some((p) => p.name === name);\r\n if (!exists) {\r\n throw new PAIError(\r\n `Provider not found: ${name}`,\r\n 1 as ExitCode,\r\n { provider: name, configPath: this.configPath }\r\n );\r\n }\r\n\r\n config.defaultProvider = name;\r\n await this.saveConfig(config);\r\n }\r\n\r\n /**\r\n * Set the default embed provider and/or model\r\n */\r\n async setDefaultEmbed(embedProvider?: string, embedModel?: string): Promise<void> {\r\n const config = await this.loadConfig();\r\n\r\n if (embedProvider) {\r\n // Verify provider exists\r\n const exists = config.providers.some((p) => p.name === embedProvider);\r\n if (!exists) {\r\n throw new PAIError(\r\n `Provider not found: ${embedProvider}`,\r\n 1 as ExitCode,\r\n { provider: embedProvider, configPath: this.configPath }\r\n );\r\n }\r\n config.defaultEmbedProvider = embedProvider;\r\n }\r\n\r\n if (embedModel) {\r\n config.defaultEmbedModel = embedModel;\r\n }\r\n\r\n await this.saveConfig(config);\r\n }\r\n\r\n /**\r\n * Delete a provider configuration\r\n */\r\n async deleteProvider(name: string): Promise<void> {\r\n const config = await this.loadConfig();\r\n\r\n const existingIndex = config.providers.findIndex((p) => p.name === name);\r\n\r\n if (existingIndex < 0) {\r\n throw new PAIError(\r\n `Provider not found: ${name}`,\r\n 1 as ExitCode,\r\n { provider: name, configPath: this.configPath }\r\n );\r\n }\r\n\r\n config.providers.splice(existingIndex, 1);\r\n\r\n // Clear defaultProvider if the deleted provider was the default\r\n if (config.defaultProvider === name) {\r\n delete config.defaultProvider;\r\n }\r\n\r\n await this.saveConfig(config);\r\n }\r\n\r\n /**\r\n * Get default configuration\r\n */\r\n private getDefaultConfig(): PAIConfig {\r\n return {\r\n schema_version: DEFAULT_SCHEMA_VERSION,\r\n providers: [],\r\n };\r\n }\r\n\r\n /**\r\n * Get config file path\r\n */\r\n getConfigPath(): string {\r\n return this.configPath;\r\n }\r\n\r\n /**\r\n * Resolve credentials for a provider\r\n * Priority: CLI param > env var > config file (apiKey or oauth)\r\n */\r\n async resolveCredentials(\r\n provider: string,\r\n cliKey?: string\r\n ): Promise<string> {\r\n // 1. Check CLI parameter\r\n if (cliKey) {\r\n return cliKey;\r\n }\r\n\r\n // 2. Check environment variable (PAI_<PROVIDER>_API_KEY pattern)\r\n const envVarName = `PAI_${provider.toUpperCase().replace(/-/g, '_')}_API_KEY`;\r\n const envKey = process.env[envVarName];\r\n if (envKey) {\r\n return envKey;\r\n }\r\n\r\n // 3. Check config file (apiKey or OAuth credentials)\r\n try {\r\n const providerConfig = await this.getProvider(provider);\r\n\r\n // 3a. Direct API key\r\n if (providerConfig.apiKey) {\r\n return providerConfig.apiKey;\r\n }\r\n\r\n // 3b. OAuth credentials stored in config\r\n if (providerConfig.oauth) {\r\n const oauthApiKey = await this.resolveOAuthCredentials(providerConfig);\r\n if (oauthApiKey) {\r\n return oauthApiKey;\r\n }\r\n }\r\n } catch {\r\n // Provider not in config\r\n }\r\n\r\n throw new PAIError(\r\n `No credentials found for provider: ${provider}`,\r\n 1 as ExitCode,\r\n {\r\n provider,\r\n checkedSources: ['CLI parameter', 'environment variable', 'config file'],\r\n }\r\n );\r\n }\r\n\r\n /**\r\n * Resolve OAuth credentials from provider config.\r\n * Automatically refreshes expired tokens and saves updated credentials.\r\n */\r\n private async resolveOAuthCredentials(\r\n providerConfig: ProviderConfig\r\n ): Promise<string | null> {\r\n const oauth = providerConfig.oauth;\r\n if (!oauth || !oauth.access) {\r\n return null;\r\n }\r\n\r\n // Check if token is expired\r\n if (oauth.expires && Date.now() >= oauth.expires) {\r\n // Try to refresh the token\r\n try {\r\n const { getOAuthProvider } = await import('@mariozechner/pi-ai/oauth');\r\n const oauthProvider = getOAuthProvider(providerConfig.name);\r\n if (oauthProvider) {\r\n const newCredentials = await oauthProvider.refreshToken(oauth as any);\r\n // Update config with refreshed credentials\r\n providerConfig.oauth = {\r\n ...oauth,\r\n refresh: newCredentials.refresh,\r\n access: newCredentials.access,\r\n expires: newCredentials.expires,\r\n };\r\n await this.addProvider(providerConfig);\r\n return oauthProvider.getApiKey(providerConfig.oauth as any);\r\n }\r\n } catch {\r\n // Refresh failed, return existing token (may still work)\r\n }\r\n }\r\n\r\n // Use getApiKey if available (some providers encode extra fields)\r\n try {\r\n const { getOAuthProvider } = await import('@mariozechner/pi-ai/oauth');\r\n const oauthProvider = getOAuthProvider(providerConfig.name);\r\n if (oauthProvider) {\r\n return oauthProvider.getApiKey(oauth as any);\r\n }\r\n } catch {\r\n // Fall back to raw access token\r\n }\r\n\r\n return oauth.access;\r\n }\r\n}\r\n","import { writeFile, appendFile } from 'node:fs/promises';\r\nimport { existsSync } from 'node:fs';\r\nimport { createReadStream } from 'node:fs';\r\nimport { createInterface } from 'node:readline';\r\nimport type { Message, ExitCode } from './types.js';\r\nimport { PAIError } from './types.js';\r\n\r\nexport class SessionManager {\r\n private sessionPath: string | undefined;\r\n\r\n constructor(sessionPath?: string) {\r\n this.sessionPath = sessionPath;\r\n }\r\n\r\n /**\r\n * Load messages from session file\r\n * Returns empty array if file doesn't exist\r\n */\r\n async loadMessages(): Promise<Message[]> {\r\n if (!this.sessionPath || !existsSync(this.sessionPath)) {\r\n return [];\r\n }\r\n\r\n try {\r\n const messages: Message[] = [];\r\n const fileStream = createReadStream(this.sessionPath, 'utf-8');\r\n const rl = createInterface({\r\n input: fileStream,\r\n crlfDelay: Infinity,\r\n });\r\n\r\n let lineNumber = 0;\r\n for await (const line of rl) {\r\n lineNumber++;\r\n \r\n // Skip empty lines\r\n if (line.trim() === '') {\r\n continue;\r\n }\r\n\r\n try {\r\n const message = JSON.parse(line) as Message;\r\n\r\n // Validate required fields\r\n if (!message.role || message.content === undefined) {\r\n throw new Error('Missing required fields: role and content');\r\n }\r\n\r\n messages.push(message);\r\n } catch (error) {\r\n throw new PAIError(\r\n `Malformed JSONL at line ${lineNumber}`,\r\n 4 as ExitCode,\r\n {\r\n path: this.sessionPath,\r\n line: lineNumber,\r\n error: error instanceof Error ? error.message : String(error),\r\n }\r\n );\r\n }\r\n }\r\n\r\n return messages;\r\n } catch (error) {\r\n if (error instanceof PAIError) {\r\n throw error;\r\n }\r\n\r\n throw new PAIError(\r\n 'Failed to read session file',\r\n 4 as ExitCode,\r\n { path: this.sessionPath, error: String(error) }\r\n );\r\n }\r\n }\r\n\r\n /**\r\n * Append a single message to session file\r\n * Creates file if it doesn't exist\r\n */\r\n async appendMessage(message: Message): Promise<void> {\r\n if (!this.sessionPath) {\r\n return;\r\n }\r\n\r\n // Add timestamp if not present\r\n if (!message.timestamp) {\r\n message.timestamp = new Date().toISOString();\r\n }\r\n\r\n try {\r\n const line = JSON.stringify(message) + '\\n';\r\n\r\n if (existsSync(this.sessionPath)) {\r\n await appendFile(this.sessionPath, line, 'utf-8');\r\n } else {\r\n await writeFile(this.sessionPath, line, 'utf-8');\r\n }\r\n } catch (error) {\r\n throw new PAIError(\r\n 'Failed to write to session file',\r\n 4 as ExitCode,\r\n { path: this.sessionPath, error: String(error) }\r\n );\r\n }\r\n }\r\n\r\n /**\r\n * Append multiple messages to session file\r\n * TODO: Implement atomic write for concurrent access\r\n */\r\n async appendMessages(messages: Message[]): Promise<void> {\r\n if (!this.sessionPath || messages.length === 0) {\r\n return;\r\n }\r\n\r\n // Add timestamps to messages without them\r\n const timestampedMessages = messages.map((msg) => ({\r\n ...msg,\r\n timestamp: msg.timestamp || new Date().toISOString(),\r\n }));\r\n\r\n try {\r\n const lines = timestampedMessages.map((msg) => JSON.stringify(msg)).join('\\n') + '\\n';\r\n\r\n if (existsSync(this.sessionPath)) {\r\n await appendFile(this.sessionPath, lines, 'utf-8');\r\n } else {\r\n await writeFile(this.sessionPath, lines, 'utf-8');\r\n }\r\n } catch (error) {\r\n throw new PAIError(\r\n 'Failed to write to session file',\r\n 4 as ExitCode,\r\n { path: this.sessionPath, error: String(error) }\r\n );\r\n }\r\n }\r\n\r\n /**\r\n * Get the session file path\r\n */\r\n getSessionPath(): string | undefined {\r\n return this.sessionPath;\r\n }\r\n}\r\n","import { readFile } from 'node:fs/promises';\r\nimport type { InputSource, MessageContent, ExitCode } from './types.js';\r\nimport { PAIError } from './types.js';\r\n\r\n/**\r\n * Resolves user input from various sources\r\n */\r\nexport class InputResolver {\r\n /**\r\n * Resolve user input from message/stdin/file/images\r\n * Validates mutual exclusivity of input sources\r\n */\r\n async resolveUserInput(source: InputSource): Promise<MessageContent> {\r\n const sourceCount = [\r\n source.message !== undefined,\r\n source.stdin === true,\r\n source.file !== undefined,\r\n ].filter(Boolean).length;\r\n\r\n if (sourceCount > 1) {\r\n throw new PAIError(\r\n 'Multiple input sources specified',\r\n 1 as ExitCode,\r\n { message: 'Cannot use both positional argument and --input-file or stdin' }\r\n );\r\n }\r\n\r\n if (sourceCount === 0) {\r\n throw new PAIError(\r\n 'No user input provided',\r\n 1 as ExitCode,\r\n { message: 'Provide input via argument, stdin, or --input-file' }\r\n );\r\n }\r\n\r\n let textContent: string;\r\n\r\n // Resolve text content\r\n if (source.message !== undefined) {\r\n textContent = source.message;\r\n } else if (source.stdin) {\r\n textContent = await this.readStdin();\r\n } else if (source.file) {\r\n textContent = await this.readFile(source.file);\r\n } else {\r\n throw new PAIError('No input source available', 1 as ExitCode);\r\n }\r\n\r\n // Handle multimodal content (text + images)\r\n if (source.images && source.images.length > 0) {\r\n const content: any[] = [{ type: 'text', text: textContent }];\r\n\r\n for (const imagePath of source.images) {\r\n const imageData = await this.readImage(imagePath);\r\n content.push(imageData);\r\n }\r\n\r\n return content;\r\n }\r\n\r\n return textContent;\r\n }\r\n\r\n /**\r\n * Resolve system instruction from text or file\r\n */\r\n async resolveSystemInput(\r\n systemText?: string,\r\n systemFile?: string\r\n ): Promise<string | undefined> {\r\n if (systemText && systemFile) {\r\n throw new PAIError(\r\n 'Multiple system instruction sources specified',\r\n 1 as ExitCode,\r\n { message: 'Cannot use both --system and --system-file' }\r\n );\r\n }\r\n\r\n if (systemFile) {\r\n return await this.readFile(systemFile);\r\n }\r\n\r\n return systemText;\r\n }\r\n\r\n /**\r\n * Read from stdin\r\n */\r\n private async readStdin(): Promise<string> {\r\n return new Promise((resolve, reject) => {\r\n let data = '';\r\n\r\n process.stdin.setEncoding('utf-8');\r\n\r\n process.stdin.on('data', (chunk) => {\r\n data += chunk;\r\n });\r\n\r\n process.stdin.on('end', () => {\r\n resolve(data);\r\n });\r\n\r\n process.stdin.on('error', (error) => {\r\n reject(\r\n new PAIError(\r\n 'Failed to read from stdin',\r\n 4 as ExitCode,\r\n { error: String(error) }\r\n )\r\n );\r\n });\r\n });\r\n }\r\n\r\n /**\r\n * Read file content\r\n */\r\n private async readFile(path: string): Promise<string> {\r\n try {\r\n return await readFile(path, 'utf-8');\r\n } catch (error) {\r\n throw new PAIError(\r\n 'Failed to read file',\r\n 4 as ExitCode,\r\n { path, error: String(error) }\r\n );\r\n }\r\n }\r\n\r\n /**\r\n * Read image file and encode for pi-ai\r\n */\r\n private async readImage(path: string): Promise<object> {\r\n try {\r\n const buffer = await readFile(path);\r\n const base64Data = buffer.toString('base64');\r\n\r\n // Determine mime type from extension\r\n const ext = path.toLowerCase().split('.').pop();\r\n let mimeType = 'image/jpeg';\r\n\r\n if (ext === 'png') mimeType = 'image/png';\r\n else if (ext === 'gif') mimeType = 'image/gif';\r\n else if (ext === 'webp') mimeType = 'image/webp';\r\n\r\n return {\r\n type: 'image',\r\n data: base64Data,\r\n mimeType,\r\n };\r\n } catch (error) {\r\n throw new PAIError(\r\n 'Failed to read image file',\r\n 4 as ExitCode,\r\n { path, error: String(error) }\r\n );\r\n }\r\n }\r\n}\r\n","import { appendFile, writeFile } from 'node:fs/promises';\r\nimport { existsSync } from 'node:fs';\r\nimport type { OutputEvent, ExitCode } from './types.js';\r\nimport { PAIError } from './types.js';\r\nimport { sanitizeContent, sanitizeString } from './sanitize.js';\r\n\r\n/**\r\n * Handles output formatting for stdout/stderr\r\n */\r\nexport class OutputFormatter {\r\n private jsonMode: boolean;\r\n private quietMode: boolean;\r\n private logFile: string | undefined;\r\n\r\n constructor(jsonMode: boolean = false, quietMode: boolean = false, logFile?: string) {\r\n this.jsonMode = jsonMode;\r\n this.quietMode = quietMode;\r\n this.logFile = logFile;\r\n }\r\n\r\n /**\r\n * Write model output to stdout\r\n * Always writes to stdout regardless of mode\r\n */\r\n writeModelOutput(content: string): void {\r\n // NOTE: DON'T sanitize model output to avoid break caller behaviors\r\n process.stdout.write(content);\r\n\r\n // Also append to log file if specified\r\n if (this.logFile) {\r\n // sanitize when output to log file\r\n const { sanitized } = sanitizeString(content);\r\n this.appendToLog('assistant', sanitized).catch(() => {\r\n // Silently fail log writes to not interrupt main flow\r\n });\r\n }\r\n }\r\n\r\n /**\r\n * Write progress/diagnostic information to stderr\r\n */\r\n writeProgress(event: OutputEvent): void {\r\n // Skip if quiet mode\r\n if (this.quietMode) return;\r\n\r\n if (this.jsonMode) {\r\n // Sanitize event.data before serializing\r\n const sc = sanitizeContent(event.data);\r\n const outEvent = { ...event, data: sc.sanitized, timestamp: event.timestamp || Date.now() };\r\n this.writeNDJSON(outEvent as OutputEvent);\r\n } else {\r\n // Sanitize data for human readable output as well\r\n const sc = sanitizeContent(event.data);\r\n const outEvent = { ...event, data: sc.sanitized };\r\n this.writeHumanReadable(outEvent as OutputEvent);\r\n }\r\n }\r\n\r\n /**\r\n * Write error to stderr\r\n */\r\n writeError(error: Error | PAIError): void {\r\n if (this.jsonMode) {\r\n const errorObj = {\r\n type: 'error',\r\n message: sanitizeString(error.message).sanitized,\r\n ...(error instanceof PAIError && error.context ? { context: sanitizeContent(error.context).sanitized } : {}),\r\n };\r\n process.stderr.write(JSON.stringify(errorObj) + '\\n');\r\n } else {\r\n process.stderr.write(`Error: ${sanitizeString(error.message).sanitized}\\n`);\r\n if (error instanceof PAIError && error.context) {\r\n process.stderr.write(`Context: ${JSON.stringify(sanitizeContent(error.context).sanitized)}\\n`);\r\n }\r\n }\r\n\r\n // Also append to log file if specified \r\n if (this.logFile) {\r\n const msg = sanitizeString(error.message).sanitized;\r\n const ctx = error instanceof PAIError && error.context ? JSON.stringify(sanitizeContent(error.context).sanitized) : '{}';\r\n this.appendToLog('error', `${msg}\\n\\nContext: ${ctx}`).catch(() => {\r\n // Silently fail log writes to not interrupt main flow\r\n });\r\n }\r\n }\r\n\r\n /**\r\n * Write NDJSON event to stderr\r\n */\r\n private writeNDJSON(event: OutputEvent): void {\r\n const line = JSON.stringify({\r\n ...event,\r\n timestamp: event.timestamp || Date.now(),\r\n });\r\n process.stderr.write(line + '\\n');\r\n }\r\n\r\n /**\r\n * Write human-readable event to stderr\r\n */\r\n private writeHumanReadable(event: OutputEvent): void {\r\n switch (event.type) {\r\n case 'start': {\r\n const d = event.data;\r\n const parts = [`Starting request (${d.provider || '?'}/${d.model || '?'}`];\r\n if (d.messages) parts.push(`${d.messages} msgs`);\r\n if (d.tools) parts.push(`${d.tools} tools`);\r\n if (d.stream) parts.push('stream');\r\n process.stderr.write(parts.join(', ') + ')...\\n');\r\n break;\r\n }\r\n case 'chunk':\r\n // Don't output individual chunks in human mode\r\n break;\r\n case 'tool_call':\r\n process.stderr.write(`Tool call: ${JSON.stringify(event.data)}\\n`);\r\n break;\r\n case 'tool_result':\r\n process.stderr.write(`Tool result: ${JSON.stringify(event.data)}\\n`);\r\n break;\r\n case 'complete': {\r\n const d = event.data;\r\n const parts = ['Request complete'];\r\n if (d.finishReason) parts.push(`reason=${d.finishReason}`);\r\n if (d.usage) parts.push(`tokens: in=${d.usage.input} out=${d.usage.output}`);\r\n process.stderr.write(parts.join(', ') + '.\\n');\r\n break;\r\n }\r\n case 'error':\r\n process.stderr.write(`Error: ${event.data}\\n`);\r\n break;\r\n }\r\n }\r\n\r\n /**\r\n * Append to log file in Markdown format\r\n */\r\n private async appendToLog(role: string, content: string): Promise<void> {\r\n if (!this.logFile) return;\r\n\r\n try {\r\n const timestamp = new Date().toISOString();\r\n const entry = `\\n### ${role.charAt(0).toUpperCase() + role.slice(1)} (${timestamp})\\n\\n${content}\\n`;\r\n\r\n if (existsSync(this.logFile)) {\r\n await appendFile(this.logFile, entry, 'utf-8');\r\n } else {\r\n const header = `# Chat Log\\n\\nGenerated: ${timestamp}\\n`;\r\n await writeFile(this.logFile, header + entry, 'utf-8');\r\n }\r\n } catch (error) {\r\n throw new PAIError(\r\n 'Failed to write to log file',\r\n 4 as ExitCode,\r\n { path: this.logFile, error: String(error) }\r\n );\r\n }\r\n }\r\n\r\n /**\r\n * Log user message\r\n */\r\n async logUserMessage(content: string): Promise<void> {\r\n if (this.logFile) {\r\n await this.appendToLog('user', content).catch(() => {\r\n // Silently fail\r\n });\r\n }\r\n }\r\n\r\n /**\r\n * Log system message\r\n */\r\n async logSystemMessage(content: string): Promise<void> {\r\n if (this.logFile) {\r\n await this.appendToLog('system', content).catch(() => {\r\n // Silently fail\r\n });\r\n }\r\n }\r\n\r\n /**\r\n * Log request summary (provider, model, parameters)\r\n */\r\n async logRequestSummary(info: { provider: string; model: string; temperature?: number | undefined; maxTokens?: number | undefined; stream?: boolean | undefined }): Promise<void> {\r\n if (this.logFile) {\r\n const lines = [\r\n `Provider: ${info.provider}`,\r\n `Model: ${info.model}`,\r\n ];\r\n if (info.temperature !== undefined) lines.push(`Temperature: ${info.temperature}`);\r\n if (info.maxTokens !== undefined) lines.push(`Max Tokens: ${info.maxTokens}`);\r\n if (info.stream) lines.push(`Stream: true`);\r\n await this.appendToLog('request', lines.join('\\n')).catch(() => {});\r\n }\r\n }\r\n\r\n /**\r\n * Log tool call\r\n */\r\n async logToolCall(name: string, args: any): Promise<void> {\r\n if (this.logFile) {\r\n const content = `**Tool:** ${name}\\n\\`\\`\\`json\\n${JSON.stringify(args, null, 2)}\\n\\`\\`\\``;\r\n await this.appendToLog('tool_call', content).catch(() => {});\r\n }\r\n }\r\n\r\n /**\r\n * Log tool result\r\n */\r\n async logToolResult(name: string, result: any): Promise<void> {\r\n if (this.logFile) {\r\n const content = `**Tool:** ${name}\\n\\`\\`\\`json\\n${JSON.stringify(result, null, 2)}\\n\\`\\`\\``;\r\n await this.appendToLog('tool_result', content).catch(() => {});\r\n }\r\n }\r\n\r\n /**\r\n * Log error\r\n */\r\n async logError(error: Error | PAIError): Promise<void> {\r\n if (this.logFile) {\r\n const detail = error instanceof PAIError && error.context\r\n ? `\\n\\nContext: ${JSON.stringify(error.context)}`\r\n : '';\r\n await this.appendToLog('error', `${error.message}${detail}`).catch(() => {});\r\n }\r\n }\r\n}\r\n","// Centralized redaction utilities\n// Provides functions to sanitize strings and structured objects before\n// writing them to stdout/stderr or logs.\n\nconst SENSITIVE_KEYS = new Set([\n 'apikey', 'api_key', 'apiKey', 'access', 'access_token', 'refresh', 'refresh_token',\n 'token', 'oauth', 'client_secret', 'client-secret', 'secret', 'password', 'passwd', 'authorization', 'auth'\n]);\n\ntype SanitizeResult = { sanitized: any; secrets: string[] };\n\nfunction isObject(v: any): v is Record<string, any> {\n return v !== null && typeof v === 'object' && !Array.isArray(v);\n}\n\nfunction maskPartial(s: string, keep = 4): string {\n if (s.length <= keep * 2) return '*'.repeat(s.length);\n return s.slice(0, keep) + '*'.repeat(Math.max(0, s.length - keep * 2)) + s.slice(-keep);\n}\n\n// Common provider-specific and generic patterns\nconst PATTERNS: Array<{ re: RegExp; replace: (m: string) => string }> = [\n // URL query params like ?key=... or &token=...\n { re: /(https?:\\/\\/[^\\s]*?[?&](?:api_key|apikey|key|token|access_token|auth)=)([^&\\s]+)/gi, replace: (_m) => '***REDACTED***' },\n // OpenAI keys\n { re: /\\bsk-[A-Za-z0-9\\-_]{16,}\\b/g, replace: (m) => maskPartial(m, 6) },\n // Anthropic-ish\n { re: /\\bsk-ant-[A-Za-z0-9\\-_]{8,}\\b/g, replace: (m) => maskPartial(m, 6) },\n // HuggingFace\n { re: /\\bhf_[A-Za-z0-9\\-_]{16,}\\b/g, replace: (m) => maskPartial(m, 6) },\n // Bearer tokens (simple)\n { re: /\\bBearer\\s+[A-Za-z0-9\\-\\._=\\/+]{8,}\\b/gi, replace: () => 'Bearer ***REDACTED***' },\n // JWT-ish (three base64url parts)\n { re: /\\b[a-zA-Z0-9-_]{10,}\\.[a-zA-Z0-9-_]{10,}\\.[a-zA-Z0-9-_]{8,}\\b/g, replace: () => 'JWT <redacted>' },\n // Long base64-like strings (avoid short hashes)\n { re: /\\b[A-Za-z0-9+\\/]{40,}={0,2}\\b/g, replace: () => '***REDACTED***' },\n];\n\n/**\n * Redact sensitive substrings from a plain string using pattern matching.\n */\nexport function sanitizeString(input: string): { sanitized: string; secrets: string[] } {\n if (!input) return { sanitized: input, secrets: [] };\n\n let out = input;\n const found: string[] = [];\n\n // First handle URL param style with capture groups to preserve prefix\n out = out.replace(/(https?:\\/\\/[^\\s]*?[?&](?:api_key|apikey|key|token|access_token|auth)=)([^&\\s]+)/gi, (_, prefix, secret) => {\n found.push(secret);\n return prefix + '***REDACTED***';\n });\n\n for (const p of PATTERNS) {\n out = out.replace(p.re, (m) => {\n // Record the raw match as a discovered secret when it looks token-like\n found.push(m);\n try {\n return p.replace(m);\n } catch {\n return '***REDACTED***';\n }\n });\n }\n\n return { sanitized: out, secrets: found };\n}\n\n/**\n * Sanitize structured data (objects/arrays) by key name and by inspecting string values.\n */\nexport function sanitizeContent(value: any): SanitizeResult {\n const secrets: string[] = [];\n\n function _sanitize(v: any): any {\n if (v === null || v === undefined) return v;\n if (typeof v === 'string') {\n const { sanitized, secrets: s } = sanitizeString(v);\n secrets.push(...s);\n return sanitized;\n }\n if (Array.isArray(v)) {\n return v.map((item) => _sanitize(item));\n }\n if (isObject(v)) {\n const out: Record<string, any> = {};\n for (const [k, val] of Object.entries(v)) {\n try {\n if (SENSITIVE_KEYS.has(k.toLowerCase()) || SENSITIVE_KEYS.has(k)) {\n // Mask sensitive field values\n if (typeof val === 'string') {\n secrets.push(String(val));\n out[k] = '***REDACTED***';\n } else {\n out[k] = '***REDACTED***';\n }\n } else {\n out[k] = _sanitize(val);\n }\n } catch (e) {\n // On unexpected error, fall back to stringifying and sanitizing\n const str = String(val);\n const { sanitized, secrets: s } = sanitizeString(str);\n secrets.push(...s);\n out[k] = sanitized;\n }\n }\n return out;\n }\n // primitives\n return v;\n }\n\n const sanitized = _sanitize(value);\n return { sanitized, secrets };\n}\n\nexport default { sanitizeString, sanitizeContent };\n","import { getModel, stream, complete, type Model, type Api } from '@mariozechner/pi-ai';\r\nimport type { LLMClientConfig, Message, Tool, ToolCall, LLMResponse } from './types.js';\r\n\r\n/**\r\n * Build a pi-ai Model object from PAI provider config + runtime overrides.\r\n * If the provider is a known pi-ai provider with pre-registered models, use getModel().\r\n * Otherwise, construct a custom Model object for custom/Azure/self-hosted endpoints.\r\n */\r\nfunction buildModel(config: LLMClientConfig): Model<any> {\r\n // If provider config specifies an api type, build a custom model\r\n if (config.api) {\r\n return {\r\n id: config.model,\r\n name: config.model,\r\n api: config.api as Api,\r\n provider: config.provider,\r\n baseUrl: config.baseUrl || '',\r\n reasoning: config.reasoning ?? false,\r\n input: (config.input as any) ?? ['text'],\r\n cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },\r\n contextWindow: config.contextWindow ?? 128000,\r\n maxTokens: config.maxTokens ?? 16384,\r\n } as Model<any>;\r\n }\r\n\r\n // Fall back to pi-ai's built-in model registry\r\n try {\r\n return getModel(config.provider as any, config.model as any);\r\n } catch {\r\n // If getModel fails, try building a custom model with openai-completions as default\r\n return {\r\n id: config.model,\r\n name: config.model,\r\n api: 'openai-completions' as Api,\r\n provider: config.provider,\r\n baseUrl: config.baseUrl || '',\r\n reasoning: false,\r\n input: ['text'],\r\n cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },\r\n contextWindow: 128000,\r\n maxTokens: 16384,\r\n } as Model<any>;\r\n }\r\n}\r\n\r\n/**\r\n * LLM Client wrapper for pi-ai library\r\n */\r\nexport class LLMClient {\r\n private config: LLMClientConfig;\r\n private model: Model<any>;\r\n\r\n constructor(config: LLMClientConfig) {\r\n this.config = config;\r\n this.model = buildModel(config);\r\n }\r\n\r\n /**\r\n * Chat with streaming responses\r\n */\r\n async *chat(messages: Message[], tools?: Tool[]): AsyncGenerator<LLMResponse> {\r\n const context = this.buildContext(messages, tools);\r\n const options = this.buildOptions();\r\n\r\n const streamResult = stream(this.model, context, options);\r\n\r\n let currentContent = '';\r\n let currentToolCalls: ToolCall[] = [];\r\n\r\n for await (const event of streamResult) {\r\n switch (event.type) {\r\n case 'text_delta':\r\n currentContent += event.delta;\r\n yield {\r\n content: event.delta,\r\n finishReason: 'streaming',\r\n };\r\n break;\r\n\r\n case 'toolcall_end':\r\n currentToolCalls.push({\r\n id: event.toolCall.id,\r\n name: event.toolCall.name,\r\n arguments: event.toolCall.arguments,\r\n });\r\n break;\r\n\r\n case 'done': {\r\n const usageData = (event as any).usage;\r\n const doneResponse: LLMResponse = {\r\n content: currentContent,\r\n finishReason: event.reason,\r\n ...(usageData ? {\r\n usage: {\r\n input: usageData.input ?? 0,\r\n output: usageData.output ?? 0,\r\n ...(usageData.cost ? { cost: { total: usageData.cost.total ?? 0 } } : {}),\r\n },\r\n } : {}),\r\n };\r\n if (currentToolCalls.length > 0) {\r\n doneResponse.toolCalls = currentToolCalls;\r\n }\r\n yield doneResponse;\r\n break;\r\n }\r\n\r\n case 'error':\r\n throw new Error(event.error.errorMessage || 'LLM request failed');\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Chat without streaming (complete response)\r\n */\r\n async chatComplete(messages: Message[], tools?: Tool[]): Promise<LLMResponse> {\r\n const context = this.buildContext(messages, tools);\r\n const options = this.buildOptions();\r\n\r\n const result = await complete(this.model, context, options);\r\n\r\n // Extract text content\r\n let content = '';\r\n const toolCalls: ToolCall[] = [];\r\n\r\n for (const block of result.content) {\r\n if (block.type === 'text') {\r\n content += block.text;\r\n } else if (block.type === 'toolCall') {\r\n toolCalls.push({\r\n id: block.id,\r\n name: block.name,\r\n arguments: block.arguments,\r\n });\r\n }\r\n }\r\n\r\n const response: LLMResponse = {\r\n content,\r\n finishReason: result.stopReason,\r\n ...(result.usage ? {\r\n usage: {\r\n input: result.usage.input ?? 0,\r\n output: result.usage.output ?? 0,\r\n ...(result.usage.cost ? { cost: { total: result.usage.cost.total ?? 0 } } : {}),\r\n },\r\n } : {}),\r\n };\r\n if (toolCalls.length > 0) {\r\n response.toolCalls = toolCalls;\r\n }\r\n\r\n return response;\r\n }\r\n\r\n /**\r\n * Build context for pi-ai\r\n */\r\n private buildContext(messages: Message[], tools?: Tool[]) {\r\n // Convert messages to pi-ai format\r\n const piMessages = messages.map((msg) => {\r\n if (msg.role === 'system') {\r\n return { role: 'system' as const, content: String(msg.content) };\r\n } else if (msg.role === 'user') {\r\n return { role: 'user' as const, content: this.formatContent(msg.content), timestamp: Date.now() };\r\n } else if (msg.role === 'assistant') {\r\n return this.buildAssistantMessage(msg);\r\n } else if (msg.role === 'tool') {\r\n return {\r\n role: 'toolResult' as const,\r\n toolCallId: msg.tool_call_id || '',\r\n toolName: msg.name || '',\r\n content: [{ type: 'text' as const, text: String(msg.content) }],\r\n isError: false,\r\n timestamp: Date.now(),\r\n };\r\n }\r\n return { role: 'user' as const, content: String(msg.content), timestamp: Date.now() };\r\n });\r\n\r\n // Extract system prompt if first message is system\r\n let systemPrompt: string | undefined;\r\n let contextMessages = piMessages;\r\n\r\n if (piMessages.length > 0 && piMessages[0]?.role === 'system') {\r\n systemPrompt = String(piMessages[0].content);\r\n contextMessages = piMessages.slice(1);\r\n }\r\n\r\n const context: any = {\r\n messages: contextMessages,\r\n };\r\n\r\n if (systemPrompt) {\r\n context.systemPrompt = systemPrompt;\r\n }\r\n\r\n // Add tools if provided\r\n if (tools && tools.length > 0) {\r\n context.tools = tools.map((tool) => ({\r\n name: tool.name,\r\n description: tool.description,\r\n parameters: tool.parameters,\r\n }));\r\n }\r\n\r\n return context;\r\n }\r\n\r\n /**\r\n * Build a pi-ai AssistantMessage from a PAI Message.\r\n * pi-ai expects assistant messages with content as an array of typed blocks.\r\n */\r\n private buildAssistantMessage(msg: Message) {\r\n const contentBlocks: any[] = [];\r\n const textContent = typeof msg.content === 'string' ? msg.content : JSON.stringify(msg.content);\r\n if (textContent) {\r\n contentBlocks.push({ type: 'text', text: textContent });\r\n }\r\n const toolCalls = (msg as any).tool_calls;\r\n if (toolCalls && Array.isArray(toolCalls)) {\r\n for (const tc of toolCalls) {\r\n contentBlocks.push({\r\n type: 'toolCall',\r\n id: tc.id,\r\n name: tc.name,\r\n arguments: tc.arguments,\r\n });\r\n }\r\n }\r\n return {\r\n role: 'assistant' as const,\r\n content: contentBlocks,\r\n api: this.model.api,\r\n provider: this.model.provider,\r\n model: this.model.id,\r\n usage: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, totalTokens: 0, cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 } },\r\n stopReason: (toolCalls ? 'toolUse' : 'stop') as 'toolUse' | 'stop',\r\n timestamp: Date.now(),\r\n };\r\n }\r\n\r\n /**\r\n * Format message content for pi-ai\r\n */\r\n private formatContent(content: any): any {\r\n if (typeof content === 'string') {\r\n return content;\r\n }\r\n if (Array.isArray(content)) {\r\n return content;\r\n }\r\n if (typeof content === 'object') {\r\n return JSON.stringify(content);\r\n }\r\n return String(content);\r\n }\r\n\r\n /**\r\n * Build options for pi-ai, including provider-specific options\r\n */\r\n private buildOptions() {\r\n const options: any = {\r\n apiKey: this.config.apiKey,\r\n };\r\n\r\n if (this.config.temperature !== undefined) {\r\n options.temperature = this.config.temperature;\r\n }\r\n\r\n if (this.config.maxTokens !== undefined) {\r\n options.maxTokens = this.config.maxTokens;\r\n }\r\n\r\n // Merge provider-specific options (e.g. azureApiVersion, azureBaseUrl, azureDeploymentName)\r\n if (this.config.providerOptions) {\r\n Object.assign(options, this.config.providerOptions);\r\n }\r\n\r\n return options;\r\n }\r\n\r\n /**\r\n * Get model information\r\n */\r\n getModel(): Model<any> {\r\n return this.model;\r\n }\r\n}\r\n","import { exec, execSync } from 'node:child_process';\r\nimport { platform } from 'node:os';\r\nimport type { Tool, BashExecArgs, BashExecResult } from '../types.js';\r\n\r\n// MAX LENGTH in MB that bash_exec tool can output to LLM\r\nconst BASH_EXEC_TOOL_MAX_OUTPUT_MB = 8;\r\n// MAX TIMEOUT in seconds for bash_exec tool\r\nconst BASH_EXEC_TOOL_MAX_TIMEOUT_S = 3600;\r\n\r\n/**\r\n * Detect the bash shell path.\r\n *\r\n * On non-Windows platforms, always returns 'bash'.\r\n *\r\n * On Windows (platform() === 'win32'), the process may still be running\r\n * inside a bash-compatible environment (Git Bash, MSYS2, Cygwin, WSL, etc.).\r\n * Detection order:\r\n * 1. SHELL env var — set by Git Bash / MSYS2 / Cygwin (e.g. '/usr/bin/bash')\r\n * 2. Probe 'bash --version' — catches bash on PATH without SHELL being set\r\n * 3. Throw — cmd.exe is NOT supported; user must install bash\r\n */\r\nexport function detectShell(): string {\r\n const isWin32 = platform() === 'win32';\r\n\r\n if (!isWin32) {\r\n return 'bash';\r\n }\r\n\r\n // 1. Check SHELL env (Git Bash / MSYS2 / Cygwin set this)\r\n const shellEnv = process.env.SHELL;\r\n if (shellEnv && /bash/i.test(shellEnv)) {\r\n return shellEnv;\r\n }\r\n\r\n // 2. Probe for bash on PATH\r\n try {\r\n execSync('bash --version', { stdio: 'ignore', timeout: 3000 });\r\n return 'bash';\r\n } catch {\r\n // bash not available\r\n }\r\n\r\n // 3. No bash found — refuse to fall back to cmd.exe\r\n throw new Error(\r\n 'bash is required but was not found on this Windows system. ' +\r\n 'Please install one of: Git Bash, MSYS2, Cygwin, or use WSL2.',\r\n );\r\n}\r\n\r\nconst BASH_EXEC_DESCRIPTION = \r\n'Execute a shell command and return the result. Supports pipes, redirections, xargs, heredocs, and shell scripts. Use cwd parameter to set working directory. Running on bash.'\r\n\r\n/**\r\n * Create bash_exec tool for LLM to execute shell commands\r\n *\r\n * This tool allows the LLM to run shell commands with full support for:\r\n * - Pipes and redirections\r\n * - xargs\r\n * - Heredoc\r\n * - Shell scripts\r\n * - Working directory (cwd parameter)\r\n *\r\n * Shell: always bash (including on Windows via Git Bash / MSYS2 / Cygwin / WSL2).\r\n * cmd.exe is NOT supported.\r\n *\r\n * No security restrictions are implemented - user responsibility\r\n * Interactive commands are not supported\r\n */\r\nexport function createBashExecTool(): Tool {\r\n const shell = detectShell();\r\n\r\n return {\r\n name: 'bash_exec',\r\n description: BASH_EXEC_DESCRIPTION,\r\n parameters: {\r\n type: 'object',\r\n properties: {\r\n command: {\r\n type: 'string',\r\n description:\r\n 'The shell command to execute. Supports bash syntax including pipes, redirections, xargs, heredocs, etc.',\r\n },\r\n cwd: {\r\n type: 'string',\r\n description: 'Optional working directory for command execution',\r\n },\r\n comment: {\r\n type: 'string',\r\n description:\r\n 'very short briefing about intention and reason of this tool call, improve observability and auditability to the user.'\r\n }\r\n },\r\n required: ['command','comment'],\r\n },\r\n handler: async (args: BashExecArgs): Promise<BashExecResult> => {\r\n // Guard against empty command\r\n if (!args.command) {\r\n return {\r\n stdout: '',\r\n stderr: 'Error: empty command',\r\n exitCode: 1,\r\n };\r\n }\r\n\r\n return new Promise((resolve) => {\r\n const options: any = {\r\n shell,\r\n maxBuffer: BASH_EXEC_TOOL_MAX_OUTPUT_MB * 1024 * 1024,\r\n timeout: BASH_EXEC_TOOL_MAX_TIMEOUT_S * 1000,\r\n encoding: 'buffer',\r\n };\r\n\r\n if (args.cwd) {\r\n options.cwd = args.cwd;\r\n }\r\n\r\n exec(args.command, options, (error: any, stdout: Buffer, stderr: Buffer) => {\r\n const stdoutBuf = stdout || Buffer.alloc(0);\r\n const stderrBuf = stderr || Buffer.alloc(0);\r\n\r\n resolve({\r\n stdout: stdoutBuf.toString('utf-8'),\r\n stderr: stderrBuf.toString('utf-8'),\r\n exitCode: error ? (error.code ?? 1) : 0,\r\n });\r\n });\r\n });\r\n },\r\n };\r\n}\r\n","import type { Tool } from './types.js';\r\nimport { createBashExecTool } from './tools/bash-exec.js';\r\n\r\n/**\r\n * Registry for managing tools available to the LLM\r\n */\r\nexport class ToolRegistry {\r\n private tools: Map<string, Tool>;\r\n\r\n constructor() {\r\n this.tools = new Map();\r\n this.registerBuiltinTools();\r\n }\r\n\r\n /**\r\n * Register built-in tools\r\n */\r\n private registerBuiltinTools(): void {\r\n this.register(createBashExecTool());\r\n }\r\n\r\n /**\r\n * Register a tool\r\n */\r\n register(tool: Tool): void {\r\n this.tools.set(tool.name, tool);\r\n }\r\n\r\n /**\r\n * Get a tool by name\r\n */\r\n get(name: string): Tool | undefined {\r\n return this.tools.get(name);\r\n }\r\n\r\n /**\r\n * Get all registered tools\r\n */\r\n getAll(): Tool[] {\r\n return Array.from(this.tools.values());\r\n }\r\n\r\n /**\r\n * Execute a tool by name with arguments\r\n */\r\n async execute(name: string, args: any): Promise<any> {\r\n const tool = this.get(name);\r\n if (!tool) {\r\n throw new Error(`Tool not found: ${name}`);\r\n }\r\n return await tool.handler(args);\r\n }\r\n\r\n /**\r\n * Check if a tool exists\r\n */\r\n has(name: string): boolean {\r\n return this.tools.has(name);\r\n }\r\n\r\n /**\r\n * Get tool count\r\n */\r\n size(): number {\r\n return this.tools.size;\r\n }\r\n}\r\n","import type { ChatOptions, Message, LLMResponse } from '../types.js';\r\nimport { PAIError } from '../types.js';\r\nimport { ConfigurationManager } from '../config-manager.js';\r\nimport { SessionManager } from '../session-manager.js';\r\nimport { InputResolver } from '../input-resolver.js';\r\nimport { OutputFormatter } from '../output-formatter.js';\r\nimport { LLMClient } from '../llm-client.js';\r\nimport { ToolRegistry } from '../tool-registry.js';\r\nimport { getModels } from '@mariozechner/pi-ai';\r\n\r\nconst DEFAULT_MAX_TURNS = 100; // Prevent infinite loops\r\n\r\n/**\r\n * Handle the chat command\r\n */\r\nexport async function handleChatCommand(\r\n prompt: string | undefined,\r\n options: ChatOptions\r\n): Promise<void> {\r\n // Initialize components\r\n const configManager = new ConfigurationManager(options);\r\n const sessionManager = new SessionManager(options.session);\r\n const inputResolver = new InputResolver();\r\n const outputFormatter = new OutputFormatter(\r\n options.json,\r\n options.quiet,\r\n options.log\r\n );\r\n const toolRegistry = new ToolRegistry();\r\n\r\n try {\r\n // Validate model parameters\r\n if (options.temperature !== undefined) {\r\n if (isNaN(options.temperature) || !isFinite(options.temperature)) {\r\n throw new PAIError(\r\n 'Invalid temperature value',\r\n 1,\r\n { temperature: options.temperature, message: 'Temperature must be a finite number' }\r\n );\r\n }\r\n if (options.temperature < 0 || options.temperature > 2) {\r\n throw new PAIError(\r\n 'Invalid temperature value',\r\n 1,\r\n { temperature: options.temperature, message: 'Temperature must be between 0 and 2' }\r\n );\r\n }\r\n }\r\n\r\n if (options.maxTokens !== undefined) {\r\n if (isNaN(options.maxTokens) || !isFinite(options.maxTokens)) {\r\n throw new PAIError(\r\n 'Invalid maxTokens value',\r\n 1,\r\n { maxTokens: options.maxTokens, message: 'maxTokens must be a finite number' }\r\n );\r\n }\r\n if (options.maxTokens <= 0) {\r\n throw new PAIError(\r\n 'Invalid maxTokens value',\r\n 1,\r\n { maxTokens: options.maxTokens, message: 'maxTokens must be greater than 0' }\r\n );\r\n }\r\n }\r\n\r\n // Load configuration and resolve credentials\r\n const provider = await configManager.getProvider(options.provider);\r\n let modelName = options.model || provider.defaultModel || provider.models?.[0];\r\n\r\n // Fall back to pi-ai's known models for this provider\r\n if (!modelName) {\r\n try {\r\n const knownModels = getModels(provider.name as any);\r\n if (knownModels.length > 0) {\r\n modelName = knownModels[0]!.id;\r\n }\r\n } catch {\r\n // Provider not recognized by pi-ai, ignore\r\n }\r\n }\r\n\r\n if (!modelName) {\r\n throw new PAIError(\r\n 'No model specified',\r\n 1,\r\n { provider: provider.name, message: 'Specify --model or configure a default model' }\r\n );\r\n }\r\n\r\n const apiKey = await configManager.resolveCredentials(provider.name, undefined);\r\n\r\n // --dry-run: show resolved config and exit\r\n if (options.dryRun) {\r\n const info = {\r\n provider: provider.name,\r\n model: modelName,\r\n configFile: configManager.getConfigPath(),\r\n temperature: options.temperature ?? provider.temperature,\r\n maxTokens: options.maxTokens ?? provider.maxTokens,\r\n stream: options.stream ?? false,\r\n credentialSource: 'resolved',\r\n };\r\n process.stderr.write(JSON.stringify(info, null, 2) + '\\n');\r\n return;\r\n }\r\n\r\n // Initialize LLM client\r\n const llmClient = new LLMClient({\r\n provider: provider.name,\r\n model: modelName,\r\n apiKey,\r\n temperature: options.temperature ?? provider.temperature,\r\n maxTokens: options.maxTokens ?? provider.maxTokens,\r\n stream: options.stream,\r\n api: provider.api,\r\n baseUrl: provider.baseUrl,\r\n reasoning: provider.reasoning,\r\n input: provider.input,\r\n contextWindow: provider.contextWindow,\r\n providerOptions: provider.providerOptions,\r\n });\r\n\r\n // Load session history\r\n const messages: Message[] = await sessionManager.loadMessages();\r\n const loadedMessageCount = messages.length;\r\n\r\n // Track new messages to append to session file\r\n const newMessages: Message[] = [];\r\n\r\n // Resolve system instruction\r\n const systemInstruction = await inputResolver.resolveSystemInput(\r\n options.system,\r\n options.systemFile\r\n );\r\n\r\n // Add or update system message\r\n if (systemInstruction) {\r\n if (messages.length > 0 && messages[0]?.role === 'system') {\r\n // Replace existing system message (already in session file, no need to append)\r\n messages[0] = { role: 'system', content: systemInstruction };\r\n } else {\r\n // Add new system message at the beginning\r\n const sysMsg: Message = { role: 'system', content: systemInstruction };\r\n messages.unshift(sysMsg);\r\n newMessages.push(sysMsg);\r\n }\r\n await outputFormatter.logSystemMessage(systemInstruction);\r\n }\r\n\r\n // Resolve user input\r\n // Only use stdin if: not a TTY AND no other input source provided\r\n const hasExplicitInput = prompt !== undefined || options.inputFile !== undefined;\r\n const stdinAvailable = !process.stdin.isTTY && !hasExplicitInput;\r\n const userInput = await inputResolver.resolveUserInput({\r\n message: prompt,\r\n stdin: stdinAvailable,\r\n file: options.inputFile,\r\n images: options.image,\r\n });\r\n\r\n // Add or update user message\r\n const userMessage: Message = { role: 'user', content: userInput };\r\n \r\n // If the last loaded message was a user message, replace it (already in session file)\r\n // Otherwise add as new message\r\n const lastLoadedIsUser = loadedMessageCount > 0 && messages[messages.length - 1]?.role === 'user';\r\n if (lastLoadedIsUser) {\r\n messages[messages.length - 1] = userMessage;\r\n } else {\r\n messages.push(userMessage);\r\n newMessages.push(userMessage);\r\n }\r\n\r\n await outputFormatter.logUserMessage(\r\n typeof userInput === 'string' ? userInput : JSON.stringify(userInput)\r\n );\r\n\r\n // Log request summary\r\n await outputFormatter.logRequestSummary({\r\n provider: provider.name,\r\n model: modelName,\r\n temperature: options.temperature ?? provider.temperature,\r\n maxTokens: options.maxTokens ?? provider.maxTokens,\r\n stream: options.stream,\r\n });\r\n\r\n // Get all tools\r\n const tools = toolRegistry.getAll();\r\n\r\n // Execute chat with tool calling loop\r\n let continueLoop = true;\r\n let maxTurns = options.maxTurns ?? DEFAULT_MAX_TURNS;\r\n const turnsLimit = maxTurns; // remember original for messages\r\n let finalRoundAttempted = false;\r\n\r\n // Compute content lengths for diagnostics\r\n const systemMsg = messages.find(m => m.role === 'system');\r\n const userMsg = [...messages].reverse().find(m => m.role === 'user');\r\n const systemChars = systemMsg ? String(systemMsg.content).length : 0;\r\n const userChars = userMsg ? (typeof userMsg.content === 'string' ? userMsg.content.length : JSON.stringify(userMsg.content).length) : 0;\r\n\r\n while (continueLoop && maxTurns > 0) {\r\n maxTurns--;\r\n\r\n // On the last allowed turn, withhold tools so the model is\r\n // forced to reply with text instead of requesting more tool calls.\r\n const isLastTurn = maxTurns === 0;\r\n const currentTools = isLastTurn ? [] : tools;\r\n\r\n if (isLastTurn) {\r\n process.stderr.write(\r\n `[Info] Approaching tool-call turn limit. Requesting final text response from model.\\n`\r\n );\r\n }\r\n\r\n outputFormatter.writeProgress({ type: 'start', data: {\r\n provider: provider.name,\r\n model: modelName,\r\n stream: options.stream ?? false,\r\n messages: messages.length,\r\n systemChars,\r\n userChars,\r\n tools: currentTools.length,\r\n } });\r\n\r\n let assistantMessage: Message;\r\n let lastResponse: LLMResponse | undefined;\r\n\r\n if (options.stream) {\r\n // Streaming mode\r\n let fullContent = '';\r\n const toolCalls: any[] = [];\r\n\r\n for await (const response of llmClient.chat(messages, currentTools)) {\r\n if (response.content && response.finishReason === 'streaming') {\r\n fullContent += response.content;\r\n outputFormatter.writeModelOutput(response.content);\r\n }\r\n\r\n if (response.finishReason !== 'streaming') {\r\n // Final response\r\n lastResponse = response;\r\n if (response.toolCalls) {\r\n toolCalls.push(...response.toolCalls);\r\n }\r\n }\r\n }\r\n\r\n assistantMessage = {\r\n role: 'assistant',\r\n content: fullContent,\r\n };\r\n\r\n // Add tool calls to message if any\r\n if (toolCalls.length > 0) {\r\n (assistantMessage as any).tool_calls = toolCalls;\r\n }\r\n } else {\r\n // Non-streaming mode\r\n const response = await llmClient.chatComplete(messages, currentTools);\r\n lastResponse = response;\r\n \r\n outputFormatter.writeModelOutput(response.content);\r\n\r\n assistantMessage = {\r\n role: 'assistant',\r\n content: response.content,\r\n };\r\n\r\n if (response.toolCalls) {\r\n (assistantMessage as any).tool_calls = response.toolCalls;\r\n }\r\n }\r\n\r\n messages.push(assistantMessage);\r\n newMessages.push(assistantMessage);\r\n\r\n outputFormatter.writeProgress({ type: 'complete', data: {\r\n finishReason: lastResponse?.finishReason ?? 'unknown',\r\n usage: lastResponse?.usage,\r\n } });\r\n\r\n // Handle tool calls\r\n const toolCalls = (assistantMessage as any).tool_calls;\r\n \r\n if (toolCalls && toolCalls.length > 0) {\r\n for (const toolCall of toolCalls) {\r\n outputFormatter.writeProgress({\r\n type: 'tool_call',\r\n data: { name: toolCall.name, arguments: toolCall.arguments },\r\n });\r\n\r\n await outputFormatter.logToolCall(toolCall.name, toolCall.arguments);\r\n\r\n // If we've exhausted turns, reject remaining tool calls\r\n // and let the loop exit naturally on the next condition check.\r\n if (maxTurns <= 0) {\r\n const rejectContent = `Error: Tool-call turn limit (${turnsLimit}) reached. Please provide a final text summary without further tool calls.`;\r\n const rejectMessage: Message = {\r\n role: 'tool',\r\n name: toolCall.name,\r\n tool_call_id: toolCall.id,\r\n content: rejectContent,\r\n };\r\n messages.push(rejectMessage);\r\n newMessages.push(rejectMessage);\r\n\r\n outputFormatter.writeProgress({\r\n type: 'tool_result',\r\n data: { error: rejectContent },\r\n });\r\n await outputFormatter.logToolResult(toolCall.name, { error: rejectContent });\r\n continue;\r\n }\r\n\r\n try {\r\n const result = await toolRegistry.execute(\r\n toolCall.name,\r\n toolCall.arguments\r\n );\r\n\r\n const toolResultMessage: Message = {\r\n role: 'tool',\r\n name: toolCall.name,\r\n tool_call_id: toolCall.id,\r\n content: JSON.stringify(result),\r\n };\r\n\r\n messages.push(toolResultMessage);\r\n newMessages.push(toolResultMessage);\r\n\r\n outputFormatter.writeProgress({\r\n type: 'tool_result',\r\n data: result,\r\n });\r\n\r\n await outputFormatter.logToolResult(toolCall.name, result);\r\n } catch (error) {\r\n const errorMessage: Message = {\r\n role: 'tool',\r\n name: toolCall.name,\r\n tool_call_id: toolCall.id,\r\n content: `Error: ${error instanceof Error ? error.message : String(error)}`,\r\n };\r\n\r\n messages.push(errorMessage);\r\n newMessages.push(errorMessage);\r\n\r\n outputFormatter.writeProgress({\r\n type: 'tool_result',\r\n data: { error: String(error) },\r\n });\r\n\r\n await outputFormatter.logToolResult(toolCall.name, { error: String(error) });\r\n }\r\n }\r\n\r\n // If tool calls were rejected due to turn limit, do one\r\n // final round without tools so the model produces a text reply.\r\n if (maxTurns <= 0) {\r\n if (finalRoundAttempted) {\r\n // Already tried a final round — model keeps returning tool calls.\r\n // Force exit to prevent infinite loop.\r\n process.stderr.write(\r\n `[Warning] Model continues to request tool calls after final round. Stopping.\\n`\r\n );\r\n continueLoop = false;\r\n } else {\r\n finalRoundAttempted = true;\r\n process.stderr.write(\r\n `[Warning] Tool-call turn limit (${turnsLimit}) reached. Making one final request for a text summary.\\n`\r\n );\r\n // Allow one more turn, but tools are already withheld\r\n // because isLastTurn will be true (maxTurns is 0).\r\n maxTurns = 1;\r\n }\r\n }\r\n\r\n // Continue loop to get model's response after tool execution\r\n continueLoop = true;\r\n } else {\r\n // No tool calls, we're done\r\n continueLoop = false;\r\n }\r\n }\r\n\r\n // Save session if not disabled — only append new messages from this invocation\r\n // Commander.js parses --no-append as options.append = false\r\n if (options.append !== false && sessionManager.getSessionPath()) {\r\n await sessionManager.appendMessages(newMessages);\r\n }\r\n\r\n } catch (error) {\r\n if (error instanceof PAIError) {\r\n await outputFormatter.logError(error);\r\n outputFormatter.writeError(error);\r\n process.exit(error.exitCode);\r\n } else {\r\n const paiError = new PAIError(\r\n error instanceof Error ? error.message : String(error),\r\n 2,\r\n { originalError: String(error) }\r\n );\r\n await outputFormatter.logError(paiError);\r\n outputFormatter.writeError(paiError);\r\n process.exit(2);\r\n }\r\n }\r\n}\r\n","/**\r\n * Embedding API client for OpenAI-compatible endpoints.\r\n * Calls provider HTTP endpoints directly since pi-ai doesn't support embeddings.\r\n */\r\n\r\nimport { PAIError, ExitCode } from './types.js';\r\n\r\n// ---------------------------------------------------------------------------\r\n// Types\r\n// ---------------------------------------------------------------------------\r\n\r\nexport interface EmbeddingRequest {\r\n texts: string[];\r\n model: string;\r\n}\r\n\r\nexport interface EmbeddingResponse {\r\n embeddings: number[][];\r\n model: string;\r\n usage: {\r\n promptTokens: number;\r\n totalTokens: number;\r\n };\r\n}\r\n\r\nexport interface EmbeddingClientConfig {\r\n provider: string;\r\n apiKey: string;\r\n model: string;\r\n baseUrl?: string;\r\n providerOptions?: Record<string, any>;\r\n /** The API type, e.g. 'azure-openai-responses' */\r\n api?: string;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Provider default base URLs\r\n// ---------------------------------------------------------------------------\r\n\r\nconst PROVIDER_DEFAULT_BASE_URLS: Record<string, string> = {\r\n openai: 'https://api.openai.com',\r\n};\r\n\r\n// ---------------------------------------------------------------------------\r\n// EmbeddingClient\r\n// ---------------------------------------------------------------------------\r\n\r\nexport class EmbeddingClient {\r\n private readonly endpoint: string;\r\n private readonly apiKey: string;\r\n private readonly model: string;\r\n private readonly isAzure: boolean;\r\n\r\n constructor(config: EmbeddingClientConfig) {\r\n this.apiKey = config.apiKey;\r\n this.model = config.model;\r\n const apiType = config.api ?? config.provider;\r\n this.isAzure = apiType === 'azure-openai-responses' || apiType === 'azure-openai';\r\n this.endpoint = this.isAzure\r\n ? EmbeddingClient.resolveAzureEndpoint(config.baseUrl, config.model, config.providerOptions)\r\n : EmbeddingClient.resolveEndpoint(config.provider, config.baseUrl);\r\n }\r\n\r\n /**\r\n * Resolve the full embeddings API endpoint URL.\r\n * If baseUrl is provided, use it; otherwise fall back to the provider default.\r\n */\r\n static resolveEndpoint(provider: string, baseUrl?: string): string {\r\n const base =\r\n baseUrl ?? (Object.hasOwn(PROVIDER_DEFAULT_BASE_URLS, provider) ? PROVIDER_DEFAULT_BASE_URLS[provider] : undefined);\r\n if (!base) {\r\n throw new PAIError(\r\n `No base URL configured for provider \"${provider}\". Please specify a baseUrl.`,\r\n ExitCode.PARAMETER_ERROR,\r\n { provider },\r\n );\r\n }\r\n // Strip trailing slash before appending path\r\n return `${base.replace(/\\/+$/, '')}/v1/embeddings`;\r\n }\r\n\r\n /**\r\n * Resolve the Azure OpenAI embeddings endpoint URL.\r\n * Azure format: {baseUrl}/openai/deployments/{deployment}/embeddings?api-version={version}\r\n */\r\n static resolveAzureEndpoint(baseUrl?: string, model?: string, providerOptions?: Record<string, any>): string {\r\n if (!baseUrl) {\r\n throw new PAIError(\r\n 'Azure OpenAI requires a baseUrl. Please specify a baseUrl.',\r\n ExitCode.PARAMETER_ERROR,\r\n );\r\n }\r\n // For embeddings, use the model name as deployment name (embedding deployments\r\n // are typically named after the model). azureDeploymentName in providerOptions\r\n // usually refers to the chat model deployment, not the embedding one.\r\n const deployment = model ?? providerOptions?.azureDeploymentName;\r\n if (!deployment) {\r\n throw new PAIError(\r\n 'Azure OpenAI requires a deployment name. Specify a model or set providerOptions.azureDeploymentName.',\r\n ExitCode.PARAMETER_ERROR,\r\n );\r\n }\r\n const apiVersion = providerOptions?.azureApiVersion;\r\n // If azureApiVersion looks invalid (e.g. \"v1\"), fall back to a known good default\r\n const resolvedVersion = (apiVersion && /^\\d{4}-\\d{2}-\\d{2}/.test(apiVersion))\r\n ? apiVersion\r\n : '2024-06-01';\r\n // Strip any /openai/v1 or trailing path from baseUrl to get the resource root\r\n const resourceBase = baseUrl.replace(/\\/openai\\/v1\\/?$/, '').replace(/\\/+$/, '');\r\n return `${resourceBase}/openai/deployments/${deployment}/embeddings?api-version=${resolvedVersion}`;\r\n }\r\n\r\n /**\r\n * Call the embedding API for the given texts.\r\n */\r\n async embed(request: EmbeddingRequest): Promise<EmbeddingResponse> {\r\n const body = JSON.stringify({\r\n model: request.model,\r\n input: request.texts,\r\n });\r\n\r\n let response: Response;\r\n try {\r\n const headers: Record<string, string> = {\r\n 'Content-Type': 'application/json',\r\n };\r\n if (this.isAzure) {\r\n headers['api-key'] = this.apiKey;\r\n } else {\r\n headers['Authorization'] = `Bearer ${this.apiKey}`;\r\n }\r\n\r\n response = await fetch(this.endpoint, {\r\n method: 'POST',\r\n headers,\r\n body,\r\n });\r\n } catch (err: unknown) {\r\n // Network-level errors (timeout, DNS, connection refused, etc.)\r\n const message = err instanceof Error ? err.message : String(err);\r\n throw new PAIError(\r\n `Network error calling embedding API: ${message}`,\r\n ExitCode.RUNTIME_ERROR,\r\n { endpoint: this.endpoint, cause: message },\r\n );\r\n }\r\n\r\n if (!response.ok) {\r\n let detail = '';\r\n try {\r\n const errorBody = await response.text();\r\n detail = errorBody;\r\n } catch {\r\n // ignore – we already have the status code\r\n }\r\n throw new PAIError(\r\n `Embedding API error (${response.status}): ${detail || response.statusText}`,\r\n ExitCode.API_ERROR,\r\n { status: response.status, detail },\r\n );\r\n }\r\n\r\n // Parse successful response (OpenAI-compatible format)\r\n const json = (await response.json()) as {\r\n data: { embedding: number[]; index: number }[];\r\n model: string;\r\n usage: { prompt_tokens: number; total_tokens: number };\r\n };\r\n\r\n // Sort by index to guarantee order matches input order\r\n const sorted = [...json.data].sort((a, b) => a.index - b.index);\r\n\r\n return {\r\n embeddings: sorted.map((d) => d.embedding),\r\n model: json.model,\r\n usage: {\r\n promptTokens: json.usage.prompt_tokens,\r\n totalTokens: json.usage.total_tokens,\r\n },\r\n };\r\n }\r\n}\r\n","import type { EmbedOptions, PAIConfig } from './types.js';\r\nimport { PAIError, ExitCode } from './types.js';\r\n\r\n/**\r\n * Resolve the embed provider and model from CLI options and config.\r\n *\r\n * Priority:\r\n * 1. CLI --provider / --model\r\n * 2. PAIConfig.defaultEmbedProvider / defaultEmbedModel\r\n * 3. PAIConfig.defaultProvider (fallback, but model must be explicitly specified)\r\n *\r\n * Throws PAIError (exitCode 1) when provider or model cannot be resolved.\r\n */\r\nexport function resolveEmbedModel(\r\n options: EmbedOptions,\r\n config: PAIConfig\r\n): { provider: string; model: string } {\r\n // --- Resolve provider ---\r\n const provider =\r\n options.provider ??\r\n config.defaultEmbedProvider ??\r\n config.defaultProvider;\r\n\r\n if (!provider) {\r\n throw new PAIError(\r\n 'No embed provider specified and no default provider configured',\r\n ExitCode.PARAMETER_ERROR\r\n );\r\n }\r\n\r\n // --- Resolve model ---\r\n const model =\r\n options.model ??\r\n config.defaultEmbedModel;\r\n\r\n if (!model) {\r\n throw new PAIError(\r\n 'No embed model specified and no default embed model configured',\r\n ExitCode.PARAMETER_ERROR\r\n );\r\n }\r\n\r\n return { provider, model };\r\n}\r\n","/**\r\n * Embedding model token limits and text truncation utilities.\r\n */\r\n\r\n/**\r\n * Built-in maximum token limits for common embedding models.\r\n */\r\nexport const EMBEDDING_MODEL_LIMITS: Record<string, number> = {\r\n // OpenAI\r\n 'text-embedding-3-small': 8191,\r\n 'text-embedding-3-large': 8191,\r\n 'text-embedding-ada-002': 8191,\r\n // Google\r\n 'text-embedding-004': 2048,\r\n // Cohere\r\n 'embed-english-v3.0': 512,\r\n 'embed-multilingual-v3.0': 512,\r\n 'embed-english-light-v3.0': 512,\r\n 'embed-multilingual-light-v3.0': 512,\r\n};\r\n\r\n/** Characters per token estimate */\r\nconst CHARS_PER_TOKEN = 4;\r\n\r\nexport interface TruncateResult {\r\n text: string;\r\n truncated: boolean;\r\n originalTokens: number;\r\n}\r\n\r\n/**\r\n * Estimate token count using simple character-level approximation (1 token ≈ 4 characters).\r\n */\r\nexport function estimateTokens(text: string): number {\r\n return Math.ceil(text.length / CHARS_PER_TOKEN);\r\n}\r\n\r\n/**\r\n * Truncate text to fit within a model's token limit.\r\n *\r\n * - If the model is not in EMBEDDING_MODEL_LIMITS, returns the original text unchanged.\r\n * - Uses simple character-level estimation (1 token ≈ 4 characters).\r\n */\r\nexport function truncateText(text: string, model: string): TruncateResult {\r\n const limit = EMBEDDING_MODEL_LIMITS[model];\r\n const originalTokens = estimateTokens(text);\r\n\r\n // Unknown model — skip truncation\r\n if (limit === undefined) {\r\n return { text, truncated: false, originalTokens };\r\n }\r\n\r\n // Within limit — no truncation needed\r\n if (originalTokens <= limit) {\r\n return { text, truncated: false, originalTokens };\r\n }\r\n\r\n // Truncate: limit * CHARS_PER_TOKEN characters\r\n const maxChars = limit * CHARS_PER_TOKEN;\r\n return {\r\n text: text.slice(0, maxChars),\r\n truncated: true,\r\n originalTokens,\r\n };\r\n}\r\n","/**\r\n * Batch input parsing and embedding output formatting for the embed command.\r\n */\r\n\r\nimport { PAIError, ExitCode } from './types.js';\r\nimport type { EmbeddingResponse } from './embedding-client.js';\r\n\r\n/**\r\n * Encode a float64 number[] vector as a hex string array of float32 values (big-endian).\r\n * Each float32 becomes one 8-char hex string, e.g. [0.5, -1.0] → [\"3f000000\", \"bf800000\"].\r\n * This is lossless at float32 precision and more compact than a JSON number array.\r\n */\r\nexport function vectorToHex(vec: number[]): string[] {\r\n const buf = new ArrayBuffer(4);\r\n const view = new DataView(buf);\r\n const result: string[] = new Array(vec.length);\r\n for (let i = 0; i < vec.length; i++) {\r\n view.setFloat32(0, vec[i]!, false); // big-endian\r\n let hex = '';\r\n for (let b = 0; b < 4; b++) {\r\n const byte = view.getUint8(b);\r\n hex += (byte < 16 ? '0' : '') + byte.toString(16);\r\n }\r\n result[i] = hex;\r\n }\r\n return result;\r\n}\r\n\r\n/**\r\n * Parse a raw string as a JSON string array for batch embedding.\r\n * Throws PAIError (exitCode 1) if the JSON is invalid or not an array of strings.\r\n * Returns an empty array if the input is an empty JSON array.\r\n */\r\nexport function parseBatchInput(raw: string): string[] {\r\n let parsed: unknown;\r\n try {\r\n parsed = JSON.parse(raw);\r\n } catch {\r\n throw new PAIError(\r\n 'Invalid batch input: not valid JSON',\r\n ExitCode.PARAMETER_ERROR,\r\n );\r\n }\r\n\r\n if (!Array.isArray(parsed)) {\r\n throw new PAIError(\r\n 'Invalid batch input: expected a JSON array of strings',\r\n ExitCode.PARAMETER_ERROR,\r\n );\r\n }\r\n\r\n for (let i = 0; i < parsed.length; i++) {\r\n if (typeof parsed[i] !== 'string') {\r\n throw new PAIError(\r\n `Invalid batch input: element at index ${i} is not a string`,\r\n ExitCode.PARAMETER_ERROR,\r\n );\r\n }\r\n }\r\n\r\n return parsed as string[];\r\n}\r\n\r\n/**\r\n * Format an EmbeddingResponse for stdout output.\r\n *\r\n * Vectors are encoded as hex string arrays (each float32 → one 8-char hex string).\r\n * This preserves float32 precision exactly and is more compact than a JSON number array.\r\n *\r\n * Plain text mode (json=false):\r\n * Single: one line with the hex array, e.g. [\"3f800000\",\"bf800000\"]\r\n * Batch: one hex array per line\r\n *\r\n * JSON mode (json=true):\r\n * Single: { \"embedding\": [\"<hex>\", ...], \"model\": \"...\", \"usage\": { ... } }\r\n * Batch: { \"embeddings\": [[\"<hex>\", ...], ...], \"model\": \"...\", \"usage\": { ... } }\r\n */\r\nexport function formatEmbeddingOutput(\r\n result: EmbeddingResponse,\r\n options: { json: boolean; batch: boolean },\r\n): string {\r\n if (!options.json) {\r\n // Plain text: each embedding as a hex string array on its own line\r\n return result.embeddings\r\n .map((emb) => JSON.stringify(vectorToHex(emb)))\r\n .join('\\n');\r\n }\r\n\r\n // JSON mode\r\n const usage = {\r\n prompt_tokens: result.usage.promptTokens,\r\n total_tokens: result.usage.totalTokens,\r\n };\r\n\r\n if (options.batch) {\r\n return JSON.stringify({\r\n embeddings: result.embeddings.map((emb) => vectorToHex(emb)),\r\n model: result.model,\r\n usage,\r\n });\r\n }\r\n\r\n // Single mode – use \"embedding\" (singular) with the first vector\r\n return JSON.stringify({\r\n embedding: vectorToHex(result.embeddings[0]!),\r\n model: result.model,\r\n usage,\r\n });\r\n}\r\n","import type { EmbedOptions } from '../types.js';\r\nimport { PAIError, ExitCode } from '../types.js';\r\nimport { ConfigurationManager } from '../config-manager.js';\r\nimport { InputResolver } from '../input-resolver.js';\r\nimport { OutputFormatter } from '../output-formatter.js';\r\nimport { EmbeddingClient } from '../embedding-client.js';\r\nimport { resolveEmbedModel } from '../embed-model-resolver.js';\r\nimport { truncateText, EMBEDDING_MODEL_LIMITS } from '../embedding-models.js';\r\nimport { parseBatchInput, formatEmbeddingOutput } from '../embed-io.js';\r\n\r\n/**\r\n * Handle the embed command\r\n */\r\nexport async function handleEmbedCommand(\r\n text: string | undefined,\r\n options: EmbedOptions\r\n): Promise<void> {\r\n const configManager = new ConfigurationManager(options);\r\n const inputResolver = new InputResolver();\r\n const outputFormatter = new OutputFormatter(\r\n options.json,\r\n options.quiet ?? true\r\n );\r\n\r\n try {\r\n // Load configuration\r\n const config = await configManager.loadConfig();\r\n\r\n // Resolve provider and model\r\n const { provider: providerName, model: modelName } = resolveEmbedModel(options, config);\r\n\r\n // Verify provider exists in config and resolve credentials\r\n const providerConfig = config.providers.find((p) => p.name === providerName);\r\n if (!providerConfig) {\r\n throw new PAIError(\r\n `Provider not found: ${providerName}`,\r\n ExitCode.PARAMETER_ERROR,\r\n { provider: providerName }\r\n );\r\n }\r\n\r\n const apiKey = await configManager.resolveCredentials(providerName, undefined);\r\n\r\n // Resolve input text\r\n const hasExplicitInput = text !== undefined || options.inputFile !== undefined;\r\n const stdinAvailable = !process.stdin.isTTY && !hasExplicitInput;\r\n\r\n // Count input sources to validate mutual exclusivity\r\n const sourceCount = [\r\n text !== undefined,\r\n stdinAvailable,\r\n options.inputFile !== undefined,\r\n ].filter(Boolean).length;\r\n\r\n if (sourceCount > 1) {\r\n throw new PAIError(\r\n 'Multiple input sources specified',\r\n ExitCode.PARAMETER_ERROR,\r\n { message: 'Provide input via argument, stdin, or --input-file (only one)' }\r\n );\r\n }\r\n\r\n // Read input using InputResolver\r\n let rawInput: string;\r\n if (text !== undefined) {\r\n rawInput = text;\r\n } else if (options.inputFile) {\r\n rawInput = (await inputResolver.resolveUserInput({\r\n file: options.inputFile,\r\n })) as string;\r\n } else if (stdinAvailable) {\r\n rawInput = (await inputResolver.resolveUserInput({\r\n stdin: true,\r\n })) as string;\r\n } else {\r\n throw new PAIError(\r\n 'No input text provided',\r\n ExitCode.PARAMETER_ERROR,\r\n { message: 'Provide input via argument, stdin, or --input-file' }\r\n );\r\n }\r\n\r\n // Parse batch input or wrap single text\r\n let texts: string[];\r\n if (options.batch) {\r\n texts = parseBatchInput(rawInput);\r\n } else {\r\n texts = [rawInput];\r\n }\r\n\r\n // Truncate texts and output warnings\r\n texts = texts.map((t) => {\r\n const result = truncateText(t, modelName);\r\n if (result.truncated) {\r\n const truncatedTokens = Math.ceil(result.text.length / 4);\r\n const modelLimit = EMBEDDING_MODEL_LIMITS[modelName] ?? truncatedTokens;\r\n if (options.json) {\r\n // NDJSON warning event to stderr\r\n const warning = {\r\n type: 'warning',\r\n data: {\r\n message: `Input text truncated from ~${result.originalTokens} tokens to ${truncatedTokens} tokens (model limit: ${modelLimit})`,\r\n originalTokens: result.originalTokens,\r\n truncatedTokens,\r\n },\r\n };\r\n process.stderr.write(JSON.stringify(warning) + '\\n');\r\n } else {\r\n process.stderr.write(\r\n `[Warning] Input text truncated from ~${result.originalTokens} tokens to ${truncatedTokens} tokens (model limit: ${modelLimit})\\n`\r\n );\r\n }\r\n }\r\n return result.text;\r\n });\r\n\r\n // Output progress\r\n outputFormatter.writeProgress({\r\n type: 'start',\r\n data: {\r\n provider: providerName,\r\n model: modelName,\r\n texts: texts.length,\r\n batch: options.batch ?? false,\r\n },\r\n });\r\n\r\n // Call embedding API\r\n const clientConfig: {\r\n provider: string;\r\n apiKey: string;\r\n model: string;\r\n baseUrl?: string;\r\n providerOptions?: Record<string, any>;\r\n api?: string;\r\n } = {\r\n provider: providerName,\r\n apiKey,\r\n model: modelName,\r\n };\r\n if (providerConfig.baseUrl) {\r\n clientConfig.baseUrl = providerConfig.baseUrl;\r\n }\r\n if (providerConfig.providerOptions) {\r\n clientConfig.providerOptions = providerConfig.providerOptions;\r\n }\r\n if (providerConfig.api) {\r\n clientConfig.api = providerConfig.api;\r\n }\r\n const client = new EmbeddingClient(clientConfig);\r\n\r\n const response = await client.embed({ texts, model: modelName });\r\n\r\n // Output progress complete\r\n outputFormatter.writeProgress({\r\n type: 'complete',\r\n data: {\r\n model: response.model,\r\n usage: response.usage,\r\n },\r\n });\r\n\r\n // Format and write output to stdout\r\n const output = formatEmbeddingOutput(response, {\r\n json: options.json ?? false,\r\n batch: options.batch ?? false,\r\n });\r\n process.stdout.write(output + '\\n');\r\n } catch (error) {\r\n if (error instanceof PAIError) {\r\n outputFormatter.writeError(error);\r\n process.exit(error.exitCode);\r\n } else {\r\n const paiError = new PAIError(\r\n error instanceof Error ? error.message : String(error),\r\n ExitCode.RUNTIME_ERROR,\r\n { originalError: String(error) }\r\n );\r\n outputFormatter.writeError(paiError);\r\n process.exit(ExitCode.RUNTIME_ERROR);\r\n }\r\n }\r\n}\r\n","import { getProviders, getModels } from '@mariozechner/pi-ai';\r\nimport { getOAuthProvider, getOAuthProviders } from '@mariozechner/pi-ai/oauth';\r\nimport { createInterface } from 'node:readline';\r\nimport type { ModelConfigOptions } from '../types.js';\r\nimport { PAIError } from '../types.js';\r\nimport { ConfigurationManager } from '../config-manager.js';\r\n\r\n/**\r\n * Handle model list command\r\n */\r\nexport async function handleModelList(options: ModelConfigOptions): Promise<void> {\r\n const configManager = new ConfigurationManager(options);\r\n\r\n try {\r\n const config = await configManager.loadConfig();\r\n\r\n // Show config file path (to stderr so it doesn't pollute JSON output)\r\n if (!options.json) {\r\n console.log(`Config: ${configManager.getConfigPath()}\\n`);\r\n } else {\r\n process.stderr.write(`Config: ${configManager.getConfigPath()}\\n`);\r\n }\r\n\r\n if (options.all) {\r\n // List all supported providers\r\n const allProviders = getProviders();\r\n \r\n if (options.json) {\r\n const output = {\r\n defaultEmbedProvider: config.defaultEmbedProvider ?? null,\r\n defaultEmbedModel: config.defaultEmbedModel ?? null,\r\n providers: allProviders.map((provider) => {\r\n const models = getModels(provider as any);\r\n const configured = config.providers.some((p) => p.name === provider);\r\n\r\n return {\r\n name: provider,\r\n provider,\r\n configured,\r\n models: models.map((m) => m.id),\r\n };\r\n }),\r\n };\r\n\r\n console.log(JSON.stringify(output, null, 2));\r\n } else {\r\n if (config.defaultEmbedProvider || config.defaultEmbedModel) {\r\n const ep = config.defaultEmbedProvider ?? '(not set)';\r\n const em = config.defaultEmbedModel ?? '(not set)';\r\n console.log(`Default Embed: ${ep}/${em}\\n`);\r\n }\r\n console.log('Available Providers:\\n');\r\n for (const provider of allProviders) {\r\n const models = getModels(provider as any);\r\n const configured = config.providers.some((p) => p.name === provider);\r\n const status = configured ? '✓' : ' ';\r\n\r\n console.log(`[${status}] ${provider}`);\r\n console.log(` Models: ${models.length} available`);\r\n if (models.length > 0 && models.length <= 5) {\r\n models.forEach((m) => console.log(` - ${m.id}`));\r\n }\r\n console.log();\r\n }\r\n }\r\n } else {\r\n // List only configured providers\r\n if (config.providers.length === 0) {\r\n console.log('No providers configured.');\r\n console.log('Use \"pai model config --add\" to add a provider.');\r\n return;\r\n }\r\n\r\n if (options.json) {\r\n const output = {\r\n defaultEmbedProvider: config.defaultEmbedProvider ?? null,\r\n defaultEmbedModel: config.defaultEmbedModel ?? null,\r\n providers: config.providers.map((p) => ({\r\n name: p.name,\r\n provider: p.name,\r\n configured: true,\r\n models: p.models || [],\r\n defaultModel: p.defaultModel,\r\n })),\r\n };\r\n\r\n console.log(JSON.stringify(output, null, 2));\r\n } else {\r\n if (config.defaultEmbedProvider || config.defaultEmbedModel) {\r\n const ep = config.defaultEmbedProvider ?? '(not set)';\r\n const em = config.defaultEmbedModel ?? '(not set)';\r\n console.log(`Default Embed: ${ep}/${em}\\n`);\r\n }\r\n console.log('Configured Providers:\\n');\r\n for (const provider of config.providers) {\r\n console.log(`✓ ${provider.name}`);\r\n if (provider.defaultModel) {\r\n console.log(` Default: ${provider.defaultModel}`);\r\n }\r\n if (provider.models && provider.models.length > 0) {\r\n console.log(` Models: ${provider.models.join(', ')}`);\r\n }\r\n console.log();\r\n }\r\n }\r\n }\r\n } catch (error) {\r\n if (error instanceof PAIError) {\r\n console.error(`Error: ${error.message}`);\r\n process.exit(error.exitCode);\r\n } else {\r\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\r\n process.exit(2);\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Handle model config command\r\n */\r\nexport async function handleModelConfig(options: ModelConfigOptions): Promise<void> {\r\n const configManager = new ConfigurationManager(options);\r\n\r\n try {\r\n // Show config file path\r\n process.stderr.write(`Config: ${configManager.getConfigPath()}\\n`);\r\n\r\n if (options.show) {\r\n // Show a single provider's config\r\n if (!options.name) {\r\n throw new PAIError('Provider name is required', 1, {\r\n message: 'Use --name <provider-name>',\r\n });\r\n }\r\n\r\n const provider = await configManager.getProvider(options.name);\r\n\r\n // Mask sensitive fields\r\n const masked: Record<string, any> = { ...provider };\r\n if (masked.apiKey) masked.apiKey = '***';\r\n if (masked.oauth) {\r\n masked.oauth = {\r\n ...masked.oauth,\r\n refresh: '***',\r\n access: '***',\r\n };\r\n }\r\n\r\n if (options.json) {\r\n console.log(JSON.stringify(masked, null, 2));\r\n } else {\r\n console.log(`\\nProvider: ${provider.name}`);\r\n for (const [key, value] of Object.entries(masked)) {\r\n if (key === 'name') continue;\r\n if (typeof value === 'object' && value !== null) {\r\n console.log(` ${key}: ${JSON.stringify(value)}`);\r\n } else {\r\n console.log(` ${key}: ${value}`);\r\n }\r\n }\r\n }\r\n } else if (options.add) {\r\n // Add or update provider\r\n if (!options.name) {\r\n throw new PAIError('Provider name is required', 1, {\r\n message: 'Use --name <provider-name>',\r\n });\r\n }\r\n\r\n if (!options.provider) {\r\n throw new PAIError('Provider type is required', 1, {\r\n message: 'Use --provider <provider-type>',\r\n });\r\n }\r\n\r\n // Validate provider is supported\r\n const supportedProviders = getProviders();\r\n if (!supportedProviders.includes(options.provider as any)) {\r\n throw new PAIError(\r\n `Unsupported provider: ${options.provider}`,\r\n 1,\r\n {\r\n message: `Supported providers: ${supportedProviders.join(', ')}`,\r\n }\r\n );\r\n }\r\n\r\n const providerConfig: any = {\r\n name: options.name,\r\n };\r\n\r\n // Known configuration keys\r\n const knownKeys = new Set([\r\n 'apiKey', 'defaultModel', 'models', 'temperature', 'maxTokens',\r\n 'api', 'baseUrl', 'reasoning', 'input', 'contextWindow',\r\n 'providerOptions',\r\n ]);\r\n\r\n // Parse --set options\r\n if (options.set && options.set.length > 0) {\r\n for (const setting of options.set) {\r\n const eqIndex = setting.indexOf('=');\r\n if (eqIndex < 1) {\r\n throw new PAIError(\r\n `Invalid --set format: ${setting}`,\r\n 1,\r\n { message: 'Use --set key=value' }\r\n );\r\n }\r\n const key = setting.substring(0, eqIndex);\r\n const value = setting.substring(eqIndex + 1);\r\n\r\n // Warn on unknown keys (but still allow them for extensibility)\r\n const topKey = key.split('.')[0]!;\r\n if (!knownKeys.has(topKey)) {\r\n console.error(`Warning: unknown key \"${key}\". Known keys: ${[...knownKeys].join(', ')}`);\r\n }\r\n\r\n // Support nested keys like providerOptions.azureApiVersion\r\n if (key.includes('.')) {\r\n const parts = key.split('.');\r\n let target = providerConfig;\r\n for (let i = 0; i < parts.length - 1; i++) {\r\n const part = parts[i]!;\r\n if (!target[part] || typeof target[part] !== 'object') {\r\n target[part] = {};\r\n }\r\n target = target[part];\r\n }\r\n target[parts[parts.length - 1]!] = value;\r\n } else {\r\n providerConfig[key] = value;\r\n }\r\n }\r\n }\r\n\r\n await configManager.addProvider(providerConfig);\r\n\r\n // Set as default provider if --default flag is provided\r\n if (options.default) {\r\n await configManager.setDefaultProvider(options.name);\r\n }\r\n\r\n console.log(`Provider \"${options.name}\" configured successfully.`);\r\n } else if (options.update) {\r\n // Update existing provider fields\r\n if (!options.name) {\r\n throw new PAIError('Provider name is required', 1, {\r\n message: 'Use --name <provider-name>',\r\n });\r\n }\r\n\r\n if (!options.set || options.set.length === 0) {\r\n throw new PAIError('No fields to update', 1, {\r\n message: 'Use --set key=value to specify fields to update',\r\n });\r\n }\r\n\r\n // Known configuration keys\r\n const knownKeys = new Set([\r\n 'apiKey', 'defaultModel', 'models', 'temperature', 'maxTokens',\r\n 'api', 'baseUrl', 'reasoning', 'input', 'contextWindow',\r\n 'providerOptions',\r\n ]);\r\n\r\n const updates: Record<string, any> = {};\r\n\r\n for (const setting of options.set) {\r\n const eqIndex = setting.indexOf('=');\r\n if (eqIndex < 1) {\r\n throw new PAIError(\r\n `Invalid --set format: ${setting}`,\r\n 1,\r\n { message: 'Use --set key=value' }\r\n );\r\n }\r\n const key = setting.substring(0, eqIndex);\r\n const value = setting.substring(eqIndex + 1);\r\n\r\n const topKey = key.split('.')[0]!;\r\n if (!knownKeys.has(topKey)) {\r\n console.error(`Warning: unknown key \"${key}\". Known keys: ${[...knownKeys].join(', ')}`);\r\n }\r\n\r\n if (key.includes('.')) {\r\n const parts = key.split('.');\r\n let target = updates;\r\n for (let i = 0; i < parts.length - 1; i++) {\r\n const part = parts[i]!;\r\n if (!target[part] || typeof target[part] !== 'object') {\r\n target[part] = {};\r\n }\r\n target = target[part];\r\n }\r\n target[parts[parts.length - 1]!] = value;\r\n } else {\r\n updates[key] = value;\r\n }\r\n }\r\n\r\n await configManager.updateProvider(options.name, updates);\r\n\r\n // Set as default provider if --default flag is provided\r\n if (options.default) {\r\n await configManager.setDefaultProvider(options.name);\r\n }\r\n\r\n console.log(`Provider \"${options.name}\" updated successfully.`);\r\n } else if (options.delete) {\r\n // Delete provider\r\n if (!options.name) {\r\n throw new PAIError('Provider name is required', 1, {\r\n message: 'Use --name <provider-name>',\r\n });\r\n }\r\n\r\n await configManager.deleteProvider(options.name);\r\n\r\n console.log(`Provider \"${options.name}\" deleted successfully.`);\r\n } else {\r\n throw new PAIError('No action specified', 1, {\r\n message: 'Use --add, --update, --delete, or --show',\r\n });\r\n }\r\n } catch (error) {\r\n if (error instanceof PAIError) {\r\n console.error(`Error: ${error.message}`);\r\n if (error.context) {\r\n console.error(`Context: ${JSON.stringify(error.context)}`);\r\n }\r\n process.exit(error.exitCode);\r\n } else {\r\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\r\n process.exit(2);\r\n }\r\n }\r\n}\r\n\r\n\r\n/**\r\n * Handle model default command — view or set the default provider and embed settings\r\n */\r\nexport async function handleModelDefault(options: ModelConfigOptions): Promise<void> {\r\n const configManager = new ConfigurationManager(options);\r\n\r\n try {\r\n const hasSetEmbed = options.embedProvider || options.embedModel;\r\n\r\n if (options.name || hasSetEmbed) {\r\n // Set default provider and/or embed settings\r\n if (options.name) {\r\n await configManager.setDefaultProvider(options.name);\r\n }\r\n if (hasSetEmbed) {\r\n await configManager.setDefaultEmbed(options.embedProvider, options.embedModel);\r\n }\r\n\r\n const parts: string[] = [];\r\n if (options.name) parts.push(`Default provider set to \"${options.name}\".`);\r\n if (options.embedProvider) parts.push(`Default embed provider set to \"${options.embedProvider}\".`);\r\n if (options.embedModel) parts.push(`Default embed model set to \"${options.embedModel}\".`);\r\n console.log(parts.join('\\n'));\r\n } else {\r\n // Show current defaults\r\n const config = await configManager.loadConfig();\r\n\r\n if (options.json) {\r\n console.log(JSON.stringify({\r\n defaultProvider: config.defaultProvider ?? null,\r\n defaultEmbedProvider: config.defaultEmbedProvider ?? null,\r\n defaultEmbedModel: config.defaultEmbedModel ?? null,\r\n }));\r\n } else {\r\n if (config.defaultProvider) {\r\n console.log(`Default provider: ${config.defaultProvider}`);\r\n } else {\r\n console.log('No default provider configured.');\r\n console.log('Use \"pai model default --name <provider>\" to set one.');\r\n }\r\n if (config.defaultEmbedProvider || config.defaultEmbedModel) {\r\n const embedParts: string[] = [];\r\n if (config.defaultEmbedProvider) embedParts.push(`provider: ${config.defaultEmbedProvider}`);\r\n if (config.defaultEmbedModel) embedParts.push(`model: ${config.defaultEmbedModel}`);\r\n console.log(`Default embed: ${embedParts.join(', ')}`);\r\n }\r\n }\r\n }\r\n } catch (error) {\r\n if (error instanceof PAIError) {\r\n console.error(`Error: ${error.message}`);\r\n if (error.context) {\r\n console.error(`Context: ${JSON.stringify(error.context)}`);\r\n }\r\n process.exit(error.exitCode);\r\n } else {\r\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\r\n process.exit(2);\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Handle model login command (OAuth providers)\r\n */\r\nexport async function handleModelLogin(options: ModelConfigOptions): Promise<void> {\r\n const configManager = new ConfigurationManager(options);\r\n\r\n try {\r\n if (!options.name) {\r\n throw new PAIError('Provider name is required', 1, {\r\n message: 'Use --name <provider-name>',\r\n });\r\n }\r\n\r\n // Check if this is an OAuth provider\r\n const oauthProviders = getOAuthProviders();\r\n const oauthProvider = getOAuthProvider(options.name);\r\n\r\n if (!oauthProvider) {\r\n const oauthIds = oauthProviders.map((p) => p.id).join(', ');\r\n throw new PAIError(\r\n `Provider \"${options.name}\" does not support OAuth login`,\r\n 1,\r\n { message: `OAuth providers: ${oauthIds}` }\r\n );\r\n }\r\n\r\n const rl = createInterface({ input: process.stdin, output: process.stdout });\r\n const prompt = (msg: string): Promise<string> =>\r\n new Promise((resolve) => rl.question(`${msg} `, resolve));\r\n\r\n try {\r\n console.log(`Logging in to ${oauthProvider.name}...`);\r\n\r\n const credentials = await oauthProvider.login({\r\n onAuth: (info) => {\r\n console.log(`\\nOpen this URL in your browser:\\n${info.url}`);\r\n if (info.instructions) console.log(info.instructions);\r\n console.log();\r\n },\r\n onPrompt: async (p) => {\r\n return await prompt(\r\n `${p.message}${p.placeholder ? ` (${p.placeholder})` : ''}:`\r\n );\r\n },\r\n onProgress: (msg) => console.log(msg),\r\n });\r\n\r\n // Load existing provider config or create new one\r\n let providerConfig;\r\n try {\r\n providerConfig = await configManager.getProvider(options.name);\r\n } catch {\r\n providerConfig = { name: options.name };\r\n }\r\n\r\n // Store OAuth credentials in the provider config\r\n providerConfig.oauth = {\r\n refresh: credentials.refresh,\r\n access: credentials.access,\r\n expires: credentials.expires,\r\n ...(Object.fromEntries(\r\n Object.entries(credentials).filter(\r\n ([k]) => !['refresh', 'access', 'expires'].includes(k)\r\n )\r\n )),\r\n };\r\n\r\n await configManager.addProvider(providerConfig);\r\n\r\n console.log(`\\nProvider \"${options.name}\" logged in and credentials saved to config.`);\r\n } finally {\r\n rl.close();\r\n }\r\n } catch (error) {\r\n if (error instanceof PAIError) {\r\n console.error(`Error: ${error.message}`);\r\n if (error.context) {\r\n console.error(`Context: ${JSON.stringify(error.context)}`);\r\n }\r\n process.exit(error.exitCode);\r\n } else {\r\n console.error(\r\n `Error: ${error instanceof Error ? error.message : String(error)}`\r\n );\r\n process.exit(2);\r\n }\r\n }\r\n}\r\n","import type { Command } from 'commander';\r\n\r\n// ── Help text data ──────────────────────────────────────────\r\n\r\nconst MAIN_EXAMPLES = `\r\nExamples:\r\n $ pai chat \"Hello, how are you?\" # 简单对话\r\n $ echo \"Explain this\" | pai chat # stdin 输入\r\n $ pai chat \"Write a story\" --stream # 流式输出\r\n $ pai model config --add --name openai --provider openai --set apiKey=sk-...\r\n $ pai model list # 查看已配置 provider\r\n $ pai model default --name openai # 设置默认 provider`;\r\n\r\nconst MAIN_VERBOSE = `\r\nPrerequisites:\r\n 使用前需先配置至少一个 provider:\r\n pai model config --add --name <name> --provider <type> --set apiKey=<key>\r\n 或使用 OAuth 登录:\r\n pai model login --name github-copilot\r\n\r\nConfig:\r\n 默认配置文件: ~/.config/pai/default.json\r\n 可通过 --config <path> 或 PAI_CONFIG 环境变量覆盖\r\n\r\nExit Codes:\r\n 0 成功\r\n 1 参数/用法错误\r\n 2 本地运行时错误\r\n 3 外部 API/Provider 错误\r\n 4 IO/文件错误`;\r\n\r\nconst CHAT_EXAMPLES = `\r\nExamples:\r\n $ pai chat \"What is the capital of France?\"\r\n $ echo \"Summarize this\" | pai chat # stdin 输入\r\n $ cat doc.txt | pai chat \"Summarize this document\"\r\n $ pai chat \"Hello\" --session chat.jsonl # 多轮对话\r\n $ pai chat \"Describe this\" --image photo.jpg # 图片分析\r\n $ pai chat --dry-run --provider openai # 查看配置不调用 LLM\r\n\r\nStdin:\r\n 支持通过管道传入用户消息,与 --input-file 和位置参数互斥。\r\n\r\nJSON output (--json):\r\n 进度信息以 NDJSON 输出到 stderr,LLM 回复输出到 stdout。`;\r\n\r\nconst EMBED_EXAMPLES = `\r\nExamples:\r\n $ pai embed \"hello world\" --provider openai --model text-embedding-3-small\r\n $ echo \"hello\" | pai embed # stdin 输入\r\n $ pai embed --input-file doc.txt # 文件输入\r\n $ pai embed --batch '[\"hello\",\"world\"]' # 批量模式\r\n\r\nStdin:\r\n 支持通过管道传入文本。与位置参数和 --input-file 互斥。\r\n\r\nJSON output (--json):\r\n 单条: {\"embedding\":[...],\"model\":\"...\",\"usage\":{...}}\r\n 批量: {\"embeddings\":[[...],[...]],\"model\":\"...\",\"usage\":{...}}`;\r\n\r\nconst MODEL_LIST_EXAMPLES = `\r\nExamples:\r\n $ pai model list # 已配置 provider\r\n $ pai model list --all # 所有支持的 provider\r\n $ pai model list --json # JSON 输出`;\r\n\r\nconst MODEL_CONFIG_EXAMPLES = `\r\nExamples:\r\n $ pai model config --add --name openai --provider openai --set apiKey=sk-...\r\n $ pai model config --update --name openai --set defaultModel=gpt-4o\r\n $ pai model config --show --name openai # 查看配置(敏感信息脱敏)\r\n $ pai model config --delete --name openai\r\n\r\nNote:\r\n --add 对同名 provider 执行 upsert(幂等操作)。`;\r\n\r\nconst MODEL_DEFAULT_EXAMPLES = `\r\nExamples:\r\n $ pai model default # 查看当前默认\r\n $ pai model default --name openai # 设置默认 provider\r\n $ pai model default --embed-provider openai --embed-model text-embedding-3-small`;\r\n\r\nconst MODEL_LOGIN_EXAMPLES = `\r\nExamples:\r\n $ pai model login --name github-copilot # OAuth 登录\r\n $ pai model login --name anthropic # Anthropic OAuth\r\n\r\nSupported: github-copilot, anthropic, google-gemini-cli, google-antigravity, openai-codex`;\r\n\r\n// ── Verbose help data (keyed by command name path) ──────────\r\n\r\nconst VERBOSE_HELP: Record<string, string> = {\r\n 'pai': MAIN_VERBOSE,\r\n};\r\n\r\n// ── Setup functions ─────────────────────────────────────────\r\n\r\n/**\r\n * Install --help --verbose support and examples on a command tree.\r\n */\r\nexport function installHelp(program: Command): void {\r\n // Main program\r\n program.addHelpText('after', MAIN_EXAMPLES);\r\n\r\n // We need to intercept --verbose for help\r\n installVerboseHelp(program);\r\n}\r\n\r\n/**\r\n * Add examples to a specific subcommand by name.\r\n */\r\nexport function addSubcommandExamples(cmd: Command, name: string): void {\r\n const examples: Record<string, string> = {\r\n 'chat': CHAT_EXAMPLES,\r\n 'embed': EMBED_EXAMPLES,\r\n 'list': MODEL_LIST_EXAMPLES,\r\n 'config': MODEL_CONFIG_EXAMPLES,\r\n 'default': MODEL_DEFAULT_EXAMPLES,\r\n 'login': MODEL_LOGIN_EXAMPLES,\r\n };\r\n const text = examples[name];\r\n if (text) {\r\n cmd.addHelpText('after', text);\r\n }\r\n}\r\n\r\n/**\r\n * Install verbose help support. When --verbose is present alongside --help,\r\n * output extended information.\r\n */\r\nfunction installVerboseHelp(program: Command): void {\r\n // Add a hidden --verbose option\r\n program.option('--verbose', '(与 --help 一起使用) 显示完整帮助信息');\r\n program.on('option:verbose', () => {\r\n // Mark that verbose was requested\r\n (program as unknown as Record<string, boolean>).__verboseHelp = true;\r\n });\r\n\r\n // Hook into the help display\r\n program.addHelpText('afterAll', () => {\r\n if ((program as unknown as Record<string, boolean>).__verboseHelp) {\r\n return MAIN_VERBOSE;\r\n }\r\n return '';\r\n });\r\n}\r\n"],"mappings":"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","names":["join","dirname","getOAuthProvider","writeFile","existsSync","existsSync","writeFile","readFile","readFile","appendFile","writeFile","existsSync","sanitized","existsSync","appendFile","writeFile","toolCalls","getModels","createInterface","getModels","createInterface","program","dirname","join"]}
package/package.json ADDED
@@ -0,0 +1,41 @@
1
+ {
2
+ "name": "@theclawlab/pai",
3
+ "type": "module",
4
+ "version": "1.0.0",
5
+ "description": "pai is a linux command to interact with LLMs (with only one bash_exec tool and basic session support).",
6
+ "bin": {
7
+ "pai": "dist/index.js"
8
+ },
9
+ "scripts": {
10
+ "dev-old": "tsx watch src/index.ts",
11
+ "dev": "tsup --watch --onSuccess 'node dist/index.js'",
12
+ "build": "tsup",
13
+ "test": "vitest",
14
+ "test:coverage": "vitest run --coverage",
15
+ "release:local": "npm run build && npm link",
16
+ "release:public": "npm run build && npm publish --access public"
17
+ },
18
+ "publishConfig": {
19
+ "access": "public",
20
+ "registry": "https://registry.npmjs.org"
21
+ },
22
+ "files": [
23
+ "dist",
24
+ "README.md"
25
+ ],
26
+ "keywords": [],
27
+ "author": "",
28
+ "license": "MIT",
29
+ "devDependencies": {
30
+ "@types/node": "^25.4.0",
31
+ "fast-check": "^4.6.0",
32
+ "tsup": "^8.5.1",
33
+ "tsx": "^4.21.0",
34
+ "typescript": "^5.9.3",
35
+ "vitest": "^4.0.18"
36
+ },
37
+ "dependencies": {
38
+ "@mariozechner/pi-ai": "^0.57.1",
39
+ "commander": "^14.0.3"
40
+ }
41
+ }