nudge-ui 0.2.2 → 0.2.4
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.
- package/README.md +164 -46
- package/dist/client.mjs +260 -61
- package/dist/css/value-semantics/colorSemantics.d.ts +4 -0
- package/dist/css/value-semantics/colorSemantics.js +17 -0
- package/dist/hosts/astro/astroRuntimeConfig.js +1 -0
- package/dist/hosts/astro/clientTransport.js +38 -32
- package/dist/hosts/astro/integration.js +5 -1
- package/dist/hosts/astro/markdownIdentity.d.ts +28 -0
- package/dist/hosts/astro/markdownIdentity.js +81 -0
- package/dist/hosts/next/manifest.js +1 -1
- package/dist/hosts/next/sidecar.js +5 -1
- package/dist/hosts/static/manifest.js +1 -1
- package/dist/hosts/static/server.js +3 -0
- package/dist/hosts/vite/vite.d.ts +3 -0
- package/dist/hosts/vite/vite.js +24 -4
- package/dist/inspector/agent/McpConnectionDialog.js +13 -19
- package/dist/inspector/agent/activity.d.ts +18 -0
- package/dist/inspector/agent/activity.js +70 -0
- package/dist/inspector/agent/client.d.ts +2 -0
- package/dist/inspector/agent/client.js +29 -1
- package/dist/inspector/agent/connectionStatus.js +1 -1
- package/dist/inspector/agent/httpTransport.js +9 -2
- package/dist/inspector/agent/protocol.d.ts +6 -3
- package/dist/inspector/agent/protocol.js +1 -1
- package/dist/inspector/agent/verification.d.ts +15 -7
- package/dist/inspector/agent/verification.js +113 -41
- package/dist/inspector/canvas/AgentActivityOverlay.d.ts +13 -0
- package/dist/inspector/canvas/AgentActivityOverlay.js +111 -0
- package/dist/inspector/canvas/CanvasCard.d.ts +9 -2
- package/dist/inspector/canvas/CanvasCard.js +135 -38
- package/dist/inspector/canvas/CanvasElementOverlay.js +166 -16
- package/dist/inspector/canvas/CanvasToolIcons.d.ts +10 -0
- package/dist/inspector/canvas/CanvasToolIcons.js +20 -0
- package/dist/inspector/canvas/CanvasToolbar.js +8 -4
- package/dist/inspector/canvas/CanvasWorkspace.js +270 -122
- package/dist/inspector/canvas/StaleChangeIndicator.js +3 -13
- package/dist/inspector/canvas/agentPresentation.d.ts +8 -8
- package/dist/inspector/canvas/agentPresentation.js +64 -52
- package/dist/inspector/canvas/canvasGestures.d.ts +1 -1
- package/dist/inspector/canvas/canvasGestures.js +1 -1
- package/dist/inspector/canvas/canvasStore.d.ts +46 -82
- package/dist/inspector/canvas/canvasStore.js +251 -284
- package/dist/inspector/canvas/frameContent.d.ts +21 -0
- package/dist/inspector/canvas/frameContent.js +44 -0
- package/dist/inspector/canvas/frameProtocol.d.ts +21 -4
- package/dist/inspector/canvas/frameProtocol.js +3 -3
- package/dist/inspector/canvas/frameScrollbarStyles.d.ts +3 -0
- package/dist/inspector/canvas/frameScrollbarStyles.js +21 -0
- package/dist/inspector/canvas/keyboardShortcuts.d.ts +3 -1
- package/dist/inspector/canvas/keyboardShortcuts.js +4 -4
- package/dist/inspector/canvas/layout.d.ts +52 -0
- package/dist/inspector/canvas/layout.js +106 -0
- package/dist/inspector/canvas/projection.d.ts +15 -5
- package/dist/inspector/canvas/projection.js +69 -13
- package/dist/inspector/canvas/rendererBootstrap.js +32 -4
- package/dist/inspector/canvas/rendererElementSelector.js +47 -6
- package/dist/inspector/canvas/rendererStylesheet.js +2 -2
- package/dist/inspector/canvas/resizeHandleScale.js +1 -1
- package/dist/inspector/canvas/sessionStore.d.ts +11 -26
- package/dist/inspector/canvas/sessionStore.js +43 -183
- package/dist/inspector/canvas/staleChangeDetector.js +9 -3
- package/dist/inspector/canvas/useCanvasLayoutAnimation.d.ts +5 -0
- package/dist/inspector/canvas/useCanvasLayoutAnimation.js +107 -0
- package/dist/inspector/canvas/viewStore.d.ts +38 -0
- package/dist/inspector/canvas/viewStore.js +104 -0
- package/dist/inspector/canvas/wheelPan.d.ts +8 -0
- package/dist/inspector/canvas/wheelPan.js +8 -0
- package/dist/inspector/changes/changesLog.d.ts +9 -6
- package/dist/inspector/changes/changesLog.js +48 -32
- package/dist/inspector/changes/codecs.d.ts +1 -0
- package/dist/inspector/changes/codecs.js +10 -1
- package/dist/inspector/changes/draftChanges.d.ts +58 -0
- package/dist/inspector/changes/draftChanges.js +304 -0
- package/dist/inspector/changes/editModel.d.ts +10 -0
- package/dist/inspector/changes/editModel.js +9 -2
- package/dist/inspector/changes/previewDiagnostics.d.ts +4 -2
- package/dist/inspector/changes/previewDiagnostics.js +11 -25
- package/dist/inspector/changes/types.d.ts +7 -0
- package/dist/inspector/clientManifest.d.ts +1 -1
- package/dist/inspector/comments/CommentsOverlay.d.ts +2 -0
- package/dist/inspector/comments/CommentsOverlay.js +250 -0
- package/dist/inspector/comments/element.d.ts +6 -0
- package/dist/inspector/comments/element.js +54 -0
- package/dist/inspector/comments/store.d.ts +29 -0
- package/dist/inspector/comments/store.js +121 -0
- package/dist/inspector/comments/verification.d.ts +5 -0
- package/dist/inspector/comments/verification.js +52 -0
- package/dist/inspector/componentSemantics/adapterRegistry.d.ts +6 -1
- package/dist/inspector/componentSemantics/adapterRegistry.js +23 -1
- package/dist/inspector/componentSemantics/reactRuntime.d.ts +2 -1
- package/dist/inspector/componentSemantics/reactRuntime.js +38 -0
- package/dist/inspector/componentSemantics/runtimeBridge.d.ts +4 -2
- package/dist/inspector/componentSemantics/runtimeBridge.js +17 -0
- package/dist/inspector/componentSemantics/types.d.ts +11 -0
- package/dist/inspector/drafts/model.d.ts +35 -0
- package/dist/inspector/drafts/model.js +45 -0
- package/dist/inspector/drafts/store.d.ts +28 -0
- package/dist/inspector/drafts/store.js +231 -0
- package/dist/inspector/index.js +20 -27
- package/dist/inspector/inline-text/inlineTextEditor.js +7 -0
- package/dist/inspector/inspection/useBrowserCssInspection.js +15 -1
- package/dist/inspector/iterations/capture.d.ts +2 -0
- package/dist/inspector/iterations/capture.js +174 -0
- package/dist/inspector/iterations/client.d.ts +7 -0
- package/dist/inspector/iterations/client.js +52 -0
- package/dist/inspector/iterations/coordinator.d.ts +15 -0
- package/dist/inspector/iterations/coordinator.js +130 -0
- package/dist/inspector/iterations/prompt.d.ts +3 -0
- package/dist/inspector/iterations/prompt.js +26 -0
- package/dist/inspector/overlay/DomNavigator.js +21 -15
- package/dist/inspector/overlay/interactionStyles.js +3 -1
- package/dist/inspector/overlay/spacingGestures.d.ts +13 -1
- package/dist/inspector/overlay/spacingGestures.js +82 -5
- package/dist/inspector/projection/{workspaceProjection.d.ts → draftProjection.d.ts} +6 -6
- package/dist/inspector/projection/{workspaceProjection.js → draftProjection.js} +4 -4
- package/dist/inspector/projection/renderedInstance.d.ts +17 -3
- package/dist/inspector/projection/renderedInstance.js +62 -11
- package/dist/inspector/projection/structuralProjection.d.ts +2 -1
- package/dist/inspector/projection/structuralProjection.js +21 -17
- package/dist/inspector/projection/textProjection.d.ts +2 -1
- package/dist/inspector/projection/textProjection.js +64 -15
- package/dist/inspector/prompt/PromptSettingsDialog.js +1 -5
- package/dist/inspector/prompt/clipboardHandoff.d.ts +15 -18
- package/dist/inspector/prompt/clipboardHandoff.js +97 -143
- package/dist/inspector/prompt/generatePrompt.d.ts +4 -1
- package/dist/inspector/prompt/generatePrompt.js +22 -17
- package/dist/inspector/runtime/runtimeConfig.d.ts +9 -0
- package/dist/inspector/runtime/runtimeConfig.js +24 -0
- package/dist/inspector/selection/sourceSite.d.ts +12 -0
- package/dist/inspector/selection/sourceSite.js +28 -0
- package/dist/inspector/settings/SettingsDialog.js +21 -8
- package/dist/inspector/shell/AgentStatusButton.d.ts +11 -0
- package/dist/inspector/shell/AgentStatusButton.js +36 -0
- package/dist/inspector/shell/AppShell.js +4 -2
- package/dist/inspector/shell/ChangesLog.js +46 -26
- package/dist/inspector/shell/CopyPromptButton.js +184 -93
- package/dist/inspector/shell/EmptyState.js +9 -8
- package/dist/inspector/shell/InspectorShell.js +13 -21
- package/dist/inspector/shell/PeekOriginalButton.js +24 -23
- package/dist/inspector/shell/originalPreview.js +5 -5
- package/dist/inspector/shell/shortcuts.d.ts +3 -0
- package/dist/inspector/shell/shortcuts.js +11 -0
- package/dist/inspector/sketch/SketchEditor.js +14 -14
- package/dist/inspector/sketch/SketchEntryButton.js +1 -1
- package/dist/inspector/sketch/SketchFrameOverlay.d.ts +3 -1
- package/dist/inspector/sketch/SketchFrameOverlay.js +11 -8
- package/dist/inspector/sketch/SketchLayersPanel.js +13 -5
- package/dist/inspector/sketch/SketchOverlay.js +7 -7
- package/dist/inspector/sketch/SketchWorkspace.js +18 -12
- package/dist/inspector/sketch/interaction.d.ts +1 -0
- package/dist/inspector/sketch/interaction.js +8 -4
- package/dist/inspector/sketch/model.d.ts +5 -0
- package/dist/inspector/sketch/model.js +6 -2
- package/dist/inspector/sketch/raster.d.ts +1 -2
- package/dist/inspector/sketch/raster.js +68 -4
- package/dist/inspector/styleEditors/BackgroundEditor.d.ts +4 -0
- package/dist/inspector/styleEditors/BackgroundEditor.js +195 -0
- package/dist/inspector/styleEditors/BorderEditor.js +49 -78
- package/dist/inspector/styleEditors/BorderRadiusEditor.js +6 -1
- package/dist/inspector/styleEditors/BoxShadowEditor.d.ts +1 -2
- package/dist/inspector/styleEditors/BoxShadowEditor.js +132 -4
- package/dist/inspector/styleEditors/ColorPicker.d.ts +5 -1
- package/dist/inspector/styleEditors/ColorPicker.js +10 -4
- package/dist/inspector/styleEditors/GapField.js +3 -5
- package/dist/inspector/styleEditors/GridChildSection.d.ts +1 -1
- package/dist/inspector/styleEditors/GridChildSection.js +18 -9
- package/dist/inspector/styleEditors/GridPicker.d.ts +1 -1
- package/dist/inspector/styleEditors/GridPicker.js +8 -2
- package/dist/inspector/styleEditors/GridSection.js +1 -1
- package/dist/inspector/styleEditors/GridValueField.js +19 -14
- package/dist/inspector/styleEditors/ImageBackgroundEditor.d.ts +18 -0
- package/dist/inspector/styleEditors/ImageBackgroundEditor.js +118 -0
- package/dist/inspector/styleEditors/LayoutBlockedIndicator.d.ts +2 -2
- package/dist/inspector/styleEditors/LayoutBlockedIndicator.js +3 -3
- package/dist/inspector/styleEditors/LayoutComboField.js +6 -4
- package/dist/inspector/styleEditors/LayoutDropdown.js +6 -3
- package/dist/inspector/styleEditors/LayoutSection.js +32 -11
- package/dist/inspector/styleEditors/SpacingBox.js +7 -5
- package/dist/inspector/styleEditors/Typography.js +11 -3
- package/dist/inspector/styleEditors/backgroundLayers.d.ts +24 -0
- package/dist/inspector/styleEditors/backgroundLayers.js +51 -0
- package/dist/inspector/styleEditors/gradientValue.d.ts +17 -0
- package/dist/inspector/styleEditors/gradientValue.js +114 -0
- package/dist/inspector/styleEditors/inlineAuthored.d.ts +10 -0
- package/dist/inspector/styleEditors/inlineAuthored.js +114 -0
- package/dist/inspector/styleEditors/layoutValue.d.ts +0 -8
- package/dist/inspector/styleEditors/layoutValue.js +0 -42
- package/dist/inspector/styleEditors/nudgeValue.d.ts +2 -2
- package/dist/inspector/styleEditors/nudgeValue.js +36 -8
- package/dist/inspector/tokens/TokenField.d.ts +7 -0
- package/dist/inspector/tokens/TokenField.js +35 -25
- package/dist/inspector/tokens/TokenLabel.js +5 -14
- package/dist/inspector/tokens/editActions.d.ts +1 -1
- package/dist/inspector/tokens/editActions.js +7 -1
- package/dist/inspector/ui/AtRuleContext.js +4 -6
- package/dist/inspector/ui/Button.d.ts +6 -2
- package/dist/inspector/ui/Button.js +4 -3
- package/dist/inspector/ui/ControlSurface.d.ts +2 -2
- package/dist/inspector/ui/ControlSurface.js +4 -3
- package/dist/inspector/ui/InlineStyleWarning.d.ts +11 -0
- package/dist/inspector/ui/InlineStyleWarning.js +13 -0
- package/dist/inspector/ui/InspectorPopover.d.ts +2 -1
- package/dist/inspector/ui/InspectorPopover.js +4 -5
- package/dist/inspector/ui/PopoverListbox.d.ts +2 -1
- package/dist/inspector/ui/PopoverListbox.js +8 -7
- package/dist/inspector/ui/SegmentedControl.d.ts +2 -1
- package/dist/inspector/ui/SegmentedControl.js +2 -2
- package/dist/inspector/ui/Select.d.ts +6 -1
- package/dist/inspector/ui/Select.js +7 -11
- package/dist/inspector/ui/SideValuesField.js +1 -1
- package/dist/inspector/ui/Tooltip.d.ts +26 -0
- package/dist/inspector/ui/Tooltip.js +32 -0
- package/dist/inspector/ui/classNames.d.ts +2 -0
- package/dist/inspector/ui/classNames.js +4 -0
- package/dist/inspector/ui/customCursors.d.ts +23 -0
- package/dist/inspector/ui/customCursors.js +122 -0
- package/dist/inspector/ui/dragCursor.d.ts +0 -2
- package/dist/inspector/ui/dragCursor.js +2 -10
- package/dist/inspector/ui/portalContainer.d.ts +2 -0
- package/dist/inspector/ui/portalContainer.js +6 -0
- package/dist/inspector/ui/styles.js +29 -21
- package/dist/inspector/workspace/commands.d.ts +9 -0
- package/dist/inspector/workspace/commands.js +82 -0
- package/dist/inspector/workspace/controller.d.ts +4 -0
- package/dist/inspector/workspace/controller.js +66 -0
- package/dist/inspector/workspace/handoff.d.ts +42 -0
- package/dist/inspector/workspace/handoff.js +115 -0
- package/dist/inspector/workspace/sentItems.d.ts +19 -0
- package/dist/inspector/workspace/sentItems.js +51 -0
- package/dist/inspector/workspace/timeline.d.ts +30 -0
- package/dist/inspector/workspace/timeline.js +108 -0
- package/dist/internal/agent-protocol.d.ts +19 -2
- package/dist/internal/agent-protocol.js +13 -0
- package/dist/nudge-ui.mjs +558 -311
- package/dist/project/artifacts.d.ts +13 -0
- package/dist/project/artifacts.js +253 -0
- package/dist/transport/artifacts.d.ts +8 -0
- package/dist/transport/artifacts.js +9 -0
- package/dist/transport/editor.js +3 -1
- package/dist/transport/routes.d.ts +2 -0
- package/dist/transport/routes.js +2 -0
- package/package.json +7 -3
- package/dist/inspector/changes/workspaceChanges.d.ts +0 -47
- package/dist/inspector/changes/workspaceChanges.js +0 -265
|
@@ -5,6 +5,8 @@ import { formatComponentPropBaseline, formatComponentPropValue, } from "../compo
|
|
|
5
5
|
import { boundRuntimeEvidence, isRuntimeGeneratedSource, normalizeRuntimeTag, normalizeRuntimeText, } from "../runtime/staticHtmlRuntimeIdentity.js";
|
|
6
6
|
import { getSourceCoordinatePolicy } from "../runtime/runtimeConfig.js";
|
|
7
7
|
import { DEFAULT_CUSTOM_INSTRUCTIONS } from "./promptSettings.js";
|
|
8
|
+
import { getCommentsForTarget } from "../comments/store.js";
|
|
9
|
+
import { documentTarget } from "../drafts/model.js";
|
|
8
10
|
const EMPTY_SENTINEL = "<!-- No changes to export -->\n\nThe changes log is empty. Make a change in the Nudge UI inspector first.";
|
|
9
11
|
function renderPrompt(sections, customInstructions) {
|
|
10
12
|
const lines = [
|
|
@@ -230,7 +232,10 @@ function renderedInstanceDescription(ref) {
|
|
|
230
232
|
function structuralChangeLine(change) {
|
|
231
233
|
const target = renderedInstanceDescription(change.target);
|
|
232
234
|
if (change.kind === "delete") {
|
|
233
|
-
|
|
235
|
+
const invocation = change.target.locator.invocation;
|
|
236
|
+
return invocation
|
|
237
|
+
? `- Remove the ${promptText(`<${invocation.componentName}>`)} invocation at ${invocation.callsiteId} from the source; keep its other invocations. It renders ${target}.`
|
|
238
|
+
: `- Remove ${target} from the source.`;
|
|
234
239
|
}
|
|
235
240
|
const before = change.destination.before;
|
|
236
241
|
const sourceParent = sourceSiteLabel(change.source.parent);
|
|
@@ -244,17 +249,6 @@ function structuralChangeLine(change) {
|
|
|
244
249
|
? `- Move ${target} before ${renderedInstanceDescription(before)} in ${destinationParent}.`
|
|
245
250
|
: `- Move ${target} to the end of ${destinationParent}.`;
|
|
246
251
|
}
|
|
247
|
-
function sketchLines(sketches) {
|
|
248
|
-
const titles = [...new Set(sketches.map((sketch) => sketch.capture.title || "(untitled)"))];
|
|
249
|
-
return [
|
|
250
|
-
...titles.map((title) => `- Page title: ${promptText(title)}`),
|
|
251
|
-
...sketches.flatMap((sketch) => [
|
|
252
|
-
...(sketch.description ? [`- Description: ${promptText(sketch.description)}`] : []),
|
|
253
|
-
...(sketch.annotations ?? []).map((annotation) => `- Annotation ${annotation.number}: ${promptText(annotation.description)}`),
|
|
254
|
-
]),
|
|
255
|
-
"- Interpret the attached frozen screenshot, blue strokes, and numbered annotations as visual feedback. Do not derive selectors, source coordinates, or semantics from the strokes. Use each annotation number to match the note to its numbered dot.",
|
|
256
|
-
];
|
|
257
|
-
}
|
|
258
252
|
function renderedInstanceKey(ref) {
|
|
259
253
|
const { sourceSite, locator } = ref;
|
|
260
254
|
return JSON.stringify([
|
|
@@ -263,6 +257,7 @@ function renderedInstanceKey(ref) {
|
|
|
263
257
|
locator.props,
|
|
264
258
|
locator.text,
|
|
265
259
|
locator.ariaLabel ?? null,
|
|
260
|
+
locator.invocation?.callsiteId ?? null,
|
|
266
261
|
]);
|
|
267
262
|
}
|
|
268
263
|
/** Export final intent, not the gesture history required to replay the preview. */
|
|
@@ -315,10 +310,14 @@ function canonicalizeStructuralChanges(changes) {
|
|
|
315
310
|
}
|
|
316
311
|
return canonical;
|
|
317
312
|
}
|
|
318
|
-
|
|
313
|
+
/** Counts the final edit intents exported by the prompt, preserving gesture history for undo. */
|
|
314
|
+
export function countPromptChanges(changes, structuralChanges = [], sketchCount = 0) {
|
|
315
|
+
return canonicalizeChanges([...changes]).length + canonicalizeStructuralChanges(structuralChanges).length + sketchCount;
|
|
316
|
+
}
|
|
317
|
+
export function generatePrompt(changes, frameworkHints, structuralChanges = [], customInstructions = DEFAULT_CUSTOM_INSTRUCTIONS, sketches = [], comments = getCommentsForTarget(documentTarget(window.location.href))) {
|
|
319
318
|
const deduplicated = canonicalizeChanges(changes);
|
|
320
319
|
const structuralIntent = canonicalizeStructuralChanges(structuralChanges);
|
|
321
|
-
if (deduplicated.length === 0 && structuralIntent.length === 0 && sketches.length === 0)
|
|
320
|
+
if (deduplicated.length === 0 && structuralIntent.length === 0 && sketches.length === 0 && comments.length === 0)
|
|
322
321
|
return EMPTY_SENTINEL;
|
|
323
322
|
const tokenChanges = deduplicated.filter(isTokenChange);
|
|
324
323
|
const componentChanges = deduplicated.filter(isComponentChange);
|
|
@@ -398,10 +397,16 @@ export function generatePrompt(changes, frameworkHints, structuralChanges = [],
|
|
|
398
397
|
lines: structuralIntent.map(structuralChangeLine),
|
|
399
398
|
});
|
|
400
399
|
}
|
|
401
|
-
if (
|
|
400
|
+
if (comments.length > 0) {
|
|
402
401
|
sections.push({
|
|
403
|
-
heading: "
|
|
404
|
-
lines:
|
|
402
|
+
heading: "Element comments",
|
|
403
|
+
lines: comments.flatMap((comment) => [
|
|
404
|
+
`### <${comment.tag}> (${comment.target.sourceSite.src || "source unknown"})`,
|
|
405
|
+
`- Page: ${promptText(comment.route)}`,
|
|
406
|
+
`- Target: ${renderedInstanceDescription(comment.target)}`,
|
|
407
|
+
`- Note: ${promptText(comment.note)}`,
|
|
408
|
+
"",
|
|
409
|
+
]),
|
|
405
410
|
});
|
|
406
411
|
}
|
|
407
412
|
return renderPrompt(sections, customInstructions);
|
|
@@ -39,6 +39,11 @@ export interface NudgeUiRuntimeCapabilities {
|
|
|
39
39
|
*/
|
|
40
40
|
readonly scopingSelectorPattern?: string;
|
|
41
41
|
}
|
|
42
|
+
/** Product features that a host can selectively expose in its inspector UI. */
|
|
43
|
+
export interface NudgeUiRuntimeFeatures {
|
|
44
|
+
/** Whether Canvas can create filesystem-backed HTML iterations. */
|
|
45
|
+
readonly canvasIterations?: boolean;
|
|
46
|
+
}
|
|
42
47
|
/**
|
|
43
48
|
* Browser knowledge supplied by a host Adapter before the inspector mounts.
|
|
44
49
|
*
|
|
@@ -53,6 +58,8 @@ export interface NudgeUiRuntimeConfig {
|
|
|
53
58
|
readonly framework: NudgeUiRuntimeFramework;
|
|
54
59
|
readonly stylingSystem: string;
|
|
55
60
|
readonly capabilities: NudgeUiRuntimeCapabilities;
|
|
61
|
+
/** Product-level feature switches; omitted features remain enabled. */
|
|
62
|
+
readonly features?: NudgeUiRuntimeFeatures;
|
|
56
63
|
readonly tokenCatalog: readonly TokenDefinition[];
|
|
57
64
|
readonly tokens: readonly TokenEntry[];
|
|
58
65
|
readonly tokenDiagnostics: readonly TokenCatalogDiagnostic[];
|
|
@@ -91,6 +98,8 @@ export declare function normalizeNudgeUiRuntimeConfig(input: unknown): NudgeUiRu
|
|
|
91
98
|
export declare function configureNudgeUiRuntime(config: NudgeUiRuntimeConfig): void;
|
|
92
99
|
/** Returns the immutable runtime snapshot used by shared inspector Modules. */
|
|
93
100
|
export declare function getNudgeUiRuntimeConfig(): NudgeUiRuntimeConfig;
|
|
101
|
+
/** Returns whether a product feature is enabled; omitted flags default to enabled. */
|
|
102
|
+
export declare function isNudgeUiFeatureEnabled(features: NudgeUiRuntimeFeatures | undefined, feature: keyof NudgeUiRuntimeFeatures): boolean;
|
|
94
103
|
/**
|
|
95
104
|
* Whether this document runs the explicit public landing demo (ADR-0014 and
|
|
96
105
|
* ADR-0016). The plugin emits `demo: true` for the flagged demo route and for
|
|
@@ -98,6 +98,15 @@ function optionalBoolean(input, field) {
|
|
|
98
98
|
}
|
|
99
99
|
return value;
|
|
100
100
|
}
|
|
101
|
+
function optionalFeatureBoolean(input, field) {
|
|
102
|
+
const value = input[field];
|
|
103
|
+
if (value === undefined)
|
|
104
|
+
return undefined;
|
|
105
|
+
if (typeof value !== "boolean") {
|
|
106
|
+
throw new TypeError(`Nudge UI runtime feature "${field}" must be a boolean; received ${JSON.stringify(value)}.`);
|
|
107
|
+
}
|
|
108
|
+
return value;
|
|
109
|
+
}
|
|
101
110
|
function optionalNonEmptyString(input, field) {
|
|
102
111
|
const value = input[field];
|
|
103
112
|
if (value === undefined)
|
|
@@ -142,6 +151,15 @@ function normalizeCapabilities(input) {
|
|
|
142
151
|
scopingSelectorPattern: optionalNonEmptyString(input, "scopingSelectorPattern"),
|
|
143
152
|
};
|
|
144
153
|
}
|
|
154
|
+
function normalizeFeatures(input) {
|
|
155
|
+
if (input === undefined)
|
|
156
|
+
return undefined;
|
|
157
|
+
if (!isPlainRecord(input)) {
|
|
158
|
+
throw new TypeError('Nudge UI runtime configuration field "features" must be an object.');
|
|
159
|
+
}
|
|
160
|
+
const canvasIterations = optionalFeatureBoolean(input, "canvasIterations");
|
|
161
|
+
return canvasIterations === undefined ? {} : { canvasIterations };
|
|
162
|
+
}
|
|
145
163
|
function optionalDemoFlag(input) {
|
|
146
164
|
const value = input.demo;
|
|
147
165
|
if (value === undefined || value === false)
|
|
@@ -172,12 +190,14 @@ export function normalizeNudgeUiRuntimeConfig(input) {
|
|
|
172
190
|
const demo = optionalDemoFlag(input);
|
|
173
191
|
const demoPages = optionalStringArray(input, "demoPages");
|
|
174
192
|
const demoCardLabels = optionalStringArray(input, "demoCardLabels");
|
|
193
|
+
const features = normalizeFeatures(input.features);
|
|
175
194
|
const normalized = cloneAndFreeze({
|
|
176
195
|
projectId: requireString(input, "projectId"),
|
|
177
196
|
host: requireEnum(input, "host", RUNTIME_HOSTS),
|
|
178
197
|
framework: requireEnum(input, "framework", RUNTIME_FRAMEWORKS),
|
|
179
198
|
stylingSystem: optionalString(input, "stylingSystem"),
|
|
180
199
|
capabilities: normalizeCapabilities(input.capabilities),
|
|
200
|
+
...(features === undefined ? {} : { features }),
|
|
181
201
|
tokenCatalog: optionalArray(input, "tokenCatalog"),
|
|
182
202
|
tokens: optionalArray(input, "tokens"),
|
|
183
203
|
tokenDiagnostics: optionalArray(input, "tokenDiagnostics"),
|
|
@@ -217,6 +237,10 @@ export function configureNudgeUiRuntime(config) {
|
|
|
217
237
|
export function getNudgeUiRuntimeConfig() {
|
|
218
238
|
return activeRuntimeConfig;
|
|
219
239
|
}
|
|
240
|
+
/** Returns whether a product feature is enabled; omitted flags default to enabled. */
|
|
241
|
+
export function isNudgeUiFeatureEnabled(features, feature) {
|
|
242
|
+
return features?.[feature] !== false;
|
|
243
|
+
}
|
|
220
244
|
/**
|
|
221
245
|
* Whether this document runs the explicit public landing demo (ADR-0014 and
|
|
222
246
|
* ADR-0016). The plugin emits `demo: true` for the flagged demo route and for
|
|
@@ -1,2 +1,14 @@
|
|
|
1
1
|
/** Stable JSX instrumentation selector, shared by source and instance edits. */
|
|
2
2
|
export declare function sourceSiteSelector(cid: string, src: string): string | null;
|
|
3
|
+
/**
|
|
4
|
+
* Finds a source site whose position moved because its file gained or lost
|
|
5
|
+
* lines. It returns a site only when the original renders nothing and exactly
|
|
6
|
+
* one other position in the same file and component renders matching elements.
|
|
7
|
+
*/
|
|
8
|
+
export declare function relocateSourceSite(doc: Document, site: {
|
|
9
|
+
readonly cid: string;
|
|
10
|
+
readonly src: string;
|
|
11
|
+
}, matches: (element: HTMLElement) => boolean): {
|
|
12
|
+
cid: string;
|
|
13
|
+
src: string;
|
|
14
|
+
} | null;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { escapeAttrValue } from "../projection/cssEscapes.js";
|
|
2
|
+
const SOURCE_POSITION = /^(.+):\d+:\d+$/;
|
|
2
3
|
/** Stable JSX instrumentation selector, shared by source and instance edits. */
|
|
3
4
|
export function sourceSiteSelector(cid, src) {
|
|
4
5
|
if (!cid)
|
|
@@ -10,3 +11,30 @@ export function sourceSiteSelector(cid, src) {
|
|
|
10
11
|
// single formatted line share a managed rule.
|
|
11
12
|
return `[data-cid="${escapeAttrValue(cid)}"][data-src="${escapeAttrValue(src)}"]`;
|
|
12
13
|
}
|
|
14
|
+
/**
|
|
15
|
+
* Finds a source site whose position moved because its file gained or lost
|
|
16
|
+
* lines. It returns a site only when the original renders nothing and exactly
|
|
17
|
+
* one other position in the same file and component renders matching elements.
|
|
18
|
+
*/
|
|
19
|
+
export function relocateSourceSite(doc, site, matches) {
|
|
20
|
+
const file = SOURCE_POSITION.exec(site.src)?.[1];
|
|
21
|
+
const exact = sourceSiteSelector(site.cid, site.src);
|
|
22
|
+
if (!file || !exact)
|
|
23
|
+
return null;
|
|
24
|
+
try {
|
|
25
|
+
if (doc.querySelector(exact))
|
|
26
|
+
return null;
|
|
27
|
+
const sites = new Set();
|
|
28
|
+
const sameFile = `[data-cid="${escapeAttrValue(site.cid)}"][data-src^="${escapeAttrValue(`${file}:`)}"]`;
|
|
29
|
+
for (const element of doc.querySelectorAll(sameFile)) {
|
|
30
|
+
const src = element.getAttribute("data-src") ?? "";
|
|
31
|
+
if (SOURCE_POSITION.exec(src)?.[1] === file && matches(element))
|
|
32
|
+
sites.add(src);
|
|
33
|
+
}
|
|
34
|
+
const [src] = sites;
|
|
35
|
+
return sites.size === 1 && src ? { cid: site.cid, src } : null;
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useEffect, useRef, useState } from "react";
|
|
3
3
|
import { Dialog } from "@base-ui/react/dialog";
|
|
4
|
-
import { IconColorSwatch, IconPlugConnected, IconSettings, IconX, } from "@tabler/icons-react";
|
|
4
|
+
import { IconColorSwatch, IconPlugConnected, IconSettings, IconX, IconTrash, } from "@tabler/icons-react";
|
|
5
5
|
import { useBrowserCssInspection } from "../inspection/useBrowserCssInspection.js";
|
|
6
6
|
import { McpConnectionContent, } from "../agent/McpConnectionDialog.js";
|
|
7
7
|
import { PromptSettingsFields, } from "../prompt/PromptSettingsDialog.js";
|
|
@@ -10,10 +10,17 @@ import { useSelectedElement } from "../selection/selectionStore.js";
|
|
|
10
10
|
import { useFocusedCardId, useSelectedCardId } from "../canvas/canvasStore.js";
|
|
11
11
|
import { getRegisteredFrames } from "../canvas/projection.js";
|
|
12
12
|
import { getBrowserCssInspection } from "../inspection/browserCssInspectionRegistry.js";
|
|
13
|
+
import { portalContainer } from "../ui/portalContainer.js";
|
|
14
|
+
import { clearRestoreCount, clearSession } from "../canvas/sessionStore.js";
|
|
15
|
+
import { hasWriteLease } from "../canvas/workspaceLease.js";
|
|
16
|
+
import { cancelSketchInteraction } from "../sketch/interaction.js";
|
|
17
|
+
import { closeSketchNote } from "../sketch/sketchNote.js";
|
|
18
|
+
import { clearSketchClipboardHandoff } from "../sketch/handoff.js";
|
|
19
|
+
import { clearSketchesForProject } from "../sketch/store.js";
|
|
13
20
|
const SETTINGS_SECTIONS = [
|
|
14
21
|
{
|
|
15
22
|
id: "instructions",
|
|
16
|
-
label: "
|
|
23
|
+
label: "Instructions",
|
|
17
24
|
icon: _jsx(IconSettings, { size: "var(--icon-size-small)", stroke: 1.8, "aria-hidden": "true" }),
|
|
18
25
|
},
|
|
19
26
|
{
|
|
@@ -27,11 +34,6 @@ const SETTINGS_SECTIONS = [
|
|
|
27
34
|
icon: _jsx(IconColorSwatch, { size: "var(--icon-size-small)", stroke: 1.8, "aria-hidden": "true" }),
|
|
28
35
|
},
|
|
29
36
|
];
|
|
30
|
-
function portalContainer() {
|
|
31
|
-
return typeof document !== "undefined"
|
|
32
|
-
? document.getElementById("nudge-ui-root")?.shadowRoot ?? document.body
|
|
33
|
-
: null;
|
|
34
|
-
}
|
|
35
37
|
/** Provides one settings surface for prompt, MCP, and token configuration. */
|
|
36
38
|
export function SettingsDialog({ open, initialSection, value, onValueChange, onOpenChange, projectId, origin, snapshot, onConnect, onTakeOver, onDisconnect, onCheckAgain, }) {
|
|
37
39
|
const [activeSection, setActiveSection] = useState(initialSection);
|
|
@@ -52,5 +54,16 @@ export function SettingsDialog({ open, initialSection, value, onValueChange, onO
|
|
|
52
54
|
if (open)
|
|
53
55
|
setActiveSection(initialSection);
|
|
54
56
|
}, [initialSection, open]);
|
|
55
|
-
|
|
57
|
+
function resetCanvas() {
|
|
58
|
+
if (!hasWriteLease())
|
|
59
|
+
return;
|
|
60
|
+
cancelSketchInteraction();
|
|
61
|
+
closeSketchNote();
|
|
62
|
+
clearSketchClipboardHandoff();
|
|
63
|
+
clearSession();
|
|
64
|
+
clearRestoreCount();
|
|
65
|
+
void clearSketchesForProject(projectId).catch(() => undefined);
|
|
66
|
+
onOpenChange(false);
|
|
67
|
+
}
|
|
68
|
+
return (_jsx(Dialog.Root, { open: open, onOpenChange: onOpenChange, children: _jsxs(Dialog.Portal, { container: portalContainer(), children: [_jsx(Dialog.Backdrop, { className: "settings__backdrop", "data-test": "settings-backdrop" }), _jsxs(Dialog.Popup, { className: "settings__popup", "data-test": "settings-dialog", initialFocus: closeRef, children: [_jsx(Dialog.Title, { className: "settings__visually-hidden", children: "Settings" }), _jsx(Dialog.Description, { className: "settings__visually-hidden", children: "Configure how Nudge connects to your coding agent and uses your design system." }), _jsx(Dialog.Close, { ref: closeRef, className: "icon-button icon-button--quiet settings__close", "aria-label": "Close settings", "data-test": "settings-close", type: "button", children: _jsx(IconX, { size: "var(--icon-size-small)", stroke: 1.8, "aria-hidden": "true" }) }), _jsxs("div", { className: "settings__body", children: [_jsxs("nav", { className: "settings__nav", "aria-label": "Settings sections", children: [_jsx("span", { className: "settings__nav-label", children: "Settings" }), _jsx("div", { className: "settings__nav-items", children: SETTINGS_SECTIONS.map((section) => (_jsxs("button", { className: `settings__nav-item${activeSection === section.id ? " settings__nav-item--active" : ""}`, "data-test": `settings-nav-${section.id}`, type: "button", "aria-current": activeSection === section.id ? "page" : undefined, onClick: () => setActiveSection(section.id), children: [section.icon, _jsx("span", { className: "settings__nav-item-label", children: section.label })] }, section.id))) }), _jsxs("button", { className: "settings__nav-item settings__reset-canvas", "data-test": "settings-reset-canvas", type: "button", onClick: resetCanvas, children: [_jsx(IconTrash, { size: "var(--icon-size-small)", stroke: 1.8, "aria-hidden": "true" }), _jsx("span", { className: "settings__nav-item-label", children: "Reset canvas" })] })] }), _jsxs("main", { className: "settings__content", "data-test": "settings-content", children: [activeSection === "instructions" ? (_jsxs("section", { className: "settings__section", "data-test": "prompt-settings-dialog", "data-settings-section": "instructions", children: [_jsx("h2", { className: "settings__section-title", children: "Custom instructions" }), _jsx("p", { className: "settings__section-description", children: "These instructions are added to the end of every copied prompt." }), _jsx(PromptSettingsFields, { value: value, onChange: onValueChange, instructionsRef: instructionsRef })] })) : null, activeSection === "mcp" ? (_jsxs("section", { className: "settings__section", "data-test": "settings-section-mcp", children: [_jsx("h2", { className: "settings__section-title", children: activeDefinition.label }), _jsx("div", { "data-test": "mcp-connection-dialog", children: _jsx(McpConnectionContent, { projectId: projectId, origin: origin, snapshot: snapshot, onConnect: onConnect, onTakeOver: onTakeOver, onDisconnect: onDisconnect, onCheckAgain: onCheckAgain }) })] })) : null, activeSection === "tokens" ? (_jsxs("section", { className: "settings__section", "data-test": "settings-section-tokens", children: [_jsx("h2", { className: "settings__section-title", children: activeDefinition.label }), _jsx("p", { className: "settings__section-description", children: "Inspect and edit the design tokens available in this page." }), _jsx(TokensPanel, { rows: tokenRows })] })) : null] })] })] })] }) }));
|
|
56
69
|
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { ReactElement } from "react";
|
|
2
|
+
import { type AgentClientSnapshot } from "../agent/client.js";
|
|
3
|
+
import type { SettingsSection } from "../settings/SettingsDialog.js";
|
|
4
|
+
export interface AgentStatusButtonProps {
|
|
5
|
+
onOpenSettings: (section: SettingsSection) => void;
|
|
6
|
+
}
|
|
7
|
+
export declare function AgentStatusButton({ onOpenSettings }: AgentStatusButtonProps): ReactElement;
|
|
8
|
+
/** Renders the connection snapshot provided by the project client. */
|
|
9
|
+
export declare function AgentStatusButtonView({ agent, onOpenSettings }: AgentStatusButtonProps & {
|
|
10
|
+
agent: AgentClientSnapshot;
|
|
11
|
+
}): ReactElement;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { IconRobot } from "@tabler/icons-react";
|
|
3
|
+
import { useAgentClient } from "../agent/client.js";
|
|
4
|
+
import { getAgentConnectionStatus } from "../agent/connectionStatus.js";
|
|
5
|
+
import { useNudgeUiRuntimeConfig } from "../runtime/useRuntimeConfig.js";
|
|
6
|
+
import { Button } from "../ui/Button.js";
|
|
7
|
+
import { Tooltip } from "../ui/Tooltip.js";
|
|
8
|
+
/** Renders a known MCP client logo, or a generic robot avatar. */
|
|
9
|
+
function ConnectedAgentAvatar({ name }) {
|
|
10
|
+
const harness = name?.toLowerCase().match(/(?:^|[^a-z])(codex|claude|cursor)(?:$|[^a-z])/)?.[1];
|
|
11
|
+
return (_jsx("span", { className: "agent-status-button__avatars", role: "img", "aria-label": harness === "codex" ? "Codex" : harness === "claude" ? "Claude" : harness === "cursor" ? "Cursor" : "Agent", children: harness === "codex" ? _jsx(CodexAvatar, {})
|
|
12
|
+
: harness === "claude" ? _jsx(ClaudeAvatar, {})
|
|
13
|
+
: harness === "cursor" ? _jsx(CursorAvatar, {})
|
|
14
|
+
: _jsx("span", { className: "agent-status-button__avatar", children: _jsx(IconRobot, { size: 24, color: "#000", "aria-hidden": "true" }) }) }));
|
|
15
|
+
}
|
|
16
|
+
function CodexAvatar() {
|
|
17
|
+
return (_jsx("span", { className: "agent-status-button__avatar", children: _jsx("svg", { viewBox: "0 0 24 24", width: "24", height: "24", fill: "none", children: _jsx("path", { fill: "#000", d: "M20.686 10.184a4.92 4.92 0 0 0-.435-4.092 5.1 5.1 0 0 0-2.35-2.093 5.17 5.17 0 0 0-3.15-.324A5.13 5.13 0 0 0 12.53 2.25a5.2 5.2 0 0 0-2.648-.14 5.15 5.15 0 0 0-2.364 1.185 5.05 5.05 0 0 0-1.447 2.19 5.1 5.1 0 0 0-1.953.85A5 5 0 0 0 2.693 7.9a4.98 4.98 0 0 0 .627 5.914 4.92 4.92 0 0 0 .432 4.092A5.1 5.1 0 0 0 6.104 20c.99.435 2.093.548 3.151.324.478.53 1.065.955 1.722 1.243a5.1 5.1 0 0 0 2.087.433 5.16 5.16 0 0 0 3.018-.968 5.05 5.05 0 0 0 1.858-2.537 5.1 5.1 0 0 0 1.953-.849 5 5 0 0 0 1.425-1.568 4.99 4.99 0 0 0-.632-5.894m-7.622 10.507a3.8 3.8 0 0 1-2.43-.867l.12-.067 4.037-2.299a.67.67 0 0 0 .332-.568v-5.614l1.706.974a.06.06 0 0 1 .032.043v4.653a3.73 3.73 0 0 1-1.114 2.646 3.83 3.83 0 0 1-2.683 1.099m-8.161-3.438a3.68 3.68 0 0 1-.452-2.511l.12.07 4.041 2.3a.66.66 0 0 0 .66 0l4.935-2.808v1.944a.07.07 0 0 1-.027.051l-4.09 2.326a3.85 3.85 0 0 1-2.88.373 3.8 3.8 0 0 1-2.307-1.745M3.84 8.58a3.78 3.78 0 0 1 1.998-1.644v4.73a.63.63 0 0 0 .328.564l4.912 2.796-1.707.973a.07.07 0 0 1-.06 0l-4.08-2.322a3.76 3.76 0 0 1-1.758-2.267 3.7 3.7 0 0 1 .367-2.83m14.02 3.213L12.934 8.97 14.635 8a.07.07 0 0 1 .06 0l4.08 2.326a3.77 3.77 0 0 1 1.467 1.508 3.7 3.7 0 0 1-.338 3.999 3.8 3.8 0 0 1-1.7 1.246v-4.73a.65.65 0 0 0-.343-.556m1.7-2.52-.12-.07-4.034-2.319a.66.66 0 0 0-.663 0L9.811 9.691V7.748a.05.05 0 0 1 .024-.051l4.08-2.323a3.84 3.84 0 0 1 4.073.174 3.76 3.76 0 0 0 1.332 1.63c.279.657.361 1.378.24 2.08zM8.88 12.72l-1.707-.97a.07.07 0 0 1-.032-.047v-4.64c.001-.712.207-1.409.595-2.01s.94-1.079 1.594-1.38a3.85 3.85 0 0 1 4.042.512l-.12.067-4.036 2.298a.67.67 0 0 0-.332.568zm.927-1.971 2.198-1.25 2.202 1.25v2.5l-2.194 1.25-2.202-1.25z" }) }) }));
|
|
18
|
+
}
|
|
19
|
+
function ClaudeAvatar() {
|
|
20
|
+
return (_jsx("span", { className: "agent-status-button__avatar", children: _jsx("svg", { viewBox: "0 0 24 24", width: "24", height: "24", fill: "none", children: _jsx("path", { fill: "#e8704e", d: "m5.924 15.296 3.934-2.206.066-.192-.066-.106h-.192l-.658-.04-2.248-.061-1.95-.081-1.888-.101-.476-.102L2 11.82l.046-.293.4-.268.572.05 1.266.086 1.898.132 1.377.08 2.041.213h.324l.046-.131-.112-.081-.086-.081-1.964-1.33L5.68 8.79l-1.114-.81-.602-.41-.304-.384-.132-.84.547-.602.734.05.188.051.744.572 1.59 1.23 2.076 1.527.304.253.121-.086.015-.06-.137-.228-1.129-2.04L7.377 4.94l-.536-.86-.142-.517a2.5 2.5 0 0 1-.086-.607l.623-.845L7.58 2l.83.111.35.304.516 1.179.835 1.857 1.297 2.524.38.749.202.693.076.213h.131v-.122l.107-1.421.197-1.746.193-2.246.065-.633.314-.759.623-.41.486.233.4.572-.055.37-.238 1.542-.466 2.419-.304 1.619h.177l.203-.203.82-1.087 1.377-1.72.608-.684.709-.753.455-.36h.861l.633.941-.284.972-.886 1.123-.734.951-1.053 1.417-.658 1.133.06.091.158-.015 2.38-.506 1.285-.233 1.535-.263.693.324.076.329-.273.673-1.64.405-1.925.384-2.866.678-.035.025.04.051 1.292.121.551.03h1.352l2.517.188.658.435.395.531-.066.405-1.012.516-1.368-.324-3.19-.759-1.093-.273h-.152v.091l.911.89 1.671 1.508 2.091 1.943.107.48-.269.38-.283-.04-1.838-1.381-.709-.623-1.605-1.35h-.106v.141l.37.542 1.954 2.934.1.9-.14.294-.507.177-.557-.101-1.144-1.604-1.18-1.806-.952-1.62-.117.067-.562 6.046-.263.308-.607.233-.507-.384-.268-.623.268-1.23.324-1.603.264-1.275.238-1.584.141-.526-.01-.035-.116.015-1.195 1.64-1.818 2.453-1.438 1.538-.344.137-.598-.309.056-.551.334-.491 1.99-2.53 1.2-1.568.775-.906-.005-.132h-.046l-5.286 3.43-.942.122-.405-.38.05-.622.193-.202 1.59-1.093z" }) }) }));
|
|
21
|
+
}
|
|
22
|
+
function CursorAvatar() {
|
|
23
|
+
return (_jsx("span", { className: "agent-status-button__avatar", children: _jsx("svg", { viewBox: "0 0 24 24", width: "24", height: "24", fill: "none", children: _jsx("path", { fill: "#000", d: "M11.576 2.11 3.359 6.731a.7.7 0 0 0-.262.256.7.7 0 0 0-.097.349v9.323c0 .25.138.48.359.604l8.214 4.625a.87.87 0 0 0 .853 0l8.215-4.625a.7.7 0 0 0 .262-.255.7.7 0 0 0-.097-.349V7.337a.7.7 0 0 0-.096-.35.7.7 0 0 0-.263-.255l-8.216-4.623a.88.88 0 0 0-.851 0m-7.56 5.173H19.87c.225 0 .367.24.254.43l-7.928 13.387c-.053.089-.196.053-.196-.05v-8.77a.48.48 0 0 0-.252-.425l-7.787-4.38c-.094-.053-.055-.192.052-.192" }) }) }));
|
|
24
|
+
}
|
|
25
|
+
export function AgentStatusButton({ onOpenSettings }) {
|
|
26
|
+
const runtimeConfig = useNudgeUiRuntimeConfig();
|
|
27
|
+
const agent = useAgentClient(runtimeConfig.projectId);
|
|
28
|
+
return _jsx(AgentStatusButtonView, { agent: agent, onOpenSettings: onOpenSettings });
|
|
29
|
+
}
|
|
30
|
+
/** Renders the connection snapshot provided by the project client. */
|
|
31
|
+
export function AgentStatusButtonView({ agent, onOpenSettings }) {
|
|
32
|
+
const status = getAgentConnectionStatus(agent);
|
|
33
|
+
const connected = agent.paired || agent.pairedElsewhere;
|
|
34
|
+
const listening = connected && agent.listenerActive;
|
|
35
|
+
return (_jsx(Tooltip, { content: connected ? status.label : "Agent & MCP settings", stableTrigger: true, children: _jsxs(Button, { variant: "quiet", className: "agent-status-button", "aria-label": connected ? `MCP · ${status.label}` : "Settings", "data-test": "settings-button", "data-mcp-connected": connected ? "true" : "false", "data-mcp-listening": listening ? "true" : "false", onClick: () => onOpenSettings("mcp"), children: [connected ? _jsx(ConnectedAgentAvatar, { name: agent.agentClientName }) : _jsxs("span", { className: "agent-status-button__avatars", children: [_jsx(CodexAvatar, {}), _jsx(ClaudeAvatar, {}), _jsx(CursorAvatar, {})] }), _jsx("span", { className: "agent-status-button__label", children: connected ? "MCP" : "Settings" }), connected ? (_jsx("span", { className: "agent-status-button__dot", "data-test": "agent-status-dot", "aria-hidden": "true" })) : null] }) }));
|
|
36
|
+
}
|
|
@@ -1,13 +1,15 @@
|
|
|
1
|
-
import { jsx as _jsx,
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { InspectorShell } from "./InspectorShell.js";
|
|
3
3
|
import { CanvasWorkspace } from "../canvas/CanvasWorkspace.js";
|
|
4
4
|
import { CanvasElementOverlay } from "../canvas/CanvasElementOverlay.js";
|
|
5
5
|
import { useNudgeUiRuntimeConfig } from "../runtime/useRuntimeConfig.js";
|
|
6
6
|
import { readNudgeUiEditorTarget } from "../../transport/editor.js";
|
|
7
|
+
import { TooltipGroup } from "../ui/Tooltip.js";
|
|
8
|
+
import { CommentsOverlay } from "../comments/CommentsOverlay.js";
|
|
7
9
|
export function AppShell() {
|
|
8
10
|
const canvasEnabled = useNudgeUiRuntimeConfig().capabilities.canvas;
|
|
9
11
|
const primaryUrl = typeof window === "undefined"
|
|
10
12
|
? null
|
|
11
13
|
: readNudgeUiEditorTarget(window.location.href);
|
|
12
|
-
return (_jsxs(
|
|
14
|
+
return (_jsxs(TooltipGroup, { children: [canvasEnabled ? _jsx(CanvasWorkspace, { primaryUrl: primaryUrl }) : null, canvasEnabled ? _jsx(CanvasElementOverlay, {}) : null, canvasEnabled ? _jsx(CommentsOverlay, {}) : null, _jsx(InspectorShell, {})] }));
|
|
13
15
|
}
|
|
@@ -1,15 +1,20 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { useMemo, useSyncExternalStore } from "react";
|
|
3
|
-
import {
|
|
3
|
+
import { IconArrowBackUp } from "@tabler/icons-react";
|
|
4
|
+
import { isComponentChange, isElementChange, isTextContentChange, isTokenChange, useChanges, revertChange, } from "../changes/changesLog.js";
|
|
4
5
|
import { StaleChangeIndicator } from "../canvas/StaleChangeIndicator.js";
|
|
5
6
|
import { Button } from "../ui/Button.js";
|
|
6
7
|
import { Disclosure } from "../ui/Disclosure.js";
|
|
8
|
+
import { IconButton } from "../ui/IconButton.js";
|
|
9
|
+
import { Tooltip } from "../ui/Tooltip.js";
|
|
7
10
|
import { presentChange } from "../changes/presentation.js";
|
|
8
11
|
import { getStructuralChanges, getStructuralChangeDiagnostics, getStructuralDiagnosticRevision, revertStructuralChange, subscribeStructuralChanges, subscribeStructuralDiagnostics, } from "../projection/structuralProjection.js";
|
|
9
12
|
import { getRenderedInstanceChangeDiagnostics, getRenderedInstanceDiagnosticRevision, subscribeRenderedInstanceDiagnostics, } from "../projection/renderedInstance.js";
|
|
10
13
|
import { getTextContentChangeDiagnostics, getTextProjectionDiagnosticRevision, subscribeTextProjectionDiagnostics, } from "../projection/textProjection.js";
|
|
11
14
|
import { SketchChanges } from "../sketch/SketchChanges.js";
|
|
12
15
|
import { useSketchStore } from "../sketch/store.js";
|
|
16
|
+
import { useFrameComments } from "../comments/store.js";
|
|
17
|
+
import { countPromptChanges } from "../prompt/generatePrompt.js";
|
|
13
18
|
function groupChanges(changes) {
|
|
14
19
|
const map = new Map();
|
|
15
20
|
for (const change of changes) {
|
|
@@ -20,7 +25,6 @@ function groupChanges(changes) {
|
|
|
20
25
|
group = {
|
|
21
26
|
key,
|
|
22
27
|
label: presentation.groupLabel,
|
|
23
|
-
file: presentation.file,
|
|
24
28
|
changes: [],
|
|
25
29
|
};
|
|
26
30
|
map.set(key, group);
|
|
@@ -29,9 +33,6 @@ function groupChanges(changes) {
|
|
|
29
33
|
}
|
|
30
34
|
return Array.from(map.values());
|
|
31
35
|
}
|
|
32
|
-
function sourceFile(change) {
|
|
33
|
-
return change.target.sourceSite.src.split(":").slice(0, -2).join(":") || change.target.sourceSite.src;
|
|
34
|
-
}
|
|
35
36
|
function structuralParentLabel(change, side) {
|
|
36
37
|
const parent = side === "source" ? change.source.parent : change.destination.parent;
|
|
37
38
|
const tag = side === "source" ? change.presentation.sourceParentTag : change.presentation.destinationParentTag;
|
|
@@ -60,8 +61,26 @@ function structuralReasonLabel(reason) {
|
|
|
60
61
|
function structuralDiagnosticText(diagnostic) {
|
|
61
62
|
return `${diagnostic.document}: ${diagnostic.status}${diagnostic.reason ? ` (${structuralReasonLabel(diagnostic.reason)})` : ""}`;
|
|
62
63
|
}
|
|
64
|
+
function changeTargetLabel(change, presentation) {
|
|
65
|
+
if (isComponentChange(change))
|
|
66
|
+
return change.target.componentName;
|
|
67
|
+
if (isTextContentChange(change))
|
|
68
|
+
return change.target.sourceSite.cid;
|
|
69
|
+
if (isTokenChange(change))
|
|
70
|
+
return change.tokenName;
|
|
71
|
+
return isElementChange(change) ? change.cid : presentation.groupLabel;
|
|
72
|
+
}
|
|
73
|
+
function changeActionLabel(change, presentation) {
|
|
74
|
+
if (isTextContentChange(change))
|
|
75
|
+
return "Changed text";
|
|
76
|
+
return `Changed ${presentation.propertyLabel}`;
|
|
77
|
+
}
|
|
78
|
+
function RevertButton({ dataTest, dataProperty, onClick, }) {
|
|
79
|
+
return (_jsx(Tooltip, { content: "Revert", stableTrigger: true, children: _jsx(IconButton, { variant: "quiet", size: "compact", className: "changes__revert", "data-test": dataTest, "data-property": dataProperty, label: "Revert change", onClick: onClick, children: _jsx(IconArrowBackUp, { size: "var(--icon-size-small)", stroke: "var(--icon-stroke-width)", "aria-hidden": "true" }) }) }));
|
|
80
|
+
}
|
|
63
81
|
export function ChangesLog({ onClearSession }) {
|
|
64
82
|
const changes = useChanges();
|
|
83
|
+
const comments = useFrameComments();
|
|
65
84
|
const sketchStore = useSketchStore();
|
|
66
85
|
const sketches = sketchStore.items;
|
|
67
86
|
const structuralChanges = useSyncExternalStore(subscribeStructuralChanges, getStructuralChanges, getStructuralChanges);
|
|
@@ -71,26 +90,27 @@ export function ChangesLog({ onClearSession }) {
|
|
|
71
90
|
useSyncExternalStore(subscribeRenderedInstanceDiagnostics, getRenderedInstanceDiagnosticRevision, getRenderedInstanceDiagnosticRevision);
|
|
72
91
|
useSyncExternalStore(subscribeTextProjectionDiagnostics, getTextProjectionDiagnosticRevision, getTextProjectionDiagnosticRevision);
|
|
73
92
|
const groups = useMemo(() => groupChanges(changes), [changes]);
|
|
74
|
-
const total = changes
|
|
75
|
-
|
|
93
|
+
const total = countPromptChanges(changes, structuralChanges, sketches.length);
|
|
94
|
+
const hasLoggedChanges = total > 0 || sketchStore.error !== null;
|
|
95
|
+
if (!hasLoggedChanges && comments.length === 0)
|
|
76
96
|
return null;
|
|
77
|
-
return (_jsxs(_Fragment, { children: [_jsx(Disclosure, { className: "changes", "data-test": "changes-log", triggerDataTest: "changes-toggle", title: "Changes", badge: total > 0 ? _jsx("span", { className: "changes__count", children: total }) : null, panelClassName: "changes__content", children: groups.length === 0 && structuralChanges.length === 0 && sketches.length === 0 && sketchStore.error === null ? (_jsx("div", { className: "changes__empty", "data-test": "changes-empty", children: "No changes yet" })) : (_jsxs(_Fragment, { children: [groups.map((group) => (
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
97
|
+
return (_jsxs(_Fragment, { children: [hasLoggedChanges ? _jsx(Disclosure, { className: "changes", "data-test": "changes-log", triggerDataTest: "changes-toggle", title: "Changes", badge: total > 0 ? _jsx("span", { className: "changes__count", children: total }) : null, panelClassName: "changes__content", children: groups.length === 0 && structuralChanges.length === 0 && sketches.length === 0 && sketchStore.error === null ? (_jsx("div", { className: "changes__empty", "data-test": "changes-empty", children: "No changes yet" })) : (_jsxs(_Fragment, { children: [groups.map((group) => (_jsx("div", { className: "changes__group", "data-test": "changes-group", "data-cid": group.label, children: group.changes.map((change, i) => {
|
|
98
|
+
const presentation = presentChange(change);
|
|
99
|
+
const instanceDiagnostics = isElementChange(change) && change.scope === "rendered-instance"
|
|
100
|
+
&& change.instanceOverride
|
|
101
|
+
? getRenderedInstanceChangeDiagnostics(change.instanceOverride.id)
|
|
102
|
+
: [];
|
|
103
|
+
const textDiagnostics = change.kind === "text-content"
|
|
104
|
+
? getTextContentChangeDiagnostics(change.id)
|
|
105
|
+
: [];
|
|
106
|
+
return (_jsxs("div", { className: "changes__row", "data-test": "change-row", "data-property": presentation.property, children: [_jsx("span", { className: "changes__target", "data-test": "change-target", children: changeTargetLabel(change, presentation) }), _jsx("span", { className: "changes__action", "data-test": "change-action", children: changeActionLabel(change, presentation) }), _jsxs("span", { className: "changes__metadata", "aria-hidden": "true", children: [_jsx("span", { className: "changes__prop", children: presentation.propertyLabel }), _jsxs("span", { className: "changes__value", children: [_jsx("span", { className: "changes__before", children: presentation.before }), _jsx("span", { className: "changes__arrow", children: "\u2192" }), _jsx("span", { className: "changes__after", children: presentation.after })] }), presentation.scope ? (_jsx("span", { className: "changes__scope", "data-test": "change-scope", children: presentation.scope === "source-site" ? "All outputs at source site" : "This rendered item only" })) : null, presentation.evidence ? (_jsx("span", { className: "changes__evidence", "data-test": "change-evidence", children: presentation.evidence })) : null, _jsx(StaleChangeIndicator, { change: change }), instanceDiagnostics.map((diagnostic) => (_jsxs("span", { className: "changes__diagnostic", "data-test": "instance-diagnostic", "data-document": diagnostic.document, "data-status": diagnostic.status, children: [diagnostic.document, ": ", diagnostic.status] }, `${diagnostic.document}:${diagnostic.status}`))), textDiagnostics.map((diagnostic) => (_jsxs("span", { className: "changes__diagnostic", "data-test": "text-projection-diagnostic", "data-document": diagnostic.document, "data-status": diagnostic.status, children: [diagnostic.document, ": ", diagnostic.status] }, `${diagnostic.document}:${diagnostic.status}`)))] }), _jsx(RevertButton, { dataTest: "change-revert", dataProperty: presentation.property, onClick: () => revertChange(change) })] }, `${group.key}\u0000${presentation.property}\u0000${i}`));
|
|
107
|
+
}) }, group.key))), structuralChanges.map((change) => (_jsx("div", { className: "changes__group", "data-test": "dom-change", "data-cid": change.target.sourceSite.cid, children: _jsxs("div", { className: "changes__row", "data-test": "dom-change-row", "data-action": change.kind, children: [_jsx("span", { className: "changes__target", "data-test": "structural-target", children: change.target.sourceSite.cid }), _jsx("span", { className: "changes__action", "data-test": "structural-action", children: change.kind === "move" ? "Moved" : "Deleted" }), _jsxs("span", { className: "changes__metadata", "aria-hidden": "true", children: [_jsxs("span", { className: "changes__source-site", "data-test": "structural-source-site", children: ["Source site: ", change.target.sourceSite.cid] }), _jsx("span", { className: "changes__prop", children: change.kind === "move" ? "Move in DOM" : "Delete from DOM" }), _jsxs("span", { className: "changes__value", children: [_jsx("span", { className: "changes__before", children: change.kind === "move"
|
|
108
|
+
? structuralParentIdentityKey(change.source.parent) === structuralParentIdentityKey(change.destination.parent)
|
|
109
|
+
? `${change.presentation.sourceParentTag} position ${change.presentation.fromIndex + 1}`
|
|
110
|
+
: `${structuralParentLabel(change, "source")} position ${change.presentation.fromIndex + 1}`
|
|
111
|
+
: "Visible" }), _jsx("span", { className: "changes__arrow", children: "\u2192" }), _jsx("span", { className: "changes__after", children: change.kind === "move"
|
|
112
|
+
? structuralParentIdentityKey(change.source.parent) === structuralParentIdentityKey(change.destination.parent)
|
|
113
|
+
? `${change.presentation.destinationParentTag} position ${change.presentation.toIndex + 1}`
|
|
114
|
+
: `${structuralParentLabel(change, "destination")} position ${change.presentation.toIndex + 1}`
|
|
115
|
+
: "Removed" })] }), _jsx("span", { className: "changes__scope", "data-test": "structural-scope", children: "This rendered item only" }), getStructuralChangeDiagnostics(change.id).map((diagnostic) => (_jsx("span", { className: "changes__diagnostic", "data-test": "structural-diagnostic", "data-document": diagnostic.document, "data-status": diagnostic.status, "data-reason": diagnostic.reason, children: structuralDiagnosticText(diagnostic) }, `${diagnostic.document}:${diagnostic.status}:${diagnostic.reason ?? ""}`)))] }), _jsx(RevertButton, { dataTest: "dom-change-revert", onClick: () => revertStructuralChange(change.id) })] }) }, change.id))), _jsx(SketchChanges, {})] })) }) : null, onClearSession ? (_jsx("div", { className: "changes__session-action", "data-test": "session-actions", children: _jsx(Button, { variant: "secondary", type: "button", "data-test": "clear-session", onClick: onClearSession, children: "Clear Changes" }) })) : null] }));
|
|
96
116
|
}
|