@triedotdev/mcp 1.0.168 → 1.0.170

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 (149) hide show
  1. package/README.md +54 -500
  2. package/dist/chunk-2YXOBNKW.js +619 -0
  3. package/dist/chunk-2YXOBNKW.js.map +1 -0
  4. package/dist/chunk-QR64Y5TI.js +363 -0
  5. package/dist/chunk-QR64Y5TI.js.map +1 -0
  6. package/dist/cli/main.d.ts +0 -15
  7. package/dist/cli/main.js +356 -3100
  8. package/dist/cli/main.js.map +1 -1
  9. package/dist/index.js +2 -36
  10. package/dist/index.js.map +1 -1
  11. package/dist/server/mcp-server.js +2 -36
  12. package/package.json +8 -31
  13. package/dist/autonomy-config-FSERX3O3.js +0 -30
  14. package/dist/autonomy-config-FSERX3O3.js.map +0 -1
  15. package/dist/chat-store-JNGNTDSN.js +0 -15
  16. package/dist/chat-store-JNGNTDSN.js.map +0 -1
  17. package/dist/chunk-2HF65EHQ.js +0 -311
  18. package/dist/chunk-2HF65EHQ.js.map +0 -1
  19. package/dist/chunk-43X6JBEM.js +0 -36
  20. package/dist/chunk-43X6JBEM.js.map +0 -1
  21. package/dist/chunk-4MXH2ZPT.js +0 -1827
  22. package/dist/chunk-4MXH2ZPT.js.map +0 -1
  23. package/dist/chunk-575YT2SD.js +0 -737
  24. package/dist/chunk-575YT2SD.js.map +0 -1
  25. package/dist/chunk-5BRRRTN6.js +0 -354
  26. package/dist/chunk-5BRRRTN6.js.map +0 -1
  27. package/dist/chunk-6NLHFIYA.js +0 -344
  28. package/dist/chunk-6NLHFIYA.js.map +0 -1
  29. package/dist/chunk-7WITSO22.js +0 -824
  30. package/dist/chunk-7WITSO22.js.map +0 -1
  31. package/dist/chunk-DGUM43GV.js +0 -11
  32. package/dist/chunk-DGUM43GV.js.map +0 -1
  33. package/dist/chunk-EFWVF6TI.js +0 -267
  34. package/dist/chunk-EFWVF6TI.js.map +0 -1
  35. package/dist/chunk-F6WFNUAY.js +0 -216
  36. package/dist/chunk-F6WFNUAY.js.map +0 -1
  37. package/dist/chunk-FQ45QP5A.js +0 -361
  38. package/dist/chunk-FQ45QP5A.js.map +0 -1
  39. package/dist/chunk-G2TGF6TR.js +0 -573
  40. package/dist/chunk-G2TGF6TR.js.map +0 -1
  41. package/dist/chunk-GTKYBOXL.js +0 -700
  42. package/dist/chunk-GTKYBOXL.js.map +0 -1
  43. package/dist/chunk-HVCDY3AK.js +0 -850
  44. package/dist/chunk-HVCDY3AK.js.map +0 -1
  45. package/dist/chunk-JVMBCWKS.js +0 -348
  46. package/dist/chunk-JVMBCWKS.js.map +0 -1
  47. package/dist/chunk-KDHN2ZQE.js +0 -313
  48. package/dist/chunk-KDHN2ZQE.js.map +0 -1
  49. package/dist/chunk-LQIMKE3P.js +0 -12524
  50. package/dist/chunk-LQIMKE3P.js.map +0 -1
  51. package/dist/chunk-ME2OERF5.js +0 -345
  52. package/dist/chunk-ME2OERF5.js.map +0 -1
  53. package/dist/chunk-MRHKX5M5.js +0 -662
  54. package/dist/chunk-MRHKX5M5.js.map +0 -1
  55. package/dist/chunk-OBQ74FOU.js +0 -27
  56. package/dist/chunk-OBQ74FOU.js.map +0 -1
  57. package/dist/chunk-OMR4YCBS.js +0 -987
  58. package/dist/chunk-OMR4YCBS.js.map +0 -1
  59. package/dist/chunk-Q5EKA5YA.js +0 -254
  60. package/dist/chunk-Q5EKA5YA.js.map +0 -1
  61. package/dist/chunk-Q63FFI6D.js +0 -132
  62. package/dist/chunk-Q63FFI6D.js.map +0 -1
  63. package/dist/chunk-SY6KQG44.js +0 -983
  64. package/dist/chunk-SY6KQG44.js.map +0 -1
  65. package/dist/chunk-T63OHG4Q.js +0 -440
  66. package/dist/chunk-T63OHG4Q.js.map +0 -1
  67. package/dist/chunk-TN5WEKWI.js +0 -173
  68. package/dist/chunk-TN5WEKWI.js.map +0 -1
  69. package/dist/chunk-VUL52BQL.js +0 -402
  70. package/dist/chunk-VUL52BQL.js.map +0 -1
  71. package/dist/chunk-VVITXIHN.js +0 -189
  72. package/dist/chunk-VVITXIHN.js.map +0 -1
  73. package/dist/chunk-WCN7S3EI.js +0 -14
  74. package/dist/chunk-WCN7S3EI.js.map +0 -1
  75. package/dist/chunk-XE6KQRKZ.js +0 -816
  76. package/dist/chunk-XE6KQRKZ.js.map +0 -1
  77. package/dist/chunk-XPZZFPBZ.js +0 -491
  78. package/dist/chunk-XPZZFPBZ.js.map +0 -1
  79. package/dist/chunk-XTFWT2XM.js +0 -727
  80. package/dist/chunk-XTFWT2XM.js.map +0 -1
  81. package/dist/chunk-YDHUCDHM.js +0 -4011
  82. package/dist/chunk-YDHUCDHM.js.map +0 -1
  83. package/dist/chunk-YZ6Y2H3P.js +0 -1289
  84. package/dist/chunk-YZ6Y2H3P.js.map +0 -1
  85. package/dist/chunk-ZJF5FTBX.js +0 -1396
  86. package/dist/chunk-ZJF5FTBX.js.map +0 -1
  87. package/dist/chunk-ZV2K6M7T.js +0 -74
  88. package/dist/chunk-ZV2K6M7T.js.map +0 -1
  89. package/dist/cli/create-agent.d.ts +0 -1
  90. package/dist/cli/create-agent.js +0 -1050
  91. package/dist/cli/create-agent.js.map +0 -1
  92. package/dist/cli/yolo-daemon.d.ts +0 -1
  93. package/dist/cli/yolo-daemon.js +0 -423
  94. package/dist/cli/yolo-daemon.js.map +0 -1
  95. package/dist/client-NJPZE5JT.js +0 -28
  96. package/dist/client-NJPZE5JT.js.map +0 -1
  97. package/dist/codebase-index-VAPF32XX.js +0 -12
  98. package/dist/codebase-index-VAPF32XX.js.map +0 -1
  99. package/dist/fast-analyzer-XXYMOXRK.js +0 -216
  100. package/dist/fast-analyzer-XXYMOXRK.js.map +0 -1
  101. package/dist/git-EO5SRFMN.js +0 -28
  102. package/dist/git-EO5SRFMN.js.map +0 -1
  103. package/dist/github-ingester-ZOKK6GRS.js +0 -11
  104. package/dist/github-ingester-ZOKK6GRS.js.map +0 -1
  105. package/dist/goal-manager-YOB7VWK7.js +0 -25
  106. package/dist/goal-manager-YOB7VWK7.js.map +0 -1
  107. package/dist/goal-validator-ULKIBDPX.js +0 -24
  108. package/dist/goal-validator-ULKIBDPX.js.map +0 -1
  109. package/dist/graph-B3NA4S7I.js +0 -10
  110. package/dist/graph-B3NA4S7I.js.map +0 -1
  111. package/dist/hypothesis-7BFFT5JY.js +0 -23
  112. package/dist/hypothesis-7BFFT5JY.js.map +0 -1
  113. package/dist/incident-index-EFNUSGWL.js +0 -11
  114. package/dist/incident-index-EFNUSGWL.js.map +0 -1
  115. package/dist/insight-store-EC4PLSAW.js +0 -22
  116. package/dist/insight-store-EC4PLSAW.js.map +0 -1
  117. package/dist/issue-store-ZIRP23EP.js +0 -36
  118. package/dist/issue-store-ZIRP23EP.js.map +0 -1
  119. package/dist/ledger-TWZTGDFA.js +0 -58
  120. package/dist/ledger-TWZTGDFA.js.map +0 -1
  121. package/dist/linear-ingester-XXPAZZRW.js +0 -11
  122. package/dist/linear-ingester-XXPAZZRW.js.map +0 -1
  123. package/dist/output-manager-RVJ37XKA.js +0 -13
  124. package/dist/output-manager-RVJ37XKA.js.map +0 -1
  125. package/dist/parse-goal-violation-SACGFG3C.js +0 -8
  126. package/dist/parse-goal-violation-SACGFG3C.js.map +0 -1
  127. package/dist/pattern-discovery-F7LU5K6E.js +0 -8
  128. package/dist/pattern-discovery-F7LU5K6E.js.map +0 -1
  129. package/dist/progress-SRQ2V3BP.js +0 -18
  130. package/dist/progress-SRQ2V3BP.js.map +0 -1
  131. package/dist/project-state-AHPA77SM.js +0 -28
  132. package/dist/project-state-AHPA77SM.js.map +0 -1
  133. package/dist/sync-M2FSWPBC.js +0 -12
  134. package/dist/sync-M2FSWPBC.js.map +0 -1
  135. package/dist/terminal-spawn-5YXDMUCF.js +0 -157
  136. package/dist/terminal-spawn-5YXDMUCF.js.map +0 -1
  137. package/dist/tiered-storage-Z3YCR465.js +0 -12
  138. package/dist/tiered-storage-Z3YCR465.js.map +0 -1
  139. package/dist/trie-agent-3YDPEGHJ.js +0 -28
  140. package/dist/trie-agent-3YDPEGHJ.js.map +0 -1
  141. package/dist/ui/chat.html +0 -1014
  142. package/dist/ui/goals.html +0 -967
  143. package/dist/ui/hypotheses.html +0 -1011
  144. package/dist/ui/ledger.html +0 -954
  145. package/dist/ui/nudges.html +0 -995
  146. package/dist/vibe-code-signatures-F6URTBW3.js +0 -16
  147. package/dist/vibe-code-signatures-F6URTBW3.js.map +0 -1
  148. package/dist/vulnerability-signatures-T7SKHORW.js +0 -18
  149. package/dist/vulnerability-signatures-T7SKHORW.js.map +0 -1
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/trie/vibe-code-signatures.ts"],"sourcesContent":["/**\n * Vibe Code Signatures\n * \n * Patterns commonly found in AI-generated and \"vibe coded\" projects.\n * These are issues that non-technical users encounter when using\n * AI tools like Cursor, v0, Lovable, Bolt, Replit, etc.\n * \n * Research sources:\n * - Reddit r/vibecoding (~130k members) - Andrej Karpathy's vibe coding movement\n * - Reddit r/ClaudeAI (~431k members) - Claude usage patterns\n * - Reddit r/cursor - Cursor IDE specific issues\n * - vibecodingwiki.com - Community documentation\n * - Twitter/X discussions on AI coding\n * \n * \"Vibe coding\" (coined by Andrej Karpathy, Feb 2025):\n * AI-assisted development where you describe tasks to LLMs and they generate code.\n * Focus on iterative experimentation over code correctness.\n * \n * Common issues we detect:\n * - Massive single files (1000+ line App.jsx - THE classic vibe code smell)\n * - API keys exposed in frontend (NEXT_PUBLIC_, VITE_, etc.)\n * - No error handling on fetch/axios calls\n * - No loading states (blank screens while data loads)\n * - No empty states (nothing shown when no data)\n * - Hardcoded localhost URLs that break in production\n * - Console.log debugging left everywhere\n * - TypeScript 'any' used to silence all type errors\n * - useEffect misuse (async useEffect, missing deps)\n * - No input validation on req.body\n * - Database calls directly in React components\n * - Copy-paste duplication instead of components\n * - @ts-ignore and eslint-disable to hide problems\n */\n\nimport { AhoCorasick, PatternMetadata } from './trie.js';\nimport { isInteractiveMode } from '../utils/progress.js';\n\nexport interface VibeCodeMatch {\n pattern: string;\n line: number;\n column: number;\n severity: 'critical' | 'serious' | 'moderate' | 'low';\n category: string;\n description: string;\n commonMistake: string;\n fix: string;\n learnMore?: string;\n}\n\n/**\n * Vibe code anti-patterns - things AI often generates wrong\n */\nconst VIBE_CODE_PATTERNS: Array<{\n pattern: string;\n metadata: PatternMetadata & { commonMistake: string; learnMore?: string };\n}> = [\n // ============================================\n // CRITICAL: Security issues AI often creates\n // ============================================\n {\n pattern: 'NEXT_PUBLIC_',\n metadata: {\n type: 'pattern',\n severity: 'serious',\n category: 'exposed-secrets',\n description: 'Environment variable exposed to browser',\n commonMistake: 'AI puts API keys in NEXT_PUBLIC_ variables, exposing them to users',\n fix: 'Only NEXT_PUBLIC_ for non-sensitive data. Move secrets to server-side API routes',\n learnMore: 'https://nextjs.org/docs/basic-features/environment-variables',\n },\n },\n {\n pattern: 'VITE_',\n metadata: {\n type: 'pattern',\n severity: 'serious',\n category: 'exposed-secrets',\n description: 'Environment variable exposed to browser',\n commonMistake: 'AI puts API keys in VITE_ variables, exposing them to users',\n fix: 'Only VITE_ for non-sensitive data. Create a backend API to hide secrets',\n learnMore: 'https://vitejs.dev/guide/env-and-mode.html',\n },\n },\n {\n pattern: 'REACT_APP_',\n metadata: {\n type: 'pattern',\n severity: 'serious',\n category: 'exposed-secrets',\n description: 'Environment variable exposed to browser',\n commonMistake: 'AI puts sensitive keys in REACT_APP_ making them visible in bundle',\n fix: 'Never put secrets in REACT_APP_. Use a backend proxy for API calls',\n },\n },\n {\n pattern: '\"sk-',\n metadata: {\n type: 'pattern',\n severity: 'critical',\n category: 'exposed-secrets',\n description: 'OpenAI API key pattern detected in string',\n commonMistake: 'AI generates code with OpenAI key in frontend - anyone can steal it!',\n fix: 'NEVER put sk- keys in frontend. Create /api/chat endpoint on server',\n },\n },\n {\n pattern: \"'sk-\",\n metadata: {\n type: 'pattern',\n severity: 'critical',\n category: 'exposed-secrets',\n description: 'OpenAI API key pattern detected in string',\n commonMistake: 'AI generates code with OpenAI key in frontend - anyone can steal it!',\n fix: 'NEVER put sk- keys in frontend. Create /api/chat endpoint on server',\n },\n },\n {\n pattern: '`sk-',\n metadata: {\n type: 'pattern',\n severity: 'critical',\n category: 'exposed-secrets',\n description: 'OpenAI API key pattern detected in template',\n commonMistake: 'AI generates code with OpenAI key in frontend - anyone can steal it!',\n fix: 'NEVER put sk- keys in frontend. Create /api/chat endpoint on server',\n },\n },\n {\n pattern: 'sk_live_',\n metadata: {\n type: 'pattern',\n severity: 'critical',\n category: 'exposed-secrets',\n description: 'Stripe live secret key detected',\n commonMistake: 'Stripe secret key in frontend = attackers can charge your account',\n fix: 'Use Stripe.js with publishable key only. Secret key stays on server',\n },\n },\n {\n pattern: 'sk_test_',\n metadata: {\n type: 'pattern',\n severity: 'serious',\n category: 'exposed-secrets',\n description: 'Stripe test secret key in code',\n commonMistake: 'Even test keys shouldnt be in frontend - bad habit',\n fix: 'Move to environment variables on server side',\n },\n },\n\n // ============================================\n // SERIOUS: Giant file anti-patterns\n // ============================================\n {\n pattern: 'function App()',\n metadata: {\n type: 'pattern',\n severity: 'moderate',\n category: 'giant-file',\n description: 'Main App component - check file size',\n commonMistake: 'AI puts EVERYTHING in App.jsx - 1000+ lines, impossible to maintain',\n fix: 'Split into components: Header, Sidebar, MainContent, Footer, etc.',\n },\n },\n {\n pattern: 'export default function Home',\n metadata: {\n type: 'pattern',\n severity: 'moderate',\n category: 'giant-file',\n description: 'Next.js page component - check file size',\n commonMistake: 'AI dumps entire page logic in one file including API calls',\n fix: 'Extract components to /components, hooks to /hooks, API to /lib',\n },\n },\n {\n pattern: 'useState(',\n metadata: {\n type: 'pattern',\n severity: 'low',\n category: 'state-management',\n description: 'useState hook - check if overused',\n commonMistake: 'AI creates 20+ useState calls in one component instead of useReducer',\n fix: 'Group related state with useReducer or create custom hooks',\n },\n },\n\n // ============================================\n // No error handling\n // ============================================\n {\n pattern: 'fetch(',\n metadata: {\n type: 'pattern',\n severity: 'moderate',\n category: 'no-error-handling',\n description: 'fetch call - verify error handling exists',\n commonMistake: 'AI generates fetch() without try/catch or .catch() - app crashes on network error',\n fix: 'Wrap in try/catch, add loading state, show error message to user',\n },\n },\n {\n pattern: 'axios.',\n metadata: {\n type: 'pattern',\n severity: 'moderate',\n category: 'no-error-handling',\n description: 'axios call - verify error handling exists',\n commonMistake: 'AI uses axios without error handling or loading states',\n fix: 'Add try/catch, loading state, and user-friendly error messages',\n },\n },\n {\n pattern: '.then(',\n metadata: {\n type: 'pattern',\n severity: 'low',\n category: 'no-error-handling',\n description: 'Promise chain - check for .catch()',\n commonMistake: 'AI chains .then() without .catch() - silent failures',\n fix: 'Always add .catch() or use async/await with try/catch',\n },\n },\n {\n pattern: 'await ',\n metadata: {\n type: 'pattern',\n severity: 'low',\n category: 'no-error-handling',\n description: 'await - verify try/catch exists',\n commonMistake: 'AI uses await without try/catch wrapper',\n fix: 'Wrap async operations in try/catch blocks',\n },\n },\n\n // ============================================\n // Missing loading/empty states\n // ============================================\n {\n pattern: 'isLoading',\n metadata: {\n type: 'pattern',\n severity: 'low',\n category: 'loading-state',\n description: 'Loading state exists - good!',\n commonMistake: 'This is actually good! Just verify its being used',\n fix: 'Make sure to show spinner/skeleton while isLoading is true',\n },\n },\n {\n pattern: 'loading ?',\n metadata: {\n type: 'pattern',\n severity: 'low',\n category: 'loading-state',\n description: 'Conditional loading render',\n commonMistake: 'AI sometimes forgets the else case for loading',\n fix: 'Show meaningful loading UI, not just null',\n },\n },\n {\n pattern: '{data &&',\n metadata: {\n type: 'pattern',\n severity: 'low',\n category: 'empty-state',\n description: 'Conditional data render',\n commonMistake: 'AI checks if data exists but no UI for when its missing',\n fix: 'Add empty state: \"No items found\" or call-to-action',\n },\n },\n {\n pattern: '{data?.map(',\n metadata: {\n type: 'pattern',\n severity: 'low',\n category: 'empty-state',\n description: 'Optional chaining on map',\n commonMistake: 'Shows nothing when data is empty - confusing for users',\n fix: 'Check data.length and show \"No items yet\" message',\n },\n },\n\n // ============================================\n // Hardcoded values\n // ============================================\n {\n pattern: 'localhost:',\n metadata: {\n type: 'pattern',\n severity: 'serious',\n category: 'hardcoded',\n description: 'Hardcoded localhost URL',\n commonMistake: 'AI hardcodes localhost:3000 URLs - breaks in production',\n fix: 'Use environment variable: process.env.NEXT_PUBLIC_API_URL',\n },\n },\n {\n pattern: 'http://localhost',\n metadata: {\n type: 'pattern',\n severity: 'serious',\n category: 'hardcoded',\n description: 'Hardcoded localhost URL',\n commonMistake: 'Works locally, fails when deployed',\n fix: 'Use relative URLs (/api/...) or environment variables',\n },\n },\n {\n pattern: '127.0.0.1',\n metadata: {\n type: 'pattern',\n severity: 'serious',\n category: 'hardcoded',\n description: 'Hardcoded localhost IP',\n commonMistake: 'Hardcoded local IP wont work in production',\n fix: 'Use environment variables for all URLs',\n },\n },\n\n // ============================================\n // Copy-paste code smells\n // ============================================\n {\n pattern: 'TODO',\n metadata: {\n type: 'pattern',\n severity: 'low',\n category: 'incomplete',\n description: 'TODO comment left behind',\n commonMistake: 'AI leaves TODO comments that never get done',\n fix: 'Either implement the TODO or remove it',\n },\n },\n {\n pattern: 'FIXME',\n metadata: {\n type: 'pattern',\n severity: 'moderate',\n category: 'incomplete',\n description: 'FIXME comment - known issue',\n commonMistake: 'AI acknowledges a problem but doesnt fix it',\n fix: 'Actually fix the issue or create a GitHub issue to track it',\n },\n },\n {\n pattern: '// eslint-disable',\n metadata: {\n type: 'pattern',\n severity: 'moderate',\n category: 'code-smell',\n description: 'ESLint rule disabled',\n commonMistake: 'AI disables linter instead of fixing the actual problem',\n fix: 'Fix the underlying issue, dont silence the linter',\n },\n },\n {\n pattern: '@ts-ignore',\n metadata: {\n type: 'pattern',\n severity: 'moderate',\n category: 'code-smell',\n description: 'TypeScript error ignored',\n commonMistake: 'AI uses @ts-ignore to hide type errors instead of fixing them',\n fix: 'Fix the type error properly or use @ts-expect-error with explanation',\n },\n },\n {\n pattern: '@ts-nocheck',\n metadata: {\n type: 'pattern',\n severity: 'serious',\n category: 'code-smell',\n description: 'TypeScript checking disabled for entire file',\n commonMistake: 'AI disables all type checking - defeats the purpose of TypeScript',\n fix: 'Remove @ts-nocheck and fix type errors one by one',\n },\n },\n {\n pattern: ': any',\n metadata: {\n type: 'pattern',\n severity: 'moderate',\n category: 'code-smell',\n description: 'any type used',\n commonMistake: 'AI uses \"any\" to avoid writing proper types',\n fix: 'Define proper interfaces/types for your data',\n },\n },\n {\n pattern: 'as any',\n metadata: {\n type: 'pattern',\n severity: 'moderate',\n category: 'code-smell',\n description: 'Type assertion to any',\n commonMistake: 'AI casts to \"any\" to silence type errors',\n fix: 'Use proper type narrowing or define correct types',\n },\n },\n\n // ============================================\n // Debug code left in\n // ============================================\n {\n pattern: 'console.log(',\n metadata: {\n type: 'pattern',\n severity: 'low',\n category: 'debug-code',\n description: 'console.log left in code',\n commonMistake: 'AI adds console.log for debugging, forgets to remove',\n fix: 'Remove before production or use proper logging library',\n },\n },\n {\n pattern: 'console.error(',\n metadata: {\n type: 'pattern',\n severity: 'low',\n category: 'debug-code',\n description: 'console.error in code',\n commonMistake: 'Error logging is fine but should use proper error tracking',\n fix: 'Consider using Sentry, LogRocket, or similar for production',\n },\n },\n {\n pattern: 'debugger',\n metadata: {\n type: 'pattern',\n severity: 'serious',\n category: 'debug-code',\n description: 'debugger statement left in code',\n commonMistake: 'AI leaves debugger statements - freezes browser in production!',\n fix: 'Remove all debugger statements before deploying',\n },\n },\n\n // ============================================\n // Bad practices specific to frameworks\n // ============================================\n {\n pattern: 'useEffect(() => {',\n metadata: {\n type: 'pattern',\n severity: 'low',\n category: 'react-antipattern',\n description: 'useEffect usage - verify necessity',\n commonMistake: 'AI overuses useEffect for things that dont need it',\n fix: 'Consider: Is this really a side effect? Could use useMemo, derived state, or event handler instead?',\n learnMore: 'https://react.dev/learn/you-might-not-need-an-effect',\n },\n },\n {\n pattern: 'useEffect(async',\n metadata: {\n type: 'pattern',\n severity: 'serious',\n category: 'react-antipattern',\n description: 'async useEffect - incorrect pattern',\n commonMistake: 'AI makes useEffect async directly - causes warnings and bugs',\n fix: 'Define async function inside useEffect, then call it',\n },\n },\n {\n pattern: ', [])',\n metadata: {\n type: 'pattern',\n severity: 'low',\n category: 'react-antipattern',\n description: 'Empty dependency array',\n commonMistake: 'AI uses [] to \"fix\" useEffect warnings without understanding why',\n fix: 'Verify all dependencies are listed, or intentionally run once',\n },\n },\n {\n pattern: 'key={index}',\n metadata: {\n type: 'pattern',\n severity: 'moderate',\n category: 'react-antipattern',\n description: 'Array index used as key',\n commonMistake: 'AI uses array index as key - causes bugs with reordering/filtering',\n fix: 'Use unique identifier from data: key={item.id}',\n },\n },\n {\n pattern: 'key={i}',\n metadata: {\n type: 'pattern',\n severity: 'moderate',\n category: 'react-antipattern',\n description: 'Loop index used as key',\n commonMistake: 'Using loop index as key breaks React reconciliation',\n fix: 'Use unique identifier: key={item.id} or key={item.slug}',\n },\n },\n\n // ============================================\n // No input validation\n // ============================================\n {\n pattern: 'req.body.',\n metadata: {\n type: 'pattern',\n severity: 'serious',\n category: 'no-validation',\n description: 'Request body accessed directly',\n commonMistake: 'AI trusts user input without validation - security risk!',\n fix: 'Validate with Zod, Yup, or joi before using req.body',\n },\n },\n {\n pattern: 'req.query.',\n metadata: {\n type: 'pattern',\n severity: 'moderate',\n category: 'no-validation',\n description: 'Query param accessed directly',\n commonMistake: 'AI doesnt validate query parameters',\n fix: 'Validate and sanitize query parameters before use',\n },\n },\n {\n pattern: 'req.params.',\n metadata: {\n type: 'pattern',\n severity: 'moderate',\n category: 'no-validation',\n description: 'URL param accessed directly',\n commonMistake: 'AI trusts URL parameters without validation',\n fix: 'Validate params (especially IDs) before database queries',\n },\n },\n\n // ============================================\n // Mixing concerns (DB in components)\n // ============================================\n {\n pattern: 'prisma.',\n metadata: {\n type: 'pattern',\n severity: 'moderate',\n category: 'mixing-concerns',\n description: 'Prisma in component/page',\n commonMistake: 'AI puts database calls directly in React components',\n fix: 'Move to API routes, server actions, or /lib/db.ts',\n },\n },\n {\n pattern: 'mongoose.',\n metadata: {\n type: 'pattern',\n severity: 'moderate',\n category: 'mixing-concerns',\n description: 'Mongoose in component',\n commonMistake: 'Database logic mixed with UI code',\n fix: 'Create separate /lib/db.ts or /services/ for data access',\n },\n },\n {\n pattern: 'supabase.',\n metadata: {\n type: 'pattern',\n severity: 'low',\n category: 'mixing-concerns',\n description: 'Supabase client usage',\n commonMistake: 'AI puts Supabase calls everywhere instead of centralizing',\n fix: 'Create /lib/supabase.ts with helper functions',\n },\n },\n\n // ============================================\n // Common AI oversights\n // ============================================\n {\n pattern: 'onClick={() =>',\n metadata: {\n type: 'pattern',\n severity: 'low',\n category: 'performance',\n description: 'Inline arrow function in onClick',\n commonMistake: 'AI creates new function on every render',\n fix: 'For simple cases its fine, but consider useCallback for expensive components',\n },\n },\n {\n pattern: 'style={{',\n metadata: {\n type: 'pattern',\n severity: 'low',\n category: 'performance',\n description: 'Inline style object',\n commonMistake: 'AI uses inline styles creating new objects every render',\n fix: 'Use CSS classes, Tailwind, or define styles outside component',\n },\n },\n {\n pattern: 'new Date()',\n metadata: {\n type: 'pattern',\n severity: 'low',\n category: 'dates',\n description: 'Date creation',\n commonMistake: 'AI uses new Date() without considering timezones',\n fix: 'Consider timezone handling, use date-fns or dayjs for complex date logic',\n },\n },\n\n // ============================================\n // Vibe coding specific patterns (r/vibecoding)\n // ============================================\n {\n pattern: 'just works',\n metadata: {\n type: 'pattern',\n severity: 'low',\n category: 'vibe-smell',\n description: 'Comment suggesting \"it just works\"',\n commonMistake: 'Classic vibe coding - accepting code without understanding it',\n fix: 'Take time to understand WHY it works, or it will break later',\n },\n },\n {\n pattern: 'idk why',\n metadata: {\n type: 'pattern',\n severity: 'moderate',\n category: 'vibe-smell',\n description: 'Comment admitting confusion',\n commonMistake: 'AI generated something you dont understand - tech debt waiting to happen',\n fix: 'Ask the AI to explain what this code does and why',\n },\n },\n {\n pattern: 'dont touch',\n metadata: {\n type: 'pattern',\n severity: 'moderate',\n category: 'vibe-smell',\n description: 'Warning comment about fragile code',\n commonMistake: 'Code that \"works but nobody knows how\" - very fragile',\n fix: 'Refactor this section or at least document what it does',\n },\n },\n {\n pattern: '// ai generated',\n metadata: {\n type: 'pattern',\n severity: 'low',\n category: 'vibe-smell',\n description: 'AI generated code marker',\n commonMistake: 'At least you labeled it! But did you review it?',\n fix: 'Review AI-generated code for security issues and edge cases',\n },\n },\n {\n pattern: '// cursor',\n metadata: {\n type: 'pattern',\n severity: 'low',\n category: 'vibe-smell',\n description: 'Cursor-generated code marker',\n commonMistake: 'Marked as Cursor-generated - make sure to review',\n fix: 'Verify the logic is correct and handles errors properly',\n },\n },\n {\n pattern: '// copilot',\n metadata: {\n type: 'pattern',\n severity: 'low',\n category: 'vibe-smell',\n description: 'Copilot-generated code marker',\n commonMistake: 'Copilot suggestion accepted without review',\n fix: 'Always review Copilot suggestions for correctness',\n },\n },\n\n // ============================================\n // Deployment/Production issues\n // ============================================\n {\n pattern: 'npm run dev',\n metadata: {\n type: 'pattern',\n severity: 'low',\n category: 'deployment',\n description: 'Dev script reference',\n commonMistake: 'Make sure you also have build and start scripts for production',\n fix: 'Verify you can run: npm run build && npm start',\n },\n },\n {\n pattern: 'development',\n metadata: {\n type: 'pattern',\n severity: 'low',\n category: 'deployment',\n description: 'Development mode reference',\n commonMistake: 'Ensure dev-only code doesnt run in production',\n fix: 'Check NODE_ENV and use proper environment detection',\n },\n },\n {\n pattern: '.env.local',\n metadata: {\n type: 'pattern',\n severity: 'low',\n category: 'deployment',\n description: 'Local env file reference',\n commonMistake: 'Local env works, but did you set up production env vars?',\n fix: 'Set up environment variables in your deployment platform',\n },\n },\n\n // ============================================\n // Common LLM hallucination patterns\n // ============================================\n {\n pattern: 'import { something }',\n metadata: {\n type: 'pattern',\n severity: 'low',\n category: 'hallucination',\n description: 'Named import - verify it exists',\n commonMistake: 'AI sometimes imports functions that dont exist in the library',\n fix: 'If you get \"X is not exported\" error, check library docs',\n },\n },\n {\n pattern: 'v3',\n metadata: {\n type: 'pattern',\n severity: 'low',\n category: 'hallucination',\n description: 'Version number in code',\n commonMistake: 'AI may use outdated API patterns from old library versions',\n fix: 'Check you are using the correct API for your installed version',\n },\n },\n\n // ============================================\n // Quick prototyping shortcuts that become problems\n // ============================================\n {\n pattern: 'setTimeout(',\n metadata: {\n type: 'pattern',\n severity: 'moderate',\n category: 'timing-hack',\n description: 'setTimeout usage',\n commonMistake: 'AI uses setTimeout to \"fix\" race conditions instead of proper async',\n fix: 'Use proper async/await, promises, or state management instead',\n },\n },\n {\n pattern: 'sleep(',\n metadata: {\n type: 'pattern',\n severity: 'moderate',\n category: 'timing-hack',\n description: 'Sleep function usage',\n commonMistake: 'Artificial delays hide real timing issues',\n fix: 'Fix the underlying race condition instead of adding delays',\n },\n },\n {\n pattern: 'window.location.reload',\n metadata: {\n type: 'pattern',\n severity: 'moderate',\n category: 'hack',\n description: 'Page reload to \"fix\" state issues',\n commonMistake: 'AI reloads page instead of properly managing state',\n fix: 'Fix state management - reloading is bad UX',\n },\n },\n {\n pattern: 'force: true',\n metadata: {\n type: 'pattern',\n severity: 'moderate',\n category: 'hack',\n description: 'Force flag usage',\n commonMistake: 'AI uses force flags to bypass checks instead of fixing root cause',\n fix: 'Understand why the check exists before bypassing it',\n },\n },\n];\n\n/**\n * File-level checks (not pattern based, but size/structure based)\n */\nexport interface FileLevelIssue {\n file: string;\n issue: string;\n severity: 'critical' | 'serious' | 'moderate' | 'low';\n category: string;\n commonMistake: string;\n fix: string;\n}\n\nexport function checkFileLevelIssues(filePath: string, content: string): FileLevelIssue[] {\n const issues: FileLevelIssue[] = [];\n const lines = content.split('\\n');\n const lineCount = lines.length;\n const fileName = filePath.split('/').pop() || '';\n\n // Giant file check\n if (lineCount > 500) {\n issues.push({\n file: filePath,\n issue: `File has ${lineCount} lines - way too big!`,\n severity: lineCount > 1000 ? 'serious' : 'moderate',\n category: 'giant-file',\n commonMistake: 'AI dumps everything in one file. Reddit is FULL of posts about 2000 line App.jsx files',\n fix: `Split into smaller files. Rule of thumb: components < 200 lines, pages < 300 lines`,\n });\n }\n\n // Too many useState\n const useStateCount = (content.match(/useState\\(/g) || []).length;\n if (useStateCount > 10) {\n issues.push({\n file: filePath,\n issue: `${useStateCount} useState hooks in one component`,\n severity: useStateCount > 15 ? 'serious' : 'moderate',\n category: 'state-explosion',\n commonMistake: 'AI creates separate useState for every field instead of grouping',\n fix: 'Group related state into objects, or use useReducer for complex state',\n });\n }\n\n // Too many useEffect\n const useEffectCount = (content.match(/useEffect\\(/g) || []).length;\n if (useEffectCount > 5) {\n issues.push({\n file: filePath,\n issue: `${useEffectCount} useEffect hooks - probably too many`,\n severity: 'moderate',\n category: 'effect-hell',\n commonMistake: 'AI creates useEffect for everything. Most effects are unnecessary',\n fix: 'Review each useEffect - many can be replaced with event handlers or derived state',\n });\n }\n\n // Main file patterns\n if (/^(App|app|main|Main|index|page)\\.(jsx?|tsx?)$/.test(fileName) && lineCount > 300) {\n issues.push({\n file: filePath,\n issue: `Main entry file is ${lineCount} lines`,\n severity: 'serious',\n category: 'giant-main',\n commonMistake: 'Classic AI pattern: everything in App.jsx or page.tsx',\n fix: 'Extract: Header, Footer, Sidebar, MainContent as separate components',\n });\n }\n\n // No TypeScript types\n if (filePath.endsWith('.tsx') || filePath.endsWith('.ts')) {\n const anyCount = (content.match(/:\\s*any\\b/g) || []).length;\n if (anyCount > 5) {\n issues.push({\n file: filePath,\n issue: `${anyCount} uses of \"any\" type`,\n severity: 'moderate',\n category: 'weak-typing',\n commonMistake: 'AI uses \"any\" to avoid writing proper types',\n fix: 'Define interfaces for your data shapes. AI can help: \"Generate types for this data\"',\n });\n }\n }\n\n // Console.log density\n const consoleLogCount = (content.match(/console\\.(log|warn|error|debug)/g) || []).length;\n if (consoleLogCount > 10) {\n issues.push({\n file: filePath,\n issue: `${consoleLogCount} console statements - cleanup needed`,\n severity: 'low',\n category: 'debug-code',\n commonMistake: 'AI adds console.log for debugging, user never removes them',\n fix: 'Remove debug logs before deploying. Use proper error tracking for production.',\n });\n }\n\n return issues;\n}\n\n/**\n * Build the vibe code trie\n */\nlet vibeCodeTrie: AhoCorasick<PatternMetadata & { commonMistake: string }> | null = null;\n\nexport function getVibeCodeTrie(): AhoCorasick<PatternMetadata & { commonMistake: string }> {\n if (!vibeCodeTrie) {\n vibeCodeTrie = new AhoCorasick<PatternMetadata & { commonMistake: string }>();\n \n for (const { pattern, metadata } of VIBE_CODE_PATTERNS) {\n vibeCodeTrie.addPattern(pattern, metadata, metadata);\n }\n \n vibeCodeTrie.build();\n if (!isInteractiveMode()) {\n console.error(` Loaded ${VIBE_CODE_PATTERNS.length} vibe-code patterns into trie`);\n }\n }\n \n return vibeCodeTrie;\n}\n\n/**\n * Files/patterns to exclude from vibe code checks\n */\nconst VIBE_EXCLUDED_PATTERNS = [\n /package-lock\\.json$/,\n /yarn\\.lock$/,\n /pnpm-lock\\.yaml$/,\n /node_modules[\\/\\\\]/,\n /\\.min\\.[jt]s$/,\n /dist[\\/\\\\]/,\n /build[\\/\\\\]/,\n /\\.d\\.ts$/,\n /vulnerability-signatures\\.[jt]s$/, // CRITICAL: Never scan ourselves!\n /vibe-code-signatures\\.[jt]s$/, // Never scan signature files\n /legal\\.[jt]s$/, // Legal skill contains detection patterns\n /security-scanner\\.[jt]s$/, // Security scanner contains patterns\n /agent-smith\\.[jt]s$/, // Agent Smith contains patterns\n /security\\.[jt]s$/, // Security skill\n /privacy\\.[jt]s$/, // Privacy skill\n /soc2\\.[jt]s$/, // SOC2 skill\n /skills[\\/\\\\]built-in[\\/\\\\]/, // Never scan Trie's own skill implementations\n /skills[\\/\\\\].*\\.[jt]s$/, // Never scan any skills directory\n /trie-agents?[\\/\\\\]src[\\/\\\\]/, // Never scan Trie's source when installed as dependency\n /trie-agents?[\\/\\\\]dist[\\/\\\\]/, // Never scan Trie's dist when installed\n];\n\n/**\n * Check if a file should be excluded from vibe code scans\n */\nfunction shouldExcludeVibeFile(filePath: string): boolean {\n // Normalize path to use forward slashes for consistent matching\n const normalizedPath = filePath.replace(/\\\\/g, '/');\n \n // Check against exclusion patterns\n if (VIBE_EXCLUDED_PATTERNS.some(pattern => pattern.test(normalizedPath))) {\n return true;\n }\n \n // Also exclude files in Trie's source directories (handles both installed and development)\n if (normalizedPath.includes('trie') && normalizedPath.includes('/src/')) {\n return true;\n }\n \n // Exclude specific Trie scanner/skill files by filename (regardless of path)\n const fileName = normalizedPath.split('/').pop() || '';\n const TRIE_SCANNER_FILES = [\n 'vulnerability-signatures.ts', 'vulnerability-signatures.js',\n 'vibe-code-signatures.ts', 'vibe-code-signatures.js',\n 'legal.ts', 'legal.js',\n 'security-scanner.ts', 'security-scanner.js',\n 'agent-smith.ts', 'agent-smith.js',\n 'security.ts', 'security.js',\n 'privacy.ts', 'privacy.js',\n 'soc2.ts', 'soc2.js',\n ];\n if (TRIE_SCANNER_FILES.includes(fileName)) {\n // Only exclude if it looks like it's in a skills/trie directory\n if (normalizedPath.includes('/skills/') || normalizedPath.includes('/trie/')) {\n return true;\n }\n }\n \n return false;\n}\n\n/**\n * Check if line is a false positive for vibe patterns\n */\nfunction isVibeFalsePositive(line: string, pattern: string, filePath: string, category: string): boolean {\n const trimmedLine = line.trim();\n \n // Skip comments\n if (trimmedLine.startsWith('//') || \n trimmedLine.startsWith('*') || \n trimmedLine.startsWith('/*') ||\n trimmedLine.startsWith('#')) {\n return true;\n }\n \n // Skip type definitions\n if (/^\\s*(interface|type|export\\s+interface|export\\s+type)\\s/.test(line)) {\n return true;\n }\n \n // Skip when reading from environment\n if (/process\\.env|import\\.meta\\.env/.test(line)) {\n // Allow NEXT_PUBLIC_, VITE_, REACT_APP_ when reading env\n if (['exposed-secrets'].includes(category) && !/=\\s*['\"`]/.test(line)) {\n return true;\n }\n }\n \n // Pattern-specific false positive detection\n switch (pattern) {\n case 'console.log(':\n case 'console.error(':\n // Allow in development/debug files\n if (/debug|dev|development/i.test(filePath)) return true;\n // Allow console.error for error handling\n if (pattern === 'console.error(') return true;\n break;\n \n case 'useState(':\n // Low severity, only flag if excessive (handled by file-level checks)\n return true; // Don't flag individual useState\n \n case 'await ':\n // Very common, only flag if there's obvious missing try/catch\n // Let the file-level check handle this\n return true;\n \n case '.then(':\n // Only flag if no .catch in nearby context\n return true; // Too noisy, disable\n \n case 'TODO':\n case 'FIXME':\n // These are intentional markers, low priority\n break;\n \n case 'useEffect(() => {':\n // Very common, only flag excessive usage via file-level checks\n return true;\n \n case ', [])':\n // Common and often correct, disable as too noisy\n return true;\n \n case 'development':\n // Too generic\n return true;\n \n case 'import { something }':\n // Way too generic, disable\n return true;\n \n case 'v3':\n // Too generic\n return true;\n \n case 'new Date()':\n // Very common and usually fine\n return true;\n \n case 'style={{':\n case 'onClick={() =>':\n // Common patterns, not always a problem\n return true;\n }\n \n // Skip test files for most patterns\n if (/\\.(test|spec)\\.[jt]sx?$/.test(filePath) || /__tests__\\//.test(filePath)) {\n // Only keep critical patterns (exposed secrets) in test files\n if (!['exposed-secrets'].includes(category)) {\n return true;\n }\n }\n \n return false;\n}\n\n/**\n * Scan for vibe code issues\n */\nexport function scanForVibeCodeIssues(code: string, filePath: string): VibeCodeMatch[] {\n // Skip excluded files entirely\n if (shouldExcludeVibeFile(filePath)) {\n return [];\n }\n \n const trie = getVibeCodeTrie();\n const rawMatches = trie.search(code);\n const lines = code.split('\\n');\n \n const matches: VibeCodeMatch[] = [];\n const seen = new Set<string>();\n \n for (const match of rawMatches) {\n const key = `${match.line}:${match.pattern}`;\n if (seen.has(key)) continue;\n seen.add(key);\n \n const line = lines[match.line - 1] || '';\n const meta = match.metadata as any;\n const category = meta.category || 'unknown';\n \n // Check for false positives\n if (isVibeFalsePositive(line, match.pattern, filePath, category)) continue;\n \n matches.push({\n pattern: match.pattern,\n line: match.line,\n column: match.column,\n severity: meta.severity,\n category,\n description: meta.description || '',\n commonMistake: meta.commonMistake || '',\n fix: meta.fix || '',\n learnMore: meta.learnMore,\n });\n }\n \n return matches;\n}\n\n/**\n * Get vibe code pattern statistics\n */\nexport function getVibeCodeStats(): { total: number; byCategory: Record<string, number> } {\n const byCategory: Record<string, number> = {};\n \n for (const { metadata } of VIBE_CODE_PATTERNS) {\n const cat = metadata.category || 'unknown';\n byCategory[cat] = (byCategory[cat] || 0) + 1;\n }\n \n return {\n total: VIBE_CODE_PATTERNS.length,\n byCategory,\n };\n}\n\n"],"mappings":"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","names":[]}
@@ -1,254 +0,0 @@
1
- import {
2
- Trie
3
- } from "./chunk-6NLHFIYA.js";
4
- import {
5
- atomicWriteJSON
6
- } from "./chunk-43X6JBEM.js";
7
- import {
8
- getTrieDirectory
9
- } from "./chunk-VVITXIHN.js";
10
-
11
- // src/context/codebase-index.ts
12
- import { readFile, stat } from "fs/promises";
13
- import { createHash } from "crypto";
14
- import { join } from "path";
15
- import { existsSync, readFileSync } from "fs";
16
- var CodebaseIndex = class {
17
- trie = new Trie();
18
- projectPath;
19
- indexPath;
20
- lastUpdated = null;
21
- constructor(projectPath) {
22
- this.projectPath = projectPath;
23
- this.indexPath = join(getTrieDirectory(projectPath), "codebase-index.json");
24
- this.load();
25
- }
26
- /**
27
- * Load index from disk if it exists
28
- */
29
- load() {
30
- if (!existsSync(this.indexPath)) return;
31
- try {
32
- const raw = JSON.parse(readFileSync(this.indexPath, "utf-8"));
33
- if (raw.trie) {
34
- this.trie = Trie.fromJSON(raw.trie);
35
- }
36
- if (raw.lastUpdated) {
37
- this.lastUpdated = raw.lastUpdated;
38
- }
39
- } catch (error) {
40
- console.error("Failed to load codebase index:", error);
41
- }
42
- }
43
- /**
44
- * Save index to disk
45
- */
46
- async save() {
47
- this.lastUpdated = (/* @__PURE__ */ new Date()).toISOString();
48
- const data = {
49
- version: 1,
50
- lastUpdated: this.lastUpdated,
51
- fileCount: this.trie.getWithPrefix("").length,
52
- trie: this.trie.toJSON()
53
- };
54
- await atomicWriteJSON(this.indexPath, data);
55
- }
56
- /**
57
- * Add or update a file in the index
58
- * Returns null if the file doesn't exist or can't be read
59
- */
60
- async indexFile(filePath) {
61
- if (filePath.startsWith("/")) {
62
- if (!filePath.toLowerCase().startsWith(this.projectPath.toLowerCase())) {
63
- return null;
64
- }
65
- }
66
- const absolutePath = filePath.startsWith("/") ? filePath : join(this.projectPath, filePath);
67
- try {
68
- const content = await readFile(absolutePath, "utf-8");
69
- const stats = await stat(absolutePath);
70
- const hash = createHash("sha256").update(content).digest("hex");
71
- const metadata = {
72
- path: filePath,
73
- hash,
74
- size: stats.size,
75
- lastModified: stats.mtimeMs,
76
- type: filePath.split(".").pop() || ""
77
- };
78
- const existing = this.trie.search(filePath);
79
- if (existing.found && existing.value) {
80
- if (existing.value.hash === hash) {
81
- if (existing.value.violations) metadata.violations = existing.value.violations;
82
- if (existing.value.lastScanned != null) metadata.lastScanned = existing.value.lastScanned;
83
- }
84
- }
85
- this.trie.insert(filePath, metadata);
86
- return metadata;
87
- } catch (error) {
88
- return null;
89
- }
90
- }
91
- /**
92
- * Get file metadata from index
93
- */
94
- getFile(filePath) {
95
- const result = this.trie.search(filePath);
96
- return result.found && result.value ? result.value : null;
97
- }
98
- /**
99
- * Check if file has changed since last index
100
- */
101
- async hasChanged(filePath) {
102
- if (filePath.startsWith("/") && !filePath.toLowerCase().startsWith(this.projectPath.toLowerCase())) {
103
- return true;
104
- }
105
- const metadata = this.getFile(filePath);
106
- if (!metadata) return true;
107
- const absolutePath = filePath.startsWith("/") ? filePath : join(this.projectPath, filePath);
108
- try {
109
- const stats = await stat(absolutePath);
110
- if (stats.mtimeMs !== metadata.lastModified) return true;
111
- const content = await readFile(absolutePath, "utf-8");
112
- const hash = createHash("sha256").update(content).digest("hex");
113
- return hash !== metadata.hash;
114
- } catch {
115
- return true;
116
- }
117
- }
118
- /**
119
- * Get files in a directory
120
- */
121
- getDirectoryFiles(directoryPath) {
122
- const prefix = directoryPath.endsWith("/") ? directoryPath : `${directoryPath}/`;
123
- const matches = this.trie.getWithPrefix(prefix);
124
- return matches.map((m) => m.value).filter((v) => v !== null);
125
- }
126
- /**
127
- * Get files that match a pattern (uses Trie prefix matching)
128
- */
129
- getFilesWithPrefix(prefix) {
130
- const matches = this.trie.getWithPrefix(prefix);
131
- return matches.map((m) => m.value).filter((v) => v !== null);
132
- }
133
- /**
134
- * Get files by type (extension)
135
- */
136
- getFilesByType(type) {
137
- const allFiles = this.trie.getWithPrefix("");
138
- return allFiles.map((m) => m.value).filter((v) => v != null && v.type === type);
139
- }
140
- /**
141
- * Record goal violation scan result for a file
142
- */
143
- recordViolation(filePath, goalId, goalDescription, found, details, confidence) {
144
- const metadata = this.getFile(filePath);
145
- if (!metadata) return;
146
- metadata.lastScanned = Date.now();
147
- if (!metadata.violations) metadata.violations = [];
148
- metadata.violations = metadata.violations.filter((v) => v.goalId !== goalId);
149
- const entry = {
150
- goalId,
151
- goalDescription,
152
- found,
153
- timestamp: Date.now()
154
- };
155
- if (details !== void 0) entry.details = details;
156
- if (confidence !== void 0) entry.confidence = confidence;
157
- metadata.violations.push(entry);
158
- this.trie.insert(filePath, metadata);
159
- }
160
- /**
161
- * Get cached violation results for a file
162
- */
163
- getCachedViolations(filePath, goalId) {
164
- const metadata = this.getFile(filePath);
165
- if (!metadata || !metadata.violations) return void 0;
166
- if (goalId) {
167
- return metadata.violations.filter((v) => v.goalId === goalId);
168
- }
169
- return metadata.violations;
170
- }
171
- /**
172
- * Check if the index is empty (needs initial indexing)
173
- */
174
- isEmpty() {
175
- return this.trie.getWithPrefix("").length === 0;
176
- }
177
- /**
178
- * Get statistics about the index
179
- */
180
- getStats() {
181
- const allFiles = this.trie.getWithPrefix("").map((m) => m.value).filter((v) => v !== null);
182
- const stats = {
183
- totalFiles: allFiles.length,
184
- totalSize: allFiles.reduce((sum, f) => sum + f.size, 0),
185
- filesByType: {},
186
- scannedFiles: allFiles.filter((f) => f.lastScanned).length,
187
- filesWithViolations: allFiles.filter((f) => f.violations && f.violations.some((v) => v.found)).length,
188
- lastUpdated: this.lastUpdated
189
- };
190
- for (const file of allFiles) {
191
- stats.filesByType[file.type] = (stats.filesByType[file.type] || 0) + 1;
192
- }
193
- return stats;
194
- }
195
- /**
196
- * Clear stale cached results (older than maxAgeMs)
197
- */
198
- clearStaleCache(maxAgeMs = 7 * 24 * 60 * 60 * 1e3) {
199
- const allFiles = this.trie.getWithPrefix("").map((m) => m.value).filter((v) => v !== null);
200
- const cutoff = Date.now() - maxAgeMs;
201
- let cleared = 0;
202
- for (const file of allFiles) {
203
- if (file.violations) {
204
- const before = file.violations.length;
205
- file.violations = file.violations.filter((v) => v.timestamp > cutoff);
206
- cleared += before - file.violations.length;
207
- if (file.violations.length === 0) {
208
- delete file.lastScanned;
209
- }
210
- this.trie.insert(file.path, file);
211
- }
212
- }
213
- return cleared;
214
- }
215
- /**
216
- * Get file count
217
- */
218
- getFileCount() {
219
- return this.trie.getWithPrefix("").length;
220
- }
221
- /**
222
- * Get approximate cache size in bytes
223
- */
224
- getCacheSize() {
225
- const allFiles = this.trie.getWithPrefix("").map((m) => m.value).filter((v) => v !== null);
226
- return allFiles.reduce((sum, file) => {
227
- const violationSize = file.violations ? file.violations.reduce((vSum, v) => vSum + (v.details?.length || 50), 0) : 0;
228
- return sum + file.path.length + violationSize;
229
- }, 0);
230
- }
231
- /**
232
- * Get last updated timestamp
233
- */
234
- getLastUpdated() {
235
- return this.lastUpdated;
236
- }
237
- /**
238
- * Set cached violations for a file and goal (used by fast analyzer)
239
- */
240
- setCachedViolations(filePath, goalId, violations) {
241
- const metadata = this.getFile(filePath);
242
- if (!metadata) return;
243
- metadata.lastScanned = Date.now();
244
- if (!metadata.violations) metadata.violations = [];
245
- metadata.violations = metadata.violations.filter((v) => v.goalId !== goalId);
246
- metadata.violations.push(...violations);
247
- this.trie.insert(filePath, metadata);
248
- }
249
- };
250
-
251
- export {
252
- CodebaseIndex
253
- };
254
- //# sourceMappingURL=chunk-Q5EKA5YA.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/context/codebase-index.ts"],"sourcesContent":["/**\n * Codebase Index - Fast file indexing for goal violation detection\n * \n * Uses Trie structure for efficient file lookup and caching to avoid\n * re-scanning unchanged files.\n * \n * For large codebases, this dramatically improves goal check performance:\n * - Indexes file hashes to detect changes\n * - Caches AI analysis results\n * - Uses Trie for O(m) lookups where m = path length\n * - Stores file metadata (size, type, last modified, etc.)\n */\n\nimport { readFile, stat } from 'fs/promises';\nimport { createHash } from 'crypto';\nimport { join } from 'path';\nimport { existsSync, readFileSync } from 'fs';\nimport { Trie } from '../trie/trie.js';\nimport { getTrieDirectory } from '../utils/workspace.js';\nimport { atomicWriteJSON } from '../utils/atomic-write.js';\n\nexport interface FileMetadata {\n path: string;\n hash: string; // SHA-256 of content\n size: number;\n lastModified: number;\n type: string; // Extension\n lastScanned?: number; // Timestamp of last AI scan\n violations?: {\n goalId: string;\n goalDescription: string;\n found: boolean;\n details?: string;\n confidence?: number;\n timestamp: number;\n }[];\n}\n\nexport interface CodebaseIndexData {\n version: number;\n lastUpdated: string;\n fileCount: number;\n trie: any; // Serialized Trie\n}\n\nexport class CodebaseIndex {\n private trie: Trie<FileMetadata> = new Trie();\n private projectPath: string;\n private indexPath: string;\n private lastUpdated: string | null = null;\n\n constructor(projectPath: string) {\n this.projectPath = projectPath;\n this.indexPath = join(getTrieDirectory(projectPath), 'codebase-index.json');\n this.load();\n }\n\n /**\n * Load index from disk if it exists\n */\n private load(): void {\n if (!existsSync(this.indexPath)) return;\n\n try {\n const raw = JSON.parse(readFileSync(this.indexPath, 'utf-8'));\n if (raw.trie) {\n this.trie = Trie.fromJSON<FileMetadata>(raw.trie);\n }\n if (raw.lastUpdated) {\n this.lastUpdated = raw.lastUpdated;\n }\n } catch (error) {\n console.error('Failed to load codebase index:', error);\n }\n }\n\n /**\n * Save index to disk\n */\n async save(): Promise<void> {\n this.lastUpdated = new Date().toISOString();\n const data: CodebaseIndexData = {\n version: 1,\n lastUpdated: this.lastUpdated,\n fileCount: this.trie.getWithPrefix('').length,\n trie: this.trie.toJSON(),\n };\n\n await atomicWriteJSON(this.indexPath, data);\n }\n\n /**\n * Add or update a file in the index\n * Returns null if the file doesn't exist or can't be read\n */\n async indexFile(filePath: string): Promise<FileMetadata | null> {\n // Safety check: if filePath is already absolute and doesn't start with projectPath,\n // this is likely a bug (stale cache entry from different project)\n if (filePath.startsWith('/')) {\n // Already absolute - check if it's within our project\n if (!filePath.toLowerCase().startsWith(this.projectPath.toLowerCase())) {\n return null; // Wrong project, skip silently\n }\n // It's absolute but within our project - use as-is\n }\n \n // Build absolute path: if filePath is relative, join with projectPath\n // If filePath is absolute (and within project), use it directly\n const absolutePath = filePath.startsWith('/') ? filePath : join(this.projectPath, filePath);\n \n try {\n const content = await readFile(absolutePath, 'utf-8');\n const stats = await stat(absolutePath);\n const hash = createHash('sha256').update(content).digest('hex');\n\n const metadata: FileMetadata = {\n path: filePath,\n hash,\n size: stats.size,\n lastModified: stats.mtimeMs,\n type: filePath.split('.').pop() || '',\n };\n\n // Check if file exists in index\n const existing = this.trie.search(filePath);\n if (existing.found && existing.value) {\n // File exists - preserve violations if hash matches\n if (existing.value.hash === hash) {\n if (existing.value.violations) metadata.violations = existing.value.violations;\n if (existing.value.lastScanned != null) metadata.lastScanned = existing.value.lastScanned;\n }\n }\n\n this.trie.insert(filePath, metadata);\n return metadata;\n } catch (error) {\n // File doesn't exist, was deleted, or can't be read - return null\n return null;\n }\n }\n\n /**\n * Get file metadata from index\n */\n getFile(filePath: string): FileMetadata | null {\n const result = this.trie.search(filePath);\n return result.found && result.value ? result.value : null;\n }\n\n /**\n * Check if file has changed since last index\n */\n async hasChanged(filePath: string): Promise<boolean> {\n // Safety check for absolute paths from wrong project\n if (filePath.startsWith('/') && !filePath.toLowerCase().startsWith(this.projectPath.toLowerCase())) {\n return true; // Wrong project, treat as changed (will be skipped later)\n }\n \n const metadata = this.getFile(filePath);\n if (!metadata) return true; // Not indexed = changed\n\n // Build absolute path correctly\n const absolutePath = filePath.startsWith('/') ? filePath : join(this.projectPath, filePath);\n try {\n const stats = await stat(absolutePath);\n if (stats.mtimeMs !== metadata.lastModified) return true;\n\n // Double-check with hash for certainty\n const content = await readFile(absolutePath, 'utf-8');\n const hash = createHash('sha256').update(content).digest('hex');\n return hash !== metadata.hash;\n } catch {\n return true; // Error = assume changed\n }\n }\n\n /**\n * Get files in a directory\n */\n getDirectoryFiles(directoryPath: string): FileMetadata[] {\n const prefix = directoryPath.endsWith('/') ? directoryPath : `${directoryPath}/`;\n const matches = this.trie.getWithPrefix(prefix);\n return matches.map(m => m.value).filter((v): v is FileMetadata => v !== null);\n }\n\n /**\n * Get files that match a pattern (uses Trie prefix matching)\n */\n getFilesWithPrefix(prefix: string): FileMetadata[] {\n const matches = this.trie.getWithPrefix(prefix);\n return matches.map(m => m.value).filter((v): v is FileMetadata => v !== null);\n }\n\n /**\n * Get files by type (extension)\n */\n getFilesByType(type: string): FileMetadata[] {\n const allFiles = this.trie.getWithPrefix('');\n return allFiles\n .map(m => m.value)\n .filter((v): v is FileMetadata => v != null && v.type === type);\n }\n\n /**\n * Record goal violation scan result for a file\n */\n recordViolation(\n filePath: string,\n goalId: string,\n goalDescription: string,\n found: boolean,\n details?: string,\n confidence?: number\n ): void {\n const metadata = this.getFile(filePath);\n if (!metadata) return;\n\n metadata.lastScanned = Date.now();\n if (!metadata.violations) metadata.violations = [];\n\n // Remove existing violation for this goal\n metadata.violations = metadata.violations.filter(v => v.goalId !== goalId);\n\n // Add new violation result\n const entry: { goalId: string; goalDescription: string; found: boolean; timestamp: number; details?: string; confidence?: number } = {\n goalId,\n goalDescription,\n found,\n timestamp: Date.now(),\n };\n if (details !== undefined) entry.details = details;\n if (confidence !== undefined) entry.confidence = confidence;\n metadata.violations.push(entry);\n\n this.trie.insert(filePath, metadata);\n }\n\n /**\n * Get cached violation results for a file\n */\n getCachedViolations(filePath: string, goalId?: string): FileMetadata['violations'] {\n const metadata = this.getFile(filePath);\n if (!metadata || !metadata.violations) return undefined;\n\n if (goalId) {\n return metadata.violations.filter(v => v.goalId === goalId);\n }\n\n return metadata.violations;\n }\n\n /**\n * Check if the index is empty (needs initial indexing)\n */\n isEmpty(): boolean {\n return this.trie.getWithPrefix('').length === 0;\n }\n\n /**\n * Get statistics about the index\n */\n getStats(): {\n totalFiles: number;\n totalSize: number;\n filesByType: Record<string, number>;\n scannedFiles: number;\n filesWithViolations: number;\n lastUpdated: string | null;\n } {\n const allFiles = this.trie.getWithPrefix('').map(m => m.value).filter((v): v is FileMetadata => v !== null);\n\n const stats = {\n totalFiles: allFiles.length,\n totalSize: allFiles.reduce((sum, f) => sum + f.size, 0),\n filesByType: {} as Record<string, number>,\n scannedFiles: allFiles.filter(f => f.lastScanned).length,\n filesWithViolations: allFiles.filter(f => f.violations && f.violations.some(v => v.found)).length,\n lastUpdated: this.lastUpdated,\n };\n\n for (const file of allFiles) {\n stats.filesByType[file.type] = (stats.filesByType[file.type] || 0) + 1;\n }\n\n return stats;\n }\n\n /**\n * Clear stale cached results (older than maxAgeMs)\n */\n clearStaleCache(maxAgeMs: number = 7 * 24 * 60 * 60 * 1000): number {\n const allFiles = this.trie.getWithPrefix('').map(m => m.value).filter((v): v is FileMetadata => v !== null);\n const cutoff = Date.now() - maxAgeMs;\n let cleared = 0;\n\n for (const file of allFiles) {\n if (file.violations) {\n const before = file.violations.length;\n file.violations = file.violations.filter(v => v.timestamp > cutoff);\n cleared += before - file.violations.length;\n if (file.violations.length === 0) {\n delete file.lastScanned;\n }\n this.trie.insert(file.path, file);\n }\n }\n\n return cleared;\n }\n\n /**\n * Get file count\n */\n getFileCount(): number {\n return this.trie.getWithPrefix('').length;\n }\n\n /**\n * Get approximate cache size in bytes\n */\n getCacheSize(): number {\n const allFiles = this.trie.getWithPrefix('').map(m => m.value).filter((v): v is FileMetadata => v !== null);\n return allFiles.reduce((sum, file) => {\n const violationSize = file.violations\n ? file.violations.reduce((vSum, v) => vSum + (v.details?.length || 50), 0)\n : 0;\n return sum + file.path.length + violationSize;\n }, 0);\n }\n\n /**\n * Get last updated timestamp\n */\n getLastUpdated(): string | null {\n return this.lastUpdated;\n }\n\n /**\n * Set cached violations for a file and goal (used by fast analyzer)\n */\n setCachedViolations(\n filePath: string,\n goalId: string,\n violations: Array<{\n goalId: string;\n goalDescription: string;\n found: boolean;\n details?: string;\n confidence?: number;\n timestamp: number;\n }>\n ): void {\n const metadata = this.getFile(filePath);\n if (!metadata) return;\n\n metadata.lastScanned = Date.now();\n if (!metadata.violations) metadata.violations = [];\n\n // Remove existing violations for this goal\n metadata.violations = metadata.violations.filter(v => v.goalId !== goalId);\n\n // Add new violations\n metadata.violations.push(...violations);\n\n this.trie.insert(filePath, metadata);\n }\n}\n"],"mappings":"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","names":[]}
@@ -1,132 +0,0 @@
1
- import {
2
- loadConfig
3
- } from "./chunk-XPZZFPBZ.js";
4
-
5
- // src/ingest/linear-ingester.ts
6
- import path from "path";
7
- var LinearIngester = class {
8
- graph;
9
- constructor(_projectPath, graph) {
10
- this.graph = graph;
11
- }
12
- async syncTickets() {
13
- const apiKey = await this.getApiKey();
14
- if (!apiKey) {
15
- console.warn('Linear API key not found. Run "trie linear auth <key>" to enable ticket sync.');
16
- return;
17
- }
18
- const tickets = await this.fetchActiveTickets(apiKey);
19
- for (const ticket of tickets) {
20
- await this.ingestTicket(ticket);
21
- }
22
- }
23
- async getApiKey() {
24
- const config = await loadConfig();
25
- return config.apiKeys?.linear ?? process.env.LINEAR_API_KEY ?? null;
26
- }
27
- async fetchActiveTickets(apiKey) {
28
- const query = `
29
- query {
30
- issues(filter: { state: { type: { in: ["started", "unstarted"] } } }) {
31
- nodes {
32
- id
33
- identifier
34
- title
35
- description
36
- priority
37
- url
38
- status {
39
- name
40
- }
41
- assignee {
42
- name
43
- }
44
- labels {
45
- nodes {
46
- name
47
- }
48
- }
49
- createdAt
50
- updatedAt
51
- }
52
- }
53
- }
54
- `;
55
- const response = await fetch("https://api.linear.app/graphql", {
56
- method: "POST",
57
- headers: {
58
- "Content-Type": "application/json",
59
- "Authorization": apiKey
60
- },
61
- body: JSON.stringify({ query })
62
- });
63
- if (!response.ok) {
64
- throw new Error(`Linear API error: ${response.statusText}`);
65
- }
66
- const data = await response.json();
67
- return data.data.issues.nodes;
68
- }
69
- async ingestTicket(ticket) {
70
- const labels = ticket.labels.nodes.map((l) => l.name);
71
- const intentVibe = this.extractIntentVibes(ticket.title, ticket.description, labels);
72
- const linkedFiles = this.extractLinkedFiles(ticket.description);
73
- const data = {
74
- ticketId: ticket.identifier,
75
- title: ticket.title,
76
- description: ticket.description || "",
77
- priority: this.mapPriority(ticket.priority),
78
- labels,
79
- intentVibe,
80
- linkedFiles,
81
- status: ticket.status.name,
82
- assignee: ticket.assignee?.name || null,
83
- url: ticket.url || `https://linear.app/issue/${ticket.identifier}`,
84
- createdAt: ticket.createdAt,
85
- updatedAt: ticket.updatedAt
86
- };
87
- await this.graph.addNode("linear-ticket", data);
88
- for (const file of linkedFiles) {
89
- const resolvedPath = path.resolve(this.graph.projectRoot, file);
90
- const fileNode = await this.graph.getNode("file", resolvedPath);
91
- if (fileNode) {
92
- await this.graph.addEdge(`linear:${ticket.identifier}`, fileNode.id, "relatedTo");
93
- }
94
- }
95
- }
96
- extractIntentVibes(title, description, labels) {
97
- const vibes = /* @__PURE__ */ new Set();
98
- const text = (title + " " + (description || "") + " " + labels.join(" ")).toLowerCase();
99
- if (text.includes("performance") || text.includes("slow") || text.includes("optimize")) vibes.add("performance");
100
- if (text.includes("security") || text.includes("auth") || text.includes("vulnerability")) vibes.add("security");
101
- if (text.includes("refactor") || text.includes("cleanup") || text.includes("debt")) vibes.add("refactor");
102
- if (text.includes("feature") || text.includes("new")) vibes.add("feature");
103
- if (text.includes("bug") || text.includes("fix") || text.includes("broken")) vibes.add("bug");
104
- if (text.includes("breaking") || text.includes("major change")) vibes.add("breaking-change");
105
- return Array.from(vibes);
106
- }
107
- extractLinkedFiles(description) {
108
- if (!description) return [];
109
- const matches = description.match(/[\w./_-]+\.(ts|tsx|js|jsx|mjs|cjs|py|go|rs)/gi);
110
- if (!matches) return [];
111
- return Array.from(new Set(matches.map((m) => m.replace(/^\.\/+/, ""))));
112
- }
113
- mapPriority(priority) {
114
- switch (priority) {
115
- case 1:
116
- return "urgent";
117
- case 2:
118
- return "high";
119
- case 3:
120
- return "medium";
121
- case 4:
122
- return "low";
123
- default:
124
- return "none";
125
- }
126
- }
127
- };
128
-
129
- export {
130
- LinearIngester
131
- };
132
- //# sourceMappingURL=chunk-Q63FFI6D.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/ingest/linear-ingester.ts"],"sourcesContent":["import path from 'node:path';\nimport { loadConfig } from '../config/loader.js';\nimport { ContextGraph } from '../context/graph.js';\nimport type { LinearTicketNodeData } from '../context/nodes.js';\n\nexport interface LinearTicket {\n id: string;\n identifier: string;\n title: string;\n description: string;\n priority: number;\n url: string;\n status: { name: string };\n assignee?: { name: string };\n labels: { nodes: { name: string }[] };\n createdAt: string;\n updatedAt: string;\n}\n\nexport class LinearIngester {\n private readonly graph: ContextGraph;\n\n constructor(_projectPath: string, graph: ContextGraph) {\n this.graph = graph;\n }\n\n async syncTickets(): Promise<void> {\n const apiKey = await this.getApiKey();\n if (!apiKey) {\n console.warn('Linear API key not found. Run \"trie linear auth <key>\" to enable ticket sync.');\n return;\n }\n\n const tickets = await this.fetchActiveTickets(apiKey);\n for (const ticket of tickets) {\n await this.ingestTicket(ticket);\n }\n }\n\n private async getApiKey(): Promise<string | null> {\n const config = await loadConfig();\n return config.apiKeys?.linear ?? process.env.LINEAR_API_KEY ?? null;\n }\n\n private async fetchActiveTickets(apiKey: string): Promise<LinearTicket[]> {\n const query = `\n query {\n issues(filter: { state: { type: { in: [\"started\", \"unstarted\"] } } }) {\n nodes {\n id\n identifier\n title\n description\n priority\n url\n status {\n name\n }\n assignee {\n name\n }\n labels {\n nodes {\n name\n }\n }\n createdAt\n updatedAt\n }\n }\n }\n `;\n\n const response = await fetch('https://api.linear.app/graphql', {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': apiKey,\n },\n body: JSON.stringify({ query }),\n });\n\n if (!response.ok) {\n throw new Error(`Linear API error: ${response.statusText}`);\n }\n\n const data = (await response.json()) as any;\n return data.data.issues.nodes as LinearTicket[];\n }\n\n private async ingestTicket(ticket: LinearTicket): Promise<void> {\n const labels = ticket.labels.nodes.map(l => l.name);\n const intentVibe = this.extractIntentVibes(ticket.title, ticket.description, labels);\n \n // Attempt to find linked files in description or via labels (heuristic)\n const linkedFiles = this.extractLinkedFiles(ticket.description);\n\n const data: LinearTicketNodeData = {\n ticketId: ticket.identifier,\n title: ticket.title,\n description: ticket.description || '',\n priority: this.mapPriority(ticket.priority),\n labels,\n intentVibe,\n linkedFiles,\n status: ticket.status.name,\n assignee: ticket.assignee?.name || null,\n url: ticket.url || `https://linear.app/issue/${ticket.identifier}`,\n createdAt: ticket.createdAt,\n updatedAt: ticket.updatedAt,\n };\n\n await this.graph.addNode('linear-ticket', data);\n\n // Link to files if found (file node IDs are normalized absolute paths)\n for (const file of linkedFiles) {\n const resolvedPath = path.resolve(this.graph.projectRoot, file);\n const fileNode = await this.graph.getNode('file', resolvedPath);\n if (fileNode) {\n await this.graph.addEdge(`linear:${ticket.identifier}`, fileNode.id, 'relatedTo');\n }\n }\n }\n\n private extractIntentVibes(title: string, description: string, labels: string[]): string[] {\n const vibes = new Set<string>();\n const text = (title + ' ' + (description || '') + ' ' + labels.join(' ')).toLowerCase();\n\n if (text.includes('performance') || text.includes('slow') || text.includes('optimize')) vibes.add('performance');\n if (text.includes('security') || text.includes('auth') || text.includes('vulnerability')) vibes.add('security');\n if (text.includes('refactor') || text.includes('cleanup') || text.includes('debt')) vibes.add('refactor');\n if (text.includes('feature') || text.includes('new')) vibes.add('feature');\n if (text.includes('bug') || text.includes('fix') || text.includes('broken')) vibes.add('bug');\n if (text.includes('breaking') || text.includes('major change')) vibes.add('breaking-change');\n\n return Array.from(vibes);\n }\n\n private extractLinkedFiles(description: string): string[] {\n if (!description) return [];\n const matches = description.match(/[\\w./_-]+\\.(ts|tsx|js|jsx|mjs|cjs|py|go|rs)/gi);\n if (!matches) return [];\n return Array.from(new Set(matches.map(m => m.replace(/^\\.\\/+/, ''))));\n }\n\n private mapPriority(priority: number): string {\n switch (priority) {\n case 1: return 'urgent';\n case 2: return 'high';\n case 3: return 'medium';\n case 4: return 'low';\n default: return 'none';\n }\n }\n}\n"],"mappings":"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","names":[]}