@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,311 @@
|
|
|
1
|
+
import { existsSync } from 'node:fs'
|
|
2
|
+
import { readFile, writeFile } from 'node:fs/promises'
|
|
3
|
+
import { basename, join, relative } from 'node:path'
|
|
4
|
+
import {
|
|
5
|
+
fenceMask,
|
|
6
|
+
listTaskStems,
|
|
7
|
+
OUTCOME_PATTERN,
|
|
8
|
+
readPlanTarget,
|
|
9
|
+
tasksDir,
|
|
10
|
+
} from '@/tasks/archive'
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Lines a task carries above its outcomes naming where the work came from. The
|
|
14
|
+
* `Pull request:` line joins them, so the last one present is the anchor.
|
|
15
|
+
*/
|
|
16
|
+
const ORIGIN_PREFIXES = ['Plan:', 'Groundwork:', 'Intake:', 'Issue:'] as const
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* `bad-input` is separated from the board-state reasons on purpose. `git-pr`
|
|
20
|
+
* swallows `no-board`, `no-match`, and `ambiguous`, because each is a case where
|
|
21
|
+
* a guessed write would archive the wrong task. A caller that passed a
|
|
22
|
+
* malformed argument has a defect nobody would otherwise hear about, so it
|
|
23
|
+
* reports rather than joining the swallowed set.
|
|
24
|
+
*/
|
|
25
|
+
export const RECORD_REFUSALS = [
|
|
26
|
+
'no-board',
|
|
27
|
+
'no-match',
|
|
28
|
+
'ambiguous',
|
|
29
|
+
'no-outcomes',
|
|
30
|
+
'out-of-range',
|
|
31
|
+
'bad-input',
|
|
32
|
+
] as const
|
|
33
|
+
|
|
34
|
+
export type RecordRefusal = (typeof RECORD_REFUSALS)[number]
|
|
35
|
+
|
|
36
|
+
export interface RecordRefused {
|
|
37
|
+
readonly ok: false
|
|
38
|
+
readonly reason: RecordRefusal
|
|
39
|
+
readonly message: string
|
|
40
|
+
readonly detail: readonly string[]
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export type RecordSelector =
|
|
44
|
+
| { readonly kind: 'stem'; readonly stem: string }
|
|
45
|
+
| { readonly kind: 'plan'; readonly plan: string }
|
|
46
|
+
|
|
47
|
+
export type LineAction = 'added' | 'corrected' | 'unchanged'
|
|
48
|
+
|
|
49
|
+
export interface PullRequestRecorded {
|
|
50
|
+
readonly ok: true
|
|
51
|
+
readonly stem: string
|
|
52
|
+
readonly path: string
|
|
53
|
+
readonly number: number
|
|
54
|
+
readonly action: LineAction
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export type PullRequestOutcome = PullRequestRecorded | RecordRefused
|
|
58
|
+
|
|
59
|
+
export interface OutcomesClosed {
|
|
60
|
+
readonly ok: true
|
|
61
|
+
readonly stem: string
|
|
62
|
+
readonly path: string
|
|
63
|
+
readonly closed: readonly string[]
|
|
64
|
+
readonly alreadyClosed: readonly string[]
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export type CloseOutcome = OutcomesClosed | RecordRefused
|
|
68
|
+
|
|
69
|
+
function refuse(
|
|
70
|
+
reason: RecordRefusal,
|
|
71
|
+
message: string,
|
|
72
|
+
detail: readonly string[] = [],
|
|
73
|
+
): RecordRefused {
|
|
74
|
+
return { ok: false, reason, message, detail }
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Reduces a plan reference to the token both spellings share. A task's `Plan:`
|
|
79
|
+
* line carries a path, a caller carries the branch slug, and the two differ by
|
|
80
|
+
* the folder, the extension, and the `feature-` prefix the filename adds.
|
|
81
|
+
*/
|
|
82
|
+
function planKey(reference: string): string {
|
|
83
|
+
const stem = basename(reference).replace(/\.md$/, '')
|
|
84
|
+
return stem.startsWith('feature-') ? stem.slice('feature-'.length) : stem
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Places the `Pull request:` line under the origin lines the task already
|
|
89
|
+
* carries, and corrects the number in place when the line exists. A task with
|
|
90
|
+
* no origin line takes it under the H1, which is the only other anchor the
|
|
91
|
+
* board format guarantees.
|
|
92
|
+
*/
|
|
93
|
+
export function writePullRequestLine(
|
|
94
|
+
text: string,
|
|
95
|
+
number: number,
|
|
96
|
+
): { readonly text: string; readonly action: LineAction } {
|
|
97
|
+
const line = `Pull request: #${number}`
|
|
98
|
+
const lines = text.split('\n')
|
|
99
|
+
const existing = lines.findIndex((entry) => entry.startsWith('Pull request:'))
|
|
100
|
+
|
|
101
|
+
if (existing !== -1) {
|
|
102
|
+
if (lines[existing] === line) return { text, action: 'unchanged' }
|
|
103
|
+
lines[existing] = line
|
|
104
|
+
return { text: lines.join('\n'), action: 'corrected' }
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const origin = lastOriginLine(lines)
|
|
108
|
+
if (origin !== undefined) {
|
|
109
|
+
lines.splice(origin + 1, 0, line)
|
|
110
|
+
return { text: lines.join('\n'), action: 'added' }
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const heading = lines.findIndex((entry) => entry.startsWith('# '))
|
|
114
|
+
if (heading === -1) return { text: `${line}\n${text}`, action: 'added' }
|
|
115
|
+
|
|
116
|
+
lines.splice(heading + 1, 0, '', line)
|
|
117
|
+
return { text: lines.join('\n'), action: 'added' }
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function lastOriginLine(lines: readonly string[]): number | undefined {
|
|
121
|
+
let found: number | undefined
|
|
122
|
+
|
|
123
|
+
for (const [index, line] of lines.entries()) {
|
|
124
|
+
if (ORIGIN_PREFIXES.some((prefix) => line.startsWith(prefix))) found = index
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
return found
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Marks outcomes closed by their 1-based position in the task's outcome list,
|
|
132
|
+
* which is the order the board format writes them. A caller reads the file
|
|
133
|
+
* before deciding, so a position is what it already holds, while a text match
|
|
134
|
+
* would need the wording handed back exactly.
|
|
135
|
+
*/
|
|
136
|
+
export function closeOutcomeLines(
|
|
137
|
+
text: string,
|
|
138
|
+
positions: readonly number[],
|
|
139
|
+
): {
|
|
140
|
+
readonly text: string
|
|
141
|
+
readonly closed: readonly string[]
|
|
142
|
+
readonly alreadyClosed: readonly string[]
|
|
143
|
+
readonly total: number
|
|
144
|
+
} {
|
|
145
|
+
const wanted = new Set(positions)
|
|
146
|
+
const closed: string[] = []
|
|
147
|
+
const alreadyClosed: string[] = []
|
|
148
|
+
const lines = text.split('\n')
|
|
149
|
+
const fenced = fenceMask(lines)
|
|
150
|
+
let seen = 0
|
|
151
|
+
|
|
152
|
+
const rewritten = lines.map((line, index) => {
|
|
153
|
+
if (fenced[index]) return line
|
|
154
|
+
|
|
155
|
+
const match = OUTCOME_PATTERN.exec(line)
|
|
156
|
+
if (!match) return line
|
|
157
|
+
|
|
158
|
+
seen += 1
|
|
159
|
+
if (!wanted.has(seen)) return line
|
|
160
|
+
|
|
161
|
+
const [, box, body] = match
|
|
162
|
+
if (box !== ' ') {
|
|
163
|
+
alreadyClosed.push(body.trim())
|
|
164
|
+
return line
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
closed.push(body.trim())
|
|
168
|
+
return body ? `- [x] ${body}` : '- [x]'
|
|
169
|
+
})
|
|
170
|
+
|
|
171
|
+
return { text: rewritten.join('\n'), closed, alreadyClosed, total: seen }
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
async function matchByPlan(
|
|
175
|
+
dir: string,
|
|
176
|
+
stems: readonly string[],
|
|
177
|
+
plan: string,
|
|
178
|
+
): Promise<string[]> {
|
|
179
|
+
const key = planKey(plan)
|
|
180
|
+
|
|
181
|
+
const read = await Promise.all(
|
|
182
|
+
stems.map(async (stem) => ({
|
|
183
|
+
stem,
|
|
184
|
+
target: readPlanTarget(await readFile(join(dir, `${stem}.md`), 'utf8')),
|
|
185
|
+
})),
|
|
186
|
+
)
|
|
187
|
+
|
|
188
|
+
return read
|
|
189
|
+
.filter(
|
|
190
|
+
(entry) => entry.target !== undefined && planKey(entry.target) === key,
|
|
191
|
+
)
|
|
192
|
+
.map(({ stem }) => stem)
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
async function resolveStem(
|
|
196
|
+
dir: string,
|
|
197
|
+
selector: RecordSelector,
|
|
198
|
+
): Promise<string | RecordRefused> {
|
|
199
|
+
const stems = await listTaskStems(dir)
|
|
200
|
+
|
|
201
|
+
if (selector.kind === 'stem') {
|
|
202
|
+
if (!stems.includes(selector.stem)) {
|
|
203
|
+
return refuse(
|
|
204
|
+
'no-match',
|
|
205
|
+
`No task named ${selector.stem} on the board.`,
|
|
206
|
+
stems,
|
|
207
|
+
)
|
|
208
|
+
}
|
|
209
|
+
return selector.stem
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
const matched = await matchByPlan(dir, stems, selector.plan)
|
|
213
|
+
|
|
214
|
+
if (matched.length === 0) {
|
|
215
|
+
return refuse('no-match', `No task names plan ${selector.plan}.`)
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
if (matched.length > 1) {
|
|
219
|
+
return refuse(
|
|
220
|
+
'ambiguous',
|
|
221
|
+
`${matched.length} tasks name plan ${selector.plan}. One task, one plan.`,
|
|
222
|
+
matched,
|
|
223
|
+
)
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
return matched[0]
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
async function openTask(
|
|
230
|
+
root: string,
|
|
231
|
+
selector: RecordSelector,
|
|
232
|
+
): Promise<{ readonly stem: string; readonly path: string } | RecordRefused> {
|
|
233
|
+
const dir = tasksDir(root)
|
|
234
|
+
|
|
235
|
+
if (!existsSync(dir)) {
|
|
236
|
+
return refuse('no-board', `No task board at ${relative(root, dir)}.`)
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
const resolved = await resolveStem(dir, selector)
|
|
240
|
+
if (typeof resolved !== 'string') return resolved
|
|
241
|
+
|
|
242
|
+
return { stem: resolved, path: join(dir, `${resolved}.md`) }
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Records a pull request number on the task the branch closes. `git-pr` runs
|
|
247
|
+
* this from a linked worktree, where an in-place edit through the file-editing
|
|
248
|
+
* tools is refused and a shell stream editor is banned, so the write has to
|
|
249
|
+
* resolve the board root in-process.
|
|
250
|
+
*/
|
|
251
|
+
export async function recordPullRequest(
|
|
252
|
+
root: string,
|
|
253
|
+
selector: RecordSelector,
|
|
254
|
+
number: number,
|
|
255
|
+
): Promise<PullRequestOutcome> {
|
|
256
|
+
const opened = await openTask(root, selector)
|
|
257
|
+
if ('ok' in opened) return opened
|
|
258
|
+
|
|
259
|
+
const { stem, path } = opened
|
|
260
|
+
const { text, action } = writePullRequestLine(
|
|
261
|
+
await readFile(path, 'utf8'),
|
|
262
|
+
number,
|
|
263
|
+
)
|
|
264
|
+
|
|
265
|
+
if (action !== 'unchanged') await writeFile(path, text)
|
|
266
|
+
|
|
267
|
+
return { ok: true, stem, path, number, action }
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* Marks the named outcomes `[x]` in place. `claude-docs` runs this against a
|
|
272
|
+
* board it can read and cannot edit from a linked worktree, and the positions
|
|
273
|
+
* come from the read it already made.
|
|
274
|
+
*/
|
|
275
|
+
export async function closeOutcomes(
|
|
276
|
+
root: string,
|
|
277
|
+
selector: RecordSelector,
|
|
278
|
+
positions: readonly number[],
|
|
279
|
+
): Promise<CloseOutcome> {
|
|
280
|
+
const opened = await openTask(root, selector)
|
|
281
|
+
if ('ok' in opened) return opened
|
|
282
|
+
|
|
283
|
+
const { stem, path } = opened
|
|
284
|
+
const result = closeOutcomeLines(await readFile(path, 'utf8'), positions)
|
|
285
|
+
|
|
286
|
+
if (result.total === 0) {
|
|
287
|
+
return refuse('no-outcomes', `${stem} carries no outcomes to close.`)
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
const beyond = positions.filter(
|
|
291
|
+
(position) => position < 1 || position > result.total,
|
|
292
|
+
)
|
|
293
|
+
|
|
294
|
+
if (beyond.length > 0) {
|
|
295
|
+
return refuse(
|
|
296
|
+
'out-of-range',
|
|
297
|
+
`${stem} carries ${result.total} outcome(s), so ${beyond.join(', ')} names nothing.`,
|
|
298
|
+
beyond.map(String),
|
|
299
|
+
)
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
if (result.closed.length > 0) await writeFile(path, result.text)
|
|
303
|
+
|
|
304
|
+
return {
|
|
305
|
+
ok: true,
|
|
306
|
+
stem,
|
|
307
|
+
path,
|
|
308
|
+
closed: result.closed,
|
|
309
|
+
alreadyClosed: result.alreadyClosed,
|
|
310
|
+
}
|
|
311
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { execa } from 'execa'
|
|
2
|
+
import { gitEnv } from '@/git-env'
|
|
3
|
+
|
|
4
|
+
const GIT_TIMEOUT_MS = 10_000
|
|
5
|
+
|
|
6
|
+
/** Preferred first. A clone with no remote still answers off its local trunk. */
|
|
7
|
+
const TRUNK_REFS = ['origin/main', 'main'] as const
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Reports whether a pull request's work reached the trunk. `undefined` means
|
|
11
|
+
* the trunk could not be read, which is a different answer from `false` and has
|
|
12
|
+
* to stay one: a check that degraded to "not landed" on an unreachable trunk
|
|
13
|
+
* would report a board silently rather than say what it failed to test.
|
|
14
|
+
*/
|
|
15
|
+
export type TrunkReader = (pullRequest: number) => Promise<boolean | undefined>
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Matches the two subjects a landed pull request leaves on the trunk: the
|
|
19
|
+
* `(#NNN)` suffix a squash merge writes, and the subject GitHub writes for a
|
|
20
|
+
* merge commit. Both carry the number in a form no other commit spells, so a
|
|
21
|
+
* pull request numbered 12 cannot match one numbered 123.
|
|
22
|
+
*/
|
|
23
|
+
function grepArgs(pullRequest: number): string[] {
|
|
24
|
+
return [
|
|
25
|
+
'--extended-regexp',
|
|
26
|
+
'--grep',
|
|
27
|
+
`\\(#${pullRequest}\\)`,
|
|
28
|
+
'--grep',
|
|
29
|
+
`Merge pull request #${pullRequest} from`,
|
|
30
|
+
]
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Reads the trunk as this clone already holds it and never fetches. A validate
|
|
35
|
+
* run happens several times a sweep and a fetch per run is a cost the check
|
|
36
|
+
* does not carry today, so a clone behind the remote reports the row untested
|
|
37
|
+
* or leaves it parked rather than claiming work landed.
|
|
38
|
+
*/
|
|
39
|
+
export function gitTrunkReader(root: string): TrunkReader {
|
|
40
|
+
const answered = new Map<number, boolean | undefined>()
|
|
41
|
+
|
|
42
|
+
return async (pullRequest) => {
|
|
43
|
+
if (answered.has(pullRequest)) return answered.get(pullRequest)
|
|
44
|
+
|
|
45
|
+
const landed = await readTrunk(root, pullRequest)
|
|
46
|
+
answered.set(pullRequest, landed)
|
|
47
|
+
return landed
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
async function readTrunk(
|
|
52
|
+
root: string,
|
|
53
|
+
pullRequest: number,
|
|
54
|
+
): Promise<boolean | undefined> {
|
|
55
|
+
for (const ref of TRUNK_REFS) {
|
|
56
|
+
const result = await execa(
|
|
57
|
+
'git',
|
|
58
|
+
[
|
|
59
|
+
'-C',
|
|
60
|
+
root,
|
|
61
|
+
'log',
|
|
62
|
+
ref,
|
|
63
|
+
'-n',
|
|
64
|
+
'1',
|
|
65
|
+
'--format=%H',
|
|
66
|
+
...grepArgs(pullRequest),
|
|
67
|
+
// The ref is a revision, and a repository tracking a path under the
|
|
68
|
+
// same name would otherwise fail the whole read as ambiguous.
|
|
69
|
+
'--',
|
|
70
|
+
],
|
|
71
|
+
// `post-merge` drives the task verbs, and a hook exports the repository
|
|
72
|
+
// variables git reads ahead of `-C`, so the ambient environment would
|
|
73
|
+
// answer for whatever repository fired the hook.
|
|
74
|
+
{
|
|
75
|
+
reject: false,
|
|
76
|
+
timeout: GIT_TIMEOUT_MS,
|
|
77
|
+
env: gitEnv(),
|
|
78
|
+
extendEnv: false,
|
|
79
|
+
},
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
// A missing ref exits non-zero, which is the next ref's turn rather than an
|
|
83
|
+
// answer. An exit of zero with no commit is the ref saying the work is not
|
|
84
|
+
// on it, which is an answer and stops the walk.
|
|
85
|
+
if (result.exitCode === 0) return result.stdout.trim().length > 0
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return undefined
|
|
89
|
+
}
|