opencode-telos 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (568) hide show
  1. package/README.md +927 -0
  2. package/dist/code-intelligence/analyzer.d.ts +9 -0
  3. package/dist/code-intelligence/analyzer.d.ts.map +1 -0
  4. package/dist/code-intelligence/analyzer.js +321 -0
  5. package/dist/code-intelligence/analyzer.js.map +1 -0
  6. package/dist/code-intelligence/ast/cache.d.ts +16 -0
  7. package/dist/code-intelligence/ast/cache.d.ts.map +1 -0
  8. package/dist/code-intelligence/ast/cache.js +44 -0
  9. package/dist/code-intelligence/ast/cache.js.map +1 -0
  10. package/dist/code-intelligence/ast/common.d.ts +8 -0
  11. package/dist/code-intelligence/ast/common.d.ts.map +1 -0
  12. package/dist/code-intelligence/ast/common.js +42 -0
  13. package/dist/code-intelligence/ast/common.js.map +1 -0
  14. package/dist/code-intelligence/ast/component.d.ts +10 -0
  15. package/dist/code-intelligence/ast/component.d.ts.map +1 -0
  16. package/dist/code-intelligence/ast/component.js +38 -0
  17. package/dist/code-intelligence/ast/component.js.map +1 -0
  18. package/dist/code-intelligence/ast/fallback.d.ts +9 -0
  19. package/dist/code-intelligence/ast/fallback.d.ts.map +1 -0
  20. package/dist/code-intelligence/ast/fallback.js +38 -0
  21. package/dist/code-intelligence/ast/fallback.js.map +1 -0
  22. package/dist/code-intelligence/ast/index.d.ts +5 -0
  23. package/dist/code-intelligence/ast/index.d.ts.map +1 -0
  24. package/dist/code-intelligence/ast/index.js +5 -0
  25. package/dist/code-intelligence/ast/index.js.map +1 -0
  26. package/dist/code-intelligence/ast/ir.d.ts +72 -0
  27. package/dist/code-intelligence/ast/ir.d.ts.map +1 -0
  28. package/dist/code-intelligence/ast/ir.js +2 -0
  29. package/dist/code-intelligence/ast/ir.js.map +1 -0
  30. package/dist/code-intelligence/ast/metrics.d.ts +25 -0
  31. package/dist/code-intelligence/ast/metrics.d.ts.map +1 -0
  32. package/dist/code-intelligence/ast/metrics.js +38 -0
  33. package/dist/code-intelligence/ast/metrics.js.map +1 -0
  34. package/dist/code-intelligence/ast/registry.d.ts +5 -0
  35. package/dist/code-intelligence/ast/registry.d.ts.map +1 -0
  36. package/dist/code-intelligence/ast/registry.js +22 -0
  37. package/dist/code-intelligence/ast/registry.js.map +1 -0
  38. package/dist/code-intelligence/ast/tree-sitter.d.ts +8 -0
  39. package/dist/code-intelligence/ast/tree-sitter.d.ts.map +1 -0
  40. package/dist/code-intelligence/ast/tree-sitter.js +247 -0
  41. package/dist/code-intelligence/ast/tree-sitter.js.map +1 -0
  42. package/dist/code-intelligence/ast/typescript.d.ts +8 -0
  43. package/dist/code-intelligence/ast/typescript.d.ts.map +1 -0
  44. package/dist/code-intelligence/ast/typescript.js +147 -0
  45. package/dist/code-intelligence/ast/typescript.js.map +1 -0
  46. package/dist/index.d.ts +10 -0
  47. package/dist/index.d.ts.map +1 -0
  48. package/dist/index.js +18 -0
  49. package/dist/index.js.map +1 -0
  50. package/dist/mcp/server.d.ts +27 -0
  51. package/dist/mcp/server.d.ts.map +1 -0
  52. package/dist/mcp/server.js +67 -0
  53. package/dist/mcp/server.js.map +1 -0
  54. package/dist/opencode/hooks.d.ts +9 -0
  55. package/dist/opencode/hooks.d.ts.map +1 -0
  56. package/dist/opencode/hooks.js +583 -0
  57. package/dist/opencode/hooks.js.map +1 -0
  58. package/dist/opencode/router/categories.d.ts +31 -0
  59. package/dist/opencode/router/categories.d.ts.map +1 -0
  60. package/dist/opencode/router/categories.js +165 -0
  61. package/dist/opencode/router/categories.js.map +1 -0
  62. package/dist/opencode/router/embeddings.d.ts +41 -0
  63. package/dist/opencode/router/embeddings.d.ts.map +1 -0
  64. package/dist/opencode/router/embeddings.js +136 -0
  65. package/dist/opencode/router/embeddings.js.map +1 -0
  66. package/dist/opencode/router/graph-state-snapshot.d.ts +35 -0
  67. package/dist/opencode/router/graph-state-snapshot.d.ts.map +1 -0
  68. package/dist/opencode/router/graph-state-snapshot.js +129 -0
  69. package/dist/opencode/router/graph-state-snapshot.js.map +1 -0
  70. package/dist/opencode/router/index.d.ts +21 -0
  71. package/dist/opencode/router/index.d.ts.map +1 -0
  72. package/dist/opencode/router/index.js +23 -0
  73. package/dist/opencode/router/index.js.map +1 -0
  74. package/dist/opencode/router/intent-classifier.d.ts +35 -0
  75. package/dist/opencode/router/intent-classifier.d.ts.map +1 -0
  76. package/dist/opencode/router/intent-classifier.js +108 -0
  77. package/dist/opencode/router/intent-classifier.js.map +1 -0
  78. package/dist/opencode/router/semantic-nudge.d.ts +42 -0
  79. package/dist/opencode/router/semantic-nudge.d.ts.map +1 -0
  80. package/dist/opencode/router/semantic-nudge.js +73 -0
  81. package/dist/opencode/router/semantic-nudge.js.map +1 -0
  82. package/dist/opencode/router/state-gate.d.ts +25 -0
  83. package/dist/opencode/router/state-gate.d.ts.map +1 -0
  84. package/dist/opencode/router/state-gate.js +178 -0
  85. package/dist/opencode/router/state-gate.js.map +1 -0
  86. package/dist/opencode/router/tool-embeddings.d.ts +36 -0
  87. package/dist/opencode/router/tool-embeddings.d.ts.map +1 -0
  88. package/dist/opencode/router/tool-embeddings.js +140 -0
  89. package/dist/opencode/router/tool-embeddings.js.map +1 -0
  90. package/dist/opencode/router/tool-registry.d.ts +45 -0
  91. package/dist/opencode/router/tool-registry.d.ts.map +1 -0
  92. package/dist/opencode/router/tool-registry.js +103 -0
  93. package/dist/opencode/router/tool-registry.js.map +1 -0
  94. package/dist/opencode/router/tool-taxonomy.d.ts +51 -0
  95. package/dist/opencode/router/tool-taxonomy.d.ts.map +1 -0
  96. package/dist/opencode/router/tool-taxonomy.js +250 -0
  97. package/dist/opencode/router/tool-taxonomy.js.map +1 -0
  98. package/dist/opencode/router/tools-composite.d.ts +21 -0
  99. package/dist/opencode/router/tools-composite.d.ts.map +1 -0
  100. package/dist/opencode/router/tools-composite.js +684 -0
  101. package/dist/opencode/router/tools-composite.js.map +1 -0
  102. package/dist/opencode/shell-hooks.d.ts +7 -0
  103. package/dist/opencode/shell-hooks.d.ts.map +1 -0
  104. package/dist/opencode/shell-hooks.js +96 -0
  105. package/dist/opencode/shell-hooks.js.map +1 -0
  106. package/dist/opencode/system-prompt.d.ts +10 -0
  107. package/dist/opencode/system-prompt.d.ts.map +1 -0
  108. package/dist/opencode/system-prompt.js +600 -0
  109. package/dist/opencode/system-prompt.js.map +1 -0
  110. package/dist/opencode/tools.d.ts +8 -0
  111. package/dist/opencode/tools.d.ts.map +1 -0
  112. package/dist/opencode/tools.js +3731 -0
  113. package/dist/opencode/tools.js.map +1 -0
  114. package/dist/opencode/workflows/chains.d.ts +52 -0
  115. package/dist/opencode/workflows/chains.d.ts.map +1 -0
  116. package/dist/opencode/workflows/chains.js +170 -0
  117. package/dist/opencode/workflows/chains.js.map +1 -0
  118. package/dist/opencode/workflows/executor.d.ts +52 -0
  119. package/dist/opencode/workflows/executor.d.ts.map +1 -0
  120. package/dist/opencode/workflows/executor.js +130 -0
  121. package/dist/opencode/workflows/executor.js.map +1 -0
  122. package/dist/opencode/workflows/index.d.ts +14 -0
  123. package/dist/opencode/workflows/index.d.ts.map +1 -0
  124. package/dist/opencode/workflows/index.js +15 -0
  125. package/dist/opencode/workflows/index.js.map +1 -0
  126. package/dist/opencode/workflows/tools-workflow.d.ts +24 -0
  127. package/dist/opencode/workflows/tools-workflow.d.ts.map +1 -0
  128. package/dist/opencode/workflows/tools-workflow.js +85 -0
  129. package/dist/opencode/workflows/tools-workflow.js.map +1 -0
  130. package/dist/opencode/workflows/types.d.ts +32 -0
  131. package/dist/opencode/workflows/types.d.ts.map +1 -0
  132. package/dist/opencode/workflows/types.js +13 -0
  133. package/dist/opencode/workflows/types.js.map +1 -0
  134. package/dist/sdd/analysis/compliance.d.ts +30 -0
  135. package/dist/sdd/analysis/compliance.d.ts.map +1 -0
  136. package/dist/sdd/analysis/compliance.js +251 -0
  137. package/dist/sdd/analysis/compliance.js.map +1 -0
  138. package/dist/sdd/analysis/scalability.d.ts +15 -0
  139. package/dist/sdd/analysis/scalability.d.ts.map +1 -0
  140. package/dist/sdd/analysis/scalability.js +72 -0
  141. package/dist/sdd/analysis/scalability.js.map +1 -0
  142. package/dist/sdd/analysis/security.d.ts +25 -0
  143. package/dist/sdd/analysis/security.d.ts.map +1 -0
  144. package/dist/sdd/analysis/security.js +94 -0
  145. package/dist/sdd/analysis/security.js.map +1 -0
  146. package/dist/sdd/brownfield/scanner.d.ts +31 -0
  147. package/dist/sdd/brownfield/scanner.d.ts.map +1 -0
  148. package/dist/sdd/brownfield/scanner.js +228 -0
  149. package/dist/sdd/brownfield/scanner.js.map +1 -0
  150. package/dist/sdd/cache/manager.d.ts +237 -0
  151. package/dist/sdd/cache/manager.d.ts.map +1 -0
  152. package/dist/sdd/cache/manager.js +770 -0
  153. package/dist/sdd/cache/manager.js.map +1 -0
  154. package/dist/sdd/cache/snapshot-store.d.ts +39 -0
  155. package/dist/sdd/cache/snapshot-store.d.ts.map +1 -0
  156. package/dist/sdd/cache/snapshot-store.js +156 -0
  157. package/dist/sdd/cache/snapshot-store.js.map +1 -0
  158. package/dist/sdd/changes/manager.d.ts +58 -0
  159. package/dist/sdd/changes/manager.d.ts.map +1 -0
  160. package/dist/sdd/changes/manager.js +235 -0
  161. package/dist/sdd/changes/manager.js.map +1 -0
  162. package/dist/sdd/cicd/generators.d.ts +16 -0
  163. package/dist/sdd/cicd/generators.d.ts.map +1 -0
  164. package/dist/sdd/cicd/generators.js +1042 -0
  165. package/dist/sdd/cicd/generators.js.map +1 -0
  166. package/dist/sdd/code-quality/complexity.d.ts +38 -0
  167. package/dist/sdd/code-quality/complexity.d.ts.map +1 -0
  168. package/dist/sdd/code-quality/complexity.js +161 -0
  169. package/dist/sdd/code-quality/complexity.js.map +1 -0
  170. package/dist/sdd/code-quality/conventions.d.ts +33 -0
  171. package/dist/sdd/code-quality/conventions.d.ts.map +1 -0
  172. package/dist/sdd/code-quality/conventions.js +193 -0
  173. package/dist/sdd/code-quality/conventions.js.map +1 -0
  174. package/dist/sdd/code-quality/dependencies.d.ts +27 -0
  175. package/dist/sdd/code-quality/dependencies.d.ts.map +1 -0
  176. package/dist/sdd/code-quality/dependencies.js +142 -0
  177. package/dist/sdd/code-quality/dependencies.js.map +1 -0
  178. package/dist/sdd/code-quality/import-analyzer.d.ts +49 -0
  179. package/dist/sdd/code-quality/import-analyzer.d.ts.map +1 -0
  180. package/dist/sdd/code-quality/import-analyzer.js +213 -0
  181. package/dist/sdd/code-quality/import-analyzer.js.map +1 -0
  182. package/dist/sdd/code-quality/metrics.d.ts +35 -0
  183. package/dist/sdd/code-quality/metrics.d.ts.map +1 -0
  184. package/dist/sdd/code-quality/metrics.js +172 -0
  185. package/dist/sdd/code-quality/metrics.js.map +1 -0
  186. package/dist/sdd/code-quality/smells.d.ts +38 -0
  187. package/dist/sdd/code-quality/smells.d.ts.map +1 -0
  188. package/dist/sdd/code-quality/smells.js +319 -0
  189. package/dist/sdd/code-quality/smells.js.map +1 -0
  190. package/dist/sdd/code-quality/symbol-parser.d.ts +28 -0
  191. package/dist/sdd/code-quality/symbol-parser.d.ts.map +1 -0
  192. package/dist/sdd/code-quality/symbol-parser.js +230 -0
  193. package/dist/sdd/code-quality/symbol-parser.js.map +1 -0
  194. package/dist/sdd/code-quality/usage-tracker.d.ts +59 -0
  195. package/dist/sdd/code-quality/usage-tracker.d.ts.map +1 -0
  196. package/dist/sdd/code-quality/usage-tracker.js +402 -0
  197. package/dist/sdd/code-quality/usage-tracker.js.map +1 -0
  198. package/dist/sdd/code-quality/utils.d.ts +6 -0
  199. package/dist/sdd/code-quality/utils.d.ts.map +1 -0
  200. package/dist/sdd/code-quality/utils.js +14 -0
  201. package/dist/sdd/code-quality/utils.js.map +1 -0
  202. package/dist/sdd/codegen/generator.d.ts +42 -0
  203. package/dist/sdd/codegen/generator.d.ts.map +1 -0
  204. package/dist/sdd/codegen/generator.js +1023 -0
  205. package/dist/sdd/codegen/generator.js.map +1 -0
  206. package/dist/sdd/constitution/validator.d.ts +37 -0
  207. package/dist/sdd/constitution/validator.d.ts.map +1 -0
  208. package/dist/sdd/constitution/validator.js +192 -0
  209. package/dist/sdd/constitution/validator.js.map +1 -0
  210. package/dist/sdd/cost/estimator.d.ts +31 -0
  211. package/dist/sdd/cost/estimator.d.ts.map +1 -0
  212. package/dist/sdd/cost/estimator.js +92 -0
  213. package/dist/sdd/cost/estimator.js.map +1 -0
  214. package/dist/sdd/coverage/tracker.d.ts +47 -0
  215. package/dist/sdd/coverage/tracker.d.ts.map +1 -0
  216. package/dist/sdd/coverage/tracker.js +251 -0
  217. package/dist/sdd/coverage/tracker.js.map +1 -0
  218. package/dist/sdd/disaster/recovery.d.ts +11 -0
  219. package/dist/sdd/disaster/recovery.d.ts.map +1 -0
  220. package/dist/sdd/disaster/recovery.js +55 -0
  221. package/dist/sdd/disaster/recovery.js.map +1 -0
  222. package/dist/sdd/discovery/adaptive.d.ts +14 -0
  223. package/dist/sdd/discovery/adaptive.d.ts.map +1 -0
  224. package/dist/sdd/discovery/adaptive.js +145 -0
  225. package/dist/sdd/discovery/adaptive.js.map +1 -0
  226. package/dist/sdd/discovery/briefing-analyzer.d.ts +66 -0
  227. package/dist/sdd/discovery/briefing-analyzer.d.ts.map +1 -0
  228. package/dist/sdd/discovery/briefing-analyzer.js +672 -0
  229. package/dist/sdd/discovery/briefing-analyzer.js.map +1 -0
  230. package/dist/sdd/discovery/briefing.d.ts +109 -0
  231. package/dist/sdd/discovery/briefing.d.ts.map +1 -0
  232. package/dist/sdd/discovery/briefing.js +617 -0
  233. package/dist/sdd/discovery/briefing.js.map +1 -0
  234. package/dist/sdd/discovery/graph-builder.d.ts +10 -0
  235. package/dist/sdd/discovery/graph-builder.d.ts.map +1 -0
  236. package/dist/sdd/discovery/graph-builder.js +510 -0
  237. package/dist/sdd/discovery/graph-builder.js.map +1 -0
  238. package/dist/sdd/documentation/generator.d.ts +7 -0
  239. package/dist/sdd/documentation/generator.d.ts.map +1 -0
  240. package/dist/sdd/documentation/generator.js +119 -0
  241. package/dist/sdd/documentation/generator.js.map +1 -0
  242. package/dist/sdd/domain/types.d.ts +460 -0
  243. package/dist/sdd/domain/types.d.ts.map +1 -0
  244. package/dist/sdd/domain/types.js +25 -0
  245. package/dist/sdd/domain/types.js.map +1 -0
  246. package/dist/sdd/drift/detector.d.ts +28 -0
  247. package/dist/sdd/drift/detector.d.ts.map +1 -0
  248. package/dist/sdd/drift/detector.js +379 -0
  249. package/dist/sdd/drift/detector.js.map +1 -0
  250. package/dist/sdd/drift/exclusion.d.ts +54 -0
  251. package/dist/sdd/drift/exclusion.d.ts.map +1 -0
  252. package/dist/sdd/drift/exclusion.js +179 -0
  253. package/dist/sdd/drift/exclusion.js.map +1 -0
  254. package/dist/sdd/drift/signals.d.ts +52 -0
  255. package/dist/sdd/drift/signals.d.ts.map +1 -0
  256. package/dist/sdd/drift/signals.js +470 -0
  257. package/dist/sdd/drift/signals.js.map +1 -0
  258. package/dist/sdd/enforcement/interceptor.d.ts +47 -0
  259. package/dist/sdd/enforcement/interceptor.d.ts.map +1 -0
  260. package/dist/sdd/enforcement/interceptor.js +365 -0
  261. package/dist/sdd/enforcement/interceptor.js.map +1 -0
  262. package/dist/sdd/enforcement/workflow-tracker.d.ts +66 -0
  263. package/dist/sdd/enforcement/workflow-tracker.d.ts.map +1 -0
  264. package/dist/sdd/enforcement/workflow-tracker.js +229 -0
  265. package/dist/sdd/enforcement/workflow-tracker.js.map +1 -0
  266. package/dist/sdd/graph/engine.d.ts +44 -0
  267. package/dist/sdd/graph/engine.d.ts.map +1 -0
  268. package/dist/sdd/graph/engine.js +203 -0
  269. package/dist/sdd/graph/engine.js.map +1 -0
  270. package/dist/sdd/graph/index.d.ts +160 -0
  271. package/dist/sdd/graph/index.d.ts.map +1 -0
  272. package/dist/sdd/graph/index.js +624 -0
  273. package/dist/sdd/graph/index.js.map +1 -0
  274. package/dist/sdd/graph/integrity-guard.d.ts +129 -0
  275. package/dist/sdd/graph/integrity-guard.d.ts.map +1 -0
  276. package/dist/sdd/graph/integrity-guard.js +263 -0
  277. package/dist/sdd/graph/integrity-guard.js.map +1 -0
  278. package/dist/sdd/graph/integrity.d.ts +79 -0
  279. package/dist/sdd/graph/integrity.d.ts.map +1 -0
  280. package/dist/sdd/graph/integrity.js +462 -0
  281. package/dist/sdd/graph/integrity.js.map +1 -0
  282. package/dist/sdd/graph/pruner.d.ts +27 -0
  283. package/dist/sdd/graph/pruner.d.ts.map +1 -0
  284. package/dist/sdd/graph/pruner.js +203 -0
  285. package/dist/sdd/graph/pruner.js.map +1 -0
  286. package/dist/sdd/graph/traverse.d.ts +43 -0
  287. package/dist/sdd/graph/traverse.d.ts.map +1 -0
  288. package/dist/sdd/graph/traverse.js +265 -0
  289. package/dist/sdd/graph/traverse.js.map +1 -0
  290. package/dist/sdd/incidents/manager.d.ts +10 -0
  291. package/dist/sdd/incidents/manager.d.ts.map +1 -0
  292. package/dist/sdd/incidents/manager.js +63 -0
  293. package/dist/sdd/incidents/manager.js.map +1 -0
  294. package/dist/sdd/knowledge/transfer.d.ts +24 -0
  295. package/dist/sdd/knowledge/transfer.d.ts.map +1 -0
  296. package/dist/sdd/knowledge/transfer.js +94 -0
  297. package/dist/sdd/knowledge/transfer.js.map +1 -0
  298. package/dist/sdd/migrations/fixes.d.ts +2 -0
  299. package/dist/sdd/migrations/fixes.d.ts.map +1 -0
  300. package/dist/sdd/migrations/fixes.js +159 -0
  301. package/dist/sdd/migrations/fixes.js.map +1 -0
  302. package/dist/sdd/migrations/index.d.ts +2 -0
  303. package/dist/sdd/migrations/index.d.ts.map +1 -0
  304. package/dist/sdd/migrations/index.js +5 -0
  305. package/dist/sdd/migrations/index.js.map +1 -0
  306. package/dist/sdd/migrations/migration-runner.d.ts +41 -0
  307. package/dist/sdd/migrations/migration-runner.d.ts.map +1 -0
  308. package/dist/sdd/migrations/migration-runner.js +91 -0
  309. package/dist/sdd/migrations/migration-runner.js.map +1 -0
  310. package/dist/sdd/monitoring/setup.d.ts +40 -0
  311. package/dist/sdd/monitoring/setup.d.ts.map +1 -0
  312. package/dist/sdd/monitoring/setup.js +177 -0
  313. package/dist/sdd/monitoring/setup.js.map +1 -0
  314. package/dist/sdd/monitoring/telemetry.d.ts +18 -0
  315. package/dist/sdd/monitoring/telemetry.d.ts.map +1 -0
  316. package/dist/sdd/monitoring/telemetry.js +37 -0
  317. package/dist/sdd/monitoring/telemetry.js.map +1 -0
  318. package/dist/sdd/patterns/anti-patterns.d.ts +21 -0
  319. package/dist/sdd/patterns/anti-patterns.d.ts.map +1 -0
  320. package/dist/sdd/patterns/anti-patterns.js +286 -0
  321. package/dist/sdd/patterns/anti-patterns.js.map +1 -0
  322. package/dist/sdd/patterns/ast-clones.d.ts +23 -0
  323. package/dist/sdd/patterns/ast-clones.d.ts.map +1 -0
  324. package/dist/sdd/patterns/ast-clones.js +171 -0
  325. package/dist/sdd/patterns/ast-clones.js.map +1 -0
  326. package/dist/sdd/patterns/config-drift.d.ts +16 -0
  327. package/dist/sdd/patterns/config-drift.d.ts.map +1 -0
  328. package/dist/sdd/patterns/config-drift.js +322 -0
  329. package/dist/sdd/patterns/config-drift.js.map +1 -0
  330. package/dist/sdd/patterns/contradictions.d.ts +38 -0
  331. package/dist/sdd/patterns/contradictions.d.ts.map +1 -0
  332. package/dist/sdd/patterns/contradictions.js +237 -0
  333. package/dist/sdd/patterns/contradictions.js.map +1 -0
  334. package/dist/sdd/patterns/learner.d.ts +49 -0
  335. package/dist/sdd/patterns/learner.d.ts.map +1 -0
  336. package/dist/sdd/patterns/learner.js +226 -0
  337. package/dist/sdd/patterns/learner.js.map +1 -0
  338. package/dist/sdd/permissions/access.d.ts +69 -0
  339. package/dist/sdd/permissions/access.d.ts.map +1 -0
  340. package/dist/sdd/permissions/access.js +333 -0
  341. package/dist/sdd/permissions/access.js.map +1 -0
  342. package/dist/sdd/persistence/repository.d.ts +60 -0
  343. package/dist/sdd/persistence/repository.d.ts.map +1 -0
  344. package/dist/sdd/persistence/repository.js +96 -0
  345. package/dist/sdd/persistence/repository.js.map +1 -0
  346. package/dist/sdd/persistence/sqlite.d.ts +122 -0
  347. package/dist/sdd/persistence/sqlite.d.ts.map +1 -0
  348. package/dist/sdd/persistence/sqlite.js +602 -0
  349. package/dist/sdd/persistence/sqlite.js.map +1 -0
  350. package/dist/sdd/persistence/yaml.d.ts +41 -0
  351. package/dist/sdd/persistence/yaml.d.ts.map +1 -0
  352. package/dist/sdd/persistence/yaml.js +382 -0
  353. package/dist/sdd/persistence/yaml.js.map +1 -0
  354. package/dist/sdd/promises/classifier.d.ts +48 -0
  355. package/dist/sdd/promises/classifier.d.ts.map +1 -0
  356. package/dist/sdd/promises/classifier.js +215 -0
  357. package/dist/sdd/promises/classifier.js.map +1 -0
  358. package/dist/sdd/promises/tracker.d.ts +20 -0
  359. package/dist/sdd/promises/tracker.d.ts.map +1 -0
  360. package/dist/sdd/promises/tracker.js +204 -0
  361. package/dist/sdd/promises/tracker.js.map +1 -0
  362. package/dist/sdd/quality/scorer.d.ts +44 -0
  363. package/dist/sdd/quality/scorer.d.ts.map +1 -0
  364. package/dist/sdd/quality/scorer.js +216 -0
  365. package/dist/sdd/quality/scorer.js.map +1 -0
  366. package/dist/sdd/rollback/manager.d.ts +45 -0
  367. package/dist/sdd/rollback/manager.d.ts.map +1 -0
  368. package/dist/sdd/rollback/manager.js +266 -0
  369. package/dist/sdd/rollback/manager.js.map +1 -0
  370. package/dist/sdd/session/handoff.d.ts +52 -0
  371. package/dist/sdd/session/handoff.d.ts.map +1 -0
  372. package/dist/sdd/session/handoff.js +264 -0
  373. package/dist/sdd/session/handoff.js.map +1 -0
  374. package/dist/sdd/sla/tracker.d.ts +11 -0
  375. package/dist/sdd/sla/tracker.d.ts.map +1 -0
  376. package/dist/sdd/sla/tracker.js +52 -0
  377. package/dist/sdd/sla/tracker.js.map +1 -0
  378. package/dist/sdd/sync/git-sync.d.ts +61 -0
  379. package/dist/sdd/sync/git-sync.d.ts.map +1 -0
  380. package/dist/sdd/sync/git-sync.js +297 -0
  381. package/dist/sdd/sync/git-sync.js.map +1 -0
  382. package/dist/sdd/toggle/state.d.ts +8 -0
  383. package/dist/sdd/toggle/state.d.ts.map +1 -0
  384. package/dist/sdd/toggle/state.js +32 -0
  385. package/dist/sdd/toggle/state.js.map +1 -0
  386. package/dist/sdd/transactions/manager.d.ts +12 -0
  387. package/dist/sdd/transactions/manager.d.ts.map +1 -0
  388. package/dist/sdd/transactions/manager.js +80 -0
  389. package/dist/sdd/transactions/manager.js.map +1 -0
  390. package/dist/sdd/validation/coverage-index.d.ts +117 -0
  391. package/dist/sdd/validation/coverage-index.d.ts.map +1 -0
  392. package/dist/sdd/validation/coverage-index.js +251 -0
  393. package/dist/sdd/validation/coverage-index.js.map +1 -0
  394. package/dist/sdd/validation/executable.d.ts +26 -0
  395. package/dist/sdd/validation/executable.d.ts.map +1 -0
  396. package/dist/sdd/validation/executable.js +122 -0
  397. package/dist/sdd/validation/executable.js.map +1 -0
  398. package/dist/sdd/validation/smart-validator.d.ts +53 -0
  399. package/dist/sdd/validation/smart-validator.d.ts.map +1 -0
  400. package/dist/sdd/validation/smart-validator.js +347 -0
  401. package/dist/sdd/validation/smart-validator.js.map +1 -0
  402. package/dist/sdd/validation/validator.d.ts +39 -0
  403. package/dist/sdd/validation/validator.d.ts.map +1 -0
  404. package/dist/sdd/validation/validator.js +512 -0
  405. package/dist/sdd/validation/validator.js.map +1 -0
  406. package/dist/sdd/workflow/exporter.d.ts +36 -0
  407. package/dist/sdd/workflow/exporter.d.ts.map +1 -0
  408. package/dist/sdd/workflow/exporter.js +112 -0
  409. package/dist/sdd/workflow/exporter.js.map +1 -0
  410. package/dist/sdd/workflows/ab-testing.d.ts +18 -0
  411. package/dist/sdd/workflows/ab-testing.d.ts.map +1 -0
  412. package/dist/sdd/workflows/ab-testing.js +67 -0
  413. package/dist/sdd/workflows/ab-testing.js.map +1 -0
  414. package/dist/sdd/workflows/bug-fix.d.ts +13 -0
  415. package/dist/sdd/workflows/bug-fix.d.ts.map +1 -0
  416. package/dist/sdd/workflows/bug-fix.js +65 -0
  417. package/dist/sdd/workflows/bug-fix.js.map +1 -0
  418. package/dist/sdd/workflows/data-migration.d.ts +14 -0
  419. package/dist/sdd/workflows/data-migration.d.ts.map +1 -0
  420. package/dist/sdd/workflows/data-migration.js +68 -0
  421. package/dist/sdd/workflows/data-migration.js.map +1 -0
  422. package/dist/sdd/workflows/deprecation.d.ts +15 -0
  423. package/dist/sdd/workflows/deprecation.d.ts.map +1 -0
  424. package/dist/sdd/workflows/deprecation.js +68 -0
  425. package/dist/sdd/workflows/deprecation.js.map +1 -0
  426. package/dist/sdd/workflows/feature-flags.d.ts +14 -0
  427. package/dist/sdd/workflows/feature-flags.d.ts.map +1 -0
  428. package/dist/sdd/workflows/feature-flags.js +73 -0
  429. package/dist/sdd/workflows/feature-flags.js.map +1 -0
  430. package/dist/sdd/workflows/hotfix.d.ts +13 -0
  431. package/dist/sdd/workflows/hotfix.d.ts.map +1 -0
  432. package/dist/sdd/workflows/hotfix.js +67 -0
  433. package/dist/sdd/workflows/hotfix.js.map +1 -0
  434. package/dist/sdd/workflows/multi-tenancy.d.ts +13 -0
  435. package/dist/sdd/workflows/multi-tenancy.d.ts.map +1 -0
  436. package/dist/sdd/workflows/multi-tenancy.js +68 -0
  437. package/dist/sdd/workflows/multi-tenancy.js.map +1 -0
  438. package/dist/sdd/workflows/onboarding.d.ts +7 -0
  439. package/dist/sdd/workflows/onboarding.d.ts.map +1 -0
  440. package/dist/sdd/workflows/onboarding.js +43 -0
  441. package/dist/sdd/workflows/onboarding.js.map +1 -0
  442. package/dist/sdd/workflows/refactoring.d.ts +14 -0
  443. package/dist/sdd/workflows/refactoring.d.ts.map +1 -0
  444. package/dist/sdd/workflows/refactoring.js +73 -0
  445. package/dist/sdd/workflows/refactoring.js.map +1 -0
  446. package/dist/server/events.d.ts +64 -0
  447. package/dist/server/events.d.ts.map +1 -0
  448. package/dist/server/events.js +149 -0
  449. package/dist/server/events.js.map +1 -0
  450. package/dist/server/server.d.ts +33 -0
  451. package/dist/server/server.d.ts.map +1 -0
  452. package/dist/server/server.js +1019 -0
  453. package/dist/server/server.js.map +1 -0
  454. package/marketplace.json +39 -0
  455. package/package.json +65 -0
  456. package/src/code-intelligence/analyzer.ts +350 -0
  457. package/src/code-intelligence/ast/cache.ts +61 -0
  458. package/src/code-intelligence/ast/common.ts +62 -0
  459. package/src/code-intelligence/ast/component.ts +39 -0
  460. package/src/code-intelligence/ast/fallback.ts +44 -0
  461. package/src/code-intelligence/ast/index.ts +4 -0
  462. package/src/code-intelligence/ast/ir.ts +91 -0
  463. package/src/code-intelligence/ast/metrics.ts +65 -0
  464. package/src/code-intelligence/ast/registry.ts +28 -0
  465. package/src/code-intelligence/ast/tree-sitter.ts +226 -0
  466. package/src/code-intelligence/ast/typescript.ts +140 -0
  467. package/src/index.ts +22 -0
  468. package/src/mcp/server.ts +77 -0
  469. package/src/opencode/hooks.ts +728 -0
  470. package/src/opencode/router/categories.ts +192 -0
  471. package/src/opencode/router/embeddings.ts +149 -0
  472. package/src/opencode/router/graph-state-snapshot.ts +163 -0
  473. package/src/opencode/router/index.ts +44 -0
  474. package/src/opencode/router/intent-classifier.ts +140 -0
  475. package/src/opencode/router/semantic-nudge.ts +89 -0
  476. package/src/opencode/router/state-gate.ts +192 -0
  477. package/src/opencode/router/tool-embeddings.ts +162 -0
  478. package/src/opencode/router/tool-registry.ts +135 -0
  479. package/src/opencode/router/tool-taxonomy.ts +284 -0
  480. package/src/opencode/router/tools-composite.ts +685 -0
  481. package/src/opencode/shell-hooks.ts +115 -0
  482. package/src/opencode/system-prompt.ts +617 -0
  483. package/src/opencode/tools.ts +4102 -0
  484. package/src/opencode/workflows/chains.ts +205 -0
  485. package/src/opencode/workflows/executor.ts +172 -0
  486. package/src/opencode/workflows/index.ts +21 -0
  487. package/src/opencode/workflows/tools-workflow.ts +91 -0
  488. package/src/opencode/workflows/types.ts +42 -0
  489. package/src/sdd/analysis/compliance.ts +279 -0
  490. package/src/sdd/analysis/scalability.ts +97 -0
  491. package/src/sdd/analysis/security.ts +135 -0
  492. package/src/sdd/brownfield/scanner.ts +276 -0
  493. package/src/sdd/cache/manager.ts +899 -0
  494. package/src/sdd/cache/snapshot-store.ts +185 -0
  495. package/src/sdd/changes/manager.ts +326 -0
  496. package/src/sdd/cicd/generators.ts +1095 -0
  497. package/src/sdd/code-quality/complexity.ts +235 -0
  498. package/src/sdd/code-quality/conventions.ts +220 -0
  499. package/src/sdd/code-quality/dependencies.ts +203 -0
  500. package/src/sdd/code-quality/import-analyzer.ts +294 -0
  501. package/src/sdd/code-quality/metrics.ts +232 -0
  502. package/src/sdd/code-quality/smells.ts +415 -0
  503. package/src/sdd/code-quality/symbol-parser.ts +335 -0
  504. package/src/sdd/code-quality/usage-tracker.ts +527 -0
  505. package/src/sdd/code-quality/utils.ts +13 -0
  506. package/src/sdd/codegen/generator.ts +1181 -0
  507. package/src/sdd/constitution/validator.ts +253 -0
  508. package/src/sdd/cost/estimator.ts +147 -0
  509. package/src/sdd/coverage/tracker.ts +342 -0
  510. package/src/sdd/disaster/recovery.ts +79 -0
  511. package/src/sdd/discovery/adaptive.ts +167 -0
  512. package/src/sdd/discovery/briefing-analyzer.ts +802 -0
  513. package/src/sdd/discovery/briefing.ts +770 -0
  514. package/src/sdd/discovery/graph-builder.ts +598 -0
  515. package/src/sdd/documentation/generator.ts +158 -0
  516. package/src/sdd/domain/types.ts +658 -0
  517. package/src/sdd/drift/detector.ts +465 -0
  518. package/src/sdd/drift/exclusion.ts +223 -0
  519. package/src/sdd/drift/signals.ts +577 -0
  520. package/src/sdd/enforcement/interceptor.ts +444 -0
  521. package/src/sdd/enforcement/workflow-tracker.ts +263 -0
  522. package/src/sdd/graph/engine.ts +277 -0
  523. package/src/sdd/graph/index.ts +700 -0
  524. package/src/sdd/graph/integrity-guard.ts +348 -0
  525. package/src/sdd/graph/integrity.ts +628 -0
  526. package/src/sdd/graph/pruner.ts +221 -0
  527. package/src/sdd/graph/traverse.ts +331 -0
  528. package/src/sdd/incidents/manager.ts +87 -0
  529. package/src/sdd/knowledge/transfer.ts +140 -0
  530. package/src/sdd/migrations/fixes.ts +154 -0
  531. package/src/sdd/migrations/index.ts +14 -0
  532. package/src/sdd/migrations/migration-runner.ts +118 -0
  533. package/src/sdd/monitoring/setup.ts +237 -0
  534. package/src/sdd/monitoring/telemetry.ts +44 -0
  535. package/src/sdd/patterns/anti-patterns.ts +333 -0
  536. package/src/sdd/patterns/ast-clones.ts +214 -0
  537. package/src/sdd/patterns/config-drift.ts +346 -0
  538. package/src/sdd/patterns/contradictions.ts +323 -0
  539. package/src/sdd/patterns/learner.ts +266 -0
  540. package/src/sdd/permissions/access.ts +478 -0
  541. package/src/sdd/persistence/repository.ts +166 -0
  542. package/src/sdd/persistence/sqlite.ts +703 -0
  543. package/src/sdd/persistence/yaml.ts +409 -0
  544. package/src/sdd/promises/classifier.ts +253 -0
  545. package/src/sdd/promises/tracker.ts +258 -0
  546. package/src/sdd/quality/scorer.ts +263 -0
  547. package/src/sdd/rollback/manager.ts +361 -0
  548. package/src/sdd/session/handoff.ts +354 -0
  549. package/src/sdd/sla/tracker.ts +68 -0
  550. package/src/sdd/sync/git-sync.ts +401 -0
  551. package/src/sdd/toggle/state.ts +38 -0
  552. package/src/sdd/transactions/manager.ts +93 -0
  553. package/src/sdd/validation/coverage-index.ts +339 -0
  554. package/src/sdd/validation/executable.ts +127 -0
  555. package/src/sdd/validation/smart-validator.ts +470 -0
  556. package/src/sdd/validation/validator.ts +641 -0
  557. package/src/sdd/workflow/exporter.ts +169 -0
  558. package/src/sdd/workflows/ab-testing.ts +90 -0
  559. package/src/sdd/workflows/bug-fix.ts +81 -0
  560. package/src/sdd/workflows/data-migration.ts +86 -0
  561. package/src/sdd/workflows/deprecation.ts +87 -0
  562. package/src/sdd/workflows/feature-flags.ts +91 -0
  563. package/src/sdd/workflows/hotfix.ts +83 -0
  564. package/src/sdd/workflows/multi-tenancy.ts +84 -0
  565. package/src/sdd/workflows/onboarding.ts +82 -0
  566. package/src/sdd/workflows/refactoring.ts +90 -0
  567. package/src/server/events.ts +184 -0
  568. package/src/server/server.ts +1088 -0
