neon 8.11.1 → 8.11.2

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.
Files changed (105) hide show
  1. package/README.md +1 -1
  2. package/dist/_chunks/api-GbEaBZJ5.js +388 -0
  3. package/dist/_chunks/api_keys-CNnnugbQ.js +281 -0
  4. package/dist/_chunks/ask-DVwy0eUL.js +155 -0
  5. package/dist/_chunks/auth-CIUtXByB.js +495 -0
  6. package/dist/_chunks/bootstrap-wPZWa1sT.js +499 -0
  7. package/dist/_chunks/branches-BNa1xX1L.js +460 -0
  8. package/dist/_chunks/bucket-BCdryTkD.js +409 -0
  9. package/dist/_chunks/checkout-CXIOydqZ.js +348 -0
  10. package/dist/_chunks/claim-DqAvAvDm.js +473 -0
  11. package/dist/_chunks/config-BH_qRHiG.js +1113 -0
  12. package/dist/_chunks/connection_string-DB4awPzZ.js +154 -0
  13. package/dist/_chunks/credentials-BSjE9fRR.js +146 -0
  14. package/dist/_chunks/data_api-Djxj5ZQD.js +263 -0
  15. package/dist/_chunks/databases-Dok4wru7.js +84 -0
  16. package/dist/_chunks/deploy-D7B0Xfjg.js +33 -0
  17. package/dist/_chunks/dev-CSvxAecE.js +945 -0
  18. package/dist/_chunks/diff-DhxxbdQE.js +178 -0
  19. package/dist/_chunks/docs-CrVybkTP.js +197 -0
  20. package/dist/_chunks/env-5HS5qQGd.js +284 -0
  21. package/dist/_chunks/feedback-CMayyTa8.js +88 -0
  22. package/dist/_chunks/functions-Q0zuvtnk.js +464 -0
  23. package/dist/_chunks/git-H32TNt6M.js +356 -0
  24. package/dist/_chunks/init-BkA6RilG.js +111 -0
  25. package/dist/_chunks/inspect-g0wekylj.js +90 -0
  26. package/dist/_chunks/ip_allow-5lLFvIuE.js +106 -0
  27. package/dist/_chunks/link-BgtkOBws.js +936 -0
  28. package/dist/_chunks/logs-DWkpjzIH.js +291 -0
  29. package/dist/_chunks/mcp-Bo-7TKc7.js +253 -0
  30. package/dist/_chunks/neon_auth-CBs1_3qu.js +822 -0
  31. package/dist/_chunks/open-CX3BT3Tp.js +33 -0
  32. package/dist/_chunks/operations-D4I-AxVs.js +37 -0
  33. package/dist/_chunks/orgs-xGfANwHQ.js +52 -0
  34. package/dist/_chunks/plugins-DqD7BDO1.js +169 -0
  35. package/dist/_chunks/profile-yXOiKk9R.js +672 -0
  36. package/dist/_chunks/projects-BwI2Uo0z.js +439 -0
  37. package/dist/_chunks/psql-BM-doe8e.js +64 -0
  38. package/dist/_chunks/realtime-BRqIyGR-.js +79 -0
  39. package/dist/_chunks/roles-B4w3YT_7.js +79 -0
  40. package/dist/_chunks/set_context-DbrwoImy.js +38 -0
  41. package/dist/_chunks/skills-DyiBXKS3.js +255 -0
  42. package/dist/_chunks/snapshots-RJBzW8GM.js +338 -0
  43. package/dist/_chunks/status-DV8Z2kw3.js +44 -0
  44. package/dist/_chunks/triggers-BrRo1z4b.js +302 -0
  45. package/dist/_chunks/user-dlOGXbX9.js +60 -0
  46. package/dist/_chunks/vpc_endpoints-CNb0YfMo.js +105 -0
  47. package/dist/auth_recovery.js +1 -1
  48. package/dist/commands/api.js +1 -388
  49. package/dist/commands/api_keys.js +1 -281
  50. package/dist/commands/ask.js +1 -155
  51. package/dist/commands/auth.js +1 -495
  52. package/dist/commands/bootstrap.js +1 -499
  53. package/dist/commands/branches.js +1 -460
  54. package/dist/commands/bucket.js +1 -409
  55. package/dist/commands/checkout.js +1 -348
  56. package/dist/commands/claim.js +1 -473
  57. package/dist/commands/config.js +1 -1113
  58. package/dist/commands/connection_string.js +1 -154
  59. package/dist/commands/credentials.js +1 -146
  60. package/dist/commands/data_api.js +1 -263
  61. package/dist/commands/databases.js +1 -84
  62. package/dist/commands/deploy.js +1 -33
  63. package/dist/commands/dev.js +1 -945
  64. package/dist/commands/diff.js +1 -178
  65. package/dist/commands/docs.js +1 -197
  66. package/dist/commands/env.js +1 -284
  67. package/dist/commands/feedback.js +1 -88
  68. package/dist/commands/functions.js +1 -464
  69. package/dist/commands/functions_new.js +1 -1
  70. package/dist/commands/git.js +1 -356
  71. package/dist/commands/index.js +45 -45
  72. package/dist/commands/init.js +1 -111
  73. package/dist/commands/inspect.js +1 -90
  74. package/dist/commands/ip_allow.js +1 -106
  75. package/dist/commands/link.js +1 -936
  76. package/dist/commands/logs.js +1 -291
  77. package/dist/commands/mcp.js +1 -253
  78. package/dist/commands/neon_auth.js +1 -822
  79. package/dist/commands/open.js +1 -33
  80. package/dist/commands/operations.js +1 -37
  81. package/dist/commands/orgs.js +1 -52
  82. package/dist/commands/plugins.js +1 -169
  83. package/dist/commands/profile.js +1 -672
  84. package/dist/commands/projects.js +1 -439
  85. package/dist/commands/psql.js +1 -64
  86. package/dist/commands/realtime.js +1 -79
  87. package/dist/commands/roles.js +1 -79
  88. package/dist/commands/set_context.js +1 -38
  89. package/dist/commands/skills.js +1 -255
  90. package/dist/commands/snapshots.js +1 -338
  91. package/dist/commands/status.js +1 -44
  92. package/dist/commands/subscribe.js +1 -1
  93. package/dist/commands/triggers.js +1 -302
  94. package/dist/commands/user.js +1 -60
  95. package/dist/commands/vpc_endpoints.js +1 -105
  96. package/dist/functions/registry.js +29 -151
  97. package/dist/functions/source.js +42 -2
  98. package/dist/index.js +1 -1
  99. package/dist/init/auth.js +3 -3
  100. package/dist/init/link.js +2 -2
  101. package/dist/init/run.js +3 -3
  102. package/dist/init/tooling.js +3 -3
  103. package/dist/mcp/mint.js +1 -1
  104. package/dist/test_utils/registry.js +1 -2
  105. package/package.json +8 -6
