neon-init 0.13.0 → 0.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +4 -5
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +15 -30
- package/dist/index.js.map +1 -1
- package/dist/lib/agents.d.ts +18 -0
- package/dist/lib/agents.d.ts.map +1 -0
- package/dist/lib/agents.js +87 -0
- package/dist/lib/agents.js.map +1 -0
- package/dist/lib/auth.js +1 -2
- package/dist/lib/auth.js.map +1 -1
- package/dist/lib/editors.js +1 -2
- package/dist/lib/editors.js.map +1 -1
- package/dist/lib/extension.js +1 -2
- package/dist/lib/extension.js.map +1 -1
- package/dist/lib/install.d.ts +1 -1
- package/dist/lib/install.d.ts.map +1 -1
- package/dist/lib/install.js +43 -57
- package/dist/lib/install.js.map +1 -1
- package/dist/lib/skills.d.ts +1 -1
- package/dist/lib/skills.d.ts.map +1 -1
- package/dist/lib/skills.js +19 -20
- package/dist/lib/skills.js.map +1 -1
- package/dist/lib/types.d.ts +2 -18
- package/dist/lib/types.d.ts.map +1 -1
- package/dist/lib/types.js +1 -1
- package/package.json +3 -2
- package/dist/lib/mcp-config.d.ts +0 -24
- package/dist/lib/mcp-config.d.ts.map +0 -1
- package/dist/lib/mcp-config.js +0 -51
- package/dist/lib/mcp-config.js.map +0 -1
package/dist/cli.js
CHANGED
|
@@ -2,12 +2,11 @@
|
|
|
2
2
|
import { init } from "./index.js";
|
|
3
3
|
import yargs from "yargs";
|
|
4
4
|
import { hideBin } from "yargs/helpers";
|
|
5
|
-
|
|
6
5
|
//#region src/cli.ts
|
|
7
6
|
const AGENT_FLAG_VALUES = [
|
|
8
7
|
"cursor",
|
|
9
8
|
"copilot",
|
|
10
|
-
"
|
|
9
|
+
"claude"
|
|
11
10
|
];
|
|
12
11
|
function parseAgentToEditor(value) {
|
|
13
12
|
switch (value.trim().toLowerCase()) {
|
|
@@ -27,7 +26,7 @@ function parseAgentToEditor(value) {
|
|
|
27
26
|
const agentArg = yargs(hideBin(process.argv)).scriptName("neon-init").option("agent", {
|
|
28
27
|
alias: "a",
|
|
29
28
|
type: "string",
|
|
30
|
-
description: "Agent to configure (cursor, copilot,
|
|
29
|
+
description: "Agent to configure (cursor, copilot, claude)."
|
|
31
30
|
}).help().parseSync().agent;
|
|
32
31
|
if (agentArg !== void 0) {
|
|
33
32
|
const editor = parseAgentToEditor(agentArg);
|
|
@@ -37,7 +36,7 @@ if (agentArg !== void 0) {
|
|
|
37
36
|
}
|
|
38
37
|
await init({ agent: editor });
|
|
39
38
|
} else await init();
|
|
40
|
-
|
|
41
39
|
//#endregion
|
|
42
|
-
export {
|
|
40
|
+
export {};
|
|
41
|
+
|
|
43
42
|
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","names":[],"sources":["../src/cli.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport yargs from \"yargs\";\nimport { hideBin } from \"yargs/helpers\";\nimport { init } from \"./index.js\";\nimport type { Editor } from \"./lib/types.js\";\n\nconst AGENT_FLAG_VALUES = [\"cursor\", \"copilot\", \"
|
|
1
|
+
{"version":3,"file":"cli.js","names":[],"sources":["../src/cli.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport yargs from \"yargs\";\nimport { hideBin } from \"yargs/helpers\";\nimport { init } from \"./index.js\";\nimport type { Editor } from \"./lib/types.js\";\n\nconst AGENT_FLAG_VALUES = [\"cursor\", \"copilot\", \"claude\"] as const;\n\nfunction parseAgentToEditor(value: string): Editor | null {\n\tconst normalized = value.trim().toLowerCase();\n\tswitch (normalized) {\n\t\tcase \"cursor\":\n\t\t\treturn \"Cursor\";\n\t\tcase \"github-copilot\":\n\t\tcase \"copilot\":\n\t\tcase \"vs code\":\n\t\tcase \"vscode\":\n\t\tcase \"vs-code\":\n\t\t\treturn \"VS Code\";\n\t\tcase \"claude-code\":\n\t\tcase \"claude cli\":\n\t\tcase \"claude-cli\":\n\t\tcase \"claude\":\n\t\t\treturn \"Claude CLI\";\n\t\tdefault:\n\t\t\treturn null;\n\t}\n}\n\nconst argv = yargs(hideBin(process.argv))\n\t.scriptName(\"neon-init\")\n\t.option(\"agent\", {\n\t\talias: \"a\",\n\t\ttype: \"string\",\n\t\tdescription: \"Agent to configure (cursor, copilot, claude).\",\n\t})\n\t.help()\n\t.parseSync();\n\nconst agentArg = argv.agent;\nif (agentArg !== undefined) {\n\tconst editor = parseAgentToEditor(agentArg);\n\tif (editor === null) {\n\t\tconsole.error(\n\t\t\t`Invalid --agent value: \"${agentArg}\". Supported: ${AGENT_FLAG_VALUES.join(\", \")}`,\n\t\t);\n\t\tprocess.exit(1);\n\t}\n\tawait init({ agent: editor });\n} else {\n\tawait init();\n}\n"],"mappings":";;;;;AAOA,MAAM,oBAAoB;CAAC;CAAU;CAAW;CAAS;AAEzD,SAAS,mBAAmB,OAA8B;AAEzD,SADmB,MAAM,MAAM,CAAC,aAAa,EAC7C;EACC,KAAK,SACJ,QAAO;EACR,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK,UACJ,QAAO;EACR,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK,SACJ,QAAO;EACR,QACC,QAAO;;;AAcV,MAAM,WAVO,MAAM,QAAQ,QAAQ,KAAK,CAAC,CACvC,WAAW,YAAY,CACvB,OAAO,SAAS;CAChB,OAAO;CACP,MAAM;CACN,aAAa;CACb,CAAC,CACD,MAAM,CACN,WAAW,CAES;AACtB,IAAI,aAAa,KAAA,GAAW;CAC3B,MAAM,SAAS,mBAAmB,SAAS;AAC3C,KAAI,WAAW,MAAM;AACpB,UAAQ,MACP,2BAA2B,SAAS,gBAAgB,kBAAkB,KAAK,KAAK,GAChF;AACD,UAAQ,KAAK,EAAE;;AAEhB,OAAM,KAAK,EAAE,OAAO,QAAQ,CAAC;MAE7B,OAAM,MAAM"}
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/index.ts"],"sourcesContent":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/index.ts"],"sourcesContent":[],"mappings":";;;UASiB,WAAA;;EAAA,KAAA,CAAA,EAER,MAFmB;AAQ5B;;;;AAA0D,iBAApC,IAAA,CAAoC,OAAA,CAAA,EAArB,WAAqB,CAAA,EAAP,OAAO,CAAA,IAAA,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -1,52 +1,34 @@
|
|
|
1
|
+
import { ALL_CONFIGURABLE_AGENTS } from "./lib/agents.js";
|
|
1
2
|
import { detectAvailableEditors } from "./lib/editors.js";
|
|
2
3
|
import { usesExtension } from "./lib/extension.js";
|
|
3
4
|
import { installNeon } from "./lib/install.js";
|
|
4
5
|
import { installAgentSkills } from "./lib/skills.js";
|
|
5
|
-
import {
|
|
6
|
+
import { intro, isCancel, log, multiselect, note, outro } from "@clack/prompts";
|
|
6
7
|
import { bold, cyan } from "yoctocolors";
|
|
7
|
-
|
|
8
8
|
//#region src/index.ts
|
|
9
9
|
/**
|
|
10
10
|
* Initialize Neon projects with MCP Server
|
|
11
11
|
*/
|
|
12
12
|
async function init(options) {
|
|
13
|
-
intro(
|
|
13
|
+
if (options?.agent !== void 0) if (usesExtension(options.agent)) intro(`Adding Neon extension (includes MCP server) and agent skills for ${options.agent}`);
|
|
14
|
+
else intro(`Adding Neon MCP server and agent skills for ${options.agent}`);
|
|
15
|
+
else intro("Adding Neon MCP server, extension (for VS Code and Cursor) and agent skills");
|
|
14
16
|
const homeDir = process.env.HOME || process.env.USERPROFILE;
|
|
15
17
|
if (!homeDir) {
|
|
16
18
|
log.error("Could not determine home directory");
|
|
17
19
|
outro("📣 Is this unexpected? Email us at feedback@neon.tech");
|
|
18
20
|
process.exit(1);
|
|
19
21
|
}
|
|
20
|
-
const workspaceDir = process.cwd();
|
|
21
22
|
let selectedEditors;
|
|
22
23
|
if (options?.agent !== void 0) selectedEditors = [options.agent];
|
|
23
24
|
else {
|
|
24
25
|
const availableEditors = await detectAvailableEditors(homeDir);
|
|
25
|
-
if (availableEditors.length === 0) {
|
|
26
|
-
log.warn("No supported editors detected on your system.");
|
|
27
|
-
log.info("Supported editors:");
|
|
28
|
-
log.info(" • VS Code (with Neon Local Connect extension)");
|
|
29
|
-
log.info(" • Cursor (with Neon Local Connect extension)");
|
|
30
|
-
log.info(" • Claude CLI (with MCP Server)");
|
|
31
|
-
const continueAnyway = await confirm({
|
|
32
|
-
message: "Would you like to configure Neon anyway? (You can manually select your editor)",
|
|
33
|
-
initialValue: true
|
|
34
|
-
});
|
|
35
|
-
if (isCancel(continueAnyway) || !continueAnyway) {
|
|
36
|
-
outro("Installation cancelled");
|
|
37
|
-
process.exit(0);
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
26
|
const response = await multiselect({
|
|
41
27
|
message: "Which editor(s) would you like to configure? (Space to toggle each option, Enter to confirm your selection)",
|
|
42
|
-
options:
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
].map((editor) => ({
|
|
47
|
-
value: editor,
|
|
48
|
-
label: editor,
|
|
49
|
-
hint: editor === "Claude CLI" ? "MCP Server" : "Neon Local Connect extension"
|
|
28
|
+
options: ALL_CONFIGURABLE_AGENTS.map((agent) => ({
|
|
29
|
+
value: agent.editor,
|
|
30
|
+
label: agent.editor,
|
|
31
|
+
hint: agent.hint
|
|
50
32
|
})),
|
|
51
33
|
initialValues: availableEditors,
|
|
52
34
|
required: true
|
|
@@ -62,7 +44,7 @@ async function init(options) {
|
|
|
62
44
|
outro("Installation cancelled");
|
|
63
45
|
process.exit(0);
|
|
64
46
|
}
|
|
65
|
-
const results = await installNeon(
|
|
47
|
+
const results = await installNeon(selectedEditors);
|
|
66
48
|
const successful = [];
|
|
67
49
|
const failed = [];
|
|
68
50
|
for (const [editor, status] of results.entries()) if (status === "success") successful.push(editor);
|
|
@@ -85,7 +67,10 @@ async function init(options) {
|
|
|
85
67
|
for (const editor of failedExtensionEditors) if (editor === "VS Code") log.info(" • VS Code: https://marketplace.visualstudio.com/items?itemName=databricks.neon-local-connect");
|
|
86
68
|
else if (editor === "Cursor") log.info(" • Cursor: https://open-vsx.org/extension/databricks/neon-local-connect");
|
|
87
69
|
}
|
|
88
|
-
if (failedMcpEditors.length > 0)
|
|
70
|
+
if (failedMcpEditors.length > 0) {
|
|
71
|
+
log.error(`Failed to configure MCP Server for ${failedMcpEditors.join(" / ")}`);
|
|
72
|
+
log.info("You can manually configure the MCP server by running: npx add-mcp https://mcp.neon.tech/mcp");
|
|
73
|
+
}
|
|
89
74
|
if (successful.length === 0) {
|
|
90
75
|
outro("Installation cancelled or failed. Please check the output above and try again.");
|
|
91
76
|
process.exit(1);
|
|
@@ -95,7 +80,7 @@ async function init(options) {
|
|
|
95
80
|
else note(`\x1b[0mFor ${extensionEditors.join(" / ")}: Restart, open the Neon extension and type in "${bold(cyan("Get started with Neon"))}\x1b[0m" in your agent chat\n\x1b[0mFor ${mcpEditors.join(" / ")}: Restart and type in "${bold(cyan("Get started with Neon"))}\x1b[0m" in the chat`, "What's next?");
|
|
96
81
|
outro("Have feedback? Email us at feedback@neon.tech");
|
|
97
82
|
}
|
|
98
|
-
|
|
99
83
|
//#endregion
|
|
100
84
|
export { init };
|
|
85
|
+
|
|
101
86
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["import {
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["import { intro, isCancel, log, multiselect, note, outro } from \"@clack/prompts\";\nimport { bold, cyan } from \"yoctocolors\";\nimport { ALL_CONFIGURABLE_AGENTS } from \"./lib/agents.js\";\nimport { detectAvailableEditors } from \"./lib/editors.js\";\nimport { usesExtension } from \"./lib/extension.js\";\nimport { installNeon } from \"./lib/install.js\";\nimport { installAgentSkills } from \"./lib/skills.js\";\nimport type { Editor } from \"./lib/types.js\";\n\nexport interface InitOptions {\n\t/** When set, configures only this agent and skips the editor selection prompt. */\n\tagent?: Editor;\n}\n\n/**\n * Initialize Neon projects with MCP Server\n */\nexport async function init(options?: InitOptions): Promise<void> {\n\tif (options?.agent !== undefined) {\n\t\tif (usesExtension(options.agent)) {\n\t\t\tintro(\n\t\t\t\t`Adding Neon extension (includes MCP server) and agent skills for ${options.agent}`,\n\t\t\t);\n\t\t} else {\n\t\t\tintro(\n\t\t\t\t`Adding Neon MCP server and agent skills for ${options.agent}`,\n\t\t\t);\n\t\t}\n\t} else {\n\t\tintro(\n\t\t\t\"Adding Neon MCP server, extension (for VS Code and Cursor) and agent skills\",\n\t\t);\n\t}\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\tlet selectedEditors: Editor[];\n\n\tif (options?.agent !== undefined) {\n\t\tselectedEditors = [options.agent];\n\t} else {\n\t\t// Detect available editors\n\t\tconst availableEditors = await detectAvailableEditors(homeDir);\n\n\t\t// Determine which editors to configure\n\t\tconst response = await multiselect({\n\t\t\tmessage:\n\t\t\t\t\"Which editor(s) would you like to configure? (Space to toggle each option, Enter to confirm your selection)\",\n\t\t\toptions: ALL_CONFIGURABLE_AGENTS.map((agent) => ({\n\t\t\t\tvalue: agent.editor,\n\t\t\t\tlabel: agent.editor,\n\t\t\t\thint: agent.hint,\n\t\t\t})),\n\t\t\tinitialValues: availableEditors, // Select detected editors by default\n\t\t\trequired: true,\n\t\t});\n\n\t\tif (isCancel(response)) {\n\t\t\toutro(\"Installation cancelled\");\n\t\t\tprocess.exit(0);\n\t\t}\n\n\t\tselectedEditors = response as Editor[];\n\t}\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 Neon for selected editors\n\tconst results = await installNeon(selectedEditors);\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\n\t// Install agent skills for successful installations\n\tif (successful.length > 0) {\n\t\tawait installAgentSkills(successful);\n\t}\n\n\t// Show different messages based on what was installed\n\tconst extensionEditors = successful.filter(usesExtension);\n\tconst mcpEditors = successful.filter((e) => !usesExtension(e));\n\tconst failedExtensionEditors = failed.filter(usesExtension);\n\tconst failedMcpEditors = failed.filter((e) => !usesExtension(e));\n\n\tif (extensionEditors.length > 0) {\n\t\tconst extSuccessList = extensionEditors.join(\" / \");\n\t\tlog.step(\n\t\t\t`Neon Local Connect extension installed for ${extSuccessList}.\\n`,\n\t\t);\n\t}\n\n\tif (mcpEditors.length > 0) {\n\t\tconst mcpSuccessList = mcpEditors.join(\" / \");\n\t\tlog.step(\n\t\t\t`Neon MCP Server is now ready to use with ${mcpSuccessList}.\\n`,\n\t\t);\n\t}\n\n\t// Show helpful installation links for failed extension installations\n\tif (failedExtensionEditors.length > 0) {\n\t\tlog.info(\n\t\t\t\"Failed to install extension. For the best local development experience, install Neon Local Connect manually:\",\n\t\t);\n\t\tfor (const editor of failedExtensionEditors) {\n\t\t\tif (editor === \"VS Code\") {\n\t\t\t\tlog.info(\n\t\t\t\t\t\" • VS Code: https://marketplace.visualstudio.com/items?itemName=databricks.neon-local-connect\",\n\t\t\t\t);\n\t\t\t} else if (editor === \"Cursor\") {\n\t\t\t\tlog.info(\n\t\t\t\t\t\" • Cursor: https://open-vsx.org/extension/databricks/neon-local-connect\",\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\tif (failedMcpEditors.length > 0) {\n\t\tlog.error(\n\t\t\t`Failed to configure MCP Server for ${failedMcpEditors.join(\" / \")}`,\n\t\t);\n\t\tlog.info(\n\t\t\t\"You can manually configure the MCP server by running: npx add-mcp https://mcp.neon.tech/mcp\",\n\t\t);\n\t}\n\n\t// Exit with error if all installations 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\tif (extensionEditors.length > 0 && mcpEditors.length === 0) {\n\t\t// Only extension editors (VS Code/Cursor)\n\t\tconst extSuccessList = extensionEditors.join(\" / \");\n\t\tnote(\n\t\t\t`\\x1b[0mRestart ${extSuccessList}, open the Neon extension and type in \"${bold(cyan(\"Get started with Neon\"))}\\x1b[0m\" in your agent chat`,\n\t\t\t\"What's next?\",\n\t\t);\n\t} else if (mcpEditors.length > 0 && extensionEditors.length === 0) {\n\t\t// Only MCP editors (Claude CLI)\n\t\tconst mcpSuccessList = mcpEditors.join(\" / \");\n\t\tnote(\n\t\t\t`\\x1b[0mRestart ${mcpSuccessList} and type in \"${bold(cyan(\"Get started with Neon\"))}\\x1b[0m\" in the chat`,\n\t\t\t\"What's next?\",\n\t\t);\n\t} else {\n\t\t// Mixed editors\n\t\tnote(\n\t\t\t`\\x1b[0mFor ${extensionEditors.join(\" / \")}: Restart, open the Neon extension and type in \"${bold(cyan(\"Get started with Neon\"))}\\x1b[0m\" in your agent chat\\n\\x1b[0mFor ${mcpEditors.join(\" / \")}: Restart and type in \"${bold(cyan(\"Get started with Neon\"))}\\x1b[0m\" in the chat`,\n\t\t\t\"What's next?\",\n\t\t);\n\t}\n\n\toutro(\"Have feedback? Email us at feedback@neon.tech\");\n}\n"],"mappings":";;;;;;;;;;;AAiBA,eAAsB,KAAK,SAAsC;AAChE,KAAI,SAAS,UAAU,KAAA,EACtB,KAAI,cAAc,QAAQ,MAAM,CAC/B,OACC,oEAAoE,QAAQ,QAC5E;KAED,OACC,+CAA+C,QAAQ,QACvD;KAGF,OACC,8EACA;CAIF,MAAM,UAAU,QAAQ,IAAI,QAAQ,QAAQ,IAAI;AAChD,KAAI,CAAC,SAAS;AACb,MAAI,MAAM,qCAAqC;AAC/C,QAAM,wDAAwD;AAC9D,UAAQ,KAAK,EAAE;;CAGhB,IAAI;AAEJ,KAAI,SAAS,UAAU,KAAA,EACtB,mBAAkB,CAAC,QAAQ,MAAM;MAC3B;EAEN,MAAM,mBAAmB,MAAM,uBAAuB,QAAQ;EAG9D,MAAM,WAAW,MAAM,YAAY;GAClC,SACC;GACD,SAAS,wBAAwB,KAAK,WAAW;IAChD,OAAO,MAAM;IACb,OAAO,MAAM;IACb,MAAM,MAAM;IACZ,EAAE;GACH,eAAe;GACf,UAAU;GACV,CAAC;AAEF,MAAI,SAAS,SAAS,EAAE;AACvB,SAAM,yBAAyB;AAC/B,WAAQ,KAAK,EAAE;;AAGhB,oBAAkB;;AAGnB,KAAI,gBAAgB,WAAW,GAAG;AACjC,MAAI,KAAK,uBAAuB;AAChC,QAAM,yBAAyB;AAC/B,UAAQ,KAAK,EAAE;;CAIhB,MAAM,UAAU,MAAM,YAAY,gBAAgB;CAElD,MAAM,aAAuB,EAAE;CAC/B,MAAM,SAAmB,EAAE;AAE3B,MAAK,MAAM,CAAC,QAAQ,WAAW,QAAQ,SAAS,CAC/C,KAAI,WAAW,UACd,YAAW,KAAK,OAAO;KAEvB,QAAO,KAAK,OAAO;AAKrB,KAAI,WAAW,SAAS,EACvB,OAAM,mBAAmB,WAAW;CAIrC,MAAM,mBAAmB,WAAW,OAAO,cAAc;CACzD,MAAM,aAAa,WAAW,QAAQ,MAAM,CAAC,cAAc,EAAE,CAAC;CAC9D,MAAM,yBAAyB,OAAO,OAAO,cAAc;CAC3D,MAAM,mBAAmB,OAAO,QAAQ,MAAM,CAAC,cAAc,EAAE,CAAC;AAEhE,KAAI,iBAAiB,SAAS,GAAG;EAChC,MAAM,iBAAiB,iBAAiB,KAAK,MAAM;AACnD,MAAI,KACH,8CAA8C,eAAe,KAC7D;;AAGF,KAAI,WAAW,SAAS,GAAG;EAC1B,MAAM,iBAAiB,WAAW,KAAK,MAAM;AAC7C,MAAI,KACH,4CAA4C,eAAe,KAC3D;;AAIF,KAAI,uBAAuB,SAAS,GAAG;AACtC,MAAI,KACH,+GACA;AACD,OAAK,MAAM,UAAU,uBACpB,KAAI,WAAW,UACd,KAAI,KACH,iGACA;WACS,WAAW,SACrB,KAAI,KACH,2EACA;;AAKJ,KAAI,iBAAiB,SAAS,GAAG;AAChC,MAAI,MACH,sCAAsC,iBAAiB,KAAK,MAAM,GAClE;AACD,MAAI,KACH,8FACA;;AAIF,KAAI,WAAW,WAAW,GAAG;AAC5B,QACC,iFACA;AACD,UAAQ,KAAK,EAAE;;AAGhB,KAAI,iBAAiB,SAAS,KAAK,WAAW,WAAW,EAGxD,MACC,kBAFsB,iBAAiB,KAAK,MAAM,CAEjB,yCAAyC,KAAK,KAAK,wBAAwB,CAAC,CAAC,8BAC9G,eACA;UACS,WAAW,SAAS,KAAK,iBAAiB,WAAW,EAG/D,MACC,kBAFsB,WAAW,KAAK,MAAM,CAEX,gBAAgB,KAAK,KAAK,wBAAwB,CAAC,CAAC,uBACrF,eACA;KAGD,MACC,cAAc,iBAAiB,KAAK,MAAM,CAAC,kDAAkD,KAAK,KAAK,wBAAwB,CAAC,CAAC,0CAA0C,WAAW,KAAK,MAAM,CAAC,yBAAyB,KAAK,KAAK,wBAAwB,CAAC,CAAC,uBAC/P,eACA;AAGF,OAAM,gDAAgD"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Editor } from "./types.js";
|
|
2
|
+
|
|
3
|
+
//#region src/lib/agents.d.ts
|
|
4
|
+
interface AgentConfig {
|
|
5
|
+
editor: Editor;
|
|
6
|
+
addMcpId: string;
|
|
7
|
+
hint: string;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* All agents that can be configured via neon-init.
|
|
11
|
+
* Aligns with add-mcp's supported agents table.
|
|
12
|
+
* https://github.com/neondatabase/add-mcp#supported-agents
|
|
13
|
+
*/
|
|
14
|
+
declare const ALL_CONFIGURABLE_AGENTS: AgentConfig[];
|
|
15
|
+
declare function getAddMcpAgentId(editor: Editor): string;
|
|
16
|
+
//#endregion
|
|
17
|
+
export { ALL_CONFIGURABLE_AGENTS, AgentConfig, getAddMcpAgentId };
|
|
18
|
+
//# sourceMappingURL=agents.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agents.d.ts","names":[],"sources":["../../src/lib/agents.ts"],"sourcesContent":[],"mappings":";;;UAEiB,WAAA;UACR;EADQ,QAAA,EAAA,MAAW;EAWf,IAAA,EAAA,MAAA;AAiCb;;;;;;cAjCa,yBAAyB;iBAiCtB,gBAAA,SAAyB"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
//#region src/lib/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
|
+
//#endregion
|
|
85
|
+
export { ALL_CONFIGURABLE_AGENTS, getAddMcpAgentId };
|
|
86
|
+
|
|
87
|
+
//# sourceMappingURL=agents.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agents.js","names":[],"sources":["../../src/lib/agents.ts"],"sourcesContent":["import type { Editor } from \"./types.js\";\n\nexport interface AgentConfig {\n\teditor: Editor;\n\taddMcpId: string;\n\thint: string;\n}\n\n/**\n * All agents that can be configured via neon-init.\n * Aligns with add-mcp's supported agents table.\n * https://github.com/neondatabase/add-mcp#supported-agents\n */\nexport const ALL_CONFIGURABLE_AGENTS: AgentConfig[] = [\n\t{\n\t\teditor: \"Cursor\",\n\t\taddMcpId: \"cursor\",\n\t\thint: \"Neon Local Connect extension\",\n\t},\n\t{\n\t\teditor: \"VS Code\",\n\t\taddMcpId: \"vscode\",\n\t\thint: \"Neon Local Connect extension\",\n\t},\n\t{ editor: \"Claude CLI\", addMcpId: \"claude-code\", hint: \"MCP Server\" },\n\t{\n\t\teditor: \"Claude Desktop\",\n\t\taddMcpId: \"claude-desktop\",\n\t\thint: \"MCP Server\",\n\t},\n\t{ editor: \"Codex\", addMcpId: \"codex\", hint: \"MCP Server\" },\n\t{ editor: \"OpenCode\", addMcpId: \"opencode\", hint: \"MCP Server\" },\n\t{ editor: \"Antigravity\", addMcpId: \"antigravity\", hint: \"MCP Server\" },\n\t{ editor: \"Cline\", addMcpId: \"cline\", hint: \"MCP Server\" },\n\t{ editor: \"Cline CLI\", addMcpId: \"cline-cli\", hint: \"MCP Server\" },\n\t{ editor: \"Gemini CLI\", addMcpId: \"gemini-cli\", hint: \"MCP Server\" },\n\t{\n\t\teditor: \"GitHub Copilot CLI\",\n\t\taddMcpId: \"github-copilot-cli\",\n\t\thint: \"MCP Server\",\n\t},\n\t{ editor: \"Goose\", addMcpId: \"goose\", hint: \"MCP Server\" },\n\t{ editor: \"MCPorter\", addMcpId: \"mcporter\", hint: \"MCP Server\" },\n\t{ editor: \"Zed\", addMcpId: \"zed\", hint: \"MCP Server\" },\n];\n\nexport function getAddMcpAgentId(editor: Editor): string {\n\tconst agent = ALL_CONFIGURABLE_AGENTS.find((a) => a.editor === editor);\n\tif (!agent) {\n\t\tthrow new Error(`No add-mcp agent ID found for editor: ${editor}`);\n\t}\n\treturn agent.addMcpId;\n}\n"],"mappings":";;;;;;AAaA,MAAa,0BAAyC;CACrD;EACC,QAAQ;EACR,UAAU;EACV,MAAM;EACN;CACD;EACC,QAAQ;EACR,UAAU;EACV,MAAM;EACN;CACD;EAAE,QAAQ;EAAc,UAAU;EAAe,MAAM;EAAc;CACrE;EACC,QAAQ;EACR,UAAU;EACV,MAAM;EACN;CACD;EAAE,QAAQ;EAAS,UAAU;EAAS,MAAM;EAAc;CAC1D;EAAE,QAAQ;EAAY,UAAU;EAAY,MAAM;EAAc;CAChE;EAAE,QAAQ;EAAe,UAAU;EAAe,MAAM;EAAc;CACtE;EAAE,QAAQ;EAAS,UAAU;EAAS,MAAM;EAAc;CAC1D;EAAE,QAAQ;EAAa,UAAU;EAAa,MAAM;EAAc;CAClE;EAAE,QAAQ;EAAc,UAAU;EAAc,MAAM;EAAc;CACpE;EACC,QAAQ;EACR,UAAU;EACV,MAAM;EACN;CACD;EAAE,QAAQ;EAAS,UAAU;EAAS,MAAM;EAAc;CAC1D;EAAE,QAAQ;EAAY,UAAU;EAAY,MAAM;EAAc;CAChE;EAAE,QAAQ;EAAO,UAAU;EAAO,MAAM;EAAc;CACtD;AAED,SAAgB,iBAAiB,QAAwB;CACxD,MAAM,QAAQ,wBAAwB,MAAM,MAAM,EAAE,WAAW,OAAO;AACtE,KAAI,CAAC,MACJ,OAAM,IAAI,MAAM,yCAAyC,SAAS;AAEnE,QAAO,MAAM"}
|
package/dist/lib/auth.js
CHANGED
|
@@ -2,7 +2,6 @@ import { log } from "@clack/prompts";
|
|
|
2
2
|
import { existsSync, readFileSync } from "node:fs";
|
|
3
3
|
import { resolve } from "node:path";
|
|
4
4
|
import { execa } from "execa";
|
|
5
|
-
|
|
6
5
|
//#region src/lib/auth.ts
|
|
7
6
|
/**
|
|
8
7
|
* Ensures neonctl is authenticated by running a command that triggers auth if needed
|
|
@@ -75,7 +74,7 @@ async function createApiKeyFromNeonctl() {
|
|
|
75
74
|
return null;
|
|
76
75
|
}
|
|
77
76
|
}
|
|
78
|
-
|
|
79
77
|
//#endregion
|
|
80
78
|
export { createApiKeyFromNeonctl, ensureNeonctlAuth };
|
|
79
|
+
|
|
81
80
|
//# sourceMappingURL=auth.js.map
|
package/dist/lib/auth.js.map
CHANGED
|
@@ -1 +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\t// If already authenticated (e.g. ran in a terminal before), we can proceed\n\tconst existingToken = await getNeonctlAccessToken();\n\tif (existingToken) return true;\n\n\ttry {\n\t\t// Use execa to authenticate with neonctl\n\t\tawait execa(\"npx\", [\"-y\", \"neonctl\", \"me\", \"--no-analytics\"], {\n\t\t\t// Shows OAuth URL and prompts to the user\n\t\t\tstdio: \"inherit\",\n\t\t\t// Unset CI so neonctl doesn't refuse to open the browser (e.g. when run from agent chat)\n\t\t\tenv: { ...process.env, CI: undefined },\n\t\t});\n\t\treturn true;\n\t} catch (error) {\n\t\tconst msg = error instanceof Error ? error.message : \"Unknown error\";\n\t\tif (msg.includes(\"interactive auth\") || msg.includes(\"CI\")) {\n\t\t\tlog.error(\n\t\t\t\t\"Auth requires an interactive terminal. Run neon-init in your system terminal (outside the chat) to sign in.\",\n\t\t\t);\n\t\t} else {\n\t\t\tlog.error(`Authentication failed: ${msg}`);\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":"
|
|
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\t// If already authenticated (e.g. ran in a terminal before), we can proceed\n\tconst existingToken = await getNeonctlAccessToken();\n\tif (existingToken) return true;\n\n\ttry {\n\t\t// Use execa to authenticate with neonctl\n\t\tawait execa(\"npx\", [\"-y\", \"neonctl\", \"me\", \"--no-analytics\"], {\n\t\t\t// Shows OAuth URL and prompts to the user\n\t\t\tstdio: \"inherit\",\n\t\t\t// Unset CI so neonctl doesn't refuse to open the browser (e.g. when run from agent chat)\n\t\t\tenv: { ...process.env, CI: undefined },\n\t\t});\n\t\treturn true;\n\t} catch (error) {\n\t\tconst msg = error instanceof Error ? error.message : \"Unknown error\";\n\t\tif (msg.includes(\"interactive auth\") || msg.includes(\"CI\")) {\n\t\t\tlog.error(\n\t\t\t\t\"Auth requires an interactive terminal. Run neon-init in your system terminal (outside the chat) to sign in.\",\n\t\t\t);\n\t\t} else {\n\t\t\tlog.error(`Authentication failed: ${msg}`);\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;AAG3D,KADsB,MAAM,uBAAuB,CAChC,QAAO;AAE1B,KAAI;AAEH,QAAM,MAAM,OAAO;GAAC;GAAM;GAAW;GAAM;GAAiB,EAAE;GAE7D,OAAO;GAEP,KAAK;IAAE,GAAG,QAAQ;IAAK,IAAI,KAAA;IAAW;GACtC,CAAC;AACF,SAAO;UACC,OAAO;EACf,MAAM,MAAM,iBAAiB,QAAQ,MAAM,UAAU;AACrD,MAAI,IAAI,SAAS,mBAAmB,IAAI,IAAI,SAAS,KAAK,CACzD,KAAI,MACH,8GACA;MAED,KAAI,MAAM,0BAA0B,MAAM;AAE3C,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"}
|
package/dist/lib/editors.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { existsSync } from "node:fs";
|
|
2
2
|
import { resolve } from "node:path";
|
|
3
3
|
import { execa } from "execa";
|
|
4
|
-
|
|
5
4
|
//#region src/lib/editors.ts
|
|
6
5
|
/**
|
|
7
6
|
* Gets VS Code's global config directory based on the platform
|
|
@@ -41,7 +40,7 @@ async function detectAvailableEditors(homeDir) {
|
|
|
41
40
|
if (await isClaudeCLIInstalled()) editors.push("Claude CLI");
|
|
42
41
|
return editors;
|
|
43
42
|
}
|
|
44
|
-
|
|
45
43
|
//#endregion
|
|
46
44
|
export { detectAvailableEditors, getVSCodeGlobalConfigDir };
|
|
45
|
+
|
|
47
46
|
//# sourceMappingURL=editors.js.map
|
package/dist/lib/editors.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"editors.js","names":[],"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":"
|
|
1
|
+
{"version":3,"file":"editors.js","names":[],"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,MAAM,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"}
|
package/dist/lib/extension.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { existsSync } from "node:fs";
|
|
2
2
|
import { execa } from "execa";
|
|
3
|
-
|
|
4
3
|
//#region src/lib/extension.ts
|
|
5
4
|
const NEON_EXTENSION_ID = "databricks.neon-local-connect";
|
|
6
5
|
/**
|
|
@@ -176,7 +175,7 @@ async function configureExtension(editor, apiKey) {
|
|
|
176
175
|
function usesExtension(editor) {
|
|
177
176
|
return editor === "VS Code" || editor === "Cursor";
|
|
178
177
|
}
|
|
179
|
-
|
|
180
178
|
//#endregion
|
|
181
179
|
export { configureExtension, findEditorCommand, installExtension, usesExtension, waitForExtensionInstalled };
|
|
180
|
+
|
|
182
181
|
//# sourceMappingURL=extension.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"extension.js","names":[],"sources":["../../src/lib/extension.ts"],"sourcesContent":["import { existsSync } from \"node:fs\";\nimport { execa } from \"execa\";\nimport type { Editor } from \"./types.js\";\n\nconst NEON_EXTENSION_ID = \"databricks.neon-local-connect\";\n\n/**\n * Uses macOS mdfind to locate an app by bundle identifier\n */\nasync function findAppWithMdfind(bundleId: string): Promise<string | null> {\n\ttry {\n\t\tconst result = await execa(\n\t\t\t\"mdfind\",\n\t\t\t[`kMDItemCFBundleIdentifier == '${bundleId}'`],\n\t\t\t{ timeout: 5000 },\n\t\t);\n\t\tconst paths = result.stdout.trim().split(\"\\n\").filter(Boolean);\n\t\treturn paths[0] || null;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\n/**\n * Known installation paths for VS Code CLI\n */\nfunction getVSCodePaths(): string[] {\n\tconst platform = process.platform;\n\tconst home = process.env.HOME || \"\";\n\n\tif (platform === \"darwin\") {\n\t\treturn [\n\t\t\t\"/Applications/Visual Studio Code.app/Contents/Resources/app/bin/code\",\n\t\t\t\"/Applications/Visual Studio Code - Insiders.app/Contents/Resources/app/bin/code-insiders\",\n\t\t\t`${home}/Applications/Visual Studio Code.app/Contents/Resources/app/bin/code`,\n\t\t\t`${home}/Downloads/Visual Studio Code.app/Contents/Resources/app/bin/code`,\n\t\t];\n\t}\n\n\tif (platform === \"linux\") {\n\t\treturn [\n\t\t\t\"/usr/share/code/bin/code\",\n\t\t\t\"/usr/bin/code\",\n\t\t\t\"/snap/bin/code\",\n\t\t\t\"/usr/share/code-insiders/bin/code-insiders\",\n\t\t];\n\t}\n\n\tif (platform === \"win32\") {\n\t\tconst localAppData = process.env.LOCALAPPDATA || \"\";\n\t\tconst programFiles = process.env.PROGRAMFILES || \"C:\\\\Program Files\";\n\t\treturn [\n\t\t\t`${localAppData}\\\\Programs\\\\Microsoft VS Code\\\\bin\\\\code.cmd`,\n\t\t\t`${programFiles}\\\\Microsoft VS Code\\\\bin\\\\code.cmd`,\n\t\t\t`${localAppData}\\\\Programs\\\\Microsoft VS Code Insiders\\\\bin\\\\code-insiders.cmd`,\n\t\t];\n\t}\n\n\treturn [];\n}\n\n/**\n * Known installation paths for Cursor CLI\n */\nfunction getCursorPaths(): string[] {\n\tconst platform = process.platform;\n\tconst home = process.env.HOME || \"\";\n\n\tif (platform === \"darwin\") {\n\t\treturn [\n\t\t\t\"/Applications/Cursor.app/Contents/Resources/app/bin/cursor\",\n\t\t\t`${home}/Applications/Cursor.app/Contents/Resources/app/bin/cursor`,\n\t\t\t`${home}/Downloads/Cursor.app/Contents/Resources/app/bin/cursor`,\n\t\t];\n\t}\n\n\tif (platform === \"linux\") {\n\t\treturn [\n\t\t\t\"/usr/share/cursor/bin/cursor\",\n\t\t\t\"/usr/bin/cursor\",\n\t\t\t`${home}/.local/bin/cursor`,\n\t\t\t\"/opt/cursor/bin/cursor\",\n\t\t];\n\t}\n\n\tif (platform === \"win32\") {\n\t\tconst localAppData = process.env.LOCALAPPDATA || \"\";\n\t\tconst programFiles = process.env.PROGRAMFILES || \"C:\\\\Program Files\";\n\t\treturn [\n\t\t\t`${localAppData}\\\\Programs\\\\Cursor\\\\resources\\\\app\\\\bin\\\\cursor.cmd`,\n\t\t\t`${localAppData}\\\\cursor\\\\Cursor.exe`,\n\t\t\t`${programFiles}\\\\Cursor\\\\resources\\\\app\\\\bin\\\\cursor.cmd`,\n\t\t];\n\t}\n\n\treturn [];\n}\n\n/**\n * Finds the CLI command for an editor by checking known installation paths\n * On macOS, also uses mdfind to locate the app if standard paths fail\n * Falls back to the simple command name if no full path is found (in case it's in PATH)\n */\nexport async function findEditorCommand(\n\teditor: Editor,\n): Promise<string | null> {\n\tlet paths: string[];\n\tlet fallbackCommand: string;\n\tlet bundleId: string | null = null;\n\n\tif (editor === \"VS Code\") {\n\t\tpaths = getVSCodePaths();\n\t\tfallbackCommand = \"code\";\n\t\tbundleId = \"com.microsoft.VSCode\";\n\t} else if (editor === \"Cursor\") {\n\t\tpaths = getCursorPaths();\n\t\tfallbackCommand = \"cursor\";\n\t\tbundleId = \"com.todesktop.230313mzl4w4u92\";\n\t} else {\n\t\treturn null;\n\t}\n\n\tfor (const path of paths) {\n\t\tif (existsSync(path)) {\n\t\t\treturn path;\n\t\t}\n\t}\n\n\t// On macOS, try mdfind to locate the app dynamically\n\tif (process.platform === \"darwin\" && bundleId) {\n\t\tconst appPath = await findAppWithMdfind(bundleId);\n\t\tif (appPath) {\n\t\t\tconst cliPath = `${appPath}/Contents/Resources/app/bin/${fallbackCommand}`;\n\t\t\tif (existsSync(cliPath)) {\n\t\t\t\treturn cliPath;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn fallbackCommand;\n}\n\n/**\n * Gets the URI scheme for an editor\n */\nfunction getEditorUriScheme(editor: Editor): string | null {\n\tif (editor === \"VS Code\") {\n\t\treturn \"vscode\";\n\t}\n\tif (editor === \"Cursor\") {\n\t\treturn \"cursor\";\n\t}\n\treturn null;\n}\n\n/**\n * Checks if the extension is installed by querying the editor's extension list\n */\nasync function isExtensionInList(editor: Editor): Promise<boolean> {\n\tconst command = await findEditorCommand(editor);\n\tif (!command) {\n\t\treturn false;\n\t}\n\n\ttry {\n\t\tconst result = await execa(command, [\"--list-extensions\"], {\n\t\t\ttimeout: 5000,\n\t\t});\n\t\treturn result.stdout.includes(NEON_EXTENSION_ID);\n\t} catch {\n\t\treturn false;\n\t}\n}\n\n/**\n * Waits for the extension to appear in the installed extensions list\n * This ensures the extension is fully installed and activated before we try to configure it\n */\nexport async function waitForExtensionInstalled(\n\teditor: Editor,\n\tmaxAttempts = 10,\n\tdelayMs = 1000,\n): Promise<boolean> {\n\tfor (let attempt = 0; attempt < maxAttempts; attempt++) {\n\t\tconst isInstalled = await isExtensionInList(editor);\n\n\t\tif (isInstalled) {\n\t\t\t// Give the extension a moment to fully activate and register URI handlers\n\t\t\tawait new Promise((resolve) => setTimeout(resolve, 1000));\n\t\t\treturn true;\n\t\t}\n\n\t\t// Wait before checking again (unless this is the last attempt)\n\t\tif (attempt < maxAttempts - 1) {\n\t\t\tawait new Promise((resolve) => setTimeout(resolve, delayMs));\n\t\t}\n\t}\n\n\treturn false;\n}\n\n/**\n * Installs the Neon Local Connect extension for VS Code or Cursor\n * Returns success only if installation succeeds, fails silently otherwise\n */\nexport async function installExtension(editor: Editor): Promise<boolean> {\n\tconst command = await findEditorCommand(editor);\n\tif (!command) {\n\t\treturn false;\n\t}\n\n\ttry {\n\t\tawait execa(command, [\"--install-extension\", NEON_EXTENSION_ID]);\n\t\treturn true;\n\t} catch {\n\t\treturn false;\n\t}\n}\n\n/**\n * Configures the Neon Local Connect extension with the API key\n * Uses the extension's URI handler to trigger the import-api-key command\n */\nexport async function configureExtension(\n\teditor: Editor,\n\tapiKey: string,\n): Promise<boolean> {\n\tconst scheme = getEditorUriScheme(editor);\n\tif (!scheme) {\n\t\treturn false;\n\t}\n\n\t// Build the URI to trigger the extension's import-api-key handler\n\t// Format: vscode://databricks.neon-local-connect/import-api-key?token=xxx\n\tconst encodedApiKey = encodeURIComponent(apiKey);\n\tconst uri = `${scheme}://${NEON_EXTENSION_ID}/import-api-key?token=${encodedApiKey}`;\n\n\ttry {\n\t\tconst platform = process.platform;\n\n\t\tif (platform === \"darwin\") {\n\t\t\t// macOS: use 'open' command\n\t\t\tawait execa(\"open\", [uri], { timeout: 10000 });\n\t\t} else if (platform === \"linux\") {\n\t\t\t// Linux: use 'xdg-open' command\n\t\t\tawait execa(\"xdg-open\", [uri], { timeout: 10000 });\n\t\t} else if (platform === \"win32\") {\n\t\t\t// Windows: use 'start' command\n\t\t\tawait execa(\"cmd\", [\"/c\", \"start\", \"\", uri], { timeout: 10000 });\n\t\t} else {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn true;\n\t} catch {\n\t\treturn false;\n\t}\n}\n\n/**\n * Returns the editor types that should use extension installation (vs MCP)\n */\nexport function usesExtension(editor: Editor): boolean {\n\treturn editor === \"VS Code\" || editor === \"Cursor\";\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"extension.js","names":[],"sources":["../../src/lib/extension.ts"],"sourcesContent":["import { existsSync } from \"node:fs\";\nimport { execa } from \"execa\";\nimport type { Editor } from \"./types.js\";\n\nconst NEON_EXTENSION_ID = \"databricks.neon-local-connect\";\n\n/**\n * Uses macOS mdfind to locate an app by bundle identifier\n */\nasync function findAppWithMdfind(bundleId: string): Promise<string | null> {\n\ttry {\n\t\tconst result = await execa(\n\t\t\t\"mdfind\",\n\t\t\t[`kMDItemCFBundleIdentifier == '${bundleId}'`],\n\t\t\t{ timeout: 5000 },\n\t\t);\n\t\tconst paths = result.stdout.trim().split(\"\\n\").filter(Boolean);\n\t\treturn paths[0] || null;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\n/**\n * Known installation paths for VS Code CLI\n */\nfunction getVSCodePaths(): string[] {\n\tconst platform = process.platform;\n\tconst home = process.env.HOME || \"\";\n\n\tif (platform === \"darwin\") {\n\t\treturn [\n\t\t\t\"/Applications/Visual Studio Code.app/Contents/Resources/app/bin/code\",\n\t\t\t\"/Applications/Visual Studio Code - Insiders.app/Contents/Resources/app/bin/code-insiders\",\n\t\t\t`${home}/Applications/Visual Studio Code.app/Contents/Resources/app/bin/code`,\n\t\t\t`${home}/Downloads/Visual Studio Code.app/Contents/Resources/app/bin/code`,\n\t\t];\n\t}\n\n\tif (platform === \"linux\") {\n\t\treturn [\n\t\t\t\"/usr/share/code/bin/code\",\n\t\t\t\"/usr/bin/code\",\n\t\t\t\"/snap/bin/code\",\n\t\t\t\"/usr/share/code-insiders/bin/code-insiders\",\n\t\t];\n\t}\n\n\tif (platform === \"win32\") {\n\t\tconst localAppData = process.env.LOCALAPPDATA || \"\";\n\t\tconst programFiles = process.env.PROGRAMFILES || \"C:\\\\Program Files\";\n\t\treturn [\n\t\t\t`${localAppData}\\\\Programs\\\\Microsoft VS Code\\\\bin\\\\code.cmd`,\n\t\t\t`${programFiles}\\\\Microsoft VS Code\\\\bin\\\\code.cmd`,\n\t\t\t`${localAppData}\\\\Programs\\\\Microsoft VS Code Insiders\\\\bin\\\\code-insiders.cmd`,\n\t\t];\n\t}\n\n\treturn [];\n}\n\n/**\n * Known installation paths for Cursor CLI\n */\nfunction getCursorPaths(): string[] {\n\tconst platform = process.platform;\n\tconst home = process.env.HOME || \"\";\n\n\tif (platform === \"darwin\") {\n\t\treturn [\n\t\t\t\"/Applications/Cursor.app/Contents/Resources/app/bin/cursor\",\n\t\t\t`${home}/Applications/Cursor.app/Contents/Resources/app/bin/cursor`,\n\t\t\t`${home}/Downloads/Cursor.app/Contents/Resources/app/bin/cursor`,\n\t\t];\n\t}\n\n\tif (platform === \"linux\") {\n\t\treturn [\n\t\t\t\"/usr/share/cursor/bin/cursor\",\n\t\t\t\"/usr/bin/cursor\",\n\t\t\t`${home}/.local/bin/cursor`,\n\t\t\t\"/opt/cursor/bin/cursor\",\n\t\t];\n\t}\n\n\tif (platform === \"win32\") {\n\t\tconst localAppData = process.env.LOCALAPPDATA || \"\";\n\t\tconst programFiles = process.env.PROGRAMFILES || \"C:\\\\Program Files\";\n\t\treturn [\n\t\t\t`${localAppData}\\\\Programs\\\\Cursor\\\\resources\\\\app\\\\bin\\\\cursor.cmd`,\n\t\t\t`${localAppData}\\\\cursor\\\\Cursor.exe`,\n\t\t\t`${programFiles}\\\\Cursor\\\\resources\\\\app\\\\bin\\\\cursor.cmd`,\n\t\t];\n\t}\n\n\treturn [];\n}\n\n/**\n * Finds the CLI command for an editor by checking known installation paths\n * On macOS, also uses mdfind to locate the app if standard paths fail\n * Falls back to the simple command name if no full path is found (in case it's in PATH)\n */\nexport async function findEditorCommand(\n\teditor: Editor,\n): Promise<string | null> {\n\tlet paths: string[];\n\tlet fallbackCommand: string;\n\tlet bundleId: string | null = null;\n\n\tif (editor === \"VS Code\") {\n\t\tpaths = getVSCodePaths();\n\t\tfallbackCommand = \"code\";\n\t\tbundleId = \"com.microsoft.VSCode\";\n\t} else if (editor === \"Cursor\") {\n\t\tpaths = getCursorPaths();\n\t\tfallbackCommand = \"cursor\";\n\t\tbundleId = \"com.todesktop.230313mzl4w4u92\";\n\t} else {\n\t\treturn null;\n\t}\n\n\tfor (const path of paths) {\n\t\tif (existsSync(path)) {\n\t\t\treturn path;\n\t\t}\n\t}\n\n\t// On macOS, try mdfind to locate the app dynamically\n\tif (process.platform === \"darwin\" && bundleId) {\n\t\tconst appPath = await findAppWithMdfind(bundleId);\n\t\tif (appPath) {\n\t\t\tconst cliPath = `${appPath}/Contents/Resources/app/bin/${fallbackCommand}`;\n\t\t\tif (existsSync(cliPath)) {\n\t\t\t\treturn cliPath;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn fallbackCommand;\n}\n\n/**\n * Gets the URI scheme for an editor\n */\nfunction getEditorUriScheme(editor: Editor): string | null {\n\tif (editor === \"VS Code\") {\n\t\treturn \"vscode\";\n\t}\n\tif (editor === \"Cursor\") {\n\t\treturn \"cursor\";\n\t}\n\treturn null;\n}\n\n/**\n * Checks if the extension is installed by querying the editor's extension list\n */\nasync function isExtensionInList(editor: Editor): Promise<boolean> {\n\tconst command = await findEditorCommand(editor);\n\tif (!command) {\n\t\treturn false;\n\t}\n\n\ttry {\n\t\tconst result = await execa(command, [\"--list-extensions\"], {\n\t\t\ttimeout: 5000,\n\t\t});\n\t\treturn result.stdout.includes(NEON_EXTENSION_ID);\n\t} catch {\n\t\treturn false;\n\t}\n}\n\n/**\n * Waits for the extension to appear in the installed extensions list\n * This ensures the extension is fully installed and activated before we try to configure it\n */\nexport async function waitForExtensionInstalled(\n\teditor: Editor,\n\tmaxAttempts = 10,\n\tdelayMs = 1000,\n): Promise<boolean> {\n\tfor (let attempt = 0; attempt < maxAttempts; attempt++) {\n\t\tconst isInstalled = await isExtensionInList(editor);\n\n\t\tif (isInstalled) {\n\t\t\t// Give the extension a moment to fully activate and register URI handlers\n\t\t\tawait new Promise((resolve) => setTimeout(resolve, 1000));\n\t\t\treturn true;\n\t\t}\n\n\t\t// Wait before checking again (unless this is the last attempt)\n\t\tif (attempt < maxAttempts - 1) {\n\t\t\tawait new Promise((resolve) => setTimeout(resolve, delayMs));\n\t\t}\n\t}\n\n\treturn false;\n}\n\n/**\n * Installs the Neon Local Connect extension for VS Code or Cursor\n * Returns success only if installation succeeds, fails silently otherwise\n */\nexport async function installExtension(editor: Editor): Promise<boolean> {\n\tconst command = await findEditorCommand(editor);\n\tif (!command) {\n\t\treturn false;\n\t}\n\n\ttry {\n\t\tawait execa(command, [\"--install-extension\", NEON_EXTENSION_ID]);\n\t\treturn true;\n\t} catch {\n\t\treturn false;\n\t}\n}\n\n/**\n * Configures the Neon Local Connect extension with the API key\n * Uses the extension's URI handler to trigger the import-api-key command\n */\nexport async function configureExtension(\n\teditor: Editor,\n\tapiKey: string,\n): Promise<boolean> {\n\tconst scheme = getEditorUriScheme(editor);\n\tif (!scheme) {\n\t\treturn false;\n\t}\n\n\t// Build the URI to trigger the extension's import-api-key handler\n\t// Format: vscode://databricks.neon-local-connect/import-api-key?token=xxx\n\tconst encodedApiKey = encodeURIComponent(apiKey);\n\tconst uri = `${scheme}://${NEON_EXTENSION_ID}/import-api-key?token=${encodedApiKey}`;\n\n\ttry {\n\t\tconst platform = process.platform;\n\n\t\tif (platform === \"darwin\") {\n\t\t\t// macOS: use 'open' command\n\t\t\tawait execa(\"open\", [uri], { timeout: 10000 });\n\t\t} else if (platform === \"linux\") {\n\t\t\t// Linux: use 'xdg-open' command\n\t\t\tawait execa(\"xdg-open\", [uri], { timeout: 10000 });\n\t\t} else if (platform === \"win32\") {\n\t\t\t// Windows: use 'start' command\n\t\t\tawait execa(\"cmd\", [\"/c\", \"start\", \"\", uri], { timeout: 10000 });\n\t\t} else {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn true;\n\t} catch {\n\t\treturn false;\n\t}\n}\n\n/**\n * Returns the editor types that should use extension installation (vs MCP)\n */\nexport function usesExtension(editor: Editor): boolean {\n\treturn editor === \"VS Code\" || editor === \"Cursor\";\n}\n"],"mappings":"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"}
|
package/dist/lib/install.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ import { Editor, InstallStatus } from "./types.js";
|
|
|
5
5
|
/**
|
|
6
6
|
* Installs Neon's Local Connect extension or MCP Server for specific editors
|
|
7
7
|
*/
|
|
8
|
-
declare function installNeon(
|
|
8
|
+
declare function installNeon(selectedEditors: Editor[]): Promise<Map<Editor, InstallStatus>>;
|
|
9
9
|
//#endregion
|
|
10
10
|
export { installNeon };
|
|
11
11
|
//# sourceMappingURL=install.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"install.d.ts","names":[],"sources":["../../src/lib/install.ts"],"sourcesContent":[],"mappings":";;;;;;
|
|
1
|
+
{"version":3,"file":"install.d.ts","names":[],"sources":["../../src/lib/install.ts"],"sourcesContent":[],"mappings":";;;;;;AAiDA;AAAiC,iBAAX,WAAA,CAAW,eAAA,EACf,MADe,EAAA,CAAA,EAE9B,OAF8B,CAEtB,GAFsB,CAElB,MAFkB,EAEV,aAFU,CAAA,CAAA"}
|
package/dist/lib/install.js
CHANGED
|
@@ -1,70 +1,46 @@
|
|
|
1
|
+
import { getAddMcpAgentId } from "./agents.js";
|
|
1
2
|
import { configureExtension, installExtension, usesExtension, waitForExtensionInstalled } from "./extension.js";
|
|
2
3
|
import { createApiKeyFromNeonctl, ensureNeonctlAuth } from "./auth.js";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
|
|
4
|
+
import { log, spinner } from "@clack/prompts";
|
|
5
|
+
import { execa } from "execa";
|
|
6
6
|
//#region src/lib/install.ts
|
|
7
|
+
const NEON_MCP_SERVER_URL = "https://mcp.neon.tech/mcp";
|
|
7
8
|
/**
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*/
|
|
11
|
-
async function shouldConfigureMCP(homeDir, workspaceDir, editor) {
|
|
12
|
-
const { config } = getMCPConfig(homeDir, workspaceDir, editor);
|
|
13
|
-
const serverKey = editor === "VS Code" ? config.servers : config.mcpServers;
|
|
14
|
-
if (Boolean(serverKey?.Neon)) {
|
|
15
|
-
const response = await confirm({
|
|
16
|
-
message: `Neon MCP Server is already configured for ${editor}. Would you like to reconfigure it? (Y/n)`,
|
|
17
|
-
initialValue: true
|
|
18
|
-
});
|
|
19
|
-
if (isCancel(response)) return false;
|
|
20
|
-
if (!response) {
|
|
21
|
-
log.info(`Keeping existing MCP server configuration for ${editor}.`);
|
|
22
|
-
return false;
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
return true;
|
|
26
|
-
}
|
|
27
|
-
/**
|
|
28
|
-
* Installs Neon's MCP Server for specific editors
|
|
9
|
+
* Installs Neon MCP Server for a single editor via the add-mcp CLI.
|
|
10
|
+
* Uses API key authentication via the Authorization header.
|
|
29
11
|
*/
|
|
30
|
-
async function
|
|
31
|
-
const
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
12
|
+
async function installMCPServerViaAddMcp(editor, apiKey) {
|
|
13
|
+
const agentId = getAddMcpAgentId(editor);
|
|
14
|
+
await execa("npx", [
|
|
15
|
+
"-y",
|
|
16
|
+
"add-mcp",
|
|
17
|
+
NEON_MCP_SERVER_URL,
|
|
18
|
+
"--header",
|
|
19
|
+
`Authorization: Bearer ${apiKey}`,
|
|
20
|
+
"-g",
|
|
21
|
+
"-n",
|
|
22
|
+
"Neon",
|
|
23
|
+
"-y",
|
|
24
|
+
"-a",
|
|
25
|
+
agentId
|
|
26
|
+
], {
|
|
27
|
+
stdio: "pipe",
|
|
28
|
+
timeout: 6e4
|
|
29
|
+
});
|
|
46
30
|
}
|
|
47
31
|
/**
|
|
48
32
|
* Installs Neon's Local Connect extension or MCP Server for specific editors
|
|
49
33
|
*/
|
|
50
|
-
async function installNeon(
|
|
34
|
+
async function installNeon(selectedEditors) {
|
|
51
35
|
const results = /* @__PURE__ */ new Map();
|
|
52
36
|
const extensionEditors = selectedEditors.filter(usesExtension);
|
|
53
37
|
const mcpEditors = selectedEditors.filter((e) => !usesExtension(e));
|
|
54
|
-
|
|
55
|
-
for (const editor of mcpEditors) {
|
|
56
|
-
const needsConfig = await shouldConfigureMCP(homeDir, workspaceDir, editor);
|
|
57
|
-
mcpEditorsToConfigureMap.set(editor, needsConfig);
|
|
58
|
-
if (!needsConfig) results.set(editor, "success");
|
|
59
|
-
}
|
|
60
|
-
const mcpToConfigure = mcpEditors.filter((editor) => mcpEditorsToConfigureMap.get(editor) === true);
|
|
61
|
-
const extensionsToConfigure = extensionEditors;
|
|
62
|
-
if (extensionsToConfigure.length === 0 && mcpToConfigure.length === 0) return results;
|
|
38
|
+
if (extensionEditors.length === 0 && mcpEditors.length === 0) return results;
|
|
63
39
|
const authSpinner = spinner();
|
|
64
40
|
authSpinner.start("Authenticating...");
|
|
65
41
|
if (!await ensureNeonctlAuth()) {
|
|
66
42
|
authSpinner.stop("Authentication failed");
|
|
67
|
-
for (const editor of
|
|
43
|
+
for (const editor of selectedEditors) results.set(editor, "failed");
|
|
68
44
|
return results;
|
|
69
45
|
}
|
|
70
46
|
authSpinner.stop("Authentication successful ✓");
|
|
@@ -72,10 +48,10 @@ async function installNeon(homeDir, workspaceDir, selectedEditors) {
|
|
|
72
48
|
if (!apiKey) {
|
|
73
49
|
log.error("Could not create API key after authentication.");
|
|
74
50
|
log.info("You can manually create one at: https://console.neon.tech/app/settings/api-keys");
|
|
75
|
-
for (const editor of
|
|
51
|
+
for (const editor of selectedEditors) results.set(editor, "failed");
|
|
76
52
|
return results;
|
|
77
53
|
}
|
|
78
|
-
for (const editor of
|
|
54
|
+
for (const editor of extensionEditors) {
|
|
79
55
|
if (!await installExtension(editor)) {
|
|
80
56
|
results.set(editor, "failed");
|
|
81
57
|
continue;
|
|
@@ -87,13 +63,23 @@ async function installNeon(homeDir, workspaceDir, selectedEditors) {
|
|
|
87
63
|
if (await configureExtension(editor, apiKey)) results.set(editor, "success");
|
|
88
64
|
else results.set(editor, "success");
|
|
89
65
|
}
|
|
90
|
-
|
|
91
|
-
const
|
|
92
|
-
|
|
66
|
+
if (mcpEditors.length > 0) {
|
|
67
|
+
const mcpSpinner = spinner();
|
|
68
|
+
mcpSpinner.start("Installing and configuring Neon MCP Server...");
|
|
69
|
+
let mcpSuccessCount = 0;
|
|
70
|
+
for (const editor of mcpEditors) try {
|
|
71
|
+
await installMCPServerViaAddMcp(editor, apiKey);
|
|
72
|
+
results.set(editor, "success");
|
|
73
|
+
mcpSuccessCount++;
|
|
74
|
+
} catch (err) {
|
|
75
|
+
results.set(editor, "failed");
|
|
76
|
+
if (err && typeof err === "object" && "stderr" in err && err.stderr) log.error(String(err.stderr).trim() || "failed to install MCP server via add-mcp");
|
|
77
|
+
}
|
|
78
|
+
mcpSpinner.stop(mcpSuccessCount > 0 ? "Neon MCP Server configuration complete ✓" : "Failed to configure Neon MCP Server");
|
|
93
79
|
}
|
|
94
80
|
return results;
|
|
95
81
|
}
|
|
96
|
-
|
|
97
82
|
//#endregion
|
|
98
83
|
export { installNeon };
|
|
84
|
+
|
|
99
85
|
//# sourceMappingURL=install.js.map
|
package/dist/lib/install.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"install.js","names":[],"sources":["../../src/lib/install.ts"],"sourcesContent":["import {
|
|
1
|
+
{"version":3,"file":"install.js","names":[],"sources":["../../src/lib/install.ts"],"sourcesContent":["import { log, spinner } from \"@clack/prompts\";\nimport { execa } from \"execa\";\nimport { getAddMcpAgentId } from \"./agents.js\";\nimport { createApiKeyFromNeonctl, ensureNeonctlAuth } from \"./auth.js\";\nimport {\n\tconfigureExtension,\n\tinstallExtension,\n\tusesExtension,\n\twaitForExtensionInstalled,\n} from \"./extension.js\";\nimport type { Editor, InstallStatus } from \"./types.js\";\n\nconst NEON_MCP_SERVER_URL = \"https://mcp.neon.tech/mcp\";\n\n/**\n * Installs Neon MCP Server for a single editor via the add-mcp CLI.\n * Uses API key authentication via the Authorization header.\n */\nasync function installMCPServerViaAddMcp(\n\teditor: Editor,\n\tapiKey: string,\n): Promise<void> {\n\tconst agentId = getAddMcpAgentId(editor);\n\n\tawait execa(\n\t\t\"npx\",\n\t\t[\n\t\t\t\"-y\",\n\t\t\t\"add-mcp\",\n\t\t\tNEON_MCP_SERVER_URL,\n\t\t\t\"--header\",\n\t\t\t`Authorization: Bearer ${apiKey}`,\n\t\t\t\"-g\",\n\t\t\t\"-n\",\n\t\t\t\"Neon\",\n\t\t\t\"-y\",\n\t\t\t\"-a\",\n\t\t\tagentId,\n\t\t],\n\t\t{\n\t\t\tstdio: \"pipe\",\n\t\t\ttimeout: 60000,\n\t\t},\n\t);\n}\n\n/**\n * Installs Neon's Local Connect extension or MCP Server for specific editors\n */\nexport async function installNeon(\n\tselectedEditors: Editor[],\n): Promise<Map<Editor, InstallStatus>> {\n\tconst results = new Map<Editor, InstallStatus>();\n\n\tconst extensionEditors = selectedEditors.filter(usesExtension);\n\tconst mcpEditors = selectedEditors.filter((e) => !usesExtension(e));\n\n\tif (extensionEditors.length === 0 && mcpEditors.length === 0) {\n\t\treturn results;\n\t}\n\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\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\tfor (const editor of selectedEditors) {\n\t\t\tresults.set(editor, \"failed\");\n\t\t}\n\t\treturn results;\n\t}\n\n\tfor (const editor of extensionEditors) {\n\t\tconst installSuccess = await installExtension(editor);\n\n\t\tif (!installSuccess) {\n\t\t\tresults.set(editor, \"failed\");\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst isReady = await waitForExtensionInstalled(editor);\n\t\tif (!isReady) {\n\t\t\t// Extension install command succeeded but extension didn't appear in list\n\t\t\tresults.set(editor, \"failed\");\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Configure the extension with the API key\n\t\tconst configSuccess = await configureExtension(editor, apiKey);\n\n\t\tif (configSuccess) {\n\t\t\tresults.set(editor, \"success\");\n\t\t} else {\n\t\t\t// Extension installed but auth failed but user can manually configure later\n\t\t\tresults.set(editor, \"success\");\n\t\t}\n\t}\n\n\tif (mcpEditors.length > 0) {\n\t\tconst mcpSpinner = spinner();\n\t\tmcpSpinner.start(\"Installing and configuring Neon MCP Server...\");\n\n\t\tlet mcpSuccessCount = 0;\n\t\tfor (const editor of mcpEditors) {\n\t\t\ttry {\n\t\t\t\tawait installMCPServerViaAddMcp(editor, apiKey);\n\t\t\t\tresults.set(editor, \"success\");\n\t\t\t\tmcpSuccessCount++;\n\t\t\t} catch (err) {\n\t\t\t\tresults.set(editor, \"failed\");\n\t\t\t\tif (\n\t\t\t\t\terr &&\n\t\t\t\t\ttypeof err === \"object\" &&\n\t\t\t\t\t\"stderr\" in err &&\n\t\t\t\t\terr.stderr\n\t\t\t\t) {\n\t\t\t\t\tlog.error(\n\t\t\t\t\t\tString(err.stderr).trim() ||\n\t\t\t\t\t\t\t\"failed to install MCP server via add-mcp\",\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tmcpSpinner.stop(\n\t\t\tmcpSuccessCount > 0\n\t\t\t\t? \"Neon MCP Server configuration complete ✓\"\n\t\t\t\t: \"Failed to configure Neon MCP Server\",\n\t\t);\n\t}\n\n\treturn results;\n}\n"],"mappings":";;;;;;AAYA,MAAM,sBAAsB;;;;;AAM5B,eAAe,0BACd,QACA,QACgB;CAChB,MAAM,UAAU,iBAAiB,OAAO;AAExC,OAAM,MACL,OACA;EACC;EACA;EACA;EACA;EACA,yBAAyB;EACzB;EACA;EACA;EACA;EACA;EACA;EACA,EACD;EACC,OAAO;EACP,SAAS;EACT,CACD;;;;;AAMF,eAAsB,YACrB,iBACsC;CACtC,MAAM,0BAAU,IAAI,KAA4B;CAEhD,MAAM,mBAAmB,gBAAgB,OAAO,cAAc;CAC9D,MAAM,aAAa,gBAAgB,QAAQ,MAAM,CAAC,cAAc,EAAE,CAAC;AAEnE,KAAI,iBAAiB,WAAW,KAAK,WAAW,WAAW,EAC1D,QAAO;CAGR,MAAM,cAAc,SAAS;AAC7B,aAAY,MAAM,oBAAoB;AAItC,KAAI,CAFgB,MAAM,mBAAmB,EAE3B;AACjB,cAAY,KAAK,wBAAwB;AACzC,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;AACD,OAAK,MAAM,UAAU,gBACpB,SAAQ,IAAI,QAAQ,SAAS;AAE9B,SAAO;;AAGR,MAAK,MAAM,UAAU,kBAAkB;AAGtC,MAAI,CAFmB,MAAM,iBAAiB,OAAO,EAEhC;AACpB,WAAQ,IAAI,QAAQ,SAAS;AAC7B;;AAID,MAAI,CADY,MAAM,0BAA0B,OAAO,EACzC;AAEb,WAAQ,IAAI,QAAQ,SAAS;AAC7B;;AAMD,MAFsB,MAAM,mBAAmB,QAAQ,OAAO,CAG7D,SAAQ,IAAI,QAAQ,UAAU;MAG9B,SAAQ,IAAI,QAAQ,UAAU;;AAIhC,KAAI,WAAW,SAAS,GAAG;EAC1B,MAAM,aAAa,SAAS;AAC5B,aAAW,MAAM,gDAAgD;EAEjE,IAAI,kBAAkB;AACtB,OAAK,MAAM,UAAU,WACpB,KAAI;AACH,SAAM,0BAA0B,QAAQ,OAAO;AAC/C,WAAQ,IAAI,QAAQ,UAAU;AAC9B;WACQ,KAAK;AACb,WAAQ,IAAI,QAAQ,SAAS;AAC7B,OACC,OACA,OAAO,QAAQ,YACf,YAAY,OACZ,IAAI,OAEJ,KAAI,MACH,OAAO,IAAI,OAAO,CAAC,MAAM,IACxB,2CACD;;AAKJ,aAAW,KACV,kBAAkB,IACf,6CACA,sCACH;;AAGF,QAAO"}
|
package/dist/lib/skills.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { Editor } from "./types.js";
|
|
|
3
3
|
//#region src/lib/skills.d.ts
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
* Installs Neon agent skills using Vercel's skills CLI
|
|
6
|
+
* Installs Neon agent skills using Vercel's skills CLI.
|
|
7
7
|
*/
|
|
8
8
|
declare function installAgentSkills(selectedEditors: Editor[]): Promise<boolean>;
|
|
9
9
|
//#endregion
|
package/dist/lib/skills.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"skills.d.ts","names":[],"sources":["../../src/lib/skills.ts"],"sourcesContent":[],"mappings":";;;;;;
|
|
1
|
+
{"version":3,"file":"skills.d.ts","names":[],"sources":["../../src/lib/skills.ts"],"sourcesContent":[],"mappings":";;;;;;AAqCA;AAAwC,iBAAlB,kBAAA,CAAkB,eAAA,EACtB,MADsB,EAAA,CAAA,EAErC,OAFqC,CAAA,OAAA,CAAA"}
|
package/dist/lib/skills.js
CHANGED
|
@@ -1,33 +1,36 @@
|
|
|
1
1
|
import { log, spinner } from "@clack/prompts";
|
|
2
2
|
import { execa } from "execa";
|
|
3
|
-
|
|
4
3
|
//#region src/lib/skills.ts
|
|
5
4
|
/**
|
|
6
|
-
* Maps editor names to the corresponding agent names used by the skills CLI
|
|
5
|
+
* Maps editor names to the corresponding agent names used by the skills CLI.
|
|
7
6
|
*/
|
|
8
7
|
function getSkillsAgentName(editor) {
|
|
9
8
|
switch (editor) {
|
|
10
9
|
case "Cursor": return "cursor";
|
|
11
|
-
case "VS Code":
|
|
10
|
+
case "VS Code":
|
|
11
|
+
case "GitHub Copilot CLI": return "github-copilot";
|
|
12
12
|
case "Claude CLI": return "claude-code";
|
|
13
|
+
case "Codex": return "codex";
|
|
14
|
+
case "OpenCode": return "opencode";
|
|
15
|
+
case "Antigravity": return "antigravity";
|
|
16
|
+
case "Cline":
|
|
17
|
+
case "Cline CLI": return "cline";
|
|
18
|
+
case "Gemini CLI": return "gemini-cli";
|
|
19
|
+
case "Goose": return "goose";
|
|
13
20
|
default: return "";
|
|
14
21
|
}
|
|
15
22
|
}
|
|
16
23
|
/**
|
|
17
|
-
* Installs Neon agent skills using Vercel's skills CLI
|
|
24
|
+
* Installs Neon agent skills using Vercel's skills CLI.
|
|
18
25
|
*/
|
|
19
26
|
async function installAgentSkills(selectedEditors) {
|
|
20
|
-
|
|
27
|
+
const editorsWithSkills = selectedEditors.filter((e) => getSkillsAgentName(e) !== "");
|
|
28
|
+
if (editorsWithSkills.length === 0) return true;
|
|
21
29
|
const skillsSpinner = spinner();
|
|
22
|
-
skillsSpinner.start("Installing agent skills for Neon...");
|
|
30
|
+
skillsSpinner.start("Installing agent skills for Neon in this project...");
|
|
23
31
|
let anyFailed = false;
|
|
24
|
-
for (const editor of
|
|
32
|
+
for (const editor of editorsWithSkills) {
|
|
25
33
|
const agentName = getSkillsAgentName(editor);
|
|
26
|
-
if (agentName === "") {
|
|
27
|
-
log.error(`Unsupported editor: ${editor}`);
|
|
28
|
-
anyFailed = true;
|
|
29
|
-
continue;
|
|
30
|
-
}
|
|
31
34
|
try {
|
|
32
35
|
await execa("npx", [
|
|
33
36
|
"skills",
|
|
@@ -40,11 +43,7 @@ async function installAgentSkills(selectedEditors) {
|
|
|
40
43
|
"-y"
|
|
41
44
|
], {
|
|
42
45
|
stdio: "pipe",
|
|
43
|
-
timeout: 1e4
|
|
44
|
-
env: {
|
|
45
|
-
...process.env,
|
|
46
|
-
DISABLE_TELEMETRY: "1"
|
|
47
|
-
}
|
|
46
|
+
timeout: 1e4
|
|
48
47
|
});
|
|
49
48
|
} catch (error) {
|
|
50
49
|
log.error(`Failed to install agent skills for ${editor}: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
@@ -52,14 +51,14 @@ async function installAgentSkills(selectedEditors) {
|
|
|
52
51
|
}
|
|
53
52
|
}
|
|
54
53
|
if (anyFailed) {
|
|
55
|
-
skillsSpinner.stop("Agent skills installation completed with errors");
|
|
54
|
+
skillsSpinner.stop("Agent skills installation for this project completed with errors");
|
|
56
55
|
log.info("You can manually install skills by running: npx skills add neondatabase/agent-skills --skill neon-postgres");
|
|
57
56
|
return false;
|
|
58
57
|
}
|
|
59
|
-
skillsSpinner.stop("Agent skills installed ✓");
|
|
58
|
+
skillsSpinner.stop("Agent skills installed for this project ✓");
|
|
60
59
|
return true;
|
|
61
60
|
}
|
|
62
|
-
|
|
63
61
|
//#endregion
|
|
64
62
|
export { installAgentSkills };
|
|
63
|
+
|
|
65
64
|
//# sourceMappingURL=skills.js.map
|
package/dist/lib/skills.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"skills.js","names":[],"sources":["../../src/lib/skills.ts"],"sourcesContent":["import { log, spinner } from \"@clack/prompts\";\nimport { execa } from \"execa\";\nimport type { Editor } from \"./types.js\";\n\n/**\n * Maps editor names to the corresponding agent names used by the skills CLI
|
|
1
|
+
{"version":3,"file":"skills.js","names":[],"sources":["../../src/lib/skills.ts"],"sourcesContent":["import { log, spinner } from \"@clack/prompts\";\nimport { execa } from \"execa\";\nimport type { Editor } from \"./types.js\";\n\n/**\n * Maps editor names to the corresponding agent names used by the skills CLI.\n */\nfunction getSkillsAgentName(editor: Editor): string {\n\tswitch (editor) {\n\t\tcase \"Cursor\":\n\t\t\treturn \"cursor\";\n\t\tcase \"VS Code\":\n\t\tcase \"GitHub Copilot CLI\":\n\t\t\treturn \"github-copilot\";\n\t\tcase \"Claude CLI\":\n\t\t\treturn \"claude-code\";\n\t\tcase \"Codex\":\n\t\t\treturn \"codex\";\n\t\tcase \"OpenCode\":\n\t\t\treturn \"opencode\";\n\t\tcase \"Antigravity\":\n\t\t\treturn \"antigravity\";\n\t\tcase \"Cline\":\n\t\tcase \"Cline CLI\":\n\t\t\treturn \"cline\";\n\t\tcase \"Gemini CLI\":\n\t\t\treturn \"gemini-cli\";\n\t\tcase \"Goose\":\n\t\t\treturn \"goose\";\n\t\tdefault:\n\t\t\treturn \"\";\n\t}\n}\n\n/**\n * Installs Neon agent skills using Vercel's skills CLI.\n */\nexport async function installAgentSkills(\n\tselectedEditors: Editor[],\n): Promise<boolean> {\n\tconst editorsWithSkills = selectedEditors.filter(\n\t\t(e) => getSkillsAgentName(e) !== \"\",\n\t);\n\n\tif (editorsWithSkills.length === 0) {\n\t\treturn true;\n\t}\n\n\tconst skillsSpinner = spinner();\n\tskillsSpinner.start(\"Installing agent skills for Neon in this project...\");\n\n\tlet anyFailed = false;\n\n\tfor (const editor of editorsWithSkills) {\n\t\tconst agentName = getSkillsAgentName(editor);\n\n\t\ttry {\n\t\t\tawait execa(\n\t\t\t\t\"npx\",\n\t\t\t\t[\n\t\t\t\t\t\"skills\",\n\t\t\t\t\t\"add\",\n\t\t\t\t\t\"neondatabase/agent-skills\",\n\t\t\t\t\t\"--skill\",\n\t\t\t\t\t\"neon-postgres\",\n\t\t\t\t\t\"--agent\",\n\t\t\t\t\tagentName,\n\t\t\t\t\t\"-y\",\n\t\t\t\t],\n\t\t\t\t{\n\t\t\t\t\tstdio: \"pipe\",\n\t\t\t\t\ttimeout: 10000,\n\t\t\t\t},\n\t\t\t);\n\t\t} catch (error) {\n\t\t\tlog.error(\n\t\t\t\t`Failed to install agent skills for ${editor}: ${error instanceof Error ? error.message : \"Unknown error\"}`,\n\t\t\t);\n\t\t\tanyFailed = true;\n\t\t}\n\t}\n\n\tif (anyFailed) {\n\t\tskillsSpinner.stop(\n\t\t\t\"Agent skills installation for this project completed with errors\",\n\t\t);\n\t\tlog.info(\n\t\t\t\"You can manually install skills by running: npx skills add neondatabase/agent-skills --skill neon-postgres\",\n\t\t);\n\t\treturn false;\n\t}\n\n\tskillsSpinner.stop(\"Agent skills installed for this project ✓\");\n\treturn true;\n}\n"],"mappings":";;;;;;AAOA,SAAS,mBAAmB,QAAwB;AACnD,SAAQ,QAAR;EACC,KAAK,SACJ,QAAO;EACR,KAAK;EACL,KAAK,qBACJ,QAAO;EACR,KAAK,aACJ,QAAO;EACR,KAAK,QACJ,QAAO;EACR,KAAK,WACJ,QAAO;EACR,KAAK,cACJ,QAAO;EACR,KAAK;EACL,KAAK,YACJ,QAAO;EACR,KAAK,aACJ,QAAO;EACR,KAAK,QACJ,QAAO;EACR,QACC,QAAO;;;;;;AAOV,eAAsB,mBACrB,iBACmB;CACnB,MAAM,oBAAoB,gBAAgB,QACxC,MAAM,mBAAmB,EAAE,KAAK,GACjC;AAED,KAAI,kBAAkB,WAAW,EAChC,QAAO;CAGR,MAAM,gBAAgB,SAAS;AAC/B,eAAc,MAAM,sDAAsD;CAE1E,IAAI,YAAY;AAEhB,MAAK,MAAM,UAAU,mBAAmB;EACvC,MAAM,YAAY,mBAAmB,OAAO;AAE5C,MAAI;AACH,SAAM,MACL,OACA;IACC;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA,EACD;IACC,OAAO;IACP,SAAS;IACT,CACD;WACO,OAAO;AACf,OAAI,MACH,sCAAsC,OAAO,IAAI,iBAAiB,QAAQ,MAAM,UAAU,kBAC1F;AACD,eAAY;;;AAId,KAAI,WAAW;AACd,gBAAc,KACb,mEACA;AACD,MAAI,KACH,6GACA;AACD,SAAO;;AAGR,eAAc,KAAK,4CAA4C;AAC/D,QAAO"}
|
package/dist/lib/types.d.ts
CHANGED
|
@@ -1,22 +1,6 @@
|
|
|
1
1
|
//#region src/lib/types.d.ts
|
|
2
|
-
type Editor = "Cursor" | "VS Code" | "Claude CLI";
|
|
2
|
+
type Editor = "Cursor" | "VS Code" | "Claude CLI" | "Claude Desktop" | "Codex" | "OpenCode" | "Antigravity" | "Cline" | "Cline CLI" | "Gemini CLI" | "GitHub Copilot CLI" | "Goose" | "MCPorter" | "Zed";
|
|
3
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
4
|
//#endregion
|
|
21
|
-
export { Editor, InstallStatus
|
|
5
|
+
export { Editor, InstallStatus };
|
|
22
6
|
//# sourceMappingURL=types.d.ts.map
|
package/dist/lib/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","names":[],"sources":["../../src/lib/types.ts"],"sourcesContent":[],"mappings":";KAAY,MAAA;AAAA,
|
|
1
|
+
{"version":3,"file":"types.d.ts","names":[],"sources":["../../src/lib/types.ts"],"sourcesContent":[],"mappings":";KAAY,MAAA;AAAA,KAgBA,aAAA,GAhBM,SAAA,GAAA,QAAA"}
|
package/dist/lib/types.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "neon-init",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.14.0",
|
|
4
4
|
"description": "Initialize Neon projects",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"neon",
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
],
|
|
11
11
|
"repository": {
|
|
12
12
|
"type": "git",
|
|
13
|
-
"url": "git+https://github.com/neondatabase/
|
|
13
|
+
"url": "git+https://github.com/neondatabase/neon-pkgs.git"
|
|
14
14
|
},
|
|
15
15
|
"license": "Apache-2.0",
|
|
16
16
|
"author": {
|
|
@@ -44,6 +44,7 @@
|
|
|
44
44
|
},
|
|
45
45
|
"dependencies": {
|
|
46
46
|
"@clack/prompts": "0.10.1",
|
|
47
|
+
"add-mcp": "^1.5.1",
|
|
47
48
|
"execa": "^9.5.2",
|
|
48
49
|
"yargs": "^18.0.0",
|
|
49
50
|
"yoctocolors": "^2.1.2"
|
package/dist/lib/mcp-config.d.ts
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
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
|
|
@@ -1 +0,0 @@
|
|
|
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"}
|
package/dist/lib/mcp-config.js
DELETED
|
@@ -1,51 +0,0 @@
|
|
|
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
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"mcp-config.js","names":[],"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,IAAI;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"}
|