karni-cli 0.3.1__tar.gz → 0.5.0__tar.gz

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 (596) hide show
  1. {karni_cli-0.3.1 → karni_cli-0.5.0}/.gitignore +8 -2
  2. {karni_cli-0.3.1 → karni_cli-0.5.0}/PKG-INFO +110 -56
  3. karni_cli-0.5.0/README.md +206 -0
  4. {karni_cli-0.3.1 → karni_cli-0.5.0}/hatch_build.py +38 -1
  5. karni_cli-0.5.0/karni_cli/__init__.py +8 -0
  6. {karni_cli-0.3.1 → karni_cli-0.5.0}/karni_cli/_agent/__init__.py +4 -1
  7. {karni_cli-0.3.1 → karni_cli-0.5.0}/karni_cli/_agent/check.py +71 -25
  8. {karni_cli-0.3.1 → karni_cli-0.5.0}/karni_cli/_agent/history.py +1 -1
  9. {karni_cli-0.3.1 → karni_cli-0.5.0}/karni_cli/_agent/history_chronicle.py +2 -1
  10. {karni_cli-0.3.1 → karni_cli-0.5.0}/karni_cli/_agent/overrides.py +2 -2
  11. karni_cli-0.5.0/karni_cli/_agent/rules.py +1308 -0
  12. karni_cli-0.5.0/karni_cli/_catalog/__init__.py +576 -0
  13. karni_cli-0.5.0/karni_cli/_catalog/__main__.py +30 -0
  14. karni_cli-0.5.0/karni_cli/_catalog/features/api_cache.toml +19 -0
  15. karni_cli-0.5.0/karni_cli/_catalog/features/email_code_login.toml +25 -0
  16. karni_cli-0.5.0/karni_cli/_catalog/features/social_login.toml +27 -0
  17. karni_cli-0.5.0/karni_cli/_catalog/features/terms.toml +28 -0
  18. karni_cli-0.5.0/karni_cli/_catalog/features/two_factor.toml +20 -0
  19. karni_cli-0.5.0/karni_cli/_catalog/features/user_grants.toml +21 -0
  20. karni_cli-0.5.0/karni_cli/_catalog/modules/karni-ai.toml +61 -0
  21. karni_cli-0.5.0/karni_cli/_catalog/modules/karni-approvals.toml +50 -0
  22. karni_cli-0.5.0/karni_cli/_catalog/modules/karni-charts.toml +34 -0
  23. karni_cli-0.5.0/karni_cli/_catalog/modules/karni-impersonation.toml +59 -0
  24. karni_cli-0.5.0/karni_cli/_catalog/modules/karni-payments.toml +56 -0
  25. karni_cli-0.5.0/karni_cli/_catalog/modules/karni-reports.toml +53 -0
  26. karni_cli-0.5.0/karni_cli/_catalog/modules/karni-site.toml +84 -0
  27. karni_cli-0.5.0/karni_cli/_catalog/modules/karni-storage.toml +67 -0
  28. karni_cli-0.5.0/karni_cli/_changelog/0.4.0.toml +101 -0
  29. karni_cli-0.5.0/karni_cli/_changelog/0.5.0.toml +819 -0
  30. karni_cli-0.5.0/karni_cli/_errorcodes/__init__.py +3202 -0
  31. karni_cli-0.5.0/karni_cli/_errorcodes/failures.py +1282 -0
  32. {karni_cli-0.3.1 → karni_cli-0.5.0}/karni_cli/_errorcodes/links.py +4 -2
  33. karni_cli-0.5.0/karni_cli/_settings/base.py +796 -0
  34. karni_cli-0.5.0/karni_cli/_settings/reference.py +491 -0
  35. {karni_cli-0.3.1 → karni_cli-0.5.0}/karni_cli/_templates/project/cookiecutter.json +4 -2
  36. {karni_cli-0.3.1 → karni_cli-0.5.0}/karni_cli/_templates/project/{{cookiecutter.project_slug}}/.dockerignore +4 -0
  37. karni_cli-0.5.0/karni_cli/_templates/project/{{cookiecutter.project_slug}}/.env.example +146 -0
  38. karni_cli-0.5.0/karni_cli/_templates/project/{{cookiecutter.project_slug}}/.gitignore +19 -0
  39. karni_cli-0.5.0/karni_cli/_templates/project/{{cookiecutter.project_slug}}/Dockerfile +112 -0
  40. {karni_cli-0.3.1 → karni_cli-0.5.0}/karni_cli/_templates/project/{{cookiecutter.project_slug}}/Makefile +1 -1
  41. karni_cli-0.5.0/karni_cli/_templates/project/{{cookiecutter.project_slug}}/README.md +220 -0
  42. karni_cli-0.5.0/karni_cli/_templates/project/{{cookiecutter.project_slug}}/config/settings.py +69 -0
  43. karni_cli-0.5.0/karni_cli/_templates/project/{{cookiecutter.project_slug}}/config/urls.py +45 -0
  44. {karni_cli-0.3.1 → karni_cli-0.5.0}/karni_cli/_templates/project/{{cookiecutter.project_slug}}/docker-compose.yml +14 -5
  45. karni_cli-0.5.0/karni_cli/_templates/project/{{cookiecutter.project_slug}}/frontend/.npmrc +15 -0
  46. {karni_cli-0.3.1 → karni_cli-0.5.0}/karni_cli/_templates/project/{{cookiecutter.project_slug}}/frontend/Dockerfile.dev +1 -1
  47. {karni_cli-0.3.1 → karni_cli-0.5.0}/karni_cli/_templates/project/{{cookiecutter.project_slug}}/frontend/eslint.config.js +1 -1
  48. {karni_cli-0.3.1 → karni_cli-0.5.0}/karni_cli/_templates/project/{{cookiecutter.project_slug}}/frontend/index.html +1 -0
  49. {karni_cli-0.3.1 → karni_cli-0.5.0}/karni_cli/_templates/project/{{cookiecutter.project_slug}}/frontend/package.json +12 -9
  50. karni_cli-0.5.0/karni_cli/_templates/project/{{cookiecutter.project_slug}}/frontend/src/App.tsx +21 -0
  51. karni_cli-0.5.0/karni_cli/_templates/project/{{cookiecutter.project_slug}}/frontend/src/index.css +15 -0
  52. karni_cli-0.5.0/karni_cli/_templates/project/{{cookiecutter.project_slug}}/frontend/src/layout.tsx +88 -0
  53. karni_cli-0.5.0/karni_cli/_templates/project/{{cookiecutter.project_slug}}/frontend/src/pages/home.tsx +31 -0
  54. {karni_cli-0.3.1 → karni_cli-0.5.0}/karni_cli/_templates/project/{{cookiecutter.project_slug}}/frontend/src/routes.tsx +7 -2
  55. {karni_cli-0.3.1 → karni_cli-0.5.0}/karni_cli/_templates/project/{{cookiecutter.project_slug}}/frontend/tailwind.config.ts +1 -1
  56. karni_cli-0.5.0/karni_cli/_templates/project/{{cookiecutter.project_slug}}/frontend/vite.config.ts +28 -0
  57. {karni_cli-0.3.1 → karni_cli-0.5.0}/karni_cli/_templates/project/{{cookiecutter.project_slug}}/pyproject.toml +15 -1
  58. {karni_cli-0.3.1 → karni_cli-0.5.0}/karni_cli/_templates/project/{{cookiecutter.project_slug}}/tests/test_api_schema.py +1 -1
  59. {karni_cli-0.3.1 → karni_cli-0.5.0}/karni_cli/_templates/project/{{cookiecutter.project_slug}}/tests/test_smoke.py +5 -0
  60. karni_cli-0.5.0/karni_cli/_ui/styles.css +264 -0
  61. {karni_cli-0.3.1 → karni_cli-0.5.0}/karni_cli/adapters.py +169 -26
  62. {karni_cli-0.3.1 → karni_cli-0.5.0}/karni_cli/agent_adapters.toml +24 -7
  63. {karni_cli-0.3.1 → karni_cli-0.5.0}/karni_cli/agent_data.py +11 -1
  64. karni_cli-0.5.0/karni_cli/agent_tools.py +505 -0
  65. karni_cli-0.5.0/karni_cli/builder/__init__.py +21 -0
  66. karni_cli-0.5.0/karni_cli/builder/layout.py +83 -0
  67. karni_cli-0.5.0/karni_cli/builder/output.py +134 -0
  68. karni_cli-0.5.0/karni_cli/builder/record.py +215 -0
  69. karni_cli-0.5.0/karni_cli/builder/render.py +1155 -0
  70. karni_cli-0.5.0/karni_cli/builder/run.py +1111 -0
  71. karni_cli-0.5.0/karni_cli/catalog.py +274 -0
  72. {karni_cli-0.3.1 → karni_cli-0.5.0}/karni_cli/clidoc.py +27 -12
  73. karni_cli-0.5.0/karni_cli/commands/add.py +463 -0
  74. {karni_cli-0.3.1 → karni_cli-0.5.0}/karni_cli/commands/beat.py +2 -1
  75. karni_cli-0.5.0/karni_cli/commands/build.py +131 -0
  76. karni_cli-0.5.0/karni_cli/commands/check.py +430 -0
  77. {karni_cli-0.3.1 → karni_cli-0.5.0}/karni_cli/commands/config.py +4 -4
  78. karni_cli-0.5.0/karni_cli/commands/context.py +445 -0
  79. {karni_cli-0.3.1 → karni_cli-0.5.0}/karni_cli/commands/createsuperuser.py +2 -1
  80. karni_cli-0.5.0/karni_cli/commands/design.py +246 -0
  81. karni_cli-0.5.0/karni_cli/commands/doctor.py +286 -0
  82. karni_cli-0.5.0/karni_cli/commands/explain.py +220 -0
  83. karni_cli-0.5.0/karni_cli/commands/import_design.py +608 -0
  84. karni_cli-0.5.0/karni_cli/commands/load.py +45 -0
  85. {karni_cli-0.3.1 → karni_cli-0.5.0}/karni_cli/commands/make.py +1 -1
  86. {karni_cli-0.3.1 → karni_cli-0.5.0}/karni_cli/commands/manage_passthrough.py +10 -2
  87. {karni_cli-0.3.1 → karni_cli-0.5.0}/karni_cli/commands/migrate.py +8 -3
  88. karni_cli-0.5.0/karni_cli/commands/modules.py +182 -0
  89. karni_cli-0.5.0/karni_cli/commands/new.py +697 -0
  90. karni_cli-0.5.0/karni_cli/commands/plan.py +155 -0
  91. karni_cli-0.5.0/karni_cli/commands/queries.py +106 -0
  92. karni_cli-0.5.0/karni_cli/commands/recipes.py +196 -0
  93. karni_cli-0.5.0/karni_cli/commands/remove.py +402 -0
  94. karni_cli-0.5.0/karni_cli/commands/replay.py +53 -0
  95. {karni_cli-0.3.1 → karni_cli-0.5.0}/karni_cli/commands/routes.py +4 -1
  96. {karni_cli-0.3.1 → karni_cli-0.5.0}/karni_cli/commands/rules.py +56 -10
  97. {karni_cli-0.3.1 → karni_cli-0.5.0}/karni_cli/commands/run_tests.py +2 -1
  98. {karni_cli-0.3.1 → karni_cli-0.5.0}/karni_cli/commands/schedule.py +9 -3
  99. karni_cli-0.5.0/karni_cli/commands/schema.py +61 -0
  100. karni_cli-0.5.0/karni_cli/commands/seed.py +51 -0
  101. karni_cli-0.5.0/karni_cli/commands/serve.py +164 -0
  102. {karni_cli-0.3.1 → karni_cli-0.5.0}/karni_cli/commands/shell.py +1 -1
  103. karni_cli-0.5.0/karni_cli/commands/spec.py +191 -0
  104. karni_cli-0.5.0/karni_cli/commands/suggest.py +60 -0
  105. {karni_cli-0.3.1 → karni_cli-0.5.0}/karni_cli/commands/sync_roles.py +9 -2
  106. karni_cli-0.5.0/karni_cli/commands/trace.py +31 -0
  107. karni_cli-0.5.0/karni_cli/commands/types.py +142 -0
  108. karni_cli-0.5.0/karni_cli/commands/ui.py +597 -0
  109. {karni_cli-0.3.1 → karni_cli-0.5.0}/karni_cli/commands/upgrade.py +3 -3
  110. karni_cli-0.5.0/karni_cli/commands/why.py +203 -0
  111. karni_cli-0.5.0/karni_cli/commands/worker.py +113 -0
  112. karni_cli-0.5.0/karni_cli/database.py +176 -0
  113. karni_cli-0.5.0/karni_cli/db_probe.py +89 -0
  114. karni_cli-0.5.0/karni_cli/debugging.py +113 -0
  115. karni_cli-0.5.0/karni_cli/design/__init__.py +30 -0
  116. karni_cli-0.5.0/karni_cli/design/analyze.py +361 -0
  117. karni_cli-0.5.0/karni_cli/design/builder.py +2058 -0
  118. karni_cli-0.5.0/karni_cli/design/compare.py +603 -0
  119. karni_cli-0.5.0/karni_cli/design/editable.py +1717 -0
  120. karni_cli-0.5.0/karni_cli/design/extract.py +813 -0
  121. karni_cli-0.5.0/karni_cli/design/forms.py +602 -0
  122. karni_cli-0.5.0/karni_cli/design/hours.py +281 -0
  123. karni_cli-0.5.0/karni_cli/design/images.py +388 -0
  124. karni_cli-0.5.0/karni_cli/design/mapref.py +369 -0
  125. karni_cli-0.5.0/karni_cli/design/parse.py +411 -0
  126. karni_cli-0.5.0/karni_cli/design/proposal.py +708 -0
  127. karni_cli-0.5.0/karni_cli/design/regions.py +156 -0
  128. karni_cli-0.5.0/karni_cli/design/rewrite.py +534 -0
  129. karni_cli-0.5.0/karni_cli/design/scan.py +442 -0
  130. karni_cli-0.5.0/karni_cli/design/select.py +471 -0
  131. karni_cli-0.5.0/karni_cli/design/seo.py +70 -0
  132. karni_cli-0.5.0/karni_cli/design/site.py +1013 -0
  133. karni_cli-0.5.0/karni_cli/design/sources.py +712 -0
  134. karni_cli-0.5.0/karni_cli/design/values.py +475 -0
  135. karni_cli-0.5.0/karni_cli/envfile.py +69 -0
  136. karni_cli-0.5.0/karni_cli/errorcodes.py +1614 -0
  137. {karni_cli-0.3.1 → karni_cli-0.5.0}/karni_cli/errordoc.py +78 -17
  138. karni_cli-0.5.0/karni_cli/explain_text.py +62 -0
  139. {karni_cli-0.3.1 → karni_cli-0.5.0}/karni_cli/generators/__init__.py +8 -0
  140. {karni_cli-0.3.1 → karni_cli-0.5.0}/karni_cli/generators/apitest.py +152 -35
  141. {karni_cli-0.3.1 → karni_cli-0.5.0}/karni_cli/generators/app.py +8 -7
  142. {karni_cli-0.3.1 → karni_cli-0.5.0}/karni_cli/generators/command.py +1 -1
  143. {karni_cli-0.3.1 → karni_cli-0.5.0}/karni_cli/generators/component.py +2 -2
  144. {karni_cli-0.3.1 → karni_cli-0.5.0}/karni_cli/generators/core.py +30 -13
  145. karni_cli-0.5.0/karni_cli/generators/deploy.py +880 -0
  146. {karni_cli-0.3.1 → karni_cli-0.5.0}/karni_cli/generators/event.py +1 -1
  147. karni_cli-0.5.0/karni_cli/generators/external.py +234 -0
  148. {karni_cli-0.3.1 → karni_cli-0.5.0}/karni_cli/generators/factory.py +1 -1
  149. karni_cli-0.5.0/karni_cli/generators/fields.py +807 -0
  150. karni_cli-0.5.0/karni_cli/generators/form.py +1089 -0
  151. karni_cli-0.5.0/karni_cli/generators/introspect.py +493 -0
  152. karni_cli-0.5.0/karni_cli/generators/lifecycle_fields.py +207 -0
  153. {karni_cli-0.3.1 → karni_cli-0.5.0}/karni_cli/generators/listener.py +9 -8
  154. {karni_cli-0.3.1 → karni_cli-0.5.0}/karni_cli/generators/middleware.py +2 -2
  155. {karni_cli-0.3.1 → karni_cli-0.5.0}/karni_cli/generators/migration.py +5 -5
  156. karni_cli-0.5.0/karni_cli/generators/model.py +444 -0
  157. {karni_cli-0.3.1 → karni_cli-0.5.0}/karni_cli/generators/module.py +40 -10
  158. karni_cli-0.5.0/karni_cli/generators/naming.py +225 -0
  159. {karni_cli-0.3.1 → karni_cli-0.5.0}/karni_cli/generators/page.py +264 -25
  160. {karni_cli-0.3.1 → karni_cli-0.5.0}/karni_cli/generators/pysource.py +1 -1
  161. {karni_cli-0.3.1 → karni_cli-0.5.0}/karni_cli/generators/schedule.py +9 -9
  162. {karni_cli-0.3.1 → karni_cli-0.5.0}/karni_cli/generators/seeder.py +3 -3
  163. {karni_cli-0.3.1 → karni_cli-0.5.0}/karni_cli/generators/serializer.py +7 -6
  164. {karni_cli-0.3.1 → karni_cli-0.5.0}/karni_cli/generators/service.py +3 -3
  165. karni_cli-0.5.0/karni_cli/generators/site.py +677 -0
  166. {karni_cli-0.3.1 → karni_cli-0.5.0}/karni_cli/generators/task.py +2 -2
  167. karni_cli-0.5.0/karni_cli/generators/view.py +219 -0
  168. {karni_cli-0.3.1 → karni_cli-0.5.0}/karni_cli/generators/viewset.py +81 -14
  169. karni_cli-0.5.0/karni_cli/kinds.py +253 -0
  170. {karni_cli-0.3.1 → karni_cli-0.5.0}/karni_cli/local_state.py +14 -1
  171. {karni_cli-0.3.1 → karni_cli-0.5.0}/karni_cli/main.py +61 -6
  172. karni_cli-0.5.0/karni_cli/mcp_server.py +339 -0
  173. karni_cli-0.5.0/karni_cli/module_codes.json +762 -0
  174. {karni_cli-0.3.1 → karni_cli-0.5.0}/karni_cli/project.py +136 -31
  175. karni_cli-0.5.0/karni_cli/pyproject_edit.py +121 -0
  176. karni_cli-0.5.0/karni_cli/recipes/__init__.py +506 -0
  177. karni_cli-0.5.0/karni_cli/recipes/__main__.py +9 -0
  178. karni_cli-0.5.0/karni_cli/recipes/apply.py +114 -0
  179. karni_cli-0.5.0/karni_cli/recipes/booking/files/bookings/models.py +63 -0
  180. karni_cli-0.5.0/karni_cli/recipes/booking/files/bookings/tests/test_capacity.py +45 -0
  181. karni_cli-0.5.0/karni_cli/recipes/booking/files/bookings/viewsets.py +45 -0
  182. karni_cli-0.5.0/karni_cli/recipes/booking/karni.yaml +52 -0
  183. karni_cli-0.5.0/karni_cli/recipes/booking/recipe.toml +17 -0
  184. karni_cli-0.5.0/karni_cli/recipes/crm/files/crm/tests/test_pipeline.py +57 -0
  185. karni_cli-0.5.0/karni_cli/recipes/crm/files/crm/viewsets.py +39 -0
  186. karni_cli-0.5.0/karni_cli/recipes/crm/karni.yaml +80 -0
  187. karni_cli-0.5.0/karni_cli/recipes/crm/recipe.toml +18 -0
  188. karni_cli-0.5.0/karni_cli/recipes/data-portal/files/portal/seeds.py +157 -0
  189. karni_cli-0.5.0/karni_cli/recipes/data-portal/files/portal/tests/conftest.py +10 -0
  190. karni_cli-0.5.0/karni_cli/recipes/data-portal/files/portal/tests/test_portal.py +240 -0
  191. karni_cli-0.5.0/karni_cli/recipes/data-portal/karni.yaml +120 -0
  192. karni_cli-0.5.0/karni_cli/recipes/data-portal/recipe.toml +19 -0
  193. karni_cli-0.5.0/karni_cli/recipes/lms/files/courses/models.py +41 -0
  194. karni_cli-0.5.0/karni_cli/recipes/lms/files/courses/seeds.py +42 -0
  195. karni_cli-0.5.0/karni_cli/recipes/lms/files/courses/tests/test_completion.py +45 -0
  196. karni_cli-0.5.0/karni_cli/recipes/lms/files/courses/viewsets.py +30 -0
  197. karni_cli-0.5.0/karni_cli/recipes/lms/karni.yaml +73 -0
  198. karni_cli-0.5.0/karni_cli/recipes/lms/recipe.toml +16 -0
  199. karni_cli-0.5.0/karni_cli/recipes/marketplace/files/market/models.py +70 -0
  200. karni_cli-0.5.0/karni_cli/recipes/marketplace/files/market/tests/test_payouts.py +47 -0
  201. karni_cli-0.5.0/karni_cli/recipes/marketplace/files/market/viewsets.py +42 -0
  202. karni_cli-0.5.0/karni_cli/recipes/marketplace/karni.yaml +89 -0
  203. karni_cli-0.5.0/karni_cli/recipes/marketplace/recipe.toml +17 -0
  204. karni_cli-0.5.0/karni_cli/recipes/output.py +193 -0
  205. karni_cli-0.5.0/karni_cli/recipes/shop/files/shop/models.py +83 -0
  206. karni_cli-0.5.0/karni_cli/recipes/shop/files/shop/seeds.py +42 -0
  207. karni_cli-0.5.0/karni_cli/recipes/shop/files/shop/tests/test_checkout.py +55 -0
  208. karni_cli-0.5.0/karni_cli/recipes/shop/files/shop/viewsets.py +51 -0
  209. karni_cli-0.5.0/karni_cli/recipes/shop/karni.yaml +72 -0
  210. karni_cli-0.5.0/karni_cli/recipes/shop/recipe.toml +18 -0
  211. {karni_cli-0.3.1 → karni_cli-0.5.0}/karni_cli/rules_render.py +19 -1
  212. {karni_cli-0.3.1 → karni_cli-0.5.0}/karni_cli/scaffold.py +48 -5
  213. karni_cli-0.5.0/karni_cli/services.py +157 -0
  214. karni_cli-0.5.0/karni_cli/settingref.py +150 -0
  215. karni_cli-0.5.0/karni_cli/settings_edit.py +248 -0
  216. karni_cli-0.5.0/karni_cli/spec/__init__.py +17 -0
  217. karni_cli-0.5.0/karni_cli/spec/catalog.py +159 -0
  218. karni_cli-0.5.0/karni_cli/spec/edit.py +215 -0
  219. karni_cli-0.5.0/karni_cli/spec/emit.py +121 -0
  220. karni_cli-0.5.0/karni_cli/spec/export.py +1096 -0
  221. karni_cli-0.5.0/karni_cli/spec/navigation.py +283 -0
  222. karni_cli-0.5.0/karni_cli/spec/normal.py +277 -0
  223. karni_cli-0.5.0/karni_cli/spec/plan.py +1480 -0
  224. karni_cli-0.5.0/karni_cli/spec/questions.py +733 -0
  225. karni_cli-0.5.0/karni_cli/spec/schema.py +722 -0
  226. karni_cli-0.5.0/karni_cli/spec/source.py +102 -0
  227. karni_cli-0.5.0/karni_cli/spec/validate.py +2184 -0
  228. karni_cli-0.5.0/karni_cli/suggest.py +433 -0
  229. karni_cli-0.5.0/karni_cli/templateref.py +113 -0
  230. {karni_cli-0.3.1 → karni_cli-0.5.0}/karni_cli/tips.py +5 -3
  231. karni_cli-0.5.0/karni_cli/toolchain.py +87 -0
  232. karni_cli-0.5.0/karni_cli/typegen.py +201 -0
  233. karni_cli-0.5.0/karni_cli/uitheme/__init__.py +32 -0
  234. karni_cli-0.5.0/karni_cli/uitheme/colour.py +221 -0
  235. karni_cli-0.5.0/karni_cli/uitheme/css.py +222 -0
  236. karni_cli-0.5.0/karni_cli/uitheme/defaults.py +111 -0
  237. karni_cli-0.5.0/karni_cli/uitheme/designsystems.py +699 -0
  238. karni_cli-0.5.0/karni_cli/uitheme/frontend.py +236 -0
  239. karni_cli-0.5.0/karni_cli/uitheme/jsobject.py +317 -0
  240. karni_cli-0.5.0/karni_cli/uitheme/model.py +173 -0
  241. karni_cli-0.5.0/karni_cli/uitheme/plaincss.py +1192 -0
  242. karni_cli-0.5.0/karni_cli/uitheme/primitives.py +192 -0
  243. karni_cli-0.5.0/karni_cli/uitheme/render.py +211 -0
  244. karni_cli-0.5.0/karni_cli/uitheme/shadcn.py +259 -0
  245. karni_cli-0.5.0/karni_cli/uitheme/tailwind.py +707 -0
  246. karni_cli-0.5.0/karni_cli/uitheme/wiring.py +143 -0
  247. {karni_cli-0.3.1 → karni_cli-0.5.0}/karni_cli/upgrades/engine.py +2 -2
  248. {karni_cli-0.3.1 → karni_cli-0.5.0}/karni_cli/upgrades/python.py +5 -5
  249. {karni_cli-0.3.1 → karni_cli-0.5.0}/karni_cli/upgrades/typescript.py +1 -1
  250. {karni_cli-0.3.1 → karni_cli-0.5.0}/karni_cli/upgrades/v0_2/agent_guidance.py +9 -4
  251. karni_cli-0.5.0/karni_cli/upgrades/v0_5/urls_marker.py +61 -0
  252. karni_cli-0.5.0/karni_cli/urls_edit.py +120 -0
  253. {karni_cli-0.3.1 → karni_cli-0.5.0}/pyproject.toml +14 -6
  254. karni_cli-0.5.0/tests/__init__.py +0 -0
  255. {karni_cli-0.3.1 → karni_cli-0.5.0}/tests/conftest.py +83 -0
  256. karni_cli-0.5.0/tests/fixtures/designs/academy/admissions.html +60 -0
  257. karni_cli-0.5.0/tests/fixtures/designs/academy/css/bootstrap.css +12 -0
  258. karni_cli-0.5.0/tests/fixtures/designs/academy/css/school.css +2 -0
  259. karni_cli-0.5.0/tests/fixtures/designs/academy/img/garden.svg +1 -0
  260. karni_cli-0.5.0/tests/fixtures/designs/academy/index.html +33 -0
  261. karni_cli-0.5.0/tests/fixtures/designs/bakery/about.html +37 -0
  262. karni_cli-0.5.0/tests/fixtures/designs/bakery/contact.html +40 -0
  263. karni_cli-0.5.0/tests/fixtures/designs/bakery/css/site.css +2 -0
  264. karni_cli-0.5.0/tests/fixtures/designs/bakery/img/hero.jpg +0 -0
  265. karni_cli-0.5.0/tests/fixtures/designs/bakery/img/logo.svg +1 -0
  266. karni_cli-0.5.0/tests/fixtures/designs/bakery/img/oven.jpg +0 -0
  267. karni_cli-0.5.0/tests/fixtures/designs/bakery/img/pattern.png +0 -0
  268. karni_cli-0.5.0/tests/fixtures/designs/bakery/img/unused.png +0 -0
  269. karni_cli-0.5.0/tests/fixtures/designs/bakery/index.html +42 -0
  270. karni_cli-0.5.0/tests/fixtures/designs/bakery/js/app.js +1 -0
  271. karni_cli-0.5.0/tests/fixtures/designs/bakery/menu.html +40 -0
  272. karni_cli-0.5.0/tests/fixtures/designs/bakery/specials.html +9 -0
  273. karni_cli-0.5.0/tests/fixtures/designs/clinic/404.html +36 -0
  274. karni_cli-0.5.0/tests/fixtures/designs/clinic/css/bootstrap.min.css +1 -0
  275. karni_cli-0.5.0/tests/fixtures/designs/clinic/css/clinic.css +2 -0
  276. karni_cli-0.5.0/tests/fixtures/designs/clinic/css/fonts.css +1 -0
  277. karni_cli-0.5.0/tests/fixtures/designs/clinic/fonts/clinic.woff2 +0 -0
  278. karni_cli-0.5.0/tests/fixtures/designs/clinic/img/clinic.jpg +0 -0
  279. karni_cli-0.5.0/tests/fixtures/designs/clinic/img/old-logo.png +0 -0
  280. karni_cli-0.5.0/tests/fixtures/designs/clinic/index.html +37 -0
  281. karni_cli-0.5.0/tests/fixtures/designs/clinic/js/bootstrap.bundle.min.js +1 -0
  282. karni_cli-0.5.0/tests/fixtures/designs/clinic/services/dental.html +36 -0
  283. karni_cli-0.5.0/tests/fixtures/designs/clinic/services/eyes.html +36 -0
  284. karni_cli-0.5.0/tests/fixtures/designs/clinic/services/index.html +36 -0
  285. karni_cli-0.5.0/tests/fixtures/designs/clinic/team.html +29 -0
  286. karni_cli-0.5.0/tests/fixtures/designs/college/courses.html +27 -0
  287. karni_cli-0.5.0/tests/fixtures/designs/college/css/school.css +5 -0
  288. karni_cli-0.5.0/tests/fixtures/designs/college/img/badge.jpg +0 -0
  289. karni_cli-0.5.0/tests/fixtures/designs/college/img/campus.jpg +0 -0
  290. karni_cli-0.5.0/tests/fixtures/designs/college/img/campus.webp +0 -0
  291. karni_cli-0.5.0/tests/fixtures/designs/college/img/course-art.jpg +0 -0
  292. karni_cli-0.5.0/tests/fixtures/designs/college/img/course-music.png +0 -0
  293. karni_cli-0.5.0/tests/fixtures/designs/college/img/hero.jpg +0 -0
  294. karni_cli-0.5.0/tests/fixtures/designs/college/img/logo.svg +1 -0
  295. karni_cli-0.5.0/tests/fixtures/designs/college/img/share.jpg +0 -0
  296. karni_cli-0.5.0/tests/fixtures/designs/college/img/teacher.jpg +0 -0
  297. karni_cli-0.5.0/tests/fixtures/designs/college/index.html +32 -0
  298. karni_cli-0.5.0/tests/fixtures/designs/patisserie/contact.html +37 -0
  299. karni_cli-0.5.0/tests/fixtures/designs/patisserie/css/bootstrap.min.css +2 -0
  300. karni_cli-0.5.0/tests/fixtures/designs/patisserie/css/shop.css +2 -0
  301. karni_cli-0.5.0/tests/fixtures/designs/patisserie/img/baguette.jpg +0 -0
  302. karni_cli-0.5.0/tests/fixtures/designs/patisserie/img/carrot-cake.jpg +0 -0
  303. karni_cli-0.5.0/tests/fixtures/designs/patisserie/img/eclair.jpg +0 -0
  304. karni_cli-0.5.0/tests/fixtures/designs/patisserie/img/flat-white.jpg +0 -0
  305. karni_cli-0.5.0/tests/fixtures/designs/patisserie/img/lemon-tart.jpg +0 -0
  306. karni_cli-0.5.0/tests/fixtures/designs/patisserie/img/lemonade.jpg +0 -0
  307. karni_cli-0.5.0/tests/fixtures/designs/patisserie/img/rye.jpg +0 -0
  308. karni_cli-0.5.0/tests/fixtures/designs/patisserie/img/shop.jpg +0 -0
  309. karni_cli-0.5.0/tests/fixtures/designs/patisserie/img/sourdough.jpg +0 -0
  310. karni_cli-0.5.0/tests/fixtures/designs/patisserie/index.html +82 -0
  311. karni_cli-0.5.0/tests/fixtures/designs/patisserie/menu.html +157 -0
  312. karni_cli-0.5.0/tests/fixtures/designs/portfolio/img/bg.png +0 -0
  313. karni_cli-0.5.0/tests/fixtures/designs/portfolio/img/hero.jpg +0 -0
  314. karni_cli-0.5.0/tests/fixtures/designs/portfolio/img/hero.webp +0 -0
  315. karni_cli-0.5.0/tests/fixtures/designs/portfolio/img/shot-1x.jpg +0 -0
  316. karni_cli-0.5.0/tests/fixtures/designs/portfolio/img/shot-2x.jpg +0 -0
  317. karni_cli-0.5.0/tests/fixtures/designs/portfolio/index.html +40 -0
  318. karni_cli-0.5.0/tests/fixtures/designs/portfolio/scripts/reveal.js +1 -0
  319. karni_cli-0.5.0/tests/fixtures/designs/portfolio/styles/main.css +1 -0
  320. karni_cli-0.5.0/tests/fixtures/designs/practice/about.html +29 -0
  321. karni_cli-0.5.0/tests/fixtures/designs/practice/css/practice.css +3 -0
  322. karni_cli-0.5.0/tests/fixtures/designs/practice/doctors/ada-okoro.html +54 -0
  323. karni_cli-0.5.0/tests/fixtures/designs/practice/doctors/ben-lim.html +55 -0
  324. karni_cli-0.5.0/tests/fixtures/designs/practice/doctors/cara-diaz.html +54 -0
  325. karni_cli-0.5.0/tests/fixtures/designs/practice/img/ada.jpg +0 -0
  326. karni_cli-0.5.0/tests/fixtures/designs/practice/img/ben.jpg +0 -0
  327. karni_cli-0.5.0/tests/fixtures/designs/practice/img/cara.jpg +0 -0
  328. karni_cli-0.5.0/tests/fixtures/designs/practice/img/logo.png +0 -0
  329. karni_cli-0.5.0/tests/fixtures/designs/practice/img/waiting-room.jpg +0 -0
  330. karni_cli-0.5.0/tests/fixtures/designs/practice/index.html +61 -0
  331. karni_cli-0.5.0/tests/fixtures/designs/practice/treatments.html +54 -0
  332. karni_cli-0.5.0/tests/fixtures/designs/salon/css/salon.css +12 -0
  333. karni_cli-0.5.0/tests/fixtures/designs/salon/index.html +41 -0
  334. karni_cli-0.5.0/tests/fixtures/designs/school/courses/drawing.html +55 -0
  335. karni_cli-0.5.0/tests/fixtures/designs/school/courses/pottery.html +56 -0
  336. karni_cli-0.5.0/tests/fixtures/designs/school/courses/printing.html +53 -0
  337. karni_cli-0.5.0/tests/fixtures/designs/school/courses/weaving.html +54 -0
  338. karni_cli-0.5.0/tests/fixtures/designs/school/courses.html +65 -0
  339. karni_cli-0.5.0/tests/fixtures/designs/school/css/school.css +2 -0
  340. karni_cli-0.5.0/tests/fixtures/designs/school/img/drawing-1.jpg +0 -0
  341. karni_cli-0.5.0/tests/fixtures/designs/school/img/drawing-2.jpg +0 -0
  342. karni_cli-0.5.0/tests/fixtures/designs/school/img/drawing.jpg +0 -0
  343. karni_cli-0.5.0/tests/fixtures/designs/school/img/lena.jpg +0 -0
  344. karni_cli-0.5.0/tests/fixtures/designs/school/img/mia.jpg +0 -0
  345. karni_cli-0.5.0/tests/fixtures/designs/school/img/omar.jpg +0 -0
  346. karni_cli-0.5.0/tests/fixtures/designs/school/img/pottery-1.jpg +0 -0
  347. karni_cli-0.5.0/tests/fixtures/designs/school/img/pottery-2.jpg +0 -0
  348. karni_cli-0.5.0/tests/fixtures/designs/school/img/pottery-3.jpg +0 -0
  349. karni_cli-0.5.0/tests/fixtures/designs/school/img/pottery.jpg +0 -0
  350. karni_cli-0.5.0/tests/fixtures/designs/school/img/printing-1.jpg +0 -0
  351. karni_cli-0.5.0/tests/fixtures/designs/school/img/printing.jpg +0 -0
  352. karni_cli-0.5.0/tests/fixtures/designs/school/img/studio.jpg +0 -0
  353. karni_cli-0.5.0/tests/fixtures/designs/school/img/weaving-1.jpg +0 -0
  354. karni_cli-0.5.0/tests/fixtures/designs/school/img/weaving-2.jpg +0 -0
  355. karni_cli-0.5.0/tests/fixtures/designs/school/img/weaving.jpg +0 -0
  356. karni_cli-0.5.0/tests/fixtures/designs/school/index.html +56 -0
  357. karni_cli-0.5.0/tests/fixtures/designs/school/teachers.html +45 -0
  358. karni_cli-0.5.0/tests/fixtures/designs/studio/about.html +63 -0
  359. karni_cli-0.5.0/tests/fixtures/designs/studio/css/studio.css +2 -0
  360. karni_cli-0.5.0/tests/fixtures/designs/studio/img/about-1.jpg +0 -0
  361. karni_cli-0.5.0/tests/fixtures/designs/studio/img/about-2.jpg +0 -0
  362. karni_cli-0.5.0/tests/fixtures/designs/studio/img/ines.jpg +0 -0
  363. karni_cli-0.5.0/tests/fixtures/designs/studio/img/kiosk-2.jpg +0 -0
  364. karni_cli-0.5.0/tests/fixtures/designs/studio/img/kiosk.jpg +0 -0
  365. karni_cli-0.5.0/tests/fixtures/designs/studio/img/lakehouse-2.jpg +0 -0
  366. karni_cli-0.5.0/tests/fixtures/designs/studio/img/lakehouse-3.jpg +0 -0
  367. karni_cli-0.5.0/tests/fixtures/designs/studio/img/lakehouse.jpg +0 -0
  368. karni_cli-0.5.0/tests/fixtures/designs/studio/img/library-2.jpg +0 -0
  369. karni_cli-0.5.0/tests/fixtures/designs/studio/img/library-3.jpg +0 -0
  370. karni_cli-0.5.0/tests/fixtures/designs/studio/img/library.jpg +0 -0
  371. karni_cli-0.5.0/tests/fixtures/designs/studio/img/loft-2.jpg +0 -0
  372. karni_cli-0.5.0/tests/fixtures/designs/studio/img/loft.jpg +0 -0
  373. karni_cli-0.5.0/tests/fixtures/designs/studio/img/ola.jpg +0 -0
  374. karni_cli-0.5.0/tests/fixtures/designs/studio/img/slide-1.jpg +0 -0
  375. karni_cli-0.5.0/tests/fixtures/designs/studio/img/slide-2.jpg +0 -0
  376. karni_cli-0.5.0/tests/fixtures/designs/studio/img/slide-3.jpg +0 -0
  377. karni_cli-0.5.0/tests/fixtures/designs/studio/img/theo.jpg +0 -0
  378. karni_cli-0.5.0/tests/fixtures/designs/studio/img/yara.jpg +0 -0
  379. karni_cli-0.5.0/tests/fixtures/designs/studio/index.html +119 -0
  380. karni_cli-0.5.0/tests/fixtures/designs/studio/js/studio.js +1 -0
  381. karni_cli-0.5.0/tests/fixtures/spec/harbour-yoga.build.json +448 -0
  382. karni_cli-0.5.0/tests/fixtures/spec/harbour-yoga.plan.json +287 -0
  383. karni_cli-0.5.0/tests/fixtures/spec/harbour-yoga.yaml +60 -0
  384. karni_cli-0.5.0/tests/fixtures/ui/chakra/package.json +9 -0
  385. karni_cli-0.5.0/tests/fixtures/ui/chakra/src/main.tsx +7 -0
  386. karni_cli-0.5.0/tests/fixtures/ui/chakra/src/theme.ts +35 -0
  387. karni_cli-0.5.0/tests/fixtures/ui/chakra3/package.json +9 -0
  388. karni_cli-0.5.0/tests/fixtures/ui/chakra3/src/components/ui/theme.ts +29 -0
  389. karni_cli-0.5.0/tests/fixtures/ui/chakra3/src/main.tsx +7 -0
  390. karni_cli-0.5.0/tests/fixtures/ui/css/bakery/menu.css +36 -0
  391. karni_cli-0.5.0/tests/fixtures/ui/css/bootstrap/theme.css +39 -0
  392. karni_cli-0.5.0/tests/fixtures/ui/css/clinic/style.css +57 -0
  393. karni_cli-0.5.0/tests/fixtures/ui/css/night/theme.css +20 -0
  394. karni_cli-0.5.0/tests/fixtures/ui/css/portfolio/about.html +9 -0
  395. karni_cli-0.5.0/tests/fixtures/ui/css/portfolio/css/about.css +2 -0
  396. karni_cli-0.5.0/tests/fixtures/ui/css/portfolio/css/site.css +17 -0
  397. karni_cli-0.5.0/tests/fixtures/ui/css/portfolio/css/tokens.css +8 -0
  398. karni_cli-0.5.0/tests/fixtures/ui/css/portfolio/css/unused.css +2 -0
  399. karni_cli-0.5.0/tests/fixtures/ui/css/portfolio/index.html +14 -0
  400. karni_cli-0.5.0/tests/fixtures/ui/css/portfolio/vendor/normalize.css +4 -0
  401. karni_cli-0.5.0/tests/fixtures/ui/css/switching/app.css +27 -0
  402. karni_cli-0.5.0/tests/fixtures/ui/mantine/package.json +9 -0
  403. karni_cli-0.5.0/tests/fixtures/ui/mantine/src/main.tsx +7 -0
  404. karni_cli-0.5.0/tests/fixtures/ui/mantine/src/theme.ts +41 -0
  405. karni_cli-0.5.0/tests/fixtures/ui/mui/package.json +11 -0
  406. karni_cli-0.5.0/tests/fixtures/ui/mui/src/main.tsx +7 -0
  407. karni_cli-0.5.0/tests/fixtures/ui/mui/src/theme/index.ts +29 -0
  408. karni_cli-0.5.0/tests/fixtures/ui/plain/package.json +5 -0
  409. karni_cli-0.5.0/tests/fixtures/ui/plain/src/index.css +4 -0
  410. karni_cli-0.5.0/tests/fixtures/ui/plain/src/main.tsx +7 -0
  411. karni_cli-0.5.0/tests/fixtures/ui/shadcn-tw3/components.json +18 -0
  412. karni_cli-0.5.0/tests/fixtures/ui/shadcn-tw3/package.json +16 -0
  413. {karni_cli-0.3.1/karni_cli/_templates/project/{{cookiecutter.project_slug}}/frontend → karni_cli-0.5.0/tests/fixtures/ui/shadcn-tw3}/src/App.tsx +0 -2
  414. karni_cli-0.5.0/tests/fixtures/ui/shadcn-tw3/src/components/ui/button.tsx +29 -0
  415. karni_cli-0.5.0/tests/fixtures/ui/shadcn-tw3/src/components/ui/checkbox.tsx +14 -0
  416. karni_cli-0.5.0/tests/fixtures/ui/shadcn-tw3/src/components/ui/input.tsx +12 -0
  417. karni_cli-0.5.0/tests/fixtures/ui/shadcn-tw3/src/components/ui/label.tsx +16 -0
  418. karni_cli-0.5.0/tests/fixtures/ui/shadcn-tw3/src/components/ui/select.tsx +69 -0
  419. karni_cli-0.5.0/tests/fixtures/ui/shadcn-tw3/src/index.css +49 -0
  420. karni_cli-0.5.0/tests/fixtures/ui/shadcn-tw3/src/main.tsx +11 -0
  421. karni_cli-0.5.0/tests/fixtures/ui/shadcn-tw3/tailwind.config.js +18 -0
  422. karni_cli-0.5.0/tests/fixtures/ui/shadcn-tw3/tsconfig.json +10 -0
  423. karni_cli-0.5.0/tests/fixtures/ui/shadcn-tw4/components.json +21 -0
  424. karni_cli-0.5.0/tests/fixtures/ui/shadcn-tw4/package.json +11 -0
  425. karni_cli-0.5.0/tests/fixtures/ui/shadcn-tw4/src/App.tsx +5 -0
  426. karni_cli-0.5.0/tests/fixtures/ui/shadcn-tw4/src/components/ui/button.tsx +23 -0
  427. karni_cli-0.5.0/tests/fixtures/ui/shadcn-tw4/src/components/ui/select.tsx +42 -0
  428. karni_cli-0.5.0/tests/fixtures/ui/shadcn-tw4/src/components/ui/switch.tsx +10 -0
  429. karni_cli-0.5.0/tests/fixtures/ui/shadcn-tw4/src/components/ui/textarea.tsx +9 -0
  430. karni_cli-0.5.0/tests/fixtures/ui/shadcn-tw4/src/index.css +60 -0
  431. karni_cli-0.5.0/tests/fixtures/ui/shadcn-tw4/src/main.tsx +10 -0
  432. karni_cli-0.5.0/tests/fixtures/ui/shadcn-tw4/tsconfig.json +9 -0
  433. karni_cli-0.5.0/tests/fixtures/ui/tailwind3/package.json +6 -0
  434. karni_cli-0.5.0/tests/fixtures/ui/tailwind3/src/index.css +3 -0
  435. karni_cli-0.5.0/tests/fixtures/ui/tailwind3/src/main.tsx +7 -0
  436. karni_cli-0.5.0/tests/fixtures/ui/tailwind3/tailwind.config.ts +32 -0
  437. karni_cli-0.5.0/tests/fixtures/ui/tailwind4/package.json +7 -0
  438. karni_cli-0.5.0/tests/fixtures/ui/tailwind4/src/index.css +8 -0
  439. karni_cli-0.5.0/tests/fixtures/ui/tailwind4/src/main.tsx +7 -0
  440. karni_cli-0.5.0/tests/fixtures/ui/tailwind4/src/theme.css +27 -0
  441. {karni_cli-0.3.1 → karni_cli-0.5.0}/tests/test_adapters.py +142 -25
  442. {karni_cli-0.3.1 → karni_cli-0.5.0}/tests/test_add.py +49 -11
  443. {karni_cli-0.3.1 → karni_cli-0.5.0}/tests/test_agent_upgrade.py +6 -0
  444. {karni_cli-0.3.1 → karni_cli-0.5.0}/tests/test_audit_fixes.py +59 -2
  445. karni_cli-0.5.0/tests/test_bench_tokens.py +668 -0
  446. karni_cli-0.5.0/tests/test_benchmark.py +98 -0
  447. karni_cli-0.5.0/tests/test_build.py +1289 -0
  448. karni_cli-0.5.0/tests/test_catalog.py +567 -0
  449. karni_cli-0.5.0/tests/test_check.py +366 -0
  450. {karni_cli-0.3.1 → karni_cli-0.5.0}/tests/test_clidoc.py +1 -1
  451. karni_cli-0.5.0/tests/test_command_states.py +268 -0
  452. karni_cli-0.5.0/tests/test_context.py +366 -0
  453. karni_cli-0.5.0/tests/test_database.py +309 -0
  454. karni_cli-0.5.0/tests/test_debugging.py +176 -0
  455. karni_cli-0.5.0/tests/test_design_address.py +121 -0
  456. karni_cli-0.5.0/tests/test_design_analyze.py +658 -0
  457. karni_cli-0.5.0/tests/test_design_content.py +174 -0
  458. karni_cli-0.5.0/tests/test_design_extract.py +431 -0
  459. karni_cli-0.5.0/tests/test_design_hours.py +69 -0
  460. karni_cli-0.5.0/tests/test_design_terms.py +106 -0
  461. karni_cli-0.5.0/tests/test_docs_links.py +181 -0
  462. karni_cli-0.5.0/tests/test_docs_roadmap.py +60 -0
  463. {karni_cli-0.3.1 → karni_cli-0.5.0}/tests/test_doctor.py +99 -10
  464. karni_cli-0.5.0/tests/test_envfile.py +51 -0
  465. karni_cli-0.5.0/tests/test_errorcodes_cli.py +297 -0
  466. karni_cli-0.5.0/tests/test_explain_tags_and_map.py +123 -0
  467. karni_cli-0.5.0/tests/test_explain_text.py +233 -0
  468. {karni_cli-0.3.1 → karni_cli-0.5.0}/tests/test_history.py +7 -4
  469. karni_cli-0.5.0/tests/test_import_design.py +1004 -0
  470. karni_cli-0.5.0/tests/test_import_design_menu_rows.py +127 -0
  471. karni_cli-0.5.0/tests/test_import_design_seo.py +240 -0
  472. karni_cli-0.5.0/tests/test_kinds.py +518 -0
  473. karni_cli-0.5.0/tests/test_make.py +1317 -0
  474. karni_cli-0.5.0/tests/test_make_deploy.py +564 -0
  475. karni_cli-0.5.0/tests/test_make_external.py +216 -0
  476. karni_cli-0.5.0/tests/test_make_form.py +833 -0
  477. karni_cli-0.5.0/tests/test_make_gate.py +792 -0
  478. karni_cli-0.5.0/tests/test_make_lifecycle.py +114 -0
  479. karni_cli-0.5.0/tests/test_make_model_order_key.py +49 -0
  480. karni_cli-0.5.0/tests/test_make_model_pk.py +65 -0
  481. {karni_cli-0.3.1 → karni_cli-0.5.0}/tests/test_make_units.py +111 -1
  482. {karni_cli-0.3.1 → karni_cli-0.5.0}/tests/test_mcp.py +42 -4
  483. karni_cli-0.5.0/tests/test_model_plural.py +85 -0
  484. karni_cli-0.5.0/tests/test_module_migrations.py +55 -0
  485. karni_cli-0.5.0/tests/test_new.py +587 -0
  486. karni_cli-0.5.0/tests/test_new_app.py +320 -0
  487. karni_cli-0.5.0/tests/test_new_recipe.py +376 -0
  488. karni_cli-0.5.0/tests/test_plan.py +1232 -0
  489. karni_cli-0.5.0/tests/test_questions.py +612 -0
  490. karni_cli-0.5.0/tests/test_recipe_builds.py +74 -0
  491. karni_cli-0.5.0/tests/test_recipes.py +405 -0
  492. karni_cli-0.5.0/tests/test_release.py +537 -0
  493. karni_cli-0.5.0/tests/test_rules.py +278 -0
  494. {karni_cli-0.3.1 → karni_cli-0.5.0}/tests/test_runners.py +183 -7
  495. karni_cli-0.5.0/tests/test_schema_cli.py +83 -0
  496. karni_cli-0.5.0/tests/test_services.py +254 -0
  497. karni_cli-0.5.0/tests/test_spec.py +1281 -0
  498. karni_cli-0.5.0/tests/test_spec_navigation.py +194 -0
  499. karni_cli-0.5.0/tests/test_speed.py +83 -0
  500. karni_cli-0.5.0/tests/test_suggest.py +474 -0
  501. karni_cli-0.5.0/tests/test_tool_names.py +101 -0
  502. karni_cli-0.5.0/tests/test_types.py +210 -0
  503. karni_cli-0.5.0/tests/test_ui_detect.py +721 -0
  504. karni_cli-0.5.0/tests/test_ui_detect_css.py +458 -0
  505. {karni_cli-0.3.1 → karni_cli-0.5.0}/tests/test_upgrade.py +149 -6
  506. karni_cli-0.5.0/tests/test_why.py +191 -0
  507. karni_cli-0.3.1/README.md +0 -153
  508. karni_cli-0.3.1/karni_cli/__init__.py +0 -3
  509. karni_cli-0.3.1/karni_cli/_agent/rules.py +0 -673
  510. karni_cli-0.3.1/karni_cli/_errorcodes/__init__.py +0 -1171
  511. karni_cli-0.3.1/karni_cli/_templates/project/{{cookiecutter.project_slug}}/.env.example +0 -85
  512. karni_cli-0.3.1/karni_cli/_templates/project/{{cookiecutter.project_slug}}/.gitignore +0 -10
  513. karni_cli-0.3.1/karni_cli/_templates/project/{{cookiecutter.project_slug}}/Caddyfile +0 -22
  514. karni_cli-0.3.1/karni_cli/_templates/project/{{cookiecutter.project_slug}}/Dockerfile +0 -53
  515. karni_cli-0.3.1/karni_cli/_templates/project/{{cookiecutter.project_slug}}/README.md +0 -169
  516. karni_cli-0.3.1/karni_cli/_templates/project/{{cookiecutter.project_slug}}/config/settings.py +0 -28
  517. karni_cli-0.3.1/karni_cli/_templates/project/{{cookiecutter.project_slug}}/config/urls.py +0 -31
  518. karni_cli-0.3.1/karni_cli/_templates/project/{{cookiecutter.project_slug}}/frontend/.npmrc +0 -7
  519. karni_cli-0.3.1/karni_cli/_templates/project/{{cookiecutter.project_slug}}/frontend/postcss.config.js +0 -6
  520. karni_cli-0.3.1/karni_cli/_templates/project/{{cookiecutter.project_slug}}/frontend/src/api/health.ts +0 -21
  521. karni_cli-0.3.1/karni_cli/_templates/project/{{cookiecutter.project_slug}}/frontend/src/index.css +0 -11
  522. karni_cli-0.3.1/karni_cli/_templates/project/{{cookiecutter.project_slug}}/frontend/src/layout.tsx +0 -51
  523. karni_cli-0.3.1/karni_cli/_templates/project/{{cookiecutter.project_slug}}/frontend/src/pages/home.tsx +0 -28
  524. karni_cli-0.3.1/karni_cli/_templates/project/{{cookiecutter.project_slug}}/frontend/vite.config.ts +0 -18
  525. karni_cli-0.3.1/karni_cli/commands/add.py +0 -144
  526. karni_cli-0.3.1/karni_cli/commands/check.py +0 -101
  527. karni_cli-0.3.1/karni_cli/commands/context.py +0 -171
  528. karni_cli-0.3.1/karni_cli/commands/doctor.py +0 -136
  529. karni_cli-0.3.1/karni_cli/commands/explain.py +0 -60
  530. karni_cli-0.3.1/karni_cli/commands/new.py +0 -106
  531. karni_cli-0.3.1/karni_cli/commands/seed.py +0 -34
  532. karni_cli-0.3.1/karni_cli/commands/serve.py +0 -50
  533. karni_cli-0.3.1/karni_cli/commands/types.py +0 -72
  534. karni_cli-0.3.1/karni_cli/commands/worker.py +0 -63
  535. karni_cli-0.3.1/karni_cli/errorcodes.py +0 -377
  536. karni_cli-0.3.1/karni_cli/generators/fields.py +0 -343
  537. karni_cli-0.3.1/karni_cli/generators/introspect.py +0 -263
  538. karni_cli-0.3.1/karni_cli/generators/model.py +0 -235
  539. karni_cli-0.3.1/karni_cli/generators/naming.py +0 -100
  540. karni_cli-0.3.1/karni_cli/mcp_server.py +0 -103
  541. karni_cli-0.3.1/karni_cli/settings_edit.py +0 -128
  542. karni_cli-0.3.1/karni_cli/typegen.py +0 -101
  543. karni_cli-0.3.1/tests/test_check.py +0 -78
  544. karni_cli-0.3.1/tests/test_context.py +0 -134
  545. karni_cli-0.3.1/tests/test_errorcodes_cli.py +0 -130
  546. karni_cli-0.3.1/tests/test_make.py +0 -541
  547. karni_cli-0.3.1/tests/test_make_gate.py +0 -404
  548. karni_cli-0.3.1/tests/test_new.py +0 -216
  549. karni_cli-0.3.1/tests/test_rules.py +0 -156
  550. karni_cli-0.3.1/tests/test_types.py +0 -48
  551. {karni_cli-0.3.1 → karni_cli-0.5.0}/LICENSE +0 -0
  552. {karni_cli-0.3.1 → karni_cli-0.5.0}/karni_cli/_agent/__main__.py +0 -0
  553. {karni_cli-0.3.1 → karni_cli-0.5.0}/karni_cli/_changelog/0.2.0.toml +0 -0
  554. {karni_cli-0.3.1 → karni_cli-0.5.0}/karni_cli/_changelog/0.3.0.toml +0 -0
  555. {karni_cli-0.3.1 → karni_cli-0.5.0}/karni_cli/_changelog/__init__.py +0 -0
  556. {karni_cli-0.3.1 → karni_cli-0.5.0}/karni_cli/_errorcodes/__main__.py +0 -0
  557. {karni_cli-0.3.1 → karni_cli-0.5.0}/karni_cli/_templates/project/{{cookiecutter.project_slug}}/config/__init__.py +0 -0
  558. {karni_cli-0.3.1 → karni_cli-0.5.0}/karni_cli/_templates/project/{{cookiecutter.project_slug}}/config/asgi.py +0 -0
  559. {karni_cli-0.3.1 → karni_cli-0.5.0}/karni_cli/_templates/project/{{cookiecutter.project_slug}}/config/celery.py +0 -0
  560. {karni_cli-0.3.1 → karni_cli-0.5.0}/karni_cli/_templates/project/{{cookiecutter.project_slug}}/config/wsgi.py +0 -0
  561. {karni_cli-0.3.1 → karni_cli-0.5.0}/karni_cli/_templates/project/{{cookiecutter.project_slug}}/frontend/.dockerignore +0 -0
  562. {karni_cli-0.3.1 → karni_cli-0.5.0}/karni_cli/_templates/project/{{cookiecutter.project_slug}}/frontend/.jscpd.json +0 -0
  563. {karni_cli-0.3.1 → karni_cli-0.5.0}/karni_cli/_templates/project/{{cookiecutter.project_slug}}/frontend/public/favicon.svg +0 -0
  564. {karni_cli-0.3.1 → karni_cli-0.5.0}/karni_cli/_templates/project/{{cookiecutter.project_slug}}/frontend/src/main.tsx +0 -0
  565. {karni_cli-0.3.1 → karni_cli-0.5.0}/karni_cli/_templates/project/{{cookiecutter.project_slug}}/frontend/src/vite-env.d.ts +0 -0
  566. {karni_cli-0.3.1 → karni_cli-0.5.0}/karni_cli/_templates/project/{{cookiecutter.project_slug}}/frontend/tsconfig.json +0 -0
  567. {karni_cli-0.3.1 → karni_cli-0.5.0}/karni_cli/_templates/project/{{cookiecutter.project_slug}}/manage.py +0 -0
  568. {karni_cli-0.3.1 → karni_cli-0.5.0}/karni_cli/_templates/project/{{cookiecutter.project_slug}}/tests/__init__.py +0 -0
  569. {karni_cli-0.3.1 → karni_cli-0.5.0}/karni_cli/brand.py +0 -0
  570. {karni_cli-0.3.1 → karni_cli-0.5.0}/karni_cli/commands/__init__.py +0 -0
  571. {karni_cli-0.3.1 → karni_cli-0.5.0}/karni_cli/commands/mcp.py +0 -0
  572. {karni_cli-0.3.1 → karni_cli-0.5.0}/karni_cli/config.py +0 -0
  573. {karni_cli-0.3.1 → karni_cli-0.5.0}/karni_cli/environment.py +0 -0
  574. {karni_cli-0.3.1 → karni_cli-0.5.0}/karni_cli/history.py +0 -0
  575. {karni_cli-0.3.1 → karni_cli-0.5.0}/karni_cli/upgrades/__init__.py +0 -0
  576. {karni_cli-0.3.1 → karni_cli-0.5.0}/karni_cli/upgrades/changelog.py +0 -0
  577. {karni_cli-0.3.1 → karni_cli-0.5.0}/karni_cli/upgrades/codemod.py +0 -0
  578. {karni_cli-0.3.1 → karni_cli-0.5.0}/karni_cli/upgrades/legacy_agent_files.py +0 -0
  579. {karni_cli-0.3.1 → karni_cli-0.5.0}/karni_cli/upgrades/transforms/rename-export.cjs +0 -0
  580. {karni_cli-0.3.1 → karni_cli-0.5.0}/karni_cli/upgrades/v0_2/__init__.py +0 -0
  581. {karni_cli-0.3.1/tests → karni_cli-0.5.0/karni_cli/upgrades/v0_5}/__init__.py +0 -0
  582. {karni_cli-0.3.1 → karni_cli-0.5.0}/karni_cli/upgrades/v1_0/__init__.py +0 -0
  583. {karni_cli-0.3.1 → karni_cli-0.5.0}/karni_cli/upgrades/v1_0/all_objects_to_without.py +0 -0
  584. {karni_cli-0.3.1 → karni_cli-0.5.0}/karni_cli/upgrades/v1_0/all_with_deleted_to_without.py +0 -0
  585. {karni_cli-0.3.1 → karni_cli-0.5.0}/karni_cli/upgrades/v1_0/deleted_only_to_without_dead.py +0 -0
  586. {karni_cli-0.3.1 → karni_cli-0.5.0}/karni_cli/upgrades/v1_0/object_permission_classes_to_access.py +0 -0
  587. {karni_cli-0.3.1 → karni_cli-0.5.0}/karni_cli/upgrades/v1_0/related_lookups_to_optimize.py +0 -0
  588. {karni_cli-0.3.1 → karni_cli-0.5.0}/karni_cli/upgrades/v1_0/scoped_related_lookups_to_optimize.py +0 -0
  589. {karni_cli-0.3.1 → karni_cli-0.5.0}/karni_cli/upgrades/v1_0/soft_delete_manager_mixin_to_scoped.py +0 -0
  590. {karni_cli-0.3.1 → karni_cli-0.5.0}/tests/fixtures/schema.fixture.json +0 -0
  591. {karni_cli-0.3.1 → karni_cli-0.5.0}/tests/fixtures/upgrade_changelog/0.9.0.toml +0 -0
  592. {karni_cli-0.3.1 → karni_cli-0.5.0}/tests/test_brand.py +0 -0
  593. {karni_cli-0.3.1 → karni_cli-0.5.0}/tests/test_docs_tutorial.py +0 -0
  594. {karni_cli-0.3.1 → karni_cli-0.5.0}/tests/test_project.py +0 -0
  595. {karni_cli-0.3.1 → karni_cli-0.5.0}/tests/test_upgrade_codemods.py +0 -0
  596. {karni_cli-0.3.1 → karni_cli-0.5.0}/tests/test_upgrade_typescript.py +0 -0
