@cejel/cejel 0.2.2 → 0.3.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/README.md +22 -9
- package/dist/chunk-LZVKQV3R.js +360 -0
- package/dist/{chunk-SNDRU52Z.js → chunk-XB65L6WE.js} +759 -332
- package/dist/index.js +42 -4
- package/dist/mcp/index.js +214 -5
- package/dist/packs/d-series/index.js +211708 -0
- package/package.json +14 -1
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
|
|
@@ -64,7 +68,7 @@ if (-not $expected -or $actual -ne $expected.ToLowerInvariant()) {
|
|
|
64
68
|
```
|
|
65
69
|
|
|
66
70
|
> **Windows signing status:** `cejel-Windows-x86_64.exe` is intentionally unsigned in
|
|
67
|
-
> 0.
|
|
71
|
+
> 0.3.2 and may trigger Microsoft SmartScreen. The release build removes Node's inherited
|
|
68
72
|
> signature before SEA injection and fails unless Windows reports the result as `NotSigned`;
|
|
69
73
|
> it does not ship an invalid signature. Before running it, verify `SHA256SUMS` and the
|
|
70
74
|
> GitHub build-provenance attestation. Each binary also has an attached SPDX SBOM and an
|
|
@@ -87,7 +91,7 @@ docker run --rm --network=none -v "$PWD:/w" -w /w -v "$PWD/cejel:/cejel:ro" debi
|
|
|
87
91
|
npx @cejel/cejel@latest .
|
|
88
92
|
```
|
|
89
93
|
|
|
90
|
-
> **Distribution note:** Cejel `0.
|
|
94
|
+
> **Distribution note:** Cejel `0.3.2` is the coordinated release version for npm,
|
|
91
95
|
> standalone binaries, Docker/OCI, GitHub Action, Homebrew, and MCP Registry.
|
|
92
96
|
|
|
93
97
|
`npx` can reuse a stale cached package. Force the current npm release with the `@latest`
|
|
@@ -136,16 +140,16 @@ gh attestation verify ./cejel-Windows-x86_64.exe -R BargLabs/cejel
|
|
|
136
140
|
This is cryptographically signed provenance. It is distinct from Apple Developer ID or
|
|
137
141
|
Microsoft Authenticode code-signing.
|
|
138
142
|
|
|
139
|
-
**Docker / OCI.** The current container release is `0.
|
|
143
|
+
**Docker / OCI.** The current container release is `0.3.2`:
|
|
140
144
|
|
|
141
145
|
```bash
|
|
142
|
-
docker run --rm -i -v "$PWD:/workspace:ro" ghcr.io/barglabs/cejel:0.
|
|
146
|
+
docker run --rm -i -v "$PWD:/workspace:ro" ghcr.io/barglabs/cejel:0.3.2
|
|
143
147
|
```
|
|
144
148
|
|
|
145
149
|
The image defaults to `cejel-mcp` over stdio. To use the CLI instead:
|
|
146
150
|
|
|
147
151
|
```bash
|
|
148
|
-
docker run --rm -v "$PWD:/workspace:ro" --entrypoint cejel ghcr.io/barglabs/cejel:0.
|
|
152
|
+
docker run --rm -v "$PWD:/workspace:ro" --entrypoint cejel ghcr.io/barglabs/cejel:0.3.2 .
|
|
149
153
|
```
|
|
150
154
|
|
|
151
155
|
The OCI image carries an SBOM, maximum-mode build provenance, and a signed registry
|
|
@@ -422,7 +426,7 @@ The OCI image is an alternative when Docker is the preferred execution boundary.
|
|
|
422
426
|
the host path with the repository OpenClaw should allow Cejel to read:
|
|
423
427
|
|
|
424
428
|
```bash
|
|
425
|
-
openclaw mcp set cejel-oci '{"command":"docker","args":["run","--rm","-i","-v","/absolute/path/to/repo:/workspace:ro","ghcr.io/barglabs/cejel:0.
|
|
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.2"]}'
|
|
426
430
|
openclaw mcp doctor cejel-oci --probe
|
|
427
431
|
```
|
|
428
432
|
|
|
@@ -436,9 +440,18 @@ the future paid Agent Pack.
|
|
|
436
440
|
## What "offline" means here
|
|
437
441
|
|
|
438
442
|
Scoring a repo — `cejel scan .` itself, and the Action's scoring step — makes zero network
|
|
439
|
-
calls: no telemetry, no signup, no model call.
|
|
440
|
-
|
|
441
|
-
|
|
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.
|
|
442
455
|
|
|
443
456
|
## Help validate Cejel
|
|
444
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
|
+
};
|