@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,129 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from 'node:fs'
|
|
2
|
+
import { rm } from 'node:fs/promises'
|
|
3
|
+
import { basename, join } from 'node:path'
|
|
4
|
+
import {
|
|
5
|
+
installRules,
|
|
6
|
+
installedRulesDir,
|
|
7
|
+
lookupRules,
|
|
8
|
+
type RuleSource,
|
|
9
|
+
ruleSubdir,
|
|
10
|
+
} from '@/gov/install'
|
|
11
|
+
import { mergeExtraRules, resolveRules } from '@/gov/stacks'
|
|
12
|
+
|
|
13
|
+
export const RECORD_REL = join('internal', 'governance.toml')
|
|
14
|
+
|
|
15
|
+
const INTERNAL_RULES_REL = join('internal', 'rules')
|
|
16
|
+
|
|
17
|
+
/** The stack a repository installs into its own `.claude/rules/`. */
|
|
18
|
+
export interface ConsumedRecord {
|
|
19
|
+
readonly stack: string
|
|
20
|
+
readonly add: readonly string[]
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export type ConsumedResult =
|
|
24
|
+
| { readonly ok: true; readonly installed: readonly string[] }
|
|
25
|
+
| { readonly ok: false; readonly reason: string }
|
|
26
|
+
|
|
27
|
+
export function consumedRecordPath(root: string): string {
|
|
28
|
+
return join(root, RECORD_REL)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function internalRulesDir(root: string): string {
|
|
32
|
+
return join(root, INTERNAL_RULES_REL)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Reads the record naming the consumed stack. A file with no `stack` reads the
|
|
37
|
+
* same as no file at all, since neither tells the producer what to install and
|
|
38
|
+
* the caller's message covers both.
|
|
39
|
+
*/
|
|
40
|
+
export function readConsumedRecord(root: string): ConsumedRecord | undefined {
|
|
41
|
+
const path = consumedRecordPath(root)
|
|
42
|
+
if (!existsSync(path)) return undefined
|
|
43
|
+
|
|
44
|
+
const parsed = Bun.TOML.parse(readFileSync(path, 'utf8')) as Record<
|
|
45
|
+
string,
|
|
46
|
+
unknown
|
|
47
|
+
>
|
|
48
|
+
const stack = typeof parsed.stack === 'string' ? parsed.stack : ''
|
|
49
|
+
if (stack === '') return undefined
|
|
50
|
+
|
|
51
|
+
return {
|
|
52
|
+
stack,
|
|
53
|
+
add: Array.isArray(parsed.add)
|
|
54
|
+
? parsed.add.filter(
|
|
55
|
+
(rule): rule is string => typeof rule === 'string' && rule !== '',
|
|
56
|
+
)
|
|
57
|
+
: [],
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Lists rules authored under `internal/rules/`. These govern toolkit authoring
|
|
63
|
+
* against paths only this repository has, so they install into the consumed
|
|
64
|
+
* copy without ever entering `governance/rules/`, which ships to targets.
|
|
65
|
+
*/
|
|
66
|
+
export function listInternalRules(root: string): RuleSource[] {
|
|
67
|
+
const dir = internalRulesDir(root)
|
|
68
|
+
if (!existsSync(dir)) return []
|
|
69
|
+
|
|
70
|
+
return [...new Bun.Glob('**/*.md').scanSync({ cwd: dir, onlyFiles: true })]
|
|
71
|
+
.sort()
|
|
72
|
+
.map((rel) => {
|
|
73
|
+
const src = join(dir, rel)
|
|
74
|
+
return { rule: basename(rel, '.md'), src, subdir: ruleSubdir(src, dir) }
|
|
75
|
+
})
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Rebuilds a repository's own `.claude/rules/` from its record. Unlike
|
|
80
|
+
* `gov install` and `gov sync`, this runs against the toolkit root on purpose:
|
|
81
|
+
* those two refuse it because a target's rules are the operator's to edit,
|
|
82
|
+
* while this destination is produced output that happens to live beside its
|
|
83
|
+
* source.
|
|
84
|
+
*/
|
|
85
|
+
export async function regenConsumedRules(
|
|
86
|
+
root: string,
|
|
87
|
+
): Promise<ConsumedResult> {
|
|
88
|
+
const record = readConsumedRecord(root)
|
|
89
|
+
if (record === undefined) {
|
|
90
|
+
return { ok: false, reason: `No stack recorded at ${RECORD_REL}` }
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const resolution = resolveRules(root, record.stack)
|
|
94
|
+
if (!resolution.ok) {
|
|
95
|
+
return { ok: false, reason: `Stack not found: ${resolution.missingStack}` }
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const { found, missing } = lookupRules(
|
|
99
|
+
root,
|
|
100
|
+
mergeExtraRules(resolution.rules, record.add.join(',')),
|
|
101
|
+
)
|
|
102
|
+
if (missing.length > 0) {
|
|
103
|
+
return { ok: false, reason: `No source for: ${missing.join(', ')}` }
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const internal = listInternalRules(root)
|
|
107
|
+
const stackRules = new Set(found.map((entry) => entry.rule))
|
|
108
|
+
const shadowed = internal
|
|
109
|
+
.filter((entry) => stackRules.has(entry.rule))
|
|
110
|
+
.map((entry) => entry.rule)
|
|
111
|
+
if (shadowed.length > 0) {
|
|
112
|
+
return {
|
|
113
|
+
ok: false,
|
|
114
|
+
reason: `Internal rules shadow stack rules: ${shadowed.join(', ')}`,
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Clearing first is what makes a rule the record stopped naming disappear.
|
|
119
|
+
// Copying over the destination would leave it behind as an unsourced file,
|
|
120
|
+
// which is the state this producer exists to end.
|
|
121
|
+
await rm(installedRulesDir(root), { recursive: true, force: true })
|
|
122
|
+
|
|
123
|
+
const installed = [
|
|
124
|
+
...(await installRules(found, root)),
|
|
125
|
+
...(await installRules(internal, root)),
|
|
126
|
+
]
|
|
127
|
+
|
|
128
|
+
return { ok: true, installed: installed.sort() }
|
|
129
|
+
}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { existsSync } from 'node:fs'
|
|
2
|
+
import { basename, dirname, join, relative } from 'node:path'
|
|
3
|
+
import { copyPreservingMode } from '@/copy'
|
|
4
|
+
|
|
5
|
+
export interface RuleSource {
|
|
6
|
+
readonly rule: string
|
|
7
|
+
readonly src: string
|
|
8
|
+
readonly subdir: string
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface RuleLookup {
|
|
12
|
+
readonly found: readonly RuleSource[]
|
|
13
|
+
readonly missing: readonly string[]
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function rulesSourceDir(root: string): string {
|
|
17
|
+
return join(root, 'governance', 'rules')
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function installedRulesDir(target: string): string {
|
|
21
|
+
return join(target, '.claude', 'rules')
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Rule names a target already holds, read off the installed tree by basename
|
|
26
|
+
* rather than off a recorded stack, since a target may hold rules `--add`
|
|
27
|
+
* layered on that no stack lists.
|
|
28
|
+
*/
|
|
29
|
+
export function installedRuleNames(target: string): Set<string> {
|
|
30
|
+
const dir = installedRulesDir(target)
|
|
31
|
+
const names = new Set<string>()
|
|
32
|
+
if (!existsSync(dir)) return names
|
|
33
|
+
|
|
34
|
+
for (const rel of new Bun.Glob('**/*.md').scanSync({
|
|
35
|
+
cwd: dir,
|
|
36
|
+
onlyFiles: true,
|
|
37
|
+
dot: true,
|
|
38
|
+
})) {
|
|
39
|
+
names.add(basename(rel, '.md'))
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return names
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Mirrors `rule_subdir` in `scripts/lib/gov.sh`, which stays in bash for the
|
|
47
|
+
* sandbox loops. A rule sitting directly under `governance/rules/` has no
|
|
48
|
+
* subdirectory and installs flat.
|
|
49
|
+
*/
|
|
50
|
+
export function ruleSubdir(src: string, rulesRoot: string): string {
|
|
51
|
+
const subdir = dirname(relative(rulesRoot, src))
|
|
52
|
+
return subdir === '.' ? '' : subdir
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Lists every rule source path under `governance/rules/`, relative to it and
|
|
57
|
+
* sorted, so a caller walking the tree and a caller resolving one name read the
|
|
58
|
+
* same order.
|
|
59
|
+
*/
|
|
60
|
+
export function listRuleSourcePaths(root: string): string[] {
|
|
61
|
+
const rulesRoot = rulesSourceDir(root)
|
|
62
|
+
if (!existsSync(rulesRoot)) return []
|
|
63
|
+
|
|
64
|
+
return [
|
|
65
|
+
...new Bun.Glob('**/*.md').scanSync({ cwd: rulesRoot, onlyFiles: true }),
|
|
66
|
+
].sort()
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Maps each rule name to its source file. First path wins, so a name appearing
|
|
71
|
+
* in two subdirectories resolves deterministically rather than by whichever
|
|
72
|
+
* entry the filesystem yielded first.
|
|
73
|
+
*/
|
|
74
|
+
function indexRuleSources(root: string): Map<string, string> {
|
|
75
|
+
const rulesRoot = rulesSourceDir(root)
|
|
76
|
+
const byName = new Map<string, string>()
|
|
77
|
+
|
|
78
|
+
for (const rel of listRuleSourcePaths(root)) {
|
|
79
|
+
const name = rel.slice(rel.lastIndexOf('/') + 1, -'.md'.length)
|
|
80
|
+
if (!byName.has(name)) byName.set(name, join(rulesRoot, rel))
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return byName
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Finds each rule's source file by name across the `governance/rules/`
|
|
88
|
+
* subfolders. A rule with no source is reported rather than dropped, matching
|
|
89
|
+
* the `(source not found, skipping)` warning the bash printed.
|
|
90
|
+
*/
|
|
91
|
+
export function lookupRules(
|
|
92
|
+
root: string,
|
|
93
|
+
rules: readonly string[],
|
|
94
|
+
): RuleLookup {
|
|
95
|
+
const rulesRoot = rulesSourceDir(root)
|
|
96
|
+
const byName = indexRuleSources(root)
|
|
97
|
+
|
|
98
|
+
const found: RuleSource[] = []
|
|
99
|
+
const missing: string[] = []
|
|
100
|
+
|
|
101
|
+
for (const rule of rules) {
|
|
102
|
+
const src = byName.get(rule)
|
|
103
|
+
if (src === undefined) {
|
|
104
|
+
missing.push(rule)
|
|
105
|
+
continue
|
|
106
|
+
}
|
|
107
|
+
found.push({ rule, src, subdir: ruleSubdir(src, rulesRoot) })
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return { found, missing }
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Copies each rule into the subdirectory it was authored in, so the installed
|
|
115
|
+
* tree keeps the band structure `governance/rules/` carries. Returns the
|
|
116
|
+
* target-relative paths the timeline prints.
|
|
117
|
+
*/
|
|
118
|
+
export async function installRules(
|
|
119
|
+
sources: readonly RuleSource[],
|
|
120
|
+
target: string,
|
|
121
|
+
): Promise<string[]> {
|
|
122
|
+
const rulesDir = installedRulesDir(target)
|
|
123
|
+
const installed: string[] = []
|
|
124
|
+
|
|
125
|
+
for (const source of sources) {
|
|
126
|
+
const dest = join(rulesDir, source.subdir, `${source.rule}.md`)
|
|
127
|
+
await copyPreservingMode(source.src, dest)
|
|
128
|
+
installed.push(relative(target, dest))
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
return installed
|
|
132
|
+
}
|
package/src/gov/list.ts
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs'
|
|
2
|
+
import { basename, join } from 'node:path'
|
|
3
|
+
import { listRuleSourcePaths, rulesSourceDir } from '@/gov/install'
|
|
4
|
+
import {
|
|
5
|
+
expandStackEntry,
|
|
6
|
+
listGovStacks,
|
|
7
|
+
loadGovStack,
|
|
8
|
+
unreferencedRules,
|
|
9
|
+
} from '@/gov/stacks'
|
|
10
|
+
import { parseFrontmatter, readField } from '@/indexes/frontmatter'
|
|
11
|
+
|
|
12
|
+
export interface StackEntry {
|
|
13
|
+
readonly name: string
|
|
14
|
+
readonly extends: string | null
|
|
15
|
+
readonly rules: string[]
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface RuleEntry {
|
|
19
|
+
readonly name: string
|
|
20
|
+
readonly domain: string
|
|
21
|
+
readonly description: string
|
|
22
|
+
readonly paths: string[] | null
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface GovCatalog {
|
|
26
|
+
readonly stacks: StackEntry[]
|
|
27
|
+
readonly rules: RuleEntry[]
|
|
28
|
+
readonly unreferenced: string[]
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Reports each stack's own entries expanded, so a folder entry reaches a
|
|
33
|
+
* consumer as the rules it stands for. `setup-gov` dedupes `--add` extras
|
|
34
|
+
* against this list, and a stack answering `core` there would re-add every
|
|
35
|
+
* rule that folder already carries.
|
|
36
|
+
*
|
|
37
|
+
* The `extends` chain is deliberately not resolved, which is what the bash
|
|
38
|
+
* did. The list shows what each stack contributes beside the parent it
|
|
39
|
+
* inherits from, rather than repeating the ancestors under every descendant.
|
|
40
|
+
*/
|
|
41
|
+
export function buildStackEntries(root: string): StackEntry[] {
|
|
42
|
+
const entries: StackEntry[] = []
|
|
43
|
+
|
|
44
|
+
for (const name of listGovStacks(root)) {
|
|
45
|
+
const stack = loadGovStack(root, name)
|
|
46
|
+
if (!stack) continue
|
|
47
|
+
|
|
48
|
+
const seen = new Set<string>()
|
|
49
|
+
const rules: string[] = []
|
|
50
|
+
|
|
51
|
+
for (const entry of stack.rules) {
|
|
52
|
+
for (const rule of expandStackEntry(root, entry)) {
|
|
53
|
+
if (seen.has(rule)) continue
|
|
54
|
+
seen.add(rule)
|
|
55
|
+
rules.push(rule)
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
entries.push({ name, extends: stack.parent ?? null, rules })
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return entries
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Reads the catalog straight off the source tree. A rule's domain is the
|
|
67
|
+
* subdirectory it sits in, which is the band grouping install preserves.
|
|
68
|
+
*/
|
|
69
|
+
export function buildRuleEntries(root: string): RuleEntry[] {
|
|
70
|
+
const rulesRoot = rulesSourceDir(root)
|
|
71
|
+
|
|
72
|
+
return listRuleSourcePaths(root).map((rel) => {
|
|
73
|
+
const frontmatter = parseFrontmatter(
|
|
74
|
+
readFileSync(join(rulesRoot, rel), 'utf8'),
|
|
75
|
+
)
|
|
76
|
+
const paths = frontmatter?.fields.paths
|
|
77
|
+
|
|
78
|
+
return {
|
|
79
|
+
name: basename(rel, '.md'),
|
|
80
|
+
domain: rel.includes('/') ? rel.slice(0, rel.indexOf('/')) : '',
|
|
81
|
+
description: readField(frontmatter, 'description') ?? '',
|
|
82
|
+
paths: Array.isArray(paths)
|
|
83
|
+
? paths.filter((entry): entry is string => typeof entry === 'string')
|
|
84
|
+
: null,
|
|
85
|
+
}
|
|
86
|
+
})
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export function buildGovCatalog(root: string): GovCatalog {
|
|
90
|
+
return {
|
|
91
|
+
stacks: buildStackEntries(root),
|
|
92
|
+
rules: buildRuleEntries(root),
|
|
93
|
+
unreferenced: unreferencedRules(root),
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export function describeStack(entry: StackEntry): string {
|
|
98
|
+
const count = `${entry.rules.length} rules`
|
|
99
|
+
return entry.extends === null
|
|
100
|
+
? `${entry.name} (${count})`
|
|
101
|
+
: `${entry.name} (extends: ${entry.extends}, ${count})`
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export function describeRule(entry: RuleEntry): string {
|
|
105
|
+
return `${entry.name} [${entry.domain}] ${entry.description}`
|
|
106
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs'
|
|
2
|
+
import { basename, resolve } from 'node:path'
|
|
3
|
+
import { stripFrontmatter } from '@/frontmatter'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Lists installed rules in the order the payload concatenates them. Sorting by
|
|
7
|
+
* path keeps the numeric filename prefixes ordered inside each subdirectory,
|
|
8
|
+
* which is how the rule bands are meant to read.
|
|
9
|
+
*/
|
|
10
|
+
export function listRuleFiles(rulesDir: string): string[] {
|
|
11
|
+
return [
|
|
12
|
+
...new Bun.Glob('**/*.md').scanSync({
|
|
13
|
+
cwd: rulesDir,
|
|
14
|
+
onlyFiles: true,
|
|
15
|
+
dot: true,
|
|
16
|
+
}),
|
|
17
|
+
]
|
|
18
|
+
.sort()
|
|
19
|
+
.map((path) => resolve(rulesDir, path))
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Wraps each rule in a named tag so a model reading the payload can tell the
|
|
24
|
+
* rules apart without the file boundaries. Bodies are trimmed of blank lines
|
|
25
|
+
* at both ends and separated by exactly one blank line.
|
|
26
|
+
*/
|
|
27
|
+
export function buildRulesPayload(files: readonly string[]): string {
|
|
28
|
+
const blocks = files.map((file) => {
|
|
29
|
+
const name = basename(file, '.md')
|
|
30
|
+
const body = trimBlankLines(stripFrontmatter(readFileSync(file, 'utf8')))
|
|
31
|
+
return `<rule name="${name}">\n${body}\n</rule>`
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
return `${blocks.join('\n\n')}\n`
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function trimBlankLines(source: string): string {
|
|
38
|
+
return source.replace(/^(?:[ \t]*\n)+/, '').replace(/(?:\n[ \t]*)+$/, '')
|
|
39
|
+
}
|