neon 8.11.3 → 8.12.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 +13 -0
- package/dist/_chunks/{checkout-CXIOydqZ.js → checkout-BGvlLc43.js} +3 -3
- package/dist/_chunks/{claim-DqAvAvDm.js → claim-DqzLXZMN.js} +1 -1
- package/dist/_chunks/{config-BH_qRHiG.js → config-BnwcGpbq.js} +1 -1
- package/dist/_chunks/{deploy-D7B0Xfjg.js → deploy-BCVcDR1O.js} +1 -1
- package/dist/_chunks/{dev-CSvxAecE.js → dev-mrJKMt2R.js} +3 -3
- package/dist/_chunks/{git-H32TNt6M.js → git-pN4kMH0d.js} +2 -2
- package/dist/_chunks/{link-BgtkOBws.js → link-DOM84hYj.js} +2 -2
- package/dist/_chunks/{skills-DyiBXKS3.js → skills-BP6pIm7O.js} +35 -4
- package/dist/_chunks/{status-DV8Z2kw3.js → status-DoNjIbKf.js} +1 -1
- package/dist/cli.js +1 -0
- package/dist/commands/checkout.js +1 -1
- package/dist/commands/claim.js +1 -1
- package/dist/commands/config.js +1 -1
- package/dist/commands/deploy.js +1 -1
- package/dist/commands/dev.js +1 -1
- package/dist/commands/env.js +1 -1
- package/dist/commands/functions_new.js +1 -1
- package/dist/commands/git.js +1 -1
- package/dist/commands/index.js +10 -10
- package/dist/commands/link.js +1 -1
- package/dist/commands/skills.js +1 -1
- package/dist/commands/status.js +1 -1
- package/dist/commands/subscribe.js +1 -1
- package/dist/index.js +13 -3
- package/dist/init/auth.js +1 -1
- package/dist/init/link.js +1 -1
- package/dist/init/run.js +3 -3
- package/dist/init/tooling.js +1 -1
- package/dist/node_version.js +25 -0
- package/dist/skills/check_worker.js +17 -0
- package/dist/skills/freshness.js +349 -0
- package/dist/skills/run.js +1 -2
- package/dist/test_utils/fixtures.js +1 -0
- package/dist/update_notifier.js +15 -1
- package/package.json +6 -6
- package/dist/_chunks/{env-5HS5qQGd.js → env-uVRY4xah.js} +1 -1
package/README.md
CHANGED
|
@@ -58,6 +58,13 @@ of them is Homebrew, the warning recommends `brew uninstall neonctl`, which
|
|
|
58
58
|
leaves `neon` running the other install, such as npm. While duplicates remain, the update notice is held back;
|
|
59
59
|
`NO_UPDATE_NOTIFIER=1` silences both.
|
|
60
60
|
|
|
61
|
+
Commands also warn once a day when Neon agent skills are behind their source, in this
|
|
62
|
+
directory's `skills-lock.json` or the user-level skills lock (see
|
|
63
|
+
[`neon skills status`](#install-neon-agent-skills-skills)). This warning runs without a
|
|
64
|
+
terminal too, so coding agents see it. It checks GitHub once a day in the background and
|
|
65
|
+
follows the same CI, machine-readable output, standalone binary, and
|
|
66
|
+
`NO_UPDATE_NOTIFIER=1` rules.
|
|
67
|
+
|
|
61
68
|
## Connect
|
|
62
69
|
|
|
63
70
|
Run the following command to authenticate a connection to Neon:
|
|
@@ -973,8 +980,14 @@ $ neon skills --global
|
|
|
973
980
|
$ neon skills update
|
|
974
981
|
$ neon skills update -y
|
|
975
982
|
$ neon skills update --global -y
|
|
983
|
+
|
|
984
|
+
# Check whether installed Neon skills are behind their source.
|
|
985
|
+
$ neon skills status
|
|
986
|
+
$ neon skills status --global
|
|
976
987
|
```
|
|
977
988
|
|
|
989
|
+
`neon skills status` compares each Neon skill in this directory's `skills-lock.json` (or, with `--global`, the user-level skills lock) with the skill folder on its source repository's default branch, and prints `up to date`, `outdated`, or `not found upstream` per skill. It reads GitHub anonymously; set `GITHUB_TOKEN` or `GH_TOKEN` if the GitHub API rate limit is reached. Skills installed through an agent plugin are not in either lock and are not listed.
|
|
990
|
+
|
|
978
991
|
On a TTY the command asks which agents and which skills, then installs. Detected agents start selected from project-folder markers such as `.cursor`. Default skills start selected. `neon-postgres-agent-platforms` is offered and starts unselected.
|
|
979
992
|
|
|
980
993
|
`-y` skips those questions and installs the default skills into detected agents: project-folder markers such as `.cursor`, else the agent driving the CLI. `--agent` / `-a` names coding agents and skips the agent picker. `--skill` / `-s` names specific skills and skips the skill picker; it does not select agents. `--global -y` uses installed apps, else the host CLI agent. Without a TTY, pass `-y`, or `--skill <name>` (add `--agent <name>` to name agents). If `-y` finds no agent, it exits: pass `--agent <name>`, run from a supported agent, or omit `-y` in a terminal to pick.
|
|
@@ -11,9 +11,9 @@ import { looksLikeBranchId } from "../utils/formats.js";
|
|
|
11
11
|
import { fillSingleProject, listAllProjectBranches } from "../utils/enrichers.js";
|
|
12
12
|
import { buildCheckoutEvent, readGitContext } from "../utils/git.js";
|
|
13
13
|
import { buildHookBranch, loadHookConfig, resolveHookEnv, runCheckoutAfterHook, runCheckoutBeforeHook, runCreateAfterHook, runCreateBeforeHook } from "../utils/hooks.js";
|
|
14
|
-
import { n as autoPullEnvAfterPin } from "./env-
|
|
15
|
-
import { a as applyPolicyOnCreate, f as envFlag, l as createBranchFromPolicyOnCheckout } from "./config-
|
|
16
|
-
import { i as handler$1 } from "./link-
|
|
14
|
+
import { n as autoPullEnvAfterPin } from "./env-uVRY4xah.js";
|
|
15
|
+
import { a as applyPolicyOnCreate, f as envFlag, l as createBranchFromPolicyOnCheckout } from "./config-BnwcGpbq.js";
|
|
16
|
+
import { i as handler$1 } from "./link-DOM84hYj.js";
|
|
17
17
|
import chalk from "chalk";
|
|
18
18
|
import prompts from "prompts";
|
|
19
19
|
//#region src/commands/checkout.ts
|
|
@@ -12,7 +12,7 @@ import { projectConfigPath } from "../project.js";
|
|
|
12
12
|
import { resolveEnvFilePath } from "../env_file.js";
|
|
13
13
|
import { writer } from "../writer.js";
|
|
14
14
|
import { noPassthrough } from "../utils/flags.js";
|
|
15
|
-
import { c as pull } from "./env-
|
|
15
|
+
import { c as pull } from "./env-uVRY4xah.js";
|
|
16
16
|
import { existsSync, readFileSync, unlinkSync, writeFileSync } from "node:fs";
|
|
17
17
|
import open from "open";
|
|
18
18
|
import prompts from "prompts";
|
|
@@ -23,7 +23,7 @@ import { readGitContext } from "../utils/git.js";
|
|
|
23
23
|
import { resolveHookEnv, runDeployAfterHook, runDeployBeforeHook } from "../utils/hooks.js";
|
|
24
24
|
import { pickServicesInteractively } from "../utils/service_picker.js";
|
|
25
25
|
import { zipBundle } from "../utils/zip.js";
|
|
26
|
-
import { n as autoPullEnvAfterPin } from "./env-
|
|
26
|
+
import { n as autoPullEnvAfterPin } from "./env-uVRY4xah.js";
|
|
27
27
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
28
28
|
import { dirname, join, relative, resolve } from "node:path";
|
|
29
29
|
import chalk from "chalk";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { t as __exportAll } from "./rolldown-runtime-8H4AJuhK.js";
|
|
2
2
|
import { fillSingleProject } from "../utils/enrichers.js";
|
|
3
|
-
import { f as envFlag, i as applyFlags, p as envPullFlag, r as applyCmd } from "./config-
|
|
3
|
+
import { f as envFlag, i as applyFlags, p as envPullFlag, r as applyCmd } from "./config-BnwcGpbq.js";
|
|
4
4
|
import { DEPLOY_COMMANDS_EPILOGUE } from "../commands/deploy_help.js";
|
|
5
5
|
//#region src/commands/deploy.ts
|
|
6
6
|
var deploy_exports = /* @__PURE__ */ __exportAll({
|
|
@@ -4,12 +4,12 @@ import { isClaimableEnvTarget } from "../claimable/state.js";
|
|
|
4
4
|
import { getCliName } from "../utils/cli_name.js";
|
|
5
5
|
import { defaultDevEnvFiles, readEnvFile, resolveEnvFilePath } from "../env_file.js";
|
|
6
6
|
import { l as functionBaseUrlKey } from "./env-BpP3Dqpe.js";
|
|
7
|
-
import { branchIdResolve } from "../utils/enrichers.js";
|
|
8
|
-
import { bundleEntry } from "../utils/esbuild.js";
|
|
9
7
|
import { a as resolveDevEnv } from "./env-BNm69Qh8.js";
|
|
10
|
-
import { f as envFlag } from "./config-BH_qRHiG.js";
|
|
11
8
|
import { findConfigFunctionBySource, resolveFunctionsFromConfig } from "../dev/functions.js";
|
|
12
9
|
import { resolveWatchInputs } from "../dev/inputs.js";
|
|
10
|
+
import { branchIdResolve } from "../utils/enrichers.js";
|
|
11
|
+
import { bundleEntry } from "../utils/esbuild.js";
|
|
12
|
+
import { f as envFlag } from "./config-BnwcGpbq.js";
|
|
13
13
|
import { existsSync, mkdirSync, rmSync, statSync, writeFileSync } from "node:fs";
|
|
14
14
|
import { basename, dirname, join, relative, resolve } from "node:path";
|
|
15
15
|
import { fileURLToPath } from "node:url";
|
|
@@ -5,8 +5,8 @@ import { CONTEXT_FILE, contextBranch, gitBranchMap, gitBranchMapping, isUnfollow
|
|
|
5
5
|
import { writer } from "../writer.js";
|
|
6
6
|
import { neonSafeBranchName } from "../utils/branch_name.js";
|
|
7
7
|
import { currentGitBranch, gitPull, gitRepoRoot, hasUpstream, installPostCheckoutHook, isGitRepo, isManagedHook, localGitBranches, postCheckoutHookPath, readGitContext, removePostCheckoutHook } from "../utils/git.js";
|
|
8
|
-
import { o as quoteFlagValue } from "./link-
|
|
9
|
-
import { o as handler$1 } from "./checkout-
|
|
8
|
+
import { o as quoteFlagValue } from "./link-DOM84hYj.js";
|
|
9
|
+
import { o as handler$1 } from "./checkout-BGvlLc43.js";
|
|
10
10
|
import { existsSync } from "node:fs";
|
|
11
11
|
import { join } from "node:path";
|
|
12
12
|
import chalk from "chalk";
|
|
@@ -13,8 +13,8 @@ import { writer } from "../writer.js";
|
|
|
13
13
|
import { createBranch, pickBranchInteractively } from "../utils/branch_picker.js";
|
|
14
14
|
import { looksLikeBranchId } from "../utils/formats.js";
|
|
15
15
|
import { listAllProjectBranches } from "../utils/enrichers.js";
|
|
16
|
-
import { n as autoPullEnvAfterPin } from "./env-
|
|
17
|
-
import { h as initCmd } from "./config-
|
|
16
|
+
import { n as autoPullEnvAfterPin } from "./env-uVRY4xah.js";
|
|
17
|
+
import { h as initCmd } from "./config-BnwcGpbq.js";
|
|
18
18
|
import { formatLinkSummary } from "../commands/link_output.js";
|
|
19
19
|
import { r as REGIONS } from "./projects-BwI2Uo0z.js";
|
|
20
20
|
import prompts from "prompts";
|
|
@@ -10,9 +10,10 @@ import { noPassthrough } from "../utils/flags.js";
|
|
|
10
10
|
import { AGENT_SKILLS_SKIP_MESSAGE } from "../init/copy.js";
|
|
11
11
|
import { canPickAgentsInteractively, skippableAgentPicker } from "../utils/agent_picker.js";
|
|
12
12
|
import { skillsHelpValues, skillsYesHelp } from "../skills/catalog.js";
|
|
13
|
+
import { lockPath, neonSkillsUpdateCommand, readLockedSkills, refreshSkillsCheckCache, scopeLabel, skillsCheckCachePath, skillsStatusRows } from "../skills/freshness.js";
|
|
13
14
|
import { confirmSkillsUpdate } from "../skills/wizard.js";
|
|
14
15
|
import { assertSkillsCanRun, resolveSkillsPlan } from "../skills/plan.js";
|
|
15
|
-
import { assertSkillsNode, neonSkillsRetryCommand,
|
|
16
|
+
import { assertSkillsNode, neonSkillsRetryCommand, runSkillsCli, skillsAddArgs, skillsMetadata, skillsUpdateArgs, skillsUpdateDetail, skillsUpdateHadNothing } from "../skills/run.js";
|
|
16
17
|
//#region src/commands/skills.ts
|
|
17
18
|
var skills_exports = /* @__PURE__ */ __exportAll({
|
|
18
19
|
aliases: () => aliases,
|
|
@@ -24,7 +25,6 @@ var skills_exports = /* @__PURE__ */ __exportAll({
|
|
|
24
25
|
reportSkillsInstall: () => reportSkillsInstall,
|
|
25
26
|
skillsInstallError: () => skillsInstallError
|
|
26
27
|
});
|
|
27
|
-
const scopeLabel = (scope) => scope === "project" ? "this directory" : "user-level";
|
|
28
28
|
const coerceAgents = (value) => {
|
|
29
29
|
if (value === void 0) return [];
|
|
30
30
|
const list = Array.isArray(value) ? value : [value];
|
|
@@ -60,7 +60,17 @@ const builder = (argv) => argv.usage("$0 skills [command] [options]").command("u
|
|
|
60
60
|
const skills = args.skill;
|
|
61
61
|
if (Array.isArray(skills) && skills.length > 0) throw new Error("neon skills update does not take --skill. It refreshes every installed skill in this directory (or --global).");
|
|
62
62
|
return true;
|
|
63
|
-
}), (args) => updateHandler(args)).options({
|
|
63
|
+
}), (args) => updateHandler(args)).command("status", "Check whether installed Neon skills match their source", (yargs) => yargs.usage("$0 skills status [options]").options({ global: {
|
|
64
|
+
type: "boolean",
|
|
65
|
+
default: false,
|
|
66
|
+
describe: "Check user-level skills (skills CLI -g). Default is this directory"
|
|
67
|
+
} }).example("$0 skills status", "Neon skills in this directory's skills-lock.json").example("$0 skills status --global", "User-level Neon skills").strict().hide("agent").hide("skill").hide("yes").check((args) => {
|
|
68
|
+
noPassthrough("skills status")(args);
|
|
69
|
+
const agents = args.agent;
|
|
70
|
+
const skills = args.skill;
|
|
71
|
+
if (Array.isArray(agents) && agents.length > 0 || Array.isArray(skills) && skills.length > 0) throw new Error("neon skills status does not take --agent or --skill. It checks every Neon skill in this directory (or --global).");
|
|
72
|
+
return true;
|
|
73
|
+
}), (args) => statusHandler(args)).options({
|
|
64
74
|
yes: {
|
|
65
75
|
alias: "y",
|
|
66
76
|
type: "boolean",
|
|
@@ -249,7 +259,28 @@ const updateHandler = async (props) => {
|
|
|
249
259
|
title: "Skills"
|
|
250
260
|
});
|
|
251
261
|
out.end();
|
|
252
|
-
if (failure !== void 0) throw new Error(failure.includes("needs npx (Node.js)") || failure.includes("needs Node.js") ? failure : `${failure}\nRetry with: ${
|
|
262
|
+
if (failure !== void 0) throw new Error(failure.includes("needs npx (Node.js)") || failure.includes("needs Node.js") ? failure : `${failure}\nRetry with: ${neonSkillsUpdateCommand(scope)}`);
|
|
263
|
+
};
|
|
264
|
+
const statusHandler = async (props) => {
|
|
265
|
+
const scope = props.global === true ? "global" : "project";
|
|
266
|
+
const skills = readLockedSkills(lockPath(scope, process.cwd()), scope);
|
|
267
|
+
const folders = skills.length === 0 ? {} : await refreshSkillsCheckCache({
|
|
268
|
+
cachePath: skillsCheckCachePath(props.configDir),
|
|
269
|
+
skills
|
|
270
|
+
});
|
|
271
|
+
const rows = skillsStatusRows(skills, folders);
|
|
272
|
+
const out = writer(props);
|
|
273
|
+
out.write(rows, {
|
|
274
|
+
fields: [
|
|
275
|
+
"scope",
|
|
276
|
+
"skill",
|
|
277
|
+
"status"
|
|
278
|
+
],
|
|
279
|
+
title: "Skills",
|
|
280
|
+
emptyMessage: scope === "project" ? "No Neon skills in this directory's skills-lock.json. For user-level skills, run: neon skills status --global" : "No user-level Neon skills in the skills CLI lock."
|
|
281
|
+
});
|
|
282
|
+
out.end();
|
|
283
|
+
if (rows.some((row) => row.status === "outdated")) log.info("Update them: %s", neonSkillsUpdateCommand(scope));
|
|
253
284
|
};
|
|
254
285
|
//#endregion
|
|
255
286
|
export { handler as a, skillsInstallError as c, describe as i, skills_exports as l, builder as n, installSkills as o, command as r, reportSkillsInstall as s, aliases as t };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { t as __exportAll } from "./rolldown-runtime-8H4AJuhK.js";
|
|
2
2
|
import { fillSingleProject } from "../utils/enrichers.js";
|
|
3
|
-
import { y as status } from "./config-
|
|
3
|
+
import { y as status } from "./config-BnwcGpbq.js";
|
|
4
4
|
//#region src/commands/status.ts
|
|
5
5
|
var status_exports = /* @__PURE__ */ __exportAll({
|
|
6
6
|
builder: () => builder,
|
package/dist/cli.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { t as builder, r as command, i as describe, a as formatCheckoutPolicyFailure, o as handler } from "../_chunks/checkout-
|
|
1
|
+
export { t as builder, r as command, i as describe, a as formatCheckoutPolicyFailure, o as handler } from "../_chunks/checkout-BGvlLc43.js";
|
package/dist/commands/claim.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { t as CLAIM_CREATE_FIELDS, n as CLAIM_LIST_FIELDS, r as aliases, i as builder, a as claimCreateFields, s as claimableCapabilities, c as command, l as create, u as describe, d as handler } from "../_chunks/claim-
|
|
1
|
+
export { t as CLAIM_CREATE_FIELDS, n as CLAIM_LIST_FIELDS, r as aliases, i as builder, a as claimCreateFields, s as claimableCapabilities, c as command, l as create, u as describe, d as handler } from "../_chunks/claim-DqzLXZMN.js";
|
package/dist/commands/config.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { t as ConfigInstallFailed, n as addCmd, r as applyCmd, i as applyFlags, a as applyPolicyOnCreate, o as builder, s as command, l as createBranchFromPolicyOnCheckout, u as describe, d as ensureConfigPackages, f as envFlag, p as envPullFlag, m as handler, h as initCmd, g as installCommandFrom, _ as missingDependencies, v as planCmd, y as status } from "../_chunks/config-
|
|
1
|
+
export { t as ConfigInstallFailed, n as addCmd, r as applyCmd, i as applyFlags, a as applyPolicyOnCreate, o as builder, s as command, l as createBranchFromPolicyOnCheckout, u as describe, d as ensureConfigPackages, f as envFlag, p as envPullFlag, m as handler, h as initCmd, g as installCommandFrom, _ as missingDependencies, v as planCmd, y as status } from "../_chunks/config-BnwcGpbq.js";
|
package/dist/commands/deploy.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { t as builder, n as command, i as describe, a as handler } from "../_chunks/deploy-
|
|
1
|
+
export { t as builder, n as command, i as describe, a as handler } from "../_chunks/deploy-BCVcDR1O.js";
|
package/dist/commands/dev.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { t as builder, n as captureShellEnv, r as command, i as describe, a as devBundleDir, o as devEnvContext, c as diffUnits, l as formatEnvFiles, u as formatEnvSummary, d as handler, f as loadDevEnvFiles, p as localFunctionUrlEnv, m as planFunctionsToUnits, h as reportDevCredential, g as sourceFunctionUrlOverlay } from "../_chunks/dev-
|
|
1
|
+
export { t as builder, n as captureShellEnv, r as command, i as describe, a as devBundleDir, o as devEnvContext, c as diffUnits, l as formatEnvFiles, u as formatEnvSummary, d as handler, f as loadDevEnvFiles, p as localFunctionUrlEnv, m as planFunctionsToUnits, h as reportDevCredential, g as sourceFunctionUrlOverlay } from "../_chunks/dev-mrJKMt2R.js";
|
package/dist/commands/env.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { t as ENV_PULL_SKIPPED_HINT, n as autoPullEnvAfterPin, r as builder, i as command, a as describe, s as handler, c as pull } from "../_chunks/env-
|
|
1
|
+
export { t as ENV_PULL_SKIPPED_HINT, n as autoPullEnvAfterPin, r as builder, i as command, a as describe, s as handler, c as pull } from "../_chunks/env-uVRY4xah.js";
|
|
@@ -8,7 +8,7 @@ import { writer } from "../writer.js";
|
|
|
8
8
|
import { formatInitDone, printInitDone } from "../init/chrome.js";
|
|
9
9
|
import { FUNCTION_SLUG_PATTERN, deriveFunctionSlug } from "../utils/function_slug.js";
|
|
10
10
|
import { displayPath } from "./env_output.js";
|
|
11
|
-
import { _ as missingDependencies, d as ensureConfigPackages, g as installCommandFrom } from "../_chunks/config-
|
|
11
|
+
import { _ as missingDependencies, d as ensureConfigPackages, g as installCommandFrom } from "../_chunks/config-BnwcGpbq.js";
|
|
12
12
|
import { recommendedOperations } from "../functions/registry.js";
|
|
13
13
|
import { collidingFiles, operationsFromFlags, planConfigRegistration, planEnvExample, planScaffold, writeScaffold } from "../functions/scaffold.js";
|
|
14
14
|
import { describeRegistrySource, openRegistry } from "../functions/source.js";
|
package/dist/commands/git.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { t as aliases, n as builder, r as cleanup, i as command, a as describe, s as handler, c as install, l as partitionBranchesToPrune, u as status, d as sync, f as uninstall } from "../_chunks/git-
|
|
1
|
+
export { t as aliases, n as builder, r as cleanup, i as command, a as describe, s as handler, c as install, l as partitionBranchesToPrune, u as status, d as sync, f as uninstall } from "../_chunks/git-pN4kMH0d.js";
|
package/dist/commands/index.js
CHANGED
|
@@ -2,29 +2,29 @@ import { r as auth_exports } from "../_chunks/auth-CIUtXByB.js";
|
|
|
2
2
|
import { t as api_exports } from "../_chunks/api-GbEaBZJ5.js";
|
|
3
3
|
import { n as api_keys_exports } from "../_chunks/api_keys-CNnnugbQ.js";
|
|
4
4
|
import { n as ask_exports } from "../_chunks/ask-DVwy0eUL.js";
|
|
5
|
-
import { o as env_exports } from "../_chunks/env-
|
|
6
|
-
import { c as config_exports } from "../_chunks/config-
|
|
5
|
+
import { o as env_exports } from "../_chunks/env-uVRY4xah.js";
|
|
6
|
+
import { c as config_exports } from "../_chunks/config-BnwcGpbq.js";
|
|
7
7
|
import { u as projects_exports } from "../_chunks/projects-BwI2Uo0z.js";
|
|
8
|
-
import { a as link_exports } from "../_chunks/link-
|
|
8
|
+
import { a as link_exports } from "../_chunks/link-DOM84hYj.js";
|
|
9
9
|
import { o as mcp_exports } from "../_chunks/mcp-Bo-7TKc7.js";
|
|
10
10
|
import { c as plugins_exports } from "../_chunks/plugins-DqD7BDO1.js";
|
|
11
|
-
import { l as skills_exports } from "../_chunks/skills-
|
|
11
|
+
import { l as skills_exports } from "../_chunks/skills-BP6pIm7O.js";
|
|
12
12
|
import { t as bootstrap_exports } from "../_chunks/bootstrap-wPZWa1sT.js";
|
|
13
13
|
import { r as branches_exports } from "../_chunks/branches-BNa1xX1L.js";
|
|
14
14
|
import { n as bucket_exports } from "../_chunks/bucket-BCdryTkD.js";
|
|
15
|
-
import { n as checkout_exports } from "../_chunks/checkout-
|
|
16
|
-
import { o as claim_exports } from "../_chunks/claim-
|
|
15
|
+
import { n as checkout_exports } from "../_chunks/checkout-BGvlLc43.js";
|
|
16
|
+
import { o as claim_exports } from "../_chunks/claim-DqzLXZMN.js";
|
|
17
17
|
import { a as connection_string_exports } from "../_chunks/connection_string-DB4awPzZ.js";
|
|
18
18
|
import { a as credentials_exports } from "../_chunks/credentials-BSjE9fRR.js";
|
|
19
19
|
import { r as data_api_exports } from "../_chunks/data_api-Djxj5ZQD.js";
|
|
20
20
|
import { o as databases_exports } from "../_chunks/databases-Dok4wru7.js";
|
|
21
|
-
import { r as deploy_exports } from "../_chunks/deploy-
|
|
22
|
-
import { s as dev_exports } from "../_chunks/dev-
|
|
21
|
+
import { r as deploy_exports } from "../_chunks/deploy-BCVcDR1O.js";
|
|
22
|
+
import { s as dev_exports } from "../_chunks/dev-mrJKMt2R.js";
|
|
23
23
|
import { i as diff_exports } from "../_chunks/diff-DhxxbdQE.js";
|
|
24
24
|
import { c as docs_exports } from "../_chunks/docs-CrVybkTP.js";
|
|
25
25
|
import { o as feedback_exports } from "../_chunks/feedback-CMayyTa8.js";
|
|
26
26
|
import { o as functions_exports } from "../_chunks/functions-Q0zuvtnk.js";
|
|
27
|
-
import { o as git_exports } from "../_chunks/git-
|
|
27
|
+
import { o as git_exports } from "../_chunks/git-pN4kMH0d.js";
|
|
28
28
|
import { a as init_exports } from "../_chunks/init-BkA6RilG.js";
|
|
29
29
|
import { o as inspect_exports } from "../_chunks/inspect-g0wekylj.js";
|
|
30
30
|
import { a as ip_allow_exports } from "../_chunks/ip_allow-5lLFvIuE.js";
|
|
@@ -39,7 +39,7 @@ import { s as realtime_exports } from "../_chunks/realtime-BRqIyGR-.js";
|
|
|
39
39
|
import { l as roles_exports } from "../_chunks/roles-B4w3YT_7.js";
|
|
40
40
|
import { a as set_context_exports } from "../_chunks/set_context-DbrwoImy.js";
|
|
41
41
|
import { s as snapshots_exports } from "../_chunks/snapshots-RJBzW8GM.js";
|
|
42
|
-
import { a as status_exports } from "../_chunks/status-
|
|
42
|
+
import { a as status_exports } from "../_chunks/status-DoNjIbKf.js";
|
|
43
43
|
import { d as triggers_exports } from "../_chunks/triggers-BrRo1z4b.js";
|
|
44
44
|
import { s as user_exports } from "../_chunks/user-dlOGXbX9.js";
|
|
45
45
|
import { i as vpc_endpoints_exports } from "../_chunks/vpc_endpoints-CNb0YfMo.js";
|
package/dist/commands/link.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { t as builder, n as command, r as describe, i as handler, o as quoteFlagValue, s as runLink, c as shouldOfferConfigInit } from "../_chunks/link-
|
|
1
|
+
export { t as builder, n as command, r as describe, i as handler, o as quoteFlagValue, s as runLink, c as shouldOfferConfigInit } from "../_chunks/link-DOM84hYj.js";
|
package/dist/commands/skills.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { t as aliases, n as builder, r as command, i as describe, a as handler, o as installSkills, s as reportSkillsInstall, c as skillsInstallError } from "../_chunks/skills-
|
|
1
|
+
export { t as aliases, n as builder, r as command, i as describe, a as handler, o as installSkills, s as reportSkillsInstall, c as skillsInstallError } from "../_chunks/skills-BP6pIm7O.js";
|
package/dist/commands/status.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { t as builder, n as command, r as describe, i as handler } from "../_chunks/status-
|
|
1
|
+
export { t as builder, n as command, r as describe, i as handler } from "../_chunks/status-DoNjIbKf.js";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { writer } from "../writer.js";
|
|
2
|
-
import { branchIdFromProps } from "../utils/enrichers.js";
|
|
3
2
|
import { o as resolveNeonEnvVars } from "../_chunks/env-BNm69Qh8.js";
|
|
3
|
+
import { branchIdFromProps } from "../utils/enrichers.js";
|
|
4
4
|
import YAML from "yaml";
|
|
5
5
|
//#region src/commands/subscribe.ts
|
|
6
6
|
const builder = (argv) => argv.usage("$0 realtime subscribe \"<query>\" [options]").positional("query", {
|
package/dist/index.js
CHANGED
|
@@ -15,7 +15,7 @@ import { UsageError, failOnUsageError, isBareParentCommand, showHelp, showUsageE
|
|
|
15
15
|
import { lazyCommands, preloadCommand } from "./commands/manifest.js";
|
|
16
16
|
import { rewriteUnknownAgentArg } from "./init/plan.js";
|
|
17
17
|
import { recoverFromSSO } from "./sso_recovery.js";
|
|
18
|
-
import { notifyIfUpdateAvailable } from "./update_notifier.js";
|
|
18
|
+
import { notifyIfUpdateAvailable, shouldRunSkillsNotifier } from "./update_notifier.js";
|
|
19
19
|
import { fillInArgs, resolveApiKeyFromEnv } from "./utils/middlewares.js";
|
|
20
20
|
import { collapseRepeatedFlags, declaredOptions } from "./utils/repeated_flags.js";
|
|
21
21
|
import { stagingFeaturesEnabledForArgv } from "./utils/staging.js";
|
|
@@ -214,13 +214,23 @@ async function handleError(msg, err, canRetry) {
|
|
|
214
214
|
process.exit(0);
|
|
215
215
|
}
|
|
216
216
|
await closeAnalytics();
|
|
217
|
-
|
|
217
|
+
const notifier = {
|
|
218
218
|
commandPath: args._.map(String),
|
|
219
219
|
configDir: typeof args.configDir === "string" ? args.configDir : defaultDir,
|
|
220
220
|
currentBranch: Boolean(args.currentBranch),
|
|
221
|
-
currentVersion: pkg_default.version,
|
|
222
221
|
output: typeof args.output === "string" ? args.output : "table"
|
|
222
|
+
};
|
|
223
|
+
notifyIfUpdateAvailable({
|
|
224
|
+
...notifier,
|
|
225
|
+
currentVersion: pkg_default.version
|
|
223
226
|
});
|
|
227
|
+
if (shouldRunSkillsNotifier(notifier)) {
|
|
228
|
+
const { notifyIfSkillsOutdated } = await import("./skills/freshness.js");
|
|
229
|
+
notifyIfSkillsOutdated({
|
|
230
|
+
configDir: notifier.configDir,
|
|
231
|
+
cwd: process.cwd()
|
|
232
|
+
});
|
|
233
|
+
}
|
|
224
234
|
break;
|
|
225
235
|
} catch (err) {
|
|
226
236
|
takeCommandSuccessExtras();
|
package/dist/init/auth.js
CHANGED
|
@@ -4,7 +4,7 @@ import "../config.js";
|
|
|
4
4
|
import "../auth.js";
|
|
5
5
|
import { c as ensureAuth } from "../_chunks/auth-CIUtXByB.js";
|
|
6
6
|
import { recoverFrom401 } from "../auth_recovery.js";
|
|
7
|
-
import { c as pull } from "../_chunks/env-
|
|
7
|
+
import { c as pull } from "../_chunks/env-uVRY4xah.js";
|
|
8
8
|
import { c as setupNeonMcp } from "../_chunks/mcp-Bo-7TKc7.js";
|
|
9
9
|
//#region src/init/auth.ts
|
|
10
10
|
const isUnauthorized = (error) => isNeonApiError(error) && error.status === 401;
|
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-CIUtXByB.js";
|
|
6
6
|
import { recoverFrom401 } from "../auth_recovery.js";
|
|
7
|
-
import { s as runLink } from "../_chunks/link-
|
|
7
|
+
import { s as runLink } from "../_chunks/link-DOM84hYj.js";
|
|
8
8
|
//#region 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/run.js
CHANGED
|
@@ -17,15 +17,15 @@ import { FALLBACK_SKILLS_AGENTS, assertNamedAgentTooling, funnelAgentSetup, plan
|
|
|
17
17
|
import { inferPackageManager, resolvePackageManager } from "../utils/package_manager.js";
|
|
18
18
|
import { 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, unattendedUnauthedNext } from "./copy.js";
|
|
19
19
|
import { agentsRowValue, configRowValue, formatInitDone, headingForKind, printInitBanner, printInitDone, printInitProgress, projectRowValue, shouldPrintInitBanner } from "./chrome.js";
|
|
20
|
-
import { h as initCmd, t as ConfigInstallFailed } from "../_chunks/config-
|
|
21
|
-
import { o as quoteFlagValue, s as runLink } from "../_chunks/link-
|
|
20
|
+
import { h as initCmd, t as ConfigInstallFailed } from "../_chunks/config-BnwcGpbq.js";
|
|
21
|
+
import { o as quoteFlagValue, s as runLink } from "../_chunks/link-DOM84hYj.js";
|
|
22
22
|
import { runAuthenticatedLink } from "./link.js";
|
|
23
23
|
import { CannotMintApiKeyError } from "../mcp/mint.js";
|
|
24
24
|
import { pullInitEnv } 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 } from "./tooling.js";
|
|
28
|
-
import { l as create } from "../_chunks/claim-
|
|
28
|
+
import { l as create } from "../_chunks/claim-DqzLXZMN.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 } from "./funnel.js";
|
package/dist/init/tooling.js
CHANGED
|
@@ -7,7 +7,7 @@ import { detectAgent } from "./detect_host.js";
|
|
|
7
7
|
import { AgentSelectionSkipped, canPickAgentsInteractively } from "../utils/agent_picker.js";
|
|
8
8
|
import { a as mcpInstallError, s as reportMcpInstall } from "../_chunks/mcp-Bo-7TKc7.js";
|
|
9
9
|
import { l as reportPluginsInstall, o as installPlugins, s as pluginsInstallError } from "../_chunks/plugins-DqD7BDO1.js";
|
|
10
|
-
import { c as skillsInstallError, o as installSkills, s as reportSkillsInstall } from "../_chunks/skills-
|
|
10
|
+
import { c as skillsInstallError, o as installSkills, s as reportSkillsInstall } from "../_chunks/skills-BP6pIm7O.js";
|
|
11
11
|
import { runAuthenticatedMcp } from "./auth.js";
|
|
12
12
|
import { raceSigint } from "./cancelled.js";
|
|
13
13
|
import { pickAgentSetupInteractively } from "./wizard.js";
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { getCliName } from "./utils/cli_name.js";
|
|
2
|
+
//#region src/node_version.ts
|
|
3
|
+
/** Matches `engines.node` in package.json; npm only warns when it isn't met. */
|
|
4
|
+
const MIN_NODE_VERSION = [
|
|
5
|
+
20,
|
|
6
|
+
19,
|
|
7
|
+
0
|
|
8
|
+
];
|
|
9
|
+
/** The error to print for an unsupported Node.js version, or `undefined` when it is supported. */
|
|
10
|
+
function unsupportedNodeMessage(version, cliName) {
|
|
11
|
+
const parts = version.replace(/^v/, "").split(".").map(Number);
|
|
12
|
+
for (let i = 0; i < MIN_NODE_VERSION.length; i += 1) {
|
|
13
|
+
const actual = parts[i] ?? 0;
|
|
14
|
+
const required = MIN_NODE_VERSION[i];
|
|
15
|
+
if (actual > required) return void 0;
|
|
16
|
+
if (actual < required) return `${cliName} requires Node.js ${MIN_NODE_VERSION[0]}.${MIN_NODE_VERSION[1]} or newer (found ${version.replace(/^v/, "")}).`;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
const message = unsupportedNodeMessage(process.versions.node, getCliName());
|
|
20
|
+
if (message) {
|
|
21
|
+
process.stderr.write(`${message}\n`);
|
|
22
|
+
process.exit(1);
|
|
23
|
+
}
|
|
24
|
+
//#endregion
|
|
25
|
+
export { MIN_NODE_VERSION, unsupportedNodeMessage };
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { globalLockPath, projectLockPath, readLockedSkills, refreshSkillsCheckCache } from "./freshness.js";
|
|
2
|
+
import { pathToFileURL } from "node:url";
|
|
3
|
+
//#region src/skills/check_worker.ts
|
|
4
|
+
const run = async () => {
|
|
5
|
+
const [cachePath, cwd] = process.argv.slice(2);
|
|
6
|
+
if (cachePath === void 0 || cwd === void 0) return;
|
|
7
|
+
try {
|
|
8
|
+
await refreshSkillsCheckCache({
|
|
9
|
+
cachePath,
|
|
10
|
+
skills: [...readLockedSkills(globalLockPath(), "global"), ...readLockedSkills(projectLockPath(cwd), "project")]
|
|
11
|
+
});
|
|
12
|
+
} catch {}
|
|
13
|
+
};
|
|
14
|
+
const entry = process.argv[1];
|
|
15
|
+
if (entry !== void 0 && import.meta.url === pathToFileURL(entry).href) run();
|
|
16
|
+
//#endregion
|
|
17
|
+
export {};
|
|
@@ -0,0 +1,349 @@
|
|
|
1
|
+
import { log } from "../log.js";
|
|
2
|
+
import { writeJsonFile } from "../utils/json_file.js";
|
|
3
|
+
import { showNotice } from "../notices.js";
|
|
4
|
+
import { AGENT_SKILLS_SOURCE, PLATFORMS_SKILLS_SOURCE } from "./catalog.js";
|
|
5
|
+
import { closeSync, constants, existsSync, fstatSync, openSync, readFileSync, statSync } from "node:fs";
|
|
6
|
+
import { join } from "node:path";
|
|
7
|
+
import { createHash } from "node:crypto";
|
|
8
|
+
import { fileURLToPath } from "node:url";
|
|
9
|
+
import { homedir } from "node:os";
|
|
10
|
+
import { spawn } from "node:child_process";
|
|
11
|
+
//#region src/skills/freshness.ts
|
|
12
|
+
const DAY_MS = 864e5;
|
|
13
|
+
const CACHE_FILE = "skills-check.json";
|
|
14
|
+
const FETCH_TIMEOUT_MS = 1e4;
|
|
15
|
+
const NEON_SOURCES = /* @__PURE__ */ new Set([AGENT_SKILLS_SOURCE, PLATFORMS_SKILLS_SOURCE]);
|
|
16
|
+
const scopeLabel = (scope) => scope === "project" ? "this directory" : "user-level";
|
|
17
|
+
const neonSkillsUpdateCommand = (scope) => scope === "global" ? "neon skills update --global -y" : "neon skills update -y";
|
|
18
|
+
/** Where the skills CLI keeps its user-level lock. */
|
|
19
|
+
const globalLockPath = (env = process.env) => env.XDG_STATE_HOME ? join(env.XDG_STATE_HOME, "skills", ".skill-lock.json") : join(homedir(), ".agents", ".skill-lock.json");
|
|
20
|
+
const projectLockPath = (cwd) => join(cwd, "skills-lock.json");
|
|
21
|
+
const lockPath = (scope, cwd) => scope === "global" ? globalLockPath() : projectLockPath(cwd);
|
|
22
|
+
const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
23
|
+
/** The Agent Skills name rule. A lock is repository content, and names reach the terminal. */
|
|
24
|
+
const SKILL_NAME = /^[a-z0-9][a-z0-9-]{0,63}$/;
|
|
25
|
+
const skillFolder = (skillPath) => skillPath.replace(/\\/g, "/").replace(/\/?SKILL\.md$/i, "");
|
|
26
|
+
/**
|
|
27
|
+
* Entries pinned to a `ref` are left out: `neon skills` never pins one, and a pinned skill
|
|
28
|
+
* tracks that ref rather than the repository's default branch.
|
|
29
|
+
*
|
|
30
|
+
* The global lock's `skillFolderHash` is usually a tree SHA, but the skills CLI stores a
|
|
31
|
+
* content SHA-256 there when it installed from a Git clone; it tells them apart by length.
|
|
32
|
+
*/
|
|
33
|
+
const parseSkillsLock = (raw, scope) => {
|
|
34
|
+
const value = JSON.parse(raw);
|
|
35
|
+
if (!isRecord(value) || !isRecord(value.skills)) return [];
|
|
36
|
+
const field = scope === "global" ? "skillFolderHash" : "computedHash";
|
|
37
|
+
const skills = [];
|
|
38
|
+
for (const [skill, entry] of Object.entries(value.skills)) {
|
|
39
|
+
if (!isRecord(entry)) continue;
|
|
40
|
+
const { source, skillPath, ref } = entry;
|
|
41
|
+
const hash = entry[field];
|
|
42
|
+
if (!SKILL_NAME.test(skill) || typeof source !== "string" || !NEON_SOURCES.has(source) || ref !== void 0 || typeof skillPath !== "string" || typeof hash !== "string" || hash === "") continue;
|
|
43
|
+
const folder = skillFolder(skillPath);
|
|
44
|
+
if (folder === "") continue;
|
|
45
|
+
const hashKind = scope === "global" && /^[0-9a-f]{40}$/i.test(hash) ? "tree" : "content";
|
|
46
|
+
skills.push({
|
|
47
|
+
scope,
|
|
48
|
+
skill,
|
|
49
|
+
source,
|
|
50
|
+
folder,
|
|
51
|
+
hash,
|
|
52
|
+
hashKind
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
return skills;
|
|
56
|
+
};
|
|
57
|
+
const readLockedSkills = (path, scope) => {
|
|
58
|
+
if (!existsSync(path)) return [];
|
|
59
|
+
const raw = readLockFile(path);
|
|
60
|
+
try {
|
|
61
|
+
return parseSkillsLock(raw, scope);
|
|
62
|
+
} catch {
|
|
63
|
+
throw new Error(`${path} is not valid JSON.`);
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
const MAX_LOCK_BYTES = 1048576;
|
|
67
|
+
/**
|
|
68
|
+
* A project lock is repository content: a FIFO would block the open and `/dev/zero` the read,
|
|
69
|
+
* on every command run in that directory.
|
|
70
|
+
*/
|
|
71
|
+
const readLockFile = (path) => {
|
|
72
|
+
const fd = openSync(path, constants.O_RDONLY | (constants.O_NONBLOCK ?? 0));
|
|
73
|
+
try {
|
|
74
|
+
const stat = fstatSync(fd);
|
|
75
|
+
if (!stat.isFile()) throw new Error(`${path} is not a regular file.`);
|
|
76
|
+
if (stat.size > MAX_LOCK_BYTES) throw new Error(`${path} is larger than ${MAX_LOCK_BYTES} bytes.`);
|
|
77
|
+
return readFileSync(fd, "utf8");
|
|
78
|
+
} finally {
|
|
79
|
+
closeSync(fd);
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
const folderKey = ({ source, folder }) => `${source}:${folder}`;
|
|
83
|
+
/** `undefined` when the remote side has not been fetched yet. */
|
|
84
|
+
const skillStatus = (skill, remote) => {
|
|
85
|
+
if (remote?.missing === true) return "not found upstream";
|
|
86
|
+
const latest = skill.hashKind === "tree" ? remote?.tree : remote?.content;
|
|
87
|
+
if (latest === void 0) return void 0;
|
|
88
|
+
return latest === skill.hash ? "up to date" : "outdated";
|
|
89
|
+
};
|
|
90
|
+
const parseRemoteFolder = (value) => {
|
|
91
|
+
if (!isRecord(value)) return void 0;
|
|
92
|
+
const { tree, content, missing, pending } = value;
|
|
93
|
+
if (tree !== void 0 && typeof tree !== "string" || content !== void 0 && typeof content !== "string" || missing !== void 0 && missing !== true || pending !== void 0 && pending !== true) return;
|
|
94
|
+
return {
|
|
95
|
+
...tree === void 0 ? {} : { tree },
|
|
96
|
+
...content === void 0 ? {} : { content },
|
|
97
|
+
...missing === void 0 ? {} : { missing },
|
|
98
|
+
...pending === void 0 ? {} : { pending }
|
|
99
|
+
};
|
|
100
|
+
};
|
|
101
|
+
const parseSkillsCheckCache = (raw) => {
|
|
102
|
+
try {
|
|
103
|
+
const value = JSON.parse(raw);
|
|
104
|
+
if (!isRecord(value) || typeof value.checkedAt !== "number" || !Number.isFinite(value.checkedAt) || !isRecord(value.folders)) return;
|
|
105
|
+
const folders = {};
|
|
106
|
+
for (const [key, entry] of Object.entries(value.folders)) {
|
|
107
|
+
const folder = parseRemoteFolder(entry);
|
|
108
|
+
if (folder !== void 0) folders[key] = folder;
|
|
109
|
+
}
|
|
110
|
+
const { attemptedAt } = value;
|
|
111
|
+
return {
|
|
112
|
+
checkedAt: value.checkedAt,
|
|
113
|
+
...typeof attemptedAt === "number" && Number.isFinite(attemptedAt) ? { attemptedAt } : {},
|
|
114
|
+
folders
|
|
115
|
+
};
|
|
116
|
+
} catch {
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
const readSkillsCheckCache = (cachePath) => {
|
|
121
|
+
try {
|
|
122
|
+
return parseSkillsCheckCache(readFileSync(cachePath, "utf8"));
|
|
123
|
+
} catch {
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
const skillsCheckCachePath = (configDir) => join(configDir, CACHE_FILE);
|
|
128
|
+
/**
|
|
129
|
+
* The digest the skills CLI writes to `computedHash`: every file's folder-relative path and
|
|
130
|
+
* then its bytes, in `localeCompare` order of path.
|
|
131
|
+
*/
|
|
132
|
+
const skillContentHash = (files) => {
|
|
133
|
+
const hash = createHash("sha256");
|
|
134
|
+
for (const file of [...files].sort((a, b) => a.path.localeCompare(b.path))) {
|
|
135
|
+
hash.update(file.path);
|
|
136
|
+
hash.update(file.bytes);
|
|
137
|
+
}
|
|
138
|
+
return hash.digest("hex");
|
|
139
|
+
};
|
|
140
|
+
const gitBlobSha = (bytes) => createHash("sha1").update(`blob ${bytes.byteLength}\0`).update(bytes).digest("hex");
|
|
141
|
+
const isTreeEntry = (value) => isRecord(value) && typeof value.path === "string" && typeof value.mode === "string" && typeof value.type === "string" && typeof value.sha === "string";
|
|
142
|
+
const githubHeaders = (env) => {
|
|
143
|
+
const token = env.GITHUB_TOKEN || env.GH_TOKEN;
|
|
144
|
+
return {
|
|
145
|
+
Accept: "application/vnd.github+json",
|
|
146
|
+
"User-Agent": "neon-cli",
|
|
147
|
+
...token ? { Authorization: `Bearer ${token}` } : {}
|
|
148
|
+
};
|
|
149
|
+
};
|
|
150
|
+
const fetchTree = async (source, env) => {
|
|
151
|
+
const response = await fetch(`https://api.github.com/repos/${source}/git/trees/HEAD?recursive=1`, {
|
|
152
|
+
headers: githubHeaders(env),
|
|
153
|
+
signal: AbortSignal.timeout(FETCH_TIMEOUT_MS)
|
|
154
|
+
});
|
|
155
|
+
if (!response.ok) {
|
|
156
|
+
if ((response.status === 403 || response.status === 429) && response.headers.get("x-ratelimit-remaining") === "0") throw new Error(`GitHub API rate limit reached while checking ${source}. Set GITHUB_TOKEN and retry.`);
|
|
157
|
+
throw new Error(`GitHub returned ${response.status} for the file tree of ${source}.`);
|
|
158
|
+
}
|
|
159
|
+
const body = await response.json();
|
|
160
|
+
if (!isRecord(body) || !Array.isArray(body.tree)) throw new Error(`GitHub returned an unexpected file tree for ${source}.`);
|
|
161
|
+
if (body.truncated === true) throw new Error(`GitHub truncated the file tree of ${source}.`);
|
|
162
|
+
return body.tree.filter(isTreeEntry);
|
|
163
|
+
};
|
|
164
|
+
/** The files the skills CLI hashes: regular files, outside `.git` and `node_modules`. */
|
|
165
|
+
const folderFiles = (tree, folder) => tree.filter((entry) => {
|
|
166
|
+
if (entry.type !== "blob" || entry.mode === "120000") return false;
|
|
167
|
+
if (!entry.path.startsWith(`${folder}/`)) return false;
|
|
168
|
+
const dirs = entry.path.slice(folder.length + 1).split("/").slice(0, -1);
|
|
169
|
+
return !dirs.includes(".git") && !dirs.includes("node_modules");
|
|
170
|
+
});
|
|
171
|
+
const fetchContentHash = async (source, folder, tree) => {
|
|
172
|
+
const files = await Promise.all(folderFiles(tree, folder).map(async (entry) => {
|
|
173
|
+
const path = entry.path.split("/").map(encodeURIComponent).join("/");
|
|
174
|
+
const response = await fetch(`https://raw.githubusercontent.com/${source}/HEAD/${path}`, { signal: AbortSignal.timeout(FETCH_TIMEOUT_MS) });
|
|
175
|
+
if (!response.ok) throw new Error(`GitHub returned ${response.status} for ${entry.path} in ${source}.`);
|
|
176
|
+
const bytes = new Uint8Array(await response.arrayBuffer());
|
|
177
|
+
if (gitBlobSha(bytes) !== entry.sha) throw new Error(`${source} changed during the check. Retry.`);
|
|
178
|
+
return {
|
|
179
|
+
path: entry.path.slice(folder.length + 1),
|
|
180
|
+
bytes
|
|
181
|
+
};
|
|
182
|
+
}));
|
|
183
|
+
return skillContentHash(files);
|
|
184
|
+
};
|
|
185
|
+
/**
|
|
186
|
+
* The folders to fetch: the given skills, plus every folder already in the cache so
|
|
187
|
+
* results for other directories stay current.
|
|
188
|
+
*/
|
|
189
|
+
const folderRequests = (skills, previous) => {
|
|
190
|
+
const requests = /* @__PURE__ */ new Map();
|
|
191
|
+
const add = (request) => {
|
|
192
|
+
const key = folderKey(request);
|
|
193
|
+
const existing = requests.get(key);
|
|
194
|
+
requests.set(key, {
|
|
195
|
+
...request,
|
|
196
|
+
content: request.content || existing?.content === true
|
|
197
|
+
});
|
|
198
|
+
};
|
|
199
|
+
for (const [key, remote] of Object.entries(previous)) {
|
|
200
|
+
const split = key.lastIndexOf(":");
|
|
201
|
+
const source = key.slice(0, split);
|
|
202
|
+
if (split <= 0 || !NEON_SOURCES.has(source)) continue;
|
|
203
|
+
add({
|
|
204
|
+
source,
|
|
205
|
+
folder: key.slice(split + 1),
|
|
206
|
+
content: remote.content !== void 0
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
for (const skill of skills) add({
|
|
210
|
+
source: skill.source,
|
|
211
|
+
folder: skill.folder,
|
|
212
|
+
content: skill.hashKind === "content"
|
|
213
|
+
});
|
|
214
|
+
return [...requests.values()];
|
|
215
|
+
};
|
|
216
|
+
/**
|
|
217
|
+
* Fetches the default-branch state of every requested skill folder and writes it to the
|
|
218
|
+
* cache. File contents are downloaded only for folders whose tree changed since the cache.
|
|
219
|
+
*/
|
|
220
|
+
const refreshSkillsCheckCache = async ({ cachePath, skills, env = process.env, now = Date.now() }) => {
|
|
221
|
+
const previous = readSkillsCheckCache(cachePath)?.folders ?? {};
|
|
222
|
+
const requests = folderRequests(skills, previous);
|
|
223
|
+
const folders = {};
|
|
224
|
+
for (const source of new Set(requests.map((request) => request.source))) {
|
|
225
|
+
const tree = await fetchTree(source, env);
|
|
226
|
+
for (const request of requests) {
|
|
227
|
+
if (request.source !== source) continue;
|
|
228
|
+
const key = folderKey(request);
|
|
229
|
+
const node = tree.find((entry) => entry.type === "tree" && entry.path === request.folder);
|
|
230
|
+
if (node === void 0) {
|
|
231
|
+
folders[key] = { missing: true };
|
|
232
|
+
continue;
|
|
233
|
+
}
|
|
234
|
+
const prior = previous[key];
|
|
235
|
+
let content = prior?.tree === node.sha ? prior.content : void 0;
|
|
236
|
+
if (request.content && content === void 0) content = await fetchContentHash(source, request.folder, tree);
|
|
237
|
+
folders[key] = {
|
|
238
|
+
tree: node.sha,
|
|
239
|
+
...content === void 0 ? {} : { content }
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
writeJsonFile(cachePath, {
|
|
244
|
+
checkedAt: now,
|
|
245
|
+
folders
|
|
246
|
+
}, "skills check cache");
|
|
247
|
+
return folders;
|
|
248
|
+
};
|
|
249
|
+
const skillsStatusRows = (skills, folders) => skills.map((skill) => {
|
|
250
|
+
const status = skillStatus(skill, folders[folderKey(skill)]);
|
|
251
|
+
if (status === void 0) throw new Error(`No result for ${skill.skill} from ${skill.source}. Retry the check.`);
|
|
252
|
+
return {
|
|
253
|
+
scope: scopeLabel(skill.scope),
|
|
254
|
+
skill: skill.skill,
|
|
255
|
+
status
|
|
256
|
+
};
|
|
257
|
+
});
|
|
258
|
+
const formatSkillsNotice = (outdated) => {
|
|
259
|
+
if (outdated.length === 0) return void 0;
|
|
260
|
+
const scopes = ["global", "project"].filter((scope) => outdated.some((skill) => skill.scope === scope));
|
|
261
|
+
return [
|
|
262
|
+
"Neon agent skills have updates:",
|
|
263
|
+
...scopes.map((scope) => ` ${scopeLabel(scope)}: ${outdated.filter((skill) => skill.scope === scope).map((skill) => skill.skill).join(", ")}`),
|
|
264
|
+
"Update them:",
|
|
265
|
+
...scopes.map((scope) => ` ${neonSkillsUpdateCommand(scope)}`)
|
|
266
|
+
].join("\n");
|
|
267
|
+
};
|
|
268
|
+
/**
|
|
269
|
+
* `pending` folders are left alone until the next daily check. A lock written after the last
|
|
270
|
+
* check (an install or an update) holds back the warning and checks every skill again,
|
|
271
|
+
* because the cache can be older than what was just installed.
|
|
272
|
+
*/
|
|
273
|
+
const planSkillsCheck = ({ skills, cache, lockModifiedAt, now }) => {
|
|
274
|
+
const remote = (skill) => cache?.folders[folderKey(skill)];
|
|
275
|
+
const settled = (skill) => remote(skill)?.pending !== true;
|
|
276
|
+
const lockChanged = cache !== void 0 && lockModifiedAt > cache.checkedAt;
|
|
277
|
+
const outdated = lockChanged ? [] : skills.filter((skill) => settled(skill) && skillStatus(skill, remote(skill)) === "outdated");
|
|
278
|
+
const toCheck = skills.filter((skill) => settled(skill) && (lockChanged || skillStatus(skill, remote(skill)) === void 0));
|
|
279
|
+
return {
|
|
280
|
+
outdated,
|
|
281
|
+
toCheck,
|
|
282
|
+
refresh: cache === void 0 || toCheck.length > 0 || now - (cache.attemptedAt ?? cache.checkedAt) >= DAY_MS
|
|
283
|
+
};
|
|
284
|
+
};
|
|
285
|
+
const spawnSkillsCheckWorker = (cachePath, cwd) => {
|
|
286
|
+
const workerPath = fileURLToPath(new URL("./check_worker.js", import.meta.url));
|
|
287
|
+
if (!existsSync(workerPath)) return;
|
|
288
|
+
try {
|
|
289
|
+
const child = spawn(process.execPath, [
|
|
290
|
+
workerPath,
|
|
291
|
+
cachePath,
|
|
292
|
+
cwd
|
|
293
|
+
], {
|
|
294
|
+
detached: true,
|
|
295
|
+
stdio: "ignore",
|
|
296
|
+
windowsHide: true
|
|
297
|
+
});
|
|
298
|
+
child.on("error", (error) => {
|
|
299
|
+
log.debug("Skills check failed to start: %s", error.message);
|
|
300
|
+
});
|
|
301
|
+
child.unref();
|
|
302
|
+
} catch (error) {
|
|
303
|
+
log.debug("Could not start the skills check: %s", error instanceof Error ? error.message : String(error));
|
|
304
|
+
}
|
|
305
|
+
};
|
|
306
|
+
/**
|
|
307
|
+
* Warns at most once a day when a Neon skill in the user-level lock or this directory's
|
|
308
|
+
* `skills-lock.json` is behind its source, from a cache a background worker refreshes daily.
|
|
309
|
+
*/
|
|
310
|
+
const notifyIfSkillsOutdated = ({ configDir, cwd, now = Date.now() }) => {
|
|
311
|
+
const lockPaths = [globalLockPath(), projectLockPath(cwd)];
|
|
312
|
+
let skills;
|
|
313
|
+
try {
|
|
314
|
+
skills = [...readLockedSkills(lockPaths[0], "global"), ...readLockedSkills(lockPaths[1], "project")];
|
|
315
|
+
} catch (error) {
|
|
316
|
+
log.debug("Skipping the skills check: %s", error instanceof Error ? error.message : String(error));
|
|
317
|
+
return;
|
|
318
|
+
}
|
|
319
|
+
if (skills.length === 0) return;
|
|
320
|
+
const cachePath = skillsCheckCachePath(configDir);
|
|
321
|
+
const cache = readSkillsCheckCache(cachePath);
|
|
322
|
+
const plan = planSkillsCheck({
|
|
323
|
+
skills,
|
|
324
|
+
cache,
|
|
325
|
+
lockModifiedAt: Math.max(...lockPaths.map((path) => statSync(path, { throwIfNoEntry: false })?.mtimeMs ?? 0)),
|
|
326
|
+
now
|
|
327
|
+
});
|
|
328
|
+
const notice = formatSkillsNotice(plan.outdated);
|
|
329
|
+
if (notice !== void 0) showNotice({
|
|
330
|
+
configDir,
|
|
331
|
+
id: "skills",
|
|
332
|
+
intervalMs: DAY_MS,
|
|
333
|
+
message: notice,
|
|
334
|
+
now
|
|
335
|
+
});
|
|
336
|
+
if (!plan.refresh) return;
|
|
337
|
+
const folders = { ...cache?.folders };
|
|
338
|
+
for (const skill of plan.toCheck) folders[folderKey(skill)] = {
|
|
339
|
+
...folders[folderKey(skill)],
|
|
340
|
+
pending: true
|
|
341
|
+
};
|
|
342
|
+
if (writeJsonFile(cachePath, {
|
|
343
|
+
checkedAt: cache?.checkedAt ?? 0,
|
|
344
|
+
attemptedAt: now,
|
|
345
|
+
folders
|
|
346
|
+
}, "skills check cache")) spawnSkillsCheckWorker(cachePath, cwd);
|
|
347
|
+
};
|
|
348
|
+
//#endregion
|
|
349
|
+
export { formatSkillsNotice, globalLockPath, lockPath, neonSkillsUpdateCommand, notifyIfSkillsOutdated, parseSkillsCheckCache, parseSkillsLock, planSkillsCheck, projectLockPath, readLockedSkills, refreshSkillsCheckCache, scopeLabel, skillContentHash, skillStatus, skillsCheckCachePath, skillsStatusRows };
|
package/dist/skills/run.js
CHANGED
|
@@ -59,7 +59,6 @@ const neonSkillsRetryCommand = (options) => {
|
|
|
59
59
|
args.push("-y");
|
|
60
60
|
return `neon ${args.map(quoteNpxArg).join(" ")}`;
|
|
61
61
|
};
|
|
62
|
-
const neonSkillsUpdateRetryCommand = (global) => global ? "neon skills update --global -y" : "neon skills update -y";
|
|
63
62
|
const quoteNpxArg = (part) => /[\s"'\\*]/.test(part) ? `'${part.replace(/'/g, `'\\''`)}'` : part;
|
|
64
63
|
const npxCommand = (args) => `npx ${args.map(quoteNpxArg).join(" ")}`;
|
|
65
64
|
const ANSI = /\u001b\[[0-9;]*[A-Za-z]/g;
|
|
@@ -116,4 +115,4 @@ const runSkillsCli = async (options) => {
|
|
|
116
115
|
const isCommandMissing = (error) => typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
|
|
117
116
|
const isExecaFailure = (error) => typeof error === "object" && error !== null && "shortMessage" in error && typeof error.shortMessage === "string";
|
|
118
117
|
//#endregion
|
|
119
|
-
export { SKILLS_MIN_NODE, assertSkillsNode, neonSkillsRetryCommand,
|
|
118
|
+
export { SKILLS_MIN_NODE, assertSkillsNode, neonSkillsRetryCommand, nodeMeetsMinimum, npxCommand, quoteNpxArg, runSkillsCli, skillsAddArgs, skillsChildEnv, skillsMetadata, skillsUpdateArgs, skillsUpdateDetail, skillsUpdateHadNothing };
|
package/dist/update_notifier.js
CHANGED
|
@@ -145,6 +145,20 @@ const shouldRunUpdateNotifier = ({ commandPath, currentBranch, disabled, isCi: r
|
|
|
145
145
|
commandPath,
|
|
146
146
|
currentBranch
|
|
147
147
|
});
|
|
148
|
+
/**
|
|
149
|
+
* The skills notice drops the terminal checks: coding agents run the CLI without a TTY,
|
|
150
|
+
* and they are the ones that act on it. `neon skills` itself reports skill state.
|
|
151
|
+
*/
|
|
152
|
+
const shouldRunSkillsNotifier = ({ commandPath, currentBranch, output }) => commandPath[0] !== "skills" && commandPath[0] !== "skill" && shouldRunUpdateNotifier({
|
|
153
|
+
commandPath,
|
|
154
|
+
currentBranch,
|
|
155
|
+
disabled: "NO_UPDATE_NOTIFIER" in process.env,
|
|
156
|
+
isCi: isCi(),
|
|
157
|
+
isPackaged: isPackagedExecutable(),
|
|
158
|
+
output,
|
|
159
|
+
stderrIsTty: true,
|
|
160
|
+
stdoutIsTty: true
|
|
161
|
+
});
|
|
148
162
|
const notifyIfUpdateAvailable = ({ commandPath, configDir, currentBranch, currentVersion, output }) => {
|
|
149
163
|
if (!shouldRunUpdateNotifier({
|
|
150
164
|
commandPath,
|
|
@@ -204,4 +218,4 @@ const recordLatestVersion = (cachePath, source, latestVersion) => {
|
|
|
204
218
|
});
|
|
205
219
|
};
|
|
206
220
|
//#endregion
|
|
207
|
-
export { cacheForUpdateSource, findCliInstalls, formatDuplicateInstallNotice, formatUpdateNotice, notifyIfUpdateAvailable, parseUpdateCheckCache, recordLatestVersion, shouldRefreshUpdateCheck, shouldRunUpdateNotifier, spawnUpdateWorkerProcess, writeUpdateCheckCache };
|
|
221
|
+
export { cacheForUpdateSource, findCliInstalls, formatDuplicateInstallNotice, formatUpdateNotice, notifyIfUpdateAvailable, parseUpdateCheckCache, recordLatestVersion, shouldRefreshUpdateCheck, shouldRunSkillsNotifier, shouldRunUpdateNotifier, spawnUpdateWorkerProcess, writeUpdateCheckCache };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "neon",
|
|
3
|
-
"version": "8.
|
|
3
|
+
"version": "8.12.0",
|
|
4
4
|
"description": "CLI tool for Neon, the cloud backend primitives built around Lakebase Postgres",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"neon",
|
|
@@ -73,8 +73,8 @@
|
|
|
73
73
|
"yargs": "17.7.2",
|
|
74
74
|
"yoctocolors": "^2.1.2",
|
|
75
75
|
"@neon/config": "1.9.4",
|
|
76
|
-
"@neon/realtime": "0.1.2",
|
|
77
76
|
"@neon/config-runtime": "1.10.3",
|
|
77
|
+
"@neon/realtime": "0.1.2",
|
|
78
78
|
"@neon/sdk": "7.5.0"
|
|
79
79
|
},
|
|
80
80
|
"optionalDependencies": {
|
|
@@ -98,7 +98,7 @@
|
|
|
98
98
|
"@types/which": "3.0.4",
|
|
99
99
|
"@types/yargs": "^17.0.35",
|
|
100
100
|
"@vitest/coverage-v8": "^3.0.9",
|
|
101
|
-
"@yao-pkg/pkg": "6.
|
|
101
|
+
"@yao-pkg/pkg": "6.23.0",
|
|
102
102
|
"emocks": "3.0.4",
|
|
103
103
|
"express": "4.19.2",
|
|
104
104
|
"hono": "^4.12.25",
|
|
@@ -111,11 +111,11 @@
|
|
|
111
111
|
"tsx": "4.22.3",
|
|
112
112
|
"typescript": "^5.9.0",
|
|
113
113
|
"vitest": "^3.0.9",
|
|
114
|
-
"@neon-internals/cli-core": "0.0.0",
|
|
115
114
|
"@neon-internals/env-core": "0.0.35",
|
|
115
|
+
"@neon/e2e-harness": "0.0.0",
|
|
116
116
|
"@neon/env": "1.6.5",
|
|
117
|
-
"@neon/
|
|
118
|
-
"@neon/
|
|
117
|
+
"@neon-internals/cli-core": "0.0.0",
|
|
118
|
+
"@neon/functions": "0.11.0"
|
|
119
119
|
},
|
|
120
120
|
"publishConfig": {
|
|
121
121
|
"access": "public",
|
|
@@ -7,9 +7,9 @@ import { deprecatedServiceMessage, parseServices, servicesFlagValue, servicesOpt
|
|
|
7
7
|
import { mergeEnvFile, readEnvFile, resolveEnvFilePath } from "../env_file.js";
|
|
8
8
|
import { t as NEON_ENV_VAR_KEYS, u as isFunctionBaseUrlKey } from "./env-BpP3Dqpe.js";
|
|
9
9
|
import { ENV_PULL_KEY_HELP, ENV_PULL_SERVICES, envKeysForSelection, envPullFlagValue, ownedEnvServiceKeys, parseEnvPullKeys } from "../env_services.js";
|
|
10
|
+
import { i as dropClaimableUnsupported, o as resolveNeonEnvVars } from "./env-BNm69Qh8.js";
|
|
10
11
|
import { fillSingleProject, resolveBranchRef } from "../utils/enrichers.js";
|
|
11
12
|
import { warnAiGateway } from "../utils/ai_gateway_notice.js";
|
|
12
|
-
import { i as dropClaimableUnsupported, o as resolveNeonEnvVars } from "./env-BNm69Qh8.js";
|
|
13
13
|
import { formatPulledEnv, pulledBranch } from "../commands/env_output.js";
|
|
14
14
|
import { existsSync } from "node:fs";
|
|
15
15
|
import chalk from "chalk";
|