neon-init 0.7.0 → 0.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../src/index.ts"],"sourcesContent":[],"mappings":";;AAsdA;;iBAAsB,IAAA,CAAA,GAAQ"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../src/index.ts"],"sourcesContent":[],"mappings":";;AAwbA;;iBAAsB,IAAA,CAAA,GAAQ"}
package/dist/index.js CHANGED
@@ -3,8 +3,9 @@ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
3
3
  import { dirname, resolve } from "node:path";
4
4
  import { fileURLToPath } from "node:url";
5
5
  import { promisify } from "node:util";
6
- import { confirm, intro, isCancel, log, outro, select, spinner } from "@clack/prompts";
6
+ import { confirm, intro, isCancel, log, note, outro, select, spinner } from "@clack/prompts";
7
7
  import { execa } from "execa";
8
+ import { bold, cyan } from "yoctocolors";
8
9
 
9
10
  //#region src/index.ts
10
11
  const execAsync = promisify(exec);
@@ -19,8 +20,6 @@ async function ensureNeonctlAuth() {
19
20
  "-y",
20
21
  "neonctl",
21
22
  "me",
22
- "--output",
23
- "json",
24
23
  "--no-analytics"
25
24
  ], { stdio: "inherit" });
26
25
  return true;
@@ -140,39 +139,36 @@ When using any Neon MCP tools or API calls, always pass this \`org_id\` paramete
140
139
  function getAgentsNeonReference() {
141
140
  return `## Working with Neon Database
142
141
 
143
- When the user asks to **"Get started with Neon"** or something similar, refer to the detailed guidelines in \`neon.md\`.`;
142
+ When the user asks to **"Get started with Neon"** or something similar, refer to the detailed guidelines in \`.neon/AGENTS.md\`.`;
144
143
  }
145
144
  /**
146
- * Creates or updates neon.md with detailed Neon guidelines
145
+ * Creates or updates .neon/AGENTS.md with detailed Neon guidelines
147
146
  */
