neon 6.2.3 → 6.3.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.
@@ -1,10 +1,10 @@
1
1
  import { CONFIG_INIT_SERVICES } from "../config_template.js";
2
- import { AGENT_DETECTED_DESCRIPTION, AGENT_OTHER_DESCRIPTION, AGENT_PICKER_MESSAGE, AGENT_SETUP_MESSAGE, AGENT_SETUP_PLUGIN_DESCRIPTION, AGENT_SETUP_PLUGIN_TITLE, AGENT_SETUP_SKILLS_DESCRIPTION, AGENT_SETUP_SKILLS_TITLE, AGENT_SETUP_SKIP_DESCRIPTION, AGENT_SETUP_SKIP_TITLE, CONFIG_CONFIRM_HINT, CONFIG_CONFIRM_MESSAGE, MCP_AUTH_API_KEY_DESCRIPTION, MCP_AUTH_API_KEY_TITLE, MCP_AUTH_MESSAGE, MCP_AUTH_OAUTH_DESCRIPTION, MCP_AUTH_OAUTH_TITLE, MCP_SCOPE_GLOBAL_DESCRIPTION, MCP_SCOPE_GLOBAL_TITLE, MCP_SCOPE_MESSAGE, MCP_SCOPE_PROJECT_DESCRIPTION, MCP_SCOPE_PROJECT_TITLE, MODE_CUSTOM_DESCRIPTION, MODE_CUSTOM_TITLE, MODE_MESSAGE, MODE_RECOMMENDED_DESCRIPTION, MODE_RECOMMENDED_TITLE, PACKAGE_MANAGER_MESSAGE, PROJECT_SETUP_CLAIMABLE_DESCRIPTION, PROJECT_SETUP_CLAIMABLE_TITLE, PROJECT_SETUP_LINK_DESCRIPTION, PROJECT_SETUP_LINK_TITLE, PROJECT_SETUP_MESSAGE, SERVICES_HINT, SERVICES_MESSAGE, SKILLS_PICKER_MESSAGE } from "./copy.js";
2
+ import { AGENT_DETECTED_DESCRIPTION, AGENT_MCP_PICKER_MESSAGE, AGENT_MCP_SKIP_MESSAGE, AGENT_OTHER_DESCRIPTION, AGENT_PICKER_MESSAGE, AGENT_PLUGIN_SKIP_MESSAGE, AGENT_SETUP_MESSAGE, AGENT_SETUP_PLUGIN_DESCRIPTION, AGENT_SETUP_PLUGIN_TITLE, AGENT_SETUP_SKILLS_DESCRIPTION, AGENT_SETUP_SKILLS_TITLE, AGENT_SETUP_SKIP_DESCRIPTION, AGENT_SETUP_SKIP_TITLE, AGENT_SKILLS_PICKER_MESSAGE, AGENT_SKILLS_SKIP_MESSAGE, CONFIG_CONFIRM_HINT, CONFIG_CONFIRM_MESSAGE, MCP_AUTH_API_KEY_DESCRIPTION, MCP_AUTH_API_KEY_TITLE, MCP_AUTH_MESSAGE, MCP_AUTH_OAUTH_DESCRIPTION, MCP_AUTH_OAUTH_TITLE, MCP_SCOPE_GLOBAL_DESCRIPTION, MCP_SCOPE_GLOBAL_TITLE, MCP_SCOPE_MESSAGE, MCP_SCOPE_PROJECT_DESCRIPTION, MCP_SCOPE_PROJECT_TITLE, MODE_CUSTOM_DESCRIPTION, MODE_CUSTOM_TITLE, MODE_MESSAGE, MODE_RECOMMENDED_DESCRIPTION, MODE_RECOMMENDED_TITLE, PACKAGE_MANAGER_MESSAGE, PROJECT_SETUP_CLAIMABLE_DESCRIPTION, PROJECT_SETUP_CLAIMABLE_TITLE, PROJECT_SETUP_LINK_DESCRIPTION, PROJECT_SETUP_LINK_TITLE, PROJECT_SETUP_MESSAGE, SERVICES_HINT, SERVICES_MESSAGE, SKILLS_PICKER_MESSAGE, agentMissingCommandDescription } from "./copy.js";
3
3
  import { installedPackageManagers } from "../utils/package_manager.js";
4
4
  import { POSTGRES_SERVICE_CHOICE, keepPostgresSelected } from "../utils/service_picker.js";
5
5
  import { getAgentDisplayName, listMcpAgentIds } from "../mcp/agents.js";