@@ -0,0 +1,899 @@
1
+ import { existsSync, readFileSync, writeFileSync, mkdirSync, unlinkSync } from "fs"
2
+ import { join, dirname } from "path"
3
+ import { createHash } from "crypto"
4
+ import { PerTypeGraphCache, IncrementalGraphHash } from "../graph/index.js"
5
+ import type { AnyNode, NodeType, Relationship } from "../domain/types.js"
6
+ import { getGraphSnapshotStore } from "./snapshot-store.js"
7
+ import type { KnowledgeGraph } from "../domain/types.js"
8
+
9
+ // ── Cache Entry Types ────────────────────────────────────────────────
10
+
11
+ interface CacheEntry<T> {
12
+ value: T
13
+ timestamp: number
14
+ version: number
15
+ accessCount: number
16
+ lastAccess: number
17
+ }
18
+
19
+ interface ToolCacheEntry {
20
+ response: string
21
+ timestamp: number
22
+ lastAccess: number
23
+ toolName: string
24
+ argsHash: string
25
+ graphVersion: string
26
+ }
27
+
28
+ interface AnalysisCacheEntry {
29
+ result: unknown
30
+ timestamp: number
31
+ lastAccess: number
32
+ graphVersion: number
33
+ nodeCount: number
34
+ type: string
35
+ }
36
+
37
+ interface PersistentCacheData {
38
+ version: number
39
+ toolResponses: Record<string, ToolCacheEntry>
40
+ analysisResults: Record<string, AnalysisCacheEntry>
41
+ graphSnapshot: {
42
+ nodeCount: number
43
+ relationshipCount: number
44
+ version: string
45
+ lastModified: number
46
+ } | null
47
+ graphHash: string
48
+ }
49
+
50
+ // ── Granular Invalidation Tracking ───────────────────────────────────
51
+
52
+ interface InvalidationTracker {
53
+ lastFullInvalidation: number
54
+ dirtyTypes: Set<string>
55
+ dirtyNodeIds: Set<string>
56
+ dirtyRelTypes: Set<string>
57
+ version: number
58
+ }
59
+
60
+ // ── Main Cache Manager ───────────────────────────────────────────────
61
+
62
+ const TOOL_RESPONSE_TTL = 5 * 60 * 1000 // 5 minutes
63
+ const ANALYSIS_TTL = 3 * 60 * 1000 // 3 minutes
64
+ const PERSISTENT_CACHE_FILE = ".sdd/cache.json"
65
+ const INVALIDATION_FILE = ".sdd/cache-invalidated.json"
66
+
67
+ export class CacheManager {
68
+ private projectDir: string
69
+
70
+ // In-memory caches
71
+ private toolResponses: Map<string, ToolCacheEntry> = new Map()
72
+ private analysisResults: Map<string, AnalysisCacheEntry> = new Map()
73
+
74
+ // Granular invalidation tracker
75
+ private invalidation: InvalidationTracker = {
76
+ lastFullInvalidation: 0,
77
+ dirtyTypes: new Set(),
78
+ dirtyNodeIds: new Set(),
79
+ dirtyRelTypes: new Set(),
80
+ version: 0,
81
+ }
82
+
83
+ // Version counter for lazy revalidation (F)
84
+ private invalidationVersionOnWrite: number = 0
85
+
86
+ // Per-type graph cache
87
+ private graphCache = new PerTypeGraphCache()
88
+
89
+ // Incremental graph hash
90
+ private graphHash = new IncrementalGraphHash()
91
+
92
+ // Statistics
93
+ private stats = {
94
+ toolHits: 0,
95
+ toolMisses: 0,
96
+ analysisHits: 0,
97
+ analysisMisses: 0,
98
+ invalidations: 0,
99
+ }
100
+
101
+ constructor(projectDir: string) {
102
+ this.projectDir = projectDir
103
+ this.loadInvalidationTracker()
104
+ this.invalidationVersionOnWrite = this.invalidation.version
105
+ }
106
+
107
+ // ── Tool Response Cache ───────────────────────────────────────────
108
+
109
+ /**
110
+ * Get cached tool response if valid.
111
+ * Checks: TTL (using lastAccess for freshness), graph version, invalidation status.
112
+ * F: Uses lazy revalidation — checks version before clearing.
113
+ */
114
+ getToolResponse(toolName: string, args: Record<string, unknown>, graphVersion: string): string | null {
115
+ const key = this.toolCacheKey(toolName, args)
116
+ const entry = this.toolResponses.get(key)
117
+
118
+ if (!entry) {
119
+ this.stats.toolMisses++
120
+ return null
121
+ }
122
+
123
+ // F: Lazy revalidation — if invalidation version changed, check if this entry is affected
124
+ if (this.invalidation.version !== this.invalidationVersionOnWrite) {
125
+ if (this.isToolAffectedByInvalidation(toolName, entry.argsHash)) {
126
+ this.toolResponses.delete(key)
127
+ this.clearDirtyTypesForTool(toolName)
128
+ this.stats.toolMisses++
129
+ return null
130
+ }
131
+ }
132
+
133
+ // B: Check TTL using lastAccess (not timestamp) — entries accessed recently survive restore
134
+ const effectiveAge = Date.now() - (entry.lastAccess || entry.timestamp)
135
+ if (effectiveAge > TOOL_RESPONSE_TTL) {
136
+ this.toolResponses.delete(key)
137
+ this.stats.toolMisses++
138
+ return null
139
+ }
140
+
141
+ // Check graph version consistency
142
+ if (entry.graphVersion !== graphVersion) {
143
+ this.toolResponses.delete(key)
144
+ this.stats.toolMisses++
145
+ return null
146
+ }
147
+
148
+ // Update access stats — refresh lastAccess on hit
149
+ entry.lastAccess = Date.now()
150
+ this.stats.toolHits++
151
+ return entry.response
152
+ }
153
+
154
+ /**
155
+ * Cache a tool response.
156
+ */
157
+ setToolResponse(toolName: string, args: Record<string, unknown>, response: string, graphVersion: string): void {
158
+ const key = this.toolCacheKey(toolName, args)
159
+ const now = Date.now()
160
+ this.toolResponses.set(key, {
161
+ response,
162
+ timestamp: now,
163
+ lastAccess: now,
164
+ toolName,
165
+ argsHash: this.toolCacheKey(toolName, args).split(':')[1] || '',
166
+ graphVersion,
167
+ })
168
+
169
+ // Evict old entries if cache is too large
170
+ if (this.toolResponses.size > 200) {
171
+ this.evictOldestToolEntries(50)
172
+ }
173
+ }
174
+
175
+ // ── Analysis Result Cache ─────────────────────────────────────────
176
+
177
+ /**
178
+ * Get cached analysis result (validate, drift, quality, etc.).
179
+ * Revalidates based on graph state.
180
+ * F: Uses lazy revalidation.
181
+ */
182
+ getAnalysisResult(type: string, graphVersion: number, nodeCount: number): unknown | null {
183
+ const key = `analysis:${type}`
184
+ const entry = this.analysisResults.get(key)
185
+
186
+ if (!entry) {
187
+ this.stats.analysisMisses++
188
+ return null
189
+ }
190
+
191
+ // F: Lazy revalidation
192
+ if (this.invalidation.version !== this.invalidationVersionOnWrite) {
193
+ if (this.isAnalysisAffectedByInvalidation(type)) {
194
+ this.analysisResults.delete(key)
195
+ this.clearDirtyTypesForAnalysis(type)
196
+ this.stats.analysisMisses++
197
+ return null
198
+ }
199
+ }
200
+
201
+ // B: Check TTL using lastAccess
202
+ const effectiveAge = Date.now() - (entry.lastAccess || entry.timestamp)
203
+ if (effectiveAge > ANALYSIS_TTL) {
204
+ this.analysisResults.delete(key)
205
+ this.stats.analysisMisses++
206
+ return null
207
+ }
208
+
209
+ // Revalidation: if graph changed since analysis, invalidate
210
+ if (entry.graphVersion !== graphVersion || entry.nodeCount !== nodeCount) {
211
+ this.analysisResults.delete(key)
212
+ this.stats.analysisMisses++
213
+ return null
214
+ }
215
+
216
+ // Update lastAccess
217
+ entry.lastAccess = Date.now()
218
+ this.stats.analysisHits++
219
+ return entry.result
220
+ }
221
+
222
+ /**
223
+ * Cache an analysis result.
224
+ */
225
+ setAnalysisResult(type: string, result: unknown, graphVersion: number, nodeCount: number): void {
226
+ const key = `analysis:${type}`
227
+ const now = Date.now()
228
+ this.analysisResults.set(key, {
229
+ result,
230
+ timestamp: now,
231
+ lastAccess: now,
232
+ graphVersion,
233
+ nodeCount,
234
+ type,
235
+ })
236
+ }
237
+
238
+ // ── Granular Invalidation ─────────────────────────────────────────
239
+
240
+ /**
241
+ * Mark specific node IDs as dirty.
242
+ */
243
+ invalidateNodeIds(ids: string[]): void {
244
+ for (const id of ids) {
245
+ this.invalidation.dirtyNodeIds.add(id)
246
+ }
247
+ this.invalidation.version++
248
+ this.saveInvalidationTracker()
249
+ }
250
+
251
+ /**
252
+ * Mark specific relationship types as dirty.
253
+ */
254
+ invalidateRelTypes(types: string[]): void {
255
+ for (const type of types) {
256
+ this.invalidation.dirtyRelTypes.add(type)
257
+ }
258
+ this.invalidation.version++
259
+ this.saveInvalidationTracker()
260
+ }
261
+
262
+ /**
263
+ * Full invalidation: clear everything.
264
+ * Now reserved only for explicit reset (H) or major structural changes.
265
+ */
266
+ invalidateAll(): void {
267
+ this.toolResponses.clear()
268
+ this.analysisResults.clear()
269
+ this.graphCache.invalidateAll()
270
+ this.invalidation.lastFullInvalidation = Date.now()
271
+ this.invalidation.dirtyTypes.clear()
272
+ this.invalidation.dirtyNodeIds.clear()
273
+ this.invalidation.dirtyRelTypes.clear()
274
+ this.invalidation.version++
275
+ this.stats.invalidations++
276
+ this.saveInvalidationTracker()
277
+ }
278
+
279
+ /**
280
+ * Partial invalidation: clear only affected caches.
281
+ * A: Much faster than full invalidation for targeted changes.
282
+ * Called by repositories after saveGraph() with the dirty types.
283
+ */
284
+ invalidatePartial(changedNodeTypes: string[], changedRelTypes: string[] = []): void {
285
+ // Invalidate tool responses that depend on changed types
286
+ for (const [key, entry] of this.toolResponses) {
287
+ if (this.doesToolDependOnTypes(key, changedNodeTypes, changedRelTypes)) {
288
+ this.toolResponses.delete(key)
289
+ }
290
+ }
291
+
292
+ // Invalidate analysis results that depend on changed types
293
+ for (const [key, entry] of this.analysisResults) {
294
+ if (this.doesAnalysisDependOnTypes(key, changedNodeTypes, changedRelTypes)) {
295
+ this.analysisResults.delete(key)
296
+ }
297
+ }
298
+
299
+ // Track dirty types
300
+ this.invalidateNodeTypes(changedNodeTypes)
301
+ this.invalidateRelTypes(changedRelTypes)
302
+ }
303
+
304
+ /**
305
+ * Invalidate specific node IDs (e.g., when a node is updated).
306
+ */
307
+ invalidateNodeId(nodeId: string, nodeType: string): void {
308
+ // Invalidate tool responses that mention this node
309
+ for (const [key, entry] of this.toolResponses) {
310
+ if (entry.response.includes(nodeId)) {
311
+ this.toolResponses.delete(key)
312
+ }
313
+ }
314
+
315
+ // Invalidate analysis results for this node type
316
+ const analysisTypes = this.getAnalysisTypesForNodeType(nodeType)
317
+ for (const type of analysisTypes) {
318
+ this.analysisResults.delete(`analysis:${type}`)
319
+ }
320
+
321
+ this.invalidation.dirtyNodeIds.add(nodeId)
322
+ this.invalidation.dirtyTypes.add(nodeType)
323
+ this.invalidation.version++
324
+ this.saveInvalidationTracker()
325
+ }
326
+
327
+ // ── Persistent Cache (Cross-Session) ──────────────────────────────
328
+
329
+ /**
330
+ * Load persistent cache from disk.
331
+ */
332
+ loadPersistentCache(): PersistentCacheData | null {
333
+ const path = join(this.projectDir, PERSISTENT_CACHE_FILE)
334
+ if (!existsSync(path)) return null
335
+ try {
336
+ const data = JSON.parse(readFileSync(path, "utf-8"))
337
+ // Check if persistent cache is too old (>1 hour)
338
+ if (Date.now() - (data.timestamp || 0) > 60 * 60 * 1000) {
339
+ return null
340
+ }
341
+ return data
342
+ } catch {
343
+ return null
344
+ }
345
+ }
346
+
347
+ /**
348
+ * Save persistent cache to disk.
349
+ */
350
+ savePersistentCache(data: PersistentCacheData): void {
351
+ const path = join(this.projectDir, PERSISTENT_CACHE_FILE)
352
+ const dir = dirname(path)
353
+ if (!existsSync(dir)) mkdirSync(dir, { recursive: true })
354
+ writeFileSync(path, JSON.stringify({ ...data, timestamp: Date.now() }, null, 2))
355
+ }
356
+
357
+ /**
358
+ * Restore tool responses from persistent cache.
359
+ * B: Uses lastAccess for TTL check so recently-accessed entries survive restore.
360
+ */
361
+ restoreFromPersistentCache(): number {
362
+ const persistent = this.loadPersistentCache()
363
+ if (!persistent) return 0
364
+
365
+ let restored = 0
366
+ for (const [key, entry] of Object.entries(persistent.toolResponses)) {
367
+ // B: Use lastAccess for freshness check — entries accessed recently are valid
368
+ const effectiveAge = Date.now() - (entry.lastAccess || entry.timestamp)
369
+ if (effectiveAge < TOOL_RESPONSE_TTL) {
370
+ this.toolResponses.set(key, {
371
+ response: entry.response,
372
+ timestamp: entry.timestamp,
373
+ lastAccess: entry.lastAccess || entry.timestamp,
374
+ toolName: entry.toolName,
375
+ argsHash: entry.argsHash,
376
+ graphVersion: entry.graphVersion,
377
+ })
378
+ restored++
379
+ }
380
+ }
381
+
382
+ for (const [key, entry] of Object.entries(persistent.analysisResults)) {
383
+ const effectiveAge = Date.now() - (entry.lastAccess || entry.timestamp)
384
+ if (effectiveAge < ANALYSIS_TTL) {
385
+ this.analysisResults.set(key, {
386
+ result: entry.result,
387
+ timestamp: entry.timestamp,
388
+ lastAccess: entry.lastAccess || entry.timestamp,
389
+ graphVersion: entry.graphVersion,
390
+ nodeCount: entry.nodeCount,
391
+ type: key.replace("analysis:", ""),
392
+ })
393
+ restored++
394
+ }
395
+ }
396
+
397
+ return restored
398
+ }
399
+
400
+ /**
401
+ * Persist current cache to disk.
402
+ */
403
+ persistToDisk(): void {
404
+ const toolResponses: Record<string, ToolCacheEntry> = {}
405
+ for (const [key, entry] of this.toolResponses) {
406
+ toolResponses[key] = {
407
+ response: entry.response,
408
+ timestamp: entry.timestamp,
409
+ lastAccess: entry.lastAccess,
410
+ toolName: entry.toolName,
411
+ argsHash: entry.argsHash,
412
+ graphVersion: entry.graphVersion,
413
+ }
414
+ }
415
+
416
+ const analysisResults: Record<string, AnalysisCacheEntry> = {}
417
+ for (const [key, entry] of this.analysisResults) {
418
+ analysisResults[key] = {
419
+ result: entry.result,
420
+ timestamp: entry.timestamp,
421
+ lastAccess: entry.lastAccess,
422
+ graphVersion: entry.graphVersion,
423
+ nodeCount: entry.nodeCount,
424
+ type: key.replace("analysis:", ""),
425
+ }
426
+ }
427
+
428
+ this.savePersistentCache({
429
+ version: 2,
430
+ toolResponses,
431
+ analysisResults,
432
+ graphSnapshot: null,
433
+ graphHash: this.graphHash.getHash(),
434
+ })
435
+ }
436
+
437
+ /**
438
+ * Save graph snapshot to disk (G).
439
+ * Called after graph mutations and on dispose.
440
+ */
441
+ saveGraphSnapshot(graph: KnowledgeGraph): void {
442
+ try {
443
+ const store = getGraphSnapshotStore(this.projectDir)
444
+ store.save(graph, this.graphHash.getHash())
445
+ } catch {}
446
+ }
447
+
448
+ /**
449
+ * Load graph snapshot from disk (G).
450
+ * Returns null if no valid snapshot exists.
451
+ */
452
+ loadGraphSnapshot(): { graph: KnowledgeGraph; graphHash: string } | null {
453
+ try {
454
+ const store = getGraphSnapshotStore(this.projectDir)
455
+ return store.load()
456
+ } catch {
457
+ return null
458
+ }
459
+ }
460
+
461
+ /**
462
+ * Invalidate graph snapshot on disk.
463
+ */
464
+ invalidateGraphSnapshot(): void {
465
+ try {
466
+ const store = getGraphSnapshotStore(this.projectDir)
467
+ store.invalidate()
468
+ } catch {}
469
+ }
470
+
471
+ // ── Cross-Process Shared Cache ────────────────────────────────────
472
+
473
+ /**
474
+ * D: Check if another process has modified the graph since our last read.
475
+ * Uses file-based locking + PID liveness check for robust cross-process coordination.
476
+ */
477
+ checkCrossProcessInvalidation(graphPath: string): boolean {
478
+ const lockPath = join(this.projectDir, ".sdd", ".cache-lock")
479
+ try {
480
+ if (existsSync(lockPath)) {
481
+ const lockData = JSON.parse(readFileSync(lockPath, "utf-8"))
482
+
483
+ // D: If lock is older than 30 seconds, check if the process is still alive
484
+ if (Date.now() - lockData.timestamp > 30000) {
485
+ // D: If the locking process is dead, treat as invalidation needed
486
+ if (lockData.pid && lockData.pid !== process.pid) {
487
+ try {
488
+ process.kill(lockData.pid, 0) // Signal 0 = check if alive
489
+ // Process is alive but lock is stale — another process is slow, ignore
490
+ return false
491
+ } catch {
492
+ // Process is dead — force invalidation
493
+ this.invalidation.lastFullInvalidation = Date.now()
494
+ this.invalidation.version++
495
+ return true
496
+ }
497
+ }
498
+ return false // Stale lock from same process or no PID
499
+ }
500
+
501
+ // If another process wrote after our last read
502
+ if (lockData.timestamp > (this.invalidation.lastFullInvalidation || 0)) {
503
+ return true
504
+ }
505
+ }
506
+ } catch {}
507
+ return false
508
+ }
509
+
510
+ /**
511
+ * Acquire cross-process lock before writing.
512
+ */
513
+ acquireWriteLock(): boolean {
514
+ const lockPath = join(this.projectDir, ".sdd", ".cache-lock")
515
+ const dir = dirname(lockPath)
516
+ if (!existsSync(dir)) mkdirSync(dir, { recursive: true })
517
+
518
+ try {
519
+ // Try to create lock file
520
+ if (existsSync(lockPath)) {
521
+ const existing = JSON.parse(readFileSync(lockPath, "utf-8"))
522
+ // If lock is stale (>30s), override it
523
+ if (Date.now() - existing.timestamp > 30000) {
524
+ // Stale lock, ok to override
525
+ } else if (existing.pid !== process.pid) {
526
+ return false // Another process holds the lock
527
+ }
528
+ }
529
+
530
+ writeFileSync(lockPath, JSON.stringify({
531
+ pid: process.pid,
532
+ timestamp: Date.now(),
533
+ }))
534
+ return true
535
+ } catch {
536
+ return false
537
+ }
538
+ }
539
+
540
+ /**
541
+ * Release cross-process lock.
542
+ */
543
+ releaseWriteLock(): void {
544
+ const lockPath = join(this.projectDir, ".sdd", ".cache-lock")
545
+ try {
546
+ if (existsSync(lockPath)) {
547
+ const lockData = JSON.parse(readFileSync(lockPath, "utf-8"))
548
+ if (lockData.pid === process.pid) {
549
+ unlinkSync(lockPath)
550
+ }
551
+ }
552
+ } catch {}
553
+ }
554
+
555
+ // ── Full Reset (H) ───────────────────────────────────────────────
556
+
557
+ /**
558
+ * H: Full cache reset — clears everything in memory and on disk.
559
+ * Used by /sdd cache reset command.
560
+ */
561
+ fullReset(): { cleared: { memory: boolean; disk: boolean; snapshot: boolean; lock: boolean } } {
562
+ // Clear in-memory
563
+ this.toolResponses.clear()
564
+ this.analysisResults.clear()
565
+ this.graphCache.invalidateAll()
566
+
567
+ // Reset invalidation tracker
568
+ this.invalidation.lastFullInvalidation = Date.now()
569
+ this.invalidation.dirtyTypes.clear()
570
+ this.invalidation.dirtyNodeIds.clear()
571
+ this.invalidation.dirtyRelTypes.clear()
572
+ this.invalidation.version++
573
+ this.stats.invalidations++
574
+ this.saveInvalidationTracker()
575
+
576
+ // Clear persistent cache on disk
577
+ let disk = false
578
+ try {
579
+ const cachePath = join(this.projectDir, PERSISTENT_CACHE_FILE)
580
+ if (existsSync(cachePath)) {
581
+ unlinkSync(cachePath)
582
+ disk = true
583
+ }
584
+ } catch {}
585
+
586
+ // Clear graph snapshot (G)
587
+ let snapshot = false
588
+ try {
589
+ const store = getGraphSnapshotStore(this.projectDir)
590
+ if (store.isValid()) {
591
+ store.invalidate()
592
+ snapshot = true
593
+ }
594
+ } catch {}
595
+
596
+ // Release lock
597
+ let lock = false
598
+ try {
599
+ const lockPath = join(this.projectDir, ".sdd", ".cache-lock")
600
+ if (existsSync(lockPath)) {
601
+ this.releaseWriteLock()
602
+ lock = true
603
+ }
604
+ } catch {}
605
+
606
+ return { cleared: { memory: true, disk, snapshot, lock } }
607
+ }
608
+
609
+ /**
610
+ * Get current invalidation version (for external checks).
611
+ */
612
+ getInvalidationVersion(): number {
613
+ return this.invalidation.version
614
+ }
615
+
616
+ /**
617
+ * Sync invalidation version after external write.
618
+ */
619
+ syncInvalidationVersion(): void {
620
+ this.invalidationVersionOnWrite = this.invalidation.version
621
+ }
622
+
623
+ // ── Per-Type Graph Cache ──────────────────────────────────────────
624
+
625
+ /**
626
+ * Get cached nodes for a specific type.
627
+ * Only returns if the cache version matches.
628
+ */
629
+ getCachedNodesByType(type: NodeType, graphVersion: number): AnyNode[] | null {
630
+ return this.graphCache.getNodesByType(type, graphVersion)
631
+ }
632
+
633
+ /**
634
+ * Cache nodes for a specific type.
635
+ */
636
+ setCachedNodesByType(type: NodeType, nodes: AnyNode[], graphVersion: number): void {
637
+ this.graphCache.setType(type, nodes, graphVersion)
638
+ }
639
+
640
+ /**
641
+ * Invalidate cache for a specific node type only.
642
+ * Other types remain cached.
643
+ */
644
+ invalidateNodeType(type: NodeType): void {
645
+ this.graphCache.invalidateType(type)
646
+ this.invalidateNodeTypes([type])
647
+ }
648
+
649
+ /**
650
+ * Invalidate cache for multiple node types.
651
+ */
652
+ invalidateNodeTypes(types: string[]): void {
653
+ for (const type of types) {
654
+ this.invalidation.dirtyTypes.add(type)
655
+ this.graphCache.invalidateType(type as NodeType)
656
+ }
657
+ this.invalidation.version++
658
+ this.saveInvalidationTracker()
659
+ }
660
+
661
+ /**
662
+ * Get cached relationships.
663
+ */
664
+ getCachedRelationships(graphVersion: number): Relationship[] | null {
665
+ return this.graphCache.getRelationships(graphVersion)
666
+ }
667
+
668
+ /**
669
+ * Cache relationships.
670
+ */
671
+ setCachedRelationships(rels: Relationship[], graphVersion: number): void {
672
+ this.graphCache.setRelationships(rels, graphVersion)
673
+ }
674
+
675
+ // ── Incremental Graph Hash ────────────────────────────────────────
676
+
677
+ /**
678
+ * Initialize the incremental hash from graph state.
679
+ */
680
+ initGraphHash(nodeCount: number, relCount: number): void {
681
+ this.graphHash.initialize(nodeCount, relCount)
682
+ }
683
+
684
+ /**
685
+ * Record a node mutation for incremental hash.
686
+ */
687
+ recordNodeMutation(delta: number = 0): void {
688
+ this.graphHash.recordNodeCountChange(delta)
689
+ }
690
+
691
+ /**
692
+ * Record a relationship mutation for incremental hash.
693
+ */
694
+ recordRelMutation(delta: number = 0): void {
695
+ this.graphHash.recordRelCountChange(delta)
696
+ }
697
+
698
+ /**
699
+ * Get current graph hash.
700
+ */
701
+ getGraphHash(): string {
702
+ return this.graphHash.getHash()
703
+ }
704
+
705
+ /**
706
+ * Check if graph hash matches.
707
+ */
708
+ isGraphHashValid(expectedHash: string): boolean {
709
+ return this.graphHash.matches(expectedHash)
710
+ }
711
+
712
+ /**
713
+ * Get current node count from incremental hash.
714
+ */
715
+ getNodeCountFromHash(): number {
716
+ return this.graphHash.getNodeCount()
717
+ }
718
+
719
+ // ── Statistics ────────────────────────────────────────────────────
720
+
721
+ getStats() {
722
+ return {
723
+ ...this.stats,
724
+ toolCacheSize: this.toolResponses.size,
725
+ analysisCacheSize: this.analysisResults.size,
726
+ invalidationVersion: this.invalidation.version,
727
+ hitRate: this.stats.toolHits + this.stats.toolMisses > 0
728
+ ? (this.stats.toolHits / (this.stats.toolHits + this.stats.toolMisses) * 100).toFixed(1) + "%"
729
+ : "0%",
730
+ analysisHitRate: this.stats.analysisHits + this.stats.analysisMisses > 0
731
+ ? (this.stats.analysisHits / (this.stats.analysisHits + this.stats.analysisMisses) * 100).toFixed(1) + "%"
732
+ : "0%",
733
+ }
734
+ }
735
+
736
+ // ── Private Helpers ───────────────────────────────────────────────
737
+
738
+ private toolCacheKey(toolName: string, args: Record<string, unknown>): string {
739
+ const argsStr = JSON.stringify(args, Object.keys(args).sort())
740
+ const argsHash = createHash("md5").update(argsStr).digest("hex").slice(0, 8)
741
+ return `${toolName}:${argsHash}`
742
+ }
743
+
744
+ private isToolAffectedByInvalidation(toolName: string, argsHash: string): boolean {
745
+ // Check if the tool's dependent types have been invalidated
746
+ const dependentTypes = this.getToolDependentTypes(toolName)
747
+ for (const type of dependentTypes) {
748
+ if (this.invalidation.dirtyTypes.has(type)) return true
749
+ }
750
+ return false
751
+ }
752
+
753
+ private isAnalysisAffectedByInvalidation(analysisType: string): boolean {
754
+ const dependentTypes = this.getAnalysisDependentTypes(analysisType)
755
+ for (const type of dependentTypes) {
756
+ if (this.invalidation.dirtyTypes.has(type)) return true
757
+ }
758
+ return false
759
+ }
760
+
761
+ /**
762
+ * Clear dirty types that are relevant to a specific analysis type.
763
+ * Called after the analysis cache entry has been invalidated due to dirty types.
764
+ * This allows the cache to work again after the analysis is recomputed.
765
+ */
766
+ private clearDirtyTypesForAnalysis(analysisType: string): void {
767
+ const dependentTypes = this.getAnalysisDependentTypes(analysisType)
768
+ for (const type of dependentTypes) {
769
+ this.invalidation.dirtyTypes.delete(type)
770
+ }
771
+ this.invalidation.version++
772
+ }
773
+
774
+ /**
775
+ * Clear dirty types that are relevant to a specific tool.
776
+ */
777
+ private clearDirtyTypesForTool(toolName: string): void {
778
+ const dependentTypes = this.getToolDependentTypes(toolName)
779
+ for (const type of dependentTypes) {
780
+ this.invalidation.dirtyTypes.delete(type)
781
+ }
782
+ this.invalidation.version++
783
+ }
784
+
785
+ private getToolDependentTypes(toolName: string): string[] {
786
+ const map: Record<string, string[]> = {
787
+ "sdd.query_graph": [], // depends on any type
788
+ "sdd.list_nodes": [], // depends on queried type
789
+ "sdd.get_nodes_by_status": [],
790
+ "sdd.count_nodes": [],
791
+ "sdd.inspect": [],
792
+ "sdd.validate": ["feature", "requirement", "entity", "api", "endpoint", "table", "task", "test", "change", "constitution", "business_rule"],
793
+ "sdd.detect_drift": ["file", "task", "change", "entity", "api"],
794
+ "sdd.quality": ["feature", "requirement", "entity", "api", "endpoint", "task", "test", "change", "constitution", "business_rule"],
795
+ "sdd.anti_patterns": ["feature", "requirement", "entity", "change", "task", "test"],
796
+ "sdd.contradictions": ["requirement", "business_rule", "constraint"],
797
+ "sdd.coverage": ["requirement", "test"],
798
+ "sdd.analyze_impact": [],
799
+ "sdd.get_context": [],
800
+ "sdd.pending_changes": ["change"],
801
+ "sdd.session_handoff": ["change", "decision"],
802
+ }
803
+ return map[toolName] || []
804
+ }
805
+
806
+ private getAnalysisDependentTypes(analysisType: string): string[] {
807
+ const map: Record<string, string[]> = {
808
+ "validate": ["feature", "requirement", "entity", "api", "endpoint", "table", "task", "test", "change", "constitution", "business_rule"],
809
+ "drift": ["file", "task", "change", "entity", "api"],
810
+ "quality": ["feature", "requirement", "entity", "api", "endpoint", "task", "test", "change", "constitution", "business_rule"],
811
+ "anti_patterns": ["feature", "requirement", "entity", "change", "task", "test"],
812
+ "contradictions": ["requirement", "business_rule", "constraint"],
813
+ "coverage": ["requirement", "test"],
814
+ "constitution": ["constitution", "feature", "requirement", "entity", "business_rule"],
815
+ "promises": ["requirement", "business_rule"],
816
+ "integrity": [],
817
+ }
818
+ return map[analysisType] || []
819
+ }
820
+
821
+ private getAnalysisTypesForNodeType(nodeType: string): string[] {
822
+ const map: Record<string, string[]> = {
823
+ "feature": ["validate", "quality", "anti_patterns"],
824
+ "requirement": ["validate", "quality", "coverage", "promises", "constitution"],
825
+ "entity": ["validate", "quality", "drift"],
826
+ "endpoint": ["validate", "quality"],
827
+ "api": ["validate", "quality"],
828
+ "business_rule": ["validate", "quality", "contradictions", "promises"],
829
+ "change": ["validate", "quality", "anti_patterns"],
830
+ "task": ["validate", "quality", "drift"],
831
+ "test": ["validate", "quality", "coverage"],
832
+ "file": ["drift"],
833
+ "constitution": ["validate", "constitution"],
834
+ "constraint": ["contradictions"],
835
+ }
836
+ return map[nodeType] || []
837
+ }
838
+
839
+ private doesToolDependOnTypes(key: string, types: string[], relTypes: string[]): boolean {
840
+ const toolName = key.split(":")[0]
841
+ const depTypes = this.getToolDependentTypes(toolName)
842
+ if (depTypes.length === 0) return true // Unknown dependency, invalidate to be safe
843
+ return types.some(t => depTypes.includes(t))
844
+ }
845
+
846
+ private doesAnalysisDependOnTypes(key: string, types: string[], relTypes: string[]): boolean {
847
+ const analysisType = key.replace("analysis:", "")
848
+ const depTypes = this.getAnalysisDependentTypes(analysisType)
849
+ if (depTypes.length === 0) return true
850
+ return types.some(t => depTypes.includes(t))
851
+ }
852
+
853
+ private evictOldestToolEntries(count: number): void {
854
+ const entries = [...this.toolResponses.entries()]
855
+ .sort((a, b) => (a[1].lastAccess || a[1].timestamp) - (b[1].lastAccess || b[1].timestamp))
856
+ for (let i = 0; i < count && i < entries.length; i++) {
857
+ this.toolResponses.delete(entries[i][0])
858
+ }
859
+ }
860
+
861
+ private loadInvalidationTracker(): void {
862
+ const path = join(this.projectDir, INVALIDATION_FILE)
863
+ if (!existsSync(path)) return
864
+ try {
865
+ const data = JSON.parse(readFileSync(path, "utf-8"))
866
+ this.invalidation.lastFullInvalidation = data.lastFullInvalidation || 0
867
+ this.invalidation.version = data.version || 0
868
+ this.invalidation.dirtyTypes = new Set(data.dirtyTypes || [])
869
+ this.invalidation.dirtyNodeIds = new Set(data.dirtyNodeIds || [])
870
+ this.invalidation.dirtyRelTypes = new Set(data.dirtyRelTypes || [])
871
+ } catch {}
872
+ }
873
+
874
+ private saveInvalidationTracker(): void {
875
+ const path = join(this.projectDir, INVALIDATION_FILE)
876
+ const dir = dirname(path)
877
+ if (!existsSync(dir)) mkdirSync(dir, { recursive: true })
878
+ writeFileSync(path, JSON.stringify({
879
+ lastFullInvalidation: this.invalidation.lastFullInvalidation,
880
+ version: this.invalidation.version,
881
+ dirtyTypes: [...this.invalidation.dirtyTypes],
882
+ dirtyNodeIds: [...this.invalidation.dirtyNodeIds],
883
+ dirtyRelTypes: [...this.invalidation.dirtyRelTypes],
884
+ }))
885
+ }
886
+ }
887
+
888
+ // ── Singleton per project ────────────────────────────────────────────
889
+
890
+ const instances = new Map<string, CacheManager>()
891
+
892
+ export function getCacheManager(projectDir: string): CacheManager {
893
+ let instance = instances.get(projectDir)
894
+ if (!instance) {
895
+ instance = new CacheManager(projectDir)
896
+ instances.set(projectDir, instance)
897
+ }
898
+ return instance
899
+ }