neon-init 0.13.1 → 0.15.0
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/dist/cli.js +368 -33
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +15 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +220 -41
- package/dist/index.js.map +1 -1
- package/dist/interactive.d.ts +12 -0
- package/dist/interactive.d.ts.map +1 -0
- package/dist/interactive.js +495 -0
- package/dist/interactive.js.map +1 -0
- package/dist/lib/agents.d.ts +23 -0
- package/dist/lib/agents.d.ts.map +1 -0
- package/dist/lib/agents.js +148 -0
- package/dist/lib/agents.js.map +1 -0
- package/dist/lib/auth.d.ts +10 -3
- package/dist/lib/auth.d.ts.map +1 -1
- package/dist/lib/auth.js +20 -13
- package/dist/lib/auth.js.map +1 -1
- package/dist/lib/bootstrap.d.ts +30 -0
- package/dist/lib/bootstrap.d.ts.map +1 -0
- package/dist/lib/bootstrap.js +61 -0
- package/dist/lib/bootstrap.js.map +1 -0
- package/dist/lib/build-config.d.ts +5 -0
- package/dist/lib/build-config.d.ts.map +1 -0
- package/dist/lib/build-config.js +6 -0
- package/dist/lib/build-config.js.map +1 -0
- package/dist/lib/detect-agent.d.ts +22 -0
- package/dist/lib/detect-agent.d.ts.map +1 -0
- package/dist/lib/detect-agent.js +65 -0
- package/dist/lib/detect-agent.js.map +1 -0
- package/dist/lib/editors.d.ts.map +1 -1
- package/dist/lib/editors.js +1 -2
- package/dist/lib/editors.js.map +1 -1
- package/dist/lib/extension.d.ts +11 -3
- package/dist/lib/extension.d.ts.map +1 -1
- package/dist/lib/extension.js +29 -9
- package/dist/lib/extension.js.map +1 -1
- package/dist/lib/inspect.d.ts +28 -0
- package/dist/lib/inspect.d.ts.map +1 -0
- package/dist/lib/inspect.js +190 -0
- package/dist/lib/inspect.js.map +1 -0
- package/dist/lib/install.d.ts +10 -4
- package/dist/lib/install.d.ts.map +1 -1
- package/dist/lib/install.js +74 -71
- package/dist/lib/install.js.map +1 -1
- package/dist/lib/neonctl.d.ts +32 -0
- package/dist/lib/neonctl.d.ts.map +1 -0
- package/dist/lib/neonctl.js +149 -0
- package/dist/lib/neonctl.js.map +1 -0
- package/dist/lib/phases/auth.d.ts +12 -0
- package/dist/lib/phases/auth.d.ts.map +1 -0
- package/dist/lib/phases/auth.js +188 -0
- package/dist/lib/phases/auth.js.map +1 -0
- package/dist/lib/phases/cleanup.d.ts +12 -0
- package/dist/lib/phases/cleanup.d.ts.map +1 -0
- package/dist/lib/phases/cleanup.js +29 -0
- package/dist/lib/phases/cleanup.js.map +1 -0
- package/dist/lib/phases/db.d.ts +17 -0
- package/dist/lib/phases/db.d.ts.map +1 -0
- package/dist/lib/phases/db.js +258 -0
- package/dist/lib/phases/db.js.map +1 -0
- package/dist/lib/phases/getting-started.d.ts +26 -0
- package/dist/lib/phases/getting-started.d.ts.map +1 -0
- package/dist/lib/phases/getting-started.js +195 -0
- package/dist/lib/phases/getting-started.js.map +1 -0
- package/dist/lib/phases/mcp.d.ts +15 -0
- package/dist/lib/phases/mcp.d.ts.map +1 -0
- package/dist/lib/phases/mcp.js +179 -0
- package/dist/lib/phases/mcp.js.map +1 -0
- package/dist/lib/phases/migrations.d.ts +14 -0
- package/dist/lib/phases/migrations.d.ts.map +1 -0
- package/dist/lib/phases/migrations.js +239 -0
- package/dist/lib/phases/migrations.js.map +1 -0
- package/dist/lib/phases/neon-auth.d.ts +13 -0
- package/dist/lib/phases/neon-auth.d.ts.map +1 -0
- package/dist/lib/phases/neon-auth.js +117 -0
- package/dist/lib/phases/neon-auth.js.map +1 -0
- package/dist/lib/phases/setup.d.ts +41 -0
- package/dist/lib/phases/setup.d.ts.map +1 -0
- package/dist/lib/phases/setup.js +689 -0
- package/dist/lib/phases/setup.js.map +1 -0
- package/dist/lib/phases/skills.d.ts +14 -0
- package/dist/lib/phases/skills.d.ts.map +1 -0
- package/dist/lib/phases/skills.js +80 -0
- package/dist/lib/phases/skills.js.map +1 -0
- package/dist/lib/phases/status.d.ts +10 -0
- package/dist/lib/phases/status.d.ts.map +1 -0
- package/dist/lib/phases/status.js +65 -0
- package/dist/lib/phases/status.js.map +1 -0
- package/dist/lib/resolve-context.d.ts +19 -0
- package/dist/lib/resolve-context.d.ts.map +1 -0
- package/dist/lib/resolve-context.js +112 -0
- package/dist/lib/resolve-context.js.map +1 -0
- package/dist/lib/route-command.d.ts +8 -0
- package/dist/lib/route-command.d.ts.map +1 -0
- package/dist/lib/route-command.js +195 -0
- package/dist/lib/route-command.js.map +1 -0
- package/dist/lib/skills.d.ts +21 -4
- package/dist/lib/skills.d.ts.map +1 -1
- package/dist/lib/skills.js +129 -22
- package/dist/lib/skills.js.map +1 -1
- package/dist/lib/types.d.ts +146 -13
- package/dist/lib/types.d.ts.map +1 -1
- package/dist/lib/types.js +1 -1
- package/dist/lib/vsix.d.ts +15 -0
- package/dist/lib/vsix.d.ts.map +1 -0
- package/dist/lib/vsix.js +91 -0
- package/dist/lib/vsix.js.map +1 -0
- package/dist/v2.d.ts +31 -0
- package/dist/v2.d.ts.map +1 -0
- package/dist/v2.js +147 -0
- package/dist/v2.js.map +1 -0
- package/package.json +9 -4
- package/dist/lib/mcp-config.d.ts +0 -24
- package/dist/lib/mcp-config.d.ts.map +0 -1
- package/dist/lib/mcp-config.js +0 -51
- package/dist/lib/mcp-config.js.map +0 -1
|
@@ -0,0 +1,495 @@
|
|
|
1
|
+
import { ALL_CONFIGURABLE_AGENTS, getAddMcpAgentId } from "./lib/agents.js";
|
|
2
|
+
import { ensureNeonctlAuth, isAuthenticated } from "./lib/auth.js";
|
|
3
|
+
import { FALLBACK_TEMPLATES, fetchTemplates } from "./lib/bootstrap.js";
|
|
4
|
+
import { detectAgent } from "./lib/detect-agent.js";
|
|
5
|
+
import { detectAvailableEditors } from "./lib/editors.js";
|
|
6
|
+
import { installExtension, isExtensionInstalled, usesExtension } from "./lib/extension.js";
|
|
7
|
+
import { inspectProject } from "./lib/inspect.js";
|
|
8
|
+
import { ensureNeonctl } from "./lib/neonctl.js";
|
|
9
|
+
import { installAgentSkills } from "./lib/skills.js";
|
|
10
|
+
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
11
|
+
import { resolve } from "node:path";
|
|
12
|
+
import { confirm, isCancel, log, multiselect, outro, select, spinner } from "@clack/prompts";
|
|
13
|
+
import { execa } from "execa";
|
|
14
|
+
import { bold, dim } from "yoctocolors";
|
|
15
|
+
import picocolors from "picocolors";
|
|
16
|
+
//#region src/interactive.ts
|
|
17
|
+
/**
|
|
18
|
+
* Interactive v2 CLI — purpose-built guided flow for humans.
|
|
19
|
+
* Uses the same underlying install functions but with a clean clack-based UX.
|
|
20
|
+
*/
|
|
21
|
+
function wordWrap(text, width) {
|
|
22
|
+
return text.split("\n").map((line) => {
|
|
23
|
+
if (line.length <= width) return line;
|
|
24
|
+
const words = line.split(" ");
|
|
25
|
+
const lines = [];
|
|
26
|
+
let current = "";
|
|
27
|
+
for (const word of words) if (current.length + word.length + 1 > width && current.length > 0) {
|
|
28
|
+
lines.push(current);
|
|
29
|
+
current = word;
|
|
30
|
+
} else current = current.length > 0 ? `${current} ${word}` : word;
|
|
31
|
+
if (current.length > 0) lines.push(current);
|
|
32
|
+
return lines.join("\n");
|
|
33
|
+
}).join("\n");
|
|
34
|
+
}
|
|
35
|
+
const neonGreenFn = (s) => `\x1b[38;2;75;181;120m${s}\x1b[39m`;
|
|
36
|
+
const originalCyan = picocolors.cyan;
|
|
37
|
+
const originalMagenta = picocolors.magenta;
|
|
38
|
+
function patchClackColors() {
|
|
39
|
+
const pc = picocolors;
|
|
40
|
+
pc.cyan = neonGreenFn;
|
|
41
|
+
pc.magenta = neonGreenFn;
|
|
42
|
+
return () => {
|
|
43
|
+
pc.cyan = originalCyan;
|
|
44
|
+
pc.magenta = originalMagenta;
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
async function interactiveInit(options = {}) {
|
|
48
|
+
const restoreColors = patchClackColors();
|
|
49
|
+
try {
|
|
50
|
+
await interactiveInitInner(options);
|
|
51
|
+
} finally {
|
|
52
|
+
restoreColors();
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
async function interactiveInitInner(options) {
|
|
56
|
+
console.log();
|
|
57
|
+
console.log("\x1B[38;2;75;181;120m" + [
|
|
58
|
+
" ██╗ ██╗██████╗ ██████╗ ██╗ ██╗",
|
|
59
|
+
" ███╗ ██║██╔═══╝ ██╔═══██╗███╗ ██║",
|
|
60
|
+
" ████╗██║██████╗ ██║ ██║████╗██║",
|
|
61
|
+
" ██╔████║██╔═══╝ ██║ ██║██╔████║",
|
|
62
|
+
" ██║╚███║██████╗ ╚██████╔╝██║╚███║",
|
|
63
|
+
" ╚═╝ ╚══╝╚═════╝ ╚═════╝ ╚═╝ ╚══╝"
|
|
64
|
+
].join("\n") + "\x1B[0m");
|
|
65
|
+
console.log(dim(wordWrap("\nLet's get your project set up with Neon. We'll install the MCP server, agent skills, and IDE extension, then connect your app to a database.\n", process.stdout.columns || 80)));
|
|
66
|
+
const detectedAgentId = detectAgent();
|
|
67
|
+
const detectedEditor = detectedAgentId ? agentIdToEditor(detectedAgentId) : null;
|
|
68
|
+
let editorList = detectedEditor ?? "your editor";
|
|
69
|
+
const inspectSpinner = spinner();
|
|
70
|
+
inspectSpinner.start("Checking existing configuration...");
|
|
71
|
+
const inspection = await inspectProject([
|
|
72
|
+
{
|
|
73
|
+
id: "has_app",
|
|
74
|
+
description: "",
|
|
75
|
+
lookFor: []
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
id: "mcp_server",
|
|
79
|
+
description: "",
|
|
80
|
+
lookFor: []
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
id: "skills",
|
|
84
|
+
description: "",
|
|
85
|
+
lookFor: []
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
id: "connection_string",
|
|
89
|
+
description: "",
|
|
90
|
+
lookFor: []
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
id: "project_stack",
|
|
94
|
+
description: "",
|
|
95
|
+
lookFor: []
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
id: "migrations",
|
|
99
|
+
description: "",
|
|
100
|
+
lookFor: []
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
id: "ide_type",
|
|
104
|
+
description: "",
|
|
105
|
+
lookFor: []
|
|
106
|
+
}
|
|
107
|
+
]);
|
|
108
|
+
inspectSpinner.stop(dim("Configuration checked ✓"));
|
|
109
|
+
const hasApp = inspection.hasApp === true;
|
|
110
|
+
let selectedFeatures = [];
|
|
111
|
+
let selectedTemplate = null;
|
|
112
|
+
if (options.preview && !hasApp) {
|
|
113
|
+
let templates = FALLBACK_TEMPLATES;
|
|
114
|
+
try {
|
|
115
|
+
const fetched = await fetchTemplates();
|
|
116
|
+
if (fetched && fetched.length > 0) templates = fetched;
|
|
117
|
+
} catch {}
|
|
118
|
+
const templateResult = await select({
|
|
119
|
+
message: "No application detected. Would you like to scaffold a new project from a template?",
|
|
120
|
+
options: [...templates.map((t) => ({
|
|
121
|
+
value: t.id,
|
|
122
|
+
label: t.title,
|
|
123
|
+
hint: t.description
|
|
124
|
+
})), {
|
|
125
|
+
value: "none",
|
|
126
|
+
label: "No thanks — continue without scaffolding"
|
|
127
|
+
}],
|
|
128
|
+
initialValue: templates[0]?.id ?? "none"
|
|
129
|
+
});
|
|
130
|
+
if (isCancel(templateResult)) {
|
|
131
|
+
outro("Setup cancelled.");
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
if (templateResult !== "none") {
|
|
135
|
+
selectedTemplate = templates.find((t) => t.id === templateResult) ?? null;
|
|
136
|
+
if (selectedTemplate) {
|
|
137
|
+
selectedFeatures = selectedTemplate.requires;
|
|
138
|
+
const bootstrapS = spinner();
|
|
139
|
+
bootstrapS.start(`Scaffolding project from template "${selectedTemplate.title}"...`);
|
|
140
|
+
try {
|
|
141
|
+
await execa("npx", [
|
|
142
|
+
"neonctl",
|
|
143
|
+
"bootstrap",
|
|
144
|
+
".",
|
|
145
|
+
"--template",
|
|
146
|
+
selectedTemplate.id,
|
|
147
|
+
"--force"
|
|
148
|
+
], {
|
|
149
|
+
stdio: "pipe",
|
|
150
|
+
timeout: 12e4
|
|
151
|
+
});
|
|
152
|
+
bootstrapS.stop(dim(`Scaffolded project from "${selectedTemplate.title}" ✓`));
|
|
153
|
+
} catch (err) {
|
|
154
|
+
const msg = err instanceof Error ? err.message : "Unknown error";
|
|
155
|
+
bootstrapS.stop("Failed to scaffold project");
|
|
156
|
+
log.error(msg);
|
|
157
|
+
outro("Setup failed.");
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
if (!selectedTemplate && hasApp) {
|
|
164
|
+
const featuresResult = await select({
|
|
165
|
+
message: "Which Neon features would you like to enable for this project?",
|
|
166
|
+
options: [{
|
|
167
|
+
value: "database",
|
|
168
|
+
label: "Database"
|
|
169
|
+
}, {
|
|
170
|
+
value: "database,auth",
|
|
171
|
+
label: "Database + Neon Auth (adds authentication via Neon)"
|
|
172
|
+
}],
|
|
173
|
+
initialValue: "database"
|
|
174
|
+
});
|
|
175
|
+
if (isCancel(featuresResult)) {
|
|
176
|
+
outro("Setup cancelled.");
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
selectedFeatures = featuresResult.split(",");
|
|
180
|
+
}
|
|
181
|
+
if (selectedFeatures.length > 0) {
|
|
182
|
+
const neonPath = resolve(process.cwd(), ".neon");
|
|
183
|
+
let existing = {};
|
|
184
|
+
if (existsSync(neonPath)) try {
|
|
185
|
+
existing = JSON.parse(readFileSync(neonPath, "utf-8"));
|
|
186
|
+
} catch {}
|
|
187
|
+
existing._init = { features: selectedFeatures };
|
|
188
|
+
writeFileSync(neonPath, `${JSON.stringify(existing, null, 2)}\n`);
|
|
189
|
+
}
|
|
190
|
+
const mcpAlready = inspection.mcpConfigured === true;
|
|
191
|
+
const skillsAlready = inspection.skillsInstalled === true || selectedTemplate !== null;
|
|
192
|
+
const hasNeonConnection = inspection.connectionString === true;
|
|
193
|
+
const needsMcp = !mcpAlready;
|
|
194
|
+
const needsSkills = !skillsAlready;
|
|
195
|
+
const needsInstall = needsMcp || needsSkills;
|
|
196
|
+
const neonContextPath = resolve(process.cwd(), ".neon");
|
|
197
|
+
const hasNeonContext = existsSync(neonContextPath) && (() => {
|
|
198
|
+
try {
|
|
199
|
+
return !!JSON.parse(readFileSync(neonContextPath, "utf-8")).projectId;
|
|
200
|
+
} catch {
|
|
201
|
+
return false;
|
|
202
|
+
}
|
|
203
|
+
})();
|
|
204
|
+
const hasNeonAuth = (() => {
|
|
205
|
+
for (const envFile of [".env", ".env.local"]) {
|
|
206
|
+
const envPath = resolve(process.cwd(), envFile);
|
|
207
|
+
if (existsSync(envPath)) try {
|
|
208
|
+
const content = readFileSync(envPath, "utf-8");
|
|
209
|
+
if (/^NEON_AUTH_/m.test(content)) return true;
|
|
210
|
+
} catch {}
|
|
211
|
+
}
|
|
212
|
+
return false;
|
|
213
|
+
})();
|
|
214
|
+
let extensionAlready = false;
|
|
215
|
+
if (detectedEditor && usesExtension(detectedEditor)) extensionAlready = await isExtensionInstalled(detectedEditor);
|
|
216
|
+
if (mcpAlready && skillsAlready && hasNeonConnection && hasNeonContext) {
|
|
217
|
+
log.step(dim("Neon MCP server already configured ✓"));
|
|
218
|
+
log.step(dim("Neon agent skills already installed ✓"));
|
|
219
|
+
if (extensionAlready) log.step(dim("Neon editor extension installed ✓"));
|
|
220
|
+
log.step(dim("Neon database connected ✓"));
|
|
221
|
+
if (hasNeonAuth) {
|
|
222
|
+
log.step(dim("Neon Auth configured ✓"));
|
|
223
|
+
outro(dim("Your project is fully configured with Neon. Nothing to do."));
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
const authResult = await select({
|
|
227
|
+
message: "Would you like to set up Neon Auth for user authentication?",
|
|
228
|
+
options: [{
|
|
229
|
+
value: "yes",
|
|
230
|
+
label: "Yes, set up Neon Auth"
|
|
231
|
+
}, {
|
|
232
|
+
value: "no",
|
|
233
|
+
label: "No, skip for now"
|
|
234
|
+
}],
|
|
235
|
+
initialValue: "no"
|
|
236
|
+
});
|
|
237
|
+
if (isCancel(authResult) || authResult === "no") {
|
|
238
|
+
outro(dim("Your project is configured with Neon. You can set up Neon Auth later by having your agent run: neon-init neon-auth"));
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
let projectId = null;
|
|
242
|
+
try {
|
|
243
|
+
projectId = JSON.parse(readFileSync(neonContextPath, "utf-8")).projectId ?? null;
|
|
244
|
+
} catch {}
|
|
245
|
+
log.step("Next steps");
|
|
246
|
+
const promptLines = ["Set up Neon Auth for this project."];
|
|
247
|
+
if (projectId) promptLines.push(`Project ID: ${projectId}.`);
|
|
248
|
+
log.message(dim("Copy the following into your agent chat:"));
|
|
249
|
+
log.message(promptLines.map((line) => bold(neonGreenFn(line))).join("\n"));
|
|
250
|
+
outro(dim("Have feedback? Email us at feedback@neon.tech"));
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
253
|
+
if (mcpAlready) log.step(dim("Neon MCP server already configured ✓"));
|
|
254
|
+
if (skillsAlready) log.step(dim("Neon agent skills already installed ✓"));
|
|
255
|
+
if (needsInstall) {
|
|
256
|
+
const homeDir = process.env.HOME || process.env.USERPROFILE;
|
|
257
|
+
if (!homeDir) {
|
|
258
|
+
log.error("Could not determine home directory.");
|
|
259
|
+
outro("Setup failed.");
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
let selectedEditors;
|
|
263
|
+
if (detectedEditor) selectedEditors = [detectedEditor];
|
|
264
|
+
else {
|
|
265
|
+
const availableEditors = await detectAvailableEditors(homeDir);
|
|
266
|
+
const editorResponse = await multiselect({
|
|
267
|
+
message: "Which editor(s) would you like to configure?",
|
|
268
|
+
options: ALL_CONFIGURABLE_AGENTS.map((agent) => ({
|
|
269
|
+
value: agent.editor,
|
|
270
|
+
label: agent.editor,
|
|
271
|
+
hint: agent.hint
|
|
272
|
+
})),
|
|
273
|
+
initialValues: availableEditors,
|
|
274
|
+
required: true
|
|
275
|
+
});
|
|
276
|
+
if (isCancel(editorResponse)) {
|
|
277
|
+
outro("Setup cancelled.");
|
|
278
|
+
return;
|
|
279
|
+
}
|
|
280
|
+
selectedEditors = editorResponse;
|
|
281
|
+
if (selectedEditors.length === 0) {
|
|
282
|
+
log.warn("No editors selected.");
|
|
283
|
+
outro("Setup cancelled.");
|
|
284
|
+
return;
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
const vscodeEditors = selectedEditors.filter(usesExtension);
|
|
288
|
+
let extensionAlreadyInstalled = false;
|
|
289
|
+
if (vscodeEditors.length > 0) {
|
|
290
|
+
extensionAlreadyInstalled = (await Promise.all(vscodeEditors.map((e) => isExtensionInstalled(e)))).every(Boolean);
|
|
291
|
+
if (extensionAlreadyInstalled) log.step(dim("Neon editor extension already installed ✓"));
|
|
292
|
+
}
|
|
293
|
+
let doInstallExtension = vscodeEditors.length > 0 && !extensionAlreadyInstalled;
|
|
294
|
+
const hintParts = [];
|
|
295
|
+
if (needsMcp) hintParts.push("MCP server (global)");
|
|
296
|
+
if (needsSkills) hintParts.push("agent skills (project)");
|
|
297
|
+
if (doInstallExtension) hintParts.push("editor extension");
|
|
298
|
+
let mcpScope = "global";
|
|
299
|
+
let skillsScope = "project";
|
|
300
|
+
let modeResult;
|
|
301
|
+
while (true) {
|
|
302
|
+
const result = await select({
|
|
303
|
+
message: `Configure ${selectedEditors.join(", ")} for Neon:`,
|
|
304
|
+
options: [
|
|
305
|
+
{
|
|
306
|
+
value: "defaults",
|
|
307
|
+
label: "Install with defaults",
|
|
308
|
+
hint: hintParts.join(", ")
|
|
309
|
+
},
|
|
310
|
+
{
|
|
311
|
+
value: "customize",
|
|
312
|
+
label: "Customize installation",
|
|
313
|
+
hint: "choose scopes and options"
|
|
314
|
+
},
|
|
315
|
+
{
|
|
316
|
+
value: "change_editor",
|
|
317
|
+
label: "Configure a different editor"
|
|
318
|
+
}
|
|
319
|
+
],
|
|
320
|
+
initialValue: "defaults"
|
|
321
|
+
});
|
|
322
|
+
if (isCancel(result)) {
|
|
323
|
+
outro("Setup cancelled.");
|
|
324
|
+
return;
|
|
325
|
+
}
|
|
326
|
+
if (result === "change_editor") {
|
|
327
|
+
const availableEditors = await detectAvailableEditors(homeDir);
|
|
328
|
+
const editorResponse = await multiselect({
|
|
329
|
+
message: "Which editor(s) would you like to configure?",
|
|
330
|
+
options: ALL_CONFIGURABLE_AGENTS.map((agent) => ({
|
|
331
|
+
value: agent.editor,
|
|
332
|
+
label: agent.editor,
|
|
333
|
+
hint: agent.hint
|
|
334
|
+
})),
|
|
335
|
+
initialValues: availableEditors,
|
|
336
|
+
required: true
|
|
337
|
+
});
|
|
338
|
+
if (isCancel(editorResponse)) {
|
|
339
|
+
outro("Setup cancelled.");
|
|
340
|
+
return;
|
|
341
|
+
}
|
|
342
|
+
selectedEditors = editorResponse;
|
|
343
|
+
if (selectedEditors.length === 0) {
|
|
344
|
+
outro("Setup cancelled.");
|
|
345
|
+
return;
|
|
346
|
+
}
|
|
347
|
+
continue;
|
|
348
|
+
}
|
|
349
|
+
modeResult = result;
|
|
350
|
+
break;
|
|
351
|
+
}
|
|
352
|
+
if (modeResult === "customize") {
|
|
353
|
+
if (needsMcp) {
|
|
354
|
+
const scopeResult = await select({
|
|
355
|
+
message: "Where should the Neon MCP server be configured?",
|
|
356
|
+
options: [{
|
|
357
|
+
value: "global",
|
|
358
|
+
label: "Global (available in all projects)"
|
|
359
|
+
}, {
|
|
360
|
+
value: "project",
|
|
361
|
+
label: "Project-level (this project only)"
|
|
362
|
+
}]
|
|
363
|
+
});
|
|
364
|
+
if (isCancel(scopeResult)) {
|
|
365
|
+
outro("Setup cancelled.");
|
|
366
|
+
return;
|
|
367
|
+
}
|
|
368
|
+
mcpScope = scopeResult;
|
|
369
|
+
}
|
|
370
|
+
if (needsSkills) {
|
|
371
|
+
const skillsScopeResult = await select({
|
|
372
|
+
message: "Where should Neon agent skills be installed?",
|
|
373
|
+
options: [{
|
|
374
|
+
value: "global",
|
|
375
|
+
label: "Global (available in all projects)"
|
|
376
|
+
}, {
|
|
377
|
+
value: "project",
|
|
378
|
+
label: "Project-level (this project only)"
|
|
379
|
+
}],
|
|
380
|
+
initialValue: "project"
|
|
381
|
+
});
|
|
382
|
+
if (isCancel(skillsScopeResult)) {
|
|
383
|
+
outro("Setup cancelled.");
|
|
384
|
+
return;
|
|
385
|
+
}
|
|
386
|
+
skillsScope = skillsScopeResult;
|
|
387
|
+
}
|
|
388
|
+
if (doInstallExtension) {
|
|
389
|
+
const extResult = await confirm({ message: `Install the Neon extension for ${vscodeEditors.join(", ")}?` });
|
|
390
|
+
if (isCancel(extResult)) {
|
|
391
|
+
outro("Setup cancelled.");
|
|
392
|
+
return;
|
|
393
|
+
}
|
|
394
|
+
doInstallExtension = extResult;
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
if (!await isAuthenticated()) {
|
|
398
|
+
const authS = spinner();
|
|
399
|
+
authS.start("Authenticating with Neon...");
|
|
400
|
+
if (!await ensureNeonctlAuth()) {
|
|
401
|
+
authS.stop("Authentication failed.");
|
|
402
|
+
outro("Run neon-init again after signing in.");
|
|
403
|
+
return;
|
|
404
|
+
}
|
|
405
|
+
authS.stop("Authenticated.");
|
|
406
|
+
}
|
|
407
|
+
const nctlS = spinner();
|
|
408
|
+
nctlS.start("Checking neonctl CLI...");
|
|
409
|
+
const nctlResult = await ensureNeonctl();
|
|
410
|
+
switch (nctlResult.status) {
|
|
411
|
+
case "already_current":
|
|
412
|
+
nctlS.stop(dim(`neonctl CLI is up to date (v${nctlResult.version}) ✓`));
|
|
413
|
+
break;
|
|
414
|
+
case "installed":
|
|
415
|
+
nctlS.stop(dim(`Installed neonctl CLI (v${nctlResult.version}) ✓`));
|
|
416
|
+
break;
|
|
417
|
+
case "updated":
|
|
418
|
+
nctlS.stop(dim(`Updated neonctl CLI to v${nctlResult.version} ✓`));
|
|
419
|
+
break;
|
|
420
|
+
case "failed":
|
|
421
|
+
nctlS.stop("Failed to install neonctl CLI");
|
|
422
|
+
log.warn("neonctl could not be installed automatically. The setup will continue using npx.");
|
|
423
|
+
break;
|
|
424
|
+
}
|
|
425
|
+
for (const editor of selectedEditors) {
|
|
426
|
+
if (needsMcp) {
|
|
427
|
+
const mcpArgs = [
|
|
428
|
+
"-y",
|
|
429
|
+
"add-mcp",
|
|
430
|
+
"https://mcp.neon.tech/mcp",
|
|
431
|
+
"-n",
|
|
432
|
+
"Neon",
|
|
433
|
+
"-y",
|
|
434
|
+
"-a",
|
|
435
|
+
getAddMcpAgentId(editor)
|
|
436
|
+
];
|
|
437
|
+
if (mcpScope === "global") mcpArgs.splice(5, 0, "-g");
|
|
438
|
+
const mcpS = spinner();
|
|
439
|
+
mcpS.start(`Installing Neon MCP server for ${editor}...`);
|
|
440
|
+
try {
|
|
441
|
+
await execa("npx", mcpArgs, {
|
|
442
|
+
stdio: "pipe",
|
|
443
|
+
timeout: 6e4
|
|
444
|
+
});
|
|
445
|
+
mcpS.stop(dim(`Neon MCP server configured for ${editor} (${mcpScope}) ✓`));
|
|
446
|
+
} catch (err) {
|
|
447
|
+
const msg = err instanceof Error ? err.message : "Unknown error";
|
|
448
|
+
mcpS.stop(`Failed to configure MCP server for ${editor}`);
|
|
449
|
+
log.error(msg);
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
if (needsSkills) await installAgentSkills([editor], { scope: skillsScope });
|
|
453
|
+
if (doInstallExtension && usesExtension(editor)) {
|
|
454
|
+
const extS = spinner();
|
|
455
|
+
extS.start(`Installing Neon extension for ${editor}...`);
|
|
456
|
+
if (await installExtension(editor)) extS.stop(dim(`Neon extension installed for ${editor} ✓`));
|
|
457
|
+
else extS.stop(`Extension install failed — install manually from the extensions panel.`);
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
editorList = selectedEditors.join(", ");
|
|
461
|
+
}
|
|
462
|
+
const gettingStartedData = {};
|
|
463
|
+
if (hasNeonConnection) gettingStartedData.hasConnectionString = true;
|
|
464
|
+
if (inspection.framework && inspection.framework !== "none") gettingStartedData.framework = inspection.framework;
|
|
465
|
+
if (inspection.orm && inspection.orm !== "none") gettingStartedData.orm = inspection.orm;
|
|
466
|
+
if (inspection.migrationTool && inspection.migrationTool !== "none") gettingStartedData.migrationTool = inspection.migrationTool;
|
|
467
|
+
if (inspection.migrationDir && inspection.migrationDir !== "none") gettingStartedData.migrationDir = inspection.migrationDir;
|
|
468
|
+
if (selectedFeatures.length > 0) gettingStartedData.features = selectedFeatures;
|
|
469
|
+
if (options.preview) gettingStartedData.preview = true;
|
|
470
|
+
const promptLines = [
|
|
471
|
+
"Continue setting up Neon for this project.",
|
|
472
|
+
`Run this command to proceed: neon-init getting-started --json --data '${JSON.stringify(gettingStartedData)}'`,
|
|
473
|
+
"Follow the steps it returns to connect a Neon database, pull environment variables, and verify the connection."
|
|
474
|
+
];
|
|
475
|
+
if (selectedFeatures.includes("auth")) promptLines.push("After the database is connected, it will automatically set up Neon Auth.");
|
|
476
|
+
log.step("Next steps");
|
|
477
|
+
log.message(dim(`Restart ${editorList} to load the Neon MCP server, then copy the following into your agent chat:`));
|
|
478
|
+
log.message(promptLines.map((line) => bold(neonGreenFn(line))).join("\n"));
|
|
479
|
+
outro(dim("Have feedback? Email us at feedback@neon.tech"));
|
|
480
|
+
}
|
|
481
|
+
function agentIdToEditor(agentId) {
|
|
482
|
+
switch (agentId) {
|
|
483
|
+
case "cursor": return "Cursor";
|
|
484
|
+
case "vscode": return "VS Code";
|
|
485
|
+
case "claude-code": return "Claude CLI";
|
|
486
|
+
case "windsurf": return null;
|
|
487
|
+
case "codex": return "Codex";
|
|
488
|
+
case "cline": return "Cline";
|
|
489
|
+
default: return null;
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
//#endregion
|
|
493
|
+
export { interactiveInit };
|
|
494
|
+
|
|
495
|
+
//# sourceMappingURL=interactive.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interactive.js","names":[],"sources":["../src/interactive.ts"],"sourcesContent":["/**\n * Interactive v2 CLI — purpose-built guided flow for humans.\n * Uses the same underlying install functions but with a clean clack-based UX.\n */\n\nimport { existsSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport {\n\tconfirm,\n\tisCancel,\n\tlog,\n\tmultiselect,\n\toutro,\n\tselect,\n\tspinner,\n} from \"@clack/prompts\";\nimport { execa } from \"execa\";\nimport { bold, dim } from \"yoctocolors\";\nimport { ALL_CONFIGURABLE_AGENTS, getAddMcpAgentId } from \"./lib/agents.js\";\nimport { ensureNeonctlAuth, isAuthenticated } from \"./lib/auth.js\";\nimport {\n\ttype BootstrapTemplate,\n\tFALLBACK_TEMPLATES,\n\tfetchTemplates,\n\ttype NeonFeature,\n} from \"./lib/bootstrap.js\";\nimport { detectAgent } from \"./lib/detect-agent.js\";\nimport { detectAvailableEditors } from \"./lib/editors.js\";\nimport {\n\tinstallExtension,\n\tisExtensionInstalled,\n\tusesExtension,\n} from \"./lib/extension.js\";\nimport { inspectProject } from \"./lib/inspect.js\";\nimport { ensureNeonctl } from \"./lib/neonctl.js\";\nimport { installAgentSkills } from \"./lib/skills.js\";\nimport type { Editor } from \"./lib/types.js\";\n\nfunction wordWrap(text: string, width: number): string {\n\treturn text\n\t\t.split(\"\\n\")\n\t\t.map((line) => {\n\t\t\tif (line.length <= width) return line;\n\t\t\tconst words = line.split(\" \");\n\t\t\tconst lines: string[] = [];\n\t\t\tlet current = \"\";\n\t\t\tfor (const word of words) {\n\t\t\t\tif (\n\t\t\t\t\tcurrent.length + word.length + 1 > width &&\n\t\t\t\t\tcurrent.length > 0\n\t\t\t\t) {\n\t\t\t\t\tlines.push(current);\n\t\t\t\t\tcurrent = word;\n\t\t\t\t} else {\n\t\t\t\t\tcurrent = current.length > 0 ? `${current} ${word}` : word;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (current.length > 0) lines.push(current);\n\t\t\treturn lines.join(\"\\n\");\n\t\t})\n\t\t.join(\"\\n\");\n}\n\n// Patch picocolors (used by @clack/prompts) to use Neon green instead of cyan/magenta.\n// clack hardcodes picocolors.cyan() with no theme API, so this is the least invasive override.\nimport picocolors from \"picocolors\";\n\nconst neonGreenFn = (s: string) => `\\x1b[38;2;75;181;120m${s}\\x1b[39m`;\nconst originalCyan = picocolors.cyan;\nconst originalMagenta = picocolors.magenta;\n\nfunction patchClackColors(): () => void {\n\tconst pc = picocolors as unknown as Record<string, unknown>;\n\tpc.cyan = neonGreenFn;\n\tpc.magenta = neonGreenFn;\n\treturn () => {\n\t\tpc.cyan = originalCyan;\n\t\tpc.magenta = originalMagenta;\n\t};\n}\n\nexport interface InteractiveInitOptions {\n\tpreview?: boolean;\n}\n\nexport async function interactiveInit(\n\toptions: InteractiveInitOptions = {},\n): Promise<void> {\n\tconst restoreColors = patchClackColors();\n\ttry {\n\t\tawait interactiveInitInner(options);\n\t} finally {\n\t\trestoreColors();\n\t}\n}\n\nasync function interactiveInitInner(\n\toptions: InteractiveInitOptions,\n): Promise<void> {\n\tconsole.log();\n\tconsole.log(\n\t\t\"\\x1b[38;2;75;181;120m\" +\n\t\t\t[\n\t\t\t\t\" ██╗ ██╗██████╗ ██████╗ ██╗ ██╗\",\n\t\t\t\t\" ███╗ ██║██╔═══╝ ██╔═══██╗███╗ ██║\",\n\t\t\t\t\" ████╗██║██████╗ ██║ ██║████╗██║\",\n\t\t\t\t\" ██╔████║██╔═══╝ ██║ ██║██╔████║\",\n\t\t\t\t\" ██║╚███║██████╗ ╚██████╔╝██║╚███║\",\n\t\t\t\t\" ╚═╝ ╚══╝╚═════╝ ╚═════╝ ╚═╝ ╚══╝\",\n\t\t\t].join(\"\\n\") +\n\t\t\t\"\\x1b[0m\",\n\t);\n\tconsole.log(\n\t\tdim(\n\t\t\twordWrap(\n\t\t\t\t\"\\nLet's get your project set up with Neon. We'll install the MCP server, agent skills, and IDE extension, then connect your app to a database.\\n\",\n\t\t\t\tprocess.stdout.columns || 80,\n\t\t\t),\n\t\t),\n\t);\n\n\tconst detectedAgentId = detectAgent();\n\tconst detectedEditor = detectedAgentId\n\t\t? agentIdToEditor(detectedAgentId)\n\t\t: null;\n\tlet editorList = detectedEditor ?? \"your editor\";\n\n\t// -----------------------------------------------------------------------\n\t// Step 1: Inspect what's already in place\n\t// -----------------------------------------------------------------------\n\tconst inspectSpinner = spinner();\n\tinspectSpinner.start(\"Checking existing configuration...\");\n\tconst inspection = await inspectProject([\n\t\t{ id: \"has_app\", description: \"\", lookFor: [] },\n\t\t{ id: \"mcp_server\", description: \"\", lookFor: [] },\n\t\t{ id: \"skills\", description: \"\", lookFor: [] },\n\t\t{ id: \"connection_string\", description: \"\", lookFor: [] },\n\t\t{ id: \"project_stack\", description: \"\", lookFor: [] },\n\t\t{ id: \"migrations\", description: \"\", lookFor: [] },\n\t\t{ id: \"ide_type\", description: \"\", lookFor: [] },\n\t]);\n\tinspectSpinner.stop(dim(\"Configuration checked ✓\"));\n\n\tconst hasApp = inspection.hasApp === true;\n\tlet selectedFeatures: NeonFeature[] = [];\n\tlet selectedTemplate: BootstrapTemplate | null = null;\n\n\t// Preview mode: bootstrap from template if no app detected\n\tif (options.preview && !hasApp) {\n\t\tlet templates = FALLBACK_TEMPLATES;\n\t\ttry {\n\t\t\tconst fetched = await fetchTemplates();\n\t\t\tif (fetched && fetched.length > 0) templates = fetched;\n\t\t} catch {}\n\n\t\tconst templateResult = await select({\n\t\t\tmessage:\n\t\t\t\t\"No application detected. Would you like to scaffold a new project from a template?\",\n\t\t\toptions: [\n\t\t\t\t...templates.map((t) => ({\n\t\t\t\t\tvalue: t.id,\n\t\t\t\t\tlabel: t.title,\n\t\t\t\t\thint: t.description,\n\t\t\t\t})),\n\t\t\t\t{\n\t\t\t\t\tvalue: \"none\",\n\t\t\t\t\tlabel: \"No thanks — continue without scaffolding\",\n\t\t\t\t},\n\t\t\t],\n\t\t\tinitialValue: templates[0]?.id ?? \"none\",\n\t\t});\n\t\tif (isCancel(templateResult)) {\n\t\t\toutro(\"Setup cancelled.\");\n\t\t\treturn;\n\t\t}\n\t\tif (templateResult !== \"none\") {\n\t\t\tselectedTemplate =\n\t\t\t\ttemplates.find((t) => t.id === templateResult) ?? null;\n\t\t\tif (selectedTemplate) {\n\t\t\t\tselectedFeatures = selectedTemplate.requires;\n\t\t\t\tconst bootstrapS = spinner();\n\t\t\t\tbootstrapS.start(\n\t\t\t\t\t`Scaffolding project from template \"${selectedTemplate.title}\"...`,\n\t\t\t\t);\n\t\t\t\ttry {\n\t\t\t\t\tawait execa(\n\t\t\t\t\t\t\"npx\",\n\t\t\t\t\t\t[\n\t\t\t\t\t\t\t\"neonctl\",\n\t\t\t\t\t\t\t\"bootstrap\",\n\t\t\t\t\t\t\t\".\",\n\t\t\t\t\t\t\t\"--template\",\n\t\t\t\t\t\t\tselectedTemplate.id,\n\t\t\t\t\t\t\t\"--force\",\n\t\t\t\t\t\t],\n\t\t\t\t\t\t{ stdio: \"pipe\", timeout: 120000 },\n\t\t\t\t\t);\n\t\t\t\t\tbootstrapS.stop(\n\t\t\t\t\t\tdim(\n\t\t\t\t\t\t\t`Scaffolded project from \"${selectedTemplate.title}\" ✓`,\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\t\t\t\t} catch (err) {\n\t\t\t\t\tconst msg =\n\t\t\t\t\t\terr instanceof Error ? err.message : \"Unknown error\";\n\t\t\t\t\tbootstrapS.stop(\"Failed to scaffold project\");\n\t\t\t\t\tlog.error(msg);\n\t\t\t\t\toutro(\"Setup failed.\");\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// For brownfield flows (existing app), ask which features to enable\n\tif (!selectedTemplate && hasApp) {\n\t\tconst featuresResult = await select({\n\t\t\tmessage:\n\t\t\t\t\"Which Neon features would you like to enable for this project?\",\n\t\t\toptions: [\n\t\t\t\t{ value: \"database\", label: \"Database\" },\n\t\t\t\t{\n\t\t\t\t\tvalue: \"database,auth\",\n\t\t\t\t\tlabel: \"Database + Neon Auth (adds authentication via Neon)\",\n\t\t\t\t},\n\t\t\t],\n\t\t\tinitialValue: \"database\",\n\t\t});\n\t\tif (isCancel(featuresResult)) {\n\t\t\toutro(\"Setup cancelled.\");\n\t\t\treturn;\n\t\t}\n\t\tselectedFeatures = (featuresResult as string).split(\n\t\t\t\",\",\n\t\t) as NeonFeature[];\n\t}\n\n\t// Write _init metadata to .neon\n\tif (selectedFeatures.length > 0) {\n\t\tconst neonPath = resolve(process.cwd(), \".neon\");\n\t\tlet existing: Record<string, unknown> = {};\n\t\tif (existsSync(neonPath)) {\n\t\t\ttry {\n\t\t\t\texisting = JSON.parse(readFileSync(neonPath, \"utf-8\"));\n\t\t\t} catch {}\n\t\t}\n\t\texisting._init = { features: selectedFeatures };\n\t\twriteFileSync(neonPath, `${JSON.stringify(existing, null, 2)}\\n`);\n\t}\n\n\tconst mcpAlready = inspection.mcpConfigured === true;\n\t// If we bootstrapped, skills come from the template\n\tconst skillsAlready =\n\t\tinspection.skillsInstalled === true || selectedTemplate !== null;\n\tconst hasNeonConnection = inspection.connectionString === true;\n\tconst needsMcp = !mcpAlready;\n\tconst needsSkills = !skillsAlready;\n\tconst needsInstall = needsMcp || needsSkills;\n\n\t// Check if .neon context file exists\n\tconst neonContextPath = resolve(process.cwd(), \".neon\");\n\tconst hasNeonContext =\n\t\texistsSync(neonContextPath) &&\n\t\t(() => {\n\t\t\ttry {\n\t\t\t\tconst content = JSON.parse(\n\t\t\t\t\treadFileSync(neonContextPath, \"utf-8\"),\n\t\t\t\t);\n\t\t\t\treturn !!content.projectId;\n\t\t\t} catch {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t})();\n\n\t// Check if Neon Auth is configured\n\tconst hasNeonAuth = (() => {\n\t\tfor (const envFile of [\".env\", \".env.local\"]) {\n\t\t\tconst envPath = resolve(process.cwd(), envFile);\n\t\t\tif (existsSync(envPath)) {\n\t\t\t\ttry {\n\t\t\t\t\tconst content = readFileSync(envPath, \"utf-8\");\n\t\t\t\t\tif (/^NEON_AUTH_/m.test(content)) return true;\n\t\t\t\t} catch {}\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t})();\n\n\t// Check if extension is installed for the detected editor\n\tlet extensionAlready = false;\n\tif (detectedEditor && usesExtension(detectedEditor)) {\n\t\textensionAlready = await isExtensionInstalled(detectedEditor);\n\t}\n\n\t// If tooling + database are configured, check if there's anything left to do\n\tif (mcpAlready && skillsAlready && hasNeonConnection && hasNeonContext) {\n\t\tlog.step(dim(\"Neon MCP server already configured ✓\"));\n\t\tlog.step(dim(\"Neon agent skills already installed ✓\"));\n\t\tif (extensionAlready)\n\t\t\tlog.step(dim(\"Neon editor extension installed ✓\"));\n\t\tlog.step(dim(\"Neon database connected ✓\"));\n\n\t\tif (hasNeonAuth) {\n\t\t\tlog.step(dim(\"Neon Auth configured ✓\"));\n\t\t\toutro(\n\t\t\t\tdim(\n\t\t\t\t\t\"Your project is fully configured with Neon. Nothing to do.\",\n\t\t\t\t),\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\n\t\t// Neon Auth not configured — ask if they want it\n\t\tconst authResult = await select({\n\t\t\tmessage:\n\t\t\t\t\"Would you like to set up Neon Auth for user authentication?\",\n\t\t\toptions: [\n\t\t\t\t{ value: \"yes\", label: \"Yes, set up Neon Auth\" },\n\t\t\t\t{ value: \"no\", label: \"No, skip for now\" },\n\t\t\t],\n\t\t\tinitialValue: \"no\",\n\t\t});\n\n\t\tif (isCancel(authResult) || authResult === \"no\") {\n\t\t\toutro(\n\t\t\t\tdim(\n\t\t\t\t\t\"Your project is configured with Neon. You can set up Neon Auth later by having your agent run: neon-init neon-auth\",\n\t\t\t\t),\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\n\t\t// Read .neon for project context\n\t\tlet projectId: string | null = null;\n\t\ttry {\n\t\t\tconst neonCtx = JSON.parse(readFileSync(neonContextPath, \"utf-8\"));\n\t\t\tprojectId = neonCtx.projectId ?? null;\n\t\t} catch {}\n\n\t\tlog.step(\"Next steps\");\n\t\tconst promptLines = [\"Set up Neon Auth for this project.\"];\n\t\tif (projectId) promptLines.push(`Project ID: ${projectId}.`);\n\t\tlog.message(dim(\"Copy the following into your agent chat:\"));\n\t\tlog.message(\n\t\t\tpromptLines.map((line) => bold(neonGreenFn(line))).join(\"\\n\"),\n\t\t);\n\t\toutro(dim(\"Have feedback? Email us at feedback@neon.tech\"));\n\t\treturn;\n\t}\n\n\t// Log what's already in place\n\tif (mcpAlready) log.step(dim(\"Neon MCP server already configured ✓\"));\n\tif (skillsAlready) log.step(dim(\"Neon agent skills already installed ✓\"));\n\n\t// -----------------------------------------------------------------------\n\t// Step 3–5: Install what's missing (skip entirely if everything is configured)\n\t// -----------------------------------------------------------------------\n\tif (needsInstall) {\n\t\tconst homeDir = process.env.HOME || process.env.USERPROFILE;\n\t\tif (!homeDir) {\n\t\t\tlog.error(\"Could not determine home directory.\");\n\t\t\toutro(\"Setup failed.\");\n\t\t\treturn;\n\t\t}\n\n\t\tlet selectedEditors: Editor[];\n\t\tif (detectedEditor) {\n\t\t\tselectedEditors = [detectedEditor];\n\t\t} else {\n\t\t\tconst availableEditors = await detectAvailableEditors(homeDir);\n\t\t\tconst editorResponse = await multiselect({\n\t\t\t\tmessage: \"Which editor(s) would you like to configure?\",\n\t\t\t\toptions: ALL_CONFIGURABLE_AGENTS.map((agent) => ({\n\t\t\t\t\tvalue: agent.editor,\n\t\t\t\t\tlabel: agent.editor,\n\t\t\t\t\thint: agent.hint,\n\t\t\t\t})),\n\t\t\t\tinitialValues: availableEditors,\n\t\t\t\trequired: true,\n\t\t\t});\n\t\t\tif (isCancel(editorResponse)) {\n\t\t\t\toutro(\"Setup cancelled.\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tselectedEditors = editorResponse as Editor[];\n\t\t\tif (selectedEditors.length === 0) {\n\t\t\t\tlog.warn(\"No editors selected.\");\n\t\t\t\toutro(\"Setup cancelled.\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n\t\t// Check extension status\n\t\tconst vscodeEditors = selectedEditors.filter(usesExtension);\n\t\tlet extensionAlreadyInstalled = false;\n\t\tif (vscodeEditors.length > 0) {\n\t\t\tconst checks = await Promise.all(\n\t\t\t\tvscodeEditors.map((e) => isExtensionInstalled(e)),\n\t\t\t);\n\t\t\textensionAlreadyInstalled = checks.every(Boolean);\n\t\t\tif (extensionAlreadyInstalled) {\n\t\t\t\tlog.step(dim(\"Neon editor extension already installed ✓\"));\n\t\t\t}\n\t\t}\n\t\tlet doInstallExtension =\n\t\t\tvscodeEditors.length > 0 && !extensionAlreadyInstalled;\n\n\t\t// Build hint showing only what needs installing\n\t\tconst hintParts: string[] = [];\n\t\tif (needsMcp) hintParts.push(\"MCP server (global)\");\n\t\tif (needsSkills) hintParts.push(\"agent skills (project)\");\n\t\tif (doInstallExtension) hintParts.push(\"editor extension\");\n\n\t\t// Installation preferences\n\t\tlet mcpScope: \"global\" | \"project\" = \"global\";\n\t\tlet skillsScope: \"global\" | \"project\" = \"project\";\n\n\t\tlet modeResult: string;\n\t\twhile (true) {\n\t\t\tconst editorName = selectedEditors.join(\", \");\n\t\t\tconst result = await select({\n\t\t\t\tmessage: `Configure ${editorName} for Neon:`,\n\t\t\t\toptions: [\n\t\t\t\t\t{\n\t\t\t\t\t\tvalue: \"defaults\",\n\t\t\t\t\t\tlabel: \"Install with defaults\",\n\t\t\t\t\t\thint: hintParts.join(\", \"),\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tvalue: \"customize\",\n\t\t\t\t\t\tlabel: \"Customize installation\",\n\t\t\t\t\t\thint: \"choose scopes and options\",\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tvalue: \"change_editor\",\n\t\t\t\t\t\tlabel: \"Configure a different editor\",\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t\tinitialValue: \"defaults\",\n\t\t\t});\n\n\t\t\tif (isCancel(result)) {\n\t\t\t\toutro(\"Setup cancelled.\");\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (result === \"change_editor\") {\n\t\t\t\tconst availableEditors = await detectAvailableEditors(homeDir);\n\t\t\t\tconst editorResponse = await multiselect({\n\t\t\t\t\tmessage: \"Which editor(s) would you like to configure?\",\n\t\t\t\t\toptions: ALL_CONFIGURABLE_AGENTS.map((agent) => ({\n\t\t\t\t\t\tvalue: agent.editor,\n\t\t\t\t\t\tlabel: agent.editor,\n\t\t\t\t\t\thint: agent.hint,\n\t\t\t\t\t})),\n\t\t\t\t\tinitialValues: availableEditors,\n\t\t\t\t\trequired: true,\n\t\t\t\t});\n\t\t\t\tif (isCancel(editorResponse)) {\n\t\t\t\t\toutro(\"Setup cancelled.\");\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tselectedEditors = editorResponse as Editor[];\n\t\t\t\tif (selectedEditors.length === 0) {\n\t\t\t\t\toutro(\"Setup cancelled.\");\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tmodeResult = result as string;\n\t\t\tbreak;\n\t\t}\n\n\t\tif (modeResult === \"customize\") {\n\t\t\tif (needsMcp) {\n\t\t\t\tconst scopeResult = await select({\n\t\t\t\t\tmessage: \"Where should the Neon MCP server be configured?\",\n\t\t\t\t\toptions: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tvalue: \"global\",\n\t\t\t\t\t\t\tlabel: \"Global (available in all projects)\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tvalue: \"project\",\n\t\t\t\t\t\t\tlabel: \"Project-level (this project only)\",\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t});\n\t\t\t\tif (isCancel(scopeResult)) {\n\t\t\t\t\toutro(\"Setup cancelled.\");\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tmcpScope = scopeResult as \"global\" | \"project\";\n\t\t\t}\n\n\t\t\tif (needsSkills) {\n\t\t\t\tconst skillsScopeResult = await select({\n\t\t\t\t\tmessage: \"Where should Neon agent skills be installed?\",\n\t\t\t\t\toptions: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tvalue: \"global\",\n\t\t\t\t\t\t\tlabel: \"Global (available in all projects)\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tvalue: \"project\",\n\t\t\t\t\t\t\tlabel: \"Project-level (this project only)\",\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t\tinitialValue: \"project\",\n\t\t\t\t});\n\t\t\t\tif (isCancel(skillsScopeResult)) {\n\t\t\t\t\toutro(\"Setup cancelled.\");\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tskillsScope = skillsScopeResult as \"global\" | \"project\";\n\t\t\t}\n\n\t\t\tif (doInstallExtension) {\n\t\t\t\tconst extResult = await confirm({\n\t\t\t\t\tmessage: `Install the Neon extension for ${vscodeEditors.join(\", \")}?`,\n\t\t\t\t});\n\t\t\t\tif (isCancel(extResult)) {\n\t\t\t\t\toutro(\"Setup cancelled.\");\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tdoInstallExtension = extResult;\n\t\t\t}\n\t\t}\n\n\t\t// Auth check before install\n\t\tconst installAuthed = await isAuthenticated();\n\t\tif (!installAuthed) {\n\t\t\tconst authS = spinner();\n\t\t\tauthS.start(\"Authenticating with Neon...\");\n\t\t\tconst authSuccess = await ensureNeonctlAuth();\n\t\t\tif (!authSuccess) {\n\t\t\t\tauthS.stop(\"Authentication failed.\");\n\t\t\t\toutro(\"Run neon-init again after signing in.\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tauthS.stop(\"Authenticated.\");\n\t\t}\n\n\t\t// Ensure neonctl CLI is installed and up to date\n\t\tconst nctlS = spinner();\n\t\tnctlS.start(\"Checking neonctl CLI...\");\n\t\tconst nctlResult = await ensureNeonctl();\n\t\tswitch (nctlResult.status) {\n\t\t\tcase \"already_current\":\n\t\t\t\tnctlS.stop(\n\t\t\t\t\tdim(`neonctl CLI is up to date (v${nctlResult.version}) ✓`),\n\t\t\t\t);\n\t\t\t\tbreak;\n\t\t\tcase \"installed\":\n\t\t\t\tnctlS.stop(\n\t\t\t\t\tdim(`Installed neonctl CLI (v${nctlResult.version}) ✓`),\n\t\t\t\t);\n\t\t\t\tbreak;\n\t\t\tcase \"updated\":\n\t\t\t\tnctlS.stop(\n\t\t\t\t\tdim(`Updated neonctl CLI to v${nctlResult.version} ✓`),\n\t\t\t\t);\n\t\t\t\tbreak;\n\t\t\tcase \"failed\":\n\t\t\t\tnctlS.stop(\"Failed to install neonctl CLI\");\n\t\t\t\tlog.warn(\n\t\t\t\t\t\"neonctl could not be installed automatically. The setup will continue using npx.\",\n\t\t\t\t);\n\t\t\t\tbreak;\n\t\t}\n\n\t\t// Install only what's missing\n\t\tfor (const editor of selectedEditors) {\n\t\t\tif (needsMcp) {\n\t\t\t\tconst mcpAgentId = getAddMcpAgentId(editor);\n\t\t\t\tconst mcpArgs = [\n\t\t\t\t\t\"-y\",\n\t\t\t\t\t\"add-mcp\",\n\t\t\t\t\t\"https://mcp.neon.tech/mcp\",\n\t\t\t\t\t\"-n\",\n\t\t\t\t\t\"Neon\",\n\t\t\t\t\t\"-y\",\n\t\t\t\t\t\"-a\",\n\t\t\t\t\tmcpAgentId,\n\t\t\t\t];\n\t\t\t\tif (mcpScope === \"global\") mcpArgs.splice(5, 0, \"-g\");\n\n\t\t\t\tconst mcpS = spinner();\n\t\t\t\tmcpS.start(`Installing Neon MCP server for ${editor}...`);\n\t\t\t\ttry {\n\t\t\t\t\tawait execa(\"npx\", mcpArgs, {\n\t\t\t\t\t\tstdio: \"pipe\",\n\t\t\t\t\t\ttimeout: 60000,\n\t\t\t\t\t});\n\t\t\t\t\tmcpS.stop(\n\t\t\t\t\t\tdim(\n\t\t\t\t\t\t\t`Neon MCP server configured for ${editor} (${mcpScope}) ✓`,\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\t\t\t\t} catch (err) {\n\t\t\t\t\tconst msg =\n\t\t\t\t\t\terr instanceof Error ? err.message : \"Unknown error\";\n\t\t\t\t\tmcpS.stop(`Failed to configure MCP server for ${editor}`);\n\t\t\t\t\tlog.error(msg);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (needsSkills) {\n\t\t\t\tawait installAgentSkills([editor], { scope: skillsScope });\n\t\t\t}\n\n\t\t\tif (doInstallExtension && usesExtension(editor)) {\n\t\t\t\tconst extS = spinner();\n\t\t\t\textS.start(`Installing Neon extension for ${editor}...`);\n\t\t\t\tconst extOk = await installExtension(editor);\n\t\t\t\tif (extOk) {\n\t\t\t\t\textS.stop(dim(`Neon extension installed for ${editor} ✓`));\n\t\t\t\t} else {\n\t\t\t\t\textS.stop(\n\t\t\t\t\t\t`Extension install failed — install manually from the extensions panel.`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\teditorList = selectedEditors.join(\", \");\n\t}\n\n\t// -----------------------------------------------------------------------\n\t// Step 6: Done — build prompt for the agent to continue\n\t// -----------------------------------------------------------------------\n\n\t// Build the getting-started data payload (same as agent mode)\n\tconst gettingStartedData: Record<string, unknown> = {};\n\tif (hasNeonConnection) gettingStartedData.hasConnectionString = true;\n\tif (inspection.framework && inspection.framework !== \"none\")\n\t\tgettingStartedData.framework = inspection.framework;\n\tif (inspection.orm && inspection.orm !== \"none\")\n\t\tgettingStartedData.orm = inspection.orm;\n\tif (inspection.migrationTool && inspection.migrationTool !== \"none\")\n\t\tgettingStartedData.migrationTool = inspection.migrationTool;\n\tif (inspection.migrationDir && inspection.migrationDir !== \"none\")\n\t\tgettingStartedData.migrationDir = inspection.migrationDir;\n\tif (selectedFeatures.length > 0)\n\t\tgettingStartedData.features = selectedFeatures;\n\tif (options.preview) gettingStartedData.preview = true;\n\n\tconst dataJson = JSON.stringify(gettingStartedData);\n\n\t// Build a natural-language prompt for the user to paste into their agent\n\tconst promptLines: string[] = [\n\t\t\"Continue setting up Neon for this project.\",\n\t\t`Run this command to proceed: neon-init getting-started --json --data '${dataJson}'`,\n\t\t\"Follow the steps it returns to connect a Neon database, pull environment variables, and verify the connection.\",\n\t];\n\tif (selectedFeatures.includes(\"auth\")) {\n\t\tpromptLines.push(\n\t\t\t\"After the database is connected, it will automatically set up Neon Auth.\",\n\t\t);\n\t}\n\n\tlog.step(\"Next steps\");\n\tlog.message(\n\t\tdim(\n\t\t\t`Restart ${editorList} to load the Neon MCP server, then copy the following into your agent chat:`,\n\t\t),\n\t);\n\tlog.message(promptLines.map((line) => bold(neonGreenFn(line))).join(\"\\n\"));\n\toutro(dim(\"Have feedback? Email us at feedback@neon.tech\"));\n}\n\nfunction agentIdToEditor(agentId: string): Editor | null {\n\tswitch (agentId) {\n\t\tcase \"cursor\":\n\t\t\treturn \"Cursor\";\n\t\tcase \"vscode\":\n\t\t\treturn \"VS Code\";\n\t\tcase \"claude-code\":\n\t\t\treturn \"Claude CLI\";\n\t\tcase \"windsurf\":\n\t\t\t// Windsurf not in Editor type yet — fall back to prompt\n\t\t\treturn null;\n\t\tcase \"codex\":\n\t\t\treturn \"Codex\";\n\t\tcase \"cline\":\n\t\t\treturn \"Cline\";\n\t\tdefault:\n\t\t\treturn null;\n\t}\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { Editor } from "./types.js";
|
|
2
|
+
|
|
3
|
+
//#region src/lib/agents.d.ts
|
|
4
|
+
interface AgentConfig {
|
|
5
|
+
editor: Editor;
|
|
6
|
+
addMcpId: string;
|
|
7
|
+
hint: string;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* All agents that can be configured via neon-init.
|
|
11
|
+
* Aligns with add-mcp's supported agents table.
|
|
12
|
+
* https://github.com/neondatabase/add-mcp#supported-agents
|
|
13
|
+
*/
|
|
14
|
+
declare const ALL_CONFIGURABLE_AGENTS: AgentConfig[];
|
|
15
|
+
declare function getAddMcpAgentId(editor: Editor): string;
|
|
16
|
+
declare function resolveAddMcpAgentId(rawAgent: string): string;
|
|
17
|
+
/**
|
|
18
|
+
* Maps a raw agent identifier to the skills CLI agent name.
|
|
19
|
+
*/
|
|
20
|
+
declare function getSkillsAgentName(agent: string): string;
|
|
21
|
+
//#endregion
|
|
22
|
+
export { ALL_CONFIGURABLE_AGENTS, AgentConfig, getAddMcpAgentId, getSkillsAgentName, resolveAddMcpAgentId };
|
|
23
|
+
//# sourceMappingURL=agents.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agents.d.ts","names":[],"sources":["../../src/lib/agents.ts"],"mappings":";;;UAEiB,WAAA;UACR;EADQ,QAAA,EAAA,MAAW;EAWf,IAAA,EAAA,MAAA;AAiCb;AAqCA;AAaA;;;;cAnFa,yBAAyB;iBAiCtB,gBAAA,SAAyB;iBAqCzB,oBAAA;;;;iBAaA,kBAAA"}
|