solokit 0.1.1__py3-none-any.whl

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 (323) hide show
  1. solokit/__init__.py +10 -0
  2. solokit/__version__.py +3 -0
  3. solokit/cli.py +374 -0
  4. solokit/core/__init__.py +1 -0
  5. solokit/core/cache.py +102 -0
  6. solokit/core/command_runner.py +278 -0
  7. solokit/core/config.py +453 -0
  8. solokit/core/config_validator.py +204 -0
  9. solokit/core/constants.py +291 -0
  10. solokit/core/error_formatter.py +279 -0
  11. solokit/core/error_handlers.py +346 -0
  12. solokit/core/exceptions.py +1567 -0
  13. solokit/core/file_ops.py +309 -0
  14. solokit/core/logging_config.py +166 -0
  15. solokit/core/output.py +99 -0
  16. solokit/core/performance.py +57 -0
  17. solokit/core/protocols.py +141 -0
  18. solokit/core/types.py +312 -0
  19. solokit/deployment/__init__.py +1 -0
  20. solokit/deployment/executor.py +411 -0
  21. solokit/git/__init__.py +1 -0
  22. solokit/git/integration.py +619 -0
  23. solokit/init/__init__.py +41 -0
  24. solokit/init/claude_commands_installer.py +87 -0
  25. solokit/init/dependency_installer.py +313 -0
  26. solokit/init/docs_structure.py +90 -0
  27. solokit/init/env_generator.py +160 -0
  28. solokit/init/environment_validator.py +334 -0
  29. solokit/init/git_hooks_installer.py +71 -0
  30. solokit/init/git_setup.py +188 -0
  31. solokit/init/gitignore_updater.py +195 -0
  32. solokit/init/initial_commit.py +145 -0
  33. solokit/init/initial_scans.py +109 -0
  34. solokit/init/orchestrator.py +246 -0
  35. solokit/init/readme_generator.py +207 -0
  36. solokit/init/session_structure.py +239 -0
  37. solokit/init/template_installer.py +424 -0
  38. solokit/learning/__init__.py +1 -0
  39. solokit/learning/archiver.py +115 -0
  40. solokit/learning/categorizer.py +126 -0
  41. solokit/learning/curator.py +428 -0
  42. solokit/learning/extractor.py +352 -0
  43. solokit/learning/reporter.py +351 -0
  44. solokit/learning/repository.py +254 -0
  45. solokit/learning/similarity.py +342 -0
  46. solokit/learning/validator.py +144 -0
  47. solokit/project/__init__.py +1 -0
  48. solokit/project/init.py +1162 -0
  49. solokit/project/stack.py +436 -0
  50. solokit/project/sync_plugin.py +438 -0
  51. solokit/project/tree.py +375 -0
  52. solokit/quality/__init__.py +1 -0
  53. solokit/quality/api_validator.py +424 -0
  54. solokit/quality/checkers/__init__.py +25 -0
  55. solokit/quality/checkers/base.py +114 -0
  56. solokit/quality/checkers/context7.py +221 -0
  57. solokit/quality/checkers/custom.py +162 -0
  58. solokit/quality/checkers/deployment.py +323 -0
  59. solokit/quality/checkers/documentation.py +179 -0
  60. solokit/quality/checkers/formatting.py +161 -0
  61. solokit/quality/checkers/integration.py +394 -0
  62. solokit/quality/checkers/linting.py +159 -0
  63. solokit/quality/checkers/security.py +261 -0
  64. solokit/quality/checkers/spec_completeness.py +127 -0
  65. solokit/quality/checkers/tests.py +184 -0
  66. solokit/quality/env_validator.py +306 -0
  67. solokit/quality/gates.py +655 -0
  68. solokit/quality/reporters/__init__.py +10 -0
  69. solokit/quality/reporters/base.py +25 -0
  70. solokit/quality/reporters/console.py +98 -0
  71. solokit/quality/reporters/json_reporter.py +34 -0
  72. solokit/quality/results.py +98 -0
  73. solokit/session/__init__.py +1 -0
  74. solokit/session/briefing/__init__.py +245 -0
  75. solokit/session/briefing/documentation_loader.py +53 -0
  76. solokit/session/briefing/formatter.py +476 -0
  77. solokit/session/briefing/git_context.py +282 -0
  78. solokit/session/briefing/learning_loader.py +212 -0
  79. solokit/session/briefing/milestone_builder.py +78 -0
  80. solokit/session/briefing/orchestrator.py +137 -0
  81. solokit/session/briefing/stack_detector.py +51 -0
  82. solokit/session/briefing/tree_generator.py +52 -0
  83. solokit/session/briefing/work_item_loader.py +209 -0
  84. solokit/session/briefing.py +353 -0
  85. solokit/session/complete.py +1188 -0
  86. solokit/session/status.py +246 -0
  87. solokit/session/validate.py +452 -0
  88. solokit/templates/.claude/commands/end.md +109 -0
  89. solokit/templates/.claude/commands/init.md +159 -0
  90. solokit/templates/.claude/commands/learn-curate.md +88 -0
  91. solokit/templates/.claude/commands/learn-search.md +62 -0
  92. solokit/templates/.claude/commands/learn-show.md +69 -0
  93. solokit/templates/.claude/commands/learn.md +136 -0
  94. solokit/templates/.claude/commands/start.md +114 -0
  95. solokit/templates/.claude/commands/status.md +22 -0
  96. solokit/templates/.claude/commands/validate.md +27 -0
  97. solokit/templates/.claude/commands/work-delete.md +119 -0
  98. solokit/templates/.claude/commands/work-graph.md +139 -0
  99. solokit/templates/.claude/commands/work-list.md +26 -0
  100. solokit/templates/.claude/commands/work-new.md +114 -0
  101. solokit/templates/.claude/commands/work-next.md +25 -0
  102. solokit/templates/.claude/commands/work-show.md +24 -0
  103. solokit/templates/.claude/commands/work-update.md +141 -0
  104. solokit/templates/CHANGELOG.md +17 -0
  105. solokit/templates/WORK_ITEM_TYPES.md +141 -0
  106. solokit/templates/__init__.py +1 -0
  107. solokit/templates/bug_spec.md +217 -0
  108. solokit/templates/config.schema.json +150 -0
  109. solokit/templates/dashboard_refine/base/.gitignore +36 -0
  110. solokit/templates/dashboard_refine/base/app/(dashboard)/layout.tsx +22 -0
  111. solokit/templates/dashboard_refine/base/app/(dashboard)/page.tsx +68 -0
  112. solokit/templates/dashboard_refine/base/app/(dashboard)/users/page.tsx +77 -0
  113. solokit/templates/dashboard_refine/base/app/globals.css +60 -0
  114. solokit/templates/dashboard_refine/base/app/layout.tsx +23 -0
  115. solokit/templates/dashboard_refine/base/app/page.tsx +9 -0
  116. solokit/templates/dashboard_refine/base/components/client-refine-wrapper.tsx +21 -0
  117. solokit/templates/dashboard_refine/base/components/layout/header.tsx +44 -0
  118. solokit/templates/dashboard_refine/base/components/layout/sidebar.tsx +82 -0
  119. solokit/templates/dashboard_refine/base/components/ui/button.tsx +53 -0
  120. solokit/templates/dashboard_refine/base/components/ui/card.tsx +78 -0
  121. solokit/templates/dashboard_refine/base/components/ui/table.tsx +116 -0
  122. solokit/templates/dashboard_refine/base/components.json +16 -0
  123. solokit/templates/dashboard_refine/base/lib/refine.tsx +65 -0
  124. solokit/templates/dashboard_refine/base/lib/utils.ts +13 -0
  125. solokit/templates/dashboard_refine/base/next.config.ts +10 -0
  126. solokit/templates/dashboard_refine/base/package.json.template +40 -0
  127. solokit/templates/dashboard_refine/base/postcss.config.mjs +8 -0
  128. solokit/templates/dashboard_refine/base/providers/refine-provider.tsx +26 -0
  129. solokit/templates/dashboard_refine/base/tailwind.config.ts +57 -0
  130. solokit/templates/dashboard_refine/base/tsconfig.json +27 -0
  131. solokit/templates/dashboard_refine/docker/Dockerfile +57 -0
  132. solokit/templates/dashboard_refine/docker/docker-compose.prod.yml +31 -0
  133. solokit/templates/dashboard_refine/docker/docker-compose.yml +21 -0
  134. solokit/templates/dashboard_refine/tier-1-essential/.eslintrc.json +7 -0
  135. solokit/templates/dashboard_refine/tier-1-essential/jest.config.ts +17 -0
  136. solokit/templates/dashboard_refine/tier-1-essential/jest.setup.ts +1 -0
  137. solokit/templates/dashboard_refine/tier-1-essential/package.json.tier1.template +57 -0
  138. solokit/templates/dashboard_refine/tier-1-essential/tests/setup.ts +26 -0
  139. solokit/templates/dashboard_refine/tier-1-essential/tests/unit/example.test.tsx +73 -0
  140. solokit/templates/dashboard_refine/tier-2-standard/package.json.tier2.template +62 -0
  141. solokit/templates/dashboard_refine/tier-3-comprehensive/eslint.config.mjs +22 -0
  142. solokit/templates/dashboard_refine/tier-3-comprehensive/package.json.tier3.template +79 -0
  143. solokit/templates/dashboard_refine/tier-3-comprehensive/playwright.config.ts +66 -0
  144. solokit/templates/dashboard_refine/tier-3-comprehensive/stryker.conf.json +38 -0
  145. solokit/templates/dashboard_refine/tier-3-comprehensive/tests/e2e/dashboard.spec.ts +88 -0
  146. solokit/templates/dashboard_refine/tier-3-comprehensive/tests/e2e/user-management.spec.ts +102 -0
  147. solokit/templates/dashboard_refine/tier-3-comprehensive/tests/integration/dashboard.test.tsx +90 -0
  148. solokit/templates/dashboard_refine/tier-3-comprehensive/type-coverage.json +16 -0
  149. solokit/templates/dashboard_refine/tier-4-production/instrumentation.ts +9 -0
  150. solokit/templates/dashboard_refine/tier-4-production/k6/dashboard-load-test.js +70 -0
  151. solokit/templates/dashboard_refine/tier-4-production/next.config.ts +46 -0
  152. solokit/templates/dashboard_refine/tier-4-production/package.json.tier4.template +89 -0
  153. solokit/templates/dashboard_refine/tier-4-production/sentry.client.config.ts +26 -0
  154. solokit/templates/dashboard_refine/tier-4-production/sentry.edge.config.ts +11 -0
  155. solokit/templates/dashboard_refine/tier-4-production/sentry.server.config.ts +11 -0
  156. solokit/templates/deployment_spec.md +500 -0
  157. solokit/templates/feature_spec.md +248 -0
  158. solokit/templates/fullstack_nextjs/base/.gitignore +36 -0
  159. solokit/templates/fullstack_nextjs/base/app/api/example/route.ts +65 -0
  160. solokit/templates/fullstack_nextjs/base/app/globals.css +27 -0
  161. solokit/templates/fullstack_nextjs/base/app/layout.tsx +20 -0
  162. solokit/templates/fullstack_nextjs/base/app/page.tsx +32 -0
  163. solokit/templates/fullstack_nextjs/base/components/example-component.tsx +20 -0
  164. solokit/templates/fullstack_nextjs/base/lib/prisma.ts +17 -0
  165. solokit/templates/fullstack_nextjs/base/lib/utils.ts +13 -0
  166. solokit/templates/fullstack_nextjs/base/lib/validations.ts +20 -0
  167. solokit/templates/fullstack_nextjs/base/next.config.ts +7 -0
  168. solokit/templates/fullstack_nextjs/base/package.json.template +32 -0
  169. solokit/templates/fullstack_nextjs/base/postcss.config.mjs +8 -0
  170. solokit/templates/fullstack_nextjs/base/prisma/schema.prisma +21 -0
  171. solokit/templates/fullstack_nextjs/base/tailwind.config.ts +19 -0
  172. solokit/templates/fullstack_nextjs/base/tsconfig.json +27 -0
  173. solokit/templates/fullstack_nextjs/docker/Dockerfile +60 -0
  174. solokit/templates/fullstack_nextjs/docker/docker-compose.prod.yml +57 -0
  175. solokit/templates/fullstack_nextjs/docker/docker-compose.yml +47 -0
  176. solokit/templates/fullstack_nextjs/tier-1-essential/.eslintrc.json +7 -0
  177. solokit/templates/fullstack_nextjs/tier-1-essential/jest.config.ts +17 -0
  178. solokit/templates/fullstack_nextjs/tier-1-essential/jest.setup.ts +1 -0
  179. solokit/templates/fullstack_nextjs/tier-1-essential/package.json.tier1.template +48 -0
  180. solokit/templates/fullstack_nextjs/tier-1-essential/tests/api/example.test.ts +88 -0
  181. solokit/templates/fullstack_nextjs/tier-1-essential/tests/setup.ts +22 -0
  182. solokit/templates/fullstack_nextjs/tier-1-essential/tests/unit/example.test.tsx +22 -0
  183. solokit/templates/fullstack_nextjs/tier-2-standard/package.json.tier2.template +52 -0
  184. solokit/templates/fullstack_nextjs/tier-3-comprehensive/eslint.config.mjs +39 -0
  185. solokit/templates/fullstack_nextjs/tier-3-comprehensive/package.json.tier3.template +68 -0
  186. solokit/templates/fullstack_nextjs/tier-3-comprehensive/playwright.config.ts +66 -0
  187. solokit/templates/fullstack_nextjs/tier-3-comprehensive/stryker.conf.json +33 -0
  188. solokit/templates/fullstack_nextjs/tier-3-comprehensive/tests/e2e/flow.spec.ts +59 -0
  189. solokit/templates/fullstack_nextjs/tier-3-comprehensive/tests/integration/api.test.ts +165 -0
  190. solokit/templates/fullstack_nextjs/tier-3-comprehensive/type-coverage.json +12 -0
  191. solokit/templates/fullstack_nextjs/tier-4-production/instrumentation.ts +9 -0
  192. solokit/templates/fullstack_nextjs/tier-4-production/k6/load-test.js +45 -0
  193. solokit/templates/fullstack_nextjs/tier-4-production/next.config.ts +46 -0
  194. solokit/templates/fullstack_nextjs/tier-4-production/package.json.tier4.template +77 -0
  195. solokit/templates/fullstack_nextjs/tier-4-production/sentry.client.config.ts +26 -0
  196. solokit/templates/fullstack_nextjs/tier-4-production/sentry.edge.config.ts +11 -0
  197. solokit/templates/fullstack_nextjs/tier-4-production/sentry.server.config.ts +11 -0
  198. solokit/templates/git-hooks/prepare-commit-msg +24 -0
  199. solokit/templates/integration_test_spec.md +363 -0
  200. solokit/templates/learnings.json +15 -0
  201. solokit/templates/ml_ai_fastapi/base/.gitignore +104 -0
  202. solokit/templates/ml_ai_fastapi/base/alembic/env.py +96 -0
  203. solokit/templates/ml_ai_fastapi/base/alembic.ini +114 -0
  204. solokit/templates/ml_ai_fastapi/base/pyproject.toml.template +91 -0
  205. solokit/templates/ml_ai_fastapi/base/requirements.txt.template +28 -0
  206. solokit/templates/ml_ai_fastapi/base/src/__init__.py +5 -0
  207. solokit/templates/ml_ai_fastapi/base/src/api/__init__.py +3 -0
  208. solokit/templates/ml_ai_fastapi/base/src/api/dependencies.py +20 -0
  209. solokit/templates/ml_ai_fastapi/base/src/api/routes/__init__.py +3 -0
  210. solokit/templates/ml_ai_fastapi/base/src/api/routes/example.py +134 -0
  211. solokit/templates/ml_ai_fastapi/base/src/api/routes/health.py +66 -0
  212. solokit/templates/ml_ai_fastapi/base/src/core/__init__.py +3 -0
  213. solokit/templates/ml_ai_fastapi/base/src/core/config.py +64 -0
  214. solokit/templates/ml_ai_fastapi/base/src/core/database.py +50 -0
  215. solokit/templates/ml_ai_fastapi/base/src/main.py +64 -0
  216. solokit/templates/ml_ai_fastapi/base/src/models/__init__.py +7 -0
  217. solokit/templates/ml_ai_fastapi/base/src/models/example.py +61 -0
  218. solokit/templates/ml_ai_fastapi/base/src/services/__init__.py +3 -0
  219. solokit/templates/ml_ai_fastapi/base/src/services/example.py +115 -0
  220. solokit/templates/ml_ai_fastapi/docker/Dockerfile +59 -0
  221. solokit/templates/ml_ai_fastapi/docker/docker-compose.prod.yml +112 -0
  222. solokit/templates/ml_ai_fastapi/docker/docker-compose.yml +77 -0
  223. solokit/templates/ml_ai_fastapi/tier-1-essential/pyproject.toml.tier1.template +112 -0
  224. solokit/templates/ml_ai_fastapi/tier-1-essential/pyrightconfig.json +41 -0
  225. solokit/templates/ml_ai_fastapi/tier-1-essential/pytest.ini +69 -0
  226. solokit/templates/ml_ai_fastapi/tier-1-essential/requirements-dev.txt +17 -0
  227. solokit/templates/ml_ai_fastapi/tier-1-essential/ruff.toml +81 -0
  228. solokit/templates/ml_ai_fastapi/tier-1-essential/tests/__init__.py +3 -0
  229. solokit/templates/ml_ai_fastapi/tier-1-essential/tests/conftest.py +72 -0
  230. solokit/templates/ml_ai_fastapi/tier-1-essential/tests/test_main.py +49 -0
  231. solokit/templates/ml_ai_fastapi/tier-1-essential/tests/unit/__init__.py +3 -0
  232. solokit/templates/ml_ai_fastapi/tier-1-essential/tests/unit/test_example.py +113 -0
  233. solokit/templates/ml_ai_fastapi/tier-2-standard/pyproject.toml.tier2.template +130 -0
  234. solokit/templates/ml_ai_fastapi/tier-3-comprehensive/locustfile.py +99 -0
  235. solokit/templates/ml_ai_fastapi/tier-3-comprehensive/mutmut_config.py +53 -0
  236. solokit/templates/ml_ai_fastapi/tier-3-comprehensive/pyproject.toml.tier3.template +150 -0
  237. solokit/templates/ml_ai_fastapi/tier-3-comprehensive/tests/integration/__init__.py +3 -0
  238. solokit/templates/ml_ai_fastapi/tier-3-comprehensive/tests/integration/conftest.py +74 -0
  239. solokit/templates/ml_ai_fastapi/tier-3-comprehensive/tests/integration/test_api.py +131 -0
  240. solokit/templates/ml_ai_fastapi/tier-4-production/pyproject.toml.tier4.template +162 -0
  241. solokit/templates/ml_ai_fastapi/tier-4-production/requirements-prod.txt +25 -0
  242. solokit/templates/ml_ai_fastapi/tier-4-production/src/api/routes/metrics.py +19 -0
  243. solokit/templates/ml_ai_fastapi/tier-4-production/src/core/logging.py +74 -0
  244. solokit/templates/ml_ai_fastapi/tier-4-production/src/core/monitoring.py +68 -0
  245. solokit/templates/ml_ai_fastapi/tier-4-production/src/core/sentry.py +66 -0
  246. solokit/templates/ml_ai_fastapi/tier-4-production/src/middleware/__init__.py +3 -0
  247. solokit/templates/ml_ai_fastapi/tier-4-production/src/middleware/logging.py +79 -0
  248. solokit/templates/ml_ai_fastapi/tier-4-production/src/middleware/tracing.py +60 -0
  249. solokit/templates/refactor_spec.md +287 -0
  250. solokit/templates/saas_t3/base/.gitignore +36 -0
  251. solokit/templates/saas_t3/base/app/api/trpc/[trpc]/route.ts +33 -0
  252. solokit/templates/saas_t3/base/app/globals.css +27 -0
  253. solokit/templates/saas_t3/base/app/layout.tsx +23 -0
  254. solokit/templates/saas_t3/base/app/page.tsx +31 -0
  255. solokit/templates/saas_t3/base/lib/api.tsx +77 -0
  256. solokit/templates/saas_t3/base/lib/utils.ts +13 -0
  257. solokit/templates/saas_t3/base/next.config.ts +7 -0
  258. solokit/templates/saas_t3/base/package.json.template +38 -0
  259. solokit/templates/saas_t3/base/postcss.config.mjs +8 -0
  260. solokit/templates/saas_t3/base/prisma/schema.prisma +20 -0
  261. solokit/templates/saas_t3/base/server/api/root.ts +19 -0
  262. solokit/templates/saas_t3/base/server/api/routers/example.ts +28 -0
  263. solokit/templates/saas_t3/base/server/api/trpc.ts +52 -0
  264. solokit/templates/saas_t3/base/server/db.ts +17 -0
  265. solokit/templates/saas_t3/base/tailwind.config.ts +19 -0
  266. solokit/templates/saas_t3/base/tsconfig.json +27 -0
  267. solokit/templates/saas_t3/docker/Dockerfile +60 -0
  268. solokit/templates/saas_t3/docker/docker-compose.prod.yml +59 -0
  269. solokit/templates/saas_t3/docker/docker-compose.yml +49 -0
  270. solokit/templates/saas_t3/tier-1-essential/.eslintrc.json +7 -0
  271. solokit/templates/saas_t3/tier-1-essential/jest.config.ts +17 -0
  272. solokit/templates/saas_t3/tier-1-essential/jest.setup.ts +1 -0
  273. solokit/templates/saas_t3/tier-1-essential/package.json.tier1.template +54 -0
  274. solokit/templates/saas_t3/tier-1-essential/tests/setup.ts +22 -0
  275. solokit/templates/saas_t3/tier-1-essential/tests/unit/example.test.tsx +24 -0
  276. solokit/templates/saas_t3/tier-2-standard/package.json.tier2.template +58 -0
  277. solokit/templates/saas_t3/tier-3-comprehensive/eslint.config.mjs +39 -0
  278. solokit/templates/saas_t3/tier-3-comprehensive/package.json.tier3.template +74 -0
  279. solokit/templates/saas_t3/tier-3-comprehensive/playwright.config.ts +66 -0
  280. solokit/templates/saas_t3/tier-3-comprehensive/stryker.conf.json +34 -0
  281. solokit/templates/saas_t3/tier-3-comprehensive/tests/e2e/home.spec.ts +41 -0
  282. solokit/templates/saas_t3/tier-3-comprehensive/tests/integration/api.test.ts +44 -0
  283. solokit/templates/saas_t3/tier-3-comprehensive/type-coverage.json +12 -0
  284. solokit/templates/saas_t3/tier-4-production/instrumentation.ts +9 -0
  285. solokit/templates/saas_t3/tier-4-production/k6/load-test.js +51 -0
  286. solokit/templates/saas_t3/tier-4-production/next.config.ts +46 -0
  287. solokit/templates/saas_t3/tier-4-production/package.json.tier4.template +83 -0
  288. solokit/templates/saas_t3/tier-4-production/sentry.client.config.ts +26 -0
  289. solokit/templates/saas_t3/tier-4-production/sentry.edge.config.ts +11 -0
  290. solokit/templates/saas_t3/tier-4-production/sentry.server.config.ts +11 -0
  291. solokit/templates/saas_t3/tier-4-production/vercel.json +37 -0
  292. solokit/templates/security_spec.md +287 -0
  293. solokit/templates/stack-versions.yaml +617 -0
  294. solokit/templates/status_update.json +6 -0
  295. solokit/templates/template-registry.json +257 -0
  296. solokit/templates/work_items.json +11 -0
  297. solokit/testing/__init__.py +1 -0
  298. solokit/testing/integration_runner.py +550 -0
  299. solokit/testing/performance.py +637 -0
  300. solokit/visualization/__init__.py +1 -0
  301. solokit/visualization/dependency_graph.py +788 -0
  302. solokit/work_items/__init__.py +1 -0
  303. solokit/work_items/creator.py +217 -0
  304. solokit/work_items/delete.py +264 -0
  305. solokit/work_items/get_dependencies.py +185 -0
  306. solokit/work_items/get_dependents.py +113 -0
  307. solokit/work_items/get_metadata.py +121 -0
  308. solokit/work_items/get_next_recommendations.py +133 -0
  309. solokit/work_items/manager.py +235 -0
  310. solokit/work_items/milestones.py +137 -0
  311. solokit/work_items/query.py +376 -0
  312. solokit/work_items/repository.py +267 -0
  313. solokit/work_items/scheduler.py +184 -0
  314. solokit/work_items/spec_parser.py +838 -0
  315. solokit/work_items/spec_validator.py +493 -0
  316. solokit/work_items/updater.py +157 -0
  317. solokit/work_items/validator.py +205 -0
  318. solokit-0.1.1.dist-info/METADATA +640 -0
  319. solokit-0.1.1.dist-info/RECORD +323 -0
  320. solokit-0.1.1.dist-info/WHEEL +5 -0
  321. solokit-0.1.1.dist-info/entry_points.txt +2 -0
  322. solokit-0.1.1.dist-info/licenses/LICENSE +21 -0
  323. solokit-0.1.1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,394 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Integration test validation checker.
