nudge-ui 0.2.4 → 0.2.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (250) hide show
  1. package/dist/cli/agentCommand.js +4 -28
  2. package/dist/client.mjs +863 -213
  3. package/dist/hosts/next/wrapper.js +1 -7
  4. package/dist/hosts/projectBridge.js +3 -17
  5. package/dist/inspector/agent/McpConnectionDialog.js +7 -3
  6. package/dist/inspector/agent/activity.d.ts +1 -1
  7. package/dist/inspector/agent/activity.js +3 -2
  8. package/dist/inspector/agent/client.d.ts +2 -2
  9. package/dist/inspector/agent/client.js +28 -29
  10. package/dist/inspector/agent/connectionStatus.d.ts +3 -1
  11. package/dist/inspector/agent/connectionStatus.js +25 -0
  12. package/dist/inspector/agent/httpTransport.js +31 -147
  13. package/dist/inspector/agent/protocol.d.ts +1 -1
  14. package/dist/inspector/agent/protocol.js +1 -1
  15. package/dist/inspector/agent/verification.d.ts +1 -1
  16. package/dist/inspector/agent/verification.js +7 -4
  17. package/dist/inspector/boot.d.ts +3 -0
  18. package/dist/inspector/boot.js +297 -0
  19. package/dist/inspector/canvas/AgentActivityOverlay.d.ts +2 -1
  20. package/dist/inspector/canvas/AgentActivityOverlay.js +6 -3
  21. package/dist/inspector/canvas/CanvasCard.js +21 -12
  22. package/dist/inspector/canvas/CanvasElementOverlay.js +82 -127
  23. package/dist/inspector/canvas/CanvasToolbar.js +2 -1
  24. package/dist/inspector/canvas/CanvasWorkspace.js +74 -97
  25. package/dist/inspector/canvas/LockedWorkspaceNotice.d.ts +3 -2
  26. package/dist/inspector/canvas/LockedWorkspaceNotice.js +10 -6
  27. package/dist/inspector/canvas/PageCard.d.ts +10 -0
  28. package/dist/inspector/canvas/PageCard.js +51 -0
  29. package/dist/inspector/canvas/SketchToolOptions.d.ts +5 -0
  30. package/dist/inspector/canvas/SketchToolOptions.js +86 -0
  31. package/dist/inspector/canvas/StaleChangeIndicator.d.ts +1 -1
  32. package/dist/inspector/canvas/StaleChangeIndicator.js +1 -1
  33. package/dist/inspector/canvas/ToolOptionsDrawer.d.ts +21 -0
  34. package/dist/inspector/canvas/ToolOptionsDrawer.js +77 -0
  35. package/dist/inspector/canvas/activeCanvasDocument.d.ts +3 -2
  36. package/dist/inspector/canvas/assets/eraser.svg +28 -0
  37. package/dist/inspector/canvas/assets/pen.svg +25 -0
  38. package/dist/inspector/canvas/canvasFrame.d.ts +16 -0
  39. package/dist/inspector/canvas/canvasFrame.js +10 -0
  40. package/dist/inspector/canvas/canvasGestures.d.ts +0 -1
  41. package/dist/inspector/canvas/canvasGestures.js +0 -6
  42. package/dist/inspector/canvas/canvasStore.d.ts +6 -0
  43. package/dist/inspector/canvas/canvasStore.js +36 -1
  44. package/dist/inspector/canvas/frameConnection.d.ts +48 -0
  45. package/dist/inspector/canvas/frameConnection.js +73 -0
  46. package/dist/inspector/canvas/frameProtocol.d.ts +18 -1
  47. package/dist/inspector/canvas/frameProtocol.js +36 -0
  48. package/dist/inspector/canvas/pageSurface.d.ts +11 -0
  49. package/dist/inspector/canvas/pageSurface.js +34 -0
  50. package/dist/inspector/canvas/projection.d.ts +19 -9
  51. package/dist/inspector/canvas/projection.js +58 -31
  52. package/dist/inspector/canvas/rendererBootstrap.js +4 -1
  53. package/dist/inspector/canvas/rendererElementSelector.js +9 -1
  54. package/dist/inspector/canvas/rendererMessageRouter.d.ts +4 -5
  55. package/dist/inspector/canvas/rendererMessageRouter.js +12 -16
  56. package/dist/inspector/canvas/rendererSelectionProxy.d.ts +7 -1
  57. package/dist/inspector/canvas/rendererSelectionProxy.js +8 -36
  58. package/dist/inspector/canvas/rendererStylesheet.js +15 -0
  59. package/dist/inspector/canvas/sessionStore.d.ts +2 -2
  60. package/dist/inspector/canvas/sessionStore.js +12 -9
  61. package/dist/inspector/canvas/staleChangeDetector.d.ts +1 -1
  62. package/dist/inspector/canvas/staleChangeDetector.js +10 -22
  63. package/dist/inspector/changes/codecs.d.ts +1 -0
  64. package/dist/inspector/changes/codecs.js +20 -5
  65. package/dist/inspector/changes/draftPreview.d.ts +12 -0
  66. package/dist/inspector/changes/draftPreview.js +133 -0
  67. package/dist/inspector/changes/editModel.d.ts +8 -0
  68. package/dist/inspector/changes/editModel.js +8 -2
  69. package/dist/inspector/changes/managedStyleProjection.js +2 -1
  70. package/dist/inspector/changes/previewDiagnostics.js +1 -1
  71. package/dist/inspector/changes/types.d.ts +11 -1
  72. package/dist/inspector/comments/CommentsOverlay.js +18 -16
  73. package/dist/inspector/comments/store.js +3 -2
  74. package/dist/inspector/comments/verification.js +1 -1
  75. package/dist/inspector/componentSemantics/ComponentPropsSection.js +2 -1
  76. package/dist/inspector/componentSemantics/changeAction.js +1 -1
  77. package/dist/inspector/componentSemantics/textBinding.d.ts +1 -2
  78. package/dist/inspector/componentSemantics/textBinding.js +4 -45
  79. package/dist/inspector/drafts/draftStore.d.ts +109 -0
  80. package/dist/inspector/drafts/draftStore.js +451 -0
  81. package/dist/inspector/drafts/model.d.ts +9 -1
  82. package/dist/inspector/drafts/model.js +5 -1
  83. package/dist/inspector/drafts/store.d.ts +53 -15
  84. package/dist/inspector/drafts/store.js +143 -169
  85. package/dist/inspector/index.d.ts +2 -4
  86. package/dist/inspector/index.js +2 -264
  87. package/dist/inspector/inline-text/inlineTextEditor.d.ts +1 -1
  88. package/dist/inspector/inline-text/inlineTextEditor.js +1 -2
  89. package/dist/inspector/inline-text/textEditChange.d.ts +1 -1
  90. package/dist/inspector/inspection/bridge.d.ts +1 -1
  91. package/dist/inspector/inspection/bridge.js +2 -1
  92. package/dist/inspector/inspection/browserCssInspection.d.ts +8 -0
  93. package/dist/inspector/inspection/browserCssInspection.js +28 -6
  94. package/dist/inspector/inspection/inspectionSnapshot.d.ts +6 -0
  95. package/dist/inspector/inspection/inspectionSnapshot.js +10 -0
  96. package/dist/inspector/inspection/performanceDiagnostics.d.ts +18 -0
  97. package/dist/inspector/inspection/performanceDiagnostics.js +31 -0
  98. package/dist/inspector/inspection/useBrowserCssInspection.js +17 -38
  99. package/dist/inspector/iterations/capture.d.ts +2 -1
  100. package/dist/inspector/iterations/client.d.ts +2 -1
  101. package/dist/inspector/iterations/coordinator.d.ts +4 -3
  102. package/dist/inspector/iterations/coordinator.js +5 -3
  103. package/dist/inspector/iterations/prompt.js +9 -8
  104. package/dist/inspector/overlay/interactionStyles.js +17 -0
  105. package/dist/inspector/pageInspector.d.ts +42 -0
  106. package/dist/inspector/pageInspector.js +342 -0
  107. package/dist/inspector/projection/draftProjection.d.ts +10 -2
  108. package/dist/inspector/projection/draftProjection.js +9 -1
  109. package/dist/inspector/projection/managedStylesheet.js +24 -4
  110. package/dist/inspector/projection/renderedInstance.js +7 -1
  111. package/dist/inspector/projection/structuralProjection.d.ts +0 -9
  112. package/dist/inspector/projection/structuralProjection.js +14 -44
  113. package/dist/inspector/projection/textProjection.d.ts +8 -2
  114. package/dist/inspector/projection/textProjection.js +21 -13
  115. package/dist/inspector/prompt/clipboardHandoff.d.ts +9 -0
  116. package/dist/inspector/prompt/clipboardHandoff.js +42 -16
  117. package/dist/inspector/prompt/generatePrompt.d.ts +1 -1
  118. package/dist/inspector/prompt/generatePrompt.js +243 -147
  119. package/dist/inspector/prompt/promptDocument.d.ts +3 -0
  120. package/dist/inspector/prompt/promptDocument.js +8 -0
  121. package/dist/inspector/prompt/promptSettings.js +7 -5
  122. package/dist/inspector/runtime/inspectorStorage.d.ts +17 -0
  123. package/dist/inspector/runtime/inspectorStorage.js +42 -0
  124. package/dist/inspector/runtime/ownedStylesheets.d.ts +20 -0
  125. package/dist/inspector/runtime/ownedStylesheets.js +72 -0
  126. package/dist/inspector/runtime/runtimeConfig.d.ts +4 -0
  127. package/dist/inspector/runtime/runtimeConfig.js +10 -1
  128. package/dist/inspector/runtime/runtimeIdentityClaims.d.ts +29 -0
  129. package/dist/inspector/runtime/runtimeIdentityClaims.js +188 -0
  130. package/dist/inspector/runtime/staticHtmlRuntimeIdentity.d.ts +15 -0
  131. package/dist/inspector/runtime/staticHtmlRuntimeIdentity.js +113 -29
  132. package/dist/inspector/selection/editScope.d.ts +1 -0
  133. package/dist/inspector/selection/editScope.js +13 -2
  134. package/dist/inspector/shell/AgentStatusButton.js +2 -2
  135. package/dist/inspector/shell/AppShell.js +6 -2
  136. package/dist/inspector/shell/ChangesLog.js +27 -9
  137. package/dist/inspector/shell/CopyPromptButton.js +60 -54
  138. package/dist/inspector/shell/EmptyState.js +3 -3
  139. package/dist/inspector/shell/InspectorShell.d.ts +0 -3
  140. package/dist/inspector/shell/InspectorShell.js +21 -13
  141. package/dist/inspector/shell/PeekOriginalButton.js +3 -3
  142. package/dist/inspector/shell/interactionStatePreview.d.ts +9 -0
  143. package/dist/inspector/shell/interactionStatePreview.js +112 -0
  144. package/dist/inspector/shell/originalPreview.d.ts +3 -2
  145. package/dist/inspector/shell/originalPreview.js +10 -37
  146. package/dist/inspector/shell/stateValue.js +2 -3
  147. package/dist/inspector/sketch/SketchEditor.js +5 -4
  148. package/dist/inspector/sketch/SketchFrameOverlay.d.ts +2 -1
  149. package/dist/inspector/sketch/SketchFrameOverlay.js +5 -4
  150. package/dist/inspector/sketch/SketchOverlay.d.ts +3 -5
  151. package/dist/inspector/sketch/SketchOverlay.js +139 -263
  152. package/dist/inspector/sketch/SketchPromptPanel.d.ts +1 -1
  153. package/dist/inspector/sketch/SketchPromptPanel.js +8 -1
  154. package/dist/inspector/sketch/SketchThumbnail.d.ts +5 -0
  155. package/dist/inspector/sketch/SketchThumbnail.js +18 -0
  156. package/dist/inspector/sketch/SketchWorkspace.d.ts +1 -2
  157. package/dist/inspector/sketch/SketchWorkspace.js +69 -34
  158. package/dist/inspector/sketch/capture.js +19 -3
  159. package/dist/inspector/sketch/copySketch.d.ts +10 -0
  160. package/dist/inspector/sketch/copySketch.js +52 -0
  161. package/dist/inspector/sketch/drawingTools.d.ts +17 -0
  162. package/dist/inspector/sketch/drawingTools.js +47 -0
  163. package/dist/inspector/sketch/frameHeading.d.ts +9 -0
  164. package/dist/inspector/sketch/frameHeading.js +30 -0
  165. package/dist/inspector/sketch/freehand.js +3 -3
  166. package/dist/inspector/sketch/geometry.d.ts +6 -0
  167. package/dist/inspector/sketch/geometry.js +19 -0
  168. package/dist/inspector/sketch/history.d.ts +30 -0
  169. package/dist/inspector/sketch/history.js +58 -0
  170. package/dist/inspector/sketch/interaction.d.ts +1 -3
  171. package/dist/inspector/sketch/interaction.js +6 -9
  172. package/dist/inspector/sketch/model.d.ts +35 -1
  173. package/dist/inspector/sketch/model.js +116 -61
  174. package/dist/inspector/sketch/persistence.d.ts +14 -0
  175. package/dist/inspector/sketch/persistence.js +63 -7
  176. package/dist/inspector/sketch/raster.d.ts +6 -2
  177. package/dist/inspector/sketch/raster.js +43 -17
  178. package/dist/inspector/sketch/store.d.ts +1 -1
  179. package/dist/inspector/sketch/store.js +1 -1
  180. package/dist/inspector/sketch/videoFrames.d.ts +6 -0
  181. package/dist/inspector/sketch/videoFrames.js +81 -0
  182. package/dist/inspector/styleEditors/BackgroundEditor.js +2 -1
  183. package/dist/inspector/styleEditors/BorderEditor.js +30 -130
  184. package/dist/inspector/styleEditors/BorderRadiusEditor.js +8 -3
  185. package/dist/inspector/styleEditors/ImageBackgroundEditor.js +1 -1
  186. package/dist/inspector/styleEditors/LayoutSection.js +2 -2
  187. package/dist/inspector/styleEditors/borderModel.d.ts +42 -0
  188. package/dist/inspector/styleEditors/borderModel.js +114 -0
  189. package/dist/inspector/styleEditors/layoutValue.js +2 -3
  190. package/dist/inspector/tokens/TokenField.js +34 -3
  191. package/dist/inspector/tokens/TokensPanel.js +2 -1
  192. package/dist/inspector/tokens/editActions.d.ts +3 -3
  193. package/dist/inspector/tokens/editActions.js +9 -3
  194. package/dist/inspector/tokens/resolution/containerQueryEvaluator.d.ts +15 -0
  195. package/dist/inspector/tokens/resolution/containerQueryEvaluator.js +86 -0
  196. package/dist/inspector/tokens/resolution/cssomCollector.js +44 -9
  197. package/dist/inspector/tokens/resolution/nestedSelectors.d.ts +6 -0
  198. package/dist/inspector/tokens/resolution/nestedSelectors.js +67 -0
  199. package/dist/inspector/tokens/resolution/ruleMatching.js +23 -4
  200. package/dist/inspector/tokens/resolution.d.ts +6 -3
  201. package/dist/inspector/tokens/resolution.js +91 -112
  202. package/dist/inspector/tokens/tokenEdits.d.ts +1 -1
  203. package/dist/inspector/tokens/tokenEdits.js +1 -1
  204. package/dist/inspector/ui/InlineStyleWarning.js +2 -2
  205. package/dist/inspector/ui/InspectorStyle.d.ts +8 -0
  206. package/dist/inspector/ui/InspectorStyle.js +26 -0
  207. package/dist/inspector/ui/PopoverListbox.d.ts +2 -1
  208. package/dist/inspector/ui/PopoverListbox.js +3 -3
  209. package/dist/inspector/ui/Toast.d.ts +14 -0
  210. package/dist/inspector/ui/Toast.js +30 -0
  211. package/dist/inspector/ui/assets/canvasIllustration.d.ts +2 -0
  212. package/dist/inspector/ui/assets/canvasIllustration.js +21 -0
  213. package/dist/inspector/ui/assets/gridIllustration.d.ts +2 -0
  214. package/dist/inspector/ui/assets/{grid.svg → gridIllustration.js} +3 -2
  215. package/dist/inspector/ui/customCursors.d.ts +5 -0
  216. package/dist/inspector/ui/customCursors.js +32 -6
  217. package/dist/inspector/ui/styles.js +12 -10
  218. package/dist/inspector/workspace/commands.js +1 -2
  219. package/dist/inspector/workspace/controller.js +1 -2
  220. package/dist/inspector/workspace/handoff.js +3 -2
  221. package/dist/inspector/workspace/sentItems.d.ts +3 -6
  222. package/dist/inspector/workspace/sentItems.js +6 -24
  223. package/dist/inspector/workspace/timeline.d.ts +24 -10
  224. package/dist/inspector/workspace/timeline.js +118 -96
  225. package/dist/internal/agent-protocol.d.ts +50 -13
  226. package/dist/internal/agent-protocol.js +145 -19
  227. package/dist/nudge-ui.mjs +81 -65
  228. package/dist/project/mcpPackage.d.ts +8 -0
  229. package/dist/project/mcpPackage.js +60 -0
  230. package/package.json +12 -2
  231. package/dist/inspector/canvas/measurementProjection.d.ts +0 -8
  232. package/dist/inspector/canvas/measurementProjection.js +0 -16
  233. package/dist/inspector/changes/changesLog.d.ts +0 -49
  234. package/dist/inspector/changes/changesLog.js +0 -255
  235. package/dist/inspector/changes/draftChanges.d.ts +0 -58
  236. package/dist/inspector/changes/draftChanges.js +0 -304
  237. package/dist/inspector/conformance/projection.d.ts +0 -2
  238. package/dist/inspector/conformance/projection.js +0 -3
  239. package/dist/inspector/inline-text/textChangeBoundary.d.ts +0 -6
  240. package/dist/inspector/inline-text/textChangeBoundary.js +0 -1
  241. package/dist/inspector/overlay/InspectorOverlay.d.ts +0 -5
  242. package/dist/inspector/overlay/InspectorOverlay.js +0 -332
  243. package/dist/inspector/overlay/elementSelector.d.ts +0 -1
  244. package/dist/inspector/overlay/elementSelector.js +0 -111
  245. package/dist/inspector/sketch/SketchChanges.d.ts +0 -2
  246. package/dist/inspector/sketch/SketchChanges.js +0 -72
  247. package/dist/inspector/sketch/SketchEntryButton.d.ts +0 -4
  248. package/dist/inspector/sketch/SketchEntryButton.js +0 -11
  249. package/dist/inspector/sketch/SketchLayersPanel.d.ts +0 -2
  250. package/dist/inspector/sketch/SketchLayersPanel.js +0 -71
