Skip to content

feat(webkit): add webkit sync — provenance-stamped Claude bundle copies - #970

Merged
isaque-bock-azion merged 4 commits into
mainfrom
feat/webkit-sync
Sep 16, 2026
Merged

isaque-bock-azion merged 4 commits into
mainfrom
feat/webkit-sync

Conversation

@isaque-bock-azion

@isaque-bock-azion isaque-bock-azion commented Sep 16, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • init copied the .claude/ bundle (rules/skills/agents) once, skip-if-exists, with no version marker — an upstream template update never reached a consumer, and a pristine copy was indistinguishable from one edited locally.
  • Every bundle file init/sync writes now carries an inert HTML-comment provenance marker (<!-- webkit-sync source=... version=... sha256=... -->), placed on line 1 or right after a YAML frontmatter block's closing ---. bundle.js gained stamp/parseMarker/stripMarker/bodyHash/classify to compute and compare it.
  • New packages/webkit/src/cli/sync.js (planSync) classifies every bundle file as missing/current/stale/modified/unstamped-identical/unstamped-different/orphan against the templates this webkit version ships, and plans the safe action for each — copy what's missing, update what's stale, leave a local edit alone unless --force, never delete an orphan. The CLAUDE.md fragment is folded into the same run via the existing fence mechanism.
  • New webkit sync [--check] [--dry-run] [--force] [--json] CLI command; doctor gained a claude bundle check (FAIL on drift, WARN on a local-edit-only state) and its pre-commit-hook check was relaxed to a loose stylelint-invocation match instead of requiring the exact hook line.
  • init's own bundle-copy step now delegates to planSync so both commands share one policy — a fresh project has every file missing, so init's output is unchanged except every copy is now stamped.

Rebased on main after #968 merged. Also folds in two review fixes to the bundle derivation: a fixed bundle shape (rules/*.md, agents/*.md, skills/*/SKILL.md) so a future references/*.md is not shipped by accident, and a legacy-marker migration that no longer depends on a heading literal copied from CLAUDE.fragment.md.

How to test

  1. pnpm --filter @aziontech/webkit test:toolkit — 153 tests, all green (includes new test/cli/sync.test.mjs and the extended test/cli/bundle.test.mjs).
  2. pnpm --filter @aziontech/webkit lint and pnpm --filter @aziontech/webkit format:check — clean.
  3. node packages/webkit/scripts/smoke-consume.mjs — packs the real tarballs, scaffolds a Vite+Vue app, runs init, then exercises sync --check (clean), a local edit (sync --check reports modified, disk untouched), sync --force (restores it), and doctor (claude bundle OK) before the final build/CSS assertions.
  4. Manually: npx @aziontech/webkit sync --check in a project that already ran init should print "drift: no" and exit 0; editing a copied rule and re-running should report it modified (exit 0, not drift) without touching the file; --force then restores it.

Notes

None.

@isaque-bock-azion
isaque-bock-azion requested a review from a team as a code owner September 16, 2026 01:11
@isaque-bock-azion
isaque-bock-azion changed the base branch from feat/claude-bundle-fence to main September 16, 2026 01:19
init copied the .claude/ bundle (rules/skills/agents) once, skip-if-exists,
with no version marker. An upstream update to a rule or skill never reached
a project that had already run init, and there was no way to tell a
pristine copy from one a consumer had edited on purpose.

Every bundle file init/sync writes now carries one inert HTML-comment
provenance marker:

  <!-- webkit-sync source=claude/rules/webkit-imports.md version=5.0.0 sha256=<16 hex> -->

placed on line 1 for a file with no frontmatter, or as the first line after
the closing --- of a YAML frontmatter block (skills/agents), so it can
never be mistaken for a frontmatter key. The sha256 is a short hash of the
file's own body (marker removed, \r\n normalized). Comparing that hash
against a freshly computed one is how a file is classified as missing,
current, stale (the template changed since it was stamped), modified (the
consumer edited it), unstamped-identical/unstamped-different (a copy made
before sync existed), or orphan (a webkit-named file whose marker source no
longer exists in the bundle).

