@geonosis/ratchet 2.5.0 → 2.5.2
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/CHANGELOG.md +21 -0
- package/bin/geonosis-ratchet.mjs +11 -3
- package/dist/{chunk-2EAYMSC5.js → chunk-WENVCC67.js} +209 -148
- package/dist/cli.js +9 -1
- package/dist/index.d.ts +37 -1
- package/dist/index.js +11 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,26 @@
|
|
|
1
1
|
# @geonosis/ratchet
|
|
2
2
|
|
|
3
|
+
## 2.5.2
|
|
4
|
+
|
|
5
|
+
## 2.5.1
|
|
6
|
+
|
|
7
|
+
### Patch Changes
|
|
8
|
+
|
|
9
|
+
- 7f24da6: A machine-wide heavy budget, two slots, held by every tool that spends one (#385): measured load 48
|
|
10
|
+
with during.day's Stop-hook tier, this kit's Stop-hook tier, its ratchet and an engineer's suite all
|
|
11
|
+
running at once — nothing held the two-slot budget across the two repos, and three kit tests read
|
|
12
|
+
red under it that were green alone. `@geonosis/ratchet` ships `takeSlot`/`heavySlotDir` (a lock
|
|
13
|
+
directory under `os.tmpdir()/geonosis-heavy`, two slot files each holding `{ pid, command, cwd,
|
|
14
|
+
startedAt }`, a dead holder reaped on the next take, a taker that finds both held waiting once
|
|
15
|
+
before refusing naming them); `geonosis-verify` (each tier run) and `geonosis-ratchet` (the run, not
|
|
16
|
+
`--prove`'s inner unit) take a slot for the run's duration. `@geonosis/release`'s `smoke
|
|
17
|
+
baseline`/`smoke run` take one too, from their own copy (this layer imports nothing, same posture as
|
|
18
|
+
`envelope.ts`). The plugin's Stop hook reads a fresh green `gate-report.<tier>.json` — its own
|
|
19
|
+
recorded commit equal to the current `HEAD` with a clean tree — and reports PASS without re-running;
|
|
20
|
+
otherwise it peeks the same two slots (never claims one itself, or the verify child it is about to
|
|
21
|
+
spawn would be racing against its own reservation) and blocks naming both holders rather than
|
|
22
|
+
running a third tier.
|
|
23
|
+
|
|
3
24
|
## 2.5.0
|
|
4
25
|
|
|
5
26
|
## 2.4.3
|
package/bin/geonosis-ratchet.mjs
CHANGED
|
@@ -9,11 +9,19 @@ import { dirname, join } from 'node:path'
|
|
|
9
9
|
import { fileURLToPath } from 'node:url'
|
|
10
10
|
|
|
11
11
|
const here = dirname(fileURLToPath(import.meta.url))
|
|
12
|
-
|
|
12
|
+
// tsup never reads a test file, so one counting as source made every bin refuse a build that had
|
|
13
|
+
// not gone stale (#399).
|
|
14
|
+
const NOT_SOURCE = (name) =>
|
|
15
|
+
name.endsWith('.test.ts') ||
|
|
16
|
+
name.endsWith('.test.tsx') ||
|
|
17
|
+
name === '__tests__' ||
|
|
18
|
+
name === '__fixtures__'
|
|
19
|
+
const newest = (dir, skip) =>
|
|
13
20
|
existsSync(dir)
|
|
14
21
|
? readdirSync(dir, { withFileTypes: true }).reduce((most, entry) => {
|
|
22
|
+
if (skip !== undefined && skip(entry.name)) return most
|
|
15
23
|
const at = join(dir, entry.name)
|
|
16
|
-
return Math.max(most, entry.isDirectory() ? newest(at) : statSync(at).mtimeMs)
|
|
24
|
+
return Math.max(most, entry.isDirectory() ? newest(at, skip) : statSync(at).mtimeMs)
|
|
17
25
|
}, 0)
|
|
18
26
|
: 0
|
|
19
27
|
const src = join(here, '..', 'src')
|
|
@@ -30,7 +38,7 @@ if (existsSync(src)) {
|
|
|
30
38
|
)
|
|
31
39
|
process.exit(2)
|
|
32
40
|
}
|
|
33
|
-
if (newest(src) > built) {
|
|
41
|
+
if (newest(src, NOT_SOURCE) > built) {
|
|
34
42
|
process.stderr.write(
|
|
35
43
|
'geonosis-ratchet: dist is older than src — run pnpm build before trusting this bin.\n',
|
|
36
44
|
)
|
|
@@ -70,23 +70,53 @@ var versionOf = (moduleUrl) => {
|
|
|
70
70
|
}
|
|
71
71
|
};
|
|
72
72
|
|
|
73
|
-
// src/core/
|
|
73
|
+
// src/core/heavy-slot.ts
|
|
74
|
+
import { readFileSync as readFileSync2, rmSync as rmSync2 } from "fs";
|
|
75
|
+
import { tmpdir } from "os";
|
|
76
|
+
import { join as join2 } from "path";
|
|
77
|
+
|
|
78
|
+
// src/core/file-claim.ts
|
|
74
79
|
import { randomUUID } from "crypto";
|
|
75
|
-
import { linkSync, mkdirSync as mkdirSync2,
|
|
76
|
-
import {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
80
|
+
import { linkSync, mkdirSync as mkdirSync2, rmSync, writeFileSync as writeFileSync2 } from "fs";
|
|
81
|
+
import { dirname as dirname2 } from "path";
|
|
82
|
+
var alive = (pid) => {
|
|
83
|
+
try {
|
|
84
|
+
process.kill(pid, 0);
|
|
85
|
+
return true;
|
|
86
|
+
} catch (error) {
|
|
87
|
+
return error.code === "EPERM";
|
|
88
|
+
}
|
|
84
89
|
};
|
|
85
90
|
var sleep = (ms) => new Promise((done) => setTimeout(done, ms));
|
|
91
|
+
var claimFile = (path, holder) => {
|
|
92
|
+
mkdirSync2(dirname2(path), { recursive: true });
|
|
93
|
+
const staging = `${path}.${holder.pid}.${randomUUID()}`;
|
|
94
|
+
try {
|
|
95
|
+
writeFileSync2(staging, JSON.stringify(holder));
|
|
96
|
+
linkSync(staging, path);
|
|
97
|
+
return true;
|
|
98
|
+
} catch (error) {
|
|
99
|
+
if (error.code === "EEXIST") return false;
|
|
100
|
+
throw error;
|
|
101
|
+
} finally {
|
|
102
|
+
rmSync(staging, { force: true });
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
// src/core/heavy-slot.ts
|
|
107
|
+
var HEAVY_SLOTS = 2;
|
|
108
|
+
var DEFAULT_WAIT_MS = 20 * 6e4;
|
|
109
|
+
var heavySlotDir = () => {
|
|
110
|
+
const named = process.env.GEONOSIS_HEAVY_SLOT_DIR;
|
|
111
|
+
if (named !== void 0 && named !== "") return named;
|
|
112
|
+
return join2(tmpdir(), "geonosis-heavy");
|
|
113
|
+
};
|
|
114
|
+
var slotPath = (dir, at) => join2(dir, `slot-${at}.json`);
|
|
86
115
|
var holderOf = (path) => {
|
|
87
116
|
try {
|
|
88
117
|
const parsed = JSON.parse(readFileSync2(path, "utf8"));
|
|
89
118
|
return typeof parsed.pid === "number" ? {
|
|
119
|
+
command: parsed.command ?? "unknown",
|
|
90
120
|
cwd: parsed.cwd ?? "somewhere",
|
|
91
121
|
pid: parsed.pid,
|
|
92
122
|
startedAt: parsed.startedAt ?? "unknown"
|
|
@@ -95,12 +125,79 @@ var holderOf = (path) => {
|
|
|
95
125
|
return void 0;
|
|
96
126
|
}
|
|
97
127
|
};
|
|
98
|
-
var
|
|
128
|
+
var reapIfDead = (path) => {
|
|
129
|
+
const holder = holderOf(path);
|
|
130
|
+
if (holder !== void 0 && !alive(holder.pid)) rmSync2(path, { force: true });
|
|
131
|
+
};
|
|
132
|
+
var claim = (path, holder) => claimFile(path, holder);
|
|
133
|
+
var namedHolders = (dir) => Array.from({ length: HEAVY_SLOTS }, (_unused, at) => holderOf(slotPath(dir, at))).filter(
|
|
134
|
+
(holder) => holder !== void 0
|
|
135
|
+
);
|
|
136
|
+
var describeHolders = (holders) => holders.map((one) => `${one.pid} ${one.command} since ${one.startedAt}`).join(", ");
|
|
137
|
+
var HeavySlotTimeout = class extends Error {
|
|
138
|
+
};
|
|
139
|
+
var takeSlot = async ({
|
|
140
|
+
command,
|
|
141
|
+
cwd = process.cwd(),
|
|
142
|
+
dir = heavySlotDir(),
|
|
143
|
+
pollMs = 250,
|
|
144
|
+
say = (line) => process.stderr.write(`${line}
|
|
145
|
+
`),
|
|
146
|
+
waitMs = Number(process.env.GEONOSIS_HEAVY_WAIT_MS ?? "") || DEFAULT_WAIT_MS
|
|
147
|
+
}) => {
|
|
148
|
+
const until = Date.now() + waitMs;
|
|
149
|
+
let told = false;
|
|
150
|
+
for (; ; ) {
|
|
151
|
+
for (let at = 0; at < HEAVY_SLOTS; at += 1) {
|
|
152
|
+
const path = slotPath(dir, at);
|
|
153
|
+
reapIfDead(path);
|
|
154
|
+
const mine = {
|
|
155
|
+
command,
|
|
156
|
+
cwd,
|
|
157
|
+
pid: process.pid,
|
|
158
|
+
startedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
159
|
+
};
|
|
160
|
+
if (claim(path, mine)) {
|
|
161
|
+
return () => {
|
|
162
|
+
if (holderOf(path)?.pid === process.pid) rmSync2(path, { force: true });
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
const holders = namedHolders(dir);
|
|
167
|
+
if (!told) {
|
|
168
|
+
told = true;
|
|
169
|
+
say(`waiting for a heavy slot: ${holders.length} held \u2014 ${describeHolders(holders)}`);
|
|
170
|
+
}
|
|
171
|
+
if (Date.now() >= until) {
|
|
172
|
+
throw new HeavySlotTimeout(
|
|
173
|
+
`waited ${waitMs} ms for a heavy slot: ${holders.length} held \u2014 ${describeHolders(holders)}`
|
|
174
|
+
);
|
|
175
|
+
}
|
|
176
|
+
await sleep(pollMs);
|
|
177
|
+
}
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
// src/core/lock.ts
|
|
181
|
+
import { readFileSync as readFileSync3, rmSync as rmSync3 } from "fs";
|
|
182
|
+
import { homedir } from "os";
|
|
183
|
+
import { isAbsolute, join as join3 } from "path";
|
|
184
|
+
var heavyLockPath = () => {
|
|
185
|
+
const named = process.env.GEONOSIS_HEAVY_LOCK;
|
|
186
|
+
if (named !== void 0 && named !== "") return named;
|
|
187
|
+
const declared = process.env.XDG_CACHE_HOME;
|
|
188
|
+
const cache = declared !== void 0 && isAbsolute(declared) ? declared : join3(homedir(), ".cache");
|
|
189
|
+
return join3(cache, "geonosis", "heavy.lock");
|
|
190
|
+
};
|
|
191
|
+
var holderOf2 = (path) => {
|
|
99
192
|
try {
|
|
100
|
-
|
|
101
|
-
return
|
|
102
|
-
|
|
103
|
-
|
|
193
|
+
const parsed = JSON.parse(readFileSync3(path, "utf8"));
|
|
194
|
+
return typeof parsed.pid === "number" ? {
|
|
195
|
+
cwd: parsed.cwd ?? "somewhere",
|
|
196
|
+
pid: parsed.pid,
|
|
197
|
+
startedAt: parsed.startedAt ?? "unknown"
|
|
198
|
+
} : void 0;
|
|
199
|
+
} catch {
|
|
200
|
+
return void 0;
|
|
104
201
|
}
|
|
105
202
|
};
|
|
106
203
|
var heldFor = (holder) => {
|
|
@@ -108,25 +205,7 @@ var heldFor = (holder) => {
|
|
|
108
205
|
if (Number.isNaN(since)) return "an unknown time";
|
|
109
206
|
return `${Math.round((Date.now() - since) / 1e3)}s`;
|
|
110
207
|
};
|
|
111
|
-
var write = (path) => {
|
|
112
|
-
mkdirSync2(dirname2(path), { recursive: true });
|
|
113
|
-
const mine = {
|
|
114
|
-
cwd: process.cwd(),
|
|
115
|
-
pid: process.pid,
|
|
116
|
-
startedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
117
|
-
};
|
|
118
|
-
const staging = `${path}.${process.pid}.${randomUUID()}`;
|
|
119
|
-
try {
|
|
120
|
-
writeFileSync2(staging, JSON.stringify(mine));
|
|
121
|
-
linkSync(staging, path);
|
|
122
|
-
return true;
|
|
123
|
-
} catch (error) {
|
|
124
|
-
if (error.code === "EEXIST") return false;
|
|
125
|
-
throw error;
|
|
126
|
-
} finally {
|
|
127
|
-
rmSync(staging, { force: true });
|
|
128
|
-
}
|
|
129
|
-
};
|
|
208
|
+
var write = (path) => claimFile(path, { cwd: process.cwd(), pid: process.pid, startedAt: (/* @__PURE__ */ new Date()).toISOString() });
|
|
130
209
|
var acquireExclusive = async ({
|
|
131
210
|
noticeMs = 15e3,
|
|
132
211
|
path = heavyLockPath(),
|
|
@@ -138,16 +217,16 @@ var acquireExclusive = async ({
|
|
|
138
217
|
const until = Date.now() + timeoutSeconds * 1e3;
|
|
139
218
|
let told = 0;
|
|
140
219
|
const release = () => {
|
|
141
|
-
if (
|
|
220
|
+
if (holderOf2(path)?.pid === process.pid) rmSync3(path, { force: true });
|
|
142
221
|
};
|
|
143
222
|
for (; ; ) {
|
|
144
223
|
if (write(path)) return release;
|
|
145
|
-
const holder =
|
|
224
|
+
const holder = holderOf2(path);
|
|
146
225
|
if (holder === void 0 || !alive(holder.pid)) {
|
|
147
226
|
say(
|
|
148
227
|
`geonosis-ratchet: taking over a stale heavy lock (pid ${holder?.pid ?? "unreadable"} is gone)`
|
|
149
228
|
);
|
|
150
|
-
|
|
229
|
+
rmSync3(path, { force: true });
|
|
151
230
|
continue;
|
|
152
231
|
}
|
|
153
232
|
if (Date.now() >= until) {
|
|
@@ -167,7 +246,7 @@ var acquireExclusive = async ({
|
|
|
167
246
|
};
|
|
168
247
|
|
|
169
248
|
// src/core/config.ts
|
|
170
|
-
import { existsSync, readFileSync as
|
|
249
|
+
import { existsSync, readFileSync as readFileSync4 } from "fs";
|
|
171
250
|
import { resolve as resolve2 } from "path";
|
|
172
251
|
var CONFIG_FILE = "geonosis.ratchet.json";
|
|
173
252
|
var keyOf = (entry) => entry.key ?? entry.counter;
|
|
@@ -176,7 +255,7 @@ var loadConfig = (cwd) => {
|
|
|
176
255
|
if (!existsSync(path)) {
|
|
177
256
|
throw new Error(`no ${CONFIG_FILE} in ${cwd} \u2014 the ratchet has nothing to count`);
|
|
178
257
|
}
|
|
179
|
-
const parsed = JSON.parse(
|
|
258
|
+
const parsed = JSON.parse(readFileSync4(path, "utf8"));
|
|
180
259
|
if (!Array.isArray(parsed.counters)) {
|
|
181
260
|
throw new Error(`${CONFIG_FILE} has no "counters" array`);
|
|
182
261
|
}
|
|
@@ -204,7 +283,7 @@ var loadConfig = (cwd) => {
|
|
|
204
283
|
};
|
|
205
284
|
var resolveBaseline = (cwd) => {
|
|
206
285
|
try {
|
|
207
|
-
const parsed = JSON.parse(
|
|
286
|
+
const parsed = JSON.parse(readFileSync4(resolve2(cwd, CONFIG_FILE), "utf8"));
|
|
208
287
|
return typeof parsed.baseline === "string" ? parsed.baseline : "gate-baseline.json";
|
|
209
288
|
} catch {
|
|
210
289
|
return "gate-baseline.json";
|
|
@@ -250,9 +329,9 @@ ${output.trim()}`
|
|
|
250
329
|
};
|
|
251
330
|
|
|
252
331
|
// src/core/prove.ts
|
|
253
|
-
import { existsSync as existsSync2, mkdtempSync, rmSync as
|
|
254
|
-
import { tmpdir } from "os";
|
|
255
|
-
import { delimiter, dirname as dirname4, join as
|
|
332
|
+
import { existsSync as existsSync2, mkdtempSync, rmSync as rmSync4, writeFileSync as writeFileSync3 } from "fs";
|
|
333
|
+
import { tmpdir as tmpdir2 } from "os";
|
|
334
|
+
import { delimiter, dirname as dirname4, join as join4, resolve as resolve4 } from "path";
|
|
256
335
|
|
|
257
336
|
// src/core/exclusive.ts
|
|
258
337
|
import { spawn } from "child_process";
|
|
@@ -323,7 +402,7 @@ var toolPath = (cwd) => {
|
|
|
323
402
|
const dirs = [];
|
|
324
403
|
let dir = resolve4(cwd);
|
|
325
404
|
for (; ; ) {
|
|
326
|
-
const bin =
|
|
405
|
+
const bin = join4(dir, "node_modules", ".bin");
|
|
327
406
|
if (existsSync2(bin)) dirs.push(bin);
|
|
328
407
|
const parent = dirname4(dir);
|
|
329
408
|
if (parent === dir) break;
|
|
@@ -333,7 +412,7 @@ var toolPath = (cwd) => {
|
|
|
333
412
|
};
|
|
334
413
|
var NO_PROBE = "no probe \u2014 a counter nobody has seen read a planted finding has not been shown to measure";
|
|
335
414
|
var oneProofOf = async (counter, key, path, probe) => {
|
|
336
|
-
const dir = mkdtempSync(
|
|
415
|
+
const dir = mkdtempSync(join4(tmpdir2(), "geonosis-prove-"));
|
|
337
416
|
try {
|
|
338
417
|
probe.input(dir);
|
|
339
418
|
const command = probe.command?.(dir);
|
|
@@ -351,7 +430,7 @@ var oneProofOf = async (counter, key, path, probe) => {
|
|
|
351
430
|
} catch (error) {
|
|
352
431
|
return { counter: counter.id, key, reason: error.message, verdict: "cannot-measure" };
|
|
353
432
|
} finally {
|
|
354
|
-
|
|
433
|
+
rmSync4(dir, { force: true, recursive: true });
|
|
355
434
|
}
|
|
356
435
|
};
|
|
357
436
|
var probesOf = (counter) => {
|
|
@@ -417,7 +496,7 @@ var runProve = async ({
|
|
|
417
496
|
const entryProbe = {
|
|
418
497
|
command: () => "cat sample.txt",
|
|
419
498
|
expect: declared.expect,
|
|
420
|
-
input: (dir) => writeFileSync3(
|
|
499
|
+
input: (dir) => writeFileSync3(join4(dir, "sample.txt"), sample),
|
|
421
500
|
name: "configured reading",
|
|
422
501
|
params: Object.fromEntries(customized.map((one) => [one, entry[one]]))
|
|
423
502
|
};
|
|
@@ -434,20 +513,20 @@ var runProve = async ({
|
|
|
434
513
|
}
|
|
435
514
|
}
|
|
436
515
|
if (exclusiveVia !== void 0) {
|
|
437
|
-
const dir = mkdtempSync(
|
|
516
|
+
const dir = mkdtempSync(join4(tmpdir2(), "geonosis-lock-"));
|
|
438
517
|
try {
|
|
439
|
-
const proof = await proveExclusive({ cli: exclusiveVia, lockPath:
|
|
518
|
+
const proof = await proveExclusive({ cli: exclusiveVia, lockPath: join4(dir, "heavy.lock") });
|
|
440
519
|
proofs.push(proof);
|
|
441
520
|
if (proof.verdict !== "serialised") return { proofs, proven: false };
|
|
442
521
|
} finally {
|
|
443
|
-
|
|
522
|
+
rmSync4(dir, { force: true, recursive: true });
|
|
444
523
|
}
|
|
445
524
|
}
|
|
446
525
|
return { proofs, proven: true };
|
|
447
526
|
};
|
|
448
527
|
|
|
449
528
|
// src/core/ratchet.ts
|
|
450
|
-
import { existsSync as existsSync3, readFileSync as
|
|
529
|
+
import { existsSync as existsSync3, readFileSync as readFileSync5, writeFileSync as writeFileSync4 } from "fs";
|
|
451
530
|
import { resolve as resolve5 } from "path";
|
|
452
531
|
var EVIDENCE_LINES = 10;
|
|
453
532
|
var recorded = (counter, params, run) => {
|
|
@@ -499,7 +578,7 @@ var runRatchet = async ({
|
|
|
499
578
|
if (!existsSync3(baselinePath)) {
|
|
500
579
|
throw new Error(`no ${config.baseline} in ${cwd} \u2014 nothing to ratchet against`);
|
|
501
580
|
}
|
|
502
|
-
const baseline = JSON.parse(
|
|
581
|
+
const baseline = JSON.parse(readFileSync5(baselinePath, "utf8"));
|
|
503
582
|
const byId = new Map(counters.map((one) => [one.id, one]));
|
|
504
583
|
const measurements = [];
|
|
505
584
|
const refusals = [];
|
|
@@ -581,9 +660,9 @@ var escapeForRegex = (value) => value.replaceAll(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
|
581
660
|
|
|
582
661
|
// src/counters/plant.ts
|
|
583
662
|
import { mkdirSync as mkdirSync3, writeFileSync as writeFileSync5 } from "fs";
|
|
584
|
-
import { dirname as dirname5, join as
|
|
663
|
+
import { dirname as dirname5, join as join5 } from "path";
|
|
585
664
|
var plant = (dir, relative, contents) => {
|
|
586
|
-
const path =
|
|
665
|
+
const path = join5(dir, relative);
|
|
587
666
|
mkdirSync3(dirname5(path), { recursive: true });
|
|
588
667
|
writeFileSync5(path, contents);
|
|
589
668
|
};
|
|
@@ -674,8 +753,8 @@ var bundleBytes = {
|
|
|
674
753
|
};
|
|
675
754
|
|
|
676
755
|
// src/counters/ci.ts
|
|
677
|
-
import { readdirSync, readFileSync as
|
|
678
|
-
import { join as
|
|
756
|
+
import { readdirSync, readFileSync as readFileSync6 } from "fs";
|
|
757
|
+
import { join as join6, resolve as resolve6 } from "path";
|
|
679
758
|
var DISABLED = /\bif:[ \t]*false\b/;
|
|
680
759
|
var WORKFLOW = /\.ya?ml$/;
|
|
681
760
|
var disabledCiJobs = {
|
|
@@ -693,7 +772,7 @@ var disabledCiJobs = {
|
|
|
693
772
|
const dir = resolve6(cwd, relative);
|
|
694
773
|
let files;
|
|
695
774
|
try {
|
|
696
|
-
files = readdirSync(dir, { withFileTypes: true }).filter((entry) => WORKFLOW.test(entry.name)).map((entry) =>
|
|
775
|
+
files = readdirSync(dir, { withFileTypes: true }).filter((entry) => WORKFLOW.test(entry.name)).map((entry) => join6(dir, entry.name));
|
|
697
776
|
} catch {
|
|
698
777
|
return 0;
|
|
699
778
|
}
|
|
@@ -701,7 +780,7 @@ var disabledCiJobs = {
|
|
|
701
780
|
for (const file of files) {
|
|
702
781
|
let contents;
|
|
703
782
|
try {
|
|
704
|
-
contents =
|
|
783
|
+
contents = readFileSync6(file, "utf8");
|
|
705
784
|
} catch (error) {
|
|
706
785
|
throw new CounterError(
|
|
707
786
|
"disabledCiJobs",
|
|
@@ -790,10 +869,10 @@ ${said.slice(-500)}`
|
|
|
790
869
|
return Number(found);
|
|
791
870
|
}
|
|
792
871
|
};
|
|
793
|
-
var
|
|
872
|
+
var HEADING_LINE = /^([A-Z][A-Za-z ]+?) \((\d+)\)\s*$/;
|
|
794
873
|
var headingsIn = (output) => {
|
|
795
874
|
const found = /* @__PURE__ */ new Map();
|
|
796
|
-
for (const [, heading = "", count = "0"] of output.matchAll(
|
|
875
|
+
for (const [, heading = "", count = "0"] of output.matchAll(new RegExp(HEADING_LINE, "gm"))) {
|
|
797
876
|
found.set(heading, Number(count));
|
|
798
877
|
}
|
|
799
878
|
return found;
|
|
@@ -804,7 +883,6 @@ var excusesIn = (params) => {
|
|
|
804
883
|
typeof declared === "object" && declared !== null && !Array.isArray(declared) ? Object.keys(declared) : []
|
|
805
884
|
);
|
|
806
885
|
};
|
|
807
|
-
var HEADING_LINE = /^([A-Z][A-Za-z ]+?) \((\d+)\)\s*$/;
|
|
808
886
|
var UNRESOLVED = "Unresolved imports";
|
|
809
887
|
var KNIP_DEFAULT = "npx knip --reporter compact";
|
|
810
888
|
var knipEvidence = ({
|
|
@@ -864,7 +942,7 @@ var boundaryIssues = {
|
|
|
864
942
|
};
|
|
865
943
|
|
|
866
944
|
// src/counters/dx.ts
|
|
867
|
-
import { existsSync as existsSync4, readFileSync as
|
|
945
|
+
import { existsSync as existsSync4, readFileSync as readFileSync7 } from "fs";
|
|
868
946
|
import { resolve as resolve7 } from "path";
|
|
869
947
|
var DEFAULT_BUMP_REPORT = ".geonosis/bump-report.json";
|
|
870
948
|
var bumpFile = (id, cwd, params) => {
|
|
@@ -877,7 +955,7 @@ var bumpFile = (id, cwd, params) => {
|
|
|
877
955
|
);
|
|
878
956
|
}
|
|
879
957
|
try {
|
|
880
|
-
return JSON.parse(
|
|
958
|
+
return JSON.parse(readFileSync7(path, "utf8"));
|
|
881
959
|
} catch (error) {
|
|
882
960
|
throw new CounterError(id, `${relative} is not readable JSON: ${error.message}`);
|
|
883
961
|
}
|
|
@@ -963,7 +1041,7 @@ var openBacklogRows = {
|
|
|
963
1041
|
if (!existsSync4(at)) {
|
|
964
1042
|
throw new CounterError("openBacklogRows", `no register at ${relative}`);
|
|
965
1043
|
}
|
|
966
|
-
const lines =
|
|
1044
|
+
const lines = readFileSync7(at, "utf8").split("\n");
|
|
967
1045
|
return lines.filter((line, index) => {
|
|
968
1046
|
if (!ROW.test(line) || SEPARATOR.test(line)) return false;
|
|
969
1047
|
if (SEPARATOR.test(lines[index + 1] ?? "")) return false;
|
|
@@ -995,7 +1073,7 @@ var unformattedFiles = {
|
|
|
995
1073
|
};
|
|
996
1074
|
|
|
997
1075
|
// src/counters/gate-report.ts
|
|
998
|
-
import { existsSync as existsSync6, readFileSync as
|
|
1076
|
+
import { existsSync as existsSync6, readFileSync as readFileSync8 } from "fs";
|
|
999
1077
|
import { resolve as resolve9 } from "path";
|
|
1000
1078
|
var DEFAULT_REPORT = ".geonosis/gate-report.json";
|
|
1001
1079
|
var fastTierMs = {
|
|
@@ -1029,7 +1107,7 @@ var fastTierMs = {
|
|
|
1029
1107
|
}
|
|
1030
1108
|
let report;
|
|
1031
1109
|
try {
|
|
1032
|
-
report = JSON.parse(
|
|
1110
|
+
report = JSON.parse(readFileSync8(path, "utf8"));
|
|
1033
1111
|
} catch (error) {
|
|
1034
1112
|
throw new CounterError(
|
|
1035
1113
|
"fastTierMs",
|
|
@@ -1051,7 +1129,7 @@ var fastTierMs = {
|
|
|
1051
1129
|
};
|
|
1052
1130
|
|
|
1053
1131
|
// src/counters/law.ts
|
|
1054
|
-
import { existsSync as existsSync7, readFileSync as
|
|
1132
|
+
import { existsSync as existsSync7, readFileSync as readFileSync9 } from "fs";
|
|
1055
1133
|
import { resolve as resolve10 } from "path";
|
|
1056
1134
|
var lawLineCount = {
|
|
1057
1135
|
id: "lawLineCount",
|
|
@@ -1064,12 +1142,12 @@ var lawLineCount = {
|
|
|
1064
1142
|
const relative = stringParam("lawLineCount", params, "path", "CLAUDE.md");
|
|
1065
1143
|
const path = resolve10(cwd, relative);
|
|
1066
1144
|
if (!existsSync7(path)) throw new CounterError("lawLineCount", `no law file at ${relative}`);
|
|
1067
|
-
return
|
|
1145
|
+
return readFileSync9(path, "utf8").replace(/\n$/, "").split("\n").length;
|
|
1068
1146
|
}
|
|
1069
1147
|
};
|
|
1070
1148
|
|
|
1071
1149
|
// src/counters/oxlint.ts
|
|
1072
|
-
import { existsSync as existsSync8, readFileSync as
|
|
1150
|
+
import { existsSync as existsSync8, readFileSync as readFileSync10, rmSync as rmSync5, writeFileSync as writeFileSync6 } from "fs";
|
|
1073
1151
|
import { resolve as resolve11 } from "path";
|
|
1074
1152
|
var DEFAULT_COMMAND = "npx oxlint --format=unix --config .oxlintrc.json .";
|
|
1075
1153
|
var PROBE_COMMAND = "oxlint --format=unix --config .oxlintrc.json .";
|
|
@@ -1236,7 +1314,7 @@ var oxlintRule = {
|
|
|
1236
1314
|
const source = resolve11(cwd, config);
|
|
1237
1315
|
if (!existsSync8(source)) throw new CounterError("oxlintRule", `no config at ${config}`);
|
|
1238
1316
|
const strictName = `.oxlintrc.ratchet-${key}.json`;
|
|
1239
|
-
const strict =
|
|
1317
|
+
const strict = readFileSync10(source, "utf8").replace(
|
|
1240
1318
|
new RegExp(`("[^"]*${escapeForRegex(rule)}"\\s*:\\s*\\[?\\s*)"(warn|off)"`),
|
|
1241
1319
|
'$1"error"'
|
|
1242
1320
|
);
|
|
@@ -1244,15 +1322,15 @@ var oxlintRule = {
|
|
|
1244
1322
|
try {
|
|
1245
1323
|
return countRule(run(command.replace("{config}", strictName)), rule, expect);
|
|
1246
1324
|
} finally {
|
|
1247
|
-
|
|
1325
|
+
rmSync5(resolve11(cwd, strictName), { force: true });
|
|
1248
1326
|
}
|
|
1249
1327
|
}
|
|
1250
1328
|
};
|
|
1251
1329
|
|
|
1252
1330
|
// src/counters/probes.ts
|
|
1253
|
-
import { existsSync as existsSync9, readFileSync as
|
|
1331
|
+
import { existsSync as existsSync9, readFileSync as readFileSync11 } from "fs";
|
|
1254
1332
|
import { createRequire } from "module";
|
|
1255
|
-
import { join as
|
|
1333
|
+
import { join as join7, resolve as resolve12 } from "path";
|
|
1256
1334
|
import { pathToFileURL } from "url";
|
|
1257
1335
|
var ID2 = "probelessRules";
|
|
1258
1336
|
var OFF = /* @__PURE__ */ new Set([0, "0", "allow", "off", false]);
|
|
@@ -1274,7 +1352,7 @@ var enabledIn = (config, namespace) => {
|
|
|
1274
1352
|
var probedBy = async (cwd, plugin) => {
|
|
1275
1353
|
let entry;
|
|
1276
1354
|
try {
|
|
1277
|
-
entry = createRequire(
|
|
1355
|
+
entry = createRequire(join7(cwd, "noop.js")).resolve(plugin);
|
|
1278
1356
|
} catch (error) {
|
|
1279
1357
|
throw new CounterError(
|
|
1280
1358
|
ID2,
|
|
@@ -1334,7 +1412,7 @@ var probelessRules = {
|
|
|
1334
1412
|
if (!existsSync9(path)) throw new CounterError(ID2, `no oxlint config at ${relative}`);
|
|
1335
1413
|
let config;
|
|
1336
1414
|
try {
|
|
1337
|
-
config = JSON.parse(
|
|
1415
|
+
config = JSON.parse(readFileSync11(path, "utf8"));
|
|
1338
1416
|
} catch (error) {
|
|
1339
1417
|
throw new CounterError(ID2, `${relative} does not parse: ${error.message}`);
|
|
1340
1418
|
}
|
|
@@ -1368,15 +1446,15 @@ var runtimeCodeShipped = {
|
|
|
1368
1446
|
|
|
1369
1447
|
// src/counters/scripts.ts
|
|
1370
1448
|
import { readdirSync as readdirSync3 } from "fs";
|
|
1371
|
-
import { join as
|
|
1449
|
+
import { join as join9 } from "path";
|
|
1372
1450
|
|
|
1373
1451
|
// src/counters/workspace.ts
|
|
1374
|
-
import { existsSync as existsSync10, readdirSync as readdirSync2, readFileSync as
|
|
1375
|
-
import { join as
|
|
1452
|
+
import { existsSync as existsSync10, readdirSync as readdirSync2, readFileSync as readFileSync12 } from "fs";
|
|
1453
|
+
import { join as join8, resolve as resolve13 } from "path";
|
|
1376
1454
|
var SKIP = /^(node_modules|\.)/;
|
|
1377
1455
|
var childDirs = (dir) => {
|
|
1378
1456
|
try {
|
|
1379
|
-
return readdirSync2(dir, { withFileTypes: true }).filter((entry) => entry.isDirectory() && !SKIP.test(entry.name)).map((entry) =>
|
|
1457
|
+
return readdirSync2(dir, { withFileTypes: true }).filter((entry) => entry.isDirectory() && !SKIP.test(entry.name)).map((entry) => join8(dir, entry.name));
|
|
1380
1458
|
} catch {
|
|
1381
1459
|
return [];
|
|
1382
1460
|
}
|
|
@@ -1386,14 +1464,14 @@ var expand = (root, pattern) => {
|
|
|
1386
1464
|
const segments = pattern.split("/").filter((one) => one !== "" && one !== ".");
|
|
1387
1465
|
let dirs = [root];
|
|
1388
1466
|
for (const segment of segments) {
|
|
1389
|
-
dirs = segment === "*" ? dirs.flatMap((dir) => childDirs(dir)) : segment === "**" ? dirs.flatMap((dir) => descendants(dir, 3)) : dirs.map((dir) =>
|
|
1467
|
+
dirs = segment === "*" ? dirs.flatMap((dir) => childDirs(dir)) : segment === "**" ? dirs.flatMap((dir) => descendants(dir, 3)) : dirs.map((dir) => join8(dir, segment)).filter((dir) => existsSync10(dir));
|
|
1390
1468
|
}
|
|
1391
1469
|
return dirs;
|
|
1392
1470
|
};
|
|
1393
1471
|
var QUOTED = /^['"]|['"]$/g;
|
|
1394
1472
|
var cleaned = (value) => value.replace(/#.*$/, "").trim().replaceAll(QUOTED, "");
|
|
1395
1473
|
var pnpmPatterns = (path) => {
|
|
1396
|
-
const lines =
|
|
1474
|
+
const lines = readFileSync12(path, "utf8").split("\n");
|
|
1397
1475
|
const at = lines.findIndex((line) => line.startsWith("packages:"));
|
|
1398
1476
|
if (at === -1) return [];
|
|
1399
1477
|
const inline = lines[at]?.slice("packages:".length).trim() ?? "";
|
|
@@ -1412,31 +1490,25 @@ var pnpmPatterns = (path) => {
|
|
|
1412
1490
|
return patterns;
|
|
1413
1491
|
};
|
|
1414
1492
|
var npmPatterns = (path) => {
|
|
1415
|
-
const parsed = JSON.parse(
|
|
1493
|
+
const parsed = JSON.parse(readFileSync12(path, "utf8"));
|
|
1416
1494
|
const declared = Array.isArray(parsed.workspaces) ? parsed.workspaces : parsed.workspaces?.packages ?? [];
|
|
1417
1495
|
return declared.filter((one) => typeof one === "string");
|
|
1418
1496
|
};
|
|
1419
1497
|
var nameOf = (dir) => {
|
|
1420
|
-
const
|
|
1421
|
-
|
|
1422
|
-
try {
|
|
1423
|
-
const { name } = JSON.parse(readFileSync11(manifest, "utf8"));
|
|
1424
|
-
return typeof name === "string" && name !== "" ? name : void 0;
|
|
1425
|
-
} catch {
|
|
1426
|
-
return void 0;
|
|
1427
|
-
}
|
|
1498
|
+
const name = manifestOf(dir)?.["name"];
|
|
1499
|
+
return typeof name === "string" && name !== "" ? name : void 0;
|
|
1428
1500
|
};
|
|
1429
1501
|
var workspaceDirs = (cwd) => {
|
|
1430
1502
|
const root = resolve13(cwd);
|
|
1431
|
-
const pnpm =
|
|
1432
|
-
const manifest =
|
|
1503
|
+
const pnpm = join8(root, "pnpm-workspace.yaml");
|
|
1504
|
+
const manifest = join8(root, "package.json");
|
|
1433
1505
|
const patterns = existsSync10(pnpm) ? pnpmPatterns(pnpm) : existsSync10(manifest) ? npmPatterns(manifest) : [];
|
|
1434
|
-
const dirs = patterns.filter((pattern) => !pattern.startsWith("!")).flatMap((pattern) => expand(root, pattern)).filter((dir) => existsSync10(
|
|
1506
|
+
const dirs = patterns.filter((pattern) => !pattern.startsWith("!")).flatMap((pattern) => expand(root, pattern)).filter((dir) => existsSync10(join8(dir, "package.json")));
|
|
1435
1507
|
return [...new Set(dirs)];
|
|
1436
1508
|
};
|
|
1437
1509
|
var manifestOf = (dir) => {
|
|
1438
1510
|
try {
|
|
1439
|
-
const parsed = JSON.parse(
|
|
1511
|
+
const parsed = JSON.parse(readFileSync12(join8(dir, "package.json"), "utf8"));
|
|
1440
1512
|
return typeof parsed === "object" && parsed !== null ? parsed : void 0;
|
|
1441
1513
|
} catch {
|
|
1442
1514
|
return void 0;
|
|
@@ -1466,7 +1538,7 @@ var holdsTests = (dir, depth = 6) => {
|
|
|
1466
1538
|
if (entry.isDirectory()) {
|
|
1467
1539
|
if (entry.name === TEST_DIR) return true;
|
|
1468
1540
|
if (SKIP2.test(entry.name) || depth === 0) continue;
|
|
1469
|
-
if (holdsTests(
|
|
1541
|
+
if (holdsTests(join9(dir, entry.name), depth - 1)) return true;
|
|
1470
1542
|
continue;
|
|
1471
1543
|
}
|
|
1472
1544
|
if (TEST_FILE.test(entry.name)) return true;
|
|
@@ -1504,8 +1576,8 @@ var packagesWithoutTypecheck = {
|
|
|
1504
1576
|
};
|
|
1505
1577
|
|
|
1506
1578
|
// src/counters/seams.ts
|
|
1507
|
-
import { existsSync as existsSync11, readdirSync as readdirSync4, readFileSync as
|
|
1508
|
-
import { join as
|
|
1579
|
+
import { existsSync as existsSync11, readdirSync as readdirSync4, readFileSync as readFileSync13 } from "fs";
|
|
1580
|
+
import { join as join10, resolve as resolve14 } from "path";
|
|
1509
1581
|
var CONFIG = "geonosis.json";
|
|
1510
1582
|
var SKIP_DIRS = /* @__PURE__ */ new Set([".git", ".turbo", "coverage", "dist", "node_modules"]);
|
|
1511
1583
|
var asPattern = (glob) => new RegExp(
|
|
@@ -1515,22 +1587,22 @@ var asPattern = (glob) => new RegExp(
|
|
|
1515
1587
|
);
|
|
1516
1588
|
var filesUnder = (root, at = root) => readdirSync4(at, { withFileTypes: true }).flatMap((entry) => {
|
|
1517
1589
|
if (SKIP_DIRS.has(entry.name)) return [];
|
|
1518
|
-
const full =
|
|
1590
|
+
const full = join10(at, entry.name);
|
|
1519
1591
|
if (entry.isDirectory()) return filesUnder(root, full);
|
|
1520
1592
|
return entry.isFile() ? [full.slice(root.length + 1)] : [];
|
|
1521
1593
|
});
|
|
1522
1594
|
var seamGlobsIn = (root) => {
|
|
1523
|
-
const at =
|
|
1595
|
+
const at = join10(root, CONFIG);
|
|
1524
1596
|
if (!existsSync11(at)) return [];
|
|
1525
1597
|
try {
|
|
1526
|
-
const seams = JSON.parse(
|
|
1598
|
+
const seams = JSON.parse(readFileSync13(at, "utf8")).adoption?.seams;
|
|
1527
1599
|
return Array.isArray(seams) ? seams.filter((one) => typeof one === "string") : [];
|
|
1528
1600
|
} catch {
|
|
1529
1601
|
return [];
|
|
1530
1602
|
}
|
|
1531
1603
|
};
|
|
1532
1604
|
var linesIn = (path) => {
|
|
1533
|
-
const body =
|
|
1605
|
+
const body = readFileSync13(path, "utf8");
|
|
1534
1606
|
return body === "" ? 0 : body.replace(/\n$/, "").split("\n").length;
|
|
1535
1607
|
};
|
|
1536
1608
|
var adoptionSeamLines = {
|
|
@@ -1549,7 +1621,7 @@ var adoptionSeamLines = {
|
|
|
1549
1621
|
const root = resolve14(cwd);
|
|
1550
1622
|
const globs = seamGlobsIn(root).map(asPattern);
|
|
1551
1623
|
if (globs.length === 0) return 0;
|
|
1552
|
-
return filesUnder(root).filter((one) => globs.some((pattern) => pattern.test(one))).reduce((total2, one) => total2 + linesIn(
|
|
1624
|
+
return filesUnder(root).filter((one) => globs.some((pattern) => pattern.test(one))).reduce((total2, one) => total2 + linesIn(join10(root, one)), 0);
|
|
1553
1625
|
}
|
|
1554
1626
|
};
|
|
1555
1627
|
|
|
@@ -1575,12 +1647,14 @@ var sumOfCounts = {
|
|
|
1575
1647
|
};
|
|
1576
1648
|
|
|
1577
1649
|
// src/counters/suppressions.ts
|
|
1578
|
-
import {
|
|
1579
|
-
|
|
1650
|
+
import { resolve as resolve15 } from "path";
|
|
1651
|
+
|
|
1652
|
+
// src/counters/code-files.ts
|
|
1653
|
+
import { readdirSync as readdirSync5, readFileSync as readFileSync14 } from "fs";
|
|
1654
|
+
import { join as join11 } from "path";
|
|
1580
1655
|
var CODE_FILE = /\.(?:ts|tsx|js|jsx|mjs|cjs|mts|cts|vue|svelte|astro)$/;
|
|
1581
1656
|
var SKIP3 = /^(?:node_modules|dist|coverage|\.[^.]|__fixtures__)/;
|
|
1582
|
-
var
|
|
1583
|
-
var countIn = (dir, depth = 12) => {
|
|
1657
|
+
var countInCodeFiles = (dir, countInFile, depth = 12) => {
|
|
1584
1658
|
let entries;
|
|
1585
1659
|
try {
|
|
1586
1660
|
entries = readdirSync5(dir, { withFileTypes: true });
|
|
@@ -1591,17 +1665,21 @@ var countIn = (dir, depth = 12) => {
|
|
|
1591
1665
|
for (const entry of entries) {
|
|
1592
1666
|
if (SKIP3.test(entry.name)) continue;
|
|
1593
1667
|
if (entry.isDirectory()) {
|
|
1594
|
-
if (depth > 0) found +=
|
|
1668
|
+
if (depth > 0) found += countInCodeFiles(join11(dir, entry.name), countInFile, depth - 1);
|
|
1595
1669
|
continue;
|
|
1596
1670
|
}
|
|
1597
1671
|
if (!CODE_FILE.test(entry.name)) continue;
|
|
1598
1672
|
try {
|
|
1599
|
-
found +=
|
|
1673
|
+
found += countInFile(readFileSync14(join11(dir, entry.name), "utf8"));
|
|
1600
1674
|
} catch {
|
|
1601
1675
|
}
|
|
1602
1676
|
}
|
|
1603
1677
|
return found;
|
|
1604
1678
|
};
|
|
1679
|
+
|
|
1680
|
+
// src/counters/suppressions.ts
|
|
1681
|
+
var SUPPRESSION = /(?:eslint|oxlint|biome)-(?:disable|ignore)(?:-next-line|-line)?|@ts-expect-error|@ts-ignore/g;
|
|
1682
|
+
var countIn = (dir) => countInCodeFiles(dir, (text) => text.match(SUPPRESSION)?.length ?? 0);
|
|
1605
1683
|
var suppressionCount = {
|
|
1606
1684
|
id: "suppressionCount",
|
|
1607
1685
|
probe: {
|
|
@@ -1615,8 +1693,8 @@ var suppressionCount = {
|
|
|
1615
1693
|
};
|
|
1616
1694
|
|
|
1617
1695
|
// src/counters/surface.ts
|
|
1618
|
-
import { existsSync as existsSync12, readFileSync as
|
|
1619
|
-
import { join as
|
|
1696
|
+
import { existsSync as existsSync12, readFileSync as readFileSync15 } from "fs";
|
|
1697
|
+
import { join as join12, resolve as resolve16 } from "path";
|
|
1620
1698
|
var DECLARED = /^export\s+(?:declare\s+)?(?:abstract\s+)?(?:const|function|class|type|interface|enum|let|var)\s+([$\w]+)/;
|
|
1621
1699
|
var BRACED = /^export\s+(?:type\s+)?\{([^}]*)\}(?:\s+from\s+(['"])(.+?)\2)?/;
|
|
1622
1700
|
var nameOf2 = (spec) => {
|
|
@@ -1649,11 +1727,11 @@ var exportedSurfaceIn = (source) => {
|
|
|
1649
1727
|
};
|
|
1650
1728
|
var isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1651
1729
|
var declarationEntriesOf = (dir) => {
|
|
1652
|
-
const at =
|
|
1730
|
+
const at = join12(dir, "package.json");
|
|
1653
1731
|
if (!existsSync12(at)) {
|
|
1654
1732
|
throw new CounterError("floorSurface", `no package.json in ${dir} \u2014 that is not a package`);
|
|
1655
1733
|
}
|
|
1656
|
-
const manifest = JSON.parse(
|
|
1734
|
+
const manifest = JSON.parse(readFileSync15(at, "utf8"));
|
|
1657
1735
|
const found = [];
|
|
1658
1736
|
const walk = (value) => {
|
|
1659
1737
|
if (typeof value === "string" && value.endsWith(".d.ts")) found.push(value);
|
|
@@ -1701,16 +1779,16 @@ var floorSurface = {
|
|
|
1701
1779
|
`${relative} promises ${entry} and it is not there \u2014 build before measuring, or the surface reads as empty`
|
|
1702
1780
|
);
|
|
1703
1781
|
}
|
|
1704
|
-
for (const name of exportedSurfaceIn(
|
|
1782
|
+
for (const name of exportedSurfaceIn(readFileSync15(at, "utf8")).keys()) names.add(name);
|
|
1705
1783
|
}
|
|
1706
1784
|
return names.size;
|
|
1707
1785
|
}
|
|
1708
1786
|
};
|
|
1709
1787
|
|
|
1710
1788
|
// src/counters/tests.ts
|
|
1711
|
-
import { existsSync as existsSync13, mkdtempSync as mkdtempSync2, readFileSync as
|
|
1712
|
-
import { tmpdir as
|
|
1713
|
-
import { join as
|
|
1789
|
+
import { existsSync as existsSync13, mkdtempSync as mkdtempSync2, readFileSync as readFileSync16, rmSync as rmSync6 } from "fs";
|
|
1790
|
+
import { tmpdir as tmpdir3 } from "os";
|
|
1791
|
+
import { join as join13, resolve as resolve17 } from "path";
|
|
1714
1792
|
var COUNTER = "testFailures";
|
|
1715
1793
|
var VITEST_LINE = /^\s*Tests {2,}(.+?)\s*$/;
|
|
1716
1794
|
var VITEST_TOTAL = /\(\d+\)$/;
|
|
@@ -1750,7 +1828,7 @@ var fromReport = (path) => {
|
|
|
1750
1828
|
}
|
|
1751
1829
|
let report;
|
|
1752
1830
|
try {
|
|
1753
|
-
report = JSON.parse(
|
|
1831
|
+
report = JSON.parse(readFileSync16(path, "utf8"));
|
|
1754
1832
|
} catch (error) {
|
|
1755
1833
|
throw new CounterError(
|
|
1756
1834
|
COUNTER,
|
|
@@ -1781,7 +1859,7 @@ var reportPathFor = (cwd, params, command) => {
|
|
|
1781
1859
|
`report: "${VITEST_JSON}" needs somewhere to put the report \u2014 write ${PLACEHOLDER} into the command (--outputFile=${PLACEHOLDER}) or give the entry a "reportPath"`
|
|
1782
1860
|
);
|
|
1783
1861
|
}
|
|
1784
|
-
return { own: true, path:
|
|
1862
|
+
return { own: true, path: join13(mkdtempSync2(join13(tmpdir3(), "geonosis-report-")), "report.json") };
|
|
1785
1863
|
};
|
|
1786
1864
|
var testFailures = {
|
|
1787
1865
|
id: COUNTER,
|
|
@@ -1830,16 +1908,14 @@ var testFailures = {
|
|
|
1830
1908
|
run(command.replaceAll(PLACEHOLDER, path));
|
|
1831
1909
|
return fromReport(path);
|
|
1832
1910
|
} finally {
|
|
1833
|
-
if (own)
|
|
1911
|
+
if (own) rmSync6(join13(path, ".."), { force: true, recursive: true });
|
|
1834
1912
|
}
|
|
1835
1913
|
}
|
|
1836
1914
|
};
|
|
1837
1915
|
|
|
1838
1916
|
// src/counters/todos.ts
|
|
1839
|
-
import { existsSync as existsSync14, readdirSync as readdirSync6
|
|
1840
|
-
import {
|
|
1841
|
-
var CODE_FILE2 = /\.(?:ts|tsx|js|jsx|mjs|cjs|mts|cts|vue|svelte|astro)$/;
|
|
1842
|
-
var SKIP4 = /^(?:node_modules|dist|coverage|\.[^.]|__fixtures__)/;
|
|
1917
|
+
import { existsSync as existsSync14, readdirSync as readdirSync6 } from "fs";
|
|
1918
|
+
import { resolve as resolve18 } from "path";
|
|
1843
1919
|
var PLAN_FILE = /^(\d{3,})-[a-z\d][a-z\d.-]*\.md$/;
|
|
1844
1920
|
var plansIn = (dir) => {
|
|
1845
1921
|
if (!existsSync14(dir)) return /* @__PURE__ */ new Set();
|
|
@@ -1850,34 +1926,14 @@ var plansIn = (dir) => {
|
|
|
1850
1926
|
}
|
|
1851
1927
|
return found;
|
|
1852
1928
|
};
|
|
1853
|
-
var countIn2 = (dir, marker, plans
|
|
1854
|
-
let entries;
|
|
1855
|
-
try {
|
|
1856
|
-
entries = readdirSync6(dir, { withFileTypes: true });
|
|
1857
|
-
} catch {
|
|
1858
|
-
return 0;
|
|
1859
|
-
}
|
|
1929
|
+
var countIn2 = (dir, marker, plans) => countInCodeFiles(dir, (text) => {
|
|
1860
1930
|
let found = 0;
|
|
1861
|
-
for (const
|
|
1862
|
-
|
|
1863
|
-
if (
|
|
1864
|
-
if (depth > 0) found += countIn2(join13(dir, entry.name), marker, plans, depth - 1);
|
|
1865
|
-
continue;
|
|
1866
|
-
}
|
|
1867
|
-
if (!CODE_FILE2.test(entry.name)) continue;
|
|
1868
|
-
let text = "";
|
|
1869
|
-
try {
|
|
1870
|
-
text = readFileSync16(join13(dir, entry.name), "utf8");
|
|
1871
|
-
} catch {
|
|
1872
|
-
continue;
|
|
1873
|
-
}
|
|
1874
|
-
for (const match of text.matchAll(marker)) {
|
|
1875
|
-
const cited = match[1];
|
|
1876
|
-
if (cited === void 0 || !plans.has(String(Number(cited)))) found += 1;
|
|
1877
|
-
}
|
|
1931
|
+
for (const match of text.matchAll(marker)) {
|
|
1932
|
+
const cited = match[1];
|
|
1933
|
+
if (cited === void 0 || !plans.has(String(Number(cited)))) found += 1;
|
|
1878
1934
|
}
|
|
1879
1935
|
return found;
|
|
1880
|
-
};
|
|
1936
|
+
});
|
|
1881
1937
|
var orphanTodos = {
|
|
1882
1938
|
id: "orphanTodos",
|
|
1883
1939
|
probe: {
|
|
@@ -2128,6 +2184,11 @@ export {
|
|
|
2128
2184
|
UnbalancedEnvelope,
|
|
2129
2185
|
writeEnvelope,
|
|
2130
2186
|
versionOf,
|
|
2187
|
+
HEAVY_SLOTS,
|
|
2188
|
+
heavySlotDir,
|
|
2189
|
+
describeHolders,
|
|
2190
|
+
HeavySlotTimeout,
|
|
2191
|
+
takeSlot,
|
|
2131
2192
|
heavyLockPath,
|
|
2132
2193
|
acquireExclusive,
|
|
2133
2194
|
CONFIG_FILE,
|
package/dist/cli.js
CHANGED
|
@@ -5,9 +5,10 @@ import {
|
|
|
5
5
|
formatReport,
|
|
6
6
|
runProve,
|
|
7
7
|
runRatchet,
|
|
8
|
+
takeSlot,
|
|
8
9
|
versionOf,
|
|
9
10
|
writeEnvelope
|
|
10
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-WENVCC67.js";
|
|
11
12
|
|
|
12
13
|
// src/cli.ts
|
|
13
14
|
import process from "process";
|
|
@@ -131,6 +132,10 @@ var measure = async () => {
|
|
|
131
132
|
` : formatProve(proof));
|
|
132
133
|
return proof.proven ? 0 : 2;
|
|
133
134
|
}
|
|
135
|
+
releaseHeavySlot = await takeSlot({
|
|
136
|
+
command: `geonosis-ratchet${tier === void 0 ? "" : ` --tier ${tier}`}`,
|
|
137
|
+
cwd
|
|
138
|
+
});
|
|
134
139
|
const startedAt = Date.now();
|
|
135
140
|
const result = await runRatchet({ counters: COUNTERS, cwd, tier });
|
|
136
141
|
if (!json) process.stdout.write(formatReport(result));
|
|
@@ -152,6 +157,7 @@ var measure = async () => {
|
|
|
152
157
|
}
|
|
153
158
|
return result.measurements.some((one) => one.verdict === "grew") ? 1 : 0;
|
|
154
159
|
};
|
|
160
|
+
var releaseHeavySlot = () => void 0;
|
|
155
161
|
try {
|
|
156
162
|
if (tierFlag !== -1 && (tier === void 0 || tier.startsWith("--"))) {
|
|
157
163
|
throw new Error("--tier needs a tier name");
|
|
@@ -165,6 +171,7 @@ try {
|
|
|
165
171
|
const release = exclusive ? await acquireExclusive({ timeoutSeconds }) : () => void 0;
|
|
166
172
|
const giveBack = () => {
|
|
167
173
|
release();
|
|
174
|
+
releaseHeavySlot();
|
|
168
175
|
process.exit(130);
|
|
169
176
|
};
|
|
170
177
|
process.on("SIGINT", giveBack);
|
|
@@ -174,6 +181,7 @@ try {
|
|
|
174
181
|
code = await measure();
|
|
175
182
|
} finally {
|
|
176
183
|
release();
|
|
184
|
+
releaseHeavySlot();
|
|
177
185
|
}
|
|
178
186
|
process.exit(code);
|
|
179
187
|
} catch (error) {
|
package/dist/index.d.ts
CHANGED
|
@@ -288,6 +288,42 @@ declare const versionOf: (moduleUrl: string) => string;
|
|
|
288
288
|
declare const COUNTERS: Counter[];
|
|
289
289
|
declare const counterById: (id: string) => Counter;
|
|
290
290
|
|
|
291
|
+
/** Who is spending a heavy slot, running what, since when. */
|
|
292
|
+
type HeavySlotHolder = {
|
|
293
|
+
command: string;
|
|
294
|
+
cwd: string;
|
|
295
|
+
pid: number;
|
|
296
|
+
startedAt: string;
|
|
297
|
+
};
|
|
298
|
+
/**
|
|
299
|
+
* Two, not one: `core/lock.ts`'s `acquireExclusive` serialises a whole run against every other; this
|
|
300
|
+
* is the machine's OWN ceiling — measured 2026-09-05, load 48 with during.day's Stop-hook tier, this
|
|
301
|
+
* kit's Stop-hook tier, this kit's ratchet and an engineer's suite all running at once. A machine that
|
|
302
|
+
* can carry two heavy things at a time carries two; a third waits.
|
|
303
|
+
*/
|
|
304
|
+
declare const HEAVY_SLOTS = 2;
|
|
305
|
+
declare const heavySlotDir: () => string;
|
|
306
|
+
declare const describeHolders: (holders: HeavySlotHolder[]) => string;
|
|
307
|
+
/** A wait that ran out. The message names every holder, because the caller's own refusal is this text. */
|
|
308
|
+
declare class HeavySlotTimeout extends Error {
|
|
309
|
+
}
|
|
310
|
+
/**
|
|
311
|
+
* Claims one of the two machine-wide heavy slots, waiting for whoever holds them.
|
|
312
|
+
*
|
|
313
|
+
* A dead holder is reaped before a slot is tried, so a killed run never wedges the budget for
|
|
314
|
+
* whoever asks next. Both held is announced ONCE — not on every poll, which would turn a half-hour
|
|
315
|
+
* wait into a half hour of identical lines — and the wait is bounded, so a taker that can never get
|
|
316
|
+
* in refuses instead of hanging the process that called it.
|
|
317
|
+
*/
|
|
318
|
+
declare const takeSlot: ({ command, cwd, dir, pollMs, say, waitMs, }: {
|
|
319
|
+
command: string;
|
|
320
|
+
cwd?: string;
|
|
321
|
+
dir?: string;
|
|
322
|
+
pollMs?: number;
|
|
323
|
+
say?: (line: string) => void;
|
|
324
|
+
waitMs?: number;
|
|
325
|
+
}) => Promise<() => void>;
|
|
326
|
+
|
|
291
327
|
/** Who is running the heavy thing, since when, and where from. */
|
|
292
328
|
type Holder = {
|
|
293
329
|
cwd: string;
|
|
@@ -377,4 +413,4 @@ declare const formatProve: ({ proofs, proven }: ProveResult) => string;
|
|
|
377
413
|
*/
|
|
378
414
|
declare const runCommand: (cwd: string, counterId: string, env?: NodeJS.ProcessEnv) => (command: string) => CommandResult;
|
|
379
415
|
|
|
380
|
-
export { CONFIG_FILE, COUNTERS, type CommandResult, type Counter, type CounterConfig, type CounterContext, CounterError, type CounterProbe, ENVELOPES_DIR, type EnvelopeEntry, type Holder, type Measurement, type Proof, type ProveResult, type RatchetConfig, type RatchetResult, type Refusal, type ReportEnvelope, UnbalancedEnvelope, type Verdict, acquireExclusive, counterById, envelopePath, formatProve, formatReport, heavyLockPath, keyOf, loadConfig, resolveBaseline, runCommand, runProve, runRatchet, versionOf, writeEnvelope };
|
|
416
|
+
export { CONFIG_FILE, COUNTERS, type CommandResult, type Counter, type CounterConfig, type CounterContext, CounterError, type CounterProbe, ENVELOPES_DIR, type EnvelopeEntry, HEAVY_SLOTS, type HeavySlotHolder, HeavySlotTimeout, type Holder, type Measurement, type Proof, type ProveResult, type RatchetConfig, type RatchetResult, type Refusal, type ReportEnvelope, UnbalancedEnvelope, type Verdict, acquireExclusive, counterById, describeHolders, envelopePath, formatProve, formatReport, heavyLockPath, heavySlotDir, keyOf, loadConfig, resolveBaseline, runCommand, runProve, runRatchet, takeSlot, versionOf, writeEnvelope };
|
package/dist/index.js
CHANGED
|
@@ -3,40 +3,50 @@ import {
|
|
|
3
3
|
COUNTERS,
|
|
4
4
|
CounterError,
|
|
5
5
|
ENVELOPES_DIR,
|
|
6
|
+
HEAVY_SLOTS,
|
|
7
|
+
HeavySlotTimeout,
|
|
6
8
|
UnbalancedEnvelope,
|
|
7
9
|
acquireExclusive,
|
|
8
10
|
counterById,
|
|
11
|
+
describeHolders,
|
|
9
12
|
envelopePath,
|
|
10
13
|
formatProve,
|
|
11
14
|
formatReport,
|
|
12
15
|
heavyLockPath,
|
|
16
|
+
heavySlotDir,
|
|
13
17
|
keyOf,
|
|
14
18
|
loadConfig,
|
|
15
19
|
resolveBaseline,
|
|
16
20
|
runCommand,
|
|
17
21
|
runProve,
|
|
18
22
|
runRatchet,
|
|
23
|
+
takeSlot,
|
|
19
24
|
versionOf,
|
|
20
25
|
writeEnvelope
|
|
21
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-WENVCC67.js";
|
|
22
27
|
export {
|
|
23
28
|
CONFIG_FILE,
|
|
24
29
|
COUNTERS,
|
|
25
30
|
CounterError,
|
|
26
31
|
ENVELOPES_DIR,
|
|
32
|
+
HEAVY_SLOTS,
|
|
33
|
+
HeavySlotTimeout,
|
|
27
34
|
UnbalancedEnvelope,
|
|
28
35
|
acquireExclusive,
|
|
29
36
|
counterById,
|
|
37
|
+
describeHolders,
|
|
30
38
|
envelopePath,
|
|
31
39
|
formatProve,
|
|
32
40
|
formatReport,
|
|
33
41
|
heavyLockPath,
|
|
42
|
+
heavySlotDir,
|
|
34
43
|
keyOf,
|
|
35
44
|
loadConfig,
|
|
36
45
|
resolveBaseline,
|
|
37
46
|
runCommand,
|
|
38
47
|
runProve,
|
|
39
48
|
runRatchet,
|
|
49
|
+
takeSlot,
|
|
40
50
|
versionOf,
|
|
41
51
|
writeEnvelope
|
|
42
52
|
};
|