@@ -19,6 +19,9 @@ packages/karni-cli/karni_cli/_templates/
19
19
  packages/karni-cli/karni_cli/_agent/
20
20
  packages/karni-cli/karni_cli/_changelog/
21
21
  packages/karni-cli/karni_cli/_errorcodes/
22
+ packages/karni-cli/karni_cli/_settings/
23
+ packages/karni-cli/karni_cli/_catalog/
24
+ packages/karni-cli/karni_cli/_ui/
22
25
 
23
26
  # Node
24
27
  node_modules/
@@ -31,8 +34,11 @@ storybook-static/
31
34
  !.env.example
32
35
  .DS_Store
33
36
  .idea/
34
- .claude/scheduled_tasks.lock
35
- .claude/settings.local.json
36
37
 
37
38
  # MkDocs build output
38
39
  site/
40
+ .github/ci/prod_e2e/test-results/
41
+
42
+ # Contributors' own agent working files stay on their machines
43
+ /CLAUDE.md
44
+ /.claude/
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: karni-cli
3
- Version: 0.3.1
4
- Summary: The karni command for the Karni Django + React framework: scaffold a project, generate models, viewsets and pages, run it, upgrade it across releases, and give AI coding agents its context, rules and error explanations.
3
+ Version: 0.5.0
4
+ Summary: The karni command: scaffold, generate, run and upgrade Karni projects. Karni is an open-source Django + React framework for building with AI coding agents. Your agent writes only your domain. The API, admin, permissions and React screens come from a package you upgrade, not code it rewrites in each project. One rule set covers every coding agent. The build fails when an agent hand-writes what Karni ships.
5
5
  Project-URL: Homepage, https://github.com/cbsshekhawat18-lab/karni
