@inixiative/config 0.5.61 → 0.5.62
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 +4 -2
- package/dist/cli.js +239 -118
- package/package.json +1 -1
- package/versions.json +3 -3
package/README.md
CHANGED
|
@@ -65,7 +65,7 @@ TypeScript 6.0 notes, discovered by this repo's fixture suite:
|
|
|
65
65
|
bunx @inixiative/config check [dir] [--preset=base|node|react]
|
|
66
66
|
bunx @inixiative/config sync [dir] [--preset=...] [--force] [--no-install]
|
|
67
67
|
bunx @inixiative/config scan [root] [--lane=primitives|agentic]
|
|
68
|
-
bunx @inixiative/config train [root] [--lane=primitives|agentic] [--push]
|
|
68
|
+
bunx @inixiative/config train [root] [--lane=primitives|agentic] [--push] [--dry-run]
|
|
69
69
|
bunx @inixiative/config ports [project]
|
|
70
70
|
```
|
|
71
71
|
|
|
@@ -83,7 +83,9 @@ Lanes stand alone. A lane with a package missing a checkout, or claimed by ambig
|
|
|
83
83
|
|
|
84
84
|
Consumers run once, after every selected lane, upstreams first, against the full blessed set: a consumer of both lanes ends coherent with both whichever lane ran. They get the same bump → re-lock → `check`, never a publish, and their changes go through review: the train commits them on a `train/ecosystem-sync-<date>` branch and leaves the checkout there until it is merged.
|
|
85
85
|
|
|
86
|
-
When anything was blessed it then ships this package last, so the BOM names the new state: bumps its own patch version if npm already has the current one, blesses that version in the BOM, brings the `test/fixtures` consumers onto the blessed set, runs `check`, commits, publishes. Then every checkout the train re-locked (lane packages on their default branch, consumers on their review branch) is re-locked onto that new `@inixiative/config` and committed, so none is left pinning the previous release. It never pushes unless asked: pass `--push` to push every repo it committed to and open a PR for each consumer branch; otherwise it prints the commands.
|
|
86
|
+
When anything was blessed it then ships this package last, so the BOM names the new state: bumps its own patch version if npm already has the current one, blesses that version in the BOM, brings the `test/fixtures` consumers onto the blessed set, runs `check`, commits, publishes. Then every checkout the train re-locked (lane packages on their default branch, consumers on their review branch) is re-locked onto that new `@inixiative/config` and committed, so none is left pinning the previous release. It never pushes unless asked: pass `--push` to push every repo it committed to and open a PR for each consumer branch; otherwise it prints the commands. `--dry-run` walks the same plan and prints each step it would take (range rewrites, re-locks and checks, commits, review branches, publishes, BOM blessings, pushes) without running any of them; it only fetches and reads git state and `npm view`.
|
|
87
|
+
|
|
88
|
+
Each command accepts only its own flags. An unknown or misplaced flag (`--dryrun`, `--push` on `sync`) is a usage error and exits 2 before anything runs.
|
|
87
89
|
|
|
88
90
|
Division of labor: this CLI owns the toolchain set, ecosystem coherence, stubs, and lockfile format. Renovate owns everything else plus bumping `@inixiative/config` itself, and must be fenced off the toolchain packages.
|
|
89
91
|
|
package/dist/cli.js
CHANGED
|
@@ -6,6 +6,9 @@ import { existsSync as existsSync2, mkdtempSync, readdirSync as readdirSync2, re
|
|
|
6
6
|
import { tmpdir } from "os";
|
|
7
7
|
import { dirname as dirname2, join as join2, resolve as resolve2 } from "path";
|
|
8
8
|
|
|
9
|
+
// src/args.ts
|
|
10
|
+
import { parseArgs } from "util";
|
|
11
|
+
|
|
9
12
|
// src/lib.ts
|
|
10
13
|
import { spawnSync } from "child_process";
|
|
11
14
|
import {
|
|
@@ -22,13 +25,13 @@ import { fileURLToPath } from "url";
|
|
|
22
25
|
var packageRoot = join(dirname(fileURLToPath(import.meta.url)), "..");
|
|
23
26
|
var LANES = ["primitives", "agentic"];
|
|
24
27
|
var isLane = (value) => LANES.includes(value);
|
|
25
|
-
var lanePackages = (manifest2,
|
|
26
|
-
const section =
|
|
28
|
+
var lanePackages = (manifest2, lane2) => {
|
|
29
|
+
const section = lane2 === "primitives" ? manifest2.ecosystem : manifest2.agentic ?? {};
|
|
27
30
|
const { "@inixiative/config": _config, ...packages } = section;
|
|
28
31
|
return packages;
|
|
29
32
|
};
|
|
30
|
-
var laneSection = (manifest2,
|
|
31
|
-
if (
|
|
33
|
+
var laneSection = (manifest2, lane2) => {
|
|
34
|
+
if (lane2 === "primitives") return manifest2.ecosystem;
|
|
32
35
|
manifest2.agentic ??= {};
|
|
33
36
|
return manifest2.agentic;
|
|
34
37
|
};
|
|
@@ -38,7 +41,7 @@ var blessedVersions = (manifest2) => ({
|
|
|
38
41
|
});
|
|
39
42
|
var consumersFor = (manifest2, lanes2) => {
|
|
40
43
|
const consumers = manifest2.consumers ?? {};
|
|
41
|
-
const selected = Object.keys(consumers).filter((repo) => consumers[repo].lanes.some((
|
|
44
|
+
const selected = Object.keys(consumers).filter((repo) => consumers[repo].lanes.some((lane2) => lanes2.includes(lane2))).sort();
|
|
42
45
|
const order = [];
|
|
43
46
|
const visit = (repo, trail) => {
|
|
44
47
|
if (order.includes(repo)) return;
|
|
@@ -211,8 +214,8 @@ var candidateDirs = (root) => {
|
|
|
211
214
|
};
|
|
212
215
|
var discover = (root, manifest2, lanes2 = LANES) => {
|
|
213
216
|
const wanted = /* @__PURE__ */ new Map();
|
|
214
|
-
for (const
|
|
215
|
-
for (const name of Object.keys(lanePackages(manifest2,
|
|
217
|
+
for (const lane2 of lanes2) {
|
|
218
|
+
for (const name of Object.keys(lanePackages(manifest2, lane2))) wanted.set(name, lane2);
|
|
216
219
|
}
|
|
217
220
|
const consumerRepos = new Set(consumersFor(manifest2, lanes2));
|
|
218
221
|
const claims = /* @__PURE__ */ new Map();
|
|
@@ -328,11 +331,11 @@ var trainPlan = (root, manifest2, lanes2 = LANES) => {
|
|
|
328
331
|
)
|
|
329
332
|
);
|
|
330
333
|
return {
|
|
331
|
-
lanes: LANES.filter((
|
|
332
|
-
const names = new Set(Object.keys(lanePackages(manifest2,
|
|
333
|
-
const own = checkouts.filter((checkout) => checkout.lane ===
|
|
334
|
+
lanes: LANES.filter((lane2) => lanes2.includes(lane2)).map((lane2) => {
|
|
335
|
+
const names = new Set(Object.keys(lanePackages(manifest2, lane2)));
|
|
336
|
+
const own = checkouts.filter((checkout) => checkout.lane === lane2);
|
|
334
337
|
return {
|
|
335
|
-
lane,
|
|
338
|
+
lane: lane2,
|
|
336
339
|
checkouts: topoOrder(own),
|
|
337
340
|
missing: [...names].filter(
|
|
338
341
|
(name) => !own.some((checkout) => checkout.packages.some((entry) => entry.name === name)) && !ambiguous.some((entry) => entry.key === name)
|
|
@@ -729,8 +732,8 @@ function inspect(dir2, manifest2, presetOverride) {
|
|
|
729
732
|
}
|
|
730
733
|
}
|
|
731
734
|
}
|
|
732
|
-
const
|
|
733
|
-
const tsconfigTarget = `@inixiative/config/tsconfig/${
|
|
735
|
+
const preset2 = detectPreset(pkg, presetOverride);
|
|
736
|
+
const tsconfigTarget = `@inixiative/config/tsconfig/${preset2}.json`;
|
|
734
737
|
const tsconfigPath = join(dir2, "tsconfig.json");
|
|
735
738
|
if (!existsSync(tsconfigPath)) {
|
|
736
739
|
findings.push({
|
|
@@ -758,7 +761,7 @@ function inspect(dir2, manifest2, presetOverride) {
|
|
|
758
761
|
});
|
|
759
762
|
}
|
|
760
763
|
}
|
|
761
|
-
const biomeTargets =
|
|
764
|
+
const biomeTargets = preset2 === "react" ? ["@inixiative/config/biome/base.json", "@inixiative/config/biome/react.json"] : ["@inixiative/config/biome/base.json"];
|
|
762
765
|
const biomePath = join(dir2, "biome.json");
|
|
763
766
|
if (!existsSync(biomePath)) {
|
|
764
767
|
findings.push({
|
|
@@ -804,6 +807,58 @@ function inspect(dir2, manifest2, presetOverride) {
|
|
|
804
807
|
};
|
|
805
808
|
}
|
|
806
809
|
|
|
810
|
+
// src/args.ts
|
|
811
|
+
var COMMANDS = ["check", "sync", "scan", "train", "ports"];
|
|
812
|
+
var PRESETS = ["base", "node", "react"];
|
|
813
|
+
var preset = { type: "string" };
|
|
814
|
+
var lane = { type: "string" };
|
|
815
|
+
var flag = { type: "boolean", default: false };
|
|
816
|
+
var OPTIONS = {
|
|
817
|
+
check: { preset },
|
|
818
|
+
sync: { preset, force: flag, "no-install": flag },
|
|
819
|
+
scan: { lane },
|
|
820
|
+
train: { lane, push: flag, "dry-run": flag },
|
|
821
|
+
ports: {}
|
|
822
|
+
};
|
|
823
|
+
var UsageError = class extends Error {
|
|
824
|
+
};
|
|
825
|
+
var isCommand = (value) => COMMANDS.includes(value);
|
|
826
|
+
var parseCommandLine = (argv) => {
|
|
827
|
+
const command2 = argv[0];
|
|
828
|
+
if (!isCommand(command2)) throw new UsageError(`unknown command: ${command2 ?? "(none)"}`);
|
|
829
|
+
let values;
|
|
830
|
+
let positionals2;
|
|
831
|
+
try {
|
|
832
|
+
const options = OPTIONS[command2];
|
|
833
|
+
({ values, positionals: positionals2 } = parseArgs({
|
|
834
|
+
args: argv.slice(1),
|
|
835
|
+
options,
|
|
836
|
+
allowPositionals: true,
|
|
837
|
+
strict: true
|
|
838
|
+
}));
|
|
839
|
+
} catch (error) {
|
|
840
|
+
throw new UsageError(`${command2}: ${error instanceof Error ? error.message : String(error)}`);
|
|
841
|
+
}
|
|
842
|
+
const presetValue = values.preset;
|
|
843
|
+
if (typeof presetValue === "string" && !PRESETS.includes(presetValue)) {
|
|
844
|
+
throw new UsageError(`unknown preset: ${presetValue}`);
|
|
845
|
+
}
|
|
846
|
+
const laneValue = values.lane;
|
|
847
|
+
if (typeof laneValue === "string" && !isLane(laneValue)) {
|
|
848
|
+
throw new UsageError(`unknown lane: ${laneValue}`);
|
|
849
|
+
}
|
|
850
|
+
return {
|
|
851
|
+
command: command2,
|
|
852
|
+
positionals: positionals2,
|
|
853
|
+
preset: typeof presetValue === "string" ? presetValue : void 0,
|
|
854
|
+
lane: typeof laneValue === "string" && isLane(laneValue) ? laneValue : void 0,
|
|
855
|
+
force: values.force === true,
|
|
856
|
+
noInstall: values["no-install"] === true,
|
|
857
|
+
push: values.push === true,
|
|
858
|
+
dryRun: values["dry-run"] === true
|
|
859
|
+
};
|
|
860
|
+
};
|
|
861
|
+
|
|
807
862
|
// ports.json
|
|
808
863
|
var ports_default = {
|
|
809
864
|
$comment: "Local port registry. A project's port for a service is the service's default plus 100 times the project's block, so projects never collide and none uses a default. Add a project at the next free block; add a service with its usual default.",
|
|
@@ -847,32 +902,32 @@ function portsFor(project) {
|
|
|
847
902
|
}
|
|
848
903
|
|
|
849
904
|
// src/cli.ts
|
|
850
|
-
var
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
console.log(
|
|
859
|
-
"Usage: inixiative-config <check|sync|scan|train> [dir] [--preset=base|node|react] [--lane=primitives|agentic] [--force] [--no-install] [--push]\n inixiative-config ports [project]"
|
|
905
|
+
var commandLine;
|
|
906
|
+
try {
|
|
907
|
+
commandLine = parseCommandLine(process.argv.slice(2));
|
|
908
|
+
} catch (error) {
|
|
909
|
+
if (!(error instanceof UsageError)) throw error;
|
|
910
|
+
console.error(`\u2717 ${error.message}`);
|
|
911
|
+
console.error(
|
|
912
|
+
"Usage: inixiative-config check [dir] [--preset=base|node|react]\n inixiative-config sync [dir] [--preset=base|node|react] [--force] [--no-install]\n inixiative-config scan [root] [--lane=primitives|agentic]\n inixiative-config train [root] [--lane=primitives|agentic] [--push] [--dry-run]\n inixiative-config ports [project]"
|
|
860
913
|
);
|
|
861
914
|
process.exit(2);
|
|
862
|
-
}
|
|
915
|
+
}
|
|
916
|
+
var { command, positionals, preset: presetFlag, dryRun } = commandLine;
|
|
917
|
+
var dir = resolve2(positionals[0] ?? ".");
|
|
863
918
|
if (command === "ports") {
|
|
864
|
-
const project =
|
|
865
|
-
if (project !== void 0 && !projects.includes(project))
|
|
919
|
+
const project = positionals[0];
|
|
920
|
+
if (project !== void 0 && !projects.includes(project)) {
|
|
921
|
+
console.error(`\u2717 unknown project: ${project} (${projects.join(", ")})`);
|
|
922
|
+
process.exit(2);
|
|
923
|
+
}
|
|
866
924
|
for (const name of project ? [project] : projects)
|
|
867
925
|
console.log(
|
|
868
926
|
`${name}: ${Object.entries(portsFor(name)).map(([service, port]) => `${service}=${port}`).join(" ")}`
|
|
869
927
|
);
|
|
870
928
|
process.exit(0);
|
|
871
929
|
}
|
|
872
|
-
|
|
873
|
-
if (presetFlag && !["base", "node", "react"].includes(presetFlag)) usage();
|
|
874
|
-
if (laneFlag !== void 0 && !isLane(laneFlag)) usage();
|
|
875
|
-
var lanes = laneFlag && isLane(laneFlag) ? [laneFlag] : [...LANES];
|
|
930
|
+
var lanes = commandLine.lane ? [commandLine.lane] : [...LANES];
|
|
876
931
|
var manifest = loadManifest();
|
|
877
932
|
var report = (findings) => {
|
|
878
933
|
for (const finding of findings) {
|
|
@@ -931,13 +986,13 @@ if (command === "check") {
|
|
|
931
986
|
var laneLabel = (checkout) => checkout.consumer ? `consumer of ${checkout.consumer.lanes.join(" + ")}` : `${checkout.lane} lane`;
|
|
932
987
|
if (command === "scan") {
|
|
933
988
|
const plan = trainPlan(dir, manifest, lanes);
|
|
934
|
-
const checkouts = [...plan.lanes.flatMap((
|
|
989
|
+
const checkouts = [...plan.lanes.flatMap((lane2) => lane2.checkouts), ...plan.consumers];
|
|
935
990
|
if (checkouts.length === 0) {
|
|
936
991
|
console.error(`\u2717 no ecosystem repos found under ${dir}`);
|
|
937
992
|
process.exit(1);
|
|
938
993
|
}
|
|
939
|
-
const missing = [...plan.lanes.flatMap((
|
|
940
|
-
const ambiguous = [...plan.lanes.flatMap((
|
|
994
|
+
const missing = [...plan.lanes.flatMap((lane2) => lane2.missing), ...plan.missingConsumers];
|
|
995
|
+
const ambiguous = [...plan.lanes.flatMap((lane2) => lane2.ambiguous), ...plan.ambiguousConsumers];
|
|
941
996
|
const drifted = [];
|
|
942
997
|
for (const checkout of checkouts) {
|
|
943
998
|
console.log(`
|
|
@@ -973,13 +1028,24 @@ scanned ${checkouts.length} repos (${lanes.join(" + ")}): ${drifted.length === 0
|
|
|
973
1028
|
var Abort = class extends Error {
|
|
974
1029
|
};
|
|
975
1030
|
if (command === "train") {
|
|
1031
|
+
const effect = (description, planned, run) => {
|
|
1032
|
+
if (!dryRun) return run();
|
|
1033
|
+
console.log(` [dry-run] would ${description}`);
|
|
1034
|
+
return planned;
|
|
1035
|
+
};
|
|
1036
|
+
if (dryRun) console.log("dry run: nothing is installed, written, committed, published or pushed");
|
|
976
1037
|
git(packageRoot, "fetch", "--quiet");
|
|
977
1038
|
if (behindOrigin(packageRoot) > 0) {
|
|
978
|
-
|
|
979
|
-
|
|
1039
|
+
if (!dryRun) {
|
|
1040
|
+
console.error(
|
|
1041
|
+
"\u2717 this config checkout is behind origin \u2014 its blessed set is stale; pull first"
|
|
1042
|
+
);
|
|
1043
|
+
process.exit(1);
|
|
1044
|
+
}
|
|
1045
|
+
console.log("\u26A0 this config checkout is behind origin \u2014 the plan uses a stale blessed set");
|
|
980
1046
|
}
|
|
981
1047
|
const plan = trainPlan(dir, manifest, lanes);
|
|
982
|
-
if (plan.lanes.every((
|
|
1048
|
+
if (plan.lanes.every((lane2) => lane2.checkouts.length === 0) && plan.consumers.length === 0) {
|
|
983
1049
|
console.error(`\u2717 no ecosystem repos found under ${dir}`);
|
|
984
1050
|
process.exit(1);
|
|
985
1051
|
}
|
|
@@ -1017,30 +1083,39 @@ if (command === "train") {
|
|
|
1017
1083
|
console.log("\u26A0 diverged from origin \u2014 reconcile first, skipping");
|
|
1018
1084
|
return false;
|
|
1019
1085
|
}
|
|
1020
|
-
|
|
1086
|
+
const merged = effect(
|
|
1087
|
+
`fast-forward to origin (+${behind}); the plan below reflects the local tree`,
|
|
1088
|
+
true,
|
|
1089
|
+
() => git(checkout.dir, "merge", "--ff-only", "@{upstream}").status === 0
|
|
1090
|
+
);
|
|
1091
|
+
if (!merged) {
|
|
1021
1092
|
console.log("\u26A0 fast-forward to origin failed \u2014 reconcile first, skipping");
|
|
1022
1093
|
return false;
|
|
1023
1094
|
}
|
|
1024
|
-
|
|
1025
|
-
|
|
1095
|
+
if (!dryRun) {
|
|
1096
|
+
console.log(`\u2193 fast-forwarded to origin (+${behind})`);
|
|
1097
|
+
checkout.pkg = JSON.parse(readFileSync2(join2(checkout.dir, "package.json"), "utf8"));
|
|
1098
|
+
}
|
|
1026
1099
|
}
|
|
1027
1100
|
return true;
|
|
1028
1101
|
};
|
|
1029
1102
|
const bumpRanges = (checkout) => {
|
|
1030
1103
|
const inspection = inspect(checkout.dir, manifest);
|
|
1031
1104
|
const bumps = inspection.findings.filter((finding) => finding.kind === "ecosystem-range");
|
|
1032
|
-
for (const bump of bumps) {
|
|
1033
|
-
|
|
1034
|
-
|
|
1105
|
+
for (const bump of bumps) console.log(` ${bump.message}`);
|
|
1106
|
+
if (bumps.length > 0) {
|
|
1107
|
+
effect(`rewrite ${bumps.length} ecosystem range(s) to the blessed set`, void 0, () => {
|
|
1108
|
+
for (const bump of bumps) bump.fix?.();
|
|
1109
|
+
inspection.flush();
|
|
1110
|
+
});
|
|
1035
1111
|
}
|
|
1036
|
-
inspection.flush();
|
|
1037
1112
|
return {
|
|
1038
1113
|
inspection,
|
|
1039
1114
|
bumped: bumps.length > 0,
|
|
1040
1115
|
staleLock: inspection.findings.some((finding) => finding.kind === "stale-lock")
|
|
1041
1116
|
};
|
|
1042
1117
|
};
|
|
1043
|
-
const relockAndCheck = (checkout, check = true) => {
|
|
1118
|
+
const relockAndCheck = (checkout, check = true) => effect(`re-lock ${checkout.name}${check ? " and run its check" : ""}`, void 0, () => {
|
|
1044
1119
|
if (spawnSync2("bun", ["install"], { cwd: checkout.dir, stdio: "inherit" }).status !== 0) {
|
|
1045
1120
|
throw new Abort(`bun install failed in ${checkout.name}`);
|
|
1046
1121
|
}
|
|
@@ -1053,23 +1128,38 @@ if (command === "train") {
|
|
|
1053
1128
|
if (check && spawnSync2("bun", ["run", "check"], { cwd: checkout.dir, stdio: "inherit" }).status !== 0) {
|
|
1054
1129
|
throw new Abort(`check failed in ${checkout.name}`);
|
|
1055
1130
|
}
|
|
1056
|
-
};
|
|
1131
|
+
});
|
|
1057
1132
|
const followers = [];
|
|
1058
|
-
const commitOwned = (checkout, packagePaths) => {
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1133
|
+
const commitOwned = (checkout, packagePaths, changes) => {
|
|
1134
|
+
if (dryRun && !changes) return false;
|
|
1135
|
+
return effect(`commit its package.json files + bun.lock in ${checkout.name}`, true, () => {
|
|
1136
|
+
const tracked = [...packagePaths, "bun.lock"];
|
|
1137
|
+
const mutated = git(checkout.dir, "status", "--porcelain", "--", ...tracked);
|
|
1138
|
+
if (mutated.status !== 0 || mutated.stdout.trim().length === 0) return false;
|
|
1139
|
+
if (git(checkout.dir, "add", "--", ...tracked).status !== 0) {
|
|
1140
|
+
throw new Abort(`git add failed in ${checkout.name} \u2014 is bun.lock ignored?`);
|
|
1141
|
+
}
|
|
1142
|
+
const commit = spawnSync2(
|
|
1143
|
+
"git",
|
|
1144
|
+
["commit", "-m", "chore: sync ecosystem deps to blessed set"],
|
|
1145
|
+
{
|
|
1146
|
+
cwd: checkout.dir,
|
|
1147
|
+
stdio: "inherit"
|
|
1148
|
+
}
|
|
1149
|
+
);
|
|
1150
|
+
if (commit.status !== 0) throw new Abort(`commit failed in ${checkout.name}`);
|
|
1151
|
+
return true;
|
|
1068
1152
|
});
|
|
1069
|
-
if (commit.status !== 0) throw new Abort(`commit failed in ${checkout.name}`);
|
|
1070
|
-
return true;
|
|
1071
1153
|
};
|
|
1072
|
-
const publish = (checkout, entry) => {
|
|
1154
|
+
const publish = (checkout, entry, version, remote) => effect(`publish ${entry.name}@${version} to npm (npm has ${remote ?? "none"})`, true, () => {
|
|
1155
|
+
console.log(`publishing ${entry.name}@${version} (npm has ${remote ?? "none"})`);
|
|
1156
|
+
if (!publishToNpm(checkout, entry)) throw new Abort(`publish failed for ${entry.name}`);
|
|
1157
|
+
if (!servedByRegistry(entry.name, version)) {
|
|
1158
|
+
throw new Abort(`npm accepted ${entry.name}@${version} but the registry does not serve it`);
|
|
1159
|
+
}
|
|
1160
|
+
return true;
|
|
1161
|
+
});
|
|
1162
|
+
const publishToNpm = (checkout, entry) => {
|
|
1073
1163
|
if (entry.path === "package.json") {
|
|
1074
1164
|
return spawnSync2("npm", ["publish"], { cwd: checkout.dir, stdio: "inherit" }).status === 0;
|
|
1075
1165
|
}
|
|
@@ -1091,12 +1181,12 @@ if (command === "train") {
|
|
|
1091
1181
|
const remote = spawnSync2("npm", ["view", `${name}@latest`, "version"], { encoding: "utf8" });
|
|
1092
1182
|
return remote.status === 0 ? remote.stdout.trim() : null;
|
|
1093
1183
|
};
|
|
1094
|
-
for (const { lane, checkouts, missing, ambiguous } of plan.lanes) {
|
|
1184
|
+
for (const { lane: lane2, checkouts, missing, ambiguous } of plan.lanes) {
|
|
1095
1185
|
console.log(
|
|
1096
1186
|
`
|
|
1097
|
-
\u2550 ${
|
|
1187
|
+
\u2550 ${lane2} lane: ${checkouts.map((checkout) => checkout.name).join(" \u2192 ") || "(none)"}`
|
|
1098
1188
|
);
|
|
1099
|
-
const section = laneSection(manifest,
|
|
1189
|
+
const section = laneSection(manifest, lane2);
|
|
1100
1190
|
const before = { ...section };
|
|
1101
1191
|
const laneBlessed = [];
|
|
1102
1192
|
try {
|
|
@@ -1133,19 +1223,13 @@ if (command === "train") {
|
|
|
1133
1223
|
skipped.push(checkout.name);
|
|
1134
1224
|
continue;
|
|
1135
1225
|
}
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
if (commitOwned(checkout, inspection.packagePaths)) committed.add(checkout.dir);
|
|
1226
|
+
const relocked = bumped || staleLock || releases.some((release) => release.ahead);
|
|
1227
|
+
if (relocked) relockAndCheck(checkout);
|
|
1228
|
+
if (commitOwned(checkout, inspection.packagePaths, relocked)) committed.add(checkout.dir);
|
|
1139
1229
|
followers.push(checkout);
|
|
1140
1230
|
for (const { entry, local, remote, ahead } of releases) {
|
|
1141
1231
|
if (ahead) {
|
|
1142
|
-
|
|
1143
|
-
if (!publish(checkout, entry)) throw new Abort(`publish failed for ${entry.name}`);
|
|
1144
|
-
if (!servedByRegistry(entry.name, local)) {
|
|
1145
|
-
throw new Abort(
|
|
1146
|
-
`npm accepted ${entry.name}@${local} but the registry does not serve it`
|
|
1147
|
-
);
|
|
1148
|
-
}
|
|
1232
|
+
publish(checkout, entry, local, remote);
|
|
1149
1233
|
} else if (section[entry.name] === local) {
|
|
1150
1234
|
console.log(`\u2713 ${entry.name}@${local} already on npm and blessed`);
|
|
1151
1235
|
continue;
|
|
@@ -1157,19 +1241,23 @@ if (command === "train") {
|
|
|
1157
1241
|
}
|
|
1158
1242
|
}
|
|
1159
1243
|
if (laneBlessed.length > 0) {
|
|
1160
|
-
|
|
1244
|
+
effect(
|
|
1245
|
+
`bless ${laneBlessed.join(", ")} in versions.json`,
|
|
1246
|
+
void 0,
|
|
1247
|
+
() => writeManifest(manifest)
|
|
1248
|
+
);
|
|
1161
1249
|
bomDirty = true;
|
|
1162
1250
|
blessed.push(...laneBlessed);
|
|
1163
1251
|
}
|
|
1164
1252
|
console.log(
|
|
1165
|
-
`${
|
|
1253
|
+
`${lane2} lane blessed: ${laneBlessed.length === 0 ? "nothing new" : laneBlessed.join(", ")}`
|
|
1166
1254
|
);
|
|
1167
1255
|
} catch (error) {
|
|
1168
1256
|
if (!(error instanceof Abort)) throw error;
|
|
1169
1257
|
for (const name of Object.keys(section)) delete section[name];
|
|
1170
1258
|
Object.assign(section, before);
|
|
1171
|
-
failed.push(`${
|
|
1172
|
-
console.error(`\u2717 ${error.message} \u2014 ${
|
|
1259
|
+
failed.push(`${lane2} lane`);
|
|
1260
|
+
console.error(`\u2717 ${error.message} \u2014 ${lane2} lane stopped; its BOM entries are unchanged`);
|
|
1173
1261
|
if (laneBlessed.length > 0) {
|
|
1174
1262
|
console.error(
|
|
1175
1263
|
` published but not blessed: ${laneBlessed.join(", ")} \u2014 the next train blesses them`
|
|
@@ -1210,13 +1298,18 @@ if (command === "train") {
|
|
|
1210
1298
|
checkout.dir,
|
|
1211
1299
|
`train/ecosystem-sync-${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}`
|
|
1212
1300
|
);
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1301
|
+
const switched = effect(
|
|
1302
|
+
`create review branch ${branch} in ${checkout.name}`,
|
|
1303
|
+
true,
|
|
1304
|
+
() => git(checkout.dir, "switch", "-c", branch).status === 0
|
|
1305
|
+
);
|
|
1306
|
+
if (!switched) throw new Abort(`could not create ${branch} in ${checkout.name}`);
|
|
1216
1307
|
followers.push(checkout);
|
|
1217
|
-
if (commitOwned(checkout, inspection.packagePaths)) {
|
|
1308
|
+
if (commitOwned(checkout, inspection.packagePaths, true)) {
|
|
1218
1309
|
reviewBranches.push({ dir: checkout.dir, branch, base });
|
|
1219
|
-
|
|
1310
|
+
if (!dryRun) {
|
|
1311
|
+
console.log(`committed on ${branch} for review; the checkout stays on it until merged`);
|
|
1312
|
+
}
|
|
1220
1313
|
}
|
|
1221
1314
|
} catch (error) {
|
|
1222
1315
|
if (!(error instanceof Abort)) throw error;
|
|
@@ -1233,52 +1326,73 @@ blessed: ${blessed.length === 0 ? "nothing" : blessed.join(", ")}`);
|
|
|
1233
1326
|
let version = ownVersion();
|
|
1234
1327
|
if (remoteVersion !== null && compare(version, remoteVersion) <= 0) {
|
|
1235
1328
|
version = bumpPatch(remoteVersion);
|
|
1236
|
-
const
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1329
|
+
const bumped = version;
|
|
1330
|
+
effect(`bump @inixiative/config to ${bumped} in package.json`, void 0, () => {
|
|
1331
|
+
const pkgPath = join2(packageRoot, "package.json");
|
|
1332
|
+
const pkg = JSON.parse(readFileSync2(pkgPath, "utf8"));
|
|
1333
|
+
pkg.version = bumped;
|
|
1334
|
+
writeFileSync2(pkgPath, `${JSON.stringify(pkg, null, 2)}
|
|
1240
1335
|
`);
|
|
1336
|
+
});
|
|
1241
1337
|
}
|
|
1242
1338
|
manifest.ecosystem["@inixiative/config"] = version;
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1339
|
+
effect(
|
|
1340
|
+
`bless @inixiative/config@${version} in versions.json and move test/fixtures onto the blessed set`,
|
|
1341
|
+
void 0,
|
|
1342
|
+
() => {
|
|
1343
|
+
writeManifest(manifest);
|
|
1344
|
+
for (const fixture of fixtureDirs()) {
|
|
1345
|
+
const inspection = inspect(fixture, manifest);
|
|
1346
|
+
for (const finding of inspection.findings)
|
|
1347
|
+
if (finding.kind === "ecosystem-range") finding.fix?.();
|
|
1348
|
+
inspection.flush();
|
|
1349
|
+
}
|
|
1350
|
+
}
|
|
1351
|
+
);
|
|
1352
|
+
effect("run bun run check in @inixiative/config", void 0, () => {
|
|
1353
|
+
const check = spawnSync2("bun", ["run", "check"], { cwd: packageRoot, stdio: "inherit" });
|
|
1354
|
+
if (check.status !== 0) {
|
|
1355
|
+
console.error("\u2717 check failed in @inixiative/config \u2014 aborting before publish");
|
|
1356
|
+
process.exit(1);
|
|
1357
|
+
}
|
|
1257
1358
|
});
|
|
1258
|
-
|
|
1259
|
-
"
|
|
1260
|
-
|
|
1261
|
-
|
|
1359
|
+
effect(
|
|
1360
|
+
`commit "chore: bless ${blessed.join(", ")} \u2014 ${version}" in @inixiative/config`,
|
|
1361
|
+
void 0,
|
|
1362
|
+
() => {
|
|
1363
|
+
spawnSync2("git", ["add", "--", "package.json", "versions.json", "test/fixtures"], {
|
|
1364
|
+
cwd: packageRoot
|
|
1365
|
+
});
|
|
1366
|
+
const commit = spawnSync2(
|
|
1367
|
+
"git",
|
|
1368
|
+
["commit", "-m", `chore: bless ${blessed.join(", ")} \u2014 ${version}`],
|
|
1369
|
+
{ cwd: packageRoot, stdio: "inherit" }
|
|
1370
|
+
);
|
|
1371
|
+
if (commit.status !== 0) {
|
|
1372
|
+
console.error("\u2717 commit failed in @inixiative/config \u2014 aborting before publish");
|
|
1373
|
+
process.exit(1);
|
|
1374
|
+
}
|
|
1375
|
+
}
|
|
1262
1376
|
);
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
console.
|
|
1270
|
-
|
|
1271
|
-
}
|
|
1377
|
+
effect(`publish @inixiative/config@${version} to npm`, void 0, () => {
|
|
1378
|
+
const publish2 = spawnSync2("npm", ["publish"], { cwd: packageRoot, stdio: "inherit" });
|
|
1379
|
+
if (publish2.status !== 0 || !servedByRegistry("@inixiative/config", version)) {
|
|
1380
|
+
console.error("\u2717 publish failed for @inixiative/config");
|
|
1381
|
+
process.exit(1);
|
|
1382
|
+
}
|
|
1383
|
+
console.log(`published: @inixiative/config@${version} \u2014 the BOM names the new state`);
|
|
1384
|
+
});
|
|
1272
1385
|
committed.add(packageRoot);
|
|
1273
|
-
console.log(`
|
|
1386
|
+
if (followers.length > 0) console.log(`
|
|
1387
|
+
\u2550 re-lock onto @inixiative/config@${version}`);
|
|
1274
1388
|
for (const checkout of followers) {
|
|
1275
1389
|
try {
|
|
1276
1390
|
const { inspection, bumped, staleLock } = bumpRanges(checkout);
|
|
1277
1391
|
if (!bumped && !staleLock) continue;
|
|
1278
1392
|
relockAndCheck(checkout, false);
|
|
1279
|
-
if (commitOwned(checkout, inspection.packagePaths) && !checkout.consumer)
|
|
1393
|
+
if (commitOwned(checkout, inspection.packagePaths, true) && !checkout.consumer)
|
|
1280
1394
|
committed.add(checkout.dir);
|
|
1281
|
-
console.log(`\u2713 ${checkout.name} locked to @inixiative/config@${version}`);
|
|
1395
|
+
if (!dryRun) console.log(`\u2713 ${checkout.name} locked to @inixiative/config@${version}`);
|
|
1282
1396
|
} catch (error) {
|
|
1283
1397
|
if (!(error instanceof Abort)) throw error;
|
|
1284
1398
|
failed.push(checkout.name);
|
|
@@ -1286,7 +1400,14 @@ blessed: ${blessed.length === 0 ? "nothing" : blessed.join(", ")}`);
|
|
|
1286
1400
|
}
|
|
1287
1401
|
}
|
|
1288
1402
|
}
|
|
1289
|
-
if (
|
|
1403
|
+
if (dryRun) {
|
|
1404
|
+
console.log(
|
|
1405
|
+
`
|
|
1406
|
+
dry run complete \u2014 a real train would commit in ${committed.size} repo(s) and open ${reviewBranches.length} review branch(es)${commandLine.push ? ", then push them" : ""}:`
|
|
1407
|
+
);
|
|
1408
|
+
for (const repoDir of committed) console.log(` ${repoDir}`);
|
|
1409
|
+
for (const { dir: repoDir, branch } of reviewBranches) console.log(` ${repoDir} (${branch})`);
|
|
1410
|
+
} else if (commandLine.push) {
|
|
1290
1411
|
for (const repoDir of committed) {
|
|
1291
1412
|
if (spawnSync2("git", ["push"], { cwd: repoDir, stdio: "inherit" }).status !== 0) {
|
|
1292
1413
|
console.error(`\u2717 push failed in ${repoDir}`);
|
|
@@ -1345,7 +1466,7 @@ function fixtureDirs() {
|
|
|
1345
1466
|
if (!existsSync2(root)) return [];
|
|
1346
1467
|
return readdirSync2(root).map((name) => join2(root, name)).filter((dir2) => existsSync2(join2(dir2, "package.json")));
|
|
1347
1468
|
}
|
|
1348
|
-
if (existsSync2(join2(dir, ".git")) && !
|
|
1469
|
+
if (existsSync2(join2(dir, ".git")) && !commandLine.force) {
|
|
1349
1470
|
const status = spawnSync2("git", ["status", "--porcelain"], { cwd: dir, encoding: "utf8" });
|
|
1350
1471
|
if (status.status === 0 && status.stdout.trim().length > 0) {
|
|
1351
1472
|
console.error("\u2717 working tree dirty \u2014 commit first or pass --force");
|
|
@@ -1357,7 +1478,7 @@ for (const finding of first.findings) finding.fix?.();
|
|
|
1357
1478
|
first.flush();
|
|
1358
1479
|
var fixed = first.findings.filter((finding) => finding.fix).length;
|
|
1359
1480
|
if (fixed > 0) console.log(`applied ${fixed} fix${fixed === 1 ? "" : "es"}`);
|
|
1360
|
-
if (!
|
|
1481
|
+
if (!commandLine.noInstall) {
|
|
1361
1482
|
const relinked = new Set(
|
|
1362
1483
|
first.findings.flatMap(
|
|
1363
1484
|
(finding) => finding.kind === "member-toolchain" && finding.path ? [dirname2(finding.path)] : []
|
package/package.json
CHANGED
package/versions.json
CHANGED
|
@@ -13,10 +13,10 @@
|
|
|
13
13
|
"@types/bun"
|
|
14
14
|
],
|
|
15
15
|
"ecosystem": {
|
|
16
|
-
"@inixiative/config": "0.5.
|
|
17
|
-
"@inixiative/json-rules": "3.4.
|
|
16
|
+
"@inixiative/config": "0.5.62",
|
|
17
|
+
"@inixiative/json-rules": "3.4.1",
|
|
18
18
|
"@inixiative/permissions": "0.4.0",
|
|
19
|
-
"@inixiative/transitions": "0.
|
|
19
|
+
"@inixiative/transitions": "0.4.0",
|
|
20
20
|
"@inixiative/rules-builder": "0.30.0",
|
|
21
21
|
"@inixiative/prisma-map": "0.2.0",
|
|
22
22
|
"@inixiative/atlas": "0.2.0",
|