@erclx/aitk 0.91.1 → 0.91.2

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": "0.91.1",
4
+ "version": "0.91.2",
5
5
  "author": {
6
6
  "name": "Eric Le",
7
7
  "url": "https://github.com/erclx"
@@ -17,6 +17,8 @@ aitk capture assets --out .claude/review/captures
17
17
 
18
18
  Only the HTML is asserted for drift. The PNG is a chromium render whose bytes move with the browser version, so rebuild it with `aitk capture assets/hero.html` when the check reports the HTML changed.
19
19
 
20
+ Every render writes a stamp beside its PNG, `hero.png` next to `hero.stamp`, holding the source filename, a `source-sha256` over the markup bytes it read, and an `image-sha256` over the image bytes it wrote. Both digests are what `bun run check` compares, so a markup edit committed without a capture and a PNG swapped under unchanged markup each fail. The stamp is tracked and commits alongside the pair. Nothing hand-edits it, and a capture that cannot write it reports that source as failed and exits 1, so an image whose stamp never landed is reported rather than passed over.
21
+
20
22
  | Option | Behavior |
21
23
  | ------------------ | ------------------------------------------------- |
22
24
  | `--out <dir>` | Write every PNG here instead of beside its source |
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@erclx/aitk",
3
3
  "type": "module",
4
- "version": "0.91.1",
4
+ "version": "0.91.2",
5
5
  "description": "Infrastructure and quality tooling for developer workflows",
6
6
  "license": "MIT",
7
7
  "bin": {
@@ -5,7 +5,9 @@
5
5
  # bytes move with the browser version, so asserting it in verify.sh would fail
6
6
  # on a machine whose chromium differs rather than on a stale count. Rebuild the
7
7
  # image with `aitk capture assets/hero.html` after this script reports a change.
8
- # The frame carries no version. `package.json` is bumped on main by the release
8
+ # That capture also writes assets/hero.stamp, which records the digest of the
9
+ # markup it rendered and is what the Hero stage compares, so all three files
10
+ # commit together. The frame carries no version. `package.json` is bumped on main by the release
9
11
  # tooling, so embedding it drifts every open branch on the next release and the
10
12
  # stage then fails for work that touched nothing.
11
13
  #
@@ -111,21 +111,90 @@ collect_plugin_manifests() {
111
111
  } | sort -u
112
112
  }
113
113
 
114
+ # sha256 of a file under the coreutils name and the macOS one. `aitk capture`
115
+ # writes the same digest into the stamp through node's crypto, so the two sides
116
+ # agree on an algorithm rather than on a tool being installed.
117
+ #
118
+ # Neither tool present returns 1 and says so. Falling through to an empty digest
119
+ # reports a mismatch against a blank value, which tells the reader the image is
120
+ # wrong when the truth is that the checker never ran.
121
+ #
122
+ # The refusal goes to stderr because every caller reads this through `$(...)`,
123
+ # which captures stdout into the digest variable and would swallow the message.
124
+ # `run_check` folds stderr into what it pipes, so the reader still sees it.
125
+ file_sha256() {
126
+ local digest
127
+ if command -v sha256sum >/dev/null 2>&1; then
128
+ digest=$(sha256sum "$1")
129
+ elif command -v shasum >/dev/null 2>&1; then
130
+ digest=$(shasum -a 256 "$1")
131
+ else
132
+ echo "Neither sha256sum nor shasum is installed, so $1 cannot be hashed." >&2
133
+ return 1
134
+ fi
135
+ printf '%s\n' "${digest%% *}"
136
+ }
137
+
138
+ # One digest the stamp recorded against the file it was taken over. An absent
139
+ # field reports itself rather than comparing against an empty string, so a stamp
140
+ # predating the current format is distinguishable from a file that moved.
141
+ #
142
+ # Both names in the message come off the paths rather than from arguments. The
143
+ # caller passes absolute paths and the reader wants repository-relative ones, and
144
+ # deriving them here is what keeps a name from disagreeing with the file it
145
+ # labels once a second capture source calls this.
146
+ assert_stamp_field() {
147
+ local stamp=$1 field=$2 file=$3
148
+ local stamp_label=${stamp#"$PROJECT_ROOT"/}
149
+ local file_label=${file#"$PROJECT_ROOT"/}
150
+ local recorded actual
151
+ recorded=$(awk -v key="$field:" '$1 == key { print $2; exit }' "$stamp")
152
+ if [ -z "$recorded" ]; then
153
+ echo "$stamp_label carries no $field line, so it predates the capture that writes one."
154
+ return 1
155
+ fi
156
+ actual=$(file_sha256 "$file") || return 1
157
+ if [ "$recorded" != "$actual" ]; then
158
+ echo "$stamp_label records $field $recorded"
159
+ echo "$file_label hashes to $actual"
160
+ return 1
161
+ fi
162
+ }
163
+
114
164
  # The drift assert covers the HTML because the PNG is a chromium render whose
115
165
  # bytes move with the browser. That leaves the artifact a visitor actually sees
116
166
  # asserted nowhere, so a branch that regenerates the HTML and never runs the
117
167
  # capture passes every stage while shipping an image with the old counts.
118
168
  #
119
- # The two files move together or the image is stale, so their last-touching
120
- # commit is the same commit. Comparing the branch's file list instead would pass
121
- # any branch that touched both anywhere, including one that regenerated the HTML
122
- # alone in a later commit. Both absent resolves to two empty strings and passes,
123
- # which is correct for a tree that carries neither.
124
- assert_hero_pair() {
125
- local html_commit png_commit
126
- html_commit=$(git -C "$PROJECT_ROOT" log -1 --format=%H -- assets/hero.html)
127
- png_commit=$(git -C "$PROJECT_ROOT" log -1 --format=%H -- assets/hero.png)
128
- [ "$html_commit" = "$png_commit" ]
169
+ # `aitk capture` records a digest of the markup it rendered and one of the image
170
+ # it wrote, so this reads provenance rather than timing. Comparing the commit
171
+ # that last touched each file passes any pair that moved together whatever the
172
+ # two files hold, which is what a binary conflict resolved by taking either side
173
+ # produces. All three absent passes, which is correct for a tree that carries
174
+ # none of them.
175
+ #
176
+ # Both digests are checked because either file can move alone. The markup side
177
+ # catches an edit committed with no capture, and the image side catches a PNG
178
+ # replaced under markup that never changed, which is the case the timing read
179
+ # caught by accident and a markup-only digest would drop.
180
+ assert_hero_stamp() {
181
+ local html="$PROJECT_ROOT/assets/hero.html"
182
+ local png="$PROJECT_ROOT/assets/hero.png"
183
+ local stamp="$PROJECT_ROOT/assets/hero.stamp"
184
+
185
+ if [ ! -f "$html" ] && [ ! -f "$png" ] && [ ! -f "$stamp" ]; then return 0; fi
186
+
187
+ local missing=""
188
+ [ -f "$html" ] || missing="$missing assets/hero.html"
189
+ [ -f "$png" ] || missing="$missing assets/hero.png"
190
+ [ -f "$stamp" ] || missing="$missing assets/hero.stamp"
191
+ if [ -n "$missing" ]; then
192
+ echo "Missing from the hero set:$missing"
193
+ return 1
194
+ fi
195
+
196
+ assert_stamp_field "$stamp" source-sha256 "$html" || return 1
197
+ assert_stamp_field "$stamp" image-sha256 "$png" || return 1
129
198
  }
130
199
 
131
200
  # Entries the audit actually measured, summed across the folders it resolved.
@@ -188,8 +257,8 @@ main() {
188
257
  # machine whose chromium differs rather than on a stale count.
189
258
  log_step "Hero"
190
259
  run_check "bash $PROJECT_ROOT/scripts/core/regen-hero.sh" "Hero regen failed"
191
- assert_no_drift "assets/hero.html" "Hero counts drifted. Run bun run check, then aitk capture assets/hero.html, and commit assets/hero.html with assets/hero.png."
192
- run_check "assert_hero_pair" "Hero HTML and image last moved in different commits, so the image may be stale. Run aitk capture assets/hero.html and commit both files together."
260
+ assert_no_drift "assets/hero.html" "Hero counts drifted. Run bun run check, then aitk capture assets/hero.html, and commit assets/hero.html with assets/hero.png and assets/hero.stamp."
261
+ run_check "assert_hero_stamp" "The hero set disagrees with the stamp written when the image was captured. Run aitk capture assets/hero.html and commit all three files together."
193
262
  log_info "Hero clean"
194
263
 
195
264
  log_step "Skill references"