@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.
Files changed (137) hide show
  1. package/claude/.claude-plugin/plugin.json +1 -1
  2. package/claude/skills/api-design/REQUIREMENT.md +15 -31
  3. package/claude/skills/auto-ship/REQUIREMENT.md +14 -25
  4. package/claude/skills/backlog-triage/REQUIREMENT.md +12 -23
  5. package/claude/skills/build-in-slices/REQUIREMENT.md +15 -25
  6. package/claude/skills/canon-cli/REQUIREMENT.md +15 -27
  7. package/claude/skills/canon-feedback/REQUIREMENT.md +10 -18
  8. package/claude/skills/canon-feedback-triage/REQUIREMENT.md +10 -15
  9. package/claude/skills/canvas-board/REQUIREMENT.md +14 -28
  10. package/claude/skills/ci-workflow/REQUIREMENT.md +12 -21
  11. package/claude/skills/code-craft/REQUIREMENT.md +14 -28
  12. package/claude/skills/codebase-layout/REQUIREMENT.md +14 -31
  13. package/claude/skills/context-fold/REQUIREMENT.md +15 -39
  14. package/claude/skills/context-fold/references/context.md +3 -3
  15. package/claude/skills/create-rule/REQUIREMENT.md +10 -24
  16. package/claude/skills/create-rule/SKILL.md +3 -0
  17. package/claude/skills/create-skill/REQUIREMENT.md +10 -21
  18. package/claude/skills/decision-escalate/REQUIREMENT.md +12 -24
  19. package/claude/skills/deploy-app/REQUIREMENT.md +12 -22
  20. package/claude/skills/deprecation-migration/REQUIREMENT.md +14 -42
  21. package/claude/skills/design-identity/REQUIREMENT.md +14 -20
  22. package/claude/skills/design-taste/REQUIREMENT.md +16 -57
  23. package/claude/skills/docs-sync/REQUIREMENT.md +14 -23
  24. package/claude/skills/document-health/REQUIREMENT.md +15 -29
  25. package/claude/skills/document-health/SKILL.md +2 -2
  26. package/claude/skills/document-repair/REQUIREMENT.md +32 -0
  27. package/claude/skills/document-repair/SKILL.md +76 -0
  28. package/claude/skills/document-repair/references/batches.md +44 -0
  29. package/claude/skills/draft-and-pick/REQUIREMENT.md +4 -3
  30. package/claude/skills/draft-doc/REQUIREMENT.md +4 -3
  31. package/claude/skills/draft-figure/REQUIREMENT.md +4 -3
  32. package/claude/skills/draft-identity/REQUIREMENT.md +4 -3
  33. package/claude/skills/draft-ready/REQUIREMENT.md +4 -3
  34. package/claude/skills/draft-screencast/REQUIREMENT.md +4 -3
  35. package/claude/skills/draft-slides/REQUIREMENT.md +4 -3
  36. package/claude/skills/draw-figure/REQUIREMENT.md +15 -39
  37. package/claude/skills/git-branch/REQUIREMENT.md +12 -26
  38. package/claude/skills/git-commit/REQUIREMENT.md +11 -15
  39. package/claude/skills/git-followup/REQUIREMENT.md +11 -22
  40. package/claude/skills/git-issue/REQUIREMENT.md +9 -15
  41. package/claude/skills/git-pr/REQUIREMENT.md +13 -32
  42. package/claude/skills/git-pr/SKILL.md +10 -2
  43. package/claude/skills/git-pr/references/closing-issues.md +47 -0
  44. package/claude/skills/git-pr/references/pr.md +4 -0
  45. package/claude/skills/git-ship/REQUIREMENT.md +13 -26
  46. package/claude/skills/git-split/REQUIREMENT.md +10 -17
  47. package/claude/skills/git-stage/REQUIREMENT.md +12 -18
  48. package/claude/skills/git-worktree/REQUIREMENT.md +15 -19
  49. package/claude/skills/make-deck/REQUIREMENT.md +13 -21
  50. package/claude/skills/markdown-craft/REQUIREMENT.md +9 -3
  51. package/claude/skills/plan-feature/REQUIREMENT.md +15 -24
  52. package/claude/skills/plan-groundwork/REQUIREMENT.md +12 -28
  53. package/claude/skills/plan-groundwork/SKILL.md +5 -2
  54. package/claude/skills/plan-groundwork/references/output.md +47 -1
  55. package/claude/skills/plan-intake/REQUIREMENT.md +11 -26
  56. package/claude/skills/plan-intake/references/intake.md +2 -2
  57. package/claude/skills/plan-intake-answer/REQUIREMENT.md +14 -29
  58. package/claude/skills/plan-intake-answer/SKILL.md +7 -1
  59. package/claude/skills/plan-ready/REQUIREMENT.md +17 -36
  60. package/claude/skills/pr-evidence/REQUIREMENT.md +11 -17
  61. package/claude/skills/read-frames/REQUIREMENT.md +3 -8
  62. package/claude/skills/record-screencast/REQUIREMENT.md +14 -17
  63. package/claude/skills/review-address/REQUIREMENT.md +14 -38
  64. package/claude/skills/review-craft/REQUIREMENT.md +14 -32
  65. package/claude/skills/review-pr/REQUIREMENT.md +15 -34
  66. package/claude/skills/review-ui/REQUIREMENT.md +14 -39
  67. package/claude/skills/role-orchestrator/REQUIREMENT.md +2 -2
  68. package/claude/skills/role-orchestrator/references/orchestrator-refill.md +5 -0
  69. package/claude/skills/role-orchestrator/references/orchestrator-review-dispatch.md +9 -0
  70. package/claude/skills/role-reviewer/REQUIREMENT.md +15 -65
  71. package/claude/skills/role-reviewer/SKILL.md +5 -1
  72. package/claude/skills/role-worker/REQUIREMENT.md +1 -1
  73. package/claude/skills/role-worker/SKILL.md +2 -0
  74. package/claude/skills/script-screencast/REQUIREMENT.md +10 -16
  75. package/claude/skills/search-craft/REQUIREMENT.md +12 -36
  76. package/claude/skills/search-craft/SKILL.md +1 -1
  77. package/claude/skills/search-craft/references/adopted.md +2 -2
  78. package/claude/skills/session-compact/REQUIREMENT.md +13 -23
  79. package/claude/skills/session-map/REQUIREMENT.md +13 -29
  80. package/claude/skills/session-relay/REQUIREMENT.md +14 -58
  81. package/claude/skills/session-relay/SKILL.md +6 -0
  82. package/claude/skills/session-resume/REQUIREMENT.md +13 -27
  83. package/claude/skills/session-worktree/REQUIREMENT.md +14 -43
  84. package/claude/skills/systematic-debugging/REQUIREMENT.md +13 -34
  85. package/claude/skills/target-check/REQUIREMENT.md +16 -23
  86. package/claude/skills/target-setup/REQUIREMENT.md +11 -34
  87. package/claude/skills/task-board/REQUIREMENT.md +13 -22
  88. package/claude/skills/task-board/SKILL.md +7 -0
  89. package/claude/skills/task-board/references/tasks.md +1 -1
  90. package/claude/skills/task-complete/REQUIREMENT.md +11 -24
  91. package/claude/skills/task-complete/references/archive.md +1 -0
  92. package/claude/skills/teach-workspace/REQUIREMENT.md +14 -45
  93. package/claude/skills/test-craft/REQUIREMENT.md +15 -46
  94. package/claude/skills/test-first/REQUIREMENT.md +14 -20
  95. package/claude/skills/ui-checklist/REQUIREMENT.md +14 -29
  96. package/claude/skills/ux-audit/REQUIREMENT.md +3 -7
  97. package/claude/skills/ux-measure/REQUIREMENT.md +14 -28
  98. package/claude/skills/video-craft/REQUIREMENT.md +14 -27
  99. package/claude/skills/write-doc/REQUIREMENT.md +14 -24
  100. package/claude/skills/write-human/REQUIREMENT.md +15 -27
  101. package/claude/skills/youtube-transcripts/REQUIREMENT.md +9 -15
  102. package/docs/agents/context-audit.md +19 -12
  103. package/docs/agents/markdown-audit.md +15 -10
  104. package/docs/target/projects.md +2 -0
  105. package/docs/workflow/skill-map.md +6 -5
  106. package/governance/renames.toml +0 -2
  107. package/governance/rules/claude/output.md +5 -1
  108. package/governance/rules/code/routing.md +5 -1
  109. package/governance/stacks/base.toml +0 -1
  110. package/package.json +1 -1
  111. package/src/claude/cases/workflow.ts +12 -0
  112. package/src/commands/context.ts +57 -3
  113. package/src/commands/labels.ts +83 -3
  114. package/src/commands/markdown.ts +188 -21
  115. package/src/commands/sessions.ts +36 -3
  116. package/src/commands/tasks.ts +180 -0
  117. package/src/commands/worktrees.ts +2 -0
  118. package/src/context/coverage.ts +210 -0
  119. package/src/context/gate.ts +12 -3
  120. package/src/gate/stages.ts +1 -1
  121. package/src/init/steps.ts +45 -0
  122. package/src/intake/items.ts +14 -0
  123. package/src/labels/closing.ts +46 -0
  124. package/src/markdown/gated.ts +250 -0
  125. package/src/markdown/scope.ts +115 -2
  126. package/src/migrate/rename.ts +6 -0
  127. package/src/sessions/claim.ts +7 -0
  128. package/src/sessions/live.ts +53 -6
  129. package/src/sessions/registry.ts +11 -0
  130. package/src/sessions/resolve.ts +32 -5
  131. package/src/tasks/closes.ts +136 -0
  132. package/src/tasks/record.ts +1 -1
  133. package/src/worktrees/reclaim.ts +16 -1
  134. package/tooling/base/configs/scripts/verify.ts +1 -1
  135. package/tooling/claude/seeds/.claude/hooks/board-validate.sh +1 -1
  136. package/tooling/claude/seeds/CLAUDE.md +2 -2
  137. 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
+ }
@@ -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> {
@@ -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 = 'gh-missing' | 'gh-failed' | 'sessions-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, or a relative link resolves to nothing on disk',
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 // empty' 2>/dev/null)
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/<domain>.md`. Pick which from the index anchor below.
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
- - [Command to run before committing]
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.