@@ -0,0 +1,342 @@
1
+ /**
2
+ * Entry for loading the inspector into any page without a host Adapter.
3
+ *
4
+ * Everything a host normally supplies is derived from the live document:
5
+ * runtime identity is assigned lazily under the pointer, and tokens come from
6
+ * readable stylesheets plus the root's computed custom properties. Source
7
+ * locations, component semantics, iterations, and the agent bridge are
8
+ * unavailable. In editor mode the application runs in Canvas frames;
9
+ * otherwise the page itself is the only Canvas card.
10
+ */
11
+ import { bootstrapNudgeUi, configureNudgeUiRuntime, getNudgeUiRuntimeConfig, isCanvasRenderer, readNudgeUiEditorTarget, setInspectorOpen, unmountInspector, } from "./index.js";
12
+ import { CANVAS_RENDERER_ATTR } from "./canvas/roleDetection.js";
13
+ import { releaseLease } from "./canvas/workspaceLease.js";
14
+ import { enablePageSurface } from "./canvas/pageSurface.js";
15
+ import { setNudgeUiHostDevFlag } from "./runtime/devFlag.js";
16
+ import { configureInspectorStorage } from "./runtime/inspectorStorage.js";
17
+ import { configureSketchStorage } from "./sketch/persistence.js";
18
+ import { preferAdoptedStylesheets } from "./runtime/ownedStylesheets.js";
19
+ import { enableInspectionPerformanceDiagnostics } from "./inspection/performanceDiagnostics.js";
20
+ import { installLazyRuntimeIdentity } from "./runtime/staticHtmlRuntimeIdentity.js";
21
+ import { createTokenInventory } from "../css/token-inventory/inventory.js";
22
+ export { createMirroredStorage } from "./runtime/inspectorStorage.js";
23
+ const MOUNT_ID = "nudge-ui-root";
24
+ const LOADED_FLAG = "__NUDGE_UI_PAGE_INSPECTOR__";
25
+ const COMPUTED_ROOT_ID = "computed:root";
26
+ function isNudgeOwnedSheet(sheet) {
27
+ const owner = sheet.ownerNode;
28
+ return owner instanceof Element && owner.hasAttribute("data-nudge-ui");
29
+ }
30
+ function sheetId(sheet, index, base) {
31
+ const owner = sheet.ownerNode;
32
+ const viteId = owner instanceof HTMLElement ? owner.dataset.viteDevId : undefined;
33
+ if (viteId)
34
+ return viteId;
35
+ if (sheet.href) {
36
+ const url = new URL(sheet.href, base);
37
+ return url.origin === new URL(base).origin ? url.pathname : url.href;
38
+ }
39
+ return `inline-style-${index + 1}`;
40
+ }
41
+ function serializeRules(sheet) {
42
+ return Array.from(sheet.cssRules, (rule) => rule.cssText).join("\n");
43
+ }
44
+ async function collectSheet(sheet, index, base) {
45
+ const id = sheetId(sheet, index, base);
46
+ try {
47
+ return { id, content: serializeRules(sheet) };
48
+ }
49
+ catch {
50
+ if (!sheet.href)
51
+ return { id, readError: "stylesheet rules are not readable" };
52
+ }
53
+ try {
54
+ const response = await fetch(sheet.href, { mode: "cors", credentials: "omit" });
55
+ if (!response.ok)
56
+ return { id, readError: `HTTP ${response.status}` };
57
+ return { id, content: await response.text() };
58
+ }
59
+ catch {
60
+ return { id, readError: "cross-origin stylesheet without CORS access" };
61
+ }
62
+ }
63
+ /**
64
+ * Custom properties visible on the root element but absent from readable
65
+ * stylesheets: definitions in cross-origin sheets without CORS, scoped theme
66
+ * rules the inventory rejects, or variables set from JavaScript.
67
+ */
68
+ function computedRootDeclarations(doc, definedNames) {
69
+ const declarations = [];
70
+ const view = doc.defaultView ?? window;
71
+ for (const element of [doc.documentElement, doc.body]) {
72
+ if (!element)
73
+ continue;
74
+ const style = view.getComputedStyle(element);
75
+ for (let index = 0; index < style.length; index += 1) {
76
+ const name = style.item(index);
77
+ if (!name.startsWith("--") || definedNames.has(name))
78
+ continue;
79
+ const value = style.getPropertyValue(name).trim();
80
+ if (!value)
81
+ continue;
82
+ definedNames.add(name);
83
+ declarations.push(` ${name}: ${value};`);
84
+ }
85
+ }
86
+ return declarations.length > 0 ? `:root {\n${declarations.join("\n")}\n}` : null;
87
+ }
88
+ function mapDiagnostic(diagnostic) {
89
+ return {
90
+ code: diagnostic.code,
91
+ message: diagnostic.message,
92
+ module: diagnostic.module ?? diagnostic.artifact ?? "document",
93
+ ...(diagnostic.exportName !== undefined ? { exportName: diagnostic.exportName } : {}),
94
+ };
95
+ }
96
+ async function collectDocumentTokens(doc) {
97
+ const sheets = Array.from(doc.styleSheets).filter((sheet) => !isNudgeOwnedSheet(sheet));
98
+ const collected = await Promise.all(sheets.map((sheet, index) => collectSheet(sheet, index, doc.location.href)));
99
+ const inventory = createTokenInventory();
100
+ for (const [order, sheet] of collected.entries()) {
101
+ const artifact = {
102
+ buildTool: "browser",
103
+ id: sheet.id,
104
+ stage: "authored",
105
+ provenance: "project",
106
+ order,
107
+ ...(sheet.content !== undefined ? { content: sheet.content } : {}),
108
+ ...(sheet.readError ? {
109
+ diagnostics: [{
110
+ code: "stylesheet-unreadable",
111
+ message: `Stylesheet "${sheet.id}" could not be read: ${sheet.readError}`,
112
+ module: sheet.id,
113
+ }],
114
+ } : {}),
115
+ };
116
+ inventory.apply(artifact);
117
+ }
118
+ const definedNames = new Set(inventory.snapshot().definitions.map((definition) => definition.cssName));
119
+ const computed = computedRootDeclarations(doc, definedNames);
120
+ if (computed) {
121
+ inventory.apply({
122
+ buildTool: "browser",
123
+ id: COMPUTED_ROOT_ID,
124
+ stage: "authored",
125
+ provenance: "project",
126
+ order: -1,
127
+ content: computed,
128
+ });
129
+ }
130
+ const snapshot = inventory.snapshot();
131
+ return {
132
+ tokenCatalog: snapshot.definitions.map((definition) => ({
133
+ ...definition,
134
+ declarations: definition.declarations.map((declaration) => ({
135
+ id: declaration.id,
136
+ order: declaration.order,
137
+ value: declaration.value,
138
+ source: declaration.source,
139
+ important: declaration.important,
140
+ context: declaration.context,
141
+ })),
142
+ })),
143
+ tokens: snapshot.tokens,
144
+ tokenDiagnostics: snapshot.diagnostics.map(mapDiagnostic),
145
+ tokenGeneration: `browser:${snapshot.generation}`,
146
+ };
147
+ }
148
+ const NO_TOKENS = { tokenCatalog: [], tokens: [], tokenDiagnostics: [], tokenGeneration: "" };
149
+ function runtimeConfig(tokens, unavailableReason) {
150
+ return {
151
+ projectId: `page:${location.origin}`,
152
+ host: "static-html",
153
+ framework: "HTML",
154
+ stylingSystem: "CSS custom properties",
155
+ capabilities: { canvas: !unavailableReason, componentSemantics: false, domNavigation: !unavailableReason },
156
+ features: { canvasIterations: false, ...(unavailableReason ? { sketch: false } : {}) },
157
+ ...(unavailableReason ? { inspectionUnavailableReason: unavailableReason } : {}),
158
+ componentContracts: [],
159
+ ...tokens,
160
+ };
161
+ }
162
+ function createMount() {
163
+ const mount = document.createElement("div");
164
+ mount.id = MOUNT_ID;
165
+ document.body.append(mount);
166
+ return mount;
167
+ }
168
+ /** Mounts the inspector and returns a toggle that fully unmounts and remounts it. */
169
+ function mountPageInspector() {
170
+ let mount = null;
171
+ let removeIdentityListeners = null;
172
+ const enable = () => {
173
+ setNudgeUiHostDevFlag(true);
174
+ removeIdentityListeners = installLazyRuntimeIdentity(document);
175
+ mount = createMount();
176
+ bootstrapNudgeUi(mount);
177
+ setInspectorOpen(true);
178
+ };
179
+ const disable = (target) => {
180
+ unmountInspector();
181
+ removeIdentityListeners?.();
182
+ removeIdentityListeners = null;
183
+ releaseLease();
184
+ setInspectorOpen(false);
185
+ setNudgeUiHostDevFlag(false);
186
+ target.remove();
187
+ mount = null;
188
+ };
189
+ enable();
190
+ return () => {
191
+ if (mount)
192
+ disable(mount);
193
+ else
194
+ enable();
195
+ };
196
+ }
197
+ /**
198
+ * Replaces the page's content with the iframe editor. The application runs in
199
+ * Canvas renderer frames, which the caller loads the inspector into.
200
+ */
201
+ function mountEditor(onRendererFrameLoad) {
202
+ document.head.replaceChildren();
203
+ document.body.replaceChildren();
204
+ for (const element of [document.documentElement, document.body]) {
205
+ element.removeAttribute("style");
206
+ element.removeAttribute("hidden");
207
+ element.removeAttribute("inert");
208
+ }
209
+ document.title = "Nudge UI";
210
+ const layout = new CSSStyleSheet();
211
+ layout.replaceSync(`html, body, #${MOUNT_ID} { display: block; width: 100%; height: 100%; margin: 0; overflow: hidden; }`);
212
+ document.adoptedStyleSheets = [layout];
213
+ // A parsed meta policy remains active even after the original head is removed.
214
+ document.addEventListener("securitypolicyviolation", (event) => {
215
+ if (event.disposition !== "enforce" || event.effectiveDirective !== "frame-src")
216
+ return;
217
+ if (getNudgeUiRuntimeConfig().inspectionUnavailableReason)
218
+ return;
219
+ configureNudgeUiRuntime(runtimeConfig(NO_TOKENS, "its security policy"));
220
+ });
221
+ setNudgeUiHostDevFlag(true);
222
+ const mount = createMount();
223
+ bootstrapNudgeUi(mount);
224
+ setInspectorOpen(true);
225
+ // Storage hydration can delay the controller mount; watch its host now.
226
+ const root = mount.shadowRoot ?? mount.attachShadow({ mode: "open" });
227
+ const frames = () => root.querySelectorAll(`iframe[${CANVAS_RENDERER_ATTR}]`);
228
+ const applicationDocument = (frame) => {
229
+ const frameDocument = frame.contentDocument;
230
+ return frameDocument && frameDocument.location.href !== "about:blank" ? frameDocument : null;
231
+ };
232
+ // A frame's `load` waits for every image, so renderers start once the DOM is ready.
233
+ const announced = new WeakSet();
234
+ const announceReadyDocuments = () => {
235
+ for (const frame of frames()) {
236
+ const frameDocument = applicationDocument(frame);
237
+ if (!frameDocument || frameDocument.readyState === "loading" || announced.has(frameDocument))
238
+ continue;
239
+ announced.add(frameDocument);
240
+ onRendererFrameLoad?.();
241
+ }
242
+ };
243
+ window.setInterval(announceReadyDocuments, 100);
244
+ // Script-built styles exist only in the application frames, not in this document.
245
+ const collectFrameTokens = (frame) => {
246
+ const frameDocument = applicationDocument(frame);
247
+ if (!frameDocument)
248
+ return;
249
+ void collectDocumentTokens(frameDocument).then((tokens) => {
250
+ if (getNudgeUiRuntimeConfig().inspectionUnavailableReason)
251
+ return;
252
+ if (tokens.tokenGeneration !== getNudgeUiRuntimeConfig().tokenGeneration) {
253
+ configureNudgeUiRuntime(runtimeConfig(tokens));
254
+ }
255
+ });
256
+ };
257
+ const watched = new WeakSet();
258
+ const watch = () => {
259
+ for (const frame of frames()) {
260
+ if (watched.has(frame))
261
+ continue;
262
+ watched.add(frame);
263
+ frame.addEventListener("load", () => collectFrameTokens(frame));
264
+ collectFrameTokens(frame);
265
+ }
266
+ };
267
+ new MutationObserver(watch).observe(root, { childList: true, subtree: true });
268
+ watch();
269
+ }
270
+ /** Leaves the editor by loading the application URL it frames. */
271
+ function exitEditor() {
272
+ location.replace(readNudgeUiEditorTarget(location.href) ?? location.href);
273
+ }
274
+ /**
275
+ * Starts the inspector on the current page. Running a second bundle copy in
276
+ * the same window toggles the first instance instead, because only the first
277
+ * copy's stores drive the UI.
278
+ */
279
+ export async function startPageInspector(options = {}) {
280
+ const target = window;
281
+ const loaded = target[LOADED_FLAG];
282
+ if (loaded) {
283
+ loaded.toggle();
284
+ return;
285
+ }
286
+ const editor = options.surface === "editor" && readNudgeUiEditorTarget(location.href) !== null;
287
+ let toggle = editor ? exitEditor : null;
288
+ target[LOADED_FLAG] = {
289
+ surface: editor ? "editor" : "page",
290
+ toggle: () => toggle?.(),
291
+ enablePerformanceDiagnostics: () => enableInspectionPerformanceDiagnostics(document),
292
+ };
293
+ if (options.storage)
294
+ configureInspectorStorage(options.storage);
295
+ if (options.sketchStorage)
296
+ configureSketchStorage(options.sketchStorage);
297
+ if (options.adoptStylesheets)
298
+ preferAdoptedStylesheets();
299
+ const tokens = options.unavailableReason ? NO_TOKENS : await collectDocumentTokens(document);
300
+ configureNudgeUiRuntime(runtimeConfig(tokens, options.unavailableReason));
301
+ if (editor) {
302
+ mountEditor(options.onRendererFrameLoad);
303
+ }
304
+ else {
305
+ if (!options.unavailableReason)
306
+ enablePageSurface();
307
+ toggle = mountPageInspector();
308
+ }
309
+ console.info(`[nudge-ui] Inspector loaded in ${editor ? "editor" : "page"} mode with ${tokens.tokenCatalog.length} tokens`
310
+ + (tokens.tokenDiagnostics.length > 0 ? ` and ${tokens.tokenDiagnostics.length} stylesheet diagnostics.` : "."), tokens.tokenDiagnostics);
311
+ }
312
+ /**
313
+ * Starts the renderer in an editor's Canvas frame. Does nothing in any other
314
+ * document, or when the frame already runs one.
315
+ */
316
+ export function startCanvasRenderer(options = {}) {
317
+ const target = window;
318
+ if (!isCanvasRenderer() || target[LOADED_FLAG])
319
+ return;
320
+ target[LOADED_FLAG] = {
321
+ surface: "renderer",
322
+ toggle: () => undefined,
323
+ enablePerformanceDiagnostics: () => enableInspectionPerformanceDiagnostics(document),
324
+ };
325
+ if (options.adoptStylesheets)
326
+ preferAdoptedStylesheets();
327
+ setNudgeUiHostDevFlag(true);
328
+ installLazyRuntimeIdentity(document);
329
+ configureNudgeUiRuntime(runtimeConfig(NO_TOKENS));
330
+ bootstrapNudgeUi(createMount());
331
+ // Renderers inspect their own elements, so they need this document's tokens.
332
+ const collectTokens = () => {
333
+ void collectDocumentTokens(document).then((tokens) => {
334
+ if (tokens.tokenGeneration !== getNudgeUiRuntimeConfig().tokenGeneration) {
335
+ configureNudgeUiRuntime(runtimeConfig(tokens));
336
+ }
337
+ });
338
+ };
339
+ collectTokens();
340
+ if (document.readyState !== "complete")
341
+ window.addEventListener("load", collectTokens, { once: true });
342
+ }
@@ -3,7 +3,8 @@ import type { RenderedInstanceOverride } from "../changes/editModel.js";
3
3
  import { type StructuralChange } from "./structuralProjection.js";
