@theholocron/astromech 5.0.0-alpha.12 → 5.0.0-alpha.121

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,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,11 +111,125 @@ 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;
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;
229
233
  //#endregion
230
234
  //#region src/astromech.d.ts
231
235
  interface AstromechOptions {
@@ -328,14 +332,28 @@ interface Astromech {
328
332
  * (not just an orchestrator) silently vanishes from `turbo run <task>`.
329
333
  * Pass `pnpm-workspace.yaml`'s current content (or `""` if none exists —
330
334
  * 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.
335
+ * already) and root `package.json`'s own `scripts` object — values and
336
+ * all, not just keys, so a task-name-matching script that's already the
337
+ * generated `holocron run <task> --` wrapper (predating this call, not
338
+ * written by it) is correctly excluded rather than treated as proof root
339
+ * is directly buildable (#846). `changed: false` means don't write
340
+ * anything — the file is already correct.
333
341
  */
334
- ensureRootWorkspaceMember(workspaceYaml: string, rootScripts: readonly string[]): EnsureRootWorkspaceMemberResult;
342
+ ensureRootWorkspaceMember(workspaceYaml: string, rootScripts: Readonly<Record<string, string>>): EnsureRootWorkspaceMemberResult;
343
+ /**
344
+ * `turboConfig()` writes a `turbo.json` but never touches `package.json`
345
+ * — a repo with no local `turbo` devDependency falls back to whatever
346
+ * (if anything) is globally on `PATH`, per `run.ts`'s `resolveBin()`.
347
+ * Pass root `package.json`'s raw content and `pnpm-workspace.yaml`'s
348
+ * current content (checked for an existing `turbo` catalog entry, which
349
+ * takes precedence over the hardcoded fallback version). `changed: false`
350
+ * means don't write anything — `devDependencies.turbo` already exists.
351
+ */
352
+ ensureTurboDependency(packageJson: string, workspaceYaml: string): EnsureTurboDependencyResult;
335
353
  }
336
354
  declare function createAstromech(options: AstromechOptions): Astromech;
337
355
  //#endregion
338
- //#region src/codecov.d.ts
356
+ //#region src/generators/codecov.d.ts
339
357
  /**
340
358
  * `codecov.yml` generation — a manifest-derived artifact (component `paths`
341
359
  * come from workspace packages; the status targets track the `test` task's
@@ -380,76 +398,105 @@ declare function createCodecovConfig(packages: WorkspacePackage[]): string;
380
398
  */
381
399
  declare function codecovConfig(repoRoot: string, existing: string | null): string;
382
400
  //#endregion
383
- //#region src/linters.d.ts
401
+ //#region src/generators/github-action-reusable-workflows.d.ts
384
402
  /**
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.
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.
390
406
  *
391
- * Spec: `docs/wiki/specifications/tech-astromech-task-runner.spec.md` "Lint parity".
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/`.
392
414
  */
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[];
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[];
431
+ //#endregion
432
+ //#region src/generators/tsconfig.d.ts
433
+ /**
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}.
441
+ *
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.
473
+ */
474
+ interface TsconfigOptions {
475
+ /** Human-readable name for the `display` field — the package's own name is the usual choice. */
476
+ display: string;
410
477
  /**
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.
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.
413
482
  */
414
- installHint?: string;
483
+ variant?: "astro" | "nextjs" | "node-lts" | "react";
415
484
  /**
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.
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.
418
487
  */
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";
488
+ paths?: boolean;
424
489
  }
425
490
  /**
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.
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).
445
498
  */
446
- declare function resolveLinters(opts: {
447
- explicit?: string[];
448
- rootFiles: string[];
449
- }): Array<{
450
- name: string;
451
- def: LinterDef;
452
- }>;
499
+ declare function createTsconfig(options: TsconfigOptions): string;
453
500
  //#endregion
454
501
  //#region src/registry.d.ts
455
502
  /**
@@ -559,144 +606,51 @@ declare const KNOWN_TASKS: Set<string>;
559
606
  */
560
607
  declare const CI_ORDER: string[];
561
608
  //#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;
609
+ //#region src/tasks/deploy-on-release.d.ts
610
+ interface SpawnResult {
611
+ status: number | null;
612
+ stdout: string;
613
+ stderr: string;
594
614
  }
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;
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[];
690
648
  }
691
649
  /**
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).
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.
699
653
  */
700
- declare function createTsconfig(options: TsconfigOptions): string;
654
+ declare function deployOnRelease(options: DeployOnReleaseOptions, { run, readJson, listDirs, sleep, now, loadTasks }?: DeployOnReleaseDeps): Promise<DeployOnReleaseReport>;
701
655
  //#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 };
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 };