nudge-ui 0.2.1 → 0.2.3

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 (258) hide show
  1. package/README.md +164 -46
  2. package/dist/client.mjs +252 -54
  3. package/dist/css/value-semantics/colorSemantics.d.ts +4 -0
  4. package/dist/css/value-semantics/colorSemantics.js +17 -0
  5. package/dist/hosts/astro/astroRuntimeConfig.js +1 -0
  6. package/dist/hosts/astro/clientTransport.js +41 -32
  7. package/dist/hosts/astro/integration.d.ts +2 -2
  8. package/dist/hosts/astro/integration.js +9 -4
  9. package/dist/hosts/astro/markdownIdentity.d.ts +28 -0
  10. package/dist/hosts/astro/markdownIdentity.js +81 -0
  11. package/dist/hosts/environment.d.ts +15 -0
  12. package/dist/hosts/environment.js +16 -0
  13. package/dist/hosts/next/manifest.js +1 -1
  14. package/dist/hosts/next/sidecar.js +12 -2
  15. package/dist/hosts/next/wrapper.d.ts +2 -0
  16. package/dist/hosts/next/wrapper.js +2 -1
  17. package/dist/hosts/projectBridge.d.ts +1 -0
  18. package/dist/hosts/projectBridge.js +1 -0
  19. package/dist/hosts/static/manifest.js +3 -1
  20. package/dist/hosts/static/server.js +4 -0
  21. package/dist/hosts/vite/vite.d.ts +4 -0
  22. package/dist/hosts/vite/vite.js +28 -5
  23. package/dist/inspector/agent/McpConnectionDialog.d.ts +3 -2
  24. package/dist/inspector/agent/McpConnectionDialog.js +23 -22
  25. package/dist/inspector/agent/activity.d.ts +18 -0
  26. package/dist/inspector/agent/activity.js +70 -0
  27. package/dist/inspector/agent/client.d.ts +8 -0
  28. package/dist/inspector/agent/client.js +65 -5
  29. package/dist/inspector/agent/connectionStatus.d.ts +3 -3
  30. package/dist/inspector/agent/connectionStatus.js +9 -2
  31. package/dist/inspector/agent/httpTransport.d.ts +6 -0
  32. package/dist/inspector/agent/httpTransport.js +50 -3
  33. package/dist/inspector/agent/protocol.d.ts +9 -3
  34. package/dist/inspector/agent/protocol.js +1 -1
  35. package/dist/inspector/agent/verification.d.ts +11 -1
  36. package/dist/inspector/agent/verification.js +53 -25
  37. package/dist/inspector/canvas/AgentActivityOverlay.d.ts +13 -0
  38. package/dist/inspector/canvas/AgentActivityOverlay.js +111 -0
  39. package/dist/inspector/canvas/CanvasCard.d.ts +9 -2
  40. package/dist/inspector/canvas/CanvasCard.js +133 -38
  41. package/dist/inspector/canvas/CanvasElementOverlay.js +200 -22
  42. package/dist/inspector/canvas/CanvasToolIcons.d.ts +10 -0
  43. package/dist/inspector/canvas/CanvasToolIcons.js +20 -0
  44. package/dist/inspector/canvas/CanvasToolbar.js +8 -4
  45. package/dist/inspector/canvas/CanvasWorkspace.js +243 -56
  46. package/dist/inspector/canvas/StaleChangeIndicator.js +3 -13
  47. package/dist/inspector/canvas/agentPresentation.d.ts +8 -8
  48. package/dist/inspector/canvas/agentPresentation.js +64 -52
  49. package/dist/inspector/canvas/canvasGestures.d.ts +1 -1
  50. package/dist/inspector/canvas/canvasGestures.js +1 -1
  51. package/dist/inspector/canvas/canvasStore.d.ts +46 -82
  52. package/dist/inspector/canvas/canvasStore.js +251 -284
  53. package/dist/inspector/canvas/frameContent.d.ts +21 -0
  54. package/dist/inspector/canvas/frameContent.js +44 -0
  55. package/dist/inspector/canvas/frameProtocol.d.ts +34 -4
  56. package/dist/inspector/canvas/frameProtocol.js +9 -2
  57. package/dist/inspector/canvas/keyboardShortcuts.d.ts +4 -1
  58. package/dist/inspector/canvas/keyboardShortcuts.js +5 -3
  59. package/dist/inspector/canvas/layout.d.ts +52 -0
  60. package/dist/inspector/canvas/layout.js +106 -0
  61. package/dist/inspector/canvas/linkEligibility.d.ts +0 -5
  62. package/dist/inspector/canvas/linkEligibility.js +0 -29
  63. package/dist/inspector/canvas/projection.d.ts +15 -5
  64. package/dist/inspector/canvas/projection.js +69 -13
  65. package/dist/inspector/canvas/rendererBootstrap.js +45 -4
  66. package/dist/inspector/canvas/rendererElementSelector.d.ts +1 -1
  67. package/dist/inspector/canvas/rendererElementSelector.js +102 -45
  68. package/dist/inspector/canvas/rendererStylesheet.js +2 -2
  69. package/dist/inspector/canvas/resizeHandleScale.js +1 -1
  70. package/dist/inspector/canvas/sessionStore.d.ts +11 -26
  71. package/dist/inspector/canvas/sessionStore.js +43 -183
  72. package/dist/inspector/canvas/staleChangeDetector.js +9 -3
  73. package/dist/inspector/canvas/useCanvasLayoutAnimation.d.ts +5 -0
  74. package/dist/inspector/canvas/useCanvasLayoutAnimation.js +107 -0
  75. package/dist/inspector/canvas/viewStore.d.ts +38 -0
  76. package/dist/inspector/canvas/viewStore.js +104 -0
  77. package/dist/inspector/canvas/wheelPan.d.ts +8 -0
  78. package/dist/inspector/canvas/wheelPan.js +8 -0
  79. package/dist/inspector/changes/changesLog.d.ts +6 -5
  80. package/dist/inspector/changes/changesLog.js +40 -32
  81. package/dist/inspector/changes/draftChanges.d.ts +56 -0
  82. package/dist/inspector/changes/draftChanges.js +300 -0
  83. package/dist/inspector/changes/previewDiagnostics.d.ts +4 -2
  84. package/dist/inspector/changes/previewDiagnostics.js +11 -25
  85. package/dist/inspector/clientManifest.d.ts +3 -1
  86. package/dist/inspector/clientManifest.js +1 -0
  87. package/dist/inspector/comments/CommentsOverlay.d.ts +2 -0
  88. package/dist/inspector/comments/CommentsOverlay.js +250 -0
  89. package/dist/inspector/comments/element.d.ts +6 -0
  90. package/dist/inspector/comments/element.js +47 -0
  91. package/dist/inspector/comments/store.d.ts +29 -0
  92. package/dist/inspector/comments/store.js +121 -0
  93. package/dist/inspector/comments/verification.d.ts +5 -0
  94. package/dist/inspector/comments/verification.js +52 -0
  95. package/dist/inspector/drafts/model.d.ts +35 -0
  96. package/dist/inspector/drafts/model.js +45 -0
  97. package/dist/inspector/drafts/store.d.ts +28 -0
  98. package/dist/inspector/drafts/store.js +231 -0
  99. package/dist/inspector/index.js +26 -35
  100. package/dist/inspector/inline-text/inlineTextEditor.js +7 -0
  101. package/dist/inspector/inspection/useBrowserCssInspection.js +15 -1
  102. package/dist/inspector/iterations/capture.d.ts +2 -0
  103. package/dist/inspector/iterations/capture.js +173 -0
  104. package/dist/inspector/iterations/client.d.ts +7 -0
  105. package/dist/inspector/iterations/client.js +52 -0
  106. package/dist/inspector/iterations/coordinator.d.ts +15 -0
  107. package/dist/inspector/iterations/coordinator.js +130 -0
  108. package/dist/inspector/iterations/prompt.d.ts +3 -0
  109. package/dist/inspector/iterations/prompt.js +26 -0
  110. package/dist/inspector/overlay/DomNavigator.d.ts +10 -0
  111. package/dist/inspector/overlay/DomNavigator.js +46 -0
  112. package/dist/inspector/overlay/InspectorOverlay.js +6 -2
  113. package/dist/inspector/overlay/clickPolicy.d.ts +18 -2
  114. package/dist/inspector/overlay/clickPolicy.js +34 -3
  115. package/dist/inspector/overlay/elementSelector.d.ts +1 -1
  116. package/dist/inspector/overlay/elementSelector.js +18 -7
  117. package/dist/inspector/overlay/interactionStyles.js +3 -1
  118. package/dist/inspector/overlay/spacingGestures.d.ts +15 -3
  119. package/dist/inspector/overlay/spacingGestures.js +88 -13
  120. package/dist/inspector/projection/{workspaceProjection.d.ts → draftProjection.d.ts} +6 -6
  121. package/dist/inspector/projection/{workspaceProjection.js → draftProjection.js} +4 -4
  122. package/dist/inspector/projection/renderedInstance.d.ts +2 -1
  123. package/dist/inspector/projection/renderedInstance.js +9 -5
  124. package/dist/inspector/projection/structuralProjection.d.ts +2 -1
  125. package/dist/inspector/projection/structuralProjection.js +19 -15
  126. package/dist/inspector/projection/textProjection.d.ts +2 -1
  127. package/dist/inspector/projection/textProjection.js +8 -4
  128. package/dist/inspector/prompt/PromptSettingsDialog.js +1 -5
  129. package/dist/inspector/prompt/clipboardHandoff.d.ts +10 -18
  130. package/dist/inspector/prompt/clipboardHandoff.js +92 -143
  131. package/dist/inspector/prompt/generatePrompt.d.ts +4 -1
  132. package/dist/inspector/prompt/generatePrompt.js +17 -16
  133. package/dist/inspector/runtime/runtimeConfig.d.ts +10 -1
  134. package/dist/inspector/runtime/runtimeConfig.js +24 -0
  135. package/dist/inspector/selection/hierarchy.d.ts +6 -0
  136. package/dist/inspector/selection/hierarchy.js +8 -0
  137. package/dist/inspector/settings/SettingsDialog.d.ts +1 -1
  138. package/dist/inspector/settings/SettingsDialog.js +22 -9
  139. package/dist/inspector/shell/AgentStatusButton.d.ts +11 -0
  140. package/dist/inspector/shell/AgentStatusButton.js +36 -0
  141. package/dist/inspector/shell/AppShell.js +4 -2
  142. package/dist/inspector/shell/ChangesLog.js +47 -27
  143. package/dist/inspector/shell/CopyPromptButton.js +146 -90
  144. package/dist/inspector/shell/EmptyState.js +9 -8
  145. package/dist/inspector/shell/InspectorShell.js +14 -25
  146. package/dist/inspector/shell/PeekOriginalButton.js +24 -23
  147. package/dist/inspector/shell/originalPreview.js +5 -5
  148. package/dist/inspector/shell/shortcuts.d.ts +3 -0
  149. package/dist/inspector/shell/shortcuts.js +11 -0
  150. package/dist/inspector/sketch/SketchEditor.js +14 -14
  151. package/dist/inspector/sketch/SketchEntryButton.js +1 -1
  152. package/dist/inspector/sketch/SketchFrameOverlay.d.ts +3 -1
  153. package/dist/inspector/sketch/SketchFrameOverlay.js +11 -8
  154. package/dist/inspector/sketch/SketchLayersPanel.js +13 -5
  155. package/dist/inspector/sketch/SketchOverlay.js +7 -7
  156. package/dist/inspector/sketch/SketchWorkspace.js +18 -12
  157. package/dist/inspector/sketch/interaction.d.ts +1 -0
  158. package/dist/inspector/sketch/interaction.js +8 -4
  159. package/dist/inspector/sketch/model.d.ts +5 -0
  160. package/dist/inspector/sketch/model.js +6 -2
  161. package/dist/inspector/sketch/raster.d.ts +1 -2
  162. package/dist/inspector/sketch/raster.js +68 -4
  163. package/dist/inspector/sketch/store.js +48 -23
  164. package/dist/inspector/styleEditors/BackgroundEditor.d.ts +4 -0
  165. package/dist/inspector/styleEditors/BackgroundEditor.js +195 -0
  166. package/dist/inspector/styleEditors/BorderEditor.js +49 -78
  167. package/dist/inspector/styleEditors/BorderRadiusEditor.js +6 -1
  168. package/dist/inspector/styleEditors/BoxShadowEditor.d.ts +1 -2
  169. package/dist/inspector/styleEditors/BoxShadowEditor.js +132 -4
  170. package/dist/inspector/styleEditors/ColorPicker.d.ts +5 -1
  171. package/dist/inspector/styleEditors/ColorPicker.js +10 -4
  172. package/dist/inspector/styleEditors/GapField.js +3 -5
  173. package/dist/inspector/styleEditors/GridChildSection.d.ts +1 -1
  174. package/dist/inspector/styleEditors/GridChildSection.js +18 -9
  175. package/dist/inspector/styleEditors/GridPicker.d.ts +1 -1
  176. package/dist/inspector/styleEditors/GridPicker.js +8 -2
  177. package/dist/inspector/styleEditors/GridSection.js +1 -1
  178. package/dist/inspector/styleEditors/GridValueField.js +19 -14
  179. package/dist/inspector/styleEditors/ImageBackgroundEditor.d.ts +18 -0
  180. package/dist/inspector/styleEditors/ImageBackgroundEditor.js +118 -0
  181. package/dist/inspector/styleEditors/LayoutBlockedIndicator.d.ts +2 -2
  182. package/dist/inspector/styleEditors/LayoutBlockedIndicator.js +3 -3
  183. package/dist/inspector/styleEditors/LayoutComboField.js +6 -4
  184. package/dist/inspector/styleEditors/LayoutDropdown.js +6 -3
  185. package/dist/inspector/styleEditors/LayoutSection.js +32 -11
  186. package/dist/inspector/styleEditors/SpacingBox.js +16 -9
  187. package/dist/inspector/styleEditors/Typography.js +11 -3
  188. package/dist/inspector/styleEditors/backgroundLayers.d.ts +24 -0
  189. package/dist/inspector/styleEditors/backgroundLayers.js +51 -0
  190. package/dist/inspector/styleEditors/gradientValue.d.ts +17 -0
  191. package/dist/inspector/styleEditors/gradientValue.js +114 -0
  192. package/dist/inspector/styleEditors/inlineAuthored.d.ts +10 -0
  193. package/dist/inspector/styleEditors/inlineAuthored.js +114 -0
  194. package/dist/inspector/styleEditors/layoutValue.d.ts +0 -8
  195. package/dist/inspector/styleEditors/layoutValue.js +0 -42
  196. package/dist/inspector/styleEditors/nudgeValue.d.ts +4 -4
  197. package/dist/inspector/styleEditors/nudgeValue.js +41 -11
  198. package/dist/inspector/tokens/TokenField.d.ts +7 -0
  199. package/dist/inspector/tokens/TokenField.js +49 -22
  200. package/dist/inspector/tokens/TokenLabel.js +5 -14
  201. package/dist/inspector/tokens/TokensPanel.js +2 -1
  202. package/dist/inspector/tokens/dragPointerLock.d.ts +8 -0
  203. package/dist/inspector/tokens/dragPointerLock.js +70 -0
  204. package/dist/inspector/tokens/editActions.d.ts +1 -1
  205. package/dist/inspector/tokens/editActions.js +1 -1
  206. package/dist/inspector/ui/AtRuleContext.js +4 -6
  207. package/dist/inspector/ui/Button.d.ts +6 -2
  208. package/dist/inspector/ui/Button.js +4 -3
  209. package/dist/inspector/ui/ControlSurface.d.ts +2 -2
  210. package/dist/inspector/ui/ControlSurface.js +4 -3
  211. package/dist/inspector/ui/Disclosure.d.ts +22 -0
  212. package/dist/inspector/ui/Disclosure.js +13 -0
  213. package/dist/inspector/ui/InlineStyleWarning.d.ts +11 -0
  214. package/dist/inspector/ui/InlineStyleWarning.js +13 -0
  215. package/dist/inspector/ui/InspectorPopover.d.ts +2 -1
  216. package/dist/inspector/ui/InspectorPopover.js +4 -5
  217. package/dist/inspector/ui/PopoverListbox.d.ts +2 -1
  218. package/dist/inspector/ui/PopoverListbox.js +8 -7
  219. package/dist/inspector/ui/SegmentedControl.d.ts +2 -1
  220. package/dist/inspector/ui/SegmentedControl.js +2 -2
  221. package/dist/inspector/ui/Select.d.ts +6 -1
  222. package/dist/inspector/ui/Select.js +7 -11
  223. package/dist/inspector/ui/SideValuesField.js +1 -1
  224. package/dist/inspector/ui/Tooltip.d.ts +26 -0
  225. package/dist/inspector/ui/Tooltip.js +32 -0
  226. package/dist/inspector/ui/classNames.d.ts +2 -0
  227. package/dist/inspector/ui/classNames.js +4 -0
  228. package/dist/inspector/ui/customCursors.d.ts +23 -0
  229. package/dist/inspector/ui/customCursors.js +122 -0
  230. package/dist/inspector/ui/dragCursor.d.ts +6 -0
  231. package/dist/inspector/ui/dragCursor.js +13 -0
  232. package/dist/inspector/ui/portalContainer.d.ts +2 -0
  233. package/dist/inspector/ui/portalContainer.js +6 -0
  234. package/dist/inspector/ui/styles.js +34 -24
  235. package/dist/inspector/workspace/commands.d.ts +9 -0
  236. package/dist/inspector/workspace/commands.js +82 -0
  237. package/dist/inspector/workspace/controller.d.ts +4 -0
  238. package/dist/inspector/workspace/controller.js +66 -0
  239. package/dist/inspector/workspace/handoff.d.ts +42 -0
  240. package/dist/inspector/workspace/handoff.js +115 -0
  241. package/dist/inspector/workspace/timeline.d.ts +30 -0
  242. package/dist/inspector/workspace/timeline.js +108 -0
  243. package/dist/internal/agent-protocol.d.ts +19 -2
  244. package/dist/internal/agent-protocol.js +13 -0
  245. package/dist/nudge-ui.mjs +560 -299
  246. package/dist/project/artifacts.d.ts +13 -0
  247. package/dist/project/artifacts.js +253 -0
  248. package/dist/transport/artifacts.d.ts +8 -0
  249. package/dist/transport/artifacts.js +9 -0
  250. package/dist/transport/editor.d.ts +20 -1
  251. package/dist/transport/editor.js +44 -11
  252. package/dist/transport/routes.d.ts +6 -1
  253. package/dist/transport/routes.js +6 -1
  254. package/package.json +6 -2
  255. package/dist/inspector/changes/workspaceChanges.d.ts +0 -43
  256. package/dist/inspector/changes/workspaceChanges.js +0 -239
  257. package/dist/inspector/shell/DomNavigation.d.ts +0 -8
  258. package/dist/inspector/shell/DomNavigation.js +0 -30
