@theholocron/cli 5.0.0-alpha.20 → 5.0.0-alpha.200
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 +305 -55
- package/dist/cli.mjs +6730 -2616
- package/dist/cli.mjs.map +1 -1
- package/dist/index.d.mts +222 -127
- package/dist/index.mjs +39 -54
- package/dist/plugin/capabilities.d.mts +647 -48
- package/dist/plugin/capabilities.mjs +2 -1
- package/package.json +19 -13
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
|
|
21
|
-
missing a required positional (`holocron deploy`, `holocron
|
|
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
|
+
```
|
|
23
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:
|
|
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
|
-
|
|
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` |
|
|
45
|
-
| `repo-aware` | `./holocron.config
|
|
46
|
-
| `workspace` | the `@theholocron/holocron-plugin-*` packages resolvable | `doctor`, `setup`, `sync`, `secrets
|
|
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
|
|
|
@@ -160,7 +243,7 @@ posts, instead of reporting pass/fail.
|
|
|
160
243
|
|
|
161
244
|
### Required status checks (`protection: "strict"`)
|
|
162
245
|
|
|
163
|
-
`holocron setup` builds the branch-protection required-check list from the
|
|
246
|
+
`holocron repo setup` builds the branch-protection required-check list from the
|
|
164
247
|
manifest, not a hand-maintained array:
|
|
165
248
|
|
|
166
249
|
- `"DCO"` (hard-prepended), then
|
|
@@ -186,12 +269,32 @@ The generated ruleset also sets `require_extra_approval_for_unattributed_changes
|
|
|
186
269
|
false` — with `required_approving_review_count: 0` and a single maintainer, the
|
|
187
270
|
GitHub default (`true`) is an unsatisfiable block on any PR with an
|
|
188
271
|
unverified/unattributed commit. Repository-admin bypass still covers the real
|
|
189
|
-
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:
|
|
190
273
|
success` on every status default, so an infra-only PR (dep bump, config,
|
|
191
274
|
lockfile — no coverable change) passes instead of hanging on a `codecov/*`
|
|
192
|
-
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
|
|
193
276
|
an existing repo.
|
|
194
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
|
+
|
|
195
298
|
### Git hooks
|
|
196
299
|
|
|
197
300
|
```ts
|
|
@@ -202,7 +305,7 @@ export default defineConfig({
|
|
|
202
305
|
});
|
|
203
306
|
```
|
|
204
307
|
|
|
205
|
-
`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
|
|
206
309
|
push) and `.husky/pre-commit` (runs `gitleaks protect --staged` + `lint-staged`
|
|
207
310
|
before every commit — scoped to staged changes, not the whole history, so a
|
|
208
311
|
past false positive can't permanently block future commits) and sets
|
|
@@ -213,7 +316,7 @@ setup --hooks` / `--no-hooks` override per run. Bypass one push with `git push
|
|
|
213
316
|
|
|
214
317
|
### Task scripts
|
|
215
318
|
|
|
216
|
-
`holocron sync` reconciles `package.json#scripts` from the `tasks` manifest
|
|
319
|
+
`holocron repo sync` reconciles `package.json#scripts` from the `tasks` manifest
|
|
217
320
|
(merge, never clobber — only the managed keys are touched):
|
|
218
321
|
|
|
219
322
|
```ts
|
|
@@ -248,8 +351,8 @@ export default defineConfig({
|
|
|
248
351
|
`@theholocron/astromech`'s `loadTasksConfig` merges it over
|
|
249
352
|
`holocron.config`'s `tasks` — **task arrays concatenate**
|
|
250
353
|
(`holocron.config` first), the dedicated file **wins on scalars**,
|
|
251
|
-
`extraRequiredChecks` concatenate. `holocron run` / `holocron ci` /
|
|
252
|
-
`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
|
|
253
356
|
split is transparent. Useful for keeping the capability/provider config
|
|
254
357
|
and the "what this repo runs" manifest in separate files (this repo does).
|
|
255
358
|
|
|
@@ -276,10 +379,27 @@ job execute the same thing — at a turbo root both are
|
|
|
276
379
|
`turbo run test -- --coverage` (the registry's org-default flags flow through
|
|
277
380
|
turbo's `--`).
|
|
278
381
|
|
|
279
|
-
### `holocron
|
|
382
|
+
### `holocron deploy on-release`
|
|
280
383
|
|
|
281
384
|
```bash
|
|
282
|
-
holocron
|
|
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`
|
|
400
|
+
|
|
401
|
+
```bash
|
|
402
|
+
holocron run ci [--all] [--filter <pkg>] [--dry-run]
|
|
283
403
|
```
|
|
284
404
|
|
|
285
405
|
Runs the merge-gating checks locally, in CI order, exiting non-zero on the
|
|
@@ -293,6 +413,46 @@ Order comes from the `CI_ORDER` constant in `@theholocron/astromech`
|
|
|
293
413
|
expands into its sub-jobs (each under its own `audit / …` check context)
|
|
294
414
|
unless the repo ships its own `"audit"` script.
|
|
295
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
|
+
|
|
296
456
|
### Lint parity
|
|
297
457
|
|
|
298
458
|
The `lint` task takes an optional `linters` array — one list that drives
|
|
@@ -310,7 +470,7 @@ export default defineConfig({
|
|
|
310
470
|
|
|
311
471
|
### Skills installer
|
|
312
472
|
|
|
313
|
-
`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:
|
|
314
474
|
|
|
315
475
|
```ts
|
|
316
476
|
export default defineConfig({
|
|
@@ -371,18 +531,62 @@ export default acmeConfig;
|
|
|
371
531
|
|
|
372
532
|
```
|
|
373
533
|
|
|
534
|
+
## Notifications — server as code
|
|
535
|
+
|
|
536
|
+
A `notifications` provider can declare a whole server in `holocron.config.ts`
|
|
537
|
+
(`layout`: categories, channels, roles, access, server settings, welcome screen,
|
|
538
|
+
onboarding, the bot application) and the CLI applies and checks it. The
|
|
539
|
+
commands and the config are provider-neutral; Discord is the first provider.
|
|
540
|
+
|
|
541
|
+
| Command | What it does |
|
|
542
|
+
| ---------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
|
|
543
|
+
| `holocron notifications setup` | Applies the layout; looks everything up by name first, so a re-run changes nothing that matches |
|
|
544
|
+
| `holocron notifications channel add <name>` | Creates one channel (optionally with a webhook whose URL is stored as a secret) |
|
|
545
|
+
| `holocron notifications link` | Links your account on the provider to your GitHub account by signing in with the provider (OAuth, nothing secret kept) |
|
|
546
|
+
| `holocron notifications sync-roles` | Makes who holds a role match a GitHub team, through the links file (`--keep` only adds; `--provider` picks one) |
|
|
547
|
+
| `holocron doctor notifications [--built-only]` | Read-only, step by step: does the server match the layout, and do the secrets exist |
|
|
548
|
+
|
|
549
|
+
Config shape added for role sync and sign-in (all under the provider's `layout`):
|
|
550
|
+
|
|
551
|
+
| Field | Meaning |
|
|
552
|
+
| ----------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
553
|
+
| `roles[].team` | A GitHub team slug. The role follows that team: given to linked members, taken from linked people who left. Never touches holders nobody has linked. |
|
|
554
|
+
| `links.hostedUrl` | A hosted sign-in service (Sentinel). `link` asks `<hostedUrl>/api/link` and uses it when it answers `{ "service": "link" }`; otherwise it signs in locally. |
|
|
555
|
+
| `links.localPort` | The port of the local sign-in listener (default `53682`, bound to `127.0.0.1` only). |
|
|
556
|
+
| `links.repo` / `links.path` | Where the links file lives (default `<org>/.github-private` and `notifications/<provider>-links.json`). |
|
|
557
|
+
| `application.intents.members` | Switches the Server Members Intent on or off (needed to list who holds a role). |
|
|
558
|
+
| `application.redirectUris` | Redirect URIs that must be registered. Check-only: the API cannot set them, so `setup` and the doctor say what to add in the developer portal. |
|
|
559
|
+
|
|
560
|
+
The links file is `{ "version": 1, "links": [{ "github": "<id>", "login": "<login>", "member": "<id>" }] }`: two public ids per person.
|
|
561
|
+
It is read and written through the `source` capability with the `github.user-sync` token (fine-grained, **only** the
|
|
562
|
+
private config repo, Contents read and write), so no other token needs Contents on other repositories.
|
|
563
|
+
|
|
564
|
+
Capability surface behind it (all optional, so providers without the concept omit them):
|
|
565
|
+
|
|
566
|
+
- `Source.teamMembers(teamSlug, org?)`, `Source.readFile(path, repo?)` (returns the `version` a later write must present),
|
|
567
|
+
`Source.writeFile(path, content, { message, version?, repo? })` (a changed `version` is refused: a real conflict check).
|
|
568
|
+
- `Notifications.roleMembers(role)`, `addRoleMember(role, memberId)`, `removeRoleMember(role, memberId)`.
|
|
569
|
+
- `Notifications.signIn()` returning `{ authorizeUrl, complete }`: the provider-neutral shape of "prove which account you own".
|
|
570
|
+
- `Notifications.ensureApplication` returns `{ updated, todo? }`; each `todo` is a step only a person can do (a portal setting
|
|
571
|
+
the API ignores) and is reported as a failure until done.
|
|
572
|
+
|
|
573
|
+
Provider credentials for Discord: `discord.holonet` is the **bot token** (Bot → Reset Token), `discord.holonet.oauth` is the
|
|
574
|
+
**OAuth client secret** (OAuth2 → Reset Secret). They are different values; the API can create or read neither.
|
|
575
|
+
|
|
576
|
+
See the [command pages](https://theholocron.dev/holocron/commands/notifications-setup/) for each command's options.
|
|
577
|
+
|
|
374
578
|
## Upgrading
|
|
375
579
|
|
|
376
|
-
- **`holocron upgrade node <to>`** — patches every Node.js version pin
|
|
580
|
+
- **`holocron repo upgrade node <to>`** — patches every Node.js version pin
|
|
377
581
|
(`engines.node`, `.nvmrc`, `.node-version`, `.github/workflows/*`,
|
|
378
582
|
`Dockerfile`, `.tool-versions`) to a new major.
|
|
379
|
-
- **`holocron upgrade deps`** — bumps every `@theholocron/*` pin in
|
|
583
|
+
- **`holocron repo upgrade deps`** — bumps every `@theholocron/*` pin in
|
|
380
584
|
`pnpm-workspace.yaml` (`catalog:` and every named `catalogs.*`) to its latest
|
|
381
585
|
published version, then migrates `holocron.config.ts` from the 7.x preset
|
|
382
586
|
shape (`const { repo, workflows } = node()` + `repo.requiredChecks` +
|
|
383
587
|
`workflows:`) to the current composed-preset API (`const preset = node()` +
|
|
384
588
|
`...preset` + `tasks:` + `extraRequiredChecks:`). Mechanical transforms only —
|
|
385
|
-
review the result, then `pnpm install && holocron ci`. `--pins-only` skips
|
|
589
|
+
review the result, then `pnpm install && holocron run ci`. `--pins-only` skips
|
|
386
590
|
the config migration; `--dry-run` prints without writing.
|
|
387
591
|
|
|
388
592
|
## Auth — fine-grained tokens
|
|
@@ -397,11 +601,12 @@ holocron auth set github.issues ghp_xxx # issue management
|
|
|
397
601
|
holocron auth set github.sync ghp_xxx # sync-github workflow templates
|
|
398
602
|
holocron auth set github.release ghp_xxx # semantic-release
|
|
399
603
|
holocron auth set github.admin ghp_xxx # setup, secrets, environments
|
|
604
|
+
holocron auth set github.user-sync ghp_xxx # the files that link GitHub accounts to other services' members
|
|
400
605
|
```
|
|
401
606
|
|
|
402
607
|
The resolution chain per capability is:
|
|
403
608
|
|
|
404
|
-
```
|
|
609
|
+
```text
|
|
405
610
|
--token flag → HOLOCRON_<FEATURE>_TOKEN env var → keyring("github.<feature>")
|
|
406
611
|
```
|
|
407
612
|
|
|
@@ -418,16 +623,21 @@ holocron auth list # show all stored providers
|
|
|
418
623
|
## Logging
|
|
419
624
|
|
|
420
625
|
Operational output goes through `@theholocron/observability/logger` — separate
|
|
421
|
-
from the user-facing `print` surface.
|
|
626
|
+
from the user-facing `print` surface. Local/interactive runs are quiet by
|
|
627
|
+
default: no colorized or raw structured console output, regardless of the
|
|
628
|
+
resolved level (Axiom shipping, when configured, is unaffected). CI is
|
|
629
|
+
untouched — its existing stdout output still appears. Global flags:
|
|
422
630
|
|
|
423
631
|
```sh
|
|
424
|
-
holocron doctor --
|
|
425
|
-
holocron doctor --
|
|
632
|
+
holocron doctor --log debug # show console output at this level (opt back in)
|
|
633
|
+
holocron doctor --verbose # log level → debug, and shows console output
|
|
634
|
+
holocron doctor --quiet # log level → error, and shows console output
|
|
426
635
|
holocron doctor --debug # print "Run ID: <uuid>" at command end for Axiom lookup
|
|
427
636
|
```
|
|
428
637
|
|
|
429
|
-
Level resolution (highest priority first): `--
|
|
430
|
-
`HOLOCRON_LOG_LEVEL` → `log.level` in `holocron.config` →
|
|
638
|
+
Level resolution (highest priority first): `--log <level>` → `--verbose` /
|
|
639
|
+
`--quiet` → `HOLOCRON_LOG_LEVEL` → `log.level` in `holocron.config` →
|
|
640
|
+
`"info"`.
|
|
431
641
|
|
|
432
642
|
```ts
|
|
433
643
|
export default defineConfig({
|
|
@@ -439,7 +649,16 @@ Axiom shipping activates when a token (`HOLOCRON_AXIOM_TOKEN` / `AXIOM_TOKEN`
|
|
|
439
649
|
→ OS keyring `axiom.<org>` → `axiom`) **and** a dataset
|
|
440
650
|
(`HOLOCRON_AXIOM_DATASET` / `AXIOM_DATASET` → `log.axiom.dataset` in
|
|
441
651
|
`holocron.config`) both resolve; env vars win. The token is never read from a
|
|
442
|
-
config file.
|
|
652
|
+
config file.
|
|
653
|
+
|
|
654
|
+
The dataset side of that resolution is **execution-context-aware** (ADR-0012):
|
|
655
|
+
a `global`-context command (`clone`, `new`, `auth set`, `upgrade node`, `plugin
|
|
656
|
+
create`, …) always ships to holocron's own dataset regardless of `$PWD` — it
|
|
657
|
+
isn't "about" any repo, so routing it through whichever repo's `.envrc`
|
|
658
|
+
happens to be active would be wrong. `repo-aware` / `workspace` commands
|
|
659
|
+
(`doctor`, `deploy`, `sync`, …) keep the env-var/config chain above, so a
|
|
660
|
+
per-repo `HOLOCRON_AXIOM_DATASET` — e.g. via a `.envrc` + `direnv` — separates
|
|
661
|
+
each consuming repo's logs. See the [logging guide](https://docs.theholocron.dev/holocron/logging/).
|
|
443
662
|
|
|
444
663
|
### Telemetry
|
|
445
664
|
|
|
@@ -468,38 +687,69 @@ export default defineConfig({
|
|
|
468
687
|
|
|
469
688
|
Each SDK sits behind an interface from `@theholocron/observability` —
|
|
470
689
|
`ErrorSink` (Sentry) / `AnalyticsSink` (PostHog); the adapters, and the only
|
|
471
|
-
`@sentry/node` / `posthog-node` imports, live in that package. `telemetry.ts`
|
|
690
|
+
`@sentry/node` / `posthog-node` imports, live in that package. `observability/telemetry.ts`
|
|
472
691
|
holds the orchestration + the Holocron-specific credential resolution
|
|
473
|
-
(`
|
|
692
|
+
(`observability/resolve-telemetry.ts`). See the
|
|
474
693
|
[telemetry guide](https://docs.theholocron.dev/holocron/telemetry/).
|
|
475
694
|
|
|
695
|
+
### ESLint bundle options
|
|
696
|
+
|
|
697
|
+
Most repos need nothing here — `@theholocron/eslint-config`'s `library()`
|
|
698
|
+
bundle resolves with zero committed file (Bucket A: `eslint --config
|
|
699
|
+
<shared path>`, no per-repo `eslint.config.ts` needed). A package with a
|
|
700
|
+
genuine, deliberate exception — e.g. Web Crypto globals a Node-targeted
|
|
701
|
+
package still needs, exempted via `library()`'s own `browserPackages`
|
|
702
|
+
option in that package's own `eslint.config.ts` — should also declare the
|
|
703
|
+
same paths in `holocron.config`'s `eslint.browserPackages`:
|
|
704
|
+
|
|
705
|
+
```ts
|
|
706
|
+
export default defineConfig({
|
|
707
|
+
eslint: {
|
|
708
|
+
browserPackages: ["packages/github-client/src/app-auth"],
|
|
709
|
+
},
|
|
710
|
+
});
|
|
711
|
+
```
|
|
712
|
+
|
|
713
|
+
This doesn't replace the package's own `eslint.config.ts` (local/CI linting
|
|
714
|
+
still resolves that file directly) — it's the signal Sentinel's centralized
|
|
715
|
+
static-analysis check (holocron#849/#858) reads instead, since that check
|
|
716
|
+
never reads a PR's own committed config files. Without it, Sentinel flags a
|
|
717
|
+
false-positive `eslint-plugin-n` node-builtins finding on exactly the files
|
|
718
|
+
the local override exists to exempt.
|
|
719
|
+
|
|
476
720
|
## What's in here
|
|
477
721
|
|
|
478
|
-
- `src/capabilities
|
|
479
|
-
implement
|
|
722
|
+
- `src/plugin/capabilities.ts` — the 18 capability interfaces that
|
|
723
|
+
providers implement
|
|
480
724
|
- `src/config.ts` — config schema, `defineConfig`, `resolveConfig`,
|
|
481
725
|
`CapabilityConfigPackage`
|
|
482
726
|
- `src/config/load-config.ts` — `loadConfig` — reads `holocron.config.*`
|
|
483
727
|
(file discovery via [`@theholocron/datapad`](../datapad))
|
|
484
728
|
- `src/define-config.ts` — `defineConfig` typed pass-through
|
|
485
|
-
- `src/logger.ts` — CLI-side `@theholocron/observability/logger` wiring
|
|
729
|
+
- `src/observability/logger.ts` — CLI-side `@theholocron/observability/logger` wiring
|
|
486
730
|
(`buildCliLogger`, `resolveLogLevel`)
|
|
487
731
|
- `src/loader.ts` — `PluginLoader` — dynamic-imports plugins, resolves
|
|
488
732
|
capability config packages, builds the capability registry
|
|
489
733
|
- `src/cli.ts` — yargs entry, dispatches subcommands. `holocron run` / `ci` are
|
|
490
734
|
delegated to [`@theholocron/astromech`](../astromech) (`createAstromech`).
|
|
491
|
-
`holocron sync` / `holocron setup` write each repo's `.github/workflows/*.yml`
|
|
492
|
-
thin callers from `astromech.thinCallers()`; `holocron sync
|
|
735
|
+
`holocron repo sync` / `holocron repo setup` write each repo's `.github/workflows/*.yml`
|
|
736
|
+
thin callers from `astromech.thinCallers()`; `holocron sync github` pushes the
|
|
493
737
|
reusable `workflow_call` implementations + composite actions from
|
|
494
738
|
`astromech.reusableTemplates()` to `theholocron/.github` (a pure sync target —
|
|
495
739
|
never hand-edit its `.github/workflows/*`).
|
|
496
|
-
- `src/commands/` — `setup`, `sync`, `doctor`, `deploy`,
|
|
497
|
-
`
|
|
498
|
-
`
|
|
499
|
-
|
|
500
|
-
`
|
|
501
|
-
`
|
|
502
|
-
|
|
740
|
+
- `src/commands/` — `repo setup`, `repo sync`, `doctor`, `deploy`,
|
|
741
|
+
`monitoring check`, `secrets set`, `secrets sync`, `package publish`,
|
|
742
|
+
`package bump-versions`, `sync github`, `repo upgrade node`,
|
|
743
|
+
`repo upgrade deps`, `new plugin`, `auth`, `notifications setup`,
|
|
744
|
+
`notifications channel add`, `notifications link`,
|
|
745
|
+
`notifications sync-roles`, `doctor notifications`
|
|
746
|
+
- `src/interactive-menu/` — the interactive fallback: `command-registry`
|
|
747
|
+
(`COMMAND_REGISTRY`, each entry's `positionals`/`options`), `launch-menu`
|
|
748
|
+
(Layers 1–2, picks + spawns a fresh `holocron <command>`), `child-argv`
|
|
749
|
+
(builds the spawned argv + secret env), `menu-items`, `run-menu-entries`.
|
|
750
|
+
The generic prompting pieces it calls — `promptForPositionals`,
|
|
751
|
+
`promptForOptions` (Layer 3) — live in `src/ui/`, which has no knowledge
|
|
752
|
+
of commands.
|
|
503
753
|
|
|
504
754
|
## Status
|
|
505
755
|
|