@theholocron/cli 5.0.0-alpha.18 → 5.0.0-alpha.180

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
@@ -17,33 +17,101 @@ holocron --help
17
17
  ## Interactive mode
18
18
 
19
19
  Run `holocron` with no command, a parent command with no subcommand
20
- (`holocron auth`, `holocron skills`, `holocron upgrade`), or a leaf command
21
- missing a required positional (`holocron deploy`, `holocron secret set`), and
22
- you get a prompt instead of a `--help` dead end:
20
+ (`holocron auth`, `holocron repo`, `holocron repo upgrade`, …), or a leaf command
21
+ missing a required positional (`holocron deploy`, `holocron secrets set`), and
22
+ you get a prompt instead of a `--help` dead end.
23
+
24
+ The menu mirrors the command tree: each level shows only the next word, and a
25
+ group (marked `›`) opens its own submenu, as deep as the commands nest. Nothing
26
+ is shown as a `<command> <subcommand>` path — `config show` is `config ›` then
27
+ `show`. Every submenu has a `← back` item, and a command that is also a group
28
+ (`repo sync`, `deploy`) has a `(run it)` item at the top of its submenu. Typing
29
+ searches the whole tree — `upgrade` at the top finds the `repo` group — with
30
+ name matches ranked above description matches.
31
+
32
+ ```console
33
+ $ holocron
34
+ ? What would you like to do? › repo
35
+ ❯ repo ›
36
+ ? repo — choose a subcommand: › upgrade
37
+ ? repo upgrade — choose a subcommand: › node
38
+ ? Target Node.js major version: › 24
39
+ ```
40
+
41
+ For a command that declares options (so far: `package publish` — more are
42
+ rolled out one command group at a time), it also offers those: any required
43
+ option is prompted like a positional, and everything else goes through one
44
+ "Set any options?" checkbox, prompting only what you picked:
23
45
 
46
+ ```console
47
+ ? Set any options? (space to select, enter to skip) › ◉ npm dist-tag ◯ One-time password (2FA)
48
+ ? npm dist-tag (blank = latest): › beta
24
49
  ```
25
- $ holocron
26
- ? What would you like to do? › dep
27
- ────────────────────────────────────────────────
28
- ❯ deploy Trigger a deployment via the configured `deployment` capability
29
50
 
30
- ? Branch to deploy: › main
51
+ `package publish` specifically has three workflows that don't mix — a
52
+ steady-state publish, a one-shot `--initial` bootstrap, and a `--sync-trust`
53
+ maintenance run — so it asks which one first, then only offers that
54
+ workflow's own options; nothing from a different workflow is ever shown:
55
+
56
+ ```console
57
+ ? What would you like to do? › Initial publish (--initial)
58
+ ? Set any options? (space to select, enter to skip) › ◉ One-time password (2FA)
59
+ ...dry-run output...
60
+ ? Dry run complete — proceed with the real run? › yes
61
+ ? One-time password (2FA), if npm requires it for this publish: › ***
31
62
  ```
32
63
 
64
+ Each workflow's label ends with its real flag in parentheses when it has
65
+ one, and a longer caveat ("use only for a package's very first publish")
66
+ shows as helper text under the highlighted choice rather than bloating the
67
+ label itself.
68
+
69
+ A secret option (`--otp`) is masked as you type and delivered to the spawned
70
+ command through its environment, never its argv — `ps` and shell history
71
+ both expose a child's argv, never its env. A time-sensitive one like `--otp`
72
+ is checked off early but not actually typed until right before the real run
73
+ — after the dry-run preview and the "proceed?" question, never before —
74
+ since a dry run never checks it anyway and a code typed any earlier risks
75
+ going stale while something else is still being answered.
76
+
77
+ Whether an option is _checkbox-optional vs. always included_ and _collected
78
+ upfront vs. collected last_ are independent choices. `package publish`'s
79
+ `--otp` is always collected last, but whether it's checkbox-optional depends
80
+ on `HOLOCRON_NPM_ENFORCE_2FA`: unset (the default), it's opt-in like any other
81
+ checkbox pick; set in your own shell profile (never checked into the repo),
82
+ it's always included — for an operator whose own npm account enforces 2FA
83
+ on every publish, so the box doesn't need re-checking every single run.
84
+ Setting it has no effect on anyone else publishing from the same repo.
85
+
33
86
  The picked command spawns as a normal `holocron <command> …` invocation —
