@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
|
@@ -355,60 +355,135 @@ function isRedirectOperator(token) {
|
|
|
355
355
|
function isFdDuplication(token) {
|
|
356
356
|
return FD_DUPLICATION_PATTERN.test(token);
|
|
357
357
|
}
|
|
358
|
-
function
|
|
358
|
+
function lexShell(input) {
|
|
359
359
|
const tokens = [];
|
|
360
|
-
let
|
|
360
|
+
let value = "";
|
|
361
|
+
let wordStart = null;
|
|
362
|
+
let parts = [];
|
|
361
363
|
let quote = null;
|
|
362
|
-
let
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
364
|
+
let quoteStart = -1;
|
|
365
|
+
let quoteHadContent = false;
|
|
366
|
+
let complete = true;
|
|
367
|
+
const startWord = (index) => {
|
|
368
|
+
wordStart ??= index;
|
|
369
|
+
};
|
|
370
|
+
const append = (decoded, start, end, mode, hasExpansion) => {
|
|
371
|
+
startWord(start);
|
|
372
|
+
value += decoded;
|
|
373
|
+
const previous = parts.at(-1);
|
|
374
|
+
if (previous && previous.quote === mode && previous.hasExpansion === hasExpansion && previous.end === start) {
|
|
375
|
+
previous.value += decoded;
|
|
376
|
+
previous.raw += input.slice(start, end);
|
|
377
|
+
previous.end = end;
|
|
378
|
+
return;
|
|
367
379
|
}
|
|
380
|
+
parts.push({
|
|
381
|
+
value: decoded,
|
|
382
|
+
raw: input.slice(start, end),
|
|
383
|
+
start,
|
|
384
|
+
end,
|
|
385
|
+
quote: mode,
|
|
386
|
+
hasExpansion
|
|
387
|
+
});
|
|
388
|
+
};
|
|
389
|
+
const flushWord = (end) => {
|
|
390
|
+
if (wordStart === null) return;
|
|
391
|
+
tokens.push({
|
|
392
|
+
kind: "word",
|
|
393
|
+
value,
|
|
394
|
+
raw: input.slice(wordStart, end),
|
|
395
|
+
start: wordStart,
|
|
396
|
+
end,
|
|
397
|
+
parts
|
|
398
|
+
});
|
|
399
|
+
value = "";
|
|
400
|
+
wordStart = null;
|
|
401
|
+
parts = [];
|
|
402
|
+
};
|
|
403
|
+
const pushOperator = (token, start, end) => {
|
|
404
|
+
tokens.push({ kind: "operator", value: token, raw: input.slice(start, end), start, end });
|
|
368
405
|
};
|
|
369
406
|
for (let index = 0; index < input.length; index += 1) {
|
|
370
|
-
const char = input[index];
|
|
371
|
-
if (
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
407
|
+
const char = input[index] ?? "";
|
|
408
|
+
if (quote === "single") {
|
|
409
|
+
if (char === "'") {
|
|
410
|
+
if (!quoteHadContent) append("", quoteStart, index + 1, "single", false);
|
|
411
|
+
quote = null;
|
|
412
|
+
} else {
|
|
413
|
+
append(char, index, index + 1, "single", false);
|
|
414
|
+
quoteHadContent = true;
|
|
415
|
+
}
|
|
378
416
|
continue;
|
|
379
417
|
}
|
|
380
|
-
if (quote) {
|
|
381
|
-
if (char ===
|
|
418
|
+
if (quote === "double") {
|
|
419
|
+
if (char === '"') {
|
|
420
|
+
if (!quoteHadContent) append("", quoteStart, index + 1, "double", false);
|
|
382
421
|
quote = null;
|
|
383
|
-
|
|
384
|
-
buffer += char;
|
|
422
|
+
continue;
|
|
385
423
|
}
|
|
424
|
+
if (char === "\\") {
|
|
425
|
+
const next = input[index + 1];
|
|
426
|
+
if (next === void 0) {
|
|
427
|
+
append("\\", index, index + 1, "double", false);
|
|
428
|
+
complete = false;
|
|
429
|
+
continue;
|
|
430
|
+
}
|
|
431
|
+
if (next === "$" || next === "`" || next === '"' || next === "\\" || next === "\n") {
|
|
432
|
+
append(next === "\n" ? "" : next, index, index + 2, "double", false);
|
|
433
|
+
quoteHadContent = true;
|
|
434
|
+
index += 1;
|
|
435
|
+
continue;
|
|
436
|
+
}
|
|
437
|
+
append("\\", index, index + 1, "double", false);
|
|
438
|
+
quoteHadContent = true;
|
|
439
|
+
continue;
|
|
440
|
+
}
|
|
441
|
+
append(char, index, index + 1, "double", char === "$" || char === "`");
|
|
442
|
+
quoteHadContent = true;
|
|
386
443
|
continue;
|
|
387
444
|
}
|
|
388
|
-
if (char === '"
|
|
389
|
-
|
|
445
|
+
if (char === "'" || char === '"') {
|
|
446
|
+
startWord(index);
|
|
447
|
+
quote = char === "'" ? "single" : "double";
|
|
448
|
+
quoteStart = index;
|
|
449
|
+
quoteHadContent = false;
|
|
450
|
+
continue;
|
|
451
|
+
}
|
|
452
|
+
if (char === "\\") {
|
|
453
|
+
const next = input[index + 1];
|
|
454
|
+
if (next === void 0) {
|
|
455
|
+
append("\\", index, index + 1, "unquoted", false);
|
|
456
|
+
complete = false;
|
|
457
|
+
continue;
|
|
458
|
+
}
|
|
459
|
+
append(next, index, index + 2, "unquoted", false);
|
|
460
|
+
index += 1;
|
|
390
461
|
continue;
|
|
391
462
|
}
|
|
392
463
|
const operator = readShellOperator(input, index);
|
|
393
464
|
if (operator) {
|
|
394
|
-
|
|
395
|
-
|
|
465
|
+
flushWord(index);
|
|
466
|
+
pushOperator(operator.token, index, index + operator.length);
|
|
396
467
|
index += operator.length - 1;
|
|
397
468
|
continue;
|
|
398
469
|
}
|
|
399
470
|
if (char === "\n" || char === "\r") {
|
|
400
|
-
|
|
401
|
-
|
|
471
|
+
flushWord(index);
|
|
472
|
+
pushOperator(";", index, index + 1);
|
|
402
473
|
continue;
|
|
403
474
|
}
|
|
404
475
|
if (/\s/.test(char)) {
|
|
405
|
-
|
|
476
|
+
flushWord(index);
|
|
406
477
|
continue;
|
|
407
478
|
}
|
|
408
|
-
|
|
479
|
+
append(char, index, index + 1, "unquoted", char === "$" || char === "`");
|
|
409
480
|
}
|
|
410
|
-
|
|
411
|
-
|
|
481
|
+
if (quote !== null) complete = false;
|
|
482
|
+
flushWord(input.length);
|
|
483
|
+
return { tokens, complete };
|
|
484
|
+
}
|
|
485
|
+
function tokenizeShell(input) {
|
|
486
|
+
return lexShell(input).tokens.map((token) => token.value);
|
|
412
487
|
}
|
|
413
488
|
function commandKey(tokens) {
|
|
414
489
|
const filtered = tokens.filter((token) => token !== "sudo");
|
|
@@ -1400,6 +1475,22 @@ import { createHash as createHash2 } from "node:crypto";
|
|
|
1400
1475
|
function approvalCorrelationId(approvalId) {
|
|
1401
1476
|
return createHash2("sha256").update(approvalId).digest("hex").slice(0, 16);
|
|
1402
1477
|
}
|
|
1478
|
+
function canonicalToolUseIdForCorrelation(toolUseId) {
|
|
1479
|
+
const trimmed = toolUseId.trim();
|
|
1480
|
+
if (trimmed.startsWith("tool_")) {
|
|
1481
|
+
const remainder = trimmed.slice("tool_".length);
|
|
1482
|
+
if (TOOL_USE_UUID_PATTERN.test(remainder)) {
|
|
1483
|
+
return remainder.toLowerCase();
|
|
1484
|
+
}
|
|
1485
|
+
}
|
|
1486
|
+
if (TOOL_USE_UUID_PATTERN.test(trimmed)) {
|
|
1487
|
+
return trimmed.toLowerCase();
|
|
1488
|
+
}
|
|
1489
|
+
return trimmed;
|
|
1490
|
+
}
|
|
1491
|
+
function toolInvocationCorrelationId(toolUseId) {
|
|
1492
|
+
return createHash2("sha256").update(canonicalToolUseIdForCorrelation(toolUseId)).digest("hex").slice(0, 16);
|
|
1493
|
+
}
|
|
1403
1494
|
function isValidApprovalCorrelationId(value) {
|
|
1404
1495
|
return /^[a-f0-9]{16}$/.test(value);
|
|
1405
1496
|
}
|
|
@@ -1422,7 +1513,16 @@ function isValidPreservedHashField(field, value) {
|
|
|
1422
1513
|
return isValidAuditFingerprint(value);
|
|
1423
1514
|
}
|
|
1424
1515
|
function scrubAuditContainer(value, options) {
|
|
1425
|
-
|
|
1516
|
+
const withoutRawToolIds = (input) => {
|
|
1517
|
+
if (Array.isArray(input)) return input.map(withoutRawToolIds);
|
|
1518
|
+
if (input && typeof input === "object") {
|
|
1519
|
+
return Object.fromEntries(
|
|
1520
|
+
Object.entries(input).filter(([key]) => key !== "tool_use_id").map(([key, child]) => [key, withoutRawToolIds(child)])
|
|
1521
|
+
);
|
|
1522
|
+
}
|
|
1523
|
+
return input;
|
|
1524
|
+
};
|
|
1525
|
+
return scrubValue(withoutRawToolIds(value), {
|
|
1426
1526
|
...options,
|
|
1427
1527
|
maskHighEntropyStrings: true
|
|
1428
1528
|
});
|
|
@@ -1441,7 +1541,7 @@ function serializeAuditField(key, value, options) {
|
|
|
1441
1541
|
if (key === "timestamp" && typeof value === "string" && isValidAuditTimestamp(value)) {
|
|
1442
1542
|
return value;
|
|
1443
1543
|
}
|
|
1444
|
-
if (key === "approvalCorrelationId" && typeof value === "string" && isValidApprovalCorrelationId(value)) {
|
|
1544
|
+
if ((key === "approvalCorrelationId" || key === "toolInvocationCorrelationId") && typeof value === "string" && isValidApprovalCorrelationId(value)) {
|
|
1445
1545
|
return value;
|
|
1446
1546
|
}
|
|
1447
1547
|
if ((key === "runtimeVersion" || key === "runtimeBuildStamp" || key === "boundaryProfile") && typeof value === "string" && value.length > 0) {
|
|
@@ -1493,7 +1593,7 @@ function serializeAuditRecordV3(record, options) {
|
|
|
1493
1593
|
serialized.approvalCorrelationId = record.approvalCorrelationId;
|
|
1494
1594
|
}
|
|
1495
1595
|
for (const [key, value] of Object.entries(record)) {
|
|
1496
|
-
if (key === "timestamp" || key === "ts" || key === "approvalId" || key === "schemaVersion") {
|
|
1596
|
+
if (key === "timestamp" || key === "ts" || key === "approvalId" || key === "tool_use_id" || key === "schemaVersion") {
|
|
1497
1597
|
continue;
|
|
1498
1598
|
}
|
|
1499
1599
|
const next = serializeAuditField(key, value, options);
|
|
@@ -1503,7 +1603,7 @@ function serializeAuditRecordV3(record, options) {
|
|
|
1503
1603
|
}
|
|
1504
1604
|
return serialized;
|
|
1505
1605
|
}
|
|
1506
|
-
var AUDIT_SCHEMA_VERSION, ISO8601_PATTERN, HEX64_PATTERN, SCRUB_PLACEHOLDERS, PRESERVED_HASH_FIELDS, PRESERVED_LITERAL_FIELDS, SCRUBBED_CONTAINER_FIELDS;
|
|
1606
|
+
var AUDIT_SCHEMA_VERSION, ISO8601_PATTERN, HEX64_PATTERN, SCRUB_PLACEHOLDERS, PRESERVED_HASH_FIELDS, PRESERVED_LITERAL_FIELDS, SCRUBBED_CONTAINER_FIELDS, TOOL_USE_UUID_PATTERN;
|
|
1507
1607
|
var init_audit_serialize = __esm({
|
|
1508
1608
|
"src/core/audit-serialize.ts"() {
|
|
1509
1609
|
"use strict";
|
|
@@ -1525,6 +1625,7 @@ var init_audit_serialize = __esm({
|
|
|
1525
1625
|
PRESERVED_LITERAL_FIELDS = /* @__PURE__ */ new Set([
|
|
1526
1626
|
"timestamp",
|
|
1527
1627
|
"approvalCorrelationId",
|
|
1628
|
+
"toolInvocationCorrelationId",
|
|
1528
1629
|
"runtimeVersion",
|
|
1529
1630
|
"runtimeBuildStamp",
|
|
1530
1631
|
"boundaryProfile",
|
|
@@ -1545,6 +1646,7 @@ var init_audit_serialize = __esm({
|
|
|
1545
1646
|
"predictedAssessment",
|
|
1546
1647
|
"observedAssessment"
|
|
1547
1648
|
]);
|
|
1649
|
+
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;
|
|
1548
1650
|
}
|
|
1549
1651
|
});
|
|
1550
1652
|
|
|
@@ -4130,7 +4232,7 @@ init_approval_replay();
|
|
|
4130
4232
|
import { randomUUID as randomUUID6 } from "node:crypto";
|
|
4131
4233
|
import { existsSync as existsSync16 } from "node:fs";
|
|
4132
4234
|
import { mkdir as mkdir14, readFile as readFile15, writeFile as writeFile11 } from "node:fs/promises";
|
|
4133
|
-
import
|
|
4235
|
+
import path54 from "node:path";
|
|
4134
4236
|
|
|
4135
4237
|
// src/core/approval-service.ts
|
|
4136
4238
|
init_config_io();
|
|
@@ -10872,6 +10974,24 @@ init_fingerprint2();
|
|
|
10872
10974
|
|
|
10873
10975
|
// src/core/replay-scrub.ts
|
|
10874
10976
|
init_scrub();
|
|
10977
|
+
function redactToolInvocationId(value, rawToolUseId) {
|
|
10978
|
+
if (typeof value === "string") {
|
|
10979
|
+
return rawToolUseId ? value.replaceAll(rawToolUseId, "<tool-use-id>") : value;
|
|
10980
|
+
}
|
|
10981
|
+
if (Array.isArray(value)) {
|
|
10982
|
+
return value.map((item) => redactToolInvocationId(item, rawToolUseId));
|
|
10983
|
+
}
|
|
10984
|
+
if (value && typeof value === "object") {
|
|
10985
|
+
const result = {};
|
|
10986
|
+
for (const [key, child] of Object.entries(value)) {
|
|
10987
|
+
if (key !== "tool_use_id") {
|
|
10988
|
+
result[key] = redactToolInvocationId(child, rawToolUseId);
|
|
10989
|
+
}
|
|
10990
|
+
}
|
|
10991
|
+
return result;
|
|
10992
|
+
}
|
|
10993
|
+
return value;
|
|
10994
|
+
}
|
|
10875
10995
|
function subagentFingerprintSource(payload, scrubOptions) {
|
|
10876
10996
|
const toolInput = payload.tool_input;
|
|
10877
10997
|
if (toolInput && typeof toolInput === "object") {
|
|
@@ -10904,16 +11024,20 @@ function fingerprintReplayPayload(kind, payload, scrubOptions) {
|
|
|
10904
11024
|
if (!payload) {
|
|
10905
11025
|
return void 0;
|
|
10906
11026
|
}
|
|
11027
|
+
const replayPayload = redactToolInvocationId(
|
|
11028
|
+
payload,
|
|
11029
|
+
typeof payload.tool_use_id === "string" ? payload.tool_use_id : void 0
|
|
11030
|
+
);
|
|
10907
11031
|
if (kind === "tool") {
|
|
10908
|
-
const toolInput =
|
|
11032
|
+
const toolInput = replayPayload.tool_input;
|
|
10909
11033
|
if (toolInput && typeof toolInput === "object") {
|
|
10910
11034
|
return scrubValue(toolInput, scrubOptions);
|
|
10911
11035
|
}
|
|
10912
11036
|
}
|
|
10913
11037
|
if (kind === "subagent") {
|
|
10914
|
-
return subagentFingerprintSource(
|
|
11038
|
+
return subagentFingerprintSource(replayPayload, scrubOptions);
|
|
10915
11039
|
}
|
|
10916
|
-
return scrubValue(
|
|
11040
|
+
return scrubValue(replayPayload, scrubOptions);
|
|
10917
11041
|
}
|
|
10918
11042
|
|
|
10919
11043
|
// src/core/classify-subagent.ts
|
|
@@ -11005,7 +11129,7 @@ function classifySubagent(payload, repoRoot, options = {}, config) {
|
|
|
11005
11129
|
}
|
|
11006
11130
|
|
|
11007
11131
|
// src/core/classify-tool.ts
|
|
11008
|
-
import
|
|
11132
|
+
import path42 from "node:path";
|
|
11009
11133
|
init_fingerprint2();
|
|
11010
11134
|
init_path_utils();
|
|
11011
11135
|
init_scrub();
|
|
@@ -11128,10 +11252,346 @@ init_git_resource_identity();
|
|
|
11128
11252
|
init_path_utils();
|
|
11129
11253
|
init_shell_tokenizer();
|
|
11130
11254
|
import { lstatSync as lstatSync2, realpathSync as realpathSync4 } from "node:fs";
|
|
11131
|
-
import
|
|
11255
|
+
import path41 from "node:path";
|
|
11132
11256
|
|
|
11133
|
-
// src/core/verdict/
|
|
11257
|
+
// src/core/verdict/docker-compose-run.ts
|
|
11258
|
+
import path36 from "node:path";
|
|
11259
|
+
|
|
11260
|
+
// src/core/verdict/recursive-invocation.ts
|
|
11134
11261
|
import path35 from "node:path";
|
|
11262
|
+
var SHELL_INTERPRETERS = /* @__PURE__ */ new Set(["bash", "sh", "zsh", "dash", "fish"]);
|
|
11263
|
+
var PYTHON_INTERPRETERS = /* @__PURE__ */ new Set(["python", "python3"]);
|
|
11264
|
+
var SHELL_SHORT_OPTIONS = /* @__PURE__ */ new Set(["c", "l", "e", "x", "u"]);
|
|
11265
|
+
var SHELL_NON_SCRIPT_SHORT_OPTIONS = /* @__PURE__ */ new Set(["n"]);
|
|
11266
|
+
var SHELL_TERMINAL_OPTIONS = /* @__PURE__ */ new Map([
|
|
11267
|
+
["bash", /* @__PURE__ */ new Set(["--help", "--version"])],
|
|
11268
|
+
["zsh", /* @__PURE__ */ new Set(["--version"])],
|
|
11269
|
+
["fish", /* @__PURE__ */ new Set(["-h", "--help", "-v", "--version"])]
|
|
11270
|
+
]);
|
|
11271
|
+
var SHELL_VALUE_OPTIONS = /* @__PURE__ */ new Set(["-O", "+O", "--init-file", "--rcfile"]);
|
|
11272
|
+
var NODE_TERMINAL_OPTIONS = /* @__PURE__ */ new Set(["-h", "--help", "--help-all", "-v", "--version"]);
|
|
11273
|
+
var NODE_FILE_OPTIONS = /* @__PURE__ */ new Set(["-c", "--check"]);
|
|
11274
|
+
var PYTHON_PROFILE = {
|
|
11275
|
+
scriptOptions: /* @__PURE__ */ new Set(["-c"]),
|
|
11276
|
+
terminalOptions: /* @__PURE__ */ new Set(["-h", "--help", "-V", "-VV", "--version"]),
|
|
11277
|
+
terminalValueOptions: /* @__PURE__ */ new Set(["-m"]),
|
|
11278
|
+
flagOptions: /* @__PURE__ */ new Set([
|
|
11279
|
+
"-b",
|
|
11280
|
+
"-bb",
|
|
11281
|
+
"-B",
|
|
11282
|
+
"-d",
|
|
11283
|
+
"-E",
|
|
11284
|
+
"-I",
|
|
11285
|
+
"-O",
|
|
11286
|
+
"-OO",
|
|
11287
|
+
"-P",
|
|
11288
|
+
"-q",
|
|
11289
|
+
"-s",
|
|
11290
|
+
"-S",
|
|
11291
|
+
"-u",
|
|
11292
|
+
"-v",
|
|
11293
|
+
"-x"
|
|
11294
|
+
]),
|
|
11295
|
+
valueOptions: /* @__PURE__ */ new Set(["-W", "-X"]),
|
|
11296
|
+
attachedValuePrefixes: ["-W", "-X"]
|
|
11297
|
+
};
|
|
11298
|
+
var RUBY_PROFILE = {
|
|
11299
|
+
scriptOptions: /* @__PURE__ */ new Set(["-e"]),
|
|
11300
|
+
terminalOptions: /* @__PURE__ */ new Set(["-h", "--help", "-v", "--version", "--copyright"]),
|
|
11301
|
+
terminalValueOptions: /* @__PURE__ */ new Set([]),
|
|
11302
|
+
flagOptions: /* @__PURE__ */ new Set(["-d", "--debug", "-w"]),
|
|
11303
|
+
valueOptions: /* @__PURE__ */ new Set(["-I"]),
|
|
11304
|
+
attachedValuePrefixes: ["-I"]
|
|
11305
|
+
};
|
|
11306
|
+
var PERL_PROFILE = {
|
|
11307
|
+
scriptOptions: /* @__PURE__ */ new Set(["-e"]),
|
|
11308
|
+
terminalOptions: /* @__PURE__ */ new Set(["-h", "--help", "-v", "--version"]),
|
|
11309
|
+
terminalValueOptions: /* @__PURE__ */ new Set([]),
|
|
11310
|
+
flagOptions: /* @__PURE__ */ new Set([]),
|
|
11311
|
+
valueOptions: /* @__PURE__ */ new Set(["-I"]),
|
|
11312
|
+
attachedValuePrefixes: ["-I"]
|
|
11313
|
+
};
|
|
11314
|
+
var OSASCRIPT_PROFILE = {
|
|
11315
|
+
scriptOptions: /* @__PURE__ */ new Set(["-e"]),
|
|
11316
|
+
terminalOptions: /* @__PURE__ */ new Set(["-h", "--help"]),
|
|
11317
|
+
terminalValueOptions: /* @__PURE__ */ new Set([]),
|
|
11318
|
+
flagOptions: /* @__PURE__ */ new Set([]),
|
|
11319
|
+
valueOptions: /* @__PURE__ */ new Set(["-l"]),
|
|
11320
|
+
attachedValuePrefixes: []
|
|
11321
|
+
};
|
|
11322
|
+
function normalizeInterpreter(value) {
|
|
11323
|
+
return path35.basename(value);
|
|
11324
|
+
}
|
|
11325
|
+
function scriptResult(interpreter, token) {
|
|
11326
|
+
if (!token) {
|
|
11327
|
+
return { kind: "indeterminate", interpreter, signal: "shell.interpreter_argv_incomplete" };
|
|
11328
|
+
}
|
|
11329
|
+
if (token.parts.some((part) => part.hasExpansion)) {
|
|
11330
|
+
return { kind: "dynamic", interpreter, signal: "shell.script_expanded" };
|
|
11331
|
+
}
|
|
11332
|
+
return { kind: "static", interpreter, script: token.value };
|
|
11333
|
+
}
|
|
11334
|
+
function decodeShell(words, interpreter) {
|
|
11335
|
+
for (let index = 1; index < words.length; index += 1) {
|
|
11336
|
+
const option = words[index]?.value ?? "";
|
|
11337
|
+
if (option === "--") return { kind: "none" };
|
|
11338
|
+
if (SHELL_TERMINAL_OPTIONS.get(interpreter)?.has(option)) return { kind: "none" };
|
|
11339
|
+
if (interpreter === "bash" && SHELL_VALUE_OPTIONS.has(option)) {
|
|
11340
|
+
const operand = words[index + 1]?.value;
|
|
11341
|
+
if (!operand || operand.startsWith("-")) {
|
|
11342
|
+
return { kind: "indeterminate", interpreter, signal: "shell.interpreter_option_unknown" };
|
|
11343
|
+
}
|
|
11344
|
+
index += 1;
|
|
11345
|
+
continue;
|
|
11346
|
+
}
|
|
11347
|
+
if (!option.startsWith("-") || option === "-") return { kind: "none" };
|
|
11348
|
+
const flags = [...option.slice(1)];
|
|
11349
|
+
if (flags.length === 0) {
|
|
11350
|
+
return { kind: "indeterminate", interpreter, signal: "shell.interpreter_option_unknown" };
|
|
11351
|
+
}
|
|
11352
|
+
if (flags.every((flag) => SHELL_SHORT_OPTIONS.has(flag))) {
|
|
11353
|
+
if (!flags.includes("c")) continue;
|
|
11354
|
+
return scriptResult(interpreter, words[index + 1]);
|
|
11355
|
+
}
|
|
11356
|
+
if (flags.every(
|
|
11357
|
+
(flag) => SHELL_SHORT_OPTIONS.has(flag) || SHELL_NON_SCRIPT_SHORT_OPTIONS.has(flag)
|
|
11358
|
+
) && flags.some((flag) => SHELL_NON_SCRIPT_SHORT_OPTIONS.has(flag))) {
|
|
11359
|
+
return { kind: "none" };
|
|
11360
|
+
}
|
|
11361
|
+
return { kind: "indeterminate", interpreter, signal: "shell.interpreter_option_unknown" };
|
|
11362
|
+
}
|
|
11363
|
+
return { kind: "none" };
|
|
11364
|
+
}
|
|
11365
|
+
function decodeSeparated(words, interpreter, profile) {
|
|
11366
|
+
for (let index = 1; index < words.length; index += 1) {
|
|
11367
|
+
const option = words[index]?.value ?? "";
|
|
11368
|
+
if (option === "--" || !option.startsWith("-") || option === "-") return { kind: "none" };
|
|
11369
|
+
if (profile.scriptOptions.has(option)) {
|
|
11370
|
+
return scriptResult(interpreter, words[index + 1]);
|
|
11371
|
+
}
|
|
11372
|
+
if (profile.terminalOptions.has(option)) return { kind: "none" };
|
|
11373
|
+
if (profile.terminalValueOptions.has(option)) {
|
|
11374
|
+
const operand = words[index + 1]?.value;
|
|
11375
|
+
if (!operand || operand.startsWith("-")) {
|
|
11376
|
+
return { kind: "indeterminate", interpreter, signal: "shell.interpreter_option_unknown" };
|
|
11377
|
+
}
|
|
11378
|
+
return { kind: "none" };
|
|
11379
|
+
}
|
|
11380
|
+
if (profile.flagOptions.has(option)) {
|
|
11381
|
+
continue;
|
|
11382
|
+
}
|
|
11383
|
+
if (profile.valueOptions.has(option)) {
|
|
11384
|
+
const operand = words[index + 1]?.value;
|
|
11385
|
+
if (!operand || operand.startsWith("-")) {
|
|
11386
|
+
return { kind: "indeterminate", interpreter, signal: "shell.interpreter_option_unknown" };
|
|
11387
|
+
}
|
|
11388
|
+
index += 1;
|
|
11389
|
+
continue;
|
|
11390
|
+
}
|
|
11391
|
+
if (profile.attachedValuePrefixes.some(
|
|
11392
|
+
(prefix) => option.startsWith(prefix) && option.length > prefix.length
|
|
11393
|
+
)) {
|
|
11394
|
+
continue;
|
|
11395
|
+
}
|
|
11396
|
+
return { kind: "indeterminate", interpreter, signal: "shell.interpreter_option_unknown" };
|
|
11397
|
+
}
|
|
11398
|
+
return { kind: "none" };
|
|
11399
|
+
}
|
|
11400
|
+
function decodeNode(words, interpreter) {
|
|
11401
|
+
const option = words[1]?.value ?? "";
|
|
11402
|
+
if (option === "--" || !option.startsWith("-") || option === "-") return { kind: "none" };
|
|
11403
|
+
if (option === "-e" || option === "--eval") {
|
|
11404
|
+
return scriptResult(interpreter, words[2]);
|
|
11405
|
+
}
|
|
11406
|
+
if (option.startsWith("--eval=")) {
|
|
11407
|
+
const script = option.slice("--eval=".length);
|
|
11408
|
+
if (words[1]?.parts.some((part) => part.hasExpansion)) {
|
|
11409
|
+
return { kind: "dynamic", interpreter, signal: "shell.script_expanded" };
|
|
11410
|
+
}
|
|
11411
|
+
return { kind: "static", interpreter, script };
|
|
11412
|
+
}
|
|
11413
|
+
if (NODE_TERMINAL_OPTIONS.has(option)) return { kind: "none" };
|
|
11414
|
+
if (NODE_FILE_OPTIONS.has(option)) return { kind: "none" };
|
|
11415
|
+
return { kind: "indeterminate", interpreter, signal: "shell.interpreter_option_unknown" };
|
|
11416
|
+
}
|
|
11417
|
+
function decodeEval(words) {
|
|
11418
|
+
const arguments_ = words.slice(1);
|
|
11419
|
+
if (arguments_.length === 0) return { kind: "none" };
|
|
11420
|
+
if (arguments_.some((word) => word.parts.some((part) => part.hasExpansion))) {
|
|
11421
|
+
return { kind: "dynamic", interpreter: "eval", signal: "shell.script_expanded" };
|
|
11422
|
+
}
|
|
11423
|
+
return {
|
|
11424
|
+
kind: "static",
|
|
11425
|
+
interpreter: "eval",
|
|
11426
|
+
script: arguments_.map((word) => word.value).join(" ")
|
|
11427
|
+
};
|
|
11428
|
+
}
|
|
11429
|
+
function decodeRecursiveInvocation(tokens) {
|
|
11430
|
+
if (tokens.some((token) => token.kind === "operator")) return { kind: "none" };
|
|
11431
|
+
const words = tokens.filter((token) => token.kind === "word");
|
|
11432
|
+
const interpreter = normalizeInterpreter(words[0]?.value ?? "");
|
|
11433
|
+
if (!interpreter) return { kind: "none" };
|
|
11434
|
+
if (interpreter === "eval") return decodeEval(words);
|
|
11435
|
+
if (SHELL_INTERPRETERS.has(interpreter)) return decodeShell(words, interpreter);
|
|
11436
|
+
if (PYTHON_INTERPRETERS.has(interpreter)) {
|
|
11437
|
+
return decodeSeparated(words, interpreter, PYTHON_PROFILE);
|
|
11438
|
+
}
|
|
11439
|
+
if (interpreter === "node") return decodeNode(words, interpreter);
|
|
11440
|
+
if (interpreter === "ruby") return decodeSeparated(words, interpreter, RUBY_PROFILE);
|
|
11441
|
+
if (interpreter === "perl") return decodeSeparated(words, interpreter, PERL_PROFILE);
|
|
11442
|
+
if (interpreter === "osascript") return decodeSeparated(words, interpreter, OSASCRIPT_PROFILE);
|
|
11443
|
+
return { kind: "none" };
|
|
11444
|
+
}
|
|
11445
|
+
function shellTokensFromValues(values, options = {}) {
|
|
11446
|
+
let offset = 0;
|
|
11447
|
+
return values.map((value) => {
|
|
11448
|
+
const start = offset;
|
|
11449
|
+
const end = start + value.length;
|
|
11450
|
+
offset = end + 1;
|
|
11451
|
+
return {
|
|
11452
|
+
kind: "word",
|
|
11453
|
+
value,
|
|
11454
|
+
raw: value,
|
|
11455
|
+
start,
|
|
11456
|
+
end,
|
|
11457
|
+
parts: [
|
|
11458
|
+
{
|
|
11459
|
+
value,
|
|
11460
|
+
raw: value,
|
|
11461
|
+
start,
|
|
11462
|
+
end,
|
|
11463
|
+
quote: "unquoted",
|
|
11464
|
+
hasExpansion: options.detectExpansion !== false && (value.includes("$") || value.includes("`"))
|
|
11465
|
+
}
|
|
11466
|
+
]
|
|
11467
|
+
};
|
|
11468
|
+
});
|
|
11469
|
+
}
|
|
11470
|
+
|
|
11471
|
+
// src/core/verdict/docker-compose-run.ts
|
|
11472
|
+
var COMPOSE_GLOBAL_OPTIONS = /* @__PURE__ */ new Map([
|
|
11473
|
+
["--all-resources", 0],
|
|
11474
|
+
["--ansi", 1],
|
|
11475
|
+
["--compatibility", 0],
|
|
11476
|
+
["--dry-run", 0],
|
|
11477
|
+
["--env-file", 1],
|
|
11478
|
+
["-f", 1],
|
|
11479
|
+
["--file", 1],
|
|
11480
|
+
["--parallel", 1],
|
|
11481
|
+
["--profile", 1],
|
|
11482
|
+
["--progress", 1],
|
|
11483
|
+
["--project-directory", 1],
|
|
11484
|
+
["-p", 1],
|
|
11485
|
+
["--project-name", 1]
|
|
11486
|
+
]);
|
|
11487
|
+
var COMPOSE_RUN_OPTIONS = /* @__PURE__ */ new Map([
|
|
11488
|
+
["--build", 0],
|
|
11489
|
+
["--cap-add", 1],
|
|
11490
|
+
["--cap-drop", 1],
|
|
11491
|
+
["-d", 0],
|
|
11492
|
+
["--detach", 0],
|
|
11493
|
+
["--entrypoint", 1],
|
|
11494
|
+
["-e", 1],
|
|
11495
|
+
["--env", 1],
|
|
11496
|
+
["--env-from-file", 1],
|
|
11497
|
+
["-i", 0],
|
|
11498
|
+
["--interactive", 0],
|
|
11499
|
+
["-l", 1],
|
|
11500
|
+
["--label", 1],
|
|
11501
|
+
["--name", 1],
|
|
11502
|
+
["--no-deps", 0],
|
|
11503
|
+
["-T", 0],
|
|
11504
|
+
["--no-tty", 0],
|
|
11505
|
+
["-p", 1],
|
|
11506
|
+
["--publish", 1],
|
|
11507
|
+
["--pull", 1],
|
|
11508
|
+
["-q", 0],
|
|
11509
|
+
["--quiet", 0],
|
|
11510
|
+
["--quiet-build", 0],
|
|
11511
|
+
["--quiet-pull", 0],
|
|
11512
|
+
["--remove-orphans", 0],
|
|
11513
|
+
["--rm", 0],
|
|
11514
|
+
["-P", 0],
|
|
11515
|
+
["--service-ports", 0],
|
|
11516
|
+
["--use-aliases", 0],
|
|
11517
|
+
["-u", 1],
|
|
11518
|
+
["--user", 1],
|
|
11519
|
+
["-v", 1],
|
|
11520
|
+
["--volume", 1],
|
|
11521
|
+
["-w", 1],
|
|
11522
|
+
["--workdir", 1]
|
|
11523
|
+
]);
|
|
11524
|
+
function parseOptions(words, start, options) {
|
|
11525
|
+
let index = start;
|
|
11526
|
+
while (index < words.length) {
|
|
11527
|
+
const value = words[index]?.value ?? "";
|
|
11528
|
+
if (value === "--") return { kind: "ok", index: index + 1 };
|
|
11529
|
+
if (!value.startsWith("-") || value === "-") return { kind: "ok", index };
|
|
11530
|
+
const equalsIndex = value.indexOf("=");
|
|
11531
|
+
const name = equalsIndex === -1 ? value : value.slice(0, equalsIndex);
|
|
11532
|
+
const arity = options.get(name);
|
|
11533
|
+
if (arity === void 0) return { kind: "indeterminate" };
|
|
11534
|
+
if (equalsIndex !== -1) {
|
|
11535
|
+
if (!value.startsWith("--") || arity !== 1 || equalsIndex === value.length - 1) {
|
|
11536
|
+
return { kind: "indeterminate" };
|
|
11537
|
+
}
|
|
11538
|
+
index += 1;
|
|
11539
|
+
continue;
|
|
11540
|
+
}
|
|
11541
|
+
if (arity === 1) {
|
|
11542
|
+
if (!words[index + 1]) return { kind: "indeterminate" };
|
|
11543
|
+
index += 2;
|
|
11544
|
+
continue;
|
|
11545
|
+
}
|
|
11546
|
+
index += 1;
|
|
11547
|
+
}
|
|
11548
|
+
return { kind: "ok", index };
|
|
11549
|
+
}
|
|
11550
|
+
function decodeDockerComposeRun(tokens) {
|
|
11551
|
+
if (tokens.some((token) => token.kind === "operator")) return { kind: "none" };
|
|
11552
|
+
const words = tokens.filter((token) => token.kind === "word");
|
|
11553
|
+
const head = path36.basename(words[0]?.value ?? "");
|
|
11554
|
+
let index;
|
|
11555
|
+
if (head === "docker-compose") {
|
|
11556
|
+
index = 1;
|
|
11557
|
+
} else if (head === "docker" && words[1]?.value === "compose") {
|
|
11558
|
+
index = 2;
|
|
11559
|
+
} else {
|
|
11560
|
+
return { kind: "none" };
|
|
11561
|
+
}
|
|
11562
|
+
const globalOptions = parseOptions(words, index, COMPOSE_GLOBAL_OPTIONS);
|
|
11563
|
+
if (globalOptions.kind === "indeterminate") {
|
|
11564
|
+
return { kind: "indeterminate", signal: "shell.compose_argv_indeterminate" };
|
|
11565
|
+
}
|
|
11566
|
+
index = globalOptions.index;
|
|
11567
|
+
if (words[index]?.value !== "run") return { kind: "none" };
|
|
11568
|
+
const runOptions = parseOptions(words, index + 1, COMPOSE_RUN_OPTIONS);
|
|
11569
|
+
if (runOptions.kind === "indeterminate") {
|
|
11570
|
+
return { kind: "indeterminate", signal: "shell.compose_argv_indeterminate" };
|
|
11571
|
+
}
|
|
11572
|
+
index = runOptions.index;
|
|
11573
|
+
const service = words[index]?.value;
|
|
11574
|
+
if (!service) return { kind: "indeterminate", signal: "shell.compose_argv_indeterminate" };
|
|
11575
|
+
const command = words.slice(index + 1);
|
|
11576
|
+
if (command.length === 0) return { kind: "none" };
|
|
11577
|
+
const recursive = decodeRecursiveInvocation(command);
|
|
11578
|
+
if (recursive.kind === "static") {
|
|
11579
|
+
return {
|
|
11580
|
+
kind: "recursive",
|
|
11581
|
+
service,
|
|
11582
|
+
interpreter: recursive.interpreter,
|
|
11583
|
+
script: recursive.script
|
|
11584
|
+
};
|
|
11585
|
+
}
|
|
11586
|
+
if (recursive.kind === "dynamic") return { kind: "dynamic", service, signal: recursive.signal };
|
|
11587
|
+
if (recursive.kind === "indeterminate") {
|
|
11588
|
+
return { kind: "indeterminate", signal: "shell.compose_argv_indeterminate" };
|
|
11589
|
+
}
|
|
11590
|
+
return { kind: "none" };
|
|
11591
|
+
}
|
|
11592
|
+
|
|
11593
|
+
// src/core/verdict/egress-classify.ts
|
|
11594
|
+
import path37 from "node:path";
|
|
11135
11595
|
var CURL_EFFECT_NEUTRAL_FLAGS = /* @__PURE__ */ new Set([
|
|
11136
11596
|
"-f",
|
|
11137
11597
|
"-L",
|
|
@@ -11166,7 +11626,7 @@ var GH_READ_COMMANDS = /* @__PURE__ */ new Set([
|
|
|
11166
11626
|
"workflow view"
|
|
11167
11627
|
]);
|
|
11168
11628
|
function decodeEgressEffects(params) {
|
|
11169
|
-
const head =
|
|
11629
|
+
const head = path37.basename(params.tokens[0] ?? "");
|
|
11170
11630
|
if (head !== "curl" && head !== "wget" && head !== "gh") {
|
|
11171
11631
|
return null;
|
|
11172
11632
|
}
|
|
@@ -11174,7 +11634,7 @@ function decodeEgressEffects(params) {
|
|
|
11174
11634
|
const provenance = { segment: params.segment };
|
|
11175
11635
|
const requirements = [];
|
|
11176
11636
|
for (const file of decoded.files) {
|
|
11177
|
-
const resolved =
|
|
11637
|
+
const resolved = path37.resolve(params.cwd, expandHome2(file));
|
|
11178
11638
|
requirements.push(
|
|
11179
11639
|
requirement("fs.read", "fs.read", { kind: "path", path: resolved }, params.segment, [
|
|
11180
11640
|
"egress.explicit_file_read"
|
|
@@ -11196,7 +11656,7 @@ function decodeEgressEffects(params) {
|
|
|
11196
11656
|
if (file === "-") {
|
|
11197
11657
|
continue;
|
|
11198
11658
|
}
|
|
11199
|
-
const resolved =
|
|
11659
|
+
const resolved = path37.resolve(params.cwd, expandHome2(file));
|
|
11200
11660
|
if (resolved === "/dev/null") {
|
|
11201
11661
|
continue;
|
|
11202
11662
|
}
|
|
@@ -11674,13 +12134,13 @@ function decodeSingleCurlWgetGrammar(head, tokens) {
|
|
|
11674
12134
|
if (head === "wget" && !explicitOutput) {
|
|
11675
12135
|
outputFiles.push(
|
|
11676
12136
|
...endpointOutputNames.map(
|
|
11677
|
-
(name) => outputDirectory ?
|
|
12137
|
+
(name) => outputDirectory ? path37.join(outputDirectory, name) : name
|
|
11678
12138
|
)
|
|
11679
12139
|
);
|
|
11680
12140
|
} else if (head === "curl" && remoteNameOutput) {
|
|
11681
12141
|
outputFiles.push(
|
|
11682
12142
|
...endpointOutputNames.map(
|
|
11683
|
-
(name) => outputDirectory ?
|
|
12143
|
+
(name) => outputDirectory ? path37.join(outputDirectory, name) : name
|
|
11684
12144
|
)
|
|
11685
12145
|
);
|
|
11686
12146
|
}
|
|
@@ -11694,7 +12154,7 @@ function decodeSingleCurlWgetGrammar(head, tokens) {
|
|
|
11694
12154
|
outputFiles: [
|
|
11695
12155
|
...new Set(
|
|
11696
12156
|
outputFiles.map(
|
|
11697
|
-
(file) => outputDirectory && directoryEligibleOutputs.has(file) && !
|
|
12157
|
+
(file) => outputDirectory && directoryEligibleOutputs.has(file) && !path37.isAbsolute(file) ? path37.join(outputDirectory, file) : file
|
|
11698
12158
|
)
|
|
11699
12159
|
)
|
|
11700
12160
|
],
|
|
@@ -11709,7 +12169,7 @@ function remoteOutputName(spec) {
|
|
|
11709
12169
|
} catch {
|
|
11710
12170
|
pathname = spec.split(/[?#]/, 1)[0] ?? "";
|
|
11711
12171
|
}
|
|
11712
|
-
const name =
|
|
12172
|
+
const name = path37.posix.basename(pathname);
|
|
11713
12173
|
return name && name !== "/" ? name : "index.html";
|
|
11714
12174
|
}
|
|
11715
12175
|
function decodeGhGrammar(tokens) {
|
|
@@ -11874,7 +12334,7 @@ function expandHome2(value) {
|
|
|
11874
12334
|
return process.env.HOME ?? value;
|
|
11875
12335
|
}
|
|
11876
12336
|
if (value.startsWith("~/")) {
|
|
11877
|
-
return
|
|
12337
|
+
return path37.join(process.env.HOME ?? "~", value.slice(2));
|
|
11878
12338
|
}
|
|
11879
12339
|
return value;
|
|
11880
12340
|
}
|
|
@@ -11893,7 +12353,7 @@ function requirement(tag, action, resource, segment, signals) {
|
|
|
11893
12353
|
}
|
|
11894
12354
|
|
|
11895
12355
|
// src/core/verdict/git-classifier.ts
|
|
11896
|
-
import
|
|
12356
|
+
import path38 from "node:path";
|
|
11897
12357
|
init_shell_tokenizer();
|
|
11898
12358
|
var GIT_BRANCH_MUTATION_FLAGS = /* @__PURE__ */ new Set([
|
|
11899
12359
|
"--copy",
|
|
@@ -11989,7 +12449,7 @@ var FILE_OPERAND_SUBCOMMANDS = /* @__PURE__ */ new Set([
|
|
|
11989
12449
|
var COMPOUND_SUBCOMMAND_HEADS = /* @__PURE__ */ new Set(["worktree", "stash", "tag"]);
|
|
11990
12450
|
var REF_ONLY_WITHOUT_TERMINATOR = /* @__PURE__ */ new Set(["checkout", "show", "log"]);
|
|
11991
12451
|
function isGitExecutable(token) {
|
|
11992
|
-
return
|
|
12452
|
+
return path38.basename(token) === "git";
|
|
11993
12453
|
}
|
|
11994
12454
|
function takesValue(flag) {
|
|
11995
12455
|
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=");
|
|
@@ -12017,7 +12477,7 @@ function peelGlobalOptions(tokens, baseCwd) {
|
|
|
12017
12477
|
if (token === "-C" || token === "--work-tree" || token === "--git-dir" || token === "-c") {
|
|
12018
12478
|
const value = tokens[index + 1];
|
|
12019
12479
|
if (token === "-C" && value) {
|
|
12020
|
-
effectiveCwd =
|
|
12480
|
+
effectiveCwd = path38.resolve(baseCwd, value);
|
|
12021
12481
|
} else if (token === "--work-tree" && value) {
|
|
12022
12482
|
workTree = value;
|
|
12023
12483
|
} else if (token === "--git-dir" && value) {
|
|
@@ -12027,7 +12487,7 @@ function peelGlobalOptions(tokens, baseCwd) {
|
|
|
12027
12487
|
continue;
|
|
12028
12488
|
}
|
|
12029
12489
|
if (token.startsWith("-C") && token.length > 2) {
|
|
12030
|
-
effectiveCwd =
|
|
12490
|
+
effectiveCwd = path38.resolve(baseCwd, token.slice(2));
|
|
12031
12491
|
index += 1;
|
|
12032
12492
|
continue;
|
|
12033
12493
|
}
|
|
@@ -12170,7 +12630,7 @@ function looksLikeDiffPathOperand(token) {
|
|
|
12170
12630
|
if (!looksLikeFileOperand(token)) {
|
|
12171
12631
|
return false;
|
|
12172
12632
|
}
|
|
12173
|
-
if (token.startsWith(".") ||
|
|
12633
|
+
if (token.startsWith(".") || path38.isAbsolute(token)) {
|
|
12174
12634
|
return true;
|
|
12175
12635
|
}
|
|
12176
12636
|
return token.includes(".");
|
|
@@ -12178,12 +12638,12 @@ function looksLikeDiffPathOperand(token) {
|
|
|
12178
12638
|
function resolveGitWorkTree(baseCwd, effectiveCwd, workTree, gitDir) {
|
|
12179
12639
|
const resolveBase = effectiveCwd ?? baseCwd;
|
|
12180
12640
|
if (workTree) {
|
|
12181
|
-
return
|
|
12641
|
+
return path38.resolve(resolveBase, workTree);
|
|
12182
12642
|
}
|
|
12183
12643
|
if (gitDir) {
|
|
12184
|
-
const resolvedGitDir =
|
|
12185
|
-
if (
|
|
12186
|
-
return
|
|
12644
|
+
const resolvedGitDir = path38.resolve(resolveBase, gitDir);
|
|
12645
|
+
if (path38.basename(resolvedGitDir) === ".git") {
|
|
12646
|
+
return path38.dirname(resolvedGitDir);
|
|
12187
12647
|
}
|
|
12188
12648
|
}
|
|
12189
12649
|
return void 0;
|
|
@@ -12264,7 +12724,7 @@ function classifyGitCommand(tokens, baseCwd) {
|
|
|
12264
12724
|
const { subcommand, args, effectiveCwd, gitDir, workTree } = normalized;
|
|
12265
12725
|
const normalizedKey = `git ${subcommand}`;
|
|
12266
12726
|
const gitWorkTree = resolveGitWorkTree(baseCwd, effectiveCwd, workTree, gitDir);
|
|
12267
|
-
const effectiveGitDir = gitDir ?
|
|
12727
|
+
const effectiveGitDir = gitDir ? path38.resolve(effectiveCwd ?? baseCwd, gitDir) : void 0;
|
|
12268
12728
|
const scopeTargets = [effectiveCwd, gitWorkTree, effectiveGitDir].filter(
|
|
12269
12729
|
(target, index, targets) => Boolean(target) && targets.indexOf(target) === index
|
|
12270
12730
|
);
|
|
@@ -12416,9 +12876,9 @@ function decodeGitEffects(params) {
|
|
|
12416
12876
|
...subcommand === "push" ? ["tier0_external"] : []
|
|
12417
12877
|
];
|
|
12418
12878
|
const effectiveCwd = normalized.effectiveCwd ?? params.cwd;
|
|
12419
|
-
const workTreeRoot = normalized.workTree ?
|
|
12420
|
-
const gitRefRoot = normalized.gitDir ?
|
|
12421
|
-
const gitControlRoot = normalized.gitDir ? gitRefRoot :
|
|
12879
|
+
const workTreeRoot = normalized.workTree ? path38.resolve(normalized.effectiveCwd ?? params.cwd, normalized.workTree) : normalized.effectiveCwd ?? params.repoRoot;
|
|
12880
|
+
const gitRefRoot = normalized.gitDir ? path38.resolve(effectiveCwd, normalized.gitDir) : workTreeRoot;
|
|
12881
|
+
const gitControlRoot = normalized.gitDir ? gitRefRoot : path38.join(gitRefRoot, ".git");
|
|
12422
12882
|
const requirements = [];
|
|
12423
12883
|
if (subcommand === "fetch" || subcommand === "pull") {
|
|
12424
12884
|
const positionals = gitRemotePositionals(args);
|
|
@@ -12577,7 +13037,7 @@ function decodeGitEffects(params) {
|
|
|
12577
13037
|
gitRequirement(
|
|
12578
13038
|
"control_plane.write",
|
|
12579
13039
|
"control_plane.write",
|
|
12580
|
-
{ kind: "path", path:
|
|
13040
|
+
{ kind: "path", path: path38.join(gitControlRoot, "logs") },
|
|
12581
13041
|
params.segment,
|
|
12582
13042
|
[...signals, "git_history_destructive", "git.reflog.mutate"]
|
|
12583
13043
|
)
|
|
@@ -12635,7 +13095,7 @@ function decodeGitEffects(params) {
|
|
|
12635
13095
|
gitRequirement(
|
|
12636
13096
|
"fs.read",
|
|
12637
13097
|
"fs.read",
|
|
12638
|
-
{ kind: "path", path:
|
|
13098
|
+
{ kind: "path", path: path38.resolve(workTreeRoot, operand) },
|
|
12639
13099
|
params.segment,
|
|
12640
13100
|
[...signals, "git.path.read"]
|
|
12641
13101
|
)
|
|
@@ -12670,7 +13130,7 @@ function decodeGitEffects(params) {
|
|
|
12670
13130
|
gitRequirement(
|
|
12671
13131
|
"fs.write",
|
|
12672
13132
|
"fs.write",
|
|
12673
|
-
{ kind: "path", path:
|
|
13133
|
+
{ kind: "path", path: path38.resolve(workTreeRoot, operand) },
|
|
12674
13134
|
params.segment,
|
|
12675
13135
|
[...signals, "git.path.write"]
|
|
12676
13136
|
)
|
|
@@ -12855,7 +13315,7 @@ function gitRequirement(tag, action, resource, segment, signals) {
|
|
|
12855
13315
|
|
|
12856
13316
|
// src/core/verdict/launcher-resolve.ts
|
|
12857
13317
|
import { existsSync as existsSync11, readFileSync as readFileSync5 } from "node:fs";
|
|
12858
|
-
import
|
|
13318
|
+
import path39 from "node:path";
|
|
12859
13319
|
|
|
12860
13320
|
// src/core/verdict/makefile-expand.ts
|
|
12861
13321
|
var MAX_EXPAND_DEPTH = 16;
|
|
@@ -12874,22 +13334,6 @@ function parseMakefileVariables(content) {
|
|
|
12874
13334
|
}
|
|
12875
13335
|
return variables;
|
|
12876
13336
|
}
|
|
12877
|
-
function parsePhonyTargets(content) {
|
|
12878
|
-
const phony = /* @__PURE__ */ new Set();
|
|
12879
|
-
for (const line of content.split("\n")) {
|
|
12880
|
-
const trimmed = line.trim();
|
|
12881
|
-
const match = /^\.PHONY:\s*(.+)$/.exec(trimmed);
|
|
12882
|
-
if (!match) {
|
|
12883
|
-
continue;
|
|
12884
|
-
}
|
|
12885
|
-
for (const token of (match[1] ?? "").split(/\s+/)) {
|
|
12886
|
-
if (token) {
|
|
12887
|
-
phony.add(token);
|
|
12888
|
-
}
|
|
12889
|
-
}
|
|
12890
|
-
}
|
|
12891
|
-
return phony;
|
|
12892
|
-
}
|
|
12893
13337
|
function normalizeMakeRecipeLine(line) {
|
|
12894
13338
|
let normalized = line.trim();
|
|
12895
13339
|
while (normalized.startsWith("@") || normalized.startsWith("-") || normalized.startsWith("+")) {
|
|
@@ -13044,7 +13488,7 @@ var PNPM_BUILTIN_COMMANDS = /* @__PURE__ */ new Set([
|
|
|
13044
13488
|
"why"
|
|
13045
13489
|
]);
|
|
13046
13490
|
function readPackageJson(dir) {
|
|
13047
|
-
const packagePath =
|
|
13491
|
+
const packagePath = path39.join(dir, "package.json");
|
|
13048
13492
|
if (!existsSync11(packagePath)) {
|
|
13049
13493
|
return null;
|
|
13050
13494
|
}
|
|
@@ -13055,17 +13499,17 @@ function readPackageJson(dir) {
|
|
|
13055
13499
|
}
|
|
13056
13500
|
}
|
|
13057
13501
|
function findPackageJson(startDir, stopDir) {
|
|
13058
|
-
let current =
|
|
13059
|
-
const stop =
|
|
13502
|
+
let current = path39.resolve(startDir);
|
|
13503
|
+
const stop = path39.resolve(stopDir);
|
|
13060
13504
|
while (true) {
|
|
13061
|
-
const packagePath =
|
|
13505
|
+
const packagePath = path39.join(current, "package.json");
|
|
13062
13506
|
if (existsSync11(packagePath)) {
|
|
13063
13507
|
return packagePath;
|
|
13064
13508
|
}
|
|
13065
|
-
if (current === stop || current ===
|
|
13509
|
+
if (current === stop || current === path39.dirname(current)) {
|
|
13066
13510
|
return existsSync11(packagePath) ? packagePath : null;
|
|
13067
13511
|
}
|
|
13068
|
-
const parent =
|
|
13512
|
+
const parent = path39.dirname(current);
|
|
13069
13513
|
if (!parent.startsWith(stop) && parent !== current) {
|
|
13070
13514
|
}
|
|
13071
13515
|
if (parent === current) {
|
|
@@ -13122,7 +13566,7 @@ function resolveNpmRecipe(cwd, repoRoot, scriptName, extraArgs) {
|
|
|
13122
13566
|
}
|
|
13123
13567
|
return { recipes: [], opaque: true, reason: "package_json_missing" };
|
|
13124
13568
|
}
|
|
13125
|
-
const pkg = readPackageJson(
|
|
13569
|
+
const pkg = readPackageJson(path39.dirname(packagePath));
|
|
13126
13570
|
const scripts = pkg?.scripts;
|
|
13127
13571
|
if (!scripts || typeof scripts !== "object") {
|
|
13128
13572
|
return { recipes: [], opaque: true, reason: "package_scripts_missing" };
|
|
@@ -13213,27 +13657,26 @@ function parseMakefileRecipeContent(content) {
|
|
|
13213
13657
|
function resolveMakeRecipe(cwd, repoRoot, target, cliVars = {}) {
|
|
13214
13658
|
const candidates = ["Makefile", "makefile", "GNUmakefile"];
|
|
13215
13659
|
let makefilePath = null;
|
|
13216
|
-
let searchDir =
|
|
13217
|
-
const stop =
|
|
13660
|
+
let searchDir = path39.resolve(cwd);
|
|
13661
|
+
const stop = path39.resolve(repoRoot);
|
|
13218
13662
|
while (true) {
|
|
13219
13663
|
for (const name of candidates) {
|
|
13220
|
-
const candidate =
|
|
13664
|
+
const candidate = path39.join(searchDir, name);
|
|
13221
13665
|
if (existsSync11(candidate)) {
|
|
13222
13666
|
makefilePath = candidate;
|
|
13223
13667
|
break;
|
|
13224
13668
|
}
|
|
13225
13669
|
}
|
|
13226
|
-
if (makefilePath || searchDir === stop || searchDir ===
|
|
13670
|
+
if (makefilePath || searchDir === stop || searchDir === path39.dirname(searchDir)) {
|
|
13227
13671
|
break;
|
|
13228
13672
|
}
|
|
13229
|
-
searchDir =
|
|
13673
|
+
searchDir = path39.dirname(searchDir);
|
|
13230
13674
|
}
|
|
13231
13675
|
if (!makefilePath) {
|
|
13232
13676
|
return { recipes: [], opaque: true, reason: "unknown_local_effect" };
|
|
13233
13677
|
}
|
|
13234
13678
|
const makefileContent = readFileSync5(makefilePath, "utf8");
|
|
13235
13679
|
const makefileVars = parseMakefileVariables(makefileContent);
|
|
13236
|
-
const phonyTargets = parsePhonyTargets(makefileContent);
|
|
13237
13680
|
const targets = parseMakefileRecipeContent(makefileContent);
|
|
13238
13681
|
if (!targets.has(target)) {
|
|
13239
13682
|
return { recipes: [], opaque: true, reason: "make_target_undefined" };
|
|
@@ -13241,36 +13684,34 @@ function resolveMakeRecipe(cwd, repoRoot, target, cliVars = {}) {
|
|
|
13241
13684
|
const recipeLines = [];
|
|
13242
13685
|
const visiting = /* @__PURE__ */ new Set();
|
|
13243
13686
|
const visited = /* @__PURE__ */ new Set();
|
|
13244
|
-
let
|
|
13687
|
+
let hasDynamicPrerequisite = false;
|
|
13688
|
+
let hasUndefinedPrerequisite = false;
|
|
13689
|
+
let hasDependencyCycle = false;
|
|
13245
13690
|
const collect = (name) => {
|
|
13246
13691
|
if (visited.has(name)) {
|
|
13247
|
-
return
|
|
13692
|
+
return;
|
|
13248
13693
|
}
|
|
13249
13694
|
if (visiting.has(name)) {
|
|
13250
|
-
|
|
13695
|
+
hasDependencyCycle = true;
|
|
13696
|
+
return;
|
|
13251
13697
|
}
|
|
13252
13698
|
const entry = targets.get(name);
|
|
13253
13699
|
if (!entry) {
|
|
13254
|
-
|
|
13700
|
+
if (!existsSync11(path39.resolve(path39.dirname(makefilePath), name))) {
|
|
13701
|
+
hasUndefinedPrerequisite = true;
|
|
13702
|
+
}
|
|
13703
|
+
return;
|
|
13255
13704
|
}
|
|
13256
13705
|
visiting.add(name);
|
|
13257
|
-
|
|
13706
|
+
hasDynamicPrerequisite ||= entry.opaquePrerequisites;
|
|
13258
13707
|
for (const prerequisite of entry.prerequisites) {
|
|
13259
|
-
|
|
13260
|
-
return false;
|
|
13261
|
-
}
|
|
13262
|
-
}
|
|
13263
|
-
const skipPhonyPrerequisiteRecipes = name !== target && (phonyTargets.has(name) || name.startsWith("_")) && (targets.get(target)?.recipes.length ?? 0) > 0;
|
|
13264
|
-
if (!skipPhonyPrerequisiteRecipes) {
|
|
13265
|
-
recipeLines.push(...entry.recipes);
|
|
13708
|
+
collect(prerequisite);
|
|
13266
13709
|
}
|
|
13710
|
+
recipeLines.push(...entry.recipes);
|
|
13267
13711
|
visiting.delete(name);
|
|
13268
13712
|
visited.add(name);
|
|
13269
|
-
return true;
|
|
13270
13713
|
};
|
|
13271
|
-
|
|
13272
|
-
return { recipes: recipeLines, opaque: true, reason: "make_dependency_cycle" };
|
|
13273
|
-
}
|
|
13714
|
+
collect(target);
|
|
13274
13715
|
const expandedRecipes = [];
|
|
13275
13716
|
for (const line of recipeLines) {
|
|
13276
13717
|
const normalized = normalizeMakeRecipeLine(line);
|
|
@@ -13285,18 +13726,24 @@ function resolveMakeRecipe(cwd, repoRoot, target, cliVars = {}) {
|
|
|
13285
13726
|
return { recipes: expandedRecipes, opaque: true, reason: "make_recipe_dynamic" };
|
|
13286
13727
|
}
|
|
13287
13728
|
}
|
|
13288
|
-
if (
|
|
13729
|
+
if (hasDependencyCycle) {
|
|
13730
|
+
return { recipes: expandedRecipes, opaque: true, reason: "make_dependency_cycle" };
|
|
13731
|
+
}
|
|
13732
|
+
if (hasDynamicPrerequisite) {
|
|
13289
13733
|
return { recipes: expandedRecipes, opaque: true, reason: "make_prerequisite_dynamic" };
|
|
13290
13734
|
}
|
|
13735
|
+
if (hasUndefinedPrerequisite) {
|
|
13736
|
+
return { recipes: expandedRecipes, opaque: true, reason: "make_prerequisite_undefined" };
|
|
13737
|
+
}
|
|
13291
13738
|
return { recipes: expandedRecipes, opaque: false, reason: "make_recipe_resolved" };
|
|
13292
13739
|
}
|
|
13293
13740
|
function resolveLauncherRecipe(params) {
|
|
13294
|
-
if (params.depth >= MAX_RESOLVE_DEPTH) {
|
|
13295
|
-
return { recipes: [], opaque: true, reason: "launcher_depth_exceeded" };
|
|
13296
|
-
}
|
|
13297
13741
|
const tokens = params.tokens;
|
|
13298
13742
|
const scriptName = npmScriptName(tokens);
|
|
13299
13743
|
if (scriptName) {
|
|
13744
|
+
if (params.depth >= MAX_RESOLVE_DEPTH) {
|
|
13745
|
+
return { recipes: [], opaque: true, reason: "launcher_depth_exceeded" };
|
|
13746
|
+
}
|
|
13300
13747
|
const resolution = resolveNpmRecipe(
|
|
13301
13748
|
params.cwd,
|
|
13302
13749
|
params.repoRoot,
|
|
@@ -13313,6 +13760,9 @@ function resolveLauncherRecipe(params) {
|
|
|
13313
13760
|
return resolution;
|
|
13314
13761
|
}
|
|
13315
13762
|
if (tokens[0] === "make") {
|
|
13763
|
+
if (params.depth >= MAX_RESOLVE_DEPTH) {
|
|
13764
|
+
return { recipes: [], opaque: true, reason: "launcher_depth_exceeded" };
|
|
13765
|
+
}
|
|
13316
13766
|
if (tokens.includes("-n") || tokens.includes("--dry-run")) {
|
|
13317
13767
|
return null;
|
|
13318
13768
|
}
|
|
@@ -13346,7 +13796,7 @@ function resolveLauncherRecipe(params) {
|
|
|
13346
13796
|
}
|
|
13347
13797
|
|
|
13348
13798
|
// src/core/verdict/parser.ts
|
|
13349
|
-
import
|
|
13799
|
+
import path40 from "node:path";
|
|
13350
13800
|
|
|
13351
13801
|
// src/core/shell-substitution.ts
|
|
13352
13802
|
function findStructuralCommandSubstitutions(command) {
|
|
@@ -13571,9 +14021,8 @@ function hasUnbalancedDollarParen(command) {
|
|
|
13571
14021
|
// src/core/verdict/parser.ts
|
|
13572
14022
|
var ENV_PREFIX_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*=(?:'[^']*'|"[^"]*"|\S+)$/;
|
|
13573
14023
|
var MAX_WRAPPER_PEEL_DEPTH = 32;
|
|
13574
|
-
var
|
|
14024
|
+
var SHELL_INTERPRETERS2 = /* @__PURE__ */ new Set(["bash", "sh", "zsh", "dash", "fish"]);
|
|
13575
14025
|
var CODE_INTERPRETERS = /* @__PURE__ */ new Set(["python", "python3", "node", "ruby", "perl", "osascript"]);
|
|
13576
|
-
var SCRIPT_FLAGS = /* @__PURE__ */ new Set(["-c", "-lc", "-e", "--eval"]);
|
|
13577
14026
|
var INTERPRETER_SCRIPT_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
13578
14027
|
".js",
|
|
13579
14028
|
".mjs",
|
|
@@ -13585,7 +14034,7 @@ var INTERPRETER_SCRIPT_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
|
13585
14034
|
".sh"
|
|
13586
14035
|
]);
|
|
13587
14036
|
function normalizeHead(token) {
|
|
13588
|
-
const base =
|
|
14037
|
+
const base = path40.basename(token);
|
|
13589
14038
|
if (base && base !== "." && base !== "..") {
|
|
13590
14039
|
return base;
|
|
13591
14040
|
}
|
|
@@ -13597,10 +14046,6 @@ function peelTransparentWrappers(tokens) {
|
|
|
13597
14046
|
let encounteredXargs = false;
|
|
13598
14047
|
let peelDepth = 0;
|
|
13599
14048
|
while (current.length > 0) {
|
|
13600
|
-
if (peelDepth >= MAX_WRAPPER_PEEL_DEPTH) {
|
|
13601
|
-
return { tokens: current, xargsStdinOpaque: false, encounteredXargs, opaque: true };
|
|
13602
|
-
}
|
|
13603
|
-
peelDepth += 1;
|
|
13604
14049
|
while (current.length > 0 && ENV_PREFIX_PATTERN.test(current[0] ?? "")) {
|
|
13605
14050
|
current.shift();
|
|
13606
14051
|
}
|
|
@@ -13610,6 +14055,10 @@ function peelTransparentWrappers(tokens) {
|
|
|
13610
14055
|
const head = normalizeHead(current[0] ?? "");
|
|
13611
14056
|
if (head === "xargs") {
|
|
13612
14057
|
encounteredXargs = true;
|
|
14058
|
+
if (peelDepth >= MAX_WRAPPER_PEEL_DEPTH) {
|
|
14059
|
+
return { tokens: current, xargsStdinOpaque: false, encounteredXargs, opaque: true };
|
|
14060
|
+
}
|
|
14061
|
+
peelDepth += 1;
|
|
13613
14062
|
const wrapper2 = peelXargsWrapper(current);
|
|
13614
14063
|
if (wrapper2.kind === "opaque") {
|
|
13615
14064
|
xargsStdinOpaque = current.length === 1;
|
|
@@ -13627,6 +14076,10 @@ function peelTransparentWrappers(tokens) {
|
|
|
13627
14076
|
if (!wrapper) {
|
|
13628
14077
|
break;
|
|
13629
14078
|
}
|
|
14079
|
+
if (peelDepth >= MAX_WRAPPER_PEEL_DEPTH) {
|
|
14080
|
+
return { tokens: current, xargsStdinOpaque: false, encounteredXargs, opaque: true };
|
|
14081
|
+
}
|
|
14082
|
+
peelDepth += 1;
|
|
13630
14083
|
if (wrapper.kind === "opaque") {
|
|
13631
14084
|
return { tokens: current, xargsStdinOpaque: false, encounteredXargs, opaque: true };
|
|
13632
14085
|
}
|
|
@@ -13854,50 +14307,16 @@ function extractRecursiveScript(tokens) {
|
|
|
13854
14307
|
const body = filtered.slice(1).join(" ").trim();
|
|
13855
14308
|
return body || null;
|
|
13856
14309
|
}
|
|
13857
|
-
|
|
13858
|
-
|
|
13859
|
-
|
|
13860
|
-
|
|
13861
|
-
return body || null;
|
|
13862
|
-
}
|
|
13863
|
-
}
|
|
13864
|
-
return null;
|
|
13865
|
-
}
|
|
13866
|
-
function extractDockerComposeRunScript(tokens) {
|
|
13867
|
-
const head = normalizeHead(tokens[0] ?? "");
|
|
13868
|
-
const usesCompose = head === "docker-compose" || head === "docker" && (tokens[1] ?? "") === "compose";
|
|
13869
|
-
if (!usesCompose) {
|
|
13870
|
-
return null;
|
|
13871
|
-
}
|
|
13872
|
-
if (!tokens.includes("run")) {
|
|
13873
|
-
return null;
|
|
13874
|
-
}
|
|
13875
|
-
const runIndex = tokens.indexOf("run");
|
|
13876
|
-
const tail = tokens.slice(runIndex + 1);
|
|
13877
|
-
for (let index = 0; index < tail.length; index += 1) {
|
|
13878
|
-
const shellHead = normalizeHead(tail[index] ?? "");
|
|
13879
|
-
if (!SHELL_INTERPRETERS.has(shellHead)) {
|
|
13880
|
-
continue;
|
|
13881
|
-
}
|
|
13882
|
-
const flag = tail[index + 1] ?? "";
|
|
13883
|
-
if (flag !== "-lc" && flag !== "-c") {
|
|
13884
|
-
continue;
|
|
13885
|
-
}
|
|
13886
|
-
const body = tail[index + 2] ?? "";
|
|
13887
|
-
return body || null;
|
|
13888
|
-
}
|
|
13889
|
-
return null;
|
|
14310
|
+
const invocation = decodeRecursiveInvocation(
|
|
14311
|
+
shellTokensFromValues(filtered, { detectExpansion: false })
|
|
14312
|
+
);
|
|
14313
|
+
return invocation.kind === "static" ? invocation.script || null : null;
|
|
13890
14314
|
}
|
|
13891
|
-
function
|
|
13892
|
-
const
|
|
13893
|
-
|
|
13894
|
-
|
|
13895
|
-
|
|
13896
|
-
const head = normalizeHead(filtered[0] ?? "");
|
|
13897
|
-
if (head === "eval") {
|
|
13898
|
-
return true;
|
|
13899
|
-
}
|
|
13900
|
-
return (SHELL_INTERPRETERS.has(head) || CODE_INTERPRETERS.has(head)) && filtered.some((token) => SCRIPT_FLAGS.has(token));
|
|
14315
|
+
function decodeRecursiveInvocationTokens(tokens) {
|
|
14316
|
+
const values = tokens.map((token) => token.value);
|
|
14317
|
+
const { tokens: filtered, opaque } = peelTransparentWrappers(values);
|
|
14318
|
+
if (opaque) return { kind: "none" };
|
|
14319
|
+
return decodeRecursiveInvocation(tokens.slice(values.length - filtered.length));
|
|
13901
14320
|
}
|
|
13902
14321
|
function isCommandInspection(tokens) {
|
|
13903
14322
|
return normalizeHead(tokens[0] ?? "") === "command" && peelCommandWrapper(tokens).kind === "preserve";
|
|
@@ -13911,11 +14330,10 @@ function isBareInterpreter(tokens) {
|
|
|
13911
14330
|
return false;
|
|
13912
14331
|
}
|
|
13913
14332
|
const head = normalizeHead(peeled[0] ?? "");
|
|
13914
|
-
if (!
|
|
14333
|
+
if (!SHELL_INTERPRETERS2.has(head) && !CODE_INTERPRETERS.has(head)) {
|
|
13915
14334
|
return false;
|
|
13916
14335
|
}
|
|
13917
|
-
|
|
13918
|
-
if (hasScriptFlag) {
|
|
14336
|
+
if (decodeRecursiveInvocation(shellTokensFromValues(peeled)).kind !== "none") {
|
|
13919
14337
|
return false;
|
|
13920
14338
|
}
|
|
13921
14339
|
const args = peeled.slice(1);
|
|
@@ -13926,7 +14344,7 @@ function isBareInterpreter(tokens) {
|
|
|
13926
14344
|
return false;
|
|
13927
14345
|
}
|
|
13928
14346
|
const scriptArg = args.find((token) => !token.startsWith("-"));
|
|
13929
|
-
if (scriptArg && INTERPRETER_SCRIPT_EXTENSIONS.has(
|
|
14347
|
+
if (scriptArg && INTERPRETER_SCRIPT_EXTENSIONS.has(path40.extname(scriptArg))) {
|
|
13930
14348
|
return false;
|
|
13931
14349
|
}
|
|
13932
14350
|
if (scriptArg) {
|
|
@@ -14218,11 +14636,11 @@ function lowerTopLevelSegments(command, context) {
|
|
|
14218
14636
|
}
|
|
14219
14637
|
function startsLocalPostgresService(command) {
|
|
14220
14638
|
const tokens = tokenizeShell(command);
|
|
14221
|
-
return
|
|
14639
|
+
return path41.basename(tokens[0] ?? "") === "docker" && tokens[1] === "compose" && ["up", "start", "restart"].includes(tokens[2] ?? "") && tokens.includes("postgres");
|
|
14222
14640
|
}
|
|
14223
14641
|
function resolveCdTransition(command, currentCwd) {
|
|
14224
14642
|
const tokens = tokenizeShell(command);
|
|
14225
|
-
if (
|
|
14643
|
+
if (path41.basename(tokens[0] ?? "") !== "cd") {
|
|
14226
14644
|
return null;
|
|
14227
14645
|
}
|
|
14228
14646
|
const target = tokens[1] ?? "~";
|
|
@@ -14243,7 +14661,8 @@ function joinNestedOpacity(outer, nested) {
|
|
|
14243
14661
|
}
|
|
14244
14662
|
function lowerSegment(command, context) {
|
|
14245
14663
|
const commandRedacted = redactCommand(command);
|
|
14246
|
-
const
|
|
14664
|
+
const lexed = lexShell(command);
|
|
14665
|
+
const rawTokens = lexed.tokens.map((token) => token.value);
|
|
14247
14666
|
const environment = extractEnvironment(rawTokens, context.env);
|
|
14248
14667
|
const env = environment.env;
|
|
14249
14668
|
const parsed = parseSegment(command);
|
|
@@ -14251,10 +14670,23 @@ function lowerSegment(command, context) {
|
|
|
14251
14670
|
const tokens = stripRedirects(
|
|
14252
14671
|
parsedTokens.length === 0 && rawTokens.length > 0 && rawTokens.every((token) => ENV_PREFIX_PATTERN2.test(token)) ? rawTokens : parsedTokens
|
|
14253
14672
|
).map((token) => expandKnownVariables(token, env));
|
|
14254
|
-
const
|
|
14673
|
+
const decoderTokens = alignStructuredTokens(
|
|
14674
|
+
stripStructuredRedirects(lexed.tokens),
|
|
14675
|
+
stripRedirects(parsedTokens)
|
|
14676
|
+
);
|
|
14677
|
+
const head = path41.basename(tokens[0] ?? parsed.head);
|
|
14255
14678
|
let opacity = segmentOpacity(command);
|
|
14256
14679
|
const signals = /* @__PURE__ */ new Set();
|
|
14257
14680
|
const requirements = [];
|
|
14681
|
+
if (!lexed.complete) {
|
|
14682
|
+
requirements.push(
|
|
14683
|
+
requirement2("indeterminate", "indeterminate", { kind: "unknown" }, commandRedacted, [
|
|
14684
|
+
"shell.grammar_incomplete"
|
|
14685
|
+
])
|
|
14686
|
+
);
|
|
14687
|
+
signals.add("shell.grammar_incomplete");
|
|
14688
|
+
opacity = joinEffectOpacity(opacity, "unparseable");
|
|
14689
|
+
}
|
|
14258
14690
|
addRedirectEffects(requirements, rawTokens, env, context, commandRedacted);
|
|
14259
14691
|
addSubstitutionEffects(requirements, command, context, commandRedacted, signals);
|
|
14260
14692
|
if (environment.malformed) {
|
|
@@ -14274,7 +14706,7 @@ function lowerSegment(command, context) {
|
|
|
14274
14706
|
signals.add("shell.xargs_stdin_dynamic");
|
|
14275
14707
|
opacity = joinEffectOpacity(opacity, "opaque");
|
|
14276
14708
|
}
|
|
14277
|
-
if (context.depth
|
|
14709
|
+
if (context.depth > MAX_LOWER_DEPTH) {
|
|
14278
14710
|
requirements.push(
|
|
14279
14711
|
requirement2("indeterminate", "indeterminate", { kind: "unknown" }, commandRedacted, [
|
|
14280
14712
|
"shell.lower_depth_exceeded"
|
|
@@ -14321,62 +14753,96 @@ function lowerSegment(command, context) {
|
|
|
14321
14753
|
}
|
|
14322
14754
|
return shellSegment(commandRedacted, head, requirements, opacity, signals);
|
|
14323
14755
|
}
|
|
14324
|
-
const
|
|
14325
|
-
if (
|
|
14326
|
-
const dynamicEvaluation = isDynamicRecursiveEvaluation(tokens);
|
|
14756
|
+
const recursive = decodeRecursiveInvocationTokens(decoderTokens);
|
|
14757
|
+
if (recursive.kind === "static" && opacity !== "opaque" && opacity !== "unparseable") {
|
|
14327
14758
|
requirements.push(
|
|
14328
|
-
processRequirement(
|
|
14759
|
+
processRequirement(recursive.interpreter, "spawn", commandRedacted, [
|
|
14329
14760
|
"shell.recursive_wrapper",
|
|
14330
|
-
|
|
14761
|
+
"dynamic_shell_evaluation"
|
|
14331
14762
|
])
|
|
14332
14763
|
);
|
|
14333
|
-
|
|
14334
|
-
|
|
14335
|
-
|
|
14336
|
-
|
|
14337
|
-
|
|
14338
|
-
|
|
14339
|
-
|
|
14340
|
-
|
|
14341
|
-
|
|
14342
|
-
(
|
|
14343
|
-
|
|
14344
|
-
|
|
14345
|
-
|
|
14346
|
-
signals.add(signal);
|
|
14764
|
+
if (recursive.script !== "") {
|
|
14765
|
+
const nested = lowerTopLevelSegments(recursive.script, {
|
|
14766
|
+
...context,
|
|
14767
|
+
command: recursive.script,
|
|
14768
|
+
env,
|
|
14769
|
+
depth: context.depth + 1
|
|
14770
|
+
});
|
|
14771
|
+
for (const nestedSegment of nested) {
|
|
14772
|
+
requirements.push(
|
|
14773
|
+
...nestedSegment.requirements.map(
|
|
14774
|
+
(entry) => withInnerProvenance(entry, recursive.script, head, commandRedacted)
|
|
14775
|
+
)
|
|
14776
|
+
);
|
|
14777
|
+
for (const signal of nestedSegment.signals) signals.add(signal);
|
|
14347
14778
|
}
|
|
14348
14779
|
}
|
|
14349
14780
|
signals.add("shell.recursive_wrapper");
|
|
14350
|
-
|
|
14351
|
-
signals.add("dynamic_shell_evaluation");
|
|
14352
|
-
}
|
|
14781
|
+
signals.add("dynamic_shell_evaluation");
|
|
14353
14782
|
return shellSegment(commandRedacted, head, requirements, "recursive", signals);
|
|
14354
14783
|
}
|
|
14355
|
-
|
|
14356
|
-
|
|
14784
|
+
if (recursive.kind === "dynamic" || recursive.kind === "indeterminate") {
|
|
14785
|
+
const recursiveSignals = [
|
|
14786
|
+
recursive.signal,
|
|
14787
|
+
...recursive.kind === "dynamic" ? ["dynamic_shell_evaluation"] : []
|
|
14788
|
+
];
|
|
14789
|
+
requirements.push(
|
|
14790
|
+
processRequirement(recursive.interpreter, "spawn", commandRedacted, recursiveSignals),
|
|
14791
|
+
requirement2("indeterminate", "indeterminate", { kind: "unknown" }, commandRedacted, [
|
|
14792
|
+
...recursiveSignals
|
|
14793
|
+
])
|
|
14794
|
+
);
|
|
14795
|
+
for (const signal of recursiveSignals) signals.add(signal);
|
|
14796
|
+
return shellSegment(
|
|
14797
|
+
commandRedacted,
|
|
14798
|
+
head,
|
|
14799
|
+
requirements,
|
|
14800
|
+
joinEffectOpacity(opacity, "opaque"),
|
|
14801
|
+
signals
|
|
14802
|
+
);
|
|
14803
|
+
}
|
|
14804
|
+
const compose = decodeDockerComposeRun(decoderTokens);
|
|
14805
|
+
if (compose.kind === "recursive" && opacity !== "opaque" && opacity !== "unparseable") {
|
|
14357
14806
|
requirements.push(
|
|
14358
14807
|
processRequirement(head, "spawn", commandRedacted, ["process.docker_compose_run"])
|
|
14359
14808
|
);
|
|
14360
|
-
|
|
14361
|
-
|
|
14362
|
-
|
|
14363
|
-
|
|
14364
|
-
|
|
14365
|
-
|
|
14366
|
-
|
|
14367
|
-
|
|
14368
|
-
|
|
14369
|
-
(
|
|
14370
|
-
|
|
14371
|
-
|
|
14372
|
-
|
|
14373
|
-
signals.add(signal);
|
|
14809
|
+
if (compose.script !== "") {
|
|
14810
|
+
const nested = lowerTopLevelSegments(compose.script, {
|
|
14811
|
+
...context,
|
|
14812
|
+
command: compose.script,
|
|
14813
|
+
env,
|
|
14814
|
+
depth: context.depth + 1
|
|
14815
|
+
});
|
|
14816
|
+
for (const nestedSegment of nested) {
|
|
14817
|
+
requirements.push(
|
|
14818
|
+
...nestedSegment.requirements.map(
|
|
14819
|
+
(entry) => withInnerProvenance(entry, compose.script, head, commandRedacted)
|
|
14820
|
+
)
|
|
14821
|
+
);
|
|
14822
|
+
for (const signal of nestedSegment.signals) signals.add(signal);
|
|
14823
|
+
opacity = joinNestedOpacity(opacity, nestedSegment);
|
|
14374
14824
|
}
|
|
14375
|
-
opacity = joinNestedOpacity(opacity, nestedSegment);
|
|
14376
14825
|
}
|
|
14377
14826
|
signals.add("process.docker_compose_run");
|
|
14378
14827
|
return shellSegment(commandRedacted, head, requirements, "recursive", signals);
|
|
14379
14828
|
}
|
|
14829
|
+
if (compose.kind === "dynamic" || compose.kind === "indeterminate") {
|
|
14830
|
+
requirements.push(
|
|
14831
|
+
processRequirement(head, "spawn", commandRedacted, ["process.docker_compose_run"]),
|
|
14832
|
+
requirement2("indeterminate", "indeterminate", { kind: "unknown" }, commandRedacted, [
|
|
14833
|
+
compose.signal
|
|
14834
|
+
])
|
|
14835
|
+
);
|
|
14836
|
+
signals.add("process.docker_compose_run");
|
|
14837
|
+
signals.add(compose.signal);
|
|
14838
|
+
return shellSegment(
|
|
14839
|
+
commandRedacted,
|
|
14840
|
+
head,
|
|
14841
|
+
requirements,
|
|
14842
|
+
joinEffectOpacity(opacity, "opaque"),
|
|
14843
|
+
signals
|
|
14844
|
+
);
|
|
14845
|
+
}
|
|
14380
14846
|
const launcher = resolveLauncherRecipe({
|
|
14381
14847
|
tokens,
|
|
14382
14848
|
cwd: context.cwd,
|
|
@@ -14588,7 +15054,7 @@ function isMetadataOnlyArgv(argv) {
|
|
|
14588
15054
|
return argv.length > 0 && argv.every((token) => METADATA_ONLY_FLAGS.has(token));
|
|
14589
15055
|
}
|
|
14590
15056
|
function executableBaseName(head) {
|
|
14591
|
-
return
|
|
15057
|
+
return path41.basename(head);
|
|
14592
15058
|
}
|
|
14593
15059
|
var RAILS_READ_ONLY_SUBCOMMANDS = /* @__PURE__ */ new Set(["routes", "middleware", "stats", "about", "version"]);
|
|
14594
15060
|
function railsReadOnlySubcommand(args) {
|
|
@@ -14599,7 +15065,7 @@ function railsReadOnlySubcommand(args) {
|
|
|
14599
15065
|
return RAILS_READ_ONLY_SUBCOMMANDS.has(subcommand);
|
|
14600
15066
|
}
|
|
14601
15067
|
function isRubyTestScript(scriptPath) {
|
|
14602
|
-
const base =
|
|
15068
|
+
const base = path41.basename(scriptPath);
|
|
14603
15069
|
return base.endsWith("_test.rb") || base.endsWith("_spec.rb");
|
|
14604
15070
|
}
|
|
14605
15071
|
function parseRubyTestInvocation(args) {
|
|
@@ -14784,7 +15250,7 @@ function decodeShellControlBuiltin(head, args) {
|
|
|
14784
15250
|
}
|
|
14785
15251
|
return null;
|
|
14786
15252
|
}
|
|
14787
|
-
function
|
|
15253
|
+
function decodeDockerComposeRun2(head, args, segment) {
|
|
14788
15254
|
let composeArgs = null;
|
|
14789
15255
|
let command = head;
|
|
14790
15256
|
if (head === "docker-compose") {
|
|
@@ -14878,7 +15344,7 @@ function decodeProcessOrFilesystem(params) {
|
|
|
14878
15344
|
requirement2(
|
|
14879
15345
|
"fs.read",
|
|
14880
15346
|
"fs.read",
|
|
14881
|
-
{ kind: "path", path:
|
|
15347
|
+
{ kind: "path", path: path41.resolve(cwd, syntax) },
|
|
14882
15348
|
segment,
|
|
14883
15349
|
["shell.syntax_source_read"]
|
|
14884
15350
|
)
|
|
@@ -14902,7 +15368,7 @@ function decodeProcessOrFilesystem(params) {
|
|
|
14902
15368
|
return decoded;
|
|
14903
15369
|
}
|
|
14904
15370
|
}
|
|
14905
|
-
const dockerCompose =
|
|
15371
|
+
const dockerCompose = decodeDockerComposeRun2(head, args, segment);
|
|
14906
15372
|
if (dockerCompose) {
|
|
14907
15373
|
return dockerCompose;
|
|
14908
15374
|
}
|
|
@@ -14928,7 +15394,7 @@ function decodeProcessOrFilesystem(params) {
|
|
|
14928
15394
|
return [processRequirement(head, "inspect", segment, ["process.inspect.base64_stdin"])];
|
|
14929
15395
|
}
|
|
14930
15396
|
if (head === "node") {
|
|
14931
|
-
return
|
|
15397
|
+
return decodeNode2(args, cwd, segment);
|
|
14932
15398
|
}
|
|
14933
15399
|
if (head === "vite" || head === "vite-node") {
|
|
14934
15400
|
return [processRequirement(head, "spawn", segment, ["process.local_dev_spawn"])];
|
|
@@ -15018,7 +15484,7 @@ function decodeBelay(args, repoRoot, segment) {
|
|
|
15018
15484
|
requirement2(
|
|
15019
15485
|
"control_plane.write",
|
|
15020
15486
|
"control_plane.write",
|
|
15021
|
-
{ kind: "path", path:
|
|
15487
|
+
{ kind: "path", path: path41.join(repoRoot, ".belay-control-plane") },
|
|
15022
15488
|
segment,
|
|
15023
15489
|
["belay.config_non_judge_mutation"]
|
|
15024
15490
|
)
|
|
@@ -15180,11 +15646,11 @@ function decodeRm(args, cwd, repoRoot, segment) {
|
|
|
15180
15646
|
function canonicalRmOperand(targetPath, finalOperandIsSymlink) {
|
|
15181
15647
|
try {
|
|
15182
15648
|
if (finalOperandIsSymlink) {
|
|
15183
|
-
return
|
|
15649
|
+
return path41.join(realpathSync4.native(path41.dirname(targetPath)), path41.basename(targetPath));
|
|
15184
15650
|
}
|
|
15185
15651
|
return realpathSync4.native(targetPath);
|
|
15186
15652
|
} catch {
|
|
15187
|
-
return
|
|
15653
|
+
return path41.resolve(targetPath);
|
|
15188
15654
|
}
|
|
15189
15655
|
}
|
|
15190
15656
|
function isSymbolicLink(targetPath) {
|
|
@@ -15195,8 +15661,8 @@ function isSymbolicLink(targetPath) {
|
|
|
15195
15661
|
}
|
|
15196
15662
|
}
|
|
15197
15663
|
function pathContains(ancestor, candidate) {
|
|
15198
|
-
const relative =
|
|
15199
|
-
return relative === "" || !relative.startsWith("..") && !
|
|
15664
|
+
const relative = path41.relative(path41.resolve(ancestor), path41.resolve(candidate));
|
|
15665
|
+
return relative === "" || !relative.startsWith("..") && !path41.isAbsolute(relative);
|
|
15200
15666
|
}
|
|
15201
15667
|
function decodeGo(args, segment) {
|
|
15202
15668
|
if (["test", "list", "vet"].includes(args[0] ?? "")) {
|
|
@@ -15342,7 +15808,7 @@ function decodeSed(args, cwd, segment) {
|
|
|
15342
15808
|
}
|
|
15343
15809
|
return lowered;
|
|
15344
15810
|
}
|
|
15345
|
-
function
|
|
15811
|
+
function decodeNode2(args, cwd, segment) {
|
|
15346
15812
|
if (args.length > 0 && args.every((arg) => ["--help", "--version", "-h", "-v"].includes(arg))) {
|
|
15347
15813
|
return [processRequirement("node", "inspect", segment, ["process.inspect.node_metadata"])];
|
|
15348
15814
|
}
|
|
@@ -15608,15 +16074,36 @@ function stripRedirects(tokens) {
|
|
|
15608
16074
|
stripped.push(token);
|
|
15609
16075
|
continue;
|
|
15610
16076
|
}
|
|
15611
|
-
|
|
15612
|
-
|
|
15613
|
-
|
|
15614
|
-
|
|
15615
|
-
|
|
16077
|
+
index += 1;
|
|
16078
|
+
}
|
|
16079
|
+
return stripped;
|
|
16080
|
+
}
|
|
16081
|
+
function stripStructuredRedirects(tokens) {
|
|
16082
|
+
const stripped = [];
|
|
16083
|
+
for (let index = 0; index < tokens.length; index += 1) {
|
|
16084
|
+
const token = tokens[index];
|
|
16085
|
+
if (!token) continue;
|
|
16086
|
+
if (isFdDuplication(token.value)) {
|
|
16087
|
+
continue;
|
|
16088
|
+
}
|
|
16089
|
+
if (!isRedirectOperator(token.value)) {
|
|
16090
|
+
stripped.push(token);
|
|
16091
|
+
continue;
|
|
15616
16092
|
}
|
|
16093
|
+
index += 1;
|
|
15617
16094
|
}
|
|
15618
16095
|
return stripped;
|
|
15619
16096
|
}
|
|
16097
|
+
function alignStructuredTokens(tokens, values) {
|
|
16098
|
+
if (values.length === 0) return [];
|
|
16099
|
+
for (let start = tokens.length - values.length; start >= 0; start -= 1) {
|
|
16100
|
+
const candidate = tokens.slice(start);
|
|
16101
|
+
if (candidate.length === values.length && candidate.every((token, index) => token.value === values[index])) {
|
|
16102
|
+
return candidate;
|
|
16103
|
+
}
|
|
16104
|
+
}
|
|
16105
|
+
return [];
|
|
16106
|
+
}
|
|
15620
16107
|
function shellSegment(commandRedacted, segmentHead, requirements, opacity, signals) {
|
|
15621
16108
|
const normalizedRequirements = requirements.flatMap((entry) => {
|
|
15622
16109
|
const dynamicSignal = dynamicResourceSignal(entry.resource);
|
|
@@ -16016,9 +16503,9 @@ function resolvePathOperand(operand, cwd) {
|
|
|
16016
16503
|
return process.env.HOME ?? operand;
|
|
16017
16504
|
}
|
|
16018
16505
|
if (operand.startsWith("~/")) {
|
|
16019
|
-
return
|
|
16506
|
+
return path41.join(process.env.HOME ?? "~", operand.slice(2));
|
|
16020
16507
|
}
|
|
16021
|
-
return
|
|
16508
|
+
return path41.resolve(cwd, operand);
|
|
16022
16509
|
}
|
|
16023
16510
|
function isShellHead(head) {
|
|
16024
16511
|
return head === "bash" || head === "sh" || head === "zsh" || head === "dash" || head === "fish";
|
|
@@ -16542,7 +17029,7 @@ async function classifyToolUse(payload, repoRoot, cwd, config, options = {}) {
|
|
|
16542
17029
|
};
|
|
16543
17030
|
}
|
|
16544
17031
|
const signals = [];
|
|
16545
|
-
const resolvedPath =
|
|
17032
|
+
const resolvedPath = path42.isAbsolute(filePath) ? filePath : path42.resolve(cwd, filePath);
|
|
16546
17033
|
const hitsProtectedRoot = protectedRoots.some((root) => pathWithinRoot(root, resolvedPath));
|
|
16547
17034
|
if (hitsProtectedRoot) {
|
|
16548
17035
|
signals.push("control_plane_path");
|
|
@@ -17144,7 +17631,7 @@ function hashDecisionConfig(config) {
|
|
|
17144
17631
|
init_fingerprint2();
|
|
17145
17632
|
|
|
17146
17633
|
// src/version.ts
|
|
17147
|
-
var PACKAGE_VERSION = "0.9.
|
|
17634
|
+
var PACKAGE_VERSION = "0.9.3";
|
|
17148
17635
|
|
|
17149
17636
|
// src/runtime-provenance.ts
|
|
17150
17637
|
function resolveRuntimeArtifactHash(artifactHash) {
|
|
@@ -17219,7 +17706,7 @@ init_path_utils();
|
|
|
17219
17706
|
import { randomUUID as randomUUID5 } from "node:crypto";
|
|
17220
17707
|
import { existsSync as existsSync15 } from "node:fs";
|
|
17221
17708
|
import { mkdir as mkdir11, readdir as readdir3, readFile as readFile12, rename as rename3, rm as rm6 } from "node:fs/promises";
|
|
17222
|
-
import
|
|
17709
|
+
import path47 from "node:path";
|
|
17223
17710
|
|
|
17224
17711
|
// src/core/recovery/artifact-store.ts
|
|
17225
17712
|
init_fingerprint2();
|
|
@@ -17227,7 +17714,7 @@ init_path_utils();
|
|
|
17227
17714
|
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
17228
17715
|
import { existsSync as existsSync13 } from "node:fs";
|
|
17229
17716
|
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";
|
|
17230
|
-
import
|
|
17717
|
+
import path44 from "node:path";
|
|
17231
17718
|
|
|
17232
17719
|
// src/core/recovery/snapshot-node.ts
|
|
17233
17720
|
init_fingerprint2();
|
|
@@ -17247,25 +17734,25 @@ import {
|
|
|
17247
17734
|
symlink as symlink3,
|
|
17248
17735
|
writeFile as writeFile6
|
|
17249
17736
|
} from "node:fs/promises";
|
|
17250
|
-
import
|
|
17737
|
+
import path43 from "node:path";
|
|
17251
17738
|
var RECOVERY_UNSUPPORTED_FILE_KIND = "recovery_unsupported_file_kind";
|
|
17252
17739
|
function validRecoveryRelativePath(relativePath) {
|
|
17253
|
-
if (!relativePath || relativePath.includes("\0") ||
|
|
17254
|
-
const normalized =
|
|
17255
|
-
return normalized !== "." && normalized !== ".." && !normalized.startsWith(`..${
|
|
17740
|
+
if (!relativePath || relativePath.includes("\0") || path43.isAbsolute(relativePath)) return false;
|
|
17741
|
+
const normalized = path43.normalize(relativePath);
|
|
17742
|
+
return normalized !== "." && normalized !== ".." && !normalized.startsWith(`..${path43.sep}`);
|
|
17256
17743
|
}
|
|
17257
17744
|
async function assertRecoverySafeTarget(resourceRoot, relativePath) {
|
|
17258
17745
|
if (!validRecoveryRelativePath(relativePath)) throw new Error("recovery_path_escape");
|
|
17259
17746
|
const root = canonicalPath(resourceRoot);
|
|
17260
|
-
const target =
|
|
17261
|
-
const relative =
|
|
17262
|
-
if (relative === ".." || relative.startsWith(`..${
|
|
17747
|
+
const target = path43.resolve(root, relativePath);
|
|
17748
|
+
const relative = path43.relative(root, target);
|
|
17749
|
+
if (relative === ".." || relative.startsWith(`..${path43.sep}`) || path43.isAbsolute(relative)) {
|
|
17263
17750
|
throw new Error("recovery_path_escape");
|
|
17264
17751
|
}
|
|
17265
17752
|
let current = root;
|
|
17266
|
-
const parentParts =
|
|
17753
|
+
const parentParts = path43.relative(root, path43.dirname(target)).split(path43.sep).filter(Boolean);
|
|
17267
17754
|
for (const part of parentParts) {
|
|
17268
|
-
current =
|
|
17755
|
+
current = path43.join(current, part);
|
|
17269
17756
|
if (!existsSync12(current)) break;
|
|
17270
17757
|
const info = await lstat6(current);
|
|
17271
17758
|
if (info.isSymbolicLink()) throw new Error("recovery_symlink_escape");
|
|
@@ -17321,7 +17808,7 @@ async function captureRecoverySnapshot(filePath, options) {
|
|
|
17321
17808
|
let blob;
|
|
17322
17809
|
if (options?.blobDir) {
|
|
17323
17810
|
await mkdir9(options.blobDir, { recursive: true, mode: 448 });
|
|
17324
|
-
const blobPath =
|
|
17811
|
+
const blobPath = path43.join(options.blobDir, hash);
|
|
17325
17812
|
if (!existsSync12(blobPath)) {
|
|
17326
17813
|
await writeFile6(blobPath, content, { mode: 384 });
|
|
17327
17814
|
await fsyncPath(blobPath);
|
|
@@ -17376,7 +17863,7 @@ async function validateRecoverySnapshot(params) {
|
|
|
17376
17863
|
if (record.blob !== `blobs/${record.hash}`) throw new Error(params.corruptReason);
|
|
17377
17864
|
let content;
|
|
17378
17865
|
try {
|
|
17379
|
-
content = await readFile8(
|
|
17866
|
+
content = await readFile8(path43.join(params.artifactDir, record.blob));
|
|
17380
17867
|
} catch {
|
|
17381
17868
|
throw new Error(params.corruptReason);
|
|
17382
17869
|
}
|
|
@@ -17404,13 +17891,13 @@ var RECOVERY_STATES = /* @__PURE__ */ new Set([
|
|
|
17404
17891
|
]);
|
|
17405
17892
|
var STAGING_STALE_MS = 5 * 6e4;
|
|
17406
17893
|
function checkpointsRoot(stateDir) {
|
|
17407
|
-
return
|
|
17894
|
+
return path44.join(stateDir, "recovery", "checkpoints");
|
|
17408
17895
|
}
|
|
17409
17896
|
function checkpointDir(stateDir, checkpointId) {
|
|
17410
17897
|
if (!/^cp_[a-f0-9]{24}$/.test(checkpointId)) {
|
|
17411
17898
|
throw new Error("invalid_recovery_checkpoint_id");
|
|
17412
17899
|
}
|
|
17413
|
-
return
|
|
17900
|
+
return path44.join(checkpointsRoot(stateDir), checkpointId);
|
|
17414
17901
|
}
|
|
17415
17902
|
async function fsyncPath2(filePath) {
|
|
17416
17903
|
const handle = await open5(filePath, "r");
|
|
@@ -17421,13 +17908,13 @@ async function fsyncPath2(filePath) {
|
|
|
17421
17908
|
}
|
|
17422
17909
|
}
|
|
17423
17910
|
async function atomicWriteJson(filePath, value) {
|
|
17424
|
-
await mkdir10(
|
|
17911
|
+
await mkdir10(path44.dirname(filePath), { recursive: true, mode: 448 });
|
|
17425
17912
|
const temporary = `${filePath}.tmp-${randomUUID4()}`;
|
|
17426
17913
|
await writeFile7(temporary, `${JSON.stringify(value, null, 2)}
|
|
17427
17914
|
`, { mode: 384 });
|
|
17428
17915
|
await fsyncPath2(temporary);
|
|
17429
17916
|
await rename2(temporary, filePath);
|
|
17430
|
-
await fsyncPath2(
|
|
17917
|
+
await fsyncPath2(path44.dirname(filePath));
|
|
17431
17918
|
}
|
|
17432
17919
|
async function writeRecoveryState(artifactDir, state, manifestHash, detail) {
|
|
17433
17920
|
const value = {
|
|
@@ -17437,13 +17924,13 @@ async function writeRecoveryState(artifactDir, state, manifestHash, detail) {
|
|
|
17437
17924
|
manifestHash,
|
|
17438
17925
|
...detail ? { detail } : {}
|
|
17439
17926
|
};
|
|
17440
|
-
await atomicWriteJson(
|
|
17927
|
+
await atomicWriteJson(path44.join(artifactDir, "state.json"), value);
|
|
17441
17928
|
}
|
|
17442
17929
|
async function directorySize(root) {
|
|
17443
17930
|
if (!existsSync13(root)) return 0;
|
|
17444
17931
|
let total = 0;
|
|
17445
17932
|
for (const entry of await readdir2(root, { withFileTypes: true })) {
|
|
17446
|
-
const entryPath =
|
|
17933
|
+
const entryPath = path44.join(root, entry.name);
|
|
17447
17934
|
if (entry.isDirectory()) total += await directorySize(entryPath);
|
|
17448
17935
|
else total += (await lstat7(entryPath)).size;
|
|
17449
17936
|
}
|
|
@@ -17488,9 +17975,9 @@ async function readRecoveryArtifact(stateDir, checkpointId) {
|
|
|
17488
17975
|
let rawManifest;
|
|
17489
17976
|
let state;
|
|
17490
17977
|
try {
|
|
17491
|
-
rawManifest = JSON.parse(await readFile9(
|
|
17978
|
+
rawManifest = JSON.parse(await readFile9(path44.join(artifactDir, "manifest.json"), "utf8"));
|
|
17492
17979
|
state = JSON.parse(
|
|
17493
|
-
await readFile9(
|
|
17980
|
+
await readFile9(path44.join(artifactDir, "state.json"), "utf8")
|
|
17494
17981
|
);
|
|
17495
17982
|
} catch {
|
|
17496
17983
|
throw new Error(RECOVERY_CHECKPOINT_CORRUPT);
|
|
@@ -17506,10 +17993,10 @@ async function readRecoveryArtifact(stateDir, checkpointId) {
|
|
|
17506
17993
|
}
|
|
17507
17994
|
const entryPaths = /* @__PURE__ */ new Set();
|
|
17508
17995
|
for (const entry of manifest.entries) {
|
|
17509
|
-
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(
|
|
17996
|
+
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))) {
|
|
17510
17997
|
throw new Error(RECOVERY_CHECKPOINT_CORRUPT);
|
|
17511
17998
|
}
|
|
17512
|
-
entryPaths.add(
|
|
17999
|
+
entryPaths.add(path44.normalize(entry.path));
|
|
17513
18000
|
for (const [side, snapshot] of [
|
|
17514
18001
|
["before", entry.before],
|
|
17515
18002
|
["after", entry.after]
|
|
@@ -17523,7 +18010,7 @@ async function readRecoveryArtifact(stateDir, checkpointId) {
|
|
|
17523
18010
|
});
|
|
17524
18011
|
}
|
|
17525
18012
|
}
|
|
17526
|
-
const receiptPath =
|
|
18013
|
+
const receiptPath = path44.join(artifactDir, "receipt.json");
|
|
17527
18014
|
let receipt;
|
|
17528
18015
|
if (["applied", "restoring", "restored", "conflict"].includes(state.state) || existsSync13(receiptPath)) {
|
|
17529
18016
|
receipt = await readAndValidateRecoveryReceipt(artifactDir, manifest, manifestHash);
|
|
@@ -17533,7 +18020,7 @@ async function readRecoveryArtifact(stateDir, checkpointId) {
|
|
|
17533
18020
|
async function readAndValidateRecoveryReceipt(artifactDir, manifest, manifestHash) {
|
|
17534
18021
|
let rawReceipt;
|
|
17535
18022
|
try {
|
|
17536
|
-
rawReceipt = JSON.parse(await readFile9(
|
|
18023
|
+
rawReceipt = JSON.parse(await readFile9(path44.join(artifactDir, "receipt.json"), "utf8"));
|
|
17537
18024
|
} catch {
|
|
17538
18025
|
throw new Error(RECOVERY_CHECKPOINT_CORRUPT);
|
|
17539
18026
|
}
|
|
@@ -17556,7 +18043,7 @@ async function readAndValidateRecoveryReceipt(artifactDir, manifest, manifestHas
|
|
|
17556
18043
|
return receipt;
|
|
17557
18044
|
}
|
|
17558
18045
|
async function ensureRecoveryReceipt(artifactDir, manifest, manifestHash) {
|
|
17559
|
-
const receiptPath =
|
|
18046
|
+
const receiptPath = path44.join(artifactDir, "receipt.json");
|
|
17560
18047
|
if (existsSync13(receiptPath)) {
|
|
17561
18048
|
return readAndValidateRecoveryReceipt(artifactDir, manifest, manifestHash);
|
|
17562
18049
|
}
|
|
@@ -17581,7 +18068,7 @@ async function artifactRepoRoot(stateDir, checkpointId) {
|
|
|
17581
18068
|
const artifactDir = checkpointDir(stateDir, checkpointId);
|
|
17582
18069
|
try {
|
|
17583
18070
|
const manifest = JSON.parse(
|
|
17584
|
-
await readFile9(
|
|
18071
|
+
await readFile9(path44.join(artifactDir, "manifest.json"), "utf8")
|
|
17585
18072
|
);
|
|
17586
18073
|
if (typeof manifest.repoRoot === "string" && manifest.repoRoot) {
|
|
17587
18074
|
return canonicalPath(manifest.repoRoot);
|
|
@@ -17589,7 +18076,7 @@ async function artifactRepoRoot(stateDir, checkpointId) {
|
|
|
17589
18076
|
} catch {
|
|
17590
18077
|
}
|
|
17591
18078
|
try {
|
|
17592
|
-
const owner = JSON.parse(await readFile9(
|
|
18079
|
+
const owner = JSON.parse(await readFile9(path44.join(artifactDir, "owner.json"), "utf8"));
|
|
17593
18080
|
return typeof owner.repoRoot === "string" && owner.repoRoot ? canonicalPath(owner.repoRoot) : null;
|
|
17594
18081
|
} catch {
|
|
17595
18082
|
return null;
|
|
@@ -17609,10 +18096,10 @@ async function cleanupOrphanedStaging(stateDir) {
|
|
|
17609
18096
|
const now = Date.now();
|
|
17610
18097
|
for (const entry of await readdir2(root, { withFileTypes: true })) {
|
|
17611
18098
|
if (!entry.isDirectory() || !/^\.tmp-cp_[a-f0-9]{24}$/.test(entry.name)) continue;
|
|
17612
|
-
const stagingPath =
|
|
18099
|
+
const stagingPath = path44.join(root, entry.name);
|
|
17613
18100
|
let stale = false;
|
|
17614
18101
|
try {
|
|
17615
|
-
const owner = JSON.parse(await readFile9(
|
|
18102
|
+
const owner = JSON.parse(await readFile9(path44.join(stagingPath, "owner.json"), "utf8"));
|
|
17616
18103
|
const pid = typeof owner.pid === "number" ? owner.pid : Number.NaN;
|
|
17617
18104
|
const createdAt = typeof owner.createdAt === "string" ? Date.parse(owner.createdAt) : NaN;
|
|
17618
18105
|
let alive = false;
|
|
@@ -17654,7 +18141,7 @@ async function markRecoveryCheckpointApplied(stateDir, checkpoint) {
|
|
|
17654
18141
|
init_fingerprint2();
|
|
17655
18142
|
import { existsSync as existsSync14 } from "node:fs";
|
|
17656
18143
|
import { readFile as readFile10 } from "node:fs/promises";
|
|
17657
|
-
import
|
|
18144
|
+
import path45 from "node:path";
|
|
17658
18145
|
async function matchRecoverySide(resourceRoot, entries, side) {
|
|
17659
18146
|
for (const entry of entries) {
|
|
17660
18147
|
const target = await assertRecoverySafeTarget(resourceRoot, entry.path);
|
|
@@ -17669,7 +18156,7 @@ async function reconcileRecoveryCheckpoint(stateDir, checkpointId) {
|
|
|
17669
18156
|
} catch {
|
|
17670
18157
|
const artifactDir = checkpointDir(stateDir, checkpointId);
|
|
17671
18158
|
if (existsSync14(artifactDir)) {
|
|
17672
|
-
const manifestPath =
|
|
18159
|
+
const manifestPath = path45.join(artifactDir, "manifest.json");
|
|
17673
18160
|
const hash = existsSync14(manifestPath) ? hashValue(await readFile10(manifestPath, "utf8")) : "unavailable";
|
|
17674
18161
|
await writeRecoveryState(artifactDir, "corrupt", hash, RECOVERY_CHECKPOINT_CORRUPT);
|
|
17675
18162
|
}
|
|
@@ -17706,7 +18193,7 @@ async function reconcileRecoveryCheckpoint(stateDir, checkpointId) {
|
|
|
17706
18193
|
// src/core/recovery/resource-identity.ts
|
|
17707
18194
|
init_fingerprint2();
|
|
17708
18195
|
import { lstat as lstat8, readFile as readFile11, realpath as realpath3 } from "node:fs/promises";
|
|
17709
|
-
import
|
|
18196
|
+
import path46 from "node:path";
|
|
17710
18197
|
async function currentRecoveryResourceIdentity(resourceRoot, resourceKind) {
|
|
17711
18198
|
const resolvedRoot = await realpath3(resourceRoot);
|
|
17712
18199
|
if (resourceKind === "directory") {
|
|
@@ -17714,13 +18201,13 @@ async function currentRecoveryResourceIdentity(resourceRoot, resourceKind) {
|
|
|
17714
18201
|
if (!rootInfo.isDirectory()) throw new Error("recovery_repo_identity_unavailable");
|
|
17715
18202
|
return hashValue(`${resolvedRoot}\0${rootInfo.dev}:${rootInfo.ino}:${rootInfo.birthtimeMs}`);
|
|
17716
18203
|
}
|
|
17717
|
-
const dotGit =
|
|
18204
|
+
const dotGit = path46.join(resolvedRoot, ".git");
|
|
17718
18205
|
const gitInfo = await lstat8(dotGit);
|
|
17719
18206
|
let gitMetadataPath = dotGit;
|
|
17720
18207
|
if (gitInfo.isFile()) {
|
|
17721
18208
|
const marker = (await readFile11(dotGit, "utf8")).trim();
|
|
17722
18209
|
if (!marker.startsWith("gitdir:")) throw new Error("recovery_repo_identity_unavailable");
|
|
17723
|
-
gitMetadataPath =
|
|
18210
|
+
gitMetadataPath = path46.resolve(resolvedRoot, marker.slice("gitdir:".length).trim());
|
|
17724
18211
|
} else if (!gitInfo.isDirectory()) {
|
|
17725
18212
|
throw new Error("recovery_repo_identity_unavailable");
|
|
17726
18213
|
}
|
|
@@ -17793,16 +18280,16 @@ async function prepareRecoveryCheckpoint(params) {
|
|
|
17793
18280
|
throw new Error(RECOVERY_CHECKPOINT_QUOTA);
|
|
17794
18281
|
}
|
|
17795
18282
|
const checkpointId = `cp_${randomUUID5().replaceAll("-", "").slice(0, 24)}`;
|
|
17796
|
-
const temporary =
|
|
18283
|
+
const temporary = path47.join(checkpointsRoot(params.stateDir), `.tmp-${checkpointId}`);
|
|
17797
18284
|
const finalDir = checkpointDir(params.stateDir, checkpointId);
|
|
17798
18285
|
await mkdir11(temporary, { recursive: true, mode: 448 });
|
|
17799
|
-
await atomicWriteJson(
|
|
18286
|
+
await atomicWriteJson(path47.join(temporary, "owner.json"), {
|
|
17800
18287
|
version: 1,
|
|
17801
18288
|
pid: process.pid,
|
|
17802
18289
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
17803
18290
|
repoRoot: canonicalPath(params.repoRoot)
|
|
17804
18291
|
});
|
|
17805
|
-
await mkdir11(
|
|
18292
|
+
await mkdir11(path47.join(temporary, "blobs"), { recursive: true, mode: 448 });
|
|
17806
18293
|
try {
|
|
17807
18294
|
const entries = [];
|
|
17808
18295
|
const protectedRoots = (params.protectedRoots ?? []).map(canonicalPath);
|
|
@@ -17811,8 +18298,8 @@ async function prepareRecoveryCheckpoint(params) {
|
|
|
17811
18298
|
)) {
|
|
17812
18299
|
const target = await assertRecoverySafeTarget(params.repoRoot, change.relativePath);
|
|
17813
18300
|
if (protectedRoots.some((root) => {
|
|
17814
|
-
const relative =
|
|
17815
|
-
return relative === "" || relative !== ".." && !relative.startsWith(`..${
|
|
18301
|
+
const relative = path47.relative(root, target);
|
|
18302
|
+
return relative === "" || relative !== ".." && !relative.startsWith(`..${path47.sep}`) && !path47.isAbsolute(relative);
|
|
17816
18303
|
})) {
|
|
17817
18304
|
throw new Error("recovery_protected_path");
|
|
17818
18305
|
}
|
|
@@ -17824,7 +18311,7 @@ async function prepareRecoveryCheckpoint(params) {
|
|
|
17824
18311
|
entries.push({
|
|
17825
18312
|
path: change.relativePath,
|
|
17826
18313
|
before: await captureRecoverySnapshot(baseline, {
|
|
17827
|
-
blobDir:
|
|
18314
|
+
blobDir: path47.join(temporary, "blobs")
|
|
17828
18315
|
}),
|
|
17829
18316
|
after: withoutRecoveryBlob(await captureRecoverySnapshot(source))
|
|
17830
18317
|
});
|
|
@@ -17861,7 +18348,7 @@ async function prepareRecoveryCheckpoint(params) {
|
|
|
17861
18348
|
entries
|
|
17862
18349
|
};
|
|
17863
18350
|
const manifestHash = hashValue(canonicalStringify(manifest));
|
|
17864
|
-
await atomicWriteJson(
|
|
18351
|
+
await atomicWriteJson(path47.join(temporary, "manifest.json"), manifest);
|
|
17865
18352
|
await writeRecoveryState(temporary, "prepared", manifestHash);
|
|
17866
18353
|
await fsyncPath2(temporary);
|
|
17867
18354
|
const projectedBytes = await recoveryCheckpointStorageBytes(params.stateDir, params.repoRoot);
|
|
@@ -17904,7 +18391,7 @@ async function listRecoveryCheckpoints(stateDir, repoRoot) {
|
|
|
17904
18391
|
} catch {
|
|
17905
18392
|
try {
|
|
17906
18393
|
const raw = JSON.parse(
|
|
17907
|
-
await readFile12(
|
|
18394
|
+
await readFile12(path47.join(checkpointDir(stateDir, id), "manifest.json"), "utf8")
|
|
17908
18395
|
);
|
|
17909
18396
|
rootFromArtifact = typeof raw.repoRoot === "string" && raw.repoRoot ? raw.repoRoot : void 0;
|
|
17910
18397
|
} catch {
|
|
@@ -17938,7 +18425,7 @@ async function listRecoveryCheckpoints(stateDir, repoRoot) {
|
|
|
17938
18425
|
} catch {
|
|
17939
18426
|
try {
|
|
17940
18427
|
const manifest = JSON.parse(
|
|
17941
|
-
await readFile12(
|
|
18428
|
+
await readFile12(path47.join(checkpointDir(stateDir, id), "manifest.json"), "utf8")
|
|
17942
18429
|
);
|
|
17943
18430
|
if (manifest.checkpointId !== id || ![1, 2].includes(manifest.version)) continue;
|
|
17944
18431
|
if (repoRoot && canonicalPath(manifest.repoRoot) !== canonicalPath(repoRoot)) continue;
|
|
@@ -17968,7 +18455,7 @@ async function recoveryCheckpointStorageBytes(stateDir, repoRoot) {
|
|
|
17968
18455
|
let total = 0;
|
|
17969
18456
|
for (const entry of await readdir3(root, { withFileTypes: true })) {
|
|
17970
18457
|
if (!entry.isDirectory()) continue;
|
|
17971
|
-
const entryPath =
|
|
18458
|
+
const entryPath = path47.join(root, entry.name);
|
|
17972
18459
|
if (/^cp_[a-f0-9]{24}$/.test(entry.name)) {
|
|
17973
18460
|
if (await artifactRepoRoot(stateDir, entry.name) === expected) {
|
|
17974
18461
|
total += await directorySize(entryPath);
|
|
@@ -17977,7 +18464,7 @@ async function recoveryCheckpointStorageBytes(stateDir, repoRoot) {
|
|
|
17977
18464
|
}
|
|
17978
18465
|
if (/^\.tmp-cp_[a-f0-9]{24}$/.test(entry.name)) {
|
|
17979
18466
|
try {
|
|
17980
|
-
const owner = JSON.parse(await readFile12(
|
|
18467
|
+
const owner = JSON.parse(await readFile12(path47.join(entryPath, "owner.json"), "utf8"));
|
|
17981
18468
|
if (typeof owner.repoRoot === "string" && canonicalPath(owner.repoRoot) === expected) {
|
|
17982
18469
|
total += await directorySize(entryPath);
|
|
17983
18470
|
}
|
|
@@ -18021,14 +18508,14 @@ init_scrub();
|
|
|
18021
18508
|
// src/core/transactional/file-checkpoint-backend.ts
|
|
18022
18509
|
import { cp, lstat as lstat11, mkdir as mkdir13, mkdtemp as mkdtemp5, readdir as readdir6, rm as rm9, writeFile as writeFile10 } from "node:fs/promises";
|
|
18023
18510
|
import os5 from "node:os";
|
|
18024
|
-
import
|
|
18511
|
+
import path51 from "node:path";
|
|
18025
18512
|
|
|
18026
18513
|
// src/core/transactional/file-checkpoint-git.ts
|
|
18027
18514
|
init_path_utils();
|
|
18028
18515
|
import { spawn as spawn8 } from "node:child_process";
|
|
18029
18516
|
import { createHash as createHash13 } from "node:crypto";
|
|
18030
18517
|
import { copyFile as copyFile3, lstat as lstat9, readdir as readdir4, readFile as readFile13 } from "node:fs/promises";
|
|
18031
|
-
import
|
|
18518
|
+
import path48 from "node:path";
|
|
18032
18519
|
var FILE_CHECKPOINT_GIT_METADATA_CHANGED = "file_checkpoint_git_metadata_changed";
|
|
18033
18520
|
var FILE_CHECKPOINT_SOURCE_CHANGED = "file_checkpoint_source_changed";
|
|
18034
18521
|
var FILE_CHECKPOINT_CWD_OUTSIDE_ROOT = "file_checkpoint_cwd_outside_root";
|
|
@@ -18062,7 +18549,7 @@ function rethrowStableFileCheckpointError(error) {
|
|
|
18062
18549
|
}
|
|
18063
18550
|
async function rootGitMetadataPresent(repoRoot) {
|
|
18064
18551
|
try {
|
|
18065
|
-
await lstat9(
|
|
18552
|
+
await lstat9(path48.join(repoRoot, ".git"));
|
|
18066
18553
|
return true;
|
|
18067
18554
|
} catch {
|
|
18068
18555
|
return false;
|
|
@@ -18111,10 +18598,10 @@ function execGit2(repoRoot, args) {
|
|
|
18111
18598
|
}
|
|
18112
18599
|
async function resolveGitPath(repoRoot, gitPath) {
|
|
18113
18600
|
const trimmed = gitPath.trim();
|
|
18114
|
-
if (
|
|
18601
|
+
if (path48.isAbsolute(trimmed)) {
|
|
18115
18602
|
return trimmed;
|
|
18116
18603
|
}
|
|
18117
|
-
return
|
|
18604
|
+
return path48.join(repoRoot, trimmed);
|
|
18118
18605
|
}
|
|
18119
18606
|
async function cloneBareWorktreeCopy(sourceRoot, destinationRoot) {
|
|
18120
18607
|
await execGit2(sourceRoot, [
|
|
@@ -18156,7 +18643,7 @@ async function copyGitIndexState(sourceRoot, destinationRoot) {
|
|
|
18156
18643
|
destinationRoot,
|
|
18157
18644
|
await execGit2(destinationRoot, ["rev-parse", "--git-dir"])
|
|
18158
18645
|
);
|
|
18159
|
-
const destinationShared =
|
|
18646
|
+
const destinationShared = path48.join(destinationGitDir, path48.basename(sourceShared));
|
|
18160
18647
|
try {
|
|
18161
18648
|
await copyFile3(sourceShared, destinationShared);
|
|
18162
18649
|
} catch (error) {
|
|
@@ -18165,7 +18652,7 @@ async function copyGitIndexState(sourceRoot, destinationRoot) {
|
|
|
18165
18652
|
}
|
|
18166
18653
|
async function readGitFile(gitDir, relativePath) {
|
|
18167
18654
|
try {
|
|
18168
|
-
return await readFile13(
|
|
18655
|
+
return await readFile13(path48.join(gitDir, relativePath));
|
|
18169
18656
|
} catch {
|
|
18170
18657
|
return null;
|
|
18171
18658
|
}
|
|
@@ -18189,8 +18676,8 @@ async function hashResolvedGitPath(repoRoot, gitDir, gitPath, hash) {
|
|
|
18189
18676
|
repoRoot,
|
|
18190
18677
|
await execGit2(repoRoot, ["rev-parse", "--git-path", gitPath])
|
|
18191
18678
|
);
|
|
18192
|
-
const relative =
|
|
18193
|
-
const content = typeof relative === "string" && !relative.startsWith("..") && !
|
|
18679
|
+
const relative = path48.resolve(resolved).startsWith(path48.resolve(gitDir)) ? path48.relative(gitDir, resolved) : resolved;
|
|
18680
|
+
const content = typeof relative === "string" && !relative.startsWith("..") && !path48.isAbsolute(relative) ? await readGitFile(gitDir, relative) : await readAbsoluteGitFile(resolved);
|
|
18194
18681
|
if (content !== null) {
|
|
18195
18682
|
hashGitFileContent(hash, gitPath, content);
|
|
18196
18683
|
}
|
|
@@ -18200,13 +18687,13 @@ async function hashResolvedGitPath(repoRoot, gitDir, gitPath, hash) {
|
|
|
18200
18687
|
async function hashGitTree(gitDir, relativeDir, hash) {
|
|
18201
18688
|
let names;
|
|
18202
18689
|
try {
|
|
18203
|
-
names = await readdir4(
|
|
18690
|
+
names = await readdir4(path48.join(gitDir, relativeDir));
|
|
18204
18691
|
} catch {
|
|
18205
18692
|
return;
|
|
18206
18693
|
}
|
|
18207
18694
|
for (const name of names.sort()) {
|
|
18208
|
-
const relativePath = relativeDir ?
|
|
18209
|
-
const absolutePath =
|
|
18695
|
+
const relativePath = relativeDir ? path48.join(relativeDir, name) : name;
|
|
18696
|
+
const absolutePath = path48.join(gitDir, relativePath);
|
|
18210
18697
|
let childNames = null;
|
|
18211
18698
|
try {
|
|
18212
18699
|
childNames = await readdir4(absolutePath);
|
|
@@ -18228,7 +18715,7 @@ async function hashGitTree(gitDir, relativeDir, hash) {
|
|
|
18228
18715
|
}
|
|
18229
18716
|
async function computeGitMetadataFingerprint(repoRoot) {
|
|
18230
18717
|
const gitDirRel = (await execGit2(repoRoot, ["rev-parse", "--git-dir"])).trim();
|
|
18231
|
-
const gitDir =
|
|
18718
|
+
const gitDir = path48.isAbsolute(gitDirRel) ? gitDirRel : path48.join(repoRoot, gitDirRel);
|
|
18232
18719
|
const hash = createHash13("sha256");
|
|
18233
18720
|
for (const file of [
|
|
18234
18721
|
"HEAD",
|
|
@@ -18251,8 +18738,8 @@ async function computeGitMetadataFingerprint(repoRoot) {
|
|
|
18251
18738
|
const sharedIndex = (await execGit2(repoRoot, ["rev-parse", "--shared-index-path"])).trim();
|
|
18252
18739
|
if (sharedIndex) {
|
|
18253
18740
|
const resolved = await resolveGitPath(repoRoot, sharedIndex);
|
|
18254
|
-
const relative =
|
|
18255
|
-
const content = relative && !relative.startsWith("..") && !
|
|
18741
|
+
const relative = path48.relative(gitDir, resolved);
|
|
18742
|
+
const content = relative && !relative.startsWith("..") && !path48.isAbsolute(relative) ? await readGitFile(gitDir, relative) : await readAbsoluteGitFile(resolved);
|
|
18256
18743
|
if (content !== null) {
|
|
18257
18744
|
hashGitFileContent(hash, "shared-index", content);
|
|
18258
18745
|
}
|
|
@@ -18263,7 +18750,7 @@ async function computeGitMetadataFingerprint(repoRoot) {
|
|
|
18263
18750
|
await hashResolvedGitPath(repoRoot, gitDir, gitPath, hash);
|
|
18264
18751
|
}
|
|
18265
18752
|
try {
|
|
18266
|
-
const rootGitPath =
|
|
18753
|
+
const rootGitPath = path48.join(repoRoot, ".git");
|
|
18267
18754
|
const rootGitInfo = await lstat9(rootGitPath);
|
|
18268
18755
|
if (rootGitInfo.isFile()) {
|
|
18269
18756
|
const content = await readAbsoluteGitFile(rootGitPath);
|
|
@@ -18279,14 +18766,14 @@ async function computeGitMetadataFingerprint(repoRoot) {
|
|
|
18279
18766
|
function resolveExecutionCwdRelative(resourceRoot, cwd) {
|
|
18280
18767
|
const resolvedCwd = canonicalPath(cwd);
|
|
18281
18768
|
const resourceCanonical = canonicalPath(resourceRoot);
|
|
18282
|
-
const relative =
|
|
18769
|
+
const relative = path48.relative(resourceCanonical, resolvedCwd);
|
|
18283
18770
|
if (relative === "" || relative === ".") {
|
|
18284
18771
|
return "";
|
|
18285
18772
|
}
|
|
18286
|
-
if (relative.startsWith("..") ||
|
|
18773
|
+
if (relative.startsWith("..") || path48.isAbsolute(relative)) {
|
|
18287
18774
|
throw new Error(FILE_CHECKPOINT_CWD_OUTSIDE_ROOT);
|
|
18288
18775
|
}
|
|
18289
|
-
return relative.split(
|
|
18776
|
+
return relative.split(path48.sep).join("/");
|
|
18290
18777
|
}
|
|
18291
18778
|
|
|
18292
18779
|
// src/core/transactional/file-checkpoint-isolation.ts
|
|
@@ -18308,7 +18795,7 @@ function fileCheckpointIsolationReason(context) {
|
|
|
18308
18795
|
|
|
18309
18796
|
// src/core/transactional/file-checkpoint-staging.ts
|
|
18310
18797
|
import { readdir as readdir5, readFile as readFile14, rm as rm7, writeFile as writeFile8 } from "node:fs/promises";
|
|
18311
|
-
import
|
|
18798
|
+
import path49 from "node:path";
|
|
18312
18799
|
function isOwnerProcessAlive(pid) {
|
|
18313
18800
|
try {
|
|
18314
18801
|
process.kill(pid, 0);
|
|
@@ -18318,12 +18805,12 @@ function isOwnerProcessAlive(pid) {
|
|
|
18318
18805
|
}
|
|
18319
18806
|
}
|
|
18320
18807
|
async function writeOwnerMarker(stagingRoot, marker) {
|
|
18321
|
-
await writeFile8(
|
|
18808
|
+
await writeFile8(path49.join(stagingRoot, "owner.json"), `${JSON.stringify(marker)}
|
|
18322
18809
|
`, "utf8");
|
|
18323
18810
|
}
|
|
18324
18811
|
async function readOwnerMarker(stagingRoot) {
|
|
18325
18812
|
try {
|
|
18326
|
-
const raw = await readFile14(
|
|
18813
|
+
const raw = await readFile14(path49.join(stagingRoot, "owner.json"), "utf8");
|
|
18327
18814
|
return JSON.parse(raw.trim());
|
|
18328
18815
|
} catch {
|
|
18329
18816
|
return null;
|
|
@@ -18341,7 +18828,7 @@ async function collectDeadOwnerStaging(parentDir) {
|
|
|
18341
18828
|
if (!name.startsWith("belay-file-checkpoint-")) {
|
|
18342
18829
|
continue;
|
|
18343
18830
|
}
|
|
18344
|
-
const stagingRoot =
|
|
18831
|
+
const stagingRoot = path49.join(parentDir, name);
|
|
18345
18832
|
const marker = await readOwnerMarker(stagingRoot);
|
|
18346
18833
|
if (!marker) {
|
|
18347
18834
|
dead.push(stagingRoot);
|
|
@@ -18373,7 +18860,7 @@ import {
|
|
|
18373
18860
|
writeFile as writeFile9
|
|
18374
18861
|
} from "node:fs/promises";
|
|
18375
18862
|
import os4 from "node:os";
|
|
18376
|
-
import
|
|
18863
|
+
import path50 from "node:path";
|
|
18377
18864
|
var FILE_CHECKPOINT_COPY_FAILED = "file_checkpoint_copy_failed";
|
|
18378
18865
|
async function chmodSafe2(target, mode) {
|
|
18379
18866
|
try {
|
|
@@ -18383,7 +18870,7 @@ async function chmodSafe2(target, mode) {
|
|
|
18383
18870
|
}
|
|
18384
18871
|
}
|
|
18385
18872
|
async function copyRegularFile(sourcePath, destinationPath, mode, strategy) {
|
|
18386
|
-
await mkdir12(
|
|
18873
|
+
await mkdir12(path50.dirname(destinationPath), { recursive: true });
|
|
18387
18874
|
if (strategy === "clonefile" && fsConstants2.COPYFILE_FICLONE !== void 0) {
|
|
18388
18875
|
try {
|
|
18389
18876
|
await copyFile4(sourcePath, destinationPath, fsConstants2.COPYFILE_FICLONE);
|
|
@@ -18409,7 +18896,7 @@ async function copyNode(sourceRoot, destinationRoot, relativePath, strategy) {
|
|
|
18409
18896
|
return strategy;
|
|
18410
18897
|
}
|
|
18411
18898
|
if (info.isSymbolicLink()) {
|
|
18412
|
-
await mkdir12(
|
|
18899
|
+
await mkdir12(path50.dirname(destinationPath), { recursive: true });
|
|
18413
18900
|
await symlink4(await readlink5(sourcePath), destinationPath);
|
|
18414
18901
|
return strategy;
|
|
18415
18902
|
}
|
|
@@ -18465,9 +18952,9 @@ async function mapWithConcurrency(items, concurrency, worker) {
|
|
|
18465
18952
|
async function probeFileCloneStrategy() {
|
|
18466
18953
|
let tempDir = null;
|
|
18467
18954
|
try {
|
|
18468
|
-
tempDir = await mkdtemp4(
|
|
18469
|
-
const source =
|
|
18470
|
-
const destination =
|
|
18955
|
+
tempDir = await mkdtemp4(path50.join(os4.tmpdir(), "belay-clone-probe-"));
|
|
18956
|
+
const source = path50.join(tempDir, "source.txt");
|
|
18957
|
+
const destination = path50.join(tempDir, "dest.txt");
|
|
18471
18958
|
await writeFile9(source, "probe\n");
|
|
18472
18959
|
if (fsConstants2.COPYFILE_FICLONE_FORCE !== void 0) {
|
|
18473
18960
|
try {
|
|
@@ -18620,11 +19107,11 @@ async function protectedRootState(root) {
|
|
|
18620
19107
|
return `directory:${node.hash}:${index.treeHash}`;
|
|
18621
19108
|
}
|
|
18622
19109
|
function executionProtectedRoot(resourceRoot, executionRoot, protectedRoot) {
|
|
18623
|
-
const relative =
|
|
18624
|
-
if (relative === "" || relative.startsWith("..") ||
|
|
19110
|
+
const relative = path51.relative(path51.resolve(resourceRoot), path51.resolve(protectedRoot));
|
|
19111
|
+
if (relative === "" || relative.startsWith("..") || path51.isAbsolute(relative)) {
|
|
18625
19112
|
return null;
|
|
18626
19113
|
}
|
|
18627
|
-
return
|
|
19114
|
+
return path51.join(executionRoot, relative);
|
|
18628
19115
|
}
|
|
18629
19116
|
async function captureProtectedRootStates(resourceRoot, executionRoot, protectedRoots) {
|
|
18630
19117
|
const states = /* @__PURE__ */ new Map();
|
|
@@ -18649,15 +19136,15 @@ async function directoryByteSize(root, deadlineMs) {
|
|
|
18649
19136
|
}
|
|
18650
19137
|
let total = 0;
|
|
18651
19138
|
for (const name of await readdir6(root)) {
|
|
18652
|
-
total += await directoryByteSize(
|
|
19139
|
+
total += await directoryByteSize(path51.join(root, name), deadlineMs);
|
|
18653
19140
|
}
|
|
18654
19141
|
return total;
|
|
18655
19142
|
}
|
|
18656
19143
|
async function copyGitMetadataDirectory(sourceRoot, destinationRoot) {
|
|
18657
19144
|
const gitDirRel = (await execGit2(sourceRoot, ["rev-parse", "--git-dir"])).trim();
|
|
18658
|
-
const sourceGitDir =
|
|
18659
|
-
const relativeGitDir =
|
|
18660
|
-
const destinationGitDir = relativeGitDir && !relativeGitDir.startsWith("..") ?
|
|
19145
|
+
const sourceGitDir = path51.isAbsolute(gitDirRel) ? gitDirRel : path51.join(sourceRoot, gitDirRel);
|
|
19146
|
+
const relativeGitDir = path51.relative(path51.resolve(sourceRoot), path51.resolve(sourceGitDir));
|
|
19147
|
+
const destinationGitDir = relativeGitDir && !relativeGitDir.startsWith("..") ? path51.join(destinationRoot, relativeGitDir) : path51.join(destinationRoot, ".git");
|
|
18661
19148
|
await cp(sourceGitDir, destinationGitDir, { recursive: true, force: true });
|
|
18662
19149
|
}
|
|
18663
19150
|
async function prepareDirtyGitSnapshot(context) {
|
|
@@ -18666,7 +19153,7 @@ async function prepareDirtyGitSnapshot(context) {
|
|
|
18666
19153
|
const quotas = context.fileCheckpoint;
|
|
18667
19154
|
const deadlineMs = Date.now() + quotas.prepareTimeoutMs;
|
|
18668
19155
|
await removeDeadOwnerStaging(os5.tmpdir());
|
|
18669
|
-
const stagingRoot = await mkdtemp5(
|
|
19156
|
+
const stagingRoot = await mkdtemp5(path51.join(os5.tmpdir(), "belay-file-checkpoint-"));
|
|
18670
19157
|
await writeOwnerMarker(stagingRoot, {
|
|
18671
19158
|
version: 1,
|
|
18672
19159
|
pid: process.pid,
|
|
@@ -18674,8 +19161,8 @@ async function prepareDirtyGitSnapshot(context) {
|
|
|
18674
19161
|
resourceRoot: context.repoRoot,
|
|
18675
19162
|
backend: "file_checkpoint"
|
|
18676
19163
|
});
|
|
18677
|
-
const baselineRoot =
|
|
18678
|
-
const executionRoot =
|
|
19164
|
+
const baselineRoot = path51.join(stagingRoot, "baseline");
|
|
19165
|
+
const executionRoot = path51.join(stagingRoot, "execution");
|
|
18679
19166
|
try {
|
|
18680
19167
|
resolveExecutionCwdRelative(context.repoRoot, context.cwd);
|
|
18681
19168
|
const sourceGitMetadataFingerprint = await computeGitMetadataFingerprint(context.repoRoot);
|
|
@@ -18709,7 +19196,7 @@ async function prepareDirtyGitSnapshot(context) {
|
|
|
18709
19196
|
throw new Error(FILE_CHECKPOINT_SOURCE_CHANGED);
|
|
18710
19197
|
}
|
|
18711
19198
|
await writeFile10(
|
|
18712
|
-
|
|
19199
|
+
path51.join(stagingRoot, "baseline-index.json"),
|
|
18713
19200
|
`${JSON.stringify(baselineIndex)}
|
|
18714
19201
|
`,
|
|
18715
19202
|
"utf8"
|
|
@@ -18759,7 +19246,7 @@ async function prepareNonGitSnapshot(context) {
|
|
|
18759
19246
|
const quotas = context.fileCheckpoint;
|
|
18760
19247
|
const deadlineMs = Date.now() + quotas.prepareTimeoutMs;
|
|
18761
19248
|
await removeDeadOwnerStaging(os5.tmpdir());
|
|
18762
|
-
const stagingRoot = await mkdtemp5(
|
|
19249
|
+
const stagingRoot = await mkdtemp5(path51.join(os5.tmpdir(), "belay-file-checkpoint-"));
|
|
18763
19250
|
await writeOwnerMarker(stagingRoot, {
|
|
18764
19251
|
version: 1,
|
|
18765
19252
|
pid: process.pid,
|
|
@@ -18767,8 +19254,8 @@ async function prepareNonGitSnapshot(context) {
|
|
|
18767
19254
|
resourceRoot: context.repoRoot,
|
|
18768
19255
|
backend: "file_checkpoint"
|
|
18769
19256
|
});
|
|
18770
|
-
const baselineRoot =
|
|
18771
|
-
const executionRoot =
|
|
19257
|
+
const baselineRoot = path51.join(stagingRoot, "baseline");
|
|
19258
|
+
const executionRoot = path51.join(stagingRoot, "execution");
|
|
18772
19259
|
try {
|
|
18773
19260
|
resolveExecutionCwdRelative(context.repoRoot, context.cwd);
|
|
18774
19261
|
const resourceIdentity = await currentRecoveryResourceIdentity(context.repoRoot, "directory");
|
|
@@ -18797,7 +19284,7 @@ async function prepareNonGitSnapshot(context) {
|
|
|
18797
19284
|
throw new Error(FILE_CHECKPOINT_SOURCE_CHANGED);
|
|
18798
19285
|
}
|
|
18799
19286
|
await writeFile10(
|
|
18800
|
-
|
|
19287
|
+
path51.join(stagingRoot, "baseline-index.json"),
|
|
18801
19288
|
`${JSON.stringify(baselineIndex)}
|
|
18802
19289
|
`,
|
|
18803
19290
|
"utf8"
|
|
@@ -19150,10 +19637,10 @@ async function selectTransactionalBackend(context) {
|
|
|
19150
19637
|
}
|
|
19151
19638
|
|
|
19152
19639
|
// src/core/transactional/diff-evaluator.ts
|
|
19153
|
-
import
|
|
19640
|
+
import path52 from "node:path";
|
|
19154
19641
|
init_path_utils();
|
|
19155
19642
|
function categorizeChange(change, ctx) {
|
|
19156
|
-
const absolutePath = canonicalPath(
|
|
19643
|
+
const absolutePath = canonicalPath(path52.join(ctx.repoRoot, change.relativePath));
|
|
19157
19644
|
if (!pathWithinRoot(ctx.repoRoot, absolutePath)) {
|
|
19158
19645
|
return "repo_outside";
|
|
19159
19646
|
}
|
|
@@ -19747,7 +20234,7 @@ async function notifyDeny(config, event) {
|
|
|
19747
20234
|
init_path_utils();
|
|
19748
20235
|
|
|
19749
20236
|
// src/adapters/layouts/protected-paths.ts
|
|
19750
|
-
import
|
|
20237
|
+
import path53 from "node:path";
|
|
19751
20238
|
function protectedArtifactRoots(layout, repoRoot, controlPlaneDir) {
|
|
19752
20239
|
const roots = [
|
|
19753
20240
|
layout.configPath(repoRoot),
|
|
@@ -19759,7 +20246,7 @@ function protectedArtifactRoots(layout, repoRoot, controlPlaneDir) {
|
|
|
19759
20246
|
if (controlPlaneDir) {
|
|
19760
20247
|
roots.push(controlPlaneDir);
|
|
19761
20248
|
}
|
|
19762
|
-
return roots.map((entry) =>
|
|
20249
|
+
return roots.map((entry) => path53.resolve(entry));
|
|
19763
20250
|
}
|
|
19764
20251
|
|
|
19765
20252
|
// src/adapters/shared/gate-runtime.ts
|
|
@@ -19812,8 +20299,8 @@ function createDefaultGateRuntimeDeps() {
|
|
|
19812
20299
|
return loadJsonFile(configPath, {});
|
|
19813
20300
|
},
|
|
19814
20301
|
async appendAudit(ctx, event) {
|
|
19815
|
-
const auditPath =
|
|
19816
|
-
await mkdir14(
|
|
20302
|
+
const auditPath = path54.join(ctx.repoRoot, ctx.config.audit.logPath);
|
|
20303
|
+
await mkdir14(path54.dirname(auditPath), { recursive: true });
|
|
19817
20304
|
const provenance = auditProvenance(ctx.config);
|
|
19818
20305
|
const record = {
|
|
19819
20306
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -19846,7 +20333,7 @@ function createDefaultGateRuntimeDeps() {
|
|
|
19846
20333
|
};
|
|
19847
20334
|
},
|
|
19848
20335
|
async writeApprovals(filePath, state) {
|
|
19849
|
-
await mkdir14(
|
|
20336
|
+
await mkdir14(path54.dirname(filePath), { recursive: true });
|
|
19850
20337
|
await writeFile11(filePath, `${JSON.stringify(compactApprovals(state), null, 2)}
|
|
19851
20338
|
`, "utf8");
|
|
19852
20339
|
},
|
|
@@ -20008,7 +20495,7 @@ function deriveWorkspaceRootScopeHint(params) {
|
|
|
20008
20495
|
if (!targetPath) {
|
|
20009
20496
|
return void 0;
|
|
20010
20497
|
}
|
|
20011
|
-
const candidateRoot = canonicalPath(
|
|
20498
|
+
const candidateRoot = canonicalPath(path54.dirname(targetPath));
|
|
20012
20499
|
const validation = validateTrustedWorkspaceRootCandidate({
|
|
20013
20500
|
candidatePath: candidateRoot,
|
|
20014
20501
|
repoRoot: action.repoRoot,
|
|
@@ -20342,6 +20829,7 @@ async function evaluateGatedAction(ctx, deps, params) {
|
|
|
20342
20829
|
event: resolveGateAuditEvent(sourceEvent, params.kind),
|
|
20343
20830
|
sourceEvent,
|
|
20344
20831
|
kind: params.kind,
|
|
20832
|
+
...typeof params.payload?.tool_use_id === "string" ? { toolInvocationCorrelationId: toolInvocationCorrelationId(params.payload.tool_use_id) } : {},
|
|
20345
20833
|
fingerprint: verdict2.fingerprint,
|
|
20346
20834
|
verdict: verdict2.verdict,
|
|
20347
20835
|
reason: verdict2.reason,
|
|
@@ -20499,6 +20987,7 @@ async function evaluateGatedAction(ctx, deps, params) {
|
|
|
20499
20987
|
const scrubbedPayload = fingerprintReplayPayload(params.kind, params.payload, scrubOpts);
|
|
20500
20988
|
return gateDecisionToVerdict(ctx, deps, params.kind, result, {
|
|
20501
20989
|
sourceEvent: params.sourceEvent,
|
|
20990
|
+
toolInvocationCorrelationId: typeof params.payload?.tool_use_id === "string" ? toolInvocationCorrelationId(params.payload.tool_use_id) : void 0,
|
|
20502
20991
|
predictedAssessment,
|
|
20503
20992
|
observedAssessment: observedAssessment2,
|
|
20504
20993
|
transactionalLayer,
|
|
@@ -20582,6 +21071,7 @@ async function gateDecisionToVerdict(ctx, deps, kind, result, auditExtras = {})
|
|
|
20582
21071
|
event: auditEvent,
|
|
20583
21072
|
sourceEvent,
|
|
20584
21073
|
kind,
|
|
21074
|
+
...auditExtras.toolInvocationCorrelationId ? { toolInvocationCorrelationId: auditExtras.toolInvocationCorrelationId } : {},
|
|
20585
21075
|
fingerprint: result.fingerprint,
|
|
20586
21076
|
summary: result.normalizedCommand ?? result.summary ?? "",
|
|
20587
21077
|
assessment: result.assessment,
|
|
@@ -21028,29 +21518,56 @@ function gateVerdictToClaudeUserPromptResponse(verdict2) {
|
|
|
21028
21518
|
};
|
|
21029
21519
|
}
|
|
21030
21520
|
async function appendObservedAudit(ctx, deps, eventName, payload) {
|
|
21521
|
+
const rawToolUseId = typeof payload.tool_use_id === "string" ? payload.tool_use_id : void 0;
|
|
21522
|
+
const summaryPayload = redactToolInvocationId(payload, rawToolUseId);
|
|
21031
21523
|
await deps.appendAudit(ctx, {
|
|
21032
21524
|
event: eventName,
|
|
21033
21525
|
kind: "audit",
|
|
21034
21526
|
verdict: "allow",
|
|
21035
21527
|
reason: "observed",
|
|
21036
|
-
|
|
21528
|
+
...rawToolUseId ? { toolInvocationCorrelationId: toolInvocationCorrelationId(rawToolUseId) } : {},
|
|
21529
|
+
...typeof summaryPayload.tool_name === "string" ? { toolName: summaryPayload.tool_name } : {},
|
|
21530
|
+
...typeof summaryPayload.failure_type === "string" ? { failureType: summaryPayload.failure_type } : {},
|
|
21531
|
+
...typeof summaryPayload.error_message === "string" ? { errorMessage: summaryPayload.error_message } : {},
|
|
21532
|
+
...typeof payload.duration === "number" ? { durationMs: payload.duration } : {},
|
|
21533
|
+
...typeof payload.is_interrupt === "boolean" ? { isInterrupt: payload.is_interrupt } : {},
|
|
21534
|
+
summary: canonicalStringify(summaryPayload)
|
|
21037
21535
|
});
|
|
21038
21536
|
}
|
|
21039
21537
|
|
|
21040
21538
|
// src/adapters/shared/repo-root.ts
|
|
21041
21539
|
import { existsSync as existsSync17 } from "node:fs";
|
|
21042
|
-
import
|
|
21540
|
+
import path55 from "node:path";
|
|
21541
|
+
function belayConfigPath(current, adapterName) {
|
|
21542
|
+
if (adapterName === "cursor") {
|
|
21543
|
+
return path55.join(current, ".cursor", "belay.config.json");
|
|
21544
|
+
}
|
|
21545
|
+
if (adapterName === "claude") {
|
|
21546
|
+
return path55.join(current, ".claude", "belay.config.json");
|
|
21547
|
+
}
|
|
21548
|
+
return path55.join(current, ".codex", "belay.config.json");
|
|
21549
|
+
}
|
|
21550
|
+
function markerMatches(current, marker, layout) {
|
|
21551
|
+
const markerPath = path55.join(current, marker);
|
|
21552
|
+
if (!existsSync17(markerPath)) {
|
|
21553
|
+
return false;
|
|
21554
|
+
}
|
|
21555
|
+
if (marker === ".cursor" || marker === ".claude" || marker === ".codex") {
|
|
21556
|
+
return existsSync17(belayConfigPath(current, layout.name));
|
|
21557
|
+
}
|
|
21558
|
+
return true;
|
|
21559
|
+
}
|
|
21043
21560
|
function findRepoRoot(startPath, layout) {
|
|
21044
|
-
let current =
|
|
21561
|
+
let current = path55.resolve(startPath);
|
|
21045
21562
|
while (true) {
|
|
21046
21563
|
for (const marker of layout.repoRootMarkers) {
|
|
21047
|
-
if (
|
|
21564
|
+
if (markerMatches(current, marker, layout)) {
|
|
21048
21565
|
return current;
|
|
21049
21566
|
}
|
|
21050
21567
|
}
|
|
21051
|
-
const parent =
|
|
21568
|
+
const parent = path55.dirname(current);
|
|
21052
21569
|
if (parent === current) {
|
|
21053
|
-
return
|
|
21570
|
+
return path55.resolve(startPath);
|
|
21054
21571
|
}
|
|
21055
21572
|
current = parent;
|
|
21056
21573
|
}
|