@nudge-ui/mcp 0.2.0 → 0.2.1
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 +71 -53
- package/dist/bridge.d.ts +4 -2
- package/dist/bridge.js +237 -15
- package/dist/cli.d.ts +2 -1
- package/dist/cli.js +65 -12
- package/dist/cli.mjs +14741 -13959
- package/dist/discovery.d.ts +29 -0
- package/dist/discovery.js +112 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.js +3 -1
- package/dist/internal/agent-protocol.d.ts +65 -1
- package/dist/internal/agent-protocol.js +183 -3
- package/dist/project.d.ts +54 -0
- package/dist/project.js +151 -0
- package/dist/projectSessionClient.d.ts +28 -0
- package/dist/projectSessionClient.js +93 -0
- package/dist/protocol.d.ts +13 -2
- package/dist/protocol.js +12 -1
- package/dist/server.d.ts +14 -0
- package/dist/server.js +90 -22
- package/dist/sessionRegistry.d.ts +8 -0
- package/dist/sessionRegistry.js +89 -0
- package/dist/sessionSelection.d.ts +15 -0
- package/dist/sessionSelection.js +41 -0
- package/package.json +6 -1
package/dist/cli.js
CHANGED
|
@@ -2,7 +2,8 @@ import { createHash } from "node:crypto";
|
|
|
2
2
|
import { spawn } from "node:child_process";
|
|
3
3
|
import { basename, resolve } from "node:path";
|
|
4
4
|
import { defaultBridgePort } from "./internal/agent-protocol.js";
|
|
5
|
-
import {
|
|
5
|
+
import { discoverProjectSessions } from "./discovery.js";
|
|
6
|
+
import { createAgentCompanion, createDiscoveredAgentAdapter, } from "./server.js";
|
|
6
7
|
const DEFAULT_PORT = 0;
|
|
7
8
|
const DEFAULT_COMMAND_TIMEOUT_MS = 5_000;
|
|
8
9
|
const PAGE_PROBE_TIMEOUT_MS = 1_500;
|
|
@@ -59,6 +60,8 @@ function parseInteger(value, flag, maximum) {
|
|
|
59
60
|
}
|
|
60
61
|
/** Parses only project-scoped, host-neutral CLI options. */
|
|
61
62
|
export function parseCliArguments(argv = process.argv.slice(2), environment = process.env) {
|
|
63
|
+
const command = argv[0] === "doctor" ? "doctor" : "serve";
|
|
64
|
+
const argumentsToParse = command === "doctor" ? argv.slice(1) : argv;
|
|
62
65
|
const root = resolve(environment.NUDGE_UI_WORKSPACE_ROOT ?? environment.INIT_CWD ?? process.cwd());
|
|
63
66
|
let projectId = environment.NUDGE_UI_PROJECT_ID ?? projectIdFor(root);
|
|
64
67
|
let origin = environment.NUDGE_UI_ORIGIN;
|
|
@@ -73,27 +76,27 @@ export function parseCliArguments(argv = process.argv.slice(2), environment = pr
|
|
|
73
76
|
let workspaceRoot = root;
|
|
74
77
|
let help = false;
|
|
75
78
|
let explicitPort = environment.NUDGE_UI_BRIDGE_PORT !== undefined;
|
|
76
|
-
for (let index = 0; index <
|
|
77
|
-
const argument =
|
|
79
|
+
for (let index = 0; index < argumentsToParse.length; index += 1) {
|
|
80
|
+
const argument = argumentsToParse[index];
|
|
78
81
|
switch (argument) {
|
|
79
82
|
case "--help":
|
|
80
83
|
case "-h":
|
|
81
84
|
help = true;
|
|
82
85
|
break;
|
|
83
86
|
case "--project-id":
|
|
84
|
-
projectId = valueAfter(
|
|
87
|
+
projectId = valueAfter(argumentsToParse, index, argument);
|
|
85
88
|
index += 1;
|
|
86
89
|
break;
|
|
87
90
|
case "--origin":
|
|
88
|
-
origin = valueAfter(
|
|
91
|
+
origin = valueAfter(argumentsToParse, index, argument);
|
|
89
92
|
index += 1;
|
|
90
93
|
break;
|
|
91
94
|
case "--workspace-root":
|
|
92
|
-
workspaceRoot = resolve(valueAfter(
|
|
95
|
+
workspaceRoot = resolve(valueAfter(argumentsToParse, index, argument));
|
|
93
96
|
index += 1;
|
|
94
97
|
break;
|
|
95
98
|
case "--host": {
|
|
96
|
-
const candidate = valueAfter(
|
|
99
|
+
const candidate = valueAfter(argumentsToParse, index, argument);
|
|
97
100
|
if (candidate !== "127.0.0.1" && candidate !== "::1" && candidate !== "localhost") {
|
|
98
101
|
throw new TypeError("--host must be 127.0.0.1, ::1, or localhost");
|
|
99
102
|
}
|
|
@@ -102,12 +105,12 @@ export function parseCliArguments(argv = process.argv.slice(2), environment = pr
|
|
|
102
105
|
break;
|
|
103
106
|
}
|
|
104
107
|
case "--port":
|
|
105
|
-
port = parseInteger(valueAfter(
|
|
108
|
+
port = parseInteger(valueAfter(argumentsToParse, index, argument), argument, 65_535);
|
|
106
109
|
explicitPort = true;
|
|
107
110
|
index += 1;
|
|
108
111
|
break;
|
|
109
112
|
case "--command-timeout-ms":
|
|
110
|
-
commandTimeoutMs = parseInteger(valueAfter(
|
|
113
|
+
commandTimeoutMs = parseInteger(valueAfter(argumentsToParse, index, argument), argument, 60_000);
|
|
111
114
|
if (commandTimeoutMs === 0)
|
|
112
115
|
throw new TypeError("--command-timeout-ms must be greater than zero");
|
|
113
116
|
index += 1;
|
|
@@ -120,11 +123,12 @@ export function parseCliArguments(argv = process.argv.slice(2), environment = pr
|
|
|
120
123
|
throw new TypeError("--project-id must be a bounded non-empty string");
|
|
121
124
|
if (!explicitPort)
|
|
122
125
|
port = defaultBridgePort(projectId);
|
|
123
|
-
return { projectId, origin, workspaceRoot, host, port, commandTimeoutMs, help };
|
|
126
|
+
return { command, projectId, origin, workspaceRoot, host, port, commandTimeoutMs, help };
|
|
124
127
|
}
|
|
125
|
-
export const CLI_USAGE = `Usage: nudge-mcp [options]
|
|
128
|
+
export const CLI_USAGE = `Usage: nudge-mcp [doctor] [options]
|
|
126
129
|
|
|
127
|
-
Starts a
|
|
130
|
+
Starts a standard MCP stdio adapter. It discovers the bridge owned by the
|
|
131
|
+
running project unless --origin selects the legacy coupled mode.
|
|
128
132
|
|
|
129
133
|
Options:
|
|
130
134
|
--project-id <id> Stable project pairing identity
|
|
@@ -142,6 +146,55 @@ export async function runCli(argv = process.argv.slice(2), environment = process
|
|
|
142
146
|
process.stdout.write(CLI_USAGE);
|
|
143
147
|
return;
|
|
144
148
|
}
|
|
149
|
+
if (options.command === "doctor") {
|
|
150
|
+
const sessions = await discoverProjectSessions(options.workspaceRoot);
|
|
151
|
+
const matches = sessions.filter((session) => session.matchesApplication);
|
|
152
|
+
process.stdout.write([
|
|
153
|
+
`[nudge-ui] workspace: ${options.workspaceRoot}`,
|
|
154
|
+
`[nudge-ui] live sessions: ${sessions.length}`,
|
|
155
|
+
`[nudge-ui] matching sessions: ${matches.length}`,
|
|
156
|
+
...(matches.length === 0
|
|
157
|
+
? ["[nudge-ui] no matching project bridge is running; start the development server to make Nudge available"]
|
|
158
|
+
: matches.map((session) => {
|
|
159
|
+
const state = session.status.connection === "working"
|
|
160
|
+
? "working"
|
|
161
|
+
: session.status.listenerActive ? "listening" : "available";
|
|
162
|
+
return `[nudge-ui] ${state}: ${session.projectId} (${session.origin})${session.claimed ? " [claimed]" : ""}`;
|
|
163
|
+
})),
|
|
164
|
+
].join("\n") + "\n");
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
if (!options.origin) {
|
|
168
|
+
const adapter = await createDiscoveredAgentAdapter({ workspaceRoot: options.workspaceRoot });
|
|
169
|
+
let stopping = false;
|
|
170
|
+
let resolveAdapterWait = null;
|
|
171
|
+
const stop = () => {
|
|
172
|
+
if (stopping)
|
|
173
|
+
return;
|
|
174
|
+
stopping = true;
|
|
175
|
+
void adapter.close();
|
|
176
|
+
resolveAdapterWait?.();
|
|
177
|
+
};
|
|
178
|
+
process.once("SIGINT", stop);
|
|
179
|
+
process.once("SIGTERM", stop);
|
|
180
|
+
try {
|
|
181
|
+
await adapter.start();
|
|
182
|
+
await new Promise((resolveAdapter) => {
|
|
183
|
+
const finish = () => resolveAdapter();
|
|
184
|
+
// Keep a direct resolver so signal handlers terminate even though
|
|
185
|
+
// installing a signal handler suppresses Node's default process exit.
|
|
186
|
+
resolveAdapterWait = finish;
|
|
187
|
+
process.stdin.once("end", finish);
|
|
188
|
+
process.once("exit", finish);
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
finally {
|
|
192
|
+
process.off("SIGINT", stop);
|
|
193
|
+
process.off("SIGTERM", stop);
|
|
194
|
+
await adapter.close();
|
|
195
|
+
}
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
145
198
|
const companion = createAgentCompanion({
|
|
146
199
|
...options,
|
|
147
200
|
onControllerUnavailable: (pageUrl) => openPairedPage(pageUrl).then(() => undefined),
|