34
87
  `--token`, `--org`, `--cwd`, and `--dry-run` on the original invocation carry
35
88
  through. A non-interactive shell (CI, a script, a pipe) gets the old
36
89
  hard-failure message instead of hanging on a prompt.
37
90
 
91
+ For a command whose handler honours `--dry-run` (most of them — everything
92
+ except `auth *` and `config show`), the menu always previews it first — a
93
+ dry run doesn't mutate anything, so there's nothing to ask permission for —
94
+ then asks the one real decision:
95
+
96
+ ```console
97
+ ...dry-run output...
98
+ ? Dry run complete — proceed with the real run? › yes
99
+ ```
100
+
101
+ A preview that reports nothing would actually change (e.g. `clone` finding
102
+ every repo already cloned) skips that question too — there'd be nothing for
103
+ the real run to do either. `--skip-dry-run` opts out of the preview
104
+ entirely, straight to the real run, for when you already know what you want.
105
+
38
106
  ## Execution contexts
39
107
 
40
108
  Every command is tagged with how much of a repo it needs:
41
109
 
42
- | Context | Needs | Examples |
43
- | ------------ | -------------------------------------------------------- | -------------------------------------------------------------------------------------------- |
44
- | `global` | just the CLI binary | `version`, `clone`, `new`, `upgrade node`, `auth set` / `check`, `plugin create`, `skills …` |
45
- | `repo-aware` | `./holocron.config` in cwd, no plugins | `run`, `ci`, `config show`, `sync-readme` |
46
- | `workspace` | the `@theholocron/holocron-plugin-*` packages resolvable | `doctor`, `setup`, `sync`, `secrets sync`, `deploy` |
110
+ | Context | Needs | Examples |
111
+ | ------------ | -------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------- |
112
+ | `global` | the CLI binary alone | `version`, `clone`, `new repo` / `plugin`, `repo upgrade …`, `auth set` / `check`, `package …`, `run lint commit-msg`, `skills …` |
113
+ | `repo-aware` | `./holocron.config`, walking up from cwd, no plugins | `run`, `run ci`, `config show`, `repo sync readme`, `deploy on-release` |
114
+ | `workspace` | the `@theholocron/holocron-plugin-*` packages resolvable | `doctor`, `repo setup`, `repo sync`, `secrets …`, `deploy`, `sync github` |
47
115
 
48
116
  A `workspace` command run from a bare global install (no plugins next to the
49
117
  CLI) fails with one actionable line — install the plugins as devDependencies or
@@ -51,6 +119,21 @@ use `pnpm exec holocron <cmd>`. `auth check` degrades to "token present,
51
119
  verification skipped" instead. `holocron --help` prints the grouping; see
