@theholocron/cli 4.13.0 → 4.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -338,7 +338,28 @@ The CLI reports on itself through three sinks: **Sentry** (errors), **Axiom**
338
338
  duration, failure rates, keyed to a one-way `sha256(hostname + username)`
339
339
  fingerprint). PostHog activates from `HOLOCRON_POSTHOG_PROJECT_TOKEN` → `POSTHOG_PROJECT_TOKEN`
340
340
  → a shipped ingest-only key (on by default). `HOLOCRON_TELEMETRY=false` disables
341
- all three. See the [telemetry guide](https://docs.theholocron.dev/holocron/telemetry/).
341
+ all three.
342
+
343
+ For a committed, repo-wide opt-out, add a `telemetry` block to `holocron.config`
344
+ — the version-controlled peer of `HOLOCRON_TELEMETRY=false` (the env var still
345
+ wins; this is an override layer applied after config loads):
346
+
347
+ ```ts
348
+ import { defineConfig } from "@theholocron/cli";
349
+
350
+ export default defineConfig({
351
+ // …
352
+ telemetry: {
353
+ enabled: false, // no-ops Sentry + PostHog for every command
354
+ // analytics: "none", // alternative: PostHog off, Sentry error reporting kept
355
+ },
356
+ });
357
+ ```
358
+
359
+ Each SDK sits behind a Holocron-owned interface — `ErrorSink` (Sentry) /
360
+ `AnalyticsSink` (PostHog) in `src/telemetry/sinks.ts`; `@sentry/node` and
361
+ `posthog-node` are imported only from their adapter modules. See the
362
+ [telemetry guide](https://docs.theholocron.dev/holocron/telemetry/).
342
363
 
343
364
  ## What's in here
344
365
 
package/dist/cli.mjs CHANGED
@@ -21,8 +21,8 @@ import { createHash } from "node:crypto";
21
21
  import { generateReadme } from "@theholocron/components-doc/markdown";
22
22
  import { getClients, getConfigs, getDocs, getPlugins, getSkills, getThemes, getUtils } from "@theholocron/registry-doc";
23
23
  import { createGitHubClient } from "@theholocron/github-client";
24
- import * as Sentry from "@sentry/node";
25
24
  import { PostHog } from "posthog-node";
25
+ import * as Sentry from "@sentry/node";
26
26
  import { promisify } from "node:util";
27
27
  import { ConfigFileError, loadConfigFile } from "@theholocron/datapad";
28
28
  //#region src/env.ts
@@ -292,7 +292,8 @@ function resolveConfig(raw) {
292
292
  skills: raw.skills,
293
293
  docs,
294
294
  env: raw.env,
295
- log: raw.log
295
+ log: raw.log,
296
+ telemetry: raw.telemetry
296
297
  };
297
298
  }
298
299
  //#endregion
@@ -5820,50 +5821,165 @@ async function writeWorkflowFile(repoRoot, filename, content) {
5820
5821
  await writeFile(join(dir, filename), content, "utf8");
5821
5822
  }
5822
5823
  //#endregion
5823
- //#region src/telemetry.ts
5824
- const FALLBACK_DSN = "https://95cbb72ad5636c94e119a5405ee8f55f@o4508238154104832.ingest.us.sentry.io/4511810950791168";
5824
+ //#region src/telemetry/posthog-sink.ts
5825
5825
  /**
5826
- * Resolve the Sentry DSN — the `errors` capability's self-contained
5827
- * activation, per ADR-0007:
5826
+ * `PostHogSink` — the **only** `posthog-node` import in the CLI. Product
5827
+ * analytics (usage, adoption, retention), activated self-contained per ADR-0008:
5828
5828
  *
5829
- * HOLOCRON_SENTRY_DSN → SENTRY_DSN → built-in fallback
5829
+ * HOLOCRON_POSTHOG_PROJECT_TOKEN → POSTHOG_PROJECT_TOKEN → built-in fallback key
5830
+ * HOLOCRON_POSTHOG_HOST → POSTHOG_HOST → https://us.i.posthog.com
5830
5831
  *
5831
- * A consumer repo with `SENTRY_DSN` set gets CLI errors routed to its own
5832
- * project with no config. Opt out entirely with `HOLOCRON_TELEMETRY=false`.
5832
+ * The built-in fallback is an ingest-only project write key (`phc_…`) — it can
5833
+ * capture events, never read data — so it ships in the published package, the
5834
+ * same risk model as the hard-coded Sentry DSN. {@link resolvePostHogKey}
5835
+ * returning `""` is how the caller decides to install a `NoopAnalyticsSink`.
5833
5836
  */
5834
- function resolveDsn() {
5835
- return env.get("HOLOCRON_SENTRY_DSN") ?? env.get("SENTRY_DSN") ?? FALLBACK_DSN;
5836
- }
5837
5837
  const FALLBACK_POSTHOG_PROJECT_TOKEN = "phc_AC4vFCvYzwnzmG7Vg5nEc3PZKZztoPyfKp4Lb9BbXcLK";
5838
5838
  const DEFAULT_POSTHOG_HOST = "https://us.i.posthog.com";
5839
- /**
5840
- * Resolve the PostHog project key — mirrors {@link resolveDsn} and the
5841
- * `HOLOCRON_AXIOM_TOKEN` / `AXIOM_TOKEN` pattern, per ADR-0008:
5842
- *
5843
- * HOLOCRON_POSTHOG_PROJECT_TOKEN → POSTHOG_PROJECT_TOKEN → built-in fallback
5844
- *
5845
- * `POSTHOG_PROJECT_TOKEN` is the vendor-native name a consumer repo sets (as a
5846
- * plain variable, not a secret — the `phc_…` key is publishable) to route CLI
5847
- * usage to its own project.
5848
- */
5839
+ /** Resolve the PostHog project key. `""` → usage analytics disabled. */
5849
5840
  function resolvePostHogKey() {
5850
5841
  return env.get("HOLOCRON_POSTHOG_PROJECT_TOKEN") ?? env.get("POSTHOG_PROJECT_TOKEN") ?? FALLBACK_POSTHOG_PROJECT_TOKEN;
5851
5842
  }
5852
5843
  function resolvePostHogHost() {
5853
5844
  return env.get("HOLOCRON_POSTHOG_HOST") ?? env.get("POSTHOG_HOST") ?? DEFAULT_POSTHOG_HOST;
5854
5845
  }
5846
+ var PostHogSink = class {
5847
+ #client;
5848
+ constructor() {
5849
+ this.#client = new PostHog(resolvePostHogKey(), { host: resolvePostHogHost() });
5850
+ }
5851
+ identify(distinctId, props) {
5852
+ this.#client.identify({
5853
+ distinctId,
5854
+ properties: props
5855
+ });
5856
+ }
5857
+ capture(distinctId, event, props) {
5858
+ this.#client.capture({
5859
+ distinctId,
5860
+ event,
5861
+ properties: props
5862
+ });
5863
+ }
5864
+ async shutdown() {
5865
+ await this.#client.shutdown();
5866
+ }
5867
+ };
5868
+ //#endregion
5869
+ //#region src/telemetry/redact.ts
5870
+ /**
5871
+ * Token-shape scrubbing for telemetry payloads — a raw token never leaves the
5872
+ * process, even when a value is controlled. Regex-on-the-serialised-string
5873
+ * (matches a token shape *anywhere*), distinct from `@theholocron/logger`'s
5874
+ * field-path redaction. Shared by {@link scrubError} (Sentry `beforeSend`) and
5875
+ * the PostHog `event()` path.
5876
+ */
5877
+ const TOKEN_RE = /\b(ghp_|ghs_|glpat-|xoxb-|xoxp-|npm_|sk-|[A-Z][A-Z0-9_]{2,}_TOKEN[=\s])[^\s"]*/g;
5878
+ /** Replace token-shaped substrings in a string with `[REDACTED]`. */
5879
+ function redact(raw) {
5880
+ return raw.replace(TOKEN_RE, "[REDACTED]");
5881
+ }
5882
+ /** Deep-scrub every string in an object by round-tripping through {@link redact}. */
5883
+ function redactObject(value) {
5884
+ return JSON.parse(redact(JSON.stringify(value)));
5885
+ }
5886
+ //#endregion
5887
+ //#region src/telemetry/sentry-sink.ts
5888
+ const FALLBACK_DSN = "https://95cbb72ad5636c94e119a5405ee8f55f@o4508238154104832.ingest.us.sentry.io/4511810950791168";
5889
+ /** Resolve the Sentry DSN. `""` → error telemetry disabled. */
5890
+ function resolveDsn() {
5891
+ return env.get("HOLOCRON_SENTRY_DSN") ?? env.get("SENTRY_DSN") ?? FALLBACK_DSN;
5892
+ }
5893
+ /** `beforeSend` — token-shaped strings never leave the process. */
5894
+ function scrubError(event, _hint) {
5895
+ return redactObject(event);
5896
+ }
5897
+ var SentrySink = class {
5898
+ init(ctx) {
5899
+ Sentry.init({
5900
+ dsn: resolveDsn(),
5901
+ release: ctx.release,
5902
+ environment: ctx.environment,
5903
+ tracesSampleRate: 1,
5904
+ beforeSend: scrubError
5905
+ });
5906
+ Sentry.startSession();
5907
+ for (const [key, value] of Object.entries(ctx.tags)) Sentry.setTag(key, value);
5908
+ }
5909
+ startSpan(name) {
5910
+ Sentry.setTag("command", name);
5911
+ const span = Sentry.startInactiveSpan({
5912
+ name,
5913
+ op: "holocron.command",
5914
+ forceTransaction: true
5915
+ });
5916
+ return {
5917
+ setStatus: (ok) => span.setStatus({ code: ok ? 1 : 2 }),
5918
+ end: () => span.end()
5919
+ };
5920
+ }
5921
+ captureException(err) {
5922
+ Sentry.captureException(err);
5923
+ }
5924
+ endSession() {
5925
+ Sentry.endSession();
5926
+ }
5927
+ async flush() {
5928
+ await Sentry.close(2e3);
5929
+ }
5930
+ };
5931
+ //#endregion
5932
+ //#region src/telemetry/sinks.ts
5933
+ /**
5934
+ * The disabled path made explicit — one shared no-op instead of a scatter of
5935
+ * `if (!enabled) return` guards. Used when telemetry is opted out
5936
+ * (`HOLOCRON_TELEMETRY=false`, `config.telemetry.enabled: false`) or no
5937
+ * credentials resolve.
5938
+ */
5939
+ var NoopErrorSink = class {
5940
+ init() {}
5941
+ startSpan() {}
5942
+ captureException() {}
5943
+ endSession() {}
5944
+ async flush() {}
5945
+ };
5946
+ /** @see NoopErrorSink */
5947
+ var NoopAnalyticsSink = class {
5948
+ identify() {}
5949
+ capture() {}
5950
+ async shutdown() {}
5951
+ };
5952
+ //#endregion
5953
+ //#region src/telemetry.ts
5954
+ /**
5955
+ * CLI self-telemetry orchestration — errors (Sentry), usage analytics (PostHog).
5956
+ *
5957
+ * This module holds *no* vendor SDK import. Each concern sits behind a
5958
+ * Holocron-owned interface ({@link ErrorSink} / {@link AnalyticsSink}); the
5959
+ * concrete `SentrySink` / `PostHogSink` are the only `@sentry/node` /
5960
+ * `posthog-node` call sites, and a `Noop*Sink` is installed when telemetry is
5961
+ * off. Same seam `@theholocron/logger` uses for Pino.
5962
+ *
5963
+ * Activation is env-var + shipped-fallback, resolved inside each sink. The
5964
+ * single kill switch is `HOLOCRON_TELEMETRY=false` (legacy alias
5965
+ * `NO_HOLOCRON_TELEMETRY`); see ADR-0007 / ADR-0008.
5966
+ */
5967
+ let errors = new NoopErrorSink();
5968
+ let analytics = new NoopAnalyticsSink();
5969
+ /**
5970
+ * The shared opt-out. `HOLOCRON_TELEMETRY=false` (going-forward) or
5971
+ * `NO_HOLOCRON_TELEMETRY` (any truthy value, back-compat) disables all sinks.
5972
+ */
5855
5973
  function isEnabled() {
5856
5974
  return env.get("HOLOCRON_TELEMETRY") !== "false" && !env.get("NO_HOLOCRON_TELEMETRY");
5857
5975
  }
5858
- const sentryEnabled = () => isEnabled() && resolveDsn() !== "";
5859
- const posthogEnabled = () => isEnabled() && resolvePostHogKey() !== "";
5860
- let posthog;
5861
5976
  let commandStartedAt = 0;
5862
5977
  let currentCommand = "unknown";
5978
+ let lastErrorType;
5979
+ let currentSpan;
5863
5980
  /**
5864
5981
  * Anonymous, stable per-machine id — `sha256(hostname + username)` truncated
5865
- * (ADR-0008). A one-way fingerprint: no raw hostname or username is ever
5866
- * transmitted, and it is not personal data under this project's rule.
5982
+ * (ADR-0008). One-way: no raw hostname or username is ever transmitted.
5867
5983
  */
5868
5984
  function machineId() {
5869
5985
  try {
@@ -5872,7 +5988,7 @@ function machineId() {
5872
5988
  return "unknown";
5873
5989
  }
5874
5990
  }
5875
- /** Properties every event carries, so any event can be pivoted to its Axiom trace. */
5991
+ /** Properties every analytics event carries — pivot key to the Axiom trace. */
5876
5992
  function baseProps() {
5877
5993
  const runId = getRunId();
5878
5994
  return {
@@ -5881,76 +5997,74 @@ function baseProps() {
5881
5997
  ...runId ? { runId } : {}
5882
5998
  };
5883
5999
  }
5884
- /**
5885
- * Capture a PostHog event. Runs every `properties` object through the same
5886
- * token scrubber Sentry uses (defence-in-depth — values are controlled).
5887
- */
5888
- function event(name, properties = {}) {
5889
- if (!posthogEnabled() || !posthog) return;
5890
- const merged = {
5891
- ...baseProps(),
5892
- ...properties
5893
- };
5894
- posthog.capture({
5895
- distinctId: machineId(),
5896
- event: name,
5897
- properties: JSON.parse(redact(JSON.stringify(merged)))
5898
- });
5899
- }
5900
6000
  function init(version) {
5901
- initSentry(version);
5902
- initPostHog(version);
5903
- }
5904
- function initSentry(version) {
5905
- if (!sentryEnabled()) return;
5906
- Sentry.init({
5907
- dsn: resolveDsn(),
5908
- release: `holocron@${version}`,
5909
- environment: env.get("CI") ? "ci" : "local",
5910
- tracesSampleRate: 1,
5911
- beforeSend: scrubError
5912
- });
5913
- Sentry.startSession();
5914
- Sentry.setTag("os", process.platform);
5915
- Sentry.setTag("node", process.version);
5916
- Sentry.setTag("ci", String(Boolean(env.get("CI"))));
5917
- }
5918
- function initPostHog(version) {
5919
- if (!posthogEnabled()) return;
5920
- posthog = new PostHog(resolvePostHogKey(), { host: resolvePostHogHost() });
5921
- posthog.identify({
5922
- distinctId: machineId(),
5923
- properties: {
6001
+ if (isEnabled() && resolveDsn() !== "") {
6002
+ errors = new SentrySink();
6003
+ errors.init({
6004
+ release: `holocron@${version}`,
6005
+ environment: env.get("CI") ? "ci" : "local",
6006
+ tags: {
6007
+ os: process.platform,
6008
+ node: process.version,
6009
+ ci: String(Boolean(env.get("CI")))
6010
+ }
6011
+ });
6012
+ }
6013
+ if (isEnabled() && resolvePostHogKey() !== "") {
6014
+ analytics = new PostHogSink();
6015
+ analytics.identify(machineId(), {
5924
6016
  ci: Boolean(env.get("CI")),
5925
6017
  os: process.platform,
5926
6018
  node: process.version,
5927
6019
  cli: version,
5928
6020
  ...env.get("HOLOCRON_ORG") ? { org: env.get("HOLOCRON_ORG") } : {}
5929
- }
5930
- });
6021
+ });
6022
+ }
5931
6023
  }
5932
- let lastErrorType;
5933
- /** Start a Sentry command span, or `undefined` when Sentry is off. */
5934
- function startSpan(name) {
5935
- if (!sentryEnabled()) return void 0;
5936
- Sentry.setTag("command", name);
5937
- return Sentry.startInactiveSpan({
5938
- name,
5939
- op: "holocron.command",
5940
- forceTransaction: true
5941
- });
6024
+ /**
6025
+ * Apply the `telemetry` config block — the committed override layer, run once
6026
+ * per command *after* config loads (so it lands after {@link init}). Env still
6027
+ * wins: this only ever *narrows* what `init` turned on, never re-enables.
6028
+ *
6029
+ * - `enabled: false` → swap both sinks to no-ops for the rest of the run.
6030
+ * - `analytics: "none"` → drop usage analytics only; error reporting stays.
6031
+ *
6032
+ * A live sink is drained best-effort before it is dropped so an in-flight
6033
+ * Sentry session / PostHog queue still leaves the process cleanly.
6034
+ */
6035
+ function applyConfig(cfg) {
6036
+ if (!cfg) return;
6037
+ const drain = (p) => {
6038
+ p.catch(() => {});
6039
+ };
6040
+ if (cfg.enabled === false) {
6041
+ drain(errors.flush());
6042
+ drain(analytics.shutdown());
6043
+ errors = new NoopErrorSink();
6044
+ analytics = new NoopAnalyticsSink();
6045
+ return;
6046
+ }
6047
+ if (cfg.analytics === "none") {
6048
+ drain(analytics.shutdown());
6049
+ analytics = new NoopAnalyticsSink();
6050
+ }
6051
+ }
6052
+ /** Capture a PostHog event. Every `properties` object runs through the scrubber. */
6053
+ function event(name, properties = {}) {
6054
+ analytics.capture(machineId(), name, redactObject({
6055
+ ...baseProps(),
6056
+ ...properties
6057
+ }));
5942
6058
  }
5943
6059
  function startCommand(name) {
5944
6060
  currentCommand = name;
5945
6061
  commandStartedAt = Date.now();
5946
6062
  lastErrorType = void 0;
5947
- const span = startSpan(name);
6063
+ currentSpan = errors.startSpan(name);
5948
6064
  event("command_started", { dry_run: process.argv.includes("--dry-run") });
5949
6065
  return (ok) => {
5950
- if (span) {
5951
- span.setStatus({ code: ok ? 1 : 2 });
5952
- span.end();
5953
- }
6066
+ currentSpan?.setStatus(ok);
6067
+ currentSpan?.end();
5954
6068
  event(ok ? "command_completed" : "command_failed", {
5955
6069
  status: ok ? "ok" : "fail",
5956
6070
  duration_ms: Date.now() - commandStartedAt,
@@ -5960,26 +6074,16 @@ function startCommand(name) {
5960
6074
  }
5961
6075
  function captureException(err) {
5962
6076
  lastErrorType = err instanceof Error ? err.constructor.name : "Error";
5963
- if (!sentryEnabled()) return;
5964
- Sentry.captureException(err);
6077
+ errors.captureException(err);
5965
6078
  }
5966
6079
  function endSession() {
5967
- if (!sentryEnabled()) return;
5968
- Sentry.endSession();
6080
+ errors.endSession();
5969
6081
  }
5970
6082
  async function flush() {
5971
- if (sentryEnabled()) await Sentry.close(2e3);
5972
- if (posthog) {
5973
- await posthog.shutdown();
5974
- posthog = void 0;
5975
- }
5976
- }
5977
- const TOKEN_RE = /\b(ghp_|ghs_|glpat-|xoxb-|xoxp-|npm_|sk-|[A-Z][A-Z0-9_]{2,}_TOKEN[=\s])[^\s"]*/g;
5978
- function redact(raw) {
5979
- return raw.replace(TOKEN_RE, "[REDACTED]");
5980
- }
5981
- function scrubError(event, _hint) {
5982
- return JSON.parse(redact(JSON.stringify(event)));
6083
+ await errors.flush();
6084
+ await analytics.shutdown();
6085
+ errors = new NoopErrorSink();
6086
+ analytics = new NoopAnalyticsSink();
5983
6087
  }
5984
6088
  //#endregion
5985
6089
  //#region src/commands/sync-github.ts
@@ -6630,6 +6734,17 @@ function cliLoggerOpts(argv, resolved) {
6630
6734
  org: resolveOrg(argv, resolved)
6631
6735
  };
6632
6736
  }
6737
+ /**
6738
+ * Fold a loaded `holocron.config` into the running process: reconfigure the
6739
+ * logger from `log:`, then apply the `telemetry:` override layer. Every handler
6740
+ * that has called `loadConfig` runs this, so a repo's `telemetry.enabled: false`
6741
+ * (or `analytics: "none"`) is honoured for that command. Env still wins —
6742
+ * `applyConfig` only narrows what `init` already turned on.
6743
+ */
6744
+ function applyResolvedConfig(argv, resolved) {
6745
+ buildCliLogger(argv, cliLoggerOpts(argv, resolved));
6746
+ applyConfig(resolved.telemetry);
6747
+ }
6633
6748
  /** Parses --token values and returns the context spread, or null on parse error (exits with code 1). */
6634
6749
  function tokenContext(rawTokens) {
6635
6750
  if (!rawTokens?.length) return {};
@@ -6716,7 +6831,7 @@ try {
6716
6831
  const tokens = tokenContext(argv.token);
6717
6832
  if (!tokens) return;
6718
6833
  const loaded = await loadConfig(argv.cwd);
6719
- buildCliLogger(argv, cliLoggerOpts(argv, loaded.resolved));
6834
+ applyResolvedConfig(argv, loaded.resolved);
6720
6835
  if ((await runDoctor({
6721
6836
  loaded,
6722
6837
  context: {
@@ -6737,7 +6852,7 @@ try {
6737
6852
  const tokens = tokenContext(argv.token);
6738
6853
  if (!tokens) return;
6739
6854
  const loaded = await loadConfig(argv.cwd);
6740
- buildCliLogger(argv, cliLoggerOpts(argv, loaded.resolved));
6855
+ applyResolvedConfig(argv, loaded.resolved);
6741
6856
  if ((await runSetup({
6742
6857
  loaded,
6743
6858
  context: {
@@ -6804,7 +6919,7 @@ try {
6804
6919
  const scopeArg = argv.scope;
6805
6920
  const scope = parseScope(scopeArg);
6806
6921
  const loaded = await loadConfig(argv.cwd);
6807
- buildCliLogger(argv, cliLoggerOpts(argv, loaded.resolved));
6922
+ applyResolvedConfig(argv, loaded.resolved);
6808
6923
  if ((await runSecretSet({
6809
6924
  loaded,
6810
6925
  context: {
@@ -6834,7 +6949,7 @@ try {
6834
6949
  const tokens = tokenContext(argv.token);
6835
6950
  if (!tokens) return;
6836
6951
  const loaded = await loadConfig(argv.cwd);
6837
- buildCliLogger(argv, cliLoggerOpts(argv, loaded.resolved));
6952
+ applyResolvedConfig(argv, loaded.resolved);
6838
6953
  if ((await runSecretsSync({
6839
6954
  loaded,
6840
6955
  context: {
@@ -6863,7 +6978,7 @@ try {
6863
6978
  const tokens = tokenContext(argv.token);
6864
6979
  if (!tokens) return;
6865
6980
  const loaded = await loadConfig(argv.cwd);
6866
- buildCliLogger(argv, cliLoggerOpts(argv, loaded.resolved));
6981
+ applyResolvedConfig(argv, loaded.resolved);
6867
6982
  if ((await runDeploy({
6868
6983
  loaded,
6869
6984
  context: {
@@ -6891,7 +7006,7 @@ try {
6891
7006
  const tokens = tokenContext(argv.token);
6892
7007
  if (!tokens) return;
6893
7008
  const loaded = await loadConfig(argv.cwd);
6894
- buildCliLogger(argv, cliLoggerOpts(argv, loaded.resolved));
7009
+ applyResolvedConfig(argv, loaded.resolved);
6895
7010
  if ((await runCleanupPreview({
6896
7011
  loaded,
6897
7012
  context: {
@@ -6939,7 +7054,7 @@ try {
6939
7054
  const tokens = tokenContext(argv.token);
6940
7055
  if (!tokens) return;
6941
7056
  const loaded = await loadConfig(argv.cwd);
6942
- buildCliLogger(argv, cliLoggerOpts(argv, loaded.resolved));
7057
+ applyResolvedConfig(argv, loaded.resolved);
6943
7058
  if ((await runSync({
6944
7059
  loaded,
6945
7060
  context: {
@@ -7048,7 +7163,7 @@ try {
7048
7163
  default: false
7049
7164
  }), async (argv) => {
7050
7165
  const loaded = await loadConfig(argv.cwd);
7051
- buildCliLogger(argv, cliLoggerOpts(argv, loaded.resolved));
7166
+ applyResolvedConfig(argv, loaded.resolved);
7052
7167
  if ((await runSyncReadme({
7053
7168
  loaded,
7054
7169
  context: {