neon-init 0.19.0 → 0.20.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -1
- package/dist/cli.js +2 -2
- package/dist/cli.js.map +1 -1
- package/dist/index.js +4 -4
- package/dist/index.js.map +1 -1
- package/dist/interactive.js +8 -8
- package/dist/interactive.js.map +1 -1
- package/dist/lib/auth.js +2 -2
- package/dist/lib/auth.js.map +1 -1
- package/dist/lib/enrich-output.d.ts +1 -1
- package/dist/lib/enrich-output.js +4 -4
- package/dist/lib/enrich-output.js.map +1 -1
- package/dist/lib/neonctl.d.ts +5 -3
- package/dist/lib/neonctl.d.ts.map +1 -1
- package/dist/lib/neonctl.js +6 -4
- package/dist/lib/neonctl.js.map +1 -1
- package/dist/lib/phases/getting-started.d.ts +1 -1
- package/dist/lib/phases/getting-started.js +4 -4
- package/dist/lib/phases/getting-started.js.map +1 -1
- package/dist/lib/phases/neon-auth.js +1 -1
- package/dist/lib/phases/neon-auth.js.map +1 -1
- package/dist/lib/phases/setup.js +6 -6
- package/dist/lib/phases/setup.js.map +1 -1
- package/dist/lib/phases/status.js +4 -4
- package/dist/lib/phases/status.js.map +1 -1
- package/package.json +4 -4
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\nexport interface AuthOptions {\n\tjson?: boolean;\n}\n\n/**\n * Ensures neonctl is authenticated by running a command that triggers auth if needed\n * This will automatically start the OAuth flow if the user isn't already authenticated\n */\nexport async function ensureNeonctlAuth(\n\toptions?: AuthOptions,\n): Promise<boolean> {\n\tconst quiet = options?.json === true;\n\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\"], {\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 (!quiet) {\n\t\t\tif (msg.includes(\"interactive auth\") || msg.includes(\"CI\")) {\n\t\t\t\tlog.error(\n\t\t\t\t\t\"Auth requires an interactive terminal. Run
|
|
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\nexport interface AuthOptions {\n\tjson?: boolean;\n}\n\n/**\n * Ensures neonctl is authenticated by running a command that triggers auth if needed\n * This will automatically start the OAuth flow if the user isn't already authenticated\n */\nexport async function ensureNeonctlAuth(\n\toptions?: AuthOptions,\n): Promise<boolean> {\n\tconst quiet = options?.json === true;\n\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\"], {\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 (!quiet) {\n\t\t\tif (msg.includes(\"interactive auth\") || msg.includes(\"CI\")) {\n\t\t\t\tlog.error(\n\t\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\t);\n\t\t\t} else {\n\t\t\t\tlog.error(`Authentication failed: ${msg}`);\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n}\n\n/**\n * Checks whether neonctl has stored OAuth credentials.\n */\nexport async function isAuthenticated(): Promise<boolean> {\n\tconst token = await getNeonctlAccessToken();\n\treturn token !== null;\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(\n\toptions?: AuthOptions,\n): Promise<string | null> {\n\tconst quiet = options?.json === true;\n\n\ttry {\n\t\tconst accessToken = await getNeonctlAccessToken();\n\t\tif (!accessToken) {\n\t\t\tif (!quiet)\n\t\t\t\tlog.error(\"Could not find OAuth token from the Neon CLI\");\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 apiBase = process.env.NEON_API_HOST\n\t\t\t? `${new URL(process.env.NEON_API_HOST).origin}/api/v2`\n\t\t\t: \"https://console.neon.tech/api/v2\";\n\t\tconst response = await fetch(`${apiBase}/api_keys`, {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: {\n\t\t\t\tAuthorization: `Bearer ${accessToken}`,\n\t\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t},\n\t\t\tbody: JSON.stringify({\n\t\t\t\tkey_name: keyName,\n\t\t\t}),\n\t\t\tsignal: AbortSignal.timeout(30000),\n\t\t});\n\n\t\tif (!response.ok) {\n\t\t\tconst errorText = await response.text();\n\t\t\tif (!quiet)\n\t\t\t\tlog.error(\n\t\t\t\t\t`Failed to create API key: ${response.status} ${errorText}`,\n\t\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\tif (!quiet)\n\t\t\tlog.error(\n\t\t\t\t`Failed to create API key: ${error instanceof Error ? error.message : \"Unknown error\"}`,\n\t\t\t);\n\t\treturn null;\n\t}\n}\n"],"mappings":";;;;;;;;;AAaA,eAAsB,kBACrB,SACmB;CACnB,MAAM,QAAQ,SAAS,SAAS;CAIhC,IAAI,MADwB,sBAAsB,GAC/B,OAAO;CAE1B,IAAI;EAEH,MAAM,MAAM,OAAO;GAAC;GAAM;GAAW;EAAI,GAAG;GAE3C,OAAO;GAEP,KAAK;IAAE,GAAG,QAAQ;IAAK,IAAI,KAAA;GAAU;EACtC,CAAC;EACD,OAAO;CACR,SAAS,OAAO;EACf,MAAM,MAAM,iBAAiB,QAAQ,MAAM,UAAU;EACrD,IAAI,CAAC,OACJ,IAAI,IAAI,SAAS,kBAAkB,KAAK,IAAI,SAAS,IAAI,GACxD,IAAI,MACH,6GACD;OAEA,IAAI,MAAM,0BAA0B,KAAK;EAG3C,OAAO;CACR;AACD;;;;AAKA,eAAsB,kBAAoC;CAEzD,OAAO,MADa,sBAAsB,MACzB;AAClB;;;;AAKA,eAAe,wBAAgD;CAC9D,IAAI;EACH,MAAM,UAAU,QAAQ,IAAI,QAAQ,QAAQ,IAAI;EAChD,IAAI,CAAC,SAAS,OAAO;EAErB,MAAM,kBAAkB,QACvB,SACA,WACA,WACA,kBACD;EACA,IAAI,CAAC,WAAW,eAAe,GAAG,OAAO;EAGzC,OADoB,KAAK,MAAM,aAAa,iBAAiB,OAAO,CACnD,CAAC,CAAC,gBAAgB;CACpC,QAAQ;EACP,OAAO;CACR;AACD;;;;AAKA,eAAsB,wBACrB,SACyB;CACzB,MAAM,QAAQ,SAAS,SAAS;CAEhC,IAAI;EACH,MAAM,cAAc,MAAM,sBAAsB;EAChD,IAAI,CAAC,aAAa;GACjB,IAAI,CAAC,OACJ,IAAI,MAAM,8CAA8C;GACzD,OAAO;EACR;EAOA,MAAM,UAAU,iCAJE,IAAI,KAAK,EAAA,CACzB,YAAY,CAAC,CACb,QAAQ,SAAS,GAAG,CAAC,CACrB,MAAM,GAAG,EAC6B;EAGxC,MAAM,UAAU,QAAQ,IAAI,gBACzB,GAAG,IAAI,IAAI,QAAQ,IAAI,aAAa,CAAC,CAAC,OAAO,WAC7C;EACH,MAAM,WAAW,MAAM,MAAM,GAAG,QAAQ,YAAY;GACnD,QAAQ;GACR,SAAS;IACR,eAAe,UAAU;IACzB,gBAAgB;GACjB;GACA,MAAM,KAAK,UAAU,EACpB,UAAU,QACX,CAAC;GACD,QAAQ,YAAY,QAAQ,GAAK;EAClC,CAAC;EAED,IAAI,CAAC,SAAS,IAAI;GACjB,MAAM,YAAY,MAAM,SAAS,KAAK;GACtC,IAAI,CAAC,OACJ,IAAI,MACH,6BAA6B,SAAS,OAAO,GAAG,WACjD;GACD,OAAO;EACR;EAGA,QAAO,MADY,SAAS,KAAK,EAAA,CACrB,OAAO;CACpB,SAAS,OAAO;EACf,IAAI,CAAC,OACJ,IAAI,MACH,6BAA6B,iBAAiB,QAAQ,MAAM,UAAU,iBACvE;EACD,OAAO;CACR;AACD"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
//#region src/lib/enrich-output.d.ts
|
|
2
2
|
/**
|
|
3
3
|
* Walks a phase response object and:
|
|
4
|
-
* 1. Replaces `args` arrays with `command` strings (
|
|
4
|
+
* 1. Replaces `args` arrays with `command` strings (neon init --data format)
|
|
5
5
|
* 2. Renames `run_neon_init` → `run_shell_command`
|
|
6
6
|
* 3. Adds a description to finalize steps
|
|
7
7
|
*/
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
//#region src/lib/enrich-output.ts
|
|
2
2
|
/**
|
|
3
3
|
* Converts neon-init args (e.g. ["neon-auth", "--json", "--setup"]) to a
|
|
4
|
-
*
|
|
4
|
+
* neon init --data command using the step routing pattern.
|
|
5
5
|
*/
|
|
6
6
|
function argsToCommand(args) {
|
|
7
7
|
const data = {};
|
|
@@ -28,11 +28,11 @@ function argsToCommand(args) {
|
|
|
28
28
|
}
|
|
29
29
|
} else i += 1;
|
|
30
30
|
}
|
|
31
|
-
return `
|
|
31
|
+
return `neon init --agent --data '${JSON.stringify(data)}'`;
|
|
32
32
|
}
|
|
33
33
|
/**
|
|
34
34
|
* Walks a phase response object and:
|
|
35
|
-
* 1. Replaces `args` arrays with `command` strings (
|
|
35
|
+
* 1. Replaces `args` arrays with `command` strings (neon init --data format)
|
|
36
36
|
* 2. Renames `run_neon_init` → `run_shell_command`
|
|
37
37
|
* 3. Adds a description to finalize steps
|
|
38
38
|
*/
|
|
@@ -48,7 +48,7 @@ function enrichResponse(obj) {
|
|
|
48
48
|
}
|
|
49
49
|
if (result.type === "run_neon_init") {
|
|
50
50
|
result.type = "run_shell_command";
|
|
51
|
-
if (typeof result.command === "string" && result.command.includes("\"step\":\"finalize\"")) result.description = "Run this command to complete the setup. This is the final step — do not run any other
|
|
51
|
+
if (typeof result.command === "string" && result.command.includes("\"step\":\"finalize\"")) result.description = "Run this command to complete the setup. This is the final step — do not run any other neon init commands after this.";
|
|
52
52
|
}
|
|
53
53
|
return result;
|
|
54
54
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"enrich-output.js","names":[],"sources":["../../src/lib/enrich-output.ts"],"sourcesContent":["/**\n * Converts neon-init args (e.g. [\"neon-auth\", \"--json\", \"--setup\"]) to a\n *
|
|
1
|
+
{"version":3,"file":"enrich-output.js","names":[],"sources":["../../src/lib/enrich-output.ts"],"sourcesContent":["/**\n * Converts neon-init args (e.g. [\"neon-auth\", \"--json\", \"--setup\"]) to a\n * neon init --data command using the step routing pattern.\n */\nfunction argsToCommand(args: string[]): string {\n\tconst data: Record<string, unknown> = {};\n\tlet i = 0;\n\n\t// First non-flag arg is the subcommand → step\n\tif (args.length > 0 && !args[0].startsWith(\"-\")) {\n\t\tdata.step = args[0];\n\t\ti = 1;\n\t}\n\n\twhile (i < args.length) {\n\t\tconst arg = args[i];\n\t\tif (arg.startsWith(\"--\")) {\n\t\t\tconst key = arg\n\t\t\t\t.slice(2)\n\t\t\t\t.replace(/-([a-z])/g, (_, c: string) => c.toUpperCase());\n\t\t\tif (key === \"json\") {\n\t\t\t\ti += 1;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst next = args[i + 1];\n\t\t\tif (next !== undefined && !next.startsWith(\"-\")) {\n\t\t\t\tdata[key] = next;\n\t\t\t\ti += 2;\n\t\t\t} else {\n\t\t\t\tdata[key] = true;\n\t\t\t\ti += 1;\n\t\t\t}\n\t\t} else {\n\t\t\ti += 1;\n\t\t}\n\t}\n\n\treturn `neon init --agent --data '${JSON.stringify(data)}'`;\n}\n\n/**\n * Walks a phase response object and:\n * 1. Replaces `args` arrays with `command` strings (neon init --data format)\n * 2. Renames `run_neon_init` → `run_shell_command`\n * 3. Adds a description to finalize steps\n */\nexport function enrichResponse(obj: unknown): unknown {\n\tif (obj === null || typeof obj !== \"object\") return obj;\n\tif (Array.isArray(obj)) return obj.map(enrichResponse);\n\n\tconst record = obj as Record<string, unknown>;\n\tconst result: Record<string, unknown> = {};\n\n\tfor (const [key, value] of Object.entries(record)) {\n\t\tresult[key] = enrichResponse(value);\n\t}\n\n\t// Replace args with command in run_neon_init actions and responseMapping entries\n\tif (Array.isArray(result.args)) {\n\t\tresult.command = argsToCommand(result.args as string[]);\n\t\tdelete result.args;\n\t}\n\n\t// Rename run_neon_init → run_shell_command so agents don't infer subcommand patterns\n\tif (result.type === \"run_neon_init\") {\n\t\tresult.type = \"run_shell_command\";\n\t\t// Help agents understand finalize is the terminal step\n\t\tif (\n\t\t\ttypeof result.command === \"string\" &&\n\t\t\tresult.command.includes('\"step\":\"finalize\"')\n\t\t) {\n\t\t\tresult.description =\n\t\t\t\t\"Run this command to complete the setup. This is the final step — do not run any other neon init commands after this.\";\n\t\t}\n\t}\n\n\treturn result;\n}\n"],"mappings":";;;;;AAIA,SAAS,cAAc,MAAwB;CAC9C,MAAM,OAAgC,CAAC;CACvC,IAAI,IAAI;CAGR,IAAI,KAAK,SAAS,KAAK,CAAC,KAAK,EAAE,CAAC,WAAW,GAAG,GAAG;EAChD,KAAK,OAAO,KAAK;EACjB,IAAI;CACL;CAEA,OAAO,IAAI,KAAK,QAAQ;EACvB,MAAM,MAAM,KAAK;EACjB,IAAI,IAAI,WAAW,IAAI,GAAG;GACzB,MAAM,MAAM,IACV,MAAM,CAAC,CAAC,CACR,QAAQ,cAAc,GAAG,MAAc,EAAE,YAAY,CAAC;GACxD,IAAI,QAAQ,QAAQ;IACnB,KAAK;IACL;GACD;GACA,MAAM,OAAO,KAAK,IAAI;GACtB,IAAI,SAAS,KAAA,KAAa,CAAC,KAAK,WAAW,GAAG,GAAG;IAChD,KAAK,OAAO;IACZ,KAAK;GACN,OAAO;IACN,KAAK,OAAO;IACZ,KAAK;GACN;EACD,OACC,KAAK;CAEP;CAEA,OAAO,6BAA6B,KAAK,UAAU,IAAI,EAAE;AAC1D;;;;;;;AAQA,SAAgB,eAAe,KAAuB;CACrD,IAAI,QAAQ,QAAQ,OAAO,QAAQ,UAAU,OAAO;CACpD,IAAI,MAAM,QAAQ,GAAG,GAAG,OAAO,IAAI,IAAI,cAAc;CAErD,MAAM,SAAS;CACf,MAAM,SAAkC,CAAC;CAEzC,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,MAAM,GAC/C,OAAO,OAAO,eAAe,KAAK;CAInC,IAAI,MAAM,QAAQ,OAAO,IAAI,GAAG;EAC/B,OAAO,UAAU,cAAc,OAAO,IAAgB;EACtD,OAAO,OAAO;CACf;CAGA,IAAI,OAAO,SAAS,iBAAiB;EACpC,OAAO,OAAO;EAEd,IACC,OAAO,OAAO,YAAY,YAC1B,OAAO,QAAQ,SAAS,uBAAmB,GAE3C,OAAO,cACN;CAEH;CAEA,OAAO;AACR"}
|
package/dist/lib/neonctl.d.ts
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
//#region src/lib/neonctl.d.ts
|
|
2
2
|
/**
|
|
3
|
-
* Returns the
|
|
3
|
+
* Returns the Neon CLI command prefix: "CI= npx -y neon".
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
* directly, so no extra flags are needed.
|
|
5
|
+
* The CLI reads NEON_API_HOST and NEON_OAUTH_HOST from the environment
|
|
6
|
+
* directly, so no extra flags are needed. The `neon` package ships both the
|
|
7
|
+
* `neon` and `neonctl` binaries; we surface the cleaner `neon` command in the
|
|
8
|
+
* examples emitted to users and agents.
|
|
7
9
|
*
|
|
8
10
|
* Usage: `${neonctlCmd()} orgs list --output json`
|
|
9
11
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"neonctl.d.ts","names":[],"sources":["../../src/lib/neonctl.ts"],"mappings":";;
|
|
1
|
+
{"version":3,"file":"neonctl.d.ts","names":[],"sources":["../../src/lib/neonctl.ts"],"mappings":";;AAaA;AAWA;AAQC;AAkDD;;;;AAA6C;AAiD7C;AAqCsB,iBA3JN,UAAA,CAAA,CA2JmB,EAAA,MAAA;;;;AAAW;;;;iBAhJ9B,oBAAA,CAAA;UA6BN,aAAA;;;;;;;;;iBA6BY,YAAA,CAAA,GAAgB,QAAQ;UAiD7B,mBAAA;;;;;;;;;iBAqCK,aAAA,CAAA,GAAiB,QAAQ"}
|
package/dist/lib/neonctl.js
CHANGED
|
@@ -2,15 +2,17 @@ import { lstatSync } from "node:fs";
|
|
|
2
2
|
import { execa } from "execa";
|
|
3
3
|
//#region src/lib/neonctl.ts
|
|
4
4
|
/**
|
|
5
|
-
* Returns the
|
|
5
|
+
* Returns the Neon CLI command prefix: "CI= npx -y neon".
|
|
6
6
|
*
|
|
7
|
-
*
|
|
8
|
-
* directly, so no extra flags are needed.
|
|
7
|
+
* The CLI reads NEON_API_HOST and NEON_OAUTH_HOST from the environment
|
|
8
|
+
* directly, so no extra flags are needed. The `neon` package ships both the
|
|
9
|
+
* `neon` and `neonctl` binaries; we surface the cleaner `neon` command in the
|
|
10
|
+
* examples emitted to users and agents.
|
|
9
11
|
*
|
|
10
12
|
* Usage: `${neonctlCmd()} orgs list --output json`
|
|
11
13
|
*/
|
|
12
14
|
function neonctlCmd() {
|
|
13
|
-
return "CI= npx -y
|
|
15
|
+
return "CI= npx -y neon";
|
|
14
16
|
}
|
|
15
17
|
/**
|
|
16
18
|
* Detects which package manager was used to invoke the current process.
|
package/dist/lib/neonctl.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"neonctl.js","names":[],"sources":["../../src/lib/neonctl.ts"],"sourcesContent":["import { lstatSync } from \"node:fs\";\nimport { execa } from \"execa\";\n\n/**\n * Returns the
|
|
1
|
+
{"version":3,"file":"neonctl.js","names":[],"sources":["../../src/lib/neonctl.ts"],"sourcesContent":["import { lstatSync } from \"node:fs\";\nimport { execa } from \"execa\";\n\n/**\n * Returns the Neon CLI command prefix: \"CI= npx -y neon\".\n *\n * The CLI reads NEON_API_HOST and NEON_OAUTH_HOST from the environment\n * directly, so no extra flags are needed. The `neon` package ships both the\n * `neon` and `neonctl` binaries; we surface the cleaner `neon` command in the\n * examples emitted to users and agents.\n *\n * Usage: `${neonctlCmd()} orgs list --output json`\n */\nexport function neonctlCmd(): string {\n\treturn \"CI= npx -y neon\";\n}\n\n/**\n * Detects which package manager was used to invoke the current process.\n * Reads the `npm_config_user_agent` env var set by npm/pnpm/yarn/bun when\n * they spawn child processes (including via `npx`, `pnpx`, `bunx`, etc.).\n *\n * Falls back to \"npm\" if detection fails.\n */\nexport function detectPackageManager(): \"npm\" | \"pnpm\" | \"yarn\" | \"bun\" {\n\tconst ua = process.env.npm_config_user_agent;\n\tif (ua) {\n\t\tif (ua.startsWith(\"pnpm/\")) return \"pnpm\";\n\t\tif (ua.startsWith(\"yarn/\")) return \"yarn\";\n\t\tif (ua.startsWith(\"bun/\")) return \"bun\";\n\t}\n\treturn \"npm\";\n}\n\n/**\n * Returns the global install command for a given package manager.\n */\nfunction globalInstallArgs(\n\tpm: \"npm\" | \"pnpm\" | \"yarn\" | \"bun\",\n\tpkg: string,\n): { command: string; args: string[] } {\n\tswitch (pm) {\n\t\tcase \"pnpm\":\n\t\t\treturn { command: \"pnpm\", args: [\"add\", \"-g\", pkg] };\n\t\tcase \"yarn\":\n\t\t\treturn { command: \"yarn\", args: [\"global\", \"add\", pkg] };\n\t\tcase \"bun\":\n\t\t\treturn { command: \"bun\", args: [\"add\", \"-g\", pkg] };\n\t\tdefault:\n\t\t\treturn { command: \"npm\", args: [\"install\", \"-g\", pkg] };\n\t}\n}\n\ninterface NeonctlStatus {\n\tinstalled: boolean;\n\tcurrentVersion: string | null;\n\tlatestVersion: string | null;\n\tneedsUpdate: boolean;\n}\n\n/**\n * Gets the currently available neonctl version.\n * Tries the global binary first, then falls back to npx.\n */\nasync function getNeonctlVersion(): Promise<string | null> {\n\t// Try global binary first (fast path)\n\ttry {\n\t\tconst result = await execa(\"neonctl\", [\"--version\"], {\n\t\t\tstdio: \"pipe\",\n\t\t\ttimeout: 5000,\n\t\t});\n\t\tconst match = result.stdout.trim().match(/(\\d+\\.\\d+\\.\\d+)/);\n\t\tif (match) return match[1];\n\t} catch {\n\t\t// Not globally installed — that's fine\n\t}\n\treturn null;\n}\n\n/**\n * Checks whether the neonctl CLI is globally installed and whether it's up to date.\n */\nexport async function checkNeonctl(): Promise<NeonctlStatus> {\n\tconst currentVersion = await getNeonctlVersion();\n\n\tif (!currentVersion) {\n\t\treturn {\n\t\t\tinstalled: false,\n\t\t\tcurrentVersion: null,\n\t\t\tlatestVersion: null,\n\t\t\tneedsUpdate: true,\n\t\t};\n\t}\n\n\t// Check latest version from npm registry\n\tlet latestVersion: string | null = null;\n\ttry {\n\t\tconst result = await execa(\"npm\", [\"view\", \"neonctl\", \"version\"], {\n\t\t\tstdio: \"pipe\",\n\t\t\ttimeout: 10000,\n\t\t});\n\t\tlatestVersion = result.stdout.trim();\n\t} catch {\n\t\t// Can't determine latest — assume current is fine\n\t\treturn {\n\t\t\tinstalled: true,\n\t\t\tcurrentVersion,\n\t\t\tlatestVersion: null,\n\t\t\tneedsUpdate: false,\n\t\t};\n\t}\n\n\tconst needsUpdate =\n\t\tcurrentVersion !== null &&\n\t\tlatestVersion !== null &&\n\t\tcurrentVersion !== latestVersion &&\n\t\tisOlderVersion(currentVersion, latestVersion);\n\n\treturn { installed: true, currentVersion, latestVersion, needsUpdate };\n}\n\nfunction isOlderVersion(current: string, latest: string): boolean {\n\tconst c = current.split(\".\").map(Number);\n\tconst l = latest.split(\".\").map(Number);\n\tfor (let i = 0; i < 3; i++) {\n\t\tif ((c[i] ?? 0) < (l[i] ?? 0)) return true;\n\t\tif ((c[i] ?? 0) > (l[i] ?? 0)) return false;\n\t}\n\treturn false;\n}\n\nexport interface EnsureNeonctlResult {\n\tstatus: \"already_current\" | \"installed\" | \"updated\" | \"failed\";\n\tversion?: string;\n\terror?: string;\n}\n\n/**\n * Checks if neonctl is installed via a local dev symlink.\n * If so, skip install/update — the developer manages it manually.\n */\nfunction isLocalDevSymlink(): boolean {\n\ttry {\n\t\tconst home = process.env.HOME || process.env.USERPROFILE || \"\";\n\t\tconst nvmDir = process.env.NVM_DIR || `${home}/.nvm`;\n\t\t// Check common global module locations for a symlink\n\t\tconst candidates = [\n\t\t\t`${nvmDir}/versions/node/${process.version}/lib/node_modules/neonctl`,\n\t\t\t`${home}/.nvm/versions/node/${process.version}/lib/node_modules/neonctl`,\n\t\t];\n\t\tfor (const candidate of candidates) {\n\t\t\ttry {\n\t\t\t\tconst stat = lstatSync(candidate);\n\t\t\t\tif (stat.isSymbolicLink()) return true;\n\t\t\t} catch {\n\t\t\t\t// path doesn't exist\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t} catch {\n\t\treturn false;\n\t}\n}\n\n/**\n * Ensures neonctl is globally installed and up to date.\n * Uses the same package manager that invoked the init command.\n */\nexport async function ensureNeonctl(): Promise<EnsureNeonctlResult> {\n\t// Skip install for local dev symlinks to avoid permission errors\n\tif (isLocalDevSymlink()) {\n\t\tconst version = await getNeonctlVersion();\n\t\treturn {\n\t\t\tstatus: \"already_current\",\n\t\t\tversion: version ?? \"dev\",\n\t\t};\n\t}\n\n\tconst check = await checkNeonctl();\n\n\tif (check.installed && !check.needsUpdate) {\n\t\treturn {\n\t\t\tstatus: \"already_current\",\n\t\t\tversion: check.currentVersion ?? undefined,\n\t\t};\n\t}\n\n\tconst pm = detectPackageManager();\n\tconst { command, args } = globalInstallArgs(pm, \"neonctl\");\n\n\ttry {\n\t\tawait execa(command, args, { stdio: \"pipe\", timeout: 60000 });\n\n\t\t// Verify installation\n\t\tconst version = await getNeonctlVersion();\n\t\treturn {\n\t\t\tstatus: check.installed ? \"updated\" : \"installed\",\n\t\t\tversion: version ?? undefined,\n\t\t};\n\t} catch (err) {\n\t\treturn {\n\t\t\tstatus: \"failed\",\n\t\t\terror: err instanceof Error ? err.message : \"Unknown error\",\n\t\t};\n\t}\n}\n"],"mappings":"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"}
|
|
@@ -18,7 +18,7 @@ interface GettingStartedPhaseOptions {
|
|
|
18
18
|
*
|
|
19
19
|
* Steps are concrete and executable — each has a CLI command to run
|
|
20
20
|
* or a specific file operation. The agent should attempt each step
|
|
21
|
-
* in order and actually perform the action using the
|
|
21
|
+
* in order and actually perform the action using the Neon CLI.
|
|
22
22
|
*/
|
|
23
23
|
declare function handleGettingStartedPhase(options: GettingStartedPhaseOptions): Promise<PhaseResponse>;
|
|
24
24
|
//#endregion
|
|
@@ -6,7 +6,7 @@ import { SKILL_REFERENCE_URLS, ensureSkillsUpToDate } from "../skills.js";
|
|
|
6
6
|
*
|
|
7
7
|
* Steps are concrete and executable — each has a CLI command to run
|
|
8
8
|
* or a specific file operation. The agent should attempt each step
|
|
9
|
-
* in order and actually perform the action using the
|
|
9
|
+
* in order and actually perform the action using the Neon CLI.
|
|
10
10
|
*/
|
|
11
11
|
async function handleGettingStartedPhase(options) {
|
|
12
12
|
if (options.agent) await ensureSkillsUpToDate(options.agent);
|
|
@@ -79,14 +79,14 @@ async function handleGettingStartedPhase(options) {
|
|
|
79
79
|
description: [
|
|
80
80
|
"Check if node_modules exists in the project root.",
|
|
81
81
|
"If not, install project dependencies using the appropriate package manager (check for pnpm-lock.yaml, yarn.lock, bun.lockb, or default to npm).",
|
|
82
|
-
"This must be done before `
|
|
82
|
+
"This must be done before `neon env pull` because the project's Neon config file may import packages that need to be installed first."
|
|
83
83
|
].join(" "),
|
|
84
84
|
command: "npm install"
|
|
85
85
|
});
|
|
86
86
|
steps.push({
|
|
87
87
|
id: "pull_env",
|
|
88
88
|
description: [
|
|
89
|
-
"Now that the .neon context file is in place and dependencies are installed, run `
|
|
89
|
+
"Now that the .neon context file is in place and dependencies are installed, run `neon env pull` to populate the project's environment variables.",
|
|
90
90
|
"This automatically writes the database connection string (and any other Neon-managed env vars) to the correct env file.",
|
|
91
91
|
"It reads the .neon context file to determine the project, and writes to the appropriate env file for the project.",
|
|
92
92
|
"Ensure the target env file is listed in .gitignore."
|
|
@@ -153,7 +153,7 @@ async function handleGettingStartedPhase(options) {
|
|
|
153
153
|
description: [
|
|
154
154
|
"Verify the database connection works by running a SQL query against the Neon database.",
|
|
155
155
|
"Write and run a short script that connects using DATABASE_URL from the project's env file and executes `SELECT 1` (or queries a table from the migration if migrations were run).",
|
|
156
|
-
"Do NOT use the
|
|
156
|
+
"Do NOT use the Neon CLI or MCP tools for this — use a direct database connection to verify end-to-end connectivity."
|
|
157
157
|
].join(" ")
|
|
158
158
|
});
|
|
159
159
|
return {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getting-started.js","names":[],"sources":["../../../src/lib/phases/getting-started.ts"],"sourcesContent":["import { neonctlCmd } from \"../neonctl.js\";\nimport { ensureSkillsUpToDate, SKILL_REFERENCE_URLS } from \"../skills.js\";\nimport type { PhaseResponse } from \"../types.js\";\n\nexport interface GettingStartedPhaseOptions {\n\tagent?: string;\n\thasConnectionString?: boolean;\n\tframework?: string;\n\torm?: string;\n\tmigrationTool?: string;\n\tmigrationDir?: string;\n\t/** Neon features required by the project (from .neon or template) */\n\tfeatures?: string[];\n\t/** Preview mode — restricts project creation to new projects in AWS us-east */\n\tpreview?: boolean;\n}\n\n/**\n * Initiates the \"Get started with Neon\" workflow.\n *\n * Steps are concrete and executable — each has a CLI command to run\n * or a specific file operation. The agent should attempt each step\n * in order and actually perform the action using the neonctl CLI.\n */\nexport async function handleGettingStartedPhase(\n\toptions: GettingStartedPhaseOptions,\n): Promise<PhaseResponse> {\n\t// Ensure skills are up to date (no-op if recently updated)\n\tif (options.agent) {\n\t\tawait ensureSkillsUpToDate(options.agent);\n\t}\n\tconst steps: { id: string; description: string; command?: string }[] = [];\n\n\tif (!options.hasConnectionString) {\n\t\tif (options.preview) {\n\t\t\t// Preview mode: new project in AWS us-east-2, or existing eligible project\n\t\t\tsteps.push(\n\t\t\t\t{\n\t\t\t\t\tid: \"select_org\",\n\t\t\t\t\tdescription: [\n\t\t\t\t\t\t\"List the user's Neon organizations using the CLI command below.\",\n\t\t\t\t\t\t\"If only one org exists, use it automatically.\",\n\t\t\t\t\t\t\"If multiple orgs exist, ask the user which one to use.\",\n\t\t\t\t\t\t\"Remember the selected org ID for the next steps.\",\n\t\t\t\t\t].join(\" \"),\n\t\t\t\t\tcommand: `${neonctlCmd()} orgs list --output json`,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tid: \"select_or_create_project\",\n\t\t\t\t\tdescription: [\n\t\t\t\t\t\t\"List existing Neon projects in the selected organization using the CLI command below (replace <org-id> with the selected org ID).\",\n\t\t\t\t\t\t\"IMPORTANT: Preview features require a project in the AWS us-east-2 region created on or after 2026-06-15.\",\n\t\t\t\t\t\t\"Filter the project list to ONLY show projects where region_id is 'aws-us-east-2' AND created_at is on or after '2026-06-15'.\",\n\t\t\t\t\t\t\"If eligible projects exist, present them alongside a 'Create new project' option.\",\n\t\t\t\t\t\t\"If no eligible projects exist, tell the user and proceed directly to creating a new one.\",\n\t\t\t\t\t\t\"IMPORTANT: Always include --org-id when creating a project to avoid interactive prompts.\",\n\t\t\t\t\t].join(\" \"),\n\t\t\t\t\tcommand: `${neonctlCmd()} projects list --org-id <org-id> --output json`,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tid: \"create_project_if_needed\",\n\t\t\t\t\tdescription: [\n\t\t\t\t\t\t\"If the user chose to create a new project, create it in the AWS us-east-2 region using the CLI command below (replace <org-id> and <project-name>).\",\n\t\t\t\t\t\t\"Ask the user for a project name (suggest the current directory name).\",\n\t\t\t\t\t\t\"If the user chose an existing eligible project, skip this step.\",\n\t\t\t\t\t].join(\" \"),\n\t\t\t\t\tcommand: `${neonctlCmd()} projects create --name <project-name> --org-id <org-id> --region-id aws-us-east-2 --output json`,\n\t\t\t\t},\n\t\t\t);\n\t\t} else {\n\t\t\t// Standard mode: let user choose existing or create new\n\t\t\tsteps.push(\n\t\t\t\t{\n\t\t\t\t\tid: \"select_org\",\n\t\t\t\t\tdescription: [\n\t\t\t\t\t\t\"List the user's Neon organizations using the CLI command below.\",\n\t\t\t\t\t\t\"If only one org exists, use it automatically.\",\n\t\t\t\t\t\t\"If multiple orgs exist, ask the user which one to use.\",\n\t\t\t\t\t\t\"Remember the selected org ID for the next steps.\",\n\t\t\t\t\t].join(\" \"),\n\t\t\t\t\tcommand: `${neonctlCmd()} orgs list --output json`,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tid: \"select_or_create_project\",\n\t\t\t\t\tdescription: [\n\t\t\t\t\t\t\"List existing Neon projects in the selected organization using the CLI command below (replace <org-id> with the selected org ID).\",\n\t\t\t\t\t\t\"Ask the user whether they want to use an existing project or create a new one.\",\n\t\t\t\t\t\t\"If creating new, ask the user for a project name (suggest the current directory name).\",\n\t\t\t\t\t\t\"IMPORTANT: Always include --org-id when creating a project to avoid interactive prompts.\",\n\t\t\t\t\t].join(\" \"),\n\t\t\t\t\tcommand: `${neonctlCmd()} projects list --org-id <org-id> --output json`,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tid: \"create_project_if_needed\",\n\t\t\t\t\tdescription: [\n\t\t\t\t\t\t\"If the user chose to create a new project, create it using the CLI command below (replace <org-id> and <project-name>).\",\n\t\t\t\t\t\t\"If the user chose an existing project, skip this step.\",\n\t\t\t\t\t].join(\" \"),\n\t\t\t\t\tcommand: `${neonctlCmd()} projects create --name <project-name> --org-id <org-id> --output json`,\n\t\t\t\t},\n\t\t\t);\n\t\t}\n\n\t\t// Create/update .neon context file\n\t\tsteps.push({\n\t\t\tid: \"create_neon_context\",\n\t\t\tdescription: [\n\t\t\t\t\"Update the .neon context file in the project root with the selected org and project IDs.\",\n\t\t\t\t\"IMPORTANT: If a .neon file already exists, you MUST read it first, then merge the new orgId and projectId into the existing content. Do NOT overwrite the file — other fields (like _init, branch, etc.) must be preserved.\",\n\t\t\t\t\"If no .neon file exists, create one.\",\n\t\t\t\t'The file is JSON. Add/update only the orgId and projectId fields: {\"orgId\": \"<org-id>\", \"projectId\": \"<project-id>\", ...existing fields}.',\n\t\t\t\t\"This file is safe to commit — it contains no secrets.\",\n\t\t\t].join(\" \"),\n\t\t});\n\n\t\t// Install project dependencies (required before env pull — config files may import packages)\n\t\tsteps.push({\n\t\t\tid: \"install_dependencies\",\n\t\t\tdescription: [\n\t\t\t\t\"Check if node_modules exists in the project root.\",\n\t\t\t\t\"If not, install project dependencies using the appropriate package manager (check for pnpm-lock.yaml, yarn.lock, bun.lockb, or default to npm).\",\n\t\t\t\t\"This must be done before `neonctl env pull` because the project's Neon config file may import packages that need to be installed first.\",\n\t\t\t].join(\" \"),\n\t\t\tcommand: \"npm install\",\n\t\t});\n\n\t\t// Pull environment variables (connection string, etc.) from Neon\n\t\tsteps.push({\n\t\t\tid: \"pull_env\",\n\t\t\tdescription: [\n\t\t\t\t\"Now that the .neon context file is in place and dependencies are installed, run `neonctl env pull` to populate the project's environment variables.\",\n\t\t\t\t\"This automatically writes the database connection string (and any other Neon-managed env vars) to the correct env file.\",\n\t\t\t\t\"It reads the .neon context file to determine the project, and writes to the appropriate env file for the project.\",\n\t\t\t\t\"Ensure the target env file is listed in .gitignore.\",\n\t\t\t].join(\" \"),\n\t\t\tcommand: `${neonctlCmd()} env pull`,\n\t\t});\n\n\t\t// Step 6: Install Neon serverless driver if needed\n\t\tif (options.orm === \"prisma\") {\n\t\t\tsteps.push({\n\t\t\t\tid: \"install_driver\",\n\t\t\t\tdescription: [\n\t\t\t\t\t\"Install the @neondatabase/serverless driver adapter for Prisma.\",\n\t\t\t\t\t\"This enables Prisma to use Neon's serverless driver for edge/serverless deployments.\",\n\t\t\t\t].join(\" \"),\n\t\t\t\tcommand:\n\t\t\t\t\t\"npm install @neondatabase/serverless @prisma/adapter-neon\",\n\t\t\t});\n\t\t} else if (options.orm === \"drizzle\" || options.orm === \"drizzle-orm\") {\n\t\t\tsteps.push({\n\t\t\t\tid: \"install_driver\",\n\t\t\t\tdescription: \"Install the Neon serverless driver for Drizzle.\",\n\t\t\t\tcommand: \"npm install @neondatabase/serverless\",\n\t\t\t});\n\t\t} else if (!options.orm || options.orm === \"none\") {\n\t\t\tsteps.push({\n\t\t\t\tid: \"install_driver\",\n\t\t\t\tdescription:\n\t\t\t\t\t\"Install the Neon serverless driver for direct database access.\",\n\t\t\t\tcommand: \"npm install @neondatabase/serverless\",\n\t\t\t});\n\t\t}\n\t}\n\n\t// Run migrations if applicable\n\tif (options.migrationTool && options.migrationTool !== \"none\") {\n\t\tconst tool = options.migrationTool.toLowerCase();\n\t\tconst migrationDir = options.migrationDir;\n\t\tconst hasMigrationDir = migrationDir && migrationDir !== \"none\";\n\n\t\tif (tool === \"drizzle\") {\n\t\t\tsteps.push({\n\t\t\t\tid: \"run_migrations\",\n\t\t\t\tdescription: [\n\t\t\t\t\thasMigrationDir\n\t\t\t\t\t\t? `Check if the ${migrationDir} directory contains .sql migration files.`\n\t\t\t\t\t\t: \"Check if a drizzle migrations directory exists with .sql files.\",\n\t\t\t\t\t\"If .sql files exist, apply them with `npx drizzle-kit migrate`.\",\n\t\t\t\t\t\"If the directory is empty or missing but a drizzle schema file exists (e.g. src/db/schema.ts, drizzle/schema.ts), run `npx drizzle-kit generate` first to create migrations, then `npx drizzle-kit migrate` to apply them.\",\n\t\t\t\t\t\"If neither schema nor migrations exist, skip this step.\",\n\t\t\t\t].join(\" \"),\n\t\t\t\tcommand: \"npx drizzle-kit migrate\",\n\t\t\t});\n\t\t} else if (tool === \"prisma\") {\n\t\t\tsteps.push({\n\t\t\t\tid: \"run_migrations\",\n\t\t\t\tdescription: [\n\t\t\t\t\thasMigrationDir\n\t\t\t\t\t\t? `Check if the ${migrationDir} directory contains migration folders.`\n\t\t\t\t\t\t: \"Check if prisma/migrations contains migration folders.\",\n\t\t\t\t\t\"If migrations exist, apply them with `npx prisma migrate deploy`.\",\n\t\t\t\t\t\"If the migrations directory is empty or missing but prisma/schema.prisma has models defined, run `npx prisma migrate dev --name init` to create and apply the initial migration.\",\n\t\t\t\t\t\"If no models are defined, skip this step.\",\n\t\t\t\t].join(\" \"),\n\t\t\t\tcommand: \"npx prisma migrate deploy\",\n\t\t\t});\n\t\t} else if (tool === \"knex\") {\n\t\t\tsteps.push({\n\t\t\t\tid: \"run_migrations\",\n\t\t\t\tdescription: `Apply existing knex migrations to the Neon database.`,\n\t\t\t\tcommand: \"npx knex migrate:latest\",\n\t\t\t});\n\t\t}\n\t} else if (options.preview) {\n\t\t// Bootstrap flow: migration tool wasn't detected because the project was\n\t\t// inspected before scaffolding. Detect and run migrations from the scaffolded template.\n\t\tsteps.push({\n\t\t\tid: \"run_migrations\",\n\t\t\tdescription: [\n\t\t\t\t\"Check the scaffolded project for a migration tool and schema.\",\n\t\t\t\t\"Look for: drizzle.config.ts/js (Drizzle), prisma/schema.prisma (Prisma), or knexfile.ts/js (Knex).\",\n\t\t\t\t\"If Drizzle is found: check if a drizzle migrations directory exists with .sql files. If .sql files exist, run `npx drizzle-kit migrate`. If the directory is empty or missing but a schema file exists, run `npx drizzle-kit generate` first, then `npx drizzle-kit migrate`.\",\n\t\t\t\t\"If Prisma is found: check if prisma/migrations contains migration folders. If yes, run `npx prisma migrate deploy`. If not but models exist, run `npx prisma migrate dev --name init`.\",\n\t\t\t\t\"If no migration tool is found, skip this step.\",\n\t\t\t].join(\" \"),\n\t\t});\n\t}\n\n\t// Verify the connection\n\tsteps.push({\n\t\tid: \"verify_connection\",\n\t\tdescription: [\n\t\t\t\"Verify the database connection works by running a SQL query against the Neon database.\",\n\t\t\t\"Write and run a short script that connects using DATABASE_URL from the project's env file and executes `SELECT 1` (or queries a table from the migration if migrations were run).\",\n\t\t\t\"Do NOT use the neonctl CLI or MCP tools for this — use a direct database connection to verify end-to-end connectivity.\",\n\t\t].join(\" \"),\n\t});\n\n\treturn {\n\t\tphase: \"setup\",\n\t\tstatus: \"getting_started\",\n\t\tnextAction: {\n\t\t\ttype: \"agent_action\",\n\t\t\tprerequisite: SKILL_REFERENCE_URLS.gettingStarted,\n\t\t\tsteps,\n\t\t\tonComplete: buildOnComplete(options),\n\t\t},\n\t};\n}\n\nfunction buildOnComplete(\n\toptions: GettingStartedPhaseOptions,\n): import(\"../types.js\").RunNeonInitAction {\n\tconst agentArgs = options.agent ? [\"--agent\", options.agent] : [];\n\tconst features = options.features ?? [];\n\tconst hasFeatureRequirements = features.length > 0;\n\n\t// If features are specified and auth is not required, go to finalize\n\tif (hasFeatureRequirements && !features.includes(\"auth\")) {\n\t\treturn {\n\t\t\ttype: \"run_neon_init\",\n\t\t\targs: [\"finalize\", \"--json\", ...agentArgs],\n\t\t};\n\t}\n\n\t// Chain to neon-auth — if user already selected auth via features, go straight to setup\n\tconst authSetup =\n\t\thasFeatureRequirements && features.includes(\"auth\") ? [\"--setup\"] : [];\n\treturn {\n\t\ttype: \"run_neon_init\",\n\t\targs: [\"neon-auth\", \"--json\", ...agentArgs, ...authSetup],\n\t};\n}\n"],"mappings":";;;;;;;;;;AAwBA,eAAsB,0BACrB,SACyB;CAEzB,IAAI,QAAQ,OACX,MAAM,qBAAqB,QAAQ,KAAK;CAEzC,MAAM,QAAiE,CAAC;CAExE,IAAI,CAAC,QAAQ,qBAAqB;EACjC,IAAI,QAAQ,SAEX,MAAM,KACL;GACC,IAAI;GACJ,aAAa;IACZ;IACA;IACA;IACA;GACD,CAAC,CAAC,KAAK,GAAG;GACV,SAAS,GAAG,WAAW,EAAE;EAC1B,GACA;GACC,IAAI;GACJ,aAAa;IACZ;IACA;IACA;IACA;IACA;IACA;GACD,CAAC,CAAC,KAAK,GAAG;GACV,SAAS,GAAG,WAAW,EAAE;EAC1B,GACA;GACC,IAAI;GACJ,aAAa;IACZ;IACA;IACA;GACD,CAAC,CAAC,KAAK,GAAG;GACV,SAAS,GAAG,WAAW,EAAE;EAC1B,CACD;OAGA,MAAM,KACL;GACC,IAAI;GACJ,aAAa;IACZ;IACA;IACA;IACA;GACD,CAAC,CAAC,KAAK,GAAG;GACV,SAAS,GAAG,WAAW,EAAE;EAC1B,GACA;GACC,IAAI;GACJ,aAAa;IACZ;IACA;IACA;IACA;GACD,CAAC,CAAC,KAAK,GAAG;GACV,SAAS,GAAG,WAAW,EAAE;EAC1B,GACA;GACC,IAAI;GACJ,aAAa,CACZ,2HACA,wDACD,CAAC,CAAC,KAAK,GAAG;GACV,SAAS,GAAG,WAAW,EAAE;EAC1B,CACD;EAID,MAAM,KAAK;GACV,IAAI;GACJ,aAAa;IACZ;IACA;IACA;IACA;IACA;GACD,CAAC,CAAC,KAAK,GAAG;EACX,CAAC;EAGD,MAAM,KAAK;GACV,IAAI;GACJ,aAAa;IACZ;IACA;IACA;GACD,CAAC,CAAC,KAAK,GAAG;GACV,SAAS;EACV,CAAC;EAGD,MAAM,KAAK;GACV,IAAI;GACJ,aAAa;IACZ;IACA;IACA;IACA;GACD,CAAC,CAAC,KAAK,GAAG;GACV,SAAS,GAAG,WAAW,EAAE;EAC1B,CAAC;EAGD,IAAI,QAAQ,QAAQ,UACnB,MAAM,KAAK;GACV,IAAI;GACJ,aAAa,CACZ,mEACA,sFACD,CAAC,CAAC,KAAK,GAAG;GACV,SACC;EACF,CAAC;OACK,IAAI,QAAQ,QAAQ,aAAa,QAAQ,QAAQ,eACvD,MAAM,KAAK;GACV,IAAI;GACJ,aAAa;GACb,SAAS;EACV,CAAC;OACK,IAAI,CAAC,QAAQ,OAAO,QAAQ,QAAQ,QAC1C,MAAM,KAAK;GACV,IAAI;GACJ,aACC;GACD,SAAS;EACV,CAAC;CAEH;CAGA,IAAI,QAAQ,iBAAiB,QAAQ,kBAAkB,QAAQ;EAC9D,MAAM,OAAO,QAAQ,cAAc,YAAY;EAC/C,MAAM,eAAe,QAAQ;EAC7B,MAAM,kBAAkB,gBAAgB,iBAAiB;EAEzD,IAAI,SAAS,WACZ,MAAM,KAAK;GACV,IAAI;GACJ,aAAa;IACZ,kBACG,gBAAgB,aAAa,6CAC7B;IACH;IACA;IACA;GACD,CAAC,CAAC,KAAK,GAAG;GACV,SAAS;EACV,CAAC;OACK,IAAI,SAAS,UACnB,MAAM,KAAK;GACV,IAAI;GACJ,aAAa;IACZ,kBACG,gBAAgB,aAAa,0CAC7B;IACH;IACA;IACA;GACD,CAAC,CAAC,KAAK,GAAG;GACV,SAAS;EACV,CAAC;OACK,IAAI,SAAS,QACnB,MAAM,KAAK;GACV,IAAI;GACJ,aAAa;GACb,SAAS;EACV,CAAC;CAEH,OAAO,IAAI,QAAQ,SAGlB,MAAM,KAAK;EACV,IAAI;EACJ,aAAa;GACZ;GACA;GACA;GACA;GACA;EACD,CAAC,CAAC,KAAK,GAAG;CACX,CAAC;CAIF,MAAM,KAAK;EACV,IAAI;EACJ,aAAa;GACZ;GACA;GACA;EACD,CAAC,CAAC,KAAK,GAAG;CACX,CAAC;CAED,OAAO;EACN,OAAO;EACP,QAAQ;EACR,YAAY;GACX,MAAM;GACN,cAAc,qBAAqB;GACnC;GACA,YAAY,gBAAgB,OAAO;EACpC;CACD;AACD;AAEA,SAAS,gBACR,SAC0C;CAC1C,MAAM,YAAY,QAAQ,QAAQ,CAAC,WAAW,QAAQ,KAAK,IAAI,CAAC;CAChE,MAAM,WAAW,QAAQ,YAAY,CAAC;CACtC,MAAM,yBAAyB,SAAS,SAAS;CAGjD,IAAI,0BAA0B,CAAC,SAAS,SAAS,MAAM,GACtD,OAAO;EACN,MAAM;EACN,MAAM;GAAC;GAAY;GAAU,GAAG;EAAS;CAC1C;CAID,MAAM,YACL,0BAA0B,SAAS,SAAS,MAAM,IAAI,CAAC,SAAS,IAAI,CAAC;CACtE,OAAO;EACN,MAAM;EACN,MAAM;GAAC;GAAa;GAAU,GAAG;GAAW,GAAG;EAAS;CACzD;AACD"}
|
|
1
|
+
{"version":3,"file":"getting-started.js","names":[],"sources":["../../../src/lib/phases/getting-started.ts"],"sourcesContent":["import { neonctlCmd } from \"../neonctl.js\";\nimport { ensureSkillsUpToDate, SKILL_REFERENCE_URLS } from \"../skills.js\";\nimport type { PhaseResponse } from \"../types.js\";\n\nexport interface GettingStartedPhaseOptions {\n\tagent?: string;\n\thasConnectionString?: boolean;\n\tframework?: string;\n\torm?: string;\n\tmigrationTool?: string;\n\tmigrationDir?: string;\n\t/** Neon features required by the project (from .neon or template) */\n\tfeatures?: string[];\n\t/** Preview mode — restricts project creation to new projects in AWS us-east */\n\tpreview?: boolean;\n}\n\n/**\n * Initiates the \"Get started with Neon\" workflow.\n *\n * Steps are concrete and executable — each has a CLI command to run\n * or a specific file operation. The agent should attempt each step\n * in order and actually perform the action using the Neon CLI.\n */\nexport async function handleGettingStartedPhase(\n\toptions: GettingStartedPhaseOptions,\n): Promise<PhaseResponse> {\n\t// Ensure skills are up to date (no-op if recently updated)\n\tif (options.agent) {\n\t\tawait ensureSkillsUpToDate(options.agent);\n\t}\n\tconst steps: { id: string; description: string; command?: string }[] = [];\n\n\tif (!options.hasConnectionString) {\n\t\tif (options.preview) {\n\t\t\t// Preview mode: new project in AWS us-east-2, or existing eligible project\n\t\t\tsteps.push(\n\t\t\t\t{\n\t\t\t\t\tid: \"select_org\",\n\t\t\t\t\tdescription: [\n\t\t\t\t\t\t\"List the user's Neon organizations using the CLI command below.\",\n\t\t\t\t\t\t\"If only one org exists, use it automatically.\",\n\t\t\t\t\t\t\"If multiple orgs exist, ask the user which one to use.\",\n\t\t\t\t\t\t\"Remember the selected org ID for the next steps.\",\n\t\t\t\t\t].join(\" \"),\n\t\t\t\t\tcommand: `${neonctlCmd()} orgs list --output json`,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tid: \"select_or_create_project\",\n\t\t\t\t\tdescription: [\n\t\t\t\t\t\t\"List existing Neon projects in the selected organization using the CLI command below (replace <org-id> with the selected org ID).\",\n\t\t\t\t\t\t\"IMPORTANT: Preview features require a project in the AWS us-east-2 region created on or after 2026-06-15.\",\n\t\t\t\t\t\t\"Filter the project list to ONLY show projects where region_id is 'aws-us-east-2' AND created_at is on or after '2026-06-15'.\",\n\t\t\t\t\t\t\"If eligible projects exist, present them alongside a 'Create new project' option.\",\n\t\t\t\t\t\t\"If no eligible projects exist, tell the user and proceed directly to creating a new one.\",\n\t\t\t\t\t\t\"IMPORTANT: Always include --org-id when creating a project to avoid interactive prompts.\",\n\t\t\t\t\t].join(\" \"),\n\t\t\t\t\tcommand: `${neonctlCmd()} projects list --org-id <org-id> --output json`,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tid: \"create_project_if_needed\",\n\t\t\t\t\tdescription: [\n\t\t\t\t\t\t\"If the user chose to create a new project, create it in the AWS us-east-2 region using the CLI command below (replace <org-id> and <project-name>).\",\n\t\t\t\t\t\t\"Ask the user for a project name (suggest the current directory name).\",\n\t\t\t\t\t\t\"If the user chose an existing eligible project, skip this step.\",\n\t\t\t\t\t].join(\" \"),\n\t\t\t\t\tcommand: `${neonctlCmd()} projects create --name <project-name> --org-id <org-id> --region-id aws-us-east-2 --output json`,\n\t\t\t\t},\n\t\t\t);\n\t\t} else {\n\t\t\t// Standard mode: let user choose existing or create new\n\t\t\tsteps.push(\n\t\t\t\t{\n\t\t\t\t\tid: \"select_org\",\n\t\t\t\t\tdescription: [\n\t\t\t\t\t\t\"List the user's Neon organizations using the CLI command below.\",\n\t\t\t\t\t\t\"If only one org exists, use it automatically.\",\n\t\t\t\t\t\t\"If multiple orgs exist, ask the user which one to use.\",\n\t\t\t\t\t\t\"Remember the selected org ID for the next steps.\",\n\t\t\t\t\t].join(\" \"),\n\t\t\t\t\tcommand: `${neonctlCmd()} orgs list --output json`,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tid: \"select_or_create_project\",\n\t\t\t\t\tdescription: [\n\t\t\t\t\t\t\"List existing Neon projects in the selected organization using the CLI command below (replace <org-id> with the selected org ID).\",\n\t\t\t\t\t\t\"Ask the user whether they want to use an existing project or create a new one.\",\n\t\t\t\t\t\t\"If creating new, ask the user for a project name (suggest the current directory name).\",\n\t\t\t\t\t\t\"IMPORTANT: Always include --org-id when creating a project to avoid interactive prompts.\",\n\t\t\t\t\t].join(\" \"),\n\t\t\t\t\tcommand: `${neonctlCmd()} projects list --org-id <org-id> --output json`,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tid: \"create_project_if_needed\",\n\t\t\t\t\tdescription: [\n\t\t\t\t\t\t\"If the user chose to create a new project, create it using the CLI command below (replace <org-id> and <project-name>).\",\n\t\t\t\t\t\t\"If the user chose an existing project, skip this step.\",\n\t\t\t\t\t].join(\" \"),\n\t\t\t\t\tcommand: `${neonctlCmd()} projects create --name <project-name> --org-id <org-id> --output json`,\n\t\t\t\t},\n\t\t\t);\n\t\t}\n\n\t\t// Create/update .neon context file\n\t\tsteps.push({\n\t\t\tid: \"create_neon_context\",\n\t\t\tdescription: [\n\t\t\t\t\"Update the .neon context file in the project root with the selected org and project IDs.\",\n\t\t\t\t\"IMPORTANT: If a .neon file already exists, you MUST read it first, then merge the new orgId and projectId into the existing content. Do NOT overwrite the file — other fields (like _init, branch, etc.) must be preserved.\",\n\t\t\t\t\"If no .neon file exists, create one.\",\n\t\t\t\t'The file is JSON. Add/update only the orgId and projectId fields: {\"orgId\": \"<org-id>\", \"projectId\": \"<project-id>\", ...existing fields}.',\n\t\t\t\t\"This file is safe to commit — it contains no secrets.\",\n\t\t\t].join(\" \"),\n\t\t});\n\n\t\t// Install project dependencies (required before env pull — config files may import packages)\n\t\tsteps.push({\n\t\t\tid: \"install_dependencies\",\n\t\t\tdescription: [\n\t\t\t\t\"Check if node_modules exists in the project root.\",\n\t\t\t\t\"If not, install project dependencies using the appropriate package manager (check for pnpm-lock.yaml, yarn.lock, bun.lockb, or default to npm).\",\n\t\t\t\t\"This must be done before `neon env pull` because the project's Neon config file may import packages that need to be installed first.\",\n\t\t\t].join(\" \"),\n\t\t\tcommand: \"npm install\",\n\t\t});\n\n\t\t// Pull environment variables (connection string, etc.) from Neon\n\t\tsteps.push({\n\t\t\tid: \"pull_env\",\n\t\t\tdescription: [\n\t\t\t\t\"Now that the .neon context file is in place and dependencies are installed, run `neon env pull` to populate the project's environment variables.\",\n\t\t\t\t\"This automatically writes the database connection string (and any other Neon-managed env vars) to the correct env file.\",\n\t\t\t\t\"It reads the .neon context file to determine the project, and writes to the appropriate env file for the project.\",\n\t\t\t\t\"Ensure the target env file is listed in .gitignore.\",\n\t\t\t].join(\" \"),\n\t\t\tcommand: `${neonctlCmd()} env pull`,\n\t\t});\n\n\t\t// Step 6: Install Neon serverless driver if needed\n\t\tif (options.orm === \"prisma\") {\n\t\t\tsteps.push({\n\t\t\t\tid: \"install_driver\",\n\t\t\t\tdescription: [\n\t\t\t\t\t\"Install the @neondatabase/serverless driver adapter for Prisma.\",\n\t\t\t\t\t\"This enables Prisma to use Neon's serverless driver for edge/serverless deployments.\",\n\t\t\t\t].join(\" \"),\n\t\t\t\tcommand:\n\t\t\t\t\t\"npm install @neondatabase/serverless @prisma/adapter-neon\",\n\t\t\t});\n\t\t} else if (options.orm === \"drizzle\" || options.orm === \"drizzle-orm\") {\n\t\t\tsteps.push({\n\t\t\t\tid: \"install_driver\",\n\t\t\t\tdescription: \"Install the Neon serverless driver for Drizzle.\",\n\t\t\t\tcommand: \"npm install @neondatabase/serverless\",\n\t\t\t});\n\t\t} else if (!options.orm || options.orm === \"none\") {\n\t\t\tsteps.push({\n\t\t\t\tid: \"install_driver\",\n\t\t\t\tdescription:\n\t\t\t\t\t\"Install the Neon serverless driver for direct database access.\",\n\t\t\t\tcommand: \"npm install @neondatabase/serverless\",\n\t\t\t});\n\t\t}\n\t}\n\n\t// Run migrations if applicable\n\tif (options.migrationTool && options.migrationTool !== \"none\") {\n\t\tconst tool = options.migrationTool.toLowerCase();\n\t\tconst migrationDir = options.migrationDir;\n\t\tconst hasMigrationDir = migrationDir && migrationDir !== \"none\";\n\n\t\tif (tool === \"drizzle\") {\n\t\t\tsteps.push({\n\t\t\t\tid: \"run_migrations\",\n\t\t\t\tdescription: [\n\t\t\t\t\thasMigrationDir\n\t\t\t\t\t\t? `Check if the ${migrationDir} directory contains .sql migration files.`\n\t\t\t\t\t\t: \"Check if a drizzle migrations directory exists with .sql files.\",\n\t\t\t\t\t\"If .sql files exist, apply them with `npx drizzle-kit migrate`.\",\n\t\t\t\t\t\"If the directory is empty or missing but a drizzle schema file exists (e.g. src/db/schema.ts, drizzle/schema.ts), run `npx drizzle-kit generate` first to create migrations, then `npx drizzle-kit migrate` to apply them.\",\n\t\t\t\t\t\"If neither schema nor migrations exist, skip this step.\",\n\t\t\t\t].join(\" \"),\n\t\t\t\tcommand: \"npx drizzle-kit migrate\",\n\t\t\t});\n\t\t} else if (tool === \"prisma\") {\n\t\t\tsteps.push({\n\t\t\t\tid: \"run_migrations\",\n\t\t\t\tdescription: [\n\t\t\t\t\thasMigrationDir\n\t\t\t\t\t\t? `Check if the ${migrationDir} directory contains migration folders.`\n\t\t\t\t\t\t: \"Check if prisma/migrations contains migration folders.\",\n\t\t\t\t\t\"If migrations exist, apply them with `npx prisma migrate deploy`.\",\n\t\t\t\t\t\"If the migrations directory is empty or missing but prisma/schema.prisma has models defined, run `npx prisma migrate dev --name init` to create and apply the initial migration.\",\n\t\t\t\t\t\"If no models are defined, skip this step.\",\n\t\t\t\t].join(\" \"),\n\t\t\t\tcommand: \"npx prisma migrate deploy\",\n\t\t\t});\n\t\t} else if (tool === \"knex\") {\n\t\t\tsteps.push({\n\t\t\t\tid: \"run_migrations\",\n\t\t\t\tdescription: `Apply existing knex migrations to the Neon database.`,\n\t\t\t\tcommand: \"npx knex migrate:latest\",\n\t\t\t});\n\t\t}\n\t} else if (options.preview) {\n\t\t// Bootstrap flow: migration tool wasn't detected because the project was\n\t\t// inspected before scaffolding. Detect and run migrations from the scaffolded template.\n\t\tsteps.push({\n\t\t\tid: \"run_migrations\",\n\t\t\tdescription: [\n\t\t\t\t\"Check the scaffolded project for a migration tool and schema.\",\n\t\t\t\t\"Look for: drizzle.config.ts/js (Drizzle), prisma/schema.prisma (Prisma), or knexfile.ts/js (Knex).\",\n\t\t\t\t\"If Drizzle is found: check if a drizzle migrations directory exists with .sql files. If .sql files exist, run `npx drizzle-kit migrate`. If the directory is empty or missing but a schema file exists, run `npx drizzle-kit generate` first, then `npx drizzle-kit migrate`.\",\n\t\t\t\t\"If Prisma is found: check if prisma/migrations contains migration folders. If yes, run `npx prisma migrate deploy`. If not but models exist, run `npx prisma migrate dev --name init`.\",\n\t\t\t\t\"If no migration tool is found, skip this step.\",\n\t\t\t].join(\" \"),\n\t\t});\n\t}\n\n\t// Verify the connection\n\tsteps.push({\n\t\tid: \"verify_connection\",\n\t\tdescription: [\n\t\t\t\"Verify the database connection works by running a SQL query against the Neon database.\",\n\t\t\t\"Write and run a short script that connects using DATABASE_URL from the project's env file and executes `SELECT 1` (or queries a table from the migration if migrations were run).\",\n\t\t\t\"Do NOT use the Neon CLI or MCP tools for this — use a direct database connection to verify end-to-end connectivity.\",\n\t\t].join(\" \"),\n\t});\n\n\treturn {\n\t\tphase: \"setup\",\n\t\tstatus: \"getting_started\",\n\t\tnextAction: {\n\t\t\ttype: \"agent_action\",\n\t\t\tprerequisite: SKILL_REFERENCE_URLS.gettingStarted,\n\t\t\tsteps,\n\t\t\tonComplete: buildOnComplete(options),\n\t\t},\n\t};\n}\n\nfunction buildOnComplete(\n\toptions: GettingStartedPhaseOptions,\n): import(\"../types.js\").RunNeonInitAction {\n\tconst agentArgs = options.agent ? [\"--agent\", options.agent] : [];\n\tconst features = options.features ?? [];\n\tconst hasFeatureRequirements = features.length > 0;\n\n\t// If features are specified and auth is not required, go to finalize\n\tif (hasFeatureRequirements && !features.includes(\"auth\")) {\n\t\treturn {\n\t\t\ttype: \"run_neon_init\",\n\t\t\targs: [\"finalize\", \"--json\", ...agentArgs],\n\t\t};\n\t}\n\n\t// Chain to neon-auth — if user already selected auth via features, go straight to setup\n\tconst authSetup =\n\t\thasFeatureRequirements && features.includes(\"auth\") ? [\"--setup\"] : [];\n\treturn {\n\t\ttype: \"run_neon_init\",\n\t\targs: [\"neon-auth\", \"--json\", ...agentArgs, ...authSetup],\n\t};\n}\n"],"mappings":"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"}
|
|
@@ -43,7 +43,7 @@ async function handleNeonAuthPhase(options) {
|
|
|
43
43
|
steps: [
|
|
44
44
|
{
|
|
45
45
|
id: "provision",
|
|
46
|
-
description: `Enable Neon Auth on the project using the
|
|
46
|
+
description: `Enable Neon Auth on the project using the Neon CLI. Run: \`${neonctlCmd()} neon-auth enable --project-id <project-id> --output json\`. You can check current status with: \`${neonctlCmd()} neon-auth status --project-id <project-id> --output json\`.` + (options.projectId ? ` Project ID: ${options.projectId}.` : " Determine the project ID from the .neon file in the project root, or from the DATABASE_URL in .env, or ask the user.")
|
|
47
47
|
},
|
|
48
48
|
{
|
|
49
49
|
id: "install_packages",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"neon-auth.js","names":[],"sources":["../../../src/lib/phases/neon-auth.ts"],"sourcesContent":["import { neonctlCmd } from \"../neonctl.js\";\nimport { ensureSkillsUpToDate, SKILL_REFERENCE_URLS } from \"../skills.js\";\nimport type { PhaseResponse } from \"../types.js\";\n\nexport interface NeonAuthPhaseOptions {\n\tagent?: string;\n\tsetup?: boolean;\n\tinfo?: boolean;\n\tprojectId?: string;\n}\n\nexport async function handleNeonAuthPhase(\n\toptions: NeonAuthPhaseOptions,\n): Promise<PhaseResponse> {\n\t// Validate IDs that may be interpolated into instruction strings\n\tif (options.projectId && !/^[\\w.:-]+$/.test(options.projectId)) {\n\t\tthrow new Error(\n\t\t\t`Invalid project ID: \"${options.projectId}\". Expected alphanumeric, hyphens, underscores, dots, or colons.`,\n\t\t);\n\t}\n\n\t// Ensure skills are up to date (no-op if recently updated)\n\tif (options.agent) {\n\t\tawait ensureSkillsUpToDate(options.agent);\n\t}\n\t// --info: return information about Neon Auth\n\tif (options.info) {\n\t\treturn {\n\t\t\tphase: \"neon_auth\",\n\t\t\tstatus: \"info\",\n\t\t\tnextAction: {\n\t\t\t\ttype: \"ask_user\",\n\t\t\t\tquestion:\n\t\t\t\t\t\"Neon Auth provides drop-in user authentication that integrates with your Neon database. It handles user sign-up, sign-in, and session management. Would you like to set it up?\",\n\t\t\t\toptions: [\n\t\t\t\t\t{ value: \"yes\", label: \"Yes, set up Neon Auth\" },\n\t\t\t\t\t{ value: \"no\", label: \"No, skip for now\" },\n\t\t\t\t],\n\t\t\t\tcontext: `Full documentation: ${SKILL_REFERENCE_URLS.neonAuth}`,\n\t\t\t\tresponseMapping: {\n\t\t\t\t\tyes: {\n\t\t\t\t\t\targs: [\n\t\t\t\t\t\t\t\"neon-auth\",\n\t\t\t\t\t\t\t\"--json\",\n\t\t\t\t\t\t\t...(options.agent\n\t\t\t\t\t\t\t\t? [\"--agent\", options.agent]\n\t\t\t\t\t\t\t\t: []),\n\t\t\t\t\t\t\t\"--setup\",\n\t\t\t\t\t\t\t...(options.projectId\n\t\t\t\t\t\t\t\t? [\"--project-id\", options.projectId]\n\t\t\t\t\t\t\t\t: []),\n\t\t\t\t\t\t],\n\t\t\t\t\t},\n\t\t\t\t\tno: {\n\t\t\t\t\t\targs: [\n\t\t\t\t\t\t\t\"finalize\",\n\t\t\t\t\t\t\t\"--json\",\n\t\t\t\t\t\t\t...(options.agent\n\t\t\t\t\t\t\t\t? [\"--agent\", options.agent]\n\t\t\t\t\t\t\t\t: []),\n\t\t\t\t\t\t],\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t};\n\t}\n\n\t// --setup: guide through Neon Auth configuration\n\tif (options.setup) {\n\t\treturn {\n\t\t\tphase: \"neon_auth\",\n\t\t\tstatus: \"in_progress\",\n\t\t\tnextAction: {\n\t\t\t\ttype: \"agent_action\",\n\t\t\t\tprerequisite: SKILL_REFERENCE_URLS.neonAuth,\n\t\t\t\tsteps: [\n\t\t\t\t\t{\n\t\t\t\t\t\tid: \"provision\",\n\t\t\t\t\t\tdescription:\n\t\t\t\t\t\t\t\"Enable Neon Auth on the project using the
|
|
1
|
+
{"version":3,"file":"neon-auth.js","names":[],"sources":["../../../src/lib/phases/neon-auth.ts"],"sourcesContent":["import { neonctlCmd } from \"../neonctl.js\";\nimport { ensureSkillsUpToDate, SKILL_REFERENCE_URLS } from \"../skills.js\";\nimport type { PhaseResponse } from \"../types.js\";\n\nexport interface NeonAuthPhaseOptions {\n\tagent?: string;\n\tsetup?: boolean;\n\tinfo?: boolean;\n\tprojectId?: string;\n}\n\nexport async function handleNeonAuthPhase(\n\toptions: NeonAuthPhaseOptions,\n): Promise<PhaseResponse> {\n\t// Validate IDs that may be interpolated into instruction strings\n\tif (options.projectId && !/^[\\w.:-]+$/.test(options.projectId)) {\n\t\tthrow new Error(\n\t\t\t`Invalid project ID: \"${options.projectId}\". Expected alphanumeric, hyphens, underscores, dots, or colons.`,\n\t\t);\n\t}\n\n\t// Ensure skills are up to date (no-op if recently updated)\n\tif (options.agent) {\n\t\tawait ensureSkillsUpToDate(options.agent);\n\t}\n\t// --info: return information about Neon Auth\n\tif (options.info) {\n\t\treturn {\n\t\t\tphase: \"neon_auth\",\n\t\t\tstatus: \"info\",\n\t\t\tnextAction: {\n\t\t\t\ttype: \"ask_user\",\n\t\t\t\tquestion:\n\t\t\t\t\t\"Neon Auth provides drop-in user authentication that integrates with your Neon database. It handles user sign-up, sign-in, and session management. Would you like to set it up?\",\n\t\t\t\toptions: [\n\t\t\t\t\t{ value: \"yes\", label: \"Yes, set up Neon Auth\" },\n\t\t\t\t\t{ value: \"no\", label: \"No, skip for now\" },\n\t\t\t\t],\n\t\t\t\tcontext: `Full documentation: ${SKILL_REFERENCE_URLS.neonAuth}`,\n\t\t\t\tresponseMapping: {\n\t\t\t\t\tyes: {\n\t\t\t\t\t\targs: [\n\t\t\t\t\t\t\t\"neon-auth\",\n\t\t\t\t\t\t\t\"--json\",\n\t\t\t\t\t\t\t...(options.agent\n\t\t\t\t\t\t\t\t? [\"--agent\", options.agent]\n\t\t\t\t\t\t\t\t: []),\n\t\t\t\t\t\t\t\"--setup\",\n\t\t\t\t\t\t\t...(options.projectId\n\t\t\t\t\t\t\t\t? [\"--project-id\", options.projectId]\n\t\t\t\t\t\t\t\t: []),\n\t\t\t\t\t\t],\n\t\t\t\t\t},\n\t\t\t\t\tno: {\n\t\t\t\t\t\targs: [\n\t\t\t\t\t\t\t\"finalize\",\n\t\t\t\t\t\t\t\"--json\",\n\t\t\t\t\t\t\t...(options.agent\n\t\t\t\t\t\t\t\t? [\"--agent\", options.agent]\n\t\t\t\t\t\t\t\t: []),\n\t\t\t\t\t\t],\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t};\n\t}\n\n\t// --setup: guide through Neon Auth configuration\n\tif (options.setup) {\n\t\treturn {\n\t\t\tphase: \"neon_auth\",\n\t\t\tstatus: \"in_progress\",\n\t\t\tnextAction: {\n\t\t\t\ttype: \"agent_action\",\n\t\t\t\tprerequisite: SKILL_REFERENCE_URLS.neonAuth,\n\t\t\t\tsteps: [\n\t\t\t\t\t{\n\t\t\t\t\t\tid: \"provision\",\n\t\t\t\t\t\tdescription:\n\t\t\t\t\t\t\t\"Enable Neon Auth on the project using the Neon CLI. \" +\n\t\t\t\t\t\t\t`Run: \\`${neonctlCmd()} neon-auth enable --project-id <project-id> --output json\\`. ` +\n\t\t\t\t\t\t\t`You can check current status with: \\`${neonctlCmd()} neon-auth status --project-id <project-id> --output json\\`.` +\n\t\t\t\t\t\t\t(options.projectId\n\t\t\t\t\t\t\t\t? ` Project ID: ${options.projectId}.`\n\t\t\t\t\t\t\t\t: \" Determine the project ID from the .neon file in the project root, or from the DATABASE_URL in .env, or ask the user.\"),\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tid: \"install_packages\",\n\t\t\t\t\t\tdescription:\n\t\t\t\t\t\t\t\"Install required packages per the skill reference. The exact packages depend on the framework (Next.js, React, etc.).\",\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tid: \"create_components\",\n\t\t\t\t\t\tdescription:\n\t\t\t\t\t\t\t\"Create auth components per the skill reference. Follow the exact patterns and imports specified.\",\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tid: \"pull_env\",\n\t\t\t\t\t\tdescription: `Run \\`${neonctlCmd()} env pull\\` to populate the NEON_AUTH_BASE_URL, NEON_AUTH_JWKS_URL, and other Neon Auth environment variables. This reads the .neon context file and writes the auth URLs to the project's env file.`,\n\t\t\t\t\t\tcommand: `${neonctlCmd()} env pull`,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t\tonComplete: {\n\t\t\t\t\ttype: \"run_neon_init\",\n\t\t\t\t\targs: [\n\t\t\t\t\t\t\"finalize\",\n\t\t\t\t\t\t\"--json\",\n\t\t\t\t\t\t...(options.agent ? [\"--agent\", options.agent] : []),\n\t\t\t\t\t],\n\t\t\t\t},\n\t\t\t},\n\t\t};\n\t}\n\n\t// Default: ask if they want Neon Auth\n\treturn {\n\t\tphase: \"neon_auth\",\n\t\tstatus: \"optional\",\n\t\tnextAction: {\n\t\t\ttype: \"ask_user\",\n\t\t\tquestion:\n\t\t\t\t\"Would you like to set up Neon Auth for user authentication in your app?\",\n\t\t\toptions: [\n\t\t\t\t{ value: \"yes\", label: \"Yes, set up Neon Auth\" },\n\t\t\t\t{ value: \"no\", label: \"No, skip for now\" },\n\t\t\t\t{ value: \"info\", label: \"Tell me more about Neon Auth\" },\n\t\t\t],\n\t\t\tcontext:\n\t\t\t\t\"Neon Auth provides drop-in user authentication that integrates with your Neon database.\",\n\t\t\tresponseMapping: {\n\t\t\t\tyes: {\n\t\t\t\t\targs: [\n\t\t\t\t\t\t\"neon-auth\",\n\t\t\t\t\t\t\"--json\",\n\t\t\t\t\t\t...(options.agent ? [\"--agent\", options.agent] : []),\n\t\t\t\t\t\t\"--setup\",\n\t\t\t\t\t],\n\t\t\t\t},\n\t\t\t\tno: {\n\t\t\t\t\targs: [\n\t\t\t\t\t\t\"finalize\",\n\t\t\t\t\t\t\"--json\",\n\t\t\t\t\t\t...(options.agent ? [\"--agent\", options.agent] : []),\n\t\t\t\t\t],\n\t\t\t\t},\n\t\t\t\tinfo: {\n\t\t\t\t\targs: [\n\t\t\t\t\t\t\"neon-auth\",\n\t\t\t\t\t\t\"--json\",\n\t\t\t\t\t\t...(options.agent ? [\"--agent\", options.agent] : []),\n\t\t\t\t\t\t\"--info\",\n\t\t\t\t\t],\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t};\n}\n"],"mappings":";;;AAWA,eAAsB,oBACrB,SACyB;CAEzB,IAAI,QAAQ,aAAa,CAAC,aAAa,KAAK,QAAQ,SAAS,GAC5D,MAAM,IAAI,MACT,wBAAwB,QAAQ,UAAU,iEAC3C;CAID,IAAI,QAAQ,OACX,MAAM,qBAAqB,QAAQ,KAAK;CAGzC,IAAI,QAAQ,MACX,OAAO;EACN,OAAO;EACP,QAAQ;EACR,YAAY;GACX,MAAM;GACN,UACC;GACD,SAAS,CACR;IAAE,OAAO;IAAO,OAAO;GAAwB,GAC/C;IAAE,OAAO;IAAM,OAAO;GAAmB,CAC1C;GACA,SAAS,uBAAuB,qBAAqB;GACrD,iBAAiB;IAChB,KAAK,EACJ,MAAM;KACL;KACA;KACA,GAAI,QAAQ,QACT,CAAC,WAAW,QAAQ,KAAK,IACzB,CAAC;KACJ;KACA,GAAI,QAAQ,YACT,CAAC,gBAAgB,QAAQ,SAAS,IAClC,CAAC;IACL,EACD;IACA,IAAI,EACH,MAAM;KACL;KACA;KACA,GAAI,QAAQ,QACT,CAAC,WAAW,QAAQ,KAAK,IACzB,CAAC;IACL,EACD;GACD;EACD;CACD;CAID,IAAI,QAAQ,OACX,OAAO;EACN,OAAO;EACP,QAAQ;EACR,YAAY;GACX,MAAM;GACN,cAAc,qBAAqB;GACnC,OAAO;IACN;KACC,IAAI;KACJ,aACC,8DACU,WAAW,EAAE,oGACiB,WAAW,EAAE,iEACpD,QAAQ,YACN,gBAAgB,QAAQ,UAAU,KAClC;IACL;IACA;KACC,IAAI;KACJ,aACC;IACF;IACA;KACC,IAAI;KACJ,aACC;IACF;IACA;KACC,IAAI;KACJ,aAAa,SAAS,WAAW,EAAE;KACnC,SAAS,GAAG,WAAW,EAAE;IAC1B;GACD;GACA,YAAY;IACX,MAAM;IACN,MAAM;KACL;KACA;KACA,GAAI,QAAQ,QAAQ,CAAC,WAAW,QAAQ,KAAK,IAAI,CAAC;IACnD;GACD;EACD;CACD;CAID,OAAO;EACN,OAAO;EACP,QAAQ;EACR,YAAY;GACX,MAAM;GACN,UACC;GACD,SAAS;IACR;KAAE,OAAO;KAAO,OAAO;IAAwB;IAC/C;KAAE,OAAO;KAAM,OAAO;IAAmB;IACzC;KAAE,OAAO;KAAQ,OAAO;IAA+B;GACxD;GACA,SACC;GACD,iBAAiB;IAChB,KAAK,EACJ,MAAM;KACL;KACA;KACA,GAAI,QAAQ,QAAQ,CAAC,WAAW,QAAQ,KAAK,IAAI,CAAC;KAClD;IACD,EACD;IACA,IAAI,EACH,MAAM;KACL;KACA;KACA,GAAI,QAAQ,QAAQ,CAAC,WAAW,QAAQ,KAAK,IAAI,CAAC;IACnD,EACD;IACA,MAAM,EACL,MAAM;KACL;KACA;KACA,GAAI,QAAQ,QAAQ,CAAC,WAAW,QAAQ,KAAK,IAAI,CAAC;KAClD;IACD,EACD;GACD;EACD;CACD;AACD"}
|
package/dist/lib/phases/setup.js
CHANGED
|
@@ -113,7 +113,7 @@ async function buildBulkInspection(options) {
|
|
|
113
113
|
checks: [
|
|
114
114
|
{
|
|
115
115
|
id: "neonctl",
|
|
116
|
-
description: "The
|
|
116
|
+
description: "The Neon CLI will be installed or updated automatically (no action needed from the agent)",
|
|
117
117
|
lookFor: []
|
|
118
118
|
},
|
|
119
119
|
{
|
|
@@ -159,7 +159,7 @@ async function buildBulkInspection(options) {
|
|
|
159
159
|
phase: "after_checks",
|
|
160
160
|
options: [{
|
|
161
161
|
value: "defaults",
|
|
162
|
-
label: hasApp ? "Use defaults (
|
|
162
|
+
label: hasApp ? "Use defaults (Neon CLI, MCP: global, skills: project-level, extension if applicable — already-configured components will be skipped)" : "Use defaults (Neon CLI, MCP: global, extension if applicable — skills included in template)"
|
|
163
163
|
}, {
|
|
164
164
|
value: "customize",
|
|
165
165
|
label: "Customize installation settings"
|
|
@@ -295,28 +295,28 @@ async function executeBatchedInstallation(options) {
|
|
|
295
295
|
case "already_current":
|
|
296
296
|
results.push({
|
|
297
297
|
id: "neonctl",
|
|
298
|
-
description: `
|
|
298
|
+
description: `Neon CLI is up to date (v${neonctlResult.version})`,
|
|
299
299
|
status: "success"
|
|
300
300
|
});
|
|
301
301
|
break;
|
|
302
302
|
case "installed":
|
|
303
303
|
results.push({
|
|
304
304
|
id: "neonctl",
|
|
305
|
-
description: `Installed
|
|
305
|
+
description: `Installed Neon CLI (v${neonctlResult.version})`,
|
|
306
306
|
status: "success"
|
|
307
307
|
});
|
|
308
308
|
break;
|
|
309
309
|
case "updated":
|
|
310
310
|
results.push({
|
|
311
311
|
id: "neonctl",
|
|
312
|
-
description: `Updated
|
|
312
|
+
description: `Updated Neon CLI to v${neonctlResult.version}`,
|
|
313
313
|
status: "success"
|
|
314
314
|
});
|
|
315
315
|
break;
|
|
316
316
|
case "failed":
|
|
317
317
|
results.push({
|
|
318
318
|
id: "neonctl",
|
|
319
|
-
description: "Failed to install
|
|
319
|
+
description: "Failed to install Neon CLI",
|
|
320
320
|
status: "failed",
|
|
321
321
|
error: neonctlResult.error
|
|
322
322
|
});
|