neon-init 0.9.1 → 0.10.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # neon-init
2
2
 
3
- Set up your project with Neon's MCP Server for AI-powered database operations.
3
+ Set up Neon's MCP Server for AI-powered database operations in VS Code, Cursor, and Claude CLI.
4
4
 
5
5
  ## Installation
6
6
 
@@ -16,16 +16,32 @@ import { init } from "neon-init";
16
16
  await init();
17
17
  ```
18
18
 
19
+ Or via CLI:
20
+
21
+ ```sh
22
+ npx neon-init
23
+ ```
24
+
19
25
  Then:
20
26
 
21
- 1. Restart your AI coding assistant (Cursor, Windsurf, etc.)
27
+ 1. Restart your editor (VS Code, Cursor, or Claude CLI)
22
28
  2. Type **"Get started with Neon using MCP Resource"** in your AI chat
23
29
 
24
30
  ## What It Does
25
31
 
26
32
  ### Configures Neon MCP Server
27
33
 
28
- Creates `~/.cursor/mcp.json` (global config) to enable AI-powered database operations through the Model Context Protocol.
34
+ - **Cursor**: Creates or updates `~/.cursor/mcp.json` (global config - works across all projects)
35
+ - **VS Code**: Creates or updates global `mcp.json` if VS Code is installed, otherwise falls back to `.vscode/mcp.json` (workspace config)
36
+ - **Claude CLI**: Creates or updates `~/.claude.json` (global config - works across all projects)
37
+
38
+ **Supported Editors:**
39
+
40
+ - **VS Code** with GitHub Copilot
41
+ - **Cursor**
42
+ - **Claude CLI**
43
+
44
+ The tool automatically detects which editors are installed on your system and you'll be prompted to choose which one(s) to configure.
29
45
 
30
46
  **Authentication:** Uses OAuth via `neonctl` and creates an API key for you - opens your browser, no manual API keys needed.
31
47
 
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../src/index.ts"],"sourcesContent":[],"mappings":";;AA+OA;;iBAAsB,IAAA,CAAA,GAAQ"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../src/index.ts"],"sourcesContent":[],"mappings":";;AAiBA;;iBAAsB,IAAA,CAAA,GAAQ"}
package/dist/index.js CHANGED
@@ -1,169 +1,76 @@
1
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
2
- import { dirname, resolve } from "node:path";
3
- import { fileURLToPath } from "node:url";
4
- import { confirm, intro, isCancel, log, note, outro, spinner } from "@clack/prompts";
5
- import { execa } from "execa";
1
+ import { detectAvailableEditors } from "./lib/editors.js";
2
+ import { installMCPServer } from "./lib/install.js";
3
+ import { confirm, intro, isCancel, log, multiselect, note, outro } from "@clack/prompts";
6
4
  import { bold, cyan } from "yoctocolors";
7
5
 
8
6
  //#region src/index.ts
9
- dirname(fileURLToPath(import.meta.url));
10
7
  /**
11
- * Ensures neonctl is authenticated by running a command that triggers auth if needed
12
- * This will automatically start the OAuth flow if the user isn't already authenticated
13
- */
14
- async function ensureNeonctlAuth() {
15
- try {
16
- await execa("npx", [
17
- "-y",
18
- "neonctl",
19
- "me",
20
- "--no-analytics"
21
- ], { stdio: "inherit" });
22
- return true;
23
- } catch (error) {
24
- log.error(`Authentication failed: ${error instanceof Error ? error.message : "Unknown error"}`);
25
- return false;
26
- }
27
- }
28
- /**
29
- * Gets the OAuth access token from neonctl's stored credentials
30
- */
31
- async function getNeonctlAccessToken() {
32
- try {
33
- const homeDir = process.env.HOME || process.env.USERPROFILE;
34
- if (!homeDir) return null;
35
- const credentialsPath = resolve(homeDir, ".config", "neonctl", "credentials.json");
36
- if (!existsSync(credentialsPath)) return null;
37
- return JSON.parse(readFileSync(credentialsPath, "utf-8")).access_token || null;
38
- } catch {
39
- return null;
40
- }
41
- }
42
- /**
43
- * Creates an API key using the Neon API with the OAuth token from neonctl
44
- */
45
- async function createApiKeyFromNeonctl() {
46
- try {
47
- const accessToken = await getNeonctlAccessToken();
48
- if (!accessToken) {
49
- log.error("Could not find OAuth token from neonctl");
50
- return null;
51
- }
52
- const keyName = `neonctl-init-${(/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").slice(0, -5)}`;
53
- const response = await fetch("https://console.neon.tech/api/v2/api_keys", {
54
- method: "POST",
55
- headers: {
56
- Authorization: `Bearer ${accessToken}`,
57
- "Content-Type": "application/json"
58
- },
59
- body: JSON.stringify({ key_name: keyName })
60
- });
61
- if (!response.ok) {
62
- const errorText = await response.text();
63
- log.error(`Failed to create API key: ${response.status} ${errorText}`);
64
- return null;
65
- }
66
- return (await response.json()).key || null;
67
- } catch (error) {
68
- log.error(`Failed to create API key: ${error instanceof Error ? error.message : "Unknown error"}`);
69
- return null;
70
- }
71
- }
72
- /**
73
- * Gets or creates the .cursor/mcp.json configuration
74
- */
75
- function getMCPConfig(cursorDir) {
76
- const mcpConfigPath = resolve(cursorDir, "mcp.json");
77
- if (existsSync(mcpConfigPath)) try {
78
- const content = readFileSync(mcpConfigPath, "utf-8");
79
- return JSON.parse(content);
80
- } catch (_error) {
81
- log.warn("Failed to parse existing mcp.json. Creating a new configuration.");
82
- return { mcpServers: {} };
83
- }
84
- return { mcpServers: {} };
85
- }
86
- /**
87
- * Writes the MCP configuration to .cursor/mcp.json
88
- */
89
- function writeMCPConfig(cursorDir, config) {
90
- const mcpConfigPath = resolve(cursorDir, "mcp.json");
91
- if (!existsSync(cursorDir)) mkdirSync(cursorDir, { recursive: true });
92
- writeFileSync(mcpConfigPath, JSON.stringify(config, null, 2), "utf-8");
93
- }
94
- /**
95
- * Installs Neon's MCP Server by configuring it globally in ~/.cursor/mcp.json
8
+ * Initialize Neon projects with MCP Server
96
9
  */
