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,436 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Generate and update technology stack documentation.
4
+
5
+ Detects:
6
+ - Languages (from file extensions)
7
+ - Frameworks (from imports and config files)
8
+ - Libraries (from requirements.txt, package.json, etc.)
9
+ - Databases (from connection strings, imports)
10
+ - MCP Servers (from context7 usage, etc.)
11
+ - External APIs (from code inspection)
12
+ """
13
+
14
+ from __future__ import annotations
15
+
16
+ import json
17
+ import re
18
+ from datetime import datetime
19
+ from pathlib import Path
20
+ from typing import Any
21
+
22
+ from solokit.core.error_handlers import log_errors
23
+ from solokit.core.exceptions import FileOperationError
24
+ from solokit.core.output import get_output
25
+
26
+ output = get_output()
27
+
28
+
29
+ class StackGenerator:
30
+ """Generate technology stack documentation."""
31
+
32
+ def __init__(self, project_root: Path | None = None):
33
+ """Initialize StackGenerator with project root path."""
34
+ self.project_root = project_root or Path.cwd()
35
+ self.stack_file = self.project_root / ".session" / "tracking" / "stack.txt"
36
+ self.updates_file = self.project_root / ".session" / "tracking" / "stack_updates.json"
37
+
38
+ def detect_languages(self) -> dict[str, str]:
39
+ """Detect programming languages from file extensions."""
40
+ languages = {}
41
+
42
+ # Count files by extension
43
+ extensions = {
44
+ ".py": ("Python", "python"),
45
+ ".js": ("JavaScript", "javascript"),
46
+ ".ts": ("TypeScript", "typescript"),
47
+ ".rs": ("Rust", "rust"),
48
+ ".go": ("Go", "go"),
49
+ ".java": ("Java", "java"),
50
+ ".cpp": ("C++", "cpp"),
51
+ ".c": ("C", "c"),
52
+ }
53
+
54
+ for ext, (name, key) in extensions.items():
55
+ files = list(self.project_root.rglob(f"*{ext}"))
56
+ # Exclude common non-source directories
57
+ files = [
58
+ f
59
+ for f in files
60
+ if not any(
61
+ part in f.parts
62
+ for part in [
63
+ "node_modules",
64
+ "venv",
65
+ ".venv",
66
+ "build",
67
+ "dist",
68
+ "__pycache__",
69
+ ]
70
+ )
71
+ ]
72
+
73
+ if files:
74
+ # Try to detect version
75
+ version = self._detect_language_version(key)
76
+ languages[name] = version or "detected"
77
+
78
+ return languages
79
+
80
+ def _detect_language_version(self, language: str) -> str:
81
+ """Detect language version from environment."""
82
+ from solokit.core.command_runner import CommandRunner
83
+ from solokit.core.constants import STACK_DETECTION_TIMEOUT
84
+ from solokit.core.error_handlers import safe_execute
85
+
86
+ version_commands = {
87
+ "python": ["python", "--version"],
88
+ "node": ["node", "--version"],
89
+ "rust": ["rustc", "--version"],
90
+ "go": ["go", "version"],
91
+ }
92
+
93
+ if language in version_commands:
94
+
95
+ def detect_version() -> str:
96
+ runner = CommandRunner(default_timeout=STACK_DETECTION_TIMEOUT)
97
+ result = runner.run(version_commands[language])
98
+ if result.success:
99
+ # Extract version number
100
+ version_match = re.search(r"(\d+\.\d+(?:\.\d+)?)", result.stdout)
101
+ if version_match:
102
+ return version_match.group(1)
103
+ return ""
104
+
105
+ result = safe_execute(detect_version, default="", log_errors=False)
106
+ return result or ""
107
+
108
+ return ""
109
+
110
+ def detect_frameworks(self) -> dict[str, list[str]]:
111
+ """Detect frameworks from imports and config files."""
112
+ from solokit.core.error_handlers import safe_execute
113
+
114
+ frameworks: dict[str, list[str]] = {
115
+ "backend": [],
116
+ "frontend": [],
117
+ "testing": [],
118
+ "database": [],
119
+ }
120
+
121
+ # Check Python imports
122
+ if (self.project_root / "requirements.txt").exists():
123
+ try:
124
+ requirements = (self.project_root / "requirements.txt").read_text()
125
+ if "fastapi" in requirements.lower():
126
+ version = self._extract_version(requirements, "fastapi")
127
+ frameworks["backend"].append(f"FastAPI {version}")
128
+ if "django" in requirements.lower():
129
+ version = self._extract_version(requirements, "django")
130
+ frameworks["backend"].append(f"Django {version}")
131
+ if "flask" in requirements.lower():
132
+ version = self._extract_version(requirements, "flask")
133
+ frameworks["backend"].append(f"Flask {version}")
134
+ if "sqlalchemy" in requirements.lower():
135
+ version = self._extract_version(requirements, "sqlalchemy")
136
+ frameworks["database"].append(f"SQLAlchemy {version}")
137
+ if "pytest" in requirements.lower():
138
+ frameworks["testing"].append("pytest")
139
+ except OSError as e:
140
+ raise FileOperationError(
141
+ operation="read",
142
+ file_path=str(self.project_root / "requirements.txt"),
143
+ details=str(e),
144
+ cause=e,
145
+ )
146
+
147
+ # Check JavaScript/TypeScript frameworks
148
+ if (self.project_root / "package.json").exists():
149
+
150
+ def parse_package_json() -> None:
151
+ try:
152
+ content = (self.project_root / "package.json").read_text()
153
+ package = json.loads(content)
154
+ deps = {
155
+ **package.get("dependencies", {}),
156
+ **package.get("devDependencies", {}),
157
+ }
158
+
159
+ if "react" in deps:
160
+ frameworks["frontend"].append(f"React {deps['react']}")
161
+ if "vue" in deps:
162
+ frameworks["frontend"].append(f"Vue {deps['vue']}")
163
+ if "next" in deps:
164
+ frameworks["frontend"].append(f"Next.js {deps['next']}")
165
+ if "jest" in deps:
166
+ frameworks["testing"].append("Jest")
167
+ except json.JSONDecodeError as e:
168
+ raise FileOperationError(
169
+ operation="parse",
170
+ file_path=str(self.project_root / "package.json"),
171
+ details=f"Invalid JSON: {e}",
172
+ cause=e,
173
+ )
174
+
175
+ safe_execute(parse_package_json, default=None, log_errors=False)
176
+
177
+ return {k: v for k, v in frameworks.items() if v}
178
+
179
+ def _extract_version(self, requirements: str, package: str) -> str:
180
+ """Extract version from requirements file."""
181
+ pattern = rf"{package}\s*[>=<~]+\s*([0-9.]+)"
182
+ match = re.search(pattern, requirements, re.IGNORECASE)
183
+ if match:
184
+ return match.group(1)
185
+ return ""
186
+
187
+ def detect_libraries(self) -> list[str]:
188
+ """Detect libraries from dependency files."""
189
+ libraries = []
190
+
191
+ # Python libraries
192
+ if (self.project_root / "requirements.txt").exists():
193
+ try:
194
+ requirements = (self.project_root / "requirements.txt").read_text()
195
+ for line in requirements.split("\n"):
196
+ line = line.strip()
197
+ if line and not line.startswith("#"):
198
+ # Extract package name and version
199
+ match = re.match(r"([a-zA-Z0-9_-]+)([>=<~]+.*)?", line)
200
+ if match:
201
+ libraries.append(line)
202
+ except OSError as e:
203
+ raise FileOperationError(
204
+ operation="read",
205
+ file_path=str(self.project_root / "requirements.txt"),
206
+ details=str(e),
207
+ cause=e,
208
+ )
209
+
210
+ return libraries[:20] # Limit to top 20
211
+
212
+ def detect_mcp_servers(self) -> list[str]:
213
+ """Detect MCP servers in use."""
214
+ from solokit.core.error_handlers import safe_execute
215
+
216
+ mcp_servers = []
217
+
218
+ # Check for context7 usage in code
219
+ for py_file in self.project_root.rglob("*.py"):
220
+
221
+ def read_py_file() -> bool:
222
+ content = py_file.read_text()
223
+ if "context7" in content.lower() or "mcp__context7" in content:
224
+ if "Context7 (library documentation)" not in mcp_servers:
225
+ mcp_servers.append("Context7 (library documentation)")
226
+ return True
227
+ return False
228
+
229
+ if safe_execute(read_py_file, default=False, log_errors=False):
230
+ break # Found it, no need to continue
231
+
232
+ return mcp_servers
233
+
234
+ def generate_stack_txt(self) -> str:
235
+ """Generate stack.txt content."""
236
+ languages = self.detect_languages()
237
+ frameworks = self.detect_frameworks()
238
+ libraries = self.detect_libraries()
239
+ mcp_servers = self.detect_mcp_servers()
240
+
241
+ lines = ["# Technology Stack\n"]
242
+
243
+ if languages:
244
+ lines.append("## Languages")
245
+ for name, version in languages.items():
246
+ lines.append(f"- {name} {version}")
247
+ lines.append("")
248
+
249
+ if frameworks.get("backend"):
250
+ lines.append("## Backend Framework")
251
+ for fw in frameworks["backend"]:
252
+ lines.append(f"- {fw}")
253
+ lines.append("")
254
+
255
+ if frameworks.get("frontend"):
256
+ lines.append("## Frontend Framework")
257
+ for fw in frameworks["frontend"]:
258
+ lines.append(f"- {fw}")
259
+ lines.append("")
260
+
261
+ if frameworks.get("database"):
262
+ lines.append("## Database")
263
+ for db in frameworks["database"]:
264
+ lines.append(f"- {db}")
265
+ lines.append("")
266
+
267
+ if mcp_servers:
268
+ lines.append("## MCP Servers")
269
+ for mcp in mcp_servers:
270
+ lines.append(f"- {mcp}")
271
+ lines.append("")
272
+
273
+ if frameworks.get("testing"):
274
+ lines.append("## Testing")
275
+ for test in frameworks["testing"]:
276
+ lines.append(f"- {test}")
277
+ lines.append("")
278
+
279
+ if libraries:
280
+ lines.append("## Key Libraries")
281
+ for lib in libraries:
282
+ lines.append(f"- {lib}")
283
+ lines.append("")
284
+
285
+ lines.append(f"Generated: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
286
+
287
+ return "\n".join(lines)
288
+
289
+ def detect_changes(self, old_content: str, new_content: str) -> list[dict]:
290
+ """Detect changes between old and new stack."""
291
+ old_lines = set(old_content.split("\n"))
292
+ new_lines = set(new_content.split("\n"))
293
+
294
+ added = new_lines - old_lines
295
+ removed = old_lines - new_lines
296
+
297
+ changes = []
298
+ for line in added:
299
+ if line.strip() and not line.startswith("#") and not line.startswith("Generated:"):
300
+ changes.append({"type": "addition", "content": line.strip()})
301
+
302
+ for line in removed:
303
+ if line.strip() and not line.startswith("#") and not line.startswith("Generated:"):
304
+ changes.append({"type": "removal", "content": line.strip()})
305
+
306
+ return changes
307
+
308
+ @log_errors()
309
+ def update_stack(
310
+ self, session_num: int | None = None, non_interactive: bool = False
311
+ ) -> list[dict[str, str]]:
312
+ """Generate/update stack.txt and detect changes.
313
+
314
+ Args:
315
+ session_num: Current session number
316
+ non_interactive: If True, skip interactive reasoning prompts
317
+ """
318
+ # Generate new stack content
319
+ new_content = self.generate_stack_txt()
320
+
321
+ # Load old content if exists
322
+ old_content = ""
323
+ if self.stack_file.exists():
324
+ try:
325
+ old_content = self.stack_file.read_text()
326
+ except OSError as e:
327
+ raise FileOperationError(
328
+ operation="read", file_path=str(self.stack_file), details=str(e), cause=e
329
+ )
330
+
331
+ # Detect changes
332
+ changes = self.detect_changes(old_content, new_content)
333
+
334
+ # Save new stack
335
+ try:
336
+ self.stack_file.parent.mkdir(parents=True, exist_ok=True)
337
+ self.stack_file.write_text(new_content)
338
+ except OSError as e:
339
+ raise FileOperationError(
340
+ operation="write", file_path=str(self.stack_file), details=str(e), cause=e
341
+ )
342
+
343
+ # If changes detected, prompt for reasoning (unless non-interactive)
344
+ if changes and session_num:
345
+ output.info(f"\n{'=' * 50}")
346
+ output.info("Stack Changes Detected")
347
+ output.info("=" * 50)
348
+
349
+ for change in changes:
350
+ output.info(f" {change['type'].upper()}: {change['content']}")
351
+
352
+ if non_interactive:
353
+ reasoning = "Automated update during session completion"
354
+ output.info("\n(Non-interactive mode: recording changes without manual reasoning)")
355
+ else:
356
+ output.info("\nPlease provide reasoning for these changes:")
357
+ reasoning = input("> ")
358
+
359
+ # Update stack_updates.json
360
+ self._record_stack_update(session_num, changes, reasoning)
361
+
362
+ return changes
363
+
364
+ def _record_stack_update(
365
+ self, session_num: int, changes: list[dict[str, Any]], reasoning: str
366
+ ) -> None:
367
+ """Record stack update in stack_updates.json."""
368
+ from solokit.core.error_handlers import safe_execute
369
+
370
+ updates: dict[str, Any] = {"updates": []}
371
+
372
+ if self.updates_file.exists():
373
+
374
+ def load_updates() -> dict[str, Any]:
375
+ try:
376
+ content = self.updates_file.read_text()
377
+ return json.loads(content) # type: ignore[no-any-return]
378
+ except json.JSONDecodeError as e:
379
+ raise FileOperationError(
380
+ operation="parse",
381
+ file_path=str(self.updates_file),
382
+ details=f"Invalid JSON: {e}",
383
+ cause=e,
384
+ )
385
+
386
+ loaded_updates = safe_execute(load_updates, default=None, log_errors=False)
387
+ if loaded_updates:
388
+ updates = loaded_updates
389
+
390
+ update_entry = {
391
+ "timestamp": datetime.now().isoformat(),
392
+ "session": session_num,
393
+ "changes": changes,
394
+ "reasoning": reasoning,
395
+ }
396
+
397
+ updates["updates"].append(update_entry)
398
+
399
+ try:
400
+ self.updates_file.write_text(json.dumps(updates, indent=2))
401
+ except OSError as e:
402
+ raise FileOperationError(
403
+ operation="write", file_path=str(self.updates_file), details=str(e), cause=e
404
+ )
405
+
406
+
407
+ def main() -> None:
408
+ """CLI entry point."""
409
+ import argparse
410
+
411
+ from solokit.core.output import get_output
412
+
413
+ output = get_output()
414
+
415
+ parser = argparse.ArgumentParser(description="Generate technology stack documentation")
416
+ parser.add_argument("--session", type=int, help="Current session number")
417
+ parser.add_argument(
418
+ "--non-interactive",
419
+ action="store_true",
420
+ help="Skip interactive prompts (use automated reasoning)",
421
+ )
422
+ args = parser.parse_args()
423
+
424
+ generator = StackGenerator()
425
+ changes = generator.update_stack(session_num=args.session, non_interactive=args.non_interactive)
426
+
427
+ if changes:
428
+ output.info(f"\n✓ Stack updated with {len(changes)} changes")
429
+ else:
430
+ output.info("\n✓ Stack generated (no changes)")
431
+
432
+ output.info(f"✓ Saved to: {generator.stack_file}")
433
+
434
+
435
+ if __name__ == "__main__":
436
+ main()