neon-init 0.14.0 → 0.15.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 +207 -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 +19 -11
- 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 +32 -0
- package/dist/lib/neonctl.d.ts.map +1 -0
- package/dist/lib/neonctl.js +149 -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 +188 -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 +258 -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 +195 -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 +117 -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,188 @@
|
|
|
1
|
+
import { isAuthenticated } from "../auth.js";
|
|
2
|
+
//#region src/lib/phases/auth.ts
|
|
3
|
+
const SIGNUP_COMMANDS = {
|
|
4
|
+
darwin: "open https://console.neon.tech/signup",
|
|
5
|
+
linux: "xdg-open https://console.neon.tech/signup",
|
|
6
|
+
win32: "start https://console.neon.tech/signup"
|
|
7
|
+
};
|
|
8
|
+
async function handleAuthPhase(options) {
|
|
9
|
+
const agentArgs = options.agent ? [
|
|
10
|
+
"--agent",
|
|
11
|
+
options.agent,
|
|
12
|
+
"--json"
|
|
13
|
+
] : ["--json"];
|
|
14
|
+
if (options.verify) {
|
|
15
|
+
if (await isAuthenticated()) return {
|
|
16
|
+
phase: "auth",
|
|
17
|
+
status: "verified",
|
|
18
|
+
nextAction: {
|
|
19
|
+
type: "run_neon_init",
|
|
20
|
+
args: agentArgs
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
return {
|
|
24
|
+
phase: "auth",
|
|
25
|
+
status: "not_authenticated",
|
|
26
|
+
nextAction: {
|
|
27
|
+
type: "run_neon_init",
|
|
28
|
+
args: ["auth", "--json"]
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
if (await isAuthenticated()) return {
|
|
33
|
+
phase: "auth",
|
|
34
|
+
status: "verified",
|
|
35
|
+
nextAction: {
|
|
36
|
+
type: "run_neon_init",
|
|
37
|
+
args: agentArgs
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
if (options.method === "new") return {
|
|
41
|
+
phase: "auth",
|
|
42
|
+
status: "in_progress",
|
|
43
|
+
nextAction: {
|
|
44
|
+
type: "agent_action",
|
|
45
|
+
steps: [{
|
|
46
|
+
id: "open_signup",
|
|
47
|
+
description: "Open the Neon sign-up page in the user's browser",
|
|
48
|
+
command: SIGNUP_COMMANDS[process.platform] ?? SIGNUP_COMMANDS.linux
|
|
49
|
+
}, {
|
|
50
|
+
id: "wait_for_signup",
|
|
51
|
+
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.'"
|
|
52
|
+
}],
|
|
53
|
+
onComplete: {
|
|
54
|
+
type: "run_neon_init",
|
|
55
|
+
args: [
|
|
56
|
+
"auth",
|
|
57
|
+
"--json",
|
|
58
|
+
"--method",
|
|
59
|
+
"existing"
|
|
60
|
+
]
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
if (options.method === "existing") return {
|
|
65
|
+
phase: "auth",
|
|
66
|
+
status: "in_progress",
|
|
67
|
+
nextAction: {
|
|
68
|
+
type: "run_command",
|
|
69
|
+
command: "CI= npx -y neonctl auth",
|
|
70
|
+
description: "This will open your browser for Neon OAuth sign-in.",
|
|
71
|
+
timeout: 12e4,
|
|
72
|
+
onSuccess: {
|
|
73
|
+
type: "run_neon_init",
|
|
74
|
+
args: [
|
|
75
|
+
"auth",
|
|
76
|
+
"--json",
|
|
77
|
+
"--verify"
|
|
78
|
+
]
|
|
79
|
+
},
|
|
80
|
+
onFailure: {
|
|
81
|
+
"2": {
|
|
82
|
+
type: "ask_user",
|
|
83
|
+
question: "The sign-in timed out. Did you complete the sign-in in your browser?",
|
|
84
|
+
options: ["yes_retry", "need_help"],
|
|
85
|
+
responseMapping: {
|
|
86
|
+
yes_retry: { args: [
|
|
87
|
+
"auth",
|
|
88
|
+
"--json",
|
|
89
|
+
"--method",
|
|
90
|
+
"existing"
|
|
91
|
+
] },
|
|
92
|
+
need_help: { args: [
|
|
93
|
+
"auth",
|
|
94
|
+
"--json",
|
|
95
|
+
"--method",
|
|
96
|
+
"new"
|
|
97
|
+
] }
|
|
98
|
+
}
|
|
99
|
+
},
|
|
100
|
+
other: {
|
|
101
|
+
type: "run_neon_init",
|
|
102
|
+
args: ["auth", "--json"]
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
return {
|
|
108
|
+
phase: "auth",
|
|
109
|
+
status: "required",
|
|
110
|
+
nextAction: {
|
|
111
|
+
type: "ask_user",
|
|
112
|
+
question: "Do you have an existing Neon account, or do you need to create one?",
|
|
113
|
+
options: [{
|
|
114
|
+
value: "existing_account",
|
|
115
|
+
label: "I have an existing Neon account"
|
|
116
|
+
}, {
|
|
117
|
+
value: "new_account",
|
|
118
|
+
label: "I need to create a new account"
|
|
119
|
+
}],
|
|
120
|
+
context: "Neon is a serverless Postgres provider. A free account is required to continue.",
|
|
121
|
+
responseMapping: {
|
|
122
|
+
existing_account: { action: {
|
|
123
|
+
type: "run_command",
|
|
124
|
+
command: "CI= npx -y neonctl auth",
|
|
125
|
+
description: "This will open your browser for Neon OAuth sign-in.",
|
|
126
|
+
timeout: 12e4,
|
|
127
|
+
onSuccess: {
|
|
128
|
+
type: "run_neon_init",
|
|
129
|
+
args: [
|
|
130
|
+
"auth",
|
|
131
|
+
"--json",
|
|
132
|
+
"--verify"
|
|
133
|
+
]
|
|
134
|
+
},
|
|
135
|
+
onFailure: {
|
|
136
|
+
"2": {
|
|
137
|
+
type: "ask_user",
|
|
138
|
+
question: "The sign-in timed out. Did you complete the sign-in in your browser?",
|
|
139
|
+
options: ["yes_retry", "need_help"],
|
|
140
|
+
responseMapping: {
|
|
141
|
+
yes_retry: { args: [
|
|
142
|
+
"auth",
|
|
143
|
+
"--json",
|
|
144
|
+
"--method",
|
|
145
|
+
"existing"
|
|
146
|
+
] },
|
|
147
|
+
need_help: { args: [
|
|
148
|
+
"auth",
|
|
149
|
+
"--json",
|
|
150
|
+
"--method",
|
|
151
|
+
"new"
|
|
152
|
+
] }
|
|
153
|
+
}
|
|
154
|
+
},
|
|
155
|
+
other: {
|
|
156
|
+
type: "run_neon_init",
|
|
157
|
+
args: ["auth", "--json"]
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
} },
|
|
161
|
+
new_account: { action: {
|
|
162
|
+
type: "agent_action",
|
|
163
|
+
steps: [{
|
|
164
|
+
id: "open_signup",
|
|
165
|
+
description: "Open the Neon sign-up page in the user's browser",
|
|
166
|
+
command: SIGNUP_COMMANDS[process.platform] ?? SIGNUP_COMMANDS.linux
|
|
167
|
+
}, {
|
|
168
|
+
id: "wait_for_signup",
|
|
169
|
+
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.'"
|
|
170
|
+
}],
|
|
171
|
+
onComplete: {
|
|
172
|
+
type: "run_neon_init",
|
|
173
|
+
args: [
|
|
174
|
+
"auth",
|
|
175
|
+
"--json",
|
|
176
|
+
"--method",
|
|
177
|
+
"existing"
|
|
178
|
+
]
|
|
179
|
+
}
|
|
180
|
+
} }
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
//#endregion
|
|
186
|
+
export { handleAuthPhase };
|
|
187
|
+
|
|
188
|
+
//# 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 type { PhaseResponse } from \"../types.js\";\n\nconst SIGNUP_COMMANDS: Record<string, string> = {\n\tdarwin: \"open https://console.neon.tech/signup\",\n\tlinux: \"xdg-open https://console.neon.tech/signup\",\n\twin32: \"start https://console.neon.tech/signup\",\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\tSIGNUP_COMMANDS[process.platform] ?? SIGNUP_COMMANDS.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: \"CI= npx -y neonctl 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 = SIGNUP_COMMANDS[process.platform] ?? SIGNUP_COMMANDS.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: \"CI= npx -y neonctl 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":";;AAGA,MAAM,kBAA0C;CAC/C,QAAQ;CACR,OAAO;CACP,OAAO;AACR;AAQA,eAAsB,gBACrB,SACyB;CACzB,MAAM,YAAY,QAAQ,QACvB;EAAC;EAAW,QAAQ;EAAO;CAAQ,IACnC,CAAC,QAAQ;CAGZ,IAAI,QAAQ,QAAQ;EAEnB,IAAI,MADiB,gBAAgB,GAIpC,OAAO;GACN,OAAO;GACP,QAAQ;GACR,YAAY;IACX,MAAM;IACN,MAAM;GACP;EACD;EAED,OAAO;GACN,OAAO;GACP,QAAQ;GACR,YAAY;IACX,MAAM;IACN,MAAM,CAAC,QAAQ,QAAQ;GACxB;EACD;CACD;CAIA,IAAI,MADiB,gBAAgB,GAEpC,OAAO;EACN,OAAO;EACP,QAAQ;EACR,YAAY;GACX,MAAM;GACN,MAAM;EACP;CACD;CAID,IAAI,QAAQ,WAAW,OAGtB,OAAO;EACN,OAAO;EACP,QAAQ;EACR,YAAY;GACX,MAAM;GACN,OAAO,CACN;IACC,IAAI;IACJ,aACC;IACD,SAXH,gBAAgB,QAAQ,aAAa,gBAAgB;GAYnD,GACA;IACC,IAAI;IACJ,aACC;GACF,CACD;GACA,YAAY;IACX,MAAM;IACN,MAAM;KAAC;KAAQ;KAAU;KAAY;IAAU;GAChD;EACD;CACD;CAID,IAAI,QAAQ,WAAW,YACtB,OAAO;EACN,OAAO;EACP,QAAQ;EACR,YAAY;GACX,MAAM;GACN,SAAS;GACT,aACC;GACD,SAAS;GACT,WAAW;IACV,MAAM;IACN,MAAM;KAAC;KAAQ;KAAU;IAAU;GACpC;GACA,WAAW;IACV,KAAK;KACJ,MAAM;KACN,UACC;KACD,SAAS,CAAC,aAAa,WAAW;KAClC,iBAAiB;MAChB,WAAW,EACV,MAAM;OACL;OACA;OACA;OACA;MACD,EACD;MACA,WAAW,EACV,MAAM;OAAC;OAAQ;OAAU;OAAY;MAAK,EAC3C;KACD;IACD;IACA,OAAO;KACN,MAAM;KACN,MAAM,CAAC,QAAQ,QAAQ;IACxB;GACD;EACD;CACD;CAMD,OAAO;EACN,OAAO;EACP,QAAQ;EACR,YAAY;GACX,MAAM;GACN,UACC;GACD,SAAS,CACR;IACC,OAAO;IACP,OAAO;GACR,GACA;IACC,OAAO;IACP,OAAO;GACR,CACD;GACA,SACC;GACD,iBAAiB;IAChB,kBAAkB,EACjB,QAAQ;KACP,MAAM;KACN,SAAS;KACT,aACC;KACD,SAAS;KACT,WAAW;MACV,MAAM;MACN,MAAM;OAAC;OAAQ;OAAU;MAAU;KACpC;KACA,WAAW;MACV,KAAK;OACJ,MAAM;OACN,UACC;OACD,SAAS,CAAC,aAAa,WAAW;OAClC,iBAAiB;QAChB,WAAW,EACV,MAAM;SACL;SACA;SACA;SACA;QACD,EACD;QACA,WAAW,EACV,MAAM;SACL;SACA;SACA;SACA;QACD,EACD;OACD;MACD;MACA,OAAO;OACN,MAAM;OACN,MAAM,CAAC,QAAQ,QAAQ;MACxB;KACD;IACD,EACD;IACA,aAAa,EACZ,QAAQ;KACP,MAAM;KACN,OAAO,CACN;MACC,IAAI;MACJ,aACC;MACD,SAxES,gBAAgB,QAAQ,aAAa,gBAAgB;KAyE/D,GACA;MACC,IAAI;MACJ,aACC;KACF,CACD;KACA,YAAY;MACX,MAAM;MACN,MAAM;OAAC;OAAQ;OAAU;OAAY;MAAU;KAChD;IACD,EACD;GACD;EACD;CACD;AACD"}
|
|
@@ -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":";;;UAeiB,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,258 @@
|
|
|
1
|
+
import { SKILL_REFERENCE_URLS } from "../skills.js";
|
|
2
|
+
//#region src/lib/phases/db.ts
|
|
3
|
+
/**
|
|
4
|
+
* Validates that an ID contains only safe characters for shell interpolation.
|
|
5
|
+
* Neon org/project IDs are typically UUIDs or slug-like strings.
|
|
6
|
+
*/
|
|
7
|
+
function assertSafeId(value, label) {
|
|
8
|
+
if (!/^[\w.:-]+$/.test(value)) throw new Error(`Invalid ${label}: "${value}". Expected alphanumeric, hyphens, underscores, dots, or colons.`);
|
|
9
|
+
}
|
|
10
|
+
async function handleDbPhase(options) {
|
|
11
|
+
const agentArgs = options.agent ? [
|
|
12
|
+
"--agent",
|
|
13
|
+
options.agent,
|
|
14
|
+
"--json"
|
|
15
|
+
] : ["--json"];
|
|
16
|
+
if (options.projectId) assertSafeId(options.projectId, "project ID");
|
|
17
|
+
if (options.orgId) assertSafeId(options.orgId, "org ID");
|
|
18
|
+
if (options.error) return {
|
|
19
|
+
phase: "db",
|
|
20
|
+
status: "error",
|
|
21
|
+
error: options.error,
|
|
22
|
+
nextAction: {
|
|
23
|
+
type: "ask_user",
|
|
24
|
+
question: `An error occurred during database setup: ${options.error}. Would you like to try again or skip this step?`,
|
|
25
|
+
options: [{
|
|
26
|
+
value: "retry",
|
|
27
|
+
label: "Try again"
|
|
28
|
+
}, {
|
|
29
|
+
value: "skip",
|
|
30
|
+
label: "Skip database setup"
|
|
31
|
+
}],
|
|
32
|
+
responseMapping: {
|
|
33
|
+
retry: { args: ["db", "--json"] },
|
|
34
|
+
skip: { args: agentArgs }
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
if (options.projectId) return {
|
|
39
|
+
phase: "db",
|
|
40
|
+
status: "project_ready",
|
|
41
|
+
project: { id: options.projectId },
|
|
42
|
+
nextAction: {
|
|
43
|
+
type: "agent_action",
|
|
44
|
+
prerequisite: SKILL_REFERENCE_URLS.connectionMethods,
|
|
45
|
+
steps: [
|
|
46
|
+
{
|
|
47
|
+
id: "get_connection_string",
|
|
48
|
+
description: "Get the database connection string",
|
|
49
|
+
command: `CI= npx -y neonctl connection-string --project-id ${options.projectId}`
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
id: "store_env",
|
|
53
|
+
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."
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
id: "detect_framework",
|
|
57
|
+
description: "Examine the project to determine the framework (Next.js, Remix, Express, etc.) and ORM (Prisma, Drizzle, raw SQL) in use."
|
|
58
|
+
}
|
|
59
|
+
],
|
|
60
|
+
onComplete: {
|
|
61
|
+
type: "run_neon_init",
|
|
62
|
+
args: agentArgs
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
if (options.projectsResult) {
|
|
67
|
+
let projects;
|
|
68
|
+
try {
|
|
69
|
+
const parsed = JSON.parse(options.projectsResult);
|
|
70
|
+
projects = Array.isArray(parsed.projects) ? parsed.projects : Array.isArray(parsed) ? parsed : [];
|
|
71
|
+
} catch {
|
|
72
|
+
projects = [];
|
|
73
|
+
}
|
|
74
|
+
const orgIdArgs = options.orgId ? ["--org-id", options.orgId] : [];
|
|
75
|
+
if (projects.length === 0) return {
|
|
76
|
+
phase: "db",
|
|
77
|
+
status: "no_projects",
|
|
78
|
+
nextAction: {
|
|
79
|
+
type: "ask_user",
|
|
80
|
+
question: "You don't have any Neon projects yet. What would you like to name your new project?",
|
|
81
|
+
options: [{
|
|
82
|
+
value: "create",
|
|
83
|
+
label: "Create a new project (provide a name)"
|
|
84
|
+
}],
|
|
85
|
+
context: "The agent should ask the user for a project name, then run: CI= npx -y neonctl projects create --name <name> --output json" + (options.orgId ? ` --org-id ${options.orgId}` : "") + " and pass the result back.",
|
|
86
|
+
responseMapping: { create: { args: [
|
|
87
|
+
"db",
|
|
88
|
+
"--json",
|
|
89
|
+
...orgIdArgs,
|
|
90
|
+
"--project-id",
|
|
91
|
+
"<created-project-id>"
|
|
92
|
+
] } }
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
const projectOptions = projects.map((p) => ({
|
|
96
|
+
value: p.id,
|
|
97
|
+
label: `${p.name} (${p.id})`
|
|
98
|
+
}));
|
|
99
|
+
projectOptions.push({
|
|
100
|
+
value: "create_new",
|
|
101
|
+
label: "Create a new project"
|
|
102
|
+
});
|
|
103
|
+
const responseMapping = {};
|
|
104
|
+
for (const p of projects) responseMapping[p.id] = { args: [
|
|
105
|
+
"db",
|
|
106
|
+
"--json",
|
|
107
|
+
...orgIdArgs,
|
|
108
|
+
"--project-id",
|
|
109
|
+
p.id
|
|
110
|
+
] };
|
|
111
|
+
responseMapping.create_new = { args: [
|
|
112
|
+
"db",
|
|
113
|
+
"--json",
|
|
114
|
+
...orgIdArgs,
|
|
115
|
+
"--project-id",
|
|
116
|
+
"<created-project-id>"
|
|
117
|
+
] };
|
|
118
|
+
return {
|
|
119
|
+
phase: "db",
|
|
120
|
+
status: "select_project",
|
|
121
|
+
nextAction: {
|
|
122
|
+
type: "ask_user",
|
|
123
|
+
question: "Which Neon project would you like to use?",
|
|
124
|
+
options: projectOptions,
|
|
125
|
+
context: "If the user wants to create a new project, ask for a name then run: CI= npx -y neonctl projects create --name <name> --output json and use the returned project id.",
|
|
126
|
+
responseMapping
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
if (options.orgsResult) {
|
|
131
|
+
let orgs;
|
|
132
|
+
try {
|
|
133
|
+
const parsed = JSON.parse(options.orgsResult);
|
|
134
|
+
orgs = Array.isArray(parsed.organizations) ? parsed.organizations : Array.isArray(parsed) ? parsed : [];
|
|
135
|
+
} catch {
|
|
136
|
+
orgs = [];
|
|
137
|
+
}
|
|
138
|
+
const orgId = options.orgId ?? (orgs.length === 1 ? orgs[0].id : null);
|
|
139
|
+
if (orgId) {
|
|
140
|
+
assertSafeId(orgId, "org ID");
|
|
141
|
+
return {
|
|
142
|
+
phase: "db",
|
|
143
|
+
status: "org_selected",
|
|
144
|
+
org: { id: orgId },
|
|
145
|
+
nextAction: {
|
|
146
|
+
type: "run_command",
|
|
147
|
+
command: `CI= npx -y neonctl projects list --org-id ${orgId} --output json`,
|
|
148
|
+
description: "Listing Neon projects.",
|
|
149
|
+
timeout: 3e4,
|
|
150
|
+
onSuccess: {
|
|
151
|
+
type: "run_neon_init",
|
|
152
|
+
args: [
|
|
153
|
+
"db",
|
|
154
|
+
"--json",
|
|
155
|
+
"--org-id",
|
|
156
|
+
orgId,
|
|
157
|
+
"--projects-result",
|
|
158
|
+
"<stdout>"
|
|
159
|
+
]
|
|
160
|
+
},
|
|
161
|
+
onFailure: { other: {
|
|
162
|
+
type: "run_neon_init",
|
|
163
|
+
args: [
|
|
164
|
+
"db",
|
|
165
|
+
"--json",
|
|
166
|
+
"--error",
|
|
167
|
+
"projects-list-failed"
|
|
168
|
+
]
|
|
169
|
+
} }
|
|
170
|
+
}
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
const orgOptions = orgs.map((o) => ({
|
|
174
|
+
value: o.id,
|
|
175
|
+
label: `${o.name} (${o.id})`
|
|
176
|
+
}));
|
|
177
|
+
const responseMapping = {};
|
|
178
|
+
for (const o of orgs) responseMapping[o.id] = { args: [
|
|
179
|
+
"db",
|
|
180
|
+
"--json",
|
|
181
|
+
"--org-id",
|
|
182
|
+
o.id
|
|
183
|
+
] };
|
|
184
|
+
return {
|
|
185
|
+
phase: "db",
|
|
186
|
+
status: "select_org",
|
|
187
|
+
nextAction: {
|
|
188
|
+
type: "ask_user",
|
|
189
|
+
question: "Which Neon organization would you like to use?",
|
|
190
|
+
options: orgOptions,
|
|
191
|
+
responseMapping
|
|
192
|
+
}
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
if (options.orgId) return {
|
|
196
|
+
phase: "db",
|
|
197
|
+
status: "org_selected",
|
|
198
|
+
org: { id: options.orgId },
|
|
199
|
+
nextAction: {
|
|
200
|
+
type: "run_command",
|
|
201
|
+
command: `CI= npx -y neonctl projects list --org-id ${options.orgId} --output json`,
|
|
202
|
+
description: "Listing Neon projects.",
|
|
203
|
+
timeout: 3e4,
|
|
204
|
+
onSuccess: {
|
|
205
|
+
type: "run_neon_init",
|
|
206
|
+
args: [
|
|
207
|
+
"db",
|
|
208
|
+
"--json",
|
|
209
|
+
"--org-id",
|
|
210
|
+
options.orgId,
|
|
211
|
+
"--projects-result",
|
|
212
|
+
"<stdout>"
|
|
213
|
+
]
|
|
214
|
+
},
|
|
215
|
+
onFailure: { other: {
|
|
216
|
+
type: "run_neon_init",
|
|
217
|
+
args: [
|
|
218
|
+
"db",
|
|
219
|
+
"--json",
|
|
220
|
+
"--error",
|
|
221
|
+
"projects-list-failed"
|
|
222
|
+
]
|
|
223
|
+
} }
|
|
224
|
+
}
|
|
225
|
+
};
|
|
226
|
+
return {
|
|
227
|
+
phase: "db",
|
|
228
|
+
status: "ready",
|
|
229
|
+
nextAction: {
|
|
230
|
+
type: "run_command",
|
|
231
|
+
command: "CI= npx -y neonctl orgs list --output json",
|
|
232
|
+
description: "Listing your Neon organizations.",
|
|
233
|
+
timeout: 3e4,
|
|
234
|
+
onSuccess: {
|
|
235
|
+
type: "run_neon_init",
|
|
236
|
+
args: [
|
|
237
|
+
"db",
|
|
238
|
+
"--json",
|
|
239
|
+
"--orgs-result",
|
|
240
|
+
"<stdout>"
|
|
241
|
+
]
|
|
242
|
+
},
|
|
243
|
+
onFailure: { other: {
|
|
244
|
+
type: "run_neon_init",
|
|
245
|
+
args: [
|
|
246
|
+
"db",
|
|
247
|
+
"--json",
|
|
248
|
+
"--error",
|
|
249
|
+
"orgs-list-failed"
|
|
250
|
+
]
|
|
251
|
+
} }
|
|
252
|
+
}
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
//#endregion
|
|
256
|
+
export { handleDbPhase };
|
|
257
|
+
|
|
258
|
+
//# sourceMappingURL=db.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"db.js","names":[],"sources":["../../../src/lib/phases/db.ts"],"sourcesContent":["import { 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: `CI= npx -y neonctl 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: CI= npx -y neonctl 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:\n\t\t\t\t\t\"If the user wants to create a new project, ask for a name then run: CI= npx -y neonctl 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: `CI= npx -y neonctl 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: `CI= npx -y neonctl 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: \"CI= npx -y neonctl 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":";;;UAGiB,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"}
|