6
6
  import { INIT_NEEDS_YES_OR_TERMINAL } from "./plan.js";
7
- import { canPickAgentsInteractively } from "../utils/agent_picker.js";
7
+ import { canPickAgentsInteractively, pickAgentsInteractively } from "../utils/agent_picker.js";
8
8
  import { NEON_SKILL_CATALOG, listSkillIds } from "../skills/catalog.js";
9
9
  import { InitCancelled, restoreCursorVisibilityOnAbort } from "./cancelled.js";
10
10
  import chalk from "chalk";
@@ -71,24 +71,23 @@ const pickAgentSetupInteractively = async () => {
71
71
  };
72
72
  const pickInitAgentsInteractively = async (input) => {
73
73
  requireInteractive();
74
- if (input.available.length === 0) throw new Error("No coding agents are available to pick.");
75
74
  const detected = new Set(input.detected);
76
- const { agents } = await prompts({
77
- onState: restoreCursorOnAbort,
78
- type: "multiselect",
79
- name: "agents",
80
- message: AGENT_PICKER_MESSAGE,
81
- instructions: false,
82
- min: 1,
83
- choices: input.available.map((id) => ({
84
- value: id,
85
- title: `${getAgentDisplayName(id)} (${id})`,
86
- description: detected.has(id) ? AGENT_DETECTED_DESCRIPTION : AGENT_OTHER_DESCRIPTION,
87
- selected: detected.has(id)
88
- }))
75
+ const missing = new Map((input.missingCommands ?? []).map((row) => [row.agent, row.command]));
76
+ const selected = await pickAgentsInteractively({
77
+ onCancel: aborted,
78
+ message: input.setup === "skills" ? AGENT_SKILLS_PICKER_MESSAGE : input.setup === "mcp" ? AGENT_MCP_PICKER_MESSAGE : AGENT_PICKER_MESSAGE,
79
+ skipMessage: input.setup === "plugin" ? AGENT_PLUGIN_SKIP_MESSAGE : input.setup === "skills" ? AGENT_SKILLS_SKIP_MESSAGE : AGENT_MCP_SKIP_MESSAGE,
80
+ selected: input.preselected ?? input.detected,
81
+ choices: input.available.map((id) => {
82
+ const command = missing.get(id);
83
+ return {
84
+ id,
85
+ title: `${getAgentDisplayName(id)} (${id})`,
86
+ description: command !== void 0 ? agentMissingCommandDescription(command) : detected.has(id) ? AGENT_DETECTED_DESCRIPTION : AGENT_OTHER_DESCRIPTION
87
+ };
88
+ })
89
89
  });
90
- if (!Array.isArray(agents)) return aborted();
91
- return agents.filter((id) => typeof id === "string");
90
+ return selected.length > 0 ? selected : void 0;
92
91
  };
93
92
  const pickInitSkillsInteractively = async () => {
94
93
  requireInteractive();
@@ -1,14 +1,19 @@
1
1
  import { getAgentDisplayName, tryResolveAddMcpAgentId } from "../mcp/agents.js";
2
2
  import "../init/agents.js";
3
- import { detectPluginsAgents, getPluginsTargetName, isUserScopeOnlyPluginsTarget, mappedPluginsTargets, pluginsInstallableAgents } from "./targets.js";
3
+ import { detectPluginsAgents, getPluginsTargetName, isUserScopeOnlyPluginsTarget, mappedPluginsTargets, missingPluginsCommands, pluginsInstallableAgents } from "./targets.js";
4
4
  import { collectYesAgents, noDetectedAgentsMessage } from "../init/plan.js";
5
5
  import { detectAgent } from "../init/detect_host.js";
6
6
  import { agentChoicesFrom, pickAgentsInteractively, resolveAgentSelection } from "../utils/agent_picker.js";
7
7
  //#region src/plugins/plan.ts
8
+ const missingPluginsCommandsError = (missing) => new Error(missing.map(({ agent, command }) => `Cannot install the Neon plugin for ${getAgentDisplayName(agent)}: "${command}" was not found on PATH. Install it or add it to PATH, then retry.`).join("\n"));
8
9
  const assertPluginsCanRun = (options) => {
9
10
  if (options.yes || options.interactive || options.hasAgents) return;
10
11
  throw new Error("No interactive terminal. Pass -y to install into detected agents, or --agent <name> to name them.");
11
12
  };
13
+ const commandLookup = (options) => ({
14
+ cwd: options.cwd,
15
+ ...options.commandPath !== void 0 ? { path: options.commandPath } : {}
16
+ });
12
17
  async function resolvePluginsPlan(options) {
13
18
  assertPluginsCanRun({
14
19
  yes: options.yes,
@@ -29,10 +34,18 @@ async function resolvePluginsPlan(options) {
29
34
  detectAgent: options.detectAgent ?? detectAgent,
30
35
  acceptHost: (id) => availableSet.has(id) || getPluginsTargetName(id) !== void 0
31
36
  }) : scoped;
37
+ const missingDetected = new Map((prompt ? missingPluginsCommands(detected, commandLookup(options)) : []).map((row) => [row.agent, row.command]));
38
+ const choices = agentChoicesFrom(available, detected).map((choice) => {
39
+ const command = missingDetected.get(choice.id);
40
+ return command === void 0 ? choice : {
41
+ ...choice,
42
+ description: `detected, but "${command}" is not on PATH`
43
+ };
44
+ });
32
45
  const selected = await resolveAgentSelection({
33
46
  specified: options.agents,
34
- choices: agentChoicesFrom(available, detected),
35
- detected,
47
+ choices,
48
+ detected: detected.filter((id) => !missingDetected.has(id)),
36
49
  message: "Which coding agents should get the Neon plugin? (space to toggle, enter to confirm)",
37
50
  nonInteractiveMessage: noDetectedAgentsMessage({
38
51
  scope,
@@ -64,6 +77,20 @@ async function resolvePluginsPlan(options) {
64
77
  }
65
78
  agents.push(id);
66
79
  }
80
+ const missingCommands = missingPluginsCommands(agents, commandLookup(options));
81
+ if (missingCommands.length > 0) {
82
+ if (!(options.agents.length === 0 && !prompt)) throw missingPluginsCommandsError(missingCommands);
83
+ const missingAgents = new Set(missingCommands.map((row) => row.agent));
84
+ const installable = agents.filter((id) => !missingAgents.has(id));
85
+ return {
86
+ scope,
87
+ agents: installable,
88
+ skipped,
89
+ userScopeSkipped,
90
+ missingCommands,
91
+ targets: installable.length === 0 ? [] : mappedPluginsTargets(installable, scope)
92
+ };
93
+ }
67
94
  if (agents.length === 0) {
68
95
  if (userScopeSkipped.length > 0 && skipped.length === 0) {
69
96
  const names = userScopeSkipped.map((id) => getAgentDisplayName(id)).join(", ");
@@ -76,8 +103,9 @@ async function resolvePluginsPlan(options) {
76
103
  agents,
77
104
  skipped,
78
105
  userScopeSkipped,
106
+ missingCommands,
79
107
  targets: mappedPluginsTargets(agents, scope)
80
108
  };
81
109
  }
82
110
  //#endregion
83
- export { assertPluginsCanRun, resolvePluginsPlan };
111
+ export { assertPluginsCanRun, missingPluginsCommandsError, resolvePluginsPlan };
@@ -1,27 +1,67 @@
1
1
  import { detectInstalledAgents, listMcpAgentIds, tryResolveAddMcpAgentId, uniqueAgentIds } from "../mcp/agents.js";
2
2
  import "../init/agents.js";
3
+ import { delimiter, dirname, join, resolve } from "node:path";
4
+ import which from "which";
3
5
  import { detectProjectAgents } from "add-mcp";
4
6
  //#region src/plugins/targets.ts
7
+ const CLAUDE_CODE = { target: "claude-code" };
5
8
  const PLUGINS_TARGET_BY_TYPE = {
6
- cursor: "cursor",
7
- vscode: "vscode",
8
- "claude-code": "claude-code",
9
- "claude-desktop": "claude-code",
10
- codex: "codex",
11
- "github-copilot-cli": "github-copilot",
12
- "grok-build": "grok"
9
+ cursor: { target: "cursor" },
10
+ vscode: { target: "vscode" },
11
+ "claude-code": CLAUDE_CODE,
12
+ "claude-desktop": CLAUDE_CODE,
13
+ codex: { target: "codex" },
14
+ "github-copilot-cli": {
15
+ target: "github-copilot",
16
+ command: "copilot"
17
+ },
18
+ "grok-build": {
19
+ target: "grok",
20
+ command: "grok"
21
+ }
13
22
  };
23
+ const pluginsTargets = () => [...new Set(Object.values(PLUGINS_TARGET_BY_TYPE))];
14
24
  const USER_SCOPE_ONLY_TARGETS = /* @__PURE__ */ new Set([
15
25
  "vscode",
16
26
  "github-copilot",
17
27
  "grok"
18
28
  ]);
19
- function getPluginsTargetName(agent) {
29
+ /** npx runs the plugins CLI with every `node_modules/.bin` from `cwd` up to the root ahead of PATH. */
30
+ const pluginsCommandSearchPath = (cwd, path) => {
31
+ const bins = [];
32
+ let dir = resolve(cwd);
33
+ for (;;) {
34
+ bins.push(join(dir, "node_modules", ".bin"));
35
+ const parent = dirname(dir);
36
+ if (parent === dir) break;
37
+ dir = parent;
38
+ }
39
+ return [...bins, path].join(delimiter);
40
+ };
41
+ const missingPluginsCommands = (agents, options) => {
42
+ const searchPath = pluginsCommandSearchPath(options.cwd, options.path ?? process.env.PATH ?? "");
43
+ const missing = [];
44
+ for (const agent of uniqueAgentIds(agents)) {
45
+ const command = getPluginsTarget(agent)?.command;
46
+ if (command !== void 0 && which.sync(command, {
47
+ nothrow: true,
48
+ path: searchPath
49
+ }) === null) missing.push({
50
+ agent,
51
+ command
52
+ });
53
+ }
54
+ return missing;
55
+ };
56
+ function getPluginsTarget(agent) {
20
57
  if (Object.prototype.hasOwnProperty.call(PLUGINS_TARGET_BY_TYPE, agent)) return PLUGINS_TARGET_BY_TYPE[agent];
21
58
  const id = tryResolveAddMcpAgentId(agent);
22
59
  if (!id) return void 0;
23
60
  return PLUGINS_TARGET_BY_TYPE[id];
24
61
  }
62
+ function getPluginsTargetName(agent) {
63
+ return getPluginsTarget(agent)?.target;
64
+ }
25
65
  function supportsPlugins(agent) {
26
66
  return getPluginsTargetName(agent) !== void 0;
27
67
  }
@@ -65,4 +105,4 @@ const mappedPluginsTargets = (agents, scope) => {
65
105
  return mapped;
66
106
  };
67
107
  //#endregion
68
- export { detectInstallablePluginsAgents, detectPluginsAgents, getPluginsTargetName, isUserScopeOnlyPluginsTarget, mappedPluginsTargets, pluginsInstallableAgents, pluginsMappedAgents, supportsPlugins };
108
+ export { detectInstallablePluginsAgents, detectPluginsAgents, getPluginsTargetName, isUserScopeOnlyPluginsTarget, mappedPluginsTargets, missingPluginsCommands, pluginsInstallableAgents, pluginsMappedAgents, pluginsTargets, supportsPlugins };
@@ -0,0 +1,92 @@
1
+ import { isCi } from "./env.js";
2
+ import { log } from "./log.js";
3
+ import { codeFromBody } from "./api.js";
4
+ import open from "open";
5
+ import prompts from "prompts";
6
+ //#region src/sso_recovery.ts
7
+ /**
8
+ * Extract the SSO step-up URL from the error message.
9
+ *
10
+ * The Neon public API carries the recovery URL in the human-readable `message`
11
+ * ("...Open <url> in your browser to authorize, then retry."), not a structured field — so this
12
+ * works against the API's standard error shape without a bespoke contract.
13
+ */
14
+ function extractStepUpUrl(message) {
15
+ if (typeof message !== "string") return;
16
+ const match = message.match(/(https?:\/\/[^\s)]+)/);
17
+ return match ? match[1] : void 0;
18
+ }
19
+ /**
20
+ * Whether the invocation opted out of prompts via --yes/-y.
21
+ *
22
+ * The skip-prompts flag is per-command in this CLI (link, projects update, init, …), not a global
23
+ * option, so — exactly like the --help/-h check in the error handler — detect it from argv rather than
24
+ * a parsed global. A run that documented itself as non-interactive (`neon link -y`) must take the
25
+ * unattended path, never open a browser or block on a confirm.
26
+ */
27
+ function promptsSkipped() {
28
+ return process.argv.includes("--yes") || process.argv.includes("-y");
29
+ }
30
+ /** Whether this process can drive an interactive open-browser-then-confirm-and-retry flow. */
31
+ function canInteract() {
32
+ return !isCi() && !promptsSkipped() && Boolean(process.stdout.isTTY) && Boolean(process.stdin.isTTY);
33
+ }
34
+ /**
35
+ * Recover from an SSO authorization error.
36
+ *
37
+ * Detection is by the machine `code` in the response body, NOT the HTTP status: Neon masks org
38
+ * access-denials as 404 (existence-hiding), so the error arrives as 403 or 404 with the code in the
39
+ * body.
40
+ * - SSO_AUTHORIZATION_REQUIRED: the user must complete a one-time SSO authorization in a browser.
41
+ * On an interactive terminal we open the step-up URL and wait for the user to confirm they've
42
+ * finished before signalling a retry. Unattended (CI, no TTY, or an explicit --yes/-y that opted
43
+ * out of prompts) we print the URL and fail, since no browser round-trip is possible.
44
+ * - SSO_ORG_CREDS_ONLY: terminal — no browser step resolves it; the user must use an
45
+ * organization-scoped API key. Return false (no retry).
46
+ *
47
+ * @param error the API error
48
+ * @param canRetry whether the caller is willing to retry (false once we've already retried)
49
+ * @returns true if the caller should retry the command, false otherwise
50
+ */
51
+ const recoverFromSSO = async (error, canRetry) => {
52
+ const code = codeFromBody(error.data);
53
+ if (code === "SSO_ORG_CREDS_ONLY") {
54
+ log.error(error.message);
55
+ return false;
56
+ }
57
+ if (code !== "SSO_AUTHORIZATION_REQUIRED") return false;
58
+ if (!canRetry) {
59
+ log.error(error.message);
60
+ return false;
61
+ }
62
+ const stepUpUrl = extractStepUpUrl(error.message);
63
+ if (!stepUpUrl) {
64
+ log.error(error.message);
65
+ return false;
66
+ }
67
+ if (!canInteract()) {
68
+ log.error("This organization requires a one-time SSO authorization, which needs an interactive browser session. Open this URL in a browser to authorize, then re-run the command:\n" + stepUpUrl);
69
+ return false;
70
+ }
71
+ log.info(`This organization requires SSO authorization. Opening your browser to authorize; if it doesn't open, visit this URL manually:\n${stepUpUrl}`);
72
+ try {
73
+ (await open(stepUpUrl)).once("error", (err) => {
74
+ log.warning(`Could not launch a browser automatically: ${err.message}`);
75
+ });
76
+ } catch {
77
+ log.warning("Could not launch a browser automatically; open the URL above manually.");
78
+ }
79
+ const { confirmed } = await prompts({
80
+ type: "confirm",
81
+ name: "confirmed",
82
+ message: "Press Enter once you've completed authorization in the browser to retry (or 'n' to cancel)",
83
+ initial: true
84
+ });
85
+ if (confirmed !== true) {
86
+ log.error(`SSO authorization was not completed. Re-run the command after authorizing at:\n${stepUpUrl}`);
87
+ return false;
88
+ }
89
+ return true;
90
+ };
91
+ //#endregion
92
+ export { recoverFromSSO };
@@ -2,40 +2,66 @@ import { isCi } from "../env.js";
2
2
  import { getAgentDisplayName, resolveAddMcpAgentId, uniqueAgentIds } from "../mcp/agents.js";
3
3
  import prompts from "prompts";
4
4
  //#region src/utils/agent_picker.ts
5
+ var AgentSelectionSkipped = class extends Error {};
5
6
  const canPickAgentsInteractively = () => !isCi() && Boolean(process.stdout.isTTY) && Boolean(process.stdin.isTTY);
7
+ const restoreCursorOnAbort = (exit) => (state) => {
8
+ if (state.aborted) {
9
+ process.stdout.write("\x1B[?25h");
10
+ process.stdout.write("\n");
11
+ if (exit) process.exit(1);
12
+ }
13
+ };
6
14
  const pickAgentsInteractively = async (options) => {
7
15
  if (!canPickAgentsInteractively()) throw new Error("No interactive terminal. Pass -y, or run this command in a terminal to pick agents.");
8
16
  if (options.choices.length === 0) throw new Error("No coding agents are available to pick.");
17
+ const cancel = options.onCancel ?? (() => {
18
+ throw new Error("Aborted: no agents selected.");
19
+ });
20
+ const onState = restoreCursorOnAbort(options.onCancel === void 0);
9
21
  const selected = new Set(options.selected ?? []);
10
- const { agents } = await prompts({
11
- onState: (state) => {
12
- if (state.aborted) {
13
- process.stdout.write("\x1B[?25h");
14
- process.stdout.write("\n");
15
- process.exit(1);
16
- }
17
- },
22
+ const question = {
23
+ onState,
18
24
  type: "multiselect",
19
25
  name: "agents",
20
26
  message: options.message,
21
27
  instructions: false,
22
- min: 1,
28
+ min: options.skipMessage ? 0 : 1,
23
29
  choices: options.choices.map((choice) => ({
24
30
  value: choice.id,
25
31
  title: choice.title,
26
32
  description: choice.description,
27
33
  selected: selected.has(choice.id)
28
34
  }))
29
- });
30
- if (!Array.isArray(agents)) throw new Error("Aborted: no agents selected.");
31
- const picked = [];
32
- for (const value of agents) {
33
- const id = agentIdInChoices(value, options.choices);
34
- if (id === void 0) throw new Error(`Unknown agent: "${String(value)}".`);
35
- picked.push(id);
35
+ };
36
+ while (true) {
37
+ const { agents } = await prompts(question);
38
+ if (!Array.isArray(agents)) return cancel();
39
+ const picked = [];
40
+ for (const value of agents) {
41
+ const id = agentIdInChoices(value, options.choices);
42
+ if (id === void 0) throw new Error(`Unknown agent: "${String(value)}".`);
43
+ picked.push(id);
44
+ }
45
+ if (picked.length > 0 || !options.skipMessage) return uniqueAgentIds(picked);
46
+ const { skip } = await prompts({
47
+ onState,
48
+ type: "confirm",
49
+ name: "skip",
50
+ message: options.skipMessage,
51
+ initial: true
52
+ });
53
+ if (typeof skip !== "boolean") return cancel();
54
+ if (skip) return [];
36
55
  }
37
- return uniqueAgentIds(picked);
38
56
  };
57
+ const skippableAgentPicker = (allowed, message) => allowed ? async (options) => {
58
+ const selected = await pickAgentsInteractively({
59
+ ...options,
60
+ skipMessage: message
61
+ });
62
+ if (selected.length === 0) throw new AgentSelectionSkipped();
63
+ return selected;
64
+ } : void 0;
39
65
  const resolveAgentSelection = async (options) => {
40
66
  if (options.specified.length > 0) {
41
67
  const resolve = options.resolveSpecified ?? resolveAddMcpAgentId;
@@ -67,4 +93,4 @@ const agentIdInChoices = (value, choices) => {
67
93
  for (const choice of choices) if (choice.id === value) return choice.id;
68
94
  };
69
95
  //#endregion
70
- export { agentChoicesFrom, canPickAgentsInteractively, pickAgentsInteractively, resolveAgentSelection };
96
+ export { AgentSelectionSkipped, agentChoicesFrom, canPickAgentsInteractively, pickAgentsInteractively, resolveAgentSelection, skippableAgentPicker };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "neon",
3
- "version": "6.2.3",
3
+ "version": "6.3.0",
4
4
  "description": "CLI tool for Neon, the cloud backend primitives built around Lakebase Postgres",
5
5
  "keywords": [
6
6
  "neon",
@@ -64,8 +64,8 @@
64
64
  "yaml": "^2.9.0",
65
65
  "yargs": "17.7.2",
66
66
  "yoctocolors": "^2.1.2",
67
- "@neon/config-runtime": "1.7.2",
68
67
  "@neon/config": "1.8.2",
68
+ "@neon/config-runtime": "1.7.2",
69
69
  "@neon/sdk": "6.1.2"
70
70
  },
71
71
  "optionalDependencies": {
@@ -99,9 +99,9 @@
99
99
  "tsx": "4.22.3",
100
100
  "typescript": "^5.9.0",
101
101
  "vitest": "^3.0.9",
102
+ "@neon-internals/cli-core": "0.0.0",
102
103
  "@neon-internals/env-core": "0.0.25",
103
104
  "@neon/e2e-harness": "0.0.0",
104
- "@neon-internals/cli-core": "0.0.0",
105
105
  "@neon/functions": "0.11.0"
106
106
  },
107
107
  "publishConfig": {
@@ -125,7 +125,7 @@
125
125
  "scripts": {
126
126
  "generateParams": "tsx generateOptionsFromSpec.ts",
127
127
  "clean": "rm -rf dist",
128
- "build": "pnpm generateParams && tsc --noEmit && tsdown && cp src/*.html ./dist",
128
+ "build": "pnpm generateParams && tsc --noEmit && tsdown && node scripts/build-callback.mjs",
129
129
  "build:internal": "pnpm build",
130
130
  "bundle": "node pkg.js",
131
131
  "typecheck": "tsc --noEmit",