@theholocron/cli 3.60.0 → 3.62.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 +357 -106
- package/dist/cli.mjs.map +1 -1
- package/package.json +3 -3
package/dist/cli.mjs
CHANGED
|
@@ -9,9 +9,9 @@ import { AuthError, ProviderApiError, ProviderApiError as ProviderApiError$1, cr
|
|
|
9
9
|
import { createEnvLookup } from "@theholocron/env-utils";
|
|
10
10
|
import { Entry, findCredentials } from "@napi-rs/keyring";
|
|
11
11
|
import { pathToFileURL } from "node:url";
|
|
12
|
+
import { createLogger, parseLogLevel, resolveAxiomFromEnv } from "@theholocron/logger";
|
|
12
13
|
import ora from "ora";
|
|
13
14
|
import chalk from "chalk";
|
|
14
|
-
import { createLogger, parseLogLevel, resolveAxiomFromEnv } from "@theholocron/logger";
|
|
15
15
|
import { execFile, execFileSync, spawnSync } from "node:child_process";
|
|
16
16
|
import { homedir } from "node:os";
|
|
17
17
|
import { access, copyFile, mkdir, readFile, readdir, rm, stat, symlink, unlink, writeFile } from "node:fs/promises";
|
|
@@ -288,6 +288,94 @@ function resolveConfig(raw) {
|
|
|
288
288
|
};
|
|
289
289
|
}
|
|
290
290
|
//#endregion
|
|
291
|
+
//#region src/logger.ts
|
|
292
|
+
/**
|
|
293
|
+
* CLI-side wiring for `@theholocron/logger`.
|
|
294
|
+
*
|
|
295
|
+
* `logger` is the operational-output channel — internal state, debug
|
|
296
|
+
* traces, errors, structured context that routes to Axiom. It runs in
|
|
297
|
+
* parallel to `print` (user-facing UX output) and does not replace it.
|
|
298
|
+
*/
|
|
299
|
+
/**
|
|
300
|
+
* Resolve the explicit level to hand to `createLogger`, in priority order:
|
|
301
|
+
*
|
|
302
|
+
* 1. `--verbose` → `"debug"` 2. `--quiet` → `"error"`
|
|
303
|
+
* 3. `HOLOCRON_LOG_LEVEL` env var
|
|
304
|
+
* 4. `holocron.config` `log.level` (`configLevel`)
|
|
305
|
+
*
|
|
306
|
+
* Returns `undefined` when nothing applies — `createLogger` then defaults
|
|
307
|
+
* to `"info"`. Resolving the full chain here (rather than passing
|
|
308
|
+
* `configLevel` straight through) keeps config below the env var.
|
|
309
|
+
*/
|
|
310
|
+
function resolveLogLevel(argv, configLevel) {
|
|
311
|
+
if (argv.verbose) return "debug";
|
|
312
|
+
if (argv.quiet) return "error";
|
|
313
|
+
return parseLogLevel(env.get("HOLOCRON_LOG_LEVEL")) ?? configLevel;
|
|
314
|
+
}
|
|
315
|
+
let root;
|
|
316
|
+
let rootLevel;
|
|
317
|
+
let rootCommand;
|
|
318
|
+
let rootAxiomKey;
|
|
319
|
+
/**
|
|
320
|
+
* Resolve Axiom credentials for the CLI. Env vars win — same contract as
|
|
321
|
+
* `@theholocron/logger`'s `resolveAxiomFromEnv`. Failing that, the CLI-only
|
|
322
|
+
* bridge pairs the OS-keyring token (`axiom.<org>` then bare `axiom`) with a
|
|
323
|
+
* dataset from `HOLOCRON_AXIOM_DATASET` / `AXIOM_DATASET` or
|
|
324
|
+
* `holocron.config` `log.axiom.dataset`. Returns `undefined` unless both a
|
|
325
|
+
* token and a dataset are found.
|
|
326
|
+
*/
|
|
327
|
+
function resolveCliAxiom(opts) {
|
|
328
|
+
const fromEnv = resolveAxiomFromEnv();
|
|
329
|
+
if (fromEnv) return fromEnv;
|
|
330
|
+
const dataset = env.get("HOLOCRON_AXIOM_DATASET") || env.get("AXIOM_DATASET") || opts.configAxiomDataset;
|
|
331
|
+
if (!dataset) return void 0;
|
|
332
|
+
const org = opts.org ?? env.get("HOLOCRON_ORG");
|
|
333
|
+
const token = (org ? getToken(`axiom.${org}`) : null) ?? getToken("axiom");
|
|
334
|
+
return token ? {
|
|
335
|
+
dataset,
|
|
336
|
+
token
|
|
337
|
+
} : void 0;
|
|
338
|
+
}
|
|
339
|
+
/**
|
|
340
|
+
* The process-wide root logger. Built once (from `cli.ts`'s middleware,
|
|
341
|
+
* with the command name + flags + env). Rebuilt at most once more when a
|
|
342
|
+
* command's handler supplies `holocron.config` context the flag/env-only
|
|
343
|
+
* first pass could not have known — `log.level` (unless `--verbose` /
|
|
344
|
+
* `--quiet` already fixed it) or `log.axiom.dataset` + the resolved org
|
|
345
|
+
* for a keyring-backed Axiom transport. That rebuild generates a fresh
|
|
346
|
+
* `runId`, which is harmless: nothing logs between the middleware and the
|
|
347
|
+
* handler.
|
|
348
|
+
*/
|
|
349
|
+
function buildCliLogger(argv, opts = {}) {
|
|
350
|
+
const { command, configLevel } = opts;
|
|
351
|
+
if (command) rootCommand = command;
|
|
352
|
+
const level = resolveLogLevel(argv, configLevel);
|
|
353
|
+
const axiom = resolveCliAxiom(opts);
|
|
354
|
+
const axiomKey = axiom?.dataset;
|
|
355
|
+
const rebuildForConfig = configLevel !== void 0 && level !== rootLevel && !argv.verbose && !argv.quiet;
|
|
356
|
+
if (!root || rebuildForConfig || axiomKey !== void 0 && axiomKey !== rootAxiomKey) {
|
|
357
|
+
const built = createLogger({
|
|
358
|
+
...level ? { level } : {},
|
|
359
|
+
...axiom ? { axiom } : {}
|
|
360
|
+
});
|
|
361
|
+
root = {
|
|
362
|
+
logger: rootCommand ? built.logger.child({ command: rootCommand }) : built.logger,
|
|
363
|
+
runId: built.runId
|
|
364
|
+
};
|
|
365
|
+
rootLevel = level;
|
|
366
|
+
rootAxiomKey = axiomKey;
|
|
367
|
+
}
|
|
368
|
+
return root;
|
|
369
|
+
}
|
|
370
|
+
/** Lazily-memoized `Logger` for module-level call sites with no `argv` in scope. */
|
|
371
|
+
function getLogger() {
|
|
372
|
+
return (root ??= createLogger()).logger;
|
|
373
|
+
}
|
|
374
|
+
/** The current root logger's correlation id, if a root has been built. */
|
|
375
|
+
function getRunId() {
|
|
376
|
+
return root?.runId;
|
|
377
|
+
}
|
|
378
|
+
//#endregion
|
|
291
379
|
//#region src/ui/progress.ts
|
|
292
380
|
/**
|
|
293
381
|
* Runs `fn`, showing an ora spinner for its duration in TTY environments.
|
|
@@ -356,6 +444,7 @@ function resolveAuthSetToken(input) {
|
|
|
356
444
|
}
|
|
357
445
|
async function runAuthSet(input) {
|
|
358
446
|
const print = input.print ?? ((l) => console.log(l));
|
|
447
|
+
const logger = input.logger ?? getLogger();
|
|
359
448
|
const importer = input.importer ?? defaultImporter$1;
|
|
360
449
|
const { provider } = input;
|
|
361
450
|
const keyringKey = input.org ? `${provider}.${input.org}` : provider;
|
|
@@ -374,6 +463,11 @@ async function runAuthSet(input) {
|
|
|
374
463
|
const hint = await tryLoadHint(importer, packageName);
|
|
375
464
|
if (hint) print(style.hint(` hint: ${hint}`));
|
|
376
465
|
}
|
|
466
|
+
logger.warn({
|
|
467
|
+
provider,
|
|
468
|
+
keyringKey,
|
|
469
|
+
reason: "no token supplied"
|
|
470
|
+
}, `auth set: ${keyringKey}`);
|
|
377
471
|
return {
|
|
378
472
|
status: "fail",
|
|
379
473
|
message: "no token supplied"
|
|
@@ -387,6 +481,12 @@ async function runAuthSet(input) {
|
|
|
387
481
|
if (!verified.ok) {
|
|
388
482
|
print(style.fail(`token rejected by ${provider}: ${verified.message}`));
|
|
389
483
|
if (module.AUTH_HINT) print(style.hint(` hint: ${module.AUTH_HINT}`));
|
|
484
|
+
logger.warn({
|
|
485
|
+
provider,
|
|
486
|
+
keyringKey,
|
|
487
|
+
verified: false,
|
|
488
|
+
reason: verified.message
|
|
489
|
+
}, `auth set: ${keyringKey}`);
|
|
390
490
|
return {
|
|
391
491
|
status: "fail",
|
|
392
492
|
message: verified.message
|
|
@@ -401,12 +501,24 @@ async function runAuthSet(input) {
|
|
|
401
501
|
}
|
|
402
502
|
if (!setToken(keyringKey, token)) {
|
|
403
503
|
print(style.fail(`keyring unavailable — token not stored. Use env vars instead.`));
|
|
504
|
+
logger.warn({
|
|
505
|
+
provider,
|
|
506
|
+
keyringKey,
|
|
507
|
+
reason: "keyring unavailable"
|
|
508
|
+
}, `auth set: ${keyringKey}`);
|
|
404
509
|
return {
|
|
405
510
|
status: "fail",
|
|
406
511
|
message: "keyring unavailable"
|
|
407
512
|
};
|
|
408
513
|
}
|
|
409
514
|
print(style.success(`stored ${keyringKey} token${subject ? ` (${subject})` : ""}`));
|
|
515
|
+
logger.info({
|
|
516
|
+
provider,
|
|
517
|
+
keyringKey,
|
|
518
|
+
verified: subject !== void 0,
|
|
519
|
+
...subject ? { subject } : {},
|
|
520
|
+
status: "ok"
|
|
521
|
+
}, `auth set: ${keyringKey}`);
|
|
410
522
|
return {
|
|
411
523
|
status: "ok",
|
|
412
524
|
...subject ? { message: subject } : {}
|
|
@@ -414,11 +526,20 @@ async function runAuthSet(input) {
|
|
|
414
526
|
}
|
|
415
527
|
function runAuthUnset(input) {
|
|
416
528
|
const print = input.print ?? ((l) => console.log(l));
|
|
529
|
+
const logger = input.logger ?? getLogger();
|
|
417
530
|
if (deleteToken(input.provider)) {
|
|
418
531
|
print(style.success(`removed ${input.provider} token`));
|
|
532
|
+
logger.info({
|
|
533
|
+
provider: input.provider,
|
|
534
|
+
status: "ok"
|
|
535
|
+
}, `auth unset: ${input.provider}`);
|
|
419
536
|
return { status: "ok" };
|
|
420
537
|
}
|
|
421
538
|
print(style.dim(`no stored token for ${input.provider}`));
|
|
539
|
+
logger.info({
|
|
540
|
+
provider: input.provider,
|
|
541
|
+
status: "skip"
|
|
542
|
+
}, `auth unset: ${input.provider}`);
|
|
422
543
|
return {
|
|
423
544
|
status: "skip",
|
|
424
545
|
message: "nothing to remove"
|
|
@@ -426,12 +547,19 @@ function runAuthUnset(input) {
|
|
|
426
547
|
}
|
|
427
548
|
async function runAuthCheck(input) {
|
|
428
549
|
const print = input.print ?? ((l) => console.log(l));
|
|
550
|
+
const logger = input.logger ?? getLogger();
|
|
429
551
|
const importer = input.importer ?? defaultImporter$1;
|
|
430
552
|
const { provider } = input;
|
|
431
553
|
const keyringKey = input.org ? `${provider}.${input.org}` : provider;
|
|
432
554
|
const token = getToken(keyringKey);
|
|
433
555
|
if (!token) {
|
|
434
556
|
print(style.dim(`no stored token for ${keyringKey}`));
|
|
557
|
+
logger.info({
|
|
558
|
+
provider,
|
|
559
|
+
keyringKey,
|
|
560
|
+
status: "skip",
|
|
561
|
+
reason: "no stored token"
|
|
562
|
+
}, `auth check: ${keyringKey}`);
|
|
435
563
|
return {
|
|
436
564
|
status: "skip",
|
|
437
565
|
message: "no stored token"
|
|
@@ -458,6 +586,13 @@ async function runAuthCheck(input) {
|
|
|
458
586
|
const verified = input.showSpinner !== false ? await withSpinner(`Verifying ${keyringKey} token…`, verify) : await verify();
|
|
459
587
|
if (verified.ok) {
|
|
460
588
|
print(style.success(`${keyringKey}: ok — ${verified.subject}`));
|
|
589
|
+
logger.info({
|
|
590
|
+
provider,
|
|
591
|
+
keyringKey,
|
|
592
|
+
verified: true,
|
|
593
|
+
subject: verified.subject,
|
|
594
|
+
status: "ok"
|
|
595
|
+
}, `auth check: ${keyringKey}`);
|
|
461
596
|
return {
|
|
462
597
|
status: "ok",
|
|
463
598
|
message: verified.subject
|
|
@@ -465,6 +600,13 @@ async function runAuthCheck(input) {
|
|
|
465
600
|
}
|
|
466
601
|
print(style.fail(`${keyringKey}: rejected — ${verified.message}`));
|
|
467
602
|
if (module.AUTH_HINT) print(style.hint(` hint: ${module.AUTH_HINT}`));
|
|
603
|
+
logger.warn({
|
|
604
|
+
provider,
|
|
605
|
+
keyringKey,
|
|
606
|
+
verified: false,
|
|
607
|
+
reason: verified.message,
|
|
608
|
+
status: "fail"
|
|
609
|
+
}, `auth check: ${keyringKey}`);
|
|
468
610
|
return {
|
|
469
611
|
status: "fail",
|
|
470
612
|
message: verified.message
|
|
@@ -472,6 +614,12 @@ async function runAuthCheck(input) {
|
|
|
472
614
|
} catch (err) {
|
|
473
615
|
const msg = err instanceof Error ? err.message : String(err);
|
|
474
616
|
print(style.fail(`${keyringKey}: cannot verify — ${msg}`));
|
|
617
|
+
logger.warn({
|
|
618
|
+
provider,
|
|
619
|
+
keyringKey,
|
|
620
|
+
reason: msg,
|
|
621
|
+
status: "fail"
|
|
622
|
+
}, `auth check: ${keyringKey}`);
|
|
475
623
|
return {
|
|
476
624
|
status: "fail",
|
|
477
625
|
message: msg
|
|
@@ -480,28 +628,42 @@ async function runAuthCheck(input) {
|
|
|
480
628
|
}
|
|
481
629
|
async function runAuthList(input = {}) {
|
|
482
630
|
const print = input.print ?? ((l) => console.log(l));
|
|
631
|
+
const logger = input.logger ?? getLogger();
|
|
483
632
|
const importer = input.importer ?? defaultImporter$1;
|
|
484
633
|
const providers = listStoredProviders();
|
|
485
634
|
if (providers.length === 0) {
|
|
486
635
|
print(style.dim("no stored tokens."));
|
|
487
636
|
print(style.hint("run: holocron auth set <provider> <token>"));
|
|
637
|
+
logger.info({ providers: 0 }, "auth list: done");
|
|
488
638
|
return {
|
|
489
639
|
status: "ok",
|
|
490
640
|
message: "none"
|
|
491
641
|
};
|
|
492
642
|
}
|
|
643
|
+
let ok = 0;
|
|
644
|
+
let fail = 0;
|
|
493
645
|
for (const provider of providers.sort()) {
|
|
494
646
|
const check = await runAuthCheck({
|
|
495
647
|
provider,
|
|
496
648
|
importer,
|
|
497
649
|
print: () => {},
|
|
650
|
+
logger,
|
|
498
651
|
showSpinner: false
|
|
499
652
|
});
|
|
500
653
|
const label = `${provider}${check.message ? ` — ${check.message}` : ""}`;
|
|
501
|
-
if (check.status === "ok")
|
|
502
|
-
|
|
503
|
-
|
|
654
|
+
if (check.status === "ok") {
|
|
655
|
+
ok += 1;
|
|
656
|
+
print(` ${style.success(label)}`);
|
|
657
|
+
} else if (check.status === "fail") {
|
|
658
|
+
fail += 1;
|
|
659
|
+
print(` ${style.fail(label)}`);
|
|
660
|
+
} else print(` ${style.dim(`· ${label}`)}`);
|
|
504
661
|
}
|
|
662
|
+
logger.info({
|
|
663
|
+
providers: providers.length,
|
|
664
|
+
ok,
|
|
665
|
+
fail
|
|
666
|
+
}, "auth list: done");
|
|
505
667
|
return { status: "ok" };
|
|
506
668
|
}
|
|
507
669
|
async function tryLoadHint(importer, packageName) {
|
|
@@ -512,94 +674,6 @@ async function tryLoadHint(importer, packageName) {
|
|
|
512
674
|
}
|
|
513
675
|
}
|
|
514
676
|
//#endregion
|
|
515
|
-
//#region src/logger.ts
|
|
516
|
-
/**
|
|
517
|
-
* CLI-side wiring for `@theholocron/logger`.
|
|
518
|
-
*
|
|
519
|
-
* `logger` is the operational-output channel — internal state, debug
|
|
520
|
-
* traces, errors, structured context that routes to Axiom. It runs in
|
|
521
|
-
* parallel to `print` (user-facing UX output) and does not replace it.
|
|
522
|
-
*/
|
|
523
|
-
/**
|
|
524
|
-
* Resolve the explicit level to hand to `createLogger`, in priority order:
|
|
525
|
-
*
|
|
526
|
-
* 1. `--verbose` → `"debug"` 2. `--quiet` → `"error"`
|
|
527
|
-
* 3. `HOLOCRON_LOG_LEVEL` env var
|
|
528
|
-
* 4. `holocron.config` `log.level` (`configLevel`)
|
|
529
|
-
*
|
|
530
|
-
* Returns `undefined` when nothing applies — `createLogger` then defaults
|
|
531
|
-
* to `"info"`. Resolving the full chain here (rather than passing
|
|
532
|
-
* `configLevel` straight through) keeps config below the env var.
|
|
533
|
-
*/
|
|
534
|
-
function resolveLogLevel(argv, configLevel) {
|
|
535
|
-
if (argv.verbose) return "debug";
|
|
536
|
-
if (argv.quiet) return "error";
|
|
537
|
-
return parseLogLevel(env.get("HOLOCRON_LOG_LEVEL")) ?? configLevel;
|
|
538
|
-
}
|
|
539
|
-
let root;
|
|
540
|
-
let rootLevel;
|
|
541
|
-
let rootCommand;
|
|
542
|
-
let rootAxiomKey;
|
|
543
|
-
/**
|
|
544
|
-
* Resolve Axiom credentials for the CLI. Env vars win — same contract as
|
|
545
|
-
* `@theholocron/logger`'s `resolveAxiomFromEnv`. Failing that, the CLI-only
|
|
546
|
-
* bridge pairs the OS-keyring token (`axiom.<org>` then bare `axiom`) with a
|
|
547
|
-
* dataset from `HOLOCRON_AXIOM_DATASET` / `AXIOM_DATASET` or
|
|
548
|
-
* `holocron.config` `log.axiom.dataset`. Returns `undefined` unless both a
|
|
549
|
-
* token and a dataset are found.
|
|
550
|
-
*/
|
|
551
|
-
function resolveCliAxiom(opts) {
|
|
552
|
-
const fromEnv = resolveAxiomFromEnv();
|
|
553
|
-
if (fromEnv) return fromEnv;
|
|
554
|
-
const dataset = env.get("HOLOCRON_AXIOM_DATASET") || env.get("AXIOM_DATASET") || opts.configAxiomDataset;
|
|
555
|
-
if (!dataset) return void 0;
|
|
556
|
-
const org = opts.org ?? env.get("HOLOCRON_ORG");
|
|
557
|
-
const token = (org ? getToken(`axiom.${org}`) : null) ?? getToken("axiom");
|
|
558
|
-
return token ? {
|
|
559
|
-
dataset,
|
|
560
|
-
token
|
|
561
|
-
} : void 0;
|
|
562
|
-
}
|
|
563
|
-
/**
|
|
564
|
-
* The process-wide root logger. Built once (from `cli.ts`'s middleware,
|
|
565
|
-
* with the command name + flags + env). Rebuilt at most once more when a
|
|
566
|
-
* command's handler supplies `holocron.config` context the flag/env-only
|
|
567
|
-
* first pass could not have known — `log.level` (unless `--verbose` /
|
|
568
|
-
* `--quiet` already fixed it) or `log.axiom.dataset` + the resolved org
|
|
569
|
-
* for a keyring-backed Axiom transport. That rebuild generates a fresh
|
|
570
|
-
* `runId`, which is harmless: nothing logs between the middleware and the
|
|
571
|
-
* handler.
|
|
572
|
-
*/
|
|
573
|
-
function buildCliLogger(argv, opts = {}) {
|
|
574
|
-
const { command, configLevel } = opts;
|
|
575
|
-
if (command) rootCommand = command;
|
|
576
|
-
const level = resolveLogLevel(argv, configLevel);
|
|
577
|
-
const axiom = resolveCliAxiom(opts);
|
|
578
|
-
const axiomKey = axiom?.dataset;
|
|
579
|
-
const rebuildForConfig = configLevel !== void 0 && level !== rootLevel && !argv.verbose && !argv.quiet;
|
|
580
|
-
if (!root || rebuildForConfig || axiomKey !== void 0 && axiomKey !== rootAxiomKey) {
|
|
581
|
-
const built = createLogger({
|
|
582
|
-
...level ? { level } : {},
|
|
583
|
-
...axiom ? { axiom } : {}
|
|
584
|
-
});
|
|
585
|
-
root = {
|
|
586
|
-
logger: rootCommand ? built.logger.child({ command: rootCommand }) : built.logger,
|
|
587
|
-
runId: built.runId
|
|
588
|
-
};
|
|
589
|
-
rootLevel = level;
|
|
590
|
-
rootAxiomKey = axiomKey;
|
|
591
|
-
}
|
|
592
|
-
return root;
|
|
593
|
-
}
|
|
594
|
-
/** Lazily-memoized `Logger` for module-level call sites with no `argv` in scope. */
|
|
595
|
-
function getLogger() {
|
|
596
|
-
return (root ??= createLogger()).logger;
|
|
597
|
-
}
|
|
598
|
-
/** The current root logger's correlation id, if a root has been built. */
|
|
599
|
-
function getRunId() {
|
|
600
|
-
return root?.runId;
|
|
601
|
-
}
|
|
602
|
-
//#endregion
|
|
603
677
|
//#region src/plugin/loader.ts
|
|
604
678
|
/**
|
|
605
679
|
* `PluginLoader` — loads provider plugins per the resolved config and
|
|
@@ -928,9 +1002,15 @@ async function listOrgRepos(org, token, fetchFn) {
|
|
|
928
1002
|
}
|
|
929
1003
|
async function runClone(input) {
|
|
930
1004
|
const print = input.print ?? ((line) => console.log(line));
|
|
1005
|
+
const logger = input.logger ?? getLogger();
|
|
931
1006
|
const fetchFn = input.fetch ?? globalThis.fetch;
|
|
932
1007
|
const dryRun = input.dryRun ?? false;
|
|
933
1008
|
const targetDir = resolve(input.dir ?? join(homedir(), "Code", input.org));
|
|
1009
|
+
logger.info({
|
|
1010
|
+
org: input.org,
|
|
1011
|
+
targetDir,
|
|
1012
|
+
dryRun: dryRun || void 0
|
|
1013
|
+
}, "clone: start");
|
|
934
1014
|
const exec = input.exec ?? ((cmd, args, opts) => {
|
|
935
1015
|
return { status: spawnSync(cmd, args, {
|
|
936
1016
|
cwd: opts.cwd,
|
|
@@ -944,12 +1024,17 @@ async function runClone(input) {
|
|
|
944
1024
|
try {
|
|
945
1025
|
repos = await listOrgRepos(input.org, input.token, fetchFn);
|
|
946
1026
|
} catch (err) {
|
|
1027
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
1028
|
+
logger.warn({
|
|
1029
|
+
org: input.org,
|
|
1030
|
+
reason: message
|
|
1031
|
+
}, "clone: failed to list org repos");
|
|
947
1032
|
return {
|
|
948
1033
|
status: "fail",
|
|
949
1034
|
cloned: 0,
|
|
950
1035
|
skipped: 0,
|
|
951
1036
|
failed: 0,
|
|
952
|
-
message
|
|
1037
|
+
message
|
|
953
1038
|
};
|
|
954
1039
|
}
|
|
955
1040
|
let cloned = 0;
|
|
@@ -997,8 +1082,16 @@ async function runClone(input) {
|
|
|
997
1082
|
}
|
|
998
1083
|
const summary = `${cloned} cloned, ${skipped} skipped, ${failed} failed`;
|
|
999
1084
|
print(dryRun ? style.dim(`\n dry-run: ${summary}`) : failed > 0 ? style.fail(`\n ${summary}`) : style.success(`\n ${summary}`));
|
|
1085
|
+
const status = dryRun ? "dry-run" : failed > 0 ? "fail" : "ok";
|
|
1086
|
+
logger[failed > 0 ? "warn" : "info"]({
|
|
1087
|
+
org: input.org,
|
|
1088
|
+
status,
|
|
1089
|
+
cloned,
|
|
1090
|
+
skipped,
|
|
1091
|
+
failed
|
|
1092
|
+
}, "clone: done");
|
|
1000
1093
|
return {
|
|
1001
|
-
status
|
|
1094
|
+
status,
|
|
1002
1095
|
cloned,
|
|
1003
1096
|
skipped,
|
|
1004
1097
|
failed
|
|
@@ -1384,6 +1477,7 @@ async function runNew(input) {
|
|
|
1384
1477
|
const cwd = input.cwd ?? process.cwd();
|
|
1385
1478
|
const org = input.org ?? "theholocron";
|
|
1386
1479
|
const print = input.print ?? ((line) => console.log(line));
|
|
1480
|
+
const logger = input.logger ?? getLogger();
|
|
1387
1481
|
const execFn = input.exec ?? defaultExec$3;
|
|
1388
1482
|
const readFn = input.readFile ?? defaultReadFile;
|
|
1389
1483
|
const writeFn = input.writeFile ?? defaultWriteFile;
|
|
@@ -1392,6 +1486,11 @@ async function runNew(input) {
|
|
|
1392
1486
|
const templateRepo = `${org}/${input.type}-template`;
|
|
1393
1487
|
const newRepo = `${org}/${input.name}`;
|
|
1394
1488
|
const repoDir = path.join(cwd, input.name);
|
|
1489
|
+
logger.info({
|
|
1490
|
+
repo: newRepo,
|
|
1491
|
+
template: templateRepo,
|
|
1492
|
+
dryRun: input.dryRun || void 0
|
|
1493
|
+
}, "new: start");
|
|
1395
1494
|
if (input.dryRun) {
|
|
1396
1495
|
print(` Would create ${newRepo} from template ${templateRepo}`);
|
|
1397
1496
|
print(` Would clone to ${repoDir}`);
|
|
@@ -1400,6 +1499,10 @@ async function runNew(input) {
|
|
|
1400
1499
|
if (input.homepage) print(` Would replace <homepage> → "${input.homepage}"`);
|
|
1401
1500
|
if (input.runtimeEnvironment) print(` Would replace <runtime_environment> → "${input.runtimeEnvironment}"`);
|
|
1402
1501
|
print(` Would generate holocron.config.ts`);
|
|
1502
|
+
logger.info({
|
|
1503
|
+
repo: newRepo,
|
|
1504
|
+
status: "dry-run"
|
|
1505
|
+
}, "new: done");
|
|
1403
1506
|
return { status: "dry-run" };
|
|
1404
1507
|
}
|
|
1405
1508
|
if (existsSync(repoDir)) throw new NewError(`\`${repoDir}\` already exists — delete it or pick a different name.`);
|
|
@@ -1555,6 +1658,12 @@ async function runNew(input) {
|
|
|
1555
1658
|
print(` 3. holocron setup # wire up secrets, teams, labels, etc.`);
|
|
1556
1659
|
print(` 4. git push -u origin HEAD`);
|
|
1557
1660
|
} else print(` 2. git push -u origin HEAD`);
|
|
1661
|
+
logger.info({
|
|
1662
|
+
repo: newRepo,
|
|
1663
|
+
repoDir,
|
|
1664
|
+
filesPatched,
|
|
1665
|
+
status: "ok"
|
|
1666
|
+
}, "new: done");
|
|
1558
1667
|
return {
|
|
1559
1668
|
status: "ok",
|
|
1560
1669
|
repoDir,
|
|
@@ -1565,6 +1674,7 @@ async function runNew(input) {
|
|
|
1565
1674
|
//#region src/commands/npm-bump-versions.ts
|
|
1566
1675
|
async function runNpmBumpVersions(input) {
|
|
1567
1676
|
const print = input.print ?? ((line) => console.log(line));
|
|
1677
|
+
const logger = input.logger ?? getLogger();
|
|
1568
1678
|
const cwd = input.cwd ?? process.cwd();
|
|
1569
1679
|
const { version, dryRun = false } = input;
|
|
1570
1680
|
const readFile = input.readFile ?? ((p) => readFileSync(p, "utf8"));
|
|
@@ -1574,6 +1684,10 @@ async function runNpmBumpVersions(input) {
|
|
|
1574
1684
|
const bumped = [];
|
|
1575
1685
|
const skipped = [];
|
|
1576
1686
|
print(`Bumping monorepo to ${version}${dryRun ? " (dry-run)" : ""}…`);
|
|
1687
|
+
logger.info({
|
|
1688
|
+
version,
|
|
1689
|
+
dryRun: dryRun || void 0
|
|
1690
|
+
}, "npm bump-versions: start");
|
|
1577
1691
|
function bumpFile(absPath, label) {
|
|
1578
1692
|
let pkg;
|
|
1579
1693
|
try {
|
|
@@ -1596,8 +1710,15 @@ async function runNpmBumpVersions(input) {
|
|
|
1596
1710
|
try {
|
|
1597
1711
|
entries = listDir(packagesDir);
|
|
1598
1712
|
} catch {
|
|
1713
|
+
const status = dryRun ? "dry-run" : "ok";
|
|
1714
|
+
logger.info({
|
|
1715
|
+
version,
|
|
1716
|
+
status,
|
|
1717
|
+
bumped: bumped.length,
|
|
1718
|
+
skipped: skipped.length
|
|
1719
|
+
}, "npm bump-versions: done");
|
|
1599
1720
|
return {
|
|
1600
|
-
status
|
|
1721
|
+
status,
|
|
1601
1722
|
bumped,
|
|
1602
1723
|
skipped
|
|
1603
1724
|
};
|
|
@@ -1624,8 +1745,15 @@ async function runNpmBumpVersions(input) {
|
|
|
1624
1745
|
}
|
|
1625
1746
|
bumpFile(pkgFile, `packages/${entry}`);
|
|
1626
1747
|
}
|
|
1748
|
+
const status = dryRun ? "dry-run" : "ok";
|
|
1749
|
+
logger.info({
|
|
1750
|
+
version,
|
|
1751
|
+
status,
|
|
1752
|
+
bumped: bumped.length,
|
|
1753
|
+
skipped: skipped.length
|
|
1754
|
+
}, "npm bump-versions: done");
|
|
1627
1755
|
return {
|
|
1628
|
-
status
|
|
1756
|
+
status,
|
|
1629
1757
|
bumped,
|
|
1630
1758
|
skipped
|
|
1631
1759
|
};
|
|
@@ -1659,6 +1787,7 @@ async function runNpmBumpVersions(input) {
|
|
|
1659
1787
|
*/
|
|
1660
1788
|
async function runNpmPublishInitial(input = {}) {
|
|
1661
1789
|
const print = input.print ?? ((line) => console.log(line));
|
|
1790
|
+
const logger = input.logger ?? getLogger();
|
|
1662
1791
|
const cwd = input.cwd ?? process.cwd();
|
|
1663
1792
|
const tag = input.tag ?? "alpha";
|
|
1664
1793
|
const dryRun = input.dryRun ?? false;
|
|
@@ -1679,6 +1808,10 @@ async function runNpmPublishInitial(input = {}) {
|
|
|
1679
1808
|
print(`Holocron npm publish-initial${dryRun ? " (dry-run)" : ""}`);
|
|
1680
1809
|
print(` cwd: ${cwd}`);
|
|
1681
1810
|
print(` tag: ${tag}`);
|
|
1811
|
+
logger.info({
|
|
1812
|
+
tag,
|
|
1813
|
+
dryRun: dryRun || void 0
|
|
1814
|
+
}, "npm publish-initial: start");
|
|
1682
1815
|
if (otp) print(` otp: <${otp.length} chars>`);
|
|
1683
1816
|
print("");
|
|
1684
1817
|
print(" → verifying npm auth (`npm whoami`)…");
|
|
@@ -1686,10 +1819,12 @@ async function runNpmPublishInitial(input = {}) {
|
|
|
1686
1819
|
if (whoami.exitCode !== 0) {
|
|
1687
1820
|
const message = "npm is not authenticated. Run `npm login --auth-type=web` (browser flow, no token stored) or `npm login`, then re-run this command.";
|
|
1688
1821
|
print(` ✗ ${message}`);
|
|
1822
|
+
const packageNames = input.packages ?? discoverPublicPackages(cwd);
|
|
1823
|
+
logger.warn({ reason: "npm not authenticated" }, "npm publish-initial: done");
|
|
1689
1824
|
return {
|
|
1690
1825
|
status: "fail",
|
|
1691
1826
|
message,
|
|
1692
|
-
packageNames
|
|
1827
|
+
packageNames
|
|
1693
1828
|
};
|
|
1694
1829
|
}
|
|
1695
1830
|
print(` ✓ authed as ${whoami.stdout.trim() || "<unknown>"}`);
|
|
@@ -1700,6 +1835,11 @@ async function runNpmPublishInitial(input = {}) {
|
|
|
1700
1835
|
print(" … (dry-run) skipping actual publish");
|
|
1701
1836
|
print(` would run: pnpm ${publishArgs.join(" ")}`);
|
|
1702
1837
|
printNextSteps$1(print, env, packageNames, repoName);
|
|
1838
|
+
logger.info({
|
|
1839
|
+
tag,
|
|
1840
|
+
status: "dry-run",
|
|
1841
|
+
packages: packageNames.length
|
|
1842
|
+
}, "npm publish-initial: done");
|
|
1703
1843
|
return {
|
|
1704
1844
|
status: "dry-run",
|
|
1705
1845
|
message: "dry-run — no publish executed",
|
|
@@ -1717,6 +1857,10 @@ async function runNpmPublishInitial(input = {}) {
|
|
|
1717
1857
|
print(" → hint: your npm account requires 2FA for writes. Re-run with `--otp <code>`:");
|
|
1718
1858
|
print(` pnpm exec tsx packages/cli/src/cli.ts npm publish-initial --otp <6-digit-code>`);
|
|
1719
1859
|
}
|
|
1860
|
+
logger.warn({
|
|
1861
|
+
tag,
|
|
1862
|
+
reason: message
|
|
1863
|
+
}, "npm publish-initial: done");
|
|
1720
1864
|
return {
|
|
1721
1865
|
status: "fail",
|
|
1722
1866
|
message,
|
|
@@ -1725,6 +1869,11 @@ async function runNpmPublishInitial(input = {}) {
|
|
|
1725
1869
|
}
|
|
1726
1870
|
print(" ✓ publish complete");
|
|
1727
1871
|
printNextSteps$1(print, env, packageNames, repoName);
|
|
1872
|
+
logger.info({
|
|
1873
|
+
tag,
|
|
1874
|
+
status: "ok",
|
|
1875
|
+
packages: packageNames.length
|
|
1876
|
+
}, "npm publish-initial: done");
|
|
1728
1877
|
return {
|
|
1729
1878
|
status: "ok",
|
|
1730
1879
|
packageNames
|
|
@@ -2704,6 +2853,7 @@ function resolvePath(template, inputs) {
|
|
|
2704
2853
|
function runPluginCreate(input) {
|
|
2705
2854
|
const cwd = input.cwd ?? process.cwd();
|
|
2706
2855
|
const print = input.print ?? ((line) => console.log(line));
|
|
2856
|
+
const logger = input.logger ?? getLogger();
|
|
2707
2857
|
const write = input.writeFile ?? defaultWrite;
|
|
2708
2858
|
preflight(cwd);
|
|
2709
2859
|
validateSlug(input.slug);
|
|
@@ -2730,6 +2880,11 @@ function runPluginCreate(input) {
|
|
|
2730
2880
|
const filesWritten = [];
|
|
2731
2881
|
print(`Scaffolding @theholocron/holocron-plugin-${inputs.slug}${input.dryRun ? " (dry-run)" : ""}`);
|
|
2732
2882
|
print(` → ${packageDir}`);
|
|
2883
|
+
logger.info({
|
|
2884
|
+
slug: inputs.slug,
|
|
2885
|
+
capability: inputs.capability,
|
|
2886
|
+
dryRun: input.dryRun || void 0
|
|
2887
|
+
}, "plugin create: start");
|
|
2733
2888
|
for (const template of TEMPLATES) {
|
|
2734
2889
|
const resolvedPath = resolvePath(template.path, inputs);
|
|
2735
2890
|
const filepath = path.join(packageDir, resolvedPath);
|
|
@@ -2777,7 +2932,14 @@ function runPluginCreate(input) {
|
|
|
2777
2932
|
});
|
|
2778
2933
|
print(" ✓ scaffold verified");
|
|
2779
2934
|
} catch (err) {
|
|
2780
|
-
|
|
2935
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
2936
|
+
print(` ✗ verify failed — ${message}`);
|
|
2937
|
+
logger.warn({
|
|
2938
|
+
slug: inputs.slug,
|
|
2939
|
+
files: filesWritten.length,
|
|
2940
|
+
reason: message,
|
|
2941
|
+
status: "fail"
|
|
2942
|
+
}, "plugin create: done");
|
|
2781
2943
|
return {
|
|
2782
2944
|
status: "fail",
|
|
2783
2945
|
packagePath: packageDir,
|
|
@@ -2787,6 +2949,12 @@ function runPluginCreate(input) {
|
|
|
2787
2949
|
}
|
|
2788
2950
|
}
|
|
2789
2951
|
if (!input.dryRun) printNextSteps(print, inputs);
|
|
2952
|
+
logger.info({
|
|
2953
|
+
slug: inputs.slug,
|
|
2954
|
+
capability: inputs.capability,
|
|
2955
|
+
files: filesWritten.length,
|
|
2956
|
+
status: input.dryRun ? "dry-run" : "ok"
|
|
2957
|
+
}, "plugin create: done");
|
|
2790
2958
|
return {
|
|
2791
2959
|
status: "ok",
|
|
2792
2960
|
packagePath: packageDir,
|
|
@@ -2852,6 +3020,7 @@ function printNextSteps(print, inputs) {
|
|
|
2852
3020
|
//#region src/commands/secret-set.ts
|
|
2853
3021
|
async function runSecretSet(input) {
|
|
2854
3022
|
const print = input.print ?? ((line) => console.log(line));
|
|
3023
|
+
const logger = input.logger ?? getLogger();
|
|
2855
3024
|
const loader = input.loader ?? new PluginLoader(input.loaded.resolved, input.context);
|
|
2856
3025
|
await loader.load();
|
|
2857
3026
|
const dryRun = input.context.dryRun ?? false;
|
|
@@ -2874,6 +3043,12 @@ async function runSecretSet(input) {
|
|
|
2874
3043
|
const secrets = loader.get("secrets");
|
|
2875
3044
|
await secrets.setSecret(scope, input.name, value);
|
|
2876
3045
|
print(` ✓ set ${input.name} via ${secrets.providerName}`);
|
|
3046
|
+
logger.info({
|
|
3047
|
+
key: input.name,
|
|
3048
|
+
scope: describeScope(scope),
|
|
3049
|
+
provider: secrets.providerName,
|
|
3050
|
+
status: "ok"
|
|
3051
|
+
}, `secret set: ${input.name}`);
|
|
2877
3052
|
return {
|
|
2878
3053
|
status: "ok",
|
|
2879
3054
|
name: input.name,
|
|
@@ -2882,6 +3057,11 @@ async function runSecretSet(input) {
|
|
|
2882
3057
|
} catch (err) {
|
|
2883
3058
|
const message = err instanceof Error ? err.message : String(err);
|
|
2884
3059
|
print(` ✗ ${message}`);
|
|
3060
|
+
logger.warn({
|
|
3061
|
+
key: input.name,
|
|
3062
|
+
scope: describeScope(scope),
|
|
3063
|
+
reason: message
|
|
3064
|
+
}, `secret set: ${input.name}`);
|
|
2885
3065
|
return {
|
|
2886
3066
|
status: "fail",
|
|
2887
3067
|
name: input.name,
|
|
@@ -4931,25 +5111,50 @@ const defaultExec = (cmd, args, opts) => {
|
|
|
4931
5111
|
};
|
|
4932
5112
|
async function runSkillsInstall(input) {
|
|
4933
5113
|
const print = input.print ?? ((line) => console.log(line));
|
|
5114
|
+
const logger = input.logger ?? getLogger();
|
|
4934
5115
|
const config = input.loaded.resolved;
|
|
4935
5116
|
if (!config.agent || !config.skills?.length) {
|
|
4936
5117
|
print("Nothing to install — set `agent` and `skills` in holocron.config.ts");
|
|
5118
|
+
logger.info({
|
|
5119
|
+
status: "skip",
|
|
5120
|
+
reason: "no agent/skills configured"
|
|
5121
|
+
}, "skills install: done");
|
|
4937
5122
|
return;
|
|
4938
5123
|
}
|
|
4939
5124
|
if (input.context.dryRun) {
|
|
4940
5125
|
print(`Would install ${config.skills.length} skill(s) for agent: ${config.agent}`);
|
|
4941
5126
|
for (const name of config.skills) print(` → would install: ${name}`);
|
|
5127
|
+
logger.info({
|
|
5128
|
+
agent: config.agent,
|
|
5129
|
+
skills: config.skills,
|
|
5130
|
+
status: "dry-run"
|
|
5131
|
+
}, "skills install: done");
|
|
4942
5132
|
return;
|
|
4943
5133
|
}
|
|
4944
5134
|
print(`Installing ${config.skills.length} skill(s) for agent: ${config.agent}`);
|
|
5135
|
+
logger.info({
|
|
5136
|
+
agent: config.agent,
|
|
5137
|
+
count: config.skills.length
|
|
5138
|
+
}, "skills install: start");
|
|
4945
5139
|
try {
|
|
4946
5140
|
print(` → ${await installSkills({
|
|
4947
5141
|
agent: config.agent,
|
|
4948
5142
|
skills: config.skills,
|
|
4949
5143
|
repoRoot: input.context.repoRoot
|
|
4950
5144
|
})}`);
|
|
5145
|
+
logger.info({
|
|
5146
|
+
agent: config.agent,
|
|
5147
|
+
skills: config.skills,
|
|
5148
|
+
status: "ok"
|
|
5149
|
+
}, "skills install: done");
|
|
4951
5150
|
} catch (err) {
|
|
4952
|
-
|
|
5151
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
5152
|
+
print(` ✗ ${message}`);
|
|
5153
|
+
logger.warn({
|
|
5154
|
+
agent: config.agent,
|
|
5155
|
+
reason: message,
|
|
5156
|
+
status: "fail"
|
|
5157
|
+
}, "skills install: done");
|
|
4953
5158
|
}
|
|
4954
5159
|
}
|
|
4955
5160
|
function runSkillsRemove(input) {
|
|
@@ -5073,6 +5278,7 @@ async function updateIndexMdxDescription(repoRoot, description, dryRun, readFile
|
|
|
5073
5278
|
}
|
|
5074
5279
|
async function runSyncReadme(input) {
|
|
5075
5280
|
const { loaded, context, print = console.log, readFileFn = readFile, writeFileFn = writeFile } = input;
|
|
5281
|
+
const logger = input.logger ?? getLogger();
|
|
5076
5282
|
const { repoRoot, dryRun = false } = context;
|
|
5077
5283
|
const namespaces = loaded.resolved.env?.namespaces ?? [];
|
|
5078
5284
|
print(style.header(`Syncing README installation block${dryRun ? " (dry-run)" : ""}…`));
|
|
@@ -5082,6 +5288,10 @@ async function runSyncReadme(input) {
|
|
|
5082
5288
|
const raw = await readFileFn(join(repoRoot, "package.json"), "utf8");
|
|
5083
5289
|
pkg = JSON.parse(raw);
|
|
5084
5290
|
} catch {
|
|
5291
|
+
logger.warn({
|
|
5292
|
+
repoRoot,
|
|
5293
|
+
reason: "could not read package.json"
|
|
5294
|
+
}, "sync readme: done");
|
|
5085
5295
|
return {
|
|
5086
5296
|
status: "fail",
|
|
5087
5297
|
updated: false,
|
|
@@ -5103,6 +5313,10 @@ async function runSyncReadme(input) {
|
|
|
5103
5313
|
const updated = await updateReadme(repoRoot, generateInstallBlock(pkg), markerSections, dryRun, readFileFn, writeFileFn);
|
|
5104
5314
|
if (!updated) {
|
|
5105
5315
|
print(style.warn("README.md not found or has no writable location for installation block"));
|
|
5316
|
+
logger.warn({
|
|
5317
|
+
repoRoot,
|
|
5318
|
+
reason: "README.md not found / no marker block"
|
|
5319
|
+
}, "sync readme: done");
|
|
5106
5320
|
return {
|
|
5107
5321
|
status: "fail",
|
|
5108
5322
|
updated: false,
|
|
@@ -5111,8 +5325,14 @@ async function runSyncReadme(input) {
|
|
|
5111
5325
|
}
|
|
5112
5326
|
if (description) await updateIndexMdxDescription(repoRoot, description, dryRun, readFileFn, writeFileFn);
|
|
5113
5327
|
print(dryRun ? style.hint(" would update README.md") : style.success(" updated README.md"));
|
|
5328
|
+
const status = dryRun ? "dry-run" : "ok";
|
|
5329
|
+
logger.info({
|
|
5330
|
+
repoRoot,
|
|
5331
|
+
status,
|
|
5332
|
+
updated
|
|
5333
|
+
}, "sync readme: done");
|
|
5114
5334
|
return {
|
|
5115
|
-
status
|
|
5335
|
+
status,
|
|
5116
5336
|
updated
|
|
5117
5337
|
};
|
|
5118
5338
|
}
|
|
@@ -6217,19 +6437,38 @@ function defaultWalkFiles(dir) {
|
|
|
6217
6437
|
}
|
|
6218
6438
|
async function runUpgradeNode(input) {
|
|
6219
6439
|
const print = input.print ?? ((line) => console.log(line));
|
|
6440
|
+
const logger = input.logger ?? getLogger();
|
|
6220
6441
|
const cwd = input.cwd ?? process.cwd();
|
|
6221
6442
|
const { to, dryRun = false, extra = [] } = input;
|
|
6222
6443
|
const _readFile = input.readFile ?? ((p) => readFileSync(p, "utf8"));
|
|
6223
6444
|
const _writeFile = input.writeFile ?? ((p, c) => writeFileSync(p, c));
|
|
6224
6445
|
const _walkFiles = input.walkFiles ?? defaultWalkFiles;
|
|
6225
6446
|
const from = input.from ?? detectFrom(cwd, _readFile);
|
|
6226
|
-
if (from === null)
|
|
6227
|
-
|
|
6228
|
-
|
|
6229
|
-
|
|
6230
|
-
|
|
6447
|
+
if (from === null) {
|
|
6448
|
+
const message = "could not detect current Node version — pass --from <major>";
|
|
6449
|
+
logger.warn({
|
|
6450
|
+
to,
|
|
6451
|
+
reason: message
|
|
6452
|
+
}, "upgrade node: done");
|
|
6453
|
+
return {
|
|
6454
|
+
status: "fail",
|
|
6455
|
+
updated: [],
|
|
6456
|
+
message
|
|
6457
|
+
};
|
|
6458
|
+
}
|
|
6459
|
+
logger.info({
|
|
6460
|
+
from,
|
|
6461
|
+
to,
|
|
6462
|
+
dryRun: dryRun || void 0
|
|
6463
|
+
}, "upgrade node: start");
|
|
6231
6464
|
if (from === to) {
|
|
6232
6465
|
print(`Already at Node.js ${to} — nothing to do.`);
|
|
6466
|
+
logger.info({
|
|
6467
|
+
from,
|
|
6468
|
+
to,
|
|
6469
|
+
updated: 0,
|
|
6470
|
+
status: "ok"
|
|
6471
|
+
}, "upgrade node: done");
|
|
6233
6472
|
return {
|
|
6234
6473
|
status: "ok",
|
|
6235
6474
|
updated: []
|
|
@@ -6253,11 +6492,23 @@ async function runUpgradeNode(input) {
|
|
|
6253
6492
|
const rel = abs.startsWith(cwd + "/") ? abs.slice(cwd.length + 1) : abs;
|
|
6254
6493
|
if (!dryRun) _writeFile(abs, patched);
|
|
6255
6494
|
print(` ${dryRun ? "~" : "✓"} ${rel}`);
|
|
6495
|
+
logger.debug({
|
|
6496
|
+
file: rel,
|
|
6497
|
+
from,
|
|
6498
|
+
to
|
|
6499
|
+
}, "upgrade node: patched");
|
|
6256
6500
|
updated.push(rel);
|
|
6257
6501
|
}
|
|
6258
6502
|
if (updated.length === 0) print(` · no files contained Node.js ${from} pins`);
|
|
6503
|
+
const status = dryRun ? "dry-run" : "ok";
|
|
6504
|
+
logger.info({
|
|
6505
|
+
from,
|
|
6506
|
+
to,
|
|
6507
|
+
updated: updated.length,
|
|
6508
|
+
status
|
|
6509
|
+
}, "upgrade node: done");
|
|
6259
6510
|
return {
|
|
6260
|
-
status
|
|
6511
|
+
status,
|
|
6261
6512
|
updated
|
|
6262
6513
|
};
|
|
6263
6514
|
}
|