Introduces sdkCutoverPersist(): when STUDIO_SDK_CUTOVER_ENABLED is set,
inline-style PatchOps are routed through the SDK session's in-memory document
model instead of the server patch-element API. The SDK serialize() result is
written back through the same writeProjectFile + editHistory.recordEdit path,
so the on-disk output is identical to the legacy route.
- packages/studio/src/utils/sdkCutover.ts (new): sdkCutoverPersist() +
shouldUseSdkCutover() guard; domEditSaveTimestampRef.current is stamped on
each write to suppress the echo file-change reload.
- packages/studio/src/components/editor/manualEditingAvailability.ts: adds
STUDIO_SDK_CUTOVER_ENABLED flag (default false); changes
STUDIO_SDK_SHADOW_ENABLED default to false now that cutover is available.
- packages/studio/src/hooks/useSdkSession.ts: adds optional
domEditSaveTimestampRef param; self-write suppress window (SELF_WRITE_SUPPRESS_MS)
gates file-change reloads so SDK writes don't echo back as external edits.
- packages/studio/src/App.tsx: passes domEditSaveTimestampRef to useSdkSession
so the suppress window can gate reloads triggered by SDK cutover writes.
- Test coverage: sdkCutover.test.ts (new, 141 lines) + useDomEditSession.test.ts
(new, 50 lines) — guard function + happy-path assertions.
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>