@erclx/canon 5.45.0 → 5.46.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/api-design/REQUIREMENT.md +15 -31
- package/claude/skills/auto-ship/REQUIREMENT.md +14 -25
- package/claude/skills/backlog-triage/REQUIREMENT.md +12 -23
- package/claude/skills/build-in-slices/REQUIREMENT.md +15 -25
- package/claude/skills/canon-cli/REQUIREMENT.md +15 -27
- package/claude/skills/canon-feedback/REQUIREMENT.md +10 -18
- package/claude/skills/canon-feedback-triage/REQUIREMENT.md +10 -15
- package/claude/skills/canvas-board/REQUIREMENT.md +14 -28
- package/claude/skills/ci-workflow/REQUIREMENT.md +12 -21
- package/claude/skills/code-craft/REQUIREMENT.md +14 -28
- package/claude/skills/codebase-layout/REQUIREMENT.md +14 -31
- package/claude/skills/context-fold/REQUIREMENT.md +15 -39
- package/claude/skills/context-fold/references/context.md +3 -3
- package/claude/skills/create-rule/REQUIREMENT.md +10 -24
- package/claude/skills/create-rule/SKILL.md +3 -0
- package/claude/skills/create-skill/REQUIREMENT.md +10 -21
- package/claude/skills/decision-escalate/REQUIREMENT.md +12 -24
- package/claude/skills/deploy-app/REQUIREMENT.md +12 -22
- package/claude/skills/deprecation-migration/REQUIREMENT.md +14 -42
- package/claude/skills/design-identity/REQUIREMENT.md +14 -20
- package/claude/skills/design-taste/REQUIREMENT.md +16 -57
- package/claude/skills/docs-sync/REQUIREMENT.md +14 -23
- package/claude/skills/document-health/REQUIREMENT.md +15 -29
- package/claude/skills/document-health/SKILL.md +2 -2
- package/claude/skills/document-repair/REQUIREMENT.md +32 -0
- package/claude/skills/document-repair/SKILL.md +76 -0
- package/claude/skills/document-repair/references/batches.md +44 -0
- package/claude/skills/draft-and-pick/REQUIREMENT.md +4 -3
- package/claude/skills/draft-doc/REQUIREMENT.md +4 -3
- package/claude/skills/draft-figure/REQUIREMENT.md +4 -3
- package/claude/skills/draft-identity/REQUIREMENT.md +4 -3
- package/claude/skills/draft-ready/REQUIREMENT.md +4 -3
- package/claude/skills/draft-screencast/REQUIREMENT.md +4 -3
- package/claude/skills/draft-slides/REQUIREMENT.md +4 -3
- package/claude/skills/draw-figure/REQUIREMENT.md +15 -39
- package/claude/skills/git-branch/REQUIREMENT.md +12 -26
- package/claude/skills/git-commit/REQUIREMENT.md +11 -15
- package/claude/skills/git-followup/REQUIREMENT.md +11 -22
- package/claude/skills/git-issue/REQUIREMENT.md +9 -15
- package/claude/skills/git-pr/REQUIREMENT.md +13 -32
- package/claude/skills/git-pr/SKILL.md +10 -2
- package/claude/skills/git-pr/references/closing-issues.md +47 -0
- package/claude/skills/git-pr/references/pr.md +4 -0
- package/claude/skills/git-ship/REQUIREMENT.md +13 -26
- package/claude/skills/git-split/REQUIREMENT.md +10 -17
- package/claude/skills/git-stage/REQUIREMENT.md +12 -18
- package/claude/skills/git-worktree/REQUIREMENT.md +15 -19
- package/claude/skills/make-deck/REQUIREMENT.md +13 -21
- package/claude/skills/markdown-craft/REQUIREMENT.md +9 -3
- package/claude/skills/plan-feature/REQUIREMENT.md +15 -24
- package/claude/skills/plan-groundwork/REQUIREMENT.md +12 -28
- package/claude/skills/plan-groundwork/SKILL.md +5 -2
- package/claude/skills/plan-groundwork/references/output.md +47 -1
- package/claude/skills/plan-intake/REQUIREMENT.md +11 -26
- package/claude/skills/plan-intake/references/intake.md +2 -2
- package/claude/skills/plan-intake-answer/REQUIREMENT.md +14 -29
- package/claude/skills/plan-intake-answer/SKILL.md +7 -1
- package/claude/skills/plan-ready/REQUIREMENT.md +17 -36
- package/claude/skills/pr-evidence/REQUIREMENT.md +11 -17
- package/claude/skills/read-frames/REQUIREMENT.md +3 -8
- package/claude/skills/record-screencast/REQUIREMENT.md +14 -17
- package/claude/skills/review-address/REQUIREMENT.md +14 -38
- package/claude/skills/review-craft/REQUIREMENT.md +14 -32
- package/claude/skills/review-pr/REQUIREMENT.md +15 -34
- package/claude/skills/review-ui/REQUIREMENT.md +14 -39
- package/claude/skills/role-orchestrator/REQUIREMENT.md +2 -2
- package/claude/skills/role-orchestrator/references/orchestrator-refill.md +5 -0
- package/claude/skills/role-orchestrator/references/orchestrator-review-dispatch.md +9 -0
- package/claude/skills/role-reviewer/REQUIREMENT.md +15 -65
- package/claude/skills/role-reviewer/SKILL.md +5 -1
- package/claude/skills/role-worker/REQUIREMENT.md +1 -1
- package/claude/skills/role-worker/SKILL.md +2 -0
- package/claude/skills/script-screencast/REQUIREMENT.md +10 -16
- package/claude/skills/search-craft/REQUIREMENT.md +12 -36
- package/claude/skills/search-craft/SKILL.md +1 -1
- package/claude/skills/search-craft/references/adopted.md +2 -2
- package/claude/skills/session-compact/REQUIREMENT.md +13 -23
- package/claude/skills/session-map/REQUIREMENT.md +13 -29
- package/claude/skills/session-relay/REQUIREMENT.md +14 -58
- package/claude/skills/session-relay/SKILL.md +6 -0
- package/claude/skills/session-resume/REQUIREMENT.md +13 -27
- package/claude/skills/session-worktree/REQUIREMENT.md +14 -43
- package/claude/skills/systematic-debugging/REQUIREMENT.md +13 -34
- package/claude/skills/target-check/REQUIREMENT.md +16 -23
- package/claude/skills/target-setup/REQUIREMENT.md +11 -34
- package/claude/skills/task-board/REQUIREMENT.md +13 -22
- package/claude/skills/task-board/SKILL.md +7 -0
- package/claude/skills/task-board/references/tasks.md +1 -1
- package/claude/skills/task-complete/REQUIREMENT.md +11 -24
- package/claude/skills/task-complete/references/archive.md +1 -0
- package/claude/skills/teach-workspace/REQUIREMENT.md +14 -45
- package/claude/skills/test-craft/REQUIREMENT.md +15 -46
- package/claude/skills/test-first/REQUIREMENT.md +14 -20
- package/claude/skills/ui-checklist/REQUIREMENT.md +14 -29
- package/claude/skills/ux-audit/REQUIREMENT.md +3 -7
- package/claude/skills/ux-measure/REQUIREMENT.md +14 -28
- package/claude/skills/video-craft/REQUIREMENT.md +14 -27
- package/claude/skills/write-doc/REQUIREMENT.md +14 -24
- package/claude/skills/write-human/REQUIREMENT.md +15 -27
- package/claude/skills/youtube-transcripts/REQUIREMENT.md +9 -15
- package/docs/agents/context-audit.md +19 -12
- package/docs/agents/markdown-audit.md +15 -10
- package/docs/target/projects.md +2 -0
- package/docs/workflow/skill-map.md +6 -5
- package/governance/renames.toml +0 -2
- package/governance/rules/claude/output.md +5 -1
- package/governance/rules/code/routing.md +5 -1
- package/governance/stacks/base.toml +0 -1
- package/package.json +1 -1
- package/src/claude/cases/workflow.ts +12 -0
- package/src/commands/context.ts +57 -3
- package/src/commands/labels.ts +83 -3
- package/src/commands/markdown.ts +188 -21
- package/src/commands/sessions.ts +36 -3
- package/src/commands/tasks.ts +180 -0
- package/src/commands/worktrees.ts +2 -0
- package/src/context/coverage.ts +210 -0
- package/src/context/gate.ts +12 -3
- package/src/gate/stages.ts +1 -1
- package/src/init/steps.ts +45 -0
- package/src/intake/items.ts +14 -0
- package/src/labels/closing.ts +46 -0
- package/src/markdown/gated.ts +250 -0
- package/src/markdown/scope.ts +115 -2
- package/src/migrate/rename.ts +6 -0
- package/src/sessions/claim.ts +7 -0
- package/src/sessions/live.ts +53 -6
- package/src/sessions/registry.ts +11 -0
- package/src/sessions/resolve.ts +32 -5
- package/src/tasks/closes.ts +136 -0
- package/src/tasks/record.ts +1 -1
- package/src/worktrees/reclaim.ts +16 -1
- package/tooling/base/configs/scripts/verify.ts +1 -1
- package/tooling/claude/seeds/.claude/hooks/board-validate.sh +1 -1
- package/tooling/claude/seeds/CLAUDE.md +2 -2
- package/governance/rules/canon/task-scope.md +0 -12
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises'
|
|
2
|
+
import {
|
|
3
|
+
fenceMask,
|
|
4
|
+
readOutcomes,
|
|
5
|
+
readPendingBranches,
|
|
6
|
+
readPullRequest,
|
|
7
|
+
} from '@/tasks/archive'
|
|
8
|
+
import {
|
|
9
|
+
openTask,
|
|
10
|
+
type RecordRefused,
|
|
11
|
+
type RecordSelector,
|
|
12
|
+
} from '@/tasks/record'
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Why a task does or does not close its issues. `last-slice` is the only
|
|
16
|
+
* reason that closes. The rest mirror the conditions `archiveTask` applies at
|
|
17
|
+
* merge time, so an issue closes exactly when the task archives.
|
|
18
|
+
*/
|
|
19
|
+
export type ClosingReason =
|
|
20
|
+
| 'earlier-slice'
|
|
21
|
+
| 'last-slice'
|
|
22
|
+
| 'lookup-failed'
|
|
23
|
+
| 'no-issues'
|
|
24
|
+
| 'no-outcomes'
|
|
25
|
+
| 'open-outcomes'
|
|
26
|
+
| 'pending-branch'
|
|
27
|
+
|
|
28
|
+
export interface Closure {
|
|
29
|
+
readonly issues: readonly number[]
|
|
30
|
+
readonly closing: boolean
|
|
31
|
+
readonly reason: ClosingReason
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface TaskClosure extends Closure {
|
|
35
|
+
readonly ok: true
|
|
36
|
+
readonly stem: string
|
|
37
|
+
readonly path: string
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export type ClosureOutcome = TaskClosure | RecordRefused
|
|
41
|
+
|
|
42
|
+
const ISSUE_LINE = /^Issue:[ \t]*(#\d+(?:[ \t]*,[ \t]*#\d+)*)[ \t]*$/
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Reads every `Issue:` line outside a fence, each a bare `#NNN` or a comma
|
|
46
|
+
* list of them. A line carrying anything else, such as the older bare-path
|
|
47
|
+
* form, names no issue rather than the numbers that happened to parse, since a
|
|
48
|
+
* wrong number would close an unrelated issue.
|
|
49
|
+
*/
|
|
50
|
+
export function readIssues(text: string): readonly number[] {
|
|
51
|
+
const lines = text.split('\n')
|
|
52
|
+
const fenced = fenceMask(lines)
|
|
53
|
+
const issues = new Set<number>()
|
|
54
|
+
|
|
55
|
+
for (const [index, line] of lines.entries()) {
|
|
56
|
+
if (fenced[index]) continue
|
|
57
|
+
|
|
58
|
+
const match = ISSUE_LINE.exec(line)
|
|
59
|
+
if (!match) continue
|
|
60
|
+
|
|
61
|
+
for (const entry of match[1].split(',')) {
|
|
62
|
+
issues.add(Number(entry.trim().slice(1)))
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return [...issues]
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Decides whether the pull request for `branches` closes the task's issues.
|
|
71
|
+
* `branches` is the working branch and every name it carried, since a rename
|
|
72
|
+
* leaves the `Pending branch:` marker under the old one. Any other pending
|
|
73
|
+
* branch is a slice still to ship, so the task stays open behind it.
|
|
74
|
+
*/
|
|
75
|
+
export function decideClosing(
|
|
76
|
+
text: string,
|
|
77
|
+
branches: readonly string[],
|
|
78
|
+
pulls: readonly number[] | null = [],
|
|
79
|
+
): Closure {
|
|
80
|
+
const issues = readIssues(text)
|
|
81
|
+
if (issues.length === 0) {
|
|
82
|
+
return { issues, closing: false, reason: 'no-issues' }
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const listed = readPullRequest(text)
|
|
86
|
+
const last = listed.at(-1)
|
|
87
|
+
|
|
88
|
+
// A failed lookup cannot rule out that this branch is an earlier slice, and
|
|
89
|
+
// closing early is the unsafe direction. With nothing recorded yet there is
|
|
90
|
+
// no earlier slice to confuse it with, so that case still closes.
|
|
91
|
+
if (pulls === null && listed.length > 0) {
|
|
92
|
+
return { issues, closing: false, reason: 'lookup-failed' }
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (
|
|
96
|
+
last !== undefined &&
|
|
97
|
+
pulls !== null &&
|
|
98
|
+
!pulls.includes(last) &&
|
|
99
|
+
pulls.some((number) => listed.includes(number))
|
|
100
|
+
) {
|
|
101
|
+
return { issues, closing: false, reason: 'earlier-slice' }
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const others = readPendingBranches(text).filter(
|
|
105
|
+
(branch) => !branches.includes(branch),
|
|
106
|
+
)
|
|
107
|
+
if (others.length > 0) {
|
|
108
|
+
return { issues, closing: false, reason: 'pending-branch' }
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const { open, closed, cut } = readOutcomes(text)
|
|
112
|
+
if (open.length > 0) {
|
|
113
|
+
return { issues, closing: false, reason: 'open-outcomes' }
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
if (closed.length === 0 && cut.length === 0) {
|
|
117
|
+
return { issues, closing: false, reason: 'no-outcomes' }
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
return { issues, closing: true, reason: 'last-slice' }
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/** Resolves the task through the same selector `pull-request` takes. */
|
|
124
|
+
export async function readClosure(
|
|
125
|
+
root: string,
|
|
126
|
+
selector: RecordSelector,
|
|
127
|
+
branches: readonly string[],
|
|
128
|
+
pulls: readonly number[] | null = [],
|
|
129
|
+
): Promise<ClosureOutcome> {
|
|
130
|
+
const opened = await openTask(root, selector)
|
|
131
|
+
if ('ok' in opened) return opened
|
|
132
|
+
|
|
133
|
+
const text = await readFile(opened.path, 'utf8')
|
|
134
|
+
|
|
135
|
+
return { ok: true, ...opened, ...decideClosing(text, branches, pulls) }
|
|
136
|
+
}
|
package/src/tasks/record.ts
CHANGED
|
@@ -400,7 +400,7 @@ async function resolveStem(
|
|
|
400
400
|
return matched[0]
|
|
401
401
|
}
|
|
402
402
|
|
|
403
|
-
async function openTask(
|
|
403
|
+
export async function openTask(
|
|
404
404
|
root: string,
|
|
405
405
|
selector: RecordSelector,
|
|
406
406
|
): Promise<{ readonly stem: string; readonly path: string } | RecordRefused> {
|
package/src/worktrees/reclaim.ts
CHANGED
|
@@ -37,7 +37,11 @@ export type Refusal =
|
|
|
37
37
|
| 'held-by-session'
|
|
38
38
|
|
|
39
39
|
/** Why the whole reading was refused, so no verdict was produced at all. */
|
|
40
|
-
export type Unreadable =
|
|
40
|
+
export type Unreadable =
|
|
41
|
+
| 'gh-missing'
|
|
42
|
+
| 'gh-failed'
|
|
43
|
+
| 'sessions-unreadable'
|
|
44
|
+
| 'sessions-unchecked'
|
|
41
45
|
|
|
42
46
|
/**
|
|
43
47
|
* Which removal shape applies. `session` removes the background session and its
|
|
@@ -395,6 +399,17 @@ export async function reclaimReport(
|
|
|
395
399
|
}
|
|
396
400
|
}
|
|
397
401
|
|
|
402
|
+
// A foreign-namespace record whose socket is gone reads dead, but a reader
|
|
403
|
+
// that cannot see the pid may also be unable to see the socket, so it may be
|
|
404
|
+
// a live holder. The roster drops it, and a removal on that reading is final.
|
|
405
|
+
if (sessions.foreignDead > 0) {
|
|
406
|
+
return {
|
|
407
|
+
kind: 'unreadable',
|
|
408
|
+
reason: 'sessions-unchecked',
|
|
409
|
+
detail: `${sessions.foreignDead} session records come from another pid namespace and no socket answers for them, so nothing was read about whether they still hold a worktree.`,
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
|
|
398
413
|
const byBranch = new Map(
|
|
399
414
|
merged.merged.map((request) => [request.branch, request.number]),
|
|
400
415
|
)
|
|
@@ -323,7 +323,7 @@ function checkMarkdownBans(): void {
|
|
|
323
323
|
case 2:
|
|
324
324
|
pipeOutput(output)
|
|
325
325
|
fail(
|
|
326
|
-
'Markdown prose carries a banned character,
|
|
326
|
+
'Markdown prose carries a banned character, a relative link resolves to nothing on disk, or a gated path breaks a density limit',
|
|
327
327
|
)
|
|
328
328
|
break
|
|
329
329
|
case 3:
|
|
@@ -51,7 +51,7 @@ fi
|
|
|
51
51
|
# Exit 2 carries findings, so the status is read off the record rather than
|
|
52
52
|
# the exit code.
|
|
53
53
|
record=$(canon tasks validate --json --root "$root" 2>/dev/null)
|
|
54
|
-
ok=$(printf '%s' "$record" | jq -r '.ok
|
|
54
|
+
ok=$(printf '%s' "$record" | jq -r '.ok | tostring' 2>/dev/null)
|
|
55
55
|
|
|
56
56
|
if [ "$ok" = false ]; then
|
|
57
57
|
report "canon tasks validate refused the board after this edit: $(printf '%s' "$record" | jq -r '.message // .reason')"
|
|
@@ -4,14 +4,14 @@
|
|
|
4
4
|
|
|
5
5
|
## Context
|
|
6
6
|
|
|
7
|
-
- Before non-trivial work in a domain read `canon/context
|
|
7
|
+
- Before non-trivial work in a domain, read its entry under `canon/context/`. Find it from the index anchor below.
|
|
8
8
|
|
|
9
9
|
@canon/REQUIREMENTS.md
|
|
10
10
|
@canon/context/index.md
|
|
11
11
|
|
|
12
12
|
## Commands
|
|
13
13
|
|
|
14
|
-
-
|
|
14
|
+
- Run `bun run check` to verify and `bun run format` to fix before committing. The pre-push hook runs `check`, which writes nothing.
|
|
15
15
|
|
|
16
16
|
## Key paths
|
|
17
17
|
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: Scope, size, and link a task file correctly
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
# Tasks standards
|
|
6
|
-
|
|
7
|
-
## Task files
|
|
8
|
-
|
|
9
|
-
- Only create a task for work that spans multiple sessions or has real dependencies. Handle small edits immediately without a task entry.
|
|
10
|
-
- Do not add tasks retroactively for work already completed. Completed work is visible in git.
|
|
11
|
-
- Write a plan in `.canon/plans/` when a task needs execution detail beyond its own file, and link it from the task's intro paragraph.
|
|
12
|
-
- Write that plan in the same session as the task, since the executing session would otherwise re-derive the reasoning behind it.
|