@theholocron/cli 3.55.0 → 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 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,
@@ -5597,7 +5623,7 @@ var security_default = "name: Security\n\non: # yamllint disable-line rule:truth
5597
5623
  var stale_default = "name: Stale\n\non: # yamllint disable-line rule:truthy\n workflow_call:\n inputs:\n days-before-stale:\n description: Days of inactivity before an issue or PR is marked stale (applies to both unless type-specific value is set)\n type: number\n required: false\n default: 30\n days-before-close:\n description: Days after stale label before closing (applies to both unless type-specific value is set)\n type: number\n required: false\n default: 5\n days-before-issue-stale:\n description: Days of inactivity before an issue is marked stale; overrides days-before-stale when set to a non-negative value\n type: number\n required: false\n default: -1\n days-before-issue-close:\n description: Days after stale label before closing an issue; overrides days-before-close when set to a non-negative value\n type: number\n required: false\n default: -1\n days-before-pr-stale:\n description: Days of inactivity before a PR is marked stale; overrides days-before-stale when set to a non-negative value\n type: number\n required: false\n default: -1\n days-before-pr-close:\n description: Days after stale label before closing a PR; overrides days-before-close when set to a non-negative value\n type: number\n required: false\n default: -1\n exempt-issue-labels:\n description: Comma-separated labels that exempt an issue from being marked stale\n type: string\n required: false\n default: \"in-progress,wip\"\n exempt-pr-labels:\n description: Comma-separated labels that exempt a PR from being marked stale\n type: string\n required: false\n default: \"\"\n exempt-all-issue-milestones:\n description: Issues assigned to any milestone are never marked stale\n type: boolean\n required: false\n default: true\n exempt-all-pr-milestones:\n description: PRs assigned to any milestone are never marked stale\n type: boolean\n required: false\n default: true\n exempt-all-issue-projects:\n description: Issues assigned to any project are never marked stale\n type: boolean\n required: false\n default: true\n exempt-all-pr-projects:\n description: PRs assigned to any project are never marked stale\n type: boolean\n required: false\n default: true\n\njobs:\n stale:\n name: Mark stale issues and pull requests\n permissions:\n contents: write\n issues: write\n pull-requests: write\n runs-on: ubuntu-latest\n timeout-minutes: 10\n steps:\n - uses: actions/stale@1e223db275d687790206a7acac4d1a11bd6fe629 # v10.4.0\n name: Run Stale\n with:\n close-issue-message: >\n This issue was closed because it has been stalled for\n ${{ inputs.days-before-close }} days with no activity.\n days-before-close: ${{ inputs.days-before-close }}\n days-before-issue-close: ${{ inputs.days-before-issue-close }}\n days-before-issue-stale: ${{ inputs.days-before-issue-stale }}\n days-before-pr-close: ${{ inputs.days-before-pr-close }}\n days-before-pr-stale: ${{ inputs.days-before-pr-stale }}\n days-before-stale: ${{ inputs.days-before-stale }}\n exempt-all-issue-milestones: ${{ inputs.exempt-all-issue-milestones }}\n exempt-all-issue-projects: ${{ inputs.exempt-all-issue-projects }}\n exempt-all-pr-milestones: ${{ inputs.exempt-all-pr-milestones }}\n exempt-all-pr-projects: ${{ inputs.exempt-all-pr-projects }}\n exempt-issue-labels: ${{ inputs.exempt-issue-labels }}\n exempt-pr-labels: ${{ inputs.exempt-pr-labels }}\n stale-issue-label: wontfix\n stale-issue-message: >\n This issue is stale because it has been open ${{ inputs.days-before-stale }}\n days with no activity. Remove the stale label or comment, or this will be\n closed in ${{ inputs.days-before-close }} days.\n stale-pr-label: wontfix\n stale-pr-message: >\n This PR is stale because it has been open ${{ inputs.days-before-stale }}\n days with no activity. Remove the stale label or comment, or this will be\n closed in ${{ inputs.days-before-close }} days.\n";
5598
5624
  //#endregion
5599
5625
  //#region src/templates/workflows/sync.yml
