@theholocron/astromech 5.0.0-alpha.117 → 5.0.0-alpha.119

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.
Files changed (3) hide show
  1. package/dist/index.d.mts +242 -375
  2. package/dist/index.mjs +1661 -1581
  3. package/package.json +3 -3
package/dist/index.d.mts CHANGED
@@ -1,115 +1,5 @@
1
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
2
+ //#region src/generators/github-action-thin-callers.d.ts
113
3
  /**
114
4
  * Workflow templates + thin-caller generation.
115
5
  *
@@ -221,7 +111,7 @@ declare function normalizeWorkflowWith(raw: Record<string, unknown>): Record<str
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;
@@ -231,6 +121,116 @@ interface EnsureTurboDependencyResult {
231
121
  changed: boolean;
232
122
  }
233
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
234
  //#region src/astromech.d.ts
235
235
  interface AstromechOptions {
236
236
  /** Repo root. */
@@ -353,7 +353,7 @@ interface Astromech {
353
353
  }
354
354
  declare function createAstromech(options: AstromechOptions): Astromech;
355
355
  //#endregion
356
- //#region src/codecov.d.ts
356
+ //#region src/generators/codecov.d.ts
357
357
  /**
358
358
  * `codecov.yml` generation — a manifest-derived artifact (component `paths`
359
359
  * come from workspace packages; the status targets track the `test` task's
@@ -398,133 +398,105 @@ declare function createCodecovConfig(packages: WorkspacePackage[]): string;
398
398
  */
399
399
  declare function codecovConfig(repoRoot: string, existing: string | null): string;
400
400
  //#endregion
401
- //#region src/deploy-on-release.d.ts
402
- interface SpawnResult {
403
- status: number | null;
404
- stdout: string;
405
- stderr: string;
406
- }
407
- type Run = (command: string, args: string[], options: Record<string, unknown>) => SpawnResult;
408
- interface Tree {
409
- readJson: (path: string) => unknown;
410
- listDirs: (path: string) => string[];
411
- }
412
- interface DeployOnReleaseOptions {
413
- cwd: string;
414
- /** The release's channel: its prerelease identifier (`alpha`); empty or `main` for a stable release. */
415
- channel: string;
416
- /** The previous release's commit; omitted when there is none, so every deploying channel match deploys. */
417
- from?: string;
418
- /** The release commit. Default `HEAD`. */
419
- to?: string;
420
- /** Where progress lines go (stdout in the CLI). */
421
- print: (line: string) => void;
422
- dryRun?: boolean;
423
- }
424
- interface DeployOnReleaseDeps extends Partial<Tree> {
425
- run?: Run;
426
- sleep?: (ms: number) => Promise<void>;
427
- now?: () => number;
428
- /** Reads a package folder's task manifest; `loadTasksConfig` by default. */
429
- loadTasks?: (dir: string) => Promise<TasksConfig>;
430
- }
431
- interface DeployOnReleaseResult {
432
- pkg: string;
433
- status: "ok" | "fail" | "skip" | "dry-run";
434
- message: string;
435
- }
436
- interface DeployOnReleaseReport {
437
- /** `fail` if any package's deploy failed; `skip` if none applied to this release; else `ok`. */
438
- status: "ok" | "fail" | "skip";
439
- results: DeployOnReleaseResult[];
440
- }
401
+ //#region src/generators/github-action-reusable-workflows.d.ts
441
402
  /**
442
- * Deploys every package whose manifest declares a release-time deploy that
443
- * applies to this release. Never throws for a deploy problem: each package's
444
- * outcome is in the report, and `status: "fail"` is the caller's exit code.
403
+ * The **reusable** GitHub Actions surface pushed to `theholocron/.github` by
404
+ * `holocron sync-github` — the `workflow_call` implementations and composite
405
+ * actions that every repo's thin callers delegate to.
406
+ *
407
+ * `theholocron/.github` is a **pure sync target**: `.github/workflows/*`,
408
+ * `.github/actions/*` and `workflow-templates/*` there are generated from the
409
+ * `.yml` files in `src/templates/reusable/` and pushed verbatim (with a
410
+ * "do not edit" header). Never hand-edit them in `.github`.
411
+ *
412
+ * Not to be confused with `WORKFLOW_TEMPLATES` in `github-action-thin-callers.ts` — those are
413
+ * the *thin-caller bases* written into each consumer repo's `.github/workflows/`.
445
414
  */
