@triedotdev/mcp 1.0.133 → 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.
- package/dist/{chunk-LRQV7SGQ.js → chunk-AJ34GCMD.js} +2 -2
- package/dist/{chunk-T62V4H5O.js → chunk-G5PRBQIQ.js} +4 -4
- package/dist/{chunk-JCU6REX7.js → chunk-O6OTJI3W.js} +16 -5
- package/dist/{chunk-JCU6REX7.js.map → chunk-O6OTJI3W.js.map} +1 -1
- package/dist/{chunk-LMFREFAP.js → chunk-POHBQUG7.js} +94 -39
- package/dist/chunk-POHBQUG7.js.map +1 -0
- package/dist/{chunk-3DPVJQNM.js → chunk-UHX4462X.js} +2 -2
- package/dist/cli/main.js +2 -2
- package/dist/cli/yolo-daemon.js +5 -5
- package/dist/{client-OVI6TBX7.js → client-BZHI675W.js} +2 -2
- package/dist/{goal-validator-KLAK5TZN.js → goal-validator-PDKYZSNP.js} +2 -2
- package/dist/{guardian-agent-3EUJUAJ2.js → guardian-agent-4RHGIXUD.js} +5 -5
- package/dist/{hypothesis-I276JIDW.js → hypothesis-L5446W36.js} +2 -2
- package/dist/index.js +10 -10
- package/package.json +2 -1
- package/dist/chunk-LMFREFAP.js.map +0 -1
- /package/dist/{chunk-LRQV7SGQ.js.map → chunk-AJ34GCMD.js.map} +0 -0
- /package/dist/{chunk-T62V4H5O.js.map → chunk-G5PRBQIQ.js.map} +0 -0
- /package/dist/{chunk-3DPVJQNM.js.map → chunk-UHX4462X.js.map} +0 -0
- /package/dist/{client-OVI6TBX7.js.map → client-BZHI675W.js.map} +0 -0
- /package/dist/{goal-validator-KLAK5TZN.js.map → goal-validator-PDKYZSNP.js.map} +0 -0
- /package/dist/{guardian-agent-3EUJUAJ2.js.map → guardian-agent-4RHGIXUD.js.map} +0 -0
- /package/dist/{hypothesis-I276JIDW.js.map → hypothesis-L5446W36.js.map} +0 -0
|
@@ -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-
|
|
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-
|
|
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-
|
|
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-
|
|
14
|
+
} from "./chunk-UHX4462X.js";
|
|
15
15
|
import {
|
|
16
16
|
isAIAvailable,
|
|
17
17
|
runAIAnalysis
|
|
18
|
-
} from "./chunk-
|
|
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-
|
|
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)
|
|
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)
|
|
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)
|
|
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-
|
|
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":";;;;;;AAcA,OAAO,eAAe;AACtB,SAAS,cAAc,eAAe,WAAW,kBAAkB;AACnE,SAAS,gBAAgB;AACzB,SAAS,YAAY;AAIrB,IAAI,iBAAmC;AACvC,IAAI,gBAAgB;AACpB,IAAI,kBAAkB;AAKf,SAAS,gBAAyB;AACvC,MAAI,CAAC,eAAe;AAClB,gBAAY;AAAA,EACd;AACA,SAAO;AACT;AAKO,SAAS,qBAAoC;AAClD,MAAI,QAAQ,aAAa,SAAU,QAAO;AAC1C,MAAI;AACF,UAAM,SAAS;AAAA,MACb;AAAA,MACA,EAAE,UAAU,QAAQ;AAAA,IACtB,EAAE,KAAK;AACP,WAAO,OAAO,SAAS,KAAK,SAAS;AAAA,EACvC,QAAQ;AAAE,WAAO;AAAA,EAAM;AACzB;AAKO,SAAS,kBAAkB,KAAsB;AACtD,MAAI,QAAQ,aAAa,SAAU,QAAO;AAC1C,MAAI;AACF,QAAI;AAAE,eAAS,+EAA+E;AAAA,IAAG,QAAQ;AAAA,IAAkB;AAC3H,aAAS,sEAAsE,IAAI,QAAQ,MAAM,KAAK,CAAC,GAAG;AAC1G,WAAO;AAAA,EACT,QAAQ;AAAE,WAAO;AAAA,EAAO;AAC1B;AAKO,SAAS,UAAU,KAAgE;AACxF,UAAQ,IAAI,oBAAoB;AAChC,mBAAiB;AACjB,kBAAgB;AAChB,oBAAkB;AAElB,MAAI,kBAAkB,GAAG,GAAG;AAC1B,WAAO,EAAE,OAAO,MAAM,QAAQ,WAAW;AAAA,EAC3C;AAEA,MAAI;AACF,UAAM,UAAU,oBAAoB,QAAW,IAAI;AACnD,UAAM,UAAU,iBAAiB,OAAO;AACxC,UAAM,aAAa,KAAK,SAAS,aAAa;AAC9C,QAAI,SAAkC,CAAC;AACvC,QAAI,WAAW,UAAU,GAAG;AAC1B,eAAS,KAAK,MAAM,aAAa,YAAY,OAAO,CAAC;AAAA,IACvD;AACA,QAAI,CAAC,OAAO,WAAW,OAAO,OAAO,YAAY,SAAU,QAAO,UAAU,CAAC;AAC7E,IAAC,OAAO,QAAmC,YAAY;AACvD,cAAU,SAAS,EAAE,WAAW,KAAK,CAAC;AACtC,kBAAc,YAAY,KAAK,UAAU,QAAQ,MAAM,CAAC,CAAC;AAAA,EAC3D,QAAQ;AAAA,EAAoB;AAE5B,SAAO,EAAE,OAAO,MAAM,QAAQ,SAAS;AACzC;AAKA,SAAS,cAAoB;AAC3B,kBAAgB;AAGhB,QAAM,YAAY,QAAQ,IAAI;AAC9B,MAAI,aAAa,UAAU,SAAS,IAAI;AACtC,sBAAkB;AAClB;AAAA,EACF;AAGA,QAAM,cAAc,mBAAmB;AACvC,MAAI,aAAa;AACf,YAAQ,IAAI,oBAAoB;AAChC,sBAAkB;AAClB;AAAA,EACF;AAGA,MAAI;AACF,UAAM,UAAU,oBAAoB,QAAW,IAAI;AACnD,UAAM,aAAa,KAAK,iBAAiB,OAAO,GAAG,aAAa;AAEhE,QAAI,WAAW,UAAU,GAAG;AAC1B,YAAM,gBAAgB,aAAa,YAAY,OAAO;AACtD,YAAM,SAAS,KAAK,MAAM,aAAa;AAEvC,UAAI,OAAO,SAAS,aAAa,OAAO,QAAQ,UAAU,SAAS,IAAI;AACrE,gBAAQ,IAAI,oBAAoB,OAAO,QAAQ;AAC/C,0BAAkB;AAClB;AAAA,MACF;AAAA,IACF;AAAA,EACF,QAAQ;AAAA,EAER;AAGA,MAAI;AACF,UAAM,UAAU,oBAAoB,QAAW,IAAI;AACnD,UAAM,WAAW,CAAC,QAAQ,cAAc,iBAAiB;AAEzD,eAAW,WAAW,UAAU;AAC9B,YAAM,UAAU,KAAK,SAAS,OAAO;AACrC,UAAI,WAAW,OAAO,GAAG;AACvB,cAAM,aAAa,aAAa,SAAS,OAAO;AAChD,cAAM,QAAQ,WAAW,MAAM,IAAI;AAEnC,mBAAW,QAAQ,OAAO;AACxB,gBAAM,QAAQ,KAAK,MAAM,mCAAmC;AAC5D,cAAI,SAAS,MAAM,CAAC,GAAG;AACrB,kBAAM,MAAM,MAAM,CAAC,EAAE,KAAK,EAAE,QAAQ,gBAAgB,EAAE;AACtD,gBAAI,IAAI,SAAS,IAAI;AACnB,sBAAQ,IAAI,oBAAoB;AAChC,gCAAkB;AAClB;AAAA,YACF;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF,QAAQ;AAAA,EAER;AAEA,oBAAkB;AACpB;AAMO,SAAS,YAAuB;AACrC,MAAI,CAAC,cAAc,GAAG;AACpB,UAAM,IAAI;AAAA,MACR;AAAA,IAEF;AAAA,EACF;AAEA,MAAI,CAAC,gBAAgB;AACnB,qBAAiB,IAAI,UAAU;AAAA,EACjC;AAEA,SAAO;AACT;AAKO,SAAS,eAAiC;AAC/C,MAAI,CAAC,cAAc,GAAG;AACpB,WAAO;AAAA,EACT;AAEA,MAAI,CAAC,gBAAgB;AACnB,qBAAiB,IAAI,UAAU;AAAA,EACjC;AAEA,SAAO;AACT;AAsBA,eAAsB,cAAc,SAAuD;AACzF,QAAM,SAAS,aAAa;AAE5B,MAAI,CAAC,QAAQ;AACX,WAAO;AAAA,MACL,SAAS;AAAA,MACT,SAAS;AAAA,MACT,OAAO;AAAA,IACT;AAAA,EACF;AAEA,MAAI;AACF,UAAM,WAAW,MAAM,OAAO,SAAS,OAAO;AAAA,MAC5C,OAAO;AAAA,MACP,YAAY,QAAQ,aAAa;AAAA,MACjC,aAAa,QAAQ,eAAe;AAAA,MACpC,QAAQ,QAAQ;AAAA,MAChB,UAAU;AAAA,QACR;AAAA,UACE,MAAM;AAAA,UACN,SAAS,QAAQ;AAAA,QACnB;AAAA,MACF;AAAA,IACF,CAAC;AAGD,UAAM,cAAc,SAAS,QAC1B,OAAO,CAAC,UAAwC,MAAM,SAAS,MAAM,EACrE,IAAI,WAAS,MAAM,IAAI,EACvB,KAAK,IAAI;AAEZ,WAAO;AAAA,MACL,SAAS;AAAA,MACT,SAAS;AAAA,MACT,YAAY;AAAA,QACV,OAAO,SAAS,MAAM;AAAA,QACtB,QAAQ,SAAS,MAAM;AAAA,MACzB;AAAA,IACF;AAAA,EACF,SAAS,OAAO;AACd,UAAM,eAAe,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAG1E,QAAI,aAAa,SAAS,gBAAgB,KAAK,aAAa,SAAS,SAAS,GAAG;AAC/E,aAAO;AAAA,QACL,SAAS;AAAA,QACT,SAAS;AAAA,QACT,OAAO;AAAA,MACT;AAAA,IACF;AAEA,QAAI,aAAa,SAAS,YAAY,GAAG;AACvC,aAAO;AAAA,QACL,SAAS;AAAA,QACT,SAAS;AAAA,QACT,OAAO;AAAA,MACT;AAAA,IACF;AAEA,WAAO;AAAA,MACL,SAAS;AAAA,MACT,SAAS;AAAA,MACT,OAAO,uBAAuB,YAAY;AAAA,IAC5C;AAAA,EACF;AACF;AAoBA,eAAsB,kBAAkB,SAA8D;AACpG,QAAM,gBAA0E;AAAA,IAC9E,UAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAaV,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAQR,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAOL,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMX;AAEA,QAAM,aAAa,QAAQ,OAAO,IAAI,CAAC,OAAO,MAAM;AAClD,QAAI,OAAO,aAAa,IAAI,CAAC,KAAK,MAAM,IAAI,GAAG,MAAM,OAAO,MAAM,MAAM,OAAO,EAAE;AAAA;AACjF,YAAQ,gBAAgB,MAAM,KAAK;AAAA;AACnC,QAAI,MAAM,MAAM;AACd,cAAQ;AAAA;AAAA,EAAsB,MAAM,IAAI;AAAA;AAAA;AAAA,IAC1C;AACA,WAAO;AAAA,EACT,CAAC,EAAE,KAAK,IAAI;AAEZ,QAAM,aAAa,GAAG,QAAQ,UAAU,YAAY,QAAQ,OAAO;AAAA;AAAA,IAAS,EAAE,GAAG,UAAU;AAE3F,SAAO,cAAc;AAAA,IACnB,cAAc,cAAc,QAAQ,YAAY;AAAA,IAChD;AAAA,IACA,WAAW;AAAA,IACX,aAAa;AAAA,EACf,CAAC;AACH;AAKO,SAAS,qBAA6B;AAC3C,MAAI,cAAc,GAAG;AACnB,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAkBA,eAAsB,eAAe,SAQP;AAC5B,QAAM,SAAS,aAAa;AAC5B,MAAI,CAAC,QAAQ;AACX,WAAO,EAAE,SAAS,OAAO,SAAS,IAAI,OAAO,+CAA+C;AAAA,EAC9F;AAEA,QAAM,YAAY,QAAQ,iBAAiB;AAC3C,QAAM,WAAqC,CAAC,GAAG,QAAQ,QAAQ;AAC/D,QAAM,eAAmC,CAAC;AAE1C,QAAM,EAAE,WAAW,IAAI;AAEvB,MAAI;AACF,aAAS,QAAQ,GAAG,QAAQ,WAAW,SAAS;AAC9C,mBAAa,UAAU,IAAI,iBAAiB,qBAAqB,QAAQ,CAAC,MAAM;AAChF,YAAM,WAAW,MAAM,OAAO,SAAS,OAAO;AAAA,QAC5C,OAAO;AAAA,QACP,YAAY,QAAQ,aAAa;AAAA,QACjC,aAAa;AAAA,QACb,QAAQ,QAAQ;AAAA,QAChB;AAAA,QACA,OAAO,QAAQ;AAAA,MACjB,CAAC;AAED,YAAM,gBAAgB,SAAS,QAAQ;AAAA,QACrC,CAAC,MAAmC,EAAE,SAAS;AAAA,MACjD;AACA,YAAM,aAAa,SAAS,QAAQ;AAAA,QAClC,CAAC,MAAgC,EAAE,SAAS;AAAA,MAC9C;AAEA,UAAI,cAAc,WAAW,GAAG;AAC9B,cAAMA,UAA2B;AAAA,UAC/B,SAAS;AAAA,UACT,SAAS,WAAW,IAAI,OAAK,EAAE,IAAI,EAAE,KAAK,IAAI;AAAA,QAChD;AACA,YAAI,aAAa,SAAS,EAAG,CAAAA,QAAO,YAAY;AAChD,eAAOA;AAAA,MACT;AAGA,eAAS,KAAK,EAAE,MAAM,aAAa,SAAS,SAAS,QAAQ,CAAC;AAE9D,YAAM,cAAgD,CAAC;AACvD,iBAAW,SAAS,eAAe;AACjC,cAAM,QAAS,MAAM,SAAS,CAAC;AAC/B,qBAAa,KAAK,EAAE,IAAI,MAAM,IAAI,MAAM,MAAM,MAAM,MAAM,CAAC;AAC3D,cAAM,YAAY,MAAM,KAAK,QAAQ,UAAU,EAAE,EAAE,QAAQ,MAAM,GAAG;AACpE,qBAAa,WAAW,SAAS,KAAK;AACtC,YAAI;AACJ,YAAI,UAAU;AACd,YAAI;AACF,uBAAa,MAAM,QAAQ,YAAY,MAAM,MAAM,OAAO,UAAU;AAAA,QACtE,SAAS,KAAK;AACZ,uBAAa,eAAe,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAC5E,oBAAU;AAAA,QACZ;AACA,oBAAY,KAAK;AAAA,UACf,MAAM;AAAA,UACN,aAAa,MAAM;AAAA,UACnB,SAAS;AAAA,UACT,UAAU;AAAA,QACZ,CAAC;AAAA,MACH;AAEA,eAAS,KAAK,EAAE,MAAM,QAAQ,SAAS,YAAY,CAAC;AAEpD,UAAI,SAAS,gBAAgB,YAAY;AACvC,cAAM,OAAO,WAAW,IAAI,OAAK,EAAE,IAAI,EAAE,KAAK,IAAI;AAClD,cAAMA,UAA2B,EAAE,SAAS,MAAM,SAAS,QAAQ,QAAQ;AAC3E,YAAI,aAAa,SAAS,EAAG,CAAAA,QAAO,YAAY;AAChD,eAAOA;AAAA,MACT;AAAA,IACF;AAEA,UAAM,SAA2B,EAAE,SAAS,MAAM,SAAS,+BAA+B;AAC1F,QAAI,aAAa,SAAS,EAAG,QAAO,YAAY;AAChD,WAAO;AAAA,EACT,SAAS,OAAO;AACd,UAAM,eAAe,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAC1E,WAAO,EAAE,SAAS,OAAO,SAAS,IAAI,OAAO,uBAAuB,YAAY,GAAG;AAAA,EACrF;AACF;","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":";;;;;;AAcA,OAAO,eAAe;AACtB,SAAS,cAAc,eAAe,WAAW,kBAAkB;AACnE,SAAS,gBAAgB;AACzB,SAAS,YAAY;AAIrB,IAAI,iBAAmC;AACvC,IAAI,gBAAgB;AACpB,IAAI,kBAAkB;AAKf,SAAS,gBAAyB;AACvC,MAAI,CAAC,eAAe;AAClB,gBAAY;AAAA,EACd;AACA,SAAO;AACT;AAKO,SAAS,qBAAoC;AAClD,MAAI,QAAQ,aAAa,SAAU,QAAO;AAC1C,MAAI;AACF,UAAM,SAAS;AAAA,MACb;AAAA,MACA,EAAE,UAAU,QAAQ;AAAA,IACtB,EAAE,KAAK;AACP,WAAO,OAAO,SAAS,KAAK,SAAS;AAAA,EACvC,QAAQ;AAAE,WAAO;AAAA,EAAM;AACzB;AAKO,SAAS,kBAAkB,KAAsB;AACtD,MAAI,QAAQ,aAAa,SAAU,QAAO;AAC1C,MAAI;AACF,QAAI;AAAE,eAAS,+EAA+E;AAAA,IAAG,QAAQ;AAAA,IAAkB;AAC3H,aAAS,sEAAsE,IAAI,QAAQ,MAAM,KAAK,CAAC,GAAG;AAC1G,WAAO;AAAA,EACT,QAAQ;AAAE,WAAO;AAAA,EAAO;AAC1B;AAKO,SAAS,UAAU,KAAgE;AACxF,UAAQ,IAAI,oBAAoB;AAChC,mBAAiB;AACjB,kBAAgB;AAChB,oBAAkB;AAElB,MAAI,kBAAkB,GAAG,GAAG;AAC1B,WAAO,EAAE,OAAO,MAAM,QAAQ,WAAW;AAAA,EAC3C;AAEA,MAAI;AACF,UAAM,UAAU,oBAAoB,QAAW,IAAI;AACnD,UAAM,UAAU,iBAAiB,OAAO;AACxC,UAAM,aAAa,KAAK,SAAS,aAAa;AAC9C,QAAI,SAAkC,CAAC;AACvC,QAAI,WAAW,UAAU,GAAG;AAC1B,eAAS,KAAK,MAAM,aAAa,YAAY,OAAO,CAAC;AAAA,IACvD;AACA,QAAI,CAAC,OAAO,WAAW,OAAO,OAAO,YAAY,SAAU,QAAO,UAAU,CAAC;AAC7E,IAAC,OAAO,QAAmC,YAAY;AACvD,cAAU,SAAS,EAAE,WAAW,KAAK,CAAC;AACtC,kBAAc,YAAY,KAAK,UAAU,QAAQ,MAAM,CAAC,CAAC;AAAA,EAC3D,QAAQ;AAAA,EAAoB;AAE5B,SAAO,EAAE,OAAO,MAAM,QAAQ,SAAS;AACzC;AAKA,SAAS,cAAoB;AAC3B,kBAAgB;AAGhB,QAAM,YAAY,QAAQ,IAAI;AAC9B,MAAI,aAAa,UAAU,SAAS,IAAI;AACtC,sBAAkB;AAClB;AAAA,EACF;AAGA,QAAM,cAAc,mBAAmB;AACvC,MAAI,aAAa;AACf,YAAQ,IAAI,oBAAoB;AAChC,sBAAkB;AAClB;AAAA,EACF;AAGA,MAAI;AACF,UAAM,UAAU,oBAAoB,QAAW,IAAI;AACnD,UAAM,aAAa,KAAK,iBAAiB,OAAO,GAAG,aAAa;AAEhE,QAAI,WAAW,UAAU,GAAG;AAC1B,YAAM,gBAAgB,aAAa,YAAY,OAAO;AACtD,YAAM,SAAS,KAAK,MAAM,aAAa;AAEvC,UAAI,OAAO,SAAS,aAAa,OAAO,QAAQ,UAAU,SAAS,IAAI;AACrE,gBAAQ,IAAI,oBAAoB,OAAO,QAAQ;AAC/C,0BAAkB;AAClB;AAAA,MACF;AAAA,IACF;AAAA,EACF,QAAQ;AAAA,EAER;AAGA,MAAI;AACF,UAAM,UAAU,oBAAoB,QAAW,IAAI;AACnD,UAAM,WAAW,CAAC,QAAQ,cAAc,iBAAiB;AAEzD,eAAW,WAAW,UAAU;AAC9B,YAAM,UAAU,KAAK,SAAS,OAAO;AACrC,UAAI,WAAW,OAAO,GAAG;AACvB,cAAM,aAAa,aAAa,SAAS,OAAO;AAChD,cAAM,QAAQ,WAAW,MAAM,IAAI;AAEnC,mBAAW,QAAQ,OAAO;AACxB,gBAAM,QAAQ,KAAK,MAAM,mCAAmC;AAC5D,cAAI,SAAS,MAAM,CAAC,GAAG;AACrB,kBAAM,MAAM,MAAM,CAAC,EAAE,KAAK,EAAE,QAAQ,gBAAgB,EAAE;AACtD,gBAAI,IAAI,SAAS,IAAI;AACnB,sBAAQ,IAAI,oBAAoB;AAChC,gCAAkB;AAClB;AAAA,YACF;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF,QAAQ;AAAA,EAER;AAEA,oBAAkB;AACpB;AAMO,SAAS,YAAuB;AACrC,MAAI,CAAC,cAAc,GAAG;AACpB,UAAM,IAAI;AAAA,MACR;AAAA,IAEF;AAAA,EACF;AAEA,MAAI,CAAC,gBAAgB;AACnB,qBAAiB,IAAI,UAAU;AAAA,EACjC;AAEA,SAAO;AACT;AAKO,SAAS,eAAiC;AAC/C,MAAI,CAAC,cAAc,GAAG;AACpB,WAAO;AAAA,EACT;AAEA,MAAI,CAAC,gBAAgB;AACnB,qBAAiB,IAAI,UAAU;AAAA,EACjC;AAEA,SAAO;AACT;AAsBA,eAAsB,cAAc,SAAuD;AACzF,QAAM,SAAS,aAAa;AAE5B,MAAI,CAAC,QAAQ;AACX,WAAO;AAAA,MACL,SAAS;AAAA,MACT,SAAS;AAAA,MACT,OAAO;AAAA,IACT;AAAA,EACF;AAEA,MAAI;AACF,UAAM,WAAW,MAAM,OAAO,SAAS,OAAO;AAAA,MAC5C,OAAO;AAAA,MACP,YAAY,QAAQ,aAAa;AAAA,MACjC,aAAa,QAAQ,eAAe;AAAA,MACpC,QAAQ,QAAQ;AAAA,MAChB,UAAU;AAAA,QACR;AAAA,UACE,MAAM;AAAA,UACN,SAAS,QAAQ;AAAA,QACnB;AAAA,MACF;AAAA,IACF,CAAC;AAGD,UAAM,cAAc,SAAS,QAC1B,OAAO,CAAC,UAAwC,MAAM,SAAS,MAAM,EACrE,IAAI,WAAS,MAAM,IAAI,EACvB,KAAK,IAAI;AAEZ,WAAO;AAAA,MACL,SAAS;AAAA,MACT,SAAS;AAAA,MACT,YAAY;AAAA,QACV,OAAO,SAAS,MAAM;AAAA,QACtB,QAAQ,SAAS,MAAM;AAAA,MACzB;AAAA,IACF;AAAA,EACF,SAAS,OAAO;AACd,UAAM,eAAe,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAG1E,QAAI,aAAa,SAAS,gBAAgB,KAAK,aAAa,SAAS,SAAS,GAAG;AAC/E,aAAO;AAAA,QACL,SAAS;AAAA,QACT,SAAS;AAAA,QACT,OAAO;AAAA,MACT;AAAA,IACF;AAEA,QAAI,aAAa,SAAS,YAAY,GAAG;AACvC,aAAO;AAAA,QACL,SAAS;AAAA,QACT,SAAS;AAAA,QACT,OAAO;AAAA,MACT;AAAA,IACF;AAEA,WAAO;AAAA,MACL,SAAS;AAAA,MACT,SAAS;AAAA,MACT,OAAO,uBAAuB,YAAY;AAAA,IAC5C;AAAA,EACF;AACF;AAoBA,eAAsB,kBAAkB,SAA8D;AACpG,QAAM,gBAA0E;AAAA,IAC9E,UAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAaV,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAQR,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAOL,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMX;AAEA,QAAM,aAAa,QAAQ,OAAO,IAAI,CAAC,OAAO,MAAM;AAClD,QAAI,OAAO,aAAa,IAAI,CAAC,KAAK,MAAM,IAAI,GAAG,MAAM,OAAO,MAAM,MAAM,OAAO,EAAE;AAAA;AACjF,YAAQ,gBAAgB,MAAM,KAAK;AAAA;AACnC,QAAI,MAAM,MAAM;AACd,cAAQ;AAAA;AAAA,EAAsB,MAAM,IAAI;AAAA;AAAA;AAAA,IAC1C;AACA,WAAO;AAAA,EACT,CAAC,EAAE,KAAK,IAAI;AAEZ,QAAM,aAAa,GAAG,QAAQ,UAAU,YAAY,QAAQ,OAAO;AAAA;AAAA,IAAS,EAAE,GAAG,UAAU;AAE3F,SAAO,cAAc;AAAA,IACnB,cAAc,cAAc,QAAQ,YAAY;AAAA,IAChD;AAAA,IACA,WAAW;AAAA,IACX,aAAa;AAAA,EACf,CAAC;AACH;AAKO,SAAS,qBAA6B;AAC3C,MAAI,cAAc,GAAG;AACnB,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAoBA,eAAsB,eAAe,SAQP;AAC5B,QAAM,SAAS,aAAa;AAC5B,MAAI,CAAC,QAAQ;AACX,WAAO,EAAE,SAAS,OAAO,SAAS,IAAI,OAAO,+CAA+C;AAAA,EAC9F;AAEA,QAAM,YAAY,QAAQ,iBAAiB;AAC3C,QAAM,WAAqC,CAAC,GAAG,QAAQ,QAAQ;AAC/D,QAAM,eAAmC,CAAC;AAC1C,QAAM,iBAA2B,CAAC;AAElC,QAAM,EAAE,WAAW,IAAI;AAEvB,MAAI;AACF,aAAS,QAAQ,GAAG,QAAQ,WAAW,SAAS;AAC9C,mBAAa,UAAU,IAAI,iBAAiB,qBAAqB,QAAQ,CAAC,MAAM;AAChF,YAAM,WAAW,MAAM,OAAO,SAAS,OAAO;AAAA,QAC5C,OAAO;AAAA,QACP,YAAY,QAAQ,aAAa;AAAA,QACjC,aAAa;AAAA,QACb,QAAQ,QAAQ;AAAA,QAChB;AAAA,QACA,OAAO,QAAQ;AAAA,MACjB,CAAC;AAED,YAAM,gBAAgB,SAAS,QAAQ;AAAA,QACrC,CAAC,MAAmC,EAAE,SAAS;AAAA,MACjD;AACA,YAAM,aAAa,SAAS,QAAQ;AAAA,QAClC,CAAC,MAAgC,EAAE,SAAS;AAAA,MAC9C;AAEA,UAAI,cAAc,WAAW,GAAG;AAC9B,cAAMA,UAA2B;AAAA,UAC/B,SAAS;AAAA,UACT,SAAS,WAAW,IAAI,OAAK,EAAE,IAAI,EAAE,KAAK,IAAI;AAAA,QAChD;AACA,YAAI,aAAa,SAAS,GAAG;AAC3B,UAAAA,QAAO,YAAY;AACnB,UAAAA,QAAO,cAAc;AAAA,QACvB;AACA,eAAOA;AAAA,MACT;AAGA,eAAS,KAAK,EAAE,MAAM,aAAa,SAAS,SAAS,QAAQ,CAAC;AAE9D,YAAM,cAAgD,CAAC;AACvD,iBAAW,SAAS,eAAe;AACjC,cAAM,QAAS,MAAM,SAAS,CAAC;AAC/B,cAAM,YAAY,MAAM,KAAK,QAAQ,UAAU,EAAE,EAAE,QAAQ,MAAM,GAAG;AACpE,qBAAa,WAAW,SAAS,KAAK;AACtC,YAAI;AACJ,YAAI,UAAU;AACd,YAAI;AACF,uBAAa,MAAM,QAAQ,YAAY,MAAM,MAAM,OAAO,UAAU;AAAA,QACtE,SAAS,KAAK;AACZ,uBAAa,eAAe,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAC5E,oBAAU;AAAA,QACZ;AACA,qBAAa,KAAK,EAAE,MAAM,MAAM,MAAM,OAAO,QAAQ,WAAW,CAAC;AACjE,uBAAe,KAAK,UAAU;AAC9B,oBAAY,KAAK;AAAA,UACf,MAAM;AAAA,UACN,aAAa,MAAM;AAAA,UACnB,SAAS;AAAA,UACT,UAAU;AAAA,QACZ,CAAC;AAAA,MACH;AAEA,eAAS,KAAK,EAAE,MAAM,QAAQ,SAAS,YAAY,CAAC;AAEpD,UAAI,SAAS,gBAAgB,YAAY;AACvC,cAAM,OAAO,WAAW,IAAI,OAAK,EAAE,IAAI,EAAE,KAAK,IAAI;AAClD,cAAMA,UAA2B,EAAE,SAAS,MAAM,SAAS,QAAQ,QAAQ;AAC3E,YAAI,aAAa,SAAS,GAAG;AAC3B,UAAAA,QAAO,YAAY;AACnB,UAAAA,QAAO,cAAc;AAAA,QACvB;AACA,eAAOA;AAAA,MACT;AAAA,IACF;AAEA,UAAM,SAA2B,EAAE,SAAS,MAAM,SAAS,+BAA+B;AAC1F,QAAI,aAAa,SAAS,GAAG;AAC3B,aAAO,YAAY;AACnB,aAAO,cAAc;AAAA,IACvB;AACA,WAAO;AAAA,EACT,SAAS,OAAO;AACd,UAAM,eAAe,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAC1E,WAAO,EAAE,SAAS,OAAO,SAAS,IAAI,OAAO,uBAAuB,YAAY,GAAG;AAAA,EACrF;AACF;","names":["result"]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
getGuardian
|
|
3
|
-
} from "./chunk-
|
|
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-
|
|
22
|
+
} from "./chunk-UHX4462X.js";
|
|
23
23
|
import {
|
|
24
24
|
getKeyFromKeychain,
|
|
25
25
|
isAIAvailable,
|
|
26
26
|
runAIWithTools,
|
|
27
27
|
setAPIKey
|
|
28
|
-
} from "./chunk-
|
|
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: "
|
|
1499
|
-
{ key: "f", description: "
|
|
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)
|
|
1853
|
-
|
|
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-
|
|
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-
|
|
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-
|
|
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);
|
|
@@ -5802,13 +5817,6 @@ function ChatView() {
|
|
|
5802
5817
|
useEffect3(() => {
|
|
5803
5818
|
setScrollOffset(0);
|
|
5804
5819
|
}, [messages.length]);
|
|
5805
|
-
useEffect3(() => {
|
|
5806
|
-
if (!loading && messageQueue.length > 0) {
|
|
5807
|
-
const msg = messageQueue[0];
|
|
5808
|
-
dispatch({ type: "DEQUEUE_CHAT_MESSAGE" });
|
|
5809
|
-
void sendMessage(msg);
|
|
5810
|
-
}
|
|
5811
|
-
}, [loading, messageQueue.length, sendMessage, dispatch]);
|
|
5812
5820
|
useEffect3(() => {
|
|
5813
5821
|
if (messages.length === 0) return;
|
|
5814
5822
|
const saveChat = async () => {
|
|
@@ -5834,9 +5842,9 @@ function ChatView() {
|
|
|
5834
5842
|
const sendMessage = useCallback5(async (question) => {
|
|
5835
5843
|
if (loadingRef.current) return;
|
|
5836
5844
|
loadingRef.current = true;
|
|
5845
|
+
dispatch({ type: "SET_CHAT_LOADING", loading: true });
|
|
5837
5846
|
dispatch({ type: "ADD_CHAT_MESSAGE", role: "user", content: question });
|
|
5838
5847
|
dispatch({ type: "SET_CHAT_INPUT", buffer: "" });
|
|
5839
|
-
dispatch({ type: "SET_CHAT_LOADING", loading: true });
|
|
5840
5848
|
dispatch({ type: "SET_CHAT_PROGRESS", message: "Thinking..." });
|
|
5841
5849
|
try {
|
|
5842
5850
|
const workDir = getWorkingDirectory(void 0, true);
|
|
@@ -5931,22 +5939,15 @@ ${contextBlock}`;
|
|
|
5931
5939
|
...messages,
|
|
5932
5940
|
{ role: "user", content: question, timestamp: Date.now() }
|
|
5933
5941
|
]);
|
|
5934
|
-
const
|
|
5935
|
-
|
|
5936
|
-
|
|
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 })
|
|
5937
5950
|
});
|
|
5938
|
-
const result = await Promise.race([
|
|
5939
|
-
runAIWithTools({
|
|
5940
|
-
systemPrompt: fullSystem,
|
|
5941
|
-
messages: history,
|
|
5942
|
-
tools: CHAT_TOOLS,
|
|
5943
|
-
executeTool,
|
|
5944
|
-
maxTokens: 4096,
|
|
5945
|
-
maxToolRounds: 8,
|
|
5946
|
-
onProgress: (msg) => dispatch({ type: "SET_CHAT_PROGRESS", message: msg })
|
|
5947
|
-
}),
|
|
5948
|
-
timeoutPromise
|
|
5949
|
-
]);
|
|
5950
5951
|
if (result.success) {
|
|
5951
5952
|
const action = {
|
|
5952
5953
|
type: "ADD_CHAT_MESSAGE",
|
|
@@ -5966,6 +5967,24 @@ ${contextBlock}`;
|
|
|
5966
5967
|
} catch {
|
|
5967
5968
|
}
|
|
5968
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
|
+
}
|
|
5969
5988
|
if (pendingFixes.length > 0) {
|
|
5970
5989
|
action.content = result.content.replace(/\[PENDING_FIX:.+?\]/g, "").trim();
|
|
5971
5990
|
const firstFix = pendingFixes[0];
|
|
@@ -6026,7 +6045,14 @@ ${contextBlock}`;
|
|
|
6026
6045
|
dispatch({ type: "SET_CHAT_PROGRESS", message: null });
|
|
6027
6046
|
loadingRef.current = false;
|
|
6028
6047
|
}
|
|
6029
|
-
}, [dispatch,
|
|
6048
|
+
}, [dispatch, state]);
|
|
6049
|
+
useEffect3(() => {
|
|
6050
|
+
if (!loading && messageQueue.length > 0 && !loadingRef.current) {
|
|
6051
|
+
const msg = messageQueue[0];
|
|
6052
|
+
dispatch({ type: "DEQUEUE_CHAT_MESSAGE" });
|
|
6053
|
+
void sendMessage(msg);
|
|
6054
|
+
}
|
|
6055
|
+
}, [loading, messageQueue.length, dispatch, sendMessage]);
|
|
6030
6056
|
useInput8((input, key) => {
|
|
6031
6057
|
if (loading && key.escape) {
|
|
6032
6058
|
loadingRef.current = false;
|
|
@@ -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-
|
|
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-
|
|
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) {
|
|
@@ -6510,10 +6536,35 @@ function DashboardApp({ onReady }) {
|
|
|
6510
6536
|
} catch {
|
|
6511
6537
|
}
|
|
6512
6538
|
}, []);
|
|
6539
|
+
const loadPersistedNudges = useCallback7(async () => {
|
|
6540
|
+
try {
|
|
6541
|
+
const workDir = getWorkingDirectory(void 0, true);
|
|
6542
|
+
const { getStorage: getStorage2 } = await import("./tiered-storage-QW2G7GSG.js");
|
|
6543
|
+
const storage = getStorage2(workDir);
|
|
6544
|
+
await storage.initialize();
|
|
6545
|
+
const nudges = await storage.queryNudges({ resolved: false, limit: 50 });
|
|
6546
|
+
if (nudges.length === 0) return;
|
|
6547
|
+
const insights = nudges.map((n) => ({
|
|
6548
|
+
id: n.id,
|
|
6549
|
+
type: n.severity === "critical" || n.severity === "warning" ? "warning" : "observation",
|
|
6550
|
+
message: n.message,
|
|
6551
|
+
suggestedAction: n.suggestedAction ?? (n.file ? `Review ${n.file}` : void 0),
|
|
6552
|
+
relatedIssues: Array.isArray(n.relatedIssues) ? n.relatedIssues.map(String) : [],
|
|
6553
|
+
priority: n.priority ?? (n.severity === "critical" ? 9 : 6),
|
|
6554
|
+
timestamp: typeof n.timestamp === "string" ? new Date(n.timestamp).getTime() : n.timestamp,
|
|
6555
|
+
dismissed: n.dismissed ?? false,
|
|
6556
|
+
category: n.category || "quality"
|
|
6557
|
+
}));
|
|
6558
|
+
dispatchRef.current({ type: "ADD_INSIGHTS", insights });
|
|
6559
|
+
} catch {
|
|
6560
|
+
}
|
|
6561
|
+
}, []);
|
|
6513
6562
|
useEffect5(() => {
|
|
6514
6563
|
void loadConfig();
|
|
6515
6564
|
void refreshGoals();
|
|
6516
6565
|
void refreshHypotheses();
|
|
6566
|
+
void processInsights([]);
|
|
6567
|
+
void loadPersistedNudges();
|
|
6517
6568
|
const outputManager = getOutputManager();
|
|
6518
6569
|
outputManager.setMode("tui");
|
|
6519
6570
|
outputManager.registerTUICallbacks({
|
|
@@ -6588,7 +6639,7 @@ function DashboardApp({ onReady }) {
|
|
|
6588
6639
|
outputManager.clearTUICallbacks();
|
|
6589
6640
|
outputManager.setMode("console");
|
|
6590
6641
|
};
|
|
6591
|
-
}, [loadConfig, onReady, processInsights, refreshGoals, refreshHypotheses]);
|
|
6642
|
+
}, [loadConfig, onReady, processInsights, refreshGoals, refreshHypotheses, loadPersistedNudges]);
|
|
6592
6643
|
useEffect5(() => {
|
|
6593
6644
|
const interval = setInterval(() => {
|
|
6594
6645
|
dispatchRef.current({ type: "AUTO_DISMISS_NOTIFICATIONS" });
|
|
@@ -6600,7 +6651,11 @@ function DashboardApp({ onReady }) {
|
|
|
6600
6651
|
const toApply = state.pendingFixes.filter((f) => f.status === "applying" && !applyingFixIds.current.has(f.id));
|
|
6601
6652
|
for (const fix of toApply) {
|
|
6602
6653
|
applyingFixIds.current.add(fix.id);
|
|
6603
|
-
|
|
6654
|
+
applyGoalFix(fix, dispatchRef.current).catch((error) => {
|
|
6655
|
+
console.error(`Failed to apply fix for ${fix.file}:`, error);
|
|
6656
|
+
dispatchRef.current({ type: "DISMISS_FIX", id: fix.id });
|
|
6657
|
+
getOutputManager().nudge(`Fix failed for ${fix.file}: ${error instanceof Error ? error.message : "unknown error"}`, "warning");
|
|
6658
|
+
});
|
|
6604
6659
|
}
|
|
6605
6660
|
}, [state.pendingFixes]);
|
|
6606
6661
|
useInput10((input, key) => {
|
|
@@ -6766,4 +6821,4 @@ export {
|
|
|
6766
6821
|
handleCheckpointTool,
|
|
6767
6822
|
InteractiveDashboard
|
|
6768
6823
|
};
|
|
6769
|
-
//# sourceMappingURL=chunk-
|
|
6824
|
+
//# sourceMappingURL=chunk-POHBQUG7.js.map
|