6
6
  Project-URL: Documentation, https://cbsshekhawat18-lab.github.io/karni/
7
7
  Project-URL: Repository, https://github.com/cbsshekhawat18-lab/karni
@@ -10,7 +10,7 @@ Project-URL: Changelog, https://github.com/cbsshekhawat18-lab/karni/tree/main/do
10
10
  Author-email: Chandrabhan Shekhawat <cbsshekhawat18@gmail.com>
11
11
  License-Expression: Apache-2.0
12
12
  License-File: LICENSE
13
- Keywords: ai-agents,claude-code,cli,code-generation,cookiecutter,copilot,cursor,django,mcp,project-template,react,scaffolding
13
+ Keywords: ai-agents,cli,code-generation,cookiecutter,django,mcp,project-template,react,scaffolding
14
14
  Classifier: Development Status :: 3 - Alpha
15
15
  Classifier: Environment :: Console
16
16
  Classifier: Framework :: Django
@@ -29,6 +29,7 @@ Requires-Python: >=3.12
29
29
  Requires-Dist: cookiecutter>=2.5
30
30
  Requires-Dist: libcst>=1.4
31
31
  Requires-Dist: packaging>=24.0
32
+ Requires-Dist: pydantic>=2
32
33
  Requires-Dist: pyyaml>=6.0
