@inixiative/config 0.5.81 → 0.5.83

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 CHANGED
@@ -85,7 +85,7 @@ Lanes stand alone. A lane with a package missing a checkout, or claimed by ambig
85
85
  Blessing is two-phase, so a dependent that needs work never deadlocks a release:
86
86
 
87
87
  1. **Candidate.** A published version is recorded under `candidates`, and the config release that ends the train carries it, so `check` in any repo's CI accepts it from then on.
88
- 2. **Adopt.** A repo (lane checkout or consumer) whose check fails against the candidates it was moved onto doesn't stop the train. Its checkout is put back as it was, and the train opens `train/adopt-<pkg>-<version>` in a worktree (with the repo's root `.env*` files copied in): the same bump and re-lock, then the repo's `train:adopt` script if its package.json declares one (Foundry's re-records cassettes with `bun run test:live`), all committed, and re-locked onto the new config release so the PR's CI judges it against the candidates. A lane checkout that adopts publishes nothing this run. A consumer that passes against candidates gets the same branch name: its default branch is still on the previous versions until the branch merges. If the adoption's commit is refused (its hooks typecheck), the branch is deleted and the summary says to adopt by hand.
88
+ 2. **Adopt.** A repo (lane checkout or consumer) whose check fails against the candidates it was moved onto doesn't stop the train. Its checkout is put back as it was, and the train opens `train/adopt-<pkg>-<version>` in a worktree (the repo's own `worktree:create <base> <branch>` when it declares one, so a template-based repo gets its slot's databases, released with its `worktree:destroy`; otherwise a temporary linked worktree; either way with the repo's ignored `.env*` files copied in where missing): the same bump and re-lock, then the repo's `train:adopt` script if its package.json declares one (Foundry's re-records cassettes with `bun run test:live`), all committed, and re-locked onto the new config release so the PR's CI judges it against the candidates. A lane checkout that adopts publishes nothing this run. A consumer that passes against candidates gets the same branch name: its default branch is still on the previous versions until the branch merges. If the adoption's commit is refused (its hooks typecheck), the branch is deleted and the summary says to adopt by hand.
89
89
  3. **Promote.** At the end of each run a candidate is blessed (moved into its lane's section) unless something holds it: its lane stopped; a repo has an adoption branch for it that is not yet on its default branch (opened this run, unmerged, or committed but never pushed); or a repo that declares it was not walked to an outcome this run — another lane's checkout, a skipped or failed one, a consumer without a checkout. A later train finds a waiting adoption branch and opens nothing new; once it merges, the repo is on the candidate and the train promotes it. A candidate every dependent already accepts is blessed in the run that published it. An adoption PR closed without merging holds its candidates until its branch is deleted.
90
90
 
91
91
  The summary lists what was blessed, every candidate with what holds it, and each pending adoption branch with its PR when `gh` can find one.
package/dist/cli.js CHANGED
@@ -2,7 +2,15 @@
2
2
 
3
3
  // src/cli.ts
4
4
  import { spawnSync as spawnSync2 } from "child_process";
5
- import { existsSync as existsSync2, mkdtempSync, readdirSync as readdirSync2, readFileSync as readFileSync2, rmSync as rmSync2, writeFileSync as writeFileSync2 } from "fs";
5
+ import {
6
+ existsSync as existsSync2,
7
+ mkdirSync as mkdirSync2,
8
+ mkdtempSync,
9
+ readdirSync as readdirSync2,
10
+ readFileSync as readFileSync2,
11
+ rmSync as rmSync2,
12
+ writeFileSync as writeFileSync2
13
+ } from "fs";
6
14
  import { hostname as hostname2, tmpdir } from "os";
7
15
  import { basename, dirname as dirname2, join as join2, resolve as resolve2 } from "path";
8
16
 
@@ -1266,10 +1274,16 @@ if (command === "train") {
1266
1274
  const waiting = [];
1267
1275
  const walked = /* @__PURE__ */ new Set();
1268
1276
  const worktrees = [];
1277
+ const removeWorktree = ({ repo, path, tooling }) => {
1278
+ if (tooling) {
1279
+ spawnSync2("bun", ["run", "worktree:destroy", basename(path), "--force"], {
1280
+ cwd: repo,
1281
+ stdio: "inherit"
1282
+ });
1283
+ } else git(repo, "worktree", "remove", "--force", path);
1284
+ };
1269
1285
  process.on("exit", () => {
1270
- for (const { repo, path } of worktrees.splice(0)) {
1271
- git(repo, "worktree", "remove", "--force", path);
1272
- }
1286
+ for (const entry of worktrees.splice(0)) removeWorktree(entry);
1273
1287
  });
1274
1288
  const target = () => adoptionTarget(manifest);
1275
1289
  const ready = (checkout) => {
@@ -1337,7 +1351,8 @@ if (command === "train") {
1337
1351
  };
1338
1352
  };
1339
1353
  const relockAndCheck = (checkout, check = true) => effect(`re-lock ${checkout.name}${check ? " and run its check" : ""}`, void 0, () => {
1340
- if (spawnSync2("bun", ["install"], { cwd: checkout.dir, stdio: "inherit" }).status !== 0) {
1354
+ const install = (...flags) => spawnSync2("bun", ["install", ...flags], { cwd: checkout.dir, stdio: "inherit" }).status === 0;
1355
+ if (!install() && !install("--no-cache")) {
1341
1356
  throw new Abort(`bun install failed in ${checkout.name}`);
1342
1357
  }
1343
1358
  for (const { cwd, names } of staleUpdates(
@@ -1384,15 +1399,29 @@ if (command === "train") {
1384
1399
  return true;
1385
1400
  };
1386
1401
  const worktree = (checkout, branch) => {
1387
- const path = join2(mkdtempSync(join2(tmpdir(), "inixiative-train-")), basename(checkout.dir));
1388
- if (git(checkout.dir, "worktree", "add", "--quiet", "-b", branch, path, "HEAD").status !== 0) {
1389
- throw new Abort(`could not create ${branch} in ${checkout.name}`);
1390
- }
1391
- worktrees.push({ repo: checkout.dir, path });
1392
- for (const name of readdirSync2(checkout.dir)) {
1393
- if (/^\.env(\..+)?$/.test(name) && !existsSync2(join2(path, name))) {
1394
- writeFileSync2(join2(path, name), readFileSync2(join2(checkout.dir, name)));
1395
- }
1402
+ const tooling = !!checkout.pkg.scripts?.["worktree:create"];
1403
+ const path = tooling ? join2(checkout.dir, ".worktrees", branch.replaceAll("/", "-")) : join2(mkdtempSync(join2(tmpdir(), "inixiative-train-")), basename(checkout.dir));
1404
+ const created = tooling ? spawnSync2("bun", ["run", "worktree:create", defaultBranch(checkout.dir), branch], {
1405
+ cwd: checkout.dir,
1406
+ stdio: "inherit"
1407
+ }).status === 0 && existsSync2(path) : git(checkout.dir, "worktree", "add", "--quiet", "-b", branch, path, "HEAD").status === 0;
1408
+ if (!created) throw new Abort(`could not create ${branch} in ${checkout.name}`);
1409
+ worktrees.push({ repo: checkout.dir, path, tooling });
1410
+ const envFiles = git(
1411
+ checkout.dir,
1412
+ "ls-files",
1413
+ "--others",
1414
+ "--ignored",
1415
+ "--exclude-standard",
1416
+ "--",
1417
+ ":(glob)**/.env*"
1418
+ ).stdout.split("\n").filter(
1419
+ (file) => /(^|\/)\.env[^/]*$/.test(file) && !/(^|\/)(node_modules|\.worktrees)\//.test(file)
1420
+ );
1421
+ for (const file of envFiles) {
1422
+ if (existsSync2(join2(path, file))) continue;
1423
+ mkdirSync2(dirname2(join2(path, file)), { recursive: true });
1424
+ writeFileSync2(join2(path, file), readFileSync2(join2(checkout.dir, file)));
1396
1425
  }
1397
1426
  return { ...checkout, dir: path };
1398
1427
  };
@@ -1401,7 +1430,7 @@ if (command === "train") {
1401
1430
  (tree) => tree.repo === checkout.dir && currentBranch(tree.path) === branch
1402
1431
  );
1403
1432
  if (entry) {
1404
- git(checkout.dir, "worktree", "remove", "--force", entry.path);
1433
+ removeWorktree(entry);
1405
1434
  worktrees.splice(worktrees.indexOf(entry), 1);
1406
1435
  }
1407
1436
  git(checkout.dir, "branch", "-D", branch);
@@ -1425,6 +1454,7 @@ if (command === "train") {
1425
1454
  relockAndCheck(branchCheckout, false);
1426
1455
  const message = moving.length > 0 ? `chore: adopt ${moving.map((name) => `${name}@${manifest.candidates?.[name]}`).join(", ")}` : void 0;
1427
1456
  if (!commitOwned(branchCheckout, packagePaths, true, message)) {
1457
+ console.log(`\u2713 nothing to commit for ${checkout.name} after its re-lock`);
1428
1458
  dropBranch(checkout, branch);
1429
1459
  return false;
1430
1460
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inixiative/config",
3
- "version": "0.5.81",
3
+ "version": "0.5.83",
4
4
  "description": "Shared toolchain for the inixiative ecosystem: tsconfig/biome/tsup presets, a version manifest (BOM), and a sync/check CLI",
5
5
  "type": "module",
6
6
  "license": "MIT",
package/versions.json CHANGED
@@ -13,7 +13,7 @@
13
13
  "@types/bun"
14
14
  ],
15
15
  "ecosystem": {
16
- "@inixiative/config": "0.5.81",
16
+ "@inixiative/config": "0.5.83",
17
17
  "@inixiative/json-rules": "3.5.4",
18
18
  "@inixiative/permissions": "0.4.0",
19
19
  "@inixiative/transitions": "0.5.0",
@@ -24,8 +24,8 @@
24
24
  },
25
25
  "agentic": {
26
26
  "@inixiative/signet": "0.4.0",
27
- "@inixiative/archive": "0.18.0",
28
- "@inixiative/agent-session": "0.6.3",
27
+ "@inixiative/archive": "0.19.0",
28
+ "@inixiative/agent-session": "0.6.4",
29
29
  "@inixiative/foundry-core": "0.5.1",
30
30
  "@inixiative/foundry": "0.5.3",
31
31
  "@inixiative/foundry-acp": "0.1.1"
@@ -48,8 +48,5 @@
48
48
  "agentic"
49
49
  ]
50
50
  }
51
- },
52
- "candidates": {
53
- "@inixiative/archive": "0.19.0"
54
51
  }
55
52
  }