@geonosis/doctor 2.0.0 → 2.1.0
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 +9 -7
- package/dist/{chunk-SMCRXSH5.js → chunk-R2R2OYH3.js} +495 -404
- package/dist/doctor-cli.js +115 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +1 -1
- package/package.json +5 -2
|
@@ -319,6 +319,22 @@ var checkDeployed = ({ root }) => {
|
|
|
319
319
|
];
|
|
320
320
|
};
|
|
321
321
|
|
|
322
|
+
// src/repo-corpus.ts
|
|
323
|
+
import { existsSync as existsSync2, readFileSync as readFileSync3 } from "fs";
|
|
324
|
+
import { join as join3 } from "path";
|
|
325
|
+
var GEONOSIS_FILE = "geonosis.json";
|
|
326
|
+
var repoCorpusOf = (root) => {
|
|
327
|
+
const path = join3(root, GEONOSIS_FILE);
|
|
328
|
+
if (!existsSync2(path)) return void 0;
|
|
329
|
+
try {
|
|
330
|
+
const parsed = JSON.parse(readFileSync3(path, "utf8"));
|
|
331
|
+
const declared = parsed.doctor?.corpus;
|
|
332
|
+
return typeof declared === "string" && declared !== "" ? join3(root, declared) : void 0;
|
|
333
|
+
} catch {
|
|
334
|
+
return void 0;
|
|
335
|
+
}
|
|
336
|
+
};
|
|
337
|
+
|
|
322
338
|
// src/types.ts
|
|
323
339
|
var CHECKS = [
|
|
324
340
|
"loaded",
|
|
@@ -340,9 +356,9 @@ var DoctorError = class extends Error {
|
|
|
340
356
|
};
|
|
341
357
|
|
|
342
358
|
// src/resolve.ts
|
|
343
|
-
import { existsSync as
|
|
359
|
+
import { existsSync as existsSync3, readFileSync as readFileSync4, realpathSync } from "fs";
|
|
344
360
|
import { createRequire } from "module";
|
|
345
|
-
import { dirname, join as
|
|
361
|
+
import { dirname, join as join4 } from "path";
|
|
346
362
|
import { pathToFileURL } from "url";
|
|
347
363
|
var packageNameOf = (specifier) => {
|
|
348
364
|
const parts2 = specifier.split("/");
|
|
@@ -350,13 +366,13 @@ var packageNameOf = (specifier) => {
|
|
|
350
366
|
};
|
|
351
367
|
var resolveFrom = (dir, specifier) => {
|
|
352
368
|
if (specifier.startsWith(".") || specifier.startsWith("/")) {
|
|
353
|
-
return createRequire(
|
|
369
|
+
return createRequire(join4(dir, "noop.js")).resolve(specifier);
|
|
354
370
|
}
|
|
355
371
|
const name = packageNameOf(specifier);
|
|
356
372
|
let at = dir;
|
|
357
373
|
for (; ; ) {
|
|
358
|
-
if (
|
|
359
|
-
return createRequire(
|
|
374
|
+
if (existsSync3(join4(at, "node_modules", name, "package.json"))) {
|
|
375
|
+
return createRequire(join4(at, "noop.js")).resolve(specifier);
|
|
360
376
|
}
|
|
361
377
|
const parent = dirname(at);
|
|
362
378
|
if (parent === at) break;
|
|
@@ -369,10 +385,10 @@ var resolveFrom = (dir, specifier) => {
|
|
|
369
385
|
var packageDirOf = (entry, name) => {
|
|
370
386
|
let dir = dirname(entry);
|
|
371
387
|
for (; ; ) {
|
|
372
|
-
const manifest =
|
|
373
|
-
if (
|
|
388
|
+
const manifest = join4(dir, "package.json");
|
|
389
|
+
if (existsSync3(manifest)) {
|
|
374
390
|
try {
|
|
375
|
-
const parsed = JSON.parse(
|
|
391
|
+
const parsed = JSON.parse(readFileSync4(manifest, "utf8"));
|
|
376
392
|
if (parsed.name === name) return dir;
|
|
377
393
|
} catch {
|
|
378
394
|
}
|
|
@@ -421,7 +437,7 @@ var presumptionsOf = async (entry) => {
|
|
|
421
437
|
)
|
|
422
438
|
};
|
|
423
439
|
};
|
|
424
|
-
var corpusOfPlugin = (from, specifier) =>
|
|
440
|
+
var corpusOfPlugin = (from, specifier) => join4(packageDirOf(resolveFrom(from, specifier), specifier), "corpus");
|
|
425
441
|
var real = (path) => {
|
|
426
442
|
try {
|
|
427
443
|
return realpathSync(path);
|
|
@@ -431,14 +447,13 @@ var real = (path) => {
|
|
|
431
447
|
};
|
|
432
448
|
var relativeToRoot = (root, path) => relativePath(real(root), real(path));
|
|
433
449
|
|
|
434
|
-
// src/
|
|
435
|
-
import {
|
|
436
|
-
import {
|
|
437
|
-
import { join as join5, sep as sep2 } from "path";
|
|
450
|
+
// src/group.ts
|
|
451
|
+
import { existsSync as existsSync5, readFileSync as readFileSync6 } from "fs";
|
|
452
|
+
import { join as join6 } from "path";
|
|
438
453
|
|
|
439
454
|
// src/hooks.ts
|
|
440
|
-
import { existsSync as
|
|
441
|
-
import { join as
|
|
455
|
+
import { existsSync as existsSync4, readdirSync as readdirSync2, readFileSync as readFileSync5 } from "fs";
|
|
456
|
+
import { join as join5 } from "path";
|
|
442
457
|
var HOOK_FILES = ["lefthook.yml", "lefthook.yaml", ".lefthook.yml", ".lefthook.yaml"];
|
|
443
458
|
var HOOK_DIRS = [".husky", ".githooks"];
|
|
444
459
|
var VERSION_MANAGED = /(?:^|[\s;&|(])(?<runner>pnpm|npx|bunx|yarn)\b(?:\s+(?:exec|run|dlx|x))?\s+(?<bin>geonosis(?:-[a-z-]+)?)\b/;
|
|
@@ -447,26 +462,267 @@ var hookLines = (root) => {
|
|
|
447
462
|
const found = [];
|
|
448
463
|
const read = (path) => {
|
|
449
464
|
const at = relativePath(root, path);
|
|
450
|
-
for (const line of
|
|
465
|
+
for (const line of readFileSync5(path, "utf8").split("\n")) {
|
|
451
466
|
if (line.trim() !== "") found.push({ at, line });
|
|
452
467
|
}
|
|
453
468
|
};
|
|
454
469
|
for (const name of HOOK_FILES) {
|
|
455
|
-
const path =
|
|
456
|
-
if (
|
|
470
|
+
const path = join5(root, name);
|
|
471
|
+
if (existsSync4(path)) read(path);
|
|
457
472
|
}
|
|
458
473
|
for (const name of HOOK_DIRS) {
|
|
459
|
-
const dir =
|
|
460
|
-
if (!
|
|
474
|
+
const dir = join5(root, name);
|
|
475
|
+
if (!existsSync4(dir)) continue;
|
|
461
476
|
for (const entry of readdirSync2(dir, { withFileTypes: true })) {
|
|
462
477
|
if (entry.isFile() && !entry.name.startsWith("_") && !entry.name.startsWith(".")) {
|
|
463
|
-
read(
|
|
478
|
+
read(join5(dir, entry.name));
|
|
464
479
|
}
|
|
465
480
|
}
|
|
466
481
|
}
|
|
467
482
|
return found;
|
|
468
483
|
};
|
|
469
484
|
|
|
485
|
+
// src/group.ts
|
|
486
|
+
var FIXED_GROUP = [
|
|
487
|
+
"@geonosis/cli",
|
|
488
|
+
"@geonosis/doctor",
|
|
489
|
+
"@geonosis/evals",
|
|
490
|
+
"@geonosis/integrations",
|
|
491
|
+
"@geonosis/ledger",
|
|
492
|
+
"@geonosis/lint-parity",
|
|
493
|
+
"@geonosis/mcp",
|
|
494
|
+
"@geonosis/observability",
|
|
495
|
+
"@geonosis/oxlint-plugin-biological-architecture",
|
|
496
|
+
"@geonosis/policy",
|
|
497
|
+
"@geonosis/rails",
|
|
498
|
+
"@geonosis/ratchet",
|
|
499
|
+
"@geonosis/release",
|
|
500
|
+
"@geonosis/review",
|
|
501
|
+
"@geonosis/testbed",
|
|
502
|
+
"@geonosis/themekit",
|
|
503
|
+
"@geonosis/verify",
|
|
504
|
+
"@geonosis/verify-arch",
|
|
505
|
+
"@geonosis/visual-diff",
|
|
506
|
+
"@geonosis/walk",
|
|
507
|
+
"create-geonosis",
|
|
508
|
+
"geonosis"
|
|
509
|
+
];
|
|
510
|
+
var KIT_GROUP = { name: "@geonosis fixed group", packages: FIXED_GROUP };
|
|
511
|
+
var declaredGroupsOf = (root) => {
|
|
512
|
+
const path = join6(root, GEONOSIS_FILE);
|
|
513
|
+
if (!existsSync5(path)) return void 0;
|
|
514
|
+
let parsed;
|
|
515
|
+
try {
|
|
516
|
+
parsed = JSON.parse(readFileSync6(path, "utf8"));
|
|
517
|
+
} catch {
|
|
518
|
+
return void 0;
|
|
519
|
+
}
|
|
520
|
+
const declared = parsed.doctor?.groups;
|
|
521
|
+
if (declared === void 0) return void 0;
|
|
522
|
+
if (!Array.isArray(declared) || declared.length === 0) {
|
|
523
|
+
throw new DoctorError(
|
|
524
|
+
`${GEONOSIS_FILE} declares doctor.groups and names no group in it \u2014 say which packages must move together, or remove the key and get the kit's own group`
|
|
525
|
+
);
|
|
526
|
+
}
|
|
527
|
+
return declared.map((one, at) => {
|
|
528
|
+
const group = one;
|
|
529
|
+
if (typeof group.name !== "string" || !Array.isArray(group.packages) || group.packages.length < 2) {
|
|
530
|
+
throw new DoctorError(
|
|
531
|
+
`${GEONOSIS_FILE} doctor.groups[${at}] needs a name and at least two packages \u2014 one package cannot disagree with itself`
|
|
532
|
+
);
|
|
533
|
+
}
|
|
534
|
+
return { name: group.name, packages: group.packages };
|
|
535
|
+
});
|
|
536
|
+
};
|
|
537
|
+
var labelOf = (workspace) => workspace.relative === "" ? "root" : workspace.relative;
|
|
538
|
+
var versionOf = (dir, name) => {
|
|
539
|
+
let entry;
|
|
540
|
+
try {
|
|
541
|
+
entry = resolveFrom(dir, name);
|
|
542
|
+
} catch {
|
|
543
|
+
return { kind: "absent" };
|
|
544
|
+
}
|
|
545
|
+
try {
|
|
546
|
+
const manifest = JSON.parse(
|
|
547
|
+
readFileSync6(join6(packageDirOf(entry, name), "package.json"), "utf8")
|
|
548
|
+
);
|
|
549
|
+
return typeof manifest.version === "string" ? { kind: "read", version: manifest.version } : { kind: "unreadable", why: "its package.json declares no version" };
|
|
550
|
+
} catch (error) {
|
|
551
|
+
return { kind: "unreadable", why: String(error.message).split("\n")[0] ?? "" };
|
|
552
|
+
}
|
|
553
|
+
};
|
|
554
|
+
var finding3 = (subject, verdict, message) => ({
|
|
555
|
+
check: "group",
|
|
556
|
+
message,
|
|
557
|
+
subject,
|
|
558
|
+
verdict
|
|
559
|
+
});
|
|
560
|
+
var said = (versions) => [...versions.entries()].map(([version, from]) => `${version} (${from.join(", ")})`).join("; ");
|
|
561
|
+
var repoWide = (name, found) => {
|
|
562
|
+
const versions = /* @__PURE__ */ new Map();
|
|
563
|
+
for (const one of found) versions.set(one.version, [...versions.get(one.version) ?? [], one.at]);
|
|
564
|
+
if (versions.size === 1) return void 0;
|
|
565
|
+
return finding3(
|
|
566
|
+
name,
|
|
567
|
+
"FAIL",
|
|
568
|
+
`${versions.size} versions in one tree \u2014 ${said(versions)}. They are published as one number, so a tree holding two is a tree where one workspace is running code another has already replaced; remove the nested copies and reinstall`
|
|
569
|
+
);
|
|
570
|
+
};
|
|
571
|
+
var perWorkspace = (group, at, found) => {
|
|
572
|
+
if (new Set(found.map((one) => one.version)).size === 1) return void 0;
|
|
573
|
+
const listed = found.map((one) => `${one.name} ${one.version}`).join(", ");
|
|
574
|
+
return finding3(
|
|
575
|
+
at,
|
|
576
|
+
"FAIL",
|
|
577
|
+
`${group.name} does not hold together here \u2014 ${listed}. Every member is cut on one version, so a workspace resolving two of them is a bump that landed halfway`
|
|
578
|
+
);
|
|
579
|
+
};
|
|
580
|
+
var DOORS = ["@geonosis/cli", "geonosis"];
|
|
581
|
+
var manifestOf = (dir, name) => {
|
|
582
|
+
try {
|
|
583
|
+
return JSON.parse(
|
|
584
|
+
readFileSync6(join6(packageDirOf(resolveFrom(dir, name), name), "package.json"), "utf8")
|
|
585
|
+
);
|
|
586
|
+
} catch {
|
|
587
|
+
return void 0;
|
|
588
|
+
}
|
|
589
|
+
};
|
|
590
|
+
var binNamesOf = (manifest, name) => {
|
|
591
|
+
const declared = manifest?.bin;
|
|
592
|
+
return typeof declared === "string" ? [name.replace(/^@[^/]+\//, "")] : Object.keys(declared ?? {});
|
|
593
|
+
};
|
|
594
|
+
var declaredIn2 = (manifest) => [
|
|
595
|
+
...new Set(
|
|
596
|
+
[
|
|
597
|
+
manifest.dependencies,
|
|
598
|
+
manifest.devDependencies,
|
|
599
|
+
manifest.optionalDependencies,
|
|
600
|
+
manifest.peerDependencies
|
|
601
|
+
].flatMap((block) => Object.keys(block ?? {}))
|
|
602
|
+
)
|
|
603
|
+
];
|
|
604
|
+
var calls = (lines, bin) => new RegExp(`(?:^|[\\s;&|(/])${bin}(?:\\s|$)`).test(lines);
|
|
605
|
+
var workspaceCaller = (workspaces, bins) => {
|
|
606
|
+
for (const workspace of workspaces) {
|
|
607
|
+
if (workspace.relative === "") continue;
|
|
608
|
+
for (const [script, line] of Object.entries(workspace.manifest.scripts ?? {})) {
|
|
609
|
+
if (bins.some((bin) => calls(line, bin))) return { at: workspace.relative, script };
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
return void 0;
|
|
613
|
+
};
|
|
614
|
+
var rootDeclarations = (root, workspaces) => {
|
|
615
|
+
const here = workspaces.find((one) => one.relative === "");
|
|
616
|
+
if (here === void 0) return [];
|
|
617
|
+
const declared = declaredIn2(here.manifest);
|
|
618
|
+
const door = DOORS.find((name) => declared.includes(name));
|
|
619
|
+
if (door === void 0) return [];
|
|
620
|
+
const owned = new Set(
|
|
621
|
+
[door, ...DOORS].flatMap((name) => {
|
|
622
|
+
const manifest = manifestOf(root, name);
|
|
623
|
+
return manifest === void 0 ? [] : Object.keys(manifest.dependencies ?? {});
|
|
624
|
+
})
|
|
625
|
+
);
|
|
626
|
+
const callers = [
|
|
627
|
+
...Object.values(here.manifest.scripts ?? {}),
|
|
628
|
+
...hookLines(root).map((one) => one.line)
|
|
629
|
+
].join("\n");
|
|
630
|
+
const loadedHere = new Set(readConfig(join6(root, CONFIG_FILE), root).jsPlugins);
|
|
631
|
+
const spare = declared.filter(
|
|
632
|
+
(name) => !DOORS.includes(name) && owned.has(name) && !loadedHere.has(name) && !binNamesOf(manifestOf(root, name), name).some((bin) => calls(callers, bin))
|
|
633
|
+
);
|
|
634
|
+
if (spare.length === 0) {
|
|
635
|
+
return [
|
|
636
|
+
finding3(
|
|
637
|
+
"package.json",
|
|
638
|
+
"OK",
|
|
639
|
+
`every @geonosis package this root declares is ${door} or a bin its own scripts call by name`
|
|
640
|
+
)
|
|
641
|
+
];
|
|
642
|
+
}
|
|
643
|
+
return spare.map((name) => {
|
|
644
|
+
const bins = binNamesOf(manifestOf(root, name), name);
|
|
645
|
+
const inWorkspace = workspaceCaller(workspaces, bins);
|
|
646
|
+
if (inWorkspace !== void 0) {
|
|
647
|
+
return finding3(
|
|
648
|
+
name,
|
|
649
|
+
"OK",
|
|
650
|
+
`no root script calls its bin, and ${inWorkspace.at}'s "${inWorkspace.script}" script does \u2014 under a hoisted linker the ROOT declaration is what makes that bin resolvable there, so this is the declaration doing its job`
|
|
651
|
+
);
|
|
652
|
+
}
|
|
653
|
+
return finding3(
|
|
654
|
+
name,
|
|
655
|
+
"WARN",
|
|
656
|
+
`the root declares it and no script in this repo calls its bin \u2014 ${door} already brings it, so this second declaration is a version that can disagree with the door's, and every tool that asks what is used here reads it as unused. Drop it from the root, or declare it in the workspace whose code imports it`
|
|
657
|
+
);
|
|
658
|
+
});
|
|
659
|
+
};
|
|
660
|
+
var checkGroup = ({
|
|
661
|
+
groups,
|
|
662
|
+
root,
|
|
663
|
+
workspaces
|
|
664
|
+
}) => {
|
|
665
|
+
const findings = [...rootDeclarations(root, workspaces)];
|
|
666
|
+
for (const group of groups ?? [KIT_GROUP]) {
|
|
667
|
+
const found = [];
|
|
668
|
+
for (const workspace of workspaces) {
|
|
669
|
+
const at = labelOf(workspace);
|
|
670
|
+
const here = [];
|
|
671
|
+
for (const name of group.packages) {
|
|
672
|
+
const reading = versionOf(workspace.dir, name);
|
|
673
|
+
if (reading.kind === "read") here.push({ at, name, version: reading.version });
|
|
674
|
+
if (reading.kind === "unreadable") {
|
|
675
|
+
findings.push(
|
|
676
|
+
finding3(
|
|
677
|
+
`${at} \u2192 ${name}`,
|
|
678
|
+
"UNJUDGED",
|
|
679
|
+
`it resolves from here and ${reading.why} \u2014 this copy could be any version, so the group cannot be said to hold or not to hold`
|
|
680
|
+
)
|
|
681
|
+
);
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
const split2 = here.length > 0 ? perWorkspace(group, at, here) : void 0;
|
|
685
|
+
if (split2 !== void 0) findings.push(split2);
|
|
686
|
+
found.push(...here);
|
|
687
|
+
}
|
|
688
|
+
if (found.length === 0) {
|
|
689
|
+
findings.push(
|
|
690
|
+
finding3(
|
|
691
|
+
group.name,
|
|
692
|
+
"SKIP",
|
|
693
|
+
`no workspace under ${root} resolves any of ${group.packages.join(", ")}, so nothing here versions together`
|
|
694
|
+
)
|
|
695
|
+
);
|
|
696
|
+
continue;
|
|
697
|
+
}
|
|
698
|
+
const names = [...new Set(found.map((one) => one.name))].toSorted();
|
|
699
|
+
const split = names.flatMap((name) => {
|
|
700
|
+
const line = repoWide(
|
|
701
|
+
name,
|
|
702
|
+
found.filter((one) => one.name === name)
|
|
703
|
+
);
|
|
704
|
+
return line === void 0 ? [] : [line];
|
|
705
|
+
});
|
|
706
|
+
findings.push(...split);
|
|
707
|
+
if (split.length === 0) {
|
|
708
|
+
const versions = [...new Set(found.map((one) => one.version))];
|
|
709
|
+
findings.push(
|
|
710
|
+
finding3(
|
|
711
|
+
group.name,
|
|
712
|
+
"OK",
|
|
713
|
+
`${names.length} of ${group.packages.length} installed, at ${versions.join(", ")}, one copy each across ${new Set(found.map((one) => one.at)).size} workspaces`
|
|
714
|
+
)
|
|
715
|
+
);
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
return findings;
|
|
719
|
+
};
|
|
720
|
+
|
|
721
|
+
// src/drift.ts
|
|
722
|
+
import { closeSync, existsSync as existsSync6, openSync, readdirSync as readdirSync3, readFileSync as readFileSync7, readSync } from "fs";
|
|
723
|
+
import { homedir } from "os";
|
|
724
|
+
import { join as join7, sep as sep2 } from "path";
|
|
725
|
+
|
|
470
726
|
// src/overrides.ts
|
|
471
727
|
var SPECIAL = /* @__PURE__ */ new Set(["$", "(", ")", "+", ".", "/", "@", "\\", "^", "|"]);
|
|
472
728
|
var globToRegExp = (glob) => {
|
|
@@ -537,7 +793,7 @@ var GEONOSIS = "geonosis.json";
|
|
|
537
793
|
var LAW = "CLAUDE.md";
|
|
538
794
|
var CEILING = 200;
|
|
539
795
|
var SWITCHED_OFF = /^\s*if:\s*(?:\$\{\{\s*)?false\b/m;
|
|
540
|
-
var
|
|
796
|
+
var finding4 = (subject, verdict, message) => ({
|
|
541
797
|
check: "drift",
|
|
542
798
|
message,
|
|
543
799
|
subject,
|
|
@@ -555,27 +811,27 @@ var filesUnder = (dir, match) => {
|
|
|
555
811
|
}
|
|
556
812
|
for (const entry of entries) {
|
|
557
813
|
if (entry.isDirectory()) {
|
|
558
|
-
if (!entry.name.startsWith(".") && !NEVER_WALKED2.has(entry.name)) walk2(
|
|
814
|
+
if (!entry.name.startsWith(".") && !NEVER_WALKED2.has(entry.name)) walk2(join7(at, entry.name));
|
|
559
815
|
continue;
|
|
560
816
|
}
|
|
561
|
-
if (entry.isFile() && match(entry.name)) found.push(
|
|
817
|
+
if (entry.isFile() && match(entry.name)) found.push(join7(at, entry.name));
|
|
562
818
|
}
|
|
563
819
|
};
|
|
564
820
|
walk2(dir);
|
|
565
821
|
return found;
|
|
566
822
|
};
|
|
567
823
|
var ci = (root) => {
|
|
568
|
-
const dir =
|
|
569
|
-
if (!
|
|
570
|
-
return [
|
|
824
|
+
const dir = join7(root, WORKFLOWS);
|
|
825
|
+
if (!existsSync6(dir)) {
|
|
826
|
+
return [finding4(WORKFLOWS, "SKIP", "there are no workflows here to read")];
|
|
571
827
|
}
|
|
572
828
|
return filesUnder(dir, (name) => name.endsWith(".yml") || name.endsWith(".yaml")).map((path) => {
|
|
573
829
|
const at = relativePath(root, path);
|
|
574
|
-
return SWITCHED_OFF.test(
|
|
830
|
+
return SWITCHED_OFF.test(readFileSync7(path, "utf8")) ? finding4(
|
|
575
831
|
at,
|
|
576
832
|
"FAIL",
|
|
577
833
|
"a job or step here is switched off by a condition that can never be true \u2014 every gate downstream of it reports green having run nothing"
|
|
578
|
-
) :
|
|
834
|
+
) : finding4(at, "OK", "nothing in it is switched off");
|
|
579
835
|
});
|
|
580
836
|
};
|
|
581
837
|
var holds = (parent, child) => child === parent || child.startsWith(`${parent}${sep2}`);
|
|
@@ -591,10 +847,10 @@ var orphanTests = (root, workspaces) => {
|
|
|
591
847
|
orphaned.set(at, [...orphaned.get(at) ?? [], relativePath(root, path)]);
|
|
592
848
|
}
|
|
593
849
|
if (orphaned.size === 0) {
|
|
594
|
-
return [
|
|
850
|
+
return [finding4("test files", "OK", "every test file sits under a workspace that runs tests")];
|
|
595
851
|
}
|
|
596
852
|
return [...orphaned.entries()].map(
|
|
597
|
-
([at, files]) =>
|
|
853
|
+
([at, files]) => finding4(
|
|
598
854
|
at,
|
|
599
855
|
"FAIL",
|
|
600
856
|
`${files.length} test file(s) here and no test script to run them \u2014 ${files.slice(0, 3).join(", ")}`
|
|
@@ -619,16 +875,16 @@ var pathsRunByScript = (script) => script.split(BETWEEN_COMMANDS).map(pathRunBy)
|
|
|
619
875
|
var scriptPaths = (workspaces) => {
|
|
620
876
|
const missing = workspaces.flatMap(
|
|
621
877
|
(one) => Object.entries(one.manifest.scripts ?? {}).flatMap(
|
|
622
|
-
([name, script]) => pathsRunByScript(script).filter((path) => !
|
|
878
|
+
([name, script]) => pathsRunByScript(script).filter((path) => !existsSync6(join7(one.dir, path))).map((path) => ({ name, path, workspace: one }))
|
|
623
879
|
)
|
|
624
880
|
);
|
|
625
881
|
if (missing.length === 0) {
|
|
626
882
|
return [
|
|
627
|
-
|
|
883
|
+
finding4("script paths", "OK", "every file a script hands to bun, node or tsx is on disk")
|
|
628
884
|
];
|
|
629
885
|
}
|
|
630
886
|
return missing.map(
|
|
631
|
-
({ name, path, workspace }) =>
|
|
887
|
+
({ name, path, workspace }) => finding4(
|
|
632
888
|
workspace.relative === "" ? "package.json" : `${workspace.relative}/package.json`,
|
|
633
889
|
"FAIL",
|
|
634
890
|
`the "${name}" script runs ${path} and there is no such file \u2014 this script fails at that command, and every gate that calls it has been running nothing since the file went`
|
|
@@ -651,16 +907,16 @@ var workspaceBins = (workspaces) => {
|
|
|
651
907
|
var linkedBins = (root, workspaces) => {
|
|
652
908
|
const bins = workspaceBins(workspaces);
|
|
653
909
|
if (bins.size === 0) {
|
|
654
|
-
return [
|
|
910
|
+
return [finding4("workspace bins", "SKIP", "no workspace here declares a bin")];
|
|
655
911
|
}
|
|
656
912
|
const missing = workspaces.flatMap(
|
|
657
913
|
(one) => Object.entries(one.manifest.scripts ?? {}).flatMap(
|
|
658
|
-
([script, body]) => [...new Set(body.split(/[\s;|&()]+/).filter((word) => bins.has(word)))].filter((name) => !
|
|
914
|
+
([script, body]) => [...new Set(body.split(/[\s;|&()]+/).filter((word) => bins.has(word)))].filter((name) => !existsSync6(join7(root, "node_modules/.bin", name))).map((name) => ({ name, script, workspace: one }))
|
|
659
915
|
)
|
|
660
916
|
);
|
|
661
917
|
if (missing.length === 0) {
|
|
662
918
|
return [
|
|
663
|
-
|
|
919
|
+
finding4(
|
|
664
920
|
"workspace bins",
|
|
665
921
|
"OK",
|
|
666
922
|
"every workspace bin a script names is linked under the root"
|
|
@@ -668,7 +924,7 @@ var linkedBins = (root, workspaces) => {
|
|
|
668
924
|
];
|
|
669
925
|
}
|
|
670
926
|
return missing.map(
|
|
671
|
-
({ name, script, workspace }) =>
|
|
927
|
+
({ name, script, workspace }) => finding4(
|
|
672
928
|
name,
|
|
673
929
|
"FAIL",
|
|
674
930
|
`the "${script}" script in ${workspace.relative === "" ? "package.json" : `${workspace.relative}/package.json`} calls it, ${bins.get(name)?.manifest.name ?? "a workspace"} declares it, and node_modules/.bin/${name} is not there \u2014 add that package as a dependency of the one whose script calls it, so the package manager links the bin`
|
|
@@ -690,7 +946,7 @@ var preloadAroundPnpm = (root, workspaces) => {
|
|
|
690
946
|
const some = scripts.slice(0, 3).join(", ");
|
|
691
947
|
const rest = scripts.length > 3 ? ` and ${scripts.length - 3} more` : "";
|
|
692
948
|
return [
|
|
693
|
-
|
|
949
|
+
finding4(
|
|
694
950
|
"NODE_OPTIONS",
|
|
695
951
|
"WARN",
|
|
696
952
|
`${scripts.length} script(s) preload something through NODE_OPTIONS (${some}${rest}), and the "${named2}" counter(s) shell out to pnpm \u2014 a nested pnpm INHERITS the option and dies on it (a preloaded resolver patch sends it looking for a .pnpmfile.mjs that is not there). Run the ratchet outside those scripts, or unset NODE_OPTIONS for the nested call: env -u NODE_OPTIONS pnpm \u2026`
|
|
@@ -726,11 +982,11 @@ var everythingRun = (root, workspaces) => {
|
|
|
726
982
|
const scripts = workspaces.flatMap((one) => Object.values(one.manifest.scripts ?? {}));
|
|
727
983
|
const counters = (readRatchet(root)?.counters ?? []).map((entry) => String(entry.command ?? ""));
|
|
728
984
|
const workflows = filesUnder(
|
|
729
|
-
|
|
985
|
+
join7(root, WORKFLOWS),
|
|
730
986
|
(name) => name.endsWith(".yml") || name.endsWith(".yaml")
|
|
731
987
|
).map((path) => {
|
|
732
988
|
try {
|
|
733
|
-
return
|
|
989
|
+
return readFileSync7(path, "utf8");
|
|
734
990
|
} catch {
|
|
735
991
|
return "";
|
|
736
992
|
}
|
|
@@ -741,7 +997,7 @@ var generatedFiles = (root, workspaces) => {
|
|
|
741
997
|
const marked = filesUnder(root, (name) => CAN_CARRY_A_MARKER.test(name)).map((path) => ({ marker: markerIn(path), path })).filter((one) => one.marker !== void 0);
|
|
742
998
|
if (marked.length === 0) {
|
|
743
999
|
return [
|
|
744
|
-
|
|
1000
|
+
finding4(
|
|
745
1001
|
"generated files",
|
|
746
1002
|
"SKIP",
|
|
747
1003
|
"nothing here says it was generated, so there is no write half here to look for a read half of"
|
|
@@ -752,13 +1008,13 @@ var generatedFiles = (root, workspaces) => {
|
|
|
752
1008
|
return marked.map(({ marker, path }) => {
|
|
753
1009
|
const at = relativePath(root, path);
|
|
754
1010
|
if (!("gate" in marker)) {
|
|
755
|
-
return
|
|
1011
|
+
return finding4(
|
|
756
1012
|
at,
|
|
757
1013
|
"FAIL",
|
|
758
1014
|
`generated by \`${marker.writer}\` and it names no gate that reads it back. A written file no check reads is the write half of an instrument with no read half: it can drift from its source for ever and every gate stays green. Re-run \`${marker.writer}\` on a version that writes the \`geonosis:gated-by:\` marker, and run the gate it names`
|
|
759
1015
|
);
|
|
760
1016
|
}
|
|
761
|
-
return run.includes(marker.gate) ?
|
|
1017
|
+
return run.includes(marker.gate) ? finding4(at, "OK", `generated, and \`${marker.gate}\` reads it back`) : finding4(
|
|
762
1018
|
at,
|
|
763
1019
|
"FAIL",
|
|
764
1020
|
`generated, and nothing here runs \`${marker.gate}\` \u2014 the gate it names. A written file no check reads is the write half of an instrument with no read half: it can drift from its source for ever and every gate stays green. Add \`${marker.gate}\` to a script, a counter or a workflow`
|
|
@@ -766,10 +1022,10 @@ var generatedFiles = (root, workspaces) => {
|
|
|
766
1022
|
});
|
|
767
1023
|
};
|
|
768
1024
|
var readGeonosis = (root) => {
|
|
769
|
-
const path =
|
|
770
|
-
if (!
|
|
1025
|
+
const path = join7(root, GEONOSIS);
|
|
1026
|
+
if (!existsSync6(path)) return void 0;
|
|
771
1027
|
try {
|
|
772
|
-
return JSON.parse(
|
|
1028
|
+
return JSON.parse(readFileSync7(path, "utf8"));
|
|
773
1029
|
} catch {
|
|
774
1030
|
return void 0;
|
|
775
1031
|
}
|
|
@@ -777,15 +1033,15 @@ var readGeonosis = (root) => {
|
|
|
777
1033
|
var law = (root, config) => {
|
|
778
1034
|
const declared = config?.law ?? {};
|
|
779
1035
|
const file = typeof declared.file === "string" ? declared.file : LAW;
|
|
780
|
-
const path =
|
|
781
|
-
if (!
|
|
782
|
-
return [
|
|
1036
|
+
const path = join7(root, file);
|
|
1037
|
+
if (!existsSync6(path)) {
|
|
1038
|
+
return [finding4(file, "SKIP", "there is no law file here to measure")];
|
|
783
1039
|
}
|
|
784
|
-
const source =
|
|
1040
|
+
const source = readFileSync7(path, "utf8");
|
|
785
1041
|
const lines = source.split("\n").length - (source.endsWith("\n") ? 1 : 0);
|
|
786
1042
|
if (typeof declared.maxLines !== "number") {
|
|
787
1043
|
return [
|
|
788
|
-
|
|
1044
|
+
finding4(
|
|
789
1045
|
file,
|
|
790
1046
|
"SKIP",
|
|
791
1047
|
`${lines} lines, and no ceiling to measure them against \u2014 set law.maxLines in geonosis.json to have this asked (${CEILING} is what both source repos converged on)`
|
|
@@ -794,18 +1050,18 @@ var law = (root, config) => {
|
|
|
794
1050
|
}
|
|
795
1051
|
const ceiling = declared.maxLines;
|
|
796
1052
|
return [
|
|
797
|
-
lines > ceiling ?
|
|
1053
|
+
lines > ceiling ? finding4(
|
|
798
1054
|
file,
|
|
799
1055
|
"WARN",
|
|
800
1056
|
`${lines} lines against a ceiling of ${ceiling} \u2014 depth belongs in the skills and in the rules, where it is read`
|
|
801
|
-
) :
|
|
1057
|
+
) : finding4(file, "OK", `${lines} lines, under the ceiling of ${ceiling}`)
|
|
802
1058
|
];
|
|
803
1059
|
};
|
|
804
1060
|
var KIT_PLUGIN = "geonosis";
|
|
805
1061
|
var enablesKit = (path) => {
|
|
806
|
-
if (!
|
|
1062
|
+
if (!existsSync6(path)) return false;
|
|
807
1063
|
try {
|
|
808
|
-
const parsed = JSON.parse(
|
|
1064
|
+
const parsed = JSON.parse(readFileSync7(path, "utf8"));
|
|
809
1065
|
const enabled = parsed.enabledPlugins;
|
|
810
1066
|
if (typeof enabled !== "object" || enabled === null) return false;
|
|
811
1067
|
return Object.entries(enabled).some(
|
|
@@ -816,13 +1072,13 @@ var enablesKit = (path) => {
|
|
|
816
1072
|
}
|
|
817
1073
|
};
|
|
818
1074
|
var hooks = (root, userSettings) => {
|
|
819
|
-
const path =
|
|
1075
|
+
const path = join7(root, SETTINGS);
|
|
820
1076
|
if (enablesKit(path)) {
|
|
821
|
-
return [
|
|
1077
|
+
return [finding4(SETTINGS, "OK", `\`enabledPlugins\` here enables the kit\u2019s plugin`)];
|
|
822
1078
|
}
|
|
823
1079
|
if (enablesKit(userSettings)) {
|
|
824
1080
|
return [
|
|
825
|
-
|
|
1081
|
+
finding4(
|
|
826
1082
|
SETTINGS,
|
|
827
1083
|
"OK",
|
|
828
1084
|
`installed elsewhere \u2014 not this repo\u2019s to declare: \`enabledPlugins\` in ${userSettings} enables it for every repo on this machine`
|
|
@@ -830,7 +1086,7 @@ var hooks = (root, userSettings) => {
|
|
|
830
1086
|
];
|
|
831
1087
|
}
|
|
832
1088
|
return [
|
|
833
|
-
|
|
1089
|
+
finding4(
|
|
834
1090
|
SETTINGS,
|
|
835
1091
|
"WARN",
|
|
836
1092
|
`nothing enables the kit\u2019s plugin, so none of the hooks, agents or skills reach this repo \u2014 the gates run, the method does not. What satisfies this: a "geonosis@<marketplace>" entry under \`enabledPlugins\` in ${SETTINGS} here, or the same in the user-scope ${userSettings}`
|
|
@@ -839,9 +1095,9 @@ var hooks = (root, userSettings) => {
|
|
|
839
1095
|
};
|
|
840
1096
|
var ALLOW_BUILDS_KEY = "allowBuilds";
|
|
841
1097
|
var allowedBuilds = (root) => {
|
|
842
|
-
const path =
|
|
843
|
-
if (!
|
|
844
|
-
const lines =
|
|
1098
|
+
const path = join7(root, WORKSPACE_YAML);
|
|
1099
|
+
if (!existsSync6(path)) return void 0;
|
|
1100
|
+
const lines = readFileSync7(path, "utf8").split("\n");
|
|
845
1101
|
const at = lines.findIndex((line) => new RegExp(`^${ALLOW_BUILDS_KEY}\\s*:`).test(line));
|
|
846
1102
|
if (at < 0) return void 0;
|
|
847
1103
|
const names = [];
|
|
@@ -866,7 +1122,7 @@ var platformSplitBuilds = (root) => {
|
|
|
866
1122
|
}
|
|
867
1123
|
return [...families.entries()].flatMap(
|
|
868
1124
|
([family, allowed]) => allowed.length > 1 ? [] : [
|
|
869
|
-
|
|
1125
|
+
finding4(
|
|
870
1126
|
allowed[0] ?? family,
|
|
871
1127
|
"WARN",
|
|
872
1128
|
`this ${ALLOW_BUILDS_KEY} entry names one platform of ${family}, which publishes one package per platform \u2014 pnpm writes the entry for the machine that ran the install, so an install on any other platform refuses by the name that is missing, on somebody else's machine. List every platform ${family} publishes, or none of them`
|
|
@@ -892,7 +1148,7 @@ var pathsLintedBy = (script, dir) => {
|
|
|
892
1148
|
if (word.startsWith("-")) continue;
|
|
893
1149
|
const before = words[at - 1] ?? "";
|
|
894
1150
|
if (TAKES_A_VALUE.has(before)) continue;
|
|
895
|
-
if (
|
|
1151
|
+
if (existsSync6(join7(dir, word))) named2.push(word.replace(/^\.\//, "").replace(/\/$/, ""));
|
|
896
1152
|
}
|
|
897
1153
|
return named2;
|
|
898
1154
|
};
|
|
@@ -905,13 +1161,13 @@ var sourceDirsIn = (dir) => {
|
|
|
905
1161
|
return [];
|
|
906
1162
|
}
|
|
907
1163
|
return entries.filter(
|
|
908
|
-
(entry) => entry.isDirectory() && !entry.name.startsWith(".") && !NEVER_WALKED2.has(entry.name) && filesUnder(
|
|
1164
|
+
(entry) => entry.isDirectory() && !entry.name.startsWith(".") && !NEVER_WALKED2.has(entry.name) && filesUnder(join7(dir, entry.name), (name) => LINTABLE.test(name)).length > 0
|
|
909
1165
|
).map((entry) => entry.name);
|
|
910
1166
|
};
|
|
911
1167
|
var lintScopes = (root, workspaces) => {
|
|
912
1168
|
if (!hookLines(root).some((one) => LINTS_STAGED.test(one.line))) {
|
|
913
1169
|
return [
|
|
914
|
-
|
|
1170
|
+
finding4(
|
|
915
1171
|
"lint scope",
|
|
916
1172
|
"SKIP",
|
|
917
1173
|
"no committed hook lints staged files here, so there is no second file set for a lint script to be narrower than"
|
|
@@ -924,16 +1180,16 @@ var lintScopes = (root, workspaces) => {
|
|
|
924
1180
|
const at = workspace.relative === "" ? "package.json" : `${workspace.relative}/package.json`;
|
|
925
1181
|
const covered = pathsLintedBy(script, workspace.dir);
|
|
926
1182
|
if (covered.length === 0 || covered.includes(".")) {
|
|
927
|
-
return [
|
|
1183
|
+
return [finding4(at, "OK", `"${script}" covers everything the hook could stage here`)];
|
|
928
1184
|
}
|
|
929
1185
|
const uncovered = sourceDirsIn(workspace.dir).filter(
|
|
930
1186
|
(name) => !covered.some((path) => name === path || path.startsWith(`${name}/`))
|
|
931
1187
|
);
|
|
932
1188
|
if (uncovered.length === 0) {
|
|
933
|
-
return [
|
|
1189
|
+
return [finding4(at, "OK", `"${script}" covers every source directory under this workspace`)];
|
|
934
1190
|
}
|
|
935
1191
|
return [
|
|
936
|
-
|
|
1192
|
+
finding4(
|
|
937
1193
|
at,
|
|
938
1194
|
"WARN",
|
|
939
1195
|
`the "lint" script covers ${covered.join(", ")} and the pre-commit hook lints whatever is staged, so ${uncovered.map((name) => `${name}/**`).join(", ")} is linted by the hook alone \u2014 the package gate has never read those files, and the drift stays invisible until one moves across it. Widen the script, or say in it which globs are deliberately outside`
|
|
@@ -969,7 +1225,7 @@ var composedHere = (root, workspaces) => {
|
|
|
969
1225
|
for (const path of filesUnder(root, (name) => SOURCE_FILE.test(name))) {
|
|
970
1226
|
let body;
|
|
971
1227
|
try {
|
|
972
|
-
body =
|
|
1228
|
+
body = readFileSync7(path, "utf8");
|
|
973
1229
|
} catch {
|
|
974
1230
|
continue;
|
|
975
1231
|
}
|
|
@@ -980,11 +1236,11 @@ var composedHere = (root, workspaces) => {
|
|
|
980
1236
|
}
|
|
981
1237
|
return wanted.map((one) => {
|
|
982
1238
|
const at = importing.get(one.name);
|
|
983
|
-
return at === void 0 ?
|
|
1239
|
+
return at === void 0 ? finding4(
|
|
984
1240
|
one.name,
|
|
985
1241
|
"WARN",
|
|
986
1242
|
`it is declared here and no source file imports it \u2014 ${one.uncomposed}`
|
|
987
|
-
) :
|
|
1243
|
+
) : finding4(
|
|
988
1244
|
one.name,
|
|
989
1245
|
"OK",
|
|
990
1246
|
`composed in ${relativePath(root, at)} \u2014 something here builds what it reports through`
|
|
@@ -998,6 +1254,18 @@ var READERS = {
|
|
|
998
1254
|
verify: "@geonosis/verify",
|
|
999
1255
|
walk: "@geonosis/walk"
|
|
1000
1256
|
};
|
|
1257
|
+
var doorBringing = (root, name, declared) => DOORS.filter((door) => declared.has(door)).find(
|
|
1258
|
+
(door) => Object.hasOwn(dependenciesOf(root, door), name)
|
|
1259
|
+
);
|
|
1260
|
+
var dependenciesOf = (root, name) => {
|
|
1261
|
+
try {
|
|
1262
|
+
return JSON.parse(
|
|
1263
|
+
readFileSync7(join7(packageDirOf(resolveFrom(root, name), name), "package.json"), "utf8")
|
|
1264
|
+
).dependencies ?? {};
|
|
1265
|
+
} catch {
|
|
1266
|
+
return {};
|
|
1267
|
+
}
|
|
1268
|
+
};
|
|
1001
1269
|
var resolves = (root, name) => {
|
|
1002
1270
|
try {
|
|
1003
1271
|
resolveFrom(root, name);
|
|
@@ -1019,7 +1287,7 @@ var declaredAnywhere = (workspaces) => new Set(
|
|
|
1019
1287
|
var blocks = (root, config, readers, workspaces) => {
|
|
1020
1288
|
if (config === void 0) {
|
|
1021
1289
|
return [
|
|
1022
|
-
|
|
1290
|
+
finding4(
|
|
1023
1291
|
GEONOSIS,
|
|
1024
1292
|
"SKIP",
|
|
1025
1293
|
"there is no geonosis.json here, so no block says what this repo asks the kit to do"
|
|
@@ -1029,11 +1297,21 @@ var blocks = (root, config, readers, workspaces) => {
|
|
|
1029
1297
|
const declaredPackages = declaredAnywhere(workspaces);
|
|
1030
1298
|
return Object.entries(readers).flatMap(([block, name]) => {
|
|
1031
1299
|
const declared = config[block] !== void 0;
|
|
1300
|
+
const door = doorBringing(root, name, declaredPackages);
|
|
1032
1301
|
const chosen = declaredPackages.has(name);
|
|
1033
1302
|
const installed = resolves(root, name);
|
|
1303
|
+
if (declared && !chosen && door !== void 0) {
|
|
1304
|
+
return [
|
|
1305
|
+
finding4(
|
|
1306
|
+
name,
|
|
1307
|
+
"OK",
|
|
1308
|
+
`a "${block}" block, and ${door} brings ${name} to read it \u2014 #177: the root declares the door, not what the door owns`
|
|
1309
|
+
)
|
|
1310
|
+
];
|
|
1311
|
+
}
|
|
1034
1312
|
if (declared && !chosen) {
|
|
1035
1313
|
return [
|
|
1036
|
-
|
|
1314
|
+
finding4(
|
|
1037
1315
|
name,
|
|
1038
1316
|
"WARN",
|
|
1039
1317
|
`geonosis.json has a "${block}" block and no manifest here declares ${name} \u2014 nothing reads it${installed ? ", and the copy still under node_modules is what a stale install left behind" : ""}`
|
|
@@ -1042,7 +1320,7 @@ var blocks = (root, config, readers, workspaces) => {
|
|
|
1042
1320
|
}
|
|
1043
1321
|
if (declared && !installed) {
|
|
1044
1322
|
return [
|
|
1045
|
-
|
|
1323
|
+
finding4(
|
|
1046
1324
|
name,
|
|
1047
1325
|
"WARN",
|
|
1048
1326
|
`geonosis.json has a "${block}" block, a manifest declares ${name}, and it does not resolve here \u2014 run the install`
|
|
@@ -1051,7 +1329,7 @@ var blocks = (root, config, readers, workspaces) => {
|
|
|
1051
1329
|
}
|
|
1052
1330
|
if (!declared && chosen && installed) {
|
|
1053
1331
|
return [
|
|
1054
|
-
|
|
1332
|
+
finding4(
|
|
1055
1333
|
name,
|
|
1056
1334
|
"WARN",
|
|
1057
1335
|
`${name} is installed and geonosis.json has no "${block}" block \u2014 it runs on its defaults, whatever they are`
|
|
@@ -1060,14 +1338,14 @@ var blocks = (root, config, readers, workspaces) => {
|
|
|
1060
1338
|
}
|
|
1061
1339
|
if (!declared && installed) {
|
|
1062
1340
|
return [
|
|
1063
|
-
|
|
1341
|
+
finding4(
|
|
1064
1342
|
name,
|
|
1065
1343
|
"OK",
|
|
1066
1344
|
`${name} is here but no manifest declares it \u2014 a transitive dependency this repo did not choose, so it wants no "${block}" block`
|
|
1067
1345
|
)
|
|
1068
1346
|
];
|
|
1069
1347
|
}
|
|
1070
|
-
return declared ? [
|
|
1348
|
+
return declared ? [finding4(name, "OK", `a "${block}" block, and ${name} to read it`)] : [];
|
|
1071
1349
|
});
|
|
1072
1350
|
};
|
|
1073
1351
|
var PLUGIN_DIR_RULE = "biological-architecture/no-unregistered-plugin-dir";
|
|
@@ -1083,8 +1361,8 @@ var pluginDirsOf = (level) => {
|
|
|
1083
1361
|
return { manifests: options.manifests ?? ["index.ts"], registry, roots: options.roots };
|
|
1084
1362
|
};
|
|
1085
1363
|
var pluginDirLayers = (root) => {
|
|
1086
|
-
const path =
|
|
1087
|
-
if (!
|
|
1364
|
+
const path = join7(root, ".oxlintrc.json");
|
|
1365
|
+
if (!existsSync6(path)) return [];
|
|
1088
1366
|
const layers = [];
|
|
1089
1367
|
for (const layer of layersOf(readConfig(path, root), PLUGIN_DIR_RULE)) {
|
|
1090
1368
|
const dirs = pluginDirsOf(layer.level);
|
|
@@ -1093,7 +1371,7 @@ var pluginDirLayers = (root) => {
|
|
|
1093
1371
|
return layers;
|
|
1094
1372
|
};
|
|
1095
1373
|
var layerOver = (layers, root, relative) => {
|
|
1096
|
-
const at =
|
|
1374
|
+
const at = join7(root, relative);
|
|
1097
1375
|
const inside = readdirSync3(at, { withFileTypes: true }).filter((entry) => entry.isFile()).map((entry) => `${relative}/${entry.name}`);
|
|
1098
1376
|
const paths = inside.length === 0 ? [relative] : inside;
|
|
1099
1377
|
const wrapped = layers.map((layer) => ({ files: layer.files, level: layer.dirs }));
|
|
@@ -1107,7 +1385,7 @@ var pluginDirs = (root) => {
|
|
|
1107
1385
|
const layers = pluginDirLayers(root);
|
|
1108
1386
|
if (layers.length === 0) {
|
|
1109
1387
|
return [
|
|
1110
|
-
|
|
1388
|
+
finding4(
|
|
1111
1389
|
"plugin directories",
|
|
1112
1390
|
"SKIP",
|
|
1113
1391
|
"no-unregistered-plugin-dir is not configured here, so this repo has not said where its integrations live"
|
|
@@ -1115,34 +1393,34 @@ var pluginDirs = (root) => {
|
|
|
1115
1393
|
];
|
|
1116
1394
|
}
|
|
1117
1395
|
const missing = [...new Set(layers.flatMap((layer) => layer.dirs.registry))].filter(
|
|
1118
|
-
(registry) => !
|
|
1396
|
+
(registry) => !existsSync6(join7(root, registry))
|
|
1119
1397
|
);
|
|
1120
1398
|
if (missing.length > 0) {
|
|
1121
1399
|
return missing.map(
|
|
1122
|
-
(registry) =>
|
|
1400
|
+
(registry) => finding4(registry, "FAIL", "the registry the rule names is not there")
|
|
1123
1401
|
);
|
|
1124
1402
|
}
|
|
1125
1403
|
const source = /* @__PURE__ */ new Map();
|
|
1126
1404
|
const unreachable = /* @__PURE__ */ new Map();
|
|
1127
1405
|
for (const rootDir of new Set(layers.flatMap((layer) => layer.dirs.roots))) {
|
|
1128
|
-
const at =
|
|
1129
|
-
if (!
|
|
1406
|
+
const at = join7(root, rootDir);
|
|
1407
|
+
if (!existsSync6(at)) continue;
|
|
1130
1408
|
for (const entry of readdirSync3(at, { withFileTypes: true })) {
|
|
1131
1409
|
if (!entry.isDirectory()) continue;
|
|
1132
1410
|
const relative = `${rootDir}/${entry.name}`;
|
|
1133
1411
|
const governs = layerOver(layers, root, relative);
|
|
1134
1412
|
if (governs === void 0) continue;
|
|
1135
1413
|
const key = governs.registry.join(", ");
|
|
1136
|
-
const registry = source.get(key) ?? governs.registry.map((half) =>
|
|
1414
|
+
const registry = source.get(key) ?? governs.registry.map((half) => readFileSync7(join7(root, half), "utf8")).join("\n");
|
|
1137
1415
|
source.set(key, registry);
|
|
1138
|
-
const hasManifest = governs.manifests.some((name) =>
|
|
1416
|
+
const hasManifest = governs.manifests.some((name) => existsSync6(join7(at, entry.name, name)));
|
|
1139
1417
|
if (!hasManifest || registry.includes(entry.name)) continue;
|
|
1140
1418
|
unreachable.set(key, [...unreachable.get(key) ?? [], relative]);
|
|
1141
1419
|
}
|
|
1142
1420
|
}
|
|
1143
1421
|
return [...source.keys()].toSorted().map((registry) => {
|
|
1144
1422
|
const named2 = unreachable.get(registry) ?? [];
|
|
1145
|
-
return named2.length === 0 ?
|
|
1423
|
+
return named2.length === 0 ? finding4(registry, "OK", "every directory under the declared roots is named by it") : finding4(
|
|
1146
1424
|
registry,
|
|
1147
1425
|
"FAIL",
|
|
1148
1426
|
`${named2.length} directory(ies) it never names: ${named2.join(", ")}`
|
|
@@ -1153,9 +1431,9 @@ var WORKSPACE_YAML = "pnpm-workspace.yaml";
|
|
|
1153
1431
|
var HOIST_KEY = "publicHoistPattern";
|
|
1154
1432
|
var HOIST_REPAIR = "rm -rf node_modules/.modules.yaml node_modules/.pnpm-workspace-state-v1.json && pnpm install";
|
|
1155
1433
|
var hoistPatterns = (root) => {
|
|
1156
|
-
const path =
|
|
1157
|
-
if (!
|
|
1158
|
-
const lines =
|
|
1434
|
+
const path = join7(root, WORKSPACE_YAML);
|
|
1435
|
+
if (!existsSync6(path)) return void 0;
|
|
1436
|
+
const lines = readFileSync7(path, "utf8").split("\n");
|
|
1159
1437
|
const at = lines.findIndex((line) => new RegExp(`^${HOIST_KEY}\\s*:`).test(line));
|
|
1160
1438
|
if (at < 0) return void 0;
|
|
1161
1439
|
const patterns = [];
|
|
@@ -1172,7 +1450,7 @@ var publicHoists = (root, workspaces) => {
|
|
|
1172
1450
|
const patterns = hoistPatterns(root);
|
|
1173
1451
|
if (patterns === void 0) {
|
|
1174
1452
|
return [
|
|
1175
|
-
|
|
1453
|
+
finding4(
|
|
1176
1454
|
WORKSPACE_YAML,
|
|
1177
1455
|
"SKIP",
|
|
1178
1456
|
`no ${HOIST_KEY} is declared here, so nothing claims a package should be linked at the root`
|
|
@@ -1186,21 +1464,21 @@ var publicHoists = (root, workspaces) => {
|
|
|
1186
1464
|
const shape = matching(pattern);
|
|
1187
1465
|
const hoisted = named2.filter((name) => shape.test(name));
|
|
1188
1466
|
if (hoisted.length === 0) {
|
|
1189
|
-
return
|
|
1467
|
+
return finding4(
|
|
1190
1468
|
pattern,
|
|
1191
1469
|
"SKIP",
|
|
1192
1470
|
`this ${HOIST_KEY} matches no workspace package here, so what it should have linked at the root is a question this cannot answer`
|
|
1193
1471
|
);
|
|
1194
1472
|
}
|
|
1195
|
-
const pruned = hoisted.filter((name) => !
|
|
1473
|
+
const pruned = hoisted.filter((name) => !existsSync6(join7(root, "node_modules", name)));
|
|
1196
1474
|
if (pruned.length === 0) {
|
|
1197
|
-
return
|
|
1475
|
+
return finding4(
|
|
1198
1476
|
pattern,
|
|
1199
1477
|
"OK",
|
|
1200
1478
|
`every workspace package this ${HOIST_KEY} matches is linked at the root`
|
|
1201
1479
|
);
|
|
1202
1480
|
}
|
|
1203
|
-
return
|
|
1481
|
+
return finding4(
|
|
1204
1482
|
pattern,
|
|
1205
1483
|
"FAIL",
|
|
1206
1484
|
`the ${HOIST_KEY} \`${pattern}\` has no root link for ${pruned.map((name) => `node_modules/${name}`).join(", ")} \u2014 pnpm prunes one during an unrelated add and then answers "Already up to date" over a clean git status forever. Repair: ${HOIST_REPAIR}`
|
|
@@ -1210,7 +1488,7 @@ var publicHoists = (root, workspaces) => {
|
|
|
1210
1488
|
var checkDrift = ({
|
|
1211
1489
|
readers = READERS,
|
|
1212
1490
|
root,
|
|
1213
|
-
userSettings =
|
|
1491
|
+
userSettings = join7(homedir(), SETTINGS),
|
|
1214
1492
|
workspaces
|
|
1215
1493
|
}) => {
|
|
1216
1494
|
const config = readGeonosis(root);
|
|
@@ -1236,21 +1514,21 @@ var checkDrift = ({
|
|
|
1236
1514
|
import { spawnSync as spawnSync2 } from "child_process";
|
|
1237
1515
|
import {
|
|
1238
1516
|
cpSync,
|
|
1239
|
-
existsSync as
|
|
1517
|
+
existsSync as existsSync7,
|
|
1240
1518
|
mkdirSync,
|
|
1241
1519
|
mkdtempSync,
|
|
1242
|
-
readFileSync as
|
|
1520
|
+
readFileSync as readFileSync8,
|
|
1243
1521
|
rmSync,
|
|
1244
1522
|
writeFileSync
|
|
1245
1523
|
} from "fs";
|
|
1246
1524
|
import { tmpdir } from "os";
|
|
1247
|
-
import { dirname as dirname2, join as
|
|
1525
|
+
import { dirname as dirname2, join as join8, resolve } from "path";
|
|
1248
1526
|
import { corpusOf, readManifest } from "@geonosis/lint-parity";
|
|
1249
1527
|
var OFF = /* @__PURE__ */ new Set([0, "0", "allow", "off", false]);
|
|
1250
1528
|
var severityOf = (level) => Array.isArray(level) ? level[0] : level;
|
|
1251
1529
|
var enabledRulesOf = (rules, plugin) => Object.keys(rules).filter((id) => id.startsWith(`${plugin}/`) && !OFF.has(severityOf(rules[id]))).toSorted();
|
|
1252
1530
|
var passes = (findings) => !findings.some((one) => one.verdict === "FAIL" || one.verdict === "UNJUDGED");
|
|
1253
|
-
var
|
|
1531
|
+
var finding5 = (subject, verdict, message) => ({
|
|
1254
1532
|
check: "exercised",
|
|
1255
1533
|
message,
|
|
1256
1534
|
subject,
|
|
@@ -1262,9 +1540,9 @@ var refusal = (error) => {
|
|
|
1262
1540
|
return said2.length > LIMIT ? `${said2.slice(0, LIMIT)}\u2026` : said2;
|
|
1263
1541
|
};
|
|
1264
1542
|
var reasonFrom = (config, oxlint) => {
|
|
1265
|
-
const dir = mkdtempSync(
|
|
1543
|
+
const dir = mkdtempSync(join8(tmpdir(), "geonosis-doctor-why-"));
|
|
1266
1544
|
try {
|
|
1267
|
-
const probe =
|
|
1545
|
+
const probe = join8(dir, "probe.tsx");
|
|
1268
1546
|
writeFileSync(probe, "export const probe = 1\n");
|
|
1269
1547
|
const run = spawnSync2(
|
|
1270
1548
|
oxlint,
|
|
@@ -1354,8 +1632,8 @@ var throughProbes = ({
|
|
|
1354
1632
|
}) => {
|
|
1355
1633
|
const refused = /* @__PURE__ */ new Map();
|
|
1356
1634
|
const placed = /* @__PURE__ */ new Set();
|
|
1357
|
-
const dir = mkdtempSync(
|
|
1358
|
-
const here =
|
|
1635
|
+
const dir = mkdtempSync(join8(tmpdir(), "geonosis-doctor-probe-"));
|
|
1636
|
+
const here = join8(dir, "corpus");
|
|
1359
1637
|
try {
|
|
1360
1638
|
cpSync(corpus, here, { recursive: true });
|
|
1361
1639
|
for (const rule of silent) {
|
|
@@ -1392,7 +1670,7 @@ var throughProbes = ({
|
|
|
1392
1670
|
mounted = rehomed;
|
|
1393
1671
|
}
|
|
1394
1672
|
for (const file of mounted) {
|
|
1395
|
-
const at2 =
|
|
1673
|
+
const at2 = join8(here, file.path);
|
|
1396
1674
|
if (placed.has(at2)) continue;
|
|
1397
1675
|
placed.add(at2);
|
|
1398
1676
|
mkdirSync(dirname2(at2), { recursive: true });
|
|
@@ -1405,12 +1683,12 @@ var throughProbes = ({
|
|
|
1405
1683
|
refused.set(rule, String(error.message));
|
|
1406
1684
|
}
|
|
1407
1685
|
}
|
|
1408
|
-
const probeConfig = JSON.parse(
|
|
1686
|
+
const probeConfig = JSON.parse(readFileSync8(config.path, "utf8"));
|
|
1409
1687
|
const configDir = dirname2(config.path);
|
|
1410
1688
|
probeConfig.jsPlugins = (probeConfig.jsPlugins ?? []).map(
|
|
1411
1689
|
(spec) => spec.startsWith(".") || spec.startsWith("/") ? resolve(configDir, spec) : packageDirOf(resolveFrom(configDir, spec), spec)
|
|
1412
1690
|
);
|
|
1413
|
-
const at =
|
|
1691
|
+
const at = join8(here, ".oxlintrc-geonosis-probe.json");
|
|
1414
1692
|
writeFileSync(at, JSON.stringify(probeConfig, null, 2));
|
|
1415
1693
|
const run = spawnSync2(
|
|
1416
1694
|
oxlint,
|
|
@@ -1440,14 +1718,14 @@ var checkExercised = async ({
|
|
|
1440
1718
|
repoCorpus,
|
|
1441
1719
|
root
|
|
1442
1720
|
}) => {
|
|
1443
|
-
const said2 = (verdict, message) =>
|
|
1444
|
-
if (repoCorpus !== void 0 && !
|
|
1721
|
+
const said2 = (verdict, message) => finding5(config.relative, verdict, message);
|
|
1722
|
+
if (repoCorpus !== void 0 && !existsSync7(repoCorpus)) {
|
|
1445
1723
|
return said2(
|
|
1446
1724
|
"FAIL",
|
|
1447
1725
|
`geonosis.json declares a reach corpus at ${relativeToRoot(root, repoCorpus)} and there is nothing there \u2014 a corpus that cannot be read is a claim, not evidence`
|
|
1448
1726
|
);
|
|
1449
1727
|
}
|
|
1450
|
-
if (!
|
|
1728
|
+
if (!existsSync7(corpus)) {
|
|
1451
1729
|
return said2(
|
|
1452
1730
|
"SKIP",
|
|
1453
1731
|
`the plugin loaded from here ships no corpus at ${relativeToRoot(root, corpus)} \u2014 nothing declares which rules it can be evidence about`
|
|
@@ -1520,7 +1798,7 @@ var checkExercised = async ({
|
|
|
1520
1798
|
);
|
|
1521
1799
|
}
|
|
1522
1800
|
const unplaceable = inert.map((rule) => `${rule}: ${probed.refused.get(rule) ?? ""}`);
|
|
1523
|
-
const kitNote = unprobed.length === 0 || loadedProbes === null ? "" : `the loaded plugin ships no probe for ${unprobed.length === 1 ? "this enabled rule" : `${unprobed.length} enabled rules`} \u2014 the kit's omission, not this repo's (geonosis #131): ${unprobed.join(", ")}`;
|
|
1801
|
+
const kitNote = unprobed.length === 0 || loadedProbes === null ? "" : `the loaded plugin ships no probe for ${unprobed.length === 1 ? "this enabled rule" : `${unprobed.length} enabled rules`}, so the question cannot be asked here at all \u2014 the kit's omission, not this repo's, and nothing in this tree is the fix (geonosis #131): ${unprobed.join(", ")}`;
|
|
1524
1802
|
const unknowable = loadedProbes === null ? unprobed.map(
|
|
1525
1803
|
(rule) => `${rule} declares no probe, so ${optionSetsOf(config, rule).every((options) => options.length === 0) ? "its scope" : under(config, rule)} does not reach the corpus`
|
|
1526
1804
|
) : [];
|
|
@@ -1530,7 +1808,7 @@ var checkExercised = async ({
|
|
|
1530
1808
|
named([...unknowable, ...unplaceable]) + (kitNote === "" ? "" : ` \u2014 and ${kitNote}`)
|
|
1531
1809
|
);
|
|
1532
1810
|
}
|
|
1533
|
-
if (kitNote !== "") return said2("
|
|
1811
|
+
if (kitNote !== "") return said2("SKIP", kitNote);
|
|
1534
1812
|
const through = exercised.length === 1 ? "1 through its declared probe under this repo\u2019s options" : `${exercised.length} through their declared probes under this repo\u2019s options`;
|
|
1535
1813
|
return said2(
|
|
1536
1814
|
"OK",
|
|
@@ -1539,12 +1817,14 @@ var checkExercised = async ({
|
|
|
1539
1817
|
};
|
|
1540
1818
|
|
|
1541
1819
|
// src/envelope.ts
|
|
1542
|
-
import { existsSync as
|
|
1543
|
-
import { join as
|
|
1820
|
+
import { existsSync as existsSync8, readdirSync as readdirSync4, readFileSync as readFileSync9 } from "fs";
|
|
1821
|
+
import { join as join9 } from "path";
|
|
1544
1822
|
var ENVELOPES_DIR = ".geonosis/envelopes";
|
|
1545
|
-
var
|
|
1823
|
+
var THIS_TOOL = "doctor";
|
|
1824
|
+
var OWN = `${THIS_TOOL}.json`;
|
|
1825
|
+
var NO_ENVELOPES = "no .geonosis/envelopes/*.json \u2014 the tools write one per run, so an absent envelope is a run nobody has made here yet, and it is not a balanced one (this run\u2019s own doctor.json is not one of them: it is written after these checks, and balanced at write time)";
|
|
1546
1826
|
var isRecord2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1547
|
-
var
|
|
1827
|
+
var finding6 = (verdict, subject, message) => ({
|
|
1548
1828
|
check: "envelope",
|
|
1549
1829
|
message,
|
|
1550
1830
|
subject,
|
|
@@ -1553,17 +1833,17 @@ var finding5 = (verdict, subject, message) => ({
|
|
|
1553
1833
|
var lengthOf = (value) => Array.isArray(value) ? value.length : void 0;
|
|
1554
1834
|
var NEXT = "Next: re-run the tool that wrote it and read the numbers it prints \u2014 a run that has lost count of its own inputs is a bug in that tool, not in this tree";
|
|
1555
1835
|
var judge = (subject, name, parsed) => {
|
|
1556
|
-
if (!isRecord2(parsed)) return
|
|
1836
|
+
if (!isRecord2(parsed)) return finding6("FAIL", subject, `is not an object. ${NEXT}`);
|
|
1557
1837
|
const tool = parsed["tool"];
|
|
1558
1838
|
if (typeof tool !== "string" || tool.trim() === "") {
|
|
1559
|
-
return
|
|
1839
|
+
return finding6(
|
|
1560
1840
|
"FAIL",
|
|
1561
1841
|
subject,
|
|
1562
1842
|
`names no tool, so nothing here says which run it is about. ${NEXT}`
|
|
1563
1843
|
);
|
|
1564
1844
|
}
|
|
1565
1845
|
if (tool !== name) {
|
|
1566
|
-
return
|
|
1846
|
+
return finding6(
|
|
1567
1847
|
"FAIL",
|
|
1568
1848
|
subject,
|
|
1569
1849
|
`is written by "${tool}", not "${name}" \u2014 a tool writing another tool's envelope leaves both of their numbers unattributable. ${NEXT}`
|
|
@@ -1571,7 +1851,7 @@ var judge = (subject, name, parsed) => {
|
|
|
1571
1851
|
}
|
|
1572
1852
|
const version = parsed["version"];
|
|
1573
1853
|
if (typeof version !== "string" || version.trim() === "") {
|
|
1574
|
-
return
|
|
1854
|
+
return finding6(
|
|
1575
1855
|
"FAIL",
|
|
1576
1856
|
subject,
|
|
1577
1857
|
`${tool}: names no version, so nothing dates this run and a stale envelope reads exactly like a fresh one. ${NEXT}`
|
|
@@ -1582,279 +1862,44 @@ var judge = (subject, name, parsed) => {
|
|
|
1582
1862
|
const refused = lengthOf(parsed["refused"]);
|
|
1583
1863
|
const excused = lengthOf(parsed["excused"]);
|
|
1584
1864
|
if (typeof considered !== "number" || typeof read !== "number" || refused === void 0 || excused === void 0) {
|
|
1585
|
-
return
|
|
1865
|
+
return finding6(
|
|
1586
1866
|
"FAIL",
|
|
1587
1867
|
subject,
|
|
1588
1868
|
`${tool}: has no considered/read/refused/excused to check \u2014 the four numbers ARE the envelope, and a file without them measures nothing. ${NEXT}`
|
|
1589
1869
|
);
|
|
1590
1870
|
}
|
|
1591
1871
|
const accounted = read + refused + excused;
|
|
1592
|
-
return considered === accounted ?
|
|
1872
|
+
return considered === accounted ? finding6(
|
|
1593
1873
|
"OK",
|
|
1594
1874
|
subject,
|
|
1595
1875
|
`${tool} considered ${considered} and accounts for all of them \u2014 ${read} read + ${refused} refused + ${excused} excused`
|
|
1596
|
-
) :
|
|
1876
|
+
) : finding6(
|
|
1597
1877
|
"FAIL",
|
|
1598
1878
|
subject,
|
|
1599
1879
|
`${tool}: considered ${considered} but accounts for ${accounted} \u2014 ${read} read + ${refused} refused + ${excused} excused. It reported on fewer things than it was handed, and every verdict it printed is over the smaller number. ${NEXT}`
|
|
1600
1880
|
);
|
|
1601
1881
|
};
|
|
1602
1882
|
var checkEnvelopes = ({ root }) => {
|
|
1603
|
-
const dir =
|
|
1604
|
-
const files =
|
|
1605
|
-
if (files.length === 0) return [
|
|
1883
|
+
const dir = join9(root, ENVELOPES_DIR);
|
|
1884
|
+
const files = existsSync8(dir) ? readdirSync4(dir).filter((name) => name.endsWith(".json") && name !== OWN).toSorted() : [];
|
|
1885
|
+
if (files.length === 0) return [finding6("SKIP", ENVELOPES_DIR, NO_ENVELOPES)];
|
|
1606
1886
|
return files.map((name) => {
|
|
1607
1887
|
const subject = `${ENVELOPES_DIR}/${name}`;
|
|
1608
1888
|
let parsed;
|
|
1609
1889
|
try {
|
|
1610
|
-
parsed = JSON.parse(
|
|
1890
|
+
parsed = JSON.parse(readFileSync9(join9(dir, name), "utf8"));
|
|
1611
1891
|
} catch (error) {
|
|
1612
|
-
return
|
|
1892
|
+
return finding6("FAIL", subject, `is not readable JSON: ${error.message}. ${NEXT}`);
|
|
1613
1893
|
}
|
|
1614
1894
|
return judge(subject, name.replace(/\.json$/, ""), parsed);
|
|
1615
1895
|
});
|
|
1616
1896
|
};
|
|
1617
1897
|
|
|
1618
|
-
// src/repo-corpus.ts
|
|
1619
|
-
import { existsSync as existsSync7, readFileSync as readFileSync8 } from "fs";
|
|
1620
|
-
import { join as join8 } from "path";
|
|
1621
|
-
var GEONOSIS_FILE = "geonosis.json";
|
|
1622
|
-
var repoCorpusOf = (root) => {
|
|
1623
|
-
const path = join8(root, GEONOSIS_FILE);
|
|
1624
|
-
if (!existsSync7(path)) return void 0;
|
|
1625
|
-
try {
|
|
1626
|
-
const parsed = JSON.parse(readFileSync8(path, "utf8"));
|
|
1627
|
-
const declared = parsed.doctor?.corpus;
|
|
1628
|
-
return typeof declared === "string" && declared !== "" ? join8(root, declared) : void 0;
|
|
1629
|
-
} catch {
|
|
1630
|
-
return void 0;
|
|
1631
|
-
}
|
|
1632
|
-
};
|
|
1633
|
-
|
|
1634
|
-
// src/group.ts
|
|
1635
|
-
import { existsSync as existsSync8, readFileSync as readFileSync9 } from "fs";
|
|
1636
|
-
import { join as join9 } from "path";
|
|
1637
|
-
var FIXED_GROUP = [
|
|
1638
|
-
"@geonosis/cli",
|
|
1639
|
-
"@geonosis/doctor",
|
|
1640
|
-
"@geonosis/evals",
|
|
1641
|
-
"@geonosis/integrations",
|
|
1642
|
-
"@geonosis/ledger",
|
|
1643
|
-
"@geonosis/lint-parity",
|
|
1644
|
-
"@geonosis/mcp",
|
|
1645
|
-
"@geonosis/observability",
|
|
1646
|
-
"@geonosis/oxlint-plugin-biological-architecture",
|
|
1647
|
-
"@geonosis/policy",
|
|
1648
|
-
"@geonosis/rails",
|
|
1649
|
-
"@geonosis/ratchet",
|
|
1650
|
-
"@geonosis/release",
|
|
1651
|
-
"@geonosis/review",
|
|
1652
|
-
"@geonosis/testbed",
|
|
1653
|
-
"@geonosis/themekit",
|
|
1654
|
-
"@geonosis/verify",
|
|
1655
|
-
"@geonosis/verify-arch",
|
|
1656
|
-
"@geonosis/visual-diff",
|
|
1657
|
-
"@geonosis/walk",
|
|
1658
|
-
"create-geonosis",
|
|
1659
|
-
"geonosis"
|
|
1660
|
-
];
|
|
1661
|
-
var KIT_GROUP = { name: "@geonosis fixed group", packages: FIXED_GROUP };
|
|
1662
|
-
var declaredGroupsOf = (root) => {
|
|
1663
|
-
const path = join9(root, GEONOSIS_FILE);
|
|
1664
|
-
if (!existsSync8(path)) return void 0;
|
|
1665
|
-
let parsed;
|
|
1666
|
-
try {
|
|
1667
|
-
parsed = JSON.parse(readFileSync9(path, "utf8"));
|
|
1668
|
-
} catch {
|
|
1669
|
-
return void 0;
|
|
1670
|
-
}
|
|
1671
|
-
const declared = parsed.doctor?.groups;
|
|
1672
|
-
if (declared === void 0) return void 0;
|
|
1673
|
-
if (!Array.isArray(declared) || declared.length === 0) {
|
|
1674
|
-
throw new DoctorError(
|
|
1675
|
-
`${GEONOSIS_FILE} declares doctor.groups and names no group in it \u2014 say which packages must move together, or remove the key and get the kit's own group`
|
|
1676
|
-
);
|
|
1677
|
-
}
|
|
1678
|
-
return declared.map((one, at) => {
|
|
1679
|
-
const group = one;
|
|
1680
|
-
if (typeof group.name !== "string" || !Array.isArray(group.packages) || group.packages.length < 2) {
|
|
1681
|
-
throw new DoctorError(
|
|
1682
|
-
`${GEONOSIS_FILE} doctor.groups[${at}] needs a name and at least two packages \u2014 one package cannot disagree with itself`
|
|
1683
|
-
);
|
|
1684
|
-
}
|
|
1685
|
-
return { name: group.name, packages: group.packages };
|
|
1686
|
-
});
|
|
1687
|
-
};
|
|
1688
|
-
var labelOf = (workspace) => workspace.relative === "" ? "root" : workspace.relative;
|
|
1689
|
-
var versionOf = (dir, name) => {
|
|
1690
|
-
let entry;
|
|
1691
|
-
try {
|
|
1692
|
-
entry = resolveFrom(dir, name);
|
|
1693
|
-
} catch {
|
|
1694
|
-
return { kind: "absent" };
|
|
1695
|
-
}
|
|
1696
|
-
try {
|
|
1697
|
-
const manifest = JSON.parse(
|
|
1698
|
-
readFileSync9(join9(packageDirOf(entry, name), "package.json"), "utf8")
|
|
1699
|
-
);
|
|
1700
|
-
return typeof manifest.version === "string" ? { kind: "read", version: manifest.version } : { kind: "unreadable", why: "its package.json declares no version" };
|
|
1701
|
-
} catch (error) {
|
|
1702
|
-
return { kind: "unreadable", why: String(error.message).split("\n")[0] ?? "" };
|
|
1703
|
-
}
|
|
1704
|
-
};
|
|
1705
|
-
var finding6 = (subject, verdict, message) => ({
|
|
1706
|
-
check: "group",
|
|
1707
|
-
message,
|
|
1708
|
-
subject,
|
|
1709
|
-
verdict
|
|
1710
|
-
});
|
|
1711
|
-
var said = (versions) => [...versions.entries()].map(([version, from]) => `${version} (${from.join(", ")})`).join("; ");
|
|
1712
|
-
var repoWide = (name, found) => {
|
|
1713
|
-
const versions = /* @__PURE__ */ new Map();
|
|
1714
|
-
for (const one of found) versions.set(one.version, [...versions.get(one.version) ?? [], one.at]);
|
|
1715
|
-
if (versions.size === 1) return void 0;
|
|
1716
|
-
return finding6(
|
|
1717
|
-
name,
|
|
1718
|
-
"FAIL",
|
|
1719
|
-
`${versions.size} versions in one tree \u2014 ${said(versions)}. They are published as one number, so a tree holding two is a tree where one workspace is running code another has already replaced; remove the nested copies and reinstall`
|
|
1720
|
-
);
|
|
1721
|
-
};
|
|
1722
|
-
var perWorkspace = (group, at, found) => {
|
|
1723
|
-
if (new Set(found.map((one) => one.version)).size === 1) return void 0;
|
|
1724
|
-
const listed = found.map((one) => `${one.name} ${one.version}`).join(", ");
|
|
1725
|
-
return finding6(
|
|
1726
|
-
at,
|
|
1727
|
-
"FAIL",
|
|
1728
|
-
`${group.name} does not hold together here \u2014 ${listed}. Every member is cut on one version, so a workspace resolving two of them is a bump that landed halfway`
|
|
1729
|
-
);
|
|
1730
|
-
};
|
|
1731
|
-
var DOORS = ["@geonosis/cli", "geonosis"];
|
|
1732
|
-
var manifestOf = (dir, name) => {
|
|
1733
|
-
try {
|
|
1734
|
-
return JSON.parse(
|
|
1735
|
-
readFileSync9(join9(packageDirOf(resolveFrom(dir, name), name), "package.json"), "utf8")
|
|
1736
|
-
);
|
|
1737
|
-
} catch {
|
|
1738
|
-
return void 0;
|
|
1739
|
-
}
|
|
1740
|
-
};
|
|
1741
|
-
var binNamesOf = (manifest, name) => {
|
|
1742
|
-
const declared = manifest?.bin;
|
|
1743
|
-
return typeof declared === "string" ? [name.replace(/^@[^/]+\//, "")] : Object.keys(declared ?? {});
|
|
1744
|
-
};
|
|
1745
|
-
var declaredIn2 = (manifest) => [
|
|
1746
|
-
...new Set(
|
|
1747
|
-
[
|
|
1748
|
-
manifest.dependencies,
|
|
1749
|
-
manifest.devDependencies,
|
|
1750
|
-
manifest.optionalDependencies,
|
|
1751
|
-
manifest.peerDependencies
|
|
1752
|
-
].flatMap((block) => Object.keys(block ?? {}))
|
|
1753
|
-
)
|
|
1754
|
-
];
|
|
1755
|
-
var rootDeclarations = (root, workspaces) => {
|
|
1756
|
-
const here = workspaces.find((one) => one.relative === "");
|
|
1757
|
-
if (here === void 0) return [];
|
|
1758
|
-
const declared = declaredIn2(here.manifest);
|
|
1759
|
-
const door = DOORS.find((name) => declared.includes(name));
|
|
1760
|
-
if (door === void 0) return [];
|
|
1761
|
-
const owned = new Set(
|
|
1762
|
-
[door, ...DOORS].flatMap((name) => {
|
|
1763
|
-
const manifest = manifestOf(root, name);
|
|
1764
|
-
return manifest === void 0 ? [] : Object.keys(manifest.dependencies ?? {});
|
|
1765
|
-
})
|
|
1766
|
-
);
|
|
1767
|
-
const callers = [
|
|
1768
|
-
...Object.values(here.manifest.scripts ?? {}),
|
|
1769
|
-
...hookLines(root).map((one) => one.line)
|
|
1770
|
-
].join("\n");
|
|
1771
|
-
const spare = declared.filter(
|
|
1772
|
-
(name) => !DOORS.includes(name) && owned.has(name) && !binNamesOf(manifestOf(root, name), name).some(
|
|
1773
|
-
(bin) => new RegExp(`(?:^|[\\s;&|(/])${bin}(?:\\s|$)`).test(callers)
|
|
1774
|
-
)
|
|
1775
|
-
);
|
|
1776
|
-
if (spare.length === 0) {
|
|
1777
|
-
return [
|
|
1778
|
-
finding6(
|
|
1779
|
-
"package.json",
|
|
1780
|
-
"OK",
|
|
1781
|
-
`every @geonosis package this root declares is ${door} or a bin its own scripts call by name`
|
|
1782
|
-
)
|
|
1783
|
-
];
|
|
1784
|
-
}
|
|
1785
|
-
return spare.map(
|
|
1786
|
-
(name) => finding6(
|
|
1787
|
-
name,
|
|
1788
|
-
"WARN",
|
|
1789
|
-
`the root declares it and no root script calls its bin \u2014 ${door} already brings it, so this second declaration is a version that can disagree with the door's, and every tool that asks what is used here reads it as unused. Drop it from the root, or declare it in the workspace whose code imports it`
|
|
1790
|
-
)
|
|
1791
|
-
);
|
|
1792
|
-
};
|
|
1793
|
-
var checkGroup = ({
|
|
1794
|
-
groups,
|
|
1795
|
-
root,
|
|
1796
|
-
workspaces
|
|
1797
|
-
}) => {
|
|
1798
|
-
const findings = [...rootDeclarations(root, workspaces)];
|
|
1799
|
-
for (const group of groups ?? [KIT_GROUP]) {
|
|
1800
|
-
const found = [];
|
|
1801
|
-
for (const workspace of workspaces) {
|
|
1802
|
-
const at = labelOf(workspace);
|
|
1803
|
-
const here = [];
|
|
1804
|
-
for (const name of group.packages) {
|
|
1805
|
-
const reading = versionOf(workspace.dir, name);
|
|
1806
|
-
if (reading.kind === "read") here.push({ at, name, version: reading.version });
|
|
1807
|
-
if (reading.kind === "unreadable") {
|
|
1808
|
-
findings.push(
|
|
1809
|
-
finding6(
|
|
1810
|
-
`${at} \u2192 ${name}`,
|
|
1811
|
-
"UNJUDGED",
|
|
1812
|
-
`it resolves from here and ${reading.why} \u2014 this copy could be any version, so the group cannot be said to hold or not to hold`
|
|
1813
|
-
)
|
|
1814
|
-
);
|
|
1815
|
-
}
|
|
1816
|
-
}
|
|
1817
|
-
const split2 = here.length > 0 ? perWorkspace(group, at, here) : void 0;
|
|
1818
|
-
if (split2 !== void 0) findings.push(split2);
|
|
1819
|
-
found.push(...here);
|
|
1820
|
-
}
|
|
1821
|
-
if (found.length === 0) {
|
|
1822
|
-
findings.push(
|
|
1823
|
-
finding6(
|
|
1824
|
-
group.name,
|
|
1825
|
-
"SKIP",
|
|
1826
|
-
`no workspace under ${root} resolves any of ${group.packages.join(", ")}, so nothing here versions together`
|
|
1827
|
-
)
|
|
1828
|
-
);
|
|
1829
|
-
continue;
|
|
1830
|
-
}
|
|
1831
|
-
const names = [...new Set(found.map((one) => one.name))].toSorted();
|
|
1832
|
-
const split = names.flatMap((name) => {
|
|
1833
|
-
const line = repoWide(
|
|
1834
|
-
name,
|
|
1835
|
-
found.filter((one) => one.name === name)
|
|
1836
|
-
);
|
|
1837
|
-
return line === void 0 ? [] : [line];
|
|
1838
|
-
});
|
|
1839
|
-
findings.push(...split);
|
|
1840
|
-
if (split.length === 0) {
|
|
1841
|
-
const versions = [...new Set(found.map((one) => one.version))];
|
|
1842
|
-
findings.push(
|
|
1843
|
-
finding6(
|
|
1844
|
-
group.name,
|
|
1845
|
-
"OK",
|
|
1846
|
-
`${names.length} of ${group.packages.length} installed, at ${versions.join(", ")}, one copy each across ${new Set(found.map((one) => one.at)).size} workspaces`
|
|
1847
|
-
)
|
|
1848
|
-
);
|
|
1849
|
-
}
|
|
1850
|
-
}
|
|
1851
|
-
return findings;
|
|
1852
|
-
};
|
|
1853
|
-
|
|
1854
1898
|
// src/loaded.ts
|
|
1855
1899
|
import { readFileSync as readFileSync10 } from "fs";
|
|
1856
1900
|
import { join as join10, sep as sep3 } from "path";
|
|
1857
1901
|
var SCOPE = "@geonosis/";
|
|
1902
|
+
var NOT_THE_SCOPE_DIRECTORY = "Deleting only the scope directory inside that node_modules is a repair no pnpm install undoes \u2014 the tree is then missing the package and every install stays green.";
|
|
1858
1903
|
var BLOCKS = [
|
|
1859
1904
|
"dependencies",
|
|
1860
1905
|
"devDependencies",
|
|
@@ -1966,7 +2011,7 @@ var oneConfig = async ({
|
|
|
1966
2011
|
}
|
|
1967
2012
|
return held ? said2("OK", `loaded ${loaded.version} = declared ${declared.spec} (${declared.at})`) : said2(
|
|
1968
2013
|
"FAIL",
|
|
1969
|
-
`loaded ${loaded.version}, declared ${declared.spec} (${declared.at}) \u2014 a nested copy at ${loaded.at}.
|
|
2014
|
+
`loaded ${loaded.version}, declared ${declared.spec} (${declared.at}) \u2014 a nested copy at ${loaded.at}. Run \`geonosis update --to ${declared.spec}\`: it removes the WHOLE node_modules of every non-root workspace carrying one, never the root's, and reinstalls. ${NOT_THE_SCOPE_DIRECTORY} The linter is not running what the tree declares until then`
|
|
1970
2015
|
);
|
|
1971
2016
|
};
|
|
1972
2017
|
var labelOf2 = (workspace) => workspace.relative === "" ? "root" : workspace.relative;
|
|
@@ -2373,9 +2418,8 @@ var declaredIn3 = (manifest) => new Set(
|
|
|
2373
2418
|
].flatMap((block) => Object.keys(block ?? {}))
|
|
2374
2419
|
);
|
|
2375
2420
|
var holds3 = (parent, child) => child === parent || child.startsWith(`${parent}${sep4}`);
|
|
2376
|
-
var
|
|
2377
|
-
|
|
2378
|
-
);
|
|
2421
|
+
var labelOf3 = (workspace) => workspace.relative === "" ? "root" : workspace.relative;
|
|
2422
|
+
var governedBy = (dir, workspaces) => workspaces.filter((one) => holds3(one.dir, dir) || holds3(dir, one.dir));
|
|
2379
2423
|
var enabledHere2 = (config, plugin) => [
|
|
2380
2424
|
.../* @__PURE__ */ new Set([
|
|
2381
2425
|
...enabledRulesOf(config.rules, plugin),
|
|
@@ -2387,18 +2431,20 @@ var checkEngines = async ({
|
|
|
2387
2431
|
entry,
|
|
2388
2432
|
workspaces
|
|
2389
2433
|
}) => {
|
|
2390
|
-
const
|
|
2391
|
-
if (
|
|
2434
|
+
const plugin = await presumptionsOf(entry).catch(() => void 0);
|
|
2435
|
+
if (plugin === void 0 || plugin.namespace === "" || Object.keys(plugin.presumed).length === 0) {
|
|
2392
2436
|
return [];
|
|
2393
2437
|
}
|
|
2394
|
-
const
|
|
2395
|
-
|
|
2396
|
-
|
|
2438
|
+
const governed = governedBy(config.dir, workspaces);
|
|
2439
|
+
const declared = new Set(governed.flatMap((one) => [...declaredIn3(one.manifest)]));
|
|
2440
|
+
const asked = governed.map(labelOf3).join(", ");
|
|
2441
|
+
return enabledHere2(config, plugin.namespace).flatMap((rule) => {
|
|
2442
|
+
const presumes = plugin.presumed[rule.slice(plugin.namespace.length + 1)];
|
|
2397
2443
|
if (presumes === void 0 || presumes.packages.some((name) => declared.has(name))) return [];
|
|
2398
2444
|
return [
|
|
2399
2445
|
{
|
|
2400
2446
|
check: "exercised",
|
|
2401
|
-
message: `it presumes ${presumes.engine}, and
|
|
2447
|
+
message: `it presumes ${presumes.engine}, and none of the manifests this config governs (${asked}) declares ${presumes.packages.join(" or ")} \u2014 enabled here it has no possible finding, which reads exactly like a clean tree. Drop it from this config, or say which package brings the engine`,
|
|
2402
2448
|
subject: `${config.relative} \u2192 ${rule}`,
|
|
2403
2449
|
verdict: "WARN"
|
|
2404
2450
|
}
|
|
@@ -2552,6 +2598,15 @@ var missingOption = (error) => {
|
|
|
2552
2598
|
const named2 = error.option;
|
|
2553
2599
|
return typeof named2 === "string" ? named2 : HEADER.exec(String(error.message))?.[1];
|
|
2554
2600
|
};
|
|
2601
|
+
var refusesBare = (rule) => {
|
|
2602
|
+
try {
|
|
2603
|
+
rule.create({ options: [], report: () => {
|
|
2604
|
+
} });
|
|
2605
|
+
return false;
|
|
2606
|
+
} catch (error) {
|
|
2607
|
+
return missingOption(error) !== void 0;
|
|
2608
|
+
}
|
|
2609
|
+
};
|
|
2555
2610
|
var configured = (config, namespace) => [config.rules, ...config.overrides.map((one) => one.rules)].flatMap(
|
|
2556
2611
|
(rules) => enabledRulesOf(rules, namespace).map((id) => [id, optionsOf2(rules[id])])
|
|
2557
2612
|
);
|
|
@@ -2563,26 +2618,37 @@ var checkRequiredOptions = async ({
|
|
|
2563
2618
|
const namespace = loaded?.default?.meta?.name;
|
|
2564
2619
|
const rules = loaded?.default?.rules;
|
|
2565
2620
|
if (typeof namespace !== "string" || namespace === "" || rules === void 0) return [];
|
|
2566
|
-
|
|
2621
|
+
const enabled = configured(config, namespace);
|
|
2622
|
+
if (enabled.length === 0) return [];
|
|
2623
|
+
const missing = [];
|
|
2624
|
+
let gated = 0;
|
|
2625
|
+
for (const [id, options] of enabled) {
|
|
2567
2626
|
const rule = rules[id.slice(namespace.length + 1)];
|
|
2568
|
-
if (rule === void 0)
|
|
2627
|
+
if (rule === void 0) continue;
|
|
2628
|
+
if (refusesBare(rule)) gated += 1;
|
|
2569
2629
|
try {
|
|
2570
2630
|
rule.create({ options, report: () => {
|
|
2571
2631
|
} });
|
|
2572
|
-
return [];
|
|
2573
2632
|
} catch (error) {
|
|
2574
2633
|
const option = missingOption(error);
|
|
2575
|
-
if (option === void 0)
|
|
2576
|
-
|
|
2577
|
-
|
|
2578
|
-
|
|
2579
|
-
|
|
2580
|
-
|
|
2581
|
-
|
|
2582
|
-
}
|
|
2583
|
-
];
|
|
2634
|
+
if (option === void 0) continue;
|
|
2635
|
+
missing.push({
|
|
2636
|
+
check: "loaded",
|
|
2637
|
+
message: `it is enabled here with no \`${option}\`, and the rule refuses to be constructed without one \u2014 oxlint stops the whole run at load, linting nothing. Configure \`${option}\`, or turn the rule off`,
|
|
2638
|
+
subject: `${config.relative} \u2192 ${id}`,
|
|
2639
|
+
verdict: "FAIL"
|
|
2640
|
+
});
|
|
2584
2641
|
}
|
|
2585
|
-
}
|
|
2642
|
+
}
|
|
2643
|
+
if (missing.length > 0) return missing;
|
|
2644
|
+
return [
|
|
2645
|
+
{
|
|
2646
|
+
check: "loaded",
|
|
2647
|
+
message: `${gated} rules require options, ${gated} carry them`,
|
|
2648
|
+
subject: config.relative,
|
|
2649
|
+
verdict: "OK"
|
|
2650
|
+
}
|
|
2651
|
+
];
|
|
2586
2652
|
};
|
|
2587
2653
|
|
|
2588
2654
|
// src/doctor.ts
|
|
@@ -2611,7 +2677,7 @@ var exercisedOf = ({
|
|
|
2611
2677
|
];
|
|
2612
2678
|
}
|
|
2613
2679
|
const own = repoCorpus !== void 0 && config.relative === CONFIG_FILE ? repoCorpus : void 0;
|
|
2614
|
-
const [reach, engines
|
|
2680
|
+
const [reach, engines] = await Promise.all([
|
|
2615
2681
|
checkExercised({
|
|
2616
2682
|
config,
|
|
2617
2683
|
corpus,
|
|
@@ -2622,15 +2688,28 @@ var exercisedOf = ({
|
|
|
2622
2688
|
}),
|
|
2623
2689
|
// #159: the rules whose engine this tree has not got. Beside the reach line rather than
|
|
2624
2690
|
// inside it — one is about the corpus, the other about this repo's own manifests.
|
|
2625
|
-
checkEngines({ config, entry, workspaces })
|
|
2626
|
-
// #202: and the rules this config enables without an option they require, which the
|
|
2627
|
-
// lint can only report as a run it could not make.
|
|
2628
|
-
checkRequiredOptions({ config, entry })
|
|
2691
|
+
checkEngines({ config, entry, workspaces })
|
|
2629
2692
|
]);
|
|
2630
|
-
return [reach, ...engines
|
|
2693
|
+
return [reach, ...engines];
|
|
2631
2694
|
})
|
|
2632
2695
|
)
|
|
2633
2696
|
);
|
|
2697
|
+
var requiredOptionsOf = async (configs) => {
|
|
2698
|
+
const found = await Promise.all(
|
|
2699
|
+
configs.flatMap(
|
|
2700
|
+
(config) => config.jsPlugins.filter((name) => name.startsWith(SCOPE)).map(async (specifier) => {
|
|
2701
|
+
let entry;
|
|
2702
|
+
try {
|
|
2703
|
+
entry = resolveFrom(config.dir, specifier);
|
|
2704
|
+
} catch {
|
|
2705
|
+
return [];
|
|
2706
|
+
}
|
|
2707
|
+
return checkRequiredOptions({ config, entry });
|
|
2708
|
+
})
|
|
2709
|
+
)
|
|
2710
|
+
);
|
|
2711
|
+
return found.flat();
|
|
2712
|
+
};
|
|
2634
2713
|
var skip = (message) => [
|
|
2635
2714
|
{ check: "baseline", message, subject: RATCHET_FILE, verdict: "SKIP" }
|
|
2636
2715
|
];
|
|
@@ -2668,7 +2747,13 @@ var runDoctor = async ({
|
|
|
2668
2747
|
}
|
|
2669
2748
|
const asked = (check) => only === void 0 || only.includes(check);
|
|
2670
2749
|
const runs = [
|
|
2671
|
-
[
|
|
2750
|
+
[
|
|
2751
|
+
"loaded",
|
|
2752
|
+
async () => [
|
|
2753
|
+
...await checkLoaded({ configs, root, workspaces }),
|
|
2754
|
+
...await requiredOptionsOf(configs)
|
|
2755
|
+
]
|
|
2756
|
+
],
|
|
2672
2757
|
[
|
|
2673
2758
|
"group",
|
|
2674
2759
|
() => {
|
|
@@ -2702,13 +2787,19 @@ var runDoctor = async ({
|
|
|
2702
2787
|
["rails", () => checkRails({ root, userSettings: join14(homedir2(), USER_SETTINGS) })]
|
|
2703
2788
|
];
|
|
2704
2789
|
const collected = [];
|
|
2705
|
-
|
|
2790
|
+
const ran = [];
|
|
2791
|
+
for (const [check, run] of runs) {
|
|
2792
|
+
if (!asked(check)) continue;
|
|
2793
|
+
ran.push(check);
|
|
2794
|
+
collected.push(...await run());
|
|
2795
|
+
}
|
|
2706
2796
|
const found = ordered(collected);
|
|
2707
2797
|
const findings = strict ? found.map((one) => one.verdict === "WARN" ? { ...one, verdict: "FAIL" } : one) : found;
|
|
2708
2798
|
return {
|
|
2709
2799
|
counts: countsOf(findings),
|
|
2710
2800
|
findings,
|
|
2711
2801
|
ok: passes(findings),
|
|
2802
|
+
ran,
|
|
2712
2803
|
root
|
|
2713
2804
|
};
|
|
2714
2805
|
};
|
|
@@ -2765,6 +2856,8 @@ export {
|
|
|
2765
2856
|
DEPLOYED_FILE,
|
|
2766
2857
|
NOT_WRITTEN,
|
|
2767
2858
|
checkDeployed,
|
|
2859
|
+
GEONOSIS_FILE,
|
|
2860
|
+
repoCorpusOf,
|
|
2768
2861
|
CHECKS,
|
|
2769
2862
|
DoctorError,
|
|
2770
2863
|
resolveFrom,
|
|
@@ -2772,6 +2865,10 @@ export {
|
|
|
2772
2865
|
pluginVersionOf,
|
|
2773
2866
|
corpusOfPlugin,
|
|
2774
2867
|
relativeToRoot,
|
|
2868
|
+
FIXED_GROUP,
|
|
2869
|
+
KIT_GROUP,
|
|
2870
|
+
declaredGroupsOf,
|
|
2871
|
+
checkGroup,
|
|
2775
2872
|
COMPOSITION_ROOT,
|
|
2776
2873
|
FLOOR_PACKAGES,
|
|
2777
2874
|
READERS,
|
|
@@ -2781,12 +2878,6 @@ export {
|
|
|
2781
2878
|
ENVELOPES_DIR,
|
|
2782
2879
|
NO_ENVELOPES,
|
|
2783
2880
|
checkEnvelopes,
|
|
2784
|
-
GEONOSIS_FILE,
|
|
2785
|
-
repoCorpusOf,
|
|
2786
|
-
FIXED_GROUP,
|
|
2787
|
-
KIT_GROUP,
|
|
2788
|
-
declaredGroupsOf,
|
|
2789
|
-
checkGroup,
|
|
2790
2881
|
SCOPE,
|
|
2791
2882
|
satisfies,
|
|
2792
2883
|
declaredFor,
|