@erclx/canon 4.73.0 ā 4.75.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/claude/.claude-plugin/plugin.json +1 -1
- package/claude/skills/create-skill/SKILL.md +0 -1
- package/claude/skills/docs-fold/SKILL.md +1 -1
- package/claude/skills/git-followup/SKILL.md +9 -5
- package/claude/skills/git-pr/SKILL.md +21 -0
- package/claude/skills/markdown-propose/REQUIREMENT.md +1 -1
- package/claude/skills/markdown-propose/SKILL.md +9 -7
- package/claude/skills/markdown-propose/references/format.md +5 -3
- package/claude/skills/plan-feature/SKILL.md +3 -3
- package/claude/skills/plan-groundwork/SKILL.md +6 -5
- package/claude/skills/plan-intake/SKILL.md +1 -1
- package/claude/skills/review-pr/SKILL.md +2 -2
- package/claude/skills/role-orchestrator/references/orchestrator-dispatch.md +1 -0
- package/claude/skills/role-orchestrator/references/orchestrator-parked.md +2 -1
- package/claude/skills/role-orchestrator/scripts/poll.sh +16 -10
- package/claude/skills/task-board/SKILL.md +37 -3
- package/claude/skills/teach-workspace/references/lesson-craft.md +1 -6
- package/docs/agents/commands.md +2 -0
- package/docs/agents/index.md +2 -1
- package/docs/agents/install-and-sync.md +7 -4
- package/docs/agents/pr-evidence.md +108 -0
- package/docs/agents/records.md +29 -9
- package/docs/agents/tasks.md +2 -0
- package/docs/target-projects.md +4 -0
- package/governance/rules/ui/440-surface-capture.md +1 -0
- package/package.json +1 -1
- package/src/commands/design.ts +10 -2
- package/src/commands/pr.ts +220 -0
- package/src/commands/records.ts +138 -0
- package/src/commands/transcripts.ts +20 -3
- package/src/design/base.css +59 -0
- package/src/design/components.ts +80 -50
- package/src/design/fonts.ts +21 -0
- package/src/init/plan.ts +8 -1
- package/src/init/steps.ts +17 -0
- package/src/intake/folder.ts +1 -1
- package/src/pr/evidence.ts +171 -0
- package/src/records/backup.ts +110 -38
- package/src/records/ordinal.ts +243 -0
- package/src/records/validate.ts +28 -0
- package/src/tasks/answers.ts +10 -1
- package/src/teach/fonts.ts +9 -11
- package/src/transcripts/fetch.ts +31 -1
- package/standards/architecture.md +1 -0
- package/standards/figures.md +51 -0
- package/standards/groundwork.md +2 -1
- package/standards/index.md +1 -0
- package/standards/intake.md +2 -1
- package/standards/plan.md +1 -0
- package/standards/skill.md +1 -1
- package/tooling/base/configs/.husky/post-merge +27 -0
- package/tooling/claude/seeds/.claude/hooks/tasks-index.sh +5 -4
package/src/transcripts/fetch.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
|
+
existsSync,
|
|
2
3
|
mkdirSync,
|
|
3
4
|
mkdtempSync,
|
|
4
5
|
readdirSync,
|
|
@@ -81,13 +82,42 @@ interface WriteOptions {
|
|
|
81
82
|
readonly fetchedAt: string
|
|
82
83
|
}
|
|
83
84
|
|
|
85
|
+
const INDEX_FILE = 'index.md'
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Writes a minimal index.md stub if the output directory carries none yet,
|
|
89
|
+
* so `canon indexes regen` has frontmatter to render entries against. Left
|
|
90
|
+
* alone once present, since a project may have customized it.
|
|
91
|
+
*/
|
|
92
|
+
function ensureIndex(outDir: string): void {
|
|
93
|
+
const indexPath = join(outDir, INDEX_FILE)
|
|
94
|
+
if (existsSync(indexPath)) return
|
|
95
|
+
|
|
96
|
+
const content = [
|
|
97
|
+
'---',
|
|
98
|
+
'title: Transcripts',
|
|
99
|
+
'subtitle: YouTube transcripts fetched by canon transcripts, one file per video.',
|
|
100
|
+
'---',
|
|
101
|
+
'',
|
|
102
|
+
'# Transcripts',
|
|
103
|
+
'',
|
|
104
|
+
'YouTube transcripts fetched by canon transcripts, one file per video.',
|
|
105
|
+
'',
|
|
106
|
+
'This folder is machine-written. Run canon indexes regen here to refresh its entries.',
|
|
107
|
+
'',
|
|
108
|
+
].join('\n')
|
|
109
|
+
|
|
110
|
+
writeFileSync(indexPath, content)
|
|
111
|
+
}
|
|
112
|
+
|
|
84
113
|
export function writeTranscript(
|
|
85
114
|
metadata: VideoMetadata,
|
|
86
115
|
subPath: string | null,
|
|
87
116
|
{ outDir, keepTimestamps, fetchedAt }: WriteOptions,
|
|
88
117
|
): string {
|
|
89
118
|
mkdirSync(outDir, { recursive: true })
|
|
90
|
-
|
|
119
|
+
ensureIndex(outDir)
|
|
120
|
+
const slug = `${fetchedAt}--${slugify(metadata.title)}--${metadata.videoId}`
|
|
91
121
|
const target = join(outDir, `${slug}.md`)
|
|
92
122
|
|
|
93
123
|
const hasTranscript = subPath !== null
|
|
@@ -27,6 +27,7 @@ Does not govern:
|
|
|
27
27
|
|
|
28
28
|
- How individual functions work line by line. The code carries its own behavior.
|
|
29
29
|
- Full type definitions. They live in code. Reference the shape conceptually if needed.
|
|
30
|
+
- A measurement paragraph specific to one domain's own mechanism. Route it to that domain's `.claude/context/<domain>.md` entry instead. The choice and its rejected alternative stay here whatever their reach, since reach is what makes a decision cross-domain, not how many domains its supporting measurement happens to touch.
|
|
30
31
|
|
|
31
32
|
## Sections
|
|
32
33
|
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Figure reference
|
|
3
|
+
description: When a figure earns its place, the render-first policy for a graph-shaped subject, freehand SVG as the escape hatch, and its wrapping, color, and accessibility rules
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Figure reference
|
|
7
|
+
|
|
8
|
+
Applies to every hand-drawn figure, wherever it is authored. A figure sits inside a document some other standard shapes, so this file reaches the figure and stops at its closing `</figure>` tag.
|
|
9
|
+
|
|
10
|
+
## Scope
|
|
11
|
+
|
|
12
|
+
Governs a hand-drawn figure wherever one is authored, naming no path because an attribute standard governs a fragment rather than a document type: when it earns its place, the render-first policy routing a graph-shaped subject through Mermaid, the wrapping and caption every figure carries, and its color and accessibility rules. It carries no template, since a figure has no document shape of its own and sits inside one another standard sets.
|
|
13
|
+
|
|
14
|
+
Does not govern:
|
|
15
|
+
|
|
16
|
+
- Direction, layout, node and edge budgets, labels, and render verification for the Mermaid path: `mermaid.md`
|
|
17
|
+
- The toolkit's own architecture-diagram surface at `.canon/diagrams/`, which shares no code, font, or visual language with this convention: `diagrams.md`
|
|
18
|
+
- Language, word choice, punctuation, and formatting in the caption or surrounding prose: `markdown.md`
|
|
19
|
+
- Voice, rhythm, and sentence construction in that prose: the `write-human` skill
|
|
20
|
+
- Which document types may carry a figure, and what else they require: that document type's own standard
|
|
21
|
+
|
|
22
|
+
## What a working figure looks like
|
|
23
|
+
|
|
24
|
+
A figure works when a reader who cannot see it still gets what it was for, and one who can see it gets nothing a well-placed sentence could not carry:
|
|
25
|
+
|
|
26
|
+
- Does the subject clear the bar: a relationship, a boundary, a path, or a before-and-after that prose or a list cannot carry as well?
|
|
27
|
+
- Does the caption name what to take from the figure rather than what it shows?
|
|
28
|
+
- Does the figure still read after every color and font it depends on is stripped to its fallback?
|
|
29
|
+
|
|
30
|
+
A figure failing these is non-conforming even when it satisfies every shape rule below.
|
|
31
|
+
|
|
32
|
+
## When a figure earns its place
|
|
33
|
+
|
|
34
|
+
- Draw a figure only when a relationship, a boundary, a path, or a before-and-after is the point of the passage rather than decoration for it. Most passages do not clear that bar.
|
|
35
|
+
- Leave the point in prose or a list when it already carries there. A figure reaching for every passage repeats the failure restraint already guards against elsewhere in the document.
|
|
36
|
+
|
|
37
|
+
## The render-first policy
|
|
38
|
+
|
|
39
|
+
- Route a graph-shaped subject, one whose relationship, boundary, or path a flowchart already expresses, through Mermaid's own hand-drawn look rather than through model-authored SVG coordinates. `mermaid.md` governs the fence itself.
|
|
40
|
+
- Reserve freehand inline SVG, plain shapes and lines authored directly in the markup, for a subject that is not graph-shaped. A figure that cannot express its subject through the deterministic path is a worse failure than an inconsistent one drawn by hand, so the hatch stays open rather than forcing every figure through the renderer.
|
|
41
|
+
- State this as a render-first policy rather than a ban on a tool-exported drawing. Routing a graph-shaped figure through Mermaid is itself running it through an external tool, so a rule banning any diagram "exported from a diagramming tool" would forbid the path this policy requires.
|
|
42
|
+
|
|
43
|
+
## Wrapping and captioning
|
|
44
|
+
|
|
45
|
+
- Wrap a figure in a `<figure>` element holding its drawing and a `<figcaption>` that names what to take from the figure rather than what it shows.
|
|
46
|
+
- Let the figure run wider than the surrounding prose column. A figure cramped to the reading measure loses the labels it needs.
|
|
47
|
+
|
|
48
|
+
## Color and accessibility
|
|
49
|
+
|
|
50
|
+
- Color every fill and stroke through a custom property the surrounding document's own stylesheet defines, never a literal hex value. The figure then re-colors itself on the same switch that re-colors the page.
|
|
51
|
+
- Give the drawing an accessible name: `role="img"` with `aria-label` for one short line, or `aria-labelledby` pointing at a `<title>` element inside it for a longer one.
|
package/standards/groundwork.md
CHANGED
|
@@ -25,7 +25,8 @@ Does not govern:
|
|
|
25
25
|
## Folder name
|
|
26
26
|
|
|
27
27
|
- Name the folder `<nn>-<slug>`, a two-digit zero-padded ordinal followed by a kebab-case slug.
|
|
28
|
-
-
|
|
28
|
+
- The ordinal marks a folder per track, opened once and worked over time, distinct from a file addressed by name, one already carrying its own sorting prefix, or one deliberately overwritten.
|
|
29
|
+
- Claim the ordinal through `canon records ordinal groundwork <slug> --claim`, which reads the highest one already present across both `.canon/groundwork/` and `.canon/intake/` and creates the folder in the same atomic act, closing the race a read-then-create sequence leaves open between two sessions opening at once. A listing then sorts by when each folder opened rather than alphabetically, and the count includes both kinds because the two share one creation-order line.
|
|
29
30
|
- With neither folder holding an entry, the first one opened takes `01`. Do not read this off the numbering inside a track, which starts at `00` on a large one and disagrees with intake's own first file.
|
|
30
31
|
- Never renumber an existing folder. The ordinal is the order it opened, and a later reader cites it by that name.
|
|
31
32
|
|
package/standards/index.md
CHANGED
|
@@ -14,6 +14,7 @@ Reference docs for consistent authoring across the toolkit and target projects.
|
|
|
14
14
|
- [Design reference](design.md): Shape and content rules for .claude/DESIGN.md
|
|
15
15
|
- [Diagram reference](diagrams.md): Shape and content rules for .canon/diagrams/<kind>.md files
|
|
16
16
|
- [Docs reference](docs.md): Reader and jurisdiction, frontmatter, page structure, what a page links out to, the diagram permission, and when a category earns a subfolder
|
|
17
|
+
- [Figure reference](figures.md): When a figure earns its place, the render-first policy for a graph-shaped subject, freehand SVG as the escape hatch, and its wrapping, color, and accessibility rules
|
|
17
18
|
- [Glossary reference](glossary.md): Frontmatter, entry shape, ordering, and the rules deciding which terms a glossary carries
|
|
18
19
|
- [Groundwork reference](groundwork.md): Folder layout, ordinal naming, reserved numbering, frontmatter and dating, required file contents, and conventions for a measurement track
|
|
19
20
|
- [Intake reference](intake.md): Folder layout, ordinal naming, reserved index number, frontmatter and dating, the item template, the answer contract, and retrieval
|
package/standards/intake.md
CHANGED
|
@@ -25,7 +25,8 @@ Does not govern:
|
|
|
25
25
|
## Folder name
|
|
26
26
|
|
|
27
27
|
- Name the folder `<nn>-<slug>`, a two-digit zero-padded ordinal followed by a kebab-case slug. This is the folder's own ordinal, distinct from the `NN-<domain>.md` numbering a cluster file carries inside it.
|
|
28
|
-
-
|
|
28
|
+
- The ordinal marks a folder per track, opened once and worked over time, distinct from a file addressed by name, one already carrying its own sorting prefix, or one deliberately overwritten.
|
|
29
|
+
- Claim the ordinal through `canon records ordinal intake <slug> --claim`, which reads the highest one already present across both `.canon/intake/` and `.canon/groundwork/` and creates the folder in the same atomic act, closing the race a read-then-create sequence leaves open between two sessions opening at once. A listing then sorts by when each folder opened rather than alphabetically, and the count includes both kinds because the two share one creation-order line.
|
|
29
30
|
- With neither folder holding an entry, the first one opened takes `01`. Do not read this off the numbering inside a dump, which starts at `00` and disagrees with groundwork's own first required file.
|
|
30
31
|
- Never renumber an existing folder. The ordinal is the order it opened, and a later reader cites it by that name.
|
|
31
32
|
|
package/standards/plan.md
CHANGED
|
@@ -38,6 +38,7 @@ A plan failing these is non-conforming even when it satisfies every shape rule b
|
|
|
38
38
|
|
|
39
39
|
- Name the file `feature-<slug>.md`, with `<slug>` two to four kebab-case words naming the concern.
|
|
40
40
|
- Write one concern per file. A request spanning two independent concerns takes two plans rather than one bundling both, since a bundled plan cannot be executed by two sessions or abandoned by half.
|
|
41
|
+
- A staged batch is a concern of its own and takes its own file rather than a `**Batch N**` sub-heading inside one plan's `**Files to touch:**`. `canon tasks plan-branch` derives one branch from one plan filename, so every batch sharing a file has nothing left to open a pull request against once an earlier batch merges under that name. State a batch's dependency on the ones before it in its own `**Constraints:**`.
|
|
41
42
|
- Derive the slug from the concern rather than from a branch, because the plan is written before the branch exists.
|
|
42
43
|
- Give the branch that executes the plan the same slug. A later surface finds the plan from the branch name and finds nothing when the two spellings differ.
|
|
43
44
|
|
package/standards/skill.md
CHANGED
|
@@ -156,7 +156,7 @@ Without this skill, a session <observed failure>, <observed failure>.
|
|
|
156
156
|
|
|
157
157
|
- `name` (required): kebab-case, matches folder name, no spaces or capitals
|
|
158
158
|
- `description` (required): what it does + when to use it, under 1024 chars, no XML tags
|
|
159
|
-
- `disable-model-invocation: true`: user-invoked only, Claude will not auto-trigger
|
|
159
|
+
- `disable-model-invocation: true`: user-invoked only, Claude will not auto-trigger. Set it on a skill that starts a process the operator owns, never on one reachable by a matched trigger. The field marks that boundary, not a style preference.
|
|
160
160
|
- `allowed-tools`: restrict tool access when the skill is active
|
|
161
161
|
- `metadata`: optional key-value pairs (`author`, `version`, `mcp-server`)
|
|
162
162
|
|
|
@@ -59,3 +59,30 @@ done
|
|
|
59
59
|
printf '\nš %s archive candidate(s) on the board:\n%s\n' "$count" "$closed"
|
|
60
60
|
printf 'Outcomes are marked on the branch, so each still needs its work confirmed\n'
|
|
61
61
|
printf 'on main. Run /task-board, which checks that and sweeps the plan first.\n\n'
|
|
62
|
+
|
|
63
|
+
# The gitignored record folders live on one disk and nowhere else, and a merge
|
|
64
|
+
# is the event that changes them most. This runs on every merge rather than
|
|
65
|
+
# only on one that closes a task, since a review report and a memory entry
|
|
66
|
+
# both land on runs that archive nothing.
|
|
67
|
+
#
|
|
68
|
+
# Sits last so a slow or unreachable remote delays no candidate announcement,
|
|
69
|
+
# and inside an `if` so a push failing offline, or a machine that never ran
|
|
70
|
+
# the one-time setup, still leaves this hook exiting zero. Guarded by its own
|
|
71
|
+
# `command -v canon` check, since this file carries none above it.
|
|
72
|
+
if command -v canon >/dev/null 2>&1; then
|
|
73
|
+
if backup=$(canon records push --root "$root" --json 2>/dev/null); then
|
|
74
|
+
changed=$(printf '%s' "$backup" | sed -n 's/.*"changed":\([0-9][0-9]*\).*/\1/p')
|
|
75
|
+
if [ -n "$changed" ] && [ "$changed" != "0" ]; then
|
|
76
|
+
printf '\nšļø Backed up %s record path(s).\n\n' "$changed"
|
|
77
|
+
fi
|
|
78
|
+
else
|
|
79
|
+
reason=$(printf '%s' "$backup" | sed -n 's/.*"reason":"\([^"]*\)".*/\1/p')
|
|
80
|
+
|
|
81
|
+
# No records history on this machine, which is every checkout that never
|
|
82
|
+
# ran the one-time setup. Nothing to report.
|
|
83
|
+
if [ "$reason" != "no-repository" ]; then
|
|
84
|
+
printf '\nšļø Records not backed up: %s\n' "${reason:-unknown}"
|
|
85
|
+
printf 'Run canon records push when the remote is reachable.\n\n'
|
|
86
|
+
fi
|
|
87
|
+
fi
|
|
88
|
+
fi
|
|
@@ -34,11 +34,12 @@ case "$file_path" in
|
|
|
34
34
|
esac
|
|
35
35
|
|
|
36
36
|
# The board index covers the live folder alone. A shell pattern's wildcard
|
|
37
|
-
# crosses a separator, so the guard above matches an archived
|
|
38
|
-
# a regen fired on one would rebuild the index
|
|
37
|
+
# crosses a separator, so the guard above matches an archived or declined task
|
|
38
|
+
# as well, and a regen fired on one would rebuild the index that task was
|
|
39
|
+
# taken out of.
|
|
39
40
|
case "$file_path" in
|
|
40
|
-
*/.claude/tasks/index.md | */.claude/tasks/archive/*) exit 0 ;;
|
|
41
|
-
*/.canon/tasks/index.md | */.canon/tasks/archive/*) exit 0 ;;
|
|
41
|
+
*/.claude/tasks/index.md | */.claude/tasks/archive/* | */.claude/tasks/declined/*) exit 0 ;;
|
|
42
|
+
*/.canon/tasks/index.md | */.canon/tasks/archive/* | */.canon/tasks/declined/*) exit 0 ;;
|
|
42
43
|
esac
|
|
43
44
|
|
|
44
45
|
# The walk-up boundary has to come from the path, not from the session. Shared
|