@theholocron/astromech 5.0.0-alpha.40 → 5.0.0-alpha.42

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/README.md +22 -22
  2. package/dist/index.mjs +41 -7
  3. package/package.json +3 -3
package/README.md CHANGED
@@ -53,28 +53,28 @@ what it actually runs, and why. Tool names never appear in
53
53
  `holocron.config.ts` — they're an implementation detail this table
54
54
  documents, not a naming convention repos need to follow.
55
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) |
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, or `package.json`'s own `dependencies`/`devDependencies` if that config file isn't there | |
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
78
 
79
79
  **`preview` is a cross-cutting feature, not a namespace.** npm has staging
80
80
  dist-tags, Cloudflare/Vercel do per-PR preview deploys, Fern previews
package/dist/index.mjs CHANGED
@@ -580,7 +580,7 @@ function runTask(input) {
580
580
  def.local.command,
581
581
  ...passthrough
582
582
  ]);
583
- const runner = resolveRunner(def.local, cwd, listDir);
583
+ const runner = resolveRunner(def.local, cwd, listDir, readFile);
584
584
  if (runner) {
585
585
  const flags = (def.flags?.[runner.tool] ?? []).filter((f) => !passthrough.includes(f));
586
586
  const configFlags = resolveToolConfig(runner.tool, cwd, {
@@ -643,7 +643,7 @@ function runTask(input) {
643
643
  * here, flag the rest, let CI enforce.
644
644
  */
645
645
  function runUnit(input, label, local, run, passthrough) {
646
- const { print, logger, listDir, lookPath, cwd } = input;
646
+ const { print, logger, listDir, lookPath, cwd, readFile } = input;
647
647
  const skip = (msg) => {
648
648
  print(input.required ? `✗ ${msg} (required)` : `· ${msg}`);
649
649
  logger[input.required ? "warn" : "debug"]({
@@ -656,7 +656,7 @@ function runUnit(input, label, local, run, passthrough) {
656
656
  };
657
657
  };
658
658
  if (local) {
659
- const runner = resolveRunner(local, cwd, listDir);
659
+ const runner = resolveRunner(local, cwd, listDir, readFile);
660
660
  if (!runner) return skip(`no ${label} runner for this repo`);
661
661
  const found = lookPath(cwd, runner.tool);
662
662
  if (!found) return skip(`${runner.tool} not installed locally for ${label} — enforced in CI`);
@@ -792,19 +792,53 @@ const mkRunner = (tool, args = []) => ({
792
792
  });
793
793
  /**
794
794
  * Resolve `{ tool, args }` for a runner, applying `detect[]` against repo
795
- * files. Only called for `tool` / `detect` runners — the caller handles
795
+ * files, falling back (#750) to each candidate's `tool` name against
796
+ * `package.json`'s own declared dependencies when neither matches by
797
+ * filename. Only called for `tool` / `detect` runners — the caller handles
796
798
  * `command` runners itself, so `local.detect` is present whenever
797
799
  * `local.tool` is not.
800
+ *
801
+ * The dependency fallback matters once a Bucket A migration (#680) deletes
802
+ * a build tool's own config file (`tsdown.config.ts`, `vite.config.ts`, …):
803
+ * that file was the *only* signal `detect[]` had to offer, so removing it
804
+ * used to make `delivery.build` report "no task for this repo" and silently
805
+ * skip the build, even though the tool is still very much in use — a
806
+ * package can't actually build with `tsdown` without it in
807
+ * `dependencies`/`devDependencies`, so that's a signal at least as reliable
808
+ * as the config file, and one deleting the file doesn't remove.
809
+ *
810
+ * **Per-candidate, not two full passes** (#750 follow-up — the first
811
+ * shipped version got this wrong): `delivery.build`'s own `detect[]` ends
812
+ * with `{ when: /^tsconfig\.json$/, tool: "tsc" }` as its last-resort
813
+ * fallback, and `tsconfig.json` exists in essentially every package
814
+ * regardless of build tool. A "check every candidate's filename, *then*
815
+ * check every candidate's dependency" two-pass design would let that
816
+ * always-present fallback file win over a real `tsdown`/`vite`/`rollup`
817
+ * dependency match, the moment the earlier candidates' own config files are
818
+ * gone — exactly backwards. Checking `(file match) || (dependency match)`
819
+ * together for each candidate before moving to the next preserves the
820
+ * intended precedence: a real signal for an *earlier* candidate, by either
821
+ * means, still wins over a later candidate's mere filename presence.
798
822
  */
799
- function resolveRunner(local, cwd, listDir) {
823
+ function resolveRunner(local, cwd, listDir, readFile) {
800
824
  if (local.tool) return mkRunner(local.tool, local.args);
801
825
  let files;
802
826
  try {
803
827
  files = listDir(cwd);
804
828
  } catch {
805
- return;
829
+ files = [];
830
+ }
831
+ const deps = packageJsonDependencies(cwd, readFile);
832
+ for (const candidate of local.detect) if (files.some((f) => candidate.when.test(f)) || deps.has(candidate.tool)) return mkRunner(candidate.tool, candidate.args);
833
+ }
834
+ /** Every key from `package.json`'s `dependencies` + `devDependencies`, or an empty set on any read/parse failure. */
835
+ function packageJsonDependencies(cwd, readFile) {
836
+ try {
837
+ const pkg = JSON.parse(readFile(join(cwd, "package.json")));
838
+ return /* @__PURE__ */ new Set([...Object.keys(pkg.dependencies ?? {}), ...Object.keys(pkg.devDependencies ?? {})]);
839
+ } catch {
840
+ return /* @__PURE__ */ new Set();
806
841
  }
807
- for (const candidate of local.detect) if (files.some((f) => candidate.when.test(f))) return mkRunner(candidate.tool, candidate.args);
808
842
  }
809
843
  function resolveBin(cwd, tool, fileExists) {
810
844
  const local = join(cwd, "node_modules", ".bin", tool);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@theholocron/astromech",
3
- "version": "5.0.0-alpha.40",
3
+ "version": "5.0.0-alpha.42",
4
4
  "description": "The Holocron task runner — one task manifest drives `holocron run`, `holocron ci`, the CI workflows, package.json scripts, linters, and required checks.",
5
5
  "keywords": [
6
6
  "ci",
@@ -37,7 +37,7 @@
37
37
  "dist"
38
38
  ],
39
39
  "dependencies": {
40
- "@theholocron/datapad": "5.0.0-alpha.40"
40
+ "@theholocron/datapad": "5.0.0-alpha.42"
41
41
  },
42
42
  "devDependencies": {
43
43
  "@theholocron/eslint-config": "^8.0.0",
@@ -53,7 +53,7 @@
53
53
  "tsdown": "^0.22.14",
54
54
  "typescript": "^5.9.3",
55
55
  "vitest": "^4.1.11",
56
- "@theholocron/rollup-plugin-transform-template": "5.0.0-alpha.40"
56
+ "@theholocron/rollup-plugin-transform-template": "5.0.0-alpha.42"
57
57
  },
58
58
  "engines": {
59
59
  "node": ">=22"