5600
- var sync_default = "name: Sync\n\non: # yamllint disable-line rule:truthy\n workflow_call:\n inputs:\n steps:\n description: >\n Sync steps to run (default: all). Valid values:\n labels, properties, teams, topics, keywords, description, homepage, readme, workflows, wiki.\n Pass a space-separated list to run a subset, e.g. \"readme\" or \"readme wiki\".\n type: string\n required: false\n secrets:\n HOLOCRON_ADMIN_TOKEN:\n description: Fine-grained PAT with admin scopes (labels, properties, teams).\n required: false\n HOLOCRON_DEPLOY_TOKEN:\n description: Fine-grained PAT for GitHub Pages configuration.\n required: false\n HOLOCRON_ISSUES_TOKEN:\n description: Fine-grained PAT for issue management.\n required: false\n HOLOCRON_ORG_TOKEN:\n description: Org-scoped fine-grained PAT for team sync and org properties.\n required: false\n HOLOCRON_READ_TOKEN:\n description: Fine-grained PAT for read-only GitHub API calls.\n required: false\n HOLOCRON_SYNC_TOKEN:\n required: false\n GH_TOKEN:\n description: >\n Generic GitHub token fallback for gh CLI calls. Used when\n HOLOCRON_SYNC_TOKEN is not set.\n required: false\n\njobs:\n sync:\n name: Sync repo from config\n runs-on: ubuntu-latest\n timeout-minutes: 10\n permissions:\n contents: write\n pull-requests: write\n steps:\n - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0\n name: Checkout repository\n with:\n token: ${{ secrets.HOLOCRON_SYNC_TOKEN || secrets.GH_TOKEN || github.token }}\n\n - uses: theholocron/.github/.github/actions/setup@main\n name: Setup\n\n - name: Run holocron sync\n run: |\n if [ -n \"$STEPS\" ]; then\n # shellcheck disable=SC2086\n pnpm --workspace-root exec holocron sync --steps $STEPS\n else\n pnpm --workspace-root exec holocron sync\n fi\n env:\n HOLOCRON_ADMIN_TOKEN: ${{ secrets.HOLOCRON_ADMIN_TOKEN }}\n HOLOCRON_DEPLOY_TOKEN: ${{ secrets.HOLOCRON_DEPLOY_TOKEN }}\n HOLOCRON_ISSUES_TOKEN: ${{ secrets.HOLOCRON_ISSUES_TOKEN }}\n HOLOCRON_ORG_TOKEN: ${{ secrets.HOLOCRON_ORG_TOKEN }}\n HOLOCRON_READ_TOKEN: ${{ secrets.HOLOCRON_READ_TOKEN }}\n HOLOCRON_SYNC_TOKEN: ${{ secrets.HOLOCRON_SYNC_TOKEN }}\n STEPS: ${{ inputs.steps }}\n\n - name: Format generated files\n run: pnpm exec prettier --write README.md docs/src/content/docs/index.mdx 2>/dev/null || true\n\n - uses: theholocron/.github/.github/actions/auto-commit@main\n id: auto-commit\n name: Commit sync changes\n with:\n token: ${{ secrets.HOLOCRON_SYNC_TOKEN || secrets.GH_TOKEN || github.token }}\n branch: chore/auto-sync\n commit-message: \"chore: sync from holocron.config\"\n commit-options: \"--no-verify\"\n\n - name: Open PR if changes were committed\n if: steps.auto-commit.outputs.changes-detected == 'true'\n run: |\n gh pr create \\\n --title \"chore: sync README and repo metadata\" \\\n --body \"Automated sync triggered by changes to config or package files. Merge to apply.\" \\\n --base main \\\n --head chore/auto-sync \\\n || echo \"PR already open — branch updated.\"\n env:\n GH_TOKEN: ${{ secrets.HOLOCRON_SYNC_TOKEN || secrets.GH_TOKEN || github.token }}\n\n - name: Broadcast wiki sync if navbar changed\n if: >-\n steps.auto-commit.outputs.changes-detected == 'true' &&\n github.event_name == 'push' &&\n (inputs.steps == '' || contains(inputs.steps, 'wiki'))\n run: |\n if git diff HEAD~1 --name-only | grep -q 'fern/docs.yml'; then\n gh workflow run sync-dispatch.yml \\\n --repo theholocron/.github \\\n --field \"steps=wiki\" \\\n || echo \"skipping broadcast — insufficient permissions\"\n fi\n env:\n GH_TOKEN: ${{ secrets.HOLOCRON_SYNC_TOKEN || secrets.GH_TOKEN || github.token }}\n";
5626
+ var sync_default = "name: Sync\n\non: # yamllint disable-line rule:truthy\n workflow_call:\n inputs:\n steps:\n description: >\n Sync steps to run (default: all). Valid values:\n labels, properties, teams, topics, keywords, description, homepage, readme, workflows, wiki.\n Pass a space-separated list to run a subset, e.g. \"readme\" or \"readme wiki\".\n type: string\n required: false\n secrets:\n HOLOCRON_ADMIN_TOKEN:\n description: Fine-grained PAT with admin scopes (labels, properties, teams).\n required: false\n HOLOCRON_DEPLOY_TOKEN:\n description: Fine-grained PAT for GitHub Pages configuration.\n required: false\n HOLOCRON_ISSUES_TOKEN:\n description: Fine-grained PAT for issue management.\n required: false\n HOLOCRON_ORG_TOKEN:\n description: Org-scoped fine-grained PAT for team sync and org properties.\n required: false\n HOLOCRON_READ_TOKEN:\n description: Fine-grained PAT for read-only GitHub API calls.\n required: false\n HOLOCRON_SYNC_TOKEN:\n required: false\n GH_TOKEN:\n description: >\n Generic GitHub token fallback for gh CLI calls. Used when\n HOLOCRON_SYNC_TOKEN is not set.\n required: false\n\njobs:\n sync:\n name: Sync repo from config\n runs-on: ubuntu-latest\n timeout-minutes: 10\n permissions:\n contents: write\n pull-requests: write\n steps:\n - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0\n name: Checkout repository\n with:\n token: ${{ secrets.HOLOCRON_SYNC_TOKEN || secrets.GH_TOKEN || github.token }}\n\n - uses: theholocron/.github/.github/actions/setup@main\n name: Setup\n\n - run: pnpm build\n name: Build CLI\n\n - name: Run holocron sync\n run: |\n if [ -n \"$STEPS\" ]; then\n # shellcheck disable=SC2086\n pnpm --workspace-root exec holocron sync --steps $STEPS\n else\n pnpm --workspace-root exec holocron sync\n fi\n env:\n HOLOCRON_ADMIN_TOKEN: ${{ secrets.HOLOCRON_ADMIN_TOKEN }}\n HOLOCRON_DEPLOY_TOKEN: ${{ secrets.HOLOCRON_DEPLOY_TOKEN }}\n HOLOCRON_ISSUES_TOKEN: ${{ secrets.HOLOCRON_ISSUES_TOKEN }}\n HOLOCRON_ORG_TOKEN: ${{ secrets.HOLOCRON_ORG_TOKEN }}\n HOLOCRON_READ_TOKEN: ${{ secrets.HOLOCRON_READ_TOKEN }}\n HOLOCRON_SYNC_TOKEN: ${{ secrets.HOLOCRON_SYNC_TOKEN }}\n STEPS: ${{ inputs.steps }}\n\n - name: Format generated files\n run: pnpm exec prettier --write README.md docs/src/content/docs/index.mdx 2>/dev/null || true\n\n - uses: theholocron/.github/.github/actions/auto-commit@main\n id: auto-commit\n name: Commit sync changes\n with:\n token: ${{ secrets.HOLOCRON_SYNC_TOKEN || secrets.GH_TOKEN || github.token }}\n branch: chore/auto-sync\n commit-message: \"chore: sync from holocron.config\"\n commit-options: \"--no-verify\"\n\n - name: Open PR if changes were committed\n if: steps.auto-commit.outputs.changes-detected == 'true'\n run: |\n gh pr create \\\n --title \"chore: sync README and repo metadata\" \\\n --body \"Automated sync triggered by changes to config or package files. Merge to apply.\" \\\n --base main \\\n --head chore/auto-sync \\\n || echo \"PR already open — branch updated.\"\n env:\n GH_TOKEN: ${{ secrets.HOLOCRON_SYNC_TOKEN || secrets.GH_TOKEN || github.token }}\n\n - name: Broadcast wiki sync if navbar changed\n if: >-\n steps.auto-commit.outputs.changes-detected == 'true' &&\n github.event_name == 'push' &&\n (inputs.steps == '' || contains(inputs.steps, 'wiki'))\n run: |\n if git diff HEAD~1 --name-only | grep -q 'fern/docs.yml'; then\n gh workflow run sync-dispatch.yml \\\n --repo theholocron/.github \\\n --field \"steps=wiki\" \\\n || echo \"skipping broadcast — insufficient permissions\"\n fi\n env:\n GH_TOKEN: ${{ secrets.HOLOCRON_SYNC_TOKEN || secrets.GH_TOKEN || github.token }}\n";
5601
5627
  //#endregion