4
+
5
+ Validates integration test environment, documentation, and execution.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ import json
11
+ import time
12
+ from pathlib import Path
13
+ from typing import Any, Union, cast
14
+
15
+ from solokit.core.command_runner import CommandRunner
16
+ from solokit.core.constants import DOCKER_COMMAND_TIMEOUT, QUALITY_CHECK_STANDARD_TIMEOUT
17
+ from solokit.core.exceptions import CommandExecutionError
18
+ from solokit.core.logging_config import get_logger
19
+ from solokit.core.types import WorkItemType
20
+ from solokit.quality.checkers.base import CheckResult, QualityChecker
21
+ from solokit.work_items import spec_parser
22
+
23
+ logger = get_logger(__name__)
24
+
25
+
26
+ class IntegrationChecker(QualityChecker):
27
+ """Integration test requirements validation."""
28
+
29
+ def __init__(
30
+ self,
31
+ work_item: dict[str, Any],
32
+ config: dict[str, Any],
33
+ runner: CommandRunner | None = None,
34
+ config_path: Path | None = None,
35
+ ):
36
+ """Initialize integration checker.
37
+
38
+ Args:
39
+ work_item: Work item dictionary (must be integration_test type)
40
+ config: Integration test configuration
41
+ runner: Optional CommandRunner instance (for testing)
42
+ config_path: Path to full config file (for loading documentation settings)
43
+ """
44
+ super().__init__(config)
45
+ self.work_item = work_item
46
+ self.runner = (
47
+ runner
48
+ if runner is not None
49
+ else CommandRunner(default_timeout=QUALITY_CHECK_STANDARD_TIMEOUT)
50
+ )
51
+ self.config_path = config_path if config_path is not None else Path(".session/config.json")
52
+
53
+ def name(self) -> str:
54
+ """Return checker name."""
55
+ return "integration"
56
+
57
+ def is_enabled(self) -> bool:
58
+ """Check if integration validation is enabled."""
59
+ return bool(self.config.get("enabled", True))
60
+
61
+ def run(self) -> CheckResult:
62
+ """Execute integration test validation (full orchestration).
63
+
64
+ Returns:
65
+ CheckResult with orchestrated validation outcome
66
+ """
67
+ start_time = time.time()
68
+
69
+ # Only run for integration_test work items
70
+ if self.work_item.get("type") != WorkItemType.INTEGRATION_TEST.value:
71
+ return self._create_skipped_result("not integration test")
72
+
73
+ if not self.is_enabled():
74
+ return self._create_skipped_result("disabled")
75
+
76
+ logger.info("Running integration test quality gates...")
77
+
78
+ results: dict[str, Any] = {
79
+ "integration_tests": {},
80
+ "performance_benchmarks": {},
81
+ "api_contracts": {},
82
+ }
83
+
84
+ errors = []
85
+ warnings = []
86
+
87
+ # Import here to avoid circular imports
88
+ from solokit.core.exceptions import (
89
+ EnvironmentSetupError,
90
+ IntegrationExecutionError,
91
+ IntegrationTestError,
92
+ )
93
+ from solokit.testing.integration_runner import IntegrationTestRunner
94
+
95
+ runner_instance = IntegrationTestRunner(self.work_item)
96
+
97
+ try:
98
+ # Setup environment (now raises exceptions instead of returning tuple)
99
+ runner_instance.setup_environment()
100
+
101
+ # Execute integration tests (now returns dict and raises exceptions on failure)
102
+ test_results = runner_instance.run_tests()
103
+ results["integration_tests"] = test_results
104
+
105
+ # Check if tests passed
106
+ if test_results.get("failed", 0) > 0:
107
+ logger.error("Integration tests failed")
108
+ errors.append(
109
+ {"message": f"{test_results.get('failed', 0)} integration tests failed"}
110
+ )
111
+
112
+ logger.info(f"Integration tests passed ({test_results.get('passed', 0)} tests)")
113
+
114
+ # 2. Run performance benchmarks
115
+ if self.work_item.get("performance_benchmarks"):
116
+ from solokit.testing.performance import PerformanceBenchmark
117
+
118
+ benchmark = PerformanceBenchmark(self.work_item)
119
+ benchmarks_passed, benchmark_results = benchmark.run_benchmarks()
120
+ results["performance_benchmarks"] = benchmark_results
121
+
122
+ if not benchmarks_passed:
123
+ logger.error("Performance benchmarks failed")
124
+ if self.config.get("performance_benchmarks", {}).get("required", True):
125
+ errors.append({"message": "Performance benchmarks failed"})
126
+ else:
127
+ warnings.append({"message": "Performance benchmarks failed (optional)"})
128
+ else:
129
+ logger.info("Performance benchmarks passed")
130
+
131
+ # 3. Validate API contracts
132
+ if self.work_item.get("api_contracts"):
133
+ from solokit.quality.api_validator import APIContractValidator
134
+
135
+ validator = APIContractValidator(self.work_item)
136
+ contracts_passed, contract_results = validator.validate_contracts()
137
+ results["api_contracts"] = contract_results
138
+
139
+ if not contracts_passed:
140
+ logger.error("API contract validation failed")
141
+ if self.config.get("api_contracts", {}).get("required", True):
142
+ errors.append({"message": "API contract validation failed"})
143
+ else:
144
+ warnings.append({"message": "API contract validation failed (optional)"})
145
+ else:
146
+ logger.info("API contracts validated")
147
+
148
+ except (
149
+ EnvironmentSetupError,
150
+ IntegrationExecutionError,
151
+ IntegrationTestError,
152
+ ) as e:
153
+ # Integration test setup or execution failed
154
+ logger.error(f"Integration test error: {e}")
155
+ errors.append({"message": str(e)})
156
+
157
+ finally:
158
+ # Always teardown environment
159
+ try:
160
+ runner_instance.teardown_environment()
161
+ except (OSError, CommandExecutionError) as e:
162
+ # Log teardown failures but don't fail the gate
163
+ logger.warning(f"Environment teardown failed: {e}")
164
+ warnings.append({"message": f"Environment teardown failed: {e}"})
165
+
166
+ execution_time = time.time() - start_time
167
+ passed = len(errors) == 0
168
+
169
+ return CheckResult(
170
+ checker_name=self.name(),
171
+ passed=passed,
172
+ status="passed" if passed else "failed",
173
+ errors=cast(list[Union[dict[str, Any], str]], errors),
174
+ warnings=cast(list[Union[dict[str, Any], str]], warnings),
175
+ info=results,
176
+ execution_time=execution_time,
177
+ )
178
+
179
+ def validate_environment(self) -> CheckResult:
180
+ """Validate integration test environment requirements.
181
+
182
+ Returns:
183
+ CheckResult with environment validation outcome
184
+ """
185
+ start_time = time.time()
186
+
187
+ if self.work_item.get("type") != WorkItemType.INTEGRATION_TEST.value:
188
+ return self._create_skipped_result("not integration test")
189
+
190
+ env_requirements = self.work_item.get("environment_requirements", {})
191
+ results: dict[str, Any] = {
192
+ "docker_available": False,
193
+ "docker_compose_available": False,
194
+ "required_services": [],
195
+ "missing_config": [],
196
+ }
197
+
198
+ errors = []
199
+
200
+ # Check Docker available
201
+ result = self.runner.run(["docker", "--version"], timeout=DOCKER_COMMAND_TIMEOUT)
202
+ results["docker_available"] = result.success
203
+
204
+ if not result.success:
205
+ errors.append({"message": "Docker not available"})
206
+
207
+ # Check Docker Compose available
208
+ result = self.runner.run(["docker-compose", "--version"], timeout=DOCKER_COMMAND_TIMEOUT)
209
+ results["docker_compose_available"] = result.success
210
+
211
+ if not result.success:
212
+ errors.append({"message": "Docker Compose not available"})
213
+
214
+ # Check compose file exists
215
+ compose_file = env_requirements.get("compose_file", "docker-compose.integration.yml")
216
+ if not Path(compose_file).exists():
217
+ results["missing_config"].append(compose_file)
218
+ errors.append({"message": f"Missing compose file: {compose_file}"})
219
+
220
+ # Check config files exist
221
+ config_files = env_requirements.get("config_files", [])
222
+ for config_file in config_files:
223
+ if not Path(config_file).exists():
224
+ results["missing_config"].append(config_file)
225
+ errors.append({"message": f"Missing config file: {config_file}"})
226
+
227
+ execution_time = time.time() - start_time
228
+ passed = (
229
+ results["docker_available"]
230
+ and results["docker_compose_available"]
231
+ and len(results["missing_config"]) == 0
232
+ )
233
+
234
+ return CheckResult(
235
+ checker_name=self.name(),
236
+ passed=passed,
237
+ status="passed" if passed else "failed",
238
+ errors=cast(list[Union[dict[str, Any], str]], errors),
239
+ warnings=[],
240
+ info=results,
241
+ execution_time=execution_time,
242
+ )
243
+
244
+ def validate_documentation(self) -> CheckResult:
245
+ """Validate integration test documentation requirements.
246
+
247
+ Returns:
248
+ CheckResult with documentation validation outcome
249
+ """
250
+ start_time = time.time()
251
+
252
+ if self.work_item.get("type") != WorkItemType.INTEGRATION_TEST.value:
253
+ return self._create_skipped_result("not integration test")
254
+
255
+ # Get integration documentation config
256
+ full_config: dict[str, Any] = {}
257
+ if self.config_path.exists():
258
+ try:
259
+ with open(self.config_path) as f:
260
+ full_config = json.load(f)
261
+ except (OSError, json.JSONDecodeError) as e:
262
+ logger.debug(f"Failed to load config: {e}")
263
+
264
+ config = full_config.get("integration_tests", {}).get("documentation", {})
265
+ if not config.get("enabled", True):
266
+ return self._create_skipped_result("documentation validation disabled")
267
+
268
+ results: dict[str, Any] = {"checks": [], "missing": []}
269
+
270
+ # 1. Check for integration architecture diagram
271
+ if config.get("architecture_diagrams", True):
272
+ diagram_paths = [
273
+ "docs/architecture/integration-architecture.md",
274
+ "docs/integration-architecture.md",
275
+ ".session/specs/integration-architecture.md",
276
+ ]
277
+
278
+ diagram_found = any(Path(p).exists() for p in diagram_paths)
279
+ results["checks"].append(
280
+ {"name": "Integration architecture diagram", "passed": diagram_found}
281
+ )
282
+
283
+ if not diagram_found:
284
+ results["missing"].append("Integration architecture diagram")
285
+
286
+ # 2. Check for sequence diagrams (using spec_parser)
287
+ if config.get("sequence_diagrams", True):
288
+ # Parse spec file to get test scenarios
289
+ try:
290
+ parsed_spec = spec_parser.parse_spec_file(self.work_item)
291
+ scenarios = parsed_spec.get("test_scenarios", [])
292
+ except (OSError, ValueError, KeyError) as e:
293
+ logger.debug(f"Failed to parse spec file for scenarios: {e}")
294
+ scenarios = []
295
+
296
+ if scenarios:
297
+ # Check if any scenario content contains sequence diagrams
298
+ has_sequence = False
299
+ for scenario in scenarios:
300
+ content = scenario.get("content", "")
301
+ if "```mermaid" in content or "sequenceDiagram" in content:
302
+ has_sequence = True
303
+ break
304
+
305
+ results["checks"].append({"name": "Sequence diagrams", "passed": has_sequence})
306
+
307
+ if not has_sequence:
308
+ results["missing"].append("Sequence diagrams for test scenarios")
309
+
310
+ # 3. Check for API contract documentation (using spec_parser)
311
+ if config.get("contract_documentation", True):
312
+ # Parse spec file to get API contracts
313
+ try:
314
+ parsed_spec = spec_parser.parse_spec_file(self.work_item)
315
+ api_contracts = parsed_spec.get("api_contracts", "")
316
+ # API contracts should be documented in the spec
317
+ has_contracts = api_contracts and len(api_contracts.strip()) > 20
318
+ except (OSError, ValueError, KeyError) as e:
319
+ logger.debug(f"Failed to parse spec file for API contracts: {e}")
320
+ has_contracts = False
321
+
322
+ results["checks"].append(
323
+ {
324
+ "name": "API contracts documented",
325
+ "passed": has_contracts,
326
+ }
327
+ )
328
+
329
+ if not has_contracts:
330
+ results["missing"].append("API contract documentation")
331
+
332
+ # 4. Check for performance baseline documentation (using spec_parser)
333
+ if config.get("performance_baseline_docs", True):
334
+ # Parse spec file to get performance benchmarks
335
+ try:
336
+ parsed_spec = spec_parser.parse_spec_file(self.work_item)
337
+ benchmarks = parsed_spec.get("performance_benchmarks", "")
338
+ has_benchmarks = benchmarks and len(benchmarks.strip()) > 20
339
+ except (OSError, ValueError, KeyError) as e:
340
+ logger.debug(f"Failed to parse spec file for performance benchmarks: {e}")
341
+ has_benchmarks = False
342
+
343
+ if has_benchmarks:
344
+ baseline_file = Path(".session/tracking/performance_baselines.json")
345
+ baseline_exists = baseline_file.exists()
346
+
347
+ results["checks"].append(
348
+ {
349
+ "name": "Performance baseline documented",
350
+ "passed": baseline_exists,
351
+ }
352
+ )
353
+
354
+ if not baseline_exists:
355
+ results["missing"].append("Performance baseline documentation")
356
+
357
+ # 5. Check for integration point documentation (using spec_parser)
358
+ try:
359
+ parsed_spec = spec_parser.parse_spec_file(self.work_item.get("id"))
360
+ scope = parsed_spec.get("scope", "")
361
+ # Check if scope has meaningful content
362
+ documented = scope and len(scope.strip()) > 20
363
+ except (OSError, ValueError, KeyError) as e:
364
+ logger.debug(f"Failed to parse spec file for integration points: {e}")
365
+ documented = False
366
+
367
+ results["checks"].append({"name": "Integration points documented", "passed": documented})
368
+
369
+ if not documented:
370
+ results["missing"].append("Integration points documentation")
371
+
372
+ # Determine overall pass/fail
373
+ passed_checks = sum(1 for check in results["checks"] if check["passed"])
374
+ total_checks = len(results["checks"])
375
+
376
+ # Pass if all required checks pass
377
+ passed = len(results["missing"]) == 0
378
+ results["summary"] = f"{passed_checks}/{total_checks} documentation requirements met"
379
+
380
+ execution_time = time.time() - start_time
381
+
382
+ errors = []
383
+ for missing in results["missing"]:
384
+ errors.append({"message": f"Missing: {missing}"})
385
+
386
+ return CheckResult(
387
+ checker_name=self.name(),
388
+ passed=passed,
389
+ status="passed" if passed else "failed",
390
+ errors=cast(list[Union[dict[str, Any], str]], errors),
391
+ warnings=[],
392
+ info=results,
393
+ execution_time=execution_time,
394
+ )
@@ -0,0 +1,159 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Code linting checker.
4
+
5
+ Runs linters like ruff, flake8, eslint, etc.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ import time
11
+ from pathlib import Path
12
+ from typing import Any, Union, cast
13
+
14
+ from solokit.core.command_runner import CommandRunner
15
+ from solokit.core.constants import QUALITY_CHECK_VERY_LONG_TIMEOUT
16
+ from solokit.core.logging_config import get_logger
17
+ from solokit.quality.checkers.base import CheckResult, QualityChecker
18
+
19
+ logger = get_logger(__name__)
20
+
21
+
22
+ class LintingChecker(QualityChecker):
23
+ """Code linting validation."""
24
+
25
+ def __init__(
26
+ self,
27
+ config: dict[str, Any],
28
+ project_root: Path | None = None,
29
+ language: str | None = None,
30
+ auto_fix: bool | None = None,
31
+ runner: CommandRunner | None = None,
32
+ ):
33
+ """Initialize linting checker.
34
+
35
+ Args:
36
+ config: Linting configuration
37
+ project_root: Project root directory
38
+ language: Programming language (python, javascript, typescript)
39
+ auto_fix: Whether to automatically fix issues (overrides config)
40
+ runner: Optional CommandRunner instance (for testing)
41
+ """
42
+ super().__init__(config, project_root)
43
+ self.runner = (
44
+ runner
45
+ if runner is not None
46
+ else CommandRunner(default_timeout=QUALITY_CHECK_VERY_LONG_TIMEOUT)
47
+ )
48
+ self.language = language or self._detect_language()
49
+ self.auto_fix = auto_fix if auto_fix is not None else self.config.get("auto_fix", False)
50
+
51
+ def name(self) -> str:
52
+ """Return checker name."""
53
+ return "linting"
54
+
55
+ def is_enabled(self) -> bool:
56
+ """Check if linting is enabled."""
57
+ return bool(self.config.get("enabled", True))
58
+
59
+ def _detect_language(self) -> str:
60
+ """Detect primary project language."""
61
+ if (self.project_root / "pyproject.toml").exists() or (
62
+ self.project_root / "setup.py"
63
+ ).exists():
64
+ return "python"
65
+ elif (self.project_root / "package.json").exists():
66
+ if (self.project_root / "tsconfig.json").exists():
67
+ return "typescript"
68
+ return "javascript"
69
+ return "python" # default
70
+
71
+ def run(self) -> CheckResult:
72
+ """Run linting checks."""
73
+ start_time = time.time()
74
+
75
+ if not self.is_enabled():
76
+ return self._create_skipped_result()
77
+
78
+ logger.info(f"Running linting for {self.language}")
79
+
80
+ # Get linting command for language
81
+ commands = self.config.get("commands", {})
82
+ command = commands.get(self.language)
83
+ if not command:
84
+ logger.warning(f"No linting command configured for language: {self.language}")
85
+ return self._create_skipped_result(reason=f"no command for {self.language}")
86
+
87
+ # Add auto-fix flag if supported
88
+ if self.auto_fix:
89
+ if self.language == "python":
90
+ command += " --fix"
91
+ elif self.language in ["javascript", "typescript"]:
92
+ command += " --fix"
93
+
94
+ # Run linter
95
+ result = self.runner.run(command.split(), timeout=QUALITY_CHECK_VERY_LONG_TIMEOUT)
96
+
97
+ execution_time = time.time() - start_time
98
+
99
+ if result.timed_out:
100
+ required = self.config.get("required", False)
101
+ if required:
102
+ return CheckResult(
103
+ checker_name=self.name(),
104
+ passed=False,
105
+ status="failed",
106
+ errors=[{"message": "Linting timed out"}],
107
+ warnings=[],
108
+ info={"reason": "timeout"},
109
+ execution_time=execution_time,
110
+ )
111
+ return CheckResult(
112
+ checker_name=self.name(),
113
+ passed=True,
114
+ status="skipped",
115
+ errors=[],
116
+ warnings=[],
117
+ info={"reason": "timeout"},
118
+ execution_time=execution_time,
119
+ )
120
+
121
+ # Tool not found
122
+ if result.returncode == -1:
123
+ required = self.config.get("required", False)
124
+ if required:
125
+ return CheckResult(
126
+ checker_name=self.name(),
127
+ passed=False,
128
+ status="failed",
129
+ errors=[{"message": "Required linting tool not found"}],
130
+ warnings=[],
131
+ info={"reason": "tool not found"},
132
+ execution_time=execution_time,
133
+ )
134
+ return self._create_skipped_result(reason="linting tool not available")
135
+
136
+ passed = result.returncode == 0
137
+
138
+ errors = []
139
+ if not passed:
140
+ errors.append(
141
+ {
142
+ "message": f"Linting found {result.returncode} issue(s)",
143
+ "output": result.stdout[:500] if result.stdout else "",
144
+ }
145
+ )
146
+
147
+ return CheckResult(
148
+ checker_name=self.name(),
149
+ passed=passed,
150
+ status="passed" if passed else "failed",
151
+ errors=cast(list[Union[dict[str, Any], str]], errors),
152
+ warnings=[],
153
+ info={
154
+ "issues_found": result.returncode,
155
+ "auto_fixed": self.auto_fix,
156
+ "output": result.stdout[:1000] if result.stdout else "",
157
+ },
158
+ execution_time=execution_time,
159
+ )