karni-cli 0.3.1__tar.gz → 0.4.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.
- {karni_cli-0.3.1 → karni_cli-0.4.0}/.gitignore +1 -0
- {karni_cli-0.3.1 → karni_cli-0.4.0}/PKG-INFO +61 -53
- {karni_cli-0.3.1 → karni_cli-0.4.0}/README.md +59 -51
- {karni_cli-0.3.1 → karni_cli-0.4.0}/hatch_build.py +13 -1
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/__init__.py +1 -1
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/_agent/check.py +6 -6
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/_agent/history.py +1 -1
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/_agent/history_chronicle.py +2 -1
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/_agent/overrides.py +1 -1
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/_agent/rules.py +299 -93
- karni_cli-0.4.0/karni_cli/_changelog/0.4.0.toml +101 -0
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/_errorcodes/__init__.py +579 -115
- karni_cli-0.4.0/karni_cli/_errorcodes/failures.py +1282 -0
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/_errorcodes/links.py +1 -1
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/_templates/project/cookiecutter.json +1 -1
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/_templates/project/{{cookiecutter.project_slug}}/.dockerignore +3 -0
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/_templates/project/{{cookiecutter.project_slug}}/.env.example +6 -4
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/_templates/project/{{cookiecutter.project_slug}}/.gitignore +4 -0
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/_templates/project/{{cookiecutter.project_slug}}/Caddyfile +1 -1
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/_templates/project/{{cookiecutter.project_slug}}/Dockerfile +3 -3
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/_templates/project/{{cookiecutter.project_slug}}/README.md +31 -24
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/_templates/project/{{cookiecutter.project_slug}}/config/settings.py +2 -2
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/_templates/project/{{cookiecutter.project_slug}}/config/urls.py +2 -2
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/_templates/project/{{cookiecutter.project_slug}}/docker-compose.yml +6 -2
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/_templates/project/{{cookiecutter.project_slug}}/frontend/Dockerfile.dev +1 -1
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/_templates/project/{{cookiecutter.project_slug}}/frontend/eslint.config.js +1 -1
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/_templates/project/{{cookiecutter.project_slug}}/frontend/package.json +4 -8
- karni_cli-0.4.0/karni_cli/_templates/project/{{cookiecutter.project_slug}}/frontend/src/App.tsx +21 -0
- karni_cli-0.4.0/karni_cli/_templates/project/{{cookiecutter.project_slug}}/frontend/src/index.css +15 -0
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/_templates/project/{{cookiecutter.project_slug}}/frontend/src/layout.tsx +4 -3
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/_templates/project/{{cookiecutter.project_slug}}/frontend/src/routes.tsx +1 -1
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/_templates/project/{{cookiecutter.project_slug}}/frontend/tailwind.config.ts +1 -1
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/_templates/project/{{cookiecutter.project_slug}}/frontend/vite.config.ts +4 -1
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/_templates/project/{{cookiecutter.project_slug}}/pyproject.toml +10 -1
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/_templates/project/{{cookiecutter.project_slug}}/tests/test_api_schema.py +1 -1
- karni_cli-0.4.0/karni_cli/_ui/styles.css +248 -0
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/adapters.py +11 -10
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/agent_adapters.toml +2 -2
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/agent_data.py +1 -1
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/clidoc.py +20 -7
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/commands/add.py +5 -5
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/commands/beat.py +2 -1
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/commands/check.py +14 -7
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/commands/config.py +4 -4
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/commands/context.py +5 -4
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/commands/createsuperuser.py +2 -1
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/commands/doctor.py +5 -5
- karni_cli-0.4.0/karni_cli/commands/explain.py +119 -0
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/commands/make.py +1 -1
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/commands/manage_passthrough.py +10 -2
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/commands/migrate.py +7 -2
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/commands/new.py +14 -6
- karni_cli-0.4.0/karni_cli/commands/queries.py +99 -0
- karni_cli-0.4.0/karni_cli/commands/replay.py +53 -0
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/commands/routes.py +4 -1
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/commands/rules.py +6 -6
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/commands/run_tests.py +2 -1
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/commands/schedule.py +9 -3
- karni_cli-0.4.0/karni_cli/commands/schema.py +61 -0
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/commands/seed.py +11 -6
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/commands/serve.py +7 -4
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/commands/shell.py +1 -1
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/commands/sync_roles.py +9 -2
- karni_cli-0.4.0/karni_cli/commands/trace.py +31 -0
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/commands/types.py +3 -3
- karni_cli-0.4.0/karni_cli/commands/ui.py +384 -0
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/commands/upgrade.py +3 -3
- karni_cli-0.4.0/karni_cli/commands/why.py +203 -0
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/commands/worker.py +2 -1
- karni_cli-0.4.0/karni_cli/database.py +176 -0
- karni_cli-0.4.0/karni_cli/db_probe.py +89 -0
- karni_cli-0.4.0/karni_cli/debugging.py +113 -0
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/errorcodes.py +244 -18
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/errordoc.py +7 -5
- karni_cli-0.4.0/karni_cli/explain_text.py +62 -0
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/generators/apitest.py +16 -14
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/generators/app.py +4 -4
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/generators/command.py +1 -1
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/generators/component.py +2 -2
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/generators/core.py +11 -13
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/generators/event.py +1 -1
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/generators/factory.py +1 -1
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/generators/fields.py +248 -20
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/generators/introspect.py +2 -2
- karni_cli-0.4.0/karni_cli/generators/lifecycle_fields.py +207 -0
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/generators/listener.py +9 -8
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/generators/middleware.py +2 -2
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/generators/migration.py +5 -5
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/generators/model.py +10 -8
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/generators/module.py +4 -4
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/generators/page.py +12 -9
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/generators/pysource.py +1 -1
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/generators/schedule.py +9 -9
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/generators/seeder.py +3 -3
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/generators/serializer.py +4 -4
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/generators/service.py +3 -3
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/generators/task.py +2 -2
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/generators/viewset.py +7 -7
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/local_state.py +1 -1
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/main.py +27 -2
- karni_cli-0.4.0/karni_cli/mcp_server.py +272 -0
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/project.py +61 -16
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/rules_render.py +1 -1
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/scaffold.py +17 -5
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/settings_edit.py +2 -2
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/tips.py +5 -3
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/typegen.py +1 -1
- karni_cli-0.4.0/karni_cli/uitheme/__init__.py +23 -0
- karni_cli-0.4.0/karni_cli/uitheme/css.py +190 -0
- karni_cli-0.4.0/karni_cli/uitheme/defaults.py +91 -0
- karni_cli-0.4.0/karni_cli/uitheme/designsystems.py +699 -0
- karni_cli-0.4.0/karni_cli/uitheme/frontend.py +236 -0
- karni_cli-0.4.0/karni_cli/uitheme/jsobject.py +317 -0
- karni_cli-0.4.0/karni_cli/uitheme/model.py +173 -0
- karni_cli-0.4.0/karni_cli/uitheme/primitives.py +192 -0
- karni_cli-0.4.0/karni_cli/uitheme/render.py +201 -0
- karni_cli-0.4.0/karni_cli/uitheme/shadcn.py +259 -0
- karni_cli-0.4.0/karni_cli/uitheme/tailwind.py +707 -0
- karni_cli-0.4.0/karni_cli/uitheme/wiring.py +143 -0
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/upgrades/engine.py +2 -2
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/upgrades/python.py +5 -5
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/upgrades/typescript.py +1 -1
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/upgrades/v0_2/agent_guidance.py +3 -3
- {karni_cli-0.3.1 → karni_cli-0.4.0}/pyproject.toml +5 -3
- {karni_cli-0.3.1 → karni_cli-0.4.0}/tests/conftest.py +45 -0
- karni_cli-0.4.0/tests/fixtures/ui/chakra/package.json +9 -0
- karni_cli-0.4.0/tests/fixtures/ui/chakra/src/main.tsx +7 -0
- karni_cli-0.4.0/tests/fixtures/ui/chakra/src/theme.ts +35 -0
- karni_cli-0.4.0/tests/fixtures/ui/chakra3/package.json +9 -0
- karni_cli-0.4.0/tests/fixtures/ui/chakra3/src/components/ui/theme.ts +29 -0
- karni_cli-0.4.0/tests/fixtures/ui/chakra3/src/main.tsx +7 -0
- karni_cli-0.4.0/tests/fixtures/ui/mantine/package.json +9 -0
- karni_cli-0.4.0/tests/fixtures/ui/mantine/src/main.tsx +7 -0
- karni_cli-0.4.0/tests/fixtures/ui/mantine/src/theme.ts +41 -0
- karni_cli-0.4.0/tests/fixtures/ui/mui/package.json +11 -0
- karni_cli-0.4.0/tests/fixtures/ui/mui/src/main.tsx +7 -0
- karni_cli-0.4.0/tests/fixtures/ui/mui/src/theme/index.ts +29 -0
- karni_cli-0.4.0/tests/fixtures/ui/plain/package.json +5 -0
- karni_cli-0.4.0/tests/fixtures/ui/plain/src/index.css +4 -0
- karni_cli-0.4.0/tests/fixtures/ui/plain/src/main.tsx +7 -0
- karni_cli-0.4.0/tests/fixtures/ui/shadcn-tw3/components.json +18 -0
- karni_cli-0.4.0/tests/fixtures/ui/shadcn-tw3/package.json +16 -0
- {karni_cli-0.3.1/karni_cli/_templates/project/{{cookiecutter.project_slug}}/frontend → karni_cli-0.4.0/tests/fixtures/ui/shadcn-tw3}/src/App.tsx +0 -2
- karni_cli-0.4.0/tests/fixtures/ui/shadcn-tw3/src/components/ui/button.tsx +29 -0
- karni_cli-0.4.0/tests/fixtures/ui/shadcn-tw3/src/components/ui/checkbox.tsx +14 -0
- karni_cli-0.4.0/tests/fixtures/ui/shadcn-tw3/src/components/ui/input.tsx +12 -0
- karni_cli-0.4.0/tests/fixtures/ui/shadcn-tw3/src/components/ui/label.tsx +16 -0
- karni_cli-0.4.0/tests/fixtures/ui/shadcn-tw3/src/components/ui/select.tsx +69 -0
- karni_cli-0.4.0/tests/fixtures/ui/shadcn-tw3/src/index.css +49 -0
- karni_cli-0.4.0/tests/fixtures/ui/shadcn-tw3/src/main.tsx +11 -0
- karni_cli-0.4.0/tests/fixtures/ui/shadcn-tw3/tailwind.config.js +18 -0
- karni_cli-0.4.0/tests/fixtures/ui/shadcn-tw3/tsconfig.json +10 -0
- karni_cli-0.4.0/tests/fixtures/ui/shadcn-tw4/components.json +21 -0
- karni_cli-0.4.0/tests/fixtures/ui/shadcn-tw4/package.json +11 -0
- karni_cli-0.4.0/tests/fixtures/ui/shadcn-tw4/src/App.tsx +5 -0
- karni_cli-0.4.0/tests/fixtures/ui/shadcn-tw4/src/components/ui/button.tsx +23 -0
- karni_cli-0.4.0/tests/fixtures/ui/shadcn-tw4/src/components/ui/select.tsx +42 -0
- karni_cli-0.4.0/tests/fixtures/ui/shadcn-tw4/src/components/ui/switch.tsx +10 -0
- karni_cli-0.4.0/tests/fixtures/ui/shadcn-tw4/src/components/ui/textarea.tsx +9 -0
- karni_cli-0.4.0/tests/fixtures/ui/shadcn-tw4/src/index.css +60 -0
- karni_cli-0.4.0/tests/fixtures/ui/shadcn-tw4/src/main.tsx +10 -0
- karni_cli-0.4.0/tests/fixtures/ui/shadcn-tw4/tsconfig.json +9 -0
- karni_cli-0.4.0/tests/fixtures/ui/tailwind3/package.json +6 -0
- karni_cli-0.4.0/tests/fixtures/ui/tailwind3/src/index.css +3 -0
- karni_cli-0.4.0/tests/fixtures/ui/tailwind3/src/main.tsx +7 -0
- karni_cli-0.4.0/tests/fixtures/ui/tailwind3/tailwind.config.ts +32 -0
- karni_cli-0.4.0/tests/fixtures/ui/tailwind4/package.json +7 -0
- karni_cli-0.4.0/tests/fixtures/ui/tailwind4/src/index.css +8 -0
- karni_cli-0.4.0/tests/fixtures/ui/tailwind4/src/main.tsx +7 -0
- karni_cli-0.4.0/tests/fixtures/ui/tailwind4/src/theme.css +27 -0
- {karni_cli-0.3.1 → karni_cli-0.4.0}/tests/test_add.py +2 -2
- {karni_cli-0.3.1 → karni_cli-0.4.0}/tests/test_audit_fixes.py +2 -2
- {karni_cli-0.3.1 → karni_cli-0.4.0}/tests/test_check.py +12 -2
- {karni_cli-0.3.1 → karni_cli-0.4.0}/tests/test_clidoc.py +1 -1
- karni_cli-0.4.0/tests/test_command_states.py +267 -0
- karni_cli-0.4.0/tests/test_database.py +308 -0
- karni_cli-0.4.0/tests/test_debugging.py +176 -0
- {karni_cli-0.3.1 → karni_cli-0.4.0}/tests/test_doctor.py +6 -4
- {karni_cli-0.3.1 → karni_cli-0.4.0}/tests/test_errorcodes_cli.py +11 -3
- karni_cli-0.4.0/tests/test_explain_text.py +233 -0
- {karni_cli-0.3.1 → karni_cli-0.4.0}/tests/test_history.py +4 -3
- {karni_cli-0.3.1 → karni_cli-0.4.0}/tests/test_make.py +5 -5
- {karni_cli-0.3.1 → karni_cli-0.4.0}/tests/test_make_gate.py +45 -1
- karni_cli-0.4.0/tests/test_make_lifecycle.py +114 -0
- {karni_cli-0.3.1 → karni_cli-0.4.0}/tests/test_make_units.py +69 -1
- {karni_cli-0.3.1 → karni_cli-0.4.0}/tests/test_mcp.py +21 -2
- {karni_cli-0.3.1 → karni_cli-0.4.0}/tests/test_new.py +72 -4
- {karni_cli-0.3.1 → karni_cli-0.4.0}/tests/test_rules.py +4 -2
- karni_cli-0.4.0/tests/test_schema_cli.py +83 -0
- {karni_cli-0.3.1 → karni_cli-0.4.0}/tests/test_types.py +1 -1
- karni_cli-0.4.0/tests/test_ui_detect.py +703 -0
- {karni_cli-0.3.1 → karni_cli-0.4.0}/tests/test_upgrade.py +11 -6
- karni_cli-0.4.0/tests/test_why.py +191 -0
- karni_cli-0.3.1/karni_cli/_templates/project/{{cookiecutter.project_slug}}/frontend/postcss.config.js +0 -6
- karni_cli-0.3.1/karni_cli/_templates/project/{{cookiecutter.project_slug}}/frontend/src/index.css +0 -11
- karni_cli-0.3.1/karni_cli/commands/explain.py +0 -60
- karni_cli-0.3.1/karni_cli/mcp_server.py +0 -103
- {karni_cli-0.3.1 → karni_cli-0.4.0}/LICENSE +0 -0
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/_agent/__init__.py +0 -0
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/_agent/__main__.py +0 -0
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/_changelog/0.2.0.toml +0 -0
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/_changelog/0.3.0.toml +0 -0
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/_changelog/__init__.py +0 -0
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/_errorcodes/__main__.py +0 -0
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/_templates/project/{{cookiecutter.project_slug}}/Makefile +0 -0
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/_templates/project/{{cookiecutter.project_slug}}/config/__init__.py +0 -0
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/_templates/project/{{cookiecutter.project_slug}}/config/asgi.py +0 -0
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/_templates/project/{{cookiecutter.project_slug}}/config/celery.py +0 -0
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/_templates/project/{{cookiecutter.project_slug}}/config/wsgi.py +0 -0
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/_templates/project/{{cookiecutter.project_slug}}/frontend/.dockerignore +0 -0
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/_templates/project/{{cookiecutter.project_slug}}/frontend/.jscpd.json +0 -0
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/_templates/project/{{cookiecutter.project_slug}}/frontend/.npmrc +0 -0
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/_templates/project/{{cookiecutter.project_slug}}/frontend/index.html +0 -0
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/_templates/project/{{cookiecutter.project_slug}}/frontend/public/favicon.svg +0 -0
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/_templates/project/{{cookiecutter.project_slug}}/frontend/src/api/health.ts +0 -0
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/_templates/project/{{cookiecutter.project_slug}}/frontend/src/main.tsx +0 -0
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/_templates/project/{{cookiecutter.project_slug}}/frontend/src/pages/home.tsx +0 -0
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/_templates/project/{{cookiecutter.project_slug}}/frontend/src/vite-env.d.ts +0 -0
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/_templates/project/{{cookiecutter.project_slug}}/frontend/tsconfig.json +0 -0
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/_templates/project/{{cookiecutter.project_slug}}/manage.py +0 -0
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/_templates/project/{{cookiecutter.project_slug}}/tests/__init__.py +0 -0
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/_templates/project/{{cookiecutter.project_slug}}/tests/test_smoke.py +0 -0
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/brand.py +0 -0
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/commands/__init__.py +0 -0
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/commands/mcp.py +0 -0
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/config.py +0 -0
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/environment.py +0 -0
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/generators/__init__.py +0 -0
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/generators/naming.py +0 -0
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/history.py +0 -0
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/upgrades/__init__.py +0 -0
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/upgrades/changelog.py +0 -0
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/upgrades/codemod.py +0 -0
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/upgrades/legacy_agent_files.py +0 -0
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/upgrades/transforms/rename-export.cjs +0 -0
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/upgrades/v0_2/__init__.py +0 -0
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/upgrades/v1_0/__init__.py +0 -0
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/upgrades/v1_0/all_objects_to_without.py +0 -0
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/upgrades/v1_0/all_with_deleted_to_without.py +0 -0
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/upgrades/v1_0/deleted_only_to_without_dead.py +0 -0
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/upgrades/v1_0/object_permission_classes_to_access.py +0 -0
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/upgrades/v1_0/related_lookups_to_optimize.py +0 -0
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/upgrades/v1_0/scoped_related_lookups_to_optimize.py +0 -0
- {karni_cli-0.3.1 → karni_cli-0.4.0}/karni_cli/upgrades/v1_0/soft_delete_manager_mixin_to_scoped.py +0 -0
- {karni_cli-0.3.1 → karni_cli-0.4.0}/tests/__init__.py +0 -0
- {karni_cli-0.3.1 → karni_cli-0.4.0}/tests/fixtures/schema.fixture.json +0 -0
- {karni_cli-0.3.1 → karni_cli-0.4.0}/tests/fixtures/upgrade_changelog/0.9.0.toml +0 -0
- {karni_cli-0.3.1 → karni_cli-0.4.0}/tests/test_adapters.py +0 -0
- {karni_cli-0.3.1 → karni_cli-0.4.0}/tests/test_agent_upgrade.py +0 -0
- {karni_cli-0.3.1 → karni_cli-0.4.0}/tests/test_brand.py +0 -0
- {karni_cli-0.3.1 → karni_cli-0.4.0}/tests/test_context.py +0 -0
- {karni_cli-0.3.1 → karni_cli-0.4.0}/tests/test_docs_tutorial.py +0 -0
- {karni_cli-0.3.1 → karni_cli-0.4.0}/tests/test_project.py +0 -0
- {karni_cli-0.3.1 → karni_cli-0.4.0}/tests/test_runners.py +0 -0
- {karni_cli-0.3.1 → karni_cli-0.4.0}/tests/test_upgrade_codemods.py +0 -0
- {karni_cli-0.3.1 → karni_cli-0.4.0}/tests/test_upgrade_typescript.py +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: karni-cli
|
|
3
|
-
Version: 0.
|
|
4
|
-
Summary: The karni command
|
|
3
|
+
Version: 0.4.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 Claude Code, Cursor and Copilot. 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
|
|
@@ -38,66 +38,73 @@ Description-Content-Type: text/markdown
|
|
|
38
38
|
|
|
39
39
|
# karni-cli
|
|
40
40
|
|
|
41
|
-
The `karni` command.
|
|
42
|
-
subprocess
|
|
41
|
+
The `karni` command. It runs a Karni project's own `manage.py` as a
|
|
42
|
+
subprocess, so the CLI itself never imports Django.
|
|
43
43
|
|
|
44
44
|
## Commands
|
|
45
|
-
- `karni new <name
|
|
46
|
-
template
|
|
47
|
-
`KARNI_TEMPLATES`
|
|
48
|
-
- `karni add <module
|
|
45
|
+
- `karni new <name>`: scaffold a project from the bundled cookiecutter
|
|
46
|
+
template. Monorepo checkouts use the live `templates/project`, and
|
|
47
|
+
`KARNI_TEMPLATES` overrides it.
|
|
48
|
+
- `karni add <module>`: add `karni-<module>` to `[project].dependencies` and
|
|
49
49
|
wire `karni_<module>` into the `# karni:apps` block in config/settings.py.
|
|
50
|
-
Only that marker block is managed
|
|
50
|
+
Only that marker block is managed. Any other layout gets a clear error, and
|
|
51
51
|
you edit settings manually.
|
|
52
52
|
Once the module is installed it also records the module's
|
|
53
53
|
`AGENTS.fragment.md` as `.karni/modules/<module>.md` and refreshes the agent
|
|
54
54
|
adapters.
|
|
55
|
-
- `karni types
|
|
55
|
+
- `karni types`: dump the OpenAPI schema (`manage.py spectacular`), generate
|
|
56
56
|
`types.ts` (openapi-typescript, project-pinned binary preferred, else
|
|
57
57
|
`npx openapi-typescript@^7`) and typed hooks (`hooks.ts`) over @karni/ui.
|
|
58
|
-
- `karni
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
58
|
+
- `karni ui detect`: map the frontend's design system (shadcn/ui, a Tailwind
|
|
59
|
+
theme, Material UI, Chakra UI or Mantine) onto @karni/ui's `--karni-*`
|
|
60
|
+
tokens in `karni-theme.css`, plus `karni-primitives.tsx` for shadcn/ui.
|
|
61
|
+
`--dry-run` previews, `--json` reports for agents, and edited files are kept
|
|
62
|
+
unless `--force`.
|
|
63
|
+
- `karni context`: a compact machine-readable inventory (< 200 tokens for a
|
|
64
|
+
typical project). APPS (from the `# karni:apps` block) and PAGES (from
|
|
65
|
+
`frontend/src/pages/`) are read statically, MODELS/VIEWSETS come from `manage.py karni_context`,
|
|
66
|
+
and COMPONENTS/HOOKS from @karni/ui's build-generated `dist/manifest.json`.
|
|
67
|
+
Those two are omitted when the manifest is absent. Run `npm i @karni/ui` in
|
|
68
|
+
`frontend/` on the host to enable them, or override with `--manifest PATH`.
|
|
69
|
+
Nothing is hand-maintained.
|
|
70
|
+
- `karni context --with-history [PATH]`: the same inventory plus a
|
|
65
71
|
`HISTORY:` brief of what was already asked and decided about PATH (without
|
|
66
72
|
PATH: the project's recorded decisions) from any history provider that
|
|
67
73
|
detects a store, e.g. Gigai Chronicle's `.chronicle/`. Capped at ~300
|
|
68
74
|
tokens (characters ÷ 4), cut at line boundaries with a last line naming the
|
|
69
75
|
full-brief command. With no store the output is exactly `karni context`'s.
|
|
70
76
|
See `docs/concepts/history-providers.md`.
|
|
71
|
-
- `karni check [-q]
|
|
77
|
+
- `karni check [-q]`: Django system checks plus `karni.checks` entry-point hooks
|
|
72
78
|
(the architecture-test extension surface). A clean run outside CI may end
|
|
73
|
-
with one tip on stderr, at most once per project
|
|
74
|
-
- `karni doctor [-q]
|
|
75
|
-
interpreter (`.venv` / compose service), Node/npm, the @karni/ui
|
|
76
|
-
adapter freshness
|
|
77
|
-
-
|
|
78
|
-
|
|
79
|
-
|
|
79
|
+
with one tip on stderr, at most once per project. `-q` suppresses it.
|
|
80
|
+
- `karni doctor [-q]`: a human-readable environment report covering the
|
|
81
|
+
project, interpreter (`.venv` / compose service), Node/npm, the @karni/ui
|
|
82
|
+
manifest, adapter freshness and history providers. It may end with the same
|
|
83
|
+
one-time tip.
|
|
84
|
+
- `karni config get|set|list [--global] KEY [VALUE]`: settings
|
|
85
|
+
(`suggest_tools`), kept in `.karni/config.toml` in the project (committed) or
|
|
86
|
+
in `$XDG_CONFIG_HOME/karni/config.toml` with `--global`. The project wins.
|
|
80
87
|
Machine-local state (e.g. "tip shown") lives in the self-ignoring
|
|
81
88
|
`.karni/local/`.
|
|
82
|
-
- `karni rules [--explain CODE | --procedure NAME | --check FILE... | --json]
|
|
83
|
-
|
|
89
|
+
- `karni rules [--explain CODE | --procedure NAME | --check FILE... | --json]`:
|
|
90
|
+
Karni's conventions from `karni.agent.rules` (no Django needed), and
|
|
84
91
|
static single-file checks (exit 1 on violations).
|
|
85
|
-
- `karni rules sync [--check] [--force]
|
|
92
|
+
- `karni rules sync [--check] [--force]`: regenerate the thin agent adapters
|
|
86
93
|
(AGENTS.md, CLAUDE.md, Cursor, Windsurf, Copilot, Cline, Aider, Junie) and
|
|
87
|
-
slash commands from `karni_cli/agent_adapters.toml
|
|
94
|
+
slash commands from `karni_cli/agent_adapters.toml`. `--check` is the CI
|
|
88
95
|
staleness gate.
|
|
89
|
-
- `karni mcp
|
|
96
|
+
- `karni mcp`: context, rules and check as MCP tools
|
|
90
97
|
(`pip install 'karni-cli[mcp]'`).
|
|
91
98
|
- `karni upgrade [--to VERSION] [--from VERSION] [--dry-run] [--allow-dirty] [--list]`
|
|
92
99
|
moves the project across Karni versions. It reads the karni installed in
|
|
93
100
|
the project (`--from` overrides), takes every breaking change between that
|
|
94
101
|
and `--to` from Karni's machine-readable changelog
|
|
95
102
|
(`packages/karni/karni/changelog/*.toml`, bundled into karni-cli), and runs
|
|
96
|
-
their codemods in release order. Python codemods use libcst
|
|
97
|
-
codemods use a pinned jscodeshift through `npx
|
|
98
|
-
|
|
103
|
+
their codemods in release order. Python codemods use libcst. TypeScript
|
|
104
|
+
codemods use a pinned jscodeshift through `npx`, and without Node.js they
|
|
105
|
+
are skipped with the reason. The codemods run on a scratch copy, and the result
|
|
99
106
|
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
|
|
107
|
+
a unified diff and writes nothing. Writing needs a clean git tree.
|
|
101
108
|
`--allow-dirty` overrides that, and is also required outside git. The
|
|
102
109
|
report lists what was applied (each file and its rewrite count), what could
|
|
103
110
|
not be fixed automatically (the sites found, with each migration-note link)
|
|
@@ -110,7 +117,7 @@ See `docs/agents.md` for the agent surface in full.
|
|
|
110
117
|
Artisan-style shortcuts. Each runner runs one project command through the
|
|
111
118
|
project interpreter (see *Execution environment* below), streams its output
|
|
112
119
|
and exits with its exit code. `--help` on each names the command it wraps.
|
|
113
|
-
Extra arguments pass straight through
|
|
120
|
+
Extra arguments pass straight through. Put `--` before any that clash with
|
|
114
121
|
karni's own options (`--docker`, `--service`, `--help`).
|
|
115
122
|
|
|
116
123
|
| Command | Runs |
|
|
@@ -138,25 +145,25 @@ With the compose stack up, `worker` and `beat` already run as services, so
|
|
|
138
145
|
## Generators
|
|
139
146
|
`karni make <type>` writes the project code a task needs, so neither a person
|
|
140
147
|
nor an AI agent hand-creates a file a generator makes. `karni make --list`
|
|
141
|
-
prints them all
|
|
148
|
+
prints them all. Each one is also available as a hidden Laravel-style alias,
|
|
142
149
|
`karni make:<type>`. The full reference (every option, the field DSL) is
|
|
143
150
|
[docs/cli.md](https://cbsshekhawat18-lab.github.io/karni/cli/), generated from this CLI.
|
|
144
151
|
|
|
145
152
|
| Command | Writes |
|
|
146
153
|
|---|---|
|
|
147
|
-
| `karni make app NAME` | `NAME/{__init__,apps,models,viewsets}.py`, `migrations/`, `tests
|
|
148
|
-
| `karni make model NAME [FIELD...]` | `class NAME(BaseModel)` in `<app>/models.py
|
|
154
|
+
| `karni make app NAME` | `NAME/{__init__,apps,models,viewsets}.py`, `migrations/`, `tests/`, and wires `# karni:apps` |
|
|
155
|
+
| `karni make model NAME [FIELD...]` | `class NAME(BaseModel)` in `<app>/models.py`, with `--with viewset,page` / `-a` chains and `--migrate` |
|
|
149
156
|
| `karni make viewset MODEL` | `<Model>ViewSet` with its `access` (`--access authenticated\|public-read\|owned:<field>\|staff\|role:<name>`), `--search` |
|
|
150
157
|
| `karni make serializer MODEL --reason ...` | `<app>/serializers.py` + `serializer_class` on the viewset |
|
|
151
158
|
| `karni make migration [NAME]` | runs `manage.py makemigrations [--app] [--name] [--empty]` through the project interpreter |
|
|
152
159
|
| `karni make task NAME` | `@shared_task` in `<app>/tasks.py` (`--retry N`) |
|
|
153
160
|
| `karni make schedule NAME` | `every(...)`/`cron(...)` in `<app>/schedules.py` (`--every 15m` / `--cron "0 3 * * *"`, `--task`) |
|
|
154
161
|
| `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
|
|
162
|
+
| `karni make listener NAME --on ...` | `<app>/listeners.py`: `Model.created\|updated\|deleted` or a custom event, with `--queued` |
|
|
156
163
|
| `karni make command NAME` | `<app>/management/commands/NAME.py` |
|
|
157
164
|
| `karni make service NAME` | `<app>/services/NAME.py` (where HTTP clients are allowed) |
|
|
158
165
|
| `karni make middleware NAME` | `<app>/middleware.py`, wired through `# karni:middleware` |
|
|
159
|
-
| `karni make page NAME` | `frontend/src/pages/NAME.tsx` (≤ 50 lines
|
|
166
|
+
| `karni make page NAME` | `frontend/src/pages/NAME.tsx` (≤ 50 lines, `--resource R --kind list\|detail\|form`), route in `frontend/src/routes.tsx` |
|
|
160
167
|
| `karni make component NAME` | `frontend/src/components/NAME.tsx` claiming a role (`--role`) |
|
|
161
168
|
| `karni make module NAME` | `modules/karni-NAME/` per docs/modules.md |
|
|
162
169
|
|
|
@@ -169,23 +176,24 @@ karni make listener notify_organizer --on Event.created --queued
|
|
|
169
176
|
karni make schedule nightly-report --cron "0 3 * * *"
|
|
170
177
|
```
|
|
171
178
|
|
|
172
|
-
Every generator
|
|
173
|
-
files and diff and writes nothing
|
|
174
|
-
notes (the chosen `access`, the route,
|
|
175
|
-
from `--app` or the project's only
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
pages parse and stay within
|
|
180
|
-
every type into a fresh scaffold
|
|
181
|
-
frontend's ESLint config when
|
|
182
|
-
installed `frontend/node_modules`)
|
|
183
|
-
(makemigrations, migrate, check,
|
|
179
|
+
Every generator follows the same rules. It never overwrites without
|
|
180
|
+
`--force`, and `--dry-run` prints the files and diff and writes nothing. It
|
|
181
|
+
prints each created/modified file plus notes (the chosen `access`, the route,
|
|
182
|
+
the next command). It resolves the app from `--app` or the project's only
|
|
183
|
+
local app. It edits existing files only through marker comments or
|
|
184
|
+
AST-located appends, and an unfamiliar layout is an error naming the manual
|
|
185
|
+
step. It never imports Django. Generated Python is clean under ruff (lint and
|
|
186
|
+
format) and `karni rules --check`, and generated pages parse and stay within
|
|
187
|
+
50 lines. `tests/test_make_gate.py` generates every type into a fresh scaffold
|
|
188
|
+
and asserts this (plus `tsc` and the frontend's ESLint config when
|
|
189
|
+
`KARNI_TEST_NODE_MODULES` points at an installed `frontend/node_modules`).
|
|
190
|
+
Then it runs the generated backend for real (makemigrations, migrate, check,
|
|
191
|
+
requests through the Django test client).
|
|
184
192
|
|
|
185
193
|
Quote fields that end in `?` in zsh (`'venue:fk:Venue?'`) and choice values
|
|
186
194
|
joined by `|`.
|
|
187
195
|
|
|
188
196
|
## Execution environment
|
|
189
197
|
Commands that run the project resolve, in order: `--docker/--no-docker` flag →
|
|
190
|
-
`<project>/.venv` → a running compose service (default `django
|
|
198
|
+
`<project>/.venv` → a running compose service (default `django`, changed with
|
|
191
199
|
`--service` or `KARNI_COMPOSE_SERVICE`) → an error naming both remedies.
|
|
@@ -1,65 +1,72 @@
|
|
|
1
1
|
# karni-cli
|
|
2
2
|
|
|
3
|
-
The `karni` command.
|
|
4
|
-
subprocess
|
|
3
|
+
The `karni` command. It runs a Karni project's own `manage.py` as a
|
|
4
|
+
subprocess, so the CLI itself never imports Django.
|
|
5
5
|
|
|
6
6
|
## Commands
|
|
7
|
-
- `karni new <name
|
|
8
|
-
template
|
|
9
|
-
`KARNI_TEMPLATES`
|
|
10
|
-
- `karni add <module
|
|
7
|
+
- `karni new <name>`: scaffold a project from the bundled cookiecutter
|
|
8
|
+
template. Monorepo checkouts use the live `templates/project`, and
|
|
9
|
+
`KARNI_TEMPLATES` overrides it.
|
|
10
|
+
- `karni add <module>`: add `karni-<module>` to `[project].dependencies` and
|
|
11
11
|
wire `karni_<module>` into the `# karni:apps` block in config/settings.py.
|
|
12
|
-
Only that marker block is managed
|
|
12
|
+
Only that marker block is managed. Any other layout gets a clear error, and
|
|
13
13
|
you edit settings manually.
|
|
14
14
|
Once the module is installed it also records the module's
|
|
15
15
|
`AGENTS.fragment.md` as `.karni/modules/<module>.md` and refreshes the agent
|
|
16
16
|
adapters.
|
|
17
|
-
- `karni types
|
|
17
|
+
- `karni types`: dump the OpenAPI schema (`manage.py spectacular`), generate
|
|
18
18
|
`types.ts` (openapi-typescript, project-pinned binary preferred, else
|
|
19
19
|
`npx openapi-typescript@^7`) and typed hooks (`hooks.ts`) over @karni/ui.
|
|
20
|
-
- `karni
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
20
|
+
- `karni ui detect`: map the frontend's design system (shadcn/ui, a Tailwind
|
|
21
|
+
theme, Material UI, Chakra UI or Mantine) onto @karni/ui's `--karni-*`
|
|
22
|
+
tokens in `karni-theme.css`, plus `karni-primitives.tsx` for shadcn/ui.
|
|
23
|
+
`--dry-run` previews, `--json` reports for agents, and edited files are kept
|
|
24
|
+
unless `--force`.
|
|
25
|
+
- `karni context`: a compact machine-readable inventory (< 200 tokens for a
|
|
26
|
+
typical project). APPS (from the `# karni:apps` block) and PAGES (from
|
|
27
|
+
`frontend/src/pages/`) are read statically, MODELS/VIEWSETS come from `manage.py karni_context`,
|
|
28
|
+
and COMPONENTS/HOOKS from @karni/ui's build-generated `dist/manifest.json`.
|
|
29
|
+
Those two are omitted when the manifest is absent. Run `npm i @karni/ui` in
|
|
30
|
+
`frontend/` on the host to enable them, or override with `--manifest PATH`.
|
|
31
|
+
Nothing is hand-maintained.
|
|
32
|
+
- `karni context --with-history [PATH]`: the same inventory plus a
|
|
27
33
|
`HISTORY:` brief of what was already asked and decided about PATH (without
|
|
28
34
|
PATH: the project's recorded decisions) from any history provider that
|
|
29
35
|
detects a store, e.g. Gigai Chronicle's `.chronicle/`. Capped at ~300
|
|
30
36
|
tokens (characters ÷ 4), cut at line boundaries with a last line naming the
|
|
31
37
|
full-brief command. With no store the output is exactly `karni context`'s.
|
|
32
38
|
See `docs/concepts/history-providers.md`.
|
|
33
|
-
- `karni check [-q]
|
|
39
|
+
- `karni check [-q]`: Django system checks plus `karni.checks` entry-point hooks
|
|
34
40
|
(the architecture-test extension surface). A clean run outside CI may end
|
|
35
|
-
with one tip on stderr, at most once per project
|
|
36
|
-
- `karni doctor [-q]
|
|
37
|
-
interpreter (`.venv` / compose service), Node/npm, the @karni/ui
|
|
38
|
-
adapter freshness
|
|
39
|
-
-
|
|
40
|
-
|
|
41
|
-
|
|
41
|
+
with one tip on stderr, at most once per project. `-q` suppresses it.
|
|
42
|
+
- `karni doctor [-q]`: a human-readable environment report covering the
|
|
43
|
+
project, interpreter (`.venv` / compose service), Node/npm, the @karni/ui
|
|
44
|
+
manifest, adapter freshness and history providers. It may end with the same
|
|
45
|
+
one-time tip.
|
|
46
|
+
- `karni config get|set|list [--global] KEY [VALUE]`: settings
|
|
47
|
+
(`suggest_tools`), kept in `.karni/config.toml` in the project (committed) or
|
|
48
|
+
in `$XDG_CONFIG_HOME/karni/config.toml` with `--global`. The project wins.
|
|
42
49
|
Machine-local state (e.g. "tip shown") lives in the self-ignoring
|
|
43
50
|
`.karni/local/`.
|
|
44
|
-
- `karni rules [--explain CODE | --procedure NAME | --check FILE... | --json]
|
|
45
|
-
|
|
51
|
+
- `karni rules [--explain CODE | --procedure NAME | --check FILE... | --json]`:
|
|
52
|
+
Karni's conventions from `karni.agent.rules` (no Django needed), and
|
|
46
53
|
static single-file checks (exit 1 on violations).
|
|
47
|
-
- `karni rules sync [--check] [--force]
|
|
54
|
+
- `karni rules sync [--check] [--force]`: regenerate the thin agent adapters
|
|
48
55
|
(AGENTS.md, CLAUDE.md, Cursor, Windsurf, Copilot, Cline, Aider, Junie) and
|
|
49
|
-
slash commands from `karni_cli/agent_adapters.toml
|
|
56
|
+
slash commands from `karni_cli/agent_adapters.toml`. `--check` is the CI
|
|
50
57
|
staleness gate.
|
|
51
|
-
- `karni mcp
|
|
58
|
+
- `karni mcp`: context, rules and check as MCP tools
|
|
52
59
|
(`pip install 'karni-cli[mcp]'`).
|
|
53
60
|
- `karni upgrade [--to VERSION] [--from VERSION] [--dry-run] [--allow-dirty] [--list]`
|
|
54
61
|
moves the project across Karni versions. It reads the karni installed in
|
|
55
62
|
the project (`--from` overrides), takes every breaking change between that
|
|
56
63
|
and `--to` from Karni's machine-readable changelog
|
|
57
64
|
(`packages/karni/karni/changelog/*.toml`, bundled into karni-cli), and runs
|
|
58
|
-
their codemods in release order. Python codemods use libcst
|
|
59
|
-
codemods use a pinned jscodeshift through `npx
|
|
60
|
-
|
|
65
|
+
their codemods in release order. Python codemods use libcst. TypeScript
|
|
66
|
+
codemods use a pinned jscodeshift through `npx`, and without Node.js they
|
|
67
|
+
are skipped with the reason. The codemods run on a scratch copy, and the result
|
|
61
68
|
is written back all at once, or not at all if one fails. `--dry-run` prints
|
|
62
|
-
a unified diff and writes nothing. Writing needs a clean git tree
|
|
69
|
+
a unified diff and writes nothing. Writing needs a clean git tree.
|
|
63
70
|
`--allow-dirty` overrides that, and is also required outside git. The
|
|
64
71
|
report lists what was applied (each file and its rewrite count), what could
|
|
65
72
|
not be fixed automatically (the sites found, with each migration-note link)
|
|
@@ -72,7 +79,7 @@ See `docs/agents.md` for the agent surface in full.
|
|
|
72
79
|
Artisan-style shortcuts. Each runner runs one project command through the
|
|
73
80
|
project interpreter (see *Execution environment* below), streams its output
|
|
74
81
|
and exits with its exit code. `--help` on each names the command it wraps.
|
|
75
|
-
Extra arguments pass straight through
|
|
82
|
+
Extra arguments pass straight through. Put `--` before any that clash with
|
|
76
83
|
karni's own options (`--docker`, `--service`, `--help`).
|
|
77
84
|
|
|
78
85
|
| Command | Runs |
|
|
@@ -100,25 +107,25 @@ With the compose stack up, `worker` and `beat` already run as services, so
|
|
|
100
107
|
## Generators
|
|
101
108
|
`karni make <type>` writes the project code a task needs, so neither a person
|
|
102
109
|
nor an AI agent hand-creates a file a generator makes. `karni make --list`
|
|
103
|
-
prints them all
|
|
110
|
+
prints them all. Each one is also available as a hidden Laravel-style alias,
|
|
104
111
|
`karni make:<type>`. The full reference (every option, the field DSL) is
|
|
105
112
|
[docs/cli.md](https://cbsshekhawat18-lab.github.io/karni/cli/), generated from this CLI.
|
|
106
113
|
|
|
107
114
|
| Command | Writes |
|
|
108
115
|
|---|---|
|
|
109
|
-
| `karni make app NAME` | `NAME/{__init__,apps,models,viewsets}.py`, `migrations/`, `tests
|
|
110
|
-
| `karni make model NAME [FIELD...]` | `class NAME(BaseModel)` in `<app>/models.py
|
|
116
|
+
| `karni make app NAME` | `NAME/{__init__,apps,models,viewsets}.py`, `migrations/`, `tests/`, and wires `# karni:apps` |
|
|
117
|
+
| `karni make model NAME [FIELD...]` | `class NAME(BaseModel)` in `<app>/models.py`, with `--with viewset,page` / `-a` chains and `--migrate` |
|
|
111
118
|
| `karni make viewset MODEL` | `<Model>ViewSet` with its `access` (`--access authenticated\|public-read\|owned:<field>\|staff\|role:<name>`), `--search` |
|
|
112
119
|
| `karni make serializer MODEL --reason ...` | `<app>/serializers.py` + `serializer_class` on the viewset |
|
|
113
120
|
| `karni make migration [NAME]` | runs `manage.py makemigrations [--app] [--name] [--empty]` through the project interpreter |
|
|
114
121
|
| `karni make task NAME` | `@shared_task` in `<app>/tasks.py` (`--retry N`) |
|
|
115
122
|
| `karni make schedule NAME` | `every(...)`/`cron(...)` in `<app>/schedules.py` (`--every 15m` / `--cron "0 3 * * *"`, `--task`) |
|
|
116
123
|
| `karni make event NAME` | a `Signal` in `<app>/events.py` |
|
|
117
|
-
| `karni make listener NAME --on ...` | `<app>/listeners.py`: `Model.created\|updated\|deleted` or a custom event
|
|
124
|
+
| `karni make listener NAME --on ...` | `<app>/listeners.py`: `Model.created\|updated\|deleted` or a custom event, with `--queued` |
|
|
118
125
|
| `karni make command NAME` | `<app>/management/commands/NAME.py` |
|
|
119
126
|
| `karni make service NAME` | `<app>/services/NAME.py` (where HTTP clients are allowed) |
|
|
120
127
|
| `karni make middleware NAME` | `<app>/middleware.py`, wired through `# karni:middleware` |
|
|
121
|
-
| `karni make page NAME` | `frontend/src/pages/NAME.tsx` (≤ 50 lines
|
|
128
|
+
| `karni make page NAME` | `frontend/src/pages/NAME.tsx` (≤ 50 lines, `--resource R --kind list\|detail\|form`), route in `frontend/src/routes.tsx` |
|
|
122
129
|
| `karni make component NAME` | `frontend/src/components/NAME.tsx` claiming a role (`--role`) |
|
|
123
130
|
| `karni make module NAME` | `modules/karni-NAME/` per docs/modules.md |
|
|
124
131
|
|
|
@@ -131,23 +138,24 @@ karni make listener notify_organizer --on Event.created --queued
|
|
|
131
138
|
karni make schedule nightly-report --cron "0 3 * * *"
|
|
132
139
|
```
|
|
133
140
|
|
|
134
|
-
Every generator
|
|
135
|
-
files and diff and writes nothing
|
|
136
|
-
notes (the chosen `access`, the route,
|
|
137
|
-
from `--app` or the project's only
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
pages parse and stay within
|
|
142
|
-
every type into a fresh scaffold
|
|
143
|
-
frontend's ESLint config when
|
|
144
|
-
installed `frontend/node_modules`)
|
|
145
|
-
(makemigrations, migrate, check,
|
|
141
|
+
Every generator follows the same rules. It never overwrites without
|
|
142
|
+
`--force`, and `--dry-run` prints the files and diff and writes nothing. It
|
|
143
|
+
prints each created/modified file plus notes (the chosen `access`, the route,
|
|
144
|
+
the next command). It resolves the app from `--app` or the project's only
|
|
145
|
+
local app. It edits existing files only through marker comments or
|
|
146
|
+
AST-located appends, and an unfamiliar layout is an error naming the manual
|
|
147
|
+
step. It never imports Django. Generated Python is clean under ruff (lint and
|
|
148
|
+
format) and `karni rules --check`, and generated pages parse and stay within
|
|
149
|
+
50 lines. `tests/test_make_gate.py` generates every type into a fresh scaffold
|
|
150
|
+
and asserts this (plus `tsc` and the frontend's ESLint config when
|
|
151
|
+
`KARNI_TEST_NODE_MODULES` points at an installed `frontend/node_modules`).
|
|
152
|
+
Then it runs the generated backend for real (makemigrations, migrate, check,
|
|
153
|
+
requests through the Django test client).
|
|
146
154
|
|
|
147
155
|
Quote fields that end in `?` in zsh (`'venue:fk:Venue?'`) and choice values
|
|
148
156
|
joined by `|`.
|
|
149
157
|
|
|
150
158
|
## Execution environment
|
|
151
159
|
Commands that run the project resolve, in order: `--docker/--no-docker` flag →
|
|
152
|
-
`<project>/.venv` → a running compose service (default `django
|
|
160
|
+
`<project>/.venv` → a running compose service (default `django`, changed with
|
|
153
161
|
`--service` or `KARNI_COMPOSE_SERVICE`) → an error naming both remedies.
|
|
@@ -11,7 +11,10 @@ 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, and
|
|
15
|
+
@karni/ui's token stylesheet (packages/karni-ui/src/styles.css ->
|
|
16
|
+
karni_cli/_ui/styles.css), whose defaults `karni ui detect` lists when a
|
|
17
|
+
project has neither @karni/ui installed nor a monorepo checkout.
|
|
15
18
|
"""
|
|
16
19
|
|
|
17
20
|
from __future__ import annotations
|
|
@@ -58,6 +61,15 @@ class TemplateBundleHook(BuildHookInterface):
|
|
|
58
61
|
elif not bundled_links.is_file():
|
|
59
62
|
raise RuntimeError("No karni/links.py to bundle into karni_cli/_errorcodes.")
|
|
60
63
|
|
|
64
|
+
styles = pkg_root.parent / "karni-ui" / "src" / "styles.css"
|
|
65
|
+
bundled_styles = pkg_root / "karni_cli" / "_ui" / "styles.css"
|
|
66
|
+
if styles.is_file():
|
|
67
|
+
bundled_styles.parent.mkdir(parents=True, exist_ok=True)
|
|
68
|
+
shutil.copy2(styles, bundled_styles)
|
|
69
|
+
elif not bundled_styles.is_file():
|
|
70
|
+
raise RuntimeError("No @karni/ui styles.css to bundle into karni_cli/_ui.")
|
|
71
|
+
build_data["artifacts"].append("karni_cli/_ui/")
|
|
72
|
+
|
|
61
73
|
@staticmethod
|
|
62
74
|
def _bundle_karni(
|
|
63
75
|
pkg_root: Path, package: str, bundle: str, what: str, build_data: dict[str, Any]
|
|
@@ -290,7 +290,7 @@ def _python(path: str, text: str) -> list[tuple[Finding, list[int]]]:
|
|
|
290
290
|
_finding(
|
|
291
291
|
"viewset-access",
|
|
292
292
|
node.lineno,
|
|
293
|
-
f"{node.name} declares no `access
|
|
293
|
+
f"{node.name} declares no `access`, so every request is denied",
|
|
294
294
|
),
|
|
295
295
|
_class_lines(node),
|
|
296
296
|
)
|
|
@@ -301,7 +301,7 @@ def _python(path: str, text: str) -> list[tuple[Finding, list[int]]]:
|
|
|
301
301
|
_finding(
|
|
302
302
|
"redundant-serializer",
|
|
303
303
|
node.lineno,
|
|
304
|
-
f"{node.name} is a Meta-only ModelSerializer
|
|
304
|
+
f"{node.name} is a Meta-only ModelSerializer, and "
|
|
305
305
|
"BaseViewSet(model=X) already generates it",
|
|
306
306
|
),
|
|
307
307
|
_class_lines(node),
|
|
@@ -329,7 +329,7 @@ def _python(path: str, text: str) -> list[tuple[Finding, list[int]]]:
|
|
|
329
329
|
_finding(
|
|
330
330
|
"access-override",
|
|
331
331
|
lineno,
|
|
332
|
-
"filter_queryset_for_user overridden
|
|
332
|
+
"filter_queryset_for_user overridden: express row rules in `access`",
|
|
333
333
|
),
|
|
334
334
|
candidates,
|
|
335
335
|
)
|
|
@@ -562,7 +562,7 @@ def _ts(path: str, text: str) -> list[Finding]:
|
|
|
562
562
|
report(
|
|
563
563
|
"karni/no-raw-elements",
|
|
564
564
|
number,
|
|
565
|
-
f"raw <{element}
|
|
565
|
+
f"raw <{element}>: compose {_REPLACEMENTS[element]} from @karni/ui",
|
|
566
566
|
)
|
|
567
567
|
if "pages" in parts[:-1]:
|
|
568
568
|
physical = text.split("\n")
|
|
@@ -587,7 +587,7 @@ def _ts(path: str, text: str) -> list[Finding]:
|
|
|
587
587
|
if _FETCH.search(bare):
|
|
588
588
|
report("karni/no-direct-http", number, "direct fetch() outside src/api/")
|
|
589
589
|
if _AXIOS.search(code):
|
|
590
|
-
report("karni/no-direct-http", number, "axios import
|
|
590
|
+
report("karni/no-direct-http", number, "axios import: Karni ships the HTTP layer")
|
|
591
591
|
for m in _NEW_TRANSPORT.finditer(bare):
|
|
592
592
|
report("karni/no-direct-http", number, f"new {m.group(1)}() outside src/api/")
|
|
593
593
|
return findings
|
|
@@ -620,7 +620,7 @@ def check_source(path: str | Path, text: str) -> list[Finding]:
|
|
|
620
620
|
except SyntaxError as exc:
|
|
621
621
|
raise SourceParseError(
|
|
622
622
|
f"{path}:{exc.lineno}: cannot parse: {exc.msg}. karni check reads code "
|
|
623
|
-
"statically
|
|
623
|
+
"statically. Fix the syntax error and run it again."
|
|
624
624
|
) from None
|
|
625
625
|
findings = _python_optouts(text.splitlines(), found)
|
|
626
626
|
elif suffix in TS_SUFFIXES:
|
|
@@ -288,7 +288,7 @@ def _truncation_line(
|
|
|
288
288
|
full_command = getattr(provider, "full_command", None)
|
|
289
289
|
command = _safe(lambda: full_command(root, path)) if callable(full_command) else None
|
|
290
290
|
if isinstance(command, str) and command.strip():
|
|
291
|
-
return f"… truncated at ~{max_tokens} tokens
|
|
291
|
+
return f"… truncated at ~{max_tokens} tokens. Full brief: {command.strip()}"
|
|
292
292
|
return f"… truncated at ~{max_tokens} tokens; {provider.name} holds the full brief"
|
|
293
293
|
|
|
294
294
|
|
|
@@ -221,7 +221,8 @@ def brief_from_pack(prompts: object, knowledge: object) -> str:
|
|
|
221
221
|
for i, prompt in enumerate(shaped, start=1):
|
|
222
222
|
text = prompt.get("text")
|
|
223
223
|
quoted = '"' + " ".join(text.split()) + '"' if isinstance(text, str) else "(no text)"
|
|
224
|
-
|
|
224
|
+
label = f"{_when(prompt.get('ts'))} {prompt.get('churn', '')}".strip()
|
|
225
|
+
lines.append(f"{i}. {label}: {quoted}" if label else f"{i}. {quoted}")
|
|
225
226
|
return "\n".join(_SPACES.sub(" ", line) for line in lines)
|
|
226
227
|
|
|
227
228
|
|
|
@@ -64,7 +64,7 @@ def _literal(node: ast.expr, name: str, path: Path) -> Any:
|
|
|
64
64
|
return ast.literal_eval(node)
|
|
65
65
|
except ValueError:
|
|
66
66
|
raise OverrideError(
|
|
67
|
-
f"{path}:{node.lineno}: {name} must be a literal (strings, lists, dicts)
|
|
67
|
+
f"{path}:{node.lineno}: {name} must be a literal (strings, lists, dicts). "
|
|
68
68
|
"karni.rules.py is read statically and never executed."
|
|
69
69
|
) from None
|
|
70
70
|
|