claudish 5.18.1 → 5.19.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 +1829 -1377
  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",
@@ -35118,7 +35259,7 @@ import {
35118
35259
  existsSync as existsSync14,
35119
35260
  mkdirSync as mkdirSync6,
35120
35261
  copyFileSync,
35121
- readdirSync as readdirSync3,
35262
+ readdirSync as readdirSync4,
35122
35263
  unlinkSync as unlinkSync4
35123
35264
  } from "fs";
35124
35265
  import { fileURLToPath as fileURLToPath3 } from "url";
@@ -35134,7 +35275,7 @@ function clearAllModelCaches() {
35134
35275
  const cachePatterns = ["all-models.json", "pricing-cache.json"];
35135
35276
  let cleared = 0;
35136
35277
  try {
35137
- const files = readdirSync3(cacheDir);
35278
+ const files = readdirSync4(cacheDir);
35138
35279
  for (const file2 of files) {
35139
35280
  if (cachePatterns.includes(file2) || file2.startsWith("litellm-models-")) {
35140
35281
  unlinkSync4(join14(cacheDir, file2));
@@ -35162,6 +35303,7 @@ async function parseArgs(args) {
35162
35303
  stdin: false,
35163
35304
  freeOnly: false,
35164
35305
  noLogs: false,
35306
+ diagMode: "auto",
35165
35307
  claudeArgs: []
35166
35308
  };
35167
35309
  const claudishModel = process.env[ENV.CLAUDISH_MODEL];
@@ -35186,6 +35328,10 @@ async function parseArgs(args) {
35186
35328
  if (envSummarizeTools === "true" || envSummarizeTools === "1") {
35187
35329
  config3.summarizeTools = true;
35188
35330
  }
35331
+ const envDiagMode = process.env[ENV.CLAUDISH_DIAG_MODE]?.toLowerCase();
35332
+ if (envDiagMode && ["auto", "pty", "tmux", "logfile", "off"].includes(envDiagMode)) {
35333
+ config3.diagMode = envDiagMode;
35334
+ }
35189
35335
  let i = 0;
35190
35336
  while (i < args.length) {
35191
35337
  const arg = args[i];
@@ -35330,6 +35476,11 @@ async function parseArgs(args) {
35330
35476
  config3.summarizeTools = true;
35331
35477
  } else if (arg === "--no-logs") {
35332
35478
  config3.noLogs = true;
35479
+ } else if (arg === "--diag-mode" && i + 1 < args.length) {
35480
+ const mode = args[++i].toLowerCase();
35481
+ if (["auto", "pty", "tmux", "logfile", "off"].includes(mode)) {
35482
+ config3.diagMode = mode;
35483
+ }
35333
35484
  } else if (arg === "--") {
35334
35485
  config3.claudeArgs.push(...args.slice(i + 1));
35335
35486
  break;
@@ -36260,6 +36411,7 @@ OPTIONS:
36260
36411
  --port <port> Proxy server port (default: random)
36261
36412
  -d, --debug Enable debug logging to file (logs/claudish_*.log)
36262
36413
  --no-logs Disable always-on structural logging (~/.claudish/logs/)
36414
+ --diag-mode <mode> Diagnostic output: auto (default), pty, tmux, logfile, off
36263
36415
  --log-level <level> Log verbosity: debug (full), info (truncated), minimal (labels only)
36264
36416
  -q, --quiet Suppress [claudish] log messages (default in single-shot mode)
36265
36417
  -v, --verbose Show [claudish] log messages (default in interactive mode)
@@ -36738,7 +36890,7 @@ async function fetchGLMCodingModels() {
36738
36890
  return [];
36739
36891
  }
36740
36892
  }
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;
36893
+ var __filename4, __dirname4, VERSION = "5.19.0", CACHE_MAX_AGE_DAYS2 = 2, CLAUDISH_CACHE_DIR2, BUNDLED_MODELS_PATH, CACHED_MODELS_PATH, ALL_MODELS_JSON_PATH;
36742
36894
  var init_cli = __esm(() => {
36743
36895
  init_config();
36744
36896
  init_model_loader();
@@ -98068,17 +98220,28 @@ var init_providers = __esm(() => {
98068
98220
  var C2;
98069
98221
  var init_theme2 = __esm(() => {
98070
98222
  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"
98223
+ bg: "#000000",
98224
+ bgAlt: "#111111",
98225
+ bgHighlight: "#1e3a5f",
98226
+ fg: "#ffffff",
98227
+ fgMuted: "#a0a0a0",
98228
+ dim: "#555555",
98229
+ border: "#333333",
98230
+ focusBorder: "#57a5ff",
98231
+ green: "#39ff14",
98232
+ brightGreen: "#55ff55",
98233
+ red: "#ff003c",
98234
+ yellow: "#fce94f",
98235
+ cyan: "#00ffff",
98236
+ blue: "#0088ff",
98237
+ magenta: "#ff00ff",
98238
+ orange: "#ff8800",
98239
+ white: "#ffffff",
98240
+ black: "#000000",
98241
+ tabActiveBg: "#0088ff",
98242
+ tabInactiveBg: "#001a33",
98243
+ tabActiveFg: "#ffffff",
98244
+ tabInactiveFg: "#0088ff"
98082
98245
  };
98083
98246
  });
98084
98247
 
@@ -98088,1104 +98251,1210 @@ var init_jsx_dev_runtime = __esm(() => {
98088
98251
  import_jsx_dev_runtime2 = __toESM(require_jsx_dev_runtime(), 1);
98089
98252
  });
98090
98253
 
98091
- // src/tui/panels/ApiKeysPanel.tsx
98092
- function pad(str, len) {
98093
- return str.padEnd(len).substring(0, len);
98254
+ // src/tui/App.tsx
98255
+ function bytesHuman(b2) {
98256
+ if (b2 < 1024)
98257
+ return `${b2} B`;
98258
+ if (b2 < 1024 * 1024)
98259
+ return `${(b2 / 1024).toFixed(1)} KB`;
98260
+ return `${(b2 / (1024 * 1024)).toFixed(1)} MB`;
98094
98261
  }
98095
- function ApiKeysPanel({ focused, height: height2, width, onEditingChange }) {
98262
+ function App() {
98263
+ const renderer = useRenderer();
98264
+ const { width, height: height2 } = useTerminalDimensions();
98096
98265
  const [config3, setConfig] = import_react13.useState(() => loadConfig());
98266
+ const [bufStats, setBufStats] = import_react13.useState(() => getBufferStats());
98267
+ const [providerIndex, setProviderIndex] = import_react13.useState(0);
98268
+ const [activeTab, setActiveTab] = import_react13.useState("providers");
98097
98269
  const [mode, setMode] = import_react13.useState("browse");
98098
- const [itemIndex, setItemIndex] = import_react13.useState(0);
98099
- const [actionIndex, setActionIndex] = import_react13.useState(0);
98100
98270
  const [inputValue, setInputValue] = import_react13.useState("");
98271
+ const [routingPattern, setRoutingPattern] = import_react13.useState("");
98272
+ const [routingChain, setRoutingChain] = import_react13.useState("");
98101
98273
  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]);
98274
+ const quit = import_react13.useCallback(() => renderer.destroy(), [renderer]);
98275
+ const displayProviders = import_react13.useMemo(() => {
98276
+ return [...PROVIDERS].sort((a, b2) => {
98277
+ const aHasKey = !!(config3.apiKeys?.[a.apiKeyEnvVar] || process.env[a.apiKeyEnvVar]);
98278
+ const bHasKey = !!(config3.apiKeys?.[b2.apiKeyEnvVar] || process.env[b2.apiKeyEnvVar]);
98279
+ if (aHasKey === bHasKey)
98280
+ return PROVIDERS.indexOf(a) - PROVIDERS.indexOf(b2);
98281
+ return aHasKey ? -1 : 1;
98282
+ });
98283
+ }, [config3]);
98284
+ const selectedProvider = displayProviders[providerIndex];
98285
+ const refreshConfig = import_react13.useCallback(() => {
98286
+ setConfig(loadConfig());
98287
+ setBufStats(getBufferStats());
98288
+ }, []);
98289
+ const hasCfgKey = !!config3.apiKeys?.[selectedProvider.apiKeyEnvVar];
98290
+ const hasEnvKey = !!process.env[selectedProvider.apiKeyEnvVar];
98291
+ const hasKey = hasCfgKey || hasEnvKey;
98292
+ const cfgKeyMask = maskKey2(config3.apiKeys?.[selectedProvider.apiKeyEnvVar]);
98293
+ const envKeyMask = maskKey2(process.env[selectedProvider.apiKeyEnvVar]);
98294
+ const keySrc = hasEnvKey && hasCfgKey ? "e+c" : hasEnvKey ? "env" : hasCfgKey ? "cfg" : "";
98295
+ const activeEndpoint = (selectedProvider.endpointEnvVar ? config3.endpoints?.[selectedProvider.endpointEnvVar] || process.env[selectedProvider.endpointEnvVar] : undefined) || selectedProvider.defaultEndpoint || "";
98296
+ const telemetryEnabled = process.env.CLAUDISH_TELEMETRY !== "0" && process.env.CLAUDISH_TELEMETRY !== "false" && config3.telemetry?.enabled === true;
98297
+ const statsEnabled2 = process.env.CLAUDISH_STATS !== "0" && process.env.CLAUDISH_STATS !== "false";
98298
+ const ruleEntries = Object.entries(config3.routing ?? {});
98299
+ const profileName = config3.defaultProfile || "default";
98300
+ const readyCount = PROVIDERS.filter((p) => !!(config3.apiKeys?.[p.apiKeyEnvVar] || process.env[p.apiKeyEnvVar])).length;
98148
98301
  useKeyboard((key) => {
98149
- if (!focused)
98150
- return;
98302
+ if (key.ctrl && key.name === "c")
98303
+ return quit();
98151
98304
  if (mode === "input_key" || mode === "input_endpoint") {
98152
98305
  if (key.name === "return" || key.name === "enter") {
98153
98306
  const val = inputValue.trim();
98154
98307
  if (!val) {
98155
- setStatusMsg("\u2717 Aborted (empty).");
98308
+ setStatusMsg("Aborted (empty).");
98156
98309
  setMode("browse");
98157
98310
  return;
98158
98311
  }
98159
98312
  if (mode === "input_key") {
98160
98313
  setApiKey(selectedProvider.apiKeyEnvVar, val);
98161
98314
  process.env[selectedProvider.apiKeyEnvVar] = val;
98162
- setStatusMsg(`\u2713 API Key saved for ${selectedProvider.displayName}.`);
98315
+ setStatusMsg(`Key saved for ${selectedProvider.displayName}.`);
98163
98316
  } else {
98164
- setEndpoint(selectedProvider.endpointEnvVar, val);
98165
- process.env[selectedProvider.endpointEnvVar] = val;
98166
- setStatusMsg(`\u2713 Custom endpoint saved.`);
98317
+ if (selectedProvider.endpointEnvVar) {
98318
+ setEndpoint(selectedProvider.endpointEnvVar, val);
98319
+ process.env[selectedProvider.endpointEnvVar] = val;
98320
+ }
98321
+ setStatusMsg("Endpoint saved.");
98167
98322
  }
98168
- setConfig(loadConfig());
98323
+ refreshConfig();
98169
98324
  setInputValue("");
98170
98325
  setMode("browse");
98171
98326
  } 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";
98327
+ setInputValue("");
98328
+ setMode("browse");
98329
+ }
98330
+ return;
98191
98331
  }
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);
98332
+ if (mode === "add_routing_pattern") {
98333
+ if (key.name === "return" || key.name === "enter") {
98334
+ if (routingPattern.trim())
98335
+ setMode("add_routing_chain");
98336
+ } else if (key.name === "escape") {
98337
+ setMode("browse");
98338
+ }
98339
+ return;
98340
+ }
98341
+ if (mode === "add_routing_chain") {
98342
+ if (key.name === "return" || key.name === "enter") {
98343
+ const pat = routingPattern.trim();
98344
+ const ch = routingChain.trim().split(",").map((s) => s.trim()).filter(Boolean);
98345
+ if (pat && ch.length) {
98346
+ const cfg = loadConfig();
98347
+ if (!cfg.routing)
98348
+ cfg.routing = {};
98349
+ cfg.routing[pat] = ch;
98350
+ saveConfig(cfg);
98351
+ refreshConfig();
98352
+ setStatusMsg(`Rule added for '${pat}'.`);
98353
+ }
98354
+ setRoutingPattern("");
98355
+ setRoutingChain("");
98356
+ setMode("browse");
98357
+ } else if (key.name === "escape") {
98358
+ setMode("add_routing_pattern");
98359
+ }
98360
+ return;
98361
+ }
98362
+ if (key.name === "q")
98363
+ return quit();
98364
+ if (key.name === "tab") {
98365
+ const tabs = ["providers", "routing", "privacy"];
98366
+ const idx = tabs.indexOf(activeTab);
98367
+ setActiveTab(tabs[(idx + 1) % tabs.length]);
98368
+ setStatusMsg(null);
98369
+ return;
98370
+ }
98371
+ if (key.name === "1") {
98372
+ setActiveTab("providers");
98373
+ setStatusMsg(null);
98374
+ return;
98375
+ }
98376
+ if (key.name === "2") {
98377
+ setActiveTab("routing");
98378
+ setStatusMsg(null);
98379
+ return;
98380
+ }
98381
+ if (key.name === "3") {
98382
+ setActiveTab("privacy");
98383
+ setStatusMsg(null);
98384
+ return;
98385
+ }
98386
+ if (activeTab === "providers") {
98387
+ if (key.name === "up" || key.name === "k") {
98388
+ setProviderIndex((i) => Math.max(0, i - 1));
98389
+ setStatusMsg(null);
98390
+ } else if (key.name === "down" || key.name === "j") {
98391
+ setProviderIndex((i) => Math.min(displayProviders.length - 1, i + 1));
98392
+ setStatusMsg(null);
98393
+ } else if (key.name === "s") {
98394
+ setInputValue("");
98395
+ setStatusMsg(null);
98396
+ setMode("input_key");
98397
+ } else if (key.name === "e") {
98398
+ if (selectedProvider.endpointEnvVar) {
98399
+ setInputValue(activeEndpoint);
98223
98400
  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
98401
+ setMode("input_endpoint");
98402
+ } else {
98403
+ setStatusMsg("This provider has no custom endpoint.");
98404
+ }
98405
+ } else if (key.name === "x") {
98406
+ if (hasCfgKey) {
98407
+ removeApiKey(selectedProvider.apiKeyEnvVar);
98408
+ if (selectedProvider.endpointEnvVar) {
98409
+ removeEndpoint(selectedProvider.endpointEnvVar);
98410
+ }
98411
+ refreshConfig();
98412
+ setStatusMsg(`Key removed for ${selectedProvider.displayName}.`);
98413
+ } else {
98414
+ setStatusMsg("No stored key to remove.");
98415
+ }
98416
+ }
98417
+ } else if (activeTab === "routing") {
98418
+ if (key.name === "a") {
98419
+ setRoutingPattern("");
98420
+ setRoutingChain("");
98421
+ setStatusMsg(null);
98422
+ setMode("add_routing_pattern");
98423
+ } else if (key.name === "d") {
98424
+ if (ruleEntries.length > 0) {
98425
+ const [pat] = ruleEntries[Math.min(providerIndex, ruleEntries.length - 1)];
98426
+ const cfg = loadConfig();
98427
+ if (cfg.routing) {
98428
+ delete cfg.routing[pat];
98429
+ saveConfig(cfg);
98430
+ refreshConfig();
98431
+ setStatusMsg(`Rule deleted: '${pat}'.`);
98432
+ }
98433
+ } else {
98434
+ setStatusMsg("No routing rules to delete.");
98435
+ }
98436
+ } else if (key.name === "up" || key.name === "k") {
98437
+ setProviderIndex((i) => Math.max(0, i - 1));
98438
+ } else if (key.name === "down" || key.name === "j") {
98439
+ setProviderIndex((i) => Math.min(Math.max(0, ruleEntries.length - 1), i + 1));
98440
+ }
98441
+ } else if (activeTab === "privacy") {
98442
+ if (key.name === "t") {
98443
+ const cfg = loadConfig();
98444
+ const next = !telemetryEnabled;
98445
+ cfg.telemetry = {
98446
+ ...cfg.telemetry ?? {},
98447
+ enabled: next,
98448
+ askedAt: cfg.telemetry?.askedAt ?? new Date().toISOString()
98449
+ };
98450
+ saveConfig(cfg);
98451
+ refreshConfig();
98452
+ setStatusMsg(`Telemetry ${next ? "enabled" : "disabled"}.`);
98453
+ } else if (key.name === "u") {
98454
+ const cfg = loadConfig();
98455
+ const statsKey = "CLAUDISH_STATS";
98456
+ const next = !statsEnabled2;
98457
+ if (!cfg.telemetry)
98458
+ cfg.telemetry = { enabled: telemetryEnabled, askedAt: new Date().toISOString() };
98459
+ cfg.statsEnabled = next;
98460
+ saveConfig(cfg);
98461
+ refreshConfig();
98462
+ setStatusMsg(`Usage stats ${next ? "enabled" : "disabled"}.`);
98463
+ } else if (key.name === "c") {
98464
+ clearBuffer();
98465
+ setBufStats(getBufferStats());
98466
+ setStatusMsg("Stats buffer cleared.");
98467
+ }
98468
+ }
98469
+ });
98470
+ if (height2 < 15 || width < 60) {
98471
+ return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
98472
+ width: "100%",
98473
+ height: "100%",
98474
+ padding: 1,
98475
+ backgroundColor: C2.bg,
98476
+ children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
98477
+ children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98478
+ fg: C2.red,
98479
+ bold: true,
98480
+ children: [
98481
+ "Terminal too small (",
98482
+ width,
98483
+ "x",
98484
+ height2,
98485
+ "). Resize to at least 60x15."
98486
+ ]
98487
+ }, undefined, true, undefined, this)
98488
+ }, undefined, false, undefined, this)
98489
+ }, undefined, false, undefined, this);
98490
+ }
98491
+ const isInputMode = mode === "input_key" || mode === "input_endpoint";
98492
+ const isRoutingInput = mode === "add_routing_pattern" || mode === "add_routing_chain";
98493
+ const HEADER_H = 1;
98494
+ const TABS_H = 2;
98495
+ const FOOTER_H = 1;
98496
+ const DETAIL_H = 5;
98497
+ const contentH = Math.max(4, height2 - HEADER_H - TABS_H - DETAIL_H - FOOTER_H);
98498
+ function TabBar() {
98499
+ const tabs = [
98500
+ { label: "Providers", value: "providers", num: "1" },
98501
+ { label: "Routing", value: "routing", num: "2" },
98502
+ { label: "Privacy", value: "privacy", num: "3" }
98503
+ ];
98504
+ return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
98505
+ height: TABS_H,
98506
+ flexDirection: "column",
98507
+ backgroundColor: C2.bg,
98508
+ children: [
98509
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
98510
+ height: 1,
98511
+ flexDirection: "row",
98512
+ paddingX: 1,
98513
+ children: [
98514
+ tabs.map((t2, i) => {
98515
+ const active = activeTab === t2.value;
98516
+ return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
98517
+ children: [
98518
+ i > 0 && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98519
+ fg: C2.bg,
98520
+ children: " "
98521
+ }, undefined, false, undefined, this),
98522
+ active ? /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98523
+ fg: C2.tabActiveFg,
98524
+ backgroundColor: C2.tabActiveBg,
98525
+ bold: true,
98526
+ children: ` ${t2.num}. ${t2.label} `
98527
+ }, undefined, false, undefined, this) : /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98528
+ fg: C2.tabInactiveFg,
98529
+ backgroundColor: C2.tabInactiveBg,
98530
+ bold: true,
98531
+ children: ` ${t2.num}. ${t2.label} `
98532
+ }, undefined, false, undefined, this)
98533
+ ]
98534
+ }, t2.value, true, undefined, this);
98535
+ }),
98536
+ statusMsg && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
98537
+ children: [
98538
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98539
+ fg: C2.dim,
98540
+ children: " \u2500 "
98541
+ }, undefined, false, undefined, this),
98542
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98543
+ 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,
98544
+ bold: true,
98545
+ children: statusMsg
98546
+ }, undefined, false, undefined, this)
98547
+ ]
98548
+ }, undefined, true, undefined, this)
98549
+ ]
98550
+ }, undefined, true, undefined, this),
98551
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
98552
+ height: 1,
98553
+ paddingX: 1,
98554
+ children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
98555
+ children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98556
+ fg: C2.tabActiveBg,
98557
+ children: "\u2500".repeat(Math.max(0, width - 2))
98558
+ }, undefined, false, undefined, this)
98235
98559
  }, undefined, false, undefined, this)