446
- declare function deployOnRelease(options: DeployOnReleaseOptions, { run, readJson, listDirs, sleep, now, loadTasks }?: DeployOnReleaseDeps): Promise<DeployOnReleaseReport>;
415
+ /** `workflow_call` implementations → `.github/workflows/<name>.yml`. */
416
+ declare const REUSABLE_WORKFLOWS: Record<string, string>;
417
+ /** Composite actions → `.github/actions/<name>/action.yml` (key includes `/action`). */
418
+ declare const REUSABLE_ACTIONS: Record<string, string>;
419
+ /** GitHub starter-workflow metadata → `workflow-templates/<name>.properties.json`. */
420
+ declare const WORKFLOW_TEMPLATE_PROPERTIES: Record<string, string>;
421
+ /**
422
+ * The complete file batch `holocron sync-github` pushes to `theholocron/.github`:
423
+ * path → content. YAML gets the "do not edit" header; the starter-workflow
424
+ * `.properties.json` files are left bare (native JSON, not a commented file).
425
+ */
426
+ declare function reusableTemplates(): Map<string, string>;
427
+ //#endregion
428
+ //#region src/generators/required-checks.d.ts
429
+ /** Ordered (task contexts in {@link CI_ORDER}, then extras), de-duplicated. */
430
+ declare function requiredChecks(config: TasksConfig): string[];
447
431
  //#endregion
448
- //#region src/linters.d.ts
432
+ //#region src/generators/tsconfig.d.ts
449
433
  /**
450
- * The linter registry — one list of linter names (from `config.tasks`'
451
- * `{ name: "lint", linters: [...] }`, or auto-detected) maps to both the
452
- * CI super-linter `VALIDATE_*` env and the native local run. This table is
453
- * the single source of truth for that mapping; {@link superLinterConfig}
454
- * (CI) and the `holocron run lint` aggregate (local) both read it.
434
+ * `tsconfig.json` generation — Bucket B (config-resolution workstream, #676):
435
+ * the file must stay committed (the TypeScript language server discovers it
436
+ * directly from disk, no `--config` override mechanism to hand it a path
437
+ * instead), but its content is fully derivable, so it's generated rather
438
+ * than hand-authored — the same category as `.editorconfig`
439
+ * ({@link "./templates/configs/editorconfig/create-config.js" createConfig})
440
+ * and {@link codecovConfig}.
455
441
  *
456
- * Spec: `docs/wiki/specifications/tech-astromech-task-runner.spec.md` "Lint parity".
442
+ * Surveyed every package-level `tsconfig.json` across the org (`holocron`,
443
+ * `clients`, `utils` — 20+ packages). `extends: "@theholocron/tsconfig/
444
+ * node-lts"`, `compilerOptions.baseUrl: "./"`, `compilerOptions.outDir:
445
+ * "./dist"`, `include: ["src/**\/*.ts"]`, and `exclude: ["node_modules",
446
+ * "dist"]` are uniform in every one — safe defaults here. `paths` (a `@/*`
447
+ * → `./src/*` import alias) is a real per-package choice, present in
448
+ * roughly 40% of packages checked — an opt-in parameter, not a default.
449
+ *
450
+ * Two fields checked and deliberately *not* absorbed as defaults, unlike
451
+ * `eslint-config`'s `tsconfigRootDir`/`settings.node` (which turned out
452
+ * redundant with the shared package's own behavior, `configs`#461):
453
+ * `compilerOptions.module`/`moduleResolution` (only `@theholocron/cli`
454
+ * overrides these, to `esnext`/`bundler` — a genuine deviation from the
455
+ * shared `node-lts` preset's `nodenext`/`nodenext`, needed for its bundler
456
+ * tooling, not something every package should inherit) and
457
+ * `compilerOptions.rootDir` (present in exactly two packages, always the
458
+ * same value `./src` that `include` already implies — an unnecessary
459
+ * override wherever it appears, not a pattern worth generalizing).
460
+ *
461
+ * Monorepo *root* `tsconfig.json` (a TS project-references "solution
462
+ * file" — `holocron`'s own root is `{ files: [], references: [...] }`,
463
+ * listing which packages to build) is a structurally different, genuinely
464
+ * per-repo document — out of scope here, same as Bucket C content.
465
+ *
466
+ * Not yet wired into `holocron setup`'s per-package write loop (every
467
+ * other Bucket B file there is a single repo-root file, safely
468
+ * overwritten every run — `tsconfig.json` is per-package, and most
469
+ * packages' files still carry real hand-authored content today, not yet
470
+ * migrated to a fully-generated state). That per-package iteration +
471
+ * safe-migration design is `#680`'s job, not duplicated here — this is
472
+ * the generator itself, ready for it to call.
457
473
  */