New `webkit sync [--check] [--dry-run] [--force] [--json]` applies the
policy this classification implies: copy what's missing, rewrite what's
stale or was an unstamped-but-identical copy, leave a modified file alone
unless --force says otherwise, and only ever report an orphan — never
delete it. The CLAUDE.md fragment is folded into the same run via the
existing fence mechanism. sync touches only .claude/{rules,skills,agents}
and CLAUDE.md, never .husky, .mcp.json, or package.json. `doctor` gained a
"claude bundle" check that fails on drift and warns on a local edit alone;
its pre-commit-hook check was also relaxed to a loose stylelint-invocation
match so a consumer's customized hook doesn't warn forever.

init's own bundle step now delegates to planSync so both commands share one
policy — a fresh project has every file "missing", so init's plan is
unchanged except that every copy is now stamped.
…ratchet

Moves the provenance-marker and classify()/planSync() rationale into
docs/toolkit/cli.md's sync section, leaving one-line JSDoc pointers in
source, per the verbose-comment-block and comment-heavy-file checks.
…ading

listBundle walked skills/ recursively, so a future references/*.md inside a
consumer skill would ship to every consumer unless someone remembered the
EXCLUDE set — the same drift the derived list was meant to remove, inverted.
The bundle now has a fixed shape (rules/*.md, agents/*.md, skills/*/SKILL.md)
and the test comparing it to a full walk of the templates dir fails when a
file appears outside it, so shipping one becomes a deliberate decision.

The legacy-marker migration compared headings against a string literal copied
from CLAUDE.fragment.md. A renamed heading would have silently truncated the
legacy block and left the old body behind the new fence as user content. The
boundary is now derived: the heading right after the marker and any heading
present in the new body are the fragment's own; only other headings end the
block.
@isaque-bock-azion
isaque-bock-azion merged commit d0df1b3 into main Sep 16, 2026
23 checks passed
@isaque-bock-azion
isaque-bock-azion deleted the feat/webkit-sync branch September 16, 2026 20:46
@github-actions github-actions Bot mentioned this pull request Sep 16, 2026
gabriel-lisboa-azion added a commit that referenced this pull request Sep 21, 2026
demo/vue-sample had drifted 540 ahead / 31 behind main while most of its
webkit work was reviewed and landed upstream (#941 command-menu, #942
GlobalHeader placements, #943 NavigationMenu, #952 Menu, #960 sidebar
collapse, #973 floating-panel placement, #975 paginator, #977 templates
exports, #921 amount ladder), after which main swept comments (#951) and
reworked the CLI onto a derived bundle (#968/#970).

Main is the source for everything the two share. Of the 28 conflicted
source files, 17 differed from main only in comments — their code was
byte-identical — and 6 more were genuinely newer on main, so all 23 take
main verbatim, including the use-placement TypeScript rewrite that
replaces the old index.js.

Three carve-outs keep demo work main does not have yet:

- sidebar: main's CSS-driven collapse is the base; the `side` axis is
  re-applied on top of it as data-[side=end] variants rather than the JS
  edge map it used to be, and the drag sign moves into the rail
  composable. The one test that asserted the removed inline transform now
  asserts the panel's published edge, since the direction is CSS the
  unstyled test env cannot see.
- theme: texts.data.js keeps demo's 13 extra text-wrap and 10 extra
  tracking declarations (PR #982, in flight). Both sides carry the same
  34 entries, so an entry count would not have caught the loss.
- doc-prose keeps its chrome-padding fix (PR #981, in flight).

catalog.json, authoring-baseline.json, the theme dist and the lockfile
are regenerated rather than hand-resolved; the 13 conflicted visual
baselines take main's and are regenerated from CI next.

Verified: every file main touched is byte-identical to main except the
22 accounted for above; 2364 browser tests, 179 toolkit tests, lint,
vue-tsc, 99.98% type coverage, both ratchets, the Storybook build and
the webkit-sample build all pass.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

3 participants