neon 8.15.0 → 8.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/README.md +9 -5
  2. package/dist/_chunks/{checkout-BpOcFaAi.js → checkout-CNBIS3gA.js} +3 -3
  3. package/dist/_chunks/{claim-DlLZmcq0.js → claim-m5sIJdm5.js} +1 -1
  4. package/dist/_chunks/{config-BjCm5cfr.js → config-CgtJH8xE.js} +1 -1
  5. package/dist/_chunks/{databases-DC2h6IW2.js → databases-B2Yapqme.js} +9 -4
  6. package/dist/_chunks/{deploy-DmEEhux0.js → deploy-Bs5gmi4Q.js} +1 -1
  7. package/dist/_chunks/{dev-DlUJFzRs.js → dev-DxiIp4c9.js} +3 -3
  8. package/dist/_chunks/{docs-CClmgj_Z.js → docs-BpLiSTmm.js} +1 -1
  9. package/dist/_chunks/{functions-3ypiRwZK.js → functions-PHaU-kRb.js} +1 -1
  10. package/dist/_chunks/{git-j6xSVo3e.js → git-DRUZBCmZ.js} +2 -2
  11. package/dist/_chunks/{link-nAiuWKfg.js → link-CNO-HxHN.js} +2 -2
  12. package/dist/_chunks/{mcp-BznTRK3w.js → mcp-SvqWzHnT.js} +6 -4
  13. package/dist/_chunks/{plugins-CKOcBuuP.js → plugins-7cxVcgay.js} +5 -5
  14. package/dist/_chunks/{roles-xRuu0462.js → roles-BVc69rjG.js} +9 -4
  15. package/dist/_chunks/{status-BC4XXuuE.js → status-BlrzeKyA.js} +1 -1
  16. package/dist/analytics.js +4 -2
  17. package/dist/commands/bootstrap.js +1 -1
  18. package/dist/commands/checkout.js +1 -1
  19. package/dist/commands/claim.js +1 -1
  20. package/dist/commands/config.js +1 -1
  21. package/dist/commands/databases.js +1 -1
  22. package/dist/commands/deploy.js +1 -1
  23. package/dist/commands/dev.js +1 -1
  24. package/dist/commands/docs.js +1 -1
  25. package/dist/commands/env.js +1 -1
  26. package/dist/commands/functions.js +1 -1
  27. package/dist/commands/functions_new.js +3 -4
  28. package/dist/commands/git.js +1 -1
  29. package/dist/commands/index.js +17 -17
  30. package/dist/commands/link.js +1 -1
  31. package/dist/commands/mcp.js +1 -1
  32. package/dist/commands/plugins.js +1 -1
  33. package/dist/commands/roles.js +1 -1
  34. package/dist/commands/skills.js +1 -1
  35. package/dist/commands/status.js +1 -1
  36. package/dist/commands/subscribe.js +1 -1
  37. package/dist/env.js +19 -4
  38. package/dist/index.js +1 -1
  39. package/dist/init/agents.js +11 -3
  40. package/dist/init/auth.js +2 -2
  41. package/dist/init/copy.js +3 -2
  42. package/dist/init/detect.js +1 -2
  43. package/dist/init/link.js +1 -1
  44. package/dist/init/plan.js +2 -63
  45. package/dist/init/run.js +29 -20
  46. package/dist/init/tooling.js +5 -5
  47. package/dist/init/unknown_agent_arg.js +63 -0
  48. package/dist/init/wizard.js +6 -6
  49. package/dist/mcp/agents.js +25 -5
  50. package/dist/mcp/install.js +95 -30
  51. package/dist/mcp/targets.js +2 -3
  52. package/dist/plugins/child_env.js +10 -0
  53. package/dist/plugins/plan.js +14 -14
  54. package/dist/plugins/run.js +2 -8
  55. package/dist/plugins/targets.js +134 -15
  56. package/dist/skills/targets.js +1 -2
  57. package/dist/update_notifier.js +8 -5
  58. package/dist/utils/ai_gateway_notice.js +1 -1
  59. package/package.json +6 -5
  60. package/dist/_chunks/{bootstrap-BDkvsAVJ.js → bootstrap-vAtWRZXa.js} +2 -2
  61. package/dist/_chunks/{env-BOt9AZ1j.js → env-BtG4vH55.js} +1 -1
  62. package/dist/_chunks/{skills-DKgafm65.js → skills-Bv8oKKwE.js} +3 -3
package/dist/init/copy.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { getCliName } from "../utils/cli_name.js";
2
+ import { pluginsCommandProblemText } from "../plugins/targets.js";
2
3
  // src/init/copy.ts
3
4
  const INIT_SUBTITLE = "Set up coding agents and this directory for Neon.";
4
5
  const MODE_MESSAGE = "How would you like to set up Neon?";
@@ -16,7 +17,7 @@ const AGENT_SETUP_SKIP_DESCRIPTION = "Continue to project setup without changing
16
17
  const AGENT_PICKER_MESSAGE = "Which coding agents should receive Neon tooling? (space to toggle, enter to confirm)";
17
18
  const AGENT_DETECTED_DESCRIPTION = "Detected on this machine or in this directory.";
18
19
  const AGENT_OTHER_DESCRIPTION = "Install for this agent.";
19
- const agentMissingCommandDescription = (command) => `Detected, but "${command}" was not found on PATH. Its plugin cannot install.`;
20
+ const agentUnusableCommandDescription = (row) => `Detected, but "${row.command.name}" ${pluginsCommandProblemText(row)}. Its plugin cannot install.`;
20
21
  const AGENT_PLUGIN_SKIP_MESSAGE = "No agents selected. Continue without installing the Neon plugin?";
21
22
  const AGENT_SKILLS_PICKER_MESSAGE = "Which coding agents should receive Neon skills? (space to toggle, enter to confirm)";
22
23
  const AGENT_MCP_PICKER_MESSAGE = "Which coding agents should receive the Neon MCP server? (space to toggle, enter to confirm)";
@@ -184,4 +185,4 @@ const headingForOutcome = (outcome) => {
184
185
  default: return outcome;
185
186
  }
186
187
  };
