@arkveil/cli 1.1.0 → 1.2.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/dist/index.js +250 -5
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -5413,9 +5413,9 @@ var require_src = __commonJS({
|
|
|
5413
5413
|
});
|
|
5414
5414
|
|
|
5415
5415
|
// src/index.ts
|
|
5416
|
-
import { readFileSync as
|
|
5417
|
-
import { fileURLToPath as
|
|
5418
|
-
import { dirname, join as
|
|
5416
|
+
import { readFileSync as readFileSync5 } from "fs";
|
|
5417
|
+
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
5418
|
+
import { dirname as dirname2, join as join3 } from "path";
|
|
5419
5419
|
|
|
5420
5420
|
// node_modules/.pnpm/commander@12.1.0/node_modules/commander/esm.mjs
|
|
5421
5421
|
var import_index = __toESM(require_commander(), 1);
|
|
@@ -14954,12 +14954,255 @@ function registerAdmin(program2) {
|
|
|
14954
14954
|
});
|
|
14955
14955
|
}
|
|
14956
14956
|
|
|
14957
|
+
// src/commands/update/update.ts
|
|
14958
|
+
import { execFile as execFile6 } from "child_process";
|
|
14959
|
+
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
14960
|
+
|
|
14961
|
+
// src/commands/update/npm.ts
|
|
14962
|
+
import { existsSync, readFileSync as readFileSync4 } from "fs";
|
|
14963
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
14964
|
+
import { dirname, join as join2, parse } from "path";
|
|
14965
|
+
function readPackageMeta() {
|
|
14966
|
+
let dir = dirname(fileURLToPath2(import.meta.url));
|
|
14967
|
+
const { root } = parse(dir);
|
|
14968
|
+
while (true) {
|
|
14969
|
+
const candidate = join2(dir, "package.json");
|
|
14970
|
+
if (existsSync(candidate)) {
|
|
14971
|
+
const pkg = JSON.parse(readFileSync4(candidate, "utf8"));
|
|
14972
|
+
return { name: pkg.name ?? "@arkveil/cli", version: pkg.version ?? "0.0.0" };
|
|
14973
|
+
}
|
|
14974
|
+
if (dir === root) break;
|
|
14975
|
+
dir = dirname(dir);
|
|
14976
|
+
}
|
|
14977
|
+
return { name: "@arkveil/cli", version: "0.0.0" };
|
|
14978
|
+
}
|
|
14979
|
+
function parseSemver(version) {
|
|
14980
|
+
const cleaned = version.trim().replace(/^v/, "");
|
|
14981
|
+
const [main3 = "", pre = null] = cleaned.split("-", 2);
|
|
14982
|
+
const core = main3.split(".").map((p) => Number.parseInt(p, 10) || 0);
|
|
14983
|
+
while (core.length < 3) core.push(0);
|
|
14984
|
+
return { core: core.slice(0, 3), pre: pre ?? null };
|
|
14985
|
+
}
|
|
14986
|
+
function compareSemver(a3, b3) {
|
|
14987
|
+
const pa = parseSemver(a3);
|
|
14988
|
+
const pb = parseSemver(b3);
|
|
14989
|
+
for (let i = 0; i < 3; i++) {
|
|
14990
|
+
const diff = (pa.core[i] ?? 0) - (pb.core[i] ?? 0);
|
|
14991
|
+
if (diff !== 0) return diff < 0 ? -1 : 1;
|
|
14992
|
+
}
|
|
14993
|
+
if (pa.pre === pb.pre) return 0;
|
|
14994
|
+
if (pa.pre === null) return 1;
|
|
14995
|
+
if (pb.pre === null) return -1;
|
|
14996
|
+
return pa.pre < pb.pre ? -1 : 1;
|
|
14997
|
+
}
|
|
14998
|
+
var PACKAGE_MANAGERS = ["pnpm", "yarn", "bun", "npm"];
|
|
14999
|
+
function detectPackageManager(modulePath, env2 = process.env) {
|
|
15000
|
+
const path2 = modulePath.toLowerCase();
|
|
15001
|
+
if (path2.includes("pnpm")) return "pnpm";
|
|
15002
|
+
if (path2.includes(`${"/"}.bun${"/"}`) || path2.includes("/bun/")) return "bun";
|
|
15003
|
+
if (path2.includes(".yarn") || path2.includes("/yarn/")) return "yarn";
|
|
15004
|
+
const agent = (env2.npm_config_user_agent ?? "").toLowerCase();
|
|
15005
|
+
const fromAgent = PACKAGE_MANAGERS.find((pm) => agent.startsWith(pm));
|
|
15006
|
+
if (fromAgent) return fromAgent;
|
|
15007
|
+
return "npm";
|
|
15008
|
+
}
|
|
15009
|
+
function installCommand(pm, spec) {
|
|
15010
|
+
switch (pm) {
|
|
15011
|
+
case "pnpm":
|
|
15012
|
+
return { cmd: "pnpm", args: ["add", "-g", spec] };
|
|
15013
|
+
case "yarn":
|
|
15014
|
+
return { cmd: "yarn", args: ["global", "add", spec] };
|
|
15015
|
+
case "bun":
|
|
15016
|
+
return { cmd: "bun", args: ["add", "-g", spec] };
|
|
15017
|
+
case "npm":
|
|
15018
|
+
default:
|
|
15019
|
+
return { cmd: "npm", args: ["install", "-g", spec] };
|
|
15020
|
+
}
|
|
15021
|
+
}
|
|
15022
|
+
async function fetchLatestVersion(opts) {
|
|
15023
|
+
const tag = opts.tag ?? "latest";
|
|
15024
|
+
const registry = (opts.registry ?? "https://registry.npmjs.org").replace(/\/+$/, "");
|
|
15025
|
+
const encoded = opts.name.replace("/", "%2f");
|
|
15026
|
+
const url = `${registry}/${encoded}/${tag}`;
|
|
15027
|
+
const controller = new AbortController();
|
|
15028
|
+
const timer = setTimeout(() => controller.abort(), opts.timeoutMs ?? 1e4);
|
|
15029
|
+
try {
|
|
15030
|
+
const res = await fetch(url, {
|
|
15031
|
+
headers: { accept: "application/json" },
|
|
15032
|
+
signal: controller.signal
|
|
15033
|
+
});
|
|
15034
|
+
if (!res.ok) {
|
|
15035
|
+
throw new NetworkError(
|
|
15036
|
+
`npm registry returned ${res.status} for ${opts.name}@${tag}.`,
|
|
15037
|
+
"Check your network connection and that the package/tag exists."
|
|
15038
|
+
);
|
|
15039
|
+
}
|
|
15040
|
+
const body = await res.json();
|
|
15041
|
+
if (!body.version) {
|
|
15042
|
+
throw new NetworkError(
|
|
15043
|
+
`npm registry response for ${opts.name}@${tag} had no version.`
|
|
15044
|
+
);
|
|
15045
|
+
}
|
|
15046
|
+
return body.version;
|
|
15047
|
+
} catch (err) {
|
|
15048
|
+
if (err instanceof NetworkError) throw err;
|
|
15049
|
+
if (err instanceof Error && err.name === "AbortError") {
|
|
15050
|
+
throw new NetworkError(
|
|
15051
|
+
`Timed out contacting the npm registry for ${opts.name}@${tag}.`,
|
|
15052
|
+
"Retry, or increase the timeout with --timeout <ms>.",
|
|
15053
|
+
err
|
|
15054
|
+
);
|
|
15055
|
+
}
|
|
15056
|
+
throw new NetworkError(
|
|
15057
|
+
`Could not reach the npm registry: ${err instanceof Error ? err.message : String(err)}`,
|
|
15058
|
+
"Check your network connection.",
|
|
15059
|
+
err
|
|
15060
|
+
);
|
|
15061
|
+
} finally {
|
|
15062
|
+
clearTimeout(timer);
|
|
15063
|
+
}
|
|
15064
|
+
}
|
|
15065
|
+
|
|
15066
|
+
// src/commands/update/update.ts
|
|
15067
|
+
var VALID_PMS = ["npm", "pnpm", "yarn", "bun"];
|
|
15068
|
+
async function selfUpdate(ctx, options) {
|
|
15069
|
+
const { out, config } = ctx;
|
|
15070
|
+
const meta = readPackageMeta();
|
|
15071
|
+
const tag = options.tag ?? "latest";
|
|
15072
|
+
if (options.use && !VALID_PMS.includes(options.use)) {
|
|
15073
|
+
throw new CliError(`Unknown package manager "${options.use}".`, {
|
|
15074
|
+
exitCode: ExitCode.Usage,
|
|
15075
|
+
hint: `Choose one of: ${VALID_PMS.join(", ")}.`
|
|
15076
|
+
});
|
|
15077
|
+
}
|
|
15078
|
+
const spinner = out.spinner(`Checking npm for ${meta.name}@${tag}\u2026`);
|
|
15079
|
+
let latest;
|
|
15080
|
+
try {
|
|
15081
|
+
latest = await fetchLatestVersion({
|
|
15082
|
+
name: meta.name,
|
|
15083
|
+
tag,
|
|
15084
|
+
timeoutMs: config.timeoutMs
|
|
15085
|
+
});
|
|
15086
|
+
spinner.stop();
|
|
15087
|
+
} catch (err) {
|
|
15088
|
+
spinner.fail("Could not check for updates.");
|
|
15089
|
+
throw err;
|
|
15090
|
+
}
|
|
15091
|
+
const cmp = compareSemver(meta.version, latest);
|
|
15092
|
+
const upToDate = cmp >= 0;
|
|
15093
|
+
const willUpdate = !upToDate || Boolean(options.force);
|
|
15094
|
+
const pm = options.use ?? detectPackageManager(fileURLToPath3(import.meta.url));
|
|
15095
|
+
const spec = `${meta.name}@${tag}`;
|
|
15096
|
+
const { cmd, args } = installCommand(pm, spec);
|
|
15097
|
+
const commandLine = `${cmd} ${args.join(" ")}`;
|
|
15098
|
+
if (options.check || options.dryRun || !willUpdate) {
|
|
15099
|
+
out.data(
|
|
15100
|
+
{
|
|
15101
|
+
name: meta.name,
|
|
15102
|
+
current: meta.version,
|
|
15103
|
+
latest,
|
|
15104
|
+
tag,
|
|
15105
|
+
updateAvailable: !upToDate,
|
|
15106
|
+
upToDate,
|
|
15107
|
+
packageManager: pm,
|
|
15108
|
+
command: commandLine,
|
|
15109
|
+
action: options.dryRun ? "dry-run" : options.check ? "check" : "none"
|
|
15110
|
+
},
|
|
15111
|
+
(o2) => {
|
|
15112
|
+
if (upToDate) {
|
|
15113
|
+
return `${o2.c.green("\u2714")} ${meta.name} is up to date (${meta.version}).`;
|
|
15114
|
+
}
|
|
15115
|
+
const lines = [
|
|
15116
|
+
`${o2.c.yellow("!")} Update available: ${o2.c.dim(meta.version)} \u2192 ${o2.c.green(latest)}`
|
|
15117
|
+
];
|
|
15118
|
+
if (options.dryRun) {
|
|
15119
|
+
lines.push(` Would run: ${o2.c.cyan(commandLine)}`);
|
|
15120
|
+
} else {
|
|
15121
|
+
lines.push(` Run ${o2.c.cyan("arkveil update")} to upgrade (uses: ${o2.c.cyan(commandLine)}).`);
|
|
15122
|
+
}
|
|
15123
|
+
return lines.join("\n");
|
|
15124
|
+
}
|
|
15125
|
+
);
|
|
15126
|
+
return;
|
|
15127
|
+
}
|
|
15128
|
+
const label = upToDate ? `Reinstalling ${spec}\u2026` : `Updating ${meta.name} ${meta.version} \u2192 ${latest}\u2026`;
|
|
15129
|
+
out.verbose(`Running: ${commandLine}`);
|
|
15130
|
+
const install = out.spinner(label);
|
|
15131
|
+
try {
|
|
15132
|
+
await runInstall(cmd, args);
|
|
15133
|
+
install.succeed(`Updated to ${latest}. Run \`arkveil --version\` to confirm.`);
|
|
15134
|
+
} catch (err) {
|
|
15135
|
+
install.fail("Update failed.");
|
|
15136
|
+
throw toInstallError(err, pm, commandLine);
|
|
15137
|
+
}
|
|
15138
|
+
out.data(
|
|
15139
|
+
{
|
|
15140
|
+
name: meta.name,
|
|
15141
|
+
previous: meta.version,
|
|
15142
|
+
latest,
|
|
15143
|
+
tag,
|
|
15144
|
+
packageManager: pm,
|
|
15145
|
+
command: commandLine,
|
|
15146
|
+
action: "updated"
|
|
15147
|
+
},
|
|
15148
|
+
() => {
|
|
15149
|
+
}
|
|
15150
|
+
);
|
|
15151
|
+
}
|
|
15152
|
+
function runInstall(cmd, args) {
|
|
15153
|
+
return new Promise((resolve2, reject) => {
|
|
15154
|
+
execFile6(cmd, args, { timeout: 12e4 }, (err) => {
|
|
15155
|
+
if (err) reject(err);
|
|
15156
|
+
else resolve2();
|
|
15157
|
+
});
|
|
15158
|
+
});
|
|
15159
|
+
}
|
|
15160
|
+
function toInstallError(err, pm, commandLine) {
|
|
15161
|
+
const e2 = err;
|
|
15162
|
+
if (e2?.code === "ENOENT") {
|
|
15163
|
+
return new CliError(`${pm} was not found on your PATH.`, {
|
|
15164
|
+
exitCode: ExitCode.Generic,
|
|
15165
|
+
hint: `Install ${pm}, or pass --use <npm|pnpm|yarn|bun> to pick another package manager.`,
|
|
15166
|
+
cause: err
|
|
15167
|
+
});
|
|
15168
|
+
}
|
|
15169
|
+
const detail = (e2?.stderr ?? e2?.message ?? String(err)).trim().split("\n").slice(-3).join(" ");
|
|
15170
|
+
return new CliError(`Upgrade command failed: ${detail || commandLine}`, {
|
|
15171
|
+
exitCode: ExitCode.Generic,
|
|
15172
|
+
hint: `Try running it yourself: ${commandLine}. A global install may require elevated permissions (sudo).`,
|
|
15173
|
+
cause: err
|
|
15174
|
+
});
|
|
15175
|
+
}
|
|
15176
|
+
|
|
15177
|
+
// src/commands/update/index.ts
|
|
15178
|
+
function registerUpdate(program2) {
|
|
15179
|
+
program2.command("update").aliases(["upgrade", "self-update"]).description("Update the Arkveil CLI to the latest published version").option("--check", "only report whether an update is available; don't install").option("--dry-run", "print the install command that would run, without executing it").option("--tag <tag>", "npm dist-tag to install (default latest)", "latest").option("--use <pm>", "package manager to use: npm, pnpm, yarn, or bun").option("--force", "reinstall even if already on the target version").addHelpText(
|
|
15180
|
+
"after",
|
|
15181
|
+
`
|
|
15182
|
+
Checks the npm registry for a newer release of the CLI and upgrades this install
|
|
15183
|
+
in place using the package manager that installed it (auto-detected; override
|
|
15184
|
+
with --use). Use --check in scripts/CI to detect a pending update via the exit
|
|
15185
|
+
output without changing anything.
|
|
15186
|
+
|
|
15187
|
+
Examples:
|
|
15188
|
+
$ arkveil update # upgrade to the latest release
|
|
15189
|
+
$ arkveil update --check # is a newer version available?
|
|
15190
|
+
$ arkveil update --dry-run # show the command without running it
|
|
15191
|
+
$ arkveil update --tag next # install the "next" dist-tag
|
|
15192
|
+
$ arkveil update --use pnpm # force pnpm for the global install
|
|
15193
|
+
$ arkveil update --json # machine-readable result
|
|
15194
|
+
`
|
|
15195
|
+
).action(async (options, command) => {
|
|
15196
|
+
await run(command, (ctx) => selfUpdate(ctx, options));
|
|
15197
|
+
});
|
|
15198
|
+
}
|
|
15199
|
+
|
|
14957
15200
|
// src/index.ts
|
|
14958
15201
|
function readVersion() {
|
|
14959
15202
|
try {
|
|
14960
|
-
const here =
|
|
15203
|
+
const here = dirname2(fileURLToPath4(import.meta.url));
|
|
14961
15204
|
const pkg = JSON.parse(
|
|
14962
|
-
|
|
15205
|
+
readFileSync5(join3(here, "..", "package.json"), "utf8")
|
|
14963
15206
|
);
|
|
14964
15207
|
return pkg.version ?? "0.0.0";
|
|
14965
15208
|
} catch {
|
|
@@ -14993,6 +15236,7 @@ function buildProgram() {
|
|
|
14993
15236
|
registerEval(program2);
|
|
14994
15237
|
registerAbac(program2);
|
|
14995
15238
|
registerAdmin(program2);
|
|
15239
|
+
registerUpdate(program2);
|
|
14996
15240
|
program2.addHelpText(
|
|
14997
15241
|
"after",
|
|
14998
15242
|
`
|
|
@@ -15002,6 +15246,7 @@ Examples:
|
|
|
15002
15246
|
$ arkveil tags list --json List tags as JSON
|
|
15003
15247
|
$ arkveil trees forest Show the full navigation forest
|
|
15004
15248
|
$ arkveil sdk info How to install & use the SDK
|
|
15249
|
+
$ arkveil update Update the CLI to the latest release
|
|
15005
15250
|
$ arkveil formula syntax Print the formula DSL reference
|
|
15006
15251
|
$ arkveil eval explain -a orders:read \\
|
|
15007
15252
|
--user '{"role":"admin"}' --context '{}' Explain an access decision
|