458
- interface LinterDef {
459
- /**
460
- * super-linter `VALIDATE_*` keys this linter turns on. Setting any
461
- * `VALIDATE_*` puts super-linter in allow-list mode, so emitting only the
462
- * enabled keys makes it run exactly this set.
463
- */
464
- validate: string[];
465
- /** super-linter `FIX_*` keys (auto-commit / `--write` parity). */
466
- fix?: string[];
467
- /**
468
- * Local binary, resolved from `node_modules/.bin` then `PATH`. Absent →
469
- * the linter has no meaningful local run (`holocron run lint` prints
470
- * "CI only"); CI still enforces it.
471
- */
472
- localBin?: string;
473
- /** Args for `localBin` in CHECK mode — never `--write` / `--fix`. */
474
- localArgs?: string[];
474
+ interface TsconfigOptions {
475
+ /** Human-readable name for the `display` field — the package's own name is the usual choice. */
476
+ display: string;
475
477
  /**
476
- * Shown by `holocron run lint` when `localBin` is set but not found on
477
- * PATH — the "you're missing a tool the repo needs" nudge.
478
+ * `@theholocron/tsconfig` variant. Defaults to `"node-lts"` — every
479
+ * checked package uses it; the other three (`astro`, `nextjs`, `react`)
480
+ * exist for a template repo's app-shaped packages, not the plain
481
+ * Node.js library packages this org's currently-migrated repos ship.
478
482
  */
479
- installHint?: string;
483
+ variant?: "astro" | "nextjs" | "node-lts" | "react";
480
484
  /**
481
- * Repo-root filenames that auto-enable this linter when the `lint` task
482
- * has no explicit `linters` list. Ignored when {@link always} is set.
485
+ * Add a `@/*` → `./src/*` path alias. A real per-package choice, not a
486
+ * default — roughly 40% of packages checked use one, the rest don't.
483
487
  */
484
- detect?: string[];
485
- /** Enabled regardless of detection (the org baseline). */
486
- always?: boolean;
487
- /** Reusable-workflow config-file input this linter honors, if any. */
488
- configInput?: "eslint-config" | "prettier-config" | "yaml-config";
488
+ paths?: boolean;
489
489
  }
490
490
  /**
491
- * Known linters, in execution order. `always` entries are the current
492
- * hard-coded super-linter baseline; `prettier` is always-on because the org
493
- * applies it universally (super-linter only lints files that exist).
494
- */
495
- declare const LINTERS: Record<string, LinterDef>;
496
- /** Every linter name the registry knows. */
497
- declare const LINTER_NAMES: ReadonlySet<string>;
498
- /**
499
- * Resolve the linter set for a repo. An `explicit` list (from `config.tasks`)
500
- * picks the candidate set; otherwise the candidates are every `always` linter
501
- * plus every `detect`-gated linter whose filenames are present at the repo
502
- * root, OR whose mapped `@theholocron/*-config` package resolves per
503
- * {@link sharedConfigAvailable} — a repo can't run eslint with genuinely no
504
- * config anywhere (super-linter FATALs if you ask it to,
505
- * theholocron/holocron#654), but a *shared* one it has installed counts
506
- * (holocron#795: proving `clients`' eslint.config.ts files reduce to zero
507
- * remaining content is only half the story — the file itself was still load-
508
- * bearing here as the sole "eslint is even configured" signal until this
509
- * fallback existed). `always` linters are unconditional. Result is ordered
510
- * by {@link LINTERS} declaration order.
511
- *
512
- * `sharedConfigAvailable` is caller-computed (`run.ts`'s `runLinterGroup`
513
- * already resolves each linter's `resolveToolConfig()` per member to build
514
- * its actual command — reusing that instead of duplicating the package-
515
- * resolution logic here keeps this function itself pure and file-I/O-free).
516
- *
517
- * @throws when an `explicit` name is not in the registry — a typo is a
518
- * config bug, not a linter to silently skip.
491
+ * A package-level `tsconfig.json` — the uniform shape confirmed across
492
+ * every package checked, parameterized only by the two fields that
493
+ * genuinely vary (`display`, `paths`). No scaffold/workflow header (matches
494
+ * `.alexrc.json`'s existing precedent for a strict-JSON Bucket B file —
495
+ * JSON has no comment syntax to carry one, and TypeScript's own tolerance
496
+ * for JSONC comments in `tsconfig.json` isn't worth relying on for a file
497
+ * this thin).
519
498
  */
520
- declare function resolveLinters(opts: {
521
- explicit?: string[];
522
- rootFiles: string[];
523
- sharedConfigAvailable?: ReadonlySet<string>;
524
- }): Array<{
525
- name: string;
526
- def: LinterDef;
527
- }>;
499
+ declare function createTsconfig(options: TsconfigOptions): string;
528
500
  //#endregion
529
501
  //#region src/registry.d.ts
530
502
  /**
@@ -634,156 +606,51 @@ declare const KNOWN_TASKS: Set<string>;
634
606
  */
635
607
  declare const CI_ORDER: string[];
636
608
  //#endregion
637
- //#region src/required-checks.d.ts
638
- /** Ordered (task contexts in {@link CI_ORDER}, then extras), de-duplicated. */
639
- declare function requiredChecks(config: TasksConfig): string[];
640
- //#endregion
641
- //#region src/resolver.d.ts
642
- /**
643
- * Resolves the absolute path to a Bucket A tool's shared `@theholocron/*-config`
644
- * entry point, installed in the consuming repo's own `node_modules` — and the
645
- * CLI flag(s) to hand it via (`--config`, `--extends`, …). `run.ts` splices the
646
- * result into the command it builds for a tool/detect runner or a linter-group
647
- * entry, right after the tool's own args.
648
- *
649
- * Every mapped package's resolved entry point already carries a ready-to-use
650
- * default export (a plain re-export for `prettier`/`commitlint`; an invoked,
651
- * zero-arg preset for `eslint`/`vitest`/`tsdown` — verified end-to-end against
652
- * each tool's real `--config`/`--extends` loader, not just the file's shape).
653
- * A repo doesn't need this package installed at all — every lookup degrades to
654
- * `[]` (no flag added, the tool falls back to its own auto-discovery of a
655
- * local file, unchanged from today) rather than throwing.
656
- *
657
- * **Local file wins.** A `<tool>.config.*` sitting in `cwd` (whether it's
658
- * pure boilerplate or has real per-package customization on top of the
659
- * shared bundle, e.g. `mergeConfig(base, { test: { coverage: { exclude }
660
- * } })`) always skips the splice, even when the shared package is also
661
- * installed — an explicit `--config <shared path>` flag beats a tool's own
662
- * auto-discovery every time, so splicing it unconditionally would silently
663
- * discard that customization the file is still sitting right there on disk.
664
- * The shared bundle is only ever the fallback for a package with *no* local
665
- * file at all — that's still the "delete the file to go fully shared" path
666
- * this was designed for (#676); it just isn't unconditional (#749).
667
- *
668
- * `semantic-release`, `devmoji`, `editorconfig-checker`, and `knip` are
669
- * deliberately absent — `semantic-release-config`'s `defineConfig()` needs
670
- * real per-repo data (branches, npm options) a static `--extends <path>` can't
671
- * carry; `devmoji` runs through a git hook template, not `holocron run
672
- * <task>`; `editorconfig-checker` has no shared-config package yet; `knip` is
673
- * repo-specific by nature, never a shared-config candidate. See
674
- * `.notes/tech-config-resolution.spec.md` (#676).
675
- */
676
- interface ResolverDeps {
677
- readFile: (path: string) => string;
678
- fileExists: (path: string) => boolean;
609
+ //#region src/tasks/deploy-on-release.d.ts
610
+ interface SpawnResult {
611
+ status: number | null;
612
+ stdout: string;
613
+ stderr: string;
679
614
  }
680
- /** Every tool name the resolver knows how to point at a shared config. */
681
- declare const RESOLVABLE_TOOLS: ReadonlySet<string>;
682
- /**
683
- * `<flag> <absolute path>` for `tool`, resolved against `cwd`'s
684
- * `node_modules` — or `[]` when the tool isn't mapped, `cwd` already has its
685
- * own local config file for it (#749 — local always wins, customized or
686
- * not), the shared package isn't installed, its `package.json` doesn't
687
- * declare the export subpath this needs, or the resolved file doesn't
688
- * actually exist on disk (a stale install, or a package version that
689
- * predates the export existing).
690
- */
691
- declare function resolveToolConfig(tool: string, cwd: string, deps: ResolverDeps): string[];
692
- //#endregion
693
- //#region src/reusable.d.ts
694
- /**
695
- * The **reusable** GitHub Actions surface pushed to `theholocron/.github` by
696
- * `holocron sync-github` — the `workflow_call` implementations and composite
697
- * actions that every repo's thin callers delegate to.
698
- *
699
- * `theholocron/.github` is a **pure sync target**: `.github/workflows/*`,
700
- * `.github/actions/*` and `workflow-templates/*` there are generated from the
701
- * `.yml` files in `src/templates/reusable/` and pushed verbatim (with a
702
- * "do not edit" header). Never hand-edit them in `.github`.
703
- *
704
- * Not to be confused with `WORKFLOW_TEMPLATES` in `thin-callers.ts` — those are
705
- * the *thin-caller bases* written into each consumer repo's `.github/workflows/`.
706
- */
707
- /** `workflow_call` implementations → `.github/workflows/<name>.yml`. */
708
- declare const REUSABLE_WORKFLOWS: Record<string, string>;
709
- /** Composite actions → `.github/actions/<name>/action.yml` (key includes `/action`). */
710
- declare const REUSABLE_ACTIONS: Record<string, string>;
711
- /** GitHub starter-workflow metadata → `workflow-templates/<name>.properties.json`. */
712
- declare const WORKFLOW_TEMPLATE_PROPERTIES: Record<string, string>;
713
- /**
714
- * The complete file batch `holocron sync-github` pushes to `theholocron/.github`:
715
- * path → content. YAML gets the "do not edit" header; the starter-workflow
716
- * `.properties.json` files are left bare (native JSON, not a commented file).
717
- */
718
- declare function reusableTemplates(): Map<string, string>;
719
- //#endregion
720
- //#region src/tsconfig.d.ts
721
- /**
722
- * `tsconfig.json` generation — Bucket B (config-resolution workstream, #676):
723
- * the file must stay committed (the TypeScript language server discovers it
724
- * directly from disk, no `--config` override mechanism to hand it a path
725
- * instead), but its content is fully derivable, so it's generated rather
726
- * than hand-authored — the same category as `.editorconfig`
727
- * ({@link "./templates/configs/editorconfig/create-config.js" createConfig})
728
- * and {@link codecovConfig}.
729
- *
730
- * Surveyed every package-level `tsconfig.json` across the org (`holocron`,
731
- * `clients`, `utils` — 20+ packages). `extends: "@theholocron/tsconfig/
732
- * node-lts"`, `compilerOptions.baseUrl: "./"`, `compilerOptions.outDir:
733
- * "./dist"`, `include: ["src/**\/*.ts"]`, and `exclude: ["node_modules",
734
- * "dist"]` are uniform in every one — safe defaults here. `paths` (a `@/*`
735
- * → `./src/*` import alias) is a real per-package choice, present in
736
- * roughly 40% of packages checked — an opt-in parameter, not a default.
737
- *
738
- * Two fields checked and deliberately *not* absorbed as defaults, unlike
739
- * `eslint-config`'s `tsconfigRootDir`/`settings.node` (which turned out
740
- * redundant with the shared package's own behavior, `configs`#461):
741
- * `compilerOptions.module`/`moduleResolution` (only `@theholocron/cli`
742
- * overrides these, to `esnext`/`bundler` — a genuine deviation from the
743
- * shared `node-lts` preset's `nodenext`/`nodenext`, needed for its bundler
744
- * tooling, not something every package should inherit) and
745
- * `compilerOptions.rootDir` (present in exactly two packages, always the
746
- * same value `./src` that `include` already implies — an unnecessary
747
- * override wherever it appears, not a pattern worth generalizing).
748
- *
749
- * Monorepo *root* `tsconfig.json` (a TS project-references "solution
750
- * file" — `holocron`'s own root is `{ files: [], references: [...] }`,
751
- * listing which packages to build) is a structurally different, genuinely
752
- * per-repo document — out of scope here, same as Bucket C content.
753
- *
754
- * Not yet wired into `holocron setup`'s per-package write loop (every
755
- * other Bucket B file there is a single repo-root file, safely
756
- * overwritten every run — `tsconfig.json` is per-package, and most
757
- * packages' files still carry real hand-authored content today, not yet
758
- * migrated to a fully-generated state). That per-package iteration +
759
- * safe-migration design is `#680`'s job, not duplicated here — this is
760
- * the generator itself, ready for it to call.
761
- */
762
- interface TsconfigOptions {
763
- /** Human-readable name for the `display` field — the package's own name is the usual choice. */
764
- display: string;
765
- /**
766
- * `@theholocron/tsconfig` variant. Defaults to `"node-lts"` — every
767
- * checked package uses it; the other three (`astro`, `nextjs`, `react`)
768
- * exist for a template repo's app-shaped packages, not the plain
769
- * Node.js library packages this org's currently-migrated repos ship.
770
- */
771
- variant?: "astro" | "nextjs" | "node-lts" | "react";
772
- /**
773
- * Add a `@/*` → `./src/*` path alias. A real per-package choice, not a
774
- * default — roughly 40% of packages checked use one, the rest don't.
775
- */
776
- paths?: boolean;
615
+ type Run = (command: string, args: string[], options: Record<string, unknown>) => SpawnResult;
616
+ interface Tree {
617
+ readJson: (path: string) => unknown;
618
+ listDirs: (path: string) => string[];
619
+ }
620
+ interface DeployOnReleaseOptions {
621
+ cwd: string;
622
+ /** The release's channel: its prerelease identifier (`alpha`); empty or `main` for a stable release. */
623
+ channel: string;
624
+ /** The previous release's commit; omitted when there is none, so every deploying channel match deploys. */
625
+ from?: string;
626
+ /** The release commit. Default `HEAD`. */
627
+ to?: string;
628
+ /** Where progress lines go (stdout in the CLI). */
629
+ print: (line: string) => void;
630
+ dryRun?: boolean;
631
+ }
632
+ interface DeployOnReleaseDeps extends Partial<Tree> {
633
+ run?: Run;
634
+ sleep?: (ms: number) => Promise<void>;
635
+ now?: () => number;
636
+ /** Reads a package folder's task manifest; `loadTasksConfig` by default. */
637
+ loadTasks?: (dir: string) => Promise<TasksConfig>;
638
+ }
639
+ interface DeployOnReleaseResult {
640
+ pkg: string;
641
+ status: "ok" | "fail" | "skip" | "dry-run";
642
+ message: string;
643
+ }
644
+ interface DeployOnReleaseReport {
645
+ /** `fail` if any package's deploy failed; `skip` if none applied to this release; else `ok`. */
646
+ status: "ok" | "fail" | "skip";
647
+ results: DeployOnReleaseResult[];
777
648
  }
778
649
  /**
779
- * A package-level `tsconfig.json` — the uniform shape confirmed across
780
- * every package checked, parameterized only by the two fields that
781
- * genuinely vary (`display`, `paths`). No scaffold/workflow header (matches
782
- * `.alexrc.json`'s existing precedent for a strict-JSON Bucket B file —
783
- * JSON has no comment syntax to carry one, and TypeScript's own tolerance
784
- * for JSONC comments in `tsconfig.json` isn't worth relying on for a file
785
- * this thin).
650
+ * Deploys every package whose manifest declares a release-time deploy that
651
+ * applies to this release. Never throws for a deploy problem: each package's
652
+ * outcome is in the report, and `status: "fail"` is the caller's exit code.
786
653
  */
787
- declare function createTsconfig(options: TsconfigOptions): string;
654
+ declare function deployOnRelease(options: DeployOnReleaseOptions, { run, readJson, listDirs, sleep, now, loadTasks }?: DeployOnReleaseDeps): Promise<DeployOnReleaseReport>;
788
655
  //#endregion
789
- export { type Astromech, type AstromechOptions, CI_ORDER, type CiJobReport, type CiOptions, type CiReport, type DeployOnReleaseOptions, type DeployOnReleaseReport, type DeployOnReleaseResult, 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, deployOnRelease, deriveDeployPaths, ensureIfNotFound, extractPreviewConfig, generateCombinedDeployContent, generateThinCallerContent, mergeCodecovComponents, normalizeWorkflowWith, readWorkspacePackages, requiredChecks, resolveLinters, resolveToolConfig, reusableTemplates, runCi, runTask };
656
+ export { type Astromech, type AstromechOptions, CI_ORDER, type CiJobReport, type CiOptions, type CiReport, type DeployOnReleaseOptions, type DeployOnReleaseReport, type DeployOnReleaseResult, type ExecFn, 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, mergeCodecovComponents, normalizeWorkflowWith, readWorkspacePackages, requiredChecks, reusableTemplates, runCi, runTask };