@cejel/cejel 0.2.1 → 0.3.1

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
@@ -11,6 +11,10 @@ a trust certificate + badge. Especially valuable when AI wrote a lot of the code
11
11
  exactly when you can't eyeball trust. Built on a deterministic, no-LLM scoring core — the
12
12
  free path makes zero network calls and requires no account.
13
13
 
14
+ **Claim boundary:** Cejel scores engineering-trust signals; it does not claim to detect software
15
+ defects or prove that code is safe. Defect and vulnerability scanners remain evidence producers
16
+ that Cejel can aggregate into a trust certificate.
17
+
14
18
  Cejel is not another point scanner competing with the one you already run — it's the open,
15
19
  portable, offline trust certificate that aggregates them. Pipe in SARIF-compatible output
16
20
  (MunaTrust, Snyk, Semgrep, CodeQL, Codex) plus OpenSSF Scorecard, and get one shareable
@@ -49,6 +53,29 @@ chmod +x cejel
49
53
  ./cejel .
50
54
  ```
51
55
 
56
+ **Windows x86_64 (PowerShell).**
57
+
58
+ ```powershell
59
+ $asset = "cejel-Windows-x86_64.exe"
60
+ Invoke-WebRequest "https://github.com/BargLabs/cejel/releases/latest/download/$asset" -OutFile $asset
61
+ Invoke-WebRequest "https://github.com/BargLabs/cejel/releases/latest/download/SHA256SUMS" -OutFile SHA256SUMS
62
+ $expected = ((Select-String -Path SHA256SUMS -Pattern " $([regex]::Escape($asset))$").Line -split "\s+")[0]
63
+ $actual = (Get-FileHash -Algorithm SHA256 $asset).Hash.ToLowerInvariant()
64
+ if (-not $expected -or $actual -ne $expected.ToLowerInvariant()) {
65
+ throw "SHA-256 verification failed for $asset"
66
+ }
67
+ .\cejel-Windows-x86_64.exe .
68
+ ```
69
+
70
+ > **Windows signing status:** `cejel-Windows-x86_64.exe` is intentionally unsigned in
71
+ > 0.3.1 and may trigger Microsoft SmartScreen. The release build removes Node's inherited
72
+ > signature before SEA injection and fails unless Windows reports the result as `NotSigned`;
73
+ > it does not ship an invalid signature. Before running it, verify `SHA256SUMS` and the
74
+ > GitHub build-provenance attestation. Each binary also has an attached SPDX SBOM and an
75
+ > own-platform verification receipt covering `--version`, `--help`, a real scan,
76
+ > source/binary parity, and a network-denied scan. If your policy requires Authenticode,
77
+ > use the npm package or the OCI image until a human-approved signing path is available.
78
+
52
79
  **Don't take the offline claim on trust — check it.** Turn your network off, then run the
53
80
  binary. It will score your repository and write you a certificate anyway. That is the whole
54
81
  product, and you can falsify it in ten seconds:
@@ -61,7 +88,17 @@ docker run --rm --network=none -v "$PWD:/w" -w /w -v "$PWD/cejel:/cejel:ro" debi
61
88
  **npm.**
62
89
 
63
90
  ```bash
64
- npx @cejel/cejel .
91
+ npx @cejel/cejel@latest .
92
+ ```
93
+
94
+ > **Distribution note:** Cejel `0.3.1` is the coordinated release version for npm,
95
+ > standalone binaries, Docker/OCI, GitHub Action, Homebrew, and MCP Registry.
96
+
97
+ `npx` can reuse a stale cached package. Force the current npm release with the `@latest`
98
+ specifier above, and check the version that will run before comparing certificates:
99
+
100
+ ```bash
101
+ npx @cejel/cejel@latest --version
65
102
  ```
66
103
 
67
104
  If a root `package.json` still carries a template name, override only the certificate display
@@ -89,30 +126,30 @@ pnpm install && pnpm build
89
126
  node dist/index.js .
90
127
  ```
91
128
 