package/dist/nudge-ui.mjs CHANGED
@@ -2020,7 +2020,7 @@ var require_util = __commonJS({
2020
2020
  }
2021
2021
  path = url.path;
2022
2022
  }
2023
- var isAbsolute4 = exports.isAbsolute(path);
2023
+ var isAbsolute5 = exports.isAbsolute(path);
2024
2024
  var parts = [];
2025
2025
  var start = 0;
2026
2026
  var i = 0;
@@ -2055,7 +2055,7 @@ var require_util = __commonJS({
2055
2055
  }
2056
2056
  path = parts.join("/");
2057
2057
  if (path === "") {
2058
- path = isAbsolute4 ? "/" : ".";
2058
+ path = isAbsolute5 ? "/" : ".";
2059
2059
  }
2060
2060
  if (url) {
2061
2061
  url.path = path;
@@ -2064,7 +2064,7 @@ var require_util = __commonJS({
2064
2064
  return path;
2065
2065
  });
2066
2066
  exports.normalize = normalize;
2067
- function join6(aRoot, aPath) {
2067
+ function join7(aRoot, aPath) {
2068
2068
  if (aRoot === "") {
2069
2069
  aRoot = ".";
2070
2070
  }
@@ -2096,11 +2096,11 @@ var require_util = __commonJS({
2096
2096
  }
2097
2097
  return joined;
2098
2098
  }
2099
- exports.join = join6;
2099
+ exports.join = join7;
2100
2100
  exports.isAbsolute = function(aPath) {
2101
2101
  return aPath.charAt(0) === "/" || urlRegexp.test(aPath);
2102
2102
  };
2103
- function relative4(aRoot, aPath) {
2103
+ function relative5(aRoot, aPath) {
2104
2104
  if (aRoot === "") {
2105
2105
  aRoot = ".";
2106
2106
  }
@@ -2119,7 +2119,7 @@ var require_util = __commonJS({
2119
2119
  }
2120
2120
  return Array(level + 1).join("../") + aPath.substr(aRoot.length + 1);
2121
2121
  }
2122
- exports.relative = relative4;
2122
+ exports.relative = relative5;
2123
2123
  var supportsNullProto = (function() {
2124
2124
  var obj = /* @__PURE__ */ Object.create(null);
2125
2125
  return !("__proto__" in obj);
@@ -2310,7 +2310,7 @@ var require_util = __commonJS({
2310
2310
  parsed.path = parsed.path.substring(0, index + 1);
2311
2311
  }
2312
2312
  }
2313
- sourceURL = join6(urlGenerate(parsed), sourceURL);
2313
+ sourceURL = join7(urlGenerate(parsed), sourceURL);
2314
2314
  }
2315
2315
  return normalize(sourceURL);
2316
2316
  }
@@ -3750,8 +3750,8 @@ var require_source_map = __commonJS({
3750
3750
  var require_previous_map = __commonJS({
3751
3751
  "../../node_modules/.pnpm/postcss@8.5.26/node_modules/postcss/lib/previous-map.js"(exports, module) {
3752
3752
  "use strict";
3753
- var { existsSync: existsSync4, readFileSync, realpathSync: realpathSync3 } = __require("fs");
3754
- var { dirname: dirname5, isAbsolute: isAbsolute4, join: join6, relative: relative4, sep: sep3 } = __require("path");
3753
+ var { existsSync: existsSync4, readFileSync: readFileSync2, realpathSync: realpathSync3 } = __require("fs");
3754
+ var { dirname: dirname5, isAbsolute: isAbsolute5, join: join7, relative: relative5, sep: sep4 } = __require("path");
3755
3755
  var { SourceMapConsumer, SourceMapGenerator } = require_source_map();
3756
3756
  function realPath(path) {
3757
3757
  try {
@@ -3824,15 +3824,15 @@ var require_previous_map = __commonJS({
3824
3824
  if (!trusted && !this.unsafeMap) {
3825
3825
  if (!/\.map$/i.test(path)) return void 0;
3826
3826
  if (!cssFile) return void 0;
3827
- let rel = relative4(realPath(dirname5(cssFile)), realPath(path));
3828
- if (rel === ".." || rel.startsWith(".." + sep3) || isAbsolute4(rel)) {
3827
+ let rel = relative5(realPath(dirname5(cssFile)), realPath(path));
3828
+ if (rel === ".." || rel.startsWith(".." + sep4) || isAbsolute5(rel)) {
3829
3829
  return void 0;
3830
3830
  }
3831
3831
  }
3832
3832
  this.root = dirname5(path);
3833
3833
  if (existsSync4(path)) {
3834
3834
  this.mapFile = path;
3835
- return readFileSync(path, "utf-8").toString().trim();
3835
+ return readFileSync2(path, "utf-8").toString().trim();
3836
3836
  }
3837
3837
  }
3838
3838
  loadMap(file, prev) {
@@ -3866,7 +3866,7 @@ var require_previous_map = __commonJS({
3866
3866
  return this.decodeInline(this.annotation);
3867
3867
  } else if (this.annotation) {
3868
3868
  let map = this.annotation;
3869
- if (file) map = join6(dirname5(file), map);
3869
+ if (file) map = join7(dirname5(file), map);
3870
3870
  let unknown = this.loadFile(map, file, false);
3871
3871
  if (unknown) {
3872
3872
  try {
@@ -3896,7 +3896,7 @@ var require_input = __commonJS({
3896
3896
  "../../node_modules/.pnpm/postcss@8.5.26/node_modules/postcss/lib/input.js"(exports, module) {
3897
3897
  "use strict";
3898
3898
  var { nanoid } = require_non_secure();
3899
- var { isAbsolute: isAbsolute4, resolve: resolve5 } = __require("path");
3899
+ var { isAbsolute: isAbsolute5, resolve: resolve5 } = __require("path");
3900
3900
  var { SourceMapConsumer, SourceMapGenerator } = require_source_map();
3901
3901
  var { fileURLToPath, pathToFileURL: pathToFileURL2 } = __require("url");
3902
3902
  var CssSyntaxError2 = require_css_syntax_error();
@@ -3904,7 +3904,7 @@ var require_input = __commonJS({
3904
3904
  var terminalHighlight = require_terminal_highlight();
3905
3905
  var lineToIndexCache = /* @__PURE__ */ Symbol("lineToIndexCache");
3906
3906
  var sourceMapAvailable = Boolean(SourceMapConsumer && SourceMapGenerator);
3907
- var pathAvailable = Boolean(resolve5 && isAbsolute4);
3907
+ var pathAvailable = Boolean(resolve5 && isAbsolute5);
3908
3908
  function getLineToIndex(input) {
3909
3909
  if (input[lineToIndexCache]) return input[lineToIndexCache];
3910
3910
  let lines = input.css.split("\n");
@@ -3935,7 +3935,7 @@ var require_input = __commonJS({
3935
3935
  this.document = this.css;
3936
3936
  if (opts.document) this.document = opts.document.toString();
3937
3937
  if (opts.from) {
3938
- if (!pathAvailable || /^\w+:\/\//.test(opts.from) || isAbsolute4(opts.from)) {
3938
+ if (!pathAvailable || /^\w+:\/\//.test(opts.from) || isAbsolute5(opts.from)) {
3939
3939
  this.file = opts.from;
3940
3940
  } else {
3941
3941
  this.file = resolve5(opts.from);
@@ -4075,7 +4075,7 @@ var require_input = __commonJS({
4075
4075
  if (toPosition.source) to = toPosition;
4076
4076
  }
4077
4077
  let fromUrl;
4078
- if (isAbsolute4(from.source)) {
4078
+ if (isAbsolute5(from.source)) {
4079
4079
  fromUrl = pathToFileURL2(from.source);
4080
4080
  } else {
4081
4081
  fromUrl = new URL(
@@ -4256,8 +4256,8 @@ var require_rule = __commonJS({
4256
4256
  }
4257
4257
  set selectors(values) {
4258
4258
  let match = this.selector ? this.selector.match(/,\s*/) : null;
4259
- let sep3 = match ? match[0] : "," + this.raw("between", "beforeOpen");
4260
- this.selector = values.join(sep3);
4259
+ let sep4 = match ? match[0] : "," + this.raw("between", "beforeOpen");
4260
+ this.selector = values.join(sep4);
4261
4261
  }
4262
4262
  constructor(defaults) {
4263
4263
  super(defaults);
@@ -4369,12 +4369,12 @@ var require_fromJSON = __commonJS({
4369
4369
  var require_map_generator = __commonJS({
4370
4370
  "../../node_modules/.pnpm/postcss@8.5.26/node_modules/postcss/lib/map-generator.js"(exports, module) {
4371
4371
  "use strict";
4372
- var { dirname: dirname5, relative: relative4, resolve: resolve5, sep: sep3 } = __require("path");
4372
+ var { dirname: dirname5, relative: relative5, resolve: resolve5, sep: sep4 } = __require("path");
4373
4373
  var { SourceMapConsumer, SourceMapGenerator } = require_source_map();
4374
4374
  var { pathToFileURL: pathToFileURL2 } = __require("url");
4375
4375
  var Input2 = require_input();
4376
4376
  var sourceMapAvailable = Boolean(SourceMapConsumer && SourceMapGenerator);
4377
- var pathAvailable = Boolean(dirname5 && resolve5 && relative4 && sep3);
4377
+ var pathAvailable = Boolean(dirname5 && resolve5 && relative5 && sep4);
4378
4378
  var MapGenerator = class {
4379
4379
  constructor(stringify2, root2, opts, cssString) {
4380
4380
  this.stringify = stringify2;
@@ -4605,7 +4605,7 @@ var require_map_generator = __commonJS({
4605
4605
  if (typeof this.mapOpts.annotation === "string") {
4606
4606
  from = dirname5(resolve5(from, this.mapOpts.annotation));
4607
4607
  }
4608
- let path = relative4(from, file);
4608
+ let path = relative5(from, file);
4609
4609
  this.memoizedPaths.set(file, path);
4610
4610
  return path;
4611
4611
  }
@@ -4678,7 +4678,7 @@ var require_map_generator = __commonJS({
4678
4678
  toUrl(path) {
4679
4679
  let cached = this.memoizedURLs.get(path);
4680
4680
  if (cached) return cached;
4681
- if (sep3 === "\\") {
4681
+ if (sep4 === "\\") {
4682
4682
  path = path.replace(/\\/g, "/");
4683
4683
  }
4684
4684
  let url = encodeURI(path).replace(/[#?]/g, encodeURIComponent);
@@ -6182,13 +6182,13 @@ function planAgentCommand(args, projectRoot, packageVersion) {
6182
6182
  throw new Error("Usage: nudge-ui agent <setup|doctor> [options]");
6183
6183
  }
6184
6184
  function findLocalMcp(projectRoot, projectRequire) {
6185
- let directory = projectRoot;
6185
+ let directory2 = projectRoot;
6186
6186
  while (true) {
6187
- const candidate = join(directory, "node_modules", "@nudge-ui", "mcp");
6187
+ const candidate = join(directory2, "node_modules", "@nudge-ui", "mcp");
6188
6188
  if (existsSync(join(candidate, "package.json"))) return candidate;
6189
- const parent = dirname(directory);
6190
- if (parent === directory) break;
6191
- directory = parent;
6189
+ const parent = dirname(directory2);
6190
+ if (parent === directory2) break;
6191
+ directory2 = parent;
6192
6192
  }
6193
6193
  if (process.versions.pnp) {
6194
6194
  return projectRequire.resolve("@nudge-ui/mcp");
@@ -6204,20 +6204,122 @@ function runAgentCommand(args, packageVersion) {
6204
6204
  }
6205
6205
  }
6206
6206
 
6207
- // src/hosts/static/server.ts
6208
- import { createHash as createHash2 } from "node:crypto";
6209
- import {
6210
- createServer
6211
- } from "node:http";
6212
- import {
6213
- constants,
6214
- existsSync as existsSync3,
6215
- realpathSync as realpathSync2,
6216
- statSync as statSync2
6217
- } from "node:fs";
6218
- import { open, stat as stat2 } from "node:fs/promises";
6219
- import { dirname as dirname4, extname as extname2, isAbsolute as isAbsolute3, join as join5, relative as relative3, resolve as resolve3 } from "node:path";
6220
- import { createRequire as createRequire3 } from "node:module";
6207
+ // src/transport/artifacts.ts
6208
+ var HTML_ARTIFACT_REVISION_ATTRIBUTE = "data-nudge-artifact-revision";
6209
+ var HTML_ITERATION_CONFLICT = "This iteration changed outside Nudge. Your visual edits are still pending. Create another iteration to keep your design, then clear this iteration\u2019s changes to load the external update.";
6210
+ function isHtmlArtifactRevision(value) {
6211
+ if (!value || typeof value !== "object") return false;
6212
+ const item = value;
6213
+ return typeof item.document === "string" && /^[a-f0-9]{64}$/.test(item.document) && typeof item.preview === "string" && /^[a-f0-9]{64}$/.test(item.preview);
6214
+ }
6215
+
6216
+ // src/project/artifacts.ts
6217
+ import { createHash } from "node:crypto";
6218
+ import { readFileSync, renameSync, writeFileSync } from "node:fs";
6219
+ import { mkdir, readFile, realpath, rename, rm, writeFile } from "node:fs/promises";
6220
+ import { isAbsolute, join as join2, relative, sep } from "node:path";
6221
+
6222
+ // src/transport/routes.ts
6223
+ var NUDGE_UI_ROUTE_PREFIX = "/__nudge_ui__/";
6224
+ var NUDGE_UI_MANIFEST_PATH = `${NUDGE_UI_ROUTE_PREFIX}manifest`;
6225
+ var NUDGE_UI_CLIENT_PATH = `${NUDGE_UI_ROUTE_PREFIX}client.mjs`;
6226
+ var NUDGE_UI_EDITOR_PATH = `${NUDGE_UI_ROUTE_PREFIX}editor`;
6227
+ var NUDGE_UI_RELOAD_PATH = `${NUDGE_UI_ROUTE_PREFIX}reload`;
6228
+ var NUDGE_UI_ARTIFACTS_PATH = `${NUDGE_UI_ROUTE_PREFIX}artifacts`;
6229
+ var NUDGE_UI_MOUNT_ID = "nudge-ui-root";
6230
+ var NUDGE_UI_EDITOR_QUERY_PARAM = "nudge-ui";
6231
+ var NUDGE_UI_EDITOR_QUERY_VALUE = "editor";
6232
+ function isReservedNudgeUiRoute(pathname) {
6233
+ return pathname === NUDGE_UI_ROUTE_PREFIX.slice(0, -1) || pathname.startsWith(NUDGE_UI_ROUTE_PREFIX);
6234
+ }
6235
+
6236
+ // src/transport/editor.ts
6237
+ function isNudgeUiEditorDocumentRequest(requestHref, method, headers) {
6238
+ const normalizedMethod = (method ?? "GET").toUpperCase();
6239
+ if (normalizedMethod !== "GET" && normalizedMethod !== "HEAD") return false;
6240
+ const url = new URL(requestHref, "http://nudge-ui.local");
6241
+ if (url.pathname === NUDGE_UI_EDITOR_PATH) return true;
6242
+ if (!isApplicationUrl(url)) return false;
6243
+ if (!url.searchParams.getAll(NUDGE_UI_EDITOR_QUERY_PARAM).includes(NUDGE_UI_EDITOR_QUERY_VALUE)) return false;
6244
+ const header = (name) => {
6245
+ const value = headers?.[name] ?? headers?.[name.toLowerCase()];
6246
+ return typeof value === "string" ? value : value?.join(",") ?? "";
6247
+ };
6248
+ return header("sec-fetch-dest").toLowerCase() === "document" || header("accept").toLowerCase().includes("text/html");
6249
+ }
6250
+ function isApplicationUrl(url) {
6251
+ return (url.protocol === "http:" || url.protocol === "https:") && url.username === "" && url.password === "" && !isReservedNudgeUiRoute(url.pathname);
6252
+ }
6253
+ function createNudgeUiEditorDocument() {
6254
+ return `<!doctype html>
6255
+ <html lang="en" data-nudge-ui-editor>
6256
+ <head>
6257
+ <meta charset="utf-8">
6258
+ <meta name="viewport" content="width=device-width, initial-scale=1">
6259
+ <title>Nudge UI</title>
6260
+ <style>html,body,#${NUDGE_UI_MOUNT_ID}{width:100%;height:100%;margin:0}body{overflow:hidden}</style>
6261
+ </head>
6262
+ <body>
6263
+ <div id="${NUDGE_UI_MOUNT_ID}"></div>
6264
+ <script type="module" src="${NUDGE_UI_CLIENT_PATH}" data-nudge-ui-client data-nudge-ui-manifest="${NUDGE_UI_MANIFEST_PATH}"></script>
6265
+ </body>
6266
+ </html>`;
6267
+ }
6268
+
6269
+ // src/transport/index.ts
6270
+ var NUDGE_UI_MANIFEST_VERSION = 1;
6271
+
6272
+ // src/hosts/environment.ts
6273
+ function readNudgeUiEnvironmentSwitch(env = process.env) {
6274
+ const value = env.NUDGE_UI?.trim().toLowerCase();
6275
+ if (value === "0" || value === "false" || value === "off") return "off";
6276
+ if (value === "1" || value === "true" || value === "on") return "on";
6277
+ return null;
6278
+ }
6279
+ function automationManifestFields(env = process.env) {
6280
+ return readNudgeUiEnvironmentSwitch(env) === "on" ? { inspectAutomatedBrowsers: true } : {};
6281
+ }
6282
+
6283
+ // src/hosts/static/manifest.ts
6284
+ function createStandaloneRuntimeManifest(projectId, tokenSnapshot = emptyTokenSnapshot(), revision2 = 0) {
6285
+ return {
6286
+ version: NUDGE_UI_MANIFEST_VERSION,
6287
+ revision: revision2,
6288
+ runtime: {
6289
+ projectId,
6290
+ host: "static-html",
6291
+ framework: "HTML",
6292
+ stylingSystem: "CSS custom properties",
6293
+ // Canvas shares the Vite host's controller/renderer runtime (ADR-0012):
6294
+ // every served document carries the bootstrap, so card iframes boot as
6295
+ // renderers without host-specific code.
6296
+ capabilities: { canvas: true, componentSemantics: false, domNavigation: true },
6297
+ tokenCatalog: tokenSnapshot.tokenCatalog,
6298
+ tokens: tokenSnapshot.tokens,
6299
+ tokenDiagnostics: tokenSnapshot.tokenDiagnostics,
6300
+ tokenGeneration: tokenSnapshot.tokenGeneration,
6301
+ componentContracts: []
6302
+ },
6303
+ document: {
6304
+ runtimeIdentity: "static-html",
6305
+ stylesheetOrder: "browser"
6306
+ },
6307
+ reload: {
6308
+ endpoint: NUDGE_UI_RELOAD_PATH,
6309
+ strategy: "reload-document",
6310
+ events: ["ready", "reload"]
6311
+ },
6312
+ ...automationManifestFields()
6313
+ };
6314
+ }
6315
+ function emptyTokenSnapshot() {
6316
+ return {
6317
+ tokenCatalog: [],
6318
+ tokens: [],
6319
+ tokenDiagnostics: [],
6320
+ tokenGeneration: "empty"
6321
+ };
6322
+ }
6221
6323
 
6222
6324
  // ../../node_modules/.pnpm/parse5@7.3.0/node_modules/parse5/dist/common/unicode.js
6223
6325
  var UNDEFINED_CODE_POINTS = /* @__PURE__ */ new Set([
@@ -14073,6 +14175,323 @@ function parse(html, options) {
14073
14175
  return Parser.parse(html, options);
14074
14176
  }
14075
14177
 
14178
+ // src/hosts/static/html/bootstrap.ts
14179
+ var CLIENT_MARKER = "data-nudge-ui-client";
14180
+ var MOUNT_MARKER = "data-nudge-ui-mount";
14181
+ function injectStandaloneBootstrap(html, options = {}) {
14182
+ const clientPath = options.clientPath ?? NUDGE_UI_CLIENT_PATH;
14183
+ const manifestPath = options.manifestPath ?? NUDGE_UI_MANIFEST_PATH;
14184
+ const document2 = parse(html, { sourceCodeLocationInfo: true });
14185
+ const sourceFacts = inspectSource(document2, clientPath);
14186
+ const nodes = [];
14187
+ if (!sourceFacts.hasMount) {
14188
+ nodes.push(
14189
+ `<div id="${NUDGE_UI_MOUNT_ID}" ${MOUNT_MARKER}></div>`
14190
+ );
14191
+ }
14192
+ if (!sourceFacts.hasClient) {
14193
+ nodes.push(
14194
+ `<script type="module" src="${escapeAttributeValue(clientPath)}" ${CLIENT_MARKER} data-nudge-ui-manifest="${escapeAttributeValue(manifestPath)}"></script>`
14195
+ );
14196
+ }
14197
+ if (nodes.length === 0) return { html, injected: false };
14198
+ const injection = `
14199
+ ${nodes.join("\n")}
14200
+ `;
14201
+ const offset = sourceFacts.bodyEndOffset ?? sourceFacts.htmlEndOffset ?? html.length;
14202
+ return {
14203
+ html: `${html.slice(0, offset)}${injection}${html.slice(offset)}`,
14204
+ injected: true
14205
+ };
14206
+ }
14207
+ function inspectSource(document2, clientPath) {
14208
+ const facts = {
14209
+ hasMount: false,
14210
+ hasClient: false,
14211
+ bodyEndOffset: null,
14212
+ htmlEndOffset: null
14213
+ };
14214
+ let body2 = null;
14215
+ visitElements(document2, (element) => {
14216
+ if (element.namespaceURI !== "http://www.w3.org/1999/xhtml") return;
14217
+ const tagName = element.tagName.toLowerCase();
14218
+ if (tagName === "body") body2 = element;
14219
+ if (tagName === "script" && (attributeValue(element, CLIENT_MARKER) !== null || attributeValue(element, "src") === clientPath)) {
14220
+ facts.hasClient = true;
14221
+ }
14222
+ const endOffset = element.sourceCodeLocation?.endTag?.startOffset;
14223
+ if (tagName === "body" && endOffset !== void 0) facts.bodyEndOffset = endOffset;
14224
+ if (tagName === "html" && endOffset !== void 0) facts.htmlEndOffset = endOffset;
14225
+ });
14226
+ if (body2) {
14227
+ visitElements(body2, (element) => {
14228
+ if (element !== body2 && attributeValue(element, "id") === NUDGE_UI_MOUNT_ID) {
14229
+ facts.hasMount = true;
14230
+ }
14231
+ });
14232
+ }
14233
+ return facts;
14234
+ }
14235
+ function visitElements(parent, visit) {
14236
+ for (const child of parent.childNodes) {
14237
+ if (!("tagName" in child) || typeof child.tagName !== "string") continue;
14238
+ if (child.tagName.toLowerCase() === "template") continue;
14239
+ visit(child);
14240
+ visitElements(child, visit);
14241
+ }
14242
+ }
14243
+ function attributeValue(element, name) {
14244
+ return element.attrs.find((attribute) => attribute.name === name)?.value ?? null;
14245
+ }
14246
+ function escapeAttributeValue(value) {
14247
+ return value.replaceAll("&", "&amp;").replaceAll('"', "&quot;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
14248
+ }
14249
+
14250
+ // src/project/artifacts.ts
14251
+ var artifactOperations = /* @__PURE__ */ new Map();
14252
+ async function withArtifactLock(path, operation) {
14253
+ const previous = artifactOperations.get(path) ?? Promise.resolve();
14254
+ const pending = previous.catch(() => void 0).then(operation);
14255
+ artifactOperations.set(path, pending);
14256
+ try {
14257
+ return await pending;
14258
+ } finally {
14259
+ if (artifactOperations.get(path) === pending) artifactOperations.delete(path);
14260
+ }
14261
+ }
14262
+ function revision(html) {
14263
+ return createHash("sha256").update(html).digest("hex");
14264
+ }
14265
+ async function readRevision(target) {
14266
+ const [document2, preview] = await Promise.all([
14267
+ readFile(join2(target, "document.html")),
14268
+ readFile(join2(target, "preview.html"))
14269
+ ]);
14270
+ return { document: revision(document2), preview: revision(preview) };
14271
+ }
14272
+ function sameRevision(left, right) {
14273
+ return left.document === right.document && left.preview === right.preview;
14274
+ }
14275
+ var ID = /^[a-f0-9-]{36}$/i;
14276
+ var MAX_BYTES = 12 * 1024 * 1024;
14277
+ var INERT_INTERACTIONS = `<script data-nudge-artifact-guard>
14278
+ document.addEventListener("submit", event => event.preventDefault(), true);
14279
+ document.addEventListener("click", event => {
14280
+ if (event.target instanceof Element && event.target.closest("a")) event.preventDefault();
14281
+ }, true);
14282
+ </script>`;
14283
+ async function directory(root2, id) {
14284
+ const project = await realpath(root2);
14285
+ const artifacts = join2(project, ".nudge", "artifacts");
14286
+ await mkdir(artifacts, { recursive: true });
14287
+ const actual = await realpath(artifacts);
14288
+ const pathFromRoot = relative(project, actual);
14289
+ if (pathFromRoot === ".." || pathFromRoot.startsWith(`..${sep}`) || isAbsolute(pathFromRoot)) {
14290
+ throw new Error("Artifact storage must remain inside the project root");
14291
+ }
14292
+ return join2(actual, id);
14293
+ }
14294
+ async function body(request) {
14295
+ const chunks = [];
14296
+ let size = 0;
14297
+ for await (const chunk of request) {
14298
+ const data = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
14299
+ size += data.byteLength;
14300
+ if (size > MAX_BYTES) throw new Error("HTML artifact exceeds 12 MB");
14301
+ chunks.push(data);
14302
+ }
14303
+ const text = Buffer.concat(chunks).toString("utf8");
14304
+ return text.length === 0 ? {} : JSON.parse(text);
14305
+ }
14306
+ function respond(response, status, content, type = "text/plain; charset=utf-8") {
14307
+ response.writeHead(status, {
14308
+ "content-type": type,
14309
+ "cache-control": "no-store",
14310
+ "x-content-type-options": "nosniff"
14311
+ });
14312
+ response.end(content);
14313
+ }
14314
+ async function handleHtmlArtifactRequest(request, response, root2, transformHtml) {
14315
+ const pathname = new URL(request.url ?? "/", "http://nudge-ui.local").pathname;
14316
+ if (pathname !== NUDGE_UI_ARTIFACTS_PATH && !pathname.startsWith(`${NUDGE_UI_ARTIFACTS_PATH}/`)) return false;
14317
+ const parts = pathname.slice(NUDGE_UI_ARTIFACTS_PATH.length).split("/").filter(Boolean);
14318
+ if (request.method !== "GET" && request.method !== "HEAD") {
14319
+ const origin = request.headers.origin;
14320
+ const host = request.headers.host;
14321
+ if (origin && host) {
14322
+ try {
14323
+ if (new URL(origin).host !== host) {
14324
+ respond(response, 403, "Cross-origin artifact writes are not allowed");
14325
+ return true;
14326
+ }
14327
+ } catch {
14328
+ respond(response, 403, "Invalid request origin");
14329
+ return true;
14330
+ }
14331
+ }
14332
+ }
14333
+ const id = parts[0];
14334
+ if (parts.length > 2 || id && !ID.test(id) || parts.length === 2 && !["document", "baseline", "preview", "commit", "revision"].includes(parts[1])) {
14335
+ respond(response, 404, "Not Found");
14336
+ return true;
14337
+ }
14338
+ try {
14339
+ if (request.method === "POST" && parts.length === 0) {
14340
+ const input = await body(request);
14341
+ if (!validArtifact(input)) {
14342
+ respond(response, 400, "Invalid artifact");
14343
+ return true;
14344
+ }
14345
+ const target2 = await directory(root2, input.id);
14346
+ const temporary = `${target2}.create-${crypto.randomUUID()}`;
14347
+ const metadata = {
14348
+ id: input.id,
14349
+ sourceUrl: input.sourceUrl,
14350
+ title: input.title,
14351
+ capturedAt: Date.now(),
14352
+ viewport: input.viewport
14353
+ };
14354
+ await mkdir(temporary);
14355
+ try {
14356
+ await writeFile(join2(temporary, "baseline.html"), input.html);
14357
+ await writeFile(join2(temporary, "preview.html"), input.html);
14358
+ await writeFile(join2(temporary, "document.html"), input.html);
14359
+ await writeFile(join2(temporary, "metadata.json"), JSON.stringify(metadata));
14360
+ await rename(temporary, target2);
14361
+ } catch (error) {
14362
+ await rm(temporary, { recursive: true, force: true });
14363
+ throw error;
14364
+ }
14365
+ respond(response, 201, JSON.stringify(metadata), "application/json; charset=utf-8");
14366
+ return true;
14367
+ }
14368
+ if (!id) {
14369
+ respond(response, 405, "Method Not Allowed");
14370
+ return true;
14371
+ }
14372
+ const target = await directory(root2, id);
14373
+ return await withArtifactLock(target, async () => {
14374
+ if (request.method !== "DELETE") {
14375
+ const actual = await realpath(target);
14376
+ if (actual !== target) throw new Error("Artifact directory must not be a symbolic link");
14377
+ }
14378
+ if (request.method === "GET" && parts[1] === "revision") {
14379
+ respond(response, 200, JSON.stringify(await readRevision(target)), "application/json; charset=utf-8");
14380
+ return true;
14381
+ }
14382
+ if (request.method === "GET" && parts.length === 2 && parts[1] !== "commit") {
14383
+ const file = parts[1] === "baseline" ? "baseline.html" : parts[1] === "preview" ? "preview.html" : "document.html";
14384
+ const html = await readFile(join2(target, file), "utf8");
14385
+ const stamped = html.replace(/<html\b/i, `<html ${HTML_ARTIFACT_REVISION_ATTRIBUTE}="${revision(html)}"`);
14386
+ const bootstrapped = injectStandaloneBootstrap(stamped).html;
14387
+ const guarded = bootstrapped.replace(/<\/body>/i, `${INERT_INTERACTIONS}</body>`);
14388
+ respond(response, 200, transformHtml ? await transformHtml(guarded) : guarded, "text/html; charset=utf-8");
14389
+ return true;
14390
+ }
14391
+ if (request.method === "GET" && parts.length === 1) {
14392
+ respond(response, 200, await readFile(join2(target, "metadata.json"), "utf8"), "application/json; charset=utf-8");
14393
+ return true;
14394
+ }
14395
+ if (request.method === "PUT" && parts[1] === "document" || request.method === "POST" && parts[1] === "commit") {
14396
+ const input = await body(request);
14397
+ if (!input || typeof input !== "object") {
14398
+ respond(response, 400, "Invalid document");
14399
+ return true;
14400
+ }
14401
+ const item = input;
14402
+ if (!isHtmlArtifactRevision(item.expected)) {
14403
+ respond(response, 428, "An expected iteration revision is required");
14404
+ return true;
14405
+ }
14406
+ if (item.html !== void 0 && typeof item.html !== "string" || request.method === "PUT" && typeof item.html !== "string") {
14407
+ respond(response, 400, "Invalid document");
14408
+ return true;
14409
+ }
14410
+ const expected = item.expected;
14411
+ if (!sameRevision(await readRevision(target), expected)) {
14412
+ respond(response, 409, HTML_ITERATION_CONFLICT);
14413
+ return true;
14414
+ }
14415
+ const html = typeof item.html === "string" ? item.html : await readFile(join2(target, "document.html"), "utf8");
14416
+ const writes = request.method === "POST" ? ["preview.html"] : [];
14417
+ if (typeof item.html === "string") writes.push("document.html");
14418
+ const previewBefore = await readFile(join2(target, "preview.html"));
14419
+ const temporaryFiles = [];
14420
+ try {
14421
+ for (const file of writes) {
14422
+ const temporary = join2(target, `${file}-${crypto.randomUUID()}.tmp`);
14423
+ temporaryFiles.push({ temporary, destination: join2(target, file) });
14424
+ await writeFile(temporary, html);
14425
+ }
14426
+ const latest = {
14427
+ document: revision(readFileSync(join2(target, "document.html"))),
14428
+ preview: revision(readFileSync(join2(target, "preview.html")))
14429
+ };
14430
+ if (!sameRevision(latest, expected)) {
14431
+ respond(response, 409, HTML_ITERATION_CONFLICT);
14432
+ return true;
14433
+ }
14434
+ let replacedPreview = false;
14435
+ try {
14436
+ for (const file of temporaryFiles) {
14437
+ renameSync(file.temporary, file.destination);
14438
+ replacedPreview ||= file.destination === join2(target, "preview.html");
14439
+ }
14440
+ } catch (error) {
14441
+ if (replacedPreview) {
14442
+ const rollback = join2(target, `preview-rollback-${crypto.randomUUID()}.tmp`);
14443
+ writeFileSync(rollback, previewBefore);
14444
+ renameSync(rollback, join2(target, "preview.html"));
14445
+ }
14446
+ throw error;
14447
+ }
14448
+ } finally {
14449
+ await Promise.all(temporaryFiles.map((file) => rm(file.temporary, { force: true }).catch(() => void 0)));
14450
+ }
14451
+ const saved = revision(html);
14452
+ respond(response, 200, JSON.stringify({ document: saved, preview: request.method === "POST" ? saved : expected.preview }), "application/json; charset=utf-8");
14453
+ return true;
14454
+ }
14455
+ if (request.method === "DELETE" && parts.length === 1) {
14456
+ await rm(target, { recursive: true, force: true });
14457
+ respond(response, 204, "");
14458
+ return true;
14459
+ }
14460
+ respond(response, 405, "Method Not Allowed");
14461
+ return true;
14462
+ });
14463
+ } catch (error) {
14464
+ const code = error.code;
14465
+ respond(
14466
+ response,
14467
+ code === "ENOENT" ? 404 : code === "EEXIST" || code === "ENOTEMPTY" ? 409 : 500,
14468
+ code === "ENOENT" ? "Artifact not found" : error instanceof Error ? error.message : "Artifact storage failed"
14469
+ );
14470
+ }
14471
+ return true;
14472
+ }
14473
+ function validArtifact(value) {
14474
+ if (!value || typeof value !== "object") return false;
14475
+ const item = value;
14476
+ const viewport = item.viewport;
14477
+ return typeof item.id === "string" && ID.test(item.id) && typeof item.sourceUrl === "string" && item.sourceUrl.length < 4096 && typeof item.title === "string" && item.title.length < 512 && typeof item.html === "string" && item.html.length > 0 && !!viewport && typeof viewport.width === "number" && typeof viewport.height === "number";
14478
+ }
14479
+
14480
+ // src/hosts/static/server.ts
14481
+ import { createHash as createHash3 } from "node:crypto";
14482
+ import {
14483
+ createServer
14484
+ } from "node:http";
14485
+ import {
14486
+ constants,
14487
+ existsSync as existsSync3,
14488
+ realpathSync as realpathSync2,
14489
+ statSync as statSync2
14490
+ } from "node:fs";
14491
+ import { open, stat as stat2 } from "node:fs/promises";
14492
+ import { dirname as dirname4, extname as extname2, isAbsolute as isAbsolute4, join as join6, relative as relative4, resolve as resolve3 } from "node:path";
14493
+ import { createRequire as createRequire3 } from "node:module";
14494
+
14076
14495
  // src/html/dom.ts
14077
14496
  var HTML_NAMESPACE = "http://www.w3.org/1999/xhtml";
14078
14497
  var EXCLUDED_TAG_NAMES = /* @__PURE__ */ new Set([
@@ -14106,7 +14525,7 @@ function findBodyElements(document2) {
14106
14525
  visit(document2);
14107
14526
  return bodies;
14108
14527
  }
14109
- function escapeAttributeValue(value) {
14528
+ function escapeAttributeValue2(value) {
14110
14529
  return value.replaceAll("&", "&amp;").replaceAll('"', "&quot;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
14111
14530
  }
14112
14531
 
@@ -14160,19 +14579,6 @@ function positionAt(positions, offset) {
14160
14579
  return { line: low + 1, column: offset - lineStarts[low] + 1 };
14161
14580
  }
14162
14581
 
14163
- // src/transport/routes.ts
14164
- var NUDGE_UI_ROUTE_PREFIX = "/__nudge_ui__/";
14165
- var NUDGE_UI_MANIFEST_PATH = `${NUDGE_UI_ROUTE_PREFIX}manifest`;
14166
- var NUDGE_UI_CLIENT_PATH = `${NUDGE_UI_ROUTE_PREFIX}client.mjs`;
14167
- var NUDGE_UI_EDITOR_PATH = `${NUDGE_UI_ROUTE_PREFIX}editor`;
14168
- var NUDGE_UI_RELOAD_PATH = `${NUDGE_UI_ROUTE_PREFIX}reload`;
14169
- var NUDGE_UI_MOUNT_ID = "nudge-ui-root";
14170
- var NUDGE_UI_EDITOR_QUERY_PARAM = "nudge-ui";
14171
- var NUDGE_UI_EDITOR_QUERY_VALUE = "editor";
14172
- function isReservedNudgeUiRoute(pathname) {
14173
- return pathname === NUDGE_UI_ROUTE_PREFIX.slice(0, -1) || pathname.startsWith(NUDGE_UI_ROUTE_PREFIX);
14174
- }
14175
-
14176
14582
  // src/html/identity.ts
14177
14583
  function runIdentityPass(source, pass) {
14178
14584
  const diagnostics = [];
@@ -14245,8 +14651,8 @@ function runIdentityPass(source, pass) {
14245
14651
  if (isElement(child)) visit(child);
14246
14652
  }
14247
14653
  };
14248
- for (const body of findBodyElements(document2)) {
14249
- for (const child of body.childNodes) {
14654
+ for (const body2 of findBodyElements(document2)) {
14655
+ for (const child of body2.childNodes) {
14250
14656
  if (isElement(child)) visit(child);
14251
14657
  }
14252
14658
  }
@@ -14262,168 +14668,20 @@ function instrumentSourceHtml(source, file) {
14262
14668
  attributesFor({ element, line, column }) {
14263
14669
  const attributes = [];
14264
14670
  if (!hasAttribute(element, "data-cid")) {
14265
- attributes.push(`data-cid="${escapeAttributeValue(`html:${element.tagName}`)}"`);
14671
+ attributes.push(`data-cid="${escapeAttributeValue2(`html:${element.tagName}`)}"`);
14266
14672
  }
14267
14673
  if (!hasAttribute(element, "data-src")) {
14268
- attributes.push(`data-src="${escapeAttributeValue(`${file}:${line}:${column}`)}"`);
14674
+ attributes.push(`data-src="${escapeAttributeValue2(`${file}:${line}:${column}`)}"`);
14269
14675
  }
14270
14676
  return attributes;
14271
14677
  }
14272
14678
  });
14273
14679
  }
14274
14680
 
14275
- // src/transport/editor.ts
14276
- function isNudgeUiEditorDocumentRequest(requestHref, method, headers) {
14277
- const normalizedMethod = (method ?? "GET").toUpperCase();
14278
- if (normalizedMethod !== "GET" && normalizedMethod !== "HEAD") return false;
14279
- const url = new URL(requestHref, "http://nudge-ui.local");
14280
- if (url.pathname === NUDGE_UI_EDITOR_PATH) return true;
14281
- if (!isApplicationUrl(url)) return false;
14282
- if (!url.searchParams.getAll(NUDGE_UI_EDITOR_QUERY_PARAM).includes(NUDGE_UI_EDITOR_QUERY_VALUE)) return false;
14283
- const header = (name) => {
14284
- const value = headers?.[name] ?? headers?.[name.toLowerCase()];
14285
- return typeof value === "string" ? value : value?.join(",") ?? "";
14286
- };
14287
- return header("sec-fetch-dest").toLowerCase() === "document" || header("accept").toLowerCase().includes("text/html");
14288
- }
14289
- function isApplicationUrl(url) {
14290
- return (url.protocol === "http:" || url.protocol === "https:") && url.username === "" && url.password === "" && !isReservedNudgeUiRoute(url.pathname);
14291
- }
14292
- function createNudgeUiEditorDocument() {
14293
- return `<!doctype html>
14294
- <html lang="en" data-nudge-ui-editor>
14295
- <head>
14296
- <meta charset="utf-8">
14297
- <meta name="viewport" content="width=device-width, initial-scale=1">
14298
- <title>Nudge UI</title>
14299
- <style>html,body,#${NUDGE_UI_MOUNT_ID}{width:100%;height:100%;margin:0}body{overflow:hidden}</style>
14300
- </head>
14301
- <body>
14302
- <div id="${NUDGE_UI_MOUNT_ID}"></div>
14303
- <script type="module" src="${NUDGE_UI_CLIENT_PATH}" data-nudge-ui-client data-nudge-ui-manifest="${NUDGE_UI_MANIFEST_PATH}"></script>
14304
- </body>
14305
- </html>`;
14306
- }
14307
-
14308
- // src/transport/index.ts
14309
- var NUDGE_UI_MANIFEST_VERSION = 1;
14310
-
14311
- // src/hosts/static/manifest.ts
14312
- function createStandaloneRuntimeManifest(projectId, tokenSnapshot = emptyTokenSnapshot(), revision = 0) {
14313
- return {
14314
- version: NUDGE_UI_MANIFEST_VERSION,
14315
- revision,
14316
- runtime: {
14317
- projectId,
14318
- host: "static-html",
14319
- framework: "HTML",
14320
- stylingSystem: "CSS custom properties",
14321
- // Canvas shares the Vite host's controller/renderer runtime (ADR-0012):
14322
- // every served document carries the bootstrap, so card iframes boot as
14323
- // renderers without host-specific code.
14324
- capabilities: { canvas: true, componentSemantics: false },
14325
- tokenCatalog: tokenSnapshot.tokenCatalog,
14326
- tokens: tokenSnapshot.tokens,
14327
- tokenDiagnostics: tokenSnapshot.tokenDiagnostics,
14328
- tokenGeneration: tokenSnapshot.tokenGeneration,
14329
- componentContracts: []
14330
- },
14331
- document: {
14332
- runtimeIdentity: "static-html",
14333
- stylesheetOrder: "browser"
14334
- },
14335
- reload: {
14336
- endpoint: NUDGE_UI_RELOAD_PATH,
14337
- strategy: "reload-document",
14338
- events: ["ready", "reload"]
14339
- }
14340
- };
14341
- }
14342
- function emptyTokenSnapshot() {
14343
- return {
14344
- tokenCatalog: [],
14345
- tokens: [],
14346
- tokenDiagnostics: [],
14347
- tokenGeneration: "empty"
14348
- };
14349
- }
14350
-
14351
- // src/hosts/static/html/bootstrap.ts
14352
- var CLIENT_MARKER = "data-nudge-ui-client";
14353
- var MOUNT_MARKER = "data-nudge-ui-mount";
14354
- function injectStandaloneBootstrap(html, options = {}) {
14355
- const clientPath = options.clientPath ?? NUDGE_UI_CLIENT_PATH;
14356
- const manifestPath = options.manifestPath ?? NUDGE_UI_MANIFEST_PATH;
14357
- const document2 = parse(html, { sourceCodeLocationInfo: true });
14358
- const sourceFacts = inspectSource(document2, clientPath);
14359
- const nodes = [];
14360
- if (!sourceFacts.hasMount) {
14361
- nodes.push(
14362
- `<div id="${NUDGE_UI_MOUNT_ID}" ${MOUNT_MARKER}></div>`
14363
- );
14364
- }
14365
- if (!sourceFacts.hasClient) {
14366
- nodes.push(
14367
- `<script type="module" src="${escapeAttributeValue2(clientPath)}" ${CLIENT_MARKER} data-nudge-ui-manifest="${escapeAttributeValue2(manifestPath)}"></script>`
14368
- );
14369
- }
14370
- if (nodes.length === 0) return { html, injected: false };
14371
- const injection = `
14372
- ${nodes.join("\n")}
14373
- `;
14374
- const offset = sourceFacts.bodyEndOffset ?? sourceFacts.htmlEndOffset ?? html.length;
14375
- return {
14376
- html: `${html.slice(0, offset)}${injection}${html.slice(offset)}`,
14377
- injected: true
14378
- };
14379
- }
14380
- function inspectSource(document2, clientPath) {
14381
- const facts = {
14382
- hasMount: false,
14383
- hasClient: false,
14384
- bodyEndOffset: null,
14385
- htmlEndOffset: null
14386
- };
14387
- let body = null;
14388
- visitElements(document2, (element) => {
14389
- if (element.namespaceURI !== "http://www.w3.org/1999/xhtml") return;
14390
- const tagName = element.tagName.toLowerCase();
14391
- if (tagName === "body") body = element;
14392
- if (tagName === "script" && (attributeValue(element, CLIENT_MARKER) !== null || attributeValue(element, "src") === clientPath)) {
14393
- facts.hasClient = true;
14394
- }
14395
- const endOffset = element.sourceCodeLocation?.endTag?.startOffset;
14396
- if (tagName === "body" && endOffset !== void 0) facts.bodyEndOffset = endOffset;
14397
- if (tagName === "html" && endOffset !== void 0) facts.htmlEndOffset = endOffset;
14398
- });
14399
- if (body) {
14400
- visitElements(body, (element) => {
14401
- if (element !== body && attributeValue(element, "id") === NUDGE_UI_MOUNT_ID) {
14402
- facts.hasMount = true;
14403
- }
14404
- });
14405
- }
14406
- return facts;
14407
- }
14408
- function visitElements(parent, visit) {
14409
- for (const child of parent.childNodes) {
14410
- if (!("tagName" in child) || typeof child.tagName !== "string") continue;
14411
- if (child.tagName.toLowerCase() === "template") continue;
14412
- visit(child);
14413
- visitElements(child, visit);
14414
- }
14415
- }
14416
- function attributeValue(element, name) {
14417
- return element.attrs.find((attribute) => attribute.name === name)?.value ?? null;
14418
- }
14419
- function escapeAttributeValue2(value) {
14420
- return value.replaceAll("&", "&amp;").replaceAll('"', "&quot;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
14421
- }
14422
-
14423
14681
  // src/hosts/projectBridge.ts
14424
14682
  import { existsSync as existsSync2 } from "node:fs";
14425
14683
  import { createRequire as createRequire2 } from "node:module";
14426
- import { dirname as dirname2, join as join2, parse as parse2 } from "node:path";
14684
+ import { dirname as dirname2, join as join3, parse as parse2 } from "node:path";
14427
14685
  import { pathToFileURL } from "node:url";
14428
14686
  var runningBridges = /* @__PURE__ */ new Map();
14429
14687
  async function startOptionalProjectBridge(input) {
@@ -14444,7 +14702,7 @@ async function launchOptionalProjectBridge(input, key) {
14444
14702
  runningBridges.delete(key);
14445
14703
  return null;
14446
14704
  }
14447
- modulePath = createRequire2(join2(input.appRoot, "package.json")).resolve("@nudge-ui/mcp/project");
14705
+ modulePath = createRequire2(join3(input.appRoot, "package.json")).resolve("@nudge-ui/mcp/project");
14448
14706
  } catch {
14449
14707
  runningBridges.delete(key);
14450
14708
  return null;
@@ -14464,6 +14722,7 @@ async function launchOptionalProjectBridge(input, key) {
14464
14722
  await runtime.close().catch(() => void 0);
14465
14723
  throw new Error("the project bridge returned a different project or origin");
14466
14724
  }
14725
+ input.info?.(`[nudge-ui] project bridge ready for ${input.projectId}`);
14467
14726
  let closed = false;
14468
14727
  return {
14469
14728
  browser: { baseUrl: runtime.browser.bridgeUrl, autoConnect: true },
@@ -14485,24 +14744,24 @@ function isPnpRuntime() {
14485
14744
  return typeof process.versions.pnp === "string";
14486
14745
  }
14487
14746
  function hasProjectInstalledMcp(appRoot) {
14488
- let directory = appRoot;
14489
- const root2 = parse2(directory).root;
14747
+ let directory2 = appRoot;
14748
+ const root2 = parse2(directory2).root;
14490
14749
  for (; ; ) {
14491
- if (existsSync2(join2(directory, "node_modules", "@nudge-ui", "mcp", "package.json"))) return true;
14492
- if (directory === root2) return false;
14493
- directory = dirname2(directory);
14750
+ if (existsSync2(join3(directory2, "node_modules", "@nudge-ui", "mcp", "package.json"))) return true;
14751
+ if (directory2 === root2) return false;
14752
+ directory2 = dirname2(directory2);
14494
14753
  }
14495
14754
  }
14496
14755
 
14497
14756
  // src/project/tokens.ts
14498
- import { createHash } from "node:crypto";
14757
+ import { createHash as createHash2 } from "node:crypto";
14499
14758
  import {
14500
14759
  readFile as readUtf8File,
14501
14760
  readdir,
14502
- realpath,
14761
+ realpath as realpath2,
14503
14762
  stat
14504
14763
  } from "node:fs/promises";
14505
- import { extname, isAbsolute, join as join3, relative, resolve, sep } from "node:path";
14764
+ import { extname, isAbsolute as isAbsolute2, join as join4, relative as relative2, resolve, sep as sep2 } from "node:path";
14506
14765
 
14507
14766
  // ../../node_modules/.pnpm/postcss@8.5.26/node_modules/postcss/lib/postcss.mjs
14508
14767
  var import_postcss = __toESM(require_postcss(), 1);
@@ -15016,7 +15275,7 @@ var EMPTY_PROJECT_TOKEN_SNAPSHOT = {
15016
15275
  async function createProjectTokenSnapshot(options) {
15017
15276
  const rootDirectory = await canonicalRoot(options.rootDirectory);
15018
15277
  const additionalRoots = (await Promise.all(
15019
- (options.additionalRootDirectories ?? []).map((directory) => canonicalOptionalRoot(directory))
15278
+ (options.additionalRootDirectories ?? []).map((directory2) => canonicalOptionalRoot(directory2))
15020
15279
  )).filter((root2) => root2 !== null);
15021
15280
  const scanRoots = [rootDirectory, ...additionalRoots.filter((root2) => root2 !== rootDirectory)];
15022
15281
  const discovered = await Promise.all(
@@ -15026,12 +15285,12 @@ async function createProjectTokenSnapshot(options) {
15026
15285
  const seenFiles = /* @__PURE__ */ new Set();
15027
15286
  for (let index = 0; index < discovered.length; index += 1) {
15028
15287
  for (const artifact of discovered[index] ?? []) {
15029
- const canonicalPath = await realpath(artifact.absolutePath).catch(() => artifact.absolutePath);
15288
+ const canonicalPath = await realpath2(artifact.absolutePath).catch(() => artifact.absolutePath);
15030
15289
  if (seenFiles.has(canonicalPath)) continue;
15031
15290
  seenFiles.add(canonicalPath);
15032
15291
  artifacts.push({
15033
15292
  ...artifact,
15034
- projectPath: index === 0 ? artifact.projectPath : relative(rootDirectory, artifact.absolutePath).split(sep).join("/")
15293
+ projectPath: index === 0 ? artifact.projectPath : relative2(rootDirectory, artifact.absolutePath).split(sep2).join("/")
15035
15294
  });
15036
15295
  }
15037
15296
  }
@@ -15074,32 +15333,32 @@ async function createProjectTokenSnapshot(options) {
15074
15333
  tokenGeneration
15075
15334
  };
15076
15335
  }
15077
- async function discoverProjectCssArtifacts(rootDirectory, readFile = (absolutePath) => readUtf8File(absolutePath, "utf8")) {
15336
+ async function discoverProjectCssArtifacts(rootDirectory, readFile2 = (absolutePath) => readUtf8File(absolutePath, "utf8")) {
15078
15337
  const root2 = await canonicalRoot(rootDirectory);
15079
15338
  const artifacts = [];
15080
15339
  const visitedDirectories = /* @__PURE__ */ new Set();
15081
15340
  const visitedFiles = /* @__PURE__ */ new Set();
15082
- await walkDirectory(root2, root2, visitedDirectories, visitedFiles, artifacts, readFile);
15341
+ await walkDirectory(root2, root2, visitedDirectories, visitedFiles, artifacts, readFile2);
15083
15342
  artifacts.sort((a, b) => comparePosixStrings(a.projectPath, b.projectPath));
15084
15343
  return artifacts;
15085
15344
  }
15086
- async function walkDirectory(rootDirectory, directory, visitedDirectories, visitedFiles, artifacts, readFile) {
15087
- const canonicalDirectoryPath = await canonicalWithinRoot(rootDirectory, directory);
15345
+ async function walkDirectory(rootDirectory, directory2, visitedDirectories, visitedFiles, artifacts, readFile2) {
15346
+ const canonicalDirectoryPath = await canonicalWithinRoot(rootDirectory, directory2);
15088
15347
  if (!canonicalDirectoryPath || visitedDirectories.has(canonicalDirectoryPath)) return;
15089
- const projectDirectoryPath = relative(rootDirectory, directory).split(sep).join("/");
15090
- const canonicalProjectDirectoryPath = relative(rootDirectory, canonicalDirectoryPath).split(sep).join("/");
15348
+ const projectDirectoryPath = relative2(rootDirectory, directory2).split(sep2).join("/");
15349
+ const canonicalProjectDirectoryPath = relative2(rootDirectory, canonicalDirectoryPath).split(sep2).join("/");
15091
15350
  if (isSensitiveProjectPath(projectDirectoryPath) || isSensitiveProjectPath(canonicalProjectDirectoryPath)) return;
15092
15351
  visitedDirectories.add(canonicalDirectoryPath);
15093
15352
  let entries;
15094
15353
  try {
15095
- entries = await readdir(directory, { withFileTypes: true });
15354
+ entries = await readdir(directory2, { withFileTypes: true });
15096
15355
  } catch {
15097
15356
  return;
15098
15357
  }
15099
15358
  entries.sort((a, b) => comparePosixStrings(a.name, b.name));
15100
15359
  for (const entry of entries) {
15101
15360
  if (entry.isDirectory() && isExcludedDirectoryName(entry.name)) continue;
15102
- const absolutePath = join3(directory, entry.name);
15361
+ const absolutePath = join4(directory2, entry.name);
15103
15362
  const canonicalPath = await canonicalWithinRoot(rootDirectory, absolutePath);
15104
15363
  if (!canonicalPath) continue;
15105
15364
  let stats;
@@ -15116,20 +15375,20 @@ async function walkDirectory(rootDirectory, directory, visitedDirectories, visit
15116
15375
  visitedDirectories,
15117
15376
  visitedFiles,
15118
15377
  artifacts,
15119
- readFile
15378
+ readFile2
15120
15379
  );
15121
15380
  continue;
15122
15381
  }
15123
15382
  if (!stats.isFile() || extname(entry.name).toLowerCase() !== ".css") continue;
15124
15383
  if (visitedFiles.has(canonicalPath)) continue;
15125
15384
  visitedFiles.add(canonicalPath);
15126
- const projectPath = relative(rootDirectory, absolutePath).split(sep).join("/");
15127
- const canonicalProjectPath2 = relative(rootDirectory, canonicalPath).split(sep).join("/");
15385
+ const projectPath = relative2(rootDirectory, absolutePath).split(sep2).join("/");
15386
+ const canonicalProjectPath2 = relative2(rootDirectory, canonicalPath).split(sep2).join("/");
15128
15387
  if (isSensitiveProjectPath(projectPath) || isSensitiveProjectPath(canonicalProjectPath2)) {
15129
15388
  continue;
15130
15389
  }
15131
15390
  try {
15132
- const content = await readFile(absolutePath);
15391
+ const content = await readFile2(absolutePath);
15133
15392
  artifacts.push({ absolutePath, projectPath, content });
15134
15393
  } catch (error) {
15135
15394
  artifacts.push({
@@ -15141,7 +15400,7 @@ async function walkDirectory(rootDirectory, directory, visitedDirectories, visit
15141
15400
  }
15142
15401
  }
15143
15402
  async function canonicalRoot(rootDirectory) {
15144
- const root2 = await realpath(resolve(rootDirectory));
15403
+ const root2 = await realpath2(resolve(rootDirectory));
15145
15404
  if (!(await stat(root2)).isDirectory()) {
15146
15405
  throw new Error(`Standalone root is not a directory: ${rootDirectory}`);
15147
15406
  }
@@ -15156,9 +15415,9 @@ async function canonicalOptionalRoot(rootDirectory) {
15156
15415
  }
15157
15416
  async function canonicalWithinRoot(rootDirectory, candidate) {
15158
15417
  try {
15159
- const canonical = await realpath(candidate);
15160
- const pathFromRoot = relative(rootDirectory, canonical);
15161
- if (pathFromRoot === "" || !pathFromRoot.startsWith(`..${sep}`) && pathFromRoot !== ".." && !isAbsolute(pathFromRoot)) {
15418
+ const canonical = await realpath2(candidate);
15419
+ const pathFromRoot = relative2(rootDirectory, canonical);
15420
+ if (pathFromRoot === "" || !pathFromRoot.startsWith(`..${sep2}`) && pathFromRoot !== ".." && !isAbsolute2(pathFromRoot)) {
15162
15421
  return canonical;
15163
15422
  }
15164
15423
  } catch {
@@ -15186,7 +15445,7 @@ function deterministicGeneration(artifacts, inventoryGeneration, label) {
15186
15445
  content: artifact.content,
15187
15446
  readError: artifact.readError
15188
15447
  }));
15189
- const digest = createHash("sha256").update(`${facts.join("\n")}
15448
+ const digest = createHash2("sha256").update(`${facts.join("\n")}
15190
15449
  ${inventoryGeneration}`).digest("hex").slice(0, 24);
15191
15450
  return `${label}:${digest}`;
15192
15451
  }
@@ -15198,7 +15457,7 @@ function comparePosixStrings(a, b) {
15198
15457
  import { watch } from "node:fs";
15199
15458
  import { readdir as readdir2 } from "node:fs/promises";
15200
15459
  import { realpathSync, statSync } from "node:fs";
15201
- import { dirname as dirname3, isAbsolute as isAbsolute2, join as join4, relative as relative2, resolve as resolve2, sep as sep2 } from "node:path";
15460
+ import { dirname as dirname3, isAbsolute as isAbsolute3, join as join5, relative as relative3, resolve as resolve2, sep as sep3 } from "node:path";
15202
15461
  function createProjectFileWatcher(options) {
15203
15462
  const rootDirectory = realpathSync(resolve2(options.rootDirectory));
15204
15463
  const debounceMs = Math.max(0, options.debounceMs ?? 60);
@@ -15228,30 +15487,30 @@ function createProjectFileWatcher(options) {
15228
15487
  pending.clear();
15229
15488
  void Promise.resolve(options.onSettled(changes)).catch(reportError);
15230
15489
  };
15231
- const closeDirectory = (directory) => {
15232
- const entry = watches.get(directory);
15490
+ const closeDirectory = (directory2) => {
15491
+ const entry = watches.get(directory2);
15233
15492
  if (!entry) return;
15234
- watches.delete(directory);
15493
+ watches.delete(directory2);
15235
15494
  entry.watcher.close();
15236
15495
  };
15237
- const closeDescendants = (directory) => {
15496
+ const closeDescendants = (directory2) => {
15238
15497
  for (const watchedDirectory of [...watches.keys()]) {
15239
- if (watchedDirectory === directory || watchedDirectory.startsWith(`${directory}${sep2}`)) {
15498
+ if (watchedDirectory === directory2 || watchedDirectory.startsWith(`${directory2}${sep3}`)) {
15240
15499
  closeDirectory(watchedDirectory);
15241
15500
  }
15242
15501
  }
15243
15502
  };
15244
- const watchDirectory = (directory) => {
15245
- if (closed || !isProjectDirectory(rootDirectory, directory)) return;
15246
- const canonicalDirectory2 = canonicalProjectPath(rootDirectory, directory);
15503
+ const watchDirectory = (directory2) => {
15504
+ if (closed || !isProjectDirectory(rootDirectory, directory2)) return;
15505
+ const canonicalDirectory2 = canonicalProjectPath(rootDirectory, directory2);
15247
15506
  if (!canonicalDirectory2 || [...watches.values()].some(
15248
15507
  (entry) => entry.canonicalDirectory === canonicalDirectory2
15249
15508
  )) return;
15250
15509
  let directoryWatcher;
15251
15510
  try {
15252
- directoryWatcher = watch(directory, { persistent: true }, (eventType, filename) => {
15511
+ directoryWatcher = watch(directory2, { persistent: true }, (eventType, filename) => {
15253
15512
  const changedName = filename?.toString();
15254
- const changedPath = changedName ? join4(directory, changedName) : directory;
15513
+ const changedPath = changedName ? join5(directory2, changedName) : directory2;
15255
15514
  if (!isProjectPath(rootDirectory, changedPath)) return;
15256
15515
  if (isProjectDirectory(rootDirectory, changedPath)) watchDirectory(changedPath);
15257
15516
  else if (!exists(changedPath)) closeDescendants(changedPath);
@@ -15262,17 +15521,17 @@ function createProjectFileWatcher(options) {
15262
15521
  reportError(error);
15263
15522
  return;
15264
15523
  }
15265
- watches.set(directory, { directory, canonicalDirectory: canonicalDirectory2, watcher: directoryWatcher });
15524
+ watches.set(directory2, { directory: directory2, canonicalDirectory: canonicalDirectory2, watcher: directoryWatcher });
15266
15525
  pendingScans += 1;
15267
- scanQueue = scanQueue.then(() => scanSubdirectories(directory)).catch(reportError).finally(() => {
15526
+ scanQueue = scanQueue.then(() => scanSubdirectories(directory2)).catch(reportError).finally(() => {
15268
15527
  pendingScans -= 1;
15269
15528
  if (pendingScans === 0) resolveReady?.();
15270
15529
  });
15271
15530
  };
15272
- const scanSubdirectories = async (directory) => {
15531
+ const scanSubdirectories = async (directory2) => {
15273
15532
  let entries;
15274
15533
  try {
15275
- entries = await readdir2(directory, { withFileTypes: true });
15534
+ entries = await readdir2(directory2, { withFileTypes: true });
15276
15535
  } catch {
15277
15536
  return;
15278
15537
  }
@@ -15280,7 +15539,7 @@ function createProjectFileWatcher(options) {
15280
15539
  for (const entry of entries) {
15281
15540
  if (closed) return;
15282
15541
  if (!entry.isDirectory() || isExcludedDirectoryName(entry.name)) continue;
15283
- const child = join4(directory, entry.name);
15542
+ const child = join5(directory2, entry.name);
15284
15543
  if (!isProjectPath(rootDirectory, child)) continue;
15285
15544
  watchDirectory(child);
15286
15545
  }
@@ -15304,7 +15563,7 @@ function createProjectFileWatcher(options) {
15304
15563
  timer = null;
15305
15564
  }
15306
15565
  pending.clear();
15307
- for (const directory of [...watches.keys()]) closeDirectory(directory);
15566
+ for (const directory2 of [...watches.keys()]) closeDirectory(directory2);
15308
15567
  await scanQueue;
15309
15568
  }
15310
15569
  };
@@ -15342,24 +15601,24 @@ function isProjectPath(rootDirectory, path) {
15342
15601
  function canonicalProjectPath(rootDirectory, path) {
15343
15602
  try {
15344
15603
  const canonical = realpathSync(path);
15345
- return isWithin(rootDirectory, canonical) && !isSensitiveProjectPath(relative2(rootDirectory, canonical).split(sep2).join("/")) ? canonical : null;
15604
+ return isWithin(rootDirectory, canonical) && !isSensitiveProjectPath(relative3(rootDirectory, canonical).split(sep3).join("/")) ? canonical : null;
15346
15605
  } catch {
15347
15606
  const parent = dirname3(path);
15348
15607
  if (parent === path) return null;
15349
15608
  try {
15350
15609
  const canonicalParent = realpathSync(parent);
15351
- return isWithin(rootDirectory, canonicalParent) && !isSensitiveProjectPath(relative2(rootDirectory, canonicalParent).split(sep2).join("/")) ? canonicalParent : null;
15610
+ return isWithin(rootDirectory, canonicalParent) && !isSensitiveProjectPath(relative3(rootDirectory, canonicalParent).split(sep3).join("/")) ? canonicalParent : null;
15352
15611
  } catch {
15353
15612
  return null;
15354
15613
  }
15355
15614
  }
15356
15615
  }
15357
15616
  function isExcludedDirectory(rootDirectory, path) {
15358
- return relative2(rootDirectory, resolve2(path)).split(sep2).some((segment) => isExcludedDirectoryName(segment));
15617
+ return relative3(rootDirectory, resolve2(path)).split(sep3).some((segment) => isExcludedDirectoryName(segment));
15359
15618
  }
15360
15619
  function isWithin(rootDirectory, candidate) {
15361
- const pathFromRoot = relative2(rootDirectory, candidate);
15362
- return pathFromRoot === "" || !pathFromRoot.startsWith(`..${sep2}`) && pathFromRoot !== ".." && !isAbsolute2(pathFromRoot);
15620
+ const pathFromRoot = relative3(rootDirectory, candidate);
15621
+ return pathFromRoot === "" || !pathFromRoot.startsWith(`..${sep3}`) && pathFromRoot !== ".." && !isAbsolute3(pathFromRoot);
15363
15622
  }
15364
15623
  function comparePosixStrings2(a, b) {
15365
15624
  return Buffer.from(a, "utf8").compare(Buffer.from(b, "utf8"));
@@ -15380,15 +15639,15 @@ function createStandaloneServer(options) {
15380
15639
  validatePort(port);
15381
15640
  const clientPath = options.clientPath;
15382
15641
  const projectId = options.projectId ?? createStandaloneProjectId(rootDirectory);
15383
- let revision = 0;
15642
+ let revision2 = 0;
15384
15643
  let manifest = createStandaloneRuntimeManifest(
15385
15644
  projectId,
15386
15645
  EMPTY_PROJECT_TOKEN_SNAPSHOT,
15387
- revision
15646
+ revision2
15388
15647
  );
15389
15648
  let projectBridge = null;
15390
15649
  const initialTokens = createProjectTokenSnapshot({ rootDirectory, generationLabel: "static-html" }).then((tokens) => {
15391
- manifest = createStandaloneRuntimeManifest(projectId, tokens, revision);
15650
+ manifest = createStandaloneRuntimeManifest(projectId, tokens, revision2);
15392
15651
  return tokens;
15393
15652
  });
15394
15653
  void initialTokens.catch(() => void 0);
@@ -15404,7 +15663,7 @@ function createStandaloneServer(options) {
15404
15663
  };
15405
15664
  const notifyReload = () => {
15406
15665
  const payload = `event: reload
15407
- data: ${JSON.stringify({ revision })}
15666
+ data: ${JSON.stringify({ revision: revision2 })}
15408
15667
 
15409
15668
  `;
15410
15669
  for (const client of [...reloadClients]) {
@@ -15424,10 +15683,10 @@ data: ${JSON.stringify({ revision })}
15424
15683
  changeQueue = changeQueue.then(async () => {
15425
15684
  const tokens = await createProjectTokenSnapshot({ rootDirectory, generationLabel: "static-html" });
15426
15685
  manifest = {
15427
- ...createStandaloneRuntimeManifest(projectId, tokens, revision + 1),
15686
+ ...createStandaloneRuntimeManifest(projectId, tokens, revision2 + 1),
15428
15687
  ...projectBridge ? { agentBridge: projectBridge.browser } : {}
15429
15688
  };
15430
- revision += 1;
15689
+ revision2 += 1;
15431
15690
  notifyReload();
15432
15691
  }).catch((error) => {
15433
15692
  console.warn(
@@ -15498,6 +15757,7 @@ data: ${JSON.stringify({ revision })}
15498
15757
  appRoot: rootDirectory,
15499
15758
  projectId,
15500
15759
  origin: address.url.replace(/\/$/, ""),
15760
+ info: (message) => console.info(message),
15501
15761
  warn: (message) => console.warn(message)
15502
15762
  }).then((bridge) => {
15503
15763
  projectBridge = bridge;
@@ -15561,7 +15821,7 @@ function resolveDecodedStaticFile(root2, decodedPath) {
15561
15821
  let filePath = canonicalCandidate;
15562
15822
  const stats = statSync2(filePath);
15563
15823
  if (stats.isDirectory()) {
15564
- const indexCandidate = join5(filePath, "index.html");
15824
+ const indexCandidate = join6(filePath, "index.html");
15565
15825
  const canonicalIndex = canonicalExistingAncestor(indexCandidate);
15566
15826
  if (!canonicalIndex || !isWithin2(root2, canonicalIndex) || !existsSync3(indexCandidate)) {
15567
15827
  return null;
@@ -15571,13 +15831,13 @@ function resolveDecodedStaticFile(root2, decodedPath) {
15571
15831
  } else if (!stats.isFile()) {
15572
15832
  return null;
15573
15833
  }
15574
- const relativePath = relative3(root2, filePath).split("\\").join("/");
15834
+ const relativePath = relative4(root2, filePath).split("\\").join("/");
15575
15835
  if (isSensitiveProjectPath(relativePath)) return null;
15576
15836
  return { absolutePath: filePath, projectPath: relativePath };
15577
15837
  }
15578
15838
  function createStandaloneProjectId(rootDirectory) {
15579
15839
  const canonicalRoot2 = canonicalDirectory(rootDirectory);
15580
- const digest = createHash2("sha256").update(canonicalRoot2).digest("hex").slice(0, 24);
15840
+ const digest = createHash3("sha256").update(canonicalRoot2).digest("hex").slice(0, 24);
15581
15841
  return `static-html:${digest}`;
15582
15842
  }
15583
15843
  function contentTypeForPath(filePath) {
@@ -15587,15 +15847,15 @@ function contentTypeForPath(filePath) {
15587
15847
  function isReservedNudgeUiRoute2(pathname) {
15588
15848
  return pathname === NUDGE_UI_ROUTE_PREFIX.slice(0, -1) || pathname.startsWith(NUDGE_UI_ROUTE_PREFIX);
15589
15849
  }
15590
- function canonicalDirectory(directory) {
15591
- const canonical = canonicalDirectoryOrNull(directory);
15592
- if (!canonical) throw new Error(`Standalone root is not a readable directory: ${directory}`);
15850
+ function canonicalDirectory(directory2) {
15851
+ const canonical = canonicalDirectoryOrNull(directory2);
15852
+ if (!canonical) throw new Error(`Standalone root is not a readable directory: ${directory2}`);
15593
15853
  return canonical;
15594
15854
  }
15595
- function canonicalDirectoryOrNull(directory) {
15596
- if (!isAbsolute3(directory)) return null;
15855
+ function canonicalDirectoryOrNull(directory2) {
15856
+ if (!isAbsolute4(directory2)) return null;
15597
15857
  try {
15598
- const canonical = realpathSync2(directory);
15858
+ const canonical = realpathSync2(directory2);
15599
15859
  return statSync2(canonical).isDirectory() ? canonical : null;
15600
15860
  } catch {
15601
15861
  return null;
@@ -15653,11 +15913,12 @@ function isMissingPathError(error) {
15653
15913
  return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
15654
15914
  }
15655
15915
  function isWithin2(root2, candidate) {
15656
- const pathFromRoot = relative3(root2, candidate);
15657
- return pathFromRoot === "" || !pathFromRoot.startsWith("..") && !isAbsolute3(pathFromRoot);
15916
+ const pathFromRoot = relative4(root2, candidate);
15917
+ return pathFromRoot === "" || !pathFromRoot.startsWith("..") && !isAbsolute4(pathFromRoot);
15658
15918
  }
15659
15919
  async function handleRequest(input) {
15660
15920
  const { request, response } = input;
15921
+ if (await handleHtmlArtifactRequest(request, response, input.rootDirectory)) return;
15661
15922
  if (request.method !== "GET" && request.method !== "HEAD") {
15662
15923
  sendText(response, 405, "Method Not Allowed", { Allow: "GET, HEAD" });
15663
15924
  return;
@@ -15672,8 +15933,8 @@ async function handleRequest(input) {
15672
15933
  return;
15673
15934
  }
15674
15935
  if (isNudgeUiEditorDocumentRequest(request.url ?? "/", request.method, request.headers)) {
15675
- const body2 = request.method === "HEAD" ? Buffer.alloc(0) : Buffer.from(createNudgeUiEditorDocument(), "utf8");
15676
- sendBody(response, 200, body2, "text/html; charset=utf-8", { "Cache-Control": "no-store" });
15936
+ const body3 = request.method === "HEAD" ? Buffer.alloc(0) : Buffer.from(createNudgeUiEditorDocument(), "utf8");
15937
+ sendBody(response, 200, body3, "text/html; charset=utf-8", { "Cache-Control": "no-store" });
15677
15938
  return;
15678
15939
  }
15679
15940
  const resolution = resolveDecodedStaticFile(input.rootDirectory, decodedPath);
@@ -15684,7 +15945,7 @@ async function handleRequest(input) {
15684
15945
  const isHtml = HTML_EXTENSIONS.has(extname2(resolution.projectPath).toLowerCase());
15685
15946
  const contentType = contentTypeForPath(resolution.projectPath);
15686
15947
  if (request.method === "HEAD") {
15687
- const body2 = await readProjectFile(resolution.absolutePath);
15948
+ const body3 = await readProjectFile(resolution.absolutePath);
15688
15949
  if (isHtml) {
15689
15950
  response.writeHead(200, {
15690
15951
  "Content-Type": contentType,
@@ -15693,25 +15954,25 @@ async function handleRequest(input) {
15693
15954
  });
15694
15955
  response.end();
15695
15956
  } else {
15696
- sendBody(response, 200, body2, contentType);
15957
+ sendBody(response, 200, body3, contentType);
15697
15958
  }
15698
15959
  return;
15699
15960
  }
15700
- let body = await readProjectFile(resolution.absolutePath);
15961
+ let body2 = await readProjectFile(resolution.absolutePath);
15701
15962
  if (isHtml) {
15702
- body = instrumentHtmlResponse(body, resolution.projectPath);
15963
+ body2 = instrumentHtmlResponse(body2, resolution.projectPath);
15703
15964
  }
15704
- sendBody(response, 200, body, contentType, isHtml ? { "Cache-Control": "no-cache" } : {});
15965
+ sendBody(response, 200, body2, contentType, isHtml ? { "Cache-Control": "no-cache" } : {});
15705
15966
  }
15706
- function instrumentHtmlResponse(body, projectPath) {
15967
+ function instrumentHtmlResponse(body2, projectPath) {
15707
15968
  let source;
15708
15969
  try {
15709
- source = strictUtf8Decoder.decode(body);
15970
+ source = strictUtf8Decoder.decode(body2);
15710
15971
  } catch {
15711
15972
  console.warn(
15712
15973
  `Nudge UI served ${projectPath} without instrumentation because it is not valid UTF-8.`
15713
15974
  );
15714
- return body;
15975
+ return body2;
15715
15976
  }
15716
15977
  const identified = instrumentSourceHtml(source, projectPath);
15717
15978
  const bootstrapped = injectStandaloneBootstrap(identified.html);
@@ -15720,23 +15981,23 @@ function instrumentHtmlResponse(body, projectPath) {
15720
15981
  var strictUtf8Decoder = new TextDecoder("utf-8", { fatal: true });
15721
15982
  async function handleNudgeUiRoute(input, pathname) {
15722
15983
  if (pathname === NUDGE_UI_MANIFEST_PATH) {
15723
- const body = Buffer.from(JSON.stringify(input.getManifest()), "utf8");
15724
- sendBody(input.response, 200, body, "application/json; charset=utf-8", {
15984
+ const body2 = Buffer.from(JSON.stringify(input.getManifest()), "utf8");
15985
+ sendBody(input.response, 200, body2, "application/json; charset=utf-8", {
15725
15986
  "Cache-Control": "no-store"
15726
15987
  });
15727
15988
  return;
15728
15989
  }
15729
15990
  if (pathname === NUDGE_UI_EDITOR_PATH) {
15730
- const body = input.request.method === "HEAD" ? Buffer.alloc(0) : Buffer.from(createNudgeUiEditorDocument(), "utf8");
15731
- sendBody(input.response, 200, body, "text/html; charset=utf-8", {
15991
+ const body2 = input.request.method === "HEAD" ? Buffer.alloc(0) : Buffer.from(createNudgeUiEditorDocument(), "utf8");
15992
+ sendBody(input.response, 200, body2, "text/html; charset=utf-8", {
15732
15993
  "Cache-Control": "no-store"
15733
15994
  });
15734
15995
  return;
15735
15996
  }
15736
15997
  if (pathname === NUDGE_UI_CLIENT_PATH) {
15737
15998
  try {
15738
- const body = await readFileFromDescriptor(input.clientPath ?? resolveDefaultClientPath());
15739
- sendBody(input.response, 200, body, "text/javascript; charset=utf-8", {
15999
+ const body2 = await readFileFromDescriptor(input.clientPath ?? resolveDefaultClientPath());
16000
+ sendBody(input.response, 200, body2, "text/javascript; charset=utf-8", {
15740
16001
  "Cache-Control": "no-cache"
15741
16002
  });
15742
16003
  } catch {
@@ -15813,14 +16074,14 @@ function validatePort(port) {
15813
16074
  function sendText(response, status, text, headers = {}) {
15814
16075
  sendBody(response, status, Buffer.from(text, "utf8"), "text/plain; charset=utf-8", headers);
15815
16076
  }
15816
- function sendBody(response, status, body, contentType, headers = {}) {
16077
+ function sendBody(response, status, body2, contentType, headers = {}) {
15817
16078
  response.writeHead(status, {
15818
16079
  "Content-Type": contentType,
15819
- "Content-Length": body.byteLength,
16080
+ "Content-Length": body2.byteLength,
15820
16081
  "X-Content-Type-Options": "nosniff",
15821
16082
  ...headers
15822
16083
  });
15823
- if (response.req?.method !== "HEAD") response.end(body);
16084
+ if (response.req?.method !== "HEAD") response.end(body2);
15824
16085
  else response.end();
15825
16086
  }
15826
16087
  var MIME_TYPES2 = {
@@ -15856,7 +16117,7 @@ function parseServeArguments(args, currentDirectory = process.cwd()) {
15856
16117
  if (args[0] !== "serve") {
15857
16118
  throw new Error("Usage: nudge-ui serve [directory] [--port <port>] [--host <loopback>]");
15858
16119
  }
15859
- let directory = ".";
16120
+ let directory2 = ".";
15860
16121
  let host = "127.0.0.1";
15861
16122
  let port = 4173;
15862
16123
  let directoryProvided = false;
@@ -15873,13 +16134,13 @@ function parseServeArguments(args, currentDirectory = process.cwd()) {
15873
16134
  } else if (argument.startsWith("-")) {
15874
16135
  throw new Error(`Unknown option: ${argument}`);
15875
16136
  } else if (!directoryProvided) {
15876
- directory = argument;
16137
+ directory2 = argument;
15877
16138
  directoryProvided = true;
15878
16139
  } else {
15879
16140
  throw new Error(`Unexpected argument: ${argument}`);
15880
16141
  }
15881
16142
  }
15882
- return { rootDirectory: resolve4(currentDirectory, directory), host, port };
16143
+ return { rootDirectory: resolve4(currentDirectory, directory2), host, port };
15883
16144
  }
15884
16145
  async function runServeCommand(options) {
15885
16146
  const server = createStandaloneServer(options);