@triedotdev/mcp 1.0.135 → 1.0.136

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.
@@ -133,7 +133,7 @@ var HypothesisEngine = class {
133
133
  * This enables fully agentic hypothesis creation based on actual codebase observations
134
134
  */
135
135
  async generateHypothesesWithAI(context) {
136
- const { isAIAvailable, runAIAnalysis } = await import("./client-OVI6TBX7.js");
136
+ const { isAIAvailable, runAIAnalysis } = await import("./client-BZHI675W.js");
137
137
  if (!isAIAvailable()) {
138
138
  return [];
139
139
  }
@@ -718,4 +718,4 @@ export {
718
718
  clearHypothesisEngines,
719
719
  gatherEvidenceForHypothesis
720
720
  };
721
- //# sourceMappingURL=chunk-LRQV7SGQ.js.map
721
+ //# sourceMappingURL=chunk-AJ34GCMD.js.map
@@ -3,7 +3,7 @@ import {
3
3
  } from "./chunk-T4THB2OR.js";
4
4
  import {
5
5
  getHypothesisEngine
6
- } from "./chunk-LRQV7SGQ.js";
6
+ } from "./chunk-AJ34GCMD.js";
7
7
  import {
8
8
  getInsightStore
9
9
  } from "./chunk-4YJ6KLGI.js";
@@ -11,11 +11,11 @@ import {
11
11
  GotchaPredictor,
12
12
  findCrossProjectPatterns,
13
13
  recordToGlobalMemory
14
- } from "./chunk-3DPVJQNM.js";
14
+ } from "./chunk-UHX4462X.js";
15
15
  import {
16
16
  isAIAvailable,
17
17
  runAIAnalysis
18
- } from "./chunk-JCU6REX7.js";
18
+ } from "./chunk-O6OTJI3W.js";
19
19
  import {
20
20
  autoResolveIssues,
21
21
  getHistoricalInsights,
@@ -2143,4 +2143,4 @@ export {
2143
2143
  GuardianAgent,
2144
2144
  getGuardian
2145
2145
  };
2146
- //# sourceMappingURL=chunk-T62V4H5O.js.map
2146
+ //# sourceMappingURL=chunk-G5PRBQIQ.js.map
@@ -264,6 +264,7 @@ async function runAIWithTools(request) {
264
264
  const maxRounds = request.maxToolRounds ?? 5;
265
265
  const messages = [...request.messages];
266
266
  const allToolCalls = [];
267
+ const allToolResults = [];
267
268
  const { onProgress } = request;
268
269
  try {
269
270
  for (let round = 0; round < maxRounds; round++) {
@@ -287,14 +288,16 @@ async function runAIWithTools(request) {
287
288
  success: true,
288
289
  content: textBlocks.map((b) => b.text).join("\n")
289
290
  };
290
- if (allToolCalls.length > 0) result2.toolCalls = allToolCalls;
291
+ if (allToolCalls.length > 0) {
292
+ result2.toolCalls = allToolCalls;
293
+ result2.toolResults = allToolResults;
294
+ }
291
295
  return result2;
292
296
  }
293
297
  messages.push({ role: "assistant", content: response.content });
294
298
  const toolResults = [];
295
299
  for (const block of toolUseBlocks) {
296
300
  const input = block.input ?? {};
297
- allToolCalls.push({ id: block.id, name: block.name, input });
298
301
  const toolLabel = block.name.replace(/^trie_/, "").replace(/_/g, " ");
299
302
  onProgress?.(`Running ${toolLabel}...`);
300
303
  let resultText;
@@ -305,6 +308,8 @@ async function runAIWithTools(request) {
305
308
  resultText = `Tool error: ${err instanceof Error ? err.message : String(err)}`;
306
309
  isError = true;
307
310
  }
311
+ allToolCalls.push({ name: block.name, input, result: resultText });
312
+ allToolResults.push(resultText);
308
313
  toolResults.push({
309
314
  type: "tool_result",
310
315
  tool_use_id: block.id,
@@ -316,12 +321,18 @@ async function runAIWithTools(request) {
316
321
  if (response.stop_reason === "end_turn") {
317
322
  const text = textBlocks.map((b) => b.text).join("\n");
318
323
  const result2 = { success: true, content: text || "Done." };
319
- if (allToolCalls.length > 0) result2.toolCalls = allToolCalls;
324
+ if (allToolCalls.length > 0) {
325
+ result2.toolCalls = allToolCalls;
326
+ result2.toolResults = allToolResults;
327
+ }
320
328
  return result2;
321
329
  }
322
330
  }
323
331
  const result = { success: true, content: "Reached maximum tool rounds." };
324
- if (allToolCalls.length > 0) result.toolCalls = allToolCalls;
332
+ if (allToolCalls.length > 0) {
333
+ result.toolCalls = allToolCalls;
334
+ result.toolResults = allToolResults;
335
+ }
325
336
  return result;
326
337
  } catch (error) {
327
338
  const errorMessage = error instanceof Error ? error.message : String(error);
@@ -341,4 +352,4 @@ export {
341
352
  getAIStatusMessage,
342
353
  runAIWithTools
343
354
  };
344
- //# sourceMappingURL=chunk-JCU6REX7.js.map
355
+ //# sourceMappingURL=chunk-O6OTJI3W.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/ai/client.ts"],"sourcesContent":["/**\n * Centralized AI Client\n * \n * Handles API key detection, graceful fallbacks, and AI-powered analysis.\n * All agents use this for AI-enhanced analysis.\n * \n * API Key Setup:\n * 1. Set ANTHROPIC_API_KEY in your environment\n * 2. Or add it to your MCP server config (mcp.json)\n * 3. Or create .env file in your project root\n * \n * If no API key is found, agents fall back to pattern-only mode.\n */\n\nimport Anthropic from '@anthropic-ai/sdk';\nimport { readFileSync, writeFileSync, mkdirSync, existsSync } from 'fs';\nimport { execSync } from 'node:child_process';\nimport { join } from 'path';\nimport { getWorkingDirectory, getTrieDirectory } from '../utils/workspace.js';\n\n// Cached client instance\nlet clientInstance: Anthropic | null = null;\nlet apiKeyChecked = false;\nlet apiKeyAvailable = false;\n\n/**\n * Check if AI is available (API key is set)\n */\nexport function isAIAvailable(): boolean {\n if (!apiKeyChecked) {\n checkAPIKey();\n }\n return apiKeyAvailable;\n}\n\n/**\n * Read API key from Apple Keychain (macOS only)\n */\nexport function getKeyFromKeychain(): string | null {\n if (process.platform !== 'darwin') return null;\n try {\n const result = execSync(\n 'security find-generic-password -a \"trie\" -s \"anthropic-api-key\" -w 2>/dev/null',\n { encoding: 'utf-8' }\n ).trim();\n return result.length > 10 ? result : null;\n } catch { return null; }\n}\n\n/**\n * Save API key to Apple Keychain (macOS only)\n */\nexport function saveKeyToKeychain(key: string): boolean {\n if (process.platform !== 'darwin') return false;\n try {\n try { execSync('security delete-generic-password -a \"trie\" -s \"anthropic-api-key\" 2>/dev/null'); } catch { /* not found */ }\n execSync(`security add-generic-password -a \"trie\" -s \"anthropic-api-key\" -w \"${key.replace(/\"/g, '\\\\\"')}\"`);\n return true;\n } catch { return false; }\n}\n\n/**\n * Save API key and refresh the cached state\n */\nexport function setAPIKey(key: string): { saved: boolean; method: 'keychain' | 'config' } {\n process.env.ANTHROPIC_API_KEY = key;\n clientInstance = null;\n apiKeyChecked = true;\n apiKeyAvailable = true;\n\n if (saveKeyToKeychain(key)) {\n return { saved: true, method: 'keychain' };\n }\n\n try {\n const workDir = getWorkingDirectory(undefined, true);\n const trieDir = getTrieDirectory(workDir);\n const configPath = join(trieDir, 'config.json');\n let config: Record<string, unknown> = {};\n if (existsSync(configPath)) {\n config = JSON.parse(readFileSync(configPath, 'utf-8'));\n }\n if (!config.apiKeys || typeof config.apiKeys !== 'object') config.apiKeys = {};\n (config.apiKeys as Record<string, string>).anthropic = key;\n mkdirSync(trieDir, { recursive: true });\n writeFileSync(configPath, JSON.stringify(config, null, 2));\n } catch { /* best effort */ }\n\n return { saved: true, method: 'config' };\n}\n\n/**\n * Check for API key in environment, keychain, config, and .env files\n */\nfunction checkAPIKey(): void {\n apiKeyChecked = true;\n \n // 1. Check standard env var first\n const envApiKey = process.env.ANTHROPIC_API_KEY;\n if (envApiKey && envApiKey.length > 10) {\n apiKeyAvailable = true;\n return;\n }\n\n // 2. Check Apple Keychain (macOS)\n const keychainKey = getKeyFromKeychain();\n if (keychainKey) {\n process.env.ANTHROPIC_API_KEY = keychainKey;\n apiKeyAvailable = true;\n return;\n }\n \n // 3. Check config file\n try {\n const workDir = getWorkingDirectory(undefined, true);\n const configPath = join(getTrieDirectory(workDir), 'config.json');\n \n if (existsSync(configPath)) {\n const configContent = readFileSync(configPath, 'utf-8');\n const config = JSON.parse(configContent);\n \n if (config.apiKeys?.anthropic && config.apiKeys.anthropic.length > 10) {\n process.env.ANTHROPIC_API_KEY = config.apiKeys.anthropic;\n apiKeyAvailable = true;\n return;\n }\n }\n } catch {\n // Config file doesn't exist or couldn't be read\n }\n \n // 4. Check .env files\n try {\n const workDir = getWorkingDirectory(undefined, true);\n const envFiles = ['.env', '.env.local', '.env.production'];\n \n for (const envFile of envFiles) {\n const envPath = join(workDir, envFile);\n if (existsSync(envPath)) {\n const envContent = readFileSync(envPath, 'utf-8');\n const lines = envContent.split('\\n');\n \n for (const line of lines) {\n const match = line.match(/^\\s*ANTHROPIC_API_KEY\\s*=\\s*(.+)$/);\n if (match && match[1]) {\n const key = match[1].trim().replace(/^[\"']|[\"']$/g, '');\n if (key.length > 10) {\n process.env.ANTHROPIC_API_KEY = key;\n apiKeyAvailable = true;\n return;\n }\n }\n }\n }\n }\n } catch {\n // .env file doesn't exist or couldn't be read\n }\n \n apiKeyAvailable = false;\n}\n\n/**\n * Get the Anthropic client (lazy initialized)\n * Throws if API key is not available\n */\nexport function getClient(): Anthropic {\n if (!isAIAvailable()) {\n throw new Error(\n 'ANTHROPIC_API_KEY not found. Set it in your environment to enable AI-powered analysis.\\n' +\n 'Example: export ANTHROPIC_API_KEY=sk-ant-...'\n );\n }\n \n if (!clientInstance) {\n clientInstance = new Anthropic();\n }\n \n return clientInstance;\n}\n\n/**\n * Try to get client, return null if not available\n */\nexport function tryGetClient(): Anthropic | null {\n if (!isAIAvailable()) {\n return null;\n }\n \n if (!clientInstance) {\n clientInstance = new Anthropic();\n }\n \n return clientInstance;\n}\n\nexport interface AIAnalysisRequest {\n systemPrompt: string;\n userPrompt: string;\n maxTokens?: number;\n temperature?: number;\n}\n\nexport interface AIAnalysisResult {\n success: boolean;\n content: string;\n error?: string;\n tokensUsed?: {\n input: number;\n output: number;\n };\n}\n\n/**\n * Run AI analysis with the given prompts\n */\nexport async function runAIAnalysis(request: AIAnalysisRequest): Promise<AIAnalysisResult> {\n const client = tryGetClient();\n \n if (!client) {\n return {\n success: false,\n content: '',\n error: 'AI not available - ANTHROPIC_API_KEY not set'\n };\n }\n \n try {\n const response = await client.messages.create({\n model: 'claude-sonnet-4-20250514',\n max_tokens: request.maxTokens || 4096,\n temperature: request.temperature ?? 0.3,\n system: request.systemPrompt,\n messages: [\n {\n role: 'user',\n content: request.userPrompt\n }\n ]\n });\n \n // Extract text content\n const textContent = response.content\n .filter((block): block is Anthropic.TextBlock => block.type === 'text')\n .map(block => block.text)\n .join('\\n');\n \n return {\n success: true,\n content: textContent,\n tokensUsed: {\n input: response.usage.input_tokens,\n output: response.usage.output_tokens\n }\n };\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n \n // Check for specific error types\n if (errorMessage.includes('authentication') || errorMessage.includes('API key')) {\n return {\n success: false,\n content: '',\n error: 'Invalid API key. Check your ANTHROPIC_API_KEY.'\n };\n }\n \n if (errorMessage.includes('rate limit')) {\n return {\n success: false,\n content: '',\n error: 'Rate limited. Try again in a moment.'\n };\n }\n \n return {\n success: false,\n content: '',\n error: `AI analysis failed: ${errorMessage}`\n };\n }\n}\n\n/**\n * AI analysis for code issues\n */\nexport interface CodeIssueAnalysisRequest {\n issues: Array<{\n file: string;\n line?: number;\n issue: string;\n code?: string;\n }>;\n analysisType: 'validate' | 'expand' | 'fix' | 'explain';\n context?: string;\n}\n\n/**\n * Run AI analysis on code issues\n * Used by agents to validate, expand, or fix detected issues\n */\nexport async function analyzeCodeIssues(request: CodeIssueAnalysisRequest): Promise<AIAnalysisResult> {\n const systemPrompts: Record<CodeIssueAnalysisRequest['analysisType'], string> = {\n validate: `You are a senior code reviewer. Analyze the following issues detected by static analysis.\nFor each issue:\n1. Determine if it's a TRUE POSITIVE (real problem) or FALSE POSITIVE (not actually an issue)\n2. Provide a confidence score (0-100)\n3. Explain your reasoning briefly\n\nOutput format:\n### Issue 1: [file:line]\n**Verdict:** TRUE_POSITIVE / FALSE_POSITIVE\n**Confidence:** [0-100]\n**Reason:** [one line explanation]\n**Fix:** [specific fix if true positive]`,\n\n expand: `You are a security expert and senior architect. Given these detected code issues, look deeper:\n1. Are there related problems in the same code that were missed?\n2. What's the root cause of these patterns?\n3. What's the blast radius if these issues cause problems?\n4. What architectural changes would prevent these patterns?\n\nBe specific. Reference line numbers. Provide code examples.`,\n\n fix: `You are an expert programmer. For each issue, provide a specific fix:\n1. Show the exact code change needed\n2. Explain why this fix works\n3. Note any edge cases to consider\n\nUse markdown code blocks with the language specified.`,\n\n explain: `You are a patient teacher explaining code issues to a junior developer.\nFor each issue:\n1. Explain what the problem is in simple terms\n2. Explain why it's a problem (what could go wrong)\n3. Explain the fix and why it works\n4. Provide a learning resource if relevant`\n };\n\n const issuesText = request.issues.map((issue, i) => {\n let text = `### Issue ${i + 1}: ${issue.file}${issue.line ? ':' + issue.line : ''}\\n`;\n text += `**Problem:** ${issue.issue}\\n`;\n if (issue.code) {\n text += `**Code:**\\n\\`\\`\\`\\n${issue.code}\\n\\`\\`\\`\\n`;\n }\n return text;\n }).join('\\n');\n\n const userPrompt = `${request.context ? `Context: ${request.context}\\n\\n` : ''}${issuesText}`;\n\n return runAIAnalysis({\n systemPrompt: systemPrompts[request.analysisType],\n userPrompt,\n maxTokens: 4096,\n temperature: 0.2\n });\n}\n\n/**\n * Get status message about AI availability\n */\nexport function getAIStatusMessage(): string {\n if (isAIAvailable()) {\n return '[AI] AI-powered analysis enabled';\n }\n return '[!] AI not available (ANTHROPIC_API_KEY not set) - using pattern-only mode';\n}\n\nexport interface AIToolCallRecord {\n name: string;\n input: Record<string, unknown>;\n}\n\nexport interface AIToolCallResult {\n success: boolean;\n content: string;\n error?: string;\n toolCalls?: AIToolCallRecord[];\n}\n\n/**\n * Run AI analysis with tool-use support.\n * Loops until Claude returns a final text response or hits maxToolRounds.\n */\nexport async function runAIWithTools(request: {\n systemPrompt: string;\n messages: Anthropic.MessageParam[];\n tools: Anthropic.Tool[];\n executeTool: (name: string, input: Record<string, unknown>, onProgress?: (msg: string) => void) => Promise<string>;\n maxTokens?: number;\n maxToolRounds?: number;\n onProgress?: (message: string) => void;\n}): Promise<AIToolCallResult> {\n const client = tryGetClient();\n if (!client) {\n return { success: false, content: '', error: 'AI not available - ANTHROPIC_API_KEY not set' };\n }\n\n const maxRounds = request.maxToolRounds ?? 5;\n const messages: Anthropic.MessageParam[] = [...request.messages];\n const allToolCalls: AIToolCallRecord[] = [];\n\n const { onProgress } = request;\n\n try {\n for (let round = 0; round < maxRounds; round++) {\n onProgress?.(round === 0 ? 'Analyzing...' : `Processing (round ${round + 1})...`);\n const response = await client.messages.create({\n model: 'claude-sonnet-4-20250514',\n max_tokens: request.maxTokens || 4096,\n temperature: 0.3,\n system: request.systemPrompt,\n messages,\n tools: request.tools,\n });\n\n const toolUseBlocks = response.content.filter(\n (b): b is Anthropic.ToolUseBlock => b.type === 'tool_use'\n );\n const textBlocks = response.content.filter(\n (b): b is Anthropic.TextBlock => b.type === 'text'\n );\n\n if (toolUseBlocks.length === 0) {\n const result: AIToolCallResult = {\n success: true,\n content: textBlocks.map(b => b.text).join('\\n'),\n };\n if (allToolCalls.length > 0) result.toolCalls = allToolCalls;\n return result;\n }\n\n // Claude wants to use tools -- execute them\n messages.push({ role: 'assistant', content: response.content });\n\n const toolResults: Anthropic.ToolResultBlockParam[] = [];\n for (const block of toolUseBlocks) {\n const input = (block.input ?? {}) as Record<string, unknown>;\n allToolCalls.push({ id: block.id, name: block.name, input });\n const toolLabel = block.name.replace(/^trie_/, '').replace(/_/g, ' ');\n onProgress?.(`Running ${toolLabel}...`);\n let resultText: string;\n let isError = false;\n try {\n resultText = await request.executeTool(block.name, input, onProgress);\n } catch (err) {\n resultText = `Tool error: ${err instanceof Error ? err.message : String(err)}`;\n isError = true;\n }\n toolResults.push({\n type: 'tool_result',\n tool_use_id: block.id,\n content: resultText,\n is_error: isError,\n });\n }\n\n messages.push({ role: 'user', content: toolResults });\n\n if (response.stop_reason === 'end_turn') {\n const text = textBlocks.map(b => b.text).join('\\n');\n const result: AIToolCallResult = { success: true, content: text || 'Done.' };\n if (allToolCalls.length > 0) result.toolCalls = allToolCalls;\n return result;\n }\n }\n\n const result: AIToolCallResult = { success: true, content: 'Reached maximum tool rounds.' };\n if (allToolCalls.length > 0) result.toolCalls = allToolCalls;\n return result;\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n return { success: false, content: '', error: `AI tool-use failed: ${errorMessage}` };\n }\n}\n"],"mappings":"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","names":["result"]}
1
+ {"version":3,"sources":["../src/ai/client.ts"],"sourcesContent":["/**\n * Centralized AI Client\n * \n * Handles API key detection, graceful fallbacks, and AI-powered analysis.\n * All agents use this for AI-enhanced analysis.\n * \n * API Key Setup:\n * 1. Set ANTHROPIC_API_KEY in your environment\n * 2. Or add it to your MCP server config (mcp.json)\n * 3. Or create .env file in your project root\n * \n * If no API key is found, agents fall back to pattern-only mode.\n */\n\nimport Anthropic from '@anthropic-ai/sdk';\nimport { readFileSync, writeFileSync, mkdirSync, existsSync } from 'fs';\nimport { execSync } from 'node:child_process';\nimport { join } from 'path';\nimport { getWorkingDirectory, getTrieDirectory } from '../utils/workspace.js';\n\n// Cached client instance\nlet clientInstance: Anthropic | null = null;\nlet apiKeyChecked = false;\nlet apiKeyAvailable = false;\n\n/**\n * Check if AI is available (API key is set)\n */\nexport function isAIAvailable(): boolean {\n if (!apiKeyChecked) {\n checkAPIKey();\n }\n return apiKeyAvailable;\n}\n\n/**\n * Read API key from Apple Keychain (macOS only)\n */\nexport function getKeyFromKeychain(): string | null {\n if (process.platform !== 'darwin') return null;\n try {\n const result = execSync(\n 'security find-generic-password -a \"trie\" -s \"anthropic-api-key\" -w 2>/dev/null',\n { encoding: 'utf-8' }\n ).trim();\n return result.length > 10 ? result : null;\n } catch { return null; }\n}\n\n/**\n * Save API key to Apple Keychain (macOS only)\n */\nexport function saveKeyToKeychain(key: string): boolean {\n if (process.platform !== 'darwin') return false;\n try {\n try { execSync('security delete-generic-password -a \"trie\" -s \"anthropic-api-key\" 2>/dev/null'); } catch { /* not found */ }\n execSync(`security add-generic-password -a \"trie\" -s \"anthropic-api-key\" -w \"${key.replace(/\"/g, '\\\\\"')}\"`);\n return true;\n } catch { return false; }\n}\n\n/**\n * Save API key and refresh the cached state\n */\nexport function setAPIKey(key: string): { saved: boolean; method: 'keychain' | 'config' } {\n process.env.ANTHROPIC_API_KEY = key;\n clientInstance = null;\n apiKeyChecked = true;\n apiKeyAvailable = true;\n\n if (saveKeyToKeychain(key)) {\n return { saved: true, method: 'keychain' };\n }\n\n try {\n const workDir = getWorkingDirectory(undefined, true);\n const trieDir = getTrieDirectory(workDir);\n const configPath = join(trieDir, 'config.json');\n let config: Record<string, unknown> = {};\n if (existsSync(configPath)) {\n config = JSON.parse(readFileSync(configPath, 'utf-8'));\n }\n if (!config.apiKeys || typeof config.apiKeys !== 'object') config.apiKeys = {};\n (config.apiKeys as Record<string, string>).anthropic = key;\n mkdirSync(trieDir, { recursive: true });\n writeFileSync(configPath, JSON.stringify(config, null, 2));\n } catch { /* best effort */ }\n\n return { saved: true, method: 'config' };\n}\n\n/**\n * Check for API key in environment, keychain, config, and .env files\n */\nfunction checkAPIKey(): void {\n apiKeyChecked = true;\n \n // 1. Check standard env var first\n const envApiKey = process.env.ANTHROPIC_API_KEY;\n if (envApiKey && envApiKey.length > 10) {\n apiKeyAvailable = true;\n return;\n }\n\n // 2. Check Apple Keychain (macOS)\n const keychainKey = getKeyFromKeychain();\n if (keychainKey) {\n process.env.ANTHROPIC_API_KEY = keychainKey;\n apiKeyAvailable = true;\n return;\n }\n \n // 3. Check config file\n try {\n const workDir = getWorkingDirectory(undefined, true);\n const configPath = join(getTrieDirectory(workDir), 'config.json');\n \n if (existsSync(configPath)) {\n const configContent = readFileSync(configPath, 'utf-8');\n const config = JSON.parse(configContent);\n \n if (config.apiKeys?.anthropic && config.apiKeys.anthropic.length > 10) {\n process.env.ANTHROPIC_API_KEY = config.apiKeys.anthropic;\n apiKeyAvailable = true;\n return;\n }\n }\n } catch {\n // Config file doesn't exist or couldn't be read\n }\n \n // 4. Check .env files\n try {\n const workDir = getWorkingDirectory(undefined, true);\n const envFiles = ['.env', '.env.local', '.env.production'];\n \n for (const envFile of envFiles) {\n const envPath = join(workDir, envFile);\n if (existsSync(envPath)) {\n const envContent = readFileSync(envPath, 'utf-8');\n const lines = envContent.split('\\n');\n \n for (const line of lines) {\n const match = line.match(/^\\s*ANTHROPIC_API_KEY\\s*=\\s*(.+)$/);\n if (match && match[1]) {\n const key = match[1].trim().replace(/^[\"']|[\"']$/g, '');\n if (key.length > 10) {\n process.env.ANTHROPIC_API_KEY = key;\n apiKeyAvailable = true;\n return;\n }\n }\n }\n }\n }\n } catch {\n // .env file doesn't exist or couldn't be read\n }\n \n apiKeyAvailable = false;\n}\n\n/**\n * Get the Anthropic client (lazy initialized)\n * Throws if API key is not available\n */\nexport function getClient(): Anthropic {\n if (!isAIAvailable()) {\n throw new Error(\n 'ANTHROPIC_API_KEY not found. Set it in your environment to enable AI-powered analysis.\\n' +\n 'Example: export ANTHROPIC_API_KEY=sk-ant-...'\n );\n }\n \n if (!clientInstance) {\n clientInstance = new Anthropic();\n }\n \n return clientInstance;\n}\n\n/**\n * Try to get client, return null if not available\n */\nexport function tryGetClient(): Anthropic | null {\n if (!isAIAvailable()) {\n return null;\n }\n \n if (!clientInstance) {\n clientInstance = new Anthropic();\n }\n \n return clientInstance;\n}\n\nexport interface AIAnalysisRequest {\n systemPrompt: string;\n userPrompt: string;\n maxTokens?: number;\n temperature?: number;\n}\n\nexport interface AIAnalysisResult {\n success: boolean;\n content: string;\n error?: string;\n tokensUsed?: {\n input: number;\n output: number;\n };\n}\n\n/**\n * Run AI analysis with the given prompts\n */\nexport async function runAIAnalysis(request: AIAnalysisRequest): Promise<AIAnalysisResult> {\n const client = tryGetClient();\n \n if (!client) {\n return {\n success: false,\n content: '',\n error: 'AI not available - ANTHROPIC_API_KEY not set'\n };\n }\n \n try {\n const response = await client.messages.create({\n model: 'claude-sonnet-4-20250514',\n max_tokens: request.maxTokens || 4096,\n temperature: request.temperature ?? 0.3,\n system: request.systemPrompt,\n messages: [\n {\n role: 'user',\n content: request.userPrompt\n }\n ]\n });\n \n // Extract text content\n const textContent = response.content\n .filter((block): block is Anthropic.TextBlock => block.type === 'text')\n .map(block => block.text)\n .join('\\n');\n \n return {\n success: true,\n content: textContent,\n tokensUsed: {\n input: response.usage.input_tokens,\n output: response.usage.output_tokens\n }\n };\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n \n // Check for specific error types\n if (errorMessage.includes('authentication') || errorMessage.includes('API key')) {\n return {\n success: false,\n content: '',\n error: 'Invalid API key. Check your ANTHROPIC_API_KEY.'\n };\n }\n \n if (errorMessage.includes('rate limit')) {\n return {\n success: false,\n content: '',\n error: 'Rate limited. Try again in a moment.'\n };\n }\n \n return {\n success: false,\n content: '',\n error: `AI analysis failed: ${errorMessage}`\n };\n }\n}\n\n/**\n * AI analysis for code issues\n */\nexport interface CodeIssueAnalysisRequest {\n issues: Array<{\n file: string;\n line?: number;\n issue: string;\n code?: string;\n }>;\n analysisType: 'validate' | 'expand' | 'fix' | 'explain';\n context?: string;\n}\n\n/**\n * Run AI analysis on code issues\n * Used by agents to validate, expand, or fix detected issues\n */\nexport async function analyzeCodeIssues(request: CodeIssueAnalysisRequest): Promise<AIAnalysisResult> {\n const systemPrompts: Record<CodeIssueAnalysisRequest['analysisType'], string> = {\n validate: `You are a senior code reviewer. Analyze the following issues detected by static analysis.\nFor each issue:\n1. Determine if it's a TRUE POSITIVE (real problem) or FALSE POSITIVE (not actually an issue)\n2. Provide a confidence score (0-100)\n3. Explain your reasoning briefly\n\nOutput format:\n### Issue 1: [file:line]\n**Verdict:** TRUE_POSITIVE / FALSE_POSITIVE\n**Confidence:** [0-100]\n**Reason:** [one line explanation]\n**Fix:** [specific fix if true positive]`,\n\n expand: `You are a security expert and senior architect. Given these detected code issues, look deeper:\n1. Are there related problems in the same code that were missed?\n2. What's the root cause of these patterns?\n3. What's the blast radius if these issues cause problems?\n4. What architectural changes would prevent these patterns?\n\nBe specific. Reference line numbers. Provide code examples.`,\n\n fix: `You are an expert programmer. For each issue, provide a specific fix:\n1. Show the exact code change needed\n2. Explain why this fix works\n3. Note any edge cases to consider\n\nUse markdown code blocks with the language specified.`,\n\n explain: `You are a patient teacher explaining code issues to a junior developer.\nFor each issue:\n1. Explain what the problem is in simple terms\n2. Explain why it's a problem (what could go wrong)\n3. Explain the fix and why it works\n4. Provide a learning resource if relevant`\n };\n\n const issuesText = request.issues.map((issue, i) => {\n let text = `### Issue ${i + 1}: ${issue.file}${issue.line ? ':' + issue.line : ''}\\n`;\n text += `**Problem:** ${issue.issue}\\n`;\n if (issue.code) {\n text += `**Code:**\\n\\`\\`\\`\\n${issue.code}\\n\\`\\`\\`\\n`;\n }\n return text;\n }).join('\\n');\n\n const userPrompt = `${request.context ? `Context: ${request.context}\\n\\n` : ''}${issuesText}`;\n\n return runAIAnalysis({\n systemPrompt: systemPrompts[request.analysisType],\n userPrompt,\n maxTokens: 4096,\n temperature: 0.2\n });\n}\n\n/**\n * Get status message about AI availability\n */\nexport function getAIStatusMessage(): string {\n if (isAIAvailable()) {\n return '[AI] AI-powered analysis enabled';\n }\n return '[!] AI not available (ANTHROPIC_API_KEY not set) - using pattern-only mode';\n}\n\nexport interface AIToolCallRecord {\n name: string;\n input: Record<string, unknown>;\n result?: string;\n}\n\nexport interface AIToolCallResult {\n success: boolean;\n content: string;\n error?: string;\n toolCalls?: AIToolCallRecord[];\n toolResults?: string[];\n}\n\n/**\n * Run AI analysis with tool-use support.\n * Loops until Claude returns a final text response or hits maxToolRounds.\n */\nexport async function runAIWithTools(request: {\n systemPrompt: string;\n messages: Anthropic.MessageParam[];\n tools: Anthropic.Tool[];\n executeTool: (name: string, input: Record<string, unknown>, onProgress?: (msg: string) => void) => Promise<string>;\n maxTokens?: number;\n maxToolRounds?: number;\n onProgress?: (message: string) => void;\n}): Promise<AIToolCallResult> {\n const client = tryGetClient();\n if (!client) {\n return { success: false, content: '', error: 'AI not available - ANTHROPIC_API_KEY not set' };\n }\n\n const maxRounds = request.maxToolRounds ?? 5;\n const messages: Anthropic.MessageParam[] = [...request.messages];\n const allToolCalls: AIToolCallRecord[] = [];\n const allToolResults: string[] = [];\n\n const { onProgress } = request;\n\n try {\n for (let round = 0; round < maxRounds; round++) {\n onProgress?.(round === 0 ? 'Analyzing...' : `Processing (round ${round + 1})...`);\n const response = await client.messages.create({\n model: 'claude-sonnet-4-20250514',\n max_tokens: request.maxTokens || 4096,\n temperature: 0.3,\n system: request.systemPrompt,\n messages,\n tools: request.tools,\n });\n\n const toolUseBlocks = response.content.filter(\n (b): b is Anthropic.ToolUseBlock => b.type === 'tool_use'\n );\n const textBlocks = response.content.filter(\n (b): b is Anthropic.TextBlock => b.type === 'text'\n );\n\n if (toolUseBlocks.length === 0) {\n const result: AIToolCallResult = {\n success: true,\n content: textBlocks.map(b => b.text).join('\\n'),\n };\n if (allToolCalls.length > 0) {\n result.toolCalls = allToolCalls;\n result.toolResults = allToolResults;\n }\n return result;\n }\n\n // Claude wants to use tools -- execute them\n messages.push({ role: 'assistant', content: response.content });\n\n const toolResults: Anthropic.ToolResultBlockParam[] = [];\n for (const block of toolUseBlocks) {\n const input = (block.input ?? {}) as Record<string, unknown>;\n const toolLabel = block.name.replace(/^trie_/, '').replace(/_/g, ' ');\n onProgress?.(`Running ${toolLabel}...`);\n let resultText: string;\n let isError = false;\n try {\n resultText = await request.executeTool(block.name, input, onProgress);\n } catch (err) {\n resultText = `Tool error: ${err instanceof Error ? err.message : String(err)}`;\n isError = true;\n }\n allToolCalls.push({ name: block.name, input, result: resultText });\n allToolResults.push(resultText);\n toolResults.push({\n type: 'tool_result',\n tool_use_id: block.id,\n content: resultText,\n is_error: isError,\n });\n }\n\n messages.push({ role: 'user', content: toolResults });\n\n if (response.stop_reason === 'end_turn') {\n const text = textBlocks.map(b => b.text).join('\\n');\n const result: AIToolCallResult = { success: true, content: text || 'Done.' };\n if (allToolCalls.length > 0) {\n result.toolCalls = allToolCalls;\n result.toolResults = allToolResults;\n }\n return result;\n }\n }\n\n const result: AIToolCallResult = { success: true, content: 'Reached maximum tool rounds.' };\n if (allToolCalls.length > 0) {\n result.toolCalls = allToolCalls;\n result.toolResults = allToolResults;\n }\n return result;\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n return { success: false, content: '', error: `AI tool-use failed: ${errorMessage}` };\n }\n}\n"],"mappings":"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","names":["result"]}
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  getGuardian
3
- } from "./chunk-T62V4H5O.js";
3
+ } from "./chunk-G5PRBQIQ.js";
4
4
  import {
5
5
  getChatStore
6
6
  } from "./chunk-DFPVUMVE.js";
@@ -19,13 +19,13 @@ import {
19
19
  } from "./chunk-WHIQAGB7.js";
20
20
  import {
21
21
  findCrossProjectPatterns
22
- } from "./chunk-3DPVJQNM.js";
22
+ } from "./chunk-UHX4462X.js";
23
23
  import {
24
24
  getKeyFromKeychain,
25
25
  isAIAvailable,
26
26
  runAIWithTools,
27
27
  setAPIKey
28
- } from "./chunk-JCU6REX7.js";
28
+ } from "./chunk-O6OTJI3W.js";
29
29
  import {
30
30
  getGuardianState
31
31
  } from "./chunk-UHMMANC2.js";
@@ -1495,8 +1495,8 @@ var VIEW_HELP = {
1495
1495
  agent: [
1496
1496
  { key: "j / \u2193", description: "Move down" },
1497
1497
  { key: "k / \u2191", description: "Move up" },
1498
- { key: "enter", description: "Expand selected nudge" },
1499
- { key: "f", description: "Spawn Claude Code to fix selected goal violation" },
1498
+ { key: "enter", description: "Fix goal violation (or expand if not a violation)" },
1499
+ { key: "f", description: "Force spawn Claude Code fix" },
1500
1500
  { key: "d", description: "Dismiss selected nudge" },
1501
1501
  { key: "tab", description: "Navigate between views" },
1502
1502
  { key: "s", description: "Open Settings" },
@@ -1849,8 +1849,18 @@ function AgentView() {
1849
1849
  useInput3((input, key) => {
1850
1850
  if (key.upArrow || input === "k") dispatch({ type: "NAVIGATE_UP" });
1851
1851
  else if (key.downArrow || input === "j") dispatch({ type: "NAVIGATE_DOWN" });
1852
- else if (key.return) dispatch({ type: "TOGGLE_INSIGHT", index: selectedInsight });
1853
- else if (input === "d") void dismissInsight();
1852
+ else if (key.return) {
1853
+ const visible = getVisibleInsights(state);
1854
+ const insight = visible[selectedInsight];
1855
+ if (insight) {
1856
+ const parsed = parseGoalViolation(insight.message);
1857
+ if (parsed) {
1858
+ void spawnFixForInsight();
1859
+ } else {
1860
+ dispatch({ type: "TOGGLE_INSIGHT", index: selectedInsight });
1861
+ }
1862
+ }
1863
+ } else if (input === "d") void dismissInsight();
1854
1864
  else if (input === "f") void spawnFixForInsight();
1855
1865
  });
1856
1866
  const alertCount = alerts.length;
@@ -2096,7 +2106,7 @@ function GoalsView() {
2096
2106
  if (!goal) return;
2097
2107
  dispatch({ type: "ADD_ACTIVITY", message: `Checking goal: ${goal.description.slice(0, 30)}...` });
2098
2108
  dispatch({ type: "SHOW_NOTIFICATION", message: `Scanning files...`, severity: "info", autoHideMs: 5e3 });
2099
- const { checkFilesForGoalViolations } = await import("./goal-validator-KLAK5TZN.js");
2109
+ const { checkFilesForGoalViolations } = await import("./goal-validator-PDKYZSNP.js");
2100
2110
  const violations = await checkFilesForGoalViolations([goal], workDir);
2101
2111
  if (violations.length === 0) {
2102
2112
  dispatch({ type: "SHOW_NOTIFICATION", message: `\u2713 No violations found for: ${goal.description.slice(0, 40)}`, severity: "info", autoHideMs: 5e3 });
@@ -2298,7 +2308,7 @@ function HypothesesView() {
2298
2308
  if (!hypo) return;
2299
2309
  dispatch({ type: "ADD_ACTIVITY", message: `Testing hypothesis: ${hypo.statement.slice(0, 30)}...` });
2300
2310
  dispatch({ type: "SHOW_NOTIFICATION", message: `Gathering evidence for hypothesis...`, severity: "info", autoHideMs: 3e3 });
2301
- const { gatherEvidenceForHypothesis } = await import("./hypothesis-I276JIDW.js");
2311
+ const { gatherEvidenceForHypothesis } = await import("./hypothesis-L5446W36.js");
2302
2312
  const evidence = await gatherEvidenceForHypothesis(hypoId, workDir);
2303
2313
  if (evidence.length === 0) {
2304
2314
  dispatch({ type: "SHOW_NOTIFICATION", message: `No evidence found for: ${hypo.statement.slice(0, 40)}`, severity: "info", autoHideMs: 5e3 });
@@ -2360,6 +2370,11 @@ function HypothesesView() {
2360
2370
  ] }) }),
2361
2371
  /* @__PURE__ */ jsx10(Text9, { dimColor: true, children: " enter save \xB7 esc cancel" })
2362
2372
  ] }) : /* @__PURE__ */ jsx10(Fragment4, { children: hypothesesPanel.hypotheses.length === 0 ? /* @__PURE__ */ jsx10(Text9, { dimColor: true, children: " No hypotheses yet. Press a to add one." }) : /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", children: [
2373
+ testing.length === 0 && hypothesesPanel.hypotheses.length > 0 && /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", marginBottom: 1, paddingX: 1, borderStyle: "round", borderColor: "yellow", children: [
2374
+ /* @__PURE__ */ jsx10(Text9, { color: "yellow", bold: true, children: "\u26A0 No Active Hypotheses" }),
2375
+ /* @__PURE__ */ jsx10(Text9, { dimColor: true, children: "Hypotheses exist but none are being tested. Evidence won't be gathered." }),
2376
+ /* @__PURE__ */ jsx10(Text9, { dimColor: true, children: 'Press a to add a new hypothesis, or run: trie hypothesis add "your hypothesis"' })
2377
+ ] }),
2363
2378
  testing.map((hypo, idx) => {
2364
2379
  const isSelected = hypothesesPanel.selectedIndex === idx;
2365
2380
  const conf = Math.round(hypo.confidence * 100);
@@ -5605,7 +5620,7 @@ ${truncated}`;
5605
5620
  const goalId = input.goalId ? String(input.goalId).trim() : void 0;
5606
5621
  try {
5607
5622
  onProgress?.("Loading goals...");
5608
- const { checkFilesForGoalViolations, getActiveGoals } = await import("./goal-validator-KLAK5TZN.js");
5623
+ const { checkFilesForGoalViolations, getActiveGoals } = await import("./goal-validator-PDKYZSNP.js");
5609
5624
  const agentState = getGuardianState(directory);
5610
5625
  await agentState.load();
5611
5626
  const allGoals = await getActiveGoals(directory);
@@ -5924,22 +5939,15 @@ ${contextBlock}`;
5924
5939
  ...messages,
5925
5940
  { role: "user", content: question, timestamp: Date.now() }
5926
5941
  ]);
5927
- const CHAT_TIMEOUT_MS = 18e4;
5928
- const timeoutPromise = new Promise((_, reject) => {
5929
- setTimeout(() => reject(new Error("Request timed out. Large scans (e.g. emoji removal) can take a few minutes. Try again or run the scan from the Goals view.")), CHAT_TIMEOUT_MS);
5942
+ const result = await runAIWithTools({
5943
+ systemPrompt: fullSystem,
5944
+ messages: history,
5945
+ tools: CHAT_TOOLS,
5946
+ executeTool,
5947
+ maxTokens: 4096,
5948
+ maxToolRounds: 8,
5949
+ onProgress: (msg) => dispatch({ type: "SET_CHAT_PROGRESS", message: msg })
5930
5950
  });
5931
- const result = await Promise.race([
5932
- runAIWithTools({
5933
- systemPrompt: fullSystem,
5934
- messages: history,
5935
- tools: CHAT_TOOLS,
5936
- executeTool,
5937
- maxTokens: 4096,
5938
- maxToolRounds: 8,
5939
- onProgress: (msg) => dispatch({ type: "SET_CHAT_PROGRESS", message: msg })
5940
- }),
5941
- timeoutPromise
5942
- ]);
5943
5951
  if (result.success) {
5944
5952
  const action = {
5945
5953
  type: "ADD_CHAT_MESSAGE",
@@ -5959,6 +5967,24 @@ ${contextBlock}`;
5959
5967
  } catch {
5960
5968
  }
5961
5969
  }
5970
+ if (result.toolResults && result.toolResults.length > 0) {
5971
+ for (const toolResult of result.toolResults) {
5972
+ const toolRegex = /\[PENDING_FIX:(.+?)\]/g;
5973
+ let toolMatch;
5974
+ while ((toolMatch = toolRegex.exec(toolResult)) !== null) {
5975
+ try {
5976
+ const jsonStr = toolMatch[1];
5977
+ if (jsonStr) {
5978
+ const fixData = JSON.parse(jsonStr);
5979
+ if (!pendingFixes.some((f) => f.file === fixData.file)) {
5980
+ pendingFixes.push(fixData);
5981
+ }
5982
+ }
5983
+ } catch {
5984
+ }
5985
+ }
5986
+ }
5987
+ }
5962
5988
  if (pendingFixes.length > 0) {
5963
5989
  action.content = result.content.replace(/\[PENDING_FIX:.+?\]/g, "").trim();
5964
5990
  const firstFix = pendingFixes[0];
@@ -6373,7 +6399,7 @@ import { jsx as jsx15, jsxs as jsxs14 } from "react/jsx-runtime";
6373
6399
  var MAIN_VIEWS = ["overview", "memory", "goals", "hypotheses", "agent", "chat"];
6374
6400
  async function applyGoalFix(fix, dispatch) {
6375
6401
  try {
6376
- const { runAIAnalysis, isAIAvailable: isAIAvailable2 } = await import("./client-OVI6TBX7.js");
6402
+ const { runAIAnalysis, isAIAvailable: isAIAvailable2 } = await import("./client-BZHI675W.js");
6377
6403
  if (!isAIAvailable2()) {
6378
6404
  dispatch({ type: "DISMISS_FIX", id: fix.id });
6379
6405
  getOutputManager().nudge("AI not available for fix", "warning");
@@ -6408,7 +6434,7 @@ ${content}
6408
6434
  fixedContent = fixedContent.replace(/^```\w*\n?/, "").replace(/\n?```$/, "");
6409
6435
  }
6410
6436
  await writeFile(fullPath, fixedContent, "utf-8");
6411
- const { recordGoalViolationFixed, getActiveGoals } = await import("./goal-validator-KLAK5TZN.js");
6437
+ const { recordGoalViolationFixed, getActiveGoals } = await import("./goal-validator-PDKYZSNP.js");
6412
6438
  const goals = await getActiveGoals(projectPath);
6413
6439
  const matchedGoal = goals.find((g) => g.description === fix.goalDescription);
6414
6440
  if (matchedGoal) {
@@ -6795,4 +6821,4 @@ export {
6795
6821
  handleCheckpointTool,
6796
6822
  InteractiveDashboard
6797
6823
  };
6798
- //# sourceMappingURL=chunk-TFGNTSMH.js.map
6824
+ //# sourceMappingURL=chunk-POHBQUG7.js.map