@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,201 @@
|
|
|
1
|
+
import { basename, dirname, resolve } from 'node:path'
|
|
2
|
+
import { readField, readFrontmatter } from '@/indexes/frontmatter'
|
|
3
|
+
import { INDEX_FILE, listIndexes } from '@/indexes/walk'
|
|
4
|
+
|
|
5
|
+
export interface IndexEntry {
|
|
6
|
+
readonly name: string
|
|
7
|
+
readonly title: string
|
|
8
|
+
readonly description: string
|
|
9
|
+
readonly category?: string
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface SubCatalog {
|
|
13
|
+
readonly name: string
|
|
14
|
+
readonly title: string
|
|
15
|
+
readonly subtitle: string
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export type RenderResult =
|
|
19
|
+
| { readonly ok: true; readonly content: string }
|
|
20
|
+
| { readonly ok: false; readonly errors: string[] }
|
|
21
|
+
|
|
22
|
+
interface IndexHead {
|
|
23
|
+
readonly raw: string
|
|
24
|
+
readonly title: string
|
|
25
|
+
readonly subtitle: string
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Builds a folder's `index.md` from its own frontmatter plus every sibling's.
|
|
30
|
+
*
|
|
31
|
+
* Frontmatter is re-emitted verbatim rather than re-serialized, so key order
|
|
32
|
+
* and any `auto: false` marker survive a regeneration untouched.
|
|
33
|
+
*/
|
|
34
|
+
export async function computeIndex(dir: string): Promise<RenderResult> {
|
|
35
|
+
const indexPath = `${dir}/${INDEX_FILE}`
|
|
36
|
+
const head = await readIndexHead(indexPath)
|
|
37
|
+
if (!head.ok) return head
|
|
38
|
+
|
|
39
|
+
const entries = await collectEntries(dir)
|
|
40
|
+
if (!entries.ok) return entries
|
|
41
|
+
|
|
42
|
+
const subCatalogs = await collectSubCatalogs(dir)
|
|
43
|
+
|
|
44
|
+
return {
|
|
45
|
+
ok: true,
|
|
46
|
+
content: renderIndex(head.head, entries.entries, subCatalogs),
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
async function readIndexHead(
|
|
51
|
+
indexPath: string,
|
|
52
|
+
): Promise<{ ok: true; head: IndexHead } | { ok: false; errors: string[] }> {
|
|
53
|
+
const frontmatter = await readFrontmatter(indexPath)
|
|
54
|
+
const title = readField(frontmatter, 'title')
|
|
55
|
+
const subtitle = readField(frontmatter, 'subtitle')
|
|
56
|
+
|
|
57
|
+
const errors: string[] = []
|
|
58
|
+
if (!title) errors.push(`missing frontmatter field "title" in ${indexPath}`)
|
|
59
|
+
if (!subtitle) {
|
|
60
|
+
errors.push(`missing frontmatter field "subtitle" in ${indexPath}`)
|
|
61
|
+
}
|
|
62
|
+
if (!frontmatter || !title || !subtitle) return { ok: false, errors }
|
|
63
|
+
|
|
64
|
+
return { ok: true, head: { raw: frontmatter.raw, title, subtitle } }
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
async function collectEntries(
|
|
68
|
+
dir: string,
|
|
69
|
+
): Promise<
|
|
70
|
+
{ ok: true; entries: IndexEntry[] } | { ok: false; errors: string[] }
|
|
71
|
+
> {
|
|
72
|
+
const glob = new Bun.Glob('*.md')
|
|
73
|
+
const paths: string[] = []
|
|
74
|
+
|
|
75
|
+
for await (const rel of glob.scan({ cwd: dir, onlyFiles: true, dot: true })) {
|
|
76
|
+
if (rel === INDEX_FILE) continue
|
|
77
|
+
paths.push(resolve(dir, rel))
|
|
78
|
+
}
|
|
79
|
+
paths.sort()
|
|
80
|
+
|
|
81
|
+
const entries: IndexEntry[] = []
|
|
82
|
+
const errors: string[] = []
|
|
83
|
+
|
|
84
|
+
for (const path of paths) {
|
|
85
|
+
const frontmatter = await readFrontmatter(path)
|
|
86
|
+
const title = readField(frontmatter, 'title')
|
|
87
|
+
const description = readField(frontmatter, 'description')
|
|
88
|
+
|
|
89
|
+
if (!title) errors.push(`missing frontmatter field "title" in ${path}`)
|
|
90
|
+
if (!description) {
|
|
91
|
+
errors.push(`missing frontmatter field "description" in ${path}`)
|
|
92
|
+
}
|
|
93
|
+
if (!title || !description) continue
|
|
94
|
+
|
|
95
|
+
entries.push({
|
|
96
|
+
name: basename(path),
|
|
97
|
+
title,
|
|
98
|
+
description,
|
|
99
|
+
category: readField(frontmatter, 'category'),
|
|
100
|
+
})
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (errors.length > 0) {
|
|
104
|
+
errors.push(`${errors.length} missing frontmatter field(s) in ${dir}`)
|
|
105
|
+
return { ok: false, errors }
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
return { ok: true, entries }
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Reuses the shared walker so nested discovery inherits the same prune and
|
|
113
|
+
* gitignore rules, then keeps only direct children of this folder.
|
|
114
|
+
*/
|
|
115
|
+
async function collectSubCatalogs(dir: string): Promise<SubCatalog[]> {
|
|
116
|
+
const nested = await listIndexes(dir)
|
|
117
|
+
const catalogs: SubCatalog[] = []
|
|
118
|
+
|
|
119
|
+
for (const indexPath of nested.sort()) {
|
|
120
|
+
const childDir = dirname(indexPath)
|
|
121
|
+
if (dirname(childDir) !== resolve(dir)) continue
|
|
122
|
+
|
|
123
|
+
const frontmatter = await readFrontmatter(indexPath)
|
|
124
|
+
const title = readField(frontmatter, 'title')
|
|
125
|
+
const subtitle = readField(frontmatter, 'subtitle')
|
|
126
|
+
|
|
127
|
+
if (!title || !subtitle) {
|
|
128
|
+
process.stderr.write(
|
|
129
|
+
`WARNING: skipping nested index ${childDir}/${INDEX_FILE} (missing title or subtitle)\n`,
|
|
130
|
+
)
|
|
131
|
+
continue
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
catalogs.push({ name: basename(childDir), title, subtitle })
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
return catalogs
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function renderIndex(
|
|
141
|
+
head: IndexHead,
|
|
142
|
+
entries: IndexEntry[],
|
|
143
|
+
subCatalogs: SubCatalog[],
|
|
144
|
+
): string {
|
|
145
|
+
const hasCategories = entries.some((entry) => Boolean(entry.category))
|
|
146
|
+
|
|
147
|
+
let out = `${head.raw}\n\n# ${head.title}\n\n${head.subtitle}\n`
|
|
148
|
+
if (entries.length > 0 || subCatalogs.length > 0) out += '\n'
|
|
149
|
+
|
|
150
|
+
if (hasCategories) {
|
|
151
|
+
const categories = [
|
|
152
|
+
...new Set(entries.map((entry) => entry.category).filter(Boolean)),
|
|
153
|
+
].sort() as string[]
|
|
154
|
+
|
|
155
|
+
categories.forEach((category, position) => {
|
|
156
|
+
if (position > 0) out += '\n'
|
|
157
|
+
out += `## ${category}\n\n`
|
|
158
|
+
for (const entry of entries) {
|
|
159
|
+
if (entry.category !== category) continue
|
|
160
|
+
out += formatEntry(entry)
|
|
161
|
+
}
|
|
162
|
+
})
|
|
163
|
+
} else {
|
|
164
|
+
/**
|
|
165
|
+
* Flat mode sorts sub-catalogs among the files rather than after them. A
|
|
166
|
+
* folder and a file are both one domain to a reader scanning the catalog,
|
|
167
|
+
* so a trailing folder reads as absent from the alphabetical run it belongs
|
|
168
|
+
* in. Grouped mode keeps its own heading below, where a category is the
|
|
169
|
+
* organizing key and alphabetical position carries no meaning.
|
|
170
|
+
*/
|
|
171
|
+
const lines = [
|
|
172
|
+
...entries.map((entry) => ({
|
|
173
|
+
key: entry.name,
|
|
174
|
+
text: formatEntry(entry),
|
|
175
|
+
})),
|
|
176
|
+
...subCatalogs.map((catalog) => ({
|
|
177
|
+
key: catalog.name,
|
|
178
|
+
text: formatSubCatalog(catalog),
|
|
179
|
+
})),
|
|
180
|
+
].sort((a, b) => (a.key < b.key ? -1 : a.key > b.key ? 1 : 0))
|
|
181
|
+
|
|
182
|
+
for (const line of lines) out += line.text
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
if (hasCategories && subCatalogs.length > 0) {
|
|
186
|
+
out += '\n## Sub-catalogs\n\n'
|
|
187
|
+
for (const catalog of subCatalogs) {
|
|
188
|
+
out += formatSubCatalog(catalog)
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
return out
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
function formatSubCatalog(catalog: SubCatalog): string {
|
|
196
|
+
return `- [${catalog.title}](${catalog.name}/${INDEX_FILE}): ${catalog.subtitle}\n`
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
function formatEntry(entry: IndexEntry): string {
|
|
200
|
+
return `- [${entry.title}](${entry.name}): ${entry.description}\n`
|
|
201
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { existsSync, statSync } from 'node:fs'
|
|
2
|
+
import { dirname, resolve } from 'node:path'
|
|
3
|
+
import { listIgnored } from '@/git-ignore'
|
|
4
|
+
|
|
5
|
+
const INDEX_FILE = 'index.md'
|
|
6
|
+
|
|
7
|
+
const PRUNED_SEGMENTS = ['node_modules', '.git']
|
|
8
|
+
|
|
9
|
+
function isPruned(relativePath: string): boolean {
|
|
10
|
+
return relativePath
|
|
11
|
+
.split('/')
|
|
12
|
+
.some((segment) => PRUNED_SEGMENTS.includes(segment))
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Lists every folder index under `root`.
|
|
17
|
+
*
|
|
18
|
+
* Vendored and git trees are pruned by path segment, since `Bun.Glob` has no
|
|
19
|
+
* exclude. Everything else is dropped via `git check-ignore`, so a project's
|
|
20
|
+
* own `.gitignore` governs what the walker sees. Outside a git repo the
|
|
21
|
+
* segment prune is the only filter that applies.
|
|
22
|
+
*/
|
|
23
|
+
export async function listIndexes(root: string): Promise<string[]> {
|
|
24
|
+
const glob = new Bun.Glob(`**/${INDEX_FILE}`)
|
|
25
|
+
const candidates: string[] = []
|
|
26
|
+
|
|
27
|
+
for await (const rel of glob.scan({
|
|
28
|
+
cwd: root,
|
|
29
|
+
onlyFiles: true,
|
|
30
|
+
dot: true,
|
|
31
|
+
})) {
|
|
32
|
+
if (isPruned(rel)) continue
|
|
33
|
+
candidates.push(resolve(root, rel))
|
|
34
|
+
}
|
|
35
|
+
candidates.sort()
|
|
36
|
+
|
|
37
|
+
if (candidates.length === 0) return []
|
|
38
|
+
|
|
39
|
+
const ignored = await listIgnored(root, candidates)
|
|
40
|
+
if (ignored.size === 0) return candidates
|
|
41
|
+
|
|
42
|
+
return candidates.filter((path) => !ignored.has(path))
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Reports whether git ignores `path`.
|
|
47
|
+
*
|
|
48
|
+
* Positional regen reaches an ignored folder, because `findIndexedAncestor`
|
|
49
|
+
* walks the filesystem and never consults git. Staging what it writes there
|
|
50
|
+
* always fails, so the caller checks this first and skips the attempt rather
|
|
51
|
+
* than warning on a no-op.
|
|
52
|
+
*/
|
|
53
|
+
export async function isIgnored(root: string, path: string): Promise<boolean> {
|
|
54
|
+
const ignored = await listIgnored(root, [resolve(path)])
|
|
55
|
+
return ignored.has(resolve(path))
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Walks up from `path` to the nearest folder holding an index, stopping at
|
|
60
|
+
* `root`. Returns undefined when the path escapes the boundary or nothing
|
|
61
|
+
* indexed is found.
|
|
62
|
+
*/
|
|
63
|
+
export function findIndexedAncestor(
|
|
64
|
+
path: string,
|
|
65
|
+
root: string,
|
|
66
|
+
): string | undefined {
|
|
67
|
+
if (!existsSync(path)) return undefined
|
|
68
|
+
|
|
69
|
+
const rootAbs = resolve(root)
|
|
70
|
+
let dir = statSync(path).isDirectory()
|
|
71
|
+
? resolve(path)
|
|
72
|
+
: dirname(resolve(path))
|
|
73
|
+
|
|
74
|
+
while (dir === rootAbs || dir.startsWith(`${rootAbs}/`)) {
|
|
75
|
+
if (existsSync(`${dir}/${INDEX_FILE}`)) return dir
|
|
76
|
+
if (dir === rootAbs) return undefined
|
|
77
|
+
dir = dirname(dir)
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return undefined
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export { INDEX_FILE, PRUNED_SEGMENTS }
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import type { Command } from 'commander'
|
|
2
|
+
import { DEFAULT_STACK, SKIPPABLE_DOMAINS } from '@/init/plan'
|
|
3
|
+
|
|
4
|
+
interface InitOptionSpec {
|
|
5
|
+
/** The option value key commander stores the parsed value under. */
|
|
6
|
+
readonly key: string
|
|
7
|
+
readonly flags: string
|
|
8
|
+
readonly description: string
|
|
9
|
+
readonly defaultValue?: string
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* The option surface of `canon init`, declared once so the flag list and the
|
|
14
|
+
* provenance check cannot drift apart. Reading the key from the spec is what
|
|
15
|
+
* keeps a renamed flag from silently dropping out of `flagsProvided`.
|
|
16
|
+
*/
|
|
17
|
+
export const INIT_OPTIONS: readonly InitOptionSpec[] = [
|
|
18
|
+
{
|
|
19
|
+
key: 'stack',
|
|
20
|
+
flags: '--stack <name>',
|
|
21
|
+
description: 'Governance stack (e.g., base, astro, react)',
|
|
22
|
+
defaultValue: DEFAULT_STACK,
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
key: 'add',
|
|
26
|
+
flags: '--add <rules>',
|
|
27
|
+
description: 'Comma-separated governance rules to layer on',
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
key: 'skip',
|
|
31
|
+
flags: '--skip <list>',
|
|
32
|
+
description: `Skip core domains: ${SKIPPABLE_DOMAINS.join(', ')}`,
|
|
33
|
+
},
|
|
34
|
+
]
|
|
35
|
+
|
|
36
|
+
/** Declares every init option on the command, defaults included. */
|
|
37
|
+
export function applyInitOptions(command: Command): Command {
|
|
38
|
+
for (const option of INIT_OPTIONS) {
|
|
39
|
+
if (option.defaultValue === undefined) {
|
|
40
|
+
command.option(option.flags, option.description)
|
|
41
|
+
continue
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
command.option(option.flags, option.description, option.defaultValue)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return command
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Whether the operator passed any flag, which is what makes the command
|
|
52
|
+
* scriptable by suppressing the confirmation prompt. `--stack` carries a
|
|
53
|
+
* default, so presence has to be read from where the value came from rather
|
|
54
|
+
* than from the value itself.
|
|
55
|
+
*/
|
|
56
|
+
export function flagsProvided(cmd: Command): boolean {
|
|
57
|
+
return INIT_OPTIONS.some(
|
|
58
|
+
(option) => cmd.getOptionValueSource(option.key) === 'cli',
|
|
59
|
+
)
|
|
60
|
+
}
|
package/src/init/plan.ts
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
export const SKIPPABLE_DOMAINS = ['wiki', 'governance'] as const
|
|
2
|
+
|
|
3
|
+
export type SkippableDomain = (typeof SKIPPABLE_DOMAINS)[number]
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* The stack a caller gets without asking. Governance installs on every init so
|
|
7
|
+
* a scaffolded project arrives with the rules that route it, and
|
|
8
|
+
* `--skip governance` is the one spelling for declining.
|
|
9
|
+
*/
|
|
10
|
+
export const DEFAULT_STACK = 'base'
|
|
11
|
+
|
|
12
|
+
export interface SkipPlan {
|
|
13
|
+
readonly skipped: ReadonlySet<SkippableDomain>
|
|
14
|
+
/** Values that named nothing skippable. Warned about, never fatal. */
|
|
15
|
+
readonly unknown: readonly string[]
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export type PreviewLevel = 'info' | 'warn'
|
|
19
|
+
|
|
20
|
+
export interface PreviewLine {
|
|
21
|
+
readonly level: PreviewLevel
|
|
22
|
+
readonly text: string
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface InitPlan {
|
|
26
|
+
readonly preview: readonly PreviewLine[]
|
|
27
|
+
readonly total: number
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export interface InitFlags {
|
|
31
|
+
readonly stack?: string
|
|
32
|
+
readonly add?: string
|
|
33
|
+
readonly skip: SkipPlan
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Resolves the stack the run will install. An empty `--stack` reads as absent
|
|
38
|
+
* rather than as a way to decline, so the flag carries a real name or nothing
|
|
39
|
+
* and `--skip governance` stays the only spelling for opting out.
|
|
40
|
+
*/
|
|
41
|
+
export function resolveStack(stack: string | undefined): string {
|
|
42
|
+
return stack === undefined || stack === '' ? DEFAULT_STACK : stack
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Reads the `--skip` list. An unrecognized value is reported and dropped rather
|
|
47
|
+
* than aborting, because the flag names optional domains and a typo should not
|
|
48
|
+
* cost the operator the whole init.
|
|
49
|
+
*/
|
|
50
|
+
export function parseSkip(csv: string | undefined): SkipPlan {
|
|
51
|
+
const skipped = new Set<SkippableDomain>()
|
|
52
|
+
const unknown: string[] = []
|
|
53
|
+
|
|
54
|
+
for (const raw of (csv ?? '').split(',')) {
|
|
55
|
+
const item = raw.trim()
|
|
56
|
+
if (item === '') continue
|
|
57
|
+
|
|
58
|
+
if (isSkippable(item)) skipped.add(item)
|
|
59
|
+
else unknown.push(item)
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return { skipped, unknown }
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Builds the preview and the count from one pass, so the two cannot disagree.
|
|
67
|
+
* Every `info` line is a domain that will run, which is what makes the count a
|
|
68
|
+
* filter rather than a second tally kept in step by hand. A skipped domain
|
|
69
|
+
* prints nothing at all and declined governance prints a warning, so neither
|
|
70
|
+
* reaches the total.
|
|
71
|
+
*
|
|
72
|
+
* The skip drops `--add`, which names rules the caller asked for. Input
|
|
73
|
+
* that goes nowhere is reported for the same reason `parseSkip` reports an
|
|
74
|
+
* unrecognized value, so the warning names the flag rather than dropping it
|
|
75
|
+
* without a word.
|
|
76
|
+
*/
|
|
77
|
+
export function planInit(flags: InitFlags): InitPlan {
|
|
78
|
+
const preview: PreviewLine[] = [
|
|
79
|
+
{ level: 'info', text: 'base tooling (configs, seeds, deps, scripts)' },
|
|
80
|
+
{ level: 'info', text: 'claude (workflow docs, settings)' },
|
|
81
|
+
]
|
|
82
|
+
|
|
83
|
+
const stack = resolveStack(flags.stack)
|
|
84
|
+
|
|
85
|
+
if (flags.skip.skipped.has('governance')) {
|
|
86
|
+
const detail =
|
|
87
|
+
flags.add === undefined || flags.add === ''
|
|
88
|
+
? ''
|
|
89
|
+
: `, --add ${flags.add} not installed`
|
|
90
|
+
preview.push({ level: 'warn', text: `governance (skipped${detail})` })
|
|
91
|
+
} else if (flags.add === undefined || flags.add === '') {
|
|
92
|
+
preview.push({ level: 'info', text: `governance (stack: ${stack})` })
|
|
93
|
+
} else {
|
|
94
|
+
preview.push({
|
|
95
|
+
level: 'info',
|
|
96
|
+
text: `governance (stack: ${stack}, extras: ${flags.add})`,
|
|
97
|
+
})
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (!flags.skip.skipped.has('wiki')) {
|
|
101
|
+
preview.push({
|
|
102
|
+
level: 'info',
|
|
103
|
+
text: 'wiki (.claude/wiki/ with a stub index)',
|
|
104
|
+
})
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const total = preview.filter((line) => line.level === 'info').length
|
|
108
|
+
|
|
109
|
+
return { preview, total }
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function isSkippable(value: string): value is SkippableDomain {
|
|
113
|
+
return (SKIPPABLE_DOMAINS as readonly string[]).includes(value)
|
|
114
|
+
}
|
package/src/init/run.ts
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { logInfo, logStep, logWarn } from '@/ui'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* A domain either runs or announces why it did not. Governance under
|
|
5
|
+
* `--skip governance` is the second kind: it reports in sequence so the
|
|
6
|
+
* timeline still accounts for every core domain, without counting as a failure.
|
|
7
|
+
*/
|
|
8
|
+
export type DomainStep =
|
|
9
|
+
| { readonly kind: 'run'; readonly label: string; run(): Promise<boolean> }
|
|
10
|
+
| { readonly kind: 'skip'; readonly label: string; readonly notice: string }
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Runs each step in order and returns the labels that failed.
|
|
14
|
+
*
|
|
15
|
+
* Partial failure is a first-class outcome rather than an error path. An init
|
|
16
|
+
* that aborts on the first failing domain would look tidier and leave the
|
|
17
|
+
* operator with no idea which of the remaining domains would have worked, so
|
|
18
|
+
* the run continues and the caller reports the failures at the end.
|
|
19
|
+
*
|
|
20
|
+
* The sequence is deliberate. Base tooling seeds the files the later domains
|
|
21
|
+
* install alongside, so these are not independent operations to batch.
|
|
22
|
+
*/
|
|
23
|
+
export async function runDomains(
|
|
24
|
+
steps: readonly DomainStep[],
|
|
25
|
+
): Promise<string[]> {
|
|
26
|
+
const failed: string[] = []
|
|
27
|
+
|
|
28
|
+
for (const step of steps) {
|
|
29
|
+
logStep(step.label)
|
|
30
|
+
|
|
31
|
+
if (step.kind === 'skip') {
|
|
32
|
+
logWarn(step.notice)
|
|
33
|
+
continue
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (await step.run()) {
|
|
37
|
+
logInfo('Done')
|
|
38
|
+
continue
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
logWarn('Failed, run manually')
|
|
42
|
+
failed.push(step.label)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return failed
|
|
46
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { type InitFlags, resolveStack } from '@/init/plan'
|
|
2
|
+
import type { DomainStep } from '@/init/run'
|
|
3
|
+
|
|
4
|
+
/** Builds the child-process invocation for one domain. */
|
|
5
|
+
export type RunFactory = (args: readonly string[]) => () => Promise<boolean>
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Orders the domains an init installs. Base tooling seeds the files the later
|
|
9
|
+
* domains install alongside, so the sequence is part of the contract rather
|
|
10
|
+
* than an arbitrary listing.
|
|
11
|
+
*
|
|
12
|
+
* The caller supplies the run factory so the list can be read for its labels
|
|
13
|
+
* and kinds without spawning anything.
|
|
14
|
+
*/
|
|
15
|
+
export function buildSteps(
|
|
16
|
+
target: string,
|
|
17
|
+
resolved: string,
|
|
18
|
+
flags: InitFlags,
|
|
19
|
+
child: RunFactory,
|
|
20
|
+
): DomainStep[] {
|
|
21
|
+
const steps: DomainStep[] = [
|
|
22
|
+
{
|
|
23
|
+
kind: 'run',
|
|
24
|
+
label: 'Base tooling',
|
|
25
|
+
run: child(['tooling', 'sync', 'base', resolved, '--write']),
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
kind: 'run',
|
|
29
|
+
label: 'Claude workflow',
|
|
30
|
+
run: child(['claude', 'init', resolved]),
|
|
31
|
+
},
|
|
32
|
+
]
|
|
33
|
+
|
|
34
|
+
const stack = resolveStack(flags.stack)
|
|
35
|
+
|
|
36
|
+
if (flags.skip.skipped.has('governance')) {
|
|
37
|
+
const recovery = govArgs(stack, flags.add, target).join(' ')
|
|
38
|
+
steps.push({
|
|
39
|
+
kind: 'skip',
|
|
40
|
+
label: 'Governance',
|
|
41
|
+
notice: `Skipped: --skip governance. Run 'canon ${recovery}' to install rules.`,
|
|
42
|
+
})
|
|
43
|
+
} else {
|
|
44
|
+
steps.push({
|
|
45
|
+
kind: 'run',
|
|
46
|
+
label: 'Governance',
|
|
47
|
+
run: child(govArgs(stack, flags.add, resolved)),
|
|
48
|
+
})
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (!flags.skip.skipped.has('wiki')) {
|
|
52
|
+
steps.push({
|
|
53
|
+
kind: 'run',
|
|
54
|
+
label: 'Wiki',
|
|
55
|
+
run: child(['wiki', 'init', resolved]),
|
|
56
|
+
})
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return steps
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Builds the `gov install` argv. The run and the recovery command a skip prints
|
|
64
|
+
* come from here both, so the command a caller is told to paste installs what
|
|
65
|
+
* the run would have.
|
|
66
|
+
*/
|
|
67
|
+
function govArgs(
|
|
68
|
+
stack: string,
|
|
69
|
+
add: string | undefined,
|
|
70
|
+
path: string,
|
|
71
|
+
): string[] {
|
|
72
|
+
const args = ['gov', 'install', stack]
|
|
73
|
+
if (add !== undefined && add !== '') args.push('--add', add)
|
|
74
|
+
args.push(path)
|
|
75
|
+
|
|
76
|
+
return args
|
|
77
|
+
}
|