create-nudge-ui 0.2.1 → 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/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  `create-nudge-ui` detects an application's host framework, installs the
4
4
  corresponding Nudge UI adapter, and updates the host configuration. The guided
5
- setup can also connect a coding agent to the project-local Nudge MCP server.
5
+ setup can also connect a coding agent to Nudge.
6
6
 
7
7
  Run the initializer from the application root:
8
8
 
@@ -16,12 +16,13 @@ with React islands receives `nudge-ui/astro`, not `nudge-ui/vite`.
16
16
 
17
17
  In an interactive terminal, the initializer asks whether to connect a coding
18
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.
19
+ version in the project, and installs a versioned reusable adapter under
20
+ `~/.nudge-ui/adapters/`. The adapter is independent of the application and
21
+ does not contain a project path, so different Git worktrees can use the same
22
+ global MCP registration. Existing project-scoped Nudge entries are backed up
23
+ and removed when the host supports that migration.
23
24
 
24
- Reload an agent that was already running, then ask it to “listen to Nudge.”
25
+ Fully restart the agent host, then ask it to “listen to Nudge.”
25
26
 
26
27
  Use an explicit framework when automatic detection is ambiguous:
27
28
 
@@ -53,6 +54,13 @@ framework configuration:
53
54
  npm create nudge-ui@latest -- --agent-only --agent codex --yes
54
55
  ```
55
56
 
57
+ For local MCP package testing, pass a tarball with `--mcp-package`. Setup uses
58
+ that artifact for both the project bridge and reusable adapter:
59
+
60
+ ```sh
61
+ npx nudge-ui agent setup --mcp-package /absolute/path/to/nudge-ui-mcp.tgz
62
+ ```
63
+
56
64
  Agent configuration is best-effort. If an agent is not supported or its native
57
65
  configuration cannot be updated, the initializer prints the complete stdio
58
66
  configuration to add to that agent's project settings. Other MCP servers and
@@ -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?: string;
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
- /** Builds the reproducible, project-local MCP installation and launch plan. */
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 can store an MCP configuration in this project. */
26
+ /** Returns agents that support a reusable stdio MCP configuration. */
23
27
  export declare function projectAgentTypes(): AgentType[];
24
- /** Detects installed or already configured agents while preserving project scope. */
28
+ /** Detects installed or already configured agents. */
25
29
  export declare function detectProjectAgentCandidates(projectRoot: string): Promise<AgentType[]>;
26
- /** Adds or repairs Nudge's project-scoped MCP entry without replacing other servers. */
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<{
@@ -1,40 +1,40 @@
1
- import { existsSync, readFileSync, realpathSync } from "node:fs";
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
- /** Builds the reproducible, project-local MCP installation and launch plan. */
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 serverEntry = join(canonicalRoot, "node_modules", "@nudge-ui", "mcp", "dist", "cli.mjs");
11
- const usesPlugAndPlay = packageManager === "yarn";
12
- const serverConfig = usesPlugAndPlay
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
- serverEntry: usesPlugAndPlay ? undefined : serverEntry,
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 plan.serverEntry === undefined || existsSync(plan.serverEntry);
31
+ return existsSync(plan.serverEntry);
32
32
  }
33
- /** Returns agents that can store an MCP configuration in this project. */
33
+ /** Returns agents that support a reusable stdio MCP configuration. */
34
34
  export function projectAgentTypes() {
35
- return getAgentTypes().filter((agent) => agents[agent].localConfigPath !== undefined);
35
+ return getAgentTypes().filter((agent) => agents[agent].supportedTransports.includes("stdio"));
36
36
  }
37
- /** Detects installed or already configured agents while preserving project scope. */
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
- /** Adds or repairs Nudge's project-scoped MCP entry without replacing other servers. */
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
- return [...new Set(selectedAgents)].map((agent) => {
49
+ const outcomes = [];
50
+ for (const agent of new Set(selectedAgents)) {
50
51
  if (!supported.has(agent)) {
51
- return { agent, displayName: agent, unsupported: true };
52
+ outcomes.push({ agent, displayName: agent, unsupported: true });
53
+ continue;
52
54
  }
53
55
  const agentType = agent;
54
- const result = upsertServer(agentType, nudgeServerName, plan.serverConfig, {
55
- cwd: plan.projectRoot,
56
- local: true,
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
- return {
59
- agent,
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,3 @@
1
+ import type { McpServerConfig } from "add-mcp";
2
+ /** Verifies the configured executable, initialization, and tools without claiming a project. */
3
+ export declare function verifyAgentServer(config: McpServerConfig): Promise<void>;
@@ -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
+ }
@@ -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 local Nudge MCP server\n --no-mcp Skip coding-agent setup\n --agent <id> Configure a supported agent (repeatable)\n --agent-only Install or repair only the agent integration\n -y, --yes Accept defaults without prompting\n --dry-run\n -h, --help";
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 local Nudge MCP server
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 project-local MCP companion. Safe to rerun for repairs. */
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 project-local MCP companion. Safe to rerun for repairs. */
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 project MCP for: ${selected.join(", ")}\n`);
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 local MCP executable was not found at ${plan.serverEntry}.\n`);
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 project setup.\n`);
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("Coding-agent setup is ready. Reload the agent if it is already open, then ask it to listen to Nudge.\n");
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 project-scoped stdio server to your agent's MCP settings:\n");
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.1",
3
+ "version": "0.2.2",
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"