@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,743 @@
|
|
|
1
|
+
import { relative } from 'node:path'
|
|
2
|
+
import type { Command } from 'commander'
|
|
3
|
+
import {
|
|
4
|
+
type ArchiveOutcome,
|
|
5
|
+
archiveTask,
|
|
6
|
+
type CitationOutcome,
|
|
7
|
+
type PlanCitations,
|
|
8
|
+
planCitations,
|
|
9
|
+
} from '@/tasks/archive'
|
|
10
|
+
import {
|
|
11
|
+
type CloseOutcome,
|
|
12
|
+
closeOutcomes,
|
|
13
|
+
type PullRequestOutcome,
|
|
14
|
+
type RecordRefused,
|
|
15
|
+
type RecordSelector,
|
|
16
|
+
recordPullRequest,
|
|
17
|
+
} from '@/tasks/record'
|
|
18
|
+
import {
|
|
19
|
+
type Finding,
|
|
20
|
+
type FolderClaim,
|
|
21
|
+
type Untested,
|
|
22
|
+
type ValidateOutcome,
|
|
23
|
+
validateBoard,
|
|
24
|
+
} from '@/tasks/validate'
|
|
25
|
+
import {
|
|
26
|
+
intro,
|
|
27
|
+
logAdd,
|
|
28
|
+
logError,
|
|
29
|
+
logInfo,
|
|
30
|
+
logRemove,
|
|
31
|
+
logStep,
|
|
32
|
+
logWarn,
|
|
33
|
+
outro,
|
|
34
|
+
pipeOutput,
|
|
35
|
+
} from '@/ui'
|
|
36
|
+
import { mainWorktreeRoot } from '@/worktree'
|
|
37
|
+
|
|
38
|
+
/** Returned when the board carries a finding, which is the gating result. */
|
|
39
|
+
const EXIT_FINDINGS = 2
|
|
40
|
+
|
|
41
|
+
interface ArchiveCommandOptions {
|
|
42
|
+
readonly json?: boolean
|
|
43
|
+
readonly pullRequest?: string
|
|
44
|
+
readonly root?: string
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
interface ValidateCommandOptions {
|
|
48
|
+
readonly json?: boolean
|
|
49
|
+
readonly root?: string
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
interface CitationsCommandOptions {
|
|
53
|
+
readonly json?: boolean
|
|
54
|
+
readonly root?: string
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
interface PullRequestCommandOptions {
|
|
58
|
+
readonly json?: boolean
|
|
59
|
+
readonly plan?: string
|
|
60
|
+
readonly root?: string
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
interface OutcomeCommandOptions {
|
|
64
|
+
readonly close?: readonly string[]
|
|
65
|
+
readonly json?: boolean
|
|
66
|
+
readonly plan?: string
|
|
67
|
+
readonly root?: string
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export function register(program: Command): void {
|
|
71
|
+
const tasks = program
|
|
72
|
+
.command('tasks')
|
|
73
|
+
.description('Manage the task board in .claude/tasks/')
|
|
74
|
+
.helpOption('-h, --help', 'Show this help message')
|
|
75
|
+
|
|
76
|
+
tasks
|
|
77
|
+
.command('archive')
|
|
78
|
+
.description('Move a shipped task out of the board and clear its ordering')
|
|
79
|
+
.argument('[task]', 'Task filename stem, as in v28.1-trigger-escalation')
|
|
80
|
+
.helpOption('-h, --help', 'Show this help message')
|
|
81
|
+
.option(
|
|
82
|
+
'--pull-request <number>',
|
|
83
|
+
'Select the task naming this pull request',
|
|
84
|
+
)
|
|
85
|
+
.option('--json', 'Emit a machine-readable record on stdout')
|
|
86
|
+
.option('--root <path>', 'Board root, defaulting to the main worktree')
|
|
87
|
+
.addHelpText(
|
|
88
|
+
'after',
|
|
89
|
+
[
|
|
90
|
+
'',
|
|
91
|
+
'Exit codes:',
|
|
92
|
+
' 0 the task was archived',
|
|
93
|
+
' 1 refused, with the reason on stderr or in the JSON record',
|
|
94
|
+
'',
|
|
95
|
+
'Examples:',
|
|
96
|
+
' canon tasks archive v28.1-trigger-escalation',
|
|
97
|
+
' canon tasks archive --pull-request 673 --json',
|
|
98
|
+
'',
|
|
99
|
+
].join('\n'),
|
|
100
|
+
)
|
|
101
|
+
.action(async (task: string | undefined, opts: ArchiveCommandOptions) => {
|
|
102
|
+
process.exitCode = await runArchive(task, opts)
|
|
103
|
+
})
|
|
104
|
+
|
|
105
|
+
tasks
|
|
106
|
+
.command('validate')
|
|
107
|
+
.description(
|
|
108
|
+
'Report what each board row claims against what the tree holds',
|
|
109
|
+
)
|
|
110
|
+
.helpOption('-h, --help', 'Show this help message')
|
|
111
|
+
.option('--json', 'Add a machine-readable record on stdout')
|
|
112
|
+
.option('--root <path>', 'Board root, defaulting to the main worktree')
|
|
113
|
+
.addHelpText(
|
|
114
|
+
'after',
|
|
115
|
+
[
|
|
116
|
+
'',
|
|
117
|
+
'Checks:',
|
|
118
|
+
' every Run now row points at a plan file that resolves',
|
|
119
|
+
' every task file carries a board row or a backlog line, never both',
|
|
120
|
+
' no task carries more than one row',
|
|
121
|
+
' no two Run now rows touch the same file',
|
|
122
|
+
'',
|
|
123
|
+
'Exit codes:',
|
|
124
|
+
' 0 every check passed',
|
|
125
|
+
' 1 refused, with the reason on stderr or in the JSON record',
|
|
126
|
+
' 2 the board carries at least one finding',
|
|
127
|
+
'',
|
|
128
|
+
'It reports and never writes. A row is a claim about readiness, so a',
|
|
129
|
+
'session fixes the row the report names.',
|
|
130
|
+
'',
|
|
131
|
+
'Examples:',
|
|
132
|
+
' canon tasks validate',
|
|
133
|
+
' canon tasks validate --json',
|
|
134
|
+
'',
|
|
135
|
+
].join('\n'),
|
|
136
|
+
)
|
|
137
|
+
.action(async (opts: ValidateCommandOptions) => {
|
|
138
|
+
process.exitCode = await runValidate(opts)
|
|
139
|
+
})
|
|
140
|
+
|
|
141
|
+
tasks
|
|
142
|
+
.command('plan-citations')
|
|
143
|
+
.description('Report where a task plan sits and which live tasks hold it')
|
|
144
|
+
.argument('<task>', 'Task filename stem, as in v28.1-trigger-escalation')
|
|
145
|
+
.helpOption('-h, --help', 'Show this help message')
|
|
146
|
+
.option('--json', 'Emit a machine-readable record on stdout')
|
|
147
|
+
.option('--root <path>', 'Board root, defaulting to the main worktree')
|
|
148
|
+
.addHelpText(
|
|
149
|
+
'after',
|
|
150
|
+
[
|
|
151
|
+
'',
|
|
152
|
+
'Locations:',
|
|
153
|
+
' unstated the task carries no Plan: line',
|
|
154
|
+
' live the target resolves inside .claude/plans/',
|
|
155
|
+
' archived the target resolves inside .claude/plans/archive/',
|
|
156
|
+
' outside the target resolves somewhere else',
|
|
157
|
+
'',
|
|
158
|
+
'Exit codes:',
|
|
159
|
+
' 0 the citations were read',
|
|
160
|
+
' 1 refused, with the reason on stderr or in the JSON record',
|
|
161
|
+
'',
|
|
162
|
+
'It reports and never writes. A live plan whose citedBy list is empty',
|
|
163
|
+
'is the sweep to run, and one a sibling still holds is left alone.',
|
|
164
|
+
'The archive gate reads the same answer, so neither can drift.',
|
|
165
|
+
'',
|
|
166
|
+
'Examples:',
|
|
167
|
+
' canon tasks plan-citations v28.1-trigger-escalation',
|
|
168
|
+
' canon tasks plan-citations v28.1-trigger-escalation --json',
|
|
169
|
+
'',
|
|
170
|
+
].join('\n'),
|
|
171
|
+
)
|
|
172
|
+
.action(async (task: string, opts: CitationsCommandOptions) => {
|
|
173
|
+
process.exitCode = await runCitations(task, opts)
|
|
174
|
+
})
|
|
175
|
+
|
|
176
|
+
tasks
|
|
177
|
+
.command('pull-request')
|
|
178
|
+
.description('Record a pull request number on the task a branch closes')
|
|
179
|
+
.argument('<number>', 'Pull request number, without the #')
|
|
180
|
+
.argument('[task]', 'Task filename stem, as in v28.1-trigger-escalation')
|
|
181
|
+
.helpOption('-h, --help', 'Show this help message')
|
|
182
|
+
.option('--plan <slug>', 'Select the task whose Plan line names this plan')
|
|
183
|
+
.option('--json', 'Emit a machine-readable record on stdout')
|
|
184
|
+
.option('--root <path>', 'Board root, defaulting to the main worktree')
|
|
185
|
+
.addHelpText(
|
|
186
|
+
'after',
|
|
187
|
+
[
|
|
188
|
+
'',
|
|
189
|
+
'Exit codes:',
|
|
190
|
+
' 0 the line was added, corrected, or already correct',
|
|
191
|
+
' 1 refused, with the reason on stderr or in the JSON record',
|
|
192
|
+
'',
|
|
193
|
+
'It adds Pull request: #NNN under the origin lines the task carries,',
|
|
194
|
+
'and corrects the number in place when the line exists. The board is',
|
|
195
|
+
'shared scratch, so a linked worktree records against the same board.',
|
|
196
|
+
'',
|
|
197
|
+
'Examples:',
|
|
198
|
+
' canon tasks pull-request 673 v28.1-trigger-escalation',
|
|
199
|
+
' canon tasks pull-request 673 --plan worktree-scratch-routing --json',
|
|
200
|
+
'',
|
|
201
|
+
].join('\n'),
|
|
202
|
+
)
|
|
203
|
+
.action(
|
|
204
|
+
async (
|
|
205
|
+
number: string,
|
|
206
|
+
task: string | undefined,
|
|
207
|
+
opts: PullRequestCommandOptions,
|
|
208
|
+
) => {
|
|
209
|
+
process.exitCode = await runPullRequest(number, task, opts)
|
|
210
|
+
},
|
|
211
|
+
)
|
|
212
|
+
|
|
213
|
+
tasks
|
|
214
|
+
.command('outcome')
|
|
215
|
+
.description('Mark outcomes closed on a task by their position')
|
|
216
|
+
.argument('[task]', 'Task filename stem, as in v28.1-trigger-escalation')
|
|
217
|
+
.helpOption('-h, --help', 'Show this help message')
|
|
218
|
+
.option(
|
|
219
|
+
'--close <position>',
|
|
220
|
+
'Outcome to mark [x], 1-based, repeatable',
|
|
221
|
+
collectPosition,
|
|
222
|
+
[] as string[],
|
|
223
|
+
)
|
|
224
|
+
.option('--plan <slug>', 'Select the task whose Plan line names this plan')
|
|
225
|
+
.option('--json', 'Emit a machine-readable record on stdout')
|
|
226
|
+
.option('--root <path>', 'Board root, defaulting to the main worktree')
|
|
227
|
+
.addHelpText(
|
|
228
|
+
'after',
|
|
229
|
+
[
|
|
230
|
+
'',
|
|
231
|
+
'Exit codes:',
|
|
232
|
+
' 0 every named outcome is closed',
|
|
233
|
+
' 1 refused, with the reason on stderr or in the JSON record',
|
|
234
|
+
'',
|
|
235
|
+
'Positions count every outcome checkbox in file order, starting at 1.',
|
|
236
|
+
'An outcome already closed is reported rather than refused, so a rerun',
|
|
237
|
+
'against the same positions is safe.',
|
|
238
|
+
'',
|
|
239
|
+
'Examples:',
|
|
240
|
+
' canon tasks outcome v28.1-trigger-escalation --close 1 --close 3',
|
|
241
|
+
' canon tasks outcome --plan worktree-scratch-routing --close 2 --json',
|
|
242
|
+
'',
|
|
243
|
+
].join('\n'),
|
|
244
|
+
)
|
|
245
|
+
.action(async (task: string | undefined, opts: OutcomeCommandOptions) => {
|
|
246
|
+
process.exitCode = await runOutcome(task, opts)
|
|
247
|
+
})
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
function collectPosition(value: string, previous: string[]): string[] {
|
|
251
|
+
return [...previous, value]
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* Both record verbs name a task the same two ways, and naming it neither way or
|
|
256
|
+
* both ways is the same refusal in each. Both are `bad-input` rather than
|
|
257
|
+
* `ambiguous` or `no-match`, since those two describe the board and these
|
|
258
|
+
* describe the command line that reached it.
|
|
259
|
+
*/
|
|
260
|
+
function selectorFor(
|
|
261
|
+
task: string | undefined,
|
|
262
|
+
plan: string | undefined,
|
|
263
|
+
): RecordSelector | RecordRefused {
|
|
264
|
+
if (task && plan) {
|
|
265
|
+
return {
|
|
266
|
+
ok: false,
|
|
267
|
+
reason: 'bad-input',
|
|
268
|
+
message: 'Name a task or a plan, not both.',
|
|
269
|
+
detail: [],
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
if (task) return { kind: 'stem', stem: task }
|
|
274
|
+
if (plan) return { kind: 'plan', plan }
|
|
275
|
+
|
|
276
|
+
return {
|
|
277
|
+
ok: false,
|
|
278
|
+
reason: 'bad-input',
|
|
279
|
+
message: 'No task named. Pass a filename stem or --plan <slug>.',
|
|
280
|
+
detail: [],
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
async function runPullRequest(
|
|
285
|
+
number: string,
|
|
286
|
+
task: string | undefined,
|
|
287
|
+
opts: PullRequestCommandOptions,
|
|
288
|
+
): Promise<number> {
|
|
289
|
+
const emitJson = opts.json ?? false
|
|
290
|
+
const selector = selectorFor(task, opts.plan)
|
|
291
|
+
|
|
292
|
+
if ('ok' in selector) {
|
|
293
|
+
return reportRecord(
|
|
294
|
+
'canon tasks pull-request',
|
|
295
|
+
selector,
|
|
296
|
+
emitJson,
|
|
297
|
+
process.cwd(),
|
|
298
|
+
)
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
if (!/^\d+$/.test(number)) {
|
|
302
|
+
return reportRecord(
|
|
303
|
+
'canon tasks pull-request',
|
|
304
|
+
{
|
|
305
|
+
ok: false,
|
|
306
|
+
reason: 'bad-input',
|
|
307
|
+
message: `Not a pull request number: ${number}`,
|
|
308
|
+
detail: [],
|
|
309
|
+
},
|
|
310
|
+
emitJson,
|
|
311
|
+
process.cwd(),
|
|
312
|
+
)
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
const root = opts.root ?? (await mainWorktreeRoot())
|
|
316
|
+
const outcome = await recordPullRequest(root, selector, Number(number))
|
|
317
|
+
|
|
318
|
+
return reportPullRequest(outcome, emitJson, root)
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
async function runOutcome(
|
|
322
|
+
task: string | undefined,
|
|
323
|
+
opts: OutcomeCommandOptions,
|
|
324
|
+
): Promise<number> {
|
|
325
|
+
const emitJson = opts.json ?? false
|
|
326
|
+
const selector = selectorFor(task, opts.plan)
|
|
327
|
+
|
|
328
|
+
if ('ok' in selector) {
|
|
329
|
+
return reportRecord(
|
|
330
|
+
'canon tasks outcome',
|
|
331
|
+
selector,
|
|
332
|
+
emitJson,
|
|
333
|
+
process.cwd(),
|
|
334
|
+
)
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
const raw = opts.close ?? []
|
|
338
|
+
|
|
339
|
+
if (raw.length === 0) {
|
|
340
|
+
return reportRecord(
|
|
341
|
+
'canon tasks outcome',
|
|
342
|
+
{
|
|
343
|
+
ok: false,
|
|
344
|
+
reason: 'bad-input',
|
|
345
|
+
message: 'No outcome named. Pass --close <position>.',
|
|
346
|
+
detail: [],
|
|
347
|
+
},
|
|
348
|
+
emitJson,
|
|
349
|
+
process.cwd(),
|
|
350
|
+
)
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
const invalid = raw.filter((value) => !/^\d+$/.test(value))
|
|
354
|
+
|
|
355
|
+
if (invalid.length > 0) {
|
|
356
|
+
return reportRecord(
|
|
357
|
+
'canon tasks outcome',
|
|
358
|
+
{
|
|
359
|
+
ok: false,
|
|
360
|
+
reason: 'bad-input',
|
|
361
|
+
message: `Not an outcome position: ${invalid.join(', ')}`,
|
|
362
|
+
detail: invalid,
|
|
363
|
+
},
|
|
364
|
+
emitJson,
|
|
365
|
+
process.cwd(),
|
|
366
|
+
)
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
const root = opts.root ?? (await mainWorktreeRoot())
|
|
370
|
+
const outcome = await closeOutcomes(root, selector, raw.map(Number))
|
|
371
|
+
|
|
372
|
+
return reportOutcome(outcome, emitJson, root)
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
function reportRecord(
|
|
376
|
+
title: string,
|
|
377
|
+
refused: RecordRefused,
|
|
378
|
+
emitJson: boolean,
|
|
379
|
+
root: string,
|
|
380
|
+
): number {
|
|
381
|
+
// The framed branch below already reaches stderr through logError, so the
|
|
382
|
+
// bare write is what keeps the JSON mode from reporting the reason on stdout
|
|
383
|
+
// alone.
|
|
384
|
+
if (emitJson) {
|
|
385
|
+
process.stderr.write(`${refused.message}\n`)
|
|
386
|
+
process.stdout.write(
|
|
387
|
+
`${JSON.stringify({
|
|
388
|
+
ok: false,
|
|
389
|
+
root,
|
|
390
|
+
reason: refused.reason,
|
|
391
|
+
message: refused.message,
|
|
392
|
+
detail: refused.detail,
|
|
393
|
+
})}\n`,
|
|
394
|
+
)
|
|
395
|
+
return 1
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
intro(title)
|
|
399
|
+
logStep('Refused')
|
|
400
|
+
logError(refused.message)
|
|
401
|
+
if (refused.detail.length > 0) pipeOutput(refused.detail.join('\n'))
|
|
402
|
+
outro()
|
|
403
|
+
|
|
404
|
+
return 1
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
function reportPullRequest(
|
|
408
|
+
outcome: PullRequestOutcome,
|
|
409
|
+
emitJson: boolean,
|
|
410
|
+
root: string,
|
|
411
|
+
): number {
|
|
412
|
+
if (!outcome.ok) {
|
|
413
|
+
return reportRecord('canon tasks pull-request', outcome, emitJson, root)
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
if (emitJson) {
|
|
417
|
+
process.stdout.write(
|
|
418
|
+
`${JSON.stringify({
|
|
419
|
+
ok: true,
|
|
420
|
+
root,
|
|
421
|
+
task: outcome.stem,
|
|
422
|
+
path: relative(root, outcome.path),
|
|
423
|
+
pullRequest: outcome.number,
|
|
424
|
+
action: outcome.action,
|
|
425
|
+
})}\n`,
|
|
426
|
+
)
|
|
427
|
+
return 0
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
intro('canon tasks pull-request')
|
|
431
|
+
logStep(outcome.action === 'unchanged' ? 'Already recorded' : 'Recorded')
|
|
432
|
+
logInfo(`${outcome.stem} names pull request #${outcome.number}`)
|
|
433
|
+
if (outcome.action !== 'unchanged') logAdd(relative(root, outcome.path))
|
|
434
|
+
outro()
|
|
435
|
+
|
|
436
|
+
return 0
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
function reportOutcome(
|
|
440
|
+
outcome: CloseOutcome,
|
|
441
|
+
emitJson: boolean,
|
|
442
|
+
root: string,
|
|
443
|
+
): number {
|
|
444
|
+
if (!outcome.ok) {
|
|
445
|
+
return reportRecord('canon tasks outcome', outcome, emitJson, root)
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
if (emitJson) {
|
|
449
|
+
process.stdout.write(
|
|
450
|
+
`${JSON.stringify({
|
|
451
|
+
ok: true,
|
|
452
|
+
root,
|
|
453
|
+
task: outcome.stem,
|
|
454
|
+
path: relative(root, outcome.path),
|
|
455
|
+
closed: outcome.closed,
|
|
456
|
+
alreadyClosed: outcome.alreadyClosed,
|
|
457
|
+
})}\n`,
|
|
458
|
+
)
|
|
459
|
+
return 0
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
intro('canon tasks outcome')
|
|
463
|
+
logStep(outcome.closed.length > 0 ? 'Closed' : 'Nothing to close')
|
|
464
|
+
|
|
465
|
+
for (const closed of outcome.closed) logAdd(closed)
|
|
466
|
+
for (const already of outcome.alreadyClosed) logInfo(`${already} (already)`)
|
|
467
|
+
|
|
468
|
+
if (outcome.closed.length > 0) logInfo(relative(root, outcome.path))
|
|
469
|
+
outro()
|
|
470
|
+
|
|
471
|
+
return 0
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
async function runValidate(opts: ValidateCommandOptions): Promise<number> {
|
|
475
|
+
const root = opts.root ?? (await mainWorktreeRoot())
|
|
476
|
+
const outcome = await validateBoard(root)
|
|
477
|
+
|
|
478
|
+
return reportValidation(outcome, opts.json ?? false, root)
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
async function runCitations(
|
|
482
|
+
task: string,
|
|
483
|
+
opts: CitationsCommandOptions,
|
|
484
|
+
): Promise<number> {
|
|
485
|
+
const root = opts.root ?? (await mainWorktreeRoot())
|
|
486
|
+
const outcome = await planCitations(root, task)
|
|
487
|
+
|
|
488
|
+
return reportCitations(outcome, opts.json ?? false, root)
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
function reportCitations(
|
|
492
|
+
outcome: CitationOutcome,
|
|
493
|
+
emitJson: boolean,
|
|
494
|
+
root: string,
|
|
495
|
+
): number {
|
|
496
|
+
if (!outcome.ok) {
|
|
497
|
+
if (emitJson) {
|
|
498
|
+
process.stdout.write(
|
|
499
|
+
`${JSON.stringify({ ok: false, reason: outcome.reason, message: outcome.message })}\n`,
|
|
500
|
+
)
|
|
501
|
+
return 1
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
intro('canon tasks plan-citations')
|
|
505
|
+
logStep('Refused')
|
|
506
|
+
logError(outcome.message)
|
|
507
|
+
outro()
|
|
508
|
+
return 1
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
if (emitJson) {
|
|
512
|
+
process.stdout.write(`${JSON.stringify({ ...outcome, root })}\n`)
|
|
513
|
+
return 0
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
intro('canon tasks plan-citations')
|
|
517
|
+
logStep(outcome.stem)
|
|
518
|
+
logInfo(describeCitations(outcome))
|
|
519
|
+
outro()
|
|
520
|
+
|
|
521
|
+
return 0
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
function describeCitations(outcome: PlanCitations): string {
|
|
525
|
+
if (outcome.location === 'unstated') return 'carries no Plan: line.'
|
|
526
|
+
|
|
527
|
+
if (outcome.location === 'archived') {
|
|
528
|
+
return `points at ${outcome.target}, which an earlier sweep already archived.`
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
if (outcome.location === 'outside') {
|
|
532
|
+
return `points at ${outcome.target}, which resolves outside both plans folders.`
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
if (outcome.citedBy.length === 0) {
|
|
536
|
+
return `is the last live task citing ${outcome.target}, so the sweep may archive it.`
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
return `shares ${outcome.target} with ${outcome.citedBy.join(', ')}, so the sweep leaves it.`
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
function reportValidation(
|
|
543
|
+
outcome: ValidateOutcome,
|
|
544
|
+
emitJson: boolean,
|
|
545
|
+
root: string,
|
|
546
|
+
): number {
|
|
547
|
+
if (!outcome.ok) {
|
|
548
|
+
if (emitJson) {
|
|
549
|
+
process.stdout.write(
|
|
550
|
+
`${JSON.stringify({ ok: false, reason: outcome.reason, message: outcome.message })}\n`,
|
|
551
|
+
)
|
|
552
|
+
return 1
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
intro('canon tasks validate')
|
|
556
|
+
logStep('Refused')
|
|
557
|
+
logError(outcome.message)
|
|
558
|
+
outro()
|
|
559
|
+
return 1
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
if (!emitJson) {
|
|
563
|
+
intro('canon tasks validate')
|
|
564
|
+
logStep('Board')
|
|
565
|
+
logInfo(
|
|
566
|
+
`${outcome.rows} row(s) across the readiness groups, ${outcome.backlog} backlog line(s), ${outcome.tasks} task file(s)`,
|
|
567
|
+
)
|
|
568
|
+
|
|
569
|
+
logStep(outcome.findings.length === 0 ? 'Clean' : 'Findings')
|
|
570
|
+
if (outcome.findings.length === 0) {
|
|
571
|
+
logInfo(
|
|
572
|
+
'every row resolves, every task sits on one surface, and each touches its own files',
|
|
573
|
+
)
|
|
574
|
+
} else {
|
|
575
|
+
for (const finding of outcome.findings) logWarn(describe(finding))
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
// The untested rows carry the warn glyph rather than the pass glyph. They
|
|
579
|
+
// move no exit code, and a green tick on a row nothing re-took is the
|
|
580
|
+
// misread this section exists to prevent.
|
|
581
|
+
logStep('Parked rows')
|
|
582
|
+
if (outcome.untested.length === 0) {
|
|
583
|
+
logInfo('every parked row carried a citation or a file set to re-test')
|
|
584
|
+
} else {
|
|
585
|
+
logWarn(
|
|
586
|
+
`${outcome.untested.length} row(s) carry a blocker no check can settle`,
|
|
587
|
+
)
|
|
588
|
+
for (const row of outcome.untested) logWarn(describeUntested(row))
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
// A folder claim is often the correct way to say a row rewrites a whole
|
|
592
|
+
// directory, so it reports beside the findings and moves no exit code. A
|
|
593
|
+
// measure that fails on a legitimate cell trains a reader to skip it.
|
|
594
|
+
logStep('Folder claims')
|
|
595
|
+
if (outcome.claims.length === 0) {
|
|
596
|
+
logInfo('every run now row names files rather than folders')
|
|
597
|
+
} else {
|
|
598
|
+
for (const claim of outcome.claims) logWarn(describeClaim(claim))
|
|
599
|
+
}
|
|
600
|
+
outro()
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
if (emitJson) {
|
|
604
|
+
process.stdout.write(
|
|
605
|
+
`${JSON.stringify({
|
|
606
|
+
ok: true,
|
|
607
|
+
root,
|
|
608
|
+
rows: outcome.rows,
|
|
609
|
+
backlog: outcome.backlog,
|
|
610
|
+
tasks: outcome.tasks,
|
|
611
|
+
findings: outcome.findings,
|
|
612
|
+
untested: outcome.untested,
|
|
613
|
+
claims: outcome.claims,
|
|
614
|
+
})}\n`,
|
|
615
|
+
)
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
return outcome.findings.length > 0 ? EXIT_FINDINGS : 0
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
function describe(finding: Finding): string {
|
|
622
|
+
const scope = finding.group ? `${finding.group}: ` : ''
|
|
623
|
+
return `${scope}${finding.subject} ${finding.message}`
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
function describeUntested(row: Untested): string {
|
|
627
|
+
return `${row.group}: ${row.subject} ${row.message}`
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
function describeClaim(claim: FolderClaim): string {
|
|
631
|
+
return `${claim.group}: ${claim.subject} ${claim.message}`
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
async function runArchive(
|
|
635
|
+
task: string | undefined,
|
|
636
|
+
opts: ArchiveCommandOptions,
|
|
637
|
+
): Promise<number> {
|
|
638
|
+
const emitJson = opts.json ?? false
|
|
639
|
+
|
|
640
|
+
if (task && opts.pullRequest) {
|
|
641
|
+
return report(
|
|
642
|
+
{
|
|
643
|
+
ok: false,
|
|
644
|
+
reason: 'bad-input',
|
|
645
|
+
message: 'Name a task or a pull request, not both.',
|
|
646
|
+
detail: [],
|
|
647
|
+
},
|
|
648
|
+
emitJson,
|
|
649
|
+
process.cwd(),
|
|
650
|
+
)
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
if (!task && !opts.pullRequest) {
|
|
654
|
+
return report(
|
|
655
|
+
{
|
|
656
|
+
ok: false,
|
|
657
|
+
reason: 'bad-input',
|
|
658
|
+
message:
|
|
659
|
+
'No task named. Pass a filename stem or --pull-request <number>.',
|
|
660
|
+
detail: [],
|
|
661
|
+
},
|
|
662
|
+
emitJson,
|
|
663
|
+
process.cwd(),
|
|
664
|
+
)
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
const root = opts.root ?? (await mainWorktreeRoot())
|
|
668
|
+
|
|
669
|
+
if (opts.pullRequest && !/^\d+$/.test(opts.pullRequest)) {
|
|
670
|
+
return report(
|
|
671
|
+
{
|
|
672
|
+
ok: false,
|
|
673
|
+
reason: 'bad-input',
|
|
674
|
+
message: `Not a pull request number: ${opts.pullRequest}`,
|
|
675
|
+
detail: [],
|
|
676
|
+
},
|
|
677
|
+
emitJson,
|
|
678
|
+
root,
|
|
679
|
+
)
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
const outcome = await archiveTask(
|
|
683
|
+
root,
|
|
684
|
+
task
|
|
685
|
+
? { kind: 'stem', stem: task }
|
|
686
|
+
: { kind: 'pull-request', number: Number(opts.pullRequest) },
|
|
687
|
+
)
|
|
688
|
+
|
|
689
|
+
return report(outcome, emitJson, root)
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
function report(
|
|
693
|
+
outcome: ArchiveOutcome,
|
|
694
|
+
emitJson: boolean,
|
|
695
|
+
root: string,
|
|
696
|
+
): number {
|
|
697
|
+
if (emitJson) {
|
|
698
|
+
process.stdout.write(`${JSON.stringify(recordFor(outcome, root))}\n`)
|
|
699
|
+
return outcome.ok ? 0 : 1
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
intro('canon tasks archive')
|
|
703
|
+
|
|
704
|
+
if (!outcome.ok) {
|
|
705
|
+
logStep('Refused')
|
|
706
|
+
logError(outcome.message)
|
|
707
|
+
if (outcome.detail.length > 0) pipeOutput(outcome.detail.join('\n'))
|
|
708
|
+
outro()
|
|
709
|
+
return 1
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
logStep('Archived')
|
|
713
|
+
logRemove(relative(root, outcome.from))
|
|
714
|
+
logAdd(relative(root, outcome.to))
|
|
715
|
+
if (outcome.priorityRowRemoved) logInfo('cleared the ordering row')
|
|
716
|
+
if (outcome.indexRegenerated) logInfo('regenerated index.md')
|
|
717
|
+
outro()
|
|
718
|
+
|
|
719
|
+
return 0
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
function recordFor(
|
|
723
|
+
outcome: ArchiveOutcome,
|
|
724
|
+
root: string,
|
|
725
|
+
): Record<string, unknown> {
|
|
726
|
+
if (!outcome.ok) {
|
|
727
|
+
return {
|
|
728
|
+
ok: false,
|
|
729
|
+
reason: outcome.reason,
|
|
730
|
+
message: outcome.message,
|
|
731
|
+
detail: outcome.detail,
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
return {
|
|
736
|
+
ok: true,
|
|
737
|
+
task: outcome.stem,
|
|
738
|
+
from: relative(root, outcome.from),
|
|
739
|
+
to: relative(root, outcome.to),
|
|
740
|
+
priorityRowRemoved: outcome.priorityRowRemoved,
|
|
741
|
+
indexRegenerated: outcome.indexRegenerated,
|
|
742
|
+
}
|
|
743
|
+
}
|