neon-init 0.12.0 → 0.13.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/README.md CHANGED
@@ -60,9 +60,9 @@ The tool automatically detects which editors are installed on your system and yo
60
60
  - Neon-specific features (branching, autoscaling, scale-to-zero)
61
61
 
62
62
  ### Installs Neon Agent Skills
63
- After configuring your editor, `neon-init` automatically installs Neon-specific agent skills using Vercel's [skills ecosystem](https://skills.sh). This enhances your agent with additional Neon capabilities and commands.
63
+ After configuring your editor, `neon-init` automatically installs the `neon-postgres` skill using Vercel's [skills ecosystem](https://skills.sh). This enhances your agent with Neon-specific Postgres capabilities and commands.
64
64
 
65
- - Runs `npx skills add neondatabase/agent-skills` for each selected editor
65
+ - Runs `npx skills add neondatabase/agent-skills --skill neon-postgres` for each selected editor
66
66
  - Auto-confirms installation with `-y` flag
67
67
  - Maps editors to agent names: Cursor → `cursor`, VS Code → `github-copilot`, Claude CLI → `claude-code`
68
68
 
package/dist/cli.d.ts CHANGED
@@ -1,2 +1 @@
1
- #!/usr/bin/env node
2
1
  export {};
package/dist/cli.js CHANGED
@@ -1,8 +1,42 @@
1
1
  #!/usr/bin/env node
2
2
  import { init } from "./index.js";
3
+ import yargs from "yargs";
4
+ import { hideBin } from "yargs/helpers";
3
5
 
4
6
  //#region src/cli.ts
5
- await init();
7
+ const AGENT_FLAG_VALUES = [
8
+ "cursor",
9
+ "copilot",
10
+ "code"
11
+ ];
12
+ function parseAgentToEditor(value) {
13
+ switch (value.trim().toLowerCase()) {
14
+ case "cursor": return "Cursor";
15
+ case "github-copilot":
16
+ case "copilot":
17
+ case "vs code":
18
+ case "vscode":
19
+ case "vs-code": return "VS Code";
20
+ case "claude-code":
21
+ case "claude cli":
22
+ case "claude-cli":
23
+ case "claude": return "Claude CLI";
24
+ default: return null;
25
+ }
26
+ }
27
+ const agentArg = yargs(hideBin(process.argv)).scriptName("neon-init").option("agent", {
28
+ alias: "a",
29
+ type: "string",
30
+ description: "Agent to configure (cursor, copilot, code)."
31
+ }).help().parseSync().agent;
32
+ if (agentArg !== void 0) {
33
+ const editor = parseAgentToEditor(agentArg);
34
+ if (editor === null) {
35
+ console.error(`Invalid --agent value: "${agentArg}". Supported: ${AGENT_FLAG_VALUES.join(", ")}`);
36
+ process.exit(1);
37
+ }
38
+ await init({ agent: editor });
39
+ } else await init();
6
40
 
7
41
  //#endregion
8
42
  export { };
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 { init } from \"./index.js\";\n\nawait init();\n"],"mappings":";;;;AAIA,MAAM,MAAM"}
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\", \"code\"] 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, code).\",\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;CAAO;AAEvD,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,QAAW;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 CHANGED
@@ -1,8 +1,14 @@
1
+ import { Editor } from "./lib/types.js";
2
+
1
3
  //#region src/index.d.ts
4
+ interface InitOptions {
5
+ /** When set, configures only this agent and skips the editor selection prompt. */
6
+ agent?: Editor;
7
+ }
2
8
  /**
3
9
  * Initialize Neon projects with MCP Server
4
10
  */
5
- declare function init(): Promise<void>;
11
+ declare function init(options?: InitOptions): Promise<void>;
6
12
  //#endregion
7
- export { init };
13
+ export { InitOptions, init };
8
14
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../src/index.ts"],"sourcesContent":[],"mappings":";;AAmBA;;iBAAsB,IAAA,CAAA,GAAQ"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../src/index.ts"],"sourcesContent":[],"mappings":";;;UAgBiB,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
@@ -9,8 +9,8 @@ import { bold, cyan } from "yoctocolors";
9
9
  /**
10
10
  * Initialize Neon projects with MCP Server
11
11
  */
