mcp-efficiency-engine 0.1.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 (360) hide show
  1. package/.github/CODEOWNERS +40 -0
  2. package/.github/GITHUB_MCP_INTEGRATION.md +366 -0
  3. package/.github/ISSUE_TEMPLATE/bug.md +51 -0
  4. package/.github/ISSUE_TEMPLATE/feature_request.md +45 -0
  5. package/.github/ISSUE_TEMPLATE/question.md +18 -0
  6. package/.github/agents/backend.agent.md +18 -0
  7. package/.github/agents/community-manager.agent.md +18 -0
  8. package/.github/agents/dba.agent.md +18 -0
  9. package/.github/agents/frontend-agent.agent.md +18 -0
  10. package/.github/agents/github-repository-manager.agent.md +338 -0
  11. package/.github/agents/iot.agent.md +20 -0
  12. package/.github/agents/legacy.agent.md +18 -0
  13. package/.github/agents/rag-azure.agent.md +18 -0
  14. package/.github/agents/rag-local.agent.md +18 -0
  15. package/.github/agents/snapshot.agent.md +18 -0
  16. package/.github/agents/ux-ui.agent.md +18 -0
  17. package/.github/agents/wiki-agent.agent.md +23 -0
  18. package/.github/copilot-instructions.md +44 -0
  19. package/.github/instructions/always-on-optimization.instructions.md +54 -0
  20. package/.github/prompts/auto-route.prompt.md +33 -0
  21. package/.github/prompts/azure-rag.query.prompt.md +19 -0
  22. package/.github/prompts/backend.fix-bug.prompt.md +13 -0
  23. package/.github/prompts/cavecrew.prompt.md +16 -0
  24. package/.github/prompts/caveman-commit.prompt.md +14 -0
  25. package/.github/prompts/caveman-compress.prompt.md +15 -0
  26. package/.github/prompts/caveman-debug.prompt.md +13 -0
  27. package/.github/prompts/caveman-help.prompt.md +11 -0
  28. package/.github/prompts/caveman-review.prompt.md +15 -0
  29. package/.github/prompts/caveman-stats.prompt.md +11 -0
  30. package/.github/prompts/caveman.prompt.md +11 -0
  31. package/.github/prompts/community.post.prompt.md +14 -0
  32. package/.github/prompts/dba.query-review.prompt.md +15 -0
  33. package/.github/prompts/dev.fix-bug.prompt.md +13 -0
  34. package/.github/prompts/frontend.code.prompt.md +13 -0
  35. package/.github/prompts/legacy.impact-analysis.prompt.md +14 -0
  36. package/.github/prompts/project.kickoff-analysis.prompt.md +51 -0
  37. package/.github/prompts/rag.knowledge-answer.prompt.md +13 -0
  38. package/.github/prompts/token-saver-review.prompt.md +14 -0
  39. package/.github/prompts/ux-ui.review.prompt.md +14 -0
  40. package/.github/pull_request_template.md +71 -0
  41. package/.github/skills/ahorro-tokens/SKILL.md +36 -0
  42. package/.github/skills/azure-rag-enterprise/SKILL.md +24 -0
  43. package/.github/skills/backend-coding/SKILL.md +24 -0
  44. package/.github/skills/cavecrew/SKILL.md +17 -0
  45. package/.github/skills/caveman/SKILL.md +25 -0
  46. package/.github/skills/caveman-commit/SKILL.md +15 -0
  47. package/.github/skills/caveman-compress/SKILL.md +14 -0
  48. package/.github/skills/caveman-help/SKILL.md +19 -0
  49. package/.github/skills/caveman-mode/SKILL.md +43 -0
  50. package/.github/skills/caveman-review/SKILL.md +16 -0
  51. package/.github/skills/caveman-stats/SKILL.md +13 -0
  52. package/.github/skills/community-content/SKILL.md +22 -0
  53. package/.github/skills/database-analysis/SKILL.md +23 -0
  54. package/.github/skills/dev-coding/SKILL.md +24 -0
  55. package/.github/skills/frontend-coding/SKILL.md +24 -0
  56. package/.github/skills/human-in-the-loop/SKILL.md +47 -0
  57. package/.github/skills/iot-architecture/SKILL.md +22 -0
  58. package/.github/skills/legacy-migration/SKILL.md +22 -0
  59. package/.github/skills/rag-knowledge/SKILL.md +21 -0
  60. package/.github/skills/token-saver/SKILL.md +36 -0
  61. package/.github/skills/ux-ui-governance/SKILL.md +24 -0
  62. package/.github/skills/wiki-tools.json +24 -0
  63. package/.github/workflows/auto-devlog.yml +56 -0
  64. package/.github/workflows/auto-manage-issues.yml +64 -0
  65. package/.github/workflows/auto-sync.yml +54 -0
  66. package/.github/workflows/autodocs-sync.yml +114 -0
  67. package/.github/workflows/ci.yml +68 -0
  68. package/.github/workflows/pages.yml +59 -0
  69. package/.github/workflows/routing-evals.yml +59 -0
  70. package/.github/workflows/techriders-coverage-effective.yml +91 -0
  71. package/.vscode/mcp.json +44 -0
  72. package/AGENTS.md +160 -0
  73. package/ARCHITECTURE.md +57 -0
  74. package/FINAL_USAGE_GUIDE.md +106 -0
  75. package/LICENSE +21 -0
  76. package/README.md +385 -0
  77. package/README_WIKI.md +130 -0
  78. package/autodocs/README.md +22 -0
  79. package/autodocs/schema/wiki-node.schema.json +56 -0
  80. package/autolearning/feedback-loop.md +90 -0
  81. package/bin/install-host.js +326 -0
  82. package/bin/mcpee.js +116 -0
  83. package/context/repomix/repomix.config.json +20 -0
  84. package/memory/cross-memory-reasoning.md +17 -0
  85. package/memory/mempry-registry.yml +16 -0
  86. package/observability/evals/chat-token-usage-report.json +64 -0
  87. package/observability/evals/chat-token-usage-report.md +33 -0
  88. package/observability/evals/iteration-value-report.json +76 -0
  89. package/observability/evals/iteration-value-report.md +39 -0
  90. package/observability/evals/learning-loop-report.json +268 -0
  91. package/observability/evals/learning-loop-report.md +37 -0
  92. package/observability/evals/repo-intake-eval-cases.md +23 -0
  93. package/observability/evals/routing-eval-cases.json +68 -0
  94. package/observability/evals/routing-eval-cases.md +25 -0
  95. package/observability/evals/routing-eval-report.json +72 -0
  96. package/observability/evaluation.md +34 -0
  97. package/observability/logs/copilot-usage-ingest-report.json +13 -0
  98. package/observability/logs/iteration-metrics.jsonl +75 -0
  99. package/observability/logs/learning-feedback.jsonl +152 -0
  100. package/observability/logs/routing-decisions.jsonl +333 -0
  101. package/observability/logs/session/agent-pipeline-preflight-20260701-004146.log +8 -0
  102. package/observability/logs/session/agent-pipeline-preflight-20260701-005554.log +8 -0
  103. package/observability/logs/session/agent-pipeline-preflight-20260701-010351.log +8 -0
  104. package/observability/logs/session/agent-pipeline-preflight-20260704-145829.log +8 -0
  105. package/observability/logs/session/agent-pipeline-preflight-20260704-150021.log +8 -0
  106. package/observability/logs/session/agent-pipeline-preflight-20260704-154328.log +8 -0
  107. package/observability/logs/session/bye-20260629-221513.json +39 -0
  108. package/observability/logs/session/bye-20260629-221545.json +59 -0
  109. package/observability/logs/session/bye-20260629-222007.json +52 -0
  110. package/observability/logs/session/bye-20260629-222133.json +59 -0
  111. package/observability/logs/session/bye-20260629-222412.json +45 -0
  112. package/observability/logs/session/bye-20260629-223224.json +52 -0
  113. package/observability/logs/session/bye-20260629-224050.json +59 -0
  114. package/observability/logs/session/bye-20260630-105732.json +24 -0
  115. package/observability/logs/session/bye-20260630-211536.json +87 -0
  116. package/observability/logs/session/bye-20260630-223423.json +87 -0
  117. package/observability/logs/session/bye-20260630-232534.json +87 -0
  118. package/observability/logs/session/bye-20260701-003638.json +126 -0
  119. package/observability/logs/session/bye-20260701-003849.json +126 -0
  120. package/observability/logs/session/bye-20260701-004315.json +138 -0
  121. package/observability/logs/session/bye-20260701-004559.json +76 -0
  122. package/observability/logs/session/bye-20260701-005913.json +138 -0
  123. package/observability/logs/session/bye-20260701-010753.json +138 -0
  124. package/observability/logs/session/bye-20260703-194106.json +24 -0
  125. package/observability/logs/session/bye-20260703-233443.json +76 -0
  126. package/observability/logs/session/bye-20260703-233653.json +76 -0
  127. package/observability/logs/session/bye-20260704-150317.json +152 -0
  128. package/observability/logs/session/bye-20260704-150929.json +75 -0
  129. package/observability/logs/session/bye-20260704-151050.json +75 -0
  130. package/observability/logs/session/bye-20260705-115458.json +165 -0
  131. package/observability/logs/session/codegraph-status-20260701-004228.log +39 -0
  132. package/observability/logs/session/codegraph-status-20260701-004310.log +39 -0
  133. package/observability/logs/session/codegraph-status-20260701-005637.log +39 -0
  134. package/observability/logs/session/codegraph-status-20260701-005908.log +39 -0
  135. package/observability/logs/session/codegraph-status-20260701-010444.log +39 -0
  136. package/observability/logs/session/codegraph-status-20260701-010747.log +39 -0
  137. package/observability/logs/session/codegraph-status-20260704-150137.log +26 -0
  138. package/observability/logs/session/codegraph-status-20260704-150313.log +28 -0
  139. package/observability/logs/session/codegraph-status-20260704-154445.log +26 -0
  140. package/observability/logs/session/codegraph-status-20260705-115454.log +27 -0
  141. package/observability/logs/session/codegraph-sync-20260701-004211.log +88 -0
  142. package/observability/logs/session/codegraph-sync-20260701-004241.log +82 -0
  143. package/observability/logs/session/codegraph-sync-20260701-005620.log +89 -0
  144. package/observability/logs/session/codegraph-sync-20260701-005840.log +88 -0
  145. package/observability/logs/session/codegraph-sync-20260701-010419.log +93 -0
  146. package/observability/logs/session/codegraph-sync-20260701-010609.log +90 -0
  147. package/observability/logs/session/codegraph-sync-20260704-145856.log +70 -0
  148. package/observability/logs/session/codegraph-sync-20260704-150047.log +53 -0
  149. package/observability/logs/session/codegraph-sync-20260704-150204.log +44 -0
  150. package/observability/logs/session/codegraph-sync-20260704-154353.log +26 -0
  151. package/observability/logs/session/codegraph-sync-20260705-115337.log +32 -0
  152. package/observability/logs/session/hi-20260629-221459.json +38 -0
  153. package/observability/logs/session/hi-20260629-221945.json +59 -0
  154. package/observability/logs/session/hi-20260629-222108.json +66 -0
  155. package/observability/logs/session/hi-20260629-222352.json +45 -0
  156. package/observability/logs/session/hi-20260629-225719.json +59 -0
  157. package/observability/logs/session/hi-20260629-233722.json +52 -0
  158. package/observability/logs/session/hi-20260629-233913.json +198 -0
  159. package/observability/logs/session/hi-20260630-110156.json +177 -0
  160. package/observability/logs/session/hi-20260630-191243.json +184 -0
  161. package/observability/logs/session/hi-20260630-230050.json +234 -0
  162. package/observability/logs/session/hi-20260630-230523.json +227 -0
  163. package/observability/logs/session/hi-20260630-230855.json +227 -0
  164. package/observability/logs/session/hi-20260630-231638.json +227 -0
  165. package/observability/logs/session/hi-20260630-231756.json +219 -0
  166. package/observability/logs/session/hi-20260701-002842.json +234 -0
  167. package/observability/logs/session/hi-20260701-003458.json +282 -0
  168. package/observability/logs/session/hi-20260701-004233.json +290 -0
  169. package/observability/logs/session/hi-20260701-004554.json +236 -0
  170. package/observability/logs/session/hi-20260701-005641.json +290 -0
  171. package/observability/logs/session/hi-20260701-010450.json +290 -0
  172. package/observability/logs/session/hi-20260703-233854.json +312 -0
  173. package/observability/logs/session/hi-20260703-234448.json +318 -0
  174. package/observability/logs/session/hi-20260704-145907.json +353 -0
  175. package/observability/logs/session/hi-20260704-150141.json +392 -0
  176. package/observability/logs/session/hi-20260704-154448.json +392 -0
  177. package/observability/logs/session/iteration-value-refresh-20260701-004309.log +3 -0
  178. package/observability/logs/session/iteration-value-refresh-20260701-005907.log +3 -0
  179. package/observability/logs/session/iteration-value-refresh-20260701-010747.log +3 -0
  180. package/observability/logs/session/iteration-value-refresh-20260704-150312.log +3 -0
  181. package/observability/logs/session/iteration-value-refresh-20260705-115453.log +3 -0
  182. package/observability/logs/session/learning-loop-refresh-20260701-004309.log +3 -0
  183. package/observability/logs/session/learning-loop-refresh-20260701-005906.log +3 -0
  184. package/observability/logs/session/learning-loop-refresh-20260701-010745.log +3 -0
  185. package/observability/logs/session/learning-loop-refresh-20260704-150309.log +3 -0
  186. package/observability/logs/session/learning-loop-refresh-20260705-115450.log +3 -0
  187. package/observability/logs/session/project-notes-refresh-20260701-004227.log +1 -0
  188. package/observability/logs/session/project-notes-refresh-20260701-004308.log +1 -0
  189. package/observability/logs/session/project-notes-refresh-20260701-005636.log +1 -0
  190. package/observability/logs/session/project-notes-refresh-20260701-005906.log +1 -0
  191. package/observability/logs/session/project-notes-refresh-20260701-010443.log +1 -0
  192. package/observability/logs/session/project-notes-refresh-20260701-010744.log +1 -0
  193. package/observability/logs/session/project-notes-refresh-20260704-150133.log +1 -0
  194. package/observability/logs/session/project-notes-refresh-20260704-150309.log +1 -0
  195. package/observability/logs/session/project-notes-refresh-20260704-154442.log +1 -0
  196. package/observability/logs/session/project-notes-refresh-20260705-115449.log +1 -0
  197. package/observability/logs/session/repo-intake-20260701-004218.log +6 -0
  198. package/observability/logs/session/repo-intake-20260701-005626.log +6 -0
  199. package/observability/logs/session/repo-intake-20260701-010433.log +6 -0
  200. package/observability/logs/session/repo-intake-20260704-150053.log +6 -0
  201. package/observability/logs/session/repo-intake-20260704-154404.log +6 -0
  202. package/observability/logs/session/repo-intake-refresh-20260701-004247.log +6 -0
  203. package/observability/logs/session/repo-intake-refresh-20260701-005847.log +6 -0
  204. package/observability/logs/session/repo-intake-refresh-20260701-010615.log +6 -0
  205. package/observability/logs/session/repo-intake-refresh-20260704-150209.log +6 -0
  206. package/observability/logs/session/repo-intake-refresh-20260705-115342.log +6 -0
  207. package/observability/logs/session/repo-registry-validation-20260701-004234.log +2 -0
  208. package/observability/logs/session/repo-registry-validation-20260701-004556.log +2 -0
  209. package/observability/logs/session/repo-registry-validation-20260701-005833.log +2 -0
  210. package/observability/logs/session/repo-registry-validation-20260701-010601.log +2 -0
  211. package/observability/logs/session/repo-registry-validation-20260704-150155.log +2 -0
  212. package/observability/logs/session/repo-registry-validation-20260705-115323.log +2 -0
  213. package/observability/logs/session/repomix-refresh-20260701-003823.log +4236 -0
  214. package/observability/logs/session/repomix-refresh-20260701-004251.log +4275 -0
  215. package/observability/logs/session/repomix-refresh-20260701-005850.log +4248 -0
  216. package/observability/logs/session/repomix-refresh-20260701-010619.log +6531 -0
  217. package/observability/logs/session/repomix-refresh-20260704-150239.log +652 -0
  218. package/observability/logs/session/repomix-refresh-20260705-115419.log +178 -0
  219. package/observability/logs/session/routing-evals-20260701-004221.log +2 -0
  220. package/observability/logs/session/routing-evals-20260701-004235.log +2 -0
  221. package/observability/logs/session/routing-evals-20260701-005629.log +2 -0
  222. package/observability/logs/session/routing-evals-20260701-005834.log +2 -0
  223. package/observability/logs/session/routing-evals-20260701-010437.log +2 -0
  224. package/observability/logs/session/routing-evals-20260701-010603.log +2 -0
  225. package/observability/logs/session/routing-evals-20260704-150125.log +2 -0
  226. package/observability/logs/session/routing-evals-20260704-150157.log +2 -0
  227. package/observability/logs/session/routing-evals-20260704-154434.log +2 -0
  228. package/observability/logs/session/routing-evals-20260705-115327.log +2 -0
  229. package/observability/logs/session/sibling-discovery-refresh-20260701-004250.log +3 -0
  230. package/observability/logs/session/sibling-discovery-refresh-20260701-005850.log +3 -0
  231. package/observability/logs/session/sibling-discovery-refresh-20260701-010618.log +3 -0
  232. package/observability/logs/session/sibling-discovery-refresh-20260704-150238.log +3 -0
  233. package/observability/logs/session/sibling-discovery-refresh-20260705-115418.log +3 -0
  234. package/observability/logs.schema.json +95 -0
  235. package/observability/logs.schema.md +26 -0
  236. package/observability/metrics.md +35 -0
  237. package/observability/routing-evaluator.md +37 -0
  238. package/observability/scoring-rubric.md +38 -0
  239. package/optimization/ALWAYS_ON_OPTIMIZATION.md +98 -0
  240. package/optimization/caveman-mode.md +62 -0
  241. package/optimization/examples/login-bug.md +25 -0
  242. package/optimization/examples/sla-query.md +25 -0
  243. package/optimization/optimization-routing.md +30 -0
  244. package/optimization/policies/response-style.policy.md +45 -0
  245. package/optimization/policies/token-budget.policy.md +28 -0
  246. package/optimization/profiles/always-on.profile.md +19 -0
  247. package/optimization/profiles/architecture.profile.md +20 -0
  248. package/optimization/profiles/debug.profile.md +20 -0
  249. package/optimization/profiles/enterprise-rag.profile.md +20 -0
  250. package/optimization/profiles/training.profile.md +20 -0
  251. package/optimization/token-saver.md +58 -0
  252. package/orchestrator/corporate-routing.md +51 -0
  253. package/orchestrator/decision-matrix.md +33 -0
  254. package/orchestrator/fallback.md +29 -0
  255. package/orchestrator/repo-routing.md +58 -0
  256. package/orchestrator/router.md +75 -0
  257. package/orchestrator/wiki/__init__.py +5 -0
  258. package/orchestrator/wiki/graph_consolidator.py +506 -0
  259. package/orchestrator/wiki/incremental_engine.py +57 -0
  260. package/orchestrator/wiki/plugin_manager.py +40 -0
  261. package/package.json +70 -0
  262. package/policies/context-policy.md +25 -0
  263. package/policies/cost-policy.md +25 -0
  264. package/policies/repo-intake-policy.md +36 -0
  265. package/policies/security-policy.md +25 -0
  266. package/repo-intake/README.md +81 -0
  267. package/repo-intake/templates/agent.template.md +4 -0
  268. package/repo-intake/templates/context-manifest.template.md +4 -0
  269. package/repo-intake/templates/skill.template.md +3 -0
  270. package/repo-registry/repos.schema.json +102 -0
  271. package/repo-registry/repos.template.json +26 -0
  272. package/requirements.txt +1 -0
  273. package/scripts/README.md +109 -0
  274. package/scripts/__init__.py +0 -0
  275. package/scripts/bootstrap-portable.cmd +4 -0
  276. package/scripts/bootstrap-portable.ps1 +90 -0
  277. package/scripts/context/azure-rag-mcp-adapter.py +1 -0
  278. package/scripts/context/build-graphify.ps1 +1 -0
  279. package/scripts/context/build-repomix.ps1 +1 -0
  280. package/scripts/discovery/discover-boost-repos.cmd +4 -0
  281. package/scripts/discovery/discover-boost-repos.py +186 -0
  282. package/scripts/discovery/refresh-project-notes.py +179 -0
  283. package/scripts/github/INSTALL.md +295 -0
  284. package/scripts/github/README.md +455 -0
  285. package/scripts/github/apply-boost-templates.ps1 +163 -0
  286. package/scripts/github/apply-single-repo.ps1 +85 -0
  287. package/scripts/github/create-devlog.ps1 +380 -0
  288. package/scripts/github/manage-issues.ps1 +332 -0
  289. package/scripts/github/sync-repo.ps1 +267 -0
  290. package/scripts/intake/agent-pipeline-preflight.py +151 -0
  291. package/scripts/intake/init-template-registry.cmd +4 -0
  292. package/scripts/intake/init-template-registry.ps1 +258 -0
  293. package/scripts/intake/repo-intake.py +354 -0
  294. package/scripts/intake/resolve-routing.py +620 -0
  295. package/scripts/intake/run-repo-intake.cmd +4 -0
  296. package/scripts/intake/run-repo-intake.ps1 +46 -0
  297. package/scripts/intake/run-routing-evals.py +147 -0
  298. package/scripts/intake/validate-database-routing.py +91 -0
  299. package/scripts/intake/validate-rag-routing.py +85 -0
  300. package/scripts/intake/validate-repo-registry.ps1 +20 -0
  301. package/scripts/intake/validate-repo-registry.py +286 -0
  302. package/scripts/intake/validate-security.py +170 -0
  303. package/scripts/learning/autolearning-gate.py +71 -0
  304. package/scripts/learning/chat-token-usage-report.py +326 -0
  305. package/scripts/learning/ingest-copilot-session-usage.py +421 -0
  306. package/scripts/learning/iteration-value-report.py +275 -0
  307. package/scripts/learning/learning-loop-report.py +272 -0
  308. package/scripts/learning/record-iteration-metrics.py +116 -0
  309. package/scripts/learning/record-learning-feedback.py +91 -0
  310. package/scripts/ops/bye.ps1 +620 -0
  311. package/scripts/ops/compare-demo-results.ps1 +826 -0
  312. package/scripts/ops/demo1.ps1 +11 -0
  313. package/scripts/ops/demo2.ps1 +11 -0
  314. package/scripts/ops/demo3.ps1 +11 -0
  315. package/scripts/ops/demo4.ps1 +11 -0
  316. package/scripts/ops/hi.ps1 +1045 -0
  317. package/scripts/ops/llm-token-probe.py +164 -0
  318. package/scripts/ops/run-all-demos.ps1 +39 -0
  319. package/scripts/ops/run-demo-block.ps1 +85 -0
  320. package/scripts/ops/run-demo-session.ps1 +532 -0
  321. package/scripts/setup/optimize-engines.ps1 +183 -0
  322. package/scripts/setup/setup-codegraph.ps1 +3 -0
  323. package/scripts/setup/setup-gitnexus.ps1 +3 -0
  324. package/scripts/setup/setup-graphify.ps1 +2 -0
  325. package/scripts/setup/setup-prerequisites.ps1 +205 -0
  326. package/scripts/setup/start-gitnexus.ps1 +71 -0
  327. package/scripts/setup/validate-context.ps1 +361 -0
  328. package/scripts/wiki/__init__.py +0 -0
  329. package/scripts/wiki/compiler_main.py +189 -0
  330. package/scripts/wiki/normalizer.py +206 -0
  331. package/scripts/wiki/providers/base_provider.py +25 -0
  332. package/scripts/wiki/providers/codegraph_provider.py +49 -0
  333. package/scripts/wiki/providers/graphify_provider.py +49 -0
  334. package/scripts/wiki/providers/repo_content_provider.py +408 -0
  335. package/scripts/wiki/query_autodocs.py +60 -0
  336. package/scripts/wiki/validator.py +183 -0
  337. package/scripts/wiki/wiki_compiler.py +5 -0
  338. package/specs/architecture.spec.md +32 -0
  339. package/specs/azure-rag.spec.md +28 -0
  340. package/specs/coding-standards.spec.md +24 -0
  341. package/specs/database.spec.md +29 -0
  342. package/specs/migration.spec.md +26 -0
  343. package/specs/observability.spec.md +24 -0
  344. package/specs/optimization.spec.md +31 -0
  345. package/specs/rag.spec.md +30 -0
  346. package/specs/repo-intake.spec.md +25 -0
  347. package/specs/routing.spec.md +24 -0
  348. package/specs/security.spec.md +30 -0
  349. package/specs/wiki/provider-contract.json +33 -0
  350. package/specs/wiki/unified-knowledge-graph.json +25 -0
  351. package/templates/BOOST_README_TEMPLATE.md +96 -0
  352. package/templates/CODEOWNERS_TEMPLATE.txt +29 -0
  353. package/templates/LICENSE_MIT_TEMPLATE.txt +21 -0
  354. package/templates/PERSONAL_README_TEMPLATE.md +90 -0
  355. package/templates/README_boost_RAG_Azure.md +46 -0
  356. package/templates/README_boost_azure_iot_edge.md +48 -0
  357. package/templates/README_boost_backend.md +47 -0
  358. package/templates/README_boost_dba.md +57 -0
  359. package/templates/ci.yml.template +73 -0
  360. package/tooling/tooling.manifest.json +72 -0