52
120
  [Execution Contexts](https://theholocron.github.io/holocron/execution-contexts).
53
121
 
122
+ ### Viewing the resolved config
123
+
124
+ `holocron config show` prints the resolved config. On a TTY it opens a foldable
125
+ tree by default; piped or redirected, it always emits plain, valid JSON
126
+ (`holocron config show | jq`).
127
+
128
+ ```console
129
+ holocron config show # TTY: foldable tree (↑↓ move, →/⏎ expand, ← collapse, E/C all, q quit)
130
+ holocron config show --depth 2 # static coloured tree, anything nested deeper than 2 levels collapsed
131
+ holocron config show --no-interactive # static coloured tree, fully expanded
132
+ ```
133
+
134
+ Passing `--interactive` explicitly needs a TTY on stdin and stdout and fails
135
+ with a one-line message otherwise; the default falls back to static output. It has no extra dependencies — nothing to install.
136
+
54
137
  ## Config file
55
138
 
56
139
  Holocron reads `holocron.config.{json,js,ts}` from the project root
@@ -103,18 +186,18 @@ A minimal config — for repos with a `package.json` and a GitHub remote
103
186
 
104
187
  ### repo options
105
188
 
106
- Additional `repo` fields recognised by `holocron setup`:
189
+ Additional `repo` fields recognised by `holocron repo setup`:
107
190
 
108
- | Field | Type | Description |
109
- | ----------------- | --------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
110
- | `repo.teams` | `Array<string \| { slug, permission }>` | GitHub teams granted repo access. String shorthand defaults to `push` (Write). `holocron setup` also writes `.github/CODEOWNERS` for teams with `push`/`maintain`/`admin`. |
111
- | `repo.topics` | `string[]` | GitHub topics set on the repository. |
112
- | `repo.protection` | `"balanced" \| "strict" \| "none"` | Branch-protection preset applied by `holocron setup`. For `"strict"`, the required status checks are derived from the task manifest — see below. |
113
- | `repo.properties` | `RepoProperties` | Org-level custom property values synced to the GitHub dashboard. |
191
+ | Field | Type | Description |
192
+ | ----------------- | --------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
193
+ | `repo.teams` | `Array<string \| { slug, permission }>` | GitHub teams granted repo access. String shorthand defaults to `push` (Write). `holocron repo setup` also writes `.github/CODEOWNERS` for teams with `push`/`maintain`/`admin`. |
194
+ | `repo.topics` | `string[]` | GitHub topics set on the repository. |
195
+ | `repo.protection` | `"balanced" \| "strict" \| "none"` | Branch-protection preset applied by `holocron repo setup`. For `"strict"`, the required status checks are derived from the task manifest — see below. |
196
+ | `repo.properties` | `RepoProperties` | Org-level custom property values synced to the GitHub dashboard. |
114
197
 
115
198
  ### Custom properties synced to GitHub
116
199
 
117
- `holocron setup` and `holocron sync` both call `syncProperties()` with two
200
+ `holocron repo setup` and `holocron repo sync` both call `syncProperties()` with two
118
201
  kinds of fields — always one-way (`holocron.config.ts` → resolved →
119
202
  properties; properties are never a second editable source of truth):
120
203
 
@@ -152,9 +235,15 @@ these functions unchanged, gathering the same inputs over the GitHub API
152
235
  instead (D8 — one derivation, two input sources, not two
153
236
  implementations).
154
237
 
238
+ `missingCapabilities(capabilities)` is `deriveCompliance()`'s sibling —
239
+ same `REQUIRED_BASELINE` table, but returns _which_ required capabilities
240
+ are absent rather than whether any are. `@theholocron/sentinel`'s
241
+ `postCheckRun()` uses it to name what's missing on the check run it
242
+ posts, instead of reporting pass/fail.
243
+
155
244
  ### Required status checks (`protection: "strict"`)
156
245
 
157
- `holocron setup` builds the branch-protection required-check list from the
246
+ `holocron repo setup` builds the branch-protection required-check list from the
158
247
  manifest, not a hand-maintained array:
159
248
 
160
249
  - `"DCO"` (hard-prepended), then
@@ -180,12 +269,32 @@ The generated ruleset also sets `require_extra_approval_for_unattributed_changes
180
269
  false` — with `required_approving_review_count: 0` and a single maintainer, the
181
270
  GitHub default (`true`) is an unsatisfiable block on any PR with an
182
271
  unverified/unattributed commit. Repository-admin bypass still covers the real
183
- risk. And the `codecov.yml` `holocron setup` writes carries `if_not_found:
272
+ risk. And the `codecov.yml` `holocron repo setup` writes carries `if_not_found:
184
273
  success` on every status default, so an infra-only PR (dep bump, config,
185
274
  lockfile — no coverable change) passes instead of hanging on a `codecov/*`
186
- required check that never posts. A re-run of `holocron setup` backfills both into
275
+ required check that never posts. A re-run of `holocron repo setup` backfills both into
187
276
  an existing repo.
188
277
 
278
+ ### Default branch (`repo.defaultBranch`)
279
+
280
+ ```ts
281
+ export default defineConfig({
282
+ repo: { protection: "strict", defaultBranch: "alpha" },
283
+ providers: { source: "github" },
284
+ });
285
+ ```
286
+
287
+ `holocron repo setup` syncs GitHub's repo-level default branch (`HEAD`) — what a
288
+ fresh clone checks out, what `gh pr create`/the compare UI target by default,
289
+ and what Sentinel's `validateConfig()` reads (it only ever reads config from
290
+ the repo's default branch, never a PR ref — a deliberate security boundary).
291
+ Omit this field to leave GitHub's current setting untouched; most repos never
292
+ need it. It exists for a repo using a `main`/`alpha` prerelease-channel split
293
+ where active development happens on a non-`main` branch: set this to that
294
+ branch so Sentinel validates against what's actually being developed, then
295
+ change it back once that branch merges to `main` for a stable cut and stops
296
+ being the active branch.
297
+
189
298
  ### Git hooks
190
299
 
191
300
  ```ts
@@ -196,7 +305,7 @@ export default defineConfig({
196
305
  });
197
306
  ```
198
307
 
199
- `holocron setup` writes `.husky/pre-push` (runs `holocron ci` before every
308
+ `holocron repo setup` writes `.husky/pre-push` (runs `holocron run ci` before every
200
309
  push) and `.husky/pre-commit` (runs `gitleaks protect --staged` + `lint-staged`
201
310
  before every commit — scoped to staged changes, not the whole history, so a
202
311
  past false positive can't permanently block future commits) and sets
@@ -207,7 +316,7 @@ setup --hooks` / `--no-hooks` override per run. Bypass one push with `git push
207
316
 
208
317
  ### Task scripts
209
318
 
210
- `holocron sync` reconciles `package.json#scripts` from the `tasks` manifest
319
+ `holocron repo sync` reconciles `package.json#scripts` from the `tasks` manifest
211
320
  (merge, never clobber — only the managed keys are touched):
212
321
 
213
322
  ```ts
@@ -242,8 +351,8 @@ export default defineConfig({
242
351
  `@theholocron/astromech`'s `loadTasksConfig` merges it over
243
352
  `holocron.config`'s `tasks` — **task arrays concatenate**
244
353
  (`holocron.config` first), the dedicated file **wins on scalars**,
245
- `extraRequiredChecks` concatenate. `holocron run` / `holocron ci` /
246
- `holocron setup` / `holocron sync` all read the merged result, so the
354
+ `extraRequiredChecks` concatenate. `holocron run` / `holocron run ci` /
355
+ `holocron repo setup` / `holocron repo sync` all read the merged result, so the
247
356
  split is transparent. Useful for keeping the capability/provider config
248
357
  and the "what this repo runs" manifest in separate files (this repo does).
249
358
 
@@ -270,10 +379,27 @@ job execute the same thing — at a turbo root both are
270
379
  `turbo run test -- --coverage` (the registry's org-default flags flow through
271
380
  turbo's `--`).
272
381
 
273
- ### `holocron ci`
382
+ ### `holocron deploy on-release`
383
+
384
+ ```bash
385
+ holocron deploy on-release [--channel <alpha|main>] [--from <commit>] [--to <commit>] [--dry-run]
386
+ ```
387
+
388
+ Deploys every workspace package whose own `holocron.config` declares
389
+ `{ name: "delivery.deploy", with: { on: "release" } }` (holocron#930), when the
390
+ release (`--channel`: its prerelease identifier, or `main`/empty for a stable
391
+ release) is on the task's `channel` (default `main`, the stable release) and changes the package or one of its
392
+ `workspace:*` dependencies between `--from` (the previous release's commit,
393
+ omitted when there is none) and `--to` (default `HEAD`). It waits for npm to
394
+ serve the release's new dependency versions, then runs `pnpm --filter <pkg>
395
+ delivery.deploy`. A package that doesn't apply is skipped; a deploy that
396
+ doesn't succeed exits non-zero. The shared `delivery.publish` workflow runs it as its own
397
+ `deploy` job after the release job (opt in with `deploy-on-release: true`).
398
+
399
+ ### `holocron run ci`
274
400
 
275
401
  ```bash
276
- holocron ci [--all] [--filter <pkg>] [--dry-run]
402
+ holocron run ci [--all] [--filter <pkg>] [--dry-run]
277
403
  ```
278
404
 
279
405
  Runs the merge-gating checks locally, in CI order, exiting non-zero on the
@@ -287,6 +413,46 @@ Order comes from the `CI_ORDER` constant in `@theholocron/astromech`
287
413
  expands into its sub-jobs (each under its own `audit / …` check context)
288
414
  unless the repo ships its own `"audit"` script.
289
415
 
416
+ ### `holocron deploy`
417
+
418
+ `holocron deploy <branch>` (a Git-linked deployment) and `holocron deploy
419
+ --files <dir>` (a directory of build output, no linked repo) both trigger a
420
+ deployment through the configured `deployment` capability, then **wait for
421
+ it to finish**. The command reports success, exit code 0, only when the
422
+ deployment reaches `ready`. A deployment that ends `error` or `cancelled`,
423
+ or is still building after 10 minutes, is a failure: the exit code is
424
+ non-zero and the output includes the provider's own reason
425
+ (`DeploymentRecord.errorMessage`, e.g. Vercel's `Command "npm install"
426
+ exited with 1`). Providers build asynchronously, so accepting a deployment
427
+ isn't the same as it going live (holocron#911).
428
+
429
+ Provider plugins support this through the `Deployment` capability's
430
+ existing `getDeployment(id)`. They should set `errorMessage` on the
431
+ returned `DeploymentRecord` whenever the provider exposes one.
432
+
433
+ ### `holocron monitoring check <url>`
434
+
435
+ Runs every configured `monitoring` check against `<url>` instead of each
436
+ check's own configured `url` — no vendor API call, only a plain HTTP
437
+ request evaluated locally against the exact same `assertions` already in
438
+ `holocron.config.ts`. Built for CI: the `delivery.previewCheck` task runs
439
+ this against a PR's Vercel preview deployment (triggered by
440
+ `deployment_status`, not `push`/`pull_request`), reusing the production
441
+ check definitions to catch a breaking change before merge instead of
442
+ after (holocron#1010).
443
+
444
+ ```ts
445
+ export default defineConfig({
446
+ tasks: ["delivery.previewCheck"],
447
+ providers: {
448
+ monitoring: ["checkly", { accountId: "...", checks: [/* ... */] }],
449
+ },
450
+ });
451
+ ```
452
+
453
+ Exits non-zero if any check fails — the job's own pass/fail is what
454
+ posts as the GitHub check, no separate reporting step needed.
455
+
290
456
  ### Lint parity
291
457
 
292
458
  The `lint` task takes an optional `linters` array — one list that drives
@@ -304,7 +470,7 @@ export default defineConfig({
304
470
 
305
471
  ### Skills installer
306
472
 
307
- `holocron setup` can install shared skills from `@theholocron/skills` into the local repo:
473
+ `holocron repo setup` can install shared skills from `@theholocron/skills` into the local repo:
308
474
 
309
475
  ```ts
