@guilz-dev/belay 0.9.2 → 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 +1 -0
- package/dist/adapters/cursor/hooks.js +21 -0
- 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 +855 -338
- package/dist/bundle/codex-runtime.mjs +877 -342
- package/dist/bundle/cursor-runtime.mjs +3886 -3141
- package/dist/cli.js +33 -3
- package/dist/commands/doctor.js +24 -1
- 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-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 +93 -40
- 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 +28 -28
- package/dist/core/verdict/parser.d.ts +3 -0
- package/dist/core/verdict/parser.js +23 -40
- package/dist/core/verdict/recursive-invocation.d.ts +20 -0
- package/dist/core/verdict/recursive-invocation.js +224 -0
- package/dist/defaults.js +7 -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();
|
|
@@ -11123,10 +11248,346 @@ init_git_resource_identity();
|
|
|
11123
11248
|
init_path_utils();
|
|
11124
11249
|
init_shell_tokenizer();
|
|
11125
11250
|
import { lstatSync as lstatSync2, realpathSync as realpathSync4 } from "node:fs";
|
|
11126
|
-
import
|
|
11251
|
+
import path41 from "node:path";
|
|
11127
11252
|
|
|
11128
|
-
// 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
|
|
11129
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";
|
|
11130
11591
|
var CURL_EFFECT_NEUTRAL_FLAGS = /* @__PURE__ */ new Set([
|
|
11131
11592
|
"-f",
|
|
11132
11593
|
"-L",
|
|
@@ -11161,7 +11622,7 @@ var GH_READ_COMMANDS = /* @__PURE__ */ new Set([
|
|
|
11161
11622
|
"workflow view"
|
|
11162
11623
|
]);
|
|
11163
11624
|
function decodeEgressEffects(params) {
|
|
11164
|
-
const head =
|
|
11625
|
+
const head = path37.basename(params.tokens[0] ?? "");
|
|
11165
11626
|
if (head !== "curl" && head !== "wget" && head !== "gh") {
|
|
11166
11627
|
return null;
|
|
11167
11628
|
}
|
|
@@ -11169,7 +11630,7 @@ function decodeEgressEffects(params) {
|
|
|
11169
11630
|
const provenance = { segment: params.segment };
|
|
11170
11631
|
const requirements = [];
|
|
11171
11632
|
for (const file of decoded.files) {
|
|
11172
|
-
const resolved =
|
|
11633
|
+
const resolved = path37.resolve(params.cwd, expandHome2(file));
|
|
11173
11634
|
requirements.push(
|
|
11174
11635
|
requirement("fs.read", "fs.read", { kind: "path", path: resolved }, params.segment, [
|
|
11175
11636
|
"egress.explicit_file_read"
|
|
@@ -11191,7 +11652,7 @@ function decodeEgressEffects(params) {
|
|
|
11191
11652
|
if (file === "-") {
|
|
11192
11653
|
continue;
|
|
11193
11654
|
}
|
|
11194
|
-
const resolved =
|
|
11655
|
+
const resolved = path37.resolve(params.cwd, expandHome2(file));
|
|
11195
11656
|
if (resolved === "/dev/null") {
|
|
11196
11657
|
continue;
|
|
11197
11658
|
}
|
|
@@ -11669,13 +12130,13 @@ function decodeSingleCurlWgetGrammar(head, tokens) {
|
|
|
11669
12130
|
if (head === "wget" && !explicitOutput) {
|
|
11670
12131
|
outputFiles.push(
|
|
11671
12132
|
...endpointOutputNames.map(
|
|
11672
|
-
(name) => outputDirectory ?
|
|
12133
|
+
(name) => outputDirectory ? path37.join(outputDirectory, name) : name
|
|
11673
12134
|
)
|
|
11674
12135
|
);
|
|
11675
12136
|
} else if (head === "curl" && remoteNameOutput) {
|
|
11676
12137
|
outputFiles.push(
|
|
11677
12138
|
...endpointOutputNames.map(
|
|
11678
|
-
(name) => outputDirectory ?
|
|
12139
|
+
(name) => outputDirectory ? path37.join(outputDirectory, name) : name
|
|
11679
12140
|
)
|
|
11680
12141
|
);
|
|
11681
12142
|
}
|
|
@@ -11689,7 +12150,7 @@ function decodeSingleCurlWgetGrammar(head, tokens) {
|
|
|
11689
12150
|
outputFiles: [
|
|
11690
12151
|
...new Set(
|
|
11691
12152
|
outputFiles.map(
|
|
11692
|
-
(file) => outputDirectory && directoryEligibleOutputs.has(file) && !
|
|
12153
|
+
(file) => outputDirectory && directoryEligibleOutputs.has(file) && !path37.isAbsolute(file) ? path37.join(outputDirectory, file) : file
|
|
11693
12154
|
)
|
|
11694
12155
|
)
|
|
11695
12156
|
],
|
|
@@ -11704,7 +12165,7 @@ function remoteOutputName(spec) {
|
|
|
11704
12165
|
} catch {
|
|
11705
12166
|
pathname = spec.split(/[?#]/, 1)[0] ?? "";
|
|
11706
12167
|
}
|
|
11707
|
-
const name =
|
|
12168
|
+
const name = path37.posix.basename(pathname);
|
|
11708
12169
|
return name && name !== "/" ? name : "index.html";
|
|
11709
12170
|
}
|
|
11710
12171
|
function decodeGhGrammar(tokens) {
|
|
@@ -11869,7 +12330,7 @@ function expandHome2(value) {
|
|
|
11869
12330
|
return process.env.HOME ?? value;
|
|
11870
12331
|
}
|
|
11871
12332
|
if (value.startsWith("~/")) {
|
|
11872
|
-
return
|
|
12333
|
+
return path37.join(process.env.HOME ?? "~", value.slice(2));
|
|
11873
12334
|
}
|
|
11874
12335
|
return value;
|
|
11875
12336
|
}
|
|
@@ -11888,7 +12349,7 @@ function requirement(tag, action, resource, segment, signals) {
|
|
|
11888
12349
|
}
|
|
11889
12350
|
|
|
11890
12351
|
// src/core/verdict/git-classifier.ts
|
|
11891
|
-
import
|
|
12352
|
+
import path38 from "node:path";
|
|
11892
12353
|
init_shell_tokenizer();
|
|
11893
12354
|
var GIT_BRANCH_MUTATION_FLAGS = /* @__PURE__ */ new Set([
|
|
11894
12355
|
"--copy",
|
|
@@ -11984,7 +12445,7 @@ var FILE_OPERAND_SUBCOMMANDS = /* @__PURE__ */ new Set([
|
|
|
11984
12445
|
var COMPOUND_SUBCOMMAND_HEADS = /* @__PURE__ */ new Set(["worktree", "stash", "tag"]);
|
|
11985
12446
|
var REF_ONLY_WITHOUT_TERMINATOR = /* @__PURE__ */ new Set(["checkout", "show", "log"]);
|
|
11986
12447
|
function isGitExecutable(token) {
|
|
11987
|
-
return
|
|
12448
|
+
return path38.basename(token) === "git";
|
|
11988
12449
|
}
|
|
11989
12450
|
function takesValue(flag) {
|
|
11990
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=");
|
|
@@ -12012,7 +12473,7 @@ function peelGlobalOptions(tokens, baseCwd) {
|
|
|
12012
12473
|
if (token === "-C" || token === "--work-tree" || token === "--git-dir" || token === "-c") {
|
|
12013
12474
|
const value = tokens[index + 1];
|
|
12014
12475
|
if (token === "-C" && value) {
|
|
12015
|
-
effectiveCwd =
|
|
12476
|
+
effectiveCwd = path38.resolve(baseCwd, value);
|
|
12016
12477
|
} else if (token === "--work-tree" && value) {
|
|
12017
12478
|
workTree = value;
|
|
12018
12479
|
} else if (token === "--git-dir" && value) {
|
|
@@ -12022,7 +12483,7 @@ function peelGlobalOptions(tokens, baseCwd) {
|
|
|
12022
12483
|
continue;
|
|
12023
12484
|
}
|
|
12024
12485
|
if (token.startsWith("-C") && token.length > 2) {
|
|
12025
|
-
effectiveCwd =
|
|
12486
|
+
effectiveCwd = path38.resolve(baseCwd, token.slice(2));
|
|
12026
12487
|
index += 1;
|
|
12027
12488
|
continue;
|
|
12028
12489
|
}
|
|
@@ -12165,7 +12626,7 @@ function looksLikeDiffPathOperand(token) {
|
|
|
12165
12626
|
if (!looksLikeFileOperand(token)) {
|
|
12166
12627
|
return false;
|
|
12167
12628
|
}
|
|
12168
|
-
if (token.startsWith(".") ||
|
|
12629
|
+
if (token.startsWith(".") || path38.isAbsolute(token)) {
|
|
12169
12630
|
return true;
|
|
12170
12631
|
}
|
|
12171
12632
|
return token.includes(".");
|
|
@@ -12173,12 +12634,12 @@ function looksLikeDiffPathOperand(token) {
|
|
|
12173
12634
|
function resolveGitWorkTree(baseCwd, effectiveCwd, workTree, gitDir) {
|
|
12174
12635
|
const resolveBase = effectiveCwd ?? baseCwd;
|
|
12175
12636
|
if (workTree) {
|
|
12176
|
-
return
|
|
12637
|
+
return path38.resolve(resolveBase, workTree);
|
|
12177
12638
|
}
|
|
12178
12639
|
if (gitDir) {
|
|
12179
|
-
const resolvedGitDir =
|
|
12180
|
-
if (
|
|
12181
|
-
return
|
|
12640
|
+
const resolvedGitDir = path38.resolve(resolveBase, gitDir);
|
|
12641
|
+
if (path38.basename(resolvedGitDir) === ".git") {
|
|
12642
|
+
return path38.dirname(resolvedGitDir);
|
|
12182
12643
|
}
|
|
12183
12644
|
}
|
|
12184
12645
|
return void 0;
|
|
@@ -12259,7 +12720,7 @@ function classifyGitCommand(tokens, baseCwd) {
|
|
|
12259
12720
|
const { subcommand, args, effectiveCwd, gitDir, workTree } = normalized;
|
|
12260
12721
|
const normalizedKey = `git ${subcommand}`;
|
|
12261
12722
|
const gitWorkTree = resolveGitWorkTree(baseCwd, effectiveCwd, workTree, gitDir);
|
|
12262
|
-
const effectiveGitDir = gitDir ?
|
|
12723
|
+
const effectiveGitDir = gitDir ? path38.resolve(effectiveCwd ?? baseCwd, gitDir) : void 0;
|
|
12263
12724
|
const scopeTargets = [effectiveCwd, gitWorkTree, effectiveGitDir].filter(
|
|
12264
12725
|
(target, index, targets) => Boolean(target) && targets.indexOf(target) === index
|
|
12265
12726
|
);
|
|
@@ -12411,9 +12872,9 @@ function decodeGitEffects(params) {
|
|
|
12411
12872
|
...subcommand === "push" ? ["tier0_external"] : []
|
|
12412
12873
|
];
|
|
12413
12874
|
const effectiveCwd = normalized.effectiveCwd ?? params.cwd;
|
|
12414
|
-
const workTreeRoot = normalized.workTree ?
|
|
12415
|
-
const gitRefRoot = normalized.gitDir ?
|
|
12416
|
-
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");
|
|
12417
12878
|
const requirements = [];
|
|
12418
12879
|
if (subcommand === "fetch" || subcommand === "pull") {
|
|
12419
12880
|
const positionals = gitRemotePositionals(args);
|
|
@@ -12572,7 +13033,7 @@ function decodeGitEffects(params) {
|
|
|
12572
13033
|
gitRequirement(
|
|
12573
13034
|
"control_plane.write",
|
|
12574
13035
|
"control_plane.write",
|
|
12575
|
-
{ kind: "path", path:
|
|
13036
|
+
{ kind: "path", path: path38.join(gitControlRoot, "logs") },
|
|
12576
13037
|
params.segment,
|
|
12577
13038
|
[...signals, "git_history_destructive", "git.reflog.mutate"]
|
|
12578
13039
|
)
|
|
@@ -12630,7 +13091,7 @@ function decodeGitEffects(params) {
|
|
|
12630
13091
|
gitRequirement(
|
|
12631
13092
|
"fs.read",
|
|
12632
13093
|
"fs.read",
|
|
12633
|
-
{ kind: "path", path:
|
|
13094
|
+
{ kind: "path", path: path38.resolve(workTreeRoot, operand) },
|
|
12634
13095
|
params.segment,
|
|
12635
13096
|
[...signals, "git.path.read"]
|
|
12636
13097
|
)
|
|
@@ -12665,7 +13126,7 @@ function decodeGitEffects(params) {
|
|
|
12665
13126
|
gitRequirement(
|
|
12666
13127
|
"fs.write",
|
|
12667
13128
|
"fs.write",
|
|
12668
|
-
{ kind: "path", path:
|
|
13129
|
+
{ kind: "path", path: path38.resolve(workTreeRoot, operand) },
|
|
12669
13130
|
params.segment,
|
|
12670
13131
|
[...signals, "git.path.write"]
|
|
12671
13132
|
)
|
|
@@ -12850,7 +13311,7 @@ function gitRequirement(tag, action, resource, segment, signals) {
|
|
|
12850
13311
|
|
|
12851
13312
|
// src/core/verdict/launcher-resolve.ts
|
|
12852
13313
|
import { existsSync as existsSync11, readFileSync as readFileSync5 } from "node:fs";
|
|
12853
|
-
import
|
|
13314
|
+
import path39 from "node:path";
|
|
12854
13315
|
|
|
12855
13316
|
// src/core/verdict/makefile-expand.ts
|
|
12856
13317
|
var MAX_EXPAND_DEPTH = 16;
|
|
@@ -12869,22 +13330,6 @@ function parseMakefileVariables(content) {
|
|
|
12869
13330
|
}
|
|
12870
13331
|
return variables;
|
|
12871
13332
|
}
|
|
12872
|
-
function parsePhonyTargets(content) {
|
|
12873
|
-
const phony = /* @__PURE__ */ new Set();
|
|
12874
|
-
for (const line of content.split("\n")) {
|
|
12875
|
-
const trimmed = line.trim();
|
|
12876
|
-
const match = /^\.PHONY:\s*(.+)$/.exec(trimmed);
|
|
12877
|
-
if (!match) {
|
|
12878
|
-
continue;
|
|
12879
|
-
}
|
|
12880
|
-
for (const token of (match[1] ?? "").split(/\s+/)) {
|
|
12881
|
-
if (token) {
|
|
12882
|
-
phony.add(token);
|
|
12883
|
-
}
|
|
12884
|
-
}
|
|
12885
|
-
}
|
|
12886
|
-
return phony;
|
|
12887
|
-
}
|
|
12888
13333
|
function normalizeMakeRecipeLine(line) {
|
|
12889
13334
|
let normalized = line.trim();
|
|
12890
13335
|
while (normalized.startsWith("@") || normalized.startsWith("-") || normalized.startsWith("+")) {
|
|
@@ -13039,7 +13484,7 @@ var PNPM_BUILTIN_COMMANDS = /* @__PURE__ */ new Set([
|
|
|
13039
13484
|
"why"
|
|
13040
13485
|
]);
|
|
13041
13486
|
function readPackageJson(dir) {
|
|
13042
|
-
const packagePath =
|
|
13487
|
+
const packagePath = path39.join(dir, "package.json");
|
|
13043
13488
|
if (!existsSync11(packagePath)) {
|
|
13044
13489
|
return null;
|
|
13045
13490
|
}
|
|
@@ -13050,17 +13495,17 @@ function readPackageJson(dir) {
|
|
|
13050
13495
|
}
|
|
13051
13496
|
}
|
|
13052
13497
|
function findPackageJson(startDir, stopDir) {
|
|
13053
|
-
let current =
|
|
13054
|
-
const stop =
|
|
13498
|
+
let current = path39.resolve(startDir);
|
|
13499
|
+
const stop = path39.resolve(stopDir);
|
|
13055
13500
|
while (true) {
|
|
13056
|
-
const packagePath =
|
|
13501
|
+
const packagePath = path39.join(current, "package.json");
|
|
13057
13502
|
if (existsSync11(packagePath)) {
|
|
13058
13503
|
return packagePath;
|
|
13059
13504
|
}
|
|
13060
|
-
if (current === stop || current ===
|
|
13505
|
+
if (current === stop || current === path39.dirname(current)) {
|
|
13061
13506
|
return existsSync11(packagePath) ? packagePath : null;
|
|
13062
13507
|
}
|
|
13063
|
-
const parent =
|
|
13508
|
+
const parent = path39.dirname(current);
|
|
13064
13509
|
if (!parent.startsWith(stop) && parent !== current) {
|
|
13065
13510
|
}
|
|
13066
13511
|
if (parent === current) {
|
|
@@ -13117,7 +13562,7 @@ function resolveNpmRecipe(cwd, repoRoot, scriptName, extraArgs) {
|
|
|
13117
13562
|
}
|
|
13118
13563
|
return { recipes: [], opaque: true, reason: "package_json_missing" };
|
|
13119
13564
|
}
|
|
13120
|
-
const pkg = readPackageJson(
|
|
13565
|
+
const pkg = readPackageJson(path39.dirname(packagePath));
|
|
13121
13566
|
const scripts = pkg?.scripts;
|
|
13122
13567
|
if (!scripts || typeof scripts !== "object") {
|
|
13123
13568
|
return { recipes: [], opaque: true, reason: "package_scripts_missing" };
|
|
@@ -13208,27 +13653,26 @@ function parseMakefileRecipeContent(content) {
|
|
|
13208
13653
|
function resolveMakeRecipe(cwd, repoRoot, target, cliVars = {}) {
|
|
13209
13654
|
const candidates = ["Makefile", "makefile", "GNUmakefile"];
|
|
13210
13655
|
let makefilePath = null;
|
|
13211
|
-
let searchDir =
|
|
13212
|
-
const stop =
|
|
13656
|
+
let searchDir = path39.resolve(cwd);
|
|
13657
|
+
const stop = path39.resolve(repoRoot);
|
|
13213
13658
|
while (true) {
|
|
13214
13659
|
for (const name of candidates) {
|
|
13215
|
-
const candidate =
|
|
13660
|
+
const candidate = path39.join(searchDir, name);
|
|
13216
13661
|
if (existsSync11(candidate)) {
|
|
13217
13662
|
makefilePath = candidate;
|
|
13218
13663
|
break;
|
|
13219
13664
|
}
|
|
13220
13665
|
}
|
|
13221
|
-
if (makefilePath || searchDir === stop || searchDir ===
|
|
13666
|
+
if (makefilePath || searchDir === stop || searchDir === path39.dirname(searchDir)) {
|
|
13222
13667
|
break;
|
|
13223
13668
|
}
|
|
13224
|
-
searchDir =
|
|
13669
|
+
searchDir = path39.dirname(searchDir);
|
|
13225
13670
|
}
|
|
13226
13671
|
if (!makefilePath) {
|
|
13227
13672
|
return { recipes: [], opaque: true, reason: "unknown_local_effect" };
|
|
13228
13673
|
}
|
|
13229
13674
|
const makefileContent = readFileSync5(makefilePath, "utf8");
|
|
13230
13675
|
const makefileVars = parseMakefileVariables(makefileContent);
|
|
13231
|
-
const phonyTargets = parsePhonyTargets(makefileContent);
|
|
13232
13676
|
const targets = parseMakefileRecipeContent(makefileContent);
|
|
13233
13677
|
if (!targets.has(target)) {
|
|
13234
13678
|
return { recipes: [], opaque: true, reason: "make_target_undefined" };
|
|
@@ -13236,36 +13680,34 @@ function resolveMakeRecipe(cwd, repoRoot, target, cliVars = {}) {
|
|
|
13236
13680
|
const recipeLines = [];
|
|
13237
13681
|
const visiting = /* @__PURE__ */ new Set();
|
|
13238
13682
|
const visited = /* @__PURE__ */ new Set();
|
|
13239
|
-
let
|
|
13683
|
+
let hasDynamicPrerequisite = false;
|
|
13684
|
+
let hasUndefinedPrerequisite = false;
|
|
13685
|
+
let hasDependencyCycle = false;
|
|
13240
13686
|
const collect = (name) => {
|
|
13241
13687
|
if (visited.has(name)) {
|
|
13242
|
-
return
|
|
13688
|
+
return;
|
|
13243
13689
|
}
|
|
13244
13690
|
if (visiting.has(name)) {
|
|
13245
|
-
|
|
13691
|
+
hasDependencyCycle = true;
|
|
13692
|
+
return;
|
|
13246
13693
|
}
|
|
13247
13694
|
const entry = targets.get(name);
|
|
13248
13695
|
if (!entry) {
|
|
13249
|
-
|
|
13696
|
+
if (!existsSync11(path39.resolve(path39.dirname(makefilePath), name))) {
|
|
13697
|
+
hasUndefinedPrerequisite = true;
|
|
13698
|
+
}
|
|
13699
|
+
return;
|
|
13250
13700
|
}
|
|
13251
13701
|
visiting.add(name);
|
|
13252
|
-
|
|
13702
|
+
hasDynamicPrerequisite ||= entry.opaquePrerequisites;
|
|
13253
13703
|
for (const prerequisite of entry.prerequisites) {
|
|
13254
|
-
|
|
13255
|
-
return false;
|
|
13256
|
-
}
|
|
13257
|
-
}
|
|
13258
|
-
const skipPhonyPrerequisiteRecipes = name !== target && (phonyTargets.has(name) || name.startsWith("_")) && (targets.get(target)?.recipes.length ?? 0) > 0;
|
|
13259
|
-
if (!skipPhonyPrerequisiteRecipes) {
|
|
13260
|
-
recipeLines.push(...entry.recipes);
|
|
13704
|
+
collect(prerequisite);
|
|
13261
13705
|
}
|
|
13706
|
+
recipeLines.push(...entry.recipes);
|
|
13262
13707
|
visiting.delete(name);
|
|
13263
13708
|
visited.add(name);
|
|
13264
|
-
return true;
|
|
13265
13709
|
};
|
|
13266
|
-
|
|
13267
|
-
return { recipes: recipeLines, opaque: true, reason: "make_dependency_cycle" };
|
|
13268
|
-
}
|
|
13710
|
+
collect(target);
|
|
13269
13711
|
const expandedRecipes = [];
|
|
13270
13712
|
for (const line of recipeLines) {
|
|
13271
13713
|
const normalized = normalizeMakeRecipeLine(line);
|
|
@@ -13280,18 +13722,24 @@ function resolveMakeRecipe(cwd, repoRoot, target, cliVars = {}) {
|
|
|
13280
13722
|
return { recipes: expandedRecipes, opaque: true, reason: "make_recipe_dynamic" };
|
|
13281
13723
|
}
|
|
13282
13724
|
}
|
|
13283
|
-
if (
|
|
13725
|
+
if (hasDependencyCycle) {
|
|
13726
|
+
return { recipes: expandedRecipes, opaque: true, reason: "make_dependency_cycle" };
|
|
13727
|
+
}
|
|
13728
|
+
if (hasDynamicPrerequisite) {
|
|
13284
13729
|
return { recipes: expandedRecipes, opaque: true, reason: "make_prerequisite_dynamic" };
|
|
13285
13730
|
}
|
|
13731
|
+
if (hasUndefinedPrerequisite) {
|
|
13732
|
+
return { recipes: expandedRecipes, opaque: true, reason: "make_prerequisite_undefined" };
|
|
13733
|
+
}
|
|
13286
13734
|
return { recipes: expandedRecipes, opaque: false, reason: "make_recipe_resolved" };
|
|
13287
13735
|
}
|
|
13288
13736
|
function resolveLauncherRecipe(params) {
|
|
13289
|
-
if (params.depth >= MAX_RESOLVE_DEPTH) {
|
|
13290
|
-
return { recipes: [], opaque: true, reason: "launcher_depth_exceeded" };
|
|
13291
|
-
}
|
|
13292
13737
|
const tokens = params.tokens;
|
|
13293
13738
|
const scriptName = npmScriptName(tokens);
|
|
13294
13739
|
if (scriptName) {
|
|
13740
|
+
if (params.depth >= MAX_RESOLVE_DEPTH) {
|
|
13741
|
+
return { recipes: [], opaque: true, reason: "launcher_depth_exceeded" };
|
|
13742
|
+
}
|
|
13295
13743
|
const resolution = resolveNpmRecipe(
|
|
13296
13744
|
params.cwd,
|
|
13297
13745
|
params.repoRoot,
|
|
@@ -13308,6 +13756,9 @@ function resolveLauncherRecipe(params) {
|
|
|
13308
13756
|
return resolution;
|
|
13309
13757
|
}
|
|
13310
13758
|
if (tokens[0] === "make") {
|
|
13759
|
+
if (params.depth >= MAX_RESOLVE_DEPTH) {
|
|
13760
|
+
return { recipes: [], opaque: true, reason: "launcher_depth_exceeded" };
|
|
13761
|
+
}
|
|
13311
13762
|
if (tokens.includes("-n") || tokens.includes("--dry-run")) {
|
|
13312
13763
|
return null;
|
|
13313
13764
|
}
|
|
@@ -13341,7 +13792,7 @@ function resolveLauncherRecipe(params) {
|
|
|
13341
13792
|
}
|
|
13342
13793
|
|
|
13343
13794
|
// src/core/verdict/parser.ts
|
|
13344
|
-
import
|
|
13795
|
+
import path40 from "node:path";
|
|
13345
13796
|
|
|
13346
13797
|
// src/core/shell-substitution.ts
|
|
13347
13798
|
function findStructuralCommandSubstitutions(command) {
|
|
@@ -13566,9 +14017,8 @@ function hasUnbalancedDollarParen(command) {
|
|
|
13566
14017
|
// src/core/verdict/parser.ts
|
|
13567
14018
|
var ENV_PREFIX_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*=(?:'[^']*'|"[^"]*"|\S+)$/;
|
|
13568
14019
|
var MAX_WRAPPER_PEEL_DEPTH = 32;
|
|
13569
|
-
var
|
|
14020
|
+
var SHELL_INTERPRETERS2 = /* @__PURE__ */ new Set(["bash", "sh", "zsh", "dash", "fish"]);
|
|
13570
14021
|
var CODE_INTERPRETERS = /* @__PURE__ */ new Set(["python", "python3", "node", "ruby", "perl", "osascript"]);
|
|
13571
|
-
var SCRIPT_FLAGS = /* @__PURE__ */ new Set(["-c", "-lc", "-e", "--eval"]);
|
|
13572
14022
|
var INTERPRETER_SCRIPT_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
13573
14023
|
".js",
|
|
13574
14024
|
".mjs",
|
|
@@ -13580,7 +14030,7 @@ var INTERPRETER_SCRIPT_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
|
13580
14030
|
".sh"
|
|
13581
14031
|
]);
|
|
13582
14032
|
function normalizeHead(token) {
|
|
13583
|
-
const base =
|
|
14033
|
+
const base = path40.basename(token);
|
|
13584
14034
|
if (base && base !== "." && base !== "..") {
|
|
13585
14035
|
return base;
|
|
13586
14036
|
}
|
|
@@ -13592,10 +14042,6 @@ function peelTransparentWrappers(tokens) {
|
|
|
13592
14042
|
let encounteredXargs = false;
|
|
13593
14043
|
let peelDepth = 0;
|
|
13594
14044
|
while (current.length > 0) {
|
|
13595
|
-
if (peelDepth >= MAX_WRAPPER_PEEL_DEPTH) {
|
|
13596
|
-
return { tokens: current, xargsStdinOpaque: false, encounteredXargs, opaque: true };
|
|
13597
|
-
}
|
|
13598
|
-
peelDepth += 1;
|
|
13599
14045
|
while (current.length > 0 && ENV_PREFIX_PATTERN.test(current[0] ?? "")) {
|
|
13600
14046
|
current.shift();
|
|
13601
14047
|
}
|
|
@@ -13605,6 +14051,10 @@ function peelTransparentWrappers(tokens) {
|
|
|
13605
14051
|
const head = normalizeHead(current[0] ?? "");
|
|
13606
14052
|
if (head === "xargs") {
|
|
13607
14053
|
encounteredXargs = true;
|
|
14054
|
+
if (peelDepth >= MAX_WRAPPER_PEEL_DEPTH) {
|
|
14055
|
+
return { tokens: current, xargsStdinOpaque: false, encounteredXargs, opaque: true };
|
|
14056
|
+
}
|
|
14057
|
+
peelDepth += 1;
|
|
13608
14058
|
const wrapper2 = peelXargsWrapper(current);
|
|
13609
14059
|
if (wrapper2.kind === "opaque") {
|
|
13610
14060
|
xargsStdinOpaque = current.length === 1;
|
|
@@ -13622,6 +14072,10 @@ function peelTransparentWrappers(tokens) {
|
|
|
13622
14072
|
if (!wrapper) {
|
|
13623
14073
|
break;
|
|
13624
14074
|
}
|
|
14075
|
+
if (peelDepth >= MAX_WRAPPER_PEEL_DEPTH) {
|
|
14076
|
+
return { tokens: current, xargsStdinOpaque: false, encounteredXargs, opaque: true };
|
|
14077
|
+
}
|
|
14078
|
+
peelDepth += 1;
|
|
13625
14079
|
if (wrapper.kind === "opaque") {
|
|
13626
14080
|
return { tokens: current, xargsStdinOpaque: false, encounteredXargs, opaque: true };
|
|
13627
14081
|
}
|
|
@@ -13849,50 +14303,16 @@ function extractRecursiveScript(tokens) {
|
|
|
13849
14303
|
const body = filtered.slice(1).join(" ").trim();
|
|
13850
14304
|
return body || null;
|
|
13851
14305
|
}
|
|
13852
|
-
|
|
13853
|
-
|
|
13854
|
-
|
|
13855
|
-
|
|
13856
|
-
return body || null;
|
|
13857
|
-
}
|
|
13858
|
-
}
|
|
13859
|
-
return null;
|
|
13860
|
-
}
|
|
13861
|
-
function extractDockerComposeRunScript(tokens) {
|
|
13862
|
-
const head = normalizeHead(tokens[0] ?? "");
|
|
13863
|
-
const usesCompose = head === "docker-compose" || head === "docker" && (tokens[1] ?? "") === "compose";
|
|
13864
|
-
if (!usesCompose) {
|
|
13865
|
-
return null;
|
|
13866
|
-
}
|
|
13867
|
-
if (!tokens.includes("run")) {
|
|
13868
|
-
return null;
|
|
13869
|
-
}
|
|
13870
|
-
const runIndex = tokens.indexOf("run");
|
|
13871
|
-
const tail = tokens.slice(runIndex + 1);
|
|
13872
|
-
for (let index = 0; index < tail.length; index += 1) {
|
|
13873
|
-
const shellHead = normalizeHead(tail[index] ?? "");
|
|
13874
|
-
if (!SHELL_INTERPRETERS.has(shellHead)) {
|
|
13875
|
-
continue;
|
|
13876
|
-
}
|
|
13877
|
-
const flag = tail[index + 1] ?? "";
|
|
13878
|
-
if (flag !== "-lc" && flag !== "-c") {
|
|
13879
|
-
continue;
|
|
13880
|
-
}
|
|
13881
|
-
const body = tail[index + 2] ?? "";
|
|
13882
|
-
return body || null;
|
|
13883
|
-
}
|
|
13884
|
-
return null;
|
|
14306
|
+
const invocation = decodeRecursiveInvocation(
|
|
14307
|
+
shellTokensFromValues(filtered, { detectExpansion: false })
|
|
14308
|
+
);
|
|
14309
|
+
return invocation.kind === "static" ? invocation.script || null : null;
|
|
13885
14310
|
}
|
|
13886
|
-
function
|
|
13887
|
-
const
|
|
13888
|
-
|
|
13889
|
-
|
|
13890
|
-
|
|
13891
|
-
const head = normalizeHead(filtered[0] ?? "");
|
|
13892
|
-
if (head === "eval") {
|
|
13893
|
-
return true;
|
|
13894
|
-
}
|
|
13895
|
-
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));
|
|
13896
14316
|
}
|
|
13897
14317
|
function isCommandInspection(tokens) {
|
|
13898
14318
|
return normalizeHead(tokens[0] ?? "") === "command" && peelCommandWrapper(tokens).kind === "preserve";
|
|
@@ -13906,11 +14326,10 @@ function isBareInterpreter(tokens) {
|
|
|
13906
14326
|
return false;
|
|
13907
14327
|
}
|
|
13908
14328
|
const head = normalizeHead(peeled[0] ?? "");
|
|
13909
|
-
if (!
|
|
14329
|
+
if (!SHELL_INTERPRETERS2.has(head) && !CODE_INTERPRETERS.has(head)) {
|
|
13910
14330
|
return false;
|
|
13911
14331
|
}
|
|
13912
|
-
|
|
13913
|
-
if (hasScriptFlag) {
|
|
14332
|
+
if (decodeRecursiveInvocation(shellTokensFromValues(peeled)).kind !== "none") {
|
|
13914
14333
|
return false;
|
|
13915
14334
|
}
|
|
13916
14335
|
const args = peeled.slice(1);
|
|
@@ -13921,7 +14340,7 @@ function isBareInterpreter(tokens) {
|
|
|
13921
14340
|
return false;
|
|
13922
14341
|
}
|
|
13923
14342
|
const scriptArg = args.find((token) => !token.startsWith("-"));
|
|
13924
|
-
if (scriptArg && INTERPRETER_SCRIPT_EXTENSIONS.has(
|
|
14343
|
+
if (scriptArg && INTERPRETER_SCRIPT_EXTENSIONS.has(path40.extname(scriptArg))) {
|
|
13925
14344
|
return false;
|
|
13926
14345
|
}
|
|
13927
14346
|
if (scriptArg) {
|
|
@@ -14213,11 +14632,11 @@ function lowerTopLevelSegments(command, context) {
|
|
|
14213
14632
|
}
|
|
14214
14633
|
function startsLocalPostgresService(command) {
|
|
14215
14634
|
const tokens = tokenizeShell(command);
|
|
14216
|
-
return
|
|
14635
|
+
return path41.basename(tokens[0] ?? "") === "docker" && tokens[1] === "compose" && ["up", "start", "restart"].includes(tokens[2] ?? "") && tokens.includes("postgres");
|
|
14217
14636
|
}
|
|
14218
14637
|
function resolveCdTransition(command, currentCwd) {
|
|
14219
14638
|
const tokens = tokenizeShell(command);
|
|
14220
|
-
if (
|
|
14639
|
+
if (path41.basename(tokens[0] ?? "") !== "cd") {
|
|
14221
14640
|
return null;
|
|
14222
14641
|
}
|
|
14223
14642
|
const target = tokens[1] ?? "~";
|
|
@@ -14238,7 +14657,8 @@ function joinNestedOpacity(outer, nested) {
|
|
|
14238
14657
|
}
|
|
14239
14658
|
function lowerSegment(command, context) {
|
|
14240
14659
|
const commandRedacted = redactCommand(command);
|
|
14241
|
-
const
|
|
14660
|
+
const lexed = lexShell(command);
|
|
14661
|
+
const rawTokens = lexed.tokens.map((token) => token.value);
|
|
14242
14662
|
const environment = extractEnvironment(rawTokens, context.env);
|
|
14243
14663
|
const env = environment.env;
|
|
14244
14664
|
const parsed = parseSegment(command);
|
|
@@ -14246,10 +14666,23 @@ function lowerSegment(command, context) {
|
|
|
14246
14666
|
const tokens = stripRedirects(
|
|
14247
14667
|
parsedTokens.length === 0 && rawTokens.length > 0 && rawTokens.every((token) => ENV_PREFIX_PATTERN2.test(token)) ? rawTokens : parsedTokens
|
|
14248
14668
|
).map((token) => expandKnownVariables(token, env));
|
|
14249
|
-
const
|
|
14669
|
+
const decoderTokens = alignStructuredTokens(
|
|
14670
|
+
stripStructuredRedirects(lexed.tokens),
|
|
14671
|
+
stripRedirects(parsedTokens)
|
|
14672
|
+
);
|
|
14673
|
+
const head = path41.basename(tokens[0] ?? parsed.head);
|
|
14250
14674
|
let opacity = segmentOpacity(command);
|
|
14251
14675
|
const signals = /* @__PURE__ */ new Set();
|
|
14252
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
|
+
}
|
|
14253
14686
|
addRedirectEffects(requirements, rawTokens, env, context, commandRedacted);
|
|
14254
14687
|
addSubstitutionEffects(requirements, command, context, commandRedacted, signals);
|
|
14255
14688
|
if (environment.malformed) {
|
|
@@ -14269,7 +14702,7 @@ function lowerSegment(command, context) {
|
|
|
14269
14702
|
signals.add("shell.xargs_stdin_dynamic");
|
|
14270
14703
|
opacity = joinEffectOpacity(opacity, "opaque");
|
|
14271
14704
|
}
|
|
14272
|
-
if (context.depth
|
|
14705
|
+
if (context.depth > MAX_LOWER_DEPTH) {
|
|
14273
14706
|
requirements.push(
|
|
14274
14707
|
requirement2("indeterminate", "indeterminate", { kind: "unknown" }, commandRedacted, [
|
|
14275
14708
|
"shell.lower_depth_exceeded"
|
|
@@ -14316,62 +14749,96 @@ function lowerSegment(command, context) {
|
|
|
14316
14749
|
}
|
|
14317
14750
|
return shellSegment(commandRedacted, head, requirements, opacity, signals);
|
|
14318
14751
|
}
|
|
14319
|
-
const
|
|
14320
|
-
if (
|
|
14321
|
-
const dynamicEvaluation = isDynamicRecursiveEvaluation(tokens);
|
|
14752
|
+
const recursive = decodeRecursiveInvocationTokens(decoderTokens);
|
|
14753
|
+
if (recursive.kind === "static" && opacity !== "opaque" && opacity !== "unparseable") {
|
|
14322
14754
|
requirements.push(
|
|
14323
|
-
processRequirement(
|
|
14755
|
+
processRequirement(recursive.interpreter, "spawn", commandRedacted, [
|
|
14324
14756
|
"shell.recursive_wrapper",
|
|
14325
|
-
|
|
14757
|
+
"dynamic_shell_evaluation"
|
|
14326
14758
|
])
|
|
14327
14759
|
);
|
|
14328
|
-
|
|
14329
|
-
|
|
14330
|
-
|
|
14331
|
-
|
|
14332
|
-
|
|
14333
|
-
|
|
14334
|
-
|
|
14335
|
-
|
|
14336
|
-
|
|
14337
|
-
(
|
|
14338
|
-
|
|
14339
|
-
|
|
14340
|
-
|
|
14341
|
-
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);
|
|
14342
14774
|
}
|
|
14343
14775
|
}
|
|
14344
14776
|
signals.add("shell.recursive_wrapper");
|
|
14345
|
-
|
|
14346
|
-
signals.add("dynamic_shell_evaluation");
|
|
14347
|
-
}
|
|
14777
|
+
signals.add("dynamic_shell_evaluation");
|
|
14348
14778
|
return shellSegment(commandRedacted, head, requirements, "recursive", signals);
|
|
14349
14779
|
}
|
|
14350
|
-
|
|
14351
|
-
|
|
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") {
|
|
14352
14802
|
requirements.push(
|
|
14353
14803
|
processRequirement(head, "spawn", commandRedacted, ["process.docker_compose_run"])
|
|
14354
14804
|
);
|
|
14355
|
-
|
|
14356
|
-
|
|
14357
|
-
|
|
14358
|
-
|
|
14359
|
-
|
|
14360
|
-
|
|
14361
|
-
|
|
14362
|
-
|
|
14363
|
-
|
|
14364
|
-
(
|
|
14365
|
-
|
|
14366
|
-
|
|
14367
|
-
|
|
14368
|
-
signals.add(signal);
|
|
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);
|
|
14369
14820
|
}
|
|
14370
|
-
opacity = joinNestedOpacity(opacity, nestedSegment);
|
|
14371
14821
|
}
|
|
14372
14822
|
signals.add("process.docker_compose_run");
|
|
14373
14823
|
return shellSegment(commandRedacted, head, requirements, "recursive", signals);
|
|
14374
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
|
+
}
|
|
14375
14842
|
const launcher = resolveLauncherRecipe({
|
|
14376
14843
|
tokens,
|
|
14377
14844
|
cwd: context.cwd,
|
|
@@ -14583,7 +15050,7 @@ function isMetadataOnlyArgv(argv) {
|
|
|
14583
15050
|
return argv.length > 0 && argv.every((token) => METADATA_ONLY_FLAGS.has(token));
|
|
14584
15051
|
}
|
|
14585
15052
|
function executableBaseName(head) {
|
|
14586
|
-
return
|
|
15053
|
+
return path41.basename(head);
|
|
14587
15054
|
}
|
|
14588
15055
|
var RAILS_READ_ONLY_SUBCOMMANDS = /* @__PURE__ */ new Set(["routes", "middleware", "stats", "about", "version"]);
|
|
14589
15056
|
function railsReadOnlySubcommand(args) {
|
|
@@ -14594,7 +15061,7 @@ function railsReadOnlySubcommand(args) {
|
|
|
14594
15061
|
return RAILS_READ_ONLY_SUBCOMMANDS.has(subcommand);
|
|
14595
15062
|
}
|
|
14596
15063
|
function isRubyTestScript(scriptPath) {
|
|
14597
|
-
const base =
|
|
15064
|
+
const base = path41.basename(scriptPath);
|
|
14598
15065
|
return base.endsWith("_test.rb") || base.endsWith("_spec.rb");
|
|
14599
15066
|
}
|
|
14600
15067
|
function parseRubyTestInvocation(args) {
|
|
@@ -14779,7 +15246,7 @@ function decodeShellControlBuiltin(head, args) {
|
|
|
14779
15246
|
}
|
|
14780
15247
|
return null;
|
|
14781
15248
|
}
|
|
14782
|
-
function
|
|
15249
|
+
function decodeDockerComposeRun2(head, args, segment) {
|
|
14783
15250
|
let composeArgs = null;
|
|
14784
15251
|
let command = head;
|
|
14785
15252
|
if (head === "docker-compose") {
|
|
@@ -14873,7 +15340,7 @@ function decodeProcessOrFilesystem(params) {
|
|
|
14873
15340
|
requirement2(
|
|
14874
15341
|
"fs.read",
|
|
14875
15342
|
"fs.read",
|
|
14876
|
-
{ kind: "path", path:
|
|
15343
|
+
{ kind: "path", path: path41.resolve(cwd, syntax) },
|
|
14877
15344
|
segment,
|
|
14878
15345
|
["shell.syntax_source_read"]
|
|
14879
15346
|
)
|
|
@@ -14897,7 +15364,7 @@ function decodeProcessOrFilesystem(params) {
|
|
|
14897
15364
|
return decoded;
|
|
14898
15365
|
}
|
|
14899
15366
|
}
|
|
14900
|
-
const dockerCompose =
|
|
15367
|
+
const dockerCompose = decodeDockerComposeRun2(head, args, segment);
|
|
14901
15368
|
if (dockerCompose) {
|
|
14902
15369
|
return dockerCompose;
|
|
14903
15370
|
}
|
|
@@ -14923,7 +15390,7 @@ function decodeProcessOrFilesystem(params) {
|
|
|
14923
15390
|
return [processRequirement(head, "inspect", segment, ["process.inspect.base64_stdin"])];
|
|
14924
15391
|
}
|
|
14925
15392
|
if (head === "node") {
|
|
14926
|
-
return
|
|
15393
|
+
return decodeNode2(args, cwd, segment);
|
|
14927
15394
|
}
|
|
14928
15395
|
if (head === "vite" || head === "vite-node") {
|
|
14929
15396
|
return [processRequirement(head, "spawn", segment, ["process.local_dev_spawn"])];
|
|
@@ -15013,7 +15480,7 @@ function decodeBelay(args, repoRoot, segment) {
|
|
|
15013
15480
|
requirement2(
|
|
15014
15481
|
"control_plane.write",
|
|
15015
15482
|
"control_plane.write",
|
|
15016
|
-
{ kind: "path", path:
|
|
15483
|
+
{ kind: "path", path: path41.join(repoRoot, ".belay-control-plane") },
|
|
15017
15484
|
segment,
|
|
15018
15485
|
["belay.config_non_judge_mutation"]
|
|
15019
15486
|
)
|
|
@@ -15175,11 +15642,11 @@ function decodeRm(args, cwd, repoRoot, segment) {
|
|
|
15175
15642
|
function canonicalRmOperand(targetPath, finalOperandIsSymlink) {
|
|
15176
15643
|
try {
|
|
15177
15644
|
if (finalOperandIsSymlink) {
|
|
15178
|
-
return
|
|
15645
|
+
return path41.join(realpathSync4.native(path41.dirname(targetPath)), path41.basename(targetPath));
|
|
15179
15646
|
}
|
|
15180
15647
|
return realpathSync4.native(targetPath);
|
|
15181
15648
|
} catch {
|
|
15182
|
-
return
|
|
15649
|
+
return path41.resolve(targetPath);
|
|
15183
15650
|
}
|
|
15184
15651
|
}
|
|
15185
15652
|
function isSymbolicLink(targetPath) {
|
|
@@ -15190,8 +15657,8 @@ function isSymbolicLink(targetPath) {
|
|
|
15190
15657
|
}
|
|
15191
15658
|
}
|
|
15192
15659
|
function pathContains(ancestor, candidate) {
|
|
15193
|
-
const relative =
|
|
15194
|
-
return relative === "" || !relative.startsWith("..") && !
|
|
15660
|
+
const relative = path41.relative(path41.resolve(ancestor), path41.resolve(candidate));
|
|
15661
|
+
return relative === "" || !relative.startsWith("..") && !path41.isAbsolute(relative);
|
|
15195
15662
|
}
|
|
15196
15663
|
function decodeGo(args, segment) {
|
|
15197
15664
|
if (["test", "list", "vet"].includes(args[0] ?? "")) {
|
|
@@ -15337,7 +15804,7 @@ function decodeSed(args, cwd, segment) {
|
|
|
15337
15804
|
}
|
|
15338
15805
|
return lowered;
|
|
15339
15806
|
}
|
|
15340
|
-
function
|
|
15807
|
+
function decodeNode2(args, cwd, segment) {
|
|
15341
15808
|
if (args.length > 0 && args.every((arg) => ["--help", "--version", "-h", "-v"].includes(arg))) {
|
|
15342
15809
|
return [processRequirement("node", "inspect", segment, ["process.inspect.node_metadata"])];
|
|
15343
15810
|
}
|
|
@@ -15603,15 +16070,36 @@ function stripRedirects(tokens) {
|
|
|
15603
16070
|
stripped.push(token);
|
|
15604
16071
|
continue;
|
|
15605
16072
|
}
|
|
15606
|
-
|
|
15607
|
-
|
|
15608
|
-
|
|
15609
|
-
|
|
15610
|
-
|
|
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;
|
|
15611
16088
|
}
|
|
16089
|
+
index += 1;
|
|
15612
16090
|
}
|
|
15613
16091
|
return stripped;
|
|
15614
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
|
+
}
|
|
15615
16103
|
function shellSegment(commandRedacted, segmentHead, requirements, opacity, signals) {
|
|
15616
16104
|
const normalizedRequirements = requirements.flatMap((entry) => {
|
|
15617
16105
|
const dynamicSignal = dynamicResourceSignal(entry.resource);
|
|
@@ -16011,9 +16499,9 @@ function resolvePathOperand(operand, cwd) {
|
|
|
16011
16499
|
return process.env.HOME ?? operand;
|
|
16012
16500
|
}
|
|
16013
16501
|
if (operand.startsWith("~/")) {
|
|
16014
|
-
return
|
|
16502
|
+
return path41.join(process.env.HOME ?? "~", operand.slice(2));
|
|
16015
16503
|
}
|
|
16016
|
-
return
|
|
16504
|
+
return path41.resolve(cwd, operand);
|
|
16017
16505
|
}
|
|
16018
16506
|
function isShellHead(head) {
|
|
16019
16507
|
return head === "bash" || head === "sh" || head === "zsh" || head === "dash" || head === "fish";
|
|
@@ -16537,7 +17025,7 @@ async function classifyToolUse(payload, repoRoot, cwd, config, options = {}) {
|
|
|
16537
17025
|
};
|
|
16538
17026
|
}
|
|
16539
17027
|
const signals = [];
|
|
16540
|
-
const resolvedPath =
|
|
17028
|
+
const resolvedPath = path42.isAbsolute(filePath) ? filePath : path42.resolve(cwd, filePath);
|
|
16541
17029
|
const hitsProtectedRoot = protectedRoots.some((root) => pathWithinRoot(root, resolvedPath));
|
|
16542
17030
|
if (hitsProtectedRoot) {
|
|
16543
17031
|
signals.push("control_plane_path");
|
|
@@ -17139,7 +17627,7 @@ function hashDecisionConfig(config) {
|
|
|
17139
17627
|
init_fingerprint2();
|
|
17140
17628
|
|
|
17141
17629
|
// src/version.ts
|
|
17142
|
-
var PACKAGE_VERSION = "0.9.
|
|
17630
|
+
var PACKAGE_VERSION = "0.9.3";
|
|
17143
17631
|
|
|
17144
17632
|
// src/runtime-provenance.ts
|
|
17145
17633
|
function resolveRuntimeArtifactHash(artifactHash) {
|
|
@@ -17214,7 +17702,7 @@ init_path_utils();
|
|
|
17214
17702
|
import { randomUUID as randomUUID5 } from "node:crypto";
|
|
17215
17703
|
import { existsSync as existsSync15 } from "node:fs";
|
|
17216
17704
|
import { mkdir as mkdir11, readdir as readdir3, readFile as readFile12, rename as rename3, rm as rm6 } from "node:fs/promises";
|
|
17217
|
-
import
|
|
17705
|
+
import path47 from "node:path";
|
|
17218
17706
|
|
|
17219
17707
|
// src/core/recovery/artifact-store.ts
|
|
17220
17708
|
init_fingerprint2();
|
|
@@ -17222,7 +17710,7 @@ init_path_utils();
|
|
|
17222
17710
|
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
17223
17711
|
import { existsSync as existsSync13 } from "node:fs";
|
|
17224
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";
|
|
17225
|
-
import
|
|
17713
|
+
import path44 from "node:path";
|
|
17226
17714
|
|
|
17227
17715
|
// src/core/recovery/snapshot-node.ts
|
|
17228
17716
|
init_fingerprint2();
|
|
@@ -17242,25 +17730,25 @@ import {
|
|
|
17242
17730
|
symlink as symlink3,
|
|
17243
17731
|
writeFile as writeFile6
|
|
17244
17732
|
} from "node:fs/promises";
|
|
17245
|
-
import
|
|
17733
|
+
import path43 from "node:path";
|
|
17246
17734
|
var RECOVERY_UNSUPPORTED_FILE_KIND = "recovery_unsupported_file_kind";
|
|
17247
17735
|
function validRecoveryRelativePath(relativePath) {
|
|
17248
|
-
if (!relativePath || relativePath.includes("\0") ||
|
|
17249
|
-
const normalized =
|
|
17250
|
-
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}`);
|
|
17251
17739
|
}
|
|
17252
17740
|
async function assertRecoverySafeTarget(resourceRoot, relativePath) {
|
|
17253
17741
|
if (!validRecoveryRelativePath(relativePath)) throw new Error("recovery_path_escape");
|
|
17254
17742
|
const root = canonicalPath(resourceRoot);
|
|
17255
|
-
const target =
|
|
17256
|
-
const relative =
|
|
17257
|
-
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)) {
|
|
17258
17746
|
throw new Error("recovery_path_escape");
|
|
17259
17747
|
}
|
|
17260
17748
|
let current = root;
|
|
17261
|
-
const parentParts =
|
|
17749
|
+
const parentParts = path43.relative(root, path43.dirname(target)).split(path43.sep).filter(Boolean);
|
|
17262
17750
|
for (const part of parentParts) {
|
|
17263
|
-
current =
|
|
17751
|
+
current = path43.join(current, part);
|
|
17264
17752
|
if (!existsSync12(current)) break;
|
|
17265
17753
|
const info = await lstat6(current);
|
|
17266
17754
|
if (info.isSymbolicLink()) throw new Error("recovery_symlink_escape");
|
|
@@ -17316,7 +17804,7 @@ async function captureRecoverySnapshot(filePath, options) {
|
|
|
17316
17804
|
let blob;
|
|
17317
17805
|
if (options?.blobDir) {
|
|
17318
17806
|
await mkdir9(options.blobDir, { recursive: true, mode: 448 });
|
|
17319
|
-
const blobPath =
|
|
17807
|
+
const blobPath = path43.join(options.blobDir, hash);
|
|
17320
17808
|
if (!existsSync12(blobPath)) {
|
|
17321
17809
|
await writeFile6(blobPath, content, { mode: 384 });
|
|
17322
17810
|
await fsyncPath(blobPath);
|
|
@@ -17371,7 +17859,7 @@ async function validateRecoverySnapshot(params) {
|
|
|
17371
17859
|
if (record.blob !== `blobs/${record.hash}`) throw new Error(params.corruptReason);
|
|
17372
17860
|
let content;
|
|
17373
17861
|
try {
|
|
17374
|
-
content = await readFile8(
|
|
17862
|
+
content = await readFile8(path43.join(params.artifactDir, record.blob));
|
|
17375
17863
|
} catch {
|
|
17376
17864
|
throw new Error(params.corruptReason);
|
|
17377
17865
|
}
|
|
@@ -17399,13 +17887,13 @@ var RECOVERY_STATES = /* @__PURE__ */ new Set([
|
|
|
17399
17887
|
]);
|
|
17400
17888
|
var STAGING_STALE_MS = 5 * 6e4;
|
|
17401
17889
|
function checkpointsRoot(stateDir) {
|
|
17402
|
-
return
|
|
17890
|
+
return path44.join(stateDir, "recovery", "checkpoints");
|
|
17403
17891
|
}
|
|
17404
17892
|
function checkpointDir(stateDir, checkpointId) {
|
|
17405
17893
|
if (!/^cp_[a-f0-9]{24}$/.test(checkpointId)) {
|
|
17406
17894
|
throw new Error("invalid_recovery_checkpoint_id");
|
|
17407
17895
|
}
|
|
17408
|
-
return
|
|
17896
|
+
return path44.join(checkpointsRoot(stateDir), checkpointId);
|
|
17409
17897
|
}
|
|
17410
17898
|
async function fsyncPath2(filePath) {
|
|
17411
17899
|
const handle = await open5(filePath, "r");
|
|
@@ -17416,13 +17904,13 @@ async function fsyncPath2(filePath) {
|
|
|
17416
17904
|
}
|
|
17417
17905
|
}
|
|
17418
17906
|
async function atomicWriteJson(filePath, value) {
|
|
17419
|
-
await mkdir10(
|
|
17907
|
+
await mkdir10(path44.dirname(filePath), { recursive: true, mode: 448 });
|
|
17420
17908
|
const temporary = `${filePath}.tmp-${randomUUID4()}`;
|
|
17421
17909
|
await writeFile7(temporary, `${JSON.stringify(value, null, 2)}
|
|
17422
17910
|
`, { mode: 384 });
|
|
17423
17911
|
await fsyncPath2(temporary);
|
|
17424
17912
|
await rename2(temporary, filePath);
|
|
17425
|
-
await fsyncPath2(
|
|
17913
|
+
await fsyncPath2(path44.dirname(filePath));
|
|
17426
17914
|
}
|
|
17427
17915
|
async function writeRecoveryState(artifactDir, state, manifestHash, detail) {
|
|
17428
17916
|
const value = {
|
|
@@ -17432,13 +17920,13 @@ async function writeRecoveryState(artifactDir, state, manifestHash, detail) {
|
|
|
17432
17920
|
manifestHash,
|
|
17433
17921
|
...detail ? { detail } : {}
|
|
17434
17922
|
};
|
|
17435
|
-
await atomicWriteJson(
|
|
17923
|
+
await atomicWriteJson(path44.join(artifactDir, "state.json"), value);
|
|
17436
17924
|
}
|
|
17437
17925
|
async function directorySize(root) {
|
|
17438
17926
|
if (!existsSync13(root)) return 0;
|
|
17439
17927
|
let total = 0;
|
|
17440
17928
|
for (const entry of await readdir2(root, { withFileTypes: true })) {
|
|
17441
|
-
const entryPath =
|
|
17929
|
+
const entryPath = path44.join(root, entry.name);
|
|
17442
17930
|
if (entry.isDirectory()) total += await directorySize(entryPath);
|
|
17443
17931
|
else total += (await lstat7(entryPath)).size;
|
|
17444
17932
|
}
|
|
@@ -17483,9 +17971,9 @@ async function readRecoveryArtifact(stateDir, checkpointId) {
|
|
|
17483
17971
|
let rawManifest;
|
|
17484
17972
|
let state;
|
|
17485
17973
|
try {
|
|
17486
|
-
rawManifest = JSON.parse(await readFile9(
|
|
17974
|
+
rawManifest = JSON.parse(await readFile9(path44.join(artifactDir, "manifest.json"), "utf8"));
|
|
17487
17975
|
state = JSON.parse(
|
|
17488
|
-
await readFile9(
|
|
17976
|
+
await readFile9(path44.join(artifactDir, "state.json"), "utf8")
|
|
17489
17977
|
);
|
|
17490
17978
|
} catch {
|
|
17491
17979
|
throw new Error(RECOVERY_CHECKPOINT_CORRUPT);
|
|
@@ -17501,10 +17989,10 @@ async function readRecoveryArtifact(stateDir, checkpointId) {
|
|
|
17501
17989
|
}
|
|
17502
17990
|
const entryPaths = /* @__PURE__ */ new Set();
|
|
17503
17991
|
for (const entry of manifest.entries) {
|
|
17504
|
-
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))) {
|
|
17505
17993
|
throw new Error(RECOVERY_CHECKPOINT_CORRUPT);
|
|
17506
17994
|
}
|
|
17507
|
-
entryPaths.add(
|
|
17995
|
+
entryPaths.add(path44.normalize(entry.path));
|
|
17508
17996
|
for (const [side, snapshot] of [
|
|
17509
17997
|
["before", entry.before],
|
|
17510
17998
|
["after", entry.after]
|
|
@@ -17518,7 +18006,7 @@ async function readRecoveryArtifact(stateDir, checkpointId) {
|
|
|
17518
18006
|
});
|
|
17519
18007
|
}
|
|
17520
18008
|
}
|
|
17521
|
-
const receiptPath =
|
|
18009
|
+
const receiptPath = path44.join(artifactDir, "receipt.json");
|
|
17522
18010
|
let receipt;
|
|
17523
18011
|
if (["applied", "restoring", "restored", "conflict"].includes(state.state) || existsSync13(receiptPath)) {
|
|
17524
18012
|
receipt = await readAndValidateRecoveryReceipt(artifactDir, manifest, manifestHash);
|
|
@@ -17528,7 +18016,7 @@ async function readRecoveryArtifact(stateDir, checkpointId) {
|
|
|
17528
18016
|
async function readAndValidateRecoveryReceipt(artifactDir, manifest, manifestHash) {
|
|
17529
18017
|
let rawReceipt;
|
|
17530
18018
|
try {
|
|
17531
|
-
rawReceipt = JSON.parse(await readFile9(
|
|
18019
|
+
rawReceipt = JSON.parse(await readFile9(path44.join(artifactDir, "receipt.json"), "utf8"));
|
|
17532
18020
|
} catch {
|
|
17533
18021
|
throw new Error(RECOVERY_CHECKPOINT_CORRUPT);
|
|
17534
18022
|
}
|
|
@@ -17551,7 +18039,7 @@ async function readAndValidateRecoveryReceipt(artifactDir, manifest, manifestHas
|
|
|
17551
18039
|
return receipt;
|
|
17552
18040
|
}
|
|
17553
18041
|
async function ensureRecoveryReceipt(artifactDir, manifest, manifestHash) {
|
|
17554
|
-
const receiptPath =
|
|
18042
|
+
const receiptPath = path44.join(artifactDir, "receipt.json");
|
|
17555
18043
|
if (existsSync13(receiptPath)) {
|
|
17556
18044
|
return readAndValidateRecoveryReceipt(artifactDir, manifest, manifestHash);
|
|
17557
18045
|
}
|
|
@@ -17576,7 +18064,7 @@ async function artifactRepoRoot(stateDir, checkpointId) {
|
|
|
17576
18064
|
const artifactDir = checkpointDir(stateDir, checkpointId);
|
|
17577
18065
|
try {
|
|
17578
18066
|
const manifest = JSON.parse(
|
|
17579
|
-
await readFile9(
|
|
18067
|
+
await readFile9(path44.join(artifactDir, "manifest.json"), "utf8")
|
|
17580
18068
|
);
|
|
17581
18069
|
if (typeof manifest.repoRoot === "string" && manifest.repoRoot) {
|
|
17582
18070
|
return canonicalPath(manifest.repoRoot);
|
|
@@ -17584,7 +18072,7 @@ async function artifactRepoRoot(stateDir, checkpointId) {
|
|
|
17584
18072
|
} catch {
|
|
17585
18073
|
}
|
|
17586
18074
|
try {
|
|
17587
|
-
const owner = JSON.parse(await readFile9(
|
|
18075
|
+
const owner = JSON.parse(await readFile9(path44.join(artifactDir, "owner.json"), "utf8"));
|
|
17588
18076
|
return typeof owner.repoRoot === "string" && owner.repoRoot ? canonicalPath(owner.repoRoot) : null;
|
|
17589
18077
|
} catch {
|
|
17590
18078
|
return null;
|
|
@@ -17604,10 +18092,10 @@ async function cleanupOrphanedStaging(stateDir) {
|
|
|
17604
18092
|
const now = Date.now();
|
|
17605
18093
|
for (const entry of await readdir2(root, { withFileTypes: true })) {
|
|
17606
18094
|
if (!entry.isDirectory() || !/^\.tmp-cp_[a-f0-9]{24}$/.test(entry.name)) continue;
|
|
17607
|
-
const stagingPath =
|
|
18095
|
+
const stagingPath = path44.join(root, entry.name);
|
|
17608
18096
|
let stale = false;
|
|
17609
18097
|
try {
|
|
17610
|
-
const owner = JSON.parse(await readFile9(
|
|
18098
|
+
const owner = JSON.parse(await readFile9(path44.join(stagingPath, "owner.json"), "utf8"));
|
|
17611
18099
|
const pid = typeof owner.pid === "number" ? owner.pid : Number.NaN;
|
|
17612
18100
|
const createdAt = typeof owner.createdAt === "string" ? Date.parse(owner.createdAt) : NaN;
|
|
17613
18101
|
let alive = false;
|
|
@@ -17649,7 +18137,7 @@ async function markRecoveryCheckpointApplied(stateDir, checkpoint) {
|
|
|
17649
18137
|
init_fingerprint2();
|
|
17650
18138
|
import { existsSync as existsSync14 } from "node:fs";
|
|
17651
18139
|
import { readFile as readFile10 } from "node:fs/promises";
|
|
17652
|
-
import
|
|
18140
|
+
import path45 from "node:path";
|
|
17653
18141
|
async function matchRecoverySide(resourceRoot, entries, side) {
|
|
17654
18142
|
for (const entry of entries) {
|
|
17655
18143
|
const target = await assertRecoverySafeTarget(resourceRoot, entry.path);
|
|
@@ -17664,7 +18152,7 @@ async function reconcileRecoveryCheckpoint(stateDir, checkpointId) {
|
|
|
17664
18152
|
} catch {
|
|
17665
18153
|
const artifactDir = checkpointDir(stateDir, checkpointId);
|
|
17666
18154
|
if (existsSync14(artifactDir)) {
|
|
17667
|
-
const manifestPath =
|
|
18155
|
+
const manifestPath = path45.join(artifactDir, "manifest.json");
|
|
17668
18156
|
const hash = existsSync14(manifestPath) ? hashValue(await readFile10(manifestPath, "utf8")) : "unavailable";
|
|
17669
18157
|
await writeRecoveryState(artifactDir, "corrupt", hash, RECOVERY_CHECKPOINT_CORRUPT);
|
|
17670
18158
|
}
|
|
@@ -17701,7 +18189,7 @@ async function reconcileRecoveryCheckpoint(stateDir, checkpointId) {
|
|
|
17701
18189
|
// src/core/recovery/resource-identity.ts
|
|
17702
18190
|
init_fingerprint2();
|
|
17703
18191
|
import { lstat as lstat8, readFile as readFile11, realpath as realpath3 } from "node:fs/promises";
|
|
17704
|
-
import
|
|
18192
|
+
import path46 from "node:path";
|
|
17705
18193
|
async function currentRecoveryResourceIdentity(resourceRoot, resourceKind) {
|
|
17706
18194
|
const resolvedRoot = await realpath3(resourceRoot);
|
|
17707
18195
|
if (resourceKind === "directory") {
|
|
@@ -17709,13 +18197,13 @@ async function currentRecoveryResourceIdentity(resourceRoot, resourceKind) {
|
|
|
17709
18197
|
if (!rootInfo.isDirectory()) throw new Error("recovery_repo_identity_unavailable");
|
|
17710
18198
|
return hashValue(`${resolvedRoot}\0${rootInfo.dev}:${rootInfo.ino}:${rootInfo.birthtimeMs}`);
|
|
17711
18199
|
}
|
|
17712
|
-
const dotGit =
|
|
18200
|
+
const dotGit = path46.join(resolvedRoot, ".git");
|
|
17713
18201
|
const gitInfo = await lstat8(dotGit);
|
|
17714
18202
|
let gitMetadataPath = dotGit;
|
|
17715
18203
|
if (gitInfo.isFile()) {
|
|
17716
18204
|
const marker = (await readFile11(dotGit, "utf8")).trim();
|
|
17717
18205
|
if (!marker.startsWith("gitdir:")) throw new Error("recovery_repo_identity_unavailable");
|
|
17718
|
-
gitMetadataPath =
|
|
18206
|
+
gitMetadataPath = path46.resolve(resolvedRoot, marker.slice("gitdir:".length).trim());
|
|
17719
18207
|
} else if (!gitInfo.isDirectory()) {
|
|
17720
18208
|
throw new Error("recovery_repo_identity_unavailable");
|
|
17721
18209
|
}
|
|
@@ -17788,16 +18276,16 @@ async function prepareRecoveryCheckpoint(params) {
|
|
|
17788
18276
|
throw new Error(RECOVERY_CHECKPOINT_QUOTA);
|
|
17789
18277
|
}
|
|
17790
18278
|
const checkpointId = `cp_${randomUUID5().replaceAll("-", "").slice(0, 24)}`;
|
|
17791
|
-
const temporary =
|
|
18279
|
+
const temporary = path47.join(checkpointsRoot(params.stateDir), `.tmp-${checkpointId}`);
|
|
17792
18280
|
const finalDir = checkpointDir(params.stateDir, checkpointId);
|
|
17793
18281
|
await mkdir11(temporary, { recursive: true, mode: 448 });
|
|
17794
|
-
await atomicWriteJson(
|
|
18282
|
+
await atomicWriteJson(path47.join(temporary, "owner.json"), {
|
|
17795
18283
|
version: 1,
|
|
17796
18284
|
pid: process.pid,
|
|
17797
18285
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
17798
18286
|
repoRoot: canonicalPath(params.repoRoot)
|
|
17799
18287
|
});
|
|
17800
|
-
await mkdir11(
|
|
18288
|
+
await mkdir11(path47.join(temporary, "blobs"), { recursive: true, mode: 448 });
|
|
17801
18289
|
try {
|
|
17802
18290
|
const entries = [];
|
|
17803
18291
|
const protectedRoots = (params.protectedRoots ?? []).map(canonicalPath);
|
|
@@ -17806,8 +18294,8 @@ async function prepareRecoveryCheckpoint(params) {
|
|
|
17806
18294
|
)) {
|
|
17807
18295
|
const target = await assertRecoverySafeTarget(params.repoRoot, change.relativePath);
|
|
17808
18296
|
if (protectedRoots.some((root) => {
|
|
17809
|
-
const relative =
|
|
17810
|
-
return relative === "" || relative !== ".." && !relative.startsWith(`..${
|
|
18297
|
+
const relative = path47.relative(root, target);
|
|
18298
|
+
return relative === "" || relative !== ".." && !relative.startsWith(`..${path47.sep}`) && !path47.isAbsolute(relative);
|
|
17811
18299
|
})) {
|
|
17812
18300
|
throw new Error("recovery_protected_path");
|
|
17813
18301
|
}
|
|
@@ -17819,7 +18307,7 @@ async function prepareRecoveryCheckpoint(params) {
|
|
|
17819
18307
|
entries.push({
|
|
17820
18308
|
path: change.relativePath,
|
|
17821
18309
|
before: await captureRecoverySnapshot(baseline, {
|
|
17822
|
-
blobDir:
|
|
18310
|
+
blobDir: path47.join(temporary, "blobs")
|
|
17823
18311
|
}),
|
|
17824
18312
|
after: withoutRecoveryBlob(await captureRecoverySnapshot(source))
|
|
17825
18313
|
});
|
|
@@ -17856,7 +18344,7 @@ async function prepareRecoveryCheckpoint(params) {
|
|
|
17856
18344
|
entries
|
|
17857
18345
|
};
|
|
17858
18346
|
const manifestHash = hashValue(canonicalStringify(manifest));
|
|
17859
|
-
await atomicWriteJson(
|
|
18347
|
+
await atomicWriteJson(path47.join(temporary, "manifest.json"), manifest);
|
|
17860
18348
|
await writeRecoveryState(temporary, "prepared", manifestHash);
|
|
17861
18349
|
await fsyncPath2(temporary);
|
|
17862
18350
|
const projectedBytes = await recoveryCheckpointStorageBytes(params.stateDir, params.repoRoot);
|
|
@@ -17899,7 +18387,7 @@ async function listRecoveryCheckpoints(stateDir, repoRoot) {
|
|
|
17899
18387
|
} catch {
|
|
17900
18388
|
try {
|
|
17901
18389
|
const raw = JSON.parse(
|
|
17902
|
-
await readFile12(
|
|
18390
|
+
await readFile12(path47.join(checkpointDir(stateDir, id), "manifest.json"), "utf8")
|
|
17903
18391
|
);
|
|
17904
18392
|
rootFromArtifact = typeof raw.repoRoot === "string" && raw.repoRoot ? raw.repoRoot : void 0;
|
|
17905
18393
|
} catch {
|
|
@@ -17933,7 +18421,7 @@ async function listRecoveryCheckpoints(stateDir, repoRoot) {
|
|
|
17933
18421
|
} catch {
|
|
17934
18422
|
try {
|
|
17935
18423
|
const manifest = JSON.parse(
|
|
17936
|
-
await readFile12(
|
|
18424
|
+
await readFile12(path47.join(checkpointDir(stateDir, id), "manifest.json"), "utf8")
|
|
17937
18425
|
);
|
|
17938
18426
|
if (manifest.checkpointId !== id || ![1, 2].includes(manifest.version)) continue;
|
|
17939
18427
|
if (repoRoot && canonicalPath(manifest.repoRoot) !== canonicalPath(repoRoot)) continue;
|
|
@@ -17963,7 +18451,7 @@ async function recoveryCheckpointStorageBytes(stateDir, repoRoot) {
|
|
|
17963
18451
|
let total = 0;
|
|
17964
18452
|
for (const entry of await readdir3(root, { withFileTypes: true })) {
|
|
17965
18453
|
if (!entry.isDirectory()) continue;
|
|
17966
|
-
const entryPath =
|
|
18454
|
+
const entryPath = path47.join(root, entry.name);
|
|
17967
18455
|
if (/^cp_[a-f0-9]{24}$/.test(entry.name)) {
|
|
17968
18456
|
if (await artifactRepoRoot(stateDir, entry.name) === expected) {
|
|
17969
18457
|
total += await directorySize(entryPath);
|
|
@@ -17972,7 +18460,7 @@ async function recoveryCheckpointStorageBytes(stateDir, repoRoot) {
|
|
|
17972
18460
|
}
|
|
17973
18461
|
if (/^\.tmp-cp_[a-f0-9]{24}$/.test(entry.name)) {
|
|
17974
18462
|
try {
|
|
17975
|
-
const owner = JSON.parse(await readFile12(
|
|
18463
|
+
const owner = JSON.parse(await readFile12(path47.join(entryPath, "owner.json"), "utf8"));
|
|
17976
18464
|
if (typeof owner.repoRoot === "string" && canonicalPath(owner.repoRoot) === expected) {
|
|
17977
18465
|
total += await directorySize(entryPath);
|
|
17978
18466
|
}
|
|
@@ -18016,14 +18504,14 @@ init_scrub();
|
|
|
18016
18504
|
// src/core/transactional/file-checkpoint-backend.ts
|
|
18017
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";
|
|
18018
18506
|
import os5 from "node:os";
|
|
18019
|
-
import
|
|
18507
|
+
import path51 from "node:path";
|
|
18020
18508
|
|
|
18021
18509
|
// src/core/transactional/file-checkpoint-git.ts
|
|
18022
18510
|
init_path_utils();
|
|
18023
18511
|
import { spawn as spawn8 } from "node:child_process";
|
|
18024
18512
|
import { createHash as createHash13 } from "node:crypto";
|
|
18025
18513
|
import { copyFile as copyFile3, lstat as lstat9, readdir as readdir4, readFile as readFile13 } from "node:fs/promises";
|
|
18026
|
-
import
|
|
18514
|
+
import path48 from "node:path";
|
|
18027
18515
|
var FILE_CHECKPOINT_GIT_METADATA_CHANGED = "file_checkpoint_git_metadata_changed";
|
|
18028
18516
|
var FILE_CHECKPOINT_SOURCE_CHANGED = "file_checkpoint_source_changed";
|
|
18029
18517
|
var FILE_CHECKPOINT_CWD_OUTSIDE_ROOT = "file_checkpoint_cwd_outside_root";
|
|
@@ -18057,7 +18545,7 @@ function rethrowStableFileCheckpointError(error) {
|
|
|
18057
18545
|
}
|
|
18058
18546
|
async function rootGitMetadataPresent(repoRoot) {
|
|
18059
18547
|
try {
|
|
18060
|
-
await lstat9(
|
|
18548
|
+
await lstat9(path48.join(repoRoot, ".git"));
|
|
18061
18549
|
return true;
|
|
18062
18550
|
} catch {
|
|
18063
18551
|
return false;
|
|
@@ -18106,10 +18594,10 @@ function execGit2(repoRoot, args) {
|
|
|
18106
18594
|
}
|
|
18107
18595
|
async function resolveGitPath(repoRoot, gitPath) {
|
|
18108
18596
|
const trimmed = gitPath.trim();
|
|
18109
|
-
if (
|
|
18597
|
+
if (path48.isAbsolute(trimmed)) {
|
|
18110
18598
|
return trimmed;
|
|
18111
18599
|
}
|
|
18112
|
-
return
|
|
18600
|
+
return path48.join(repoRoot, trimmed);
|
|
18113
18601
|
}
|
|
18114
18602
|
async function cloneBareWorktreeCopy(sourceRoot, destinationRoot) {
|
|
18115
18603
|
await execGit2(sourceRoot, [
|
|
@@ -18151,7 +18639,7 @@ async function copyGitIndexState(sourceRoot, destinationRoot) {
|
|
|
18151
18639
|
destinationRoot,
|
|
18152
18640
|
await execGit2(destinationRoot, ["rev-parse", "--git-dir"])
|
|
18153
18641
|
);
|
|
18154
|
-
const destinationShared =
|
|
18642
|
+
const destinationShared = path48.join(destinationGitDir, path48.basename(sourceShared));
|
|
18155
18643
|
try {
|
|
18156
18644
|
await copyFile3(sourceShared, destinationShared);
|
|
18157
18645
|
} catch (error) {
|
|
@@ -18160,7 +18648,7 @@ async function copyGitIndexState(sourceRoot, destinationRoot) {
|
|
|
18160
18648
|
}
|
|
18161
18649
|
async function readGitFile(gitDir, relativePath) {
|
|
18162
18650
|
try {
|
|
18163
|
-
return await readFile13(
|
|
18651
|
+
return await readFile13(path48.join(gitDir, relativePath));
|
|
18164
18652
|
} catch {
|
|
18165
18653
|
return null;
|
|
18166
18654
|
}
|
|
@@ -18184,8 +18672,8 @@ async function hashResolvedGitPath(repoRoot, gitDir, gitPath, hash) {
|
|
|
18184
18672
|
repoRoot,
|
|
18185
18673
|
await execGit2(repoRoot, ["rev-parse", "--git-path", gitPath])
|
|
18186
18674
|
);
|
|
18187
|
-
const relative =
|
|
18188
|
-
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);
|
|
18189
18677
|
if (content !== null) {
|
|
18190
18678
|
hashGitFileContent(hash, gitPath, content);
|
|
18191
18679
|
}
|
|
@@ -18195,13 +18683,13 @@ async function hashResolvedGitPath(repoRoot, gitDir, gitPath, hash) {
|
|
|
18195
18683
|
async function hashGitTree(gitDir, relativeDir, hash) {
|
|
18196
18684
|
let names;
|
|
18197
18685
|
try {
|
|
18198
|
-
names = await readdir4(
|
|
18686
|
+
names = await readdir4(path48.join(gitDir, relativeDir));
|
|
18199
18687
|
} catch {
|
|
18200
18688
|
return;
|
|
18201
18689
|
}
|
|
18202
18690
|
for (const name of names.sort()) {
|
|
18203
|
-
const relativePath = relativeDir ?
|
|
18204
|
-
const absolutePath =
|
|
18691
|
+
const relativePath = relativeDir ? path48.join(relativeDir, name) : name;
|
|
18692
|
+
const absolutePath = path48.join(gitDir, relativePath);
|
|
18205
18693
|
let childNames = null;
|
|
18206
18694
|
try {
|
|
18207
18695
|
childNames = await readdir4(absolutePath);
|
|
@@ -18223,7 +18711,7 @@ async function hashGitTree(gitDir, relativeDir, hash) {
|
|
|
18223
18711
|
}
|
|
18224
18712
|
async function computeGitMetadataFingerprint(repoRoot) {
|
|
18225
18713
|
const gitDirRel = (await execGit2(repoRoot, ["rev-parse", "--git-dir"])).trim();
|
|
18226
|
-
const gitDir =
|
|
18714
|
+
const gitDir = path48.isAbsolute(gitDirRel) ? gitDirRel : path48.join(repoRoot, gitDirRel);
|
|
18227
18715
|
const hash = createHash13("sha256");
|
|
18228
18716
|
for (const file of [
|
|
18229
18717
|
"HEAD",
|
|
@@ -18246,8 +18734,8 @@ async function computeGitMetadataFingerprint(repoRoot) {
|
|
|
18246
18734
|
const sharedIndex = (await execGit2(repoRoot, ["rev-parse", "--shared-index-path"])).trim();
|
|
18247
18735
|
if (sharedIndex) {
|
|
18248
18736
|
const resolved = await resolveGitPath(repoRoot, sharedIndex);
|
|
18249
|
-
const relative =
|
|
18250
|
-
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);
|
|
18251
18739
|
if (content !== null) {
|
|
18252
18740
|
hashGitFileContent(hash, "shared-index", content);
|
|
18253
18741
|
}
|
|
@@ -18258,7 +18746,7 @@ async function computeGitMetadataFingerprint(repoRoot) {
|
|
|
18258
18746
|
await hashResolvedGitPath(repoRoot, gitDir, gitPath, hash);
|
|
18259
18747
|
}
|
|
18260
18748
|
try {
|
|
18261
|
-
const rootGitPath =
|
|
18749
|
+
const rootGitPath = path48.join(repoRoot, ".git");
|
|
18262
18750
|
const rootGitInfo = await lstat9(rootGitPath);
|
|
18263
18751
|
if (rootGitInfo.isFile()) {
|
|
18264
18752
|
const content = await readAbsoluteGitFile(rootGitPath);
|
|
@@ -18274,14 +18762,14 @@ async function computeGitMetadataFingerprint(repoRoot) {
|
|
|
18274
18762
|
function resolveExecutionCwdRelative(resourceRoot, cwd) {
|
|
18275
18763
|
const resolvedCwd = canonicalPath(cwd);
|
|
18276
18764
|
const resourceCanonical = canonicalPath(resourceRoot);
|
|
18277
|
-
const relative =
|
|
18765
|
+
const relative = path48.relative(resourceCanonical, resolvedCwd);
|
|
18278
18766
|
if (relative === "" || relative === ".") {
|
|
18279
18767
|
return "";
|
|
18280
18768
|
}
|
|
18281
|
-
if (relative.startsWith("..") ||
|
|
18769
|
+
if (relative.startsWith("..") || path48.isAbsolute(relative)) {
|
|
18282
18770
|
throw new Error(FILE_CHECKPOINT_CWD_OUTSIDE_ROOT);
|
|
18283
18771
|
}
|
|
18284
|
-
return relative.split(
|
|
18772
|
+
return relative.split(path48.sep).join("/");
|
|
18285
18773
|
}
|
|
18286
18774
|
|
|
18287
18775
|
// src/core/transactional/file-checkpoint-isolation.ts
|
|
@@ -18303,7 +18791,7 @@ function fileCheckpointIsolationReason(context) {
|
|
|
18303
18791
|
|
|
18304
18792
|
// src/core/transactional/file-checkpoint-staging.ts
|
|
18305
18793
|
import { readdir as readdir5, readFile as readFile14, rm as rm7, writeFile as writeFile8 } from "node:fs/promises";
|
|
18306
|
-
import
|
|
18794
|
+
import path49 from "node:path";
|
|
18307
18795
|
function isOwnerProcessAlive(pid) {
|
|
18308
18796
|
try {
|
|
18309
18797
|
process.kill(pid, 0);
|
|
@@ -18313,12 +18801,12 @@ function isOwnerProcessAlive(pid) {
|
|
|
18313
18801
|
}
|
|
18314
18802
|
}
|
|
18315
18803
|
async function writeOwnerMarker(stagingRoot, marker) {
|
|
18316
|
-
await writeFile8(
|
|
18804
|
+
await writeFile8(path49.join(stagingRoot, "owner.json"), `${JSON.stringify(marker)}
|
|
18317
18805
|
`, "utf8");
|
|
18318
18806
|
}
|
|
18319
18807
|
async function readOwnerMarker(stagingRoot) {
|
|
18320
18808
|
try {
|
|
18321
|
-
const raw = await readFile14(
|
|
18809
|
+
const raw = await readFile14(path49.join(stagingRoot, "owner.json"), "utf8");
|
|
18322
18810
|
return JSON.parse(raw.trim());
|
|
18323
18811
|
} catch {
|
|
18324
18812
|
return null;
|
|
@@ -18336,7 +18824,7 @@ async function collectDeadOwnerStaging(parentDir) {
|
|
|
18336
18824
|
if (!name.startsWith("belay-file-checkpoint-")) {
|
|
18337
18825
|
continue;
|
|
18338
18826
|
}
|
|
18339
|
-
const stagingRoot =
|
|
18827
|
+
const stagingRoot = path49.join(parentDir, name);
|
|
18340
18828
|
const marker = await readOwnerMarker(stagingRoot);
|
|
18341
18829
|
if (!marker) {
|
|
18342
18830
|
dead.push(stagingRoot);
|
|
@@ -18368,7 +18856,7 @@ import {
|
|
|
18368
18856
|
writeFile as writeFile9
|
|
18369
18857
|
} from "node:fs/promises";
|
|
18370
18858
|
import os4 from "node:os";
|
|
18371
|
-
import
|
|
18859
|
+
import path50 from "node:path";
|
|
18372
18860
|
var FILE_CHECKPOINT_COPY_FAILED = "file_checkpoint_copy_failed";
|
|
18373
18861
|
async function chmodSafe2(target, mode) {
|
|
18374
18862
|
try {
|
|
@@ -18378,7 +18866,7 @@ async function chmodSafe2(target, mode) {
|
|
|
18378
18866
|
}
|
|
18379
18867
|
}
|
|
18380
18868
|
async function copyRegularFile(sourcePath, destinationPath, mode, strategy) {
|
|
18381
|
-
await mkdir12(
|
|
18869
|
+
await mkdir12(path50.dirname(destinationPath), { recursive: true });
|
|
18382
18870
|
if (strategy === "clonefile" && fsConstants2.COPYFILE_FICLONE !== void 0) {
|
|
18383
18871
|
try {
|
|
18384
18872
|
await copyFile4(sourcePath, destinationPath, fsConstants2.COPYFILE_FICLONE);
|
|
@@ -18404,7 +18892,7 @@ async function copyNode(sourceRoot, destinationRoot, relativePath, strategy) {
|
|
|
18404
18892
|
return strategy;
|
|
18405
18893
|
}
|
|
18406
18894
|
if (info.isSymbolicLink()) {
|
|
18407
|
-
await mkdir12(
|
|
18895
|
+
await mkdir12(path50.dirname(destinationPath), { recursive: true });
|
|
18408
18896
|
await symlink4(await readlink5(sourcePath), destinationPath);
|
|
18409
18897
|
return strategy;
|
|
18410
18898
|
}
|
|
@@ -18460,9 +18948,9 @@ async function mapWithConcurrency(items, concurrency, worker) {
|
|
|
18460
18948
|
async function probeFileCloneStrategy() {
|
|
18461
18949
|
let tempDir = null;
|
|
18462
18950
|
try {
|
|
18463
|
-
tempDir = await mkdtemp4(
|
|
18464
|
-
const source =
|
|
18465
|
-
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");
|
|
18466
18954
|
await writeFile9(source, "probe\n");
|
|
18467
18955
|
if (fsConstants2.COPYFILE_FICLONE_FORCE !== void 0) {
|
|
18468
18956
|
try {
|
|
@@ -18615,11 +19103,11 @@ async function protectedRootState(root) {
|
|
|
18615
19103
|
return `directory:${node.hash}:${index.treeHash}`;
|
|
18616
19104
|
}
|
|
18617
19105
|
function executionProtectedRoot(resourceRoot, executionRoot, protectedRoot) {
|
|
18618
|
-
const relative =
|
|
18619
|
-
if (relative === "" || relative.startsWith("..") ||
|
|
19106
|
+
const relative = path51.relative(path51.resolve(resourceRoot), path51.resolve(protectedRoot));
|
|
19107
|
+
if (relative === "" || relative.startsWith("..") || path51.isAbsolute(relative)) {
|
|
18620
19108
|
return null;
|
|
18621
19109
|
}
|
|
18622
|
-
return
|
|
19110
|
+
return path51.join(executionRoot, relative);
|
|
18623
19111
|
}
|
|
18624
19112
|
async function captureProtectedRootStates(resourceRoot, executionRoot, protectedRoots) {
|
|
18625
19113
|
const states = /* @__PURE__ */ new Map();
|
|
@@ -18644,15 +19132,15 @@ async function directoryByteSize(root, deadlineMs) {
|
|
|
18644
19132
|
}
|
|
18645
19133
|
let total = 0;
|
|
18646
19134
|
for (const name of await readdir6(root)) {
|
|
18647
|
-
total += await directoryByteSize(
|
|
19135
|
+
total += await directoryByteSize(path51.join(root, name), deadlineMs);
|
|
18648
19136
|
}
|
|
18649
19137
|
return total;
|
|
18650
19138
|
}
|
|
18651
19139
|
async function copyGitMetadataDirectory(sourceRoot, destinationRoot) {
|
|
18652
19140
|
const gitDirRel = (await execGit2(sourceRoot, ["rev-parse", "--git-dir"])).trim();
|
|
18653
|
-
const sourceGitDir =
|
|
18654
|
-
const relativeGitDir =
|
|
18655
|
-
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");
|
|
18656
19144
|
await cp(sourceGitDir, destinationGitDir, { recursive: true, force: true });
|
|
18657
19145
|
}
|
|
18658
19146
|
async function prepareDirtyGitSnapshot(context) {
|
|
@@ -18661,7 +19149,7 @@ async function prepareDirtyGitSnapshot(context) {
|
|
|
18661
19149
|
const quotas = context.fileCheckpoint;
|
|
18662
19150
|
const deadlineMs = Date.now() + quotas.prepareTimeoutMs;
|
|
18663
19151
|
await removeDeadOwnerStaging(os5.tmpdir());
|
|
18664
|
-
const stagingRoot = await mkdtemp5(
|
|
19152
|
+
const stagingRoot = await mkdtemp5(path51.join(os5.tmpdir(), "belay-file-checkpoint-"));
|
|
18665
19153
|
await writeOwnerMarker(stagingRoot, {
|
|
18666
19154
|
version: 1,
|
|
18667
19155
|
pid: process.pid,
|
|
@@ -18669,8 +19157,8 @@ async function prepareDirtyGitSnapshot(context) {
|
|
|
18669
19157
|
resourceRoot: context.repoRoot,
|
|
18670
19158
|
backend: "file_checkpoint"
|
|
18671
19159
|
});
|
|
18672
|
-
const baselineRoot =
|
|
18673
|
-
const executionRoot =
|
|
19160
|
+
const baselineRoot = path51.join(stagingRoot, "baseline");
|
|
19161
|
+
const executionRoot = path51.join(stagingRoot, "execution");
|
|
18674
19162
|
try {
|
|
18675
19163
|
resolveExecutionCwdRelative(context.repoRoot, context.cwd);
|
|
18676
19164
|
const sourceGitMetadataFingerprint = await computeGitMetadataFingerprint(context.repoRoot);
|
|
@@ -18704,7 +19192,7 @@ async function prepareDirtyGitSnapshot(context) {
|
|
|
18704
19192
|
throw new Error(FILE_CHECKPOINT_SOURCE_CHANGED);
|
|
18705
19193
|
}
|
|
18706
19194
|
await writeFile10(
|
|
18707
|
-
|
|
19195
|
+
path51.join(stagingRoot, "baseline-index.json"),
|
|
18708
19196
|
`${JSON.stringify(baselineIndex)}
|
|
18709
19197
|
`,
|
|
18710
19198
|
"utf8"
|
|
@@ -18754,7 +19242,7 @@ async function prepareNonGitSnapshot(context) {
|
|
|
18754
19242
|
const quotas = context.fileCheckpoint;
|
|
18755
19243
|
const deadlineMs = Date.now() + quotas.prepareTimeoutMs;
|
|
18756
19244
|
await removeDeadOwnerStaging(os5.tmpdir());
|
|
18757
|
-
const stagingRoot = await mkdtemp5(
|
|
19245
|
+
const stagingRoot = await mkdtemp5(path51.join(os5.tmpdir(), "belay-file-checkpoint-"));
|
|
18758
19246
|
await writeOwnerMarker(stagingRoot, {
|
|
18759
19247
|
version: 1,
|
|
18760
19248
|
pid: process.pid,
|
|
@@ -18762,8 +19250,8 @@ async function prepareNonGitSnapshot(context) {
|
|
|
18762
19250
|
resourceRoot: context.repoRoot,
|
|
18763
19251
|
backend: "file_checkpoint"
|
|
18764
19252
|
});
|
|
18765
|
-
const baselineRoot =
|
|
18766
|
-
const executionRoot =
|
|
19253
|
+
const baselineRoot = path51.join(stagingRoot, "baseline");
|
|
19254
|
+
const executionRoot = path51.join(stagingRoot, "execution");
|
|
18767
19255
|
try {
|
|
18768
19256
|
resolveExecutionCwdRelative(context.repoRoot, context.cwd);
|
|
18769
19257
|
const resourceIdentity = await currentRecoveryResourceIdentity(context.repoRoot, "directory");
|
|
@@ -18792,7 +19280,7 @@ async function prepareNonGitSnapshot(context) {
|
|
|
18792
19280
|
throw new Error(FILE_CHECKPOINT_SOURCE_CHANGED);
|
|
18793
19281
|
}
|
|
18794
19282
|
await writeFile10(
|
|
18795
|
-
|
|
19283
|
+
path51.join(stagingRoot, "baseline-index.json"),
|
|
18796
19284
|
`${JSON.stringify(baselineIndex)}
|
|
18797
19285
|
`,
|
|
18798
19286
|
"utf8"
|
|
@@ -19145,10 +19633,10 @@ async function selectTransactionalBackend(context) {
|
|
|
19145
19633
|
}
|
|
19146
19634
|
|
|
19147
19635
|
// src/core/transactional/diff-evaluator.ts
|
|
19148
|
-
import
|
|
19636
|
+
import path52 from "node:path";
|
|
19149
19637
|
init_path_utils();
|
|
19150
19638
|
function categorizeChange(change, ctx) {
|
|
19151
|
-
const absolutePath = canonicalPath(
|
|
19639
|
+
const absolutePath = canonicalPath(path52.join(ctx.repoRoot, change.relativePath));
|
|
19152
19640
|
if (!pathWithinRoot(ctx.repoRoot, absolutePath)) {
|
|
19153
19641
|
return "repo_outside";
|
|
19154
19642
|
}
|
|
@@ -19742,7 +20230,7 @@ async function notifyDeny(config, event) {
|
|
|
19742
20230
|
init_path_utils();
|
|
19743
20231
|
|
|
19744
20232
|
// src/adapters/layouts/protected-paths.ts
|
|
19745
|
-
import
|
|
20233
|
+
import path53 from "node:path";
|
|
19746
20234
|
function protectedArtifactRoots(layout, repoRoot, controlPlaneDir) {
|
|
19747
20235
|
const roots = [
|
|
19748
20236
|
layout.configPath(repoRoot),
|
|
@@ -19754,7 +20242,7 @@ function protectedArtifactRoots(layout, repoRoot, controlPlaneDir) {
|
|
|
19754
20242
|
if (controlPlaneDir) {
|
|
19755
20243
|
roots.push(controlPlaneDir);
|
|
19756
20244
|
}
|
|
19757
|
-
return roots.map((entry) =>
|
|
20245
|
+
return roots.map((entry) => path53.resolve(entry));
|
|
19758
20246
|
}
|
|
19759
20247
|
|
|
19760
20248
|
// src/adapters/shared/gate-runtime.ts
|
|
@@ -19807,8 +20295,8 @@ function createDefaultGateRuntimeDeps() {
|
|
|
19807
20295
|
return loadJsonFile(configPath, {});
|
|
19808
20296
|
},
|
|
19809
20297
|
async appendAudit(ctx, event) {
|
|
19810
|
-
const auditPath =
|
|
19811
|
-
await mkdir14(
|
|
20298
|
+
const auditPath = path54.join(ctx.repoRoot, ctx.config.audit.logPath);
|
|
20299
|
+
await mkdir14(path54.dirname(auditPath), { recursive: true });
|
|
19812
20300
|
const provenance = auditProvenance(ctx.config);
|
|
19813
20301
|
const record = {
|
|
19814
20302
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -19841,7 +20329,7 @@ function createDefaultGateRuntimeDeps() {
|
|
|
19841
20329
|
};
|
|
19842
20330
|
},
|
|
19843
20331
|
async writeApprovals(filePath, state) {
|
|
19844
|
-
await mkdir14(
|
|
20332
|
+
await mkdir14(path54.dirname(filePath), { recursive: true });
|
|
19845
20333
|
await writeFile11(filePath, `${JSON.stringify(compactApprovals(state), null, 2)}
|
|
19846
20334
|
`, "utf8");
|
|
19847
20335
|
},
|
|
@@ -20003,7 +20491,7 @@ function deriveWorkspaceRootScopeHint(params) {
|
|
|
20003
20491
|
if (!targetPath) {
|
|
20004
20492
|
return void 0;
|
|
20005
20493
|
}
|
|
20006
|
-
const candidateRoot = canonicalPath(
|
|
20494
|
+
const candidateRoot = canonicalPath(path54.dirname(targetPath));
|
|
20007
20495
|
const validation = validateTrustedWorkspaceRootCandidate({
|
|
20008
20496
|
candidatePath: candidateRoot,
|
|
20009
20497
|
repoRoot: action.repoRoot,
|
|
@@ -20337,6 +20825,7 @@ async function evaluateGatedAction(ctx, deps, params) {
|
|
|
20337
20825
|
event: resolveGateAuditEvent(sourceEvent, params.kind),
|
|
20338
20826
|
sourceEvent,
|
|
20339
20827
|
kind: params.kind,
|
|
20828
|
+
...typeof params.payload?.tool_use_id === "string" ? { toolInvocationCorrelationId: toolInvocationCorrelationId(params.payload.tool_use_id) } : {},
|
|
20340
20829
|
fingerprint: verdict2.fingerprint,
|
|
20341
20830
|
verdict: verdict2.verdict,
|
|
20342
20831
|
reason: verdict2.reason,
|
|
@@ -20494,6 +20983,7 @@ async function evaluateGatedAction(ctx, deps, params) {
|
|
|
20494
20983
|
const scrubbedPayload = fingerprintReplayPayload(params.kind, params.payload, scrubOpts);
|
|
20495
20984
|
return gateDecisionToVerdict(ctx, deps, params.kind, result, {
|
|
20496
20985
|
sourceEvent: params.sourceEvent,
|
|
20986
|
+
toolInvocationCorrelationId: typeof params.payload?.tool_use_id === "string" ? toolInvocationCorrelationId(params.payload.tool_use_id) : void 0,
|
|
20497
20987
|
predictedAssessment,
|
|
20498
20988
|
observedAssessment: observedAssessment2,
|
|
20499
20989
|
transactionalLayer,
|
|
@@ -20611,6 +21101,7 @@ async function gateDecisionToVerdict(ctx, deps, kind, result, auditExtras = {})
|
|
|
20611
21101
|
event: auditEvent,
|
|
20612
21102
|
sourceEvent,
|
|
20613
21103
|
kind,
|
|
21104
|
+
...auditExtras.toolInvocationCorrelationId ? { toolInvocationCorrelationId: auditExtras.toolInvocationCorrelationId } : {},
|
|
20614
21105
|
fingerprint: result.fingerprint,
|
|
20615
21106
|
summary: result.normalizedCommand ?? result.summary ?? "",
|
|
20616
21107
|
assessment: result.assessment,
|
|
@@ -21061,29 +21552,56 @@ function gateVerdictToCodexUserPromptResponse(verdict2) {
|
|
|
21061
21552
|
};
|
|
21062
21553
|
}
|
|
21063
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);
|
|
21064
21557
|
await deps.appendAudit(ctx, {
|
|
21065
21558
|
event: eventName,
|
|
21066
21559
|
kind: "audit",
|
|
21067
21560
|
verdict: "allow",
|
|
21068
21561
|
reason: "observed",
|
|
21069
|
-
|
|
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)
|
|
21070
21569
|
});
|
|
21071
21570
|
}
|
|
21072
21571
|
|
|
21073
21572
|
// src/adapters/shared/repo-root.ts
|
|
21074
21573
|
import { existsSync as existsSync17 } from "node:fs";
|
|
21075
|
-
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
|
+
}
|
|
21076
21594
|
function findRepoRoot(startPath, layout) {
|
|
21077
|
-
let current =
|
|
21595
|
+
let current = path55.resolve(startPath);
|
|
21078
21596
|
while (true) {
|
|
21079
21597
|
for (const marker of layout.repoRootMarkers) {
|
|
21080
|
-
if (
|
|
21598
|
+
if (markerMatches(current, marker, layout)) {
|
|
21081
21599
|
return current;
|
|
21082
21600
|
}
|
|
21083
21601
|
}
|
|
21084
|
-
const parent =
|
|
21602
|
+
const parent = path55.dirname(current);
|
|
21085
21603
|
if (parent === current) {
|
|
21086
|
-
return
|
|
21604
|
+
return path55.resolve(startPath);
|
|
21087
21605
|
}
|
|
21088
21606
|
current = parent;
|
|
21089
21607
|
}
|
|
@@ -21109,6 +21627,16 @@ function jsonResponse(value) {
|
|
|
21109
21627
|
process2.stdout.write(`${JSON.stringify(value)}
|
|
21110
21628
|
`);
|
|
21111
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
|
+
}
|
|
21112
21640
|
async function loadRuntimeContext(cwd) {
|
|
21113
21641
|
const repoRoot = findRepoRoot(cwd, codexLayout);
|
|
21114
21642
|
const configPath = codexLayout.configPath(repoRoot);
|
|
@@ -21201,7 +21729,8 @@ async function runBeforeSubmitPromptHook() {
|
|
|
21201
21729
|
try {
|
|
21202
21730
|
const payload = await readStdinJson();
|
|
21203
21731
|
const prompt = String(payload.prompt ?? payload.user_message ?? "");
|
|
21204
|
-
const
|
|
21732
|
+
const cwd = resolveCodexActionCwd(payload);
|
|
21733
|
+
const ctx = await loadRuntimeContext(cwd);
|
|
21205
21734
|
const deps = createDefaultGateRuntimeDeps();
|
|
21206
21735
|
const result = await processApprovalPrompt(ctx, deps, prompt);
|
|
21207
21736
|
jsonResponse(gateVerdictToCodexUserPromptResponse(result));
|
|
@@ -21215,9 +21744,10 @@ async function runBeforeSubmitPromptHook() {
|
|
|
21215
21744
|
async function runToolGateHook(eventName) {
|
|
21216
21745
|
try {
|
|
21217
21746
|
const payload = await readStdinJson();
|
|
21218
|
-
const cwd = process2.cwd();
|
|
21219
21747
|
const toolName = String(payload.tool_name ?? payload.toolName ?? "");
|
|
21220
21748
|
const kind = resolveCodexGateKind(eventName, toolName);
|
|
21749
|
+
const includeToolInputCwd = (eventName === "PreToolUse" || eventName === "preToolUse") && kind === "shell";
|
|
21750
|
+
const cwd = resolveCodexActionCwd(payload, process2.cwd(), { includeToolInputCwd });
|
|
21221
21751
|
const ctx = await loadRuntimeContext(cwd);
|
|
21222
21752
|
const deps = createDefaultGateRuntimeDeps();
|
|
21223
21753
|
if (!kind) {
|
|
@@ -21255,7 +21785,7 @@ async function runShellGateHook() {
|
|
|
21255
21785
|
try {
|
|
21256
21786
|
const payload = await readStdinJson();
|
|
21257
21787
|
const command = extractString(payload.tool_input, "command") || String(payload.command ?? "");
|
|
21258
|
-
const cwd = process2.cwd();
|
|
21788
|
+
const cwd = resolveCodexActionCwd(payload, process2.cwd(), { includeToolInputCwd: true });
|
|
21259
21789
|
const ctx = await loadRuntimeContext(cwd);
|
|
21260
21790
|
const deps = createDefaultGateRuntimeDeps();
|
|
21261
21791
|
const verdict2 = await evaluateGatedAction(ctx, deps, {
|
|
@@ -21280,7 +21810,11 @@ async function runShellGateHook() {
|
|
|
21280
21810
|
async function runAuditHook(eventName) {
|
|
21281
21811
|
try {
|
|
21282
21812
|
const payload = await readStdinJson();
|
|
21283
|
-
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);
|
|
21284
21818
|
const deps = createDefaultGateRuntimeDeps();
|
|
21285
21819
|
await appendObservedAudit(ctx, deps, eventName, payload);
|
|
21286
21820
|
jsonResponse({});
|
|
@@ -21293,6 +21827,7 @@ async function runAuditHook(eventName) {
|
|
|
21293
21827
|
}
|
|
21294
21828
|
}
|
|
21295
21829
|
export {
|
|
21830
|
+
resolveCodexActionCwd,
|
|
21296
21831
|
runAuditHook,
|
|
21297
21832
|
runBeforeSubmitPromptHook,
|
|
21298
21833
|
runShellGateHook,
|