kingmadoc 0.3.0.dev7__tar.gz → 0.3.0.dev8__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.
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/CHANGELOG.md +8 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/PKG-INFO +1 -1
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/skill/explaining-code/SKILL.md +15 -4
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/skill/explaining-code/reference/arc42.md +1 -1
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/skill/explaining-code/reference/c4-model.md +10 -5
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/skill/explaining-code/reference/c4.md +1 -1
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/skill/explaining-code/reference/models.md +2 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/skill/explaining-code/reference/split.md +1 -1
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/src/kingmadoc/cli.py +6 -5
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/src/kingmadoc/render.py +61 -3
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/tests/test_render.py +43 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/tests/test_skill_explaining_code.py +21 -1
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/tests/test_skill_models.py +17 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/.featuredoc.yml +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/.github/workflows/ci.yml +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/.github/workflows/release.yml +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/.gitignore +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/CLAUDE.md +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/CONTRIBUTING.md +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/LICENSE +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/README.md +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/docs/conventions.md +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/docs/index.md +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/docs/releasing.md +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/docs/roadmap.md +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/docs/test-plan.md +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/evals/README.md +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/evals/fixtures/shop/manage.py +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/evals/fixtures/shop/requirements.txt +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/evals/fixtures/shop/shop/__init__.py +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/evals/fixtures/shop/shop/models.py +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/evals/fixtures/shop/shop/services.py +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/evals/fixtures/shop/shop/settings.py +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/evals/fixtures/shop/shop/urls.py +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/evals/fixtures/shop/shop/views.py +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/evals/fixtures/shop-discount/shop/discounts.py +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/evals/fixtures/shop-discount/shop/services.py +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/evals/results/2026-09-27T111837Z.json +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/evals/results/2026-09-27T112600Z.json +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/evals/results/2026-09-27T162715Z.json +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/evals/scenarios/explain-branch.yml +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/evals/scenarios/explain-feature.yml +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/evals/scenarios/plan-feature.yml +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/examples/verify-mode-plan.md +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/pyproject.toml +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/scripts/build_skill_variants.py +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/scripts/run_evals.py +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/skill/SKILL.md +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/skill/codex.md +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/skill/copilot.md +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/skill/cursor.md +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/skill/reference/diagram-rules.md +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/skill/reference/formats.md +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/src/kingmadoc/__init__.py +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/src/kingmadoc/about.py +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/src/kingmadoc/adr.py +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/src/kingmadoc/config.py +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/src/kingmadoc/d2_binary.py +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/src/kingmadoc/diagrams/__init__.py +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/src/kingmadoc/diagrams/base.py +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/src/kingmadoc/diagrams/d2.py +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/src/kingmadoc/diagrams/mermaid.py +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/src/kingmadoc/diagrams/plantuml.py +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/src/kingmadoc/documents.py +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/src/kingmadoc/exceptions.py +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/src/kingmadoc/explain.py +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/src/kingmadoc/facts/__init__.py +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/src/kingmadoc/facts/branch.py +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/src/kingmadoc/facts/collect.py +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/src/kingmadoc/facts/data_model.py +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/src/kingmadoc/facts/dominators.py +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/src/kingmadoc/facts/js_modules.py +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/src/kingmadoc/facts/projects.py +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/src/kingmadoc/facts/routes.py +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/src/kingmadoc/facts/services.py +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/src/kingmadoc/git.py +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/src/kingmadoc/naming.py +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/src/kingmadoc/plan/__init__.py +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/src/kingmadoc/plan/analyzer.py +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/src/kingmadoc/plan/dependencies.py +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/src/kingmadoc/plan/generator.py +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/src/kingmadoc/plan/models.py +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/src/kingmadoc/plandoc.py +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/src/kingmadoc/skills.py +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/src/kingmadoc/templates/adr.md.j2 +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/src/kingmadoc/templates/domain_design.md.j2 +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/src/kingmadoc/templates/functional_design.md.j2 +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/src/kingmadoc/templates/plan_default.md.j2 +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/src/kingmadoc/templates/security_design.md.j2 +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/src/kingmadoc/templates/technical_design.md.j2 +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/src/kingmadoc/templating.py +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/src/kingmadoc/verify/__init__.py +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/src/kingmadoc/verify/changes.py +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/src/kingmadoc/verify/commands.py +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/src/kingmadoc/verify/deviations.py +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/src/kingmadoc/verify/locate.py +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/src/kingmadoc/verify/report.py +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/src/kingmadoc/vscode.py +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/tests/fixtures/backends/d2/class.d2 +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/tests/fixtures/backends/d2/component.d2 +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/tests/fixtures/backends/d2/container.d2 +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/tests/fixtures/backends/d2/context.d2 +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/tests/fixtures/backends/d2/sequence.d2 +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/tests/fixtures/backends/mermaid/class.mmd +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/tests/fixtures/backends/mermaid/component.mmd +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/tests/fixtures/backends/mermaid/container.mmd +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/tests/fixtures/backends/mermaid/context.mmd +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/tests/fixtures/backends/mermaid/sequence.mmd +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/tests/fixtures/backends/plantuml/class.puml +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/tests/fixtures/backends/plantuml/component.puml +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/tests/fixtures/backends/plantuml/container.puml +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/tests/fixtures/backends/plantuml/context.puml +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/tests/fixtures/backends/plantuml/sequence.puml +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/tests/fixtures/mermaid/component.mmd +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/tests/fixtures/mermaid/container.mmd +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/tests/fixtures/mermaid/context.mmd +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/tests/test_adr.py +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/tests/test_adr_numbering.py +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/tests/test_analyzer.py +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/tests/test_cli.py +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/tests/test_cli_encoding.py +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/tests/test_cli_init.py +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/tests/test_cli_plan_custom_template.py +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/tests/test_cli_sigint.py +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/tests/test_cli_verify_config.py +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/tests/test_config.py +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/tests/test_config_poetry.py +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/tests/test_config_shape.py +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/tests/test_d2_download.py +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/tests/test_dependencies.py +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/tests/test_dependency_graph_model.py +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/tests/test_design_models.py +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/tests/test_diagram_backends.py +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/tests/test_diagrams_mermaid.py +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/tests/test_documents.py +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/tests/test_duplicate_names.py +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/tests/test_evals.py +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/tests/test_explain.py +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/tests/test_explain_config.py +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/tests/test_explain_status.py +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/tests/test_extra_designs_coverage.py +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/tests/test_facts.py +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/tests/test_facts_code.py +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/tests/test_facts_data_model.py +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/tests/test_facts_dominators.py +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/tests/test_functional_design.py +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/tests/test_generator.py +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/tests/test_grep_performance.py +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/tests/test_manifests.py +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/tests/test_max_lines_per_file.py +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/tests/test_output_dir.py +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/tests/test_plan_e2e.py +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/tests/test_plandoc.py +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/tests/test_properties.py +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/tests/test_security_domain_designs.py +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/tests/test_skill.py +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/tests/test_skills_install.py +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/tests/test_source_dirs.py +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/tests/test_summary_slug_diagram_defaults.py +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/tests/test_technical_design.py +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/tests/test_templating_security.py +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/tests/test_verify.py +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/tests/test_verify_locate.py +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/tests/test_version.py +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/tests/test_vscode_preview.py +0 -0
- {kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/uv.lock +0 -0
|
@@ -9,6 +9,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
9
9
|
|
|
10
10
|
### Changed
|
|
11
11
|
|
|
12
|
+
- Tidier diagrams: `kingmadoc render` lays figures out with ELK (straight,
|
|
13
|
+
right-angled arrows with fewer crossings; a diagram that sets its own
|
|
14
|
+
`layout-engine` keeps it) and warns about more than 12 arrows or two arrows between
|
|
15
|
+
the same shapes. `explaining-code` 5.7: one flow direction, one arrow per pair, at
|
|
16
|
+
most 12 arrows, labels of at most six words; C4 boundary labels sit top-left in a
|
|
17
|
+
small font so arrows do not cross them. At hand-over the agent asks whether VS Code
|
|
18
|
+
should open explainers as a preview (the pictures only show there) and sets it up on
|
|
19
|
+
yes.
|
|
12
20
|
- Beta channel: every commit on `main` that passes CI is published to PyPI as a
|
|
13
21
|
development version (`0.3.0.devN`); follow it with
|
|
14
22
|
`pipx install --pip-args=--pre kingmadoc` and `pipx upgrade kingmadoc`.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: kingmadoc
|
|
3
|
-
Version: 0.3.0.
|
|
3
|
+
Version: 0.3.0.dev8
|
|
4
4
|
Summary: Feature docs for AI coding agents: a plan with C4 diagrams before the code, a verification doc after.
|
|
5
5
|
Project-URL: Homepage, https://github.com/ATkingma/KingmaDoc
|
|
6
6
|
Project-URL: Issues, https://github.com/ATkingma/KingmaDoc/issues
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: explaining-code
|
|
3
3
|
description: "Explains existing code with rendered diagrams (C4 in Simon Brown's notation; UML sequence, state, class, activity, use case; ER; data flow) and short tables, as an arc42 or compact C4 document, one file or split into functional and technical. Fixes code blindness, e.g. after an agent wrote the code. Scope: a feature, a branch or PR, a whole project, or a folder, service or module. Use when the user asks to explain, describe, document, map, diagram, draw, visualise or give an overview of existing code or architecture; asks how something works, what it does, how the parts fit together, where something happens, or what a branch, PR, commit or task changed; wants onboarding, a walkthrough, a codebase tour, an architecture or design document, arc42, C4, UML, sequence, ER or deployment diagrams of existing code; or no longer understands the code. The request may be in any language. Not for features that are not built yet."
|
|
4
|
-
version: 5.
|
|
4
|
+
version: 5.7.0
|
|
5
5
|
allowed-tools: [Read, Write, Glob, Grep, Bash]
|
|
6
6
|
---
|
|
7
7
|
|
|
@@ -163,6 +163,12 @@ Write every diagram in **D2** (Step 5 turns them into images).
|
|
|
163
163
|
Never set a `font-color` without a fill (titles, labels: the theme picks the colour),
|
|
164
164
|
and never fill white: boundaries and nodes are `fill: transparent`. Put
|
|
165
165
|
`shape: sequence_diagram` at the top level, or give its container the label `""`.
|
|
166
|
+
5. **Tidy arrows:** set `direction: down` (people on top, data stores at the bottom;
|
|
167
|
+
`right` only for timelines and swimlanes), draw one arrow per pair of shapes with a
|
|
168
|
+
combined label, keep at most 12 arrows per figure (split it otherwise, e.g. one
|
|
169
|
+
figure per container), label each arrow in at most six words plus `[protocol]`, and
|
|
170
|
+
point arrows at the shapes inside a boundary, not at the boundary. `kingmadoc render`
|
|
171
|
+
lays figures out with straight, right-angled arrows (ELK) and warns about crowded ones.
|
|
166
172
|
|
|
167
173
|
For a **branch**, mark changes by border, so the C4 colours stay meaningful, and add
|
|
168
174
|
both to the legend:
|
|
@@ -174,6 +180,7 @@ classes: {
|
|
|
174
180
|
changed: {style: {stroke: "#ef6c00"; stroke-width: 4}}
|
|
175
181
|
}
|
|
176
182
|
title: "[Container] Webshop - branch feature/invoices" {shape: text; near: top-center; style: {font-size: 24; bold: true}}
|
|
183
|
+
direction: down
|
|
177
184
|
vars: {
|
|
178
185
|
d2-legend: {
|
|
179
186
|
n: New in this branch {class: [container; new]}
|
|
@@ -236,6 +243,10 @@ Go through the checklist of each figure's model (end of
|
|
|
236
243
|
and fix what fails; check that the document embeds every image. Then hand over in at most five lines:
|
|
237
244
|
the path, one or two sentences on what the system is, the number of figures, and the
|
|
238
245
|
"Couldn't work out" questions (at most three), which you then answer into the explainer.
|
|
239
|
-
Do not paste the explainer or its figures into the chat.
|
|
240
|
-
|
|
241
|
-
|
|
246
|
+
Do not paste the explainer or its figures into the chat.
|
|
247
|
+
|
|
248
|
+
VS Code shows the pictures only in its Markdown preview. If `.vscode/settings.json` does
|
|
249
|
+
not yet open `docs/explain/` as a preview, Ask once: "Should VS Code open explainers
|
|
250
|
+
directly as a preview, with the pictures?" and, on yes, run
|
|
251
|
+
`kingmadoc skills install --vscode` (it adds one setting). Never run it without that yes;
|
|
252
|
+
without it, mention that Ctrl+Shift+V shows the pictures.
|
|
@@ -63,7 +63,7 @@ Text in `<angle brackets>` is filled in; leave out subsections marked optional.
|
|
|
63
63
|
| **Scope** | <feature / branch `<branch>` vs `<base>` / project / part `<path>`> |
|
|
64
64
|
| **Stack** | <languages, frameworks, data stores> |
|
|
65
65
|
| **Entry points** | <`path`, …> |
|
|
66
|
-
| **Based on** | <commit hash (branch)> · <ISO date> · KingmaDoc skill explaining-code 5.
|
|
66
|
+
| **Based on** | <commit hash (branch)> · <ISO date> · KingmaDoc skill explaining-code 5.7.0 (arc42) |
|
|
67
67
|
|
|
68
68
|
## What changed (branch only)
|
|
69
69
|
|
|
@@ -106,10 +106,11 @@ classes: {
|
|
|
106
106
|
container: {shape: rectangle; style: {fill: "#438dd5"; stroke: "#3c7fc0"; font-color: "#ffffff"}}
|
|
107
107
|
database: {shape: cylinder; style: {fill: "#438dd5"; stroke: "#3c7fc0"; font-color: "#ffffff"}}
|
|
108
108
|
component: {shape: rectangle; style: {fill: "#85bbf0"; stroke: "#5d82a8"; font-color: "#000000"}}
|
|
109
|
-
boundary: {style: {fill: transparent; stroke: "#888888"; stroke-dash: 4}}
|
|
110
|
-
node: {style: {fill: transparent; stroke: "#888888"}}
|
|
109
|
+
boundary: {label.near: top-left; style: {fill: transparent; stroke: "#888888"; stroke-dash: 4; font-size: 15}}
|
|
110
|
+
node: {label.near: top-left; style: {fill: transparent; stroke: "#888888"; font-size: 15}}
|
|
111
111
|
}
|
|
112
112
|
title: "[System Context] Webshop" {
|
|
113
|
+
direction: down
|
|
113
114
|
shape: text
|
|
114
115
|
near: top-center
|
|
115
116
|
style: {font-size: 24; bold: true}
|
|
@@ -155,9 +156,10 @@ classes: {
|
|
|
155
156
|
external: {shape: rectangle; style: {fill: "#999999"; stroke: "#6b6b6b"; font-color: "#ffffff"}}
|
|
156
157
|
container: {shape: rectangle; style: {fill: "#438dd5"; stroke: "#3c7fc0"; font-color: "#ffffff"}}
|
|
157
158
|
database: {shape: cylinder; style: {fill: "#438dd5"; stroke: "#3c7fc0"; font-color: "#ffffff"}}
|
|
158
|
-
boundary: {style: {fill: transparent; stroke: "#888888"; stroke-dash: 4}}
|
|
159
|
+
boundary: {label.near: top-left; style: {fill: transparent; stroke: "#888888"; stroke-dash: 4; font-size: 15}}
|
|
159
160
|
}
|
|
160
161
|
title: "[Container] Webshop" {shape: text; near: top-center; style: {font-size: 24; bold: true}}
|
|
162
|
+
direction: down
|
|
161
163
|
vars: {
|
|
162
164
|
d2-legend: {
|
|
163
165
|
p: Person {class: person}
|
|
@@ -213,9 +215,10 @@ classes: {
|
|
|
213
215
|
container: {shape: rectangle; style: {fill: "#438dd5"; stroke: "#3c7fc0"; font-color: "#ffffff"}}
|
|
214
216
|
database: {shape: cylinder; style: {fill: "#438dd5"; stroke: "#3c7fc0"; font-color: "#ffffff"}}
|
|
215
217
|
component: {shape: rectangle; style: {fill: "#85bbf0"; stroke: "#5d82a8"; font-color: "#000000"}}
|
|
216
|
-
boundary: {style: {fill: transparent; stroke: "#888888"; stroke-dash: 4}}
|
|
218
|
+
boundary: {label.near: top-left; style: {fill: transparent; stroke: "#888888"; stroke-dash: 4; font-size: 15}}
|
|
217
219
|
}
|
|
218
220
|
title: "[Component] Webshop - API" {shape: text; near: top-center; style: {font-size: 24; bold: true}}
|
|
221
|
+
direction: down
|
|
219
222
|
vars: {
|
|
220
223
|
d2-legend: {
|
|
221
224
|
c: Container {class: container}
|
|
@@ -262,9 +265,10 @@ instances they run; infrastructure (proxy, DNS) only when the code configures it
|
|
|
262
265
|
classes: {
|
|
263
266
|
container: {shape: rectangle; style: {fill: "#438dd5"; stroke: "#3c7fc0"; font-color: "#ffffff"}}
|
|
264
267
|
database: {shape: cylinder; style: {fill: "#438dd5"; stroke: "#3c7fc0"; font-color: "#ffffff"}}
|
|
265
|
-
node: {style: {fill: transparent; stroke: "#888888"}}
|
|
268
|
+
node: {label.near: top-left; style: {fill: transparent; stroke: "#888888"; font-size: 15}}
|
|
266
269
|
}
|
|
267
270
|
title: "[Deployment] Webshop - production" {shape: text; near: top-center; style: {font-size: 24; bold: true}}
|
|
271
|
+
direction: down
|
|
268
272
|
vars: {
|
|
269
273
|
d2-legend: {
|
|
270
274
|
n: Deployment node {class: node}
|
|
@@ -298,6 +302,7 @@ classes: {
|
|
|
298
302
|
database: {shape: cylinder; style: {fill: "#438dd5"; stroke: "#3c7fc0"; font-color: "#ffffff"}}
|
|
299
303
|
}
|
|
300
304
|
title: "[Dynamic] Webshop - placing an order" {shape: text; near: top-center; style: {font-size: 24; bold: true}}
|
|
305
|
+
direction: down
|
|
301
306
|
vars: {
|
|
302
307
|
d2-legend: {
|
|
303
308
|
p: Person {class: person}
|
|
@@ -22,7 +22,7 @@ Text in `<angle brackets>` is filled in.
|
|
|
22
22
|
| **Scope** | <feature / branch `<branch>` vs `<base>` / project / part `<path>`> |
|
|
23
23
|
| **Stack** | <languages, frameworks, data stores> |
|
|
24
24
|
| **Entry points** | <`path`, …> |
|
|
25
|
-
| **Based on** | <commit hash (branch)> · <ISO date> · KingmaDoc skill explaining-code 5.
|
|
25
|
+
| **Based on** | <commit hash (branch)> · <ISO date> · KingmaDoc skill explaining-code 5.7.0 |
|
|
26
26
|
|
|
27
27
|
## In short
|
|
28
28
|
|
|
@@ -140,6 +140,7 @@ no methods, no types, multiplicities kept.
|
|
|
140
140
|
|
|
141
141
|
```d2
|
|
142
142
|
title: "[Class] Diagram backends" {shape: text; near: top-center; style: {font-size: 24; bold: true}}
|
|
143
|
+
direction: down
|
|
143
144
|
backend: "«interface» DiagramBackend" {
|
|
144
145
|
shape: class
|
|
145
146
|
"+render_context(diagram)": str
|
|
@@ -171,6 +172,7 @@ inside it.
|
|
|
171
172
|
|
|
172
173
|
```d2
|
|
173
174
|
title: "[Package] kingmadoc" {shape: text; near: top-center; style: {font-size: 24; bold: true}}
|
|
175
|
+
direction: down
|
|
174
176
|
cli: cli {shape: package}
|
|
175
177
|
plan: plan {shape: package}
|
|
176
178
|
diagrams: diagrams {shape: package}
|
|
@@ -43,7 +43,7 @@ in its first line. `kingmadoc render` takes all three files at once.
|
|
|
43
43
|
| **Scope** | <feature / branch `<branch>` vs `<base>` / project / part `<path>`> |
|
|
44
44
|
| **Stack** | <languages, frameworks, data stores> |
|
|
45
45
|
| **Entry points** | <`path`, …> |
|
|
46
|
-
| **Based on** | <commit hash (branch)> · <ISO date> · KingmaDoc skill explaining-code 5.
|
|
46
|
+
| **Based on** | <commit hash (branch)> · <ISO date> · KingmaDoc skill explaining-code 5.7.0 (split) |
|
|
47
47
|
|
|
48
48
|
<at most three plain sentences: what it is, for whom, what it does>
|
|
49
49
|
|
|
@@ -49,7 +49,7 @@ from kingmadoc.plan.generator import (
|
|
|
49
49
|
render_plan,
|
|
50
50
|
)
|
|
51
51
|
from kingmadoc.plandoc import check_plan, generated_at, parse_plan, set_status
|
|
52
|
-
from kingmadoc.render import
|
|
52
|
+
from kingmadoc.render import diagram_warnings, render_file
|
|
53
53
|
from kingmadoc.skills import AGENT_DIRS, install_skills
|
|
54
54
|
from kingmadoc.verify.changes import detect_changes
|
|
55
55
|
from kingmadoc.verify.commands import MARKER_FILES, detect_commands, run_check
|
|
@@ -474,10 +474,11 @@ def render_command(documents: tuple[Path, ...], light: bool, verbose: bool) -> N
|
|
|
474
474
|
noun = "image" if len(images) == 1 else "images"
|
|
475
475
|
click.echo(f"{document}: {len(images)} {noun} ({span})")
|
|
476
476
|
for image in images:
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
477
|
+
source = image.with_suffix(".d2")
|
|
478
|
+
for warning in diagram_warnings(source.read_text(encoding="utf-8")):
|
|
479
|
+
if light and warning.endswith("(dark mode)"):
|
|
480
|
+
continue
|
|
481
|
+
click.echo(f"{source}: {warning}", err=True)
|
|
481
482
|
except KingmaDocError as exc:
|
|
482
483
|
raise click.ClickException(str(exc)) from exc
|
|
483
484
|
|
|
@@ -35,6 +35,12 @@ D2_PAD = 20
|
|
|
35
35
|
IMAGE_MODE = 0o644
|
|
36
36
|
# D2's own dark theme; the SVG switches to it when the viewer uses dark mode.
|
|
37
37
|
D2_DARK_THEME = 200
|
|
38
|
+
# Straight, right-angled arrows (see _layout_args); bundled with D2 like dagre.
|
|
39
|
+
LAYOUT_ENGINE = "elk"
|
|
40
|
+
# Above this many arrows a figure gets hard to follow (render warns).
|
|
41
|
+
MAX_ARROWS = 12
|
|
42
|
+
_ARROW = re.compile(r"^\s*([\w.]+)\s*(<->|->|<-|--)\s*([\w.]+)", re.M)
|
|
43
|
+
_LEGEND = re.compile(r"vars:\s*\{\s*d2-legend:\s*\{.*?^\s*\}\s*^\}", re.S | re.M)
|
|
38
44
|
|
|
39
45
|
# A diagram is either a fenced d2 block, or a reference written by an earlier render.
|
|
40
46
|
# References may only point into img/ next to the document (no other paths).
|
|
@@ -82,7 +88,7 @@ def render_file(path: Path, d2: Sequence[str], dark: bool = True) -> list[Path]:
|
|
|
82
88
|
# across filesystems (EXDEV when /tmp is another disk).
|
|
83
89
|
with tempfile.TemporaryDirectory(dir=path.parent, prefix=".kingmadoc-render-") as tmp:
|
|
84
90
|
rendered = [
|
|
85
|
-
_render(source, Path(tmp), n, path, [*d2, *_theme_args(dark)])
|
|
91
|
+
_render(source, Path(tmp), n, path, [*d2, *_theme_args(dark), *_layout_args(source)])
|
|
86
92
|
for n, source in enumerate(sources, start=1)
|
|
87
93
|
]
|
|
88
94
|
image_dir.mkdir(parents=True, exist_ok=True)
|
|
@@ -101,6 +107,49 @@ def render_file(path: Path, d2: Sequence[str], dark: bool = True) -> list[Path]:
|
|
|
101
107
|
return [image_dir / f"{name}.svg" for name in names]
|
|
102
108
|
|
|
103
109
|
|
|
110
|
+
def diagram_warnings(source: str) -> list[str]:
|
|
111
|
+
"""Everything worth fixing in a D2 diagram: dark-mode styles and crowded arrows.
|
|
112
|
+
|
|
113
|
+
Args:
|
|
114
|
+
source: The D2 source.
|
|
115
|
+
|
|
116
|
+
Returns:
|
|
117
|
+
One message per problem (empty when there is none).
|
|
118
|
+
"""
|
|
119
|
+
return dark_mode_warnings(source) + crowding_warnings(source)
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def crowding_warnings(source: str) -> list[str]:
|
|
123
|
+
"""Warn about figures whose arrows get hard to follow.
|
|
124
|
+
|
|
125
|
+
More than :data:`MAX_ARROWS` arrows, or two arrows between the same two shapes (one
|
|
126
|
+
arrow with a combined label reads better).
|
|
127
|
+
|
|
128
|
+
Args:
|
|
129
|
+
source: The D2 source.
|
|
130
|
+
|
|
131
|
+
Returns:
|
|
132
|
+
One message per problem.
|
|
133
|
+
"""
|
|
134
|
+
body = _LEGEND.sub("", source)
|
|
135
|
+
if "sequence_diagram" in body:
|
|
136
|
+
return [] # a sequence diagram's arrows are its messages, in order
|
|
137
|
+
pairs = [(a, b) for a, _, b in _ARROW.findall(body)]
|
|
138
|
+
warnings = []
|
|
139
|
+
if len(pairs) > MAX_ARROWS:
|
|
140
|
+
warnings.append(f"{len(pairs)} arrows (more than {MAX_ARROWS}) are hard to follow; "
|
|
141
|
+
"split the figure or combine arrows")
|
|
142
|
+
seen: dict[frozenset[str], int] = {}
|
|
143
|
+
for a, b in pairs:
|
|
144
|
+
seen[frozenset((a, b))] = seen.get(frozenset((a, b)), 0) + 1
|
|
145
|
+
for pair, count in seen.items():
|
|
146
|
+
if count > 1 and len(pair) == 2:
|
|
147
|
+
a, b = sorted(pair)
|
|
148
|
+
warnings.append(f"{count} arrows between `{a}` and `{b}`; draw one with a "
|
|
149
|
+
"combined label")
|
|
150
|
+
return warnings
|
|
151
|
+
|
|
152
|
+
|
|
104
153
|
def dark_mode_warnings(source: str) -> list[str]:
|
|
105
154
|
"""Find styles in a D2 diagram that break when the image shows in dark mode.
|
|
106
155
|
|
|
@@ -121,10 +170,10 @@ def dark_mode_warnings(source: str) -> list[str]:
|
|
|
121
170
|
fill = re.search(r"\bfill: *\"?([^;}\n\"]+)", block)
|
|
122
171
|
if not fill or fill.group(1).strip() == "transparent":
|
|
123
172
|
warnings.append(f"{_key(source, match.start())}: font-color without a fill stays "
|
|
124
|
-
"dark on the dark background; remove the font-color")
|
|
173
|
+
"dark on the dark background; remove the font-color (dark mode)")
|
|
125
174
|
for match in re.finditer(r"\bfill: *\"?(?:#fff\b|#ffffff|white)\"?", source, re.I):
|
|
126
175
|
warnings.append(f"{_key(source, match.start())}: a white fill stays white while the "
|
|
127
|
-
"text on it turns light; use fill: transparent")
|
|
176
|
+
"text on it turns light; use fill: transparent (dark mode)")
|
|
128
177
|
for match in re.finditer(r"^( +)shape: *sequence_diagram", source, re.M):
|
|
129
178
|
opening = source[: match.start()].rstrip().rsplit("\n", 1)[-1]
|
|
130
179
|
if not re.search(r':\s*""\s*\{$', opening):
|
|
@@ -202,6 +251,15 @@ def _render(source: str, tmp: Path, n: int, doc: Path, d2: Sequence[str]) -> Pat
|
|
|
202
251
|
return out
|
|
203
252
|
|
|
204
253
|
|
|
254
|
+
def _layout_args(source: str) -> list[str]:
|
|
255
|
+
"""ELK unless the diagram picks its own engine (``vars: {d2-config: {layout-engine}}``).
|
|
256
|
+
|
|
257
|
+
ELK routes arrows orthogonally, with fewer crossings than D2's default (dagre, curved
|
|
258
|
+
splines that run over each other in bigger diagrams).
|
|
259
|
+
"""
|
|
260
|
+
return [] if "layout-engine" in source else ["--layout", LAYOUT_ENGINE]
|
|
261
|
+
|
|
262
|
+
|
|
205
263
|
def _theme_args(dark: bool) -> list[str]:
|
|
206
264
|
return ["--dark-theme", str(D2_DARK_THEME)] if dark else []
|
|
207
265
|
|
|
@@ -426,3 +426,46 @@ def test_images_are_readable_by_everyone(tmp_path: Path, d2: list[str]) -> None:
|
|
|
426
426
|
images = render_file(_doc(tmp_path), d2)
|
|
427
427
|
|
|
428
428
|
assert all(p.stat().st_mode & 0o777 == 0o644 for p in images)
|
|
429
|
+
|
|
430
|
+
|
|
431
|
+
def test_images_use_the_elk_layout(
|
|
432
|
+
tmp_path: Path, d2: list[str], monkeypatch: pytest.MonkeyPatch
|
|
433
|
+
) -> None:
|
|
434
|
+
"""ELK routes arrows straight and at right angles (dagre curves them over each other)."""
|
|
435
|
+
commands = _commands(tmp_path, d2, monkeypatch)
|
|
436
|
+
|
|
437
|
+
assert commands and all(c[c.index("--layout") + 1] == "elk" for c in commands)
|
|
438
|
+
|
|
439
|
+
|
|
440
|
+
def test_a_diagram_that_picks_its_layout_keeps_it(
|
|
441
|
+
tmp_path: Path, d2: list[str], monkeypatch: pytest.MonkeyPatch
|
|
442
|
+
) -> None:
|
|
443
|
+
"""vars.d2-config.layout-engine in the source wins over the default."""
|
|
444
|
+
import subprocess
|
|
445
|
+
|
|
446
|
+
from kingmadoc import render
|
|
447
|
+
|
|
448
|
+
seen: list[list[str]] = []
|
|
449
|
+
real_run = subprocess.run
|
|
450
|
+
|
|
451
|
+
def run(command: list[str], **kwargs: object): # type: ignore[no-untyped-def]
|
|
452
|
+
seen.append(command)
|
|
453
|
+
return real_run(command, **kwargs) # type: ignore[call-overload]
|
|
454
|
+
|
|
455
|
+
monkeypatch.setattr(render.subprocess, "run", run)
|
|
456
|
+
source = "vars: {d2-config: {layout-engine: dagre}}\na -> b\n"
|
|
457
|
+
render_file(_doc(tmp_path, f"# T\n\n```d2\n{source}```\n"), d2)
|
|
458
|
+
|
|
459
|
+
assert seen and "--layout" not in seen[0]
|
|
460
|
+
|
|
461
|
+
|
|
462
|
+
def test_crowded_diagrams_are_reported() -> None:
|
|
463
|
+
"""More than 12 arrows, or two arrows between the same pair, make a figure hard to read."""
|
|
464
|
+
from kingmadoc.render import diagram_warnings
|
|
465
|
+
|
|
466
|
+
crowded = "\n".join(f"a{i} -> b{i}: x" for i in range(13))
|
|
467
|
+
twice = "api -> db: reads\ndb -> api: rows\nweb -> api: calls\n"
|
|
468
|
+
|
|
469
|
+
assert any("13 arrows" in w for w in diagram_warnings(crowded))
|
|
470
|
+
assert any("`api` and `db`" in w for w in diagram_warnings(twice))
|
|
471
|
+
assert diagram_warnings("a -> b: x\nb -> c: y\n") == []
|
|
@@ -211,8 +211,12 @@ def test_d2_examples_compile(tmp_path: Path, index: int) -> None:
|
|
|
211
211
|
source = re.sub(r"<([A-Za-z][^<>\n]*)>", r"\1", examples[index])
|
|
212
212
|
(tmp_path / "x.d2").write_text(source, encoding="utf-8")
|
|
213
213
|
|
|
214
|
+
# The same options as `kingmadoc render`: the ELK layout and the dark theme.
|
|
215
|
+
from kingmadoc.render import D2_DARK_THEME, _layout_args
|
|
216
|
+
|
|
214
217
|
result = subprocess.run(
|
|
215
|
-
[D2 or "d2",
|
|
218
|
+
[D2 or "d2", *_layout_args(source), "--dark-theme", str(D2_DARK_THEME),
|
|
219
|
+
str(tmp_path / "x.d2"), str(tmp_path / "x.svg")],
|
|
216
220
|
capture_output=True, text=True, timeout=60, check=False,
|
|
217
221
|
)
|
|
218
222
|
|
|
@@ -262,3 +266,19 @@ def test_long_references_start_with_their_contents() -> None:
|
|
|
262
266
|
assert "Contents:" in head, path.name
|
|
263
267
|
for section in re.findall(r"^## (.+)$", _read(path).split("````", 1)[0], re.M):
|
|
264
268
|
assert section.split(".")[0] in head or section in head, f"{path.name}: {section}"
|
|
269
|
+
|
|
270
|
+
|
|
271
|
+
def test_arrows_stay_tidy() -> None:
|
|
272
|
+
"""One flow direction, one arrow per pair, at most 12 arrows, short labels."""
|
|
273
|
+
step = re.sub(r"\s+", " ", _read(SKILL).split("## Step 3.", 1)[1].split("## Step 4.", 1)[0])
|
|
274
|
+
|
|
275
|
+
assert "direction: down" in step and "one arrow per pair" in step
|
|
276
|
+
assert "at most 12 arrows" in step and "six words" in step
|
|
277
|
+
|
|
278
|
+
|
|
279
|
+
def test_hand_over_offers_the_vs_code_preview() -> None:
|
|
280
|
+
"""The pictures only show in a preview: ask once, then set it up on yes."""
|
|
281
|
+
hand_over = re.sub(r"\s+", " ", _read(SKILL).split("## Step 6.", 1)[1])
|
|
282
|
+
|
|
283
|
+
assert "kingmadoc skills install --vscode" in hand_over
|
|
284
|
+
assert "Ask" in hand_over and "on yes" in hand_over
|
|
@@ -331,3 +331,20 @@ def test_algorithm_model_explains_with_formula_trace_and_complexity() -> None:
|
|
|
331
331
|
assert "```text" in body and "Invariant" in body
|
|
332
332
|
assert re.search(r"\bO\(.+\) time", body)
|
|
333
333
|
assert re.search(r"^\| Step \|", body, re.M), "a trace table, one row per step"
|
|
334
|
+
|
|
335
|
+
|
|
336
|
+
def test_c4_boundaries_keep_their_label_out_of_the_arrows() -> None:
|
|
337
|
+
"""Boundary and node labels sit top-left in a small font, so arrows do not cross them."""
|
|
338
|
+
for line in re.findall(r"^\s*(?:boundary|node): \{.*$", _read(C4_MODEL), re.M):
|
|
339
|
+
assert "label.near: top-left" in line and "font-size: 15" in line, line
|
|
340
|
+
|
|
341
|
+
|
|
342
|
+
@pytest.mark.parametrize("path", ALL_FILES, ids=lambda p: p.name)
|
|
343
|
+
def test_diagrams_flow_down(path: Path) -> None:
|
|
344
|
+
"""Every example with arrows (except sequence diagrams) sets one flow direction:
|
|
345
|
+
down, or right for timelines and swimlanes."""
|
|
346
|
+
for source in _examples(_read(path)):
|
|
347
|
+
if _edges(source) and "sequence_diagram" not in source and "grid-" not in source:
|
|
348
|
+
assert re.search(r"^direction: (down|right)$", source, re.M), (
|
|
349
|
+
f"{path.name}:\n{source[:120]}"
|
|
350
|
+
)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/evals/fixtures/shop-discount/shop/discounts.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/src/kingmadoc/templates/functional_design.md.j2
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/src/kingmadoc/templates/technical_design.md.j2
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/tests/fixtures/backends/plantuml/component.puml
RENAMED
|
File without changes
|
{kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/tests/fixtures/backends/plantuml/container.puml
RENAMED
|
File without changes
|
|
File without changes
|
{kingmadoc-0.3.0.dev7 → kingmadoc-0.3.0.dev8}/tests/fixtures/backends/plantuml/sequence.puml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|