@erclx/aitk 3.14.1 → 3.15.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.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "aitk",
3
3
  "description": "Automated governance, versioning, and discovery tools for Claude Code.",
4
- "version": "3.14.1",
4
+ "version": "3.15.0",
5
5
  "author": {
6
6
  "name": "Eric Le",
7
7
  "url": "https://github.com/erclx"
@@ -30,7 +30,7 @@ The greenfield path needs a personality paragraph to propose against, and stops
30
30
 
31
31
  Read these on both paths, skipping any that do not exist:
32
32
 
33
- - `CLAUDE.md`: voice, personality, spelling rules
33
+ - `CLAUDE.md`: voice and personality
34
34
  - `.claude/REQUIREMENTS.md`: the `## Personality` paragraph, worldview, non-goals
35
35
  - `${CLAUDE_SKILL_DIR}/../../standards/markdown.md`: word, punctuation, and formatting constraints
36
36
  - The `write-human` skill: tone and sentence construction constraints
@@ -73,6 +73,20 @@ git merge-base --is-ancestor <prior-oid> <headRefOid>
73
73
 
74
74
  On exit zero, review `<prior-oid>..<headRefOid>` and nothing else. `git diff` and `git log --oneline` over that range are the whole read, because the first pass already covered everything behind it. A non-zero exit means the branch was rebased or force-pushed, so the delta is undefined rather than empty. Fall back to the full pass above and say so in the body.
75
75
 
76
+ A commit is its own ancestor, so an unchanged head passes that test too, with an empty range. When `<prior-oid>` equals `<headRefOid>`, decide whether this pass has anything to add before reading anything else, since the empty range itself cannot answer that:
77
+
78
+ ```bash
79
+ gh pr view <number> --json reviews,comments --jq '([.reviews[] | select(.body // "" | split("\n")[0] | rtrimstr("\r") | . == "## Review" or . == "## Review closed")] | last | .submittedAt) as $prior | [.comments[] | select(.body // "" | split("\n")[0] | rtrimstr("\r") | . == "## Review response") | select(.createdAt > $prior)] | last | .url // empty | split("-") | last'
80
+ ```
81
+
82
+ Scope the responses to those newer than the prior pass, never to every response the thread carries. A pass answering the newest response and a pass answering an older one derive the same third segment (Step 4), so an unscoped read hands a re-run after a close-out the name its own prior pass already wrote. That is the collision this case exists to prevent, reached without a rebase or an error.
83
+
84
+ Read the number off `.url`. The `id` field carries a GraphQL node id, which the thread never displays. Keep the `// empty` guard, since `split` aborts jq on the null an empty selection returns, and an aborted command reaches the session as an error rather than as the empty result the stop below reads.
85
+
86
+ An empty result means no response arrived since the prior pass, so the head is unchanged and this pass has nothing new to add. Stop here, before Step 3 or Step 4 run: `❌ The head is unchanged since the prior pass on <short-sha>. Nothing new to review.` This is the earliest point every path crosses, which is why the check sits here rather than inside Step 4's filename derivation. A path that decides there is nothing to add never reaches a step reached only when composing a body, so a stop written there is a stop a shortcut path can route around.
87
+
88
+ A non-empty result carries the comment id Step 4 needs for the third filename segment. Read that comment for what the worker changed or accepted, and treat an accepted finding as closed rather than restating it. This is the entire read on a repeated head, since the empty range above has nothing in it to say whether a prior finding landed. Skip the diff and file reads below.
89
+
76
90
  Read each changed file in scope. Skip deleted files. Run reads in parallel.
77
91
 
78
92
  ## Step 3: review
@@ -109,19 +123,7 @@ Write the comment to `.claude/.tmp/pr-review/body-<number>-<short-sha>.md`. The
109
123
 
110
124
  Derive both segments from Step 1. Never pick a suffix by hand, and never reuse a name the folder already holds.
111
125
 
112
- When `<prior-oid>` from Step 2 equals `headRefOid`, the head repeats and the folder already holds `body-<number>-<short-sha>.md`. Add a third segment taking the id of the `## Review response` comment this pass answers, giving `body-<number>-<short-sha>-r<comment-id>.md`. That satisfies both prohibitions above rather than carving an exception into either.
113
-
114
- ```bash
115
- gh pr view <number> --json reviews,comments --jq '([.reviews[] | select(.body // "" | split("\n")[0] | rtrimstr("\r") | . == "## Review" or . == "## Review closed")] | last | .submittedAt) as $prior | [.comments[] | select(.body // "" | split("\n")[0] | rtrimstr("\r") | . == "## Review response") | select(.createdAt > $prior)] | last | .url // empty | split("-") | last'
116
- ```
117
-
118
- Scope the responses to those newer than the prior pass, never to every response the thread carries. A pass answering the newest response and a pass answering an older one derive the same third segment, so an unscoped read hands a re-run after a close-out the name its own prior pass already wrote. That is the collision this case exists to prevent, reached without a rebase or an error.
119
-
120
- Read the number off `.url`. The `id` field carries a GraphQL node id, which the thread never displays. Keep the `// empty` guard, since `split` aborts jq on the null an empty selection returns, and an aborted command reaches the session as an error rather than as the empty result the stop below reads.
121
-
122
- An empty result means no response arrived since the prior pass, so this pass would restate a body the folder already holds. Stop: `❌ No response since the prior pass on <short-sha>. Nothing new to review.`
123
-
124
- The response is also the whole read on a repeated head. Step 2 resolves an empty range, because a commit is its own ancestor and `<prior-oid>..<headRefOid>` spans nothing, so the delta cannot answer whether a prior finding landed. Read that comment for what the worker changed or accepted, and treat an accepted finding as closed rather than restating it.
126
+ When `<prior-oid>` from Step 2 equals `headRefOid`, the head repeats and the folder already holds `body-<number>-<short-sha>.md`. Add a third segment taking the id of the `## Review response` comment Step 2 resolved, giving `body-<number>-<short-sha>-r<comment-id>.md`. That satisfies both prohibitions above rather than carving an exception into either. Step 2 already stopped the pass when that resolution came back empty, so reaching this line means the comment id is in hand.
125
127
 
126
128
  The comment is a rendered-for-human GitHub surface, so load the `write-human` skill for voice and follow `${CLAUDE_SKILL_DIR}/../../standards/markdown.md` for the banned words: cut editorializing, and keep every sentence load-bearing. Match this shape on a first pass:
127
129
 
@@ -0,0 +1,14 @@
1
+ ---
2
+ description: Route index.md edits to the regeneration verb, its frontmatter contract, and the hand-edit opt-out
3
+ paths:
4
+ - '**/index.md'
5
+ ---
6
+
7
+ # Index standards
8
+
9
+ ## Generation
10
+
11
+ - Do not hand-edit an `index.md` that an agent browses to pick a document. Run `aitk indexes regen` instead.
12
+ - Preserve an `index.md`'s own frontmatter (`title`, `subtitle`). The regen walker keeps it.
13
+ - Add `auto: false` to an `index.md`'s frontmatter to keep that folder's index hand-edited.
14
+ - Skip `index.md` in a code folder or a scratch folder. Neither needs one.
@@ -0,0 +1,19 @@
1
+ ---
2
+ description: Route .cspell/ dictionary additions to the right seeded file and keep each sorted
3
+ paths:
4
+ - '.cspell/**'
5
+ ---
6
+
7
+ # Spelling standards
8
+
9
+ ## Dictionary routing
10
+
11
+ - Rewrite a typo rather than adding it. Add only a real term.
12
+ - Add a term from a tool, library, or platform the project depends on to `.cspell/tech-stack.txt`, whether it is the dependency's own name or vocabulary from its config, API, or spec.
13
+ - Add jargon, an acronym, a handle, or another project-specific term to `.cspell/project-terms.txt`.
14
+ - Leave a dictionary declared `addWords: false` alone. It mirrors a closed set maintained elsewhere in the project rather than approved vocabulary, so route a word there through whatever maintains that set instead of editing the dictionary file.
15
+ - Add a third dictionary only when cspell still flags a term neither file covers. Declare its path in `cspell.json` with `addWords: true` before adding words to it.
16
+
17
+ ## File shape
18
+
19
+ - Keep every dictionary file sorted alphabetically.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@erclx/aitk",
3
3
  "type": "module",
4
- "version": "3.14.1",
4
+ "version": "3.15.0",
5
5
  "description": "Infrastructure and quality tooling for developer workflows",
6
6
  "license": "MIT",
7
7
  "bin": {
@@ -31,8 +31,6 @@
31
31
  ## Indexes
32
32
 
33
33
  - Check a folder's `index.md` before grepping its source or reading its files, starting with `.claude/context/` for a domain and `.claude/wireframes/` for a UI surface. It orients faster than a blind search.
34
- - For folders where an agent browses to pick a document, `index.md` is regenerated from each file's frontmatter. Do not hand-edit `index.md`. Code folders and scratch folders do not need one.
35
- - Every `index.md` carries its own frontmatter (`title`, `subtitle`) that the walker preserves. To keep a folder's `index.md` hand-edited, add `auto: false` to its frontmatter.
36
34
 
37
35
  ## Commands
38
36
 
@@ -60,11 +58,6 @@
60
58
  - `.claude/rules/`: path-scoped coding standards loaded by Claude Code on file match
61
59
  - `.claude/review/`: gitignored scratch for review and UI-test output, overwritten on each run
62
60
 
63
- ## Spelling
64
-
65
- - When cspell flags a word, rewrite typos. Add real terms to the appropriate dictionary in `cspell.json`.
66
- - Keep dictionary files sorted alphabetically
67
-
68
61
  ## Tasks
69
62
 
70
63
  - `.claude/tasks/` is gitignored local session scratch, one file per task. Edit freely. No staging or revert before commits.