@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,364 @@
|
|
|
1
|
+
import { access, readFile } from 'node:fs/promises'
|
|
2
|
+
import { join } from 'node:path'
|
|
3
|
+
import { AUDITS } from '@/audits/catalog'
|
|
4
|
+
import { bodyLines } from '@/markdown/scan'
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* The record this measures, relative to the project root.
|
|
8
|
+
*
|
|
9
|
+
* One fixed path rather than a folder walk, because the standard governing it
|
|
10
|
+
* names one document, and the length rule this measures is stated by whichever
|
|
11
|
+
* record sits there rather than by the standard or by this file.
|
|
12
|
+
*/
|
|
13
|
+
export const RECORD_REL = '.claude/ARCHITECTURE.md'
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* The line allowances a record states for itself, absent when it states none.
|
|
17
|
+
*
|
|
18
|
+
* No standard sets a length rule for this document, so the numbers belong to
|
|
19
|
+
* whichever record declares them rather than to the toolkit. Holding a pair in
|
|
20
|
+
* code and gating every project against it audits a target against a rule it
|
|
21
|
+
* never adopted, which is the failure `canResolveAtRoot` already answers on the
|
|
22
|
+
* folder side. A record stating no rule is measured and never gated.
|
|
23
|
+
*/
|
|
24
|
+
export interface Allowances {
|
|
25
|
+
readonly frame: number
|
|
26
|
+
readonly perDecision: number
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* What a machine could do with the entry's reasoning, which is a candidate
|
|
31
|
+
* rather than a verdict.
|
|
32
|
+
*
|
|
33
|
+
* - `countable`: carries a figure over a tree, so a run could recompute it.
|
|
34
|
+
* - `invariant`: quantifies over a named tree, so a walk could falsify it.
|
|
35
|
+
* - `neither`: says why a choice was made, which nothing tests.
|
|
36
|
+
*/
|
|
37
|
+
export type ClaimKind = 'countable' | 'invariant' | 'neither'
|
|
38
|
+
|
|
39
|
+
export interface DecisionReport {
|
|
40
|
+
readonly heading: string
|
|
41
|
+
/** Line of the `###` heading, so a report line opens at the entry. */
|
|
42
|
+
readonly line: number
|
|
43
|
+
readonly claim: ClaimKind
|
|
44
|
+
/** The digit-spelled figures behind a `countable` reading, in order. */
|
|
45
|
+
readonly figures: readonly string[]
|
|
46
|
+
/** The first sentence behind an `invariant` reading, absent otherwise. */
|
|
47
|
+
readonly quantified?: string
|
|
48
|
+
/**
|
|
49
|
+
* Executable checks the entry names, which is the only coverage signal the
|
|
50
|
+
* record carries. Empty on an entry that names none, including one whose
|
|
51
|
+
* claim some check happens to cover without the entry saying so.
|
|
52
|
+
*/
|
|
53
|
+
readonly checks: readonly string[]
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export interface ArchitectureReport {
|
|
57
|
+
readonly rel: string
|
|
58
|
+
readonly lines: number
|
|
59
|
+
/** What the record declared, absent when it states no length rule. */
|
|
60
|
+
readonly allowances?: Allowances
|
|
61
|
+
/** The frame plus the per-decision allowance, absent alongside it. */
|
|
62
|
+
readonly ceiling?: number
|
|
63
|
+
readonly decisions: readonly DecisionReport[]
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const DECISION_HEADING = /^###\s+(.+?)\s*$/
|
|
67
|
+
const SECTION_HEADING = /^##\s+\S/
|
|
68
|
+
const CODE_SPAN = /`[^`]*`/g
|
|
69
|
+
/** Dropped ahead of the figure scan, since an anchor date is not a claim. */
|
|
70
|
+
const ISO_DATE = /\b\d{4}-\d{2}-\d{2}\b/g
|
|
71
|
+
const FIGURE = /\b\d+(?:,\d{3})*\b/g
|
|
72
|
+
const SENTENCE_SPLIT = /(?<=[.])\s+/
|
|
73
|
+
|
|
74
|
+
/** A code span naming a path, which is what a quantifier has to govern. */
|
|
75
|
+
const PATH_SPAN = String.raw`\`[^\`]*(?:/|\.md|\.ts|\.sh|\.json)[^\`]*\``
|
|
76
|
+
const QUANTIFIER = String.raw`\b(?:every|each|no|nothing|any|all|never|only)\b`
|
|
77
|
+
/** Six words is the widest gap the corpus puts between the two. */
|
|
78
|
+
const WINDOW = String.raw`(?:\s+\S+){0,6}?\s+`
|
|
79
|
+
|
|
80
|
+
const QUANTIFIES_PATH = new RegExp(
|
|
81
|
+
`${QUANTIFIER}${WINDOW}${PATH_SPAN}|${PATH_SPAN}${WINDOW}${QUANTIFIER}`,
|
|
82
|
+
'i',
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
/** A code span naming a shell check this repository could run. */
|
|
86
|
+
const SCRIPT_SPAN = /^scripts\/[\w./-]+\.sh$/
|
|
87
|
+
/** A code span invoking the CLI, which may or may not name a registered audit. */
|
|
88
|
+
const CANON_SPAN = /^canon\s+(.+)$/
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* The audit invocations a decision could name, spelled as a reader writes them.
|
|
92
|
+
*
|
|
93
|
+
* Read off the catalog rather than listed, so a verb renamed at its source
|
|
94
|
+
* stops matching here instead of going on matching a string nobody maintains.
|
|
95
|
+
*/
|
|
96
|
+
const AUDIT_INVOCATIONS: readonly string[] = AUDITS.map((audit) =>
|
|
97
|
+
audit.argv.filter((arg) => arg !== '--json').join(' '),
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
function codeSpans(text: string): string[] {
|
|
101
|
+
return (text.match(CODE_SPAN) ?? []).map((span) => span.slice(1, -1))
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Names the executable checks an entry spells.
|
|
106
|
+
*
|
|
107
|
+
* A script has to exist on disk and a `canon` invocation has to match a
|
|
108
|
+
* registered audit, because an entry naming a check that was removed is an
|
|
109
|
+
* uncovered claim wearing a covered one's words.
|
|
110
|
+
*/
|
|
111
|
+
async function namedChecks(root: string, body: string): Promise<string[]> {
|
|
112
|
+
const spans = [...new Set(codeSpans(body))]
|
|
113
|
+
|
|
114
|
+
const verbs = spans.filter((span) => {
|
|
115
|
+
const invocation = span.match(CANON_SPAN)?.[1]
|
|
116
|
+
return invocation !== undefined && AUDIT_INVOCATIONS.includes(invocation)
|
|
117
|
+
})
|
|
118
|
+
|
|
119
|
+
const scripts = spans.filter((span) => SCRIPT_SPAN.test(span))
|
|
120
|
+
const present = await Promise.all(
|
|
121
|
+
scripts.map((span) =>
|
|
122
|
+
access(join(root, span)).then(
|
|
123
|
+
() => true,
|
|
124
|
+
() => false,
|
|
125
|
+
),
|
|
126
|
+
),
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
return [...verbs, ...scripts.filter((_, index) => present[index])]
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Reads the figures a decision carries, which is the countable-claim signal.
|
|
134
|
+
*
|
|
135
|
+
* Digits alone. A cardinal spelled in words reads as pronominal far more often
|
|
136
|
+
* than as measured in this corpus, where "the alternative and it is one nobody
|
|
137
|
+
* passes" outnumbers "eleven copies", and admitting the spelled form classified
|
|
138
|
+
* 22 of 24 entries as countable, which distinguishes nothing. The cost is that
|
|
139
|
+
* a measured claim written in words reads as uncounted, which the report says.
|
|
140
|
+
*/
|
|
141
|
+
function figuresIn(body: string): string[] {
|
|
142
|
+
return body.replace(ISO_DATE, ' ').replace(CODE_SPAN, ' ').match(FIGURE) ?? []
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* The first sentence quantifying over a named tree, or undefined.
|
|
147
|
+
*
|
|
148
|
+
* The quantifier has to sit within a short window of the path so a sentence
|
|
149
|
+
* mentioning both without relating them does not read as a claim about the
|
|
150
|
+
* tree. Both orders are matched, since the corpus writes the property before
|
|
151
|
+
* the path as readily as after it.
|
|
152
|
+
*/
|
|
153
|
+
function quantifiedSentence(body: string): string | undefined {
|
|
154
|
+
return body
|
|
155
|
+
.replace(ISO_DATE, ' ')
|
|
156
|
+
.split(SENTENCE_SPLIT)
|
|
157
|
+
.map((sentence) => sentence.replace(/\n/g, ' ').trim())
|
|
158
|
+
.find((sentence) => QUANTIFIES_PATH.test(sentence))
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Classifies one entry, with the countable reading taking precedence.
|
|
163
|
+
*
|
|
164
|
+
* An entry carrying both a figure and a quantified tree is recomputable, which
|
|
165
|
+
* is the stronger test, and the two readings are reported as one kind because
|
|
166
|
+
* the coverage split a reader wants is testable against unverifiable rather
|
|
167
|
+
* than a per-entry inventory of every claim in it.
|
|
168
|
+
*/
|
|
169
|
+
export function classifyDecision(body: string): {
|
|
170
|
+
claim: ClaimKind
|
|
171
|
+
figures: string[]
|
|
172
|
+
quantified?: string
|
|
173
|
+
} {
|
|
174
|
+
const figures = figuresIn(body)
|
|
175
|
+
if (figures.length > 0) return { claim: 'countable', figures }
|
|
176
|
+
|
|
177
|
+
const quantified = quantifiedSentence(body)
|
|
178
|
+
if (quantified !== undefined) {
|
|
179
|
+
return { claim: 'invariant', figures: [], quantified }
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
return { claim: 'neither', figures: [] }
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
interface RawDecision {
|
|
186
|
+
readonly heading: string
|
|
187
|
+
readonly line: number
|
|
188
|
+
readonly body: string
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Splits the record into its `###` entries.
|
|
193
|
+
*
|
|
194
|
+
* A heading inside a fenced block is skipped, since the seed template shows the
|
|
195
|
+
* shape it asks a project to write and a template entry is not a decision.
|
|
196
|
+
*
|
|
197
|
+
* A heading carrying several decisions counts once, so the total reads low by
|
|
198
|
+
* however many it holds. The report states that rather than parsing for it,
|
|
199
|
+
* because splitting a decision from its heading needs a marker the standard
|
|
200
|
+
* does not ask a record to carry.
|
|
201
|
+
*/
|
|
202
|
+
export function splitDecisions(source: string): RawDecision[] {
|
|
203
|
+
const lines = bodyLines(source)
|
|
204
|
+
const decisions: RawDecision[] = []
|
|
205
|
+
let open: { heading: string; line: number; body: string[] } | undefined
|
|
206
|
+
|
|
207
|
+
for (const line of lines) {
|
|
208
|
+
if (line.fenced) {
|
|
209
|
+
open?.body.push(line.text)
|
|
210
|
+
continue
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
const heading = line.text.match(DECISION_HEADING)?.[1]
|
|
214
|
+
if (heading !== undefined) {
|
|
215
|
+
if (open) decisions.push({ ...open, body: open.body.join('\n') })
|
|
216
|
+
open = { heading, line: line.number, body: [] }
|
|
217
|
+
continue
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// A decision runs to the next `###` or to the section that follows the
|
|
221
|
+
// decision list, so the risks below never read as the last entry's body.
|
|
222
|
+
if (SECTION_HEADING.test(line.text)) {
|
|
223
|
+
if (open) decisions.push({ ...open, body: open.body.join('\n') })
|
|
224
|
+
open = undefined
|
|
225
|
+
continue
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
open?.body.push(line.text)
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
if (open) decisions.push({ ...open, body: open.body.join('\n') })
|
|
232
|
+
return decisions
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/** Cardinals a record spells rather than writes, which the corpus does for both. */
|
|
236
|
+
const SPELLED: Record<string, number> = {
|
|
237
|
+
one: 1,
|
|
238
|
+
two: 2,
|
|
239
|
+
three: 3,
|
|
240
|
+
four: 4,
|
|
241
|
+
five: 5,
|
|
242
|
+
six: 6,
|
|
243
|
+
seven: 7,
|
|
244
|
+
eight: 8,
|
|
245
|
+
nine: 9,
|
|
246
|
+
ten: 10,
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
const CARDINAL = String.raw`(\d+|${Object.keys(SPELLED).join('|')})`
|
|
250
|
+
const FRAME_CLAUSE = new RegExp(String.raw`${CARDINAL}-line frame`, 'i')
|
|
251
|
+
const PER_DECISION_CLAUSE = new RegExp(
|
|
252
|
+
String.raw`${CARDINAL}\s+lines?\s+a\s+decision`,
|
|
253
|
+
'i',
|
|
254
|
+
)
|
|
255
|
+
|
|
256
|
+
function readCardinal(token: string | undefined): number | undefined {
|
|
257
|
+
if (token === undefined) return undefined
|
|
258
|
+
const spelled = SPELLED[token.toLowerCase()]
|
|
259
|
+
if (spelled !== undefined) return spelled
|
|
260
|
+
|
|
261
|
+
const digits = Number.parseInt(token, 10)
|
|
262
|
+
return Number.isNaN(digits) ? undefined : digits
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* Reads the allowances a record declares for itself, or nothing.
|
|
267
|
+
*
|
|
268
|
+
* Both clauses have to be present, because half a formula is not one. A record
|
|
269
|
+
* whose wording drifts past these clauses falls back to reporting rather than
|
|
270
|
+
* to a stale ceiling held here, so the failure is visible in the run's own
|
|
271
|
+
* output instead of gating a project on a rule nobody can point at.
|
|
272
|
+
*/
|
|
273
|
+
export function readAllowances(source: string): Allowances | undefined {
|
|
274
|
+
const frame = readCardinal(source.match(FRAME_CLAUSE)?.[1])
|
|
275
|
+
const perDecision = readCardinal(source.match(PER_DECISION_CLAUSE)?.[1])
|
|
276
|
+
|
|
277
|
+
if (frame === undefined || perDecision === undefined) return undefined
|
|
278
|
+
return { frame, perDecision }
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
/** Whether a read failed because nothing sits at the path. */
|
|
282
|
+
function isMissing(error: unknown): boolean {
|
|
283
|
+
const code = (error as { code?: unknown }).code
|
|
284
|
+
return code === 'ENOENT' || code === 'ENOTDIR'
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/** The ceiling the record's own formula derives from its decision count. */
|
|
288
|
+
export function ceilingFor(allowances: Allowances, decisions: number): number {
|
|
289
|
+
return allowances.frame + allowances.perDecision * decisions
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* Measures the record, or reports nothing when the project carries none.
|
|
294
|
+
*
|
|
295
|
+
* Absent rather than empty, for the reason the sibling checks state: a project
|
|
296
|
+
* with no record and one whose record holds no decision are different answers,
|
|
297
|
+
* and a zeroed report reads as the second.
|
|
298
|
+
*/
|
|
299
|
+
export async function measureArchitecture(
|
|
300
|
+
root: string,
|
|
301
|
+
): Promise<ArchitectureReport | undefined> {
|
|
302
|
+
const path = join(root, RECORD_REL)
|
|
303
|
+
|
|
304
|
+
let source: string
|
|
305
|
+
try {
|
|
306
|
+
source = await readFile(path, 'utf8')
|
|
307
|
+
} catch (error) {
|
|
308
|
+
// Only a record that is not there reads as absent. A record present and
|
|
309
|
+
// unreadable propagates the way every sibling reader here lets one
|
|
310
|
+
// propagate, since swallowing it reports a project with no record and the
|
|
311
|
+
// length gate passes over a file nobody opened.
|
|
312
|
+
if (!isMissing(error)) throw error
|
|
313
|
+
return undefined
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
const allowances = readAllowances(source)
|
|
317
|
+
const raw = splitDecisions(source)
|
|
318
|
+
const decisions = await Promise.all(
|
|
319
|
+
raw.map(async (entry) => {
|
|
320
|
+
const { claim, figures, quantified } = classifyDecision(entry.body)
|
|
321
|
+
return {
|
|
322
|
+
heading: entry.heading,
|
|
323
|
+
line: entry.line,
|
|
324
|
+
claim,
|
|
325
|
+
figures,
|
|
326
|
+
...(quantified !== undefined && { quantified }),
|
|
327
|
+
checks: await namedChecks(root, entry.body),
|
|
328
|
+
}
|
|
329
|
+
}),
|
|
330
|
+
)
|
|
331
|
+
|
|
332
|
+
return {
|
|
333
|
+
rel: RECORD_REL,
|
|
334
|
+
lines: source.replace(/\n$/, '').split('\n').length,
|
|
335
|
+
...(allowances !== undefined && {
|
|
336
|
+
allowances,
|
|
337
|
+
ceiling: ceilingFor(allowances, raw.length),
|
|
338
|
+
}),
|
|
339
|
+
decisions,
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
/**
|
|
344
|
+
* Whether the record is longer than the ceiling it derives for itself.
|
|
345
|
+
*
|
|
346
|
+
* False for a record declaring no allowances, which has no ceiling to be past.
|
|
347
|
+
* That is the answer rather than a gap, since the length rule is the record's
|
|
348
|
+
* own and a project that never wrote one owes nothing to it.
|
|
349
|
+
*/
|
|
350
|
+
export function isOverLength(report: ArchitectureReport): boolean {
|
|
351
|
+
return report.ceiling !== undefined && report.lines > report.ceiling
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
/** How many entries carry a claim a machine could test. */
|
|
355
|
+
export function testableCount(report: ArchitectureReport): number {
|
|
356
|
+
return report.decisions.filter((entry) => entry.claim !== 'neither').length
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
/** How many testable entries name a check that exists. */
|
|
360
|
+
export function coveredCount(report: ArchitectureReport): number {
|
|
361
|
+
return report.decisions.filter(
|
|
362
|
+
(entry) => entry.claim !== 'neither' && entry.checks.length > 0,
|
|
363
|
+
).length
|
|
364
|
+
}
|