187
- export { AGENTS_NOT_INSTALLED, 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, CANCELLED_BODY, CLAIMABLE_ACCOUNT_FLAGS, CLAIMABLE_ALREADY_LINKED, CLAIMABLE_MCP_API_KEY, CLAIMABLE_NO_LINK, CONFIG_CONFIRM_HINT, CONFIG_CONFIRM_MESSAGE, HEADING_CANCELLED, HEADING_COMPLETE, HEADING_FAILED, HEADING_PENDING, INIT_NEEDS_YES, INIT_SUBTITLE, MCP_API_KEY_NEEDS_AUTH, MCP_AUTH_API_KEY_DESCRIPTION, MCP_AUTH_API_KEY_TITLE, MCP_AUTH_MESSAGE, MCP_AUTH_OAUTH_DESCRIPTION, MCP_AUTH_OAUTH_TITLE, MCP_OAUTH_FALLBACK, MCP_SCOPED_NEEDS_PROJECT, 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, NON_TTY_AGENT_SETUP, NON_TTY_LINK_NEEDS_AUTH, NO_AGENTS_FALLBACK_STATUS, NO_AGENT_SETUP_CONFLICT, PACKAGE_MANAGER_MESSAGE, PROGRESS, PROJECT_PINNED_OFFLINE, 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, claimableNext, claimableThenServicesNext, configInitNext, envPullFailedNext, existingConfigNext, headingForOutcome, installFailedNext, mcpAfterLinkNext, mcpConfigLocationSkipped, mcpConfigLocationUnavailable, mcpKeyFailedNext, namedAgentsUnavailable, newConfigNext, offlinePinNext, skippedLinkNext, toolingFailedNext, unattendedUnauthedNext };
188
+ export { AGENTS_NOT_INSTALLED, 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, CANCELLED_BODY, CLAIMABLE_ACCOUNT_FLAGS, CLAIMABLE_ALREADY_LINKED, CLAIMABLE_MCP_API_KEY, CLAIMABLE_NO_LINK, CONFIG_CONFIRM_HINT, CONFIG_CONFIRM_MESSAGE, HEADING_CANCELLED, HEADING_COMPLETE, HEADING_FAILED, HEADING_PENDING, INIT_NEEDS_YES, INIT_SUBTITLE, MCP_API_KEY_NEEDS_AUTH, MCP_AUTH_API_KEY_DESCRIPTION, MCP_AUTH_API_KEY_TITLE, MCP_AUTH_MESSAGE, MCP_AUTH_OAUTH_DESCRIPTION, MCP_AUTH_OAUTH_TITLE, MCP_OAUTH_FALLBACK, MCP_SCOPED_NEEDS_PROJECT, 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, NON_TTY_AGENT_SETUP, NON_TTY_LINK_NEEDS_AUTH, NO_AGENTS_FALLBACK_STATUS, NO_AGENT_SETUP_CONFLICT, PACKAGE_MANAGER_MESSAGE, PROGRESS, PROJECT_PINNED_OFFLINE, 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, agentUnusableCommandDescription, claimableNext, claimableThenServicesNext, configInitNext, envPullFailedNext, existingConfigNext, headingForOutcome, installFailedNext, mcpAfterLinkNext, mcpConfigLocationSkipped, mcpConfigLocationUnavailable, mcpKeyFailedNext, namedAgentsUnavailable, newConfigNext, offlinePinNext, skippedLinkNext, toolingFailedNext, unattendedUnauthedNext };
@@ -2,13 +2,12 @@ import { t as storeFor } from "../_chunks/credential_io-DbeSh3Pl.js";
2
2
  import { isCi } from "../env.js";
3
3
  import { h as resolveProfile, u as locationOf } from "../_chunks/profiles-DTazQtjK.js";
4
4
  import { i as selectCredential, t as credentialInputs } from "../_chunks/auth_selection-CwGLN9Qz.js";
5
- import { detectInstalledAgents, uniqueAgentIds } from "../mcp/agents.js";
5
+ import { detectInstalledAgents, detectProjectAgents, uniqueAgentIds } from "../mcp/agents.js";
6
6
  import "./agents.js";
7
7
  import { directoryIsEmpty } from "./plan.js";
8
8
  import { detectAgent } from "./detect_host.js";
9
9
  import { canPickAgentsInteractively } from "../utils/agent_picker.js";
10
10
  import { existsSync, readdirSync } from "node:fs";
11
- import { detectProjectAgents } from "add-mcp";
12
11
  // src/init/detect.ts
