@erclx/canon 4.0.0
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.
- package/LICENSE +21 -0
- package/README.md +129 -0
- package/claude/.claude-plugin/plugin.json +19 -0
- package/claude/skills/bash-cli-script/REQUIREMENT.md +42 -0
- package/claude/skills/bash-cli-script/SKILL.md +48 -0
- package/claude/skills/bash-cli-script/references/template.md +43 -0
- package/claude/skills/bash-script/REQUIREMENT.md +36 -0
- package/claude/skills/bash-script/SKILL.md +100 -0
- package/claude/skills/bash-script/references/patterns.md +349 -0
- package/claude/skills/canon-cli/REQUIREMENT.md +41 -0
- package/claude/skills/canon-cli/SKILL.md +103 -0
- package/claude/skills/canon-feedback-file/REQUIREMENT.md +40 -0
- package/claude/skills/canon-feedback-file/SKILL.md +80 -0
- package/claude/skills/canon-feedback-triage/REQUIREMENT.md +40 -0
- package/claude/skills/canon-feedback-triage/SKILL.md +63 -0
- package/claude/skills/canon-operator/REQUIREMENT.md +61 -0
- package/claude/skills/canon-operator/SKILL.md +108 -0
- package/claude/skills/canon-rollout/REQUIREMENT.md +59 -0
- package/claude/skills/canon-rollout/SKILL.md +147 -0
- package/claude/skills/canon-screencast/REQUIREMENT.md +39 -0
- package/claude/skills/canon-screencast/SKILL.md +167 -0
- package/claude/skills/canon-slides-draft/REQUIREMENT.md +39 -0
- package/claude/skills/canon-slides-draft/SKILL.md +62 -0
- package/claude/skills/ci-workflow/REQUIREMENT.md +40 -0
- package/claude/skills/ci-workflow/SKILL.md +65 -0
- package/claude/skills/ci-workflow/references/workflows.md +98 -0
- package/claude/skills/claude-address-review/REQUIREMENT.md +57 -0
- package/claude/skills/claude-address-review/SKILL.md +212 -0
- package/claude/skills/claude-address-review/references/rebase-conflicts.md +39 -0
- package/claude/skills/claude-autoship/REQUIREMENT.md +50 -0
- package/claude/skills/claude-autoship/SKILL.md +207 -0
- package/claude/skills/claude-design-extract/REQUIREMENT.md +42 -0
- package/claude/skills/claude-design-extract/SKILL.md +102 -0
- package/claude/skills/claude-diagram/REQUIREMENT.md +45 -0
- package/claude/skills/claude-diagram/SKILL.md +177 -0
- package/claude/skills/claude-docs/REQUIREMENT.md +60 -0
- package/claude/skills/claude-docs/SKILL.md +287 -0
- package/claude/skills/claude-docs/references/anchor-sweep.md +58 -0
- package/claude/skills/claude-docs/references/wireframe-sweep.md +45 -0
- package/claude/skills/claude-feature/REQUIREMENT.md +36 -0
- package/claude/skills/claude-feature/SKILL.md +115 -0
- package/claude/skills/claude-groundwork/REQUIREMENT.md +48 -0
- package/claude/skills/claude-groundwork/SKILL.md +142 -0
- package/claude/skills/claude-intake/REQUIREMENT.md +49 -0
- package/claude/skills/claude-intake/SKILL.md +114 -0
- package/claude/skills/claude-intake-answer/REQUIREMENT.md +48 -0
- package/claude/skills/claude-intake-answer/SKILL.md +90 -0
- package/claude/skills/claude-markdown-propose/REQUIREMENT.md +48 -0
- package/claude/skills/claude-markdown-propose/SKILL.md +118 -0
- package/claude/skills/claude-markdown-propose/references/format.md +107 -0
- package/claude/skills/claude-memory-capture/REQUIREMENT.md +50 -0
- package/claude/skills/claude-memory-capture/SKILL.md +101 -0
- package/claude/skills/claude-memory-review/REQUIREMENT.md +50 -0
- package/claude/skills/claude-memory-review/SKILL.md +210 -0
- package/claude/skills/claude-memory-review/references/receipt-format.md +48 -0
- package/claude/skills/claude-orchestrate/REQUIREMENT.md +121 -0
- package/claude/skills/claude-orchestrate/SKILL.md +241 -0
- package/claude/skills/claude-orchestrate/references/orchestrator-dispatch.md +132 -0
- package/claude/skills/claude-orchestrate/references/orchestrator-handoff.md +32 -0
- package/claude/skills/claude-orchestrate/references/orchestrator-parked.md +72 -0
- package/claude/skills/claude-orchestrate/references/orchestrator-poll.md +87 -0
- package/claude/skills/claude-orchestrate/references/orchestrator-resume.md +30 -0
- package/claude/skills/claude-orchestrate/references/orchestrator-sweep.md +21 -0
- package/claude/skills/claude-orchestrate/scripts/poll.sh +373 -0
- package/claude/skills/claude-orchestrate/scripts/watch.sh +181 -0
- package/claude/skills/claude-pr-review/REQUIREMENT.md +47 -0
- package/claude/skills/claude-pr-review/SKILL.md +295 -0
- package/claude/skills/claude-review/REQUIREMENT.md +39 -0
- package/claude/skills/claude-review/SKILL.md +142 -0
- package/claude/skills/claude-seed-sync/REQUIREMENT.md +45 -0
- package/claude/skills/claude-seed-sync/SKILL.md +156 -0
- package/claude/skills/claude-standards-audit/REQUIREMENT.md +33 -0
- package/claude/skills/claude-standards-audit/SKILL.md +99 -0
- package/claude/skills/claude-tasks/REQUIREMENT.md +43 -0
- package/claude/skills/claude-tasks/SKILL.md +161 -0
- package/claude/skills/claude-teach/REQUIREMENT.md +56 -0
- package/claude/skills/claude-teach/SKILL.md +196 -0
- package/claude/skills/claude-teach/references/lesson-craft.md +59 -0
- package/claude/skills/claude-teach/references/pedagogy.md +67 -0
- package/claude/skills/claude-teach/references/promotion.md +54 -0
- package/claude/skills/claude-ui-test/REQUIREMENT.md +40 -0
- package/claude/skills/claude-ui-test/SKILL.md +77 -0
- package/claude/skills/claude-ux-audit/REQUIREMENT.md +40 -0
- package/claude/skills/claude-ux-audit/SKILL.md +79 -0
- package/claude/skills/claude-ux-measure/REQUIREMENT.md +48 -0
- package/claude/skills/claude-ux-measure/SKILL.md +122 -0
- package/claude/skills/claude-worker/REQUIREMENT.md +54 -0
- package/claude/skills/claude-worker/SKILL.md +96 -0
- package/claude/skills/claude-worktree/REQUIREMENT.md +58 -0
- package/claude/skills/claude-worktree/SKILL.md +136 -0
- package/claude/skills/create-rule/REQUIREMENT.md +45 -0
- package/claude/skills/create-rule/SKILL.md +68 -0
- package/claude/skills/create-skill/REQUIREMENT.md +38 -0
- package/claude/skills/create-skill/SKILL.md +32 -0
- package/claude/skills/create-snippet/REQUIREMENT.md +39 -0
- package/claude/skills/create-snippet/SKILL.md +30 -0
- package/claude/skills/create-standard/REQUIREMENT.md +35 -0
- package/claude/skills/create-standard/SKILL.md +29 -0
- package/claude/skills/decision-escalate/REQUIREMENT.md +45 -0
- package/claude/skills/decision-escalate/SKILL.md +79 -0
- package/claude/skills/docs-sync/REQUIREMENT.md +41 -0
- package/claude/skills/docs-sync/SKILL.md +95 -0
- package/claude/skills/git-branch/REQUIREMENT.md +38 -0
- package/claude/skills/git-branch/SKILL.md +60 -0
- package/claude/skills/git-commit/REQUIREMENT.md +36 -0
- package/claude/skills/git-commit/SKILL.md +49 -0
- package/claude/skills/git-followup/REQUIREMENT.md +43 -0
- package/claude/skills/git-followup/SKILL.md +48 -0
- package/claude/skills/git-issue/REQUIREMENT.md +38 -0
- package/claude/skills/git-issue/SKILL.md +65 -0
- package/claude/skills/git-pr/REQUIREMENT.md +50 -0
- package/claude/skills/git-pr/SKILL.md +164 -0
- package/claude/skills/git-pr/references/labels.md +95 -0
- package/claude/skills/git-ship/REQUIREMENT.md +42 -0
- package/claude/skills/git-ship/SKILL.md +55 -0
- package/claude/skills/git-split/REQUIREMENT.md +39 -0
- package/claude/skills/git-split/SKILL.md +162 -0
- package/claude/skills/git-stage/REQUIREMENT.md +39 -0
- package/claude/skills/git-stage/SKILL.md +73 -0
- package/claude/skills/git-worktree/REQUIREMENT.md +38 -0
- package/claude/skills/git-worktree/SKILL.md +130 -0
- package/claude/skills/migration-claude-md/REQUIREMENT.md +40 -0
- package/claude/skills/migration-claude-md/SKILL.md +76 -0
- package/claude/skills/migration-context/REQUIREMENT.md +36 -0
- package/claude/skills/migration-context/SKILL.md +95 -0
- package/claude/skills/migration-standards-drop/REQUIREMENT.md +55 -0
- package/claude/skills/migration-standards-drop/SKILL.md +113 -0
- package/claude/skills/migration-superseded/REQUIREMENT.md +44 -0
- package/claude/skills/migration-superseded/SKILL.md +115 -0
- package/claude/skills/project-commands/REQUIREMENT.md +42 -0
- package/claude/skills/project-commands/SKILL.md +85 -0
- package/claude/skills/restate-plainly/REQUIREMENT.md +41 -0
- package/claude/skills/restate-plainly/SKILL.md +39 -0
- package/claude/skills/session-map/REQUIREMENT.md +57 -0
- package/claude/skills/session-map/SKILL.md +70 -0
- package/claude/skills/session-resume/REQUIREMENT.md +49 -0
- package/claude/skills/session-resume/SKILL.md +51 -0
- package/claude/skills/setup-gov/REQUIREMENT.md +37 -0
- package/claude/skills/setup-gov/SKILL.md +77 -0
- package/claude/skills/setup-indexes/REQUIREMENT.md +45 -0
- package/claude/skills/setup-indexes/SKILL.md +153 -0
- package/claude/skills/setup-init/REQUIREMENT.md +45 -0
- package/claude/skills/setup-init/SKILL.md +127 -0
- package/claude/skills/setup-plugins/REQUIREMENT.md +42 -0
- package/claude/skills/setup-plugins/SKILL.md +81 -0
- package/claude/skills/setup-plugins/references/plugin-catalog.md +53 -0
- package/claude/skills/setup-verify/REQUIREMENT.md +39 -0
- package/claude/skills/setup-verify/SKILL.md +51 -0
- package/claude/skills/systematic-debugging/REQUIREMENT.md +41 -0
- package/claude/skills/systematic-debugging/SKILL.md +70 -0
- package/claude/skills/write-human/REQUIREMENT.md +46 -0
- package/claude/skills/write-human/SKILL.md +68 -0
- package/claude/skills/write-human/references/density.md +38 -0
- package/claude/skills/write-human/references/machine-tells.md +107 -0
- package/claude/skills/write-human/references/source-material.md +37 -0
- package/claude/skills/youtube-transcripts/REQUIREMENT.md +38 -0
- package/claude/skills/youtube-transcripts/SKILL.md +34 -0
- package/docs/agents/audits.md +98 -0
- package/docs/agents/capture.md +37 -0
- package/docs/agents/census.md +23 -0
- package/docs/agents/commands.md +146 -0
- package/docs/agents/comments.md +34 -0
- package/docs/agents/context-audit-checks.md +120 -0
- package/docs/agents/context-audit.md +83 -0
- package/docs/agents/counts.md +76 -0
- package/docs/agents/demo.md +86 -0
- package/docs/agents/docs.md +17 -0
- package/docs/agents/gate.md +84 -0
- package/docs/agents/index.md +47 -0
- package/docs/agents/indexes.md +35 -0
- package/docs/agents/install-and-sync.md +385 -0
- package/docs/agents/intake.md +81 -0
- package/docs/agents/key-changes.md +103 -0
- package/docs/agents/label-coverage.md +73 -0
- package/docs/agents/markdown-audit.md +197 -0
- package/docs/agents/output-shape.md +70 -0
- package/docs/agents/overview.md +26 -0
- package/docs/agents/records.md +170 -0
- package/docs/agents/restated.md +81 -0
- package/docs/agents/review-classification.md +77 -0
- package/docs/agents/routing.md +61 -0
- package/docs/agents/rule-citations.md +98 -0
- package/docs/agents/sandbox.md +71 -0
- package/docs/agents/scripting.md +149 -0
- package/docs/agents/sessions.md +120 -0
- package/docs/agents/skills-audit.md +94 -0
- package/docs/agents/skills-reach.md +64 -0
- package/docs/agents/standards-audit.md +38 -0
- package/docs/agents/state-scoped-risk.md +105 -0
- package/docs/agents/superseded.md +85 -0
- package/docs/agents/targets.md +83 -0
- package/docs/agents/tasks.md +200 -0
- package/docs/agents/teach.md +158 -0
- package/docs/agents/test-order.md +56 -0
- package/docs/agents/worktrees.md +62 -0
- package/docs/ai-workflow.md +317 -0
- package/docs/index.md +23 -0
- package/docs/operating-model.md +223 -0
- package/docs/target-projects.md +258 -0
- package/docs/visual-design-workflow.md +151 -0
- package/docs/zshrc-aliases.md +65 -0
- package/governance/rules/ci/700-ci-workflow.md +44 -0
- package/governance/rules/claude/500-prose.md +15 -0
- package/governance/rules/claude/501-markdown.md +14 -0
- package/governance/rules/claude/510-context.md +28 -0
- package/governance/rules/claude/511-indexes.md +14 -0
- package/governance/rules/claude/520-wireframes.md +12 -0
- package/governance/rules/claude/530-requirements.md +11 -0
- package/governance/rules/claude/540-architecture.md +11 -0
- package/governance/rules/claude/550-design.md +11 -0
- package/governance/rules/claude/555-tasks.md +12 -0
- package/governance/rules/claude/556-groundwork.md +11 -0
- package/governance/rules/claude/557-intake.md +11 -0
- package/governance/rules/claude/558-plan.md +22 -0
- package/governance/rules/claude/559-memory.md +11 -0
- package/governance/rules/claude/560-diagrams.md +18 -0
- package/governance/rules/claude/561-teach.md +13 -0
- package/governance/rules/claude/562-session.md +15 -0
- package/governance/rules/claude/570-skill.md +24 -0
- package/governance/rules/claude/575-hooks.md +17 -0
- package/governance/rules/claude/576-settings.md +14 -0
- package/governance/rules/claude/580-readme.md +11 -0
- package/governance/rules/claude/590-rule-authoring.md +12 -0
- package/governance/rules/claude/591-standard-authoring.md +12 -0
- package/governance/rules/claude/592-claude-md.md +19 -0
- package/governance/rules/core/000-constitution.md +30 -0
- package/governance/rules/core/005-behavior.md +27 -0
- package/governance/rules/core/010-testing.md +35 -0
- package/governance/rules/core/015-output.md +20 -0
- package/governance/rules/core/020-concurrency.md +22 -0
- package/governance/rules/core/025-indexes.md +9 -0
- package/governance/rules/core/030-error-handling.md +31 -0
- package/governance/rules/core/035-tasks.md +13 -0
- package/governance/rules/core/040-performance.md +20 -0
- package/governance/rules/core/045-memory.md +12 -0
- package/governance/rules/core/050-logging.md +20 -0
- package/governance/rules/core/055-scratch.md +9 -0
- package/governance/rules/core/060-naming.md +19 -0
- package/governance/rules/core/065-spelling.md +19 -0
- package/governance/rules/core/070-planning.md +18 -0
- package/governance/rules/core/075-dependencies.md +25 -0
- package/governance/rules/core/080-config-comments.md +22 -0
- package/governance/rules/core/085-worktrees.md +17 -0
- package/governance/rules/core/087-git.md +11 -0
- package/governance/rules/core/090-code-comments.md +39 -0
- package/governance/rules/framework/200-react.md +51 -0
- package/governance/rules/framework/210-astro.md +41 -0
- package/governance/rules/framework/220-fastapi.md +43 -0
- package/governance/rules/framework/230-nextjs.md +48 -0
- package/governance/rules/framework/250-tailwind.md +32 -0
- package/governance/rules/framework/260-shadcn.md +34 -0
- package/governance/rules/lang/100-typescript.md +40 -0
- package/governance/rules/lang/110-python.md +42 -0
- package/governance/rules/lang/120-bash.md +19 -0
- package/governance/rules/lib/300-testing-ts.md +39 -0
- package/governance/rules/lib/305-e2e-reliability.md +34 -0
- package/governance/rules/lib/306-test-scope.md +25 -0
- package/governance/rules/lib/310-zod.md +25 -0
- package/governance/rules/lib/320-tanstack-query.md +32 -0
- package/governance/rules/lib/330-testing-py.md +44 -0
- package/governance/rules/lib/340-pydantic.md +38 -0
- package/governance/rules/lib/350-security-web.md +32 -0
- package/governance/rules/lib/360-security-server.md +39 -0
- package/governance/rules/lib/370-database.md +35 -0
- package/governance/rules/snippets/505-at-references.md +9 -0
- package/governance/rules/ui/400-ui.md +36 -0
- package/governance/rules/ui/410-a11y.md +48 -0
- package/governance/rules/ui/420-forms.md +36 -0
- package/governance/rules/ui/430-ux-completeness.md +65 -0
- package/governance/rules/ui/440-surface-capture.md +34 -0
- package/governance/rules/ui/450-link-behavior.md +19 -0
- package/governance/stacks/astro.toml +2 -0
- package/governance/stacks/base.toml +8 -0
- package/governance/stacks/node-server.toml +2 -0
- package/governance/stacks/node.toml +2 -0
- package/governance/stacks/python-fastapi.toml +2 -0
- package/governance/stacks/python.toml +2 -0
- package/governance/stacks/react.toml +2 -0
- package/package.json +69 -0
- package/scripts/config.sh +11 -0
- package/scripts/core/bootstrap.sh +81 -0
- package/scripts/core/check-color-source.sh +41 -0
- package/scripts/core/check-ignore-parity.sh +162 -0
- package/scripts/core/check-plugin-boundary.sh +45 -0
- package/scripts/core/check-seed-independence.sh +59 -0
- package/scripts/core/check-skill-paths.sh +24 -0
- package/scripts/core/clean.sh +36 -0
- package/scripts/core/install-check.sh +101 -0
- package/scripts/core/list-seed-roots.sh +18 -0
- package/scripts/core/regen-claude-copies.sh +10 -0
- package/scripts/core/regen-hero.sh +217 -0
- package/scripts/core/regen-indexes.sh +10 -0
- package/scripts/core/regen-tooling-paths.sh +61 -0
- package/scripts/core/repair-bare-flag.sh +19 -0
- package/scripts/core/snapshot.sh +134 -0
- package/scripts/core/update.sh +35 -0
- package/scripts/docs/list.sh +165 -0
- package/scripts/lib/frontmatter.sh +30 -0
- package/scripts/lib/gov.sh +14 -0
- package/scripts/lib/sandbox-fixtures.sh +191 -0
- package/scripts/lib/sandbox-git.sh +125 -0
- package/scripts/lib/sandbox-path.sh +206 -0
- package/scripts/lib/tooling.sh +35 -0
- package/scripts/lib/ui.sh +266 -0
- package/scripts/lib/worktree.sh +20 -0
- package/scripts/manage-sandbox.sh +466 -0
- package/scripts/snippets/create.sh +156 -0
- package/scripts/standards/list.sh +115 -0
- package/scripts/tooling/create.sh +109 -0
- package/scripts/tooling/verify.sh +179 -0
- package/snippets/align.md +12 -0
- package/snippets/claude/decision-memo.md +39 -0
- package/snippets/claude/feature-recap.md +19 -0
- package/snippets/claude/figma-steps.md +24 -0
- package/snippets/compact-summary.md +5 -0
- package/snippets/decision-help.md +6 -0
- package/snippets/meta-prompt.md +14 -0
- package/snippets/research-prompt.md +7 -0
- package/snippets/session-notes.md +11 -0
- package/snippets/snippets.toml +5 -0
- package/snippets/step-by-step.md +10 -0
- package/snippets/web-research.md +21 -0
- package/src/audits/baseline.ts +201 -0
- package/src/audits/catalog.ts +876 -0
- package/src/audits/run.ts +204 -0
- package/src/autoship/classify.ts +75 -0
- package/src/autoship/paths.ts +51 -0
- package/src/binary.ts +16 -0
- package/src/browser/engine.ts +40 -0
- package/src/census/count.ts +113 -0
- package/src/claude/cases/all.ts +24 -0
- package/src/claude/cases/authoring.ts +53 -0
- package/src/claude/cases/claude-workflow.ts +158 -0
- package/src/claude/cases/git.ts +44 -0
- package/src/claude/cases/misc.ts +27 -0
- package/src/claude/cases/setup.ts +94 -0
- package/src/claude/gitignore.ts +51 -0
- package/src/claude/routing.ts +283 -0
- package/src/claude/seeds-list.ts +47 -0
- package/src/claude/seeds.ts +150 -0
- package/src/claude/settings.ts +151 -0
- package/src/claude/skills-audit.ts +228 -0
- package/src/claude/skills-drift.ts +156 -0
- package/src/claude/skills-list.ts +99 -0
- package/src/claude/skills-rank.ts +320 -0
- package/src/claude/skills-reach.ts +227 -0
- package/src/cli-run.ts +43 -0
- package/src/cli.ts +200 -0
- package/src/commands/audits.ts +350 -0
- package/src/commands/autoship.ts +129 -0
- package/src/commands/capture.ts +133 -0
- package/src/commands/census.ts +105 -0
- package/src/commands/claude.ts +1286 -0
- package/src/commands/comments.ts +240 -0
- package/src/commands/context.ts +857 -0
- package/src/commands/demo.ts +389 -0
- package/src/commands/deps.ts +173 -0
- package/src/commands/design.ts +36 -0
- package/src/commands/docs.ts +60 -0
- package/src/commands/feedback-format.ts +23 -0
- package/src/commands/feedback.ts +112 -0
- package/src/commands/gate.ts +189 -0
- package/src/commands/gov.ts +1265 -0
- package/src/commands/indexes.ts +184 -0
- package/src/commands/init.ts +113 -0
- package/src/commands/intake.ts +406 -0
- package/src/commands/inventory.ts +256 -0
- package/src/commands/labels.ts +361 -0
- package/src/commands/markdown.ts +544 -0
- package/src/commands/migrate.ts +175 -0
- package/src/commands/pass-through.ts +39 -0
- package/src/commands/pr.ts +411 -0
- package/src/commands/records.ts +728 -0
- package/src/commands/sandbox.ts +468 -0
- package/src/commands/secrets.ts +132 -0
- package/src/commands/serve.ts +159 -0
- package/src/commands/sessions.ts +408 -0
- package/src/commands/slides.ts +126 -0
- package/src/commands/snippets.ts +84 -0
- package/src/commands/standards.ts +247 -0
- package/src/commands/sync.ts +428 -0
- package/src/commands/targets.ts +319 -0
- package/src/commands/tasks.ts +743 -0
- package/src/commands/teach.ts +786 -0
- package/src/commands/tooling.ts +573 -0
- package/src/commands/transcripts.ts +44 -0
- package/src/commands/upgrade.ts +231 -0
- package/src/commands/wiki.ts +100 -0
- package/src/commands/worktrees.ts +191 -0
- package/src/comments/scan.ts +338 -0
- package/src/comments/trend.ts +207 -0
- package/src/comments/vocabulary.ts +85 -0
- package/src/context/architecture.ts +364 -0
- package/src/context/audit.ts +790 -0
- package/src/context/citations.ts +196 -0
- package/src/context/folders.ts +186 -0
- package/src/context/gate.ts +57 -0
- package/src/context/index-drift.ts +64 -0
- package/src/context/narration.ts +99 -0
- package/src/copy.ts +30 -0
- package/src/counts/catalogs.ts +96 -0
- package/src/counts/numbers.ts +79 -0
- package/src/counts/scan.ts +314 -0
- package/src/demo/beats.ts +135 -0
- package/src/demo/compile.ts +326 -0
- package/src/demo/container.ts +63 -0
- package/src/demo/cursors.ts +55 -0
- package/src/demo/drive.ts +357 -0
- package/src/demo/pointer.ts +178 -0
- package/src/demo/theme.ts +112 -0
- package/src/deps/audit.ts +153 -0
- package/src/design/parse.ts +116 -0
- package/src/design/render.ts +249 -0
- package/src/docs/read.ts +77 -0
- package/src/exec.ts +16 -0
- package/src/exempt-marker.ts +43 -0
- package/src/frontmatter.ts +13 -0
- package/src/gate/measures.ts +682 -0
- package/src/gate/sequencer.ts +386 -0
- package/src/gate/stages.ts +412 -0
- package/src/git-env.ts +36 -0
- package/src/git-files.ts +105 -0
- package/src/git-ignore.ts +46 -0
- package/src/github-format.ts +13 -0
- package/src/github.ts +24 -0
- package/src/gov/adapter.ts +103 -0
- package/src/gov/citations.ts +514 -0
- package/src/gov/consumed.ts +129 -0
- package/src/gov/install.ts +132 -0
- package/src/gov/list.ts +106 -0
- package/src/gov/payload.ts +39 -0
- package/src/gov/restated.ts +814 -0
- package/src/gov/stacks.ts +205 -0
- package/src/gov/superseded.ts +415 -0
- package/src/gov/test-order.ts +407 -0
- package/src/indexes/frontmatter.ts +46 -0
- package/src/indexes/regen.ts +84 -0
- package/src/indexes/render.ts +201 -0
- package/src/indexes/walk.ts +83 -0
- package/src/init/flags.ts +60 -0
- package/src/init/plan.ts +114 -0
- package/src/init/run.ts +46 -0
- package/src/init/steps.ts +77 -0
- package/src/intake/folder.ts +320 -0
- package/src/intake/items.ts +174 -0
- package/src/inventory/config.ts +117 -0
- package/src/inventory/group.ts +76 -0
- package/src/inventory/subjects.ts +114 -0
- package/src/inventory/walk.ts +129 -0
- package/src/labels/audit.ts +82 -0
- package/src/labels/coverage.ts +79 -0
- package/src/labels/map.ts +101 -0
- package/src/labels/phase.ts +95 -0
- package/src/markdown/bans.ts +94 -0
- package/src/markdown/files.ts +102 -0
- package/src/markdown/gate.ts +28 -0
- package/src/markdown/scan.ts +295 -0
- package/src/markdown/structure.ts +730 -0
- package/src/migrate/apply.ts +115 -0
- package/src/migrate/plan.ts +103 -0
- package/src/migrate/rename.ts +183 -0
- package/src/pr/bijection.ts +145 -0
- package/src/pr/paths.ts +335 -0
- package/src/process/harness.ts +167 -0
- package/src/project-root.ts +19 -0
- package/src/records/backup.ts +455 -0
- package/src/records/migrate.ts +78 -0
- package/src/records/size.ts +260 -0
- package/src/records/validate.ts +1162 -0
- package/src/sandbox/census.ts +228 -0
- package/src/sandbox/coverage.ts +115 -0
- package/src/sandbox/expect.ts +629 -0
- package/src/sandbox/tree.ts +47 -0
- package/src/secrets/marker.ts +30 -0
- package/src/secrets/patterns.ts +142 -0
- package/src/secrets/scan.ts +123 -0
- package/src/secrets/shipped.ts +111 -0
- package/src/seed-marker.ts +74 -0
- package/src/serve/static.ts +322 -0
- package/src/sessions/claim.ts +85 -0
- package/src/sessions/live.ts +79 -0
- package/src/sessions/registry.ts +137 -0
- package/src/sessions/resolve.ts +333 -0
- package/src/slides/layouts.ts +391 -0
- package/src/slides/open.ts +18 -0
- package/src/slides/parse.ts +84 -0
- package/src/slides/render.ts +88 -0
- package/src/slides/styles.ts +44 -0
- package/src/snippets/categories.ts +66 -0
- package/src/snippets/list.ts +32 -0
- package/src/snippets/presets.ts +50 -0
- package/src/standards/audit.ts +132 -0
- package/src/standards/read.ts +100 -0
- package/src/sync/check.ts +692 -0
- package/src/sync/engine.ts +576 -0
- package/src/sync/git.ts +225 -0
- package/src/sync/history.ts +123 -0
- package/src/sync/layout.ts +140 -0
- package/src/sync/reverse.ts +268 -0
- package/src/sync/seeds-report.ts +126 -0
- package/src/sync/stamp.ts +358 -0
- package/src/sync/target.ts +70 -0
- package/src/sync/workflow.ts +200 -0
- package/src/target.ts +43 -0
- package/src/targets/pulls.ts +250 -0
- package/src/targets/registry.ts +203 -0
- package/src/targets/resolve.ts +145 -0
- package/src/targets/sweep.ts +246 -0
- package/src/tasks/archive.ts +506 -0
- package/src/tasks/record.ts +311 -0
- package/src/tasks/trunk.ts +89 -0
- package/src/tasks/validate.ts +1001 -0
- package/src/teach/lesson.ts +180 -0
- package/src/teach/workspace.ts +842 -0
- package/src/tooling/gitignore.ts +122 -0
- package/src/tooling/inject.ts +193 -0
- package/src/tooling/list.ts +39 -0
- package/src/tooling/manifest.ts +176 -0
- package/src/tooling/package.ts +166 -0
- package/src/tooling/read.ts +65 -0
- package/src/tooling/scan.ts +147 -0
- package/src/tooling/stamp.ts +44 -0
- package/src/transcripts/fetch.ts +156 -0
- package/src/transcripts/metadata.ts +54 -0
- package/src/transcripts/vtt.ts +114 -0
- package/src/ui.ts +266 -0
- package/src/version/compare.ts +53 -0
- package/src/version/installed.ts +40 -0
- package/src/version/manager.ts +67 -0
- package/src/version/skew.ts +192 -0
- package/src/wiki/init.ts +85 -0
- package/src/worktree.ts +143 -0
- package/src/worktrees/reclaim.ts +306 -0
- package/standards/architecture.md +72 -0
- package/standards/branch.md +59 -0
- package/standards/commit.md +72 -0
- package/standards/context.md +151 -0
- package/standards/design.md +93 -0
- package/standards/diagrams.md +152 -0
- package/standards/glossary.md +75 -0
- package/standards/groundwork.md +211 -0
- package/standards/index.md +36 -0
- package/standards/intake.md +192 -0
- package/standards/issue.md +94 -0
- package/standards/markdown.md +137 -0
- package/standards/memory.md +144 -0
- package/standards/plan.md +172 -0
- package/standards/pr.md +139 -0
- package/standards/publish.md +51 -0
- package/standards/readme.md +208 -0
- package/standards/requirements.md +70 -0
- package/standards/rule.md +118 -0
- package/standards/session.md +109 -0
- package/standards/skill.md +300 -0
- package/standards/slug.md +39 -0
- package/standards/snippets.md +76 -0
- package/standards/standard.md +170 -0
- package/standards/tasks.md +254 -0
- package/standards/teach.md +153 -0
- package/standards/versioning.md +71 -0
- package/standards/wireframes.md +113 -0
- package/tooling/astro/configs/astro.config.mjs +31 -0
- package/tooling/astro/configs/eslint.config.js +79 -0
- package/tooling/astro/configs/playwright.config.ts +26 -0
- package/tooling/astro/configs/tsconfig.json +12 -0
- package/tooling/astro/configs/vitest.config.ts +22 -0
- package/tooling/astro/manifest.toml +34 -0
- package/tooling/astro/reference.md +60 -0
- package/tooling/base/configs/.editorconfig +5 -0
- package/tooling/base/configs/.github/pull_request_template.md +18 -0
- package/tooling/base/configs/.github/workflows/verify.yml +35 -0
- package/tooling/base/configs/.husky/commit-msg +1 -0
- package/tooling/base/configs/.husky/post-merge +61 -0
- package/tooling/base/configs/.husky/post-rewrite +21 -0
- package/tooling/base/configs/.husky/pre-commit +1 -0
- package/tooling/base/configs/.husky/pre-push +1 -0
- package/tooling/base/configs/.prettierrc +12 -0
- package/tooling/base/configs/.shellcheckrc +1 -0
- package/tooling/base/configs/.vscode/extensions.json +9 -0
- package/tooling/base/configs/.vscode/settings.json +3 -0
- package/tooling/base/configs/commitlint.config.js +11 -0
- package/tooling/base/configs/scripts/verify.sh +64 -0
- package/tooling/base/manifest.toml +30 -0
- package/tooling/base/reference.md +98 -0
- package/tooling/base/seeds/.claude/context/ci.md +33 -0
- package/tooling/base/seeds/.claude/context/development.md +37 -0
- package/tooling/base/seeds/.claude/context/index.md +11 -0
- package/tooling/base/seeds/.cspell/project-terms.txt +0 -0
- package/tooling/base/seeds/.cspell/tech-stack.txt +19 -0
- package/tooling/base/seeds/.lintstagedrc +8 -0
- package/tooling/base/seeds/.prettierignore +0 -0
- package/tooling/base/seeds/cspell.json +20 -0
- package/tooling/claude/manifest.toml +14 -0
- package/tooling/claude/reference.md +79 -0
- package/tooling/claude/seeds/.claude/ARCHITECTURE.md +13 -0
- package/tooling/claude/seeds/.claude/DESIGN.md +62 -0
- package/tooling/claude/seeds/.claude/REQUIREMENTS.md +18 -0
- package/tooling/claude/seeds/.claude/diagrams/index.md +8 -0
- package/tooling/claude/seeds/.claude/hooks/index-reminder.sh +50 -0
- package/tooling/claude/seeds/.claude/hooks/memory-index.sh +68 -0
- package/tooling/claude/seeds/.claude/hooks/path-form.sh +57 -0
- package/tooling/claude/seeds/.claude/hooks/scratch-guard.sh +52 -0
- package/tooling/claude/seeds/.claude/hooks/standards-audit.sh +86 -0
- package/tooling/claude/seeds/.claude/hooks/tasks-index.sh +71 -0
- package/tooling/claude/seeds/.claude/memory/index.md +8 -0
- package/tooling/claude/seeds/.claude/settings.json +47 -0
- package/tooling/claude/seeds/.claude/tasks/index.md +8 -0
- package/tooling/claude/seeds/.claude/wireframes/index.md +8 -0
- package/tooling/claude/seeds/CLAUDE.md +29 -0
- package/tooling/claude/user/settings.template.json +10 -0
- package/tooling/claude/user/statusline-command.sh +53 -0
- package/tooling/python/configs/.coveragerc +14 -0
- package/tooling/python/configs/.python-version +1 -0
- package/tooling/python/configs/mypy.ini +6 -0
- package/tooling/python/configs/pytest.ini +4 -0
- package/tooling/python/configs/ruff.toml +15 -0
- package/tooling/python/configs/scripts/verify.sh +77 -0
- package/tooling/python/manifest.toml +16 -0
- package/tooling/python/reference.md +66 -0
- package/tooling/python/seeds/.cspell/tech-stack.txt +19 -0
- package/tooling/python/seeds/tests/test_smoke.py +2 -0
- package/tooling/vite-react/configs/playwright.config.ts +26 -0
- package/tooling/vite-react/configs/tsconfig.json +35 -0
- package/tooling/vite-react/configs/vite.config.ts +24 -0
- package/tooling/vite-react/configs/vitest.config.ts +26 -0
- package/tooling/vite-react/manifest.toml +23 -0
- package/tooling/vite-react/reference.md +55 -0
- package/tooling/vite-react/seeds/.cspell/project-terms.txt +1 -0
- package/tooling/vite-react/seeds/.cspell/tech-stack.txt +1 -0
- package/tooling/web/configs/.github/workflows/verify.yml +134 -0
- package/tooling/web/configs/.vscode/extensions.json +13 -0
- package/tooling/web/configs/.vscode/settings.json +10 -0
- package/tooling/web/configs/e2e/home.spec.ts +6 -0
- package/tooling/web/configs/e2e/screenshot.ts +53 -0
- package/tooling/web/configs/eslint.config.js +82 -0
- package/tooling/web/configs/scripts/screenshot.sh +28 -0
- package/tooling/web/configs/scripts/verify.sh +80 -0
- package/tooling/web/configs/scripts/worktree-port.sh +74 -0
- package/tooling/web/configs/src/test/setup.ts +8 -0
- package/tooling/web/manifest.toml +58 -0
- package/tooling/web/reference.md +115 -0
- package/tooling/web/seeds/.cspell/tech-stack.txt +18 -0
- package/tsconfig.json +14 -0
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
import { existsSync, readFileSync, readdirSync } from 'node:fs'
|
|
2
|
+
import { join } from 'node:path'
|
|
3
|
+
import { collectCoverage, type CoverageReport } from '@/sandbox/coverage'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Holds the exemption declarations, beside the scenario categories rather than
|
|
7
|
+
* inside one. `listScenarios` in `coverage.ts` walks directories only, so a file
|
|
8
|
+
* at that level joins no category and never reads as a scenario.
|
|
9
|
+
*/
|
|
10
|
+
const EXEMPT_FILE = 'exempt.toml'
|
|
11
|
+
|
|
12
|
+
export type SkillVerdict = 'asserted' | 'should-be-asserted' | 'exempt'
|
|
13
|
+
|
|
14
|
+
export interface SkillCensusEntry {
|
|
15
|
+
readonly skill: string
|
|
16
|
+
readonly verdict: SkillVerdict
|
|
17
|
+
/**
|
|
18
|
+
* Every `<category>:<command>` pairing to this skill, empty when none does.
|
|
19
|
+
* Plural because the mapping is many-to-one: two scenarios can drive one
|
|
20
|
+
* skill, and naming only the first would credit its arms to the wrong file.
|
|
21
|
+
*/
|
|
22
|
+
readonly scenarios: readonly string[]
|
|
23
|
+
/**
|
|
24
|
+
* Each armed arm as `<category>:<command>/<arm>`. Qualified rather than bare,
|
|
25
|
+
* because a skill two scenarios drive can hold two arms of the same name and
|
|
26
|
+
* a bare list renders them as one label twice. Deduplicating instead would
|
|
27
|
+
* read as one arm where two assert, which understates in the one direction
|
|
28
|
+
* this report exists to keep honest.
|
|
29
|
+
*/
|
|
30
|
+
readonly armed: readonly string[]
|
|
31
|
+
/** Why no arm asserts this skill. Present only on `exempt`. */
|
|
32
|
+
readonly reason?: string
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export interface CensusReport {
|
|
36
|
+
readonly skills: readonly SkillCensusEntry[]
|
|
37
|
+
readonly totalSkills: number
|
|
38
|
+
readonly asserted: number
|
|
39
|
+
readonly shouldBeAsserted: number
|
|
40
|
+
readonly exempt: number
|
|
41
|
+
/** Exemptions naming a skill the tree does not carry. */
|
|
42
|
+
readonly staleExemptions: readonly string[]
|
|
43
|
+
/**
|
|
44
|
+
* Exemptions on a skill an arm now asserts. The claim is wrong in the one
|
|
45
|
+
* direction a verdict decays, and the entry outranks nothing, so dropping it
|
|
46
|
+
* silently leaves committed data nobody is told to delete.
|
|
47
|
+
*/
|
|
48
|
+
readonly supersededExemptions: readonly string[]
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function directories(path: string): string[] {
|
|
52
|
+
if (!existsSync(path)) return []
|
|
53
|
+
|
|
54
|
+
return readdirSync(path, { withFileTypes: true })
|
|
55
|
+
.filter((entry) => entry.isDirectory())
|
|
56
|
+
.map((entry) => entry.name)
|
|
57
|
+
.sort()
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Every skill the plugin ships, which is the census denominator. Reads the
|
|
62
|
+
* authoring root rather than `.claude/skills/`, since the latter holds
|
|
63
|
+
* toolkit-internal skills that reach no target and would inflate the count.
|
|
64
|
+
*/
|
|
65
|
+
export function listSkills(root: string): string[] {
|
|
66
|
+
return directories(join(root, 'claude', 'skills'))
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Maps a scenario to the skill it drives, trying two spellings in order.
|
|
71
|
+
*
|
|
72
|
+
* `<category>-<command>` is the rule `.claude/context/sandbox/coverage.md` states, and it
|
|
73
|
+
* alone pairs 29 of 54 skills. The bare `<command>` fallback is what reaches the
|
|
74
|
+
* rest: `claude/setup-init.sh` drives the `setup-init` skill, not a
|
|
75
|
+
* `claude-setup-init` that does not exist. Stating one spelling and shipping two
|
|
76
|
+
* is what let the audit report a paired skill as unpaired.
|
|
77
|
+
*
|
|
78
|
+
* Returns undefined for a scenario driving no skill at all, which is every
|
|
79
|
+
* `infra/` and `tooling/` scenario. Those exercise a CLI domain rather than a
|
|
80
|
+
* skill and belong to the scenario count, not to this one.
|
|
81
|
+
*/
|
|
82
|
+
export function skillForScenario(
|
|
83
|
+
category: string,
|
|
84
|
+
command: string,
|
|
85
|
+
skills: ReadonlySet<string>,
|
|
86
|
+
): string | undefined {
|
|
87
|
+
const prefixed = `${category}-${command}`
|
|
88
|
+
if (skills.has(prefixed)) return prefixed
|
|
89
|
+
if (skills.has(command)) return command
|
|
90
|
+
|
|
91
|
+
return undefined
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Reads the exemption declarations, keyed by skill with a `reason` each.
|
|
96
|
+
*
|
|
97
|
+
* The reason cannot live in the arm's `manual` array, which is where `#723` put
|
|
98
|
+
* prose a checker could not assert. `resolveVerdict` fails any declaration
|
|
99
|
+
* carrying zero mechanical assertions, so an `expect.toml` holding only an
|
|
100
|
+
* exempt reason goes red at the moment it is written. An exempt skill has no
|
|
101
|
+
* assertion to pair the prose with, which is what makes it exempt, so the two
|
|
102
|
+
* cases cannot share a home.
|
|
103
|
+
*
|
|
104
|
+
* Throws on a malformed file and on a table carrying no usable `reason`, rather
|
|
105
|
+
* than reporting a smaller set. Both losses are invisible downstream: the skill
|
|
106
|
+
* reclassifies to should-be-asserted and rejoins a work queue someone already
|
|
107
|
+
* ruled it out of, with nothing naming the entry that stopped counting. This is
|
|
108
|
+
* the stray-key rule `contentArray` applies in `expect.ts` for the same reason,
|
|
109
|
+
* where the declaration is well-formed and silently lost a key it appears to
|
|
110
|
+
* carry. `runCoverage` catches both and frames them.
|
|
111
|
+
*/
|
|
112
|
+
export function parseExemptions(source: string): Map<string, string> {
|
|
113
|
+
const parsed = Bun.TOML.parse(source) as Record<string, unknown>
|
|
114
|
+
const exemptions = new Map<string, string>()
|
|
115
|
+
|
|
116
|
+
for (const [skill, value] of Object.entries(parsed)) {
|
|
117
|
+
if (typeof value !== 'object' || value === null) {
|
|
118
|
+
throw new Error(
|
|
119
|
+
`exemption ${skill} is not a table. Write [${skill}] with a reason below it.`,
|
|
120
|
+
)
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const reason = (value as Record<string, unknown>).reason
|
|
124
|
+
if (typeof reason !== 'string' || reason === '') {
|
|
125
|
+
throw new Error(
|
|
126
|
+
`exemption ${skill} declares no reason. An exemption without one cannot be checked or overturned.`,
|
|
127
|
+
)
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
exemptions.set(skill, reason)
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
return exemptions
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function readExemptions(root: string): Map<string, string> {
|
|
137
|
+
const path = join(root, 'scripts', 'sandbox', EXEMPT_FILE)
|
|
138
|
+
if (!existsSync(path)) return new Map()
|
|
139
|
+
|
|
140
|
+
return parseExemptions(readFileSync(path, 'utf8'))
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Gives every shipped skill an asserted, should-be-asserted, or exempt verdict
|
|
145
|
+
* against declared expectations rather than against a scenario existing.
|
|
146
|
+
*
|
|
147
|
+
* A paired scenario is not an asserted skill. A scenario with no `expect.toml`
|
|
148
|
+
* provisions a state and prints a human-readable `Expect:` line, so a run over
|
|
149
|
+
* it exits zero having proved nothing. Counting pairs would report coverage the
|
|
150
|
+
* suite does not have, which is the measure this report exists to replace.
|
|
151
|
+
*
|
|
152
|
+
* An armed arm outranks an exemption. A skill listed exempt that acquired an arm
|
|
153
|
+
* is asserted in fact, and reporting the stale claim instead would hide the one
|
|
154
|
+
* direction the verdict decays in.
|
|
155
|
+
*/
|
|
156
|
+
export function collectCensus(
|
|
157
|
+
root: string,
|
|
158
|
+
coverage: CoverageReport = collectCoverage(root),
|
|
159
|
+
): CensusReport {
|
|
160
|
+
const skills = listSkills(root)
|
|
161
|
+
const known = new Set(skills)
|
|
162
|
+
const exemptions = readExemptions(root)
|
|
163
|
+
|
|
164
|
+
const pairings = new Map<string, { scenarios: string[]; armed: string[] }>()
|
|
165
|
+
for (const scenario of coverage.scenarios) {
|
|
166
|
+
const skill = skillForScenario(scenario.category, scenario.command, known)
|
|
167
|
+
if (skill === undefined) continue
|
|
168
|
+
|
|
169
|
+
// Accumulate rather than assign. Dropping a second scenario would report a
|
|
170
|
+
// skill unarmed while an arm under the other spelling asserts it.
|
|
171
|
+
const pair = `${scenario.category}:${scenario.command}`
|
|
172
|
+
const existing = pairings.get(skill) ?? { scenarios: [], armed: [] }
|
|
173
|
+
existing.scenarios.push(pair)
|
|
174
|
+
existing.armed.push(...scenario.armed.map((arm) => `${pair}/${arm}`))
|
|
175
|
+
pairings.set(skill, existing)
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
const entries = skills.map((skill): SkillCensusEntry => {
|
|
179
|
+
const pairing = pairings.get(skill)
|
|
180
|
+
const scenarios = pairing?.scenarios ?? []
|
|
181
|
+
const armed = pairing?.armed ?? []
|
|
182
|
+
const reason = exemptions.get(skill)
|
|
183
|
+
|
|
184
|
+
if (armed.length > 0) {
|
|
185
|
+
return { skill, verdict: 'asserted', scenarios, armed }
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
if (reason !== undefined) {
|
|
189
|
+
return { skill, verdict: 'exempt', scenarios, armed, reason }
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
return { skill, verdict: 'should-be-asserted', scenarios, armed }
|
|
193
|
+
})
|
|
194
|
+
|
|
195
|
+
// An exemption outranked by an arm is as wrong as one naming no skill, and it
|
|
196
|
+
// is the case the armed-wins rule creates rather than one the tree arrives
|
|
197
|
+
// with. Reading `entries` rather than recomputing keeps the two in step, so a
|
|
198
|
+
// change to the precedence cannot leave the report contradicting the verdict.
|
|
199
|
+
const assertedSkills = new Set(
|
|
200
|
+
entries.filter((e) => e.verdict === 'asserted').map((e) => e.skill),
|
|
201
|
+
)
|
|
202
|
+
|
|
203
|
+
return {
|
|
204
|
+
skills: entries,
|
|
205
|
+
totalSkills: entries.length,
|
|
206
|
+
asserted: assertedSkills.size,
|
|
207
|
+
shouldBeAsserted: entries.filter((e) => e.verdict === 'should-be-asserted')
|
|
208
|
+
.length,
|
|
209
|
+
exempt: entries.filter((e) => e.verdict === 'exempt').length,
|
|
210
|
+
staleExemptions: [...exemptions.keys()]
|
|
211
|
+
.filter((skill) => !known.has(skill))
|
|
212
|
+
.sort(),
|
|
213
|
+
supersededExemptions: [...exemptions.keys()]
|
|
214
|
+
.filter((skill) => assertedSkills.has(skill))
|
|
215
|
+
.sort(),
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Whole percent, floored, over skills rather than scenarios. Floored for the
|
|
221
|
+
* reason `coveragePercent` is: the number exists to look worse than a wall of
|
|
222
|
+
* green does.
|
|
223
|
+
*/
|
|
224
|
+
export function assertedPercent(report: CensusReport): number {
|
|
225
|
+
if (report.totalSkills === 0) return 0
|
|
226
|
+
|
|
227
|
+
return Math.floor((report.asserted / report.totalSkills) * 100)
|
|
228
|
+
}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { existsSync, readdirSync } from 'node:fs'
|
|
2
|
+
import { join } from 'node:path'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* The arm a scenario declares when it carries no named arm. `expectFilePath`
|
|
6
|
+
* joins an empty arm away, so the declaration lands at the command root and has
|
|
7
|
+
* no name to print.
|
|
8
|
+
*/
|
|
9
|
+
export const DEFAULT_ARM = '(default)'
|
|
10
|
+
|
|
11
|
+
/** Holds fixture content rather than scenarios. Twin of the filter in `sandbox.ts`. */
|
|
12
|
+
const FIXTURES_DIR = 'fixtures'
|
|
13
|
+
|
|
14
|
+
export interface ScenarioCoverage {
|
|
15
|
+
readonly category: string
|
|
16
|
+
readonly command: string
|
|
17
|
+
readonly armed: readonly string[]
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface CoverageReport {
|
|
21
|
+
readonly scenarios: readonly ScenarioCoverage[]
|
|
22
|
+
readonly totalScenarios: number
|
|
23
|
+
readonly armedScenarios: number
|
|
24
|
+
readonly armedArms: number
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function directories(path: string): string[] {
|
|
28
|
+
if (!existsSync(path)) return []
|
|
29
|
+
|
|
30
|
+
return readdirSync(path, { withFileTypes: true })
|
|
31
|
+
.filter((entry) => entry.isDirectory())
|
|
32
|
+
.map((entry) => entry.name)
|
|
33
|
+
.sort()
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Enumerates from the scenario scripts rather than from the fixture tree. A
|
|
38
|
+
* scenario with no fixtures has no directory to find, and counting only what
|
|
39
|
+
* fixtures exist would hide exactly the arms this report exists to surface.
|
|
40
|
+
*/
|
|
41
|
+
function listScenarios(sandboxDir: string): ScenarioCoverage[] {
|
|
42
|
+
const scenarios: ScenarioCoverage[] = []
|
|
43
|
+
|
|
44
|
+
for (const category of directories(sandboxDir)) {
|
|
45
|
+
if (category === FIXTURES_DIR) continue
|
|
46
|
+
|
|
47
|
+
const commands = readdirSync(join(sandboxDir, category), {
|
|
48
|
+
withFileTypes: true,
|
|
49
|
+
})
|
|
50
|
+
.filter((entry) => entry.isFile() && entry.name.endsWith('.sh'))
|
|
51
|
+
.map((entry) => entry.name.replace(/\.sh$/, ''))
|
|
52
|
+
.sort()
|
|
53
|
+
|
|
54
|
+
for (const command of commands) {
|
|
55
|
+
scenarios.push({ category, command, armed: [] })
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return scenarios
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Names every arm of a scenario carrying an `expect.toml`. A declaration at the
|
|
64
|
+
* command root belongs to the unnamed arm and reports under `DEFAULT_ARM`, since
|
|
65
|
+
* an empty string in a report reads as a bug rather than as the default.
|
|
66
|
+
*/
|
|
67
|
+
function armsFor(
|
|
68
|
+
fixturesDir: string,
|
|
69
|
+
category: string,
|
|
70
|
+
command: string,
|
|
71
|
+
): string[] {
|
|
72
|
+
const commandDir = join(fixturesDir, category, command)
|
|
73
|
+
if (!existsSync(commandDir)) return []
|
|
74
|
+
|
|
75
|
+
const armed: string[] = []
|
|
76
|
+
if (existsSync(join(commandDir, 'expect.toml'))) armed.push(DEFAULT_ARM)
|
|
77
|
+
|
|
78
|
+
for (const arm of directories(commandDir)) {
|
|
79
|
+
if (existsSync(join(commandDir, arm, 'expect.toml'))) armed.push(arm)
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return armed
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Reports which scenarios declare expectations and which only provision a state.
|
|
87
|
+
* The undeclared ones exit zero today, so the count is the only thing separating
|
|
88
|
+
* a suite that proves something from one that runs.
|
|
89
|
+
*/
|
|
90
|
+
export function collectCoverage(root: string): CoverageReport {
|
|
91
|
+
const sandboxDir = join(root, 'scripts', 'sandbox')
|
|
92
|
+
const fixturesDir = join(sandboxDir, FIXTURES_DIR)
|
|
93
|
+
|
|
94
|
+
const scenarios = listScenarios(sandboxDir).map((scenario) => ({
|
|
95
|
+
...scenario,
|
|
96
|
+
armed: armsFor(fixturesDir, scenario.category, scenario.command),
|
|
97
|
+
}))
|
|
98
|
+
|
|
99
|
+
return {
|
|
100
|
+
scenarios,
|
|
101
|
+
totalScenarios: scenarios.length,
|
|
102
|
+
armedScenarios: scenarios.filter((s) => s.armed.length > 0).length,
|
|
103
|
+
armedArms: scenarios.reduce((total, s) => total + s.armed.length, 0),
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Whole percent, floored. A rollout at 13 percent should not round to 13 from
|
|
109
|
+
* above, since the number exists to look worse than a wall of green does.
|
|
110
|
+
*/
|
|
111
|
+
export function coveragePercent(report: CoverageReport): number {
|
|
112
|
+
if (report.totalScenarios === 0) return 0
|
|
113
|
+
|
|
114
|
+
return Math.floor((report.armedScenarios / report.totalScenarios) * 100)
|
|
115
|
+
}
|