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,1181 @@
1
+ import type {
2
+ KnowledgeGraph,
3
+ EntityNode,
4
+ FeatureNode,
5
+ ArchitectureComponentNode,
6
+ EndpointNode,
7
+ DatabaseNode,
8
+ TableNode,
9
+ BusinessRuleNode,
10
+ } from "../domain/types.js"
11
+ import { getNodesByType } from "../graph/engine.js"
12
+ import { getExclusionSets, isNodeExcludedOrDeprecated } from "../drift/exclusion.js"
13
+ import { writeFileSync, mkdirSync, existsSync } from "fs"
14
+ import { join, dirname, resolve, relative } from "path"
15
+
16
+ export interface GeneratedFile {
17
+ path: string
18
+ content: string
19
+ description: string
20
+ }
21
+
22
+ export interface GenerationPlan {
23
+ files: GeneratedFile[]
24
+ directories: string[]
25
+ summary: string
26
+ }
27
+
28
+ export interface TechStack {
29
+ frontend?: string
30
+ backend?: string
31
+ database?: string
32
+ language?: string
33
+ orm?: string
34
+ testFramework?: string
35
+ }
36
+
37
+ export function detectTechStack(graph: KnowledgeGraph): TechStack {
38
+ const archNodes = getNodesByType<ArchitectureComponentNode>(graph, "architecture_component")
39
+ const dbNodes = getNodesByType<DatabaseNode>(graph, "database")
40
+
41
+ const stack: TechStack = {}
42
+
43
+ for (const arch of archNodes) {
44
+ const tech = arch.metadata.technology?.toLowerCase() || ""
45
+ const layer = arch.metadata.layer
46
+
47
+ if (layer === "frontend") {
48
+ if (tech.includes("react")) stack.frontend = "react"
49
+ else if (tech.includes("vue")) stack.frontend = "vue"
50
+ else if (tech.includes("angular")) stack.frontend = "angular"
51
+ else if (tech.includes("svelte")) stack.frontend = "svelte"
52
+ else stack.frontend = tech || undefined
53
+ }
54
+
55
+ if (layer === "backend") {
56
+ if (tech.includes("express")) stack.backend = "express"
57
+ else if (tech.includes("fastify")) stack.backend = "fastify"
58
+ else if (tech.includes("nestjs")) stack.backend = "nestjs"
59
+ else if (tech.includes("django")) stack.backend = "django"
60
+ else if (tech.includes("fastapi")) stack.backend = "fastapi"
61
+ else if (tech.includes("flask")) stack.backend = "flask"
62
+ else if (tech.includes("rails")) stack.backend = "rails"
63
+ else if (tech.includes("laravel")) stack.backend = "laravel"
64
+ else if (tech.includes("gin")) stack.backend = "gin"
65
+ else if (tech.includes("fiber")) stack.backend = "fiber"
66
+ else if (tech.includes("actix") || tech.includes("axum")) stack.backend = "rust"
67
+ else if (tech.includes("spring")) stack.backend = "spring"
68
+ else stack.backend = tech || undefined
69
+ }
70
+ }
71
+
72
+ for (const db of dbNodes) {
73
+ const engine = db.metadata.engine?.toLowerCase() || ""
74
+ if (engine.includes("postgres")) stack.database = "postgresql"
75
+ else if (engine.includes("mysql")) stack.database = "mysql"
76
+ else if (engine.includes("sqlite")) stack.database = "sqlite"
77
+ else if (engine.includes("mongo")) stack.database = "mongodb"
78
+ else if (engine.includes("redis")) stack.database = "redis"
79
+ else stack.database = engine || undefined
80
+ }
81
+
82
+ return stack
83
+ }
84
+
85
+ const SUPPORTED_BACKENDS = new Set(["express", "fastify", "nestjs"])
86
+ const SUPPORTED_FRONTENDS = new Set(["react"])
87
+ const SUPPORTED_DATABASES = new Set(["sqlite", "postgresql", "mysql"])
88
+
89
+ export function hasCodegenSupport(stack: TechStack): boolean {
90
+ return (
91
+ !stack.backend || SUPPORTED_BACKENDS.has(stack.backend)
92
+ ) && (
93
+ !stack.frontend || SUPPORTED_FRONTENDS.has(stack.frontend)
94
+ ) && (
95
+ !stack.database || SUPPORTED_DATABASES.has(stack.database)
96
+ )
97
+ }
98
+
99
+ export function generateProject(
100
+ graph: KnowledgeGraph,
101
+ stack?: TechStack,
102
+ ): GenerationPlan {
103
+ const detectedStack = stack || detectTechStack(graph)
104
+
105
+ // If the stack is partially/fully unknown, return a spec prompt for the AI to generate
106
+ if (!hasCodegenSupport(detectedStack)) {
107
+ return generateSpecPrompt(graph, detectedStack)
108
+ }
109
+
110
+ const { removed, deprecated } = getExclusionSets(graph)
111
+ const entities = getNodesByType<EntityNode>(graph, "entity")
112
+ .filter((e) => !isNodeExcludedOrDeprecated(e.id, e.status, removed, deprecated))
113
+ const features = getNodesByType<FeatureNode>(graph, "feature")
114
+ .filter((f) => !isNodeExcludedOrDeprecated(f.id, f.status, removed, deprecated))
115
+ const endpoints = getNodesByType<EndpointNode>(graph, "endpoint")
116
+ .filter((e) => !isNodeExcludedOrDeprecated(e.id, e.status, removed, deprecated))
117
+ const tables = getNodesByType<TableNode>(graph, "table")
118
+ .filter((t) => !isNodeExcludedOrDeprecated(t.id, t.status, removed, deprecated))
119
+ const businessRules = getNodesByType<BusinessRuleNode>(graph, "business_rule")
120
+ .filter((b) => !isNodeExcludedOrDeprecated(b.id, b.status, removed, deprecated))
121
+
122
+ const files: GeneratedFile[] = []
123
+ const directories: Set<string> = new Set()
124
+
125
+ // Generate backend
126
+ if (detectedStack.backend === "express" || detectedStack.backend === "fastify") {
127
+ generateExpressBackend(graph, entities, endpoints, tables, businessRules, files, directories, detectedStack)
128
+ }
129
+
130
+ // Generate frontend
131
+ if (detectedStack.frontend === "react") {
132
+ generateReactFrontend(graph, entities, features, endpoints, files, directories, detectedStack)
133
+ }
134
+
135
+ // Generate database schema
136
+ generateDatabaseSchema(graph, entities, tables, files, directories, detectedStack)
137
+
138
+ // Generate tests
139
+ generateTests(graph, entities, endpoints, files, directories, detectedStack)
140
+
141
+ // Generate shared types
142
+ generateSharedTypes(graph, entities, files, directories, detectedStack)
143
+
144
+ const dirList = [...directories].sort()
145
+
146
+ return {
147
+ files,
148
+ directories: dirList,
149
+ summary: buildGenerationSummary(graph, entities, features, files, detectedStack),
150
+ }
151
+ }function generateSpecPrompt(graph: KnowledgeGraph, stack: TechStack): GenerationPlan {
152
+ const entities = getNodesByType<EntityNode>(graph, "entity")
153
+ const endpoints = getNodesByType<EndpointNode>(graph, "endpoint")
154
+ const businessRules = getNodesByType<BusinessRuleNode>(graph, "business_rule")
155
+
156
+ // ── Context-aware: gather decisions, constraints, architecture ──
157
+ const decisions = graph.nodes.filter(n => n.type === "decision")
158
+ const constraints = graph.nodes.filter(n => n.type === "constraint")
159
+ const archComponents = graph.nodes.filter(n => n.type === "architecture_component")
160
+ const constitution = graph.nodes.find(n => n.type === "constitution")
161
+
162
+ const stackDesc = [
163
+ stack.frontend && `Frontend: ${stack.frontend}`,
164
+ stack.backend && `Backend: ${stack.backend}`,
165
+ stack.database && `Database: ${stack.database}`,
166
+ stack.language && `Language: ${stack.language}`,
167
+ ].filter(Boolean).join(" | ") || "Unknown stack"
168
+
169
+ const entityList = entities.map((e) => {
170
+ const fields = (e.metadata.fields || []).map((f) => ` - ${f.name}: ${f.type}${f.required ? " (required)" : ""}`).join("\n")
171
+ return `- **${e.name}**\n${fields}`
172
+ }).join("\n")
173
+
174
+ const endpointList = endpoints.map((ep) => {
175
+ const meta = ep.metadata
176
+ return `- \`${meta.method || "GET"} ${meta.path || ep.name}\` — ${ep.description || ep.name}`
177
+ }).join("\n")
178
+
179
+ const rulesList = businessRules.map((r) => `- **${r.name}:** ${r.description || r.metadata.rule_text || ""}`).join("\n")
180
+
181
+ // Context sections
182
+ const decisionsList = decisions.map((d) => {
183
+ const meta = d.metadata as any
184
+ return `- **${meta.title || d.name}:** ${meta.decision || d.description}`
185
+ }).join("\n")
186
+
187
+ const constraintsList = constraints.map((c) => {
188
+ const meta = c.metadata as any
189
+ return `- [${meta.constraint_type || "technical"}] ${meta.rule_text || c.description}`
190
+ }).join("\n")
191
+
192
+ const archList = archComponents.map((a) => {
193
+ const meta = a.metadata as any
194
+ return `- **${a.name}** (${meta.layer}): ${meta.technology || "unknown"} — ${a.description || ""}`
195
+ }).join("\n")
196
+
197
+ const principlesList = (() => {
198
+ if (!constitution) return ""
199
+ const meta = constitution.metadata as any
200
+ if (!meta.principles) return ""
201
+ return meta.principles.map((p: any) => `- [${p.severity}] ${p.rule}`).join("\n")
202
+ })()
203
+
204
+ const prompt = [
205
+ `## Code Generation Prompt`,
206
+ ``,
207
+ `**Detected Stack:** ${stackDesc}`,
208
+ `**Note:** The detected tech stack is not in the set of stacks with built-in templates.`,
209
+ `Generate the project code using your knowledge of the specified technologies.`,
210
+ ``,
211
+ `### Entities`,
212
+ entityList || "No entities defined.",
213
+ ``,
214
+ `### API Endpoints`,
215
+ endpointList || "No endpoints defined.",
216
+ ``,
217
+ `### Business Rules`,
218
+ rulesList || "No business rules defined.",
219
+ ``,
220
+ ]
221
+
222
+ if (decisionsList) {
223
+ prompt.push(`### Architecture Decisions (ADRs)`, decisionsList, ``)
224
+ }
225
+ if (constraintsList) {
226
+ prompt.push(`### Constraints`, constraintsList, ``)
227
+ }
228
+ if (archList) {
229
+ prompt.push(`### Architecture Components`, archList, ``)
230
+ }
231
+ if (principlesList) {
232
+ prompt.push(`### Constitution (Mandatory Principles)`, principlesList, ``)
233
+ }
234
+
235
+ prompt.push(
236
+ `### Instructions`,
237
+ `Generate a complete project structure for a ${stackDesc} application.`,
238
+ `Include:`,
239
+ `1. Project configuration files (package.json, tsconfig, etc.)`,
240
+ `2. Backend: routes, controllers/services, database access layer`,
241
+ `3. Frontend: components, pages, state management`,
242
+ `4. Database schema/migrations`,
243
+ `5. Tests`,
244
+ `6. README with setup instructions`,
245
+ ``,
246
+ `Follow the conventions and patterns commonly used with the specified technologies.`,
247
+ `Use the entity fields and API endpoints above to generate the actual code.`,
248
+ )
249
+
250
+ if (decisionsList) {
251
+ prompt.push(`Respect the architecture decisions listed above.`)
252
+ }
253
+ if (constraintsList) {
254
+ prompt.push(`Apply all constraints listed above.`)
255
+ }
256
+ if (principlesList) {
257
+ prompt.push(`Follow ALL constitution principles — they are mandatory.`)
258
+ }
259
+
260
+ return {
261
+ files: [],
262
+ directories: [],
263
+ summary: prompt.join("\n"),
264
+ }
265
+ }
266
+
267
+ function generateExpressBackend(
268
+ _graph: KnowledgeGraph,
269
+ entities: EntityNode[],
270
+ _endpoints: EndpointNode[],
271
+ _tables: TableNode[],
272
+ _rules: BusinessRuleNode[],
273
+ files: GeneratedFile[],
274
+ dirs: Set<string>,
275
+ _stack: TechStack,
276
+ ): void {
277
+ dirs.add("src/server")
278
+ dirs.add("src/server/routes")
279
+ dirs.add("src/server/controllers")
280
+ dirs.add("src/server/services")
281
+ dirs.add("src/server/repositories")
282
+ dirs.add("src/server/middleware")
283
+ dirs.add("src/server/models")
284
+
285
+ // Server entry
286
+ files.push({
287
+ path: "src/server/index.ts",
288
+ description: "Express server entry point",
289
+ content: `import express from "express"
290
+ import cors from "cors"
291
+ import { router } from "./routes/index.js"
292
+
293
+ const app = express()
294
+ const PORT = process.env.PORT || 3000
295
+
296
+ app.use(cors())
297
+ app.use(express.json())
298
+
299
+ app.use("/api", router)
300
+
301
+ app.listen(PORT, () => {
302
+ console.log(\`Server running on port \${PORT}\`)
303
+ })
304
+ `,
305
+ })
306
+
307
+ // Routes index
308
+ const routeImports = entities.map((e) => {
309
+ const name = e.name.toLowerCase()
310
+ return `import { ${name}Router } from "./${name}.js"`
311
+ }).join("\n")
312
+
313
+ const routeUses = entities.map((e) => {
314
+ const name = e.name.toLowerCase()
315
+ return `router.use("/${name}s", ${name}Router)`
316
+ }).join("\n")
317
+
318
+ files.push({
319
+ path: "src/server/routes/index.ts",
320
+ description: "Route aggregator",
321
+ content: `import { Router } from "express"
322
+ ${routeImports}
323
+
324
+ const router = Router()
325
+ ${routeUses}
326
+
327
+ export { router }
328
+ `,
329
+ })
330
+
331
+ // Generate per-entity: model, repository, service, controller, routes
332
+ for (const entity of entities) {
333
+ const name = entity.name
334
+ const nameLower = name.toLowerCase()
335
+ const namePlural = `${nameLower}s`
336
+ const fields = entity.metadata.fields || []
337
+
338
+ // Model
339
+ const modelFields = fields.map((f) => {
340
+ const tsType = mapToTsType(f.type)
341
+ const optional = f.required ? "" : "?"
342
+ return ` ${f.name}${optional}: ${tsType}`
343
+ }).join("\n")
344
+
345
+ files.push({
346
+ path: `src/server/models/${nameLower}.ts`,
347
+ description: `${name} model/type definition`,
348
+ content: `export interface ${name} {
349
+ id: string
350
+ ${modelFields}
351
+ created_at: Date
352
+ updated_at: Date
353
+ }
354
+
355
+ export type Create${name}Input = Omit<${name}, "id" | "created_at" | "updated_at">
356
+ export type Update${name}Input = Partial<Create${name}Input>
357
+ `,
358
+ })
359
+
360
+ // Repository
361
+ files.push({
362
+ path: `src/server/repositories/${nameLower}.repository.ts`,
363
+ description: `${name} repository (database access)`,
364
+ content: `import { db } from "../database.js"
365
+ import type { ${name}, Create${name}Input, Update${name}Input } from "../models/${nameLower}.js"
366
+
367
+ export const ${name}Repository = {
368
+ async findAll(): Promise<${name}[]> {
369
+ return db.select().from("${namePlural}")
370
+ },
371
+
372
+ async findById(id: string): Promise<${name} | undefined> {
373
+ return db.select().from("${namePlural}").where({ id }).first()
374
+ },
375
+
376
+ async create(data: Create${name}Input): Promise<${name}> {
377
+ const id = crypto.randomUUID()
378
+ const now = new Date()
379
+ await db.insert("${namePlural}").values({ id, ...data, created_at: now, updated_at: now })
380
+ return { id, ...data, created_at: now, updated_at: now }
381
+ },
382
+
383
+ async update(id: string, data: Update${name}Input): Promise<${name} | undefined> {
384
+ const existing = await this.findById(id)
385
+ if (!existing) return undefined
386
+ const updated = { ...existing, ...data, updated_at: new Date() }
387
+ await db.update("${namePlural}").set(updated).where({ id })
388
+ return updated
389
+ },
390
+
391
+ async delete(id: string): Promise<boolean> {
392
+ const result = await db.delete("${namePlural}").where({ id })
393
+ return result.changes > 0
394
+ },
395
+ }
396
+ `,
397
+ })
398
+
399
+ // Service
400
+ files.push({
401
+ path: `src/server/services/${nameLower}.service.ts`,
402
+ description: `${name} service (business logic)`,
403
+ content: `import { ${name}Repository } from "../repositories/${nameLower}.repository.js"
404
+ import type { Create${name}Input, Update${name}Input } from "../models/${nameLower}.js"
405
+
406
+ export const ${name}Service = {
407
+ async list() {
408
+ return ${name}Repository.findAll()
409
+ },
410
+
411
+ async getById(id: string) {
412
+ const item = await ${name}Repository.findById(id)
413
+ if (!item) throw new Error("${name} not found")
414
+ return item
415
+ },
416
+
417
+ async create(data: Create${name}Input) {
418
+ return ${name}Repository.create(data)
419
+ },
420
+
421
+ async update(id: string, data: Update${name}Input) {
422
+ const item = await ${name}Repository.update(id, data)
423
+ if (!item) throw new Error("${name} not found")
424
+ return item
425
+ },
426
+
427
+ async delete(id: string) {
428
+ const deleted = await ${name}Repository.delete(id)
429
+ if (!deleted) throw new Error("${name} not found")
430
+ },
431
+ }
432
+ `,
433
+ })
434
+
435
+ // Controller
436
+ files.push({
437
+ path: `src/server/controllers/${nameLower}.controller.ts`,
438
+ description: `${name} controller (HTTP handling)`,
439
+ content: `import type { Request, Response } from "express"
440
+ import { ${name}Service } from "../services/${nameLower}.service.js"
441
+
442
+ export const ${name}Controller = {
443
+ async list(_req: Request, res: Response) {
444
+ try {
445
+ const items = await ${name}Service.list()
446
+ res.json(items)
447
+ } catch (err) {
448
+ res.status(500).json({ error: (err as Error).message })
449
+ }
450
+ },
451
+
452
+ async getById(req: Request, res: Response) {
453
+ try {
454
+ const item = await ${name}Service.getById(req.params.id)
455
+ res.json(item)
456
+ } catch (err) {
457
+ res.status(404).json({ error: (err as Error).message })
458
+ }
459
+ },
460
+
461
+ async create(req: Request, res: Response) {
462
+ try {
463
+ const item = await ${name}Service.create(req.body)
464
+ res.status(201).json(item)
465
+ } catch (err) {
466
+ res.status(400).json({ error: (err as Error).message })
467
+ }
468
+ },
469
+
470
+ async update(req: Request, res: Response) {
471
+ try {
472
+ const item = await ${name}Service.update(req.params.id, req.body)
473
+ res.json(item)
474
+ } catch (err) {
475
+ res.status(400).json({ error: (err as Error).message })
476
+ }
477
+ },
478
+
479
+ async remove(req: Request, res: Response) {
480
+ try {
481
+ await ${name}Service.delete(req.params.id)
482
+ res.status(204).end()
483
+ } catch (err) {
484
+ res.status(404).json({ error: (err as Error).message })
485
+ }
486
+ },
487
+ }
488
+ `,
489
+ })
490
+
491
+ // Routes
492
+ files.push({
493
+ path: `src/server/routes/${nameLower}.ts`,
494
+ description: `${name} routes`,
495
+ content: `import { Router } from "express"
496
+ import { ${name}Controller } from "../controllers/${nameLower}.controller.js"
497
+
498
+ export const ${nameLower}Router = Router()
499
+
500
+ ${nameLower}Router.get("/", ${name}Controller.list)
501
+ ${nameLower}Router.get("/:id", ${name}Controller.getById)
502
+ ${nameLower}Router.post("/", ${name}Controller.create)
503
+ ${nameLower}Router.put("/:id", ${name}Controller.update)
504
+ ${nameLower}Router.delete("/:id", ${name}Controller.remove)
505
+ `,
506
+ })
507
+ }
508
+ }
509
+
510
+ function generateReactFrontend(
511
+ graph: KnowledgeGraph,
512
+ entities: EntityNode[],
513
+ _features: FeatureNode[],
514
+ _endpoints: EndpointNode[],
515
+ files: GeneratedFile[],
516
+ dirs: Set<string>,
517
+ _stack: TechStack,
518
+ ): void {
519
+ dirs.add("src/client")
520
+ dirs.add("src/client/components")
521
+ dirs.add("src/client/pages")
522
+ dirs.add("src/client/hooks")
523
+ dirs.add("src/client/services")
524
+
525
+ // API client
526
+ files.push({
527
+ path: "src/client/services/api.ts",
528
+ description: "API client",
529
+ content: `const API_BASE = import.meta.env.VITE_API_URL || "http://localhost:3000/api"
530
+
531
+ async function request<T>(path: string, options?: RequestInit): Promise<T> {
532
+ const res = await fetch(\`\${API_BASE}\${path}\`, {
533
+ headers: { "Content-Type": "application/json" },
534
+ ...options,
535
+ })
536
+ if (!res.ok) throw new Error(await res.text())
537
+ if (res.status === 204) return undefined as T
538
+ return res.json()
539
+ }
540
+
541
+ export const api = {
542
+ get: <T>(path: string) => request<T>(path),
543
+ post: <T>(path: string, data: unknown) => request<T>(path, { method: "POST", body: JSON.stringify(data) }),
544
+ put: <T>(path: string, data: unknown) => request<T>(path, { method: "PUT", body: JSON.stringify(data) }),
545
+ delete: <T>(path: string) => request<T>(path, { method: "DELETE" }),
546
+ }
547
+ `,
548
+ })
549
+
550
+ // Generate per-entity: hook, list component, form component, page
551
+ for (const entity of entities) {
552
+ const name = entity.name
553
+ const nameLower = name.toLowerCase()
554
+ const namePlural = `${nameLower}s`
555
+ const fields = entity.metadata.fields || []
556
+
557
+ // Hook
558
+ const hookFields = fields.filter(f => f.name !== "id").map(f => {
559
+ const tsType = mapToTsType(f.type)
560
+ return ` ${f.name}: ${tsType}`
561
+ }).join("\n")
562
+
563
+ files.push({
564
+ path: `src/client/hooks/use${name}.ts`,
565
+ description: `${name} CRUD hook`,
566
+ content: `import { useState, useEffect, useCallback } from "react"
567
+ import { api } from "../services/api.js"
568
+
569
+ export interface ${name} {
570
+ id: string
571
+ ${hookFields}
572
+ created_at: string
573
+ updated_at: string
574
+ }
575
+
576
+ export function use${namePlural.charAt(0).toUpperCase() + namePlural.slice(1)}() {
577
+ const [items, setItems] = useState<${name}[]>([])
578
+ const [loading, setLoading] = useState(true)
579
+ const [error, setError] = useState<string | null>(null)
580
+
581
+ const fetchAll = useCallback(async () => {
582
+ try {
583
+ setLoading(true)
584
+ const data = await api.get<${name}[]>("/${namePlural}")
585
+ setItems(data)
586
+ } catch (err) {
587
+ setError((err as Error).message)
588
+ } finally {
589
+ setLoading(false)
590
+ }
591
+ }, [])
592
+
593
+ useEffect(() => { fetchAll() }, [fetchAll])
594
+
595
+ const create = async (data: Omit<${name}, "id" | "created_at" | "updated_at">) => {
596
+ const item = await api.post<${name}>("/${namePlural}", data)
597
+ setItems(prev => [...prev, item])
598
+ return item
599
+ }
600
+
601
+ const update = async (id: string, data: Partial<Omit<${name}, "id">>) => {
602
+ const item = await api.put<${name}>(\`/${namePlural}/\${id}\`, data)
603
+ setItems(prev => prev.map(i => i.id === id ? item : i))
604
+ return item
605
+ }
606
+
607
+ const remove = async (id: string) => {
608
+ await api.delete(\`/${namePlural}/\${id}\`)
609
+ setItems(prev => prev.filter(i => i.id !== id))
610
+ }
611
+
612
+ return { items, loading, error, create, update, remove, refetch: fetchAll }
613
+ }
614
+ `,
615
+ })
616
+
617
+ // List component
618
+ const tableHeaders = fields.slice(0, 5).map(f =>
619
+ ` <th className="px-4 py-2 text-left text-sm font-medium text-gray-700">${f.name}</th>`
620
+ ).join("\n")
621
+
622
+ const tableCells = fields.slice(0, 5).map(f =>
623
+ ` <td className="px-4 py-2 text-sm text-gray-600">{item.${f.name}}</td>`
624
+ ).join("\n")
625
+
626
+ files.push({
627
+ path: `src/client/components/${name}List.tsx`,
628
+ description: `${name} list/table component`,
629
+ content: `import type { ${name} } from "../hooks/use${name}.js"
630
+
631
+ interface ${name}ListProps {
632
+ items: ${name}[]
633
+ onEdit: (item: ${name}) => void
634
+ onDelete: (id: string) => void
635
+ }
636
+
637
+ export function ${name}List({ items, onEdit, onDelete }: ${name}ListProps) {
638
+ return (
639
+ <div className="overflow-x-auto">
640
+ <table className="min-w-full divide-y divide-gray-200">
641
+ <thead className="bg-gray-50">
642
+ <tr>
643
+ ${tableHeaders}
644
+ <th className="px-4 py-2 text-right text-sm font-medium">Actions</th>
645
+ </tr>
646
+ </thead>
647
+ <tbody className="bg-white divide-y divide-gray-200">
648
+ {items.map((item) => (
649
+ <tr key={item.id} className="hover:bg-gray-50">
650
+ ${tableCells}
651
+ <td className="px-4 py-2 text-right space-x-2">
652
+ <button onClick={() => onEdit(item)} className="text-blue-600 hover:text-blue-800 text-sm">Edit</button>
653
+ <button onClick={() => onDelete(item.id)} className="text-red-600 hover:text-red-800 text-sm">Delete</button>
654
+ </td>
655
+ </tr>
656
+ ))}
657
+ </tbody>
658
+ </table>
659
+ </div>
660
+ )
661
+ }
662
+ `,
663
+ })
664
+
665
+ // Form component
666
+ const formFields = fields.filter(f => f.name !== "id").map(f => {
667
+ const inputType = f.type === "number" || f.type === "integer" || f.type === "float" ? "number" : "text"
668
+ return ` <div>
669
+ <label className="block text-sm font-medium text-gray-700 mb-1">${f.name}</label>
670
+ <input
671
+ type="${inputType}"
672
+ name="${f.name}"
673
+ defaultValue={initialValues?.${f.name} ?? ""}
674
+ onChange={handleChange}
675
+ className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
676
+ />
677
+ </div>`
678
+ }).join("\n\n")
679
+
680
+ files.push({
681
+ path: `src/client/components/${name}Form.tsx`,
682
+ description: `${name} form component`,
683
+ content: `import { useState, type FormEvent, type ChangeEvent } from "react"
684
+ import type { ${name} } from "../hooks/use${name}.js"
685
+
686
+ interface ${name}FormProps {
687
+ initialValues?: Partial<${name}>
688
+ onSubmit: (data: Record<string, unknown>) => Promise<void>
689
+ onCancel: () => void
690
+ }
691
+
692
+ export function ${name}Form({ initialValues, onSubmit, onCancel }: ${name}FormProps) {
693
+ const [values, setValues] = useState<Record<string, unknown>>(initialValues || {})
694
+ const [submitting, setSubmitting] = useState(false)
695
+
696
+ const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
697
+ setValues(prev => ({ ...prev, [e.target.name]: e.target.value }))
698
+ }
699
+
700
+ const handleSubmit = async (e: FormEvent) => {
701
+ e.preventDefault()
702
+ setSubmitting(true)
703
+ try { await onSubmit(values) } finally { setSubmitting(false) }
704
+ }
705
+
706
+ return (
707
+ <form onSubmit={handleSubmit} className="space-y-4 p-4 bg-white rounded-lg shadow">
708
+ ${formFields}
709
+ <div className="flex justify-end space-x-2">
710
+ <button type="button" onClick={onCancel} className="px-4 py-2 text-gray-600 hover:text-gray-800">Cancel</button>
711
+ <button type="submit" disabled={submitting} className="px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 disabled:opacity-50">
712
+ {submitting ? "Saving..." : "Save"}
713
+ </button>
714
+ </div>
715
+ </form>
716
+ )
717
+ }
718
+ `,
719
+ })
720
+
721
+ // Page
722
+ files.push({
723
+ path: `src/client/pages/${name}Page.tsx`,
724
+ description: `${name} page (full CRUD)`,
725
+ content: `import { useState } from "react"
726
+ import { use${namePlural.charAt(0).toUpperCase() + namePlural.slice(1)} } from "../hooks/use${name}.js"
727
+ import { ${name}List } from "../components/${name}List.js"
728
+ import { ${name}Form } from "../components/${name}Form.js"
729
+ import type { ${name} } from "../hooks/use${name}.js"
730
+
731
+ export function ${name}Page() {
732
+ const { items, loading, error, create, update, remove } = use${namePlural.charAt(0).toUpperCase() + namePlural.slice(1)}()
733
+ const [editing, setEditing] = useState<${name} | null>(null)
734
+ const [showForm, setShowForm] = useState(false)
735
+
736
+ const handleCreate = async (data: Record<string, unknown>) => {
737
+ await create(data as any)
738
+ setShowForm(false)
739
+ }
740
+
741
+ const handleUpdate = async (data: Record<string, unknown>) => {
742
+ if (editing) {
743
+ await update(editing.id, data as any)
744
+ setEditing(null)
745
+ }
746
+ }
747
+
748
+ const handleDelete = async (id: string) => {
749
+ if (confirm("Are you sure?")) await remove(id)
750
+ }
751
+
752
+ if (loading) return <div className="p-8 text-center">Loading...</div>
753
+ if (error) return <div className="p-8 text-center text-red-600">Error: {error}</div>
754
+
755
+ return (
756
+ <div className="max-w-6xl mx-auto p-8">
757
+ <div className="flex justify-between items-center mb-6">
758
+ <h1 className="text-2xl font-bold text-gray-900">${name}</h1>
759
+ <button onClick={() => { setEditing(null); setShowForm(true) }} className="px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700">
760
+ Add ${name}
761
+ </button>
762
+ </div>
763
+
764
+ {showForm && (
765
+ <${name}Form onSubmit={handleCreate} onCancel={() => setShowForm(false)} />
766
+ )}
767
+
768
+ {editing && (
769
+ <${name}Form initialValues={editing} onSubmit={handleUpdate} onCancel={() => setEditing(null)} />
770
+ )}
771
+
772
+ <${name}List items={items} onEdit={(item) => { setEditing(item); setShowForm(false) }} onDelete={handleDelete} />
773
+ </div>
774
+ )
775
+ }
776
+ `,
777
+ })
778
+ }
779
+
780
+ // App.tsx
781
+ const pageImports = entities.map(e =>
782
+ `import { ${e.name}Page } from "./pages/${e.name}Page.js"`
783
+ ).join("\n")
784
+
785
+ const pageRoutes = entities.map(e => {
786
+ const nameLower = e.name.toLowerCase()
787
+ const namePlural = `${nameLower}s`
788
+ return ` <Route path="/${namePlural}" element={<${e.name}Page />} />`
789
+ }).join("\n")
790
+
791
+ files.push({
792
+ path: "src/client/App.tsx",
793
+ description: "Main App component with routing",
794
+ content: `import { BrowserRouter, Routes, Route, Link } from "react-router-dom"
795
+ ${pageImports}
796
+
797
+ function Home() {
798
+ return (
799
+ <div className="max-w-4xl mx-auto p-8">
800
+ <h1 className="text-3xl font-bold mb-6">${graph.project_id}</h1>
801
+ <nav className="space-y-2">
802
+ ${entities.map(e => ` <Link to="/${e.name.toLowerCase()}s" className="block text-blue-600 hover:underline">${e.name}</Link>`).join("\n")}
803
+ </nav>
804
+ </div>
805
+ )
806
+ }
807
+
808
+ export default function App() {
809
+ return (
810
+ <BrowserRouter>
811
+ <div className="min-h-screen bg-gray-100">
812
+ <nav className="bg-white shadow-sm">
813
+ <div className="max-w-6xl mx-auto px-4 py-3">
814
+ <Link to="/" className="text-lg font-bold text-gray-900">${graph.project_id}</Link>
815
+ </div>
816
+ </nav>
817
+ <Routes>
818
+ <Route path="/" element={<Home />} />
819
+ ${pageRoutes}
820
+ </Routes>
821
+ </div>
822
+ </BrowserRouter>
823
+ )
824
+ }
825
+ `,
826
+ })
827
+ }
828
+
829
+ function generateDatabaseSchema(
830
+ _graph: KnowledgeGraph,
831
+ entities: EntityNode[],
832
+ _tables: TableNode[],
833
+ files: GeneratedFile[],
834
+ dirs: Set<string>,
835
+ stack: TechStack,
836
+ ): void {
837
+ dirs.add("src/server")
838
+
839
+ if (stack.database === "sqlite" || stack.database === "postgresql" || stack.database === "mysql") {
840
+ const createStatements = entities.map(entity => {
841
+ const name = entity.name.toLowerCase()
842
+ const namePlural = `${name}s`
843
+ const fields = entity.metadata.fields || []
844
+
845
+ const columns = [
846
+ " id TEXT PRIMARY KEY",
847
+ ...fields.map(f => {
848
+ const colType = mapToSqlType(f.type)
849
+ const nullable = f.required ? " NOT NULL" : ""
850
+ const unique = f.unique ? " UNIQUE" : ""
851
+ return ` ${f.name} ${colType}${nullable}${unique}`
852
+ }),
853
+ " created_at TEXT NOT NULL",
854
+ " updated_at TEXT NOT NULL",
855
+ ]
856
+
857
+ return `CREATE TABLE IF NOT EXISTS ${namePlural} (\n${columns.join(",\n")}\n);`
858
+ })
859
+
860
+ files.push({
861
+ path: "src/server/schema.sql",
862
+ description: "Database schema",
863
+ content: createStatements.join("\n\n") + "\n",
864
+ })
865
+
866
+ // Database connection - built as array to avoid template literal nesting
867
+ if (stack.database === "sqlite") {
868
+ const dbLines: string[] = [
869
+ 'import Database from "bun:sqlite"',
870
+ "",
871
+ 'const sqlite = new Database(":memory:")',
872
+ "",
873
+ "export const db = {",
874
+ " select() {",
875
+ " return {",
876
+ " from: (table: string) => ({",
877
+ " where: (conditions: Record<string, unknown>) => ({",
878
+ " first: () => {",
879
+ " const keys = Object.keys(conditions)",
880
+ " const vals = Object.values(conditions)",
881
+ ' const placeholders = keys.map(k => k + " = ?").join(" AND ")',
882
+ " const stmt = sqlite.prepare(`SELECT * FROM ${" + "table" + "} WHERE ${" + "placeholders" + "}`)",
883
+ " return stmt.get(...vals) as any",
884
+ " },",
885
+ " }),",
886
+ " all: () => sqlite.prepare(`SELECT * FROM ${" + "table" + "}`).all() as any[],",
887
+ " }),",
888
+ " }",
889
+ " },",
890
+ "",
891
+ " insert(table: string) {",
892
+ " return {",
893
+ " values: (data: Record<string, unknown>) => {",
894
+ " const keys = Object.keys(data)",
895
+ " const vals = Object.values(data)",
896
+ ' const placeholders = keys.map(() => "?").join(", ")',
897
+ " const stmt = sqlite.prepare(`INSERT INTO ${" + "table" + "} (${" + "keys.join(', ')" + "}) VALUES (${" + "placeholders" + "}`)",
898
+ " return stmt.run(...vals)",
899
+ " },",
900
+ " }",
901
+ " },",
902
+ "",
903
+ " update(table: string) {",
904
+ " return {",
905
+ " set: (data: Record<string, unknown>) => ({",
906
+ " where: (conditions: Record<string, unknown>) => {",
907
+ " const setKeys = Object.keys(data)",
908
+ " const setVals = Object.values(data)",
909
+ " const whereKeys = Object.keys(conditions)",
910
+ " const whereVals = Object.values(conditions)",
911
+ ' const setClause = setKeys.map(k => k + " = ?").join(", ")',
912
+ ' const whereClause = whereKeys.map(k => k + " = ?").join(" AND ")',
913
+ " const stmt = sqlite.prepare(`UPDATE ${" + "table" + "} SET ${" + "setClause" + "} WHERE ${" + "whereClause" + "}`)",
914
+ " return stmt.run(...setVals, ...whereVals)",
915
+ " },",
916
+ " }),",
917
+ " }",
918
+ " },",
919
+ "",
920
+ " delete(table: string) {",
921
+ " return {",
922
+ " where: (conditions: Record<string, unknown>) => {",
923
+ " const keys = Object.keys(conditions)",
924
+ " const vals = Object.values(conditions)",
925
+ ' const placeholders = keys.map(k => k + " = ?").join(" AND ")',
926
+ " const stmt = sqlite.prepare(`DELETE FROM ${" + "table" + "} WHERE ${" + "placeholders" + "}`)",
927
+ " return { changes: stmt.run(...vals).changes }",
928
+ " },",
929
+ " }",
930
+ " },",
931
+ "}",
932
+ "",
933
+ "}",
934
+ ]
935
+ files.push({
936
+ path: "src/server/database.ts",
937
+ description: "SQLite database connection",
938
+ content: dbLines.join("\n"),
939
+ })
940
+ }
941
+ }
942
+ }
943
+
944
+ function generateTests(
945
+ _graph: KnowledgeGraph,
946
+ entities: EntityNode[],
947
+ _endpoints: EndpointNode[],
948
+ files: GeneratedFile[],
949
+ dirs: Set<string>,
950
+ _stack: TechStack,
951
+ ): void {
952
+ dirs.add("tests")
953
+
954
+ for (const entity of entities) {
955
+ const name = entity.name
956
+ const nameLower = name.toLowerCase()
957
+ const namePlural = `${nameLower}s`
958
+
959
+ files.push({
960
+ path: `tests/${nameLower}.test.ts`,
961
+ description: `${name} API tests`,
962
+ content: `import { describe, test, expect, beforeAll, afterAll } from "bun:test"
963
+
964
+ const API = "http://localhost:3000/api"
965
+
966
+ describe("${name} API", () => {
967
+ let createdId: string
968
+
969
+ test("POST /${namePlural} - creates ${nameLower}", async () => {
970
+ const res = await fetch(\`\${API}/${namePlural}\`, {
971
+ method: "POST",
972
+ headers: { "Content-Type": "application/json" },
973
+ body: JSON.stringify({}),
974
+ })
975
+ expect(res.status).toBe(201)
976
+ const data = await res.json()
977
+ expect(data.id).toBeDefined()
978
+ createdId = data.id
979
+ })
980
+
981
+ test("GET /${namePlural} - lists ${namePlural}", async () => {
982
+ const res = await fetch(\`\${API}/${namePlural}\`)
983
+ expect(res.status).toBe(200)
984
+ const data = await res.json()
985
+ expect(Array.isArray(data)).toBe(true)
986
+ })
987
+
988
+ test("GET /${namePlural}/:id - gets ${nameLower}", async () => {
989
+ const res = await fetch(\`\${API}/${namePlural}/\${createdId}\`)
990
+ expect(res.status).toBe(200)
991
+ const data = await res.json()
992
+ expect(data.id).toBe(createdId)
993
+ })
994
+
995
+ test("PUT /${namePlural}/:id - updates ${nameLower}", async () => {
996
+ const res = await fetch(\`\${API}/${namePlural}/\${createdId}\`, {
997
+ method: "PUT",
998
+ headers: { "Content-Type": "application/json" },
999
+ body: JSON.stringify({}),
1000
+ })
1001
+ expect(res.status).toBe(200)
1002
+ })
1003
+
1004
+ test("DELETE /${namePlural}/:id - deletes ${nameLower}", async () => {
1005
+ const res = await fetch(\`\${API}/${namePlural}/\${createdId}\`, {
1006
+ method: "DELETE",
1007
+ })
1008
+ expect(res.status).toBe(204)
1009
+ })
1010
+
1011
+ test("GET /${namePlural}/:id - returns 404 for deleted", async () => {
1012
+ const res = await fetch(\`\${API}/${namePlural}/\${createdId}\`)
1013
+ expect(res.status).toBe(404)
1014
+ })
1015
+ })
1016
+ `,
1017
+ })
1018
+ }
1019
+ }
1020
+
1021
+ function generateSharedTypes(
1022
+ _graph: KnowledgeGraph,
1023
+ entities: EntityNode[],
1024
+ files: GeneratedFile[],
1025
+ dirs: Set<string>,
1026
+ _stack: TechStack,
1027
+ ): void {
1028
+ dirs.add("src/shared")
1029
+
1030
+ const typeDefs = entities.map(entity => {
1031
+ const fields = entity.metadata.fields || []
1032
+ const fieldDefs = fields.map(f => ` ${f.name}: ${mapToTsType(f.type)}`).join("\n")
1033
+ return `export interface ${entity.name} {
1034
+ id: string
1035
+ ${fieldDefs}
1036
+ created_at: string
1037
+ updated_at: string
1038
+ }`
1039
+ })
1040
+
1041
+ files.push({
1042
+ path: "src/shared/types.ts",
1043
+ description: "Shared type definitions",
1044
+ content: typeDefs.join("\n\n") + "\n",
1045
+ })
1046
+ }
1047
+
1048
+ function mapToTsType(fieldType: string): string {
1049
+ const lower = fieldType.toLowerCase()
1050
+ if (lower === "string" || lower === "text" || lower === "varchar") return "string"
1051
+ if (lower === "number" || lower === "integer" || lower === "int" || lower === "float" || lower === "decimal") return "number"
1052
+ if (lower === "boolean" || lower === "bool") return "boolean"
1053
+ if (lower === "date" || lower === "timestamp" || lower === "datetime") return "string"
1054
+ if (lower === "json" || lower === "object") return "Record<string, unknown>"
1055
+ if (lower === "uuid") return "string"
1056
+ return "string"
1057
+ }
1058
+
1059
+ function mapToSqlType(fieldType: string): string {
1060
+ const lower = fieldType.toLowerCase()
1061
+ if (lower === "string" || lower === "text" || lower === "varchar") return "TEXT"
1062
+ if (lower === "number" || lower === "integer" || lower === "int") return "INTEGER"
1063
+ if (lower === "float" || lower === "decimal") return "REAL"
1064
+ if (lower === "boolean" || lower === "bool") return "INTEGER"
1065
+ if (lower === "date" || lower === "timestamp" || lower === "datetime") return "TEXT"
1066
+ if (lower === "json" || lower === "object") return "TEXT"
1067
+ if (lower === "uuid") return "TEXT"
1068
+ return "TEXT"
1069
+ }
1070
+
1071
+ function buildGenerationSummary(
1072
+ graph: KnowledgeGraph,
1073
+ entities: EntityNode[],
1074
+ features: FeatureNode[],
1075
+ files: GeneratedFile[],
1076
+ stack: TechStack,
1077
+ ): string {
1078
+ const lines = [
1079
+ "## Code Generation Summary",
1080
+ "",
1081
+ `**Project:** ${graph.project_id}`,
1082
+ `**Stack:** ${stack.language} | ${stack.frontend} | ${stack.backend} | ${stack.database}`,
1083
+ "",
1084
+ "### Generated",
1085
+ `- ${files.length} files`,
1086
+ `- ${entities.length} entities`,
1087
+ `- ${features.length} features`,
1088
+ "",
1089
+ "### Files",
1090
+ ]
1091
+
1092
+ for (const f of files) {
1093
+ lines.push(`- \`${f.path}\` — ${f.description}`)
1094
+ }
1095
+
1096
+ return lines.join("\n")
1097
+ }
1098
+
1099
+ export interface GeneratedWriteOptions {
1100
+ /** Existing files are never replaced unless the approved caller opts in. */
1101
+ overwrite?: boolean
1102
+ /** Save a recoverable copy before an approved replacement. */
1103
+ backup?: boolean
1104
+ }
1105
+
1106
+ export interface GeneratedWriteResult {
1107
+ written: number
1108
+ created: number
1109
+ unchanged: number
1110
+ conflicts: string[]
1111
+ backups: string[]
1112
+ errors: string[]
1113
+ }
1114
+
1115
+ /**
1116
+ * Materialize a plan without silently destroying brownfield code. The caller
1117
+ * receives all conflicts and must explicitly request overwrite after review.
1118
+ */
1119
+ export function writeGeneratedFiles(
1120
+ projectDir: string,
1121
+ plan: GenerationPlan,
1122
+ options: GeneratedWriteOptions = {},
1123
+ ): GeneratedWriteResult {
1124
+ let written = 0
1125
+ let created = 0
1126
+ let unchanged = 0
1127
+ const conflicts: string[] = []
1128
+ const backups: string[] = []
1129
+ const errors: string[] = []
1130
+
1131
+ for (const dir of plan.directories) {
1132
+ const fullPath = resolve(projectDir, dir)
1133
+ if (relative(projectDir, fullPath).startsWith("..")) {
1134
+ errors.push(`Refusing to create directory outside target: ${dir}`)
1135
+ continue
1136
+ }
1137
+ if (!existsSync(fullPath)) {
1138
+ try {
1139
+ mkdirSync(fullPath, { recursive: true })
1140
+ } catch (e) {
1141
+ errors.push(`Failed to create directory ${dir}: ${e}`)
1142
+ }
1143
+ }
1144
+ }
1145
+
1146
+ for (const file of plan.files) {
1147
+ const fullPath = resolve(projectDir, file.path)
1148
+ try {
1149
+ if (relative(projectDir, fullPath).startsWith("..")) {
1150
+ errors.push(`Refusing to write outside target: ${file.path}`)
1151
+ continue
1152
+ }
1153
+ const dir = dirname(fullPath)
1154
+ if (!existsSync(dir)) mkdirSync(dir, { recursive: true })
1155
+ if (existsSync(fullPath)) {
1156
+ const current = require("fs").readFileSync(fullPath, "utf-8")
1157
+ if (current === file.content) {
1158
+ unchanged++
1159
+ continue
1160
+ }
1161
+ if (!options.overwrite) {
1162
+ conflicts.push(file.path)
1163
+ continue
1164
+ }
1165
+ if (options.backup !== false) {
1166
+ const backupPath = `${fullPath}.opencode-telos-backup-${Date.now()}`
1167
+ writeFileSync(backupPath, current, "utf-8")
1168
+ backups.push(backupPath)
1169
+ }
1170
+ } else {
1171
+ created++
1172
+ }
1173
+ writeFileSync(fullPath, file.content, "utf-8")
1174
+ written++
1175
+ } catch (e) {
1176
+ errors.push(`Failed to write ${file.path}: ${e}`)
1177
+ }
1178
+ }
1179
+
1180
+ return { written, created, unchanged, conflicts, backups, errors }
1181
+ }