neon-init 0.14.0 → 0.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +366 -30
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +15 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +218 -13
- package/dist/index.js.map +1 -1
- package/dist/interactive.d.ts +12 -0
- package/dist/interactive.d.ts.map +1 -0
- package/dist/interactive.js +495 -0
- package/dist/interactive.js.map +1 -0
- package/dist/lib/agents.d.ts +6 -1
- package/dist/lib/agents.d.ts.map +1 -1
- package/dist/lib/agents.js +62 -1
- package/dist/lib/agents.js.map +1 -1
- package/dist/lib/auth.d.ts +10 -3
- package/dist/lib/auth.d.ts.map +1 -1
- package/dist/lib/auth.js +21 -12
- package/dist/lib/auth.js.map +1 -1
- package/dist/lib/bootstrap.d.ts +30 -0
- package/dist/lib/bootstrap.d.ts.map +1 -0
- package/dist/lib/bootstrap.js +61 -0
- package/dist/lib/bootstrap.js.map +1 -0
- package/dist/lib/build-config.d.ts +5 -0
- package/dist/lib/build-config.d.ts.map +1 -0
- package/dist/lib/build-config.js +6 -0
- package/dist/lib/build-config.js.map +1 -0
- package/dist/lib/detect-agent.d.ts +22 -0
- package/dist/lib/detect-agent.d.ts.map +1 -0
- package/dist/lib/detect-agent.js +65 -0
- package/dist/lib/detect-agent.js.map +1 -0
- package/dist/lib/editors.d.ts.map +1 -1
- package/dist/lib/editors.js.map +1 -1
- package/dist/lib/extension.d.ts +11 -3
- package/dist/lib/extension.d.ts.map +1 -1
- package/dist/lib/extension.js +28 -7
- package/dist/lib/extension.js.map +1 -1
- package/dist/lib/inspect.d.ts +28 -0
- package/dist/lib/inspect.d.ts.map +1 -0
- package/dist/lib/inspect.js +190 -0
- package/dist/lib/inspect.js.map +1 -0
- package/dist/lib/install.d.ts +10 -4
- package/dist/lib/install.d.ts.map +1 -1
- package/dist/lib/install.js +37 -20
- package/dist/lib/install.js.map +1 -1
- package/dist/lib/neonctl.d.ts +51 -0
- package/dist/lib/neonctl.d.ts.map +1 -0
- package/dist/lib/neonctl.js +184 -0
- package/dist/lib/neonctl.js.map +1 -0
- package/dist/lib/phases/auth.d.ts +12 -0
- package/dist/lib/phases/auth.d.ts.map +1 -0
- package/dist/lib/phases/auth.js +197 -0
- package/dist/lib/phases/auth.js.map +1 -0
- package/dist/lib/phases/cleanup.d.ts +12 -0
- package/dist/lib/phases/cleanup.d.ts.map +1 -0
- package/dist/lib/phases/cleanup.js +29 -0
- package/dist/lib/phases/cleanup.js.map +1 -0
- package/dist/lib/phases/db.d.ts +17 -0
- package/dist/lib/phases/db.d.ts.map +1 -0
- package/dist/lib/phases/db.js +259 -0
- package/dist/lib/phases/db.js.map +1 -0
- package/dist/lib/phases/getting-started.d.ts +26 -0
- package/dist/lib/phases/getting-started.d.ts.map +1 -0
- package/dist/lib/phases/getting-started.js +196 -0
- package/dist/lib/phases/getting-started.js.map +1 -0
- package/dist/lib/phases/mcp.d.ts +15 -0
- package/dist/lib/phases/mcp.d.ts.map +1 -0
- package/dist/lib/phases/mcp.js +179 -0
- package/dist/lib/phases/mcp.js.map +1 -0
- package/dist/lib/phases/migrations.d.ts +14 -0
- package/dist/lib/phases/migrations.d.ts.map +1 -0
- package/dist/lib/phases/migrations.js +239 -0
- package/dist/lib/phases/migrations.js.map +1 -0
- package/dist/lib/phases/neon-auth.d.ts +13 -0
- package/dist/lib/phases/neon-auth.d.ts.map +1 -0
- package/dist/lib/phases/neon-auth.js +118 -0
- package/dist/lib/phases/neon-auth.js.map +1 -0
- package/dist/lib/phases/setup.d.ts +41 -0
- package/dist/lib/phases/setup.d.ts.map +1 -0
- package/dist/lib/phases/setup.js +689 -0
- package/dist/lib/phases/setup.js.map +1 -0
- package/dist/lib/phases/skills.d.ts +14 -0
- package/dist/lib/phases/skills.d.ts.map +1 -0
- package/dist/lib/phases/skills.js +80 -0
- package/dist/lib/phases/skills.js.map +1 -0
- package/dist/lib/phases/status.d.ts +10 -0
- package/dist/lib/phases/status.d.ts.map +1 -0
- package/dist/lib/phases/status.js +65 -0
- package/dist/lib/phases/status.js.map +1 -0
- package/dist/lib/resolve-context.d.ts +19 -0
- package/dist/lib/resolve-context.d.ts.map +1 -0
- package/dist/lib/resolve-context.js +112 -0
- package/dist/lib/resolve-context.js.map +1 -0
- package/dist/lib/route-command.d.ts +8 -0
- package/dist/lib/route-command.d.ts.map +1 -0
- package/dist/lib/route-command.js +195 -0
- package/dist/lib/route-command.js.map +1 -0
- package/dist/lib/skills.d.ts +20 -3
- package/dist/lib/skills.d.ts.map +1 -1
- package/dist/lib/skills.js +116 -12
- package/dist/lib/skills.js.map +1 -1
- package/dist/lib/types.d.ts +150 -1
- package/dist/lib/types.d.ts.map +1 -1
- package/dist/lib/vsix.d.ts +15 -0
- package/dist/lib/vsix.d.ts.map +1 -0
- package/dist/lib/vsix.js +91 -0
- package/dist/lib/vsix.js.map +1 -0
- package/dist/v2.d.ts +31 -0
- package/dist/v2.d.ts.map +1 -0
- package/dist/v2.js +147 -0
- package/dist/v2.js.map +1 -0
- package/package.json +7 -3
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"neonctl.js","names":[],"sources":["../../src/lib/neonctl.ts"],"sourcesContent":["import { execa } from \"execa\";\n\n/**\n * Derives --api-host and --oauth-host flags from the NEON_API_HOST env var.\n *\n * When NEON_API_HOST is set (e.g. \"https://console-stage.neon.build\"), neonctl\n * commands need explicit flags:\n * --api-host https://console-stage.neon.build/api/v2\n * --oauth-host https://oauth2-stage.neon.build\n *\n * The oauth host is derived by replacing the \"console\" prefix in the hostname\n * with \"oauth2\" (e.g. console-stage.neon.build → oauth2-stage.neon.build).\n */\nexport function getNeonctlApiFlags(): string {\n\tconst apiHost = process.env.NEON_API_HOST;\n\tif (!apiHost) return \"\";\n\n\tconst apiUrl = `${apiHost.replace(/\\/+$/, \"\")}/api/v2`;\n\n\tlet oauthUrl = \"\";\n\ttry {\n\t\tconst url = new URL(apiHost);\n\t\turl.hostname = url.hostname.replace(/^console/, \"oauth2\");\n\t\t// OAuth host is just the origin (no path)\n\t\toauthUrl = url.origin;\n\t} catch {\n\t\t// If URL parsing fails, skip oauth-host\n\t}\n\n\tconst flags = [`--api-host ${apiUrl}`];\n\tif (oauthUrl) flags.push(`--oauth-host ${oauthUrl}`);\n\treturn flags.join(\" \");\n}\n\n/**\n * Returns the neonctl command prefix: \"CI= npx -y neonctl\" with any\n * --api-host / --oauth-host flags appended when NEON_API_HOST is set.\n *\n * Usage: `${neonctlCmd()} orgs list --output json`\n */\nexport function neonctlCmd(): string {\n\tconst flags = getNeonctlApiFlags();\n\treturn flags ? `CI= npx -y neonctl ${flags}` : \"CI= npx -y neonctl\";\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 * 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\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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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { PhaseResponse } from "../types.js";
|
|
2
|
+
|
|
3
|
+
//#region src/lib/phases/auth.d.ts
|
|
4
|
+
interface AuthPhaseOptions {
|
|
5
|
+
agent?: string;
|
|
6
|
+
method?: "existing" | "new";
|
|
7
|
+
verify?: boolean;
|
|
8
|
+
}
|
|
9
|
+
declare function handleAuthPhase(options: AuthPhaseOptions): Promise<PhaseResponse>;
|
|
10
|
+
//#endregion
|
|
11
|
+
export { AuthPhaseOptions, handleAuthPhase };
|
|
12
|
+
//# sourceMappingURL=auth.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.d.ts","names":[],"sources":["../../../src/lib/phases/auth.ts"],"mappings":";;;UAkBiB,gBAAA;;EAAA,MAAA,CAAA,EAAA,UAAgB,GAAA,KAAA;EAMX,MAAA,CAAA,EAAA,OAAA;;AACZ,iBADY,eAAA,CACZ,OAAA,EAAA,gBAAA,CAAA,EACP,OADO,CACC,aADD,CAAA"}
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
import { isAuthenticated } from "../auth.js";
|
|
2
|
+
import { neonctlCmd } from "../neonctl.js";
|
|
3
|
+
//#region src/lib/phases/auth.ts
|
|
4
|
+
function getSignupUrl() {
|
|
5
|
+
const base = process.env.NEON_API_HOST?.replace(/\/+$/, "");
|
|
6
|
+
return base ? `${base}/signup` : "https://console.neon.tech/signup";
|
|
7
|
+
}
|
|
8
|
+
function getSignupCommands() {
|
|
9
|
+
const url = getSignupUrl();
|
|
10
|
+
return {
|
|
11
|
+
darwin: `open ${url}`,
|
|
12
|
+
linux: `xdg-open ${url}`,
|
|
13
|
+
win32: `start ${url}`
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
async function handleAuthPhase(options) {
|
|
17
|
+
const agentArgs = options.agent ? [
|
|
18
|
+
"--agent",
|
|
19
|
+
options.agent,
|
|
20
|
+
"--json"
|
|
21
|
+
] : ["--json"];
|
|
22
|
+
if (options.verify) {
|
|
23
|
+
if (await isAuthenticated()) return {
|
|
24
|
+
phase: "auth",
|
|
25
|
+
status: "verified",
|
|
26
|
+
nextAction: {
|
|
27
|
+
type: "run_neon_init",
|
|
28
|
+
args: agentArgs
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
return {
|
|
32
|
+
phase: "auth",
|
|
33
|
+
status: "not_authenticated",
|
|
34
|
+
nextAction: {
|
|
35
|
+
type: "run_neon_init",
|
|
36
|
+
args: ["auth", "--json"]
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
if (await isAuthenticated()) return {
|
|
41
|
+
phase: "auth",
|
|
42
|
+
status: "verified",
|
|
43
|
+
nextAction: {
|
|
44
|
+
type: "run_neon_init",
|
|
45
|
+
args: agentArgs
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
if (options.method === "new") return {
|
|
49
|
+
phase: "auth",
|
|
50
|
+
status: "in_progress",
|
|
51
|
+
nextAction: {
|
|
52
|
+
type: "agent_action",
|
|
53
|
+
steps: [{
|
|
54
|
+
id: "open_signup",
|
|
55
|
+
description: "Open the Neon sign-up page in the user's browser",
|
|
56
|
+
command: getSignupCommands()[process.platform] ?? getSignupCommands().linux
|
|
57
|
+
}, {
|
|
58
|
+
id: "wait_for_signup",
|
|
59
|
+
description: "Tell the user: 'I've opened the Neon sign-up page. Create your account and verify your email, then let me know when you're ready.'"
|
|
60
|
+
}],
|
|
61
|
+
onComplete: {
|
|
62
|
+
type: "run_neon_init",
|
|
63
|
+
args: [
|
|
64
|
+
"auth",
|
|
65
|
+
"--json",
|
|
66
|
+
"--method",
|
|
67
|
+
"existing"
|
|
68
|
+
]
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
if (options.method === "existing") return {
|
|
73
|
+
phase: "auth",
|
|
74
|
+
status: "in_progress",
|
|
75
|
+
nextAction: {
|
|
76
|
+
type: "run_command",
|
|
77
|
+
command: `${neonctlCmd()} auth`,
|
|
78
|
+
description: "This will open your browser for Neon OAuth sign-in.",
|
|
79
|
+
timeout: 12e4,
|
|
80
|
+
onSuccess: {
|
|
81
|
+
type: "run_neon_init",
|
|
82
|
+
args: [
|
|
83
|
+
"auth",
|
|
84
|
+
"--json",
|
|
85
|
+
"--verify"
|
|
86
|
+
]
|
|
87
|
+
},
|
|
88
|
+
onFailure: {
|
|
89
|
+
"2": {
|
|
90
|
+
type: "ask_user",
|
|
91
|
+
question: "The sign-in timed out. Did you complete the sign-in in your browser?",
|
|
92
|
+
options: ["yes_retry", "need_help"],
|
|
93
|
+
responseMapping: {
|
|
94
|
+
yes_retry: { args: [
|
|
95
|
+
"auth",
|
|
96
|
+
"--json",
|
|
97
|
+
"--method",
|
|
98
|
+
"existing"
|
|
99
|
+
] },
|
|
100
|
+
need_help: { args: [
|
|
101
|
+
"auth",
|
|
102
|
+
"--json",
|
|
103
|
+
"--method",
|
|
104
|
+
"new"
|
|
105
|
+
] }
|
|
106
|
+
}
|
|
107
|
+
},
|
|
108
|
+
other: {
|
|
109
|
+
type: "run_neon_init",
|
|
110
|
+
args: ["auth", "--json"]
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
const openCmd = getSignupCommands()[process.platform] ?? getSignupCommands().linux;
|
|
116
|
+
return {
|
|
117
|
+
phase: "auth",
|
|
118
|
+
status: "required",
|
|
119
|
+
nextAction: {
|
|
120
|
+
type: "ask_user",
|
|
121
|
+
question: "Do you have an existing Neon account, or do you need to create one?",
|
|
122
|
+
options: [{
|
|
123
|
+
value: "existing_account",
|
|
124
|
+
label: "I have an existing Neon account"
|
|
125
|
+
}, {
|
|
126
|
+
value: "new_account",
|
|
127
|
+
label: "I need to create a new account"
|
|
128
|
+
}],
|
|
129
|
+
context: "Neon is a serverless Postgres provider. A free account is required to continue.",
|
|
130
|
+
responseMapping: {
|
|
131
|
+
existing_account: { action: {
|
|
132
|
+
type: "run_command",
|
|
133
|
+
command: `${neonctlCmd()} auth`,
|
|
134
|
+
description: "This will open your browser for Neon OAuth sign-in.",
|
|
135
|
+
timeout: 12e4,
|
|
136
|
+
onSuccess: {
|
|
137
|
+
type: "run_neon_init",
|
|
138
|
+
args: [
|
|
139
|
+
"auth",
|
|
140
|
+
"--json",
|
|
141
|
+
"--verify"
|
|
142
|
+
]
|
|
143
|
+
},
|
|
144
|
+
onFailure: {
|
|
145
|
+
"2": {
|
|
146
|
+
type: "ask_user",
|
|
147
|
+
question: "The sign-in timed out. Did you complete the sign-in in your browser?",
|
|
148
|
+
options: ["yes_retry", "need_help"],
|
|
149
|
+
responseMapping: {
|
|
150
|
+
yes_retry: { args: [
|
|
151
|
+
"auth",
|
|
152
|
+
"--json",
|
|
153
|
+
"--method",
|
|
154
|
+
"existing"
|
|
155
|
+
] },
|
|
156
|
+
need_help: { args: [
|
|
157
|
+
"auth",
|
|
158
|
+
"--json",
|
|
159
|
+
"--method",
|
|
160
|
+
"new"
|
|
161
|
+
] }
|
|
162
|
+
}
|
|
163
|
+
},
|
|
164
|
+
other: {
|
|
165
|
+
type: "run_neon_init",
|
|
166
|
+
args: ["auth", "--json"]
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
} },
|
|
170
|
+
new_account: { action: {
|
|
171
|
+
type: "agent_action",
|
|
172
|
+
steps: [{
|
|
173
|
+
id: "open_signup",
|
|
174
|
+
description: "Open the Neon sign-up page in the user's browser",
|
|
175
|
+
command: openCmd
|
|
176
|
+
}, {
|
|
177
|
+
id: "wait_for_signup",
|
|
178
|
+
description: "Tell the user: 'I've opened the Neon sign-up page. Create your account and verify your email, then let me know when you're ready.'"
|
|
179
|
+
}],
|
|
180
|
+
onComplete: {
|
|
181
|
+
type: "run_neon_init",
|
|
182
|
+
args: [
|
|
183
|
+
"auth",
|
|
184
|
+
"--json",
|
|
185
|
+
"--method",
|
|
186
|
+
"existing"
|
|
187
|
+
]
|
|
188
|
+
}
|
|
189
|
+
} }
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
//#endregion
|
|
195
|
+
export { handleAuthPhase };
|
|
196
|
+
|
|
197
|
+
//# sourceMappingURL=auth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.js","names":[],"sources":["../../../src/lib/phases/auth.ts"],"sourcesContent":["import { isAuthenticated } from \"../auth.js\";\nimport { neonctlCmd } from \"../neonctl.js\";\nimport type { PhaseResponse } from \"../types.js\";\n\nfunction getSignupUrl(): string {\n\tconst base = process.env.NEON_API_HOST?.replace(/\\/+$/, \"\");\n\treturn base ? `${base}/signup` : \"https://console.neon.tech/signup\";\n}\n\nfunction getSignupCommands(): Record<string, string> {\n\tconst url = getSignupUrl();\n\treturn {\n\t\tdarwin: `open ${url}`,\n\t\tlinux: `xdg-open ${url}`,\n\t\twin32: `start ${url}`,\n\t};\n}\n\nexport interface AuthPhaseOptions {\n\tagent?: string;\n\tmethod?: \"existing\" | \"new\";\n\tverify?: boolean;\n}\n\nexport async function handleAuthPhase(\n\toptions: AuthPhaseOptions,\n): Promise<PhaseResponse> {\n\tconst agentArgs = options.agent\n\t\t? [\"--agent\", options.agent, \"--json\"]\n\t\t: [\"--json\"];\n\n\t// --verify: just check if credentials exist\n\tif (options.verify) {\n\t\tconst authed = await isAuthenticated();\n\t\tif (authed) {\n\t\t\t// Continue the flow immediately — don't use \"complete\" which\n\t\t\t// causes agents to stop and get distracted by neonctl output.\n\t\t\treturn {\n\t\t\t\tphase: \"auth\",\n\t\t\t\tstatus: \"verified\",\n\t\t\t\tnextAction: {\n\t\t\t\t\ttype: \"run_neon_init\",\n\t\t\t\t\targs: agentArgs,\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\t\treturn {\n\t\t\tphase: \"auth\",\n\t\t\tstatus: \"not_authenticated\",\n\t\t\tnextAction: {\n\t\t\t\ttype: \"run_neon_init\",\n\t\t\t\targs: [\"auth\", \"--json\"],\n\t\t\t},\n\t\t};\n\t}\n\n\t// Check if already authenticated\n\tconst authed = await isAuthenticated();\n\tif (authed) {\n\t\treturn {\n\t\t\tphase: \"auth\",\n\t\t\tstatus: \"verified\",\n\t\t\tnextAction: {\n\t\t\t\ttype: \"run_neon_init\",\n\t\t\t\targs: agentArgs,\n\t\t\t},\n\t\t};\n\t}\n\n\t// --method new: guide through signup\n\tif (options.method === \"new\") {\n\t\tconst openCmd =\n\t\t\tgetSignupCommands()[process.platform] ?? getSignupCommands().linux;\n\t\treturn {\n\t\t\tphase: \"auth\",\n\t\t\tstatus: \"in_progress\",\n\t\t\tnextAction: {\n\t\t\t\ttype: \"agent_action\",\n\t\t\t\tsteps: [\n\t\t\t\t\t{\n\t\t\t\t\t\tid: \"open_signup\",\n\t\t\t\t\t\tdescription:\n\t\t\t\t\t\t\t\"Open the Neon sign-up page in the user's browser\",\n\t\t\t\t\t\tcommand: openCmd,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tid: \"wait_for_signup\",\n\t\t\t\t\t\tdescription:\n\t\t\t\t\t\t\t\"Tell the user: 'I've opened the Neon sign-up page. Create your account and verify your email, then let me know when you're ready.'\",\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: [\"auth\", \"--json\", \"--method\", \"existing\"],\n\t\t\t\t},\n\t\t\t},\n\t\t};\n\t}\n\n\t// --method existing: run OAuth flow\n\tif (options.method === \"existing\") {\n\t\treturn {\n\t\t\tphase: \"auth\",\n\t\t\tstatus: \"in_progress\",\n\t\t\tnextAction: {\n\t\t\t\ttype: \"run_command\",\n\t\t\t\tcommand: `${neonctlCmd()} auth`,\n\t\t\t\tdescription:\n\t\t\t\t\t\"This will open your browser for Neon OAuth sign-in.\",\n\t\t\t\ttimeout: 120000,\n\t\t\t\tonSuccess: {\n\t\t\t\t\ttype: \"run_neon_init\",\n\t\t\t\t\targs: [\"auth\", \"--json\", \"--verify\"],\n\t\t\t\t},\n\t\t\t\tonFailure: {\n\t\t\t\t\t\"2\": {\n\t\t\t\t\t\ttype: \"ask_user\",\n\t\t\t\t\t\tquestion:\n\t\t\t\t\t\t\t\"The sign-in timed out. Did you complete the sign-in in your browser?\",\n\t\t\t\t\t\toptions: [\"yes_retry\", \"need_help\"],\n\t\t\t\t\t\tresponseMapping: {\n\t\t\t\t\t\t\tyes_retry: {\n\t\t\t\t\t\t\t\targs: [\n\t\t\t\t\t\t\t\t\t\"auth\",\n\t\t\t\t\t\t\t\t\t\"--json\",\n\t\t\t\t\t\t\t\t\t\"--method\",\n\t\t\t\t\t\t\t\t\t\"existing\",\n\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tneed_help: {\n\t\t\t\t\t\t\t\targs: [\"auth\", \"--json\", \"--method\", \"new\"],\n\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\tother: {\n\t\t\t\t\t\ttype: \"run_neon_init\",\n\t\t\t\t\t\targs: [\"auth\", \"--json\"],\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t};\n\t}\n\n\t// No method specified: ask the user, then launch OAuth directly for\n\t// \"existing account\" without an intermediate CLI round-trip.\n\tconst openCmd =\n\t\tgetSignupCommands()[process.platform] ?? getSignupCommands().linux;\n\treturn {\n\t\tphase: \"auth\",\n\t\tstatus: \"required\",\n\t\tnextAction: {\n\t\t\ttype: \"ask_user\",\n\t\t\tquestion:\n\t\t\t\t\"Do you have an existing Neon account, or do you need to create one?\",\n\t\t\toptions: [\n\t\t\t\t{\n\t\t\t\t\tvalue: \"existing_account\",\n\t\t\t\t\tlabel: \"I have an existing Neon account\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tvalue: \"new_account\",\n\t\t\t\t\tlabel: \"I need to create a new account\",\n\t\t\t\t},\n\t\t\t],\n\t\t\tcontext:\n\t\t\t\t\"Neon is a serverless Postgres provider. A free account is required to continue.\",\n\t\t\tresponseMapping: {\n\t\t\t\texisting_account: {\n\t\t\t\t\taction: {\n\t\t\t\t\t\ttype: \"run_command\",\n\t\t\t\t\t\tcommand: `${neonctlCmd()} auth`,\n\t\t\t\t\t\tdescription:\n\t\t\t\t\t\t\t\"This will open your browser for Neon OAuth sign-in.\",\n\t\t\t\t\t\ttimeout: 120000,\n\t\t\t\t\t\tonSuccess: {\n\t\t\t\t\t\t\ttype: \"run_neon_init\",\n\t\t\t\t\t\t\targs: [\"auth\", \"--json\", \"--verify\"],\n\t\t\t\t\t\t},\n\t\t\t\t\t\tonFailure: {\n\t\t\t\t\t\t\t\"2\": {\n\t\t\t\t\t\t\t\ttype: \"ask_user\",\n\t\t\t\t\t\t\t\tquestion:\n\t\t\t\t\t\t\t\t\t\"The sign-in timed out. Did you complete the sign-in in your browser?\",\n\t\t\t\t\t\t\t\toptions: [\"yes_retry\", \"need_help\"],\n\t\t\t\t\t\t\t\tresponseMapping: {\n\t\t\t\t\t\t\t\t\tyes_retry: {\n\t\t\t\t\t\t\t\t\t\targs: [\n\t\t\t\t\t\t\t\t\t\t\t\"auth\",\n\t\t\t\t\t\t\t\t\t\t\t\"--json\",\n\t\t\t\t\t\t\t\t\t\t\t\"--method\",\n\t\t\t\t\t\t\t\t\t\t\t\"existing\",\n\t\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\tneed_help: {\n\t\t\t\t\t\t\t\t\t\targs: [\n\t\t\t\t\t\t\t\t\t\t\t\"auth\",\n\t\t\t\t\t\t\t\t\t\t\t\"--json\",\n\t\t\t\t\t\t\t\t\t\t\t\"--method\",\n\t\t\t\t\t\t\t\t\t\t\t\"new\",\n\t\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tother: {\n\t\t\t\t\t\t\t\ttype: \"run_neon_init\",\n\t\t\t\t\t\t\t\targs: [\"auth\", \"--json\"],\n\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\tnew_account: {\n\t\t\t\t\taction: {\n\t\t\t\t\t\ttype: \"agent_action\",\n\t\t\t\t\t\tsteps: [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tid: \"open_signup\",\n\t\t\t\t\t\t\t\tdescription:\n\t\t\t\t\t\t\t\t\t\"Open the Neon sign-up page in the user's browser\",\n\t\t\t\t\t\t\t\tcommand: openCmd,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tid: \"wait_for_signup\",\n\t\t\t\t\t\t\t\tdescription:\n\t\t\t\t\t\t\t\t\t\"Tell the user: 'I've opened the Neon sign-up page. Create your account and verify your email, then let me know when you're ready.'\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t],\n\t\t\t\t\t\tonComplete: {\n\t\t\t\t\t\t\ttype: \"run_neon_init\",\n\t\t\t\t\t\t\targs: [\"auth\", \"--json\", \"--method\", \"existing\"],\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"],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { PhaseResponse } from "../types.js";
|
|
2
|
+
|
|
3
|
+
//#region src/lib/phases/cleanup.d.ts
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Terminal phase: cleans up ephemeral _init state from .neon and
|
|
7
|
+
* returns a complete message. All feature chains should end here.
|
|
8
|
+
*/
|
|
9
|
+
declare function handleCleanup(): PhaseResponse;
|
|
10
|
+
//#endregion
|
|
11
|
+
export { handleCleanup };
|
|
12
|
+
//# sourceMappingURL=cleanup.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cleanup.d.ts","names":[],"sources":["../../../src/lib/phases/cleanup.ts"],"mappings":";;;;;;AAQA;;iBAAgB,aAAA,CAAA,GAAiB"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { resolve } from "node:path";
|
|
3
|
+
//#region src/lib/phases/cleanup.ts
|
|
4
|
+
/**
|
|
5
|
+
* Terminal phase: cleans up ephemeral _init state from .neon and
|
|
6
|
+
* returns a complete message. All feature chains should end here.
|
|
7
|
+
*/
|
|
8
|
+
function handleCleanup() {
|
|
9
|
+
const neonContextPath = resolve(process.cwd(), ".neon");
|
|
10
|
+
if (existsSync(neonContextPath)) try {
|
|
11
|
+
const context = JSON.parse(readFileSync(neonContextPath, "utf-8"));
|
|
12
|
+
if (context._init !== void 0) {
|
|
13
|
+
delete context._init;
|
|
14
|
+
writeFileSync(neonContextPath, `${JSON.stringify(context, null, 2)}\n`);
|
|
15
|
+
}
|
|
16
|
+
} catch {}
|
|
17
|
+
return {
|
|
18
|
+
phase: "setup",
|
|
19
|
+
status: "complete",
|
|
20
|
+
nextAction: {
|
|
21
|
+
type: "complete",
|
|
22
|
+
message: "Neon setup is complete! Your database is connected and your agent has the Neon MCP server and skills available."
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
//#endregion
|
|
27
|
+
export { handleCleanup };
|
|
28
|
+
|
|
29
|
+
//# sourceMappingURL=cleanup.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cleanup.js","names":[],"sources":["../../../src/lib/phases/cleanup.ts"],"sourcesContent":["import { existsSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport type { PhaseResponse } from \"../types.js\";\n\n/**\n * Terminal phase: cleans up ephemeral _init state from .neon and\n * returns a complete message. All feature chains should end here.\n */\nexport function handleCleanup(): PhaseResponse {\n\tconst neonContextPath = resolve(process.cwd(), \".neon\");\n\tif (existsSync(neonContextPath)) {\n\t\ttry {\n\t\t\tconst context = JSON.parse(readFileSync(neonContextPath, \"utf-8\"));\n\t\t\tif (context._init !== undefined) {\n\t\t\t\tdelete context._init;\n\t\t\t\twriteFileSync(\n\t\t\t\t\tneonContextPath,\n\t\t\t\t\t`${JSON.stringify(context, null, 2)}\\n`,\n\t\t\t\t);\n\t\t\t}\n\t\t} catch {}\n\t}\n\n\treturn {\n\t\tphase: \"setup\",\n\t\tstatus: \"complete\",\n\t\tnextAction: {\n\t\t\ttype: \"complete\",\n\t\t\tmessage:\n\t\t\t\t\"Neon setup is complete! Your database is connected and your agent has the Neon MCP server and skills available.\",\n\t\t},\n\t};\n}\n"],"mappings":";;;;;;;AAQA,SAAgB,gBAA+B;CAC9C,MAAM,kBAAkB,QAAQ,QAAQ,IAAI,GAAG,OAAO;CACtD,IAAI,WAAW,eAAe,GAC7B,IAAI;EACH,MAAM,UAAU,KAAK,MAAM,aAAa,iBAAiB,OAAO,CAAC;EACjE,IAAI,QAAQ,UAAU,KAAA,GAAW;GAChC,OAAO,QAAQ;GACf,cACC,iBACA,GAAG,KAAK,UAAU,SAAS,MAAM,CAAC,EAAE,GACrC;EACD;CACD,QAAQ,CAAC;CAGV,OAAO;EACN,OAAO;EACP,QAAQ;EACR,YAAY;GACX,MAAM;GACN,SACC;EACF;CACD;AACD"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { PhaseResponse } from "../types.js";
|
|
2
|
+
|
|
3
|
+
//#region src/lib/phases/db.d.ts
|
|
4
|
+
interface DbPhaseOptions {
|
|
5
|
+
agent?: string;
|
|
6
|
+
orgId?: string;
|
|
7
|
+
projectId?: string;
|
|
8
|
+
orgsResult?: string;
|
|
9
|
+
projectsResult?: string;
|
|
10
|
+
framework?: string;
|
|
11
|
+
orm?: string;
|
|
12
|
+
error?: string;
|
|
13
|
+
}
|
|
14
|
+
declare function handleDbPhase(options: DbPhaseOptions): Promise<PhaseResponse>;
|
|
15
|
+
//#endregion
|
|
16
|
+
export { DbPhaseOptions, handleDbPhase };
|
|
17
|
+
//# sourceMappingURL=db.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"db.d.ts","names":[],"sources":["../../../src/lib/phases/db.ts"],"mappings":";;;UAgBiB,cAAA;;EAAA,KAAA,CAAA,EAAA,MAAA;EAWK,SAAA,CAAA,EAAA,MAAa;EAAA,UAAA,CAAA,EAAA,MAAA;gBACzB,CAAA,EAAA,MAAA;WACC,CAAA,EAAA,MAAA;KAAR,CAAA,EAAA,MAAA;EAAO,KAAA,CAAA,EAAA,MAAA;;iBAFY,aAAA,UACZ,iBACP,QAAQ"}
|
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
import { neonctlCmd } from "../neonctl.js";
|
|
2
|
+
import { SKILL_REFERENCE_URLS } from "../skills.js";
|
|
3
|
+
//#region src/lib/phases/db.ts
|
|
4
|
+
/**
|
|
5
|
+
* Validates that an ID contains only safe characters for shell interpolation.
|
|
6
|
+
* Neon org/project IDs are typically UUIDs or slug-like strings.
|
|
7
|
+
*/
|
|
8
|
+
function assertSafeId(value, label) {
|
|
9
|
+
if (!/^[\w.:-]+$/.test(value)) throw new Error(`Invalid ${label}: "${value}". Expected alphanumeric, hyphens, underscores, dots, or colons.`);
|
|
10
|
+
}
|
|
11
|
+
async function handleDbPhase(options) {
|
|
12
|
+
const agentArgs = options.agent ? [
|
|
13
|
+
"--agent",
|
|
14
|
+
options.agent,
|
|
15
|
+
"--json"
|
|
16
|
+
] : ["--json"];
|
|
17
|
+
if (options.projectId) assertSafeId(options.projectId, "project ID");
|
|
18
|
+
if (options.orgId) assertSafeId(options.orgId, "org ID");
|
|
19
|
+
if (options.error) return {
|
|
20
|
+
phase: "db",
|
|
21
|
+
status: "error",
|
|
22
|
+
error: options.error,
|
|
23
|
+
nextAction: {
|
|
24
|
+
type: "ask_user",
|
|
25
|
+
question: `An error occurred during database setup: ${options.error}. Would you like to try again or skip this step?`,
|
|
26
|
+
options: [{
|
|
27
|
+
value: "retry",
|
|
28
|
+
label: "Try again"
|
|
29
|
+
}, {
|
|
30
|
+
value: "skip",
|
|
31
|
+
label: "Skip database setup"
|
|
32
|
+
}],
|
|
33
|
+
responseMapping: {
|
|
34
|
+
retry: { args: ["db", "--json"] },
|
|
35
|
+
skip: { args: agentArgs }
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
if (options.projectId) return {
|
|
40
|
+
phase: "db",
|
|
41
|
+
status: "project_ready",
|
|
42
|
+
project: { id: options.projectId },
|
|
43
|
+
nextAction: {
|
|
44
|
+
type: "agent_action",
|
|
45
|
+
prerequisite: SKILL_REFERENCE_URLS.connectionMethods,
|
|
46
|
+
steps: [
|
|
47
|
+
{
|
|
48
|
+
id: "get_connection_string",
|
|
49
|
+
description: "Get the database connection string",
|
|
50
|
+
command: `${neonctlCmd()} connection-string --project-id ${options.projectId}`
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
id: "store_env",
|
|
54
|
+
description: "Append DATABASE_URL=<connection_string> to .env. Create .env if it doesn't exist. Do NOT overwrite existing entries. Ensure .env is in .gitignore."
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
id: "detect_framework",
|
|
58
|
+
description: "Examine the project to determine the framework (Next.js, Remix, Express, etc.) and ORM (Prisma, Drizzle, raw SQL) in use."
|
|
59
|
+
}
|
|
60
|
+
],
|
|
61
|
+
onComplete: {
|
|
62
|
+
type: "run_neon_init",
|
|
63
|
+
args: agentArgs
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
if (options.projectsResult) {
|
|
68
|
+
let projects;
|
|
69
|
+
try {
|
|
70
|
+
const parsed = JSON.parse(options.projectsResult);
|
|
71
|
+
projects = Array.isArray(parsed.projects) ? parsed.projects : Array.isArray(parsed) ? parsed : [];
|
|
72
|
+
} catch {
|
|
73
|
+
projects = [];
|
|
74
|
+
}
|
|
75
|
+
const orgIdArgs = options.orgId ? ["--org-id", options.orgId] : [];
|
|
76
|
+
if (projects.length === 0) return {
|
|
77
|
+
phase: "db",
|
|
78
|
+
status: "no_projects",
|
|
79
|
+
nextAction: {
|
|
80
|
+
type: "ask_user",
|
|
81
|
+
question: "You don't have any Neon projects yet. What would you like to name your new project?",
|
|
82
|
+
options: [{
|
|
83
|
+
value: "create",
|
|
84
|
+
label: "Create a new project (provide a name)"
|
|
85
|
+
}],
|
|
86
|
+
context: `The agent should ask the user for a project name, then run: ${neonctlCmd()} projects create --name <name> --output json` + (options.orgId ? ` --org-id ${options.orgId}` : "") + " and pass the result back.",
|
|
87
|
+
responseMapping: { create: { args: [
|
|
88
|
+
"db",
|
|
89
|
+
"--json",
|
|
90
|
+
...orgIdArgs,
|
|
91
|
+
"--project-id",
|
|
92
|
+
"<created-project-id>"
|
|
93
|
+
] } }
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
const projectOptions = projects.map((p) => ({
|
|
97
|
+
value: p.id,
|
|
98
|
+
label: `${p.name} (${p.id})`
|
|
99
|
+
}));
|
|
100
|
+
projectOptions.push({
|
|
101
|
+
value: "create_new",
|
|
102
|
+
label: "Create a new project"
|
|
103
|
+
});
|
|
104
|
+
const responseMapping = {};
|
|
105
|
+
for (const p of projects) responseMapping[p.id] = { args: [
|
|
106
|
+
"db",
|
|
107
|
+
"--json",
|
|
108
|
+
...orgIdArgs,
|
|
109
|
+
"--project-id",
|
|
110
|
+
p.id
|
|
111
|
+
] };
|
|
112
|
+
responseMapping.create_new = { args: [
|
|
113
|
+
"db",
|
|
114
|
+
"--json",
|
|
115
|
+
...orgIdArgs,
|
|
116
|
+
"--project-id",
|
|
117
|
+
"<created-project-id>"
|
|
118
|
+
] };
|
|
119
|
+
return {
|
|
120
|
+
phase: "db",
|
|
121
|
+
status: "select_project",
|
|
122
|
+
nextAction: {
|
|
123
|
+
type: "ask_user",
|
|
124
|
+
question: "Which Neon project would you like to use?",
|
|
125
|
+
options: projectOptions,
|
|
126
|
+
context: `If the user wants to create a new project, ask for a name then run: ${neonctlCmd()} projects create --name <name> --output json and use the returned project id.`,
|
|
127
|
+
responseMapping
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
if (options.orgsResult) {
|
|
132
|
+
let orgs;
|
|
133
|
+
try {
|
|
134
|
+
const parsed = JSON.parse(options.orgsResult);
|
|
135
|
+
orgs = Array.isArray(parsed.organizations) ? parsed.organizations : Array.isArray(parsed) ? parsed : [];
|
|
136
|
+
} catch {
|
|
137
|
+
orgs = [];
|
|
138
|
+
}
|
|
139
|
+
const orgId = options.orgId ?? (orgs.length === 1 ? orgs[0].id : null);
|
|
140
|
+
if (orgId) {
|
|
141
|
+
assertSafeId(orgId, "org ID");
|
|
142
|
+
return {
|
|
143
|
+
phase: "db",
|
|
144
|
+
status: "org_selected",
|
|
145
|
+
org: { id: orgId },
|
|
146
|
+
nextAction: {
|
|
147
|
+
type: "run_command",
|
|
148
|
+
command: `${neonctlCmd()} projects list --org-id ${orgId} --output json`,
|
|
149
|
+
description: "Listing Neon projects.",
|
|
150
|
+
timeout: 3e4,
|
|
151
|
+
onSuccess: {
|
|
152
|
+
type: "run_neon_init",
|
|
153
|
+
args: [
|
|
154
|
+
"db",
|
|
155
|
+
"--json",
|
|
156
|
+
"--org-id",
|
|
157
|
+
orgId,
|
|
158
|
+
"--projects-result",
|
|
159
|
+
"<stdout>"
|
|
160
|
+
]
|
|
161
|
+
},
|
|
162
|
+
onFailure: { other: {
|
|
163
|
+
type: "run_neon_init",
|
|
164
|
+
args: [
|
|
165
|
+
"db",
|
|
166
|
+
"--json",
|
|
167
|
+
"--error",
|
|
168
|
+
"projects-list-failed"
|
|
169
|
+
]
|
|
170
|
+
} }
|
|
171
|
+
}
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
const orgOptions = orgs.map((o) => ({
|
|
175
|
+
value: o.id,
|
|
176
|
+
label: `${o.name} (${o.id})`
|
|
177
|
+
}));
|
|
178
|
+
const responseMapping = {};
|
|
179
|
+
for (const o of orgs) responseMapping[o.id] = { args: [
|
|
180
|
+
"db",
|
|
181
|
+
"--json",
|
|
182
|
+
"--org-id",
|
|
183
|
+
o.id
|
|
184
|
+
] };
|
|
185
|
+
return {
|
|
186
|
+
phase: "db",
|
|
187
|
+
status: "select_org",
|
|
188
|
+
nextAction: {
|
|
189
|
+
type: "ask_user",
|
|
190
|
+
question: "Which Neon organization would you like to use?",
|
|
191
|
+
options: orgOptions,
|
|
192
|
+
responseMapping
|
|
193
|
+
}
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
if (options.orgId) return {
|
|
197
|
+
phase: "db",
|
|
198
|
+
status: "org_selected",
|
|
199
|
+
org: { id: options.orgId },
|
|
200
|
+
nextAction: {
|
|
201
|
+
type: "run_command",
|
|
202
|
+
command: `${neonctlCmd()} projects list --org-id ${options.orgId} --output json`,
|
|
203
|
+
description: "Listing Neon projects.",
|
|
204
|
+
timeout: 3e4,
|
|
205
|
+
onSuccess: {
|
|
206
|
+
type: "run_neon_init",
|
|
207
|
+
args: [
|
|
208
|
+
"db",
|
|
209
|
+
"--json",
|
|
210
|
+
"--org-id",
|
|
211
|
+
options.orgId,
|
|
212
|
+
"--projects-result",
|
|
213
|
+
"<stdout>"
|
|
214
|
+
]
|
|
215
|
+
},
|
|
216
|
+
onFailure: { other: {
|
|
217
|
+
type: "run_neon_init",
|
|
218
|
+
args: [
|
|
219
|
+
"db",
|
|
220
|
+
"--json",
|
|
221
|
+
"--error",
|
|
222
|
+
"projects-list-failed"
|
|
223
|
+
]
|
|
224
|
+
} }
|
|
225
|
+
}
|
|
226
|
+
};
|
|
227
|
+
return {
|
|
228
|
+
phase: "db",
|
|
229
|
+
status: "ready",
|
|
230
|
+
nextAction: {
|
|
231
|
+
type: "run_command",
|
|
232
|
+
command: `${neonctlCmd()} orgs list --output json`,
|
|
233
|
+
description: "Listing your Neon organizations.",
|
|
234
|
+
timeout: 3e4,
|
|
235
|
+
onSuccess: {
|
|
236
|
+
type: "run_neon_init",
|
|
237
|
+
args: [
|
|
238
|
+
"db",
|
|
239
|
+
"--json",
|
|
240
|
+
"--orgs-result",
|
|
241
|
+
"<stdout>"
|
|
242
|
+
]
|
|
243
|
+
},
|
|
244
|
+
onFailure: { other: {
|
|
245
|
+
type: "run_neon_init",
|
|
246
|
+
args: [
|
|
247
|
+
"db",
|
|
248
|
+
"--json",
|
|
249
|
+
"--error",
|
|
250
|
+
"orgs-list-failed"
|
|
251
|
+
]
|
|
252
|
+
} }
|
|
253
|
+
}
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
//#endregion
|
|
257
|
+
export { handleDbPhase };
|
|
258
|
+
|
|
259
|
+
//# sourceMappingURL=db.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"db.js","names":[],"sources":["../../../src/lib/phases/db.ts"],"sourcesContent":["import { neonctlCmd } from \"../neonctl.js\";\nimport { SKILL_REFERENCE_URLS } from \"../skills.js\";\nimport type { PhaseResponse } from \"../types.js\";\n\n/**\n * Validates that an ID contains only safe characters for shell interpolation.\n * Neon org/project IDs are typically UUIDs or slug-like strings.\n */\nfunction assertSafeId(value: string, label: string): void {\n\tif (!/^[\\w.:-]+$/.test(value)) {\n\t\tthrow new Error(\n\t\t\t`Invalid ${label}: \"${value}\". Expected alphanumeric, hyphens, underscores, dots, or colons.`,\n\t\t);\n\t}\n}\n\nexport interface DbPhaseOptions {\n\tagent?: string;\n\torgId?: string;\n\tprojectId?: string;\n\torgsResult?: string;\n\tprojectsResult?: string;\n\tframework?: string;\n\torm?: string;\n\terror?: string;\n}\n\nexport async function handleDbPhase(\n\toptions: DbPhaseOptions,\n): Promise<PhaseResponse> {\n\tconst agentArgs = options.agent\n\t\t? [\"--agent\", options.agent, \"--json\"]\n\t\t: [\"--json\"];\n\n\t// Validate IDs that will be interpolated into shell commands\n\tif (options.projectId) assertSafeId(options.projectId, \"project ID\");\n\tif (options.orgId) assertSafeId(options.orgId, \"org ID\");\n\n\t// Error from a previous step\n\tif (options.error) {\n\t\treturn {\n\t\t\tphase: \"db\",\n\t\t\tstatus: \"error\",\n\t\t\terror: options.error,\n\t\t\tnextAction: {\n\t\t\t\ttype: \"ask_user\",\n\t\t\t\tquestion: `An error occurred during database setup: ${options.error}. Would you like to try again or skip this step?`,\n\t\t\t\toptions: [\n\t\t\t\t\t{ value: \"retry\", label: \"Try again\" },\n\t\t\t\t\t{ value: \"skip\", label: \"Skip database setup\" },\n\t\t\t\t],\n\t\t\t\tresponseMapping: {\n\t\t\t\t\tretry: { args: [\"db\", \"--json\"] },\n\t\t\t\t\tskip: { args: agentArgs },\n\t\t\t\t},\n\t\t\t},\n\t\t};\n\t}\n\n\t// If we have a project ID, we're in the \"wire it up\" phase\n\tif (options.projectId) {\n\t\treturn {\n\t\t\tphase: \"db\",\n\t\t\tstatus: \"project_ready\",\n\t\t\tproject: { id: options.projectId },\n\t\t\tnextAction: {\n\t\t\t\ttype: \"agent_action\",\n\t\t\t\tprerequisite: SKILL_REFERENCE_URLS.connectionMethods,\n\t\t\t\tsteps: [\n\t\t\t\t\t{\n\t\t\t\t\t\tid: \"get_connection_string\",\n\t\t\t\t\t\tdescription: \"Get the database connection string\",\n\t\t\t\t\t\tcommand: `${neonctlCmd()} connection-string --project-id ${options.projectId}`,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tid: \"store_env\",\n\t\t\t\t\t\tdescription:\n\t\t\t\t\t\t\t\"Append DATABASE_URL=<connection_string> to .env. Create .env if it doesn't exist. Do NOT overwrite existing entries. Ensure .env is in .gitignore.\",\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tid: \"detect_framework\",\n\t\t\t\t\t\tdescription:\n\t\t\t\t\t\t\t\"Examine the project to determine the framework (Next.js, Remix, Express, etc.) and ORM (Prisma, Drizzle, raw SQL) in use.\",\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: agentArgs,\n\t\t\t\t},\n\t\t\t},\n\t\t};\n\t}\n\n\t// If we have projects result, let user pick or create\n\tif (options.projectsResult) {\n\t\tlet projects: { id: string; name: string }[];\n\t\ttry {\n\t\t\tconst parsed = JSON.parse(options.projectsResult);\n\t\t\tprojects = Array.isArray(parsed.projects)\n\t\t\t\t? parsed.projects\n\t\t\t\t: Array.isArray(parsed)\n\t\t\t\t\t? parsed\n\t\t\t\t\t: [];\n\t\t} catch {\n\t\t\tprojects = [];\n\t\t}\n\n\t\tconst orgIdArgs = options.orgId ? [\"--org-id\", options.orgId] : [];\n\n\t\tif (projects.length === 0) {\n\t\t\treturn {\n\t\t\t\tphase: \"db\",\n\t\t\t\tstatus: \"no_projects\",\n\t\t\t\tnextAction: {\n\t\t\t\t\ttype: \"ask_user\",\n\t\t\t\t\tquestion:\n\t\t\t\t\t\t\"You don't have any Neon projects yet. What would you like to name your new project?\",\n\t\t\t\t\toptions: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tvalue: \"create\",\n\t\t\t\t\t\t\tlabel: \"Create a new project (provide a name)\",\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t\tcontext:\n\t\t\t\t\t\t`The agent should ask the user for a project name, then run: ${neonctlCmd()} projects create --name <name> --output json` +\n\t\t\t\t\t\t(options.orgId ? ` --org-id ${options.orgId}` : \"\") +\n\t\t\t\t\t\t\" and pass the result back.\",\n\t\t\t\t\tresponseMapping: {\n\t\t\t\t\t\tcreate: {\n\t\t\t\t\t\t\targs: [\n\t\t\t\t\t\t\t\t\"db\",\n\t\t\t\t\t\t\t\t\"--json\",\n\t\t\t\t\t\t\t\t...orgIdArgs,\n\t\t\t\t\t\t\t\t\"--project-id\",\n\t\t\t\t\t\t\t\t\"<created-project-id>\",\n\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\n\t\tconst projectOptions = projects.map((p) => ({\n\t\t\tvalue: p.id,\n\t\t\tlabel: `${p.name} (${p.id})`,\n\t\t}));\n\t\tprojectOptions.push({\n\t\t\tvalue: \"create_new\",\n\t\t\tlabel: \"Create a new project\",\n\t\t});\n\n\t\tconst responseMapping: Record<string, { args: string[] }> = {};\n\t\tfor (const p of projects) {\n\t\t\tresponseMapping[p.id] = {\n\t\t\t\targs: [\"db\", \"--json\", ...orgIdArgs, \"--project-id\", p.id],\n\t\t\t};\n\t\t}\n\t\tresponseMapping.create_new = {\n\t\t\targs: [\n\t\t\t\t\"db\",\n\t\t\t\t\"--json\",\n\t\t\t\t...orgIdArgs,\n\t\t\t\t\"--project-id\",\n\t\t\t\t\"<created-project-id>\",\n\t\t\t],\n\t\t};\n\n\t\treturn {\n\t\t\tphase: \"db\",\n\t\t\tstatus: \"select_project\",\n\t\t\tnextAction: {\n\t\t\t\ttype: \"ask_user\",\n\t\t\t\tquestion: \"Which Neon project would you like to use?\",\n\t\t\t\toptions: projectOptions,\n\t\t\t\tcontext: `If the user wants to create a new project, ask for a name then run: ${neonctlCmd()} projects create --name <name> --output json and use the returned project id.`,\n\t\t\t\tresponseMapping,\n\t\t\t},\n\t\t};\n\t}\n\n\t// If we have orgs result, decide next step\n\tif (options.orgsResult) {\n\t\tlet orgs: { id: string; name: string }[];\n\t\ttry {\n\t\t\tconst parsed = JSON.parse(options.orgsResult);\n\t\t\torgs = Array.isArray(parsed.organizations)\n\t\t\t\t? parsed.organizations\n\t\t\t\t: Array.isArray(parsed)\n\t\t\t\t\t? parsed\n\t\t\t\t\t: [];\n\t\t} catch {\n\t\t\torgs = [];\n\t\t}\n\n\t\t// Single org or org already selected: list projects\n\t\tconst orgId = options.orgId ?? (orgs.length === 1 ? orgs[0].id : null);\n\n\t\tif (orgId) {\n\t\t\tassertSafeId(orgId, \"org ID\");\n\t\t\treturn {\n\t\t\t\tphase: \"db\",\n\t\t\t\tstatus: \"org_selected\",\n\t\t\t\torg: { id: orgId },\n\t\t\t\tnextAction: {\n\t\t\t\t\ttype: \"run_command\",\n\t\t\t\t\tcommand: `${neonctlCmd()} projects list --org-id ${orgId} --output json`,\n\t\t\t\t\tdescription: \"Listing Neon projects.\",\n\t\t\t\t\ttimeout: 30000,\n\t\t\t\t\tonSuccess: {\n\t\t\t\t\t\ttype: \"run_neon_init\",\n\t\t\t\t\t\targs: [\n\t\t\t\t\t\t\t\"db\",\n\t\t\t\t\t\t\t\"--json\",\n\t\t\t\t\t\t\t\"--org-id\",\n\t\t\t\t\t\t\torgId,\n\t\t\t\t\t\t\t\"--projects-result\",\n\t\t\t\t\t\t\t\"<stdout>\",\n\t\t\t\t\t\t],\n\t\t\t\t\t},\n\t\t\t\t\tonFailure: {\n\t\t\t\t\t\tother: {\n\t\t\t\t\t\t\ttype: \"run_neon_init\",\n\t\t\t\t\t\t\targs: [\n\t\t\t\t\t\t\t\t\"db\",\n\t\t\t\t\t\t\t\t\"--json\",\n\t\t\t\t\t\t\t\t\"--error\",\n\t\t\t\t\t\t\t\t\"projects-list-failed\",\n\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\n\t\t// Multiple orgs: ask user to pick\n\t\tconst orgOptions = orgs.map((o) => ({\n\t\t\tvalue: o.id,\n\t\t\tlabel: `${o.name} (${o.id})`,\n\t\t}));\n\t\tconst responseMapping: Record<string, { args: string[] }> = {};\n\t\tfor (const o of orgs) {\n\t\t\tresponseMapping[o.id] = {\n\t\t\t\targs: [\"db\", \"--json\", \"--org-id\", o.id],\n\t\t\t};\n\t\t}\n\n\t\treturn {\n\t\t\tphase: \"db\",\n\t\t\tstatus: \"select_org\",\n\t\t\tnextAction: {\n\t\t\t\ttype: \"ask_user\",\n\t\t\t\tquestion: \"Which Neon organization would you like to use?\",\n\t\t\t\toptions: orgOptions,\n\t\t\t\tresponseMapping,\n\t\t\t},\n\t\t};\n\t}\n\n\t// If org-id provided but no orgs-result, list projects directly\n\tif (options.orgId) {\n\t\treturn {\n\t\t\tphase: \"db\",\n\t\t\tstatus: \"org_selected\",\n\t\t\torg: { id: options.orgId },\n\t\t\tnextAction: {\n\t\t\t\ttype: \"run_command\",\n\t\t\t\tcommand: `${neonctlCmd()} projects list --org-id ${options.orgId} --output json`,\n\t\t\t\tdescription: \"Listing Neon projects.\",\n\t\t\t\ttimeout: 30000,\n\t\t\t\tonSuccess: {\n\t\t\t\t\ttype: \"run_neon_init\",\n\t\t\t\t\targs: [\n\t\t\t\t\t\t\"db\",\n\t\t\t\t\t\t\"--json\",\n\t\t\t\t\t\t\"--org-id\",\n\t\t\t\t\t\toptions.orgId,\n\t\t\t\t\t\t\"--projects-result\",\n\t\t\t\t\t\t\"<stdout>\",\n\t\t\t\t\t],\n\t\t\t\t},\n\t\t\t\tonFailure: {\n\t\t\t\t\tother: {\n\t\t\t\t\t\ttype: \"run_neon_init\",\n\t\t\t\t\t\targs: [\n\t\t\t\t\t\t\t\"db\",\n\t\t\t\t\t\t\t\"--json\",\n\t\t\t\t\t\t\t\"--error\",\n\t\t\t\t\t\t\t\"projects-list-failed\",\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// Default: start by listing orgs\n\treturn {\n\t\tphase: \"db\",\n\t\tstatus: \"ready\",\n\t\tnextAction: {\n\t\t\ttype: \"run_command\",\n\t\t\tcommand: `${neonctlCmd()} orgs list --output json`,\n\t\t\tdescription: \"Listing your Neon organizations.\",\n\t\t\ttimeout: 30000,\n\t\t\tonSuccess: {\n\t\t\t\ttype: \"run_neon_init\",\n\t\t\t\targs: [\"db\", \"--json\", \"--orgs-result\", \"<stdout>\"],\n\t\t\t},\n\t\t\tonFailure: {\n\t\t\t\tother: {\n\t\t\t\t\ttype: \"run_neon_init\",\n\t\t\t\t\targs: [\"db\", \"--json\", \"--error\", \"orgs-list-failed\"],\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t};\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { PhaseResponse } from "../types.js";
|
|
2
|
+
|
|
3
|
+
//#region src/lib/phases/getting-started.d.ts
|
|
4
|
+
interface GettingStartedPhaseOptions {
|
|
5
|
+
agent?: string;
|
|
6
|
+
hasConnectionString?: boolean;
|
|
7
|
+
framework?: string;
|
|
8
|
+
orm?: string;
|
|
9
|
+
migrationTool?: string;
|
|
10
|
+
migrationDir?: string;
|
|
11
|
+
/** Neon features required by the project (from .neon or template) */
|
|
12
|
+
features?: string[];
|
|
13
|
+
/** Preview mode — restricts project creation to new projects in AWS us-east */
|
|
14
|
+
preview?: boolean;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Initiates the "Get started with Neon" workflow.
|
|
18
|
+
*
|
|
19
|
+
* Steps are concrete and executable — each has a CLI command to run
|
|
20
|
+
* or a specific file operation. The agent should attempt each step
|
|
21
|
+
* in order and actually perform the action using the neonctl CLI.
|
|
22
|
+
*/
|
|
23
|
+
declare function handleGettingStartedPhase(options: GettingStartedPhaseOptions): Promise<PhaseResponse>;
|
|
24
|
+
//#endregion
|
|
25
|
+
export { GettingStartedPhaseOptions, handleGettingStartedPhase };
|
|
26
|
+
//# sourceMappingURL=getting-started.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"getting-started.d.ts","names":[],"sources":["../../../src/lib/phases/getting-started.ts"],"mappings":";;;UAIiB,0BAAA;;EAAA,mBAAA,CAAA,EAAA,OAA0B;EAoBrB,SAAA,CAAA,EAAA,MAAA;EAAyB,GAAA,CAAA,EAAA,MAAA;eACrC,CAAA,EAAA,MAAA;cACC,CAAA,EAAA,MAAA;;EAAD,QAAA,CAAA,EAAA,MAAA,EAAA;;;;;;;;;;;iBAFY,yBAAA,UACZ,6BACP,QAAQ"}
|