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,353 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Generate session briefing for next work item.
4
+ Enhanced with full project context loading.
5
+
6
+ This module has been refactored into a package structure.
7
+ All functionality is now in solokit.session.briefing.* modules.
8
+ This file maintains the CLI entry point and backward compatibility.
9
+ """
10
+
11
+ import json
12
+ from datetime import datetime
13
+ from pathlib import Path
14
+
15
+ from solokit.core.error_handlers import log_errors
16
+ from solokit.core.exceptions import (
17
+ GitError,
18
+ SessionAlreadyActiveError,
19
+ SessionNotFoundError,
20
+ UnmetDependencyError,
21
+ ValidationError,
22
+ WorkItemNotFoundError,
23
+ )
24
+ from solokit.core.logging_config import get_logger
25
+ from solokit.core.output import get_output
26
+ from solokit.core.types import WorkItemStatus
27
+
28
+ # Import from refactored briefing package
29
+ from solokit.session.briefing import (
30
+ calculate_days_ago, # noqa: F401
31
+ check_command_exists, # noqa: F401
32
+ check_git_status, # noqa: F401
33
+ determine_git_branch_final_status, # noqa: F401
34
+ extract_keywords, # noqa: F401
35
+ extract_section, # noqa: F401
36
+ finalize_previous_work_item_git_status,
37
+ generate_briefing,
38
+ generate_deployment_briefing, # noqa: F401
39
+ generate_integration_test_briefing, # noqa: F401
40
+ generate_previous_work_section, # noqa: F401
41
+ get_next_work_item, # noqa: F401
42
+ get_relevant_learnings, # noqa: F401
43
+ load_current_stack, # noqa: F401
44
+ load_current_tree, # noqa: F401
45
+ load_learnings, # noqa: F401
46
+ load_milestone_context, # noqa: F401
47
+ load_project_docs, # noqa: F401
48
+ load_work_item_spec, # noqa: F401
49
+ load_work_items, # noqa: F401
50
+ shift_heading_levels, # noqa: F401
51
+ validate_environment, # noqa: F401
52
+ )
53
+
54
+ logger = get_logger(__name__)
55
+ output = get_output()
56
+
57
+
58
+ @log_errors()
59
+ def main():
60
+ """Main entry point for session briefing generation.
61
+
62
+ Raises:
63
+ SessionNotFoundError: If .session directory doesn't exist
64
+ WorkItemNotFoundError: If specified work item doesn't exist
65
+ SessionAlreadyActiveError: If another work item is in-progress (without --force)
66
+ UnmetDependencyError: If work item has unmet dependencies
67
+ ValidationError: If no available work items found
68
+ GitError: If git workflow fails
69
+ """
70
+ import argparse
71
+
72
+ # Parse command-line arguments
73
+ parser = argparse.ArgumentParser(description="Start session for work item")
74
+ parser.add_argument(
75
+ "work_item_id",
76
+ nargs="?",
77
+ help="Specific work item ID to start (optional)",
78
+ )
79
+ parser.add_argument(
80
+ "--force",
81
+ action="store_true",
82
+ help="Force start even if another item is in-progress",
83
+ )
84
+ args = parser.parse_args()
85
+
86
+ logger.info("Starting session briefing generation")
87
+
88
+ # Ensure .session directory exists
89
+ session_dir = Path(".session")
90
+ if not session_dir.exists():
91
+ logger.error(".session directory not found")
92
+ raise SessionNotFoundError()
93
+
94
+ # Load data
95
+ work_items_data = load_work_items()
96
+ learnings_data = load_learnings()
97
+
98
+ # Determine which work item to start
99
+ if args.work_item_id:
100
+ # User specified a work item explicitly
101
+ item_id = args.work_item_id
102
+ item = work_items_data.get("work_items", {}).get(item_id)
103
+
104
+ if not item:
105
+ logger.error("Work item not found: %s", item_id)
106
+ raise WorkItemNotFoundError(item_id)
107
+
108
+ # Check if a DIFFERENT work item is in-progress (excluding the requested one)
109
+ in_progress = [
110
+ (id, wi)
111
+ for id, wi in work_items_data.get("work_items", {}).items()
112
+ if wi["status"] == WorkItemStatus.IN_PROGRESS.value and id != item_id
113
+ ]
114
+
115
+ # If another item is in-progress, warn and exit (unless --force)
116
+ if in_progress and not args.force:
117
+ in_progress_id = in_progress[0][0]
118
+ logger.warning(
119
+ "Blocked start of %s due to in-progress item: %s (use --force to override)",
120
+ item_id,
121
+ in_progress_id,
122
+ )
123
+ raise SessionAlreadyActiveError(in_progress_id)
124
+
125
+ # Check dependencies are satisfied
126
+ deps_satisfied = all(
127
+ work_items_data.get("work_items", {}).get(dep_id, {}).get("status")
128
+ == WorkItemStatus.COMPLETED.value
129
+ for dep_id in item.get("dependencies", [])
130
+ )
131
+
132
+ if not deps_satisfied:
133
+ unmet_deps = [
134
+ dep_id
135
+ for dep_id in item.get("dependencies", [])
136
+ if work_items_data.get("work_items", {}).get(dep_id, {}).get("status")
137
+ != "completed"
138
+ ]
139
+ logger.error("Work item %s has unmet dependencies: %s", item_id, unmet_deps)
140
+ # Raise exception for the first unmet dependency
141
+ # (The exception message will indicate there are dependencies to complete)
142
+ raise UnmetDependencyError(item_id, unmet_deps[0])
143
+
144
+ # Note: If requested item is already in-progress, no conflict - just resume it
145
+ logger.info("User explicitly requested work item: %s", item_id)
146
+ else:
147
+ # Use automatic selection
148
+ item_id, item = get_next_work_item(work_items_data)
149
+
150
+ if not item_id:
151
+ logger.warning("No available work items found")
152
+ from solokit.core.exceptions import ErrorCode, ValidationError
153
+
154
+ raise ValidationError(
155
+ message="No available work items. All dependencies must be satisfied first.",
156
+ code=ErrorCode.INVALID_STATUS,
157
+ remediation="Complete dependencies or use 'sk work-list' to see work item status",
158
+ )
159
+
160
+ # Finalize previous work item's git status if starting a new work item
161
+ finalize_previous_work_item_git_status(work_items_data, item_id)
162
+
163
+ logger.info("Generating briefing for work item: %s", item_id)
164
+ # Generate briefing
165
+ briefing = generate_briefing(item_id, item, learnings_data)
166
+
167
+ # Save briefing
168
+ briefings_dir = session_dir / "briefings"
169
+ briefings_dir.mkdir(exist_ok=True)
170
+
171
+ # Determine session number
172
+ # If work item is already in progress, reuse existing session number
173
+ if item.get("status") == WorkItemStatus.IN_PROGRESS.value and item.get("sessions"):
174
+ session_num = item["sessions"][-1]["session_num"]
175
+ logger.info("Resuming existing session %d for work item %s", session_num, item_id)
176
+ else:
177
+ # Create new session number for new work or restarted work
178
+ session_num = (
179
+ max(
180
+ [int(f.stem.split("_")[1]) for f in briefings_dir.glob("session_*.md")],
181
+ default=0,
182
+ )
183
+ + 1
184
+ )
185
+ logger.info("Starting new session %d for work item %s", session_num, item_id)
186
+
187
+ # Start git workflow for work item
188
+ try:
189
+ # Import git workflow from new location
190
+ from solokit.git.integration import GitWorkflow
191
+
192
+ workflow = GitWorkflow()
193
+ git_result = workflow.start_work_item(item_id, session_num)
194
+
195
+ if git_result["success"]:
196
+ if git_result["action"] == "created":
197
+ output.success(f"Created git branch: {git_result['branch']}\n")
198
+ else:
199
+ output.success(f"Resumed git branch: {git_result['branch']}\n")
200
+ else:
201
+ output.warning(f"Git workflow warning: {git_result['message']}\n")
202
+ except GitError:
203
+ # Re-raise GitError only if it's critical (not a git repo, command not found)
204
+ # Other git errors are logged as warnings but don't block the briefing
205
+ raise
206
+ except Exception as e:
207
+ # Log unexpected errors but don't block briefing generation
208
+ # Git workflow issues are non-fatal
209
+ logger.warning("Could not start git workflow: %s", e)
210
+ output.warning(f"Could not start git workflow: {e}\n")
211
+
212
+ # Update work item status and session tracking
213
+ work_items_file = session_dir / "tracking" / "work_items.json"
214
+ if work_items_file.exists():
215
+ with open(work_items_file) as f:
216
+ work_items_data = json.load(f)
217
+
218
+ # Update work item status
219
+ if item_id in work_items_data["work_items"]:
220
+ work_item = work_items_data["work_items"][item_id]
221
+ work_item["status"] = WorkItemStatus.IN_PROGRESS.value
222
+ work_item["updated_at"] = datetime.now().isoformat()
223
+
224
+ # Add session tracking
225
+ if "sessions" not in work_item:
226
+ work_item["sessions"] = []
227
+ work_item["sessions"].append(
228
+ {"session_num": session_num, "started_at": datetime.now().isoformat()}
229
+ )
230
+
231
+ # Update metadata counters
232
+ work_items = work_items_data.get("work_items", {})
233
+ work_items_data["metadata"]["total_items"] = len(work_items)
234
+ work_items_data["metadata"]["completed"] = sum(
235
+ 1
236
+ for item in work_items.values()
237
+ if item["status"] == WorkItemStatus.COMPLETED.value
238
+ )
239
+ work_items_data["metadata"]["in_progress"] = sum(
240
+ 1
241
+ for item in work_items.values()
242
+ if item["status"] == WorkItemStatus.IN_PROGRESS.value
243
+ )
244
+ work_items_data["metadata"]["blocked"] = sum(
245
+ 1 for item in work_items.values() if item["status"] == WorkItemStatus.BLOCKED.value
246
+ )
247
+ work_items_data["metadata"]["last_updated"] = datetime.now().isoformat()
248
+
249
+ # Save updated work items
250
+ with open(work_items_file, "w") as f:
251
+ json.dump(work_items_data, f, indent=2)
252
+
253
+ # Notify that status has been updated
254
+ output.success(f"Work item status updated: {item_id} → in_progress\n")
255
+
256
+ briefing_file = briefings_dir / f"session_{session_num:03d}_briefing.md"
257
+
258
+ # Always write briefing file to include fresh context (Enhancement #11 Phase 2)
259
+ # This is critical for in-progress items to show previous work context
260
+ with open(briefing_file, "w") as f:
261
+ f.write(briefing)
262
+
263
+ if item.get("status") == WorkItemStatus.IN_PROGRESS.value:
264
+ logger.info("Updated briefing with previous work context: %s", briefing_file)
265
+ else:
266
+ logger.info("Created briefing file: %s", briefing_file)
267
+
268
+ # Print briefing (always show it, whether new or existing)
269
+ output.info(briefing)
270
+
271
+ # Update status file
272
+ status_file = session_dir / "tracking" / "status_update.json"
273
+ status = {
274
+ "current_session": session_num,
275
+ "current_work_item": item_id,
276
+ "started_at": datetime.now().isoformat(),
277
+ "status": WorkItemStatus.IN_PROGRESS.value,
278
+ }
279
+ with open(status_file, "w") as f:
280
+ json.dump(status, f, indent=2)
281
+
282
+ return 0
283
+
284
+
285
+ def _cli_main():
286
+ """CLI wrapper for main() that handles exceptions and exit codes."""
287
+ try:
288
+ return main()
289
+ except SessionNotFoundError as e:
290
+ output.info(f"Error: {e.message}")
291
+ output.info(f"\n{e.remediation}")
292
+ return e.exit_code
293
+ except WorkItemNotFoundError as e:
294
+ output.info(f"Error: {e.message}")
295
+ output.info(f"\n{e.remediation}")
296
+ # Also show available work items
297
+ try:
298
+ work_items_data = load_work_items()
299
+ output.info("\nAvailable work items:")
300
+ for wid, wi in work_items_data.get("work_items", {}).items():
301
+ status_emoji = {
302
+ WorkItemStatus.NOT_STARTED.value: "○",
303
+ WorkItemStatus.IN_PROGRESS.value: "◐",
304
+ WorkItemStatus.COMPLETED.value: "✓",
305
+ WorkItemStatus.BLOCKED.value: "✗",
306
+ }.get(wi["status"], "○")
307
+ output.info(f" {status_emoji} {wid} - {wi['title']} ({wi['status']})")
308
+ except Exception:
309
+ pass # If we can't load work items, just skip the list
310
+ return e.exit_code
311
+ except SessionAlreadyActiveError as e:
312
+ output.info(f"\nWarning: {e.message}")
313
+ output.info("\nOptions:")
314
+ output.info("1. Complete current work item first: /end")
315
+ output.info("2. Force start new work item: sk start <work_item_id> --force")
316
+ output.info("3. Cancel: Ctrl+C\n")
317
+ return e.exit_code
318
+ except UnmetDependencyError as e:
319
+ output.info(f"Error: {e.message}")
320
+ output.info(f"\n{e.remediation}")
321
+ # Show unmet dependency details
322
+ try:
323
+ work_items_data = load_work_items()
324
+ dep_id = e.context.get("dependency_id")
325
+ if dep_id:
326
+ dep = work_items_data.get("work_items", {}).get(dep_id, {})
327
+ output.info("\nDependency details:")
328
+ output.info(
329
+ f" - {dep_id}: {dep.get('title', 'Unknown')} (status: {dep.get('status', 'unknown')})"
330
+ )
331
+ except Exception:
332
+ pass # If we can't load work items, just skip the details
333
+ return e.exit_code
334
+ except ValidationError as e:
335
+ output.info(f"Error: {e.message}")
336
+ if e.remediation:
337
+ output.info(f"\n{e.remediation}")
338
+ return e.exit_code
339
+ except GitError as e:
340
+ output.info(f"Warning: {e.message}")
341
+ if e.remediation:
342
+ output.info(f"\n{e.remediation}")
343
+ # Git errors are warnings, not fatal - return success
344
+ # This maintains backwards compatibility
345
+ return 0
346
+ except Exception as e:
347
+ logger.exception("Unexpected error in briefing generation")
348
+ output.info(f"Unexpected error: {e}")
349
+ return 1
350
+
351
+
352
+ if __name__ == "__main__":
353
+ exit(_cli_main())