terminalhire 0.42.40 → 0.42.42
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/dist/bin/jpi-claim.js +515 -33
- package/dist/bin/jpi-dispatch.js +516 -34
- package/dist/bin/jpi-mcp.js +516 -34
- package/dist/bin/jpi-run.js +527 -45
- package/package.json +1 -1
package/dist/bin/jpi-claim.js
CHANGED
|
@@ -26435,7 +26435,19 @@ function isGreen(outcome) {
|
|
|
26435
26435
|
function isOurFault(outcome) {
|
|
26436
26436
|
return LIMIT_OWNER[outcome] === "ours";
|
|
26437
26437
|
}
|
|
26438
|
-
|
|
26438
|
+
function readStoppedAt(stdout, stderr = "") {
|
|
26439
|
+
return lastStepMarker(stdout) ?? lastStepMarker(stderr);
|
|
26440
|
+
}
|
|
26441
|
+
function isStepName(value) {
|
|
26442
|
+
return value.length > 0 && value.length <= STOPPED_AT_MAX && SCRIPT_NAME.test(value);
|
|
26443
|
+
}
|
|
26444
|
+
function lastStepMarker(text) {
|
|
26445
|
+
let last = null;
|
|
26446
|
+
for (const m of text.replace(/\r\n/g, "\n").matchAll(NPM_STEP_MARKER))
|
|
26447
|
+
last = m[1];
|
|
26448
|
+
return last !== null && isStepName(last) ? last : null;
|
|
26449
|
+
}
|
|
26450
|
+
var VERIFICATION_OUTCOMES, int, withSuiteFailures, countLines, READERS, SUPPORTED_RUNNERS, COVERAGE_TABLE, EXEC_FAILURE, SUITE_REPORTED_FAILURE, MISSING_SYSTEM_DEPENDENCY, OFFLINE_BUILD_GAP, LIMIT_OWNER, NPM_STEP_MARKER, STOPPED_AT_MAX, SCRIPT_NAME;
|
|
26439
26451
|
var init_classify2 = __esm({
|
|
26440
26452
|
"../../packages/envrun/dist/classify.js"() {
|
|
26441
26453
|
"use strict";
|
|
@@ -26858,6 +26870,9 @@ var init_classify2 = __esm({
|
|
|
26858
26870
|
"environment-exhausted": "ours",
|
|
26859
26871
|
"budget-exceeded": "ours"
|
|
26860
26872
|
};
|
|
26873
|
+
NPM_STEP_MARKER = /^> (?:@[^\s@/]+\/)?[^\s@]+@\S+ (\S+)/gm;
|
|
26874
|
+
STOPPED_AT_MAX = 200;
|
|
26875
|
+
SCRIPT_NAME = /^[A-Za-z0-9:_.\-/+@]+$/;
|
|
26861
26876
|
}
|
|
26862
26877
|
});
|
|
26863
26878
|
|
|
@@ -31033,7 +31048,9 @@ var init_result = __esm({
|
|
|
31033
31048
|
"leaksClean",
|
|
31034
31049
|
"leakState",
|
|
31035
31050
|
"venue",
|
|
31036
|
-
"refusalOrigin"
|
|
31051
|
+
"refusalOrigin",
|
|
31052
|
+
"stoppedAt",
|
|
31053
|
+
"installFrozen"
|
|
31037
31054
|
];
|
|
31038
31055
|
RENDER_NONE = null;
|
|
31039
31056
|
FIELD_VIEWS = {
|
|
@@ -31096,7 +31113,12 @@ var init_result = __esm({
|
|
|
31096
31113
|
venue: (r) => r.venue === null ? null : renderVenueLine(r.venue),
|
|
31097
31114
|
// For the worker and the baseline intake, not the terminal: `reason` already says which
|
|
31098
31115
|
// side refused in words a developer reads.
|
|
31099
|
-
refusalOrigin: RENDER_NONE
|
|
31116
|
+
refusalOrigin: RENDER_NONE,
|
|
31117
|
+
// Only when the run did not pass: on a green run "the last step" is just the last step.
|
|
31118
|
+
stoppedAt: (r) => r.stoppedAt === null || r.outcome === "completed" ? null : `last step ${r.stoppedAt} (the last package script named in the output)`,
|
|
31119
|
+
// The run already prints the unfrozen note while it runs (`installUnfrozenNote`); this is
|
|
31120
|
+
// the record of it for the worker and the intake.
|
|
31121
|
+
installFrozen: RENDER_NONE
|
|
31100
31122
|
};
|
|
31101
31123
|
}
|
|
31102
31124
|
});
|
|
@@ -31472,6 +31494,317 @@ var init_lockfileCheck = __esm({
|
|
|
31472
31494
|
}
|
|
31473
31495
|
});
|
|
31474
31496
|
|
|
31497
|
+
// ../../packages/envrun/dist/binaryPatch.js
|
|
31498
|
+
import { createHash as createHash11 } from "crypto";
|
|
31499
|
+
import { inflateSync } from "zlib";
|
|
31500
|
+
function decodeBase85Line(line) {
|
|
31501
|
+
const first = line.charCodeAt(0);
|
|
31502
|
+
let length;
|
|
31503
|
+
if (first >= 65 && first <= 90)
|
|
31504
|
+
length = first - 64;
|
|
31505
|
+
else if (first >= 97 && first <= 122)
|
|
31506
|
+
length = first - 96 + 26;
|
|
31507
|
+
else
|
|
31508
|
+
return null;
|
|
31509
|
+
const groups = Math.ceil(length / 4);
|
|
31510
|
+
if (line.length !== 1 + groups * 5)
|
|
31511
|
+
return null;
|
|
31512
|
+
const out = new Uint8Array(groups * 4);
|
|
31513
|
+
for (let g = 0; g < groups; g += 1) {
|
|
31514
|
+
let acc = 0;
|
|
31515
|
+
for (let k = 0; k < 5; k += 1) {
|
|
31516
|
+
const code = line.charCodeAt(1 + g * 5 + k);
|
|
31517
|
+
const value = code < 128 ? B85_VALUE[code] ?? -1 : -1;
|
|
31518
|
+
if (value < 0)
|
|
31519
|
+
return null;
|
|
31520
|
+
acc = acc * 85 + value;
|
|
31521
|
+
}
|
|
31522
|
+
if (acc > 4294967295)
|
|
31523
|
+
return null;
|
|
31524
|
+
out[g * 4] = acc >>> 24 & 255;
|
|
31525
|
+
out[g * 4 + 1] = acc >>> 16 & 255;
|
|
31526
|
+
out[g * 4 + 2] = acc >>> 8 & 255;
|
|
31527
|
+
out[g * 4 + 3] = acc & 255;
|
|
31528
|
+
}
|
|
31529
|
+
return out.subarray(0, length);
|
|
31530
|
+
}
|
|
31531
|
+
function readBinaryPayload(lines) {
|
|
31532
|
+
const blocks = [];
|
|
31533
|
+
let i = 0;
|
|
31534
|
+
while (i < lines.length) {
|
|
31535
|
+
const line = lines[i] ?? "";
|
|
31536
|
+
if (line === "") {
|
|
31537
|
+
i += 1;
|
|
31538
|
+
continue;
|
|
31539
|
+
}
|
|
31540
|
+
if (blocks.length === 2)
|
|
31541
|
+
return null;
|
|
31542
|
+
const header = BLOCK_HEADER.exec(line);
|
|
31543
|
+
if (header === null)
|
|
31544
|
+
return null;
|
|
31545
|
+
const size = Number(header[2]);
|
|
31546
|
+
if (!Number.isSafeInteger(size))
|
|
31547
|
+
return null;
|
|
31548
|
+
i += 1;
|
|
31549
|
+
const parts = [];
|
|
31550
|
+
let total = 0;
|
|
31551
|
+
while (i < lines.length && (lines[i] ?? "") !== "") {
|
|
31552
|
+
const decoded = decodeBase85Line(lines[i] ?? "");
|
|
31553
|
+
if (decoded === null)
|
|
31554
|
+
return null;
|
|
31555
|
+
total += decoded.length;
|
|
31556
|
+
if (total > MAX_BINARY_DEFLATED_BLOCK_BYTES)
|
|
31557
|
+
return null;
|
|
31558
|
+
parts.push(decoded);
|
|
31559
|
+
i += 1;
|
|
31560
|
+
}
|
|
31561
|
+
if (parts.length === 0)
|
|
31562
|
+
return null;
|
|
31563
|
+
if (i >= lines.length)
|
|
31564
|
+
return null;
|
|
31565
|
+
const deflated = new Uint8Array(total);
|
|
31566
|
+
let at = 0;
|
|
31567
|
+
for (const p of parts) {
|
|
31568
|
+
deflated.set(p, at);
|
|
31569
|
+
at += p.length;
|
|
31570
|
+
}
|
|
31571
|
+
blocks.push({ kind: header[1] === "delta" ? "delta" : "literal", size, deflated });
|
|
31572
|
+
}
|
|
31573
|
+
const forward = blocks[0];
|
|
31574
|
+
if (forward === void 0)
|
|
31575
|
+
return null;
|
|
31576
|
+
return { forward, reverse: blocks[1] ?? null };
|
|
31577
|
+
}
|
|
31578
|
+
function inflateExact(block, limit2) {
|
|
31579
|
+
if (block.size > limit2)
|
|
31580
|
+
return null;
|
|
31581
|
+
try {
|
|
31582
|
+
const out = inflateSync(block.deflated, { maxOutputLength: block.size + 1 });
|
|
31583
|
+
return out.length === block.size ? new Uint8Array(out) : null;
|
|
31584
|
+
} catch {
|
|
31585
|
+
return null;
|
|
31586
|
+
}
|
|
31587
|
+
}
|
|
31588
|
+
function readVarint(delta, from) {
|
|
31589
|
+
let value = 0;
|
|
31590
|
+
let shift = 0;
|
|
31591
|
+
let pos = from;
|
|
31592
|
+
for (; ; ) {
|
|
31593
|
+
const byte = delta[pos];
|
|
31594
|
+
if (byte === void 0 || shift > 42)
|
|
31595
|
+
return null;
|
|
31596
|
+
value += (byte & 127) * 2 ** shift;
|
|
31597
|
+
pos += 1;
|
|
31598
|
+
shift += 7;
|
|
31599
|
+
if ((byte & 128) === 0)
|
|
31600
|
+
return { value, next: pos };
|
|
31601
|
+
}
|
|
31602
|
+
}
|
|
31603
|
+
function deltaHeader(delta) {
|
|
31604
|
+
const source = readVarint(delta, 0);
|
|
31605
|
+
if (source === null)
|
|
31606
|
+
return null;
|
|
31607
|
+
const target = readVarint(delta, source.next);
|
|
31608
|
+
if (target === null)
|
|
31609
|
+
return null;
|
|
31610
|
+
return { source: source.value, target: target.value, opsAt: target.next };
|
|
31611
|
+
}
|
|
31612
|
+
function deltaLeadingInserts(delta, opsAt) {
|
|
31613
|
+
const parts = [];
|
|
31614
|
+
let pos = opsAt;
|
|
31615
|
+
while (pos < delta.length && parts.length < 64) {
|
|
31616
|
+
const op = delta[pos] ?? 0;
|
|
31617
|
+
if (op === 0 || (op & 128) !== 0)
|
|
31618
|
+
break;
|
|
31619
|
+
const end = Math.min(pos + 1 + op, delta.length);
|
|
31620
|
+
for (let i = pos + 1; i < end; i += 1)
|
|
31621
|
+
parts.push(delta[i] ?? 0);
|
|
31622
|
+
pos = end;
|
|
31623
|
+
}
|
|
31624
|
+
return Uint8Array.from(parts);
|
|
31625
|
+
}
|
|
31626
|
+
function startsWith(bytes, magic, at = 0) {
|
|
31627
|
+
if (bytes.length < at + magic.length)
|
|
31628
|
+
return false;
|
|
31629
|
+
return magic.every((b, i) => bytes[at + i] === b);
|
|
31630
|
+
}
|
|
31631
|
+
function sniffBinaryType(bytes) {
|
|
31632
|
+
if (startsWith(bytes, [127, 69, 76, 70]))
|
|
31633
|
+
return { label: "ELF", program: true };
|
|
31634
|
+
for (const magic of [
|
|
31635
|
+
[254, 237, 250, 206],
|
|
31636
|
+
[254, 237, 250, 207],
|
|
31637
|
+
[206, 250, 237, 254],
|
|
31638
|
+
[207, 250, 237, 254],
|
|
31639
|
+
[202, 254, 186, 191],
|
|
31640
|
+
[190, 186, 254, 202],
|
|
31641
|
+
[191, 186, 254, 202]
|
|
31642
|
+
]) {
|
|
31643
|
+
if (startsWith(bytes, magic))
|
|
31644
|
+
return { label: "Mach-O", program: true };
|
|
31645
|
+
}
|
|
31646
|
+
if (startsWith(bytes, [202, 254, 186, 190])) {
|
|
31647
|
+
const major = bytes.length >= 8 ? (bytes[6] ?? 0) << 8 | (bytes[7] ?? 0) : 0;
|
|
31648
|
+
return { label: major >= 45 ? "Java class" : "Mach-O", program: true };
|
|
31649
|
+
}
|
|
31650
|
+
if (startsWith(bytes, [0, 97, 115, 109]))
|
|
31651
|
+
return { label: "WebAssembly", program: true };
|
|
31652
|
+
if (startsWith(bytes, [77, 90]))
|
|
31653
|
+
return { label: "PE", program: true };
|
|
31654
|
+
if (startsWith(bytes, [137, 80, 78, 71, 13, 10, 26, 10])) {
|
|
31655
|
+
return { label: "PNG", program: false };
|
|
31656
|
+
}
|
|
31657
|
+
if (startsWith(bytes, [255, 216, 255]))
|
|
31658
|
+
return { label: "JPEG", program: false };
|
|
31659
|
+
if (startsWith(bytes, [71, 73, 70, 56, 55, 97]) || startsWith(bytes, [71, 73, 70, 56, 57, 97])) {
|
|
31660
|
+
return { label: "GIF", program: false };
|
|
31661
|
+
}
|
|
31662
|
+
if (startsWith(bytes, [82, 73, 70, 70]) && startsWith(bytes, [87, 69, 66, 80], 8)) {
|
|
31663
|
+
return { label: "WebP", program: false };
|
|
31664
|
+
}
|
|
31665
|
+
if (startsWith(bytes, [37, 80, 68, 70, 45]))
|
|
31666
|
+
return { label: "PDF", program: false };
|
|
31667
|
+
if (startsWith(bytes, [119, 79, 70, 70]))
|
|
31668
|
+
return { label: "WOFF", program: false };
|
|
31669
|
+
if (startsWith(bytes, [119, 79, 70, 50]))
|
|
31670
|
+
return { label: "WOFF2", program: false };
|
|
31671
|
+
if (startsWith(bytes, [0, 1, 0, 0]) || startsWith(bytes, [116, 114, 117, 101])) {
|
|
31672
|
+
return { label: "TTF", program: false };
|
|
31673
|
+
}
|
|
31674
|
+
if (startsWith(bytes, [79, 84, 84, 79]))
|
|
31675
|
+
return { label: "OTF", program: false };
|
|
31676
|
+
if (startsWith(bytes, [80, 75, 3, 4]) || startsWith(bytes, [80, 75, 5, 6]) || startsWith(bytes, [80, 75, 7, 8])) {
|
|
31677
|
+
return { label: "ZIP", program: false };
|
|
31678
|
+
}
|
|
31679
|
+
return { label: "unknown binary", program: false };
|
|
31680
|
+
}
|
|
31681
|
+
function formatByteSize(bytes) {
|
|
31682
|
+
if (bytes < 1024)
|
|
31683
|
+
return `${bytes} B`;
|
|
31684
|
+
if (bytes < 1024 * 1024)
|
|
31685
|
+
return `${(bytes / 1024).toFixed(1)} KB`;
|
|
31686
|
+
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
31687
|
+
}
|
|
31688
|
+
function parseFullIndexLine(line) {
|
|
31689
|
+
const m = /^index ([0-9a-f]+)\.\.([0-9a-f]+)(?: ([0-7]{6}))?$/.exec(line);
|
|
31690
|
+
if (m === null)
|
|
31691
|
+
return null;
|
|
31692
|
+
const pre = m[1] ?? "";
|
|
31693
|
+
const post = m[2] ?? "";
|
|
31694
|
+
if (!FULL_ID.test(pre) || !FULL_ID.test(post))
|
|
31695
|
+
return null;
|
|
31696
|
+
return { pre, post, mode: m[3] ?? null };
|
|
31697
|
+
}
|
|
31698
|
+
function isZeroId(id) {
|
|
31699
|
+
return id === ZERO_ID;
|
|
31700
|
+
}
|
|
31701
|
+
function refuse4(code, detail) {
|
|
31702
|
+
return { kind: "refuse", code, detail };
|
|
31703
|
+
}
|
|
31704
|
+
function judgeBinaryEntry(input) {
|
|
31705
|
+
const { path: path5 } = input;
|
|
31706
|
+
if (input.stub) {
|
|
31707
|
+
return refuse4("binary-content-missing", `${path5} is a binary file, but the patch leaves out its contents. Update terminalhire (npm install -g terminalhire@latest) and submit again.`);
|
|
31708
|
+
}
|
|
31709
|
+
if (input.textContent || input.indexLines.length !== 1)
|
|
31710
|
+
return { kind: "unreadable" };
|
|
31711
|
+
const index = parseFullIndexLine(input.indexLines[0] ?? "");
|
|
31712
|
+
if (index === null)
|
|
31713
|
+
return { kind: "unreadable" };
|
|
31714
|
+
if (isZeroId(index.pre) !== input.createsFile)
|
|
31715
|
+
return { kind: "unreadable" };
|
|
31716
|
+
if (isZeroId(index.post) !== input.deletesFile)
|
|
31717
|
+
return { kind: "unreadable" };
|
|
31718
|
+
const payload = readBinaryPayload(input.payload);
|
|
31719
|
+
if (payload === null)
|
|
31720
|
+
return { kind: "unreadable" };
|
|
31721
|
+
if (input.deletesFile) {
|
|
31722
|
+
const forward2 = payload.forward;
|
|
31723
|
+
if (forward2.kind !== "literal" || inflateExact(forward2, 0) === null) {
|
|
31724
|
+
return { kind: "unreadable" };
|
|
31725
|
+
}
|
|
31726
|
+
const reverse = payload.reverse;
|
|
31727
|
+
const removed = reverse !== null && reverse.kind === "literal" ? inflateExact(reverse, MAX_BINARY_FILE_BYTES) : null;
|
|
31728
|
+
return {
|
|
31729
|
+
kind: "hold",
|
|
31730
|
+
type: removed === null ? "unknown binary" : sniffBinaryType(removed).label,
|
|
31731
|
+
size: reverse !== null && reverse.kind === "literal" ? reverse.size : 0,
|
|
31732
|
+
writes: 0,
|
|
31733
|
+
hash: index.pre
|
|
31734
|
+
};
|
|
31735
|
+
}
|
|
31736
|
+
const mode = input.newMode ?? index.mode ?? "100644";
|
|
31737
|
+
if (mode === "100755")
|
|
31738
|
+
return refuse4("binary-executable", binaryExecutableDetail(path5));
|
|
31739
|
+
if (mode !== "100644")
|
|
31740
|
+
return refuse4("binary-mode", unsupportedModeDetail(path5, mode));
|
|
31741
|
+
const tooLarge = (size2) => refuse4("binary-too-large", `${path5} is ${formatByteSize(size2)}. One binary file can be at most 2 MB.`);
|
|
31742
|
+
let size;
|
|
31743
|
+
let head;
|
|
31744
|
+
const forward = payload.forward;
|
|
31745
|
+
if (forward.kind === "literal") {
|
|
31746
|
+
if (forward.size > MAX_BINARY_FILE_BYTES) {
|
|
31747
|
+
return tooLarge(forward.size);
|
|
31748
|
+
}
|
|
31749
|
+
const bytes = inflateExact(forward, MAX_BINARY_FILE_BYTES);
|
|
31750
|
+
if (bytes === null)
|
|
31751
|
+
return { kind: "unreadable" };
|
|
31752
|
+
size = bytes.length;
|
|
31753
|
+
head = bytes;
|
|
31754
|
+
} else {
|
|
31755
|
+
if (input.createsFile)
|
|
31756
|
+
return { kind: "unreadable" };
|
|
31757
|
+
const delta = inflateExact(forward, 2 * MAX_BINARY_FILE_BYTES);
|
|
31758
|
+
if (delta === null)
|
|
31759
|
+
return { kind: "unreadable" };
|
|
31760
|
+
const header = deltaHeader(delta);
|
|
31761
|
+
if (header === null)
|
|
31762
|
+
return { kind: "unreadable" };
|
|
31763
|
+
if (header.target > MAX_BINARY_FILE_BYTES)
|
|
31764
|
+
return tooLarge(header.target);
|
|
31765
|
+
size = header.target;
|
|
31766
|
+
head = deltaLeadingInserts(delta, header.opsAt);
|
|
31767
|
+
}
|
|
31768
|
+
const type = sniffBinaryType(head);
|
|
31769
|
+
if (type.program) {
|
|
31770
|
+
return refuse4("binary-program", binaryProgramDetail(path5, type.label));
|
|
31771
|
+
}
|
|
31772
|
+
return { kind: "hold", type: type.label, size, writes: size, hash: index.post };
|
|
31773
|
+
}
|
|
31774
|
+
function binaryTotalRefusal(totalBytes) {
|
|
31775
|
+
if (totalBytes <= MAX_BINARY_PATCH_BYTES)
|
|
31776
|
+
return null;
|
|
31777
|
+
return `The binary files in this patch add up to ${formatByteSize(totalBytes)}. A patch can carry at most 3 MB of binary files.`;
|
|
31778
|
+
}
|
|
31779
|
+
function binaryExecutableDetail(path5) {
|
|
31780
|
+
return `${path5} is a binary file marked executable. Binary files can't be marked executable in a patch.`;
|
|
31781
|
+
}
|
|
31782
|
+
function unsupportedModeDetail(path5, mode) {
|
|
31783
|
+
return `The patch changes ${path5} to a file type this platform will not apply on your behalf (mode ${mode}). Nothing on your repository was changed.`;
|
|
31784
|
+
}
|
|
31785
|
+
function binaryProgramDetail(path5, label) {
|
|
31786
|
+
return `${path5} is a program (${label}). Patches can't add or change programs, because the install or test step could run them.`;
|
|
31787
|
+
}
|
|
31788
|
+
var MAX_BINARY_FILE_BYTES, MAX_BINARY_PATCH_BYTES, MAX_BINARY_DEFLATED_BLOCK_BYTES, FULL_ID, ZERO_ID, B85_ALPHABET, B85_VALUE, BLOCK_HEADER;
|
|
31789
|
+
var init_binaryPatch = __esm({
|
|
31790
|
+
"../../packages/envrun/dist/binaryPatch.js"() {
|
|
31791
|
+
"use strict";
|
|
31792
|
+
MAX_BINARY_FILE_BYTES = 2 * 1024 * 1024;
|
|
31793
|
+
MAX_BINARY_PATCH_BYTES = 3 * 1024 * 1024;
|
|
31794
|
+
MAX_BINARY_DEFLATED_BLOCK_BYTES = 2 * MAX_BINARY_FILE_BYTES + 64 * 1024;
|
|
31795
|
+
FULL_ID = /^[0-9a-f]{40}$/;
|
|
31796
|
+
ZERO_ID = "0".repeat(40);
|
|
31797
|
+
B85_ALPHABET = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!#$%&()*+-;<=>?@^_`{|}~";
|
|
31798
|
+
B85_VALUE = (() => {
|
|
31799
|
+
const table = new Array(128).fill(-1);
|
|
31800
|
+
for (let i = 0; i < B85_ALPHABET.length; i += 1)
|
|
31801
|
+
table[B85_ALPHABET.charCodeAt(i)] = i;
|
|
31802
|
+
return table;
|
|
31803
|
+
})();
|
|
31804
|
+
BLOCK_HEADER = /^(literal|delta) (0|[1-9][0-9]{0,15})$/;
|
|
31805
|
+
}
|
|
31806
|
+
});
|
|
31807
|
+
|
|
31475
31808
|
// ../../packages/envrun/dist/boundary.js
|
|
31476
31809
|
function lockfileRefusal(base) {
|
|
31477
31810
|
const kind = LOCKFILE_KINDS[base];
|
|
@@ -31596,6 +31929,11 @@ function parsePatchPaths(patch) {
|
|
|
31596
31929
|
entry = {
|
|
31597
31930
|
rawPaths: [],
|
|
31598
31931
|
binary: false,
|
|
31932
|
+
binaryStub: false,
|
|
31933
|
+
binaryPayload: [],
|
|
31934
|
+
indexLines: [],
|
|
31935
|
+
newMode: null,
|
|
31936
|
+
textContent: false,
|
|
31599
31937
|
headerOld: null,
|
|
31600
31938
|
headerNew: null,
|
|
31601
31939
|
plusPath: null,
|
|
@@ -31629,8 +31967,10 @@ function parsePatchPaths(patch) {
|
|
|
31629
31967
|
}
|
|
31630
31968
|
if (entry === null)
|
|
31631
31969
|
continue;
|
|
31632
|
-
if (skippingBinary)
|
|
31970
|
+
if (skippingBinary) {
|
|
31971
|
+
entry.binaryPayload.push(line);
|
|
31633
31972
|
continue;
|
|
31973
|
+
}
|
|
31634
31974
|
if (inHunk) {
|
|
31635
31975
|
const marker = line === "" ? " " : line[0];
|
|
31636
31976
|
if (marker === "\\")
|
|
@@ -31657,6 +31997,7 @@ function parsePatchPaths(patch) {
|
|
|
31657
31997
|
if (line === "-- " || line === "--")
|
|
31658
31998
|
break;
|
|
31659
31999
|
if (line.startsWith("@@")) {
|
|
32000
|
+
entry.textContent = true;
|
|
31660
32001
|
const m = HUNK_HEADER.exec(line);
|
|
31661
32002
|
if (m === null) {
|
|
31662
32003
|
return fail3("a change block header is malformed, so we cannot tell which lines belong to it");
|
|
@@ -31673,13 +32014,20 @@ function parsePatchPaths(patch) {
|
|
|
31673
32014
|
const mode = /^(?:old mode|new mode|new file mode|deleted file mode) (\d+)$/.exec(line)?.[1] ?? /^index [0-9a-f]+\.\.[0-9a-f]+ (\d+)$/.exec(line)?.[1];
|
|
31674
32015
|
if (mode !== void 0)
|
|
31675
32016
|
entry.modes.push(mode);
|
|
32017
|
+
if (line.startsWith("index "))
|
|
32018
|
+
entry.indexLines.push(line);
|
|
32019
|
+
if (line.startsWith("new file mode ") || line.startsWith("new mode ")) {
|
|
32020
|
+
entry.newMode = line.slice(line.lastIndexOf(" ") + 1).trim();
|
|
32021
|
+
}
|
|
31676
32022
|
if (line === "GIT binary patch" || line.startsWith("Binary files ")) {
|
|
31677
32023
|
entry.binary = true;
|
|
32024
|
+
entry.binaryStub = line !== "GIT binary patch";
|
|
31678
32025
|
skippingBinary = true;
|
|
31679
32026
|
continue;
|
|
31680
32027
|
}
|
|
31681
32028
|
const sideMarker = line.startsWith("--- ") ? "a/" : line.startsWith("+++ ") ? "b/" : null;
|
|
31682
32029
|
if (sideMarker !== null) {
|
|
32030
|
+
entry.textContent = true;
|
|
31683
32031
|
const rest = line.slice(4);
|
|
31684
32032
|
const tab = rest.indexOf(" ");
|
|
31685
32033
|
const token = tab === -1 ? rest : rest.slice(0, tab);
|
|
@@ -31754,16 +32102,14 @@ function preflightBoundary(input) {
|
|
|
31754
32102
|
const changedManifests = /* @__PURE__ */ new Set();
|
|
31755
32103
|
const deniedPaths = /* @__PURE__ */ new Set();
|
|
31756
32104
|
const nonFileLockfiles = /* @__PURE__ */ new Set();
|
|
32105
|
+
let binaryBytes = 0;
|
|
31757
32106
|
for (const entry of parsed.entries) {
|
|
31758
|
-
|
|
31759
|
-
const name = entry.rawPaths[0] ?? "a file";
|
|
31760
|
-
refusals.push(refusal("binary-patch", normalizePath(name)?.path ?? null, `${name} is changed as binary content, which nobody can review line by line. Binary changes are refused.`));
|
|
31761
|
-
continue;
|
|
31762
|
-
}
|
|
32107
|
+
let refusedByPath = false;
|
|
31763
32108
|
const entryPaths = [];
|
|
31764
32109
|
for (const raw of entry.rawPaths) {
|
|
31765
32110
|
const normalized = normalizePath(raw);
|
|
31766
32111
|
if (normalized === null) {
|
|
32112
|
+
refusedByPath = true;
|
|
31767
32113
|
if (!seenPaths.has(raw)) {
|
|
31768
32114
|
seenPaths.add(raw);
|
|
31769
32115
|
refusals.push(refusal("unsafe-path", raw, `${raw} is not a file name a patch may name \u2014 it points outside the repository, or it is written in a form we cannot check.`));
|
|
@@ -31781,6 +32127,7 @@ function preflightBoundary(input) {
|
|
|
31781
32127
|
seenPaths.add(path5);
|
|
31782
32128
|
const denied = DENY_RULES.find((rule) => rule.matches(path5, segments, base));
|
|
31783
32129
|
if (denied !== void 0) {
|
|
32130
|
+
refusedByPath = true;
|
|
31784
32131
|
deniedPaths.add(path5);
|
|
31785
32132
|
const why = typeof denied.why === "string" ? denied.why : denied.why(base);
|
|
31786
32133
|
refusals.push(refusal(denied.code, path5, `${path5} ${why}.`));
|
|
@@ -31806,7 +32153,29 @@ function preflightBoundary(input) {
|
|
|
31806
32153
|
if (contentPath !== null && contentPath.split("/").pop() === "package.json" && entry.changed) {
|
|
31807
32154
|
changedManifests.add(contentPath);
|
|
31808
32155
|
}
|
|
32156
|
+
if (entry.binary && !refusedByPath && contentPath !== null) {
|
|
32157
|
+
const verdict = judgeBinaryEntry({
|
|
32158
|
+
path: contentPath,
|
|
32159
|
+
stub: entry.binaryStub,
|
|
32160
|
+
payload: entry.binaryPayload,
|
|
32161
|
+
indexLines: entry.indexLines,
|
|
32162
|
+
newMode: entry.newMode,
|
|
32163
|
+
createsFile: entry.createsFile,
|
|
32164
|
+
deletesFile: entry.deletesFile,
|
|
32165
|
+
textContent: entry.textContent
|
|
32166
|
+
});
|
|
32167
|
+
if (verdict.kind === "refuse") {
|
|
32168
|
+
refusals.push(refusal(verdict.code, contentPath, verdict.detail));
|
|
32169
|
+
} else if (verdict.kind === "unreadable") {
|
|
32170
|
+
refusals.push(refusal("unparseable", contentPath, `The patch could not be read: the entry for ${contentPath} carries no changes we can apply. A patch we cannot read in full is refused rather than applied in part.`));
|
|
32171
|
+
} else {
|
|
32172
|
+
binaryBytes += verdict.writes;
|
|
32173
|
+
}
|
|
32174
|
+
}
|
|
31809
32175
|
}
|
|
32176
|
+
const overBinaryCap = binaryTotalRefusal(binaryBytes);
|
|
32177
|
+
if (overBinaryCap !== null)
|
|
32178
|
+
refusals.push(refusal("binary-too-large", null, overBinaryCap));
|
|
31810
32179
|
for (const [path5, { touches, edits }] of lockfileTouches) {
|
|
31811
32180
|
if (deniedPaths.has(path5))
|
|
31812
32181
|
continue;
|
|
@@ -31830,10 +32199,18 @@ var init_boundary = __esm({
|
|
|
31830
32199
|
"../../packages/envrun/dist/boundary.js"() {
|
|
31831
32200
|
"use strict";
|
|
31832
32201
|
init_lockfileCheck();
|
|
32202
|
+
init_binaryPatch();
|
|
31833
32203
|
PATH_REFUSAL_CODES = [
|
|
31834
32204
|
"empty-patch",
|
|
31835
32205
|
"unparseable",
|
|
31836
32206
|
"binary-patch",
|
|
32207
|
+
// Not path-derived, but refused on both sides for the same bytes, so they belong on the
|
|
32208
|
+
// surface `boundary-oracle.test.mjs` compares (TERM-1342).
|
|
32209
|
+
"binary-content-missing",
|
|
32210
|
+
"binary-executable",
|
|
32211
|
+
"binary-mode",
|
|
32212
|
+
"binary-program",
|
|
32213
|
+
"binary-too-large",
|
|
31837
32214
|
"unsafe-path",
|
|
31838
32215
|
"out-of-slice",
|
|
31839
32216
|
"ci-config",
|
|
@@ -32190,7 +32567,7 @@ var init_emptyGitConfig = __esm({
|
|
|
32190
32567
|
|
|
32191
32568
|
// ../../packages/envrun/dist/hostedVenue.js
|
|
32192
32569
|
import { spawn as spawn4, spawnSync as spawnSync5 } from "child_process";
|
|
32193
|
-
import { createHash as
|
|
32570
|
+
import { createHash as createHash12, X509Certificate } from "crypto";
|
|
32194
32571
|
import { chmodSync as chmodSync3, existsSync as existsSync12, mkdtempSync as mkdtempSync3, readFileSync as readFileSync12, rmSync as rmSync8, writeFileSync as writeFileSync14 } from "fs";
|
|
32195
32572
|
import { request as httpsRequest } from "https";
|
|
32196
32573
|
import { createServer } from "net";
|
|
@@ -32860,7 +33237,7 @@ function iapPortTunnelArgv(vm, project, zone, remotePort, localPort) {
|
|
|
32860
33237
|
}
|
|
32861
33238
|
function spkiSha256Hex(certDer) {
|
|
32862
33239
|
const spki = new X509Certificate(certDer).publicKey.export({ type: "spki", format: "der" });
|
|
32863
|
-
return
|
|
33240
|
+
return createHash12("sha256").update(spki).digest("hex");
|
|
32864
33241
|
}
|
|
32865
33242
|
function certMetadataValue(pem) {
|
|
32866
33243
|
return new X509Certificate(pem).raw.toString("base64url");
|
|
@@ -34779,6 +35156,10 @@ function nodeInstallCommand(repo) {
|
|
|
34779
35156
|
return null;
|
|
34780
35157
|
}
|
|
34781
35158
|
function lockfileGaps(repo) {
|
|
35159
|
+
const read = readLockfileGaps(repo);
|
|
35160
|
+
return read === null || read.missing.length === 0 ? null : { lockfile: read.lockfile, missing: read.missing };
|
|
35161
|
+
}
|
|
35162
|
+
function readLockfileGaps(repo) {
|
|
34782
35163
|
const pkg = readJsonObject(repo, "package.json");
|
|
34783
35164
|
if (pkg === null)
|
|
34784
35165
|
return null;
|
|
@@ -34805,7 +35186,7 @@ function lockfileGaps(repo) {
|
|
|
34805
35186
|
missing.push(`${n}@${r} (${dir})`);
|
|
34806
35187
|
}
|
|
34807
35188
|
}
|
|
34808
|
-
return
|
|
35189
|
+
return { lockfile, missing, rootRead: rootListing !== null };
|
|
34809
35190
|
}
|
|
34810
35191
|
function wantedDependencies(pkg) {
|
|
34811
35192
|
const wanted = [];
|
|
@@ -37304,7 +37685,11 @@ function refusedRun(fields) {
|
|
|
37304
37685
|
// reasoning as `leaksClean` above: null because nothing happened, and it must
|
|
37305
37686
|
// not read as a venue we looked at and could not name.
|
|
37306
37687
|
venue: null,
|
|
37307
|
-
refusalOrigin: fields.origin
|
|
37688
|
+
refusalOrigin: fields.origin,
|
|
37689
|
+
// No test step ran, so there is no output to read a step from.
|
|
37690
|
+
stoppedAt: null,
|
|
37691
|
+
// Refused before any install step ran.
|
|
37692
|
+
installFrozen: null
|
|
37308
37693
|
};
|
|
37309
37694
|
}
|
|
37310
37695
|
function refusalOriginOf(refusal2) {
|
|
@@ -37388,7 +37773,29 @@ function installUnfrozenNote(spec) {
|
|
|
37388
37773
|
const u = spec.installUnfrozen;
|
|
37389
37774
|
if (u === void 0)
|
|
37390
37775
|
return null;
|
|
37391
|
-
return `${u.lockfile} does not list ${u.missing.join(", ")}, so the install ran as \`${String(spec.installCommand)}\` without its frozen-lockfile check.
|
|
37776
|
+
return `${u.lockfile} does not list ${u.missing.join(", ")}, so the install ran as \`${String(spec.installCommand)}\` without its frozen-lockfile check. Include the updated ${u.lockfile} in the patch, or regenerate it before merging.`;
|
|
37777
|
+
}
|
|
37778
|
+
function isFrozenInstallCommand(command) {
|
|
37779
|
+
const lead = /^(?:(?:sudo|time)\s+|env(?:\s+[A-Za-z_]\w*=\S*)*\s+)*/.exec(command)?.[0] ?? "";
|
|
37780
|
+
const install = command.slice(lead.length).split(/;|&&|\|\|/)[0]?.trim() ?? "";
|
|
37781
|
+
if (/^npm ci(\s|$)/.test(install))
|
|
37782
|
+
return true;
|
|
37783
|
+
if (/^(yarn|pnpm|bun)\b/.test(install) && /\s--frozen-lockfile(?=\s|$)/.test(install)) {
|
|
37784
|
+
return true;
|
|
37785
|
+
}
|
|
37786
|
+
return /^yarn\b/.test(install) && /\s--immutable(?=\s|$)/.test(install);
|
|
37787
|
+
}
|
|
37788
|
+
function installFrozenFor(spec, install) {
|
|
37789
|
+
if (install === null)
|
|
37790
|
+
return null;
|
|
37791
|
+
const launched = install.exitCode !== INSTALL_NEVER_STARTED && (install.exitCode !== null || install.timedOut);
|
|
37792
|
+
if (!launched)
|
|
37793
|
+
return null;
|
|
37794
|
+
if (spec.runtime !== "node")
|
|
37795
|
+
return null;
|
|
37796
|
+
if (spec.installUnfrozen !== void 0)
|
|
37797
|
+
return false;
|
|
37798
|
+
return isFrozenInstallCommand(install.command);
|
|
37392
37799
|
}
|
|
37393
37800
|
async function verifyWorkingDiff(req) {
|
|
37394
37801
|
const ctx = {
|
|
@@ -37755,7 +38162,10 @@ async function runVerification(req, ctx) {
|
|
|
37755
38162
|
// reasoning and the #735 failure that makes the distinction load-bearing.
|
|
37756
38163
|
venue: describeVenue(lease),
|
|
37757
38164
|
// A run that reached a verdict was not refused, so neither side refused it.
|
|
37758
|
-
refusalOrigin: null
|
|
38165
|
+
refusalOrigin: null,
|
|
38166
|
+
// Read from the full test output, not `outputTail`, which is an excerpt.
|
|
38167
|
+
stoppedAt: readStoppedAt(verdict.test?.stdout ?? "", verdict.test?.stderr ?? ""),
|
|
38168
|
+
installFrozen: installFrozenFor(spec, verdict.install)
|
|
37759
38169
|
};
|
|
37760
38170
|
let later = null;
|
|
37761
38171
|
if (req.screenshots !== void 0) {
|
|
@@ -37954,7 +38364,7 @@ async function prepareBaseTree(o) {
|
|
|
37954
38364
|
throw err;
|
|
37955
38365
|
}
|
|
37956
38366
|
}
|
|
37957
|
-
var ThRunError, OUTPUT_TAIL_BYTES, LOCKFILE_READ_CAP, FULL_COMMIT_ID, ALLOWED_URL_SCHEMES, SCP_STYLE, URL_SCHEME, WINDOWS_ABSOLUTE, UNC_PATH, TRANSPORT_REASON, SHA_REASON, FULL_SHA, MIN_GIT_VERSION_FOR_END_OF_OPTIONS, CloneUnavailableError, GIT_ENV_ALLOWLIST, credentialFreeHomeDir, SSH_ISOLATION_ARGS, WITHHELD_SEGMENT, UNPARSEABLE_TARGET, DEFERRED_GATE_TIMEOUT_MS, FAILURE_LINE, REDACTED_TARGET_REPO, REDACTED_TARGET_SHA;
|
|
38367
|
+
var ThRunError, OUTPUT_TAIL_BYTES, LOCKFILE_READ_CAP, FULL_COMMIT_ID, ALLOWED_URL_SCHEMES, SCP_STYLE, URL_SCHEME, WINDOWS_ABSOLUTE, UNC_PATH, TRANSPORT_REASON, SHA_REASON, FULL_SHA, MIN_GIT_VERSION_FOR_END_OF_OPTIONS, CloneUnavailableError, GIT_ENV_ALLOWLIST, credentialFreeHomeDir, SSH_ISOLATION_ARGS, WITHHELD_SEGMENT, UNPARSEABLE_TARGET, DEFERRED_GATE_TIMEOUT_MS, FAILURE_LINE, REDACTED_TARGET_REPO, REDACTED_TARGET_SHA, INSTALL_NEVER_STARTED;
|
|
37958
38368
|
var init_thrun = __esm({
|
|
37959
38369
|
"../../packages/envrun/dist/thrun.js"() {
|
|
37960
38370
|
"use strict";
|
|
@@ -37962,6 +38372,7 @@ var init_thrun = __esm({
|
|
|
37962
38372
|
init_screenshots();
|
|
37963
38373
|
init_dist3();
|
|
37964
38374
|
init_attestation2();
|
|
38375
|
+
init_classify2();
|
|
37965
38376
|
init_boundary();
|
|
37966
38377
|
init_lockfileCheck();
|
|
37967
38378
|
init_emptyGitConfig();
|
|
@@ -38042,6 +38453,7 @@ var init_thrun = __esm({
|
|
|
38042
38453
|
FAILURE_LINE = /^(?:[ \t]*(?:not ok |FAILED |FAIL )|E {3}|# fail [1-9])/m;
|
|
38043
38454
|
REDACTED_TARGET_REPO = "(refused before the target was accepted)";
|
|
38044
38455
|
REDACTED_TARGET_SHA = "(refused)";
|
|
38456
|
+
INSTALL_NEVER_STARTED = 125;
|
|
38045
38457
|
}
|
|
38046
38458
|
});
|
|
38047
38459
|
|
|
@@ -38943,6 +39355,7 @@ __export(dist_exports, {
|
|
|
38943
39355
|
imageRepo: () => imageRepo,
|
|
38944
39356
|
imageVariantFor: () => imageVariantFor,
|
|
38945
39357
|
installCommandFor: () => installCommandFor,
|
|
39358
|
+
installFrozenFor: () => installFrozenFor,
|
|
38946
39359
|
installLocalMigrationTooling: () => installLocalMigrationTooling,
|
|
38947
39360
|
installUnfrozenNote: () => installUnfrozenNote,
|
|
38948
39361
|
isBookkeepingTable: () => isBookkeepingTable,
|
|
@@ -38971,6 +39384,7 @@ __export(dist_exports, {
|
|
|
38971
39384
|
readAlembicChain: () => readAlembicChain,
|
|
38972
39385
|
readCounts: () => readCounts,
|
|
38973
39386
|
readSchema: () => readSchema,
|
|
39387
|
+
readStoppedAt: () => readStoppedAt,
|
|
38974
39388
|
recordedApplied: () => recordedApplied,
|
|
38975
39389
|
refuseSshTransport: () => refuseSshTransport,
|
|
38976
39390
|
refuseUnbuildableSpec: () => refuseUnbuildableSpec,
|
|
@@ -39314,7 +39728,7 @@ import {
|
|
|
39314
39728
|
closeSync as closeSync6
|
|
39315
39729
|
} from "fs";
|
|
39316
39730
|
import { join as join31, dirname as dirname9, isAbsolute as isAbsolute5, resolve as pathResolve } from "path";
|
|
39317
|
-
import { createHash as
|
|
39731
|
+
import { createHash as createHash13 } from "crypto";
|
|
39318
39732
|
import { homedir as homedir14, hostname as osHostname } from "os";
|
|
39319
39733
|
import { execFile as execFile3, execFileSync as execFileSync2, spawnSync as spawnSync8 } from "child_process";
|
|
39320
39734
|
import { promisify as promisify3 } from "util";
|
|
@@ -41127,7 +41541,7 @@ async function registerFounderClaim(b) {
|
|
|
41127
41541
|
let clearedLocalCredential = false;
|
|
41128
41542
|
let refusedForPurpose = false;
|
|
41129
41543
|
let preserveBackgroundToken = false;
|
|
41130
|
-
const
|
|
41544
|
+
const refuse5 = (reason) => {
|
|
41131
41545
|
console.error(
|
|
41132
41546
|
`
|
|
41133
41547
|
terminalhire claim: refusing to record \u2014 ${reason}
|
|
@@ -41152,7 +41566,7 @@ terminalhire claim: refusing to record \u2014 ${reason}
|
|
|
41152
41566
|
try {
|
|
41153
41567
|
expectLogin = await localLoginForPaidBrowserClaim();
|
|
41154
41568
|
} catch (err) {
|
|
41155
|
-
|
|
41569
|
+
refuse5(
|
|
41156
41570
|
`could not verify which GitHub account this machine is signed in as: ${err instanceof Error ? err.message : String(err)}.
|
|
41157
41571
|
Run \`terminalhire login\`, then retry this claim. Browser verification was
|
|
41158
41572
|
not opened and no claim was sent.`
|
|
@@ -41168,16 +41582,16 @@ terminalhire claim: refusing to record \u2014 ${reason}
|
|
|
41168
41582
|
claimRef: opportunityShortToken(b.bountyId)
|
|
41169
41583
|
});
|
|
41170
41584
|
if (!proofToken) {
|
|
41171
|
-
|
|
41585
|
+
refuse5("could not verify your GitHub identity with terminalhire (see above).");
|
|
41172
41586
|
}
|
|
41173
41587
|
const verifiedLogin = proofTokenLogin(proofToken);
|
|
41174
41588
|
if (!verifiedLogin) {
|
|
41175
|
-
|
|
41589
|
+
refuse5(
|
|
41176
41590
|
"the browser verification response did not name a GitHub account, so it could not be compared with this machine\u2019s sign-in. Nothing was sent; retry the claim."
|
|
41177
41591
|
);
|
|
41178
41592
|
}
|
|
41179
41593
|
if (verifiedLogin.toLowerCase() !== expectLogin.toLowerCase()) {
|
|
41180
|
-
|
|
41594
|
+
refuse5(
|
|
41181
41595
|
`you verified in the browser as @${verifiedLogin}, but this machine is signed in as @${expectLogin}.
|
|
41182
41596
|
Nothing was sent. Sign the browser into @${expectLogin} and run this again, or
|
|
41183
41597
|
run \`terminalhire login\` if you meant to work as @${verifiedLogin}.`
|
|
@@ -41209,7 +41623,7 @@ terminalhire claim: refusing to record \u2014 ${reason}
|
|
|
41209
41623
|
try {
|
|
41210
41624
|
res = await sendRegistration(true);
|
|
41211
41625
|
} catch (err) {
|
|
41212
|
-
|
|
41626
|
+
refuse5(
|
|
41213
41627
|
`terminalhire is unreachable (${err instanceof Error ? err.message : String(err)}), so the posting could not be revalidated.`
|
|
41214
41628
|
);
|
|
41215
41629
|
}
|
|
@@ -41260,7 +41674,7 @@ terminalhire claim: refusing to record \u2014 ${reason}
|
|
|
41260
41674
|
try {
|
|
41261
41675
|
res = await sendRegistration(true);
|
|
41262
41676
|
} catch (err) {
|
|
41263
|
-
|
|
41677
|
+
refuse5(
|
|
41264
41678
|
`terminalhire is unreachable (${err instanceof Error ? err.message : String(err)}), so the posting could not be revalidated.`
|
|
41265
41679
|
);
|
|
41266
41680
|
}
|
|
@@ -41271,14 +41685,14 @@ terminalhire claim: refusing to record \u2014 ${reason}
|
|
|
41271
41685
|
res = await sendRegistration(false);
|
|
41272
41686
|
refusalBody = await readRefusal(res);
|
|
41273
41687
|
} catch (err) {
|
|
41274
|
-
|
|
41688
|
+
refuse5(
|
|
41275
41689
|
`terminalhire is unreachable (${err instanceof Error ? err.message : String(err)}), so the posting could not be revalidated.`
|
|
41276
41690
|
);
|
|
41277
41691
|
}
|
|
41278
41692
|
}
|
|
41279
41693
|
if (!res.ok) {
|
|
41280
41694
|
const detail = refusalBody?.message || refusalBody?.error || "";
|
|
41281
|
-
|
|
41695
|
+
refuse5(
|
|
41282
41696
|
detail ? `the server refused this claim (${res.status}): ${detail}` : `the server refused this claim (${res.status}).`
|
|
41283
41697
|
);
|
|
41284
41698
|
}
|
|
@@ -41289,7 +41703,7 @@ terminalhire claim: refusing to record \u2014 ${reason}
|
|
|
41289
41703
|
body = null;
|
|
41290
41704
|
}
|
|
41291
41705
|
if (!body || body.ok !== true) {
|
|
41292
|
-
|
|
41706
|
+
refuse5("malformed registration response from the server.");
|
|
41293
41707
|
}
|
|
41294
41708
|
const mintedToken = typeof body.pushToken === "string" && body.pushToken.length > 0 ? body.pushToken : null;
|
|
41295
41709
|
if (refusedForPurpose && mintedToken && !preserveBackgroundToken) {
|
|
@@ -42821,7 +43235,7 @@ function writePackFile(destDir, relPath, content, what) {
|
|
|
42821
43235
|
return { written: true, reason: null, sha256: sha256OfUtf8(content) };
|
|
42822
43236
|
}
|
|
42823
43237
|
function sha256OfUtf8(content) {
|
|
42824
|
-
return
|
|
43238
|
+
return createHash13("sha256").update(content, "utf8").digest("hex");
|
|
42825
43239
|
}
|
|
42826
43240
|
function writeWorkspacePack(destDir, spec, claim, delivery) {
|
|
42827
43241
|
if (delivery !== "full" && delivery !== "sparse") {
|
|
@@ -43724,7 +44138,7 @@ function loadClaimScreenshots(specArg) {
|
|
|
43724
44138
|
items.push({
|
|
43725
44139
|
file,
|
|
43726
44140
|
caption: shot.caption,
|
|
43727
|
-
sha256:
|
|
44141
|
+
sha256: createHash13("sha256").update(bytes).digest("hex"),
|
|
43728
44142
|
bytes: bytes.byteLength,
|
|
43729
44143
|
width,
|
|
43730
44144
|
height
|
|
@@ -43790,6 +44204,67 @@ async function uploadClaimScreenshots(intake, uploads) {
|
|
|
43790
44204
|
);
|
|
43791
44205
|
}
|
|
43792
44206
|
}
|
|
44207
|
+
var DEPENDENCY_SECTIONS2 = [
|
|
44208
|
+
"dependencies",
|
|
44209
|
+
"devDependencies",
|
|
44210
|
+
"optionalDependencies",
|
|
44211
|
+
"peerDependencies"
|
|
44212
|
+
];
|
|
44213
|
+
var SENDABLE_LOCKFILES = [
|
|
44214
|
+
["package-lock.json", "npm install"],
|
|
44215
|
+
["yarn.lock", "yarn install"]
|
|
44216
|
+
];
|
|
44217
|
+
async function packageJsonAt(wt, rev, path5) {
|
|
44218
|
+
let text;
|
|
44219
|
+
try {
|
|
44220
|
+
({ stdout: text } = await pExecFile("git", ["-C", wt, "show", `${rev}:${path5}`], {
|
|
44221
|
+
shell: false,
|
|
44222
|
+
maxBuffer: 16 * 1024 * 1024
|
|
44223
|
+
}));
|
|
44224
|
+
} catch {
|
|
44225
|
+
return {};
|
|
44226
|
+
}
|
|
44227
|
+
try {
|
|
44228
|
+
const parsed = JSON.parse(String(text));
|
|
44229
|
+
return parsed !== null && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
|
|
44230
|
+
} catch {
|
|
44231
|
+
return null;
|
|
44232
|
+
}
|
|
44233
|
+
}
|
|
44234
|
+
function sectionKey(pkg, section) {
|
|
44235
|
+
const value = pkg[section];
|
|
44236
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
44237
|
+
return JSON.stringify(value ?? null);
|
|
44238
|
+
}
|
|
44239
|
+
return JSON.stringify(Object.keys(value).sort().map((k) => [k, value[k]]));
|
|
44240
|
+
}
|
|
44241
|
+
async function patchChangesDependencies(wt, base, touched) {
|
|
44242
|
+
for (const path5 of touched) {
|
|
44243
|
+
if (path5.split("/").pop() !== "package.json") continue;
|
|
44244
|
+
const before = await packageJsonAt(wt, base, path5);
|
|
44245
|
+
const after = await packageJsonAt(wt, "HEAD", path5);
|
|
44246
|
+
if (before === null || after === null) continue;
|
|
44247
|
+
if (DEPENDENCY_SECTIONS2.some((s) => sectionKey(before, s) !== sectionKey(after, s))) return true;
|
|
44248
|
+
}
|
|
44249
|
+
return false;
|
|
44250
|
+
}
|
|
44251
|
+
async function dependencyLockfileWarnings(wt, base, touched) {
|
|
44252
|
+
if (!await patchChangesDependencies(wt, base, touched)) return [];
|
|
44253
|
+
const warnings = [];
|
|
44254
|
+
for (const [lockfile, cmd] of SENDABLE_LOCKFILES) {
|
|
44255
|
+
let present;
|
|
44256
|
+
try {
|
|
44257
|
+
present = (await sh("git", ["-C", wt, "ls-tree", "--name-only", base, "--", lockfile])).trim() === lockfile;
|
|
44258
|
+
} catch {
|
|
44259
|
+
present = false;
|
|
44260
|
+
}
|
|
44261
|
+
if (!present || touched.includes(lockfile)) continue;
|
|
44262
|
+
warnings.push(
|
|
44263
|
+
` \u26A0 package.json changes dependencies, but ${lockfile} is not in this patch. The run will install without its frozen-lockfile check. Run \`${cmd}\` and commit ${lockfile} to keep it frozen.`
|
|
44264
|
+
);
|
|
44265
|
+
}
|
|
44266
|
+
return warnings;
|
|
44267
|
+
}
|
|
43793
44268
|
async function submitFounderPatch({ claims, claim, id, wt, flags }) {
|
|
43794
44269
|
let roots;
|
|
43795
44270
|
try {
|
|
@@ -43809,10 +44284,14 @@ async function submitFounderPatch({ claims, claim, id, wt, flags }) {
|
|
|
43809
44284
|
const base = roots[0];
|
|
43810
44285
|
let patch;
|
|
43811
44286
|
try {
|
|
43812
|
-
({ stdout: patch } = await pExecFile(
|
|
43813
|
-
|
|
43814
|
-
|
|
43815
|
-
|
|
44287
|
+
({ stdout: patch } = await pExecFile(
|
|
44288
|
+
"git",
|
|
44289
|
+
["-C", wt, "diff", "--binary", "--full-index", base, "HEAD"],
|
|
44290
|
+
{
|
|
44291
|
+
shell: false,
|
|
44292
|
+
maxBuffer: 16 * 1024 * 1024
|
|
44293
|
+
}
|
|
44294
|
+
));
|
|
43816
44295
|
patch = String(patch);
|
|
43817
44296
|
} catch (err) {
|
|
43818
44297
|
console.error(
|
|
@@ -43836,6 +44315,9 @@ async function submitFounderPatch({ claims, claim, id, wt, flags }) {
|
|
|
43836
44315
|
);
|
|
43837
44316
|
process.exit(1);
|
|
43838
44317
|
}
|
|
44318
|
+
const lockfileWarnings = await dependencyLockfileWarnings(wt, base, touched);
|
|
44319
|
+
if (lockfileWarnings.length > 0) console.log(`
|
|
44320
|
+
${lockfileWarnings.join("\n")}`);
|
|
43839
44321
|
const authorName = await sh("git", ["-C", wt, "log", "-1", "--format=%an"]);
|
|
43840
44322
|
const authorEmail = await sh("git", ["-C", wt, "log", "-1", "--format=%ae"]);
|
|
43841
44323
|
const shots = flags.screenshots === void 0 ? null : loadClaimScreenshots(flags.screenshots);
|