12
- async function init() {
13
- intro("Adding Neon to your project");
12
+ async function init(options) {
13
+ intro("Adding Neon MCP server, extension (for VS Code and Cursor) and agent skills");
14
14
  const homeDir = process.env.HOME || process.env.USERPROFILE;
15
15
  if (!homeDir) {
16
16
  log.error("Could not determine home directory");
@@ -18,41 +18,45 @@ async function init() {
18
18
  process.exit(1);
19
19
  }
20
20
  const workspaceDir = process.cwd();
21
- const availableEditors = await detectAvailableEditors(homeDir);
22
- if (availableEditors.length === 0) {
23
- log.warn("No supported editors detected on your system.");
24
- log.info("Supported editors:");
25
- log.info(" • VS Code (with Neon Local Connect extension)");
26
- log.info(" Cursor (with Neon Local Connect extension)");
27
- log.info(" Claude CLI (with MCP Server)");
28
- const continueAnyway = await confirm({
29
- message: "Would you like to configure Neon anyway? (You can manually select your editor)",
30
- initialValue: true
21
+ let selectedEditors;
22
+ if (options?.agent !== void 0) selectedEditors = [options.agent];
23
+ else {
24
+ 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
+ const response = await multiselect({
41
+ message: "Which editor(s) would you like to configure? (Space to toggle each option, Enter to confirm your selection)",
42
+ options: [
43
+ "Cursor",
44
+ "VS Code",
45
+ "Claude CLI"
46
+ ].map((editor) => ({
47
+ value: editor,
48
+ label: editor,
49
+ hint: editor === "Claude CLI" ? "MCP Server" : "Neon Local Connect extension"
50
+ })),
51
+ initialValues: availableEditors,
52
+ required: true
31
53
  });
32
- if (isCancel(continueAnyway) || !continueAnyway) {
54
+ if (isCancel(response)) {
33
55
  outro("Installation cancelled");
34
56
  process.exit(0);
35
57
  }
58
+ selectedEditors = response;
36
59
  }
37
- const response = await multiselect({
38
- message: "Which editor(s) would you like to configure? (Space to toggle each option, Enter to confirm your selection)",
39
- options: [
40
- "Cursor",
41
- "VS Code",
42
- "Claude CLI"
43
- ].map((editor) => ({
44
- value: editor,
45
- label: editor,
46
- hint: editor === "Claude CLI" ? "MCP Server" : "Neon Local Connect extension"
47
- })),
48
- initialValues: availableEditors,
49
- required: true
50
- });
51
- if (isCancel(response)) {
52
- outro("Installation cancelled");
53
- process.exit(0);
54
- }
55
- const selectedEditors = response;
56
60
  if (selectedEditors.length === 0) {
57
61
  log.warn("No editors selected.");
58
62
  outro("Installation cancelled");
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["import {\n\tconfirm,\n\tintro,\n\tisCancel,\n\tlog,\n\tmultiselect,\n\tnote,\n\toutro,\n} from \"@clack/prompts\";\nimport { bold, cyan } from \"yoctocolors\";\nimport { detectAvailableEditors } from \"./lib/editors.js\";\nimport { 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\n/**\n * Initialize Neon projects with MCP Server\n */\nexport async function init(): Promise<void> {\n\tintro(\"Adding Neon to your project\");\n\n\t// Get the home directory\n\tconst homeDir = process.env.HOME || process.env.USERPROFILE;\n\tif (!homeDir) {\n\t\tlog.error(\"Could not determine home directory\");\n\t\toutro(\"📣 Is this unexpected? Email us at feedback@neon.tech\");\n\t\tprocess.exit(1);\n\t}\n\n\t// Get the current workspace directory\n\tconst workspaceDir = process.cwd();\n\n\t// Detect available editors\n\tconst availableEditors = await detectAvailableEditors(homeDir);\n\n\t// If no editors detected, offer to continue anyway\n\tif (availableEditors.length === 0) {\n\t\tlog.warn(\"No supported editors detected on your system.\");\n\t\tlog.info(\"Supported editors:\");\n\t\tlog.info(\" • VS Code (with Neon Local Connect extension)\");\n\t\tlog.info(\" • Cursor (with Neon Local Connect extension)\");\n\t\tlog.info(\" • Claude CLI (with MCP Server)\");\n\n\t\tconst continueAnyway = await confirm({\n\t\t\tmessage:\n\t\t\t\t\"Would you like to configure Neon anyway? (You can manually select your editor)\",\n\t\t\tinitialValue: true,\n\t\t});\n\n\t\tif (isCancel(continueAnyway) || !continueAnyway) {\n\t\t\toutro(\"Installation cancelled\");\n\t\t\tprocess.exit(0);\n\t\t}\n\t}\n\n\t// Determine which editors to configure\n\tconst response = await multiselect({\n\t\tmessage:\n\t\t\t\"Which editor(s) would you like to configure? (Space to toggle each option, Enter to confirm your selection)\",\n\t\toptions: [\"Cursor\", \"VS Code\", \"Claude CLI\"].map((editor) => ({\n\t\t\tvalue: editor,\n\t\t\tlabel: editor,\n\t\t\thint:\n\t\t\t\teditor === \"Claude CLI\"\n\t\t\t\t\t? \"MCP Server\"\n\t\t\t\t\t: \"Neon Local Connect extension\",\n\t\t})),\n\t\tinitialValues: availableEditors, // Select detected editors by default\n\t\trequired: true,\n\t});\n\n\tif (isCancel(response)) {\n\t\toutro(\"Installation cancelled\");\n\t\tprocess.exit(0);\n\t}\n\n\tconst selectedEditors = response as Editor[];\n\n\tif (selectedEditors.length === 0) {\n\t\tlog.warn(\"No editors selected.\");\n\t\toutro(\"Installation cancelled\");\n\t\tprocess.exit(0);\n\t}\n\n\t// Install Neon for selected editors\n\tconst results = await installNeon(homeDir, workspaceDir, 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}\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":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["import {\n\tconfirm,\n\tintro,\n\tisCancel,\n\tlog,\n\tmultiselect,\n\tnote,\n\toutro,\n} from \"@clack/prompts\";\nimport { bold, cyan } from \"yoctocolors\";\nimport { detectAvailableEditors } from \"./lib/editors.js\";\nimport { 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\tintro(\n\t\t\"Adding Neon MCP server, extension (for VS Code and Cursor) and agent skills\",\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\t// Get the current workspace directory\n\tconst workspaceDir = process.cwd();\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// If no editors detected, offer to continue anyway\n\t\tif (availableEditors.length === 0) {\n\t\t\tlog.warn(\"No supported editors detected on your system.\");\n\t\t\tlog.info(\"Supported editors:\");\n\t\t\tlog.info(\" • VS Code (with Neon Local Connect extension)\");\n\t\t\tlog.info(\" • Cursor (with Neon Local Connect extension)\");\n\t\t\tlog.info(\" • Claude CLI (with MCP Server)\");\n\n\t\t\tconst continueAnyway = await confirm({\n\t\t\t\tmessage:\n\t\t\t\t\t\"Would you like to configure Neon anyway? (You can manually select your editor)\",\n\t\t\t\tinitialValue: true,\n\t\t\t});\n\n\t\t\tif (isCancel(continueAnyway) || !continueAnyway) {\n\t\t\t\toutro(\"Installation cancelled\");\n\t\t\t\tprocess.exit(0);\n\t\t\t}\n\t\t}\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: [\"Cursor\", \"VS Code\", \"Claude CLI\"].map((editor) => ({\n\t\t\t\tvalue: editor,\n\t\t\t\tlabel: editor,\n\t\t\t\thint:\n\t\t\t\t\teditor === \"Claude CLI\"\n\t\t\t\t\t\t? \"MCP Server\"\n\t\t\t\t\t\t: \"Neon Local Connect extension\",\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(homeDir, workspaceDir, 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}\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":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"auth.d.ts","names":[],"sources":["../../src/lib/auth.ts"],"sourcesContent":[],"mappings":";;AASA;AA0CA;;iBA1CsB,iBAAA,CAAA,GAAqB;;;;iBA0CrB,uBAAA,CAAA,GAA2B"}
1
+ {"version":3,"file":"auth.d.ts","names":[],"sources":["../../src/lib/auth.ts"],"sourcesContent":[],"mappings":";;AASA;AAqDA;;iBArDsB,iBAAA,CAAA,GAAqB;;;;iBAqDrB,uBAAA,CAAA,GAA2B"}
package/dist/lib/auth.js CHANGED
@@ -9,16 +9,25 @@ import { execa } from "execa";
9
9
  * This will automatically start the OAuth flow if the user isn't already authenticated
10
10
  */
11
11
  async function ensureNeonctlAuth() {
12
+ if (await getNeonctlAccessToken()) return true;
12
13
  try {
13
14
  await execa("npx", [
14
15
  "-y",
15
16
  "neonctl",
16
17
  "me",
17
18
  "--no-analytics"
18
- ], { stdio: "inherit" });
19
+ ], {
20
+ stdio: "inherit",
21
+ env: {
22
+ ...process.env,
23
+ CI: void 0
24
+ }
25
+ });
19
26
  return true;
20
27
  } catch (error) {
21
- log.error(`Authentication failed: ${error instanceof Error ? error.message : "Unknown error"}`);
28
+ const msg = error instanceof Error ? error.message : "Unknown error";
29
+ if (msg.includes("interactive auth") || msg.includes("CI")) log.error("Auth requires an interactive terminal. Run neon-init in your system terminal (outside the chat) to sign in.");
30
+ else log.error(`Authentication failed: ${msg}`);
22
31
  return false;
23
32
  }
24
33
  }
@@ -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\ttry {\n\t\t// Use execa to authenticate with neonctl\n\t\tawait execa(\"npx\", [\"-y\", \"neonctl\", \"me\", \"--no-analytics\"], {\n\t\t\tstdio: \"inherit\", // Shows OAuth URL and prompts to the user\n\t\t});\n\n\t\treturn true;\n\t} catch (error) {\n\t\tlog.error(\n\t\t\t`Authentication failed: ${error instanceof Error ? error.message : \"Unknown error\"}`,\n\t\t);\n\t\treturn false;\n\t}\n}\n\n/**\n * Gets the OAuth access token from neonctl's stored credentials\n */\nasync function getNeonctlAccessToken(): Promise<string | null> {\n\ttry {\n\t\tconst homeDir = process.env.HOME || process.env.USERPROFILE;\n\t\tif (!homeDir) return null;\n\n\t\tconst credentialsPath = resolve(\n\t\t\thomeDir,\n\t\t\t\".config\",\n\t\t\t\"neonctl\",\n\t\t\t\"credentials.json\",\n\t\t);\n\t\tif (!existsSync(credentialsPath)) return null;\n\n\t\tconst credentials = JSON.parse(readFileSync(credentialsPath, \"utf-8\"));\n\t\treturn credentials.access_token || null;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\n/**\n * Creates an API key using the Neon API with the OAuth token from neonctl\n */\nexport async function createApiKeyFromNeonctl(): Promise<string | null> {\n\ttry {\n\t\tconst accessToken = await getNeonctlAccessToken();\n\t\tif (!accessToken) {\n\t\t\tlog.error(\"Could not find OAuth token from neonctl\");\n\t\t\treturn null;\n\t\t}\n\n\t\t// Generate a unique key name with timestamp\n\t\tconst timestamp = new Date()\n\t\t\t.toISOString()\n\t\t\t.replace(/[:.]/g, \"-\")\n\t\t\t.slice(0, -5); // e.g., 2024-10-08T15-30-45\n\t\tconst keyName = `neonctl-init-${timestamp}`;\n\n\t\t// Call Neon API to create an API key\n\t\tconst response = await fetch(\n\t\t\t\"https://console.neon.tech/api/v2/api_keys\",\n\t\t\t{\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders: {\n\t\t\t\t\tAuthorization: `Bearer ${accessToken}`,\n\t\t\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t\t},\n\t\t\t\tbody: JSON.stringify({\n\t\t\t\t\tkey_name: keyName,\n\t\t\t\t}),\n\t\t\t},\n\t\t);\n\n\t\tif (!response.ok) {\n\t\t\tconst errorText = await response.text();\n\t\t\tlog.error(\n\t\t\t\t`Failed to create API key: ${response.status} ${errorText}`,\n\t\t\t);\n\t\t\treturn null;\n\t\t}\n\n\t\tconst data = await response.json();\n\t\treturn data.key || null;\n\t} catch (error) {\n\t\tlog.error(\n\t\t\t`Failed to create API key: ${error instanceof Error ? error.message : \"Unknown error\"}`,\n\t\t);\n\t\treturn null;\n\t}\n}\n"],"mappings":";;;;;;;;;;AASA,eAAsB,oBAAsC;AAC3D,KAAI;AAEH,QAAM,MAAM,OAAO;GAAC;GAAM;GAAW;GAAM;GAAiB,EAAE,EAC7D,OAAO,WACP,CAAC;AAEF,SAAO;UACC,OAAO;AACf,MAAI,MACH,0BAA0B,iBAAiB,QAAQ,MAAM,UAAU,kBACnE;AACD,SAAO;;;;;;AAOT,eAAe,wBAAgD;AAC9D,KAAI;EACH,MAAM,UAAU,QAAQ,IAAI,QAAQ,QAAQ,IAAI;AAChD,MAAI,CAAC,QAAS,QAAO;EAErB,MAAM,kBAAkB,QACvB,SACA,WACA,WACA,mBACA;AACD,MAAI,CAAC,WAAW,gBAAgB,CAAE,QAAO;AAGzC,SADoB,KAAK,MAAM,aAAa,iBAAiB,QAAQ,CAAC,CACnD,gBAAgB;SAC5B;AACP,SAAO;;;;;;AAOT,eAAsB,0BAAkD;AACvE,KAAI;EACH,MAAM,cAAc,MAAM,uBAAuB;AACjD,MAAI,CAAC,aAAa;AACjB,OAAI,MAAM,0CAA0C;AACpD,UAAO;;EAQR,MAAM,UAAU,iCAJE,IAAI,MAAM,EAC1B,aAAa,CACb,QAAQ,SAAS,IAAI,CACrB,MAAM,GAAG,GAAG;EAId,MAAM,WAAW,MAAM,MACtB,6CACA;GACC,QAAQ;GACR,SAAS;IACR,eAAe,UAAU;IACzB,gBAAgB;IAChB;GACD,MAAM,KAAK,UAAU,EACpB,UAAU,SACV,CAAC;GACF,CACD;AAED,MAAI,CAAC,SAAS,IAAI;GACjB,MAAM,YAAY,MAAM,SAAS,MAAM;AACvC,OAAI,MACH,6BAA6B,SAAS,OAAO,GAAG,YAChD;AACD,UAAO;;AAIR,UADa,MAAM,SAAS,MAAM,EACtB,OAAO;UACX,OAAO;AACf,MAAI,MACH,6BAA6B,iBAAiB,QAAQ,MAAM,UAAU,kBACtE;AACD,SAAO"}
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;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"}
@@ -33,6 +33,8 @@ async function installAgentSkills(selectedEditors) {
33
33
  "skills",
34
34
  "add",
35
35
  "neondatabase/agent-skills",
36
+ "--skill",
37
+ "neon-postgres",
36
38
  "--agent",
37
39
  agentName,
38
40
  "-y"
@@ -51,7 +53,7 @@ async function installAgentSkills(selectedEditors) {
51
53
  }
52
54
  if (anyFailed) {
53
55
  skillsSpinner.stop("Agent skills installation completed with errors");
54
- log.info("You can manually install skills by running: npx skills add neondatabase/agent-skills");
56
+ log.info("You can manually install skills by running: npx skills add neondatabase/agent-skills --skill neon-postgres");
55
57
  return false;
56
58
  }
57
59
  skillsSpinner.stop("Agent skills installed ✓");
@@ -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\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\t\treturn \"github-copilot\";\n\t\tcase \"Claude CLI\":\n\t\t\treturn \"claude-code\";\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\tif (selectedEditors.length === 0) {\n\t\treturn true;\n\t}\n\n\tconst skillsSpinner = spinner();\n\tskillsSpinner.start(\"Installing agent skills for Neon...\");\n\n\tlet anyFailed = false;\n\n\t// Run skills add for each selected editor/agent\n\tfor (const editor of selectedEditors) {\n\t\tconst agentName = getSkillsAgentName(editor);\n\n\t\tif (agentName === \"\") {\n\t\t\tlog.error(`Unsupported editor: ${editor}`);\n\t\t\tanyFailed = true;\n\t\t\tcontinue;\n\t\t}\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\"--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\tenv: {\n\t\t\t\t\t\t...process.env,\n\t\t\t\t\t\tDISABLE_TELEMETRY: \"1\",\n\t\t\t\t\t},\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(\"Agent skills installation completed with errors\");\n\t\tlog.info(\n\t\t\t\"You can manually install skills by running: npx skills add neondatabase/agent-skills\",\n\t\t);\n\t\treturn false;\n\t}\n\n\tskillsSpinner.stop(\"Agent skills installed ✓\");\n\treturn true;\n}\n"],"mappings":";;;;;;;AAOA,SAAS,mBAAmB,QAAwB;AACnD,SAAQ,QAAR;EACC,KAAK,SACJ,QAAO;EACR,KAAK,UACJ,QAAO;EACR,KAAK,aACJ,QAAO;EACR,QACC,QAAO;;;;;;AAOV,eAAsB,mBACrB,iBACmB;AACnB,KAAI,gBAAgB,WAAW,EAC9B,QAAO;CAGR,MAAM,gBAAgB,SAAS;AAC/B,eAAc,MAAM,sCAAsC;CAE1D,IAAI,YAAY;AAGhB,MAAK,MAAM,UAAU,iBAAiB;EACrC,MAAM,YAAY,mBAAmB,OAAO;AAE5C,MAAI,cAAc,IAAI;AACrB,OAAI,MAAM,uBAAuB,SAAS;AAC1C,eAAY;AACZ;;AAGD,MAAI;AACH,SAAM,MACL,OACA;IACC;IACA;IACA;IACA;IACA;IACA;IACA,EACD;IACC,OAAO;IACP,SAAS;IACT,KAAK;KACJ,GAAG,QAAQ;KACX,mBAAmB;KACnB;IACD,CACD;WACO,OAAO;AACf,OAAI,MACH,sCAAsC,OAAO,IAAI,iBAAiB,QAAQ,MAAM,UAAU,kBAC1F;AACD,eAAY;;;AAId,KAAI,WAAW;AACd,gBAAc,KAAK,kDAAkD;AACrE,MAAI,KACH,uFACA;AACD,SAAO;;AAGR,eAAc,KAAK,2BAA2B;AAC9C,QAAO"}
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\t\treturn \"github-copilot\";\n\t\tcase \"Claude CLI\":\n\t\t\treturn \"claude-code\";\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\tif (selectedEditors.length === 0) {\n\t\treturn true;\n\t}\n\n\tconst skillsSpinner = spinner();\n\tskillsSpinner.start(\"Installing agent skills for Neon...\");\n\n\tlet anyFailed = false;\n\n\t// Run skills add for each selected editor/agent\n\tfor (const editor of selectedEditors) {\n\t\tconst agentName = getSkillsAgentName(editor);\n\n\t\tif (agentName === \"\") {\n\t\t\tlog.error(`Unsupported editor: ${editor}`);\n\t\t\tanyFailed = true;\n\t\t\tcontinue;\n\t\t}\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\tenv: {\n\t\t\t\t\t\t...process.env,\n\t\t\t\t\t\tDISABLE_TELEMETRY: \"1\",\n\t\t\t\t\t},\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(\"Agent skills installation completed with errors\");\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 ✓\");\n\treturn true;\n}\n"],"mappings":";;;;;;;AAOA,SAAS,mBAAmB,QAAwB;AACnD,SAAQ,QAAR;EACC,KAAK,SACJ,QAAO;EACR,KAAK,UACJ,QAAO;EACR,KAAK,aACJ,QAAO;EACR,QACC,QAAO;;;;;;AAOV,eAAsB,mBACrB,iBACmB;AACnB,KAAI,gBAAgB,WAAW,EAC9B,QAAO;CAGR,MAAM,gBAAgB,SAAS;AAC/B,eAAc,MAAM,sCAAsC;CAE1D,IAAI,YAAY;AAGhB,MAAK,MAAM,UAAU,iBAAiB;EACrC,MAAM,YAAY,mBAAmB,OAAO;AAE5C,MAAI,cAAc,IAAI;AACrB,OAAI,MAAM,uBAAuB,SAAS;AAC1C,eAAY;AACZ;;AAGD,MAAI;AACH,SAAM,MACL,OACA;IACC;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA,EACD;IACC,OAAO;IACP,SAAS;IACT,KAAK;KACJ,GAAG,QAAQ;KACX,mBAAmB;KACnB;IACD,CACD;WACO,OAAO;AACf,OAAI,MACH,sCAAsC,OAAO,IAAI,iBAAiB,QAAQ,MAAM,UAAU,kBAC1F;AACD,eAAY;;;AAId,KAAI,WAAW;AACd,gBAAc,KAAK,kDAAkD;AACrE,MAAI,KACH,6GACA;AACD,SAAO;;AAGR,eAAc,KAAK,2BAA2B;AAC9C,QAAO"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "neon-init",
3
- "version": "0.12.0",
3
+ "version": "0.13.0",
4
4
  "description": "Initialize Neon projects",
5
5
  "keywords": [
6
6
  "neon",
@@ -35,6 +35,7 @@
35
35
  ],
36
36
  "devDependencies": {
37
37
  "@types/node": "^20.19.0",
38
+ "@types/yargs": "^17.0.35",
38
39
  "@vitest/coverage-v8": "3.0.9",
39
40
  "console-fail-test": "0.5.0",
40
41
  "tsdown": "^0.14.1",
@@ -44,6 +45,7 @@
44
45
  "dependencies": {
45
46
  "@clack/prompts": "0.10.1",
46
47
  "execa": "^9.5.2",
48
+ "yargs": "^18.0.0",
47
49
  "yoctocolors": "^2.1.2"
48
50
  },
49
51
  "engines": {