create-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 +80 -34
- package/dist/agent-setup.d.ts +11 -7
- package/dist/agent-setup.js +55 -35
- package/dist/agent-verification.d.ts +3 -0
- package/dist/agent-verification.js +21 -0
- package/dist/arguments.d.ts +2 -1
- package/dist/arguments.js +8 -2
- package/dist/cli.d.ts +3 -1
- package/dist/cli.js +42 -9
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -1,59 +1,105 @@
|
|
|
1
|
-
#
|
|
1
|
+
# create-nudge-ui
|
|
2
2
|
|
|
3
|
-
`create-nudge-ui` detects
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
Add Nudge UI to an existing app with one command. `create-nudge-ui` detects your
|
|
4
|
+
framework, installs `nudge-ui`, and updates your development configuration. It
|
|
5
|
+
can also connect your coding agent so you can send design changes from the browser.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
[Nudge UI](https://www.npmjs.com/package/nudge-ui) lets you inspect your running
|
|
8
|
+
app, preview visual edits, and turn them into a prompt for a coding agent.
|
|
9
|
+
|
|
10
|
+
## Get started
|
|
11
|
+
|
|
12
|
+
From your application's root directory, run:
|
|
8
13
|
|
|
9
14
|
```sh
|
|
10
15
|
npm create nudge-ui@latest
|
|
11
16
|
```
|
|
12
17
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
18
|
+
Follow the prompts, then start your app with its usual development command and
|
|
19
|
+
open the local URL. For static HTML, run the `nudge-ui serve` command printed by
|
|
20
|
+
the initializer.
|
|
21
|
+
|
|
22
|
+
Requires Node.js 20 or later and a supported app. Your framework or build tool
|
|
23
|
+
may require a newer Node.js version.
|
|
16
24
|
|
|
17
|
-
|
|
18
|
-
agent. It detects installed agents, installs the matching `@nudge-ui/mcp`
|
|
19
|
-
version in the project, and adds a project-scoped MCP entry. The entry launches
|
|
20
|
-
the package from this project's `node_modules` directory and passes the
|
|
21
|
-
canonical workspace path, so different Git worktrees do not share a server
|
|
22
|
-
configuration.
|
|
25
|
+
## What setup does
|
|
23
26
|
|
|
24
|
-
|
|
27
|
+
- Detects Next.js, Astro, Vite with React, or a static HTML directory.
|
|
28
|
+
- Installs `nudge-ui` as a development dependency using npm, pnpm, Yarn, or Bun.
|
|
29
|
+
- Adds the framework integration to your configuration. Static HTML uses the
|
|
30
|
+
bundled development server instead.
|
|
31
|
+
- Offers to connect a coding agent through
|
|
32
|
+
[`@nudge-ui/mcp`](https://www.npmjs.com/package/@nudge-ui/mcp).
|
|
25
33
|
|
|
26
|
-
|
|
34
|
+
Run it inside the app directory in a monorepo. If detection is ambiguous, choose
|
|
35
|
+
the framework explicitly:
|
|
27
36
|
|
|
28
37
|
```sh
|
|
29
38
|
npm create nudge-ui@latest -- --framework astro
|
|
30
39
|
```
|
|
31
40
|
|
|
32
|
-
|
|
33
|
-
without modifying the project. Run `npm create nudge-ui@latest -- --help` for
|
|
34
|
-
the complete command reference.
|
|
41
|
+
## Connect a coding agent
|
|
35
42
|
|
|
36
|
-
|
|
43
|
+
Choose agent setup during initialization, or add it later:
|
|
37
44
|
|
|
38
45
|
```sh
|
|
39
|
-
|
|
40
|
-
|
|
46
|
+
npm create nudge-ui@latest -- --agent-only
|
|
47
|
+
```
|
|
41
48
|
|
|
42
|
-
|
|
43
|
-
|
|
49
|
+
Setup installs a bridge dependency in the app and a reusable MCP adapter under
|
|
50
|
+
`~/.nudge-ui/adapters/`. It registers the adapter globally for the selected
|
|
51
|
+
agents, so other checkouts and Git worktrees can use it. Each app still needs
|
|
52
|
+
its own Nudge integration and bridge dependency.
|
|
44
53
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
54
|
+
Setup verifies the adapter before changing agent settings. If automatic
|
|
55
|
+
configuration fails, it prints a global stdio configuration you
|
|
56
|
+
can add manually. npm must be available to install the reusable adapter, even
|
|
57
|
+
when your app uses another package manager.
|
|
48
58
|
|
|
49
|
-
|
|
50
|
-
|
|
59
|
+
Fully restart your agent host, then ask it to **listen to Nudge in this
|
|
60
|
+
workspace**. Keep the agent listening while you send changes from the browser.
|
|
61
|
+
The MCP integration is early alpha; host behavior and setup may change.
|
|
62
|
+
|
|
63
|
+
## Common commands
|
|
51
64
|
|
|
52
65
|
```sh
|
|
53
|
-
|
|
66
|
+
# Preview setup without changing files or installing packages.
|
|
67
|
+
npm create nudge-ui@latest -- --dry-run
|
|
68
|
+
|
|
69
|
+
# Install the inspector without agent setup.
|
|
70
|
+
npm create nudge-ui@latest -- --no-mcp
|
|
71
|
+
|
|
72
|
+
# Set up a specific agent without prompts.
|
|
73
|
+
npm create nudge-ui@latest -- --agent codex --yes
|
|
74
|
+
|
|
75
|
+
# Connect an agent to an existing Nudge installation.
|
|
76
|
+
npm create nudge-ui@latest -- --agent-only --agent cursor --yes
|
|
54
77
|
```
|
|
55
78
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
79
|
+
## Options
|
|
80
|
+
|
|
81
|
+
Pass options after `--` when using `npm create`.
|
|
82
|
+
|
|
83
|
+
| Option | Purpose |
|
|
84
|
+
| --- | --- |
|
|
85
|
+
| `--framework <name>` | Select `nextjs`, `astro`, `vite-react`, or `standalone`. |
|
|
86
|
+
| `--package-manager <name>` | Select `npm`, `pnpm`, `yarn`, or `bun`. |
|
|
87
|
+
| `--mcp` | Enable agent setup. |
|
|
88
|
+
| `--no-mcp` | Skip agent setup. |
|
|
89
|
+
| `--agent <id>` | Select an agent, such as `codex` or `cursor`. Repeat for multiple agents. Enables agent setup. |
|
|
90
|
+
| `--agent-only` | Install or repair agent integration without changing framework configuration. |
|
|
91
|
+
| `--yes`, `-y` | Accept defaults without prompts, including setup for detected agents. Use `--no-mcp` to skip agent setup. |
|
|
92
|
+
| `--dry-run` | Print planned changes without applying them. |
|
|
93
|
+
| `--mcp-package <specifier>` | Use a specific MCP package or local tarball for both the bridge and adapter. |
|
|
94
|
+
| `--help`, `-h` | Show command help. |
|
|
95
|
+
|
|
96
|
+
For troubleshooting and custom integrations, see the
|
|
97
|
+
[coding-agent guide](https://github.com/charlessmart/nudge-ui/blob/main/docs/agent-integration.md).
|
|
98
|
+
For manual framework setup, see
|
|
99
|
+
[`nudge-ui`](https://www.npmjs.com/package/nudge-ui).
|
|
100
|
+
|
|
101
|
+
## Links
|
|
102
|
+
|
|
103
|
+
[Repository](https://github.com/charlessmart/nudge-ui) ·
|
|
104
|
+
[Issues](https://github.com/charlessmart/nudge-ui/issues) ·
|
|
105
|
+
[MIT license](https://github.com/charlessmart/nudge-ui/blob/main/LICENSE)
|
package/dist/agent-setup.d.ts
CHANGED
|
@@ -6,25 +6,29 @@ export interface AgentSetupPlan {
|
|
|
6
6
|
readonly projectRoot: string;
|
|
7
7
|
readonly packageSpecifier: string;
|
|
8
8
|
readonly installCommand: InstallCommand;
|
|
9
|
+
readonly adapterRoot: string;
|
|
10
|
+
readonly adapterInstallCommand: InstallCommand;
|
|
9
11
|
readonly serverConfig: McpServerConfig;
|
|
10
|
-
readonly serverEntry
|
|
12
|
+
readonly serverEntry: string;
|
|
11
13
|
}
|
|
12
14
|
export interface AgentInstallOutcome {
|
|
13
15
|
readonly agent: string;
|
|
14
16
|
readonly displayName: string;
|
|
15
17
|
readonly result?: InstallResult;
|
|
16
18
|
readonly unsupported: boolean;
|
|
19
|
+
readonly migrationError?: string;
|
|
20
|
+
readonly backups?: readonly string[];
|
|
17
21
|
}
|
|
18
|
-
/**
|
|
19
|
-
export declare function planAgentSetup(projectRoot: string, packageManager: PackageManager, nudgeUiVersion?: string): AgentSetupPlan;
|
|
22
|
+
/** Plans the project bridge dependency and an independent, versioned adapter installation. */
|
|
23
|
+
export declare function planAgentSetup(projectRoot: string, packageManager: PackageManager, nudgeUiVersion?: string, adapterDirectory?: string, mcpPackageSpecifier?: string): AgentSetupPlan;
|
|
20
24
|
/** Checks that a node_modules based install produced the configured executable. */
|
|
21
25
|
export declare function isAgentServerAvailable(plan: AgentSetupPlan): boolean;
|
|
22
|
-
/** Returns agents that
|
|
26
|
+
/** Returns agents that support a reusable stdio MCP configuration. */
|
|
23
27
|
export declare function projectAgentTypes(): AgentType[];
|
|
24
|
-
/** Detects installed or already configured agents
|
|
28
|
+
/** Detects installed or already configured agents. */
|
|
25
29
|
export declare function detectProjectAgentCandidates(projectRoot: string): Promise<AgentType[]>;
|
|
26
|
-
/**
|
|
27
|
-
export declare function configureProjectAgents(plan: AgentSetupPlan, selectedAgents: readonly string[]): AgentInstallOutcome[]
|
|
30
|
+
/** Registers the reusable adapter and removes the current project's overriding entry. */
|
|
31
|
+
export declare function configureProjectAgents(plan: AgentSetupPlan, selectedAgents: readonly string[]): Promise<AgentInstallOutcome[]>;
|
|
28
32
|
/** Formats a complete stdio entry for agents that add-mcp cannot configure. */
|
|
29
33
|
export declare function manualAgentConfiguration(plan: AgentSetupPlan): string;
|
|
30
34
|
export declare function projectAgentChoices(detected: readonly AgentType[]): Array<{
|
package/dist/agent-setup.js
CHANGED
|
@@ -1,40 +1,40 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { copyFileSync, existsSync, readFileSync, realpathSync } from "node:fs";
|
|
3
|
+
import { homedir } from "node:os";
|
|
2
4
|
import { join } from "node:path";
|
|
3
|
-
import { agents, detectGlobalAgents, detectProjectAgents, getAgentTypes, upsertServer, } from "add-mcp";
|
|
5
|
+
import { agents, detectGlobalAgents, detectProjectAgents, getAgentTypes, upsertServer, listInstalledServers, removeServer, } from "add-mcp";
|
|
4
6
|
import { installCommand } from "./installer.js";
|
|
5
7
|
export const nudgeServerName = "nudge_ui";
|
|
6
|
-
/**
|
|
7
|
-
export function planAgentSetup(projectRoot, packageManager, nudgeUiVersion) {
|
|
8
|
+
/** Plans the project bridge dependency and an independent, versioned adapter installation. */
|
|
9
|
+
export function planAgentSetup(projectRoot, packageManager, nudgeUiVersion, adapterDirectory = join(homedir(), ".nudge-ui", "adapters"), mcpPackageSpecifier) {
|
|
8
10
|
const canonicalRoot = realpathSync.native(projectRoot);
|
|
9
|
-
const packageSpecifier = `@nudge-ui/mcp@${nudgeUiVersion ?? installedNudgeUiVersion(canonicalRoot) ?? initializerVersion()}`;
|
|
10
|
-
const
|
|
11
|
-
const
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
command: "yarn",
|
|
15
|
-
args: ["--cwd", canonicalRoot, "exec", "nudge-mcp", "--workspace-root", canonicalRoot],
|
|
16
|
-
}
|
|
17
|
-
: {
|
|
18
|
-
command: "node",
|
|
19
|
-
args: [serverEntry, "--workspace-root", canonicalRoot],
|
|
20
|
-
};
|
|
11
|
+
const packageSpecifier = mcpPackageSpecifier ?? `@nudge-ui/mcp@${nudgeUiVersion ?? installedNudgeUiVersion(canonicalRoot) ?? initializerVersion()}`;
|
|
12
|
+
const adapterPackageSpecifier = mcpPackageSpecifier ?? `@nudge-ui/mcp@${initializerVersion()}`;
|
|
13
|
+
const adapterRoot = join(adapterDirectory, initializerVersion());
|
|
14
|
+
const serverEntry = join(adapterRoot, "node_modules", "@nudge-ui", "mcp", "dist", "cli.mjs");
|
|
15
|
+
const serverConfig = { command: process.execPath, args: [serverEntry] };
|
|
21
16
|
return {
|
|
22
17
|
projectRoot: canonicalRoot,
|
|
23
18
|
packageSpecifier,
|
|
24
19
|
installCommand: installCommand(packageManager, packageSpecifier),
|
|
25
20
|
serverConfig,
|
|
26
|
-
|
|
21
|
+
adapterRoot,
|
|
22
|
+
adapterInstallCommand: {
|
|
23
|
+
executable: "npm",
|
|
24
|
+
args: ["install", "--prefix", adapterRoot, "--no-save", "--package-lock=false", adapterPackageSpecifier],
|
|
25
|
+
},
|
|
26
|
+
serverEntry,
|
|
27
27
|
};
|
|
28
28
|
}
|
|
29
29
|
/** Checks that a node_modules based install produced the configured executable. */
|
|
30
30
|
export function isAgentServerAvailable(plan) {
|
|
31
|
-
return
|
|
31
|
+
return existsSync(plan.serverEntry);
|
|
32
32
|
}
|
|
33
|
-
/** Returns agents that
|
|
33
|
+
/** Returns agents that support a reusable stdio MCP configuration. */
|
|
34
34
|
export function projectAgentTypes() {
|
|
35
|
-
return getAgentTypes().filter((agent) => agents[agent].
|
|
35
|
+
return getAgentTypes().filter((agent) => agents[agent].supportedTransports.includes("stdio"));
|
|
36
36
|
}
|
|
37
|
-
/** Detects installed or already configured agents
|
|
37
|
+
/** Detects installed or already configured agents. */
|
|
38
38
|
export async function detectProjectAgentCandidates(projectRoot) {
|
|
39
39
|
const supported = new Set(projectAgentTypes());
|
|
40
40
|
const detected = [
|
|
@@ -43,25 +43,45 @@ export async function detectProjectAgentCandidates(projectRoot) {
|
|
|
43
43
|
].filter((agent) => supported.has(agent));
|
|
44
44
|
return [...new Set(detected)];
|
|
45
45
|
}
|
|
46
|
-
/**
|
|
47
|
-
export function configureProjectAgents(plan, selectedAgents) {
|
|
46
|
+
/** Registers the reusable adapter and removes the current project's overriding entry. */
|
|
47
|
+
export async function configureProjectAgents(plan, selectedAgents) {
|
|
48
48
|
const supported = new Set(projectAgentTypes());
|
|
49
|
-
|
|
49
|
+
const outcomes = [];
|
|
50
|
+
for (const agent of new Set(selectedAgents)) {
|
|
50
51
|
if (!supported.has(agent)) {
|
|
51
|
-
|
|
52
|
+
outcomes.push({ agent, displayName: agent, unsupported: true });
|
|
53
|
+
continue;
|
|
52
54
|
}
|
|
53
55
|
const agentType = agent;
|
|
54
|
-
const
|
|
55
|
-
|
|
56
|
-
|
|
56
|
+
const global = await listInstalledServers({ agents: [agentType], global: true, cwd: plan.projectRoot });
|
|
57
|
+
const local = agents[agentType].localConfigPath
|
|
58
|
+
? await listInstalledServers({ agents: [agentType], global: false, cwd: plan.projectRoot })
|
|
59
|
+
: [];
|
|
60
|
+
const configurations = [...global, ...local];
|
|
61
|
+
const invalid = configurations.find((configuration) => configuration.error);
|
|
62
|
+
if (invalid) {
|
|
63
|
+
outcomes.push({ agent, displayName: agents[agentType].displayName, unsupported: false,
|
|
64
|
+
result: { success: false, path: invalid.configPath, error: invalid.error } });
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
const backups = [];
|
|
68
|
+
for (const configuration of configurations) {
|
|
69
|
+
if (!configuration.servers.some((server) => server.serverName === nudgeServerName))
|
|
70
|
+
continue;
|
|
71
|
+
const backup = `${configuration.configPath}.nudge-backup-${randomUUID()}`;
|
|
72
|
+
copyFileSync(configuration.configPath, backup);
|
|
73
|
+
backups.push(backup);
|
|
74
|
+
}
|
|
75
|
+
const result = upsertServer(agentType, nudgeServerName, plan.serverConfig, { local: false, cwd: plan.projectRoot });
|
|
76
|
+
const removal = result.success && agents[agentType].localConfigPath
|
|
77
|
+
? removeServer(agentType, nudgeServerName, { local: true, cwd: plan.projectRoot })
|
|
78
|
+
: undefined;
|
|
79
|
+
outcomes.push({
|
|
80
|
+
agent, displayName: agents[agentType].displayName, result, unsupported: false, backups,
|
|
81
|
+
...(removal && !removal.success ? { migrationError: removal.error ?? "Could not remove the project override." } : {}),
|
|
57
82
|
});
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
displayName: agents[agentType].displayName,
|
|
61
|
-
result,
|
|
62
|
-
unsupported: false,
|
|
63
|
-
};
|
|
64
|
-
});
|
|
83
|
+
}
|
|
84
|
+
return outcomes;
|
|
65
85
|
}
|
|
66
86
|
/** Formats a complete stdio entry for agents that add-mcp cannot configure. */
|
|
67
87
|
export function manualAgentConfiguration(plan) {
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
2
|
+
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
|
|
3
|
+
/** Verifies the configured executable, initialization, and tools without claiming a project. */
|
|
4
|
+
export async function verifyAgentServer(config) {
|
|
5
|
+
if (!config.command)
|
|
6
|
+
throw new Error("The MCP adapter has no executable.");
|
|
7
|
+
const client = new Client({ name: "nudge-setup", version: "1.0.0" });
|
|
8
|
+
const transport = new StdioClientTransport({ command: config.command, args: config.args, stderr: "inherit" });
|
|
9
|
+
try {
|
|
10
|
+
await client.connect(transport, { timeout: 15_000 });
|
|
11
|
+
const { tools } = await client.listTools({}, { timeout: 15_000 });
|
|
12
|
+
const listen = tools.find((tool) => tool.name === "nudge_listen");
|
|
13
|
+
if (!listen?.inputSchema.required?.includes("workspaceRoot") || !tools.some((tool) => tool.name === "nudge_list_sessions")) {
|
|
14
|
+
throw new Error("The installed adapter does not support connection-time project selection. Upgrade @nudge-ui/mcp.");
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
finally {
|
|
18
|
+
await transport.close();
|
|
19
|
+
await client.close();
|
|
20
|
+
}
|
|
21
|
+
}
|
package/dist/arguments.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ export interface CliOptions {
|
|
|
4
4
|
readonly packageManager?: PackageManager;
|
|
5
5
|
readonly agentOnly: boolean;
|
|
6
6
|
readonly agents: readonly string[];
|
|
7
|
+
readonly mcpPackageSpecifier?: string;
|
|
7
8
|
readonly mcp?: boolean;
|
|
8
9
|
readonly yes: boolean;
|
|
9
10
|
readonly dryRun: boolean;
|
|
@@ -11,4 +12,4 @@ export interface CliOptions {
|
|
|
11
12
|
}
|
|
12
13
|
/** Parses the initializer command line. */
|
|
13
14
|
export declare function parseArguments(args: readonly string[]): CliOptions;
|
|
14
|
-
export declare const helpText = "Set up Nudge UI in the current project.\n\nUsage: npm create nudge-ui@latest -- [options]\n\nOptions:\n --framework <nextjs|astro|vite-react|standalone>\n --package-manager <pnpm|npm|yarn|bun>\n --mcp Configure the
|
|
15
|
+
export declare const helpText = "Set up Nudge UI in the current project.\n\nUsage: npm create nudge-ui@latest -- [options]\n\nOptions:\n --framework <nextjs|astro|vite-react|standalone>\n --package-manager <pnpm|npm|yarn|bun>\n --mcp Configure the reusable Nudge MCP adapter\n --no-mcp Skip coding-agent setup\n --agent <id> Configure a supported agent (repeatable)\n --mcp-package <path|package> Use this MCP package for the project and adapter\n --agent-only Install or repair only the agent integration\n -y, --yes Accept defaults without prompting\n --dry-run\n -h, --help";
|
package/dist/arguments.js
CHANGED
|
@@ -5,6 +5,7 @@ export function parseArguments(args) {
|
|
|
5
5
|
let packageManager;
|
|
6
6
|
let agentOnly = false;
|
|
7
7
|
const agents = [];
|
|
8
|
+
let mcpPackageSpecifier;
|
|
8
9
|
let mcp;
|
|
9
10
|
let yes = false;
|
|
10
11
|
let dryRun = false;
|
|
@@ -32,6 +33,10 @@ export function parseArguments(args) {
|
|
|
32
33
|
agents.push(requiredValue(args, ++index, argument));
|
|
33
34
|
else if (argument.startsWith("--agent="))
|
|
34
35
|
agents.push(requiredValue([argument.slice("--agent=".length)], 0, "--agent"));
|
|
36
|
+
else if (argument === "--mcp-package")
|
|
37
|
+
mcpPackageSpecifier = requiredValue(args, ++index, argument);
|
|
38
|
+
else if (argument.startsWith("--mcp-package="))
|
|
39
|
+
mcpPackageSpecifier = requiredValue([argument.slice("--mcp-package=".length)], 0, "--mcp-package");
|
|
35
40
|
else if (argument === "--help" || argument === "-h")
|
|
36
41
|
help = true;
|
|
37
42
|
else if (argument === "--framework")
|
|
@@ -51,7 +56,7 @@ export function parseArguments(args) {
|
|
|
51
56
|
throw new Error("--agent cannot be combined with --no-mcp.");
|
|
52
57
|
if (agentOnly && mcp === false)
|
|
53
58
|
throw new Error("--agent-only cannot be combined with --no-mcp.");
|
|
54
|
-
return { framework, packageManager, agentOnly, agents, mcp, yes, dryRun, help };
|
|
59
|
+
return { framework, packageManager, agentOnly, agents, mcpPackageSpecifier, mcp, yes, dryRun, help };
|
|
55
60
|
}
|
|
56
61
|
function setMcpPreference(current, next) {
|
|
57
62
|
if (current !== undefined && current !== next)
|
|
@@ -71,9 +76,10 @@ Usage: npm create nudge-ui@latest -- [options]
|
|
|
71
76
|
Options:
|
|
72
77
|
--framework <nextjs|astro|vite-react|standalone>
|
|
73
78
|
--package-manager <pnpm|npm|yarn|bun>
|
|
74
|
-
--mcp Configure the
|
|
79
|
+
--mcp Configure the reusable Nudge MCP adapter
|
|
75
80
|
--no-mcp Skip coding-agent setup
|
|
76
81
|
--agent <id> Configure a supported agent (repeatable)
|
|
82
|
+
--mcp-package <path|package> Use this MCP package for the project and adapter
|
|
77
83
|
--agent-only Install or repair only the agent integration
|
|
78
84
|
-y, --yes Accept defaults without prompting
|
|
79
85
|
--dry-run
|
package/dist/cli.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { type PackageManager } from "./types.js";
|
|
2
2
|
export interface RunAgentSetupOptions {
|
|
3
3
|
readonly agents?: readonly string[];
|
|
4
|
+
/** Optional package specifier or tarball used for both bridge and adapter testing. */
|
|
5
|
+
readonly mcpPackageSpecifier?: string;
|
|
4
6
|
readonly dryRun?: boolean;
|
|
5
7
|
readonly nudgeUiVersion?: string;
|
|
6
8
|
readonly packageManager?: PackageManager;
|
|
@@ -8,5 +10,5 @@ export interface RunAgentSetupOptions {
|
|
|
8
10
|
}
|
|
9
11
|
/** Runs the Nudge UI project initializer. */
|
|
10
12
|
export declare function runCli(args?: string[], projectRoot?: string): Promise<void>;
|
|
11
|
-
/** Installs and configures the
|
|
13
|
+
/** Installs and configures the reusable MCP adapter and project bridge dependency. Safe to rerun for repairs. */
|
|
12
14
|
export declare function runAgentSetup(projectRoot?: string, options?: RunAgentSetupOptions): Promise<void>;
|
package/dist/cli.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { rmSync, writeFileSync } from "node:fs";
|
|
1
|
+
import { mkdirSync, rmSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { verifyAgentServer } from "./agent-verification.js";
|
|
2
3
|
import { createInterface } from "node:readline/promises";
|
|
3
4
|
import { stdin, stdout } from "node:process";
|
|
4
5
|
import { basename, relative } from "node:path";
|
|
@@ -20,6 +21,7 @@ export async function runCli(args = process.argv.slice(2), projectRoot = process
|
|
|
20
21
|
if (options.agentOnly) {
|
|
21
22
|
await runAgentSetup(projectRoot, {
|
|
22
23
|
agents: options.agents,
|
|
24
|
+
mcpPackageSpecifier: options.mcpPackageSpecifier,
|
|
23
25
|
dryRun: options.dryRun,
|
|
24
26
|
packageManager,
|
|
25
27
|
yes: options.yes,
|
|
@@ -44,6 +46,7 @@ export async function runCli(args = process.argv.slice(2), projectRoot = process
|
|
|
44
46
|
if (await shouldConfigureAgent(options.mcp, options.agents.length > 0, options.yes)) {
|
|
45
47
|
await runAgentSetup(projectRoot, {
|
|
46
48
|
agents: options.agents,
|
|
49
|
+
mcpPackageSpecifier: options.mcpPackageSpecifier,
|
|
47
50
|
dryRun: true,
|
|
48
51
|
nudgeUiVersion: initializerVersion(),
|
|
49
52
|
packageManager,
|
|
@@ -73,17 +76,18 @@ export async function runCli(args = process.argv.slice(2), projectRoot = process
|
|
|
73
76
|
if (await shouldConfigureAgent(options.mcp, options.agents.length > 0, options.yes)) {
|
|
74
77
|
await runAgentSetup(projectRoot, {
|
|
75
78
|
agents: options.agents,
|
|
79
|
+
mcpPackageSpecifier: options.mcpPackageSpecifier,
|
|
76
80
|
nudgeUiVersion: initializerVersion(),
|
|
77
81
|
packageManager,
|
|
78
82
|
yes: options.yes,
|
|
79
83
|
});
|
|
80
84
|
}
|
|
81
85
|
}
|
|
82
|
-
/** Installs and configures the
|
|
86
|
+
/** Installs and configures the reusable MCP adapter and project bridge dependency. Safe to rerun for repairs. */
|
|
83
87
|
export async function runAgentSetup(projectRoot = process.cwd(), options = {}) {
|
|
84
88
|
const manifest = readProjectManifest(projectRoot);
|
|
85
89
|
const packageManager = options.packageManager ?? detectPackageManager(projectRoot, manifest);
|
|
86
|
-
const plan = planAgentSetup(projectRoot, packageManager, options.nudgeUiVersion);
|
|
90
|
+
const plan = planAgentSetup(projectRoot, packageManager, options.nudgeUiVersion, undefined, options.mcpPackageSpecifier);
|
|
87
91
|
const detected = await detectProjectAgentCandidates(plan.projectRoot);
|
|
88
92
|
const selected = options.agents && options.agents.length > 0
|
|
89
93
|
? options.agents
|
|
@@ -92,8 +96,9 @@ export async function runAgentSetup(projectRoot = process.cwd(), options = {}) {
|
|
|
92
96
|
: await selectAgents(detected);
|
|
93
97
|
if (options.dryRun) {
|
|
94
98
|
stdout.write(`Would run: ${formatCommand(plan.installCommand)}\n`);
|
|
99
|
+
stdout.write(`Would run: ${formatCommand(plan.adapterInstallCommand)}\n`);
|
|
95
100
|
if (selected.length > 0) {
|
|
96
|
-
stdout.write(`Would configure
|
|
101
|
+
stdout.write(`Would configure global MCP and migrate this project override for: ${selected.join(", ")}\n`);
|
|
97
102
|
}
|
|
98
103
|
else {
|
|
99
104
|
stdout.write("No coding agent was detected. Use --agent <id> or add the configuration below manually.\n");
|
|
@@ -102,11 +107,33 @@ export async function runAgentSetup(projectRoot = process.cwd(), options = {}) {
|
|
|
102
107
|
return;
|
|
103
108
|
}
|
|
104
109
|
installPackage(plan.installCommand, plan.projectRoot);
|
|
110
|
+
try {
|
|
111
|
+
mkdirSync(plan.adapterRoot, { recursive: true });
|
|
112
|
+
installPackage(plan.adapterInstallCommand, plan.adapterRoot);
|
|
113
|
+
}
|
|
114
|
+
catch (error) {
|
|
115
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
116
|
+
stdout.write(`Could not install the reusable MCP adapter: ${message}\n`);
|
|
117
|
+
stdout.write(`Retry with: ${formatCommand(plan.adapterInstallCommand)}\n`);
|
|
118
|
+
stdout.write("The coding-agent configuration was not changed. After the adapter install succeeds, rerun with --agent-only.\n");
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
105
121
|
if (!isAgentServerAvailable(plan)) {
|
|
106
|
-
stdout.write(`Installed ${plan.packageSpecifier}, but its
|
|
122
|
+
stdout.write(`Installed ${plan.packageSpecifier}, but its reusable MCP executable was not found at ${plan.serverEntry}.\n`);
|
|
123
|
+
stdout.write(`Retry with: ${formatCommand(plan.adapterInstallCommand)}\n`);
|
|
107
124
|
stdout.write("The coding-agent configuration was not changed. Check the package-manager install output, then rerun with --agent-only.\n");
|
|
108
125
|
return;
|
|
109
126
|
}
|
|
127
|
+
try {
|
|
128
|
+
await verifyAgentServer(plan.serverConfig);
|
|
129
|
+
stdout.write("Verified MCP initialization and tool discovery with a fresh client.\n");
|
|
130
|
+
}
|
|
131
|
+
catch (error) {
|
|
132
|
+
stdout.write(`MCP verification failed: ${error instanceof Error ? error.message : String(error)}\n`);
|
|
133
|
+
stdout.write(`Retry with: ${formatCommand(plan.adapterInstallCommand)}\n`);
|
|
134
|
+
stdout.write("The coding-agent configuration was not changed. After repairing the adapter install, rerun with --agent-only.\n");
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
110
137
|
if (selected.length === 0) {
|
|
111
138
|
stdout.write(`Installed ${plan.packageSpecifier}, but no coding agent was detected.\n`);
|
|
112
139
|
writeManualInstructions(plan);
|
|
@@ -114,7 +141,7 @@ export async function runAgentSetup(projectRoot = process.cwd(), options = {}) {
|
|
|
114
141
|
}
|
|
115
142
|
let outcomes;
|
|
116
143
|
try {
|
|
117
|
-
outcomes = configureProjectAgents(plan, selected);
|
|
144
|
+
outcomes = await configureProjectAgents(plan, selected);
|
|
118
145
|
}
|
|
119
146
|
catch (error) {
|
|
120
147
|
const message = error instanceof Error ? error.message : String(error);
|
|
@@ -125,7 +152,13 @@ export async function runAgentSetup(projectRoot = process.cwd(), options = {}) {
|
|
|
125
152
|
let configured = 0;
|
|
126
153
|
for (const outcome of outcomes) {
|
|
127
154
|
if (outcome.unsupported) {
|
|
128
|
-
stdout.write(`${outcome.displayName} is not supported for automatic
|
|
155
|
+
stdout.write(`${outcome.displayName} is not supported for automatic global setup.\n`);
|
|
156
|
+
continue;
|
|
157
|
+
}
|
|
158
|
+
for (const backup of outcome.backups ?? [])
|
|
159
|
+
stdout.write(`Saved previous MCP configuration: ${backup}\n`);
|
|
160
|
+
if (outcome.migrationError) {
|
|
161
|
+
stdout.write(`Global adapter configured, but project override migration failed: ${outcome.migrationError}\n`);
|
|
129
162
|
continue;
|
|
130
163
|
}
|
|
131
164
|
if (outcome.result?.success) {
|
|
@@ -138,7 +171,7 @@ export async function runAgentSetup(projectRoot = process.cwd(), options = {}) {
|
|
|
138
171
|
if (configured !== outcomes.length)
|
|
139
172
|
writeManualInstructions(plan);
|
|
140
173
|
if (configured > 0) {
|
|
141
|
-
stdout.write("
|
|
174
|
+
stdout.write("Adapter configuration is ready. Fully restart the agent host to load it, then ask it to listen to Nudge in the current workspace. Existing overrides in other projects require one setup rerun there.\n");
|
|
142
175
|
}
|
|
143
176
|
}
|
|
144
177
|
async function shouldConfigureAgent(preference, hasExplicitAgents, yes) {
|
|
@@ -189,7 +222,7 @@ async function selectAgents(detected) {
|
|
|
189
222
|
}
|
|
190
223
|
}
|
|
191
224
|
function writeManualInstructions(plan) {
|
|
192
|
-
stdout.write("Add this
|
|
225
|
+
stdout.write("Add this global stdio server to your agent's MCP settings:\n");
|
|
193
226
|
stdout.write(`${manualAgentConfiguration(plan)}\n`);
|
|
194
227
|
}
|
|
195
228
|
async function selectFramework(detected) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-nudge-ui",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.3",
|
|
4
4
|
"description": "Framework-detecting installer for Nudge UI.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -30,7 +30,8 @@
|
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
32
|
"add-mcp": "^2.4.0",
|
|
33
|
-
"typescript": "^5.9.3"
|
|
33
|
+
"typescript": "^5.9.3",
|
|
34
|
+
"@modelcontextprotocol/sdk": "^1.30.0"
|
|
34
35
|
},
|
|
35
36
|
"devDependencies": {
|
|
36
37
|
"vitest": "^2.1.9"
|