97
- async function installMCPServer() {
10
+ async function init() {
11
+ intro("Adding Neon to your project");
98
12
  const homeDir = process.env.HOME || process.env.USERPROFILE;
99
13
  if (!homeDir) {
100
14
  log.error("Could not determine home directory");
101
- return false;
15
+ outro("📣 Is this unexpected? Email us at feedback@neon.tech");
16
+ process.exit(1);
102
17
  }
103
- const cursorDir = resolve(homeDir, ".cursor");
104
- const config = getMCPConfig(cursorDir);
105
- const alreadyConfigured = Boolean(config.mcpServers.Neon);
106
- let shouldReconfigure = false;
107
- if (alreadyConfigured) {
108
- const response = await confirm({
109
- message: "Neon MCP Server is already configured. Would you like to reconfigure it? (Y/n)",
18
+ const workspaceDir = process.cwd();
19
+ const availableEditors = await detectAvailableEditors(homeDir);
20
+ if (availableEditors.length === 0) {
21
+ log.warn("No supported editors detected on your system.");
22
+ log.info("Supported editors:");
23
+ log.info(" • VS Code (with GitHub Copilot)");
24
+ log.info(" • Cursor");
25
+ log.info(" • Claude CLI");
26
+ const continueAnyway = await confirm({
27
+ message: "Would you like to configure MCP anyway? (You can manually select your editor)",
110
28
  initialValue: true
111
29
  });
112
- if (isCancel(response)) return false;
113
- shouldReconfigure = response;
114
- if (!shouldReconfigure) {
115
- log.info("Keeping existing global configuration.");
116
- return true;
30
+ if (isCancel(continueAnyway) || !continueAnyway) {
31
+ outro("Installation cancelled");
32
+ process.exit(0);
117
33
  }
118
34
  }
119
- const authSpinner = spinner();
120
- authSpinner.start("Authenticating...");
121
- if (!await ensureNeonctlAuth()) {
122
- authSpinner.stop("Authentication failed");
123
- return false;
124
- }
125
- authSpinner.stop("Authentication successful ✓");
126
- const apiKey = await createApiKeyFromNeonctl();
127
- if (!apiKey) {
128
- log.error("Could not create API key after authentication.");
129
- log.info("You can manually create one at: https://console.neon.tech/app/settings/api-keys");
130
- return false;
131
- }
132
- config.mcpServers.Neon = {
133
- url: "https://mcp.neon.tech/mcp",
134
- headers: { Authorization: `Bearer ${apiKey}` }
135
- };
136
- try {
137
- writeMCPConfig(cursorDir, config);
138
- return true;
139
- } catch (error) {
140
- log.error(`Failed to write global configuration: ${error instanceof Error ? error.message : "Unknown error"}`);
141
- return false;
35
+ const response = await multiselect({
36
+ message: "Which editor(s) would you like to configure? (Space to toggle each option, Enter to confirm your selection)",
37
+ options: [
38
+ "Cursor",
39
+ "VS Code",
40
+ "Claude CLI"
41
+ ].map((editor) => ({
42
+ value: editor,
43
+ label: editor
44
+ })),
45
+ initialValues: availableEditors,
46
+ required: true
47
+ });
48
+ if (isCancel(response)) {
49
+ outro("Installation cancelled");
50
+ process.exit(0);
142
51
  }
143
- }
144
- /**
145
- * Initialize Neon projects with MCP Server
146
- */
147
- async function init() {
148
- intro("Adding Neon to your project");
149
- const homeDir = process.env.HOME || process.env.USERPROFILE;
150
- if (!homeDir) {
151
- log.error("Could not determine home directory");
152
- process.exit(1);
52
+ const selectedEditors = response;
53
+ if (selectedEditors.length === 0) {
54
+ log.warn("No editors selected.");
55
+ outro("Installation cancelled");
56
+ process.exit(0);
153
57
  }
154
- if (!existsSync(resolve(homeDir, ".cursor"))) {
155
- log.warn("Cursor not found.");
156
- log.warn("Error: Cursor is required to continue. Support for additional agents is coming soon.");
157
- outro("📣 Is this unexpected? Email us at feedback@neon.tech");
158
- process.exit(1);
58
+ const results = await installMCPServer(homeDir, workspaceDir, selectedEditors);
59
+ const successful = [];
60
+ const failed = [];
61
+ for (const [editor, status] of results.entries()) if (status === "success") successful.push(editor);
62
+ else failed.push(editor);
63
+ const successList = successful.join(" / ");
64
+ if (successful.length > 0) {
65
+ log.step("Installed Neon MCP server");
66
+ log.step(`Success! Neon is now ready to use with ${successList}.\n`);
159
67
  }
160
- if (!await installMCPServer()) {
161
- outro("Initialization cancelled or failed. Please check the output above and try again.");
68
+ if (failed.length > 0) log.error(`Failed to configure: ${failed.join(" / ")}`);
69
+ if (successful.length === 0) {
70
+ outro("Installation cancelled or failed. Please check the output above and try again.");
162
71
  process.exit(1);
163
72
  }
164
- log.step("Installed Neon MCP server");
165
- log.step("Success! Neon is now ready to use with Cursor.\n");
166
- note(`\x1b[0mRestart Cursor and ask Cursor to "${bold(cyan("Get started with Neon using MCP Resource"))}\x1b[0m" in the chat`, "What's next?");
73
+ note(`\x1b[0mRestart ${successList} and type in "${bold(cyan("Get started with Neon"))}\x1b[0m" in the chat`, "What's next?");
167
74
  outro("Have feedback? Email us at feedback@neon.tech");
168
75
  }
169
76
 
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["import { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { dirname, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport {\n\tconfirm,\n\tintro,\n\tisCancel,\n\tlog,\n\tnote,\n\toutro,\n\tspinner,\n} from \"@clack/prompts\";\nimport { execa } from \"execa\";\nimport { bold, cyan } from \"yoctocolors\";\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\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\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 * Installs Neon's MCP Server by configuring it globally in ~/.cursor/mcp.json\n */\nasync function installMCPServer(): Promise<boolean> {\n\tconst homeDir = process.env.HOME || process.env.USERPROFILE;\n\tif (!homeDir) {\n\t\tlog.error(\"Could not determine home directory\");\n\t\treturn 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 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\treturn true;\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 false;\n\t}\n\n\tauthSpinner.stop(\"Authentication successful ✓\");\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 false;\n\t}\n\n\t// 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 true;\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 false;\n\t}\n}\n\n/**\n * Initialize Neon projects with MCP Server\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 mcpSuccess = 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}\n\n\tlog.step(\"Installed Neon MCP server\");\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[0mRestart Cursor and ask Cursor to \"${bold(cyan(\"Get started with Neon using MCP Resource\"))}\\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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"}
1
+ {"version":3,"file":"index.js","names":["successful: Editor[]","failed: Editor[]"],"sources":["../src/index.ts"],"sourcesContent":["import {\n\tconfirm,\n\tintro,\n\tisCancel,\n\tlog,\n\tmultiselect,\n\tnote,\n\toutro,\n} from \"@clack/prompts\";\nimport { bold, cyan } from \"yoctocolors\";\nimport { detectAvailableEditors } from \"./lib/editors.js\";\nimport { installMCPServer } from \"./lib/install.js\";\nimport type { Editor } from \"./lib/types.js\";\n\n/**\n * Initialize Neon projects with MCP Server\n */\nexport async function init(): Promise<void> {\n\tintro(\"Adding Neon to your project\");\n\n\t// Get the home directory\n\tconst homeDir = process.env.HOME || process.env.USERPROFILE;\n\tif (!homeDir) {\n\t\tlog.error(\"Could not determine home directory\");\n\t\toutro(\"📣 Is this unexpected? Email us at feedback@neon.tech\");\n\t\tprocess.exit(1);\n\t}\n\n\t// Get the current workspace directory\n\tconst workspaceDir = process.cwd();\n\n\t// Detect available editors\n\tconst availableEditors = await detectAvailableEditors(homeDir);\n\n\t// If no editors detected, offer to continue anyway\n\tif (availableEditors.length === 0) {\n\t\tlog.warn(\"No supported editors detected on your system.\");\n\t\tlog.info(\"Supported editors:\");\n\t\tlog.info(\" • VS Code (with GitHub Copilot)\");\n\t\tlog.info(\" • Cursor\");\n\t\tlog.info(\" • Claude CLI\");\n\n\t\tconst continueAnyway = await confirm({\n\t\t\tmessage:\n\t\t\t\t\"Would you like to configure MCP anyway? (You can manually select your editor)\",\n\t\t\tinitialValue: true,\n\t\t});\n\n\t\tif (isCancel(continueAnyway) || !continueAnyway) {\n\t\t\toutro(\"Installation cancelled\");\n\t\t\tprocess.exit(0);\n\t\t}\n\t}\n\n\t// Determine which editors to configure\n\tconst response = await multiselect({\n\t\tmessage:\n\t\t\t\"Which editor(s) would you like to configure? (Space to toggle each option, Enter to confirm your selection)\",\n\t\toptions: [\"Cursor\", \"VS Code\", \"Claude CLI\"].map((editor) => ({\n\t\t\tvalue: editor,\n\t\t\tlabel: editor,\n\t\t})),\n\t\tinitialValues: availableEditors, // Select detected editors by default\n\t\trequired: true,\n\t});\n\n\tif (isCancel(response)) {\n\t\toutro(\"Installation cancelled\");\n\t\tprocess.exit(0);\n\t}\n\n\tconst selectedEditors = response as Editor[];\n\n\tif (selectedEditors.length === 0) {\n\t\tlog.warn(\"No editors selected.\");\n\t\toutro(\"Installation cancelled\");\n\t\tprocess.exit(0);\n\t}\n\n\t// Install MCP server for selected editors\n\tconst results = await installMCPServer(\n\t\thomeDir,\n\t\tworkspaceDir,\n\t\tselectedEditors,\n\t);\n\n\tconst successful: Editor[] = [];\n\tconst failed: Editor[] = [];\n\n\tfor (const [editor, status] of results.entries()) {\n\t\tif (status === \"success\") {\n\t\t\tsuccessful.push(editor);\n\t\t} else {\n\t\t\tfailed.push(editor);\n\t\t}\n\t}\n\tconst successList = successful.join(\" / \");\n\tif (successful.length > 0) {\n\t\tlog.step(\"Installed Neon MCP server\");\n\t\tlog.step(`Success! Neon is now ready to use with ${successList}.\\n`);\n\t}\n\n\tif (failed.length > 0) {\n\t\tlog.error(`Failed to configure: ${failed.join(\" / \")}`);\n\t}\n\n\t// Exit with error if all failed\n\tif (successful.length === 0) {\n\t\toutro(\n\t\t\t\"Installation cancelled or failed. Please check the output above and try again.\",\n\t\t);\n\t\tprocess.exit(1);\n\t}\n\n\tnote(\n\t\t`\\x1b[0mRestart ${successList} and type in \"${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":";;;;;;;;;AAiBA,eAAsB,OAAsB;AAC3C,OAAM,8BAA8B;CAGpC,MAAM,UAAU,QAAQ,IAAI,QAAQ,QAAQ,IAAI;AAChD,KAAI,CAAC,SAAS;AACb,MAAI,MAAM,qCAAqC;AAC/C,QAAM,wDAAwD;AAC9D,UAAQ,KAAK,EAAE;;CAIhB,MAAM,eAAe,QAAQ,KAAK;CAGlC,MAAM,mBAAmB,MAAM,uBAAuB,QAAQ;AAG9D,KAAI,iBAAiB,WAAW,GAAG;AAClC,MAAI,KAAK,gDAAgD;AACzD,MAAI,KAAK,qBAAqB;AAC9B,MAAI,KAAK,oCAAoC;AAC7C,MAAI,KAAK,aAAa;AACtB,MAAI,KAAK,iBAAiB;EAE1B,MAAM,iBAAiB,MAAM,QAAQ;GACpC,SACC;GACD,cAAc;GACd,CAAC;AAEF,MAAI,SAAS,eAAe,IAAI,CAAC,gBAAgB;AAChD,SAAM,yBAAyB;AAC/B,WAAQ,KAAK,EAAE;;;CAKjB,MAAM,WAAW,MAAM,YAAY;EAClC,SACC;EACD,SAAS;GAAC;GAAU;GAAW;GAAa,CAAC,KAAK,YAAY;GAC7D,OAAO;GACP,OAAO;GACP,EAAE;EACH,eAAe;EACf,UAAU;EACV,CAAC;AAEF,KAAI,SAAS,SAAS,EAAE;AACvB,QAAM,yBAAyB;AAC/B,UAAQ,KAAK,EAAE;;CAGhB,MAAM,kBAAkB;AAExB,KAAI,gBAAgB,WAAW,GAAG;AACjC,MAAI,KAAK,uBAAuB;AAChC,QAAM,yBAAyB;AAC/B,UAAQ,KAAK,EAAE;;CAIhB,MAAM,UAAU,MAAM,iBACrB,SACA,cACA,gBACA;CAED,MAAMA,aAAuB,EAAE;CAC/B,MAAMC,SAAmB,EAAE;AAE3B,MAAK,MAAM,CAAC,QAAQ,WAAW,QAAQ,SAAS,CAC/C,KAAI,WAAW,UACd,YAAW,KAAK,OAAO;KAEvB,QAAO,KAAK,OAAO;CAGrB,MAAM,cAAc,WAAW,KAAK,MAAM;AAC1C,KAAI,WAAW,SAAS,GAAG;AAC1B,MAAI,KAAK,4BAA4B;AACrC,MAAI,KAAK,0CAA0C,YAAY,KAAK;;AAGrE,KAAI,OAAO,SAAS,EACnB,KAAI,MAAM,wBAAwB,OAAO,KAAK,MAAM,GAAG;AAIxD,KAAI,WAAW,WAAW,GAAG;AAC5B,QACC,iFACA;AACD,UAAQ,KAAK,EAAE;;AAGhB,MACC,kBAAkB,YAAY,gBAAgB,KAAK,KAAK,wBAAwB,CAAC,CAAC,uBAClF,eACA;AAED,OAAM,gDAAgD"}
@@ -0,0 +1,13 @@
1
+ //#region src/lib/auth.d.ts
2
+ /**
3
+ * Ensures neonctl is authenticated by running a command that triggers auth if needed
4
+ * This will automatically start the OAuth flow if the user isn't already authenticated
5
+ */
6
+ declare function ensureNeonctlAuth(): Promise<boolean>;
7
+ /**
8
+ * Creates an API key using the Neon API with the OAuth token from neonctl
9
+ */
10
+ declare function createApiKeyFromNeonctl(): Promise<string | null>;
11
+ //#endregion
12
+ export { createApiKeyFromNeonctl, ensureNeonctlAuth };
13
+ //# sourceMappingURL=auth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.d.ts","names":[],"sources":["../../src/lib/auth.ts"],"sourcesContent":[],"mappings":";;AASA;AA0CA;;iBA1CsB,iBAAA,CAAA,GAAqB;;;;iBA0CrB,uBAAA,CAAA,GAA2B"}
@@ -0,0 +1,72 @@
1
+ import { log } from "@clack/prompts";
2
+ import { existsSync, readFileSync } from "node:fs";
3
+ import { resolve } from "node:path";
4
+ import { execa } from "execa";
5
+
6
+ //#region src/lib/auth.ts
7
+ /**
8
+ * Ensures neonctl is authenticated by running a command that triggers auth if needed
9
+ * This will automatically start the OAuth flow if the user isn't already authenticated
10
+ */
11
+ async function ensureNeonctlAuth() {
12
+ try {
13
+ await execa("npx", [
14
+ "-y",
15
+ "neonctl",
16
+ "me",
17
+ "--no-analytics"
18
+ ], { stdio: "inherit" });
19
+ return true;
20
+ } catch (error) {
21
+ log.error(`Authentication failed: ${error instanceof Error ? error.message : "Unknown error"}`);
22
+ return false;
23
+ }
24
+ }
25
+ /**
26
+ * Gets the OAuth access token from neonctl's stored credentials
27
+ */
28
+ async function getNeonctlAccessToken() {
29
+ try {
30
+ const homeDir = process.env.HOME || process.env.USERPROFILE;
31
+ if (!homeDir) return null;
32
+ const credentialsPath = resolve(homeDir, ".config", "neonctl", "credentials.json");
33
+ if (!existsSync(credentialsPath)) return null;
34
+ return JSON.parse(readFileSync(credentialsPath, "utf-8")).access_token || null;
35
+ } catch {
36
+ return null;
37
+ }
38
+ }
39
+ /**
40
+ * Creates an API key using the Neon API with the OAuth token from neonctl
41
+ */
42
+ async function createApiKeyFromNeonctl() {
43
+ try {
44
+ const accessToken = await getNeonctlAccessToken();
45
+ if (!accessToken) {
46
+ log.error("Could not find OAuth token from neonctl");
47
+ return null;
48
+ }
49
+ const keyName = `neonctl-init-${(/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").slice(0, -5)}`;
50
+ const response = await fetch("https://console.neon.tech/api/v2/api_keys", {
51
+ method: "POST",
52
+ headers: {
53
+ Authorization: `Bearer ${accessToken}`,
54
+ "Content-Type": "application/json"
55
+ },
56
+ body: JSON.stringify({ key_name: keyName })
57
+ });
58
+ if (!response.ok) {
59
+ const errorText = await response.text();
60
+ log.error(`Failed to create API key: ${response.status} ${errorText}`);
61
+ return null;
62
+ }
63
+ return (await response.json()).key || null;
64
+ } catch (error) {
65
+ log.error(`Failed to create API key: ${error instanceof Error ? error.message : "Unknown error"}`);
66
+ return null;
67
+ }
68
+ }
69
+
70
+ //#endregion
71
+ export { createApiKeyFromNeonctl, ensureNeonctlAuth };
72
+ //# sourceMappingURL=auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.js","names":[],"sources":["../../src/lib/auth.ts"],"sourcesContent":["import { existsSync, readFileSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport { log } from \"@clack/prompts\";\nimport { execa } from \"execa\";\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 */\nexport async 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 */\nexport async 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"],"mappings":";;;;;;;;;;AASA,eAAsB,oBAAsC;AAC3D,KAAI;AAEH,QAAM,MAAM,OAAO;GAAC;GAAM;GAAW;GAAM;GAAiB,EAAE,EAC7D,OAAO,WACP,CAAC;AAEF,SAAO;UACC,OAAO;AACf,MAAI,MACH,0BAA0B,iBAAiB,QAAQ,MAAM,UAAU,kBACnE;AACD,SAAO;;;;;;AAOT,eAAe,wBAAgD;AAC9D,KAAI;EACH,MAAM,UAAU,QAAQ,IAAI,QAAQ,QAAQ,IAAI;AAChD,MAAI,CAAC,QAAS,QAAO;EAErB,MAAM,kBAAkB,QACvB,SACA,WACA,WACA,mBACA;AACD,MAAI,CAAC,WAAW,gBAAgB,CAAE,QAAO;AAGzC,SADoB,KAAK,MAAM,aAAa,iBAAiB,QAAQ,CAAC,CACnD,gBAAgB;SAC5B;AACP,SAAO;;;;;;AAOT,eAAsB,0BAAkD;AACvE,KAAI;EACH,MAAM,cAAc,MAAM,uBAAuB;AACjD,MAAI,CAAC,aAAa;AACjB,OAAI,MAAM,0CAA0C;AACpD,UAAO;;EAQR,MAAM,UAAU,iCAJE,IAAI,MAAM,EAC1B,aAAa,CACb,QAAQ,SAAS,IAAI,CACrB,MAAM,GAAG,GAAG;EAId,MAAM,WAAW,MAAM,MACtB,6CACA;GACC,QAAQ;GACR,SAAS;IACR,eAAe,UAAU;IACzB,gBAAgB;IAChB;GACD,MAAM,KAAK,UAAU,EACpB,UAAU,SACV,CAAC;GACF,CACD;AAED,MAAI,CAAC,SAAS,IAAI;GACjB,MAAM,YAAY,MAAM,SAAS,MAAM;AACvC,OAAI,MACH,6BAA6B,SAAS,OAAO,GAAG,YAChD;AACD,UAAO;;AAIR,UADa,MAAM,SAAS,MAAM,EACtB,OAAO;UACX,OAAO;AACf,MAAI,MACH,6BAA6B,iBAAiB,QAAQ,MAAM,UAAU,kBACtE;AACD,SAAO"}
@@ -0,0 +1,15 @@
1
+ import { Editor } from "./types.js";
2
+
3
+ //#region src/lib/editors.d.ts
4
+
5
+ /**
6
+ * Gets VS Code's global config directory based on the platform
7
+ */
8
+ declare function getVSCodeGlobalConfigDir(homeDir: string): string | null;
9
+ /**
10
+ * Detects which editors are installed on the system
11
+ */
12
+ declare function detectAvailableEditors(homeDir: string): Promise<Editor[]>;
13
+ //#endregion
14
+ export { detectAvailableEditors, getVSCodeGlobalConfigDir };
15
+ //# sourceMappingURL=editors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"editors.d.ts","names":[],"sources":["../../src/lib/editors.ts"],"sourcesContent":[],"mappings":";;;;;;AAQA;AA8CsB,iBA9CN,wBAAA,CA8C4B,OAAA,EAAA,MAAA,CAAA,EAAA,MAAA,GAAA,IAAA;;;;AAElC,iBAFY,sBAAA,CAEZ,OAAA,EAAA,MAAA,CAAA,EAAP,OAAO,CAAC,MAAD,EAAA,CAAA"}
@@ -0,0 +1,47 @@
1
+ import { existsSync } from "node:fs";
2
+ import { resolve } from "node:path";
3
+ import { execa } from "execa";
4
+
5
+ //#region src/lib/editors.ts
6
+ /**
7
+ * Gets VS Code's global config directory based on the platform
8
+ */
9
+ function getVSCodeGlobalConfigDir(homeDir) {
10
+ const platform = process.platform;
11
+ if (platform === "darwin") return resolve(homeDir, "Library", "Application Support", "Code", "User");
12
+ if (platform === "linux") return resolve(homeDir, ".config", "Code", "User");
13
+ if (platform === "win32") {
14
+ const appData = process.env.APPDATA;
15
+ if (appData) return resolve(appData, "Code", "User");
16
+ }
17
+ return null;
18
+ }
19
+ /**
20
+ * Checks if Claude CLI is installed
21
+ */
22
+ async function isClaudeCLIInstalled() {
23
+ try {
24
+ await execa("claude", ["--version"], {
25
+ stdio: "ignore",
26
+ timeout: 5e3
27
+ });
28
+ return true;
29
+ } catch {
30
+ return false;
31
+ }
32
+ }
33
+ /**
34
+ * Detects which editors are installed on the system
35
+ */
36
+ async function detectAvailableEditors(homeDir) {
37
+ const editors = [];
38
+ if (existsSync(resolve(homeDir, ".cursor"))) editors.push("Cursor");
39
+ const vscodeGlobalDir = getVSCodeGlobalConfigDir(homeDir);
40
+ if (vscodeGlobalDir && existsSync(vscodeGlobalDir)) editors.push("VS Code");
41
+ if (await isClaudeCLIInstalled()) editors.push("Claude CLI");
42
+ return editors;
43
+ }
44
+
45
+ //#endregion
46
+ export { detectAvailableEditors, getVSCodeGlobalConfigDir };
47
+ //# sourceMappingURL=editors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"editors.js","names":["editors: Editor[]"],"sources":["../../src/lib/editors.ts"],"sourcesContent":["import { existsSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport { execa } from \"execa\";\nimport type { Editor } from \"./types.js\";\n\n/**\n * Gets VS Code's global config directory based on the platform\n */\nexport function getVSCodeGlobalConfigDir(homeDir: string): string | null {\n\tconst platform = process.platform;\n\n\tif (platform === \"darwin\") {\n\t\t// macOS: ~/Library/Application Support/Code/User\n\t\treturn resolve(\n\t\t\thomeDir,\n\t\t\t\"Library\",\n\t\t\t\"Application Support\",\n\t\t\t\"Code\",\n\t\t\t\"User\",\n\t\t);\n\t}\n\tif (platform === \"linux\") {\n\t\t// Linux: ~/.config/Code/User\n\t\treturn resolve(homeDir, \".config\", \"Code\", \"User\");\n\t}\n\tif (platform === \"win32\") {\n\t\t// Windows: %APPDATA%\\Code\\User\n\t\tconst appData = process.env.APPDATA;\n\t\tif (appData) {\n\t\t\treturn resolve(appData, \"Code\", \"User\");\n\t\t}\n\t}\n\n\treturn null;\n}\n\n/**\n * Checks if Claude CLI is installed\n */\nasync function isClaudeCLIInstalled(): Promise<boolean> {\n\ttry {\n\t\tawait execa(\"claude\", [\"--version\"], {\n\t\t\tstdio: \"ignore\",\n\t\t\ttimeout: 5000,\n\t\t});\n\t\treturn true;\n\t} catch {\n\t\treturn false;\n\t}\n}\n\n/**\n * Detects which editors are installed on the system\n */\nexport async function detectAvailableEditors(\n\thomeDir: string,\n): Promise<Editor[]> {\n\tconst editors: Editor[] = [];\n\n\t// Check for Cursor (global config directory)\n\tconst cursorDir = resolve(homeDir, \".cursor\");\n\tif (existsSync(cursorDir)) {\n\t\teditors.push(\"Cursor\");\n\t}\n\n\t// Check if VS Code's global config directory exists\n\tconst vscodeGlobalDir = getVSCodeGlobalConfigDir(homeDir);\n\tif (vscodeGlobalDir && existsSync(vscodeGlobalDir)) {\n\t\teditors.push(\"VS Code\");\n\t}\n\n\t// Check for Claude CLI by running the command\n\tconst claudeInstalled = await isClaudeCLIInstalled();\n\tif (claudeInstalled) {\n\t\teditors.push(\"Claude CLI\");\n\t}\n\n\treturn editors;\n}\n"],"mappings":";;;;;;;;AAQA,SAAgB,yBAAyB,SAAgC;CACxE,MAAM,WAAW,QAAQ;AAEzB,KAAI,aAAa,SAEhB,QAAO,QACN,SACA,WACA,uBACA,QACA,OACA;AAEF,KAAI,aAAa,QAEhB,QAAO,QAAQ,SAAS,WAAW,QAAQ,OAAO;AAEnD,KAAI,aAAa,SAAS;EAEzB,MAAM,UAAU,QAAQ,IAAI;AAC5B,MAAI,QACH,QAAO,QAAQ,SAAS,QAAQ,OAAO;;AAIzC,QAAO;;;;;AAMR,eAAe,uBAAyC;AACvD,KAAI;AACH,QAAM,MAAM,UAAU,CAAC,YAAY,EAAE;GACpC,OAAO;GACP,SAAS;GACT,CAAC;AACF,SAAO;SACA;AACP,SAAO;;;;;;AAOT,eAAsB,uBACrB,SACoB;CACpB,MAAMA,UAAoB,EAAE;AAI5B,KAAI,WADc,QAAQ,SAAS,UAAU,CACpB,CACxB,SAAQ,KAAK,SAAS;CAIvB,MAAM,kBAAkB,yBAAyB,QAAQ;AACzD,KAAI,mBAAmB,WAAW,gBAAgB,CACjD,SAAQ,KAAK,UAAU;AAKxB,KADwB,MAAM,sBAAsB,CAEnD,SAAQ,KAAK,aAAa;AAG3B,QAAO"}
@@ -0,0 +1,14 @@
1
+ import { Editor, InstallStatus } from "./types.js";
2
+
3
+ //#region src/lib/install.d.ts
4
+
5
+ /**
6
+ * Installs Neon's MCP Server
7
+ * - Cursor: Global config
8
+ * - VS Code: Global config (preferred) or workspace config (fallback)
9
+ * - Claude CLI: Global config
10
+ */
11
+ declare function installMCPServer(homeDir: string, workspaceDir: string, selectedEditors: Editor[]): Promise<Map<Editor, InstallStatus>>;
12
+ //#endregion
13
+ export { installMCPServer };
14
+ //# sourceMappingURL=install.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"install.d.ts","names":[],"sources":["../../src/lib/install.ts"],"sourcesContent":[],"mappings":";;;;;;AAmFA;;;;AAIuB,iBAJD,gBAAA,CAIC,OAAA,EAAA,MAAA,EAAA,YAAA,EAAA,MAAA,EAAA,eAAA,EADL,MACK,EAAA,CAAA,EAApB,OAAoB,CAAZ,GAAY,CAAR,MAAQ,EAAA,aAAA,CAAA,CAAA"}
@@ -0,0 +1,78 @@
1
+ import { createApiKeyFromNeonctl, ensureNeonctlAuth } from "./auth.js";
2
+ import { getMCPConfig, writeMCPConfig } from "./mcp-config.js";
3
+ import { confirm, isCancel, log, spinner } from "@clack/prompts";
4
+
5
+ //#region src/lib/install.ts
6
+ /**
7
+ * Installs Neon's MCP Server for a specific editor
8
+ * - Cursor: Global config
9
+ * - VS Code: Global config (preferred) or workspace config (fallback)
10
+ * - Claude CLI: Global config
11
+ */
12
+ async function installMCPServerForEditor(homeDir, workspaceDir, editor, apiKey) {
13
+ const { config, configPath } = getMCPConfig(homeDir, workspaceDir, editor);
14
+ const serverKey = editor === "VS Code" ? config.servers : config.mcpServers;
15
+ if (Boolean(serverKey?.Neon)) {
16
+ const response = await confirm({
17
+ message: `Neon MCP Server is already configured for ${editor}. Would you like to reconfigure it? (Y/n)`,
18
+ initialValue: true
19
+ });
20
+ if (isCancel(response)) return "failed";
21
+ if (!response) {
22
+ log.info(`Keeping existing configuration for ${editor}.`);
23
+ return "success";
24
+ }
25
+ }
26
+ const neonServerConfig = {
27
+ type: "http",
28
+ url: "https://mcp.neon.tech/mcp",
29
+ headers: { Authorization: `Bearer ${apiKey}` }
30
+ };
31
+ if (editor === "VS Code") {
32
+ if (!config.servers) config.servers = {};
33
+ config.servers.Neon = neonServerConfig;
34
+ } else {
35
+ if (!config.mcpServers) config.mcpServers = {};
36
+ config.mcpServers.Neon = neonServerConfig;
37
+ }
38
+ try {
39
+ writeMCPConfig(configPath, config);
40
+ return "success";
41
+ } catch (error) {
42
+ log.error(`Failed to write configuration for ${editor}: ${error instanceof Error ? error.message : "Unknown error"}`);
43
+ return "failed";
44
+ }
45
+ }
46
+ /**
47
+ * Installs Neon's MCP Server
48
+ * - Cursor: Global config
49
+ * - VS Code: Global config (preferred) or workspace config (fallback)
50
+ * - Claude CLI: Global config
51
+ */
52
+ async function installMCPServer(homeDir, workspaceDir, selectedEditors) {
53
+ const results = /* @__PURE__ */ new Map();
54
+ const authSpinner = spinner();
55
+ authSpinner.start("Authenticating...");
56
+ if (!await ensureNeonctlAuth()) {
57
+ authSpinner.stop("Authentication failed");
58
+ for (const editor of selectedEditors) results.set(editor, "failed");
59
+ return results;
60
+ }
61
+ authSpinner.stop("Authentication successful ✓");
62
+ const apiKey = await createApiKeyFromNeonctl();
63
+ if (!apiKey) {
64
+ log.error("Could not create API key after authentication.");
65
+ log.info("You can manually create one at: https://console.neon.tech/app/settings/api-keys");
66
+ for (const editor of selectedEditors) results.set(editor, "failed");
67
+ return results;
68
+ }
69
+ for (const editor of selectedEditors) {
70
+ const status = await installMCPServerForEditor(homeDir, workspaceDir, editor, apiKey);
71
+ results.set(editor, status);
72
+ }
73
+ return results;
74
+ }
75
+
76
+ //#endregion
77
+ export { installMCPServer };
78
+ //# sourceMappingURL=install.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"install.js","names":[],"sources":["../../src/lib/install.ts"],"sourcesContent":["import { confirm, isCancel, log, spinner } from \"@clack/prompts\";\nimport { createApiKeyFromNeonctl, ensureNeonctlAuth } from \"./auth.js\";\nimport { getMCPConfig, writeMCPConfig } from \"./mcp-config.js\";\nimport type { Editor, InstallStatus } from \"./types.js\";\n\n/**\n * Installs Neon's MCP Server for a specific editor\n * - Cursor: Global config\n * - VS Code: Global config (preferred) or workspace config (fallback)\n * - Claude CLI: Global config\n */\nasync function installMCPServerForEditor(\n\thomeDir: string,\n\tworkspaceDir: string,\n\teditor: Editor,\n\tapiKey: string,\n): Promise<InstallStatus> {\n\tconst { config, configPath } = getMCPConfig(homeDir, workspaceDir, editor);\n\n\t// Check if already configured\n\tconst serverKey = editor === \"VS Code\" ? config.servers : config.mcpServers;\n\tconst alreadyConfigured = Boolean(serverKey?.Neon);\n\n\tif (alreadyConfigured) {\n\t\tconst response = await confirm({\n\t\t\tmessage: `Neon MCP Server is already configured for ${editor}. 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 \"failed\";\n\t\t}\n\n\t\tconst shouldReconfigure = response as boolean;\n\n\t\tif (!shouldReconfigure) {\n\t\t\tlog.info(`Keeping existing configuration for ${editor}.`);\n\t\t\treturn \"success\";\n\t\t}\n\t}\n\n\t// 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\tconst neonServerConfig = {\n\t\ttype: \"http\",\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// VS Code uses \"servers\" key, Cursor and Claude CLI use \"mcpServers\" key\n\tif (editor === \"VS Code\") {\n\t\tif (!config.servers) {\n\t\t\tconfig.servers = {};\n\t\t}\n\t\tconfig.servers.Neon = neonServerConfig;\n\t} else {\n\t\tif (!config.mcpServers) {\n\t\t\tconfig.mcpServers = {};\n\t\t}\n\t\tconfig.mcpServers.Neon = neonServerConfig;\n\t}\n\n\t// Write configuration\n\ttry {\n\t\twriteMCPConfig(configPath, config);\n\t\treturn \"success\";\n\t} catch (error) {\n\t\tlog.error(\n\t\t\t`Failed to write configuration for ${editor}: ${error instanceof Error ? error.message : \"Unknown error\"}`,\n\t\t);\n\t\treturn \"failed\";\n\t}\n}\n\n/**\n * Installs Neon's MCP Server\n * - Cursor: Global config\n * - VS Code: Global config (preferred) or workspace config (fallback)\n * - Claude CLI: Global config\n */\nexport async function installMCPServer(\n\thomeDir: string,\n\tworkspaceDir: string,\n\tselectedEditors: Editor[],\n): Promise<Map<Editor, InstallStatus>> {\n\tconst results = new Map<Editor, InstallStatus>();\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\t// Mark all editors as failed due to auth failure\n\t\tfor (const editor of selectedEditors) {\n\t\t\tresults.set(editor, \"failed\");\n\t\t}\n\t\treturn results;\n\t}\n\n\tauthSpinner.stop(\"Authentication successful ✓\");\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\t// Mark all editors as failed due to API key creation failure\n\t\tfor (const editor of selectedEditors) {\n\t\t\tresults.set(editor, \"failed\");\n\t\t}\n\t\treturn results;\n\t}\n\n\t// Install MCP server for each selected editor\n\tfor (const editor of selectedEditors) {\n\t\tconst status = await installMCPServerForEditor(\n\t\t\thomeDir,\n\t\t\tworkspaceDir,\n\t\t\teditor,\n\t\t\tapiKey,\n\t\t);\n\t\tresults.set(editor, status);\n\t}\n\n\treturn results;\n}\n"],"mappings":";;;;;;;;;;;AAWA,eAAe,0BACd,SACA,cACA,QACA,QACyB;CACzB,MAAM,EAAE,QAAQ,eAAe,aAAa,SAAS,cAAc,OAAO;CAG1E,MAAM,YAAY,WAAW,YAAY,OAAO,UAAU,OAAO;AAGjE,KAF0B,QAAQ,WAAW,KAAK,EAE3B;EACtB,MAAM,WAAW,MAAM,QAAQ;GAC9B,SAAS,6CAA6C,OAAO;GAC7D,cAAc;GACd,CAAC;AAEF,MAAI,SAAS,SAAS,CACrB,QAAO;AAKR,MAAI,CAFsB,UAEF;AACvB,OAAI,KAAK,sCAAsC,OAAO,GAAG;AACzD,UAAO;;;CAOT,MAAM,mBAAmB;EACxB,MAAM;EACN,KAAK;EACL,SAAS,EACR,eAAe,UAAU,UACzB;EACD;AAGD,KAAI,WAAW,WAAW;AACzB,MAAI,CAAC,OAAO,QACX,QAAO,UAAU,EAAE;AAEpB,SAAO,QAAQ,OAAO;QAChB;AACN,MAAI,CAAC,OAAO,WACX,QAAO,aAAa,EAAE;AAEvB,SAAO,WAAW,OAAO;;AAI1B,KAAI;AACH,iBAAe,YAAY,OAAO;AAClC,SAAO;UACC,OAAO;AACf,MAAI,MACH,qCAAqC,OAAO,IAAI,iBAAiB,QAAQ,MAAM,UAAU,kBACzF;AACD,SAAO;;;;;;;;;AAUT,eAAsB,iBACrB,SACA,cACA,iBACsC;CACtC,MAAM,0BAAU,IAAI,KAA4B;CAGhD,MAAM,cAAc,SAAS;AAC7B,aAAY,MAAM,oBAAoB;AAItC,KAAI,CAFgB,MAAM,mBAAmB,EAE3B;AACjB,cAAY,KAAK,wBAAwB;AAEzC,OAAK,MAAM,UAAU,gBACpB,SAAQ,IAAI,QAAQ,SAAS;AAE9B,SAAO;;AAGR,aAAY,KAAK,8BAA8B;CAG/C,MAAM,SAAS,MAAM,yBAAyB;AAE9C,KAAI,CAAC,QAAQ;AACZ,MAAI,MAAM,iDAAiD;AAC3D,MAAI,KACH,kFACA;AAED,OAAK,MAAM,UAAU,gBACpB,SAAQ,IAAI,QAAQ,SAAS;AAE9B,SAAO;;AAIR,MAAK,MAAM,UAAU,iBAAiB;EACrC,MAAM,SAAS,MAAM,0BACpB,SACA,cACA,QACA,OACA;AACD,UAAQ,IAAI,QAAQ,OAAO;;AAG5B,QAAO"}
@@ -0,0 +1,24 @@
1
+ import { Editor, MCPConfig } from "./types.js";
2
+
3
+ //#region src/lib/mcp-config.d.ts
4
+
5
+ /**
6
+ * Gets or creates the MCP configuration for a specific editor
7
+ * - Cursor: Global config at ~/.cursor/mcp.json
8
+ * - VS Code: Try global config first, then workspace
9
+ * - Claude CLI: Global config at ~/.claude.json
10
+ */
11
+ declare function getMCPConfig(homeDir: string, workspaceDir: string, editor: Editor): {
12
+ config: MCPConfig;
13
+ configPath: string;
14
+ };
15
+ /**
16
+ * Writes the MCP configuration to the appropriate location
17
+ * - Cursor: Global config at ~/.cursor/mcp.json
18
+ * - VS Code: Global config (preferred) or workspace config (fallback)
19
+ * - Claude CLI: Global config at ~/.claude.json
20
+ */
21
+ declare function writeMCPConfig(configPath: string, config: MCPConfig): void;
22
+ //#endregion
23
+ export { getMCPConfig, writeMCPConfig };
24
+ //# sourceMappingURL=mcp-config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-config.d.ts","names":[],"sources":["../../src/lib/mcp-config.ts"],"sourcesContent":[],"mappings":";;;;;;AAWA;;;;AAIsB,iBAJN,YAAA,CAIM,OAAA,EAAA,MAAA,EAAA,YAAA,EAAA,MAAA,EAAA,MAAA,EADb,MACa,CAAA,EAAA;EAgDN,MAAA,EAhDH,SAgDiB;;;;;;;;;iBAAd,cAAA,6BAA2C"}
@@ -0,0 +1,51 @@
1
+ import { getVSCodeGlobalConfigDir } from "./editors.js";
2
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
3
+ import { dirname, resolve } from "node:path";
4
+
5
+ //#region src/lib/mcp-config.ts
6
+ /**
7
+ * Gets or creates the MCP configuration for a specific editor
8
+ * - Cursor: Global config at ~/.cursor/mcp.json
9
+ * - VS Code: Try global config first, then workspace
10
+ * - Claude CLI: Global config at ~/.claude.json
11
+ */
12
+ function getMCPConfig(homeDir, workspaceDir, editor) {
13
+ let mcpConfigPath;
14
+ if (editor === "VS Code") {
15
+ const vscodeGlobalDir = getVSCodeGlobalConfigDir(homeDir);
16
+ if (vscodeGlobalDir && existsSync(vscodeGlobalDir)) mcpConfigPath = resolve(vscodeGlobalDir, "mcp.json");
17
+ else mcpConfigPath = resolve(workspaceDir, ".vscode", "mcp.json");
18
+ } else if (editor === "Claude CLI") mcpConfigPath = resolve(homeDir, ".claude.json");
19
+ else mcpConfigPath = resolve(homeDir, ".cursor", "mcp.json");
20
+ if (existsSync(mcpConfigPath)) try {
21
+ const content = readFileSync(mcpConfigPath, "utf-8");
22
+ return {
23
+ config: JSON.parse(content),
24
+ configPath: mcpConfigPath
25
+ };
26
+ } catch (_error) {
27
+ return {
28
+ config: editor === "VS Code" ? { servers: {} } : { mcpServers: {} },
29
+ configPath: mcpConfigPath
30
+ };
31
+ }
32
+ return {
33
+ config: editor === "VS Code" ? { servers: {} } : { mcpServers: {} },
34
+ configPath: mcpConfigPath
35
+ };
36
+ }
37
+ /**
38
+ * Writes the MCP configuration to the appropriate location
39
+ * - Cursor: Global config at ~/.cursor/mcp.json
40
+ * - VS Code: Global config (preferred) or workspace config (fallback)
41
+ * - Claude CLI: Global config at ~/.claude.json
42
+ */
43
+ function writeMCPConfig(configPath, config) {
44
+ const editorDir = dirname(configPath);
45
+ if (!existsSync(editorDir)) mkdirSync(editorDir, { recursive: true });
46
+ writeFileSync(configPath, JSON.stringify(config, null, 2), "utf-8");
47
+ }
48
+
49
+ //#endregion
50
+ export { getMCPConfig, writeMCPConfig };
51
+ //# sourceMappingURL=mcp-config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-config.js","names":["mcpConfigPath: string"],"sources":["../../src/lib/mcp-config.ts"],"sourcesContent":["import { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { dirname, resolve } from \"node:path\";\nimport { getVSCodeGlobalConfigDir } from \"./editors.js\";\nimport type { Editor, MCPConfig } from \"./types.js\";\n\n/**\n * Gets or creates the MCP configuration for a specific editor\n * - Cursor: Global config at ~/.cursor/mcp.json\n * - VS Code: Try global config first, then workspace\n * - Claude CLI: Global config at ~/.claude.json\n */\nexport function getMCPConfig(\n\thomeDir: string,\n\tworkspaceDir: string,\n\teditor: Editor,\n): { config: MCPConfig; configPath: string } {\n\tlet mcpConfigPath: string;\n\n\tif (editor === \"VS Code\") {\n\t\t// Try global config first\n\t\tconst vscodeGlobalDir = getVSCodeGlobalConfigDir(homeDir);\n\t\tif (vscodeGlobalDir && existsSync(vscodeGlobalDir)) {\n\t\t\tmcpConfigPath = resolve(vscodeGlobalDir, \"mcp.json\");\n\t\t} else {\n\t\t\t// Fall back to workspace\n\t\t\tmcpConfigPath = resolve(workspaceDir, \".vscode\", \"mcp.json\");\n\t\t}\n\t} else if (editor === \"Claude CLI\") {\n\t\t// Claude CLI uses ~/.claude.json\n\t\tmcpConfigPath = resolve(homeDir, \".claude.json\");\n\t} else {\n\t\t// Cursor uses ~/.cursor/mcp.json\n\t\tmcpConfigPath = resolve(homeDir, \".cursor\", \"mcp.json\");\n\t}\n\n\tif (existsSync(mcpConfigPath)) {\n\t\ttry {\n\t\t\tconst content = readFileSync(mcpConfigPath, \"utf-8\");\n\t\t\treturn {\n\t\t\t\tconfig: JSON.parse(content),\n\t\t\t\tconfigPath: mcpConfigPath,\n\t\t\t};\n\t\t} catch (_error) {\n\t\t\treturn {\n\t\t\t\tconfig:\n\t\t\t\t\teditor === \"VS Code\" ? { servers: {} } : { mcpServers: {} },\n\t\t\t\tconfigPath: mcpConfigPath,\n\t\t\t};\n\t\t}\n\t}\n\n\treturn {\n\t\tconfig: editor === \"VS Code\" ? { servers: {} } : { mcpServers: {} },\n\t\tconfigPath: mcpConfigPath,\n\t};\n}\n\n/**\n * Writes the MCP configuration to the appropriate location\n * - Cursor: Global config at ~/.cursor/mcp.json\n * - VS Code: Global config (preferred) or workspace config (fallback)\n * - Claude CLI: Global config at ~/.claude.json\n */\nexport function writeMCPConfig(configPath: string, config: MCPConfig): void {\n\tconst editorDir = dirname(configPath);\n\n\tif (!existsSync(editorDir)) {\n\t\tmkdirSync(editorDir, { recursive: true });\n\t}\n\n\twriteFileSync(configPath, JSON.stringify(config, null, 2), \"utf-8\");\n}\n"],"mappings":";;;;;;;;;;;AAWA,SAAgB,aACf,SACA,cACA,QAC4C;CAC5C,IAAIA;AAEJ,KAAI,WAAW,WAAW;EAEzB,MAAM,kBAAkB,yBAAyB,QAAQ;AACzD,MAAI,mBAAmB,WAAW,gBAAgB,CACjD,iBAAgB,QAAQ,iBAAiB,WAAW;MAGpD,iBAAgB,QAAQ,cAAc,WAAW,WAAW;YAEnD,WAAW,aAErB,iBAAgB,QAAQ,SAAS,eAAe;KAGhD,iBAAgB,QAAQ,SAAS,WAAW,WAAW;AAGxD,KAAI,WAAW,cAAc,CAC5B,KAAI;EACH,MAAM,UAAU,aAAa,eAAe,QAAQ;AACpD,SAAO;GACN,QAAQ,KAAK,MAAM,QAAQ;GAC3B,YAAY;GACZ;UACO,QAAQ;AAChB,SAAO;GACN,QACC,WAAW,YAAY,EAAE,SAAS,EAAE,EAAE,GAAG,EAAE,YAAY,EAAE,EAAE;GAC5D,YAAY;GACZ;;AAIH,QAAO;EACN,QAAQ,WAAW,YAAY,EAAE,SAAS,EAAE,EAAE,GAAG,EAAE,YAAY,EAAE,EAAE;EACnE,YAAY;EACZ;;;;;;;;AASF,SAAgB,eAAe,YAAoB,QAAyB;CAC3E,MAAM,YAAY,QAAQ,WAAW;AAErC,KAAI,CAAC,WAAW,UAAU,CACzB,WAAU,WAAW,EAAE,WAAW,MAAM,CAAC;AAG1C,eAAc,YAAY,KAAK,UAAU,QAAQ,MAAM,EAAE,EAAE,QAAQ"}
@@ -0,0 +1,22 @@
1
+ //#region src/lib/types.d.ts
2
+ type Editor = "Cursor" | "VS Code" | "Claude CLI";
3
+ type InstallStatus = "success" | "failed";
4
+ interface MCPConfig {
5
+ mcpServers?: {
6
+ [key: string]: {
7
+ type?: string;
8
+ url: string;
9
+ headers?: Record<string, string>;
10
+ };
11
+ };
12
+ servers?: {
13
+ [key: string]: {
14
+ type?: string;
15
+ url: string;
16
+ headers?: Record<string, string>;
17
+ };
18
+ };
19
+ }
20
+ //#endregion
21
+ export { Editor, InstallStatus, MCPConfig };
22
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","names":[],"sources":["../../src/lib/types.ts"],"sourcesContent":[],"mappings":";KAAY,MAAA;AAAA,KAEA,aAAA,GAFM,SAAA,GAAA,QAAA;AAEN,UAEK,SAAA,CAFQ;EAER,UAAA,CAAA,EAAS;IAAA,CAAA,GAAA,EAAA,MAAA,CAAA,EAAA;MAKb,IAAA,CAAA,EAAA,MAAA;MAOA,GAAA,EAAA,MAAA;MAAM,OAAA,CAAA,EAPN,MAOM,CAAA,MAAA,EAAA,MAAA,CAAA;;;;;;;gBAAN"}
@@ -0,0 +1 @@
1
+ export { };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "neon-init",
3
- "version": "0.9.1",
3
+ "version": "0.10.1",
4
4
  "description": "Initialize Neon projects",
5
5
  "keywords": [
6
6
  "neon",