nudge-ui 0.2.2 → 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 (226) hide show
  1. package/README.md +164 -46
  2. package/dist/client.mjs +252 -61
  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 +38 -32
  7. package/dist/hosts/astro/integration.js +5 -1
  8. package/dist/hosts/astro/markdownIdentity.d.ts +28 -0
  9. package/dist/hosts/astro/markdownIdentity.js +81 -0
  10. package/dist/hosts/next/manifest.js +1 -1
  11. package/dist/hosts/next/sidecar.js +5 -1
  12. package/dist/hosts/static/manifest.js +1 -1
  13. package/dist/hosts/static/server.js +3 -0
  14. package/dist/hosts/vite/vite.d.ts +3 -0
  15. package/dist/hosts/vite/vite.js +24 -4
  16. package/dist/inspector/agent/McpConnectionDialog.js +13 -19
  17. package/dist/inspector/agent/activity.d.ts +18 -0
  18. package/dist/inspector/agent/activity.js +70 -0
  19. package/dist/inspector/agent/client.d.ts +2 -0
  20. package/dist/inspector/agent/client.js +29 -1
  21. package/dist/inspector/agent/connectionStatus.js +1 -1
  22. package/dist/inspector/agent/httpTransport.js +9 -2
  23. package/dist/inspector/agent/protocol.d.ts +6 -3
  24. package/dist/inspector/agent/protocol.js +1 -1
  25. package/dist/inspector/agent/verification.d.ts +11 -1
  26. package/dist/inspector/agent/verification.js +53 -25
  27. package/dist/inspector/canvas/AgentActivityOverlay.d.ts +13 -0
  28. package/dist/inspector/canvas/AgentActivityOverlay.js +111 -0
  29. package/dist/inspector/canvas/CanvasCard.d.ts +9 -2
  30. package/dist/inspector/canvas/CanvasCard.js +133 -38
  31. package/dist/inspector/canvas/CanvasElementOverlay.js +152 -16
  32. package/dist/inspector/canvas/CanvasToolIcons.d.ts +10 -0
  33. package/dist/inspector/canvas/CanvasToolIcons.js +20 -0
  34. package/dist/inspector/canvas/CanvasToolbar.js +8 -4
  35. package/dist/inspector/canvas/CanvasWorkspace.js +225 -57
  36. package/dist/inspector/canvas/StaleChangeIndicator.js +3 -13
  37. package/dist/inspector/canvas/agentPresentation.d.ts +8 -8
  38. package/dist/inspector/canvas/agentPresentation.js +64 -52
  39. package/dist/inspector/canvas/canvasGestures.d.ts +1 -1
  40. package/dist/inspector/canvas/canvasGestures.js +1 -1
  41. package/dist/inspector/canvas/canvasStore.d.ts +46 -82
  42. package/dist/inspector/canvas/canvasStore.js +251 -284
  43. package/dist/inspector/canvas/frameContent.d.ts +21 -0
  44. package/dist/inspector/canvas/frameContent.js +44 -0
  45. package/dist/inspector/canvas/frameProtocol.d.ts +21 -4
  46. package/dist/inspector/canvas/frameProtocol.js +3 -3
  47. package/dist/inspector/canvas/keyboardShortcuts.d.ts +3 -1
  48. package/dist/inspector/canvas/keyboardShortcuts.js +4 -4
  49. package/dist/inspector/canvas/layout.d.ts +52 -0
  50. package/dist/inspector/canvas/layout.js +106 -0
  51. package/dist/inspector/canvas/projection.d.ts +15 -5
  52. package/dist/inspector/canvas/projection.js +69 -13
  53. package/dist/inspector/canvas/rendererBootstrap.js +32 -4
  54. package/dist/inspector/canvas/rendererElementSelector.js +47 -6
  55. package/dist/inspector/canvas/rendererStylesheet.js +2 -2
  56. package/dist/inspector/canvas/resizeHandleScale.js +1 -1
  57. package/dist/inspector/canvas/sessionStore.d.ts +11 -26
  58. package/dist/inspector/canvas/sessionStore.js +43 -183
  59. package/dist/inspector/canvas/staleChangeDetector.js +9 -3
  60. package/dist/inspector/canvas/useCanvasLayoutAnimation.d.ts +5 -0
  61. package/dist/inspector/canvas/useCanvasLayoutAnimation.js +107 -0
  62. package/dist/inspector/canvas/viewStore.d.ts +38 -0
  63. package/dist/inspector/canvas/viewStore.js +104 -0
  64. package/dist/inspector/canvas/wheelPan.d.ts +8 -0
  65. package/dist/inspector/canvas/wheelPan.js +8 -0
  66. package/dist/inspector/changes/changesLog.d.ts +6 -5
  67. package/dist/inspector/changes/changesLog.js +40 -32
  68. package/dist/inspector/changes/draftChanges.d.ts +56 -0
  69. package/dist/inspector/changes/draftChanges.js +300 -0
  70. package/dist/inspector/changes/previewDiagnostics.d.ts +4 -2
  71. package/dist/inspector/changes/previewDiagnostics.js +11 -25
  72. package/dist/inspector/clientManifest.d.ts +1 -1
  73. package/dist/inspector/comments/CommentsOverlay.d.ts +2 -0
  74. package/dist/inspector/comments/CommentsOverlay.js +250 -0
  75. package/dist/inspector/comments/element.d.ts +6 -0
  76. package/dist/inspector/comments/element.js +47 -0
  77. package/dist/inspector/comments/store.d.ts +29 -0
  78. package/dist/inspector/comments/store.js +121 -0
  79. package/dist/inspector/comments/verification.d.ts +5 -0
  80. package/dist/inspector/comments/verification.js +52 -0
  81. package/dist/inspector/drafts/model.d.ts +35 -0
  82. package/dist/inspector/drafts/model.js +45 -0
  83. package/dist/inspector/drafts/store.d.ts +28 -0
  84. package/dist/inspector/drafts/store.js +231 -0
  85. package/dist/inspector/index.js +20 -27
  86. package/dist/inspector/inline-text/inlineTextEditor.js +7 -0
  87. package/dist/inspector/inspection/useBrowserCssInspection.js +15 -1
  88. package/dist/inspector/iterations/capture.d.ts +2 -0
  89. package/dist/inspector/iterations/capture.js +173 -0
  90. package/dist/inspector/iterations/client.d.ts +7 -0
  91. package/dist/inspector/iterations/client.js +52 -0
  92. package/dist/inspector/iterations/coordinator.d.ts +15 -0
  93. package/dist/inspector/iterations/coordinator.js +130 -0
  94. package/dist/inspector/iterations/prompt.d.ts +3 -0
  95. package/dist/inspector/iterations/prompt.js +26 -0
  96. package/dist/inspector/overlay/DomNavigator.js +21 -15
  97. package/dist/inspector/overlay/interactionStyles.js +3 -1
  98. package/dist/inspector/overlay/spacingGestures.d.ts +13 -1
  99. package/dist/inspector/overlay/spacingGestures.js +82 -5
  100. package/dist/inspector/projection/{workspaceProjection.d.ts → draftProjection.d.ts} +6 -6
  101. package/dist/inspector/projection/{workspaceProjection.js → draftProjection.js} +4 -4
  102. package/dist/inspector/projection/renderedInstance.d.ts +2 -1
  103. package/dist/inspector/projection/renderedInstance.js +9 -5
  104. package/dist/inspector/projection/structuralProjection.d.ts +2 -1
  105. package/dist/inspector/projection/structuralProjection.js +19 -15
  106. package/dist/inspector/projection/textProjection.d.ts +2 -1
  107. package/dist/inspector/projection/textProjection.js +8 -4
  108. package/dist/inspector/prompt/PromptSettingsDialog.js +1 -5
  109. package/dist/inspector/prompt/clipboardHandoff.d.ts +10 -18
  110. package/dist/inspector/prompt/clipboardHandoff.js +92 -143
  111. package/dist/inspector/prompt/generatePrompt.d.ts +4 -1
  112. package/dist/inspector/prompt/generatePrompt.js +17 -16
  113. package/dist/inspector/runtime/runtimeConfig.d.ts +9 -0
  114. package/dist/inspector/runtime/runtimeConfig.js +24 -0
  115. package/dist/inspector/settings/SettingsDialog.js +21 -8
  116. package/dist/inspector/shell/AgentStatusButton.d.ts +11 -0
  117. package/dist/inspector/shell/AgentStatusButton.js +36 -0
  118. package/dist/inspector/shell/AppShell.js +4 -2
  119. package/dist/inspector/shell/ChangesLog.js +46 -26
  120. package/dist/inspector/shell/CopyPromptButton.js +138 -89
  121. package/dist/inspector/shell/EmptyState.js +9 -8
  122. package/dist/inspector/shell/InspectorShell.js +13 -21
  123. package/dist/inspector/shell/PeekOriginalButton.js +24 -23
  124. package/dist/inspector/shell/originalPreview.js +5 -5
  125. package/dist/inspector/shell/shortcuts.d.ts +3 -0
  126. package/dist/inspector/shell/shortcuts.js +11 -0
  127. package/dist/inspector/sketch/SketchEditor.js +14 -14
  128. package/dist/inspector/sketch/SketchEntryButton.js +1 -1
  129. package/dist/inspector/sketch/SketchFrameOverlay.d.ts +3 -1
  130. package/dist/inspector/sketch/SketchFrameOverlay.js +11 -8
  131. package/dist/inspector/sketch/SketchLayersPanel.js +13 -5
  132. package/dist/inspector/sketch/SketchOverlay.js +7 -7
  133. package/dist/inspector/sketch/SketchWorkspace.js +18 -12
  134. package/dist/inspector/sketch/interaction.d.ts +1 -0
  135. package/dist/inspector/sketch/interaction.js +8 -4
  136. package/dist/inspector/sketch/model.d.ts +5 -0
  137. package/dist/inspector/sketch/model.js +6 -2
  138. package/dist/inspector/sketch/raster.d.ts +1 -2
  139. package/dist/inspector/sketch/raster.js +68 -4
  140. package/dist/inspector/styleEditors/BackgroundEditor.d.ts +4 -0
  141. package/dist/inspector/styleEditors/BackgroundEditor.js +195 -0
  142. package/dist/inspector/styleEditors/BorderEditor.js +49 -78
  143. package/dist/inspector/styleEditors/BorderRadiusEditor.js +6 -1
  144. package/dist/inspector/styleEditors/BoxShadowEditor.d.ts +1 -2
  145. package/dist/inspector/styleEditors/BoxShadowEditor.js +132 -4
  146. package/dist/inspector/styleEditors/ColorPicker.d.ts +5 -1
  147. package/dist/inspector/styleEditors/ColorPicker.js +10 -4
  148. package/dist/inspector/styleEditors/GapField.js +3 -5
  149. package/dist/inspector/styleEditors/GridChildSection.d.ts +1 -1
  150. package/dist/inspector/styleEditors/GridChildSection.js +18 -9
  151. package/dist/inspector/styleEditors/GridPicker.d.ts +1 -1
  152. package/dist/inspector/styleEditors/GridPicker.js +8 -2
  153. package/dist/inspector/styleEditors/GridSection.js +1 -1
  154. package/dist/inspector/styleEditors/GridValueField.js +19 -14
  155. package/dist/inspector/styleEditors/ImageBackgroundEditor.d.ts +18 -0
  156. package/dist/inspector/styleEditors/ImageBackgroundEditor.js +118 -0
  157. package/dist/inspector/styleEditors/LayoutBlockedIndicator.d.ts +2 -2
  158. package/dist/inspector/styleEditors/LayoutBlockedIndicator.js +3 -3
  159. package/dist/inspector/styleEditors/LayoutComboField.js +6 -4
  160. package/dist/inspector/styleEditors/LayoutDropdown.js +6 -3
  161. package/dist/inspector/styleEditors/LayoutSection.js +32 -11
  162. package/dist/inspector/styleEditors/SpacingBox.js +7 -5
  163. package/dist/inspector/styleEditors/Typography.js +11 -3
  164. package/dist/inspector/styleEditors/backgroundLayers.d.ts +24 -0
  165. package/dist/inspector/styleEditors/backgroundLayers.js +51 -0
  166. package/dist/inspector/styleEditors/gradientValue.d.ts +17 -0
  167. package/dist/inspector/styleEditors/gradientValue.js +114 -0
  168. package/dist/inspector/styleEditors/inlineAuthored.d.ts +10 -0
  169. package/dist/inspector/styleEditors/inlineAuthored.js +114 -0
  170. package/dist/inspector/styleEditors/layoutValue.d.ts +0 -8
  171. package/dist/inspector/styleEditors/layoutValue.js +0 -42
  172. package/dist/inspector/styleEditors/nudgeValue.d.ts +2 -2
  173. package/dist/inspector/styleEditors/nudgeValue.js +36 -8
  174. package/dist/inspector/tokens/TokenField.d.ts +7 -0
  175. package/dist/inspector/tokens/TokenField.js +29 -21
  176. package/dist/inspector/tokens/TokenLabel.js +5 -14
  177. package/dist/inspector/tokens/editActions.d.ts +1 -1
  178. package/dist/inspector/tokens/editActions.js +1 -1
  179. package/dist/inspector/ui/AtRuleContext.js +4 -6
  180. package/dist/inspector/ui/Button.d.ts +6 -2
  181. package/dist/inspector/ui/Button.js +4 -3
  182. package/dist/inspector/ui/ControlSurface.d.ts +2 -2
  183. package/dist/inspector/ui/ControlSurface.js +4 -3
  184. package/dist/inspector/ui/InlineStyleWarning.d.ts +11 -0
  185. package/dist/inspector/ui/InlineStyleWarning.js +13 -0
  186. package/dist/inspector/ui/InspectorPopover.d.ts +2 -1
  187. package/dist/inspector/ui/InspectorPopover.js +4 -5
  188. package/dist/inspector/ui/PopoverListbox.d.ts +2 -1
  189. package/dist/inspector/ui/PopoverListbox.js +8 -7
  190. package/dist/inspector/ui/SegmentedControl.d.ts +2 -1
  191. package/dist/inspector/ui/SegmentedControl.js +2 -2
  192. package/dist/inspector/ui/Select.d.ts +6 -1
  193. package/dist/inspector/ui/Select.js +7 -11
  194. package/dist/inspector/ui/SideValuesField.js +1 -1
  195. package/dist/inspector/ui/Tooltip.d.ts +26 -0
  196. package/dist/inspector/ui/Tooltip.js +32 -0
  197. package/dist/inspector/ui/classNames.d.ts +2 -0
  198. package/dist/inspector/ui/classNames.js +4 -0
  199. package/dist/inspector/ui/customCursors.d.ts +23 -0
  200. package/dist/inspector/ui/customCursors.js +122 -0
  201. package/dist/inspector/ui/dragCursor.d.ts +0 -2
  202. package/dist/inspector/ui/dragCursor.js +2 -10
  203. package/dist/inspector/ui/portalContainer.d.ts +2 -0
  204. package/dist/inspector/ui/portalContainer.js +6 -0
  205. package/dist/inspector/ui/styles.js +29 -21
  206. package/dist/inspector/workspace/commands.d.ts +9 -0
  207. package/dist/inspector/workspace/commands.js +82 -0
  208. package/dist/inspector/workspace/controller.d.ts +4 -0
  209. package/dist/inspector/workspace/controller.js +66 -0
  210. package/dist/inspector/workspace/handoff.d.ts +42 -0
  211. package/dist/inspector/workspace/handoff.js +115 -0
  212. package/dist/inspector/workspace/timeline.d.ts +30 -0
  213. package/dist/inspector/workspace/timeline.js +108 -0
  214. package/dist/internal/agent-protocol.d.ts +19 -2
  215. package/dist/internal/agent-protocol.js +13 -0
  216. package/dist/nudge-ui.mjs +558 -311
  217. package/dist/project/artifacts.d.ts +13 -0
  218. package/dist/project/artifacts.js +253 -0
  219. package/dist/transport/artifacts.d.ts +8 -0
  220. package/dist/transport/artifacts.js +9 -0
  221. package/dist/transport/editor.js +3 -1
  222. package/dist/transport/routes.d.ts +2 -0
  223. package/dist/transport/routes.js +2 -0
  224. package/package.json +6 -2
  225. package/dist/inspector/changes/workspaceChanges.d.ts +0 -47
  226. package/dist/inspector/changes/workspaceChanges.js +0 -265
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,180 +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/environment.ts
14312
- function readNudgeUiEnvironmentSwitch(env = process.env) {
14313
- const value = env.NUDGE_UI?.trim().toLowerCase();
14314
- if (value === "0" || value === "false" || value === "off") return "off";
14315
- if (value === "1" || value === "true" || value === "on") return "on";
14316
- return null;
14317
- }
14318
- function automationManifestFields(env = process.env) {
14319
- return readNudgeUiEnvironmentSwitch(env) === "on" ? { inspectAutomatedBrowsers: true } : {};
14320
- }
14321
-
14322
- // src/hosts/static/manifest.ts
14323
- function createStandaloneRuntimeManifest(projectId, tokenSnapshot = emptyTokenSnapshot(), revision = 0) {
14324
- return {
14325
- version: NUDGE_UI_MANIFEST_VERSION,
14326
- revision,
14327
- runtime: {
14328
- projectId,
14329
- host: "static-html",
14330
- framework: "HTML",
14331
- stylingSystem: "CSS custom properties",
14332
- // Canvas shares the Vite host's controller/renderer runtime (ADR-0012):
14333
- // every served document carries the bootstrap, so card iframes boot as
14334
- // renderers without host-specific code.
14335
- capabilities: { canvas: true, componentSemantics: false },
14336
- tokenCatalog: tokenSnapshot.tokenCatalog,
14337
- tokens: tokenSnapshot.tokens,
14338
- tokenDiagnostics: tokenSnapshot.tokenDiagnostics,
14339
- tokenGeneration: tokenSnapshot.tokenGeneration,
14340
- componentContracts: []
14341
- },
14342
- document: {
14343
- runtimeIdentity: "static-html",
14344
- stylesheetOrder: "browser"
14345
- },
14346
- reload: {
14347
- endpoint: NUDGE_UI_RELOAD_PATH,
14348
- strategy: "reload-document",
14349
- events: ["ready", "reload"]
14350
- },
14351
- ...automationManifestFields()
14352
- };
14353
- }
14354
- function emptyTokenSnapshot() {
14355
- return {
14356
- tokenCatalog: [],
14357
- tokens: [],
14358
- tokenDiagnostics: [],
14359
- tokenGeneration: "empty"
14360
- };
14361
- }
14362
-
14363
- // src/hosts/static/html/bootstrap.ts
14364
- var CLIENT_MARKER = "data-nudge-ui-client";
14365
- var MOUNT_MARKER = "data-nudge-ui-mount";
14366
- function injectStandaloneBootstrap(html, options = {}) {
14367
- const clientPath = options.clientPath ?? NUDGE_UI_CLIENT_PATH;
14368
- const manifestPath = options.manifestPath ?? NUDGE_UI_MANIFEST_PATH;
14369
- const document2 = parse(html, { sourceCodeLocationInfo: true });
14370
- const sourceFacts = inspectSource(document2, clientPath);
14371
- const nodes = [];
14372
- if (!sourceFacts.hasMount) {
14373
- nodes.push(
14374
- `<div id="${NUDGE_UI_MOUNT_ID}" ${MOUNT_MARKER}></div>`
14375
- );
14376
- }
14377
- if (!sourceFacts.hasClient) {
14378
- nodes.push(
14379
- `<script type="module" src="${escapeAttributeValue2(clientPath)}" ${CLIENT_MARKER} data-nudge-ui-manifest="${escapeAttributeValue2(manifestPath)}"></script>`
14380
- );
14381
- }
14382
- if (nodes.length === 0) return { html, injected: false };
14383
- const injection = `
14384
- ${nodes.join("\n")}
14385
- `;
14386
- const offset = sourceFacts.bodyEndOffset ?? sourceFacts.htmlEndOffset ?? html.length;
14387
- return {
14388
- html: `${html.slice(0, offset)}${injection}${html.slice(offset)}`,
14389
- injected: true
14390
- };
14391
- }
14392
- function inspectSource(document2, clientPath) {
14393
- const facts = {
14394
- hasMount: false,
14395
- hasClient: false,
14396
- bodyEndOffset: null,
14397
- htmlEndOffset: null
14398
- };
14399
- let body = null;
14400
- visitElements(document2, (element) => {
14401
- if (element.namespaceURI !== "http://www.w3.org/1999/xhtml") return;
14402
- const tagName = element.tagName.toLowerCase();
14403
- if (tagName === "body") body = element;
14404
- if (tagName === "script" && (attributeValue(element, CLIENT_MARKER) !== null || attributeValue(element, "src") === clientPath)) {
14405
- facts.hasClient = true;
14406
- }
14407
- const endOffset = element.sourceCodeLocation?.endTag?.startOffset;
14408
- if (tagName === "body" && endOffset !== void 0) facts.bodyEndOffset = endOffset;
14409
- if (tagName === "html" && endOffset !== void 0) facts.htmlEndOffset = endOffset;
14410
- });
14411
- if (body) {
14412
- visitElements(body, (element) => {
14413
- if (element !== body && attributeValue(element, "id") === NUDGE_UI_MOUNT_ID) {
14414
- facts.hasMount = true;
14415
- }
14416
- });
14417
- }
14418
- return facts;
14419
- }
14420
- function visitElements(parent, visit) {
14421
- for (const child of parent.childNodes) {
14422
- if (!("tagName" in child) || typeof child.tagName !== "string") continue;
14423
- if (child.tagName.toLowerCase() === "template") continue;
14424
- visit(child);
14425
- visitElements(child, visit);
14426
- }
14427
- }
14428
- function attributeValue(element, name) {
14429
- return element.attrs.find((attribute) => attribute.name === name)?.value ?? null;
14430
- }
14431
- function escapeAttributeValue2(value) {
14432
- return value.replaceAll("&", "&amp;").replaceAll('"', "&quot;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
14433
- }
14434
-
14435
14681
  // src/hosts/projectBridge.ts
14436
14682
  import { existsSync as existsSync2 } from "node:fs";
14437
14683
  import { createRequire as createRequire2 } from "node:module";
14438
- 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";
14439
14685
  import { pathToFileURL } from "node:url";
14440
14686
  var runningBridges = /* @__PURE__ */ new Map();
14441
14687
  async function startOptionalProjectBridge(input) {
@@ -14456,7 +14702,7 @@ async function launchOptionalProjectBridge(input, key) {
14456
14702
  runningBridges.delete(key);
14457
14703
  return null;
14458
14704
  }
14459
- 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");
14460
14706
  } catch {
14461
14707
  runningBridges.delete(key);
14462
14708
  return null;
@@ -14498,24 +14744,24 @@ function isPnpRuntime() {
14498
14744
  return typeof process.versions.pnp === "string";
14499
14745
  }
14500
14746
  function hasProjectInstalledMcp(appRoot) {
14501
- let directory = appRoot;
14502
- const root2 = parse2(directory).root;
14747
+ let directory2 = appRoot;
14748
+ const root2 = parse2(directory2).root;
14503
14749
  for (; ; ) {
14504
- if (existsSync2(join2(directory, "node_modules", "@nudge-ui", "mcp", "package.json"))) return true;
14505
- if (directory === root2) return false;
14506
- 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);
14507
14753
  }
14508
14754
  }
14509
14755
 
14510
14756
  // src/project/tokens.ts
14511
- import { createHash } from "node:crypto";
14757
+ import { createHash as createHash2 } from "node:crypto";
14512
14758
  import {
14513
14759
  readFile as readUtf8File,
14514
14760
  readdir,
14515
- realpath,
14761
+ realpath as realpath2,
14516
14762
  stat
14517
14763
  } from "node:fs/promises";
14518
- 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";
14519
14765
 
14520
14766
  // ../../node_modules/.pnpm/postcss@8.5.26/node_modules/postcss/lib/postcss.mjs
14521
14767
  var import_postcss = __toESM(require_postcss(), 1);
@@ -15029,7 +15275,7 @@ var EMPTY_PROJECT_TOKEN_SNAPSHOT = {
15029
15275
  async function createProjectTokenSnapshot(options) {
15030
15276
  const rootDirectory = await canonicalRoot(options.rootDirectory);
15031
15277
  const additionalRoots = (await Promise.all(
15032
- (options.additionalRootDirectories ?? []).map((directory) => canonicalOptionalRoot(directory))
15278
+ (options.additionalRootDirectories ?? []).map((directory2) => canonicalOptionalRoot(directory2))
15033
15279
  )).filter((root2) => root2 !== null);
15034
15280
  const scanRoots = [rootDirectory, ...additionalRoots.filter((root2) => root2 !== rootDirectory)];
15035
15281
  const discovered = await Promise.all(
@@ -15039,12 +15285,12 @@ async function createProjectTokenSnapshot(options) {
15039
15285
  const seenFiles = /* @__PURE__ */ new Set();
15040
15286
  for (let index = 0; index < discovered.length; index += 1) {
15041
15287
  for (const artifact of discovered[index] ?? []) {
15042
- const canonicalPath = await realpath(artifact.absolutePath).catch(() => artifact.absolutePath);
15288
+ const canonicalPath = await realpath2(artifact.absolutePath).catch(() => artifact.absolutePath);
15043
15289
  if (seenFiles.has(canonicalPath)) continue;
15044
15290
  seenFiles.add(canonicalPath);
15045
15291
  artifacts.push({
15046
15292
  ...artifact,
15047
- 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("/")
15048
15294
  });
15049
15295
  }
15050
15296
  }
@@ -15087,32 +15333,32 @@ async function createProjectTokenSnapshot(options) {
15087
15333
  tokenGeneration
15088
15334
  };
15089
15335
  }
15090
- async function discoverProjectCssArtifacts(rootDirectory, readFile = (absolutePath) => readUtf8File(absolutePath, "utf8")) {
15336
+ async function discoverProjectCssArtifacts(rootDirectory, readFile2 = (absolutePath) => readUtf8File(absolutePath, "utf8")) {
15091
15337
  const root2 = await canonicalRoot(rootDirectory);
15092
15338
  const artifacts = [];
15093
15339
  const visitedDirectories = /* @__PURE__ */ new Set();
15094
15340
  const visitedFiles = /* @__PURE__ */ new Set();
15095
- await walkDirectory(root2, root2, visitedDirectories, visitedFiles, artifacts, readFile);
15341
+ await walkDirectory(root2, root2, visitedDirectories, visitedFiles, artifacts, readFile2);
15096
15342
  artifacts.sort((a, b) => comparePosixStrings(a.projectPath, b.projectPath));
15097
15343
  return artifacts;
15098
15344
  }
15099
- async function walkDirectory(rootDirectory, directory, visitedDirectories, visitedFiles, artifacts, readFile) {
15100
- const canonicalDirectoryPath = await canonicalWithinRoot(rootDirectory, directory);
15345
+ async function walkDirectory(rootDirectory, directory2, visitedDirectories, visitedFiles, artifacts, readFile2) {
15346
+ const canonicalDirectoryPath = await canonicalWithinRoot(rootDirectory, directory2);
15101
15347
  if (!canonicalDirectoryPath || visitedDirectories.has(canonicalDirectoryPath)) return;
15102
- const projectDirectoryPath = relative(rootDirectory, directory).split(sep).join("/");
15103
- 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("/");
15104
15350
  if (isSensitiveProjectPath(projectDirectoryPath) || isSensitiveProjectPath(canonicalProjectDirectoryPath)) return;
15105
15351
  visitedDirectories.add(canonicalDirectoryPath);
15106
15352
  let entries;
15107
15353
  try {
15108
- entries = await readdir(directory, { withFileTypes: true });
15354
+ entries = await readdir(directory2, { withFileTypes: true });
15109
15355
  } catch {
15110
15356
  return;
15111
15357
  }
15112
15358
  entries.sort((a, b) => comparePosixStrings(a.name, b.name));
15113
15359
  for (const entry of entries) {
15114
15360
  if (entry.isDirectory() && isExcludedDirectoryName(entry.name)) continue;
15115
- const absolutePath = join3(directory, entry.name);
15361
+ const absolutePath = join4(directory2, entry.name);
15116
15362
  const canonicalPath = await canonicalWithinRoot(rootDirectory, absolutePath);
15117
15363
  if (!canonicalPath) continue;
15118
15364
  let stats;
@@ -15129,20 +15375,20 @@ async function walkDirectory(rootDirectory, directory, visitedDirectories, visit
15129
15375
  visitedDirectories,
15130
15376
  visitedFiles,
15131
15377
  artifacts,
15132
- readFile
15378
+ readFile2
15133
15379
  );
15134
15380
  continue;
15135
15381
  }
15136
15382
  if (!stats.isFile() || extname(entry.name).toLowerCase() !== ".css") continue;
15137
15383
  if (visitedFiles.has(canonicalPath)) continue;
15138
15384
  visitedFiles.add(canonicalPath);
15139
- const projectPath = relative(rootDirectory, absolutePath).split(sep).join("/");
15140
- 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("/");
15141
15387
  if (isSensitiveProjectPath(projectPath) || isSensitiveProjectPath(canonicalProjectPath2)) {
15142
15388
  continue;
15143
15389
  }
15144
15390
  try {
15145
- const content = await readFile(absolutePath);
15391
+ const content = await readFile2(absolutePath);
15146
15392
  artifacts.push({ absolutePath, projectPath, content });
15147
15393
  } catch (error) {
15148
15394
  artifacts.push({
@@ -15154,7 +15400,7 @@ async function walkDirectory(rootDirectory, directory, visitedDirectories, visit
15154
15400
  }
15155
15401
  }
15156
15402
  async function canonicalRoot(rootDirectory) {
15157
- const root2 = await realpath(resolve(rootDirectory));
15403
+ const root2 = await realpath2(resolve(rootDirectory));
15158
15404
  if (!(await stat(root2)).isDirectory()) {
15159
15405
  throw new Error(`Standalone root is not a directory: ${rootDirectory}`);
15160
15406
  }
@@ -15169,9 +15415,9 @@ async function canonicalOptionalRoot(rootDirectory) {
15169
15415
  }
15170
15416
  async function canonicalWithinRoot(rootDirectory, candidate) {
15171
15417
  try {
15172
- const canonical = await realpath(candidate);
15173
- const pathFromRoot = relative(rootDirectory, canonical);
15174
- 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)) {
15175
15421
  return canonical;
15176
15422
  }
15177
15423
  } catch {
@@ -15199,7 +15445,7 @@ function deterministicGeneration(artifacts, inventoryGeneration, label) {
15199
15445
  content: artifact.content,
15200
15446
  readError: artifact.readError
15201
15447
  }));
15202
- const digest = createHash("sha256").update(`${facts.join("\n")}
15448
+ const digest = createHash2("sha256").update(`${facts.join("\n")}
15203
15449
  ${inventoryGeneration}`).digest("hex").slice(0, 24);
15204
15450
  return `${label}:${digest}`;
15205
15451
  }
@@ -15211,7 +15457,7 @@ function comparePosixStrings(a, b) {
15211
15457
  import { watch } from "node:fs";
15212
15458
  import { readdir as readdir2 } from "node:fs/promises";
15213
15459
  import { realpathSync, statSync } from "node:fs";
15214
- 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";
15215
15461
  function createProjectFileWatcher(options) {
15216
15462
  const rootDirectory = realpathSync(resolve2(options.rootDirectory));
15217
15463
  const debounceMs = Math.max(0, options.debounceMs ?? 60);
@@ -15241,30 +15487,30 @@ function createProjectFileWatcher(options) {
15241
15487
  pending.clear();
15242
15488
  void Promise.resolve(options.onSettled(changes)).catch(reportError);
15243
15489
  };
15244
- const closeDirectory = (directory) => {
15245
- const entry = watches.get(directory);
15490
+ const closeDirectory = (directory2) => {
15491
+ const entry = watches.get(directory2);
15246
15492
  if (!entry) return;
15247
- watches.delete(directory);
15493
+ watches.delete(directory2);
15248
15494
  entry.watcher.close();
15249
15495
  };
15250
- const closeDescendants = (directory) => {
15496
+ const closeDescendants = (directory2) => {
15251
15497
  for (const watchedDirectory of [...watches.keys()]) {
15252
- if (watchedDirectory === directory || watchedDirectory.startsWith(`${directory}${sep2}`)) {
15498
+ if (watchedDirectory === directory2 || watchedDirectory.startsWith(`${directory2}${sep3}`)) {
15253
15499
  closeDirectory(watchedDirectory);
15254
15500
  }
15255
15501
  }
15256
15502
  };
15257
- const watchDirectory = (directory) => {
15258
- if (closed || !isProjectDirectory(rootDirectory, directory)) return;
15259
- const canonicalDirectory2 = canonicalProjectPath(rootDirectory, directory);
15503
+ const watchDirectory = (directory2) => {
15504
+ if (closed || !isProjectDirectory(rootDirectory, directory2)) return;
15505
+ const canonicalDirectory2 = canonicalProjectPath(rootDirectory, directory2);
15260
15506
  if (!canonicalDirectory2 || [...watches.values()].some(
15261
15507
  (entry) => entry.canonicalDirectory === canonicalDirectory2
15262
15508
  )) return;
15263
15509
  let directoryWatcher;
15264
15510
  try {
15265
- directoryWatcher = watch(directory, { persistent: true }, (eventType, filename) => {
15511
+ directoryWatcher = watch(directory2, { persistent: true }, (eventType, filename) => {
15266
15512
  const changedName = filename?.toString();
15267
- const changedPath = changedName ? join4(directory, changedName) : directory;
15513
+ const changedPath = changedName ? join5(directory2, changedName) : directory2;
15268
15514
  if (!isProjectPath(rootDirectory, changedPath)) return;
15269
15515
  if (isProjectDirectory(rootDirectory, changedPath)) watchDirectory(changedPath);
15270
15516
  else if (!exists(changedPath)) closeDescendants(changedPath);
@@ -15275,17 +15521,17 @@ function createProjectFileWatcher(options) {
15275
15521
  reportError(error);
15276
15522
  return;
15277
15523
  }
15278
- watches.set(directory, { directory, canonicalDirectory: canonicalDirectory2, watcher: directoryWatcher });
15524
+ watches.set(directory2, { directory: directory2, canonicalDirectory: canonicalDirectory2, watcher: directoryWatcher });
15279
15525
  pendingScans += 1;
15280
- scanQueue = scanQueue.then(() => scanSubdirectories(directory)).catch(reportError).finally(() => {
15526
+ scanQueue = scanQueue.then(() => scanSubdirectories(directory2)).catch(reportError).finally(() => {
15281
15527
  pendingScans -= 1;
15282
15528
  if (pendingScans === 0) resolveReady?.();
15283
15529
  });
15284
15530
  };
15285
- const scanSubdirectories = async (directory) => {
15531
+ const scanSubdirectories = async (directory2) => {
15286
15532
  let entries;
15287
15533
  try {
15288
- entries = await readdir2(directory, { withFileTypes: true });
15534
+ entries = await readdir2(directory2, { withFileTypes: true });
15289
15535
  } catch {
15290
15536
  return;
15291
15537
  }
@@ -15293,7 +15539,7 @@ function createProjectFileWatcher(options) {
15293
15539
  for (const entry of entries) {
15294
15540
  if (closed) return;
15295
15541
  if (!entry.isDirectory() || isExcludedDirectoryName(entry.name)) continue;
15296
- const child = join4(directory, entry.name);
15542
+ const child = join5(directory2, entry.name);
15297
15543
  if (!isProjectPath(rootDirectory, child)) continue;
15298
15544
  watchDirectory(child);
15299
15545
  }
@@ -15317,7 +15563,7 @@ function createProjectFileWatcher(options) {
15317
15563
  timer = null;
15318
15564
  }
15319
15565
  pending.clear();
15320
- for (const directory of [...watches.keys()]) closeDirectory(directory);
15566
+ for (const directory2 of [...watches.keys()]) closeDirectory(directory2);
15321
15567
  await scanQueue;
15322
15568
  }
15323
15569
  };
@@ -15355,24 +15601,24 @@ function isProjectPath(rootDirectory, path) {
15355
15601
  function canonicalProjectPath(rootDirectory, path) {
15356
15602
  try {
15357
15603
  const canonical = realpathSync(path);
15358
- 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;
15359
15605
  } catch {
15360
15606
  const parent = dirname3(path);
15361
15607
  if (parent === path) return null;
15362
15608
  try {
15363
15609
  const canonicalParent = realpathSync(parent);
15364
- 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;
15365
15611
  } catch {
15366
15612
  return null;
15367
15613
  }
15368
15614
  }
15369
15615
  }
15370
15616
  function isExcludedDirectory(rootDirectory, path) {
15371
- return relative2(rootDirectory, resolve2(path)).split(sep2).some((segment) => isExcludedDirectoryName(segment));
15617
+ return relative3(rootDirectory, resolve2(path)).split(sep3).some((segment) => isExcludedDirectoryName(segment));
15372
15618
  }
15373
15619
  function isWithin(rootDirectory, candidate) {
15374
- const pathFromRoot = relative2(rootDirectory, candidate);
15375
- return pathFromRoot === "" || !pathFromRoot.startsWith(`..${sep2}`) && pathFromRoot !== ".." && !isAbsolute2(pathFromRoot);
15620
+ const pathFromRoot = relative3(rootDirectory, candidate);
15621
+ return pathFromRoot === "" || !pathFromRoot.startsWith(`..${sep3}`) && pathFromRoot !== ".." && !isAbsolute3(pathFromRoot);
15376
15622
  }
15377
15623
  function comparePosixStrings2(a, b) {
15378
15624
  return Buffer.from(a, "utf8").compare(Buffer.from(b, "utf8"));
@@ -15393,15 +15639,15 @@ function createStandaloneServer(options) {
15393
15639
  validatePort(port);
15394
15640
  const clientPath = options.clientPath;
15395
15641
  const projectId = options.projectId ?? createStandaloneProjectId(rootDirectory);
15396
- let revision = 0;
15642
+ let revision2 = 0;
15397
15643
  let manifest = createStandaloneRuntimeManifest(
15398
15644
  projectId,
15399
15645
  EMPTY_PROJECT_TOKEN_SNAPSHOT,
15400
- revision
15646
+ revision2
15401
15647
  );
15402
15648
  let projectBridge = null;
15403
15649
  const initialTokens = createProjectTokenSnapshot({ rootDirectory, generationLabel: "static-html" }).then((tokens) => {
15404
- manifest = createStandaloneRuntimeManifest(projectId, tokens, revision);
15650
+ manifest = createStandaloneRuntimeManifest(projectId, tokens, revision2);
15405
15651
  return tokens;
15406
15652
  });
15407
15653
  void initialTokens.catch(() => void 0);
@@ -15417,7 +15663,7 @@ function createStandaloneServer(options) {
15417
15663
  };
15418
15664
  const notifyReload = () => {
15419
15665
  const payload = `event: reload
15420
- data: ${JSON.stringify({ revision })}
15666
+ data: ${JSON.stringify({ revision: revision2 })}
15421
15667
 
15422
15668
  `;
15423
15669
  for (const client of [...reloadClients]) {
@@ -15437,10 +15683,10 @@ data: ${JSON.stringify({ revision })}
15437
15683
  changeQueue = changeQueue.then(async () => {
15438
15684
  const tokens = await createProjectTokenSnapshot({ rootDirectory, generationLabel: "static-html" });
15439
15685
  manifest = {
15440
- ...createStandaloneRuntimeManifest(projectId, tokens, revision + 1),
15686
+ ...createStandaloneRuntimeManifest(projectId, tokens, revision2 + 1),
15441
15687
  ...projectBridge ? { agentBridge: projectBridge.browser } : {}
15442
15688
  };
15443
- revision += 1;
15689
+ revision2 += 1;
15444
15690
  notifyReload();
15445
15691
  }).catch((error) => {
15446
15692
  console.warn(
@@ -15575,7 +15821,7 @@ function resolveDecodedStaticFile(root2, decodedPath) {
15575
15821
  let filePath = canonicalCandidate;
15576
15822
  const stats = statSync2(filePath);
15577
15823
  if (stats.isDirectory()) {
15578
- const indexCandidate = join5(filePath, "index.html");
15824
+ const indexCandidate = join6(filePath, "index.html");
15579
15825
  const canonicalIndex = canonicalExistingAncestor(indexCandidate);
15580
15826
  if (!canonicalIndex || !isWithin2(root2, canonicalIndex) || !existsSync3(indexCandidate)) {
15581
15827
  return null;
@@ -15585,13 +15831,13 @@ function resolveDecodedStaticFile(root2, decodedPath) {
15585
15831
  } else if (!stats.isFile()) {
15586
15832
  return null;
15587
15833
  }
15588
- const relativePath = relative3(root2, filePath).split("\\").join("/");
15834
+ const relativePath = relative4(root2, filePath).split("\\").join("/");
15589
15835
  if (isSensitiveProjectPath(relativePath)) return null;
15590
15836
  return { absolutePath: filePath, projectPath: relativePath };
15591
15837
  }
15592
15838
  function createStandaloneProjectId(rootDirectory) {
15593
15839
  const canonicalRoot2 = canonicalDirectory(rootDirectory);
15594
- const digest = createHash2("sha256").update(canonicalRoot2).digest("hex").slice(0, 24);
15840
+ const digest = createHash3("sha256").update(canonicalRoot2).digest("hex").slice(0, 24);
15595
15841
  return `static-html:${digest}`;
15596
15842
  }
15597
15843
  function contentTypeForPath(filePath) {
@@ -15601,15 +15847,15 @@ function contentTypeForPath(filePath) {
15601
15847
  function isReservedNudgeUiRoute2(pathname) {
15602
15848
  return pathname === NUDGE_UI_ROUTE_PREFIX.slice(0, -1) || pathname.startsWith(NUDGE_UI_ROUTE_PREFIX);
15603
15849
  }
15604
- function canonicalDirectory(directory) {
15605
- const canonical = canonicalDirectoryOrNull(directory);
15606
- 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}`);
15607
15853
  return canonical;
15608
15854
  }
15609
- function canonicalDirectoryOrNull(directory) {
15610
- if (!isAbsolute3(directory)) return null;
15855
+ function canonicalDirectoryOrNull(directory2) {
15856
+ if (!isAbsolute4(directory2)) return null;
15611
15857
  try {
15612
- const canonical = realpathSync2(directory);
15858
+ const canonical = realpathSync2(directory2);
15613
15859
  return statSync2(canonical).isDirectory() ? canonical : null;
15614
15860
  } catch {
15615
15861
  return null;
@@ -15667,11 +15913,12 @@ function isMissingPathError(error) {
15667
15913
  return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
15668
15914
  }
15669
15915
  function isWithin2(root2, candidate) {
15670
- const pathFromRoot = relative3(root2, candidate);
15671
- return pathFromRoot === "" || !pathFromRoot.startsWith("..") && !isAbsolute3(pathFromRoot);
15916
+ const pathFromRoot = relative4(root2, candidate);
15917
+ return pathFromRoot === "" || !pathFromRoot.startsWith("..") && !isAbsolute4(pathFromRoot);
15672
15918
  }
15673
15919
  async function handleRequest(input) {
15674
15920
  const { request, response } = input;
15921
+ if (await handleHtmlArtifactRequest(request, response, input.rootDirectory)) return;
15675
15922
  if (request.method !== "GET" && request.method !== "HEAD") {
15676
15923
  sendText(response, 405, "Method Not Allowed", { Allow: "GET, HEAD" });
15677
15924
  return;
@@ -15686,8 +15933,8 @@ async function handleRequest(input) {
15686
15933
  return;
15687
15934
  }
15688
15935
  if (isNudgeUiEditorDocumentRequest(request.url ?? "/", request.method, request.headers)) {
15689
- const body2 = request.method === "HEAD" ? Buffer.alloc(0) : Buffer.from(createNudgeUiEditorDocument(), "utf8");
15690
- 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" });
15691
15938
  return;
15692
15939
  }
15693
15940
  const resolution = resolveDecodedStaticFile(input.rootDirectory, decodedPath);
@@ -15698,7 +15945,7 @@ async function handleRequest(input) {
15698
15945
  const isHtml = HTML_EXTENSIONS.has(extname2(resolution.projectPath).toLowerCase());
15699
15946
  const contentType = contentTypeForPath(resolution.projectPath);
15700
15947
  if (request.method === "HEAD") {
15701
- const body2 = await readProjectFile(resolution.absolutePath);
15948
+ const body3 = await readProjectFile(resolution.absolutePath);
15702
15949
  if (isHtml) {
15703
15950
  response.writeHead(200, {
15704
15951
  "Content-Type": contentType,
@@ -15707,25 +15954,25 @@ async function handleRequest(input) {
15707
15954
  });
15708
15955
  response.end();
15709
15956
  } else {
15710
- sendBody(response, 200, body2, contentType);
15957
+ sendBody(response, 200, body3, contentType);
15711
15958
  }
15712
15959
  return;
15713
15960
  }
15714
- let body = await readProjectFile(resolution.absolutePath);
15961
+ let body2 = await readProjectFile(resolution.absolutePath);
15715
15962
  if (isHtml) {
15716
- body = instrumentHtmlResponse(body, resolution.projectPath);
15963
+ body2 = instrumentHtmlResponse(body2, resolution.projectPath);
15717
15964
  }
15718
- sendBody(response, 200, body, contentType, isHtml ? { "Cache-Control": "no-cache" } : {});
15965
+ sendBody(response, 200, body2, contentType, isHtml ? { "Cache-Control": "no-cache" } : {});
15719
15966
  }
15720
- function instrumentHtmlResponse(body, projectPath) {
15967
+ function instrumentHtmlResponse(body2, projectPath) {
15721
15968
  let source;
15722
15969
  try {
15723
- source = strictUtf8Decoder.decode(body);
15970
+ source = strictUtf8Decoder.decode(body2);
15724
15971
  } catch {
15725
15972
  console.warn(
15726
15973
  `Nudge UI served ${projectPath} without instrumentation because it is not valid UTF-8.`
15727
15974
  );
15728
- return body;
15975
+ return body2;
15729
15976
  }
15730
15977
  const identified = instrumentSourceHtml(source, projectPath);
15731
15978
  const bootstrapped = injectStandaloneBootstrap(identified.html);
@@ -15734,23 +15981,23 @@ function instrumentHtmlResponse(body, projectPath) {
15734
15981
  var strictUtf8Decoder = new TextDecoder("utf-8", { fatal: true });
15735
15982
  async function handleNudgeUiRoute(input, pathname) {
15736
15983
  if (pathname === NUDGE_UI_MANIFEST_PATH) {
15737
- const body = Buffer.from(JSON.stringify(input.getManifest()), "utf8");
15738
- 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", {
15739
15986
  "Cache-Control": "no-store"
15740
15987
  });
15741
15988
  return;
15742
15989
  }
15743
15990
  if (pathname === NUDGE_UI_EDITOR_PATH) {
15744
- const body = input.request.method === "HEAD" ? Buffer.alloc(0) : Buffer.from(createNudgeUiEditorDocument(), "utf8");
15745
- 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", {
15746
15993
  "Cache-Control": "no-store"
15747
15994
  });
15748
15995
  return;
15749
15996
  }
15750
15997
  if (pathname === NUDGE_UI_CLIENT_PATH) {
15751
15998
  try {
15752
- const body = await readFileFromDescriptor(input.clientPath ?? resolveDefaultClientPath());
15753
- 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", {
15754
16001
  "Cache-Control": "no-cache"
15755
16002
  });
15756
16003
  } catch {
@@ -15827,14 +16074,14 @@ function validatePort(port) {
15827
16074
  function sendText(response, status, text, headers = {}) {
15828
16075
  sendBody(response, status, Buffer.from(text, "utf8"), "text/plain; charset=utf-8", headers);
15829
16076
  }
15830
- function sendBody(response, status, body, contentType, headers = {}) {
16077
+ function sendBody(response, status, body2, contentType, headers = {}) {
15831
16078
  response.writeHead(status, {
15832
16079
  "Content-Type": contentType,
15833
- "Content-Length": body.byteLength,
16080
+ "Content-Length": body2.byteLength,
15834
16081
  "X-Content-Type-Options": "nosniff",
15835
16082
  ...headers
15836
16083
  });
15837
- if (response.req?.method !== "HEAD") response.end(body);
16084
+ if (response.req?.method !== "HEAD") response.end(body2);
15838
16085
  else response.end();
15839
16086
  }
15840
16087
  var MIME_TYPES2 = {
@@ -15870,7 +16117,7 @@ function parseServeArguments(args, currentDirectory = process.cwd()) {
15870
16117
  if (args[0] !== "serve") {
15871
16118
  throw new Error("Usage: nudge-ui serve [directory] [--port <port>] [--host <loopback>]");
15872
16119
  }
15873
- let directory = ".";
16120
+ let directory2 = ".";
15874
16121
  let host = "127.0.0.1";
15875
16122
  let port = 4173;
15876
16123
  let directoryProvided = false;
@@ -15887,13 +16134,13 @@ function parseServeArguments(args, currentDirectory = process.cwd()) {
15887
16134
  } else if (argument.startsWith("-")) {
15888
16135
  throw new Error(`Unknown option: ${argument}`);
15889
16136
  } else if (!directoryProvided) {
15890
- directory = argument;
16137
+ directory2 = argument;
15891
16138
  directoryProvided = true;
15892
16139
  } else {
15893
16140
  throw new Error(`Unexpected argument: ${argument}`);
15894
16141
  }
15895
16142
  }
15896
- return { rootDirectory: resolve4(currentDirectory, directory), host, port };
16143
+ return { rootDirectory: resolve4(currentDirectory, directory2), host, port };
15897
16144
  }
15898
16145
  async function runServeCommand(options) {
15899
16146
  const server = createStandaloneServer(options);