5602
5628
  //#region src/templates/workflows/sync-dispatch.yml
5603
5629
  var sync_dispatch_default = "name: Sync Dispatch\n\non: # yamllint disable-line rule:truthy\n workflow_dispatch:\n inputs:\n steps:\n description: >\n Sync steps to pass to each repo's sync.yml. Default is \"readme\"\n (only README marker blocks are updated).\n type: string\n required: false\n default: readme\n\npermissions:\n contents: read\n\njobs:\n broadcast:\n name: Broadcast sync to all repos\n runs-on: ubuntu-latest\n timeout-minutes: 15\n steps:\n - name: Dispatch sync to all repos with sync.yml\n run: |\n gh api /orgs/theholocron/repos --paginate --jq '.[].name' \\\n | while IFS= read -r repo; do\n gh api \"/repos/theholocron/$repo/contents/.github/workflows/sync.yml\" --silent 2>/dev/null || continue\n echo \"Dispatching sync to theholocron/$repo\"\n gh workflow run sync.yml \\\n --repo \"theholocron/$repo\" \\\n --field \"steps=$STEPS\" \\\n || echo \"Warning: could not dispatch to theholocron/$repo — skipping\"\n done\n env:\n GH_TOKEN: ${{ secrets.HOLOCRON_SYNC_TOKEN }}\n STEPS: ${{ inputs.steps }}\n";
@@ -6164,14 +6190,26 @@ async function fileExists(path) {
6164
6190
  }
6165
6191
  //#endregion
6166
6192
  //#region src/telemetry.ts
6167
- const DSN = "https://95cbb72ad5636c94e119a5405ee8f55f@o4508238154104832.ingest.us.sentry.io/4511810950791168";
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"))) && true;
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: 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
- finishCommand = startCommand(argv._.slice(0, 2).join(" ") || "unknown");
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: {