148
147
  async function createNeonMd(orgId) {
149
- const neonMdPath = resolve(process.cwd(), "neon.md");
148
+ const neonDir = resolve(process.cwd(), ".neon");
149
+ const neonAgentsPath = resolve(neonDir, "AGENTS.md");
150
150
  try {
151
- if (existsSync(neonMdPath)) {
152
- log.info("neon.md already exists");
151
+ if (!existsSync(neonDir)) mkdirSync(neonDir, { recursive: true });
152
+ if (existsSync(neonAgentsPath)) {
153
153
  const response = await confirm({
154
- message: "Replace existing neon.md with updated guidelines? (suggested)",
154
+ message: "Replace existing .neon/AGENTS.md with updated guidelines? (suggested)",
155
155
  initialValue: true
156
156
  });
157
157
  if (isCancel(response)) return false;
158
- if (!response) {
159
- log.info("Keeping existing neon.md");
160
- return true;
161
- }
158
+ if (!response) return true;
162
159
  }
163
160
  let content = "";
164
161
  if (orgId) content += getOrgConfigSection(orgId);
165
162
  content += getNeonMdTemplate();
166
- writeFileSync(neonMdPath, content, "utf-8");
167
- log.success(`Created neon.md with detailed guidelines at ${neonMdPath}`);
163
+ writeFileSync(neonAgentsPath, content, "utf-8");
168
164
  return true;
169
165
  } catch (error) {
170
- log.error(`Failed to create neon.md: ${error instanceof Error ? error.message : "Unknown error"}`);
166
+ log.error(`Failed to create .neon/AGENTS.md: ${error instanceof Error ? error.message : "Unknown error"}`);
171
167
  return false;
172
168
  }
173
169
  }
174
170
  /**
175
- * Creates or updates AGENTS.md with a reference to neon.md
171
+ * Creates or updates AGENTS.md with a reference to .neon/AGENTS.md
176
172
  */
177
173
  async function createAgentsMd() {
178
174
  const agentsPath = resolve(process.cwd(), "AGENTS.md");
@@ -180,22 +176,15 @@ async function createAgentsMd() {
180
176
  const neonReference = getAgentsNeonReference();
181
177
  if (existsSync(agentsPath)) {
182
178
  const existingContent = readFileSync(agentsPath, "utf-8");
183
- if (existingContent.includes("## Working with Neon Database")) {
184
- log.info("Neon reference already exists in AGENTS.md");
185
- return true;
186
- }
179
+ if (existingContent.includes("## Working with Neon Database")) return true;
187
180
  writeFileSync(agentsPath, existingContent + "\n\n---\n\n" + neonReference, "utf-8");
188
- log.success(`Appended Neon reference to existing AGENTS.md at ${agentsPath}`);
189
- } else {
190
- writeFileSync(agentsPath, `# AGENTS.md
181
+ } else writeFileSync(agentsPath, `# AGENTS.md
191
182
 
192
183
  This file provides guidance to AI coding assistants when working with code in this project.
193
184
 
194
185
  ---
195
186
 
196
187
  ${neonReference}`, "utf-8");
197
- log.success(`Created AGENTS.md with Neon reference at ${agentsPath}`);
198
- }
199
188
  return true;
200
189
  } catch (error) {
201
190
  log.error(`Failed to create/update AGENTS.md: ${error instanceof Error ? error.message : "Unknown error"}`);
@@ -217,30 +206,23 @@ async function installMCPServer() {
217
206
  const alreadyConfigured = Boolean(config.mcpServers.Neon);
218
207
  let shouldReconfigure = false;
219
208
  if (alreadyConfigured) {
220
- log.info("Neon MCP Server is already configured globally");
221
209
  const response = await confirm({
222
- message: "Would you like to reconfigure it? (suggested)",
210
+ message: "Neon MCP Server is already configured. Would you like to reconfigure it? (Y/n)",
223
211
  initialValue: true
224
212
  });
225
213
  if (isCancel(response)) return { success: false };
226
214
  shouldReconfigure = response;
227
215
  if (!shouldReconfigure) log.info("Keeping existing global configuration.");
228
216
  }
229
- log.step("Authenticating with Neon...");
230
- log.info("The authentication URL will be displayed below if needed.");
231
- log.info("");
232
217
  const authSpinner = spinner();
233
- authSpinner.start("Waiting for authentication...");
218
+ authSpinner.start("Authenticating...");
234
219
  if (!await ensureNeonctlAuth()) {
235
220
  authSpinner.stop("Authentication failed");
236
221
  return { success: false };
237
222
  }
238
223
  authSpinner.stop("Authentication successful ✓");
239
224
  let selectedOrgId;
240
- const orgSpinner = spinner();
241
- orgSpinner.start("Fetching your organizations...");
242
225
  const organizations = await fetchOrganizations();
243
- orgSpinner.stop(`Found ${organizations.length} organization${organizations.length !== 1 ? "s" : ""}`);
244
226
  if (organizations.length > 1) {
245
227
  const orgChoice = await select({
246
228
  message: "Select an organization for this project:",
@@ -251,8 +233,6 @@ async function installMCPServer() {
251
233
  });
252
234
  if (isCancel(orgChoice)) return { success: false };
253
235
  selectedOrgId = orgChoice.toString();
254
- const selectedOrg = organizations.find((org) => org.id === selectedOrgId);
255
- log.success(`Selected organization: ${selectedOrg?.name}`);
256
236
  } else if (organizations.length === 1) {
257
237
  selectedOrgId = organizations[0].id;
258
238
  log.info(`Using organization: ${organizations[0].name}`);
@@ -261,10 +241,7 @@ async function installMCPServer() {
261
241
  success: true,
262
242
  orgId: selectedOrgId
263
243
  };
264
- const s = spinner();
265
- s.start("Creating API key...");
266
244
  const apiKey = await createApiKeyFromNeonctl();
267
- s.stop(apiKey ? "API key created successfully ✓" : "Failed to create API key");
268
245
  if (!apiKey) {
269
246
  log.error("Could not create API key after authentication.");
270
247
  log.info("You can manually create one at: https://console.neon.tech/app/settings/api-keys");
@@ -276,8 +253,6 @@ async function installMCPServer() {
276
253
  };
277
254
  try {
278
255
  writeMCPConfig(cursorDir, config);
279
- log.success(`Neon MCP Server configured globally at ${resolve(cursorDir, "mcp.json")}`);
280
- log.info("This configuration will be available in all your projects.");
281
256
  return {
282
257
  success: true,
283
258
  orgId: selectedOrgId
@@ -291,56 +266,29 @@ async function installMCPServer() {
291
266
  * Initialize Neon projects with MCP Server and AI assistant rules
292
267
  */
293
268
  async function init() {
294
- intro("🚀 Neon Project Initialization");
269
+ intro("Adding Neon to your project");
295
270
  const homeDir = process.env.HOME || process.env.USERPROFILE;
296
271
  if (!homeDir) {
297
272
  log.error("Could not determine home directory");
298
273
  process.exit(1);
299
274
  }
300
275
  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.");
276
+ log.warn("Cursor not found.");
277
+ log.warn("Error: Cursor is required to continue. Support for additional agents is coming soon.");
278
+ outro("📣 Is this unexpected? Email us at feedback@neon.tech");
307
279
  process.exit(1);
308
280
  }
309
- log.info("This will set up your project with Neon's MCP Server and AI coding best practices.");
310
- log.step("Step 1/3: Configuring Neon MCP Server...");
311
281
  const { success: mcpSuccess, orgId } = await installMCPServer();
312
282
  if (!mcpSuccess) {
313
- outro("Initialization cancelled or failed.");
283
+ outro("Initialization cancelled or failed. Please check the output above and try again.");
314
284
  process.exit(1);
315
- }
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...");
285
+ } else log.step("Installed Neon MCP server");
286
+ if (!await createNeonMd(orgId)) log.warn("Failed to create .neon/AGENTS.md, but MCP Server is configured.");
319
287
  if (!await createAgentsMd()) log.warn("Failed to create AGENTS.md, but MCP Server is configured.");
320
- outro("Success! Neon project initialized.");
321
- console.log("");
322
- console.log("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
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("");
328
- console.log("Next steps:");
329
- console.log("");
330
- console.log(" 1. Restart Cursor");
331
- console.log("");
332
- console.log(" 2. Type this in your Cursor chat to begin:");
333
- console.log("");
334
- console.log(" ┌──────────────────────────────────────┐");
335
- console.log(" │ │");
336
- console.log(" │ Get started with Neon │");
337
- console.log(" │ │");
338
- console.log(" └──────────────────────────────────────┘");
339
- console.log("");
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)");
342
- console.log("");
343
- console.log("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
288
+ else log.step("Added Neon instructions to AGENTS.md");
289
+ log.step("Success! Neon is now ready to use with Cursor.\n");
290
+ note(`\x1b[0mAsk Cursor to "${bold(cyan("Get started with Neon"))}\x1b[0m" in the chat`, "What's next?");
291
+ outro("Have feedback? Email us at feedback@neon.tech");
344
292
  }
345
293
 
346
294
  //#endregion
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\";\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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"}
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\tnote,\n\toutro,\n\tselect,\n\tspinner,\n} from \"@clack/prompts\";\nimport { execa } from \"execa\";\nimport { bold, cyan } from \"yoctocolors\";\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(\"npx\", [\"-y\", \"neonctl\", \"me\", \"--no-analytics\"], {\n\t\t\tstdio: \"inherit\", // Shows OAuth URL and prompts to the user\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/AGENTS.md\\`.`;\n}\n\n/**\n * Creates or updates .neon/AGENTS.md with detailed Neon guidelines\n */\nasync function createNeonMd(orgId?: string): Promise<boolean> {\n\tconst neonDir = resolve(process.cwd(), \".neon\");\n\tconst neonAgentsPath = resolve(neonDir, \"AGENTS.md\");\n\n\ttry {\n\t\t// Create .neon directory if it doesn't exist\n\t\tif (!existsSync(neonDir)) {\n\t\t\tmkdirSync(neonDir, { recursive: true });\n\t\t}\n\n\t\t// Check if .neon/AGENTS.md already exists\n\t\tif (existsSync(neonAgentsPath)) {\n\t\t\tconst response = await confirm({\n\t\t\t\tmessage:\n\t\t\t\t\t\"Replace existing .neon/AGENTS.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\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(neonAgentsPath, content, \"utf-8\");\n\t\treturn true;\n\t} catch (error) {\n\t\tlog.error(\n\t\t\t`Failed to create .neon/AGENTS.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/AGENTS.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\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} 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}\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\tconst response = await confirm({\n\t\t\tmessage:\n\t\t\t\t\"Neon MCP Server is already configured. Would you like to reconfigure it? (Y/n)\",\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// Ensure authentication (will trigger OAuth if needed)\n\tconst authSpinner = spinner();\n\tauthSpinner.start(\"Authenticating...\");\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// Fetch organizations and let user select\n\tlet selectedOrgId: string | undefined;\n\n\tconst organizations = await fetchOrganizations();\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} 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// Create API key using the OAuth token\n\tconst apiKey = await createApiKeyFromNeonctl();\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\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(\"Adding Neon to your project\");\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(\"Cursor not found.\");\n\t\tlog.warn(\n\t\t\t\"Error: Cursor is required to continue. Support for additional agents is coming soon.\",\n\t\t);\n\t\toutro(\"📣 Is this unexpected? Email us at feedback@neon.tech\");\n\t\tprocess.exit(1);\n\t}\n\n\tconst { success: mcpSuccess, orgId } = await installMCPServer();\n\n\tif (!mcpSuccess) {\n\t\toutro(\n\t\t\t\"Initialization cancelled or failed. Please check the output above and try again.\",\n\t\t);\n\t\tprocess.exit(1);\n\t} else {\n\t\tlog.step(\"Installed Neon MCP server\");\n\t}\n\n\tconst neonMdSuccess = await createNeonMd(orgId);\n\n\tif (!neonMdSuccess) {\n\t\tlog.warn(\n\t\t\t\"Failed to create .neon/AGENTS.md, but MCP Server is configured.\",\n\t\t);\n\t}\n\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} else {\n\t\tlog.step(\"Added Neon instructions to AGENTS.md\");\n\t}\n\n\tlog.step(\"Success! Neon is now ready to use with Cursor.\\n\");\n\n\t// \\x1b[0m is the ANSI escape code for \"reset all styles\" to clear any dimming/fading that clack's note() applies\n\tnote(\n\t\t`\\x1b[0mAsk Cursor to \"${bold(cyan(\"Get started with Neon\"))}\\x1b[0m\" in the chat`,\n\t\t\"What's next?\",\n\t);\n\n\toutro(\"Have feedback? Email us at feedback@neon.tech\");\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.7.0",
3
+ "version": "0.8.1",
4
4
  "description": "Initialize Neon projects",
5
5
  "keywords": [
6
6
  "neon",
@@ -44,7 +44,8 @@
44
44
  },
45
45
  "dependencies": {
46
46
  "@clack/prompts": "0.10.1",
47
- "execa": "^9.5.2"
47
+ "execa": "^9.5.2",
48
+ "yoctocolors": "^2.1.2"
48
49
  },
49
50
  "engines": {
50
51
  "node": ">=20.19.0"
@@ -71,13 +71,16 @@ Use the Neon MCP Server to check if the user has existing projects (remember to
71
71
  - Most projects use a `.env` file with `DATABASE_URL`
72
72
  - For other setups (deployed platforms, containers, cloud configs), check their project structure and ask where they store credentials
73
73
 
74
- **Important:** If you cannot write to the file (permissions, file location, etc.), run the command to allow the user to add it themselves:
74
+ **Before modifying .env:**
75
75
 
76
- ```bash
77
- echo "DATABASE_URL=postgresql://..." >> .env
78
- ```
79
-
80
- Or show them the exact line to add:
76
+ 1. **Always try to read the .env file first** to check if `DATABASE_URL` already exists
77
+ 2. If the file exists and is readable:
78
+ - Use `search_replace` to update existing `DATABASE_URL`, or
79
+ - Append new `DATABASE_URL` if it doesn't exist
80
+ 3. If the file is unreadable (in .cursorignore/.gitignore) or you lack write permissions:
81
+ - **DO NOT use the write tool** (it would overwrite the entire file)
82
+ - Instead, run the append command: `echo "DATABASE_URL=postgresql://..." >> .env`
83
+ - Or show them the exact line to add manually:
81
84
 
82
85
  ```
83
86
  DATABASE_URL=postgresql://user:password@host/database
@@ -115,7 +118,7 @@ Ask the user briefly (1-2 questions):
115
118
 
116
119
  **If it's an established project:**
117
120
 
118
- Skip the questions - you can infer what they're building from the existing codebase.
121
+ Skip the questions - you can infer what they're building from the existing codebase. Update any relevant code to use the driver you just installed to connect to their Neon database.
119
122
 
120
123
  **Remember the context** (whether from questions or code analysis) for all subsequent MCP Server interactions and recommendations. However, stay focused on Neon setup - don't get sidetracked into other architectural discussions until setup is complete.
121
124