98560
+ }, undefined, false, undefined, this),
98561
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
98562
+ height: 1
98236
98563
  }, undefined, false, undefined, this)
98237
- }, undefined, false, undefined, this),
98238
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
98564
+ ]
98565
+ }, undefined, true, undefined, this);
98566
+ }
98567
+ function ProvidersContent() {
98568
+ const listH = contentH - 2;
98569
+ let separatorRendered = false;
98570
+ const getRow = (p, idx) => {
98571
+ const isReady = !!(config3.apiKeys?.[p.apiKeyEnvVar] || process.env[p.apiKeyEnvVar]);
98572
+ const selected = idx === providerIndex;
98573
+ const keyDisplay = isReady ? maskKey2(config3.apiKeys?.[p.apiKeyEnvVar]) || maskKey2(process.env[p.apiKeyEnvVar]) : "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500";
98574
+ const namePad = p.displayName.padEnd(14).substring(0, 14);
98575
+ const isFirstUnready = !isReady && !separatorRendered;
98576
+ if (isFirstUnready)
98577
+ separatorRendered = true;
98578
+ return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
98239
98579
  flexDirection: "column",
98240
- height: bottomHeight,
98241
- paddingX: 1,
98242
98580
  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", {
98246
- 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)
98252
- }, 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)
98260
- ]
98261
- }, undefined, true, undefined, this),
98262
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
98581
+ isFirstUnready && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
98582
+ height: 1,
98583
+ paddingX: 1,
98584
+ children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
98585
+ children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98586
+ fg: C2.dim,
98263
98587
  children: [
98264
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98265
- 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: "
98281
- }, undefined, false, undefined, this),
98282
- /* @__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)
98588
+ "\u2500 not configured ",
98589
+ "\u2500".repeat(Math.max(0, width - 22))
98293
98590
  ]
98294
98591
  }, undefined, true, undefined, this)
98592
+ }, undefined, false, undefined, this)
98593
+ }, undefined, false, undefined, this),
98594
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
98595
+ height: 1,
98596
+ flexDirection: "row",
98597
+ backgroundColor: selected ? C2.bgHighlight : C2.bg,
98598
+ children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
98599
+ children: [
98600
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98601
+ fg: isReady ? C2.green : C2.dim,
98602
+ children: isReady ? "\u25CF" : "\u25CB"
98603
+ }, undefined, false, undefined, this),
98604
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98605
+ children: " "
98606
+ }, undefined, false, undefined, this),
98607
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98608
+ fg: selected ? C2.white : isReady ? C2.fgMuted : C2.dim,
98609
+ bold: selected,
98610
+ children: namePad
98611
+ }, undefined, false, undefined, this),
98612
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98613
+ fg: C2.dim,
98614
+ children: " "
98615
+ }, undefined, false, undefined, this),
98616
+ isReady ? /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98617
+ fg: C2.black,
98618
+ backgroundColor: C2.brightGreen,
98619
+ bold: true,
98620
+ children: " ready "
98621
+ }, undefined, false, undefined, this) : /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98622
+ fg: C2.dim,
98623
+ children: " not set "
98624
+ }, undefined, false, undefined, this),
98625
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98626
+ fg: C2.dim,
98627
+ children: " "
98628
+ }, undefined, false, undefined, this),
98629
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98630
+ fg: isReady ? C2.green : C2.dim,
98631
+ children: keyDisplay
98632
+ }, undefined, false, undefined, this),
98633
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98634
+ fg: C2.dim,
98635
+ children: " "
98636
+ }, undefined, false, undefined, this),
98637
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98638
+ fg: selected ? C2.white : C2.dim,
98639
+ children: p.description
98640
+ }, undefined, false, undefined, this)
98641
+ ]
98642
+ }, undefined, true, undefined, this)
98643
+ }, undefined, false, undefined, this)
98644
+ ]
98645
+ }, p.name, true, undefined, this);
98646
+ };
98647
+ return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
98648
+ height: contentH,
98649
+ border: true,
98650
+ borderStyle: "single",
98651
+ borderColor: !isInputMode ? C2.blue : C2.dim,
98652
+ backgroundColor: C2.bg,
98653
+ flexDirection: "column",
98654
+ paddingX: 1,
98655
+ children: [
98656
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
98657
+ children: [
98658
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98659
+ fg: C2.dim,
98660
+ children: " "
98661
+ }, undefined, false, undefined, this),
98662
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98663
+ fg: C2.blue,
98664
+ bold: true,
98665
+ children: "PROVIDER "
98666
+ }, undefined, false, undefined, this),
98667
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98668
+ fg: C2.blue,
98669
+ bold: true,
98670
+ children: "STATUS "
98671
+ }, undefined, false, undefined, this),
98672
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98673
+ fg: C2.blue,
98674
+ bold: true,
98675
+ children: "KEY "
98676
+ }, undefined, false, undefined, this),
98677
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98678
+ fg: C2.blue,
98679
+ bold: true,
98680
+ children: "DESCRIPTION"
98681
+ }, undefined, false, undefined, this)
98682
+ ]
98683
+ }, undefined, true, undefined, this),
98684
+ displayProviders.slice(0, listH).map(getRow)
98685
+ ]
98686
+ }, undefined, true, undefined, this);
98687
+ }
98688
+ function ProviderDetail() {
98689
+ const displayKey = hasCfgKey ? cfgKeyMask : hasEnvKey ? envKeyMask : "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500";
98690
+ if (isInputMode) {
98691
+ return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
98692
+ height: DETAIL_H,
98693
+ border: true,
98694
+ borderStyle: "single",
98695
+ borderColor: C2.focusBorder,
98696
+ title: ` Set ${mode === "input_key" ? "API Key" : "Endpoint"} \u2014 ${selectedProvider.displayName} `,
98697
+ backgroundColor: C2.bg,
98698
+ flexDirection: "column",
98699
+ paddingX: 1,
98700
+ children: [
98701
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
98702
+ children: [
98703
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98704
+ fg: C2.green,
98705
+ bold: true,
98706
+ children: "Enter "
98707
+ }, undefined, false, undefined, this),
98708
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98709
+ fg: C2.fgMuted,
98710
+ children: "to save \xB7 "
98711
+ }, undefined, false, undefined, this),
98712
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98713
+ fg: C2.red,
98714
+ bold: true,
98715
+ children: "Esc "
98716
+ }, undefined, false, undefined, this),
98717
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98718
+ fg: C2.fgMuted,
98719
+ children: "to cancel"
98720
+ }, undefined, false, undefined, this)
98295
98721
  ]
98296
98722
  }, undefined, true, undefined, this),
98297
- mode === "action" && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(import_jsx_dev_runtime2.Fragment, {
98723
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
98724
+ flexDirection: "row",
98298
98725
  children: [
98299
98726
  /* @__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)
98727
+ children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98728
+ fg: C2.green,
98729
+ bold: true,
98730
+ children: "> "
98308
98731
  }, undefined, false, undefined, this)
98309
98732
  }, 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
98733
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("input", {
98734
+ value: inputValue,
98735
+ onChange: setInputValue,
98736
+ focused: true,
98737
+ width: width - 8,
98738
+ backgroundColor: C2.bgHighlight,
98739
+ textColor: C2.white
98319
98740
  }, undefined, false, undefined, this)
98320
98741
  ]
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,
98742
+ }, undefined, true, undefined, this)
98743
+ ]
98744
+ }, undefined, true, undefined, this);
98745
+ }
98746
+ return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
98747
+ height: DETAIL_H,
98748
+ border: true,
98749
+ borderStyle: "single",
98750
+ borderColor: C2.dim,
98751
+ title: ` ${selectedProvider.displayName} `,
98752
+ backgroundColor: C2.bgAlt,
98753
+ flexDirection: "column",
98754
+ paddingX: 1,
98755
+ children: [
98756
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
98757
+ flexDirection: "row",
98758
+ children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
98325
98759
  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",
98760
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98761
+ fg: C2.blue,
98762
+ bold: true,
98763
+ children: "Status: "
98764
+ }, undefined, false, undefined, this),
98765
+ hasKey ? /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98766
+ fg: C2.green,
98767
+ bold: true,
98768
+ children: "\u25CF Ready"
98769
+ }, undefined, false, undefined, this) : /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98770
+ fg: C2.fgMuted,
98771
+ children: "\u25CB Not configured"
98772
+ }, undefined, false, undefined, this),
98773
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98774
+ fg: C2.dim,
98775
+ children: " "
98776
+ }, undefined, false, undefined, this),
98777
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98778
+ fg: C2.blue,
98779
+ bold: true,
98780
+ children: "Key: "
98781
+ }, undefined, false, undefined, this),
98782
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98783
+ fg: C2.green,
98784
+ children: displayKey
98785
+ }, undefined, false, undefined, this),
98786
+ keySrc && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98787
+ fg: C2.fgMuted,
98345
98788
  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)
98789
+ " (source: ",
98790
+ keySrc,
98791
+ ")"
98360
98792
  ]
98361
98793
  }, undefined, true, undefined, this)
98362
98794
  ]
98363
98795
  }, 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
98796
  }, undefined, false, undefined, this),
98415
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
98797
+ selectedProvider.endpointEnvVar && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
98416
98798
  children: [
98417
98799
  /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98418
- fg: C2.dim,
98419
- children: " Default Profile: "
98800
+ fg: C2.blue,
98801
+ bold: true,
98802
+ children: "URL: "
98420
98803
  }, undefined, false, undefined, this),
98421
98804
  /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98422
- fg: C2.fg,
98423
- children: config3.defaultProfile
98805
+ fg: C2.cyan,
98806
+ children: activeEndpoint || selectedProvider.defaultEndpoint || "default"
98424
98807
  }, undefined, false, undefined, this)
98425
98808
  ]
98426
98809
  }, undefined, true, undefined, this),
98427
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
98810
+ selectedProvider.keyUrl && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
98428
98811
  children: [
98429
98812
  /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98430
- fg: C2.dim,
98431
- children: " Telemetry: "
98813
+ fg: C2.blue,
98814
+ bold: true,
98815
+ children: "Get Key: "
98432
98816
  }, undefined, false, undefined, this),
98433
98817
  /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98434
- fg: tColor,
98435
- children: tState
98818
+ fg: C2.cyan,
98819
+ children: selectedProvider.keyUrl
98436
98820
  }, undefined, false, undefined, this)
98437
98821
  ]
98438
- }, undefined, true, undefined, this),
98439
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
98822
+ }, undefined, true, undefined, this)
98823
+ ]
98824
+ }, undefined, true, undefined, this);
98825
+ }
98826
+ function RoutingChain({ chain, description }) {
98827
+ return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
98828
+ children: [
98829
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98830
+ fg: C2.dim,
98831
+ children: " "
98832
+ }, undefined, false, undefined, this),
98833
+ chain.map((p, i) => /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98440
98834
  children: [
98441
98835
  /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98442
- fg: C2.dim,
98443
- children: " Config File: "
98836
+ fg: C2.black,
98837
+ backgroundColor: C2.cyan,
98838
+ bold: true,
98839
+ children: ` ${p} `
98444
98840
  }, undefined, false, undefined, this),
98445
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98446
- fg: C2.fg,
98447
- children: "~/.claudish/config.json"
98841
+ i < chain.length - 1 && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98842
+ fg: C2.dim,
98843
+ children: " \u2192 "
98448
98844
  }, undefined, false, undefined, this)
98449
98845
  ]
98450
- }, undefined, true, undefined, this),
98451
- /* @__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)
98456
- }, undefined, false, undefined, this),
98457
- /* @__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)
98846
+ }, p, true, undefined, this)),
98847
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98848
+ fg: C2.dim,
98849
+ children: " \u2014 "
98464
98850
  }, undefined, false, undefined, this),
98465
- items.length === 0 ? /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
98466
- children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98467
- fg: C2.dim,
98468
- children: " No customizations found."
98469
- }, undefined, false, undefined, this)
98470
- }, undefined, false, undefined, this) : items.map((itm) => /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
98851
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98852
+ fg: C2.fgMuted,
98853
+ children: description
98854
+ }, undefined, false, undefined, this)
98855
+ ]
98856
+ }, undefined, true, undefined, this);
98857
+ }
98858
+ function RoutingContent() {
98859
+ const innerH = contentH - 2;
98860
+ return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
98861
+ height: contentH,
98862
+ border: true,
98863
+ borderStyle: "single",
98864
+ borderColor: C2.blue,
98865
+ backgroundColor: C2.bg,
98866
+ flexDirection: "column",
98867
+ paddingX: 1,
98868
+ children: [
98869
+ ruleEntries.length === 0 && !isRoutingInput && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(import_jsx_dev_runtime2.Fragment, {
98471
98870
  children: [
98472
- /* @__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),
98479
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98480
- fg: C2.green,
98871
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
98481
98872
  children: [
98482
- " ",
98483
- maskKey2(itm?.kVal)
98873
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98874
+ fg: C2.fgMuted,
98875
+ children: "No custom rules. Press "
98876
+ }, undefined, false, undefined, this),
98877
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98878
+ fg: C2.black,
98879
+ backgroundColor: C2.green,
98880
+ bold: true,
98881
+ children: " a "
98882
+ }, undefined, false, undefined, this),
98883
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98884
+ fg: C2.fgMuted,
98885
+ children: " to add one. Default: LiteLLM \u2192 Zen \u2192 Native \u2192 OpenRouter"
98886
+ }, undefined, false, undefined, this)
98484
98887
  ]
98485
98888
  }, undefined, true, undefined, this),
98486
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98487
- fg: C2.dim,
98889
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
98890
+ children: " "
98891
+ }, undefined, false, undefined, this),
98892
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
98893
+ children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98894
+ fg: C2.blue,
98895
+ bold: true,
98896
+ children: "Examples"
98897
+ }, undefined, false, undefined, this)
98898
+ }, undefined, false, undefined, this),
98899
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
98900
+ children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98901
+ fg: C2.white,
98902
+ bold: true,
98903
+ children: " kimi-*"
98904
+ }, undefined, false, undefined, this)
98905
+ }, undefined, false, undefined, this),
98906
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(RoutingChain, {
98907
+ chain: ["kimi", "openrouter"],
98908
+ description: "Try Kimi first, fall back to OpenRouter"
98909
+ }, undefined, false, undefined, this),
98910
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
98911
+ children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98912
+ fg: C2.white,
98913
+ bold: true,
98914
+ children: " gpt-*"
98915
+ }, undefined, false, undefined, this)
98916
+ }, undefined, false, undefined, this),
98917
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(RoutingChain, {
98918
+ chain: ["oai", "litellm"],
98919
+ description: "Use OpenAI direct, then LiteLLM proxy"
98920
+ }, undefined, false, undefined, this),
98921
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
98922
+ children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98923
+ fg: C2.white,
98924
+ bold: true,
98925
+ children: " gemini-*"
98926
+ }, undefined, false, undefined, this)
98927
+ }, undefined, false, undefined, this),
98928
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(RoutingChain, {
98929
+ chain: ["google", "zen", "openrouter"],
98930
+ description: "Gemini direct \u2192 Zen free tier \u2192 OpenRouter"
98931
+ }, undefined, false, undefined, this),
98932
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
98933
+ children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98934
+ fg: C2.white,
98935
+ bold: true,
98936
+ children: " *"
98937
+ }, undefined, false, undefined, this)
98938
+ }, undefined, false, undefined, this),
98939
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(RoutingChain, {
98940
+ chain: ["zen", "openrouter"],
98941
+ description: "Catch-all: try free Zen first"
98942
+ }, undefined, false, undefined, this)
98943
+ ]
98944
+ }, undefined, true, undefined, this),
98945
+ ruleEntries.length > 0 && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(import_jsx_dev_runtime2.Fragment, {
98946
+ children: [
98947
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
98488
98948
  children: [
98489
- " (",
98490
- itm?.kSrc,
98491
- ") "
98949
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98950
+ fg: C2.blue,
98951
+ bold: true,
98952
+ children: "PATTERN "
98953
+ }, undefined, false, undefined, this),
98954
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98955
+ fg: C2.blue,
98956
+ bold: true,
98957
+ children: "CHAIN"
98958
+ }, undefined, false, undefined, this)
98492
98959
  ]
98493
98960
  }, undefined, true, undefined, this),
98494
- itm?.eVal ? /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(import_jsx_dev_runtime2.Fragment, {
98961
+ ruleEntries.slice(0, Math.max(0, innerH - 3)).map(([pat, chain], idx) => {
98962
+ const sel = idx === providerIndex;
98963
+ return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
98964
+ height: 1,
98965
+ flexDirection: "row",
98966
+ backgroundColor: sel ? C2.bgHighlight : C2.bg,
98967
+ children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
98968
+ children: [
98969
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98970
+ fg: sel ? C2.white : C2.fgMuted,
98971
+ bold: sel,
98972
+ children: pat.padEnd(16).substring(0, 16)
98973
+ }, undefined, false, undefined, this),
98974
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98975
+ fg: C2.dim,
98976
+ children: " \u2192 "
98977
+ }, undefined, false, undefined, this),
98978
+ chain.map((p, i) => /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98979
+ children: [
98980
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98981
+ fg: sel ? C2.cyan : C2.dim,
98982
+ children: p
98983
+ }, undefined, false, undefined, this),
98984
+ i < chain.length - 1 && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98985
+ fg: C2.dim,
98986
+ children: " \u2192 "
98987
+ }, undefined, false, undefined, this)
98988
+ ]
98989
+ }, p, true, undefined, this))
98990
+ ]
98991
+ }, undefined, true, undefined, this)
98992
+ }, pat, false, undefined, this);
98993
+ })
98994
+ ]
98995
+ }, undefined, true, undefined, this),
98996
+ mode === "add_routing_pattern" && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
98997
+ flexDirection: "column",
98998
+ children: [
98999
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
98495
99000
  children: [
98496
99001
  /* @__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)
99002
+ fg: C2.blue,
99003
+ bold: true,
99004
+ children: "Pattern "
98499
99005
  }, undefined, false, undefined, this),
98500
99006
  /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98501
99007
  fg: C2.dim,
98502
- children: [
98503
- " (",
98504
- itm.eSrc,
98505
- ")"
98506
- ]
98507
- }, undefined, true, undefined, this)
99008
+ children: "(e.g. kimi-*, gpt-4o):"
99009
+ }, undefined, false, undefined, this)
98508
99010
  ]
98509
- }, undefined, true, undefined, this) : /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98510
- fg: C2.dim,
98511
- children: " default target"
99011
+ }, undefined, true, undefined, this),
99012
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
99013
+ flexDirection: "row",
99014
+ children: [
99015
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
99016
+ children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99017
+ fg: C2.green,
99018
+ bold: true,
99019
+ children: "> "
99020
+ }, undefined, false, undefined, this)
99021
+ }, undefined, false, undefined, this),
99022
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("input", {
99023
+ value: routingPattern,
99024
+ onChange: setRoutingPattern,
99025
+ focused: true,
99026
+ width: width - 8,
99027
+ backgroundColor: C2.bgHighlight,
99028
+ textColor: C2.white
99029
+ }, undefined, false, undefined, this)
99030
+ ]
99031
+ }, undefined, true, undefined, this),
99032
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
99033
+ children: [
99034
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99035
+ fg: C2.green,
99036
+ bold: true,
99037
+ children: "Enter "
99038
+ }, undefined, false, undefined, this),
99039
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99040
+ fg: C2.fgMuted,
99041
+ children: "to continue \xB7 "
99042
+ }, undefined, false, undefined, this),
99043
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99044
+ fg: C2.red,
99045
+ bold: true,
99046
+ children: "Esc "
99047
+ }, undefined, false, undefined, this),
99048
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99049
+ fg: C2.fgMuted,
99050
+ children: "to cancel"
99051
+ }, undefined, false, undefined, this)
99052
+ ]
99053
+ }, undefined, true, undefined, this)
99054
+ ]
99055
+ }, undefined, true, undefined, this),
99056
+ mode === "add_routing_chain" && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
99057
+ flexDirection: "column",
99058
+ children: [
99059
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
99060
+ children: [
99061
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99062
+ fg: C2.blue,
99063
+ bold: true,
99064
+ children: "Chain for "
99065
+ }, undefined, false, undefined, this),
99066
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99067
+ fg: C2.white,
99068
+ bold: true,
99069
+ children: routingPattern
99070
+ }, undefined, false, undefined, this),
99071
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99072
+ fg: C2.dim,
99073
+ children: " (comma-separated providers):"
99074
+ }, undefined, false, undefined, this)
99075
+ ]
99076
+ }, undefined, true, undefined, this),
99077
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
99078
+ flexDirection: "row",
99079
+ children: [
99080
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
99081
+ children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99082
+ fg: C2.green,
99083
+ bold: true,
99084
+ children: "> "
99085
+ }, undefined, false, undefined, this)
99086
+ }, undefined, false, undefined, this),
99087
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("input", {
99088
+ value: routingChain,
99089
+ onChange: setRoutingChain,
99090
+ focused: true,
99091
+ width: width - 8,
99092
+ backgroundColor: C2.bgHighlight,
99093
+ textColor: C2.white
99094
+ }, undefined, false, undefined, this)
99095
+ ]
99096
+ }, undefined, true, undefined, this),
99097
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
99098
+ children: [
99099
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99100
+ fg: C2.green,
99101
+ bold: true,
99102
+ children: "Enter "
99103
+ }, undefined, false, undefined, this),
99104
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99105
+ fg: C2.fgMuted,
99106
+ children: "to save \xB7 "
99107
+ }, undefined, false, undefined, this),
99108
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99109
+ fg: C2.red,
99110
+ bold: true,
99111
+ children: "Esc "
99112
+ }, undefined, false, undefined, this),
99113
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99114
+ fg: C2.fgMuted,
99115
+ children: "to go back"
99116
+ }, undefined, false, undefined, this)
99117
+ ]
99118
+ }, undefined, true, undefined, this)
99119
+ ]
99120
+ }, undefined, true, undefined, this)
99121
+ ]
99122
+ }, undefined, true, undefined, this);
99123
+ }
99124
+ function RoutingDetail() {
99125
+ return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
99126
+ height: DETAIL_H,
99127
+ border: true,
99128
+ borderStyle: "single",
99129
+ borderColor: C2.dim,
99130
+ title: " How Routing Works ",
99131
+ backgroundColor: C2.bgAlt,
99132
+ flexDirection: "column",
99133
+ paddingX: 1,
99134
+ children: [
99135
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
99136
+ children: [
99137
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99138
+ fg: C2.fgMuted,
99139
+ children: "Claudish matches model names against "
99140
+ }, undefined, false, undefined, this),
99141
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99142
+ fg: C2.blue,
99143
+ bold: true,
99144
+ children: "Patterns"
99145
+ }, undefined, false, undefined, this),
99146
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99147
+ fg: C2.fgMuted,
99148
+ children: " (like "
99149
+ }, undefined, false, undefined, this),
99150
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99151
+ fg: C2.white,
99152
+ children: "gpt-*"
99153
+ }, undefined, false, undefined, this),
99154
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99155
+ fg: C2.fgMuted,
99156
+ children: ") and tries providers in the "
99157
+ }, undefined, false, undefined, this),
99158
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99159
+ fg: C2.blue,
99160
+ bold: true,
99161
+ children: "Chain"
99162
+ }, undefined, false, undefined, this),
99163
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99164
+ fg: C2.fgMuted,
99165
+ children: " in order."
98512
99166
  }, undefined, false, undefined, this)
98513
99167
  ]
98514
- }, `sys-${itm?.name}`, true, undefined, this)),
99168
+ }, undefined, true, undefined, this),
98515
99169
  /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
98516
99170
  children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98517
- fg: C2.dim,
98518
- children: " "
99171
+ fg: C2.fgMuted,
99172
+ children: "The first provider that responds successfully is used."
98519
99173
  }, undefined, false, undefined, this)
98520
99174
  }, undefined, false, undefined, this),
98521
99175
  /* @__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", {
98535
99176
  children: [
98536
99177
  /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98537
- fg: C2.fg,
98538
- children: [
98539
- " ",
98540
- pat.padEnd(16),
98541
- " "
98542
- ]
98543
- }, undefined, true, undefined, this),
99178
+ fg: C2.cyan,
99179
+ bold: true,
99180
+ children: ruleEntries.length
99181
+ }, undefined, false, undefined, this),
98544
99182
  /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98545
- fg: C2.yellow,
98546
- children: chain.join(" -> ")
99183
+ fg: C2.fgMuted,
99184
+ children: ` rule${ruleEntries.length !== 1 ? "s" : ""} configured`
98547
99185
  }, undefined, false, undefined, this)
98548
99186
  ]
98549
- }, `rr-${pat}`, true, undefined, this))
99187
+ }, undefined, true, undefined, this)
98550
99188
  ]
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) {
98567
- return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
98568
- 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);
99189
+ }, undefined, true, undefined, this);
98584
99190
  }
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", {
98647
- 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", {
98653
- fg: C2.dim,
98654
- children: "Read-only view. Manage profiles via standard CLI commands:"
98655
- }, 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", {
98659
- fg: C2.dim,
98660
- children: " $ claudish profile add/edit"
98661
- }, 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", {
99191
+ function PrivacyContent() {
99192
+ const halfW = Math.floor((width - 4) / 2);
99193
+ const cardH = Math.max(7, contentH - 1);
99194
+ return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
99195
+ height: contentH,
99196
+ flexDirection: "row",
99197
+ backgroundColor: C2.bg,
99198
+ paddingX: 1,
99199
+ children: [
99200
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
99201
+ width: halfW,
99202
+ height: cardH,
99203
+ border: true,
99204
+ borderStyle: "single",
99205
+ borderColor: activeTab === "privacy" ? C2.blue : C2.dim,
99206
+ title: " Telemetry ",
99207
+ backgroundColor: C2.bg,
99208
+ flexDirection: "column",
99209
+ paddingX: 1,
99210
+ children: [
99211
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
99212
+ children: [
99213
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99214
+ fg: C2.blue,
99215
+ bold: true,
99216
+ children: "Status: "
99217
+ }, undefined, false, undefined, this),
99218
+ telemetryEnabled ? /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
98849
99219
  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"
99220
+ bold: true,
99221
+ children: "\u25CF Enabled"
99222
+ }, undefined, false, undefined, this) : /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99223
+ fg: C2.fgMuted,
99224
+ children: "\u25CB Disabled"
98857
99225
  }, undefined, false, undefined, this)
99226
+ ]
99227
+ }, undefined, true, undefined, this),
99228
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
99229
+ children: " "
99230
+ }, undefined, false, undefined, this),
99231
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
99232
+ children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99233
+ fg: C2.fgMuted,
99234
+ children: "Collects anonymized platform info and"
98858
99235
  }, 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
99236
+ }, undefined, false, undefined, this),
99237
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
99238
+ children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99239
+ fg: C2.fgMuted,
99240
+ children: "sanitized error types to improve claudish."
98883
99241
  }, 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"
99242
+ }, undefined, false, undefined, this),
99243
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
99244
+ children: " "
99245
+ }, undefined, false, undefined, this),
99246
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
99247
+ children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99248
+ fg: C2.white,
99249
+ bold: true,
99250
+ children: "Never sends keys, prompts, or paths."
99051
99251
  }, 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,
99252
+ }, undefined, false, undefined, this),
99253
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
99254
+ children: " "
99255
+ }, undefined, false, undefined, this),
99256
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
99057
99257
  children: [
99058
- "Last Prompt: ",
99059
- telemetry?.askedAt || "Never"
99258
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99259
+ fg: C2.dim,
99260
+ children: "Press ["
99261
+ }, undefined, false, undefined, this),
99262
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99263
+ fg: C2.green,
99264
+ bold: true,
99265
+ children: "t"
99266
+ }, undefined, false, undefined, this),
99267
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99268
+ fg: C2.dim,
99269
+ children: "] to toggle."
99270
+ }, undefined, false, undefined, this)
99060
99271
  ]
99061
99272
  }, 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,
99273
+ ]
99274
+ }, undefined, true, undefined, this),
99275
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
99276
+ width: width - 4 - halfW,
99277
+ height: cardH,
99278
+ border: true,
99279
+ borderStyle: "single",
99280
+ borderColor: activeTab === "privacy" ? C2.blue : C2.dim,
99281
+ title: " Usage Stats ",
99282
+ backgroundColor: C2.bg,
99283
+ flexDirection: "column",
99284
+ paddingX: 1,
99285
+ children: [
99286
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
99287
+ children: [
99288
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99289
+ fg: C2.blue,
99290
+ bold: true,
99291
+ children: "Status: "
99292
+ }, undefined, false, undefined, this),
99293
+ statsEnabled2 ? /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99294
+ fg: C2.green,
99295
+ bold: true,
99296
+ children: "\u25CF Enabled"
99297
+ }, undefined, false, undefined, this) : /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99298
+ fg: C2.fgMuted,
99299
+ children: "\u25CB Disabled"
99300
+ }, undefined, false, undefined, this)
99301
+ ]
99302
+ }, undefined, true, undefined, this),
99303
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
99304
+ children: [
99305
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99306
+ fg: C2.blue,
99307
+ bold: true,
99308
+ children: "Buffer: "
99309
+ }, undefined, false, undefined, this),
99310
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99311
+ fg: C2.white,
99312
+ bold: true,
99313
+ children: bufStats.events
99314
+ }, undefined, false, undefined, this),
99315
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99316
+ fg: C2.fgMuted,
99317
+ children: " events ("
99318
+ }, undefined, false, undefined, this),
99319
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99320
+ fg: C2.yellow,
99321
+ children: bytesHuman(bufStats.bytes)
99322
+ }, undefined, false, undefined, this),
99323
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99324
+ fg: C2.fgMuted,
99325
+ children: ")"
99326
+ }, undefined, false, undefined, this)
99327
+ ]
99328
+ }, undefined, true, undefined, this),
99329
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
99066
99330
  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", {
99331
+ }, undefined, false, undefined, this),
99332
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
99071
99333
  children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99072
- fg: C2.cyan,
99073
- children: "Anonymous Payloads ONLY include:"
99334
+ fg: C2.fgMuted,
99335
+ children: "Collects local, anonymous stats on model"
99074
99336
  }, 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,
99337
+ }, undefined, false, undefined, this),
99338
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
99339
+ children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99340
+ fg: C2.fgMuted,
99341
+ children: "usage, latency, and token counts."
99342
+ }, undefined, false, undefined, this)
99343
+ }, undefined, false, undefined, this),
99344
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
99098
99345
  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)
99346
+ }, undefined, false, undefined, this),
99347
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
99348
+ children: [
99349
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99350
+ fg: C2.dim,
99351
+ children: "Press ["
99352
+ }, undefined, false, undefined, this),
99353
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99354
+ fg: C2.green,
99355
+ bold: true,
99356
+ children: "u"
99357
+ }, undefined, false, undefined, this),
99358
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99359
+ fg: C2.dim,
99360
+ children: "] to toggle, ["
99361
+ }, undefined, false, undefined, this),
99362
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99363
+ fg: C2.red,
99364
+ bold: true,
99365
+ children: "c"
99366
+ }, undefined, false, undefined, this),
99367
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99368
+ fg: C2.dim,
99369
+ children: "] to clear buffer."
99370
+ }, undefined, false, undefined, this)
99371
+ ]
99372
+ }, undefined, true, undefined, this)
99373
+ ]
99374
+ }, undefined, true, undefined, this)
99375
+ ]
99376
+ }, undefined, true, undefined, this);
99377
+ }
99378
+ function PrivacyDetail() {
99379
+ return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
99380
+ height: DETAIL_H,
99381
+ border: true,
99382
+ borderStyle: "single",
99383
+ borderColor: C2.dim,
99384
+ title: " Your Privacy ",
99385
+ backgroundColor: C2.bgAlt,
99386
+ flexDirection: "column",
99387
+ paddingX: 1,
99388
+ children: [
99389
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
99390
+ children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99391
+ fg: C2.fgMuted,
99392
+ children: "Telemetry and usage stats are always opt-in and never send personally identifiable data."
99112
99393
  }, 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");
99394
+ }, undefined, false, undefined, this),
99395
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
99396
+ children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99397
+ fg: C2.fgMuted,
99398
+ children: "All data is anonymized before transmission. You can disable either independently."
99399
+ }, undefined, false, undefined, this)
99400
+ }, undefined, false, undefined, this)
99401
+ ]
99402
+ }, undefined, true, undefined, this);
99403
+ }
99404
+ function Footer() {
99405
+ let keys;
99406
+ if (activeTab === "providers") {
99407
+ keys = [
99408
+ [C2.blue, "\u2191\u2193", "navigate"],
99409
+ [C2.green, "s", "set key"],
99410
+ [C2.green, "e", "endpoint"],
99411
+ [C2.red, "x", "remove"],
99412
+ [C2.blue, "Tab", "section"],
99413
+ [C2.dim, "q", "quit"]
99414
+ ];
99415
+ } else if (activeTab === "routing") {
99416
+ keys = [
99417
+ [C2.blue, "\u2191\u2193", "navigate"],
99418
+ [C2.green, "a", "add rule"],
99419
+ [C2.red, "d", "delete"],
99420
+ [C2.blue, "Tab", "section"],
99421
+ [C2.dim, "q", "quit"]
99422
+ ];
99423
+ } else {
99424
+ keys = [
99425
+ [C2.green, "t", "telemetry"],
99426
+ [C2.green, "u", "stats"],
99427
+ [C2.red, "c", "clear"],
99428
+ [C2.blue, "Tab", "section"],
99429
+ [C2.dim, "q", "quit"]
99430
+ ];
99154
99431
  }
99155
- }, []);
99156
- if (height2 < 15 || width < 60) {
99157
99432
  return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
99158
- width: "100%",
99159
- height: "100%",
99160
- padding: 1,
99161
- backgroundColor: C2.bg,
99433
+ height: FOOTER_H,
99434
+ flexDirection: "row",
99435
+ paddingX: 1,
99436
+ backgroundColor: C2.bgAlt,
99162
99437
  children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
99163
- children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99164
- fg: C2.red,
99438
+ children: keys.map(([color, key, label], i) => /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99165
99439
  children: [
99166
- "Terminal too small (",
99167
- width,
99168
- "x",
99169
- height2,
99170
- "). Resize to at least 60x15."
99440
+ i > 0 && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99441
+ children: " "
99442
+ }, undefined, false, undefined, this),
99443
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99444
+ fg: C2.black,
99445
+ backgroundColor: color,
99446
+ bold: true,
99447
+ children: ` ${key} `
99448
+ }, undefined, false, undefined, this),
99449
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99450
+ fg: C2.white,
99451
+ children: ` ${label}`
99452
+ }, undefined, false, undefined, this)
99171
99453
  ]
99172
- }, undefined, true, undefined, this)
99454
+ }, i, true, undefined, this))
99173
99455
  }, undefined, false, undefined, this)
99174
99456
  }, undefined, false, undefined, this);
99175
99457
  }
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
99458
  return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
99190
99459
  width,
99191
99460
  height: height2,
@@ -99193,181 +99462,90 @@ function App() {
99193
99462
  backgroundColor: C2.bg,
99194
99463
  children: [
99195
99464
  /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
99196
- height: 1,
99465
+ height: HEADER_H,
99197
99466
  flexDirection: "row",
99198
- paddingX: 2,
99199
99467
  backgroundColor: C2.bgAlt,
99468
+ paddingX: 1,
99200
99469
  children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
99201
99470
  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
99471
  /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99209
- fg: C2.bgAlt,
99210
- children: headerPad
99472
+ fg: C2.white,
99473
+ bold: true,
99474
+ children: "claudish"
99211
99475
  }, undefined, false, undefined, this),
99212
99476
  /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99213
99477
  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: [
99478
+ children: " \u2500 "
99479
+ }, undefined, false, undefined, this),
99273
99480
  /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99274
- fg: C2.cyan,
99275
- children: "Tab"
99481
+ fg: C2.blue,
99482
+ bold: true,
99483
+ children: VERSION2
99276
99484
  }, undefined, false, undefined, this),
99277
99485
  /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99278
99486
  fg: C2.dim,
99279
- children: " switch \u2502 "
99487
+ children: " \u2500 "
99280
99488
  }, undefined, false, undefined, this),
99281
99489
  /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99282
- fg: C2.cyan,
99283
- children: "\u2191\u2193"
99284
- }, undefined, false, undefined, this),
99490
+ fg: C2.orange,
99491
+ bold: true,
99492
+ children: [
99493
+ "\u2605 ",
99494
+ profileName
99495
+ ]
99496
+ }, undefined, true, undefined, this),
99285
99497
  /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99286
99498
  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"
99499
+ children: " \u2500 "
99292
99500
  }, undefined, false, undefined, this),
99293
99501
  /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99294
- fg: C2.dim,
99295
- children: " configure/select \u2502 "
99502
+ fg: C2.green,
99503
+ bold: true,
99504
+ children: readyCount
99296
99505
  }, undefined, false, undefined, this),
99297
99506
  /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99298
- fg: C2.cyan,
99299
- children: "Esc/q"
99507
+ fg: C2.fgMuted,
99508
+ children: " providers configured"
99300
99509
  }, undefined, false, undefined, this),
99301
99510
  /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
99302
99511
  fg: C2.dim,
99303
- children: " back/quit"
99512
+ children: "\u2500".repeat(Math.max(1, width - 38 - profileName.length - VERSION2.length))
99304
99513
  }, undefined, false, undefined, this)
99305
99514
  ]
99306
99515
  }, undefined, true, undefined, this)
99307
- }, undefined, false, undefined, this)
99516
+ }, undefined, false, undefined, this),
99517
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(TabBar, {}, undefined, false, undefined, this),
99518
+ activeTab === "providers" && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(import_jsx_dev_runtime2.Fragment, {
99519
+ children: [
99520
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(ProvidersContent, {}, undefined, false, undefined, this),
99521
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(ProviderDetail, {}, undefined, false, undefined, this)
99522
+ ]
99523
+ }, undefined, true, undefined, this),
99524
+ activeTab === "routing" && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(import_jsx_dev_runtime2.Fragment, {
99525
+ children: [
99526
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(RoutingContent, {}, undefined, false, undefined, this),
99527
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(RoutingDetail, {}, undefined, false, undefined, this)
99528
+ ]
99529
+ }, undefined, true, undefined, this),
99530
+ activeTab === "privacy" && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(import_jsx_dev_runtime2.Fragment, {
99531
+ children: [
99532
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(PrivacyContent, {}, undefined, false, undefined, this),
99533
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(PrivacyDetail, {}, undefined, false, undefined, this)
99534
+ ]
99535
+ }, undefined, true, undefined, this),
99536
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(Footer, {}, undefined, false, undefined, this)
99308
99537
  ]
99309
99538
  }, undefined, true, undefined, this);
99310
99539
  }
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;
99540
+ var import_react13, VERSION2 = "v5.16";
99350
99541
  var init_App = __esm(async () => {
99351
99542
  init_profile_config();
99352
- init_ConfigViewPanel();
99353
- init_ProfilesPanel();
99354
- init_ProvidersPanel();
99355
- init_TelemetryPanel();
99543
+ init_stats_buffer();
99544
+ init_providers();
99356
99545
  init_theme2();
99357
99546
  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
- ];
99547
+ await init_react();
99548
+ import_react13 = __toESM(require_react(), 1);
99371
99549
  });
99372
99550
 
99373
99551
  // src/tui/index.tsx
@@ -99692,7 +99870,7 @@ function mergeUserSettingsIfPresent(config3, tempSettingsPath, statusLine) {
99692
99870
  }
99693
99871
  config3.claudeArgs.splice(idx, 2);
99694
99872
  }
99695
- async function runClaudeWithProxy(config3, proxyUrl, onCleanup) {
99873
+ async function runClaudeWithProxy(config3, proxyUrl, onCleanup, ptyDiagRunner) {
99696
99874
  const hasProfileMappings = config3.modelOpus || config3.modelSonnet || config3.modelHaiku || config3.modelSubagent;
99697
99875
  const modelId = config3.model || (hasProfileMappings || config3.monitor ? undefined : "unknown");
99698
99876
  const portMatch = proxyUrl.match(/:(\d+)/);
@@ -99779,20 +99957,28 @@ Or set CLAUDE_PATH to your custom installation:`);
99779
99957
  }
99780
99958
  const needsShell = isWindows2() && claudeBinary.endsWith(".cmd");
99781
99959
  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);
99960
+ let exitCode;
99961
+ if (config3.interactive && ptyDiagRunner) {
99962
+ exitCode = await ptyDiagRunner.run(spawnCommand, claudeArgs, env2);
99963
+ try {
99964
+ unlinkSync7(tempSettingsPath);
99965
+ } catch {}
99966
+ } else {
99967
+ const proc = spawn2(spawnCommand, claudeArgs, {
99968
+ env: env2,
99969
+ stdio: "inherit",
99970
+ shell: needsShell
99791
99971
  });
99792
- });
99793
- try {
99794
- unlinkSync7(tempSettingsPath);
99795
- } catch (error46) {}
99972
+ setupSignalHandlers(proc, tempSettingsPath, config3.quiet, onCleanup);
99973
+ exitCode = await new Promise((resolve4) => {
99974
+ proc.on("exit", (code) => {
99975
+ resolve4(code ?? 1);
99976
+ });
99977
+ });
99978
+ try {
99979
+ unlinkSync7(tempSettingsPath);
99980
+ } catch {}
99981
+ }
99796
99982
  return exitCode;
99797
99983
  }
99798
99984
  function setupSignalHandlers(proc, tempSettingsPath, quiet, onCleanup) {
@@ -99897,6 +100083,7 @@ var exports_diag_output = {};
99897
100083
  __export(exports_diag_output, {
99898
100084
  createDiagOutput: () => createDiagOutput,
99899
100085
  TmuxDiagOutput: () => TmuxDiagOutput,
100086
+ OpentUiDiagOutput: () => OpentUiDiagOutput,
99900
100087
  NullDiagOutput: () => NullDiagOutput,
99901
100088
  LogFileDiagOutput: () => LogFileDiagOutput
99902
100089
  });
@@ -99948,6 +100135,25 @@ class LogFileDiagOutput {
99948
100135
  }
99949
100136
  }
99950
100137
 
100138
+ class OpentUiDiagOutput {
100139
+ runner;
100140
+ messages = [];
100141
+ constructor(runner) {
100142
+ this.runner = runner;
100143
+ }
100144
+ write(msg) {
100145
+ const level = msg.toLowerCase().includes("error") ? "error" : msg.toLowerCase().includes("warn") ? "warn" : "info";
100146
+ this.messages.push({ text: msg, level });
100147
+ if (this.messages.length > 4) {
100148
+ this.messages = this.messages.slice(-4);
100149
+ }
100150
+ this.runner.showDiag(this.messages);
100151
+ }
100152
+ cleanup() {
100153
+ this.runner.hideDiag();
100154
+ }
100155
+ }
100156
+
99951
100157
  class NullDiagOutput {
99952
100158
  write(_msg) {}
99953
100159
  cleanup() {}
@@ -99956,8 +100162,25 @@ function createDiagOutput(options) {
99956
100162
  if (!options.interactive) {
99957
100163
  return new NullDiagOutput;
99958
100164
  }
99959
- if (process.env.TMUX) {
99960
- return new TmuxDiagOutput;
100165
+ const mode = options.diagMode || "auto";
100166
+ if (mode === "off") {
100167
+ return new NullDiagOutput;
100168
+ }
100169
+ if (mode === "pty" || mode === "auto") {
100170
+ if (options.ptyRunner) {
100171
+ return new OpentUiDiagOutput(options.ptyRunner);
100172
+ }
100173
+ if (mode === "pty") {
100174
+ return new LogFileDiagOutput;
100175
+ }
100176
+ }
100177
+ if (mode === "tmux" || mode === "auto") {
100178
+ if (process.env.TMUX) {
100179
+ return new TmuxDiagOutput;
100180
+ }
100181
+ if (mode === "tmux") {
100182
+ return new LogFileDiagOutput;
100183
+ }
99961
100184
  }
99962
100185
  return new LogFileDiagOutput;
99963
100186
  }
@@ -99997,6 +100220,228 @@ var init_diag_output = __esm(() => {
99997
100220
  };
99998
100221
  });
99999
100222
 
100223
+ // src/tui/DiagPanel.tsx
100224
+ function DiagPanel({ messages }) {
100225
+ const { width } = useTerminalDimensions();
100226
+ const panelWidth = Math.max(1, width);
100227
+ const separator = "\u2500".repeat(panelWidth);
100228
+ return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
100229
+ x: 0,
100230
+ y: 0,
100231
+ width: panelWidth,
100232
+ height: 5,
100233
+ backgroundColor: "#1a1a2e",
100234
+ children: [
100235
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
100236
+ x: 0,
100237
+ y: 0,
100238
+ content: separator,
100239
+ color: "#44475a"
100240
+ }, undefined, false, undefined, this),
100241
+ messages.slice(-3).map((msg, i) => {
100242
+ const prefix = LEVEL_PREFIX[msg.level];
100243
+ const color = LEVEL_COLORS[msg.level];
100244
+ const maxTextLen = Math.max(1, panelWidth - prefix.length - 1);
100245
+ const truncated = msg.text.length > maxTextLen ? `${msg.text.slice(0, maxTextLen - 1)}\u2026` : msg.text;
100246
+ return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
100247
+ x: 0,
100248
+ y: i + 1,
100249
+ content: `${prefix} ${truncated}`,
100250
+ color
100251
+ }, `msg-${i}`, false, undefined, this);
100252
+ }),
100253
+ messages.length < 3 && Array.from({ length: 3 - messages.length }).map((_2, i) => /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
100254
+ x: 0,
100255
+ y: messages.length + i + 1,
100256
+ content: ""
100257
+ }, `empty-${i}`, false, undefined, this)),
100258
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
100259
+ x: 0,
100260
+ y: 4,
100261
+ content: "Press ESC to dismiss",
100262
+ color: "#6272a4"
100263
+ }, undefined, false, undefined, this)
100264
+ ]
100265
+ }, undefined, true, undefined, this);
100266
+ }
100267
+ var LEVEL_COLORS, LEVEL_PREFIX;
100268
+ var init_DiagPanel = __esm(async () => {
100269
+ init_jsx_dev_runtime();
100270
+ await init_react();
100271
+ LEVEL_COLORS = {
100272
+ error: "#ff5555",
100273
+ warn: "#ffb86c",
100274
+ info: "#8be9fd"
100275
+ };
100276
+ LEVEL_PREFIX = {
100277
+ error: "[ERROR]",
100278
+ warn: "[WARN] ",
100279
+ info: "[INFO] "
100280
+ };
100281
+ });
100282
+
100283
+ // src/pty-diag-runner.ts
100284
+ var exports_pty_diag_runner = {};
100285
+ __export(exports_pty_diag_runner, {
100286
+ tryCreatePtyRunner: () => tryCreatePtyRunner,
100287
+ PtyDiagRunner: () => PtyDiagRunner
100288
+ });
100289
+ import { writeSync as writeSync3 } from "fs";
100290
+
100291
+ class PtyDiagRunner {
100292
+ renderer = null;
100293
+ bunProc = null;
100294
+ messages = [];
100295
+ autoHideTimer = null;
100296
+ reactRoot = null;
100297
+ rawStdinHandler = null;
100298
+ async run(command, args, env2) {
100299
+ this.renderer = await createCliRenderer({
100300
+ useAlternateScreen: false,
100301
+ experimental_splitHeight: 0,
100302
+ exitOnCtrlC: false,
100303
+ useMouse: false,
100304
+ useKittyKeyboard: null,
100305
+ targetFps: 10
100306
+ });
100307
+ this.reactRoot = createRoot(this.renderer);
100308
+ this.renderDiagPanel();
100309
+ const cols = process.stdout.columns || 80;
100310
+ const rows = process.stdout.rows || 24;
100311
+ this.bunProc = Bun.spawn([command, ...args], {
100312
+ terminal: {
100313
+ cols,
100314
+ rows,
100315
+ data: (_terminal, data) => {
100316
+ const buf = typeof data === "string" ? Buffer.from(data, "binary") : data;
100317
+ writeSync3(1, buf);
100318
+ }
100319
+ },
100320
+ cwd: process.cwd(),
100321
+ env: env2
100322
+ });
100323
+ await new Promise((resolve4) => setTimeout(resolve4, 500));
100324
+ const isTerminalResponse = (data) => {
100325
+ if (data.startsWith("\x1BP"))
100326
+ return true;
100327
+ if (/^\x1b\[\??[\d;]*[Rcyn]/.test(data))
100328
+ return true;
100329
+ if (/^\x1b\[[\?>][\d;]*c/.test(data))
100330
+ return true;
100331
+ return false;
100332
+ };
100333
+ this.rawStdinHandler = (chunk) => {
100334
+ if (!this.bunProc?.terminal)
100335
+ return;
100336
+ const str = typeof chunk === "string" ? chunk : chunk.toString("binary");
100337
+ if (isTerminalResponse(str))
100338
+ return;
100339
+ this.bunProc.terminal.write(str);
100340
+ };
100341
+ process.stdin.on("data", this.rawStdinHandler);
100342
+ if (this.renderer.prependInputHandler) {
100343
+ this.renderer.prependInputHandler((sequence) => {
100344
+ if (sequence === "\x1B" && this.renderer && this.renderer.experimental_splitHeight > 0) {
100345
+ this.hideDiag();
100346
+ return true;
100347
+ }
100348
+ return false;
100349
+ });
100350
+ }
100351
+ this.renderer.on("resize", () => {
100352
+ if (this.bunProc?.terminal && this.renderer) {
100353
+ const newCols = this.renderer.terminalWidth || process.stdout.columns || 80;
100354
+ const newRows = Math.max(1, (this.renderer.terminalHeight || process.stdout.rows || 24) - this.renderer.experimental_splitHeight);
100355
+ try {
100356
+ this.bunProc.terminal.resize(newCols, newRows);
100357
+ } catch {}
100358
+ }
100359
+ });
100360
+ await this.bunProc.exited;
100361
+ const exitCode = this.bunProc.exitCode ?? 1;
100362
+ this.cleanup();
100363
+ return exitCode;
100364
+ }
100365
+ showDiag(messages) {
100366
+ if (!this.renderer)
100367
+ return;
100368
+ this.messages = messages.slice(-4);
100369
+ this.renderDiagPanel();
100370
+ if (this.renderer.experimental_splitHeight === 0) {
100371
+ this.renderer.experimental_splitHeight = 5;
100372
+ }
100373
+ if (this.autoHideTimer) {
100374
+ clearTimeout(this.autoHideTimer);
100375
+ }
100376
+ this.autoHideTimer = setTimeout(() => {
100377
+ this.hideDiag();
100378
+ }, 1e4);
100379
+ }
100380
+ hideDiag() {
100381
+ if (!this.renderer)
100382
+ return;
100383
+ if (this.autoHideTimer) {
100384
+ clearTimeout(this.autoHideTimer);
100385
+ this.autoHideTimer = null;
100386
+ }
100387
+ this.renderer.experimental_splitHeight = 0;
100388
+ }
100389
+ renderDiagPanel() {
100390
+ if (!this.reactRoot)
100391
+ return;
100392
+ this.reactRoot.render(import_react17.createElement(DiagPanel, { messages: this.messages }));
100393
+ }
100394
+ cleanup() {
100395
+ if (this.autoHideTimer) {
100396
+ clearTimeout(this.autoHideTimer);
100397
+ this.autoHideTimer = null;
100398
+ }
100399
+ if (this.rawStdinHandler) {
100400
+ process.stdin.removeListener("data", this.rawStdinHandler);
100401
+ this.rawStdinHandler = null;
100402
+ }
100403
+ if (this.bunProc) {
100404
+ try {
100405
+ this.bunProc.kill();
100406
+ } catch {}
100407
+ if (this.bunProc.terminal) {
100408
+ try {
100409
+ this.bunProc.terminal.close();
100410
+ } catch {}
100411
+ }
100412
+ this.bunProc = null;
100413
+ }
100414
+ if (this.renderer && !this.renderer.isDestroyed) {
100415
+ try {
100416
+ this.renderer.destroy();
100417
+ } catch {}
100418
+ this.renderer = null;
100419
+ }
100420
+ }
100421
+ }
100422
+ async function tryCreatePtyRunner() {
100423
+ try {
100424
+ if (typeof Bun === "undefined")
100425
+ return null;
100426
+ const test = Bun.spawn(["true"], {
100427
+ terminal: { cols: 1, rows: 1 }
100428
+ });
100429
+ await test.exited;
100430
+ return new PtyDiagRunner;
100431
+ } catch {
100432
+ return null;
100433
+ }
100434
+ }
100435
+ var import_react17;
100436
+ var init_pty_diag_runner = __esm(async () => {
100437
+ await __promiseAll([
100438
+ init_core3(),
100439
+ init_react(),
100440
+ init_DiagPanel()
100441
+ ]);
100442
+ import_react17 = __toESM(require_react(), 1);
100443
+ });
100444
+
100000
100445
  // src/port-manager.ts
100001
100446
  var exports_port_manager = {};
100002
100447
  __export(exports_port_manager, {
@@ -107038,6 +107483,7 @@ async function runCli() {
107038
107483
  } = await Promise.resolve().then(() => (init_provider_resolver(), exports_provider_resolver));
107039
107484
  const { initLogger: initLogger2, getLogFilePath: getLogFilePath2, getAlwaysOnLogPath: getAlwaysOnLogPath2, setDiagOutput: setDiagOutput2 } = await Promise.resolve().then(() => (init_logger(), exports_logger));
107040
107485
  const { createDiagOutput: createDiagOutput2, LogFileDiagOutput: LogFileDiagOutput2 } = await Promise.resolve().then(() => (init_diag_output(), exports_diag_output));
107486
+ const { tryCreatePtyRunner: tryCreatePtyRunner2 } = await init_pty_diag_runner().then(() => exports_pty_diag_runner);
107041
107487
  const { findAvailablePort: findAvailablePort2 } = await Promise.resolve().then(() => (init_port_manager(), exports_port_manager));
107042
107488
  const { createProxyServer: createProxyServer2 } = await Promise.resolve().then(() => (init_proxy_server(), exports_proxy_server));
107043
107489
  const { checkForUpdates: checkForUpdates2 } = await Promise.resolve().then(() => (init_update_checker(), exports_update_checker));
@@ -107155,16 +107601,22 @@ async function runCli() {
107155
107601
  quiet: cliConfig.quiet,
107156
107602
  isInteractive: cliConfig.interactive
107157
107603
  });
107158
- const diag = createDiagOutput2({ interactive: cliConfig.interactive });
107604
+ const needsPty = cliConfig.interactive && (cliConfig.diagMode === "auto" || cliConfig.diagMode === "pty");
107605
+ const ptyRunner = needsPty ? await tryCreatePtyRunner2() : null;
107606
+ const diag = createDiagOutput2({
107607
+ interactive: cliConfig.interactive,
107608
+ ptyRunner,
107609
+ diagMode: cliConfig.diagMode
107610
+ });
107159
107611
  if (cliConfig.interactive) {
107160
107612
  setDiagOutput2(diag);
107161
- if (!process.env.TMUX && !cliConfig.quiet && diag instanceof LogFileDiagOutput2) {
107613
+ if (!ptyRunner && !process.env.TMUX && !cliConfig.quiet && diag instanceof LogFileDiagOutput2) {
107162
107614
  console.log(`[claudish] Diagnostic log: ${diag.getLogPath()}`);
107163
107615
  }
107164
107616
  }
107165
107617
  let exitCode = 0;
107166
107618
  try {
107167
- exitCode = await runClaudeWithProxy2(cliConfig, proxy.url, () => diag.cleanup());
107619
+ exitCode = await runClaudeWithProxy2(cliConfig, proxy.url, () => diag.cleanup(), ptyRunner);
107168
107620
  } finally {
107169
107621
  setDiagOutput2(null);
107170
107622
  diag.cleanup();