neon-init 0.4.1 → 0.7.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/index.d.ts.map +1 -1
- package/dist/index.js +90 -51
- package/dist/index.js.map +1 -1
- package/package.json +4 -3
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/index.ts"],"sourcesContent":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/index.ts"],"sourcesContent":[],"mappings":";;AAsdA;;iBAAsB,IAAA,CAAA,GAAQ"}
|
package/dist/index.js
CHANGED
|
@@ -4,6 +4,7 @@ import { dirname, resolve } from "node:path";
|
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
5
5
|
import { promisify } from "node:util";
|
|
6
6
|
import { confirm, intro, isCancel, log, outro, select, spinner } from "@clack/prompts";
|
|
7
|
+
import { execa } from "execa";
|
|
7
8
|
|
|
8
9
|
//#region src/index.ts
|
|
9
10
|
const execAsync = promisify(exec);
|
|
@@ -14,22 +15,14 @@ const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
|
14
15
|
*/
|
|
15
16
|
async function ensureNeonctlAuth() {
|
|
16
17
|
try {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
"--no-analytics"
|
|
26
|
-
], { stdio: "inherit" });
|
|
27
|
-
meProcess.on("close", (code) => {
|
|
28
|
-
if (code === 0) resolve$1();
|
|
29
|
-
else reject(/* @__PURE__ */ new Error(`Authentication failed with exit code ${code}`));
|
|
30
|
-
});
|
|
31
|
-
meProcess.on("error", reject);
|
|
32
|
-
});
|
|
18
|
+
await execa("npx", [
|
|
19
|
+
"-y",
|
|
20
|
+
"neonctl",
|
|
21
|
+
"me",
|
|
22
|
+
"--output",
|
|
23
|
+
"json",
|
|
24
|
+
"--no-analytics"
|
|
25
|
+
], { stdio: "inherit" });
|
|
33
26
|
return true;
|
|
34
27
|
} catch (error) {
|
|
35
28
|
log.error(`Authentication failed: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
@@ -82,7 +75,7 @@ async function createApiKeyFromNeonctl() {
|
|
|
82
75
|
}
|
|
83
76
|
async function fetchOrganizations() {
|
|
84
77
|
try {
|
|
85
|
-
const { stdout } = await execAsync("npx -y
|
|
78
|
+
const { stdout } = await execAsync("npx -y neonctl orgs list --output json --no-analytics", { maxBuffer: 1024 * 1024 });
|
|
86
79
|
const data = JSON.parse(stdout);
|
|
87
80
|
return Array.isArray(data) ? data.map((org) => ({
|
|
88
81
|
id: org.id,
|
|
@@ -116,13 +109,13 @@ function writeMCPConfig(cursorDir, config) {
|
|
|
116
109
|
writeFileSync(mcpConfigPath, JSON.stringify(config, null, 2), "utf-8");
|
|
117
110
|
}
|
|
118
111
|
/**
|
|
119
|
-
* Gets the
|
|
112
|
+
* Gets the neon.md template with Neon-specific best practices
|
|
120
113
|
*/
|
|
121
|
-
function
|
|
114
|
+
function getNeonMdTemplate() {
|
|
122
115
|
return readFileSync(resolve(__dirname, "../src/agents-template.md"), "utf-8");
|
|
123
116
|
}
|
|
124
117
|
/**
|
|
125
|
-
* Generates the organization configuration section for
|
|
118
|
+
* Generates the organization configuration section for neon.md
|
|
126
119
|
*/
|
|
127
120
|
function getOrgConfigSection(orgId) {
|
|
128
121
|
return `## Neon Project Configuration
|
|
@@ -142,35 +135,66 @@ When using any Neon MCP tools or API calls, always pass this \`org_id\` paramete
|
|
|
142
135
|
`;
|
|
143
136
|
}
|
|
144
137
|
/**
|
|
145
|
-
*
|
|
138
|
+
* Gets the reference text to add to AGENTS.md
|
|
139
|
+
*/
|
|
140
|
+
function getAgentsNeonReference() {
|
|
141
|
+
return `## Working with Neon Database
|
|
142
|
+
|
|
143
|
+
When the user asks to **"Get started with Neon"** or something similar, refer to the detailed guidelines in \`neon.md\`.`;
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Creates or updates neon.md with detailed Neon guidelines
|
|
147
|
+
*/
|
|
148
|
+
async function createNeonMd(orgId) {
|
|
149
|
+
const neonMdPath = resolve(process.cwd(), "neon.md");
|
|
150
|
+
try {
|
|
151
|
+
if (existsSync(neonMdPath)) {
|
|
152
|
+
log.info("neon.md already exists");
|
|
153
|
+
const response = await confirm({
|
|
154
|
+
message: "Replace existing neon.md with updated guidelines? (suggested)",
|
|
155
|
+
initialValue: true
|
|
156
|
+
});
|
|
157
|
+
if (isCancel(response)) return false;
|
|
158
|
+
if (!response) {
|
|
159
|
+
log.info("Keeping existing neon.md");
|
|
160
|
+
return true;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
let content = "";
|
|
164
|
+
if (orgId) content += getOrgConfigSection(orgId);
|
|
165
|
+
content += getNeonMdTemplate();
|
|
166
|
+
writeFileSync(neonMdPath, content, "utf-8");
|
|
167
|
+
log.success(`Created neon.md with detailed guidelines at ${neonMdPath}`);
|
|
168
|
+
return true;
|
|
169
|
+
} catch (error) {
|
|
170
|
+
log.error(`Failed to create neon.md: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
171
|
+
return false;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Creates or updates AGENTS.md with a reference to neon.md
|
|
146
176
|
*/
|
|
147
|
-
async function createAgentsMd(
|
|
177
|
+
async function createAgentsMd() {
|
|
148
178
|
const agentsPath = resolve(process.cwd(), "AGENTS.md");
|
|
149
179
|
try {
|
|
180
|
+
const neonReference = getAgentsNeonReference();
|
|
150
181
|
if (existsSync(agentsPath)) {
|
|
151
182
|
const existingContent = readFileSync(agentsPath, "utf-8");
|
|
152
|
-
if (existingContent.includes("## Neon Database
|
|
153
|
-
log.info("Neon
|
|
183
|
+
if (existingContent.includes("## Working with Neon Database")) {
|
|
184
|
+
log.info("Neon reference already exists in AGENTS.md");
|
|
154
185
|
return true;
|
|
155
186
|
}
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
if (orgId) content += getOrgConfigSection(orgId);
|
|
159
|
-
content += getAgentsMdTemplate();
|
|
160
|
-
writeFileSync(agentsPath, existingContent + separator + content, "utf-8");
|
|
161
|
-
log.success(`Appended Neon best practices to existing AGENTS.md at ${agentsPath}`);
|
|
187
|
+
writeFileSync(agentsPath, existingContent + "\n\n---\n\n" + neonReference, "utf-8");
|
|
188
|
+
log.success(`Appended Neon reference to existing AGENTS.md at ${agentsPath}`);
|
|
162
189
|
} else {
|
|
163
|
-
let content = "";
|
|
164
|
-
if (orgId) content += getOrgConfigSection(orgId);
|
|
165
|
-
content += getAgentsMdTemplate();
|
|
166
190
|
writeFileSync(agentsPath, `# AGENTS.md
|
|
167
191
|
|
|
168
192
|
This file provides guidance to AI coding assistants when working with code in this project.
|
|
169
193
|
|
|
170
194
|
---
|
|
171
195
|
|
|
172
|
-
${
|
|
173
|
-
log.success(`Created AGENTS.md with Neon
|
|
196
|
+
${neonReference}`, "utf-8");
|
|
197
|
+
log.success(`Created AGENTS.md with Neon reference at ${agentsPath}`);
|
|
174
198
|
}
|
|
175
199
|
return true;
|
|
176
200
|
} catch (error) {
|
|
@@ -195,8 +219,8 @@ async function installMCPServer() {
|
|
|
195
219
|
if (alreadyConfigured) {
|
|
196
220
|
log.info("Neon MCP Server is already configured globally");
|
|
197
221
|
const response = await confirm({
|
|
198
|
-
message: "Would you like to reconfigure it?",
|
|
199
|
-
initialValue:
|
|
222
|
+
message: "Would you like to reconfigure it? (suggested)",
|
|
223
|
+
initialValue: true
|
|
200
224
|
});
|
|
201
225
|
if (isCancel(response)) return { success: false };
|
|
202
226
|
shouldReconfigure = response;
|
|
@@ -246,15 +270,9 @@ async function installMCPServer() {
|
|
|
246
270
|
log.info("You can manually create one at: https://console.neon.tech/app/settings/api-keys");
|
|
247
271
|
return { success: false };
|
|
248
272
|
}
|
|
249
|
-
const args = [
|
|
250
|
-
"-y",
|
|
251
|
-
"@neondatabase/mcp-server-neon",
|
|
252
|
-
"start",
|
|
253
|
-
apiKey
|
|
254
|
-
];
|
|
255
273
|
config.mcpServers.Neon = {
|
|
256
|
-
|
|
257
|
-
|
|
274
|
+
url: "https://mcp.neon.tech/mcp",
|
|
275
|
+
headers: { Authorization: `Bearer ${apiKey}` }
|
|
258
276
|
};
|
|
259
277
|
try {
|
|
260
278
|
writeMCPConfig(cursorDir, config);
|
|
@@ -274,24 +292,44 @@ async function installMCPServer() {
|
|
|
274
292
|
*/
|
|
275
293
|
async function init() {
|
|
276
294
|
intro("🚀 Neon Project Initialization");
|
|
295
|
+
const homeDir = process.env.HOME || process.env.USERPROFILE;
|
|
296
|
+
if (!homeDir) {
|
|
297
|
+
log.error("Could not determine home directory");
|
|
298
|
+
process.exit(1);
|
|
299
|
+
}
|
|
300
|
+
if (!existsSync(resolve(homeDir, ".cursor"))) {
|
|
301
|
+
log.warn("This tool currently only supports Cursor IDE.");
|
|
302
|
+
log.info("We'd love to hear which IDE you're using!");
|
|
303
|
+
log.info("");
|
|
304
|
+
log.info("Please send your feedback to: init-feedback@neon.tech");
|
|
305
|
+
log.info("");
|
|
306
|
+
outro("❌ Cursor IDE is required to continue.");
|
|
307
|
+
process.exit(1);
|
|
308
|
+
}
|
|
277
309
|
log.info("This will set up your project with Neon's MCP Server and AI coding best practices.");
|
|
278
|
-
log.step("Step 1/
|
|
310
|
+
log.step("Step 1/3: Configuring Neon MCP Server...");
|
|
279
311
|
const { success: mcpSuccess, orgId } = await installMCPServer();
|
|
280
312
|
if (!mcpSuccess) {
|
|
281
313
|
outro("❌ Initialization cancelled or failed.");
|
|
282
314
|
process.exit(1);
|
|
283
315
|
}
|
|
284
|
-
log.step("Step 2/
|
|
285
|
-
if (!await
|
|
316
|
+
log.step("Step 2/3: Creating neon.md with detailed guidelines...");
|
|
317
|
+
if (!await createNeonMd(orgId)) log.warn("Failed to create neon.md, but MCP Server is configured.");
|
|
318
|
+
log.step("Step 3/3: Creating AGENTS.md for Cursor...");
|
|
319
|
+
if (!await createAgentsMd()) log.warn("Failed to create AGENTS.md, but MCP Server is configured.");
|
|
286
320
|
outro("Success! Neon project initialized.");
|
|
287
321
|
console.log("");
|
|
288
322
|
console.log("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
|
|
289
323
|
console.log("");
|
|
324
|
+
console.log("⚠️ The init command is still in its early stages.");
|
|
325
|
+
console.log(" We'd appreciate any feedback! Send us an email at:");
|
|
326
|
+
console.log(" init-feedback@neon.tech");
|
|
327
|
+
console.log("");
|
|
290
328
|
console.log("Next steps:");
|
|
291
329
|
console.log("");
|
|
292
|
-
console.log(" 1. Restart
|
|
330
|
+
console.log(" 1. Restart Cursor");
|
|
293
331
|
console.log("");
|
|
294
|
-
console.log(" 2. Type this in your
|
|
332
|
+
console.log(" 2. Type this in your Cursor chat to begin:");
|
|
295
333
|
console.log("");
|
|
296
334
|
console.log(" ┌──────────────────────────────────────┐");
|
|
297
335
|
console.log(" │ │");
|
|
@@ -299,7 +337,8 @@ async function init() {
|
|
|
299
337
|
console.log(" │ │");
|
|
300
338
|
console.log(" └──────────────────────────────────────┘");
|
|
301
339
|
console.log("");
|
|
302
|
-
console.log("Your AI assistant now has access to Neon best practices via
|
|
340
|
+
console.log("Your AI assistant now has access to Neon best practices via neon.md");
|
|
341
|
+
console.log("(referenced in AGENTS.md for easy discovery)");
|
|
303
342
|
console.log("");
|
|
304
343
|
console.log("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
|
|
305
344
|
}
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["selectedOrgId: string | undefined"],"sources":["../src/index.ts"],"sourcesContent":["import { exec } from \"node:child_process\";\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { dirname, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { promisify } from \"node:util\";\nimport {\n\tconfirm,\n\tintro,\n\tisCancel,\n\tlog,\n\toutro,\n\tselect,\n\tspinner,\n} from \"@clack/prompts\";\n\nconst execAsync = promisify(exec);\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);\n\ninterface MCPConfig {\n\tmcpServers: {\n\t\t[key: string]: {\n\t\t\tcommand: string;\n\t\t\targs: string[];\n\t\t\tenv?: Record<string, string>;\n\t\t};\n\t};\n}\n\ninterface NeonOrganization {\n\tid: string;\n\tname: string;\n}\n\n/**\n * Ensures neonctl is authenticated by running a command that triggers auth if needed\n * This will automatically start the OAuth flow if the user isn't already authenticated\n */\nasync function ensureNeonctlAuth(): Promise<boolean> {\n\ttry {\n\t\t// Use spawn to show OAuth URL if authentication is needed\n\t\tconst { spawn } = await import(\"node:child_process\");\n\n\t\tawait new Promise<void>((resolve, reject) => {\n\t\t\tconst meProcess = spawn(\n\t\t\t\t\"npx\",\n\t\t\t\t[\"-y\", \"neon\", \"me\", \"--output\", \"json\", \"--no-analytics\"],\n\t\t\t\t{\n\t\t\t\t\tstdio: \"inherit\", // Shows OAuth URL and prompts to the user\n\t\t\t\t},\n\t\t\t);\n\n\t\t\tmeProcess.on(\"close\", (code) => {\n\t\t\t\tif (code === 0) {\n\t\t\t\t\tresolve();\n\t\t\t\t} else {\n\t\t\t\t\treject(\n\t\t\t\t\t\tnew Error(\n\t\t\t\t\t\t\t`Authentication failed with exit code ${code}`,\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tmeProcess.on(\"error\", reject);\n\t\t});\n\n\t\treturn true;\n\t} catch (error) {\n\t\tlog.error(\n\t\t\t`Authentication failed: ${error instanceof Error ? error.message : \"Unknown error\"}`,\n\t\t);\n\t\treturn false;\n\t}\n}\n\n/**\n * Gets the OAuth access token from neonctl's stored credentials\n */\nasync function getNeonctlAccessToken(): Promise<string | null> {\n\ttry {\n\t\tconst homeDir = process.env.HOME || process.env.USERPROFILE;\n\t\tif (!homeDir) return null;\n\n\t\tconst credentialsPath = resolve(\n\t\t\thomeDir,\n\t\t\t\".config\",\n\t\t\t\"neonctl\",\n\t\t\t\"credentials.json\",\n\t\t);\n\t\tif (!existsSync(credentialsPath)) return null;\n\n\t\tconst credentials = JSON.parse(readFileSync(credentialsPath, \"utf-8\"));\n\t\treturn credentials.access_token || null;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\n/**\n * Creates an API key using the Neon API with the OAuth token from neonctl\n */\nasync function createApiKeyFromNeonctl(): Promise<string | null> {\n\ttry {\n\t\tconst accessToken = await getNeonctlAccessToken();\n\t\tif (!accessToken) {\n\t\t\tlog.error(\"Could not find OAuth token from neonctl\");\n\t\t\treturn null;\n\t\t}\n\n\t\t// Generate a unique key name with timestamp\n\t\tconst timestamp = new Date()\n\t\t\t.toISOString()\n\t\t\t.replace(/[:.]/g, \"-\")\n\t\t\t.slice(0, -5); // e.g., 2024-10-08T15-30-45\n\t\tconst keyName = `neonctl-init-${timestamp}`;\n\n\t\t// Call Neon API to create an API key\n\t\tconst response = await fetch(\n\t\t\t\"https://console.neon.tech/api/v2/api_keys\",\n\t\t\t{\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders: {\n\t\t\t\t\tAuthorization: `Bearer ${accessToken}`,\n\t\t\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t\t},\n\t\t\t\tbody: JSON.stringify({\n\t\t\t\t\tkey_name: keyName,\n\t\t\t\t}),\n\t\t\t},\n\t\t);\n\n\t\tif (!response.ok) {\n\t\t\tconst errorText = await response.text();\n\t\t\tlog.error(\n\t\t\t\t`Failed to create API key: ${response.status} ${errorText}`,\n\t\t\t);\n\t\t\treturn null;\n\t\t}\n\n\t\tconst data = await response.json();\n\t\treturn data.key || null;\n\t} catch (error) {\n\t\tlog.error(\n\t\t\t`Failed to create API key: ${error instanceof Error ? error.message : \"Unknown error\"}`,\n\t\t);\n\t\treturn null;\n\t}\n}\n\nasync function fetchOrganizations(): Promise<NeonOrganization[]> {\n\ttry {\n\t\tconst { stdout } = await execAsync(\n\t\t\t\"npx -y neon orgs list --output json --no-analytics\",\n\t\t\t{ maxBuffer: 1024 * 1024 },\n\t\t);\n\n\t\tconst data = JSON.parse(stdout);\n\n\t\t// The neon CLI returns an array of organizations\n\t\tconst organizations: NeonOrganization[] = Array.isArray(data)\n\t\t\t? data.map((org: { id: string; name?: string }) => ({\n\t\t\t\t\tid: org.id,\n\t\t\t\t\tname: org.name || org.id,\n\t\t\t\t}))\n\t\t\t: [];\n\n\t\treturn organizations;\n\t} catch (error) {\n\t\tlog.warn(\n\t\t\t`Unable to fetch organizations: ${error instanceof Error ? error.message : \"Unknown error\"}`,\n\t\t);\n\t\treturn [];\n\t}\n}\n\n/**\n * Gets or creates the .cursor/mcp.json configuration\n */\nfunction getMCPConfig(cursorDir: string): MCPConfig {\n\tconst mcpConfigPath = resolve(cursorDir, \"mcp.json\");\n\n\tif (existsSync(mcpConfigPath)) {\n\t\ttry {\n\t\t\tconst content = readFileSync(mcpConfigPath, \"utf-8\");\n\t\t\treturn JSON.parse(content);\n\t\t} catch (_error) {\n\t\t\tlog.warn(\n\t\t\t\t\"Failed to parse existing mcp.json. Creating a new configuration.\",\n\t\t\t);\n\t\t\treturn { mcpServers: {} };\n\t\t}\n\t}\n\n\treturn { mcpServers: {} };\n}\n\n/**\n * Writes the MCP configuration to .cursor/mcp.json\n */\nfunction writeMCPConfig(cursorDir: string, config: MCPConfig): void {\n\tconst mcpConfigPath = resolve(cursorDir, \"mcp.json\");\n\n\tif (!existsSync(cursorDir)) {\n\t\tmkdirSync(cursorDir, { recursive: true });\n\t}\n\n\twriteFileSync(mcpConfigPath, JSON.stringify(config, null, 2), \"utf-8\");\n}\n\n/**\n * Gets the AGENTS.md template with Neon-specific best practices\n */\nfunction getAgentsMdTemplate(): string {\n\tconst templatePath = resolve(__dirname, \"../src/agents-template.md\");\n\treturn readFileSync(templatePath, \"utf-8\");\n}\n\n/**\n * Generates the organization configuration section for AGENTS.md\n */\nfunction getOrgConfigSection(orgId: string): string {\n\treturn `## Neon Project Configuration\n\n> **🔴 IMPORTANT: You MUST use this organization for all Neon operations in this project.**\n\n**Organization ID:** \\`${orgId}\\`\n\nWhen using any Neon MCP tools or API calls, always pass this \\`org_id\\` parameter. The MCP server is pre-configured with this organization.\n\n**Example:**\n- When listing projects: Use \\`mcp_Neon_list_projects\\` with \\`org_id: \"${orgId}\"\\`\n- When creating resources: Always include \\`org_id: \"${orgId}\"\\` in your tool calls\n\n---\n\n`;\n}\n\n/**\n * Creates or updates AGENTS.md with Neon-specific best practices\n */\nasync function createAgentsMd(orgId?: string): Promise<boolean> {\n\tconst agentsPath = resolve(process.cwd(), \"AGENTS.md\");\n\n\ttry {\n\t\t// Check if AGENTS.md already exists\n\t\tif (existsSync(agentsPath)) {\n\t\t\t// Append to existing file\n\t\t\tconst existingContent = readFileSync(agentsPath, \"utf-8\");\n\n\t\t\t// Check if Neon section already exists to avoid duplicates\n\t\t\tif (existingContent.includes(\"## Neon Database Guidelines\")) {\n\t\t\t\tlog.info(\"Neon guidelines already exist in AGENTS.md\");\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tconst separator = \"\\n\\n---\\n\\n\";\n\t\t\tlet content = \"\";\n\n\t\t\t// Add org ID context if provided\n\t\t\tif (orgId) {\n\t\t\t\tcontent += getOrgConfigSection(orgId);\n\t\t\t}\n\n\t\t\tcontent += getAgentsMdTemplate();\n\n\t\t\tconst updatedContent = existingContent + separator + content;\n\t\t\twriteFileSync(agentsPath, updatedContent, \"utf-8\");\n\t\t\tlog.success(\n\t\t\t\t`Appended Neon best practices to existing AGENTS.md at ${agentsPath}`,\n\t\t\t);\n\t\t} else {\n\t\t\t// Create new file with proper header\n\t\t\tlet content = \"\";\n\n\t\t\t// Add org ID context if provided\n\t\t\tif (orgId) {\n\t\t\t\tcontent += getOrgConfigSection(orgId);\n\t\t\t}\n\n\t\t\tcontent += getAgentsMdTemplate();\n\n\t\t\tconst newContent = `# AGENTS.md\n\nThis file provides guidance to AI coding assistants when working with code in this project.\n\n---\n\n${content}`;\n\t\t\twriteFileSync(agentsPath, newContent, \"utf-8\");\n\t\t\tlog.success(\n\t\t\t\t`Created AGENTS.md with Neon best practices at ${agentsPath}`,\n\t\t\t);\n\t\t}\n\t\treturn true;\n\t} catch (error) {\n\t\tlog.error(\n\t\t\t`Failed to create/update AGENTS.md: ${error instanceof Error ? error.message : \"Unknown error\"}`,\n\t\t);\n\t\treturn false;\n\t}\n}\n\n/**\n * Installs Neon's MCP Server by configuring it globally in ~/.cursor/mcp.json\n * Returns the selected organization ID if one was chosen\n */\nasync function installMCPServer(): Promise<{\n\tsuccess: boolean;\n\torgId?: string;\n}> {\n\tconst homeDir = process.env.HOME || process.env.USERPROFILE;\n\tif (!homeDir) {\n\t\tlog.error(\"Could not determine home directory\");\n\t\treturn { success: false };\n\t}\n\tconst cursorDir = resolve(homeDir, \".cursor\");\n\tconst config = getMCPConfig(cursorDir);\n\n\t// Check if already configured\n\tconst alreadyConfigured = Boolean(config.mcpServers.Neon);\n\tlet shouldReconfigure = false;\n\n\tif (alreadyConfigured) {\n\t\tlog.info(\"Neon MCP Server is already configured globally\");\n\t\tconst response = await confirm({\n\t\t\tmessage: \"Would you like to reconfigure it?\",\n\t\t\tinitialValue: false,\n\t\t});\n\n\t\tif (isCancel(response)) {\n\t\t\treturn { success: false };\n\t\t}\n\n\t\tshouldReconfigure = response as boolean;\n\n\t\tif (!shouldReconfigure) {\n\t\t\tlog.info(\"Keeping existing global configuration.\");\n\t\t}\n\t}\n\n\t// Step 1: Ensure authentication (will trigger OAuth if needed)\n\tlog.step(\"Authenticating with Neon...\");\n\tlog.info(\"The authentication URL will be displayed below if needed.\");\n\tlog.info(\"\");\n\n\tconst authSpinner = spinner();\n\tauthSpinner.start(\"Waiting for authentication...\");\n\n\tconst authSuccess = await ensureNeonctlAuth();\n\n\tif (!authSuccess) {\n\t\tauthSpinner.stop(\"Authentication failed\");\n\t\treturn { success: false };\n\t}\n\n\tauthSpinner.stop(\"Authentication successful ✓\");\n\n\t// Step 2: Fetch organizations and let user select\n\tlet selectedOrgId: string | undefined;\n\n\tconst orgSpinner = spinner();\n\torgSpinner.start(\"Fetching your organizations...\");\n\tconst organizations = await fetchOrganizations();\n\torgSpinner.stop(\n\t\t`Found ${organizations.length} organization${organizations.length !== 1 ? \"s\" : \"\"}`,\n\t);\n\n\tif (organizations.length > 1) {\n\t\tconst orgChoice = await select({\n\t\t\tmessage: \"Select an organization for this project:\",\n\t\t\toptions: organizations.map((org) => ({\n\t\t\t\tvalue: org.id,\n\t\t\t\tlabel: org.name,\n\t\t\t})),\n\t\t});\n\n\t\tif (isCancel(orgChoice)) {\n\t\t\treturn { success: false };\n\t\t}\n\n\t\tselectedOrgId = orgChoice.toString();\n\t\tconst selectedOrg = organizations.find(\n\t\t\t(org) => org.id === selectedOrgId,\n\t\t);\n\t\tlog.success(`Selected organization: ${selectedOrg?.name}`);\n\t} else if (organizations.length === 1) {\n\t\t// Only one org, auto-select it\n\t\tselectedOrgId = organizations[0].id;\n\t\tlog.info(`Using organization: ${organizations[0].name}`);\n\t} else {\n\t\t// No organizations found (personal account)\n\t\tlog.info(\"Using personal account\");\n\t}\n\n\t// If user chose not to reconfigure, we're done (but we still return the org ID)\n\tif (alreadyConfigured && !shouldReconfigure) {\n\t\treturn { success: true, orgId: selectedOrgId };\n\t}\n\n\t// Step 3: Create API key using the OAuth token\n\tconst s = spinner();\n\ts.start(\"Creating API key...\");\n\tconst apiKey = await createApiKeyFromNeonctl();\n\ts.stop(\n\t\tapiKey ? \"API key created successfully ✓\" : \"Failed to create API key\",\n\t);\n\n\tif (!apiKey) {\n\t\tlog.error(\"Could not create API key after authentication.\");\n\t\tlog.info(\n\t\t\t\"You can manually create one at: https://console.neon.tech/app/settings/api-keys\",\n\t\t);\n\t\treturn { success: false };\n\t}\n\n\t// Step 4: Configure Neon MCP Server\n\tconst args = [\"-y\", \"@neondatabase/mcp-server-neon\", \"start\", apiKey];\n\n\tconfig.mcpServers.Neon = {\n\t\tcommand: \"npx\",\n\t\targs,\n\t};\n\n\t// Write configuration\n\ttry {\n\t\twriteMCPConfig(cursorDir, config);\n\t\tlog.success(\n\t\t\t`Neon MCP Server configured globally at ${resolve(cursorDir, \"mcp.json\")}`,\n\t\t);\n\t\tlog.info(\"This configuration will be available in all your projects.\");\n\t\treturn { success: true, orgId: selectedOrgId };\n\t} catch (error) {\n\t\tlog.error(\n\t\t\t`Failed to write global configuration: ${error instanceof Error ? error.message : \"Unknown error\"}`,\n\t\t);\n\t\treturn { success: false };\n\t}\n}\n\n/**\n * Initialize Neon projects with MCP Server and AI assistant rules\n */\nexport async function init(): Promise<void> {\n\tintro(\"🚀 Neon Project Initialization\");\n\n\tlog.info(\n\t\t\"This will set up your project with Neon's MCP Server and AI coding best practices.\",\n\t);\n\n\tlog.step(\"Step 1/2: Configuring Neon MCP Server\");\n\tconst { success: mcpSuccess, orgId } = await installMCPServer();\n\n\tif (!mcpSuccess) {\n\t\toutro(\"❌ Initialization cancelled or failed.\");\n\t\tprocess.exit(1);\n\t}\n\n\tlog.step(\"Step 2/2: Creating AGENTS.md with Neon best practices\");\n\tconst agentsSuccess = await createAgentsMd(orgId);\n\n\tif (!agentsSuccess) {\n\t\tlog.warn(\"Failed to create AGENTS.md, but MCP Server is configured.\");\n\t}\n\n\toutro(\"Success! Neon project initialized.\");\n\tconsole.log(\"\");\n\tconsole.log(\n\t\t\"━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\",\n\t);\n\tconsole.log(\"\");\n\tconsole.log(\"Next steps:\");\n\tconsole.log(\"\");\n\tconsole.log(\n\t\t\" 1. Restart your AI coding assistant (Cursor, Windsurf, etc.)\",\n\t);\n\tconsole.log(\"\");\n\tconsole.log(\" 2. Type this in your AI chat to begin:\");\n\tconsole.log(\"\");\n\tconsole.log(\" ┌──────────────────────────────────────┐\");\n\tconsole.log(\" │ │\");\n\tconsole.log(\" │ Get started with Neon │\");\n\tconsole.log(\" │ │\");\n\tconsole.log(\" └──────────────────────────────────────┘\");\n\tconsole.log(\"\");\n\tconsole.log(\n\t\t\"Your AI assistant now has access to Neon best practices via AGENTS.md\",\n\t);\n\tconsole.log(\"\");\n\tconsole.log(\n\t\t\"━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\",\n\t);\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["selectedOrgId: string | undefined"],"sources":["../src/index.ts"],"sourcesContent":["import { exec } from \"node:child_process\";\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { dirname, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { promisify } from \"node:util\";\nimport {\n\tconfirm,\n\tintro,\n\tisCancel,\n\tlog,\n\toutro,\n\tselect,\n\tspinner,\n} from \"@clack/prompts\";\nimport { execa } from \"execa\";\n\nconst execAsync = promisify(exec);\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);\n\ninterface MCPConfig {\n\tmcpServers: {\n\t\t[key: string]: {\n\t\t\turl: string;\n\t\t\theaders?: Record<string, string>;\n\t\t};\n\t};\n}\n\ninterface NeonOrganization {\n\tid: string;\n\tname: string;\n}\n\n/**\n * Ensures neonctl is authenticated by running a command that triggers auth if needed\n * This will automatically start the OAuth flow if the user isn't already authenticated\n */\nasync function ensureNeonctlAuth(): Promise<boolean> {\n\ttry {\n\t\t// Use execa to authenticate with neonctl\n\t\tawait execa(\n\t\t\t\"npx\",\n\t\t\t[\"-y\", \"neonctl\", \"me\", \"--output\", \"json\", \"--no-analytics\"],\n\t\t\t{\n\t\t\t\tstdio: \"inherit\", // Shows OAuth URL and prompts to the user\n\t\t\t},\n\t\t);\n\n\t\treturn true;\n\t} catch (error) {\n\t\tlog.error(\n\t\t\t`Authentication failed: ${error instanceof Error ? error.message : \"Unknown error\"}`,\n\t\t);\n\t\treturn false;\n\t}\n}\n\n/**\n * Gets the OAuth access token from neonctl's stored credentials\n */\nasync function getNeonctlAccessToken(): Promise<string | null> {\n\ttry {\n\t\tconst homeDir = process.env.HOME || process.env.USERPROFILE;\n\t\tif (!homeDir) return null;\n\n\t\tconst credentialsPath = resolve(\n\t\t\thomeDir,\n\t\t\t\".config\",\n\t\t\t\"neonctl\",\n\t\t\t\"credentials.json\",\n\t\t);\n\t\tif (!existsSync(credentialsPath)) return null;\n\n\t\tconst credentials = JSON.parse(readFileSync(credentialsPath, \"utf-8\"));\n\t\treturn credentials.access_token || null;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\n/**\n * Creates an API key using the Neon API with the OAuth token from neonctl\n */\nasync function createApiKeyFromNeonctl(): Promise<string | null> {\n\ttry {\n\t\tconst accessToken = await getNeonctlAccessToken();\n\t\tif (!accessToken) {\n\t\t\tlog.error(\"Could not find OAuth token from neonctl\");\n\t\t\treturn null;\n\t\t}\n\n\t\t// Generate a unique key name with timestamp\n\t\tconst timestamp = new Date()\n\t\t\t.toISOString()\n\t\t\t.replace(/[:.]/g, \"-\")\n\t\t\t.slice(0, -5); // e.g., 2024-10-08T15-30-45\n\t\tconst keyName = `neonctl-init-${timestamp}`;\n\n\t\t// Call Neon API to create an API key\n\t\tconst response = await fetch(\n\t\t\t\"https://console.neon.tech/api/v2/api_keys\",\n\t\t\t{\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders: {\n\t\t\t\t\tAuthorization: `Bearer ${accessToken}`,\n\t\t\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t\t},\n\t\t\t\tbody: JSON.stringify({\n\t\t\t\t\tkey_name: keyName,\n\t\t\t\t}),\n\t\t\t},\n\t\t);\n\n\t\tif (!response.ok) {\n\t\t\tconst errorText = await response.text();\n\t\t\tlog.error(\n\t\t\t\t`Failed to create API key: ${response.status} ${errorText}`,\n\t\t\t);\n\t\t\treturn null;\n\t\t}\n\n\t\tconst data = await response.json();\n\t\treturn data.key || null;\n\t} catch (error) {\n\t\tlog.error(\n\t\t\t`Failed to create API key: ${error instanceof Error ? error.message : \"Unknown error\"}`,\n\t\t);\n\t\treturn null;\n\t}\n}\n\nasync function fetchOrganizations(): Promise<NeonOrganization[]> {\n\ttry {\n\t\tconst { stdout } = await execAsync(\n\t\t\t\"npx -y neonctl orgs list --output json --no-analytics\",\n\t\t\t{ maxBuffer: 1024 * 1024 },\n\t\t);\n\n\t\tconst data = JSON.parse(stdout);\n\n\t\t// The neon CLI returns an array of organizations\n\t\tconst organizations: NeonOrganization[] = Array.isArray(data)\n\t\t\t? data.map((org: { id: string; name?: string }) => ({\n\t\t\t\t\tid: org.id,\n\t\t\t\t\tname: org.name || org.id,\n\t\t\t\t}))\n\t\t\t: [];\n\n\t\treturn organizations;\n\t} catch (error) {\n\t\tlog.warn(\n\t\t\t`Unable to fetch organizations: ${error instanceof Error ? error.message : \"Unknown error\"}`,\n\t\t);\n\t\treturn [];\n\t}\n}\n\n/**\n * Gets or creates the .cursor/mcp.json configuration\n */\nfunction getMCPConfig(cursorDir: string): MCPConfig {\n\tconst mcpConfigPath = resolve(cursorDir, \"mcp.json\");\n\n\tif (existsSync(mcpConfigPath)) {\n\t\ttry {\n\t\t\tconst content = readFileSync(mcpConfigPath, \"utf-8\");\n\t\t\treturn JSON.parse(content);\n\t\t} catch (_error) {\n\t\t\tlog.warn(\n\t\t\t\t\"Failed to parse existing mcp.json. Creating a new configuration.\",\n\t\t\t);\n\t\t\treturn { mcpServers: {} };\n\t\t}\n\t}\n\n\treturn { mcpServers: {} };\n}\n\n/**\n * Writes the MCP configuration to .cursor/mcp.json\n */\nfunction writeMCPConfig(cursorDir: string, config: MCPConfig): void {\n\tconst mcpConfigPath = resolve(cursorDir, \"mcp.json\");\n\n\tif (!existsSync(cursorDir)) {\n\t\tmkdirSync(cursorDir, { recursive: true });\n\t}\n\n\twriteFileSync(mcpConfigPath, JSON.stringify(config, null, 2), \"utf-8\");\n}\n\n/**\n * Gets the neon.md template with Neon-specific best practices\n */\nfunction getNeonMdTemplate(): string {\n\tconst templatePath = resolve(__dirname, \"../src/agents-template.md\");\n\treturn readFileSync(templatePath, \"utf-8\");\n}\n\n/**\n * Generates the organization configuration section for neon.md\n */\nfunction getOrgConfigSection(orgId: string): string {\n\treturn `## Neon Project Configuration\n\n> **🔴 IMPORTANT: You MUST use this organization for all Neon operations in this project.**\n\n**Organization ID:** \\`${orgId}\\`\n\nWhen using any Neon MCP tools or API calls, always pass this \\`org_id\\` parameter. The MCP server is pre-configured with this organization.\n\n**Example:**\n- When listing projects: Use \\`mcp_Neon_list_projects\\` with \\`org_id: \"${orgId}\"\\`\n- When creating resources: Always include \\`org_id: \"${orgId}\"\\` in your tool calls\n\n---\n\n`;\n}\n\n/**\n * Gets the reference text to add to AGENTS.md\n */\nfunction getAgentsNeonReference(): string {\n\treturn `## Working with Neon Database\n\nWhen the user asks to **\"Get started with Neon\"** or something similar, refer to the detailed guidelines in \\`neon.md\\`.`;\n}\n\n/**\n * Creates or updates neon.md with detailed Neon guidelines\n */\nasync function createNeonMd(orgId?: string): Promise<boolean> {\n\tconst neonMdPath = resolve(process.cwd(), \"neon.md\");\n\n\ttry {\n\t\t// Check if neon.md already exists\n\t\tif (existsSync(neonMdPath)) {\n\t\t\tlog.info(\"neon.md already exists\");\n\t\t\tconst response = await confirm({\n\t\t\t\tmessage:\n\t\t\t\t\t\"Replace existing neon.md with updated guidelines? (suggested)\",\n\t\t\t\tinitialValue: true,\n\t\t\t});\n\n\t\t\tif (isCancel(response)) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tif (!response) {\n\t\t\t\tlog.info(\"Keeping existing neon.md\");\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\n\t\tlet content = \"\";\n\n\t\t// Add org ID context if provided\n\t\tif (orgId) {\n\t\t\tcontent += getOrgConfigSection(orgId);\n\t\t}\n\n\t\tcontent += getNeonMdTemplate();\n\n\t\twriteFileSync(neonMdPath, content, \"utf-8\");\n\t\tlog.success(\n\t\t\t`Created neon.md with detailed guidelines at ${neonMdPath}`,\n\t\t);\n\t\treturn true;\n\t} catch (error) {\n\t\tlog.error(\n\t\t\t`Failed to create neon.md: ${error instanceof Error ? error.message : \"Unknown error\"}`,\n\t\t);\n\t\treturn false;\n\t}\n}\n\n/**\n * Creates or updates AGENTS.md with a reference to neon.md\n */\nasync function createAgentsMd(): Promise<boolean> {\n\tconst agentsPath = resolve(process.cwd(), \"AGENTS.md\");\n\n\ttry {\n\t\tconst neonReference = getAgentsNeonReference();\n\n\t\t// Check if AGENTS.md already exists\n\t\tif (existsSync(agentsPath)) {\n\t\t\t// Append to existing file\n\t\t\tconst existingContent = readFileSync(agentsPath, \"utf-8\");\n\n\t\t\t// Check if Neon section already exists to avoid duplicates\n\t\t\tif (existingContent.includes(\"## Working with Neon Database\")) {\n\t\t\t\tlog.info(\"Neon reference already exists in AGENTS.md\");\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tconst separator = \"\\n\\n---\\n\\n\";\n\t\t\tconst updatedContent = existingContent + separator + neonReference;\n\t\t\twriteFileSync(agentsPath, updatedContent, \"utf-8\");\n\t\t\tlog.success(\n\t\t\t\t`Appended Neon reference to existing AGENTS.md at ${agentsPath}`,\n\t\t\t);\n\t\t} else {\n\t\t\t// Create new file with proper header\n\t\t\tconst newContent = `# AGENTS.md\n\nThis file provides guidance to AI coding assistants when working with code in this project.\n\n---\n\n${neonReference}`;\n\t\t\twriteFileSync(agentsPath, newContent, \"utf-8\");\n\t\t\tlog.success(\n\t\t\t\t`Created AGENTS.md with Neon reference at ${agentsPath}`,\n\t\t\t);\n\t\t}\n\t\treturn true;\n\t} catch (error) {\n\t\tlog.error(\n\t\t\t`Failed to create/update AGENTS.md: ${error instanceof Error ? error.message : \"Unknown error\"}`,\n\t\t);\n\t\treturn false;\n\t}\n}\n\n/**\n * Installs Neon's MCP Server by configuring it globally in ~/.cursor/mcp.json\n * Returns the selected organization ID if one was chosen\n */\nasync function installMCPServer(): Promise<{\n\tsuccess: boolean;\n\torgId?: string;\n}> {\n\tconst homeDir = process.env.HOME || process.env.USERPROFILE;\n\tif (!homeDir) {\n\t\tlog.error(\"Could not determine home directory\");\n\t\treturn { success: false };\n\t}\n\tconst cursorDir = resolve(homeDir, \".cursor\");\n\tconst config = getMCPConfig(cursorDir);\n\n\t// Check if already configured\n\tconst alreadyConfigured = Boolean(config.mcpServers.Neon);\n\tlet shouldReconfigure = false;\n\n\tif (alreadyConfigured) {\n\t\tlog.info(\"Neon MCP Server is already configured globally\");\n\t\tconst response = await confirm({\n\t\t\tmessage: \"Would you like to reconfigure it? (suggested)\",\n\t\t\tinitialValue: true,\n\t\t});\n\n\t\tif (isCancel(response)) {\n\t\t\treturn { success: false };\n\t\t}\n\n\t\tshouldReconfigure = response as boolean;\n\n\t\tif (!shouldReconfigure) {\n\t\t\tlog.info(\"Keeping existing global configuration.\");\n\t\t}\n\t}\n\n\t// Step 1: Ensure authentication (will trigger OAuth if needed)\n\tlog.step(\"Authenticating with Neon...\");\n\tlog.info(\"The authentication URL will be displayed below if needed.\");\n\tlog.info(\"\");\n\n\tconst authSpinner = spinner();\n\tauthSpinner.start(\"Waiting for authentication...\");\n\n\tconst authSuccess = await ensureNeonctlAuth();\n\n\tif (!authSuccess) {\n\t\tauthSpinner.stop(\"Authentication failed\");\n\t\treturn { success: false };\n\t}\n\n\tauthSpinner.stop(\"Authentication successful ✓\");\n\n\t// Step 2: Fetch organizations and let user select\n\tlet selectedOrgId: string | undefined;\n\n\tconst orgSpinner = spinner();\n\torgSpinner.start(\"Fetching your organizations...\");\n\tconst organizations = await fetchOrganizations();\n\torgSpinner.stop(\n\t\t`Found ${organizations.length} organization${organizations.length !== 1 ? \"s\" : \"\"}`,\n\t);\n\n\tif (organizations.length > 1) {\n\t\tconst orgChoice = await select({\n\t\t\tmessage: \"Select an organization for this project:\",\n\t\t\toptions: organizations.map((org) => ({\n\t\t\t\tvalue: org.id,\n\t\t\t\tlabel: org.name,\n\t\t\t})),\n\t\t});\n\n\t\tif (isCancel(orgChoice)) {\n\t\t\treturn { success: false };\n\t\t}\n\n\t\tselectedOrgId = orgChoice.toString();\n\t\tconst selectedOrg = organizations.find(\n\t\t\t(org) => org.id === selectedOrgId,\n\t\t);\n\t\tlog.success(`Selected organization: ${selectedOrg?.name}`);\n\t} else if (organizations.length === 1) {\n\t\t// Only one org, auto-select it\n\t\tselectedOrgId = organizations[0].id;\n\t\tlog.info(`Using organization: ${organizations[0].name}`);\n\t} else {\n\t\t// No organizations found (personal account)\n\t\tlog.info(\"Using personal account\");\n\t}\n\n\t// If user chose not to reconfigure, we're done (but we still return the org ID)\n\tif (alreadyConfigured && !shouldReconfigure) {\n\t\treturn { success: true, orgId: selectedOrgId };\n\t}\n\n\t// Step 3: Create API key using the OAuth token\n\tconst s = spinner();\n\ts.start(\"Creating API key...\");\n\tconst apiKey = await createApiKeyFromNeonctl();\n\ts.stop(\n\t\tapiKey ? \"API key created successfully ✓\" : \"Failed to create API key\",\n\t);\n\n\tif (!apiKey) {\n\t\tlog.error(\"Could not create API key after authentication.\");\n\t\tlog.info(\n\t\t\t\"You can manually create one at: https://console.neon.tech/app/settings/api-keys\",\n\t\t);\n\t\treturn { success: false };\n\t}\n\n\t// Step 4: Configure Neon MCP Server\n\t// Using remote MCP server with API key authentication\n\t// Ref: https://neon.com/docs/ai/neon-mcp-server#api-key-based-authentication\n\tconfig.mcpServers.Neon = {\n\t\turl: \"https://mcp.neon.tech/mcp\",\n\t\theaders: {\n\t\t\tAuthorization: `Bearer ${apiKey}`,\n\t\t},\n\t};\n\n\t// Write configuration\n\ttry {\n\t\twriteMCPConfig(cursorDir, config);\n\t\tlog.success(\n\t\t\t`Neon MCP Server configured globally at ${resolve(cursorDir, \"mcp.json\")}`,\n\t\t);\n\t\tlog.info(\"This configuration will be available in all your projects.\");\n\t\treturn { success: true, orgId: selectedOrgId };\n\t} catch (error) {\n\t\tlog.error(\n\t\t\t`Failed to write global configuration: ${error instanceof Error ? error.message : \"Unknown error\"}`,\n\t\t);\n\t\treturn { success: false };\n\t}\n}\n\n/**\n * Initialize Neon projects with MCP Server and AI assistant rules\n */\nexport async function init(): Promise<void> {\n\tintro(\"🚀 Neon Project Initialization\");\n\n\t// Check if Cursor is installed\n\tconst homeDir = process.env.HOME || process.env.USERPROFILE;\n\tif (!homeDir) {\n\t\tlog.error(\"Could not determine home directory\");\n\t\tprocess.exit(1);\n\t}\n\n\tconst cursorDir = resolve(homeDir, \".cursor\");\n\tif (!existsSync(cursorDir)) {\n\t\tlog.warn(\"This tool currently only supports Cursor IDE.\");\n\t\tlog.info(\"We'd love to hear which IDE you're using!\");\n\t\tlog.info(\"\");\n\t\tlog.info(\"Please send your feedback to: init-feedback@neon.tech\");\n\t\tlog.info(\"\");\n\t\toutro(\"❌ Cursor IDE is required to continue.\");\n\t\tprocess.exit(1);\n\t}\n\n\tlog.info(\n\t\t\"This will set up your project with Neon's MCP Server and AI coding best practices.\",\n\t);\n\n\tlog.step(\"Step 1/3: Configuring Neon MCP Server...\");\n\tconst { success: mcpSuccess, orgId } = await installMCPServer();\n\n\tif (!mcpSuccess) {\n\t\toutro(\"❌ Initialization cancelled or failed.\");\n\t\tprocess.exit(1);\n\t}\n\n\tlog.step(\"Step 2/3: Creating neon.md with detailed guidelines...\");\n\tconst neonMdSuccess = await createNeonMd(orgId);\n\n\tif (!neonMdSuccess) {\n\t\tlog.warn(\"Failed to create neon.md, but MCP Server is configured.\");\n\t}\n\n\tlog.step(\"Step 3/3: Creating AGENTS.md for Cursor...\");\n\tconst agentsSuccess = await createAgentsMd();\n\n\tif (!agentsSuccess) {\n\t\tlog.warn(\"Failed to create AGENTS.md, but MCP Server is configured.\");\n\t}\n\n\toutro(\"Success! Neon project initialized.\");\n\tconsole.log(\"\");\n\tconsole.log(\n\t\t\"━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\",\n\t);\n\tconsole.log(\"\");\n\tconsole.log(\"⚠️ The init command is still in its early stages.\");\n\tconsole.log(\" We'd appreciate any feedback! Send us an email at:\");\n\tconsole.log(\" init-feedback@neon.tech\");\n\tconsole.log(\"\");\n\tconsole.log(\"Next steps:\");\n\tconsole.log(\"\");\n\tconsole.log(\" 1. Restart Cursor\");\n\tconsole.log(\"\");\n\tconsole.log(\" 2. Type this in your Cursor chat to begin:\");\n\tconsole.log(\"\");\n\tconsole.log(\" ┌──────────────────────────────────────┐\");\n\tconsole.log(\" │ │\");\n\tconsole.log(\" │ Get started with Neon │\");\n\tconsole.log(\" │ │\");\n\tconsole.log(\" └──────────────────────────────────────┘\");\n\tconsole.log(\"\");\n\tconsole.log(\n\t\t\"Your AI assistant now has access to Neon best practices via neon.md\",\n\t);\n\tconsole.log(\"(referenced in AGENTS.md for easy discovery)\");\n\tconsole.log(\"\");\n\tconsole.log(\n\t\t\"━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\",\n\t);\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "neon-init",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"description": "Initialize Neon projects",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"neon",
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
"src/agents-template.md"
|
|
36
36
|
],
|
|
37
37
|
"devDependencies": {
|
|
38
|
-
"@types/node": "
|
|
38
|
+
"@types/node": "^20.19.0",
|
|
39
39
|
"@vitest/coverage-v8": "3.0.9",
|
|
40
40
|
"console-fail-test": "0.5.0",
|
|
41
41
|
"tsdown": "^0.14.1",
|
|
@@ -43,7 +43,8 @@
|
|
|
43
43
|
"vitest": "^3.0.9"
|
|
44
44
|
},
|
|
45
45
|
"dependencies": {
|
|
46
|
-
"@clack/prompts": "0.10.1"
|
|
46
|
+
"@clack/prompts": "0.10.1",
|
|
47
|
+
"execa": "^9.5.2"
|
|
47
48
|
},
|
|
48
49
|
"engines": {
|
|
49
50
|
"node": ">=20.19.0"
|