drawspec 0.1.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.
- drawspec-0.1.0/.claude/settings.json +40 -0
- drawspec-0.1.0/.claude/skills/continue/.arsenal-vendored +0 -0
- drawspec-0.1.0/.claude/skills/continue/SKILL.md +129 -0
- drawspec-0.1.0/.claude/skills/continue/evals/loading_verification.json +11 -0
- drawspec-0.1.0/.claude/skills/coverage-gaps/.arsenal-vendored +0 -0
- drawspec-0.1.0/.claude/skills/coverage-gaps/SKILL.md +74 -0
- drawspec-0.1.0/.claude/skills/coverage-gaps/evals/loading_verification.json +18 -0
- drawspec-0.1.0/.claude/skills/coverage-gaps/scripts/analyze_coverage.py +103 -0
- drawspec-0.1.0/.claude/skills/dep-upgrade/.arsenal-vendored +0 -0
- drawspec-0.1.0/.claude/skills/dep-upgrade/SKILL.md +89 -0
- drawspec-0.1.0/.claude/skills/dep-upgrade/evals/loading_verification.json +18 -0
- drawspec-0.1.0/.claude/skills/dep-upgrade/scripts/compare_lockfile.py +132 -0
- drawspec-0.1.0/.claude/skills/design/.arsenal-vendored +0 -0
- drawspec-0.1.0/.claude/skills/design/SKILL.md +113 -0
- drawspec-0.1.0/.claude/skills/design/evals/loading_verification.json +20 -0
- drawspec-0.1.0/.claude/skills/design/references/template-plan.md +80 -0
- drawspec-0.1.0/.claude/skills/design/references/template-specification-tail.md +42 -0
- drawspec-0.1.0/.claude/skills/design/scripts/validate_plan.py +116 -0
- drawspec-0.1.0/.claude/skills/execution/.arsenal-vendored +0 -0
- drawspec-0.1.0/.claude/skills/execution/SKILL.md +127 -0
- drawspec-0.1.0/.claude/skills/execution/evals/loading_verification.json +20 -0
- drawspec-0.1.0/.claude/skills/execution/references/template.md +46 -0
- drawspec-0.1.0/.claude/skills/gate-check/.arsenal-vendored +0 -0
- drawspec-0.1.0/.claude/skills/gate-check/SKILL.md +109 -0
- drawspec-0.1.0/.claude/skills/gate-check/evals/loading_verification.json +19 -0
- drawspec-0.1.0/.claude/skills/gate-check/references/gate-grammar.md +116 -0
- drawspec-0.1.0/.claude/skills/gate-check/scripts/run_gate.py +345 -0
- drawspec-0.1.0/.claude/skills/github/.arsenal-vendored +0 -0
- drawspec-0.1.0/.claude/skills/github/SKILL.md +109 -0
- drawspec-0.1.0/.claude/skills/github/evals/loading_verification.json +18 -0
- drawspec-0.1.0/.claude/skills/github/references/pr-review-loop.md +95 -0
- drawspec-0.1.0/.claude/skills/github/references/projects-detection.md +65 -0
- drawspec-0.1.0/.claude/skills/github/scripts/query_pr_state.py +455 -0
- drawspec-0.1.0/.claude/skills/github/scripts/query_project_type.py +116 -0
- drawspec-0.1.0/.claude/skills/init/.arsenal-vendored +0 -0
- drawspec-0.1.0/.claude/skills/init/SKILL.md +75 -0
- drawspec-0.1.0/.claude/skills/init/assets/.bundle-version +1 -0
- drawspec-0.1.0/.claude/skills/init/assets/AGENTS.md +203 -0
- drawspec-0.1.0/.claude/skills/init/assets/agents/worker.md +174 -0
- drawspec-0.1.0/.claude/skills/init/assets/bin/budget_check.sh +107 -0
- drawspec-0.1.0/.claude/skills/init/assets/bin/check_skill_workshop_loaded.sh +65 -0
- drawspec-0.1.0/.claude/skills/init/assets/bin/check_update.sh +305 -0
- drawspec-0.1.0/.claude/skills/init/assets/bin/claim_task.sh +103 -0
- drawspec-0.1.0/.claude/skills/init/assets/bin/detect_surface.sh +49 -0
- drawspec-0.1.0/.claude/skills/init/assets/bin/gate_run.sh +369 -0
- drawspec-0.1.0/.claude/skills/init/assets/bin/gate_target.py +168 -0
- drawspec-0.1.0/.claude/skills/init/assets/bin/github_channel.sh +158 -0
- drawspec-0.1.0/.claude/skills/init/assets/bin/mark_skill_workshop_loaded.sh +35 -0
- drawspec-0.1.0/.claude/skills/init/assets/bin/mark_skill_workshop_loaded_from_prompt.sh +37 -0
- drawspec-0.1.0/.claude/skills/init/assets/bin/open_task_pr.sh +601 -0
- drawspec-0.1.0/.claude/skills/init/assets/bin/outline.sh +120 -0
- drawspec-0.1.0/.claude/skills/init/assets/bin/rebase_stack.sh +227 -0
- drawspec-0.1.0/.claude/skills/init/assets/bin/rescue_snapshot.sh +83 -0
- drawspec-0.1.0/.claude/skills/init/assets/bin/statusline_capture.sh +81 -0
- drawspec-0.1.0/.claude/skills/init/assets/bin/worker_postcheck.sh +185 -0
- drawspec-0.1.0/.claude/skills/init/assets/bin/workspace_list.sh +13 -0
- drawspec-0.1.0/.claude/skills/init/assets/bin/worktree_probe.sh +65 -0
- drawspec-0.1.0/.claude/skills/init/assets/references/claiming-internals.md +41 -0
- drawspec-0.1.0/.claude/skills/init/assets/references/evidence-gates.md +134 -0
- drawspec-0.1.0/.claude/skills/init/assets/references/github-automation.md +121 -0
- drawspec-0.1.0/.claude/skills/init/assets/references/queue-seeding.md +146 -0
- drawspec-0.1.0/.claude/skills/init/assets/references/quota-governance.md +29 -0
- drawspec-0.1.0/.claude/skills/init/assets/references/state-layout.md +82 -0
- drawspec-0.1.0/.claude/skills/init/assets/references/worker-loop.md +301 -0
- drawspec-0.1.0/.claude/skills/init/assets/scripts/arsenal_config.py +249 -0
- drawspec-0.1.0/.claude/skills/init/assets/scripts/arsenal_migrate.py +310 -0
- drawspec-0.1.0/.claude/skills/init/assets/scripts/create_reader.py +916 -0
- drawspec-0.1.0/.claude/skills/init/assets/scripts/gate_evidence.py +208 -0
- drawspec-0.1.0/.claude/skills/init/assets/scripts/handle_sync.py +201 -0
- drawspec-0.1.0/.claude/skills/init/assets/scripts/issue_for_task.py +118 -0
- drawspec-0.1.0/.claude/skills/init/assets/scripts/issue_import.py +204 -0
- drawspec-0.1.0/.claude/skills/init/assets/scripts/query_status.py +206 -0
- drawspec-0.1.0/.claude/skills/init/assets/scripts/queue_hooks.py +573 -0
- drawspec-0.1.0/.claude/skills/init/assets/scripts/task_select.py +576 -0
- drawspec-0.1.0/.claude/skills/init/assets/session/handover.md +32 -0
- drawspec-0.1.0/.claude/skills/init/assets/workflows/arsenal-queue.yml +136 -0
- drawspec-0.1.0/.claude/skills/init/evals/loading_verification.json +11 -0
- drawspec-0.1.0/.claude/skills/init/scripts/init.py +993 -0
- drawspec-0.1.0/.claude/skills/mutmut-report/.arsenal-vendored +0 -0
- drawspec-0.1.0/.claude/skills/mutmut-report/SKILL.md +32 -0
- drawspec-0.1.0/.claude/skills/mutmut-report/evals/loading_verification.json +18 -0
- drawspec-0.1.0/.claude/skills/mutmut-report/scripts/analyze_mutmut.py +268 -0
- drawspec-0.1.0/.claude/skills/pypi-release/.arsenal-vendored +0 -0
- drawspec-0.1.0/.claude/skills/pypi-release/SKILL.md +103 -0
- drawspec-0.1.0/.claude/skills/pypi-release/evals/loading_verification.json +18 -0
- drawspec-0.1.0/.claude/skills/pypi-release/scripts/validate_release.py +142 -0
- drawspec-0.1.0/.claude/skills/python-bootstrap/.arsenal-vendored +0 -0
- drawspec-0.1.0/.claude/skills/python-bootstrap/SKILL.md +84 -0
- drawspec-0.1.0/.claude/skills/python-bootstrap/evals/loading_verification.json +18 -0
- drawspec-0.1.0/.claude/skills/python-bootstrap/references/canonical-config.md +102 -0
- drawspec-0.1.0/.claude/skills/python-bootstrap/scripts/analyze_project.py +157 -0
- drawspec-0.1.0/.claude/skills/queue-add/.arsenal-vendored +0 -0
- drawspec-0.1.0/.claude/skills/queue-add/SKILL.md +86 -0
- drawspec-0.1.0/.claude/skills/queue-add/evals/loading_verification.json +11 -0
- drawspec-0.1.0/.claude/skills/queue-add/references/payload-template.md +42 -0
- drawspec-0.1.0/.claude/skills/queue-add/scripts/new_task.py +224 -0
- drawspec-0.1.0/.claude/skills/queue-status/.arsenal-vendored +0 -0
- drawspec-0.1.0/.claude/skills/queue-status/SKILL.md +86 -0
- drawspec-0.1.0/.claude/skills/queue-status/evals/loading_verification.json +11 -0
- drawspec-0.1.0/.claude/skills/review/.arsenal-vendored +0 -0
- drawspec-0.1.0/.claude/skills/review/SKILL.md +67 -0
- drawspec-0.1.0/.claude/skills/review/evals/loading_verification.json +20 -0
- drawspec-0.1.0/.claude/skills/review/references/template.md +74 -0
- drawspec-0.1.0/.claude/skills/session-end/.arsenal-vendored +0 -0
- drawspec-0.1.0/.claude/skills/session-end/SKILL.md +133 -0
- drawspec-0.1.0/.claude/skills/session-end/evals/loading_verification.json +18 -0
- drawspec-0.1.0/.claude/skills/session-end/references/auto-fire-setup.md +129 -0
- drawspec-0.1.0/.claude/skills/session-end/references/handoff-mode.md +76 -0
- drawspec-0.1.0/.claude/skills/session-end/references/retrospective-rubric.md +120 -0
- drawspec-0.1.0/.claude/skills/session-end/scripts/create_handoff.py +82 -0
- drawspec-0.1.0/.claude/skills/session-end/scripts/query_session_history.py +278 -0
- drawspec-0.1.0/.claude/skills/ship/.arsenal-vendored +0 -0
- drawspec-0.1.0/.claude/skills/ship/SKILL.md +114 -0
- drawspec-0.1.0/.claude/skills/ship/evals/loading_verification.json +20 -0
- drawspec-0.1.0/.claude/skills/ship/references/template.md +149 -0
- drawspec-0.1.0/.claude/skills/specify/.arsenal-vendored +0 -0
- drawspec-0.1.0/.claude/skills/specify/SKILL.md +134 -0
- drawspec-0.1.0/.claude/skills/specify/evals/loading_verification.json +20 -0
- drawspec-0.1.0/.claude/skills/specify/references/template.md +83 -0
- drawspec-0.1.0/.claude/skills/specify/scripts/validate_spec.py +138 -0
- drawspec-0.1.0/.github/ISSUE_TEMPLATE/bug_report.yml +47 -0
- drawspec-0.1.0/.github/ISSUE_TEMPLATE/config.yml +8 -0
- drawspec-0.1.0/.github/ISSUE_TEMPLATE/kind_or_field_request.yml +40 -0
- drawspec-0.1.0/.github/dependabot.yml +20 -0
- drawspec-0.1.0/.github/pull_request_template.md +16 -0
- drawspec-0.1.0/.github/workflows/arsenal-queue.yml +136 -0
- drawspec-0.1.0/.github/workflows/ci.yml +85 -0
- drawspec-0.1.0/.github/workflows/release.yml +198 -0
- drawspec-0.1.0/.gitignore +249 -0
- drawspec-0.1.0/AGENTS.md +200 -0
- drawspec-0.1.0/CHANGELOG.md +437 -0
- drawspec-0.1.0/CLAUDE.md +23 -0
- drawspec-0.1.0/CONTRIBUTING.md +150 -0
- drawspec-0.1.0/LICENSE +21 -0
- drawspec-0.1.0/Makefile +51 -0
- drawspec-0.1.0/PKG-INFO +368 -0
- drawspec-0.1.0/README.md +328 -0
- drawspec-0.1.0/_config.yml +32 -0
- drawspec-0.1.0/arsenal/config.toml +44 -0
- drawspec-0.1.0/arsenal/session/handover.md +191 -0
- drawspec-0.1.0/arsenal/tasks/_history/lo-0727.md +59 -0
- drawspec-0.1.0/arsenal/tasks/_history/lo-0e20.md +37 -0
- drawspec-0.1.0/arsenal/tasks/_history/lo-0e91.md +71 -0
- drawspec-0.1.0/arsenal/tasks/_history/lo-1270.md +41 -0
- drawspec-0.1.0/arsenal/tasks/_history/lo-1291.md +32 -0
- drawspec-0.1.0/arsenal/tasks/_history/lo-1b55.md +41 -0
- drawspec-0.1.0/arsenal/tasks/_history/lo-1c11.md +70 -0
- drawspec-0.1.0/arsenal/tasks/_history/lo-1c47.md +36 -0
- drawspec-0.1.0/arsenal/tasks/_history/lo-1d28.md +60 -0
- drawspec-0.1.0/arsenal/tasks/_history/lo-21c8.md +90 -0
- drawspec-0.1.0/arsenal/tasks/_history/lo-2382.md +63 -0
- drawspec-0.1.0/arsenal/tasks/_history/lo-2f7f.md +36 -0
- drawspec-0.1.0/arsenal/tasks/_history/lo-2f92.md +79 -0
- drawspec-0.1.0/arsenal/tasks/_history/lo-30b0.md +35 -0
- drawspec-0.1.0/arsenal/tasks/_history/lo-38d8.md +38 -0
- drawspec-0.1.0/arsenal/tasks/_history/lo-3b60.md +128 -0
- drawspec-0.1.0/arsenal/tasks/_history/lo-3ecf.md +27 -0
- drawspec-0.1.0/arsenal/tasks/_history/lo-4c51.md +32 -0
- drawspec-0.1.0/arsenal/tasks/_history/lo-4e89.md +58 -0
- drawspec-0.1.0/arsenal/tasks/_history/lo-4f9b.md +37 -0
- drawspec-0.1.0/arsenal/tasks/_history/lo-533d.md +36 -0
- drawspec-0.1.0/arsenal/tasks/_history/lo-6e34.md +47 -0
- drawspec-0.1.0/arsenal/tasks/_history/lo-7bfe.md +37 -0
- drawspec-0.1.0/arsenal/tasks/_history/lo-825e.md +89 -0
- drawspec-0.1.0/arsenal/tasks/_history/lo-88b7.md +58 -0
- drawspec-0.1.0/arsenal/tasks/_history/lo-9dd6.md +36 -0
- drawspec-0.1.0/arsenal/tasks/_history/lo-a204.md +69 -0
- drawspec-0.1.0/arsenal/tasks/_history/lo-a63e.md +70 -0
- drawspec-0.1.0/arsenal/tasks/_history/lo-b569.md +36 -0
- drawspec-0.1.0/arsenal/tasks/_history/lo-b67b.md +41 -0
- drawspec-0.1.0/arsenal/tasks/_history/lo-b7a8.md +39 -0
- drawspec-0.1.0/arsenal/tasks/_history/lo-b94c.md +36 -0
- drawspec-0.1.0/arsenal/tasks/_history/lo-c107.md +35 -0
- drawspec-0.1.0/arsenal/tasks/_history/lo-dcd5.md +38 -0
- drawspec-0.1.0/arsenal/tasks/_history/lo-e854.md +22 -0
- drawspec-0.1.0/arsenal/tasks/_history/lo-e93c.md +37 -0
- drawspec-0.1.0/arsenal/tasks/_history/lo-ee92.md +41 -0
- drawspec-0.1.0/arsenal/tasks/_history/lo-f75a.md +37 -0
- drawspec-0.1.0/arsenal/tasks/_history/lo-fbbb.md +122 -0
- drawspec-0.1.0/arsenal/tasks/_migrated-history.md +42 -0
- drawspec-0.1.0/arsenal/tasks/lo-2158.md +88 -0
- drawspec-0.1.0/arsenal/tasks/lo-52fa.md +63 -0
- drawspec-0.1.0/arsenal/tasks/lo-666f.md +113 -0
- drawspec-0.1.0/arsenal/tasks/lo-70ef.md +87 -0
- drawspec-0.1.0/arsenal/tasks/lo-f0f8.md +107 -0
- drawspec-0.1.0/arsenal/tasks/t-5e82a719.md +17 -0
- drawspec-0.1.0/arsenal/tasks/t-ae407597.md +37 -0
- drawspec-0.1.0/arsenal/tasks/t-e783b178.md +27 -0
- drawspec-0.1.0/claude-arsenal/.bundle-version +1 -0
- drawspec-0.1.0/claude-arsenal/AGENTS.md +203 -0
- drawspec-0.1.0/claude-arsenal/agents/worker.md +174 -0
- drawspec-0.1.0/claude-arsenal/bin/budget_check.sh +107 -0
- drawspec-0.1.0/claude-arsenal/bin/check_skill_workshop_loaded.sh +65 -0
- drawspec-0.1.0/claude-arsenal/bin/check_update.sh +305 -0
- drawspec-0.1.0/claude-arsenal/bin/claim_task.sh +103 -0
- drawspec-0.1.0/claude-arsenal/bin/detect_surface.sh +49 -0
- drawspec-0.1.0/claude-arsenal/bin/gate_run.sh +369 -0
- drawspec-0.1.0/claude-arsenal/bin/gate_target.py +168 -0
- drawspec-0.1.0/claude-arsenal/bin/github_channel.sh +158 -0
- drawspec-0.1.0/claude-arsenal/bin/mark_skill_workshop_loaded.sh +35 -0
- drawspec-0.1.0/claude-arsenal/bin/mark_skill_workshop_loaded_from_prompt.sh +37 -0
- drawspec-0.1.0/claude-arsenal/bin/open_task_pr.sh +601 -0
- drawspec-0.1.0/claude-arsenal/bin/outline.sh +120 -0
- drawspec-0.1.0/claude-arsenal/bin/rebase_stack.sh +227 -0
- drawspec-0.1.0/claude-arsenal/bin/rescue_snapshot.sh +83 -0
- drawspec-0.1.0/claude-arsenal/bin/statusline_capture.sh +81 -0
- drawspec-0.1.0/claude-arsenal/bin/worker_postcheck.sh +185 -0
- drawspec-0.1.0/claude-arsenal/bin/workspace_list.sh +13 -0
- drawspec-0.1.0/claude-arsenal/bin/worktree_probe.sh +65 -0
- drawspec-0.1.0/claude-arsenal/references/claiming-internals.md +41 -0
- drawspec-0.1.0/claude-arsenal/references/evidence-gates.md +134 -0
- drawspec-0.1.0/claude-arsenal/references/github-automation.md +121 -0
- drawspec-0.1.0/claude-arsenal/references/queue-seeding.md +146 -0
- drawspec-0.1.0/claude-arsenal/references/quota-governance.md +29 -0
- drawspec-0.1.0/claude-arsenal/references/state-layout.md +82 -0
- drawspec-0.1.0/claude-arsenal/references/worker-loop.md +301 -0
- drawspec-0.1.0/claude-arsenal/scripts/arsenal_config.py +249 -0
- drawspec-0.1.0/claude-arsenal/scripts/arsenal_migrate.py +310 -0
- drawspec-0.1.0/claude-arsenal/scripts/create_reader.py +916 -0
- drawspec-0.1.0/claude-arsenal/scripts/gate_evidence.py +208 -0
- drawspec-0.1.0/claude-arsenal/scripts/handle_sync.py +201 -0
- drawspec-0.1.0/claude-arsenal/scripts/issue_for_task.py +118 -0
- drawspec-0.1.0/claude-arsenal/scripts/issue_import.py +204 -0
- drawspec-0.1.0/claude-arsenal/scripts/query_status.py +206 -0
- drawspec-0.1.0/claude-arsenal/scripts/queue_hooks.py +573 -0
- drawspec-0.1.0/claude-arsenal/scripts/task_select.py +576 -0
- drawspec-0.1.0/claude-arsenal/session/handover.md +32 -0
- drawspec-0.1.0/claude-arsenal/workflows/arsenal-queue.yml +136 -0
- drawspec-0.1.0/corpus/README.md +57 -0
- drawspec-0.1.0/corpus/fixtures/fixture-001.svg +23 -0
- drawspec-0.1.0/corpus/fixtures/fixture-002.svg +35 -0
- drawspec-0.1.0/corpus/fixtures/fixture-003.svg +29 -0
- drawspec-0.1.0/corpus/fixtures/fixture-004.svg +19 -0
- drawspec-0.1.0/corpus/fixtures/fixture-005.svg +39 -0
- drawspec-0.1.0/corpus/fixtures/fixture-006.svg +17 -0
- drawspec-0.1.0/corpus/fixtures/fixture-007.svg +17 -0
- drawspec-0.1.0/corpus/fixtures/fixture-008.svg +34 -0
- drawspec-0.1.0/corpus/fixtures/fixture-009.svg +34 -0
- drawspec-0.1.0/corpus/fixtures/fixture-010.svg +29 -0
- drawspec-0.1.0/corpus/fixtures/fixture-011.svg +28 -0
- drawspec-0.1.0/corpus/fixtures/fixture-012.svg +27 -0
- drawspec-0.1.0/corpus/fixtures/fixture-013.svg +32 -0
- drawspec-0.1.0/corpus/fixtures/fixture-014.svg +34 -0
- drawspec-0.1.0/corpus/fixtures/fixture-015.svg +17 -0
- drawspec-0.1.0/corpus/fixtures/fixture-016.svg +31 -0
- drawspec-0.1.0/corpus/fixtures/fixture-017.svg +41 -0
- drawspec-0.1.0/corpus/fixtures/fixture-018.svg +16 -0
- drawspec-0.1.0/corpus/fixtures/fixture-019.svg +22 -0
- drawspec-0.1.0/corpus/fixtures/fixture-020.svg +38 -0
- drawspec-0.1.0/corpus/fixtures/fixture-021.svg +43 -0
- drawspec-0.1.0/corpus/fixtures/fixture-022.svg +26 -0
- drawspec-0.1.0/corpus/fixtures/fixture-023.svg +25 -0
- drawspec-0.1.0/corpus/fixtures/fixture-024.svg +16 -0
- drawspec-0.1.0/corpus/fixtures/fixture-025.svg +37 -0
- drawspec-0.1.0/corpus/fixtures/fixture-026.svg +34 -0
- drawspec-0.1.0/corpus/fixtures/fixture-027.svg +39 -0
- drawspec-0.1.0/corpus/fixtures/fixture-028.svg +36 -0
- drawspec-0.1.0/corpus/fixtures/fixture-029.svg +28 -0
- drawspec-0.1.0/corpus/fixtures/fixture-030.svg +36 -0
- drawspec-0.1.0/corpus/fixtures/fixture-031.svg +20 -0
- drawspec-0.1.0/corpus/fixtures/fixture-032.svg +22 -0
- drawspec-0.1.0/corpus/fixtures/fixture-033.svg +34 -0
- drawspec-0.1.0/corpus/fixtures/fixture-034.svg +36 -0
- drawspec-0.1.0/corpus/fixtures/fixture-035.svg +39 -0
- drawspec-0.1.0/corpus/fixtures/fixture-036.svg +41 -0
- drawspec-0.1.0/corpus/fixtures/fixture-037.svg +19 -0
- drawspec-0.1.0/corpus/fixtures/fixture-038.svg +19 -0
- drawspec-0.1.0/corpus/fixtures/fixture-039.svg +40 -0
- drawspec-0.1.0/corpus/fixtures/fixture-040.svg +35 -0
- drawspec-0.1.0/corpus/fixtures/fixture-041.svg +28 -0
- drawspec-0.1.0/corpus/fixtures/fixture-042.svg +17 -0
- drawspec-0.1.0/corpus/fixtures/fixture-043.svg +31 -0
- drawspec-0.1.0/corpus/fixtures/fixture-044.svg +30 -0
- drawspec-0.1.0/corpus/fixtures/fixture-045.svg +19 -0
- drawspec-0.1.0/corpus/fixtures/fixture-046.svg +27 -0
- drawspec-0.1.0/corpus/fixtures/fixture-047.svg +30 -0
- drawspec-0.1.0/corpus/fixtures/fixture-048.svg +27 -0
- drawspec-0.1.0/corpus/fixtures/fixture-049.svg +50 -0
- drawspec-0.1.0/corpus/fixtures/fixture-050.svg +26 -0
- drawspec-0.1.0/corpus/fixtures/fixture-051.svg +14 -0
- drawspec-0.1.0/corpus/fixtures/fixture-052.svg +22 -0
- drawspec-0.1.0/corpus/fixtures/fixture-053.svg +16 -0
- drawspec-0.1.0/corpus/fixtures/fixture-054.svg +19 -0
- drawspec-0.1.0/corpus/fixtures/fixture-055.svg +28 -0
- drawspec-0.1.0/corpus/fixtures/fixture-056.svg +37 -0
- drawspec-0.1.0/corpus/fixtures/fixture-057.svg +25 -0
- drawspec-0.1.0/corpus/fixtures/fixture-058.svg +32 -0
- drawspec-0.1.0/corpus/fixtures/fixture-059.svg +24 -0
- drawspec-0.1.0/corpus/fixtures/fixture-060.svg +34 -0
- drawspec-0.1.0/corpus/fixtures/fixture-061.svg +22 -0
- drawspec-0.1.0/corpus/fixtures/fixture-062.svg +29 -0
- drawspec-0.1.0/corpus/fixtures/fixture-063.svg +30 -0
- drawspec-0.1.0/corpus/fixtures/fixture-064.svg +28 -0
- drawspec-0.1.0/corpus/fixtures/fixture-065.svg +30 -0
- drawspec-0.1.0/corpus/fixtures/fixture-066.svg +32 -0
- drawspec-0.1.0/corpus/fixtures/fixture-067.svg +34 -0
- drawspec-0.1.0/corpus/fixtures/fixture-068.svg +30 -0
- drawspec-0.1.0/corpus/fixtures/fixture-069.svg +27 -0
- drawspec-0.1.0/corpus/fixtures/fixture-070.svg +53 -0
- drawspec-0.1.0/corpus/fixtures/fixture-071.svg +35 -0
- drawspec-0.1.0/corpus/fixtures/fixture-072.svg +10 -0
- drawspec-0.1.0/corpus/fixtures/fixture-073.svg +24 -0
- drawspec-0.1.0/corpus/fixtures/fixture-074.svg +41 -0
- drawspec-0.1.0/corpus/fixtures/fixture-075.svg +23 -0
- drawspec-0.1.0/corpus/fixtures/fixture-076.svg +37 -0
- drawspec-0.1.0/corpus/fixtures/fixture-077.svg +33 -0
- drawspec-0.1.0/corpus/fixtures/fixture-078.svg +30 -0
- drawspec-0.1.0/corpus/fixtures/fixture-079.svg +23 -0
- drawspec-0.1.0/corpus/fixtures/fixture-080.svg +51 -0
- drawspec-0.1.0/corpus/fixtures/fixture-081.svg +38 -0
- drawspec-0.1.0/corpus/fixtures/fixture-082.svg +12 -0
- drawspec-0.1.0/corpus/fixtures/fixture-083.svg +27 -0
- drawspec-0.1.0/corpus/fixtures/fixture-084.svg +27 -0
- drawspec-0.1.0/corpus/fixtures/fixture-085.svg +33 -0
- drawspec-0.1.0/corpus/fixtures/fixture-086.svg +22 -0
- drawspec-0.1.0/corpus/fixtures/fixture-087.svg +28 -0
- drawspec-0.1.0/corpus/metrics.json +2716 -0
- drawspec-0.1.0/docs/brief.md +178 -0
- drawspec-0.1.0/docs/cli.md +162 -0
- drawspec-0.1.0/docs/format.md +789 -0
- drawspec-0.1.0/docs/gallery/board-migration.svg +1 -0
- drawspec-0.1.0/docs/gallery/board-onboarding.svg +1 -0
- drawspec-0.1.0/docs/gallery/board-retrospective.svg +1 -0
- drawspec-0.1.0/docs/gallery/board-story-map.svg +1 -0
- drawspec-0.1.0/docs/gallery/chart-accent.svg +1 -0
- drawspec-0.1.0/docs/gallery/chart-area.svg +1 -0
- drawspec-0.1.0/docs/gallery/chart-bars.svg +1 -0
- drawspec-0.1.0/docs/gallery/chart-brand-readings.svg +1 -0
- drawspec-0.1.0/docs/gallery/chart-complaints.svg +1 -0
- drawspec-0.1.0/docs/gallery/chart-responsibility.svg +1 -0
- drawspec-0.1.0/docs/gallery/chart-stacked.svg +1 -0
- drawspec-0.1.0/docs/gallery/columns-before-after.svg +1 -0
- drawspec-0.1.0/docs/gallery/columns-rise.svg +1 -0
- drawspec-0.1.0/docs/gallery/curve-burndown.svg +1 -0
- drawspec-0.1.0/docs/gallery/curve-hype.svg +1 -0
- drawspec-0.1.0/docs/gallery/curve-variance.svg +1 -0
- drawspec-0.1.0/docs/gallery/cycle-hub-flywheel.svg +1 -0
- drawspec-0.1.0/docs/gallery/cycle-hub-oncall.svg +1 -0
- drawspec-0.1.0/docs/gallery/cycle-hub-quality.svg +1 -0
- drawspec-0.1.0/docs/gallery/cycle-review.svg +1 -0
- drawspec-0.1.0/docs/gallery/cycle-wheel.svg +1 -0
- drawspec-0.1.0/docs/gallery/entities-enrolment.svg +1 -0
- drawspec-0.1.0/docs/gallery/entities-library.svg +1 -0
- drawspec-0.1.0/docs/gallery/entities-orders.svg +1 -0
- drawspec-0.1.0/docs/gallery/entities-shapes.svg +1 -0
- drawspec-0.1.0/docs/gallery/files-project.svg +1 -0
- drawspec-0.1.0/docs/gallery/files-text.svg +1 -0
- drawspec-0.1.0/docs/gallery/fishbone-backup.svg +1 -0
- drawspec-0.1.0/docs/gallery/fishbone-flaky-ci.svg +1 -0
- drawspec-0.1.0/docs/gallery/fishbone-late-orders.svg +1 -0
- drawspec-0.1.0/docs/gallery/fishbone-signups.svg +1 -0
- drawspec-0.1.0/docs/gallery/flow-accent.svg +1 -0
- drawspec-0.1.0/docs/gallery/flow-actor-handover.svg +1 -0
- drawspec-0.1.0/docs/gallery/flow-actors.svg +1 -0
- drawspec-0.1.0/docs/gallery/flow-bands.svg +1 -0
- drawspec-0.1.0/docs/gallery/flow-brand-release.svg +1 -0
- drawspec-0.1.0/docs/gallery/flow-critical-path.svg +1 -0
- drawspec-0.1.0/docs/gallery/flow-edge-roles.svg +1 -0
- drawspec-0.1.0/docs/gallery/flow-groups.svg +1 -0
- drawspec-0.1.0/docs/gallery/flow-hub.svg +1 -0
- drawspec-0.1.0/docs/gallery/flow-inventory.svg +1 -0
- drawspec-0.1.0/docs/gallery/flow-mesh.svg +1 -0
- drawspec-0.1.0/docs/gallery/flow-node-roles.svg +1 -0
- drawspec-0.1.0/docs/gallery/flow-retry.svg +1 -0
- drawspec-0.1.0/docs/gallery/flow-status-failover.svg +1 -0
- drawspec-0.1.0/docs/gallery/flow-status-search.svg +1 -0
- drawspec-0.1.0/docs/gallery/flow-triage.svg +1 -0
- drawspec-0.1.0/docs/gallery/flow-validation.svg +1 -0
- drawspec-0.1.0/docs/gallery/funnel-innovation.svg +1 -0
- drawspec-0.1.0/docs/gallery/gantt-critical-path.svg +1 -0
- drawspec-0.1.0/docs/gallery/gantt-migration.svg +1 -0
- drawspec-0.1.0/docs/gallery/gantt-semester.svg +1 -0
- drawspec-0.1.0/docs/gallery/gantt-upgrade.svg +1 -0
- drawspec-0.1.0/docs/gallery/index.html +315 -0
- drawspec-0.1.0/docs/gallery/journey-bug-report.svg +1 -0
- drawspec-0.1.0/docs/gallery/journey-first-week.svg +1 -0
- drawspec-0.1.0/docs/gallery/journey-outpatient.svg +1 -0
- drawspec-0.1.0/docs/gallery/journey-parking-permit.svg +1 -0
- drawspec-0.1.0/docs/gallery/lanes-disclosure.svg +1 -0
- drawspec-0.1.0/docs/gallery/lanes-expense.svg +1 -0
- drawspec-0.1.0/docs/gallery/lanes-onboarding.svg +1 -0
- drawspec-0.1.0/docs/gallery/lanes-tender.svg +1 -0
- drawspec-0.1.0/docs/gallery/matrix-process.svg +1 -0
- drawspec-0.1.0/docs/gallery/matrix-raid.svg +1 -0
- drawspec-0.1.0/docs/gallery/matrix-scale-ci.svg +1 -0
- drawspec-0.1.0/docs/gallery/matrix-scale-risk.svg +1 -0
- drawspec-0.1.0/docs/gallery/matrix-scale-skills.svg +1 -0
- drawspec-0.1.0/docs/gallery/pyramid-evidence.svg +1 -0
- drawspec-0.1.0/docs/gallery/pyramid-top-heavy.svg +1 -0
- drawspec-0.1.0/docs/gallery/quadrant-conflict.svg +1 -0
- drawspec-0.1.0/docs/gallery/rings-scope.svg +1 -0
- drawspec-0.1.0/docs/gallery/sankey-budget.svg +1 -0
- drawspec-0.1.0/docs/gallery/sankey-cores.svg +1 -0
- drawspec-0.1.0/docs/gallery/sankey-energy.svg +1 -0
- drawspec-0.1.0/docs/gallery/sankey-tickets.svg +1 -0
- drawspec-0.1.0/docs/gallery/scatter-pareto.svg +1 -0
- drawspec-0.1.0/docs/gallery/sequence-checkout.svg +1 -0
- drawspec-0.1.0/docs/gallery/sequence-dns.svg +1 -0
- drawspec-0.1.0/docs/gallery/sequence-drain.svg +1 -0
- drawspec-0.1.0/docs/gallery/sequence-upload.svg +1 -0
- drawspec-0.1.0/docs/gallery/stack-decisions.svg +1 -0
- drawspec-0.1.0/docs/gallery/states-brand-station.svg +1 -0
- drawspec-0.1.0/docs/gallery/states-breaker.svg +1 -0
- drawspec-0.1.0/docs/gallery/states-invoice.svg +1 -0
- drawspec-0.1.0/docs/gallery/states-process.svg +1 -0
- drawspec-0.1.0/docs/gallery/states-ticket.svg +1 -0
- drawspec-0.1.0/docs/gallery/timeline-disaster.svg +1 -0
- drawspec-0.1.0/docs/gallery/timeline-rise.svg +1 -0
- drawspec-0.1.0/docs/gallery/timeline-work.svg +1 -0
- drawspec-0.1.0/docs/gallery/tree-compartments.svg +1 -0
- drawspec-0.1.0/docs/gallery/tree-decisions.svg +1 -0
- drawspec-0.1.0/docs/gallery/tree-status-reorg.svg +1 -0
- drawspec-0.1.0/docs/gallery/treemap-bundle.svg +1 -0
- drawspec-0.1.0/docs/gallery/treemap-disk.svg +1 -0
- drawspec-0.1.0/docs/gallery/treemap-latency.svg +1 -0
- drawspec-0.1.0/docs/gallery/treemap-oncall.svg +1 -0
- drawspec-0.1.0/docs/gallery/venn-data-roles.svg +1 -0
- drawspec-0.1.0/docs/gallery/venn-frameworks.svg +1 -0
- drawspec-0.1.0/docs/gallery/venn-parity.svg +1 -0
- drawspec-0.1.0/docs/gallery/venn-telemetry.svg +1 -0
- drawspec-0.1.0/docs/guide.md +1404 -0
- drawspec-0.1.0/docs/hero.png +0 -0
- drawspec-0.1.0/docs/hero.svg +1 -0
- drawspec-0.1.0/docs/kinds-wanted.md +450 -0
- drawspec-0.1.0/docs/plan-round-five.md +349 -0
- drawspec-0.1.0/docs/plan-round-three.md +418 -0
- drawspec-0.1.0/docs/plan-round-two.md +214 -0
- drawspec-0.1.0/docs/proposals/README.md +96 -0
- drawspec-0.1.0/docs/proposals/board.md +191 -0
- drawspec-0.1.0/docs/proposals/coverage-vs-diagram-design.md +102 -0
- drawspec-0.1.0/docs/proposals/cycle-hub.md +151 -0
- drawspec-0.1.0/docs/proposals/entities.md +249 -0
- drawspec-0.1.0/docs/proposals/exports.md +77 -0
- drawspec-0.1.0/docs/proposals/filetree.md +32 -0
- drawspec-0.1.0/docs/proposals/fishbone.md +171 -0
- drawspec-0.1.0/docs/proposals/flow-status.md +141 -0
- drawspec-0.1.0/docs/proposals/gantt.md +215 -0
- drawspec-0.1.0/docs/proposals/journey.md +184 -0
- drawspec-0.1.0/docs/proposals/lanes.md +199 -0
- drawspec-0.1.0/docs/proposals/matrix-scale.md +168 -0
- drawspec-0.1.0/docs/proposals/sankey.md +218 -0
- drawspec-0.1.0/docs/proposals/sequence.md +245 -0
- drawspec-0.1.0/docs/proposals/states.md +236 -0
- drawspec-0.1.0/docs/proposals/theme-from.md +114 -0
- drawspec-0.1.0/docs/proposals/treemap.md +179 -0
- drawspec-0.1.0/docs/proposals/venn.md +153 -0
- drawspec-0.1.0/docs/reference/board-migration.json +21 -0
- drawspec-0.1.0/docs/reference/board-onboarding.json +32 -0
- drawspec-0.1.0/docs/reference/board-retrospective.json +18 -0
- drawspec-0.1.0/docs/reference/board-story-map.json +27 -0
- drawspec-0.1.0/docs/reference/brand/tidemark.css +40 -0
- drawspec-0.1.0/docs/reference/brand/tidemark.tokens.json +31 -0
- drawspec-0.1.0/docs/reference/brand/tidemark.toml +79 -0
- drawspec-0.1.0/docs/reference/chart-accent.json +16 -0
- drawspec-0.1.0/docs/reference/chart-area.json +24 -0
- drawspec-0.1.0/docs/reference/chart-bars.json +15 -0
- drawspec-0.1.0/docs/reference/chart-brand-readings.json +16 -0
- drawspec-0.1.0/docs/reference/chart-complaints.json +15 -0
- drawspec-0.1.0/docs/reference/chart-responsibility.json +63 -0
- drawspec-0.1.0/docs/reference/chart-stacked.json +15 -0
- drawspec-0.1.0/docs/reference/columns-before-after.json +11 -0
- drawspec-0.1.0/docs/reference/columns-rise.json +16 -0
- drawspec-0.1.0/docs/reference/curve-burndown.json +61 -0
- drawspec-0.1.0/docs/reference/curve-hype.json +57 -0
- drawspec-0.1.0/docs/reference/curve-variance.json +43 -0
- drawspec-0.1.0/docs/reference/cycle-hub-flywheel.json +22 -0
- drawspec-0.1.0/docs/reference/cycle-hub-oncall.json +22 -0
- drawspec-0.1.0/docs/reference/cycle-hub-quality.json +20 -0
- drawspec-0.1.0/docs/reference/cycle-review.json +22 -0
- drawspec-0.1.0/docs/reference/cycle-wheel.json +19 -0
- drawspec-0.1.0/docs/reference/entities-enrolment.json +22 -0
- drawspec-0.1.0/docs/reference/entities-library.json +18 -0
- drawspec-0.1.0/docs/reference/entities-orders.json +29 -0
- drawspec-0.1.0/docs/reference/entities-shapes.json +19 -0
- drawspec-0.1.0/docs/reference/files-project.json +20 -0
- drawspec-0.1.0/docs/reference/files-text.json +18 -0
- drawspec-0.1.0/docs/reference/fishbone-backup.json +23 -0
- drawspec-0.1.0/docs/reference/fishbone-flaky-ci.json +11 -0
- drawspec-0.1.0/docs/reference/fishbone-late-orders.json +15 -0
- drawspec-0.1.0/docs/reference/fishbone-signups.json +29 -0
- drawspec-0.1.0/docs/reference/flow-accent.json +23 -0
- drawspec-0.1.0/docs/reference/flow-actor-handover.json +19 -0
- drawspec-0.1.0/docs/reference/flow-actors.json +21 -0
- drawspec-0.1.0/docs/reference/flow-bands.json +31 -0
- drawspec-0.1.0/docs/reference/flow-brand-release.json +25 -0
- drawspec-0.1.0/docs/reference/flow-critical-path.json +20 -0
- drawspec-0.1.0/docs/reference/flow-edge-roles.json +102 -0
- drawspec-0.1.0/docs/reference/flow-groups.json +32 -0
- drawspec-0.1.0/docs/reference/flow-hub.json +19 -0
- drawspec-0.1.0/docs/reference/flow-inventory.json +31 -0
- drawspec-0.1.0/docs/reference/flow-mesh.json +30 -0
- drawspec-0.1.0/docs/reference/flow-node-roles.json +16 -0
- drawspec-0.1.0/docs/reference/flow-retry.json +22 -0
- drawspec-0.1.0/docs/reference/flow-status-failover.json +22 -0
- drawspec-0.1.0/docs/reference/flow-status-search.json +23 -0
- drawspec-0.1.0/docs/reference/flow-triage.json +18 -0
- drawspec-0.1.0/docs/reference/flow-validation.json +26 -0
- drawspec-0.1.0/docs/reference/funnel-innovation.json +12 -0
- drawspec-0.1.0/docs/reference/gantt-critical-path.json +22 -0
- drawspec-0.1.0/docs/reference/gantt-migration.json +27 -0
- drawspec-0.1.0/docs/reference/gantt-semester.json +26 -0
- drawspec-0.1.0/docs/reference/gantt-upgrade.json +22 -0
- drawspec-0.1.0/docs/reference/journey-bug-report.json +14 -0
- drawspec-0.1.0/docs/reference/journey-first-week.json +28 -0
- drawspec-0.1.0/docs/reference/journey-outpatient.json +43 -0
- drawspec-0.1.0/docs/reference/journey-parking-permit.json +35 -0
- drawspec-0.1.0/docs/reference/lanes-disclosure.json +26 -0
- drawspec-0.1.0/docs/reference/lanes-expense.json +22 -0
- drawspec-0.1.0/docs/reference/lanes-onboarding.json +25 -0
- drawspec-0.1.0/docs/reference/lanes-tender.json +25 -0
- drawspec-0.1.0/docs/reference/matrix-process.json +28 -0
- drawspec-0.1.0/docs/reference/matrix-raid.json +130 -0
- drawspec-0.1.0/docs/reference/matrix-scale-ci.json +33 -0
- drawspec-0.1.0/docs/reference/matrix-scale-risk.json +26 -0
- drawspec-0.1.0/docs/reference/matrix-scale-skills.json +28 -0
- drawspec-0.1.0/docs/reference/pyramid-evidence.json +12 -0
- drawspec-0.1.0/docs/reference/pyramid-top-heavy.json +12 -0
- drawspec-0.1.0/docs/reference/quadrant-conflict.json +17 -0
- drawspec-0.1.0/docs/reference/rendered/cycle-review-grandalf-down.svg +1 -0
- drawspec-0.1.0/docs/reference/rendered/cycle-review-grandalf-right.svg +1 -0
- drawspec-0.1.0/docs/reference/rendered/cycle-review-layered-down.svg +1 -0
- drawspec-0.1.0/docs/reference/rendered/cycle-review-layered-right.svg +1 -0
- drawspec-0.1.0/docs/reference/rendered/flow-validation-grandalf-down.svg +1 -0
- drawspec-0.1.0/docs/reference/rendered/flow-validation-grandalf-right.svg +1 -0
- drawspec-0.1.0/docs/reference/rendered/flow-validation-layered-down.svg +1 -0
- drawspec-0.1.0/docs/reference/rendered/flow-validation-layered-right.svg +1 -0
- drawspec-0.1.0/docs/reference/rendered/tree-decisions-grandalf-down.svg +1 -0
- drawspec-0.1.0/docs/reference/rendered/tree-decisions-grandalf-right.svg +1 -0
- drawspec-0.1.0/docs/reference/rendered/tree-decisions-layered-down.svg +1 -0
- drawspec-0.1.0/docs/reference/rendered/tree-decisions-layered-right.svg +1 -0
- drawspec-0.1.0/docs/reference/rings-scope.json +19 -0
- drawspec-0.1.0/docs/reference/sankey-budget.json +26 -0
- drawspec-0.1.0/docs/reference/sankey-cores.json +20 -0
- drawspec-0.1.0/docs/reference/sankey-energy.json +30 -0
- drawspec-0.1.0/docs/reference/sankey-tickets.json +28 -0
- drawspec-0.1.0/docs/reference/scatter-pareto.json +22 -0
- drawspec-0.1.0/docs/reference/sequence-checkout.json +33 -0
- drawspec-0.1.0/docs/reference/sequence-dns.json +24 -0
- drawspec-0.1.0/docs/reference/sequence-drain.json +24 -0
- drawspec-0.1.0/docs/reference/sequence-upload.json +29 -0
- drawspec-0.1.0/docs/reference/stack-decisions.json +12 -0
- drawspec-0.1.0/docs/reference/states-brand-station.json +26 -0
- drawspec-0.1.0/docs/reference/states-breaker.json +19 -0
- drawspec-0.1.0/docs/reference/states-invoice.json +26 -0
- drawspec-0.1.0/docs/reference/states-process.json +22 -0
- drawspec-0.1.0/docs/reference/states-ticket.json +28 -0
- drawspec-0.1.0/docs/reference/timeline-disaster.json +54 -0
- drawspec-0.1.0/docs/reference/timeline-rise.json +14 -0
- drawspec-0.1.0/docs/reference/timeline-work.json +14 -0
- drawspec-0.1.0/docs/reference/tree-compartments.json +37 -0
- drawspec-0.1.0/docs/reference/tree-decisions.json +32 -0
- drawspec-0.1.0/docs/reference/tree-status-reorg.json +26 -0
- drawspec-0.1.0/docs/reference/treemap-bundle.json +15 -0
- drawspec-0.1.0/docs/reference/treemap-disk.json +18 -0
- drawspec-0.1.0/docs/reference/treemap-latency.json +23 -0
- drawspec-0.1.0/docs/reference/treemap-oncall.json +14 -0
- drawspec-0.1.0/docs/reference/venn-data-roles.json +16 -0
- drawspec-0.1.0/docs/reference/venn-frameworks.json +14 -0
- drawspec-0.1.0/docs/reference/venn-parity.json +17 -0
- drawspec-0.1.0/docs/reference/venn-telemetry.json +19 -0
- drawspec-0.1.0/docs/review-2026-10.md +56 -0
- drawspec-0.1.0/docs/theme-requirements.md +161 -0
- drawspec-0.1.0/docs/theme.md +286 -0
- drawspec-0.1.0/llms.txt +34 -0
- drawspec-0.1.0/pyproject.toml +157 -0
- drawspec-0.1.0/schema/drawspec-v1.schema.json +3489 -0
- drawspec-0.1.0/skills/drawspec/SKILL.md +32 -0
- drawspec-0.1.0/src/drawspec/__init__.py +57 -0
- drawspec-0.1.0/src/drawspec/brand.py +1184 -0
- drawspec-0.1.0/src/drawspec/charts.py +1790 -0
- drawspec-0.1.0/src/drawspec/clearance.py +330 -0
- drawspec-0.1.0/src/drawspec/cli.py +466 -0
- drawspec-0.1.0/src/drawspec/emit.py +666 -0
- drawspec-0.1.0/src/drawspec/errors.py +97 -0
- drawspec-0.1.0/src/drawspec/examples.py +339 -0
- drawspec-0.1.0/src/drawspec/export.py +177 -0
- drawspec-0.1.0/src/drawspec/filetree.py +294 -0
- drawspec-0.1.0/src/drawspec/fonts/LICENSE +57 -0
- drawspec-0.1.0/src/drawspec/fonts/mono-bold.ttf +0 -0
- drawspec-0.1.0/src/drawspec/fonts/mono.ttf +0 -0
- drawspec-0.1.0/src/drawspec/fonts/sans-bold.ttf +0 -0
- drawspec-0.1.0/src/drawspec/fonts/sans.ttf +0 -0
- drawspec-0.1.0/src/drawspec/fonts/serif-bold.ttf +0 -0
- drawspec-0.1.0/src/drawspec/fonts/serif.ttf +0 -0
- drawspec-0.1.0/src/drawspec/geometry.py +657 -0
- drawspec-0.1.0/src/drawspec/kinds/__init__.py +143 -0
- drawspec-0.1.0/src/drawspec/kinds/board.py +351 -0
- drawspec-0.1.0/src/drawspec/kinds/common.py +441 -0
- drawspec-0.1.0/src/drawspec/kinds/containers.py +551 -0
- drawspec-0.1.0/src/drawspec/kinds/cycle.py +760 -0
- drawspec-0.1.0/src/drawspec/kinds/entities.py +990 -0
- drawspec-0.1.0/src/drawspec/kinds/files.py +492 -0
- drawspec-0.1.0/src/drawspec/kinds/fishbone.py +524 -0
- drawspec-0.1.0/src/drawspec/kinds/gantt.py +635 -0
- drawspec-0.1.0/src/drawspec/kinds/graph.py +1244 -0
- drawspec-0.1.0/src/drawspec/kinds/grid.py +830 -0
- drawspec-0.1.0/src/drawspec/kinds/journey.py +352 -0
- drawspec-0.1.0/src/drawspec/kinds/lanes.py +614 -0
- drawspec-0.1.0/src/drawspec/kinds/sankey.py +664 -0
- drawspec-0.1.0/src/drawspec/kinds/sequence.py +772 -0
- drawspec-0.1.0/src/drawspec/kinds/shape.py +771 -0
- drawspec-0.1.0/src/drawspec/kinds/treemap.py +714 -0
- drawspec-0.1.0/src/drawspec/kinds/venn.py +467 -0
- drawspec-0.1.0/src/drawspec/layout/__init__.py +44 -0
- drawspec-0.1.0/src/drawspec/layout/base.py +542 -0
- drawspec-0.1.0/src/drawspec/layout/grandalf_engine.py +271 -0
- drawspec-0.1.0/src/drawspec/layout/layered.py +363 -0
- drawspec-0.1.0/src/drawspec/legend.py +226 -0
- drawspec-0.1.0/src/drawspec/mcp.py +344 -0
- drawspec-0.1.0/src/drawspec/py.typed +0 -0
- drawspec-0.1.0/src/drawspec/render.py +289 -0
- drawspec-0.1.0/src/drawspec/routing.py +2782 -0
- drawspec-0.1.0/src/drawspec/scene.py +390 -0
- drawspec-0.1.0/src/drawspec/schema.py +6991 -0
- drawspec-0.1.0/src/drawspec/text/__init__.py +25 -0
- drawspec-0.1.0/src/drawspec/text/fontlib.py +494 -0
- drawspec-0.1.0/src/drawspec/text/measure.py +210 -0
- drawspec-0.1.0/src/drawspec/text/wrap.py +383 -0
- drawspec-0.1.0/src/drawspec/theme.py +1796 -0
- drawspec-0.1.0/src/drawspec/themes/accent.toml +95 -0
- drawspec-0.1.0/src/drawspec/themes/compartment.toml +26 -0
- drawspec-0.1.0/src/drawspec/themes/default.toml +356 -0
- drawspec-0.1.0/src/drawspec/themes/wheel.toml +23 -0
- drawspec-0.1.0/status/plan.md +349 -0
- drawspec-0.1.0/status/spec-annotated.md +688 -0
- drawspec-0.1.0/status/spec-reader.html +1336 -0
- drawspec-0.1.0/status/specification.md +623 -0
- drawspec-0.1.0/tests/test_acceptance.py +475 -0
- drawspec-0.1.0/tests/test_actor.py +262 -0
- drawspec-0.1.0/tests/test_box.py +557 -0
- drawspec-0.1.0/tests/test_brand.py +405 -0
- drawspec-0.1.0/tests/test_caption.py +202 -0
- drawspec-0.1.0/tests/test_clearance.py +159 -0
- drawspec-0.1.0/tests/test_cli.py +338 -0
- drawspec-0.1.0/tests/test_clipping.py +171 -0
- drawspec-0.1.0/tests/test_docs.py +242 -0
- drawspec-0.1.0/tests/test_embedding.py +289 -0
- drawspec-0.1.0/tests/test_emit.py +543 -0
- drawspec-0.1.0/tests/test_export.py +290 -0
- drawspec-0.1.0/tests/test_failure_families.py +506 -0
- drawspec-0.1.0/tests/test_gallery.py +127 -0
- drawspec-0.1.0/tests/test_kinds_board.py +416 -0
- drawspec-0.1.0/tests/test_kinds_chart.py +1480 -0
- drawspec-0.1.0/tests/test_kinds_containers.py +580 -0
- drawspec-0.1.0/tests/test_kinds_cycle.py +719 -0
- drawspec-0.1.0/tests/test_kinds_entities.py +579 -0
- drawspec-0.1.0/tests/test_kinds_files.py +270 -0
- drawspec-0.1.0/tests/test_kinds_fishbone.py +306 -0
- drawspec-0.1.0/tests/test_kinds_gantt.py +492 -0
- drawspec-0.1.0/tests/test_kinds_graph.py +482 -0
- drawspec-0.1.0/tests/test_kinds_grid.py +1116 -0
- drawspec-0.1.0/tests/test_kinds_journey.py +334 -0
- drawspec-0.1.0/tests/test_kinds_lanes.py +418 -0
- drawspec-0.1.0/tests/test_kinds_sankey.py +468 -0
- drawspec-0.1.0/tests/test_kinds_sequence.py +499 -0
- drawspec-0.1.0/tests/test_kinds_shape.py +753 -0
- drawspec-0.1.0/tests/test_kinds_states.py +543 -0
- drawspec-0.1.0/tests/test_kinds_treemap.py +442 -0
- drawspec-0.1.0/tests/test_kinds_venn.py +262 -0
- drawspec-0.1.0/tests/test_labels.py +263 -0
- drawspec-0.1.0/tests/test_layout.py +577 -0
- drawspec-0.1.0/tests/test_layout_spike.py +183 -0
- drawspec-0.1.0/tests/test_lead_rule.py +132 -0
- drawspec-0.1.0/tests/test_legend.py +300 -0
- drawspec-0.1.0/tests/test_margins.py +144 -0
- drawspec-0.1.0/tests/test_mcp.py +259 -0
- drawspec-0.1.0/tests/test_measure.py +337 -0
- drawspec-0.1.0/tests/test_packaging.py +149 -0
- drawspec-0.1.0/tests/test_readability.py +160 -0
- drawspec-0.1.0/tests/test_routing.py +809 -0
- drawspec-0.1.0/tests/test_routing_crossings.py +335 -0
- drawspec-0.1.0/tests/test_schema.py +733 -0
- drawspec-0.1.0/tests/test_self_loops.py +158 -0
- drawspec-0.1.0/tests/test_skill.py +55 -0
- drawspec-0.1.0/tests/test_status.py +273 -0
- drawspec-0.1.0/tests/test_theme.py +708 -0
- drawspec-0.1.0/tests/test_wrap.py +367 -0
- drawspec-0.1.0/tools/clipping.py +299 -0
- drawspec-0.1.0/tools/collisions.py +356 -0
- drawspec-0.1.0/tools/compare.py +690 -0
- drawspec-0.1.0/tools/docs.py +793 -0
- drawspec-0.1.0/tools/gallery.py +164 -0
- drawspec-0.1.0/tools/hero.py +640 -0
- drawspec-0.1.0/tools/spike_layout.py +301 -0
- drawspec-0.1.0/tools/subset_fonts.py +113 -0
- drawspec-0.1.0/uv.lock +1107 -0
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"statusLine": {
|
|
3
|
+
"type": "command",
|
|
4
|
+
"command": "bash claude-arsenal/bin/statusline_capture.sh"
|
|
5
|
+
},
|
|
6
|
+
"hooks": {
|
|
7
|
+
"PreToolUse": [
|
|
8
|
+
{
|
|
9
|
+
"hooks": [
|
|
10
|
+
{
|
|
11
|
+
"type": "command",
|
|
12
|
+
"command": "bash claude-arsenal/bin/check_skill_workshop_loaded.sh"
|
|
13
|
+
}
|
|
14
|
+
],
|
|
15
|
+
"matcher": "Edit|Write|MultiEdit|Bash"
|
|
16
|
+
}
|
|
17
|
+
],
|
|
18
|
+
"PostToolUse": [
|
|
19
|
+
{
|
|
20
|
+
"hooks": [
|
|
21
|
+
{
|
|
22
|
+
"type": "command",
|
|
23
|
+
"command": "bash claude-arsenal/bin/mark_skill_workshop_loaded.sh"
|
|
24
|
+
}
|
|
25
|
+
],
|
|
26
|
+
"matcher": "Skill"
|
|
27
|
+
}
|
|
28
|
+
],
|
|
29
|
+
"UserPromptSubmit": [
|
|
30
|
+
{
|
|
31
|
+
"hooks": [
|
|
32
|
+
{
|
|
33
|
+
"type": "command",
|
|
34
|
+
"command": "bash claude-arsenal/bin/mark_skill_workshop_loaded_from_prompt.sh"
|
|
35
|
+
}
|
|
36
|
+
]
|
|
37
|
+
}
|
|
38
|
+
]
|
|
39
|
+
}
|
|
40
|
+
}
|
|
File without changes
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: continue
|
|
3
|
+
description: When the user wants to resume work or run the worker loop — picks the next unblocked task, optionally scoped by tag(s) and/or a workspace, or matched by title text. Use /continue [TAG … | WORKSPACE | search-text]. Do NOT use before running init.
|
|
4
|
+
user-invocable: true
|
|
5
|
+
argument-hint: "[TAG … | WORKSPACE | search-text]"
|
|
6
|
+
metadata:
|
|
7
|
+
type: workflow
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# continue
|
|
11
|
+
|
|
12
|
+
Resumes session work: reads the task graph from the repository, picks the next unblocked
|
|
13
|
+
task, claims it so no other agent can take it, and runs the worker loop. Optionally scoped
|
|
14
|
+
by tag(s) and/or a workspace, or matched against a fuzzy task title.
|
|
15
|
+
|
|
16
|
+
CANARY: continue-loaded-2026-06-13-fb78d23e-b2c3d4e5f6a7b8c9
|
|
17
|
+
|
|
18
|
+
## When to load
|
|
19
|
+
|
|
20
|
+
Load this skill when:
|
|
21
|
+
|
|
22
|
+
- The user types `/continue`, "continue", "resume", "run the workers", or "WORKSPACE: Continue".
|
|
23
|
+
- The session needs to pick up where a previous session left off.
|
|
24
|
+
- The user provides a workspace name or task search string after the command.
|
|
25
|
+
|
|
26
|
+
## The loop
|
|
27
|
+
|
|
28
|
+
**1. Fetch the task issues.** List issues labelled `arsenal:task`, open **and** closed, using whatever GitHub access
|
|
29
|
+
this surface offers — the built-in GitHub tools, `gh`, or REST — and save the JSON. Closed ones matter: a closed-as-completed issue is what marks a
|
|
30
|
+
dependency satisfied.
|
|
31
|
+
|
|
32
|
+
Request `number`, `title`, `state`, `labels`, `assignees` — **not `body`**. The resolver reads the
|
|
33
|
+
`arsenal-task:` line when a body is present and falls back to matching the title against the task
|
|
34
|
+
files, so bodies change no answer here while dominating the cost: on a 40-issue board they are the
|
|
35
|
+
difference between ~9k and ~1.2k tokens, spent before the first task is even chosen.
|
|
36
|
+
|
|
37
|
+
Run `github_channel.sh --detect` (in `claude-arsenal/bin/`); it prints `gh`, `rest`, or `none`.
|
|
38
|
+
|
|
39
|
+
`none` means no scriptable channel exists here; make the call with the built-in GitHub
|
|
40
|
+
tools instead. It is not a reason to skip the step — a skipped step here means the session
|
|
41
|
+
picks up work another agent is already doing.
|
|
42
|
+
|
|
43
|
+
**2. Ask for the next task.** One call, one line of output:
|
|
44
|
+
|
|
45
|
+
Run `task_select.py` (in `claude-arsenal/scripts/`) with the saved issues:
|
|
46
|
+
|
|
47
|
+
```
|
|
48
|
+
task_select.py --tasks-dir arsenal/tasks --issues /tmp/issues.json \
|
|
49
|
+
--capability surface:cli --workspace FRONTEND --tag CLI
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Ordering is a computation, not a judgement — deps, priority, capabilities and scope are
|
|
53
|
+
all applied by the script, so the decision costs one line of context rather than a
|
|
54
|
+
protocol re-read each session.
|
|
55
|
+
|
|
56
|
+
**3. Check nobody else holds it.** Before claiming, read the task's issue and skip it if
|
|
57
|
+
it is closed, has an assignee, or carries `arsenal:claimed`. This is not a race — a human
|
|
58
|
+
who assigned themselves did so long ago — so a plain check settles it.
|
|
59
|
+
|
|
60
|
+
**4. Claim it.**
|
|
61
|
+
|
|
62
|
+
Run `claim_task.sh <task-id>` (in `claude-arsenal/bin/`).
|
|
63
|
+
|
|
64
|
+
Obey the result verbatim:
|
|
65
|
+
|
|
66
|
+
- `won <ref>` → the task is claimed. Nobody else can hold it: creating the ref is a
|
|
67
|
+
compare-and-swap that GitHub itself arbitrates.
|
|
68
|
+
- `lost` → another agent got there first. Drop it, take the next task. This is normal, not
|
|
69
|
+
an error.
|
|
70
|
+
- `manual POST <path> <body>` → no scriptable channel; make that exact call with the
|
|
71
|
+
built-in GitHub tools. **201 means won, 422 means lost.**
|
|
72
|
+
- `error:` → misconfiguration. Stop and surface it to the user.
|
|
73
|
+
|
|
74
|
+
Never work around a `lost` by claiming a different ref or re-running with another attempt
|
|
75
|
+
number. The whole point of the ref is that exactly one agent proceeds; routing around it
|
|
76
|
+
recreates the double-claims it exists to prevent.
|
|
77
|
+
|
|
78
|
+
Then mark the issue so a human can see which agent holds it: self-assign, add
|
|
79
|
+
`arsenal:claimed`, and comment with the session id from `CLAUDE_CODE_REMOTE_SESSION_ID`
|
|
80
|
+
— a `cse_…` value that doubles as a session URL, so the claim is clickable.
|
|
81
|
+
|
|
82
|
+
**5. Work the task, then open its PR with `open_task_pr.sh`.** It resolves the task's
|
|
83
|
+
issue number, writes `Closes #<issue>` into the PR body *and* the commit message, and
|
|
84
|
+
moves the task file into `arsenal/tasks/_history/` inside the same diff. Merging therefore
|
|
85
|
+
closes the issue, archives the task, and unblocks its dependents in one act — there is no
|
|
86
|
+
"update the queue" step to forget, and nothing left to verify afterwards.
|
|
87
|
+
|
|
88
|
+
Both keyword sites matter: the body form fires on a merge into the default branch, the
|
|
89
|
+
commit form survives a squash and covers a stacked PR based on another branch.
|
|
90
|
+
|
|
91
|
+
**6. Loop back to step 2.**
|
|
92
|
+
|
|
93
|
+
## Scoping
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
# Bare-word tokens are order-independent and resolved by membership:
|
|
97
|
+
# known workspace -> workspace filter (at most one)
|
|
98
|
+
# known tag -> tag filter (multiple tags are ANDed)
|
|
99
|
+
# anything else -> fuzzy title search
|
|
100
|
+
/continue CLI FRONTEND # tag CLI AND workspace FRONTEND
|
|
101
|
+
/continue CLI WEB # tag CLI AND tag WEB
|
|
102
|
+
/continue FRONTEND # workspace only
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
`/continue CLI FRONTEND` and `/continue FRONTEND CLI` resolve to the same scope. A task
|
|
106
|
+
qualifies only if it carries **every** requested tag and matches the workspace when one is
|
|
107
|
+
given.
|
|
108
|
+
|
|
109
|
+
## Gotchas
|
|
110
|
+
|
|
111
|
+
- **`WORKSPACE: Continue`** as natural language (e.g. "FRONTEND: Continue") is equivalent
|
|
112
|
+
to `/continue FRONTEND`.
|
|
113
|
+
- **Task files are read from the default branch.** That is what makes every agent compute
|
|
114
|
+
the same graph regardless of the branch it is working on. A task file on an unmerged
|
|
115
|
+
branch is not yet in the queue.
|
|
116
|
+
- **A task with no issue handle is invisible.** Where `.github/workflows/arsenal-queue.yml`
|
|
117
|
+
is installed, GitHub opens the handle as soon as the task file lands, so this should
|
|
118
|
+
never be outstanding. Where it is not, run `handle_sync.py` (in `claude-arsenal/scripts/`)
|
|
119
|
+
to list task files that need one, and create them. Missing handles delay work; they never
|
|
120
|
+
corrupt it — and `open_task_pr.sh` refuses to open a PR for a task it cannot link, rather
|
|
121
|
+
than merging one that closes nothing.
|
|
122
|
+
- **`gate: false` in the selector output means the task has no runnable gate.** A prose-only
|
|
123
|
+
gate executes nothing and therefore passes everything. Fix the task file before working
|
|
124
|
+
it, rather than completing something that nothing checked.
|
|
125
|
+
- **Blocked workspace**: if a scoped selection is empty but the global queue has tasks,
|
|
126
|
+
report what is blocking and offer to fall back to the global queue.
|
|
127
|
+
- **Retries claim a new ref.** A crashed session blocks nothing: attempt 2 claims
|
|
128
|
+
`<id>.a2`. Past `max-attempts` the task stops being offered and needs a human — read the
|
|
129
|
+
`## Failure notes` in the task file before re-dispatching.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{
|
|
2
|
+
"skill": "continue",
|
|
3
|
+
"canary": "continue-loaded-2026-06-13-fb78d23e-b2c3d4e5f6a7b8c9",
|
|
4
|
+
"negative_control": "this-fact-is-false-and-must-not-appear-in-the-skill-body",
|
|
5
|
+
"load_prompts": [
|
|
6
|
+
"Use the continue skill to resume work on the queue"
|
|
7
|
+
],
|
|
8
|
+
"no_load_prompts": [
|
|
9
|
+
"Generic prompt that should NOT activate continue"
|
|
10
|
+
]
|
|
11
|
+
}
|
|
File without changes
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: coverage-gaps
|
|
3
|
+
description: Use whenever the user wants to turn coverage.py's coverage.json into a ranked list of the highest-value missing tests — surfaces contiguous missing-line runs marking whole untested functions or branches. A cheap line-coverage pass below mutmut-report. Triggers — "what tests am I missing", "where are the coverage gaps". Do NOT use to run the suite or generate the report (run coverage / pytest --cov first), or for non-Python coverage.
|
|
4
|
+
argument-hint: "--input coverage.json --limit N"
|
|
5
|
+
user-invocable: true
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# coverage-gaps
|
|
9
|
+
|
|
10
|
+
Turn an existing coverage.py report into a ranked, actionable list of the tests
|
|
11
|
+
worth writing next.
|
|
12
|
+
|
|
13
|
+
CANARY: coverage-gaps-loaded-2026-06-04-ea39c2b5-b32fe2b1b5ae5e96
|
|
14
|
+
|
|
15
|
+
## When to load
|
|
16
|
+
|
|
17
|
+
Load when a `coverage.json` already exists and the question is *which* gaps to
|
|
18
|
+
fill first. This is the cheap, line-level first pass; once line coverage is
|
|
19
|
+
healthy and the question shifts to whether the existing tests actually *assert*
|
|
20
|
+
behavior, escalate to the `mutmut-report` skill (mutation testing).
|
|
21
|
+
|
|
22
|
+
## Step 1 — Ensure a JSON report exists
|
|
23
|
+
|
|
24
|
+
The script reads coverage.py's JSON export, not the `.coverage` SQLite file or
|
|
25
|
+
the terminal table. If only a run has happened, produce the JSON first:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
coverage json # after `coverage run -m pytest`
|
|
29
|
+
# or in one shot:
|
|
30
|
+
pytest --cov=PKG --cov-report=json # writes coverage.json
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Step 2 — Rank the gaps
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
python3 "${CLAUDE_SKILL_DIR}/scripts/analyze_coverage.py" --input coverage.json --limit 20
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Output is JSON: `total_percent_covered`, `files_with_gaps`, and a ranked `gaps`
|
|
40
|
+
list. Each entry carries `missing_count`, `percent_covered`, `missing_branches`,
|
|
41
|
+
`largest_run`, and `missing_runs` (inclusive `[start, end]` line ranges).
|
|
42
|
+
|
|
43
|
+
## Step 3 — Propose tests
|
|
44
|
+
|
|
45
|
+
Read the source at each `missing_runs` range and report concisely:
|
|
46
|
+
|
|
47
|
+
1. The top files by uncovered lines, and for each, what the largest run is —
|
|
48
|
+
open the source at those lines to name the untested function or branch.
|
|
49
|
+
2. For each high-value gap: the specific test to add (which function, which
|
|
50
|
+
input, which branch).
|
|
51
|
+
3. Note which gaps are low-value (scattered single lines — often defensive
|
|
52
|
+
`raise` / logging paths) and can be deferred or marked `# pragma: no cover`.
|
|
53
|
+
|
|
54
|
+
Lead with the 2-3 tests worth writing now. Do not re-explain what coverage is.
|
|
55
|
+
|
|
56
|
+
## Gotchas
|
|
57
|
+
|
|
58
|
+
- **No JSON report yet.** The script needs `coverage.json`; a bare `coverage
|
|
59
|
+
run` leaves only the `.coverage` SQLite db and a terminal summary. Run
|
|
60
|
+
`coverage json` (or `--cov-report=json`) first, or the script exits 2.
|
|
61
|
+
- **100% line coverage is not 100% tested.** A line counts as covered the
|
|
62
|
+
moment it executes, even if nothing asserts its result. Treat this skill as
|
|
63
|
+
the floor; for assertion quality, escalate to the `mutmut-report` skill.
|
|
64
|
+
- **Big contiguous run ≠ always the priority.** A long `missing_run` can be a
|
|
65
|
+
generated block, a `__repr__`, or a `if TYPE_CHECKING:` import island. Open
|
|
66
|
+
the source before recommending — rank by what the code *does*, not just line
|
|
67
|
+
count.
|
|
68
|
+
- **Branch gaps hide inside covered files.** A file at high line coverage can
|
|
69
|
+
still have untaken branches; check `missing_branches`, which only populates
|
|
70
|
+
when the report was generated with branch coverage (`--cov-branch` or
|
|
71
|
+
`[tool.coverage.run] branch = true`).
|
|
72
|
+
- **Stale report after a refactor.** Line numbers in an old `coverage.json`
|
|
73
|
+
drift from current source. Regenerate the report against the current tree
|
|
74
|
+
before trusting the ranges.
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"skill": "coverage-gaps",
|
|
3
|
+
"canary": "coverage-gaps-loaded-2026-06-04-ea39c2b5-b32fe2b1b5ae5e96",
|
|
4
|
+
"negative_control": "the coverage-gaps skill runs the pytest suite and generates the coverage.json report itself before analyzing it",
|
|
5
|
+
"load_prompts": [
|
|
6
|
+
"Which tests am I missing the most?",
|
|
7
|
+
"Analyze my coverage and tell me where the gaps are",
|
|
8
|
+
"Where is the most valuable untested code in this project?",
|
|
9
|
+
"Triage my coverage.json for the highest-value tests to add",
|
|
10
|
+
"/coverage-gaps --input coverage.json --limit 15"
|
|
11
|
+
],
|
|
12
|
+
"no_load_prompts": [
|
|
13
|
+
"Run the test suite with coverage",
|
|
14
|
+
"Which surviving mutants are real test gaps?",
|
|
15
|
+
"Publish this package to PyPI",
|
|
16
|
+
"Set up pyproject and ruff for this repo"
|
|
17
|
+
]
|
|
18
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""analyze_coverage.py — rank a coverage.py report's gaps by test value.
|
|
3
|
+
|
|
4
|
+
Reads a coverage.py JSON report (produced by `coverage json`) and emits a
|
|
5
|
+
ranked JSON list of the files with the most to gain from new tests. For each
|
|
6
|
+
file it reports the uncovered line count, the percent covered, and the
|
|
7
|
+
*contiguous* missing-line runs — a run of consecutive uncovered lines usually
|
|
8
|
+
marks a whole untested function or branch, which is higher-value than the
|
|
9
|
+
scattered single lines that tend to be defensive error handlers.
|
|
10
|
+
|
|
11
|
+
JSON-only on stdout; errors on stderr. Exit 0 when the report builds; exit 2 on
|
|
12
|
+
a usage error (e.g. the input file is missing — run `coverage json` first).
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
import argparse
|
|
16
|
+
import json
|
|
17
|
+
import sys
|
|
18
|
+
from pathlib import Path
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def contiguous_runs(lines: list[int]) -> list[list[int]]:
|
|
22
|
+
"""Collapse a sorted line list into [start, end] inclusive runs."""
|
|
23
|
+
runs: list[list[int]] = []
|
|
24
|
+
for line in sorted(lines):
|
|
25
|
+
if runs and line == runs[-1][1] + 1:
|
|
26
|
+
runs[-1][1] = line
|
|
27
|
+
else:
|
|
28
|
+
runs.append([line, line])
|
|
29
|
+
return runs
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def build_report(data: dict, limit: int) -> dict:
|
|
33
|
+
files_data = data.get("files")
|
|
34
|
+
files = []
|
|
35
|
+
for path, info in (files_data if isinstance(files_data, dict) else {}).items():
|
|
36
|
+
if not isinstance(info, dict):
|
|
37
|
+
continue
|
|
38
|
+
missing = info.get("missing_lines", [])
|
|
39
|
+
missing_branches = info.get("missing_branches", [])
|
|
40
|
+
# Include files with missing lines OR with missing branch coverage (a file
|
|
41
|
+
# at 100% line coverage can still have untaken branches — see Gotchas).
|
|
42
|
+
if not missing and not missing_branches:
|
|
43
|
+
continue
|
|
44
|
+
summary = info.get("summary") or {}
|
|
45
|
+
runs = contiguous_runs(missing)
|
|
46
|
+
files.append(
|
|
47
|
+
{
|
|
48
|
+
"file": path,
|
|
49
|
+
"percent_covered": round(summary.get("percent_covered", 0.0), 1),
|
|
50
|
+
"missing_count": len(missing),
|
|
51
|
+
"missing_branches": len(missing_branches),
|
|
52
|
+
"largest_run": max((r[1] - r[0] + 1 for r in runs), default=0),
|
|
53
|
+
"missing_runs": runs,
|
|
54
|
+
}
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
# Most uncovered lines first; break ties toward the least-covered file.
|
|
58
|
+
files.sort(key=lambda f: (-f["missing_count"], f["percent_covered"]))
|
|
59
|
+
totals = data.get("totals", {})
|
|
60
|
+
return {
|
|
61
|
+
"total_percent_covered": round(totals.get("percent_covered", 0.0), 1),
|
|
62
|
+
"files_with_gaps": len(files),
|
|
63
|
+
"gaps": files[:limit],
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def main() -> int:
|
|
68
|
+
parser = argparse.ArgumentParser(description=__doc__.splitlines()[0])
|
|
69
|
+
parser.add_argument(
|
|
70
|
+
"--input",
|
|
71
|
+
default="coverage.json",
|
|
72
|
+
help="coverage.py JSON report (default: coverage.json). Generate with `coverage json`.",
|
|
73
|
+
)
|
|
74
|
+
parser.add_argument("--limit", type=int, default=20, help="Max files to report (default: 20)")
|
|
75
|
+
args = parser.parse_args()
|
|
76
|
+
|
|
77
|
+
path = Path(args.input)
|
|
78
|
+
if not path.exists():
|
|
79
|
+
print(
|
|
80
|
+
f"✗ {path} not found — run `coverage json` (or `pytest --cov ... "
|
|
81
|
+
"--cov-report json`) first",
|
|
82
|
+
file=sys.stderr,
|
|
83
|
+
)
|
|
84
|
+
return 2
|
|
85
|
+
try:
|
|
86
|
+
data = json.loads(path.read_text(encoding="utf-8"))
|
|
87
|
+
except json.JSONDecodeError as exc:
|
|
88
|
+
print(f"✗ {path} is not valid JSON: {exc}", file=sys.stderr)
|
|
89
|
+
return 2
|
|
90
|
+
except OSError as exc:
|
|
91
|
+
print(f"✗ failed to read {path}: {exc}", file=sys.stderr)
|
|
92
|
+
return 2
|
|
93
|
+
|
|
94
|
+
if not isinstance(data, dict):
|
|
95
|
+
print(f"✗ {path} is not a coverage.py report (expected a JSON object)", file=sys.stderr)
|
|
96
|
+
return 2
|
|
97
|
+
|
|
98
|
+
print(json.dumps(build_report(data, args.limit), indent=2))
|
|
99
|
+
return 0
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
if __name__ == "__main__":
|
|
103
|
+
sys.exit(main())
|
|
File without changes
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: dep-upgrade
|
|
3
|
+
description: Use whenever a uv-managed Python project's dependencies need upgrading safely — the uv lock --upgrade, pip-audit, test-gate, classify-breakage runbook, splitting lockfile churn into direct vs transitive. Triggers — "upgrade the dependencies", "check for vulnerable dependencies". Do NOT use to add one dependency (just uv add), scaffold tooling (see python-bootstrap), or publish (see pypi-release).
|
|
4
|
+
argument-hint: "uv.lock.bak uv.lock"
|
|
5
|
+
user-invocable: true
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# dep-upgrade
|
|
9
|
+
|
|
10
|
+
Upgrade a uv-managed project's dependencies under a safety net: snapshot, lock,
|
|
11
|
+
audit for CVEs, gate on the test suite, then classify whatever broke.
|
|
12
|
+
|
|
13
|
+
CANARY: dep-upgrade-loaded-2026-06-04-ea39c2b5-719c61e6e84e1453
|
|
14
|
+
|
|
15
|
+
## When to load
|
|
16
|
+
|
|
17
|
+
Load when the task is a deliberate dependency *upgrade* of a uv project —
|
|
18
|
+
refreshing the lockfile, chasing CVEs, or pulling in newer versions. For adding
|
|
19
|
+
one new package, plain `uv add` is enough; for scaffolding tooling defer to the
|
|
20
|
+
`python-bootstrap` skill.
|
|
21
|
+
|
|
22
|
+
## Step 1 — Snapshot, then upgrade
|
|
23
|
+
|
|
24
|
+
Keep the pre-upgrade lockfile so the change is reviewable and revertible:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
cp uv.lock uv.lock.bak
|
|
28
|
+
uv lock --upgrade # refresh every pin to the latest compatible release
|
|
29
|
+
uv sync # install the new resolution into the environment
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
To upgrade a single package instead of everything: `uv lock --upgrade-package NAME`.
|
|
33
|
+
|
|
34
|
+
## Step 2 — See what actually changed
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
python3 "${CLAUDE_SKILL_DIR}/scripts/compare_lockfile.py" uv.lock.bak uv.lock
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
The JSON splits `changed` into `direct` (declared in `pyproject.toml`) and
|
|
41
|
+
transitive, with `direct_changes` / `transitive_changes` counts, plus `added`
|
|
42
|
+
and `removed`. Transitive bumps are where "passes locally, breaks on a clean
|
|
43
|
+
install" hides — read them, do not skim.
|
|
44
|
+
|
|
45
|
+
## Step 3 — Audit for CVEs
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
uvx pip-audit # scans the resolved environment for known CVEs
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Treat a finding as a reason to upgrade *further* (to the patched version), not
|
|
52
|
+
to pin backwards onto the vulnerable release. Note any advisory with no fixed
|
|
53
|
+
version as a risk to surface.
|
|
54
|
+
|
|
55
|
+
## Step 4 — Test gate + classify
|
|
56
|
+
|
|
57
|
+
Run the project's full suite against the new resolution:
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
make test # or: uv run pytest
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
If green, report the upgrade with the direct/transitive breakdown and any CVE
|
|
64
|
+
findings. If red, classify each failure: a behavior change in a direct dep
|
|
65
|
+
(read its changelog), a transitive bump that surfaced a latent bug, or a real
|
|
66
|
+
incompatibility that needs a constraint. Pin the minimum necessary in
|
|
67
|
+
`pyproject.toml`, re-lock, and re-run — never weaken the test to pass.
|
|
68
|
+
|
|
69
|
+
## Gotchas
|
|
70
|
+
|
|
71
|
+
- **Transitive churn breaks clean installs only.** A transitive bump can pass
|
|
72
|
+
every local test yet fail `uv sync` on a fresh machine or minimal CI image,
|
|
73
|
+
because the local cache still holds the old wheel. Always check
|
|
74
|
+
`transitive_changes` and re-resolve in a clean environment before trusting
|
|
75
|
+
green.
|
|
76
|
+
- **`uv lock --upgrade` moves everything at once.** A repo-wide upgrade folds
|
|
77
|
+
dozens of changes into one diff, making the culprit of a new failure hard to
|
|
78
|
+
isolate. Prefer `--upgrade-package NAME` for a targeted bump when chasing a
|
|
79
|
+
specific CVE or feature.
|
|
80
|
+
- **Pinning backwards to dodge a CVE.** Constraining a package to an old,
|
|
81
|
+
vulnerable version to "make pip-audit quiet" reintroduces the vulnerability.
|
|
82
|
+
Move forward to the fixed release; only pin backwards with an explicit,
|
|
83
|
+
documented reason.
|
|
84
|
+
- **Lockfile churn buries the signal.** `git diff uv.lock` after an upgrade is
|
|
85
|
+
enormous and mostly hash noise. Use the script's direct/transitive summary to
|
|
86
|
+
find the handful of changes that matter rather than reading the raw diff.
|
|
87
|
+
- **Skipping `uv sync` after `uv lock`.** `uv lock --upgrade` rewrites the
|
|
88
|
+
lockfile but does not touch the environment; tests run against the *old*
|
|
89
|
+
installed versions and falsely pass. Always `uv sync` before the test gate.
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"skill": "dep-upgrade",
|
|
3
|
+
"canary": "dep-upgrade-loaded-2026-06-04-ea39c2b5-719c61e6e84e1453",
|
|
4
|
+
"negative_control": "the dep-upgrade skill pins dependencies backwards to their previous versions to silence pip-audit findings",
|
|
5
|
+
"load_prompts": [
|
|
6
|
+
"Upgrade all the dependencies in this project",
|
|
7
|
+
"Run uv lock --upgrade and make sure nothing broke",
|
|
8
|
+
"Check for vulnerable dependencies and patch them",
|
|
9
|
+
"Bump our packages and tell me what changed",
|
|
10
|
+
"Is anything out of date or insecure in this repo?"
|
|
11
|
+
],
|
|
12
|
+
"no_load_prompts": [
|
|
13
|
+
"Add the requests package to this project",
|
|
14
|
+
"Set up pyproject and ruff for this repo",
|
|
15
|
+
"Publish this package to PyPI",
|
|
16
|
+
"Which tests am I missing the most?"
|
|
17
|
+
]
|
|
18
|
+
}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""compare_lockfile.py — diff two uv.lock files and classify what changed.
|
|
3
|
+
|
|
4
|
+
Takes the lockfile from before an upgrade and the lockfile after, and emits a
|
|
5
|
+
JSON summary on stdout: which packages were added, removed, or version-bumped,
|
|
6
|
+
and for each change whether the package is a *direct* dependency (declared in
|
|
7
|
+
pyproject.toml) or *transitive* (pulled in by something else). Transitive churn
|
|
8
|
+
is the usual source of "passes locally, breaks on a clean install" surprises,
|
|
9
|
+
so separating it from the deps actually requested is the point.
|
|
10
|
+
|
|
11
|
+
JSON-only on stdout; errors on stderr. Exit 0 when the diff builds; exit 2 on a
|
|
12
|
+
usage error (missing file, malformed TOML).
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
import argparse
|
|
16
|
+
import json
|
|
17
|
+
import re
|
|
18
|
+
import sys
|
|
19
|
+
import tomllib
|
|
20
|
+
from pathlib import Path
|
|
21
|
+
|
|
22
|
+
NAME_RE = re.compile(r"^([A-Za-z0-9._-]+)")
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def load_lock(path: Path) -> dict[str, str]:
|
|
26
|
+
with path.open("rb") as fh:
|
|
27
|
+
data = tomllib.load(fh)
|
|
28
|
+
packages = data.get("package", [])
|
|
29
|
+
if not isinstance(packages, list):
|
|
30
|
+
return {}
|
|
31
|
+
return {
|
|
32
|
+
pkg["name"]: pkg.get("version", "")
|
|
33
|
+
for pkg in packages
|
|
34
|
+
if isinstance(pkg, dict) and "name" in pkg
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def direct_dep_names(pyproject: Path) -> set[str]:
|
|
39
|
+
"""Canonical names of every dependency declared in pyproject.toml."""
|
|
40
|
+
if not pyproject.exists():
|
|
41
|
+
return set()
|
|
42
|
+
with pyproject.open("rb") as fh:
|
|
43
|
+
data = tomllib.load(fh)
|
|
44
|
+
|
|
45
|
+
specs: list[str] = []
|
|
46
|
+
project = data.get("project", {})
|
|
47
|
+
if isinstance(project, dict):
|
|
48
|
+
deps = project.get("dependencies", [])
|
|
49
|
+
if isinstance(deps, list):
|
|
50
|
+
specs += deps
|
|
51
|
+
opt_deps = project.get("optional-dependencies", {})
|
|
52
|
+
if isinstance(opt_deps, dict):
|
|
53
|
+
for group in opt_deps.values():
|
|
54
|
+
if isinstance(group, list):
|
|
55
|
+
specs += group
|
|
56
|
+
dep_groups = data.get("dependency-groups", {})
|
|
57
|
+
if isinstance(dep_groups, dict):
|
|
58
|
+
for group in dep_groups.values():
|
|
59
|
+
if isinstance(group, list):
|
|
60
|
+
specs += group
|
|
61
|
+
tool = data.get("tool", {})
|
|
62
|
+
uv = tool.get("uv", {}) if isinstance(tool, dict) else {}
|
|
63
|
+
if isinstance(uv, dict):
|
|
64
|
+
dev_deps = uv.get("dev-dependencies", [])
|
|
65
|
+
if isinstance(dev_deps, list):
|
|
66
|
+
specs += dev_deps
|
|
67
|
+
|
|
68
|
+
names = set()
|
|
69
|
+
for spec in specs:
|
|
70
|
+
if not isinstance(spec, str):
|
|
71
|
+
continue
|
|
72
|
+
match = NAME_RE.match(spec.strip())
|
|
73
|
+
if match:
|
|
74
|
+
names.add(match.group(1).lower().replace("_", "-"))
|
|
75
|
+
return names
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def build_report(before: dict[str, str], after: dict[str, str], direct: set[str]) -> dict:
|
|
79
|
+
def is_direct(name: str) -> bool:
|
|
80
|
+
return name.lower().replace("_", "-") in direct
|
|
81
|
+
|
|
82
|
+
changed = [
|
|
83
|
+
{"name": n, "from": before[n], "to": after[n], "direct": is_direct(n)}
|
|
84
|
+
for n in sorted(before.keys() & after.keys())
|
|
85
|
+
if before[n] != after[n]
|
|
86
|
+
]
|
|
87
|
+
added = [
|
|
88
|
+
{"name": n, "version": after[n], "direct": is_direct(n)}
|
|
89
|
+
for n in sorted(after.keys() - before.keys())
|
|
90
|
+
]
|
|
91
|
+
removed = [{"name": n, "version": before[n]} for n in sorted(before.keys() - after.keys())]
|
|
92
|
+
return {
|
|
93
|
+
"changed": changed,
|
|
94
|
+
"added": added,
|
|
95
|
+
"removed": removed,
|
|
96
|
+
"direct_changes": sum(1 for c in changed if c["direct"]),
|
|
97
|
+
"transitive_changes": sum(1 for c in changed if not c["direct"]),
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def main() -> int:
|
|
102
|
+
parser = argparse.ArgumentParser(description=__doc__.splitlines()[0])
|
|
103
|
+
parser.add_argument("before", help="uv.lock from before the upgrade (e.g. uv.lock.bak)")
|
|
104
|
+
parser.add_argument("after", help="uv.lock after the upgrade")
|
|
105
|
+
parser.add_argument(
|
|
106
|
+
"--input",
|
|
107
|
+
default="pyproject.toml",
|
|
108
|
+
help="pyproject.toml used to classify direct vs transitive (default: pyproject.toml)",
|
|
109
|
+
)
|
|
110
|
+
args = parser.parse_args()
|
|
111
|
+
|
|
112
|
+
try:
|
|
113
|
+
before = load_lock(Path(args.before))
|
|
114
|
+
after = load_lock(Path(args.after))
|
|
115
|
+
direct = direct_dep_names(Path(args.input))
|
|
116
|
+
except FileNotFoundError as exc:
|
|
117
|
+
print(f"✗ {exc}", file=sys.stderr)
|
|
118
|
+
return 2
|
|
119
|
+
except tomllib.TOMLDecodeError as exc:
|
|
120
|
+
print(f"✗ malformed TOML: {exc}", file=sys.stderr)
|
|
121
|
+
return 2
|
|
122
|
+
except OSError as exc:
|
|
123
|
+
print(f"✗ failed to read file: {exc}", file=sys.stderr)
|
|
124
|
+
return 2
|
|
125
|
+
|
|
126
|
+
report = build_report(before, after, direct)
|
|
127
|
+
print(json.dumps(report, indent=2))
|
|
128
|
+
return 0
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
if __name__ == "__main__":
|
|
132
|
+
sys.exit(main())
|
|
File without changes
|