neon 3.0.0 → 3.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +54 -0
- package/dist/_shared/auth_selection.js +76 -79
- package/dist/_shared/credentials.js +166 -187
- package/dist/_shared/env-core/env.js +354 -517
- package/dist/_shared/env-core/reuse-secrets.js +159 -203
- package/dist/_shared/paths.js +129 -126
- package/dist/_shared/profiles.js +192 -242
- package/dist/_shared/secure_file.js +36 -38
- package/dist/_virtual/_rolldown/runtime.js +13 -0
- package/dist/analytics.js +163 -207
- package/dist/api.js +815 -758
- package/dist/auth.js +121 -141
- package/dist/auth_context.js +39 -53
- package/dist/cli.js +4 -7
- package/dist/commands/api.js +220 -250
- package/dist/commands/api_keys.js +251 -314
- package/dist/commands/auth.js +283 -328
- package/dist/commands/bootstrap.js +372 -437
- package/dist/commands/branches.js +304 -455
- package/dist/commands/bucket.js +374 -514
- package/dist/commands/checkout.js +213 -298
- package/dist/commands/config.js +573 -690
- package/dist/commands/connection_string.js +137 -165
- package/dist/commands/data_api.js +238 -260
- package/dist/commands/databases.js +67 -76
- package/dist/commands/deploy.js +31 -25
- package/dist/commands/dev.js +639 -719
- package/dist/commands/diff.js +156 -200
- package/dist/commands/env.js +243 -303
- package/dist/commands/functions.js +275 -355
- package/dist/commands/index.js +70 -65
- package/dist/commands/init.js +84 -119
- package/dist/commands/inspect.js +55 -55
- package/dist/commands/ip_allow.js +88 -120
- package/dist/commands/link.js +874 -1019
- package/dist/commands/logs.js +291 -0
- package/dist/commands/neon_auth.js +725 -933
- package/dist/commands/operations.js +34 -25
- package/dist/commands/orgs.js +28 -18
- package/dist/commands/profile.js +614 -845
- package/dist/commands/projects.js +313 -373
- package/dist/commands/psql.js +60 -58
- package/dist/commands/roles.js +55 -58
- package/dist/commands/schema_diff.js +87 -131
- package/dist/commands/set_context.js +34 -26
- package/dist/commands/snapshots.js +288 -413
- package/dist/commands/status.js +41 -37
- package/dist/commands/user.js +21 -10
- package/dist/commands/vpc_endpoints.js +85 -113
- package/dist/config.js +7 -6
- package/dist/config_format.js +50 -66
- package/dist/config_template.js +128 -157
- package/dist/context.js +183 -235
- package/dist/current_branch_fast_path.js +40 -49
- package/dist/dev/env.js +313 -394
- package/dist/dev/functions.js +54 -68
- package/dist/dev/inputs.js +46 -58
- package/dist/dev/runtime.js +135 -164
- package/dist/dev/websocket.js +766 -959
- package/dist/env.js +27 -33
- package/dist/env_file.js +118 -132
- package/dist/env_services.js +36 -38
- package/dist/errors.js +57 -68
- package/dist/functions_api.js +45 -43
- package/dist/help.js +189 -140
- package/dist/index.js +182 -257
- package/dist/init/agents.js +137 -118
- package/dist/init/auth.js +58 -68
- package/dist/init/bootstrap.js +325 -396
- package/dist/init/build_config.js +4 -2
- package/dist/init/detect_agent.js +56 -101
- package/dist/init/editors.js +35 -52
- package/dist/init/enrich_output.js +51 -66
- package/dist/init/extension.js +134 -171
- package/dist/init/inspect.js +179 -266
- package/dist/init/interactive.js +510 -622
- package/dist/init/neonctl.js +117 -168
- package/dist/init/orchestrate.js +157 -173
- package/dist/init/phases/auth.js +188 -202
- package/dist/init/phases/cleanup.js +23 -23
- package/dist/init/phases/db.js +251 -277
- package/dist/init/phases/getting_started.js +213 -223
- package/dist/init/phases/mcp.js +174 -224
- package/dist/init/phases/migrations.js +247 -248
- package/dist/init/phases/neon_auth.js +114 -133
- package/dist/init/phases/setup.js +546 -703
- package/dist/init/phases/skills.js +75 -86
- package/dist/init/phases/status.js +72 -67
- package/dist/init/resolve_context.js +102 -99
- package/dist/init/route_command.js +91 -98
- package/dist/init/skills.js +174 -218
- package/dist/init/vsix.js +77 -99
- package/dist/log.js +17 -16
- package/dist/neon_services.js +104 -129
- package/dist/parameters.gen.js +481 -471
- package/dist/pkg.js +17 -19
- package/dist/profile_keys.js +44 -47
- package/dist/psql/cli.js +44 -47
- package/dist/psql/command/cmd_cond.js +231 -406
- package/dist/psql/command/cmd_connect.js +557 -764
- package/dist/psql/command/cmd_copy.js +727 -983
- package/dist/psql/command/cmd_describe.js +1499 -1688
- package/dist/psql/command/cmd_format.js +733 -905
- package/dist/psql/command/cmd_io.js +1293 -2082
- package/dist/psql/command/cmd_lo.js +297 -359
- package/dist/psql/command/cmd_meta.js +727 -878
- package/dist/psql/command/cmd_misc.js +138 -172
- package/dist/psql/command/cmd_pipeline.js +547 -1099
- package/dist/psql/command/cmd_restrict.js +119 -155
- package/dist/psql/command/cmd_show.js +529 -688
- package/dist/psql/command/dispatch.js +261 -325
- package/dist/psql/command/inputQueue.js +35 -33
- package/dist/psql/command/shared.js +49 -63
- package/dist/psql/complete/filenames.js +90 -133
- package/dist/psql/complete/index.js +59 -97
- package/dist/psql/complete/matcher.js +236 -300
- package/dist/psql/complete/psqlVars.js +218 -223
- package/dist/psql/complete/queries.js +159 -177
- package/dist/psql/complete/rules.js +1493 -2299
- package/dist/psql/core/common.js +762 -1180
- package/dist/psql/core/help.js +456 -546
- package/dist/psql/core/mainloop.js +692 -1302
- package/dist/psql/core/prompt.js +391 -408
- package/dist/psql/core/settings.js +429 -644
- package/dist/psql/core/sqlHelp.js +480 -554
- package/dist/psql/core/startup.js +626 -815
- package/dist/psql/core/syncVars.js +67 -110
- package/dist/psql/core/variables.js +156 -278
- package/dist/psql/describe/formatters.js +884 -1285
- package/dist/psql/describe/processNamePattern.js +173 -260
- package/dist/psql/describe/queries.js +1368 -2403
- package/dist/psql/describe/versionGate.js +32 -41
- package/dist/psql/index.js +1414 -1927
- package/dist/psql/io/history.js +232 -271
- package/dist/psql/io/input.js +103 -108
- package/dist/psql/io/lineEditor/buffer.js +238 -319
- package/dist/psql/io/lineEditor/complete.js +135 -213
- package/dist/psql/io/lineEditor/filename.js +139 -148
- package/dist/psql/io/lineEditor/index.js +653 -870
- package/dist/psql/io/lineEditor/keymap.js +544 -702
- package/dist/psql/io/lineEditor/vt100.js +294 -341
- package/dist/psql/io/pgpass.js +158 -187
- package/dist/psql/io/pgservice.js +146 -183
- package/dist/psql/io/psqlrc.js +328 -403
- package/dist/psql/print/aligned.js +1020 -1683
- package/dist/psql/print/asciidoc.js +180 -214
- package/dist/psql/print/crosstab.js +281 -442
- package/dist/psql/print/csv.js +48 -70
- package/dist/psql/print/html.js +195 -226
- package/dist/psql/print/json.js +75 -88
- package/dist/psql/print/latex.js +291 -364
- package/dist/psql/print/pager.js +171 -242
- package/dist/psql/print/troff.js +194 -226
- package/dist/psql/print/unaligned.js +69 -95
- package/dist/psql/print/units.js +167 -169
- package/dist/psql/scanner/slash.js +428 -483
- package/dist/psql/scanner/sql.js +445 -889
- package/dist/psql/scanner/stringutils.js +309 -379
- package/dist/psql/types/index.js +2 -7
- package/dist/psql/types/scanner.js +25 -22
- package/dist/psql/wire/connection.js +2042 -2803
- package/dist/psql/wire/copy.js +84 -100
- package/dist/psql/wire/notify.js +39 -59
- package/dist/psql/wire/pipeline.js +305 -518
- package/dist/psql/wire/protocol.js +349 -417
- package/dist/psql/wire/sasl.js +180 -265
- package/dist/psql/wire/tls.js +400 -561
- package/dist/storage_api.js +115 -129
- package/dist/test_utils/fixtures.js +94 -113
- package/dist/test_utils/oauth_server.js +10 -7
- package/dist/test_utils/project_dir.js +33 -0
- package/dist/utils/ai_gateway_notice.js +131 -162
- package/dist/utils/api_enums.js +21 -28
- package/dist/utils/auth.js +10 -4
- package/dist/utils/branch_notice.js +20 -19
- package/dist/utils/branch_picker.js +83 -89
- package/dist/utils/cli_name.js +15 -12
- package/dist/utils/compute_units.js +20 -27
- package/dist/utils/config_diff.js +127 -158
- package/dist/utils/enrichers.js +95 -148
- package/dist/utils/esbuild.js +130 -189
- package/dist/utils/flags.js +35 -47
- package/dist/utils/formats.js +8 -15
- package/dist/utils/git_diff.js +69 -80
- package/dist/utils/inspect_db.js +101 -143
- package/dist/utils/inspect_queries.js +179 -142
- package/dist/utils/middlewares.js +37 -44
- package/dist/utils/openapi.js +87 -99
- package/dist/utils/package_manager.js +312 -110
- package/dist/utils/point_in_time.js +49 -53
- package/dist/utils/psql.js +89 -106
- package/dist/utils/service_picker.js +55 -58
- package/dist/utils/string.js +5 -5
- package/dist/utils/ui.js +38 -55
- package/dist/utils/write_sync.js +26 -35
- package/dist/utils/zip.js +4 -3
- package/dist/writer.js +67 -87
- package/package.json +7 -5
package/dist/init/neonctl.js
CHANGED
|
@@ -1,184 +1,133 @@
|
|
|
1
|
+
import { globalInstallCommand, resolveInvokingPackageManager } from "../utils/package_manager.js";
|
|
1
2
|
import { lstatSync } from "node:fs";
|
|
2
3
|
import { execa } from "execa";
|
|
4
|
+
//#region src/init/neonctl.ts
|
|
3
5
|
/**
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
6
|
+
* Returns the Neon CLI command prefix: "CI= npx -y neon".
|
|
7
|
+
*
|
|
8
|
+
* The CLI reads NEON_API_HOST and NEON_OAUTH_HOST from the environment
|
|
9
|
+
* directly, so no extra flags are needed. The `neon` package ships both the
|
|
10
|
+
* `neon` and `neonctl` binaries; we surface the cleaner `neon` command in the
|
|
11
|
+
* examples emitted to users and agents.
|
|
12
|
+
*
|
|
13
|
+
* Usage: `${neonctlCmd()} orgs list --output json`
|
|
14
|
+
*/
|
|
15
|
+
function neonctlCmd() {
|
|
16
|
+
return "CI= npx -y neon";
|
|
15
17
|
}
|
|
16
18
|
/**
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
*
|
|
21
|
-
* Falls back to "npm" if detection fails.
|
|
22
|
-
*/
|
|
23
|
-
export function detectPackageManager() {
|
|
24
|
-
const ua = process.env.npm_config_user_agent;
|
|
25
|
-
if (ua) {
|
|
26
|
-
if (ua.startsWith("pnpm/"))
|
|
27
|
-
return "pnpm";
|
|
28
|
-
if (ua.startsWith("yarn/"))
|
|
29
|
-
return "yarn";
|
|
30
|
-
if (ua.startsWith("bun/"))
|
|
31
|
-
return "bun";
|
|
32
|
-
}
|
|
33
|
-
return "npm";
|
|
34
|
-
}
|
|
35
|
-
/**
|
|
36
|
-
* Returns the global install command for a given package manager.
|
|
37
|
-
*/
|
|
38
|
-
function globalInstallArgs(pm, pkg) {
|
|
39
|
-
switch (pm) {
|
|
40
|
-
case "pnpm":
|
|
41
|
-
return { command: "pnpm", args: ["add", "-g", pkg] };
|
|
42
|
-
case "yarn":
|
|
43
|
-
return { command: "yarn", args: ["global", "add", pkg] };
|
|
44
|
-
case "bun":
|
|
45
|
-
return { command: "bun", args: ["add", "-g", pkg] };
|
|
46
|
-
default:
|
|
47
|
-
return { command: "npm", args: ["install", "-g", pkg] };
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
/**
|
|
51
|
-
* Gets the currently available neonctl version.
|
|
52
|
-
* Tries the global binary first, then falls back to npx.
|
|
53
|
-
*/
|
|
19
|
+
* Gets the currently available neonctl version.
|
|
20
|
+
* Tries the global binary first, then falls back to npx.
|
|
21
|
+
*/
|
|
54
22
|
async function getNeonctlVersion() {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
return match[1];
|
|
64
|
-
}
|
|
65
|
-
catch {
|
|
66
|
-
// Not globally installed — that's fine
|
|
67
|
-
}
|
|
68
|
-
return null;
|
|
23
|
+
try {
|
|
24
|
+
const match = (await execa("neonctl", ["--version"], {
|
|
25
|
+
stdio: "pipe",
|
|
26
|
+
timeout: 5e3
|
|
27
|
+
})).stdout.trim().match(/(\d+\.\d+\.\d+)/);
|
|
28
|
+
if (match) return match[1];
|
|
29
|
+
} catch {}
|
|
30
|
+
return null;
|
|
69
31
|
}
|
|
70
32
|
/**
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
33
|
+
* Checks whether the neonctl CLI is globally installed and whether it's up to date.
|
|
34
|
+
*/
|
|
35
|
+
async function checkNeonctl() {
|
|
36
|
+
const currentVersion = await getNeonctlVersion();
|
|
37
|
+
if (!currentVersion) return {
|
|
38
|
+
installed: false,
|
|
39
|
+
currentVersion: null,
|
|
40
|
+
latestVersion: null,
|
|
41
|
+
needsUpdate: true
|
|
42
|
+
};
|
|
43
|
+
let latestVersion = null;
|
|
44
|
+
try {
|
|
45
|
+
latestVersion = (await execa("npm", [
|
|
46
|
+
"view",
|
|
47
|
+
"neonctl",
|
|
48
|
+
"version"
|
|
49
|
+
], {
|
|
50
|
+
stdio: "pipe",
|
|
51
|
+
timeout: 1e4
|
|
52
|
+
})).stdout.trim();
|
|
53
|
+
} catch {
|
|
54
|
+
return {
|
|
55
|
+
installed: true,
|
|
56
|
+
currentVersion,
|
|
57
|
+
latestVersion: null,
|
|
58
|
+
needsUpdate: false
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
const needsUpdate = currentVersion !== null && latestVersion !== null && currentVersion !== latestVersion && isOlderVersion(currentVersion, latestVersion);
|
|
62
|
+
return {
|
|
63
|
+
installed: true,
|
|
64
|
+
currentVersion,
|
|
65
|
+
latestVersion,
|
|
66
|
+
needsUpdate
|
|
67
|
+
};
|
|
106
68
|
}
|
|
107
69
|
function isOlderVersion(current, latest) {
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
}
|
|
116
|
-
return false;
|
|
70
|
+
const c = current.split(".").map(Number);
|
|
71
|
+
const l = latest.split(".").map(Number);
|
|
72
|
+
for (let i = 0; i < 3; i++) {
|
|
73
|
+
if ((c[i] ?? 0) < (l[i] ?? 0)) return true;
|
|
74
|
+
if ((c[i] ?? 0) > (l[i] ?? 0)) return false;
|
|
75
|
+
}
|
|
76
|
+
return false;
|
|
117
77
|
}
|
|
118
78
|
/**
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
79
|
+
* Checks if neonctl is installed via a local dev symlink.
|
|
80
|
+
* If so, skip install/update — the developer manages it manually.
|
|
81
|
+
*/
|
|
122
82
|
function isLocalDevSymlink() {
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
const stat = lstatSync(candidate);
|
|
134
|
-
if (stat.isSymbolicLink())
|
|
135
|
-
return true;
|
|
136
|
-
}
|
|
137
|
-
catch {
|
|
138
|
-
// path doesn't exist
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
return false;
|
|
142
|
-
}
|
|
143
|
-
catch {
|
|
144
|
-
return false;
|
|
145
|
-
}
|
|
83
|
+
try {
|
|
84
|
+
const home = process.env.HOME || process.env.USERPROFILE || "";
|
|
85
|
+
const candidates = [`${process.env.NVM_DIR || `${home}/.nvm`}/versions/node/${process.version}/lib/node_modules/neonctl`, `${home}/.nvm/versions/node/${process.version}/lib/node_modules/neonctl`];
|
|
86
|
+
for (const candidate of candidates) try {
|
|
87
|
+
if (lstatSync(candidate).isSymbolicLink()) return true;
|
|
88
|
+
} catch {}
|
|
89
|
+
return false;
|
|
90
|
+
} catch {
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
146
93
|
}
|
|
147
94
|
/**
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
95
|
+
* Ensures neonctl is globally installed and up to date.
|
|
96
|
+
* Uses the same package manager that invoked the init command.
|
|
97
|
+
*/
|
|
98
|
+
async function ensureNeonctl() {
|
|
99
|
+
if (isLocalDevSymlink()) return {
|
|
100
|
+
status: "already_current",
|
|
101
|
+
version: await getNeonctlVersion() ?? "dev"
|
|
102
|
+
};
|
|
103
|
+
const check = await checkNeonctl();
|
|
104
|
+
if (check.installed && !check.needsUpdate) return {
|
|
105
|
+
status: "already_current",
|
|
106
|
+
version: check.currentVersion ?? void 0
|
|
107
|
+
};
|
|
108
|
+
const pm = resolveInvokingPackageManager();
|
|
109
|
+
const install = globalInstallCommand(pm, "neonctl");
|
|
110
|
+
if (!install) return {
|
|
111
|
+
status: "failed",
|
|
112
|
+
error: "Could not install the Neon CLI: this machine has no package manager that can perform a global install. npm, pnpm and bun are not on PATH (yarn Berry has no global install). Install npm, pnpm or bun, then run this again."
|
|
113
|
+
};
|
|
114
|
+
const { command, args } = install;
|
|
115
|
+
try {
|
|
116
|
+
await execa(command, args, {
|
|
117
|
+
stdio: "pipe",
|
|
118
|
+
timeout: 6e4
|
|
119
|
+
});
|
|
120
|
+
const version = await getNeonctlVersion();
|
|
121
|
+
return {
|
|
122
|
+
status: check.installed ? "updated" : "installed",
|
|
123
|
+
version: version ?? void 0
|
|
124
|
+
};
|
|
125
|
+
} catch (err) {
|
|
126
|
+
return {
|
|
127
|
+
status: "failed",
|
|
128
|
+
error: err instanceof Error ? err.message : "Unknown error"
|
|
129
|
+
};
|
|
130
|
+
}
|
|
184
131
|
}
|
|
132
|
+
//#endregion
|
|
133
|
+
export { checkNeonctl, ensureNeonctl, neonctlCmd };
|
package/dist/init/orchestrate.js
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
|
-
import { resolve } from "node:path";
|
|
3
1
|
import { isAuthenticated } from "./auth.js";
|
|
4
2
|
import { inspectProject } from "./inspect.js";
|
|
5
3
|
import { handleAuthPhase } from "./phases/auth.js";
|
|
@@ -8,183 +6,169 @@ import { handleMigrationsPhase } from "./phases/migrations.js";
|
|
|
8
6
|
import { handleNeonAuthPhase } from "./phases/neon_auth.js";
|
|
9
7
|
import { handleSetupPhase } from "./phases/setup.js";
|
|
10
8
|
import { resolveNeonContext } from "./resolve_context.js";
|
|
9
|
+
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
10
|
+
import { resolve } from "node:path";
|
|
11
|
+
//#region src/init/orchestrate.ts
|
|
11
12
|
/**
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
if (!options.skipMigrations) {
|
|
143
|
-
return handleMigrationsPhase({ agent: options.agent });
|
|
144
|
-
}
|
|
145
|
-
// All done — clean up ephemeral _init state from .neon
|
|
146
|
-
cleanupInitState(neonContextPath);
|
|
147
|
-
return {
|
|
148
|
-
phase: "setup",
|
|
149
|
-
status: "complete",
|
|
150
|
-
nextAction: {
|
|
151
|
-
type: "complete",
|
|
152
|
-
message: "Neon setup is complete. Your database is configured and your agent has the Neon MCP server and skills available.",
|
|
153
|
-
},
|
|
154
|
-
};
|
|
13
|
+
* v2 orchestrator: checks phases in order and returns the first that needs attention.
|
|
14
|
+
*
|
|
15
|
+
* Phase order:
|
|
16
|
+
* auth -> setup (if tooling not installed)
|
|
17
|
+
* -> getting-started (if tooling installed but no Neon connection string)
|
|
18
|
+
* -> resolve .neon context (if connection string exists but no .neon file)
|
|
19
|
+
* -> neon_auth (optional) -> complete
|
|
20
|
+
*
|
|
21
|
+
* Each call is stateless — it re-checks everything from the file system and credentials.
|
|
22
|
+
*
|
|
23
|
+
* The orchestrator uses filesystem inspection to decide what to do:
|
|
24
|
+
* - No app detected → bootstrap phase (scaffold from template)
|
|
25
|
+
* - MCP not configured → full setup flow (inspect → install → getting-started)
|
|
26
|
+
* - MCP configured, no connection string → skip install, go to getting-started
|
|
27
|
+
* - MCP configured + connection string → fall through to neon-auth/migrations/complete
|
|
28
|
+
*/
|
|
29
|
+
async function orchestrate(options) {
|
|
30
|
+
if (!await isAuthenticated()) return handleAuthPhase({ agent: options.agent });
|
|
31
|
+
const cwd = process.cwd();
|
|
32
|
+
const inspection = await inspectProject([
|
|
33
|
+
{
|
|
34
|
+
id: "has_app",
|
|
35
|
+
description: "",
|
|
36
|
+
lookFor: []
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
id: "mcp_server",
|
|
40
|
+
description: "",
|
|
41
|
+
lookFor: []
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
id: "skills",
|
|
45
|
+
description: "",
|
|
46
|
+
lookFor: []
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
id: "connection_string",
|
|
50
|
+
description: "",
|
|
51
|
+
lookFor: []
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
id: "project_stack",
|
|
55
|
+
description: "",
|
|
56
|
+
lookFor: []
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
id: "migrations",
|
|
60
|
+
description: "",
|
|
61
|
+
lookFor: []
|
|
62
|
+
}
|
|
63
|
+
]);
|
|
64
|
+
const hasApp = options.preview ? inspection.hasApp === true : true;
|
|
65
|
+
let skillsInstalled = inspection.skillsInstalled;
|
|
66
|
+
if (options.preview && skillsInstalled && inspection.skillsScope) {
|
|
67
|
+
const { getSkillList } = await import("./skills.js");
|
|
68
|
+
const previewSkills = getSkillList(true);
|
|
69
|
+
const { existsSync: exists } = await import("node:fs");
|
|
70
|
+
const { resolve: resolvePath } = await import("node:path");
|
|
71
|
+
const home = process.env.HOME || process.env.USERPROFILE || "";
|
|
72
|
+
const dirs = inspection.skillsScope === "project" ? [
|
|
73
|
+
resolvePath(cwd, ".cursor", "skills"),
|
|
74
|
+
resolvePath(cwd, ".claude", "skills"),
|
|
75
|
+
resolvePath(cwd, ".agents", "skills")
|
|
76
|
+
] : [
|
|
77
|
+
resolvePath(home, ".cursor", "skills"),
|
|
78
|
+
resolvePath(home, ".claude", "skills"),
|
|
79
|
+
resolvePath(home, ".agents", "skills")
|
|
80
|
+
];
|
|
81
|
+
if (!previewSkills.every((skill) => dirs.some((dir) => exists(resolvePath(dir, skill, "SKILL.md"))))) {
|
|
82
|
+
skillsInstalled = false;
|
|
83
|
+
inspection.skillsScope = `${inspection.skillsScope}-partial`;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
const toolingInstalled = inspection.mcpConfigured && skillsInstalled;
|
|
87
|
+
const hasNeonConnection = inspection.connectionString === true;
|
|
88
|
+
if (!hasApp || !toolingInstalled) {
|
|
89
|
+
cleanupInitState(resolve(cwd, ".neon"));
|
|
90
|
+
return handleSetupPhase({
|
|
91
|
+
agent: options.agent,
|
|
92
|
+
preview: options.preview,
|
|
93
|
+
hasApp,
|
|
94
|
+
mcpConfigured: inspection.mcpConfigured ?? null,
|
|
95
|
+
mcpScope: inspection.mcpScope || void 0,
|
|
96
|
+
skillsInstalled: skillsInstalled ?? null,
|
|
97
|
+
skillsScope: inspection.skillsScope || void 0
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
const neonContextPath = resolve(cwd, ".neon");
|
|
101
|
+
const neonContext = readNeonContext(neonContextPath);
|
|
102
|
+
const initState = typeof neonContext._init === "object" && neonContext._init !== null ? neonContext._init : {};
|
|
103
|
+
const features = Array.isArray(initState.features) ? initState.features : [];
|
|
104
|
+
if (!hasNeonConnection) return handleGettingStartedPhase({
|
|
105
|
+
agent: options.agent,
|
|
106
|
+
cwd,
|
|
107
|
+
hasConnectionString: false,
|
|
108
|
+
framework: inspection.framework,
|
|
109
|
+
orm: inspection.orm,
|
|
110
|
+
migrationTool: inspection.migrationTool,
|
|
111
|
+
migrationDir: inspection.migrationDir,
|
|
112
|
+
features,
|
|
113
|
+
preview: options.preview
|
|
114
|
+
});
|
|
115
|
+
if (!neonContext.projectId) try {
|
|
116
|
+
const resolved = await resolveNeonContext(cwd);
|
|
117
|
+
if (resolved) {
|
|
118
|
+
const merged = { ...neonContext };
|
|
119
|
+
if (resolved.orgId) merged.orgId = resolved.orgId;
|
|
120
|
+
if (resolved.projectId) merged.projectId = resolved.projectId;
|
|
121
|
+
writeFileSync(neonContextPath, `${JSON.stringify(merged, null, 2)}\n`);
|
|
122
|
+
}
|
|
123
|
+
} catch {}
|
|
124
|
+
if (features.includes("auth")) {
|
|
125
|
+
if (!checkNeonAuth(cwd)) return handleNeonAuthPhase({
|
|
126
|
+
agent: options.agent,
|
|
127
|
+
setup: true
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
if (!options.skipMigrations) return handleMigrationsPhase({
|
|
131
|
+
agent: options.agent,
|
|
132
|
+
cwd
|
|
133
|
+
});
|
|
134
|
+
cleanupInitState(neonContextPath);
|
|
135
|
+
return {
|
|
136
|
+
phase: "setup",
|
|
137
|
+
status: "complete",
|
|
138
|
+
nextAction: {
|
|
139
|
+
type: "complete",
|
|
140
|
+
message: "Neon setup is complete. Your database is configured and your agent has the Neon MCP server and skills available."
|
|
141
|
+
}
|
|
142
|
+
};
|
|
155
143
|
}
|
|
156
144
|
/** Remove the ephemeral _init key from .neon, preserving other fields. */
|
|
157
145
|
function cleanupInitState(neonContextPath) {
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
}
|
|
167
|
-
catch { }
|
|
146
|
+
if (!existsSync(neonContextPath)) return;
|
|
147
|
+
try {
|
|
148
|
+
const context = JSON.parse(readFileSync(neonContextPath, "utf-8"));
|
|
149
|
+
if (context._init !== void 0) {
|
|
150
|
+
delete context._init;
|
|
151
|
+
writeFileSync(neonContextPath, `${JSON.stringify(context, null, 2)}\n`);
|
|
152
|
+
}
|
|
153
|
+
} catch {}
|
|
168
154
|
}
|
|
169
155
|
function readNeonContext(neonContextPath) {
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
return {};
|
|
177
|
-
}
|
|
156
|
+
if (!existsSync(neonContextPath)) return {};
|
|
157
|
+
try {
|
|
158
|
+
return JSON.parse(readFileSync(neonContextPath, "utf-8"));
|
|
159
|
+
} catch {
|
|
160
|
+
return {};
|
|
161
|
+
}
|
|
178
162
|
}
|
|
179
163
|
function checkNeonAuth(cwd) {
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
return false;
|
|
189
|
-
}
|
|
164
|
+
const envPath = resolve(cwd, ".env");
|
|
165
|
+
if (!existsSync(envPath)) return false;
|
|
166
|
+
try {
|
|
167
|
+
const content = readFileSync(envPath, "utf-8");
|
|
168
|
+
return /^NEON_AUTH_/m.test(content);
|
|
169
|
+
} catch {
|
|
170
|
+
return false;
|
|
171
|
+
}
|
|
190
172
|
}
|
|
173
|
+
//#endregion
|
|
174
|
+
export { orchestrate };
|