neon 3.4.0 → 3.5.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,93 +1,6 @@
1
+ import { agents, detectGlobalAgents, getAgentTypes } from "add-mcp";
1
2
  //#region src/init/agents.ts
2
- /**
3
- * All agents that can be configured via neon-init.
4
- * Aligns with add-mcp's supported agents table.
5
- * https://github.com/neondatabase/add-mcp#supported-agents
6
- */
7
- const ALL_CONFIGURABLE_AGENTS = [
8
- {
9
- editor: "Cursor",
10
- addMcpId: "cursor",
11
- hint: "Neon Local Connect extension"
12
- },
13
- {
14
- editor: "VS Code",
15
- addMcpId: "vscode",
16
- hint: "Neon Local Connect extension"
17
- },
18
- {
19
- editor: "Claude CLI",
20
- addMcpId: "claude-code",
21
- hint: "MCP Server"
22
- },
23
- {
24
- editor: "Claude Desktop",
25
- addMcpId: "claude-desktop",
26
- hint: "MCP Server"
27
- },
28
- {
29
- editor: "Codex",
30
- addMcpId: "codex",
31
- hint: "MCP Server"
32
- },
33
- {
34
- editor: "OpenCode",
35
- addMcpId: "opencode",
36
- hint: "MCP Server"
37
- },
38
- {
39
- editor: "Antigravity",
40
- addMcpId: "antigravity",
41
- hint: "MCP Server"
42
- },
43
- {
44
- editor: "Cline",
45
- addMcpId: "cline",
46
- hint: "MCP Server"
47
- },
48
- {
49
- editor: "Cline CLI",
50
- addMcpId: "cline-cli",
51
- hint: "MCP Server"
52
- },
53
- {
54
- editor: "Gemini CLI",
55
- addMcpId: "gemini-cli",
56
- hint: "MCP Server"
57
- },
58
- {
59
- editor: "GitHub Copilot CLI",
60
- addMcpId: "github-copilot-cli",
61
- hint: "MCP Server"
62
- },
63
- {
64
- editor: "Goose",
65
- addMcpId: "goose",
66
- hint: "MCP Server"
67
- },
68
- {
69
- editor: "MCPorter",
70
- addMcpId: "mcporter",
71
- hint: "MCP Server"
72
- },
73
- {
74
- editor: "Zed",
75
- addMcpId: "zed",
76
- hint: "MCP Server"
77
- }
78
- ];
79
- function getAddMcpAgentId(editor) {
80
- const agent = ALL_CONFIGURABLE_AGENTS.find((a) => a.editor === editor);
81
- if (!agent) throw new Error(`No add-mcp agent ID found for editor: ${editor}`);
82
- return agent.addMcpId;
83
- }
84
- /**
85
- * Maps a raw agent identifier (as reported by agents or passed via --agent)
86
- * to the add-mcp compatible agent ID.
87
- *
88
- * This handles aliases like "copilot" → "vscode", "claude" → "claude-code", etc.
89
- */
90
- const AGENT_ALIAS_TO_MCP_ID = {
3
+ const AGENT_ALIASES = {
91
4
  cursor: "cursor",
92
5
  copilot: "vscode",
93
6
  "github-copilot": "vscode",
@@ -101,46 +14,87 @@ const AGENT_ALIAS_TO_MCP_ID = {
101
14
  antigravity: "antigravity",
102
15
  cline: "cline",
103
16
  "cline-cli": "cline-cli",
17
+ "cline-vscode": "cline",
104
18
  "gemini-cli": "gemini-cli",
105
19
  gemini: "gemini-cli",
106
20
  goose: "goose",
107
21
  windsurf: "windsurf",
22
+ codeium: "windsurf",
23
+ cascade: "windsurf",
108
24
  "github-copilot-cli": "github-copilot-cli",
109
25
  mcporter: "mcporter",
110
- zed: "zed"
26
+ zed: "zed",
27
+ grok: "grok-build",
28
+ "grok-build": "grok-build"
29
+ };
30
+ const SKILLS_AGENT_BY_TYPE = {
31
+ cursor: "cursor",
32
+ vscode: "github-copilot",
33
+ "claude-code": "claude-code",
34
+ "claude-desktop": "claude-code",
35
+ codex: "codex",
36
+ opencode: "opencode",
37
+ antigravity: "antigravity",
38
+ cline: "cline",
39
+ "cline-cli": "cline",
40
+ "gemini-cli": "gemini-cli",
41
+ goose: "goose",
42
+ "github-copilot-cli": "github-copilot",
43
+ windsurf: "windsurf",
44
+ zed: "zed",
45
+ "grok-build": "grok"
111
46
  };
47
+ function listMcpAgentIds() {
48
+ return getAgentTypes();
49
+ }
50
+ function getAgentDisplayName(id) {
51
+ return agents[id].displayName;
52
+ }
53
+ function agentSupportsProjectMcp(id) {
54
+ return Boolean(agents[id].localConfigPath);
55
+ }
56
+ function agentSupportsHttpMcp(id) {
57
+ return agents[id].supportedTransports.includes("http");
58
+ }
59
+ function tryResolveAddMcpAgentId(rawAgent) {
60
+ return AGENT_ALIASES[rawAgent.toLowerCase()];
61
+ }
112
62
  function resolveAddMcpAgentId(rawAgent) {
113
- const resolved = AGENT_ALIAS_TO_MCP_ID[rawAgent.toLowerCase()];
114
- if (!resolved) throw new Error(`Unknown agent: "${rawAgent}". Supported agents: ${Object.keys(AGENT_ALIAS_TO_MCP_ID).join(", ")}`);
63
+ const resolved = tryResolveAddMcpAgentId(rawAgent);
64
+ if (!resolved) throw new Error(`Unknown agent: "${rawAgent}". Supported agents: ${listMcpAgentIds().join(", ")}`);
115
65
  return resolved;
116
66
  }
117
- /**
118
- * Maps a raw agent identifier to the skills CLI agent name.
119
- */
120
67
  function getSkillsAgentName(agent) {
121
- switch (agent.toLowerCase()) {
122
- case "cursor": return "cursor";
123
- case "copilot":
124
- case "vscode":
125
- case "vs-code":
126
- case "github-copilot": return "github-copilot";
127
- case "claude":
128
- case "claude-code": return "claude-code";
129
- case "codex": return "codex";
130
- case "opencode": return "opencode";
131
- case "antigravity": return "antigravity";
132
- case "cline": return "cline";
133
- case "gemini-cli": return "gemini-cli";
134
- case "goose": return "goose";
135
- case "claude-desktop": return "claude-code";
136
- case "cline-cli": return "cline";
137
- case "gemini": return "gemini-cli";
138
- case "windsurf": return "windsurf";
139
- case "github-copilot-cli": return "github-copilot";
140
- case "mcporter": return "mcporter";
141
- case "zed": return "zed";
142
- default: return "cursor";
143
- }
68
+ if (Object.prototype.hasOwnProperty.call(SKILLS_AGENT_BY_TYPE, agent)) return SKILLS_AGENT_BY_TYPE[agent];
69
+ const id = tryResolveAddMcpAgentId(agent);
70
+ if (!id) return void 0;
71
+ return SKILLS_AGENT_BY_TYPE[id];
72
+ }
73
+ function supportsSkills(agent) {
74
+ return getSkillsAgentName(agent) !== void 0;
75
+ }
76
+ function agentPickerHint(id) {
77
+ if (id === "cursor" || id === "vscode") return "Neon Local Connect extension";
78
+ if (id === "claude-desktop") return supportsSkills(id) ? "Connectors in the app, skills" : agents[id].unsupportedTransportMessage ?? "Add remote servers through Connectors in the app";
79
+ if (supportsSkills(id)) return "MCP server, skills";
80
+ return "MCP server";
81
+ }
82
+ async function detectInstalledAgents() {
83
+ return detectGlobalAgents();
84
+ }
85
+ function mcpPickerOptions() {
86
+ return listMcpAgentIds().map((id) => ({
87
+ value: id,
88
+ label: getAgentDisplayName(id),
89
+ hint: agentPickerHint(id)
90
+ }));
91
+ }
92
+ function skillsPickerOptions() {
93
+ return listMcpAgentIds().filter((id) => supportsSkills(id)).map((id) => ({
94
+ value: id,
95
+ label: getAgentDisplayName(id),
96
+ hint: "agent skills"
97
+ }));
144
98
  }
145
99
  //#endregion
146
- export { ALL_CONFIGURABLE_AGENTS, getAddMcpAgentId, getSkillsAgentName, resolveAddMcpAgentId };
100
+ export { agentPickerHint, agentSupportsHttpMcp, agentSupportsProjectMcp, detectInstalledAgents, getAgentDisplayName, getSkillsAgentName, listMcpAgentIds, mcpPickerOptions, resolveAddMcpAgentId, skillsPickerOptions, supportsSkills, tryResolveAddMcpAgentId };
@@ -1,10 +1,6 @@
1
- import { existsSync } from "node:fs";
1
+ import { detectInstalledAgents } from "./agents.js";
2
2
  import { resolve } from "node:path";
3
- import { execa } from "execa";
4
3
  //#region src/init/editors.ts
5
- /**
6
- * Gets VS Code's global config directory based on the platform
7
- */
8
4
  function getVSCodeGlobalConfigDir(homeDir) {
9
5
  const platform = process.platform;
10
6
  if (platform === "darwin") return resolve(homeDir, "Library", "Application Support", "Code", "User");
@@ -15,31 +11,8 @@ function getVSCodeGlobalConfigDir(homeDir) {
15
11
  }
16
12
  return null;
17
13
  }
18
- /**
19
- * Checks if Claude CLI is installed
20
- */
21
- async function isClaudeCLIInstalled() {
22
- try {
23
- await execa("claude", ["--version"], {
24
- stdio: "ignore",
25
- timeout: 5e3
26
- });
27
- return true;
28
- } catch {
29
- return false;
30
- }
31
- }
32
- /**
33
- * Detects which editors are installed on the system
34
- */
35
- async function detectAvailableEditors(homeDir) {
36
- const editors = [];
37
- const cursorDir = resolve(homeDir, ".cursor");
38
- if (existsSync(cursorDir)) 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;
14
+ async function detectAvailableEditors(_homeDir) {
15
+ return detectInstalledAgents();
43
16
  }
44
17
  //#endregion
45
18
  export { detectAvailableEditors, getVSCodeGlobalConfigDir };
@@ -1,5 +1,7 @@
1
1
  import { existsSync, readFileSync } from "node:fs";
2
- import { resolve } from "node:path";
2
+ import { resolve, sep } from "node:path";
3
+ import { homedir } from "node:os";
4
+ import { agents, getAgentTypes } from "add-mcp";
3
5
  //#region src/init/inspect.ts
4
6
  /**
5
7
  * Filesystem-based project inspection for interactive (agentless) mode.
@@ -15,9 +17,10 @@ async function inspectProject(checks) {
15
17
  const cwd = process.cwd();
16
18
  for (const check of checks) switch (check.id) {
17
19
  case "mcp_server": {
18
- const mcpScope = checkMcpServer(cwd);
19
- results.mcpConfigured = mcpScope !== false;
20
- results.mcpScope = mcpScope;
20
+ const hits = findNeonMcpAgents(cwd);
21
+ results.mcpAgents = hits;
22
+ results.mcpConfigured = hits.length > 0;
23
+ results.mcpScope = mcpScopeFromHits(hits);
21
24
  break;
22
25
  }
23
26
  case "connection_string":
@@ -51,24 +54,70 @@ async function inspectProject(checks) {
51
54
  }
52
55
  return results;
53
56
  }
54
- function checkMcpServer(cwd) {
55
- const home = process.env.HOME || process.env.USERPROFILE || "";
56
- const projectConfigs = [resolve(cwd, ".cursor", "mcp.json"), resolve(cwd, ".vscode", "settings.json")];
57
- for (const configPath of projectConfigs) if (existsSync(configPath)) try {
58
- const content = readFileSync(configPath, "utf-8");
59
- if (content.includes("neon") || content.includes("mcp.neon.tech")) return "project";
60
- } catch {}
61
- const globalConfigs = [
62
- resolve(home, ".cursor", "mcp.json"),
63
- resolve(home, ".claude", "settings.local.json"),
64
- resolve(home, ".claude", "settings.json")
65
- ];
66
- for (const configPath of globalConfigs) if (existsSync(configPath)) try {
67
- const content = readFileSync(configPath, "utf-8");
68
- if (content.includes("neon") || content.includes("mcp.neon.tech")) return "global";
69
- } catch {}
57
+ function mcpScopeFromHits(hits) {
58
+ if (hits.some((hit) => hit.scope === "project")) return "project";
59
+ if (hits.some((hit) => hit.scope === "global")) return "global";
70
60
  return false;
71
61
  }
62
+ function addMcpBakedHome() {
63
+ const cursorPath = agents.cursor.configPath;
64
+ const suffix = `${sep}.cursor${sep}mcp.json`;
65
+ if (cursorPath.endsWith(suffix)) return cursorPath.slice(0, -suffix.length);
66
+ return homedir();
67
+ }
68
+ function rebaseAddMcpHome(configPath) {
69
+ const currentHome = process.env.HOME || process.env.USERPROFILE || homedir();
70
+ const baked = addMcpBakedHome();
71
+ if (configPath.startsWith(baked)) return currentHome + configPath.slice(baked.length);
72
+ return configPath;
73
+ }
74
+ function agentProjectPath(id, cwd) {
75
+ const agent = agents[id];
76
+ if (agent.resolveConfigPath && agent.localConfigPath) return agent.resolveConfigPath(agent, {
77
+ local: true,
78
+ cwd
79
+ });
80
+ if (agent.localConfigPath) return resolve(cwd, agent.localConfigPath);
81
+ }
82
+ function agentGlobalPath(id, cwd) {
83
+ const agent = agents[id];
84
+ if (agent.resolveConfigPath) return rebaseAddMcpHome(agent.resolveConfigPath(agent, {
85
+ local: false,
86
+ cwd
87
+ }));
88
+ return rebaseAddMcpHome(agent.configPath);
89
+ }
90
+ function fileHasNeonMcp(configPath) {
91
+ if (!existsSync(configPath)) return false;
92
+ try {
93
+ const content = readFileSync(configPath, "utf-8");
94
+ if (content.toLowerCase().includes("mcp.neon.tech")) return true;
95
+ if (/"neon"\s*:/i.test(content)) return true;
96
+ if (/\[mcp_servers\.neon\]/i.test(content)) return true;
97
+ if (/^neon\s*=/im.test(content)) return true;
98
+ return false;
99
+ } catch {
100
+ return false;
101
+ }
102
+ }
103
+ function findNeonMcpAgents(cwd) {
104
+ const hits = [];
105
+ for (const id of getAgentTypes()) {
106
+ const projectPath = agentProjectPath(id, cwd);
107
+ if (projectPath && fileHasNeonMcp(projectPath)) {
108
+ hits.push({
109
+ agent: id,
110
+ scope: "project"
111
+ });
112
+ continue;
113
+ }
114
+ if (fileHasNeonMcp(agentGlobalPath(id, cwd))) hits.push({
115
+ agent: id,
116
+ scope: "global"
117
+ });
118
+ }
119
+ return hits;
120
+ }
72
121
  function checkConnectionString(cwd) {
73
122
  for (const envFile of [".env", ".env.local"]) {
74
123
  const envPath = resolve(cwd, envFile);
@@ -0,0 +1,35 @@
1
+ import { agents, upsertServer } from "add-mcp";
2
+ //#region src/init/install_mcp.ts
3
+ const NEON_MCP_URL = "https://mcp.neon.tech/mcp";
4
+ const NEON_MCP_NAME = "Neon";
5
+ function installNeonMcpServer(options) {
6
+ const agent = agents[options.agent];
7
+ if (!agent.supportedTransports.includes("http")) return {
8
+ ok: false,
9
+ unsupported: true,
10
+ error: agent.unsupportedTransportMessage ?? `${agent.displayName} does not support remote HTTP MCP servers.`
11
+ };
12
+ if (options.scope === "project" && !agent.localConfigPath) return {
13
+ ok: false,
14
+ unsupported: true,
15
+ error: `${agent.displayName} does not support project-level MCP config.`
16
+ };
17
+ const result = upsertServer(options.agent, NEON_MCP_NAME, {
18
+ type: "http",
19
+ url: NEON_MCP_URL
20
+ }, {
21
+ local: options.scope === "project",
22
+ cwd: options.cwd
23
+ });
24
+ if (result.success) return {
25
+ ok: true,
26
+ path: result.path
27
+ };
28
+ return {
29
+ ok: false,
30
+ unsupported: false,
31
+ error: result.error ?? "Failed to write Neon MCP server config"
32
+ };
33
+ }
34
+ //#endregion
35
+ export { NEON_MCP_NAME, NEON_MCP_URL, installNeonMcpServer };