@theholocron/cli 3.55.1 → 3.56.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 +106 -67
- package/dist/cli.mjs.map +1 -1
- package/package.json +3 -3
package/dist/cli.mjs
CHANGED
|
@@ -13,8 +13,8 @@ import ora from "ora";
|
|
|
13
13
|
import chalk from "chalk";
|
|
14
14
|
import { execFile, execFileSync, spawnSync } from "node:child_process";
|
|
15
15
|
import { homedir } from "node:os";
|
|
16
|
-
import { access, copyFile, mkdir, readFile, readdir, rm, stat, symlink, unlink, writeFile } from "node:fs/promises";
|
|
17
16
|
import { createLogger, parseLogLevel } from "@theholocron/logger";
|
|
17
|
+
import { access, copyFile, mkdir, readFile, readdir, rm, stat, symlink, unlink, writeFile } from "node:fs/promises";
|
|
18
18
|
import { createHash } from "node:crypto";
|
|
19
19
|
import { generateReadme } from "@theholocron/components-doc/markdown";
|
|
20
20
|
import { getClients, getConfigs, getDocs, getPlugins, getSkills, getThemes, getUtils } from "@theholocron/registry-doc";
|
|
@@ -896,6 +896,66 @@ async function runDeploy(input) {
|
|
|
896
896
|
}
|
|
897
897
|
}
|
|
898
898
|
//#endregion
|
|
899
|
+
//#region src/logger.ts
|
|
900
|
+
/**
|
|
901
|
+
* CLI-side wiring for `@theholocron/logger`.
|
|
902
|
+
*
|
|
903
|
+
* `logger` is the operational-output channel — internal state, debug
|
|
904
|
+
* traces, errors, structured context that routes to Axiom. It runs in
|
|
905
|
+
* parallel to `print` (user-facing UX output) and does not replace it.
|
|
906
|
+
*/
|
|
907
|
+
/**
|
|
908
|
+
* Resolve the explicit level to hand to `createLogger`, in priority order:
|
|
909
|
+
*
|
|
910
|
+
* 1. `--verbose` → `"debug"` 2. `--quiet` → `"error"`
|
|
911
|
+
* 3. `HOLOCRON_LOG_LEVEL` env var
|
|
912
|
+
* 4. `holocron.config` `log.level` (`configLevel`)
|
|
913
|
+
*
|
|
914
|
+
* Returns `undefined` when nothing applies — `createLogger` then defaults
|
|
915
|
+
* to `"info"`. Resolving the full chain here (rather than passing
|
|
916
|
+
* `configLevel` straight through) keeps config below the env var.
|
|
917
|
+
*/
|
|
918
|
+
function resolveLogLevel(argv, configLevel) {
|
|
919
|
+
if (argv.verbose) return "debug";
|
|
920
|
+
if (argv.quiet) return "error";
|
|
921
|
+
return parseLogLevel(env.get("HOLOCRON_LOG_LEVEL")) ?? configLevel;
|
|
922
|
+
}
|
|
923
|
+
let root;
|
|
924
|
+
let rootLevel;
|
|
925
|
+
let rootCommand;
|
|
926
|
+
/**
|
|
927
|
+
* The process-wide root logger. Built once (from `cli.ts`'s middleware,
|
|
928
|
+
* with the command name + flags + env). Rebuilt at most once more when a
|
|
929
|
+
* command's handler supplies its `holocron.config` `log.level` — a case
|
|
930
|
+
* the flag/env-only first pass could not have known — as long as no
|
|
931
|
+
* higher-priority `--verbose` / `--quiet` already fixed the level. That
|
|
932
|
+
* rebuild generates a fresh `runId`, which is harmless: nothing logs
|
|
933
|
+
* between the middleware and the handler.
|
|
934
|
+
*/
|
|
935
|
+
function buildCliLogger(argv, opts = {}) {
|
|
936
|
+
const { command, configLevel } = opts;
|
|
937
|
+
if (command) rootCommand = command;
|
|
938
|
+
const level = resolveLogLevel(argv, configLevel);
|
|
939
|
+
const rebuildForConfig = configLevel !== void 0 && level !== rootLevel && !argv.verbose && !argv.quiet;
|
|
940
|
+
if (!root || rebuildForConfig) {
|
|
941
|
+
const built = createLogger(level ? { level } : {});
|
|
942
|
+
root = {
|
|
943
|
+
logger: rootCommand ? built.logger.child({ command: rootCommand }) : built.logger,
|
|
944
|
+
runId: built.runId
|
|
945
|
+
};
|
|
946
|
+
rootLevel = level;
|
|
947
|
+
}
|
|
948
|
+
return root;
|
|
949
|
+
}
|
|
950
|
+
/** Lazily-memoized `Logger` for module-level call sites with no `argv` in scope. */
|
|
951
|
+
function getLogger() {
|
|
952
|
+
return (root ??= createLogger()).logger;
|
|
953
|
+
}
|
|
954
|
+
/** The current root logger's correlation id, if a root has been built. */
|
|
955
|
+
function getRunId() {
|
|
956
|
+
return root?.runId;
|
|
957
|
+
}
|
|
958
|
+
//#endregion
|
|
899
959
|
//#region src/commands/doctor.ts
|
|
900
960
|
async function runDoctor(input) {
|
|
901
961
|
const print = input.print ?? ((line) => console.log(line));
|
|
@@ -924,7 +984,14 @@ async function runDoctor(input) {
|
|
|
924
984
|
rows.push(row);
|
|
925
985
|
}
|
|
926
986
|
}
|
|
987
|
+
const log = getLogger();
|
|
927
988
|
for (const row of rows) {
|
|
989
|
+
log[row.status === "fail" ? "warn" : "info"]({
|
|
990
|
+
capability: row.capability,
|
|
991
|
+
provider: row.provider,
|
|
992
|
+
status: row.status,
|
|
993
|
+
detail: row.message
|
|
994
|
+
}, `doctor: ${row.capability}`);
|
|
928
995
|
const label = `${pad(row.capability, 14)} via ${pad(row.provider, 14)} ${row.message}`;
|
|
929
996
|
if (row.status === "ok") print(` ${style.success(label)}`);
|
|
930
997
|
else if (row.status === "fail") print(` ${style.fail(label)}`);
|
|
@@ -3112,59 +3179,6 @@ var dependabot_default = "version: 2\nupdates:\n - package-ecosystem: npm\n
|
|
|
3112
3179
|
//#region src/templates/labeler.yml
|
|
3113
3180
|
var labeler_default = "bug:\n - '^fix'\n\nchore:\n - '^chore(?!\\(deps)'\n\nci:\n - '^ci'\n\ndependencies:\n - '^chore\\(deps'\n\ndocumentation:\n - '^docs'\n\nenhancement:\n - '^feat'\n\nperformance:\n - '^perf'\n\nrefactor:\n - '^refactor'\n\ntest:\n - '^test'\n";
|
|
3114
3181
|
//#endregion
|
|
3115
|
-
//#region src/logger.ts
|
|
3116
|
-
/**
|
|
3117
|
-
* CLI-side wiring for `@theholocron/logger`.
|
|
3118
|
-
*
|
|
3119
|
-
* `logger` is the operational-output channel — internal state, debug
|
|
3120
|
-
* traces, errors, structured context that routes to Axiom. It runs in
|
|
3121
|
-
* parallel to `print` (user-facing UX output) and does not replace it.
|
|
3122
|
-
*/
|
|
3123
|
-
/**
|
|
3124
|
-
* Resolve the explicit level to hand to `createLogger`, in priority order:
|
|
3125
|
-
*
|
|
3126
|
-
* 1. `--verbose` → `"debug"` 2. `--quiet` → `"error"`
|
|
3127
|
-
* 3. `HOLOCRON_LOG_LEVEL` env var
|
|
3128
|
-
* 4. `holocron.config` `log.level` (`configLevel`)
|
|
3129
|
-
*
|
|
3130
|
-
* Returns `undefined` when nothing applies — `createLogger` then defaults
|
|
3131
|
-
* to `"info"`. Resolving the full chain here (rather than passing
|
|
3132
|
-
* `configLevel` straight through) keeps config below the env var.
|
|
3133
|
-
*/
|
|
3134
|
-
function resolveLogLevel(argv, configLevel) {
|
|
3135
|
-
if (argv.verbose) return "debug";
|
|
3136
|
-
if (argv.quiet) return "error";
|
|
3137
|
-
return parseLogLevel(env.get("HOLOCRON_LOG_LEVEL")) ?? configLevel;
|
|
3138
|
-
}
|
|
3139
|
-
let root;
|
|
3140
|
-
let rootLevel;
|
|
3141
|
-
/**
|
|
3142
|
-
* The process-wide root logger. Built once (from `cli.ts`'s middleware,
|
|
3143
|
-
* with flags + env only). Rebuilt at most once more when a command's
|
|
3144
|
-
* handler supplies its `holocron.config` `log.level` — a case the
|
|
3145
|
-
* flag/env-only first pass could not have known — as long as no
|
|
3146
|
-
* higher-priority `--verbose` / `--quiet` already fixed the level. That
|
|
3147
|
-
* rebuild generates a fresh `runId`, which is harmless: nothing logs
|
|
3148
|
-
* between the middleware and the handler.
|
|
3149
|
-
*/
|
|
3150
|
-
function buildCliLogger(argv, configLevel) {
|
|
3151
|
-
const level = resolveLogLevel(argv, configLevel);
|
|
3152
|
-
const rebuildForConfig = configLevel !== void 0 && level !== rootLevel && !argv.verbose && !argv.quiet;
|
|
3153
|
-
if (!root || rebuildForConfig) {
|
|
3154
|
-
root = createLogger(level ? { level } : {});
|
|
3155
|
-
rootLevel = level;
|
|
3156
|
-
}
|
|
3157
|
-
return root;
|
|
3158
|
-
}
|
|
3159
|
-
/** Lazily-memoized `Logger` for module-level call sites with no `argv` in scope. */
|
|
3160
|
-
function getLogger() {
|
|
3161
|
-
return (root ??= createLogger()).logger;
|
|
3162
|
-
}
|
|
3163
|
-
/** The current root logger's correlation id, if a root has been built. */
|
|
3164
|
-
function getRunId() {
|
|
3165
|
-
return root?.runId;
|
|
3166
|
-
}
|
|
3167
|
-
//#endregion
|
|
3168
3182
|
//#region src/commands/setup-workflows/index.ts
|
|
3169
3183
|
/**
|
|
3170
3184
|
* Thin workflow wrapper templates for `holocron setup`.
|
|
@@ -3989,6 +4003,18 @@ const BALANCED_REPO_SETTINGS = {
|
|
|
3989
4003
|
//#endregion
|
|
3990
4004
|
//#region src/commands/setup/run-step.ts
|
|
3991
4005
|
async function runStep(capability, step, dryRun, body, opts = {}) {
|
|
4006
|
+
const result = await execStep(capability, step, dryRun, body, opts);
|
|
4007
|
+
const { status, message, reason } = result;
|
|
4008
|
+
getLogger()[status === "fail" ? "warn" : "info"]({
|
|
4009
|
+
capability,
|
|
4010
|
+
step,
|
|
4011
|
+
status,
|
|
4012
|
+
...message ? { detail: message } : {},
|
|
4013
|
+
...reason ? { reason } : {}
|
|
4014
|
+
}, `${capability}.${step}`);
|
|
4015
|
+
return result;
|
|
4016
|
+
}
|
|
4017
|
+
async function execStep(capability, step, dryRun, body, opts = {}) {
|
|
3992
4018
|
if (dryRun) return {
|
|
3993
4019
|
capability,
|
|
3994
4020
|
step,
|
|
@@ -6164,14 +6190,26 @@ async function fileExists(path) {
|
|
|
6164
6190
|
}
|
|
6165
6191
|
//#endregion
|
|
6166
6192
|
//#region src/telemetry.ts
|
|
6167
|
-
const
|
|
6193
|
+
const FALLBACK_DSN = "https://95cbb72ad5636c94e119a5405ee8f55f@o4508238154104832.ingest.us.sentry.io/4511810950791168";
|
|
6194
|
+
/**
|
|
6195
|
+
* Resolve the Sentry DSN — the `errors` capability's self-contained
|
|
6196
|
+
* activation, per ADR-0007:
|
|
6197
|
+
*
|
|
6198
|
+
* HOLOCRON_SENTRY_DSN → SENTRY_DSN → built-in fallback
|
|
6199
|
+
*
|
|
6200
|
+
* A consumer repo with `SENTRY_DSN` set gets CLI errors routed to its own
|
|
6201
|
+
* project with no config. Opt out entirely with `HOLOCRON_TELEMETRY=false`.
|
|
6202
|
+
*/
|
|
6203
|
+
function resolveDsn() {
|
|
6204
|
+
return env.get("HOLOCRON_SENTRY_DSN") ?? env.get("SENTRY_DSN") ?? FALLBACK_DSN;
|
|
6205
|
+
}
|
|
6168
6206
|
function isEnabled() {
|
|
6169
|
-
return !(env.get("HOLOCRON_TELEMETRY") === "false" || Boolean(env.get("NO_HOLOCRON_TELEMETRY"))) &&
|
|
6207
|
+
return !(env.get("HOLOCRON_TELEMETRY") === "false" || Boolean(env.get("NO_HOLOCRON_TELEMETRY"))) && resolveDsn() !== "";
|
|
6170
6208
|
}
|
|
6171
6209
|
function init(version) {
|
|
6172
6210
|
if (!isEnabled()) return;
|
|
6173
6211
|
Sentry.init({
|
|
6174
|
-
dsn:
|
|
6212
|
+
dsn: resolveDsn(),
|
|
6175
6213
|
release: `holocron@${version}`,
|
|
6176
6214
|
environment: env.get("CI") ? "ci" : "local",
|
|
6177
6215
|
tracesSampleRate: 1,
|
|
@@ -6394,9 +6432,10 @@ try {
|
|
|
6394
6432
|
default: false,
|
|
6395
6433
|
describe: "Set the log level to error — suppress info and warn."
|
|
6396
6434
|
}).middleware((argv) => {
|
|
6397
|
-
|
|
6435
|
+
const name = argv._.slice(0, 2).join(" ") || "unknown";
|
|
6436
|
+
finishCommand = startCommand(name);
|
|
6398
6437
|
printRunId = Boolean(argv.debug || argv.verbose);
|
|
6399
|
-
buildCliLogger(argv);
|
|
6438
|
+
buildCliLogger(argv, { command: name });
|
|
6400
6439
|
}).command("version", "Print the CLI version", () => {}, () => {
|
|
6401
6440
|
console.log(`holocron ${CLI_VERSION}`);
|
|
6402
6441
|
}).command("clone", "Clone all repos in a GitHub org as siblings under a single directory", (y) => y.option("org", {
|
|
@@ -6430,7 +6469,7 @@ try {
|
|
|
6430
6469
|
const tokens = tokenContext(argv.token);
|
|
6431
6470
|
if (!tokens) return;
|
|
6432
6471
|
const loaded = await loadConfig(argv.cwd);
|
|
6433
|
-
buildCliLogger(argv, loaded.resolved.log?.level);
|
|
6472
|
+
buildCliLogger(argv, { configLevel: loaded.resolved.log?.level });
|
|
6434
6473
|
if ((await runDoctor({
|
|
6435
6474
|
loaded,
|
|
6436
6475
|
context: {
|
|
@@ -6448,7 +6487,7 @@ try {
|
|
|
6448
6487
|
const tokens = tokenContext(argv.token);
|
|
6449
6488
|
if (!tokens) return;
|
|
6450
6489
|
const loaded = await loadConfig(argv.cwd);
|
|
6451
|
-
buildCliLogger(argv, loaded.resolved.log?.level);
|
|
6490
|
+
buildCliLogger(argv, { configLevel: loaded.resolved.log?.level });
|
|
6452
6491
|
if ((await runSetup({
|
|
6453
6492
|
loaded,
|
|
6454
6493
|
context: {
|
|
@@ -6514,7 +6553,7 @@ try {
|
|
|
6514
6553
|
const scopeArg = argv.scope;
|
|
6515
6554
|
const scope = parseScope(scopeArg);
|
|
6516
6555
|
const loaded = await loadConfig(argv.cwd);
|
|
6517
|
-
buildCliLogger(argv, loaded.resolved.log?.level);
|
|
6556
|
+
buildCliLogger(argv, { configLevel: loaded.resolved.log?.level });
|
|
6518
6557
|
if ((await runSecretSet({
|
|
6519
6558
|
loaded,
|
|
6520
6559
|
context: {
|
|
@@ -6544,7 +6583,7 @@ try {
|
|
|
6544
6583
|
const tokens = tokenContext(argv.token);
|
|
6545
6584
|
if (!tokens) return;
|
|
6546
6585
|
const loaded = await loadConfig(argv.cwd);
|
|
6547
|
-
buildCliLogger(argv, loaded.resolved.log?.level);
|
|
6586
|
+
buildCliLogger(argv, { configLevel: loaded.resolved.log?.level });
|
|
6548
6587
|
if ((await runSecretsSync({
|
|
6549
6588
|
loaded,
|
|
6550
6589
|
context: {
|
|
@@ -6573,7 +6612,7 @@ try {
|
|
|
6573
6612
|
const tokens = tokenContext(argv.token);
|
|
6574
6613
|
if (!tokens) return;
|
|
6575
6614
|
const loaded = await loadConfig(argv.cwd);
|
|
6576
|
-
buildCliLogger(argv, loaded.resolved.log?.level);
|
|
6615
|
+
buildCliLogger(argv, { configLevel: loaded.resolved.log?.level });
|
|
6577
6616
|
if ((await runDeploy({
|
|
6578
6617
|
loaded,
|
|
6579
6618
|
context: {
|
|
@@ -6601,7 +6640,7 @@ try {
|
|
|
6601
6640
|
const tokens = tokenContext(argv.token);
|
|
6602
6641
|
if (!tokens) return;
|
|
6603
6642
|
const loaded = await loadConfig(argv.cwd);
|
|
6604
|
-
buildCliLogger(argv, loaded.resolved.log?.level);
|
|
6643
|
+
buildCliLogger(argv, { configLevel: loaded.resolved.log?.level });
|
|
6605
6644
|
if ((await runCleanupPreview({
|
|
6606
6645
|
loaded,
|
|
6607
6646
|
context: {
|
|
@@ -6649,7 +6688,7 @@ try {
|
|
|
6649
6688
|
const tokens = tokenContext(argv.token);
|
|
6650
6689
|
if (!tokens) return;
|
|
6651
6690
|
const loaded = await loadConfig(argv.cwd);
|
|
6652
|
-
buildCliLogger(argv, loaded.resolved.log?.level);
|
|
6691
|
+
buildCliLogger(argv, { configLevel: loaded.resolved.log?.level });
|
|
6653
6692
|
if ((await runSync({
|
|
6654
6693
|
loaded,
|
|
6655
6694
|
context: {
|
|
@@ -6706,7 +6745,7 @@ try {
|
|
|
6706
6745
|
default: false
|
|
6707
6746
|
}), async (argv) => {
|
|
6708
6747
|
const loaded = await loadConfig(argv.cwd);
|
|
6709
|
-
buildCliLogger(argv, loaded.resolved.log?.level);
|
|
6748
|
+
buildCliLogger(argv, { configLevel: loaded.resolved.log?.level });
|
|
6710
6749
|
if ((await runSyncReadme({
|
|
6711
6750
|
loaded,
|
|
6712
6751
|
context: {
|