@@ -0,0 +1,147 @@
1
+ from __future__ import annotations
2
+
3
+ import argparse
4
+ import json
5
+ import subprocess
6
+ import sys
7
+ from datetime import datetime, timezone
8
+ from pathlib import Path
9
+ from typing import Any
10
+
11
+
12
+ def utc_now() -> str:
13
+ return datetime.now(timezone.utc).isoformat()
14
+
15
+
16
+ def load_cases(path: Path) -> list[dict[str, Any]]:
17
+ data = json.loads(path.read_text(encoding="utf-8"))
18
+ cases = data.get("cases", [])
19
+ if not isinstance(cases, list):
20
+ return []
21
+ return [c for c in cases if isinstance(c, dict)]
22
+
23
+
24
+ def parse_event_ids(path: Path) -> set[str]:
25
+ if not path.exists():
26
+ return set()
27
+ ids: set[str] = set()
28
+ for line in path.read_text(encoding="utf-8").splitlines():
29
+ line = line.strip()
30
+ if not line:
31
+ continue
32
+ try:
33
+ obj = json.loads(line)
34
+ except Exception:
35
+ continue
36
+ if not isinstance(obj, dict):
37
+ continue
38
+ event_id = str(obj.get("event_id", "")).strip()
39
+ if event_id:
40
+ ids.add(event_id)
41
+ return ids
42
+
43
+
44
+ def run_case(repo_root: Path, case: dict[str, Any], routing_log: Path) -> tuple[bool, str, str | None]:
45
+ before_ids = parse_event_ids(routing_log)
46
+ cmd = [
47
+ sys.executable,
48
+ str((repo_root / "scripts/intake/resolve-routing.py").resolve()),
49
+ "--input",
50
+ str(case.get("input", "")),
51
+ "--intent",
52
+ str(case.get("intent", "")),
53
+ "--domain",
54
+ str(case.get("domain", "")),
55
+ "--source-type",
56
+ str(case.get("source_type", "technical-docs")),
57
+ "--capability",
58
+ str(case.get("capability", "")),
59
+ ]
60
+ proc = subprocess.run(cmd, cwd=str(repo_root), capture_output=True, text=True)
61
+ output = (proc.stdout or "") + (proc.stderr or "")
62
+
63
+ event_id: str | None = None
64
+ after_ids = parse_event_ids(routing_log)
65
+ new_ids = after_ids - before_ids
66
+ if new_ids:
67
+ event_id = sorted(new_ids)[-1]
68
+
69
+ return proc.returncode == 0, output, event_id
70
+
71
+
72
+ def record_feedback(repo_root: Path, event_id: str, case_id: str) -> tuple[bool, str]:
73
+ cmd = [
74
+ sys.executable,
75
+ str((repo_root / "scripts/learning/record-learning-feedback.py").resolve()),
76
+ "--event-id",
77
+ event_id,
78
+ "--success",
79
+ "true",
80
+ "--confidence",
81
+ "0.95",
82
+ "--source",
83
+ "ci",
84
+ "--notes",
85
+ f"routing-eval-pass:{case_id}",
86
+ ]
87
+ proc = subprocess.run(cmd, cwd=str(repo_root), capture_output=True, text=True)
88
+ output = (proc.stdout or "") + (proc.stderr or "")
89
+ return proc.returncode == 0, output
90
+
91
+
92
+ def main() -> int:
93
+ parser = argparse.ArgumentParser(description="Run routing eval cases and write JSON report.")
94
+ parser.add_argument("--cases", default="observability/evals/routing-eval-cases.json")
95
+ parser.add_argument("--report", default="observability/evals/routing-eval-report.json")
96
+ args = parser.parse_args()
97
+
98
+ repo_root = Path(__file__).resolve().parents[2]
99
+ routing_log = (repo_root / "observability/logs/routing-decisions.jsonl").resolve()
100
+ cases_path = (repo_root / args.cases).resolve()
101
+ if not cases_path.exists():
102
+ print(f"Missing eval cases file: {cases_path}")
103
+ return 1
104
+
105
+ cases = load_cases(cases_path)
106
+ results: list[dict[str, Any]] = []
107
+ passed = 0
108
+
109
+ for case in cases:
110
+ ok, output, event_id = run_case(repo_root, case, routing_log)
111
+ feedback_ok = False
112
+ feedback_output = ""
113
+ case_id = str(case.get("id", "unknown"))
114
+
115
+ if ok and event_id:
116
+ feedback_ok, feedback_output = record_feedback(repo_root, event_id, case_id)
117
+ if ok:
118
+ passed += 1
119
+ results.append(
120
+ {
121
+ "id": case_id,
122
+ "ok": ok,
123
+ "event_id": event_id,
124
+ "feedback_recorded": feedback_ok,
125
+ "feedback_output": feedback_output,
126
+ "output": output,
127
+ }
128
+ )
129
+
130
+ report = {
131
+ "timestamp": utc_now(),
132
+ "cases_total": len(cases),
133
+ "cases_passed": passed,
134
+ "cases_failed": len(cases) - passed,
135
+ "results": results,
136
+ }
137
+ report_path = (repo_root / args.report).resolve()
138
+ report_path.parent.mkdir(parents=True, exist_ok=True)
139
+ report_path.write_text(json.dumps(report, indent=2, ensure_ascii=False) + "\n", encoding="utf-8")
140
+
141
+ print(f"Routing evals completed: {passed}/{len(cases)} passed")
142
+ print(f"Report: {report_path}")
143
+ return 0 if passed == len(cases) else 1
144
+
145
+
146
+ if __name__ == "__main__":
147
+ raise SystemExit(main())
@@ -0,0 +1,91 @@
1
+ from __future__ import annotations
2
+
3
+ """Validate database routing spec requirements.
4
+
5
+ Assertions:
6
+ 1. intent=sql with domain=dba selects agent=dba.
7
+ 2. An event with no resolvable source declares grounded=false.
8
+
9
+ Exit 0 = pass. Exit 1 = fail.
10
+ """
11
+
12
+ import json
13
+ import subprocess
14
+ import sys
15
+ from pathlib import Path
16
+
17
+ REPO_ROOT = Path(__file__).resolve().parents[2]
18
+ RESOLVE_SCRIPT = REPO_ROOT / "scripts" / "intake" / "resolve-routing.py"
19
+
20
+
21
+ def run_routing(**kwargs: str) -> dict:
22
+ cmd = [sys.executable, str(RESOLVE_SCRIPT)]
23
+ for k, v in kwargs.items():
24
+ cmd += [f"--{k.replace('_', '-')}", v]
25
+ # Use utf-8 encoding and errors='replace' to handle non-ASCII chars
26
+ proc = subprocess.run(
27
+ cmd,
28
+ cwd=str(REPO_ROOT),
29
+ capture_output=True,
30
+ text=True,
31
+ encoding="utf-8",
32
+ errors="replace"
33
+ )
34
+ # Output contains a JSON block followed by a trailing log line; extract JSON.
35
+ stdout = proc.stdout or ""
36
+ brace = stdout.find("{")
37
+ last_brace = stdout.rfind("}")
38
+ if brace == -1 or last_brace == -1:
39
+ raise ValueError(f"No JSON in output: {stdout[:200]}")
40
+ return json.loads(stdout[brace : last_brace + 1])
41
+
42
+
43
+ def main() -> int:
44
+ errors: list[str] = []
45
+ print("=== validate-database-routing ===")
46
+
47
+ # --- Assertion 1: intent=sql routes to dba ---
48
+ try:
49
+ event = run_routing(
50
+ input="analiza esquema sql",
51
+ intent="sql",
52
+ domain="dba",
53
+ source_type="technical-docs",
54
+ )
55
+ agent = event.get("agent", "")
56
+ if agent != "dba":
57
+ errors.append(f"[FAIL] intent=sql expected agent=dba, got agent={agent!r}")
58
+ else:
59
+ print(f"[OK] intent=sql → agent={agent}")
60
+ except Exception as exc:
61
+ errors.append(f"[FAIL] routing error for intent=sql: {exc}")
62
+
63
+ # --- Assertion 2: no resolvable source → grounded=false ---
64
+ try:
65
+ event = run_routing(
66
+ input="test grounding",
67
+ intent="info",
68
+ domain="unknown-domain",
69
+ source_type="code",
70
+ )
71
+ grounded = event.get("grounded")
72
+ if grounded is not False:
73
+ errors.append(f"[FAIL] no-source event expected grounded=false, got grounded={grounded!r}")
74
+ else:
75
+ print("[OK] no-source event → grounded=false")
76
+ except Exception as exc:
77
+ errors.append(f"[FAIL] routing error for grounded check: {exc}")
78
+
79
+ print()
80
+ if errors:
81
+ for e in errors:
82
+ print(e)
83
+ print(f"validate-database-routing FAILED: {len(errors)} issue(s)")
84
+ return 1
85
+
86
+ print("validate-database-routing PASSED")
87
+ return 0
88
+
89
+
90
+ if __name__ == "__main__":
91
+ raise SystemExit(main())
@@ -0,0 +1,85 @@
1
+ from __future__ import annotations
2
+
3
+ """Validate RAG local routing spec requirements.
4
+
5
+ Assertions:
6
+ 1. domain=rag with source_type=technical-docs selects agent=rag-local.
7
+ 2. The routing event declares grounded=true with explicit sources from the repo.
8
+
9
+ Exit 0 = pass. Exit 1 = fail.
10
+ """
11
+
12
+ import json
13
+ import subprocess
14
+ import sys
15
+ from pathlib import Path
16
+
17
+ REPO_ROOT = Path(__file__).resolve().parents[2]
18
+ RESOLVE_SCRIPT = REPO_ROOT / "scripts" / "intake" / "resolve-routing.py"
19
+
20
+
21
+ def run_routing(**kwargs: str) -> dict:
22
+ cmd = [sys.executable, str(RESOLVE_SCRIPT)]
23
+ for k, v in kwargs.items():
24
+ cmd += [f"--{k.replace('_', '-')}", v]
25
+ # Use utf-8 encoding and errors='replace' to handle non-ASCII chars
26
+ proc = subprocess.run(
27
+ cmd,
28
+ cwd=str(REPO_ROOT),
29
+ capture_output=True,
30
+ text=True,
31
+ encoding="utf-8",
32
+ errors="replace"
33
+ )
34
+ stdout = proc.stdout or ""
35
+ brace = stdout.find("{")
36
+ last_brace = stdout.rfind("}")
37
+ if brace == -1 or last_brace == -1:
38
+ raise ValueError(f"No JSON in output: {stdout[:200]}")
39
+ return json.loads(stdout[brace : last_brace + 1])
40
+
41
+
42
+ def main() -> int:
43
+ errors: list[str] = []
44
+ print("=== validate-rag-routing ===")
45
+
46
+ # --- Assertion 1: rag domain + technical-docs → rag-local ---
47
+ try:
48
+ event = run_routing(
49
+ input="explica guia tecnica local",
50
+ intent="info",
51
+ domain="rag",
52
+ source_type="technical-docs",
53
+ )
54
+ agent = event.get("agent", "")
55
+ if agent != "rag-local":
56
+ errors.append(f"[FAIL] expected agent=rag-local, got agent={agent!r}")
57
+ else:
58
+ print(f"[OK] domain=rag + technical-docs → agent={agent}")
59
+
60
+ # --- Assertion 2: grounded=true with explicit sources ---
61
+ grounded = event.get("grounded")
62
+ sources = event.get("sources", [])
63
+ if not grounded:
64
+ errors.append(f"[FAIL] rag-local event expected grounded=true, got grounded={grounded!r}")
65
+ elif not sources:
66
+ errors.append("[FAIL] rag-local event grounded=true but sources list is empty")
67
+ else:
68
+ print(f"[OK] grounded=true with sources: {sources}")
69
+
70
+ except Exception as exc:
71
+ errors.append(f"[FAIL] routing error: {exc}")
72
+
73
+ print()
74
+ if errors:
75
+ for e in errors:
76
+ print(e)
77
+ print(f"validate-rag-routing FAILED: {len(errors)} issue(s)")
78
+ return 1
79
+
80
+ print("validate-rag-routing PASSED")
81
+ return 0
82
+
83
+
84
+ if __name__ == "__main__":
85
+ raise SystemExit(main())
@@ -0,0 +1,20 @@
1
+ param(
2
+ [string]$RegistryPath = "repo-registry/repos.yml",
3
+ [switch]$Strict
4
+ )
5
+
6
+ Set-StrictMode -Version Latest
7
+ $ErrorActionPreference = "Stop"
8
+
9
+ $repoRoot = (Resolve-Path (Join-Path $PSScriptRoot '..\..')).Path
10
+ Set-Location $repoRoot
11
+
12
+ $args = @(".\scripts\intake\validate-repo-registry.py", "--registry", $RegistryPath)
13
+ if ($Strict) {
14
+ $args += "--strict"
15
+ }
16
+
17
+ python @args
18
+ if ($LASTEXITCODE -ne 0) {
19
+ exit $LASTEXITCODE
20
+ }
@@ -0,0 +1,286 @@
1
+ from __future__ import annotations
2
+
3
+ import argparse
4
+ import json
5
+ import re
6
+ import subprocess
7
+ from dataclasses import dataclass
8
+ from datetime import datetime, timezone
9
+ from pathlib import Path
10
+ from typing import Any
11
+
12
+ try:
13
+ import yaml # type: ignore
14
+ except Exception:
15
+ yaml = None
16
+
17
+
18
+ def utc_now() -> str:
19
+ return datetime.now(timezone.utc).isoformat()
20
+
21
+
22
+ def parse_simple_yml(path: Path) -> dict[str, Any]:
23
+ repos: list[dict[str, Any]] = []
24
+ current: dict[str, Any] | None = None
25
+ for line in path.read_text(encoding="utf-8").splitlines():
26
+ st = line.strip()
27
+ if st.startswith("- name:"):
28
+ if current:
29
+ repos.append(current)
30
+ current = {"name": st.split(":", 1)[1].strip()}
31
+ elif current and ":" in st and not st.startswith("#"):
32
+ k, v = st.split(":", 1)
33
+ k = k.strip()
34
+ v = v.strip().strip('"')
35
+ if k in {"domain", "location", "type", "repo_url", "branch", "cache_location"}:
36
+ current[k] = v
37
+ if current:
38
+ repos.append(current)
39
+ return {"schema_version": "1.0", "repos": repos}
40
+
41
+
42
+ def load_registry(path: Path) -> dict[str, Any]:
43
+ content = path.read_text(encoding="utf-8")
44
+
45
+ # JSON-first support (JSON is valid YAML, but this path avoids extra deps).
46
+ if content.lstrip().startswith("{"):
47
+ return json.loads(content)
48
+
49
+ if yaml is not None:
50
+ data = yaml.safe_load(content) or {}
51
+ if isinstance(data, dict):
52
+ return data
53
+
54
+ return parse_simple_yml(path)
55
+
56
+
57
+ @dataclass
58
+ class ValidationResult:
59
+ errors: list[str]
60
+ warnings: list[str]
61
+
62
+
63
+ def command_exists(name: str) -> bool:
64
+ try:
65
+ completed = subprocess.run(
66
+ [name, "--version"],
67
+ check=False,
68
+ capture_output=True,
69
+ text=True,
70
+ )
71
+ except OSError:
72
+ return False
73
+ return completed.returncode == 0
74
+
75
+
76
+ def validate(registry: dict[str, Any], strict: bool, repo_root: Path) -> ValidationResult:
77
+ errors: list[str] = []
78
+ warnings: list[str] = []
79
+
80
+ registry_mode = str(registry.get("registry_mode", "enterprise")).strip().lower() or "enterprise"
81
+ repos = registry.get("repos")
82
+ if not isinstance(repos, list):
83
+ return ValidationResult(errors=["Registry must define a repos list."], warnings=[])
84
+
85
+ if not repos:
86
+ if strict or registry_mode != "template":
87
+ return ValidationResult(errors=["Registry must define a non-empty repos list."], warnings=[])
88
+ warnings.append("Template registry has no repos yet.")
89
+ return ValidationResult(errors=[], warnings=warnings)
90
+
91
+ schema_version = str(registry.get("schema_version", "1.0"))
92
+ is_v2 = schema_version >= "2.0"
93
+ governance = registry.get("governance", {}) if isinstance(registry.get("governance", {}), dict) else {}
94
+ repo_name_prefix = str(governance.get("repo_name_prefix", "boost_")).strip() or "boost_"
95
+
96
+ names: set[str] = set()
97
+ graph: dict[str, list[str]] = {}
98
+
99
+ for repo in repos:
100
+ if not isinstance(repo, dict):
101
+ errors.append("Each repo entry must be an object.")
102
+ continue
103
+
104
+ name = str(repo.get("name", "")).strip()
105
+ if not name:
106
+ errors.append("Repo is missing required field: name")
107
+ continue
108
+
109
+ if strict or is_v2:
110
+ if not name.startswith(repo_name_prefix):
111
+ errors.append(
112
+ f"Repo '{name}' does not satisfy naming contract. Expected prefix '{repo_name_prefix}'."
113
+ )
114
+
115
+ if name in names:
116
+ errors.append(f"Duplicate repo name: {name}")
117
+ continue
118
+ names.add(name)
119
+
120
+ for field in ("domain", "type"):
121
+ if not str(repo.get(field, "")).strip():
122
+ errors.append(f"Repo '{name}' is missing required field: {field}")
123
+
124
+ repo_type = str(repo.get("type", "")).strip().lower()
125
+ if repo_type not in {"local", "github"}:
126
+ errors.append(f"Repo '{name}' type must be 'local' or 'github'.")
127
+
128
+ location = str(repo.get("location", "")).strip()
129
+ if repo_type == "local":
130
+ if not location:
131
+ errors.append(f"Repo '{name}' is missing required field: location")
132
+ elif location:
133
+ resolved = (repo_root / location).resolve()
134
+ if not resolved.exists():
135
+ if bool(repo.get("optional", False)):
136
+ warnings.append(f"Optional repo '{name}' location does not exist: {location}")
137
+ else:
138
+ errors.append(f"Repo '{name}' location does not exist: {location}")
139
+ elif repo_type == "github":
140
+ repo_url = str(repo.get("repo_url", "")).strip()
141
+ if not repo_url:
142
+ errors.append(f"Repo '{name}' is missing required field: repo_url")
143
+ elif not re.match(r"^https://github\.com/[^/]+/[^/]+(?:\.git)?$", repo_url):
144
+ errors.append(f"Repo '{name}' repo_url must be a valid https GitHub repository URL.")
145
+ branch = str(repo.get("branch", "")).strip()
146
+ if branch and not re.match(r"^[A-Za-z0-9._\/-]+$", branch):
147
+ errors.append(f"Repo '{name}' branch contains invalid characters: {branch}")
148
+ cache_location = str(repo.get("cache_location", "")).strip()
149
+ if cache_location:
150
+ cache_resolved = (repo_root / cache_location).resolve()
151
+ cache_parent = cache_resolved.parent
152
+ if not cache_parent.exists():
153
+ warnings.append(f"GitHub repo '{name}' cache parent does not exist yet: {cache_parent}")
154
+ if strict and not command_exists("git"):
155
+ errors.append(f"Repo '{name}' requires git command for type 'github'.")
156
+
157
+ deps = repo.get("dependencies", [])
158
+ dep_refs: list[str] = []
159
+ if deps:
160
+ if not isinstance(deps, list):
161
+ errors.append(f"Repo '{name}' dependencies must be a list.")
162
+ else:
163
+ for dep in deps:
164
+ if not isinstance(dep, dict) or not str(dep.get("ref", "")).strip():
165
+ errors.append(f"Repo '{name}' has a dependency without ref.")
166
+ continue
167
+ dep_refs.append(str(dep["ref"]))
168
+ graph[name] = dep_refs
169
+
170
+ if strict or is_v2:
171
+ approval = repo.get("approval")
172
+ if not isinstance(approval, dict):
173
+ errors.append(f"Repo '{name}' requires approval block in v2/strict mode.")
174
+ else:
175
+ if approval.get("status") != "approved":
176
+ errors.append(f"Repo '{name}' is not approved (approval.status must be 'approved').")
177
+ if not str(approval.get("approved_by", "")).strip():
178
+ errors.append(f"Repo '{name}' missing approval.approved_by")
179
+ if not str(approval.get("approved_date", "")).strip():
180
+ errors.append(f"Repo '{name}' missing approval.approved_date")
181
+ if not str(approval.get("review_ticket", "")).strip():
182
+ warnings.append(f"Repo '{name}' missing approval.review_ticket")
183
+
184
+ for src, dep_refs in graph.items():
185
+ for dep in dep_refs:
186
+ if dep not in names:
187
+ errors.append(f"Repo '{src}' depends on unknown repo '{dep}'.")
188
+
189
+ # Cycle detection via DFS colors: 0=unseen, 1=visiting, 2=done
190
+ state: dict[str, int] = {name: 0 for name in names}
191
+
192
+ def visit(node: str) -> None:
193
+ if state[node] == 1:
194
+ errors.append(f"Dependency cycle detected at '{node}'.")
195
+ return
196
+ if state[node] == 2:
197
+ return
198
+ state[node] = 1
199
+ for nxt in graph.get(node, []):
200
+ if nxt in state:
201
+ visit(nxt)
202
+ state[node] = 2
203
+
204
+ for name in names:
205
+ visit(name)
206
+
207
+ return ValidationResult(errors=errors, warnings=warnings)
208
+
209
+
210
+ def write_report(
211
+ path: Path,
212
+ registry_path: Path,
213
+ registry_mode: str,
214
+ schema_version: str,
215
+ strict: bool,
216
+ result: ValidationResult,
217
+ repos_count: int,
218
+ ) -> None:
219
+ report = {
220
+ "timestamp": utc_now(),
221
+ "registry_path": str(registry_path).replace("\\", "/"),
222
+ "registry_mode": str(registry_mode),
223
+ "schema_version": schema_version,
224
+ "strict_mode": strict,
225
+ "repos_count": repos_count,
226
+ "errors_count": len(result.errors),
227
+ "warnings_count": len(result.warnings),
228
+ "errors": result.errors,
229
+ "warnings": result.warnings,
230
+ }
231
+ path.parent.mkdir(parents=True, exist_ok=True)
232
+ path.write_text(json.dumps(report, indent=2, ensure_ascii=False) + "\n", encoding="utf-8")
233
+
234
+
235
+ def main() -> int:
236
+ parser = argparse.ArgumentParser(description="Validate repo-registry with strict governance checks.")
237
+ parser.add_argument("--registry", default="repo-registry/repos.yml", help="Registry file path")
238
+ parser.add_argument("--strict", action="store_true", help="Enable strict governance checks")
239
+ args = parser.parse_args()
240
+
241
+ repo_root = Path(__file__).resolve().parents[2]
242
+ registry_path = (repo_root / args.registry).resolve()
243
+ if not registry_path.exists():
244
+ print(f"Missing registry file: {registry_path}")
245
+ return 1
246
+
247
+ try:
248
+ registry = load_registry(registry_path)
249
+ except Exception as exc:
250
+ print(f"Failed to parse registry file: {exc}")
251
+ return 1
252
+
253
+ registry_mode = str(registry.get("registry_mode", "enterprise")).strip().lower() or "enterprise"
254
+ schema_version = str(registry.get("schema_version", "1.0"))
255
+ repos_count = len(registry.get("repos", [])) if isinstance(registry.get("repos", []), list) else 0
256
+ result = validate(registry=registry, strict=args.strict, repo_root=repo_root)
257
+
258
+ report_path = repo_root / "repo-intake/generated/reports/repo-registry-validation.json"
259
+ write_report(
260
+ path=report_path,
261
+ registry_path=registry_path,
262
+ registry_mode=registry_mode,
263
+ schema_version=schema_version,
264
+ strict=args.strict,
265
+ result=result,
266
+ repos_count=repos_count,
267
+ )
268
+
269
+ if result.errors:
270
+ print("Repo registry validation failed.")
271
+ for err in result.errors:
272
+ print(f"- {err}")
273
+ print(f"Report: {report_path}")
274
+ return 1
275
+
276
+ print("Repo registry validation OK.")
277
+ if result.warnings:
278
+ print("Warnings:")
279
+ for warn in result.warnings:
280
+ print(f"- {warn}")
281
+ print(f"Report: {report_path}")
282
+ return 0
283
+
284
+
285
+ if __name__ == "__main__":
286
+ raise SystemExit(main())