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,323 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Deployment quality gates checker.
4
+
5
+ Validates deployment readiness including environment setup, documentation,
6
+ rollback procedures, and orchestrates integration tests and security scans.
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ import re
12
+ import time
13
+ from pathlib import Path
14
+ from typing import Any, Union, cast
15
+
16
+ from solokit.core.command_runner import CommandRunner
17
+ from solokit.core.constants import QUALITY_CHECK_LONG_TIMEOUT
18
+ from solokit.core.logging_config import get_logger
19
+ from solokit.quality.checkers.base import CheckResult, QualityChecker
20
+
21
+ logger = get_logger(__name__)
22
+
23
+
24
+ class DeploymentChecker(QualityChecker):
25
+ """Deployment readiness validation and orchestration."""
26
+
27
+ def __init__(
28
+ self,
29
+ work_item: dict[str, Any],
30
+ config: dict[str, Any],
31
+ project_root: Path | None = None,
32
+ runner: CommandRunner | None = None,
33
+ ):
34
+ """Initialize deployment checker.
35
+
36
+ Args:
37
+ work_item: Work item dictionary (must be deployment type)
38
+ config: Deployment quality gate configuration
39
+ project_root: Project root directory
40
+ runner: Optional CommandRunner instance (for testing)
41
+ """
42
+ super().__init__(config, project_root)
43
+ self.work_item = work_item
44
+ self.runner = (
45
+ runner
46
+ if runner is not None
47
+ else CommandRunner(default_timeout=QUALITY_CHECK_LONG_TIMEOUT)
48
+ )
49
+
50
+ def name(self) -> str:
51
+ """Return checker name."""
52
+ return "deployment"
53
+
54
+ def is_enabled(self) -> bool:
55
+ """Check if deployment quality gates are enabled."""
56
+ return bool(self.config.get("enabled", True))
57
+
58
+ def run(self) -> CheckResult:
59
+ """Execute deployment quality gates orchestration.
60
+
61
+ Orchestrates:
62
+ 1. Integration tests (via IntegrationChecker)
63
+ 2. Security scans (via SecurityChecker)
64
+ 3. Environment validation
65
+ 4. Deployment documentation validation
66
+ 5. Rollback procedure testing
67
+
68
+ Returns:
69
+ CheckResult with orchestrated deployment validation outcome
70
+ """
71
+ start_time = time.time()
72
+
73
+ if not self.is_enabled():
74
+ return self._create_skipped_result("disabled")
75
+
76
+ logger.info("Running deployment quality gates...")
77
+
78
+ gates: list[dict[str, Any]] = []
79
+ errors: list[dict[str, Any]] = []
80
+ warnings: list[dict[str, Any]] = []
81
+ overall_passed = True
82
+
83
+ # Gate 1: All integration tests must pass
84
+ try:
85
+ from solokit.quality.checkers.integration import IntegrationChecker
86
+
87
+ integration_config = self.config.get("integration_tests", {"enabled": True})
88
+ integration_checker = IntegrationChecker(
89
+ self.work_item, integration_config, runner=self.runner
90
+ )
91
+
92
+ # Check if integration checker is applicable
93
+ if integration_checker.is_enabled():
94
+ logger.info("Running integration tests gate...")
95
+ integration_result = integration_checker.run()
96
+
97
+ gates.append(
98
+ {
99
+ "name": "Integration Tests",
100
+ "required": True,
101
+ "passed": integration_result.passed,
102
+ "details": integration_result.info,
103
+ }
104
+ )
105
+
106
+ if not integration_result.passed:
107
+ overall_passed = False
108
+ for error in integration_result.errors:
109
+ errors.append({"gate": "Integration Tests", "message": error})
110
+ else:
111
+ gates.append(
112
+ {
113
+ "name": "Integration Tests",
114
+ "required": True,
115
+ "passed": True,
116
+ "details": {"skipped": "not applicable"},
117
+ }
118
+ )
119
+ except ImportError as e:
120
+ logger.warning(f"Integration checker not available: {e}")
121
+ gates.append(
122
+ {
123
+ "name": "Integration Tests",
124
+ "required": True,
125
+ "passed": True,
126
+ "details": {"skipped": "checker not available"},
127
+ }
128
+ )
129
+
130
+ # Gate 2: Security scans must pass
131
+ try:
132
+ from solokit.quality.checkers.security import SecurityChecker
133
+
134
+ security_config = self.config.get("security_scans", {"enabled": True})
135
+ security_checker = SecurityChecker(
136
+ security_config, project_root=self.project_root, runner=self.runner
137
+ )
138
+
139
+ if security_checker.is_enabled():
140
+ logger.info("Running security scans gate...")
141
+ security_result = security_checker.run()
142
+
143
+ gates.append(
144
+ {
145
+ "name": "Security Scans",
146
+ "required": True,
147
+ "passed": security_result.passed,
148
+ "details": security_result.info,
149
+ }
150
+ )
151
+
152
+ if not security_result.passed:
153
+ overall_passed = False
154
+ for error in security_result.errors:
155
+ errors.append({"gate": "Security Scans", "message": error})
156
+ else:
157
+ gates.append(
158
+ {
159
+ "name": "Security Scans",
160
+ "required": True,
161
+ "passed": True,
162
+ "details": {"skipped": "disabled"},
163
+ }
164
+ )
165
+ except ImportError as e:
166
+ logger.warning(f"Security checker not available: {e}")
167
+ gates.append(
168
+ {
169
+ "name": "Security Scans",
170
+ "required": True,
171
+ "passed": True,
172
+ "details": {"skipped": "checker not available"},
173
+ }
174
+ )
175
+
176
+ # Gate 3: Environment must be validated
177
+ logger.info("Validating deployment environment...")
178
+ env_passed = self._validate_deployment_environment()
179
+ gates.append(
180
+ {
181
+ "name": "Environment Validation",
182
+ "required": True,
183
+ "passed": env_passed,
184
+ }
185
+ )
186
+ if not env_passed:
187
+ overall_passed = False
188
+ errors.append(
189
+ {
190
+ "gate": "Environment Validation",
191
+ "message": "Deployment environment validation failed",
192
+ }
193
+ )
194
+
195
+ # Gate 4: Deployment documentation complete
196
+ logger.info("Validating deployment documentation...")
197
+ docs_passed = self._validate_deployment_documentation()
198
+ gates.append(
199
+ {
200
+ "name": "Deployment Documentation",
201
+ "required": True,
202
+ "passed": docs_passed,
203
+ }
204
+ )
205
+ if not docs_passed:
206
+ overall_passed = False
207
+ errors.append(
208
+ {
209
+ "gate": "Deployment Documentation",
210
+ "message": "Deployment documentation incomplete",
211
+ }
212
+ )
213
+
214
+ # Gate 5: Rollback procedure tested
215
+ logger.info("Checking rollback testing...")
216
+ rollback_tested = self._check_rollback_tested()
217
+ gates.append({"name": "Rollback Tested", "required": True, "passed": rollback_tested})
218
+ if not rollback_tested:
219
+ overall_passed = False
220
+ errors.append(
221
+ {
222
+ "gate": "Rollback Tested",
223
+ "message": "Rollback procedure not tested",
224
+ }
225
+ )
226
+
227
+ execution_time = time.time() - start_time
228
+
229
+ return CheckResult(
230
+ checker_name=self.name(),
231
+ passed=overall_passed,
232
+ status="passed" if overall_passed else "failed",
233
+ errors=cast(list[Union[dict[str, Any], str]], errors),
234
+ warnings=cast(list[Union[dict[str, Any], str]], warnings),
235
+ info={"gates": gates},
236
+ execution_time=execution_time,
237
+ )
238
+
239
+ def _validate_deployment_environment(self) -> bool:
240
+ """Validate deployment environment is ready.
241
+
242
+ Checks:
243
+ - Target environment extracted from work item specification
244
+ - Environment validator available and passes validation
245
+ - Falls back to True if validator not available
246
+
247
+ Returns:
248
+ True if environment validation passes, False otherwise
249
+ """
250
+ try:
251
+ from solokit.quality.env_validator import EnvironmentValidator
252
+
253
+ # Parse target environment from work item
254
+ # Try to extract from spec, fallback to "staging"
255
+ spec = self.work_item.get("specification", "")
256
+ environment = "staging" # Default fallback
257
+
258
+ # Simple pattern matching for common environment declarations
259
+ env_match = re.search(r"environment[:\s]+(\w+)", spec.lower())
260
+ if env_match:
261
+ environment = env_match.group(1)
262
+
263
+ logger.info(f"Validating deployment environment: {environment}")
264
+ validator = EnvironmentValidator(environment)
265
+ passed, _ = validator.validate_all()
266
+
267
+ return passed
268
+ except ImportError:
269
+ # If environment_validator not available, return True
270
+ logger.debug("Environment validator module not available, skipping validation")
271
+ return True
272
+
273
+ def _validate_deployment_documentation(self) -> bool:
274
+ """Validate deployment documentation is complete.
275
+
276
+ Required sections in work item specification:
277
+ - deployment procedure
278
+ - rollback procedure
279
+ - smoke tests
280
+ - monitoring & alerting
281
+
282
+ Returns:
283
+ True if all required sections present, False otherwise
284
+ """
285
+ spec = self.work_item.get("specification", "")
286
+
287
+ required_sections = [
288
+ "deployment procedure",
289
+ "rollback procedure",
290
+ "smoke tests",
291
+ "monitoring & alerting",
292
+ ]
293
+
294
+ missing_sections = []
295
+ for section in required_sections:
296
+ if section.lower() not in spec.lower():
297
+ missing_sections.append(section)
298
+ logger.warning(f"Missing required documentation section: {section}")
299
+
300
+ if missing_sections:
301
+ logger.error(
302
+ f"Deployment documentation incomplete. Missing: {', '.join(missing_sections)}"
303
+ )
304
+ return False
305
+
306
+ return True
307
+
308
+ def _check_rollback_tested(self) -> bool:
309
+ """Check if rollback procedure has been tested.
310
+
311
+ NOTE: Framework stub - Check deployment history for rollback test
312
+ When implemented, this should:
313
+ 1. Query deployment history/logs
314
+ 2. Check if rollback has been tested in staging/test environment
315
+ 3. Verify rollback completed successfully
316
+
317
+ Returns:
318
+ True by default to allow framework operation
319
+ """
320
+ # NOTE: Framework stub - Returns True to allow operation
321
+ # In production, implement actual rollback testing verification
322
+ logger.debug("Rollback testing check: Framework stub, returning True")
323
+ return True
@@ -0,0 +1,179 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Documentation validation checker.
4
+
5
+ Validates CHANGELOG updates, docstrings, and README currency.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ import sys
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 (
17
+ GIT_STANDARD_TIMEOUT,
18
+ QUALITY_CHECK_STANDARD_TIMEOUT,
19
+ )
20
+ from solokit.core.logging_config import get_logger
21
+ from solokit.quality.checkers.base import CheckResult, QualityChecker
22
+
23
+ logger = get_logger(__name__)
24
+
25
+
26
+ class DocumentationChecker(QualityChecker):
27
+ """Documentation requirements validation."""
28
+
29
+ def __init__(
30
+ self,
31
+ config: dict[str, Any],
32
+ project_root: Path | None = None,
33
+ work_item: dict[str, Any] | None = None,
34
+ runner: CommandRunner | None = None,
35
+ ):
36
+ """Initialize documentation checker.
37
+
38
+ Args:
39
+ config: Documentation configuration
40
+ project_root: Project root directory
41
+ work_item: Work item dictionary (optional, for README check)
42
+ runner: Optional CommandRunner instance (for testing)
43
+ """
44
+ super().__init__(config, project_root)
45
+ self.runner = (
46
+ runner
47
+ if runner is not None
48
+ else CommandRunner(default_timeout=QUALITY_CHECK_STANDARD_TIMEOUT)
49
+ )
50
+ self.work_item = work_item or {}
51
+
52
+ def name(self) -> str:
53
+ """Return checker name."""
54
+ return "documentation"
55
+
56
+ def is_enabled(self) -> bool:
57
+ """Check if documentation validation is enabled."""
58
+ return bool(self.config.get("enabled", True))
59
+
60
+ def run(self) -> CheckResult:
61
+ """Run documentation validation."""
62
+ start_time = time.time()
63
+
64
+ if not self.is_enabled():
65
+ return self._create_skipped_result()
66
+
67
+ logger.info("Running documentation validation")
68
+
69
+ checks = []
70
+ passed = True
71
+
72
+ # Check CHANGELOG updated
73
+ if self.config.get("check_changelog", False):
74
+ changelog_passed = self._check_changelog_updated()
75
+ checks.append({"name": "CHANGELOG updated", "passed": changelog_passed})
76
+ if not changelog_passed:
77
+ passed = False
78
+
79
+ # Check docstrings for Python
80
+ if self.config.get("check_docstrings", False):
81
+ docstrings_passed = self._check_python_docstrings()
82
+ checks.append({"name": "Docstrings present", "passed": docstrings_passed})
83
+ if not docstrings_passed:
84
+ passed = False
85
+
86
+ # Check README current
87
+ if self.config.get("check_readme", False):
88
+ readme_passed = self._check_readme_current()
89
+ checks.append({"name": "README current", "passed": readme_passed})
90
+ if not readme_passed:
91
+ passed = False
92
+
93
+ execution_time = time.time() - start_time
94
+
95
+ errors = []
96
+ for check in checks:
97
+ if not check["passed"]:
98
+ errors.append({"message": f"{check['name']} check failed"})
99
+
100
+ return CheckResult(
101
+ checker_name=self.name(),
102
+ passed=passed,
103
+ status="passed" if passed else "failed",
104
+ errors=cast(list[Union[dict[str, Any], str]], errors),
105
+ warnings=[],
106
+ info={"checks": checks},
107
+ execution_time=execution_time,
108
+ )
109
+
110
+ def _check_changelog_updated(self) -> bool:
111
+ """Check if CHANGELOG was updated in the current branch."""
112
+ # Get the current branch name
113
+ result = self.runner.run(
114
+ ["git", "rev-parse", "--abbrev-ref", "HEAD"], timeout=GIT_STANDARD_TIMEOUT
115
+ )
116
+ if not result.success:
117
+ logger.debug("Could not check CHANGELOG: git not available")
118
+ return True # Skip check if git not available
119
+
120
+ current_branch = result.stdout.strip()
121
+
122
+ # Don't check if we're on main/master
123
+ if current_branch in ["main", "master"]:
124
+ logger.debug("On main/master branch, skipping CHANGELOG check")
125
+ return True
126
+
127
+ # Check if CHANGELOG.md was modified in any commit on this branch
128
+ result = self.runner.run(
129
+ ["git", "log", "--name-only", "--pretty=format:", "main..HEAD"],
130
+ timeout=GIT_STANDARD_TIMEOUT,
131
+ )
132
+
133
+ if result.success and "CHANGELOG.md" in result.stdout:
134
+ logger.debug("CHANGELOG updated in branch")
135
+ return True
136
+ else:
137
+ logger.debug("CHANGELOG not updated in branch")
138
+ return False
139
+
140
+ def _check_python_docstrings(self) -> bool:
141
+ """Check if Python functions have docstrings."""
142
+ # Only check if this is a Python project
143
+ if (
144
+ not (self.project_root / "pyproject.toml").exists()
145
+ and not (self.project_root / "setup.py").exists()
146
+ ):
147
+ return True
148
+
149
+ result = self.runner.run(
150
+ [sys.executable, "-m", "pydocstyle", "--count"], timeout=QUALITY_CHECK_STANDARD_TIMEOUT
151
+ )
152
+
153
+ # If pydocstyle not available or timeout, skip check
154
+ if result.timed_out or result.returncode == -1:
155
+ logger.debug("pydocstyle not available, skipping docstring check")
156
+ return True
157
+
158
+ # If no issues found, return True
159
+ return result.returncode == 0
160
+
161
+ def _check_readme_current(self) -> bool:
162
+ """Check if README was updated (optional check)."""
163
+ result = self.runner.run(
164
+ ["git", "diff", "--name-only", "HEAD~1..HEAD"], timeout=GIT_STANDARD_TIMEOUT
165
+ )
166
+
167
+ if not result.success:
168
+ logger.debug("Could not check README: git not available")
169
+ return True # Skip check if git not available
170
+
171
+ changed_files = result.stdout.strip().split("\n")
172
+ readme_updated = any("README" in f.upper() for f in changed_files)
173
+
174
+ if readme_updated:
175
+ logger.debug("README updated")
176
+ else:
177
+ logger.debug("README not updated")
178
+
179
+ return readme_updated
@@ -0,0 +1,161 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Code formatting checker.
4
+
5
+ Runs formatters like black, prettier, 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 FormattingChecker(QualityChecker):
23
+ """Code formatting 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 formatting checker.
34
+
35
+ Args:
36
+ config: Formatting configuration
37
+ project_root: Project root directory
38
+ language: Programming language (python, javascript, typescript)
39
+ auto_fix: Whether to automatically format (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 "formatting"
54
+
55
+ def is_enabled(self) -> bool:
56
+ """Check if formatting 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 formatting 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 formatting for {self.language}")
79
+
80
+ # Get formatting command for language
81
+ commands = self.config.get("commands", {})
82
+ command = commands.get(self.language)
83
+ if not command:
84
+ logger.warning(f"No formatting command configured for language: {self.language}")
85
+ return self._create_skipped_result(reason=f"no command for {self.language}")
86
+
87
+ # Add appropriate flags based on auto_fix and language
88
+ if self.language == "python":
89
+ if not self.auto_fix:
90
+ command += " --check"
91
+ elif self.language in ["javascript", "typescript"]:
92
+ if self.auto_fix:
93
+ command += " --write"
94
+ else:
95
+ command += " --check"
96
+
97
+ # Run formatter
98
+ result = self.runner.run(command.split(), timeout=QUALITY_CHECK_VERY_LONG_TIMEOUT)
99
+
100
+ execution_time = time.time() - start_time
101
+
102
+ if result.timed_out:
103
+ required = self.config.get("required", False)
104
+ if required:
105
+ return CheckResult(
106
+ checker_name=self.name(),
107
+ passed=False,
108
+ status="failed",
109
+ errors=[{"message": "Formatting timed out"}],
110
+ warnings=[],
111
+ info={"reason": "timeout"},
112
+ execution_time=execution_time,
113
+ )
114
+ return CheckResult(
115
+ checker_name=self.name(),
116
+ passed=True,
117
+ status="skipped",
118
+ errors=[],
119
+ warnings=[],
120
+ info={"reason": "timeout"},
121
+ execution_time=execution_time,
122
+ )
123
+
124
+ # Tool not found
125
+ if result.returncode == -1:
126
+ required = self.config.get("required", False)
127
+ if required:
128
+ return CheckResult(
129
+ checker_name=self.name(),
130
+ passed=False,
131
+ status="failed",
132
+ errors=[{"message": "Required formatting tool not found"}],
133
+ warnings=[],
134
+ info={"reason": "tool not found"},
135
+ execution_time=execution_time,
136
+ )
137
+ return self._create_skipped_result(reason="formatting tool not available")
138
+
139
+ passed = result.returncode == 0
140
+
141
+ errors = []
142
+ if not passed:
143
+ errors.append(
144
+ {
145
+ "message": "Code formatting issues found",
146
+ "output": result.stdout[:500] if result.stdout else "",
147
+ }
148
+ )
149
+
150
+ return CheckResult(
151
+ checker_name=self.name(),
152
+ passed=passed,
153
+ status="passed" if passed else "failed",
154
+ errors=cast(list[Union[dict[str, Any], str]], errors),
155
+ warnings=[],
156
+ info={
157
+ "formatted": self.auto_fix,
158
+ "output": result.stdout[:1000] if result.stdout else "",
159
+ },
160
+ execution_time=execution_time,
161
+ )