@theholocron/astromech 4.19.0 → 5.0.0-alpha.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +93 -83
- package/dist/config/index.d.mts +1 -1
- package/dist/index.d.mts +209 -101
- package/dist/index.mjs +527 -241
- package/dist/{schema-BegK4MsY.d.mts → schema-D01VYg43.d.mts} +11 -7
- package/package.json +7 -8
package/README.md
CHANGED
|
@@ -3,8 +3,7 @@
|
|
|
3
3
|
The Holocron task runner. One **task manifest** per repo, and every
|
|
4
4
|
derived surface comes from it: `holocron run` (local), `holocron ci` (the
|
|
5
5
|
CI suite run locally), the generated GitHub Actions workflows, the
|
|
6
|
-
`package.json` scripts,
|
|
7
|
-
required-checks list.
|
|
6
|
+
`package.json` scripts, and the branch-protection required-checks list.
|
|
8
7
|
|
|
9
8
|
> An astromech droid runs a starfighter's maintenance, diagnostics and
|
|
10
9
|
> system wiring while the pilot flies. This does that for a repo.
|
|
@@ -25,27 +24,75 @@ import { createAstromech } from "@theholocron/astromech";
|
|
|
25
24
|
|
|
26
25
|
const astromech = createAstromech({ cwd });
|
|
27
26
|
|
|
28
|
-
const report = astromech.run("
|
|
27
|
+
const report = astromech.run("verification.unitTests", { passthrough: ["--watch"] });
|
|
29
28
|
// → { status: "ok" | "fail" | "skip" | "dry-run" | "unknown", command?, message? }
|
|
30
29
|
```
|
|
31
30
|
|
|
32
31
|
### `holocron run <task>` resolution
|
|
33
32
|
|
|
34
|
-
`holocron run
|
|
35
|
-
npm, or which runner:
|
|
33
|
+
`holocron run verification.unitTests` runs your tests — you don't tell it
|
|
34
|
+
turbo vs pnpm vs npm, or which runner:
|
|
36
35
|
|
|
37
36
|
```
|
|
38
37
|
1. turbo.json defines the task → turbo run <task>
|
|
39
38
|
2. package.json has a <task> script → <detected pm> run <task>
|
|
40
39
|
(a "holocron run …" thin caller is skipped — no recursion)
|
|
41
40
|
3. the registry has a local runner → <tool> <args> <org-flags> (e.g. --coverage)
|
|
42
|
-
|
|
43
|
-
|
|
41
|
+
3b. the task is a linterGroup → each resolved linter, run natively
|
|
42
|
+
4. the task is a container of jobs → each job, in declared order
|
|
43
|
+
5. known task, nothing to run → "no <task> task", exit 0 (exit 1 with --required)
|
|
44
|
+
6. unknown task → error, exit 1
|
|
44
45
|
```
|
|
45
46
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
47
|
+
## Intent → technology
|
|
48
|
+
|
|
49
|
+
Tasks are named by **intent**, not by tool — a repo declares
|
|
50
|
+
`verification.unitTests`, not `vitest`. The table below is the full
|
|
51
|
+
registry (`TASKS` in `src/registry.ts`): every task name astromech knows,
|
|
52
|
+
what it actually runs, and why. Tool names never appear in
|
|
53
|
+
`holocron.config.ts` — they're an implementation detail this table
|
|
54
|
+
documents, not a naming convention repos need to follow.
|
|
55
|
+
|
|
56
|
+
| Task | Runs | Notes |
|
|
57
|
+
| ---------------------------------------- | -------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------- |
|
|
58
|
+
| `verification.unitTests` | vitest | carries the `--coverage` org default |
|
|
59
|
+
| `verification.typeSafety` | tsc | `tsc --noEmit` |
|
|
60
|
+
| `verification.performance` | Lighthouse CI | only runs with a `lighthouse.config.*` present |
|
|
61
|
+
| `sourceQuality.staticAnalysis` | eslint, actionlint, git-merge-conflict-markers | a `linterGroup` — see below |
|
|
62
|
+
| `sourceQuality.formatting` | prettier, editorconfig-checker, markdownlint-cli2 | a `linterGroup` |
|
|
63
|
+
| `sourceQuality.structuredDataValidation` | yamllint | |
|
|
64
|
+
| `sourceQuality.deadCodeAnalysis` | knip | |
|
|
65
|
+
| `security.secretDetection` | gitleaks | |
|
|
66
|
+
| `security.codeScanning` | CodeQL | no local equivalent — CI only |
|
|
67
|
+
| `security.dependencyReview` | GitHub's native Dependabot alerts/graph | a capability-model method (`Source.enableVulnerabilityAlerts()`), not a task |
|
|
68
|
+
| `delivery.build` | tsdown / vite / rollup / tsc, detected from the repo's own config file | |
|
|
69
|
+
| `delivery.publish` | semantic-release | no local equivalent — CI only; carries `preview` (npm dist-tags) |
|
|
70
|
+
| `delivery.deploy` | Cloudflare Pages / Vercel | no local equivalent — CI only; carries `preview` |
|
|
71
|
+
| `delivery.bundleSize` | bundle-size upload to Codecov | no local equivalent — CI only |
|
|
72
|
+
| `platform.repoSync` | `holocron sync` | keeps generated files current |
|
|
73
|
+
| `platform.commitStandards` | commitlint | no local equivalent — enforced by the `commit-msg` hook locally, over the PR's commit range in CI |
|
|
74
|
+
| `platform.repoValidation` | `scripts/validate-adrs.mjs`, `scripts/validate-registry.mjs`, `scripts/validate-docs-presence.mjs` | a job-bearing task — spec/ADR frontmatter, registry-doc completeness, and docs-presence, not linters |
|
|
75
|
+
| `knowledge.wiki` | Fern | publishes `docs/wiki/*.md` — not a sync, a publish; carries `preview` |
|
|
76
|
+
| `knowledge.docs` | Astro build | the docs site itself; carries `preview` (defaults on) |
|
|
77
|
+
| `knowledge.components` | Storybook build | a browsable component catalog — "Storybook" is the tool, not the intent; carries `preview` (defaults on) |
|
|
78
|
+
|
|
79
|
+
**`preview` is a cross-cutting feature, not a namespace.** npm has staging
|
|
80
|
+
dist-tags, Cloudflare/Vercel do per-PR preview deploys, Fern previews
|
|
81
|
+
docs — none of these earn their own task or verb; it's one capability any
|
|
82
|
+
publish/deploy-shaped task can carry, toggled via that task's `with:`.
|
|
83
|
+
|
|
84
|
+
**`linterGroup` tasks** (`sourceQuality.staticAnalysis`,
|
|
85
|
+
`sourceQuality.formatting`) bundle more than one tool under a single
|
|
86
|
+
required check. Each tool is still gated by its own detection rule (e.g.
|
|
87
|
+
`eslint` only runs if `eslint.config.*` is present) — the
|
|
88
|
+
`tool name → detection rule → local binary` mapping lives in one place,
|
|
89
|
+
`src/linters.ts`. A repo's choice of which of these run is just which
|
|
90
|
+
tasks it includes in `tasks: [...]`, same as any other task.
|
|
91
|
+
|
|
92
|
+
**No super-linter.** Each task above runs its own tool directly, through
|
|
93
|
+
the same `holocron` composite action that resolves it locally — CI runs
|
|
94
|
+
the identical command a developer runs, not a third-party action bundling
|
|
95
|
+
a tool version this org doesn't control.
|
|
49
96
|
|
|
50
97
|
## Config — `@theholocron/astromech/config`
|
|
51
98
|
|
|
@@ -59,9 +106,9 @@ import { defineConfig } from "@theholocron/astromech/config";
|
|
|
59
106
|
|
|
60
107
|
export default defineConfig({
|
|
61
108
|
tasks: [
|
|
62
|
-
"
|
|
63
|
-
{ name: "
|
|
64
|
-
{ name: "
|
|
109
|
+
"verification.typeSafety",
|
|
110
|
+
{ name: "verification.unitTests", required: true, with: { "run-coverage": true } },
|
|
111
|
+
{ name: "security.codeScanning", ci: true, local: false }, // CI-only
|
|
65
112
|
],
|
|
66
113
|
});
|
|
67
114
|
```
|
|
@@ -77,7 +124,6 @@ export default defineConfig({
|
|
|
77
124
|
| `local: false` | `holocron run <name>` → "CI-only task", exit 0 |
|
|
78
125
|
| `required` | the task's check context is a required status check |
|
|
79
126
|
| `with` | per-repo overrides on the reusable-workflow channel |
|
|
80
|
-
| `linters` (`lint` only) | explicit linter list; omitted → auto-detect |
|
|
81
127
|
|
|
82
128
|
Top-level keys: `syncScripts: false` disables the `package.json` script
|
|
83
129
|
writes entirely; `holocronScript` sets the command the synced `"holocron"`
|
|
@@ -89,39 +135,43 @@ script runs (default `"holocron"`).
|
|
|
89
135
|
const astromech = createAstromech({ cwd, config, orgContext: { org, domain } });
|
|
90
136
|
|
|
91
137
|
astromech.thinCallers(); // Map<"<name>.yml", yaml> — one per templated, ci-enabled task
|
|
92
|
-
astromech.packageScripts(); // { holocron: "holocron",
|
|
93
|
-
astromech.requiredChecks(); // ["
|
|
138
|
+
astromech.packageScripts(); // { holocron: "holocron", "verification.unitTests": "holocron run verification.unitTests", … }
|
|
139
|
+
astromech.requiredChecks(); // ["Typecheck / tsc --noEmit", "codecov/patch", …] — branch-protection contexts
|
|
94
140
|
astromech.codecovConfig(existing); // codecov.yml content — merges into `existing`, or scaffolds fresh when null
|
|
95
141
|
astromech.ci({ scope: "required" }); // CiReport — run the gating checks locally, in CI order
|
|
96
142
|
```
|
|
97
143
|
|
|
98
|
-
`ci()` runs every `required: true` task (else every `ci: true` task) through
|
|
99
|
-
same resolution as `run()`, in `CI_ORDER`, and returns `{ status, jobs }`.
|
|
100
|
-
`required` task whose local runner can't run is a failure
|
|
101
|
-
|
|
144
|
+
`ci()` runs every `required: true` task (else every `ci: true` task) through
|
|
145
|
+
the same resolution as `run()`, in `CI_ORDER`, and returns `{ status, jobs }`.
|
|
146
|
+
A `required` task whose local runner can't run is a failure — **except** a
|
|
147
|
+
task that's genuinely CI-only (`local: null`, or a `linterGroup` whose every
|
|
148
|
+
member lacks a local binary entirely, like `platform.commitStandards`),
|
|
149
|
+
which is reported skipped even when required. `holocron ci` sets the
|
|
102
150
|
process exit code from `status`.
|
|
103
151
|
|
|
104
152
|
`thinCallers()` returns the raw `.github/workflows/*.yml` content (no
|
|
105
|
-
generated-by header — the caller prefixes its own). `deploy`
|
|
106
|
-
`
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
153
|
+
generated-by header — the caller prefixes its own). `delivery.deploy` /
|
|
154
|
+
`knowledge.docs` / `knowledge.components` with `preview:` produce the
|
|
155
|
+
combined push-to-Pages / PR-to-preview workflow —
|
|
156
|
+
`knowledge.docs`/`knowledge.components` default `preview` on, since
|
|
157
|
+
neither has a plain-production-only fallback template.
|
|
158
|
+
`packageScripts()` emits the `holocron` entry (`holocronScript ?? "holocron"`)
|
|
159
|
+
plus one `"<task>": "holocron run <task>"` per runnable task; it skips
|
|
160
|
+
`local: false` entries and tasks with no local runner at all, and returns
|
|
161
|
+
`{}` when `syncScripts: false` or there is no config.
|
|
112
162
|
|
|
113
163
|
### Required checks
|
|
114
164
|
|
|
115
165
|
`requiredChecks()` derives the branch-protection required-status-check list
|
|
116
|
-
from the manifest: every `{ required: true }` task's check context
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
166
|
+
from the manifest: every `{ required: true }` task's check context, ordered
|
|
167
|
+
by `CI_ORDER`, then `config.extraRequiredChecks` (codecov gates, …),
|
|
168
|
+
de-duplicated. Most tasks are single always-run jobs now, so their context
|
|
169
|
+
names that job directly (`"Typecheck / tsc --noEmit"`) — the `… /
|
|
170
|
+
Conclusion` fan-in aggregate is only used where a task genuinely has
|
|
171
|
+
several conditionally-run jobs feeding one check
|
|
172
|
+
(`verification.unitTests`, `platform.repoValidation`). `holocron setup`
|
|
173
|
+
prepends `"DCO"` and applies the list for `protection: "strict"` repos.
|
|
174
|
+
Policy-free — manifest only.
|
|
125
175
|
|
|
126
176
|
### `codecov.yml`
|
|
127
177
|
|
|
@@ -135,56 +185,16 @@ current file's content (or `null`) and it either merges the
|
|
|
135
185
|
thresholds, flags, custom rules) or scaffolds a fresh file from the base
|
|
136
186
|
template. `holocron setup` writes the result via the `source` capability;
|
|
137
187
|
this method never touches the filesystem beyond reading `packages/*` and
|
|
138
|
-
`apps/*` under `cwd`.
|
|
139
|
-
coverage setup tracks the `test` task, the same way required checks track
|
|
140
|
-
`tasks`.
|
|
141
|
-
|
|
142
|
-
## Lint parity
|
|
143
|
-
|
|
144
|
-
One linter list drives both CI and local — no asymmetry. Source: the
|
|
145
|
-
`lint` task's `linters` array, or auto-detection from the config files
|
|
146
|
-
present. The `linter name → super-linter VALIDATE_* keys` mapping lives in
|
|
147
|
-
one place, `src/linters.ts`.
|
|
148
|
-
|
|
149
|
-
| linter | `VALIDATE_*` | always-on | local binary |
|
|
150
|
-
| ---------------------------- | ----------------------------------------- | ----------------------------------- | ---------------------------------------- |
|
|
151
|
-
| `eslint` | `JAVASCRIPT_ES`, `TYPESCRIPT_ES` | on `eslint.config.*` / `.eslintrc*` | `eslint .` |
|
|
152
|
-
| `prettier` | `*_PRETTIER` (JS/JSX/TS/TSX/MD) + `FIX_*` | yes | `prettier --check .` |
|
|
153
|
-
| `yamllint` | `YAML` | yes | `yamllint .` (usually CI-only) |
|
|
154
|
-
| `actionlint` | `GITHUB_ACTIONS` | yes | `actionlint` (usually CI-only) |
|
|
155
|
-
| `gitleaks` | `GITLEAKS` | yes | `gitleaks dir` (usually CI-only) |
|
|
156
|
-
| `editorconfig` | `EDITORCONFIG` | yes | `editorconfig-checker` (usually CI-only) |
|
|
157
|
-
| `commitlint` | `GIT_COMMITLINT` | yes | — (commit-msg hook + CI) |
|
|
158
|
-
| `git-merge-conflict-markers` | `GIT_MERGE_CONFLICT_MARKERS` | yes | — (CI only) |
|
|
159
|
-
| `markdownlint` | `MARKDOWN` | on `.markdownlint*` | `markdownlint-cli2` |
|
|
160
|
-
|
|
161
|
-
```ts
|
|
162
|
-
import { superLinterConfig, resolveLinters } from "@theholocron/astromech";
|
|
163
|
-
|
|
164
|
-
superLinterConfig({ explicit: ["eslint", "prettier"], rootFiles: fs.readdirSync(cwd) });
|
|
165
|
-
// → { env: { VALIDATE_JAVASCRIPT_ES: "true", … }, linters: ["eslint","prettier"], configInputs: { … } }
|
|
166
|
-
```
|
|
167
|
-
|
|
168
|
-
`superLinterConfig().env` is the exact `VALIDATE_*`/`FIX_*` map the CI
|
|
169
|
-
`lint` job needs — the CLI serializes it as the `super-linter-env` input on
|
|
170
|
-
each repo's generated `lint` thin caller. Setting any `VALIDATE_*` puts
|
|
171
|
-
super-linter in allow-list mode, so emitting only the enabled keys makes it
|
|
172
|
-
run exactly the resolved set.
|
|
173
|
-
|
|
174
|
-
`holocron run lint` (later phase) runs the same set natively: `turbo run
|
|
175
|
-
lint` for the eslint portion (cached), then each other linter whose binary
|
|
176
|
-
resolves; linters with a binary that is not on `PATH` are flagged with an
|
|
177
|
-
install hint; the rest print "CI only".
|
|
188
|
+
`apps/*` under `cwd`.
|
|
178
189
|
|
|
179
190
|
## Development
|
|
180
191
|
|
|
181
|
-
| Script
|
|
182
|
-
|
|
|
183
|
-
| `pnpm build`
|
|
184
|
-
| `pnpm
|
|
185
|
-
| `pnpm
|
|
186
|
-
| `pnpm
|
|
187
|
-
| `pnpm lint` | ESLint |
|
|
192
|
+
| Script | Description |
|
|
193
|
+
| --------------------------------------- | ------------------------------------------- |
|
|
194
|
+
| `pnpm run delivery.build` | Bundle with tsdown |
|
|
195
|
+
| `pnpm run verification.unitTests` | Run the vitest suite (always with coverage) |
|
|
196
|
+
| `pnpm run verification.typeSafety` | `tsc --noEmit` |
|
|
197
|
+
| `pnpm run sourceQuality.staticAnalysis` | ESLint |
|
|
188
198
|
|
|
189
199
|
## Releases
|
|
190
200
|
|
package/dist/config/index.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { i as normalizeTaskEntry, n as TaskEntry, r as TasksConfig, t as TaskConfigItem } from "../schema-
|
|
1
|
+
import { i as normalizeTaskEntry, n as TaskEntry, r as TasksConfig, t as TaskConfigItem } from "../schema-D01VYg43.mjs";
|
|
2
2
|
//#region src/config/define.d.ts
|
|
3
3
|
/**
|
|
4
4
|
* Typed identity helper for `astromech.config.ts`:
|