@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,204 @@
|
|
|
1
|
+
import { join } from 'node:path'
|
|
2
|
+
import { execa } from 'execa'
|
|
3
|
+
import type { Delta } from '@/audits/baseline'
|
|
4
|
+
import { type AuditResult, type AuditSpec, classify } from '@/audits/catalog'
|
|
5
|
+
import { gitEnv } from '@/git-env'
|
|
6
|
+
import { PROJECT_ROOT } from '@/project-root'
|
|
7
|
+
|
|
8
|
+
/** At least one audit reported a finding that is a fact. */
|
|
9
|
+
export const EXIT_FINDING = 2
|
|
10
|
+
|
|
11
|
+
/** At least one audit did not report, so the run measured less than the set. */
|
|
12
|
+
export const EXIT_UNMEASURED = 3
|
|
13
|
+
|
|
14
|
+
export type Verdict =
|
|
15
|
+
/** Every audit reported and every count it produced was zero. */
|
|
16
|
+
| 'clean'
|
|
17
|
+
/** Every audit reported and at least one carries a judgment finding. */
|
|
18
|
+
| 'reported'
|
|
19
|
+
/** At least one audit carries a finding that is a fact. */
|
|
20
|
+
| 'findings'
|
|
21
|
+
/** At least one audit did not report, so this is not a pass. */
|
|
22
|
+
| 'incomplete'
|
|
23
|
+
|
|
24
|
+
export interface SpawnResult {
|
|
25
|
+
readonly exitCode: number
|
|
26
|
+
readonly stdout: string
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export type Spawn = (spec: AuditSpec) => Promise<SpawnResult>
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Runs each verb out of the checkout this CLI is executing from.
|
|
33
|
+
*
|
|
34
|
+
* `process.execPath` and the resolved `cli.ts` rather than a bare `canon`, for
|
|
35
|
+
* the reason `cliRunner` in `src/gate/sequencer.ts` already names: a globally
|
|
36
|
+
* installed binary resolves to
|
|
37
|
+
* the main checkout no matter which worktree is running, so the aggregate would
|
|
38
|
+
* measure the wrong tree and report a pass over a branch it never read.
|
|
39
|
+
*
|
|
40
|
+
* `reject: false` because a findings exit is the ordinary outcome for half of
|
|
41
|
+
* these verbs, and a throw there would be an error path for a working check.
|
|
42
|
+
*/
|
|
43
|
+
export function spawnAudit(root: string): Spawn {
|
|
44
|
+
const cli = join(PROJECT_ROOT, 'src', 'cli.ts')
|
|
45
|
+
|
|
46
|
+
return async (spec) => {
|
|
47
|
+
const result = await execa(process.execPath, [cli, ...spec.argv], {
|
|
48
|
+
cwd: root,
|
|
49
|
+
reject: false,
|
|
50
|
+
// `gitEnv` already returns the whole ambient environment minus git's
|
|
51
|
+
// resolution variables, so it replaces the environment rather than
|
|
52
|
+
// extending it. Spreading `process.env` alongside would put back the very
|
|
53
|
+
// variables it strips, and a hook's `GIT_DIR` would then point every
|
|
54
|
+
// history-reading verb at a repository nobody asked about.
|
|
55
|
+
env: { ...gitEnv(), CANON_NON_INTERACTIVE: '1' },
|
|
56
|
+
extendEnv: false,
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
return { exitCode: result.exitCode ?? 1, stdout: result.stdout }
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Runs every audit and reads each one's own record shape.
|
|
65
|
+
*
|
|
66
|
+
* The verbs walk separate trees and share no state, so they run together
|
|
67
|
+
* rather than in sequence. Serially, the aggregate would be the slowest thing
|
|
68
|
+
* in the verify pipeline for no reason beyond the order they were written in.
|
|
69
|
+
*
|
|
70
|
+
* A spawn that throws becomes an `unmeasured` result rather than a rejection.
|
|
71
|
+
* One absent binary would otherwise take the whole aggregate down and report
|
|
72
|
+
* nothing about the audits that did run.
|
|
73
|
+
*/
|
|
74
|
+
export async function runAudits(
|
|
75
|
+
specs: readonly AuditSpec[],
|
|
76
|
+
spawn: Spawn,
|
|
77
|
+
): Promise<AuditResult[]> {
|
|
78
|
+
return Promise.all(
|
|
79
|
+
specs.map(async (spec) => {
|
|
80
|
+
try {
|
|
81
|
+
const { exitCode, stdout } = await spawn(spec)
|
|
82
|
+
return classify(spec, exitCode, stdout)
|
|
83
|
+
} catch (error) {
|
|
84
|
+
return {
|
|
85
|
+
id: spec.id,
|
|
86
|
+
label: spec.label,
|
|
87
|
+
status: 'unmeasured' as const,
|
|
88
|
+
tracked: spec.corpus === 'tracked',
|
|
89
|
+
corpus: spec.corpus,
|
|
90
|
+
exitCode: 1,
|
|
91
|
+
reason: `could not be started: ${error instanceof Error ? error.message : String(error)}`,
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}),
|
|
95
|
+
)
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* The single verdict over the set.
|
|
100
|
+
*
|
|
101
|
+
* `incomplete` outranks a quiet set on purpose. An aggregate reporting a pass
|
|
102
|
+
* over a tree it did not finish measuring is the failure this whole command
|
|
103
|
+
* exists against, and an empty set takes it for the same reason: nothing ran,
|
|
104
|
+
* so nothing passed.
|
|
105
|
+
*
|
|
106
|
+
* An `absent` per-machine corpus does not reach it. That folder is gitignored
|
|
107
|
+
* and missing on every fresh clone, so folding it in would pin the verdict at
|
|
108
|
+
* `incomplete` on every CI run and leave the word meaning nothing.
|
|
109
|
+
*/
|
|
110
|
+
export function verdictOf(results: readonly AuditResult[]): Verdict {
|
|
111
|
+
if (results.length === 0) return 'incomplete'
|
|
112
|
+
if (results.some((result) => result.status === 'finding')) return 'findings'
|
|
113
|
+
if (results.some((result) => result.status === 'unmeasured')) {
|
|
114
|
+
return 'incomplete'
|
|
115
|
+
}
|
|
116
|
+
if (results.some((result) => result.status === 'reported')) return 'reported'
|
|
117
|
+
return 'clean'
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Exits non-zero only on a fact, which is the split this aggregate inherits
|
|
122
|
+
* rather than moves. A growing judgment count reports as a delta and fails
|
|
123
|
+
* nothing, because the standards behind those measures set no hard cap.
|
|
124
|
+
*
|
|
125
|
+
* An audit that did not report takes its own code rather than the findings one.
|
|
126
|
+
* The two mean opposite things to whoever reads the exit: a fact is a defect in
|
|
127
|
+
* the tree, and an unmeasured audit is a defect in the run.
|
|
128
|
+
*/
|
|
129
|
+
export function exitCodeFor(results: readonly AuditResult[]): number {
|
|
130
|
+
const verdict = verdictOf(results)
|
|
131
|
+
if (verdict === 'findings') return EXIT_FINDING
|
|
132
|
+
if (verdict === 'incomplete') return EXIT_UNMEASURED
|
|
133
|
+
return 0
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
export interface Summary {
|
|
137
|
+
readonly verdict: Verdict
|
|
138
|
+
/** Audits that reported, out of the whole set. */
|
|
139
|
+
readonly audited: number
|
|
140
|
+
/** Audits carrying a finding that is a fact. */
|
|
141
|
+
readonly facts: number
|
|
142
|
+
/** Audits that did not report at all. */
|
|
143
|
+
readonly unmeasured: number
|
|
144
|
+
/**
|
|
145
|
+
* Audits whose per-machine folder is not on this disk.
|
|
146
|
+
*
|
|
147
|
+
* Published rather than folded into `audited`, so a run stating twelve
|
|
148
|
+
* audits never implies twelve corpora were read.
|
|
149
|
+
*/
|
|
150
|
+
readonly absent: number
|
|
151
|
+
/** Tracked counts that rose against the recorded floor. */
|
|
152
|
+
readonly grown: number
|
|
153
|
+
/** Tracked counts that fell against the recorded floor. */
|
|
154
|
+
readonly shrunk: number
|
|
155
|
+
/** Tracked audits with no recorded floor to compare against. */
|
|
156
|
+
readonly unrecorded: number
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* The flat reading a shell stage takes without parsing the nested record.
|
|
161
|
+
*
|
|
162
|
+
* Published rather than left to a consumer to derive, for the reason the
|
|
163
|
+
* context audit already gives about its own join: deriving it means restating
|
|
164
|
+
* which question each number answers, and one wrong restatement is growth
|
|
165
|
+
* reported against a measure that never moved. Every key here is unique across
|
|
166
|
+
* the whole record, so a grep for one reaches the top level alone.
|
|
167
|
+
*/
|
|
168
|
+
export function summarize(
|
|
169
|
+
results: readonly AuditResult[],
|
|
170
|
+
deltas: readonly Delta[],
|
|
171
|
+
): Summary {
|
|
172
|
+
let grown = 0
|
|
173
|
+
let shrunk = 0
|
|
174
|
+
let unrecorded = 0
|
|
175
|
+
|
|
176
|
+
for (const delta of deltas) {
|
|
177
|
+
if (delta.kind === 'unrecorded') {
|
|
178
|
+
unrecorded += 1
|
|
179
|
+
continue
|
|
180
|
+
}
|
|
181
|
+
if (delta.kind !== 'compared') continue
|
|
182
|
+
|
|
183
|
+
for (const moved of delta.moved) {
|
|
184
|
+
if (moved.delta > 0) grown += 1
|
|
185
|
+
else shrunk += 1
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
const counting = (status: AuditResult['status']) =>
|
|
190
|
+
results.filter((result) => result.status === status).length
|
|
191
|
+
|
|
192
|
+
return {
|
|
193
|
+
verdict: verdictOf(results),
|
|
194
|
+
audited: results.filter(
|
|
195
|
+
(result) => result.status !== 'unmeasured' && result.status !== 'absent',
|
|
196
|
+
).length,
|
|
197
|
+
facts: counting('finding'),
|
|
198
|
+
unmeasured: counting('unmeasured'),
|
|
199
|
+
absent: counting('absent'),
|
|
200
|
+
grown,
|
|
201
|
+
shrunk,
|
|
202
|
+
unrecorded,
|
|
203
|
+
}
|
|
204
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import {
|
|
2
|
+
BEHAVIOR_FILES,
|
|
3
|
+
BEHAVIOR_PREFIXES,
|
|
4
|
+
PROSE_EXTENSIONS,
|
|
5
|
+
} from '@/autoship/paths'
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Which of the two tests a file failed.
|
|
9
|
+
*
|
|
10
|
+
* Named apart rather than folded into one boolean, because the repair differs.
|
|
11
|
+
* A non-prose extension means the branch carries code and review is ordinary. A
|
|
12
|
+
* behavior path means prose that states what an agent does, which is the half
|
|
13
|
+
* three sessions read past.
|
|
14
|
+
*/
|
|
15
|
+
export type FailedTest = 'extension' | 'behavior-path'
|
|
16
|
+
|
|
17
|
+
/** Why a classification produced no reading. */
|
|
18
|
+
export type ClassifyRefusal = 'no-changes'
|
|
19
|
+
|
|
20
|
+
export type Classification =
|
|
21
|
+
| { readonly kind: 'skip' }
|
|
22
|
+
| {
|
|
23
|
+
readonly kind: 'review'
|
|
24
|
+
readonly test: FailedTest
|
|
25
|
+
readonly file: string
|
|
26
|
+
}
|
|
27
|
+
| { readonly kind: 'refused'; readonly reason: ClassifyRefusal }
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Prefix-anchored against the folders, matching how `resolveCoverage` reads the
|
|
31
|
+
* label map, and equality against the whole paths a prefix cannot reach.
|
|
32
|
+
*/
|
|
33
|
+
function underBehaviorPath(path: string): boolean {
|
|
34
|
+
if (BEHAVIOR_FILES.some((file) => file === path)) return true
|
|
35
|
+
return BEHAVIOR_PREFIXES.some((prefix) => path.startsWith(prefix))
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function readsAsProse(path: string): boolean {
|
|
39
|
+
const lowered = path.toLowerCase()
|
|
40
|
+
return PROSE_EXTENSIONS.some((extension) => lowered.endsWith(extension))
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Decides whether a branch's changed set skips the review pass.
|
|
45
|
+
*
|
|
46
|
+
* The skip needs both tests to pass: every name reads as prose, and no name
|
|
47
|
+
* sits under a behavior path. One behavior file sends the whole branch to
|
|
48
|
+
* review, since documentation shipped beside a behavior change does not cancel
|
|
49
|
+
* it.
|
|
50
|
+
*
|
|
51
|
+
* An empty set refuses rather than skipping. Both tests are universally
|
|
52
|
+
* quantified, so an empty set satisfies them vacuously, and reading that as
|
|
53
|
+
* prose-only would route a branch past review for having produced no output at
|
|
54
|
+
* all.
|
|
55
|
+
*
|
|
56
|
+
* Names only. The caller hands the set the ship chain already computed, so no
|
|
57
|
+
* second baseline is read here and the stale-baseline half stays closed.
|
|
58
|
+
*/
|
|
59
|
+
export function classifyChanges(paths: readonly string[]): Classification {
|
|
60
|
+
if (paths.length === 0) return { kind: 'refused', reason: 'no-changes' }
|
|
61
|
+
|
|
62
|
+
// First failure in the caller's order wins, and each file is tested for its
|
|
63
|
+
// extension before its path. A set failing both tests reports one file and
|
|
64
|
+
// one test, which is all the branch needs to route.
|
|
65
|
+
for (const path of paths) {
|
|
66
|
+
if (!readsAsProse(path)) {
|
|
67
|
+
return { kind: 'review', test: 'extension', file: path }
|
|
68
|
+
}
|
|
69
|
+
if (underBehaviorPath(path)) {
|
|
70
|
+
return { kind: 'review', test: 'behavior-path', file: path }
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return { kind: 'skip' }
|
|
75
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The surfaces where markdown states what an agent does, and the extensions
|
|
3
|
+
* that read as prose, held as data one command parses.
|
|
4
|
+
*
|
|
5
|
+
* Lifted verbatim in content from the list `claude-autoship/SKILL.md` Step 5
|
|
6
|
+
* carried, which a session was asked to apply by hand. It failed that
|
|
7
|
+
* application three times, so the set moved here and the body now calls a verb
|
|
8
|
+
* that reads it. Being machine-parsed makes it permanently exempt from any
|
|
9
|
+
* later design that folds a standard back into the surface citing it, per the
|
|
10
|
+
* machine-parsed clause in `.claude/ARCHITECTURE.md`.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Path prefixes under which a markdown change is a behavior change.
|
|
15
|
+
*
|
|
16
|
+
* Most carry two spellings, the one a surface authors at and the one it reaches
|
|
17
|
+
* a session at, so the rule reads the same in this toolkit and in a project
|
|
18
|
+
* that consumed one. `standards/` and `snippets/` carry one apiece: neither
|
|
19
|
+
* installs into a project, reaching a reader by resolution and through the
|
|
20
|
+
* `claude/snippets` symlink respectively, so no `.claude/` spelling exists to
|
|
21
|
+
* name.
|
|
22
|
+
*/
|
|
23
|
+
export const BEHAVIOR_PREFIXES = [
|
|
24
|
+
'claude/skills/',
|
|
25
|
+
'.claude/skills/',
|
|
26
|
+
'governance/rules/',
|
|
27
|
+
'.claude/rules/',
|
|
28
|
+
'standards/',
|
|
29
|
+
'snippets/',
|
|
30
|
+
'internal/',
|
|
31
|
+
'tooling/',
|
|
32
|
+
] as const
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Behavior surfaces named as whole paths rather than as prefixes.
|
|
36
|
+
*
|
|
37
|
+
* A path prefix reaches nothing that sits in no folder, which is what the root
|
|
38
|
+
* instruction file is. Matching is equality rather than a suffix test, so a
|
|
39
|
+
* nested `docs/CLAUDE.md` stays informational the way the body's "at the
|
|
40
|
+
* repository root" qualifier says it should.
|
|
41
|
+
*/
|
|
42
|
+
export const BEHAVIOR_FILES = ['CLAUDE.md'] as const
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Extensions a changed file may carry for the branch to read as prose-only.
|
|
46
|
+
*
|
|
47
|
+
* Compared lowercased, so a `README.MD` is not routed to review for its
|
|
48
|
+
* spelling. Everything else is code, a config, or an asset, and one of them
|
|
49
|
+
* sends the whole branch to review.
|
|
50
|
+
*/
|
|
51
|
+
export const PROSE_EXTENSIONS = ['.md', '.txt'] as const
|
package/src/binary.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Whether the bytes are something a line scanner should not read.
|
|
3
|
+
*
|
|
4
|
+
* A NUL byte rather than an extension list, since a shipped tree carries fonts
|
|
5
|
+
* and images under names no scanner has reason to enumerate, and a list would
|
|
6
|
+
* go stale the first time a format was added. Decoded text holds no NUL, so the
|
|
7
|
+
* test costs one scan and never rejects source.
|
|
8
|
+
*
|
|
9
|
+
* Neutral rather than owned by either sweep that calls it. The secret scan
|
|
10
|
+
* shaped it and the superseded-value sweep reads the same corpus, so leaving it
|
|
11
|
+
* in `src/secrets/` would put a `src/gov/` dependency on the secret scanner for
|
|
12
|
+
* a predicate about bytes.
|
|
13
|
+
*/
|
|
14
|
+
export function isBinary(text: string): boolean {
|
|
15
|
+
return text.includes('\0')
|
|
16
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What every browser-driving command needs to know before it can report a
|
|
3
|
+
* failure honestly: how the binary is installed, and how each of the two ways
|
|
4
|
+
* it can be absent reads when it is thrown.
|
|
5
|
+
*
|
|
6
|
+
* The two are different states with different remedies. A package that never
|
|
7
|
+
* resolved means the target installed the CLI without the engine, and a binary
|
|
8
|
+
* that was never downloaded means the engine is present and its browser is not.
|
|
9
|
+
* Both were spelled inside `src/demo/` when `demo` was the only command driving
|
|
10
|
+
* a browser, and a second command is what makes them shared rather than local.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
/** Fetches the browser revision the pinned engine expects. */
|
|
14
|
+
export const INSTALL_BROWSER = 'bunx playwright install chromium'
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Separates a browser binary that was never installed from every other launch
|
|
18
|
+
* failure, because the first is a setup step the operator has to run and the
|
|
19
|
+
* second is a defect. A target inherits that setup step, which is the stated
|
|
20
|
+
* cost of shipping a browser command outside the toolkit.
|
|
21
|
+
*/
|
|
22
|
+
export function isBrowserMissing(error: unknown): boolean {
|
|
23
|
+
const text = error instanceof Error ? error.message : String(error)
|
|
24
|
+
return /executable doesn't exist|playwright install/i.test(text)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Reports the engine package failing to resolve, which is the case a target
|
|
29
|
+
* hits before installing it. Any other import failure is a defect inside the
|
|
30
|
+
* module being loaded and propagates, rather than being reported as a missing
|
|
31
|
+
* dependency.
|
|
32
|
+
*/
|
|
33
|
+
export function isEngineMissing(error: unknown): boolean {
|
|
34
|
+
return (
|
|
35
|
+
typeof error === 'object' &&
|
|
36
|
+
error !== null &&
|
|
37
|
+
'code' in error &&
|
|
38
|
+
error.code === 'ERR_MODULE_NOT_FOUND'
|
|
39
|
+
)
|
|
40
|
+
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises'
|
|
2
|
+
import { extname, join } from 'node:path'
|
|
3
|
+
import { isBinary } from '@/binary'
|
|
4
|
+
import { listRepositoryFiles } from '@/git-files'
|
|
5
|
+
|
|
6
|
+
export type CensusRefusal = 'no-git'
|
|
7
|
+
|
|
8
|
+
export interface ExtensionCount {
|
|
9
|
+
readonly extension: string
|
|
10
|
+
readonly files: number
|
|
11
|
+
readonly lines: number
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface CensusResult {
|
|
15
|
+
readonly kind: 'measured'
|
|
16
|
+
readonly files: number
|
|
17
|
+
/** Binary or unreadable, counted toward `files` and excluded from `lines`. */
|
|
18
|
+
readonly skipped: number
|
|
19
|
+
readonly lines: number
|
|
20
|
+
readonly byExtension: readonly ExtensionCount[]
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface CensusFailure {
|
|
24
|
+
readonly kind: 'refused'
|
|
25
|
+
readonly reason: CensusRefusal
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Open descriptors allowed at once while reading the tree, matching
|
|
30
|
+
* `src/comments/scan.ts`. A single `Promise.all` over every path opens one
|
|
31
|
+
* descriptor per file, which exhausts a default 1024 limit on a large
|
|
32
|
+
* repository and fails the whole census with EMFILE.
|
|
33
|
+
*/
|
|
34
|
+
const CONCURRENT_READS = 64
|
|
35
|
+
|
|
36
|
+
interface ReadOutcome {
|
|
37
|
+
readonly path: string
|
|
38
|
+
/** Absent when the read failed: a symlink leaving the tree, or a file git
|
|
39
|
+
* listed and the working tree no longer holds. */
|
|
40
|
+
readonly text?: string
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
async function readOne(root: string, path: string): Promise<ReadOutcome> {
|
|
44
|
+
try {
|
|
45
|
+
return { path, text: await readFile(join(root, path), 'utf8') }
|
|
46
|
+
} catch {
|
|
47
|
+
return { path }
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function extensionFor(path: string): string {
|
|
52
|
+
const ext = extname(path)
|
|
53
|
+
return ext === '' ? 'no-extension' : ext.slice(1).toLowerCase()
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* A trailing newline is the file's terminator rather than an empty final line,
|
|
58
|
+
* which is what keeps a file ending `a\nb\n` at two lines rather than three.
|
|
59
|
+
*/
|
|
60
|
+
function countLines(text: string): number {
|
|
61
|
+
if (text === '') return 0
|
|
62
|
+
const lines = text.split('\n')
|
|
63
|
+
return text.endsWith('\n') ? lines.length - 1 : lines.length
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Censuses the tracked-plus-untracked tree under `root`: a file count, a
|
|
68
|
+
* breakdown by extension, and a line total that skips whatever reads as
|
|
69
|
+
* binary.
|
|
70
|
+
*
|
|
71
|
+
* Reads `listRepositoryFiles`, the same corpus the citation check, the
|
|
72
|
+
* markdown corpus, and the secret scan already share, so this is not a
|
|
73
|
+
* fourth definition of what counts.
|
|
74
|
+
*/
|
|
75
|
+
export async function census(
|
|
76
|
+
root: string,
|
|
77
|
+
): Promise<CensusResult | CensusFailure> {
|
|
78
|
+
const listed = await listRepositoryFiles(root)
|
|
79
|
+
if (listed === undefined) return { kind: 'refused', reason: 'no-git' }
|
|
80
|
+
|
|
81
|
+
const totals = new Map<string, { files: number; lines: number }>()
|
|
82
|
+
let skipped = 0
|
|
83
|
+
let lines = 0
|
|
84
|
+
|
|
85
|
+
for (let start = 0; start < listed.length; start += CONCURRENT_READS) {
|
|
86
|
+
const batch = listed.slice(start, start + CONCURRENT_READS)
|
|
87
|
+
const outcomes = await Promise.all(batch.map((path) => readOne(root, path)))
|
|
88
|
+
|
|
89
|
+
for (const outcome of outcomes) {
|
|
90
|
+
const extension = extensionFor(outcome.path)
|
|
91
|
+
const entry = totals.get(extension) ?? { files: 0, lines: 0 }
|
|
92
|
+
entry.files += 1
|
|
93
|
+
|
|
94
|
+
// A read that failed and a file that read as binary are counted the
|
|
95
|
+
// same way: toward `files`, excluded from every line count.
|
|
96
|
+
if (outcome.text === undefined || isBinary(outcome.text)) {
|
|
97
|
+
skipped += 1
|
|
98
|
+
} else {
|
|
99
|
+
const counted = countLines(outcome.text)
|
|
100
|
+
entry.lines += counted
|
|
101
|
+
lines += counted
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
totals.set(extension, entry)
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const byExtension = [...totals.entries()]
|
|
109
|
+
.map(([extension, counts]) => ({ extension, ...counts }))
|
|
110
|
+
.sort((a, b) => b.files - a.files || a.extension.localeCompare(b.extension))
|
|
111
|
+
|
|
112
|
+
return { kind: 'measured', files: listed.length, skipped, lines, byExtension }
|
|
113
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { SkillCase } from '@/claude/skills-rank'
|
|
2
|
+
import { AUTHORING_CASES } from '@/claude/cases/authoring'
|
|
3
|
+
import { CLAUDE_WORKFLOW_CASES } from '@/claude/cases/claude-workflow'
|
|
4
|
+
import { GIT_CASES } from '@/claude/cases/git'
|
|
5
|
+
import { MISC_CASES } from '@/claude/cases/misc'
|
|
6
|
+
import { SETUP_CASES } from '@/claude/cases/setup'
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* The full routing case corpus, one file per domain so a description change
|
|
10
|
+
* in one family touches only the file beside it.
|
|
11
|
+
*
|
|
12
|
+
* Bootstrapped from each skill's own quoted trigger phrases and then
|
|
13
|
+
* rephrased and supplemented rather than shipped verbatim, since a positive
|
|
14
|
+
* lifted unchanged from a trigger passes by construction and never tests a
|
|
15
|
+
* person's own words. See `.claude/groundwork/42-ai-blueprint/08-spikes.md`
|
|
16
|
+
* for the extraction arm this corpus replaces as the shipped measure.
|
|
17
|
+
*/
|
|
18
|
+
export const SKILL_CASES: readonly SkillCase[] = [
|
|
19
|
+
...CLAUDE_WORKFLOW_CASES,
|
|
20
|
+
...GIT_CASES,
|
|
21
|
+
...SETUP_CASES,
|
|
22
|
+
...AUTHORING_CASES,
|
|
23
|
+
...MISC_CASES,
|
|
24
|
+
]
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type { SkillCase } from '@/claude/skills-rank'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Script, skill, snippet, standard, and doc authoring, plus the two prose
|
|
5
|
+
* skills that revise rather than generate.
|
|
6
|
+
*/
|
|
7
|
+
export const AUTHORING_CASES: readonly SkillCase[] = [
|
|
8
|
+
{
|
|
9
|
+
prompt:
|
|
10
|
+
'I need a shell tool with prompts and a nice terminal UI for people to run by hand.',
|
|
11
|
+
expect: 'bash-script',
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
prompt:
|
|
15
|
+
'Wire up a GitHub Actions pipeline with parallel jobs for this repo.',
|
|
16
|
+
expect: 'ci-workflow',
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
prompt:
|
|
20
|
+
'Write me a headless automation script with no interactive prompts.',
|
|
21
|
+
expect: 'bash-cli-script',
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
prompt: 'Scaffold a brand-new SKILL.md for this capability.',
|
|
25
|
+
expect: 'create-skill',
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
prompt: 'I need a new reusable prompt snippet added to the corpus.',
|
|
29
|
+
expect: 'create-snippet',
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
prompt: 'Write a fresh authoring convention as a new standard file.',
|
|
33
|
+
expect: 'create-standard',
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
prompt:
|
|
37
|
+
"The docs folder and README are stale against what's on main, refresh them.",
|
|
38
|
+
expect: 'docs-sync',
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
prompt: 'Say what that dense answer actually means in plain terms.',
|
|
42
|
+
expect: 'restate-plainly',
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
prompt: 'This passage reads flat and robotic, give it some real cadence.',
|
|
46
|
+
expect: 'write-human',
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
prompt:
|
|
50
|
+
'Pull the captions off this YouTube link and save them with metadata.',
|
|
51
|
+
expect: 'youtube-transcripts',
|
|
52
|
+
},
|
|
53
|
+
]
|