Skip to content

Add build system integration (SPM) with tiered compilation#3

Merged
obj-p merged 3 commits intomainfrom
build-system-integration
Mar 19, 2026
Merged

Add build system integration (SPM) with tiered compilation#3
obj-p merged 3 commits intomainfrom
build-system-integration

Conversation

@obj-p
Copy link
Copy Markdown
Owner

@obj-p obj-p commented Mar 19, 2026

Summary

  • Extensible BuildSystem protocol with SPM implementation (auto-detects Package.swift)
  • Tiered compilation: Tier 1 (bridge-only, no hot-reload) and Tier 2 (compile all target sources with ThunkGenerator, literal hot-reload works)
  • --platform ios-simulator and --device flags on run/snapshot CLI commands
  • Auto-detect build system for all commands (CLI + MCP preview_start)
  • examples/spm/ — ToDo list app for integration testing (macOS + iOS, cross-file type dependency)

Test plan

  • 34/34 unit tests pass (swift test --filter PreviewsCoreTests)
  • Agent integration test: macOS rendering, iOS rendering, tap, swipe, toggle, literal hot-reload, structural hot-reload — all pass
  • Xcode previews work on the example project
  • Standalone file regression — existing behavior unchanged

🤖 Generated with Claude Code

Extensible BuildSystem protocol with SPM implementation. Supports two tiers:
- Tier 1 (bridge-only): import target module, no hot-reload
- Tier 2 (source compilation): compile all target files with ThunkGenerator
  transforms on the preview file, enabling literal hot-reload

New files:
- BuildContext, BuildSystem protocol, SPMBuildSystem (auto-detects Package.swift)
- BridgeGenerator: generateBridgeOnlySource (Tier 1), generateOverlaySource (Tier 2)
- BuildSystemTests (8 tests)
- examples/spm/ — ToDo list app for integration testing (macOS + iOS)

CLI changes:
- --platform ios-simulator and --device flags on run/snapshot commands
- Auto-detect build system for all commands (CLI + MCP)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Comment thread examples/spm/Sources/ToDo/Item.swift Outdated
- FileWatcher: support multiple file paths (polls all, fires on any change)
- HostApp.watchFile: accept additionalPaths + buildContext for project mode
- MCP/CLI: pass all target source paths to file watcher
- BridgeGenerator: use @testable import for internal type access (Tier 1)
- Add docs/build-system-integration.md: architecture, interfaces, Xcode trace findings

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@obj-p obj-p force-pushed the build-system-integration branch from 421c5c6 to e369463 Compare March 19, 2026 04:23
…, SDK caching

- Implement --project/projectPath: BuildSystemDetector.detect(for:projectRoot:)
  uses explicit root when provided, skipping auto-detection
- CLIPlatform enum replaces raw String for --platform (ArgumentParser validation)
- RunCommand.runIOS: add FileWatcher for hot-reload (was missing vs MCP path)
- SPMBuildSystem: resolve iOS SDK path once, pass to both build and showBinPath
- Add multi-path FileWatcher test

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@obj-p obj-p merged commit 0a73b0c into main Mar 19, 2026
1 check passed
@obj-p obj-p deleted the build-system-integration branch March 19, 2026 04:43
obj-p added a commit that referenced this pull request Apr 10, 2026
…vention

The example's Package.resolved has never been committed across the repo's
history (checked via git log --all -- examples/spm/Package.resolved) —
not since the original SPM example in #3, nor through #75 which just added
a new remote dependency on lottie-spm. Meanwhile the root /Package.resolved
IS tracked, and CI hashes only the root one (.github/workflows/ci.yml).

The rationale is that examples/spm is a testbed for PreviewsMCP's SPM
build system. Leaving its Package.resolved unpinned means every fresh
checkout / CI run exercises a fresh dependency resolution, so upstream
breakage in deps like lottie-spm surfaces promptly instead of being
masked by pinned versions.

Previously this convention was implicit — the file was just left
untracked, polluting every `git status`. Make it explicit with a scoped
gitignore entry (the specific path, not a blanket `Package.resolved`
that would also affect the tracked root file) and a comment documenting
the rationale.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
obj-p added a commit that referenced this pull request Apr 23, 2026
ROOT CAUSE #3 of the IOSMCPTests.fullIOSWorkflow 20-minute hang:

When simctl io screenshot on PR #141 CI got stuck waiting for a
display subsystem that never attached, it ignored the SIGTERM from
our 180s `AsyncProcessTimeout` entirely — the kernel syscall it was
in wasn't interruptible via the term signal. The child's pipe-write
fds stayed open, the background readDataToEndOfFile threads
blocked on an EOF that never arrived, and our subsequent
pipeGroup.wait() hung indefinitely — right past the test's 20-min
.timeLimit.

Fix:
- After SIGTERM, schedule a SIGKILL on a 2s delay (unignorable; the
  kernel reaps the process and closes its fds).
- Bound pipeGroup.wait() at 10s so a totally-stuck fd can never
  strand the continuation. Whatever bytes we drained pre-kill are
  still attached to the thrown AsyncProcessTimeout error for
  diagnostics.

All existing AsyncProcessTests still pass (verified locally).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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