@@ -0,0 +1,499 @@
1
+ import { t as __exportAll } from "./rolldown-runtime-8H4AJuhK.js";
2
+ import { isCi } from "../env.js";
3
+ import { log } from "../log.js";
4
+ import { recordCommandSuccessExtras, recordScaffoldedTemplate } from "../analytics.js";
5
+ import { getCliName } from "../utils/cli_name.js";
6
+ import { helpCsv, helpEpilogue } from "../utils/help_text.js";
7
+ import { coerceAgentFlag } from "../utils/agent_flag.js";
8
+ import { assertNamedAgentTooling, chooseYesAgentTooling, initPluginAgents, initSkillsMcpAgents, postScaffoldActions, projectContextFile, resolveNamedAgents } from "../init/plan.js";
9
+ import { formatInstallCommand, inferPackageManager, installArgs, installedPackageManagers, resolvePackageManager, runCommand } from "../utils/package_manager.js";
10
+ import { writer } from "../writer.js";
11
+ import { FALLBACK_TEMPLATES, ensureTargetUsable, fetchTemplates, findTemplate, scaffoldTemplate, templateIds } from "../init/bootstrap.js";
12
+ import { agentSetupDoneLabel, formatInitDone, printInitBanner, printInitDone, shouldPrintInitBanner } from "../init/chrome.js";
13
+ import { runAuthenticatedLink } from "../init/link.js";
14
+ import { formatTemplateTitle } from "../init/template_title.js";
15
+ import { pickAgentSetupInteractively, pickInitLinkInteractively } from "../init/wizard.js";
16
+ import { runAgentTooling } from "../init/tooling.js";
17
+ import { existsSync } from "node:fs";
18
+ import { join, relative, resolve } from "node:path";
19
+ import prompts from "prompts";
20
+ //#region src/commands/bootstrap.ts
21
+ var bootstrap_exports = /* @__PURE__ */ __exportAll({
22
+ builder: () => builder,
23
+ command: () => command,
24
+ describe: () => describe,
25
+ handler: () => handler
26
+ });
27
+ const command = "bootstrap [directory]";
28
+ const describe = "Scaffold a new project from a Neon starter template, then install agent tooling and link a Neon project";
29
+ const builder = (argv) => argv.usage("$0 bootstrap [directory] [options]").positional("directory", {
30
+ describe: "Directory to scaffold into. Use \".\" for the current directory. Omit to be prompted.",
31
+ type: "string"
32
+ }).options({
33
+ template: {
34
+ describe: "Template to use (skips the interactive picker). Run with --list-templates to see available templates.",
35
+ type: "string"
36
+ },
37
+ "list-templates": {
38
+ alias: ["list", "ls"],
39
+ describe: "List available templates and exit. --output json and --output yaml print a machine-readable catalog.",
40
+ type: "boolean",
41
+ default: false
42
+ },
43
+ force: {
44
+ describe: "Scaffold into the target directory even if it is not empty (colliding files are overwritten).",
45
+ type: "boolean",
46
+ default: false
47
+ },
48
+ default: {
49
+ alias: "y",
50
+ describe: "Quick start: scaffold the default template (or --template), then install, git, agent tooling (project folders, else the host CLI agent; if none, pass --agent or omit --default in a terminal), and link with defaults. If several organizations or projects exist, link prints IDs and exits",
51
+ type: "boolean",
52
+ default: false
53
+ },
54
+ install: {
55
+ describe: "Install dependencies after scaffolding. In interactive mode this is offered as a prompt; use --no-install to skip without being asked.",
56
+ type: "boolean",
57
+ default: true
58
+ },
59
+ git: {
60
+ describe: "Initialize a git repository after scaffolding. In interactive mode this is offered as a prompt; use --no-git to skip without being asked.",
61
+ type: "boolean",
62
+ default: true
63
+ },
64
+ link: {
65
+ describe: "Link a Neon project after scaffolding. Templates with neon.ts link after install so env pull works; otherwise linking happens before install. In interactive mode this is offered as a prompt; use --no-link to skip without being asked.",
66
+ type: "boolean",
67
+ default: true
68
+ },
69
+ "agent-setup": {
70
+ type: "boolean",
71
+ default: true,
72
+ describe: "After scaffolding, install the Neon plugin or skills and MCP. Use --no-agent-setup to skip"
73
+ },
74
+ agent: {
75
+ alias: "a",
76
+ type: "array",
77
+ string: true,
78
+ describe: "Coding agent to install into (repeatable). Forwarded to plugins, or to skills and mcp. Skips agent selection. Values listed below",
79
+ coerce: coerceAgentFlag
80
+ }
81
+ }).example("$0 bootstrap my-app", "Create ./my-app from an interactively chosen template").example("$0 bootstrap . --template hono", "Scaffold the Hono template into the current directory").example("$0 bootstrap my-app --default", "Skip the pickers; if several orgs or projects exist, link prints IDs and exits").example("$0 bootstrap --list-templates --output json", "Print the template catalog as JSON").example("$0 bootstrap my-app --agent cursor --agent claude-code", "Skip agent selection; install the plugin for those agents").epilogue(helpEpilogue("--agent / -a is forwarded to plugins, or to skills and mcp, not both. It skips agent selection, including with --default.", helpCsv("Plugin agents", initPluginAgents()), helpCsv("Skills and MCP agents", initSkillsMcpAgents()))).strict();
82
+ const handler = async (props) => {
83
+ if (props.listTemplates) {
84
+ const templates = await fetchTemplates();
85
+ if (props.output === "json" || props.output === "yaml") {
86
+ writer(props).end(templates.map((t) => ({
87
+ id: t.id,
88
+ title: t.title,
89
+ description: t.description,
90
+ services: t.services ?? []
91
+ })), { fields: [
92
+ "id",
93
+ "title",
94
+ "description",
95
+ "services"
96
+ ] });
97
+ return;
98
+ }
99
+ for (const t of templates) {
100
+ const services = t.services && t.services.length > 0 ? ` [${t.services.join(" · ")}]` : "";
101
+ process.stdout.write(`${t.id} — ${t.description}${services}\n`);
102
+ }
103
+ return;
104
+ }
105
+ if (props.printBanner !== false && shouldPrintInitBanner(props.default)) printInitBanner();
106
+ const named = resolveNamedAgents(props.agent ?? []);
107
+ if (props.agentSetup !== false) assertNamedAgentTooling(named, "bootstrap", {
108
+ ...props.directory !== void 0 && props.directory.length > 0 ? { directory: props.directory } : {},
109
+ ...props.default ? { yes: true } : {}
110
+ });
111
+ const interactive = !props.default && Boolean(process.stdout.isTTY) && !isCi();
112
+ const template = props.selectedTemplate ?? await resolveSelectedTemplate(props, interactive, await resolveTemplateList(props));
113
+ const targetDir = await resolveTargetDir(props, interactive, template);
114
+ ensureTargetUsable(targetDir, props.force);
115
+ await scaffold(template, targetDir);
116
+ recordScaffoldedTemplate(template.id);
117
+ printScaffolded(template, targetDir);
118
+ const result = await runPostScaffoldSteps(props, targetDir, interactive, template, named);
119
+ recordCommandSuccessExtras({ agent_setup: result.agentSetup });
120
+ return result;
121
+ };
122
+ /**
123
+ * The template list to choose from. When --template is given we try the
124
+ * built-in fallback list first to avoid a network round-trip, only fetching the
125
+ * remote manifest if the id isn't one of the defaults.
126
+ */
127
+ const resolveTemplateList = async (props) => props.template && findTemplate(FALLBACK_TEMPLATES, props.template) ? FALLBACK_TEMPLATES : fetchTemplates();
128
+ const resolveSelectedTemplate = async (props, interactive, templates) => {
129
+ if (props.template) {
130
+ const template = findTemplate(templates, props.template);
131
+ if (!template) throw new Error(`Unknown template "${props.template}". Available templates: ${templateIds(templates)}.`);
132
+ return template;
133
+ }
134
+ if (props.default) {
135
+ const fallback = templates[0];
136
+ if (!fallback) throw new Error("No templates available to scaffold from.");
137
+ return fallback;
138
+ }
139
+ if (!interactive) throw new Error(`No template selected. Re-run in an interactive terminal to pick one, or pass --template <id>. Available templates: ${templateIds(templates)}.`);
140
+ const { id } = await prompts({
141
+ onState: onPromptState,
142
+ type: "select",
143
+ name: "id",
144
+ message: "Which template would you like to use?",
145
+ choices: templates.map((template) => ({
146
+ title: formatTemplateTitle(template),
147
+ value: template.id
148
+ })),
149
+ initial: 0
150
+ });
151
+ const template = findTemplate(templates, id);
152
+ if (!template) throw new Error("No template selected.");
153
+ return template;
154
+ };
155
+ const resolveTargetDir = async (props, interactive, template) => {
156
+ let dir = props.directory;
157
+ if (dir === void 0) {
158
+ if (props.default) return resolve(process.cwd(), defaultDirName(template));
159
+ if (!interactive) throw new Error(`No target directory given. Pass one, e.g. \`${getCliName()} bootstrap my-app\` (or "." for the current directory).`);
160
+ const { value } = await prompts({
161
+ onState: onPromptState,
162
+ type: "text",
163
+ name: "value",
164
+ message: "Where should we scaffold your project?",
165
+ initial: defaultDirName(template),
166
+ validate: (input) => input && input.trim().length > 0 ? true : "Enter a directory (use \".\" for the current directory)."
167
+ });
168
+ dir = String(value).trim();
169
+ }
170
+ return resolve(process.cwd(), dir === "." ? "" : dir);
171
+ };
172
+ const defaultDirName = (template) => template.source.subdir.split("/").pop() || template.id;
173
+ const scaffold = async (template, targetDir) => {
174
+ log.info("Fetching template \"%s\" from GitHub…", template.id);
175
+ const filesWritten = await scaffoldTemplate(template, targetDir, { onWarn: (message) => {
176
+ log.warning(message);
177
+ } });
178
+ log.info("Scaffolded %d files into %s.", filesWritten, targetDir);
179
+ return filesWritten;
180
+ };
181
+ const nestedResult = (template, targetDir, hasNeonConfig, outcome) => ({
182
+ templateTitle: template.title,
183
+ targetDir,
184
+ hasNeonConfig,
185
+ ...outcome
186
+ });
187
+ const runPostScaffoldSteps = async (props, targetDir, interactive, template, named) => {
188
+ const inferred = inferPackageManager(targetDir);
189
+ const defaultPm = resolvePackageManager(targetDir);
190
+ const neonConfig = hasNeonConfig(targetDir);
191
+ if (props.default) return runDefaultSteps(props, targetDir, defaultPm, neonConfig, template, named);
192
+ if (!interactive) {
193
+ const outcome = {
194
+ installed: false,
195
+ installFailed: false,
196
+ gitFailed: false,
197
+ git: false,
198
+ agentSetup: "skip",
199
+ linked: false,
200
+ skippedLinkForDeps: false,
201
+ agentsRan: false
202
+ };
203
+ finishPostScaffold({
204
+ heading: "Project scaffolded.",
205
+ template,
206
+ targetDir,
207
+ pm: defaultPm,
208
+ ...outcome,
209
+ suggestLink: true,
210
+ skipPrint: props.skipDoneSummary === true
211
+ });
212
+ return nestedResult(template, targetDir, neonConfig, outcome);
213
+ }
214
+ let pm = defaultPm;
215
+ const wantInstall = props.install && await confirm(installPrompt(inferred));
216
+ if (wantInstall) pm = inferred ?? await selectPackageManager();
217
+ const wantGit = props.git && !isGitRepo(targetDir) && await confirm("Initialize a git repository?");
218
+ const agentSetup = props.agentSetup === false ? "skip" : named.length > 0 ? chooseYesAgentTooling(named).setup : await (props.pickAgentSetup ?? pickAgentSetupInteractively)();
219
+ const canLink = props.link && !(neonConfig && !wantInstall);
220
+ if (props.link && !canLink) logSkippedLink(pm);
221
+ const outcome = await executePostScaffold(props, targetDir, {
222
+ yes: false,
223
+ lockAgentSetup: named.length === 0,
224
+ pm,
225
+ git: wantGit,
226
+ agentSetup,
227
+ install: wantInstall,
228
+ link: canLink,
229
+ hasNeonConfig: neonConfig,
230
+ named
231
+ });
232
+ finishPostScaffold({
233
+ heading: "Project scaffolded.",
234
+ template,
235
+ targetDir,
236
+ pm,
237
+ ...outcome,
238
+ suggestLink: !outcome.linked,
239
+ skipPrint: props.skipDoneSummary === true
240
+ });
241
+ return nestedResult(template, targetDir, neonConfig, outcome);
242
+ };
243
+ const installPrompt = (inferred) => inferred ? `Install dependencies with ${inferred}?` : "Install dependencies?";
244
+ const runDefaultSteps = async (props, targetDir, pm, neonConfig, template, named) => {
245
+ log.info("Quick start (--default): skipping the template, install, git, and agent pickers. If several organizations or projects exist, link prints IDs and exits.");
246
+ const wantGit = props.git && !isGitRepo(targetDir);
247
+ const agentSetup = props.agentSetup === false ? "skip" : named.length > 0 ? chooseYesAgentTooling(named).setup : "skills-mcp";
248
+ const outcome = await executePostScaffold(props, targetDir, {
249
+ yes: true,
250
+ lockAgentSetup: false,
251
+ pm,
252
+ git: wantGit,
253
+ agentSetup,
254
+ install: props.install,
255
+ link: props.link,
256
+ hasNeonConfig: neonConfig,
257
+ named
258
+ });
259
+ finishPostScaffold({
260
+ heading: "Project scaffolded.",
261
+ template,
262
+ targetDir,
263
+ pm,
264
+ ...outcome,
265
+ suggestLink: !outcome.linked,
266
+ skipPrint: props.skipDoneSummary === true
267
+ });
268
+ return nestedResult(template, targetDir, neonConfig, outcome);
269
+ };
270
+ const executePostScaffold = async (props, targetDir, choices) => {
271
+ const kids = {
272
+ output: "table",
273
+ auth: bootstrapAuth(props, targetDir),
274
+ operations: props.operations,
275
+ ...props.narrate ? { narrate: props.narrate } : {}
276
+ };
277
+ let installed = false;
278
+ let installFailed = false;
279
+ let gitFailed = false;
280
+ let git = false;
281
+ let linked = false;
282
+ let skippedLinkForDeps = false;
283
+ let agentSetup = choices.agentSetup;
284
+ let agentsRan = false;
285
+ const actions = postScaffoldActions({
286
+ git: choices.git,
287
+ agentSetup: choices.agentSetup,
288
+ install: choices.install,
289
+ link: choices.link,
290
+ hasNeonConfig: choices.hasNeonConfig
291
+ });
292
+ for (const action of actions) {
293
+ if (action === "git") {
294
+ git = await initGitRepo(targetDir);
295
+ if (!git) {
296
+ gitFailed = true;
297
+ break;
298
+ }
299
+ continue;
300
+ }
301
+ if (action === "agent") {
302
+ agentSetup = await runAgentTooling({
303
+ cwd: targetDir,
304
+ yes: choices.yes,
305
+ ...choices.lockAgentSetup ? { agentSetup: choices.agentSetup } : {},
306
+ ...kids,
307
+ ...choices.named.length > 0 ? { agents: choices.named } : {},
308
+ ...props.pickAgentSetup ? { pickAgentSetup: props.pickAgentSetup } : {},
309
+ ...props.hasProjectPlugins ? { hasProjectPlugins: props.hasProjectPlugins } : {},
310
+ ...props.detectProjectAgents ? { detectProjectAgents: props.detectProjectAgents } : {},
311
+ ...props.detectAgent ? { detectAgent: props.detectAgent } : {},
312
+ command: "bootstrap"
313
+ });
314
+ agentsRan = true;
315
+ continue;
316
+ }
317
+ if (action === "install") {
318
+ log.info("Installing dependencies with %s…", choices.pm);
319
+ installed = await runCommand(choices.pm, installArgs(choices.pm), targetDir);
320
+ if (!installed) installFailed = true;
321
+ continue;
322
+ }
323
+ if (action !== "link") throw new Error(`Unhandled post-scaffold action: ${action}`);
324
+ if (choices.hasNeonConfig && !installed) {
325
+ skippedLinkForDeps = true;
326
+ logSkippedLink(choices.pm);
327
+ continue;
328
+ }
329
+ if (!(choices.yes || await (props.pickLink ?? pickInitLinkInteractively)())) continue;
330
+ await (props.linkProject ?? runAuthenticatedLink)({
331
+ apiClient: props.apiClient,
332
+ apiKey: props.apiKey,
333
+ apiHost: props.apiHost,
334
+ output: props.output,
335
+ contextFile: projectContextFile(targetDir, props.contextFile),
336
+ yes: choices.yes,
337
+ clear: false,
338
+ checks: true,
339
+ envPull: true,
340
+ config: props.linkNoConfig !== true,
341
+ cwd: targetDir,
342
+ ...props.linkInputs,
343
+ ...props.configDir ? { configDir: props.configDir } : {},
344
+ ...props.profile ? { profile: props.profile } : {},
345
+ ...props.oauthHost ? { oauthHost: props.oauthHost } : {},
346
+ ...props.clientId ? { clientId: props.clientId } : {},
347
+ ...props.forceAuth !== void 0 ? { forceAuth: props.forceAuth } : {},
348
+ ...props.allowUnsafeTls !== void 0 ? { allowUnsafeTls: props.allowUnsafeTls } : {}
349
+ });
350
+ linked = true;
351
+ }
352
+ return {
353
+ installed,
354
+ installFailed,
355
+ gitFailed,
356
+ git,
357
+ linked,
358
+ skippedLinkForDeps,
359
+ agentSetup,
360
+ agentsRan
361
+ };
362
+ };
363
+ const isGitRepo = (dir) => existsSync(join(dir, ".git"));
364
+ const NEON_CONFIG_FILENAMES = [
365
+ "neon.ts",
366
+ "neon.mts",
367
+ "neon.js",
368
+ "neon.mjs"
369
+ ];
370
+ const hasNeonConfig = (dir) => NEON_CONFIG_FILENAMES.some((name) => existsSync(join(dir, name)));
371
+ const logSkippedLink = (pm) => {
372
+ log.info(`Skipping the Neon link step: \`${getCliName()} link\` reads this project's neon.ts to pull env vars, which needs its dependencies. Run \`${formatInstallCommand(pm)}\`, then \`${getCliName()} link\`.`);
373
+ };
374
+ /**
375
+ * plugins/skills need no Neon auth at all; mcp resolves it itself, in-process, exactly as
376
+ * the standalone `neon mcp` does (see `init/auth.ts`) — this is that shared context.
377
+ */
378
+ const bootstrapAuth = (props, targetDir) => ({
379
+ apiClient: props.apiClient,
380
+ apiKey: props.apiKey,
381
+ apiHost: props.apiHost,
382
+ contextFile: projectContextFile(targetDir, props.contextFile),
383
+ ...props.configDir ? { configDir: props.configDir } : {},
384
+ ...props.profile ? { profile: props.profile } : {},
385
+ ...props.oauthHost ? { oauthHost: props.oauthHost } : {},
386
+ ...props.clientId ? { clientId: props.clientId } : {},
387
+ ...props.forceAuth !== void 0 ? { forceAuth: props.forceAuth } : {},
388
+ ...props.allowUnsafeTls !== void 0 ? { allowUnsafeTls: props.allowUnsafeTls } : {}
389
+ });
390
+ /**
391
+ * Initialize a git repository in the scaffolded directory. Just `git init` — we
392
+ * deliberately don't auto-commit, both to avoid failing on a machine with no
393
+ * git identity configured and to leave the first commit to the user.
394
+ */
395
+ const initGitRepo = async (dir) => runCommand("git", ["init"], dir);
396
+ const confirm = async (message) => {
397
+ const { value } = await prompts({
398
+ onState: onPromptState,
399
+ type: "confirm",
400
+ name: "value",
401
+ message,
402
+ initial: true
403
+ });
404
+ return value === true;
405
+ };
406
+ /**
407
+ * Ask which package manager to install with when we couldn't infer one from the
408
+ * invocation. Offers the managers actually installed (npm preselected); with
409
+ * one or none installed there's nothing to choose, so it returns that one (or
410
+ * npm) without prompting. A cancelled prompt falls back to npm.
411
+ */
412
+ const selectPackageManager = async () => {
413
+ const installed = installedPackageManagers();
414
+ if (installed.length <= 1) return installed[0] ?? "npm";
415
+ const { pm } = await prompts({
416
+ onState: onPromptState,
417
+ type: "select",
418
+ name: "pm",
419
+ message: "Which package manager should we use?",
420
+ choices: installed.map((manager) => ({
421
+ title: manager,
422
+ value: manager
423
+ })),
424
+ initial: Math.max(0, installed.indexOf("npm"))
425
+ });
426
+ return pm ?? "npm";
427
+ };
428
+ const printScaffolded = (template, targetDir) => {
429
+ log.info("Scaffolded \"%s\" into %s.", template.title, isCurrentDir(targetDir) ? "the current directory" : displayDir(targetDir));
430
+ };
431
+ const printDoneSummary = (input) => {
432
+ const unfinished = input.installFailed || input.gitFailed;
433
+ const heading = unfinished ? "Setup did not finish." : input.heading;
434
+ const deps = input.installFailed ? "install failed" : input.installed ? `installed with ${input.pm}` : "skipped";
435
+ const git = input.gitFailed ? "init failed" : input.git ? "initialized" : "skipped";
436
+ const project = input.linked ? "linked" : input.skippedLinkForDeps ? "skipped (needs dependencies)" : "not linked";
437
+ const next = [];
438
+ if (!isCurrentDir(input.targetDir)) next.push(`cd ${displayDir(input.targetDir)}`);
439
+ if (!input.installed) next.push(formatInstallCommand(input.pm));
440
+ if (input.suggestLink) next.push(`${getCliName()} link`);
441
+ if (!unfinished) next.push("See the README to run it.");
442
+ printInitDone(formatInitDone({
443
+ heading,
444
+ rows: [
445
+ {
446
+ label: "Template",
447
+ value: input.template.title
448
+ },
449
+ {
450
+ label: "Directory",
451
+ value: displayDir(input.targetDir)
452
+ },
453
+ {
454
+ label: "Dependencies",
455
+ value: deps
456
+ },
457
+ {
458
+ label: "Git",
459
+ value: git
460
+ },
461
+ {
462
+ label: "Agents",
463
+ value: agentSetupDoneLabel({
464
+ setup: input.agentSetup,
465
+ ran: input.agentsRan
466
+ })
467
+ },
468
+ {
469
+ label: "Project",
470
+ value: project
471
+ }
472
+ ],
473
+ next
474
+ }));
475
+ };
476
+ const finishPostScaffold = (input) => {
477
+ if (!input.skipPrint) printDoneSummary(input);
478
+ if (input.installFailed || input.gitFailed) throw new Error("Setup did not finish.");
479
+ };
480
+ const isCurrentDir = (targetDir) => relative(process.cwd(), targetDir) === "";
481
+ /**
482
+ * The path to show the user: the bare relative path for the common
483
+ * `bootstrap my-app` case, the absolute path when the target sits outside the
484
+ * cwd (a deep `../../..` is noise), and "." for the current directory.
485
+ */
486
+ const displayDir = (targetDir) => {
487
+ const rel = relative(process.cwd(), targetDir);
488
+ if (rel === "") return ".";
489
+ return rel.startsWith("..") ? targetDir : rel;
490
+ };
491
+ const onPromptState = (state) => {
492
+ if (state.aborted) {
493
+ process.stdout.write("\x1B[?25h");
494
+ process.stdout.write("\n");
495
+ process.exit(1);
496
+ }
497
+ };
498
+ //#endregion
499
+ export { handler as a, describe as i, builder as n, command as r, bootstrap_exports as t };