4
4
  import type { ComponentOverride } from "../componentSemantics/types.js";
5
5
  import { type TextContentChangeRecord } from "../changes/types.js";
6
- import type { DraftContents } from "../changes/draftChanges.js";
6
+ import type { DraftContents } from "../drafts/model.js";
7
+ import { type RuntimeIdentityClaim } from "../runtime/runtimeIdentityClaims.js";
7
8
  export interface DraftProjectionSource extends DraftContents {
8
9
  readonly revision: number;
9
10
  }
@@ -22,9 +23,15 @@ export interface DraftProjectionPlan<ManagedStyles> {
22
23
  readonly structuralChanges: readonly StructuralChange[];
23
24
  readonly textContentChanges: readonly TextContentChangeRecord[];
24
25
  readonly componentOverrides: readonly ComponentOverride[];
26
+ /**
27
+ * Generated identities the saved edits refer to. Omitted by plans that
28
+ * only hide edits (hold-to-view-original), which keep the attached ones.
29
+ */
30
+ readonly runtimeIdentities?: readonly RuntimeIdentityClaim[];
25
31
  }
26
32
  /** Applies every projection dimension to one document-local runtime. */
27
33
  export interface DocumentProjectionAdapter<ManagedStyles> {
34
+ applyRuntimeIdentities(claims: readonly RuntimeIdentityClaim[]): void;
28
35
  applyStructural(changes: readonly StructuralChange[]): void;
29
36
  applyRenderedInstances(overrides: readonly RenderedInstanceOverride[]): void;
30
37
  applyText(changes: readonly TextContentChangeRecord[]): void;
@@ -35,7 +42,8 @@ export declare function compileDraftProjection(snapshot: DraftProjectionSource):
35
42
  /**
36
43
  * Replaces one document projection in the required order.
37
44
  *
38
- * Structural intent is applied first because later rendered-instance evidence
45
+ * Generated identities are attached first: every selector and resolver below
46
+ * looks elements up by them. Structural intent follows because later rendered-instance evidence
39
47
  * can depend on the restored element order. Managed CSS is applied last so
40
48
  * selectors can use the document-local instance markers installed above.
41
49
  */
@@ -6,6 +6,7 @@ import { replaceComponentOverrideProjection } from "../componentSemantics/index.
6
6
  import { componentChangeToOverride } from "../componentSemantics/changeModel.js";
7
7
  import { isComponentChange } from "../changes/types.js";
8
8
  import { buildManagedStyleRules } from "../changes/managedStyleProjection.js";
9
+ import { applyRuntimeIdentityClaims, collectRuntimeIdentityClaims, } from "../runtime/runtimeIdentityClaims.js";
9
10
  export function compileDraftProjection(snapshot) {
10
11
  const changes = [...snapshot.changes];
11
12
  const rules = buildManagedStyleRules(changes);
@@ -22,16 +23,20 @@ export function compileDraftProjection(snapshot) {
22
23
  .filter(isComponentChange)
23
24
  .map(componentChangeToOverride)
24
25
  .filter((override) => override !== null),
26
+ runtimeIdentities: collectRuntimeIdentityClaims(snapshot),
25
27
  };
26
28
  }
27
29
  /**
28
30
  * Replaces one document projection in the required order.
29
31
  *
30
- * Structural intent is applied first because later rendered-instance evidence
32
+ * Generated identities are attached first: every selector and resolver below
33
+ * looks elements up by them. Structural intent follows because later rendered-instance evidence
31
34
  * can depend on the restored element order. Managed CSS is applied last so
32
35
  * selectors can use the document-local instance markers installed above.
33
36
  */
34
37
  export function applyDraftProjection(adapter, plan) {
38
+ if (plan.runtimeIdentities)
39
+ adapter.applyRuntimeIdentities(plan.runtimeIdentities);
35
40
  adapter.applyStructural(plan.structuralChanges);
36
41
  adapter.applyRenderedInstances(plan.instanceOverrides);
37
42
  adapter.applyText(plan.textContentChanges);
@@ -39,6 +44,9 @@ export function applyDraftProjection(adapter, plan) {
39
44
  adapter.applyManagedStyles(plan.managedStyles);
40
45
  }
41
46
  const hostDocumentProjectionAdapter = {
47
+ applyRuntimeIdentities: (claims) => {
48
+ applyRuntimeIdentityClaims(document, claims);
49
+ },
42
50
  applyStructural: (changes) => {
43
51
  applyStructuralProjection(document, changes);
44
52
  },
@@ -2,6 +2,7 @@ import { getElementComputedStyle } from "../runtime/domRealm.js";
2
2
  import { notifyBrowserStylesheetChange } from "../inspection/browserCssInspectionRegistry.js";
3
3
  import { escapeAttrValue, escapeCssString } from "./cssEscapes.js";
4
4
  import { isNudgeUiDev } from "../runtime/devFlag.js";
5
+ import { adoptStylesheet, allowsStyleElements, releaseAdoptedStylesheet } from "../runtime/ownedStylesheets.js";
5
6
  export { escapeAttrValue, escapeCssString } from "./cssEscapes.js";
6
7
  const SHEET_ID = "nudge-ui-styles";
7
8
  let managedHeadGuardDocument = null;
@@ -25,6 +26,12 @@ function installManagedHeadGuard(doc) {
25
26
  }
26
27
  export function ensureManagedSheet() {
27
28
  const doc = document;
29
+ if (!allowsStyleElements(doc)) {
30
+ // Adopted sheets already cascade after every document stylesheet.
31
+ adoptStylesheet(doc, SHEET_ID, rulesToCssText(managedRules));
32
+ exposeManagedSheetText(doc);
33
+ return;
34
+ }
28
35
  // SAFETY: getElementById returns an Element; the managed style element is created as HTMLStyleElement when missing.
29
36
  let el = doc.getElementById(SHEET_ID);
30
37
  if (!el) {
@@ -53,6 +60,9 @@ export function ensureManagedSheet() {
53
60
  rehydrateManagedSheet(doc, el);
54
61
  }
55
62
  installManagedHeadGuard(doc);
63
+ exposeManagedSheetText(doc);
64
+ }
65
+ function exposeManagedSheetText(doc) {
56
66
  if (isNudgeUiDev() && doc.defaultView) {
57
67
  // Keep the canonical CSS available to dev diagnostics.
58
68
  doc.defaultView.__nudgeUiGetManagedSheetText = getManagedSheetText;
@@ -125,15 +135,24 @@ function rehydrateManagedSheet(doc, el) {
125
135
  * copy for rehydration if a framework moves or reparses that element.
126
136
  */
127
137
  function rebuildSheetText(rules) {
128
- // SAFETY: getElementById returns an Element; the managed style element is created as HTMLStyleElement when missing.
129
- const el = document.getElementById(SHEET_ID);
130
- if (!el)
131
- return;
132
138
  const desired = rules.map((rule) => ({
133
139
  ...rule,
134
140
  declarations: { ...rule.declarations },
135
141
  }));
136
142
  const cssText = rulesToCssText(desired);
143
+ if (!allowsStyleElements(document)) {
144
+ const rulesChanged = rulesToCssText(managedRules) !== cssText;
145
+ managedRules = desired;
146
+ if (!rulesChanged)
147
+ return;
148
+ adoptStylesheet(document, SHEET_ID, cssText);
149
+ notifyBrowserStylesheetChange(document);
150
+ return;
151
+ }
152
+ // SAFETY: getElementById returns an Element; the managed style element is created as HTMLStyleElement when missing.
153
+ const el = document.getElementById(SHEET_ID);
154
+ if (!el)
155
+ return;
137
156
  const rulesChanged = rulesToCssText(managedRules) !== cssText;
138
157
  const shouldRetryDroppedRules = el.sheet !== null
139
158
  && el.sheet.cssRules.length !== desired.length
@@ -237,6 +256,7 @@ export function removeManagedSheet() {
237
256
  const el = document.getElementById(SHEET_ID);
238
257
  if (el)
239
258
  el.remove();
259
+ releaseAdoptedStylesheet(document, SHEET_ID);
240
260
  managedRules = [];
241
261
  failedRehydrationCssText = null;
242
262
  notifyBrowserStylesheetChange(document);
@@ -1,9 +1,10 @@
1
- import { getActiveDraftChanges, getDraftChanges } from "../changes/draftChanges.js";
1
+ import { getActiveDraftChanges, getDraftChanges } from "../drafts/store.js";
2
2
  import { inspectRootInvocations } from "../componentSemantics/adapterRegistry.js";
3
3
  import { escapeAttrValue } from "./cssEscapes.js";
4
4
  import { isNudgeUiDev } from "../runtime/devFlag.js";
5
5
  import { relocateSourceSite, sourceSiteSelector } from "../selection/sourceSite.js";
6
6
  import { isRenderedInstanceOverride } from "../changes/editModel.js";
7
+ import { boundRuntimeEvidence, isRuntimeGeneratedSource, normalizeRuntimeTag, runtimeDomPath } from "../runtime/staticHtmlRuntimeIdentity.js";
7
8
  export { isRenderedInstanceOverride, isRenderedInstanceRef } from "../changes/editModel.js";
8
9
  const PROJECTION_ATTR = "data-projection-instance";
9
10
  let nextOverrideId = 1;
@@ -45,6 +46,11 @@ export function captureRenderedInstance(el) {
45
46
  props: el.getAttribute("data-cprops"),
46
47
  text: normalizedText(el),
47
48
  ariaLabel: el.getAttribute("aria-label"),
49
+ ...(isRuntimeGeneratedSource(src) ? {
50
+ tagName: normalizeRuntimeTag(el.tagName),
51
+ domPath: runtimeDomPath(el),
52
+ elementId: boundRuntimeEvidence(el.id || null),
53
+ } : {}),
48
54
  },
49
55
  };
50
56
  }
@@ -47,15 +47,6 @@ export declare function getStructuralChanges(): readonly StructuralChange[];
47
47
  export declare function getStructuralDeletes(): readonly StructuralDelete[];
48
48
  /** Revert removes one canonical intent and leaves every other intent intact. */
49
49
  export declare function revertStructuralChange(changeId: string): boolean;
50
- /**
51
- * Removes source-verified structural intents without leaving an undo path that
52
- * can recreate their browser-only previews.
53
- *
54
- * Agent completion can verify a subset of one dispatched snapshot. The
55
- * remaining records and their useful history stay intact while every verified
56
- * ID is pruned from canonical state, undo/redo snapshots, and Canvas reports.
57
- */
58
- export declare function reconcileVerifiedStructuralChanges(verifiedIds: ReadonlySet<string>): number;
59
50
  /** State changes drive controller-to-renderer projection. Diagnostics do not. */
60
51
  export declare function subscribeStructuralChanges(listener: () => void): () => void;
61
52
  /** Compatibility name retained while the controller moved to a full union. */
@@ -1,7 +1,6 @@
1
- import { getActiveDraftChanges, getDraftChanges } from "../changes/draftChanges.js";
1
+ import { commitStructuralChange, getActiveDraftChanges, getDraftChanges, revertStructuralChange as revertDraftStructuralChange, subscribeActiveDraftChanges, } from "../drafts/store.js";
2
2
  import { captureRenderedInstance, captureStructuralTarget, matchesRenderedInstanceEvidence, resolveRenderedInstance, } from "./renderedInstance.js";
3
3
  import { isStructuralProjectionReport } from "./structuralProjectionBoundary.js";
4
- import { resetDraftChanges, draftChangeStore, } from "../changes/draftChanges.js";
5
4
  export { isStructuralChange, isStructuralDelete, isStructuralMove, isStructuralProjectionReport, } from "./structuralProjectionBoundary.js";
6
5
  const VOID_PARENT_TAGS = new Set([
7
6
  "area", "base", "br", "col", "embed", "hr", "img", "input", "link", "meta", "param", "source", "track", "wbr",
@@ -177,8 +176,11 @@ function cloneSnapshot(snapshot) {
177
176
  // array is enough: no operation mutates a change or its nested references.
178
177
  return [...snapshot];
179
178
  }
180
- function projectStructuralChanges(snapshot) {
181
- reprojectKnownDocuments(snapshot.structuralChanges);
179
+ /** The Draft store already re-projected the host; this covers every other known document. */
180
+ function projectStructuralChanges() {
181
+ const changes = getStructuralChanges();
182
+ for (const doc of documentStates.keys())
183
+ applyStructuralProjection(doc, changes);
182
184
  }
183
185
  /** Captures a delete intent once, in the controller, at the user gesture. */
184
186
  export function createStructuralDelete(element, id = structuralId()) {
@@ -194,9 +196,9 @@ export function createStructuralDelete(element, id = structuralId()) {
194
196
  ...(route ? { route } : {}),
195
197
  ...(state ? { state } : {}),
196
198
  };
197
- if (!draftChangeStore.commitStructuralChange(change))
199
+ if (!commitStructuralChange(change))
198
200
  return null;
199
- projectStructuralChanges(draftChangeStore.getSnapshot());
201
+ projectStructuralChanges();
200
202
  return change;
201
203
  }
202
204
  /**
@@ -237,51 +239,27 @@ export function createStructuralMove(element, destination, id = structuralId())
237
239
  : destinationChildren.length - (sameParent ? 1 : 0),
238
240
  },
239
241
  };
240
- if (!draftChangeStore.commitStructuralChange(change))
242
+ if (!commitStructuralChange(change))
241
243
  return null;
242
- projectStructuralChanges(draftChangeStore.getSnapshot());
244
+ projectStructuralChanges();
243
245
  return change;
244
246
  }
245
247
  export function getStructuralChanges() {
246
- return draftChangeStore.getSnapshot().structuralChanges;
248
+ return getActiveDraftChanges().structuralChanges;
247
249
  }
248
250
  export function getStructuralDeletes() {
249
251
  return getStructuralChanges().filter((change) => change.kind === "delete");
250
252
  }
251
253
  /** Revert removes one canonical intent and leaves every other intent intact. */
252
254
  export function revertStructuralChange(changeId) {
253
- const changed = draftChangeStore.revertStructuralChangeRecord(changeId);
255
+ const changed = revertDraftStructuralChange(changeId);
254
256
  if (changed)
255
- projectStructuralChanges(draftChangeStore.getSnapshot());
257
+ projectStructuralChanges();
256
258
  return changed;
257
259
  }
258
- /**
259
- * Removes source-verified structural intents without leaving an undo path that
260
- * can recreate their browser-only previews.
261
- *
262
- * Agent completion can verify a subset of one dispatched snapshot. The
263
- * remaining records and their useful history stay intact while every verified
264
- * ID is pruned from canonical state, undo/redo snapshots, and Canvas reports.
265
- */
266
- export function reconcileVerifiedStructuralChanges(verifiedIds) {
267
- if (verifiedIds.size === 0)
268
- return 0;
269
- const removed = draftChangeStore.reconcileActiveDraftChanges(new Set(), verifiedIds);
270
- if (removed === 0)
271
- return 0;
272
- projectStructuralChanges(draftChangeStore.getSnapshot());
273
- for (const [cardId, canvasReports] of reportsByCanvasCard) {
274
- reportsByCanvasCard.set(cardId, {
275
- ...canvasReports,
276
- reports: canvasReports.reports.filter((report) => !verifiedIds.has(report.changeId)),
277
- });
278
- }
279
- notifyDiagnostics();
280
- return removed;
281
- }
282
260
  /** State changes drive controller-to-renderer projection. Diagnostics do not. */
283
261
  export function subscribeStructuralChanges(listener) {
284
- return draftChangeStore.subscribe(listener);
262
+ return subscribeActiveDraftChanges(listener);
285
263
  }
286
264
  /** Compatibility name retained while the controller moved to a full union. */
287
265
  export const subscribeStructuralDeletes = subscribeStructuralChanges;
@@ -503,13 +481,6 @@ function validationStatus(local) {
503
481
  ? "applied"
504
482
  : "overridden";
505
483
  }
506
- /** Rebuild already-mounted document adapters from canonical data only. */
507
- function reprojectKnownDocuments(changes = getStructuralChanges()) {
508
- for (const [doc, state] of documentStates) {
509
- rebuildForSnapshot(doc, state, changes);
510
- storeReports(doc, reportsForSnapshot(state, state.snapshot));
511
- }
512
- }
513
484
  function validateAppliedPreview(doc, state) {
514
485
  let changed = false;
515
486
  for (const local of state.applied.values()) {
@@ -619,7 +590,6 @@ export function resetStructuralDeleteProjection() {
619
590
  reportsByCanvasCard.clear();
620
591
  nextStructuralId = 1;
621
592
  diagnosticRevision = 0;
622
- resetDraftChanges();
623
593
  notifyDiagnostics();
624
594
  }
625
595
  /**
@@ -1,8 +1,8 @@
1
1
  import type { FrameProjection } from "../canvas/projection.js";
2
- import { isTextProjectionTargetValue, type TextContentChangeRecord, type TextProjectionTarget, type TextProjectionScope, type TextBindingEvidence } from "../inline-text/textChangeBoundary.js";
2
+ import { isTextProjectionTargetValue, type TextContentChangeRecord, type TextProjectionTarget, type TextProjectionScope, type TextBindingEvidence } from "../changes/editModel.js";
3
3
  /** Strict JSON boundary guard for a text projection target. */
4
4
  export declare const isTextProjectionTarget: typeof isTextProjectionTargetValue;
5
- export type { TextProjectionTarget } from "../inline-text/textChangeBoundary.js";
5
+ export type { TextProjectionTarget } from "../changes/editModel.js";
6
6
  export type TextProjectionStatus = "applied" | "missing" | "ambiguous" | "overridden";
7
7
  export interface TextProjectionReport {
8
8
  changeId: string;
@@ -30,6 +30,12 @@ export type TextProjectionResolution = {
30
30
  /** Find the exact text node represented by a target, tolerating a changed
31
31
  * child path only when one bounded before/after text node remains unique. */
32
32
  export declare function resolveTextProjectionTextNode(element: HTMLElement, target: Pick<TextProjectionTarget, "textNodePath"> & Partial<Pick<TextProjectionTarget, "beforeText">>, expectedText?: string | undefined): Text | null;
33
+ /** Whether an element's text is code, form state, or other non-prose content. */
34
+ export declare function isUnsafeTextHost(element: Element): boolean;
35
+ /** Whether an application-owned editing region contains the element. */
36
+ export declare function isInApplicationEditingHost(element: Element): boolean;
37
+ /** Whether replacing one text node inside the element keeps its authored markup. */
38
+ export declare function hasSafeMixedDescendants(element: HTMLElement): boolean;
33
39
  /** Capture stable source/evidence identity without retaining a DOM reference. */
34
40
  export declare function captureTextProjectionTarget(element: HTMLElement, beforeText?: string, selectedTextNode?: Text): TextProjectionTarget | null;
35
41
  /**