@erclx/canon 5.31.0 → 5.33.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/README.md +1 -1
- package/claude/.claude-plugin/plugin.json +1 -1
- package/claude/skills/api-design/references/adopted.md +1 -1
- package/claude/skills/auto-ship/REQUIREMENT.md +4 -16
- package/claude/skills/auto-ship/SKILL.md +13 -58
- package/claude/skills/auto-ship/references/draft-mark.md +2 -2
- package/claude/skills/auto-ship/references/failure-recovery.md +1 -5
- package/claude/skills/auto-ship/references/tier-failures.md +1 -1
- package/claude/skills/auto-ship/references/ui-checklist.md +2 -2
- package/claude/skills/auto-ship/references/verb-absent.md +3 -27
- package/claude/skills/auto-ship/references/worktree-name.md +1 -1
- package/claude/skills/backlog-triage/REQUIREMENT.md +2 -2
- package/claude/skills/backlog-triage/SKILL.md +2 -2
- package/claude/skills/canon-cli/REQUIREMENT.md +19 -18
- package/claude/skills/canon-cli/SKILL.md +75 -32
- package/claude/skills/canon-feedback/REQUIREMENT.md +1 -1
- package/claude/skills/canon-feedback/SKILL.md +11 -14
- package/claude/skills/canon-feedback-triage/REQUIREMENT.md +13 -14
- package/claude/skills/canon-feedback-triage/SKILL.md +49 -30
- package/claude/skills/{canvas → canvas-board}/REQUIREMENT.md +5 -6
- package/claude/skills/{canvas → canvas-board}/SKILL.md +7 -7
- package/{standards → claude/skills/canvas-board/references}/canvas.md +12 -1
- package/{standards → claude/skills/canvas-board/references}/design.md +13 -5
- package/claude/skills/ci-workflow/REQUIREMENT.md +0 -1
- package/claude/skills/context-fold/REQUIREMENT.md +28 -48
- package/claude/skills/context-fold/SKILL.md +26 -95
- package/claude/skills/context-fold/references/classify.md +7 -8
- package/claude/skills/context-fold/references/completion-report.md +4 -8
- package/claude/skills/context-fold/references/context-refresh.md +7 -17
- package/{standards → claude/skills/context-fold/references}/context.md +19 -10
- package/claude/skills/context-fold/references/unusable-baseline.md +4 -8
- package/claude/skills/create-rule/REQUIREMENT.md +0 -1
- package/claude/skills/create-rule/SKILL.md +2 -2
- package/{standards → claude/skills/create-rule/references}/rule.md +12 -5
- package/claude/skills/create-skill/REQUIREMENT.md +6 -4
- package/claude/skills/create-skill/SKILL.md +10 -9
- package/{standards → claude/skills/create-skill/references}/skill-paths.md +1 -0
- package/{standards → claude/skills/create-skill/references}/skill.md +18 -15
- package/claude/skills/decision-escalate/REQUIREMENT.md +1 -1
- package/claude/skills/decision-escalate/SKILL.md +1 -1
- package/claude/skills/design-taste/REQUIREMENT.md +3 -5
- package/claude/skills/design-taste/SKILL.md +2 -4
- package/claude/skills/design-taste/references/vocabulary.md +1 -1
- package/claude/skills/docs-sync/REQUIREMENT.md +3 -3
- package/claude/skills/docs-sync/SKILL.md +3 -3
- package/{standards → claude/skills/docs-sync/references}/docs.md +11 -0
- package/{standards → claude/skills/docs-sync/references}/readme.md +9 -2
- package/claude/skills/document-health/REQUIREMENT.md +2 -2
- package/claude/skills/document-health/SKILL.md +4 -5
- package/claude/skills/document-health/references/axes.md +4 -6
- package/claude/skills/draft-and-pick/REQUIREMENT.md +16 -14
- package/claude/skills/draft-and-pick/SKILL.md +40 -32
- package/claude/skills/draft-and-pick/references/live-arms.md +9 -9
- package/claude/skills/draft-doc/REQUIREMENT.md +5 -5
- package/claude/skills/draft-doc/SKILL.md +9 -10
- package/claude/skills/draft-doc/references/requirements.md +61 -0
- package/claude/skills/draft-doc/references/wiki-kind.md +53 -0
- package/claude/skills/draft-doc/references/wiki.md +50 -30
- package/claude/skills/draft-figure/REQUIREMENT.md +2 -2
- package/claude/skills/draft-figure/SKILL.md +5 -5
- package/claude/skills/draft-figure/references/architecture-set.md +4 -4
- package/claude/skills/draft-figure/references/hand-drawn.md +2 -2
- package/claude/skills/draft-figure/references/mermaid-path.md +55 -0
- package/claude/skills/draft-figure/references/mermaid.md +43 -34
- package/claude/skills/draft-identity/REQUIREMENT.md +3 -3
- package/claude/skills/draft-identity/SKILL.md +10 -8
- package/claude/skills/draft-ready/REQUIREMENT.md +1 -1
- package/claude/skills/draft-ready/SKILL.md +7 -7
- package/claude/skills/draft-ready/references/assembly.md +1 -1
- package/{standards → claude/skills/draft-ready/references}/ready.md +13 -5
- package/claude/skills/git-branch/SKILL.md +1 -1
- package/{standards → claude/skills/git-branch/references}/branch.md +1 -1
- package/claude/skills/git-commit/SKILL.md +2 -2
- package/claude/skills/git-followup/REQUIREMENT.md +1 -1
- package/claude/skills/git-followup/SKILL.md +1 -1
- package/claude/skills/git-issue/SKILL.md +1 -1
- package/claude/skills/git-issue/references/issue.md +3 -3
- package/claude/skills/git-pr/SKILL.md +13 -13
- package/claude/skills/git-pr/references/evidence.md +2 -2
- package/claude/skills/git-pr/references/final-command.md +38 -14
- package/claude/skills/git-pr/references/labels.md +5 -1
- package/{standards → claude/skills/git-pr/references}/pr.md +19 -9
- package/{standards → claude/skills/git-pr/references}/publish.md +5 -3
- package/claude/skills/git-pr/references/task-number.md +1 -1
- package/claude/skills/git-ship/REQUIREMENT.md +0 -2
- package/claude/skills/git-ship/SKILL.md +5 -12
- package/claude/skills/git-split/SKILL.md +3 -3
- package/claude/skills/git-stage/SKILL.md +1 -1
- package/claude/skills/plan-feature/REQUIREMENT.md +1 -1
- package/claude/skills/plan-feature/SKILL.md +2 -6
- package/{standards → claude/skills/plan-feature/references}/plan.md +9 -10
- package/claude/skills/plan-groundwork/SKILL.md +5 -6
- package/{standards → claude/skills/plan-groundwork/references}/groundwork.md +17 -4
- package/claude/skills/plan-intake/SKILL.md +2 -3
- package/{standards → claude/skills/plan-intake/references}/intake.md +17 -2
- package/claude/skills/plan-intake-answer/REQUIREMENT.md +1 -1
- package/claude/skills/plan-intake-answer/SKILL.md +1 -1
- package/claude/skills/review-address/SKILL.md +2 -2
- package/claude/skills/review-address/references/post-review-findings.md +1 -1
- package/claude/skills/review-craft/REQUIREMENT.md +3 -3
- package/claude/skills/review-craft/SKILL.md +2 -2
- package/claude/skills/review-craft/references/ui.md +4 -4
- package/claude/skills/review-pr/REQUIREMENT.md +2 -2
- package/claude/skills/review-pr/SKILL.md +8 -10
- package/claude/skills/review-pr/references/body-variants.md +2 -2
- package/claude/skills/review-pr/references/key-changes.md +3 -3
- package/claude/skills/review-pr/references/post.md +4 -2
- package/claude/skills/review-ui/REQUIREMENT.md +1 -2
- package/claude/skills/review-ui/SKILL.md +2 -2
- package/claude/skills/review-ui/references/post.md +1 -1
- package/claude/skills/role-orchestrator/REQUIREMENT.md +3 -3
- package/claude/skills/role-orchestrator/SKILL.md +10 -10
- package/claude/skills/role-orchestrator/references/orchestrator-dispatch.md +3 -3
- package/claude/skills/role-orchestrator/references/orchestrator-handoff.md +9 -9
- package/claude/skills/role-orchestrator/references/orchestrator-launch.md +23 -1
- package/claude/skills/role-orchestrator/references/orchestrator-parked.md +2 -2
- package/claude/skills/role-orchestrator/references/orchestrator-refill.md +2 -5
- package/claude/skills/role-orchestrator/references/orchestrator-resume.md +4 -1
- package/claude/skills/role-planner/REQUIREMENT.md +2 -1
- package/claude/skills/role-planner/SKILL.md +15 -4
- package/claude/skills/role-reviewer/SKILL.md +2 -2
- package/claude/skills/role-worker/REQUIREMENT.md +1 -0
- package/claude/skills/role-worker/SKILL.md +11 -3
- package/claude/skills/session-compact/REQUIREMENT.md +1 -4
- package/claude/skills/session-compact/SKILL.md +3 -13
- package/claude/skills/session-compact/references/handoff-note.md +2 -2
- package/claude/skills/session-map/REQUIREMENT.md +1 -9
- package/claude/skills/session-map/SKILL.md +9 -17
- package/{standards → claude/skills/session-map/references}/session.md +17 -11
- package/claude/skills/session-relay/REQUIREMENT.md +1 -1
- package/claude/skills/session-resume/REQUIREMENT.md +6 -8
- package/claude/skills/session-resume/SKILL.md +3 -9
- package/claude/skills/session-worktree/SKILL.md +6 -6
- package/claude/skills/session-worktree/references/main-root-writes.md +2 -2
- package/claude/skills/systematic-debugging/REQUIREMENT.md +0 -1
- package/claude/skills/target-check/REQUIREMENT.md +3 -3
- package/claude/skills/target-check/SKILL.md +1 -1
- package/claude/skills/target-check/references/domains.md +1 -1
- package/claude/skills/target-setup/REQUIREMENT.md +4 -4
- package/claude/skills/target-setup/SKILL.md +3 -3
- package/claude/skills/target-setup/references/detect.md +2 -2
- package/claude/skills/task-board/REQUIREMENT.md +7 -12
- package/claude/skills/task-board/SKILL.md +9 -21
- package/{standards → claude/skills/task-board/references}/board.md +9 -0
- package/claude/skills/task-board/references/decline.md +1 -1
- package/{standards → claude/skills/task-board/references}/tasks.md +15 -10
- package/claude/skills/task-complete/REQUIREMENT.md +47 -0
- package/claude/skills/task-complete/SKILL.md +86 -0
- package/claude/skills/{task-board → task-complete}/references/archive.md +5 -5
- package/claude/skills/task-complete/references/receipt-sweep.md +32 -0
- package/claude/skills/task-complete/references/unusable-baseline.md +19 -0
- package/claude/skills/teach-workspace/REQUIREMENT.md +6 -2
- package/claude/skills/teach-workspace/SKILL.md +9 -5
- package/claude/skills/teach-workspace/references/lesson-craft.md +1 -1
- package/claude/skills/teach-workspace/references/promotion-fold.md +29 -0
- package/claude/skills/teach-workspace/references/promotion.md +3 -3
- package/claude/skills/teach-workspace/references/revisit.md +1 -1
- package/{standards → claude/skills/teach-workspace/references}/teach.md +17 -5
- package/claude/skills/ui-checklist/SKILL.md +1 -1
- package/claude/skills/ux-audit/REQUIREMENT.md +2 -2
- package/claude/skills/ux-audit/SKILL.md +3 -4
- package/claude/skills/ux-measure/SKILL.md +1 -1
- package/claude/skills/write-human/REQUIREMENT.md +0 -1
- package/claude/skills/write-human/SKILL.md +1 -1
- package/docs/agents/audits.md +1 -1
- package/docs/agents/canvas.md +1 -1
- package/docs/agents/commands.md +4 -8
- package/docs/agents/context-audit-checks.md +11 -25
- package/docs/agents/context-audit.md +7 -15
- package/docs/agents/context-classify.md +5 -5
- package/docs/agents/counts.md +5 -5
- package/docs/agents/drift-surfaces.md +2 -2
- package/docs/agents/index.md +5 -7
- package/docs/agents/indexes.md +1 -1
- package/docs/agents/install-and-sync.md +6 -11
- package/docs/agents/intake.md +1 -1
- package/docs/agents/key-changes.md +5 -5
- package/docs/agents/label-coverage.md +11 -0
- package/docs/agents/migrate.md +1 -1
- package/docs/agents/records-push.md +2 -2
- package/docs/agents/records-stale.md +13 -48
- package/docs/agents/records-validate.md +4 -8
- package/docs/agents/records.md +6 -28
- package/docs/agents/restated.md +1 -1
- package/docs/agents/rule-citations.md +2 -2
- package/docs/agents/sandbox.md +4 -4
- package/docs/agents/skills-audit.md +2 -2
- package/docs/agents/state-scoped-risk.md +2 -2
- package/docs/agents/superseded.md +2 -2
- package/docs/agents/tasks-plans.md +1 -1
- package/docs/agents/tasks-validate.md +1 -1
- package/docs/agents/tasks.md +3 -3
- package/docs/agents/teach.md +1 -1
- package/docs/agents/upstream.md +26 -2
- package/docs/target/migrations.md +32 -0
- package/docs/target/projects.md +5 -7
- package/docs/target/scenarios.md +2 -2
- package/docs/target/sync.md +4 -4
- package/docs/workflow/ai-workflow.md +7 -38
- package/docs/workflow/index.md +1 -1
- package/docs/workflow/operating-model.md +10 -10
- package/docs/workflow/parallel-features.md +12 -12
- package/docs/workflow/skill-map-on-request.md +21 -24
- package/docs/workflow/skill-map.md +23 -34
- package/docs/workflow/visual-design-workflow.md +13 -16
- package/governance/renames.toml +0 -30
- package/governance/rules/canon/605-worktrees.md +1 -1
- package/governance/rules/canon/context.md +13 -0
- package/governance/rules/{standards → canon}/plan.md +4 -5
- package/governance/rules/canon/tasks.md +18 -0
- package/governance/rules/claude/skill.md +17 -0
- package/governance/stacks/base.toml +2 -4
- package/package.json +4 -4
- package/scripts/core/install-check.sh +4 -4
- package/scripts/core/regen-web-previews.ts +1 -1
- package/scripts/lib/ui.sh +0 -159
- package/src/audits/catalog.ts +5 -98
- package/src/claude/cases/authoring.ts +0 -18
- package/src/claude/cases/misc.ts +1 -14
- package/src/claude/cases/setup.ts +7 -20
- package/src/claude/cases/workflow.ts +6 -34
- package/src/claude/seeds.ts +1 -7
- package/src/claude/skills-audit.ts +3 -3
- package/src/cli/help.ts +4 -5
- package/src/cli/ui.ts +2 -3
- package/src/cli.ts +0 -4
- package/src/commands/claude.ts +9 -15
- package/src/commands/context.ts +18 -280
- package/src/commands/feedback.ts +22 -91
- package/src/commands/gov.ts +2 -15
- package/src/commands/labels.ts +326 -7
- package/src/commands/migrate.ts +6 -1
- package/src/commands/pr.ts +1 -1
- package/src/commands/records.ts +17 -403
- package/src/commands/sandbox.ts +3 -6
- package/src/commands/sync.ts +5 -3
- package/src/commands/tasks.ts +3 -3
- package/src/commands/upstream.ts +135 -0
- package/src/context/audit.ts +10 -19
- package/src/context/classify/extract.ts +6 -13
- package/src/context/classify/patterns.ts +2 -41
- package/src/context/classify/prompts.ts +2 -6
- package/src/context/classify/run.ts +3 -3
- package/src/context/folders.ts +8 -13
- package/src/context/gate.ts +11 -91
- package/src/context/requirements.ts +13 -4
- package/src/counts/scan.ts +3 -3
- package/src/design/budget.ts +1 -1
- package/src/design/components.ts +3 -3
- package/src/design/document.ts +1 -1
- package/src/design/regen.ts +1 -1
- package/src/design/render.ts +1 -1
- package/src/feedback/body.ts +0 -12
- package/src/gate/measures.ts +7 -58
- package/src/gate/sequencer.ts +56 -1
- package/src/gate/stages.ts +1 -7
- package/src/gov/citations.ts +9 -3
- package/src/gov/install.ts +2 -3
- package/src/gov/restated.ts +3 -3
- package/src/gov/stacks.ts +1 -1
- package/src/hooks/post-merge.ts +1 -1
- package/src/labels/apply.ts +39 -0
- package/src/labels/format.ts +3 -3
- package/src/labels/phase.ts +3 -3
- package/src/labels/sections.ts +43 -0
- package/src/markdown/structure.ts +2 -2
- package/src/migrate/record-layout.ts +3 -3
- package/src/migrate/skill-names.ts +20 -1
- package/src/pr/paths.ts +4 -4
- package/src/records/backup.ts +16 -6
- package/src/records/ordinal.ts +1 -1
- package/src/records/prune.ts +2 -1
- package/src/records/stale-canonical.ts +33 -3
- package/src/records/validate.ts +2 -188
- package/src/roots/record.ts +1 -1
- package/src/sandbox/census.ts +1 -1
- package/src/sandbox/coverage.ts +2 -6
- package/src/sandbox/equivalence.ts +5 -44
- package/src/sandbox/expect.ts +4 -4
- package/src/sandbox/provision.ts +13 -36
- package/src/sandbox/scenario.ts +137 -55
- package/src/sandbox/tree.ts +2 -6
- package/src/shipped/references.ts +3 -3
- package/src/standards/read.ts +44 -0
- package/src/sync/git.ts +1 -1
- package/src/sync/seeds-report.ts +1 -1
- package/src/tasks/archive.ts +5 -5
- package/src/tasks/branch.ts +3 -3
- package/src/tasks/label.ts +1 -1
- package/src/tasks/reach.ts +2 -2
- package/src/tasks/record.ts +2 -2
- package/src/tasks/validate.ts +2 -2
- package/src/teach/workspace.ts +1 -1
- package/src/upstream/cursor.ts +1 -1
- package/src/upstream/due.ts +128 -0
- package/src/upstream/releases.ts +2 -1
- package/standards/index.md +0 -35
- package/standards/standard.md +1 -7
- package/tooling/base/reference.md +2 -2
- package/tooling/base/seeds/.github/pull_request_template.md +2 -2
- package/tooling/claude/reference.md +7 -21
- package/tooling/claude/seeds/.claude/hooks/pr-create-log.sh +9 -1
- package/tooling/claude/seeds/.claude/hooks/records-index.sh +8 -20
- package/tooling/claude/seeds/.claude/hooks/review-post-scan.sh +171 -0
- package/tooling/claude/seeds/.claude/hooks/standards-audit.sh +3 -3
- package/tooling/claude/seeds/.claude/settings.json +9 -0
- package/tooling/claude/seeds/CLAUDE.md +1 -3
- package/tooling/claude/seeds/canon/REQUIREMENTS.md +2 -9
- package/tooling/web/configs/e2e/screenshot.ts +0 -1
- package/claude/skills/auto-ship/references/review-findings.md +0 -20
- package/claude/skills/bash-cli-script/REQUIREMENT.md +0 -43
- package/claude/skills/bash-cli-script/SKILL.md +0 -53
- package/claude/skills/bash-cli-script/references/template.md +0 -19
- package/claude/skills/canon-operator/REQUIREMENT.md +0 -62
- package/claude/skills/canon-operator/SKILL.md +0 -113
- package/claude/skills/canon-rollout/REQUIREMENT.md +0 -59
- package/claude/skills/canon-rollout/SKILL.md +0 -140
- package/claude/skills/canon-rollout/references/failure-recovery.md +0 -20
- package/claude/skills/context-fold/references/anchor-sweep.md +0 -58
- package/claude/skills/context-fold/references/promoted-pages.md +0 -29
- package/claude/skills/context-fold/references/receipt-sweep.md +0 -43
- package/claude/skills/context-fold/references/wireframe-sweep.md +0 -45
- package/claude/skills/create-standard/REQUIREMENT.md +0 -33
- package/claude/skills/create-standard/SKILL.md +0 -31
- package/claude/skills/design-extract/REQUIREMENT.md +0 -42
- package/claude/skills/design-extract/SKILL.md +0 -108
- package/claude/skills/draft-and-pick/references/frame.html +0 -118
- package/claude/skills/draft-doc/references/wireframes.md +0 -48
- package/claude/skills/markdown-propose/REQUIREMENT.md +0 -47
- package/claude/skills/markdown-propose/SKILL.md +0 -122
- package/claude/skills/markdown-propose/references/format.md +0 -118
- package/claude/skills/memory-capture/REQUIREMENT.md +0 -50
- package/claude/skills/memory-capture/SKILL.md +0 -117
- package/claude/skills/memory-review/REQUIREMENT.md +0 -52
- package/claude/skills/memory-review/SKILL.md +0 -129
- package/claude/skills/memory-review/references/later-phases.md +0 -118
- package/claude/skills/memory-review/references/receipt-format.md +0 -64
- package/claude/skills/project-commands/REQUIREMENT.md +0 -42
- package/claude/skills/project-commands/SKILL.md +0 -87
- package/claude/skills/repo-metadata/REQUIREMENT.md +0 -37
- package/claude/skills/repo-metadata/SKILL.md +0 -54
- package/claude/skills/restate-plainly/REQUIREMENT.md +0 -41
- package/claude/skills/restate-plainly/SKILL.md +0 -41
- package/claude/skills/review-branch/REQUIREMENT.md +0 -40
- package/claude/skills/review-branch/SKILL.md +0 -137
- package/claude/skills/seed-sync/REQUIREMENT.md +0 -45
- package/claude/skills/seed-sync/SKILL.md +0 -158
- package/claude/skills/sketch-design/REQUIREMENT.md +0 -38
- package/claude/skills/sketch-design/SKILL.md +0 -94
- package/claude/skills/ux-walkthrough/REQUIREMENT.md +0 -56
- package/claude/skills/ux-walkthrough/SKILL.md +0 -53
- package/claude/skills/ux-walkthrough/references/builds.md +0 -15
- package/claude/skills/ux-walkthrough/references/candidate-pages.md +0 -11
- package/claude/skills/ux-walkthrough/references/measuring.md +0 -22
- package/claude/skills/ux-walkthrough/references/record.md +0 -36
- package/claude/skills/ux-walkthrough/references/relay.md +0 -25
- package/docs/agents/architecture-record.md +0 -36
- package/docs/agents/review-classification.md +0 -76
- package/governance/rules/canon/603-memory.md +0 -11
- package/governance/rules/lang/120-bash.md +0 -18
- package/governance/rules/standards/architecture.md +0 -13
- package/governance/rules/standards/context.md +0 -14
- package/governance/rules/standards/design.md +0 -12
- package/governance/rules/standards/groundwork.md +0 -13
- package/governance/rules/standards/intake.md +0 -12
- package/governance/rules/standards/memory.md +0 -12
- package/governance/rules/standards/readme.md +0 -12
- package/governance/rules/standards/ready.md +0 -13
- package/governance/rules/standards/requirements.md +0 -12
- package/governance/rules/standards/rule.md +0 -13
- package/governance/rules/standards/session.md +0 -13
- package/governance/rules/standards/skill.md +0 -21
- package/governance/rules/standards/standard.md +0 -13
- package/governance/rules/standards/tasks.md +0 -15
- package/governance/rules/standards/teach.md +0 -14
- package/governance/rules/standards/wiki.md +0 -13
- package/governance/rules/standards/wireframes.md +0 -13
- package/scripts/config.sh +0 -11
- package/scripts/lib/gov.sh +0 -14
- package/scripts/lib/sandbox-fixtures.sh +0 -191
- package/scripts/lib/sandbox-git.sh +0 -125
- package/scripts/lib/sandbox-path.sh +0 -50
- package/scripts/sandbox-hook.sh +0 -99
- package/src/autoship/classify.ts +0 -75
- package/src/autoship/paths.ts +0 -50
- package/src/commands/autoship.ts +0 -129
- package/src/commands/repo.ts +0 -393
- package/src/context/architecture.ts +0 -654
- package/src/context/wireframe-states.ts +0 -238
- package/src/gov/standard-rules.ts +0 -179
- package/src/records/migrate.ts +0 -78
- package/src/records/stale.ts +0 -243
- package/src/repo/metadata.ts +0 -206
- package/src/sandbox/hooks.ts +0 -128
- package/standards/architecture.md +0 -127
- package/standards/memory.md +0 -158
- package/standards/mermaid.md +0 -64
- package/standards/requirements.md +0 -79
- package/standards/wiki.md +0 -77
- package/standards/wireframes.md +0 -143
- package/tooling/claude/seeds/.claude/memory/index.md +0 -8
- package/tooling/claude/seeds/canon/ARCHITECTURE.md +0 -23
- package/tooling/claude/seeds/canon/wireframes/index.md +0 -8
- /package/{standards → claude/skills/create-skill/references}/skill-practice.md +0 -0
- /package/{standards → claude/skills/create-skill/references}/skill-requirement.md +0 -0
- /package/{standards → claude/skills/draft-figure/references}/figures.md +0 -0
- /package/{standards → claude/skills/git-branch/references}/slug.md +0 -0
- /package/{standards → claude/skills/git-commit/references}/commit.md +0 -0
- /package/{standards → claude/skills/git-commit/references}/versioning.md +0 -0
- /package/{standards → claude/skills/plan-feature/references}/plan-lifecycle.md +0 -0
- /package/{standards → claude/skills/plan-groundwork/references}/groundwork-spikes.md +0 -0
- /package/{standards → claude/skills/task-board/references}/tasks-decline.md +0 -0
- /package/{standards → claude/skills/teach-workspace/references}/glossary.md +0 -0
|
@@ -1,238 +0,0 @@
|
|
|
1
|
-
import { readFile, readdir, stat } from 'node:fs/promises'
|
|
2
|
-
import { basename, dirname, join, relative } from 'node:path'
|
|
3
|
-
import type { AuditedFolder } from '@/context/folders'
|
|
4
|
-
import { type BodyLine, bodyLines } from '@/markdown/scan'
|
|
5
|
-
|
|
6
|
-
/** `standards/wireframes.md`'s `## States` heading, matched by text alone. */
|
|
7
|
-
const STATES_HEADING = /^##\s+States\s*$/i
|
|
8
|
-
const SECTION_HEADING = /^##\s+\S/
|
|
9
|
-
const TABLE_ROW = /^\s*\|/
|
|
10
|
-
const TABLE_SEPARATOR = /^\s*\|[\s:|-]+\|\s*$/
|
|
11
|
-
|
|
12
|
-
/** The one exception the standard admits to the states/evidence bijection. */
|
|
13
|
-
const NOT_CAPTURED = 'not captured'
|
|
14
|
-
|
|
15
|
-
/** A fenced block's opening delimiter naming the `plaintext` info string. */
|
|
16
|
-
const PLAINTEXT_FENCE = /^`{3,}\s*plaintext\s*$/i
|
|
17
|
-
|
|
18
|
-
export interface StateRow {
|
|
19
|
-
readonly line: number
|
|
20
|
-
readonly state: string
|
|
21
|
-
/** The evidence cell as written, backticks and all. */
|
|
22
|
-
readonly evidence: string
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export interface MissingFolderFinding {
|
|
26
|
-
readonly line: number
|
|
27
|
-
readonly state: string
|
|
28
|
-
/** The cited path, so a report names what to go create or fix. */
|
|
29
|
-
readonly path: string
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export interface UnlistedFolderFinding {
|
|
33
|
-
/** The evidence root the folder sits under, cited by at least one row. */
|
|
34
|
-
readonly root: string
|
|
35
|
-
readonly folder: string
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export interface WireframeStatesReport {
|
|
39
|
-
readonly rel: string
|
|
40
|
-
readonly rows: readonly StateRow[]
|
|
41
|
-
/** A row whose evidence cell names a path with no folder at it. */
|
|
42
|
-
readonly missingFolders: readonly MissingFolderFinding[]
|
|
43
|
-
/** A folder under a cited root that no row names. */
|
|
44
|
-
readonly unlistedFolders: readonly UnlistedFolderFinding[]
|
|
45
|
-
/** Line of the `plaintext` fence, absent from an entry carrying no sketch. */
|
|
46
|
-
readonly sketchLine?: number
|
|
47
|
-
/** Whether that sketch sits beside a state whose evidence already exists. */
|
|
48
|
-
readonly sketchWithEvidence: boolean
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
function cells(row: string): string[] {
|
|
52
|
-
const parts = row.split('|')
|
|
53
|
-
if ((parts[0] ?? '').trim() === '') parts.shift()
|
|
54
|
-
if ((parts[parts.length - 1] ?? '').trim() === '') parts.pop()
|
|
55
|
-
return parts.map((cell) => cell.trim())
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
function columnIndex(headers: readonly string[], name: string): number {
|
|
59
|
-
return headers.findIndex(
|
|
60
|
-
(header) => header.toLowerCase() === name.toLowerCase(),
|
|
61
|
-
)
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
* Reads the States table under the `## States` heading, matching its `State`
|
|
66
|
-
* and `Evidence` columns by header text rather than position.
|
|
67
|
-
*
|
|
68
|
-
* Column order is the one part of the standard's own table the standard could
|
|
69
|
-
* still move during its own review, per the plan this ships under. Matching
|
|
70
|
-
* position would break silently on a reorder, where matching text breaks the
|
|
71
|
-
* same way a renamed header would: visibly, by finding nothing.
|
|
72
|
-
*/
|
|
73
|
-
export function parseStatesTable(lines: readonly BodyLine[]): StateRow[] {
|
|
74
|
-
let index = 0
|
|
75
|
-
while (index < lines.length && !STATES_HEADING.test(lines[index].text)) {
|
|
76
|
-
index++
|
|
77
|
-
}
|
|
78
|
-
if (index >= lines.length) return []
|
|
79
|
-
index++
|
|
80
|
-
|
|
81
|
-
while (index < lines.length && !SECTION_HEADING.test(lines[index].text)) {
|
|
82
|
-
const separator = lines[index + 1]
|
|
83
|
-
if (
|
|
84
|
-
TABLE_ROW.test(lines[index].text) &&
|
|
85
|
-
separator !== undefined &&
|
|
86
|
-
TABLE_SEPARATOR.test(separator.text)
|
|
87
|
-
) {
|
|
88
|
-
break
|
|
89
|
-
}
|
|
90
|
-
index++
|
|
91
|
-
}
|
|
92
|
-
if (
|
|
93
|
-
index >= lines.length ||
|
|
94
|
-
SECTION_HEADING.test(lines[index].text) ||
|
|
95
|
-
!TABLE_ROW.test(lines[index].text)
|
|
96
|
-
) {
|
|
97
|
-
return []
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
const headers = cells(lines[index].text)
|
|
101
|
-
const stateCol = columnIndex(headers, 'State')
|
|
102
|
-
const evidenceCol = columnIndex(headers, 'Evidence')
|
|
103
|
-
if (stateCol === -1 || evidenceCol === -1) return []
|
|
104
|
-
|
|
105
|
-
index += 2
|
|
106
|
-
const rows: StateRow[] = []
|
|
107
|
-
while (index < lines.length && TABLE_ROW.test(lines[index].text)) {
|
|
108
|
-
const row = cells(lines[index].text)
|
|
109
|
-
rows.push({
|
|
110
|
-
line: lines[index].number,
|
|
111
|
-
state: row[stateCol] ?? '',
|
|
112
|
-
evidence: row[evidenceCol] ?? '',
|
|
113
|
-
})
|
|
114
|
-
index++
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
return rows
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
/** Line of the first `plaintext`-fenced sketch, or nothing. */
|
|
121
|
-
export function findSketchLine(lines: readonly BodyLine[]): number | undefined {
|
|
122
|
-
for (const line of lines) {
|
|
123
|
-
if (PLAINTEXT_FENCE.test(line.text.trim())) return line.number
|
|
124
|
-
}
|
|
125
|
-
return undefined
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
/**
|
|
129
|
-
* Reads an evidence cell into the path it cites, or nothing for the one cell
|
|
130
|
-
* value the standard exempts from having one.
|
|
131
|
-
*/
|
|
132
|
-
function evidencePath(cell: string): string | undefined {
|
|
133
|
-
const stripped = cell.replace(/^`+|`+$/g, '').trim()
|
|
134
|
-
if (stripped.toLowerCase() === NOT_CAPTURED) return undefined
|
|
135
|
-
return stripped.replace(/\/+$/, '')
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
async function isDirectory(path: string): Promise<boolean> {
|
|
139
|
-
try {
|
|
140
|
-
return (await stat(path)).isDirectory()
|
|
141
|
-
} catch {
|
|
142
|
-
return false
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
async function subfolders(path: string): Promise<string[]> {
|
|
147
|
-
try {
|
|
148
|
-
const entries = await readdir(path, { withFileTypes: true })
|
|
149
|
-
return entries
|
|
150
|
-
.filter((entry) => entry.isDirectory())
|
|
151
|
-
.map((entry) => entry.name)
|
|
152
|
-
} catch {
|
|
153
|
-
return []
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
/**
|
|
158
|
-
* Measures one wireframe entry against its own States table.
|
|
159
|
-
*
|
|
160
|
-
* The evidence cell resolves as the literal path it names against `root`,
|
|
161
|
-
* per the plan's operator answer, since the standard puts the path there and a
|
|
162
|
-
* root guessed from convention reads wrong in a monorepo carrying more than
|
|
163
|
-
* one evidence tree.
|
|
164
|
-
*
|
|
165
|
-
* An unlisted folder is reported only under a root at least one row already
|
|
166
|
-
* cites, per the same operator answer, so a project holding evidence with no
|
|
167
|
-
* states table at all reports nothing. `roots` is built from the rows this
|
|
168
|
-
* loop already resolved rather than scanned separately, which is what keeps
|
|
169
|
-
* the two readings in the same pass.
|
|
170
|
-
*/
|
|
171
|
-
export async function measureWireframeStates(
|
|
172
|
-
root: string,
|
|
173
|
-
rel: string,
|
|
174
|
-
source: string,
|
|
175
|
-
): Promise<WireframeStatesReport> {
|
|
176
|
-
const lines = bodyLines(source)
|
|
177
|
-
const rows = parseStatesTable(lines)
|
|
178
|
-
const sketchLine = findSketchLine(lines)
|
|
179
|
-
|
|
180
|
-
const missingFolders: MissingFolderFinding[] = []
|
|
181
|
-
const cited = new Map<string, Set<string>>()
|
|
182
|
-
let anyCaptured = false
|
|
183
|
-
|
|
184
|
-
for (const row of rows) {
|
|
185
|
-
const path = evidencePath(row.evidence)
|
|
186
|
-
if (path === undefined) continue
|
|
187
|
-
|
|
188
|
-
if (!(await isDirectory(join(root, path)))) {
|
|
189
|
-
missingFolders.push({ line: row.line, state: row.state, path })
|
|
190
|
-
continue
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
anyCaptured = true
|
|
194
|
-
const evidenceRoot = dirname(path)
|
|
195
|
-
const folder = basename(path)
|
|
196
|
-
const named = cited.get(evidenceRoot) ?? new Set<string>()
|
|
197
|
-
named.add(folder)
|
|
198
|
-
cited.set(evidenceRoot, named)
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
const unlistedFolders: UnlistedFolderFinding[] = []
|
|
202
|
-
for (const [evidenceRoot, named] of cited) {
|
|
203
|
-
for (const folder of await subfolders(join(root, evidenceRoot))) {
|
|
204
|
-
if (!named.has(folder)) {
|
|
205
|
-
unlistedFolders.push({ root: evidenceRoot, folder })
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
return {
|
|
211
|
-
rel,
|
|
212
|
-
rows,
|
|
213
|
-
missingFolders,
|
|
214
|
-
unlistedFolders,
|
|
215
|
-
...(sketchLine !== undefined && { sketchLine }),
|
|
216
|
-
sketchWithEvidence: sketchLine !== undefined && anyCaptured,
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
/** Measures every wireframe entry in a resolved `wireframes` folder. */
|
|
221
|
-
export async function measureWireframeFolder(
|
|
222
|
-
root: string,
|
|
223
|
-
folder: AuditedFolder,
|
|
224
|
-
): Promise<WireframeStatesReport[]> {
|
|
225
|
-
const reports: WireframeStatesReport[] = []
|
|
226
|
-
|
|
227
|
-
for (const path of folder.entries) {
|
|
228
|
-
reports.push(
|
|
229
|
-
await measureWireframeStates(
|
|
230
|
-
root,
|
|
231
|
-
relative(root, path),
|
|
232
|
-
await readFile(path, 'utf8'),
|
|
233
|
-
),
|
|
234
|
-
)
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
return reports
|
|
238
|
-
}
|
|
@@ -1,179 +0,0 @@
|
|
|
1
|
-
import { existsSync, readdirSync, readFileSync } from 'node:fs'
|
|
2
|
-
import { mkdir, rm, writeFile } from 'node:fs/promises'
|
|
3
|
-
import { basename, join, relative } from 'node:path'
|
|
4
|
-
import { listRuleSourcePaths, rulesSourceDir } from '@/gov/install'
|
|
5
|
-
import { parseFrontmatter } from '@/indexes/frontmatter'
|
|
6
|
-
|
|
7
|
-
const STANDARDS_REL = 'standards'
|
|
8
|
-
|
|
9
|
-
/** The band the generated rules ship in, named for what they point at. */
|
|
10
|
-
export const STANDARD_RULES_BAND = 'standards'
|
|
11
|
-
|
|
12
|
-
export type StandardRulesResult =
|
|
13
|
-
| { readonly ok: true; readonly written: readonly string[] }
|
|
14
|
-
| { readonly ok: false; readonly reason: string }
|
|
15
|
-
|
|
16
|
-
interface StandardRule {
|
|
17
|
-
readonly name: string
|
|
18
|
-
readonly sourceRel: string
|
|
19
|
-
readonly title: string
|
|
20
|
-
readonly description: string
|
|
21
|
-
readonly paths: readonly string[]
|
|
22
|
-
readonly bullets: readonly string[]
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export function standardRulesDir(root: string): string {
|
|
26
|
-
return join(rulesSourceDir(root), STANDARD_RULES_BAND)
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* Generates one path-scoped rule per standard whose frontmatter carries
|
|
31
|
-
* `paths:`. The standard owns the glob and the operative bullets, so the rule
|
|
32
|
-
* is output, committed beside the authored bands so every reader of
|
|
33
|
-
* `governance/rules/` sees it as an ordinary file.
|
|
34
|
-
*
|
|
35
|
-
* Every standard is read and checked before anything is written, so a refusal
|
|
36
|
-
* leaves the previous output whole rather than half cleared.
|
|
37
|
-
*/
|
|
38
|
-
export async function regenStandardRules(
|
|
39
|
-
root: string,
|
|
40
|
-
): Promise<StandardRulesResult> {
|
|
41
|
-
const standardsDir = join(root, STANDARDS_REL)
|
|
42
|
-
if (!existsSync(standardsDir)) return { ok: true, written: [] }
|
|
43
|
-
|
|
44
|
-
const reserved = reservedNames(root)
|
|
45
|
-
const rules: StandardRule[] = []
|
|
46
|
-
|
|
47
|
-
for (const file of readdirSync(standardsDir).sort()) {
|
|
48
|
-
if (!file.endsWith('.md')) continue
|
|
49
|
-
const read = readStandard(root, file, reserved)
|
|
50
|
-
if (typeof read === 'string') return { ok: false, reason: read }
|
|
51
|
-
if (read !== undefined) rules.push(read)
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
const dir = standardRulesDir(root)
|
|
55
|
-
await rm(dir, { recursive: true, force: true })
|
|
56
|
-
if (rules.length > 0) await mkdir(dir, { recursive: true })
|
|
57
|
-
|
|
58
|
-
const written: string[] = []
|
|
59
|
-
for (const rule of rules) {
|
|
60
|
-
const dest = join(dir, `${rule.name}.md`)
|
|
61
|
-
await writeFile(dest, renderStandardRule(rule))
|
|
62
|
-
written.push(relative(root, dest))
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
return { ok: true, written }
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* Band folders and authored rule basenames. A bare-word rule name equal to a
|
|
70
|
-
* band would install the whole band through `--add`, and one equal to an
|
|
71
|
-
* authored rule would shadow it in the name index.
|
|
72
|
-
*/
|
|
73
|
-
function reservedNames(root: string): {
|
|
74
|
-
readonly bands: ReadonlySet<string>
|
|
75
|
-
readonly rules: ReadonlySet<string>
|
|
76
|
-
} {
|
|
77
|
-
const bands = new Set<string>([STANDARD_RULES_BAND])
|
|
78
|
-
const rules = new Set<string>()
|
|
79
|
-
|
|
80
|
-
for (const rel of listRuleSourcePaths(root)) {
|
|
81
|
-
const segments = rel.split('/')
|
|
82
|
-
if (segments.length > 1) bands.add(segments[0])
|
|
83
|
-
if (segments[0] === STANDARD_RULES_BAND) continue
|
|
84
|
-
rules.add(basename(rel, '.md'))
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
return { bands, rules }
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
/** A rule to render, `undefined` for a standard with no `paths:`, or a reason. */
|
|
91
|
-
function readStandard(
|
|
92
|
-
root: string,
|
|
93
|
-
file: string,
|
|
94
|
-
reserved: ReturnType<typeof reservedNames>,
|
|
95
|
-
): StandardRule | string | undefined {
|
|
96
|
-
const sourceRel = `${STANDARDS_REL}/${file}`
|
|
97
|
-
const fields = parseFrontmatter(
|
|
98
|
-
readFileSync(join(root, STANDARDS_REL, file), 'utf8'),
|
|
99
|
-
)?.fields
|
|
100
|
-
if (fields === undefined || fields.paths === undefined) return undefined
|
|
101
|
-
|
|
102
|
-
const name = basename(file, '.md')
|
|
103
|
-
if (!isStringList(fields.paths)) {
|
|
104
|
-
return `${sourceRel}: paths must be a list of strings`
|
|
105
|
-
}
|
|
106
|
-
if (fields.rule !== undefined && !isStringList(fields.rule)) {
|
|
107
|
-
return `${sourceRel}: rule must be a list of strings`
|
|
108
|
-
}
|
|
109
|
-
if (reserved.bands.has(name)) {
|
|
110
|
-
return `${sourceRel}: name collides with a rule band folder`
|
|
111
|
-
}
|
|
112
|
-
if (reserved.rules.has(name)) {
|
|
113
|
-
return `${sourceRel}: name collides with an authored rule`
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
return {
|
|
117
|
-
name,
|
|
118
|
-
sourceRel,
|
|
119
|
-
title: typeof fields.title === 'string' ? fields.title : name,
|
|
120
|
-
description:
|
|
121
|
-
typeof fields.description === 'string' ? fields.description : '',
|
|
122
|
-
paths: fields.paths,
|
|
123
|
-
bullets: fields.rule ?? [],
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
function isStringList(value: unknown): value is string[] {
|
|
128
|
-
return (
|
|
129
|
-
Array.isArray(value) && value.every((entry) => typeof entry === 'string')
|
|
130
|
-
)
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
function renderStandardRule(rule: StandardRule): string {
|
|
134
|
-
const scope = rule.description.replace(/\.$/, '')
|
|
135
|
-
const pointer = [
|
|
136
|
-
`Follow the ${rule.name} standard for ${lowerFirst(scope)}.`,
|
|
137
|
-
'It is the single source.',
|
|
138
|
-
`Read it with \`canon standards ${rule.name}\`.`,
|
|
139
|
-
].join(' ')
|
|
140
|
-
|
|
141
|
-
return [
|
|
142
|
-
'---',
|
|
143
|
-
`# Generated by \`canon gov regen\` from ${rule.sourceRel}. Edit that frontmatter, not this file.`,
|
|
144
|
-
`description: ${yamlScalar(rule.description)}`,
|
|
145
|
-
'paths:',
|
|
146
|
-
...rule.paths.map((glob) => ` - ${yamlQuoted(glob)}`),
|
|
147
|
-
'---',
|
|
148
|
-
'',
|
|
149
|
-
`# ${rule.title.replace(/\breference$/, 'standards')}`,
|
|
150
|
-
'',
|
|
151
|
-
'## Authority',
|
|
152
|
-
'',
|
|
153
|
-
...[pointer, ...rule.bullets].map((bullet) => `- ${bullet}`),
|
|
154
|
-
'',
|
|
155
|
-
].join('\n')
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
function lowerFirst(text: string): string {
|
|
159
|
-
return text.charAt(0).toLowerCase() + text.slice(1)
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
/** Plain when YAML would read it back unchanged, single-quoted otherwise. */
|
|
163
|
-
function yamlScalar(text: string): string {
|
|
164
|
-
const isPlain =
|
|
165
|
-
text !== '' &&
|
|
166
|
-
!/^[-?:,[\]{}#&*!|>'"%@`\s]/.test(text) &&
|
|
167
|
-
!/: |\s#|:$|\s$/.test(text)
|
|
168
|
-
return isPlain ? text : yamlQuoted(text)
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
/**
|
|
172
|
-
* Quoted the way Prettier's `singleQuote` leaves YAML, so the drift check
|
|
173
|
-
* never fights the formatter: single quotes unless the text holds one and
|
|
174
|
-
* double quotes would need no escape.
|
|
175
|
-
*/
|
|
176
|
-
function yamlQuoted(text: string): string {
|
|
177
|
-
if (text.includes("'") && !/["\\]/.test(text)) return `"${text}"`
|
|
178
|
-
return `'${text.replaceAll("'", "''")}'`
|
|
179
|
-
}
|
package/src/records/migrate.ts
DELETED
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
import { parseFrontmatter, readField } from '@/indexes/frontmatter'
|
|
2
|
-
import {
|
|
3
|
-
CATEGORY_BY_TYPE,
|
|
4
|
-
type FindingRemedy,
|
|
5
|
-
MEMORY_NAME,
|
|
6
|
-
memoryType,
|
|
7
|
-
} from '@/records/validate'
|
|
8
|
-
|
|
9
|
-
export const MIGRATE_REFUSALS = ['field-unrecoverable'] as const
|
|
10
|
-
|
|
11
|
-
export type MigrateRefusal = (typeof MIGRATE_REFUSALS)[number]
|
|
12
|
-
|
|
13
|
-
export interface MigrateRepair {
|
|
14
|
-
readonly ok: true
|
|
15
|
-
readonly text: string
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export interface MigrateRefused {
|
|
19
|
-
readonly ok: false
|
|
20
|
-
readonly reason: MigrateRefusal
|
|
21
|
-
readonly message: string
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export type MigrateOutcome = MigrateRepair | MigrateRefused
|
|
25
|
-
|
|
26
|
-
function refuse(message: string): MigrateRefused {
|
|
27
|
-
return { ok: false, reason: 'field-unrecoverable', message }
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Repairs the one recoverable shape of `frontmatter-incomplete`: a memory
|
|
32
|
-
* record missing `category` alone. The value sits in the filename's type
|
|
33
|
-
* prefix already, which is the same fact `checkMemory` derives it from, so a
|
|
34
|
-
* repair here writes back what the record already states rather than a value
|
|
35
|
-
* a transform invented. It re-reads the file rather than trusting a value
|
|
36
|
-
* carried on the `Finding`, so a transform and the check it repairs cannot
|
|
37
|
-
* drift apart.
|
|
38
|
-
*/
|
|
39
|
-
function categoryFromName(name: string, text: string): MigrateOutcome {
|
|
40
|
-
const frontmatter = parseFrontmatter(text)
|
|
41
|
-
if (!frontmatter) {
|
|
42
|
-
return refuse(`${name} carries no frontmatter block to add category to.`)
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
if (readField(frontmatter, 'category')) {
|
|
46
|
-
return refuse(`${name} already carries a category.`)
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
const match = MEMORY_NAME.exec(name)
|
|
50
|
-
const type = match ? memoryType(match[1]) : undefined
|
|
51
|
-
if (!type) {
|
|
52
|
-
return refuse(
|
|
53
|
-
`${name} is not named <type>-<slug>.md, so category has no type to derive from.`,
|
|
54
|
-
)
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
const rewritten = frontmatter.raw.replace(
|
|
58
|
-
/\n---$/,
|
|
59
|
-
`\ncategory: ${CATEGORY_BY_TYPE[type]}\n---`,
|
|
60
|
-
)
|
|
61
|
-
|
|
62
|
-
return { ok: true, text: rewritten + text.slice(frontmatter.raw.length) }
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
const TRANSFORMS: Readonly<
|
|
66
|
-
Record<FindingRemedy, (name: string, text: string) => MigrateOutcome>
|
|
67
|
-
> = {
|
|
68
|
-
'category-from-name': categoryFromName,
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
/** Applies the transform a finding's `remedy` names against its own text. */
|
|
72
|
-
export function migrateRecord(
|
|
73
|
-
remedy: FindingRemedy,
|
|
74
|
-
name: string,
|
|
75
|
-
text: string,
|
|
76
|
-
): MigrateOutcome {
|
|
77
|
-
return TRANSFORMS[remedy](name, text)
|
|
78
|
-
}
|