claudish 5.18.1 → 6.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.
Files changed (2) hide show
  1. package/dist/index.js +1989 -1552
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -28781,7 +28781,7 @@ var exports_mcp_server = {};
28781
28781
  __export(exports_mcp_server, {
28782
28782
  startMcpServer: () => startMcpServer
28783
28783
  });
28784
- import { readFileSync as readFileSync2, existsSync as existsSync2, writeFileSync as writeFileSync2, mkdirSync as mkdirSync2 } from "fs";
28784
+ import { readFileSync as readFileSync2, existsSync as existsSync2, writeFileSync as writeFileSync2, mkdirSync as mkdirSync2, readdirSync as readdirSync2 } from "fs";
28785
28785
  import { join as join2, dirname } from "path";
28786
28786
  import { homedir } from "os";
28787
28787
  import { fileURLToPath } from "url";
@@ -28877,262 +28877,402 @@ function fuzzyScore(text, query) {
28877
28877
  }
28878
28878
  return queryIndex === lowerQuery.length ? score / lowerText.length : 0;
28879
28879
  }
28880
+ function formatTeamResult(status, sessionPath) {
28881
+ const entries = Object.entries(status.models);
28882
+ const failed = entries.filter(([, m]) => m.state === "FAILED" || m.state === "TIMEOUT");
28883
+ const succeeded = entries.filter(([, m]) => m.state === "COMPLETED");
28884
+ let result = JSON.stringify(status, null, 2);
28885
+ if (failed.length > 0) {
28886
+ result += `
28887
+
28888
+ ---
28889
+ ## Failures Detected
28890
+
28891
+ `;
28892
+ result += `${succeeded.length}/${entries.length} models succeeded, ${failed.length} failed.
28893
+
28894
+ `;
28895
+ for (const [id, m] of failed) {
28896
+ result += `### Model ${id}: ${m.state}
28897
+ `;
28898
+ if (m.error) {
28899
+ result += `- **Model:** ${m.error.model}
28900
+ `;
28901
+ result += `- **Command:** \`${m.error.command}\`
28902
+ `;
28903
+ result += `- **Exit code:** ${m.exitCode}
28904
+ `;
28905
+ if (m.error.stderrSnippet) {
28906
+ result += `- **Error output:**
28907
+ \`\`\`
28908
+ ${m.error.stderrSnippet}
28909
+ \`\`\`
28910
+ `;
28911
+ }
28912
+ result += `- **Full error log:** ${m.error.errorLogPath}
28913
+ `;
28914
+ result += `- **Working directory:** ${m.error.workDir}
28915
+ `;
28916
+ }
28917
+ result += `
28918
+ `;
28919
+ }
28920
+ result += `---
28921
+ `;
28922
+ result += "**To help claudish devs fix this**, use the `report_error` tool with:\n";
28923
+ result += '- `error_type`: "provider_failure" or "team_failure"\n';
28924
+ result += `- \`session_path\`: "${sessionPath}"
28925
+ `;
28926
+ result += "- Copy the stderr snippet above into `stderr_snippet`\n";
28927
+ result += "- Set `auto_send: true` to suggest enabling automatic reporting\n";
28928
+ }
28929
+ return result;
28930
+ }
28880
28931
  async function main() {
28881
28932
  const server = new McpServer({
28882
28933
  name: "claudish",
28883
28934
  version: "2.5.0"
28884
28935
  });
28885
- server.tool("run_prompt", "Run a prompt through an OpenRouter model (Grok, GPT-5, Gemini, etc.)", {
28886
- model: exports_external.string().describe("OpenRouter model ID (e.g., 'x-ai/grok-code-fast-1', 'openai/gpt-5.1-codex')"),
28887
- prompt: exports_external.string().describe("The prompt to send to the model"),
28888
- system_prompt: exports_external.string().optional().describe("Optional system prompt"),
28889
- max_tokens: exports_external.number().optional().describe("Maximum tokens in response (omit to let model decide)")
28890
- }, async ({ model, prompt, system_prompt, max_tokens }) => {
28891
- try {
28892
- const result = await runPrompt(model, prompt, system_prompt, max_tokens);
28893
- let response = result.content;
28894
- if (result.usage) {
28895
- response += `
28936
+ const toolMode = (process.env.CLAUDISH_MCP_TOOLS || "all").toLowerCase();
28937
+ const isLowLevel = toolMode === "all" || toolMode === "low-level";
28938
+ const isAgentic = toolMode === "all" || toolMode === "agentic";
28939
+ console.error(`[claudish] MCP server started (tools: ${toolMode})`);
28940
+ if (isLowLevel) {
28941
+ server.tool("run_prompt", "Run a prompt through an OpenRouter model (Grok, GPT-5, Gemini, etc.)", {
28942
+ model: exports_external.string().describe("OpenRouter model ID (e.g., 'x-ai/grok-code-fast-1', 'openai/gpt-5.1-codex')"),
28943
+ prompt: exports_external.string().describe("The prompt to send to the model"),
28944
+ system_prompt: exports_external.string().optional().describe("Optional system prompt"),
28945
+ max_tokens: exports_external.number().optional().describe("Maximum tokens in response (omit to let model decide)")
28946
+ }, async ({ model, prompt, system_prompt, max_tokens }) => {
28947
+ try {
28948
+ const result = await runPrompt(model, prompt, system_prompt, max_tokens);
28949
+ let response = result.content;
28950
+ if (result.usage) {
28951
+ response += `
28896
28952
 
28897
28953
  ---
28898
28954
  Tokens: ${result.usage.input} input, ${result.usage.output} output`;
28955
+ }
28956
+ return { content: [{ type: "text", text: response }] };
28957
+ } catch (error46) {
28958
+ return {
28959
+ content: [
28960
+ {
28961
+ type: "text",
28962
+ text: `Error: ${error46 instanceof Error ? error46.message : String(error46)}`
28963
+ }
28964
+ ],
28965
+ isError: true
28966
+ };
28899
28967
  }
28900
- return { content: [{ type: "text", text: response }] };
28901
- } catch (error46) {
28902
- return {
28903
- content: [
28904
- {
28905
- type: "text",
28906
- text: `Error: ${error46 instanceof Error ? error46.message : String(error46)}`
28907
- }
28908
- ],
28909
- isError: true
28910
- };
28911
- }
28912
- });
28913
- server.tool("list_models", "List recommended models for coding tasks", {}, async () => {
28914
- const models = loadRecommendedModels();
28915
- if (models.length === 0) {
28916
- return {
28917
- content: [
28918
- { type: "text", text: "No recommended models found. Try search_models instead." }
28919
- ]
28920
- };
28921
- }
28922
- let output = `# Recommended Models
28968
+ });
28969
+ server.tool("list_models", "List recommended models for coding tasks", {}, async () => {
28970
+ const models = loadRecommendedModels();
28971
+ if (models.length === 0) {
28972
+ return {
28973
+ content: [
28974
+ { type: "text", text: "No recommended models found. Try search_models instead." }
28975
+ ]
28976
+ };
28977
+ }
28978
+ let output = `# Recommended Models
28923
28979
 
28924
28980
  `;
28925
- output += `| Model | Provider | Pricing | Context | Tools | Reasoning | Vision |
28981
+ output += `| Model | Provider | Pricing | Context | Tools | Reasoning | Vision |
28926
28982
  `;
28927
- output += `|-------|----------|---------|---------|-------|-----------|--------|
28983
+ output += `|-------|----------|---------|---------|-------|-----------|--------|
28928
28984
  `;
28929
- for (const model of models) {
28930
- const tools = model.supportsTools ? "\u2713" : "\xB7";
28931
- const reasoning = model.supportsReasoning ? "\u2713" : "\xB7";
28932
- const vision = model.supportsVision ? "\u2713" : "\xB7";
28933
- output += `| ${model.id} | ${model.provider} | ${model.pricing?.average || "N/A"} | ${model.context || "N/A"} | ${tools} | ${reasoning} | ${vision} |
28985
+ for (const model of models) {
28986
+ const tools = model.supportsTools ? "\u2713" : "\xB7";
28987
+ const reasoning = model.supportsReasoning ? "\u2713" : "\xB7";
28988
+ const vision = model.supportsVision ? "\u2713" : "\xB7";
28989
+ output += `| ${model.id} | ${model.provider} | ${model.pricing?.average || "N/A"} | ${model.context || "N/A"} | ${tools} | ${reasoning} | ${vision} |
28934
28990
  `;
28935
- }
28936
- output += `
28991
+ }
28992
+ output += `
28937
28993
  ## Quick Picks
28938
28994
  `;
28939
- output += "- **Budget**: `minimax-m2.5` ($0.75/1M)\n";
28940
- output += "- **Large context**: `gemini-3.1-pro-preview` (1M tokens)\n";
28941
- output += "- **Most advanced**: `gpt-5.4` ($8.75/1M)\n";
28942
- output += "- **Vision + coding**: `kimi-k2.5` ($1.32/1M)\n";
28943
- output += "- **Agentic**: `glm-5` ($1.68/1M)\n";
28944
- output += "- **Multimodal**: `qwen3.5-plus-02-15` ($1.40/1M)\n";
28945
- return { content: [{ type: "text", text: output }] };
28946
- });
28947
- server.tool("search_models", "Search all OpenRouter models by name, provider, or capability", {
28948
- query: exports_external.string().describe("Search query (e.g., 'grok', 'vision', 'free')"),
28949
- limit: exports_external.number().optional().describe("Maximum results to return (default: 10)")
28950
- }, async ({ query, limit }) => {
28951
- const maxResults = limit || 10;
28952
- const allModels = await loadAllModels();
28953
- if (allModels.length === 0) {
28954
- return {
28955
- content: [
28956
- { type: "text", text: "Failed to load models. Check your internet connection." }
28957
- ],
28958
- isError: true
28959
- };
28960
- }
28961
- const results = allModels.map((model) => {
28962
- const nameScore = fuzzyScore(model.name || "", query);
28963
- const idScore = fuzzyScore(model.id || "", query);
28964
- const descScore = fuzzyScore(model.description || "", query) * 0.5;
28965
- return { model, score: Math.max(nameScore, idScore, descScore) };
28966
- }).filter((item) => item.score > 0.2).sort((a, b) => b.score - a.score).slice(0, maxResults);
28967
- if (results.length === 0) {
28968
- return {
28969
- content: [{ type: "text", text: `No models found matching "${query}"` }]
28970
- };
28971
- }
28972
- let output = `# Search Results for "${query}"
28995
+ output += "- **Budget**: `minimax-m2.5` ($0.75/1M)\n";
28996
+ output += "- **Large context**: `gemini-3.1-pro-preview` (1M tokens)\n";
28997
+ output += "- **Most advanced**: `gpt-5.4` ($8.75/1M)\n";
28998
+ output += "- **Vision + coding**: `kimi-k2.5` ($1.32/1M)\n";
28999
+ output += "- **Agentic**: `glm-5` ($1.68/1M)\n";
29000
+ output += "- **Multimodal**: `qwen3.5-plus-02-15` ($1.40/1M)\n";
29001
+ return { content: [{ type: "text", text: output }] };
29002
+ });
29003
+ server.tool("search_models", "Search all OpenRouter models by name, provider, or capability", {
29004
+ query: exports_external.string().describe("Search query (e.g., 'grok', 'vision', 'free')"),
29005
+ limit: exports_external.number().optional().describe("Maximum results to return (default: 10)")
29006
+ }, async ({ query, limit }) => {
29007
+ const maxResults = limit || 10;
29008
+ const allModels = await loadAllModels();
29009
+ if (allModels.length === 0) {
29010
+ return {
29011
+ content: [
29012
+ { type: "text", text: "Failed to load models. Check your internet connection." }
29013
+ ],
29014
+ isError: true
29015
+ };
29016
+ }
29017
+ const results = allModels.map((model) => {
29018
+ const nameScore = fuzzyScore(model.name || "", query);
29019
+ const idScore = fuzzyScore(model.id || "", query);
29020
+ const descScore = fuzzyScore(model.description || "", query) * 0.5;
29021
+ return { model, score: Math.max(nameScore, idScore, descScore) };
29022
+ }).filter((item) => item.score > 0.2).sort((a, b) => b.score - a.score).slice(0, maxResults);
29023
+ if (results.length === 0) {
29024
+ return {
29025
+ content: [{ type: "text", text: `No models found matching "${query}"` }]
29026
+ };
29027
+ }
29028
+ let output = `# Search Results for "${query}"
28973
29029
 
28974
29030
  `;
28975
- output += `| Model | Provider | Pricing | Context |
29031
+ output += `| Model | Provider | Pricing | Context |
28976
29032
  `;
28977
- output += `|-------|----------|---------|----------|
29033
+ output += `|-------|----------|---------|----------|
28978
29034
  `;
28979
- for (const { model } of results) {
28980
- const provider = model.id.split("/")[0];
28981
- const promptPrice = parseFloat(model.pricing?.prompt || "0") * 1e6;
28982
- const completionPrice = parseFloat(model.pricing?.completion || "0") * 1e6;
28983
- const avgPrice = (promptPrice + completionPrice) / 2;
28984
- const pricing = avgPrice > 0 ? `$${avgPrice.toFixed(2)}/1M` : avgPrice < 0 ? "varies" : "FREE";
28985
- const context = model.context_length ? `${Math.round(model.context_length / 1000)}K` : "N/A";
28986
- output += `| ${model.id} | ${provider} | ${pricing} | ${context} |
29035
+ for (const { model } of results) {
29036
+ const provider = model.id.split("/")[0];
29037
+ const promptPrice = parseFloat(model.pricing?.prompt || "0") * 1e6;
29038
+ const completionPrice = parseFloat(model.pricing?.completion || "0") * 1e6;
29039
+ const avgPrice = (promptPrice + completionPrice) / 2;
29040
+ const pricing = avgPrice > 0 ? `$${avgPrice.toFixed(2)}/1M` : avgPrice < 0 ? "varies" : "FREE";
29041
+ const context = model.context_length ? `${Math.round(model.context_length / 1000)}K` : "N/A";
29042
+ output += `| ${model.id} | ${provider} | ${pricing} | ${context} |
28987
29043
  `;
28988
- }
28989
- output += `
29044
+ }
29045
+ output += `
28990
29046
  Use with: run_prompt(model="${results[0].model.id}", prompt="your prompt")`;
28991
- return { content: [{ type: "text", text: output }] };
28992
- });
28993
- server.tool("compare_models", "Run the same prompt through multiple models and compare responses", {
28994
- models: exports_external.array(exports_external.string()).describe("List of model IDs to compare"),
28995
- prompt: exports_external.string().describe("The prompt to send to all models"),
28996
- system_prompt: exports_external.string().optional().describe("Optional system prompt"),
28997
- max_tokens: exports_external.number().optional().describe("Maximum tokens in response (omit to let model decide)")
28998
- }, async ({ models, prompt, system_prompt, max_tokens }) => {
28999
- const results = [];
29000
- for (const model of models) {
29001
- try {
29002
- const result = await runPrompt(model, prompt, system_prompt, max_tokens);
29003
- results.push({
29004
- model,
29005
- response: result.content,
29006
- tokens: result.usage
29007
- });
29008
- } catch (error46) {
29009
- results.push({
29010
- model,
29011
- response: "",
29012
- error: error46 instanceof Error ? error46.message : String(error46)
29013
- });
29047
+ return { content: [{ type: "text", text: output }] };
29048
+ });
29049
+ server.tool("compare_models", "Run the same prompt through multiple models and compare responses", {
29050
+ models: exports_external.array(exports_external.string()).describe("List of model IDs to compare"),
29051
+ prompt: exports_external.string().describe("The prompt to send to all models"),
29052
+ system_prompt: exports_external.string().optional().describe("Optional system prompt"),
29053
+ max_tokens: exports_external.number().optional().describe("Maximum tokens in response (omit to let model decide)")
29054
+ }, async ({ models, prompt, system_prompt, max_tokens }) => {
29055
+ const results = [];
29056
+ for (const model of models) {
29057
+ try {
29058
+ const result = await runPrompt(model, prompt, system_prompt, max_tokens);
29059
+ results.push({
29060
+ model,
29061
+ response: result.content,
29062
+ tokens: result.usage
29063
+ });
29064
+ } catch (error46) {
29065
+ results.push({
29066
+ model,
29067
+ response: "",
29068
+ error: error46 instanceof Error ? error46.message : String(error46)
29069
+ });
29070
+ }
29014
29071
  }
29015
- }
29016
- let output = `# Model Comparison
29072
+ let output = `# Model Comparison
29017
29073
 
29018
29074
  `;
29019
- output += `**Prompt:** ${prompt.slice(0, 100)}${prompt.length > 100 ? "..." : ""}
29075
+ output += `**Prompt:** ${prompt.slice(0, 100)}${prompt.length > 100 ? "..." : ""}
29020
29076
 
29021
29077
  `;
29022
- for (const result of results) {
29023
- output += `## ${result.model}
29078
+ for (const result of results) {
29079
+ output += `## ${result.model}
29024
29080
 
29025
29081
  `;
29026
- if (result.error) {
29027
- output += `**Error:** ${result.error}
29082
+ if (result.error) {
29083
+ output += `**Error:** ${result.error}
29028
29084
 
29029
29085
  `;
29030
- } else {
29031
- output += result.response + `
29086
+ } else {
29087
+ output += result.response + `
29032
29088
 
29033
29089
  `;
29034
- if (result.tokens) {
29035
- output += `*Tokens: ${result.tokens.input} in, ${result.tokens.output} out*
29090
+ if (result.tokens) {
29091
+ output += `*Tokens: ${result.tokens.input} in, ${result.tokens.output} out*
29036
29092
 
29037
29093
  `;
29094
+ }
29038
29095
  }
29039
- }
29040
- output += `---
29096
+ output += `---
29041
29097
 
29042
29098
  `;
29043
- }
29044
- return { content: [{ type: "text", text: output }] };
29045
- });
29046
- server.tool("team_run", "Run multiple AI models on a task and produce anonymized outputs in a session directory", {
29047
- path: exports_external.string().describe("Session directory path (must be within current working directory)"),
29048
- models: exports_external.array(exports_external.string()).describe("Model IDs to run (e.g., ['minimax-m2.5', 'kimi-k2.5'])"),
29049
- input: exports_external.string().optional().describe("Task prompt text (or place input.md in the session directory before calling)"),
29050
- timeout: exports_external.number().optional().describe("Per-model timeout in seconds (default: 300)")
29051
- }, async ({ path, models, input, timeout }) => {
29052
- try {
29053
- const resolved = validateSessionPath(path);
29054
- setupSession(resolved, models, input);
29055
- const status = await runModels(resolved, { timeout });
29056
- return { content: [{ type: "text", text: JSON.stringify(status, null, 2) }] };
29057
- } catch (error46) {
29058
- return {
29059
- content: [
29060
- {
29061
- type: "text",
29062
- text: `Error: ${error46 instanceof Error ? error46.message : String(error46)}`
29063
- }
29064
- ],
29065
- isError: true
29066
- };
29067
- }
29068
- });
29069
- server.tool("team_judge", "Blind-judge existing anonymized model outputs in a session directory", {
29070
- path: exports_external.string().describe("Session directory containing response-*.md files (must be within current working directory)"),
29071
- judges: exports_external.array(exports_external.string()).optional().describe("Model IDs to use as judges (default: same models that produced the responses)")
29072
- }, async ({ path, judges }) => {
29073
- try {
29074
- const resolved = validateSessionPath(path);
29075
- const verdict = await judgeResponses(resolved, { judges });
29076
- return { content: [{ type: "text", text: JSON.stringify(verdict, null, 2) }] };
29077
- } catch (error46) {
29078
- return {
29079
- content: [
29080
- {
29081
- type: "text",
29082
- text: `Error: ${error46 instanceof Error ? error46.message : String(error46)}`
29099
+ }
29100
+ return { content: [{ type: "text", text: output }] };
29101
+ });
29102
+ }
29103
+ if (isAgentic) {
29104
+ server.tool("team", "Run AI models on a task with anonymized outputs and optional blind judging. Modes: 'run' (execute models), 'judge' (blind-vote on existing outputs), 'run-and-judge' (full pipeline), 'status' (check progress).", {
29105
+ mode: exports_external.enum(["run", "judge", "run-and-judge", "status"]).describe("Operation mode"),
29106
+ path: exports_external.string().describe("Session directory path (must be within current working directory)"),
29107
+ models: exports_external.array(exports_external.string()).optional().describe("Model IDs to run (required for 'run' and 'run-and-judge' modes)"),
29108
+ judges: exports_external.array(exports_external.string()).optional().describe("Model IDs to use as judges (default: same as runners)"),
29109
+ input: exports_external.string().optional().describe("Task prompt text (or place input.md in the session directory before calling)"),
29110
+ timeout: exports_external.number().optional().describe("Per-model timeout in seconds (default: 300)")
29111
+ }, async ({ mode, path, models, judges, input, timeout }) => {
29112
+ try {
29113
+ const resolved = validateSessionPath(path);
29114
+ switch (mode) {
29115
+ case "run": {
29116
+ if (!models?.length)
29117
+ throw new Error("'models' is required for 'run' mode");
29118
+ setupSession(resolved, models, input);
29119
+ const status = await runModels(resolved, { timeout });
29120
+ return { content: [{ type: "text", text: formatTeamResult(status, resolved) }] };
29121
+ }
29122
+ case "judge": {
29123
+ const verdict = await judgeResponses(resolved, { judges });
29124
+ return { content: [{ type: "text", text: JSON.stringify(verdict, null, 2) }] };
29125
+ }
29126
+ case "run-and-judge": {
29127
+ if (!models?.length)
29128
+ throw new Error("'models' is required for 'run-and-judge' mode");
29129
+ setupSession(resolved, models, input);
29130
+ await runModels(resolved, { timeout });
29131
+ const verdict = await judgeResponses(resolved, { judges });
29132
+ return { content: [{ type: "text", text: JSON.stringify(verdict, null, 2) }] };
29133
+ }
29134
+ case "status": {
29135
+ const status = getStatus(resolved);
29136
+ return { content: [{ type: "text", text: JSON.stringify(status, null, 2) }] };
29083
29137
  }
29084
- ],
29085
- isError: true
29086
- };
29087
- }
29088
- });
29089
- server.tool("team_run_and_judge", "Run multiple AI models on a task, then blind-judge their outputs \u2014 full pipeline", {
29090
- path: exports_external.string().describe("Session directory path (must be within current working directory)"),
29091
- models: exports_external.array(exports_external.string()).describe("Model IDs to run"),
29092
- judges: exports_external.array(exports_external.string()).optional().describe("Model IDs to use as judges (default: same as runners)"),
29093
- input: exports_external.string().optional().describe("Task prompt text"),
29094
- timeout: exports_external.number().optional().describe("Per-model timeout in seconds (default: 300)")
29095
- }, async ({ path, models, judges, input, timeout }) => {
29096
- try {
29097
- const resolved = validateSessionPath(path);
29098
- setupSession(resolved, models, input);
29099
- await runModels(resolved, { timeout });
29100
- const verdict = await judgeResponses(resolved, { judges });
29101
- return { content: [{ type: "text", text: JSON.stringify(verdict, null, 2) }] };
29102
- } catch (error46) {
29103
- return {
29104
- content: [
29105
- {
29106
- type: "text",
29107
- text: `Error: ${error46 instanceof Error ? error46.message : String(error46)}`
29138
+ }
29139
+ } catch (error46) {
29140
+ return {
29141
+ content: [
29142
+ {
29143
+ type: "text",
29144
+ text: `Error: ${error46 instanceof Error ? error46.message : String(error46)}`
29145
+ }
29146
+ ],
29147
+ isError: true
29148
+ };
29149
+ }
29150
+ });
29151
+ server.tool("report_error", "Report a claudish error to developers. IMPORTANT: Ask the user for consent BEFORE calling this tool. Show them what data will be sent (sanitized). All data is anonymized: API keys, user paths, and emails are stripped. Set auto_send=true to suggest the user enables automatic future reporting.", {
29152
+ error_type: exports_external.enum(["provider_failure", "team_failure", "stream_error", "adapter_error", "other"]).describe("Category of the error"),
29153
+ model: exports_external.string().optional().describe("Model ID that failed (anonymized in report)"),
29154
+ command: exports_external.string().optional().describe("Command that was run"),
29155
+ stderr_snippet: exports_external.string().optional().describe("First 500 chars of stderr output"),
29156
+ exit_code: exports_external.number().optional().describe("Process exit code"),
29157
+ error_log_path: exports_external.string().optional().describe("Path to full error log file"),
29158
+ session_path: exports_external.string().optional().describe("Path to team session directory"),
29159
+ additional_context: exports_external.string().optional().describe("Any extra context about the error"),
29160
+ auto_send: exports_external.boolean().optional().describe("If true, suggest the user enable automatic error reporting")
29161
+ }, async ({
29162
+ error_type,
29163
+ model,
29164
+ command,
29165
+ stderr_snippet,
29166
+ exit_code,
29167
+ error_log_path,
29168
+ session_path,
29169
+ additional_context,
29170
+ auto_send
29171
+ }) => {
29172
+ function sanitize(text) {
29173
+ if (!text)
29174
+ return "";
29175
+ return text.replace(/sk-[a-zA-Z0-9_-]{10,}/g, "sk-***REDACTED***").replace(/Bearer [a-zA-Z0-9_.-]+/g, "Bearer ***REDACTED***").replace(/\/Users\/[^/\s]+/g, "/Users/***").replace(/\/home\/[^/\s]+/g, "/home/***").replace(/[A-Z_]+_API_KEY=[^\s]+/g, "***_API_KEY=REDACTED").replace(/[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/g, "***@***.***");
29176
+ }
29177
+ let stderrFull = stderr_snippet || "";
29178
+ if (error_log_path) {
29179
+ try {
29180
+ stderrFull = readFileSync2(error_log_path, "utf-8");
29181
+ } catch {}
29182
+ }
29183
+ let sessionData = {};
29184
+ if (session_path) {
29185
+ const sp = session_path;
29186
+ for (const file2 of ["status.json", "manifest.json", "input.md"]) {
29187
+ try {
29188
+ sessionData[file2] = readFileSync2(join2(sp, file2), "utf-8");
29189
+ } catch {}
29190
+ }
29191
+ try {
29192
+ const errorDir = join2(sp, "errors");
29193
+ if (existsSync2(errorDir)) {
29194
+ for (const f of readdirSync2(errorDir)) {
29195
+ if (f.endsWith(".log")) {
29196
+ try {
29197
+ sessionData[`errors/${f}`] = readFileSync2(join2(errorDir, f), "utf-8");
29198
+ } catch {}
29199
+ }
29200
+ }
29108
29201
  }
29109
- ],
29110
- isError: true
29111
- };
29112
- }
29113
- });
29114
- server.tool("team_status", "Check the execution status of a team orchestrator session", {
29115
- path: exports_external.string().describe("Session directory path (must be within current working directory)")
29116
- }, async ({ path }) => {
29117
- try {
29118
- const resolved = validateSessionPath(path);
29119
- const status = getStatus(resolved);
29120
- return { content: [{ type: "text", text: JSON.stringify(status, null, 2) }] };
29121
- } catch (error46) {
29122
- return {
29123
- content: [
29124
- {
29125
- type: "text",
29126
- text: `Error: ${error46 instanceof Error ? error46.message : String(error46)}`
29202
+ } catch {}
29203
+ try {
29204
+ for (const f of readdirSync2(sp)) {
29205
+ if (f.startsWith("response-") && f.endsWith(".md")) {
29206
+ try {
29207
+ const content = readFileSync2(join2(sp, f), "utf-8");
29208
+ sessionData[f] = content.slice(0, 200) + (content.length > 200 ? "... (truncated)" : "");
29209
+ } catch {}
29210
+ }
29127
29211
  }
29128
- ],
29129
- isError: true
29212
+ } catch {}
29213
+ }
29214
+ let version2 = "unknown";
29215
+ try {
29216
+ const pkgPath = join2(__dirname2, "../package.json");
29217
+ if (existsSync2(pkgPath)) {
29218
+ version2 = JSON.parse(readFileSync2(pkgPath, "utf-8")).version;
29219
+ }
29220
+ } catch {}
29221
+ const report = {
29222
+ version: version2,
29223
+ timestamp: new Date().toISOString(),
29224
+ error_type,
29225
+ model: model || "unknown",
29226
+ command: sanitize(command),
29227
+ stderr: sanitize(stderrFull),
29228
+ exit_code: exit_code ?? null,
29229
+ platform: process.platform,
29230
+ arch: process.arch,
29231
+ runtime: `bun ${process.version}`,
29232
+ context: sanitize(additional_context),
29233
+ session: Object.fromEntries(Object.entries(sessionData).map(([k, v]) => [k, sanitize(v)]))
29130
29234
  };
29131
- }
29132
- });
29235
+ const reportSummary = JSON.stringify(report, null, 2);
29236
+ const autoSendHint = auto_send ? "\n\n**Suggestion:** Enable automatic error reporting so future errors are sent without asking. Run `claudish config` \u2192 Privacy \u2192 toggle Telemetry, or set `CLAUDISH_TELEMETRY=1`." : "";
29237
+ const REPORT_URL = "https://api.claudish.com/v1/error-reports";
29238
+ try {
29239
+ const response = await fetch(REPORT_URL, {
29240
+ method: "POST",
29241
+ headers: { "Content-Type": "application/json" },
29242
+ body: JSON.stringify(report),
29243
+ signal: AbortSignal.timeout(5000)
29244
+ });
29245
+ if (response.ok) {
29246
+ return { content: [{ type: "text", text: `Error report sent successfully.
29247
+
29248
+ **Sanitized data sent:**
29249
+ \`\`\`json
29250
+ ${reportSummary}
29251
+ \`\`\`${autoSendHint}` }] };
29252
+ } else {
29253
+ return { content: [{ type: "text", text: `Error report endpoint returned ${response.status}. Report was NOT sent.
29254
+
29255
+ **Data that would have been sent (all sanitized):**
29256
+ \`\`\`json
29257
+ ${reportSummary}
29258
+ \`\`\`
29259
+
29260
+ You can manually report this at https://github.com/anthropics/claudish/issues${autoSendHint}` }] };
29261
+ }
29262
+ } catch (err) {
29263
+ return { content: [{ type: "text", text: `Could not reach error reporting endpoint (${err instanceof Error ? err.message : "network error"}).
29264
+
29265
+ **Sanitized error data (for manual reporting):**
29266
+ \`\`\`json
29267
+ ${reportSummary}
29268
+ \`\`\`
29269
+
29270
+ Report manually at https://github.com/anthropics/claudish/issues${autoSendHint}` }] };
29271
+ }
29272
+ });
29273
+ }
29133
29274
  const transport = new StdioServerTransport;
29134
29275
  await server.connect(transport);
29135
- console.error("[claudish] MCP server started");
29136
29276
  }
29137
29277
  function startMcpServer() {
29138
29278
  main().catch((error46) => {
@@ -29173,7 +29313,7 @@ __export(exports_logger, {
29173
29313
  getLogFilePath: () => getLogFilePath,
29174
29314
  getAlwaysOnLogPath: () => getAlwaysOnLogPath
29175
29315
  });
29176
- import { writeFileSync as writeFileSync3, appendFile, existsSync as existsSync3, mkdirSync as mkdirSync3, readdirSync as readdirSync2, unlinkSync } from "fs";
29316
+ import { writeFileSync as writeFileSync3, appendFile, existsSync as existsSync3, mkdirSync as mkdirSync3, readdirSync as readdirSync3, unlinkSync } from "fs";
29177
29317
  import { join as join3 } from "path";
29178
29318
  import { homedir as homedir2 } from "os";
29179
29319
  function flushLogBuffer() {
@@ -29218,7 +29358,7 @@ function scheduleFlush() {
29218
29358
  }
29219
29359
  function rotateOldLogs(dir, keep) {
29220
29360
  try {
29221
- const files = readdirSync2(dir).filter((f) => f.startsWith("claudish_") && f.endsWith(".log")).sort().reverse();
29361
+ const files = readdirSync3(dir).filter((f) => f.startsWith("claudish_") && f.endsWith(".log")).sort().reverse();
29222
29362
  for (const file2 of files.slice(keep)) {
29223
29363
  try {
29224
29364
  unlinkSync(join3(dir, file2));
@@ -30284,7 +30424,8 @@ var init_config = __esm(() => {
30284
30424
  GEMINI_BASE_URL: "GEMINI_BASE_URL",
30285
30425
  OPENAI_API_KEY: "OPENAI_API_KEY",
30286
30426
  OPENAI_BASE_URL: "OPENAI_BASE_URL",
30287
- CLAUDISH_SUMMARIZE_TOOLS: "CLAUDISH_SUMMARIZE_TOOLS"
30427
+ CLAUDISH_SUMMARIZE_TOOLS: "CLAUDISH_SUMMARIZE_TOOLS",
30428
+ CLAUDISH_DIAG_MODE: "CLAUDISH_DIAG_MODE"
30288
30429
  };
30289
30430
  OPENROUTER_HEADERS = {
30290
30431
  "HTTP-Referer": "https://claudish.com",
@@ -33101,14 +33242,14 @@ var init_openai_tools = __esm(() => {
33101
33242
  init_transform();
33102
33243
  });
33103
33244
 
33104
- // src/adapters/base-adapter.ts
33245
+ // src/adapters/base-api-format.ts
33105
33246
  function matchesModelFamily(modelId, family) {
33106
33247
  const lower = modelId.toLowerCase();
33107
33248
  const fam = family.toLowerCase();
33108
33249
  return lower.startsWith(fam) || lower.includes(`/${fam}`);
33109
33250
  }
33110
33251
 
33111
- class BaseModelAdapter {
33252
+ class BaseAPIFormat {
33112
33253
  modelId;
33113
33254
  toolNameMap = new Map;
33114
33255
  constructor(modelId) {
@@ -33201,12 +33342,12 @@ class BaseModelAdapter {
33201
33342
  }
33202
33343
  }
33203
33344
  }
33204
- var DefaultAdapter;
33205
- var init_base_adapter = __esm(() => {
33345
+ var DefaultAPIFormat;
33346
+ var init_base_api_format = __esm(() => {
33206
33347
  init_tool_name_utils();
33207
33348
  init_remote_provider_types();
33208
33349
  init_openai_tools();
33209
- DefaultAdapter = class DefaultAdapter extends BaseModelAdapter {
33350
+ DefaultAPIFormat = class DefaultAPIFormat extends BaseAPIFormat {
33210
33351
  processTextContent(textContent, accumulatedText) {
33211
33352
  return {
33212
33353
  cleanedText: textContent,
@@ -33218,17 +33359,17 @@ var init_base_adapter = __esm(() => {
33218
33359
  return false;
33219
33360
  }
33220
33361
  getName() {
33221
- return "DefaultAdapter";
33362
+ return "DefaultAPIFormat";
33222
33363
  }
33223
33364
  };
33224
33365
  });
33225
33366
 
33226
- // src/adapters/grok-adapter.ts
33227
- var GrokAdapter;
33228
- var init_grok_adapter = __esm(() => {
33229
- init_base_adapter();
33367
+ // src/adapters/grok-model-dialect.ts
33368
+ var GrokModelDialect;
33369
+ var init_grok_model_dialect = __esm(() => {
33370
+ init_base_api_format();
33230
33371
  init_logger();
33231
- GrokAdapter = class GrokAdapter extends BaseModelAdapter {
33372
+ GrokModelDialect = class GrokModelDialect extends BaseAPIFormat {
33232
33373
  xmlBuffer = "";
33233
33374
  processTextContent(textContent, accumulatedText) {
33234
33375
  this.xmlBuffer += textContent;
@@ -33279,9 +33420,9 @@ var init_grok_adapter = __esm(() => {
33279
33420
  const { budget_tokens } = originalRequest.thinking;
33280
33421
  const effort = budget_tokens >= 20000 ? "high" : "low";
33281
33422
  request.reasoning_effort = effort;
33282
- log(`[GrokAdapter] Mapped budget ${budget_tokens} -> reasoning_effort: ${effort}`);
33423
+ log(`[GrokModelDialect] Mapped budget ${budget_tokens} -> reasoning_effort: ${effort}`);
33283
33424
  } else {
33284
- log(`[GrokAdapter] Model ${modelId} does not support reasoning params. Stripping.`);
33425
+ log(`[GrokModelDialect] Model ${modelId} does not support reasoning params. Stripping.`);
33285
33426
  }
33286
33427
  delete request.thinking;
33287
33428
  }
@@ -33306,7 +33447,7 @@ var init_grok_adapter = __esm(() => {
33306
33447
  return matchesModelFamily(modelId, "grok") || modelId.toLowerCase().includes("x-ai/");
33307
33448
  }
33308
33449
  getName() {
33309
- return "GrokAdapter";
33450
+ return "GrokModelDialect";
33310
33451
  }
33311
33452
  getContextWindow() {
33312
33453
  const model = this.modelId.toLowerCase();
@@ -34318,10 +34459,10 @@ var init_openai_compat = __esm(() => {
34318
34459
  init_openai_sse();
34319
34460
  });
34320
34461
 
34321
- // src/adapters/gemini-adapter.ts
34322
- var REASONING_PATTERNS, REASONING_CONTINUATION_PATTERNS, GeminiAdapter;
34323
- var init_gemini_adapter = __esm(() => {
34324
- init_base_adapter();
34462
+ // src/adapters/gemini-api-format.ts
34463
+ var REASONING_PATTERNS, REASONING_CONTINUATION_PATTERNS, GeminiAPIFormat;
34464
+ var init_gemini_api_format = __esm(() => {
34465
+ init_base_api_format();
34325
34466
  init_gemini_schema();
34326
34467
  init_openai_compat();
34327
34468
  init_logger();
@@ -34363,7 +34504,7 @@ var init_gemini_adapter = __esm(() => {
34363
34504
  /^Lines?\s+\d+/i,
34364
34505
  /^The\s+`[^`]+`\s+(?:is|has|contains|needs|should)/i
34365
34506
  ];
34366
- GeminiAdapter = class GeminiAdapter extends BaseModelAdapter {
34507
+ GeminiAPIFormat = class GeminiAPIFormat extends BaseAPIFormat {
34367
34508
  toolCallMap = new Map;
34368
34509
  inReasoningBlock = false;
34369
34510
  reasoningBlockDepth = 0;
@@ -34403,7 +34544,7 @@ var init_gemini_adapter = __esm(() => {
34403
34544
  } else if (block.type === "tool_result") {
34404
34545
  const toolInfo = this.toolCallMap.get(block.tool_use_id);
34405
34546
  if (!toolInfo) {
34406
- log(`[GeminiAdapter] Warning: No function name found for tool_use_id ${block.tool_use_id}`);
34547
+ log(`[GeminiAPIFormat] Warning: No function name found for tool_use_id ${block.tool_use_id}`);
34407
34548
  continue;
34408
34549
  }
34409
34550
  parts.push({
@@ -34432,7 +34573,7 @@ var init_gemini_adapter = __esm(() => {
34432
34573
  let thoughtSignature = toolInfo?.thoughtSignature;
34433
34574
  if (!thoughtSignature) {
34434
34575
  thoughtSignature = "skip_thought_signature_validator";
34435
- log(`[GeminiAdapter] Using dummy thoughtSignature for tool ${block.name} (${block.id})`);
34576
+ log(`[GeminiAPIFormat] Using dummy thoughtSignature for tool ${block.name} (${block.id})`);
34436
34577
  }
34437
34578
  const functionCallPart = {
34438
34579
  functionCall: {
@@ -34500,7 +34641,7 @@ CRITICAL INSTRUCTION FOR OUTPUT FORMAT:
34500
34641
  registerToolCall(toolId, name, thoughtSignature) {
34501
34642
  this.toolCallMap.set(toolId, { name, thoughtSignature });
34502
34643
  if (thoughtSignature) {
34503
- log(`[GeminiAdapter] Captured thoughtSignature for tool ${name} (${toolId})`);
34644
+ log(`[GeminiAPIFormat] Captured thoughtSignature for tool ${name} (${toolId})`);
34504
34645
  }
34505
34646
  }
34506
34647
  processTextContent(textContent, _accumulatedText) {
@@ -34518,14 +34659,14 @@ CRITICAL INSTRUCTION FOR OUTPUT FORMAT:
34518
34659
  continue;
34519
34660
  }
34520
34661
  if (this.isReasoningLine(trimmed)) {
34521
- log(`[GeminiAdapter] Filtered reasoning: "${trimmed.substring(0, 50)}..."`);
34662
+ log(`[GeminiAPIFormat] Filtered reasoning: "${trimmed.substring(0, 50)}..."`);
34522
34663
  wasFiltered = true;
34523
34664
  this.inReasoningBlock = true;
34524
34665
  this.reasoningBlockDepth++;
34525
34666
  continue;
34526
34667
  }
34527
34668
  if (this.inReasoningBlock && this.isReasoningContinuation(trimmed)) {
34528
- log(`[GeminiAdapter] Filtered reasoning continuation: "${trimmed.substring(0, 50)}..."`);
34669
+ log(`[GeminiAPIFormat] Filtered reasoning continuation: "${trimmed.substring(0, 50)}..."`);
34529
34670
  wasFiltered = true;
34530
34671
  continue;
34531
34672
  }
@@ -34563,7 +34704,7 @@ CRITICAL INSTRUCTION FOR OUTPUT FORMAT:
34563
34704
  return matchesModelFamily(modelId, "gemini") || modelId.toLowerCase().includes("google/");
34564
34705
  }
34565
34706
  getName() {
34566
- return "GeminiAdapter";
34707
+ return "GeminiAPIFormat";
34567
34708
  }
34568
34709
  extractThoughtSignaturesFromReasoningDetails(reasoningDetails) {
34569
34710
  const extracted = new Map;
@@ -34597,11 +34738,11 @@ CRITICAL INSTRUCTION FOR OUTPUT FORMAT:
34597
34738
  };
34598
34739
  });
34599
34740
 
34600
- // src/adapters/codex-adapter.ts
34601
- var CodexAdapter;
34602
- var init_codex_adapter = __esm(() => {
34603
- init_base_adapter();
34604
- CodexAdapter = class CodexAdapter extends BaseModelAdapter {
34741
+ // src/adapters/codex-api-format.ts
34742
+ var CodexAPIFormat;
34743
+ var init_codex_api_format = __esm(() => {
34744
+ init_base_api_format();
34745
+ CodexAPIFormat = class CodexAPIFormat extends BaseAPIFormat {
34605
34746
  constructor(modelId) {
34606
34747
  super(modelId);
34607
34748
  }
@@ -34616,7 +34757,7 @@ var init_codex_adapter = __esm(() => {
34616
34757
  return matchesModelFamily(modelId, "codex");
34617
34758
  }
34618
34759
  getName() {
34619
- return "CodexAdapter";
34760
+ return "CodexAPIFormat";
34620
34761
  }
34621
34762
  getStreamFormat() {
34622
34763
  return "openai-responses-sse";
@@ -34730,12 +34871,12 @@ var init_codex_adapter = __esm(() => {
34730
34871
  };
34731
34872
  });
34732
34873
 
34733
- // src/adapters/openai-adapter.ts
34734
- var OpenAIAdapter;
34735
- var init_openai_adapter = __esm(() => {
34736
- init_base_adapter();
34874
+ // src/adapters/openai-api-format.ts
34875
+ var OpenAIAPIFormat;
34876
+ var init_openai_api_format = __esm(() => {
34877
+ init_base_api_format();
34737
34878
  init_logger();
34738
- OpenAIAdapter = class OpenAIAdapter extends BaseModelAdapter {
34879
+ OpenAIAPIFormat = class OpenAIAPIFormat extends BaseAPIFormat {
34739
34880
  constructor(modelId) {
34740
34881
  super(modelId);
34741
34882
  }
@@ -34761,7 +34902,7 @@ var init_openai_adapter = __esm(() => {
34761
34902
  effort = "high";
34762
34903
  request.reasoning_effort = effort;
34763
34904
  delete request.thinking;
34764
- log(`[OpenAIAdapter] Mapped budget ${budget_tokens} -> reasoning_effort: ${effort}`);
34905
+ log(`[OpenAIAPIFormat] Mapped budget ${budget_tokens} -> reasoning_effort: ${effort}`);
34765
34906
  }
34766
34907
  this.truncateToolNames(request);
34767
34908
  if (request.messages) {
@@ -34773,7 +34914,7 @@ var init_openai_adapter = __esm(() => {
34773
34914
  return modelId.startsWith("oai/") || modelId.includes("o1") || modelId.includes("o3");
34774
34915
  }
34775
34916
  getName() {
34776
- return "OpenAIAdapter";
34917
+ return "OpenAIAPIFormat";
34777
34918
  }
34778
34919
  getContextWindow() {
34779
34920
  const model = this.modelId.toLowerCase();
@@ -34834,17 +34975,17 @@ var init_openai_adapter = __esm(() => {
34834
34975
  else if (budget_tokens >= 32000)
34835
34976
  effort = "high";
34836
34977
  payload.reasoning_effort = effort;
34837
- log(`[OpenAIAdapter] Mapped thinking.budget_tokens ${budget_tokens} -> reasoning_effort: ${effort}`);
34978
+ log(`[OpenAIAPIFormat] Mapped thinking.budget_tokens ${budget_tokens} -> reasoning_effort: ${effort}`);
34838
34979
  }
34839
34980
  return payload;
34840
34981
  }
34841
34982
  };
34842
34983
  });
34843
34984
 
34844
- // src/adapters/qwen-adapter.ts
34845
- var QWEN_SPECIAL_TOKENS, QwenAdapter;
34846
- var init_qwen_adapter = __esm(() => {
34847
- init_base_adapter();
34985
+ // src/adapters/qwen-model-dialect.ts
34986
+ var QWEN_SPECIAL_TOKENS, QwenModelDialect;
34987
+ var init_qwen_model_dialect = __esm(() => {
34988
+ init_base_api_format();
34848
34989
  init_logger();
34849
34990
  QWEN_SPECIAL_TOKENS = [
34850
34991
  "<|im_start|>",
@@ -34854,7 +34995,7 @@ var init_qwen_adapter = __esm(() => {
34854
34995
  `assistant
34855
34996
  `
34856
34997
  ];
34857
- QwenAdapter = class QwenAdapter extends BaseModelAdapter {
34998
+ QwenModelDialect = class QwenModelDialect extends BaseAPIFormat {
34858
34999
  processTextContent(textContent, accumulatedText) {
34859
35000
  let cleanedText = textContent;
34860
35001
  for (const token of QWEN_SPECIAL_TOKENS) {
@@ -34881,7 +35022,7 @@ var init_qwen_adapter = __esm(() => {
34881
35022
  const { budget_tokens } = originalRequest.thinking;
34882
35023
  request.enable_thinking = true;
34883
35024
  request.thinking_budget = budget_tokens;
34884
- log(`[QwenAdapter] Mapped budget ${budget_tokens} -> enable_thinking: true, thinking_budget: ${budget_tokens}`);
35025
+ log(`[QwenModelDialect] Mapped budget ${budget_tokens} -> enable_thinking: true, thinking_budget: ${budget_tokens}`);
34885
35026
  delete request.thinking;
34886
35027
  }
34887
35028
  return request;
@@ -34890,17 +35031,17 @@ var init_qwen_adapter = __esm(() => {
34890
35031
  return matchesModelFamily(modelId, "qwen") || matchesModelFamily(modelId, "alibaba");
34891
35032
  }
34892
35033
  getName() {
34893
- return "QwenAdapter";
35034
+ return "QwenModelDialect";
34894
35035
  }
34895
35036
  };
34896
35037
  });
34897
35038
 
34898
- // src/adapters/minimax-adapter.ts
34899
- var MiniMaxAdapter;
34900
- var init_minimax_adapter = __esm(() => {
34901
- init_base_adapter();
35039
+ // src/adapters/minimax-model-dialect.ts
35040
+ var MiniMaxModelDialect;
35041
+ var init_minimax_model_dialect = __esm(() => {
35042
+ init_base_api_format();
34902
35043
  init_logger();
34903
- MiniMaxAdapter = class MiniMaxAdapter extends BaseModelAdapter {
35044
+ MiniMaxModelDialect = class MiniMaxModelDialect extends BaseAPIFormat {
34904
35045
  processTextContent(textContent, accumulatedText) {
34905
35046
  return {
34906
35047
  cleanedText: textContent,
@@ -34911,7 +35052,7 @@ var init_minimax_adapter = __esm(() => {
34911
35052
  prepareRequest(request, originalRequest) {
34912
35053
  if (originalRequest.thinking) {
34913
35054
  request.reasoning_split = true;
34914
- log(`[MiniMaxAdapter] Enabled reasoning_split: true`);
35055
+ log(`[MiniMaxModelDialect] Enabled reasoning_split: true`);
34915
35056
  delete request.thinking;
34916
35057
  }
34917
35058
  return request;
@@ -34920,17 +35061,17 @@ var init_minimax_adapter = __esm(() => {
34920
35061
  return matchesModelFamily(modelId, "minimax");
34921
35062
  }
34922
35063
  getName() {
34923
- return "MiniMaxAdapter";
35064
+ return "MiniMaxModelDialect";
34924
35065
  }
34925
35066
  };
34926
35067
  });
34927
35068
 
34928
- // src/adapters/deepseek-adapter.ts
34929
- var DeepSeekAdapter;
34930
- var init_deepseek_adapter = __esm(() => {
34931
- init_base_adapter();
35069
+ // src/adapters/deepseek-model-dialect.ts
35070
+ var DeepSeekModelDialect;
35071
+ var init_deepseek_model_dialect = __esm(() => {
35072
+ init_base_api_format();
34932
35073
  init_logger();
34933
- DeepSeekAdapter = class DeepSeekAdapter extends BaseModelAdapter {
35074
+ DeepSeekModelDialect = class DeepSeekModelDialect extends BaseAPIFormat {
34934
35075
  processTextContent(textContent, accumulatedText) {
34935
35076
  return {
34936
35077
  cleanedText: textContent,
@@ -34940,7 +35081,7 @@ var init_deepseek_adapter = __esm(() => {
34940
35081
  }
34941
35082
  prepareRequest(request, originalRequest) {
34942
35083
  if (originalRequest.thinking) {
34943
- log(`[DeepSeekAdapter] Stripping thinking object (not supported by API)`);
35084
+ log(`[DeepSeekModelDialect] Stripping thinking object (not supported by API)`);
34944
35085
  delete request.thinking;
34945
35086
  }
34946
35087
  return request;
@@ -34949,15 +35090,15 @@ var init_deepseek_adapter = __esm(() => {
34949
35090
  return matchesModelFamily(modelId, "deepseek");
34950
35091
  }
34951
35092
  getName() {
34952
- return "DeepSeekAdapter";
35093
+ return "DeepSeekModelDialect";
34953
35094
  }
34954
35095
  };
34955
35096
  });
34956
35097
 
34957
- // src/adapters/glm-adapter.ts
34958
- var GLM_CONTEXT_WINDOWS, GLM_VISION_MODELS, GLMAdapter;
34959
- var init_glm_adapter = __esm(() => {
34960
- init_base_adapter();
35098
+ // src/adapters/glm-model-dialect.ts
35099
+ var GLM_CONTEXT_WINDOWS, GLM_VISION_MODELS, GLMModelDialect;
35100
+ var init_glm_model_dialect = __esm(() => {
35101
+ init_base_api_format();
34961
35102
  init_logger();
34962
35103
  GLM_CONTEXT_WINDOWS = [
34963
35104
  ["glm-5-turbo", 202752],
@@ -34979,7 +35120,7 @@ var init_glm_adapter = __esm(() => {
34979
35120
  ["glm-", 131072]
34980
35121
  ];
34981
35122
  GLM_VISION_MODELS = ["glm-4v", "glm-4v-plus", "glm-4.5v", "glm-4.6v", "glm-5"];
34982
- GLMAdapter = class GLMAdapter extends BaseModelAdapter {
35123
+ GLMModelDialect = class GLMModelDialect extends BaseAPIFormat {
34983
35124
  processTextContent(textContent, accumulatedText) {
34984
35125
  return {
34985
35126
  cleanedText: textContent,
@@ -34989,7 +35130,7 @@ var init_glm_adapter = __esm(() => {
34989
35130
  }
34990
35131
  prepareRequest(request, originalRequest) {
34991
35132
  if (originalRequest.thinking) {
34992
- log(`[GLMAdapter] Stripping thinking object (not supported by GLM API)`);
35133
+ log(`[GLMModelDialect] Stripping thinking object (not supported by GLM API)`);
34993
35134
  delete request.thinking;
34994
35135
  }
34995
35136
  return request;
@@ -34998,7 +35139,7 @@ var init_glm_adapter = __esm(() => {
34998
35139
  return matchesModelFamily(modelId, "glm-") || matchesModelFamily(modelId, "chatglm-") || modelId.toLowerCase().includes("zhipu/");
34999
35140
  }
35000
35141
  getName() {
35001
- return "GLMAdapter";
35142
+ return "GLMModelDialect";
35002
35143
  }
35003
35144
  getContextWindow() {
35004
35145
  const lower = this.modelId.toLowerCase();
@@ -35015,12 +35156,12 @@ var init_glm_adapter = __esm(() => {
35015
35156
  };
35016
35157
  });
35017
35158
 
35018
- // src/adapters/xiaomi-adapter.ts
35019
- var XiaomiAdapter;
35020
- var init_xiaomi_adapter = __esm(() => {
35021
- init_base_adapter();
35159
+ // src/adapters/xiaomi-model-dialect.ts
35160
+ var XiaomiModelDialect;
35161
+ var init_xiaomi_model_dialect = __esm(() => {
35162
+ init_base_api_format();
35022
35163
  init_logger();
35023
- XiaomiAdapter = class XiaomiAdapter extends BaseModelAdapter {
35164
+ XiaomiModelDialect = class XiaomiModelDialect extends BaseAPIFormat {
35024
35165
  processTextContent(textContent, accumulatedText) {
35025
35166
  return {
35026
35167
  cleanedText: textContent,
@@ -35033,7 +35174,7 @@ var init_xiaomi_adapter = __esm(() => {
35033
35174
  }
35034
35175
  prepareRequest(request, originalRequest) {
35035
35176
  if (originalRequest.thinking) {
35036
- log(`[XiaomiAdapter] Stripping thinking object (not supported by Xiaomi API)`);
35177
+ log(`[XiaomiModelDialect] Stripping thinking object (not supported by Xiaomi API)`);
35037
35178
  delete request.thinking;
35038
35179
  }
35039
35180
  this.truncateToolNames(request);
@@ -35046,33 +35187,34 @@ var init_xiaomi_adapter = __esm(() => {
35046
35187
  return matchesModelFamily(modelId, "xiaomi") || matchesModelFamily(modelId, "mimo");
35047
35188
  }
35048
35189
  getName() {
35049
- return "XiaomiAdapter";
35190
+ return "XiaomiModelDialect";
35050
35191
  }
35051
35192
  };
35052
35193
  });
35053
35194
 
35054
- // src/adapters/adapter-manager.ts
35055
- var exports_adapter_manager = {};
35056
- __export(exports_adapter_manager, {
35057
- AdapterManager: () => AdapterManager
35195
+ // src/adapters/dialect-manager.ts
35196
+ var exports_dialect_manager = {};
35197
+ __export(exports_dialect_manager, {
35198
+ DialectManager: () => DialectManager,
35199
+ AdapterManager: () => DialectManager
35058
35200
  });
35059
35201
 
35060
- class AdapterManager {
35202
+ class DialectManager {
35061
35203
  adapters;
35062
35204
  defaultAdapter;
35063
35205
  constructor(modelId) {
35064
35206
  this.adapters = [
35065
- new GrokAdapter(modelId),
35066
- new GeminiAdapter(modelId),
35067
- new CodexAdapter(modelId),
35068
- new OpenAIAdapter(modelId),
35069
- new QwenAdapter(modelId),
35070
- new MiniMaxAdapter(modelId),
35071
- new DeepSeekAdapter(modelId),
35072
- new GLMAdapter(modelId),
35073
- new XiaomiAdapter(modelId)
35207
+ new GrokModelDialect(modelId),
35208
+ new GeminiAPIFormat(modelId),
35209
+ new CodexAPIFormat(modelId),
35210
+ new OpenAIAPIFormat(modelId),
35211
+ new QwenModelDialect(modelId),
35212
+ new MiniMaxModelDialect(modelId),
35213
+ new DeepSeekModelDialect(modelId),
35214
+ new GLMModelDialect(modelId),
35215
+ new XiaomiModelDialect(modelId)
35074
35216
  ];
35075
- this.defaultAdapter = new DefaultAdapter(modelId);
35217
+ this.defaultAdapter = new DefaultAPIFormat(modelId);
35076
35218
  }
35077
35219
  getAdapter() {
35078
35220
  for (const adapter of this.adapters) {
@@ -35086,17 +35228,17 @@ class AdapterManager {
35086
35228
  return this.getAdapter() !== this.defaultAdapter;
35087
35229
  }
35088
35230
  }
35089
- var init_adapter_manager = __esm(() => {
35090
- init_base_adapter();
35091
- init_grok_adapter();
35092
- init_gemini_adapter();
35093
- init_codex_adapter();
35094
- init_openai_adapter();
35095
- init_qwen_adapter();
35096
- init_minimax_adapter();
35097
- init_deepseek_adapter();
35098
- init_glm_adapter();
35099
- init_xiaomi_adapter();
35231
+ var init_dialect_manager = __esm(() => {
35232
+ init_base_api_format();
35233
+ init_grok_model_dialect();
35234
+ init_gemini_api_format();
35235
+ init_codex_api_format();
35236
+ init_openai_api_format();
35237
+ init_qwen_model_dialect();
35238
+ init_minimax_model_dialect();
35239
+ init_deepseek_model_dialect();
35240
+ init_glm_model_dialect();
35241
+ init_xiaomi_model_dialect();
35100
35242
  });
35101
35243
 
35102
35244
  // src/cli.ts
@@ -35118,7 +35260,7 @@ import {
35118
35260
  existsSync as existsSync14,
35119
35261
  mkdirSync as mkdirSync6,
35120
35262
  copyFileSync,
35121
- readdirSync as readdirSync3,
35263
+ readdirSync as readdirSync4,
35122
35264
  unlinkSync as unlinkSync4
35123
35265
  } from "fs";
35124
35266
  import { fileURLToPath as fileURLToPath3 } from "url";
@@ -35134,7 +35276,7 @@ function clearAllModelCaches() {
35134
35276
  const cachePatterns = ["all-models.json", "pricing-cache.json"];
35135
35277
  let cleared = 0;
35136
35278
  try {
35137
- const files = readdirSync3(cacheDir);
35279
+ const files = readdirSync4(cacheDir);
35138
35280
  for (const file2 of files) {
35139
35281
  if (cachePatterns.includes(file2) || file2.startsWith("litellm-models-")) {
35140
35282
  unlinkSync4(join14(cacheDir, file2));
@@ -35162,6 +35304,7 @@ async function parseArgs(args) {
35162
35304
  stdin: false,
35163
35305
  freeOnly: false,
35164
35306
  noLogs: false,
35307
+ diagMode: "auto",
35165
35308
  claudeArgs: []
35166
35309
  };
35167
35310
  const claudishModel = process.env[ENV.CLAUDISH_MODEL];
@@ -35186,6 +35329,10 @@ async function parseArgs(args) {
35186
35329
  if (envSummarizeTools === "true" || envSummarizeTools === "1") {
35187
35330
  config3.summarizeTools = true;
35188
35331
  }
35332
+ const envDiagMode = process.env[ENV.CLAUDISH_DIAG_MODE]?.toLowerCase();
35333
+ if (envDiagMode && ["auto", "pty", "tmux", "logfile", "off"].includes(envDiagMode)) {
35334
+ config3.diagMode = envDiagMode;
35335
+ }
35189
35336
  let i = 0;
35190
35337
  while (i < args.length) {
35191
35338
  const arg = args[i];
@@ -35330,6 +35477,11 @@ async function parseArgs(args) {
35330
35477
  config3.summarizeTools = true;
35331
35478
  } else if (arg === "--no-logs") {
35332
35479
  config3.noLogs = true;
35480
+ } else if (arg === "--diag-mode" && i + 1 < args.length) {
35481
+ const mode = args[++i].toLowerCase();
35482
+ if (["auto", "pty", "tmux", "logfile", "off"].includes(mode)) {
35483
+ config3.diagMode = mode;
35484
+ }
35333
35485
  } else if (arg === "--") {
35334
35486
  config3.claudeArgs.push(...args.slice(i + 1));
35335
35487
  break;
@@ -36035,31 +36187,31 @@ async function probeModelRouting(models, jsonOutput) {
36035
36187
  const { resolveRemoteProvider: resolveRemoteProvider2 } = await Promise.resolve().then(() => (init_remote_provider_registry(), exports_remote_provider_registry));
36036
36188
  const resolvedSpec = resolveRemoteProvider2(firstReadyRoute.modelSpec);
36037
36189
  const modelName = resolvedSpec?.modelName || parsed.model;
36038
- let formatAdapterName = "OpenAIAdapter";
36190
+ let formatAdapterName = "OpenAIAPIFormat";
36039
36191
  let declaredStreamFormat = "openai-sse";
36040
36192
  const anthropicCompatProviders = ["minimax", "minimax-coding", "kimi", "kimi-coding", "zai"];
36041
36193
  const isMinimaxModel = modelName.toLowerCase().includes("minimax");
36042
36194
  if (anthropicCompatProviders.includes(providerName)) {
36043
- formatAdapterName = "AnthropicPassthroughAdapter";
36195
+ formatAdapterName = "AnthropicAPIFormat";
36044
36196
  declaredStreamFormat = "anthropic-sse";
36045
36197
  } else if ((providerName === "opencode-zen" || providerName === "opencode-zen-go") && isMinimaxModel) {
36046
- formatAdapterName = "AnthropicPassthroughAdapter";
36198
+ formatAdapterName = "AnthropicAPIFormat";
36047
36199
  declaredStreamFormat = "anthropic-sse";
36048
36200
  } else if (providerName === "gemini" || providerName === "gemini-codeassist") {
36049
- formatAdapterName = "GeminiAdapter";
36201
+ formatAdapterName = "GeminiAPIFormat";
36050
36202
  declaredStreamFormat = "gemini-sse";
36051
36203
  } else if (providerName === "ollamacloud") {
36052
- formatAdapterName = "OllamaCloudAdapter";
36204
+ formatAdapterName = "OllamaAPIFormat";
36053
36205
  declaredStreamFormat = "openai-sse";
36054
36206
  } else if (providerName === "litellm") {
36055
- formatAdapterName = "LiteLLMAdapter";
36207
+ formatAdapterName = "LiteLLMAPIFormat";
36056
36208
  declaredStreamFormat = "openai-sse";
36057
36209
  } else {
36058
- formatAdapterName = "OpenAIAdapter";
36210
+ formatAdapterName = "OpenAIAPIFormat";
36059
36211
  declaredStreamFormat = "openai-sse";
36060
36212
  }
36061
- const { AdapterManager: AdapterManager2 } = await Promise.resolve().then(() => (init_adapter_manager(), exports_adapter_manager));
36062
- const adapterManager = new AdapterManager2(modelName);
36213
+ const { DialectManager: DialectManager2 } = await Promise.resolve().then(() => (init_dialect_manager(), exports_dialect_manager));
36214
+ const adapterManager = new DialectManager2(modelName);
36063
36215
  const modelTranslator = adapterManager.getAdapter();
36064
36216
  const modelTranslatorName = modelTranslator.getName();
36065
36217
  const TRANSPORT_OVERRIDES = {
@@ -36067,7 +36219,7 @@ async function probeModelRouting(models, jsonOutput) {
36067
36219
  openrouter: "openai-sse"
36068
36220
  };
36069
36221
  const transportOverride = TRANSPORT_OVERRIDES[providerName] || null;
36070
- const modelTranslatorFormat = modelTranslatorName !== "DefaultAdapter" ? modelTranslator.getStreamFormat() : null;
36222
+ const modelTranslatorFormat = modelTranslatorName !== "DefaultAPIFormat" ? modelTranslator.getStreamFormat() : null;
36071
36223
  const effectiveStreamFormat = transportOverride || modelTranslatorFormat || declaredStreamFormat;
36072
36224
  wiring = {
36073
36225
  formatAdapter: formatAdapterName,
@@ -36260,6 +36412,7 @@ OPTIONS:
36260
36412
  --port <port> Proxy server port (default: random)
36261
36413
  -d, --debug Enable debug logging to file (logs/claudish_*.log)
36262
36414
  --no-logs Disable always-on structural logging (~/.claudish/logs/)
36415
+ --diag-mode <mode> Diagnostic output: auto (default), pty, tmux, logfile, off
36263
36416
  --log-level <level> Log verbosity: debug (full), info (truncated), minimal (labels only)
36264
36417
  -q, --quiet Suppress [claudish] log messages (default in single-shot mode)
36265
36418
  -v, --verbose Show [claudish] log messages (default in interactive mode)
@@ -36738,7 +36891,7 @@ async function fetchGLMCodingModels() {
36738
36891
  return [];
36739
36892
  }
36740
36893
  }
36741
- var __filename4, __dirname4, VERSION = "5.18.1", CACHE_MAX_AGE_DAYS2 = 2, CLAUDISH_CACHE_DIR2, BUNDLED_MODELS_PATH, CACHED_MODELS_PATH, ALL_MODELS_JSON_PATH;
36894
+ var __filename4, __dirname4, VERSION = "6.0.0", CACHE_MAX_AGE_DAYS2 = 2, CLAUDISH_CACHE_DIR2, BUNDLED_MODELS_PATH, CACHED_MODELS_PATH, ALL_MODELS_JSON_PATH;
36742
36895
  var init_cli = __esm(() => {
36743
36896
  init_config();
36744
36897
  init_model_loader();
@@ -41799,7 +41952,7 @@ function recordStats(partial2) {
41799
41952
  estimated_cost: partial2.estimated_cost ?? 0,
41800
41953
  is_free_model: partial2.is_free_model ?? false,
41801
41954
  token_strategy: partial2.token_strategy ?? "standard",
41802
- adapter_name: partial2.adapter_name ?? "DefaultAdapter",
41955
+ adapter_name: partial2.adapter_name ?? "DefaultAPIFormat",
41803
41956
  middleware_names: partial2.middleware_names ?? [],
41804
41957
  fallback_used: partial2.fallback_used ?? false,
41805
41958
  invocation_mode: partial2.invocation_mode ?? "auto-route",
@@ -98068,17 +98221,28 @@ var init_providers = __esm(() => {
98068
98221
  var C2;
98069
98222
  var init_theme2 = __esm(() => {
98070
98223
  C2 = {
98071
- bg: "#1a1b26",
98072
- bgAlt: "#24283b",
98073
- fg: "#c0caf5",
98074
- dim: "#565f89",
98075
- border: "#3b4261",
98076
- focusBorder: "#7aa2f7",
98077
- green: "#9ece6a",
98078
- red: "#f7768e",
98079
- yellow: "#e0af68",
98080
- cyan: "#7dcfff",
98081
- blue: "#7aa2f7"
98224
+ bg: "#000000",
98225
+ bgAlt: "#111111",
98226
+ bgHighlight: "#1e3a5f",
98227
+ fg: "#ffffff",
98228
+ fgMuted: "#a0a0a0",
98229
+ dim: "#555555",
98230
+ border: "#333333",
98231
+ focusBorder: "#57a5ff",
98232
+ green: "#39ff14",
98233
+ brightGreen: "#55ff55",
98234
+ red: "#ff003c",
98235
+ yellow: "#fce94f",
98236
+ cyan: "#00ffff",
98237
+ blue: "#0088ff",
98238
+ magenta: "#ff00ff",
98239
+ orange: "#ff8800",
98240
+ white: "#ffffff",
98241
+ black: "#000000",
98242
+ tabActiveBg: "#0088ff",
98243
+ tabInactiveBg: "#001a33",
98244
+ tabActiveFg: "#ffffff",
98245
+ tabInactiveFg: "#0088ff"
98082
98246
  };
98083
98247
  });
98084
98248
 
@@ -98088,1104 +98252,1205 @@ var init_jsx_dev_runtime = __esm(() => {
98088
98252
  import_jsx_dev_runtime2 = __toESM(require_jsx_dev_runtime(), 1);
98089
98253
  });
98090
98254
 
98091
- // src/tui/panels/ApiKeysPanel.tsx
98092
- function pad(str, len) {
98093
- return str.padEnd(len).substring(0, len);
98255
+ // src/tui/App.tsx
98256
+ function bytesHuman(b2) {
98257
+ if (b2 < 1024)
98258
+ return `${b2} B`;
98259
+ if (b2 < 1024 * 1024)
98260
+ return `${(b2 / 1024).toFixed(1)} KB`;
98261
+ return `${(b2 / (1024 * 1024)).toFixed(1)} MB`;
98094
98262
  }
98095
- function ApiKeysPanel({ focused, height: height2, width, onEditingChange }) {
98263
+ function App() {
98264
+ const renderer = useRenderer();
98265
+ const { width, height: height2 } = useTerminalDimensions();
98096
98266
  const [config3, setConfig] = import_react13.useState(() => loadConfig());
98267
+ const [bufStats, setBufStats] = import_react13.useState(() => getBufferStats());
98268
+ const [providerIndex, setProviderIndex] = import_react13.useState(0);
98269
+ const [activeTab, setActiveTab] = import_react13.useState("providers");
98097
98270
  const [mode, setMode] = import_react13.useState("browse");
98098
- const [itemIndex, setItemIndex] = import_react13.useState(0);
98099
- const [actionIndex, setActionIndex] = import_react13.useState(0);
98100
98271
  const [inputValue, setInputValue] = import_react13.useState("");
98272
+ const [routingPattern, setRoutingPattern] = import_react13.useState("");
98273
+ const [routingChain, setRoutingChain] = import_react13.useState("");
98101
98274
  const [statusMsg, setStatusMsg] = import_react13.useState(null);
98102
- import_react13.useEffect(() => {
98103
- onEditingChange?.(mode !== "browse");
98104
- }, [mode, onEditingChange]);
98105
- const selectedProvider = PROVIDERS[itemIndex];
98106
- const getActionOptions = import_react13.useCallback(() => {
98107
- const p = selectedProvider;
98108
- const hasCfgKey = !!config3.apiKeys?.[p.apiKeyEnvVar];
98109
- const hasCfgEnd = p.endpointEnvVar ? !!config3.endpoints?.[p.endpointEnvVar] : false;
98110
- const opts = [
98111
- { name: "Set API Key...", value: "set_key" }
98112
- ];
98113
- if (hasCfgKey)
98114
- opts.push({ name: "Remove stored API Key", value: "rm_key" });
98115
- if (p.endpointEnvVar) {
98116
- opts.push({ name: "Set Custom Endpoint...", value: "set_end" });
98117
- if (hasCfgEnd)
98118
- opts.push({ name: "Remove Custom Endpoint", value: "rm_end" });
98119
- }
98120
- opts.push({ name: "Back", value: "back" });
98121
- return opts;
98122
- }, [selectedProvider, config3]);
98123
- const handleActionSelect = import_react13.useCallback((_idx, opt) => {
98124
- if (!opt?.value)
98125
- return;
98126
- const { value } = opt;
98127
- setStatusMsg(null);
98128
- if (value === "back") {
98129
- setMode("browse");
98130
- } else if (value === "set_key") {
98131
- setInputValue("");
98132
- setMode("input_key");
98133
- } else if (value === "set_end") {
98134
- setInputValue(selectedProvider.endpointEnvVar ? config3.endpoints?.[selectedProvider.endpointEnvVar] || "" : "");
98135
- setMode("input_endpoint");
98136
- } else if (value === "rm_key") {
98137
- removeApiKey(selectedProvider.apiKeyEnvVar);
98138
- setConfig(loadConfig());
98139
- setStatusMsg("\u2713 Key removed from config.");
98140
- setMode("browse");
98141
- } else if (value === "rm_end" && selectedProvider.endpointEnvVar) {
98142
- removeEndpoint(selectedProvider.endpointEnvVar);
98143
- setConfig(loadConfig());
98144
- setStatusMsg("\u2713 Endpoint reset.");
98145
- setMode("browse");
98146
- }
98147
- }, [selectedProvider, config3]);
98275
+ const quit = import_react13.useCallback(() => renderer.destroy(), [renderer]);
98276
+ const displayProviders = import_react13.useMemo(() => {
98277
+ return [...PROVIDERS].sort((a, b2) => {
98278
+ const aHasKey = !!(config3.apiKeys?.[a.apiKeyEnvVar] || process.env[a.apiKeyEnvVar]);
98279
+ const bHasKey = !!(config3.apiKeys?.[b2.apiKeyEnvVar] || process.env[b2.apiKeyEnvVar]);
98280
+ if (aHasKey === bHasKey)
98281
+ return PROVIDERS.indexOf(a) - PROVIDERS.indexOf(b2);
98282
+ return aHasKey ? -1 : 1;
98283
+ });
98284
+ }, [config3]);
98285
+ const selectedProvider = displayProviders[providerIndex];
98286
+ const refreshConfig = import_react13.useCallback(() => {
98287
+ setConfig(loadConfig());
98288
+ setBufStats(getBufferStats());
98289
+ }, []);
98290
+ const hasCfgKey = !!config3.apiKeys?.[selectedProvider.apiKeyEnvVar];
98291
+ const hasEnvKey = !!process.env[selectedProvider.apiKeyEnvVar];
98292
+ const hasKey = hasCfgKey || hasEnvKey;
98293
+ const cfgKeyMask = maskKey2(config3.apiKeys?.[selectedProvider.apiKeyEnvVar]);
98294
+ const envKeyMask = maskKey2(process.env[selectedProvider.apiKeyEnvVar]);
98295
+ const keySrc = hasEnvKey && hasCfgKey ? "e+c" : hasEnvKey ? "env" : hasCfgKey ? "cfg" : "";
98296
+ const activeEndpoint = (selectedProvider.endpointEnvVar ? config3.endpoints?.[selectedProvider.endpointEnvVar] || process.env[selectedProvider.endpointEnvVar] : undefined) || selectedProvider.defaultEndpoint || "";
98297
+ const telemetryEnabled = process.env.CLAUDISH_TELEMETRY !== "0" && process.env.CLAUDISH_TELEMETRY !== "false" && config3.telemetry?.enabled === true;
98298
+ const statsEnabled2 = process.env.CLAUDISH_STATS !== "0" && process.env.CLAUDISH_STATS !== "false";
98299
+ const ruleEntries = Object.entries(config3.routing ?? {});
98300
+ const profileName = config3.defaultProfile || "default";
98301
+ const readyCount = PROVIDERS.filter((p) => !!(config3.apiKeys?.[p.apiKeyEnvVar] || process.env[p.apiKeyEnvVar])).length;
98148
98302
  useKeyboard((key) => {
98149
- if (!focused)
98150
- return;
98303
+ if (key.ctrl && key.name === "c")
98304
+ return quit();
98151
98305
  if (mode === "input_key" || mode === "input_endpoint") {
98152
98306
  if (key.name === "return" || key.name === "enter") {
98153
98307
  const val = inputValue.trim();
98154
98308
  if (!val) {
98155
- setStatusMsg("\u2717 Aborted (empty).");
98309
+ setStatusMsg("Aborted (empty).");
98156
98310
  setMode("browse");
98157
98311
  return;
98158
98312
  }
98159
98313
  if (mode === "input_key") {
98160
98314
  setApiKey(selectedProvider.apiKeyEnvVar, val);
98161
98315
  process.env[selectedProvider.apiKeyEnvVar] = val;
98162
- setStatusMsg(`\u2713 API Key saved for ${selectedProvider.displayName}.`);
98316
+ setStatusMsg(`Key saved for ${selectedProvider.displayName}.`);
98163
98317
  } else {
98164
- setEndpoint(selectedProvider.endpointEnvVar, val);
98165
- process.env[selectedProvider.endpointEnvVar] = val;
98166
- setStatusMsg(`\u2713 Custom endpoint saved.`);
98318
+ if (selectedProvider.endpointEnvVar) {
98319
+ setEndpoint(selectedProvider.endpointEnvVar, val);
98320
+ process.env[selectedProvider.endpointEnvVar] = val;
98321
+ }
98322
+ setStatusMsg("Endpoint saved.");
98167
98323
  }
98168
- setConfig(loadConfig());
98324
+ refreshConfig();
98169
98325
  setInputValue("");
98170
98326
  setMode("browse");
98171
98327
  } else if (key.name === "escape") {
98172
- setMode("action");
98173
- }
98174
- } else if (mode === "action" && (key.name === "escape" || key.name === "q")) {
98175
- setMode("browse");
98176
- }
98177
- });
98178
- const listHeight = Math.max(3, height2 - 8);
98179
- const bottomHeight = height2 - listHeight - 1;
98180
- const listOptions = PROVIDERS.map((p) => {
98181
- const hasEnvK = !!process.env[p.apiKeyEnvVar];
98182
- const hasCfgK = !!config3.apiKeys?.[p.apiKeyEnvVar];
98183
- const icon = hasEnvK || hasCfgK ? "\u2713" : "\u2717";
98184
- const kStr = p.apiKeyEnvVar ? pad(maskKey2(hasCfgK ? config3.apiKeys[p.apiKeyEnvVar] : process.env[p.apiKeyEnvVar]), 8) : " ";
98185
- const kSrc = hasEnvK && hasCfgK ? "e+c" : hasEnvK ? "env" : hasCfgK ? "cfg" : "---";
98186
- let eSrc = " ";
98187
- if (p.endpointEnvVar) {
98188
- const hasEnvE = !!process.env[p.endpointEnvVar];
98189
- const hasCfgE = !!config3.endpoints?.[p.endpointEnvVar];
98190
- eSrc = hasEnvE && hasCfgE ? "e+c" : hasEnvE ? "env" : hasCfgE ? "cfg" : "def";
98328
+ setInputValue("");
98329
+ setMode("browse");
98330
+ }
98331
+ return;
98191
98332
  }
98192
- return {
98193
- name: ` ${icon} ${pad(p.displayName, 14)} ${kStr} ${pad(kSrc, 3)} ${pad(eSrc, 3)}`,
98194
- value: p.name
98195
- };
98196
- });
98197
- const envKeyMask = maskKey2(process.env[selectedProvider.apiKeyEnvVar]);
98198
- const cfgKeyMask = maskKey2(config3.apiKeys?.[selectedProvider.apiKeyEnvVar]);
98199
- const activeUrl = config3.endpoints?.[selectedProvider.endpointEnvVar] || process.env[selectedProvider.endpointEnvVar] || selectedProvider.defaultEndpoint || "None";
98200
- const divider = "\u2500".repeat(Math.max(1, width - 2));
98201
- return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
98202
- flexDirection: "column",
98203
- height: height2,
98204
- children: [
98205
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
98206
- height: 1,
98207
- paddingX: 1,
98208
- children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
98209
- children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98210
- fg: C2.dim,
98211
- children: " PROVIDER KEY SRC URL"
98212
- }, undefined, false, undefined, this)
98213
- }, undefined, false, undefined, this)
98214
- }, undefined, false, undefined, this),
98215
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("select", {
98216
- options: listOptions,
98217
- focused: focused && mode === "browse",
98218
- height: listHeight - 1,
98219
- selectedIndex: itemIndex,
98220
- onSelect: () => {
98221
- setMode("action");
98222
- setActionIndex(0);
98333
+ if (mode === "add_routing_pattern") {
98334
+ if (key.name === "return" || key.name === "enter") {
98335
+ if (routingPattern.trim())
98336
+ setMode("add_routing_chain");
98337
+ } else if (key.name === "escape") {
98338
+ setMode("browse");
98339
+ }
98340
+ return;
98341
+ }
98342
+ if (mode === "add_routing_chain") {
98343
+ if (key.name === "return" || key.name === "enter") {
98344
+ const pat = routingPattern.trim();
98345
+ const ch = routingChain.trim().split(",").map((s) => s.trim()).filter(Boolean);
98346
+ if (pat && ch.length) {
98347
+ const cfg = loadConfig();
98348
+ if (!cfg.routing)
98349
+ cfg.routing = {};
98350
+ cfg.routing[pat] = ch;
98351
+ saveConfig(cfg);
98352
+ refreshConfig();
98353
+ setStatusMsg(`Rule added for '${pat}'.`);
98354
+ }
98355
+ setRoutingPattern("");
98356
+ setRoutingChain("");
98357
+ setMode("browse");
98358
+ } else if (key.name === "escape") {
98359
+ setMode("add_routing_pattern");
98360
+ }
98361
+ return;
98362
+ }
98363
+ if (key.name === "q")
98364
+ return quit();
98365
+ if (key.name === "tab") {
98366
+ const tabs = ["providers", "routing", "privacy"];
98367
+ const idx = tabs.indexOf(activeTab);
98368
+ setActiveTab(tabs[(idx + 1) % tabs.length]);
98369
+ setStatusMsg(null);
98370
+ return;
98371
+ }
98372
+ if (key.name === "1") {
98373
+ setActiveTab("providers");
98374
+ setStatusMsg(null);
98375
+ return;
98376
+ }
98377
+ if (key.name === "2") {
98378
+ setActiveTab("routing");
98379
+ setStatusMsg(null);
98380
+ return;
98381
+ }
98382
+ if (key.name === "3") {
98383
+ setActiveTab("privacy");
98384
+ setStatusMsg(null);
98385
+ return;
98386
+ }
98387
+ if (activeTab === "providers") {
98388
+ if (key.name === "up" || key.name === "k") {
98389
+ setProviderIndex((i) => Math.max(0, i - 1));
98390
+ setStatusMsg(null);
98391
+ } else if (key.name === "down" || key.name === "j") {
98392
+ setProviderIndex((i) => Math.min(displayProviders.length - 1, i + 1));
98393
+ setStatusMsg(null);
98394
+ } else if (key.name === "s") {
98395
+ setInputValue("");
98396
+ setStatusMsg(null);
98397
+ setMode("input_key");
98398
+ } else if (key.name === "e") {
98399
+ if (selectedProvider.endpointEnvVar) {
98400
+ setInputValue(activeEndpoint);
98223
98401
  setStatusMsg(null);
98224
- },
98225
- onChange: (idx) => setItemIndex(idx),
98226
- selectedBackgroundColor: C2.bgAlt,
98227
- selectedTextColor: C2.cyan
98228
- }, undefined, false, undefined, this),
98229
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
98230
- height: 1,
98231
- children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
98232
- children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98233
- fg: C2.border,
98234
- children: divider
98235
- }, undefined, false, undefined, this)
98236
- }, undefined, false, undefined, this)
98237
- }, undefined, false, undefined, this),
98238
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
98239
- flexDirection: "column",
98240
- height: bottomHeight,
98241
- paddingX: 1,
98242
- children: [
98243
- mode === "browse" && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(import_jsx_dev_runtime2.Fragment, {
98244
- children: [
98245
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
98402
+ setMode("input_endpoint");
98403
+ } else {
98404
+ setStatusMsg("This provider has no custom endpoint.");
98405
+ }
98406
+ } else if (key.name === "x") {
98407
+ if (hasCfgKey) {
98408
+ removeApiKey(selectedProvider.apiKeyEnvVar);
98409
+ if (selectedProvider.endpointEnvVar) {
98410
+ removeEndpoint(selectedProvider.endpointEnvVar);
98411
+ }
98412
+ refreshConfig();
98413
+ setStatusMsg(`Key removed for ${selectedProvider.displayName}.`);
98414
+ } else {
98415
+ setStatusMsg("No stored key to remove.");
98416
+ }
98417
+ }
98418
+ } else if (activeTab === "routing") {
98419
+ if (key.name === "a") {
98420
+ setRoutingPattern("");
98421
+ setRoutingChain("");
98422
+ setStatusMsg(null);
98423
+ setMode("add_routing_pattern");
98424
+ } else if (key.name === "d") {
98425
+ if (ruleEntries.length > 0) {
98426
+ const [pat] = ruleEntries[Math.min(providerIndex, ruleEntries.length - 1)];
98427
+ const cfg = loadConfig();
98428
+ if (cfg.routing) {
98429
+ delete cfg.routing[pat];
98430
+ saveConfig(cfg);
98431
+ refreshConfig();
98432
+ setStatusMsg(`Rule deleted: '${pat}'.`);
98433
+ }
98434
+ } else {
98435
+ setStatusMsg("No routing rules to delete.");
98436
+ }
98437
+ } else if (key.name === "up" || key.name === "k") {
98438
+ setProviderIndex((i) => Math.max(0, i - 1));
98439
+ } else if (key.name === "down" || key.name === "j") {
98440
+ setProviderIndex((i) => Math.min(Math.max(0, ruleEntries.length - 1), i + 1));
98441
+ }
98442
+ } else if (activeTab === "privacy") {
98443
+ if (key.name === "t") {
98444
+ const cfg = loadConfig();
98445
+ const next = !telemetryEnabled;
98446
+ cfg.telemetry = {
98447
+ ...cfg.telemetry ?? {},
98448
+ enabled: next,
98449
+ askedAt: cfg.telemetry?.askedAt ?? new Date().toISOString()
98450
+ };
98451
+ saveConfig(cfg);
98452
+ refreshConfig();
98453
+ setStatusMsg(`Telemetry ${next ? "enabled" : "disabled"}.`);
98454
+ } else if (key.name === "u") {
98455
+ const cfg = loadConfig();
98456
+ const statsKey = "CLAUDISH_STATS";
98457
+ const next = !statsEnabled2;
98458
+ if (!cfg.telemetry)
98459
+ cfg.telemetry = { enabled: telemetryEnabled, askedAt: new Date().toISOString() };
98460
+ cfg.statsEnabled = next;
98461
+ saveConfig(cfg);
98462
+ refreshConfig();
98463
+ setStatusMsg(`Usage stats ${next ? "enabled" : "disabled"}.`);
98464
+ } else if (key.name === "c") {
98465
+ clearBuffer();
98466
+ setBufStats(getBufferStats());
98467
+ setStatusMsg("Stats buffer cleared.");
98468
+ }
98469
+ }
98470
+ });
98471
+ if (height2 < 15 || width < 60) {
98472
+ return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
98473
+ width: "100%",
98474
+ height: "100%",
98475
+ padding: 1,
98476
+ backgroundColor: C2.bg,
98477
+ children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
98478
+ children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98479
+ fg: C2.red,
98480
+ bold: true,
98481
+ children: [
98482
+ "Terminal too small (",
98483
+ width,
98484
+ "x",
98485
+ height2,
98486
+ "). Resize to at least 60x15."
98487
+ ]
98488
+ }, undefined, true, undefined, this)
98489
+ }, undefined, false, undefined, this)
98490
+ }, undefined, false, undefined, this);
98491
+ }
98492
+ const isInputMode = mode === "input_key" || mode === "input_endpoint";
98493
+ const isRoutingInput = mode === "add_routing_pattern" || mode === "add_routing_chain";
98494
+ const HEADER_H = 1;
98495
+ const TABS_H = 3;
98496
+ const FOOTER_H = 1;
98497
+ const DETAIL_H = 5;
98498
+ const contentH = Math.max(4, height2 - HEADER_H - TABS_H - DETAIL_H - FOOTER_H - 1);
98499
+ function TabBar() {
98500
+ const tabs = [
98501
+ { label: "Providers", value: "providers", num: "1" },
98502
+ { label: "Routing", value: "routing", num: "2" },
98503
+ { label: "Privacy", value: "privacy", num: "3" }
98504
+ ];
98505
+ return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
98506
+ height: TABS_H,
98507
+ flexDirection: "column",
98508
+ backgroundColor: C2.bg,
98509
+ children: [
98510
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
98511
+ height: 1,
98512
+ flexDirection: "row",
98513
+ children: [
98514
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
98515
+ width: 1,
98516
+ height: 1,
98517
+ backgroundColor: C2.bg
98518
+ }, undefined, false, undefined, this),
98519
+ tabs.map((t2, i) => {
98520
+ const active = activeTab === t2.value;
98521
+ return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
98522
+ flexDirection: "row",
98523
+ height: 1,
98246
98524
  children: [
98247
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("strong", {
98248
- children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98249
- fg: C2.cyan,
98250
- children: selectedProvider.displayName
98251
- }, undefined, false, undefined, this)
98525
+ i > 0 && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
98526
+ width: 2,
98527
+ height: 1,
98528
+ backgroundColor: C2.bg
98252
98529
  }, undefined, false, undefined, this),
98253
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98254
- fg: C2.dim,
98255
- children: [
98256
- " ",
98257
- selectedProvider.description
98258
- ]
98259
- }, undefined, true, undefined, this)
98530
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
98531
+ height: 1,
98532
+ backgroundColor: active ? C2.tabActiveBg : C2.tabInactiveBg,
98533
+ paddingX: 1,
98534
+ children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
98535
+ children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98536
+ fg: active ? C2.tabActiveFg : C2.tabInactiveFg,
98537
+ bold: true,
98538
+ children: `${t2.num}. ${t2.label}`
98539
+ }, undefined, false, undefined, this)
98540
+ }, undefined, false, undefined, this)
98541
+ }, undefined, false, undefined, this)
98260
98542
  ]
98261
- }, undefined, true, undefined, this),
98262
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
98543
+ }, t2.value, true, undefined, this);
98544
+ }),
98545
+ statusMsg && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
98546
+ height: 1,
98547
+ backgroundColor: C2.bg,
98548
+ paddingX: 1,
98549
+ children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
98263
98550
  children: [
98264
98551
  /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98265
98552
  fg: C2.dim,
98266
- children: "Keys: "
98267
- }, undefined, false, undefined, this),
98268
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98269
- fg: C2.fg,
98270
- children: [
98271
- "env=",
98272
- envKeyMask,
98273
- " cfg=",
98274
- cfgKeyMask,
98275
- " "
98276
- ]
98277
- }, undefined, true, undefined, this),
98278
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98279
- fg: C2.dim,
98280
- children: "Url: "
98553
+ children: "\u2500 "
98281
98554
  }, undefined, false, undefined, this),
98282
98555
  /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98283
- fg: C2.cyan,
98284
- children: pad(activeUrl, 30)
98285
- }, undefined, false, undefined, this),
98286
- statusMsg && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98287
- fg: C2.green,
98288
- children: [
98289
- " ",
98290
- statusMsg
98291
- ]
98292
- }, undefined, true, undefined, this)
98556
+ fg: statusMsg.startsWith("Key saved") || statusMsg.startsWith("Rule added") || statusMsg.startsWith("Endpoint") || statusMsg.startsWith("Telemetry") || statusMsg.startsWith("Usage") || statusMsg.startsWith("Stats buffer") ? C2.green : C2.yellow,
98557
+ bold: true,
98558
+ children: statusMsg
98559
+ }, undefined, false, undefined, this)
98293
98560
  ]
98294
98561
  }, undefined, true, undefined, this)
98562
+ }, undefined, false, undefined, this)
98563
+ ]
98564
+ }, undefined, true, undefined, this),
98565
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
98566
+ height: 1,
98567
+ paddingX: 1,
98568
+ children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
98569
+ children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98570
+ fg: C2.tabActiveBg,
98571
+ children: "\u2500".repeat(Math.max(0, width - 2))
98572
+ }, undefined, false, undefined, this)
98573
+ }, undefined, false, undefined, this)
98574
+ }, undefined, false, undefined, this),
98575
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
98576
+ height: 1
98577
+ }, undefined, false, undefined, this)
98578
+ ]
98579
+ }, undefined, true, undefined, this);
98580
+ }
98581
+ function ProvidersContent() {
98582
+ const listH = contentH - 2;
98583
+ let separatorRendered = false;
98584
+ const getRow = (p, idx) => {
98585
+ const isReady = !!(config3.apiKeys?.[p.apiKeyEnvVar] || process.env[p.apiKeyEnvVar]);
98586
+ const selected = idx === providerIndex;
98587
+ const cfgMask = maskKey2(config3.apiKeys?.[p.apiKeyEnvVar]);
98588
+ const envMask = maskKey2(process.env[p.apiKeyEnvVar]);
98589
+ const hasCfg = cfgMask !== "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500";
98590
+ const hasEnv = envMask !== "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500";
98591
+ const keyDisplay = isReady ? hasCfg ? cfgMask : envMask : "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500";
98592
+ const src = hasEnv && hasCfg ? "e+c" : hasEnv ? "env" : hasCfg ? "cfg" : "";
98593
+ const namePad = p.displayName.padEnd(14).substring(0, 14);
98594
+ const isFirstUnready = !isReady && !separatorRendered;
98595
+ if (isFirstUnready)
98596
+ separatorRendered = true;
98597
+ return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
98598
+ flexDirection: "column",
98599
+ children: [
98600
+ isFirstUnready && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
98601
+ height: 1,
98602
+ paddingX: 1,
98603
+ children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
98604
+ children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98605
+ fg: C2.dim,
98606
+ children: [
98607
+ "\u2500 not configured ",
98608
+ "\u2500".repeat(Math.max(0, width - 22))
98609
+ ]
98610
+ }, undefined, true, undefined, this)
98611
+ }, undefined, false, undefined, this)
98612
+ }, undefined, false, undefined, this),
98613
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
98614
+ height: 1,
98615
+ flexDirection: "row",
98616
+ backgroundColor: selected ? C2.bgHighlight : C2.bg,
98617
+ children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
98618
+ children: [
98619
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98620
+ fg: isReady ? C2.green : C2.dim,
98621
+ children: isReady ? "\u25CF" : "\u25CB"
98622
+ }, undefined, false, undefined, this),
98623
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98624
+ children: " "
98625
+ }, undefined, false, undefined, this),
98626
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98627
+ fg: selected ? C2.white : isReady ? C2.fgMuted : C2.dim,
98628
+ bold: selected,
98629
+ children: namePad
98630
+ }, undefined, false, undefined, this),
98631
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98632
+ fg: C2.dim,
98633
+ children: " "
98634
+ }, undefined, false, undefined, this),
98635
+ isReady ? /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98636
+ fg: C2.green,
98637
+ bold: true,
98638
+ children: "ready "
98639
+ }, undefined, false, undefined, this) : /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98640
+ fg: C2.dim,
98641
+ children: "not set"
98642
+ }, undefined, false, undefined, this),
98643
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98644
+ fg: C2.dim,
98645
+ children: " "
98646
+ }, undefined, false, undefined, this),
98647
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98648
+ fg: isReady ? C2.cyan : C2.dim,
98649
+ children: keyDisplay
98650
+ }, undefined, false, undefined, this),
98651
+ src ? /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98652
+ fg: C2.dim,
98653
+ children: ` (${src})`
98654
+ }, undefined, false, undefined, this) : null,
98655
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98656
+ fg: C2.dim,
98657
+ children: " "
98658
+ }, undefined, false, undefined, this),
98659
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98660
+ fg: selected ? C2.white : C2.dim,
98661
+ children: p.description
98662
+ }, undefined, false, undefined, this)
98663
+ ]
98664
+ }, undefined, true, undefined, this)
98665
+ }, undefined, false, undefined, this)
98666
+ ]
98667
+ }, p.name, true, undefined, this);
98668
+ };
98669
+ return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
98670
+ height: contentH,
98671
+ border: true,
98672
+ borderStyle: "single",
98673
+ borderColor: !isInputMode ? C2.blue : C2.dim,
98674
+ backgroundColor: C2.bg,
98675
+ flexDirection: "column",
98676
+ paddingX: 1,
98677
+ children: [
98678
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
98679
+ children: [
98680
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98681
+ fg: C2.dim,
98682
+ children: " "
98683
+ }, undefined, false, undefined, this),
98684
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98685
+ fg: C2.blue,
98686
+ bold: true,
98687
+ children: "PROVIDER "
98688
+ }, undefined, false, undefined, this),
98689
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98690
+ fg: C2.blue,
98691
+ bold: true,
98692
+ children: "STATUS "
98693
+ }, undefined, false, undefined, this),
98694
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98695
+ fg: C2.blue,
98696
+ bold: true,
98697
+ children: "KEY "
98698
+ }, undefined, false, undefined, this),
98699
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98700
+ fg: C2.blue,
98701
+ bold: true,
98702
+ children: "DESCRIPTION"
98703
+ }, undefined, false, undefined, this)
98704
+ ]
98705
+ }, undefined, true, undefined, this),
98706
+ displayProviders.slice(0, listH).map(getRow)
98707
+ ]
98708
+ }, undefined, true, undefined, this);
98709
+ }
98710
+ function ProviderDetail() {
98711
+ const displayKey = hasCfgKey ? cfgKeyMask : hasEnvKey ? envKeyMask : "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500";
98712
+ if (isInputMode) {
98713
+ return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
98714
+ height: DETAIL_H,
98715
+ border: true,
98716
+ borderStyle: "single",
98717
+ borderColor: C2.focusBorder,
98718
+ title: ` Set ${mode === "input_key" ? "API Key" : "Endpoint"} \u2014 ${selectedProvider.displayName} `,
98719
+ backgroundColor: C2.bg,
98720
+ flexDirection: "column",
98721
+ paddingX: 1,
98722
+ children: [
98723
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
98724
+ children: [
98725
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98726
+ fg: C2.green,
98727
+ bold: true,
98728
+ children: "Enter "
98729
+ }, undefined, false, undefined, this),
98730
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98731
+ fg: C2.fgMuted,
98732
+ children: "to save \xB7 "
98733
+ }, undefined, false, undefined, this),
98734
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98735
+ fg: C2.red,
98736
+ bold: true,
98737
+ children: "Esc "
98738
+ }, undefined, false, undefined, this),
98739
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98740
+ fg: C2.fgMuted,
98741
+ children: "to cancel"
98742
+ }, undefined, false, undefined, this)
98295
98743
  ]
98296
98744
  }, undefined, true, undefined, this),
98297
- mode === "action" && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(import_jsx_dev_runtime2.Fragment, {
98745
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
98746
+ flexDirection: "row",
98298
98747
  children: [
98299
98748
  /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
98300
- children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("strong", {
98301
- children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98302
- fg: C2.yellow,
98303
- children: [
98304
- "Configure ",
98305
- selectedProvider.displayName
98306
- ]
98307
- }, undefined, true, undefined, this)
98749
+ children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98750
+ fg: C2.green,
98751
+ bold: true,
98752
+ children: "> "
98308
98753
  }, undefined, false, undefined, this)
98309
98754
  }, undefined, false, undefined, this),
98310
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("select", {
98311
- options: getActionOptions(),
98312
- focused: focused && mode === "action",
98313
- height: bottomHeight - 1,
98314
- selectedIndex: actionIndex,
98315
- onSelect: handleActionSelect,
98316
- onChange: setActionIndex,
98317
- selectedBackgroundColor: C2.dim,
98318
- selectedTextColor: C2.fg
98755
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("input", {
98756
+ value: inputValue,
98757
+ onChange: setInputValue,
98758
+ focused: true,
98759
+ width: width - 8,
98760
+ backgroundColor: C2.bgHighlight,
98761
+ textColor: C2.white
98319
98762
  }, undefined, false, undefined, this)
98320
98763
  ]
98321
- }, undefined, true, undefined, this),
98322
- (mode === "input_key" || mode === "input_endpoint") && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
98323
- flexDirection: "column",
98324
- gap: 1,
98764
+ }, undefined, true, undefined, this)
98765
+ ]
98766
+ }, undefined, true, undefined, this);
98767
+ }
98768
+ return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
98769
+ height: DETAIL_H,
98770
+ border: true,
98771
+ borderStyle: "single",
98772
+ borderColor: C2.dim,
98773
+ title: ` ${selectedProvider.displayName} `,
98774
+ backgroundColor: C2.bgAlt,
98775
+ flexDirection: "column",
98776
+ paddingX: 1,
98777
+ children: [
98778
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
98779
+ flexDirection: "row",
98780
+ children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
98325
98781
  children: [
98326
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
98327
- children: [
98328
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("strong", {
98329
- children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98330
- fg: C2.yellow,
98331
- children: [
98332
- "Input ",
98333
- mode === "input_key" ? "API Key" : "Custom Endpoint URL"
98334
- ]
98335
- }, undefined, true, undefined, this)
98336
- }, undefined, false, undefined, this),
98337
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98338
- fg: C2.dim,
98339
- children: " (Enter to save, Esc to cancel)"
98340
- }, undefined, false, undefined, this)
98341
- ]
98342
- }, undefined, true, undefined, this),
98343
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
98344
- flexDirection: "row",
98782
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98783
+ fg: C2.blue,
98784
+ bold: true,
98785
+ children: "Status: "
98786
+ }, undefined, false, undefined, this),
98787
+ hasKey ? /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98788
+ fg: C2.green,
98789
+ bold: true,
98790
+ children: "\u25CF Ready"
98791
+ }, undefined, false, undefined, this) : /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98792
+ fg: C2.fgMuted,
98793
+ children: "\u25CB Not configured"
98794
+ }, undefined, false, undefined, this),
98795
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98796
+ fg: C2.dim,
98797
+ children: " "
98798
+ }, undefined, false, undefined, this),
98799
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98800
+ fg: C2.blue,
98801
+ bold: true,
98802
+ children: "Key: "
98803
+ }, undefined, false, undefined, this),
98804
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98805
+ fg: C2.green,
98806
+ children: displayKey
98807
+ }, undefined, false, undefined, this),
98808
+ keySrc && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98809
+ fg: C2.fgMuted,
98345
98810
  children: [
98346
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
98347
- children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98348
- fg: C2.dim,
98349
- children: "> "
98350
- }, undefined, false, undefined, this)
98351
- }, undefined, false, undefined, this),
98352
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("input", {
98353
- value: inputValue,
98354
- onChange: setInputValue,
98355
- focused: true,
98356
- width: width - 5,
98357
- backgroundColor: C2.bgAlt,
98358
- textColor: C2.fg
98359
- }, undefined, false, undefined, this)
98811
+ " (source: ",
98812
+ keySrc,
98813
+ ")"
98360
98814
  ]
98361
98815
  }, undefined, true, undefined, this)
98362
98816
  ]
98363
98817
  }, undefined, true, undefined, this)
98364
- ]
98365
- }, undefined, true, undefined, this)
98366
- ]
98367
- }, undefined, true, undefined, this);
98368
- }
98369
- var import_react13;
98370
- var init_ApiKeysPanel = __esm(async () => {
98371
- init_profile_config();
98372
- init_providers();
98373
- init_theme2();
98374
- init_jsx_dev_runtime();
98375
- await init_react();
98376
- import_react13 = __toESM(require_react(), 1);
98377
- });
98378
-
98379
- // src/tui/panels/ConfigViewPanel.tsx
98380
- function ConfigViewPanel({ focused, height: height2 }) {
98381
- const [config3] = import_react14.useState(() => loadConfig());
98382
- const items = PROVIDERS.map((p) => {
98383
- const kE = process.env[p.apiKeyEnvVar];
98384
- const kC = config3.apiKeys?.[p.apiKeyEnvVar];
98385
- const eE = p.endpointEnvVar ? process.env[p.endpointEnvVar] : undefined;
98386
- const eC = p.endpointEnvVar ? config3.endpoints?.[p.endpointEnvVar] : undefined;
98387
- if (!kE && !kC && !eE && !eC)
98388
- return null;
98389
- return {
98390
- name: p.displayName,
98391
- kSrc: kE && kC ? "e+c" : kE ? "env" : kC ? "cfg" : "---",
98392
- eSrc: eE && eC ? "e+c" : eE ? "env" : eC ? "cfg" : "---",
98393
- kVal: kC || kE,
98394
- eVal: eC || eE
98395
- };
98396
- }).filter(Boolean);
98397
- const tState = config3.telemetry?.enabled ? "enabled" : "disabled";
98398
- const tColor = config3.telemetry?.enabled ? C2.green : C2.yellow;
98399
- return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("scrollbox", {
98400
- focused,
98401
- height: height2,
98402
- children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
98403
- flexDirection: "column",
98404
- paddingX: 1,
98405
- gap: 0,
98406
- children: [
98407
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
98408
- children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("strong", {
98409
- children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98410
- fg: C2.cyan,
98411
- children: "System State"
98412
- }, undefined, false, undefined, this)
98413
- }, undefined, false, undefined, this)
98414
98818
  }, undefined, false, undefined, this),
98415
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
98819
+ selectedProvider.endpointEnvVar && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
98416
98820
  children: [
98417
98821
  /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98418
- fg: C2.dim,
98419
- children: " Default Profile: "
98822
+ fg: C2.blue,
98823
+ bold: true,
98824
+ children: "URL: "
98420
98825
  }, undefined, false, undefined, this),
98421
98826
  /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98422
- fg: C2.fg,
98423
- children: config3.defaultProfile
98827
+ fg: C2.cyan,
98828
+ children: activeEndpoint || selectedProvider.defaultEndpoint || "default"
98424
98829
  }, undefined, false, undefined, this)
98425
98830
  ]
98426
98831
  }, undefined, true, undefined, this),
98427
98832
  /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
98428
98833
  children: [
98429
98834
  /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98430
- fg: C2.dim,
98431
- children: " Telemetry: "
98835
+ fg: C2.blue,
98836
+ bold: true,
98837
+ children: "Desc: "
98432
98838
  }, undefined, false, undefined, this),
98433
98839
  /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98434
- fg: tColor,
98435
- children: tState
98840
+ fg: C2.white,
98841
+ children: selectedProvider.description
98436
98842
  }, undefined, false, undefined, this)
98437
98843
  ]
98438
98844
  }, undefined, true, undefined, this),
98845
+ selectedProvider.keyUrl && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
98846
+ children: [
98847
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98848
+ fg: C2.blue,
98849
+ bold: true,
98850
+ children: "Get Key: "
98851
+ }, undefined, false, undefined, this),
98852
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98853
+ fg: C2.cyan,
98854
+ children: selectedProvider.keyUrl
98855
+ }, undefined, false, undefined, this)
98856
+ ]
98857
+ }, undefined, true, undefined, this)
98858
+ ]
98859
+ }, undefined, true, undefined, this);
98860
+ }
98861
+ function chainStr(chain) {
98862
+ return chain.join(" \u2192 ");
98863
+ }
98864
+ function RoutingContent() {
98865
+ const innerH = contentH - 2;
98866
+ return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
98867
+ height: contentH,
98868
+ border: true,
98869
+ borderStyle: "single",
98870
+ borderColor: C2.blue,
98871
+ backgroundColor: C2.bg,
98872
+ flexDirection: "column",
98873
+ paddingX: 1,
98874
+ children: [
98439
98875
  /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
98440
98876
  children: [
98441
98877
  /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98442
98878
  fg: C2.dim,
98443
- children: " Config File: "
98879
+ children: " * "
98444
98880
  }, undefined, false, undefined, this),
98445
98881
  /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98446
- fg: C2.fg,
98447
- children: "~/.claudish/config.json"
98882
+ fg: C2.fgMuted,
98883
+ children: "LiteLLM \u2192 Zen Go \u2192 Subscription \u2192 Provider Direct \u2192 OpenRouter"
98884
+ }, undefined, false, undefined, this),
98885
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98886
+ fg: C2.dim,
98887
+ children: " (built-in)"
98448
98888
  }, undefined, false, undefined, this)
98449
98889
  ]
98450
98890
  }, undefined, true, undefined, this),
98451
98891
  /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
98452
- children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98453
- fg: C2.dim,
98454
- children: " "
98455
- }, undefined, false, undefined, this)
98892
+ children: " "
98456
98893
  }, undefined, false, undefined, this),
98457
98894
  /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
98458
- children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("strong", {
98459
- children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98460
- fg: C2.cyan,
98461
- children: "Active Configurations (Provider / Endpoints)"
98462
- }, undefined, false, undefined, this)
98463
- }, undefined, false, undefined, this)
98464
- }, undefined, false, undefined, this),
98465
- items.length === 0 ? /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
98466
98895
  children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98467
- fg: C2.dim,
98468
- children: " No customizations found."
98896
+ fg: C2.blue,
98897
+ bold: true,
98898
+ children: " PATTERN CHAIN"
98469
98899
  }, undefined, false, undefined, this)
98470
- }, undefined, false, undefined, this) : items.map((itm) => /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
98900
+ }, undefined, false, undefined, this),
98901
+ ruleEntries.length === 0 && !isRoutingInput && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
98471
98902
  children: [
98472
98903
  /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98473
- fg: C2.fg,
98474
- children: [
98475
- " ",
98476
- itm?.name.padEnd(16)
98477
- ]
98478
- }, undefined, true, undefined, this),
98904
+ fg: C2.fgMuted,
98905
+ children: " No custom rules. Press "
98906
+ }, undefined, false, undefined, this),
98479
98907
  /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98480
98908
  fg: C2.green,
98481
- children: [
98482
- " ",
98483
- maskKey2(itm?.kVal)
98484
- ]
98485
- }, undefined, true, undefined, this),
98909
+ bold: true,
98910
+ children: "a"
98911
+ }, undefined, false, undefined, this),
98486
98912
  /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98487
- fg: C2.dim,
98913
+ fg: C2.fgMuted,
98914
+ children: " to add one."
98915
+ }, undefined, false, undefined, this)
98916
+ ]
98917
+ }, undefined, true, undefined, this),
98918
+ ruleEntries.length > 0 && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(import_jsx_dev_runtime2.Fragment, {
98919
+ children: [
98920
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
98488
98921
  children: [
98489
- " (",
98490
- itm?.kSrc,
98491
- ") "
98922
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98923
+ fg: C2.blue,
98924
+ bold: true,
98925
+ children: "PATTERN "
98926
+ }, undefined, false, undefined, this),
98927
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98928
+ fg: C2.blue,
98929
+ bold: true,
98930
+ children: "CHAIN"
98931
+ }, undefined, false, undefined, this)
98492
98932
  ]
98493
98933
  }, undefined, true, undefined, this),
98494
- itm?.eVal ? /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(import_jsx_dev_runtime2.Fragment, {
98934
+ ruleEntries.slice(0, Math.max(0, innerH - 3)).map(([pat, chain], idx) => {
98935
+ const sel = idx === providerIndex;
98936
+ return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
98937
+ height: 1,
98938
+ flexDirection: "row",
98939
+ backgroundColor: sel ? C2.bgHighlight : C2.bg,
98940
+ children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
98941
+ children: [
98942
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98943
+ fg: sel ? C2.white : C2.fgMuted,
98944
+ bold: sel,
98945
+ children: pat.padEnd(16).substring(0, 16)
98946
+ }, undefined, false, undefined, this),
98947
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98948
+ fg: C2.dim,
98949
+ children: " "
98950
+ }, undefined, false, undefined, this),
98951
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98952
+ fg: sel ? C2.cyan : C2.fgMuted,
98953
+ children: chainStr(chain)
98954
+ }, undefined, false, undefined, this)
98955
+ ]
98956
+ }, undefined, true, undefined, this)
98957
+ }, pat, false, undefined, this);
98958
+ })
98959
+ ]
98960
+ }, undefined, true, undefined, this),
98961
+ mode === "add_routing_pattern" && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
98962
+ flexDirection: "column",
98963
+ children: [
98964
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
98495
98965
  children: [
98496
98966
  /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98497
- fg: C2.cyan,
98498
- children: itm.eVal.length > 20 ? itm.eVal.substring(0, 20) + "\u2026" : itm.eVal.padEnd(20)
98967
+ fg: C2.blue,
98968
+ bold: true,
98969
+ children: "Pattern "
98499
98970
  }, undefined, false, undefined, this),
98500
98971
  /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98501
98972
  fg: C2.dim,
98502
- children: [
98503
- " (",
98504
- itm.eSrc,
98505
- ")"
98506
- ]
98507
- }, undefined, true, undefined, this)
98973
+ children: "(e.g. kimi-*, gpt-4o):"
98974
+ }, undefined, false, undefined, this)
98508
98975
  ]
98509
- }, undefined, true, undefined, this) : /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98510
- fg: C2.dim,
98511
- children: " default target"
98512
- }, undefined, false, undefined, this)
98976
+ }, undefined, true, undefined, this),
98977
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
98978
+ flexDirection: "row",
98979
+ children: [
98980
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
98981
+ children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98982
+ fg: C2.green,
98983
+ bold: true,
98984
+ children: "> "
98985
+ }, undefined, false, undefined, this)
98986
+ }, undefined, false, undefined, this),
98987
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("input", {
98988
+ value: routingPattern,
98989
+ onChange: setRoutingPattern,
98990
+ focused: true,
98991
+ width: width - 8,
98992
+ backgroundColor: C2.bgHighlight,
98993
+ textColor: C2.white
98994
+ }, undefined, false, undefined, this)
98995
+ ]
98996
+ }, undefined, true, undefined, this),
98997
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
98998
+ children: [
98999
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99000
+ fg: C2.green,
99001
+ bold: true,
99002
+ children: "Enter "
99003
+ }, undefined, false, undefined, this),
99004
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99005
+ fg: C2.fgMuted,
99006
+ children: "to continue \xB7 "
99007
+ }, undefined, false, undefined, this),
99008
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99009
+ fg: C2.red,
99010
+ bold: true,
99011
+ children: "Esc "
99012
+ }, undefined, false, undefined, this),
99013
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99014
+ fg: C2.fgMuted,
99015
+ children: "to cancel"
99016
+ }, undefined, false, undefined, this)
99017
+ ]
99018
+ }, undefined, true, undefined, this)
98513
99019
  ]
98514
- }, `sys-${itm?.name}`, true, undefined, this)),
98515
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
98516
- children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98517
- fg: C2.dim,
98518
- children: " "
98519
- }, undefined, false, undefined, this)
98520
- }, undefined, false, undefined, this),
98521
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
98522
- children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("strong", {
98523
- children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98524
- fg: C2.cyan,
98525
- children: "Routing Rules"
98526
- }, undefined, false, undefined, this)
98527
- }, undefined, false, undefined, this)
98528
- }, undefined, false, undefined, this),
98529
- !config3.routing || Object.keys(config3.routing).length === 0 ? /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
98530
- children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98531
- fg: C2.dim,
98532
- children: " No custom routing bound."
98533
- }, undefined, false, undefined, this)
98534
- }, undefined, false, undefined, this) : Object.entries(config3.routing).map(([pat, chain]) => /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
99020
+ }, undefined, true, undefined, this),
99021
+ mode === "add_routing_chain" && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
99022
+ flexDirection: "column",
98535
99023
  children: [
98536
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98537
- fg: C2.fg,
99024
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
98538
99025
  children: [
98539
- " ",
98540
- pat.padEnd(16),
98541
- " "
99026
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99027
+ fg: C2.blue,
99028
+ bold: true,
99029
+ children: "Chain for "
99030
+ }, undefined, false, undefined, this),
99031
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99032
+ fg: C2.white,
99033
+ bold: true,
99034
+ children: routingPattern
99035
+ }, undefined, false, undefined, this),
99036
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99037
+ fg: C2.dim,
99038
+ children: " (comma-separated providers):"
99039
+ }, undefined, false, undefined, this)
98542
99040
  ]
98543
99041
  }, undefined, true, undefined, this),
98544
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98545
- fg: C2.yellow,
98546
- children: chain.join(" -> ")
98547
- }, undefined, false, undefined, this)
99042
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
99043
+ flexDirection: "row",
99044
+ children: [
99045
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
99046
+ children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99047
+ fg: C2.green,
99048
+ bold: true,
99049
+ children: "> "
99050
+ }, undefined, false, undefined, this)
99051
+ }, undefined, false, undefined, this),
99052
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("input", {
99053
+ value: routingChain,
99054
+ onChange: setRoutingChain,
99055
+ focused: true,
99056
+ width: width - 8,
99057
+ backgroundColor: C2.bgHighlight,
99058
+ textColor: C2.white
99059
+ }, undefined, false, undefined, this)
99060
+ ]
99061
+ }, undefined, true, undefined, this),
99062
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
99063
+ children: [
99064
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99065
+ fg: C2.green,
99066
+ bold: true,
99067
+ children: "Enter "
99068
+ }, undefined, false, undefined, this),
99069
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99070
+ fg: C2.fgMuted,
99071
+ children: "to save \xB7 "
99072
+ }, undefined, false, undefined, this),
99073
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99074
+ fg: C2.red,
99075
+ bold: true,
99076
+ children: "Esc "
99077
+ }, undefined, false, undefined, this),
99078
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99079
+ fg: C2.fgMuted,
99080
+ children: "to go back"
99081
+ }, undefined, false, undefined, this)
99082
+ ]
99083
+ }, undefined, true, undefined, this)
98548
99084
  ]
98549
- }, `rr-${pat}`, true, undefined, this))
99085
+ }, undefined, true, undefined, this)
98550
99086
  ]
98551
- }, undefined, true, undefined, this)
98552
- }, undefined, false, undefined, this);
98553
- }
98554
- var import_react14;
98555
- var init_ConfigViewPanel = __esm(() => {
98556
- init_profile_config();
98557
- init_providers();
98558
- init_theme2();
98559
- init_jsx_dev_runtime();
98560
- import_react14 = __toESM(require_react(), 1);
98561
- });
98562
-
98563
- // src/tui/panels/ProfilesPanel.tsx
98564
- function ProfilesPanel({ height: height2, width }) {
98565
- const profiles = listAllProfiles();
98566
- if (profiles.length === 0) {
99087
+ }, undefined, true, undefined, this);
99088
+ }
99089
+ function RoutingDetail() {
98567
99090
  return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
99091
+ height: DETAIL_H,
99092
+ border: true,
99093
+ borderStyle: "single",
99094
+ borderColor: C2.dim,
99095
+ title: " Examples ",
99096
+ backgroundColor: C2.bgAlt,
98568
99097
  flexDirection: "column",
98569
- height: height2,
98570
- padding: 1,
98571
- children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
98572
- children: [
98573
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98574
- fg: C2.dim,
98575
- children: "No profiles. Run "
98576
- }, undefined, false, undefined, this),
98577
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98578
- fg: C2.cyan,
98579
- children: "claudish init"
98580
- }, undefined, false, undefined, this)
98581
- ]
98582
- }, undefined, true, undefined, this)
98583
- }, undefined, false, undefined, this);
98584
- }
98585
- return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
98586
- flexDirection: "column",
98587
- height: height2,
98588
- children: [
98589
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
98590
- height: 1,
98591
- paddingX: 1,
98592
- children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
98593
- children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98594
- fg: C2.dim,
98595
- children: " PROFILE MAPPINGS (o/s/h/sub) SCOPE"
98596
- }, undefined, false, undefined, this)
98597
- }, undefined, false, undefined, this)
98598
- }, undefined, false, undefined, this),
98599
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
98600
- flexDirection: "column",
98601
- paddingX: 1,
98602
- gap: 0,
98603
- children: profiles.map((p, i) => {
98604
- const isDef = p.isDefault;
98605
- const sName = (isDef ? "\u2605 " : "\u25CB ") + p.name;
98606
- const nPad = sName.padEnd(16).substring(0, 16);
98607
- const pColor = isDef ? C2.green : C2.fg;
98608
- const r = (val) => val ? val.split("/").pop() : "-";
98609
- const mapStr = `${r(p.models.opus)} | ${r(p.models.sonnet)} | ${r(p.models.haiku)}`;
98610
- const mPad = mapStr.padEnd(22).substring(0, 22);
98611
- return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
98612
- children: [
98613
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98614
- fg: pColor,
98615
- children: nPad
98616
- }, undefined, false, undefined, this),
98617
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98618
- fg: C2.dim,
98619
- children: " "
98620
- }, undefined, false, undefined, this),
98621
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98622
- fg: C2.fg,
98623
- children: mPad
98624
- }, undefined, false, undefined, this),
98625
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98626
- fg: C2.dim,
98627
- children: [
98628
- " [",
98629
- p.scope,
98630
- "]"
98631
- ]
98632
- }, undefined, true, undefined, this),
98633
- p.shadowed && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98634
- fg: C2.yellow,
98635
- children: " (shadowed)"
98636
- }, undefined, false, undefined, this)
98637
- ]
98638
- }, `${p.scope}-${p.name}-${i}`, true, undefined, this);
98639
- })
98640
- }, undefined, false, undefined, this),
98641
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
98642
- paddingTop: 2,
98643
- paddingX: 1,
98644
- children: [
98645
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
98646
- children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99098
+ paddingX: 1,
99099
+ children: [
99100
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
99101
+ children: [
99102
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98647
99103
  fg: C2.dim,
98648
- children: `\u2500`.repeat(Math.max(1, width - 2))
98649
- }, undefined, false, undefined, this)
98650
- }, undefined, false, undefined, this),
98651
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
98652
- children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99104
+ children: "kimi-* "
99105
+ }, undefined, false, undefined, this),
99106
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99107
+ fg: C2.fgMuted,
99108
+ children: "kimi \u2192 or"
99109
+ }, undefined, false, undefined, this),
99110
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99111
+ fg: C2.dim,
99112
+ children: " "
99113
+ }, undefined, false, undefined, this),
99114
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99115
+ fg: C2.dim,
99116
+ children: "gpt-* "
99117
+ }, undefined, false, undefined, this),
99118
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99119
+ fg: C2.fgMuted,
99120
+ children: "oai \u2192 litellm"
99121
+ }, undefined, false, undefined, this),
99122
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99123
+ fg: C2.dim,
99124
+ children: " "
99125
+ }, undefined, false, undefined, this),
99126
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98653
99127
  fg: C2.dim,
98654
- children: "Read-only view. Manage profiles via standard CLI commands:"
99128
+ children: "gemini-* "
99129
+ }, undefined, false, undefined, this),
99130
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99131
+ fg: C2.fgMuted,
99132
+ children: "google \u2192 zen \u2192 or"
98655
99133
  }, undefined, false, undefined, this)
98656
- }, undefined, false, undefined, this),
98657
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
98658
- children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99134
+ ]
99135
+ }, undefined, true, undefined, this),
99136
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
99137
+ children: [
99138
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98659
99139
  fg: C2.dim,
98660
- children: " $ claudish profile add/edit"
99140
+ children: "glm-* "
99141
+ }, undefined, false, undefined, this),
99142
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99143
+ fg: C2.fgMuted,
99144
+ children: "glm \u2192 zen \u2192 or"
99145
+ }, undefined, false, undefined, this),
99146
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99147
+ fg: C2.dim,
99148
+ children: " "
99149
+ }, undefined, false, undefined, this),
99150
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99151
+ fg: C2.dim,
99152
+ children: "deepseek-* "
99153
+ }, undefined, false, undefined, this),
99154
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99155
+ fg: C2.fgMuted,
99156
+ children: "zen \u2192 or"
99157
+ }, undefined, false, undefined, this),
99158
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99159
+ fg: C2.dim,
99160
+ children: " "
99161
+ }, undefined, false, undefined, this),
99162
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99163
+ fg: C2.dim,
99164
+ children: "Pattern: glob (* = any)"
98661
99165
  }, undefined, false, undefined, this)
98662
- }, undefined, false, undefined, this)
98663
- ]
98664
- }, undefined, true, undefined, this)
98665
- ]
98666
- }, undefined, true, undefined, this);
98667
- }
98668
- var init_ProfilesPanel = __esm(() => {
98669
- init_profile_config();
98670
- init_theme2();
98671
- init_jsx_dev_runtime();
98672
- });
98673
-
98674
- // src/tui/panels/ProvidersPanel.tsx
98675
- function ProvidersPanel() {
98676
- return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
98677
- padding: 2,
98678
- children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
98679
- children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98680
- fg: C2.dim,
98681
- children: "This pane has been cleanly merged into Api Keys."
98682
- }, undefined, false, undefined, this)
98683
- }, undefined, false, undefined, this)
98684
- }, undefined, false, undefined, this);
98685
- }
98686
- var init_ProvidersPanel = __esm(() => {
98687
- init_theme2();
98688
- init_jsx_dev_runtime();
98689
- });
98690
-
98691
- // src/tui/panels/RoutingPanel.tsx
98692
- function pStr(s, len) {
98693
- return s.padEnd(len).substring(0, len);
98694
- }
98695
- function RoutingPanel({ focused, height: height2, onEditingChange }) {
98696
- const [config3, setConfig] = import_react16.useState(() => loadConfig());
98697
- const [mode, setMode] = import_react16.useState("list");
98698
- const [itemIndex, setItemIndex] = import_react16.useState(0);
98699
- const [actionIndex, setActionIndex] = import_react16.useState(0);
98700
- const [patternInput, setPatternInput] = import_react16.useState("");
98701
- const [chainInput, setChainInput] = import_react16.useState("");
98702
- const [statusMsg, setStatusMsg] = import_react16.useState(null);
98703
- import_react16.useEffect(() => onEditingChange?.(mode !== "list"), [mode, onEditingChange]);
98704
- const rules = config3.routing ?? {};
98705
- const ruleEntries = Object.entries(rules);
98706
- const listOptions = [
98707
- { name: " [+] Add new routing rule...", value: "__add__" },
98708
- ...ruleEntries.map(([pat, chain]) => ({
98709
- name: ` ${pStr(pat, 18)} \u2192 ${chain.join(" | ")}`,
98710
- value: pat
98711
- }))
98712
- ];
98713
- const handleActionSelect = import_react16.useCallback((_idx, opt) => {
98714
- if (!opt?.value)
98715
- return;
98716
- if (opt.value === "back") {
98717
- setMode("list");
98718
- } else if (opt.value === "delete") {
98719
- const tgt = ruleEntries[itemIndex - 1]?.[0];
98720
- if (tgt) {
98721
- delete rules[tgt];
98722
- if (Object.keys(rules).length === 0)
98723
- config3.routing = undefined;
98724
- saveConfig(config3);
98725
- setConfig(loadConfig());
98726
- setStatusMsg(`\u2713 Deleted rule for '${tgt}'`);
98727
- }
98728
- setMode("list");
98729
- } else if (opt.value === "clear") {
98730
- config3.routing = undefined;
98731
- saveConfig(config3);
98732
- setConfig(loadConfig());
98733
- setStatusMsg("\u2713 Cleared all custom routing rules");
98734
- setMode("list");
98735
- }
98736
- }, [itemIndex, ruleEntries, rules, config3]);
98737
- useKeyboard((key) => {
98738
- if (!focused)
98739
- return;
98740
- if (mode === "list") {
98741
- if (key.name === "a") {
98742
- setPatternInput("");
98743
- setChainInput("");
98744
- setMode("add_pattern");
98745
- }
98746
- if ((key.name === "r" || key.name === "delete") && itemIndex > 0) {
98747
- setMode("action");
98748
- }
98749
- } else if (mode === "add_pattern") {
98750
- if (key.name === "return" || key.name === "enter") {
98751
- if (patternInput.trim())
98752
- setMode("add_chain");
98753
- } else if (key.name === "escape") {
98754
- setMode("list");
98755
- setStatusMsg(null);
98756
- }
98757
- } else if (mode === "add_chain") {
98758
- if (key.name === "return" || key.name === "enter") {
98759
- const pat = patternInput.trim();
98760
- const ch = chainInput.trim().split(",").map((s) => s.trim()).filter(Boolean);
98761
- if (pat && ch.length) {
98762
- if (!config3.routing)
98763
- config3.routing = {};
98764
- config3.routing[pat] = ch;
98765
- saveConfig(config3);
98766
- setConfig(loadConfig());
98767
- setStatusMsg(`\u2713 Rule added for '${pat}'`);
98768
- }
98769
- setMode("list");
98770
- } else if (key.name === "escape") {
98771
- setMode("add_pattern");
98772
- }
98773
- } else if (mode === "action" && key.name === "escape") {
98774
- setMode("list");
98775
- }
98776
- });
98777
- const listHeight = Math.max(3, height2 - 7);
98778
- return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
98779
- flexDirection: "column",
98780
- height: height2,
98781
- children: [
98782
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
98783
- height: 1,
98784
- paddingX: 1,
98785
- children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
98786
- children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98787
- fg: C2.dim,
98788
- children: " PATTERN PROVIDER CHAIN"
98789
- }, undefined, false, undefined, this)
98790
- }, undefined, false, undefined, this)
98791
- }, undefined, false, undefined, this),
98792
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("select", {
98793
- options: listOptions,
98794
- focused: focused && mode === "list",
98795
- height: listHeight - 1,
98796
- selectedIndex: itemIndex,
98797
- onSelect: (idx, opt) => {
98798
- if (opt?.value === "__add__") {
98799
- setPatternInput("");
98800
- setChainInput("");
98801
- setMode("add_pattern");
98802
- } else {
98803
- setActionIndex(0);
98804
- setMode("action");
98805
- }
98806
- },
98807
- onChange: setItemIndex,
98808
- selectedBackgroundColor: C2.bgAlt,
98809
- selectedTextColor: C2.cyan
98810
- }, undefined, false, undefined, this),
98811
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
98812
- height: 1,
98813
- children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
98814
- children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98815
- fg: C2.border,
98816
- children: "\u2500".repeat(50)
98817
- }, undefined, false, undefined, this)
98818
- }, undefined, false, undefined, this)
98819
- }, undefined, false, undefined, this),
98820
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
98821
- flexDirection: "column",
98822
- height: 7,
98823
- paddingX: 1,
98824
- children: [
98825
- mode === "list" && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(import_jsx_dev_runtime2.Fragment, {
98826
- children: [
98827
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
98828
- children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("strong", {
98829
- children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98830
- fg: C2.yellow,
98831
- children: "Routing Behavior"
98832
- }, undefined, false, undefined, this)
98833
- }, undefined, false, undefined, this)
98834
- }, undefined, false, undefined, this),
98835
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
98836
- children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98837
- fg: C2.dim,
98838
- children: "Map matched model name requests directly to specific provider chains."
98839
- }, undefined, false, undefined, this)
98840
- }, undefined, false, undefined, this),
98841
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
98842
- children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98843
- fg: C2.dim,
98844
- children: "Useful for forcing patterns like 'qwen-*' natively through OpenRouter."
98845
- }, undefined, false, undefined, this)
98846
- }, undefined, false, undefined, this),
98847
- statusMsg && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
98848
- children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99166
+ ]
99167
+ }, undefined, true, undefined, this),
99168
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
99169
+ children: [
99170
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99171
+ fg: C2.cyan,
99172
+ bold: true,
99173
+ children: ruleEntries.length
99174
+ }, undefined, false, undefined, this),
99175
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99176
+ fg: C2.fgMuted,
99177
+ children: ` custom rule${ruleEntries.length !== 1 ? "s" : ""}`
99178
+ }, undefined, false, undefined, this)
99179
+ ]
99180
+ }, undefined, true, undefined, this)
99181
+ ]
99182
+ }, undefined, true, undefined, this);
99183
+ }
99184
+ function PrivacyContent() {
99185
+ const halfW = Math.floor((width - 4) / 2);
99186
+ const cardH = Math.max(7, contentH - 1);
99187
+ return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
99188
+ height: contentH,
99189
+ flexDirection: "row",
99190
+ backgroundColor: C2.bg,
99191
+ paddingX: 1,
99192
+ children: [
99193
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
99194
+ width: halfW,
99195
+ height: cardH,
99196
+ border: true,
99197
+ borderStyle: "single",
99198
+ borderColor: activeTab === "privacy" ? C2.blue : C2.dim,
99199
+ title: " Telemetry ",
99200
+ backgroundColor: C2.bg,
99201
+ flexDirection: "column",
99202
+ paddingX: 1,
99203
+ children: [
99204
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
99205
+ children: [
99206
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99207
+ fg: C2.blue,
99208
+ bold: true,
99209
+ children: "Status: "
99210
+ }, undefined, false, undefined, this),
99211
+ telemetryEnabled ? /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98849
99212
  fg: C2.green,
98850
- children: statusMsg
98851
- }, undefined, false, undefined, this)
98852
- }, undefined, false, undefined, this),
98853
- !statusMsg && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
98854
- children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98855
- fg: C2.dim,
98856
- children: "Hotkeys: [a] add [r] remove"
99213
+ bold: true,
99214
+ children: "\u25CF Enabled"
99215
+ }, undefined, false, undefined, this) : /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99216
+ fg: C2.fgMuted,
99217
+ children: "\u25CB Disabled"
98857
99218
  }, undefined, false, undefined, this)
99219
+ ]
99220
+ }, undefined, true, undefined, this),
99221
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
99222
+ children: " "
99223
+ }, undefined, false, undefined, this),
99224
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
99225
+ children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99226
+ fg: C2.fgMuted,
99227
+ children: "Collects anonymized platform info and"
98858
99228
  }, undefined, false, undefined, this)
98859
- ]
98860
- }, undefined, true, undefined, this),
98861
- mode === "action" && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(import_jsx_dev_runtime2.Fragment, {
98862
- children: [
98863
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
98864
- children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("strong", {
98865
- children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98866
- fg: C2.yellow,
98867
- children: "Manage Selected Rule"
98868
- }, undefined, false, undefined, this)
98869
- }, undefined, false, undefined, this)
98870
- }, undefined, false, undefined, this),
98871
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("select", {
98872
- options: [
98873
- { name: "Delete Rule", value: "delete" },
98874
- { name: "Clear ALL Rules", value: "clear" },
98875
- { name: "Back", value: "back" }
98876
- ],
98877
- focused: mode === "action",
98878
- height: 3,
98879
- selectedIndex: actionIndex,
98880
- onSelect: handleActionSelect,
98881
- onChange: setActionIndex,
98882
- selectedBackgroundColor: C2.dim
99229
+ }, undefined, false, undefined, this),
99230
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
99231
+ children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99232
+ fg: C2.fgMuted,
99233
+ children: "sanitized error types to improve claudish."
98883
99234
  }, undefined, false, undefined, this)
98884
- ]
98885
- }, undefined, true, undefined, this),
98886
- mode === "add_pattern" && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
98887
- flexDirection: "column",
98888
- gap: 1,
98889
- children: [
98890
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
98891
- children: [
98892
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("strong", {
98893
- children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98894
- fg: C2.yellow,
98895
- children: "Step 1: Match Pattern"
98896
- }, undefined, false, undefined, this)
98897
- }, undefined, false, undefined, this),
98898
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98899
- fg: C2.dim,
98900
- children: " (e.g. 'kimi-*' or 'gpt-4o')"
98901
- }, undefined, false, undefined, this)
98902
- ]
98903
- }, undefined, true, undefined, this),
98904
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
98905
- flexDirection: "row",
98906
- children: [
98907
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
98908
- children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98909
- fg: C2.dim,
98910
- children: "> "
98911
- }, undefined, false, undefined, this)
98912
- }, undefined, false, undefined, this),
98913
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("input", {
98914
- value: patternInput,
98915
- onChange: setPatternInput,
98916
- focused: true,
98917
- width: 40,
98918
- backgroundColor: C2.bgAlt
98919
- }, undefined, false, undefined, this)
98920
- ]
98921
- }, undefined, true, undefined, this)
98922
- ]
98923
- }, undefined, true, undefined, this),
98924
- mode === "add_chain" && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
98925
- flexDirection: "column",
98926
- gap: 1,
98927
- children: [
98928
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
98929
- children: [
98930
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("strong", {
98931
- children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98932
- fg: C2.yellow,
98933
- children: "Step 2: Provider Chain"
98934
- }, undefined, false, undefined, this)
98935
- }, undefined, false, undefined, this),
98936
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98937
- fg: C2.dim,
98938
- children: " (e.g. 'kimi@kimi-k2, openrouter')"
98939
- }, undefined, false, undefined, this)
98940
- ]
98941
- }, undefined, true, undefined, this),
98942
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
98943
- flexDirection: "row",
98944
- children: [
98945
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
98946
- children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98947
- fg: C2.dim,
98948
- children: "> "
98949
- }, undefined, false, undefined, this)
98950
- }, undefined, false, undefined, this),
98951
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("input", {
98952
- value: chainInput,
98953
- onChange: setChainInput,
98954
- focused: true,
98955
- width: 40,
98956
- backgroundColor: C2.bgAlt
98957
- }, undefined, false, undefined, this)
98958
- ]
98959
- }, undefined, true, undefined, this)
98960
- ]
98961
- }, undefined, true, undefined, this)
98962
- ]
98963
- }, undefined, true, undefined, this)
98964
- ]
98965
- }, undefined, true, undefined, this);
98966
- }
98967
- var import_react16;
98968
- var init_RoutingPanel = __esm(async () => {
98969
- init_profile_config();
98970
- init_theme2();
98971
- init_jsx_dev_runtime();
98972
- await init_react();
98973
- import_react16 = __toESM(require_react(), 1);
98974
- });
98975
-
98976
- // src/tui/panels/TelemetryPanel.tsx
98977
- function TelemetryPanel({ focused, height: height2, onEditingChange }) {
98978
- const [config3, setConfig] = import_react17.useState(() => loadConfig());
98979
- const [statusMsg, setStatusMsg] = import_react17.useState(null);
98980
- import_react17.useEffect(() => onEditingChange?.(false), [onEditingChange]);
98981
- const telemetry = config3.telemetry;
98982
- const envDisabled = process.env.CLAUDISH_TELEMETRY === "0" || process.env.CLAUDISH_TELEMETRY === "false";
98983
- const isEnabled = !envDisabled && telemetry?.enabled === true;
98984
- const handleSelect = import_react17.useCallback((_idx, opt) => {
98985
- if (!opt?.value)
98986
- return;
98987
- const cfg = loadConfig();
98988
- if (opt.value === "toggle") {
98989
- const next = !isEnabled;
98990
- cfg.telemetry = { ...cfg.telemetry ?? {}, enabled: next, askedAt: cfg.telemetry?.askedAt ?? new Date().toISOString() };
98991
- saveConfig(cfg);
98992
- setStatusMsg(next ? "\u2713 Telemetry enabled." : "\u2713 Telemetry disabled.");
98993
- } else if (opt.value === "reset") {
98994
- if (cfg.telemetry) {
98995
- cfg.telemetry.askedAt = undefined;
98996
- cfg.telemetry.enabled = false;
98997
- saveConfig(cfg);
98998
- }
98999
- setStatusMsg("\u2713 Consent reset. You will be prompted on the next error.");
99000
- }
99001
- setConfig(loadConfig());
99002
- }, [isEnabled]);
99003
- const toggleText = `[${isEnabled ? "x" : " "}] Expand error reporting pipeline`;
99004
- return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
99005
- flexDirection: "column",
99006
- height: height2,
99007
- children: [
99008
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("select", {
99009
- options: [
99010
- { name: toggleText, value: "toggle" },
99011
- { name: " [-] Reset Prompts/Consent", value: "reset" }
99012
- ],
99013
- focused,
99014
- height: 3,
99015
- onSelect: handleSelect,
99016
- selectedBackgroundColor: C2.bgAlt,
99017
- selectedTextColor: C2.cyan
99018
- }, undefined, false, undefined, this),
99019
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
99020
- height: 1,
99021
- children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
99022
- children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99023
- fg: C2.border,
99024
- children: "\u2500".repeat(50)
99025
- }, undefined, false, undefined, this)
99026
- }, undefined, false, undefined, this)
99027
- }, undefined, false, undefined, this),
99028
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
99029
- flexDirection: "column",
99030
- paddingX: 1,
99031
- gap: 0,
99032
- children: [
99033
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
99034
- children: [
99035
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99036
- fg: C2.dim,
99037
- children: "Status: "
99038
- }, undefined, false, undefined, this),
99039
- envDisabled ? /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99040
- fg: C2.yellow,
99041
- children: "DISABLED (Env override)"
99042
- }, undefined, false, undefined, this) : !telemetry ? /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99043
- fg: C2.dim,
99044
- children: "Not configured yet"
99045
- }, undefined, false, undefined, this) : telemetry.enabled ? /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99046
- fg: C2.green,
99047
- children: "ENABLED"
99048
- }, undefined, false, undefined, this) : /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99049
- fg: C2.yellow,
99050
- children: "DISABLED"
99235
+ }, undefined, false, undefined, this),
99236
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
99237
+ children: " "
99238
+ }, undefined, false, undefined, this),
99239
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
99240
+ children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99241
+ fg: C2.white,
99242
+ bold: true,
99243
+ children: "Never sends keys, prompts, or paths."
99051
99244
  }, undefined, false, undefined, this)
99052
- ]
99053
- }, undefined, true, undefined, this),
99054
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
99055
- children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99056
- fg: C2.dim,
99245
+ }, undefined, false, undefined, this),
99246
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
99247
+ children: " "
99248
+ }, undefined, false, undefined, this),
99249
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
99057
99250
  children: [
99058
- "Last Prompt: ",
99059
- telemetry?.askedAt || "Never"
99251
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99252
+ fg: C2.dim,
99253
+ children: "Press ["
99254
+ }, undefined, false, undefined, this),
99255
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99256
+ fg: C2.green,
99257
+ bold: true,
99258
+ children: "t"
99259
+ }, undefined, false, undefined, this),
99260
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99261
+ fg: C2.dim,
99262
+ children: "] to toggle."
99263
+ }, undefined, false, undefined, this)
99060
99264
  ]
99061
99265
  }, undefined, true, undefined, this)
99062
- }, undefined, false, undefined, this),
99063
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
99064
- children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99065
- fg: C2.dim,
99266
+ ]
99267
+ }, undefined, true, undefined, this),
99268
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
99269
+ width: width - 4 - halfW,
99270
+ height: cardH,
99271
+ border: true,
99272
+ borderStyle: "single",
99273
+ borderColor: activeTab === "privacy" ? C2.blue : C2.dim,
99274
+ title: " Usage Stats ",
99275
+ backgroundColor: C2.bg,
99276
+ flexDirection: "column",
99277
+ paddingX: 1,
99278
+ children: [
99279
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
99280
+ children: [
99281
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99282
+ fg: C2.blue,
99283
+ bold: true,
99284
+ children: "Status: "
99285
+ }, undefined, false, undefined, this),
99286
+ statsEnabled2 ? /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99287
+ fg: C2.green,
99288
+ bold: true,
99289
+ children: "\u25CF Enabled"
99290
+ }, undefined, false, undefined, this) : /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99291
+ fg: C2.fgMuted,
99292
+ children: "\u25CB Disabled"
99293
+ }, undefined, false, undefined, this)
99294
+ ]
99295
+ }, undefined, true, undefined, this),
99296
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
99297
+ children: [
99298
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99299
+ fg: C2.blue,
99300
+ bold: true,
99301
+ children: "Buffer: "
99302
+ }, undefined, false, undefined, this),
99303
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99304
+ fg: C2.white,
99305
+ bold: true,
99306
+ children: bufStats.events
99307
+ }, undefined, false, undefined, this),
99308
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99309
+ fg: C2.fgMuted,
99310
+ children: " events ("
99311
+ }, undefined, false, undefined, this),
99312
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99313
+ fg: C2.yellow,
99314
+ children: bytesHuman(bufStats.bytes)
99315
+ }, undefined, false, undefined, this),
99316
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99317
+ fg: C2.fgMuted,
99318
+ children: ")"
99319
+ }, undefined, false, undefined, this)
99320
+ ]
99321
+ }, undefined, true, undefined, this),
99322
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
99066
99323
  children: " "
99067
- }, undefined, false, undefined, this)
99068
- }, undefined, false, undefined, this),
99069
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
99070
- children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("strong", {
99324
+ }, undefined, false, undefined, this),
99325
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
99071
99326
  children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99072
- fg: C2.cyan,
99073
- children: "Anonymous Payloads ONLY include:"
99327
+ fg: C2.fgMuted,
99328
+ children: "Collects local, anonymous stats on model"
99074
99329
  }, undefined, false, undefined, this)
99075
- }, undefined, false, undefined, this)
99076
- }, undefined, false, undefined, this),
99077
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
99078
- children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99079
- fg: C2.dim,
99080
- children: "- Claudish release architecture & platform execution targets"
99081
- }, undefined, false, undefined, this)
99082
- }, undefined, false, undefined, this),
99083
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
99084
- children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99085
- fg: C2.dim,
99086
- children: "- Sanitized message failures (No env vars, no paths)"
99087
- }, undefined, false, undefined, this)
99088
- }, undefined, false, undefined, this),
99089
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
99090
- children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99091
- fg: C2.dim,
99092
- children: "- Isolated stack execution points"
99093
- }, undefined, false, undefined, this)
99094
- }, undefined, false, undefined, this),
99095
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
99096
- children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99097
- fg: C2.dim,
99330
+ }, undefined, false, undefined, this),
99331
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
99332
+ children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99333
+ fg: C2.fgMuted,
99334
+ children: "usage, latency, and token counts."
99335
+ }, undefined, false, undefined, this)
99336
+ }, undefined, false, undefined, this),
99337
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
99098
99338
  children: " "
99099
- }, undefined, false, undefined, this)
99100
- }, undefined, false, undefined, this),
99101
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
99102
- children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99103
- fg: C2.dim,
99104
- children: "NEVER collected: Auth strings, keys, project paths, prompt body."
99105
- }, undefined, false, undefined, this)
99106
- }, undefined, false, undefined, this),
99107
- statusMsg && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
99108
- children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99109
- fg: C2.green,
99110
- children: statusMsg
99111
- }, undefined, false, undefined, this)
99339
+ }, undefined, false, undefined, this),
99340
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
99341
+ children: [
99342
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99343
+ fg: C2.dim,
99344
+ children: "Press ["
99345
+ }, undefined, false, undefined, this),
99346
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99347
+ fg: C2.green,
99348
+ bold: true,
99349
+ children: "u"
99350
+ }, undefined, false, undefined, this),
99351
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99352
+ fg: C2.dim,
99353
+ children: "] to toggle, ["
99354
+ }, undefined, false, undefined, this),
99355
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99356
+ fg: C2.red,
99357
+ bold: true,
99358
+ children: "c"
99359
+ }, undefined, false, undefined, this),
99360
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99361
+ fg: C2.dim,
99362
+ children: "] to clear buffer."
99363
+ }, undefined, false, undefined, this)
99364
+ ]
99365
+ }, undefined, true, undefined, this)
99366
+ ]
99367
+ }, undefined, true, undefined, this)
99368
+ ]
99369
+ }, undefined, true, undefined, this);
99370
+ }
99371
+ function PrivacyDetail() {
99372
+ return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
99373
+ height: DETAIL_H,
99374
+ border: true,
99375
+ borderStyle: "single",
99376
+ borderColor: C2.dim,
99377
+ title: " Your Privacy ",
99378
+ backgroundColor: C2.bgAlt,
99379
+ flexDirection: "column",
99380
+ paddingX: 1,
99381
+ children: [
99382
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
99383
+ children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99384
+ fg: C2.fgMuted,
99385
+ children: "Telemetry and usage stats are always opt-in and never send personally identifiable data."
99112
99386
  }, undefined, false, undefined, this)
99113
- ]
99114
- }, undefined, true, undefined, this)
99115
- ]
99116
- }, undefined, true, undefined, this);
99117
- }
99118
- var import_react17;
99119
- var init_TelemetryPanel = __esm(() => {
99120
- init_profile_config();
99121
- init_theme2();
99122
- init_jsx_dev_runtime();
99123
- import_react17 = __toESM(require_react(), 1);
99124
- });
99125
-
99126
- // src/tui/App.tsx
99127
- function App() {
99128
- const renderer = useRenderer();
99129
- const { width, height: height2 } = useTerminalDimensions();
99130
- const [activePanel, setActivePanel] = import_react19.useState("menu");
99131
- const [activeSection, setActiveSection] = import_react19.useState("apikeys");
99132
- const [menuIndex, setMenuIndex] = import_react19.useState(0);
99133
- const [isEditing, setIsEditing] = import_react19.useState(false);
99134
- const [config3] = import_react19.useState(() => loadConfig());
99135
- const quit = import_react19.useCallback(() => renderer.destroy(), [renderer]);
99136
- const handleEditingChange = import_react19.useCallback((editing) => {
99137
- setIsEditing(editing);
99138
- if (!editing)
99139
- setActivePanel("content");
99140
- }, []);
99141
- useKeyboard((key) => {
99142
- if (key.name === "q" && !isEditing)
99143
- return quit();
99144
- if (key.ctrl && key.name === "c")
99145
- return quit();
99146
- if (key.name === "tab" && !isEditing) {
99147
- setActivePanel((p) => p === "menu" ? "content" : "menu");
99148
- }
99149
- });
99150
- const handleMenuSelect = import_react19.useCallback((_idx, opt) => {
99151
- if (opt?.value) {
99152
- setActiveSection(opt.value);
99153
- setActivePanel("content");
99387
+ }, undefined, false, undefined, this),
99388
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
99389
+ children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99390
+ fg: C2.fgMuted,
99391
+ children: "All data is anonymized before transmission. You can disable either independently."
99392
+ }, undefined, false, undefined, this)
99393
+ }, undefined, false, undefined, this)
99394
+ ]
99395
+ }, undefined, true, undefined, this);
99396
+ }
99397
+ function Footer() {
99398
+ let keys;
99399
+ if (activeTab === "providers") {
99400
+ keys = [
99401
+ [C2.blue, "\u2191\u2193", "navigate"],
99402
+ [C2.green, "s", "set key"],
99403
+ [C2.green, "e", "endpoint"],
99404
+ [C2.red, "x", "remove"],
99405
+ [C2.blue, "Tab", "section"],
99406
+ [C2.dim, "q", "quit"]
99407
+ ];
99408
+ } else if (activeTab === "routing") {
99409
+ keys = [
99410
+ [C2.blue, "\u2191\u2193", "navigate"],
99411
+ [C2.green, "a", "add rule"],
99412
+ [C2.red, "d", "delete"],
99413
+ [C2.blue, "Tab", "section"],
99414
+ [C2.dim, "q", "quit"]
99415
+ ];
99416
+ } else {
99417
+ keys = [
99418
+ [C2.green, "t", "telemetry"],
99419
+ [C2.green, "u", "stats"],
99420
+ [C2.red, "c", "clear"],
99421
+ [C2.blue, "Tab", "section"],
99422
+ [C2.dim, "q", "quit"]
99423
+ ];
99154
99424
  }
99155
- }, []);
99156
- if (height2 < 15 || width < 60) {
99157
99425
  return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
99158
- width: "100%",
99159
- height: "100%",
99160
- padding: 1,
99161
- backgroundColor: C2.bg,
99426
+ height: FOOTER_H,
99427
+ flexDirection: "row",
99428
+ paddingX: 1,
99429
+ backgroundColor: C2.bgAlt,
99162
99430
  children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
99163
- children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99164
- fg: C2.red,
99431
+ children: keys.map(([color, key, label], i) => /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99165
99432
  children: [
99166
- "Terminal too small (",
99167
- width,
99168
- "x",
99169
- height2,
99170
- "). Resize to at least 60x15."
99433
+ i > 0 && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99434
+ fg: C2.dim,
99435
+ children: " \u2502 "
99436
+ }, undefined, false, undefined, this),
99437
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99438
+ fg: color,
99439
+ bold: true,
99440
+ children: key
99441
+ }, undefined, false, undefined, this),
99442
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99443
+ fg: C2.fgMuted,
99444
+ children: [
99445
+ " ",
99446
+ label
99447
+ ]
99448
+ }, undefined, true, undefined, this)
99171
99449
  ]
99172
- }, undefined, true, undefined, this)
99450
+ }, i, true, undefined, this))
99173
99451
  }, undefined, false, undefined, this)
99174
99452
  }, undefined, false, undefined, this);
99175
99453
  }
99176
- const menuWidth = 26;
99177
- const contentWidth = width - menuWidth;
99178
- const mainHeight = height2 - 2;
99179
- const menuOptions = MENU_ITEMS.map((item, idx) => ({
99180
- name: (idx === menuIndex ? " " : " ") + item.label,
99181
- value: item.section
99182
- }));
99183
- const activeTitle = MENU_ITEMS.find((m2) => m2.section === activeSection)?.label ?? "Config";
99184
- const titleText = " Claudish Configuration ";
99185
- const rightText = ` ${VERSION2} | profile: ${config3.defaultProfile || "default"} `;
99186
- const innerWidth = width - 4;
99187
- const gap = Math.max(1, innerWidth - titleText.length - rightText.length);
99188
- const headerPad = " ".repeat(gap);
99189
99454
  return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
99190
99455
  width,
99191
99456
  height: height2,
@@ -99193,181 +99458,90 @@ function App() {
99193
99458
  backgroundColor: C2.bg,
99194
99459
  children: [
99195
99460
  /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
99196
- height: 1,
99461
+ height: HEADER_H,
99197
99462
  flexDirection: "row",
99198
- paddingX: 2,
99199
99463
  backgroundColor: C2.bgAlt,
99464
+ paddingX: 1,
99200
99465
  children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
99201
99466
  children: [
99202
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("strong", {
99203
- children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99204
- fg: C2.cyan,
99205
- children: titleText
99206
- }, undefined, false, undefined, this)
99207
- }, undefined, false, undefined, this),
99208
99467
  /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99209
- fg: C2.bgAlt,
99210
- children: headerPad
99468
+ fg: C2.white,
99469
+ bold: true,
99470
+ children: "claudish"
99211
99471
  }, undefined, false, undefined, this),
99212
99472
  /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99213
99473
  fg: C2.dim,
99214
- children: rightText
99215
- }, undefined, false, undefined, this)
99216
- ]
99217
- }, undefined, true, undefined, this)
99218
- }, undefined, false, undefined, this),
99219
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
99220
- flexDirection: "row",
99221
- height: mainHeight,
99222
- children: [
99223
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
99224
- border: true,
99225
- borderStyle: "single",
99226
- borderColor: activePanel === "menu" ? C2.focusBorder : C2.border,
99227
- title: " Navigation ",
99228
- width: menuWidth,
99229
- height: mainHeight,
99230
- flexDirection: "column",
99231
- backgroundColor: C2.bg,
99232
- children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("select", {
99233
- options: menuOptions,
99234
- focused: activePanel === "menu",
99235
- height: mainHeight - 2,
99236
- selectedIndex: menuIndex,
99237
- onSelect: handleMenuSelect,
99238
- onChange: (idx) => {
99239
- setMenuIndex(idx);
99240
- const section = MENU_ITEMS[idx]?.section;
99241
- if (section)
99242
- setActiveSection(section);
99243
- },
99244
- selectedBackgroundColor: C2.bgAlt,
99245
- selectedTextColor: C2.cyan
99246
- }, undefined, false, undefined, this)
99247
- }, undefined, false, undefined, this),
99248
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
99249
- border: true,
99250
- borderStyle: "single",
99251
- borderColor: activePanel === "content" ? C2.focusBorder : C2.border,
99252
- title: ` ${activeTitle} `,
99253
- width: contentWidth,
99254
- height: mainHeight,
99255
- backgroundColor: C2.bg,
99256
- children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(ContentPanel, {
99257
- section: activeSection,
99258
- focused: activePanel === "content",
99259
- height: mainHeight - 2,
99260
- width: contentWidth - 2,
99261
- onEditingChange: handleEditingChange
99262
- }, undefined, false, undefined, this)
99263
- }, undefined, false, undefined, this)
99264
- ]
99265
- }, undefined, true, undefined, this),
99266
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
99267
- height: 1,
99268
- flexDirection: "row",
99269
- alignItems: "center",
99270
- paddingX: 2,
99271
- children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
99272
- children: [
99474
+ children: " \u2500 "
99475
+ }, undefined, false, undefined, this),
99273
99476
  /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99274
- fg: C2.cyan,
99275
- children: "Tab"
99477
+ fg: C2.blue,
99478
+ bold: true,
99479
+ children: VERSION2
99276
99480
  }, undefined, false, undefined, this),
99277
99481
  /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99278
99482
  fg: C2.dim,
99279
- children: " switch \u2502 "
99483
+ children: " \u2500 "
99280
99484
  }, undefined, false, undefined, this),
99281
99485
  /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99282
- fg: C2.cyan,
99283
- children: "\u2191\u2193"
99284
- }, undefined, false, undefined, this),
99486
+ fg: C2.orange,
99487
+ bold: true,
99488
+ children: [
99489
+ "\u2605 ",
99490
+ profileName
99491
+ ]
99492
+ }, undefined, true, undefined, this),
99285
99493
  /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99286
99494
  fg: C2.dim,
99287
- children: " browse \u2502 "
99288
- }, undefined, false, undefined, this),
99289
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99290
- fg: C2.cyan,
99291
- children: "Enter"
99495
+ children: " \u2500 "
99292
99496
  }, undefined, false, undefined, this),
99293
99497
  /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99294
- fg: C2.dim,
99295
- children: " configure/select \u2502 "
99498
+ fg: C2.green,
99499
+ bold: true,
99500
+ children: readyCount
99296
99501
  }, undefined, false, undefined, this),
99297
99502
  /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99298
- fg: C2.cyan,
99299
- children: "Esc/q"
99503
+ fg: C2.fgMuted,
99504
+ children: " providers configured"
99300
99505
  }, undefined, false, undefined, this),
99301
99506
  /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99302
99507
  fg: C2.dim,
99303
- children: " back/quit"
99508
+ children: "\u2500".repeat(Math.max(1, width - 38 - profileName.length - VERSION2.length))
99304
99509
  }, undefined, false, undefined, this)
99305
99510
  ]
99306
99511
  }, undefined, true, undefined, this)
99307
- }, undefined, false, undefined, this)
99512
+ }, undefined, false, undefined, this),
99513
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(TabBar, {}, undefined, false, undefined, this),
99514
+ activeTab === "providers" && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(import_jsx_dev_runtime2.Fragment, {
99515
+ children: [
99516
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(ProvidersContent, {}, undefined, false, undefined, this),
99517
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(ProviderDetail, {}, undefined, false, undefined, this)
99518
+ ]
99519
+ }, undefined, true, undefined, this),
99520
+ activeTab === "routing" && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(import_jsx_dev_runtime2.Fragment, {
99521
+ children: [
99522
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(RoutingContent, {}, undefined, false, undefined, this),
99523
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(RoutingDetail, {}, undefined, false, undefined, this)
99524
+ ]
99525
+ }, undefined, true, undefined, this),
99526
+ activeTab === "privacy" && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(import_jsx_dev_runtime2.Fragment, {
99527
+ children: [
99528
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(PrivacyContent, {}, undefined, false, undefined, this),
99529
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(PrivacyDetail, {}, undefined, false, undefined, this)
99530
+ ]
99531
+ }, undefined, true, undefined, this),
99532
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(Footer, {}, undefined, false, undefined, this)
99308
99533
  ]
99309
99534
  }, undefined, true, undefined, this);
99310
99535
  }
99311
- function ContentPanel({ section, focused, height: height2, width, onEditingChange }) {
99312
- switch (section) {
99313
- case "apikeys":
99314
- return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(ApiKeysPanel, {
99315
- focused,
99316
- height: height2,
99317
- width,
99318
- onEditingChange
99319
- }, undefined, false, undefined, this);
99320
- case "providers":
99321
- return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(ProvidersPanel, {}, undefined, false, undefined, this);
99322
- case "profiles":
99323
- return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(ProfilesPanel, {
99324
- focused,
99325
- height: height2,
99326
- width
99327
- }, undefined, false, undefined, this);
99328
- case "routing":
99329
- return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(RoutingPanel, {
99330
- focused,
99331
- height: height2,
99332
- onEditingChange
99333
- }, undefined, false, undefined, this);
99334
- case "telemetry":
99335
- return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(TelemetryPanel, {
99336
- focused,
99337
- height: height2,
99338
- onEditingChange
99339
- }, undefined, false, undefined, this);
99340
- case "config":
99341
- return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(ConfigViewPanel, {
99342
- focused,
99343
- height: height2
99344
- }, undefined, false, undefined, this);
99345
- default:
99346
- return null;
99347
- }
99348
- }
99349
- var import_react19, VERSION2 = "v5.12.0", MENU_ITEMS;
99536
+ var import_react13, VERSION2 = "v5.16";
99350
99537
  var init_App = __esm(async () => {
99351
99538
  init_profile_config();
99352
- init_ConfigViewPanel();
99353
- init_ProfilesPanel();
99354
- init_ProvidersPanel();
99355
- init_TelemetryPanel();
99539
+ init_stats_buffer();
99540
+ init_providers();
99356
99541
  init_theme2();
99357
99542
  init_jsx_dev_runtime();
99358
- await __promiseAll([
99359
- init_react(),
99360
- init_ApiKeysPanel(),
99361
- init_RoutingPanel()
99362
- ]);
99363
- import_react19 = __toESM(require_react(), 1);
99364
- MENU_ITEMS = [
99365
- { label: "Providers & API Keys", section: "apikeys" },
99366
- { label: "Profiles", section: "profiles" },
99367
- { label: "Routing", section: "routing" },
99368
- { label: "Telemetry", section: "telemetry" },
99369
- { label: "View Config", section: "config" }
99370
- ];
99543
+ await init_react();
99544
+ import_react13 = __toESM(require_react(), 1);
99371
99545
  });
99372
99546
 
99373
99547
  // src/tui/index.tsx
@@ -99692,7 +99866,7 @@ function mergeUserSettingsIfPresent(config3, tempSettingsPath, statusLine) {
99692
99866
  }
99693
99867
  config3.claudeArgs.splice(idx, 2);
99694
99868
  }
99695
- async function runClaudeWithProxy(config3, proxyUrl, onCleanup) {
99869
+ async function runClaudeWithProxy(config3, proxyUrl, onCleanup, ptyDiagRunner) {
99696
99870
  const hasProfileMappings = config3.modelOpus || config3.modelSonnet || config3.modelHaiku || config3.modelSubagent;
99697
99871
  const modelId = config3.model || (hasProfileMappings || config3.monitor ? undefined : "unknown");
99698
99872
  const portMatch = proxyUrl.match(/:(\d+)/);
@@ -99779,20 +99953,28 @@ Or set CLAUDE_PATH to your custom installation:`);
99779
99953
  }
99780
99954
  const needsShell = isWindows2() && claudeBinary.endsWith(".cmd");
99781
99955
  const spawnCommand = needsShell ? `"${claudeBinary}"` : claudeBinary;
99782
- const proc = spawn2(spawnCommand, claudeArgs, {
99783
- env: env2,
99784
- stdio: "inherit",
99785
- shell: needsShell
99786
- });
99787
- setupSignalHandlers(proc, tempSettingsPath, config3.quiet, onCleanup);
99788
- const exitCode = await new Promise((resolve4) => {
99789
- proc.on("exit", (code) => {
99790
- resolve4(code ?? 1);
99956
+ let exitCode;
99957
+ if (config3.interactive && ptyDiagRunner) {
99958
+ exitCode = await ptyDiagRunner.run(spawnCommand, claudeArgs, env2);
99959
+ try {
99960
+ unlinkSync7(tempSettingsPath);
99961
+ } catch {}
99962
+ } else {
99963
+ const proc = spawn2(spawnCommand, claudeArgs, {
99964
+ env: env2,
99965
+ stdio: "inherit",
99966
+ shell: needsShell
99791
99967
  });
99792
- });
99793
- try {
99794
- unlinkSync7(tempSettingsPath);
99795
- } catch (error46) {}
99968
+ setupSignalHandlers(proc, tempSettingsPath, config3.quiet, onCleanup);
99969
+ exitCode = await new Promise((resolve4) => {
99970
+ proc.on("exit", (code) => {
99971
+ resolve4(code ?? 1);
99972
+ });
99973
+ });
99974
+ try {
99975
+ unlinkSync7(tempSettingsPath);
99976
+ } catch {}
99977
+ }
99796
99978
  return exitCode;
99797
99979
  }
99798
99980
  function setupSignalHandlers(proc, tempSettingsPath, quiet, onCleanup) {
@@ -99897,6 +100079,7 @@ var exports_diag_output = {};
99897
100079
  __export(exports_diag_output, {
99898
100080
  createDiagOutput: () => createDiagOutput,
99899
100081
  TmuxDiagOutput: () => TmuxDiagOutput,
100082
+ OpentUiDiagOutput: () => OpentUiDiagOutput,
99900
100083
  NullDiagOutput: () => NullDiagOutput,
99901
100084
  LogFileDiagOutput: () => LogFileDiagOutput
99902
100085
  });
@@ -99948,6 +100131,25 @@ class LogFileDiagOutput {
99948
100131
  }
99949
100132
  }
99950
100133
 
100134
+ class OpentUiDiagOutput {
100135
+ runner;
100136
+ messages = [];
100137
+ constructor(runner) {
100138
+ this.runner = runner;
100139
+ }
100140
+ write(msg) {
100141
+ const level = msg.toLowerCase().includes("error") ? "error" : msg.toLowerCase().includes("warn") ? "warn" : "info";
100142
+ this.messages.push({ text: msg, level });
100143
+ if (this.messages.length > 4) {
100144
+ this.messages = this.messages.slice(-4);
100145
+ }
100146
+ this.runner.showDiag(this.messages).catch(() => {});
100147
+ }
100148
+ cleanup() {
100149
+ this.runner.hideDiag();
100150
+ }
100151
+ }
100152
+
99951
100153
  class NullDiagOutput {
99952
100154
  write(_msg) {}
99953
100155
  cleanup() {}
@@ -99956,8 +100158,25 @@ function createDiagOutput(options) {
99956
100158
  if (!options.interactive) {
99957
100159
  return new NullDiagOutput;
99958
100160
  }
99959
- if (process.env.TMUX) {
99960
- return new TmuxDiagOutput;
100161
+ const mode = options.diagMode || "auto";
100162
+ if (mode === "off") {
100163
+ return new NullDiagOutput;
100164
+ }
100165
+ if (mode === "pty" || mode === "auto") {
100166
+ if (options.ptyRunner) {
100167
+ return new OpentUiDiagOutput(options.ptyRunner);
100168
+ }
100169
+ if (mode === "pty") {
100170
+ return new LogFileDiagOutput;
100171
+ }
100172
+ }
100173
+ if (mode === "tmux" || mode === "auto") {
100174
+ if (process.env.TMUX) {
100175
+ return new TmuxDiagOutput;
100176
+ }
100177
+ if (mode === "tmux") {
100178
+ return new LogFileDiagOutput;
100179
+ }
99961
100180
  }
99962
100181
  return new LogFileDiagOutput;
99963
100182
  }
@@ -99997,6 +100216,215 @@ var init_diag_output = __esm(() => {
99997
100216
  };
99998
100217
  });
99999
100218
 
100219
+ // src/tui/DiagPanel.tsx
100220
+ function DiagPanel({ messages }) {
100221
+ const { width } = useTerminalDimensions();
100222
+ const panelWidth = Math.max(1, width);
100223
+ const separator = "\u2500".repeat(panelWidth);
100224
+ return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
100225
+ x: 0,
100226
+ y: 0,
100227
+ width: panelWidth,
100228
+ height: 5,
100229
+ backgroundColor: "#1a1a2e",
100230
+ children: [
100231
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
100232
+ x: 0,
100233
+ y: 0,
100234
+ content: separator,
100235
+ color: "#44475a"
100236
+ }, undefined, false, undefined, this),
100237
+ messages.slice(-3).map((msg, i) => {
100238
+ const prefix = LEVEL_PREFIX[msg.level];
100239
+ const color = LEVEL_COLORS[msg.level];
100240
+ const maxTextLen = Math.max(1, panelWidth - prefix.length - 1);
100241
+ const truncated = msg.text.length > maxTextLen ? `${msg.text.slice(0, maxTextLen - 1)}\u2026` : msg.text;
100242
+ return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
100243
+ x: 0,
100244
+ y: i + 1,
100245
+ content: `${prefix} ${truncated}`,
100246
+ color
100247
+ }, `msg-${i}`, false, undefined, this);
100248
+ }),
100249
+ messages.length < 3 && Array.from({ length: 3 - messages.length }).map((_2, i) => /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
100250
+ x: 0,
100251
+ y: messages.length + i + 1,
100252
+ content: ""
100253
+ }, `empty-${i}`, false, undefined, this)),
100254
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
100255
+ x: 0,
100256
+ y: 4,
100257
+ content: "Press ESC to dismiss",
100258
+ color: "#6272a4"
100259
+ }, undefined, false, undefined, this)
100260
+ ]
100261
+ }, undefined, true, undefined, this);
100262
+ }
100263
+ var LEVEL_COLORS, LEVEL_PREFIX;
100264
+ var init_DiagPanel = __esm(async () => {
100265
+ init_jsx_dev_runtime();
100266
+ await init_react();
100267
+ LEVEL_COLORS = {
100268
+ error: "#ff5555",
100269
+ warn: "#ffb86c",
100270
+ info: "#8be9fd"
100271
+ };
100272
+ LEVEL_PREFIX = {
100273
+ error: "[ERROR]",
100274
+ warn: "[WARN] ",
100275
+ info: "[INFO] "
100276
+ };
100277
+ });
100278
+
100279
+ // src/pty-diag-runner.ts
100280
+ var exports_pty_diag_runner = {};
100281
+ __export(exports_pty_diag_runner, {
100282
+ tryCreatePtyRunner: () => tryCreatePtyRunner,
100283
+ PtyDiagRunner: () => PtyDiagRunner
100284
+ });
100285
+ import { writeSync as writeSync3 } from "fs";
100286
+
100287
+ class PtyDiagRunner {
100288
+ renderer = null;
100289
+ bunProc = null;
100290
+ messages = [];
100291
+ autoHideTimer = null;
100292
+ reactRoot = null;
100293
+ rawStdinHandler = null;
100294
+ rendererInitializing = false;
100295
+ async run(command, args, env2) {
100296
+ const cols = process.stdout.columns || 80;
100297
+ const rows = process.stdout.rows || 24;
100298
+ this.bunProc = Bun.spawn([command, ...args], {
100299
+ terminal: {
100300
+ cols,
100301
+ rows,
100302
+ data: (_terminal, data) => {
100303
+ const buf = typeof data === "string" ? Buffer.from(data, "binary") : data;
100304
+ writeSync3(1, buf);
100305
+ }
100306
+ },
100307
+ cwd: process.cwd(),
100308
+ env: env2
100309
+ });
100310
+ const startTime = Date.now();
100311
+ const GRACE_PERIOD_MS = 2000;
100312
+ this.rawStdinHandler = (chunk) => {
100313
+ if (!this.bunProc?.terminal)
100314
+ return;
100315
+ const str = typeof chunk === "string" ? chunk : chunk.toString("binary");
100316
+ if (Date.now() - startTime < GRACE_PERIOD_MS) {
100317
+ if (str.includes("\x1B"))
100318
+ return;
100319
+ }
100320
+ this.bunProc.terminal.write(str);
100321
+ };
100322
+ process.stdin.on("data", this.rawStdinHandler);
100323
+ const resizeHandler = () => {
100324
+ if (this.bunProc?.terminal) {
100325
+ try {
100326
+ this.bunProc.terminal.resize(process.stdout.columns || 80, process.stdout.rows || 24);
100327
+ } catch {}
100328
+ }
100329
+ };
100330
+ process.on("SIGWINCH", resizeHandler);
100331
+ await this.bunProc.exited;
100332
+ const exitCode = this.bunProc.exitCode ?? 1;
100333
+ process.removeListener("SIGWINCH", resizeHandler);
100334
+ this.cleanup();
100335
+ return exitCode;
100336
+ }
100337
+ async showDiag(messages) {
100338
+ this.messages = messages.slice(-4);
100339
+ if (!this.renderer && !this.rendererInitializing) {
100340
+ this.rendererInitializing = true;
100341
+ try {
100342
+ this.renderer = await createCliRenderer({
100343
+ useAlternateScreen: false,
100344
+ experimental_splitHeight: 5,
100345
+ exitOnCtrlC: false,
100346
+ useMouse: false,
100347
+ useKittyKeyboard: null,
100348
+ targetFps: 10
100349
+ });
100350
+ this.reactRoot = createRoot(this.renderer);
100351
+ this.renderDiagPanel();
100352
+ } catch {
100353
+ this.rendererInitializing = false;
100354
+ return;
100355
+ }
100356
+ this.rendererInitializing = false;
100357
+ } else if (this.renderer) {
100358
+ if (this.renderer.experimental_splitHeight === 0) {
100359
+ this.renderer.experimental_splitHeight = 5;
100360
+ }
100361
+ this.renderDiagPanel();
100362
+ }
100363
+ if (this.autoHideTimer)
100364
+ clearTimeout(this.autoHideTimer);
100365
+ this.autoHideTimer = setTimeout(() => this.hideDiag(), 1e4);
100366
+ }
100367
+ hideDiag() {
100368
+ if (!this.renderer)
100369
+ return;
100370
+ if (this.autoHideTimer) {
100371
+ clearTimeout(this.autoHideTimer);
100372
+ this.autoHideTimer = null;
100373
+ }
100374
+ this.renderer.experimental_splitHeight = 0;
100375
+ }
100376
+ renderDiagPanel() {
100377
+ if (!this.reactRoot)
100378
+ return;
100379
+ this.reactRoot.render(import_react17.createElement(DiagPanel, { messages: this.messages }));
100380
+ }
100381
+ cleanup() {
100382
+ if (this.autoHideTimer) {
100383
+ clearTimeout(this.autoHideTimer);
100384
+ this.autoHideTimer = null;
100385
+ }
100386
+ if (this.rawStdinHandler) {
100387
+ process.stdin.removeListener("data", this.rawStdinHandler);
100388
+ this.rawStdinHandler = null;
100389
+ }
100390
+ if (this.bunProc) {
100391
+ try {
100392
+ this.bunProc.kill();
100393
+ } catch {}
100394
+ try {
100395
+ this.bunProc.terminal?.close();
100396
+ } catch {}
100397
+ this.bunProc = null;
100398
+ }
100399
+ if (this.renderer && !this.renderer.isDestroyed) {
100400
+ try {
100401
+ this.renderer.destroy();
100402
+ } catch {}
100403
+ this.renderer = null;
100404
+ }
100405
+ }
100406
+ }
100407
+ async function tryCreatePtyRunner() {
100408
+ try {
100409
+ if (typeof Bun === "undefined")
100410
+ return null;
100411
+ const test = Bun.spawn(["true"], { terminal: { cols: 1, rows: 1 } });
100412
+ await test.exited;
100413
+ return new PtyDiagRunner;
100414
+ } catch {
100415
+ return null;
100416
+ }
100417
+ }
100418
+ var import_react17;
100419
+ var init_pty_diag_runner = __esm(async () => {
100420
+ await __promiseAll([
100421
+ init_core3(),
100422
+ init_react(),
100423
+ init_DiagPanel()
100424
+ ]);
100425
+ import_react17 = __toESM(require_react(), 1);
100426
+ });
100427
+
100000
100428
  // src/port-manager.ts
100001
100429
  var exports_port_manager = {};
100002
100430
  __export(exports_port_manager, {
@@ -102577,7 +103005,7 @@ var init_openrouter_queue = __esm(() => {
102577
103005
  });
102578
103006
 
102579
103007
  // src/providers/transport/openrouter.ts
102580
- class OpenRouterProvider {
103008
+ class OpenRouterProviderTransport {
102581
103009
  name = "openrouter";
102582
103010
  displayName = "OpenRouter";
102583
103011
  streamFormat = "openai-sse";
@@ -102617,17 +103045,17 @@ var init_openrouter2 = __esm(() => {
102617
103045
  init_model_loader();
102618
103046
  });
102619
103047
 
102620
- // src/adapters/openrouter-adapter.ts
102621
- var OpenRouterAdapter;
102622
- var init_openrouter_adapter = __esm(() => {
102623
- init_base_adapter();
102624
- init_adapter_manager();
103048
+ // src/adapters/openrouter-api-format.ts
103049
+ var OpenRouterAPIFormat;
103050
+ var init_openrouter_api_format = __esm(() => {
103051
+ init_base_api_format();
103052
+ init_dialect_manager();
102625
103053
  init_transform();
102626
- OpenRouterAdapter = class OpenRouterAdapter extends BaseModelAdapter {
103054
+ OpenRouterAPIFormat = class OpenRouterAPIFormat extends BaseAPIFormat {
102627
103055
  innerAdapter;
102628
103056
  constructor(modelId) {
102629
103057
  super(modelId);
102630
- const manager = new AdapterManager(modelId);
103058
+ const manager = new DialectManager(modelId);
102631
103059
  this.innerAdapter = manager.getAdapter();
102632
103060
  }
102633
103061
  modelSupportsReasoning() {
@@ -102641,7 +103069,7 @@ var init_openrouter_adapter = __esm(() => {
102641
103069
  return true;
102642
103070
  }
102643
103071
  getName() {
102644
- return `OpenRouterAdapter(${this.innerAdapter.getName()})`;
103072
+ return `OpenRouterAPIFormat(${this.innerAdapter.getName()})`;
102645
103073
  }
102646
103074
  reset() {
102647
103075
  super.reset();
@@ -103119,16 +103547,16 @@ var init_local = __esm(() => {
103119
103547
  // src/adapters/local-adapter.ts
103120
103548
  var LocalModelAdapter;
103121
103549
  var init_local_adapter = __esm(() => {
103122
- init_base_adapter();
103123
- init_adapter_manager();
103550
+ init_base_api_format();
103551
+ init_dialect_manager();
103124
103552
  init_logger();
103125
- LocalModelAdapter = class LocalModelAdapter extends BaseModelAdapter {
103553
+ LocalModelAdapter = class LocalModelAdapter extends BaseAPIFormat {
103126
103554
  innerAdapter;
103127
103555
  providerName;
103128
103556
  constructor(modelId, providerName) {
103129
103557
  super(modelId);
103130
103558
  this.providerName = providerName;
103131
- const manager = new AdapterManager(modelId);
103559
+ const manager = new DialectManager(modelId);
103132
103560
  this.innerAdapter = manager.getAdapter();
103133
103561
  }
103134
103562
  processTextContent(textContent, accumulatedText) {
@@ -104617,9 +105045,9 @@ class ComposedHandler {
104617
105045
  this.options = options;
104618
105046
  this.explicitAdapter = options.adapter;
104619
105047
  this.isInteractive = options.isInteractive ?? false;
104620
- this.adapterManager = new AdapterManager(targetModel);
105048
+ this.adapterManager = new DialectManager(targetModel);
104621
105049
  const resolvedModelAdapter = this.adapterManager.getAdapter();
104622
- if (resolvedModelAdapter.getName() !== "DefaultAdapter") {
105050
+ if (resolvedModelAdapter.getName() !== "DefaultAPIFormat") {
104623
105051
  this.modelAdapter = resolvedModelAdapter;
104624
105052
  }
104625
105053
  this.middlewareManager = new MiddlewareManager;
@@ -105102,7 +105530,7 @@ function getRecoveryHint(status, errorText, providerName) {
105102
105530
  return `Unexpected HTTP ${status} from ${providerName}.`;
105103
105531
  }
105104
105532
  var init_composed_handler = __esm(() => {
105105
- init_adapter_manager();
105533
+ init_dialect_manager();
105106
105534
  init_middleware();
105107
105535
  init_token_tracker();
105108
105536
  init_transform();
@@ -105511,7 +105939,7 @@ var init_gemini_queue = __esm(() => {
105511
105939
  });
105512
105940
 
105513
105941
  // src/providers/transport/gemini-apikey.ts
105514
- class GeminiApiKeyProvider {
105942
+ class GeminiProviderTransport {
105515
105943
  name = "gemini";
105516
105944
  displayName = "Gemini API";
105517
105945
  streamFormat = "gemini-sse";
@@ -105544,7 +105972,7 @@ var init_gemini_apikey = __esm(() => {
105544
105972
  // src/providers/transport/gemini-codeassist.ts
105545
105973
  import { randomUUID } from "crypto";
105546
105974
 
105547
- class GeminiCodeAssistProvider {
105975
+ class GeminiCodeAssistProviderTransport {
105548
105976
  name = "gemini-codeassist";
105549
105977
  displayName = "Gemini Free";
105550
105978
  streamFormat = "gemini-sse";
@@ -105589,7 +106017,7 @@ var init_gemini_codeassist = __esm(() => {
105589
106017
  });
105590
106018
 
105591
106019
  // src/providers/transport/openai.ts
105592
- class OpenAIProvider {
106020
+ class OpenAIProviderTransport {
105593
106021
  name;
105594
106022
  displayName;
105595
106023
  streamFormat;
@@ -105601,7 +106029,7 @@ class OpenAIProvider {
105601
106029
  this.modelName = modelName;
105602
106030
  this.apiKey = apiKey;
105603
106031
  this.name = provider.name;
105604
- this.displayName = OpenAIProvider.formatDisplayName(provider.name);
106032
+ this.displayName = OpenAIProviderTransport.formatDisplayName(provider.name);
105605
106033
  this.streamFormat = modelName.toLowerCase().includes("codex") ? "openai-responses-sse" : "openai-sse";
105606
106034
  }
105607
106035
  getEndpoint() {
@@ -105669,7 +106097,7 @@ var init_openai = __esm(() => {
105669
106097
  });
105670
106098
 
105671
106099
  // src/providers/transport/anthropic-compat.ts
105672
- class AnthropicCompatProvider {
106100
+ class AnthropicProviderTransport {
105673
106101
  name;
105674
106102
  displayName;
105675
106103
  streamFormat = "anthropic-sse";
@@ -105679,7 +106107,7 @@ class AnthropicCompatProvider {
105679
106107
  this.provider = provider;
105680
106108
  this.apiKey = apiKey;
105681
106109
  this.name = provider.name;
105682
- this.displayName = AnthropicCompatProvider.formatDisplayName(provider.name);
106110
+ this.displayName = AnthropicProviderTransport.formatDisplayName(provider.name);
105683
106111
  }
105684
106112
  getEndpoint() {
105685
106113
  return `${this.provider.baseUrl}${this.provider.apiPath}`;
@@ -105736,11 +106164,11 @@ var init_anthropic_compat = __esm(() => {
105736
106164
  init_logger();
105737
106165
  });
105738
106166
 
105739
- // src/adapters/anthropic-passthrough-adapter.ts
105740
- var AnthropicPassthroughAdapter;
105741
- var init_anthropic_passthrough_adapter = __esm(() => {
105742
- init_base_adapter();
105743
- AnthropicPassthroughAdapter = class AnthropicPassthroughAdapter extends BaseModelAdapter {
106167
+ // src/adapters/anthropic-api-format.ts
106168
+ var AnthropicAPIFormat;
106169
+ var init_anthropic_api_format = __esm(() => {
106170
+ init_base_api_format();
106171
+ AnthropicAPIFormat = class AnthropicAPIFormat extends BaseAPIFormat {
105744
106172
  providerName;
105745
106173
  constructor(modelId, providerName) {
105746
106174
  super(modelId);
@@ -105757,7 +106185,7 @@ var init_anthropic_passthrough_adapter = __esm(() => {
105757
106185
  return false;
105758
106186
  }
105759
106187
  getName() {
105760
- return "AnthropicPassthroughAdapter";
106188
+ return "AnthropicAPIFormat";
105761
106189
  }
105762
106190
  convertMessages(claudeRequest, _filterFn) {
105763
106191
  const messages = claudeRequest.messages || [];
@@ -105842,7 +106270,7 @@ var init_anthropic_passthrough_adapter = __esm(() => {
105842
106270
  });
105843
106271
 
105844
106272
  // src/providers/transport/ollamacloud.ts
105845
- class OllamaCloudProvider {
106273
+ class OllamaProviderTransport {
105846
106274
  name = "ollamacloud";
105847
106275
  displayName = "OllamaCloud";
105848
106276
  streamFormat = "ollama-jsonl";
@@ -105863,12 +106291,13 @@ class OllamaCloudProvider {
105863
106291
  return headers;
105864
106292
  }
105865
106293
  }
106294
+ var init_ollamacloud = () => {};
105866
106295
 
105867
- // src/adapters/ollamacloud-adapter.ts
105868
- var OllamaCloudAdapter;
105869
- var init_ollamacloud_adapter = __esm(() => {
105870
- init_base_adapter();
105871
- OllamaCloudAdapter = class OllamaCloudAdapter extends BaseModelAdapter {
106296
+ // src/adapters/ollama-api-format.ts
106297
+ var OllamaAPIFormat;
106298
+ var init_ollama_api_format = __esm(() => {
106299
+ init_base_api_format();
106300
+ OllamaAPIFormat = class OllamaAPIFormat extends BaseAPIFormat {
105872
106301
  constructor(modelId) {
105873
106302
  super(modelId);
105874
106303
  }
@@ -105883,7 +106312,7 @@ var init_ollamacloud_adapter = __esm(() => {
105883
106312
  return false;
105884
106313
  }
105885
106314
  getName() {
105886
- return "OllamaCloudAdapter";
106315
+ return "OllamaAPIFormat";
105887
106316
  }
105888
106317
  convertMessages(claudeRequest, _filterFn) {
105889
106318
  const messages = [];
@@ -105959,7 +106388,7 @@ var init_ollamacloud_adapter = __esm(() => {
105959
106388
  });
105960
106389
 
105961
106390
  // src/providers/transport/litellm.ts
105962
- class LiteLLMProvider {
106391
+ class LiteLLMProviderTransport {
105963
106392
  name = "litellm";
105964
106393
  displayName = "LiteLLM";
105965
106394
  streamFormat = "openai-sse";
@@ -106011,17 +106440,17 @@ var init_litellm2 = __esm(() => {
106011
106440
  ];
106012
106441
  });
106013
106442
 
106014
- // src/adapters/litellm-adapter.ts
106443
+ // src/adapters/litellm-api-format.ts
106015
106444
  import { existsSync as existsSync21, readFileSync as readFileSync19 } from "fs";
106016
106445
  import { createHash as createHash5 } from "crypto";
106017
106446
  import { homedir as homedir21 } from "os";
106018
106447
  import { join as join24 } from "path";
106019
- var INLINE_IMAGE_MODEL_PATTERNS, LiteLLMAdapter;
106020
- var init_litellm_adapter = __esm(() => {
106021
- init_base_adapter();
106448
+ var INLINE_IMAGE_MODEL_PATTERNS, LiteLLMAPIFormat;
106449
+ var init_litellm_api_format = __esm(() => {
106450
+ init_base_api_format();
106022
106451
  init_logger();
106023
106452
  INLINE_IMAGE_MODEL_PATTERNS = ["minimax"];
106024
- LiteLLMAdapter = class LiteLLMAdapter extends DefaultAdapter {
106453
+ LiteLLMAPIFormat = class LiteLLMAPIFormat extends DefaultAPIFormat {
106025
106454
  baseUrl;
106026
106455
  visionSupported;
106027
106456
  needsInlineImages;
@@ -106032,7 +106461,7 @@ var init_litellm_adapter = __esm(() => {
106032
106461
  this.needsInlineImages = INLINE_IMAGE_MODEL_PATTERNS.some((p) => modelId.toLowerCase().includes(p));
106033
106462
  }
106034
106463
  getName() {
106035
- return "LiteLLMAdapter";
106464
+ return "LiteLLMAPIFormat";
106036
106465
  }
106037
106466
  shouldHandle(modelId) {
106038
106467
  return false;
@@ -106057,7 +106486,7 @@ var init_litellm_adapter = __esm(() => {
106057
106486
  if (base64Match) {
106058
106487
  inlineImages += `
106059
106488
  [Image base64:${base64Match[1]}]`;
106060
- log(`[LiteLLMAdapter] Converted image_url to inline base64 for ${this.modelId}`);
106489
+ log(`[LiteLLMAPIFormat] Converted image_url to inline base64 for ${this.modelId}`);
106061
106490
  }
106062
106491
  } else if (url2) {
106063
106492
  inlineImages += `
@@ -106117,7 +106546,7 @@ var init_litellm_adapter = __esm(() => {
106117
106546
  const cacheData = JSON.parse(readFileSync19(cachePath, "utf-8"));
106118
106547
  const model = cacheData.models?.find((m2) => m2.name === this.modelId);
106119
106548
  if (model && model.supportsVision === false) {
106120
- log(`[LiteLLMAdapter] Model ${this.modelId} does not support vision`);
106549
+ log(`[LiteLLMAPIFormat] Model ${this.modelId} does not support vision`);
106121
106550
  return false;
106122
106551
  }
106123
106552
  return true;
@@ -106296,7 +106725,7 @@ function parseVertexModel(modelId) {
106296
106725
  return { publisher: parts[0], model: parts.slice(1).join("/") };
106297
106726
  }
106298
106727
 
106299
- class VertexOAuthProvider {
106728
+ class VertexProviderTransport {
106300
106729
  name = "vertex";
106301
106730
  displayName = "Vertex AI";
106302
106731
  streamFormat;
@@ -106375,24 +106804,25 @@ var init_provider_profiles = __esm(() => {
106375
106804
  init_composed_handler();
106376
106805
  init_gemini_apikey();
106377
106806
  init_gemini_codeassist();
106378
- init_gemini_adapter();
106807
+ init_gemini_api_format();
106379
106808
  init_openai();
106380
- init_openai_adapter();
106809
+ init_openai_api_format();
106381
106810
  init_anthropic_compat();
106382
- init_anthropic_passthrough_adapter();
106383
- init_ollamacloud_adapter();
106811
+ init_anthropic_api_format();
106812
+ init_ollamacloud();
106813
+ init_ollama_api_format();
106384
106814
  init_litellm2();
106385
- init_litellm_adapter();
106815
+ init_litellm_api_format();
106386
106816
  init_vertex_oauth();
106387
- init_base_adapter();
106817
+ init_base_api_format();
106388
106818
  init_remote_provider_registry();
106389
106819
  init_vertex_auth();
106390
106820
  init_logger();
106391
106821
  init_api_key_provenance();
106392
106822
  geminiProfile = {
106393
106823
  createHandler(ctx) {
106394
- const transport = new GeminiApiKeyProvider(ctx.provider, ctx.modelName, ctx.apiKey);
106395
- const adapter = new GeminiAdapter(ctx.modelName);
106824
+ const transport = new GeminiProviderTransport(ctx.provider, ctx.modelName, ctx.apiKey);
106825
+ const adapter = new GeminiAPIFormat(ctx.modelName);
106396
106826
  const handler = new ComposedHandler(transport, ctx.targetModel, ctx.modelName, ctx.port, {
106397
106827
  adapter,
106398
106828
  ...ctx.sharedOpts
@@ -106403,8 +106833,8 @@ var init_provider_profiles = __esm(() => {
106403
106833
  };
106404
106834
  geminiCodeAssistProfile = {
106405
106835
  createHandler(ctx) {
106406
- const transport = new GeminiCodeAssistProvider(ctx.modelName);
106407
- const adapter = new GeminiAdapter(ctx.modelName);
106836
+ const transport = new GeminiCodeAssistProviderTransport(ctx.modelName);
106837
+ const adapter = new GeminiAPIFormat(ctx.modelName);
106408
106838
  const handler = new ComposedHandler(transport, ctx.targetModel, ctx.modelName, ctx.port, {
106409
106839
  adapter,
106410
106840
  unwrapGeminiResponse: true,
@@ -106416,8 +106846,8 @@ var init_provider_profiles = __esm(() => {
106416
106846
  };
106417
106847
  openaiProfile = {
106418
106848
  createHandler(ctx) {
106419
- const transport = new OpenAIProvider(ctx.provider, ctx.modelName, ctx.apiKey);
106420
- const adapter = new OpenAIAdapter(ctx.modelName);
106849
+ const transport = new OpenAIProviderTransport(ctx.provider, ctx.modelName, ctx.apiKey);
106850
+ const adapter = new OpenAIAPIFormat(ctx.modelName);
106421
106851
  const handler = new ComposedHandler(transport, ctx.targetModel, ctx.modelName, ctx.port, {
106422
106852
  adapter,
106423
106853
  tokenStrategy: "delta-aware",
@@ -106429,8 +106859,8 @@ var init_provider_profiles = __esm(() => {
106429
106859
  };
106430
106860
  anthropicCompatProfile = {
106431
106861
  createHandler(ctx) {
106432
- const transport = new AnthropicCompatProvider(ctx.provider, ctx.apiKey);
106433
- const adapter = new AnthropicPassthroughAdapter(ctx.modelName, ctx.provider.name);
106862
+ const transport = new AnthropicProviderTransport(ctx.provider, ctx.apiKey);
106863
+ const adapter = new AnthropicAPIFormat(ctx.modelName, ctx.provider.name);
106434
106864
  const handler = new ComposedHandler(transport, ctx.targetModel, ctx.modelName, ctx.port, {
106435
106865
  adapter,
106436
106866
  ...ctx.sharedOpts
@@ -106441,8 +106871,8 @@ var init_provider_profiles = __esm(() => {
106441
106871
  };
106442
106872
  glmProfile = {
106443
106873
  createHandler(ctx) {
106444
- const transport = new OpenAIProvider(ctx.provider, ctx.modelName, ctx.apiKey);
106445
- const adapter = new OpenAIAdapter(ctx.modelName);
106874
+ const transport = new OpenAIProviderTransport(ctx.provider, ctx.modelName, ctx.apiKey);
106875
+ const adapter = new OpenAIAPIFormat(ctx.modelName);
106446
106876
  const handler = new ComposedHandler(transport, ctx.targetModel, ctx.modelName, ctx.port, {
106447
106877
  adapter,
106448
106878
  tokenStrategy: "delta-aware",
@@ -106457,8 +106887,8 @@ var init_provider_profiles = __esm(() => {
106457
106887
  const zenApiKey = ctx.apiKey || "public";
106458
106888
  const isGoProvider = ctx.provider.name === "opencode-zen-go";
106459
106889
  if (ctx.modelName.toLowerCase().includes("minimax")) {
106460
- const transport2 = new AnthropicCompatProvider(ctx.provider, zenApiKey);
106461
- const adapter2 = new AnthropicPassthroughAdapter(ctx.modelName, ctx.provider.name);
106890
+ const transport2 = new AnthropicProviderTransport(ctx.provider, zenApiKey);
106891
+ const adapter2 = new AnthropicAPIFormat(ctx.modelName, ctx.provider.name);
106462
106892
  const handler2 = new ComposedHandler(transport2, ctx.targetModel, ctx.modelName, ctx.port, {
106463
106893
  adapter: adapter2,
106464
106894
  ...ctx.sharedOpts
@@ -106466,8 +106896,8 @@ var init_provider_profiles = __esm(() => {
106466
106896
  log(`[Proxy] Created OpenCode Zen${isGoProvider ? " Go" : ""} (Anthropic composed): ${ctx.modelName}`);
106467
106897
  return handler2;
106468
106898
  }
106469
- const transport = new OpenAIProvider(ctx.provider, ctx.modelName, zenApiKey);
106470
- const adapter = new OpenAIAdapter(ctx.modelName);
106899
+ const transport = new OpenAIProviderTransport(ctx.provider, ctx.modelName, zenApiKey);
106900
+ const adapter = new OpenAIAPIFormat(ctx.modelName);
106471
106901
  const handler = new ComposedHandler(transport, ctx.targetModel, ctx.modelName, ctx.port, {
106472
106902
  adapter,
106473
106903
  tokenStrategy: "delta-aware",
@@ -106479,8 +106909,8 @@ var init_provider_profiles = __esm(() => {
106479
106909
  };
106480
106910
  ollamaCloudProfile = {
106481
106911
  createHandler(ctx) {
106482
- const transport = new OllamaCloudProvider(ctx.provider, ctx.apiKey);
106483
- const adapter = new OllamaCloudAdapter(ctx.modelName);
106912
+ const transport = new OllamaProviderTransport(ctx.provider, ctx.apiKey);
106913
+ const adapter = new OllamaAPIFormat(ctx.modelName);
106484
106914
  const handler = new ComposedHandler(transport, ctx.targetModel, ctx.modelName, ctx.port, {
106485
106915
  adapter,
106486
106916
  tokenStrategy: "accumulate-both",
@@ -106498,8 +106928,8 @@ var init_provider_profiles = __esm(() => {
106498
106928
  logStderr("Or use: claudish --litellm-url https://your-instance.com --model litellm@model 'task'");
106499
106929
  return null;
106500
106930
  }
106501
- const transport = new LiteLLMProvider(ctx.provider.baseUrl, ctx.apiKey, ctx.modelName);
106502
- const adapter = new LiteLLMAdapter(ctx.modelName, ctx.provider.baseUrl);
106931
+ const transport = new LiteLLMProviderTransport(ctx.provider.baseUrl, ctx.apiKey, ctx.modelName);
106932
+ const adapter = new LiteLLMAPIFormat(ctx.modelName, ctx.provider.baseUrl);
106503
106933
  const handler = new ComposedHandler(transport, ctx.targetModel, ctx.modelName, ctx.port, {
106504
106934
  adapter,
106505
106935
  ...ctx.sharedOpts
@@ -106515,8 +106945,8 @@ var init_provider_profiles = __esm(() => {
106515
106945
  if (hasApiKey) {
106516
106946
  const geminiConfig = getRegisteredRemoteProviders().find((p) => p.name === "gemini");
106517
106947
  const expressProvider = geminiConfig || ctx.provider;
106518
- const transport = new GeminiApiKeyProvider(expressProvider, ctx.modelName, process.env.VERTEX_API_KEY);
106519
- const adapter = new GeminiAdapter(ctx.modelName);
106948
+ const transport = new GeminiProviderTransport(expressProvider, ctx.modelName, process.env.VERTEX_API_KEY);
106949
+ const adapter = new GeminiAPIFormat(ctx.modelName);
106520
106950
  const handler = new ComposedHandler(transport, ctx.targetModel, ctx.modelName, ctx.port, {
106521
106951
  adapter,
106522
106952
  ...ctx.sharedOpts
@@ -106531,15 +106961,15 @@ var init_provider_profiles = __esm(() => {
106531
106961
  return null;
106532
106962
  }
106533
106963
  const parsed = parseVertexModel(ctx.modelName);
106534
- const transport = new VertexOAuthProvider(vertexConfig, parsed);
106964
+ const transport = new VertexProviderTransport(vertexConfig, parsed);
106535
106965
  let adapter;
106536
106966
  if (parsed.publisher === "google") {
106537
- adapter = new GeminiAdapter(ctx.modelName);
106967
+ adapter = new GeminiAPIFormat(ctx.modelName);
106538
106968
  } else if (parsed.publisher === "anthropic") {
106539
- adapter = new AnthropicPassthroughAdapter(parsed.model, "vertex");
106969
+ adapter = new AnthropicAPIFormat(parsed.model, "vertex");
106540
106970
  } else {
106541
106971
  const modelId = parsed.publisher === "mistralai" ? parsed.model : `${parsed.publisher}/${parsed.model}`;
106542
- adapter = new DefaultAdapter(modelId);
106972
+ adapter = new DefaultAPIFormat(modelId);
106543
106973
  }
106544
106974
  const handler = new ComposedHandler(transport, ctx.targetModel, ctx.modelName, ctx.port, {
106545
106975
  adapter,
@@ -106586,8 +107016,8 @@ async function createProxyServer(port, openrouterApiKey, model, monitorMode = fa
106586
107016
  const parsed = parseModelSpec(targetModel);
106587
107017
  const modelId = targetModel.includes("@") ? parsed.model : targetModel;
106588
107018
  if (!openRouterHandlers.has(modelId)) {
106589
- const orProvider = new OpenRouterProvider(openrouterApiKey || "", modelId);
106590
- const orAdapter = new OpenRouterAdapter(modelId);
107019
+ const orProvider = new OpenRouterProviderTransport(openrouterApiKey || "", modelId);
107020
+ const orAdapter = new OpenRouterAPIFormat(modelId);
106591
107021
  openRouterHandlers.set(modelId, new ComposedHandler(orProvider, modelId, modelId, port, {
106592
107022
  adapter: orAdapter,
106593
107023
  isInteractive: options.isInteractive,
@@ -106875,7 +107305,7 @@ var init_proxy_server = __esm(() => {
106875
107305
  init_logger();
106876
107306
  init_native_handler();
106877
107307
  init_openrouter2();
106878
- init_openrouter_adapter();
107308
+ init_openrouter_api_format();
106879
107309
  init_local();
106880
107310
  init_local_adapter();
106881
107311
  init_composed_handler();
@@ -107038,6 +107468,7 @@ async function runCli() {
107038
107468
  } = await Promise.resolve().then(() => (init_provider_resolver(), exports_provider_resolver));
107039
107469
  const { initLogger: initLogger2, getLogFilePath: getLogFilePath2, getAlwaysOnLogPath: getAlwaysOnLogPath2, setDiagOutput: setDiagOutput2 } = await Promise.resolve().then(() => (init_logger(), exports_logger));
107040
107470
  const { createDiagOutput: createDiagOutput2, LogFileDiagOutput: LogFileDiagOutput2 } = await Promise.resolve().then(() => (init_diag_output(), exports_diag_output));
107471
+ const { tryCreatePtyRunner: tryCreatePtyRunner2 } = await init_pty_diag_runner().then(() => exports_pty_diag_runner);
107041
107472
  const { findAvailablePort: findAvailablePort2 } = await Promise.resolve().then(() => (init_port_manager(), exports_port_manager));
107042
107473
  const { createProxyServer: createProxyServer2 } = await Promise.resolve().then(() => (init_proxy_server(), exports_proxy_server));
107043
107474
  const { checkForUpdates: checkForUpdates2 } = await Promise.resolve().then(() => (init_update_checker(), exports_update_checker));
@@ -107155,16 +107586,22 @@ async function runCli() {
107155
107586
  quiet: cliConfig.quiet,
107156
107587
  isInteractive: cliConfig.interactive
107157
107588
  });
107158
- const diag = createDiagOutput2({ interactive: cliConfig.interactive });
107589
+ const needsPty = cliConfig.interactive && (cliConfig.diagMode === "auto" || cliConfig.diagMode === "pty");
107590
+ const ptyRunner = needsPty ? await tryCreatePtyRunner2() : null;
107591
+ const diag = createDiagOutput2({
107592
+ interactive: cliConfig.interactive,
107593
+ ptyRunner,
107594
+ diagMode: cliConfig.diagMode
107595
+ });
107159
107596
  if (cliConfig.interactive) {
107160
107597
  setDiagOutput2(diag);
107161
- if (!process.env.TMUX && !cliConfig.quiet && diag instanceof LogFileDiagOutput2) {
107598
+ if (!ptyRunner && !process.env.TMUX && !cliConfig.quiet && diag instanceof LogFileDiagOutput2) {
107162
107599
  console.log(`[claudish] Diagnostic log: ${diag.getLogPath()}`);
107163
107600
  }
107164
107601
  }
107165
107602
  let exitCode = 0;
107166
107603
  try {
107167
- exitCode = await runClaudeWithProxy2(cliConfig, proxy.url, () => diag.cleanup());
107604
+ exitCode = await runClaudeWithProxy2(cliConfig, proxy.url, () => diag.cleanup(), ptyRunner);
107168
107605
  } finally {
107169
107606
  setDiagOutput2(null);
107170
107607
  diag.cleanup();