nudge-ui 0.2.1 → 0.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +164 -46
- package/dist/client.mjs +252 -54
- 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 +41 -32
- package/dist/hosts/astro/integration.d.ts +2 -2
- package/dist/hosts/astro/integration.js +9 -4
- package/dist/hosts/astro/markdownIdentity.d.ts +28 -0
- package/dist/hosts/astro/markdownIdentity.js +81 -0
- package/dist/hosts/environment.d.ts +15 -0
- package/dist/hosts/environment.js +16 -0
- package/dist/hosts/next/manifest.js +1 -1
- package/dist/hosts/next/sidecar.js +12 -2
- package/dist/hosts/next/wrapper.d.ts +2 -0
- package/dist/hosts/next/wrapper.js +2 -1
- package/dist/hosts/projectBridge.d.ts +1 -0
- package/dist/hosts/projectBridge.js +1 -0
- package/dist/hosts/static/manifest.js +3 -1
- package/dist/hosts/static/server.js +4 -0
- package/dist/hosts/vite/vite.d.ts +4 -0
- package/dist/hosts/vite/vite.js +28 -5
- package/dist/inspector/agent/McpConnectionDialog.d.ts +3 -2
- package/dist/inspector/agent/McpConnectionDialog.js +23 -22
- package/dist/inspector/agent/activity.d.ts +18 -0
- package/dist/inspector/agent/activity.js +70 -0
- package/dist/inspector/agent/client.d.ts +8 -0
- package/dist/inspector/agent/client.js +65 -5
- package/dist/inspector/agent/connectionStatus.d.ts +3 -3
- package/dist/inspector/agent/connectionStatus.js +9 -2
- package/dist/inspector/agent/httpTransport.d.ts +6 -0
- package/dist/inspector/agent/httpTransport.js +50 -3
- package/dist/inspector/agent/protocol.d.ts +9 -3
- package/dist/inspector/agent/protocol.js +1 -1
- package/dist/inspector/agent/verification.d.ts +11 -1
- package/dist/inspector/agent/verification.js +53 -25
- 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 +133 -38
- package/dist/inspector/canvas/CanvasElementOverlay.js +200 -22
- 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 +243 -56
- 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 +34 -4
- package/dist/inspector/canvas/frameProtocol.js +9 -2
- package/dist/inspector/canvas/keyboardShortcuts.d.ts +4 -1
- package/dist/inspector/canvas/keyboardShortcuts.js +5 -3
- package/dist/inspector/canvas/layout.d.ts +52 -0
- package/dist/inspector/canvas/layout.js +106 -0
- package/dist/inspector/canvas/linkEligibility.d.ts +0 -5
- package/dist/inspector/canvas/linkEligibility.js +0 -29
- package/dist/inspector/canvas/projection.d.ts +15 -5
- package/dist/inspector/canvas/projection.js +69 -13
- package/dist/inspector/canvas/rendererBootstrap.js +45 -4
- package/dist/inspector/canvas/rendererElementSelector.d.ts +1 -1
- package/dist/inspector/canvas/rendererElementSelector.js +102 -45
- 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 +6 -5
- package/dist/inspector/changes/changesLog.js +40 -32
- package/dist/inspector/changes/draftChanges.d.ts +56 -0
- package/dist/inspector/changes/draftChanges.js +300 -0
- package/dist/inspector/changes/previewDiagnostics.d.ts +4 -2
- package/dist/inspector/changes/previewDiagnostics.js +11 -25
- package/dist/inspector/clientManifest.d.ts +3 -1
- package/dist/inspector/clientManifest.js +1 -0
- 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 +47 -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/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 +26 -35
- 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 +173 -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.d.ts +10 -0
- package/dist/inspector/overlay/DomNavigator.js +46 -0
- package/dist/inspector/overlay/InspectorOverlay.js +6 -2
- package/dist/inspector/overlay/clickPolicy.d.ts +18 -2
- package/dist/inspector/overlay/clickPolicy.js +34 -3
- package/dist/inspector/overlay/elementSelector.d.ts +1 -1
- package/dist/inspector/overlay/elementSelector.js +18 -7
- package/dist/inspector/overlay/interactionStyles.js +3 -1
- package/dist/inspector/overlay/spacingGestures.d.ts +15 -3
- package/dist/inspector/overlay/spacingGestures.js +88 -13
- 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 +2 -1
- package/dist/inspector/projection/renderedInstance.js +9 -5
- package/dist/inspector/projection/structuralProjection.d.ts +2 -1
- package/dist/inspector/projection/structuralProjection.js +19 -15
- package/dist/inspector/projection/textProjection.d.ts +2 -1
- package/dist/inspector/projection/textProjection.js +8 -4
- package/dist/inspector/prompt/PromptSettingsDialog.js +1 -5
- package/dist/inspector/prompt/clipboardHandoff.d.ts +10 -18
- package/dist/inspector/prompt/clipboardHandoff.js +92 -143
- package/dist/inspector/prompt/generatePrompt.d.ts +4 -1
- package/dist/inspector/prompt/generatePrompt.js +17 -16
- package/dist/inspector/runtime/runtimeConfig.d.ts +10 -1
- package/dist/inspector/runtime/runtimeConfig.js +24 -0
- package/dist/inspector/selection/hierarchy.d.ts +6 -0
- package/dist/inspector/selection/hierarchy.js +8 -0
- package/dist/inspector/settings/SettingsDialog.d.ts +1 -1
- package/dist/inspector/settings/SettingsDialog.js +22 -9
- 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 +47 -27
- package/dist/inspector/shell/CopyPromptButton.js +146 -90
- package/dist/inspector/shell/EmptyState.js +9 -8
- package/dist/inspector/shell/InspectorShell.js +14 -25
- 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/sketch/store.js +48 -23
- 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 +16 -9
- 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 +4 -4
- package/dist/inspector/styleEditors/nudgeValue.js +41 -11
- package/dist/inspector/tokens/TokenField.d.ts +7 -0
- package/dist/inspector/tokens/TokenField.js +49 -22
- package/dist/inspector/tokens/TokenLabel.js +5 -14
- package/dist/inspector/tokens/TokensPanel.js +2 -1
- package/dist/inspector/tokens/dragPointerLock.d.ts +8 -0
- package/dist/inspector/tokens/dragPointerLock.js +70 -0
- package/dist/inspector/tokens/editActions.d.ts +1 -1
- package/dist/inspector/tokens/editActions.js +1 -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/Disclosure.d.ts +22 -0
- package/dist/inspector/ui/Disclosure.js +13 -0
- 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 +6 -0
- package/dist/inspector/ui/dragCursor.js +13 -0
- package/dist/inspector/ui/portalContainer.d.ts +2 -0
- package/dist/inspector/ui/portalContainer.js +6 -0
- package/dist/inspector/ui/styles.js +34 -24
- 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/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 +560 -299
- 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.d.ts +20 -1
- package/dist/transport/editor.js +44 -11
- package/dist/transport/routes.d.ts +6 -1
- package/dist/transport/routes.js +6 -1
- package/package.json +6 -2
- package/dist/inspector/changes/workspaceChanges.d.ts +0 -43
- package/dist/inspector/changes/workspaceChanges.js +0 -239
- package/dist/inspector/shell/DomNavigation.d.ts +0 -8
- package/dist/inspector/shell/DomNavigation.js +0 -30
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AGENT_PROTOCOL_VERSION, defaultBridgePort, isAgentPromptRequest, } from "./protocol.js";
|
|
1
|
+
import { AGENT_PROTOCOL_VERSION, defaultBridgePort, isAgentPromptRequest, isAgentActivity, } from "./protocol.js";
|
|
2
2
|
import { getActiveCanvasDocument } from "../canvas/activeCanvasDocument.js";
|
|
3
3
|
function isRecord(value) {
|
|
4
4
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
@@ -18,6 +18,7 @@ function endpointValue(value) {
|
|
|
18
18
|
statusUrl: stringValue(value.statusUrl),
|
|
19
19
|
canvasAckUrl: stringValue(value.canvasAckUrl),
|
|
20
20
|
disconnectUrl: stringValue(value.disconnectUrl),
|
|
21
|
+
takeoverUrl: stringValue(value.takeoverUrl),
|
|
21
22
|
...(value.autoConnect === true ? { autoConnect: true } : {}),
|
|
22
23
|
};
|
|
23
24
|
return Object.values(config).some((entry) => entry !== undefined) ? config : undefined;
|
|
@@ -96,6 +97,16 @@ function headers() {
|
|
|
96
97
|
Accept: "application/json",
|
|
97
98
|
};
|
|
98
99
|
}
|
|
100
|
+
export class AgentBridgeHttpError extends Error {
|
|
101
|
+
status;
|
|
102
|
+
code;
|
|
103
|
+
constructor(status, message, code) {
|
|
104
|
+
super(message);
|
|
105
|
+
this.name = "AgentBridgeHttpError";
|
|
106
|
+
this.status = status;
|
|
107
|
+
this.code = code;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
99
110
|
async function readJson(response) {
|
|
100
111
|
let payload;
|
|
101
112
|
try {
|
|
@@ -107,7 +118,8 @@ async function readJson(response) {
|
|
|
107
118
|
if (!response.ok) {
|
|
108
119
|
const error = isRecord(payload) && isRecord(payload.error) ? payload.error : payload;
|
|
109
120
|
const message = isRecord(error) ? stringValue(error.message) : undefined;
|
|
110
|
-
|
|
121
|
+
const code = isRecord(error) ? stringValue(error.code) : undefined;
|
|
122
|
+
throw new AgentBridgeHttpError(response.status, message ?? `Agent bridge request failed (${response.status}).`, code);
|
|
111
123
|
}
|
|
112
124
|
return isRecord(payload) ? payload : {};
|
|
113
125
|
}
|
|
@@ -156,6 +168,7 @@ function statusPayload(value) {
|
|
|
156
168
|
projectId: status.projectId,
|
|
157
169
|
connection: status.connection,
|
|
158
170
|
listenerActive: status.listenerActive,
|
|
171
|
+
...(typeof status.agentClientName === "string" ? { agentClientName: status.agentClientName.slice(0, 120) } : {}),
|
|
159
172
|
paired: status.paired,
|
|
160
173
|
request,
|
|
161
174
|
};
|
|
@@ -177,6 +190,8 @@ function eventPayload(value) {
|
|
|
177
190
|
if (type === "disconnected") {
|
|
178
191
|
return { type: "disconnected", ...(stringValue(event.reason) ? { reason: stringValue(event.reason) } : {}) };
|
|
179
192
|
}
|
|
193
|
+
if (type === "activity" && isAgentActivity(event.activity))
|
|
194
|
+
return { type: "activity", activity: event.activity };
|
|
180
195
|
if (type === "canvas-command" && isRecord(event.command)) {
|
|
181
196
|
// The Canvas controller owns command validation. Preserve the shared
|
|
182
197
|
// shape here so the parent stage can consume this event without a second
|
|
@@ -253,6 +268,34 @@ export class HttpAgentBridgeTransport {
|
|
|
253
268
|
status,
|
|
254
269
|
};
|
|
255
270
|
}
|
|
271
|
+
async takeOver(request, signal) {
|
|
272
|
+
const url = endpointUrl(this.config, request.projectId, "takeoverUrl", "/takeover", pageOrigin());
|
|
273
|
+
if (!url || typeof fetch !== "function")
|
|
274
|
+
throw new Error("Agent bridge is unavailable.");
|
|
275
|
+
const response = await fetch(url, {
|
|
276
|
+
method: "POST",
|
|
277
|
+
headers: { ...headers(), "Content-Type": "application/json" },
|
|
278
|
+
body: JSON.stringify(request),
|
|
279
|
+
signal,
|
|
280
|
+
});
|
|
281
|
+
const payload = await readJson(response);
|
|
282
|
+
if (payload.protocolVersion !== AGENT_PROTOCOL_VERSION
|
|
283
|
+
|| payload.projectId !== request.projectId
|
|
284
|
+
|| payload.origin !== request.origin
|
|
285
|
+
|| typeof payload.sessionToken !== "string") {
|
|
286
|
+
throw new Error("Agent bridge returned an invalid takeover response.");
|
|
287
|
+
}
|
|
288
|
+
const status = statusPayload(payload.status);
|
|
289
|
+
if (!status)
|
|
290
|
+
throw new Error("Agent bridge returned an invalid status.");
|
|
291
|
+
return {
|
|
292
|
+
protocolVersion: AGENT_PROTOCOL_VERSION,
|
|
293
|
+
projectId: request.projectId,
|
|
294
|
+
origin: request.origin,
|
|
295
|
+
sessionToken: payload.sessionToken,
|
|
296
|
+
status,
|
|
297
|
+
};
|
|
298
|
+
}
|
|
256
299
|
async restore(request, signal) {
|
|
257
300
|
const url = endpointUrl(this.config, request.projectId, "statusUrl", "/status", pageOrigin());
|
|
258
301
|
if (!url || typeof fetch !== "function")
|
|
@@ -282,7 +325,10 @@ export class HttpAgentBridgeTransport {
|
|
|
282
325
|
const source = new EventSource(eventUrl.href);
|
|
283
326
|
let closed = false;
|
|
284
327
|
const handleMessage = (event) => {
|
|
285
|
-
const
|
|
328
|
+
const value = eventData(event);
|
|
329
|
+
if (isRecord(value) && "event" in value && (value.protocolVersion !== AGENT_PROTOCOL_VERSION || value.projectId !== request.projectId || value.sessionToken !== request.sessionToken))
|
|
330
|
+
return;
|
|
331
|
+
const parsed = eventPayload(value);
|
|
286
332
|
if (parsed)
|
|
287
333
|
handlers.onEvent(parsed);
|
|
288
334
|
};
|
|
@@ -290,6 +336,7 @@ export class HttpAgentBridgeTransport {
|
|
|
290
336
|
source.addEventListener("status", handleMessage);
|
|
291
337
|
source.addEventListener("connected", handleMessage);
|
|
292
338
|
source.addEventListener("disconnected", handleMessage);
|
|
339
|
+
source.addEventListener("activity", handleMessage);
|
|
293
340
|
source.addEventListener("canvas-command", handleMessage);
|
|
294
341
|
source.onerror = () => {
|
|
295
342
|
if (closed)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AgentStatusSnapshot, CanvasCommand, CanvasCommandAcknowledgement, CanvasCommandResult, AgentSketchAttachment, PairingResponse, PromptDispatchResponse } from "../../internal/agent-protocol.js";
|
|
1
|
+
import type { AgentActivity, AgentStatusSnapshot, CanvasCommand, CanvasCommandAcknowledgement, CanvasCommandResult, AgentSketchAttachment, PairingResponse, PromptDispatchResponse } from "../../internal/agent-protocol.js";
|
|
2
2
|
/**
|
|
3
3
|
* Browser transport port for the shared Nudge agent protocol.
|
|
4
4
|
*
|
|
@@ -7,8 +7,8 @@ import type { AgentStatusSnapshot, CanvasCommand, CanvasCommandAcknowledgement,
|
|
|
7
7
|
* boundary local lets inspector tests use a deterministic fake while the
|
|
8
8
|
* companion remains the owner of MCP and Node-specific code.
|
|
9
9
|
*/
|
|
10
|
-
export { AGENT_PROTOCOL_LIMITS, AGENT_PROTOCOL_VERSION, defaultBridgePort, CANVAS_COMMAND_TYPES, canonicalOrigin, isAgentPromptRequest, isAgentSketchAttachment, isAgentSketchAnnotation, isAgentSketchCaptureMetadata, isAgentSketchMetadata, isAgentStatusUpdate, isAllowedOrigin, isCanvasCommand, isCanvasGroup, isCanvasState, isCanonicalOrigin, isProjectIdentity, isSameOriginRoute, protocolError, validateSketchAttachments, validateRoutes, } from "../../internal/agent-protocol.js";
|
|
11
|
-
export type { AgentConnectionState, AgentProjectIdentity, AgentPromptRequest, AgentDeliveredPrompt, AgentSketchAttachment, AgentSketchAnnotation, AgentSketchCaptureMetadata, AgentSketchMetadata, AgentRequestOutcome, AgentRequestStatus, AgentRoute, AgentStatusSnapshot, AgentStatusUpdate, BridgeCanvasCommandEvent, BridgeConnectedEvent, BridgeDisconnectedEvent, BridgeEnvelope, BridgeEvent, BridgeEventType, BridgeStatusEvent, CanvasCommand, CanvasCommandAcknowledgement, CanvasCommandError, CanvasCommandResult, CanvasGroup, CanvasGroupOwner, CanvasState, FitCanvasCommand, FocusCanvasGroupCommand, PairingRequest, PairingResponse, PresentRoutesCommand, PromptDispatchRequest, PromptDispatchResponse, ReadCanvasStateCommand, RemoveCanvasGroupCommand, StatusEventRequest, AgentProtocolVersion, } from "../../internal/agent-protocol.js";
|
|
10
|
+
export { AGENT_PROTOCOL_LIMITS, AGENT_PROTOCOL_VERSION, defaultBridgePort, CANVAS_COMMAND_TYPES, canonicalOrigin, isAgentPromptRequest, isAgentSketchAttachment, isAgentSketchAnnotation, isAgentSketchCaptureMetadata, isAgentSketchMetadata, isAgentStatusUpdate, isAgentActivity, isAllowedOrigin, isCanvasCommand, isCanvasGroup, isCanvasState, isCanonicalOrigin, isProjectIdentity, isSameOriginRoute, protocolError, validateSketchAttachments, validateRoutes, } from "../../internal/agent-protocol.js";
|
|
11
|
+
export type { AgentActivity, BridgeActivityEvent, AgentConnectionState, AgentProjectIdentity, AgentPromptRequest, AgentDeliveredPrompt, AgentSketchAttachment, AgentSketchAnnotation, AgentSketchCaptureMetadata, AgentSketchMetadata, AgentRequestOutcome, AgentRequestStatus, AgentRoute, AgentStatusSnapshot, AgentStatusUpdate, BridgeCanvasCommandEvent, BridgeConnectedEvent, BridgeDisconnectedEvent, BridgeEnvelope, BridgeEvent, BridgeEventType, BridgeStatusEvent, CanvasCommand, CanvasCommandAcknowledgement, CanvasCommandError, CanvasCommandResult, CanvasGroup, CanvasGroupOwner, CanvasState, FitCanvasCommand, FocusCanvasGroupCommand, PairingRequest, PairingResponse, PresentRoutesCommand, PromptDispatchRequest, PromptDispatchResponse, ReadCanvasStateCommand, RemoveCanvasGroupCommand, StatusEventRequest, AgentProtocolVersion, } from "../../internal/agent-protocol.js";
|
|
12
12
|
export interface AgentBridgeEndpointConfig {
|
|
13
13
|
readonly baseUrl?: string;
|
|
14
14
|
readonly healthUrl?: string;
|
|
@@ -18,6 +18,7 @@ export interface AgentBridgeEndpointConfig {
|
|
|
18
18
|
readonly statusUrl?: string;
|
|
19
19
|
readonly canvasAckUrl?: string;
|
|
20
20
|
readonly disconnectUrl?: string;
|
|
21
|
+
readonly takeoverUrl?: string;
|
|
21
22
|
/** Pair automatically when this endpoint came from the trusted dev host. */
|
|
22
23
|
readonly autoConnect?: boolean;
|
|
23
24
|
}
|
|
@@ -68,6 +69,9 @@ export interface AgentEventSubscription {
|
|
|
68
69
|
}
|
|
69
70
|
/** Events delivered by the companion's SSE stream. */
|
|
70
71
|
export type AgentBridgeEvent = {
|
|
72
|
+
readonly type: "activity";
|
|
73
|
+
readonly activity: AgentActivity;
|
|
74
|
+
} | {
|
|
71
75
|
readonly type: "status";
|
|
72
76
|
readonly status: AgentStatusSnapshot;
|
|
73
77
|
} | {
|
|
@@ -87,6 +91,8 @@ export interface AgentBridgeTransport {
|
|
|
87
91
|
readonly openEvents: (request: AgentEventsRequest, handlers: AgentEventHandlers) => AgentEventSubscription;
|
|
88
92
|
readonly dispatch: (request: AgentPromptDispatch, signal?: AbortSignal) => Promise<PromptDispatchResponse | null>;
|
|
89
93
|
readonly disconnect?: (request: AgentDisconnectRequest, signal?: AbortSignal) => Promise<void>;
|
|
94
|
+
/** Deliberately revokes another browser pairing before pairing this page. */
|
|
95
|
+
readonly takeOver?: (request: AgentPairRequest, signal?: AbortSignal) => Promise<PairingResponse>;
|
|
90
96
|
readonly acknowledgeCanvasCommand?: (request: AgentCanvasAcknowledgementRequest, signal?: AbortSignal) => Promise<void>;
|
|
91
97
|
}
|
|
92
98
|
export interface AgentClientOptions {
|
|
@@ -6,4 +6,4 @@
|
|
|
6
6
|
* boundary local lets inspector tests use a deterministic fake while the
|
|
7
7
|
* companion remains the owner of MCP and Node-specific code.
|
|
8
8
|
*/
|
|
9
|
-
export { AGENT_PROTOCOL_LIMITS, AGENT_PROTOCOL_VERSION, defaultBridgePort, CANVAS_COMMAND_TYPES, canonicalOrigin, isAgentPromptRequest, isAgentSketchAttachment, isAgentSketchAnnotation, isAgentSketchCaptureMetadata, isAgentSketchMetadata, isAgentStatusUpdate, isAllowedOrigin, isCanvasCommand, isCanvasGroup, isCanvasState, isCanonicalOrigin, isProjectIdentity, isSameOriginRoute, protocolError, validateSketchAttachments, validateRoutes, } from "../../internal/agent-protocol.js";
|
|
9
|
+
export { AGENT_PROTOCOL_LIMITS, AGENT_PROTOCOL_VERSION, defaultBridgePort, CANVAS_COMMAND_TYPES, canonicalOrigin, isAgentPromptRequest, isAgentSketchAttachment, isAgentSketchAnnotation, isAgentSketchCaptureMetadata, isAgentSketchMetadata, isAgentStatusUpdate, isAgentActivity, isAllowedOrigin, isCanvasCommand, isCanvasGroup, isCanvasState, isCanonicalOrigin, isProjectIdentity, isSameOriginRoute, protocolError, validateSketchAttachments, validateRoutes, } from "../../internal/agent-protocol.js";
|
|
@@ -1,6 +1,15 @@
|
|
|
1
|
+
import { type DraftTarget } from "../drafts/model.js";
|
|
1
2
|
import { type ChangeRecord } from "../changes/changesLog.js";
|
|
2
3
|
import { type StructuralChange } from "../projection/structuralProjection.js";
|
|
4
|
+
export interface HandoffOwner {
|
|
5
|
+
readonly draftId: string;
|
|
6
|
+
readonly draftRevision: number;
|
|
7
|
+
readonly target: DraftTarget;
|
|
8
|
+
readonly frameIds: readonly string[];
|
|
9
|
+
}
|
|
10
|
+
export declare function captureHandoffOwner(cardId?: string | null): HandoffOwner;
|
|
3
11
|
export interface HandoffSnapshot {
|
|
12
|
+
readonly owner: HandoffOwner;
|
|
4
13
|
readonly changes: readonly ChangeRecord[];
|
|
5
14
|
readonly structuralChanges: readonly StructuralChange[];
|
|
6
15
|
}
|
|
@@ -22,7 +31,7 @@ export declare function handoffStructuralFingerprint(change: StructuralChange):
|
|
|
22
31
|
*/
|
|
23
32
|
export declare function verifiedChangeKeys(sentChanges: readonly ChangeRecord[], doc?: Document): Set<string>;
|
|
24
33
|
/** Captures the exact canonical edits associated with one dispatched prompt. */
|
|
25
|
-
export declare function recordAgentDispatch(revision: number, changes: readonly ChangeRecord[], structuralChanges?: readonly StructuralChange[]): void;
|
|
34
|
+
export declare function recordAgentDispatch(revision: number, changes: readonly ChangeRecord[], structuralChanges?: readonly StructuralChange[], owner?: HandoffOwner): void;
|
|
26
35
|
/** Drops a captured revision when the bridge rejects its dispatch. */
|
|
27
36
|
export declare function discardAgentDispatch(revision: number): void;
|
|
28
37
|
/** Returns how many canonical edits were in flight for one dispatch. */
|
|
@@ -33,6 +42,7 @@ export declare function getAgentDispatchSize(revision: number): number;
|
|
|
33
42
|
* records are preserved.
|
|
34
43
|
*/
|
|
35
44
|
export declare function verifyAndReconcileHandoff(snapshot: HandoffSnapshot, doc?: Document | null): Promise<number>;
|
|
45
|
+
export declare function documentBelongsToHandoff(doc: Document, owner: HandoffOwner): boolean;
|
|
36
46
|
/** Reconciles the captured records for one completed connected-agent request. */
|
|
37
47
|
export declare function verifyAndReconcileAgentDispatch(revision: number): Promise<number>;
|
|
38
48
|
/** Test/session reset for in-memory dispatch snapshots. */
|
|
@@ -1,16 +1,24 @@
|
|
|
1
|
+
import { draftIdForCard } from "../drafts/store.js";
|
|
2
|
+
import { getCanvasCards } from "../canvas/canvasStore.js";
|
|
3
|
+
import { getRegisteredFrames, getCanvasCardIdForDocument } from "../canvas/projection.js";
|
|
4
|
+
import { applicationTarget, targetFromKey, targetKey } from "../drafts/model.js";
|
|
1
5
|
import { changeKey, tokenReference } from "../changes/model.js";
|
|
2
6
|
import { selectorForManagedChange } from "../changes/managedStyleProjection.js";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
7
|
+
import { getActiveDraftChanges, getDraftChanges, reconcileDraftChanges } from "../changes/draftChanges.js";
|
|
8
|
+
import { isComponentChange, isTextContentChange, isTokenChange, } from "../changes/changesLog.js";
|
|
5
9
|
import { verifyPreview } from "../projection/managedStylesheet.js";
|
|
6
10
|
import { resolveRenderedInstance } from "../projection/renderedInstance.js";
|
|
7
|
-
import { documentStateKey,
|
|
11
|
+
import { documentStateKey, } from "../projection/structuralProjection.js";
|
|
8
12
|
import { resolveTextProjectionTarget, resolveTextProjectionTextNode, } from "../projection/textProjection.js";
|
|
9
|
-
import {
|
|
10
|
-
import { isCanvasProjectionRevisionCurrent,
|
|
11
|
-
import { getActiveCanvasDocument } from "../canvas/activeCanvasDocument.js";
|
|
12
|
-
import { getSelectedElement } from "../selection/selectionStore.js";
|
|
13
|
+
import { applyHostDraftProjection, compileDraftProjection, } from "../projection/draftProjection.js";
|
|
14
|
+
import { isCanvasProjectionRevisionCurrent, restoreCanonicalFrameProjection, projectDraftToDocument, } from "../canvas/projection.js";
|
|
13
15
|
import { isEditorShellDocument } from "../runtime/editorShell.js";
|
|
16
|
+
export function captureHandoffOwner(cardId) {
|
|
17
|
+
const draftId = (cardId && draftIdForCard(cardId)) || getActiveDraftChanges().draftId;
|
|
18
|
+
const workspace = getDraftChanges(draftId);
|
|
19
|
+
return { draftId, draftRevision: workspace.revision, target: targetFromKey(draftId) ?? applicationTarget(),
|
|
20
|
+
frameIds: getCanvasCards().filter((card) => draftIdForCard(card.id) === workspace.draftId).map((card) => card.id) };
|
|
21
|
+
}
|
|
14
22
|
const dispatches = new Map();
|
|
15
23
|
function stableJsonValue(value) {
|
|
16
24
|
if (Array.isArray(value))
|
|
@@ -142,8 +150,9 @@ export function verifiedChangeKeys(sentChanges, doc = document) {
|
|
|
142
150
|
return verified;
|
|
143
151
|
}
|
|
144
152
|
/** Captures the exact canonical edits associated with one dispatched prompt. */
|
|
145
|
-
export function recordAgentDispatch(revision, changes, structuralChanges = []) {
|
|
153
|
+
export function recordAgentDispatch(revision, changes, structuralChanges = [], owner = captureHandoffOwner()) {
|
|
146
154
|
dispatches.set(revision, {
|
|
155
|
+
owner: structuredClone(owner),
|
|
147
156
|
changes: changes.map((change) => structuredClone(change)),
|
|
148
157
|
structuralChanges: structuralChanges.map((change) => structuredClone(change)),
|
|
149
158
|
});
|
|
@@ -186,32 +195,32 @@ function afterBrowserPaint(doc) {
|
|
|
186
195
|
* observable after removing Nudge's own preview. Newer edits and ambiguous
|
|
187
196
|
* records are preserved.
|
|
188
197
|
*/
|
|
189
|
-
export async function verifyAndReconcileHandoff(snapshot, doc =
|
|
190
|
-
if (!doc)
|
|
198
|
+
export async function verifyAndReconcileHandoff(snapshot, doc = handoffDocument(snapshot.owner)) {
|
|
199
|
+
if (!doc || !documentBelongsToHandoff(doc, snapshot.owner))
|
|
191
200
|
return 0;
|
|
192
201
|
const applyProjection = async (snapshot) => {
|
|
193
202
|
if (doc === document && !isEditorShellDocument(doc)) {
|
|
194
|
-
|
|
203
|
+
applyHostDraftProjection(compileDraftProjection(snapshot));
|
|
195
204
|
return "host";
|
|
196
205
|
}
|
|
197
206
|
if (doc === document)
|
|
198
207
|
return null;
|
|
199
|
-
return
|
|
208
|
+
return projectDraftToDocument(doc, snapshot);
|
|
200
209
|
};
|
|
201
210
|
const sentByKey = new Map(snapshot.changes.map((change) => [changeKey(change), handoffChangeFingerprint(change)]));
|
|
202
|
-
const current =
|
|
211
|
+
const current = getDraftChanges(snapshot.owner.draftId).changes;
|
|
203
212
|
const eligible = current.filter((change) => sentByKey.get(changeKey(change)) === handoffChangeFingerprint(change));
|
|
204
213
|
const eligibleKeys = new Set(eligible.map(changeKey));
|
|
205
214
|
const remaining = current.filter((change) => !eligibleKeys.has(changeKey(change)));
|
|
206
215
|
// The same "still unchanged" rule for structural intent: only canonical
|
|
207
216
|
// records byte-identical to the dispatched snapshot may be reconciled.
|
|
208
217
|
const sentStructural = new Map(snapshot.structuralChanges.map((change) => [change.id, handoffStructuralFingerprint(change)]));
|
|
209
|
-
const currentStructural =
|
|
218
|
+
const currentStructural = getDraftChanges(snapshot.owner.draftId).structuralChanges;
|
|
210
219
|
const eligibleStructural = currentStructural.filter((change) => sentStructural.get(change.id) === handoffStructuralFingerprint(change));
|
|
211
220
|
const eligibleStructuralIds = new Set(eligibleStructural.map((change) => change.id));
|
|
212
221
|
const remainingStructural = currentStructural.filter((change) => !eligibleStructuralIds.has(change.id));
|
|
213
222
|
try {
|
|
214
|
-
const currentWorkspace =
|
|
223
|
+
const currentWorkspace = getDraftChanges(snapshot.owner.draftId);
|
|
215
224
|
const previewRevision = await applyProjection({
|
|
216
225
|
revision: currentWorkspace.revision,
|
|
217
226
|
changes: remaining,
|
|
@@ -220,6 +229,8 @@ export async function verifyAndReconcileHandoff(snapshot, doc = activeVerificati
|
|
|
220
229
|
if (previewRevision === null)
|
|
221
230
|
return 0;
|
|
222
231
|
await afterBrowserPaint(doc);
|
|
232
|
+
if (!documentBelongsToHandoff(doc, snapshot.owner))
|
|
233
|
+
return 0;
|
|
223
234
|
if (typeof previewRevision === "number"
|
|
224
235
|
&& !isCanvasProjectionRevisionCurrent(doc, previewRevision))
|
|
225
236
|
return 0;
|
|
@@ -228,27 +239,44 @@ export async function verifyAndReconcileHandoff(snapshot, doc = activeVerificati
|
|
|
228
239
|
// A user can make another inspector edit while the two-frame verification
|
|
229
240
|
// window is open. Recheck byte identity immediately before reconciliation
|
|
230
241
|
// so a newer value at the same key can never be removed.
|
|
231
|
-
const currentByKey = new Map(
|
|
242
|
+
const currentByKey = new Map(getDraftChanges(snapshot.owner.draftId).changes.map((change) => [changeKey(change), handoffChangeFingerprint(change)]));
|
|
232
243
|
const stillVerified = new Set([...verified].filter((key) => currentByKey.get(key) === sentByKey.get(key)));
|
|
233
|
-
const currentStructuralById = new Map(
|
|
244
|
+
const currentStructuralById = new Map(getDraftChanges(snapshot.owner.draftId).structuralChanges.map((change) => [change.id, handoffStructuralFingerprint(change)]));
|
|
234
245
|
const stillVerifiedStructural = new Set([...verifiedStructural].filter((id) => currentStructuralById.get(id) === sentStructural.get(id)));
|
|
235
246
|
if (typeof previewRevision === "number"
|
|
236
247
|
&& !isCanvasProjectionRevisionCurrent(doc, previewRevision))
|
|
237
248
|
return 0;
|
|
238
|
-
|
|
249
|
+
if (!documentBelongsToHandoff(doc, snapshot.owner))
|
|
250
|
+
return 0;
|
|
251
|
+
return reconcileDraftChanges(snapshot.owner.draftId, stillVerified, stillVerifiedStructural);
|
|
239
252
|
}
|
|
240
253
|
finally {
|
|
241
254
|
// Reconciliation reapplies the canonical set. If it was unable to write
|
|
242
255
|
// (for example, a read-only Canvas lease), restore the untouched set here.
|
|
243
|
-
|
|
244
|
-
|
|
256
|
+
if (doc === document)
|
|
257
|
+
await applyProjection(getActiveDraftChanges());
|
|
258
|
+
else
|
|
259
|
+
restoreCanonicalFrameProjection(doc);
|
|
245
260
|
}
|
|
246
261
|
}
|
|
247
|
-
function
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
return
|
|
251
|
-
|
|
262
|
+
export function documentBelongsToHandoff(doc, owner) {
|
|
263
|
+
if (owner.target.kind === "application"
|
|
264
|
+
&& targetKey(applicationTarget(doc.location.href)) !== targetKey(owner.target))
|
|
265
|
+
return false;
|
|
266
|
+
if (doc === document)
|
|
267
|
+
return owner.target.kind === "application" && !isEditorShellDocument(doc);
|
|
268
|
+
const id = getCanvasCardIdForDocument(doc);
|
|
269
|
+
return !!id && draftIdForCard(id) === owner.draftId;
|
|
270
|
+
}
|
|
271
|
+
function handoffDocument(owner) {
|
|
272
|
+
for (const [id, frame] of getRegisteredFrames()) {
|
|
273
|
+
if (draftIdForCard(id) !== owner.draftId)
|
|
274
|
+
continue;
|
|
275
|
+
const doc = frame.contentDocument;
|
|
276
|
+
if (doc && documentBelongsToHandoff(doc, owner))
|
|
277
|
+
return doc;
|
|
278
|
+
}
|
|
279
|
+
return owner.target.kind === "application" && !isEditorShellDocument() ? document : null;
|
|
252
280
|
}
|
|
253
281
|
/** Reconciles the captured records for one completed connected-agent request. */
|
|
254
282
|
export async function verifyAndReconcileAgentDispatch(revision) {
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { type ActivityFile } from "../agent/activity.js";
|
|
2
|
+
import { type FrameContent } from "./frameContent.js";
|
|
3
|
+
export interface ActivityAttribution {
|
|
4
|
+
files: readonly ActivityFile[];
|
|
5
|
+
elements: readonly Element[];
|
|
6
|
+
}
|
|
7
|
+
/** Reuses rendered source identities. Iteration provenance cannot target application source. */
|
|
8
|
+
export declare function attributeActivity(content: FrameContent, document: Document, files: readonly ActivityFile[]): ActivityAttribution;
|
|
9
|
+
export declare function AgentActivityOverlay({ cardId, content, iframe }: {
|
|
10
|
+
cardId: string;
|
|
11
|
+
content: FrameContent;
|
|
12
|
+
iframe: HTMLIFrameElement | null;
|
|
13
|
+
}): import("react").JSX.Element | null;
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
const activityStyles = ".canvas-agent-activity {\n position: absolute;\n inset: 0;\n pointer-events: none;\n z-index: 12;\n overflow: hidden;\n border-radius: 4px;\n}\n\n.canvas-agent-activity__label {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n position: absolute;\n top: 12px;\n right: 12px;\n max-width: 80%;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n padding: 4px 10px 4px 4px;\n border-radius: 20px;\n background: #242424e8;\n color: #fff;\n font: 12px system-ui;\n box-shadow: 0 2px 12px #0003;\n}\n\n.canvas-agent-activity__label canvas {\n flex: 0 0 auto;\n}\n\n.canvas-agent-activity__label > span {\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.canvas-agent-activity__shimmer {\n position: absolute;\n border-radius: 5px;\n background: linear-gradient(110deg, transparent 20%, rgb(212 212 212 / 0.18) 35%, rgb(212 212 212 / 0.35) 50%, rgb(212 212 212 / 0.18) 65%, transparent 80%);\n background-size: 250% 100%;\n animation: nudge-component-shimmer 2.4s ease-in-out infinite;\n}\n\n@keyframes nudge-component-shimmer {\n from { background-position: 150% 0; }\n to { background-position: -150% 0; }\n}\n\n@media (prefers-reduced-motion: reduce) {\n .canvas-agent-activity__shimmer {\n animation: none;\n }\n}\n";
|
|
3
|
+
import { useEffect, useState } from "react";
|
|
4
|
+
import { ThinkingOrb } from "thinking-orbs";
|
|
5
|
+
import { useAgentActivity } from "../agent/activity.js";
|
|
6
|
+
import { getNudgeUiRuntimeConfig } from "../runtime/runtimeConfig.js";
|
|
7
|
+
import { parseDataSrc } from "../selection/resolveSelection.js";
|
|
8
|
+
import { targetKey } from "../drafts/model.js";
|
|
9
|
+
import { contentEditTarget } from "./frameContent.js";
|
|
10
|
+
/** Reuses rendered source identities. Iteration provenance cannot target application source. */
|
|
11
|
+
export function attributeActivity(content, document, files) {
|
|
12
|
+
const target = contentEditTarget(content);
|
|
13
|
+
if (target.kind === "html")
|
|
14
|
+
return { files: files.filter((file) => file.file === target.path), elements: [] };
|
|
15
|
+
const matched = new Set();
|
|
16
|
+
const elements = [];
|
|
17
|
+
for (const element of document.querySelectorAll("[data-src]")) {
|
|
18
|
+
const source = parseDataSrc(element.getAttribute("data-src") ?? "");
|
|
19
|
+
if (!source)
|
|
20
|
+
continue;
|
|
21
|
+
for (const file of files) {
|
|
22
|
+
if (source.file.replace(/^\.\//, "") !== file.file)
|
|
23
|
+
continue;
|
|
24
|
+
matched.add(file);
|
|
25
|
+
if (file.operation !== "edit" || (file.componentId && file.componentId !== element.getAttribute("data-cid")))
|
|
26
|
+
continue;
|
|
27
|
+
if (file.line !== undefined && (source.line < file.line || source.line > (file.endLine ?? file.line)))
|
|
28
|
+
continue;
|
|
29
|
+
elements.push(element);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
// Highlight outer matches once when one component contains matching descendants.
|
|
33
|
+
return { files: [...matched], elements: [...new Set(elements)].filter((element, _index, all) => !all.some((parent) => parent !== element && parent.contains(element))) };
|
|
34
|
+
}
|
|
35
|
+
export function AgentActivityOverlay({ cardId, content, iframe }) {
|
|
36
|
+
const activity = useAgentActivity(getNudgeUiRuntimeConfig().projectId);
|
|
37
|
+
const [visual, setVisual] = useState({ files: [], highlights: [] });
|
|
38
|
+
useEffect(() => {
|
|
39
|
+
if (!activity.requestId || !iframe || !activity.files.length) {
|
|
40
|
+
setVisual({ files: [], highlights: [] });
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
let detachDocument = () => { };
|
|
44
|
+
const attachDocument = () => {
|
|
45
|
+
detachDocument();
|
|
46
|
+
let document = null;
|
|
47
|
+
try {
|
|
48
|
+
document = iframe.contentDocument;
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
document = null;
|
|
52
|
+
}
|
|
53
|
+
if (!document?.defaultView) {
|
|
54
|
+
setVisual({ files: [], highlights: [] });
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
const view = document.defaultView;
|
|
58
|
+
const ownedDocument = document;
|
|
59
|
+
let attribution = attributeActivity(content, ownedDocument, activity.files);
|
|
60
|
+
let frame = null;
|
|
61
|
+
let sourceChanged = false;
|
|
62
|
+
const measure = () => {
|
|
63
|
+
frame = null;
|
|
64
|
+
if (sourceChanged) {
|
|
65
|
+
attribution = attributeActivity(content, ownedDocument, activity.files);
|
|
66
|
+
sourceChanged = false;
|
|
67
|
+
}
|
|
68
|
+
const highlights = attribution.elements.slice(0, 64).map((element) => {
|
|
69
|
+
const rect = element.getBoundingClientRect();
|
|
70
|
+
return { x: rect.left, y: rect.top, width: rect.width, height: rect.height };
|
|
71
|
+
}).filter((rect) => rect.width > 0 && rect.height > 0);
|
|
72
|
+
setVisual((previous) => {
|
|
73
|
+
const sameFiles = previous.files.length === attribution.files.length && previous.files.every((file, index) => file === attribution.files[index]);
|
|
74
|
+
const sameRects = previous.highlights.length === highlights.length && previous.highlights.every((rect, index) => { const next = highlights[index]; return rect.x === next.x && rect.y === next.y && rect.width === next.width && rect.height === next.height; });
|
|
75
|
+
return sameFiles && sameRects ? previous : { files: attribution.files, highlights };
|
|
76
|
+
});
|
|
77
|
+
};
|
|
78
|
+
const schedule = () => { if (frame === null)
|
|
79
|
+
frame = view.requestAnimationFrame(measure); };
|
|
80
|
+
const mutations = new MutationObserver((records) => {
|
|
81
|
+
sourceChanged ||= records.some((record) => record.type === "childList" || record.attributeName === "data-src" || record.attributeName === "data-cid");
|
|
82
|
+
schedule();
|
|
83
|
+
});
|
|
84
|
+
mutations.observe(ownedDocument.documentElement, { subtree: true, childList: true, characterData: true, attributes: true, attributeFilter: ["data-src", "data-cid", "class", "style"] });
|
|
85
|
+
const resize = typeof ResizeObserver === "undefined" ? null : new ResizeObserver(schedule);
|
|
86
|
+
resize?.observe(ownedDocument.documentElement);
|
|
87
|
+
for (const element of attribution.elements.slice(0, 64))
|
|
88
|
+
resize?.observe(element);
|
|
89
|
+
view.addEventListener("scroll", schedule, true);
|
|
90
|
+
view.addEventListener("resize", schedule);
|
|
91
|
+
measure();
|
|
92
|
+
detachDocument = () => {
|
|
93
|
+
mutations.disconnect();
|
|
94
|
+
resize?.disconnect();
|
|
95
|
+
view.removeEventListener("scroll", schedule, true);
|
|
96
|
+
view.removeEventListener("resize", schedule);
|
|
97
|
+
if (frame !== null)
|
|
98
|
+
view.cancelAnimationFrame(frame);
|
|
99
|
+
};
|
|
100
|
+
};
|
|
101
|
+
attachDocument();
|
|
102
|
+
iframe.addEventListener("load", attachDocument);
|
|
103
|
+
return () => { iframe.removeEventListener("load", attachDocument); detachDocument(); };
|
|
104
|
+
}, [activity, content, iframe]);
|
|
105
|
+
const submitted = activity.requestId !== null && activity.targets.includes(cardId)
|
|
106
|
+
&& (!activity.target || targetKey(activity.target) === targetKey(contentEditTarget(content)));
|
|
107
|
+
const working = activity.requestId !== null && (submitted || visual.files.length > 0);
|
|
108
|
+
if (!working)
|
|
109
|
+
return null;
|
|
110
|
+
return _jsxs("div", { className: "canvas-agent-activity", "data-test": `canvas-agent-activity-${cardId}`, children: [visual.highlights.map((rect, index) => _jsx("div", { className: "canvas-agent-activity__shimmer", "data-test": "canvas-agent-component-shimmer", style: { left: rect.x, top: rect.y, width: rect.width, height: rect.height } }, index)), _jsxs("span", { className: "canvas-agent-activity__label", role: "status", children: [_jsx(ThinkingOrb, { state: "solving", size: 20, theme: "dark", "aria-hidden": "true" }), _jsx("span", { children: "Agent working\u2026" })] }), _jsx("style", { children: activityStyles })] });
|
|
111
|
+
}
|
|
@@ -1,12 +1,19 @@
|
|
|
1
1
|
import { type ReactElement } from "react";
|
|
2
|
-
import { type CanvasCard
|
|
2
|
+
import { type CanvasCard } from "./canvasStore.js";
|
|
3
|
+
import { type CanvasPresentation } from "./viewStore.js";
|
|
3
4
|
import type { InspectorSession } from "../session/sessionFactory.js";
|
|
4
5
|
interface CanvasCardProps {
|
|
5
6
|
card: CanvasCard;
|
|
6
7
|
presentation?: CanvasPresentation;
|
|
7
8
|
presentationCard?: boolean;
|
|
9
|
+
linkedToActive?: boolean;
|
|
8
10
|
onShowFocus?: (cardId: string) => void;
|
|
11
|
+
onDuplicate?: (cardId: string) => void;
|
|
12
|
+
onCreateIteration?: (cardId: string, position?: {
|
|
13
|
+
x: number;
|
|
14
|
+
y: number;
|
|
15
|
+
}) => Promise<string>;
|
|
9
16
|
documentOwner?: InspectorSession;
|
|
10
17
|
}
|
|
11
|
-
export declare function CanvasCard({ card, presentation, presentationCard, onShowFocus, documentOwner }: CanvasCardProps): ReactElement;
|
|
18
|
+
export declare function CanvasCard({ card, presentation, presentationCard, linkedToActive, onShowFocus, onDuplicate, onCreateIteration, documentOwner }: CanvasCardProps): ReactElement;
|
|
12
19
|
export {};
|