Skip to content

feat(cli): keep your edits when you reinstall a catalog item - #3193

Merged
miguel-heygen merged 2 commits into
mainfrom
feat/add-preserves-local-edits
Aug 10, 2026
Merged

miguel-heygen merged 2 commits into
mainfrom
feat/add-preserves-local-edits

Conversation

@miguel-heygen

@miguel-heygen miguel-heygen commented Aug 10, 2026 •

Copy link
Copy Markdown
Collaborator

What

hyperframes add <item> no longer overwrites files you have edited. It keeps them, says so, and offers --force.

Why

Reinstalling an item, or installing something that depends on it, wrote over whatever was on disk. A project that had tuned a block's colours or timing lost that work with no prompt and no message. Since dependencies install silently, you could lose an edit to a file you did not name.

How

The installer records a SHA-256 of each file as it writes it, in hyperframes.lock.json at the project root, and compares before writing again.

Three cases, and the middle one is the point:

On disk What happens
Matches what we installed replaced, as before
Differs from what we installed kept, and reported
No record of it kept

The last row is deliberate. An unrecorded file covers a project that wrote it by hand and one that installed before this record existed; both would rather keep their file than have it silently replaced. A malformed or truncated record reads as "no record" for the same reason.

The check runs before fetching rather than after, so a file we are going to keep is never overwritten and then restored — a crash in between would lose it for real. Hashing happens after the block marker comment is added, or the next install would read our own marker as your edit.

This sits in installItem, so add, the Studio server's dependency install, and template scaffolding all get it.

Test plan

  • Unit tests added/updated
  • Manual testing performed
  • Documentation updated (if applicable)

Nine tests in installer.test.ts cover each row above, --force, and the marker case. They are load-bearing: with the guard stubbed out, two fail.

Also exercised through the real CLI against a scratch project, since the unit tests mock the fetch:

  1. add data-chart — installs, writes the record
  2. append a comment to the file, add data-chart again — prints kept compositions/data-chart.html — you have edited this; --force to overwrite, and the comment is still there
  3. add data-chart --force — the comment is gone
  4. add data-chart on the now-untouched file — updates normally, nothing kept

Wider suite: 102 passing across packages/cli/src/registry and add.test.ts.

End-to-end, with a variables-bearing item

Run against split-flap-board (5 declared variables), following what its catalog page tells a reader to do, against the published registry with no override:

  1. hyperframes add split-flap-board into a fresh project — writes compositions/split-flap-board.html and records its hash
  2. edit the composition the way a reader would: board text to GATE 42 CLOSING, cell count 12 to 16
  3. add split-flap-board again — prints kept compositions/split-flap-board.html — you have edited this; --force to overwrite, both edits intact
  4. render the project — the frame shows GATE 42 CLOSING across 16 cells, so the preserved file is still valid and the edits actually take effect
  5. add split-flap-board --force — registry version back, text and cell count restored
  6. add split-flap-board once more — treated as untouched, updates normally

Worth knowing for anyone editing a variables-bearing block: the default inside data-composition-variables feeds the editing UI, while the composition's own script carries a separate hardcoded fallback (num(vars.cellCount, 1, 24, 12)). Changing the declared default alone changes nothing on screen unless a host passes variables in. Both were preserved here; only the second one moved pixels.

The dependency plan is covered too: add installs dependencies first and the requested item last, so the record has to accumulate across items rather than be rewritten per item. Two tests pin that — every item keeps its record entry, and an edit to one item survives while another updates normally.

Running add again overwrote whatever was on disk, so a project that had tuned
an installed block lost that work without being asked or told.

The installer now records a hash of each file as it installs it, and compares
before writing. A file that still matches is replaced as before; one that does
not is left alone and reported. A file we have no record of counts as changed,
which covers both a project that wrote the file itself and one that installed
before the record existed.

--force restores the old behaviour for when you do want the registry's version.
@miguel-heygen
miguel-heygen merged commit 0c33b2d into main Aug 10, 2026
7 checks passed
@miguel-heygen
miguel-heygen deleted the feat/add-preserves-local-edits branch August 10, 2026 23:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant