@theholocron/astromech 5.0.0-alpha.13 → 5.0.0-alpha.134

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/index.d.mts CHANGED
@@ -1,121 +1,11 @@
1
- import { r as TasksConfig } from "./schema-D01VYg43.mjs";
2
- //#region src/run.d.ts
3
- /**
4
- * `holocron run <task> [job] [-- <passthrough>]` — run a registry task (or one
5
- * of its sub-jobs) locally.
6
- *
7
- * A `job` argument only applies to tasks that declare `jobs`; for any other
8
- * task it is folded back into the passthrough (`holocron run delivery.build
9
- * src/`).
10
- *
11
- * Resolution:
12
- *
13
- * J. job given → TASKS[task].jobs[job].local (unknown job → exit 1)
14
- * 1. turbo.json defines the task → `turbo run <task>`
15
- * 2. package.json has a `<task>` script → `<pm> run <task>`
16
- * (unless it's the `holocron run …` thin caller — that recurses)
17
- * 3. TASKS[task].local resolves → `<tool> <args> <org-flags> <passthrough>`
18
- * 3b. TASKS[task].linterGroup → run each resolved linter natively (see below)
19
- * 4. TASKS[task].jobs has entries → run each job in declared order
20
- * 5. TASKS[task].local === null → "enforced in CI" (skip, even with --required)
21
- * 5b. known task, nothing resolved → "no <task> task" (exit 0, or 1 with --required)
22
- * 6. unknown task → "unknown task" (exit 1)
23
- *
24
- * A `linterGroup` task (`sourceQuality.staticAnalysis`, etc.) runs its fixed
25
- * set of `linters.ts` entries, each still gated by that linter's own
26
- * `detect`/`always` rule — every entry runs its `localBin` natively when
27
- * found on PATH. Missing tools are flagged; the exit code is the worst of
28
- * the lot. Unlike the old single `lint` task, this check runs *after*
29
- * turbo/`package.json` resolution (step 3b, not step 0) — a `linterGroup`
30
- * task is a normal turbo-delegatable task like any other.
31
- */
32
- /** Minimal structural logger — `@theholocron/observability`'s `Logger` satisfies it. */
33
- interface RunLogger {
34
- debug(obj: Record<string, unknown>, msg?: string): void;
35
- warn(obj: Record<string, unknown>, msg?: string): void;
36
- }
37
- type ExecFn = (cmd: string, args: string[], opts: {
38
- cwd: string;
39
- }) => {
40
- exitCode: number;
41
- };
42
- /**
43
- * Everything `runTask` needs from the outside world. `createAstromech`
44
- * fills these with real implementations (or the caller's injected ones);
45
- * `runTask` never reaches for a global itself, so it has no default
46
- * branches to leave untested.
47
- */
48
- interface RunDeps {
49
- print: (line: string) => void;
50
- logger: RunLogger;
51
- exec: ExecFn;
52
- readFile: (path: string) => string;
53
- fileExists: (path: string) => boolean;
54
- listDir: (path: string) => string[];
55
- /** `node_modules/.bin/<bin>` or a PATH entry; `null` when not runnable. */
56
- lookPath: (cwd: string, bin: string) => string | null;
57
- }
58
- interface RunTaskInput extends RunDeps {
59
- /** Registry task name, e.g. `"test"`. */
60
- task: string;
61
- /**
62
- * Sub-job within the task, e.g. `"performance"` in `holocron run audit
63
- * performance`. Ignored (folded into `passthrough`) for tasks with no `jobs`.
64
- */
65
- job?: string;
66
- /** Directory to run in. */
67
- cwd: string;
68
- /** Args after `--` on the command line, forwarded to the tool / turbo / script. */
69
- passthrough?: string[];
70
- /** Print the resolved command without running it. */
71
- dryRun?: boolean;
72
- /** Turn "no such task for this repo" (normally exit 0) into a failure. */
73
- required?: boolean;
74
- /** `turbo --filter=<pkg>` passthrough (monorepo). Ignored when the repo has no `turbo.json`. */
75
- filter?: string;
76
- }
77
- interface RunTaskReport {
78
- status: "ok" | "fail" | "skip" | "dry-run" | "unknown";
79
- /** Resolved command, for the caller / tests. */
80
- command?: string;
81
- message?: string;
82
- }
83
- declare function runTask(input: RunTaskInput): RunTaskReport;
84
- //#endregion
85
- //#region src/ci.d.ts
86
- interface CiOptions {
87
- /** Print the plan without running anything. */
88
- dryRun?: boolean;
89
- /** `turbo --filter=<pkg>` passthrough (monorepo). */
90
- filter?: string;
91
- /** `"required"` (default) or `"all"` (every `ci: true` task). */
92
- scope?: "required" | "all";
93
- }
94
- interface CiJobReport {
95
- task: string;
96
- /** The branch-protection check context, or `null` for a non-gating task. */
97
- checkContext: string | null;
98
- status: "ok" | "fail" | "skip" | "dry-run";
99
- command?: string;
100
- message?: string;
101
- }
102
- interface CiReport {
103
- status: "ok" | "fail";
104
- jobs: CiJobReport[];
105
- }
106
- interface CiInput extends RunDeps, CiOptions {
107
- cwd: string;
108
- config: TasksConfig;
109
- }
110
- declare function runCi(input: CiInput): CiReport;
111
- //#endregion
112
- //#region src/thin-callers.d.ts
1
+ import { r as TasksConfig } from "./schema-BDld3xq1.mjs";
2
+ //#region src/generators/github-action-thin-callers.d.ts
113
3
  /**
114
4
  * Workflow templates + thin-caller generation.
115
5
  *
116
6
  * `WORKFLOW_TEMPLATES` holds each reusable `.github/workflows/<name>.yml`
117
7
  * (synced to `theholocron/.github`); `generateThinCallerContent` wraps one
118
- * into the thin caller `holocron setup` / `holocron sync` write locally.
8
+ * into the thin caller `holocron repo setup` / `holocron repo sync` write locally.
119
9
  */
120
10
  declare const WORKFLOW_TEMPLATES: Record<string, string>;
121
11
  declare const KNOWN_WORKFLOWS: Set<string>;
@@ -165,7 +55,7 @@ interface PreviewConfig {
165
55
  project: string;
166
56
  /**
167
57
  * Base domain for preview URLs (e.g. `"preview.theholocron.dev"`).
168
- * When set, `holocron setup` automatically provisions:
58
+ * When set, `holocron repo setup` automatically provisions:
169
59
  * - Cloudflare Pages custom domain `*.<domain>` on the project
170
60
  * - DNS wildcard CNAME `*.<domain>` → `<project>.pages.dev`
171
61
  *
@@ -212,20 +102,162 @@ declare function generateCombinedDeployContent(deployWith: Record<string, unknow
212
102
  * - run-chromatic object → run-chromatic: true + chromatic-projects
213
103
  * - plain arrays → JSON-stringified for YAML scalar quoting
214
104
  *
215
- * Used by both `holocron setup` and `sync-workflow-templates`.
105
+ * Used by both `holocron repo setup` and `sync-workflow-templates`.
216
106
  */
217
107
  declare function normalizeWorkflowWith(raw: Record<string, unknown>): Record<string, unknown>;
218
108
  /**
219
109
  * Derive on.push.paths entries from the deploy with: shorthand.
220
- * Used by both `holocron setup` and `sync-workflow-templates`.
110
+ * Used by both `holocron repo setup` and `sync-workflow-templates`.
221
111
  */
222
112
  declare function deriveDeployPaths(raw: Record<string, unknown>): string[];
223
113
  //#endregion
224
- //#region src/turbo.d.ts
114
+ //#region src/generators/turbo.d.ts
225
115
  interface EnsureRootWorkspaceMemberResult {
226
116
  content: string;
227
117
  changed: boolean;
228
118
  }
119
+ interface EnsureTurboDependencyResult {
120
+ content: string;
121
+ changed: boolean;
122
+ }
123
+ //#endregion
124
+ //#region src/tasks/run/run.d.ts
125
+ /**
126
+ * `holocron run <task> [job] [-- <passthrough>]` — run a registry task (or one
127
+ * of its sub-jobs) locally.
128
+ *
129
+ * A `job` argument only applies to tasks that declare `jobs`; for any other
130
+ * task it is folded back into the passthrough (`holocron run delivery.build
131
+ * src/`).
132
+ *
133
+ * Resolution:
134
+ *
135
+ * J. job given → TASKS[task].jobs[job].local (unknown job → exit 1)
136
+ * 1. turbo.json defines the task → `turbo run <task>`
137
+ * 2. package.json has a `<task>` script → `<pm> run <task>`
138
+ * (unless it's the `holocron run …` thin caller — that recurses)
139
+ * 3. TASKS[task].local resolves → `<tool> <args> <org-flags> <passthrough>`
140
+ * 3b. TASKS[task].linterGroup → run each resolved linter natively (see below)
141
+ * 4. TASKS[task].jobs has entries → run each job in declared order
142
+ * 5. TASKS[task].local === null → "enforced in CI" (skip, even with --required)
143
+ * 5b. known task, nothing resolved → "no <task> task" (exit 0, or 1 with --required)
144
+ * 6. unknown task → "unknown task" (exit 1)
145
+ *
146
+ * A `linterGroup` task (`sourceQuality.staticAnalysis`, etc.) runs its fixed
147
+ * set of `linters.ts` entries, each still gated by that linter's own
148
+ * `detect`/`always` rule — every entry runs its `localBin` natively when
149
+ * found on PATH. Missing tools are flagged; the exit code is the worst of
150
+ * the lot. Unlike the old single `lint` task, this check runs *after*
151
+ * turbo/`package.json` resolution (step 3b, not step 0) — a `linterGroup`
152
+ * task is a normal turbo-delegatable task like any other.
153
+ */
154
+ /** Minimal structural logger — `@theholocron/observability`'s `Logger` satisfies it. */
155
+ interface RunLogger {
156
+ debug(obj: Record<string, unknown>, msg?: string): void;
157
+ warn(obj: Record<string, unknown>, msg?: string): void;
158
+ }
159
+ type ExecFn = (cmd: string, args: string[], opts: {
160
+ cwd: string;
161
+ }) => {
162
+ exitCode: number;
163
+ };
164
+ /**
165
+ * Everything `runTask` needs from the outside world. `createAstromech`
166
+ * fills these with real implementations (or the caller's injected ones);
167
+ * `runTask` never reaches for a global itself, so it has no default
168
+ * branches to leave untested.
169
+ */
170
+ interface RunDeps {
171
+ print: (line: string) => void;
172
+ logger: RunLogger;
173
+ exec: ExecFn;
174
+ readFile: (path: string) => string;
175
+ fileExists: (path: string) => boolean;
176
+ listDir: (path: string) => string[];
177
+ /** `node_modules/.bin/<bin>` or a PATH entry; `null` when not runnable. */
178
+ lookPath: (cwd: string, bin: string) => string | null;
179
+ }
180
+ interface RunTaskInput extends RunDeps {
181
+ /** Registry task name, e.g. `"test"`. */
182
+ task: string;
183
+ /**
184
+ * Sub-job within the task, e.g. `"performance"` in `holocron run audit
185
+ * performance`. Ignored (folded into `passthrough`) for tasks with no `jobs`.
186
+ */
187
+ job?: string;
188
+ /** Directory to run in. */
189
+ cwd: string;
190
+ /** Args after `--` on the command line, forwarded to the tool / turbo / script. */
191
+ passthrough?: string[];
192
+ /** Print the resolved command without running it. */
193
+ dryRun?: boolean;
194
+ /** Turn "no such task for this repo" (normally exit 0) into a failure. */
195
+ required?: boolean;
196
+ /** `turbo --filter=<pkg>` passthrough (monorepo). Ignored when the repo has no `turbo.json`. */
197
+ filter?: string;
198
+ }
199
+ interface RunTaskReport {
200
+ status: "ok" | "fail" | "skip" | "dry-run" | "unknown";
201
+ /** Resolved command, for the caller / tests. */
202
+ command?: string;
203
+ message?: string;
204
+ }
205
+ declare function runTask(input: RunTaskInput): RunTaskReport;
206
+ //#endregion
207
+ //#region src/tasks/ci.d.ts
208
+ interface CiOptions {
209
+ /** Print the plan without running anything. */
210
+ dryRun?: boolean;
211
+ /** `turbo --filter=<pkg>` passthrough (monorepo). */
212
+ filter?: string;
213
+ /** `"required"` (default) or `"all"` (every `ci: true` task). */
214
+ scope?: "required" | "all";
215
+ }
216
+ interface CiJobReport {
217
+ task: string;
218
+ /** The branch-protection check context, or `null` for a non-gating task. */
219
+ checkContext: string | null;
220
+ status: "ok" | "fail" | "skip" | "dry-run";
221
+ command?: string;
222
+ message?: string;
223
+ }
224
+ interface CiReport {
225
+ status: "ok" | "fail";
226
+ jobs: CiJobReport[];
227
+ }
228
+ interface CiInput extends RunDeps, CiOptions {
229
+ cwd: string;
230
+ config: TasksConfig;
231
+ }
232
+ declare function runCi(input: CiInput): CiReport;
233
+ //#endregion
234
+ //#region src/tasks/group.d.ts
235
+ interface GroupOptions {
236
+ /** Print the resolved commands without running anything. */
237
+ dryRun?: boolean;
238
+ /** `turbo --filter=<pkg>` passthrough (monorepo). */
239
+ filter?: string;
240
+ }
241
+ interface GroupJobReport {
242
+ task: string;
243
+ status: "ok" | "fail" | "skip" | "dry-run";
244
+ command?: string;
245
+ message?: string;
246
+ }
247
+ interface GroupReport {
248
+ /** `"unknown"` when the namespace matches zero configured tasks. */
249
+ status: "ok" | "fail" | "dry-run" | "unknown";
250
+ jobs: GroupJobReport[];
251
+ }
252
+ interface GroupInput extends RunDeps, GroupOptions {
253
+ cwd: string;
254
+ config: TasksConfig;
255
+ /** The bare namespace, e.g. `"sourceQuality"` — matched against `"sourceQuality."`-prefixed task names. */
256
+ namespace: string;
257
+ }
258
+ /** Every configured task whose name starts with `"<namespace>."`, in manifest declaration order. */
259
+ declare function matchNamespace(config: TasksConfig, namespace: string): string[];
260
+ declare function runGroup(input: GroupInput): GroupReport;
229
261
  //#endregion
230
262
  //#region src/astromech.d.ts
231
263
  interface AstromechOptions {
@@ -272,8 +304,15 @@ interface RunOptions {
272
304
  filter?: string;
273
305
  }
274
306
  interface Astromech {
275
- /** Run one task — or one of its sub-jobs (`opts.job`) — locally. */
276
- run(task: string, opts?: RunOptions): RunTaskReport;
307
+ /**
308
+ * Run one task — or one of its sub-jobs (`opts.job`) — locally. When
309
+ * `task` isn't an exact registry task but matches the prefix of one or
310
+ * more configured tasks (`"sourceQuality"` against `sourceQuality.*`),
311
+ * runs every matching task in sequence instead ({@link GroupReport}) —
312
+ * `opts.job` is ignored for a namespace match, since a job belongs to
313
+ * one task, not a namespace.
314
+ */
315
+ run(task: string, opts?: RunOptions): RunTaskReport | GroupReport;
277
316
  /**
278
317
  * Run the merge-gating checks locally, in CI order — "will CI pass?".
279
318
  * Default scope: `required: true` tasks (falls back to every `ci: true`
@@ -288,7 +327,7 @@ interface Astromech {
288
327
  */
289
328
  thinCallers(): Map<string, string>;
290
329
  /**
291
- * The complete reusable-workflow batch `holocron sync-github` pushes to
330
+ * The complete reusable-workflow batch `holocron sync github` pushes to
292
331
  * `theholocron/.github` — repo-relative path → content, "do not edit" header
293
332
  * already applied to the YAML. Config-independent (the same for every repo).
294
333
  */
@@ -301,10 +340,19 @@ interface Astromech {
301
340
  * when there is no config or `syncScripts: false`.
302
341
  */
303
342
  packageScripts(): Record<string, string>;
343
+ /**
344
+ * Task names this repo's manifest can actually run locally — the same
345
+ * filter {@link packageScripts} applies (skips `local: false` and tasks
346
+ * with no local runner at all), but independent of `syncScripts`: a repo
347
+ * that opts out of generated `package.json` scripts still has real
348
+ * runnable tasks. Empty when there is no config. Backs `holocron`'s own
349
+ * interactive task picker (`run` with no task given).
350
+ */
351
+ runnableTasks(): string[];
304
352
  /**
305
353
  * The branch-protection required-status-check contexts for this repo —
306
354
  * every `required: true` task's check context plus `extraRequiredChecks`,
307
- * ordered and de-duplicated. `holocron setup` prepends `"DCO"` and applies
355
+ * ordered and de-duplicated. `holocron repo setup` prepends `"DCO"` and applies
308
356
  * the list; this method is policy-free (manifest only).
309
357
  */
310
358
  requiredChecks(): string[];
@@ -312,7 +360,7 @@ interface Astromech {
312
360
  * This repo's `codecov.yml` — component `paths` derived from `packages/*`.
313
361
  * Pass the current file's content (`null` if none exists yet) to either
314
362
  * merge the component list in or scaffold a fresh file. Policy-free same
315
- * as {@link requiredChecks} — `holocron setup` owns writing the result.
363
+ * as {@link requiredChecks} — `holocron repo setup` owns writing the result.
316
364
  */
317
365
  codecovConfig(existing: string | null): string;
318
366
  /**
@@ -328,27 +376,41 @@ interface Astromech {
328
376
  * (not just an orchestrator) silently vanishes from `turbo run <task>`.
329
377
  * Pass `pnpm-workspace.yaml`'s current content (or `""` if none exists —
330
378
  * a no-op either way, since no `packages:` key means single-package mode
331
- * already) and root `package.json`'s own `scripts` keys. `changed: false`
332
- * means don't write anything — the file is already correct.
379
+ * already) and root `package.json`'s own `scripts` object — values and
380
+ * all, not just keys, so a task-name-matching script that's already the
381
+ * generated `holocron run <task> --` wrapper (predating this call, not
382
+ * written by it) is correctly excluded rather than treated as proof root
383
+ * is directly buildable (#846). `changed: false` means don't write
384
+ * anything — the file is already correct.
385
+ */
386
+ ensureRootWorkspaceMember(workspaceYaml: string, rootScripts: Readonly<Record<string, string>>): EnsureRootWorkspaceMemberResult;
387
+ /**
388
+ * `turboConfig()` writes a `turbo.json` but never touches `package.json`
389
+ * — a repo with no local `turbo` devDependency falls back to whatever
390
+ * (if anything) is globally on `PATH`, per `run.ts`'s `resolveBin()`.
391
+ * Pass root `package.json`'s raw content and `pnpm-workspace.yaml`'s
392
+ * current content (checked for an existing `turbo` catalog entry, which
393
+ * takes precedence over the hardcoded fallback version). `changed: false`
394
+ * means don't write anything — `devDependencies.turbo` already exists.
333
395
  */
334
- ensureRootWorkspaceMember(workspaceYaml: string, rootScripts: readonly string[]): EnsureRootWorkspaceMemberResult;
396
+ ensureTurboDependency(packageJson: string, workspaceYaml: string): EnsureTurboDependencyResult;
335
397
  }
336
398
  declare function createAstromech(options: AstromechOptions): Astromech;
337
399
  //#endregion
338
- //#region src/codecov.d.ts
400
+ //#region src/generators/codecov.d.ts
339
401
  /**
340
402
  * `codecov.yml` generation — a manifest-derived artifact (component `paths`
341
403
  * come from workspace packages; the status targets track the `test` task's
342
404
  * coverage setup), the same category as the reusable `test.yml` this package
343
405
  * also generates. Moved out of `@theholocron/cli` (theholocron/holocron#650)
344
- * — `holocron setup`'s codecov step now calls {@link codecovConfig} instead
406
+ * — `holocron repo setup`'s codecov step now calls {@link codecovConfig} instead
345
407
  * of importing this logic directly.
346
408
  */
347
409
  interface WorkspacePackage {
348
410
  slug: string;
349
411
  name: string;
350
412
  /** Which workspace root the package was discovered under. Defaults to `"packages"`. */
351
- dir?: "packages" | "apps";
413
+ dir?: "packages" | "apps" | "plugins";
352
414
  }
353
415
  declare function codecovComponentBlock(packages: WorkspacePackage[]): string;
354
416
  /**
@@ -364,97 +426,127 @@ declare function codecovComponentBlock(packages: WorkspacePackage[]): string;
364
426
  declare function ensureIfNotFound(yaml: string): string;
365
427
  declare function mergeCodecovComponents(existing: string, packages: WorkspacePackage[]): string;
366
428
  /**
367
- * Every public `packages/*` and `apps/*` workspace, sorted by slug. `[]`
368
- * when neither directory exists. Monorepo templates (Next.js, React, …)
369
- * ship user-facing code under `apps/` alongside library code under
370
- * `packages/` — both need a codecov component so `codecov/patch/<slug>`
371
- * actually posts for each.
429
+ * Every public `packages/*`, `apps/*`, and `plugins/*` workspace, sorted by
430
+ * slug. `[]` when none of the three directories exist. Monorepo templates
431
+ * (Next.js, React, …) ship user-facing code under `apps/` alongside library
432
+ * code under `packages/`; `holocron` itself splits vendor plugin packages
433
+ * into their own `plugins/*` root — every recognized root needs a codecov
434
+ * component so `codecov/patch/<slug>` actually posts for each.
372
435
  */
373
436
  declare function readWorkspacePackages(repoRoot: string): WorkspacePackage[];
374
437
  /** A brand-new `codecov.yml` — the scaffold header + the base template + this repo's component list. */
375
438
  declare function createCodecovConfig(packages: WorkspacePackage[]): string;
376
439
  /**
377
- * The full pipeline `holocron setup` needs: read this repo's public
440
+ * The full pipeline `holocron repo setup` needs: read this repo's public
378
441
  * `packages/*`, then either merge them into an `existing` `codecov.yml` or
379
442
  * scaffold a new one.
380
443
  */
381
444
  declare function codecovConfig(repoRoot: string, existing: string | null): string;
382
445
  //#endregion
383
- //#region src/linters.d.ts
446
+ //#region src/generators/github-action-reusable-workflows.d.ts
384
447
  /**
385
- * The linter registry — one list of linter names (from `config.tasks`'
386
- * `{ name: "lint", linters: [...] }`, or auto-detected) maps to both the
387
- * CI super-linter `VALIDATE_*` env and the native local run. This table is
388
- * the single source of truth for that mapping; {@link superLinterConfig}
389
- * (CI) and the `holocron run lint` aggregate (local) both read it.
448
+ * The **reusable** GitHub Actions surface pushed to `theholocron/.github` by
449
+ * `holocron sync github` — the `workflow_call` implementations and composite
450
+ * actions that every repo's thin callers delegate to.
451
+ *
452
+ * `theholocron/.github` is a **pure sync target**: `.github/workflows/*`,
453
+ * `.github/actions/*` and `workflow-templates/*` there are generated from the
454
+ * `.yml` files in `src/templates/reusable/` and pushed verbatim (with a
455
+ * "do not edit" header). Never hand-edit them in `.github`.
390
456
  *
391
- * Spec: `docs/wiki/specifications/tech-astromech-task-runner.spec.md` "Lint parity".
457
+ * Not to be confused with `WORKFLOW_TEMPLATES` in `github-action-thin-callers.ts` — those are
458
+ * the *thin-caller bases* written into each consumer repo's `.github/workflows/`.
392
459
  */
393
- interface LinterDef {
394
- /**
395
- * super-linter `VALIDATE_*` keys this linter turns on. Setting any
396
- * `VALIDATE_*` puts super-linter in allow-list mode, so emitting only the
397
- * enabled keys makes it run exactly this set.
398
- */
399
- validate: string[];
400
- /** super-linter `FIX_*` keys (auto-commit / `--write` parity). */
401
- fix?: string[];
402
- /**
403
- * Local binary, resolved from `node_modules/.bin` then `PATH`. Absent →
404
- * the linter has no meaningful local run (`holocron run lint` prints
405
- * "CI only"); CI still enforces it.
406
- */
407
- localBin?: string;
408
- /** Args for `localBin` in CHECK mode — never `--write` / `--fix`. */
409
- localArgs?: string[];
460
+ /** `workflow_call` implementations → `.github/workflows/<name>.yml`. */
461
+ declare const REUSABLE_WORKFLOWS: Record<string, string>;
462
+ /** Composite actions → `.github/actions/<name>/action.yml` (key includes `/action`). */
463
+ declare const REUSABLE_ACTIONS: Record<string, string>;
464
+ /** GitHub starter-workflow metadata → `workflow-templates/<name>.properties.json`. */
465
+ declare const WORKFLOW_TEMPLATE_PROPERTIES: Record<string, string>;
466
+ /**
467
+ * The complete file batch `holocron sync github` pushes to `theholocron/.github`:
468
+ * path → content. YAML gets the "do not edit" header; the starter-workflow
469
+ * `.properties.json` files are left bare (native JSON, not a commented file).
470
+ */
471
+ declare function reusableTemplates(): Map<string, string>;
472
+ //#endregion
473
+ //#region src/generators/required-checks.d.ts
474
+ /** Ordered (task contexts in {@link CI_ORDER}, then extras), de-duplicated. */
475
+ declare function requiredChecks(config: TasksConfig): string[];
476
+ //#endregion
477
+ //#region src/generators/tsconfig.d.ts
478
+ /**
479
+ * `tsconfig.json` generation — Bucket B (config-resolution workstream, #676):
480
+ * the file must stay committed (the TypeScript language server discovers it
481
+ * directly from disk, no `--config` override mechanism to hand it a path
482
+ * instead), but its content is fully derivable, so it's generated rather
483
+ * than hand-authored — the same category as `.editorconfig`
484
+ * ({@link "./templates/configs/editorconfig/create-config.js" createConfig})
485
+ * and {@link codecovConfig}.
486
+ *
487
+ * Surveyed every package-level `tsconfig.json` across the org (`holocron`,
488
+ * `clients`, `utils` — 20+ packages). `extends: "@theholocron/tsconfig/
489
+ * node-lts"`, `compilerOptions.baseUrl: "./"`, `compilerOptions.outDir:
490
+ * "./dist"`, `include: ["src/**\/*.ts"]`, and `exclude: ["node_modules",
491
+ * "dist"]` are uniform in every one — safe defaults here. `paths` (a `@/*`
492
+ * → `./src/*` import alias) is a real per-package choice, present in
493
+ * roughly 40% of packages checked — an opt-in parameter, not a default.
494
+ *
495
+ * Two fields checked and deliberately *not* absorbed as defaults, unlike
496
+ * `eslint-config`'s `tsconfigRootDir`/`settings.node` (which turned out
497
+ * redundant with the shared package's own behavior, `configs`#461):
498
+ * `compilerOptions.module`/`moduleResolution` (only `@theholocron/cli`
499
+ * overrides these, to `esnext`/`bundler` — a genuine deviation from the
500
+ * shared `node-lts` preset's `nodenext`/`nodenext`, needed for its bundler
501
+ * tooling, not something every package should inherit) and
502
+ * `compilerOptions.rootDir` (present in exactly two packages, always the
503
+ * same value `./src` that `include` already implies — an unnecessary
504
+ * override wherever it appears, not a pattern worth generalizing).
505
+ *
506
+ * Monorepo *root* `tsconfig.json` (a TS project-references "solution
507
+ * file" — `holocron`'s own root is `{ files: [], references: [...] }`,
508
+ * listing which packages to build) is a structurally different, genuinely
509
+ * per-repo document — out of scope here, same as Bucket C content.
510
+ *
511
+ * Not yet wired into `holocron repo setup`'s per-package write loop (every
512
+ * other Bucket B file there is a single repo-root file, safely
513
+ * overwritten every run — `tsconfig.json` is per-package, and most
514
+ * packages' files still carry real hand-authored content today, not yet
515
+ * migrated to a fully-generated state). That per-package iteration +
516
+ * safe-migration design is `#680`'s job, not duplicated here — this is
517
+ * the generator itself, ready for it to call.
518
+ */
519
+ interface TsconfigOptions {
520
+ /** Human-readable name for the `display` field — the package's own name is the usual choice. */
521
+ display: string;
410
522
  /**
411
- * Shown by `holocron run lint` when `localBin` is set but not found on
412
- * PATH — the "you're missing a tool the repo needs" nudge.
523
+ * `@theholocron/tsconfig` variant. Defaults to `"node-lts"` — every
524
+ * checked package uses it; the other three (`astro`, `nextjs`, `react`)
525
+ * exist for a template repo's app-shaped packages, not the plain
526
+ * Node.js library packages this org's currently-migrated repos ship.
413
527
  */
414
- installHint?: string;
528
+ variant?: "astro" | "nextjs" | "node-lts" | "react";
415
529
  /**
416
- * Repo-root filenames that auto-enable this linter when the `lint` task
417
- * has no explicit `linters` list. Ignored when {@link always} is set.
530
+ * Add a `@/*` → `./src/*` path alias. A real per-package choice, not a
531
+ * default — roughly 40% of packages checked use one, the rest don't.
418
532
  */
419
- detect?: string[];
420
- /** Enabled regardless of detection (the org baseline). */
421
- always?: boolean;
422
- /** Reusable-workflow config-file input this linter honors, if any. */
423
- configInput?: "eslint-config" | "prettier-config" | "yaml-config";
533
+ paths?: boolean;
424
534
  }
425
535
  /**
426
- * Known linters, in execution order. `always` entries are the current
427
- * hard-coded super-linter baseline; `prettier` is always-on because the org
428
- * applies it universally (super-linter only lints files that exist).
429
- */
430
- declare const LINTERS: Record<string, LinterDef>;
431
- /** Every linter name the registry knows. */
432
- declare const LINTER_NAMES: ReadonlySet<string>;
433
- /**
434
- * Resolve the linter set for a repo. An `explicit` list (from `config.tasks`)
435
- * picks the candidate set; otherwise the candidates are every `always` linter
436
- * plus every `detect`-gated linter whose filenames are present at the repo
437
- * root. Either way, a `detect`-gated linter (eslint, markdownlint) only makes
438
- * the final set when its config file is actually present — a repo can't run
439
- * eslint without an `eslint.config.*`, and super-linter FATALs if you ask it
440
- * to (theholocron/holocron#654). `always` linters are unconditional. Result
441
- * is ordered by {@link LINTERS} declaration order.
442
- *
443
- * @throws when an `explicit` name is not in the registry — a typo is a
444
- * config bug, not a linter to silently skip.
536
+ * A package-level `tsconfig.json` — the uniform shape confirmed across
537
+ * every package checked, parameterized only by the two fields that
538
+ * genuinely vary (`display`, `paths`). No scaffold/workflow header (matches
539
+ * `.alexrc.json`'s existing precedent for a strict-JSON Bucket B file —
540
+ * JSON has no comment syntax to carry one, and TypeScript's own tolerance
541
+ * for JSONC comments in `tsconfig.json` isn't worth relying on for a file
542
+ * this thin).
445
543
  */
446
- declare function resolveLinters(opts: {
447
- explicit?: string[];
448
- rootFiles: string[];
449
- }): Array<{
450
- name: string;
451
- def: LinterDef;
452
- }>;
544
+ declare function createTsconfig(options: TsconfigOptions): string;
453
545
  //#endregion
454
546
  //#region src/registry.d.ts
455
547
  /**
456
548
  * The task registry — how each task runs *locally*, without GitHub
457
- * Actions. `holocron run <task>` and `holocron ci` resolve against this;
549
+ * Actions. `holocron run <task>` and `holocron run ci` resolve against this;
458
550
  * adding a task here gives every repo that task.
459
551
  *
460
552
  * Keyed identically to the workflow templates — a task IS a workflow. This
@@ -468,7 +560,7 @@ declare function resolveLinters(opts: {
468
560
  * `sourceQuality.*`, `security.*`, `delivery.*`, `platform.*`,
469
561
  * `knowledge.*`), not tool names — `eslint`/`vitest`/`tsdown`/… stay
470
562
  * internal to this file and `theholocron/configs`. See
471
- * `.notes/tech-vocabulary-rename.spec.md` (#675) for the full mapping and
563
+ * `docs/wiki/specifications/tech-vocabulary-rename.spec.md` (#675) for the full mapping and
472
564
  * the reasoning behind each namespace and decomposition.
473
565
  *
474
566
  * Spec: `docs/wiki/specifications/tech-astromech-task-runner.spec.md` (epic #581).
@@ -511,7 +603,7 @@ interface JobDef {
511
603
  /**
512
604
  * The CI status-check context this job reports as (e.g.
513
605
  * `platform.repoValidation / Validate registry consistency`) — every sub-job is a CI job.
514
- * `holocron run <task>` and `holocron ci` label each job line with it;
606
+ * `holocron run <task>` and `holocron run ci` label each job line with it;
515
607
  * the task-level `… / Conclusion` context (only for tasks with several
516
608
  * jobs) lives in `WORKFLOW_CHECK_CONTEXTS`.
517
609
  */
@@ -522,7 +614,7 @@ interface TaskDef {
522
614
  * `null` — the registry has no built-in runner (CodeQL, deploys, the
523
615
  * bundle-size job). An explicit turbo task or `package.json` script still
524
616
  * runs (resolution steps 1–2); with neither, `holocron run` does nothing
525
- * and `holocron ci` skips it — never a failure, even when the task is
617
+ * and `holocron run ci` skips it — never a failure, even when the task is
526
618
  * `required` (a CI-only check isn't a local one).
527
619
  */
528
620
  local: LocalRunner | null;
@@ -552,151 +644,58 @@ declare const TASKS: Record<string, TaskDef>;
552
644
  /** Every task name the registry knows. */
553
645
  declare const KNOWN_TASKS: Set<string>;
554
646
  /**
555
- * The order `holocron ci` runs tasks in — cheapest / fastest signal first, so
647
+ * The order `holocron run ci` runs tasks in — cheapest / fastest signal first, so
556
648
  * an agent or a `pre-push` hook fails early. Tasks not listed here run last, in
557
649
  * manifest order. (The generated thin callers carry no `needs:` — cross-workflow
558
- * ordering lives in `theholocron/.github` — so `holocron ci` declares its own.)
650
+ * ordering lives in `theholocron/.github` — so `holocron run ci` declares its own.)
559
651
  */
560
652
  declare const CI_ORDER: string[];
561
653
  //#endregion
562
- //#region src/required-checks.d.ts
563
- /** Ordered (task contexts in {@link CI_ORDER}, then extras), de-duplicated. */
564
- declare function requiredChecks(config: TasksConfig): string[];
565
- //#endregion
566
- //#region src/resolver.d.ts
567
- /**
568
- * Resolves the absolute path to a Bucket A tool's shared `@theholocron/*-config`
569
- * entry point, installed in the consuming repo's own `node_modules` — and the
570
- * CLI flag(s) to hand it via (`--config`, `--extends`, …). `run.ts` splices the
571
- * result into the command it builds for a tool/detect runner or a linter-group
572
- * entry, right after the tool's own args.
573
- *
574
- * Every mapped package's resolved entry point already carries a ready-to-use
575
- * default export (a plain re-export for `prettier`/`commitlint`; an invoked,
576
- * zero-arg preset for `eslint`/`vitest`/`tsdown` — verified end-to-end against
577
- * each tool's real `--config`/`--extends` loader, not just the file's shape).
578
- * A repo doesn't need this package installed at all — every lookup degrades to
579
- * `[]` (no flag added, the tool falls back to its own auto-discovery of a
580
- * local file, unchanged from today) rather than throwing, so this is additive
581
- * and safe to run unconditionally.
582
- *
583
- * `semantic-release`, `devmoji`, `editorconfig-checker`, and `knip` are
584
- * deliberately absent — `semantic-release-config`'s `defineConfig()` needs
585
- * real per-repo data (branches, npm options) a static `--extends <path>` can't
586
- * carry; `devmoji` runs through a git hook template, not `holocron run
587
- * <task>`; `editorconfig-checker` has no shared-config package yet; `knip` is
588
- * repo-specific by nature, never a shared-config candidate. See
589
- * `.notes/tech-config-resolution.spec.md` (#676).
590
- */
591
- interface ResolverDeps {
592
- readFile: (path: string) => string;
593
- fileExists: (path: string) => boolean;
654
+ //#region src/tasks/deploy-on-release.d.ts
655
+ interface SpawnResult {
656
+ status: number | null;
657
+ stdout: string;
658
+ stderr: string;
594
659
  }
595
- /** Every tool name the resolver knows how to point at a shared config. */
596
- declare const RESOLVABLE_TOOLS: ReadonlySet<string>;
597
- /**
598
- * `<flag> <absolute path>` for `tool`, resolved against `cwd`'s
599
- * `node_modules` — or `[]` when the tool isn't mapped, the package isn't
600
- * installed, its `package.json` doesn't declare the export subpath this
601
- * needs, or the resolved file doesn't actually exist on disk (a stale
602
- * install, or a package version that predates the export existing).
603
- */
604
- declare function resolveToolConfig(tool: string, cwd: string, deps: ResolverDeps): string[];
605
- //#endregion
606
- //#region src/reusable.d.ts
607
- /**
608
- * The **reusable** GitHub Actions surface pushed to `theholocron/.github` by
609
- * `holocron sync-github` — the `workflow_call` implementations and composite
610
- * actions that every repo's thin callers delegate to.
611
- *
612
- * `theholocron/.github` is a **pure sync target**: `.github/workflows/*`,
613
- * `.github/actions/*` and `workflow-templates/*` there are generated from the
614
- * `.yml` files in `src/templates/reusable/` and pushed verbatim (with a
615
- * "do not edit" header). Never hand-edit them in `.github`.
616
- *
617
- * Not to be confused with `WORKFLOW_TEMPLATES` in `thin-callers.ts` — those are
618
- * the *thin-caller bases* written into each consumer repo's `.github/workflows/`.
619
- */
620
- /** `workflow_call` implementations → `.github/workflows/<name>.yml`. */
621
- declare const REUSABLE_WORKFLOWS: Record<string, string>;
622
- /** Composite actions → `.github/actions/<name>/action.yml` (key includes `/action`). */
623
- declare const REUSABLE_ACTIONS: Record<string, string>;
624
- /** GitHub starter-workflow metadata → `workflow-templates/<name>.properties.json`. */
625
- declare const WORKFLOW_TEMPLATE_PROPERTIES: Record<string, string>;
626
- /**
627
- * The complete file batch `holocron sync-github` pushes to `theholocron/.github`:
628
- * path → content. YAML gets the "do not edit" header; the starter-workflow
629
- * `.properties.json` files are left bare (native JSON, not a commented file).
630
- */
631
- declare function reusableTemplates(): Map<string, string>;
632
- //#endregion
633
- //#region src/tsconfig.d.ts
634
- /**
635
- * `tsconfig.json` generation — Bucket B (config-resolution workstream, #676):
636
- * the file must stay committed (the TypeScript language server discovers it
637
- * directly from disk, no `--config` override mechanism to hand it a path
638
- * instead), but its content is fully derivable, so it's generated rather
639
- * than hand-authored — the same category as `.editorconfig`
640
- * ({@link "./templates/configs/editorconfig/create-config.js" createConfig})
641
- * and {@link codecovConfig}.
642
- *
643
- * Surveyed every package-level `tsconfig.json` across the org (`holocron`,
644
- * `clients`, `utils` — 20+ packages). `extends: "@theholocron/tsconfig/
645
- * node-lts"`, `compilerOptions.baseUrl: "./"`, `compilerOptions.outDir:
646
- * "./dist"`, `include: ["src/**\/*.ts"]`, and `exclude: ["node_modules",
647
- * "dist"]` are uniform in every one — safe defaults here. `paths` (a `@/*`
648
- * → `./src/*` import alias) is a real per-package choice, present in
649
- * roughly 40% of packages checked — an opt-in parameter, not a default.
650
- *
651
- * Two fields checked and deliberately *not* absorbed as defaults, unlike
652
- * `eslint-config`'s `tsconfigRootDir`/`settings.node` (which turned out
653
- * redundant with the shared package's own behavior, `configs`#461):
654
- * `compilerOptions.module`/`moduleResolution` (only `@theholocron/cli`
655
- * overrides these, to `esnext`/`bundler` — a genuine deviation from the
656
- * shared `node-lts` preset's `nodenext`/`nodenext`, needed for its bundler
657
- * tooling, not something every package should inherit) and
658
- * `compilerOptions.rootDir` (present in exactly two packages, always the
659
- * same value `./src` that `include` already implies — an unnecessary
660
- * override wherever it appears, not a pattern worth generalizing).
661
- *
662
- * Monorepo *root* `tsconfig.json` (a TS project-references "solution
663
- * file" — `holocron`'s own root is `{ files: [], references: [...] }`,
664
- * listing which packages to build) is a structurally different, genuinely
665
- * per-repo document — out of scope here, same as Bucket C content.
666
- *
667
- * Not yet wired into `holocron setup`'s per-package write loop (every
668
- * other Bucket B file there is a single repo-root file, safely
669
- * overwritten every run — `tsconfig.json` is per-package, and most
670
- * packages' files still carry real hand-authored content today, not yet
671
- * migrated to a fully-generated state). That per-package iteration +
672
- * safe-migration design is `#680`'s job, not duplicated here — this is
673
- * the generator itself, ready for it to call.
674
- */
675
- interface TsconfigOptions {
676
- /** Human-readable name for the `display` field — the package's own name is the usual choice. */
677
- display: string;
678
- /**
679
- * `@theholocron/tsconfig` variant. Defaults to `"node-lts"` — every
680
- * checked package uses it; the other three (`astro`, `nextjs`, `react`)
681
- * exist for a template repo's app-shaped packages, not the plain
682
- * Node.js library packages this org's currently-migrated repos ship.
683
- */
684
- variant?: "astro" | "nextjs" | "node-lts" | "react";
685
- /**
686
- * Add a `@/*` → `./src/*` path alias. A real per-package choice, not a
687
- * default — roughly 40% of packages checked use one, the rest don't.
688
- */
689
- paths?: boolean;
660
+ type Run = (command: string, args: string[], options: Record<string, unknown>) => SpawnResult;
661
+ interface Tree {
662
+ readJson: (path: string) => unknown;
663
+ listDirs: (path: string) => string[];
664
+ }
665
+ interface DeployOnReleaseOptions {
666
+ cwd: string;
667
+ /** The release's channel: its prerelease identifier (`alpha`); empty or `main` for a stable release. */
668
+ channel: string;
669
+ /** The previous release's commit; omitted when there is none, so every deploying channel match deploys. */
670
+ from?: string;
671
+ /** The release commit. Default `HEAD`. */
672
+ to?: string;
673
+ /** Where progress lines go (stdout in the CLI). */
674
+ print: (line: string) => void;
675
+ dryRun?: boolean;
676
+ }
677
+ interface DeployOnReleaseDeps extends Partial<Tree> {
678
+ run?: Run;
679
+ sleep?: (ms: number) => Promise<void>;
680
+ now?: () => number;
681
+ /** Reads a package folder's task manifest; `loadTasksConfig` by default. */
682
+ loadTasks?: (dir: string) => Promise<TasksConfig>;
683
+ }
684
+ interface DeployOnReleaseResult {
685
+ pkg: string;
686
+ status: "ok" | "fail" | "skip" | "dry-run";
687
+ message: string;
688
+ }
689
+ interface DeployOnReleaseReport {
690
+ /** `fail` if any package's deploy failed; `skip` if none applied to this release; else `ok`. */
691
+ status: "ok" | "fail" | "skip";
692
+ results: DeployOnReleaseResult[];
690
693
  }
691
694
  /**
692
- * A package-level `tsconfig.json` — the uniform shape confirmed across
693
- * every package checked, parameterized only by the two fields that
694
- * genuinely vary (`display`, `paths`). No scaffold/workflow header (matches
695
- * `.alexrc.json`'s existing precedent for a strict-JSON Bucket B file —
696
- * JSON has no comment syntax to carry one, and TypeScript's own tolerance
697
- * for JSONC comments in `tsconfig.json` isn't worth relying on for a file
698
- * this thin).
695
+ * Deploys every package whose manifest declares a release-time deploy that
696
+ * applies to this release. Never throws for a deploy problem: each package's
697
+ * outcome is in the report, and `status: "fail"` is the caller's exit code.
699
698
  */
700
- declare function createTsconfig(options: TsconfigOptions): string;
699
+ declare function deployOnRelease(options: DeployOnReleaseOptions, { run, readJson, listDirs, sleep, now, loadTasks }?: DeployOnReleaseDeps): Promise<DeployOnReleaseReport>;
701
700
  //#endregion
702
- export { type Astromech, type AstromechOptions, CI_ORDER, type CiJobReport, type CiOptions, type CiReport, type ExecFn, type JobDef, KNOWN_TASKS, KNOWN_WORKFLOWS, LINTERS, LINTER_NAMES, type LinterDef, type LocalRunner, type OrgContext, type PreviewConfig, RESOLVABLE_TOOLS, REUSABLE_ACTIONS, REUSABLE_WORKFLOWS, type ResolverDeps, type RunLogger, type RunOptions, type RunTaskInput, type RunTaskReport, TASKS, type TaskDef, type TsconfigOptions, WORKFLOW_CHECK_CONTEXTS, WORKFLOW_TEMPLATES, WORKFLOW_TEMPLATE_PROPERTIES, type WorkspacePackage, codecovComponentBlock, codecovConfig, createAstromech, createCodecovConfig, createTsconfig, deriveDeployPaths, ensureIfNotFound, extractPreviewConfig, generateCombinedDeployContent, generateThinCallerContent, mergeCodecovComponents, normalizeWorkflowWith, readWorkspacePackages, requiredChecks, resolveLinters, resolveToolConfig, reusableTemplates, runCi, runTask };
701
+ export { type Astromech, type AstromechOptions, CI_ORDER, type CiJobReport, type CiOptions, type CiReport, type DeployOnReleaseOptions, type DeployOnReleaseReport, type DeployOnReleaseResult, type ExecFn, type GroupJobReport, type GroupOptions, type GroupReport, type JobDef, KNOWN_TASKS, KNOWN_WORKFLOWS, type LocalRunner, type OrgContext, type PreviewConfig, REUSABLE_ACTIONS, REUSABLE_WORKFLOWS, type RunLogger, type RunOptions, type RunTaskInput, type RunTaskReport, TASKS, type TaskDef, type TsconfigOptions, WORKFLOW_CHECK_CONTEXTS, WORKFLOW_TEMPLATES, WORKFLOW_TEMPLATE_PROPERTIES, type WorkspacePackage, codecovComponentBlock, codecovConfig, createAstromech, createCodecovConfig, createTsconfig, deployOnRelease, deriveDeployPaths, ensureIfNotFound, extractPreviewConfig, generateCombinedDeployContent, generateThinCallerContent, matchNamespace, mergeCodecovComponents, normalizeWorkflowWith, readWorkspacePackages, requiredChecks, reusableTemplates, runCi, runGroup, runTask };