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,465 @@
1
+ import type { KnowledgeGraph, FileNode, ChangeNode } from "../domain/types.js"
2
+ import { getNode, getNodesByType } from "../graph/engine.js"
3
+ import { existsSync, readFileSync } from "fs"
4
+ import { join } from "path"
5
+ import { detectAllSignals, formatDriftSignals } from "./signals.js"
6
+ import type { DriftSignals, DuplicateDetectionOptions } from "./signals.js"
7
+ import { getExclusionSets, isNodeExcludedOrDeprecated, isFileWhitelistedPattern } from "./exclusion.js"
8
+ import { hasPersistenceMapping } from "../validation/validator.js"
9
+ import { validateGraphIntegrity } from "../graph/integrity-guard.js"
10
+ import { parseWithCache, loadAstCache, saveAstCache } from "../../code-intelligence/ast/cache.js"
11
+
12
+ export interface DriftDetectionResult {
13
+ has_drift: boolean
14
+ missing_files: MissingFileDrift[]
15
+ untracked_files: UntrackedFileDrift[]
16
+ spec_code_mismatches: SpecCodeMismatch[]
17
+ signals?: DriftSignals
18
+ }
19
+
20
+ export interface MissingFileDrift {
21
+ node_id: string
22
+ file_path: string
23
+ expected_by: string
24
+ }
25
+
26
+ export interface UntrackedFileDrift {
27
+ file_path: string
28
+ full_path?: string
29
+ severity?: "info" | "warning" | "error"
30
+ suggestion: string
31
+ }
32
+
33
+ export interface SpecCodeMismatch {
34
+ node_id: string
35
+ description: string
36
+ severity: "high" | "medium" | "low"
37
+ }
38
+
39
+
40
+
41
+ export function detectDrift(
42
+ graph: KnowledgeGraph,
43
+ projectDir: string,
44
+ options?: DuplicateDetectionOptions,
45
+ ): DriftDetectionResult {
46
+ const result: DriftDetectionResult = {
47
+ has_drift: false,
48
+ missing_files: [],
49
+ untracked_files: [],
50
+ spec_code_mismatches: [],
51
+ }
52
+
53
+ // Pre-compute sets of nodes that should be excluded from drift detection.
54
+ // Nodes removed via ChangeNode or deprecated should NOT trigger drift.
55
+ const { removed: removedNodeIds, deprecated: deprecatedNodeIds } = getExclusionSets(graph)
56
+
57
+ detectMissingFiles(graph, projectDir, result, removedNodeIds, deprecatedNodeIds)
58
+ detectUntrackedFiles(graph, projectDir, result, removedNodeIds, deprecatedNodeIds)
59
+ detectSpecCodeMismatches(graph, projectDir, result, removedNodeIds, deprecatedNodeIds)
60
+ detectAstFileMismatches(graph, projectDir, result, removedNodeIds, deprecatedNodeIds)
61
+
62
+ // Filter out whitelisted files from drift results
63
+ result.missing_files = result.missing_files.filter(
64
+ (f) => !isFileWhitelistedPattern(projectDir, f.file_path),
65
+ )
66
+ result.untracked_files = result.untracked_files.filter(
67
+ (f) => !isFileWhitelistedPattern(projectDir, f.file_path),
68
+ )
69
+ result.spec_code_mismatches = result.spec_code_mismatches.filter(
70
+ (m) => !isFileWhitelistedPattern(projectDir, m.node_id),
71
+ )
72
+
73
+ // Anti-bypass: check for out-of-band graph modifications
74
+ try {
75
+ const tamperResult = validateGraphIntegrity(projectDir, graph)
76
+ if (tamperResult.tampered) {
77
+ result.spec_code_mismatches.push({
78
+ node_id: "__tamper__",
79
+ description: tamperResult.reason || "Graph modified outside SDD workflow",
80
+ severity: "high",
81
+ })
82
+ }
83
+ } catch {}
84
+
85
+ // Re-evaluate has_drift after filtering
86
+ result.has_drift =
87
+ result.missing_files.length > 0 ||
88
+ result.untracked_files.length > 0 ||
89
+ result.spec_code_mismatches.length > 0 ||
90
+ (result.signals?.total_signals ?? 0) > 0
91
+
92
+ const signals = detectAllSignals(graph, projectDir, options)
93
+
94
+ // Filter out whitelisted architecture violations from signals
95
+ signals.architecture_violations = signals.architecture_violations.filter(
96
+ (v) => !isFileWhitelistedPattern(projectDir, v.file),
97
+ )
98
+ // Recalculate total_signals after filtering
99
+ signals.total_signals =
100
+ signals.mutant_duplicates.length +
101
+ signals.architecture_violations.length +
102
+ signals.pattern_fragmentation.length +
103
+ signals.temporal_volatility.length
104
+
105
+ result.signals = signals
106
+
107
+ result.has_drift =
108
+ result.missing_files.length > 0 ||
109
+ result.untracked_files.length > 0 ||
110
+ result.spec_code_mismatches.length > 0 ||
111
+ signals.total_signals > 0
112
+
113
+ return result
114
+ }
115
+
116
+ /** Compare persisted AST evidence with the current source without executing it. */
117
+ function detectAstFileMismatches(
118
+ graph: KnowledgeGraph,
119
+ projectDir: string,
120
+ result: DriftDetectionResult,
121
+ removedNodeIds: Set<string>,
122
+ deprecatedNodeIds: Set<string>,
123
+ ): void {
124
+ const cache = loadAstCache(projectDir)
125
+ const fileNodes = getNodesByType<FileNode>(graph, "file")
126
+ for (const fileNode of fileNodes) {
127
+ if (isNodeExcludedOrDeprecated(fileNode.id, fileNode.status, removedNodeIds, deprecatedNodeIds)) continue
128
+ const filePath = fileNode.metadata.path
129
+ if (!filePath || !existsSync(join(projectDir, filePath))) continue
130
+ try {
131
+ const content = readFileSync(join(projectDir, filePath), "utf-8")
132
+ const parsed = parseWithCache(projectDir, join(projectDir, filePath), content, cache)
133
+ const metadata = fileNode.metadata as Record<string, unknown>
134
+ if (typeof metadata.content_hash === "string" && metadata.content_hash !== parsed.content_hash) {
135
+ result.spec_code_mismatches.push({ node_id: fileNode.id, description: `AST content fingerprint changed for ${filePath}`, severity: "high" })
136
+ }
137
+ const expected = Array.isArray(metadata.expected_symbols) ? metadata.expected_symbols : Array.isArray(metadata.symbols) ? metadata.symbols : []
138
+ if (expected.length > 0) {
139
+ const actual = new Set(parsed.symbols.map((symbol) => symbol.qualified_name))
140
+ for (const value of expected) {
141
+ if (typeof value === "string" && !actual.has(value)) result.spec_code_mismatches.push({ node_id: fileNode.id, description: `Expected AST symbol ${value} is missing from ${filePath}`, severity: "high" })
142
+ }
143
+ }
144
+ if (parsed.analysis_source === "fallback") result.spec_code_mismatches.push({ node_id: fileNode.id, description: `File ${filePath} was analyzed with a low-confidence fallback parser`, severity: "low" })
145
+ } catch (error) {
146
+ result.spec_code_mismatches.push({ node_id: fileNode.id, description: `Could not parse ${filePath}: ${error instanceof Error ? error.message : String(error)}`, severity: "medium" })
147
+ }
148
+ }
149
+ saveAstCache(projectDir, cache)
150
+ }
151
+
152
+ function detectMissingFiles(
153
+ graph: KnowledgeGraph,
154
+ projectDir: string,
155
+ result: DriftDetectionResult,
156
+ removedNodeIds: Set<string>,
157
+ deprecatedNodeIds: Set<string>,
158
+ ): void {
159
+ const fileNodes = getNodesByType<FileNode>(graph, "file")
160
+ for (const fileNode of fileNodes) {
161
+ // Skip files that were removed by a completed change or deprecated
162
+ if (isNodeExcludedOrDeprecated(fileNode.id, fileNode.status, removedNodeIds, deprecatedNodeIds)) continue
163
+
164
+ const filePath = fileNode.metadata.path
165
+ if (!filePath) continue
166
+ const fullPath = join(projectDir, filePath)
167
+ if (existsSync(fullPath)) continue
168
+
169
+ // ── Fuzzy path matching: try to find the file in nearby locations ──
170
+ const fuzzyMatch = findFuzzyPathMatch(filePath, projectDir)
171
+ if (fuzzyMatch) {
172
+ // File exists but in a different path — suggest auto-heal
173
+ result.missing_files.push({
174
+ node_id: fileNode.id,
175
+ file_path: filePath,
176
+ expected_by: `File node ${fileNode.id} (exists at: ${fuzzyMatch} — consider updating path)`,
177
+ })
178
+ } else {
179
+ result.missing_files.push({
180
+ node_id: fileNode.id,
181
+ file_path: filePath,
182
+ expected_by: `File node ${fileNode.id}`,
183
+ })
184
+ }
185
+ }
186
+
187
+ // Also check task-referenced files
188
+ const taskNodes = graph.nodes.filter((n) => n.type === "task")
189
+ for (const task of taskNodes) {
190
+ // Skip tasks removed by a completed change or deprecated
191
+ if (isNodeExcludedOrDeprecated(task.id, task.status, removedNodeIds, deprecatedNodeIds)) continue
192
+
193
+ const meta = task.metadata as Record<string, unknown>
194
+ if (Array.isArray(meta.files)) {
195
+ for (const file of meta.files) {
196
+ if (typeof file === "string") {
197
+ const fullPath = join(projectDir, file)
198
+ if (!existsSync(fullPath)) {
199
+ result.missing_files.push({
200
+ node_id: task.id,
201
+ file_path: file,
202
+ expected_by: `Task ${task.id}`,
203
+ })
204
+ }
205
+ }
206
+ }
207
+ }
208
+ }
209
+ }
210
+
211
+ function detectUntrackedFiles(
212
+ graph: KnowledgeGraph,
213
+ projectDir: string,
214
+ result: DriftDetectionResult,
215
+ removedNodeIds: Set<string>,
216
+ deprecatedNodeIds: Set<string>,
217
+ ): void {
218
+ const trackedPaths = new Set<string>()
219
+ const fileNodes = getNodesByType<FileNode>(graph, "file")
220
+ for (const fn of fileNodes) {
221
+ // Skip files removed by change or deprecated — their paths should NOT
222
+ // be added to trackedPaths, so if the file still exists on disk it
223
+ // will correctly appear as untracked (or be handled by change nodes).
224
+ if (isNodeExcludedOrDeprecated(fn.id, fn.status, removedNodeIds, deprecatedNodeIds)) continue
225
+ if (fn.metadata.path) trackedPaths.add(fn.metadata.path)
226
+ }
227
+
228
+ const taskNodes = graph.nodes.filter((n) => n.type === "task")
229
+ for (const task of taskNodes) {
230
+ if (isNodeExcludedOrDeprecated(task.id, task.status, removedNodeIds, deprecatedNodeIds)) continue
231
+ const meta = task.metadata as Record<string, unknown>
232
+ if (Array.isArray(meta.files)) {
233
+ for (const f of meta.files) {
234
+ if (typeof f === "string") trackedPaths.add(f)
235
+ }
236
+ }
237
+ }
238
+
239
+ // Only track files from DRAFT/PROPOSED/APPROVED changes (pending changes)
240
+ // COMPLETED changes already had their affected files processed
241
+ const changeNodes = graph.nodes.filter((n) => n.type === "change") as ChangeNode[]
242
+ for (const change of changeNodes) {
243
+ if (["DRAFT", "PROPOSED", "APPROVED"].includes(change.status)) {
244
+ if (change.metadata.affected_files) {
245
+ for (const f of change.metadata.affected_files) {
246
+ trackedPaths.add(f)
247
+ }
248
+ }
249
+ }
250
+ }
251
+
252
+ const sourceExtensions = [".ts", ".tsx", ".js", ".jsx", ".py", ".go", ".rs", ".java", ".rb", ".vue", ".svelte"]
253
+ const excludePatterns = ["node_modules", ".sdd", "dist", "build", ".git", ".opencode", "__pycache__", "vendor"]
254
+
255
+ function scanDirectory(dir: string, relativePath: string = ""): void {
256
+ let entries: string[]
257
+ try {
258
+ entries = require("fs").readdirSync(dir)
259
+ } catch {
260
+ return
261
+ }
262
+
263
+ for (const entry of entries) {
264
+ if (excludePatterns.some(p => entry === p || entry.startsWith(p))) continue
265
+
266
+ const fullPath = `${dir}/${entry}`
267
+ const relPath = relativePath ? `${relativePath}/${entry}` : entry
268
+
269
+ let stat
270
+ try {
271
+ stat = require("fs").statSync(fullPath)
272
+ } catch {
273
+ continue
274
+ }
275
+
276
+ if (stat.isDirectory()) {
277
+ scanDirectory(fullPath, relPath)
278
+ } else if (sourceExtensions.some(ext => entry.endsWith(ext))) {
279
+ if (!trackedPaths.has(relPath) && !trackedPaths.has(fullPath)) {
280
+ result.untracked_files = result.untracked_files || []
281
+ // Infer what this file might implement based on name/path
282
+ const inferredEntity = inferEntityFromFile(relPath, graph)
283
+ const suggestion = inferredEntity
284
+ ? `File likely implements "${inferredEntity}" — use sdd.add_node to create FileNode, then sdd.add_relationship to link it`
285
+ : "Arquivo não rastreado pelo SDD. Considere adicionar um FileNode."
286
+ result.untracked_files.push({
287
+ file_path: relPath,
288
+ full_path: fullPath,
289
+ severity: "info",
290
+ suggestion,
291
+ })
292
+ if (!result.has_drift) {
293
+ result.has_drift = true
294
+ }
295
+ }
296
+ }
297
+ }
298
+ }
299
+
300
+ scanDirectory(projectDir)
301
+ }
302
+
303
+ /**
304
+ * Try to infer which entity/feature a file implements based on its name.
305
+ */
306
+ function inferEntityFromFile(filePath: string, graph: KnowledgeGraph): string | null {
307
+ const fileName = filePath.split("/").pop()?.toLowerCase().replace(/\.[^.]+$/, "") || ""
308
+ if (fileName.length < 3) return null
309
+
310
+ // Check against entity names
311
+ const entities = graph.nodes.filter(n => n.type === "entity")
312
+ for (const entity of entities) {
313
+ const entityName = entity.name.toLowerCase()
314
+ if (fileName.includes(entityName) || entityName.includes(fileName)) {
315
+ return entity.name
316
+ }
317
+ }
318
+
319
+ // Check against feature names
320
+ const features = graph.nodes.filter(n => n.type === "feature")
321
+ for (const feature of features) {
322
+ const featureName = feature.name.toLowerCase()
323
+ if (fileName.includes(featureName) || featureName.includes(fileName)) {
324
+ return feature.name
325
+ }
326
+ }
327
+
328
+ return null
329
+ }
330
+
331
+ function detectSpecCodeMismatches(
332
+ graph: KnowledgeGraph,
333
+ _projectDir: string,
334
+ result: DriftDetectionResult,
335
+ removedNodeIds: Set<string>,
336
+ deprecatedNodeIds: Set<string>,
337
+ ): void {
338
+ // Check entity nodes for corresponding persistence (multiple strategies)
339
+ // Uses the same logic as hasPersistenceMapping in validation/validator.ts
340
+ const entities = graph.nodes.filter((n) => n.type === "entity")
341
+ for (const entity of entities) {
342
+ // Skip entities removed by change or deprecated
343
+ if (isNodeExcludedOrDeprecated(entity.id, entity.status, removedNodeIds, deprecatedNodeIds)) continue
344
+
345
+ if (!hasPersistenceMapping(entity, graph) && entities.length > 0) {
346
+ result.spec_code_mismatches.push({
347
+ node_id: entity.id,
348
+ description: `Entity ${entity.id} has no persistence mapping`,
349
+ severity: "medium",
350
+ })
351
+ }
352
+ }
353
+
354
+ // Check API nodes for endpoint completeness
355
+ const apis = graph.nodes.filter((n) => n.type === "api")
356
+ for (const api of apis) {
357
+ // Skip APIs removed by change or deprecated
358
+ if (isNodeExcludedOrDeprecated(api.id, api.status, removedNodeIds, deprecatedNodeIds)) continue
359
+
360
+ const endpoints = graph.relationships
361
+ .filter((r) => r.from === api.id && r.type === "contains")
362
+ .map((r) => getNode(graph, r.to))
363
+ .filter((n) => n?.type === "endpoint")
364
+
365
+ if (endpoints.length === 0) {
366
+ result.spec_code_mismatches.push({
367
+ node_id: api.id,
368
+ description: `API ${api.id} has no endpoints defined`,
369
+ severity: "low",
370
+ })
371
+ }
372
+ }
373
+ }
374
+
375
+ /**
376
+ * Try to find a file in a nearby location when the expected path doesn't exist.
377
+ * Handles common structural changes like:
378
+ * - src/validators.ts → src/fields/validators/index.ts
379
+ * - src/schema.ts → src/schema/index.ts
380
+ * - src/components/X.ts → src/components/X/index.ts
381
+ */
382
+ function findFuzzyPathMatch(expectedPath: string, projectDir: string): string | null {
383
+ const segments = expectedPath.split("/")
384
+ const filename = segments[segments.length - 1]
385
+ const nameWithoutExt = filename.replace(/\.[^.]+$/, "")
386
+
387
+ // Strategy 1: Check if file exists as index in a subdirectory
388
+ // e.g., "src/validators.ts" → try "src/validators/index.ts"
389
+ const withoutExt = expectedPath.replace(/\.[^.]+$/, "")
390
+ const indexCandidates = [
391
+ `${withoutExt}/index.ts`,
392
+ `${withoutExt}/index.tsx`,
393
+ `${withoutExt}/index.js`,
394
+ `${withoutExt}/index.jsx`,
395
+ ]
396
+ for (const candidate of indexCandidates) {
397
+ if (existsSync(join(projectDir, candidate))) return candidate
398
+ }
399
+
400
+ // Strategy 2: Search for files with the same name in parent/sibling directories
401
+ const dir = segments.slice(0, -1).join("/")
402
+ const parentDir = segments.slice(0, -2).join("/")
403
+ if (parentDir) {
404
+ try {
405
+ const entries = require("fs").readdirSync(join(projectDir, parentDir), { withFileTypes: true })
406
+ for (const entry of entries) {
407
+ if (!entry.isDirectory()) continue
408
+ const candidateDir = `${parentDir}/${entry.name}`
409
+ const candidatePath = `${candidateDir}/${filename}`
410
+ if (existsSync(join(projectDir, candidatePath))) return candidatePath
411
+ // Also check index files in subdirectories
412
+ const idxCandidates = [
413
+ `${candidateDir}/${nameWithoutExt}/index.ts`,
414
+ `${candidateDir}/${nameWithoutExt}/index.tsx`,
415
+ ]
416
+ for (const idx of idxCandidates) {
417
+ if (existsSync(join(projectDir, idx))) return idx
418
+ }
419
+ }
420
+ } catch {
421
+ // skip
422
+ }
423
+ }
424
+
425
+ // Strategy 3: Check one level up in directory tree
426
+ if (segments.length > 2) {
427
+ const parentPath = segments.slice(0, -2).concat(filename).join("/")
428
+ if (existsSync(join(projectDir, parentPath))) return parentPath
429
+ }
430
+
431
+ return null
432
+ }
433
+
434
+ export function formatDriftReport(result: DriftDetectionResult): string {
435
+ const lines: string[] = []
436
+
437
+ if (!result.has_drift) {
438
+ lines.push("✅ No drift detected. SDD and code are in sync.\n")
439
+ return lines.join("\n")
440
+ }
441
+
442
+ lines.push("⚠️ Drift Detected\n")
443
+
444
+ if (result.missing_files.length > 0) {
445
+ lines.push(`### Missing Files (${result.missing_files.length})`)
446
+ for (const missing of result.missing_files) {
447
+ lines.push(`- [${missing.node_id}] ${missing.file_path} (expected by: ${missing.expected_by})`)
448
+ }
449
+ lines.push("")
450
+ }
451
+
452
+ if (result.spec_code_mismatches.length > 0) {
453
+ lines.push(`### Specification Mismatches (${result.spec_code_mismatches.length})`)
454
+ for (const mismatch of result.spec_code_mismatches) {
455
+ lines.push(`- [${mismatch.node_id}] ${mismatch.description} (severity: ${mismatch.severity})`)
456
+ }
457
+ lines.push("")
458
+ }
459
+
460
+ if (result.signals && result.signals.total_signals > 0) {
461
+ lines.push(formatDriftSignals(result.signals))
462
+ }
463
+
464
+ return lines.join("\n")
465
+ }
@@ -0,0 +1,223 @@
1
+ import type { KnowledgeGraph, ChangeNode } from "../domain/types.js"
2
+ import { existsSync, readFileSync, writeFileSync, mkdirSync } from "fs"
3
+ import { join, dirname } from "path"
4
+
5
+ /**
6
+ * Collects all node IDs that were removed by completed or approved changes.
7
+ * Nodes removed via ChangeNode should not be flagged as drift or cause
8
+ * false positives in validation, coverage, contradictions, etc.
9
+ */
10
+ export function getRemovedNodeIds(graph: KnowledgeGraph): Set<string> {
11
+ const removed = new Set<string>()
12
+ const changes = graph.nodes.filter(
13
+ (n): n is ChangeNode =>
14
+ n.type === "change" &&
15
+ ["COMPLETED", "APPROVED", "IMPLEMENTED"].includes(n.status),
16
+ )
17
+ for (const change of changes) {
18
+ const meta = change.metadata as ChangeNode["metadata"]
19
+ if (Array.isArray(meta.removed_nodes)) {
20
+ for (const id of meta.removed_nodes) {
21
+ removed.add(id)
22
+ }
23
+ }
24
+ }
25
+ return removed
26
+ }
27
+
28
+ /**
29
+ * Collects all node IDs that were deprecated via DeprecationNode relationships.
30
+ */
31
+ export function getDeprecatedNodeIds(graph: KnowledgeGraph): Set<string> {
32
+ const deprecated = new Set<string>()
33
+ const deprecationNodes = graph.nodes.filter((n) => n.type === "deprecation")
34
+ for (const dep of deprecationNodes) {
35
+ const targets = graph.relationships
36
+ .filter((r) => r.from === dep.id && r.type === "deprecates")
37
+ .map((r) => r.to)
38
+ for (const id of targets) {
39
+ deprecated.add(id)
40
+ }
41
+ }
42
+ return deprecated
43
+ }
44
+
45
+ /**
46
+ * Checks if a node should be excluded, also considering DEPRECATED status.
47
+ */
48
+ export function isNodeExcludedOrDeprecated(
49
+ nodeId: string,
50
+ status: string,
51
+ removedIds: Set<string>,
52
+ deprecatedIds: Set<string>,
53
+ ): boolean {
54
+ return (
55
+ status === "DEPRECATED" ||
56
+ removedIds.has(nodeId) ||
57
+ deprecatedIds.has(nodeId)
58
+ )
59
+ }
60
+
61
+ /**
62
+ * Convenience: pre-compute both sets at once.
63
+ */
64
+ export function getExclusionSets(graph: KnowledgeGraph): {
65
+ removed: Set<string>
66
+ deprecated: Set<string>
67
+ } {
68
+ return {
69
+ removed: getRemovedNodeIds(graph),
70
+ deprecated: getDeprecatedNodeIds(graph),
71
+ }
72
+ }
73
+
74
+ // ── Drift Whitelist ─────────────────────────────────────────────────
75
+
76
+ const DRIFT_WHITELIST_FILE = ".sdd/drift-whitelist.json"
77
+
78
+ export interface DriftWhitelistEntry {
79
+ file_path: string
80
+ reason: string
81
+ added_at: string
82
+ added_by?: string
83
+ }
84
+
85
+ export interface DriftWhitelist {
86
+ version: number
87
+ entries: DriftWhitelistEntry[]
88
+ }
89
+
90
+ /**
91
+ * Load the drift whitelist from disk.
92
+ */
93
+ export function loadDriftWhitelist(projectDir: string): DriftWhitelist {
94
+ const path = join(projectDir, DRIFT_WHITELIST_FILE)
95
+ if (!existsSync(path)) return { version: 1, entries: [] }
96
+ try {
97
+ return JSON.parse(readFileSync(path, "utf-8")) as DriftWhitelist
98
+ } catch {
99
+ return { version: 1, entries: [] }
100
+ }
101
+ }
102
+
103
+ /**
104
+ * Save the drift whitelist to disk.
105
+ */
106
+ export function saveDriftWhitelist(projectDir: string, whitelist: DriftWhitelist): void {
107
+ const path = join(projectDir, DRIFT_WHITELIST_FILE)
108
+ const dir = dirname(path)
109
+ if (!existsSync(dir)) mkdirSync(dir, { recursive: true })
110
+ writeFileSync(path, JSON.stringify(whitelist, null, 2), "utf-8")
111
+ }
112
+
113
+ /**
114
+ * Add a file to the drift whitelist.
115
+ */
116
+ export function addToDriftWhitelist(
117
+ projectDir: string,
118
+ filePath: string,
119
+ reason: string,
120
+ addedBy?: string,
121
+ ): DriftWhitelist {
122
+ const whitelist = loadDriftWhitelist(projectDir)
123
+ const normalizedPath = filePath.replace(/^\.\//, "")
124
+
125
+ // Don't add duplicates
126
+ if (!whitelist.entries.some(e => e.file_path === normalizedPath)) {
127
+ whitelist.entries.push({
128
+ file_path: normalizedPath,
129
+ reason,
130
+ added_at: new Date().toISOString(),
131
+ added_by: addedBy,
132
+ })
133
+ saveDriftWhitelist(projectDir, whitelist)
134
+ }
135
+
136
+ return whitelist
137
+ }
138
+
139
+ /**
140
+ * Remove a file from the drift whitelist.
141
+ */
142
+ export function removeFromDriftWhitelist(
143
+ projectDir: string,
144
+ filePath: string,
145
+ ): DriftWhitelist {
146
+ const whitelist = loadDriftWhitelist(projectDir)
147
+ const normalizedPath = filePath.replace(/^\.\//, "")
148
+ whitelist.entries = whitelist.entries.filter(e => e.file_path !== normalizedPath)
149
+ saveDriftWhitelist(projectDir, whitelist)
150
+ return whitelist
151
+ }
152
+
153
+ /**
154
+ * Check if a file path matches any whitelist pattern (supports wildcards).
155
+ * E.g., "src/validators/*" matches all files in src/validators/
156
+ */
157
+ export function isFileWhitelistedPattern(projectDir: string, filePath: string): boolean {
158
+ const whitelist = loadDriftWhitelist(projectDir)
159
+ const normalizedPath = filePath.replace(/^\.\//, "")
160
+
161
+ for (const entry of whitelist.entries) {
162
+ // Exact match
163
+ if (entry.file_path === normalizedPath) return true
164
+
165
+ // Recursive wildcard: apps/**, packages/**, **/*.ts, etc.
166
+ if (entry.file_path.endsWith("/**")) {
167
+ const prefix = entry.file_path.slice(0, -3)
168
+ if (normalizedPath.startsWith(prefix + "/") || normalizedPath === prefix) return true
169
+ }
170
+
171
+ // Single-level wildcard: src/validators/*
172
+ if (entry.file_path.endsWith("/*") && !entry.file_path.endsWith("/**")) {
173
+ const prefix = entry.file_path.slice(0, -2)
174
+ if (normalizedPath.startsWith(prefix + "/") || normalizedPath === prefix) return true
175
+ }
176
+
177
+ // Directory match (ends with /)
178
+ if (entry.file_path.endsWith("/")) {
179
+ if (normalizedPath.startsWith(entry.file_path)) return true
180
+ }
181
+
182
+ // Glob wildcard in filename: **/*.ts, *.tsx, src/**/*.ts
183
+ if (entry.file_path.includes("*")) {
184
+ const regex = globToRegex(entry.file_path)
185
+ if (regex.test(normalizedPath)) return true
186
+ }
187
+ }
188
+
189
+ return false
190
+ }
191
+
192
+ /**
193
+ * Convert a glob pattern to a RegExp.
194
+ * Supports double-star and single-star patterns.
195
+ */
196
+ function globToRegex(glob: string): RegExp {
197
+ // Process segments separated by /
198
+ const segments = glob.split("/")
199
+ const regexParts: string[] = []
200
+
201
+ for (const seg of segments) {
202
+ if (seg === "**") {
203
+ // ** matches any number of path segments
204
+ regexParts.push(".*")
205
+ } else if (seg === "*") {
206
+ // Single * matches within one segment
207
+ regexParts.push("[^/]+")
208
+ } else if (seg.includes("*")) {
209
+ // Mixed segment like *.ts or tsx-*.test
210
+ const escaped = seg.replace(/\./g, "\\.")
211
+ const inner = escaped.replace(/\*/g, "[^/]*")
212
+ regexParts.push(inner)
213
+ } else {
214
+ // Literal segment
215
+ const escaped = seg.replace(/\./g, "\\.")
216
+ regexParts.push(escaped)
217
+ }
218
+ }
219
+
220
+ // Join with \/ to match path separators
221
+ const pattern = regexParts.join("\\/")
222
+ return new RegExp("^" + pattern + "$")
223
+ }