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.
- package/README.md +1 -1
- package/dist/callback.html +471 -58
- package/dist/commands/mcp.js +4 -2
- package/dist/commands/plugins.js +7 -3
- package/dist/commands/skills.js +4 -2
- package/dist/index.js +6 -1
- package/dist/init/chrome.js +26 -6
- package/dist/init/copy.js +7 -1
- package/dist/init/mode.js +1 -3
- package/dist/init/plan.js +11 -5
- package/dist/init/run.js +63 -50
- package/dist/init/tooling.js +63 -50
- package/dist/init/wizard.js +17 -18
- package/dist/plugins/plan.js +32 -4
- package/dist/plugins/targets.js +49 -9
- package/dist/sso_recovery.js +92 -0
- package/dist/utils/agent_picker.js +44 -18
- package/package.json +4 -4
package/dist/commands/mcp.js
CHANGED
|
@@ -6,10 +6,11 @@ import { getCliName } from "../utils/cli_name.js";
|
|
|
6
6
|
import { helpCsv, helpEpilogue } from "../utils/help_text.js";
|
|
7
7
|
import { writer } from "../writer.js";
|
|
8
8
|
import { noPassthrough, single } from "../utils/flags.js";
|
|
9
|
+
import { AGENT_MCP_SKIP_MESSAGE } from "../init/copy.js";
|
|
9
10
|
import { NEON_MCP_CATEGORIES, NEON_MCP_URL, existingNeonApiKey, installNeonMcpServer, neonMcpUrl, parseMcpCategories, trackedProjectMcpConfig } from "../mcp/install.js";
|
|
10
11
|
import { mcpInstallableAgents, resolveInstallTargets } from "../mcp/targets.js";
|
|
11
12
|
import { mintMcpApiKey, mintedKeyRevokeCommand, withdrawMintedKey } from "../mcp/mint.js";
|
|
12
|
-
import { canPickAgentsInteractively } from "../utils/agent_picker.js";
|
|
13
|
+
import { canPickAgentsInteractively, skippableAgentPicker } from "../utils/agent_picker.js";
|
|
13
14
|
import { resolveMcpPlan } from "../mcp/plan.js";
|
|
14
15
|
//#region src/commands/mcp.ts
|
|
15
16
|
var mcp_exports = /* @__PURE__ */ __exportAll({
|
|
@@ -113,7 +114,8 @@ const setupNeonMcp = async (options) => {
|
|
|
113
114
|
readOnly: options.readOnly === true,
|
|
114
115
|
projectId: options.projectId,
|
|
115
116
|
categories: options.category ?? [],
|
|
116
|
-
linkedProjectId
|
|
117
|
+
linkedProjectId,
|
|
118
|
+
pickAgents: skippableAgentPicker(options.allowAgentSkip, AGENT_MCP_SKIP_MESSAGE)
|
|
117
119
|
});
|
|
118
120
|
const { install, skipped } = resolveInstallTargets({
|
|
119
121
|
agents: plan.agents,
|
package/dist/commands/plugins.js
CHANGED
|
@@ -4,11 +4,12 @@ import { recordCommandSuccessExtras } from "../analytics.js";
|
|
|
4
4
|
import { helpCsv, helpEpilogue } from "../utils/help_text.js";
|
|
5
5
|
import { writer } from "../writer.js";
|
|
6
6
|
import { noPassthrough } from "../utils/flags.js";
|
|
7
|
+
import { AGENT_PLUGIN_SKIP_MESSAGE } from "../init/copy.js";
|
|
7
8
|
import { getAgentDisplayName } from "../mcp/agents.js";
|
|
8
9
|
import { NEON_MCP_URL } from "../mcp/install.js";
|
|
9
10
|
import "../init/agents.js";
|
|
10
11
|
import { pluginsInstallableAgents } from "../plugins/targets.js";
|
|
11
|
-
import { canPickAgentsInteractively } from "../utils/agent_picker.js";
|
|
12
|
+
import { canPickAgentsInteractively, skippableAgentPicker } from "../utils/agent_picker.js";
|
|
12
13
|
import { resolvePluginsPlan } from "../plugins/plan.js";
|
|
13
14
|
import { NEON_PLUGIN_NAME, PLUGIN_SKILLS, PLUGIN_SOURCE, neonPluginsRetryCommand, pluginsAddArgs, runPluginsCli } from "../plugins/run.js";
|
|
14
15
|
//#region src/commands/plugins.ts
|
|
@@ -71,10 +72,12 @@ const installPlugins = async (options) => {
|
|
|
71
72
|
agents: options.agents ?? [],
|
|
72
73
|
yes,
|
|
73
74
|
cwd,
|
|
74
|
-
interactive
|
|
75
|
+
interactive,
|
|
76
|
+
pickAgents: skippableAgentPicker(options.allowAgentSkip, AGENT_PLUGIN_SKIP_MESSAGE)
|
|
75
77
|
});
|
|
76
78
|
for (const agent of plan.skipped) log.warning("Skipping %s: no plugins mapping.", getAgentDisplayName(agent));
|
|
77
79
|
for (const agent of plan.userScopeSkipped) log.warning("Skipping %s: plugins are user-level. Pass --global.", getAgentDisplayName(agent));
|
|
80
|
+
for (const { agent, command } of plan.missingCommands) log.warning("Skipping %s: the plugin installs through \"%s\", which was not found on PATH.", getAgentDisplayName(agent), command);
|
|
78
81
|
const rows = [];
|
|
79
82
|
const failed = [];
|
|
80
83
|
const scope = scopeLabel(plan.scope);
|
|
@@ -147,7 +150,8 @@ const reportPluginsInstall = (props, outcome) => {
|
|
|
147
150
|
title: "Plugins"
|
|
148
151
|
});
|
|
149
152
|
out.end();
|
|
150
|
-
if (outcome.
|
|
153
|
+
if (outcome.rows.length === 0) log.info("No Neon plugins installed.");
|
|
154
|
+
else if (outcome.failed.length === 0) log.info(outcome.scope === "project" ? "Installed the Neon plugin (project)." : "Installed the Neon plugin (user).");
|
|
151
155
|
};
|
|
152
156
|
const handler = async (props) => {
|
|
153
157
|
const outcome = await installPlugins({
|
package/dist/commands/skills.js
CHANGED
|
@@ -4,10 +4,11 @@ import { recordCommandSuccessExtras } from "../analytics.js";
|
|
|
4
4
|
import { helpCsv, helpEpilogue } from "../utils/help_text.js";
|
|
5
5
|
import { writer } from "../writer.js";
|
|
6
6
|
import { noPassthrough } from "../utils/flags.js";
|
|
7
|
+
import { AGENT_SKILLS_SKIP_MESSAGE } from "../init/copy.js";
|
|
7
8
|
import { getAgentDisplayName } from "../mcp/agents.js";
|
|
8
9
|
import "../init/agents.js";
|
|
9
10
|
import { mappedSkillsAgentNames, skillsInstallableAgents } from "../skills/targets.js";
|
|
10
|
-
import { canPickAgentsInteractively } from "../utils/agent_picker.js";
|
|
11
|
+
import { canPickAgentsInteractively, skippableAgentPicker } from "../utils/agent_picker.js";
|
|
11
12
|
import { skillsHelpValues, skillsYesHelp } from "../skills/catalog.js";
|
|
12
13
|
import { confirmSkillsUpdate } from "../skills/wizard.js";
|
|
13
14
|
import { assertSkillsCanRun, resolveSkillsPlan } from "../skills/plan.js";
|
|
@@ -102,7 +103,8 @@ const installSkills = async (options) => {
|
|
|
102
103
|
skills: options.skills ?? [],
|
|
103
104
|
yes,
|
|
104
105
|
cwd,
|
|
105
|
-
interactive
|
|
106
|
+
interactive,
|
|
107
|
+
pickAgents: skippableAgentPicker(options.allowAgentSkip, AGENT_SKILLS_SKIP_MESSAGE)
|
|
106
108
|
});
|
|
107
109
|
const mapped = mappedSkillsAgentNames(plan.agents);
|
|
108
110
|
for (const agent of plan.skipped) log.warning("Skipping %s: no skills mapping.", getAgentDisplayName(agent));
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { log } from "./log.js";
|
|
2
2
|
import pkg_default from "./pkg.js";
|
|
3
|
-
import { isNeonApiError, messageFromBody } from "./api.js";
|
|
3
|
+
import { codeFromBody, isNeonApiError, messageFromBody } from "./api.js";
|
|
4
4
|
import { getAuthContext } from "./auth_context.js";
|
|
5
5
|
import { r as defaultDir } from "./_chunks/paths-DMq0Lt7a.js";
|
|
6
6
|
import { ensureConfigDir } from "./config.js";
|
|
@@ -14,6 +14,7 @@ import { recoverFrom401 } from "./auth_recovery.js";
|
|
|
14
14
|
import { showHelp } from "./help.js";
|
|
15
15
|
import { rewriteUnknownAgentArg } from "./init/plan.js";
|
|
16
16
|
import commands_default from "./commands/index.js";
|
|
17
|
+
import { recoverFromSSO } from "./sso_recovery.js";
|
|
17
18
|
import { notifyIfUpdateAvailable } from "./update_notifier.js";
|
|
18
19
|
import { fillInArgs, resolveApiKeyFromEnv } from "./utils/middlewares.js";
|
|
19
20
|
import yargs from "yargs";
|
|
@@ -165,6 +166,10 @@ async function handleError(msg, err, canRetry) {
|
|
|
165
166
|
log.error("Request timed out");
|
|
166
167
|
sendError(err, "REQUEST_TIMEOUT");
|
|
167
168
|
return false;
|
|
169
|
+
} else if (codeFromBody(err.data) === "SSO_AUTHORIZATION_REQUIRED" || codeFromBody(err.data) === "SSO_ORG_CREDS_ONLY") {
|
|
170
|
+
if (await recoverFromSSO(err, canRetry)) return true;
|
|
171
|
+
sendError(err, "AUTH_FAILED");
|
|
172
|
+
return false;
|
|
168
173
|
} else if (err.status === 401) {
|
|
169
174
|
sendError(err, "AUTH_FAILED");
|
|
170
175
|
return await recoverFrom401(canRetry);
|
package/dist/init/chrome.js
CHANGED
|
@@ -49,6 +49,8 @@ const printInitDone = (text) => {
|
|
|
49
49
|
const agentSetupLabel = (setup) => {
|
|
50
50
|
if (setup === "plugin") return "plugin";
|
|
51
51
|
if (setup === "skills-mcp") return "skills and MCP";
|
|
52
|
+
if (setup === "skills") return "skills";
|
|
53
|
+
if (setup === "mcp") return "MCP";
|
|
52
54
|
return "skipped";
|
|
53
55
|
};
|
|
54
56
|
const agentSetupDoneLabel = (input) => {
|
|
@@ -56,13 +58,31 @@ const agentSetupDoneLabel = (input) => {
|
|
|
56
58
|
return agentSetupLabel(input.setup);
|
|
57
59
|
};
|
|
58
60
|
const formatAgentIds = (agents) => agents.join(", ");
|
|
61
|
+
const SETUP_LABELS = {
|
|
62
|
+
skip: "skipped",
|
|
63
|
+
plugin: "Neon plugin",
|
|
64
|
+
skills: "skills",
|
|
65
|
+
"skills-mcp": "skills and MCP",
|
|
66
|
+
mixed: "plugin and skills/MCP"
|
|
67
|
+
};
|
|
68
|
+
/** Names the agents behind each mechanism, since init picks skills and MCP agents separately. */
|
|
59
69
|
const agentsRowValue = (input) => {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
const
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
70
|
+
const { tooling } = input;
|
|
71
|
+
const parts = [];
|
|
72
|
+
const add = (label, ids) => {
|
|
73
|
+
const ran = ids.filter((id) => input.installed.includes(id));
|
|
74
|
+
if (ran.length > 0) parts.push(`${label}: ${formatAgentIds(ran)}`);
|
|
75
|
+
};
|
|
76
|
+
if (tooling.setup === "plugin" || tooling.setup === "skills") add(SETUP_LABELS[tooling.setup], tooling.agents);
|
|
77
|
+
else if (tooling.setup === "skills-mcp" || tooling.setup === "mixed") {
|
|
78
|
+
if (tooling.setup === "mixed") add("Neon plugin", tooling.pluginAgents);
|
|
79
|
+
if (tooling.skillsAgents.length === tooling.mcpAgents.length && tooling.skillsAgents.every((id) => tooling.mcpAgents.includes(id))) add("skills and MCP", tooling.skillsAgents);
|
|
80
|
+
else {
|
|
81
|
+
add("skills", tooling.skillsAgents);
|
|
82
|
+
add("MCP", tooling.mcpAgents);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return parts.length > 0 ? parts.join("; ") : SETUP_LABELS[tooling.setup];
|
|
66
86
|
};
|
|
67
87
|
const projectRowValue = (link) => {
|
|
68
88
|
switch (link) {
|
package/dist/init/copy.js
CHANGED
|
@@ -16,6 +16,12 @@ const AGENT_SETUP_SKIP_DESCRIPTION = "Continue to project setup without changing
|
|
|
16
16
|
const AGENT_PICKER_MESSAGE = "Which coding agents should receive Neon tooling? (space to toggle, enter to confirm)";
|
|
17
17
|
const AGENT_DETECTED_DESCRIPTION = "Detected on this machine or in this directory.";
|
|
18
18
|
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 AGENT_PLUGIN_SKIP_MESSAGE = "No agents selected. Continue without installing the Neon plugin?";
|
|
21
|
+
const AGENT_SKILLS_PICKER_MESSAGE = "Which coding agents should receive Neon skills? (space to toggle, enter to confirm)";
|
|
22
|
+
const AGENT_MCP_PICKER_MESSAGE = "Which coding agents should receive the Neon MCP server? (space to toggle, enter to confirm)";
|
|
23
|
+
const AGENT_SKILLS_SKIP_MESSAGE = "No agents selected. Continue without installing Neon skills?";
|
|
24
|
+
const AGENT_MCP_SKIP_MESSAGE = "No agents selected. Continue without configuring the Neon MCP server?";
|
|
19
25
|
const SKILLS_PICKER_MESSAGE = "Which Neon skills should be installed? (space to toggle, enter to confirm)";
|
|
20
26
|
const MCP_SCOPE_MESSAGE = "Where should the Neon MCP server be configured?";
|
|
21
27
|
const MCP_SCOPE_GLOBAL_TITLE = "User configuration";
|
|
@@ -130,4 +136,4 @@ const headingForOutcome = (outcome) => {
|
|
|
130
136
|
}
|
|
131
137
|
};
|
|
132
138
|
//#endregion
|
|
133
|
-
export { 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, 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_SUBTITLE, MCP_AUTH_API_KEY_DESCRIPTION, MCP_AUTH_API_KEY_TITLE, MCP_AUTH_MESSAGE, MCP_AUTH_OAUTH_DESCRIPTION, MCP_AUTH_OAUTH_TITLE, 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_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, YES_LINK_NEEDS_AUTH, claimableNext, claimableThenServicesNext, envPullFailedNext, existingConfigNext, extraServicesNext, headingForOutcome, installFailedNext, mcpConfigLocationSkipped, mcpConfigLocationUnavailable, namedAgentsUnavailable, skippedLinkNext, unattendedUnauthedNext };
|
|
139
|
+
export { 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_SUBTITLE, MCP_AUTH_API_KEY_DESCRIPTION, MCP_AUTH_API_KEY_TITLE, MCP_AUTH_MESSAGE, MCP_AUTH_OAUTH_DESCRIPTION, MCP_AUTH_OAUTH_TITLE, 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_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, YES_LINK_NEEDS_AUTH, agentMissingCommandDescription, claimableNext, claimableThenServicesNext, envPullFailedNext, existingConfigNext, extraServicesNext, headingForOutcome, installFailedNext, mcpConfigLocationSkipped, mcpConfigLocationUnavailable, namedAgentsUnavailable, skippedLinkNext, unattendedUnauthedNext };
|
package/dist/init/mode.js
CHANGED
|
@@ -18,10 +18,8 @@ const assertAgentSetupFlags = (input) => {
|
|
|
18
18
|
};
|
|
19
19
|
const inferInitAgentSetup = (input) => {
|
|
20
20
|
if (input.skipAgents) return { kind: "skip" };
|
|
21
|
-
const hasSkills = hasSkillsFlag(input.skills);
|
|
22
|
-
if (hasSkills && input.hasMcpFlags) return { kind: "skills-mcp" };
|
|
23
|
-
if (hasSkills) return { kind: "skills" };
|
|
24
21
|
if (input.hasMcpFlags) return { kind: "skills-mcp" };
|
|
22
|
+
if (hasSkillsFlag(input.skills)) return { kind: "skills" };
|
|
25
23
|
if (input.namedAgents || input.yes) return { kind: "auto" };
|
|
26
24
|
if (input.canAsk) return { kind: "ask" };
|
|
27
25
|
throw new Error(NON_TTY_AGENT_SETUP);
|
package/dist/init/plan.js
CHANGED
|
@@ -201,8 +201,9 @@ const chooseYesAgentTooling = (agents) => {
|
|
|
201
201
|
};
|
|
202
202
|
};
|
|
203
203
|
const FALLBACK_SKILLS_AGENTS = ["cursor", "codex"];
|
|
204
|
-
const splitInitTooling = (agents, pluginScope, mcpConfigLocation = pluginScope) => {
|
|
205
|
-
const
|
|
204
|
+
const splitInitTooling = (agents, pluginScope, mcpConfigLocation = pluginScope, unavailablePluginAgents = []) => {
|
|
205
|
+
const unavailable = new Set(unavailablePluginAgents);
|
|
206
|
+
const pluginSet = new Set(pluginsInstallableAgents(pluginScope).filter((id) => !unavailable.has(id)));
|
|
206
207
|
const mcpSet = new Set(mcpInstallableAgents(mcpConfigLocation));
|
|
207
208
|
const pluginAgents = uniqueAgentIds(agents.filter((id) => pluginSet.has(id)));
|
|
208
209
|
const rest = uniqueAgentIds(agents.filter((id) => !pluginSet.has(id)));
|
|
@@ -226,8 +227,8 @@ const splitInitTooling = (agents, pluginScope, mcpConfigLocation = pluginScope)
|
|
|
226
227
|
mcpAgents
|
|
227
228
|
};
|
|
228
229
|
};
|
|
229
|
-
const recommendedTooling = (detected) => {
|
|
230
|
-
const split = splitInitTooling(detected, "global");
|
|
230
|
+
const recommendedTooling = (detected, unavailablePluginAgents = []) => {
|
|
231
|
+
const split = splitInitTooling(detected, "global", "global", unavailablePluginAgents);
|
|
231
232
|
if (split.setup === "skip") return {
|
|
232
233
|
setup: "skills",
|
|
233
234
|
agents: FALLBACK_SKILLS_AGENTS
|
|
@@ -297,7 +298,12 @@ const planInitToolingSteps = (input) => {
|
|
|
297
298
|
default: return input.tooling;
|
|
298
299
|
}
|
|
299
300
|
};
|
|
300
|
-
const funnelAgentSetup = (tooling) =>
|
|
301
|
+
const funnelAgentSetup = (tooling) => {
|
|
302
|
+
if (tooling.setup !== "skills-mcp") return tooling.setup;
|
|
303
|
+
if (tooling.skillsAgents.length === 0) return "mcp";
|
|
304
|
+
if (tooling.mcpAgents.length === 0) return "skills";
|
|
305
|
+
return "skills-mcp";
|
|
306
|
+
};
|
|
301
307
|
const planYesAgentSteps = (tooling) => planToolingSteps(tooling, {
|
|
302
308
|
yes: true,
|
|
303
309
|
named: false
|
package/dist/init/run.js
CHANGED
|
@@ -13,8 +13,9 @@ import { agentsRowValue, configRowValue, formatInitDone, headingForKind, printIn
|
|
|
13
13
|
import { inferPackageManager, resolvePackageManager } from "../utils/package_manager.js";
|
|
14
14
|
import { ConfigInstallFailed, hasNeonConfigFile, initCmd, neonConfigFilename } from "../commands/config.js";
|
|
15
15
|
import { runAuthenticatedLink } from "./link.js";
|
|
16
|
+
import { getAgentDisplayName } from "../mcp/agents.js";
|
|
16
17
|
import { mcpInstallableAgents } from "../mcp/targets.js";
|
|
17
|
-
import { pluginsInstallableAgents } from "../plugins/targets.js";
|
|
18
|
+
import { missingPluginsCommands, pluginsInstallableAgents } from "../plugins/targets.js";
|
|
18
19
|
import { skillsInstallableAgents } from "../skills/targets.js";
|
|
19
20
|
import { FALLBACK_SKILLS_AGENTS, assertNamedAgentTooling, funnelAgentSetup, planInitToolingSteps, recommendedTooling, resolveNamedAgents, splitInitTooling } from "./plan.js";
|
|
20
21
|
import { pullInitEnv } from "./auth.js";
|
|
@@ -56,11 +57,10 @@ const pluginScopeFor = (agents, preferred) => {
|
|
|
56
57
|
const project = new Set(pluginsInstallableAgents("project"));
|
|
57
58
|
return agents.some((id) => !project.has(id) && pluginsInstallableAgents("global").includes(id)) ? "global" : "project";
|
|
58
59
|
};
|
|
59
|
-
const
|
|
60
|
-
if (setup
|
|
61
|
-
|
|
62
|
-
if (
|
|
63
|
-
return [.../* @__PURE__ */ new Set([...skillsInstallableAgents(), ...mcpInstallableAgents(scope === "project" ? "project" : "global")])];
|
|
60
|
+
const warnMissingPluginCommands = (missing, tooling) => {
|
|
61
|
+
if (tooling.setup !== "skills-mcp" && tooling.setup !== "mixed") return;
|
|
62
|
+
const routed = /* @__PURE__ */ new Set([...tooling.skillsAgents, ...tooling.mcpAgents]);
|
|
63
|
+
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);
|
|
64
64
|
};
|
|
65
65
|
const nonEmptyAgents = (ids, fallback) => {
|
|
66
66
|
const [first, ...rest] = ids;
|
|
@@ -75,14 +75,15 @@ const skillsTooling = (ids, fallback) => {
|
|
|
75
75
|
agents
|
|
76
76
|
};
|
|
77
77
|
};
|
|
78
|
-
const skillsMcpTooling = (
|
|
79
|
-
const
|
|
80
|
-
|
|
81
|
-
|
|
78
|
+
const skillsMcpTooling = (skillsSelection, mcpSelection, mcpConfigLocation, fallback) => {
|
|
79
|
+
const useFallback = fallback && skillsSelection?.length === 0 && mcpSelection?.length === 0;
|
|
80
|
+
const selectedSkills = (useFallback ? FALLBACK_SKILLS_AGENTS : skillsSelection ?? []).filter((id) => skillsInstallableAgents().includes(id));
|
|
81
|
+
const selectedMcp = (useFallback ? FALLBACK_SKILLS_AGENTS : mcpSelection ?? []).filter((id) => mcpInstallableAgents(mcpConfigLocation).includes(id));
|
|
82
|
+
if (selectedMcp.length === 0) return skillsTooling(selectedSkills, false);
|
|
82
83
|
return {
|
|
83
84
|
setup: "skills-mcp",
|
|
84
|
-
skillsAgents:
|
|
85
|
-
mcpAgents:
|
|
85
|
+
skillsAgents: selectedSkills,
|
|
86
|
+
mcpAgents: selectedMcp
|
|
86
87
|
};
|
|
87
88
|
};
|
|
88
89
|
const validateMcpConfigLocationSupport = (ids, location) => {
|
|
@@ -103,13 +104,18 @@ const pickOrDetectAgents = async (input) => {
|
|
|
103
104
|
return selected;
|
|
104
105
|
}
|
|
105
106
|
const detected = input.detected.filter((id) => input.available.includes(id));
|
|
107
|
+
const preselected = (input.preselected ?? input.detected).filter((id) => input.available.includes(id));
|
|
106
108
|
if (input.pickAgents !== void 0) return input.pickAgents({
|
|
107
109
|
available: [...input.available],
|
|
108
|
-
detected
|
|
110
|
+
detected: preselected,
|
|
111
|
+
setup: input.setup
|
|
109
112
|
});
|
|
110
113
|
if (input.interactive) return pickInitAgentsInteractively({
|
|
111
114
|
available: [...input.available],
|
|
112
|
-
detected
|
|
115
|
+
detected,
|
|
116
|
+
preselected,
|
|
117
|
+
...input.missingCommands !== void 0 ? { missingCommands: input.missingCommands } : {},
|
|
118
|
+
setup: input.setup
|
|
113
119
|
});
|
|
114
120
|
return detected;
|
|
115
121
|
};
|
|
@@ -229,7 +235,9 @@ const runInit = async (props) => {
|
|
|
229
235
|
}
|
|
230
236
|
const recommended = mode === "recommended";
|
|
231
237
|
const targets = named.length > 0 ? named : detection.detectedAgents;
|
|
232
|
-
|
|
238
|
+
const missingPluginCommands = missingPluginsCommands(targets, { cwd });
|
|
239
|
+
const unavailablePluginAgents = missingPluginCommands.map((row) => row.agent);
|
|
240
|
+
const pluginReady = (agents) => agents.filter((id) => !unavailablePluginAgents.includes(id));
|
|
233
241
|
let tooling = { setup: "skip" };
|
|
234
242
|
let mcpAuth = props.mcpAuth;
|
|
235
243
|
let mcpConfigLocation = props.mcpConfigLocation ?? "global";
|
|
@@ -238,9 +246,9 @@ const runInit = async (props) => {
|
|
|
238
246
|
let pluginScope = recommended ? "global" : "project";
|
|
239
247
|
if (recommended) {
|
|
240
248
|
pluginScope = "global";
|
|
241
|
-
tooling = named.length > 0 ? splitInitTooling(named, "global") : recommendedTooling(detection.detectedAgents);
|
|
249
|
+
tooling = named.length > 0 ? splitInitTooling(named, "global", "global", unavailablePluginAgents) : recommendedTooling(detection.detectedAgents, unavailablePluginAgents);
|
|
242
250
|
if (named.length === 0 && detection.detectedAgents.length === 0) printInitProgress(NO_AGENTS_FALLBACK_STATUS);
|
|
243
|
-
|
|
251
|
+
warnMissingPluginCommands(missingPluginCommands, tooling);
|
|
244
252
|
mcpAuth = !detection.authenticated && (tooling.setup === "skills-mcp" || tooling.setup === "mixed") ? "oauth" : mcpAuth;
|
|
245
253
|
} else {
|
|
246
254
|
const inferred = inferInitAgentSetup({
|
|
@@ -251,53 +259,58 @@ const runInit = async (props) => {
|
|
|
251
259
|
canAsk: detection.interactive || props.pickAgentSetup !== void 0,
|
|
252
260
|
...props.skill !== void 0 ? { skills: props.skill } : {}
|
|
253
261
|
});
|
|
254
|
-
if (inferred.kind === "skip") {
|
|
255
|
-
|
|
256
|
-
agentSetupChoice = "skip";
|
|
257
|
-
} else if (inferred.kind === "auto") {
|
|
262
|
+
if (inferred.kind === "skip") tooling = { setup: "skip" };
|
|
263
|
+
else if (inferred.kind === "auto") {
|
|
258
264
|
const autoAgents = named.length > 0 ? named : detection.detectedAgents;
|
|
259
|
-
pluginScope = pluginScopeFor(autoAgents, "project");
|
|
260
|
-
tooling = splitInitTooling(autoAgents, pluginScope, mcpConfigLocation);
|
|
265
|
+
pluginScope = pluginScopeFor(pluginReady(autoAgents), "project");
|
|
266
|
+
tooling = splitInitTooling(autoAgents, pluginScope, mcpConfigLocation, unavailablePluginAgents);
|
|
267
|
+
warnMissingPluginCommands(missingPluginCommands, tooling);
|
|
261
268
|
if (tooling.setup === "skip" && yes && named.length === 0) {
|
|
262
269
|
tooling = recommendedTooling([]);
|
|
263
270
|
printInitProgress(NO_AGENTS_FALLBACK_STATUS);
|
|
264
271
|
}
|
|
265
|
-
agentSetupChoice = funnelAgentSetup(tooling);
|
|
266
272
|
} else {
|
|
267
273
|
const setup = inferred.kind === "ask" ? await (props.pickAgentSetup ?? pickAgentSetupInteractively)() : inferred.kind;
|
|
268
|
-
agentSetupChoice = setup === "skills" ? "skills" : setup;
|
|
269
274
|
if (setup !== "skip") {
|
|
270
275
|
pluginScope = pluginScopeFor(targets, "project");
|
|
271
|
-
const
|
|
272
|
-
const
|
|
276
|
+
const namedFallback = named.length === 0;
|
|
277
|
+
const pickAgents = (setup, available) => pickOrDetectAgents({
|
|
273
278
|
named,
|
|
274
279
|
available,
|
|
275
280
|
detected: detection.detectedAgents,
|
|
281
|
+
...setup === "plugin" ? {
|
|
282
|
+
preselected: pluginReady(detection.detectedAgents),
|
|
283
|
+
missingCommands: missingPluginCommands
|
|
284
|
+
} : {},
|
|
276
285
|
interactive: detection.interactive,
|
|
277
|
-
|
|
286
|
+
setup,
|
|
287
|
+
pickAgents: props.pickAgents
|
|
278
288
|
});
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
tooling = skillsTooling(selected, namedFallback);
|
|
287
|
-
agentSetupChoice = funnelAgentSetup(tooling);
|
|
289
|
+
if (setup === "plugin" || setup === "skills") {
|
|
290
|
+
const selected = await pickAgents(setup, setup === "plugin" ? uniqueAgents([...pluginsInstallableAgents("project"), ...pluginsInstallableAgents("global")]) : [...skillsInstallableAgents()]);
|
|
291
|
+
if (selected === void 0) tooling = { setup: "skip" };
|
|
292
|
+
else if (setup === "plugin") {
|
|
293
|
+
pluginScope = pluginScopeFor(selected, pluginScope);
|
|
294
|
+
tooling = splitInitTooling(selected.filter((id) => pluginsInstallableAgents(pluginScope).includes(id)), pluginScope);
|
|
295
|
+
} else tooling = skillsTooling(selected, namedFallback);
|
|
288
296
|
} else {
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
297
|
+
const skillsAvailable = skillsInstallableAgents();
|
|
298
|
+
const skillsSelection = named.length > 0 ? named.filter((id) => skillsAvailable.includes(id)) : await pickAgents("skills", skillsAvailable);
|
|
299
|
+
if (skillsSelection !== void 0 && selectedSkills === void 0 && inferred.kind === "ask") selectedSkills = props.pickSkills !== void 0 ? await props.pickSkills() : detection.interactive ? await pickInitSkillsInteractively() : void 0;
|
|
300
|
+
const mcpSelection = named.length > 0 ? named : await pickAgents("mcp", mcpInstallableAgents("global"));
|
|
301
|
+
if (mcpSelection !== void 0) {
|
|
302
|
+
mcpConfigLocation = props.mcpConfigLocation ?? (yes ? "global" : props.pickMcpConfigLocation !== void 0 ? await props.pickMcpConfigLocation() : detection.interactive ? await pickInitMcpConfigLocationInteractively() : "global");
|
|
303
|
+
if (mcpSelection.length > 0) validateMcpConfigLocationSupport(mcpSelection, mcpConfigLocation);
|
|
304
|
+
const pickAuth = props.pickMcpAuth ?? (detection.interactive ? pickInitMcpAuthInteractively : void 0);
|
|
305
|
+
mcpAuth = props.mcpAuth ?? (yes ? void 0 : await pickAuth?.({ authenticated: detection.authenticated })) ?? (detection.authenticated && props.claimable !== true ? "api-key" : "oauth");
|
|
306
|
+
}
|
|
307
|
+
tooling = skillsMcpTooling(skillsSelection, mcpSelection, mcpConfigLocation, namedFallback);
|
|
295
308
|
}
|
|
296
309
|
}
|
|
297
310
|
}
|
|
298
311
|
}
|
|
299
|
-
funnel.agentSetup =
|
|
300
|
-
const usesMcp = tooling.setup === "skills-mcp" || tooling.setup === "mixed";
|
|
312
|
+
funnel.agentSetup = funnelAgentSetup(tooling);
|
|
313
|
+
const usesMcp = (tooling.setup === "skills-mcp" || tooling.setup === "mixed") && tooling.mcpAgents.length > 0;
|
|
301
314
|
if (mcpAuth === void 0 && usesMcp && (!detection.authenticated || props.claimable === true)) mcpAuth = "oauth";
|
|
302
315
|
delayMcp = usesMcp && (mcpAuth === "api-key" || props.mcpProjectScoped === true);
|
|
303
316
|
const mcpOauth = mcpAuth === "oauth";
|
|
@@ -355,7 +368,7 @@ const runInit = async (props) => {
|
|
|
355
368
|
funnel.link = "skipped";
|
|
356
369
|
} else if (props.pickProjectSetup !== void 0 || detection.interactive) projectSetup = await (props.pickProjectSetup ?? pickInitProjectSetupInteractively)();
|
|
357
370
|
else throw new Error(NON_TTY_LINK_NEEDS_AUTH);
|
|
358
|
-
if (mcpAuth === "api-key" && (projectSetup === "claimable" || props.claimable === true)) throw new Error(CLAIMABLE_MCP_API_KEY);
|
|
371
|
+
if (usesMcp && mcpAuth === "api-key" && (projectSetup === "claimable" || props.claimable === true)) throw new Error(CLAIMABLE_MCP_API_KEY);
|
|
359
372
|
if (projectSetup === "claimable") {
|
|
360
373
|
printInitProgress(PROGRESS.claim);
|
|
361
374
|
await (props.createClaimable ?? defaultCreateClaimable)({
|
|
@@ -529,8 +542,8 @@ const runInit = async (props) => {
|
|
|
529
542
|
{
|
|
530
543
|
label: "Agents",
|
|
531
544
|
value: agentsRowValue({
|
|
532
|
-
|
|
533
|
-
|
|
545
|
+
tooling,
|
|
546
|
+
installed: funnel.agentsInstalled
|
|
534
547
|
})
|
|
535
548
|
},
|
|
536
549
|
{
|
|
@@ -578,8 +591,8 @@ const runInit = async (props) => {
|
|
|
578
591
|
{
|
|
579
592
|
label: "Agents",
|
|
580
593
|
value: agentsRowValue({
|
|
581
|
-
|
|
582
|
-
|
|
594
|
+
tooling,
|
|
595
|
+
installed: funnel.agentsInstalled
|
|
583
596
|
})
|
|
584
597
|
},
|
|
585
598
|
{
|
package/dist/init/tooling.js
CHANGED
|
@@ -3,7 +3,7 @@ import { getCliName } from "../utils/cli_name.js";
|
|
|
3
3
|
import { PROGRESS } from "./copy.js";
|
|
4
4
|
import { assertNamedAgentTooling, chooseYesAgentTooling, collectYesAgents, initYesSupportedAgents, noDetectedAgentsMessage, planAgentSteps, planToolingSteps, planYesAgentSteps, resolveInitAgentSetup } from "./plan.js";
|
|
5
5
|
import { detectAgent } from "./detect_host.js";
|
|
6
|
-
import { canPickAgentsInteractively } from "../utils/agent_picker.js";
|
|
6
|
+
import { AgentSelectionSkipped, canPickAgentsInteractively } from "../utils/agent_picker.js";
|
|
7
7
|
import { mcpInstallError, reportMcpInstall } from "../commands/mcp.js";
|
|
8
8
|
import { installPlugins, pluginsInstallError, reportPluginsInstall } from "../commands/plugins.js";
|
|
9
9
|
import { installSkills, reportSkillsInstall, skillsInstallError } from "../commands/skills.js";
|
|
@@ -66,45 +66,61 @@ const runToolingSteps = async (steps, options) => {
|
|
|
66
66
|
...options.operations
|
|
67
67
|
};
|
|
68
68
|
const reportProps = { output: options.output };
|
|
69
|
+
const sharedOptions = {
|
|
70
|
+
cwd: options.cwd,
|
|
71
|
+
allowAgentSkip: options.allowAgentSkip
|
|
72
|
+
};
|
|
73
|
+
const completed = [];
|
|
69
74
|
for (const step of steps) {
|
|
70
75
|
const label = options.narrate === "human" ? TOOLING_STEP_LABELS[step.kind] : void 0;
|
|
71
76
|
if (label !== void 0) process.stdout.write(`${label}\n`);
|
|
72
77
|
else log.info("Running `%s %s`", getCliName(), toolingStepCommandText(step));
|
|
73
78
|
log.debug("Running `%s %s`", getCliName(), toolingStepCommandText(step));
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
79
|
+
try {
|
|
80
|
+
switch (step.kind) {
|
|
81
|
+
case "plugins": {
|
|
82
|
+
const outcome = await raceSigint(ops.installPlugins({
|
|
83
|
+
...step.options,
|
|
84
|
+
...sharedOptions
|
|
85
|
+
}));
|
|
86
|
+
reportPluginsInstall(reportProps, outcome);
|
|
87
|
+
const error = pluginsInstallError(outcome);
|
|
88
|
+
if (error) throw error;
|
|
89
|
+
break;
|
|
90
|
+
}
|
|
91
|
+
case "skills": {
|
|
92
|
+
const outcome = await raceSigint(ops.installSkills({
|
|
93
|
+
...step.options,
|
|
94
|
+
...sharedOptions
|
|
95
|
+
}));
|
|
96
|
+
reportSkillsInstall(reportProps, outcome);
|
|
97
|
+
const error = skillsInstallError(outcome);
|
|
98
|
+
if (error) throw error;
|
|
99
|
+
break;
|
|
100
|
+
}
|
|
101
|
+
case "mcp": {
|
|
102
|
+
const outcome = await raceSigint(ops.installMcp({
|
|
103
|
+
...step.options,
|
|
104
|
+
...sharedOptions
|
|
105
|
+
}));
|
|
106
|
+
reportMcpInstall(reportProps, outcome);
|
|
107
|
+
const error = mcpInstallError(outcome);
|
|
108
|
+
if (error) throw error;
|
|
109
|
+
break;
|
|
110
|
+
}
|
|
111
|
+
default: return step;
|
|
94
112
|
}
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
cwd: options.cwd
|
|
99
|
-
}));
|
|
100
|
-
reportMcpInstall(reportProps, outcome);
|
|
101
|
-
const error = mcpInstallError(outcome);
|
|
102
|
-
if (error) throw error;
|
|
103
|
-
break;
|
|
104
|
-
}
|
|
105
|
-
default: return step;
|
|
113
|
+
completed.push(step.kind);
|
|
114
|
+
} catch (error) {
|
|
115
|
+
if (!(error instanceof AgentSelectionSkipped)) throw error;
|
|
106
116
|
}
|
|
107
117
|
}
|
|
118
|
+
return completed;
|
|
119
|
+
};
|
|
120
|
+
const agentSetupResult = (setup, completed) => {
|
|
121
|
+
if (completed.length === 0) return "skip";
|
|
122
|
+
if (setup === "skills-mcp" && completed.length === 1) return completed[0] === "skills" ? "skills" : "mcp";
|
|
123
|
+
return setup;
|
|
108
124
|
};
|
|
109
125
|
const yesAgentsFromOptions = async (options) => collectYesAgents({
|
|
110
126
|
detected: () => (options.detectProjectAgents ?? defaultProjectAgents)(options.cwd),
|
|
@@ -119,47 +135,44 @@ const yesMiss = () => new Error(noDetectedAgentsMessage({
|
|
|
119
135
|
const runAgentTooling = async (options) => {
|
|
120
136
|
const yes = options.yes;
|
|
121
137
|
const named = options.agents ?? [];
|
|
138
|
+
const runSetup = async (setup, steps) => agentSetupResult(setup, await runToolingSteps(steps, {
|
|
139
|
+
...options,
|
|
140
|
+
allowAgentSkip: !yes
|
|
141
|
+
}));
|
|
122
142
|
if (named.length > 0) {
|
|
123
143
|
assertNamedAgentTooling(named, options.command ?? "init");
|
|
124
144
|
const tooling = chooseYesAgentTooling(named);
|
|
125
|
-
|
|
145
|
+
return runSetup(tooling.setup, planToolingSteps(tooling, {
|
|
126
146
|
yes,
|
|
127
147
|
named: true
|
|
128
|
-
})
|
|
129
|
-
return tooling.setup;
|
|
130
|
-
}
|
|
131
|
-
if (options.agentSetup !== void 0) {
|
|
132
|
-
await runToolingSteps(planAgentSteps({
|
|
133
|
-
yes,
|
|
134
|
-
agentSetup: options.agentSetup
|
|
135
|
-
}), options);
|
|
136
|
-
return options.agentSetup;
|
|
148
|
+
}));
|
|
137
149
|
}
|
|
150
|
+
if (options.agentSetup !== void 0) return runSetup(options.agentSetup, planAgentSteps({
|
|
151
|
+
yes,
|
|
152
|
+
agentSetup: options.agentSetup
|
|
153
|
+
}));
|
|
138
154
|
if (yes) {
|
|
139
155
|
if (options.hasProjectPlugins !== void 0) {
|
|
140
156
|
const agentSetup = await options.hasProjectPlugins(options.cwd) ? "plugin" : "skills-mcp";
|
|
141
|
-
|
|
157
|
+
return runSetup(agentSetup, planAgentSteps({
|
|
142
158
|
yes: true,
|
|
143
159
|
agentSetup
|
|
144
|
-
})
|
|
145
|
-
return agentSetup;
|
|
160
|
+
}));
|
|
146
161
|
}
|
|
147
162
|
const agents = await yesAgentsFromOptions(options);
|
|
148
163
|
const tooling = chooseYesAgentTooling(agents);
|
|
149
164
|
if (tooling.setup === "skip") throw yesMiss();
|
|
150
|
-
|
|
151
|
-
return tooling.setup;
|
|
165
|
+
return runSetup(tooling.setup, planYesAgentSteps(tooling));
|
|
152
166
|
}
|
|
153
167
|
const interactive = options.pickAgentSetup !== void 0 || canPickAgentsInteractively();
|
|
154
168
|
const agentSetup = await resolveInitAgentSetup({
|
|
155
169
|
interactive,
|
|
156
170
|
pick: options.pickAgentSetup ?? pickAgentSetupInteractively
|
|
157
171
|
});
|
|
158
|
-
|
|
172
|
+
return runSetup(agentSetup, planAgentSteps({
|
|
159
173
|
yes,
|
|
160
174
|
agentSetup
|
|
161
|
-
})
|
|
162
|
-
return agentSetup;
|
|
175
|
+
}));
|
|
163
176
|
};
|
|
164
177
|
//#endregion
|
|
165
178
|
export { runAgentTooling, runToolingSteps };
|