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,375 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Generate and update project tree documentation.
4
+
5
+ Tracks structural changes to the project with reasoning.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ import json
11
+ import sys
12
+ from datetime import datetime
13
+ from pathlib import Path
14
+ from typing import Any
15
+
16
+ from solokit.core.command_runner import CommandRunner
17
+ from solokit.core.constants import TREE_GENERATION_TIMEOUT
18
+ from solokit.core.error_handlers import log_errors
19
+ from solokit.core.exceptions import (
20
+ FileOperationError,
21
+ )
22
+ from solokit.core.output import get_output
23
+
24
+ output = get_output()
25
+
26
+
27
+ class TreeGenerator:
28
+ """Generate project tree documentation."""
29
+
30
+ def __init__(self, project_root: Path | None = None):
31
+ """Initialize TreeGenerator with project root path."""
32
+ self.project_root = project_root or Path.cwd()
33
+ self.tree_file = self.project_root / ".session" / "tracking" / "tree.txt"
34
+ self.updates_file = self.project_root / ".session" / "tracking" / "tree_updates.json"
35
+ self.runner = CommandRunner(
36
+ default_timeout=TREE_GENERATION_TIMEOUT, working_dir=self.project_root
37
+ )
38
+
39
+ # Items to ignore
40
+ self.ignore_patterns = [
41
+ # Version control
42
+ ".git",
43
+ # Python
44
+ "__pycache__",
45
+ "*.pyc",
46
+ ".pytest_cache",
47
+ ".venv",
48
+ "venv",
49
+ "*.egg-info",
50
+ ".mypy_cache",
51
+ ".ruff_cache",
52
+ # JavaScript/TypeScript
53
+ "node_modules",
54
+ ".next",
55
+ ".turbo",
56
+ "out",
57
+ "build",
58
+ "dist",
59
+ ".vercel",
60
+ "*.tsbuildinfo",
61
+ # Test coverage
62
+ "coverage",
63
+ ".nyc_output",
64
+ # Caches
65
+ ".cache",
66
+ # OS
67
+ ".DS_Store",
68
+ # Temp/logs
69
+ "*.log",
70
+ "*.tmp",
71
+ "*.backup",
72
+ # Solokit
73
+ ".session",
74
+ ]
75
+
76
+ @log_errors()
77
+ def generate_tree(self) -> str:
78
+ """Generate tree using tree command, falls back to Python implementation.
79
+
80
+ Returns:
81
+ str: Project tree representation
82
+
83
+ Raises:
84
+ FileOperationError: If tree generation fails completely
85
+ """
86
+ try:
87
+ # Build ignore arguments
88
+ ignore_args = []
89
+ for pattern in self.ignore_patterns:
90
+ ignore_args.extend(["-I", pattern])
91
+
92
+ result = self.runner.run(["tree", "-a", "--dirsfirst"] + ignore_args)
93
+
94
+ if result.success:
95
+ return result.stdout
96
+ else:
97
+ # tree command failed, use fallback
98
+ return self._generate_tree_fallback()
99
+
100
+ except (OSError, FileNotFoundError):
101
+ # tree command not available, use fallback
102
+ return self._generate_tree_fallback()
103
+
104
+ def _generate_tree_fallback(self) -> str:
105
+ """Fallback tree generation without tree command.
106
+
107
+ Returns:
108
+ str: Project tree representation
109
+
110
+ Raises:
111
+ FileOperationError: If filesystem operations fail
112
+ """
113
+ lines = [str(self.project_root.name) + "/"]
114
+
115
+ def should_ignore(path: Path) -> bool:
116
+ for pattern in self.ignore_patterns:
117
+ if pattern.startswith("*"):
118
+ if path.name.endswith(pattern[1:]):
119
+ return True
120
+ elif pattern in path.parts:
121
+ return True
122
+ return False
123
+
124
+ def add_tree(path: Path, prefix: str = "", is_last: bool = True) -> None:
125
+ if should_ignore(path):
126
+ return
127
+
128
+ connector = "└── " if is_last else "├── "
129
+ lines.append(prefix + connector + path.name)
130
+
131
+ if path.is_dir():
132
+ children = sorted(path.iterdir(), key=lambda p: (not p.is_dir(), p.name))
133
+ children = [c for c in children if not should_ignore(c)]
134
+
135
+ for i, child in enumerate(children):
136
+ is_last_child = i == len(children) - 1
137
+ extension = " " if is_last else "│ "
138
+ add_tree(child, prefix + extension, is_last_child)
139
+
140
+ # Generate tree
141
+ try:
142
+ children = sorted(self.project_root.iterdir(), key=lambda p: (not p.is_dir(), p.name))
143
+ children = [c for c in children if not should_ignore(c)]
144
+
145
+ for i, child in enumerate(children):
146
+ add_tree(child, "", i == len(children) - 1)
147
+
148
+ return "\n".join(lines)
149
+ except OSError as e:
150
+ raise FileOperationError(
151
+ operation="read",
152
+ file_path=str(self.project_root),
153
+ details="Failed to generate project tree",
154
+ cause=e,
155
+ ) from e
156
+
157
+ def detect_changes(self, old_tree: str, new_tree: str) -> list[dict]:
158
+ """Detect structural changes between trees."""
159
+ old_lines = set(old_tree.split("\n"))
160
+ new_lines = set(new_tree.split("\n"))
161
+
162
+ added = new_lines - old_lines
163
+ removed = old_lines - new_lines
164
+
165
+ changes = []
166
+
167
+ # Categorize changes
168
+ for line in added:
169
+ if "/" in line or line.strip().endswith("/"):
170
+ changes.append({"type": "directory_added", "path": line.strip()})
171
+ elif line.strip():
172
+ changes.append({"type": "file_added", "path": line.strip()})
173
+
174
+ for line in removed:
175
+ if "/" in line or line.strip().endswith("/"):
176
+ changes.append({"type": "directory_removed", "path": line.strip()})
177
+ elif line.strip():
178
+ changes.append({"type": "file_removed", "path": line.strip()})
179
+
180
+ return changes
181
+
182
+ @log_errors()
183
+ def update_tree(
184
+ self, session_num: int | None = None, non_interactive: bool = False
185
+ ) -> list[dict[str, str]]:
186
+ """Generate/update tree.txt and detect changes.
187
+
188
+ Args:
189
+ session_num: Current session number
190
+ non_interactive: If True, skip interactive reasoning prompts
191
+
192
+ Raises:
193
+ FileOperationError: If reading/writing tree files fails
194
+ """
195
+ # Generate new tree
196
+ new_tree = self.generate_tree()
197
+
198
+ # Load old tree if exists
199
+ old_tree = ""
200
+ if self.tree_file.exists():
201
+ try:
202
+ old_tree = self.tree_file.read_text()
203
+ except OSError as e:
204
+ raise FileOperationError(
205
+ operation="read",
206
+ file_path=str(self.tree_file),
207
+ details="Failed to read existing tree file",
208
+ cause=e,
209
+ ) from e
210
+
211
+ # Detect changes
212
+ changes = self.detect_changes(old_tree, new_tree)
213
+
214
+ # Filter out minor changes (just ordering, etc.)
215
+ significant_changes = [
216
+ c
217
+ for c in changes
218
+ if c["type"] in ["directory_added", "directory_removed"]
219
+ or len(changes) < 20 # If few changes, they're probably significant
220
+ ]
221
+
222
+ # Save new tree
223
+ try:
224
+ self.tree_file.parent.mkdir(parents=True, exist_ok=True)
225
+ self.tree_file.write_text(new_tree)
226
+ except OSError as e:
227
+ raise FileOperationError(
228
+ operation="write",
229
+ file_path=str(self.tree_file),
230
+ details="Failed to write tree file",
231
+ cause=e,
232
+ ) from e
233
+
234
+ # If significant changes detected, prompt for reasoning (unless non-interactive)
235
+ if significant_changes and session_num:
236
+ output.info(f"\n{'=' * 50}")
237
+ output.info("Structural Changes Detected")
238
+ output.info("=" * 50)
239
+
240
+ for change in significant_changes[:10]: # Show first 10
241
+ output.info(f" {change['type'].upper()}: {change['path']}")
242
+
243
+ if len(significant_changes) > 10:
244
+ output.info(f" ... and {len(significant_changes) - 10} more changes")
245
+
246
+ if non_interactive:
247
+ reasoning = "Automated update during session completion"
248
+ output.info("\n(Non-interactive mode: recording changes without manual reasoning)")
249
+ else:
250
+ output.info("\nPlease provide reasoning for these structural changes:")
251
+ reasoning = input("> ")
252
+
253
+ # Update tree_updates.json
254
+ self._record_tree_update(session_num, significant_changes, reasoning)
255
+
256
+ return changes
257
+
258
+ @log_errors()
259
+ def _record_tree_update(
260
+ self, session_num: int, changes: list[dict[str, Any]], reasoning: str
261
+ ) -> None:
262
+ """Record tree update in tree_updates.json.
263
+
264
+ Args:
265
+ session_num: Current session number
266
+ changes: List of detected changes
267
+ reasoning: User-provided reasoning for changes
268
+
269
+ Raises:
270
+ FileOperationError: If writing tree updates fails
271
+ """
272
+ updates: dict[str, Any] = {"updates": []}
273
+
274
+ if self.updates_file.exists():
275
+ try:
276
+ updates = json.loads(self.updates_file.read_text())
277
+ except (json.JSONDecodeError, OSError):
278
+ # If tree_updates.json is corrupted or unreadable, start fresh
279
+ # Log warning but don't fail - we can rebuild the history
280
+ updates = {"updates": []}
281
+
282
+ update_entry = {
283
+ "timestamp": datetime.now().isoformat(),
284
+ "session": session_num,
285
+ "changes": changes,
286
+ "reasoning": reasoning,
287
+ "architecture_impact": "", # Could prompt for this too
288
+ }
289
+
290
+ updates["updates"].append(update_entry)
291
+
292
+ try:
293
+ self.updates_file.write_text(json.dumps(updates, indent=2))
294
+ except OSError as e:
295
+ raise FileOperationError(
296
+ operation="write",
297
+ file_path=str(self.updates_file),
298
+ details="Failed to write tree updates",
299
+ cause=e,
300
+ ) from e
301
+
302
+
303
+ def main() -> None:
304
+ """CLI entry point.
305
+
306
+ Handles exceptions and provides user-friendly error messages.
307
+ """
308
+ import argparse
309
+
310
+ from solokit.core.exceptions import SolokitError
311
+ from solokit.core.output import get_output
312
+
313
+ output = get_output()
314
+
315
+ parser = argparse.ArgumentParser(description="Generate project tree documentation")
316
+ parser.add_argument("--session", type=int, help="Current session number")
317
+ parser.add_argument("--show-changes", action="store_true", help="Show changes from last run")
318
+ parser.add_argument(
319
+ "--non-interactive",
320
+ action="store_true",
321
+ help="Skip interactive prompts (use automated reasoning)",
322
+ )
323
+ args = parser.parse_args()
324
+
325
+ try:
326
+ generator = TreeGenerator()
327
+
328
+ if args.show_changes:
329
+ if generator.updates_file.exists():
330
+ try:
331
+ updates = json.loads(generator.updates_file.read_text())
332
+ output.info("Recent structural changes:")
333
+ for update in updates["updates"][-5:]:
334
+ output.info(f"\nSession {update['session']} ({update['timestamp']})")
335
+ output.info(f"Reasoning: {update['reasoning']}")
336
+ output.info(f"Changes: {len(update['changes'])}")
337
+ except (json.JSONDecodeError, KeyError) as e:
338
+ raise FileOperationError(
339
+ operation="read",
340
+ file_path=str(generator.updates_file),
341
+ details="Failed to parse tree updates file",
342
+ cause=e,
343
+ ) from e
344
+ else:
345
+ output.info("No tree updates recorded yet")
346
+ else:
347
+ changes = generator.update_tree(
348
+ session_num=args.session, non_interactive=args.non_interactive
349
+ )
350
+
351
+ if changes:
352
+ output.info(f"\n✓ Tree updated with {len(changes)} changes")
353
+ else:
354
+ output.info("\n✓ Tree generated (no changes)")
355
+
356
+ output.info(f"✓ Saved to: {generator.tree_file}")
357
+
358
+ except SolokitError as e:
359
+ # Handle structured Solokit errors with user-friendly output
360
+ output.error(f"\nError: {e.message}")
361
+ if e.remediation:
362
+ output.error(f"Suggestion: {e.remediation}")
363
+ sys.exit(e.exit_code)
364
+ except KeyboardInterrupt:
365
+ output.error("\n\nOperation cancelled by user.")
366
+ sys.exit(130)
367
+ except Exception as e:
368
+ # Unexpected errors
369
+ output.error(f"\nUnexpected error: {e}")
370
+ output.error("Please report this issue.")
371
+ sys.exit(1)
372
+
373
+
374
+ if __name__ == "__main__":
375
+ main()
@@ -0,0 +1 @@
1
+ """Quality gates, validation, and testing infrastructure."""