create-nudge-ui 0.1.3 → 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 +37 -2
- package/dist/agent-setup.d.ts +35 -0
- package/dist/agent-setup.js +104 -0
- package/dist/arguments.d.ts +5 -1
- package/dist/arguments.js +36 -1
- package/dist/cli.d.ts +10 -0
- package/dist/cli.js +147 -6
- package/dist/configuration.js +80 -87
- package/dist/detection.d.ts +0 -1
- package/dist/detection.js +1 -10
- package/dist/index.d.ts +3 -1
- package/dist/index.js +3 -1
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
# `create-nudge-ui`
|
|
2
2
|
|
|
3
3
|
`create-nudge-ui` detects an application's host framework, installs the
|
|
4
|
-
corresponding Nudge UI adapter, and updates the host configuration.
|
|
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
6
|
|
|
6
7
|
Run the initializer from the application root:
|
|
7
8
|
|
|
@@ -11,7 +12,16 @@ npm create nudge-ui@latest
|
|
|
11
12
|
|
|
12
13
|
The initializer supports Next.js, Astro, Vite with React, and static HTML. Host
|
|
13
14
|
frameworks take precedence over their underlying tools, so an Astro project
|
|
14
|
-
with React islands receives
|
|
15
|
+
with React islands receives `nudge-ui/astro`, not `nudge-ui/vite`.
|
|
16
|
+
|
|
17
|
+
In an interactive terminal, the initializer asks whether to connect a coding
|
|
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.
|
|
23
|
+
|
|
24
|
+
Reload an agent that was already running, then ask it to “listen to Nudge.”
|
|
15
25
|
|
|
16
26
|
Use an explicit framework when automatic detection is ambiguous:
|
|
17
27
|
|
|
@@ -22,3 +32,28 @@ npm create nudge-ui@latest -- --framework astro
|
|
|
22
32
|
Use `--dry-run` to print the package installation and configuration change
|
|
23
33
|
without modifying the project. Run `npm create nudge-ui@latest -- --help` for
|
|
24
34
|
the complete command reference.
|
|
35
|
+
|
|
36
|
+
For scripts, select the MCP behavior explicitly:
|
|
37
|
+
|
|
38
|
+
```sh
|
|
39
|
+
# Configure detected agents without prompts.
|
|
40
|
+
npm create nudge-ui@latest -- --mcp --yes
|
|
41
|
+
|
|
42
|
+
# Configure one or more supported add-mcp agent IDs.
|
|
43
|
+
npm create nudge-ui@latest -- --mcp --agent codex --agent cursor --yes
|
|
44
|
+
|
|
45
|
+
# Skip agent setup.
|
|
46
|
+
npm create nudge-ui@latest -- --no-mcp
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Use agent-only mode to add or repair the integration without changing the host
|
|
50
|
+
framework configuration:
|
|
51
|
+
|
|
52
|
+
```sh
|
|
53
|
+
npm create nudge-ui@latest -- --agent-only --agent codex --yes
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Agent configuration is best-effort. If an agent is not supported or its native
|
|
57
|
+
configuration cannot be updated, the initializer prints the complete stdio
|
|
58
|
+
configuration to add to that agent's project settings. Other MCP servers and
|
|
59
|
+
agent settings are preserved on every run.
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { type AgentType, type InstallResult, type McpServerConfig } from "add-mcp";
|
|
2
|
+
import { type InstallCommand } from "./installer.js";
|
|
3
|
+
import type { PackageManager } from "./types.js";
|
|
4
|
+
export declare const nudgeServerName = "nudge_ui";
|
|
5
|
+
export interface AgentSetupPlan {
|
|
6
|
+
readonly projectRoot: string;
|
|
7
|
+
readonly packageSpecifier: string;
|
|
8
|
+
readonly installCommand: InstallCommand;
|
|
9
|
+
readonly serverConfig: McpServerConfig;
|
|
10
|
+
readonly serverEntry?: string;
|
|
11
|
+
}
|
|
12
|
+
export interface AgentInstallOutcome {
|
|
13
|
+
readonly agent: string;
|
|
14
|
+
readonly displayName: string;
|
|
15
|
+
readonly result?: InstallResult;
|
|
16
|
+
readonly unsupported: boolean;
|
|
17
|
+
}
|
|
18
|
+
/** Builds the reproducible, project-local MCP installation and launch plan. */
|
|
19
|
+
export declare function planAgentSetup(projectRoot: string, packageManager: PackageManager, nudgeUiVersion?: string): AgentSetupPlan;
|
|
20
|
+
/** Checks that a node_modules based install produced the configured executable. */
|
|
21
|
+
export declare function isAgentServerAvailable(plan: AgentSetupPlan): boolean;
|
|
22
|
+
/** Returns agents that can store an MCP configuration in this project. */
|
|
23
|
+
export declare function projectAgentTypes(): AgentType[];
|
|
24
|
+
/** Detects installed or already configured agents while preserving project scope. */
|
|
25
|
+
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[];
|
|
28
|
+
/** Formats a complete stdio entry for agents that add-mcp cannot configure. */
|
|
29
|
+
export declare function manualAgentConfiguration(plan: AgentSetupPlan): string;
|
|
30
|
+
export declare function projectAgentChoices(detected: readonly AgentType[]): Array<{
|
|
31
|
+
readonly id: AgentType;
|
|
32
|
+
readonly label: string;
|
|
33
|
+
readonly detected: boolean;
|
|
34
|
+
}>;
|
|
35
|
+
export declare function initializerVersion(): string;
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { existsSync, readFileSync, realpathSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { agents, detectGlobalAgents, detectProjectAgents, getAgentTypes, upsertServer, } from "add-mcp";
|
|
4
|
+
import { installCommand } from "./installer.js";
|
|
5
|
+
export const nudgeServerName = "nudge_ui";
|
|
6
|
+
/** Builds the reproducible, project-local MCP installation and launch plan. */
|
|
7
|
+
export function planAgentSetup(projectRoot, packageManager, nudgeUiVersion) {
|
|
8
|
+
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
|
+
};
|
|
21
|
+
return {
|
|
22
|
+
projectRoot: canonicalRoot,
|
|
23
|
+
packageSpecifier,
|
|
24
|
+
installCommand: installCommand(packageManager, packageSpecifier),
|
|
25
|
+
serverConfig,
|
|
26
|
+
serverEntry: usesPlugAndPlay ? undefined : serverEntry,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
/** Checks that a node_modules based install produced the configured executable. */
|
|
30
|
+
export function isAgentServerAvailable(plan) {
|
|
31
|
+
return plan.serverEntry === undefined || existsSync(plan.serverEntry);
|
|
32
|
+
}
|
|
33
|
+
/** Returns agents that can store an MCP configuration in this project. */
|
|
34
|
+
export function projectAgentTypes() {
|
|
35
|
+
return getAgentTypes().filter((agent) => agents[agent].localConfigPath !== undefined);
|
|
36
|
+
}
|
|
37
|
+
/** Detects installed or already configured agents while preserving project scope. */
|
|
38
|
+
export async function detectProjectAgentCandidates(projectRoot) {
|
|
39
|
+
const supported = new Set(projectAgentTypes());
|
|
40
|
+
const detected = [
|
|
41
|
+
...detectProjectAgents(projectRoot),
|
|
42
|
+
...await detectGlobalAgents(),
|
|
43
|
+
].filter((agent) => supported.has(agent));
|
|
44
|
+
return [...new Set(detected)];
|
|
45
|
+
}
|
|
46
|
+
/** Adds or repairs Nudge's project-scoped MCP entry without replacing other servers. */
|
|
47
|
+
export function configureProjectAgents(plan, selectedAgents) {
|
|
48
|
+
const supported = new Set(projectAgentTypes());
|
|
49
|
+
return [...new Set(selectedAgents)].map((agent) => {
|
|
50
|
+
if (!supported.has(agent)) {
|
|
51
|
+
return { agent, displayName: agent, unsupported: true };
|
|
52
|
+
}
|
|
53
|
+
const agentType = agent;
|
|
54
|
+
const result = upsertServer(agentType, nudgeServerName, plan.serverConfig, {
|
|
55
|
+
cwd: plan.projectRoot,
|
|
56
|
+
local: true,
|
|
57
|
+
});
|
|
58
|
+
return {
|
|
59
|
+
agent,
|
|
60
|
+
displayName: agents[agentType].displayName,
|
|
61
|
+
result,
|
|
62
|
+
unsupported: false,
|
|
63
|
+
};
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
/** Formats a complete stdio entry for agents that add-mcp cannot configure. */
|
|
67
|
+
export function manualAgentConfiguration(plan) {
|
|
68
|
+
return JSON.stringify({
|
|
69
|
+
mcpServers: {
|
|
70
|
+
[nudgeServerName]: plan.serverConfig,
|
|
71
|
+
},
|
|
72
|
+
}, null, 2);
|
|
73
|
+
}
|
|
74
|
+
export function projectAgentChoices(detected) {
|
|
75
|
+
const detectedSet = new Set(detected);
|
|
76
|
+
return projectAgentTypes()
|
|
77
|
+
.sort((left, right) => {
|
|
78
|
+
const detectionOrder = Number(detectedSet.has(right)) - Number(detectedSet.has(left));
|
|
79
|
+
return detectionOrder || agents[left].displayName.localeCompare(agents[right].displayName);
|
|
80
|
+
})
|
|
81
|
+
.map((id) => ({ id, label: agents[id].displayName, detected: detectedSet.has(id) }));
|
|
82
|
+
}
|
|
83
|
+
export function initializerVersion() {
|
|
84
|
+
const packageJsonUrl = new URL("../package.json", import.meta.url);
|
|
85
|
+
const value = JSON.parse(readFileSync(packageJsonUrl, "utf8"));
|
|
86
|
+
if (!isPackageMetadata(value))
|
|
87
|
+
throw new TypeError("create-nudge-ui package metadata has no version.");
|
|
88
|
+
return value.version;
|
|
89
|
+
}
|
|
90
|
+
function installedNudgeUiVersion(projectRoot) {
|
|
91
|
+
const manifestPath = join(projectRoot, "node_modules", "nudge-ui", "package.json");
|
|
92
|
+
try {
|
|
93
|
+
const value = JSON.parse(readFileSync(manifestPath, "utf8"));
|
|
94
|
+
return isPackageMetadata(value) ? value.version : undefined;
|
|
95
|
+
}
|
|
96
|
+
catch {
|
|
97
|
+
return undefined;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
function isPackageMetadata(value) {
|
|
101
|
+
if (typeof value !== "object" || value === null || Array.isArray(value))
|
|
102
|
+
return false;
|
|
103
|
+
return typeof value.version === "string";
|
|
104
|
+
}
|
package/dist/arguments.d.ts
CHANGED
|
@@ -2,9 +2,13 @@ import { type Framework, type PackageManager } from "./types.js";
|
|
|
2
2
|
export interface CliOptions {
|
|
3
3
|
readonly framework?: Framework;
|
|
4
4
|
readonly packageManager?: PackageManager;
|
|
5
|
+
readonly agentOnly: boolean;
|
|
6
|
+
readonly agents: readonly string[];
|
|
7
|
+
readonly mcp?: boolean;
|
|
8
|
+
readonly yes: boolean;
|
|
5
9
|
readonly dryRun: boolean;
|
|
6
10
|
readonly help: boolean;
|
|
7
11
|
}
|
|
8
12
|
/** Parses the initializer command line. */
|
|
9
13
|
export declare function parseArguments(args: readonly string[]): CliOptions;
|
|
10
|
-
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 --dry-run\n -h, --help";
|
|
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";
|
package/dist/arguments.js
CHANGED
|
@@ -3,14 +3,35 @@ import { frameworks, packageManagers } from "./types.js";
|
|
|
3
3
|
export function parseArguments(args) {
|
|
4
4
|
let framework;
|
|
5
5
|
let packageManager;
|
|
6
|
+
let agentOnly = false;
|
|
7
|
+
const agents = [];
|
|
8
|
+
let mcp;
|
|
9
|
+
let yes = false;
|
|
6
10
|
let dryRun = false;
|
|
7
11
|
let help = false;
|
|
8
12
|
for (let index = 0; index < args.length; index += 1) {
|
|
9
13
|
const argument = args[index];
|
|
10
14
|
if (argument === "--")
|
|
11
15
|
continue;
|
|
16
|
+
if (index === 0 && argument === "agent" && args[index + 1] === "setup") {
|
|
17
|
+
agentOnly = true;
|
|
18
|
+
index += 1;
|
|
19
|
+
continue;
|
|
20
|
+
}
|
|
12
21
|
if (argument === "--dry-run")
|
|
13
22
|
dryRun = true;
|
|
23
|
+
else if (argument === "--yes" || argument === "-y")
|
|
24
|
+
yes = true;
|
|
25
|
+
else if (argument === "--agent-only")
|
|
26
|
+
agentOnly = true;
|
|
27
|
+
else if (argument === "--mcp")
|
|
28
|
+
mcp = setMcpPreference(mcp, true);
|
|
29
|
+
else if (argument === "--no-mcp")
|
|
30
|
+
mcp = setMcpPreference(mcp, false);
|
|
31
|
+
else if (argument === "--agent")
|
|
32
|
+
agents.push(requiredValue(args, ++index, argument));
|
|
33
|
+
else if (argument.startsWith("--agent="))
|
|
34
|
+
agents.push(requiredValue([argument.slice("--agent=".length)], 0, "--agent"));
|
|
14
35
|
else if (argument === "--help" || argument === "-h")
|
|
15
36
|
help = true;
|
|
16
37
|
else if (argument === "--framework")
|
|
@@ -26,7 +47,16 @@ export function parseArguments(args) {
|
|
|
26
47
|
else
|
|
27
48
|
throw new Error(`Unknown option: ${argument}`);
|
|
28
49
|
}
|
|
29
|
-
|
|
50
|
+
if (agents.length > 0 && mcp === false)
|
|
51
|
+
throw new Error("--agent cannot be combined with --no-mcp.");
|
|
52
|
+
if (agentOnly && mcp === false)
|
|
53
|
+
throw new Error("--agent-only cannot be combined with --no-mcp.");
|
|
54
|
+
return { framework, packageManager, agentOnly, agents, mcp, yes, dryRun, help };
|
|
55
|
+
}
|
|
56
|
+
function setMcpPreference(current, next) {
|
|
57
|
+
if (current !== undefined && current !== next)
|
|
58
|
+
throw new Error("--mcp and --no-mcp cannot be combined.");
|
|
59
|
+
return next;
|
|
30
60
|
}
|
|
31
61
|
function requiredValue(args, index, option) {
|
|
32
62
|
const value = args[index];
|
|
@@ -41,6 +71,11 @@ Usage: npm create nudge-ui@latest -- [options]
|
|
|
41
71
|
Options:
|
|
42
72
|
--framework <nextjs|astro|vite-react|standalone>
|
|
43
73
|
--package-manager <pnpm|npm|yarn|bun>
|
|
74
|
+
--mcp Configure the local Nudge MCP server
|
|
75
|
+
--no-mcp Skip coding-agent setup
|
|
76
|
+
--agent <id> Configure a supported agent (repeatable)
|
|
77
|
+
--agent-only Install or repair only the agent integration
|
|
78
|
+
-y, --yes Accept defaults without prompting
|
|
44
79
|
--dry-run
|
|
45
80
|
-h, --help`;
|
|
46
81
|
function parseFramework(value) {
|
package/dist/cli.d.ts
CHANGED
|
@@ -1,2 +1,12 @@
|
|
|
1
|
+
import { type PackageManager } from "./types.js";
|
|
2
|
+
export interface RunAgentSetupOptions {
|
|
3
|
+
readonly agents?: readonly string[];
|
|
4
|
+
readonly dryRun?: boolean;
|
|
5
|
+
readonly nudgeUiVersion?: string;
|
|
6
|
+
readonly packageManager?: PackageManager;
|
|
7
|
+
readonly yes?: boolean;
|
|
8
|
+
}
|
|
1
9
|
/** Runs the Nudge UI project initializer. */
|
|
2
10
|
export declare function runCli(args?: string[], projectRoot?: string): Promise<void>;
|
|
11
|
+
/** Installs and configures the project-local MCP companion. Safe to rerun for repairs. */
|
|
12
|
+
export declare function runAgentSetup(projectRoot?: string, options?: RunAgentSetupOptions): Promise<void>;
|
package/dist/cli.js
CHANGED
|
@@ -2,11 +2,12 @@ import { rmSync, writeFileSync } from "node:fs";
|
|
|
2
2
|
import { createInterface } from "node:readline/promises";
|
|
3
3
|
import { stdin, stdout } from "node:process";
|
|
4
4
|
import { basename, relative } from "node:path";
|
|
5
|
+
import { configureProjectAgents, detectProjectAgentCandidates, initializerVersion, isAgentServerAvailable, manualAgentConfiguration, planAgentSetup, projectAgentChoices, } from "./agent-setup.js";
|
|
5
6
|
import { parseArguments, helpText } from "./arguments.js";
|
|
6
7
|
import { planConfiguration } from "./configuration.js";
|
|
7
|
-
import {
|
|
8
|
+
import { detectFrameworks, detectPackageManager, detectStaticRoot, frameworkDisplayName, readProjectManifest, } from "./detection.js";
|
|
8
9
|
import { formatCommand, installCommand, installPackage } from "./installer.js";
|
|
9
|
-
import { frameworks } from "./types.js";
|
|
10
|
+
import { frameworks, } from "./types.js";
|
|
10
11
|
/** Runs the Nudge UI project initializer. */
|
|
11
12
|
export async function runCli(args = process.argv.slice(2), projectRoot = process.cwd()) {
|
|
12
13
|
const options = parseArguments(args);
|
|
@@ -15,11 +16,21 @@ export async function runCli(args = process.argv.slice(2), projectRoot = process
|
|
|
15
16
|
return;
|
|
16
17
|
}
|
|
17
18
|
const manifest = readProjectManifest(projectRoot);
|
|
19
|
+
const packageManager = options.packageManager ?? detectPackageManager(projectRoot, manifest);
|
|
20
|
+
if (options.agentOnly) {
|
|
21
|
+
await runAgentSetup(projectRoot, {
|
|
22
|
+
agents: options.agents,
|
|
23
|
+
dryRun: options.dryRun,
|
|
24
|
+
packageManager,
|
|
25
|
+
yes: options.yes,
|
|
26
|
+
});
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
18
29
|
const detected = detectFrameworks(projectRoot, manifest);
|
|
19
30
|
const framework = options.framework ?? await selectFramework(detected);
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
const command = installCommand(packageManager,
|
|
31
|
+
// One package serves every host; the framework only decides which
|
|
32
|
+
// subpath the generated configuration imports.
|
|
33
|
+
const command = installCommand(packageManager, `nudge-ui@${initializerVersion()}`);
|
|
23
34
|
const change = planConfiguration(projectRoot, framework);
|
|
24
35
|
const staticRoot = framework === "standalone" ? detectStaticRoot(projectRoot) : undefined;
|
|
25
36
|
const serveDirectory = staticRoot ? relative(projectRoot, staticRoot) || "." : ".";
|
|
@@ -30,6 +41,15 @@ export async function runCli(args = process.argv.slice(2), projectRoot = process
|
|
|
30
41
|
stdout.write(`Would ${change.created ? "create" : "update"}: ${change.path}\n`);
|
|
31
42
|
if (framework === "standalone")
|
|
32
43
|
stdout.write(`After installation, run: nudge-ui serve ${serveDirectory}\n`);
|
|
44
|
+
if (await shouldConfigureAgent(options.mcp, options.agents.length > 0, options.yes)) {
|
|
45
|
+
await runAgentSetup(projectRoot, {
|
|
46
|
+
agents: options.agents,
|
|
47
|
+
dryRun: true,
|
|
48
|
+
nudgeUiVersion: initializerVersion(),
|
|
49
|
+
packageManager,
|
|
50
|
+
yes: options.yes,
|
|
51
|
+
});
|
|
52
|
+
}
|
|
33
53
|
return;
|
|
34
54
|
}
|
|
35
55
|
if (change) {
|
|
@@ -49,7 +69,128 @@ export async function runCli(args = process.argv.slice(2), projectRoot = process
|
|
|
49
69
|
if (framework === "standalone") {
|
|
50
70
|
stdout.write(`Run \`nudge-ui serve ${serveDirectory}\` to start the instrumented development server.\n`);
|
|
51
71
|
}
|
|
52
|
-
stdout.write(`Nudge UI is configured
|
|
72
|
+
stdout.write(`Nudge UI is configured for ${frameworkDisplayName(framework)}.\n`);
|
|
73
|
+
if (await shouldConfigureAgent(options.mcp, options.agents.length > 0, options.yes)) {
|
|
74
|
+
await runAgentSetup(projectRoot, {
|
|
75
|
+
agents: options.agents,
|
|
76
|
+
nudgeUiVersion: initializerVersion(),
|
|
77
|
+
packageManager,
|
|
78
|
+
yes: options.yes,
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
/** Installs and configures the project-local MCP companion. Safe to rerun for repairs. */
|
|
83
|
+
export async function runAgentSetup(projectRoot = process.cwd(), options = {}) {
|
|
84
|
+
const manifest = readProjectManifest(projectRoot);
|
|
85
|
+
const packageManager = options.packageManager ?? detectPackageManager(projectRoot, manifest);
|
|
86
|
+
const plan = planAgentSetup(projectRoot, packageManager, options.nudgeUiVersion);
|
|
87
|
+
const detected = await detectProjectAgentCandidates(plan.projectRoot);
|
|
88
|
+
const selected = options.agents && options.agents.length > 0
|
|
89
|
+
? options.agents
|
|
90
|
+
: options.yes || !stdin.isTTY || !stdout.isTTY
|
|
91
|
+
? detected
|
|
92
|
+
: await selectAgents(detected);
|
|
93
|
+
if (options.dryRun) {
|
|
94
|
+
stdout.write(`Would run: ${formatCommand(plan.installCommand)}\n`);
|
|
95
|
+
if (selected.length > 0) {
|
|
96
|
+
stdout.write(`Would configure project MCP for: ${selected.join(", ")}\n`);
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
stdout.write("No coding agent was detected. Use --agent <id> or add the configuration below manually.\n");
|
|
100
|
+
writeManualInstructions(plan);
|
|
101
|
+
}
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
installPackage(plan.installCommand, plan.projectRoot);
|
|
105
|
+
if (!isAgentServerAvailable(plan)) {
|
|
106
|
+
stdout.write(`Installed ${plan.packageSpecifier}, but its local MCP executable was not found at ${plan.serverEntry}.\n`);
|
|
107
|
+
stdout.write("The coding-agent configuration was not changed. Check the package-manager install output, then rerun with --agent-only.\n");
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
if (selected.length === 0) {
|
|
111
|
+
stdout.write(`Installed ${plan.packageSpecifier}, but no coding agent was detected.\n`);
|
|
112
|
+
writeManualInstructions(plan);
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
let outcomes;
|
|
116
|
+
try {
|
|
117
|
+
outcomes = configureProjectAgents(plan, selected);
|
|
118
|
+
}
|
|
119
|
+
catch (error) {
|
|
120
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
121
|
+
stdout.write(`Could not update the coding-agent configuration: ${message}\n`);
|
|
122
|
+
writeManualInstructions(plan);
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
let configured = 0;
|
|
126
|
+
for (const outcome of outcomes) {
|
|
127
|
+
if (outcome.unsupported) {
|
|
128
|
+
stdout.write(`${outcome.displayName} is not supported for automatic project setup.\n`);
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
if (outcome.result?.success) {
|
|
132
|
+
configured += 1;
|
|
133
|
+
stdout.write(`Configured ${outcome.displayName}: ${outcome.result.path}\n`);
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
stdout.write(`Could not configure ${outcome.displayName}: ${outcome.result?.error ?? "unknown error"}\n`);
|
|
137
|
+
}
|
|
138
|
+
if (configured !== outcomes.length)
|
|
139
|
+
writeManualInstructions(plan);
|
|
140
|
+
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");
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
async function shouldConfigureAgent(preference, hasExplicitAgents, yes) {
|
|
145
|
+
if (preference !== undefined)
|
|
146
|
+
return preference;
|
|
147
|
+
if (hasExplicitAgents || yes)
|
|
148
|
+
return true;
|
|
149
|
+
if (!stdin.isTTY || !stdout.isTTY)
|
|
150
|
+
return false;
|
|
151
|
+
return promptYesNo("Connect a coding agent?", true);
|
|
152
|
+
}
|
|
153
|
+
async function promptYesNo(message, defaultValue) {
|
|
154
|
+
const reader = createInterface({ input: stdin, output: stdout });
|
|
155
|
+
try {
|
|
156
|
+
const answer = (await reader.question(`${message} ${defaultValue ? "[Y/n]" : "[y/N]"} `)).trim().toLowerCase();
|
|
157
|
+
if (!answer)
|
|
158
|
+
return defaultValue;
|
|
159
|
+
return answer === "y" || answer === "yes";
|
|
160
|
+
}
|
|
161
|
+
finally {
|
|
162
|
+
reader.close();
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
async function selectAgents(detected) {
|
|
166
|
+
const choices = projectAgentChoices(detected);
|
|
167
|
+
stdout.write("Select coding agents (comma-separated):\n");
|
|
168
|
+
choices.forEach((choice, index) => {
|
|
169
|
+
stdout.write(` ${index + 1}. ${choice.label}${choice.detected ? " (detected)" : ""}\n`);
|
|
170
|
+
});
|
|
171
|
+
const defaults = choices
|
|
172
|
+
.map((choice, index) => choice.detected ? String(index + 1) : undefined)
|
|
173
|
+
.filter((value) => value !== undefined)
|
|
174
|
+
.join(",");
|
|
175
|
+
const reader = createInterface({ input: stdin, output: stdout });
|
|
176
|
+
try {
|
|
177
|
+
while (true) {
|
|
178
|
+
const suffix = defaults ? ` [${defaults}]` : "";
|
|
179
|
+
const answer = (await reader.question(`Agents${suffix}: `)).trim() || defaults;
|
|
180
|
+
const indexes = answer.split(",").map((value) => Number(value.trim()) - 1);
|
|
181
|
+
if (indexes.length > 0 && indexes.every((index) => choices[index])) {
|
|
182
|
+
return [...new Set(indexes.map((index) => choices[index].id))];
|
|
183
|
+
}
|
|
184
|
+
stdout.write(`Enter one or more numbers from 1 to ${choices.length}.\n`);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
finally {
|
|
188
|
+
reader.close();
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
function writeManualInstructions(plan) {
|
|
192
|
+
stdout.write("Add this project-scoped stdio server to your agent's MCP settings:\n");
|
|
193
|
+
stdout.write(`${manualAgentConfiguration(plan)}\n`);
|
|
53
194
|
}
|
|
54
195
|
async function selectFramework(detected) {
|
|
55
196
|
if (detected.length === 1)
|
package/dist/configuration.js
CHANGED
|
@@ -3,7 +3,20 @@ import { join } from "node:path";
|
|
|
3
3
|
import ts from "typescript";
|
|
4
4
|
const nextConfigNames = ["next.config.ts", "next.config.mts", "next.config.mjs", "next.config.js", "next.config.cjs"];
|
|
5
5
|
const astroConfigNames = ["astro.config.ts", "astro.config.mts", "astro.config.mjs", "astro.config.js"];
|
|
6
|
-
|
|
6
|
+
/**
|
|
7
|
+
* Vite's own `DEFAULT_CONFIG_FILES` order. The list is order-sensitive: the
|
|
8
|
+
* first existing file wins for Vite, so it must win here too, or the installer
|
|
9
|
+
* edits a configuration Vite never loads (and creating a new `vite.config.mjs`
|
|
10
|
+
* beside a `vite.config.cjs` would silently shadow it).
|
|
11
|
+
*/
|
|
12
|
+
const viteConfigNames = [
|
|
13
|
+
"vite.config.js",
|
|
14
|
+
"vite.config.mjs",
|
|
15
|
+
"vite.config.ts",
|
|
16
|
+
"vite.config.cjs",
|
|
17
|
+
"vite.config.mts",
|
|
18
|
+
"vite.config.cts",
|
|
19
|
+
];
|
|
7
20
|
/** Plans an idempotent host-configuration edit without writing to the project. */
|
|
8
21
|
export function planConfiguration(projectRoot, framework) {
|
|
9
22
|
if (framework === "standalone")
|
|
@@ -22,45 +35,59 @@ export function planConfiguration(projectRoot, framework) {
|
|
|
22
35
|
export function configureSource(source, framework, fileName) {
|
|
23
36
|
const sourceFile = parseSource(source, fileName);
|
|
24
37
|
if (framework === "astro") {
|
|
25
|
-
return
|
|
38
|
+
return configureAstroSource(source, sourceFile);
|
|
26
39
|
}
|
|
27
40
|
if (framework === "vite-react") {
|
|
28
|
-
return
|
|
41
|
+
return configureViteSource(source, sourceFile);
|
|
29
42
|
}
|
|
30
43
|
return configureNextSource(source, sourceFile);
|
|
31
44
|
}
|
|
32
|
-
function
|
|
33
|
-
const
|
|
34
|
-
const
|
|
35
|
-
const
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
-
|
|
45
|
+
function configureViteSource(source, sourceFile) {
|
|
46
|
+
const packageName = "nudge-ui/vite";
|
|
47
|
+
const importName = "withNudgeUi";
|
|
48
|
+
const target = findConfigExport(sourceFile, "Vite");
|
|
49
|
+
const bindings = target.commonJs
|
|
50
|
+
? requiredBindings(sourceFile, packageName, importName)
|
|
51
|
+
: importedBindings(sourceFile, packageName, importName);
|
|
52
|
+
const wrapperBinding = bindings[0] ?? unusedBindingName(sourceFile, importName);
|
|
53
|
+
const callableBindings = new Set([...bindings, wrapperBinding]);
|
|
54
|
+
const edits = [];
|
|
55
|
+
if (!containsCall(target.expression, callableBindings)) {
|
|
56
|
+
const start = target.expression.getStart(sourceFile);
|
|
57
|
+
const end = target.expression.getEnd();
|
|
58
|
+
edits.push({ start, end, text: `${wrapperBinding}(${source.slice(start, end)})` });
|
|
39
59
|
}
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
}
|
|
46
|
-
if (!containsCall(property.initializer, callableBindings)) {
|
|
47
|
-
configurationEdit = insertArrayElement(source, sourceFile, property, expression);
|
|
48
|
-
}
|
|
60
|
+
if (bindings.length === 0) {
|
|
61
|
+
const statement = target.commonJs
|
|
62
|
+
? `const { ${importName}${wrapperBinding === importName ? "" : `: ${wrapperBinding}`} } = require("${packageName}");`
|
|
63
|
+
: `import { ${importName}${wrapperBinding === importName ? "" : ` as ${wrapperBinding}`} } from "${packageName}";`;
|
|
64
|
+
edits.push(importEdit(sourceFile, statement, target.commonJs));
|
|
49
65
|
}
|
|
50
|
-
|
|
51
|
-
|
|
66
|
+
return applyEdits(source, edits);
|
|
67
|
+
}
|
|
68
|
+
function configureAstroSource(source, sourceFile) {
|
|
69
|
+
const target = findDefaultExport(sourceFile, "Astro");
|
|
70
|
+
const bindings = importedBindings(sourceFile, "nudge-ui/astro", "withNudgeUi");
|
|
71
|
+
const wrapperBinding = bindings[0] ?? unusedBindingName(sourceFile, "withNudgeUi");
|
|
72
|
+
const edits = [];
|
|
73
|
+
if (!containsCall(target, new Set(bindings))) {
|
|
74
|
+
const start = target.getStart(sourceFile);
|
|
75
|
+
const end = target.getEnd();
|
|
76
|
+
edits.push({ start, end, text: `${wrapperBinding}(${source.slice(start, end)})` });
|
|
52
77
|
}
|
|
53
|
-
const edits = configurationEdit ? [configurationEdit] : [];
|
|
54
78
|
if (bindings.length === 0) {
|
|
55
|
-
|
|
79
|
+
const importedName = wrapperBinding === "withNudgeUi"
|
|
80
|
+
? "withNudgeUi"
|
|
81
|
+
: `withNudgeUi as ${wrapperBinding}`;
|
|
82
|
+
edits.push(importEdit(sourceFile, `import { ${importedName} } from "nudge-ui/astro";`, false));
|
|
56
83
|
}
|
|
57
84
|
return applyEdits(source, edits);
|
|
58
85
|
}
|
|
59
86
|
function configureNextSource(source, sourceFile) {
|
|
60
|
-
const target =
|
|
87
|
+
const target = findConfigExport(sourceFile, "Next.js");
|
|
61
88
|
const bindings = target.commonJs
|
|
62
|
-
? requiredBindings(sourceFile, "
|
|
63
|
-
: importedBindings(sourceFile, "
|
|
89
|
+
? requiredBindings(sourceFile, "nudge-ui/next", "withNudgeUi")
|
|
90
|
+
: importedBindings(sourceFile, "nudge-ui/next", "withNudgeUi");
|
|
64
91
|
const callableBindings = new Set([...bindings, "withNudgeUi"]);
|
|
65
92
|
const edits = [];
|
|
66
93
|
if (!containsCall(target.expression, callableBindings)) {
|
|
@@ -70,34 +97,19 @@ function configureNextSource(source, sourceFile) {
|
|
|
70
97
|
}
|
|
71
98
|
if (bindings.length === 0) {
|
|
72
99
|
const statement = target.commonJs
|
|
73
|
-
? 'const { withNudgeUi } = require("
|
|
74
|
-
: 'import { withNudgeUi } from "
|
|
100
|
+
? 'const { withNudgeUi } = require("nudge-ui/next");'
|
|
101
|
+
: 'import { withNudgeUi } from "nudge-ui/next";';
|
|
75
102
|
edits.push(importEdit(sourceFile, statement, target.commonJs));
|
|
76
103
|
}
|
|
77
104
|
return applyEdits(source, edits);
|
|
78
105
|
}
|
|
79
106
|
function parseSource(source, fileName) {
|
|
80
|
-
const scriptKind =
|
|
107
|
+
const scriptKind = /\.(?:ts|mts|cts)$/.test(fileName)
|
|
81
108
|
? ts.ScriptKind.TS
|
|
82
109
|
: ts.ScriptKind.JS;
|
|
83
110
|
return ts.createSourceFile(fileName, source, ts.ScriptTarget.Latest, true, scriptKind);
|
|
84
111
|
}
|
|
85
|
-
function
|
|
86
|
-
const candidates = [];
|
|
87
|
-
visit(sourceFile, (node) => {
|
|
88
|
-
if (ts.isCallExpression(node)
|
|
89
|
-
&& ts.isIdentifier(node.expression)
|
|
90
|
-
&& node.expression.text === "defineConfig"
|
|
91
|
-
&& node.arguments[0]
|
|
92
|
-
&& ts.isObjectLiteralExpression(node.arguments[0]))
|
|
93
|
-
candidates.push(node.arguments[0]);
|
|
94
|
-
});
|
|
95
|
-
if (candidates.length !== 1) {
|
|
96
|
-
throw new Error(`Could not update ${propertyName}: expected exactly one defineConfig({ ... }) call.`);
|
|
97
|
-
}
|
|
98
|
-
return candidates[0];
|
|
99
|
-
}
|
|
100
|
-
function findNextExport(sourceFile) {
|
|
112
|
+
function findConfigExport(sourceFile, frameworkName) {
|
|
101
113
|
const exports = [];
|
|
102
114
|
for (const statement of sourceFile.statements) {
|
|
103
115
|
if (ts.isExportAssignment(statement) && !statement.isExportEquals) {
|
|
@@ -112,7 +124,16 @@ function findNextExport(sourceFile) {
|
|
|
112
124
|
exports.push({ expression: assignment.right, commonJs: true });
|
|
113
125
|
}
|
|
114
126
|
if (exports.length !== 1) {
|
|
115
|
-
throw new Error(
|
|
127
|
+
throw new Error(`Could not update the ${frameworkName} configuration: expected exactly one default or module.exports assignment.`);
|
|
128
|
+
}
|
|
129
|
+
return exports[0];
|
|
130
|
+
}
|
|
131
|
+
function findDefaultExport(sourceFile, frameworkName) {
|
|
132
|
+
const exports = sourceFile.statements
|
|
133
|
+
.filter((statement) => ts.isExportAssignment(statement) && !statement.isExportEquals)
|
|
134
|
+
.map((statement) => statement.expression);
|
|
135
|
+
if (exports.length !== 1) {
|
|
136
|
+
throw new Error(`Could not update the ${frameworkName} configuration: expected exactly one default export.`);
|
|
116
137
|
}
|
|
117
138
|
return exports[0];
|
|
118
139
|
}
|
|
@@ -180,46 +201,23 @@ function containsCall(root, bindingNames) {
|
|
|
180
201
|
});
|
|
181
202
|
return found;
|
|
182
203
|
}
|
|
204
|
+
function unusedBindingName(sourceFile, preferred) {
|
|
205
|
+
const identifiers = new Set();
|
|
206
|
+
visit(sourceFile, (node) => {
|
|
207
|
+
if (ts.isIdentifier(node))
|
|
208
|
+
identifiers.add(node.text);
|
|
209
|
+
});
|
|
210
|
+
if (!identifiers.has(preferred))
|
|
211
|
+
return preferred;
|
|
212
|
+
let suffix = 2;
|
|
213
|
+
while (identifiers.has(`${preferred}${suffix}`))
|
|
214
|
+
suffix += 1;
|
|
215
|
+
return `${preferred}${suffix}`;
|
|
216
|
+
}
|
|
183
217
|
function visit(root, visitor) {
|
|
184
218
|
visitor(root);
|
|
185
219
|
ts.forEachChild(root, (child) => visit(child, visitor));
|
|
186
220
|
}
|
|
187
|
-
function propertyText(name) {
|
|
188
|
-
if (!name)
|
|
189
|
-
return undefined;
|
|
190
|
-
if (ts.isIdentifier(name) || ts.isStringLiteral(name) || ts.isNumericLiteral(name))
|
|
191
|
-
return name.text;
|
|
192
|
-
if (ts.isComputedPropertyName(name) && ts.isStringLiteral(name.expression))
|
|
193
|
-
return name.expression.text;
|
|
194
|
-
return undefined;
|
|
195
|
-
}
|
|
196
|
-
function insertArrayElement(source, sourceFile, property, expression) {
|
|
197
|
-
const array = property.initializer;
|
|
198
|
-
if (!ts.isArrayLiteralExpression(array))
|
|
199
|
-
throw new Error("Expected an array property.");
|
|
200
|
-
const start = array.getStart(sourceFile) + 1;
|
|
201
|
-
const end = array.getEnd() - 1;
|
|
202
|
-
const indentation = lineIndentation(source, property.getStart(sourceFile));
|
|
203
|
-
const elementIndentation = `${indentation} `;
|
|
204
|
-
const interior = source.slice(start, end);
|
|
205
|
-
if (interior.trim() === "") {
|
|
206
|
-
return { start, end, text: `\n${elementIndentation}${expression},\n${indentation}` };
|
|
207
|
-
}
|
|
208
|
-
const text = interior.startsWith("\n")
|
|
209
|
-
? `\n${elementIndentation}${expression},`
|
|
210
|
-
: `\n${elementIndentation}${expression},\n${elementIndentation}`;
|
|
211
|
-
return { start, end: start, text };
|
|
212
|
-
}
|
|
213
|
-
function insertObjectProperty(source, sourceFile, object, propertyName, expression) {
|
|
214
|
-
const start = object.getStart(sourceFile) + 1;
|
|
215
|
-
const indentation = lineIndentation(source, object.getStart(sourceFile));
|
|
216
|
-
const propertyIndentation = `${indentation} `;
|
|
217
|
-
const empty = object.properties.length === 0;
|
|
218
|
-
const text = empty
|
|
219
|
-
? `\n${propertyIndentation}${propertyName}: [${expression}],\n${indentation}`
|
|
220
|
-
: `\n${propertyIndentation}${propertyName}: [${expression}],`;
|
|
221
|
-
return { start, end: start, text };
|
|
222
|
-
}
|
|
223
221
|
function importEdit(sourceFile, statement, commonJs) {
|
|
224
222
|
const imports = sourceFile.statements.filter(ts.isImportDeclaration);
|
|
225
223
|
const lastImport = imports.at(-1);
|
|
@@ -235,11 +233,6 @@ function importEdit(sourceFile, statement, commonJs) {
|
|
|
235
233
|
const start = firstStatement?.getStart(sourceFile) ?? sourceFile.getEnd();
|
|
236
234
|
return { start, end: start, text: `${statement}\n` };
|
|
237
235
|
}
|
|
238
|
-
function lineIndentation(source, position) {
|
|
239
|
-
const lineStart = source.lastIndexOf("\n", position - 1) + 1;
|
|
240
|
-
const match = /^[ \t]*/.exec(source.slice(lineStart, position));
|
|
241
|
-
return match?.[0] ?? "";
|
|
242
|
-
}
|
|
243
236
|
function applyEdits(source, edits) {
|
|
244
237
|
return [...edits]
|
|
245
238
|
.sort((left, right) => right.start - left.start)
|
package/dist/detection.d.ts
CHANGED
|
@@ -8,4 +8,3 @@ export declare function detectPackageManager(projectRoot: string, manifest?: Pro
|
|
|
8
8
|
/** Finds an HTML document root without recursively scanning dependency or build output. */
|
|
9
9
|
export declare function detectStaticRoot(projectRoot: string): string | undefined;
|
|
10
10
|
export declare function frameworkDisplayName(framework: Framework): string;
|
|
11
|
-
export declare function adapterPackage(framework: Framework): string;
|
package/dist/detection.js
CHANGED
|
@@ -57,7 +57,7 @@ export function detectFrameworks(projectRoot, manifest = readProjectManifest(pro
|
|
|
57
57
|
return ["vite-react"];
|
|
58
58
|
if (hasVite)
|
|
59
59
|
return [];
|
|
60
|
-
if (manifest.dependencies.has("
|
|
60
|
+
if (manifest.dependencies.has("nudge-ui") || detectStaticRoot(projectRoot))
|
|
61
61
|
return ["standalone"];
|
|
62
62
|
return [];
|
|
63
63
|
}
|
|
@@ -107,15 +107,6 @@ export function frameworkDisplayName(framework) {
|
|
|
107
107
|
return "Vite with React";
|
|
108
108
|
return "static HTML";
|
|
109
109
|
}
|
|
110
|
-
export function adapterPackage(framework) {
|
|
111
|
-
if (framework === "nextjs")
|
|
112
|
-
return "@nudge-ui/nextjs";
|
|
113
|
-
if (framework === "astro")
|
|
114
|
-
return "@nudge-ui/astro";
|
|
115
|
-
if (framework === "vite-react")
|
|
116
|
-
return "@nudge-ui/vite-react";
|
|
117
|
-
return "@nudge-ui/standalone";
|
|
118
|
-
}
|
|
119
110
|
function hasAnyFile(projectRoot, names) {
|
|
120
111
|
return names.some((name) => existsSync(join(projectRoot, name)));
|
|
121
112
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
export { parseArguments, helpText, type CliOptions } from "./arguments.js";
|
|
2
|
+
export { configureProjectAgents, detectProjectAgentCandidates, initializerVersion, isAgentServerAvailable, manualAgentConfiguration, planAgentSetup, projectAgentChoices, projectAgentTypes, type AgentInstallOutcome, type AgentSetupPlan, } from "./agent-setup.js";
|
|
3
|
+
export { runAgentSetup, type RunAgentSetupOptions } from "./cli.js";
|
|
2
4
|
export { configureSource, planConfiguration } from "./configuration.js";
|
|
3
|
-
export {
|
|
5
|
+
export { detectFrameworks, detectPackageManager, detectStaticRoot, frameworkDisplayName, readProjectManifest, } from "./detection.js";
|
|
4
6
|
export { formatCommand, installCommand, type InstallCommand } from "./installer.js";
|
|
5
7
|
export { frameworks, packageManagers, type Framework, type PackageManager } from "./types.js";
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
export { parseArguments, helpText } from "./arguments.js";
|
|
2
|
+
export { configureProjectAgents, detectProjectAgentCandidates, initializerVersion, isAgentServerAvailable, manualAgentConfiguration, planAgentSetup, projectAgentChoices, projectAgentTypes, } from "./agent-setup.js";
|
|
3
|
+
export { runAgentSetup } from "./cli.js";
|
|
2
4
|
export { configureSource, planConfiguration } from "./configuration.js";
|
|
3
|
-
export {
|
|
5
|
+
export { detectFrameworks, detectPackageManager, detectStaticRoot, frameworkDisplayName, readProjectManifest, } from "./detection.js";
|
|
4
6
|
export { formatCommand, installCommand } from "./installer.js";
|
|
5
7
|
export { frameworks, packageManagers } from "./types.js";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-nudge-ui",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "Framework-detecting installer for Nudge UI.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -29,6 +29,7 @@
|
|
|
29
29
|
"create-nudge-ui": "./dist/entry.js"
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
|
+
"add-mcp": "^2.4.0",
|
|
32
33
|
"typescript": "^5.9.3"
|
|
33
34
|
},
|
|
34
35
|
"devDependencies": {
|