92
- Released binaries: `cejel-Darwin-arm64`, `cejel-Darwin-x86_64`, `cejel-Linux-aarch64`, and
93
- `cejel-Linux-x86_64`. The release also carries `SHA256SUMS`; each binary is executed against
94
- the source build and with networking denied before attachment. Releases from v0.1.6 also
95
- carry a Sigstore bundle containing GitHub's signed build-provenance attestation for all four
96
- binaries. Verify a downloaded binary with:
129
+ Released binaries: `cejel-Darwin-arm64`, `cejel-Darwin-x86_64`, `cejel-Linux-aarch64`,
130
+ `cejel-Linux-x86_64`, and `cejel-Windows-x86_64.exe`. The release also carries
131
+ `SHA256SUMS`, a per-binary SPDX SBOM, and an own-platform verification receipt. Each binary
132
+ is executed against the source build and with networking denied before attachment. Releases
133
+ from v0.1.6 also carry a Sigstore bundle containing GitHub's signed build-provenance
134
+ attestation for the release set. Verify a downloaded binary with:
97
135
 
98
136
  ```bash
99
- gh attestation verify ./cejel-Darwin-arm64 -R BargLabs/cejel
137
+ gh attestation verify ./cejel-Windows-x86_64.exe -R BargLabs/cejel
100
138
  ```
101
139
 
102
140
  This is cryptographically signed provenance. It is distinct from Apple Developer ID or
103
141
  Microsoft Authenticode code-signing.
104
142
 
105
- **Docker / OCI.** The current container release is `0.2.0` (container releases are
106
- versioned independently from npm-only patches):
143
+ **Docker / OCI.** The current container release is `0.3.1`:
107
144
 
108
145
  ```bash
109
- docker run --rm -i -v "$PWD:/workspace:ro" ghcr.io/barglabs/cejel:0.2.0
146
+ docker run --rm -i -v "$PWD:/workspace:ro" ghcr.io/barglabs/cejel:0.3.1
110
147
  ```
111
148
 
112
149
  The image defaults to `cejel-mcp` over stdio. To use the CLI instead:
113
150
 
114
151
  ```bash
115
- docker run --rm -v "$PWD:/workspace:ro" --entrypoint cejel ghcr.io/barglabs/cejel:0.2.0 .
152
+ docker run --rm -v "$PWD:/workspace:ro" --entrypoint cejel ghcr.io/barglabs/cejel:0.3.1 .
116
153
  ```
117
154
 
118
155
  The OCI image carries an SBOM, maximum-mode build provenance, and a signed registry
@@ -360,12 +397,61 @@ The server exposes one tool and two resources:
360
397
  Like the CLI, scoring over MCP is fully offline: no network calls, no telemetry, no signup,
361
398
  and the server writes no files.
362
399
 
400
+ ## Install on OpenClaw
401
+
402
+ OpenClaw stores outbound MCP servers under `mcp.servers`. Add Cejel with the npm package's
403
+ shipped `cejel-mcp` bin:
404
+
405
+ ```json
406
+ {
407
+ "mcp": {
408
+ "servers": {
409
+ "cejel": {
410
+ "command": "npx",
411
+ "args": ["-y", "--package=@cejel/cejel", "cejel-mcp"]
412
+ }
413
+ }
414
+ }
415
+ }
416
+ ```
417
+
418
+ The equivalent OpenClaw command is:
419
+
420
+ ```bash
421
+ openclaw mcp add cejel --command npx --arg -y --arg --package=@cejel/cejel --arg cejel-mcp
422
+ openclaw mcp doctor cejel --probe
423
+ ```
424
+
425
+ The OCI image is an alternative when Docker is the preferred execution boundary. Replace
426
+ the host path with the repository OpenClaw should allow Cejel to read:
427
+
428
+ ```bash
429
+ openclaw mcp set cejel-oci '{"command":"docker","args":["run","--rm","-i","-v","/absolute/path/to/repo:/workspace:ro","ghcr.io/barglabs/cejel:0.3.1"]}'
430
+ openclaw mcp doctor cejel-oci --probe
431
+ ```
432
+
433
+ Cejel is active in the Official MCP Registry as `io.github.BargLabs/cejel`. The explicit
434
+ OpenClaw configuration above works independently of catalog indexing.
435
+
436
+ Cejel scans code you point it at. This free adoption surface does **not** watch, intercept,
437
+ or govern an agent's runtime actions. Runtime-action governance is a separate boundary for
438
+ the future paid Agent Pack.
439
+
363
440
  ## What "offline" means here
