@theholocron/cli 3.1.1 → 3.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/cli.mjs +515 -440
- package/dist/cli.mjs.map +1 -0
- package/package.json +3 -1
package/dist/cli.mjs
CHANGED
|
@@ -1,4 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
(function() {
|
|
3
|
+
try {
|
|
4
|
+
var e = "undefined" != typeof window ? window : "undefined" != typeof global ? global : "undefined" != typeof globalThis ? globalThis : "undefined" != typeof self ? self : {};
|
|
5
|
+
e.SENTRY_RELEASE = { id: "holocron@3.1.1" };
|
|
6
|
+
var n = new e.Error().stack;
|
|
7
|
+
n && (e._sentryDebugIds = e._sentryDebugIds || {}, e._sentryDebugIds[n] = "9c44dac0-ac25-4e90-a623-6c67cc9d66a1", e._sentryDebugIdIdentifier = "sentry-dbid-9c44dac0-ac25-4e90-a623-6c67cc9d66a1");
|
|
8
|
+
} catch (e) {}
|
|
9
|
+
})();
|
|
2
10
|
import { createRequire } from "node:module";
|
|
3
11
|
import { existsSync, mkdirSync, readFileSync, readdirSync, statSync, writeFileSync } from "node:fs";
|
|
4
12
|
import path, { basename, dirname, join, relative, resolve } from "node:path";
|
|
@@ -17,6 +25,7 @@ import { access, copyFile, mkdir, readFile, readdir, rm, stat, symlink, unlink,
|
|
|
17
25
|
import { pathToFileURL } from "node:url";
|
|
18
26
|
import { createGitHubClient } from "@theholocron/github-client";
|
|
19
27
|
import { promisify } from "node:util";
|
|
28
|
+
import * as Sentry from "@sentry/node";
|
|
20
29
|
//#region src/env.ts
|
|
21
30
|
function createEnvLookup(source = process.env) {
|
|
22
31
|
return {
|
|
@@ -4477,6 +4486,58 @@ async function fileExists(path) {
|
|
|
4477
4486
|
}
|
|
4478
4487
|
}
|
|
4479
4488
|
//#endregion
|
|
4489
|
+
//#region src/telemetry.ts
|
|
4490
|
+
const DSN = "https://95cbb72ad5636c94e119a5405ee8f55f@o4508238154104832.ingest.us.sentry.io/4511810950791168";
|
|
4491
|
+
function isEnabled() {
|
|
4492
|
+
return !process.env.NO_HOLOCRON_TELEMETRY && true;
|
|
4493
|
+
}
|
|
4494
|
+
function init(version) {
|
|
4495
|
+
if (!isEnabled()) return;
|
|
4496
|
+
Sentry.init({
|
|
4497
|
+
dsn: DSN,
|
|
4498
|
+
release: `holocron@${version}`,
|
|
4499
|
+
environment: process.env.CI ? "ci" : "local",
|
|
4500
|
+
tracesSampleRate: 1,
|
|
4501
|
+
beforeSend: scrubError
|
|
4502
|
+
});
|
|
4503
|
+
Sentry.startSession();
|
|
4504
|
+
Sentry.setTag("os", process.platform);
|
|
4505
|
+
Sentry.setTag("node", process.version);
|
|
4506
|
+
Sentry.setTag("ci", String(Boolean(process.env.CI)));
|
|
4507
|
+
}
|
|
4508
|
+
function startCommand(name) {
|
|
4509
|
+
if (!isEnabled()) return () => {};
|
|
4510
|
+
Sentry.setTag("command", name);
|
|
4511
|
+
const span = Sentry.startInactiveSpan({
|
|
4512
|
+
name,
|
|
4513
|
+
op: "holocron.command",
|
|
4514
|
+
forceTransaction: true
|
|
4515
|
+
});
|
|
4516
|
+
return (ok) => {
|
|
4517
|
+
span.setStatus({ code: ok ? 1 : 2 });
|
|
4518
|
+
span.end();
|
|
4519
|
+
};
|
|
4520
|
+
}
|
|
4521
|
+
function captureException(err) {
|
|
4522
|
+
if (!isEnabled()) return;
|
|
4523
|
+
Sentry.captureException(err);
|
|
4524
|
+
}
|
|
4525
|
+
function endSession() {
|
|
4526
|
+
if (!isEnabled()) return;
|
|
4527
|
+
Sentry.endSession();
|
|
4528
|
+
}
|
|
4529
|
+
async function flush() {
|
|
4530
|
+
if (!isEnabled()) return;
|
|
4531
|
+
await Sentry.close(2e3);
|
|
4532
|
+
}
|
|
4533
|
+
const TOKEN_RE = /\b(ghp_|ghs_|glpat-|xoxb-|xoxp-|npm_|sk-|[A-Z][A-Z0-9_]{2,}_TOKEN[=\s])[^\s"]*/g;
|
|
4534
|
+
function redact(raw) {
|
|
4535
|
+
return raw.replace(TOKEN_RE, "[REDACTED]");
|
|
4536
|
+
}
|
|
4537
|
+
function scrubError(event, _hint) {
|
|
4538
|
+
return JSON.parse(redact(JSON.stringify(event)));
|
|
4539
|
+
}
|
|
4540
|
+
//#endregion
|
|
4480
4541
|
//#region src/token-args.ts
|
|
4481
4542
|
var TokenParseError = class extends Error {
|
|
4482
4543
|
name = "TokenParseError";
|
|
@@ -4651,463 +4712,475 @@ function tokenContext(rawTokens) {
|
|
|
4651
4712
|
throw err;
|
|
4652
4713
|
}
|
|
4653
4714
|
}
|
|
4715
|
+
init(CLI_VERSION);
|
|
4654
4716
|
const updateCheckPromise = checkForUpdates(CLI_VERSION);
|
|
4655
|
-
|
|
4656
|
-
|
|
4657
|
-
|
|
4658
|
-
|
|
4659
|
-
}).option("
|
|
4660
|
-
|
|
4661
|
-
|
|
4662
|
-
|
|
4663
|
-
}).option("
|
|
4664
|
-
|
|
4665
|
-
|
|
4666
|
-
|
|
4667
|
-
}).
|
|
4668
|
-
|
|
4669
|
-
|
|
4670
|
-
|
|
4671
|
-
|
|
4672
|
-
|
|
4673
|
-
}).option("
|
|
4674
|
-
|
|
4675
|
-
|
|
4676
|
-
|
|
4677
|
-
|
|
4678
|
-
|
|
4679
|
-
|
|
4680
|
-
|
|
4681
|
-
|
|
4682
|
-
|
|
4683
|
-
|
|
4684
|
-
|
|
4685
|
-
|
|
4686
|
-
|
|
4687
|
-
|
|
4688
|
-
|
|
4689
|
-
|
|
4690
|
-
dryRun: argv.dryRun,
|
|
4691
|
-
...argv.dir ? { dir: argv.dir } : {}
|
|
4692
|
-
})).status === "fail") process.exitCode = 1;
|
|
4693
|
-
}).command("doctor", "Load the config and run a smoke check against every provider", (y) => y.option("repo", {
|
|
4694
|
-
type: "string",
|
|
4695
|
-
describe: "Repo coords (\"owner/name\"). Defaults to plugin-specific resolution."
|
|
4696
|
-
}), async (argv) => {
|
|
4697
|
-
const tokens = tokenContext(argv.token);
|
|
4698
|
-
if (!tokens) return;
|
|
4699
|
-
if ((await runDoctor({
|
|
4700
|
-
loaded: await loadConfig(argv.cwd),
|
|
4701
|
-
context: {
|
|
4702
|
-
repoRoot: argv.cwd,
|
|
4703
|
-
dryRun: argv.dryRun,
|
|
4704
|
-
...argv.repo ? { repo: argv.repo } : {},
|
|
4705
|
-
...tokens
|
|
4717
|
+
let finishCommand = () => {};
|
|
4718
|
+
try {
|
|
4719
|
+
await yargs(hideBin(process.argv)).middleware((argv) => {
|
|
4720
|
+
finishCommand = startCommand(argv._.slice(0, 2).join(" ") || "unknown");
|
|
4721
|
+
}).scriptName("").usage("holocron <command> [options]").option("dry-run", {
|
|
4722
|
+
type: "boolean",
|
|
4723
|
+
default: false,
|
|
4724
|
+
describe: "Print what would be mutated without calling capability mutators. Commands branch on this; read-only commands ignore it."
|
|
4725
|
+
}).option("token", {
|
|
4726
|
+
type: "string",
|
|
4727
|
+
array: true,
|
|
4728
|
+
describe: "Vendor token override for plugins. Bare form: --token <value> (fallback for all plugins, single-plugin commands). Keyed form: --token vendor=value (targets a specific provider; repeat for each). Example: --token github=ghp_xxx --token vercel=v_yyy"
|
|
4729
|
+
}).option("cwd", {
|
|
4730
|
+
type: "string",
|
|
4731
|
+
default: process.cwd(),
|
|
4732
|
+
describe: "Directory to search for holocron.config.json"
|
|
4733
|
+
}).command("version", "Print the CLI version", () => {}, () => {
|
|
4734
|
+
console.log(`holocron ${CLI_VERSION}`);
|
|
4735
|
+
}).command("clone", "Clone all repos in a GitHub org as siblings under a single directory", (y) => y.option("org", {
|
|
4736
|
+
type: "string",
|
|
4737
|
+
demandOption: true,
|
|
4738
|
+
describe: "GitHub org to clone (e.g., theholocron)"
|
|
4739
|
+
}).option("dir", {
|
|
4740
|
+
type: "string",
|
|
4741
|
+
describe: "Parent directory to clone into (default: ~/Code/<org>)"
|
|
4742
|
+
}), async (argv) => {
|
|
4743
|
+
const tokens = tokenContext(argv.token);
|
|
4744
|
+
if (!tokens) return;
|
|
4745
|
+
let token;
|
|
4746
|
+
try {
|
|
4747
|
+
token = resolveCloneToken({ cliToken: tokens.cliTokens?.["github"] ?? tokens.cliToken });
|
|
4748
|
+
} catch (err) {
|
|
4749
|
+
console.error(`clone: ${err instanceof AuthError ? err.message : String(err)}`);
|
|
4750
|
+
process.exitCode = 1;
|
|
4751
|
+
return;
|
|
4706
4752
|
}
|
|
4707
|
-
|
|
4708
|
-
|
|
4709
|
-
|
|
4710
|
-
describe: "Repo coords (\"owner/name\"). Defaults to plugin-specific resolution."
|
|
4711
|
-
}), async (argv) => {
|
|
4712
|
-
const tokens = tokenContext(argv.token);
|
|
4713
|
-
if (!tokens) return;
|
|
4714
|
-
if ((await runSetup({
|
|
4715
|
-
loaded: await loadConfig(argv.cwd),
|
|
4716
|
-
context: {
|
|
4717
|
-
repoRoot: argv.cwd,
|
|
4753
|
+
if ((await runClone({
|
|
4754
|
+
org: argv.org,
|
|
4755
|
+
token,
|
|
4718
4756
|
dryRun: argv.dryRun,
|
|
4719
|
-
...argv.
|
|
4720
|
-
|
|
4721
|
-
|
|
4722
|
-
|
|
4723
|
-
|
|
4724
|
-
|
|
4725
|
-
|
|
4726
|
-
|
|
4727
|
-
|
|
4728
|
-
|
|
4729
|
-
|
|
4730
|
-
|
|
4731
|
-
|
|
4732
|
-
|
|
4733
|
-
|
|
4734
|
-
|
|
4735
|
-
})
|
|
4736
|
-
|
|
4737
|
-
|
|
4738
|
-
|
|
4739
|
-
|
|
4740
|
-
|
|
4741
|
-
|
|
4742
|
-
|
|
4743
|
-
|
|
4744
|
-
|
|
4745
|
-
|
|
4746
|
-
|
|
4747
|
-
|
|
4748
|
-
|
|
4749
|
-
|
|
4757
|
+
...argv.dir ? { dir: argv.dir } : {}
|
|
4758
|
+
})).status === "fail") process.exitCode = 1;
|
|
4759
|
+
}).command("doctor", "Load the config and run a smoke check against every provider", (y) => y.option("repo", {
|
|
4760
|
+
type: "string",
|
|
4761
|
+
describe: "Repo coords (\"owner/name\"). Defaults to plugin-specific resolution."
|
|
4762
|
+
}), async (argv) => {
|
|
4763
|
+
const tokens = tokenContext(argv.token);
|
|
4764
|
+
if (!tokens) return;
|
|
4765
|
+
if ((await runDoctor({
|
|
4766
|
+
loaded: await loadConfig(argv.cwd),
|
|
4767
|
+
context: {
|
|
4768
|
+
repoRoot: argv.cwd,
|
|
4769
|
+
dryRun: argv.dryRun,
|
|
4770
|
+
...argv.repo ? { repo: argv.repo } : {},
|
|
4771
|
+
...tokens
|
|
4772
|
+
}
|
|
4773
|
+
})).summary.fail > 0) process.exitCode = 1;
|
|
4774
|
+
}).command("setup", "Apply infra setup actions across every configured capability", (y) => y.option("repo", {
|
|
4775
|
+
type: "string",
|
|
4776
|
+
describe: "Repo coords (\"owner/name\"). Defaults to plugin-specific resolution."
|
|
4777
|
+
}), async (argv) => {
|
|
4778
|
+
const tokens = tokenContext(argv.token);
|
|
4779
|
+
if (!tokens) return;
|
|
4780
|
+
if ((await runSetup({
|
|
4781
|
+
loaded: await loadConfig(argv.cwd),
|
|
4782
|
+
context: {
|
|
4783
|
+
repoRoot: argv.cwd,
|
|
4784
|
+
dryRun: argv.dryRun,
|
|
4785
|
+
...argv.repo ? { repo: argv.repo } : {},
|
|
4786
|
+
...tokens
|
|
4787
|
+
}
|
|
4788
|
+
})).summary.fail > 0) process.exitCode = 1;
|
|
4789
|
+
}).command("skills", "Manage agent skills from the @theholocron/skills registry", (y) => y.command("install", "Copy skills from @theholocron/skills into .agents/ with agent symlinks", () => {}, async (argv) => {
|
|
4790
|
+
await runSkillsInstall({
|
|
4791
|
+
loaded: await loadConfig(argv.cwd),
|
|
4792
|
+
context: {
|
|
4793
|
+
repoRoot: argv.cwd,
|
|
4794
|
+
dryRun: argv.dryRun
|
|
4795
|
+
}
|
|
4796
|
+
});
|
|
4797
|
+
}).command("remove [names..]", "Remove installed skills via npx skills remove", (yy) => yy.positional("names", {
|
|
4798
|
+
type: "string",
|
|
4799
|
+
array: true,
|
|
4800
|
+
describe: "Skill name(s) to remove (omit to remove all installed skills)"
|
|
4801
|
+
}), (argv) => {
|
|
4802
|
+
if (runSkillsRemove({
|
|
4803
|
+
context: {
|
|
4804
|
+
repoRoot: argv.cwd,
|
|
4805
|
+
dryRun: argv.dryRun
|
|
4806
|
+
},
|
|
4807
|
+
...argv.names?.length ? { names: argv.names } : {}
|
|
4808
|
+
}).status === "fail") process.exitCode = 1;
|
|
4809
|
+
}).command("update [name]", "Update installed skills to their latest upstream versions via npx skills update", (yy) => yy.positional("name", {
|
|
4810
|
+
type: "string",
|
|
4811
|
+
describe: "Skill name to update (omit to update all installed skills)"
|
|
4812
|
+
}), (argv) => {
|
|
4813
|
+
if (runSkillsUpdate({
|
|
4814
|
+
context: {
|
|
4815
|
+
repoRoot: argv.cwd,
|
|
4816
|
+
dryRun: argv.dryRun
|
|
4817
|
+
},
|
|
4818
|
+
...argv.name ? { name: argv.name } : {}
|
|
4819
|
+
}).status === "fail") process.exitCode = 1;
|
|
4820
|
+
}).demandCommand(1, "Run `holocron skills --help` to see available skills subcommands."), () => {}).command("secret set <name> [value]", "Set a single secret via the configured `secrets` capability", (y) => y.positional("name", {
|
|
4821
|
+
type: "string",
|
|
4822
|
+
demandOption: true,
|
|
4823
|
+
describe: "Secret name (e.g., NPM_TOKEN)"
|
|
4824
|
+
}).positional("value", {
|
|
4825
|
+
type: "string",
|
|
4826
|
+
describe: "Secret value (positional). If omitted, sources from --from-stdin, --from-env, or env var matching <name>."
|
|
4827
|
+
}).option("from-stdin", {
|
|
4828
|
+
type: "boolean",
|
|
4829
|
+
default: false,
|
|
4830
|
+
describe: "Read the secret value from stdin"
|
|
4831
|
+
}).option("from-env", {
|
|
4832
|
+
type: "string",
|
|
4833
|
+
describe: "Read the secret value from the named env var (otherwise: env var matching <name>)"
|
|
4834
|
+
}).option("scope", {
|
|
4835
|
+
type: "string",
|
|
4836
|
+
default: "repo",
|
|
4837
|
+
describe: "Scope: \"repo\" (default), \"env=<name>\", or \"org=<name>\""
|
|
4838
|
+
}), async (argv) => {
|
|
4839
|
+
const tokens = tokenContext(argv.token);
|
|
4840
|
+
if (!tokens) return;
|
|
4841
|
+
const scopeArg = argv.scope;
|
|
4842
|
+
const scope = parseScope(scopeArg);
|
|
4843
|
+
if ((await runSecretSet({
|
|
4844
|
+
loaded: await loadConfig(argv.cwd),
|
|
4845
|
+
context: {
|
|
4846
|
+
repoRoot: argv.cwd,
|
|
4847
|
+
dryRun: argv.dryRun,
|
|
4848
|
+
...tokens
|
|
4849
|
+
},
|
|
4850
|
+
name: argv.name,
|
|
4851
|
+
...argv.value ? { value: argv.value } : {},
|
|
4852
|
+
...argv.fromStdin ? { fromStdin: true } : {},
|
|
4853
|
+
...argv.fromEnv ? { fromEnv: argv.fromEnv } : {},
|
|
4854
|
+
scope
|
|
4855
|
+
})).status === "fail") process.exitCode = 1;
|
|
4856
|
+
}).command("secrets sync <environmentId>", "Read a vault environment + fan KEY=VALUEs out to secrets + deployment env vars", (y) => y.positional("environmentId", {
|
|
4857
|
+
type: "string",
|
|
4858
|
+
demandOption: true,
|
|
4859
|
+
describe: "Vault environment id to read (1P Environment id, etc.)"
|
|
4860
|
+
}).option("project-id", {
|
|
4861
|
+
type: "string",
|
|
4862
|
+
describe: "Deployment project id (e.g., Vercel prj_*). Required when deployment is loaded."
|
|
4863
|
+
}).option("target", {
|
|
4864
|
+
type: "array",
|
|
4865
|
+
default: ["production", "preview"],
|
|
4866
|
+
describe: "Deployment targets to sync to. Defaults to production + preview."
|
|
4867
|
+
}), async (argv) => {
|
|
4868
|
+
const tokens = tokenContext(argv.token);
|
|
4869
|
+
if (!tokens) return;
|
|
4870
|
+
if ((await runSecretsSync({
|
|
4871
|
+
loaded: await loadConfig(argv.cwd),
|
|
4872
|
+
context: {
|
|
4873
|
+
repoRoot: argv.cwd,
|
|
4874
|
+
dryRun: argv.dryRun,
|
|
4875
|
+
...tokens
|
|
4876
|
+
},
|
|
4877
|
+
environmentId: argv.environmentId,
|
|
4878
|
+
...argv.projectId ? { projectId: argv.projectId } : {},
|
|
4879
|
+
targets: argv.target
|
|
4880
|
+
})).summary.fail > 0) process.exitCode = 1;
|
|
4881
|
+
}).command("deploy <branch>", "Trigger a deployment via the configured `deployment` capability", (y) => y.positional("branch", {
|
|
4882
|
+
type: "string",
|
|
4883
|
+
demandOption: true,
|
|
4884
|
+
describe: "Git branch to deploy"
|
|
4885
|
+
}).option("project-id", {
|
|
4886
|
+
type: "string",
|
|
4887
|
+
demandOption: true,
|
|
4888
|
+
describe: "Deployment project id (e.g., Vercel prj_*)"
|
|
4889
|
+
}).option("target", {
|
|
4890
|
+
type: "string",
|
|
4891
|
+
choices: ["production", "staging"],
|
|
4892
|
+
describe: "Named environment to deploy into. Omit for a branch preview."
|
|
4893
|
+
}), async (argv) => {
|
|
4894
|
+
const tokens = tokenContext(argv.token);
|
|
4895
|
+
if (!tokens) return;
|
|
4896
|
+
if ((await runDeploy({
|
|
4897
|
+
loaded: await loadConfig(argv.cwd),
|
|
4898
|
+
context: {
|
|
4899
|
+
repoRoot: argv.cwd,
|
|
4900
|
+
dryRun: argv.dryRun,
|
|
4901
|
+
...tokens
|
|
4902
|
+
},
|
|
4903
|
+
projectId: argv.projectId,
|
|
4904
|
+
branch: argv.branch,
|
|
4905
|
+
...argv.target ? { target: argv.target } : {}
|
|
4906
|
+
})).status === "fail") process.exitCode = 1;
|
|
4907
|
+
}).command("npm", "npm-related monorepo utilities", (y) => y.command("bump-versions <new-version>", "Bump all non-private package versions in lockstep (semantic-release prepareCmd)", (yy) => yy.positional("new-version", {
|
|
4908
|
+
type: "string",
|
|
4909
|
+
demandOption: true,
|
|
4910
|
+
describe: "Version to set (e.g., 4.2.0 or 2.0.0-alpha.1)"
|
|
4911
|
+
}), async (argv) => {
|
|
4912
|
+
if ((await runNpmBumpVersions({
|
|
4913
|
+
version: argv.newVersion,
|
|
4914
|
+
cwd: argv.cwd,
|
|
4750
4915
|
dryRun: argv.dryRun
|
|
4751
|
-
}
|
|
4752
|
-
|
|
4753
|
-
|
|
4754
|
-
|
|
4755
|
-
|
|
4756
|
-
|
|
4757
|
-
|
|
4758
|
-
|
|
4759
|
-
|
|
4760
|
-
|
|
4761
|
-
|
|
4762
|
-
|
|
4763
|
-
default: false,
|
|
4764
|
-
describe: "Read the secret value from stdin"
|
|
4765
|
-
}).option("from-env", {
|
|
4766
|
-
type: "string",
|
|
4767
|
-
describe: "Read the secret value from the named env var (otherwise: env var matching <name>)"
|
|
4768
|
-
}).option("scope", {
|
|
4769
|
-
type: "string",
|
|
4770
|
-
default: "repo",
|
|
4771
|
-
describe: "Scope: \"repo\" (default), \"env=<name>\", or \"org=<name>\""
|
|
4772
|
-
}), async (argv) => {
|
|
4773
|
-
const tokens = tokenContext(argv.token);
|
|
4774
|
-
if (!tokens) return;
|
|
4775
|
-
const scopeArg = argv.scope;
|
|
4776
|
-
const scope = parseScope(scopeArg);
|
|
4777
|
-
if ((await runSecretSet({
|
|
4778
|
-
loaded: await loadConfig(argv.cwd),
|
|
4779
|
-
context: {
|
|
4780
|
-
repoRoot: argv.cwd,
|
|
4781
|
-
dryRun: argv.dryRun,
|
|
4782
|
-
...tokens
|
|
4783
|
-
},
|
|
4784
|
-
name: argv.name,
|
|
4785
|
-
...argv.value ? { value: argv.value } : {},
|
|
4786
|
-
...argv.fromStdin ? { fromStdin: true } : {},
|
|
4787
|
-
...argv.fromEnv ? { fromEnv: argv.fromEnv } : {},
|
|
4788
|
-
scope
|
|
4789
|
-
})).status === "fail") process.exitCode = 1;
|
|
4790
|
-
}).command("secrets sync <environmentId>", "Read a vault environment + fan KEY=VALUEs out to secrets + deployment env vars", (y) => y.positional("environmentId", {
|
|
4791
|
-
type: "string",
|
|
4792
|
-
demandOption: true,
|
|
4793
|
-
describe: "Vault environment id to read (1P Environment id, etc.)"
|
|
4794
|
-
}).option("project-id", {
|
|
4795
|
-
type: "string",
|
|
4796
|
-
describe: "Deployment project id (e.g., Vercel prj_*). Required when deployment is loaded."
|
|
4797
|
-
}).option("target", {
|
|
4798
|
-
type: "array",
|
|
4799
|
-
default: ["production", "preview"],
|
|
4800
|
-
describe: "Deployment targets to sync to. Defaults to production + preview."
|
|
4801
|
-
}), async (argv) => {
|
|
4802
|
-
const tokens = tokenContext(argv.token);
|
|
4803
|
-
if (!tokens) return;
|
|
4804
|
-
if ((await runSecretsSync({
|
|
4805
|
-
loaded: await loadConfig(argv.cwd),
|
|
4806
|
-
context: {
|
|
4807
|
-
repoRoot: argv.cwd,
|
|
4808
|
-
dryRun: argv.dryRun,
|
|
4809
|
-
...tokens
|
|
4810
|
-
},
|
|
4811
|
-
environmentId: argv.environmentId,
|
|
4812
|
-
...argv.projectId ? { projectId: argv.projectId } : {},
|
|
4813
|
-
targets: argv.target
|
|
4814
|
-
})).summary.fail > 0) process.exitCode = 1;
|
|
4815
|
-
}).command("deploy <branch>", "Trigger a deployment via the configured `deployment` capability", (y) => y.positional("branch", {
|
|
4816
|
-
type: "string",
|
|
4817
|
-
demandOption: true,
|
|
4818
|
-
describe: "Git branch to deploy"
|
|
4819
|
-
}).option("project-id", {
|
|
4820
|
-
type: "string",
|
|
4821
|
-
demandOption: true,
|
|
4822
|
-
describe: "Deployment project id (e.g., Vercel prj_*)"
|
|
4823
|
-
}).option("target", {
|
|
4824
|
-
type: "string",
|
|
4825
|
-
choices: ["production", "staging"],
|
|
4826
|
-
describe: "Named environment to deploy into. Omit for a branch preview."
|
|
4827
|
-
}), async (argv) => {
|
|
4828
|
-
const tokens = tokenContext(argv.token);
|
|
4829
|
-
if (!tokens) return;
|
|
4830
|
-
if ((await runDeploy({
|
|
4831
|
-
loaded: await loadConfig(argv.cwd),
|
|
4832
|
-
context: {
|
|
4833
|
-
repoRoot: argv.cwd,
|
|
4834
|
-
dryRun: argv.dryRun,
|
|
4835
|
-
...tokens
|
|
4836
|
-
},
|
|
4837
|
-
projectId: argv.projectId,
|
|
4838
|
-
branch: argv.branch,
|
|
4839
|
-
...argv.target ? { target: argv.target } : {}
|
|
4840
|
-
})).status === "fail") process.exitCode = 1;
|
|
4841
|
-
}).command("npm", "npm-related monorepo utilities", (y) => y.command("bump-versions <new-version>", "Bump all non-private package versions in lockstep (semantic-release prepareCmd)", (yy) => yy.positional("new-version", {
|
|
4842
|
-
type: "string",
|
|
4843
|
-
demandOption: true,
|
|
4844
|
-
describe: "Version to set (e.g., 4.2.0 or 2.0.0-alpha.1)"
|
|
4845
|
-
}), async (argv) => {
|
|
4846
|
-
if ((await runNpmBumpVersions({
|
|
4847
|
-
version: argv.newVersion,
|
|
4848
|
-
cwd: argv.cwd,
|
|
4849
|
-
dryRun: argv.dryRun
|
|
4850
|
-
})).status === "fail") process.exitCode = 1;
|
|
4851
|
-
}).command("publish-initial", "One-shot bootstrap publish for trusted-publishing-eligible packages", (yy) => yy.option("tag", {
|
|
4852
|
-
type: "string",
|
|
4853
|
-
default: "alpha",
|
|
4854
|
-
describe: "npm distribution tag (defaults to alpha)"
|
|
4855
|
-
}).option("otp", {
|
|
4856
|
-
type: "string",
|
|
4857
|
-
describe: "One-time password from your authenticator (required if npm needs 2FA for writes)"
|
|
4858
|
-
}), async (argv) => {
|
|
4859
|
-
if ((await runNpmPublishInitial({
|
|
4860
|
-
cwd: argv.cwd,
|
|
4861
|
-
tag: argv.tag,
|
|
4862
|
-
dryRun: argv.dryRun,
|
|
4863
|
-
...argv.otp ? { otp: argv.otp } : {}
|
|
4864
|
-
})).status === "fail") process.exitCode = 1;
|
|
4865
|
-
}).demandCommand(1, "Run `holocron npm --help` to see available npm subcommands."), () => {}).command("sync [steps..]", "Sync state from config to the provider and local files (labels, properties, topics, keywords, description)", (y) => y.positional("steps", {
|
|
4866
|
-
type: "string",
|
|
4867
|
-
array: true,
|
|
4868
|
-
describe: "Steps to run: labels, properties, topics, keywords, description (default: all)"
|
|
4869
|
-
}).option("repo", {
|
|
4870
|
-
type: "string",
|
|
4871
|
-
describe: "Repo coords (\"owner/name\"). Defaults to plugin-specific resolution."
|
|
4872
|
-
}), async (argv) => {
|
|
4873
|
-
const tokens = tokenContext(argv.token);
|
|
4874
|
-
if (!tokens) return;
|
|
4875
|
-
if ((await runSync({
|
|
4876
|
-
loaded: await loadConfig(argv.cwd),
|
|
4877
|
-
context: {
|
|
4878
|
-
repoRoot: argv.cwd,
|
|
4916
|
+
})).status === "fail") process.exitCode = 1;
|
|
4917
|
+
}).command("publish-initial", "One-shot bootstrap publish for trusted-publishing-eligible packages", (yy) => yy.option("tag", {
|
|
4918
|
+
type: "string",
|
|
4919
|
+
default: "alpha",
|
|
4920
|
+
describe: "npm distribution tag (defaults to alpha)"
|
|
4921
|
+
}).option("otp", {
|
|
4922
|
+
type: "string",
|
|
4923
|
+
describe: "One-time password from your authenticator (required if npm needs 2FA for writes)"
|
|
4924
|
+
}), async (argv) => {
|
|
4925
|
+
if ((await runNpmPublishInitial({
|
|
4926
|
+
cwd: argv.cwd,
|
|
4927
|
+
tag: argv.tag,
|
|
4879
4928
|
dryRun: argv.dryRun,
|
|
4880
|
-
...argv.
|
|
4881
|
-
|
|
4882
|
-
|
|
4883
|
-
|
|
4884
|
-
|
|
4885
|
-
|
|
4886
|
-
|
|
4887
|
-
|
|
4888
|
-
|
|
4889
|
-
})
|
|
4890
|
-
|
|
4891
|
-
|
|
4892
|
-
|
|
4893
|
-
|
|
4894
|
-
|
|
4895
|
-
|
|
4896
|
-
|
|
4897
|
-
|
|
4898
|
-
|
|
4899
|
-
}
|
|
4900
|
-
|
|
4901
|
-
|
|
4902
|
-
}),
|
|
4903
|
-
|
|
4904
|
-
|
|
4905
|
-
|
|
4906
|
-
|
|
4907
|
-
|
|
4908
|
-
|
|
4909
|
-
|
|
4910
|
-
|
|
4911
|
-
|
|
4912
|
-
|
|
4913
|
-
|
|
4914
|
-
|
|
4915
|
-
|
|
4916
|
-
|
|
4917
|
-
|
|
4918
|
-
|
|
4919
|
-
|
|
4920
|
-
|
|
4921
|
-
|
|
4922
|
-
|
|
4923
|
-
|
|
4924
|
-
|
|
4925
|
-
|
|
4926
|
-
|
|
4927
|
-
}
|
|
4928
|
-
|
|
4929
|
-
describe: "Template type — maps to theholocron/<type>-template (e.g. cli, react, nextjs, node, monorepo, base)"
|
|
4930
|
-
}).positional("name", {
|
|
4931
|
-
type: "string",
|
|
4932
|
-
describe: "New repo name (kebab-case, e.g. my-tool)"
|
|
4933
|
-
}).option("description", {
|
|
4934
|
-
type: "string",
|
|
4935
|
-
describe: "Short description — replaces <description> placeholders in the template"
|
|
4936
|
-
}).option("org", {
|
|
4937
|
-
type: "string",
|
|
4938
|
-
default: "theholocron",
|
|
4939
|
-
describe: "GitHub org that owns the template and will own the new repo"
|
|
4940
|
-
}).option("verify", {
|
|
4941
|
-
type: "boolean",
|
|
4942
|
-
default: true,
|
|
4943
|
-
describe: "Run pnpm install after bootstrapping (default true; --no-verify skips)"
|
|
4944
|
-
}), async (argv) => {
|
|
4945
|
-
try {
|
|
4946
|
-
let type = argv.type;
|
|
4947
|
-
let name = argv.name;
|
|
4948
|
-
let description = argv.description;
|
|
4949
|
-
if (!type || !name || description === void 0) {
|
|
4950
|
-
const rl = createInterface({
|
|
4951
|
-
input: stdin,
|
|
4952
|
-
output: stdout
|
|
4953
|
-
});
|
|
4954
|
-
const ask = (question) => new Promise((resolve) => rl.question(` ${question} `, (answer) => resolve(answer.trim())));
|
|
4955
|
-
try {
|
|
4956
|
-
if (!type) {
|
|
4957
|
-
console.log(" Known types: base, cli, monorepo, nextjs, node, react");
|
|
4958
|
-
type = await ask("Template type:");
|
|
4959
|
-
}
|
|
4960
|
-
if (!name) name = await ask("Repo name (kebab-case):");
|
|
4961
|
-
if (description === void 0) description = await ask("Short description (Enter to skip):");
|
|
4962
|
-
} finally {
|
|
4963
|
-
rl.close();
|
|
4964
|
-
}
|
|
4965
|
-
}
|
|
4966
|
-
if (!type) {
|
|
4967
|
-
console.error("new: template type is required");
|
|
4968
|
-
process.exitCode = 1;
|
|
4969
|
-
return;
|
|
4970
|
-
}
|
|
4971
|
-
if (!name) {
|
|
4972
|
-
console.error("new: repo name is required");
|
|
4929
|
+
...argv.otp ? { otp: argv.otp } : {}
|
|
4930
|
+
})).status === "fail") process.exitCode = 1;
|
|
4931
|
+
}).demandCommand(1, "Run `holocron npm --help` to see available npm subcommands."), () => {}).command("sync [steps..]", "Sync state from config to the provider and local files (labels, properties, topics, keywords, description)", (y) => y.positional("steps", {
|
|
4932
|
+
type: "string",
|
|
4933
|
+
array: true,
|
|
4934
|
+
describe: "Steps to run: labels, properties, topics, keywords, description (default: all)"
|
|
4935
|
+
}).option("repo", {
|
|
4936
|
+
type: "string",
|
|
4937
|
+
describe: "Repo coords (\"owner/name\"). Defaults to plugin-specific resolution."
|
|
4938
|
+
}), async (argv) => {
|
|
4939
|
+
const tokens = tokenContext(argv.token);
|
|
4940
|
+
if (!tokens) return;
|
|
4941
|
+
if ((await runSync({
|
|
4942
|
+
loaded: await loadConfig(argv.cwd),
|
|
4943
|
+
context: {
|
|
4944
|
+
repoRoot: argv.cwd,
|
|
4945
|
+
dryRun: argv.dryRun,
|
|
4946
|
+
...argv.repo ? { repo: argv.repo } : {},
|
|
4947
|
+
...tokens
|
|
4948
|
+
},
|
|
4949
|
+
...argv.steps && argv.steps.length > 0 ? { steps: argv.steps } : {}
|
|
4950
|
+
})).summary.fail > 0) process.exitCode = 1;
|
|
4951
|
+
}).command("sync-github", "Sync workflow templates and composite actions to theholocron/.github via the GitHub API", (y) => y.option("repo", {
|
|
4952
|
+
type: "string",
|
|
4953
|
+
default: "theholocron/.github",
|
|
4954
|
+
describe: "Target org/repo (default: theholocron/.github)"
|
|
4955
|
+
}).option("branch", {
|
|
4956
|
+
type: "string",
|
|
4957
|
+
describe: "Push to this branch instead of the default branch (enables PR-based workflow for protected repos)"
|
|
4958
|
+
}).option("pr", {
|
|
4959
|
+
type: "boolean",
|
|
4960
|
+
default: false,
|
|
4961
|
+
describe: "Open a PR after pushing to --branch (no-op without --branch)"
|
|
4962
|
+
}).option("message", {
|
|
4963
|
+
type: "string",
|
|
4964
|
+
describe: "Commit message (default: chore: sync from theholocron/holocron)"
|
|
4965
|
+
}).option("output-dir", {
|
|
4966
|
+
type: "string",
|
|
4967
|
+
describe: "Write generated files to this local directory instead of pushing (for validation)"
|
|
4968
|
+
}), async (argv) => {
|
|
4969
|
+
const outputDir = argv["output-dir"];
|
|
4970
|
+
const parsed = tokenContext(argv.token);
|
|
4971
|
+
if (!parsed) return;
|
|
4972
|
+
let token;
|
|
4973
|
+
if (outputDir) token = "no-token-needed";
|
|
4974
|
+
else try {
|
|
4975
|
+
token = resolveSyncToken({ cliToken: parsed.cliTokens?.["github"] ?? parsed.cliToken });
|
|
4976
|
+
} catch (err) {
|
|
4977
|
+
console.error(`sync-github: ${err instanceof AuthError ? err.message : String(err)}`);
|
|
4973
4978
|
process.exitCode = 1;
|
|
4974
4979
|
return;
|
|
4975
4980
|
}
|
|
4976
|
-
if ((await
|
|
4977
|
-
|
|
4978
|
-
|
|
4979
|
-
...description ? { description } : {},
|
|
4980
|
-
org: argv.org,
|
|
4981
|
+
if ((await runSyncGithub({
|
|
4982
|
+
token,
|
|
4983
|
+
repo: argv.repo,
|
|
4981
4984
|
dryRun: argv.dryRun,
|
|
4982
|
-
|
|
4983
|
-
|
|
4985
|
+
...argv.branch ? { branch: argv.branch } : {},
|
|
4986
|
+
...argv.pr ? { createPr: true } : {},
|
|
4987
|
+
...argv.message ? { message: argv.message } : {},
|
|
4988
|
+
...outputDir ? { outputDir } : {}
|
|
4984
4989
|
})).status === "fail") process.exitCode = 1;
|
|
4985
|
-
}
|
|
4986
|
-
|
|
4987
|
-
|
|
4988
|
-
|
|
4989
|
-
|
|
4990
|
+
}).command("config show", "Print the resolved holocron config", () => {}, async (argv) => {
|
|
4991
|
+
const loaded = await loadConfig(argv.cwd);
|
|
4992
|
+
console.log(JSON.stringify(loaded.resolved, null, 2));
|
|
4993
|
+
}).command("new [type] [name]", "Scaffold a new repo from a GitHub template (e.g. cli, react, nextjs, node, monorepo, base)", (y) => y.positional("type", {
|
|
4994
|
+
type: "string",
|
|
4995
|
+
describe: "Template type — maps to theholocron/<type>-template (e.g. cli, react, nextjs, node, monorepo, base)"
|
|
4996
|
+
}).positional("name", {
|
|
4997
|
+
type: "string",
|
|
4998
|
+
describe: "New repo name (kebab-case, e.g. my-tool)"
|
|
4999
|
+
}).option("description", {
|
|
5000
|
+
type: "string",
|
|
5001
|
+
describe: "Short description — replaces <description> placeholders in the template"
|
|
5002
|
+
}).option("org", {
|
|
5003
|
+
type: "string",
|
|
5004
|
+
default: "theholocron",
|
|
5005
|
+
describe: "GitHub org that owns the template and will own the new repo"
|
|
5006
|
+
}).option("verify", {
|
|
5007
|
+
type: "boolean",
|
|
5008
|
+
default: true,
|
|
5009
|
+
describe: "Run pnpm install after bootstrapping (default true; --no-verify skips)"
|
|
5010
|
+
}), async (argv) => {
|
|
5011
|
+
try {
|
|
5012
|
+
let type = argv.type;
|
|
5013
|
+
let name = argv.name;
|
|
5014
|
+
let description = argv.description;
|
|
5015
|
+
if (!type || !name || description === void 0) {
|
|
5016
|
+
const rl = createInterface({
|
|
5017
|
+
input: stdin,
|
|
5018
|
+
output: stdout
|
|
5019
|
+
});
|
|
5020
|
+
const ask = (question) => new Promise((resolve) => rl.question(` ${question} `, (answer) => resolve(answer.trim())));
|
|
5021
|
+
try {
|
|
5022
|
+
if (!type) {
|
|
5023
|
+
console.log(" Known types: base, cli, monorepo, nextjs, node, react");
|
|
5024
|
+
type = await ask("Template type:");
|
|
5025
|
+
}
|
|
5026
|
+
if (!name) name = await ask("Repo name (kebab-case):");
|
|
5027
|
+
if (description === void 0) description = await ask("Short description (Enter to skip):");
|
|
5028
|
+
} finally {
|
|
5029
|
+
rl.close();
|
|
5030
|
+
}
|
|
5031
|
+
}
|
|
5032
|
+
if (!type) {
|
|
5033
|
+
console.error("new: template type is required");
|
|
5034
|
+
process.exitCode = 1;
|
|
5035
|
+
return;
|
|
5036
|
+
}
|
|
5037
|
+
if (!name) {
|
|
5038
|
+
console.error("new: repo name is required");
|
|
5039
|
+
process.exitCode = 1;
|
|
5040
|
+
return;
|
|
5041
|
+
}
|
|
5042
|
+
if ((await runNew({
|
|
5043
|
+
type,
|
|
5044
|
+
name,
|
|
5045
|
+
...description ? { description } : {},
|
|
5046
|
+
org: argv.org,
|
|
5047
|
+
dryRun: argv.dryRun,
|
|
5048
|
+
noVerify: !argv.verify,
|
|
5049
|
+
cwd: argv.cwd
|
|
5050
|
+
})).status === "fail") process.exitCode = 1;
|
|
5051
|
+
} catch (err) {
|
|
5052
|
+
if (err instanceof NewError) {
|
|
5053
|
+
console.error(`new: ${err.message}`);
|
|
5054
|
+
process.exitCode = 1;
|
|
5055
|
+
return;
|
|
5056
|
+
}
|
|
5057
|
+
throw err;
|
|
4990
5058
|
}
|
|
4991
|
-
|
|
4992
|
-
|
|
4993
|
-
|
|
4994
|
-
|
|
4995
|
-
|
|
4996
|
-
|
|
4997
|
-
|
|
4998
|
-
|
|
4999
|
-
|
|
5000
|
-
|
|
5001
|
-
|
|
5002
|
-
|
|
5003
|
-
|
|
5004
|
-
|
|
5005
|
-
|
|
5006
|
-
|
|
5007
|
-
|
|
5008
|
-
|
|
5009
|
-
|
|
5010
|
-
|
|
5011
|
-
|
|
5012
|
-
|
|
5013
|
-
|
|
5014
|
-
|
|
5015
|
-
|
|
5016
|
-
|
|
5017
|
-
|
|
5018
|
-
|
|
5019
|
-
|
|
5020
|
-
|
|
5021
|
-
|
|
5022
|
-
|
|
5023
|
-
|
|
5024
|
-
|
|
5025
|
-
|
|
5026
|
-
|
|
5027
|
-
|
|
5028
|
-
|
|
5029
|
-
|
|
5030
|
-
|
|
5031
|
-
|
|
5032
|
-
|
|
5033
|
-
|
|
5034
|
-
|
|
5035
|
-
|
|
5036
|
-
|
|
5037
|
-
|
|
5038
|
-
|
|
5059
|
+
}).command("plugin create <slug> <vendor>", "Scaffold a new @theholocron/holocron-plugin-<slug> package", (y) => y.positional("slug", {
|
|
5060
|
+
type: "string",
|
|
5061
|
+
demandOption: true,
|
|
5062
|
+
describe: "Package slug (kebab-case)"
|
|
5063
|
+
}).positional("vendor", {
|
|
5064
|
+
type: "string",
|
|
5065
|
+
demandOption: true,
|
|
5066
|
+
describe: "Vendor display name (PascalCase)"
|
|
5067
|
+
}).option("capability", {
|
|
5068
|
+
type: "string",
|
|
5069
|
+
describe: "Capability key: source|ci|secrets|environments|issues|deployment|storage|auth|vault|dns|tooling|notifications|analytics|observability"
|
|
5070
|
+
}).option("token-env", {
|
|
5071
|
+
type: "string",
|
|
5072
|
+
describe: "Holocron env var name (defaults to HOLOCRON_<VENDOR>_TOKEN)"
|
|
5073
|
+
}).option("vendor-env", {
|
|
5074
|
+
type: "string",
|
|
5075
|
+
describe: "Vendor-native env var name"
|
|
5076
|
+
}).option("base-url", {
|
|
5077
|
+
type: "string",
|
|
5078
|
+
describe: "REST base URL"
|
|
5079
|
+
}).option("verify", {
|
|
5080
|
+
type: "boolean",
|
|
5081
|
+
default: true,
|
|
5082
|
+
describe: "Run post-scaffold pnpm install + typecheck + lint + test (default true; --no-verify skips)"
|
|
5083
|
+
}), async (argv) => {
|
|
5084
|
+
try {
|
|
5085
|
+
const capabilityKeys = Object.keys(CARDINALITY).join(", ");
|
|
5086
|
+
const needsPrompt = !argv.capability || !argv.vendorEnv || !argv.baseUrl;
|
|
5087
|
+
let capability;
|
|
5088
|
+
let vendorEnv;
|
|
5089
|
+
let baseUrl;
|
|
5090
|
+
if (needsPrompt) {
|
|
5091
|
+
const rl = createInterface({
|
|
5092
|
+
input: stdin,
|
|
5093
|
+
output: stdout
|
|
5094
|
+
});
|
|
5095
|
+
const ask = (question) => new Promise((resolve) => rl.question(` ${question} `, (answer) => resolve(answer.trim())));
|
|
5096
|
+
try {
|
|
5097
|
+
if (!argv.capability) {
|
|
5098
|
+
console.log(` Available capabilities: ${capabilityKeys}`);
|
|
5099
|
+
capability = await ask("Capability:");
|
|
5100
|
+
} else capability = argv.capability;
|
|
5101
|
+
vendorEnv = argv.vendorEnv ? argv.vendorEnv : await ask(`Vendor-native env var for the ${argv.vendor} token (e.g. MYVENDOR_API_KEY):`);
|
|
5102
|
+
baseUrl = argv.baseUrl ? argv.baseUrl : await ask(`REST base URL for the ${argv.vendor} API (e.g. https://api.myvendor.com):`);
|
|
5103
|
+
} finally {
|
|
5104
|
+
rl.close();
|
|
5105
|
+
}
|
|
5106
|
+
} else {
|
|
5107
|
+
capability = argv.capability;
|
|
5108
|
+
vendorEnv = argv.vendorEnv;
|
|
5109
|
+
baseUrl = argv.baseUrl;
|
|
5039
5110
|
}
|
|
5040
|
-
|
|
5041
|
-
|
|
5042
|
-
|
|
5043
|
-
|
|
5111
|
+
if (runPluginCreate({
|
|
5112
|
+
slug: argv.slug,
|
|
5113
|
+
vendorName: argv.vendor,
|
|
5114
|
+
capability,
|
|
5115
|
+
vendorEnv,
|
|
5116
|
+
baseUrl,
|
|
5117
|
+
...argv.tokenEnv ? { tokenEnv: argv.tokenEnv } : {},
|
|
5118
|
+
dryRun: argv.dryRun,
|
|
5119
|
+
noVerify: !argv.verify,
|
|
5120
|
+
cwd: argv.cwd
|
|
5121
|
+
}).status === "fail") process.exitCode = 1;
|
|
5122
|
+
} catch (err) {
|
|
5123
|
+
if (err instanceof PluginCreateError) {
|
|
5124
|
+
console.error(`plugin create: ${err.message}`);
|
|
5125
|
+
process.exitCode = 1;
|
|
5126
|
+
return;
|
|
5127
|
+
}
|
|
5128
|
+
throw err;
|
|
5044
5129
|
}
|
|
5045
|
-
|
|
5046
|
-
|
|
5047
|
-
|
|
5048
|
-
|
|
5049
|
-
|
|
5050
|
-
|
|
5051
|
-
|
|
5130
|
+
}).command("upgrade", "Upgrade toolchain version pins across the repo", (y) => y.command("node <to>", "Scan the repo and update every Node.js version pin to a new major", (yy) => yy.positional("to", {
|
|
5131
|
+
type: "number",
|
|
5132
|
+
demandOption: true,
|
|
5133
|
+
describe: "Target Node.js major version (e.g., 22)"
|
|
5134
|
+
}).option("from", {
|
|
5135
|
+
type: "number",
|
|
5136
|
+
describe: "Current major version to replace. Auto-detected from .nvmrc / engines.node when omitted."
|
|
5137
|
+
}), async (argv) => {
|
|
5138
|
+
let extra = [];
|
|
5139
|
+
try {
|
|
5140
|
+
const raw = readFileSync(join(argv.cwd, "holocron.config.json"), "utf8");
|
|
5141
|
+
const upgradeNode = JSON.parse(raw).upgrade?.node;
|
|
5142
|
+
if (Array.isArray(upgradeNode?.extra)) extra = upgradeNode.extra;
|
|
5143
|
+
} catch {}
|
|
5144
|
+
const report = await runUpgradeNode({
|
|
5145
|
+
to: argv.to,
|
|
5146
|
+
...argv.from != null ? { from: argv.from } : {},
|
|
5147
|
+
cwd: argv.cwd,
|
|
5052
5148
|
dryRun: argv.dryRun,
|
|
5053
|
-
|
|
5054
|
-
|
|
5055
|
-
|
|
5056
|
-
|
|
5057
|
-
if (err instanceof PluginCreateError) {
|
|
5058
|
-
console.error(`plugin create: ${err.message}`);
|
|
5149
|
+
extra
|
|
5150
|
+
});
|
|
5151
|
+
if (report.status === "fail") {
|
|
5152
|
+
if (report.message) console.error(`upgrade node: ${report.message}`);
|
|
5059
5153
|
process.exitCode = 1;
|
|
5060
|
-
return;
|
|
5061
5154
|
}
|
|
5062
|
-
|
|
5063
|
-
|
|
5064
|
-
|
|
5065
|
-
type: "
|
|
5066
|
-
|
|
5067
|
-
|
|
5068
|
-
|
|
5069
|
-
|
|
5070
|
-
|
|
5071
|
-
|
|
5072
|
-
|
|
5073
|
-
|
|
5074
|
-
|
|
5075
|
-
|
|
5076
|
-
|
|
5077
|
-
|
|
5078
|
-
|
|
5079
|
-
|
|
5080
|
-
|
|
5081
|
-
|
|
5082
|
-
|
|
5083
|
-
|
|
5084
|
-
|
|
5085
|
-
if (
|
|
5086
|
-
|
|
5087
|
-
|
|
5088
|
-
|
|
5089
|
-
}).demandCommand(1, "Run `holocron upgrade --help` to see available upgrade subcommands."), () => {}).command("auth <subcommand>", "Manage bootstrap credentials in the OS keyring", (y) => y.command("set <provider> [value]", "Verify + store a bootstrap token for a provider", (yy) => yy.positional("provider", {
|
|
5090
|
-
type: "string",
|
|
5091
|
-
demandOption: true
|
|
5092
|
-
}).positional("value", { type: "string" }), async (argv) => {
|
|
5093
|
-
if ((await runAuthSet({
|
|
5094
|
-
provider: argv.provider,
|
|
5095
|
-
...argv.value ? { positional: argv.value } : {}
|
|
5096
|
-
})).status === "fail") process.exitCode = 1;
|
|
5097
|
-
}).command("unset <provider>", "Remove a stored bootstrap token", (yy) => yy.positional("provider", {
|
|
5098
|
-
type: "string",
|
|
5099
|
-
demandOption: true
|
|
5100
|
-
}), (argv) => {
|
|
5101
|
-
runAuthUnset({ provider: argv.provider });
|
|
5102
|
-
}).command("check <provider>", "Re-verify a stored bootstrap token", (yy) => yy.positional("provider", {
|
|
5103
|
-
type: "string",
|
|
5104
|
-
demandOption: true
|
|
5105
|
-
}), async (argv) => {
|
|
5106
|
-
if ((await runAuthCheck({ provider: argv.provider })).status === "fail") process.exitCode = 1;
|
|
5107
|
-
}).command("list", "List every provider with a stored bootstrap token", () => {}, async () => {
|
|
5108
|
-
await runAuthList();
|
|
5109
|
-
}).demandCommand(1, "Run `holocron auth --help` to see available auth subcommands."), () => {}).demandCommand(1, "Run `holocron --help` to see available commands.").strict().help().parse();
|
|
5155
|
+
}).demandCommand(1, "Run `holocron upgrade --help` to see available upgrade subcommands."), () => {}).command("auth <subcommand>", "Manage bootstrap credentials in the OS keyring", (y) => y.command("set <provider> [value]", "Verify + store a bootstrap token for a provider", (yy) => yy.positional("provider", {
|
|
5156
|
+
type: "string",
|
|
5157
|
+
demandOption: true
|
|
5158
|
+
}).positional("value", { type: "string" }), async (argv) => {
|
|
5159
|
+
if ((await runAuthSet({
|
|
5160
|
+
provider: argv.provider,
|
|
5161
|
+
...argv.value ? { positional: argv.value } : {}
|
|
5162
|
+
})).status === "fail") process.exitCode = 1;
|
|
5163
|
+
}).command("unset <provider>", "Remove a stored bootstrap token", (yy) => yy.positional("provider", {
|
|
5164
|
+
type: "string",
|
|
5165
|
+
demandOption: true
|
|
5166
|
+
}), (argv) => {
|
|
5167
|
+
runAuthUnset({ provider: argv.provider });
|
|
5168
|
+
}).command("check <provider>", "Re-verify a stored bootstrap token", (yy) => yy.positional("provider", {
|
|
5169
|
+
type: "string",
|
|
5170
|
+
demandOption: true
|
|
5171
|
+
}), async (argv) => {
|
|
5172
|
+
if ((await runAuthCheck({ provider: argv.provider })).status === "fail") process.exitCode = 1;
|
|
5173
|
+
}).command("list", "List every provider with a stored bootstrap token", () => {}, async () => {
|
|
5174
|
+
await runAuthList();
|
|
5175
|
+
}).demandCommand(1, "Run `holocron auth --help` to see available auth subcommands."), () => {}).demandCommand(1, "Run `holocron --help` to see available commands.").strict().help().parse();
|
|
5176
|
+
} catch (err) {
|
|
5177
|
+
captureException(err);
|
|
5178
|
+
if (!process.exitCode) process.exitCode = 1;
|
|
5179
|
+
}
|
|
5180
|
+
finishCommand(!process.exitCode);
|
|
5181
|
+
endSession();
|
|
5110
5182
|
(await updateCheckPromise)?.();
|
|
5183
|
+
await flush();
|
|
5111
5184
|
/**
|
|
5112
5185
|
* Parse `--scope` strings: `repo` | `env=NAME` | `org=NAME`.
|
|
5113
5186
|
*/
|
|
@@ -5125,3 +5198,5 @@ function parseScope(s) {
|
|
|
5125
5198
|
}
|
|
5126
5199
|
//#endregion
|
|
5127
5200
|
export {};
|
|
5201
|
+
|
|
5202
|
+
//# sourceMappingURL=cli.mjs.map
|