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,137 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Session briefing orchestrator.
4
+ Coordinates all briefing components to generate comprehensive session briefings.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ from pathlib import Path
10
+
11
+ from solokit.core.exceptions import GitError, SystemError
12
+ from solokit.core.logging_config import get_logger
13
+
14
+ from .documentation_loader import DocumentationLoader
15
+ from .formatter import BriefingFormatter
16
+ from .git_context import GitContext
17
+ from .learning_loader import LearningLoader
18
+ from .milestone_builder import MilestoneBuilder
19
+ from .stack_detector import StackDetector
20
+ from .tree_generator import TreeGenerator
21
+ from .work_item_loader import WorkItemLoader
22
+
23
+ logger = get_logger(__name__)
24
+
25
+
26
+ class SessionBriefing:
27
+ """Orchestrate generation of comprehensive session briefings."""
28
+
29
+ def __init__(
30
+ self,
31
+ session_dir: Path | None = None,
32
+ project_root: Path | None = None,
33
+ ):
34
+ """Initialize session briefing orchestrator.
35
+
36
+ Args:
37
+ session_dir: Path to .session directory (defaults to .session)
38
+ project_root: Path to project root (defaults to current directory)
39
+ """
40
+ self.session_dir = session_dir or Path(".session")
41
+ self.project_root = project_root or Path.cwd()
42
+
43
+ # Initialize all component modules
44
+ self.work_item_loader = WorkItemLoader(session_dir=self.session_dir)
45
+ self.learning_loader = LearningLoader(session_dir=self.session_dir)
46
+ self.doc_loader = DocumentationLoader(project_root=self.project_root)
47
+ self.stack_detector = StackDetector(session_dir=self.session_dir)
48
+ self.tree_generator = TreeGenerator(session_dir=self.session_dir)
49
+ self.git_context = GitContext()
50
+ self.milestone_builder = MilestoneBuilder(session_dir=self.session_dir)
51
+ self.formatter = BriefingFormatter()
52
+
53
+ def generate_briefing(self, item_id: str, item: dict, learnings_data: dict) -> str:
54
+ """Generate comprehensive markdown briefing with full project context.
55
+
56
+ Args:
57
+ item_id: Work item identifier
58
+ item: Work item dictionary
59
+ learnings_data: Full learnings data structure
60
+
61
+ Returns:
62
+ Complete briefing as markdown string
63
+ """
64
+ # Load all context using specialized modules
65
+ project_docs = self.doc_loader.load_project_docs()
66
+ current_stack = self.stack_detector.load_current_stack()
67
+ current_tree = self.tree_generator.load_current_tree()
68
+ work_item_spec = self.work_item_loader.load_work_item_spec(item)
69
+ env_checks = self.formatter.validate_environment()
70
+
71
+ # Check git status - gracefully handle errors as this is informational
72
+ try:
73
+ git_status = self.git_context.check_git_status()
74
+ except (GitError, SystemError) as e:
75
+ logger.warning(f"Failed to check git status: {e.message}")
76
+ git_status = {"clean": False, "status": f"Error: {e.message}", "branch": None}
77
+
78
+ # Validate spec completeness
79
+ spec_validation_warning = self._validate_spec(item_id, item["type"])
80
+
81
+ # Get milestone context
82
+ milestone_context = self.milestone_builder.load_milestone_context(item)
83
+
84
+ # Get relevant learnings
85
+ relevant_learnings = self.learning_loader.get_relevant_learnings(
86
+ learnings_data, item, work_item_spec
87
+ )
88
+
89
+ # Generate briefing using formatter
90
+ return self.formatter.generate_briefing(
91
+ item_id=item_id,
92
+ item=item,
93
+ project_docs=project_docs,
94
+ current_stack=current_stack,
95
+ current_tree=current_tree,
96
+ work_item_spec=work_item_spec,
97
+ env_checks=env_checks,
98
+ git_status=git_status,
99
+ spec_validation_warning=spec_validation_warning,
100
+ milestone_context=milestone_context,
101
+ relevant_learnings=relevant_learnings,
102
+ )
103
+
104
+ def _validate_spec(self, item_id: str, work_item_type: str) -> str | None:
105
+ """Validate spec completeness and return warning if incomplete.
106
+
107
+ Args:
108
+ item_id: Work item identifier
109
+ work_item_type: Type of work item
110
+
111
+ Returns:
112
+ Validation warning string or None if valid
113
+ """
114
+ try:
115
+ from solokit.core.exceptions import FileNotFoundError as SolokitFileNotFoundError
116
+ from solokit.core.exceptions import SpecValidationError
117
+ from solokit.work_items.spec_validator import (
118
+ format_validation_report,
119
+ validate_spec_file,
120
+ )
121
+
122
+ try:
123
+ validate_spec_file(item_id, work_item_type)
124
+ # If no exception, spec is valid
125
+ return None
126
+ except SpecValidationError as e:
127
+ # Spec has validation errors
128
+ return format_validation_report(item_id, work_item_type, e)
129
+ except (SolokitFileNotFoundError, Exception):
130
+ # Spec file doesn't exist or other error - this is not critical for briefing
131
+ # Just return None and let the briefing proceed
132
+ return None
133
+ except ImportError:
134
+ # Gracefully handle if spec_validator not available
135
+ logger.debug("Spec validator not available")
136
+
137
+ return None
@@ -0,0 +1,51 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Technology stack detection and information loading.
4
+ Part of the briefing module decomposition.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ from pathlib import Path
10
+
11
+ from solokit.core.error_handlers import log_errors
12
+ from solokit.core.exceptions import FileOperationError
13
+ from solokit.core.logging_config import get_logger
14
+
15
+ logger = get_logger(__name__)
16
+
17
+
18
+ class StackDetector:
19
+ """Detect and load technology stack information."""
20
+
21
+ def __init__(self, session_dir: Path | None = None):
22
+ """Initialize stack detector.
23
+
24
+ Args:
25
+ session_dir: Path to .session directory (defaults to .session)
26
+ """
27
+ self.session_dir = session_dir or Path(".session")
28
+ self.stack_file = self.session_dir / "tracking" / "stack.txt"
29
+
30
+ @log_errors()
31
+ def load_current_stack(self) -> str:
32
+ """Load current technology stack.
33
+
34
+ Returns:
35
+ Stack information as string
36
+
37
+ Raises:
38
+ FileOperationError: If stack file exists but cannot be read
39
+ """
40
+ if not self.stack_file.exists():
41
+ return "Stack not yet generated"
42
+
43
+ try:
44
+ return self.stack_file.read_text()
45
+ except OSError as e:
46
+ raise FileOperationError(
47
+ operation="read",
48
+ file_path=str(self.stack_file),
49
+ details=f"Failed to read stack file: {e}",
50
+ cause=e,
51
+ ) from e
@@ -0,0 +1,52 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Project directory tree loading.
4
+ Part of the briefing module decomposition.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ from pathlib import Path
10
+
11
+ from solokit.core.error_handlers import log_errors
12
+ from solokit.core.exceptions import FileOperationError
13
+ from solokit.core.logging_config import get_logger
14
+
15
+ logger = get_logger(__name__)
16
+
17
+
18
+ class TreeGenerator:
19
+ """Load and generate project directory tree."""
20
+
21
+ def __init__(self, session_dir: Path | None = None):
22
+ """Initialize tree generator.
23
+
24
+ Args:
25
+ session_dir: Path to .session directory (defaults to .session)
26
+ """
27
+ self.session_dir = session_dir or Path(".session")
28
+ self.tree_file = self.session_dir / "tracking" / "tree.txt"
29
+
30
+ @log_errors()
31
+ def load_current_tree(self) -> str:
32
+ """Load current project structure.
33
+
34
+ Returns:
35
+ Project tree as string
36
+
37
+ Raises:
38
+ FileOperationError: If tree file exists but cannot be read
39
+ """
40
+ if not self.tree_file.exists():
41
+ return "Tree not yet generated"
42
+
43
+ try:
44
+ # Return full tree
45
+ return self.tree_file.read_text()
46
+ except OSError as e:
47
+ raise FileOperationError(
48
+ operation="read",
49
+ file_path=str(self.tree_file),
50
+ details=f"Failed to read tree file: {e}",
51
+ cause=e,
52
+ ) from e
@@ -0,0 +1,209 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Work item loading and dependency resolution.
4
+ Part of the briefing module decomposition.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ import json
10
+ from datetime import datetime
11
+ from pathlib import Path
12
+ from typing import Any
13
+
14
+ from solokit.core.logging_config import get_logger
15
+ from solokit.core.types import Priority, WorkItemStatus
16
+
17
+ logger = get_logger(__name__)
18
+
19
+
20
+ class WorkItemLoader:
21
+ """Load work items and their dependencies."""
22
+
23
+ def __init__(self, session_dir: Path | None = None):
24
+ """Initialize work item loader.
25
+
26
+ Args:
27
+ session_dir: Path to .session directory (defaults to .session)
28
+ """
29
+ self.session_dir = session_dir or Path(".session")
30
+ self.work_items_file = self.session_dir / "tracking" / "work_items.json"
31
+
32
+ def load_work_items(self) -> dict[str, Any]:
33
+ """Load work items from tracking file.
34
+
35
+ Returns:
36
+ Work items data structure with 'work_items' dict
37
+ """
38
+ logger.debug("Loading work items from: %s", self.work_items_file)
39
+ if not self.work_items_file.exists():
40
+ logger.warning("Work items file not found: %s", self.work_items_file)
41
+ return {"work_items": {}}
42
+ with open(self.work_items_file) as f:
43
+ return json.load(f) # type: ignore[no-any-return]
44
+
45
+ def get_work_item(
46
+ self, work_item_id: str, work_items_data: dict[str, Any] | None = None
47
+ ) -> dict[str, Any] | None:
48
+ """Get a specific work item by ID.
49
+
50
+ Args:
51
+ work_item_id: Work item identifier
52
+ work_items_data: Pre-loaded work items data (optional)
53
+
54
+ Returns:
55
+ Work item dict or None if not found
56
+ """
57
+ if work_items_data is None:
58
+ work_items_data = self.load_work_items()
59
+
60
+ return work_items_data.get("work_items", {}).get(work_item_id) # type: ignore[no-any-return]
61
+
62
+ def get_next_work_item(self, work_items_data: dict) -> tuple[str | None, dict | None]:
63
+ """Find next available work item where dependencies are satisfied.
64
+
65
+ Prioritizes resuming in-progress items over starting new work.
66
+ Returns item with highest priority among available.
67
+
68
+ Args:
69
+ work_items_data: Loaded work items data structure
70
+
71
+ Returns:
72
+ Tuple of (item_id, item) or (None, None) if no work available
73
+ """
74
+ work_items = work_items_data.get("work_items", {})
75
+ priority_order = {
76
+ Priority.CRITICAL.value: 4,
77
+ Priority.HIGH.value: 3,
78
+ Priority.MEDIUM.value: 2,
79
+ Priority.LOW.value: 1,
80
+ }
81
+
82
+ # PRIORITY 1: Resume in-progress work
83
+ in_progress_items = []
84
+ for item_id, item in work_items.items():
85
+ if item["status"] == WorkItemStatus.IN_PROGRESS.value:
86
+ in_progress_items.append((item_id, item))
87
+
88
+ if in_progress_items:
89
+ # Sort by priority and return highest
90
+ in_progress_items.sort(
91
+ key=lambda x: priority_order.get(x[1].get("priority", Priority.MEDIUM.value), 2),
92
+ reverse=True,
93
+ )
94
+ return in_progress_items[0]
95
+
96
+ # PRIORITY 2: Start new work
97
+ available = []
98
+ for item_id, item in work_items.items():
99
+ if item["status"] != WorkItemStatus.NOT_STARTED.value:
100
+ continue
101
+
102
+ # Check dependencies
103
+ deps_satisfied = all(
104
+ work_items.get(dep_id, {}).get("status") == WorkItemStatus.COMPLETED.value
105
+ for dep_id in item.get("dependencies", [])
106
+ )
107
+
108
+ if deps_satisfied:
109
+ available.append((item_id, item))
110
+
111
+ if not available:
112
+ return None, None
113
+
114
+ # Sort by priority
115
+ available.sort(
116
+ key=lambda x: priority_order.get(x[1].get("priority", Priority.MEDIUM.value), 2),
117
+ reverse=True,
118
+ )
119
+
120
+ return available[0]
121
+
122
+ def load_work_item_spec(self, work_item: str | dict[str, Any]) -> str:
123
+ """Load work item specification file.
124
+
125
+ Args:
126
+ work_item: Either a work item dict with 'spec_file' and 'id' fields,
127
+ or a string work_item_id (for backwards compatibility)
128
+
129
+ Returns:
130
+ Specification content as string
131
+ """
132
+ # Handle backwards compatibility: accept both dict and string
133
+ if isinstance(work_item, str):
134
+ # Legacy call with just work_item_id string
135
+ work_item_id = work_item
136
+ spec_file = self.session_dir / "specs" / f"{work_item_id}.md"
137
+ else:
138
+ # New call with work item dict
139
+ # Use spec_file from work item if available, otherwise fallback to ID-based pattern
140
+ spec_file_path = work_item.get("spec_file")
141
+ if spec_file_path:
142
+ spec_file = Path(spec_file_path)
143
+ else:
144
+ # Fallback to legacy pattern for backwards compatibility
145
+ work_item_id_raw = work_item.get("id")
146
+ if not work_item_id_raw:
147
+ return "Specification file not found: work item has no id"
148
+ spec_file = self.session_dir / "specs" / f"{work_item_id_raw}.md"
149
+
150
+ if spec_file.exists():
151
+ return spec_file.read_text()
152
+ return f"Specification file not found: {spec_file}"
153
+
154
+ def update_work_item_status(
155
+ self, work_item_id: str, status: str, session_num: int | None = None
156
+ ) -> bool:
157
+ """Update work item status and optionally add session tracking.
158
+
159
+ Args:
160
+ work_item_id: Work item identifier
161
+ status: New status value
162
+ session_num: Optional session number to add to tracking
163
+
164
+ Returns:
165
+ True if update successful, False otherwise
166
+ """
167
+ if not self.work_items_file.exists():
168
+ logger.error("Work items file not found: %s", self.work_items_file)
169
+ return False
170
+
171
+ with open(self.work_items_file) as f:
172
+ work_items_data = json.load(f)
173
+
174
+ if work_item_id not in work_items_data["work_items"]:
175
+ logger.error("Work item not found: %s", work_item_id)
176
+ return False
177
+
178
+ work_item = work_items_data["work_items"][work_item_id]
179
+ work_item["status"] = status
180
+ work_item["updated_at"] = datetime.now().isoformat()
181
+
182
+ # Add session tracking if session_num provided
183
+ if session_num is not None:
184
+ if "sessions" not in work_item:
185
+ work_item["sessions"] = []
186
+ work_item["sessions"].append(
187
+ {"session_num": session_num, "started_at": datetime.now().isoformat()}
188
+ )
189
+
190
+ # Update metadata counters
191
+ work_items = work_items_data.get("work_items", {})
192
+ work_items_data["metadata"]["total_items"] = len(work_items)
193
+ work_items_data["metadata"]["completed"] = sum(
194
+ 1 for item in work_items.values() if item["status"] == WorkItemStatus.COMPLETED.value
195
+ )
196
+ work_items_data["metadata"]["in_progress"] = sum(
197
+ 1 for item in work_items.values() if item["status"] == WorkItemStatus.IN_PROGRESS.value
198
+ )
199
+ work_items_data["metadata"]["blocked"] = sum(
200
+ 1 for item in work_items.values() if item["status"] == WorkItemStatus.BLOCKED.value
201
+ )
202
+ work_items_data["metadata"]["last_updated"] = datetime.now().isoformat()
203
+
204
+ # Save updated work items
205
+ with open(self.work_items_file, "w") as f:
206
+ json.dump(work_items_data, f, indent=2)
207
+
208
+ logger.info("Updated work item %s status to %s", work_item_id, status)
209
+ return True