@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,573 @@
|
|
|
1
|
+
import { resolve } from 'node:path'
|
|
2
|
+
import type { Command } from 'commander'
|
|
3
|
+
import { execScript } from '@/exec'
|
|
4
|
+
import { PROJECT_ROOT } from '@/project-root'
|
|
5
|
+
import {
|
|
6
|
+
injectConfigs,
|
|
7
|
+
injectGitignore,
|
|
8
|
+
injectManifest,
|
|
9
|
+
injectSeeds,
|
|
10
|
+
pruneGitignore,
|
|
11
|
+
} from '@/tooling/inject'
|
|
12
|
+
import { buildStackSummaries, describeStack } from '@/tooling/list'
|
|
13
|
+
import {
|
|
14
|
+
isStackExcluded,
|
|
15
|
+
listStacks,
|
|
16
|
+
type Manifest,
|
|
17
|
+
resolveChain,
|
|
18
|
+
stackExists,
|
|
19
|
+
} from '@/tooling/manifest'
|
|
20
|
+
import { readReference, resolveReference } from '@/tooling/read'
|
|
21
|
+
import { scan, type ScanResult } from '@/tooling/scan'
|
|
22
|
+
import { recordToolingChain } from '@/tooling/stamp'
|
|
23
|
+
import {
|
|
24
|
+
intro,
|
|
25
|
+
isNonInteractive,
|
|
26
|
+
logAdd,
|
|
27
|
+
logError,
|
|
28
|
+
logInfo,
|
|
29
|
+
logStep,
|
|
30
|
+
logWarn,
|
|
31
|
+
outro,
|
|
32
|
+
palette,
|
|
33
|
+
select,
|
|
34
|
+
} from '@/ui'
|
|
35
|
+
|
|
36
|
+
const PASS_THROUGH_VERBS = ['create', 'verify'] as const
|
|
37
|
+
|
|
38
|
+
interface SyncOptions {
|
|
39
|
+
readonly skip?: string
|
|
40
|
+
readonly check?: boolean
|
|
41
|
+
readonly write?: boolean
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
interface InjectOptions {
|
|
45
|
+
readonly configs?: boolean
|
|
46
|
+
readonly seeds?: boolean
|
|
47
|
+
readonly manifest?: boolean
|
|
48
|
+
readonly gitignore?: boolean
|
|
49
|
+
readonly nested?: boolean
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
interface PruneOptions {
|
|
53
|
+
readonly nested?: boolean
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
interface ListOptions {
|
|
57
|
+
readonly json?: boolean
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
type Prepared =
|
|
61
|
+
| { readonly ok: true; readonly chain: Manifest[]; readonly target: string }
|
|
62
|
+
| { readonly ok: false; readonly error: string }
|
|
63
|
+
|
|
64
|
+
export function register(program: Command): void {
|
|
65
|
+
const tooling = program
|
|
66
|
+
.command('tooling')
|
|
67
|
+
.description('Manage tooling stacks (sync, reference, create)')
|
|
68
|
+
.helpOption('-h, --help', 'Show this help message')
|
|
69
|
+
|
|
70
|
+
tooling
|
|
71
|
+
.command('sync')
|
|
72
|
+
.description('Sync configs, seeds, deps, scripts, and gitignore entries')
|
|
73
|
+
.argument('[stack]', 'Tooling stack name (e.g. base, vite-react)')
|
|
74
|
+
.argument('[target]', 'Target directory', '.')
|
|
75
|
+
.helpOption('-h, --help', 'Show this help message')
|
|
76
|
+
.option('--skip <stack>', 'Drop a layer from the extends chain')
|
|
77
|
+
.option('--check', 'Report what would change and write nothing')
|
|
78
|
+
.option('--write', 'Apply every change without prompting')
|
|
79
|
+
.addHelpText(
|
|
80
|
+
'after',
|
|
81
|
+
[
|
|
82
|
+
'',
|
|
83
|
+
'Examples:',
|
|
84
|
+
' canon tooling sync base',
|
|
85
|
+
' canon tooling sync base --check',
|
|
86
|
+
' CANON_NON_INTERACTIVE=1 canon tooling sync base --write',
|
|
87
|
+
'',
|
|
88
|
+
'To gate CI on tooling drift, run headlessly with neither flag. That',
|
|
89
|
+
'exits 1 when a file would be replaced and 0 when none would, which is',
|
|
90
|
+
'what `canon sync --check --exit-code` spells with a flag. Pass --check',
|
|
91
|
+
'to report the same list and always exit 0.',
|
|
92
|
+
'',
|
|
93
|
+
].join('\n'),
|
|
94
|
+
)
|
|
95
|
+
.action(
|
|
96
|
+
async (stack: string | undefined, target: string, opts: SyncOptions) => {
|
|
97
|
+
process.exitCode = await runSync(stack, target, opts)
|
|
98
|
+
},
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
tooling
|
|
102
|
+
.command('inject')
|
|
103
|
+
.description('Apply one stack to a target without scanning or prompting')
|
|
104
|
+
.argument('<stack>', 'Tooling stack name')
|
|
105
|
+
.argument('[target]', 'Target directory', '.')
|
|
106
|
+
.helpOption('-h, --help', 'Show this help message')
|
|
107
|
+
.option('--configs', 'Copy stack configs')
|
|
108
|
+
.option('--seeds', 'Merge stack seeds')
|
|
109
|
+
.option('--manifest', 'Install deps, apply scripts, merge gitignore')
|
|
110
|
+
.option('--gitignore', 'Merge gitignore entries only')
|
|
111
|
+
.option('--nested', 'Suppress the frame when a caller already opened one')
|
|
112
|
+
.action(async (stack: string, target: string, opts: InjectOptions) => {
|
|
113
|
+
process.exitCode = await runInject(stack, target, opts)
|
|
114
|
+
})
|
|
115
|
+
|
|
116
|
+
tooling
|
|
117
|
+
.command('prune-gitignore')
|
|
118
|
+
.description('Remove managed gitignore entries no longer in the manifest')
|
|
119
|
+
.argument('<stack>', 'Tooling stack name')
|
|
120
|
+
.argument('[target]', 'Target directory', '.')
|
|
121
|
+
.helpOption('-h, --help', 'Show this help message')
|
|
122
|
+
.option('--nested', 'Suppress the frame when a caller already opened one')
|
|
123
|
+
.action(async (stack: string, target: string, opts: PruneOptions) => {
|
|
124
|
+
process.exitCode = await runPrune(stack, target, opts)
|
|
125
|
+
})
|
|
126
|
+
|
|
127
|
+
tooling
|
|
128
|
+
.command('list')
|
|
129
|
+
.description('List installable tooling stacks')
|
|
130
|
+
.helpOption('-h, --help', 'Show this help message')
|
|
131
|
+
.option('--json', 'Emit machine-readable JSON')
|
|
132
|
+
.action((opts: ListOptions) => {
|
|
133
|
+
process.exitCode = runList(opts)
|
|
134
|
+
})
|
|
135
|
+
|
|
136
|
+
tooling
|
|
137
|
+
.command('reference')
|
|
138
|
+
.description("Print a stack's reference doc")
|
|
139
|
+
.argument('<stack>', 'Tooling stack name (e.g. base, vite-react)')
|
|
140
|
+
.helpOption('-h, --help', 'Show this help message')
|
|
141
|
+
.addHelpText(
|
|
142
|
+
'after',
|
|
143
|
+
[
|
|
144
|
+
'',
|
|
145
|
+
'A stack resolves under tooling/ at the working root, then the corpus',
|
|
146
|
+
'inside the canon package. No reference installs into a project, so the',
|
|
147
|
+
'package corpus is what answers there. The frame names the copy it read.',
|
|
148
|
+
'',
|
|
149
|
+
'Examples:',
|
|
150
|
+
' canon tooling reference base',
|
|
151
|
+
' canon tooling reference vite-react',
|
|
152
|
+
'',
|
|
153
|
+
].join('\n'),
|
|
154
|
+
)
|
|
155
|
+
.action((stack: string) => {
|
|
156
|
+
process.exitCode = printReference(stack)
|
|
157
|
+
})
|
|
158
|
+
|
|
159
|
+
for (const verb of PASS_THROUGH_VERBS) {
|
|
160
|
+
tooling
|
|
161
|
+
.command(verb)
|
|
162
|
+
.description(`Run the tooling ${verb} command`)
|
|
163
|
+
.allowUnknownOption()
|
|
164
|
+
.allowExcessArguments(true)
|
|
165
|
+
.passThroughOptions()
|
|
166
|
+
.helpOption(false)
|
|
167
|
+
.action(async (_opts: unknown, cmd: Command) => {
|
|
168
|
+
await execScript(`tooling/${verb}.sh`, cmd.args)
|
|
169
|
+
})
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* `JSON.stringify` replaces a `printf` that interpolated manifest fields into a
|
|
175
|
+
* JSON string literal unescaped, so a stack name or description carrying a
|
|
176
|
+
* quote emitted output a consuming skill could not parse.
|
|
177
|
+
*
|
|
178
|
+
* The frame opens after the `--json` return. The bash emitted a closing `└`
|
|
179
|
+
* from its EXIT trap with no `┌` above it, because the hand-rolled
|
|
180
|
+
* pass-through loop below skips the `intro` the shared helper carries.
|
|
181
|
+
*/
|
|
182
|
+
function runList(opts: ListOptions): number {
|
|
183
|
+
const stacks = buildStackSummaries(PROJECT_ROOT)
|
|
184
|
+
|
|
185
|
+
if (opts.json) {
|
|
186
|
+
process.stdout.write(`${JSON.stringify({ stacks })}\n`)
|
|
187
|
+
return 0
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
intro('canon tooling list')
|
|
191
|
+
logStep('Stacks')
|
|
192
|
+
for (const summary of stacks) logInfo(describeStack(summary))
|
|
193
|
+
outro()
|
|
194
|
+
return 0
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Writes the reference to stdout and every frame line to stderr, so a caller
|
|
199
|
+
* capturing the output with `$(...)` receives the document alone. Mirrors
|
|
200
|
+
* `print` in `src/commands/standards.ts`.
|
|
201
|
+
*/
|
|
202
|
+
function printReference(stack: string): number {
|
|
203
|
+
intro('canon tooling reference')
|
|
204
|
+
|
|
205
|
+
const root = process.cwd()
|
|
206
|
+
const resolved = resolveReference(root, stack)
|
|
207
|
+
|
|
208
|
+
if (!resolved) {
|
|
209
|
+
logWarn(`Unknown stack: ${stack}`)
|
|
210
|
+
logStep('Available stacks')
|
|
211
|
+
for (const each of listStacks(PROJECT_ROOT)) logInfo(each)
|
|
212
|
+
logError("Run 'canon tooling list' for descriptions.")
|
|
213
|
+
outro()
|
|
214
|
+
return 1
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
logStep(resolved.source)
|
|
218
|
+
process.stdout.write(readReference(resolved))
|
|
219
|
+
outro()
|
|
220
|
+
return 0
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Resolves the chain and rejects the same inputs the bash rejected, so a bad
|
|
225
|
+
* stack name fails before anything touches the target.
|
|
226
|
+
*
|
|
227
|
+
* The excluded-stack guard is deliberately not here. It lived in the sync
|
|
228
|
+
* entry point, so `canon claude` can still drive injection for the `claude`
|
|
229
|
+
* stack the way it drove `merge_gitignore` before.
|
|
230
|
+
*/
|
|
231
|
+
function prepare(stack: string, target: string, skip?: string): Prepared {
|
|
232
|
+
if (!stackExists(PROJECT_ROOT, stack)) {
|
|
233
|
+
return { ok: false, error: `Stack not found: ${stack}` }
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
if (skip !== undefined) {
|
|
237
|
+
if (skip === stack) {
|
|
238
|
+
return {
|
|
239
|
+
ok: false,
|
|
240
|
+
error: `Cannot --skip the stack being synced: ${skip}`,
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
if (!stackExists(PROJECT_ROOT, skip)) {
|
|
244
|
+
return { ok: false, error: `Stack to skip not found: ${skip}` }
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
const resolved = resolve(target)
|
|
249
|
+
if (resolved === PROJECT_ROOT) {
|
|
250
|
+
return {
|
|
251
|
+
ok: false,
|
|
252
|
+
error:
|
|
253
|
+
'Cannot run against toolkit root. Files here are the source of truth.',
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
return {
|
|
258
|
+
ok: true,
|
|
259
|
+
chain: resolveChain(PROJECT_ROOT, stack, { skipStack: skip }),
|
|
260
|
+
target: resolved,
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
async function runSync(
|
|
265
|
+
stack: string | undefined,
|
|
266
|
+
target: string,
|
|
267
|
+
opts: SyncOptions,
|
|
268
|
+
): Promise<number> {
|
|
269
|
+
intro('canon tooling sync')
|
|
270
|
+
|
|
271
|
+
if (opts.check === true && opts.write === true) {
|
|
272
|
+
logWarn('Pass --check or --write, not both.')
|
|
273
|
+
outro()
|
|
274
|
+
return 1
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
const selected = stack ?? (await promptForStack())
|
|
278
|
+
if (selected === undefined) {
|
|
279
|
+
logWarn('No tooling stacks found')
|
|
280
|
+
outro()
|
|
281
|
+
return 1
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
if (isStackExcluded(selected)) {
|
|
285
|
+
logWarn(
|
|
286
|
+
'Claude is managed by `canon claude`, not `canon tooling`. Run `canon claude sync` instead.',
|
|
287
|
+
)
|
|
288
|
+
outro()
|
|
289
|
+
return 1
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
const prepared = prepare(selected, target, opts.skip)
|
|
293
|
+
if (!prepared.ok) {
|
|
294
|
+
logWarn(prepared.error)
|
|
295
|
+
outro()
|
|
296
|
+
return 1
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
const result = scan(prepared.chain, prepared.target)
|
|
300
|
+
|
|
301
|
+
report(result)
|
|
302
|
+
|
|
303
|
+
const mode = resolveWriteMode(opts)
|
|
304
|
+
const { GREEN, NC } = palette(process.stderr)
|
|
305
|
+
|
|
306
|
+
if (result.totalChanges === 0) {
|
|
307
|
+
// The stamp is a write like any other, so a run with no authority to write
|
|
308
|
+
// leaves the target's record alone rather than claiming a sync it never
|
|
309
|
+
// performed.
|
|
310
|
+
if (mode === 'apply' || mode === 'prompt') {
|
|
311
|
+
await stampChain(prepared.chain, prepared.target)
|
|
312
|
+
}
|
|
313
|
+
outro()
|
|
314
|
+
process.stderr.write(`${GREEN}✓ Everything up to date${NC}\n`)
|
|
315
|
+
return 0
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
const decision = await decideApply(result, mode)
|
|
319
|
+
|
|
320
|
+
if (decision !== 'apply') {
|
|
321
|
+
logWarn(
|
|
322
|
+
decision === 'cancelled'
|
|
323
|
+
? 'Sync cancelled'
|
|
324
|
+
: `Reported ${result.totalChanges} changes (${summarize(result)}). Nothing written.`,
|
|
325
|
+
)
|
|
326
|
+
if (decision === 'unauthorized') {
|
|
327
|
+
logInfo('Re-run with --write to apply them, or --check to silence this.')
|
|
328
|
+
}
|
|
329
|
+
outro()
|
|
330
|
+
return decision === 'unauthorized' ? 1 : 0
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
if (result.configs.some((entry) => entry.state !== 'matching')) {
|
|
334
|
+
await injectConfigs(prepared.chain, prepared.target)
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
await injectSeeds(prepared.chain, prepared.target)
|
|
338
|
+
await injectManifest(prepared.chain, prepared.target)
|
|
339
|
+
|
|
340
|
+
await stampChain(prepared.chain, prepared.target)
|
|
341
|
+
|
|
342
|
+
outro()
|
|
343
|
+
process.stderr.write(`${GREEN}✓ Tooling sync complete${NC}\n`)
|
|
344
|
+
return 0
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
type WriteMode = 'apply' | 'prompt' | 'report' | 'unauthorized'
|
|
348
|
+
|
|
349
|
+
type ApplyDecision = 'apply' | 'cancelled' | 'reported' | 'unauthorized'
|
|
350
|
+
|
|
351
|
+
/**
|
|
352
|
+
* Golden configs carry the CI workflow, the end-to-end harness, and the shell
|
|
353
|
+
* scripts under `scripts/`, so an overwrite reaches work no one would consent
|
|
354
|
+
* to losing. A headless caller therefore has no authority to write without
|
|
355
|
+
* `--write`, since a confirm prompt carrying `nonInteractiveDefault` resolves
|
|
356
|
+
* to its first option and would read silence as consent.
|
|
357
|
+
*/
|
|
358
|
+
function resolveWriteMode(opts: SyncOptions): WriteMode {
|
|
359
|
+
if (opts.check === true) return 'report'
|
|
360
|
+
if (opts.write === true) return 'apply'
|
|
361
|
+
return isNonInteractive() ? 'unauthorized' : 'prompt'
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
/**
|
|
365
|
+
* Exit 1 follows `unauthorized`, so a caller that forgets `--write` fails
|
|
366
|
+
* rather than reporting a sync it never performed.
|
|
367
|
+
*/
|
|
368
|
+
async function decideApply(
|
|
369
|
+
result: ScanResult,
|
|
370
|
+
mode: WriteMode,
|
|
371
|
+
): Promise<ApplyDecision> {
|
|
372
|
+
if (mode === 'report') return 'reported'
|
|
373
|
+
if (mode === 'apply') return 'apply'
|
|
374
|
+
if (mode === 'unauthorized') return 'unauthorized'
|
|
375
|
+
|
|
376
|
+
const shouldApply = await select({
|
|
377
|
+
message: `Apply ${result.totalChanges} changes (${summarize(result)})?`,
|
|
378
|
+
options: [
|
|
379
|
+
{ value: true, label: 'Apply all' },
|
|
380
|
+
{ value: false, label: 'Cancel' },
|
|
381
|
+
],
|
|
382
|
+
})
|
|
383
|
+
|
|
384
|
+
return shouldApply ? 'apply' : 'cancelled'
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
/**
|
|
388
|
+
* Writes the chain after the copies land, so a partial apply that throws leaves
|
|
389
|
+
* the previous record rather than a claim the target does not meet.
|
|
390
|
+
*/
|
|
391
|
+
async function stampChain(chain: Manifest[], target: string): Promise<void> {
|
|
392
|
+
const recorded = await recordToolingChain(
|
|
393
|
+
PROJECT_ROOT,
|
|
394
|
+
target,
|
|
395
|
+
chain,
|
|
396
|
+
new Date(),
|
|
397
|
+
)
|
|
398
|
+
|
|
399
|
+
if (recorded) {
|
|
400
|
+
logInfo(`Recorded chain: ${chain.map((entry) => entry.name).join(' < ')}`)
|
|
401
|
+
return
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
logWarn(
|
|
405
|
+
'Workspace root: no chain recorded. Tooling reports unmeasured because the answer differs per package.',
|
|
406
|
+
)
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
async function runInject(
|
|
410
|
+
stack: string,
|
|
411
|
+
target: string,
|
|
412
|
+
opts: InjectOptions,
|
|
413
|
+
): Promise<number> {
|
|
414
|
+
const framed = opts.nested !== true
|
|
415
|
+
if (framed) intro('canon tooling inject')
|
|
416
|
+
|
|
417
|
+
const prepared = prepare(stack, target)
|
|
418
|
+
if (!prepared.ok) {
|
|
419
|
+
logWarn(prepared.error)
|
|
420
|
+
if (framed) outro()
|
|
421
|
+
return 1
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
const applyAll =
|
|
425
|
+
!opts.configs && !opts.seeds && !opts.manifest && !opts.gitignore
|
|
426
|
+
|
|
427
|
+
if (opts.configs || applyAll) {
|
|
428
|
+
await injectConfigs(prepared.chain, prepared.target)
|
|
429
|
+
}
|
|
430
|
+
if (opts.seeds || applyAll) {
|
|
431
|
+
await injectSeeds(prepared.chain, prepared.target)
|
|
432
|
+
}
|
|
433
|
+
if (opts.manifest || applyAll) {
|
|
434
|
+
await injectManifest(prepared.chain, prepared.target)
|
|
435
|
+
} else if (opts.gitignore) {
|
|
436
|
+
await injectGitignore(prepared.chain, prepared.target)
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
// Only a whole-stack inject records the chain. A flag-scoped run installs one
|
|
440
|
+
// category, and a chain recorded from it would send the report scanning for
|
|
441
|
+
// configs and deps the caller never asked to install. The claude stack is
|
|
442
|
+
// excluded here rather than in `prepare`, which is what keeps `canon claude`
|
|
443
|
+
// able to drive injection while its stack stays out of the tooling record.
|
|
444
|
+
if (applyAll && !isStackExcluded(stack)) {
|
|
445
|
+
await stampChain(prepared.chain, prepared.target)
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
if (framed) outro()
|
|
449
|
+
return 0
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
/**
|
|
453
|
+
* Emits the number of pruned entries on stdout so a caller can branch on it
|
|
454
|
+
* without parsing the timeline, replacing the bash nameref return.
|
|
455
|
+
*/
|
|
456
|
+
async function runPrune(
|
|
457
|
+
stack: string,
|
|
458
|
+
target: string,
|
|
459
|
+
opts: PruneOptions,
|
|
460
|
+
): Promise<number> {
|
|
461
|
+
const framed = opts.nested !== true
|
|
462
|
+
if (framed) intro('canon tooling prune-gitignore')
|
|
463
|
+
|
|
464
|
+
const prepared = prepare(stack, target)
|
|
465
|
+
if (!prepared.ok) {
|
|
466
|
+
logWarn(prepared.error)
|
|
467
|
+
if (framed) outro()
|
|
468
|
+
return 1
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
const removed = await pruneGitignore(prepared.chain, prepared.target)
|
|
472
|
+
if (framed) outro()
|
|
473
|
+
|
|
474
|
+
process.stdout.write(`${removed.length}\n`)
|
|
475
|
+
return 0
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
async function promptForStack(): Promise<string | undefined> {
|
|
479
|
+
const stacks = listStacks(PROJECT_ROOT)
|
|
480
|
+
if (stacks.length === 0) return undefined
|
|
481
|
+
|
|
482
|
+
return select({
|
|
483
|
+
message: 'Select tooling stack:',
|
|
484
|
+
options: stacks.map((name) => ({ value: name, label: name })),
|
|
485
|
+
nonInteractiveDefault: true,
|
|
486
|
+
})
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
function report(result: ScanResult): void {
|
|
490
|
+
logStep('Scanning configs')
|
|
491
|
+
for (const entry of result.configs) {
|
|
492
|
+
if (entry.state === 'matching') logInfo(entry.rel)
|
|
493
|
+
}
|
|
494
|
+
for (const entry of result.configs) {
|
|
495
|
+
if (entry.state === 'drifted') logWarn(entry.rel)
|
|
496
|
+
}
|
|
497
|
+
for (const entry of result.configs) {
|
|
498
|
+
if (entry.state === 'new') logAdd(entry.rel)
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
logStep('Scanning seeds')
|
|
502
|
+
for (const entry of result.seeds) {
|
|
503
|
+
if (entry.state === 'present') logInfo(entry.rel)
|
|
504
|
+
}
|
|
505
|
+
for (const entry of result.seeds) {
|
|
506
|
+
if (entry.state === 'missing') logAdd(entry.rel)
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
if (result.hasPackageJson) {
|
|
510
|
+
reportPackage(result)
|
|
511
|
+
} else {
|
|
512
|
+
logWarn(
|
|
513
|
+
"Skipped scripts and deps: no package.json found (run 'bun init' to enable)",
|
|
514
|
+
)
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
logStep('Scanning gitignore')
|
|
518
|
+
for (const entry of result.gitignore) {
|
|
519
|
+
if (entry.state === 'present') logInfo(entry.entry)
|
|
520
|
+
}
|
|
521
|
+
for (const entry of result.gitignore) {
|
|
522
|
+
if (entry.state === 'missing') logAdd(entry.entry)
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
function reportPackage(result: ScanResult): void {
|
|
527
|
+
if (result.scripts.length > 0) {
|
|
528
|
+
logStep('Scanning scripts')
|
|
529
|
+
for (const entry of result.scripts) {
|
|
530
|
+
if (entry.state === 'matching') logInfo(entry.key)
|
|
531
|
+
}
|
|
532
|
+
for (const entry of result.scripts) {
|
|
533
|
+
if (entry.state === 'drifted') logWarn(entry.key)
|
|
534
|
+
}
|
|
535
|
+
for (const entry of result.scripts) {
|
|
536
|
+
if (entry.state === 'missing') logAdd(entry.key)
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
if (result.deps.length > 0) {
|
|
541
|
+
logStep('Scanning dependencies')
|
|
542
|
+
for (const entry of result.deps) {
|
|
543
|
+
if (entry.state === 'present') logInfo(entry.name)
|
|
544
|
+
}
|
|
545
|
+
for (const entry of result.deps) {
|
|
546
|
+
if (entry.state === 'missing') logAdd(entry.spec)
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
function summarize(result: ScanResult): string {
|
|
552
|
+
const parts: string[] = []
|
|
553
|
+
const add = (count: number, label: string): void => {
|
|
554
|
+
if (count > 0) parts.push(`${count} ${label}`)
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
add(
|
|
558
|
+
result.configs.filter((entry) => entry.state !== 'matching').length,
|
|
559
|
+
'configs',
|
|
560
|
+
)
|
|
561
|
+
add(result.seeds.filter((entry) => entry.state === 'missing').length, 'seeds')
|
|
562
|
+
add(
|
|
563
|
+
result.scripts.filter((entry) => entry.state !== 'matching').length,
|
|
564
|
+
'scripts',
|
|
565
|
+
)
|
|
566
|
+
add(result.deps.filter((entry) => entry.state === 'missing').length, 'deps')
|
|
567
|
+
add(
|
|
568
|
+
result.gitignore.filter((entry) => entry.state === 'missing').length,
|
|
569
|
+
'gitignore',
|
|
570
|
+
)
|
|
571
|
+
|
|
572
|
+
return parts.join(', ')
|
|
573
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { resolve } from 'node:path'
|
|
2
|
+
import type { Command } from 'commander'
|
|
3
|
+
import { ensureYtDlp, fetchOne } from '@/transcripts/fetch'
|
|
4
|
+
import { palette } from '@/ui'
|
|
5
|
+
|
|
6
|
+
interface TranscriptOptions {
|
|
7
|
+
out: string
|
|
8
|
+
keepTimestamps?: boolean
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function register(program: Command): void {
|
|
12
|
+
program
|
|
13
|
+
.command('transcripts <url>')
|
|
14
|
+
.description('Fetch a YouTube transcript with metadata frontmatter')
|
|
15
|
+
.option('-o, --out <path>', 'Output directory', 'transcripts')
|
|
16
|
+
.option(
|
|
17
|
+
'--keep-timestamps',
|
|
18
|
+
'Prefix each line with [mm:ss] instead of prose',
|
|
19
|
+
)
|
|
20
|
+
.action(async (url: string, opts: TranscriptOptions) => {
|
|
21
|
+
const outDir = resolve(process.cwd(), opts.out)
|
|
22
|
+
const { GREEN, GREY, NC, RED, WHITE } = palette(process.stderr)
|
|
23
|
+
process.stderr.write(
|
|
24
|
+
`${GREY}┌${NC}\n${GREY}│${NC} ${WHITE}canon transcripts${NC}\n`,
|
|
25
|
+
)
|
|
26
|
+
try {
|
|
27
|
+
ensureYtDlp()
|
|
28
|
+
const target = await fetchOne(url, {
|
|
29
|
+
outDir,
|
|
30
|
+
keepTimestamps: opts.keepTimestamps ?? false,
|
|
31
|
+
})
|
|
32
|
+
process.stdout.write(`${target}\n`)
|
|
33
|
+
process.stderr.write(
|
|
34
|
+
`${GREY}│${NC} ${GREEN}✓${NC} ${target}\n${GREY}└${NC}\n`,
|
|
35
|
+
)
|
|
36
|
+
} catch (error) {
|
|
37
|
+
const message = error instanceof Error ? error.message : String(error)
|
|
38
|
+
process.stderr.write(
|
|
39
|
+
`${GREY}│${NC} ${RED}✗${NC} ${message}\n${GREY}└${NC}\n`,
|
|
40
|
+
)
|
|
41
|
+
process.exitCode = 1
|
|
42
|
+
}
|
|
43
|
+
})
|
|
44
|
+
}
|