nudge-ui 0.2.0 → 0.2.2
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/bin/nudge-ui.mjs +3 -1
- package/dist/cli/agentCommand.d.ts +8 -0
- package/dist/cli/agentCommand.js +59 -0
- package/dist/client.mjs +878 -11
- package/dist/hosts/astro/astroRuntimeConfig.js +1 -1
- package/dist/hosts/astro/clientTransport.js +63 -11
- package/dist/hosts/astro/integration.d.ts +2 -2
- package/dist/hosts/astro/integration.js +4 -3
- package/dist/hosts/environment.d.ts +15 -0
- package/dist/hosts/environment.js +16 -0
- package/dist/hosts/next/sidecar.d.ts +4 -0
- package/dist/hosts/next/sidecar.js +56 -7
- package/dist/hosts/next/wrapper.d.ts +2 -0
- package/dist/hosts/next/wrapper.js +32 -3
- package/dist/hosts/projectBridge.d.ts +21 -0
- package/dist/hosts/projectBridge.js +98 -0
- package/dist/hosts/static/cli.d.ts +1 -1
- package/dist/hosts/static/cli.js +6 -1
- package/dist/hosts/static/manifest.d.ts +1 -1
- package/dist/hosts/static/manifest.js +3 -1
- package/dist/hosts/static/server.js +45 -3
- package/dist/hosts/vite/vite.d.ts +6 -1
- package/dist/hosts/vite/vite.js +82 -15
- package/dist/inspector/agent/McpConnectionDialog.d.ts +5 -4
- package/dist/inspector/agent/McpConnectionDialog.js +20 -37
- package/dist/inspector/agent/client.d.ts +16 -3
- package/dist/inspector/agent/client.js +114 -11
- package/dist/inspector/agent/connectionStatus.d.ts +3 -3
- package/dist/inspector/agent/connectionStatus.js +11 -4
- package/dist/inspector/agent/httpTransport.d.ts +8 -0
- package/dist/inspector/agent/httpTransport.js +78 -18
- package/dist/inspector/agent/protocol.d.ts +11 -3
- package/dist/inspector/agent/protocol.js +1 -1
- package/dist/inspector/agent/verification.d.ts +1 -1
- package/dist/inspector/agent/verification.js +69 -12
- package/dist/inspector/canvas/CanvasCard.d.ts +5 -3
- package/dist/inspector/canvas/CanvasCard.js +181 -91
- package/dist/inspector/canvas/CanvasElementOverlay.js +288 -52
- package/dist/inspector/canvas/CanvasToolbar.d.ts +12 -0
- package/dist/inspector/canvas/CanvasToolbar.js +24 -0
- package/dist/inspector/canvas/CanvasWorkspace.d.ts +4 -1
- package/dist/inspector/canvas/CanvasWorkspace.js +410 -72
- package/dist/inspector/canvas/activeCanvasDocument.d.ts +5 -0
- package/dist/inspector/canvas/activeCanvasDocument.js +23 -0
- package/dist/inspector/canvas/canvasResize.d.ts +30 -0
- package/dist/inspector/canvas/canvasResize.js +52 -0
- package/dist/inspector/canvas/canvasStore.d.ts +30 -6
- package/dist/inspector/canvas/canvasStore.js +128 -61
- package/dist/inspector/canvas/frameProtocol.d.ts +82 -5
- package/dist/inspector/canvas/frameProtocol.js +63 -2
- package/dist/inspector/canvas/keyboardShortcuts.d.ts +4 -0
- package/dist/inspector/canvas/keyboardShortcuts.js +16 -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 +7 -0
- package/dist/inspector/canvas/projection.js +118 -25
- package/dist/inspector/canvas/rendererBootstrap.js +42 -29
- package/dist/inspector/canvas/rendererElementSelector.d.ts +1 -1
- package/dist/inspector/canvas/rendererElementSelector.js +385 -58
- package/dist/inspector/canvas/rendererMessageRouter.d.ts +11 -0
- package/dist/inspector/canvas/rendererMessageRouter.js +43 -0
- package/dist/inspector/canvas/rendererSelectionProxy.js +6 -2
- package/dist/inspector/canvas/sessionStore.d.ts +1 -0
- package/dist/inspector/canvas/sessionStore.js +12 -4
- package/dist/inspector/canvas/staleChangeDetector.js +16 -14
- package/dist/inspector/changes/changesLog.js +31 -1
- package/dist/inspector/changes/managedStyleProjection.d.ts +1 -1
- package/dist/inspector/changes/managedStyleProjection.js +3 -3
- package/dist/inspector/changes/structuralTypes.d.ts +4 -0
- package/dist/inspector/changes/workspaceChanges.d.ts +4 -0
- package/dist/inspector/changes/workspaceChanges.js +29 -3
- package/dist/inspector/clientManifest.d.ts +7 -0
- package/dist/inspector/clientManifest.js +12 -0
- package/dist/inspector/componentSemantics/adapterRegistry.js +4 -3
- package/dist/inspector/componentSemantics/runtimeBridge.d.ts +2 -2
- package/dist/inspector/componentSemantics/runtimeBridge.js +16 -3
- package/dist/inspector/index.d.ts +2 -0
- package/dist/inspector/index.js +80 -32
- package/dist/inspector/inline-text/inlineTextDiagnostics.d.ts +10 -0
- package/dist/inspector/inline-text/inlineTextDiagnostics.js +65 -0
- package/dist/inspector/inline-text/inlineTextEditor.d.ts +3 -5
- package/dist/inspector/inline-text/inlineTextEditor.js +74 -206
- package/dist/inspector/inline-text/inlineTextFeedback.d.ts +5 -0
- package/dist/inspector/inline-text/inlineTextFeedback.js +27 -0
- package/dist/inspector/inline-text/inlineTextLifecycle.js +2 -0
- package/dist/inspector/inline-text/textEditChange.d.ts +14 -0
- package/dist/inspector/inline-text/textEditChange.js +165 -0
- package/dist/inspector/inspection/selectionProperty.d.ts +1 -0
- package/dist/inspector/inspection/selectionProperty.js +1 -0
- package/dist/inspector/overlay/DomNavigator.d.ts +10 -0
- package/dist/inspector/overlay/DomNavigator.js +40 -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/selectedGeometry.js +21 -2
- package/dist/inspector/overlay/spacingGestures.d.ts +45 -0
- package/dist/inspector/overlay/spacingGestures.js +351 -0
- package/dist/inspector/overlay/structuralGestures.d.ts +2 -2
- package/dist/inspector/overlay/structuralGestures.js +12 -10
- package/dist/inspector/projection/managedStylesheet.js +4 -1
- package/dist/inspector/projection/renderedInstance.d.ts +2 -0
- package/dist/inspector/projection/renderedInstance.js +5 -1
- package/dist/inspector/projection/structuralProjection.d.ts +2 -0
- package/dist/inspector/projection/structuralProjection.js +85 -1
- package/dist/inspector/projection/structuralProjectionBoundary.js +17 -1
- package/dist/inspector/projection/textProjection.d.ts +2 -0
- package/dist/inspector/projection/textProjection.js +10 -4
- package/dist/inspector/prompt/clipboardHandoff.d.ts +1 -1
- package/dist/inspector/prompt/clipboardHandoff.js +3 -3
- package/dist/inspector/prompt/generatePrompt.d.ts +2 -1
- package/dist/inspector/prompt/generatePrompt.js +19 -2
- package/dist/inspector/runtime/editorShell.d.ts +2 -0
- package/dist/inspector/runtime/editorShell.js +4 -0
- package/dist/inspector/runtime/runtimeConfig.d.ts +5 -1
- package/dist/inspector/runtime/runtimeConfig.js +4 -0
- package/dist/inspector/selection/hierarchy.d.ts +6 -0
- package/dist/inspector/selection/hierarchy.js +8 -0
- package/dist/inspector/selection/selectionStore.js +2 -0
- package/dist/inspector/settings/SettingsDialog.d.ts +1 -1
- package/dist/inspector/settings/SettingsDialog.js +12 -2
- package/dist/inspector/shell/AppShell.js +5 -1
- package/dist/inspector/shell/ChangesLog.js +26 -22
- package/dist/inspector/shell/CopyPromptButton.js +102 -19
- package/dist/inspector/shell/EmptyState.js +1 -1
- package/dist/inspector/shell/InspectorShell.d.ts +0 -1
- package/dist/inspector/shell/InspectorShell.js +38 -42
- package/dist/inspector/shell/PeekOriginalButton.d.ts +7 -0
- package/dist/inspector/shell/PeekOriginalButton.js +57 -0
- package/dist/inspector/shell/PeekOriginalIcon.d.ts +7 -0
- package/dist/inspector/shell/PeekOriginalIcon.js +9 -0
- package/dist/inspector/shell/originalPreview.d.ts +9 -0
- package/dist/inspector/shell/originalPreview.js +61 -0
- package/dist/inspector/shell/shortcuts.d.ts +3 -0
- package/dist/inspector/shell/shortcuts.js +15 -0
- package/dist/inspector/sketch/SketchChanges.d.ts +2 -0
- package/dist/inspector/sketch/SketchChanges.js +72 -0
- package/dist/inspector/sketch/SketchEditor.d.ts +21 -0
- package/dist/inspector/sketch/SketchEditor.js +402 -0
- package/dist/inspector/sketch/SketchEntryButton.d.ts +4 -0
- package/dist/inspector/sketch/SketchEntryButton.js +11 -0
- package/dist/inspector/sketch/SketchFrameOverlay.d.ts +11 -0
- package/dist/inspector/sketch/SketchFrameOverlay.js +119 -0
- package/dist/inspector/sketch/SketchLayersPanel.d.ts +2 -0
- package/dist/inspector/sketch/SketchLayersPanel.js +63 -0
- package/dist/inspector/sketch/SketchOverlay.d.ts +19 -0
- package/dist/inspector/sketch/SketchOverlay.js +420 -0
- package/dist/inspector/sketch/SketchPromptPanel.d.ts +15 -0
- package/dist/inspector/sketch/SketchPromptPanel.js +18 -0
- package/dist/inspector/sketch/SketchWorkspace.d.ts +13 -0
- package/dist/inspector/sketch/SketchWorkspace.js +152 -0
- package/dist/inspector/sketch/capture.d.ts +55 -0
- package/dist/inspector/sketch/capture.js +350 -0
- package/dist/inspector/sketch/freehand.d.ts +13 -0
- package/dist/inspector/sketch/freehand.js +64 -0
- package/dist/inspector/sketch/geometry.d.ts +17 -0
- package/dist/inspector/sketch/geometry.js +98 -0
- package/dist/inspector/sketch/handoff.d.ts +21 -0
- package/dist/inspector/sketch/handoff.js +72 -0
- package/dist/inspector/sketch/interaction.d.ts +21 -0
- package/dist/inspector/sketch/interaction.js +98 -0
- package/dist/inspector/sketch/model.d.ts +104 -0
- package/dist/inspector/sketch/model.js +282 -0
- package/dist/inspector/sketch/persistence.d.ts +21 -0
- package/dist/inspector/sketch/persistence.js +205 -0
- package/dist/inspector/sketch/raster.d.ts +22 -0
- package/dist/inspector/sketch/raster.js +203 -0
- package/dist/inspector/sketch/sketchNote.d.ts +10 -0
- package/dist/inspector/sketch/sketchNote.js +30 -0
- package/dist/inspector/sketch/store.d.ts +47 -0
- package/dist/inspector/sketch/store.js +434 -0
- package/dist/inspector/styleEditors/BorderEditor.js +15 -19
- package/dist/inspector/styleEditors/BorderRadiusEditor.js +6 -6
- package/dist/inspector/styleEditors/BoxShadowEditor.js +12 -1
- package/dist/inspector/styleEditors/ColorPicker.js +11 -36
- package/dist/inspector/styleEditors/GapField.d.ts +3 -2
- package/dist/inspector/styleEditors/GapField.js +2 -2
- package/dist/inspector/styleEditors/GridSection.js +1 -1
- package/dist/inspector/styleEditors/LayoutSection.js +11 -8
- package/dist/inspector/styleEditors/SpacingBox.js +31 -33
- package/dist/inspector/styleEditors/layoutPreviewState.d.ts +5 -0
- package/dist/inspector/styleEditors/layoutPreviewState.js +19 -0
- package/dist/inspector/styleEditors/layoutValue.js +3 -0
- package/dist/inspector/styleEditors/nudgeValue.d.ts +11 -0
- package/dist/inspector/styleEditors/nudgeValue.js +93 -5
- package/dist/inspector/styleEditors/stylePresence.d.ts +7 -0
- package/dist/inspector/styleEditors/stylePresence.js +22 -0
- package/dist/inspector/styleEditors/textRelevance.d.ts +3 -0
- package/dist/inspector/styleEditors/textRelevance.js +35 -0
- package/dist/inspector/styleEditors/useFieldVisibility.d.ts +6 -0
- package/dist/inspector/styleEditors/useFieldVisibility.js +26 -0
- package/dist/inspector/tokens/TokenField.js +130 -7
- 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 +2 -0
- package/dist/inspector/tokens/editActions.js +2 -2
- package/dist/inspector/tokens/resolution/cssomCollector.d.ts +1 -1
- package/dist/inspector/tokens/resolution/cssomCollector.js +9 -5
- package/dist/inspector/tokens/resolution/ruleMatching.d.ts +40 -0
- package/dist/inspector/tokens/resolution/ruleMatching.js +423 -0
- package/dist/inspector/tokens/resolution/selectorSemantics.d.ts +19 -3
- package/dist/inspector/tokens/resolution/selectorSemantics.js +378 -4
- package/dist/inspector/tokens/resolution.d.ts +3 -26
- package/dist/inspector/tokens/resolution.js +44 -735
- package/dist/inspector/tokens/tokenAvailability.d.ts +18 -0
- package/dist/inspector/tokens/tokenAvailability.js +204 -0
- package/dist/inspector/ui/Button.d.ts +1 -1
- package/dist/inspector/ui/Disclosure.d.ts +22 -0
- package/dist/inspector/ui/Disclosure.js +13 -0
- package/dist/inspector/ui/SideValuesField.js +2 -2
- package/dist/inspector/ui/StatusCallout.d.ts +4 -1
- package/dist/inspector/ui/StatusCallout.js +2 -2
- package/dist/inspector/ui/dragCursor.d.ts +8 -0
- package/dist/inspector/ui/dragCursor.js +21 -0
- package/dist/inspector/ui/styles.js +21 -17
- package/dist/internal/agent-protocol.d.ts +65 -1
- package/dist/internal/agent-protocol.js +183 -3
- package/dist/nudge-ui.mjs +276 -58
- package/dist/transport/editor.d.ts +47 -0
- package/dist/transport/editor.js +163 -0
- package/dist/transport/index.d.ts +1 -0
- package/dist/transport/index.js +1 -0
- package/dist/transport/routes.d.ts +10 -0
- package/dist/transport/routes.js +10 -0
- package/package.json +3 -1
- package/dist/inspector/shell/DomNavigation.d.ts +0 -8
- package/dist/inspector/shell/DomNavigation.js +0 -30
- package/dist/inspector/shell/panelLayout.d.ts +0 -2
- package/dist/inspector/shell/panelLayout.js +0 -29
|
@@ -12,7 +12,7 @@ export function createAstroRuntimeConfig(knowledge) {
|
|
|
12
12
|
framework: "Astro",
|
|
13
13
|
stylingSystem: detectStylingSystem(knowledge.tokens),
|
|
14
14
|
capabilities: {
|
|
15
|
-
canvas:
|
|
15
|
+
canvas: true,
|
|
16
16
|
componentSemantics: true,
|
|
17
17
|
sourceCoordinates: ASTRO_SOURCE_COORDINATES,
|
|
18
18
|
scopingSelectorPattern: ASTRO_SCOPING_SELECTOR_PATTERN,
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import {} from "../../inspector/clientManifest.js";
|
|
2
2
|
import { createAstroRuntimeConfig } from "./astroRuntimeConfig.js";
|
|
3
3
|
import { createAstroClientAssetHandler } from "./clientAsset.js";
|
|
4
|
-
import { NUDGE_UI_CLIENT_PATH, NUDGE_UI_MANIFEST_PATH, } from "../../transport/index.js";
|
|
4
|
+
import { NUDGE_UI_CLIENT_PATH, NUDGE_UI_EDITOR_PATH, NUDGE_UI_MANIFEST_PATH, createNudgeUiEditorDocument, isNudgeUiEditorDocumentRequest, } from "../../transport/index.js";
|
|
5
|
+
import { startOptionalProjectBridge } from "../projectBridge.js";
|
|
6
|
+
import { automationManifestFields } from "../environment.js";
|
|
5
7
|
const serveClient = createAstroClientAssetHandler();
|
|
6
8
|
/** Serves the prebuilt client and its host-neutral manifest in Astro dev. */
|
|
7
9
|
export function createAstroClientTransportPlugin() {
|
|
10
|
+
let projectBridge = null;
|
|
8
11
|
return {
|
|
9
12
|
name: "nudge-ui-astro-client-transport",
|
|
10
13
|
// The shared Vite plugin exposes the same route for React hosts. Astro's
|
|
@@ -15,12 +18,27 @@ export function createAstroClientTransportPlugin() {
|
|
|
15
18
|
configureServer(server) {
|
|
16
19
|
server.middlewares.use((request, response, next) => {
|
|
17
20
|
const pathname = new URL(request.url ?? "/", "http://nudge-ui.local").pathname;
|
|
21
|
+
if (isNudgeUiEditorDocumentRequest(request.url ?? "/", request.method, request.headers)) {
|
|
22
|
+
if (request.method !== "GET" && request.method !== "HEAD") {
|
|
23
|
+
response.statusCode = 405;
|
|
24
|
+
response.setHeader("Allow", "GET, HEAD");
|
|
25
|
+
response.end();
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
response.statusCode = 200;
|
|
29
|
+
response.setHeader("Content-Type", "text/html; charset=utf-8");
|
|
30
|
+
response.setHeader("Cache-Control", "no-store");
|
|
31
|
+
response.end(request.method === "HEAD" ? undefined : createNudgeUiEditorDocument());
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
18
34
|
if (pathname === NUDGE_UI_CLIENT_PATH) {
|
|
19
35
|
void serveClient(request, response).catch(next);
|
|
20
36
|
return;
|
|
21
37
|
}
|
|
22
38
|
if (pathname === NUDGE_UI_MANIFEST_PATH) {
|
|
23
|
-
void createManifest(server)
|
|
39
|
+
void createManifest(server, request, (bridge) => {
|
|
40
|
+
projectBridge = bridge;
|
|
41
|
+
})
|
|
24
42
|
.then((manifest) => {
|
|
25
43
|
response.statusCode = 200;
|
|
26
44
|
response.setHeader("Content-Type", "application/json; charset=utf-8");
|
|
@@ -33,25 +51,59 @@ export function createAstroClientTransportPlugin() {
|
|
|
33
51
|
next();
|
|
34
52
|
});
|
|
35
53
|
},
|
|
54
|
+
async closeBundle() {
|
|
55
|
+
await projectBridge?.close();
|
|
56
|
+
projectBridge = null;
|
|
57
|
+
},
|
|
36
58
|
};
|
|
37
59
|
}
|
|
38
|
-
async function createManifest(server) {
|
|
60
|
+
async function createManifest(server, request, setBridge) {
|
|
39
61
|
// SAFETY: these virtual modules are generated by the shared Nudge UI plugin
|
|
40
62
|
// with the exact exports described by TokenModule and ComponentModule.
|
|
41
63
|
const [tokenModule, componentModule] = await Promise.all([
|
|
42
64
|
server.ssrLoadModule("virtual:design-tokens"),
|
|
43
65
|
server.ssrLoadModule("virtual:nudge-ui-components"),
|
|
44
66
|
]);
|
|
67
|
+
const runtime = createAstroRuntimeConfig({
|
|
68
|
+
projectId: tokenModule.nudgeUiProjectId,
|
|
69
|
+
tokenCatalog: tokenModule.tokenCatalog,
|
|
70
|
+
tokens: tokenModule.tokens,
|
|
71
|
+
tokenDiagnostics: tokenModule.tokenDiagnostics,
|
|
72
|
+
tokenGeneration: tokenModule.tokenGeneration,
|
|
73
|
+
componentContracts: componentModule.componentContracts,
|
|
74
|
+
});
|
|
75
|
+
const origin = resolvedRequestOrigin(server, request);
|
|
76
|
+
const bridge = origin
|
|
77
|
+
? await startOptionalProjectBridge({
|
|
78
|
+
appRoot: server.config.root,
|
|
79
|
+
projectId: runtime.projectId,
|
|
80
|
+
origin,
|
|
81
|
+
info: (message) => server.config.logger.info(message),
|
|
82
|
+
warn: (message) => server.config.logger.warn(message),
|
|
83
|
+
})
|
|
84
|
+
: null;
|
|
85
|
+
setBridge(bridge);
|
|
45
86
|
return {
|
|
46
87
|
version: 1,
|
|
47
88
|
revision: 0,
|
|
48
|
-
runtime
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
tokens: tokenModule.tokens,
|
|
52
|
-
tokenDiagnostics: tokenModule.tokenDiagnostics,
|
|
53
|
-
tokenGeneration: tokenModule.tokenGeneration,
|
|
54
|
-
componentContracts: componentModule.componentContracts,
|
|
55
|
-
}),
|
|
89
|
+
runtime,
|
|
90
|
+
...(bridge ? { agentBridge: bridge.browser } : {}),
|
|
91
|
+
...automationManifestFields(),
|
|
56
92
|
};
|
|
57
93
|
}
|
|
94
|
+
function resolvedRequestOrigin(server, request) {
|
|
95
|
+
const host = request.headers.host;
|
|
96
|
+
if (!host)
|
|
97
|
+
return null;
|
|
98
|
+
const candidates = [
|
|
99
|
+
...(server.resolvedUrls?.local ?? []),
|
|
100
|
+
...(server.resolvedUrls?.network ?? []),
|
|
101
|
+
].map((url) => new URL(url).origin);
|
|
102
|
+
const protocols = new Set(candidates.map((candidate) => new URL(candidate).protocol));
|
|
103
|
+
for (const protocol of protocols) {
|
|
104
|
+
const requested = new URL(`${protocol}//${host}`).origin;
|
|
105
|
+
if (candidates.includes(requested))
|
|
106
|
+
return requested;
|
|
107
|
+
}
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
@@ -11,8 +11,8 @@ export interface NudgeUiAstroOptions extends NudgeUiOptions {
|
|
|
11
11
|
/**
|
|
12
12
|
* Nudge UI host Adapter for Astro dev servers (ADR-0011).
|
|
13
13
|
*
|
|
14
|
-
* Dev-only by contract (ADR-0002): unless `command === "dev"
|
|
15
|
-
* `enabled !== false`, the integration registers nothing at all — no Vite
|
|
14
|
+
* Dev-only by contract (ADR-0002): unless `command === "dev"`,
|
|
15
|
+
* `enabled !== false`, and `NUDGE_UI` is not `0`, the integration registers nothing at all — no Vite
|
|
16
16
|
* plugins, no injected scripts, no middleware — so `astro build` output is
|
|
17
17
|
* byte-identical to a project without the integration.
|
|
18
18
|
*
|
|
@@ -2,6 +2,7 @@ import { nudgeUi } from "../vite/index.js";
|
|
|
2
2
|
import { NUDGE_UI_CLIENT_PATH, NUDGE_UI_MANIFEST_PATH } from "../../transport/index.js";
|
|
3
3
|
import { createAstroClientTransportPlugin, } from "./clientTransport.js";
|
|
4
4
|
import { createProjectContextPlugin } from "./projectContext.js";
|
|
5
|
+
import { isNudgeUiEnabled } from "../environment.js";
|
|
5
6
|
/**
|
|
6
7
|
* Adds the prebuilt client as an external module. The inspector dependency
|
|
7
8
|
* graph therefore never enters Astro's Vite optimizer.
|
|
@@ -23,8 +24,8 @@ const MIDDLEWARE_ENTRYPOINT = new URL(import.meta.url.endsWith(".ts") ? "./middl
|
|
|
23
24
|
/**
|
|
24
25
|
* Nudge UI host Adapter for Astro dev servers (ADR-0011).
|
|
25
26
|
*
|
|
26
|
-
* Dev-only by contract (ADR-0002): unless `command === "dev"
|
|
27
|
-
* `enabled !== false`, the integration registers nothing at all — no Vite
|
|
27
|
+
* Dev-only by contract (ADR-0002): unless `command === "dev"`,
|
|
28
|
+
* `enabled !== false`, and `NUDGE_UI` is not `0`, the integration registers nothing at all — no Vite
|
|
28
29
|
* plugins, no injected scripts, no middleware — so `astro build` output is
|
|
29
30
|
* byte-identical to a project without the integration.
|
|
30
31
|
*
|
|
@@ -37,7 +38,7 @@ const MIDDLEWARE_ENTRYPOINT = new URL(import.meta.url.endsWith(".ts") ? "./middl
|
|
|
37
38
|
* identity Module.
|
|
38
39
|
*/
|
|
39
40
|
export function nudgeUiAstro(options = {}) {
|
|
40
|
-
const enabled = options.enabled
|
|
41
|
+
const enabled = isNudgeUiEnabled(options.enabled);
|
|
41
42
|
const sharedOptions = { ...options };
|
|
42
43
|
return {
|
|
43
44
|
name: "nudge-ui",
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `NUDGE_UI` environment switch shared by every development host.
|
|
3
|
+
*
|
|
4
|
+
* - `0`, `false`, or `off` disables the host Adapter for that run.
|
|
5
|
+
* - `1`, `true`, or `on` also opens the editor in automated browsers, which
|
|
6
|
+
* otherwise receive the plain application.
|
|
7
|
+
*/
|
|
8
|
+
export type NudgeUiEnvironmentSwitch = "off" | "on" | null;
|
|
9
|
+
export declare function readNudgeUiEnvironmentSwitch(env?: Readonly<Record<string, string | undefined>>): NudgeUiEnvironmentSwitch;
|
|
10
|
+
/** An explicit `enabled: false` or `NUDGE_UI=0` disables the Adapter. */
|
|
11
|
+
export declare function isNudgeUiEnabled(enabled: boolean | undefined, env?: Readonly<Record<string, string | undefined>>): boolean;
|
|
12
|
+
/** Manifest fields derived from the environment at request time. */
|
|
13
|
+
export declare function automationManifestFields(env?: Readonly<Record<string, string | undefined>>): {
|
|
14
|
+
inspectAutomatedBrowsers?: true;
|
|
15
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export function readNudgeUiEnvironmentSwitch(env = process.env) {
|
|
2
|
+
const value = env.NUDGE_UI?.trim().toLowerCase();
|
|
3
|
+
if (value === "0" || value === "false" || value === "off")
|
|
4
|
+
return "off";
|
|
5
|
+
if (value === "1" || value === "true" || value === "on")
|
|
6
|
+
return "on";
|
|
7
|
+
return null;
|
|
8
|
+
}
|
|
9
|
+
/** An explicit `enabled: false` or `NUDGE_UI=0` disables the Adapter. */
|
|
10
|
+
export function isNudgeUiEnabled(enabled, env = process.env) {
|
|
11
|
+
return enabled !== false && readNudgeUiEnvironmentSwitch(env) !== "off";
|
|
12
|
+
}
|
|
13
|
+
/** Manifest fields derived from the environment at request time. */
|
|
14
|
+
export function automationManifestFields(env = process.env) {
|
|
15
|
+
return readNudgeUiEnvironmentSwitch(env) === "on" ? { inspectAutomatedBrowsers: true } : {};
|
|
16
|
+
}
|
|
@@ -17,6 +17,10 @@ export interface SidecarOptions {
|
|
|
17
17
|
* add/change/remove transitions. Diagnostics never disable inspection.
|
|
18
18
|
*/
|
|
19
19
|
tokens?: boolean;
|
|
20
|
+
/** Trusted browser origin established by the Next development process. */
|
|
21
|
+
projectBridgeOrigin?: string;
|
|
22
|
+
/** Canonical loopback aliases for the known development port. */
|
|
23
|
+
projectBridgeAllowedOrigins?: readonly string[];
|
|
20
24
|
}
|
|
21
25
|
/**
|
|
22
26
|
* Starts (or returns) the sidecar for this dev-server process.
|
|
@@ -7,7 +7,9 @@ import { buildManifest, } from "./manifest.js";
|
|
|
7
7
|
import { extractComponentContracts } from "../../compiler/componentContracts.js";
|
|
8
8
|
import { createProjectFileWatcher, } from "../../project/files.js";
|
|
9
9
|
import { createProjectTokenSnapshot } from "../../project/tokens.js";
|
|
10
|
-
import { NUDGE_UI_CLIENT_PATH, NUDGE_UI_MANIFEST_PATH, NUDGE_UI_RELOAD_PATH, NUDGE_UI_ROUTE_PREFIX, } from "../../transport/index.js";
|
|
10
|
+
import { NUDGE_UI_CLIENT_PATH, NUDGE_UI_EDITOR_PATH, NUDGE_UI_MANIFEST_PATH, NUDGE_UI_RELOAD_PATH, NUDGE_UI_ROUTE_PREFIX, createNudgeUiEditorDocument, isNudgeUiEditorDocumentRequest, } from "../../transport/index.js";
|
|
11
|
+
import { startOptionalProjectBridge } from "../projectBridge.js";
|
|
12
|
+
import { automationManifestFields } from "../environment.js";
|
|
11
13
|
/**
|
|
12
14
|
* Loopback-only manifest/reload sidecar (ADR-0010).
|
|
13
15
|
*
|
|
@@ -221,7 +223,7 @@ export async function ensureSidecar(root, options = {}) {
|
|
|
221
223
|
// derive every filesystem-relative computation from the canonical root.
|
|
222
224
|
const fsRoot = await realpath(root).catch(() => root);
|
|
223
225
|
const scanRoots = await tokenScanRoots(fsRoot, options.sourceRoots);
|
|
224
|
-
const state = globalState(`${options.tokens ? "tokens" : "manifest"}:${fsRoot}:${scanRoots.join("|")}`);
|
|
226
|
+
const state = globalState(`${options.tokens ? "tokens" : "manifest"}:${options.projectBridgeOrigin ?? "plain"}:${fsRoot}:${scanRoots.join("|")}`);
|
|
225
227
|
// The settled promise doubles as the handle cache: awaiting it replays the
|
|
226
228
|
// same handle for every caller until close/failure clears the slot.
|
|
227
229
|
if (state.starting)
|
|
@@ -249,7 +251,36 @@ export async function ensureSidecar(root, options = {}) {
|
|
|
249
251
|
stream.write(`data: ${JSON.stringify({ revision: generation })}\n\n`);
|
|
250
252
|
}
|
|
251
253
|
};
|
|
252
|
-
|
|
254
|
+
let manifest = options.manifest ?? buildManifest({ root });
|
|
255
|
+
let projectBridge = null;
|
|
256
|
+
let projectBridgeStart = null;
|
|
257
|
+
const ensureProjectBridge = () => {
|
|
258
|
+
if (!options.projectBridgeOrigin || projectBridge || projectBridgeStart) {
|
|
259
|
+
return projectBridgeStart ?? Promise.resolve();
|
|
260
|
+
}
|
|
261
|
+
projectBridgeStart = startOptionalProjectBridge({
|
|
262
|
+
appRoot: fsRoot,
|
|
263
|
+
projectId: manifest.runtime.projectId,
|
|
264
|
+
origin: options.projectBridgeOrigin,
|
|
265
|
+
...(options.projectBridgeAllowedOrigins
|
|
266
|
+
? { allowedOrigins: options.projectBridgeAllowedOrigins }
|
|
267
|
+
: {}),
|
|
268
|
+
info: (message) => console.info(message),
|
|
269
|
+
warn: (message) => console.warn(message),
|
|
270
|
+
}).then((bridge) => {
|
|
271
|
+
projectBridge = bridge;
|
|
272
|
+
if (bridge)
|
|
273
|
+
manifest = { ...manifest, agentBridge: bridge.browser };
|
|
274
|
+
});
|
|
275
|
+
return projectBridgeStart;
|
|
276
|
+
};
|
|
277
|
+
const closeProjectBridge = async () => {
|
|
278
|
+
await projectBridgeStart;
|
|
279
|
+
const bridge = projectBridge;
|
|
280
|
+
projectBridge = null;
|
|
281
|
+
projectBridgeStart = null;
|
|
282
|
+
await bridge?.close();
|
|
283
|
+
};
|
|
253
284
|
const additionalTokenRoots = scanRoots.filter((scanRoot) => scanRoot !== fsRoot);
|
|
254
285
|
const tokenSnapshotOptions = {
|
|
255
286
|
rootDirectory: fsRoot,
|
|
@@ -290,6 +321,7 @@ export async function ensureSidecar(root, options = {}) {
|
|
|
290
321
|
// The port file is diagnostics-only; the rewrite carries the real
|
|
291
322
|
// transport, so an unwritable .next must not break instrumentation.
|
|
292
323
|
}
|
|
324
|
+
await ensureProjectBridge();
|
|
293
325
|
const watchers = [];
|
|
294
326
|
// The startup source scan runs regardless of the token lifecycle so a
|
|
295
327
|
// restarted sidecar republishes contracts even when Turbopack's
|
|
@@ -425,7 +457,7 @@ export async function ensureSidecar(root, options = {}) {
|
|
|
425
457
|
// close. Closing twice must not throw.
|
|
426
458
|
if (!server.listening) {
|
|
427
459
|
state.starting = undefined;
|
|
428
|
-
return
|
|
460
|
+
return closeProjectBridge();
|
|
429
461
|
}
|
|
430
462
|
for (const stream of streams)
|
|
431
463
|
stream.end();
|
|
@@ -433,9 +465,13 @@ export async function ensureSidecar(root, options = {}) {
|
|
|
433
465
|
void Promise.all(watchers.map((watcher) => watcher.close().catch(() => { })));
|
|
434
466
|
rmSync(portFilePath(root), { force: true });
|
|
435
467
|
state.starting = undefined;
|
|
436
|
-
|
|
468
|
+
const closeServer = new Promise((resolveClose, rejectClose) => {
|
|
437
469
|
server.close((error) => (error ? rejectClose(error) : resolveClose()));
|
|
438
470
|
});
|
|
471
|
+
return Promise.all([
|
|
472
|
+
closeServer,
|
|
473
|
+
closeProjectBridge(),
|
|
474
|
+
]).then(() => undefined);
|
|
439
475
|
},
|
|
440
476
|
};
|
|
441
477
|
return handle;
|
|
@@ -452,7 +488,8 @@ export async function ensureSidecar(root, options = {}) {
|
|
|
452
488
|
return starting;
|
|
453
489
|
}
|
|
454
490
|
function respond(req, res, currentManifest, currentGeneration, streams, receiveContracts) {
|
|
455
|
-
const
|
|
491
|
+
const requestUrl = req.url ?? "";
|
|
492
|
+
const url = requestUrl.split("?")[0];
|
|
456
493
|
// Loader postings aggregate component contracts (Stage 5). Loopback-only by
|
|
457
494
|
// virtue of the bind address; payload size is capped defensively.
|
|
458
495
|
if (url === `${NUDGE_UI_ROUTE_PREFIX}contracts` && req.method === "POST") {
|
|
@@ -479,6 +516,14 @@ function respond(req, res, currentManifest, currentGeneration, streams, receiveC
|
|
|
479
516
|
});
|
|
480
517
|
return;
|
|
481
518
|
}
|
|
519
|
+
if (isNudgeUiEditorDocumentRequest(requestUrl, req.method, req.headers)) {
|
|
520
|
+
res.writeHead(200, {
|
|
521
|
+
"content-type": "text/html; charset=utf-8",
|
|
522
|
+
"cache-control": "no-store",
|
|
523
|
+
});
|
|
524
|
+
res.end(req.method === "HEAD" ? undefined : createNudgeUiEditorDocument());
|
|
525
|
+
return;
|
|
526
|
+
}
|
|
482
527
|
if (req.method !== "GET") {
|
|
483
528
|
res.writeHead(405).end();
|
|
484
529
|
return;
|
|
@@ -486,7 +531,11 @@ function respond(req, res, currentManifest, currentGeneration, streams, receiveC
|
|
|
486
531
|
if (url === NUDGE_UI_MANIFEST_PATH) {
|
|
487
532
|
// The served snapshot carries its revision so clients can reconcile
|
|
488
533
|
// against SSE notifications instead of guessing.
|
|
489
|
-
const body = `${JSON.stringify({
|
|
534
|
+
const body = `${JSON.stringify({
|
|
535
|
+
...currentManifest(),
|
|
536
|
+
revision: currentGeneration(),
|
|
537
|
+
...automationManifestFields(),
|
|
538
|
+
})}\n`;
|
|
490
539
|
res.writeHead(200, {
|
|
491
540
|
"content-type": "application/json",
|
|
492
541
|
"cache-control": "no-store",
|
|
@@ -28,6 +28,8 @@ export interface NudgeUiNextConfig {
|
|
|
28
28
|
}
|
|
29
29
|
/** Host-specific policy additions passed to the shared source compiler. */
|
|
30
30
|
export interface NudgeUiNextOptions {
|
|
31
|
+
/** `false` returns the configuration untouched. `NUDGE_UI=0` has the same effect for one run. */
|
|
32
|
+
readonly enabled?: boolean;
|
|
31
33
|
readonly componentProtocols?: ComponentModuleProtocols;
|
|
32
34
|
/** Authored workspace directories outside the Next.js application root. */
|
|
33
35
|
readonly sourceRoots?: readonly string[];
|
|
@@ -4,7 +4,8 @@ import { dirname, join, relative, resolve } from "node:path";
|
|
|
4
4
|
import { ensureSidecar } from "./sidecar.js";
|
|
5
5
|
import { buildManifest } from "./manifest.js";
|
|
6
6
|
import { nudgeUiRepositoryPackagePath } from "./repositoryScope.js";
|
|
7
|
-
import {
|
|
7
|
+
import { isNudgeUiEnabled } from "../environment.js";
|
|
8
|
+
import { NUDGE_UI_EDITOR_QUERY_PARAM, NUDGE_UI_EDITOR_QUERY_VALUE, NUDGE_UI_ROUTE_PREFIX, } from "../../transport/index.js";
|
|
8
9
|
const NAMESPACE_PREFIX = NUDGE_UI_ROUTE_PREFIX.slice(0, -1);
|
|
9
10
|
const SUPPORTED_NEXT_RANGE = ">=15.3 <17";
|
|
10
11
|
/**
|
|
@@ -104,7 +105,7 @@ export function withNudgeUi(config = {}, options = {}) {
|
|
|
104
105
|
: () => config;
|
|
105
106
|
return (phase) => {
|
|
106
107
|
const resolved = factory(phase);
|
|
107
|
-
if (!isDevelopmentEvaluation(phase))
|
|
108
|
+
if (!isDevelopmentEvaluation(phase) || !isNudgeUiEnabled(options.enabled))
|
|
108
109
|
return resolved;
|
|
109
110
|
return instrumentConfig(resolved, options);
|
|
110
111
|
};
|
|
@@ -119,12 +120,15 @@ function instrumentConfig(config, options) {
|
|
|
119
120
|
return config;
|
|
120
121
|
}
|
|
121
122
|
const sourceRoots = options.sourceRoots?.map((sourceRoot) => resolve(root, sourceRoot));
|
|
123
|
+
const bridgeOrigin = nextDevelopmentOrigin();
|
|
122
124
|
// ensureSidecar is a per-process singleton; awaiting it wherever the port
|
|
123
125
|
// is needed removes any config-evaluation race. The same authored roots
|
|
124
126
|
// reach token discovery so workspace CSS is visible to both integrations.
|
|
125
127
|
const sidecarPort = () => ensureSidecar(root, {
|
|
126
128
|
manifest: buildManifest({ root }),
|
|
127
129
|
tokens: true,
|
|
130
|
+
projectBridgeOrigin: bridgeOrigin.origin,
|
|
131
|
+
projectBridgeAllowedOrigins: bridgeOrigin.allowedOrigins,
|
|
128
132
|
...(sourceRoots ? { sourceRoots } : {}),
|
|
129
133
|
})
|
|
130
134
|
.then((handle) => handle.port)
|
|
@@ -280,6 +284,14 @@ function instrumentConfig(config, options) {
|
|
|
280
284
|
source: `${NUDGE_UI_ROUTE_PREFIX}:path*`,
|
|
281
285
|
destination: `http://127.0.0.1:${port}${NUDGE_UI_ROUTE_PREFIX}:path*`,
|
|
282
286
|
});
|
|
287
|
+
const editorRewrite = (port, header) => ({
|
|
288
|
+
source: "/:path*",
|
|
289
|
+
has: [
|
|
290
|
+
{ type: "query", key: NUDGE_UI_EDITOR_QUERY_PARAM, value: NUDGE_UI_EDITOR_QUERY_VALUE },
|
|
291
|
+
{ type: "header", ...header },
|
|
292
|
+
],
|
|
293
|
+
destination: `http://127.0.0.1:${port}/:path*`,
|
|
294
|
+
});
|
|
283
295
|
const resolveRewrites = async () => {
|
|
284
296
|
const port = await sidecarPort();
|
|
285
297
|
const userRewrites = typeof source.rewrites === "function"
|
|
@@ -297,7 +309,12 @@ function instrumentConfig(config, options) {
|
|
|
297
309
|
// Port 0 (sidecar failed to bind) yields a dead destination; the mount
|
|
298
310
|
// surfaces an honest fetch failure instead of silently pretending to
|
|
299
311
|
// work.
|
|
300
|
-
beforeFiles: [
|
|
312
|
+
beforeFiles: [
|
|
313
|
+
proxyRewrite(port),
|
|
314
|
+
editorRewrite(port, { key: "accept", value: ".*text/html.*" }),
|
|
315
|
+
editorRewrite(port, { key: "sec-fetch-dest", value: "document" }),
|
|
316
|
+
...(shape.beforeFiles ?? []),
|
|
317
|
+
],
|
|
301
318
|
afterFiles: shape.afterFiles ?? [],
|
|
302
319
|
fallback: shape.fallback ?? [],
|
|
303
320
|
};
|
|
@@ -308,3 +325,15 @@ function instrumentConfig(config, options) {
|
|
|
308
325
|
// consumers keep their NextConfig typing via the generic passthrough.
|
|
309
326
|
return nextConfig;
|
|
310
327
|
}
|
|
328
|
+
function nextDevelopmentOrigin() {
|
|
329
|
+
const selected = process.env.__NEXT_PRIVATE_ORIGIN
|
|
330
|
+
?? `http://localhost:${process.env.PORT ?? "3000"}`;
|
|
331
|
+
const url = new URL(selected);
|
|
332
|
+
const port = url.port || (url.protocol === "https:" ? "443" : "80");
|
|
333
|
+
const aliases = ["localhost", "127.0.0.1", "[::1]"]
|
|
334
|
+
.map((host) => `${url.protocol}//${host}:${port}`);
|
|
335
|
+
return {
|
|
336
|
+
origin: url.origin,
|
|
337
|
+
allowedOrigins: [...new Set([url.origin, ...aliases])],
|
|
338
|
+
};
|
|
339
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export interface ProjectBridgeBrowserConfig {
|
|
2
|
+
readonly baseUrl: string;
|
|
3
|
+
readonly autoConnect: true;
|
|
4
|
+
}
|
|
5
|
+
/** Starts the optional project bridge installed beside the host application. */
|
|
6
|
+
export declare function startOptionalProjectBridge(input: {
|
|
7
|
+
readonly appRoot: string;
|
|
8
|
+
readonly projectId: string;
|
|
9
|
+
readonly origin: string;
|
|
10
|
+
readonly allowedOrigins?: readonly string[];
|
|
11
|
+
readonly info?: (message: string) => void;
|
|
12
|
+
readonly warn?: (message: string) => void;
|
|
13
|
+
}): Promise<{
|
|
14
|
+
browser: ProjectBridgeBrowserConfig;
|
|
15
|
+
close(): Promise<void>;
|
|
16
|
+
} | null>;
|
|
17
|
+
/** Returns the browser origin for a loopback HTTP server address. */
|
|
18
|
+
export declare function loopbackOrigin(address: {
|
|
19
|
+
address: string;
|
|
20
|
+
port: number;
|
|
21
|
+
}, protocol?: "http" | "https"): string;
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExtension) || function (path, preserveJsx) {
|
|
2
|
+
if (typeof path === "string" && /^\.\.?\//.test(path)) {
|
|
3
|
+
return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function (m, tsx, d, ext, cm) {
|
|
4
|
+
return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : (d + ext + "." + cm.toLowerCase() + "js");
|
|
5
|
+
});
|
|
6
|
+
}
|
|
7
|
+
return path;
|
|
8
|
+
};
|
|
9
|
+
import { existsSync } from "node:fs";
|
|
10
|
+
import { createRequire } from "node:module";
|
|
11
|
+
import { dirname, join, parse } from "node:path";
|
|
12
|
+
import { pathToFileURL } from "node:url";
|
|
13
|
+
const runningBridges = new Map();
|
|
14
|
+
/** Starts the optional project bridge installed beside the host application. */
|
|
15
|
+
export async function startOptionalProjectBridge(input) {
|
|
16
|
+
const key = `${input.appRoot}\u0000${input.origin}`;
|
|
17
|
+
const running = runningBridges.get(key);
|
|
18
|
+
if (running)
|
|
19
|
+
return running;
|
|
20
|
+
const starting = launchOptionalProjectBridge(input, key);
|
|
21
|
+
runningBridges.set(key, starting);
|
|
22
|
+
void starting.then((bridge) => {
|
|
23
|
+
if (bridge === null && runningBridges.get(key) === starting)
|
|
24
|
+
runningBridges.delete(key);
|
|
25
|
+
});
|
|
26
|
+
return starting;
|
|
27
|
+
}
|
|
28
|
+
async function launchOptionalProjectBridge(input, key) {
|
|
29
|
+
let modulePath;
|
|
30
|
+
try {
|
|
31
|
+
if (!isPnpRuntime() && !hasProjectInstalledMcp(input.appRoot)) {
|
|
32
|
+
runningBridges.delete(key);
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
modulePath = createRequire(join(input.appRoot, "package.json")).resolve("@nudge-ui/mcp/project");
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
runningBridges.delete(key);
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
try {
|
|
42
|
+
const loaded = await import(__rewriteRelativeImportExtension(pathToFileURL(modulePath).href));
|
|
43
|
+
if (typeof loaded.startProjectBridge !== "function") {
|
|
44
|
+
throw new Error("the project bridge export is unavailable");
|
|
45
|
+
}
|
|
46
|
+
const runtime = await loaded.startProjectBridge({
|
|
47
|
+
appRoot: input.appRoot,
|
|
48
|
+
projectId: input.projectId,
|
|
49
|
+
origin: input.origin,
|
|
50
|
+
...(input.allowedOrigins ? { allowedOrigins: input.allowedOrigins } : {}),
|
|
51
|
+
});
|
|
52
|
+
if (runtime.browser.projectId !== input.projectId || runtime.browser.origin !== input.origin) {
|
|
53
|
+
await runtime.close().catch(() => undefined);
|
|
54
|
+
throw new Error("the project bridge returned a different project or origin");
|
|
55
|
+
}
|
|
56
|
+
input.info?.(`[nudge-ui] project bridge ready for ${input.projectId}`);
|
|
57
|
+
let closed = false;
|
|
58
|
+
return {
|
|
59
|
+
browser: { baseUrl: runtime.browser.bridgeUrl, autoConnect: true },
|
|
60
|
+
close: async () => {
|
|
61
|
+
if (closed)
|
|
62
|
+
return;
|
|
63
|
+
closed = true;
|
|
64
|
+
runningBridges.delete(key);
|
|
65
|
+
await runtime.close();
|
|
66
|
+
},
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
catch (error) {
|
|
70
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
71
|
+
input.warn?.(`[nudge-ui] MCP project bridge failed to start: ${detail}`);
|
|
72
|
+
runningBridges.delete(key);
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
function isPnpRuntime() {
|
|
77
|
+
return typeof process.versions.pnp === "string";
|
|
78
|
+
}
|
|
79
|
+
function hasProjectInstalledMcp(appRoot) {
|
|
80
|
+
let directory = appRoot;
|
|
81
|
+
const root = parse(directory).root;
|
|
82
|
+
for (;;) {
|
|
83
|
+
if (existsSync(join(directory, "node_modules", "@nudge-ui", "mcp", "package.json")))
|
|
84
|
+
return true;
|
|
85
|
+
if (directory === root)
|
|
86
|
+
return false;
|
|
87
|
+
directory = dirname(directory);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
/** Returns the browser origin for a loopback HTTP server address. */
|
|
91
|
+
export function loopbackOrigin(address, protocol = "http") {
|
|
92
|
+
const host = address.address === "::" || address.address === "::1"
|
|
93
|
+
? "[::1]"
|
|
94
|
+
: address.address === "0.0.0.0"
|
|
95
|
+
? "127.0.0.1"
|
|
96
|
+
: address.address;
|
|
97
|
+
return `${protocol}://${host}:${address.port}`;
|
|
98
|
+
}
|
|
@@ -9,4 +9,4 @@ export declare function parseServeArguments(args: readonly string[], currentDire
|
|
|
9
9
|
/** Starts the CLI server and waits until the process receives a termination signal. */
|
|
10
10
|
export declare function runServeCommand(options: ServeCommandOptions): Promise<void>;
|
|
11
11
|
/** Runs the standalone command. */
|
|
12
|
-
export declare function main(args?: string[]): Promise<void>;
|
|
12
|
+
export declare function main(args?: string[], packageVersion?: string): Promise<void>;
|
package/dist/hosts/static/cli.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { resolve } from "node:path";
|
|
2
|
+
import { runAgentCommand } from "../../cli/agentCommand.js";
|
|
2
3
|
import { createStandaloneServer } from "./server.js";
|
|
3
4
|
/** Parses the standalone CLI's intentionally small command surface. */
|
|
4
5
|
export function parseServeArguments(args, currentDirectory = process.cwd()) {
|
|
@@ -44,7 +45,11 @@ export async function runServeCommand(options) {
|
|
|
44
45
|
await waitForTermination(server);
|
|
45
46
|
}
|
|
46
47
|
/** Runs the standalone command. */
|
|
47
|
-
export async function main(args = process.argv.slice(2)) {
|
|
48
|
+
export async function main(args = process.argv.slice(2), packageVersion) {
|
|
49
|
+
if (args[0] === "agent") {
|
|
50
|
+
runAgentCommand(args.slice(1), packageVersion);
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
48
53
|
const options = parseServeArguments(args);
|
|
49
54
|
await runServeCommand(options);
|
|
50
55
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { NudgeUiClientManifest } from "../../inspector/clientManifest.js";
|
|
2
2
|
import type { ProjectTokenSnapshot } from "../../project/tokens.js";
|
|
3
|
-
export { NUDGE_UI_CLIENT_PATH, NUDGE_UI_MANIFEST_PATH, NUDGE_UI_MOUNT_ID, NUDGE_UI_RELOAD_PATH, NUDGE_UI_ROUTE_PREFIX, } from "../../transport/index.js";
|
|
3
|
+
export { NUDGE_UI_CLIENT_PATH, NUDGE_UI_EDITOR_PATH, NUDGE_UI_MANIFEST_PATH, NUDGE_UI_MOUNT_ID, NUDGE_UI_RELOAD_PATH, NUDGE_UI_ROUTE_PREFIX, } from "../../transport/index.js";
|
|
4
4
|
/** The serializable runtime document sent to a standalone client. */
|
|
5
5
|
export interface StandaloneRuntimeManifest extends NudgeUiClientManifest {
|
|
6
6
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { NUDGE_UI_MANIFEST_VERSION, NUDGE_UI_RELOAD_PATH } from "../../transport/index.js";
|
|
2
|
-
|
|
2
|
+
import { automationManifestFields } from "../environment.js";
|
|
3
|
+
export { NUDGE_UI_CLIENT_PATH, NUDGE_UI_EDITOR_PATH, NUDGE_UI_MANIFEST_PATH, NUDGE_UI_MOUNT_ID, NUDGE_UI_RELOAD_PATH, NUDGE_UI_ROUTE_PREFIX, } from "../../transport/index.js";
|
|
3
4
|
/**
|
|
4
5
|
* Creates the first valid static-HTML runtime snapshot.
|
|
5
6
|
*
|
|
@@ -39,6 +40,7 @@ export function createStandaloneRuntimeManifest(projectId, tokenSnapshot = empty
|
|
|
39
40
|
strategy: "reload-document",
|
|
40
41
|
events: ["ready", "reload"],
|
|
41
42
|
},
|
|
43
|
+
...automationManifestFields(),
|
|
42
44
|
};
|
|
43
45
|
}
|
|
44
46
|
function emptyTokenSnapshot() {
|