view shell live code: a patch carries new Swift files

Merged
TE
2d ago
+61-14

Leo (2026-11-04): "Couldn't we architect stuff to make everything more amenable to hot swappage? Bridge better api better thin the layer nicer / Idk how well we can pre prepare stored properties/function signatures/deal with files"

This is the "new files" piece of that: a new Swift file no longer forces a rebuild of the view shell. In the 8,315-PR sample, 41% of the PRs that needed a rebuild added a file.

What changes

  • Prototypes/ViewShell/inject.sh: besides the files named, the patch now links two kinds of file:

    • every Swift file of the module that the running Debug build never compiled (it has no object in ViewShell.build): a new file;
    • every file newer than that build's executable.

    It prints also X.swift (new since the build | changed since the build) for each one. So a new view in a new file, used from an edited file, links inside the patch. Each repeat patch holds all of the new code, so callers never keep an earlier patch's copy of the new file. main.swift and LiveCode.swift still refuse. With no Debug build at .build/debug (or CMUX_VIEW_SHELL_BUILD), the patch holds only the files named, as before, and the script says so.

  • scripts/cmux-next/live_apply.py (try-pr's classifier): an added Swift file no longer counts as a rebuild. An added main.swift or @main is the exception and counts as new entry point. New types in existing files keep their rebuild reason.

  • scripts/measure/live-code-shell.sh: a new step 3 writes LiveCodeProbeDot.swift, has Badge.swift use it, and injects naming only Badge.swift. The stored-property step becomes step 4. result.json gains new_file_edit and new_file_edit_to_pixels_s.

  • Docs: the view shell README ("Live code") and docs/cmux-next/hot-reload.md.

Verification

  • python3 -m unittest scripts/cmux-next/tests/test_live_apply.py: 12 tests pass, including the new-file test and the @main one.
  • On a fleet Mac, scripts/measure/live-code-shell.sh was run at this head and at its base (4546c99a, which has the #35850 pointer fix but the old inject.sh). Both ran on the same machine. Rendered badge widths at 2×:
stepbasethis PR
0, the build135 px135 px
1, padding 24, red199 px199 px
2, padding 40263 px263 px
3, a new file LiveCodeProbeDot.swift used by Badge.swift; only Badge.swift namedrefused: dlopen … symbol not found … LiveCodeProbeDot…also LiveCodeProbeDot.swift (new since the build), 283 px with the dot, 1.26 s from edit to pixels
4, a new @Staterefusedrefused by the layout check
  • A file counts as new when the Debug build has no object for it (ViewShell.build/<name>.swift.o). An earlier version read SwiftPM's sources list, but that list quotes a path with a space, which made every file look new.

Part of manaflow-ai/cmuxterm-hq#7066.

🤖 Generated with Claude Code
Agent session: agent session