33
34
  Requires-Dist: tomlkit>=0.12
34
35
  Requires-Dist: typer>=0.12
@@ -38,66 +39,109 @@ Description-Content-Type: text/markdown
38
39
 
39
40
  # karni-cli
40
41
 
41
- The `karni` command. Orchestrates a Karni project's own `manage.py` via
42
- subprocess — the CLI itself never imports Django.
42
+ The karni command: scaffold, generate, run and upgrade Karni projects.
43
+
44
+ [![PyPI](https://img.shields.io/pypi/v/karni-cli)](https://pypi.org/project/karni-cli/) [![Python versions](https://img.shields.io/pypi/pyversions/karni-cli)](https://pypi.org/project/karni-cli/) [![License: Apache-2.0](https://img.shields.io/badge/license-Apache--2.0-blue)](https://github.com/cbsshekhawat18-lab/karni/blob/main/LICENSE) [![Docs](https://img.shields.io/badge/docs-online-FB5D08)](https://cbsshekhawat18-lab.github.io/karni/cli/)
45
+
46
+ It runs a project's own `manage.py` as a subprocess, so the CLI itself never imports Django. Karni's Python core is [`karni`](https://pypi.org/project/karni/) and its React side [`@karni/ui`](https://www.npmjs.com/package/@karni/ui).
47
+
48
+ ## Install
49
+
50
+ ```sh
51
+ pip install karni-cli
52
+ ```
53
+
54
+ ## A minimal example
55
+
56
+ The shop recipe, built on SQLite with no Docker:
57
+
58
+ ```sh
59
+ python3 -m venv .venv && . .venv/bin/activate
60
+ pip install karni karni-cli karni-payments pytest pytest-django
61
+ karni new "Corner Shop" --recipe shop && cd corner_shop
62
+ printf 'DATABASE_URL=sqlite:///data/db.sqlite3\nKARNI_CACHE=locmem\n' > .env
63
+ karni build
64
+ karni serve --local
65
+ ```
66
+
67
+ `karni build` runs the migrations, seeds demo data, generates the TypeScript types, and runs the tests and `karni check`. The [quickstart](https://cbsshekhawat18-lab.github.io/karni/quickstart/) does the same on PostgreSQL.
68
+
69
+ ## Main features
70
+
71
+ - **Start a project.** `karni new` scaffolds a site, an app or both, blank or from one of six [recipes](https://cbsshekhawat18-lab.github.io/karni/recipes/).
72
+ - **Build from a spec.** `karni spec validate`, `karni plan` and `karni build` turn `karni.yaml` into code ([the app spec](https://cbsshekhawat18-lab.github.io/karni/app-spec/)).
73
+ - **Generate.** `karni make app`, `model`, `page`, `schedule`, `task`, `site` and `form` write the files a project owns.
74
+ - **Modules.** `karni add` and `karni remove` wire a module in and out, and `karni modules` lists the catalog.
75
+ - **Run and check.** `karni serve`, `seed`, `migrate`, `test`, `types` and `check`, the last one failing the build when code rebuilds what Karni ships.
76
+ - **For coding agents.** `karni context`, `karni rules`, the procedures in AGENTS.md and `karni mcp`, the MCP server ([Karni for coding agents](https://cbsshekhawat18-lab.github.io/karni/agents/)).
77
+ - **Debugging.** `karni why`, `karni explain`, `karni trace`, `karni replay` and `karni queries` ([debugging](https://cbsshekhawat18-lab.github.io/karni/debugging/why/)).
78
+ - **Upgrades.** `karni upgrade` applies each release's codemods and lists what it could not change.
79
+
80
+ Every command and option is in [the karni command](https://cbsshekhawat18-lab.github.io/karni/cli/). A short list follows.
43
81
 
44
82
  ## Commands
45
- - `karni new <name>` — scaffold a project from the bundled cookiecutter
46
- template (monorepo checkouts use the live `templates/project`; override with
47
- `KARNI_TEMPLATES`).
48
- - `karni add <module>` — add `karni-<module>` to `[project].dependencies` and
83
+ - `karni new <name>`: scaffold a project from the bundled cookiecutter
84
+ template. Monorepo checkouts use the live `templates/project`, and
85
+ `KARNI_TEMPLATES` overrides it.
86
+ - `karni add <module>`: add `karni-<module>` to `[project].dependencies` and
49
87
  wire `karni_<module>` into the `# karni:apps` block in config/settings.py.
50
- Only that marker block is managed; any other layout gets a clear error and
88
+ Only that marker block is managed. Any other layout gets a clear error, and
51
89
  you edit settings manually.
52
90
  Once the module is installed it also records the module's
53
91
  `AGENTS.fragment.md` as `.karni/modules/<module>.md` and refreshes the agent
54
92
  adapters.
55
- - `karni types` — dump the OpenAPI schema (`manage.py spectacular`), generate
93
+ - `karni types`: dump the OpenAPI schema (`manage.py spectacular`), generate
56
94
  `types.ts` (openapi-typescript, project-pinned binary preferred, else
57
95
  `npx openapi-typescript@^7`) and typed hooks (`hooks.ts`) over @karni/ui.
58
- - `karni context` — compact machine-readable inventory (< 200 tokens for a
59
- typical project): APPS (from the `# karni:apps` block) and PAGES (from
60
- `frontend/src/pages/`) read statically, MODELS/VIEWSETS from `manage.py karni_context`,
61
- COMPONENTS/HOOKS from @karni/ui's build-generated `dist/manifest.json`
62
- (omitted when absent — run `npm i @karni/ui` in `frontend/` on the host to
63
- enable them; `--manifest PATH` overrides). Nothing is hand-maintained.
64
- - `karni context --with-history [PATH]` — the same inventory plus a
96
+ - `karni ui detect`: map the frontend's design system (shadcn/ui, a Tailwind
97
+ theme, Material UI, Chakra UI or Mantine) onto @karni/ui's `--karni-*`
98
+ tokens in `karni-theme.css`, plus `karni-primitives.tsx` for shadcn/ui.
99
+ `--dry-run` previews, `--json` reports for agents, and edited files are kept
100
+ unless `--force`.
101
+ - `karni context`: a compact machine-readable inventory (< 200 tokens for a
102
+ typical project). APPS (from the `# karni:apps` block) and PAGES (from
103
+ `frontend/src/pages/`) are read statically, MODELS/VIEWSETS come from `manage.py karni_context`,
104
+ and COMPONENTS/HOOKS from @karni/ui's build-generated `dist/manifest.json`.
105
+ Those two are omitted when the manifest is absent. Run `npm i @karni/ui` in
106
+ `frontend/` on the host to enable them, or override with `--manifest PATH`.
107
+ Nothing is hand-maintained.
108
+ - `karni context --with-history [PATH]`: the same inventory plus a
65
109
  `HISTORY:` brief of what was already asked and decided about PATH (without
66
110
  PATH: the project's recorded decisions) from any history provider that
67
111
  detects a store, e.g. Gigai Chronicle's `.chronicle/`. Capped at ~300
68
112
  tokens (characters ÷ 4), cut at line boundaries with a last line naming the
69
113
  full-brief command. With no store the output is exactly `karni context`'s.
70
114
  See `docs/concepts/history-providers.md`.
71
- - `karni check [-q]` — Django system checks plus `karni.checks` entry-point hooks
115
+ - `karni check [-q]`: Django system checks plus `karni.checks` entry-point hooks
72
116
  (the architecture-test extension surface). A clean run outside CI may end
73
- with one tip on stderr, at most once per project; `-q` suppresses it.
74
- - `karni doctor [-q]` — human-readable environment report: project,
75
- interpreter (`.venv` / compose service), Node/npm, the @karni/ui manifest,
76
- adapter freshness, history providers. May end with the same one-time tip.
77
- - `karni config get|set|list [--global] KEY [VALUE]` — settings
78
- (`suggest_tools`): `.karni/config.toml` in the project (committed) or
79
- `$XDG_CONFIG_HOME/karni/config.toml` with `--global`; the project wins.
117
+ with one tip on stderr, at most once per project. `-q` suppresses it.
118
+ - `karni doctor [-q]`: a human-readable environment report covering the
119
+ project, interpreter (`.venv` / compose service), Node/npm, the @karni/ui
120
+ manifest, adapter freshness and history providers. It may end with the same
121
+ one-time tip.
122
+ - `karni config get|set|list [--global] KEY [VALUE]`: settings
123
+ (`suggest_tools`), kept in `.karni/config.toml` in the project (committed) or
124
+ in `$XDG_CONFIG_HOME/karni/config.toml` with `--global`. The project wins.
80
125
  Machine-local state (e.g. "tip shown") lives in the self-ignoring
81
126
  `.karni/local/`.
82
- - `karni rules [--explain CODE | --procedure NAME | --check FILE... | --json]`
83
- — Karni's conventions from `karni.agent.rules` (no Django needed), and
127
+ - `karni rules [--explain CODE | --procedure NAME | --check FILE... | --json]`:
128
+ Karni's conventions from `karni.agent.rules` (no Django needed), and
84
129
  static single-file checks (exit 1 on violations).
85
- - `karni rules sync [--check] [--force]` — regenerate the thin agent adapters
86
- (AGENTS.md, CLAUDE.md, Cursor, Windsurf, Copilot, Cline, Aider, Junie) and
87
- slash commands from `karni_cli/agent_adapters.toml`; `--check` is the CI
88
- staleness gate.
89
- - `karni mcp` — context, rules and check as MCP tools
130
+ - `karni rules sync [--check] [--force]`: regenerate AGENTS.md, the agent
131
+ instructions with the procedures for routine tasks, from
132
+ `karni_cli/agent_adapters.toml`. `--check` is the CI staleness gate.
133
+ - `karni mcp`: context, rules and check as MCP tools
90
134
  (`pip install 'karni-cli[mcp]'`).
91
135
  - `karni upgrade [--to VERSION] [--from VERSION] [--dry-run] [--allow-dirty] [--list]`
92
136
  moves the project across Karni versions. It reads the karni installed in
93
137
  the project (`--from` overrides), takes every breaking change between that
94
138
  and `--to` from Karni's machine-readable changelog
95
139
  (`packages/karni/karni/changelog/*.toml`, bundled into karni-cli), and runs
96
- their codemods in release order. Python codemods use libcst; TypeScript
97
- codemods use a pinned jscodeshift through `npx` and are skipped, with the
98
- reason, without Node.js. The codemods run on a scratch copy, and the result
140
+ their codemods in release order. Python codemods use libcst. TypeScript
141
+ codemods use a pinned jscodeshift through `npx`, and without Node.js they
142
+ are skipped with the reason. The codemods run on a scratch copy, and the result
99
143
  is written back all at once, or not at all if one fails. `--dry-run` prints
100
- a unified diff and writes nothing. Writing needs a clean git tree;
144
+ a unified diff and writes nothing. Writing needs a clean git tree.
101
145
  `--allow-dirty` overrides that, and is also required outside git. The
102
146
  report lists what was applied (each file and its rewrite count), what could
103
147
  not be fixed automatically (the sites found, with each migration-note link)
@@ -110,7 +154,7 @@ See `docs/agents.md` for the agent surface in full.
110
154
  Artisan-style shortcuts. Each runner runs one project command through the
111
155
  project interpreter (see *Execution environment* below), streams its output
112
156
  and exits with its exit code. `--help` on each names the command it wraps.
113
- Extra arguments pass straight through; put `--` before any that clash with
157
+ Extra arguments pass straight through. Put `--` before any that clash with
114
158
  karni's own options (`--docker`, `--service`, `--help`).
115
159
 
116
160
  | Command | Runs |
@@ -138,25 +182,25 @@ With the compose stack up, `worker` and `beat` already run as services, so
138
182
  ## Generators
139
183
  `karni make <type>` writes the project code a task needs, so neither a person
140
184
  nor an AI agent hand-creates a file a generator makes. `karni make --list`
141
- prints them all; every one is also a hidden Laravel-style alias
185
+ prints them all. Each one is also available as a hidden Laravel-style alias,
142
186
  `karni make:<type>`. The full reference (every option, the field DSL) is
143
187
  [docs/cli.md](https://cbsshekhawat18-lab.github.io/karni/cli/), generated from this CLI.
144
188
 
145
189
  | Command | Writes |
146
190
  |---|---|
147
- | `karni make app NAME` | `NAME/{__init__,apps,models,viewsets}.py`, `migrations/`, `tests/`; wires `# karni:apps` |
148
- | `karni make model NAME [FIELD...]` | `class NAME(BaseModel)` in `<app>/models.py`; `--with viewset,page` / `-a` chains; `--migrate` |
191
+ | `karni make app NAME` | `NAME/{__init__,apps,models,viewsets}.py`, `migrations/`, `tests/`, and wires `# karni:apps` |
192
+ | `karni make model NAME [FIELD...]` | `class NAME(BaseModel)` in `<app>/models.py`, with `--with viewset,page` / `-a` chains and `--migrate` |
149
193
  | `karni make viewset MODEL` | `<Model>ViewSet` with its `access` (`--access authenticated\|public-read\|owned:<field>\|staff\|role:<name>`), `--search` |
150
194
  | `karni make serializer MODEL --reason ...` | `<app>/serializers.py` + `serializer_class` on the viewset |
151
195
  | `karni make migration [NAME]` | runs `manage.py makemigrations [--app] [--name] [--empty]` through the project interpreter |
152
196
  | `karni make task NAME` | `@shared_task` in `<app>/tasks.py` (`--retry N`) |
153
197
  | `karni make schedule NAME` | `every(...)`/`cron(...)` in `<app>/schedules.py` (`--every 15m` / `--cron "0 3 * * *"`, `--task`) |
154
198
  | `karni make event NAME` | a `Signal` in `<app>/events.py` |
155
- | `karni make listener NAME --on ...` | `<app>/listeners.py`: `Model.created\|updated\|deleted` or a custom event; `--queued` |
199
+ | `karni make listener NAME --on ...` | `<app>/listeners.py`: `Model.created\|updated\|deleted` or a custom event, with `--queued` |
156
200
  | `karni make command NAME` | `<app>/management/commands/NAME.py` |
157
201
  | `karni make service NAME` | `<app>/services/NAME.py` (where HTTP clients are allowed) |
158
202
  | `karni make middleware NAME` | `<app>/middleware.py`, wired through `# karni:middleware` |
159
- | `karni make page NAME` | `frontend/src/pages/NAME.tsx` (≤ 50 lines; `--resource R --kind list\|detail\|form`), route in `frontend/src/routes.tsx` |
203
+ | `karni make page NAME` | `frontend/src/pages/NAME.tsx` (≤ 50 lines, `--resource R --kind list\|detail\|form`), route in `frontend/src/routes.tsx` |
160
204
  | `karni make component NAME` | `frontend/src/components/NAME.tsx` claiming a role (`--role`) |
161
205
  | `karni make module NAME` | `modules/karni-NAME/` per docs/modules.md |
162
206
 
@@ -169,23 +213,33 @@ karni make listener notify_organizer --on Event.created --queued
169
213
  karni make schedule nightly-report --cron "0 3 * * *"
170
214
  ```
171
215
 
172
- Every generator: never overwrites without `--force`; `--dry-run` prints the
173
- files and diff and writes nothing; prints each created/modified file plus
174
- notes (the chosen `access`, the route, the next command); resolves the app
175
- from `--app` or the project's only local app; edits existing files only
176
- through marker comments or AST-located appends (an unfamiliar layout is an
177
- error naming the manual step); never imports Django. Generated Python is
178
- clean under ruff (lint and format) and `karni rules --check`, and generated
179
- pages parse and stay within 50 lines — `tests/test_make_gate.py` generates
180
- every type into a fresh scaffold and asserts it (plus `tsc` and the
181
- frontend's ESLint config when `KARNI_TEST_NODE_MODULES` points at an
182
- installed `frontend/node_modules`), then runs the generated backend for real
183
- (makemigrations, migrate, check, requests through the Django test client).
216
+ Every generator follows the same rules. It never overwrites without
217
+ `--force`, and `--dry-run` prints the files and diff and writes nothing. It
218
+ prints each created/modified file plus notes (the chosen `access`, the route,
219
+ the next command). It resolves the app from `--app` or the project's only
220
+ local app. It edits existing files only through marker comments or
221
+ AST-located appends, and an unfamiliar layout is an error naming the manual
222
+ step. It never imports Django. Generated Python is clean under ruff (lint and
223
+ format) and `karni rules --check`, and generated pages parse and stay within
224
+ 50 lines. `tests/test_make_gate.py` generates every type into a fresh scaffold
225
+ and asserts this (plus `tsc` and the frontend's ESLint config when
226
+ `KARNI_TEST_NODE_MODULES` points at an installed `frontend/node_modules`).
227
+ Then it runs the generated backend for real (makemigrations, migrate, check,
228
+ requests through the Django test client).
184
229
 
185
230
  Quote fields that end in `?` in zsh (`'venue:fk:Venue?'`) and choice values
186
231
  joined by `|`.
187
232
 
188
233
  ## Execution environment
189
234
  Commands that run the project resolve, in order: `--docker/--no-docker` flag →
190
- `<project>/.venv` → a running compose service (default `django`; change with
235
+ `<project>/.venv` → a running compose service (default `django`, changed with
191
236
  `--service` or `KARNI_COMPOSE_SERVICE`) → an error naming both remedies.
237
+
238
+ ## Links
239
+
240
+ - The karni command: <https://cbsshekhawat18-lab.github.io/karni/cli/>
241
+ - Quickstart: <https://cbsshekhawat18-lab.github.io/karni/quickstart/>
242
+ - Karni, the framework this package is part of: <https://github.com/cbsshekhawat18-lab/karni>
243
+ - Changelog: <https://github.com/cbsshekhawat18-lab/karni/blob/main/CHANGELOG.md>
244
+ - Issues: <https://github.com/cbsshekhawat18-lab/karni/issues>
245
+ - License: Apache-2.0. karni-cli is released with every other Karni package, at one version.
@@ -0,0 +1,206 @@
1
+ # karni-cli
2
+
3
+ The karni command: scaffold, generate, run and upgrade Karni projects.
4
+
5
+ [![PyPI](https://img.shields.io/pypi/v/karni-cli)](https://pypi.org/project/karni-cli/) [![Python versions](https://img.shields.io/pypi/pyversions/karni-cli)](https://pypi.org/project/karni-cli/) [![License: Apache-2.0](https://img.shields.io/badge/license-Apache--2.0-blue)](https://github.com/cbsshekhawat18-lab/karni/blob/main/LICENSE) [![Docs](https://img.shields.io/badge/docs-online-FB5D08)](https://cbsshekhawat18-lab.github.io/karni/cli/)
6
+
7
+ It runs a project's own `manage.py` as a subprocess, so the CLI itself never imports Django. Karni's Python core is [`karni`](https://pypi.org/project/karni/) and its React side [`@karni/ui`](https://www.npmjs.com/package/@karni/ui).
8
+
9
+ ## Install
10
+
11
+ ```sh
12
+ pip install karni-cli
13
+ ```
14
+
15
+ ## A minimal example
16
+
17
+ The shop recipe, built on SQLite with no Docker:
18
+
19
+ ```sh
20
+ python3 -m venv .venv && . .venv/bin/activate
21
+ pip install karni karni-cli karni-payments pytest pytest-django
22
+ karni new "Corner Shop" --recipe shop && cd corner_shop
23
+ printf 'DATABASE_URL=sqlite:///data/db.sqlite3\nKARNI_CACHE=locmem\n' > .env
24
+ karni build
25
+ karni serve --local
26
+ ```
27
+
28
+ `karni build` runs the migrations, seeds demo data, generates the TypeScript types, and runs the tests and `karni check`. The [quickstart](https://cbsshekhawat18-lab.github.io/karni/quickstart/) does the same on PostgreSQL.
29
+
30
+ ## Main features
31
+
32
+ - **Start a project.** `karni new` scaffolds a site, an app or both, blank or from one of six [recipes](https://cbsshekhawat18-lab.github.io/karni/recipes/).
33
+ - **Build from a spec.** `karni spec validate`, `karni plan` and `karni build` turn `karni.yaml` into code ([the app spec](https://cbsshekhawat18-lab.github.io/karni/app-spec/)).
34
+ - **Generate.** `karni make app`, `model`, `page`, `schedule`, `task`, `site` and `form` write the files a project owns.
35
+ - **Modules.** `karni add` and `karni remove` wire a module in and out, and `karni modules` lists the catalog.
36
+ - **Run and check.** `karni serve`, `seed`, `migrate`, `test`, `types` and `check`, the last one failing the build when code rebuilds what Karni ships.
37
+ - **For coding agents.** `karni context`, `karni rules`, the procedures in AGENTS.md and `karni mcp`, the MCP server ([Karni for coding agents](https://cbsshekhawat18-lab.github.io/karni/agents/)).
38
+ - **Debugging.** `karni why`, `karni explain`, `karni trace`, `karni replay` and `karni queries` ([debugging](https://cbsshekhawat18-lab.github.io/karni/debugging/why/)).
39
+ - **Upgrades.** `karni upgrade` applies each release's codemods and lists what it could not change.
40
+
41
+ Every command and option is in [the karni command](https://cbsshekhawat18-lab.github.io/karni/cli/). A short list follows.
42
+
43
+ ## Commands
44
+ - `karni new <name>`: scaffold a project from the bundled cookiecutter
45
+ template. Monorepo checkouts use the live `templates/project`, and
46
+ `KARNI_TEMPLATES` overrides it.
47
+ - `karni add <module>`: add `karni-<module>` to `[project].dependencies` and
48
+ wire `karni_<module>` into the `# karni:apps` block in config/settings.py.
49
+ Only that marker block is managed. Any other layout gets a clear error, and
50
+ you edit settings manually.
51
+ Once the module is installed it also records the module's
52
+ `AGENTS.fragment.md` as `.karni/modules/<module>.md` and refreshes the agent
53
+ adapters.
54
+ - `karni types`: dump the OpenAPI schema (`manage.py spectacular`), generate
55
+ `types.ts` (openapi-typescript, project-pinned binary preferred, else
56
+ `npx openapi-typescript@^7`) and typed hooks (`hooks.ts`) over @karni/ui.
57
+ - `karni ui detect`: map the frontend's design system (shadcn/ui, a Tailwind
58
+ theme, Material UI, Chakra UI or Mantine) onto @karni/ui's `--karni-*`
59
+ tokens in `karni-theme.css`, plus `karni-primitives.tsx` for shadcn/ui.
60
+ `--dry-run` previews, `--json` reports for agents, and edited files are kept
61
+ unless `--force`.
62
+ - `karni context`: a compact machine-readable inventory (< 200 tokens for a
63
+ typical project). APPS (from the `# karni:apps` block) and PAGES (from
64
+ `frontend/src/pages/`) are read statically, MODELS/VIEWSETS come from `manage.py karni_context`,
65
+ and COMPONENTS/HOOKS from @karni/ui's build-generated `dist/manifest.json`.
66
+ Those two are omitted when the manifest is absent. Run `npm i @karni/ui` in
67
+ `frontend/` on the host to enable them, or override with `--manifest PATH`.
68
+ Nothing is hand-maintained.
69
+ - `karni context --with-history [PATH]`: the same inventory plus a
70
+ `HISTORY:` brief of what was already asked and decided about PATH (without
71
+ PATH: the project's recorded decisions) from any history provider that
72
+ detects a store, e.g. Gigai Chronicle's `.chronicle/`. Capped at ~300
73
+ tokens (characters ÷ 4), cut at line boundaries with a last line naming the
74
+ full-brief command. With no store the output is exactly `karni context`'s.
75
+ See `docs/concepts/history-providers.md`.
76
+ - `karni check [-q]`: Django system checks plus `karni.checks` entry-point hooks
77
+ (the architecture-test extension surface). A clean run outside CI may end
78
+ with one tip on stderr, at most once per project. `-q` suppresses it.
79
+ - `karni doctor [-q]`: a human-readable environment report covering the
80
+ project, interpreter (`.venv` / compose service), Node/npm, the @karni/ui
81
+ manifest, adapter freshness and history providers. It may end with the same
82
+ one-time tip.
83
+ - `karni config get|set|list [--global] KEY [VALUE]`: settings
84
+ (`suggest_tools`), kept in `.karni/config.toml` in the project (committed) or
85
+ in `$XDG_CONFIG_HOME/karni/config.toml` with `--global`. The project wins.
86
+ Machine-local state (e.g. "tip shown") lives in the self-ignoring
87
+ `.karni/local/`.
88
+ - `karni rules [--explain CODE | --procedure NAME | --check FILE... | --json]`:
89
+ Karni's conventions from `karni.agent.rules` (no Django needed), and
90
+ static single-file checks (exit 1 on violations).
91
+ - `karni rules sync [--check] [--force]`: regenerate AGENTS.md, the agent
92
+ instructions with the procedures for routine tasks, from
93
+ `karni_cli/agent_adapters.toml`. `--check` is the CI staleness gate.
94
+ - `karni mcp`: context, rules and check as MCP tools
95
+ (`pip install 'karni-cli[mcp]'`).
96
+ - `karni upgrade [--to VERSION] [--from VERSION] [--dry-run] [--allow-dirty] [--list]`
97
+ moves the project across Karni versions. It reads the karni installed in
98
+ the project (`--from` overrides), takes every breaking change between that
99
+ and `--to` from Karni's machine-readable changelog
100
+ (`packages/karni/karni/changelog/*.toml`, bundled into karni-cli), and runs
101
+ their codemods in release order. Python codemods use libcst. TypeScript
102
+ codemods use a pinned jscodeshift through `npx`, and without Node.js they
103
+ are skipped with the reason. The codemods run on a scratch copy, and the result
104
+ is written back all at once, or not at all if one fails. `--dry-run` prints
105
+ a unified diff and writes nothing. Writing needs a clean git tree.
106
+ `--allow-dirty` overrides that, and is also required outside git. The
107
+ report lists what was applied (each file and its rewrite count), what could
108
+ not be fixed automatically (the sites found, with each migration-note link)
109
+ and what was skipped. Run it before you raise the karni pin. See
110
+ `docs/migrations/`.
111
+
112
+ See `docs/agents.md` for the agent surface in full.
113
+
114
+ ## Runners
115
+ Artisan-style shortcuts. Each runner runs one project command through the
116
+ project interpreter (see *Execution environment* below), streams its output
117
+ and exits with its exit code. `--help` on each names the command it wraps.
118
+ Extra arguments pass straight through. Put `--` before any that clash with
119
+ karni's own options (`--docker`, `--service`, `--help`).
120
+
121
+ | Command | Runs |
122
+ |---|---|
123
+ | `karni serve` | `docker compose up` (`--build`, `-d`) |
124
+ | `karni serve --local [--host H] [--port P]` | `manage.py runserver 127.0.0.1:8000` via `.venv` |
125
+ | `karni migrate [ARGS]` | `manage.py migrate [ARGS]` |
126
+ | `karni test [ARGS]` | `python -m pytest [ARGS]` |
127
+ | `karni shell [ARGS]` | `manage.py shell [ARGS]` |
128
+ | `karni routes [--json]` | `manage.py karni_routes`: every URL with methods, name, view, model, access |
129
+ | `karni worker [-A APP] [-l LEVEL] [ARGS]` | `python -m celery -A config worker -l info [ARGS]` |
130
+ | `karni beat [-A APP] [-l LEVEL] [ARGS]` | `python -m celery -A config beat -l info [ARGS]` |
131
+ | `karni schedule list [--json]` | `manage.py karni_schedules`: every merged beat schedule |
132
+ | `karni schedule run NAME` | `manage.py karni_schedules --run NAME`: runs the task once, synchronously |
133
+ | `karni createsuperuser [ARGS]` | `manage.py createsuperuser [ARGS]` |
134
+ | `karni manage ARGS` | `manage.py ARGS`: the raw passthrough for everything else |
135
+
136
+ In docker mode, `shell`, `test`, `worker`, `beat`, `createsuperuser` and
137
+ `manage` get a TTY (`docker compose exec` without `-T`) when karni runs in a
138
+ terminal, so prompts and Ctrl-C work. Scripted and agent runs keep `-T`.
139
+ With the compose stack up, `worker` and `beat` already run as services, so
140
+ `karni worker` and `karni beat` are for `.venv` development. See
141
+ `docs/events.md` and `docs/scheduling.md`.
142
+
143
+ ## Generators
144
+ `karni make <type>` writes the project code a task needs, so neither a person
145
+ nor an AI agent hand-creates a file a generator makes. `karni make --list`
146
+ prints them all. Each one is also available as a hidden Laravel-style alias,
147
+ `karni make:<type>`. The full reference (every option, the field DSL) is
148
+ [docs/cli.md](https://cbsshekhawat18-lab.github.io/karni/cli/), generated from this CLI.
149
+
150
+ | Command | Writes |
151
+ |---|---|
152
+ | `karni make app NAME` | `NAME/{__init__,apps,models,viewsets}.py`, `migrations/`, `tests/`, and wires `# karni:apps` |
153
+ | `karni make model NAME [FIELD...]` | `class NAME(BaseModel)` in `<app>/models.py`, with `--with viewset,page` / `-a` chains and `--migrate` |
154
+ | `karni make viewset MODEL` | `<Model>ViewSet` with its `access` (`--access authenticated\|public-read\|owned:<field>\|staff\|role:<name>`), `--search` |
155
+ | `karni make serializer MODEL --reason ...` | `<app>/serializers.py` + `serializer_class` on the viewset |
156
+ | `karni make migration [NAME]` | runs `manage.py makemigrations [--app] [--name] [--empty]` through the project interpreter |
157
+ | `karni make task NAME` | `@shared_task` in `<app>/tasks.py` (`--retry N`) |
158
+ | `karni make schedule NAME` | `every(...)`/`cron(...)` in `<app>/schedules.py` (`--every 15m` / `--cron "0 3 * * *"`, `--task`) |
159
+ | `karni make event NAME` | a `Signal` in `<app>/events.py` |
160
+ | `karni make listener NAME --on ...` | `<app>/listeners.py`: `Model.created\|updated\|deleted` or a custom event, with `--queued` |
161
+ | `karni make command NAME` | `<app>/management/commands/NAME.py` |
162
+ | `karni make service NAME` | `<app>/services/NAME.py` (where HTTP clients are allowed) |
163
+ | `karni make middleware NAME` | `<app>/middleware.py`, wired through `# karni:middleware` |
164
+ | `karni make page NAME` | `frontend/src/pages/NAME.tsx` (≤ 50 lines, `--resource R --kind list\|detail\|form`), route in `frontend/src/routes.tsx` |
165
+ | `karni make component NAME` | `frontend/src/components/NAME.tsx` claiming a role (`--role`) |
166
+ | `karni make module NAME` | `modules/karni-NAME/` per docs/modules.md |
167
+
168
+ ```sh
169
+ karni make app events
170
+ karni make model Event title:str:200 starts_at:datetime "status:choice:draft|live" \
171
+ organizer:fk:User 'venue:fk:Venue?' -a --access owned:organizer --search title
172
+ karni make migration && karni migrate
173
+ karni make listener notify_organizer --on Event.created --queued
174
+ karni make schedule nightly-report --cron "0 3 * * *"
175
+ ```
176
+
177
+ Every generator follows the same rules. It never overwrites without
178
+ `--force`, and `--dry-run` prints the files and diff and writes nothing. It
179
+ prints each created/modified file plus notes (the chosen `access`, the route,
180
+ the next command). It resolves the app from `--app` or the project's only
181
+ local app. It edits existing files only through marker comments or
182
+ AST-located appends, and an unfamiliar layout is an error naming the manual
183
+ step. It never imports Django. Generated Python is clean under ruff (lint and
184
+ format) and `karni rules --check`, and generated pages parse and stay within
185
+ 50 lines. `tests/test_make_gate.py` generates every type into a fresh scaffold
186
+ and asserts this (plus `tsc` and the frontend's ESLint config when
187
+ `KARNI_TEST_NODE_MODULES` points at an installed `frontend/node_modules`).
188
+ Then it runs the generated backend for real (makemigrations, migrate, check,
189
+ requests through the Django test client).
190
+
191
+ Quote fields that end in `?` in zsh (`'venue:fk:Venue?'`) and choice values
192
+ joined by `|`.
193
+
194
+ ## Execution environment
195
+ Commands that run the project resolve, in order: `--docker/--no-docker` flag →
196
+ `<project>/.venv` → a running compose service (default `django`, changed with
197
+ `--service` or `KARNI_COMPOSE_SERVICE`) → an error naming both remedies.
198
+
199
+ ## Links
200
+
201
+ - The karni command: <https://cbsshekhawat18-lab.github.io/karni/cli/>
202
+ - Quickstart: <https://cbsshekhawat18-lab.github.io/karni/quickstart/>
203
+ - Karni, the framework this package is part of: <https://github.com/cbsshekhawat18-lab/karni>
204
+ - Changelog: <https://github.com/cbsshekhawat18-lab/karni/blob/main/CHANGELOG.md>
205
+ - Issues: <https://github.com/cbsshekhawat18-lab/karni/issues>
206
+ - License: Apache-2.0. karni-cli is released with every other Karni package, at one version.
@@ -11,7 +11,15 @@ to Karni's machine-readable changelog (packages/karni/karni/changelog ->
11
11
  karni_cli/_changelog), which `karni upgrade` reads: the CLI must know every
12
12
  change up to its own release, whatever karni the project has installed.
13
13
  Likewise Karni's error code registry (packages/karni/karni/errorcodes ->
14
- karni_cli/_errorcodes), which `karni explain` and error messages read.
14
+ karni_cli/_errorcodes), which `karni explain` and error messages read, the
15
+ settings reference (packages/karni/karni/conf/reference.py and the base.py it
16
+ reads -> karni_cli/_settings), which `karni explain <SETTING>` reads, and
17
+ @karni/ui's token stylesheet (packages/karni-ui/src/styles.css ->
18
+ karni_cli/_ui/styles.css), whose defaults `karni ui detect` lists when a
19
+ project has neither @karni/ui installed nor a monorepo checkout. And the
20
+ module catalog (packages/karni/karni/catalog -> karni_cli/_catalog, with a
21
+ copy of each module's karni.module.toml under _catalog/modules/), so
22
+ `karni modules list` shows the modules a project has not installed.
15
23
  """
16
24
 
17
25
  from __future__ import annotations
@@ -49,6 +57,15 @@ class TemplateBundleHook(BuildHookInterface):
49
57
  self._bundle_karni(pkg_root, "agent", "_agent", "agent rules", build_data)
50
58
  self._bundle_karni(pkg_root, "changelog", "_changelog", "changelog", build_data)
51
59
  self._bundle_karni(pkg_root, "errorcodes", "_errorcodes", "error codes", build_data)
60
+ self._bundle_karni(pkg_root, "catalog", "_catalog", "module catalog", build_data)
61
+ manifests = sorted(pkg_root.parent.parent.glob("modules/*/karni_*/karni.module.toml"))
62
+ bundled_modules = pkg_root / "karni_cli" / "_catalog" / "modules"
63
+ if manifests:
64
+ bundled_modules.mkdir(parents=True, exist_ok=True)
65
+ for manifest in manifests:
66
+ shutil.copy2(manifest, bundled_modules / f"{manifest.parent.parent.name}.toml")
67
+ elif not bundled_modules.is_dir():
68
+ raise RuntimeError("No module manifests to bundle into karni_cli/_catalog/modules.")
52
69
  # karni.links (every published URL, stdlib only) rides inside the
53
70
  # errorcodes bundle: the registry loads it by path when karni is absent.
54
71
  links = pkg_root.parent / "karni" / "karni" / "links.py"
@@ -58,6 +75,26 @@ class TemplateBundleHook(BuildHookInterface):
58
75
  elif not bundled_links.is_file():
59
76
  raise RuntimeError("No karni/links.py to bundle into karni_cli/_errorcodes.")
60
77
 
78
+ # The settings reference (stdlib only) and the file it reads: `karni explain <SETTING>`.
79
+ settings_bundle = pkg_root / "karni_cli" / "_settings"
80
+ conf = pkg_root.parent / "karni" / "karni" / "conf"
81
+ if (conf / "reference.py").is_file():
82
+ settings_bundle.mkdir(parents=True, exist_ok=True)
83
+ for name in ("reference.py", "base.py"):
84
+ shutil.copy2(conf / name, settings_bundle / name)
85
+ elif not (settings_bundle / "reference.py").is_file():
86
+ raise RuntimeError("No karni/conf/reference.py to bundle into karni_cli/_settings.")
87
+ build_data["artifacts"].append("karni_cli/_settings/")
88
+
89
+ styles = pkg_root.parent / "karni-ui" / "src" / "styles.css"
90
+ bundled_styles = pkg_root / "karni_cli" / "_ui" / "styles.css"
91
+ if styles.is_file():
92
+ bundled_styles.parent.mkdir(parents=True, exist_ok=True)
93
+ shutil.copy2(styles, bundled_styles)
94
+ elif not bundled_styles.is_file():
95
+ raise RuntimeError("No @karni/ui styles.css to bundle into karni_cli/_ui.")
96
+ build_data["artifacts"].append("karni_cli/_ui/")
97
+
61
98
  @staticmethod
62
99
  def _bundle_karni(
63
100
  pkg_root: Path, package: str, bundle: str, what: str, build_data: dict[str, Any]
@@ -0,0 +1,8 @@
1
+ """karni-cli — the ``karni`` command."""
2
+
3
+ from importlib import metadata as _metadata
4
+
5
+ try:
6
+ __version__ = _metadata.version("karni-cli") # [project] version in pyproject.toml
7
+ except _metadata.PackageNotFoundError: # a source tree on sys.path, never installed
8
+ __version__ = "0+unknown"
@@ -16,7 +16,7 @@ from typing import Any
16
16
  from .check import check_file, check_source, supported
17
17
  from .history import active_conditions
18
18
  from .overrides import OVERRIDE_FILE, OverrideError, read_overrides, resolve_rules
19
- from .rules import CATEGORIES, PROCEDURES, RULES, Procedure, Rule
19
+ from .rules import CATEGORIES, PROCEDURES, RULES, TOPICS, Procedure, Rule, Topic
20
20
 
21
21
  #: Bumped when the shape of :func:`dump` changes incompatibly.
22
22
  SCHEMA_VERSION = 1
@@ -27,9 +27,11 @@ __all__ = [
27
27
  "PROCEDURES",
28
28
  "RULES",
29
29
  "SCHEMA_VERSION",
30
+ "TOPICS",
30
31
  "OverrideError",
31
32
  "Procedure",
32
33
  "Rule",
34
+ "Topic",
33
35
  "check_file",
34
36
  "check_paths",
35
37
  "check_source",
@@ -64,6 +66,7 @@ def dump(root: str | Path | None = None) -> dict[str, Any]:
64
66
  "categories": [c for c in categories if any(r.category == c for r in rules)],
65
67
  "rules": [rule.to_dict() for rule in rules],
66
68
  "procedures": [procedure.to_dict() for procedure in PROCEDURES],
69
+ "topics": [topic.to_dict() for topic in TOPICS],
67
70
  "adapters": overrides.adapters,
68
71
  "overrides_file": str(overrides.path) if overrides.path else None,
69
72
  "conditions": sorted(conditions),