310
476
  export default defineConfig({
@@ -367,16 +533,16 @@ export default acmeConfig;
367
533
 
368
534
  ## Upgrading
369
535
 
370
- - **`holocron upgrade node <to>`** — patches every Node.js version pin
536
+ - **`holocron repo upgrade node <to>`** — patches every Node.js version pin
371
537
  (`engines.node`, `.nvmrc`, `.node-version`, `.github/workflows/*`,
372
538
  `Dockerfile`, `.tool-versions`) to a new major.
373
- - **`holocron upgrade deps`** — bumps every `@theholocron/*` pin in
539
+ - **`holocron repo upgrade deps`** — bumps every `@theholocron/*` pin in
374
540
  `pnpm-workspace.yaml` (`catalog:` and every named `catalogs.*`) to its latest
375
541
  published version, then migrates `holocron.config.ts` from the 7.x preset
376
542
  shape (`const { repo, workflows } = node()` + `repo.requiredChecks` +
377
543
  `workflows:`) to the current composed-preset API (`const preset = node()` +
378
544
  `...preset` + `tasks:` + `extraRequiredChecks:`). Mechanical transforms only —
379
- review the result, then `pnpm install && holocron ci`. `--pins-only` skips
545
+ review the result, then `pnpm install && holocron run ci`. `--pins-only` skips
380
546
  the config migration; `--dry-run` prints without writing.
381
547
 
382
548
  ## Auth — fine-grained tokens
@@ -395,7 +561,7 @@ holocron auth set github.admin ghp_xxx # setup, secrets, environments
395
561
 
396
562
  The resolution chain per capability is:
397
563
 
398
- ```
564
+ ```text
399
565
  --token flag → HOLOCRON_<FEATURE>_TOKEN env var → keyring("github.<feature>")
400
566
  ```
401
567
 
@@ -412,16 +578,21 @@ holocron auth list # show all stored providers
412
578
  ## Logging
413
579
 
414
580
  Operational output goes through `@theholocron/observability/logger` — separate
415
- from the user-facing `print` surface. Global flags:
581
+ from the user-facing `print` surface. Local/interactive runs are quiet by
582
+ default: no colorized or raw structured console output, regardless of the
583
+ resolved level (Axiom shipping, when configured, is unaffected). CI is
584
+ untouched — its existing stdout output still appears. Global flags:
416
585
 
417
586
  ```sh
418
- holocron doctor --verbose # log level → debug (full structured output)
419
- holocron doctor --quiet # log level → error (suppress info + warn)
587
+ holocron doctor --log debug # show console output at this level (opt back in)
588
+ holocron doctor --verbose # log level → debug, and shows console output
589
+ holocron doctor --quiet # log level → error, and shows console output
420
590
  holocron doctor --debug # print "Run ID: <uuid>" at command end for Axiom lookup
421
591
  ```
422
592
 
423
- Level resolution (highest priority first): `--verbose` / `--quiet` →
424
- `HOLOCRON_LOG_LEVEL` → `log.level` in `holocron.config` → `"info"`.
593
+ Level resolution (highest priority first): `--log <level>` → `--verbose` /
594
+ `--quiet` → `HOLOCRON_LOG_LEVEL` → `log.level` in `holocron.config` →
595
+ `"info"`.
425
596
 
426
597
  ```ts
427
598
  export default defineConfig({
@@ -433,7 +604,16 @@ Axiom shipping activates when a token (`HOLOCRON_AXIOM_TOKEN` / `AXIOM_TOKEN`
433
604
  → OS keyring `axiom.<org>` → `axiom`) **and** a dataset
434
605
  (`HOLOCRON_AXIOM_DATASET` / `AXIOM_DATASET` → `log.axiom.dataset` in
435
606
  `holocron.config`) both resolve; env vars win. The token is never read from a
436
- config file. See the [logging guide](https://docs.theholocron.dev/holocron/logging/).
607
+ config file.
608
+
609
+ The dataset side of that resolution is **execution-context-aware** (ADR-0012):
610
+ a `global`-context command (`clone`, `new`, `auth set`, `upgrade node`, `plugin
611
+ create`, …) always ships to holocron's own dataset regardless of `$PWD` — it
612
+ isn't "about" any repo, so routing it through whichever repo's `.envrc`
613
+ happens to be active would be wrong. `repo-aware` / `workspace` commands
614
+ (`doctor`, `deploy`, `sync`, …) keep the env-var/config chain above, so a
615
+ per-repo `HOLOCRON_AXIOM_DATASET` — e.g. via a `.envrc` + `direnv` — separates
616
+ each consuming repo's logs. See the [logging guide](https://docs.theholocron.dev/holocron/logging/).
437
617
 
438
618
  ### Telemetry
439
619
 
@@ -462,38 +642,67 @@ export default defineConfig({
462
642
 
463
643
  Each SDK sits behind an interface from `@theholocron/observability` —
464
644
  `ErrorSink` (Sentry) / `AnalyticsSink` (PostHog); the adapters, and the only
465
- `@sentry/node` / `posthog-node` imports, live in that package. `telemetry.ts`
645
+ `@sentry/node` / `posthog-node` imports, live in that package. `observability/telemetry.ts`
466
646
  holds the orchestration + the Holocron-specific credential resolution
467
- (`telemetry/resolve.ts`). See the
647
+ (`observability/resolve-telemetry.ts`). See the
468
648
  [telemetry guide](https://docs.theholocron.dev/holocron/telemetry/).
469
649
 
650
+ ### ESLint bundle options
651
+
652
+ Most repos need nothing here — `@theholocron/eslint-config`'s `library()`
653
+ bundle resolves with zero committed file (Bucket A: `eslint --config
654
+ <shared path>`, no per-repo `eslint.config.ts` needed). A package with a
655
+ genuine, deliberate exception — e.g. Web Crypto globals a Node-targeted
656
+ package still needs, exempted via `library()`'s own `browserPackages`
657
+ option in that package's own `eslint.config.ts` — should also declare the
658
+ same paths in `holocron.config`'s `eslint.browserPackages`:
659
+
660
+ ```ts
661
+ export default defineConfig({
662
+ eslint: {
663
+ browserPackages: ["packages/github-client/src/app-auth"],
664
+ },
665
+ });
666
+ ```
667
+
668
+ This doesn't replace the package's own `eslint.config.ts` (local/CI linting
669
+ still resolves that file directly) — it's the signal Sentinel's centralized
670
+ static-analysis check (holocron#849/#858) reads instead, since that check
671
+ never reads a PR's own committed config files. Without it, Sentinel flags a
672
+ false-positive `eslint-plugin-n` node-builtins finding on exactly the files
673
+ the local override exists to exempt.
674
+
470
675
  ## What's in here
471
676
 
472
- - `src/capabilities/` — the 14 capability interfaces that providers
473
- implement
677
+ - `src/plugin/capabilities.ts` — the 18 capability interfaces that
678
+ providers implement
474
679
  - `src/config.ts` — config schema, `defineConfig`, `resolveConfig`,
475
680
  `CapabilityConfigPackage`
476
681
  - `src/config/load-config.ts` — `loadConfig` — reads `holocron.config.*`
477
682
  (file discovery via [`@theholocron/datapad`](../datapad))
478
683
  - `src/define-config.ts` — `defineConfig` typed pass-through
479
- - `src/logger.ts` — CLI-side `@theholocron/observability/logger` wiring
684
+ - `src/observability/logger.ts` — CLI-side `@theholocron/observability/logger` wiring
480
685
  (`buildCliLogger`, `resolveLogLevel`)
481
686
  - `src/loader.ts` — `PluginLoader` — dynamic-imports plugins, resolves
482
687
  capability config packages, builds the capability registry
483
688
  - `src/cli.ts` — yargs entry, dispatches subcommands. `holocron run` / `ci` are
484
689
  delegated to [`@theholocron/astromech`](../astromech) (`createAstromech`).
485
- `holocron sync` / `holocron setup` write each repo's `.github/workflows/*.yml`
486
- thin callers from `astromech.thinCallers()`; `holocron sync-github` pushes the
690
+ `holocron repo sync` / `holocron repo setup` write each repo's `.github/workflows/*.yml`
691
+ thin callers from `astromech.thinCallers()`; `holocron sync github` pushes the
487
692
  reusable `workflow_call` implementations + composite actions from
488
693
  `astromech.reusableTemplates()` to `theholocron/.github` (a pure sync target —
489
694
  never hand-edit its `.github/workflows/*`).
490
- - `src/commands/` — `setup`, `sync`, `doctor`, `deploy`, `secret set`,
491
- `secrets sync`, `publish`, `bump-versions`, `sync-github`, `upgrade node`,
492
- `upgrade deps`, `plugin create`, `auth`
493
- - `src/interactive-menu.ts` — the interactive fallback: `COMMAND_REGISTRY`,
494
- `launchMenu` (Layers 1–2, picks + spawns a fresh `holocron <command>`),
495
- `promptForPositionals` (Layer 3, called inline from each leaf command's
496
- `cli.ts` handler)
695
+ - `src/commands/` — `repo setup`, `repo sync`, `doctor`, `deploy`,
696
+ `monitoring check`, `secrets set`, `secrets sync`, `package publish`,
697
+ `package bump-versions`, `sync github`, `repo upgrade node`,
698
+ `repo upgrade deps`, `new plugin`, `auth`
699
+ - `src/interactive-menu/` — the interactive fallback: `command-registry`
700
+ (`COMMAND_REGISTRY`, each entry's `positionals`/`options`), `launch-menu`
701
+ (Layers 1–2, picks + spawns a fresh `holocron <command>`), `child-argv`
702
+ (builds the spawned argv + secret env), `menu-items`, `run-menu-entries`.
703
+ The generic prompting pieces it calls — `promptForPositionals`,
704
+ `promptForOptions` (Layer 3) — live in `src/ui/`, which has no knowledge
705
+ of commands.
497
706
 
498
707
  ## Status
499
708