@erclx/canon 5.31.0 → 5.32.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/backlog-triage/SKILL.md +1 -1
- package/claude/skills/canon-cli/REQUIREMENT.md +4 -6
- package/claude/skills/canon-cli/SKILL.md +2 -2
- package/claude/skills/canon-feedback/REQUIREMENT.md +1 -1
- package/claude/skills/canon-feedback/SKILL.md +10 -13
- package/claude/skills/canon-feedback-triage/REQUIREMENT.md +13 -14
- package/claude/skills/canon-feedback-triage/SKILL.md +49 -30
- package/claude/skills/canvas/REQUIREMENT.md +3 -4
- package/claude/skills/canvas/SKILL.md +5 -5
- package/{standards → claude/skills/canvas/references}/canvas.md +12 -1
- package/claude/skills/ci-workflow/REQUIREMENT.md +0 -1
- package/claude/skills/context-fold/REQUIREMENT.md +8 -20
- package/claude/skills/context-fold/SKILL.md +20 -44
- package/claude/skills/context-fold/references/classify.md +7 -8
- package/claude/skills/context-fold/references/completion-report.md +2 -6
- package/claude/skills/context-fold/references/context-refresh.md +5 -15
- package/claude/skills/context-fold/references/promoted-pages.md +3 -3
- package/claude/skills/context-fold/references/receipt-sweep.md +6 -17
- package/claude/skills/context-fold/references/unusable-baseline.md +4 -6
- package/claude/skills/create-rule/REQUIREMENT.md +0 -1
- package/claude/skills/create-skill/REQUIREMENT.md +6 -4
- package/claude/skills/create-skill/SKILL.md +8 -7
- package/{standards → claude/skills/create-skill/references}/skill-paths.md +1 -0
- 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 +0 -2
- package/claude/skills/design-taste/SKILL.md +1 -3
- package/claude/skills/design-taste/references/vocabulary.md +1 -1
- package/claude/skills/docs-sync/REQUIREMENT.md +3 -3
- 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 +4 -4
- package/claude/skills/draft-figure/references/architecture-set.md +4 -4
- package/claude/skills/draft-figure/references/hand-drawn.md +1 -1
- 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 +1 -1
- package/claude/skills/draft-identity/SKILL.md +9 -7
- package/claude/skills/draft-ready/REQUIREMENT.md +1 -1
- package/claude/skills/draft-ready/SKILL.md +6 -6
- 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-issue/references/issue.md +3 -3
- package/claude/skills/git-ship/REQUIREMENT.md +0 -2
- package/claude/skills/git-ship/SKILL.md +16 -24
- 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 +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 +1 -1
- package/claude/skills/review-pr/SKILL.md +5 -7
- package/claude/skills/review-ui/REQUIREMENT.md +0 -1
- package/claude/skills/review-ui/SKILL.md +1 -1
- package/claude/skills/role-orchestrator/REQUIREMENT.md +0 -3
- package/claude/skills/role-orchestrator/SKILL.md +8 -8
- package/claude/skills/role-orchestrator/references/orchestrator-dispatch.md +3 -3
- package/claude/skills/role-orchestrator/references/orchestrator-handoff.md +7 -10
- package/claude/skills/role-orchestrator/references/orchestrator-parked.md +2 -2
- package/claude/skills/role-orchestrator/references/orchestrator-refill.md +0 -3
- package/claude/skills/role-orchestrator/references/orchestrator-resume.md +1 -1
- package/claude/skills/role-planner/SKILL.md +2 -2
- package/claude/skills/role-reviewer/SKILL.md +1 -1
- package/claude/skills/role-worker/SKILL.md +2 -2
- 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 +8 -16
- 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 +4 -6
- package/claude/skills/session-resume/SKILL.md +3 -9
- package/claude/skills/session-worktree/SKILL.md +1 -1
- 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 +1 -1
- package/claude/skills/task-board/SKILL.md +4 -4
- package/claude/skills/task-board/references/archive.md +1 -1
- 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 +13 -8
- package/claude/skills/teach-workspace/SKILL.md +1 -1
- package/claude/skills/teach-workspace/references/revisit.md +1 -1
- package/{standards → claude/skills/teach-workspace/references}/teach.md +17 -5
- package/claude/skills/ux-audit/REQUIREMENT.md +2 -2
- package/claude/skills/ux-audit/SKILL.md +2 -3
- 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 +1 -6
- package/docs/agents/context-audit-checks.md +9 -23
- 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 +3 -5
- package/docs/agents/install-and-sync.md +6 -6
- package/docs/agents/intake.md +1 -1
- package/docs/agents/records-stale.md +5 -5
- package/docs/agents/records-validate.md +1 -1
- package/docs/agents/records.md +2 -2
- package/docs/agents/restated.md +1 -1
- package/docs/agents/rule-citations.md +1 -1
- 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 +1 -1
- package/docs/agents/teach.md +1 -1
- package/docs/agents/upstream.md +26 -2
- package/docs/target/migrations.md +24 -0
- package/docs/target/projects.md +5 -7
- package/docs/target/scenarios.md +2 -2
- package/docs/target/sync.md +3 -3
- package/docs/workflow/ai-workflow.md +7 -38
- package/docs/workflow/index.md +1 -1
- package/docs/workflow/operating-model.md +8 -8
- package/docs/workflow/parallel-features.md +7 -7
- package/docs/workflow/skill-map-on-request.md +12 -15
- package/docs/workflow/skill-map.md +20 -32
- package/docs/workflow/visual-design-workflow.md +11 -14
- package/governance/renames.toml +0 -19
- package/governance/rules/canon/605-worktrees.md +1 -1
- package/governance/rules/{standards → canon}/plan.md +4 -5
- package/governance/rules/canon/tasks.md +18 -0
- package/governance/stacks/base.toml +1 -1
- package/package.json +1 -1
- package/scripts/core/install-check.sh +1 -1
- package/scripts/core/regen-web-previews.ts +1 -1
- package/src/audits/catalog.ts +5 -97
- package/src/claude/cases/authoring.ts +0 -18
- package/src/claude/cases/misc.ts +0 -13
- package/src/claude/cases/setup.ts +3 -20
- package/src/claude/cases/workflow.ts +0 -33
- package/src/claude/seeds.ts +1 -7
- package/src/claude/skills-audit.ts +1 -1
- package/src/cli/help.ts +1 -4
- package/src/cli.ts +0 -4
- package/src/commands/claude.ts +8 -14
- package/src/commands/context.ts +18 -280
- package/src/commands/feedback.ts +22 -91
- package/src/commands/records.ts +5 -5
- package/src/commands/sync.ts +5 -3
- package/src/commands/upstream.ts +135 -0
- package/src/context/audit.ts +5 -14
- 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 +7 -12
- package/src/context/gate.ts +11 -91
- package/src/context/requirements.ts +13 -4
- package/src/counts/scan.ts +3 -3
- package/src/design/components.ts +2 -2
- package/src/feedback/body.ts +0 -12
- package/src/gate/measures.ts +6 -57
- package/src/gov/citations.ts +9 -3
- package/src/gov/restated.ts +3 -3
- package/src/markdown/structure.ts +2 -2
- package/src/migrate/record-layout.ts +3 -3
- package/src/records/ordinal.ts +1 -1
- package/src/records/prune.ts +2 -1
- package/src/records/stale-canonical.ts +2 -2
- package/src/roots/record.ts +1 -1
- package/src/sandbox/scenario.ts +115 -11
- package/src/shipped/references.ts +3 -3
- package/src/standards/read.ts +31 -0
- package/src/sync/seeds-report.ts +1 -1
- package/src/tasks/reach.ts +2 -2
- package/src/tasks/validate.ts +1 -1
- 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/context.md +3 -5
- package/standards/design.md +2 -3
- package/standards/index.md +0 -22
- package/standards/publish.md +1 -1
- package/standards/skill.md +1 -1
- package/tooling/base/reference.md +1 -1
- package/tooling/claude/reference.md +6 -20
- package/tooling/claude/seeds/.claude/hooks/records-index.sh +8 -20
- package/tooling/claude/seeds/.claude/hooks/standards-audit.sh +3 -3
- 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/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/groundwork.md +0 -13
- package/governance/rules/standards/intake.md +0 -12
- package/governance/rules/standards/memory.md +0 -12
- package/governance/rules/standards/ready.md +0 -13
- package/governance/rules/standards/requirements.md +0 -12
- package/governance/rules/standards/session.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/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/repo/metadata.ts +0 -206
- 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/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,17 +1,26 @@
|
|
|
1
1
|
import { readFile } from 'node:fs/promises'
|
|
2
2
|
import { join, relative } from 'node:path'
|
|
3
|
-
import { wordCount } from '@/context/architecture'
|
|
4
3
|
import { bodyLines } from '@/markdown/scan'
|
|
5
4
|
import { surfaceDir } from '@/roots/surface'
|
|
6
5
|
|
|
7
6
|
/**
|
|
8
7
|
* The record this measures, relative to `root`, resolved at either surface
|
|
9
|
-
* root
|
|
8
|
+
* root, since a project that has moved holds it under either.
|
|
10
9
|
*/
|
|
11
10
|
export function requirementsRel(root: string): string {
|
|
12
11
|
return relative(root, surfaceDir(root, 'REQUIREMENTS.md'))
|
|
13
12
|
}
|
|
14
13
|
|
|
14
|
+
/**
|
|
15
|
+
* Counts whitespace-delimited tokens, the unit the record's word cap is stated
|
|
16
|
+
* in. A code span counts as the tokens it holds, so a line citing a long path
|
|
17
|
+
* pays for it the way a reader does. A caller gating on the count hands in
|
|
18
|
+
* prose with fenced lines already dropped.
|
|
19
|
+
*/
|
|
20
|
+
export function wordCount(text: string): number {
|
|
21
|
+
return text.match(/\S+/g)?.length ?? 0
|
|
22
|
+
}
|
|
23
|
+
|
|
15
24
|
export interface RequirementsReport {
|
|
16
25
|
readonly rel: string
|
|
17
26
|
/** The whole record's word count, frontmatter left out. */
|
|
@@ -43,8 +52,8 @@ function isMissing(error: unknown): boolean {
|
|
|
43
52
|
/**
|
|
44
53
|
* Measures the record, or reports nothing when the project carries none.
|
|
45
54
|
*
|
|
46
|
-
* Absent rather than zeroed,
|
|
47
|
-
* record present and unreadable propagates
|
|
55
|
+
* Absent rather than zeroed, so a project with no record is never told it holds an
|
|
56
|
+
* empty one, and a record present and unreadable propagates.
|
|
48
57
|
*/
|
|
49
58
|
export async function measureRequirements(
|
|
50
59
|
root: string,
|
package/src/counts/scan.ts
CHANGED
|
@@ -35,8 +35,8 @@ export type CountsReport =
|
|
|
35
35
|
|
|
36
36
|
/**
|
|
37
37
|
* A calendar date, which reads a sentence as a historical record rather than
|
|
38
|
-
* a live claim about the tree.
|
|
39
|
-
*
|
|
38
|
+
* a live claim about the tree. The context entries
|
|
39
|
+
* carry a figure this way deliberately, and every one of them stays
|
|
40
40
|
* correct forever, so a sentence carrying one is read past rather than
|
|
41
41
|
* matched.
|
|
42
42
|
*/
|
|
@@ -142,7 +142,7 @@ const QUANTIFIERS = ['all']
|
|
|
142
142
|
* match at all. No syntactic rule tells a qualifier that narrows a catalog
|
|
143
143
|
* from one that only restates it, and the sentence was true when written, so
|
|
144
144
|
* the fix was not a narrower matcher: the clause was dated as a past state,
|
|
145
|
-
* the way
|
|
145
|
+
* the way a context entry dates its own figures, which is the class
|
|
146
146
|
* the date exclusion below already reads past.
|
|
147
147
|
*/
|
|
148
148
|
const ARTICLES = ['the', 'a', 'an']
|
package/src/design/components.ts
CHANGED
|
@@ -250,8 +250,8 @@ const TEACH_CHROME: Component = {
|
|
|
250
250
|
'navigation shared by every teach page. Recovered from two gitignored',
|
|
251
251
|
'course.css files that predate a regression that dropped this layer from the',
|
|
252
252
|
"generator, and rewritten onto this module's tokens rather than the",
|
|
253
|
-
'incompatible palette they carried. See canon/
|
|
254
|
-
'the shape.',
|
|
253
|
+
'incompatible palette they carried. See canon/context/features/teach/chrome.md',
|
|
254
|
+
'for the shape.',
|
|
255
255
|
].join('\n '),
|
|
256
256
|
reads: [
|
|
257
257
|
'--color-background',
|
package/src/feedback/body.ts
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
const SLUG_FALLBACK = 'general'
|
|
2
|
-
const SLUG_MAX_LENGTH = 40
|
|
3
1
|
const TITLE_MAX_LENGTH = 72
|
|
4
2
|
|
|
5
3
|
/**
|
|
@@ -79,16 +77,6 @@ function surfaceField(body: string): string | undefined {
|
|
|
79
77
|
return readField(body, 'Surface')?.split('\n')[0]?.trim()
|
|
80
78
|
}
|
|
81
79
|
|
|
82
|
-
export function deriveSlug(body: string): string {
|
|
83
|
-
const slug = (surfaceField(body) ?? '')
|
|
84
|
-
.toLowerCase()
|
|
85
|
-
.replace(/[^a-z0-9]+/g, '-')
|
|
86
|
-
.replace(/^-+|-+$/g, '')
|
|
87
|
-
.slice(0, SLUG_MAX_LENGTH)
|
|
88
|
-
.replace(/-+$/g, '')
|
|
89
|
-
return slug || SLUG_FALLBACK
|
|
90
|
-
}
|
|
91
|
-
|
|
92
80
|
/**
|
|
93
81
|
* Each label must exist on the toolkit repository, because `gh issue create`
|
|
94
82
|
* refuses the whole issue on an unknown label rather than dropping it.
|
package/src/gate/measures.ts
CHANGED
|
@@ -7,14 +7,6 @@ import {
|
|
|
7
7
|
type ClientCommand,
|
|
8
8
|
clientCommandCitationsIn,
|
|
9
9
|
} from '@/gate/client-commands'
|
|
10
|
-
import {
|
|
11
|
-
isOverCount,
|
|
12
|
-
isOverLength,
|
|
13
|
-
isOverRisks,
|
|
14
|
-
measureArchitecture,
|
|
15
|
-
missingRevisit,
|
|
16
|
-
overWords,
|
|
17
|
-
} from '@/context/architecture'
|
|
18
10
|
import { isOverWordCap, measureRequirements } from '@/context/requirements'
|
|
19
11
|
import {
|
|
20
12
|
auditSkills,
|
|
@@ -253,62 +245,19 @@ function citedPaths(record: { paths?: unknown } | undefined): string[] {
|
|
|
253
245
|
}
|
|
254
246
|
|
|
255
247
|
/**
|
|
256
|
-
* The
|
|
257
|
-
* architecture record carries five: the line ceiling its allowances derive,
|
|
258
|
-
* the entry cap, the revisit sentence closing each decision, the words a
|
|
259
|
-
* decision may hold, and the bullets its Risks section may hold. The
|
|
260
|
-
* requirements record carries one, its own word count.
|
|
248
|
+
* The requirements record against the word cap it states for itself.
|
|
261
249
|
*
|
|
262
250
|
* Read in-process rather than through `context audit`, whose one gating stage
|
|
263
|
-
* here runs `--citations-only` and never opens
|
|
264
|
-
*
|
|
265
|
-
*
|
|
266
|
-
* passes, since each rule belongs to the record rather than to the toolkit.
|
|
251
|
+
* here runs `--citations-only` and never opens the record. A project carrying
|
|
252
|
+
* no record, or a record stating no cap, passes, since the rule belongs to the
|
|
253
|
+
* record rather than to the toolkit.
|
|
267
254
|
*/
|
|
268
255
|
export const canonicalRecords: Measure = async (ctx) => {
|
|
269
|
-
const
|
|
270
|
-
measureArchitecture(ctx.root),
|
|
271
|
-
measureRequirements(ctx.root),
|
|
272
|
-
])
|
|
256
|
+
const requirements = await measureRequirements(ctx.root)
|
|
273
257
|
|
|
274
258
|
const failures: string[] = []
|
|
275
259
|
const emissions: Emission[] = []
|
|
276
260
|
|
|
277
|
-
if (report === undefined) {
|
|
278
|
-
emissions.push(info('No architecture record to measure'))
|
|
279
|
-
} else {
|
|
280
|
-
const decisions = report.decisions.length
|
|
281
|
-
const lackingRevisit = missingRevisit(report)
|
|
282
|
-
const longDecisions = overWords(report)
|
|
283
|
-
failures.push(
|
|
284
|
-
...[
|
|
285
|
-
isOverCount(report) &&
|
|
286
|
-
`${decisions} decisions against a cap of ${report.entryCap}. Merge two or retire one in ${report.rel}, never compress.`,
|
|
287
|
-
isOverLength(report) &&
|
|
288
|
-
`${report.lines} lines against a ceiling of ${report.ceiling} in ${report.rel}.`,
|
|
289
|
-
lackingRevisit.length > 0 &&
|
|
290
|
-
`No revisit sentence in ${lackingRevisit.map((heading) => `"${heading}"`).join(', ')}. Close each with one opening "Revisit when" in ${report.rel}.`,
|
|
291
|
-
longDecisions.length > 0 &&
|
|
292
|
-
`${longDecisions.map((entry) => `"${entry.heading}" (${entry.words})`).join(', ')} past ${report.wordCap} words a decision in ${report.rel}. Cut the reasoning to the trade, never split one decision across two headings.`,
|
|
293
|
-
isOverRisks(report) &&
|
|
294
|
-
`${report.risksBullets} risk bullets against a cap of ${report.riskCap} in ${report.rel}. Drop what is no longer open.`,
|
|
295
|
-
].filter((failure): failure is string => typeof failure === 'string'),
|
|
296
|
-
)
|
|
297
|
-
|
|
298
|
-
const cap =
|
|
299
|
-
report.entryCap === undefined
|
|
300
|
-
? 'no entry cap stated'
|
|
301
|
-
: `a cap of ${report.entryCap}`
|
|
302
|
-
emissions.push(info(`${decisions} decisions against ${cap}`))
|
|
303
|
-
if (report.riskCap !== undefined && report.risksBullets === undefined) {
|
|
304
|
-
emissions.push(
|
|
305
|
-
info(
|
|
306
|
-
`No Risks section to count against a cap of ${report.riskCap} in ${report.rel}`,
|
|
307
|
-
),
|
|
308
|
-
)
|
|
309
|
-
}
|
|
310
|
-
}
|
|
311
|
-
|
|
312
261
|
if (requirements === undefined) {
|
|
313
262
|
emissions.push(info('No requirements record to measure'))
|
|
314
263
|
} else if (isOverWordCap(requirements)) {
|
|
@@ -415,7 +364,7 @@ export const skillProvenance: Measure = async (ctx) => {
|
|
|
415
364
|
/**
|
|
416
365
|
* Every listed practice skill against the closing sections, and every skill on
|
|
417
366
|
* the wider ledger list against the ledger, both of which
|
|
418
|
-
* `
|
|
367
|
+
* `claude/skills/create-skill/references/skill-practice.md` requires.
|
|
419
368
|
*
|
|
420
369
|
* Read in-process for the reason `skillProvenance` is, so the verb keeps its
|
|
421
370
|
* missing-requirement-only exit. The list names shipped folders alone, so a
|
package/src/gov/citations.ts
CHANGED
|
@@ -6,6 +6,7 @@ import { isMarked } from '@/sweep/exempt-marker'
|
|
|
6
6
|
import { gitEnv } from '@/git/env'
|
|
7
7
|
import { listRuleFiles } from '@/gov/payload'
|
|
8
8
|
import { parseFrontmatter } from '@/indexes/frontmatter'
|
|
9
|
+
import { movedStandardPath } from '@/standards/read'
|
|
9
10
|
import { findBacktickSpans } from '@/markdown/backticks'
|
|
10
11
|
|
|
11
12
|
/**
|
|
@@ -177,8 +178,9 @@ export function classifySpan(span: string): CitationForm | undefined {
|
|
|
177
178
|
*
|
|
178
179
|
* A standard name takes the authoring root alone, matching `standardRoots` in
|
|
179
180
|
* `@/standards/read`, which reads `standards/` at the working root and then the
|
|
180
|
-
* package corpus
|
|
181
|
-
* only where those two roots
|
|
181
|
+
* package corpus, plus the skill reference a retired name moved to. This verb
|
|
182
|
+
* refuses a tree holding no rule corpus, so it runs only where those two roots
|
|
183
|
+
* are one directory. `internal/standards/` is
|
|
182
184
|
* deliberately absent: `canon standards <name>` never reaches it, so admitting it
|
|
183
185
|
* here would pass a citation that refuses for the session opening it, which is a
|
|
184
186
|
* gate failing open.
|
|
@@ -191,7 +193,11 @@ function candidatesFor(
|
|
|
191
193
|
cited: string,
|
|
192
194
|
ruleFile: string,
|
|
193
195
|
): string[] {
|
|
194
|
-
if (form === 'standard')
|
|
196
|
+
if (form === 'standard') {
|
|
197
|
+
const moved = movedStandardPath(cited)
|
|
198
|
+
|
|
199
|
+
return [join('standards', `${cited}.md`), ...(moved ? [moved] : [])]
|
|
200
|
+
}
|
|
195
201
|
if (form === 'sibling') return [join(dirname(ruleFile), cited)]
|
|
196
202
|
return [cited]
|
|
197
203
|
}
|
package/src/gov/restated.ts
CHANGED
|
@@ -36,8 +36,8 @@ const SKILL_ROOTS: readonly string[] = [SHIPPED_SKILLS_REL, PROJECT_SKILLS_REL]
|
|
|
36
36
|
/**
|
|
37
37
|
* Path pairs whose duplication is deliberate and already recorded.
|
|
38
38
|
*
|
|
39
|
-
* The seed is authored from the always-loaded file and
|
|
40
|
-
*
|
|
39
|
+
* The seed is authored from the always-loaded file and a hand merge
|
|
40
|
+
* reconciles the two, so a bullet appearing in both is the design
|
|
41
41
|
* rather than a defect. Excluding by pair rather than by content is what the
|
|
42
42
|
* plan settled on: the duplication is a location fact this repository already
|
|
43
43
|
* records, and a content test would have to rediscover it on every run.
|
|
@@ -611,7 +611,7 @@ function authorityFor(
|
|
|
611
611
|
if (candidate.kind === 'seed') {
|
|
612
612
|
return {
|
|
613
613
|
authority: 'claude-md',
|
|
614
|
-
reason: `${INSTRUCTIONS_REL} is authored first and the seed carries it to a target, so an edit starts there and reaches the seed through
|
|
614
|
+
reason: `${INSTRUCTIONS_REL} is authored first and the seed carries it to a target, so an edit starts there and reaches the seed through a hand merge`,
|
|
615
615
|
}
|
|
616
616
|
}
|
|
617
617
|
|
|
@@ -6,7 +6,7 @@ const HEADING = /^#{1,6}\s/
|
|
|
6
6
|
* A section marker holding its line alone, which is the signpost a document
|
|
7
7
|
* uses where its own template asks for bold rather than a heading.
|
|
8
8
|
*
|
|
9
|
-
* `
|
|
9
|
+
* `claude/skills/plan-feature/references/plan.md` gives `## Summary` a heading and marks the four sections
|
|
10
10
|
* below it this way, so a conforming plan read as one run from its first line
|
|
11
11
|
* to its last and all seven live plans reported past the depth checkpoint, at
|
|
12
12
|
* 106 to 166 rendered lines. A measure firing on a whole corpus says nothing
|
|
@@ -659,7 +659,7 @@ function measureParagraph(block: readonly BodyLine[]): CadenceFinding {
|
|
|
659
659
|
*
|
|
660
660
|
* `compromise` reported 2 percent. It tags a fronted past participle as a
|
|
661
661
|
* finite past-tense verb, so all twelve of those sentences in
|
|
662
|
-
*
|
|
662
|
+
* the repository's architecture record at that commit read as carrying one, eleven opening `Measured at`
|
|
663
663
|
* and one `Overturned by`, which is the exact shape the measure exists to
|
|
664
664
|
* catch. It is not even consistent with itself there: `Measured at` tags a verb
|
|
665
665
|
* and `Measured against` tags an adjective.
|
|
@@ -346,9 +346,9 @@ function entriesOf(dir: string, isDirectory: boolean): string[] {
|
|
|
346
346
|
}
|
|
347
347
|
|
|
348
348
|
/**
|
|
349
|
-
* What `draft-and-pick` Step 6
|
|
350
|
-
*
|
|
351
|
-
*
|
|
349
|
+
* What `draft-and-pick` Step 6 writes into the folder it archives a choice to:
|
|
350
|
+
* a capture per canvas frame, named `arm-<id>`. A design handoff marks a pick
|
|
351
|
+
* folder an earlier skill wrote. A folder carrying neither is evidence.
|
|
352
352
|
*/
|
|
353
353
|
const PICK_FILE = /^(?:arm-[^.]+\..+|design-handoff\.md)$/
|
|
354
354
|
|
package/src/records/ordinal.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { recordDir } from '@/roots/record'
|
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* The two record folders that share one ordinal sequence, per
|
|
7
|
-
* `
|
|
7
|
+
* `claude/skills/plan-intake/references/intake.md` and `claude/skills/plan-groundwork/references/groundwork.md`. A folder opened as
|
|
8
8
|
* either kind blocks the same number for the other, so the two read together
|
|
9
9
|
* rather than each keeping a count of its own.
|
|
10
10
|
*/
|
package/src/records/prune.ts
CHANGED
|
@@ -35,7 +35,8 @@ const LEGACY_MOVES: ReadonlyMap<string, string> = new Map([
|
|
|
35
35
|
* Scratch-root names a different migration moves out of scratch for good,
|
|
36
36
|
* derived from that migration's own table rather than duplicated in a second
|
|
37
37
|
* hand-kept list. `RECORD_LAYOUT_MOVES` names `memory-archive`, the
|
|
38
|
-
* retired-entry archive
|
|
38
|
+
* retired-entry archive of the memory kind, which is never offered for deletion,
|
|
39
|
+
* and `PROMOTED_FOLDERS`
|
|
39
40
|
* names an evidence folder a durable record cites by name. A project that has
|
|
40
41
|
* not run either migration still carries these at the scratch root, where an
|
|
41
42
|
* ordinary slug's own age test would eventually offer them.
|
|
@@ -6,8 +6,8 @@ import { gitEnv } from '@/git/env'
|
|
|
6
6
|
import { readReviewed } from '@/records/stale'
|
|
7
7
|
import { surfaceDir } from '@/roots/surface'
|
|
8
8
|
|
|
9
|
-
/** The
|
|
10
|
-
const CANONICAL_DOCS = ['REQUIREMENTS.md'
|
|
9
|
+
/** The record whose drift is identity rather than a stale path. */
|
|
10
|
+
const CANONICAL_DOCS = ['REQUIREMENTS.md'] as const
|
|
11
11
|
|
|
12
12
|
export interface CanonicalDoc {
|
|
13
13
|
/** Relative to the root, at whichever surface root carries the doc. */
|
package/src/roots/record.ts
CHANGED
|
@@ -56,7 +56,7 @@ const CANON_SCRATCH = 'tmp'
|
|
|
56
56
|
* Everything absent from this list is committed and never lands under the
|
|
57
57
|
* record root, which is the rule the move ran on. `rules`, `skills`, and
|
|
58
58
|
* `hooks` stay under `.claude/` because the vendor reads them there, while
|
|
59
|
-
* `context
|
|
59
|
+
* `context` and the loose documents are tracked surfaces that
|
|
60
60
|
* `surface.ts` resolves under `canon/` instead. A seed and a
|
|
61
61
|
* superseded-layout report each ask this rather than assuming a root.
|
|
62
62
|
*/
|
package/src/sandbox/scenario.ts
CHANGED
|
@@ -8,10 +8,19 @@ import {
|
|
|
8
8
|
readFileSync,
|
|
9
9
|
statSync,
|
|
10
10
|
writeFileSync,
|
|
11
|
+
writeSync,
|
|
11
12
|
} from 'node:fs'
|
|
12
13
|
import { createRequire } from 'node:module'
|
|
13
14
|
import { dirname, join, relative } from 'node:path'
|
|
14
|
-
import {
|
|
15
|
+
import {
|
|
16
|
+
logError,
|
|
17
|
+
logInfo,
|
|
18
|
+
logStep,
|
|
19
|
+
logWarn,
|
|
20
|
+
palette,
|
|
21
|
+
pipeOutput,
|
|
22
|
+
select,
|
|
23
|
+
} from '@/cli/ui'
|
|
15
24
|
|
|
16
25
|
/**
|
|
17
26
|
* The TypeScript form of a sandbox scenario: `sandbox/<category>/<command>.ts`,
|
|
@@ -33,7 +42,7 @@ export const FIXTURE_SUFFIX = '.fixture'
|
|
|
33
42
|
/** A scenario whose only arm carries this name routes none, as a bash file with no picker did. */
|
|
34
43
|
export const DEFAULT_ARM_NAME = 'default'
|
|
35
44
|
|
|
36
|
-
/**
|
|
45
|
+
/** What a bash scenario passed to `select_or_route_scenario` unless it named another. */
|
|
37
46
|
const ROUTE_PROMPT = 'Which scenario?'
|
|
38
47
|
|
|
39
48
|
/** Every scenario that sets the anchor pushes to this one throwaway repository. */
|
|
@@ -50,6 +59,14 @@ export interface ScenarioDefinition {
|
|
|
50
59
|
readonly config?: Readonly<Record<string, string>>
|
|
51
60
|
/** Stages the tree from the anchor fixture and names the throwaway remote. */
|
|
52
61
|
readonly anchor?: boolean
|
|
62
|
+
/**
|
|
63
|
+
* Stages and narrates what the bash form did ahead of `select_or_route_scenario`,
|
|
64
|
+
* so the picker's echo lands after it on the frame. Runs before the arm is
|
|
65
|
+
* routed, which leaves `ctx.arm` undefined.
|
|
66
|
+
*/
|
|
67
|
+
readonly prepare?: ArmSetup
|
|
68
|
+
/** The picker's message, for a bash scenario that passed something other than the default. */
|
|
69
|
+
readonly prompt?: string
|
|
53
70
|
/** In routing order, so the first arm is the one a headless caller gets. */
|
|
54
71
|
readonly arms: Readonly<Record<string, ArmSetup>>
|
|
55
72
|
}
|
|
@@ -144,7 +161,7 @@ export function loadScenario(file: string): ScenarioDefinition {
|
|
|
144
161
|
if (!isRecord(definition))
|
|
145
162
|
throw new Error(`${file} has no default export from scenario()`)
|
|
146
163
|
|
|
147
|
-
const { arms, config, anchor } = definition
|
|
164
|
+
const { arms, config, anchor, prepare, prompt } = definition
|
|
148
165
|
if (!isRecord(arms) || Object.keys(arms).length === 0)
|
|
149
166
|
throw new Error(`${file} declares no arms`)
|
|
150
167
|
for (const [name, setup] of Object.entries(arms))
|
|
@@ -158,6 +175,10 @@ export function loadScenario(file: string): ScenarioDefinition {
|
|
|
158
175
|
throw new Error(`${file} config holds a value that is not a string`)
|
|
159
176
|
if (anchor !== undefined && typeof anchor !== 'boolean')
|
|
160
177
|
throw new Error(`${file} anchor is not a boolean`)
|
|
178
|
+
if (prepare !== undefined && typeof prepare !== 'function')
|
|
179
|
+
throw new Error(`${file} prepare is not a function`)
|
|
180
|
+
if (prompt !== undefined && typeof prompt !== 'string')
|
|
181
|
+
throw new Error(`${file} prompt is not a string`)
|
|
161
182
|
|
|
162
183
|
return definition as unknown as ScenarioDefinition
|
|
163
184
|
}
|
|
@@ -225,6 +246,24 @@ export interface RunOptions {
|
|
|
225
246
|
readonly stderr?: 'inherit' | 'ignore'
|
|
226
247
|
/** Returns a failing status rather than stopping the arm, the `|| true` of the bash form. */
|
|
227
248
|
readonly allowFailure?: boolean
|
|
249
|
+
/** Set for this command alone, the `NAME=value command` prefix of the bash form. */
|
|
250
|
+
readonly env?: Readonly<Record<string, string>>
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
export interface CaptureOptions {
|
|
254
|
+
/** Relative to the tree, the `cd` of a bash subshell. */
|
|
255
|
+
readonly cwd?: string
|
|
256
|
+
/** Fed to the command's stdin, the `<file` or `<<<` of the bash form. */
|
|
257
|
+
readonly input?: string
|
|
258
|
+
readonly env?: Readonly<Record<string, string>>
|
|
259
|
+
/** `inherit` leaves the stream on the terminal, where `pipe` hands it back for a file. */
|
|
260
|
+
readonly stderr?: 'pipe' | 'inherit' | 'ignore'
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
export interface Captured {
|
|
264
|
+
readonly status: number
|
|
265
|
+
readonly stdout: string
|
|
266
|
+
readonly stderr: string
|
|
228
267
|
}
|
|
229
268
|
|
|
230
269
|
export interface StageContext {
|
|
@@ -240,6 +279,8 @@ export interface StageContext {
|
|
|
240
279
|
warn(message: string): void
|
|
241
280
|
/** A bare frame line, the `echo -e "${GREY}│${NC}"` of the bash form. */
|
|
242
281
|
bar(): void
|
|
282
|
+
/** Indents borrowed output inside the frame, the `pipe_output` of the bash form. */
|
|
283
|
+
pipe(text: string): void
|
|
243
284
|
}
|
|
244
285
|
fixtures(category: string, command: string, arm: string, stage: string): void
|
|
245
286
|
git(...args: string[]): void
|
|
@@ -248,6 +289,18 @@ export interface StageContext {
|
|
|
248
289
|
run(command: string, args: readonly string[], options?: RunOptions): number
|
|
249
290
|
/** Runs a command and returns its stdout, stopping the arm on a failure. */
|
|
250
291
|
read(command: string, args: readonly string[], options?: RunOptions): string
|
|
292
|
+
/**
|
|
293
|
+
* Runs a command and returns both streams with its status, never stopping the
|
|
294
|
+
* arm. For the `>file 2>file || status=$?` shape, where the outcome is the
|
|
295
|
+
* record the arm exists to hold.
|
|
296
|
+
*/
|
|
297
|
+
capture(
|
|
298
|
+
command: string,
|
|
299
|
+
args: readonly string[],
|
|
300
|
+
options?: CaptureOptions,
|
|
301
|
+
): Captured
|
|
302
|
+
/** Writes to a stream the way a bare `cat` or `echo` did, in order with the commands around it. */
|
|
303
|
+
print(text: string, stream?: 'stdout' | 'stderr'): void
|
|
251
304
|
write(path: string, content: string): void
|
|
252
305
|
append(path: string, content: string): void
|
|
253
306
|
mkdir(path: string): void
|
|
@@ -291,14 +344,24 @@ export function createStageContext(options: ContextOptions): StageContext {
|
|
|
291
344
|
args: readonly string[],
|
|
292
345
|
stdout: 'inherit' | 'ignore' | 'pipe',
|
|
293
346
|
stderr: 'inherit' | 'ignore' | 'pipe',
|
|
347
|
+
extra: {
|
|
348
|
+
cwd?: string
|
|
349
|
+
input?: string
|
|
350
|
+
env?: Readonly<Record<string, string>>
|
|
351
|
+
} = {},
|
|
294
352
|
) => {
|
|
295
|
-
const stdio: StdioOptions = [
|
|
353
|
+
const stdio: StdioOptions = [
|
|
354
|
+
extra.input === undefined ? 'ignore' : 'pipe',
|
|
355
|
+
stdout,
|
|
356
|
+
stderr,
|
|
357
|
+
]
|
|
296
358
|
|
|
297
359
|
return spawnSync(command, [...args], {
|
|
298
|
-
cwd: dir,
|
|
299
|
-
env,
|
|
360
|
+
cwd: extra.cwd === undefined ? dir : join(dir, extra.cwd),
|
|
361
|
+
env: extra.env === undefined ? env : { ...env, ...extra.env },
|
|
300
362
|
encoding: 'utf8',
|
|
301
363
|
stdio,
|
|
364
|
+
input: extra.input,
|
|
302
365
|
})
|
|
303
366
|
}
|
|
304
367
|
|
|
@@ -312,6 +375,7 @@ export function createStageContext(options: ContextOptions): StageContext {
|
|
|
312
375
|
args,
|
|
313
376
|
runOptions.stdout ?? 'inherit',
|
|
314
377
|
runOptions.stderr ?? 'inherit',
|
|
378
|
+
{ env: runOptions.env },
|
|
315
379
|
)
|
|
316
380
|
const status = result.status ?? 1
|
|
317
381
|
if (status !== 0 && runOptions.allowFailure !== true)
|
|
@@ -325,7 +389,13 @@ export function createStageContext(options: ContextOptions): StageContext {
|
|
|
325
389
|
args: readonly string[],
|
|
326
390
|
runOptions: RunOptions = {},
|
|
327
391
|
): string => {
|
|
328
|
-
const result = spawn(
|
|
392
|
+
const result = spawn(
|
|
393
|
+
command,
|
|
394
|
+
args,
|
|
395
|
+
'pipe',
|
|
396
|
+
runOptions.stderr ?? 'inherit',
|
|
397
|
+
{ env: runOptions.env },
|
|
398
|
+
)
|
|
329
399
|
const status = result.status ?? 1
|
|
330
400
|
if (status !== 0 && runOptions.allowFailure !== true)
|
|
331
401
|
throw new ScenarioStop(status, 'exited')
|
|
@@ -333,6 +403,26 @@ export function createStageContext(options: ContextOptions): StageContext {
|
|
|
333
403
|
return status === 0 ? result.stdout : ''
|
|
334
404
|
}
|
|
335
405
|
|
|
406
|
+
const capture = (
|
|
407
|
+
command: string,
|
|
408
|
+
args: readonly string[],
|
|
409
|
+
captureOptions: CaptureOptions = {},
|
|
410
|
+
): Captured => {
|
|
411
|
+
const result = spawn(
|
|
412
|
+
command,
|
|
413
|
+
args,
|
|
414
|
+
'pipe',
|
|
415
|
+
captureOptions.stderr ?? 'pipe',
|
|
416
|
+
captureOptions,
|
|
417
|
+
)
|
|
418
|
+
|
|
419
|
+
return {
|
|
420
|
+
status: result.status ?? 1,
|
|
421
|
+
stdout: result.stdout ?? '',
|
|
422
|
+
stderr: result.stderr ?? '',
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
|
|
336
426
|
const git = (...args: string[]): void => {
|
|
337
427
|
run('git', args)
|
|
338
428
|
}
|
|
@@ -476,12 +566,20 @@ export function createStageContext(options: ContextOptions): StageContext {
|
|
|
476
566
|
const { GREY, NC } = palette(process.stderr)
|
|
477
567
|
process.stderr.write(`${GREY}│${NC}\n`)
|
|
478
568
|
},
|
|
569
|
+
// `pipe_output` read lines, so an empty body printed nothing at all.
|
|
570
|
+
pipe: (text) => {
|
|
571
|
+
if (text !== '') pipeOutput(text)
|
|
572
|
+
},
|
|
479
573
|
},
|
|
480
574
|
fixtures,
|
|
481
575
|
git,
|
|
482
576
|
commit: (subject) => git('commit', '-m', subject, '--no-verify', '-q'),
|
|
483
577
|
run,
|
|
484
578
|
read,
|
|
579
|
+
capture,
|
|
580
|
+
print: (text, stream = 'stdout') => {
|
|
581
|
+
writeSync(stream === 'stdout' ? 1 : 2, text)
|
|
582
|
+
},
|
|
485
583
|
write: (path, content) => {
|
|
486
584
|
mkdirSync(dirname(inTree(path)), { recursive: true })
|
|
487
585
|
writeFileSync(inTree(path), content)
|
|
@@ -510,11 +608,12 @@ export function createStageContext(options: ContextOptions): StageContext {
|
|
|
510
608
|
async function routeArm(
|
|
511
609
|
names: readonly string[],
|
|
512
610
|
env: NodeJS.ProcessEnv,
|
|
611
|
+
prompt: string,
|
|
513
612
|
): Promise<string> {
|
|
514
613
|
const echo = (name: string): string => {
|
|
515
614
|
const { GREY, NC, WHITE } = palette(process.stderr)
|
|
516
615
|
process.stderr.write(
|
|
517
|
-
`${GREY}│${NC}\n${GREY}◇${NC} ${
|
|
616
|
+
`${GREY}│${NC}\n${GREY}◇${NC} ${prompt} ${WHITE}${name}${NC}\n`,
|
|
518
617
|
)
|
|
519
618
|
|
|
520
619
|
return name
|
|
@@ -533,13 +632,13 @@ async function routeArm(
|
|
|
533
632
|
|
|
534
633
|
if (!process.stdin.isTTY) {
|
|
535
634
|
logError(
|
|
536
|
-
`${
|
|
635
|
+
`${prompt} requires a TTY. Pass an argument or set CANON_NON_INTERACTIVE=1.`,
|
|
537
636
|
)
|
|
538
637
|
throw new ScenarioStop(1, 'exited')
|
|
539
638
|
}
|
|
540
639
|
|
|
541
640
|
return select({
|
|
542
|
-
message:
|
|
641
|
+
message: prompt,
|
|
543
642
|
options: names.map((name) => ({ value: name, label: name })),
|
|
544
643
|
})
|
|
545
644
|
}
|
|
@@ -560,8 +659,13 @@ export async function stageScenarioInProcess(
|
|
|
560
659
|
): Promise<StageOutcome> {
|
|
561
660
|
try {
|
|
562
661
|
const names = armNames(definition)
|
|
662
|
+
await definition.prepare?.(
|
|
663
|
+
createStageContext({ ...options, arm: undefined }),
|
|
664
|
+
)
|
|
563
665
|
const name =
|
|
564
|
-
names.length === 0
|
|
666
|
+
names.length === 0
|
|
667
|
+
? DEFAULT_ARM_NAME
|
|
668
|
+
: await routeArm(names, options.env, definition.prompt ?? ROUTE_PROMPT)
|
|
565
669
|
const setup = Object.hasOwn(definition.arms, name)
|
|
566
670
|
? definition.arms[name]
|
|
567
671
|
: undefined
|
|
@@ -168,8 +168,8 @@ const DOCS_PATH = /(?<![\w./-])docs\/[^\s`)\]]*\.md\b/g
|
|
|
168
168
|
* Reported unless `isStandardsPathReportable` reads the match as a
|
|
169
169
|
* deliberate placeholder rather than a real citation. A body illustrating
|
|
170
170
|
* the shape a project's own `standards/<name>.md` takes writes a bracketed
|
|
171
|
-
* token this pattern also matches, such as `standards/<slug>.md`
|
|
172
|
-
*
|
|
171
|
+
* token this pattern also matches, such as `standards/<slug>.md`
|
|
172
|
+
* in a skill that drafts one, which names no real file. A bare,
|
|
173
173
|
* non-bracketed match now reports whether or not the file exists, unlike
|
|
174
174
|
* `DOCS_PATH`, which still gates on existence: a same-repository citation
|
|
175
175
|
* under this corpus names no target project's own tree the way a `docs/`
|
|
@@ -206,7 +206,7 @@ const PHASE_LABEL = /\bv\d+\.\d+(?!\.\d)\b/g
|
|
|
206
206
|
*
|
|
207
207
|
* Anchored on the trailing `\d{3}-[\w-]+\.md` rather than on the bare
|
|
208
208
|
* `.claude/rules/` prefix, which is what keeps a folder mention carrying no
|
|
209
|
-
* number, such as `create-rule`, `
|
|
209
|
+
* number, such as `create-rule`, `target-check`, and `target-setup` already
|
|
210
210
|
* write correctly, from matching. The segment group between `rules/` and the
|
|
211
211
|
* numbered file admits both a governance-namespace path
|
|
212
212
|
* (`canon/canon/604-scratch.md`) and a project-namespace one
|
package/src/standards/read.ts
CHANGED
|
@@ -59,7 +59,38 @@ export function standardRoots(root: string): StandardRoot[] {
|
|
|
59
59
|
* map goes with the verb in the last slice of the retirement.
|
|
60
60
|
*/
|
|
61
61
|
const MOVED_STANDARDS: Readonly<Record<string, string>> = {
|
|
62
|
+
board: 'claude/skills/task-board/references/board.md',
|
|
62
63
|
markdown: 'claude/skills/markdown-craft/references/markdown.md',
|
|
64
|
+
canvas: 'claude/skills/canvas/references/canvas.md',
|
|
65
|
+
glossary: 'claude/skills/teach-workspace/references/glossary.md',
|
|
66
|
+
groundwork: 'claude/skills/plan-groundwork/references/groundwork.md',
|
|
67
|
+
'groundwork-spikes':
|
|
68
|
+
'claude/skills/plan-groundwork/references/groundwork-spikes.md',
|
|
69
|
+
intake: 'claude/skills/plan-intake/references/intake.md',
|
|
70
|
+
mermaid: 'claude/skills/draft-figure/references/mermaid.md',
|
|
71
|
+
plan: 'claude/skills/plan-feature/references/plan.md',
|
|
72
|
+
'plan-lifecycle': 'claude/skills/plan-feature/references/plan-lifecycle.md',
|
|
73
|
+
ready: 'claude/skills/draft-ready/references/ready.md',
|
|
74
|
+
requirements: 'claude/skills/draft-doc/references/requirements.md',
|
|
75
|
+
'skill-paths': 'claude/skills/create-skill/references/skill-paths.md',
|
|
76
|
+
'skill-practice': 'claude/skills/create-skill/references/skill-practice.md',
|
|
77
|
+
session: 'claude/skills/session-map/references/session.md',
|
|
78
|
+
'skill-requirement':
|
|
79
|
+
'claude/skills/create-skill/references/skill-requirement.md',
|
|
80
|
+
tasks: 'claude/skills/task-board/references/tasks.md',
|
|
81
|
+
'tasks-decline': 'claude/skills/task-board/references/tasks-decline.md',
|
|
82
|
+
teach: 'claude/skills/teach-workspace/references/teach.md',
|
|
83
|
+
wiki: 'claude/skills/draft-doc/references/wiki.md',
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* The package-relative path a retired standard now lives at, so a caller that
|
|
88
|
+
* resolves against a root of its own tests the same map the verb reads.
|
|
89
|
+
*/
|
|
90
|
+
export function movedStandardPath(name: string): string | undefined {
|
|
91
|
+
if (!Object.hasOwn(MOVED_STANDARDS, name)) return undefined
|
|
92
|
+
|
|
93
|
+
return MOVED_STANDARDS[name]
|
|
63
94
|
}
|
|
64
95
|
|
|
65
96
|
function filename(name: string): string {
|
package/src/sync/seeds-report.ts
CHANGED
|
@@ -34,7 +34,7 @@ export interface SeedsReport {
|
|
|
34
34
|
* Classifies every seed the toolkit ships against the target's copy, and never
|
|
35
35
|
* returns a change. Seeds are copy-once files a project is expected to edit, so
|
|
36
36
|
* the engine's copy path would overwrite `CLAUDE.md` wholesale. Reporting alone
|
|
37
|
-
* is what lets
|
|
37
|
+
* is what lets an operator merge one section at a time by hand instead.
|
|
38
38
|
*
|
|
39
39
|
* Attribution reuses the history reader rather than the engine's own recovery
|
|
40
40
|
* pass, which is private and takes a `SyncAdapter` seeds have no way to supply.
|