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,476 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Briefing formatting and generation.
4
+ Part of the briefing module decomposition.
5
+ """
6
+
7
+ import sys
8
+ from pathlib import Path
9
+ from typing import Optional
10
+
11
+ from solokit.core.command_runner import CommandRunner
12
+ from solokit.core.constants import SESSION_STATUS_TIMEOUT
13
+ from solokit.core.exceptions import (
14
+ FileOperationError,
15
+ )
16
+ from solokit.core.logging_config import get_logger
17
+ from solokit.core.types import WorkItemStatus, WorkItemType
18
+
19
+ logger = get_logger(__name__)
20
+
21
+
22
+ class BriefingFormatter:
23
+ """Format briefing content and generate output."""
24
+
25
+ def __init__(self) -> None:
26
+ """Initialize briefing formatter."""
27
+ self.runner = CommandRunner(default_timeout=SESSION_STATUS_TIMEOUT)
28
+
29
+ def shift_heading_levels(self, markdown_content: str, shift: int) -> str:
30
+ r"""Shift all markdown heading levels by a specified amount.
31
+
32
+ Args:
33
+ markdown_content: The markdown text to process
34
+ shift: Number of levels to shift (positive = deeper, e.g., H1 → H3 if shift=2)
35
+
36
+ Returns:
37
+ Modified markdown with shifted heading levels
38
+
39
+ Example:
40
+ shift_heading_levels("# Title\n## Section", 2)
41
+ Returns: "### Title\n#### Section"
42
+ """
43
+ if not markdown_content or shift <= 0:
44
+ return markdown_content
45
+
46
+ lines = markdown_content.split("\n")
47
+ result = []
48
+
49
+ for line in lines:
50
+ # Check if line starts with heading marker
51
+ if line.startswith("#"):
52
+ # Count existing heading level
53
+ heading_level = 0
54
+ for char in line:
55
+ if char == "#":
56
+ heading_level += 1
57
+ else:
58
+ break
59
+
60
+ # Calculate new level (cap at 6 for markdown)
61
+ new_level = min(heading_level + shift, 6)
62
+
63
+ # Reconstruct line with new heading level
64
+ rest_of_line = line[heading_level:]
65
+ result.append("#" * new_level + rest_of_line)
66
+ else:
67
+ result.append(line)
68
+
69
+ return "\n".join(result)
70
+
71
+ def extract_section(self, markdown: str, heading: str) -> str:
72
+ """Extract section from markdown between heading and next ## heading.
73
+
74
+ Args:
75
+ markdown: Full markdown content
76
+ heading: Heading to find (e.g., "## Commits Made")
77
+
78
+ Returns:
79
+ Section content (without the heading itself)
80
+ """
81
+ lines = markdown.split("\n")
82
+ section_lines = []
83
+ in_section = False
84
+
85
+ for line in lines:
86
+ if line.startswith(heading):
87
+ in_section = True
88
+ continue
89
+ elif in_section and line.startswith("## "):
90
+ break
91
+ elif in_section:
92
+ section_lines.append(line)
93
+
94
+ return "\n".join(section_lines).strip()
95
+
96
+ def generate_previous_work_section(self, item_id: str, item: dict) -> str:
97
+ """Generate previous work context from session summaries.
98
+
99
+ Args:
100
+ item_id: Work item identifier
101
+ item: Work item dictionary with sessions list
102
+
103
+ Returns:
104
+ Markdown section with previous work context (empty string if none)
105
+ """
106
+ sessions = item.get("sessions", [])
107
+ if not sessions:
108
+ return ""
109
+
110
+ section = "\n## Previous Work\n\n"
111
+ section += f"This work item has been in progress across {len(sessions)} session(s).\n\n"
112
+
113
+ for session_info in sessions:
114
+ session_num = session_info["session_num"]
115
+ started_at = session_info.get("started_at", "")
116
+
117
+ summary_file = Path(f".session/history/session_{session_num:03d}_summary.md")
118
+ if not summary_file.exists():
119
+ continue
120
+
121
+ try:
122
+ summary_content = summary_file.read_text()
123
+ except OSError as e:
124
+ raise FileOperationError(
125
+ operation="read",
126
+ file_path=str(summary_file),
127
+ details=f"Failed to read session summary: {str(e)}",
128
+ cause=e,
129
+ )
130
+ section += f"### Session {session_num} ({started_at[:10]})\n\n"
131
+
132
+ # Extract commits section
133
+ if "## Commits Made" in summary_content:
134
+ commits = self.extract_section(summary_content, "## Commits Made")
135
+ if commits:
136
+ section += commits + "\n\n"
137
+
138
+ # Extract quality gates
139
+ if "## Quality Gates" in summary_content:
140
+ gates = self.extract_section(summary_content, "## Quality Gates")
141
+ if gates:
142
+ section += "**Quality Gates:**\n" + gates + "\n\n"
143
+
144
+ return section
145
+
146
+ def validate_environment(self) -> list[str]:
147
+ """Validate development environment.
148
+
149
+ Returns:
150
+ List of environment check strings
151
+ """
152
+ checks = []
153
+
154
+ # Check Python version
155
+ checks.append(f"Python: {sys.version.split()[0]}")
156
+
157
+ # Check git
158
+ result = self.runner.run(["git", "--version"])
159
+ if result.success:
160
+ checks.append(f"Git: {result.stdout.strip()}")
161
+ else:
162
+ checks.append("Git: NOT FOUND")
163
+
164
+ return checks
165
+
166
+ def check_command_exists(self, command: str) -> bool:
167
+ """Check if a command is available.
168
+
169
+ Args:
170
+ command: Command to check
171
+
172
+ Returns:
173
+ True if command exists, False otherwise
174
+ """
175
+ result = self.runner.run([command, "--version"])
176
+ return result.success
177
+
178
+ def generate_integration_test_briefing(self, work_item: dict) -> str:
179
+ """Generate integration test specific briefing sections.
180
+
181
+ Args:
182
+ work_item: Integration test work item
183
+
184
+ Returns:
185
+ Additional briefing sections for integration tests
186
+ """
187
+ if work_item.get("type") != WorkItemType.INTEGRATION_TEST.value:
188
+ return ""
189
+
190
+ briefing = "\n## Integration Test Context\n\n"
191
+
192
+ # 1. Components being integrated (from scope description)
193
+ scope = work_item.get("scope", "")
194
+ if scope and len(scope) > 20:
195
+ briefing += "**Integration Scope:**\n"
196
+ briefing += f"{scope[:200]}...\n\n" if len(scope) > 200 else f"{scope}\n\n"
197
+
198
+ # 2. Environment requirements
199
+ env_requirements = work_item.get("environment_requirements", {})
200
+ services = env_requirements.get("services_required", [])
201
+
202
+ if services:
203
+ briefing += "**Required Services:**\n"
204
+ for service in services:
205
+ briefing += f"- {service}\n"
206
+ briefing += "\n"
207
+
208
+ # 3. Test scenarios summary
209
+ scenarios = work_item.get("test_scenarios", [])
210
+ if scenarios:
211
+ briefing += f"**Test Scenarios ({len(scenarios)} total):**\n"
212
+ for i, scenario in enumerate(scenarios[:5], 1): # Show first 5
213
+ scenario_name = scenario.get("name", scenario.get("description", f"Scenario {i}"))
214
+ briefing += f"{i}. {scenario_name}\n"
215
+
216
+ if len(scenarios) > 5:
217
+ briefing += f"... and {len(scenarios) - 5} more scenarios\n"
218
+ briefing += "\n"
219
+
220
+ # 4. Performance benchmarks
221
+ benchmarks = work_item.get("performance_benchmarks", {})
222
+ if benchmarks:
223
+ briefing += "**Performance Requirements:**\n"
224
+
225
+ response_time = benchmarks.get("response_time", {})
226
+ if response_time:
227
+ briefing += f"- Response time: p95 < {response_time.get('p95', 'N/A')}ms\n"
228
+
229
+ throughput = benchmarks.get("throughput", {})
230
+ if throughput:
231
+ briefing += f"- Throughput: > {throughput.get('minimum', 'N/A')} req/s\n"
232
+
233
+ briefing += "\n"
234
+
235
+ # 5. API contracts
236
+ contracts = work_item.get("api_contracts", [])
237
+ if contracts:
238
+ briefing += f"**API Contracts ({len(contracts)} contracts):**\n"
239
+ for contract in contracts:
240
+ contract_file = contract.get("contract_file", "N/A")
241
+ contract_version = contract.get("version", "N/A")
242
+ briefing += f"- {contract_file} (version: {contract_version})\n"
243
+ briefing += "\n"
244
+
245
+ # 6. Environment validation status
246
+ briefing += "**Pre-Session Checks:**\n"
247
+
248
+ # Check Docker
249
+ docker_available = self.check_command_exists("docker")
250
+ briefing += f"- Docker: {'✓ Available' if docker_available else '✗ Not found'}\n"
251
+
252
+ # Check Docker Compose
253
+ compose_available = self.check_command_exists("docker-compose")
254
+ briefing += f"- Docker Compose: {'✓ Available' if compose_available else '✗ Not found'}\n"
255
+
256
+ # Check compose file
257
+ compose_file = env_requirements.get("compose_file", "docker-compose.integration.yml")
258
+ compose_exists = Path(compose_file).exists()
259
+ status_text = "✓ Found" if compose_exists else "✗ Missing"
260
+ briefing += f"- Compose file ({compose_file}): {status_text}\n"
261
+
262
+ briefing += "\n"
263
+
264
+ return briefing
265
+
266
+ def generate_deployment_briefing(self, work_item: dict) -> str:
267
+ """Generate deployment-specific briefing section.
268
+
269
+ Args:
270
+ work_item: Deployment work item
271
+
272
+ Returns:
273
+ Deployment briefing text
274
+ """
275
+ if work_item.get("type") != WorkItemType.DEPLOYMENT.value:
276
+ return ""
277
+
278
+ briefing = []
279
+ briefing.append("\n" + "=" * 60)
280
+ briefing.append("DEPLOYMENT CONTEXT")
281
+ briefing.append("=" * 60)
282
+
283
+ spec = work_item.get("specification", "")
284
+
285
+ # Parse deployment scope
286
+ briefing.append("\n**Deployment Scope:**")
287
+ # NOTE: Framework stub - Parse deployment scope from spec using spec_parser.py
288
+ # Extract "## Deployment Scope" section and parse Application/Environment/Version fields
289
+ briefing.append(" Application: [parse from spec]")
290
+ briefing.append(" Environment: [parse from spec]")
291
+ briefing.append(" Version: [parse from spec]")
292
+
293
+ # Parse deployment procedure
294
+ briefing.append("\n**Deployment Procedure:**")
295
+ # NOTE: Framework stub - Parse deployment steps from spec using spec_parser.py
296
+ # Extract "## Deployment Steps" section and count pre/during/post steps
297
+ briefing.append(" Pre-deployment: [X steps]")
298
+ briefing.append(" Deployment: [Y steps]")
299
+ briefing.append(" Post-deployment: [Z steps]")
300
+
301
+ # Parse rollback procedure
302
+ briefing.append("\n**Rollback Procedure:**")
303
+ # NOTE: Framework stub - Parse rollback details from spec using spec_parser.py
304
+ # Extract "## Rollback Procedure" section for triggers and time estimates
305
+ has_rollback = "rollback procedure" in spec.lower()
306
+ briefing.append(f" Rollback triggers defined: {'Yes' if has_rollback else 'No'}")
307
+ briefing.append(" Estimated rollback time: [X minutes]")
308
+
309
+ # Environment pre-checks
310
+ briefing.append("\n**Pre-Session Environment Checks:**")
311
+ try:
312
+ from solokit.quality.env_validator import EnvironmentValidator
313
+
314
+ # NOTE: Framework stub - Parse target environment from spec using spec_parser.py
315
+ # Extract from "## Deployment Scope" or "## Environment" section
316
+ environment = "staging" # Default fallback
317
+ validator = EnvironmentValidator(environment)
318
+ passed, results = validator.validate_all()
319
+
320
+ briefing.append(f" Environment validation: {'✓ PASSED' if passed else '✗ FAILED'}")
321
+ for validation in results.get("validations", []):
322
+ status = "✓" if validation["passed"] else "✗"
323
+ briefing.append(f" {status} {validation['name']}")
324
+ except ImportError as e:
325
+ logger.warning(
326
+ "EnvironmentValidator module not available",
327
+ extra={"error": str(e), "module": "solokit.quality.env_validator"},
328
+ )
329
+ briefing.append(" Environment validation: ✗ Module not available")
330
+ except Exception as e:
331
+ logger.error(
332
+ "Environment validation failed",
333
+ extra={"error": str(e), "environment": "staging"},
334
+ )
335
+ briefing.append(f" Environment validation: ✗ Error ({str(e)})")
336
+
337
+ briefing.append("\n" + "=" * 60)
338
+
339
+ return "\n".join(briefing)
340
+
341
+ def generate_briefing(
342
+ self,
343
+ item_id: str,
344
+ item: dict,
345
+ project_docs: dict[str, str],
346
+ current_stack: str,
347
+ current_tree: str,
348
+ work_item_spec: str,
349
+ env_checks: list[str],
350
+ git_status: dict,
351
+ spec_validation_warning: Optional[str],
352
+ milestone_context: Optional[dict],
353
+ relevant_learnings: list[dict],
354
+ ) -> str:
355
+ """Generate comprehensive markdown briefing with full project context.
356
+
357
+ Args:
358
+ item_id: Work item identifier
359
+ item: Work item dictionary
360
+ project_docs: Project documentation (dict of filename -> content)
361
+ current_stack: Technology stack information
362
+ current_tree: Project directory tree
363
+ work_item_spec: Work item specification content
364
+ env_checks: Environment validation checks
365
+ git_status: Git status information
366
+ spec_validation_warning: Optional spec validation warning
367
+ milestone_context: Optional milestone context
368
+ relevant_learnings: List of relevant learnings
369
+
370
+ Returns:
371
+ Complete briefing as markdown string
372
+ """
373
+ # Start briefing
374
+ briefing = f"""# Session Briefing: {item["title"]}
375
+
376
+ ## Quick Reference
377
+ - **Work Item ID:** {item_id}
378
+ - **Type:** {item["type"]}
379
+ - **Priority:** {item["priority"]}
380
+ - **Status:** {item["status"]}
381
+
382
+ ## Environment Status
383
+ """
384
+
385
+ # Show environment checks
386
+ for check in env_checks:
387
+ briefing += f"- {check}\n"
388
+
389
+ # Show git status
390
+ briefing += "\n### Git Status\n"
391
+ briefing += f"- Status: {git_status['status']}\n"
392
+ if git_status.get("branch"):
393
+ briefing += f"- Current Branch: {git_status['branch']}\n"
394
+
395
+ # Project context section
396
+ briefing += "\n## Project Context\n\n"
397
+
398
+ # Vision (if available) - shift headings to maintain hierarchy under H3
399
+ if "vision.md" in project_docs:
400
+ shifted_vision = self.shift_heading_levels(project_docs["vision.md"], 3)
401
+ briefing += f"### Vision\n\n{shifted_vision}\n\n"
402
+
403
+ # Architecture (if available) - shift headings to maintain hierarchy under H3
404
+ if "architecture.md" in project_docs:
405
+ shifted_arch = self.shift_heading_levels(project_docs["architecture.md"], 3)
406
+ briefing += f"### Architecture\n\n{shifted_arch}\n\n"
407
+
408
+ # Current stack
409
+ briefing += f"### Current Stack\n```\n{current_stack}\n```\n\n"
410
+
411
+ # Project structure - full tree
412
+ briefing += f"### Project Structure\n```\n{current_tree}\n```\n\n"
413
+
414
+ # Spec validation warning (if spec is incomplete)
415
+ if spec_validation_warning:
416
+ briefing += f"""## ⚠️ Specification Validation Warning
417
+
418
+ {spec_validation_warning}
419
+
420
+ **Note:** Please review and complete the specification before proceeding with implementation.
421
+
422
+ """
423
+
424
+ # Add previous work section for in-progress items (Enhancement #11 Phase 3)
425
+ if item.get("status") == WorkItemStatus.IN_PROGRESS.value:
426
+ previous_work = self.generate_previous_work_section(item_id, item)
427
+ if previous_work:
428
+ briefing += previous_work
429
+
430
+ # Work item specification - shift headings to maintain hierarchy under H2
431
+ shifted_spec = self.shift_heading_levels(work_item_spec, 2)
432
+ briefing += f"""## Work Item Specification
433
+
434
+ {shifted_spec}
435
+
436
+ ## Dependencies
437
+ """
438
+
439
+ # Show dependency status
440
+ if item.get("dependencies"):
441
+ for dep in item["dependencies"]:
442
+ briefing += f"- {dep} ✓ completed\n"
443
+ else:
444
+ briefing += "No dependencies\n"
445
+
446
+ # Add milestone context
447
+ if milestone_context:
448
+ briefing += f"""
449
+ ## Milestone Context
450
+
451
+ **{milestone_context["title"]}**
452
+ {milestone_context["description"]}
453
+
454
+ Progress: {milestone_context["progress"]}% ({milestone_context["completed_items"]}"""
455
+ briefing += f"""/{milestone_context["total_items"]} items complete)
456
+ """
457
+ if milestone_context["target_date"]:
458
+ briefing += f"Target Date: {milestone_context['target_date']}\n"
459
+
460
+ briefing += "\nRelated work items in this milestone:\n"
461
+ # Show other items in same milestone
462
+ for related_item in milestone_context["milestone_items"]:
463
+ if related_item["id"] != item_id:
464
+ status_icon = (
465
+ "✓" if related_item["status"] == WorkItemStatus.COMPLETED.value else "○"
466
+ )
467
+ briefing += f"- {status_icon} {related_item['id']} - {related_item['title']}\n"
468
+ briefing += "\n"
469
+
470
+ # Relevant learnings
471
+ if relevant_learnings:
472
+ briefing += "\n## Relevant Learnings\n\n"
473
+ for learning in relevant_learnings:
474
+ briefing += f"**{learning.get('category', 'general')}:** {learning['content']}\n\n"
475
+
476
+ return briefing