13
12
  const listingHasCredentials = (configDir, profile) => {
14
13
  try {
package/dist/init/link.js CHANGED
@@ -4,7 +4,7 @@ import "../config.js";
4
4
  import "../auth.js";
5
5
  import { c as ensureAuth } from "../_chunks/auth-rup6nemJ.js";
6
6
  import { recoverFrom401 } from "../auth_recovery.js";
7
- import { s as runLink } from "../_chunks/link-nAiuWKfg.js";
7
+ import { s as runLink } from "../_chunks/link-CNO-HxHN.js";
8
8
  // src/init/link.ts
9
9
  const isUnauthorized = (error) => isNeonApiError(error) && error.status === 401;
10
10
  const authenticationFailed = () => /* @__PURE__ */ new Error("Authentication failed.");
package/dist/init/plan.js CHANGED
@@ -1,8 +1,8 @@
1
1
  import { getCliName } from "../utils/cli_name.js";
2
2
  import { tryResolveAddMcpAgentId, uniqueAgentIds } from "../mcp/agents.js";
3
- import { mcpInstallableAgents } from "../mcp/targets.js";
4
3
  import { supportsSkills } from "./agents.js";
5
4
  import { pluginsInstallableAgents } from "../plugins/targets.js";
5
+ import { mcpInstallableAgents } from "../mcp/targets.js";
6
6
  import { skillsInstallableAgents } from "../skills/targets.js";
7
7
  import { agentArgv } from "../utils/agent_flag.js";
8
8
  import { isAbsolute, join, relative, resolve } from "node:path";
@@ -92,67 +92,6 @@ const noDetectedAgentsMessage = (input) => {
92
92
  return `${lead} ${hint} Supported agents: ${input.supported.join(", ")}`;
93
93
  };
94
94
  const INIT_NEEDS_YES_OR_TERMINAL = "No interactive terminal. Pass -y to use defaults, or run this command in a terminal to pick.";
95
- const UNKNOWN_AGENT_COMMANDS = ["link"];
96
- const unknownAgentArgHint = (command, cliName) => `${cliName} ${command} has no --agent. Pass --project-id <id> to link without a TTY, or run ${cliName} ${command} in a terminal.`;
97
- const BOOLEAN_FLAGS = /* @__PURE__ */ new Set([
98
- "-y",
99
- "--yes",
100
- "--default",
101
- "--force",
102
- "-h",
103
- "--help",
104
- "-v",
105
- "--version",
106
- "--color",
107
- "--no-color",
108
- "--analytics",
109
- "--no-analytics",
110
- "--oauth",
111
- "--project",
112
- "--global",
113
- "--read-only",
114
- "--readonly",
115
- "--clear",
116
- "--checks",
117
- "--no-checks",
118
- "--env-pull",
119
- "--no-env-pull",
120
- "--no-agent-setup",
121
- "--no-link",
122
- "--no-config",
123
- "--claimable",
124
- "--config",
125
- "--list",
126
- "--list-templates",
127
- "--force-auth",
128
- "--no-force-auth"
129
- ]);
130
- const isUnknownAgentCommand = (token) => {
131
- for (const command of UNKNOWN_AGENT_COMMANDS) if (command === token) return true;
132
- return false;
133
- };
134
- const commandFromArgv = (argv) => {
135
- let skipValue = false;
136
- for (const token of argv) {
137
- if (skipValue) {
138
- skipValue = false;
139
- continue;
140
- }
141
- if (token === "--") break;
142
- if (token.startsWith("-")) {
143
- const flag = token.split("=")[0];
144
- if (flag !== void 0 && !token.includes("=") && !BOOLEAN_FLAGS.has(flag)) skipValue = true;
145
- continue;
146
- }
147
- if (isUnknownAgentCommand(token)) return token;
148
- }
149
- };
150
- const rewriteUnknownAgentArg = (input) => {
151
- if (input.message !== "Unknown argument: agent" && input.message !== "Unknown argument: a") return;
152
- const command = commandFromArgv(input.argv);
153
- if (command === void 0) return;
154
- return unknownAgentArgHint(command, input.cliName);
155
- };
156
95
  const initYesSupportedAgents = () => uniqueAgentIds([
157
96
  ...pluginsInstallableAgents("project"),
158
97
  ...skillsInstallableAgents(),
@@ -385,4 +324,4 @@ const resolveInitAgentSetup = async (input) => {
385
324
  if (input.interactive) return input.pick();
386
325
  throw new Error(INIT_NEEDS_YES_OR_TERMINAL);
387
326
  };
388
- export { FALLBACK_SKILLS_AGENTS, INIT_NEEDS_YES_OR_TERMINAL, NAMED_AGENTS_MIXED, NAMED_AGENTS_UNSUPPORTED, assertNamedAgentTooling, bootstrapInitStep, chooseYesAgentTooling, collectYesAgents, directoryIsEmpty, funnelAgentSetup, initPluginAgents, initSkillsMcpAgents, initYesSupportedAgents, linkInputArgv, namedAgentsMixedMessage, namedAgentsNeedSplit, noDetectedAgentsMessage, planAgentSteps, planConfigInitStep, planInitToolingSteps, planLinkStep, planToolingSteps, planYesAgentSteps, postScaffoldActions, projectContextFile, recommendedTooling, resolveInitAgentSetup, resolveNamedAgents, resolveYesAgentList, rewriteUnknownAgentArg, splitInitTooling };
327
+ export { FALLBACK_SKILLS_AGENTS, INIT_NEEDS_YES_OR_TERMINAL, NAMED_AGENTS_MIXED, NAMED_AGENTS_UNSUPPORTED, assertNamedAgentTooling, bootstrapInitStep, chooseYesAgentTooling, collectYesAgents, directoryIsEmpty, funnelAgentSetup, initPluginAgents, initSkillsMcpAgents, initYesSupportedAgents, linkInputArgv, namedAgentsMixedMessage, namedAgentsNeedSplit, noDetectedAgentsMessage, planAgentSteps, planConfigInitStep, planInitToolingSteps, planLinkStep, planToolingSteps, planYesAgentSteps, postScaffoldActions, projectContextFile, recommendedTooling, resolveInitAgentSetup, resolveNamedAgents, resolveYesAgentList, splitInitTooling };
package/dist/init/run.js CHANGED
@@ -9,23 +9,23 @@ import { getCliName } from "../utils/cli_name.js";
9
9
  import { servicesFlagValue } from "../neon_services.js";
10
10
  import { CONFIG_INIT_SERVICES, parseConfigInitServices } from "../config_template.js";
11
11
  import { hasNeonConfigFile, neonConfigFilename } from "../project.js";
12
- import { getAgentDisplayName } from "../mcp/agents.js";
13
- import { mcpInstallableAgents } from "../mcp/targets.js";
14
- import { missingPluginsCommands, pluginsInstallableAgents } from "../plugins/targets.js";
15
- import { skillsInstallableAgents } from "../skills/targets.js";
16
- import { FALLBACK_SKILLS_AGENTS, assertNamedAgentTooling, funnelAgentSetup, planInitToolingSteps, recommendedTooling, resolveNamedAgents, splitInitTooling } from "./plan.js";
17
12
  import { inferPackageManager, resolvePackageManager } from "../utils/package_manager.js";
13
+ import { getAgentDisplayName } from "../mcp/agents.js";
14
+ import { missingPluginsCommands, pluginsCommandProblemText, pluginsInstallableAgents, unusablePluginsCommands } from "../plugins/targets.js";
18
15
  import { AGENTS_NOT_INSTALLED, CANCELLED_BODY, CLAIMABLE_ACCOUNT_FLAGS, CLAIMABLE_ALREADY_LINKED, CLAIMABLE_MCP_API_KEY, CLAIMABLE_NO_LINK, MCP_API_KEY_NEEDS_AUTH, MCP_SCOPED_NEEDS_PROJECT, NON_TTY_LINK_NEEDS_AUTH, NO_AGENTS_FALLBACK_STATUS, PROGRESS, PROJECT_PINNED_OFFLINE, claimableNext, claimableThenServicesNext, configInitNext, envPullFailedNext, existingConfigNext, installFailedNext, mcpAfterLinkNext, mcpConfigLocationSkipped, mcpConfigLocationUnavailable, mcpKeyFailedNext, namedAgentsUnavailable, newConfigNext, offlinePinNext, skippedLinkNext, toolingFailedNext, unattendedUnauthedNext } from "./copy.js";
19
16
  import { agentsRowValue, configRowValue, formatInitDone, headingForKind, printInitBanner, printInitDone, printInitProgress, projectRowValue, shouldPrintInitBanner } from "./chrome.js";
20
- import { h as initCmd, t as ConfigInstallFailed } from "../_chunks/config-BjCm5cfr.js";
21
- import { o as quoteFlagValue, s as runLink } from "../_chunks/link-nAiuWKfg.js";
17
+ import { h as initCmd, t as ConfigInstallFailed } from "../_chunks/config-CgtJH8xE.js";
18
+ import { o as quoteFlagValue, s as runLink } from "../_chunks/link-CNO-HxHN.js";
22
19
  import { runAuthenticatedLink } from "./link.js";
20
+ import { mcpInstallableAgents } from "../mcp/targets.js";
21
+ import { skillsInstallableAgents } from "../skills/targets.js";
22
+ import { FALLBACK_SKILLS_AGENTS, assertNamedAgentTooling, funnelAgentSetup, planInitToolingSteps, recommendedTooling, resolveNamedAgents, splitInitTooling } from "./plan.js";
23
23
  import { CannotMintApiKeyError } from "../mcp/mint.js";
24
24
  import { pullInitEnv, resolveInitConfigApi } from "./auth.js";
25
25
  import { InitCancelled, raceSigint, restoreCursor } from "./cancelled.js";
26
26
  import { pickAgentSetupInteractively, pickInitAgentsInteractively, pickInitConfigInteractively, pickInitMcpAuthInteractively, pickInitMcpConfigLocationInteractively, pickInitModeInteractively, pickInitPackageManagerInteractively, pickInitProjectSetupInteractively, pickInitServicesInteractively, pickInitSkillsInteractively } from "./wizard.js";
27
27
  import { runToolingSteps, toolingStepCommandText } from "./tooling.js";
28
- import { l as create } from "../_chunks/claim-DlLZmcq0.js";
28
+ import { l as create } from "../_chunks/claim-m5sIJdm5.js";
29
29
  import { INIT_CONFIG_SERVICES_CONFLICT, configPlanFromResolution, initEnvPullAfterConfig, resolveInitConfigChoice } from "./choices.js";
30
30
  import { detectInitEnvironment } from "./detect.js";
31
31
  import { createInitFunnel, emitInitStart, finishInitFunnel, initStartProperties, recordInitError, recordInitExit } from "./funnel.js";
@@ -67,10 +67,10 @@ const pluginScopeFor = (agents, preferred) => {
67
67
  const project = new Set(pluginsInstallableAgents("project"));
68
68
  return agents.some((id) => !project.has(id) && pluginsInstallableAgents("global").includes(id)) ? "global" : "project";
69
69
  };
70
- const warnMissingPluginCommands = (missing, tooling) => {
70
+ const warnUnusablePluginCommands = (unusable, tooling) => {
71
71
  if (tooling.setup !== "skills-mcp" && tooling.setup !== "mixed") return;
72
72
  const routed = /* @__PURE__ */ new Set([...tooling.skillsAgents, ...tooling.mcpAgents]);
73
- for (const { agent, command } of missing) if (routed.has(agent)) log.warning("%s: \"%s\" was not found on PATH, so its plugin cannot install. Installing Neon skills and MCP instead.", getAgentDisplayName(agent), command);
73
+ for (const row of unusable) if (routed.has(row.agent)) log.warning("%s: \"%s\" %s, so its plugin cannot install. Installing Neon skills and MCP instead.", getAgentDisplayName(row.agent), row.command.name, pluginsCommandProblemText(row));
74
74
  };
75
75
  const nonEmptyAgents = (ids, fallback) => {
76
76
  const [first, ...rest] = ids;
@@ -124,7 +124,7 @@ const pickOrDetectAgents = async (input) => {
124
124
  available: [...input.available],
125
125
  detected,
126
126
  preselected,
127
- ...input.missingCommands !== void 0 ? { missingCommands: input.missingCommands } : {},
127
+ ...input.unusableCommands !== void 0 ? { unusableCommands: input.unusableCommands } : {},
128
128
  setup: input.setup
129
129
  });
130
130
  return detected;
@@ -265,9 +265,18 @@ const runInit = async (props) => {
265
265
  }
266
266
  const recommended = mode === "recommended";
267
267
  const targets = named.length > 0 ? named : detection.detectedAgents;
268
- const missingPluginCommands = missingPluginsCommands(targets, { cwd });
269
- const unavailablePluginAgents = missingPluginCommands.map((row) => row.agent);
270
- const pluginReady = (agents) => agents.filter((id) => !unavailablePluginAgents.includes(id));
268
+ let probedPluginCommands;
269
+ const unusablePluginCommands = () => {
270
+ probedPluginCommands ??= unusablePluginsCommands(targets, { cwd });
271
+ return probedPluginCommands;
272
+ };
273
+ let missingCommands;
274
+ const missingPluginCommands = () => {
275
+ missingCommands ??= missingPluginsCommands(targets, { cwd });
276
+ return missingCommands;
277
+ };
278
+ const unavailablePluginAgents = () => unusablePluginCommands().map((row) => row.agent);
279
+ const pluginReady = (agents) => agents.filter((id) => !unavailablePluginAgents().includes(id));
271
280
  let tooling = { setup: "skip" };
272
281
  let mcpAuth = props.mcpAuth;
273
282
  let mcpAuthChosen = props.mcpAuth !== void 0;
@@ -277,9 +286,9 @@ const runInit = async (props) => {
277
286
  let pluginScope = recommended ? "global" : "project";
278
287
  if (recommended) {
279
288
  pluginScope = "global";
280
- tooling = named.length > 0 ? splitInitTooling(named, "global", "global", unavailablePluginAgents) : recommendedTooling(detection.detectedAgents, unavailablePluginAgents);
289
+ tooling = named.length > 0 ? splitInitTooling(named, "global", "global", unavailablePluginAgents()) : recommendedTooling(detection.detectedAgents, unavailablePluginAgents());
281
290
  if (named.length === 0 && detection.detectedAgents.length === 0) printInitProgress(NO_AGENTS_FALLBACK_STATUS);
282
- warnMissingPluginCommands(missingPluginCommands, tooling);
291
+ warnUnusablePluginCommands(unusablePluginCommands(), tooling);
283
292
  mcpAuth = !detection.authenticated && (tooling.setup === "skills-mcp" || tooling.setup === "mixed") ? "oauth" : mcpAuth;
284
293
  } else {
285
294
  const inferred = inferInitAgentSetup({
@@ -294,8 +303,8 @@ const runInit = async (props) => {
294
303
  else if (inferred.kind === "auto") {
295
304
  const autoAgents = named.length > 0 ? named : detection.detectedAgents;
296
305
  pluginScope = pluginScopeFor(pluginReady(autoAgents), "project");
297
- tooling = splitInitTooling(autoAgents, pluginScope, mcpConfigLocation, unavailablePluginAgents);
298
- warnMissingPluginCommands(missingPluginCommands, tooling);
306
+ tooling = splitInitTooling(autoAgents, pluginScope, mcpConfigLocation, unavailablePluginAgents());
307
+ warnUnusablePluginCommands(unusablePluginCommands(), tooling);
299
308
  if (tooling.setup === "skip" && yes && named.length === 0) {
300
309
  tooling = recommendedTooling([]);
301
310
  printInitProgress(NO_AGENTS_FALLBACK_STATUS);
@@ -310,8 +319,8 @@ const runInit = async (props) => {
310
319
  available,
311
320
  detected: detection.detectedAgents,
312
321
  ...setup === "plugin" ? {
313
- preselected: pluginReady(detection.detectedAgents),
314
- missingCommands: missingPluginCommands
322
+ preselected: detection.detectedAgents.filter((id) => !missingPluginCommands().some((row) => row.agent === id)),
323
+ unusableCommands: missingPluginCommands()
315
324
  } : {},
316
325
  interactive: detection.interactive,
317
326
  setup,
@@ -1,17 +1,17 @@
1
1
  import { log } from "../log.js";
2
2
  import { getCliName } from "../utils/cli_name.js";
3
- import { assertNamedAgentTooling, chooseYesAgentTooling, collectYesAgents, initYesSupportedAgents, noDetectedAgentsMessage, planAgentSteps, planToolingSteps, planYesAgentSteps, resolveInitAgentSetup } from "./plan.js";
3
+ import { detectProjectAgents } from "../mcp/agents.js";
4
4
  import { MCP_OAUTH_FALLBACK, PROGRESS } from "./copy.js";
5
+ import { assertNamedAgentTooling, chooseYesAgentTooling, collectYesAgents, initYesSupportedAgents, noDetectedAgentsMessage, planAgentSteps, planToolingSteps, planYesAgentSteps, resolveInitAgentSetup } from "./plan.js";
5
6
  import { CannotMintApiKeyError } from "../mcp/mint.js";
6
7
  import { detectAgent } from "./detect_host.js";
7
8
  import { AgentSelectionSkipped, canPickAgentsInteractively } from "../utils/agent_picker.js";
8
- import { a as mcpInstallError, s as reportMcpInstall } from "../_chunks/mcp-BznTRK3w.js";
9
- import { l as reportPluginsInstall, o as installPlugins, s as pluginsInstallError } from "../_chunks/plugins-CKOcBuuP.js";
10
- import { c as skillsInstallError, o as installSkills, s as reportSkillsInstall } from "../_chunks/skills-DKgafm65.js";
9
+ import { a as mcpInstallError, s as reportMcpInstall } from "../_chunks/mcp-SvqWzHnT.js";
10
+ import { l as reportPluginsInstall, o as installPlugins, s as pluginsInstallError } from "../_chunks/plugins-7cxVcgay.js";
11
+ import { c as skillsInstallError, o as installSkills, s as reportSkillsInstall } from "../_chunks/skills-Bv8oKKwE.js";
11
12
  import { runAuthenticatedMcp } from "./auth.js";
12
13
  import { raceSigint } from "./cancelled.js";
13
14
  import { pickAgentSetupInteractively } from "./wizard.js";
14
- import { detectProjectAgents } from "add-mcp";
15
15
  // src/init/tooling.ts
16
16
  const defaultProjectAgents = (cwd) => detectProjectAgents(cwd);
17
17
  const TOOLING_STEP_LABELS = {
@@ -0,0 +1,63 @@
1
+ // src/init/unknown_agent_arg.ts
2
+ const UNKNOWN_AGENT_COMMANDS = ["link"];
3
+ const unknownAgentArgHint = (command, cliName) => `${cliName} ${command} has no --agent. Pass --project-id <id> to link without a TTY, or run ${cliName} ${command} in a terminal.`;
4
+ const BOOLEAN_FLAGS = /* @__PURE__ */ new Set([
5
+ "-y",
6
+ "--yes",
7
+ "--default",
8
+ "--force",
9
+ "-h",
10
+ "--help",
11
+ "-v",
12
+ "--version",
13
+ "--color",
14
+ "--no-color",
15
+ "--analytics",
16
+ "--no-analytics",
17
+ "--oauth",
18
+ "--project",
19
+ "--global",
20
+ "--read-only",
21
+ "--readonly",
22
+ "--clear",
23
+ "--checks",
24
+ "--no-checks",
25
+ "--env-pull",
26
+ "--no-env-pull",
27
+ "--no-agent-setup",
28
+ "--no-link",
29
+ "--no-config",
30
+ "--claimable",
31
+ "--config",
32
+ "--list",
33
+ "--list-templates",
34
+ "--force-auth",
35
+ "--no-force-auth"
36
+ ]);
37
+ const isUnknownAgentCommand = (token) => {
38
+ for (const command of UNKNOWN_AGENT_COMMANDS) if (command === token) return true;
39
+ return false;
40
+ };
41
+ const commandFromArgv = (argv) => {
42
+ let skipValue = false;
43
+ for (const token of argv) {
44
+ if (skipValue) {
45
+ skipValue = false;
46
+ continue;
47
+ }
48
+ if (token === "--") break;
49
+ if (token.startsWith("-")) {
50
+ const flag = token.split("=")[0];
51
+ if (flag !== void 0 && !token.includes("=") && !BOOLEAN_FLAGS.has(flag)) skipValue = true;
52
+ continue;
53
+ }
54
+ if (isUnknownAgentCommand(token)) return token;
55
+ }
56
+ };
57
+ const rewriteUnknownAgentArg = (input) => {
58
+ if (input.message !== "Unknown argument: agent" && input.message !== "Unknown argument: a") return;
59
+ const command = commandFromArgv(input.argv);
60
+ if (command === void 0) return;
61
+ return unknownAgentArgHint(command, input.cliName);
62
+ };
63
+ export { rewriteUnknownAgentArg };
@@ -1,9 +1,9 @@
1
1
  import { CONFIG_INIT_SERVICES } from "../config_template.js";
2
- import { getAgentDisplayName, listMcpAgentIds } from "../mcp/agents.js";
3
- import { INIT_NEEDS_YES_OR_TERMINAL } from "./plan.js";
4
2
  import { installedPackageManagers } from "../utils/package_manager.js";
5
- 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
+ import { getAgentDisplayName, listMcpAgentIds } from "../mcp/agents.js";
4
+ 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, agentUnusableCommandDescription } from "./copy.js";
6
5
  import { POSTGRES_SERVICE_CHOICE, keepPostgresSelected } from "../utils/service_picker.js";
6
+ import { INIT_NEEDS_YES_OR_TERMINAL } from "./plan.js";
7
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";
@@ -72,18 +72,18 @@ const pickAgentSetupInteractively = async () => {
72
72
  const pickInitAgentsInteractively = async (input) => {
73
73
  requireInteractive();
74
74
  const detected = new Set(input.detected);
75
- const missing = new Map((input.missingCommands ?? []).map((row) => [row.agent, row.command]));
75
+ const unusable = new Map((input.unusableCommands ?? []).map((row) => [row.agent, row]));
76
76
  const selected = await pickAgentsInteractively({
77
77
  onCancel: aborted,
78
78
  message: input.setup === "skills" ? AGENT_SKILLS_PICKER_MESSAGE : input.setup === "mcp" ? AGENT_MCP_PICKER_MESSAGE : AGENT_PICKER_MESSAGE,
79
79
  skipMessage: input.setup === "plugin" ? AGENT_PLUGIN_SKIP_MESSAGE : input.setup === "skills" ? AGENT_SKILLS_SKIP_MESSAGE : AGENT_MCP_SKIP_MESSAGE,
80
80
  selected: input.preselected ?? input.detected,
81
81
  choices: input.available.map((id) => {
82
- const command = missing.get(id);
82
+ const row = unusable.get(id);
83
83
  return {
84
84
  id,
85
85
  title: `${getAgentDisplayName(id)} (${id})`,
86
- description: command !== void 0 ? agentMissingCommandDescription(command) : detected.has(id) ? AGENT_DETECTED_DESCRIPTION : AGENT_OTHER_DESCRIPTION
86
+ description: row !== void 0 ? agentUnusableCommandDescription(row) : detected.has(id) ? AGENT_DETECTED_DESCRIPTION : AGENT_OTHER_DESCRIPTION
87
87
  };
88
88
  })
89
89
  });
@@ -1,5 +1,7 @@
1
- import { agents, detectGlobalAgents, getAgentTypes } from "add-mcp";
1
+ import { agents, detectGlobalAgents, detectProjectAgents as detectProjectAgents$1, getAgentTypes } from "add-mcp";
2
2
  // src/mcp/agents.ts
3
+ const UNSUPPORTED_AGENTS = /* @__PURE__ */ new Set(["mastracode"]);
4
+ const isSupportedAgent = (id) => !UNSUPPORTED_AGENTS.has(id);
3
5
  const AGENT_ALIASES = {
4
6
  cursor: "cursor",
5
7
  copilot: "vscode",
@@ -25,10 +27,25 @@ const AGENT_ALIASES = {
25
27
  mcporter: "mcporter",
26
28
  zed: "zed",
27
29
  grok: "grok-build",
28
- "grok-build": "grok-build"
30
+ "grok-build": "grok-build",
31
+ "factory-droid": "factory-droid",
32
+ droid: "factory-droid",
33
+ factory: "factory-droid",
34
+ fx: "fx",
35
+ hermes: "hermes",
36
+ "hermes-agent": "hermes",
37
+ junie: "junie",
38
+ "kilo-code": "kilo-code",
39
+ kilo: "kilo-code",
40
+ "kimi-code": "kimi-code",
41
+ kimi: "kimi-code",
42
+ "kimi-code-cli": "kimi-code",
43
+ "kiro-cli": "kiro-cli",
44
+ kiro: "kiro-cli",
45
+ pi: "pi"
29
46
  };
30
47
  function listMcpAgentIds() {
31
- return getAgentTypes();
48
+ return getAgentTypes().filter(isSupportedAgent);
32
49
  }
33
50
  function getAgentDisplayName(id) {
34
51
  return agents[id].displayName;
@@ -48,7 +65,10 @@ function resolveAddMcpAgentId(rawAgent) {
48
65
  return resolved;
49
66
  }
50
67
  async function detectInstalledAgents() {
51
- return detectGlobalAgents();
68
+ return (await detectGlobalAgents()).filter(isSupportedAgent);
69
+ }
70
+ function detectProjectAgents(cwd) {
71
+ return detectProjectAgents$1(cwd).filter(isSupportedAgent);
52
72
  }
53
73
  function uniqueAgentIds(ids) {
54
74
  const seen = /* @__PURE__ */ new Set();
@@ -60,4 +80,4 @@ function uniqueAgentIds(ids) {
60
80
  }
61
81
  return out;
62
82
  }
63
- export { agentSupportsHttpMcp, agentSupportsProjectMcp, detectInstalledAgents, getAgentDisplayName, listMcpAgentIds, resolveAddMcpAgentId, tryResolveAddMcpAgentId, uniqueAgentIds };
83
+ export { agentSupportsHttpMcp, agentSupportsProjectMcp, detectInstalledAgents, detectProjectAgents, getAgentDisplayName, listMcpAgentIds, resolveAddMcpAgentId, tryResolveAddMcpAgentId, uniqueAgentIds };
@@ -1,7 +1,9 @@
1
- import { chmodSync, existsSync, readFileSync, writeFileSync } from "node:fs";
2
- import { basename, dirname, join } from "node:path";
3
- import { agents, upsertServer } from "add-mcp";
1
+ import { getCliName } from "../utils/cli_name.js";
2
+ import { chmodSync, existsSync, readFileSync, rmSync, writeFileSync } from "node:fs";
3
+ import { basename, dirname, join, relative } from "node:path";
4
4
  import { execFileSync } from "node:child_process";
5
+ import { agents, upsertServer } from "add-mcp";
6
+ import { parse } from "jsonc-parser";
5
7
  // src/mcp/install.ts
6
8
  const NEON_MCP_URL = "https://mcp.neon.tech/mcp";
7
9
  const NEON_MCP_NAME = "Neon";
@@ -45,6 +47,7 @@ function neonMcpUrl(options = {}) {
45
47
  }
46
48
  const BEARER_RE = /Bearer\s+([^\s"]+)/i;
47
49
  function nestedValue(root, key) {
50
+ if (key === "") return root;
48
51
  let current = root;
49
52
  for (const part of key.split(".")) {
50
53
  if (!current || typeof current !== "object" || Array.isArray(current)) return;
@@ -77,35 +80,50 @@ function neonApiKeyFromFile(path, configKey) {
77
80
  } catch {
78
81
  return;
79
82
  }
80
- try {
81
- return bearerFromNeonMcpConfig(neonServers(nestedValue(JSON.parse(raw), configKey)));
82
- } catch {
83
- const neonBlock = raw.match(/\[mcp_servers\.Neon\][\s\S]*?(?=\n\[|$)/)?.[0];
84
- if (!neonBlock) return;
85
- const url = neonBlock.match(/^url\s*=\s*"([^"]*)"/m)?.[1];
86
- if (!url || !isNeonMcpUrl(url)) return;
87
- return BEARER_RE.exec(neonBlock)?.[1];
88
- }
83
+ const errors = [];
84
+ const parsed = parse(raw, errors, { allowTrailingComma: true });
85
+ if (errors.length === 0) return bearerFromNeonMcpConfig(neonServers(nestedValue(parsed, configKey)));
86
+ const neonBlock = raw.match(/\[mcp_servers\.Neon\][\s\S]*?(?=\n\[|$)/)?.[0];
87
+ if (!neonBlock) return;
88
+ const url = neonBlock.match(/^url\s*=\s*"([^"]*)"/m)?.[1];
89
+ if (!url || !isNeonMcpUrl(url)) return;
90
+ return BEARER_RE.exec(neonBlock)?.[1];
91
+ }
92
+ /**
93
+ * Claude Code installs first so that a GitHub Copilot CLI install in the same run resolves to
94
+ * the `.mcp.json` Claude Code creates, rather than to `.github/mcp.json`.
95
+ */
96
+ function mcpInstallOrder(selected) {
97
+ return [...selected.filter((agent) => agent === "claude-code"), ...selected.filter((agent) => agent !== "claude-code")];
89
98
  }
90
- function configPathFor(agent, scope, cwd) {
99
+ /** The file add-mcp's `upsertServer` writes for this agent when `selected` install in `mcpInstallOrder`. */
100
+ function configPathFor(agent, scope, cwd, selected) {
91
101
  const spec = agents[agent];
92
- if (scope === "project") {
93
- if (!spec.localConfigPath) return;
94
- return join(cwd, spec.localConfigPath);
95
- }
96
- return spec.configPath;
102
+ const local = scope === "project";
103
+ if (local && !spec.localConfigPath) return;
104
+ if (local && agent === "github-copilot-cli" && selected.includes("claude-code")) return join(cwd, ".mcp.json");
105
+ if (spec.resolveConfigPath) return spec.resolveConfigPath(spec, {
106
+ local,
107
+ cwd
108
+ });
109
+ return local && spec.localConfigPath ? join(cwd, spec.localConfigPath) : spec.configPath;
97
110
  }
98
- function configKeyFor(agent, scope) {
111
+ /** Where an existing Neon entry can sit, depending on the file's current layout. */
112
+ function configKeysFor(agent, scope) {
99
113
  const spec = agents[agent];
100
- if (scope === "project" && spec.localConfigKey) return spec.localConfigKey;
101
- return spec.configKey;
114
+ if (agent === "opencode") return ["mcp.servers", "mcp"];
115
+ if (agent === "github-copilot-cli" && scope === "project") return ["mcpServers", ""];
116
+ if (scope === "project" && spec.localConfigKey) return [spec.localConfigKey];
117
+ return [spec.configKey];
102
118
  }
103
119
  function existingNeonApiKey(options) {
104
120
  for (const agent of options.agents) {
105
- const path = configPathFor(agent, options.scope, options.cwd);
121
+ const path = configPathFor(agent, options.scope, options.cwd, options.agents);
106
122
  if (!path) continue;
107
- const key = neonApiKeyFromFile(path, configKeyFor(agent, options.scope));
108
- if (key) return key;
123
+ for (const configKey of configKeysFor(agent, options.scope)) {
124
+ const key = neonApiKeyFromFile(path, configKey);
125
+ if (key) return key;
126
+ }
109
127
  }
110
128
  }
111
129
  function isTrackedByGit(cwd, relativePath) {
@@ -129,15 +147,31 @@ function isTrackedByGit(cwd, relativePath) {
129
147
  }
130
148
  function trackedProjectMcpConfig(options) {
131
149
  for (const agent of options.agents) {
132
- const relativePath = agents[agent].localConfigPath;
133
- if (!relativePath) continue;
150
+ const path = configPathFor(agent, "project", options.cwd, options.agents);
151
+ if (!path) continue;
152
+ const relativePath = relative(options.cwd, path);
134
153
  if (isTrackedByGit(options.cwd, relativePath)) return relativePath;
135
154
  }
136
155
  }
137
- function mcpUnsupportedReason(agent, scope) {
156
+ function mcpUnsupportedReason(agent, scope, auth) {
138
157
  const spec = agents[agent];
139
158
  if (!spec.supportedTransports.includes("http")) return spec.unsupportedTransportMessage ?? `${spec.displayName} does not support remote HTTP MCP servers.`;
140
159
  if (scope === "project" && !spec.localConfigPath) return `${spec.displayName} does not support project-level MCP config.`;
160
+ if (agent === "fx" && auth === "api-key") return `fx does not accept an API key in its MCP config. Run \`${getCliName()} mcp --oauth --agent fx\`.`;
161
+ }
162
+ /**
163
+ * add-mcp refuses a project-level Claude Code install while `.github/mcp.json` exists without
164
+ * `.mcp.json`, because GitHub Copilot CLI reads `.mcp.json` first once it exists. Neon writes
165
+ * Claude Code's file anyway, so it creates `.mcp.json` before calling add-mcp.
166
+ */
167
+ function createClaudeProjectConfig(cwd) {
168
+ const path = join(cwd, ".mcp.json");
169
+ if (existsSync(path) || !existsSync(join(cwd, ".github", "mcp.json"))) return;
170
+ writeFileSync(path, "{\n \"mcpServers\": {}\n}\n");
171
+ return path;
172
+ }
173
+ function errorMessage(err) {
174
+ return err instanceof Error ? err.message : String(err);
141
175
  }
142
176
  function gitignoreProjectConfig(path) {
143
177
  const dir = dirname(path);
@@ -171,7 +205,7 @@ function redactSecrets(text) {
171
205
  function installNeonMcpServer(options) {
172
206
  const auth = options.auth ?? { kind: "oauth" };
173
207
  const url = options.url ?? "https://mcp.neon.tech/mcp";
174
- const unsupported = mcpUnsupportedReason(options.agent, options.scope);
208
+ const unsupported = mcpUnsupportedReason(options.agent, options.scope, auth.kind);
175
209
  if (unsupported) return {
176
210
  ok: false,
177
211
  unsupported: true,
@@ -185,10 +219,41 @@ function installNeonMcpServer(options) {
185
219
  type: "http",
186
220
  url
187
221
  };
222
+ const cwd = options.cwd ?? process.cwd();
223
+ let created;
224
+ if (options.agent === "claude-code" && options.scope === "project") try {
225
+ created = createClaudeProjectConfig(cwd);
226
+ } catch (err) {
227
+ return {
228
+ ok: false,
229
+ unsupported: false,
230
+ error: `Could not create ${join(cwd, ".mcp.json")}: ${errorMessage(err)}`
231
+ };
232
+ }
233
+ if (options.scope === "project" && auth.kind === "api-key") {
234
+ const tracked = trackedProjectMcpConfig({
235
+ agents: [options.agent],
236
+ cwd
237
+ });
238
+ if (tracked) return {
239
+ ok: false,
240
+ unsupported: false,
241
+ error: `${tracked} is tracked by git. Untrack it before writing an API key, or pass --oauth.`
242
+ };
243
+ }
188
244
  const result = upsertServer(options.agent, NEON_MCP_NAME, server, {
189
245
  local: options.scope === "project",
190
- cwd: options.cwd
246
+ cwd
191
247
  });
248
+ if (!result.success && created) try {
249
+ rmSync(created, { force: true });
250
+ } catch (err) {
251
+ return {
252
+ ok: false,
253
+ unsupported: false,
254
+ error: `${redactSecrets(result.error ?? "Failed to write Neon MCP server config")} Could not remove ${created}: ${errorMessage(err)}`
255
+ };
256
+ }
192
257
  if (result.success) {
193
258
  if (auth.kind === "api-key") {
194
259
  const paths = [result.path, ...result.extraPaths ?? []];
@@ -212,4 +277,4 @@ function installNeonMcpServer(options) {
212
277
  error: redactSecrets(result.error ?? "Failed to write Neon MCP server config")
213
278
  };
214
279
  }
215
- export { NEON_MCP_CATEGORIES, NEON_MCP_NAME, NEON_MCP_URL, existingNeonApiKey, installNeonMcpServer, isMcpCategory, isNeonMcpUrl, mcpUnsupportedReason, neonMcpUrl, parseMcpCategories, trackedProjectMcpConfig };
280
+ export { NEON_MCP_CATEGORIES, NEON_MCP_NAME, NEON_MCP_URL, existingNeonApiKey, installNeonMcpServer, isMcpCategory, isNeonMcpUrl, mcpInstallOrder, mcpUnsupportedReason, neonMcpUrl, parseMcpCategories, trackedProjectMcpConfig };
@@ -1,6 +1,5 @@
1
- import { detectInstalledAgents, listMcpAgentIds, resolveAddMcpAgentId, uniqueAgentIds } from "./agents.js";
1
+ import { detectInstalledAgents, detectProjectAgents, listMcpAgentIds, resolveAddMcpAgentId, uniqueAgentIds } from "./agents.js";
2
2
  import { mcpUnsupportedReason } from "./install.js";
3
- import { detectProjectAgents } from "add-mcp";
4
3
  // src/mcp/targets.ts
5
4
  function mcpInstallableAgents(scope) {
6
5
  return listMcpAgentIds().filter((id) => mcpUnsupportedReason(id, scope) === void 0);
@@ -14,7 +13,7 @@ function resolveInstallTargets(options) {
14
13
  const install = [];
15
14
  const skipped = [];
16
15
  for (const agent of requested) {
17
- const error = mcpUnsupportedReason(agent, options.scope);
16
+ const error = mcpUnsupportedReason(agent, options.scope, options.auth);
18
17
  if (error) skipped.push({
19
18
  agent,
20
19
  error
@@ -0,0 +1,10 @@
1
+ // src/plugins/child_env.ts
2
+ const TELEMETRY_BLOCKERS = ["DISABLE_TELEMETRY", "DO_NOT_TRACK"];
3
+ /** The env the plugins CLI and the agent CLIs it calls run with. */
4
+ const pluginsChildEnv = (base = process.env) => {
5
+ const env = { ...base };
6
+ for (const key of TELEMETRY_BLOCKERS) delete env[key];
7
+ for (const key of Object.keys(env)) if (key.toUpperCase() === "NEON_API_KEY") delete env[key];
8
+ return env;
9
+ };
10
+ export { pluginsChildEnv };