@triedotdev/mcp 1.0.137 → 1.0.139

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (110) hide show
  1. package/README.md +188 -43
  2. package/dist/{autonomy-config-QA6ATWLJ.js → autonomy-config-ZCOSTMPD.js} +3 -3
  3. package/dist/{chat-store-HFOOWZYN.js → chat-store-OJLJCJFI.js} +3 -3
  4. package/dist/{chunk-DFPVUMVE.js → chunk-23RJT5WT.js} +5 -4
  5. package/dist/chunk-23RJT5WT.js.map +1 -0
  6. package/dist/{chunk-QNKBXOIQ.js → chunk-3MUCUZ46.js} +3 -5
  7. package/dist/chunk-3MUCUZ46.js.map +1 -0
  8. package/dist/{chunk-WHIQAGB7.js → chunk-4C67GV3O.js} +2 -2
  9. package/dist/{chunk-AXYNWBME.js → chunk-4O2KRHK4.js} +1907 -414
  10. package/dist/chunk-4O2KRHK4.js.map +1 -0
  11. package/dist/{chunk-ZEXMMTIQ.js → chunk-5KJ4UJOY.js} +10 -5
  12. package/dist/chunk-5KJ4UJOY.js.map +1 -0
  13. package/dist/chunk-62POBLFC.js +1925 -0
  14. package/dist/chunk-62POBLFC.js.map +1 -0
  15. package/dist/{chunk-HUR67JXG.js → chunk-75ADWWUF.js} +38 -19
  16. package/dist/chunk-75ADWWUF.js.map +1 -0
  17. package/dist/{chunk-4JQ6W7LW.js → chunk-7OJ6JIPL.js} +40 -608
  18. package/dist/chunk-7OJ6JIPL.js.map +1 -0
  19. package/dist/{chunk-6VIMBFUZ.js → chunk-AF2APASP.js} +58 -20
  20. package/dist/chunk-AF2APASP.js.map +1 -0
  21. package/dist/{chunk-Z4DN527J.js → chunk-FG467PDD.js} +156 -39
  22. package/dist/chunk-FG467PDD.js.map +1 -0
  23. package/dist/{chunk-55CBWOEZ.js → chunk-FH335WL5.js} +10 -2
  24. package/dist/chunk-FH335WL5.js.map +1 -0
  25. package/dist/{chunk-O6OTJI3W.js → chunk-FPEMP54L.js} +22 -16
  26. package/dist/chunk-FPEMP54L.js.map +1 -0
  27. package/dist/{chunk-K6NTRSDF.js → chunk-GXF6JOCN.js} +24 -326
  28. package/dist/chunk-GXF6JOCN.js.map +1 -0
  29. package/dist/chunk-LD7ZEFNY.js +132 -0
  30. package/dist/chunk-LD7ZEFNY.js.map +1 -0
  31. package/dist/{chunk-6EP2VTHC.js → chunk-LT6VUZG2.js} +7 -4
  32. package/dist/chunk-LT6VUZG2.js.map +1 -0
  33. package/dist/chunk-NKHO34UZ.js +467 -0
  34. package/dist/chunk-NKHO34UZ.js.map +1 -0
  35. package/dist/{chunk-QM5VIDFN.js → chunk-OQ4A3RDY.js} +46 -30
  36. package/dist/chunk-OQ4A3RDY.js.map +1 -0
  37. package/dist/{chunk-45Y5TLQZ.js → chunk-SH7H3WRU.js} +3 -6
  38. package/dist/chunk-SH7H3WRU.js.map +1 -0
  39. package/dist/{chunk-G74XEI7K.js → chunk-UOSTOLU7.js} +21 -21
  40. package/dist/chunk-UOSTOLU7.js.map +1 -0
  41. package/dist/{chunk-DPZLABUC.js → chunk-XTTZAQWJ.js} +28 -22
  42. package/dist/chunk-XTTZAQWJ.js.map +1 -0
  43. package/dist/{chunk-A6PWS6ZV.js → chunk-YEIJW6X6.js} +15 -5
  44. package/dist/chunk-YEIJW6X6.js.map +1 -0
  45. package/dist/chunk-YOJGSRZK.js +216 -0
  46. package/dist/chunk-YOJGSRZK.js.map +1 -0
  47. package/dist/cli/create-agent.js +1 -1
  48. package/dist/cli/main.js +636 -99
  49. package/dist/cli/main.js.map +1 -1
  50. package/dist/cli/yolo-daemon.js +21 -19
  51. package/dist/cli/yolo-daemon.js.map +1 -1
  52. package/dist/{client-BZHI675W.js → client-INNE2GGZ.js} +3 -3
  53. package/dist/{codebase-index-CR6Q2HEI.js → codebase-index-5SEOESWM.js} +4 -4
  54. package/dist/fast-analyzer-AYLZB5TW.js +216 -0
  55. package/dist/fast-analyzer-AYLZB5TW.js.map +1 -0
  56. package/dist/github-ingester-J2ZFYXVE.js +11 -0
  57. package/dist/{goal-manager-62IL6WGY.js → goal-manager-ZBWKWEML.js} +6 -6
  58. package/dist/{goal-validator-HPPBSDXD.js → goal-validator-HNXXUCPW.js} +5 -5
  59. package/dist/{graph-PAUZ5EMP.js → graph-J4OGTYCO.js} +3 -3
  60. package/dist/{hypothesis-W37VG6DA.js → hypothesis-JCUMZKTG.js} +6 -6
  61. package/dist/{incident-index-ZCDSJ42L.js → incident-index-BWW2UEY7.js} +3 -3
  62. package/dist/index.js +1168 -137
  63. package/dist/index.js.map +1 -1
  64. package/dist/{insight-store-U3NYTOJE.js → insight-store-A5XXMFD6.js} +3 -5
  65. package/dist/{issue-store-EZMBHOVN.js → issue-store-LZWZIGM7.js} +3 -3
  66. package/dist/linear-ingester-JRDQAIAA.js +11 -0
  67. package/dist/{tiered-storage-QW2G7GSG.js → tiered-storage-VZL7KK64.js} +3 -3
  68. package/dist/tiered-storage-VZL7KK64.js.map +1 -0
  69. package/dist/trie-agent-M6PHM6UD.js +26 -0
  70. package/dist/trie-agent-M6PHM6UD.js.map +1 -0
  71. package/dist/ui/chat.html +260 -67
  72. package/dist/ui/goals.html +246 -3
  73. package/dist/ui/hypotheses.html +248 -5
  74. package/dist/ui/ledger.html +252 -9
  75. package/dist/ui/nudges.html +244 -1
  76. package/package.json +15 -8
  77. package/dist/chunk-45Y5TLQZ.js.map +0 -1
  78. package/dist/chunk-4JQ6W7LW.js.map +0 -1
  79. package/dist/chunk-55CBWOEZ.js.map +0 -1
  80. package/dist/chunk-6EP2VTHC.js.map +0 -1
  81. package/dist/chunk-6VIMBFUZ.js.map +0 -1
  82. package/dist/chunk-A6PWS6ZV.js.map +0 -1
  83. package/dist/chunk-AXYNWBME.js.map +0 -1
  84. package/dist/chunk-DFPVUMVE.js.map +0 -1
  85. package/dist/chunk-DPZLABUC.js.map +0 -1
  86. package/dist/chunk-G74XEI7K.js.map +0 -1
  87. package/dist/chunk-HUR67JXG.js.map +0 -1
  88. package/dist/chunk-K6NTRSDF.js.map +0 -1
  89. package/dist/chunk-O6OTJI3W.js.map +0 -1
  90. package/dist/chunk-QM5VIDFN.js.map +0 -1
  91. package/dist/chunk-QNKBXOIQ.js.map +0 -1
  92. package/dist/chunk-R3WZI6QZ.js +0 -883
  93. package/dist/chunk-R3WZI6QZ.js.map +0 -1
  94. package/dist/chunk-Z4DN527J.js.map +0 -1
  95. package/dist/chunk-ZEXMMTIQ.js.map +0 -1
  96. package/dist/guardian-agent-YKG5XURG.js +0 -30
  97. /package/dist/{autonomy-config-QA6ATWLJ.js.map → autonomy-config-ZCOSTMPD.js.map} +0 -0
  98. /package/dist/{chat-store-HFOOWZYN.js.map → chat-store-OJLJCJFI.js.map} +0 -0
  99. /package/dist/{chunk-WHIQAGB7.js.map → chunk-4C67GV3O.js.map} +0 -0
  100. /package/dist/{client-BZHI675W.js.map → client-INNE2GGZ.js.map} +0 -0
  101. /package/dist/{codebase-index-CR6Q2HEI.js.map → codebase-index-5SEOESWM.js.map} +0 -0
  102. /package/dist/{goal-manager-62IL6WGY.js.map → github-ingester-J2ZFYXVE.js.map} +0 -0
  103. /package/dist/{goal-validator-HPPBSDXD.js.map → goal-manager-ZBWKWEML.js.map} +0 -0
  104. /package/dist/{graph-PAUZ5EMP.js.map → goal-validator-HNXXUCPW.js.map} +0 -0
  105. /package/dist/{guardian-agent-YKG5XURG.js.map → graph-J4OGTYCO.js.map} +0 -0
  106. /package/dist/{hypothesis-W37VG6DA.js.map → hypothesis-JCUMZKTG.js.map} +0 -0
  107. /package/dist/{incident-index-ZCDSJ42L.js.map → incident-index-BWW2UEY7.js.map} +0 -0
  108. /package/dist/{insight-store-U3NYTOJE.js.map → insight-store-A5XXMFD6.js.map} +0 -0
  109. /package/dist/{issue-store-EZMBHOVN.js.map → issue-store-LZWZIGM7.js.map} +0 -0
  110. /package/dist/{tiered-storage-QW2G7GSG.js.map → linear-ingester-JRDQAIAA.js.map} +0 -0
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/cli/dashboard/chat-store.ts"],"sourcesContent":["/**\n * Chat Store - Persistent storage for chat history\n * \n * Features:\n * - Save and load chat sessions\n * - List all chat sessions\n * - Archive management (rename, delete, export)\n * - Atomic writes with backup rotation\n * - Zod validation for data integrity\n * \n * Persists to: .trie/memory/chats/\n */\n\nimport { mkdir, readFile, unlink } from 'fs/promises';\nimport { existsSync } from 'fs';\nimport { join } from 'path';\nimport { getTrieDirectory } from '../../utils/workspace.js';\nimport { z } from 'zod';\nimport { atomicWriteJSON } from '../../utils/atomic-write.js';\nimport type { ChatMessage } from './types.js';\n\n// ============================================================================\n// Schemas\n// ============================================================================\n\nconst ChatMessageSchema = z.object({\n role: z.enum(['user', 'assistant']),\n content: z.string(),\n timestamp: z.number(),\n toolCalls: z.array(z.object({\n id: z.string(),\n name: z.string(),\n input: z.record(z.any()),\n })).optional(),\n pendingFix: z.object({\n id: z.string(),\n file: z.string(),\n goal: z.string(),\n violation: z.string(),\n suggestedFix: z.string().optional(),\n }).optional(),\n});\n\nconst ChatSessionSchema = z.object({\n id: z.string(),\n title: z.string(),\n messages: z.array(ChatMessageSchema),\n createdAt: z.number(),\n updatedAt: z.number(),\n archived: z.boolean(),\n});\n\nexport type ChatSession = z.infer<typeof ChatSessionSchema>;\n\nconst ChatStoreIndexSchema = z.object({\n version: z.literal(1),\n sessions: z.array(z.object({\n id: z.string(),\n title: z.string(),\n createdAt: z.number(),\n updatedAt: z.number(),\n archived: z.boolean(),\n messageCount: z.number(),\n })),\n lastUpdated: z.string(),\n});\n\ntype ChatStoreIndex = z.infer<typeof ChatStoreIndexSchema>;\n\n// ============================================================================\n// ChatStore Class\n// ============================================================================\n\nexport class ChatStore {\n private projectPath: string;\n private index: ChatStoreIndex | null = null;\n \n constructor(projectPath: string) {\n this.projectPath = projectPath;\n }\n \n /**\n * Get the chats directory path\n */\n private getChatsDir(): string {\n return join(getTrieDirectory(this.projectPath), 'memory', 'chats');\n }\n \n /**\n * Get the index file path\n */\n private getIndexPath(): string {\n return join(this.getChatsDir(), 'index.json');\n }\n \n /**\n * Get the path for a specific session file\n */\n private getSessionPath(sessionId: string): string {\n return join(this.getChatsDir(), `${sessionId}.json`);\n }\n \n /**\n * Load the index file\n */\n private async loadIndex(): Promise<ChatStoreIndex> {\n if (this.index) {\n return this.index;\n }\n \n const indexPath = this.getIndexPath();\n \n if (existsSync(indexPath)) {\n try {\n const content = await readFile(indexPath, 'utf-8');\n const parsed = JSON.parse(content);\n const result = ChatStoreIndexSchema.safeParse(parsed);\n \n if (result.success) {\n this.index = result.data;\n return this.index;\n }\n } catch (error) {\n console.error('Failed to load chat index:', error);\n }\n }\n \n // Create empty index\n this.index = {\n version: 1,\n sessions: [],\n lastUpdated: new Date().toISOString(),\n };\n \n return this.index;\n }\n \n /**\n * Save the index file\n */\n private async saveIndex(): Promise<void> {\n if (!this.index) return;\n \n const indexPath = this.getIndexPath();\n const chatsDir = this.getChatsDir();\n \n // Ensure directory exists\n await mkdir(chatsDir, { recursive: true });\n \n // Update timestamp\n this.index.lastUpdated = new Date().toISOString();\n \n // Atomic write\n await atomicWriteJSON(indexPath, this.index);\n }\n \n /**\n * Generate a unique session ID\n */\n private generateSessionId(): string {\n return `chat-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;\n }\n \n /**\n * Generate a default title from the first user message\n */\n private generateTitle(messages: ChatMessage[]): string {\n const firstUser = messages.find(m => m.role === 'user');\n if (firstUser) {\n const text = firstUser.content.trim();\n const maxLen = 50;\n if (text.length > maxLen) {\n return text.slice(0, maxLen) + '...';\n }\n return text;\n }\n return 'New Chat';\n }\n \n /**\n * Save a chat session\n */\n async saveSession(messages: ChatMessage[], sessionId?: string, title?: string): Promise<string> {\n await this.loadIndex();\n \n const id = sessionId || this.generateSessionId();\n const now = Date.now();\n \n // Load existing session if updating\n let createdAt = now;\n if (sessionId) {\n const existing = this.index!.sessions.find(s => s.id === sessionId);\n if (existing) {\n createdAt = existing.createdAt;\n }\n }\n \n const session: ChatSession = {\n id,\n title: title || this.generateTitle(messages),\n messages,\n createdAt,\n updatedAt: now,\n archived: false,\n };\n \n // Validate\n const result = ChatSessionSchema.safeParse(session);\n if (!result.success) {\n throw new Error(`Invalid chat session: ${result.error.message}`);\n }\n \n // Save session file\n const sessionPath = this.getSessionPath(id);\n await mkdir(this.getChatsDir(), { recursive: true });\n await atomicWriteJSON(sessionPath, session);\n \n // Update index\n const existingIndex = this.index!.sessions.findIndex(s => s.id === id);\n const indexEntry = {\n id,\n title: session.title,\n createdAt: session.createdAt,\n updatedAt: session.updatedAt,\n archived: session.archived,\n messageCount: messages.length,\n };\n \n if (existingIndex >= 0) {\n this.index!.sessions[existingIndex] = indexEntry;\n } else {\n this.index!.sessions.unshift(indexEntry);\n }\n \n await this.saveIndex();\n \n return id;\n }\n \n /**\n * Load a chat session\n */\n async loadSession(sessionId: string): Promise<ChatSession | null> {\n const sessionPath = this.getSessionPath(sessionId);\n \n if (!existsSync(sessionPath)) {\n return null;\n }\n \n try {\n const content = await readFile(sessionPath, 'utf-8');\n const parsed = JSON.parse(content);\n const result = ChatSessionSchema.safeParse(parsed);\n \n if (result.success) {\n return result.data;\n }\n \n console.error('Invalid chat session:', result.error.message);\n return null;\n } catch (error) {\n console.error('Failed to load chat session:', error);\n return null;\n }\n }\n \n /**\n * List all chat sessions\n */\n async listSessions(includeArchived: boolean = false): Promise<ChatStoreIndex['sessions']> {\n await this.loadIndex();\n \n let sessions = this.index!.sessions;\n \n if (!includeArchived) {\n sessions = sessions.filter(s => !s.archived);\n }\n \n // Sort by most recent first\n return sessions.sort((a, b) => b.updatedAt - a.updatedAt);\n }\n \n /**\n * Delete a chat session\n */\n async deleteSession(sessionId: string): Promise<boolean> {\n await this.loadIndex();\n \n const sessionPath = this.getSessionPath(sessionId);\n \n if (!existsSync(sessionPath)) {\n return false;\n }\n \n try {\n await unlink(sessionPath);\n \n // Remove from index\n this.index!.sessions = this.index!.sessions.filter(s => s.id !== sessionId);\n await this.saveIndex();\n \n return true;\n } catch (error) {\n console.error('Failed to delete chat session:', error);\n return false;\n }\n }\n \n /**\n * Rename a chat session\n */\n async renameSession(sessionId: string, newTitle: string): Promise<boolean> {\n await this.loadIndex();\n \n const session = await this.loadSession(sessionId);\n if (!session) {\n return false;\n }\n \n session.title = newTitle;\n session.updatedAt = Date.now();\n \n // Save updated session\n const sessionPath = this.getSessionPath(sessionId);\n await atomicWriteJSON(sessionPath, session);\n \n // Update index\n const indexEntry = this.index!.sessions.find(s => s.id === sessionId);\n if (indexEntry) {\n indexEntry.title = newTitle;\n indexEntry.updatedAt = session.updatedAt;\n await this.saveIndex();\n }\n \n return true;\n }\n \n /**\n * Archive a chat session\n */\n async archiveSession(sessionId: string): Promise<boolean> {\n await this.loadIndex();\n \n const session = await this.loadSession(sessionId);\n if (!session) {\n return false;\n }\n \n session.archived = true;\n session.updatedAt = Date.now();\n \n // Save updated session\n const sessionPath = this.getSessionPath(sessionId);\n await atomicWriteJSON(sessionPath, session);\n \n // Update index\n const indexEntry = this.index!.sessions.find(s => s.id === sessionId);\n if (indexEntry) {\n indexEntry.archived = true;\n indexEntry.updatedAt = session.updatedAt;\n await this.saveIndex();\n }\n \n return true;\n }\n \n /**\n * Unarchive a chat session\n */\n async unarchiveSession(sessionId: string): Promise<boolean> {\n await this.loadIndex();\n \n const session = await this.loadSession(sessionId);\n if (!session) {\n return false;\n }\n \n session.archived = false;\n session.updatedAt = Date.now();\n \n // Save updated session\n const sessionPath = this.getSessionPath(sessionId);\n await atomicWriteJSON(sessionPath, session);\n \n // Update index\n const indexEntry = this.index!.sessions.find(s => s.id === sessionId);\n if (indexEntry) {\n indexEntry.archived = false;\n indexEntry.updatedAt = session.updatedAt;\n await this.saveIndex();\n }\n \n return true;\n }\n \n /**\n * Export a chat session as JSON\n */\n async exportSession(sessionId: string): Promise<string | null> {\n const session = await this.loadSession(sessionId);\n if (!session) {\n return null;\n }\n \n return JSON.stringify(session, null, 2);\n }\n \n /**\n * Get statistics about chat sessions\n */\n async getStats(): Promise<{\n total: number;\n active: number;\n archived: number;\n totalMessages: number;\n }> {\n await this.loadIndex();\n \n const total = this.index!.sessions.length;\n const archived = this.index!.sessions.filter(s => s.archived).length;\n const active = total - archived;\n const totalMessages = this.index!.sessions.reduce((sum, s) => sum + s.messageCount, 0);\n \n return { total, active, archived, totalMessages };\n }\n \n /**\n * Prune old sessions (older than N days)\n */\n async pruneOldSessions(daysToKeep: number = 90): Promise<number> {\n await this.loadIndex();\n \n const cutoff = Date.now() - (daysToKeep * 24 * 60 * 60 * 1000);\n const toDelete = this.index!.sessions.filter(s => s.updatedAt < cutoff);\n \n for (const session of toDelete) {\n await this.deleteSession(session.id);\n }\n \n return toDelete.length;\n }\n}\n\n// ============================================================================\n// Singleton Management\n// ============================================================================\n\nconst chatStores: Map<string, ChatStore> = new Map();\n\n/**\n * Get the ChatStore for a project (singleton per project)\n */\nexport function getChatStore(projectPath: string): ChatStore {\n let store = chatStores.get(projectPath);\n if (!store) {\n store = new ChatStore(projectPath);\n chatStores.set(projectPath, store);\n }\n return store;\n}\n\n/**\n * Clear all ChatStore instances (for testing)\n */\nexport function clearChatStores(): void {\n chatStores.clear();\n}\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/guardian/hypothesis.ts"],"sourcesContent":["/**\n * Hypothesis System - Self-improving hypothesis generation and validation\n * \n * Features:\n * - Generate hypotheses from patterns\n * - Track evidence for/against hypotheses\n * - Auto-validate/invalidate based on evidence\n * - Adjust confidence over time\n * - Learn from hypothesis outcomes\n */\n\nimport type { Hypothesis } from './guardian-state.js';\nimport { getProjectState } from './guardian-state.js';\nimport { getInsightStore, type GuardianInsight } from './insight-store.js';\nimport { searchIssues } from '../memory/issue-store.js';\nimport { dirname } from 'path';\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Hypothesis template for auto-generation\n */\nexport interface HypothesisTemplate {\n category: 'timing' | 'pattern' | 'team' | 'code' | 'general';\n statement: string;\n testCriteria: string;\n minConfidence: number;\n dataRequired: string[];\n}\n\n/**\n * Evidence for a hypothesis\n */\nexport interface HypothesisEvidence {\n type: 'supporting' | 'contradicting';\n description: string;\n weight: number; // 0-1\n timestamp: string;\n}\n\n/**\n * Hypothesis analysis result\n */\nexport interface HypothesisAnalysis {\n hypothesis: Hypothesis;\n recentEvidence: HypothesisEvidence[];\n confidenceChange: number;\n statusChange?: 'validated' | 'invalidated';\n actionRequired: boolean;\n}\n\n// ============================================================================\n// Hypothesis Templates\n// ============================================================================\n\nconst HYPOTHESIS_TEMPLATES: HypothesisTemplate[] = [\n {\n category: 'timing',\n statement: 'Issues spike after weekend deployments',\n testCriteria: 'Compare Monday issue counts to other days',\n minConfidence: 0.3,\n dataRequired: ['issue_timestamps', 'deployment_data'],\n },\n {\n category: 'timing',\n statement: 'Code quality declines on Fridays',\n testCriteria: 'Compare Friday issue introduction rate to weekly average',\n minConfidence: 0.3,\n dataRequired: ['issue_timestamps'],\n },\n {\n category: 'pattern',\n statement: 'Auth-related code has the highest incident rate',\n testCriteria: 'Compare auth/ issue count to other directories',\n minConfidence: 0.4,\n dataRequired: ['issue_files'],\n },\n {\n category: 'pattern',\n statement: 'Security issues cluster in specific directories',\n testCriteria: 'Check if security issues are concentrated (>50% in <3 dirs)',\n minConfidence: 0.4,\n dataRequired: ['issue_files', 'issue_agents'],\n },\n {\n category: 'code',\n statement: 'Files with multiple authors have more issues',\n testCriteria: 'Correlate file author count with issue count',\n minConfidence: 0.4,\n dataRequired: ['issue_files', 'git_blame'],\n },\n {\n category: 'code',\n statement: 'Recently modified files are more likely to have issues',\n testCriteria: 'Compare issue rate for recent vs old files',\n minConfidence: 0.3,\n dataRequired: ['issue_timestamps', 'file_modification_times'],\n },\n {\n category: 'pattern',\n statement: 'Critical issues often come in clusters',\n testCriteria: 'Check temporal clustering of critical issues',\n minConfidence: 0.3,\n dataRequired: ['issue_timestamps', 'issue_severities'],\n },\n];\n\n// ============================================================================\n// HypothesisEngine Class\n// ============================================================================\n\n/**\n * Engine for generating and validating hypotheses\n */\nexport class HypothesisEngine {\n private projectPath: string;\n private projectState;\n private insightStore;\n \n constructor(projectPath: string) {\n this.projectPath = projectPath;\n this.projectState = getProjectState(projectPath);\n this.insightStore = getInsightStore(projectPath);\n }\n \n /**\n * Create a new hypothesis\n */\n async createHypothesis(statement: string, options?: {\n category?: Hypothesis['category'];\n testCriteria?: string;\n initialConfidence?: number;\n }): Promise<Hypothesis> {\n const hypothesis: Hypothesis = {\n id: `hyp-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,\n statement,\n confidence: options?.initialConfidence ?? 0.5,\n status: 'proposed',\n evidence: [],\n createdAt: new Date().toISOString(),\n updatedAt: new Date().toISOString(),\n testCriteria: options?.testCriteria,\n category: options?.category ?? 'general',\n };\n \n await this.projectState.addHypothesis(hypothesis);\n \n return hypothesis;\n }\n \n /**\n * Auto-generate hypotheses based on detected patterns\n */\n async autoGenerateHypotheses(): Promise<Hypothesis[]> {\n const generated: Hypothesis[] = [];\n \n try {\n // Get existing hypotheses to avoid duplicates\n await this.projectState.load();\n const existing = this.projectState.getAllHypotheses();\n const existingStatements = new Set(existing.map(h => h.statement.toLowerCase()));\n \n // Get data for pattern detection\n const issues = await searchIssues('', {\n workDir: this.projectPath,\n limit: 500,\n includeResolved: true,\n });\n \n if (issues.length < 10) {\n return generated; // Not enough data\n }\n \n // Check each template for applicability\n for (const template of HYPOTHESIS_TEMPLATES) {\n // Skip if already have similar hypothesis\n if (existingStatements.has(template.statement.toLowerCase())) {\n continue;\n }\n \n // Check if we have enough evidence to propose this hypothesis\n const evidence = await this.gatherInitialEvidence(template, issues);\n \n if (evidence.length > 0 && evidence[0]!.weight >= template.minConfidence) {\n const hypothesis = await this.createHypothesis(template.statement, {\n category: template.category,\n testCriteria: template.testCriteria,\n initialConfidence: evidence[0]!.weight,\n });\n \n // Add initial evidence\n for (const e of evidence) {\n await this.projectState.addEvidence(hypothesis.id, e);\n }\n \n generated.push(hypothesis);\n \n // Limit to 2 new hypotheses per run\n if (generated.length >= 2) break;\n }\n }\n \n } catch (error) {\n console.error('Failed to auto-generate hypotheses:', error);\n }\n \n return generated;\n }\n \n /**\n * Use Claude AI to generate novel hypotheses from observed patterns\n * This enables fully agentic hypothesis creation based on actual codebase observations\n */\n async generateHypothesesWithAI(context: {\n recentIssues?: any[];\n patterns?: string[];\n observations?: string[];\n }): Promise<Hypothesis[]> {\n const { isAIAvailable, runAIAnalysis } = await import('../ai/client.js');\n \n if (!isAIAvailable()) {\n return []; // Fall back to template-based generation\n }\n \n const generated: Hypothesis[] = [];\n \n try {\n // Get existing hypotheses to avoid duplicates\n await this.projectState.load();\n const existing = this.projectState.getAllHypotheses();\n const existingStatements = existing.map(h => h.statement);\n \n // Get recent issue data\n const issues = context.recentIssues || await searchIssues('', {\n workDir: this.projectPath,\n limit: 100,\n includeResolved: true,\n });\n \n if (issues.length < 5) {\n return generated; // Not enough data for AI\n }\n \n // Build context for Claude\n const issuesSummary = this.summarizeIssuesForAI(issues);\n const patternsSummary = context.patterns?.join('\\n') || 'No explicit patterns provided';\n const observationsSummary = context.observations?.join('\\n') || 'No explicit observations provided';\n \n const prompt = `You are an AI agent observing a codebase over time. Based on the patterns below, generate 1-3 testable hypotheses about this codebase's quality patterns.\n\n## Recent Issues Summary\n${issuesSummary}\n\n## Observed Patterns\n${patternsSummary}\n\n## Additional Observations\n${observationsSummary}\n\n## Existing Hypotheses (avoid duplicates)\n${existingStatements.length > 0 ? existingStatements.map(s => `- ${s}`).join('\\n') : 'None yet'}\n\nGenerate hypotheses that are:\n1. Specific and testable (can be validated with data)\n2. Actionable (if validated, can guide improvements)\n3. Novel (not duplicates of existing hypotheses)\n4. Based on real patterns in the data above\n\nReturn ONLY a JSON array of hypotheses. Each hypothesis must have:\n- \"statement\": Clear, concise hypothesis statement\n- \"category\": One of: \"timing\", \"pattern\", \"team\", \"code\", \"general\"\n- \"testCriteria\": How to test this hypothesis\n- \"confidence\": Initial confidence (0-1)\n- \"reasoning\": Why you think this hypothesis is worth testing\n\nExample format:\n[\n {\n \"statement\": \"Authentication code changes correlate with security issues\",\n \"category\": \"pattern\",\n \"testCriteria\": \"Track auth file changes and subsequent security issue rates\",\n \"confidence\": 0.6,\n \"reasoning\": \"65% of security issues occur in files modified in the past week\"\n }\n]\n\nReturn empty array [] if no novel hypotheses can be generated from the data.`;\n \n const result = await runAIAnalysis({\n systemPrompt: 'You are an expert code quality analyst who identifies patterns and generates testable hypotheses.',\n userPrompt: prompt,\n maxTokens: 1024,\n temperature: 0.7, // Higher temperature for creative hypothesis generation\n });\n \n if (!result.success || !result.content.trim()) {\n return generated;\n }\n \n // Parse AI response\n let aiHypotheses: Array<{\n statement: string;\n category: Hypothesis['category'];\n testCriteria: string;\n confidence: number;\n reasoning: string;\n }> = [];\n \n try {\n const cleaned = result.content.replace(/```json?\\n?|\\n?```/g, '').trim();\n aiHypotheses = JSON.parse(cleaned);\n if (!Array.isArray(aiHypotheses)) aiHypotheses = [];\n } catch {\n return generated; // AI response wasn't valid JSON\n }\n \n // Create hypotheses from AI suggestions\n for (const aiHypo of aiHypotheses.slice(0, 3)) {\n // Check for duplicates\n const isDuplicate = existingStatements.some(existing => \n existing.toLowerCase().includes(aiHypo.statement.toLowerCase().slice(0, 30))\n );\n \n if (isDuplicate) continue;\n \n const hypothesis = await this.createHypothesis(aiHypo.statement, {\n category: aiHypo.category,\n testCriteria: aiHypo.testCriteria,\n initialConfidence: Math.max(0.3, Math.min(0.7, aiHypo.confidence)),\n });\n \n // Add AI reasoning as initial evidence\n await this.projectState.addEvidence(hypothesis.id, {\n type: 'supporting',\n description: `AI observed: ${aiHypo.reasoning}`,\n weight: aiHypo.confidence,\n });\n \n generated.push(hypothesis);\n }\n \n } catch (error) {\n console.error('Failed to generate hypotheses with AI:', error);\n }\n \n return generated;\n }\n \n /**\n * Summarize issues for AI context\n */\n private summarizeIssuesForAI(issues: Array<{ issue: any; score: number }>): string {\n const totalIssues = issues.length;\n \n // Severity breakdown\n const severityCounts: Record<string, number> = {};\n for (const { issue } of issues) {\n severityCounts[issue.severity] = (severityCounts[issue.severity] || 0) + 1;\n }\n \n // Agent breakdown\n const agentCounts: Record<string, number> = {};\n for (const { issue } of issues) {\n agentCounts[issue.agent] = (agentCounts[issue.agent] || 0) + 1;\n }\n \n // File/directory patterns\n const fileCounts: Record<string, number> = {};\n for (const { issue } of issues) {\n const dir = dirname(issue.file);\n fileCounts[dir] = (fileCounts[dir] || 0) + 1;\n }\n \n // Time patterns\n const dayOfWeekCounts: Record<number, number> = {};\n for (const { issue } of issues) {\n const date = new Date(issue.timestamp);\n const day = date.getDay();\n dayOfWeekCounts[day] = (dayOfWeekCounts[day] || 0) + 1;\n }\n \n const dayNames = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];\n const dayDistribution = Object.entries(dayOfWeekCounts)\n .sort(([a], [b]) => Number(a) - Number(b))\n .map(([day, count]) => `${dayNames[Number(day)]}: ${count}`)\n .join(', ');\n \n const topDirs = Object.entries(fileCounts)\n .sort(([, a], [, b]) => b - a)\n .slice(0, 5)\n .map(([dir, count]) => `${dir}: ${count}`)\n .join(', ');\n \n const topAgents = Object.entries(agentCounts)\n .sort(([, a], [, b]) => b - a)\n .slice(0, 5)\n .map(([agent, count]) => `${agent}: ${count}`)\n .join(', ');\n \n return `Total Issues: ${totalIssues}\nSeverities: ${Object.entries(severityCounts).map(([s, c]) => `${s}=${c}`).join(', ')}\nTop Agents: ${topAgents}\nTop Directories: ${topDirs}\nDay Distribution: ${dayDistribution}`;\n }\n \n /**\n * Gather initial evidence for a hypothesis template\n */\n private async gatherInitialEvidence(\n template: HypothesisTemplate,\n issues: Array<{ issue: any; score: number }>\n ): Promise<HypothesisEvidence[]> {\n const evidence: HypothesisEvidence[] = [];\n \n switch (template.category) {\n case 'timing':\n evidence.push(...this.analyzeTimingPatterns(template, issues));\n break;\n case 'pattern':\n evidence.push(...this.analyzeLocationPatterns(template, issues));\n break;\n case 'code':\n evidence.push(...this.analyzeCodePatterns(template, issues));\n break;\n }\n \n return evidence;\n }\n \n /**\n * Analyze timing patterns in issues\n */\n private analyzeTimingPatterns(\n template: HypothesisTemplate,\n issues: Array<{ issue: any; score: number }>\n ): HypothesisEvidence[] {\n const evidence: HypothesisEvidence[] = [];\n \n // Analyze day-of-week patterns\n const dayOfWeekCounts: Record<number, number> = {};\n for (const { issue } of issues) {\n const date = new Date(issue.timestamp);\n const day = date.getDay();\n dayOfWeekCounts[day] = (dayOfWeekCounts[day] || 0) + 1;\n }\n \n // Check for Friday pattern\n if (template.statement.includes('Friday')) {\n const fridayCount = dayOfWeekCounts[5] || 0;\n const avgOtherDays = (Object.values(dayOfWeekCounts).reduce((a, b) => a + b, 0) - fridayCount) / 4;\n \n if (fridayCount > avgOtherDays * 1.5) {\n evidence.push({\n type: 'supporting',\n description: `Friday has ${((fridayCount / avgOtherDays - 1) * 100).toFixed(0)}% more issues than average`,\n weight: Math.min(0.8, 0.3 + (fridayCount / avgOtherDays - 1) * 0.2),\n timestamp: new Date().toISOString(),\n });\n } else {\n evidence.push({\n type: 'contradicting',\n description: 'Friday issue count is not significantly higher',\n weight: 0.3,\n timestamp: new Date().toISOString(),\n });\n }\n }\n \n // Check for Monday/weekend pattern\n if (template.statement.includes('weekend') || template.statement.includes('Monday')) {\n const mondayCount = dayOfWeekCounts[1] || 0;\n const avgOtherDays = (Object.values(dayOfWeekCounts).reduce((a, b) => a + b, 0) - mondayCount) / 4;\n \n if (mondayCount > avgOtherDays * 1.5) {\n evidence.push({\n type: 'supporting',\n description: `Monday has ${((mondayCount / avgOtherDays - 1) * 100).toFixed(0)}% more issues than average`,\n weight: Math.min(0.8, 0.3 + (mondayCount / avgOtherDays - 1) * 0.2),\n timestamp: new Date().toISOString(),\n });\n }\n }\n \n return evidence;\n }\n \n /**\n * Analyze location patterns in issues\n */\n private analyzeLocationPatterns(\n template: HypothesisTemplate,\n issues: Array<{ issue: any; score: number }>\n ): HypothesisEvidence[] {\n const evidence: HypothesisEvidence[] = [];\n \n // Analyze directory distribution\n const dirCounts: Record<string, number> = {};\n for (const { issue } of issues) {\n const dir = dirname(issue.file);\n dirCounts[dir] = (dirCounts[dir] || 0) + 1;\n }\n \n const sortedDirs = Object.entries(dirCounts)\n .sort(([, a], [, b]) => b - a);\n \n // Check for auth pattern\n if (template.statement.includes('Auth')) {\n const authDirs = sortedDirs.filter(([dir]) => \n dir.toLowerCase().includes('auth') || \n dir.toLowerCase().includes('login') ||\n dir.toLowerCase().includes('session')\n );\n \n const authCount = authDirs.reduce((sum, [, count]) => sum + count, 0);\n const percentage = (authCount / issues.length) * 100;\n \n if (percentage >= 20) {\n evidence.push({\n type: 'supporting',\n description: `Auth-related code has ${percentage.toFixed(0)}% of issues`,\n weight: Math.min(0.85, 0.4 + percentage / 100),\n timestamp: new Date().toISOString(),\n });\n }\n }\n \n // Check for clustering pattern\n if (template.statement.includes('cluster')) {\n const topThreeDirs = sortedDirs.slice(0, 3);\n const topThreeCount = topThreeDirs.reduce((sum, [, count]) => sum + count, 0);\n const percentage = (topThreeCount / issues.length) * 100;\n \n if (percentage >= 50) {\n evidence.push({\n type: 'supporting',\n description: `Top 3 directories have ${percentage.toFixed(0)}% of issues`,\n weight: Math.min(0.8, 0.3 + percentage / 100),\n timestamp: new Date().toISOString(),\n });\n }\n }\n \n return evidence;\n }\n \n /**\n * Analyze code patterns\n */\n private analyzeCodePatterns(\n template: HypothesisTemplate,\n issues: Array<{ issue: any; score: number }>\n ): HypothesisEvidence[] {\n const evidence: HypothesisEvidence[] = [];\n \n // Analyze temporal clustering (critical issues in bursts)\n if (template.statement.includes('cluster')) {\n const criticalIssues = issues.filter(r => r.issue.severity === 'critical');\n \n if (criticalIssues.length >= 3) {\n // Check if critical issues are clustered in time\n const timestamps = criticalIssues\n .map(r => new Date(r.issue.timestamp).getTime())\n .sort((a, b) => a - b);\n \n let clusteredCount = 0;\n for (let i = 1; i < timestamps.length; i++) {\n // If within 24 hours of previous\n if (timestamps[i]! - timestamps[i - 1]! < 24 * 60 * 60 * 1000) {\n clusteredCount++;\n }\n }\n \n const clusterRatio = clusteredCount / (timestamps.length - 1);\n \n if (clusterRatio >= 0.5) {\n evidence.push({\n type: 'supporting',\n description: `${(clusterRatio * 100).toFixed(0)}% of critical issues occur within 24h of another`,\n weight: Math.min(0.75, 0.3 + clusterRatio * 0.4),\n timestamp: new Date().toISOString(),\n });\n }\n }\n }\n \n return evidence;\n }\n \n /**\n * Update confidence scores based on new data\n */\n async updateConfidenceFromOutcomes(): Promise<HypothesisAnalysis[]> {\n const analyses: HypothesisAnalysis[] = [];\n \n try {\n await this.projectState.load();\n const activeHypotheses = this.projectState.getActiveHypotheses();\n \n for (const hypothesis of activeHypotheses) {\n const analysis = await this.analyzeHypothesis(hypothesis);\n analyses.push(analysis);\n \n // Create insight if hypothesis was validated or invalidated\n if (analysis.statusChange && this.insightStore.canCreateInsight('hypothesis-update')) {\n const insight = this.createHypothesisInsight(analysis);\n await this.insightStore.addInsight(insight);\n await this.insightStore.markInsightCreated('hypothesis-update');\n }\n }\n \n // Update hypothesis accuracy metric\n await this.projectState.updateHypothesisAccuracy();\n \n } catch (error) {\n console.error('Failed to update hypothesis confidence:', error);\n }\n \n return analyses;\n }\n \n /**\n * Analyze a single hypothesis\n */\n private async analyzeHypothesis(hypothesis: Hypothesis): Promise<HypothesisAnalysis> {\n // Get recent issues for new evidence\n const issues = await searchIssues('', {\n workDir: this.projectPath,\n limit: 100,\n includeResolved: false,\n });\n \n // Find the matching template\n const template = HYPOTHESIS_TEMPLATES.find(t => \n t.statement.toLowerCase() === hypothesis.statement.toLowerCase()\n );\n \n const recentEvidence: HypothesisEvidence[] = [];\n \n if (template) {\n recentEvidence.push(...await this.gatherInitialEvidence(template, issues));\n } else {\n // For user-created hypotheses, use semantic evidence gathering\n recentEvidence.push(...this.gatherSemanticEvidence(hypothesis, issues));\n }\n \n // Calculate confidence change\n const oldConfidence = hypothesis.confidence;\n let newConfidence = oldConfidence;\n \n for (const evidence of recentEvidence) {\n if (evidence.type === 'supporting') {\n newConfidence = Math.min(1, newConfidence + evidence.weight * 0.1);\n } else {\n newConfidence = Math.max(0, newConfidence - evidence.weight * 0.1);\n }\n }\n \n // Determine status change\n let statusChange: 'validated' | 'invalidated' | undefined;\n \n if (newConfidence >= 0.8 && hypothesis.evidence.length >= 3) {\n statusChange = 'validated';\n await this.projectState.updateHypothesis(hypothesis.id, {\n status: 'validated',\n confidence: newConfidence,\n validatedAt: new Date().toISOString(),\n });\n } else if (newConfidence <= 0.2 && hypothesis.evidence.length >= 3) {\n statusChange = 'invalidated';\n await this.projectState.updateHypothesis(hypothesis.id, {\n status: 'invalidated',\n confidence: newConfidence,\n });\n } else {\n // Just update confidence\n await this.projectState.updateHypothesis(hypothesis.id, {\n confidence: newConfidence,\n });\n }\n \n // Add new evidence\n for (const evidence of recentEvidence) {\n await this.projectState.addEvidence(hypothesis.id, evidence);\n }\n \n const analysis: HypothesisAnalysis = {\n hypothesis: { ...hypothesis, confidence: newConfidence },\n recentEvidence,\n confidenceChange: newConfidence - oldConfidence,\n actionRequired: statusChange !== undefined,\n };\n \n if (statusChange) {\n analysis.statusChange = statusChange;\n }\n \n return analysis;\n }\n \n /**\n * Gather evidence for user-created hypotheses using semantic matching\n * \n * This enables agentic tracking for natural language hypotheses like:\n * - \"Mondays have more bugs than Fridays\"\n * - \"Code reviews reduce bug rate\"\n * - \"Security issues cluster in auth code\"\n */\n private gatherSemanticEvidence(\n hypothesis: Hypothesis,\n issues: Array<{ issue: any; score: number }>\n ): HypothesisEvidence[] {\n const evidence: HypothesisEvidence[] = [];\n const stmt = hypothesis.statement.toLowerCase();\n \n // Time-based hypotheses (days of week patterns)\n if (stmt.includes('monday') || stmt.includes('friday') || stmt.includes('weekend') ||\n stmt.includes('morning') || stmt.includes('afternoon')) {\n const dayNames = ['sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday'];\n const dayOfWeekCounts: Record<number, number> = { 0: 0, 1: 0, 2: 0, 3: 0, 4: 0, 5: 0, 6: 0 };\n \n for (const { issue } of issues) {\n const date = new Date(issue.timestamp);\n const day = date.getDay();\n dayOfWeekCounts[day] = (dayOfWeekCounts[day] || 0) + 1;\n }\n \n const totalIssues = Object.values(dayOfWeekCounts).reduce((a, b) => a + b, 0);\n const avgPerDay = totalIssues / 7;\n \n // Check each day mentioned\n for (let dayIdx = 0; dayIdx < 7; dayIdx++) {\n const dayName = dayNames[dayIdx]!;\n if (stmt.includes(dayName)) {\n const dayCount = dayOfWeekCounts[dayIdx] || 0;\n \n if (stmt.includes('more') || stmt.includes('higher') || stmt.includes('spike')) {\n // Testing if this day has MORE issues\n if (dayCount > avgPerDay * 1.3) {\n evidence.push({\n type: 'supporting',\n description: `${dayName.charAt(0).toUpperCase() + dayName.slice(1)} has ${dayCount} issues (${((dayCount/avgPerDay - 1) * 100).toFixed(0)}% above average)`,\n weight: Math.min(0.7, 0.3 + (dayCount / avgPerDay - 1) * 0.3),\n timestamp: new Date().toISOString(),\n });\n } else {\n evidence.push({\n type: 'contradicting',\n description: `${dayName.charAt(0).toUpperCase() + dayName.slice(1)} has average or below average issue count`,\n weight: 0.3,\n timestamp: new Date().toISOString(),\n });\n }\n } else if (stmt.includes('fewer') || stmt.includes('less') || stmt.includes('reduce')) {\n // Testing if this day has FEWER issues\n if (dayCount < avgPerDay * 0.7) {\n evidence.push({\n type: 'supporting',\n description: `${dayName.charAt(0).toUpperCase() + dayName.slice(1)} has ${dayCount} issues (${((1 - dayCount/avgPerDay) * 100).toFixed(0)}% below average)`,\n weight: Math.min(0.7, 0.3 + (1 - dayCount / avgPerDay) * 0.3),\n timestamp: new Date().toISOString(),\n });\n }\n }\n }\n }\n }\n \n // Code review hypotheses\n if (stmt.includes('review') || stmt.includes('pr') || stmt.includes('pull request')) {\n // Look for patterns in reviewed vs unreviewed code (approximated by commit patterns)\n const recentIssues = issues.slice(0, 30); // Most recent\n const olderIssues = issues.slice(30); // Older\n \n if (recentIssues.length >= 10 && olderIssues.length >= 10) {\n const recentRate = recentIssues.length;\n const olderRate = olderIssues.length;\n \n if (stmt.includes('reduce') || stmt.includes('fewer') || stmt.includes('less')) {\n if (recentRate < olderRate) {\n evidence.push({\n type: 'supporting',\n description: `Recent period has ${((1 - recentRate/olderRate) * 100).toFixed(0)}% fewer issues`,\n weight: Math.min(0.6, 0.3 + (1 - recentRate/olderRate) * 0.3),\n timestamp: new Date().toISOString(),\n });\n } else {\n evidence.push({\n type: 'contradicting',\n description: `Issue rate has not decreased recently`,\n weight: 0.2,\n timestamp: new Date().toISOString(),\n });\n }\n }\n }\n }\n \n // Directory/location clustering hypotheses\n if (stmt.includes('cluster') || stmt.includes('concentrate') || stmt.includes('auth') ||\n stmt.includes('specific') || stmt.includes('certain files')) {\n const dirCounts: Record<string, number> = {};\n for (const { issue } of issues) {\n const dir = dirname(issue.file);\n dirCounts[dir] = (dirCounts[dir] || 0) + 1;\n }\n \n const sortedDirs = Object.entries(dirCounts).sort(([, a], [, b]) => b - a);\n const topThreeCount = sortedDirs.slice(0, 3).reduce((sum, [, count]) => sum + count, 0);\n const totalCount = issues.length;\n const concentration = topThreeCount / totalCount;\n \n if (concentration >= 0.5) {\n evidence.push({\n type: 'supporting',\n description: `Top 3 directories have ${(concentration * 100).toFixed(0)}% of issues (concentrated)`,\n weight: Math.min(0.7, 0.3 + concentration * 0.4),\n timestamp: new Date().toISOString(),\n });\n } else {\n evidence.push({\n type: 'contradicting',\n description: `Issues are distributed across many directories`,\n weight: 0.3,\n timestamp: new Date().toISOString(),\n });\n }\n }\n \n // Severity trend hypotheses\n if (stmt.includes('critical') || stmt.includes('security') || stmt.includes('severity')) {\n const criticalCount = issues.filter(r => r.issue.severity === 'critical').length;\n const seriousCount = issues.filter(r => r.issue.severity === 'serious').length;\n const highSeverityRatio = (criticalCount + seriousCount) / issues.length;\n \n if (stmt.includes('increase') || stmt.includes('more') || stmt.includes('rise')) {\n if (highSeverityRatio > 0.3) {\n evidence.push({\n type: 'supporting',\n description: `${(highSeverityRatio * 100).toFixed(0)}% of issues are high severity`,\n weight: Math.min(0.7, 0.3 + highSeverityRatio),\n timestamp: new Date().toISOString(),\n });\n }\n } else if (stmt.includes('decrease') || stmt.includes('fewer') || stmt.includes('reduce')) {\n if (highSeverityRatio < 0.2) {\n evidence.push({\n type: 'supporting',\n description: `Only ${(highSeverityRatio * 100).toFixed(0)}% of issues are high severity`,\n weight: 0.5,\n timestamp: new Date().toISOString(),\n });\n }\n }\n }\n \n // Agent/skill specific hypotheses\n const agents = ['security', 'performance', 'accessibility', 'test', 'typecheck', 'bug-finding'];\n for (const agent of agents) {\n if (stmt.includes(agent) || stmt.includes(agent.replace('-', ' '))) {\n const agentIssues = issues.filter(r => r.issue.agent === agent);\n const agentRatio = agentIssues.length / issues.length;\n \n if (stmt.includes('most') || stmt.includes('majority') || stmt.includes('main')) {\n if (agentRatio > 0.4) {\n evidence.push({\n type: 'supporting',\n description: `${agent} accounts for ${(agentRatio * 100).toFixed(0)}% of issues`,\n weight: Math.min(0.7, 0.3 + agentRatio),\n timestamp: new Date().toISOString(),\n });\n } else {\n evidence.push({\n type: 'contradicting',\n description: `${agent} only accounts for ${(agentRatio * 100).toFixed(0)}% of issues`,\n weight: 0.3,\n timestamp: new Date().toISOString(),\n });\n }\n }\n }\n }\n \n return evidence;\n }\n \n /**\n * Create an insight for hypothesis status change\n */\n private createHypothesisInsight(analysis: HypothesisAnalysis): GuardianInsight {\n const isValidated = analysis.statusChange === 'validated';\n \n return {\n id: `insight-hyp-${analysis.hypothesis.id}`,\n type: isValidated ? 'celebration' : 'observation',\n message: isValidated\n ? `Hypothesis confirmed: \"${analysis.hypothesis.statement}\"`\n : `Hypothesis disproven: \"${analysis.hypothesis.statement}\"`,\n context: `Confidence: ${(analysis.hypothesis.confidence * 100).toFixed(0)}%. ${analysis.recentEvidence.length} evidence points analyzed.`,\n relatedIssues: [],\n priority: 5,\n timestamp: Date.now(),\n dismissed: false,\n category: 'pattern',\n details: {\n examples: analysis.recentEvidence.map(e => `${e.type}: ${e.description}`),\n },\n };\n }\n \n /**\n * Get hypothesis by ID\n */\n async getHypothesis(hypothesisId: string): Promise<Hypothesis | undefined> {\n await this.projectState.load();\n return this.projectState.getHypothesis(hypothesisId);\n }\n \n /**\n * Get all hypotheses\n */\n async getAllHypotheses(): Promise<Hypothesis[]> {\n await this.projectState.load();\n return this.projectState.getAllHypotheses();\n }\n \n /**\n * Get validated hypotheses\n */\n async getValidatedHypotheses(): Promise<Hypothesis[]> {\n await this.projectState.load();\n return this.projectState.getValidatedHypotheses();\n }\n \n /**\n * Get hypothesis accuracy stats\n */\n getAccuracy(): number {\n const metrics = this.projectState.getMetrics();\n return metrics.hypothesisAccuracy;\n }\n}\n\n// ============================================================================\n// Singleton Management\n// ============================================================================\n\nconst hypothesisEngines: Map<string, HypothesisEngine> = new Map();\n\n/**\n * Get the HypothesisEngine for a project (singleton per project)\n */\nexport function getHypothesisEngine(projectPath: string): HypothesisEngine {\n let engine = hypothesisEngines.get(projectPath);\n if (!engine) {\n engine = new HypothesisEngine(projectPath);\n hypothesisEngines.set(projectPath, engine);\n }\n return engine;\n}\n\n/**\n * Clear all HypothesisEngine instances (for testing)\n */\nexport function clearHypothesisEngines(): void {\n hypothesisEngines.clear();\n}\n\n/**\n * Gather evidence for a specific hypothesis (manual check from UI)\n */\nexport async function gatherEvidenceForHypothesis(\n hypothesisId: string,\n projectPath: string\n): Promise<Array<{ supports: boolean; description: string; weight: number }>> {\n const engine = getHypothesisEngine(projectPath);\n const projectState = getProjectState(projectPath);\n await projectState.load();\n \n const hypothesis = projectState.getAllHypotheses().find(h => h.id === hypothesisId);\n if (!hypothesis) {\n throw new Error(`Hypothesis ${hypothesisId} not found`);\n }\n \n // Get the analysis - access private method via bracket notation\n const analysis = await (engine as any).analyzeHypothesis(hypothesis);\n \n // Convert evidence to simpler format\n return analysis.recentEvidence.map((e: HypothesisEvidence) => ({\n supports: e.type === 'supporting',\n description: e.description,\n weight: e.weight,\n }));\n}\n"],"mappings":"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","names":["existing"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/memory/global-memory.ts","../src/guardian/gotcha-predictor.ts"],"sourcesContent":["/**\n * Cross-Project Memory\n * \n * Stores and retrieves patterns across all projects.\n * Location: ~/.trie/memory/\n * \n * Phase 1 Hardening:\n * - SHA256 hashing for pattern IDs\n * - Atomic writes to prevent corruption\n * - Rotational backups for recovery\n * - Zod validation for data integrity\n */\n\nimport { mkdir, writeFile, readFile, readdir } from 'fs/promises';\nimport { createHash } from 'crypto';\nimport { existsSync } from 'fs';\nimport { join } from 'path';\nimport { homedir } from 'os';\nimport type { Issue } from '../types/index.js';\nimport { atomicWriteJSON } from '../utils/atomic-write.js';\nimport { BackupManager } from '../utils/backup-manager.js';\nimport { GlobalPatternsIndexSchema, safeParseAndValidate } from './validation.js';\n\nconst GLOBAL_TRIE_DIR = join(homedir(), '.trie');\nconst GLOBAL_MEMORY_DIR = join(GLOBAL_TRIE_DIR, 'memory');\n\nexport interface GlobalPattern {\n id: string;\n pattern: string;\n description: string;\n severity: string;\n agent: string;\n occurrences: number;\n projects: string[];\n firstSeen: string;\n lastSeen: string;\n fixApplied?: {\n project: string;\n timestamp: string;\n fix: string;\n };\n}\n\nexport interface ProjectSummary {\n name: string;\n path: string;\n lastScan: string;\n totalIssues: number;\n patterns: string[];\n}\n\n/**\n * Record issues to global memory\n */\nexport async function recordToGlobalMemory(\n issues: Issue[],\n projectName: string,\n projectPath: string\n): Promise<void> {\n await mkdir(GLOBAL_MEMORY_DIR, { recursive: true });\n await mkdir(join(GLOBAL_MEMORY_DIR, 'projects'), { recursive: true });\n\n const patterns = await loadGlobalPatterns();\n const now = new Date().toISOString();\n\n for (const issue of issues) {\n const patternId = extractPatternId(issue);\n const existing = patterns.find(p => p.id === patternId);\n\n if (existing) {\n existing.occurrences++;\n existing.lastSeen = now;\n if (!existing.projects.includes(projectName)) {\n existing.projects.push(projectName);\n }\n } else {\n patterns.push({\n id: patternId,\n pattern: issue.issue.slice(0, 200),\n description: issue.fix.slice(0, 200),\n severity: issue.severity,\n agent: issue.agent,\n occurrences: 1,\n projects: [projectName],\n firstSeen: now,\n lastSeen: now,\n });\n }\n }\n\n await saveGlobalPatterns(patterns);\n\n const summaryPath = join(GLOBAL_MEMORY_DIR, 'projects', `${sanitizeName(projectName)}.json`);\n const summary: ProjectSummary = {\n name: projectName,\n path: projectPath,\n lastScan: now,\n totalIssues: issues.length,\n patterns: [...new Set(issues.map(i => extractPatternId(i)))],\n };\n \n // Use atomic write for project summary\n await atomicWriteJSON(summaryPath, summary);\n}\n\n/**\n * Find patterns that appear across multiple projects\n */\nexport async function findCrossProjectPatterns(\n minOccurrences: number = 2\n): Promise<GlobalPattern[]> {\n const patterns = await loadGlobalPatterns();\n return patterns\n .filter(p => p.projects.length >= minOccurrences)\n .sort((a, b) => b.occurrences - a.occurrences);\n}\n\n/**\n * Check if an issue has been fixed in another project\n */\nexport async function findFixFromOtherProjects(\n issue: Issue\n): Promise<GlobalPattern | null> {\n const patterns = await loadGlobalPatterns();\n const patternId = extractPatternId(issue);\n const pattern = patterns.find(p => p.id === patternId);\n\n if (pattern?.fixApplied) {\n return pattern;\n }\n\n return null;\n}\n\n/**\n * Record that a pattern was fixed\n */\nexport async function recordPatternFix(\n issue: Issue,\n projectName: string,\n fix: string\n): Promise<void> {\n const patterns = await loadGlobalPatterns();\n const patternId = extractPatternId(issue);\n const pattern = patterns.find(p => p.id === patternId);\n\n if (pattern && !pattern.fixApplied) {\n pattern.fixApplied = {\n project: projectName,\n timestamp: new Date().toISOString(),\n fix: fix.slice(0, 500),\n };\n await saveGlobalPatterns(patterns);\n }\n}\n\n/**\n * Get all tracked projects\n */\nexport async function listTrackedProjects(): Promise<ProjectSummary[]> {\n const projectsDir = join(GLOBAL_MEMORY_DIR, 'projects');\n \n try {\n if (!existsSync(projectsDir)) return [];\n \n const files = await readdir(projectsDir);\n const summaries: ProjectSummary[] = [];\n \n for (const file of files) {\n if (!file.endsWith('.json')) continue;\n try {\n const content = await readFile(join(projectsDir, file), 'utf-8');\n summaries.push(JSON.parse(content));\n } catch {\n // Skip invalid files\n }\n }\n \n return summaries.sort((a, b) => \n new Date(b.lastScan).getTime() - new Date(a.lastScan).getTime()\n );\n } catch {\n return [];\n }\n}\n\n/**\n * Get global memory statistics\n */\nexport async function getGlobalMemoryStats(): Promise<{\n totalPatterns: number;\n crossProjectPatterns: number;\n trackedProjects: number;\n totalOccurrences: number;\n fixedPatterns: number;\n patternsByAgent: Record<string, number>;\n capacityInfo: {\n current: number;\n max: number;\n percentFull: number;\n isAtCap: boolean;\n };\n deduplicationStats: {\n uniquePatterns: number;\n averageOccurrences: number;\n };\n}> {\n const patterns = await loadGlobalPatterns();\n const projects = await listTrackedProjects();\n \n const MAX_PATTERNS = 500;\n \n // Count patterns by agent type\n const patternsByAgent: Record<string, number> = {};\n for (const pattern of patterns) {\n patternsByAgent[pattern.agent] = (patternsByAgent[pattern.agent] || 0) + 1;\n }\n \n const totalOccurrences = patterns.reduce((sum, p) => sum + p.occurrences, 0);\n const avgOccurrences = patterns.length > 0 ? totalOccurrences / patterns.length : 0;\n \n return {\n totalPatterns: patterns.length,\n crossProjectPatterns: patterns.filter(p => p.projects.length >= 2).length,\n trackedProjects: projects.length,\n totalOccurrences,\n fixedPatterns: patterns.filter(p => p.fixApplied).length,\n patternsByAgent,\n capacityInfo: {\n current: patterns.length,\n max: MAX_PATTERNS,\n percentFull: Math.round((patterns.length / MAX_PATTERNS) * 100),\n isAtCap: patterns.length >= MAX_PATTERNS,\n },\n deduplicationStats: {\n uniquePatterns: patterns.length,\n averageOccurrences: Math.round(avgOccurrences * 10) / 10,\n },\n };\n}\n\n/**\n * Update GLOBAL_MEMORY.md with current patterns\n */\nexport async function updateGlobalMemoryMd(): Promise<void> {\n const patterns = await loadGlobalPatterns();\n const crossProject = patterns.filter(p => p.projects.length >= 2);\n const projects = await listTrackedProjects();\n\n const lines: string[] = [\n '# Global Trie Memory',\n '',\n '> Auto-generated file tracking patterns across all your projects.',\n `> Last updated: ${new Date().toISOString()}`,\n '',\n '## Summary',\n '',\n `- **Projects tracked:** ${projects.length}`,\n `- **Total patterns:** ${patterns.length}`,\n `- **Cross-project patterns:** ${crossProject.length}`,\n '',\n '## Cross-Project Patterns',\n '',\n 'These issues appear in multiple projects:',\n '',\n ];\n \n for (const p of crossProject.slice(0, 20)) {\n lines.push(\n `### ${p.pattern.slice(0, 60)}${p.pattern.length > 60 ? '...' : ''}`,\n '',\n `- **Severity:** ${p.severity}`,\n `- **Agent:** ${p.agent}`,\n `- **Occurrences:** ${p.occurrences} across ${p.projects.length} projects`,\n `- **Projects:** ${p.projects.slice(0, 5).join(', ')}${p.projects.length > 5 ? '...' : ''}`,\n );\n if (p.fixApplied) {\n lines.push(`- **Fixed in:** ${p.fixApplied.project} on ${p.fixApplied.timestamp.split('T')[0]}`);\n } else {\n lines.push('- **Status:** Not fixed');\n }\n lines.push('');\n }\n\n lines.push(\n '## Tracked Projects',\n '',\n '| Project | Last Scan | Issues |',\n '|---------|-----------|--------|',\n );\n \n for (const p of projects.slice(0, 20)) {\n lines.push(`| ${p.name} | ${p.lastScan.split('T')[0]} | ${p.totalIssues} |`);\n }\n\n lines.push('', '---', '', '*This file is auto-generated by Trie. Do not edit manually.*');\n\n await mkdir(GLOBAL_MEMORY_DIR, { recursive: true });\n await writeFile(join(GLOBAL_MEMORY_DIR, 'GLOBAL_MEMORY.md'), lines.join('\\n'));\n}\n\n/**\n * Search global patterns\n */\nexport async function searchGlobalPatterns(\n query: string,\n options: {\n limit?: number;\n severity?: string[];\n agent?: string;\n } = {}\n): Promise<GlobalPattern[]> {\n const patterns = await loadGlobalPatterns();\n const limit = options.limit || 10;\n const queryTerms = query.toLowerCase().split(/\\s+/).filter(t => t.length > 2);\n \n const scored = patterns\n .filter(p => {\n if (options.severity && !options.severity.includes(p.severity)) return false;\n if (options.agent && p.agent !== options.agent) return false;\n return true;\n })\n .map(p => {\n const text = `${p.pattern} ${p.description} ${p.agent}`.toLowerCase();\n let score = 0;\n for (const term of queryTerms) {\n if (text.includes(term)) score++;\n }\n return { pattern: p, score };\n })\n .filter(s => s.score > 0)\n .sort((a, b) => b.score - a.score)\n .slice(0, limit);\n \n return scored.map(s => s.pattern);\n}\n\n// Private helpers\n\n/**\n * Load global patterns with validation and auto-recovery\n */\nasync function loadGlobalPatterns(): Promise<GlobalPattern[]> {\n const patternsPath = join(GLOBAL_MEMORY_DIR, 'global-patterns.json');\n \n try {\n if (existsSync(patternsPath)) {\n const content = await readFile(patternsPath, 'utf-8');\n const result = safeParseAndValidate(content, GlobalPatternsIndexSchema);\n \n if (result.success) {\n return result.data as GlobalPattern[];\n }\n \n // Validation failed - attempt recovery\n const backupManager = new BackupManager(patternsPath);\n if (await backupManager.recoverFromBackup()) {\n const recovered = await readFile(patternsPath, 'utf-8');\n const recoveredResult = safeParseAndValidate(recovered, GlobalPatternsIndexSchema);\n if (recoveredResult.success) {\n return recoveredResult.data as GlobalPattern[];\n }\n }\n }\n } catch {\n // File doesn't exist or recovery failed\n }\n \n return [];\n}\n\n/**\n * Save global patterns with backup and atomic write\n */\nasync function saveGlobalPatterns(patterns: GlobalPattern[]): Promise<void> {\n await mkdir(GLOBAL_MEMORY_DIR, { recursive: true });\n const patternsPath = join(GLOBAL_MEMORY_DIR, 'global-patterns.json');\n \n // Intelligent deduplication: merge patterns with same ID\n const patternMap = new Map<string, GlobalPattern>();\n for (const pattern of patterns) {\n const existing = patternMap.get(pattern.id);\n if (existing) {\n // Merge: update occurrences, projects, and timestamps\n existing.occurrences += pattern.occurrences;\n for (const proj of pattern.projects) {\n if (!existing.projects.includes(proj)) {\n existing.projects.push(proj);\n }\n }\n existing.lastSeen = pattern.lastSeen > existing.lastSeen ? pattern.lastSeen : existing.lastSeen;\n } else {\n patternMap.set(pattern.id, pattern);\n }\n }\n \n const deduplicated = Array.from(patternMap.values());\n \n // Intelligent pruning: prioritize recent, high-severity, cross-project patterns\n const pruned = intelligentPruneGlobalPatterns(deduplicated, 500);\n \n // Create backup before writing\n const backupManager = new BackupManager(patternsPath);\n await backupManager.createBackup();\n \n // Atomic write\n await atomicWriteJSON(patternsPath, pruned);\n}\n\n/**\n * Intelligently prune global patterns to target count\n * Prioritizes: cross-project, high severity, recent, fixed patterns\n */\nfunction intelligentPruneGlobalPatterns(patterns: GlobalPattern[], targetCount: number): GlobalPattern[] {\n if (patterns.length <= targetCount) {\n return patterns;\n }\n \n const severityWeight: Record<string, number> = {\n critical: 100,\n high: 50,\n moderate: 20,\n low: 10,\n info: 5,\n };\n \n const scored = patterns.map(pattern => {\n const ageInDays = (Date.now() - new Date(pattern.lastSeen).getTime()) / (1000 * 60 * 60 * 24);\n const recencyScore = Math.max(0, 100 - ageInDays * 2);\n const severityScore = severityWeight[pattern.severity] || 10;\n const crossProjectBonus = (pattern.projects.length - 1) * 30; // More projects = higher score\n const fixedBonus = pattern.fixApplied ? 20 : 0;\n const occurrenceScore = Math.min(pattern.occurrences * 2, 100);\n \n return {\n pattern,\n score: recencyScore + severityScore + crossProjectBonus + fixedBonus + occurrenceScore,\n };\n });\n \n return scored\n .sort((a, b) => b.score - a.score)\n .slice(0, targetCount)\n .map(s => s.pattern);\n}\n\n/**\n * Extract a pattern ID using SHA256 for proper deduplication\n * \n * Normalizes the issue text to group similar patterns:\n * - Lowercases\n * - Replaces code snippets with 'CODE'\n * - Replaces numbers with 'N'\n * - Removes quotes\n * \n * Uses SHA256 truncated to 12 chars for collision-free IDs.\n */\nfunction extractPatternId(issue: Issue): string {\n const normalized = issue.issue\n .toLowerCase()\n .replace(/`[^`]+`/g, 'CODE')\n .replace(/\\b\\d+\\b/g, 'N')\n .replace(/['\"]/g, '')\n .slice(0, 100);\n \n const hash = createHash('sha256')\n .update(normalized)\n .digest('hex')\n .slice(0, 12);\n \n return `${issue.agent}-${issue.severity}-${hash}`;\n}\n\nfunction sanitizeName(name: string): string {\n return name.replace(/[^a-zA-Z0-9-_]/g, '-').toLowerCase();\n}\n","import { ContextGraph } from '../context/graph.js';\nimport { searchIssues } from '../memory/issue-store.js';\nimport { scanForVulnerabilities } from '../trie/vulnerability-signatures.js';\nimport { scanForVibeCodeIssues } from '../trie/vibe-code-signatures.js';\nimport type { LinearTicketNode, LinearTicketNodeData } from '../context/nodes.js';\nimport { tryGetClient } from '../ai/client.js';\nimport { getStorage } from '../storage/tiered-storage.js';\nimport fs from 'node:fs';\nimport path from 'node:path';\n\nexport interface GotchaPrediction {\n id: string;\n message: string;\n confidence: number;\n riskLevel: 'low' | 'medium' | 'high' | 'critical';\n precedentId?: string;\n recommendation: string;\n evidence: {\n pastIncidents: string[];\n matchingPatterns: string[];\n relatedTickets: string[];\n };\n}\n\nexport class GotchaPredictor {\n private readonly projectPath: string;\n private readonly graph: ContextGraph;\n\n constructor(projectPath: string, graph: ContextGraph) {\n this.projectPath = projectPath;\n this.graph = graph;\n }\n\n async predictGotchas(changedFiles: string[]): Promise<GotchaPrediction[]> {\n const gotchas: GotchaPrediction[] = [];\n\n // 1. Get active Linear tickets\n const tickets = (await this.graph.listNodes()).filter(n => n.type === 'linear-ticket') as LinearTicketNode[];\n \n for (const file of changedFiles) {\n const fileGotchas = await this.predictForFile(file, tickets);\n gotchas.push(...fileGotchas);\n }\n\n return gotchas;\n }\n\n private async predictForFile(filePath: string, tickets: LinearTicketNode[]): Promise<GotchaPrediction[]> {\n const gotchas: GotchaPrediction[] = [];\n const fullPath = path.resolve(this.projectPath, filePath);\n\n if (!fs.existsSync(fullPath)) return [];\n\n const content = fs.readFileSync(fullPath, 'utf-8');\n\n // 1. Run deterministic scanners for signatures\n const vulnerabilities = await scanForVulnerabilities(content, filePath);\n const vibeIssues = await scanForVibeCodeIssues(content, filePath);\n\n const signatures = [\n ...vulnerabilities.map(v => v.category),\n ...vibeIssues.map(v => v.category)\n ];\n\n // === NEW: Query warm storage for relevant decisions and blockers ===\n const storage = getStorage(this.projectPath);\n await storage.initialize();\n\n // Infer tags from file path and signatures\n const tags = this.extractTagsFromFile(filePath, signatures);\n \n // Query relevant decisions for this file/area\n const relevantDecisions = await storage.queryDecisions({\n tags,\n limit: 10,\n });\n\n // Query active blockers for this area\n const activeBlockers = await storage.queryBlockers({\n tags,\n limit: 5,\n });\n\n // === NEW: Add gotchas from decision ledger ===\n for (const decision of relevantDecisions) {\n // Check if this file is in the decision's file list\n if (decision.files.some(f => f.includes(filePath) || filePath.includes(f))) {\n gotchas.push({\n id: `gotcha-decision-${decision.id}`,\n message: `Decision: ${decision.decision}`,\n confidence: 0.85,\n riskLevel: 'medium',\n precedentId: decision.id,\n recommendation: decision.reasoning || 'Review this decision before making changes',\n evidence: {\n pastIncidents: [],\n matchingPatterns: decision.tags,\n relatedTickets: []\n }\n });\n }\n }\n\n // === NEW: Add gotchas from active blockers ===\n for (const blocker of activeBlockers) {\n gotchas.push({\n id: `gotcha-blocker-${blocker.id}`,\n message: `⚠️ Active Blocker: ${blocker.blocker}`,\n confidence: 0.95,\n riskLevel: blocker.impact === 'critical' ? 'critical' : \n blocker.impact === 'high' ? 'high' : 'medium',\n recommendation: `This area is currently blocked. Consider resolving this before making changes.`,\n evidence: {\n pastIncidents: [],\n matchingPatterns: blocker.tags,\n relatedTickets: []\n }\n });\n }\n\n for (const ticket of tickets) {\n const ticketData = ticket.data as LinearTicketNodeData;\n \n // Correlation 1: Ticket Intent vs Deterministic Signatures\n const intentMatch = this.correlateIntentWithSignatures(ticketData, signatures);\n if (intentMatch) {\n gotchas.push(intentMatch);\n }\n\n // Correlation 2: Historical Precedents\n const historicalPrecedents = await this.findHistoricalPrecedents(filePath, ticketData);\n if (historicalPrecedents) {\n gotchas.push(historicalPrecedents);\n }\n }\n\n return gotchas;\n }\n\n /**\n * Extract tags from file path and signatures for storage queries\n */\n private extractTagsFromFile(filePath: string, signatures: string[]): string[] {\n const tags = new Set<string>();\n\n // Add tags from file path\n const normalized = filePath.toLowerCase();\n if (normalized.includes('/auth/')) tags.add('auth');\n if (normalized.includes('/payment/')) tags.add('payments');\n if (normalized.includes('/api/')) tags.add('api');\n if (normalized.includes('/frontend/') || normalized.includes('/ui/')) tags.add('ui');\n if (normalized.includes('/backend/')) tags.add('backend');\n if (normalized.includes('/database/') || normalized.includes('/models/')) tags.add('database');\n\n // Add tags from signatures\n signatures.forEach(sig => tags.add(sig.toLowerCase()));\n\n return Array.from(tags);\n }\n\n private correlateIntentWithSignatures(ticket: LinearTicketNodeData, signatures: string[]): GotchaPrediction | null {\n const relevantSignatures = signatures.filter(sig => \n ticket.intentVibe.some(vibe => this.vibeToSignatureMap(vibe).includes(sig))\n );\n\n if (relevantSignatures.length > 0) {\n return {\n id: `gotcha-intent-${ticket.ticketId}-${Date.now()}`,\n message: `[${ticket.ticketId}] Working on \"${ticket.title}\" (${ticket.intentVibe.join(', ')}) in a file with ${relevantSignatures.join(', ')} signatures.`,\n confidence: 0.8,\n riskLevel: 'high',\n recommendation: `Be careful with ${relevantSignatures[0]} patterns as they correlate with the intent of your ticket.`,\n evidence: {\n pastIncidents: [],\n matchingPatterns: relevantSignatures,\n relatedTickets: [ticket.ticketId]\n }\n };\n }\n\n return null;\n }\n\n private async findHistoricalPrecedents(filePath: string, ticket: LinearTicketNodeData): Promise<GotchaPrediction | null> {\n // Search for historical issues similar to this ticket's description\n const similarIssues = await searchIssues(ticket.description, {\n workDir: this.projectPath,\n limit: 3\n });\n\n const relevantIssues = similarIssues.filter(r => r.issue.file === filePath || r.issue.file.includes(path.basename(filePath)));\n\n const [firstMatch] = relevantIssues;\n if (firstMatch) {\n const issue = firstMatch.issue;\n return {\n id: `gotcha-precedent-${ticket.ticketId}-${Date.now()}`,\n message: `A similar task in the past caused an issue: \"${issue.issue}\"`,\n confidence: 0.9,\n riskLevel: 'critical',\n precedentId: issue.id,\n recommendation: `Last time we worked on something similar here, we had to fix: \"${issue.fix}\". Check this first.`,\n evidence: {\n pastIncidents: [issue.id],\n matchingPatterns: [],\n relatedTickets: [ticket.ticketId]\n }\n };\n }\n\n return null;\n }\n\n private vibeToSignatureMap(vibe: string): string[] {\n const map: Record<string, string[]> = {\n 'performance': ['giant-file', 'performance', 'react-antipattern'],\n 'security': ['injection', 'secrets', 'auth', 'xss', 'crypto'],\n 'auth': ['auth', 'secrets', 'config'],\n 'bug': ['no-error-handling', 'async', 'error-handling'],\n 'feature': ['mixing-concerns', 'hardcoded'],\n 'refactor': ['code-smell', 'giant-file', 'mixing-concerns']\n };\n return map[vibe] || [];\n }\n\n async synthesizeGotchaExplanation(gotcha: GotchaPrediction): Promise<string> {\n const client = tryGetClient();\n if (!client) return gotcha.message;\n\n const prompt = `\n You are a JIT Defect Predictor. You found a potential \"gotcha\" for a developer.\n \n Ticket context: ${gotcha.evidence.relatedTickets.join(', ')}\n Signatures detected: ${gotcha.evidence.matchingPatterns.join(', ')}\n Past incidents: ${gotcha.evidence.pastIncidents.join(', ')}\n \n Raw message: ${gotcha.message}\n Recommendation: ${gotcha.recommendation}\n \n Explain this gotcha in a concise, human-friendly way (max 2 sentences). \n Make it sound like a senior dev giving a helpful nudge.\n `;\n\n try {\n const response = await client.messages.create({\n model: 'claude-3-5-sonnet-20240620',\n max_tokens: 100,\n messages: [{ role: 'user', content: prompt }]\n });\n\n const text = response.content\n .filter((block): block is { type: 'text'; text: string } => block.type === 'text')\n .map(block => block.text)\n .join('');\n \n return text.trim() || gotcha.message;\n } catch {\n return gotcha.message;\n }\n }\n}\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/guardian/goal-validator.ts"],"sourcesContent":["/**\n * Goal Validator - Helpers for goal tracking\n * \n * Goal detection is handled entirely by the AI watcher in watch.ts.\n * The AI (Anthropic) checks every changed file against user-defined goals,\n * using the Trie's priority scoring for cost control.\n * \n * This module provides:\n * - getActiveGoals: loads active goals for the AI prompt\n * - recordGoalViolationCaught: tracks when a violation is detected\n * - recordGoalViolationFixed: tracks when a violation is auto-fixed\n * - measureInitialGoalValue: measures current state for new goals\n */\n\nimport type { Goal } from './guardian-state.js';\nimport { getProjectState } from './guardian-state.js';\nimport { searchIssues } from '../memory/issue-store.js';\n\n/**\n * Get active goals for a project (used by the AI watcher)\n */\nexport async function getActiveGoals(projectPath: string): Promise<Goal[]> {\n const projectState = getProjectState(projectPath);\n await projectState.load();\n return projectState.getAllGoals().filter(g => g.status === 'active');\n}\n\nexport async function recordGoalViolationCaught(\n goal: Goal,\n file: string,\n projectPath: string\n): Promise<void> {\n const projectState = getProjectState(projectPath);\n await projectState.load();\n \n const metadata = goal.metadata || {};\n const caughtCount = (metadata.caughtCount || 0) + 1;\n \n await projectState.updateGoal(goal.id, {\n metadata: {\n ...metadata,\n caughtCount,\n lastCaught: new Date().toISOString(),\n lastCaughtFile: file,\n },\n });\n}\n\nexport async function recordGoalViolationFixed(\n goal: Goal,\n file: string,\n projectPath: string\n): Promise<void> {\n const projectState = getProjectState(projectPath);\n await projectState.load();\n \n const metadata = goal.metadata || {};\n const fixedCount = (metadata.fixedCount || 0) + 1;\n \n await projectState.updateGoal(goal.id, {\n metadata: {\n ...metadata,\n fixedCount,\n lastFixed: new Date().toISOString(),\n lastFixedFile: file,\n },\n });\n \n // Resolve the goal-violation issue in the issue store\n // This is the source of truth - measureGoalMetric() will query from here\n const { resolveGoalViolation } = await import('../memory/issue-store.js');\n await resolveGoalViolation(file, goal.description, projectPath);\n \n // Trigger immediate progress update so UI reflects the fix\n const { getGoalManager } = await import('./goal-manager.js');\n const goalManager = getGoalManager(projectPath);\n await goalManager.updateGoalProgress();\n}\n\n/**\n * Measure the initial value for a new goal based on existing issues.\n * This sets a proper baseline so progress calculation works correctly.\n * \n * For reduction goals (like \"no emojis\"), we count current violations.\n * For other goals, we use semantic matching against existing issues.\n * \n * Returns the count to use as both startValue and currentValue.\n */\nexport async function measureInitialGoalValue(\n description: string,\n projectPath: string\n): Promise<number> {\n try {\n const issues = await searchIssues('', {\n workDir: projectPath,\n limit: 1000,\n includeResolved: false,\n });\n \n if (issues.length === 0) {\n return 0;\n }\n \n const desc = description.toLowerCase();\n \n // Check for goal-violation issues that might already exist for similar goals\n const goalViolations = issues.filter(r => \n r.issue.agent === 'goal-violation' &&\n r.issue.issue.toLowerCase().includes(desc.slice(0, 30))\n );\n if (goalViolations.length > 0) {\n return goalViolations.length;\n }\n \n // Security goals\n if (desc.includes('security') || desc.includes('vulnerab')) {\n return issues.filter(r => \n r.issue.agent === 'security' || r.issue.severity === 'critical'\n ).length;\n }\n \n // Type safety goals\n if (desc.includes('type') || desc.includes('typescript') || desc.includes('any type')) {\n return issues.filter(r => \n r.issue.agent === 'typecheck' ||\n r.issue.issue.toLowerCase().includes('type')\n ).length;\n }\n \n // Bug-related goals\n if (desc.includes('bug') || desc.includes('error')) {\n return issues.filter(r => \n r.issue.agent === 'bug-finding' ||\n r.issue.severity === 'critical' ||\n r.issue.severity === 'serious'\n ).length;\n }\n \n // Dead code / unused code goals\n if (desc.includes('dead code') || desc.includes('unused')) {\n return issues.filter(r => {\n const msg = r.issue.issue.toLowerCase();\n return msg.includes('unused') || msg.includes('dead code') || msg.includes('never used');\n }).length;\n }\n \n // For custom goals like \"no emojis\", we start at 0 and let the AI scanner find violations\n // This is correct because we don't know the count until a scan runs\n return 0;\n } catch {\n return 0;\n }\n}\n\n/**\n * Manually check files against goals\n * Returns violations found\n * \n * NOW WITH CACHING: Uses CodebaseIndex to avoid re-scanning unchanged files\n */\nexport async function checkFilesForGoalViolations(\n goals: Goal[],\n projectPath: string,\n filesToCheck?: string[],\n onProgress?: (message: string) => void\n): Promise<Array<{ file: string; message: string; severity: 'critical' | 'warning' | 'info' }>> {\n // Import AI client and codebase index\n const { isAIAvailable, runAIAnalysis } = await import('../ai/client.js');\n const { CodebaseIndex } = await import('../context/codebase-index.js');\n \n if (!isAIAvailable()) {\n throw new Error('AI not available - ANTHROPIC_API_KEY not set');\n }\n \n // Initialize codebase index for caching\n const codebaseIndex = new CodebaseIndex(projectPath);\n \n // Check if index needs to be built\n if (codebaseIndex.isEmpty()) {\n onProgress?.('Building codebase index (first-time, may take a minute)...');\n console.error('[Goal Check] Codebase index is empty - building index first...');\n console.error('[Goal Check] This is a one-time operation. Future checks will be much faster.');\n \n // Auto-index the codebase\n const { glob } = await import('glob');\n const indexPattern = `${projectPath}/**/*.{ts,tsx,js,jsx,mjs,vue,svelte,astro,py,go,rs,java,c,cpp,h,hpp,cs,rb,php,css,scss,html}`;\n const indexFiles = await glob(indexPattern, {\n ignore: ['**/node_modules/**', '**/dist/**', '**/build/**', '**/.git/**', '**/.trie/**', '**/coverage/**'],\n nodir: true,\n });\n \n let indexed = 0;\n const total = Math.min(indexFiles.length, 500); // Cap at 500 files for initial index\n for (const filePath of indexFiles.slice(0, 500)) {\n let relativePath = filePath;\n if (filePath.toLowerCase().startsWith(projectPath.toLowerCase() + '/')) {\n relativePath = filePath.slice(projectPath.length + 1);\n }\n const result = await codebaseIndex.indexFile(relativePath);\n if (result) indexed++;\n \n // Progress indicator every 50 files\n if (indexed % 50 === 0) {\n onProgress?.(`Indexing files (${indexed}/${total})...`);\n console.error(`[Goal Check] Indexed ${indexed}/${total} files...`);\n }\n }\n \n await codebaseIndex.save();\n console.error(`[Goal Check] Index built: ${indexed} files indexed`);\n }\n \n // Get files to check\n let files: string[] = [];\n if (filesToCheck && filesToCheck.length > 0) {\n files = filesToCheck;\n } else {\n // MANUAL CHECK MODE: Scan ALL relevant files, not just recently modified\n const { glob } = await import('glob');\n \n const pattern = `${projectPath}/**/*.{ts,tsx,js,jsx,py,go,rs,java,c,cpp,h,hpp,cs,rb,php,css,scss,html,vue,svelte}`;\n const allFiles = await glob(pattern, {\n ignore: ['**/node_modules/**', '**/dist/**', '**/build/**', '**/.git/**', '**/.trie/**', '**/coverage/**'],\n nodir: true,\n });\n \n // For manual checks, use more files but still reasonable limit\n // Sort by modification time to prioritize recently modified\n const { stat } = await import('fs/promises');\n const withStats = await Promise.all(\n allFiles.map(async (f) => {\n try {\n const stats = await stat(f);\n return { file: f, mtime: stats.mtime.getTime() };\n } catch {\n return null;\n }\n })\n );\n \n files = withStats\n .filter((f): f is { file: string; mtime: number } => f !== null)\n .sort((a, b) => b.mtime - a.mtime)\n .slice(0, 100) // Check up to 100 files for manual scans\n .map(f => f.file);\n }\n \n if (files.length === 0) {\n throw new Error('No files found to check');\n }\n \n // Check which files need scanning vs can use cached results\n const filesToScan: string[] = [];\n const cachedViolations: Array<{ file: string; message: string; severity: 'critical' | 'warning' | 'info' }> = [];\n \n for (const filePath of files) {\n // Handle case-insensitive filesystems (macOS) and ensure we get a proper relative path\n let relativePath = filePath;\n if (filePath.toLowerCase().startsWith(projectPath.toLowerCase() + '/')) {\n relativePath = filePath.slice(projectPath.length + 1);\n } else if (filePath.startsWith('/')) {\n // Already absolute but doesn't match projectPath - skip this file\n // This can happen with stale cache entries from different projects\n continue;\n }\n const hasChanged = await codebaseIndex.hasChanged(relativePath);\n \n if (hasChanged) {\n // File changed or not indexed - needs scanning\n // Try to index the file first; skip if it doesn't exist\n const indexed = await codebaseIndex.indexFile(relativePath);\n if (indexed) {\n filesToScan.push(filePath);\n }\n // If indexFile returns null, file doesn't exist - skip it silently\n } else {\n // File unchanged - check cache for each goal\n for (const goal of goals) {\n const cached = codebaseIndex.getCachedViolations(relativePath, goal.id);\n if (cached && cached.length > 0) {\n const violation = cached[0];\n if (violation && violation.found) {\n cachedViolations.push({\n file: relativePath,\n message: `Goal \"${goal.description}\" violated in ${relativePath}: ${violation.details || 'Violation found'} [${violation.confidence || 90}% confidence] (cached)`,\n severity: 'warning',\n });\n }\n } else {\n // No cache for this goal - needs scanning\n if (!filesToScan.includes(filePath)) {\n filesToScan.push(filePath);\n }\n }\n }\n }\n }\n \n onProgress?.(`Checking ${filesToScan.length} files for violations...`);\n console.error(`[Goal Check] ${files.length} files total, ${filesToScan.length} need scanning, ${files.length - filesToScan.length} using cache`);\n \n // Process files that need scanning in batches\n const allViolations: Array<{ file: string; message: string; severity: 'critical' | 'warning' | 'info' }> = [...cachedViolations];\n \n if (filesToScan.length === 0) {\n // All results from cache!\n await codebaseIndex.save();\n return allViolations;\n }\n \n // For large file sets, process in batches to avoid token limits\n const BATCH_SIZE = 25; // Process 25 files at a time\n \n const totalBatches = Math.ceil(filesToScan.length / BATCH_SIZE);\n for (let batchStart = 0; batchStart < filesToScan.length; batchStart += BATCH_SIZE) {\n const batchNum = Math.floor(batchStart / BATCH_SIZE) + 1;\n onProgress?.(`Analyzing files (batch ${batchNum}/${totalBatches})...`);\n const batchFiles = filesToScan.slice(batchStart, batchStart + BATCH_SIZE);\n \n // Read file contents for this batch\n const { readFile } = await import('fs/promises');\n const fileContents = await Promise.all(\n batchFiles.map(async (filePath) => {\n try {\n const content = await readFile(filePath, 'utf-8');\n const relativePath = filePath.replace(projectPath + '/', '');\n return {\n path: relativePath,\n content: content.slice(0, 10000), // Increased limit for manual checks\n };\n } catch {\n return null;\n }\n })\n );\n \n const validFiles = fileContents.filter((f): f is { path: string; content: string } => f !== null);\n \n if (validFiles.length === 0) continue;\n \n // Build files block for AI\n const filesBlock = validFiles\n .map(f => `--- ${f.path} ---\\n${f.content}`)\n .join('\\n\\n');\n \n // Build goals section\n const goalsSection = `\nUSER-DEFINED GOALS (check EVERY file against ALL goals):\n${goals.map((g, i) => ` ${i + 1}. \"${g.description}\"`).join('\\n')}\n\nThis is a MANUAL CHECK requested by the user. Report ALL goal violations you find.\nFor emoji detection, look for Unicode emoji characters.\n`;\n \n // Run AI analysis\n const result = await runAIAnalysis({\n systemPrompt: `You are checking code for GOAL VIOLATIONS ONLY.\n${goalsSection}\nReply ONLY with a JSON array. Each element must have:\n- \"file\": relative file path\n- \"severity\": \"critical\" | \"major\" | \"minor\"\n- \"description\": 1-sentence description of the goal violation with specific examples\n- \"confidence\": number 0-100, how confident you are this is a violation\n- \"isGoalViolation\": true (always true for this scan)\n- \"goalIndex\": 0-based index of the violated goal\n\nCRITICAL DETECTION RULES:\n\n**EMOJIS**: Any Unicode emoji characters including but not limited to:\n- Emoticons: 😀😃😄😊🙂🙃😉😇🥰😍🤩😘😗☺️😚😙🥲\n- Symbols: ⚡️⚠️✅❌➜→←↑↓►◄▲▼★☆●○◆◇■□▪️▫️\n- Objects: 📊📈📉💻🖥️📱⌨️🖱️💾💿📀🔧🔨⚙️🛠️\n- Actions: 🔥💪👍👎👏🙌🤝✊👊🎯🎉🎊🚀\n- Weather: ☀️🌤️⛅☁️🌦️🌧️⛈️🌩️🌨️❄️\n- ALL OTHER Unicode emoji in ranges U+1F300-U+1F9FF, U+2600-U+27BF, U+2B00-U+2BFF\n\n**COLORS**: For \"purple\" or \"gradient\" goals, check:\n- CSS: purple, #purple, hsl(purple), rgb(purple), violet, #8B00FF, #9B59D6, etc.\n- Gradients: linear-gradient, radial-gradient, conic-gradient, background-image with gradients\n- Tailwind: purple-*, violet-*, bg-gradient-*\n- Styled components or CSS-in-JS with purple/violet/gradient\n\nBe EXTREMELY thorough. Check:\n1. String literals and template literals\n2. JSX/HTML content\n3. CSS files and style blocks\n4. Comments (emojis in comments still violate \"no emojis\")\n5. console.log statements\n6. Component names, variable names (if they contain emojis)\n\nIf a goal says \"no emojis\" and you see ANY emoji ANYWHERE in the file, report it.\nIf a goal says \"no console.log\" and you see console.log ANYWHERE, report it.\nIf a goal says \"no purple/gradient\" and you see ANY purple color or gradient, report it.\n\nIf no violations found, reply with: []\nOutput ONLY the JSON array, no markdown fences, no commentary.`,\n userPrompt: `Check these ${validFiles.length} files for goal violations:\\n\\n${filesBlock}`,\n maxTokens: 8192, // Increased for larger codebases\n temperature: 0.1,\n });\n \n // Parse response\n let issues: Array<{\n file: string;\n severity: 'critical' | 'major' | 'minor';\n description: string;\n confidence: number;\n isGoalViolation: boolean;\n goalIndex?: number;\n }> = [];\n \n try {\n const cleaned = result.content.replace(/```json?\\n?|\\n?```/g, '').trim();\n issues = JSON.parse(cleaned);\n if (!Array.isArray(issues)) issues = [];\n } catch (err) {\n // Parse failed - continue to next batch\n console.debug('[Goal Check] Batch parse failed:', err);\n continue;\n }\n \n // Convert to violation format and record\n for (const issue of issues) {\n if (!issue.isGoalViolation || issue.confidence < 50) continue;\n if (issue.goalIndex == null || issue.goalIndex < 0 || issue.goalIndex >= goals.length) continue;\n \n const goal = goals[issue.goalIndex];\n if (!goal) continue; // Defensive check\n const severity = issue.severity === 'critical' ? 'critical' : 'warning';\n const message = `Goal \"${goal.description}\" violated in ${issue.file}: ${issue.description} [${issue.confidence}% confidence]`;\n \n allViolations.push({\n file: issue.file,\n message,\n severity,\n });\n \n // Cache the result in codebase index\n codebaseIndex.recordViolation(\n issue.file,\n goal.id,\n goal.description,\n true, // found\n issue.description,\n issue.confidence\n );\n \n // Record violation\n await recordGoalViolationCaught(goal, issue.file, projectPath);\n }\n \n // Also record \"no violation\" for scanned files\n for (const file of validFiles) {\n for (let goalIdx = 0; goalIdx < goals.length; goalIdx++) {\n const goal = goals[goalIdx];\n if (!goal) continue;\n const hasViolation = issues.some(i => i.file === file.path && i.goalIndex === goalIdx);\n if (!hasViolation) {\n codebaseIndex.recordViolation(\n file.path,\n goal.id,\n goal.description,\n false, // not found\n undefined,\n 100\n );\n }\n }\n }\n }\n \n // Save updated index\n await codebaseIndex.save();\n \n return allViolations;\n}\n"],"mappings":"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","names":[]}