364
441
 
365
442
  Scoring a repo — `cejel scan .` itself, and the Action's scoring step — makes zero network
366
- calls: no telemetry, no signup, no model call. Fetching the `@cejel/cejel` package the
367
- first time (like any npm-distributed CLI, including this Action's own dependency install)
368
- does need network; that's a one-time install cost, not part of the scoring guarantee.
443
+ calls: no telemetry, no signup, no model call. The scanner does invoke your local `git`
444
+ binary through one hardened subprocess chokepoint: fixed argv only (never a shell), an
445
+ explicit timeout and output bound, prompts and network transports disabled, proxy variables
446
+ removed, and repository-controlled filesystem monitoring neutralized. A static CI guard
447
+ allows `node:child_process` in that one module only and rejects direct network primitives
448
+ everywhere, while each release binary is also scanned with outbound networking denied.
449
+
450
+ Fetching the `@cejel/cejel` package the first time (like any npm-distributed CLI, including
451
+ this Action's own dependency install) does need network; that's a one-time install cost, not
452
+ part of the scoring guarantee. If the tracked-file inventory fails unexpectedly, the JSON,
453
+ HTML, and markdown certificates declare that the scanner used its bounded directory fallback
454
+ instead of silently presenting the two inventories as equivalent.
369
455
 
370
456
  ## Help validate Cejel
371
457
 
@@ -0,0 +1,360 @@
1
+ #!/usr/bin/env node
2
+ import { createRequire as __cejelCreateRequire } from 'node:module';
3
+ const require = __cejelCreateRequire(import.meta.url);
4
+ var __create = Object.create;
5
+ var __defProp = Object.defineProperty;
6
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
7
+ var __getOwnPropNames = Object.getOwnPropertyNames;
8
+ var __getProtoOf = Object.getPrototypeOf;
9
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
10
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
11
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
12
+ }) : x)(function(x) {
13
+ if (typeof require !== "undefined") return require.apply(this, arguments);
14
+ throw Error('Dynamic require of "' + x + '" is not supported');
15
+ });
16
+ var __esm = (fn, res) => function __init() {
17
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
18
+ };
19
+ var __commonJS = (cb, mod) => function __require2() {
20
+ return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
21
+ };
22
+ var __export = (target, all) => {
23
+ for (var name in all)
24
+ __defProp(target, name, { get: all[name], enumerable: true });
25
+ };
26
+ var __copyProps = (to, from, except, desc) => {
27
+ if (from && typeof from === "object" || typeof from === "function") {
28
+ for (let key of __getOwnPropNames(from))
29
+ if (!__hasOwnProp.call(to, key) && key !== except)
30
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
31
+ }
32
+ return to;
33
+ };
34
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
35
+ // If the importer is in node compatibility mode or this is not an ESM
36
+ // file that has been converted to a CommonJS file using a Babel-
37
+ // compatible transform (i.e. "__esModule" has not been set), then set
38
+ // "default" to the CommonJS "module.exports" for node compatibility.
39
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
40
+ mod
41
+ ));
42
+
43
+ // node_modules/.pnpm/tsup@8.5.1_postcss@8.5.19_tsx@4.23.1_typescript@5.9.3/node_modules/tsup/assets/esm_shims.js
44
+ import path from "path";
45
+ import { fileURLToPath } from "url";
46
+ var getFilename, getDirname, __dirname, __filename;
47
+ var init_esm_shims = __esm({
48
+ "node_modules/.pnpm/tsup@8.5.1_postcss@8.5.19_tsx@4.23.1_typescript@5.9.3/node_modules/tsup/assets/esm_shims.js"() {
49
+ "use strict";
50
+ getFilename = () => fileURLToPath(import.meta.url);
51
+ getDirname = () => path.dirname(getFilename());
52
+ __dirname = /* @__PURE__ */ getDirname();
53
+ __filename = /* @__PURE__ */ getFilename();
54
+ }
55
+ });
56
+
57
+ // src/witan/content-reads.ts
58
+ init_esm_shims();
59
+ import { closeSync, lstatSync, openSync, readFileSync, readSync } from "fs";
60
+ import { resolve } from "path";
61
+ var activeSession;
62
+ function errnoClass(error) {
63
+ if (typeof error !== "object" || error === null || !("code" in error)) return null;
64
+ const code = error.code;
65
+ return typeof code === "string" && /^E[A-Z0-9_]+$/.test(code) ? code : null;
66
+ }
67
+ function recordSkip(path2, reason, errno, affectsCurrentCriterion = false, deduplicate = false) {
68
+ const session = activeSession;
69
+ if (!session) return;
70
+ if (affectsCurrentCriterion && session.criterion) {
71
+ session.affectedCriteria.add(session.criterion);
72
+ }
73
+ if (deduplicate) {
74
+ const key = `${resolve(path2)}\0${reason}\0${errno ?? ""}`;
75
+ if (session.deduplicatedSkips.has(key)) return;
76
+ session.deduplicatedSkips.add(key);
77
+ }
78
+ session.counts[reason] += 1;
79
+ if (reason === "unreadable" && errno) {
80
+ session.unreadableByErrno.set(errno, (session.unreadableByErrno.get(errno) ?? 0) + 1);
81
+ }
82
+ }
83
+ function summaryFor(session) {
84
+ const byReason = {
85
+ unreadable: session.counts.unreadable,
86
+ tooLarge: session.counts.too_large,
87
+ excludedByExtension: session.counts.excluded_by_extension,
88
+ deniedPath: session.counts.denied_path,
89
+ nonRegularFile: session.counts.non_regular_file
90
+ };
91
+ const sortedErrnos = Object.fromEntries(
92
+ [...session.unreadableByErrno.entries()].sort(([left], [right]) => left.localeCompare(right))
93
+ );
94
+ return {
95
+ skipped: Object.values(session.counts).reduce((total, count) => total + count, 0),
96
+ byReason,
97
+ unreadableByErrno: sortedErrnos,
98
+ affectedCriteria: [...session.affectedCriteria].sort()
99
+ };
100
+ }
101
+ function trackContentReads(_repoPath, collect) {
102
+ const existing = activeSession;
103
+ if (existing) {
104
+ return {
105
+ value: collect(),
106
+ summary: summaryFor(existing),
107
+ affectedCriteria: existing.affectedCriteria
108
+ };
109
+ }
110
+ const session = {
111
+ counts: {
112
+ unreadable: 0,
113
+ too_large: 0,
114
+ excluded_by_extension: 0,
115
+ denied_path: 0,
116
+ non_regular_file: 0
117
+ },
118
+ unreadableByErrno: /* @__PURE__ */ new Map(),
119
+ deduplicatedSkips: /* @__PURE__ */ new Set(),
120
+ affectedCriteria: /* @__PURE__ */ new Set()
121
+ };
122
+ activeSession = session;
123
+ try {
124
+ const value = collect();
125
+ return {
126
+ value,
127
+ summary: summaryFor(session),
128
+ affectedCriteria: session.affectedCriteria
129
+ };
130
+ } finally {
131
+ activeSession = void 0;
132
+ }
133
+ }
134
+ function withContentReadCriterion(criterion, collect) {
135
+ const session = activeSession;
136
+ if (!session) return collect();
137
+ const previous = session.criterion;
138
+ session.criterion = criterion;
139
+ try {
140
+ return collect();
141
+ } finally {
142
+ session.criterion = previous;
143
+ }
144
+ }
145
+ function recordContentSkip(path2, reason, deduplicate = false) {
146
+ recordSkip(path2, reason, void 0, false, deduplicate);
147
+ }
148
+ function recordFilesystemSkip(path2, error, deniedContext = false, deduplicate = true) {
149
+ const errno = errnoClass(error);
150
+ if (!errno) throw error;
151
+ if (deniedContext && (errno === "EACCES" || errno === "EPERM")) {
152
+ recordSkip(path2, "denied_path", errno, false, deduplicate);
153
+ return;
154
+ }
155
+ recordSkip(path2, "unreadable", errno, true, deduplicate);
156
+ }
157
+ function readRepoText(path2, encoding = "utf8") {
158
+ try {
159
+ const stat = lstatSync(path2);
160
+ if (!stat.isFile()) {
161
+ recordSkip(path2, "non_regular_file", void 0, true, true);
162
+ return "";
163
+ }
164
+ } catch (error) {
165
+ recordFilesystemSkip(path2, error);
166
+ return "";
167
+ }
168
+ try {
169
+ return readFileSync(path2, encoding);
170
+ } catch (error) {
171
+ recordFilesystemSkip(path2, error);
172
+ return "";
173
+ }
174
+ }
175
+ function readRepoTextPrefix(path2, byteLimit) {
176
+ try {
177
+ const stat = lstatSync(path2);
178
+ if (!stat.isFile()) {
179
+ recordSkip(path2, "non_regular_file", void 0, true, true);
180
+ return "";
181
+ }
182
+ } catch (error) {
183
+ recordFilesystemSkip(path2, error);
184
+ return "";
185
+ }
186
+ let descriptor = null;
187
+ try {
188
+ descriptor = openSync(path2, "r");
189
+ const buffer = Buffer.allocUnsafe(byteLimit);
190
+ const bytesRead = readSync(descriptor, buffer, 0, byteLimit, 0);
191
+ return buffer.subarray(0, bytesRead).toString("utf8");
192
+ } catch (error) {
193
+ recordFilesystemSkip(path2, error);
194
+ return "";
195
+ } finally {
196
+ if (descriptor !== null) {
197
+ try {
198
+ closeSync(descriptor);
199
+ } catch (error) {
200
+ recordFilesystemSkip(path2, error);
201
+ }
202
+ }
203
+ }
204
+ }
205
+
206
+ // src/witan/git-exec.ts
207
+ init_esm_shims();
208
+ import { execFileSync } from "child_process";
209
+ var GIT_EXEC_MAX_BUFFER_BYTES = 8 * 1024 * 1024;
210
+ var GIT_EXEC_TIMEOUT_MS = 3e4;
211
+ var HARDENED_GIT_ARGUMENTS = [
212
+ "--no-pager",
213
+ "-c",
214
+ "core.fsmonitor=false",
215
+ "-c",
216
+ "core.pager=",
217
+ "-c",
218
+ "core.editor=false",
219
+ "-c",
220
+ "core.sshCommand=false",
221
+ "-c",
222
+ "diff.external=false",
223
+ "-c",
224
+ "credential.helper=",
225
+ "-c",
226
+ "log.showSignature=false",
227
+ "-c",
228
+ "gpg.program=false",
229
+ "-c",
230
+ "gpg.openpgp.program=false",
231
+ "-c",
232
+ "gpg.x509.program=false",
233
+ "-c",
234
+ "gpg.ssh.program=false",
235
+ "-c",
236
+ "core.quotePath=false",
237
+ "-c",
238
+ "protocol.allow=never",
239
+ "-c",
240
+ "protocol.ext.allow=never",
241
+ "-c",
242
+ "protocol.file.allow=never",
243
+ "-c",
244
+ "protocol.git.allow=never",
245
+ "-c",
246
+ "protocol.http.allow=never",
247
+ "-c",
248
+ "protocol.https.allow=never",
249
+ "-c",
250
+ "protocol.ssh.allow=never"
251
+ ];
252
+ function hardenedGitEnvironment() {
253
+ const environment = {};
254
+ for (const key of ["PATH", "HOME", "TZ"]) {
255
+ const entry = Object.entries(process.env).find(
256
+ ([candidate, value]) => candidate.toUpperCase() === key && value !== void 0
257
+ );
258
+ if (entry?.[1] !== void 0) environment[key] = entry[1];
259
+ }
260
+ if (environment.HOME === void 0 && process.env.USERPROFILE !== void 0) {
261
+ environment.HOME = process.env.USERPROFILE;
262
+ }
263
+ return {
264
+ ...environment,
265
+ LC_ALL: "C",
266
+ LANG: "C",
267
+ GIT_CONFIG_NOSYSTEM: "1",
268
+ GIT_TERMINAL_PROMPT: "0",
269
+ GIT_ASKPASS: "true",
270
+ GIT_OPTIONAL_LOCKS: "0",
271
+ GIT_PAGER: "cat",
272
+ PAGER: "cat"
273
+ };
274
+ }
275
+ function errorField(error, key) {
276
+ if (typeof error !== "object" || error === null) return void 0;
277
+ return error[key];
278
+ }
279
+ function errorText(error) {
280
+ const stderr = errorField(error, "stderr");
281
+ const stderrText = typeof stderr === "string" ? stderr : Buffer.isBuffer(stderr) ? stderr.toString("utf8") : "";
282
+ const message = error instanceof Error ? error.message : "";
283
+ return `${stderrText}
284
+ ${message}`;
285
+ }
286
+ function classifyGitFailure(error) {
287
+ const code = errorField(error, "code");
288
+ const signal = errorField(error, "signal");
289
+ const text = errorText(error);
290
+ if (code === "ENOENT") return "git_absent";
291
+ if (code === "ENOBUFS" || /maxBuffer|ENOBUFS/i.test(text)) return "buffer_exceeded";
292
+ if (code === "ETIMEDOUT" || signal === "SIGTERM" || /timed?\s*out|ETIMEDOUT/i.test(text)) {
293
+ return "timeout";
294
+ }
295
+ if (/not a git repository|not inside a work tree|not in a git directory|unknown revision.*HEAD|ambiguous argument ['"]?HEAD|does not have any commits yet|needed a single revision/i.test(
296
+ text
297
+ )) {
298
+ return "not_a_repo";
299
+ }
300
+ return "exec_failed";
301
+ }
302
+ function execGit(argv, options) {
303
+ try {
304
+ const stdout = execFileSync("git", [...HARDENED_GIT_ARGUMENTS, ...argv], {
305
+ cwd: options.cwd,
306
+ encoding: "utf8",
307
+ env: hardenedGitEnvironment(),
308
+ input: options.input,
309
+ maxBuffer: options.maxBufferBytes ?? GIT_EXEC_MAX_BUFFER_BYTES,
310
+ stdio: ["pipe", "pipe", "pipe"],
311
+ timeout: GIT_EXEC_TIMEOUT_MS
312
+ });
313
+ return { ok: true, stdout };
314
+ } catch (error) {
315
+ const status = errorField(error, "status");
316
+ return {
317
+ ok: false,
318
+ reason: classifyGitFailure(error),
319
+ ...typeof status === "number" ? { exitCode: status } : {}
320
+ };
321
+ }
322
+ }
323
+ function isExpectedGitAbsence(result) {
324
+ return result.reason === "git_absent" || result.reason === "not_a_repo";
325
+ }
326
+ function describeGitFailure(reason, operation, maxBufferBytes = GIT_EXEC_MAX_BUFFER_BYTES) {
327
+ if (reason === "buffer_exceeded") {
328
+ const outputLimit = maxBufferBytes % (1024 * 1024) === 0 ? `${maxBufferBytes / (1024 * 1024)} MiB` : `${Math.ceil(maxBufferBytes / 1024)} KiB`;
329
+ return `Cejel: local git ${operation} exceeded the ${outputLimit} output limit.`;
330
+ }
331
+ if (reason === "timeout") {
332
+ return `Cejel: local git ${operation} exceeded the 30 second timeout.`;
333
+ }
334
+ if (reason === "git_absent") {
335
+ return `Cejel: local git is unavailable while running ${operation}.`;
336
+ }
337
+ if (reason === "not_a_repo") {
338
+ return `Cejel: ${operation} requires a usable Git work tree.`;
339
+ }
340
+ return `Cejel: local git ${operation} failed.`;
341
+ }
342
+
343
+ export {
344
+ __require,
345
+ __commonJS,
346
+ __export,
347
+ __toESM,
348
+ __dirname,
349
+ __filename,
350
+ init_esm_shims,
351
+ trackContentReads,
352
+ withContentReadCriterion,
353
+ recordContentSkip,
354
+ recordFilesystemSkip,
355
+ readRepoText,
356
+ readRepoTextPrefix,
357
+ execGit,
358
+ isExpectedGitAbsence,
359
+ describeGitFailure
360
+ };