@guilz-dev/belay 0.9.1 → 0.9.3
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 +1 -1
- package/dist/adapters/codex/runtime-entry.d.ts +3 -0
- package/dist/adapters/codex/runtime-entry.js +27 -4
- package/dist/adapters/cursor/cwd-resolution.d.ts +10 -0
- package/dist/adapters/cursor/cwd-resolution.js +58 -0
- package/dist/adapters/cursor/hooks.d.ts +5 -3
- package/dist/adapters/cursor/hooks.js +29 -20
- package/dist/adapters/cursor/runtime-entry.d.ts +1 -0
- package/dist/adapters/cursor/runtime-entry.js +107 -6
- package/dist/adapters/shared/gate-runtime.js +26 -3
- package/dist/adapters/shared/repo-root.js +20 -1
- package/dist/bundle/claude-runtime.mjs +1225 -287
- package/dist/bundle/codex-runtime.mjs +1247 -291
- package/dist/bundle/cursor-runtime.mjs +4320 -3154
- package/dist/cli.js +33 -3
- package/dist/commands/doctor.js +38 -9
- package/dist/commands/health-snapshot.d.ts +3 -0
- package/dist/commands/health-snapshot.js +56 -0
- package/dist/commands/report.js +14 -0
- package/dist/commands/status.js +15 -0
- package/dist/commands/where.d.ts +4 -0
- package/dist/commands/where.js +52 -0
- package/dist/core/approval-repo-lookup.d.ts +16 -0
- package/dist/core/approval-repo-lookup.js +48 -0
- package/dist/core/audit-io.d.ts +1 -1
- package/dist/core/audit-io.js +1 -1
- package/dist/core/audit-legacy-archive.d.ts +1 -0
- package/dist/core/audit-legacy-archive.js +5 -0
- package/dist/core/audit-query.d.ts +1 -0
- package/dist/core/audit-query.js +7 -0
- package/dist/core/audit-serialize.d.ts +3 -0
- package/dist/core/audit-serialize.js +39 -3
- package/dist/core/audit-summary.d.ts +9 -0
- package/dist/core/audit-summary.js +58 -1
- package/dist/core/audit-types.d.ts +4 -0
- package/dist/core/effect-ir/shell-lower.js +283 -27
- package/dist/core/replay-scrub.d.ts +1 -0
- package/dist/core/replay-scrub.js +22 -3
- package/dist/core/shell-tokenizer.d.ts +28 -0
- package/dist/core/shell-tokenizer.js +111 -29
- package/dist/core/verdict/docker-compose-run.d.ts +18 -0
- package/dist/core/verdict/docker-compose-run.js +136 -0
- package/dist/core/verdict/launcher-resolve.js +66 -25
- package/dist/core/verdict/makefile-expand.d.ts +4 -0
- package/dist/core/verdict/makefile-expand.js +151 -0
- package/dist/core/verdict/parser.d.ts +4 -0
- package/dist/core/verdict/parser.js +25 -30
- package/dist/core/verdict/recursive-invocation.d.ts +20 -0
- package/dist/core/verdict/recursive-invocation.js +224 -0
- package/dist/corpus/benign-probe-cores.d.ts +1 -1
- package/dist/corpus/benign-probe-cores.js +2 -0
- package/dist/defaults.js +16 -0
- package/dist/installer/scope-config.d.ts +2 -2
- package/dist/installer.d.ts +10 -1
- package/dist/installer.js +43 -2
- package/dist/types.d.ts +34 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +5 -2
- package/skills/belay/SKILL.md +5 -0
- package/skills/belay/belay-report.md +4 -1
|
@@ -824,6 +824,22 @@ import { createHash } from "node:crypto";
|
|
|
824
824
|
function approvalCorrelationId(approvalId) {
|
|
825
825
|
return createHash("sha256").update(approvalId).digest("hex").slice(0, 16);
|
|
826
826
|
}
|
|
827
|
+
function canonicalToolUseIdForCorrelation(toolUseId) {
|
|
828
|
+
const trimmed = toolUseId.trim();
|
|
829
|
+
if (trimmed.startsWith("tool_")) {
|
|
830
|
+
const remainder = trimmed.slice("tool_".length);
|
|
831
|
+
if (TOOL_USE_UUID_PATTERN.test(remainder)) {
|
|
832
|
+
return remainder.toLowerCase();
|
|
833
|
+
}
|
|
834
|
+
}
|
|
835
|
+
if (TOOL_USE_UUID_PATTERN.test(trimmed)) {
|
|
836
|
+
return trimmed.toLowerCase();
|
|
837
|
+
}
|
|
838
|
+
return trimmed;
|
|
839
|
+
}
|
|
840
|
+
function toolInvocationCorrelationId(toolUseId) {
|
|
841
|
+
return createHash("sha256").update(canonicalToolUseIdForCorrelation(toolUseId)).digest("hex").slice(0, 16);
|
|
842
|
+
}
|
|
827
843
|
function isValidApprovalCorrelationId(value) {
|
|
828
844
|
return /^[a-f0-9]{16}$/.test(value);
|
|
829
845
|
}
|
|
@@ -846,7 +862,16 @@ function isValidPreservedHashField(field, value) {
|
|
|
846
862
|
return isValidAuditFingerprint(value);
|
|
847
863
|
}
|
|
848
864
|
function scrubAuditContainer(value, options) {
|
|
849
|
-
|
|
865
|
+
const withoutRawToolIds = (input) => {
|
|
866
|
+
if (Array.isArray(input)) return input.map(withoutRawToolIds);
|
|
867
|
+
if (input && typeof input === "object") {
|
|
868
|
+
return Object.fromEntries(
|
|
869
|
+
Object.entries(input).filter(([key]) => key !== "tool_use_id").map(([key, child]) => [key, withoutRawToolIds(child)])
|
|
870
|
+
);
|
|
871
|
+
}
|
|
872
|
+
return input;
|
|
873
|
+
};
|
|
874
|
+
return scrubValue(withoutRawToolIds(value), {
|
|
850
875
|
...options,
|
|
851
876
|
maskHighEntropyStrings: true
|
|
852
877
|
});
|
|
@@ -865,7 +890,7 @@ function serializeAuditField(key, value, options) {
|
|
|
865
890
|
if (key === "timestamp" && typeof value === "string" && isValidAuditTimestamp(value)) {
|
|
866
891
|
return value;
|
|
867
892
|
}
|
|
868
|
-
if (key === "approvalCorrelationId" && typeof value === "string" && isValidApprovalCorrelationId(value)) {
|
|
893
|
+
if ((key === "approvalCorrelationId" || key === "toolInvocationCorrelationId") && typeof value === "string" && isValidApprovalCorrelationId(value)) {
|
|
869
894
|
return value;
|
|
870
895
|
}
|
|
871
896
|
if ((key === "runtimeVersion" || key === "runtimeBuildStamp" || key === "boundaryProfile") && typeof value === "string" && value.length > 0) {
|
|
@@ -917,7 +942,7 @@ function serializeAuditRecordV3(record, options) {
|
|
|
917
942
|
serialized.approvalCorrelationId = record.approvalCorrelationId;
|
|
918
943
|
}
|
|
919
944
|
for (const [key, value] of Object.entries(record)) {
|
|
920
|
-
if (key === "timestamp" || key === "ts" || key === "approvalId" || key === "schemaVersion") {
|
|
945
|
+
if (key === "timestamp" || key === "ts" || key === "approvalId" || key === "tool_use_id" || key === "schemaVersion") {
|
|
921
946
|
continue;
|
|
922
947
|
}
|
|
923
948
|
const next = serializeAuditField(key, value, options);
|
|
@@ -927,7 +952,7 @@ function serializeAuditRecordV3(record, options) {
|
|
|
927
952
|
}
|
|
928
953
|
return serialized;
|
|
929
954
|
}
|
|
930
|
-
var AUDIT_SCHEMA_VERSION, ISO8601_PATTERN, HEX64_PATTERN, SCRUB_PLACEHOLDERS, PRESERVED_HASH_FIELDS, PRESERVED_LITERAL_FIELDS, SCRUBBED_CONTAINER_FIELDS;
|
|
955
|
+
var AUDIT_SCHEMA_VERSION, ISO8601_PATTERN, HEX64_PATTERN, SCRUB_PLACEHOLDERS, PRESERVED_HASH_FIELDS, PRESERVED_LITERAL_FIELDS, SCRUBBED_CONTAINER_FIELDS, TOOL_USE_UUID_PATTERN;
|
|
931
956
|
var init_audit_serialize = __esm({
|
|
932
957
|
"src/core/audit-serialize.ts"() {
|
|
933
958
|
"use strict";
|
|
@@ -949,6 +974,7 @@ var init_audit_serialize = __esm({
|
|
|
949
974
|
PRESERVED_LITERAL_FIELDS = /* @__PURE__ */ new Set([
|
|
950
975
|
"timestamp",
|
|
951
976
|
"approvalCorrelationId",
|
|
977
|
+
"toolInvocationCorrelationId",
|
|
952
978
|
"runtimeVersion",
|
|
953
979
|
"runtimeBuildStamp",
|
|
954
980
|
"boundaryProfile",
|
|
@@ -969,6 +995,7 @@ var init_audit_serialize = __esm({
|
|
|
969
995
|
"predictedAssessment",
|
|
970
996
|
"observedAssessment"
|
|
971
997
|
]);
|
|
998
|
+
TOOL_USE_UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
972
999
|
}
|
|
973
1000
|
});
|
|
974
1001
|
|
|
@@ -2209,60 +2236,135 @@ function isRedirectOperator(token) {
|
|
|
2209
2236
|
function isFdDuplication(token) {
|
|
2210
2237
|
return FD_DUPLICATION_PATTERN.test(token);
|
|
2211
2238
|
}
|
|
2212
|
-
function
|
|
2239
|
+
function lexShell(input) {
|
|
2213
2240
|
const tokens = [];
|
|
2214
|
-
let
|
|
2241
|
+
let value = "";
|
|
2242
|
+
let wordStart = null;
|
|
2243
|
+
let parts = [];
|
|
2215
2244
|
let quote = null;
|
|
2216
|
-
let
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
|
|
2245
|
+
let quoteStart = -1;
|
|
2246
|
+
let quoteHadContent = false;
|
|
2247
|
+
let complete = true;
|
|
2248
|
+
const startWord = (index) => {
|
|
2249
|
+
wordStart ??= index;
|
|
2250
|
+
};
|
|
2251
|
+
const append = (decoded, start, end, mode, hasExpansion) => {
|
|
2252
|
+
startWord(start);
|
|
2253
|
+
value += decoded;
|
|
2254
|
+
const previous = parts.at(-1);
|
|
2255
|
+
if (previous && previous.quote === mode && previous.hasExpansion === hasExpansion && previous.end === start) {
|
|
2256
|
+
previous.value += decoded;
|
|
2257
|
+
previous.raw += input.slice(start, end);
|
|
2258
|
+
previous.end = end;
|
|
2259
|
+
return;
|
|
2221
2260
|
}
|
|
2261
|
+
parts.push({
|
|
2262
|
+
value: decoded,
|
|
2263
|
+
raw: input.slice(start, end),
|
|
2264
|
+
start,
|
|
2265
|
+
end,
|
|
2266
|
+
quote: mode,
|
|
2267
|
+
hasExpansion
|
|
2268
|
+
});
|
|
2269
|
+
};
|
|
2270
|
+
const flushWord = (end) => {
|
|
2271
|
+
if (wordStart === null) return;
|
|
2272
|
+
tokens.push({
|
|
2273
|
+
kind: "word",
|
|
2274
|
+
value,
|
|
2275
|
+
raw: input.slice(wordStart, end),
|
|
2276
|
+
start: wordStart,
|
|
2277
|
+
end,
|
|
2278
|
+
parts
|
|
2279
|
+
});
|
|
2280
|
+
value = "";
|
|
2281
|
+
wordStart = null;
|
|
2282
|
+
parts = [];
|
|
2283
|
+
};
|
|
2284
|
+
const pushOperator = (token, start, end) => {
|
|
2285
|
+
tokens.push({ kind: "operator", value: token, raw: input.slice(start, end), start, end });
|
|
2222
2286
|
};
|
|
2223
2287
|
for (let index = 0; index < input.length; index += 1) {
|
|
2224
|
-
const char = input[index];
|
|
2225
|
-
if (
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2288
|
+
const char = input[index] ?? "";
|
|
2289
|
+
if (quote === "single") {
|
|
2290
|
+
if (char === "'") {
|
|
2291
|
+
if (!quoteHadContent) append("", quoteStart, index + 1, "single", false);
|
|
2292
|
+
quote = null;
|
|
2293
|
+
} else {
|
|
2294
|
+
append(char, index, index + 1, "single", false);
|
|
2295
|
+
quoteHadContent = true;
|
|
2296
|
+
}
|
|
2232
2297
|
continue;
|
|
2233
2298
|
}
|
|
2234
|
-
if (quote) {
|
|
2235
|
-
if (char ===
|
|
2299
|
+
if (quote === "double") {
|
|
2300
|
+
if (char === '"') {
|
|
2301
|
+
if (!quoteHadContent) append("", quoteStart, index + 1, "double", false);
|
|
2236
2302
|
quote = null;
|
|
2237
|
-
|
|
2238
|
-
|
|
2303
|
+
continue;
|
|
2304
|
+
}
|
|
2305
|
+
if (char === "\\") {
|
|
2306
|
+
const next = input[index + 1];
|
|
2307
|
+
if (next === void 0) {
|
|
2308
|
+
append("\\", index, index + 1, "double", false);
|
|
2309
|
+
complete = false;
|
|
2310
|
+
continue;
|
|
2311
|
+
}
|
|
2312
|
+
if (next === "$" || next === "`" || next === '"' || next === "\\" || next === "\n") {
|
|
2313
|
+
append(next === "\n" ? "" : next, index, index + 2, "double", false);
|
|
2314
|
+
quoteHadContent = true;
|
|
2315
|
+
index += 1;
|
|
2316
|
+
continue;
|
|
2317
|
+
}
|
|
2318
|
+
append("\\", index, index + 1, "double", false);
|
|
2319
|
+
quoteHadContent = true;
|
|
2320
|
+
continue;
|
|
2239
2321
|
}
|
|
2322
|
+
append(char, index, index + 1, "double", char === "$" || char === "`");
|
|
2323
|
+
quoteHadContent = true;
|
|
2240
2324
|
continue;
|
|
2241
2325
|
}
|
|
2242
|
-
if (char === '"
|
|
2243
|
-
|
|
2326
|
+
if (char === "'" || char === '"') {
|
|
2327
|
+
startWord(index);
|
|
2328
|
+
quote = char === "'" ? "single" : "double";
|
|
2329
|
+
quoteStart = index;
|
|
2330
|
+
quoteHadContent = false;
|
|
2331
|
+
continue;
|
|
2332
|
+
}
|
|
2333
|
+
if (char === "\\") {
|
|
2334
|
+
const next = input[index + 1];
|
|
2335
|
+
if (next === void 0) {
|
|
2336
|
+
append("\\", index, index + 1, "unquoted", false);
|
|
2337
|
+
complete = false;
|
|
2338
|
+
continue;
|
|
2339
|
+
}
|
|
2340
|
+
append(next, index, index + 2, "unquoted", false);
|
|
2341
|
+
index += 1;
|
|
2244
2342
|
continue;
|
|
2245
2343
|
}
|
|
2246
2344
|
const operator = readShellOperator(input, index);
|
|
2247
2345
|
if (operator) {
|
|
2248
|
-
|
|
2249
|
-
|
|
2346
|
+
flushWord(index);
|
|
2347
|
+
pushOperator(operator.token, index, index + operator.length);
|
|
2250
2348
|
index += operator.length - 1;
|
|
2251
2349
|
continue;
|
|
2252
2350
|
}
|
|
2253
2351
|
if (char === "\n" || char === "\r") {
|
|
2254
|
-
|
|
2255
|
-
|
|
2352
|
+
flushWord(index);
|
|
2353
|
+
pushOperator(";", index, index + 1);
|
|
2256
2354
|
continue;
|
|
2257
2355
|
}
|
|
2258
2356
|
if (/\s/.test(char)) {
|
|
2259
|
-
|
|
2357
|
+
flushWord(index);
|
|
2260
2358
|
continue;
|
|
2261
2359
|
}
|
|
2262
|
-
|
|
2360
|
+
append(char, index, index + 1, "unquoted", char === "$" || char === "`");
|
|
2263
2361
|
}
|
|
2264
|
-
|
|
2265
|
-
|
|
2362
|
+
if (quote !== null) complete = false;
|
|
2363
|
+
flushWord(input.length);
|
|
2364
|
+
return { tokens, complete };
|
|
2365
|
+
}
|
|
2366
|
+
function tokenizeShell(input) {
|
|
2367
|
+
return lexShell(input).tokens.map((token) => token.value);
|
|
2266
2368
|
}
|
|
2267
2369
|
function commandKey(tokens) {
|
|
2268
2370
|
const filtered = tokens.filter((token) => token !== "sudo");
|
|
@@ -3472,6 +3574,7 @@ var init_config_io = __esm({
|
|
|
3472
3574
|
|
|
3473
3575
|
// src/adapters/codex/runtime-entry.ts
|
|
3474
3576
|
init_codex();
|
|
3577
|
+
import path56 from "node:path";
|
|
3475
3578
|
import process2 from "node:process";
|
|
3476
3579
|
|
|
3477
3580
|
// src/adapters/shared/gate-runtime.ts
|
|
@@ -3480,7 +3583,7 @@ init_approval_replay();
|
|
|
3480
3583
|
import { randomUUID as randomUUID6 } from "node:crypto";
|
|
3481
3584
|
import { existsSync as existsSync16 } from "node:fs";
|
|
3482
3585
|
import { mkdir as mkdir14, readFile as readFile15, writeFile as writeFile11 } from "node:fs/promises";
|
|
3483
|
-
import
|
|
3586
|
+
import path54 from "node:path";
|
|
3484
3587
|
|
|
3485
3588
|
// src/core/approval-service.ts
|
|
3486
3589
|
init_config_io();
|
|
@@ -10867,6 +10970,24 @@ init_fingerprint2();
|
|
|
10867
10970
|
|
|
10868
10971
|
// src/core/replay-scrub.ts
|
|
10869
10972
|
init_scrub();
|
|
10973
|
+
function redactToolInvocationId(value, rawToolUseId) {
|
|
10974
|
+
if (typeof value === "string") {
|
|
10975
|
+
return rawToolUseId ? value.replaceAll(rawToolUseId, "<tool-use-id>") : value;
|
|
10976
|
+
}
|
|
10977
|
+
if (Array.isArray(value)) {
|
|
10978
|
+
return value.map((item) => redactToolInvocationId(item, rawToolUseId));
|
|
10979
|
+
}
|
|
10980
|
+
if (value && typeof value === "object") {
|
|
10981
|
+
const result = {};
|
|
10982
|
+
for (const [key, child] of Object.entries(value)) {
|
|
10983
|
+
if (key !== "tool_use_id") {
|
|
10984
|
+
result[key] = redactToolInvocationId(child, rawToolUseId);
|
|
10985
|
+
}
|
|
10986
|
+
}
|
|
10987
|
+
return result;
|
|
10988
|
+
}
|
|
10989
|
+
return value;
|
|
10990
|
+
}
|
|
10870
10991
|
function subagentFingerprintSource(payload, scrubOptions) {
|
|
10871
10992
|
const toolInput = payload.tool_input;
|
|
10872
10993
|
if (toolInput && typeof toolInput === "object") {
|
|
@@ -10899,16 +11020,20 @@ function fingerprintReplayPayload(kind, payload, scrubOptions) {
|
|
|
10899
11020
|
if (!payload) {
|
|
10900
11021
|
return void 0;
|
|
10901
11022
|
}
|
|
11023
|
+
const replayPayload = redactToolInvocationId(
|
|
11024
|
+
payload,
|
|
11025
|
+
typeof payload.tool_use_id === "string" ? payload.tool_use_id : void 0
|
|
11026
|
+
);
|
|
10902
11027
|
if (kind === "tool") {
|
|
10903
|
-
const toolInput =
|
|
11028
|
+
const toolInput = replayPayload.tool_input;
|
|
10904
11029
|
if (toolInput && typeof toolInput === "object") {
|
|
10905
11030
|
return scrubValue(toolInput, scrubOptions);
|
|
10906
11031
|
}
|
|
10907
11032
|
}
|
|
10908
11033
|
if (kind === "subagent") {
|
|
10909
|
-
return subagentFingerprintSource(
|
|
11034
|
+
return subagentFingerprintSource(replayPayload, scrubOptions);
|
|
10910
11035
|
}
|
|
10911
|
-
return scrubValue(
|
|
11036
|
+
return scrubValue(replayPayload, scrubOptions);
|
|
10912
11037
|
}
|
|
10913
11038
|
|
|
10914
11039
|
// src/core/classify-subagent.ts
|
|
@@ -11000,7 +11125,7 @@ function classifySubagent(payload, repoRoot, options = {}, config) {
|
|
|
11000
11125
|
}
|
|
11001
11126
|
|
|
11002
11127
|
// src/core/classify-tool.ts
|
|
11003
|
-
import
|
|
11128
|
+
import path42 from "node:path";
|
|
11004
11129
|
init_fingerprint2();
|
|
11005
11130
|
init_path_utils();
|
|
11006
11131
|
init_scrub();
|
|
@@ -11120,12 +11245,349 @@ function worstEffectDecision(decisions) {
|
|
|
11120
11245
|
|
|
11121
11246
|
// src/core/effect-ir/shell-lower.ts
|
|
11122
11247
|
init_git_resource_identity();
|
|
11248
|
+
init_path_utils();
|
|
11123
11249
|
init_shell_tokenizer();
|
|
11124
11250
|
import { lstatSync as lstatSync2, realpathSync as realpathSync4 } from "node:fs";
|
|
11125
|
-
import
|
|
11251
|
+
import path41 from "node:path";
|
|
11126
11252
|
|
|
11127
|
-
// src/core/verdict/
|
|
11253
|
+
// src/core/verdict/docker-compose-run.ts
|
|
11254
|
+
import path36 from "node:path";
|
|
11255
|
+
|
|
11256
|
+
// src/core/verdict/recursive-invocation.ts
|
|
11128
11257
|
import path35 from "node:path";
|
|
11258
|
+
var SHELL_INTERPRETERS = /* @__PURE__ */ new Set(["bash", "sh", "zsh", "dash", "fish"]);
|
|
11259
|
+
var PYTHON_INTERPRETERS = /* @__PURE__ */ new Set(["python", "python3"]);
|
|
11260
|
+
var SHELL_SHORT_OPTIONS = /* @__PURE__ */ new Set(["c", "l", "e", "x", "u"]);
|
|
11261
|
+
var SHELL_NON_SCRIPT_SHORT_OPTIONS = /* @__PURE__ */ new Set(["n"]);
|
|
11262
|
+
var SHELL_TERMINAL_OPTIONS = /* @__PURE__ */ new Map([
|
|
11263
|
+
["bash", /* @__PURE__ */ new Set(["--help", "--version"])],
|
|
11264
|
+
["zsh", /* @__PURE__ */ new Set(["--version"])],
|
|
11265
|
+
["fish", /* @__PURE__ */ new Set(["-h", "--help", "-v", "--version"])]
|
|
11266
|
+
]);
|
|
11267
|
+
var SHELL_VALUE_OPTIONS = /* @__PURE__ */ new Set(["-O", "+O", "--init-file", "--rcfile"]);
|
|
11268
|
+
var NODE_TERMINAL_OPTIONS = /* @__PURE__ */ new Set(["-h", "--help", "--help-all", "-v", "--version"]);
|
|
11269
|
+
var NODE_FILE_OPTIONS = /* @__PURE__ */ new Set(["-c", "--check"]);
|
|
11270
|
+
var PYTHON_PROFILE = {
|
|
11271
|
+
scriptOptions: /* @__PURE__ */ new Set(["-c"]),
|
|
11272
|
+
terminalOptions: /* @__PURE__ */ new Set(["-h", "--help", "-V", "-VV", "--version"]),
|
|
11273
|
+
terminalValueOptions: /* @__PURE__ */ new Set(["-m"]),
|
|
11274
|
+
flagOptions: /* @__PURE__ */ new Set([
|
|
11275
|
+
"-b",
|
|
11276
|
+
"-bb",
|
|
11277
|
+
"-B",
|
|
11278
|
+
"-d",
|
|
11279
|
+
"-E",
|
|
11280
|
+
"-I",
|
|
11281
|
+
"-O",
|
|
11282
|
+
"-OO",
|
|
11283
|
+
"-P",
|
|
11284
|
+
"-q",
|
|
11285
|
+
"-s",
|
|
11286
|
+
"-S",
|
|
11287
|
+
"-u",
|
|
11288
|
+
"-v",
|
|
11289
|
+
"-x"
|
|
11290
|
+
]),
|
|
11291
|
+
valueOptions: /* @__PURE__ */ new Set(["-W", "-X"]),
|
|
11292
|
+
attachedValuePrefixes: ["-W", "-X"]
|
|
11293
|
+
};
|
|
11294
|
+
var RUBY_PROFILE = {
|
|
11295
|
+
scriptOptions: /* @__PURE__ */ new Set(["-e"]),
|
|
11296
|
+
terminalOptions: /* @__PURE__ */ new Set(["-h", "--help", "-v", "--version", "--copyright"]),
|
|
11297
|
+
terminalValueOptions: /* @__PURE__ */ new Set([]),
|
|
11298
|
+
flagOptions: /* @__PURE__ */ new Set(["-d", "--debug", "-w"]),
|
|
11299
|
+
valueOptions: /* @__PURE__ */ new Set(["-I"]),
|
|
11300
|
+
attachedValuePrefixes: ["-I"]
|
|
11301
|
+
};
|
|
11302
|
+
var PERL_PROFILE = {
|
|
11303
|
+
scriptOptions: /* @__PURE__ */ new Set(["-e"]),
|
|
11304
|
+
terminalOptions: /* @__PURE__ */ new Set(["-h", "--help", "-v", "--version"]),
|
|
11305
|
+
terminalValueOptions: /* @__PURE__ */ new Set([]),
|
|
11306
|
+
flagOptions: /* @__PURE__ */ new Set([]),
|
|
11307
|
+
valueOptions: /* @__PURE__ */ new Set(["-I"]),
|
|
11308
|
+
attachedValuePrefixes: ["-I"]
|
|
11309
|
+
};
|
|
11310
|
+
var OSASCRIPT_PROFILE = {
|
|
11311
|
+
scriptOptions: /* @__PURE__ */ new Set(["-e"]),
|
|
11312
|
+
terminalOptions: /* @__PURE__ */ new Set(["-h", "--help"]),
|
|
11313
|
+
terminalValueOptions: /* @__PURE__ */ new Set([]),
|
|
11314
|
+
flagOptions: /* @__PURE__ */ new Set([]),
|
|
11315
|
+
valueOptions: /* @__PURE__ */ new Set(["-l"]),
|
|
11316
|
+
attachedValuePrefixes: []
|
|
11317
|
+
};
|
|
11318
|
+
function normalizeInterpreter(value) {
|
|
11319
|
+
return path35.basename(value);
|
|
11320
|
+
}
|
|
11321
|
+
function scriptResult(interpreter, token) {
|
|
11322
|
+
if (!token) {
|
|
11323
|
+
return { kind: "indeterminate", interpreter, signal: "shell.interpreter_argv_incomplete" };
|
|
11324
|
+
}
|
|
11325
|
+
if (token.parts.some((part) => part.hasExpansion)) {
|
|
11326
|
+
return { kind: "dynamic", interpreter, signal: "shell.script_expanded" };
|
|
11327
|
+
}
|
|
11328
|
+
return { kind: "static", interpreter, script: token.value };
|
|
11329
|
+
}
|
|
11330
|
+
function decodeShell(words, interpreter) {
|
|
11331
|
+
for (let index = 1; index < words.length; index += 1) {
|
|
11332
|
+
const option = words[index]?.value ?? "";
|
|
11333
|
+
if (option === "--") return { kind: "none" };
|
|
11334
|
+
if (SHELL_TERMINAL_OPTIONS.get(interpreter)?.has(option)) return { kind: "none" };
|
|
11335
|
+
if (interpreter === "bash" && SHELL_VALUE_OPTIONS.has(option)) {
|
|
11336
|
+
const operand = words[index + 1]?.value;
|
|
11337
|
+
if (!operand || operand.startsWith("-")) {
|
|
11338
|
+
return { kind: "indeterminate", interpreter, signal: "shell.interpreter_option_unknown" };
|
|
11339
|
+
}
|
|
11340
|
+
index += 1;
|
|
11341
|
+
continue;
|
|
11342
|
+
}
|
|
11343
|
+
if (!option.startsWith("-") || option === "-") return { kind: "none" };
|
|
11344
|
+
const flags = [...option.slice(1)];
|
|
11345
|
+
if (flags.length === 0) {
|
|
11346
|
+
return { kind: "indeterminate", interpreter, signal: "shell.interpreter_option_unknown" };
|
|
11347
|
+
}
|
|
11348
|
+
if (flags.every((flag) => SHELL_SHORT_OPTIONS.has(flag))) {
|
|
11349
|
+
if (!flags.includes("c")) continue;
|
|
11350
|
+
return scriptResult(interpreter, words[index + 1]);
|
|
11351
|
+
}
|
|
11352
|
+
if (flags.every(
|
|
11353
|
+
(flag) => SHELL_SHORT_OPTIONS.has(flag) || SHELL_NON_SCRIPT_SHORT_OPTIONS.has(flag)
|
|
11354
|
+
) && flags.some((flag) => SHELL_NON_SCRIPT_SHORT_OPTIONS.has(flag))) {
|
|
11355
|
+
return { kind: "none" };
|
|
11356
|
+
}
|
|
11357
|
+
return { kind: "indeterminate", interpreter, signal: "shell.interpreter_option_unknown" };
|
|
11358
|
+
}
|
|
11359
|
+
return { kind: "none" };
|
|
11360
|
+
}
|
|
11361
|
+
function decodeSeparated(words, interpreter, profile) {
|
|
11362
|
+
for (let index = 1; index < words.length; index += 1) {
|
|
11363
|
+
const option = words[index]?.value ?? "";
|
|
11364
|
+
if (option === "--" || !option.startsWith("-") || option === "-") return { kind: "none" };
|
|
11365
|
+
if (profile.scriptOptions.has(option)) {
|
|
11366
|
+
return scriptResult(interpreter, words[index + 1]);
|
|
11367
|
+
}
|
|
11368
|
+
if (profile.terminalOptions.has(option)) return { kind: "none" };
|
|
11369
|
+
if (profile.terminalValueOptions.has(option)) {
|
|
11370
|
+
const operand = words[index + 1]?.value;
|
|
11371
|
+
if (!operand || operand.startsWith("-")) {
|
|
11372
|
+
return { kind: "indeterminate", interpreter, signal: "shell.interpreter_option_unknown" };
|
|
11373
|
+
}
|
|
11374
|
+
return { kind: "none" };
|
|
11375
|
+
}
|
|
11376
|
+
if (profile.flagOptions.has(option)) {
|
|
11377
|
+
continue;
|
|
11378
|
+
}
|
|
11379
|
+
if (profile.valueOptions.has(option)) {
|
|
11380
|
+
const operand = words[index + 1]?.value;
|
|
11381
|
+
if (!operand || operand.startsWith("-")) {
|
|
11382
|
+
return { kind: "indeterminate", interpreter, signal: "shell.interpreter_option_unknown" };
|
|
11383
|
+
}
|
|
11384
|
+
index += 1;
|
|
11385
|
+
continue;
|
|
11386
|
+
}
|
|
11387
|
+
if (profile.attachedValuePrefixes.some(
|
|
11388
|
+
(prefix) => option.startsWith(prefix) && option.length > prefix.length
|
|
11389
|
+
)) {
|
|
11390
|
+
continue;
|
|
11391
|
+
}
|
|
11392
|
+
return { kind: "indeterminate", interpreter, signal: "shell.interpreter_option_unknown" };
|
|
11393
|
+
}
|
|
11394
|
+
return { kind: "none" };
|
|
11395
|
+
}
|
|
11396
|
+
function decodeNode(words, interpreter) {
|
|
11397
|
+
const option = words[1]?.value ?? "";
|
|
11398
|
+
if (option === "--" || !option.startsWith("-") || option === "-") return { kind: "none" };
|
|
11399
|
+
if (option === "-e" || option === "--eval") {
|
|
11400
|
+
return scriptResult(interpreter, words[2]);
|
|
11401
|
+
}
|
|
11402
|
+
if (option.startsWith("--eval=")) {
|
|
11403
|
+
const script = option.slice("--eval=".length);
|
|
11404
|
+
if (words[1]?.parts.some((part) => part.hasExpansion)) {
|
|
11405
|
+
return { kind: "dynamic", interpreter, signal: "shell.script_expanded" };
|
|
11406
|
+
}
|
|
11407
|
+
return { kind: "static", interpreter, script };
|
|
11408
|
+
}
|
|
11409
|
+
if (NODE_TERMINAL_OPTIONS.has(option)) return { kind: "none" };
|
|
11410
|
+
if (NODE_FILE_OPTIONS.has(option)) return { kind: "none" };
|
|
11411
|
+
return { kind: "indeterminate", interpreter, signal: "shell.interpreter_option_unknown" };
|
|
11412
|
+
}
|
|
11413
|
+
function decodeEval(words) {
|
|
11414
|
+
const arguments_ = words.slice(1);
|
|
11415
|
+
if (arguments_.length === 0) return { kind: "none" };
|
|
11416
|
+
if (arguments_.some((word) => word.parts.some((part) => part.hasExpansion))) {
|
|
11417
|
+
return { kind: "dynamic", interpreter: "eval", signal: "shell.script_expanded" };
|
|
11418
|
+
}
|
|
11419
|
+
return {
|
|
11420
|
+
kind: "static",
|
|
11421
|
+
interpreter: "eval",
|
|
11422
|
+
script: arguments_.map((word) => word.value).join(" ")
|
|
11423
|
+
};
|
|
11424
|
+
}
|
|
11425
|
+
function decodeRecursiveInvocation(tokens) {
|
|
11426
|
+
if (tokens.some((token) => token.kind === "operator")) return { kind: "none" };
|
|
11427
|
+
const words = tokens.filter((token) => token.kind === "word");
|
|
11428
|
+
const interpreter = normalizeInterpreter(words[0]?.value ?? "");
|
|
11429
|
+
if (!interpreter) return { kind: "none" };
|
|
11430
|
+
if (interpreter === "eval") return decodeEval(words);
|
|
11431
|
+
if (SHELL_INTERPRETERS.has(interpreter)) return decodeShell(words, interpreter);
|
|
11432
|
+
if (PYTHON_INTERPRETERS.has(interpreter)) {
|
|
11433
|
+
return decodeSeparated(words, interpreter, PYTHON_PROFILE);
|
|
11434
|
+
}
|
|
11435
|
+
if (interpreter === "node") return decodeNode(words, interpreter);
|
|
11436
|
+
if (interpreter === "ruby") return decodeSeparated(words, interpreter, RUBY_PROFILE);
|
|
11437
|
+
if (interpreter === "perl") return decodeSeparated(words, interpreter, PERL_PROFILE);
|
|
11438
|
+
if (interpreter === "osascript") return decodeSeparated(words, interpreter, OSASCRIPT_PROFILE);
|
|
11439
|
+
return { kind: "none" };
|
|
11440
|
+
}
|
|
11441
|
+
function shellTokensFromValues(values, options = {}) {
|
|
11442
|
+
let offset = 0;
|
|
11443
|
+
return values.map((value) => {
|
|
11444
|
+
const start = offset;
|
|
11445
|
+
const end = start + value.length;
|
|
11446
|
+
offset = end + 1;
|
|
11447
|
+
return {
|
|
11448
|
+
kind: "word",
|
|
11449
|
+
value,
|
|
11450
|
+
raw: value,
|
|
11451
|
+
start,
|
|
11452
|
+
end,
|
|
11453
|
+
parts: [
|
|
11454
|
+
{
|
|
11455
|
+
value,
|
|
11456
|
+
raw: value,
|
|
11457
|
+
start,
|
|
11458
|
+
end,
|
|
11459
|
+
quote: "unquoted",
|
|
11460
|
+
hasExpansion: options.detectExpansion !== false && (value.includes("$") || value.includes("`"))
|
|
11461
|
+
}
|
|
11462
|
+
]
|
|
11463
|
+
};
|
|
11464
|
+
});
|
|
11465
|
+
}
|
|
11466
|
+
|
|
11467
|
+
// src/core/verdict/docker-compose-run.ts
|
|
11468
|
+
var COMPOSE_GLOBAL_OPTIONS = /* @__PURE__ */ new Map([
|
|
11469
|
+
["--all-resources", 0],
|
|
11470
|
+
["--ansi", 1],
|
|
11471
|
+
["--compatibility", 0],
|
|
11472
|
+
["--dry-run", 0],
|
|
11473
|
+
["--env-file", 1],
|
|
11474
|
+
["-f", 1],
|
|
11475
|
+
["--file", 1],
|
|
11476
|
+
["--parallel", 1],
|
|
11477
|
+
["--profile", 1],
|
|
11478
|
+
["--progress", 1],
|
|
11479
|
+
["--project-directory", 1],
|
|
11480
|
+
["-p", 1],
|
|
11481
|
+
["--project-name", 1]
|
|
11482
|
+
]);
|
|
11483
|
+
var COMPOSE_RUN_OPTIONS = /* @__PURE__ */ new Map([
|
|
11484
|
+
["--build", 0],
|
|
11485
|
+
["--cap-add", 1],
|
|
11486
|
+
["--cap-drop", 1],
|
|
11487
|
+
["-d", 0],
|
|
11488
|
+
["--detach", 0],
|
|
11489
|
+
["--entrypoint", 1],
|
|
11490
|
+
["-e", 1],
|
|
11491
|
+
["--env", 1],
|
|
11492
|
+
["--env-from-file", 1],
|
|
11493
|
+
["-i", 0],
|
|
11494
|
+
["--interactive", 0],
|
|
11495
|
+
["-l", 1],
|
|
11496
|
+
["--label", 1],
|
|
11497
|
+
["--name", 1],
|
|
11498
|
+
["--no-deps", 0],
|
|
11499
|
+
["-T", 0],
|
|
11500
|
+
["--no-tty", 0],
|
|
11501
|
+
["-p", 1],
|
|
11502
|
+
["--publish", 1],
|
|
11503
|
+
["--pull", 1],
|
|
11504
|
+
["-q", 0],
|
|
11505
|
+
["--quiet", 0],
|
|
11506
|
+
["--quiet-build", 0],
|
|
11507
|
+
["--quiet-pull", 0],
|
|
11508
|
+
["--remove-orphans", 0],
|
|
11509
|
+
["--rm", 0],
|
|
11510
|
+
["-P", 0],
|
|
11511
|
+
["--service-ports", 0],
|
|
11512
|
+
["--use-aliases", 0],
|
|
11513
|
+
["-u", 1],
|
|
11514
|
+
["--user", 1],
|
|
11515
|
+
["-v", 1],
|
|
11516
|
+
["--volume", 1],
|
|
11517
|
+
["-w", 1],
|
|
11518
|
+
["--workdir", 1]
|
|
11519
|
+
]);
|
|
11520
|
+
function parseOptions(words, start, options) {
|
|
11521
|
+
let index = start;
|
|
11522
|
+
while (index < words.length) {
|
|
11523
|
+
const value = words[index]?.value ?? "";
|
|
11524
|
+
if (value === "--") return { kind: "ok", index: index + 1 };
|
|
11525
|
+
if (!value.startsWith("-") || value === "-") return { kind: "ok", index };
|
|
11526
|
+
const equalsIndex = value.indexOf("=");
|
|
11527
|
+
const name = equalsIndex === -1 ? value : value.slice(0, equalsIndex);
|
|
11528
|
+
const arity = options.get(name);
|
|
11529
|
+
if (arity === void 0) return { kind: "indeterminate" };
|
|
11530
|
+
if (equalsIndex !== -1) {
|
|
11531
|
+
if (!value.startsWith("--") || arity !== 1 || equalsIndex === value.length - 1) {
|
|
11532
|
+
return { kind: "indeterminate" };
|
|
11533
|
+
}
|
|
11534
|
+
index += 1;
|
|
11535
|
+
continue;
|
|
11536
|
+
}
|
|
11537
|
+
if (arity === 1) {
|
|
11538
|
+
if (!words[index + 1]) return { kind: "indeterminate" };
|
|
11539
|
+
index += 2;
|
|
11540
|
+
continue;
|
|
11541
|
+
}
|
|
11542
|
+
index += 1;
|
|
11543
|
+
}
|
|
11544
|
+
return { kind: "ok", index };
|
|
11545
|
+
}
|
|
11546
|
+
function decodeDockerComposeRun(tokens) {
|
|
11547
|
+
if (tokens.some((token) => token.kind === "operator")) return { kind: "none" };
|
|
11548
|
+
const words = tokens.filter((token) => token.kind === "word");
|
|
11549
|
+
const head = path36.basename(words[0]?.value ?? "");
|
|
11550
|
+
let index;
|
|
11551
|
+
if (head === "docker-compose") {
|
|
11552
|
+
index = 1;
|
|
11553
|
+
} else if (head === "docker" && words[1]?.value === "compose") {
|
|
11554
|
+
index = 2;
|
|
11555
|
+
} else {
|
|
11556
|
+
return { kind: "none" };
|
|
11557
|
+
}
|
|
11558
|
+
const globalOptions = parseOptions(words, index, COMPOSE_GLOBAL_OPTIONS);
|
|
11559
|
+
if (globalOptions.kind === "indeterminate") {
|
|
11560
|
+
return { kind: "indeterminate", signal: "shell.compose_argv_indeterminate" };
|
|
11561
|
+
}
|
|
11562
|
+
index = globalOptions.index;
|
|
11563
|
+
if (words[index]?.value !== "run") return { kind: "none" };
|
|
11564
|
+
const runOptions = parseOptions(words, index + 1, COMPOSE_RUN_OPTIONS);
|
|
11565
|
+
if (runOptions.kind === "indeterminate") {
|
|
11566
|
+
return { kind: "indeterminate", signal: "shell.compose_argv_indeterminate" };
|
|
11567
|
+
}
|
|
11568
|
+
index = runOptions.index;
|
|
11569
|
+
const service = words[index]?.value;
|
|
11570
|
+
if (!service) return { kind: "indeterminate", signal: "shell.compose_argv_indeterminate" };
|
|
11571
|
+
const command = words.slice(index + 1);
|
|
11572
|
+
if (command.length === 0) return { kind: "none" };
|
|
11573
|
+
const recursive = decodeRecursiveInvocation(command);
|
|
11574
|
+
if (recursive.kind === "static") {
|
|
11575
|
+
return {
|
|
11576
|
+
kind: "recursive",
|
|
11577
|
+
service,
|
|
11578
|
+
interpreter: recursive.interpreter,
|
|
11579
|
+
script: recursive.script
|
|
11580
|
+
};
|
|
11581
|
+
}
|
|
11582
|
+
if (recursive.kind === "dynamic") return { kind: "dynamic", service, signal: recursive.signal };
|
|
11583
|
+
if (recursive.kind === "indeterminate") {
|
|
11584
|
+
return { kind: "indeterminate", signal: "shell.compose_argv_indeterminate" };
|
|
11585
|
+
}
|
|
11586
|
+
return { kind: "none" };
|
|
11587
|
+
}
|
|
11588
|
+
|
|
11589
|
+
// src/core/verdict/egress-classify.ts
|
|
11590
|
+
import path37 from "node:path";
|
|
11129
11591
|
var CURL_EFFECT_NEUTRAL_FLAGS = /* @__PURE__ */ new Set([
|
|
11130
11592
|
"-f",
|
|
11131
11593
|
"-L",
|
|
@@ -11160,7 +11622,7 @@ var GH_READ_COMMANDS = /* @__PURE__ */ new Set([
|
|
|
11160
11622
|
"workflow view"
|
|
11161
11623
|
]);
|
|
11162
11624
|
function decodeEgressEffects(params) {
|
|
11163
|
-
const head =
|
|
11625
|
+
const head = path37.basename(params.tokens[0] ?? "");
|
|
11164
11626
|
if (head !== "curl" && head !== "wget" && head !== "gh") {
|
|
11165
11627
|
return null;
|
|
11166
11628
|
}
|
|
@@ -11168,7 +11630,7 @@ function decodeEgressEffects(params) {
|
|
|
11168
11630
|
const provenance = { segment: params.segment };
|
|
11169
11631
|
const requirements = [];
|
|
11170
11632
|
for (const file of decoded.files) {
|
|
11171
|
-
const resolved =
|
|
11633
|
+
const resolved = path37.resolve(params.cwd, expandHome2(file));
|
|
11172
11634
|
requirements.push(
|
|
11173
11635
|
requirement("fs.read", "fs.read", { kind: "path", path: resolved }, params.segment, [
|
|
11174
11636
|
"egress.explicit_file_read"
|
|
@@ -11190,7 +11652,7 @@ function decodeEgressEffects(params) {
|
|
|
11190
11652
|
if (file === "-") {
|
|
11191
11653
|
continue;
|
|
11192
11654
|
}
|
|
11193
|
-
const resolved =
|
|
11655
|
+
const resolved = path37.resolve(params.cwd, expandHome2(file));
|
|
11194
11656
|
if (resolved === "/dev/null") {
|
|
11195
11657
|
continue;
|
|
11196
11658
|
}
|
|
@@ -11668,13 +12130,13 @@ function decodeSingleCurlWgetGrammar(head, tokens) {
|
|
|
11668
12130
|
if (head === "wget" && !explicitOutput) {
|
|
11669
12131
|
outputFiles.push(
|
|
11670
12132
|
...endpointOutputNames.map(
|
|
11671
|
-
(name) => outputDirectory ?
|
|
12133
|
+
(name) => outputDirectory ? path37.join(outputDirectory, name) : name
|
|
11672
12134
|
)
|
|
11673
12135
|
);
|
|
11674
12136
|
} else if (head === "curl" && remoteNameOutput) {
|
|
11675
12137
|
outputFiles.push(
|
|
11676
12138
|
...endpointOutputNames.map(
|
|
11677
|
-
(name) => outputDirectory ?
|
|
12139
|
+
(name) => outputDirectory ? path37.join(outputDirectory, name) : name
|
|
11678
12140
|
)
|
|
11679
12141
|
);
|
|
11680
12142
|
}
|
|
@@ -11688,7 +12150,7 @@ function decodeSingleCurlWgetGrammar(head, tokens) {
|
|
|
11688
12150
|
outputFiles: [
|
|
11689
12151
|
...new Set(
|
|
11690
12152
|
outputFiles.map(
|
|
11691
|
-
(file) => outputDirectory && directoryEligibleOutputs.has(file) && !
|
|
12153
|
+
(file) => outputDirectory && directoryEligibleOutputs.has(file) && !path37.isAbsolute(file) ? path37.join(outputDirectory, file) : file
|
|
11692
12154
|
)
|
|
11693
12155
|
)
|
|
11694
12156
|
],
|
|
@@ -11703,7 +12165,7 @@ function remoteOutputName(spec) {
|
|
|
11703
12165
|
} catch {
|
|
11704
12166
|
pathname = spec.split(/[?#]/, 1)[0] ?? "";
|
|
11705
12167
|
}
|
|
11706
|
-
const name =
|
|
12168
|
+
const name = path37.posix.basename(pathname);
|
|
11707
12169
|
return name && name !== "/" ? name : "index.html";
|
|
11708
12170
|
}
|
|
11709
12171
|
function decodeGhGrammar(tokens) {
|
|
@@ -11868,7 +12330,7 @@ function expandHome2(value) {
|
|
|
11868
12330
|
return process.env.HOME ?? value;
|
|
11869
12331
|
}
|
|
11870
12332
|
if (value.startsWith("~/")) {
|
|
11871
|
-
return
|
|
12333
|
+
return path37.join(process.env.HOME ?? "~", value.slice(2));
|
|
11872
12334
|
}
|
|
11873
12335
|
return value;
|
|
11874
12336
|
}
|
|
@@ -11887,7 +12349,7 @@ function requirement(tag, action, resource, segment, signals) {
|
|
|
11887
12349
|
}
|
|
11888
12350
|
|
|
11889
12351
|
// src/core/verdict/git-classifier.ts
|
|
11890
|
-
import
|
|
12352
|
+
import path38 from "node:path";
|
|
11891
12353
|
init_shell_tokenizer();
|
|
11892
12354
|
var GIT_BRANCH_MUTATION_FLAGS = /* @__PURE__ */ new Set([
|
|
11893
12355
|
"--copy",
|
|
@@ -11983,7 +12445,7 @@ var FILE_OPERAND_SUBCOMMANDS = /* @__PURE__ */ new Set([
|
|
|
11983
12445
|
var COMPOUND_SUBCOMMAND_HEADS = /* @__PURE__ */ new Set(["worktree", "stash", "tag"]);
|
|
11984
12446
|
var REF_ONLY_WITHOUT_TERMINATOR = /* @__PURE__ */ new Set(["checkout", "show", "log"]);
|
|
11985
12447
|
function isGitExecutable(token) {
|
|
11986
|
-
return
|
|
12448
|
+
return path38.basename(token) === "git";
|
|
11987
12449
|
}
|
|
11988
12450
|
function takesValue(flag) {
|
|
11989
12451
|
return flag === "-C" || flag === "-c" || flag === "--git-dir" || flag === "--work-tree" || flag === "--exec-path" || flag === "--paginate" || flag === "--config-env" || flag.startsWith("-C") || flag.startsWith("-c") || flag.startsWith("--git-dir=") || flag.startsWith("--work-tree=");
|
|
@@ -12011,7 +12473,7 @@ function peelGlobalOptions(tokens, baseCwd) {
|
|
|
12011
12473
|
if (token === "-C" || token === "--work-tree" || token === "--git-dir" || token === "-c") {
|
|
12012
12474
|
const value = tokens[index + 1];
|
|
12013
12475
|
if (token === "-C" && value) {
|
|
12014
|
-
effectiveCwd =
|
|
12476
|
+
effectiveCwd = path38.resolve(baseCwd, value);
|
|
12015
12477
|
} else if (token === "--work-tree" && value) {
|
|
12016
12478
|
workTree = value;
|
|
12017
12479
|
} else if (token === "--git-dir" && value) {
|
|
@@ -12021,7 +12483,7 @@ function peelGlobalOptions(tokens, baseCwd) {
|
|
|
12021
12483
|
continue;
|
|
12022
12484
|
}
|
|
12023
12485
|
if (token.startsWith("-C") && token.length > 2) {
|
|
12024
|
-
effectiveCwd =
|
|
12486
|
+
effectiveCwd = path38.resolve(baseCwd, token.slice(2));
|
|
12025
12487
|
index += 1;
|
|
12026
12488
|
continue;
|
|
12027
12489
|
}
|
|
@@ -12164,7 +12626,7 @@ function looksLikeDiffPathOperand(token) {
|
|
|
12164
12626
|
if (!looksLikeFileOperand(token)) {
|
|
12165
12627
|
return false;
|
|
12166
12628
|
}
|
|
12167
|
-
if (token.startsWith(".") ||
|
|
12629
|
+
if (token.startsWith(".") || path38.isAbsolute(token)) {
|
|
12168
12630
|
return true;
|
|
12169
12631
|
}
|
|
12170
12632
|
return token.includes(".");
|
|
@@ -12172,12 +12634,12 @@ function looksLikeDiffPathOperand(token) {
|
|
|
12172
12634
|
function resolveGitWorkTree(baseCwd, effectiveCwd, workTree, gitDir) {
|
|
12173
12635
|
const resolveBase = effectiveCwd ?? baseCwd;
|
|
12174
12636
|
if (workTree) {
|
|
12175
|
-
return
|
|
12637
|
+
return path38.resolve(resolveBase, workTree);
|
|
12176
12638
|
}
|
|
12177
12639
|
if (gitDir) {
|
|
12178
|
-
const resolvedGitDir =
|
|
12179
|
-
if (
|
|
12180
|
-
return
|
|
12640
|
+
const resolvedGitDir = path38.resolve(resolveBase, gitDir);
|
|
12641
|
+
if (path38.basename(resolvedGitDir) === ".git") {
|
|
12642
|
+
return path38.dirname(resolvedGitDir);
|
|
12181
12643
|
}
|
|
12182
12644
|
}
|
|
12183
12645
|
return void 0;
|
|
@@ -12258,7 +12720,7 @@ function classifyGitCommand(tokens, baseCwd) {
|
|
|
12258
12720
|
const { subcommand, args, effectiveCwd, gitDir, workTree } = normalized;
|
|
12259
12721
|
const normalizedKey = `git ${subcommand}`;
|
|
12260
12722
|
const gitWorkTree = resolveGitWorkTree(baseCwd, effectiveCwd, workTree, gitDir);
|
|
12261
|
-
const effectiveGitDir = gitDir ?
|
|
12723
|
+
const effectiveGitDir = gitDir ? path38.resolve(effectiveCwd ?? baseCwd, gitDir) : void 0;
|
|
12262
12724
|
const scopeTargets = [effectiveCwd, gitWorkTree, effectiveGitDir].filter(
|
|
12263
12725
|
(target, index, targets) => Boolean(target) && targets.indexOf(target) === index
|
|
12264
12726
|
);
|
|
@@ -12410,9 +12872,9 @@ function decodeGitEffects(params) {
|
|
|
12410
12872
|
...subcommand === "push" ? ["tier0_external"] : []
|
|
12411
12873
|
];
|
|
12412
12874
|
const effectiveCwd = normalized.effectiveCwd ?? params.cwd;
|
|
12413
|
-
const workTreeRoot = normalized.workTree ?
|
|
12414
|
-
const gitRefRoot = normalized.gitDir ?
|
|
12415
|
-
const gitControlRoot = normalized.gitDir ? gitRefRoot :
|
|
12875
|
+
const workTreeRoot = normalized.workTree ? path38.resolve(normalized.effectiveCwd ?? params.cwd, normalized.workTree) : normalized.effectiveCwd ?? params.repoRoot;
|
|
12876
|
+
const gitRefRoot = normalized.gitDir ? path38.resolve(effectiveCwd, normalized.gitDir) : workTreeRoot;
|
|
12877
|
+
const gitControlRoot = normalized.gitDir ? gitRefRoot : path38.join(gitRefRoot, ".git");
|
|
12416
12878
|
const requirements = [];
|
|
12417
12879
|
if (subcommand === "fetch" || subcommand === "pull") {
|
|
12418
12880
|
const positionals = gitRemotePositionals(args);
|
|
@@ -12571,7 +13033,7 @@ function decodeGitEffects(params) {
|
|
|
12571
13033
|
gitRequirement(
|
|
12572
13034
|
"control_plane.write",
|
|
12573
13035
|
"control_plane.write",
|
|
12574
|
-
{ kind: "path", path:
|
|
13036
|
+
{ kind: "path", path: path38.join(gitControlRoot, "logs") },
|
|
12575
13037
|
params.segment,
|
|
12576
13038
|
[...signals, "git_history_destructive", "git.reflog.mutate"]
|
|
12577
13039
|
)
|
|
@@ -12629,7 +13091,7 @@ function decodeGitEffects(params) {
|
|
|
12629
13091
|
gitRequirement(
|
|
12630
13092
|
"fs.read",
|
|
12631
13093
|
"fs.read",
|
|
12632
|
-
{ kind: "path", path:
|
|
13094
|
+
{ kind: "path", path: path38.resolve(workTreeRoot, operand) },
|
|
12633
13095
|
params.segment,
|
|
12634
13096
|
[...signals, "git.path.read"]
|
|
12635
13097
|
)
|
|
@@ -12664,7 +13126,7 @@ function decodeGitEffects(params) {
|
|
|
12664
13126
|
gitRequirement(
|
|
12665
13127
|
"fs.write",
|
|
12666
13128
|
"fs.write",
|
|
12667
|
-
{ kind: "path", path:
|
|
13129
|
+
{ kind: "path", path: path38.resolve(workTreeRoot, operand) },
|
|
12668
13130
|
params.segment,
|
|
12669
13131
|
[...signals, "git.path.write"]
|
|
12670
13132
|
)
|
|
@@ -12849,7 +13311,144 @@ function gitRequirement(tag, action, resource, segment, signals) {
|
|
|
12849
13311
|
|
|
12850
13312
|
// src/core/verdict/launcher-resolve.ts
|
|
12851
13313
|
import { existsSync as existsSync11, readFileSync as readFileSync5 } from "node:fs";
|
|
12852
|
-
import
|
|
13314
|
+
import path39 from "node:path";
|
|
13315
|
+
|
|
13316
|
+
// src/core/verdict/makefile-expand.ts
|
|
13317
|
+
var MAX_EXPAND_DEPTH = 16;
|
|
13318
|
+
function parseMakefileVariables(content) {
|
|
13319
|
+
const variables = /* @__PURE__ */ new Map();
|
|
13320
|
+
for (const line of content.split("\n")) {
|
|
13321
|
+
const trimmed = line.trim();
|
|
13322
|
+
if (!trimmed || trimmed.startsWith("#")) {
|
|
13323
|
+
continue;
|
|
13324
|
+
}
|
|
13325
|
+
const match = /^([A-Za-z_][A-Za-z0-9_]*)\s*[:?]?=\s*(.+)$/.exec(trimmed);
|
|
13326
|
+
if (!match) {
|
|
13327
|
+
continue;
|
|
13328
|
+
}
|
|
13329
|
+
variables.set(match[1] ?? "", (match[2] ?? "").trim());
|
|
13330
|
+
}
|
|
13331
|
+
return variables;
|
|
13332
|
+
}
|
|
13333
|
+
function normalizeMakeRecipeLine(line) {
|
|
13334
|
+
let normalized = line.trim();
|
|
13335
|
+
while (normalized.startsWith("@") || normalized.startsWith("-") || normalized.startsWith("+")) {
|
|
13336
|
+
normalized = normalized.slice(1).trimStart();
|
|
13337
|
+
}
|
|
13338
|
+
return normalized;
|
|
13339
|
+
}
|
|
13340
|
+
function expandMakeExpression(expression, cliVars, makefileVars) {
|
|
13341
|
+
if (/\$\(\s*shell\b/i.test(expression) || expression.includes("$$")) {
|
|
13342
|
+
return null;
|
|
13343
|
+
}
|
|
13344
|
+
try {
|
|
13345
|
+
const expanded = expandMakeValue(expression, cliVars, makefileVars, 0);
|
|
13346
|
+
if (expanded === null || /\$\(/.test(expanded) || /\$\{/.test(expanded)) {
|
|
13347
|
+
return null;
|
|
13348
|
+
}
|
|
13349
|
+
return expanded;
|
|
13350
|
+
} catch {
|
|
13351
|
+
return null;
|
|
13352
|
+
}
|
|
13353
|
+
}
|
|
13354
|
+
function expandMakeValue(expression, cliVars, makefileVars, depth) {
|
|
13355
|
+
if (depth > MAX_EXPAND_DEPTH) {
|
|
13356
|
+
return null;
|
|
13357
|
+
}
|
|
13358
|
+
let value = expression.trim();
|
|
13359
|
+
let changed = true;
|
|
13360
|
+
let iterations = 0;
|
|
13361
|
+
while (changed && iterations < MAX_EXPAND_DEPTH) {
|
|
13362
|
+
changed = false;
|
|
13363
|
+
iterations += 1;
|
|
13364
|
+
const orMatch = value.match(/\$\(\s*or\s+([^()]*(?:\([^)]*\)[^()]*)*)\)/);
|
|
13365
|
+
if (orMatch) {
|
|
13366
|
+
const [fullMatch, inner] = orMatch;
|
|
13367
|
+
const parts = splitMakeFunctionArgs(inner ?? "");
|
|
13368
|
+
let selected = null;
|
|
13369
|
+
for (const part of parts) {
|
|
13370
|
+
const expanded = expandMakeValue(part.trim(), cliVars, makefileVars, depth + 1);
|
|
13371
|
+
if (expanded !== null && expanded.trim() !== "") {
|
|
13372
|
+
selected = expanded;
|
|
13373
|
+
break;
|
|
13374
|
+
}
|
|
13375
|
+
}
|
|
13376
|
+
if (selected === null) {
|
|
13377
|
+
const fallback = parts.at(-1)?.trim();
|
|
13378
|
+
selected = fallback === void 0 ? "" : expandMakeValue(fallback, cliVars, makefileVars, depth + 1);
|
|
13379
|
+
}
|
|
13380
|
+
if (selected === null) {
|
|
13381
|
+
return null;
|
|
13382
|
+
}
|
|
13383
|
+
value = value.replace(fullMatch, selected);
|
|
13384
|
+
changed = true;
|
|
13385
|
+
continue;
|
|
13386
|
+
}
|
|
13387
|
+
const varMatch = value.match(/\$\(([A-Za-z_][A-Za-z0-9_]*)\)/);
|
|
13388
|
+
if (varMatch) {
|
|
13389
|
+
const [fullMatch, name] = varMatch;
|
|
13390
|
+
const resolved = resolveMakeVariable(name ?? "", cliVars, makefileVars, depth + 1);
|
|
13391
|
+
if (resolved === null) {
|
|
13392
|
+
return null;
|
|
13393
|
+
}
|
|
13394
|
+
value = value.replace(fullMatch, resolved);
|
|
13395
|
+
changed = true;
|
|
13396
|
+
continue;
|
|
13397
|
+
}
|
|
13398
|
+
const bracedMatch = value.match(/\$\{([A-Za-z_][A-Za-z0-9_]*)\}/);
|
|
13399
|
+
if (bracedMatch) {
|
|
13400
|
+
const [fullMatch, name] = bracedMatch;
|
|
13401
|
+
const resolved = name === "PWD" ? "." : resolveMakeVariable(name ?? "", cliVars, makefileVars, depth + 1);
|
|
13402
|
+
if (resolved === null) {
|
|
13403
|
+
return null;
|
|
13404
|
+
}
|
|
13405
|
+
value = value.replace(fullMatch, resolved);
|
|
13406
|
+
changed = true;
|
|
13407
|
+
continue;
|
|
13408
|
+
}
|
|
13409
|
+
break;
|
|
13410
|
+
}
|
|
13411
|
+
return value;
|
|
13412
|
+
}
|
|
13413
|
+
function resolveMakeVariable(name, cliVars, makefileVars, depth) {
|
|
13414
|
+
if (Object.hasOwn(cliVars, name)) {
|
|
13415
|
+
return cliVars[name] ?? "";
|
|
13416
|
+
}
|
|
13417
|
+
const definition = makefileVars.get(name);
|
|
13418
|
+
if (definition === void 0) {
|
|
13419
|
+
return null;
|
|
13420
|
+
}
|
|
13421
|
+
return expandMakeValue(definition, cliVars, makefileVars, depth);
|
|
13422
|
+
}
|
|
13423
|
+
function splitMakeFunctionArgs(input) {
|
|
13424
|
+
const parts = [];
|
|
13425
|
+
let current = "";
|
|
13426
|
+
let depth = 0;
|
|
13427
|
+
for (const char of input) {
|
|
13428
|
+
if (char === "(") {
|
|
13429
|
+
depth += 1;
|
|
13430
|
+
current += char;
|
|
13431
|
+
continue;
|
|
13432
|
+
}
|
|
13433
|
+
if (char === ")") {
|
|
13434
|
+
depth -= 1;
|
|
13435
|
+
current += char;
|
|
13436
|
+
continue;
|
|
13437
|
+
}
|
|
13438
|
+
if (char === "," && depth === 0) {
|
|
13439
|
+
parts.push(current.trim());
|
|
13440
|
+
current = "";
|
|
13441
|
+
continue;
|
|
13442
|
+
}
|
|
13443
|
+
current += char;
|
|
13444
|
+
}
|
|
13445
|
+
if (current.trim()) {
|
|
13446
|
+
parts.push(current.trim());
|
|
13447
|
+
}
|
|
13448
|
+
return parts;
|
|
13449
|
+
}
|
|
13450
|
+
|
|
13451
|
+
// src/core/verdict/launcher-resolve.ts
|
|
12853
13452
|
var MAX_RESOLVE_DEPTH = 8;
|
|
12854
13453
|
var PNPM_BUILTIN_COMMANDS = /* @__PURE__ */ new Set([
|
|
12855
13454
|
"add",
|
|
@@ -12885,7 +13484,7 @@ var PNPM_BUILTIN_COMMANDS = /* @__PURE__ */ new Set([
|
|
|
12885
13484
|
"why"
|
|
12886
13485
|
]);
|
|
12887
13486
|
function readPackageJson(dir) {
|
|
12888
|
-
const packagePath =
|
|
13487
|
+
const packagePath = path39.join(dir, "package.json");
|
|
12889
13488
|
if (!existsSync11(packagePath)) {
|
|
12890
13489
|
return null;
|
|
12891
13490
|
}
|
|
@@ -12896,17 +13495,17 @@ function readPackageJson(dir) {
|
|
|
12896
13495
|
}
|
|
12897
13496
|
}
|
|
12898
13497
|
function findPackageJson(startDir, stopDir) {
|
|
12899
|
-
let current =
|
|
12900
|
-
const stop =
|
|
13498
|
+
let current = path39.resolve(startDir);
|
|
13499
|
+
const stop = path39.resolve(stopDir);
|
|
12901
13500
|
while (true) {
|
|
12902
|
-
const packagePath =
|
|
13501
|
+
const packagePath = path39.join(current, "package.json");
|
|
12903
13502
|
if (existsSync11(packagePath)) {
|
|
12904
13503
|
return packagePath;
|
|
12905
13504
|
}
|
|
12906
|
-
if (current === stop || current ===
|
|
13505
|
+
if (current === stop || current === path39.dirname(current)) {
|
|
12907
13506
|
return existsSync11(packagePath) ? packagePath : null;
|
|
12908
13507
|
}
|
|
12909
|
-
const parent =
|
|
13508
|
+
const parent = path39.dirname(current);
|
|
12910
13509
|
if (!parent.startsWith(stop) && parent !== current) {
|
|
12911
13510
|
}
|
|
12912
13511
|
if (parent === current) {
|
|
@@ -12963,7 +13562,7 @@ function resolveNpmRecipe(cwd, repoRoot, scriptName, extraArgs) {
|
|
|
12963
13562
|
}
|
|
12964
13563
|
return { recipes: [], opaque: true, reason: "package_json_missing" };
|
|
12965
13564
|
}
|
|
12966
|
-
const pkg = readPackageJson(
|
|
13565
|
+
const pkg = readPackageJson(path39.dirname(packagePath));
|
|
12967
13566
|
const scripts = pkg?.scripts;
|
|
12968
13567
|
if (!scripts || typeof scripts !== "object") {
|
|
12969
13568
|
return { recipes: [], opaque: true, reason: "package_scripts_missing" };
|
|
@@ -12990,10 +13589,9 @@ function resolveNpmRecipe(cwd, repoRoot, scriptName, extraArgs) {
|
|
|
12990
13589
|
reason: "npm_script_resolved"
|
|
12991
13590
|
};
|
|
12992
13591
|
}
|
|
12993
|
-
function
|
|
13592
|
+
function parseMakefileRecipeContent(content) {
|
|
12994
13593
|
const targets = /* @__PURE__ */ new Map();
|
|
12995
13594
|
try {
|
|
12996
|
-
const content = readFileSync5(makefilePath, "utf8");
|
|
12997
13595
|
const lines = content.split("\n");
|
|
12998
13596
|
let currentTarget = null;
|
|
12999
13597
|
let recipeLines = [];
|
|
@@ -13052,78 +13650,96 @@ function parseMakefileRecipes(makefilePath) {
|
|
|
13052
13650
|
}
|
|
13053
13651
|
return targets;
|
|
13054
13652
|
}
|
|
13055
|
-
function resolveMakeRecipe(cwd, repoRoot, target) {
|
|
13653
|
+
function resolveMakeRecipe(cwd, repoRoot, target, cliVars = {}) {
|
|
13056
13654
|
const candidates = ["Makefile", "makefile", "GNUmakefile"];
|
|
13057
13655
|
let makefilePath = null;
|
|
13058
|
-
let searchDir =
|
|
13059
|
-
const stop =
|
|
13656
|
+
let searchDir = path39.resolve(cwd);
|
|
13657
|
+
const stop = path39.resolve(repoRoot);
|
|
13060
13658
|
while (true) {
|
|
13061
13659
|
for (const name of candidates) {
|
|
13062
|
-
const candidate =
|
|
13660
|
+
const candidate = path39.join(searchDir, name);
|
|
13063
13661
|
if (existsSync11(candidate)) {
|
|
13064
13662
|
makefilePath = candidate;
|
|
13065
13663
|
break;
|
|
13066
13664
|
}
|
|
13067
13665
|
}
|
|
13068
|
-
if (makefilePath || searchDir === stop || searchDir ===
|
|
13666
|
+
if (makefilePath || searchDir === stop || searchDir === path39.dirname(searchDir)) {
|
|
13069
13667
|
break;
|
|
13070
13668
|
}
|
|
13071
|
-
searchDir =
|
|
13669
|
+
searchDir = path39.dirname(searchDir);
|
|
13072
13670
|
}
|
|
13073
13671
|
if (!makefilePath) {
|
|
13074
13672
|
return { recipes: [], opaque: true, reason: "unknown_local_effect" };
|
|
13075
13673
|
}
|
|
13076
|
-
const
|
|
13674
|
+
const makefileContent = readFileSync5(makefilePath, "utf8");
|
|
13675
|
+
const makefileVars = parseMakefileVariables(makefileContent);
|
|
13676
|
+
const targets = parseMakefileRecipeContent(makefileContent);
|
|
13077
13677
|
if (!targets.has(target)) {
|
|
13078
13678
|
return { recipes: [], opaque: true, reason: "make_target_undefined" };
|
|
13079
13679
|
}
|
|
13080
13680
|
const recipeLines = [];
|
|
13081
13681
|
const visiting = /* @__PURE__ */ new Set();
|
|
13082
13682
|
const visited = /* @__PURE__ */ new Set();
|
|
13083
|
-
let
|
|
13683
|
+
let hasDynamicPrerequisite = false;
|
|
13684
|
+
let hasUndefinedPrerequisite = false;
|
|
13685
|
+
let hasDependencyCycle = false;
|
|
13084
13686
|
const collect = (name) => {
|
|
13085
13687
|
if (visited.has(name)) {
|
|
13086
|
-
return
|
|
13688
|
+
return;
|
|
13087
13689
|
}
|
|
13088
13690
|
if (visiting.has(name)) {
|
|
13089
|
-
|
|
13691
|
+
hasDependencyCycle = true;
|
|
13692
|
+
return;
|
|
13090
13693
|
}
|
|
13091
13694
|
const entry = targets.get(name);
|
|
13092
13695
|
if (!entry) {
|
|
13093
|
-
|
|
13696
|
+
if (!existsSync11(path39.resolve(path39.dirname(makefilePath), name))) {
|
|
13697
|
+
hasUndefinedPrerequisite = true;
|
|
13698
|
+
}
|
|
13699
|
+
return;
|
|
13094
13700
|
}
|
|
13095
13701
|
visiting.add(name);
|
|
13096
|
-
|
|
13702
|
+
hasDynamicPrerequisite ||= entry.opaquePrerequisites;
|
|
13097
13703
|
for (const prerequisite of entry.prerequisites) {
|
|
13098
|
-
|
|
13099
|
-
return false;
|
|
13100
|
-
}
|
|
13704
|
+
collect(prerequisite);
|
|
13101
13705
|
}
|
|
13102
13706
|
recipeLines.push(...entry.recipes);
|
|
13103
13707
|
visiting.delete(name);
|
|
13104
13708
|
visited.add(name);
|
|
13105
|
-
return true;
|
|
13106
13709
|
};
|
|
13107
|
-
|
|
13108
|
-
|
|
13109
|
-
}
|
|
13710
|
+
collect(target);
|
|
13711
|
+
const expandedRecipes = [];
|
|
13110
13712
|
for (const line of recipeLines) {
|
|
13111
|
-
|
|
13713
|
+
const normalized = normalizeMakeRecipeLine(line);
|
|
13714
|
+
const expanded = expandMakeExpression(normalized, cliVars, makefileVars);
|
|
13715
|
+
if (expanded === null) {
|
|
13112
13716
|
return { recipes: recipeLines, opaque: true, reason: "make_recipe_dynamic" };
|
|
13113
13717
|
}
|
|
13718
|
+
expandedRecipes.push(expanded);
|
|
13719
|
+
}
|
|
13720
|
+
for (const line of expandedRecipes) {
|
|
13721
|
+
if (/\$\(/.test(line) || /\$\{/.test(line)) {
|
|
13722
|
+
return { recipes: expandedRecipes, opaque: true, reason: "make_recipe_dynamic" };
|
|
13723
|
+
}
|
|
13724
|
+
}
|
|
13725
|
+
if (hasDependencyCycle) {
|
|
13726
|
+
return { recipes: expandedRecipes, opaque: true, reason: "make_dependency_cycle" };
|
|
13114
13727
|
}
|
|
13115
|
-
if (
|
|
13116
|
-
return { recipes:
|
|
13728
|
+
if (hasDynamicPrerequisite) {
|
|
13729
|
+
return { recipes: expandedRecipes, opaque: true, reason: "make_prerequisite_dynamic" };
|
|
13117
13730
|
}
|
|
13118
|
-
|
|
13731
|
+
if (hasUndefinedPrerequisite) {
|
|
13732
|
+
return { recipes: expandedRecipes, opaque: true, reason: "make_prerequisite_undefined" };
|
|
13733
|
+
}
|
|
13734
|
+
return { recipes: expandedRecipes, opaque: false, reason: "make_recipe_resolved" };
|
|
13119
13735
|
}
|
|
13120
13736
|
function resolveLauncherRecipe(params) {
|
|
13121
|
-
if (params.depth >= MAX_RESOLVE_DEPTH) {
|
|
13122
|
-
return { recipes: [], opaque: true, reason: "launcher_depth_exceeded" };
|
|
13123
|
-
}
|
|
13124
13737
|
const tokens = params.tokens;
|
|
13125
13738
|
const scriptName = npmScriptName(tokens);
|
|
13126
13739
|
if (scriptName) {
|
|
13740
|
+
if (params.depth >= MAX_RESOLVE_DEPTH) {
|
|
13741
|
+
return { recipes: [], opaque: true, reason: "launcher_depth_exceeded" };
|
|
13742
|
+
}
|
|
13127
13743
|
const resolution = resolveNpmRecipe(
|
|
13128
13744
|
params.cwd,
|
|
13129
13745
|
params.repoRoot,
|
|
@@ -13139,8 +13755,31 @@ function resolveLauncherRecipe(params) {
|
|
|
13139
13755
|
}
|
|
13140
13756
|
return resolution;
|
|
13141
13757
|
}
|
|
13142
|
-
if (tokens[0] === "make"
|
|
13143
|
-
|
|
13758
|
+
if (tokens[0] === "make") {
|
|
13759
|
+
if (params.depth >= MAX_RESOLVE_DEPTH) {
|
|
13760
|
+
return { recipes: [], opaque: true, reason: "launcher_depth_exceeded" };
|
|
13761
|
+
}
|
|
13762
|
+
if (tokens.includes("-n") || tokens.includes("--dry-run")) {
|
|
13763
|
+
return null;
|
|
13764
|
+
}
|
|
13765
|
+
let target = null;
|
|
13766
|
+
const cliVars = {};
|
|
13767
|
+
for (const token of tokens.slice(1)) {
|
|
13768
|
+
if (token.startsWith("-")) {
|
|
13769
|
+
continue;
|
|
13770
|
+
}
|
|
13771
|
+
const assignment = /^([A-Za-z_][A-Za-z0-9_]*)=(.*)$/.exec(token);
|
|
13772
|
+
if (assignment) {
|
|
13773
|
+
cliVars[assignment[1] ?? ""] = assignment[2] ?? "";
|
|
13774
|
+
continue;
|
|
13775
|
+
}
|
|
13776
|
+
if (!target) {
|
|
13777
|
+
target = token;
|
|
13778
|
+
}
|
|
13779
|
+
}
|
|
13780
|
+
if (target) {
|
|
13781
|
+
return resolveMakeRecipe(params.cwd, params.repoRoot, target, cliVars);
|
|
13782
|
+
}
|
|
13144
13783
|
}
|
|
13145
13784
|
if (tokens[0] === "pnpm" && tokens[1] === "exec" && tokens[2]) {
|
|
13146
13785
|
return {
|
|
@@ -13153,7 +13792,7 @@ function resolveLauncherRecipe(params) {
|
|
|
13153
13792
|
}
|
|
13154
13793
|
|
|
13155
13794
|
// src/core/verdict/parser.ts
|
|
13156
|
-
import
|
|
13795
|
+
import path40 from "node:path";
|
|
13157
13796
|
|
|
13158
13797
|
// src/core/shell-substitution.ts
|
|
13159
13798
|
function findStructuralCommandSubstitutions(command) {
|
|
@@ -13378,9 +14017,8 @@ function hasUnbalancedDollarParen(command) {
|
|
|
13378
14017
|
// src/core/verdict/parser.ts
|
|
13379
14018
|
var ENV_PREFIX_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*=(?:'[^']*'|"[^"]*"|\S+)$/;
|
|
13380
14019
|
var MAX_WRAPPER_PEEL_DEPTH = 32;
|
|
13381
|
-
var
|
|
14020
|
+
var SHELL_INTERPRETERS2 = /* @__PURE__ */ new Set(["bash", "sh", "zsh", "dash", "fish"]);
|
|
13382
14021
|
var CODE_INTERPRETERS = /* @__PURE__ */ new Set(["python", "python3", "node", "ruby", "perl", "osascript"]);
|
|
13383
|
-
var SCRIPT_FLAGS = /* @__PURE__ */ new Set(["-c", "-lc", "-e", "--eval"]);
|
|
13384
14022
|
var INTERPRETER_SCRIPT_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
13385
14023
|
".js",
|
|
13386
14024
|
".mjs",
|
|
@@ -13392,7 +14030,7 @@ var INTERPRETER_SCRIPT_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
|
13392
14030
|
".sh"
|
|
13393
14031
|
]);
|
|
13394
14032
|
function normalizeHead(token) {
|
|
13395
|
-
const base =
|
|
14033
|
+
const base = path40.basename(token);
|
|
13396
14034
|
if (base && base !== "." && base !== "..") {
|
|
13397
14035
|
return base;
|
|
13398
14036
|
}
|
|
@@ -13404,10 +14042,6 @@ function peelTransparentWrappers(tokens) {
|
|
|
13404
14042
|
let encounteredXargs = false;
|
|
13405
14043
|
let peelDepth = 0;
|
|
13406
14044
|
while (current.length > 0) {
|
|
13407
|
-
if (peelDepth >= MAX_WRAPPER_PEEL_DEPTH) {
|
|
13408
|
-
return { tokens: current, xargsStdinOpaque: false, encounteredXargs, opaque: true };
|
|
13409
|
-
}
|
|
13410
|
-
peelDepth += 1;
|
|
13411
14045
|
while (current.length > 0 && ENV_PREFIX_PATTERN.test(current[0] ?? "")) {
|
|
13412
14046
|
current.shift();
|
|
13413
14047
|
}
|
|
@@ -13417,6 +14051,10 @@ function peelTransparentWrappers(tokens) {
|
|
|
13417
14051
|
const head = normalizeHead(current[0] ?? "");
|
|
13418
14052
|
if (head === "xargs") {
|
|
13419
14053
|
encounteredXargs = true;
|
|
14054
|
+
if (peelDepth >= MAX_WRAPPER_PEEL_DEPTH) {
|
|
14055
|
+
return { tokens: current, xargsStdinOpaque: false, encounteredXargs, opaque: true };
|
|
14056
|
+
}
|
|
14057
|
+
peelDepth += 1;
|
|
13420
14058
|
const wrapper2 = peelXargsWrapper(current);
|
|
13421
14059
|
if (wrapper2.kind === "opaque") {
|
|
13422
14060
|
xargsStdinOpaque = current.length === 1;
|
|
@@ -13434,6 +14072,10 @@ function peelTransparentWrappers(tokens) {
|
|
|
13434
14072
|
if (!wrapper) {
|
|
13435
14073
|
break;
|
|
13436
14074
|
}
|
|
14075
|
+
if (peelDepth >= MAX_WRAPPER_PEEL_DEPTH) {
|
|
14076
|
+
return { tokens: current, xargsStdinOpaque: false, encounteredXargs, opaque: true };
|
|
14077
|
+
}
|
|
14078
|
+
peelDepth += 1;
|
|
13437
14079
|
if (wrapper.kind === "opaque") {
|
|
13438
14080
|
return { tokens: current, xargsStdinOpaque: false, encounteredXargs, opaque: true };
|
|
13439
14081
|
}
|
|
@@ -13657,34 +14299,20 @@ function extractRecursiveScript(tokens) {
|
|
|
13657
14299
|
return null;
|
|
13658
14300
|
}
|
|
13659
14301
|
const head = normalizeHead(filtered[0] ?? "");
|
|
13660
|
-
const second = filtered[1] ?? "";
|
|
13661
14302
|
if (head === "eval") {
|
|
13662
14303
|
const body = filtered.slice(1).join(" ").trim();
|
|
13663
14304
|
return body || null;
|
|
13664
14305
|
}
|
|
13665
|
-
|
|
13666
|
-
|
|
13667
|
-
|
|
13668
|
-
|
|
13669
|
-
return body || null;
|
|
13670
|
-
}
|
|
13671
|
-
}
|
|
13672
|
-
if (head === "bash" && (second === "-lc" || second === "-c")) {
|
|
13673
|
-
const body = filtered.slice(2).join(" ").replace(/^['"]|['"]$/g, "").trim();
|
|
13674
|
-
return body || null;
|
|
13675
|
-
}
|
|
13676
|
-
return null;
|
|
14306
|
+
const invocation = decodeRecursiveInvocation(
|
|
14307
|
+
shellTokensFromValues(filtered, { detectExpansion: false })
|
|
14308
|
+
);
|
|
14309
|
+
return invocation.kind === "static" ? invocation.script || null : null;
|
|
13677
14310
|
}
|
|
13678
|
-
function
|
|
13679
|
-
const
|
|
13680
|
-
|
|
13681
|
-
|
|
13682
|
-
|
|
13683
|
-
const head = normalizeHead(filtered[0] ?? "");
|
|
13684
|
-
if (head === "eval") {
|
|
13685
|
-
return true;
|
|
13686
|
-
}
|
|
13687
|
-
return (SHELL_INTERPRETERS.has(head) || CODE_INTERPRETERS.has(head)) && filtered.some((token) => SCRIPT_FLAGS.has(token));
|
|
14311
|
+
function decodeRecursiveInvocationTokens(tokens) {
|
|
14312
|
+
const values = tokens.map((token) => token.value);
|
|
14313
|
+
const { tokens: filtered, opaque } = peelTransparentWrappers(values);
|
|
14314
|
+
if (opaque) return { kind: "none" };
|
|
14315
|
+
return decodeRecursiveInvocation(tokens.slice(values.length - filtered.length));
|
|
13688
14316
|
}
|
|
13689
14317
|
function isCommandInspection(tokens) {
|
|
13690
14318
|
return normalizeHead(tokens[0] ?? "") === "command" && peelCommandWrapper(tokens).kind === "preserve";
|
|
@@ -13698,11 +14326,10 @@ function isBareInterpreter(tokens) {
|
|
|
13698
14326
|
return false;
|
|
13699
14327
|
}
|
|
13700
14328
|
const head = normalizeHead(peeled[0] ?? "");
|
|
13701
|
-
if (!
|
|
14329
|
+
if (!SHELL_INTERPRETERS2.has(head) && !CODE_INTERPRETERS.has(head)) {
|
|
13702
14330
|
return false;
|
|
13703
14331
|
}
|
|
13704
|
-
|
|
13705
|
-
if (hasScriptFlag) {
|
|
14332
|
+
if (decodeRecursiveInvocation(shellTokensFromValues(peeled)).kind !== "none") {
|
|
13706
14333
|
return false;
|
|
13707
14334
|
}
|
|
13708
14335
|
const args = peeled.slice(1);
|
|
@@ -13713,7 +14340,7 @@ function isBareInterpreter(tokens) {
|
|
|
13713
14340
|
return false;
|
|
13714
14341
|
}
|
|
13715
14342
|
const scriptArg = args.find((token) => !token.startsWith("-"));
|
|
13716
|
-
if (scriptArg && INTERPRETER_SCRIPT_EXTENSIONS.has(
|
|
14343
|
+
if (scriptArg && INTERPRETER_SCRIPT_EXTENSIONS.has(path40.extname(scriptArg))) {
|
|
13717
14344
|
return false;
|
|
13718
14345
|
}
|
|
13719
14346
|
if (scriptArg) {
|
|
@@ -14005,11 +14632,11 @@ function lowerTopLevelSegments(command, context) {
|
|
|
14005
14632
|
}
|
|
14006
14633
|
function startsLocalPostgresService(command) {
|
|
14007
14634
|
const tokens = tokenizeShell(command);
|
|
14008
|
-
return
|
|
14635
|
+
return path41.basename(tokens[0] ?? "") === "docker" && tokens[1] === "compose" && ["up", "start", "restart"].includes(tokens[2] ?? "") && tokens.includes("postgres");
|
|
14009
14636
|
}
|
|
14010
14637
|
function resolveCdTransition(command, currentCwd) {
|
|
14011
14638
|
const tokens = tokenizeShell(command);
|
|
14012
|
-
if (
|
|
14639
|
+
if (path41.basename(tokens[0] ?? "") !== "cd") {
|
|
14013
14640
|
return null;
|
|
14014
14641
|
}
|
|
14015
14642
|
const target = tokens[1] ?? "~";
|
|
@@ -14030,17 +14657,32 @@ function joinNestedOpacity(outer, nested) {
|
|
|
14030
14657
|
}
|
|
14031
14658
|
function lowerSegment(command, context) {
|
|
14032
14659
|
const commandRedacted = redactCommand(command);
|
|
14033
|
-
const
|
|
14660
|
+
const lexed = lexShell(command);
|
|
14661
|
+
const rawTokens = lexed.tokens.map((token) => token.value);
|
|
14034
14662
|
const environment = extractEnvironment(rawTokens, context.env);
|
|
14035
14663
|
const env = environment.env;
|
|
14036
14664
|
const parsed = parseSegment(command);
|
|
14037
|
-
const
|
|
14038
|
-
|
|
14665
|
+
const parsedTokens = environment.commandTokens ?? parsed.tokens;
|
|
14666
|
+
const tokens = stripRedirects(
|
|
14667
|
+
parsedTokens.length === 0 && rawTokens.length > 0 && rawTokens.every((token) => ENV_PREFIX_PATTERN2.test(token)) ? rawTokens : parsedTokens
|
|
14668
|
+
).map((token) => expandKnownVariables(token, env));
|
|
14669
|
+
const decoderTokens = alignStructuredTokens(
|
|
14670
|
+
stripStructuredRedirects(lexed.tokens),
|
|
14671
|
+
stripRedirects(parsedTokens)
|
|
14039
14672
|
);
|
|
14040
|
-
const head =
|
|
14673
|
+
const head = path41.basename(tokens[0] ?? parsed.head);
|
|
14041
14674
|
let opacity = segmentOpacity(command);
|
|
14042
14675
|
const signals = /* @__PURE__ */ new Set();
|
|
14043
14676
|
const requirements = [];
|
|
14677
|
+
if (!lexed.complete) {
|
|
14678
|
+
requirements.push(
|
|
14679
|
+
requirement2("indeterminate", "indeterminate", { kind: "unknown" }, commandRedacted, [
|
|
14680
|
+
"shell.grammar_incomplete"
|
|
14681
|
+
])
|
|
14682
|
+
);
|
|
14683
|
+
signals.add("shell.grammar_incomplete");
|
|
14684
|
+
opacity = joinEffectOpacity(opacity, "unparseable");
|
|
14685
|
+
}
|
|
14044
14686
|
addRedirectEffects(requirements, rawTokens, env, context, commandRedacted);
|
|
14045
14687
|
addSubstitutionEffects(requirements, command, context, commandRedacted, signals);
|
|
14046
14688
|
if (environment.malformed) {
|
|
@@ -14060,7 +14702,7 @@ function lowerSegment(command, context) {
|
|
|
14060
14702
|
signals.add("shell.xargs_stdin_dynamic");
|
|
14061
14703
|
opacity = joinEffectOpacity(opacity, "opaque");
|
|
14062
14704
|
}
|
|
14063
|
-
if (context.depth
|
|
14705
|
+
if (context.depth > MAX_LOWER_DEPTH) {
|
|
14064
14706
|
requirements.push(
|
|
14065
14707
|
requirement2("indeterminate", "indeterminate", { kind: "unknown" }, commandRedacted, [
|
|
14066
14708
|
"shell.lower_depth_exceeded"
|
|
@@ -14107,37 +14749,96 @@ function lowerSegment(command, context) {
|
|
|
14107
14749
|
}
|
|
14108
14750
|
return shellSegment(commandRedacted, head, requirements, opacity, signals);
|
|
14109
14751
|
}
|
|
14110
|
-
const
|
|
14111
|
-
if (
|
|
14112
|
-
const dynamicEvaluation = isDynamicRecursiveEvaluation(tokens);
|
|
14752
|
+
const recursive = decodeRecursiveInvocationTokens(decoderTokens);
|
|
14753
|
+
if (recursive.kind === "static" && opacity !== "opaque" && opacity !== "unparseable") {
|
|
14113
14754
|
requirements.push(
|
|
14114
|
-
processRequirement(
|
|
14755
|
+
processRequirement(recursive.interpreter, "spawn", commandRedacted, [
|
|
14115
14756
|
"shell.recursive_wrapper",
|
|
14116
|
-
|
|
14757
|
+
"dynamic_shell_evaluation"
|
|
14117
14758
|
])
|
|
14118
14759
|
);
|
|
14119
|
-
|
|
14120
|
-
|
|
14121
|
-
|
|
14122
|
-
|
|
14123
|
-
|
|
14124
|
-
|
|
14125
|
-
|
|
14126
|
-
|
|
14127
|
-
|
|
14128
|
-
(
|
|
14129
|
-
|
|
14130
|
-
|
|
14131
|
-
|
|
14132
|
-
signals.add(signal);
|
|
14760
|
+
if (recursive.script !== "") {
|
|
14761
|
+
const nested = lowerTopLevelSegments(recursive.script, {
|
|
14762
|
+
...context,
|
|
14763
|
+
command: recursive.script,
|
|
14764
|
+
env,
|
|
14765
|
+
depth: context.depth + 1
|
|
14766
|
+
});
|
|
14767
|
+
for (const nestedSegment of nested) {
|
|
14768
|
+
requirements.push(
|
|
14769
|
+
...nestedSegment.requirements.map(
|
|
14770
|
+
(entry) => withInnerProvenance(entry, recursive.script, head, commandRedacted)
|
|
14771
|
+
)
|
|
14772
|
+
);
|
|
14773
|
+
for (const signal of nestedSegment.signals) signals.add(signal);
|
|
14133
14774
|
}
|
|
14134
14775
|
}
|
|
14135
14776
|
signals.add("shell.recursive_wrapper");
|
|
14136
|
-
|
|
14137
|
-
|
|
14777
|
+
signals.add("dynamic_shell_evaluation");
|
|
14778
|
+
return shellSegment(commandRedacted, head, requirements, "recursive", signals);
|
|
14779
|
+
}
|
|
14780
|
+
if (recursive.kind === "dynamic" || recursive.kind === "indeterminate") {
|
|
14781
|
+
const recursiveSignals = [
|
|
14782
|
+
recursive.signal,
|
|
14783
|
+
...recursive.kind === "dynamic" ? ["dynamic_shell_evaluation"] : []
|
|
14784
|
+
];
|
|
14785
|
+
requirements.push(
|
|
14786
|
+
processRequirement(recursive.interpreter, "spawn", commandRedacted, recursiveSignals),
|
|
14787
|
+
requirement2("indeterminate", "indeterminate", { kind: "unknown" }, commandRedacted, [
|
|
14788
|
+
...recursiveSignals
|
|
14789
|
+
])
|
|
14790
|
+
);
|
|
14791
|
+
for (const signal of recursiveSignals) signals.add(signal);
|
|
14792
|
+
return shellSegment(
|
|
14793
|
+
commandRedacted,
|
|
14794
|
+
head,
|
|
14795
|
+
requirements,
|
|
14796
|
+
joinEffectOpacity(opacity, "opaque"),
|
|
14797
|
+
signals
|
|
14798
|
+
);
|
|
14799
|
+
}
|
|
14800
|
+
const compose = decodeDockerComposeRun(decoderTokens);
|
|
14801
|
+
if (compose.kind === "recursive" && opacity !== "opaque" && opacity !== "unparseable") {
|
|
14802
|
+
requirements.push(
|
|
14803
|
+
processRequirement(head, "spawn", commandRedacted, ["process.docker_compose_run"])
|
|
14804
|
+
);
|
|
14805
|
+
if (compose.script !== "") {
|
|
14806
|
+
const nested = lowerTopLevelSegments(compose.script, {
|
|
14807
|
+
...context,
|
|
14808
|
+
command: compose.script,
|
|
14809
|
+
env,
|
|
14810
|
+
depth: context.depth + 1
|
|
14811
|
+
});
|
|
14812
|
+
for (const nestedSegment of nested) {
|
|
14813
|
+
requirements.push(
|
|
14814
|
+
...nestedSegment.requirements.map(
|
|
14815
|
+
(entry) => withInnerProvenance(entry, compose.script, head, commandRedacted)
|
|
14816
|
+
)
|
|
14817
|
+
);
|
|
14818
|
+
for (const signal of nestedSegment.signals) signals.add(signal);
|
|
14819
|
+
opacity = joinNestedOpacity(opacity, nestedSegment);
|
|
14820
|
+
}
|
|
14138
14821
|
}
|
|
14822
|
+
signals.add("process.docker_compose_run");
|
|
14139
14823
|
return shellSegment(commandRedacted, head, requirements, "recursive", signals);
|
|
14140
14824
|
}
|
|
14825
|
+
if (compose.kind === "dynamic" || compose.kind === "indeterminate") {
|
|
14826
|
+
requirements.push(
|
|
14827
|
+
processRequirement(head, "spawn", commandRedacted, ["process.docker_compose_run"]),
|
|
14828
|
+
requirement2("indeterminate", "indeterminate", { kind: "unknown" }, commandRedacted, [
|
|
14829
|
+
compose.signal
|
|
14830
|
+
])
|
|
14831
|
+
);
|
|
14832
|
+
signals.add("process.docker_compose_run");
|
|
14833
|
+
signals.add(compose.signal);
|
|
14834
|
+
return shellSegment(
|
|
14835
|
+
commandRedacted,
|
|
14836
|
+
head,
|
|
14837
|
+
requirements,
|
|
14838
|
+
joinEffectOpacity(opacity, "opaque"),
|
|
14839
|
+
signals
|
|
14840
|
+
);
|
|
14841
|
+
}
|
|
14141
14842
|
const launcher = resolveLauncherRecipe({
|
|
14142
14843
|
tokens,
|
|
14143
14844
|
cwd: context.cwd,
|
|
@@ -14349,7 +15050,7 @@ function isMetadataOnlyArgv(argv) {
|
|
|
14349
15050
|
return argv.length > 0 && argv.every((token) => METADATA_ONLY_FLAGS.has(token));
|
|
14350
15051
|
}
|
|
14351
15052
|
function executableBaseName(head) {
|
|
14352
|
-
return
|
|
15053
|
+
return path41.basename(head);
|
|
14353
15054
|
}
|
|
14354
15055
|
var RAILS_READ_ONLY_SUBCOMMANDS = /* @__PURE__ */ new Set(["routes", "middleware", "stats", "about", "version"]);
|
|
14355
15056
|
function railsReadOnlySubcommand(args) {
|
|
@@ -14359,6 +15060,111 @@ function railsReadOnlySubcommand(args) {
|
|
|
14359
15060
|
}
|
|
14360
15061
|
return RAILS_READ_ONLY_SUBCOMMANDS.has(subcommand);
|
|
14361
15062
|
}
|
|
15063
|
+
function isRubyTestScript(scriptPath) {
|
|
15064
|
+
const base = path41.basename(scriptPath);
|
|
15065
|
+
return base.endsWith("_test.rb") || base.endsWith("_spec.rb");
|
|
15066
|
+
}
|
|
15067
|
+
function parseRubyTestInvocation(args) {
|
|
15068
|
+
const includePaths = [];
|
|
15069
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
15070
|
+
const arg = args[index] ?? "";
|
|
15071
|
+
if (arg === "-e" || arg === "-r") {
|
|
15072
|
+
return null;
|
|
15073
|
+
}
|
|
15074
|
+
if (arg === "-I") {
|
|
15075
|
+
const includePath = args[index + 1];
|
|
15076
|
+
if (!includePath) {
|
|
15077
|
+
return null;
|
|
15078
|
+
}
|
|
15079
|
+
includePaths.push(includePath);
|
|
15080
|
+
index += 1;
|
|
15081
|
+
continue;
|
|
15082
|
+
}
|
|
15083
|
+
if (arg.startsWith("-I") && arg.length > 2) {
|
|
15084
|
+
includePaths.push(arg.slice(2));
|
|
15085
|
+
continue;
|
|
15086
|
+
}
|
|
15087
|
+
if (arg.startsWith("-")) {
|
|
15088
|
+
if (arg === "-n") {
|
|
15089
|
+
if (!args[index + 1]) {
|
|
15090
|
+
return null;
|
|
15091
|
+
}
|
|
15092
|
+
index += 1;
|
|
15093
|
+
continue;
|
|
15094
|
+
}
|
|
15095
|
+
if (arg.startsWith("-n")) {
|
|
15096
|
+
continue;
|
|
15097
|
+
}
|
|
15098
|
+
return null;
|
|
15099
|
+
}
|
|
15100
|
+
if (isRubyTestScript(arg)) {
|
|
15101
|
+
return { includePaths, scriptPath: arg };
|
|
15102
|
+
}
|
|
15103
|
+
return null;
|
|
15104
|
+
}
|
|
15105
|
+
return null;
|
|
15106
|
+
}
|
|
15107
|
+
function isRubocopMutating(args) {
|
|
15108
|
+
return args.some(
|
|
15109
|
+
(arg) => arg === "-A" || arg === "-a" || arg === "--auto-correct" || arg === "--autocorrect" || arg.startsWith("--auto-correct-all") || arg.startsWith("--autocorrect-all")
|
|
15110
|
+
);
|
|
15111
|
+
}
|
|
15112
|
+
function decodeBundleExecInner(innerHead, innerArgs, segment) {
|
|
15113
|
+
const innerBase = executableBaseName(innerHead);
|
|
15114
|
+
if (innerBase === "rubocop") {
|
|
15115
|
+
const mutating = isRubocopMutating(innerArgs);
|
|
15116
|
+
return [
|
|
15117
|
+
processRequirement(
|
|
15118
|
+
innerHead,
|
|
15119
|
+
mutating ? "spawn" : "inspect",
|
|
15120
|
+
segment,
|
|
15121
|
+
mutating ? ["process.linter.mutating"] : ["process.inspect.linter"]
|
|
15122
|
+
)
|
|
15123
|
+
];
|
|
15124
|
+
}
|
|
15125
|
+
if (innerBase === "rspec") {
|
|
15126
|
+
const targetArgs = innerArgs.filter((arg) => !arg.startsWith("-"));
|
|
15127
|
+
if (targetArgs.length === 0) {
|
|
15128
|
+
return null;
|
|
15129
|
+
}
|
|
15130
|
+
return [processRequirement(innerHead, "spawn", segment, ["process.test_runner.rspec"])];
|
|
15131
|
+
}
|
|
15132
|
+
return null;
|
|
15133
|
+
}
|
|
15134
|
+
function decodeRuby(args, cwd, repoRoot, segment) {
|
|
15135
|
+
const parsed = parseRubyTestInvocation(args);
|
|
15136
|
+
if (!parsed) {
|
|
15137
|
+
return unsupportedProcess("ruby", segment, "process.ruby_grammar_incomplete");
|
|
15138
|
+
}
|
|
15139
|
+
const scriptPath = resolvePathOperand(parsed.scriptPath, cwd);
|
|
15140
|
+
if (!pathWithinRoot(canonicalPath(repoRoot), canonicalPath(scriptPath))) {
|
|
15141
|
+
return unsupportedProcess("ruby", segment, "process.ruby_outside_repo");
|
|
15142
|
+
}
|
|
15143
|
+
for (const includePath of parsed.includePaths) {
|
|
15144
|
+
const resolvedInclude = resolvePathOperand(includePath, cwd);
|
|
15145
|
+
if (!pathWithinRoot(canonicalPath(repoRoot), canonicalPath(resolvedInclude))) {
|
|
15146
|
+
return unsupportedProcess("ruby", segment, "process.ruby_outside_repo");
|
|
15147
|
+
}
|
|
15148
|
+
}
|
|
15149
|
+
const lowered = [
|
|
15150
|
+
processRequirement("ruby", "spawn", segment, ["process.test_runner.minitest"]),
|
|
15151
|
+
requirement2("fs.read", "fs.read", { kind: "path", path: scriptPath }, segment, [
|
|
15152
|
+
"ruby.minitest_script_read"
|
|
15153
|
+
])
|
|
15154
|
+
];
|
|
15155
|
+
for (const includePath of parsed.includePaths) {
|
|
15156
|
+
lowered.push(
|
|
15157
|
+
requirement2(
|
|
15158
|
+
"fs.read",
|
|
15159
|
+
"fs.read",
|
|
15160
|
+
{ kind: "path", path: resolvePathOperand(includePath, cwd) },
|
|
15161
|
+
segment,
|
|
15162
|
+
["ruby.minitest_load_path_read"]
|
|
15163
|
+
)
|
|
15164
|
+
);
|
|
15165
|
+
}
|
|
15166
|
+
return lowered;
|
|
15167
|
+
}
|
|
14362
15168
|
function decodeRuntimeMetadataProcess(head, args, segment) {
|
|
14363
15169
|
if (head === "bundle") {
|
|
14364
15170
|
if (args.length === 1 && isMetadataOnlyArgv(args)) {
|
|
@@ -14380,6 +15186,10 @@ function decodeRuntimeMetadataProcess(head, args, segment) {
|
|
|
14380
15186
|
])
|
|
14381
15187
|
];
|
|
14382
15188
|
}
|
|
15189
|
+
const bundleExecInner = decodeBundleExecInner(innerHead, innerArgs, segment);
|
|
15190
|
+
if (bundleExecInner) {
|
|
15191
|
+
return bundleExecInner;
|
|
15192
|
+
}
|
|
14383
15193
|
}
|
|
14384
15194
|
return null;
|
|
14385
15195
|
}
|
|
@@ -14395,9 +15205,74 @@ function decodeRuntimeMetadataProcess(head, args, segment) {
|
|
|
14395
15205
|
}
|
|
14396
15206
|
return null;
|
|
14397
15207
|
}
|
|
15208
|
+
function decodeSetBuiltin(args) {
|
|
15209
|
+
let index = 0;
|
|
15210
|
+
while (index < args.length) {
|
|
15211
|
+
const arg = args[index] ?? "";
|
|
15212
|
+
if (arg === "--") {
|
|
15213
|
+
index += 1;
|
|
15214
|
+
continue;
|
|
15215
|
+
}
|
|
15216
|
+
if (arg === "-o" || arg === "+o") {
|
|
15217
|
+
if (!args[index + 1]) {
|
|
15218
|
+
return false;
|
|
15219
|
+
}
|
|
15220
|
+
index += 2;
|
|
15221
|
+
continue;
|
|
15222
|
+
}
|
|
15223
|
+
if (/^[-+][A-Za-z0-9]+$/.test(arg)) {
|
|
15224
|
+
index += 1;
|
|
15225
|
+
continue;
|
|
15226
|
+
}
|
|
15227
|
+
return false;
|
|
15228
|
+
}
|
|
15229
|
+
return true;
|
|
15230
|
+
}
|
|
15231
|
+
function decodeShellControlBuiltin(head, args) {
|
|
15232
|
+
if (head === "set") {
|
|
15233
|
+
return decodeSetBuiltin(args) ? [] : null;
|
|
15234
|
+
}
|
|
15235
|
+
if (head === "wait") {
|
|
15236
|
+
if (args.length === 0 || args.every((arg) => /^\d+$/.test(arg))) {
|
|
15237
|
+
return [];
|
|
15238
|
+
}
|
|
15239
|
+
return null;
|
|
15240
|
+
}
|
|
15241
|
+
if (head === "exit") {
|
|
15242
|
+
if (args.length === 0 || args.length === 1 && /^-?\d+$/.test(args[0] ?? "")) {
|
|
15243
|
+
return [];
|
|
15244
|
+
}
|
|
15245
|
+
return null;
|
|
15246
|
+
}
|
|
15247
|
+
return null;
|
|
15248
|
+
}
|
|
15249
|
+
function decodeDockerComposeRun2(head, args, segment) {
|
|
15250
|
+
let composeArgs = null;
|
|
15251
|
+
let command = head;
|
|
15252
|
+
if (head === "docker-compose") {
|
|
15253
|
+
composeArgs = args;
|
|
15254
|
+
} else if (head === "docker" && args[0] === "compose") {
|
|
15255
|
+
composeArgs = args.slice(1);
|
|
15256
|
+
command = "docker";
|
|
15257
|
+
}
|
|
15258
|
+
if (!composeArgs) {
|
|
15259
|
+
return null;
|
|
15260
|
+
}
|
|
15261
|
+
if (composeArgs.includes("run")) {
|
|
15262
|
+
return [processRequirement(command, "spawn", segment, ["process.docker_compose_run"])];
|
|
15263
|
+
}
|
|
15264
|
+
return unsupportedProcess(command, segment, "process.docker_compose_grammar_incomplete");
|
|
15265
|
+
}
|
|
14398
15266
|
function decodeProcessOrFilesystem(params) {
|
|
14399
15267
|
const { tokens, head, env, cwd, repoRoot, segment } = params;
|
|
14400
15268
|
const args = tokens.slice(1);
|
|
15269
|
+
if (tokens.length > 0 && tokens.every((token) => ENV_PREFIX_PATTERN2.test(token))) {
|
|
15270
|
+
return [];
|
|
15271
|
+
}
|
|
15272
|
+
const shellControl = decodeShellControlBuiltin(head, args);
|
|
15273
|
+
if (shellControl) {
|
|
15274
|
+
return shellControl;
|
|
15275
|
+
}
|
|
14401
15276
|
if (isCommandInspection(tokens)) {
|
|
14402
15277
|
return [processRequirement(head, "inspect", segment, ["process.inspect.command_lookup"])];
|
|
14403
15278
|
}
|
|
@@ -14465,7 +15340,7 @@ function decodeProcessOrFilesystem(params) {
|
|
|
14465
15340
|
requirement2(
|
|
14466
15341
|
"fs.read",
|
|
14467
15342
|
"fs.read",
|
|
14468
|
-
{ kind: "path", path:
|
|
15343
|
+
{ kind: "path", path: path41.resolve(cwd, syntax) },
|
|
14469
15344
|
segment,
|
|
14470
15345
|
["shell.syntax_source_read"]
|
|
14471
15346
|
)
|
|
@@ -14480,6 +15355,19 @@ function decodeProcessOrFilesystem(params) {
|
|
|
14480
15355
|
if (runtimeMetadata) {
|
|
14481
15356
|
return runtimeMetadata;
|
|
14482
15357
|
}
|
|
15358
|
+
if (head === "ruby") {
|
|
15359
|
+
return decodeRuby(args, cwd, repoRoot, segment);
|
|
15360
|
+
}
|
|
15361
|
+
if (head === "rubocop" || head === "rspec") {
|
|
15362
|
+
const decoded = decodeBundleExecInner(head, args, segment);
|
|
15363
|
+
if (decoded) {
|
|
15364
|
+
return decoded;
|
|
15365
|
+
}
|
|
15366
|
+
}
|
|
15367
|
+
const dockerCompose = decodeDockerComposeRun2(head, args, segment);
|
|
15368
|
+
if (dockerCompose) {
|
|
15369
|
+
return dockerCompose;
|
|
15370
|
+
}
|
|
14483
15371
|
if ((head === "npm" || head === "pnpm") && args.length === 1 && isMetadataOnlyArgv(args)) {
|
|
14484
15372
|
return [processRequirement(head, "inspect", segment, ["process.inspect.package_manager"])];
|
|
14485
15373
|
}
|
|
@@ -14502,7 +15390,7 @@ function decodeProcessOrFilesystem(params) {
|
|
|
14502
15390
|
return [processRequirement(head, "inspect", segment, ["process.inspect.base64_stdin"])];
|
|
14503
15391
|
}
|
|
14504
15392
|
if (head === "node") {
|
|
14505
|
-
return
|
|
15393
|
+
return decodeNode2(args, cwd, segment);
|
|
14506
15394
|
}
|
|
14507
15395
|
if (head === "vite" || head === "vite-node") {
|
|
14508
15396
|
return [processRequirement(head, "spawn", segment, ["process.local_dev_spawn"])];
|
|
@@ -14592,7 +15480,7 @@ function decodeBelay(args, repoRoot, segment) {
|
|
|
14592
15480
|
requirement2(
|
|
14593
15481
|
"control_plane.write",
|
|
14594
15482
|
"control_plane.write",
|
|
14595
|
-
{ kind: "path", path:
|
|
15483
|
+
{ kind: "path", path: path41.join(repoRoot, ".belay-control-plane") },
|
|
14596
15484
|
segment,
|
|
14597
15485
|
["belay.config_non_judge_mutation"]
|
|
14598
15486
|
)
|
|
@@ -14754,11 +15642,11 @@ function decodeRm(args, cwd, repoRoot, segment) {
|
|
|
14754
15642
|
function canonicalRmOperand(targetPath, finalOperandIsSymlink) {
|
|
14755
15643
|
try {
|
|
14756
15644
|
if (finalOperandIsSymlink) {
|
|
14757
|
-
return
|
|
15645
|
+
return path41.join(realpathSync4.native(path41.dirname(targetPath)), path41.basename(targetPath));
|
|
14758
15646
|
}
|
|
14759
15647
|
return realpathSync4.native(targetPath);
|
|
14760
15648
|
} catch {
|
|
14761
|
-
return
|
|
15649
|
+
return path41.resolve(targetPath);
|
|
14762
15650
|
}
|
|
14763
15651
|
}
|
|
14764
15652
|
function isSymbolicLink(targetPath) {
|
|
@@ -14769,8 +15657,8 @@ function isSymbolicLink(targetPath) {
|
|
|
14769
15657
|
}
|
|
14770
15658
|
}
|
|
14771
15659
|
function pathContains(ancestor, candidate) {
|
|
14772
|
-
const relative =
|
|
14773
|
-
return relative === "" || !relative.startsWith("..") && !
|
|
15660
|
+
const relative = path41.relative(path41.resolve(ancestor), path41.resolve(candidate));
|
|
15661
|
+
return relative === "" || !relative.startsWith("..") && !path41.isAbsolute(relative);
|
|
14774
15662
|
}
|
|
14775
15663
|
function decodeGo(args, segment) {
|
|
14776
15664
|
if (["test", "list", "vet"].includes(args[0] ?? "")) {
|
|
@@ -14916,7 +15804,7 @@ function decodeSed(args, cwd, segment) {
|
|
|
14916
15804
|
}
|
|
14917
15805
|
return lowered;
|
|
14918
15806
|
}
|
|
14919
|
-
function
|
|
15807
|
+
function decodeNode2(args, cwd, segment) {
|
|
14920
15808
|
if (args.length > 0 && args.every((arg) => ["--help", "--version", "-h", "-v"].includes(arg))) {
|
|
14921
15809
|
return [processRequirement("node", "inspect", segment, ["process.inspect.node_metadata"])];
|
|
14922
15810
|
}
|
|
@@ -15182,15 +16070,36 @@ function stripRedirects(tokens) {
|
|
|
15182
16070
|
stripped.push(token);
|
|
15183
16071
|
continue;
|
|
15184
16072
|
}
|
|
15185
|
-
|
|
15186
|
-
|
|
15187
|
-
|
|
15188
|
-
|
|
15189
|
-
|
|
16073
|
+
index += 1;
|
|
16074
|
+
}
|
|
16075
|
+
return stripped;
|
|
16076
|
+
}
|
|
16077
|
+
function stripStructuredRedirects(tokens) {
|
|
16078
|
+
const stripped = [];
|
|
16079
|
+
for (let index = 0; index < tokens.length; index += 1) {
|
|
16080
|
+
const token = tokens[index];
|
|
16081
|
+
if (!token) continue;
|
|
16082
|
+
if (isFdDuplication(token.value)) {
|
|
16083
|
+
continue;
|
|
16084
|
+
}
|
|
16085
|
+
if (!isRedirectOperator(token.value)) {
|
|
16086
|
+
stripped.push(token);
|
|
16087
|
+
continue;
|
|
15190
16088
|
}
|
|
16089
|
+
index += 1;
|
|
15191
16090
|
}
|
|
15192
16091
|
return stripped;
|
|
15193
16092
|
}
|
|
16093
|
+
function alignStructuredTokens(tokens, values) {
|
|
16094
|
+
if (values.length === 0) return [];
|
|
16095
|
+
for (let start = tokens.length - values.length; start >= 0; start -= 1) {
|
|
16096
|
+
const candidate = tokens.slice(start);
|
|
16097
|
+
if (candidate.length === values.length && candidate.every((token, index) => token.value === values[index])) {
|
|
16098
|
+
return candidate;
|
|
16099
|
+
}
|
|
16100
|
+
}
|
|
16101
|
+
return [];
|
|
16102
|
+
}
|
|
15194
16103
|
function shellSegment(commandRedacted, segmentHead, requirements, opacity, signals) {
|
|
15195
16104
|
const normalizedRequirements = requirements.flatMap((entry) => {
|
|
15196
16105
|
const dynamicSignal = dynamicResourceSignal(entry.resource);
|
|
@@ -15590,9 +16499,9 @@ function resolvePathOperand(operand, cwd) {
|
|
|
15590
16499
|
return process.env.HOME ?? operand;
|
|
15591
16500
|
}
|
|
15592
16501
|
if (operand.startsWith("~/")) {
|
|
15593
|
-
return
|
|
16502
|
+
return path41.join(process.env.HOME ?? "~", operand.slice(2));
|
|
15594
16503
|
}
|
|
15595
|
-
return
|
|
16504
|
+
return path41.resolve(cwd, operand);
|
|
15596
16505
|
}
|
|
15597
16506
|
function isShellHead(head) {
|
|
15598
16507
|
return head === "bash" || head === "sh" || head === "zsh" || head === "dash" || head === "fish";
|
|
@@ -16116,7 +17025,7 @@ async function classifyToolUse(payload, repoRoot, cwd, config, options = {}) {
|
|
|
16116
17025
|
};
|
|
16117
17026
|
}
|
|
16118
17027
|
const signals = [];
|
|
16119
|
-
const resolvedPath =
|
|
17028
|
+
const resolvedPath = path42.isAbsolute(filePath) ? filePath : path42.resolve(cwd, filePath);
|
|
16120
17029
|
const hitsProtectedRoot = protectedRoots.some((root) => pathWithinRoot(root, resolvedPath));
|
|
16121
17030
|
if (hitsProtectedRoot) {
|
|
16122
17031
|
signals.push("control_plane_path");
|
|
@@ -16718,7 +17627,7 @@ function hashDecisionConfig(config) {
|
|
|
16718
17627
|
init_fingerprint2();
|
|
16719
17628
|
|
|
16720
17629
|
// src/version.ts
|
|
16721
|
-
var PACKAGE_VERSION = "0.9.
|
|
17630
|
+
var PACKAGE_VERSION = "0.9.3";
|
|
16722
17631
|
|
|
16723
17632
|
// src/runtime-provenance.ts
|
|
16724
17633
|
function resolveRuntimeArtifactHash(artifactHash) {
|
|
@@ -16793,7 +17702,7 @@ init_path_utils();
|
|
|
16793
17702
|
import { randomUUID as randomUUID5 } from "node:crypto";
|
|
16794
17703
|
import { existsSync as existsSync15 } from "node:fs";
|
|
16795
17704
|
import { mkdir as mkdir11, readdir as readdir3, readFile as readFile12, rename as rename3, rm as rm6 } from "node:fs/promises";
|
|
16796
|
-
import
|
|
17705
|
+
import path47 from "node:path";
|
|
16797
17706
|
|
|
16798
17707
|
// src/core/recovery/artifact-store.ts
|
|
16799
17708
|
init_fingerprint2();
|
|
@@ -16801,7 +17710,7 @@ init_path_utils();
|
|
|
16801
17710
|
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
16802
17711
|
import { existsSync as existsSync13 } from "node:fs";
|
|
16803
17712
|
import { lstat as lstat7, mkdir as mkdir10, open as open5, readdir as readdir2, readFile as readFile9, rename as rename2, rm as rm5, writeFile as writeFile7 } from "node:fs/promises";
|
|
16804
|
-
import
|
|
17713
|
+
import path44 from "node:path";
|
|
16805
17714
|
|
|
16806
17715
|
// src/core/recovery/snapshot-node.ts
|
|
16807
17716
|
init_fingerprint2();
|
|
@@ -16821,25 +17730,25 @@ import {
|
|
|
16821
17730
|
symlink as symlink3,
|
|
16822
17731
|
writeFile as writeFile6
|
|
16823
17732
|
} from "node:fs/promises";
|
|
16824
|
-
import
|
|
17733
|
+
import path43 from "node:path";
|
|
16825
17734
|
var RECOVERY_UNSUPPORTED_FILE_KIND = "recovery_unsupported_file_kind";
|
|
16826
17735
|
function validRecoveryRelativePath(relativePath) {
|
|
16827
|
-
if (!relativePath || relativePath.includes("\0") ||
|
|
16828
|
-
const normalized =
|
|
16829
|
-
return normalized !== "." && normalized !== ".." && !normalized.startsWith(`..${
|
|
17736
|
+
if (!relativePath || relativePath.includes("\0") || path43.isAbsolute(relativePath)) return false;
|
|
17737
|
+
const normalized = path43.normalize(relativePath);
|
|
17738
|
+
return normalized !== "." && normalized !== ".." && !normalized.startsWith(`..${path43.sep}`);
|
|
16830
17739
|
}
|
|
16831
17740
|
async function assertRecoverySafeTarget(resourceRoot, relativePath) {
|
|
16832
17741
|
if (!validRecoveryRelativePath(relativePath)) throw new Error("recovery_path_escape");
|
|
16833
17742
|
const root = canonicalPath(resourceRoot);
|
|
16834
|
-
const target =
|
|
16835
|
-
const relative =
|
|
16836
|
-
if (relative === ".." || relative.startsWith(`..${
|
|
17743
|
+
const target = path43.resolve(root, relativePath);
|
|
17744
|
+
const relative = path43.relative(root, target);
|
|
17745
|
+
if (relative === ".." || relative.startsWith(`..${path43.sep}`) || path43.isAbsolute(relative)) {
|
|
16837
17746
|
throw new Error("recovery_path_escape");
|
|
16838
17747
|
}
|
|
16839
17748
|
let current = root;
|
|
16840
|
-
const parentParts =
|
|
17749
|
+
const parentParts = path43.relative(root, path43.dirname(target)).split(path43.sep).filter(Boolean);
|
|
16841
17750
|
for (const part of parentParts) {
|
|
16842
|
-
current =
|
|
17751
|
+
current = path43.join(current, part);
|
|
16843
17752
|
if (!existsSync12(current)) break;
|
|
16844
17753
|
const info = await lstat6(current);
|
|
16845
17754
|
if (info.isSymbolicLink()) throw new Error("recovery_symlink_escape");
|
|
@@ -16895,7 +17804,7 @@ async function captureRecoverySnapshot(filePath, options) {
|
|
|
16895
17804
|
let blob;
|
|
16896
17805
|
if (options?.blobDir) {
|
|
16897
17806
|
await mkdir9(options.blobDir, { recursive: true, mode: 448 });
|
|
16898
|
-
const blobPath =
|
|
17807
|
+
const blobPath = path43.join(options.blobDir, hash);
|
|
16899
17808
|
if (!existsSync12(blobPath)) {
|
|
16900
17809
|
await writeFile6(blobPath, content, { mode: 384 });
|
|
16901
17810
|
await fsyncPath(blobPath);
|
|
@@ -16950,7 +17859,7 @@ async function validateRecoverySnapshot(params) {
|
|
|
16950
17859
|
if (record.blob !== `blobs/${record.hash}`) throw new Error(params.corruptReason);
|
|
16951
17860
|
let content;
|
|
16952
17861
|
try {
|
|
16953
|
-
content = await readFile8(
|
|
17862
|
+
content = await readFile8(path43.join(params.artifactDir, record.blob));
|
|
16954
17863
|
} catch {
|
|
16955
17864
|
throw new Error(params.corruptReason);
|
|
16956
17865
|
}
|
|
@@ -16978,13 +17887,13 @@ var RECOVERY_STATES = /* @__PURE__ */ new Set([
|
|
|
16978
17887
|
]);
|
|
16979
17888
|
var STAGING_STALE_MS = 5 * 6e4;
|
|
16980
17889
|
function checkpointsRoot(stateDir) {
|
|
16981
|
-
return
|
|
17890
|
+
return path44.join(stateDir, "recovery", "checkpoints");
|
|
16982
17891
|
}
|
|
16983
17892
|
function checkpointDir(stateDir, checkpointId) {
|
|
16984
17893
|
if (!/^cp_[a-f0-9]{24}$/.test(checkpointId)) {
|
|
16985
17894
|
throw new Error("invalid_recovery_checkpoint_id");
|
|
16986
17895
|
}
|
|
16987
|
-
return
|
|
17896
|
+
return path44.join(checkpointsRoot(stateDir), checkpointId);
|
|
16988
17897
|
}
|
|
16989
17898
|
async function fsyncPath2(filePath) {
|
|
16990
17899
|
const handle = await open5(filePath, "r");
|
|
@@ -16995,13 +17904,13 @@ async function fsyncPath2(filePath) {
|
|
|
16995
17904
|
}
|
|
16996
17905
|
}
|
|
16997
17906
|
async function atomicWriteJson(filePath, value) {
|
|
16998
|
-
await mkdir10(
|
|
17907
|
+
await mkdir10(path44.dirname(filePath), { recursive: true, mode: 448 });
|
|
16999
17908
|
const temporary = `${filePath}.tmp-${randomUUID4()}`;
|
|
17000
17909
|
await writeFile7(temporary, `${JSON.stringify(value, null, 2)}
|
|
17001
17910
|
`, { mode: 384 });
|
|
17002
17911
|
await fsyncPath2(temporary);
|
|
17003
17912
|
await rename2(temporary, filePath);
|
|
17004
|
-
await fsyncPath2(
|
|
17913
|
+
await fsyncPath2(path44.dirname(filePath));
|
|
17005
17914
|
}
|
|
17006
17915
|
async function writeRecoveryState(artifactDir, state, manifestHash, detail) {
|
|
17007
17916
|
const value = {
|
|
@@ -17011,13 +17920,13 @@ async function writeRecoveryState(artifactDir, state, manifestHash, detail) {
|
|
|
17011
17920
|
manifestHash,
|
|
17012
17921
|
...detail ? { detail } : {}
|
|
17013
17922
|
};
|
|
17014
|
-
await atomicWriteJson(
|
|
17923
|
+
await atomicWriteJson(path44.join(artifactDir, "state.json"), value);
|
|
17015
17924
|
}
|
|
17016
17925
|
async function directorySize(root) {
|
|
17017
17926
|
if (!existsSync13(root)) return 0;
|
|
17018
17927
|
let total = 0;
|
|
17019
17928
|
for (const entry of await readdir2(root, { withFileTypes: true })) {
|
|
17020
|
-
const entryPath =
|
|
17929
|
+
const entryPath = path44.join(root, entry.name);
|
|
17021
17930
|
if (entry.isDirectory()) total += await directorySize(entryPath);
|
|
17022
17931
|
else total += (await lstat7(entryPath)).size;
|
|
17023
17932
|
}
|
|
@@ -17062,9 +17971,9 @@ async function readRecoveryArtifact(stateDir, checkpointId) {
|
|
|
17062
17971
|
let rawManifest;
|
|
17063
17972
|
let state;
|
|
17064
17973
|
try {
|
|
17065
|
-
rawManifest = JSON.parse(await readFile9(
|
|
17974
|
+
rawManifest = JSON.parse(await readFile9(path44.join(artifactDir, "manifest.json"), "utf8"));
|
|
17066
17975
|
state = JSON.parse(
|
|
17067
|
-
await readFile9(
|
|
17976
|
+
await readFile9(path44.join(artifactDir, "state.json"), "utf8")
|
|
17068
17977
|
);
|
|
17069
17978
|
} catch {
|
|
17070
17979
|
throw new Error(RECOVERY_CHECKPOINT_CORRUPT);
|
|
@@ -17080,10 +17989,10 @@ async function readRecoveryArtifact(stateDir, checkpointId) {
|
|
|
17080
17989
|
}
|
|
17081
17990
|
const entryPaths = /* @__PURE__ */ new Set();
|
|
17082
17991
|
for (const entry of manifest.entries) {
|
|
17083
|
-
if (!entry || typeof entry !== "object" || Array.isArray(entry) || Object.keys(entry).length !== 3 || !Object.keys(entry).every((key) => ["path", "before", "after"].includes(key)) || typeof entry.path !== "string" || !("before" in entry) || !("after" in entry) || !validRecoveryRelativePath(entry.path) || entryPaths.has(
|
|
17992
|
+
if (!entry || typeof entry !== "object" || Array.isArray(entry) || Object.keys(entry).length !== 3 || !Object.keys(entry).every((key) => ["path", "before", "after"].includes(key)) || typeof entry.path !== "string" || !("before" in entry) || !("after" in entry) || !validRecoveryRelativePath(entry.path) || entryPaths.has(path44.normalize(entry.path))) {
|
|
17084
17993
|
throw new Error(RECOVERY_CHECKPOINT_CORRUPT);
|
|
17085
17994
|
}
|
|
17086
|
-
entryPaths.add(
|
|
17995
|
+
entryPaths.add(path44.normalize(entry.path));
|
|
17087
17996
|
for (const [side, snapshot] of [
|
|
17088
17997
|
["before", entry.before],
|
|
17089
17998
|
["after", entry.after]
|
|
@@ -17097,7 +18006,7 @@ async function readRecoveryArtifact(stateDir, checkpointId) {
|
|
|
17097
18006
|
});
|
|
17098
18007
|
}
|
|
17099
18008
|
}
|
|
17100
|
-
const receiptPath =
|
|
18009
|
+
const receiptPath = path44.join(artifactDir, "receipt.json");
|
|
17101
18010
|
let receipt;
|
|
17102
18011
|
if (["applied", "restoring", "restored", "conflict"].includes(state.state) || existsSync13(receiptPath)) {
|
|
17103
18012
|
receipt = await readAndValidateRecoveryReceipt(artifactDir, manifest, manifestHash);
|
|
@@ -17107,7 +18016,7 @@ async function readRecoveryArtifact(stateDir, checkpointId) {
|
|
|
17107
18016
|
async function readAndValidateRecoveryReceipt(artifactDir, manifest, manifestHash) {
|
|
17108
18017
|
let rawReceipt;
|
|
17109
18018
|
try {
|
|
17110
|
-
rawReceipt = JSON.parse(await readFile9(
|
|
18019
|
+
rawReceipt = JSON.parse(await readFile9(path44.join(artifactDir, "receipt.json"), "utf8"));
|
|
17111
18020
|
} catch {
|
|
17112
18021
|
throw new Error(RECOVERY_CHECKPOINT_CORRUPT);
|
|
17113
18022
|
}
|
|
@@ -17130,7 +18039,7 @@ async function readAndValidateRecoveryReceipt(artifactDir, manifest, manifestHas
|
|
|
17130
18039
|
return receipt;
|
|
17131
18040
|
}
|
|
17132
18041
|
async function ensureRecoveryReceipt(artifactDir, manifest, manifestHash) {
|
|
17133
|
-
const receiptPath =
|
|
18042
|
+
const receiptPath = path44.join(artifactDir, "receipt.json");
|
|
17134
18043
|
if (existsSync13(receiptPath)) {
|
|
17135
18044
|
return readAndValidateRecoveryReceipt(artifactDir, manifest, manifestHash);
|
|
17136
18045
|
}
|
|
@@ -17155,7 +18064,7 @@ async function artifactRepoRoot(stateDir, checkpointId) {
|
|
|
17155
18064
|
const artifactDir = checkpointDir(stateDir, checkpointId);
|
|
17156
18065
|
try {
|
|
17157
18066
|
const manifest = JSON.parse(
|
|
17158
|
-
await readFile9(
|
|
18067
|
+
await readFile9(path44.join(artifactDir, "manifest.json"), "utf8")
|
|
17159
18068
|
);
|
|
17160
18069
|
if (typeof manifest.repoRoot === "string" && manifest.repoRoot) {
|
|
17161
18070
|
return canonicalPath(manifest.repoRoot);
|
|
@@ -17163,7 +18072,7 @@ async function artifactRepoRoot(stateDir, checkpointId) {
|
|
|
17163
18072
|
} catch {
|
|
17164
18073
|
}
|
|
17165
18074
|
try {
|
|
17166
|
-
const owner = JSON.parse(await readFile9(
|
|
18075
|
+
const owner = JSON.parse(await readFile9(path44.join(artifactDir, "owner.json"), "utf8"));
|
|
17167
18076
|
return typeof owner.repoRoot === "string" && owner.repoRoot ? canonicalPath(owner.repoRoot) : null;
|
|
17168
18077
|
} catch {
|
|
17169
18078
|
return null;
|
|
@@ -17183,10 +18092,10 @@ async function cleanupOrphanedStaging(stateDir) {
|
|
|
17183
18092
|
const now = Date.now();
|
|
17184
18093
|
for (const entry of await readdir2(root, { withFileTypes: true })) {
|
|
17185
18094
|
if (!entry.isDirectory() || !/^\.tmp-cp_[a-f0-9]{24}$/.test(entry.name)) continue;
|
|
17186
|
-
const stagingPath =
|
|
18095
|
+
const stagingPath = path44.join(root, entry.name);
|
|
17187
18096
|
let stale = false;
|
|
17188
18097
|
try {
|
|
17189
|
-
const owner = JSON.parse(await readFile9(
|
|
18098
|
+
const owner = JSON.parse(await readFile9(path44.join(stagingPath, "owner.json"), "utf8"));
|
|
17190
18099
|
const pid = typeof owner.pid === "number" ? owner.pid : Number.NaN;
|
|
17191
18100
|
const createdAt = typeof owner.createdAt === "string" ? Date.parse(owner.createdAt) : NaN;
|
|
17192
18101
|
let alive = false;
|
|
@@ -17228,7 +18137,7 @@ async function markRecoveryCheckpointApplied(stateDir, checkpoint) {
|
|
|
17228
18137
|
init_fingerprint2();
|
|
17229
18138
|
import { existsSync as existsSync14 } from "node:fs";
|
|
17230
18139
|
import { readFile as readFile10 } from "node:fs/promises";
|
|
17231
|
-
import
|
|
18140
|
+
import path45 from "node:path";
|
|
17232
18141
|
async function matchRecoverySide(resourceRoot, entries, side) {
|
|
17233
18142
|
for (const entry of entries) {
|
|
17234
18143
|
const target = await assertRecoverySafeTarget(resourceRoot, entry.path);
|
|
@@ -17243,7 +18152,7 @@ async function reconcileRecoveryCheckpoint(stateDir, checkpointId) {
|
|
|
17243
18152
|
} catch {
|
|
17244
18153
|
const artifactDir = checkpointDir(stateDir, checkpointId);
|
|
17245
18154
|
if (existsSync14(artifactDir)) {
|
|
17246
|
-
const manifestPath =
|
|
18155
|
+
const manifestPath = path45.join(artifactDir, "manifest.json");
|
|
17247
18156
|
const hash = existsSync14(manifestPath) ? hashValue(await readFile10(manifestPath, "utf8")) : "unavailable";
|
|
17248
18157
|
await writeRecoveryState(artifactDir, "corrupt", hash, RECOVERY_CHECKPOINT_CORRUPT);
|
|
17249
18158
|
}
|
|
@@ -17280,7 +18189,7 @@ async function reconcileRecoveryCheckpoint(stateDir, checkpointId) {
|
|
|
17280
18189
|
// src/core/recovery/resource-identity.ts
|
|
17281
18190
|
init_fingerprint2();
|
|
17282
18191
|
import { lstat as lstat8, readFile as readFile11, realpath as realpath3 } from "node:fs/promises";
|
|
17283
|
-
import
|
|
18192
|
+
import path46 from "node:path";
|
|
17284
18193
|
async function currentRecoveryResourceIdentity(resourceRoot, resourceKind) {
|
|
17285
18194
|
const resolvedRoot = await realpath3(resourceRoot);
|
|
17286
18195
|
if (resourceKind === "directory") {
|
|
@@ -17288,13 +18197,13 @@ async function currentRecoveryResourceIdentity(resourceRoot, resourceKind) {
|
|
|
17288
18197
|
if (!rootInfo.isDirectory()) throw new Error("recovery_repo_identity_unavailable");
|
|
17289
18198
|
return hashValue(`${resolvedRoot}\0${rootInfo.dev}:${rootInfo.ino}:${rootInfo.birthtimeMs}`);
|
|
17290
18199
|
}
|
|
17291
|
-
const dotGit =
|
|
18200
|
+
const dotGit = path46.join(resolvedRoot, ".git");
|
|
17292
18201
|
const gitInfo = await lstat8(dotGit);
|
|
17293
18202
|
let gitMetadataPath = dotGit;
|
|
17294
18203
|
if (gitInfo.isFile()) {
|
|
17295
18204
|
const marker = (await readFile11(dotGit, "utf8")).trim();
|
|
17296
18205
|
if (!marker.startsWith("gitdir:")) throw new Error("recovery_repo_identity_unavailable");
|
|
17297
|
-
gitMetadataPath =
|
|
18206
|
+
gitMetadataPath = path46.resolve(resolvedRoot, marker.slice("gitdir:".length).trim());
|
|
17298
18207
|
} else if (!gitInfo.isDirectory()) {
|
|
17299
18208
|
throw new Error("recovery_repo_identity_unavailable");
|
|
17300
18209
|
}
|
|
@@ -17367,16 +18276,16 @@ async function prepareRecoveryCheckpoint(params) {
|
|
|
17367
18276
|
throw new Error(RECOVERY_CHECKPOINT_QUOTA);
|
|
17368
18277
|
}
|
|
17369
18278
|
const checkpointId = `cp_${randomUUID5().replaceAll("-", "").slice(0, 24)}`;
|
|
17370
|
-
const temporary =
|
|
18279
|
+
const temporary = path47.join(checkpointsRoot(params.stateDir), `.tmp-${checkpointId}`);
|
|
17371
18280
|
const finalDir = checkpointDir(params.stateDir, checkpointId);
|
|
17372
18281
|
await mkdir11(temporary, { recursive: true, mode: 448 });
|
|
17373
|
-
await atomicWriteJson(
|
|
18282
|
+
await atomicWriteJson(path47.join(temporary, "owner.json"), {
|
|
17374
18283
|
version: 1,
|
|
17375
18284
|
pid: process.pid,
|
|
17376
18285
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
17377
18286
|
repoRoot: canonicalPath(params.repoRoot)
|
|
17378
18287
|
});
|
|
17379
|
-
await mkdir11(
|
|
18288
|
+
await mkdir11(path47.join(temporary, "blobs"), { recursive: true, mode: 448 });
|
|
17380
18289
|
try {
|
|
17381
18290
|
const entries = [];
|
|
17382
18291
|
const protectedRoots = (params.protectedRoots ?? []).map(canonicalPath);
|
|
@@ -17385,8 +18294,8 @@ async function prepareRecoveryCheckpoint(params) {
|
|
|
17385
18294
|
)) {
|
|
17386
18295
|
const target = await assertRecoverySafeTarget(params.repoRoot, change.relativePath);
|
|
17387
18296
|
if (protectedRoots.some((root) => {
|
|
17388
|
-
const relative =
|
|
17389
|
-
return relative === "" || relative !== ".." && !relative.startsWith(`..${
|
|
18297
|
+
const relative = path47.relative(root, target);
|
|
18298
|
+
return relative === "" || relative !== ".." && !relative.startsWith(`..${path47.sep}`) && !path47.isAbsolute(relative);
|
|
17390
18299
|
})) {
|
|
17391
18300
|
throw new Error("recovery_protected_path");
|
|
17392
18301
|
}
|
|
@@ -17398,7 +18307,7 @@ async function prepareRecoveryCheckpoint(params) {
|
|
|
17398
18307
|
entries.push({
|
|
17399
18308
|
path: change.relativePath,
|
|
17400
18309
|
before: await captureRecoverySnapshot(baseline, {
|
|
17401
|
-
blobDir:
|
|
18310
|
+
blobDir: path47.join(temporary, "blobs")
|
|
17402
18311
|
}),
|
|
17403
18312
|
after: withoutRecoveryBlob(await captureRecoverySnapshot(source))
|
|
17404
18313
|
});
|
|
@@ -17435,7 +18344,7 @@ async function prepareRecoveryCheckpoint(params) {
|
|
|
17435
18344
|
entries
|
|
17436
18345
|
};
|
|
17437
18346
|
const manifestHash = hashValue(canonicalStringify(manifest));
|
|
17438
|
-
await atomicWriteJson(
|
|
18347
|
+
await atomicWriteJson(path47.join(temporary, "manifest.json"), manifest);
|
|
17439
18348
|
await writeRecoveryState(temporary, "prepared", manifestHash);
|
|
17440
18349
|
await fsyncPath2(temporary);
|
|
17441
18350
|
const projectedBytes = await recoveryCheckpointStorageBytes(params.stateDir, params.repoRoot);
|
|
@@ -17478,7 +18387,7 @@ async function listRecoveryCheckpoints(stateDir, repoRoot) {
|
|
|
17478
18387
|
} catch {
|
|
17479
18388
|
try {
|
|
17480
18389
|
const raw = JSON.parse(
|
|
17481
|
-
await readFile12(
|
|
18390
|
+
await readFile12(path47.join(checkpointDir(stateDir, id), "manifest.json"), "utf8")
|
|
17482
18391
|
);
|
|
17483
18392
|
rootFromArtifact = typeof raw.repoRoot === "string" && raw.repoRoot ? raw.repoRoot : void 0;
|
|
17484
18393
|
} catch {
|
|
@@ -17512,7 +18421,7 @@ async function listRecoveryCheckpoints(stateDir, repoRoot) {
|
|
|
17512
18421
|
} catch {
|
|
17513
18422
|
try {
|
|
17514
18423
|
const manifest = JSON.parse(
|
|
17515
|
-
await readFile12(
|
|
18424
|
+
await readFile12(path47.join(checkpointDir(stateDir, id), "manifest.json"), "utf8")
|
|
17516
18425
|
);
|
|
17517
18426
|
if (manifest.checkpointId !== id || ![1, 2].includes(manifest.version)) continue;
|
|
17518
18427
|
if (repoRoot && canonicalPath(manifest.repoRoot) !== canonicalPath(repoRoot)) continue;
|
|
@@ -17542,7 +18451,7 @@ async function recoveryCheckpointStorageBytes(stateDir, repoRoot) {
|
|
|
17542
18451
|
let total = 0;
|
|
17543
18452
|
for (const entry of await readdir3(root, { withFileTypes: true })) {
|
|
17544
18453
|
if (!entry.isDirectory()) continue;
|
|
17545
|
-
const entryPath =
|
|
18454
|
+
const entryPath = path47.join(root, entry.name);
|
|
17546
18455
|
if (/^cp_[a-f0-9]{24}$/.test(entry.name)) {
|
|
17547
18456
|
if (await artifactRepoRoot(stateDir, entry.name) === expected) {
|
|
17548
18457
|
total += await directorySize(entryPath);
|
|
@@ -17551,7 +18460,7 @@ async function recoveryCheckpointStorageBytes(stateDir, repoRoot) {
|
|
|
17551
18460
|
}
|
|
17552
18461
|
if (/^\.tmp-cp_[a-f0-9]{24}$/.test(entry.name)) {
|
|
17553
18462
|
try {
|
|
17554
|
-
const owner = JSON.parse(await readFile12(
|
|
18463
|
+
const owner = JSON.parse(await readFile12(path47.join(entryPath, "owner.json"), "utf8"));
|
|
17555
18464
|
if (typeof owner.repoRoot === "string" && canonicalPath(owner.repoRoot) === expected) {
|
|
17556
18465
|
total += await directorySize(entryPath);
|
|
17557
18466
|
}
|
|
@@ -17595,14 +18504,14 @@ init_scrub();
|
|
|
17595
18504
|
// src/core/transactional/file-checkpoint-backend.ts
|
|
17596
18505
|
import { cp, lstat as lstat11, mkdir as mkdir13, mkdtemp as mkdtemp5, readdir as readdir6, rm as rm9, writeFile as writeFile10 } from "node:fs/promises";
|
|
17597
18506
|
import os5 from "node:os";
|
|
17598
|
-
import
|
|
18507
|
+
import path51 from "node:path";
|
|
17599
18508
|
|
|
17600
18509
|
// src/core/transactional/file-checkpoint-git.ts
|
|
17601
18510
|
init_path_utils();
|
|
17602
18511
|
import { spawn as spawn8 } from "node:child_process";
|
|
17603
18512
|
import { createHash as createHash13 } from "node:crypto";
|
|
17604
18513
|
import { copyFile as copyFile3, lstat as lstat9, readdir as readdir4, readFile as readFile13 } from "node:fs/promises";
|
|
17605
|
-
import
|
|
18514
|
+
import path48 from "node:path";
|
|
17606
18515
|
var FILE_CHECKPOINT_GIT_METADATA_CHANGED = "file_checkpoint_git_metadata_changed";
|
|
17607
18516
|
var FILE_CHECKPOINT_SOURCE_CHANGED = "file_checkpoint_source_changed";
|
|
17608
18517
|
var FILE_CHECKPOINT_CWD_OUTSIDE_ROOT = "file_checkpoint_cwd_outside_root";
|
|
@@ -17636,7 +18545,7 @@ function rethrowStableFileCheckpointError(error) {
|
|
|
17636
18545
|
}
|
|
17637
18546
|
async function rootGitMetadataPresent(repoRoot) {
|
|
17638
18547
|
try {
|
|
17639
|
-
await lstat9(
|
|
18548
|
+
await lstat9(path48.join(repoRoot, ".git"));
|
|
17640
18549
|
return true;
|
|
17641
18550
|
} catch {
|
|
17642
18551
|
return false;
|
|
@@ -17685,10 +18594,10 @@ function execGit2(repoRoot, args) {
|
|
|
17685
18594
|
}
|
|
17686
18595
|
async function resolveGitPath(repoRoot, gitPath) {
|
|
17687
18596
|
const trimmed = gitPath.trim();
|
|
17688
|
-
if (
|
|
18597
|
+
if (path48.isAbsolute(trimmed)) {
|
|
17689
18598
|
return trimmed;
|
|
17690
18599
|
}
|
|
17691
|
-
return
|
|
18600
|
+
return path48.join(repoRoot, trimmed);
|
|
17692
18601
|
}
|
|
17693
18602
|
async function cloneBareWorktreeCopy(sourceRoot, destinationRoot) {
|
|
17694
18603
|
await execGit2(sourceRoot, [
|
|
@@ -17730,7 +18639,7 @@ async function copyGitIndexState(sourceRoot, destinationRoot) {
|
|
|
17730
18639
|
destinationRoot,
|
|
17731
18640
|
await execGit2(destinationRoot, ["rev-parse", "--git-dir"])
|
|
17732
18641
|
);
|
|
17733
|
-
const destinationShared =
|
|
18642
|
+
const destinationShared = path48.join(destinationGitDir, path48.basename(sourceShared));
|
|
17734
18643
|
try {
|
|
17735
18644
|
await copyFile3(sourceShared, destinationShared);
|
|
17736
18645
|
} catch (error) {
|
|
@@ -17739,7 +18648,7 @@ async function copyGitIndexState(sourceRoot, destinationRoot) {
|
|
|
17739
18648
|
}
|
|
17740
18649
|
async function readGitFile(gitDir, relativePath) {
|
|
17741
18650
|
try {
|
|
17742
|
-
return await readFile13(
|
|
18651
|
+
return await readFile13(path48.join(gitDir, relativePath));
|
|
17743
18652
|
} catch {
|
|
17744
18653
|
return null;
|
|
17745
18654
|
}
|
|
@@ -17763,8 +18672,8 @@ async function hashResolvedGitPath(repoRoot, gitDir, gitPath, hash) {
|
|
|
17763
18672
|
repoRoot,
|
|
17764
18673
|
await execGit2(repoRoot, ["rev-parse", "--git-path", gitPath])
|
|
17765
18674
|
);
|
|
17766
|
-
const relative =
|
|
17767
|
-
const content = typeof relative === "string" && !relative.startsWith("..") && !
|
|
18675
|
+
const relative = path48.resolve(resolved).startsWith(path48.resolve(gitDir)) ? path48.relative(gitDir, resolved) : resolved;
|
|
18676
|
+
const content = typeof relative === "string" && !relative.startsWith("..") && !path48.isAbsolute(relative) ? await readGitFile(gitDir, relative) : await readAbsoluteGitFile(resolved);
|
|
17768
18677
|
if (content !== null) {
|
|
17769
18678
|
hashGitFileContent(hash, gitPath, content);
|
|
17770
18679
|
}
|
|
@@ -17774,13 +18683,13 @@ async function hashResolvedGitPath(repoRoot, gitDir, gitPath, hash) {
|
|
|
17774
18683
|
async function hashGitTree(gitDir, relativeDir, hash) {
|
|
17775
18684
|
let names;
|
|
17776
18685
|
try {
|
|
17777
|
-
names = await readdir4(
|
|
18686
|
+
names = await readdir4(path48.join(gitDir, relativeDir));
|
|
17778
18687
|
} catch {
|
|
17779
18688
|
return;
|
|
17780
18689
|
}
|
|
17781
18690
|
for (const name of names.sort()) {
|
|
17782
|
-
const relativePath = relativeDir ?
|
|
17783
|
-
const absolutePath =
|
|
18691
|
+
const relativePath = relativeDir ? path48.join(relativeDir, name) : name;
|
|
18692
|
+
const absolutePath = path48.join(gitDir, relativePath);
|
|
17784
18693
|
let childNames = null;
|
|
17785
18694
|
try {
|
|
17786
18695
|
childNames = await readdir4(absolutePath);
|
|
@@ -17802,7 +18711,7 @@ async function hashGitTree(gitDir, relativeDir, hash) {
|
|
|
17802
18711
|
}
|
|
17803
18712
|
async function computeGitMetadataFingerprint(repoRoot) {
|
|
17804
18713
|
const gitDirRel = (await execGit2(repoRoot, ["rev-parse", "--git-dir"])).trim();
|
|
17805
|
-
const gitDir =
|
|
18714
|
+
const gitDir = path48.isAbsolute(gitDirRel) ? gitDirRel : path48.join(repoRoot, gitDirRel);
|
|
17806
18715
|
const hash = createHash13("sha256");
|
|
17807
18716
|
for (const file of [
|
|
17808
18717
|
"HEAD",
|
|
@@ -17825,8 +18734,8 @@ async function computeGitMetadataFingerprint(repoRoot) {
|
|
|
17825
18734
|
const sharedIndex = (await execGit2(repoRoot, ["rev-parse", "--shared-index-path"])).trim();
|
|
17826
18735
|
if (sharedIndex) {
|
|
17827
18736
|
const resolved = await resolveGitPath(repoRoot, sharedIndex);
|
|
17828
|
-
const relative =
|
|
17829
|
-
const content = relative && !relative.startsWith("..") && !
|
|
18737
|
+
const relative = path48.relative(gitDir, resolved);
|
|
18738
|
+
const content = relative && !relative.startsWith("..") && !path48.isAbsolute(relative) ? await readGitFile(gitDir, relative) : await readAbsoluteGitFile(resolved);
|
|
17830
18739
|
if (content !== null) {
|
|
17831
18740
|
hashGitFileContent(hash, "shared-index", content);
|
|
17832
18741
|
}
|
|
@@ -17837,7 +18746,7 @@ async function computeGitMetadataFingerprint(repoRoot) {
|
|
|
17837
18746
|
await hashResolvedGitPath(repoRoot, gitDir, gitPath, hash);
|
|
17838
18747
|
}
|
|
17839
18748
|
try {
|
|
17840
|
-
const rootGitPath =
|
|
18749
|
+
const rootGitPath = path48.join(repoRoot, ".git");
|
|
17841
18750
|
const rootGitInfo = await lstat9(rootGitPath);
|
|
17842
18751
|
if (rootGitInfo.isFile()) {
|
|
17843
18752
|
const content = await readAbsoluteGitFile(rootGitPath);
|
|
@@ -17853,14 +18762,14 @@ async function computeGitMetadataFingerprint(repoRoot) {
|
|
|
17853
18762
|
function resolveExecutionCwdRelative(resourceRoot, cwd) {
|
|
17854
18763
|
const resolvedCwd = canonicalPath(cwd);
|
|
17855
18764
|
const resourceCanonical = canonicalPath(resourceRoot);
|
|
17856
|
-
const relative =
|
|
18765
|
+
const relative = path48.relative(resourceCanonical, resolvedCwd);
|
|
17857
18766
|
if (relative === "" || relative === ".") {
|
|
17858
18767
|
return "";
|
|
17859
18768
|
}
|
|
17860
|
-
if (relative.startsWith("..") ||
|
|
18769
|
+
if (relative.startsWith("..") || path48.isAbsolute(relative)) {
|
|
17861
18770
|
throw new Error(FILE_CHECKPOINT_CWD_OUTSIDE_ROOT);
|
|
17862
18771
|
}
|
|
17863
|
-
return relative.split(
|
|
18772
|
+
return relative.split(path48.sep).join("/");
|
|
17864
18773
|
}
|
|
17865
18774
|
|
|
17866
18775
|
// src/core/transactional/file-checkpoint-isolation.ts
|
|
@@ -17882,7 +18791,7 @@ function fileCheckpointIsolationReason(context) {
|
|
|
17882
18791
|
|
|
17883
18792
|
// src/core/transactional/file-checkpoint-staging.ts
|
|
17884
18793
|
import { readdir as readdir5, readFile as readFile14, rm as rm7, writeFile as writeFile8 } from "node:fs/promises";
|
|
17885
|
-
import
|
|
18794
|
+
import path49 from "node:path";
|
|
17886
18795
|
function isOwnerProcessAlive(pid) {
|
|
17887
18796
|
try {
|
|
17888
18797
|
process.kill(pid, 0);
|
|
@@ -17892,12 +18801,12 @@ function isOwnerProcessAlive(pid) {
|
|
|
17892
18801
|
}
|
|
17893
18802
|
}
|
|
17894
18803
|
async function writeOwnerMarker(stagingRoot, marker) {
|
|
17895
|
-
await writeFile8(
|
|
18804
|
+
await writeFile8(path49.join(stagingRoot, "owner.json"), `${JSON.stringify(marker)}
|
|
17896
18805
|
`, "utf8");
|
|
17897
18806
|
}
|
|
17898
18807
|
async function readOwnerMarker(stagingRoot) {
|
|
17899
18808
|
try {
|
|
17900
|
-
const raw = await readFile14(
|
|
18809
|
+
const raw = await readFile14(path49.join(stagingRoot, "owner.json"), "utf8");
|
|
17901
18810
|
return JSON.parse(raw.trim());
|
|
17902
18811
|
} catch {
|
|
17903
18812
|
return null;
|
|
@@ -17915,7 +18824,7 @@ async function collectDeadOwnerStaging(parentDir) {
|
|
|
17915
18824
|
if (!name.startsWith("belay-file-checkpoint-")) {
|
|
17916
18825
|
continue;
|
|
17917
18826
|
}
|
|
17918
|
-
const stagingRoot =
|
|
18827
|
+
const stagingRoot = path49.join(parentDir, name);
|
|
17919
18828
|
const marker = await readOwnerMarker(stagingRoot);
|
|
17920
18829
|
if (!marker) {
|
|
17921
18830
|
dead.push(stagingRoot);
|
|
@@ -17947,7 +18856,7 @@ import {
|
|
|
17947
18856
|
writeFile as writeFile9
|
|
17948
18857
|
} from "node:fs/promises";
|
|
17949
18858
|
import os4 from "node:os";
|
|
17950
|
-
import
|
|
18859
|
+
import path50 from "node:path";
|
|
17951
18860
|
var FILE_CHECKPOINT_COPY_FAILED = "file_checkpoint_copy_failed";
|
|
17952
18861
|
async function chmodSafe2(target, mode) {
|
|
17953
18862
|
try {
|
|
@@ -17957,7 +18866,7 @@ async function chmodSafe2(target, mode) {
|
|
|
17957
18866
|
}
|
|
17958
18867
|
}
|
|
17959
18868
|
async function copyRegularFile(sourcePath, destinationPath, mode, strategy) {
|
|
17960
|
-
await mkdir12(
|
|
18869
|
+
await mkdir12(path50.dirname(destinationPath), { recursive: true });
|
|
17961
18870
|
if (strategy === "clonefile" && fsConstants2.COPYFILE_FICLONE !== void 0) {
|
|
17962
18871
|
try {
|
|
17963
18872
|
await copyFile4(sourcePath, destinationPath, fsConstants2.COPYFILE_FICLONE);
|
|
@@ -17983,7 +18892,7 @@ async function copyNode(sourceRoot, destinationRoot, relativePath, strategy) {
|
|
|
17983
18892
|
return strategy;
|
|
17984
18893
|
}
|
|
17985
18894
|
if (info.isSymbolicLink()) {
|
|
17986
|
-
await mkdir12(
|
|
18895
|
+
await mkdir12(path50.dirname(destinationPath), { recursive: true });
|
|
17987
18896
|
await symlink4(await readlink5(sourcePath), destinationPath);
|
|
17988
18897
|
return strategy;
|
|
17989
18898
|
}
|
|
@@ -18039,9 +18948,9 @@ async function mapWithConcurrency(items, concurrency, worker) {
|
|
|
18039
18948
|
async function probeFileCloneStrategy() {
|
|
18040
18949
|
let tempDir = null;
|
|
18041
18950
|
try {
|
|
18042
|
-
tempDir = await mkdtemp4(
|
|
18043
|
-
const source =
|
|
18044
|
-
const destination =
|
|
18951
|
+
tempDir = await mkdtemp4(path50.join(os4.tmpdir(), "belay-clone-probe-"));
|
|
18952
|
+
const source = path50.join(tempDir, "source.txt");
|
|
18953
|
+
const destination = path50.join(tempDir, "dest.txt");
|
|
18045
18954
|
await writeFile9(source, "probe\n");
|
|
18046
18955
|
if (fsConstants2.COPYFILE_FICLONE_FORCE !== void 0) {
|
|
18047
18956
|
try {
|
|
@@ -18194,11 +19103,11 @@ async function protectedRootState(root) {
|
|
|
18194
19103
|
return `directory:${node.hash}:${index.treeHash}`;
|
|
18195
19104
|
}
|
|
18196
19105
|
function executionProtectedRoot(resourceRoot, executionRoot, protectedRoot) {
|
|
18197
|
-
const relative =
|
|
18198
|
-
if (relative === "" || relative.startsWith("..") ||
|
|
19106
|
+
const relative = path51.relative(path51.resolve(resourceRoot), path51.resolve(protectedRoot));
|
|
19107
|
+
if (relative === "" || relative.startsWith("..") || path51.isAbsolute(relative)) {
|
|
18199
19108
|
return null;
|
|
18200
19109
|
}
|
|
18201
|
-
return
|
|
19110
|
+
return path51.join(executionRoot, relative);
|
|
18202
19111
|
}
|
|
18203
19112
|
async function captureProtectedRootStates(resourceRoot, executionRoot, protectedRoots) {
|
|
18204
19113
|
const states = /* @__PURE__ */ new Map();
|
|
@@ -18223,15 +19132,15 @@ async function directoryByteSize(root, deadlineMs) {
|
|
|
18223
19132
|
}
|
|
18224
19133
|
let total = 0;
|
|
18225
19134
|
for (const name of await readdir6(root)) {
|
|
18226
|
-
total += await directoryByteSize(
|
|
19135
|
+
total += await directoryByteSize(path51.join(root, name), deadlineMs);
|
|
18227
19136
|
}
|
|
18228
19137
|
return total;
|
|
18229
19138
|
}
|
|
18230
19139
|
async function copyGitMetadataDirectory(sourceRoot, destinationRoot) {
|
|
18231
19140
|
const gitDirRel = (await execGit2(sourceRoot, ["rev-parse", "--git-dir"])).trim();
|
|
18232
|
-
const sourceGitDir =
|
|
18233
|
-
const relativeGitDir =
|
|
18234
|
-
const destinationGitDir = relativeGitDir && !relativeGitDir.startsWith("..") ?
|
|
19141
|
+
const sourceGitDir = path51.isAbsolute(gitDirRel) ? gitDirRel : path51.join(sourceRoot, gitDirRel);
|
|
19142
|
+
const relativeGitDir = path51.relative(path51.resolve(sourceRoot), path51.resolve(sourceGitDir));
|
|
19143
|
+
const destinationGitDir = relativeGitDir && !relativeGitDir.startsWith("..") ? path51.join(destinationRoot, relativeGitDir) : path51.join(destinationRoot, ".git");
|
|
18235
19144
|
await cp(sourceGitDir, destinationGitDir, { recursive: true, force: true });
|
|
18236
19145
|
}
|
|
18237
19146
|
async function prepareDirtyGitSnapshot(context) {
|
|
@@ -18240,7 +19149,7 @@ async function prepareDirtyGitSnapshot(context) {
|
|
|
18240
19149
|
const quotas = context.fileCheckpoint;
|
|
18241
19150
|
const deadlineMs = Date.now() + quotas.prepareTimeoutMs;
|
|
18242
19151
|
await removeDeadOwnerStaging(os5.tmpdir());
|
|
18243
|
-
const stagingRoot = await mkdtemp5(
|
|
19152
|
+
const stagingRoot = await mkdtemp5(path51.join(os5.tmpdir(), "belay-file-checkpoint-"));
|
|
18244
19153
|
await writeOwnerMarker(stagingRoot, {
|
|
18245
19154
|
version: 1,
|
|
18246
19155
|
pid: process.pid,
|
|
@@ -18248,8 +19157,8 @@ async function prepareDirtyGitSnapshot(context) {
|
|
|
18248
19157
|
resourceRoot: context.repoRoot,
|
|
18249
19158
|
backend: "file_checkpoint"
|
|
18250
19159
|
});
|
|
18251
|
-
const baselineRoot =
|
|
18252
|
-
const executionRoot =
|
|
19160
|
+
const baselineRoot = path51.join(stagingRoot, "baseline");
|
|
19161
|
+
const executionRoot = path51.join(stagingRoot, "execution");
|
|
18253
19162
|
try {
|
|
18254
19163
|
resolveExecutionCwdRelative(context.repoRoot, context.cwd);
|
|
18255
19164
|
const sourceGitMetadataFingerprint = await computeGitMetadataFingerprint(context.repoRoot);
|
|
@@ -18283,7 +19192,7 @@ async function prepareDirtyGitSnapshot(context) {
|
|
|
18283
19192
|
throw new Error(FILE_CHECKPOINT_SOURCE_CHANGED);
|
|
18284
19193
|
}
|
|
18285
19194
|
await writeFile10(
|
|
18286
|
-
|
|
19195
|
+
path51.join(stagingRoot, "baseline-index.json"),
|
|
18287
19196
|
`${JSON.stringify(baselineIndex)}
|
|
18288
19197
|
`,
|
|
18289
19198
|
"utf8"
|
|
@@ -18333,7 +19242,7 @@ async function prepareNonGitSnapshot(context) {
|
|
|
18333
19242
|
const quotas = context.fileCheckpoint;
|
|
18334
19243
|
const deadlineMs = Date.now() + quotas.prepareTimeoutMs;
|
|
18335
19244
|
await removeDeadOwnerStaging(os5.tmpdir());
|
|
18336
|
-
const stagingRoot = await mkdtemp5(
|
|
19245
|
+
const stagingRoot = await mkdtemp5(path51.join(os5.tmpdir(), "belay-file-checkpoint-"));
|
|
18337
19246
|
await writeOwnerMarker(stagingRoot, {
|
|
18338
19247
|
version: 1,
|
|
18339
19248
|
pid: process.pid,
|
|
@@ -18341,8 +19250,8 @@ async function prepareNonGitSnapshot(context) {
|
|
|
18341
19250
|
resourceRoot: context.repoRoot,
|
|
18342
19251
|
backend: "file_checkpoint"
|
|
18343
19252
|
});
|
|
18344
|
-
const baselineRoot =
|
|
18345
|
-
const executionRoot =
|
|
19253
|
+
const baselineRoot = path51.join(stagingRoot, "baseline");
|
|
19254
|
+
const executionRoot = path51.join(stagingRoot, "execution");
|
|
18346
19255
|
try {
|
|
18347
19256
|
resolveExecutionCwdRelative(context.repoRoot, context.cwd);
|
|
18348
19257
|
const resourceIdentity = await currentRecoveryResourceIdentity(context.repoRoot, "directory");
|
|
@@ -18371,7 +19280,7 @@ async function prepareNonGitSnapshot(context) {
|
|
|
18371
19280
|
throw new Error(FILE_CHECKPOINT_SOURCE_CHANGED);
|
|
18372
19281
|
}
|
|
18373
19282
|
await writeFile10(
|
|
18374
|
-
|
|
19283
|
+
path51.join(stagingRoot, "baseline-index.json"),
|
|
18375
19284
|
`${JSON.stringify(baselineIndex)}
|
|
18376
19285
|
`,
|
|
18377
19286
|
"utf8"
|
|
@@ -18724,10 +19633,10 @@ async function selectTransactionalBackend(context) {
|
|
|
18724
19633
|
}
|
|
18725
19634
|
|
|
18726
19635
|
// src/core/transactional/diff-evaluator.ts
|
|
18727
|
-
import
|
|
19636
|
+
import path52 from "node:path";
|
|
18728
19637
|
init_path_utils();
|
|
18729
19638
|
function categorizeChange(change, ctx) {
|
|
18730
|
-
const absolutePath = canonicalPath(
|
|
19639
|
+
const absolutePath = canonicalPath(path52.join(ctx.repoRoot, change.relativePath));
|
|
18731
19640
|
if (!pathWithinRoot(ctx.repoRoot, absolutePath)) {
|
|
18732
19641
|
return "repo_outside";
|
|
18733
19642
|
}
|
|
@@ -19321,7 +20230,7 @@ async function notifyDeny(config, event) {
|
|
|
19321
20230
|
init_path_utils();
|
|
19322
20231
|
|
|
19323
20232
|
// src/adapters/layouts/protected-paths.ts
|
|
19324
|
-
import
|
|
20233
|
+
import path53 from "node:path";
|
|
19325
20234
|
function protectedArtifactRoots(layout, repoRoot, controlPlaneDir) {
|
|
19326
20235
|
const roots = [
|
|
19327
20236
|
layout.configPath(repoRoot),
|
|
@@ -19333,7 +20242,7 @@ function protectedArtifactRoots(layout, repoRoot, controlPlaneDir) {
|
|
|
19333
20242
|
if (controlPlaneDir) {
|
|
19334
20243
|
roots.push(controlPlaneDir);
|
|
19335
20244
|
}
|
|
19336
|
-
return roots.map((entry) =>
|
|
20245
|
+
return roots.map((entry) => path53.resolve(entry));
|
|
19337
20246
|
}
|
|
19338
20247
|
|
|
19339
20248
|
// src/adapters/shared/gate-runtime.ts
|
|
@@ -19386,8 +20295,8 @@ function createDefaultGateRuntimeDeps() {
|
|
|
19386
20295
|
return loadJsonFile(configPath, {});
|
|
19387
20296
|
},
|
|
19388
20297
|
async appendAudit(ctx, event) {
|
|
19389
|
-
const auditPath =
|
|
19390
|
-
await mkdir14(
|
|
20298
|
+
const auditPath = path54.join(ctx.repoRoot, ctx.config.audit.logPath);
|
|
20299
|
+
await mkdir14(path54.dirname(auditPath), { recursive: true });
|
|
19391
20300
|
const provenance = auditProvenance(ctx.config);
|
|
19392
20301
|
const record = {
|
|
19393
20302
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -19420,7 +20329,7 @@ function createDefaultGateRuntimeDeps() {
|
|
|
19420
20329
|
};
|
|
19421
20330
|
},
|
|
19422
20331
|
async writeApprovals(filePath, state) {
|
|
19423
|
-
await mkdir14(
|
|
20332
|
+
await mkdir14(path54.dirname(filePath), { recursive: true });
|
|
19424
20333
|
await writeFile11(filePath, `${JSON.stringify(compactApprovals(state), null, 2)}
|
|
19425
20334
|
`, "utf8");
|
|
19426
20335
|
},
|
|
@@ -19582,7 +20491,7 @@ function deriveWorkspaceRootScopeHint(params) {
|
|
|
19582
20491
|
if (!targetPath) {
|
|
19583
20492
|
return void 0;
|
|
19584
20493
|
}
|
|
19585
|
-
const candidateRoot = canonicalPath(
|
|
20494
|
+
const candidateRoot = canonicalPath(path54.dirname(targetPath));
|
|
19586
20495
|
const validation = validateTrustedWorkspaceRootCandidate({
|
|
19587
20496
|
candidatePath: candidateRoot,
|
|
19588
20497
|
repoRoot: action.repoRoot,
|
|
@@ -19916,6 +20825,7 @@ async function evaluateGatedAction(ctx, deps, params) {
|
|
|
19916
20825
|
event: resolveGateAuditEvent(sourceEvent, params.kind),
|
|
19917
20826
|
sourceEvent,
|
|
19918
20827
|
kind: params.kind,
|
|
20828
|
+
...typeof params.payload?.tool_use_id === "string" ? { toolInvocationCorrelationId: toolInvocationCorrelationId(params.payload.tool_use_id) } : {},
|
|
19919
20829
|
fingerprint: verdict2.fingerprint,
|
|
19920
20830
|
verdict: verdict2.verdict,
|
|
19921
20831
|
reason: verdict2.reason,
|
|
@@ -20073,6 +20983,7 @@ async function evaluateGatedAction(ctx, deps, params) {
|
|
|
20073
20983
|
const scrubbedPayload = fingerprintReplayPayload(params.kind, params.payload, scrubOpts);
|
|
20074
20984
|
return gateDecisionToVerdict(ctx, deps, params.kind, result, {
|
|
20075
20985
|
sourceEvent: params.sourceEvent,
|
|
20986
|
+
toolInvocationCorrelationId: typeof params.payload?.tool_use_id === "string" ? toolInvocationCorrelationId(params.payload.tool_use_id) : void 0,
|
|
20076
20987
|
predictedAssessment,
|
|
20077
20988
|
observedAssessment: observedAssessment2,
|
|
20078
20989
|
transactionalLayer,
|
|
@@ -20190,6 +21101,7 @@ async function gateDecisionToVerdict(ctx, deps, kind, result, auditExtras = {})
|
|
|
20190
21101
|
event: auditEvent,
|
|
20191
21102
|
sourceEvent,
|
|
20192
21103
|
kind,
|
|
21104
|
+
...auditExtras.toolInvocationCorrelationId ? { toolInvocationCorrelationId: auditExtras.toolInvocationCorrelationId } : {},
|
|
20193
21105
|
fingerprint: result.fingerprint,
|
|
20194
21106
|
summary: result.normalizedCommand ?? result.summary ?? "",
|
|
20195
21107
|
assessment: result.assessment,
|
|
@@ -20640,29 +21552,56 @@ function gateVerdictToCodexUserPromptResponse(verdict2) {
|
|
|
20640
21552
|
};
|
|
20641
21553
|
}
|
|
20642
21554
|
async function appendObservedAudit(ctx, deps, eventName, payload) {
|
|
21555
|
+
const rawToolUseId = typeof payload.tool_use_id === "string" ? payload.tool_use_id : void 0;
|
|
21556
|
+
const summaryPayload = redactToolInvocationId(payload, rawToolUseId);
|
|
20643
21557
|
await deps.appendAudit(ctx, {
|
|
20644
21558
|
event: eventName,
|
|
20645
21559
|
kind: "audit",
|
|
20646
21560
|
verdict: "allow",
|
|
20647
21561
|
reason: "observed",
|
|
20648
|
-
|
|
21562
|
+
...rawToolUseId ? { toolInvocationCorrelationId: toolInvocationCorrelationId(rawToolUseId) } : {},
|
|
21563
|
+
...typeof summaryPayload.tool_name === "string" ? { toolName: summaryPayload.tool_name } : {},
|
|
21564
|
+
...typeof summaryPayload.failure_type === "string" ? { failureType: summaryPayload.failure_type } : {},
|
|
21565
|
+
...typeof summaryPayload.error_message === "string" ? { errorMessage: summaryPayload.error_message } : {},
|
|
21566
|
+
...typeof payload.duration === "number" ? { durationMs: payload.duration } : {},
|
|
21567
|
+
...typeof payload.is_interrupt === "boolean" ? { isInterrupt: payload.is_interrupt } : {},
|
|
21568
|
+
summary: canonicalStringify(summaryPayload)
|
|
20649
21569
|
});
|
|
20650
21570
|
}
|
|
20651
21571
|
|
|
20652
21572
|
// src/adapters/shared/repo-root.ts
|
|
20653
21573
|
import { existsSync as existsSync17 } from "node:fs";
|
|
20654
|
-
import
|
|
21574
|
+
import path55 from "node:path";
|
|
21575
|
+
function belayConfigPath(current, adapterName) {
|
|
21576
|
+
if (adapterName === "cursor") {
|
|
21577
|
+
return path55.join(current, ".cursor", "belay.config.json");
|
|
21578
|
+
}
|
|
21579
|
+
if (adapterName === "claude") {
|
|
21580
|
+
return path55.join(current, ".claude", "belay.config.json");
|
|
21581
|
+
}
|
|
21582
|
+
return path55.join(current, ".codex", "belay.config.json");
|
|
21583
|
+
}
|
|
21584
|
+
function markerMatches(current, marker, layout) {
|
|
21585
|
+
const markerPath = path55.join(current, marker);
|
|
21586
|
+
if (!existsSync17(markerPath)) {
|
|
21587
|
+
return false;
|
|
21588
|
+
}
|
|
21589
|
+
if (marker === ".cursor" || marker === ".claude" || marker === ".codex") {
|
|
21590
|
+
return existsSync17(belayConfigPath(current, layout.name));
|
|
21591
|
+
}
|
|
21592
|
+
return true;
|
|
21593
|
+
}
|
|
20655
21594
|
function findRepoRoot(startPath, layout) {
|
|
20656
|
-
let current =
|
|
21595
|
+
let current = path55.resolve(startPath);
|
|
20657
21596
|
while (true) {
|
|
20658
21597
|
for (const marker of layout.repoRootMarkers) {
|
|
20659
|
-
if (
|
|
21598
|
+
if (markerMatches(current, marker, layout)) {
|
|
20660
21599
|
return current;
|
|
20661
21600
|
}
|
|
20662
21601
|
}
|
|
20663
|
-
const parent =
|
|
21602
|
+
const parent = path55.dirname(current);
|
|
20664
21603
|
if (parent === current) {
|
|
20665
|
-
return
|
|
21604
|
+
return path55.resolve(startPath);
|
|
20666
21605
|
}
|
|
20667
21606
|
current = parent;
|
|
20668
21607
|
}
|
|
@@ -20688,6 +21627,16 @@ function jsonResponse(value) {
|
|
|
20688
21627
|
process2.stdout.write(`${JSON.stringify(value)}
|
|
20689
21628
|
`);
|
|
20690
21629
|
}
|
|
21630
|
+
function nonEmptyPathString(value) {
|
|
21631
|
+
return typeof value === "string" && value.trim() ? value.trim() : void 0;
|
|
21632
|
+
}
|
|
21633
|
+
function resolveCodexActionCwd(payload, fallbackCwd = process2.cwd(), options = {}) {
|
|
21634
|
+
const toolInput = payload.tool_input !== null && typeof payload.tool_input === "object" ? payload.tool_input : void 0;
|
|
21635
|
+
const nestedCwd = options.includeToolInputCwd ? nonEmptyPathString(toolInput?.working_directory) ?? nonEmptyPathString(toolInput?.cwd) : void 0;
|
|
21636
|
+
const payloadCwd = nonEmptyPathString(payload.cwd);
|
|
21637
|
+
const workspaceRoot = Array.isArray(payload.workspace_roots) ? payload.workspace_roots.map(nonEmptyPathString).find(Boolean) : void 0;
|
|
21638
|
+
return path56.resolve(nestedCwd ?? payloadCwd ?? workspaceRoot ?? fallbackCwd);
|
|
21639
|
+
}
|
|
20691
21640
|
async function loadRuntimeContext(cwd) {
|
|
20692
21641
|
const repoRoot = findRepoRoot(cwd, codexLayout);
|
|
20693
21642
|
const configPath = codexLayout.configPath(repoRoot);
|
|
@@ -20780,7 +21729,8 @@ async function runBeforeSubmitPromptHook() {
|
|
|
20780
21729
|
try {
|
|
20781
21730
|
const payload = await readStdinJson();
|
|
20782
21731
|
const prompt = String(payload.prompt ?? payload.user_message ?? "");
|
|
20783
|
-
const
|
|
21732
|
+
const cwd = resolveCodexActionCwd(payload);
|
|
21733
|
+
const ctx = await loadRuntimeContext(cwd);
|
|
20784
21734
|
const deps = createDefaultGateRuntimeDeps();
|
|
20785
21735
|
const result = await processApprovalPrompt(ctx, deps, prompt);
|
|
20786
21736
|
jsonResponse(gateVerdictToCodexUserPromptResponse(result));
|
|
@@ -20794,9 +21744,10 @@ async function runBeforeSubmitPromptHook() {
|
|
|
20794
21744
|
async function runToolGateHook(eventName) {
|
|
20795
21745
|
try {
|
|
20796
21746
|
const payload = await readStdinJson();
|
|
20797
|
-
const cwd = process2.cwd();
|
|
20798
21747
|
const toolName = String(payload.tool_name ?? payload.toolName ?? "");
|
|
20799
21748
|
const kind = resolveCodexGateKind(eventName, toolName);
|
|
21749
|
+
const includeToolInputCwd = (eventName === "PreToolUse" || eventName === "preToolUse") && kind === "shell";
|
|
21750
|
+
const cwd = resolveCodexActionCwd(payload, process2.cwd(), { includeToolInputCwd });
|
|
20800
21751
|
const ctx = await loadRuntimeContext(cwd);
|
|
20801
21752
|
const deps = createDefaultGateRuntimeDeps();
|
|
20802
21753
|
if (!kind) {
|
|
@@ -20834,7 +21785,7 @@ async function runShellGateHook() {
|
|
|
20834
21785
|
try {
|
|
20835
21786
|
const payload = await readStdinJson();
|
|
20836
21787
|
const command = extractString(payload.tool_input, "command") || String(payload.command ?? "");
|
|
20837
|
-
const cwd = process2.cwd();
|
|
21788
|
+
const cwd = resolveCodexActionCwd(payload, process2.cwd(), { includeToolInputCwd: true });
|
|
20838
21789
|
const ctx = await loadRuntimeContext(cwd);
|
|
20839
21790
|
const deps = createDefaultGateRuntimeDeps();
|
|
20840
21791
|
const verdict2 = await evaluateGatedAction(ctx, deps, {
|
|
@@ -20859,7 +21810,11 @@ async function runShellGateHook() {
|
|
|
20859
21810
|
async function runAuditHook(eventName) {
|
|
20860
21811
|
try {
|
|
20861
21812
|
const payload = await readStdinJson();
|
|
20862
|
-
const
|
|
21813
|
+
const toolName = String(payload.tool_name ?? payload.toolName ?? "");
|
|
21814
|
+
const kind = resolveCodexGateKind(eventName, toolName);
|
|
21815
|
+
const includeToolInputCwd = (eventName === "PreToolUse" || eventName === "preToolUse") && kind === "shell";
|
|
21816
|
+
const cwd = resolveCodexActionCwd(payload, process2.cwd(), { includeToolInputCwd });
|
|
21817
|
+
const ctx = await loadRuntimeContext(cwd);
|
|
20863
21818
|
const deps = createDefaultGateRuntimeDeps();
|
|
20864
21819
|
await appendObservedAudit(ctx, deps, eventName, payload);
|
|
20865
21820
|
jsonResponse({});
|
|
@@ -20872,6 +21827,7 @@ async function runAuditHook(eventName) {
|
|
|
20872
21827
|
}
|
|
20873
21828
|
}
|
|
20874
21829
|
export {
|
|
21830
|
+
resolveCodexActionCwd,
|
|
20875
21831
|
runAuditHook,
|
|
20876
21832
|
runBeforeSubmitPromptHook,
|
|
20877
21833
|
runShellGateHook,
|