terminalhire 0.42.41 → 0.42.43
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-bounties.js +9 -0
- package/dist/bin/jpi-claim.js +135 -15
- package/dist/bin/jpi-dispatch.js +145 -16
- package/dist/bin/jpi-mcp.js +141 -16
- package/dist/bin/jpi-run.js +141 -16
- package/package.json +1 -1
package/dist/bin/jpi-bounties.js
CHANGED
|
@@ -12500,6 +12500,12 @@ function linkTitle(title, url) {
|
|
|
12500
12500
|
|
|
12501
12501
|
// bin/jpi-bounties.js
|
|
12502
12502
|
init_api_base();
|
|
12503
|
+
|
|
12504
|
+
// bin/review-mode-copy.js
|
|
12505
|
+
var POSTER_REVIEWED = "poster";
|
|
12506
|
+
var CLAIMANT_NOTICE = "The poster reviews this work by hand. We don't run tests on it.";
|
|
12507
|
+
|
|
12508
|
+
// bin/jpi-bounties.js
|
|
12503
12509
|
init_founder_pin();
|
|
12504
12510
|
var TERMINALHIRE_DIR7 = process.env.TERMINALHIRE_DIR || join13(homedir10(), ".terminalhire");
|
|
12505
12511
|
var INDEX_CACHE_FILE2 = join13(TERMINALHIRE_DIR7, "index-cache.json");
|
|
@@ -12614,6 +12620,9 @@ ${i + 1}. ${linkTitle(job.title, job.url)} [${ref}]`);
|
|
|
12614
12620
|
);
|
|
12615
12621
|
const marker = projectMarkerLine(b);
|
|
12616
12622
|
if (marker) console.log(` ${marker}`);
|
|
12623
|
+
if (b.bountySource === "founder" && b.reviewMode === POSTER_REVIEWED) {
|
|
12624
|
+
console.log(` ${CLAIMANT_NOTICE}`);
|
|
12625
|
+
}
|
|
12617
12626
|
if (reason) console.log(` ${reason}`);
|
|
12618
12627
|
if (continuityNote) console.log(` ${continuityNote}`);
|
|
12619
12628
|
if (b.publicSummary) {
|
package/dist/bin/jpi-claim.js
CHANGED
|
@@ -31049,7 +31049,8 @@ var init_result = __esm({
|
|
|
31049
31049
|
"leakState",
|
|
31050
31050
|
"venue",
|
|
31051
31051
|
"refusalOrigin",
|
|
31052
|
-
"stoppedAt"
|
|
31052
|
+
"stoppedAt",
|
|
31053
|
+
"installFrozen"
|
|
31053
31054
|
];
|
|
31054
31055
|
RENDER_NONE = null;
|
|
31055
31056
|
FIELD_VIEWS = {
|
|
@@ -31114,7 +31115,10 @@ var init_result = __esm({
|
|
|
31114
31115
|
// side refused in words a developer reads.
|
|
31115
31116
|
refusalOrigin: RENDER_NONE,
|
|
31116
31117
|
// Only when the run did not pass: on a green run "the last step" is just the last step.
|
|
31117
|
-
stoppedAt: (r) => r.stoppedAt === null || r.outcome === "completed" ? null : `last step ${r.stoppedAt} (the last package script named in the output)
|
|
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
|
|
31118
31122
|
};
|
|
31119
31123
|
}
|
|
31120
31124
|
});
|
|
@@ -35152,6 +35156,10 @@ function nodeInstallCommand(repo) {
|
|
|
35152
35156
|
return null;
|
|
35153
35157
|
}
|
|
35154
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) {
|
|
35155
35163
|
const pkg = readJsonObject(repo, "package.json");
|
|
35156
35164
|
if (pkg === null)
|
|
35157
35165
|
return null;
|
|
@@ -35178,7 +35186,7 @@ function lockfileGaps(repo) {
|
|
|
35178
35186
|
missing.push(`${n}@${r} (${dir})`);
|
|
35179
35187
|
}
|
|
35180
35188
|
}
|
|
35181
|
-
return
|
|
35189
|
+
return { lockfile, missing, rootRead: rootListing !== null };
|
|
35182
35190
|
}
|
|
35183
35191
|
function wantedDependencies(pkg) {
|
|
35184
35192
|
const wanted = [];
|
|
@@ -37679,7 +37687,9 @@ function refusedRun(fields) {
|
|
|
37679
37687
|
venue: null,
|
|
37680
37688
|
refusalOrigin: fields.origin,
|
|
37681
37689
|
// No test step ran, so there is no output to read a step from.
|
|
37682
|
-
stoppedAt: null
|
|
37690
|
+
stoppedAt: null,
|
|
37691
|
+
// Refused before any install step ran.
|
|
37692
|
+
installFrozen: null
|
|
37683
37693
|
};
|
|
37684
37694
|
}
|
|
37685
37695
|
function refusalOriginOf(refusal2) {
|
|
@@ -37763,7 +37773,29 @@ function installUnfrozenNote(spec) {
|
|
|
37763
37773
|
const u = spec.installUnfrozen;
|
|
37764
37774
|
if (u === void 0)
|
|
37765
37775
|
return null;
|
|
37766
|
-
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);
|
|
37767
37799
|
}
|
|
37768
37800
|
async function verifyWorkingDiff(req) {
|
|
37769
37801
|
const ctx = {
|
|
@@ -38132,7 +38164,8 @@ async function runVerification(req, ctx) {
|
|
|
38132
38164
|
// A run that reached a verdict was not refused, so neither side refused it.
|
|
38133
38165
|
refusalOrigin: null,
|
|
38134
38166
|
// Read from the full test output, not `outputTail`, which is an excerpt.
|
|
38135
|
-
stoppedAt: readStoppedAt(verdict.test?.stdout ?? "", verdict.test?.stderr ?? "")
|
|
38167
|
+
stoppedAt: readStoppedAt(verdict.test?.stdout ?? "", verdict.test?.stderr ?? ""),
|
|
38168
|
+
installFrozen: installFrozenFor(spec, verdict.install)
|
|
38136
38169
|
};
|
|
38137
38170
|
let later = null;
|
|
38138
38171
|
if (req.screenshots !== void 0) {
|
|
@@ -38331,7 +38364,7 @@ async function prepareBaseTree(o) {
|
|
|
38331
38364
|
throw err;
|
|
38332
38365
|
}
|
|
38333
38366
|
}
|
|
38334
|
-
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;
|
|
38335
38368
|
var init_thrun = __esm({
|
|
38336
38369
|
"../../packages/envrun/dist/thrun.js"() {
|
|
38337
38370
|
"use strict";
|
|
@@ -38420,6 +38453,7 @@ var init_thrun = __esm({
|
|
|
38420
38453
|
FAILURE_LINE = /^(?:[ \t]*(?:not ok |FAILED |FAIL )|E {3}|# fail [1-9])/m;
|
|
38421
38454
|
REDACTED_TARGET_REPO = "(refused before the target was accepted)";
|
|
38422
38455
|
REDACTED_TARGET_SHA = "(refused)";
|
|
38456
|
+
INSTALL_NEVER_STARTED = 125;
|
|
38423
38457
|
}
|
|
38424
38458
|
});
|
|
38425
38459
|
|
|
@@ -39321,6 +39355,7 @@ __export(dist_exports, {
|
|
|
39321
39355
|
imageRepo: () => imageRepo,
|
|
39322
39356
|
imageVariantFor: () => imageVariantFor,
|
|
39323
39357
|
installCommandFor: () => installCommandFor,
|
|
39358
|
+
installFrozenFor: () => installFrozenFor,
|
|
39324
39359
|
installLocalMigrationTooling: () => installLocalMigrationTooling,
|
|
39325
39360
|
installUnfrozenNote: () => installUnfrozenNote,
|
|
39326
39361
|
isBookkeepingTable: () => isBookkeepingTable,
|
|
@@ -40162,6 +40197,13 @@ async function syncFounderVerdicts({
|
|
|
40162
40197
|
|
|
40163
40198
|
// bin/jpi-claim.js
|
|
40164
40199
|
init_founder_note_sync();
|
|
40200
|
+
|
|
40201
|
+
// bin/review-mode-copy.js
|
|
40202
|
+
var POSTER_REVIEWED = "poster";
|
|
40203
|
+
var CLAIMANT_NOTICE = "The poster reviews this work by hand. We don't run tests on it.";
|
|
40204
|
+
var HISTORY_LINE = "Submitted for the poster's review.";
|
|
40205
|
+
|
|
40206
|
+
// bin/jpi-claim.js
|
|
40165
40207
|
var TERMINALHIRE_DIR11 = process.env.TERMINALHIRE_DIR || join31(homedir14(), ".terminalhire");
|
|
40166
40208
|
var INDEX_CACHE_FILE2 = join31(TERMINALHIRE_DIR11, "index-cache.json");
|
|
40167
40209
|
var CLAIM_PUSH_MARKER = join31(TERMINALHIRE_DIR11, "claim-push.json");
|
|
@@ -40631,9 +40673,15 @@ function extractClaimableFields(job) {
|
|
|
40631
40673
|
// poster saw. Null when the index carries none.
|
|
40632
40674
|
runRequirements: b.runRequirements && typeof b.runRequirements === "object" ? b.runRequirements : null,
|
|
40633
40675
|
// TERM-1308. Present only when the index row carries them; no key otherwise.
|
|
40634
|
-
...b.bountySource === "founder" ? baselineFields(b) : {}
|
|
40676
|
+
...b.bountySource === "founder" ? baselineFields(b) : {},
|
|
40677
|
+
// TERM-1344. The index carries `reviewMode` only for a poster-reviewed posting; any
|
|
40678
|
+
// other value is dropped rather than carried, the same as a malformed baseline field.
|
|
40679
|
+
...b.bountySource === "founder" && b.reviewMode === POSTER_REVIEWED ? { reviewMode: POSTER_REVIEWED } : {}
|
|
40635
40680
|
};
|
|
40636
40681
|
}
|
|
40682
|
+
function reviewModeLine(b) {
|
|
40683
|
+
return b?.reviewMode === POSTER_REVIEWED ? CLAIMANT_NOTICE : null;
|
|
40684
|
+
}
|
|
40637
40685
|
function parseGitHubUrl(url) {
|
|
40638
40686
|
const m = String(url ?? "").match(/github\.com\/([^/]+)\/([^/]+)\/(?:issues|pull)\/(\d+)/);
|
|
40639
40687
|
if (!m) return null;
|
|
@@ -41250,7 +41298,7 @@ async function resolveBounty(arg) {
|
|
|
41250
41298
|
if (freshPool) job = findByShortRefInPool(freshPool, arg);
|
|
41251
41299
|
}
|
|
41252
41300
|
if (job) {
|
|
41253
|
-
let testBudgetMinutes, baselineStatus, baselineSha;
|
|
41301
|
+
let testBudgetMinutes, baselineStatus, baselineSha, reviewMode;
|
|
41254
41302
|
({
|
|
41255
41303
|
bountyId,
|
|
41256
41304
|
title,
|
|
@@ -41264,12 +41312,15 @@ async function resolveBounty(arg) {
|
|
|
41264
41312
|
runRequirements,
|
|
41265
41313
|
testBudgetMinutes,
|
|
41266
41314
|
baselineStatus,
|
|
41267
|
-
baselineSha
|
|
41315
|
+
baselineSha,
|
|
41316
|
+
reviewMode
|
|
41268
41317
|
} = extractClaimableFields(job));
|
|
41269
41318
|
baseline = {
|
|
41270
41319
|
...testBudgetMinutes === void 0 ? {} : { testBudgetMinutes },
|
|
41271
41320
|
...baselineStatus === void 0 ? {} : { baselineStatus },
|
|
41272
|
-
...baselineSha === void 0 ? {} : { baselineSha }
|
|
41321
|
+
...baselineSha === void 0 ? {} : { baselineSha },
|
|
41322
|
+
// TERM-1344. Rides with the baseline fields: index-only, and no key when absent.
|
|
41323
|
+
...reviewMode === void 0 ? {} : { reviewMode }
|
|
41273
41324
|
};
|
|
41274
41325
|
indexNativeId = bountyId;
|
|
41275
41326
|
} else {
|
|
@@ -42054,6 +42105,8 @@ async function cmdPreview(arg, { json } = {}) {
|
|
|
42054
42105
|
contested: isContested(b),
|
|
42055
42106
|
// TERM-1308. The posting's test budget and baseline, only when the index carried them.
|
|
42056
42107
|
...baselineFields(b),
|
|
42108
|
+
// TERM-1344. Only for a poster-reviewed posting; absent means tests.
|
|
42109
|
+
...b.reviewMode === POSTER_REVIEWED ? { reviewMode: POSTER_REVIEWED } : {},
|
|
42057
42110
|
// Absent on a founder posting — see the scan above. A consumer must read
|
|
42058
42111
|
// "no policy key" as "no policy step exists here", never as "clean".
|
|
42059
42112
|
...policy ? {
|
|
@@ -42084,8 +42137,8 @@ async function cmdPreview(arg, { json } = {}) {
|
|
|
42084
42137
|
console.log(fmtOpenPRsLine(b));
|
|
42085
42138
|
const previewContested = fmtContestedWarning(b);
|
|
42086
42139
|
if (previewContested) console.log(previewContested);
|
|
42087
|
-
const
|
|
42088
|
-
if (
|
|
42140
|
+
const previewTests = reviewModeLine(b) ?? baselineLine(b);
|
|
42141
|
+
if (previewTests) console.log(` tests: ${previewTests}`);
|
|
42089
42142
|
if (policy) printPolicySection(policy);
|
|
42090
42143
|
if (process.stdout.isTTY) {
|
|
42091
42144
|
try {
|
|
@@ -43358,7 +43411,8 @@ function renderRunView(run2, message2, extra = {}) {
|
|
|
43358
43411
|
const rateLimitCap = extra.rateLimitCap ?? run2.rateLimitCap ?? 5;
|
|
43359
43412
|
const rateLimitCount = extra.rateLimitCount ?? run2.rateLimitCount;
|
|
43360
43413
|
if (claimState) {
|
|
43361
|
-
|
|
43414
|
+
const stateText = claimState === "poster-review" ? HISTORY_LINE : terminalSafeInline(claimState);
|
|
43415
|
+
lines.push(` state: ${stateText}`);
|
|
43362
43416
|
}
|
|
43363
43417
|
if (unverifiedCause) {
|
|
43364
43418
|
lines.push(` cause: ${terminalSafeInline(unverifiedCause)}`);
|
|
@@ -43417,7 +43471,8 @@ function renderClaimHistory(attempts, timeline) {
|
|
|
43417
43471
|
for (const a of runs) {
|
|
43418
43472
|
const sha = a.commitSha ? String(a.commitSha).slice(0, 10) : "";
|
|
43419
43473
|
const jobs = Array.isArray(a.failingJobs) && a.failingJobs.length > 0 ? ` \u2014 ${a.failingJobs.map(terminalSafeInline).join(", ")}` : "";
|
|
43420
|
-
const
|
|
43474
|
+
const note = typeof a.note === "string" ? terminalSafeInline(a.note).trim() : "";
|
|
43475
|
+
const outcome = a.conclusion ? `checks ${terminalSafeInline(a.conclusion)}${jobs}` : note !== "" ? note : a.status === "no-ci" ? "no checks ran" : "checks running";
|
|
43421
43476
|
lines.push(` attempt ${a.attemptNumber} ${sha} ${outcome} ${shortWhen(a.at)}`);
|
|
43422
43477
|
}
|
|
43423
43478
|
for (const e of told) {
|
|
@@ -44169,6 +44224,67 @@ async function uploadClaimScreenshots(intake, uploads) {
|
|
|
44169
44224
|
);
|
|
44170
44225
|
}
|
|
44171
44226
|
}
|
|
44227
|
+
var DEPENDENCY_SECTIONS2 = [
|
|
44228
|
+
"dependencies",
|
|
44229
|
+
"devDependencies",
|
|
44230
|
+
"optionalDependencies",
|
|
44231
|
+
"peerDependencies"
|
|
44232
|
+
];
|
|
44233
|
+
var SENDABLE_LOCKFILES = [
|
|
44234
|
+
["package-lock.json", "npm install"],
|
|
44235
|
+
["yarn.lock", "yarn install"]
|
|
44236
|
+
];
|
|
44237
|
+
async function packageJsonAt(wt, rev, path5) {
|
|
44238
|
+
let text;
|
|
44239
|
+
try {
|
|
44240
|
+
({ stdout: text } = await pExecFile("git", ["-C", wt, "show", `${rev}:${path5}`], {
|
|
44241
|
+
shell: false,
|
|
44242
|
+
maxBuffer: 16 * 1024 * 1024
|
|
44243
|
+
}));
|
|
44244
|
+
} catch {
|
|
44245
|
+
return {};
|
|
44246
|
+
}
|
|
44247
|
+
try {
|
|
44248
|
+
const parsed = JSON.parse(String(text));
|
|
44249
|
+
return parsed !== null && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
|
|
44250
|
+
} catch {
|
|
44251
|
+
return null;
|
|
44252
|
+
}
|
|
44253
|
+
}
|
|
44254
|
+
function sectionKey(pkg, section) {
|
|
44255
|
+
const value = pkg[section];
|
|
44256
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
44257
|
+
return JSON.stringify(value ?? null);
|
|
44258
|
+
}
|
|
44259
|
+
return JSON.stringify(Object.keys(value).sort().map((k) => [k, value[k]]));
|
|
44260
|
+
}
|
|
44261
|
+
async function patchChangesDependencies(wt, base, touched) {
|
|
44262
|
+
for (const path5 of touched) {
|
|
44263
|
+
if (path5.split("/").pop() !== "package.json") continue;
|
|
44264
|
+
const before = await packageJsonAt(wt, base, path5);
|
|
44265
|
+
const after = await packageJsonAt(wt, "HEAD", path5);
|
|
44266
|
+
if (before === null || after === null) continue;
|
|
44267
|
+
if (DEPENDENCY_SECTIONS2.some((s) => sectionKey(before, s) !== sectionKey(after, s))) return true;
|
|
44268
|
+
}
|
|
44269
|
+
return false;
|
|
44270
|
+
}
|
|
44271
|
+
async function dependencyLockfileWarnings(wt, base, touched) {
|
|
44272
|
+
if (!await patchChangesDependencies(wt, base, touched)) return [];
|
|
44273
|
+
const warnings = [];
|
|
44274
|
+
for (const [lockfile, cmd] of SENDABLE_LOCKFILES) {
|
|
44275
|
+
let present;
|
|
44276
|
+
try {
|
|
44277
|
+
present = (await sh("git", ["-C", wt, "ls-tree", "--name-only", base, "--", lockfile])).trim() === lockfile;
|
|
44278
|
+
} catch {
|
|
44279
|
+
present = false;
|
|
44280
|
+
}
|
|
44281
|
+
if (!present || touched.includes(lockfile)) continue;
|
|
44282
|
+
warnings.push(
|
|
44283
|
+
` \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.`
|
|
44284
|
+
);
|
|
44285
|
+
}
|
|
44286
|
+
return warnings;
|
|
44287
|
+
}
|
|
44172
44288
|
async function submitFounderPatch({ claims, claim, id, wt, flags }) {
|
|
44173
44289
|
let roots;
|
|
44174
44290
|
try {
|
|
@@ -44219,6 +44335,9 @@ async function submitFounderPatch({ claims, claim, id, wt, flags }) {
|
|
|
44219
44335
|
);
|
|
44220
44336
|
process.exit(1);
|
|
44221
44337
|
}
|
|
44338
|
+
const lockfileWarnings = await dependencyLockfileWarnings(wt, base, touched);
|
|
44339
|
+
if (lockfileWarnings.length > 0) console.log(`
|
|
44340
|
+
${lockfileWarnings.join("\n")}`);
|
|
44222
44341
|
const authorName = await sh("git", ["-C", wt, "log", "-1", "--format=%an"]);
|
|
44223
44342
|
const authorEmail = await sh("git", ["-C", wt, "log", "-1", "--format=%ae"]);
|
|
44224
44343
|
const shots = flags.screenshots === void 0 ? null : loadClaimScreenshots(flags.screenshots);
|
|
@@ -45845,6 +45964,7 @@ export {
|
|
|
45845
45964
|
resolveBounty,
|
|
45846
45965
|
resolveDeliveryDir,
|
|
45847
45966
|
resolveSubmitWorktree,
|
|
45967
|
+
reviewModeLine,
|
|
45848
45968
|
reviseRecoveryCommand,
|
|
45849
45969
|
revokeFailureAction,
|
|
45850
45970
|
run,
|
package/dist/bin/jpi-dispatch.js
CHANGED
|
@@ -15565,6 +15565,17 @@ var init_payout_split = __esm({
|
|
|
15565
15565
|
}
|
|
15566
15566
|
});
|
|
15567
15567
|
|
|
15568
|
+
// bin/review-mode-copy.js
|
|
15569
|
+
var POSTER_REVIEWED, CLAIMANT_NOTICE, HISTORY_LINE;
|
|
15570
|
+
var init_review_mode_copy = __esm({
|
|
15571
|
+
"bin/review-mode-copy.js"() {
|
|
15572
|
+
"use strict";
|
|
15573
|
+
POSTER_REVIEWED = "poster";
|
|
15574
|
+
CLAIMANT_NOTICE = "The poster reviews this work by hand. We don't run tests on it.";
|
|
15575
|
+
HISTORY_LINE = "Submitted for the poster's review.";
|
|
15576
|
+
}
|
|
15577
|
+
});
|
|
15578
|
+
|
|
15568
15579
|
// src/repo-experience.ts
|
|
15569
15580
|
var repo_experience_exports = {};
|
|
15570
15581
|
__export(repo_experience_exports, {
|
|
@@ -16451,6 +16462,9 @@ ${i + 1}. ${linkTitle(job.title, job.url)} [${ref}]`);
|
|
|
16451
16462
|
);
|
|
16452
16463
|
const marker = projectMarkerLine(b);
|
|
16453
16464
|
if (marker) console.log(` ${marker}`);
|
|
16465
|
+
if (b.bountySource === "founder" && b.reviewMode === POSTER_REVIEWED) {
|
|
16466
|
+
console.log(` ${CLAIMANT_NOTICE}`);
|
|
16467
|
+
}
|
|
16454
16468
|
if (reason) console.log(` ${reason}`);
|
|
16455
16469
|
if (continuityNote) console.log(` ${continuityNote}`);
|
|
16456
16470
|
if (b.publicSummary) {
|
|
@@ -16706,6 +16720,7 @@ var init_jpi_bounties = __esm({
|
|
|
16706
16720
|
init_index_revalidate();
|
|
16707
16721
|
init_sanitize();
|
|
16708
16722
|
init_api_base();
|
|
16723
|
+
init_review_mode_copy();
|
|
16709
16724
|
init_founder_pin();
|
|
16710
16725
|
TERMINALHIRE_DIR12 = process.env.TERMINALHIRE_DIR || join26(homedir20(), ".terminalhire");
|
|
16711
16726
|
INDEX_CACHE_FILE3 = join26(TERMINALHIRE_DIR12, "index-cache.json");
|
|
@@ -36824,7 +36839,8 @@ var init_result = __esm({
|
|
|
36824
36839
|
"leakState",
|
|
36825
36840
|
"venue",
|
|
36826
36841
|
"refusalOrigin",
|
|
36827
|
-
"stoppedAt"
|
|
36842
|
+
"stoppedAt",
|
|
36843
|
+
"installFrozen"
|
|
36828
36844
|
];
|
|
36829
36845
|
RENDER_NONE = null;
|
|
36830
36846
|
FIELD_VIEWS = {
|
|
@@ -36889,7 +36905,10 @@ var init_result = __esm({
|
|
|
36889
36905
|
// side refused in words a developer reads.
|
|
36890
36906
|
refusalOrigin: RENDER_NONE,
|
|
36891
36907
|
// Only when the run did not pass: on a green run "the last step" is just the last step.
|
|
36892
|
-
stoppedAt: (r) => r.stoppedAt === null || r.outcome === "completed" ? null : `last step ${r.stoppedAt} (the last package script named in the output)
|
|
36908
|
+
stoppedAt: (r) => r.stoppedAt === null || r.outcome === "completed" ? null : `last step ${r.stoppedAt} (the last package script named in the output)`,
|
|
36909
|
+
// The run already prints the unfrozen note while it runs (`installUnfrozenNote`); this is
|
|
36910
|
+
// the record of it for the worker and the intake.
|
|
36911
|
+
installFrozen: RENDER_NONE
|
|
36893
36912
|
};
|
|
36894
36913
|
}
|
|
36895
36914
|
});
|
|
@@ -40927,6 +40946,10 @@ function nodeInstallCommand(repo) {
|
|
|
40927
40946
|
return null;
|
|
40928
40947
|
}
|
|
40929
40948
|
function lockfileGaps(repo) {
|
|
40949
|
+
const read = readLockfileGaps(repo);
|
|
40950
|
+
return read === null || read.missing.length === 0 ? null : { lockfile: read.lockfile, missing: read.missing };
|
|
40951
|
+
}
|
|
40952
|
+
function readLockfileGaps(repo) {
|
|
40930
40953
|
const pkg = readJsonObject(repo, "package.json");
|
|
40931
40954
|
if (pkg === null)
|
|
40932
40955
|
return null;
|
|
@@ -40953,7 +40976,7 @@ function lockfileGaps(repo) {
|
|
|
40953
40976
|
missing.push(`${n}@${r} (${dir})`);
|
|
40954
40977
|
}
|
|
40955
40978
|
}
|
|
40956
|
-
return
|
|
40979
|
+
return { lockfile, missing, rootRead: rootListing !== null };
|
|
40957
40980
|
}
|
|
40958
40981
|
function wantedDependencies(pkg) {
|
|
40959
40982
|
const wanted = [];
|
|
@@ -43454,7 +43477,9 @@ function refusedRun(fields) {
|
|
|
43454
43477
|
venue: null,
|
|
43455
43478
|
refusalOrigin: fields.origin,
|
|
43456
43479
|
// No test step ran, so there is no output to read a step from.
|
|
43457
|
-
stoppedAt: null
|
|
43480
|
+
stoppedAt: null,
|
|
43481
|
+
// Refused before any install step ran.
|
|
43482
|
+
installFrozen: null
|
|
43458
43483
|
};
|
|
43459
43484
|
}
|
|
43460
43485
|
function refusalOriginOf(refusal2) {
|
|
@@ -43538,7 +43563,29 @@ function installUnfrozenNote(spec) {
|
|
|
43538
43563
|
const u = spec.installUnfrozen;
|
|
43539
43564
|
if (u === void 0)
|
|
43540
43565
|
return null;
|
|
43541
|
-
return `${u.lockfile} does not list ${u.missing.join(", ")}, so the install ran as \`${String(spec.installCommand)}\` without its frozen-lockfile check.
|
|
43566
|
+
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.`;
|
|
43567
|
+
}
|
|
43568
|
+
function isFrozenInstallCommand(command) {
|
|
43569
|
+
const lead = /^(?:(?:sudo|time)\s+|env(?:\s+[A-Za-z_]\w*=\S*)*\s+)*/.exec(command)?.[0] ?? "";
|
|
43570
|
+
const install = command.slice(lead.length).split(/;|&&|\|\|/)[0]?.trim() ?? "";
|
|
43571
|
+
if (/^npm ci(\s|$)/.test(install))
|
|
43572
|
+
return true;
|
|
43573
|
+
if (/^(yarn|pnpm|bun)\b/.test(install) && /\s--frozen-lockfile(?=\s|$)/.test(install)) {
|
|
43574
|
+
return true;
|
|
43575
|
+
}
|
|
43576
|
+
return /^yarn\b/.test(install) && /\s--immutable(?=\s|$)/.test(install);
|
|
43577
|
+
}
|
|
43578
|
+
function installFrozenFor(spec, install) {
|
|
43579
|
+
if (install === null)
|
|
43580
|
+
return null;
|
|
43581
|
+
const launched = install.exitCode !== INSTALL_NEVER_STARTED && (install.exitCode !== null || install.timedOut);
|
|
43582
|
+
if (!launched)
|
|
43583
|
+
return null;
|
|
43584
|
+
if (spec.runtime !== "node")
|
|
43585
|
+
return null;
|
|
43586
|
+
if (spec.installUnfrozen !== void 0)
|
|
43587
|
+
return false;
|
|
43588
|
+
return isFrozenInstallCommand(install.command);
|
|
43542
43589
|
}
|
|
43543
43590
|
async function verifyWorkingDiff(req) {
|
|
43544
43591
|
const ctx = {
|
|
@@ -43907,7 +43954,8 @@ async function runVerification(req, ctx) {
|
|
|
43907
43954
|
// A run that reached a verdict was not refused, so neither side refused it.
|
|
43908
43955
|
refusalOrigin: null,
|
|
43909
43956
|
// Read from the full test output, not `outputTail`, which is an excerpt.
|
|
43910
|
-
stoppedAt: readStoppedAt(verdict.test?.stdout ?? "", verdict.test?.stderr ?? "")
|
|
43957
|
+
stoppedAt: readStoppedAt(verdict.test?.stdout ?? "", verdict.test?.stderr ?? ""),
|
|
43958
|
+
installFrozen: installFrozenFor(spec, verdict.install)
|
|
43911
43959
|
};
|
|
43912
43960
|
let later = null;
|
|
43913
43961
|
if (req.screenshots !== void 0) {
|
|
@@ -44106,7 +44154,7 @@ async function prepareBaseTree(o) {
|
|
|
44106
44154
|
throw err;
|
|
44107
44155
|
}
|
|
44108
44156
|
}
|
|
44109
|
-
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;
|
|
44157
|
+
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;
|
|
44110
44158
|
var init_thrun = __esm({
|
|
44111
44159
|
"../../packages/envrun/dist/thrun.js"() {
|
|
44112
44160
|
"use strict";
|
|
@@ -44195,6 +44243,7 @@ var init_thrun = __esm({
|
|
|
44195
44243
|
FAILURE_LINE = /^(?:[ \t]*(?:not ok |FAILED |FAIL )|E {3}|# fail [1-9])/m;
|
|
44196
44244
|
REDACTED_TARGET_REPO = "(refused before the target was accepted)";
|
|
44197
44245
|
REDACTED_TARGET_SHA = "(refused)";
|
|
44246
|
+
INSTALL_NEVER_STARTED = 125;
|
|
44198
44247
|
}
|
|
44199
44248
|
});
|
|
44200
44249
|
|
|
@@ -45096,6 +45145,7 @@ __export(dist_exports, {
|
|
|
45096
45145
|
imageRepo: () => imageRepo,
|
|
45097
45146
|
imageVariantFor: () => imageVariantFor,
|
|
45098
45147
|
installCommandFor: () => installCommandFor,
|
|
45148
|
+
installFrozenFor: () => installFrozenFor,
|
|
45099
45149
|
installLocalMigrationTooling: () => installLocalMigrationTooling,
|
|
45100
45150
|
installUnfrozenNote: () => installUnfrozenNote,
|
|
45101
45151
|
isBookkeepingTable: () => isBookkeepingTable,
|
|
@@ -45492,6 +45542,7 @@ __export(jpi_claim_exports, {
|
|
|
45492
45542
|
resolveBounty: () => resolveBounty,
|
|
45493
45543
|
resolveDeliveryDir: () => resolveDeliveryDir,
|
|
45494
45544
|
resolveSubmitWorktree: () => resolveSubmitWorktree,
|
|
45545
|
+
reviewModeLine: () => reviewModeLine,
|
|
45495
45546
|
reviseRecoveryCommand: () => reviseRecoveryCommand,
|
|
45496
45547
|
revokeFailureAction: () => revokeFailureAction,
|
|
45497
45548
|
run: () => run7,
|
|
@@ -45959,9 +46010,15 @@ function extractClaimableFields(job) {
|
|
|
45959
46010
|
// poster saw. Null when the index carries none.
|
|
45960
46011
|
runRequirements: b.runRequirements && typeof b.runRequirements === "object" ? b.runRequirements : null,
|
|
45961
46012
|
// TERM-1308. Present only when the index row carries them; no key otherwise.
|
|
45962
|
-
...b.bountySource === "founder" ? baselineFields(b) : {}
|
|
46013
|
+
...b.bountySource === "founder" ? baselineFields(b) : {},
|
|
46014
|
+
// TERM-1344. The index carries `reviewMode` only for a poster-reviewed posting; any
|
|
46015
|
+
// other value is dropped rather than carried, the same as a malformed baseline field.
|
|
46016
|
+
...b.bountySource === "founder" && b.reviewMode === POSTER_REVIEWED ? { reviewMode: POSTER_REVIEWED } : {}
|
|
45963
46017
|
};
|
|
45964
46018
|
}
|
|
46019
|
+
function reviewModeLine(b) {
|
|
46020
|
+
return b?.reviewMode === POSTER_REVIEWED ? CLAIMANT_NOTICE : null;
|
|
46021
|
+
}
|
|
45965
46022
|
function parseGitHubUrl(url) {
|
|
45966
46023
|
const m = String(url ?? "").match(/github\.com\/([^/]+)\/([^/]+)\/(?:issues|pull)\/(\d+)/);
|
|
45967
46024
|
if (!m) return null;
|
|
@@ -46567,7 +46624,7 @@ async function resolveBounty(arg) {
|
|
|
46567
46624
|
if (freshPool) job = findByShortRefInPool(freshPool, arg);
|
|
46568
46625
|
}
|
|
46569
46626
|
if (job) {
|
|
46570
|
-
let testBudgetMinutes, baselineStatus, baselineSha;
|
|
46627
|
+
let testBudgetMinutes, baselineStatus, baselineSha, reviewMode;
|
|
46571
46628
|
({
|
|
46572
46629
|
bountyId,
|
|
46573
46630
|
title,
|
|
@@ -46581,12 +46638,15 @@ async function resolveBounty(arg) {
|
|
|
46581
46638
|
runRequirements,
|
|
46582
46639
|
testBudgetMinutes,
|
|
46583
46640
|
baselineStatus,
|
|
46584
|
-
baselineSha
|
|
46641
|
+
baselineSha,
|
|
46642
|
+
reviewMode
|
|
46585
46643
|
} = extractClaimableFields(job));
|
|
46586
46644
|
baseline = {
|
|
46587
46645
|
...testBudgetMinutes === void 0 ? {} : { testBudgetMinutes },
|
|
46588
46646
|
...baselineStatus === void 0 ? {} : { baselineStatus },
|
|
46589
|
-
...baselineSha === void 0 ? {} : { baselineSha }
|
|
46647
|
+
...baselineSha === void 0 ? {} : { baselineSha },
|
|
46648
|
+
// TERM-1344. Rides with the baseline fields: index-only, and no key when absent.
|
|
46649
|
+
...reviewMode === void 0 ? {} : { reviewMode }
|
|
46590
46650
|
};
|
|
46591
46651
|
indexNativeId = bountyId;
|
|
46592
46652
|
} else {
|
|
@@ -47346,6 +47406,8 @@ async function cmdPreview(arg, { json } = {}) {
|
|
|
47346
47406
|
contested: isContested(b),
|
|
47347
47407
|
// TERM-1308. The posting's test budget and baseline, only when the index carried them.
|
|
47348
47408
|
...baselineFields(b),
|
|
47409
|
+
// TERM-1344. Only for a poster-reviewed posting; absent means tests.
|
|
47410
|
+
...b.reviewMode === POSTER_REVIEWED ? { reviewMode: POSTER_REVIEWED } : {},
|
|
47349
47411
|
// Absent on a founder posting — see the scan above. A consumer must read
|
|
47350
47412
|
// "no policy key" as "no policy step exists here", never as "clean".
|
|
47351
47413
|
...policy ? {
|
|
@@ -47376,8 +47438,8 @@ async function cmdPreview(arg, { json } = {}) {
|
|
|
47376
47438
|
console.log(fmtOpenPRsLine(b));
|
|
47377
47439
|
const previewContested = fmtContestedWarning(b);
|
|
47378
47440
|
if (previewContested) console.log(previewContested);
|
|
47379
|
-
const
|
|
47380
|
-
if (
|
|
47441
|
+
const previewTests = reviewModeLine(b) ?? baselineLine(b);
|
|
47442
|
+
if (previewTests) console.log(` tests: ${previewTests}`);
|
|
47381
47443
|
if (policy) printPolicySection(policy);
|
|
47382
47444
|
if (process.stdout.isTTY) {
|
|
47383
47445
|
try {
|
|
@@ -48633,7 +48695,8 @@ function renderRunView(run32, message2, extra = {}) {
|
|
|
48633
48695
|
const rateLimitCap = extra.rateLimitCap ?? run32.rateLimitCap ?? 5;
|
|
48634
48696
|
const rateLimitCount = extra.rateLimitCount ?? run32.rateLimitCount;
|
|
48635
48697
|
if (claimState) {
|
|
48636
|
-
|
|
48698
|
+
const stateText = claimState === "poster-review" ? HISTORY_LINE : terminalSafeInline(claimState);
|
|
48699
|
+
lines.push(` state: ${stateText}`);
|
|
48637
48700
|
}
|
|
48638
48701
|
if (unverifiedCause) {
|
|
48639
48702
|
lines.push(` cause: ${terminalSafeInline(unverifiedCause)}`);
|
|
@@ -48679,7 +48742,8 @@ function renderClaimHistory(attempts, timeline) {
|
|
|
48679
48742
|
for (const a of runs) {
|
|
48680
48743
|
const sha = a.commitSha ? String(a.commitSha).slice(0, 10) : "";
|
|
48681
48744
|
const jobs = Array.isArray(a.failingJobs) && a.failingJobs.length > 0 ? ` \u2014 ${a.failingJobs.map(terminalSafeInline).join(", ")}` : "";
|
|
48682
|
-
const
|
|
48745
|
+
const note = typeof a.note === "string" ? terminalSafeInline(a.note).trim() : "";
|
|
48746
|
+
const outcome = a.conclusion ? `checks ${terminalSafeInline(a.conclusion)}${jobs}` : note !== "" ? note : a.status === "no-ci" ? "no checks ran" : "checks running";
|
|
48683
48747
|
lines.push(` attempt ${a.attemptNumber} ${sha} ${outcome} ${shortWhen(a.at)}`);
|
|
48684
48748
|
}
|
|
48685
48749
|
for (const e of told) {
|
|
@@ -49429,6 +49493,57 @@ async function uploadClaimScreenshots(intake, uploads) {
|
|
|
49429
49493
|
);
|
|
49430
49494
|
}
|
|
49431
49495
|
}
|
|
49496
|
+
async function packageJsonAt(wt, rev, path6) {
|
|
49497
|
+
let text;
|
|
49498
|
+
try {
|
|
49499
|
+
({ stdout: text } = await pExecFile("git", ["-C", wt, "show", `${rev}:${path6}`], {
|
|
49500
|
+
shell: false,
|
|
49501
|
+
maxBuffer: 16 * 1024 * 1024
|
|
49502
|
+
}));
|
|
49503
|
+
} catch {
|
|
49504
|
+
return {};
|
|
49505
|
+
}
|
|
49506
|
+
try {
|
|
49507
|
+
const parsed = JSON.parse(String(text));
|
|
49508
|
+
return parsed !== null && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
|
|
49509
|
+
} catch {
|
|
49510
|
+
return null;
|
|
49511
|
+
}
|
|
49512
|
+
}
|
|
49513
|
+
function sectionKey(pkg, section2) {
|
|
49514
|
+
const value = pkg[section2];
|
|
49515
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
49516
|
+
return JSON.stringify(value ?? null);
|
|
49517
|
+
}
|
|
49518
|
+
return JSON.stringify(Object.keys(value).sort().map((k) => [k, value[k]]));
|
|
49519
|
+
}
|
|
49520
|
+
async function patchChangesDependencies(wt, base, touched) {
|
|
49521
|
+
for (const path6 of touched) {
|
|
49522
|
+
if (path6.split("/").pop() !== "package.json") continue;
|
|
49523
|
+
const before = await packageJsonAt(wt, base, path6);
|
|
49524
|
+
const after = await packageJsonAt(wt, "HEAD", path6);
|
|
49525
|
+
if (before === null || after === null) continue;
|
|
49526
|
+
if (DEPENDENCY_SECTIONS2.some((s) => sectionKey(before, s) !== sectionKey(after, s))) return true;
|
|
49527
|
+
}
|
|
49528
|
+
return false;
|
|
49529
|
+
}
|
|
49530
|
+
async function dependencyLockfileWarnings(wt, base, touched) {
|
|
49531
|
+
if (!await patchChangesDependencies(wt, base, touched)) return [];
|
|
49532
|
+
const warnings = [];
|
|
49533
|
+
for (const [lockfile, cmd] of SENDABLE_LOCKFILES) {
|
|
49534
|
+
let present;
|
|
49535
|
+
try {
|
|
49536
|
+
present = (await sh("git", ["-C", wt, "ls-tree", "--name-only", base, "--", lockfile])).trim() === lockfile;
|
|
49537
|
+
} catch {
|
|
49538
|
+
present = false;
|
|
49539
|
+
}
|
|
49540
|
+
if (!present || touched.includes(lockfile)) continue;
|
|
49541
|
+
warnings.push(
|
|
49542
|
+
` \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.`
|
|
49543
|
+
);
|
|
49544
|
+
}
|
|
49545
|
+
return warnings;
|
|
49546
|
+
}
|
|
49432
49547
|
async function submitFounderPatch({ claims, claim, id, wt, flags }) {
|
|
49433
49548
|
let roots;
|
|
49434
49549
|
try {
|
|
@@ -49479,6 +49594,9 @@ async function submitFounderPatch({ claims, claim, id, wt, flags }) {
|
|
|
49479
49594
|
);
|
|
49480
49595
|
process.exit(1);
|
|
49481
49596
|
}
|
|
49597
|
+
const lockfileWarnings = await dependencyLockfileWarnings(wt, base, touched);
|
|
49598
|
+
if (lockfileWarnings.length > 0) console.log(`
|
|
49599
|
+
${lockfileWarnings.join("\n")}`);
|
|
49482
49600
|
const authorName = await sh("git", ["-C", wt, "log", "-1", "--format=%an"]);
|
|
49483
49601
|
const authorEmail = await sh("git", ["-C", wt, "log", "-1", "--format=%ae"]);
|
|
49484
49602
|
const shots = flags.screenshots === void 0 ? null : loadClaimScreenshots(flags.screenshots);
|
|
@@ -50988,7 +51106,7 @@ async function run7() {
|
|
|
50988
51106
|
process.exit(1);
|
|
50989
51107
|
}
|
|
50990
51108
|
}
|
|
50991
|
-
var TERMINALHIRE_DIR17, INDEX_CACHE_FILE5, CLAIM_PUSH_MARKER, REPO_CONTINUITY_NUDGE_MARKER, API_URL6, CLAIM_SYNC_BASE4, CLAIM_CONSENT_VERSION, CLAIM_POLL_INTERVAL_MS, CLAIM_POLL_TIMEOUT_MS, CLAIM_SYNC_WRITE_TIMEOUT_MS, GH_API3, GH_HEADERS2, CONTENTION_HINT, AI_DISCLOSURE_NOTE, pExecFile, VALUE_FLAGS, BASELINE_STATUSES, MIN_TEST_BUDGET_MINUTES, MAX_TEST_BUDGET_MINUTES, ASSIGNMENT_MARKER, STAKE_MARKER, STANDDOWN_MARKER, OUR_MARKERS, STAKE_POST_TIMEOUT_MS, STAKE_POSTING_GRACE_MS, TAKE_BOT_REPOS, SUBMIT_ACCEPTS, REVISE_RECOVERY_STATES, CLOSED_STATES, GH_SESSION_COOKIE4, PUSH_TOKEN_REFUSAL, SYNC_BACKGROUND_PUSH_ACTIVE_FIELD, ISSUE_OUTCOME_TERMINAL, RUNS_POLL_INTERVAL_MS, RUNS_POLL_ATTEMPTS, OPENABLE_AGENTS, BRIEF_DIR, BRIEF_REL_PATH, VERIFY_REL_PATH, AGENTS_REL_PATH, BRIEF_EXCLUDE_LINE, PACK_SAFE_ID, CLAIM_EVENT_LABEL, LINE_BREAKS, CONTROL_CHARS3, FOUNDER_POSTING_ID, CLAIM_SCREENSHOT_PUT_TIMEOUT_MS, CLAIM_RESOLUTION_REASONS, SETUP_FAILED_REQUIREMENTS, POSTING_LEVEL_RESOLUTION_REASONS, RESOLUTION_REASON_BLURB;
|
|
51109
|
+
var TERMINALHIRE_DIR17, INDEX_CACHE_FILE5, CLAIM_PUSH_MARKER, REPO_CONTINUITY_NUDGE_MARKER, API_URL6, CLAIM_SYNC_BASE4, CLAIM_CONSENT_VERSION, CLAIM_POLL_INTERVAL_MS, CLAIM_POLL_TIMEOUT_MS, CLAIM_SYNC_WRITE_TIMEOUT_MS, GH_API3, GH_HEADERS2, CONTENTION_HINT, AI_DISCLOSURE_NOTE, pExecFile, VALUE_FLAGS, BASELINE_STATUSES, MIN_TEST_BUDGET_MINUTES, MAX_TEST_BUDGET_MINUTES, ASSIGNMENT_MARKER, STAKE_MARKER, STANDDOWN_MARKER, OUR_MARKERS, STAKE_POST_TIMEOUT_MS, STAKE_POSTING_GRACE_MS, TAKE_BOT_REPOS, SUBMIT_ACCEPTS, REVISE_RECOVERY_STATES, CLOSED_STATES, GH_SESSION_COOKIE4, PUSH_TOKEN_REFUSAL, SYNC_BACKGROUND_PUSH_ACTIVE_FIELD, ISSUE_OUTCOME_TERMINAL, RUNS_POLL_INTERVAL_MS, RUNS_POLL_ATTEMPTS, OPENABLE_AGENTS, BRIEF_DIR, BRIEF_REL_PATH, VERIFY_REL_PATH, AGENTS_REL_PATH, BRIEF_EXCLUDE_LINE, PACK_SAFE_ID, CLAIM_EVENT_LABEL, LINE_BREAKS, CONTROL_CHARS3, FOUNDER_POSTING_ID, CLAIM_SCREENSHOT_PUT_TIMEOUT_MS, DEPENDENCY_SECTIONS2, SENDABLE_LOCKFILES, CLAIM_RESOLUTION_REASONS, SETUP_FAILED_REQUIREMENTS, POSTING_LEVEL_RESOLUTION_REASONS, RESOLUTION_REASON_BLURB;
|
|
50992
51110
|
var init_jpi_claim = __esm({
|
|
50993
51111
|
"bin/jpi-claim.js"() {
|
|
50994
51112
|
"use strict";
|
|
@@ -51004,6 +51122,7 @@ var init_jpi_claim = __esm({
|
|
|
51004
51122
|
init_claim_push_bg();
|
|
51005
51123
|
init_founder_verdict_sync();
|
|
51006
51124
|
init_founder_note_sync();
|
|
51125
|
+
init_review_mode_copy();
|
|
51007
51126
|
TERMINALHIRE_DIR17 = process.env.TERMINALHIRE_DIR || join46(homedir26(), ".terminalhire");
|
|
51008
51127
|
INDEX_CACHE_FILE5 = join46(TERMINALHIRE_DIR17, "index-cache.json");
|
|
51009
51128
|
CLAIM_PUSH_MARKER = join46(TERMINALHIRE_DIR17, "claim-push.json");
|
|
@@ -51121,6 +51240,16 @@ var init_jpi_claim = __esm({
|
|
|
51121
51240
|
CONTROL_CHARS3 = /[\u0000-\u001F\u007F-\u009F]/g;
|
|
51122
51241
|
FOUNDER_POSTING_ID = /^fb_[A-Za-z0-9_-]{1,80}$/;
|
|
51123
51242
|
CLAIM_SCREENSHOT_PUT_TIMEOUT_MS = 2e4;
|
|
51243
|
+
DEPENDENCY_SECTIONS2 = [
|
|
51244
|
+
"dependencies",
|
|
51245
|
+
"devDependencies",
|
|
51246
|
+
"optionalDependencies",
|
|
51247
|
+
"peerDependencies"
|
|
51248
|
+
];
|
|
51249
|
+
SENDABLE_LOCKFILES = [
|
|
51250
|
+
["package-lock.json", "npm install"],
|
|
51251
|
+
["yarn.lock", "yarn install"]
|
|
51252
|
+
];
|
|
51124
51253
|
CLAIM_RESOLUTION_REASONS = [
|
|
51125
51254
|
"not-my-stack",
|
|
51126
51255
|
"out-of-time",
|
package/dist/bin/jpi-mcp.js
CHANGED
|
@@ -12169,6 +12169,17 @@ var init_founder_note_sync = __esm({
|
|
|
12169
12169
|
}
|
|
12170
12170
|
});
|
|
12171
12171
|
|
|
12172
|
+
// bin/review-mode-copy.js
|
|
12173
|
+
var POSTER_REVIEWED, CLAIMANT_NOTICE, HISTORY_LINE;
|
|
12174
|
+
var init_review_mode_copy = __esm({
|
|
12175
|
+
"bin/review-mode-copy.js"() {
|
|
12176
|
+
"use strict";
|
|
12177
|
+
POSTER_REVIEWED = "poster";
|
|
12178
|
+
CLAIMANT_NOTICE = "The poster reviews this work by hand. We don't run tests on it.";
|
|
12179
|
+
HISTORY_LINE = "Submitted for the poster's review.";
|
|
12180
|
+
}
|
|
12181
|
+
});
|
|
12182
|
+
|
|
12172
12183
|
// ../../packages/core/src/policy-audit.ts
|
|
12173
12184
|
function fence(nonce, body) {
|
|
12174
12185
|
return `<<<UNTRUSTED-${nonce}
|
|
@@ -31590,7 +31601,8 @@ var init_result = __esm({
|
|
|
31590
31601
|
"leakState",
|
|
31591
31602
|
"venue",
|
|
31592
31603
|
"refusalOrigin",
|
|
31593
|
-
"stoppedAt"
|
|
31604
|
+
"stoppedAt",
|
|
31605
|
+
"installFrozen"
|
|
31594
31606
|
];
|
|
31595
31607
|
RENDER_NONE = null;
|
|
31596
31608
|
FIELD_VIEWS = {
|
|
@@ -31655,7 +31667,10 @@ var init_result = __esm({
|
|
|
31655
31667
|
// side refused in words a developer reads.
|
|
31656
31668
|
refusalOrigin: RENDER_NONE,
|
|
31657
31669
|
// Only when the run did not pass: on a green run "the last step" is just the last step.
|
|
31658
|
-
stoppedAt: (r) => r.stoppedAt === null || r.outcome === "completed" ? null : `last step ${r.stoppedAt} (the last package script named in the output)
|
|
31670
|
+
stoppedAt: (r) => r.stoppedAt === null || r.outcome === "completed" ? null : `last step ${r.stoppedAt} (the last package script named in the output)`,
|
|
31671
|
+
// The run already prints the unfrozen note while it runs (`installUnfrozenNote`); this is
|
|
31672
|
+
// the record of it for the worker and the intake.
|
|
31673
|
+
installFrozen: RENDER_NONE
|
|
31659
31674
|
};
|
|
31660
31675
|
}
|
|
31661
31676
|
});
|
|
@@ -35693,6 +35708,10 @@ function nodeInstallCommand(repo) {
|
|
|
35693
35708
|
return null;
|
|
35694
35709
|
}
|
|
35695
35710
|
function lockfileGaps(repo) {
|
|
35711
|
+
const read = readLockfileGaps(repo);
|
|
35712
|
+
return read === null || read.missing.length === 0 ? null : { lockfile: read.lockfile, missing: read.missing };
|
|
35713
|
+
}
|
|
35714
|
+
function readLockfileGaps(repo) {
|
|
35696
35715
|
const pkg = readJsonObject(repo, "package.json");
|
|
35697
35716
|
if (pkg === null)
|
|
35698
35717
|
return null;
|
|
@@ -35719,7 +35738,7 @@ function lockfileGaps(repo) {
|
|
|
35719
35738
|
missing.push(`${n}@${r} (${dir})`);
|
|
35720
35739
|
}
|
|
35721
35740
|
}
|
|
35722
|
-
return
|
|
35741
|
+
return { lockfile, missing, rootRead: rootListing !== null };
|
|
35723
35742
|
}
|
|
35724
35743
|
function wantedDependencies(pkg) {
|
|
35725
35744
|
const wanted = [];
|
|
@@ -38220,7 +38239,9 @@ function refusedRun(fields) {
|
|
|
38220
38239
|
venue: null,
|
|
38221
38240
|
refusalOrigin: fields.origin,
|
|
38222
38241
|
// No test step ran, so there is no output to read a step from.
|
|
38223
|
-
stoppedAt: null
|
|
38242
|
+
stoppedAt: null,
|
|
38243
|
+
// Refused before any install step ran.
|
|
38244
|
+
installFrozen: null
|
|
38224
38245
|
};
|
|
38225
38246
|
}
|
|
38226
38247
|
function refusalOriginOf(refusal2) {
|
|
@@ -38304,7 +38325,29 @@ function installUnfrozenNote(spec) {
|
|
|
38304
38325
|
const u = spec.installUnfrozen;
|
|
38305
38326
|
if (u === void 0)
|
|
38306
38327
|
return null;
|
|
38307
|
-
return `${u.lockfile} does not list ${u.missing.join(", ")}, so the install ran as \`${String(spec.installCommand)}\` without its frozen-lockfile check.
|
|
38328
|
+
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.`;
|
|
38329
|
+
}
|
|
38330
|
+
function isFrozenInstallCommand(command) {
|
|
38331
|
+
const lead = /^(?:(?:sudo|time)\s+|env(?:\s+[A-Za-z_]\w*=\S*)*\s+)*/.exec(command)?.[0] ?? "";
|
|
38332
|
+
const install = command.slice(lead.length).split(/;|&&|\|\|/)[0]?.trim() ?? "";
|
|
38333
|
+
if (/^npm ci(\s|$)/.test(install))
|
|
38334
|
+
return true;
|
|
38335
|
+
if (/^(yarn|pnpm|bun)\b/.test(install) && /\s--frozen-lockfile(?=\s|$)/.test(install)) {
|
|
38336
|
+
return true;
|
|
38337
|
+
}
|
|
38338
|
+
return /^yarn\b/.test(install) && /\s--immutable(?=\s|$)/.test(install);
|
|
38339
|
+
}
|
|
38340
|
+
function installFrozenFor(spec, install) {
|
|
38341
|
+
if (install === null)
|
|
38342
|
+
return null;
|
|
38343
|
+
const launched = install.exitCode !== INSTALL_NEVER_STARTED && (install.exitCode !== null || install.timedOut);
|
|
38344
|
+
if (!launched)
|
|
38345
|
+
return null;
|
|
38346
|
+
if (spec.runtime !== "node")
|
|
38347
|
+
return null;
|
|
38348
|
+
if (spec.installUnfrozen !== void 0)
|
|
38349
|
+
return false;
|
|
38350
|
+
return isFrozenInstallCommand(install.command);
|
|
38308
38351
|
}
|
|
38309
38352
|
async function verifyWorkingDiff(req) {
|
|
38310
38353
|
const ctx = {
|
|
@@ -38673,7 +38716,8 @@ async function runVerification(req, ctx) {
|
|
|
38673
38716
|
// A run that reached a verdict was not refused, so neither side refused it.
|
|
38674
38717
|
refusalOrigin: null,
|
|
38675
38718
|
// Read from the full test output, not `outputTail`, which is an excerpt.
|
|
38676
|
-
stoppedAt: readStoppedAt(verdict.test?.stdout ?? "", verdict.test?.stderr ?? "")
|
|
38719
|
+
stoppedAt: readStoppedAt(verdict.test?.stdout ?? "", verdict.test?.stderr ?? ""),
|
|
38720
|
+
installFrozen: installFrozenFor(spec, verdict.install)
|
|
38677
38721
|
};
|
|
38678
38722
|
let later = null;
|
|
38679
38723
|
if (req.screenshots !== void 0) {
|
|
@@ -38872,7 +38916,7 @@ async function prepareBaseTree(o) {
|
|
|
38872
38916
|
throw err;
|
|
38873
38917
|
}
|
|
38874
38918
|
}
|
|
38875
|
-
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;
|
|
38919
|
+
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;
|
|
38876
38920
|
var init_thrun = __esm({
|
|
38877
38921
|
"../../packages/envrun/dist/thrun.js"() {
|
|
38878
38922
|
"use strict";
|
|
@@ -38961,6 +39005,7 @@ var init_thrun = __esm({
|
|
|
38961
39005
|
FAILURE_LINE = /^(?:[ \t]*(?:not ok |FAILED |FAIL )|E {3}|# fail [1-9])/m;
|
|
38962
39006
|
REDACTED_TARGET_REPO = "(refused before the target was accepted)";
|
|
38963
39007
|
REDACTED_TARGET_SHA = "(refused)";
|
|
39008
|
+
INSTALL_NEVER_STARTED = 125;
|
|
38964
39009
|
}
|
|
38965
39010
|
});
|
|
38966
39011
|
|
|
@@ -39862,6 +39907,7 @@ __export(dist_exports, {
|
|
|
39862
39907
|
imageRepo: () => imageRepo,
|
|
39863
39908
|
imageVariantFor: () => imageVariantFor,
|
|
39864
39909
|
installCommandFor: () => installCommandFor,
|
|
39910
|
+
installFrozenFor: () => installFrozenFor,
|
|
39865
39911
|
installLocalMigrationTooling: () => installLocalMigrationTooling,
|
|
39866
39912
|
installUnfrozenNote: () => installUnfrozenNote,
|
|
39867
39913
|
isBookkeepingTable: () => isBookkeepingTable,
|
|
@@ -40258,6 +40304,7 @@ __export(jpi_claim_exports, {
|
|
|
40258
40304
|
resolveBounty: () => resolveBounty,
|
|
40259
40305
|
resolveDeliveryDir: () => resolveDeliveryDir,
|
|
40260
40306
|
resolveSubmitWorktree: () => resolveSubmitWorktree,
|
|
40307
|
+
reviewModeLine: () => reviewModeLine,
|
|
40261
40308
|
reviseRecoveryCommand: () => reviseRecoveryCommand,
|
|
40262
40309
|
revokeFailureAction: () => revokeFailureAction,
|
|
40263
40310
|
run: () => run,
|
|
@@ -40725,9 +40772,15 @@ function extractClaimableFields(job) {
|
|
|
40725
40772
|
// poster saw. Null when the index carries none.
|
|
40726
40773
|
runRequirements: b.runRequirements && typeof b.runRequirements === "object" ? b.runRequirements : null,
|
|
40727
40774
|
// TERM-1308. Present only when the index row carries them; no key otherwise.
|
|
40728
|
-
...b.bountySource === "founder" ? baselineFields(b) : {}
|
|
40775
|
+
...b.bountySource === "founder" ? baselineFields(b) : {},
|
|
40776
|
+
// TERM-1344. The index carries `reviewMode` only for a poster-reviewed posting; any
|
|
40777
|
+
// other value is dropped rather than carried, the same as a malformed baseline field.
|
|
40778
|
+
...b.bountySource === "founder" && b.reviewMode === POSTER_REVIEWED ? { reviewMode: POSTER_REVIEWED } : {}
|
|
40729
40779
|
};
|
|
40730
40780
|
}
|
|
40781
|
+
function reviewModeLine(b) {
|
|
40782
|
+
return b?.reviewMode === POSTER_REVIEWED ? CLAIMANT_NOTICE : null;
|
|
40783
|
+
}
|
|
40731
40784
|
function parseGitHubUrl(url) {
|
|
40732
40785
|
const m = String(url ?? "").match(/github\.com\/([^/]+)\/([^/]+)\/(?:issues|pull)\/(\d+)/);
|
|
40733
40786
|
if (!m) return null;
|
|
@@ -41333,7 +41386,7 @@ async function resolveBounty(arg) {
|
|
|
41333
41386
|
if (freshPool) job = findByShortRefInPool(freshPool, arg);
|
|
41334
41387
|
}
|
|
41335
41388
|
if (job) {
|
|
41336
|
-
let testBudgetMinutes, baselineStatus, baselineSha;
|
|
41389
|
+
let testBudgetMinutes, baselineStatus, baselineSha, reviewMode;
|
|
41337
41390
|
({
|
|
41338
41391
|
bountyId,
|
|
41339
41392
|
title,
|
|
@@ -41347,12 +41400,15 @@ async function resolveBounty(arg) {
|
|
|
41347
41400
|
runRequirements,
|
|
41348
41401
|
testBudgetMinutes,
|
|
41349
41402
|
baselineStatus,
|
|
41350
|
-
baselineSha
|
|
41403
|
+
baselineSha,
|
|
41404
|
+
reviewMode
|
|
41351
41405
|
} = extractClaimableFields(job));
|
|
41352
41406
|
baseline = {
|
|
41353
41407
|
...testBudgetMinutes === void 0 ? {} : { testBudgetMinutes },
|
|
41354
41408
|
...baselineStatus === void 0 ? {} : { baselineStatus },
|
|
41355
|
-
...baselineSha === void 0 ? {} : { baselineSha }
|
|
41409
|
+
...baselineSha === void 0 ? {} : { baselineSha },
|
|
41410
|
+
// TERM-1344. Rides with the baseline fields: index-only, and no key when absent.
|
|
41411
|
+
...reviewMode === void 0 ? {} : { reviewMode }
|
|
41356
41412
|
};
|
|
41357
41413
|
indexNativeId = bountyId;
|
|
41358
41414
|
} else {
|
|
@@ -42112,6 +42168,8 @@ async function cmdPreview(arg, { json } = {}) {
|
|
|
42112
42168
|
contested: isContested(b),
|
|
42113
42169
|
// TERM-1308. The posting's test budget and baseline, only when the index carried them.
|
|
42114
42170
|
...baselineFields(b),
|
|
42171
|
+
// TERM-1344. Only for a poster-reviewed posting; absent means tests.
|
|
42172
|
+
...b.reviewMode === POSTER_REVIEWED ? { reviewMode: POSTER_REVIEWED } : {},
|
|
42115
42173
|
// Absent on a founder posting — see the scan above. A consumer must read
|
|
42116
42174
|
// "no policy key" as "no policy step exists here", never as "clean".
|
|
42117
42175
|
...policy ? {
|
|
@@ -42142,8 +42200,8 @@ async function cmdPreview(arg, { json } = {}) {
|
|
|
42142
42200
|
console.log(fmtOpenPRsLine(b));
|
|
42143
42201
|
const previewContested = fmtContestedWarning(b);
|
|
42144
42202
|
if (previewContested) console.log(previewContested);
|
|
42145
|
-
const
|
|
42146
|
-
if (
|
|
42203
|
+
const previewTests = reviewModeLine(b) ?? baselineLine(b);
|
|
42204
|
+
if (previewTests) console.log(` tests: ${previewTests}`);
|
|
42147
42205
|
if (policy) printPolicySection(policy);
|
|
42148
42206
|
if (process.stdout.isTTY) {
|
|
42149
42207
|
try {
|
|
@@ -43399,7 +43457,8 @@ function renderRunView(run3, message2, extra = {}) {
|
|
|
43399
43457
|
const rateLimitCap = extra.rateLimitCap ?? run3.rateLimitCap ?? 5;
|
|
43400
43458
|
const rateLimitCount = extra.rateLimitCount ?? run3.rateLimitCount;
|
|
43401
43459
|
if (claimState) {
|
|
43402
|
-
|
|
43460
|
+
const stateText = claimState === "poster-review" ? HISTORY_LINE : terminalSafeInline(claimState);
|
|
43461
|
+
lines.push(` state: ${stateText}`);
|
|
43403
43462
|
}
|
|
43404
43463
|
if (unverifiedCause) {
|
|
43405
43464
|
lines.push(` cause: ${terminalSafeInline(unverifiedCause)}`);
|
|
@@ -43445,7 +43504,8 @@ function renderClaimHistory(attempts, timeline) {
|
|
|
43445
43504
|
for (const a of runs) {
|
|
43446
43505
|
const sha = a.commitSha ? String(a.commitSha).slice(0, 10) : "";
|
|
43447
43506
|
const jobs = Array.isArray(a.failingJobs) && a.failingJobs.length > 0 ? ` \u2014 ${a.failingJobs.map(terminalSafeInline).join(", ")}` : "";
|
|
43448
|
-
const
|
|
43507
|
+
const note = typeof a.note === "string" ? terminalSafeInline(a.note).trim() : "";
|
|
43508
|
+
const outcome = a.conclusion ? `checks ${terminalSafeInline(a.conclusion)}${jobs}` : note !== "" ? note : a.status === "no-ci" ? "no checks ran" : "checks running";
|
|
43449
43509
|
lines.push(` attempt ${a.attemptNumber} ${sha} ${outcome} ${shortWhen(a.at)}`);
|
|
43450
43510
|
}
|
|
43451
43511
|
for (const e of told) {
|
|
@@ -44195,6 +44255,57 @@ async function uploadClaimScreenshots(intake, uploads) {
|
|
|
44195
44255
|
);
|
|
44196
44256
|
}
|
|
44197
44257
|
}
|
|
44258
|
+
async function packageJsonAt(wt, rev, path5) {
|
|
44259
|
+
let text;
|
|
44260
|
+
try {
|
|
44261
|
+
({ stdout: text } = await pExecFile("git", ["-C", wt, "show", `${rev}:${path5}`], {
|
|
44262
|
+
shell: false,
|
|
44263
|
+
maxBuffer: 16 * 1024 * 1024
|
|
44264
|
+
}));
|
|
44265
|
+
} catch {
|
|
44266
|
+
return {};
|
|
44267
|
+
}
|
|
44268
|
+
try {
|
|
44269
|
+
const parsed = JSON.parse(String(text));
|
|
44270
|
+
return parsed !== null && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
|
|
44271
|
+
} catch {
|
|
44272
|
+
return null;
|
|
44273
|
+
}
|
|
44274
|
+
}
|
|
44275
|
+
function sectionKey(pkg, section) {
|
|
44276
|
+
const value = pkg[section];
|
|
44277
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
44278
|
+
return JSON.stringify(value ?? null);
|
|
44279
|
+
}
|
|
44280
|
+
return JSON.stringify(Object.keys(value).sort().map((k) => [k, value[k]]));
|
|
44281
|
+
}
|
|
44282
|
+
async function patchChangesDependencies(wt, base, touched) {
|
|
44283
|
+
for (const path5 of touched) {
|
|
44284
|
+
if (path5.split("/").pop() !== "package.json") continue;
|
|
44285
|
+
const before = await packageJsonAt(wt, base, path5);
|
|
44286
|
+
const after = await packageJsonAt(wt, "HEAD", path5);
|
|
44287
|
+
if (before === null || after === null) continue;
|
|
44288
|
+
if (DEPENDENCY_SECTIONS2.some((s) => sectionKey(before, s) !== sectionKey(after, s))) return true;
|
|
44289
|
+
}
|
|
44290
|
+
return false;
|
|
44291
|
+
}
|
|
44292
|
+
async function dependencyLockfileWarnings(wt, base, touched) {
|
|
44293
|
+
if (!await patchChangesDependencies(wt, base, touched)) return [];
|
|
44294
|
+
const warnings = [];
|
|
44295
|
+
for (const [lockfile, cmd] of SENDABLE_LOCKFILES) {
|
|
44296
|
+
let present;
|
|
44297
|
+
try {
|
|
44298
|
+
present = (await sh("git", ["-C", wt, "ls-tree", "--name-only", base, "--", lockfile])).trim() === lockfile;
|
|
44299
|
+
} catch {
|
|
44300
|
+
present = false;
|
|
44301
|
+
}
|
|
44302
|
+
if (!present || touched.includes(lockfile)) continue;
|
|
44303
|
+
warnings.push(
|
|
44304
|
+
` \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.`
|
|
44305
|
+
);
|
|
44306
|
+
}
|
|
44307
|
+
return warnings;
|
|
44308
|
+
}
|
|
44198
44309
|
async function submitFounderPatch({ claims, claim, id, wt, flags }) {
|
|
44199
44310
|
let roots;
|
|
44200
44311
|
try {
|
|
@@ -44245,6 +44356,9 @@ async function submitFounderPatch({ claims, claim, id, wt, flags }) {
|
|
|
44245
44356
|
);
|
|
44246
44357
|
process.exit(1);
|
|
44247
44358
|
}
|
|
44359
|
+
const lockfileWarnings = await dependencyLockfileWarnings(wt, base, touched);
|
|
44360
|
+
if (lockfileWarnings.length > 0) console.log(`
|
|
44361
|
+
${lockfileWarnings.join("\n")}`);
|
|
44248
44362
|
const authorName = await sh("git", ["-C", wt, "log", "-1", "--format=%an"]);
|
|
44249
44363
|
const authorEmail = await sh("git", ["-C", wt, "log", "-1", "--format=%ae"]);
|
|
44250
44364
|
const shots = flags.screenshots === void 0 ? null : loadClaimScreenshots(flags.screenshots);
|
|
@@ -45754,7 +45868,7 @@ async function run() {
|
|
|
45754
45868
|
process.exit(1);
|
|
45755
45869
|
}
|
|
45756
45870
|
}
|
|
45757
|
-
var TERMINALHIRE_DIR11, INDEX_CACHE_FILE2, CLAIM_PUSH_MARKER, REPO_CONTINUITY_NUDGE_MARKER, API_URL, CLAIM_SYNC_BASE4, CLAIM_CONSENT_VERSION, CLAIM_POLL_INTERVAL_MS, CLAIM_POLL_TIMEOUT_MS, CLAIM_SYNC_WRITE_TIMEOUT_MS, GH_API2, GH_HEADERS2, CONTENTION_HINT, AI_DISCLOSURE_NOTE, pExecFile, VALUE_FLAGS, BASELINE_STATUSES, MIN_TEST_BUDGET_MINUTES, MAX_TEST_BUDGET_MINUTES, ASSIGNMENT_MARKER, STAKE_MARKER, STANDDOWN_MARKER, OUR_MARKERS, STAKE_POST_TIMEOUT_MS, STAKE_POSTING_GRACE_MS, TAKE_BOT_REPOS, SUBMIT_ACCEPTS, REVISE_RECOVERY_STATES, CLOSED_STATES, GH_SESSION_COOKIE, PUSH_TOKEN_REFUSAL, SYNC_BACKGROUND_PUSH_ACTIVE_FIELD, ISSUE_OUTCOME_TERMINAL, RUNS_POLL_INTERVAL_MS, RUNS_POLL_ATTEMPTS, OPENABLE_AGENTS, BRIEF_DIR, BRIEF_REL_PATH, VERIFY_REL_PATH, AGENTS_REL_PATH, BRIEF_EXCLUDE_LINE, PACK_SAFE_ID, CLAIM_EVENT_LABEL, LINE_BREAKS, CONTROL_CHARS3, FOUNDER_POSTING_ID, CLAIM_SCREENSHOT_PUT_TIMEOUT_MS, CLAIM_RESOLUTION_REASONS, SETUP_FAILED_REQUIREMENTS, POSTING_LEVEL_RESOLUTION_REASONS, RESOLUTION_REASON_BLURB;
|
|
45871
|
+
var TERMINALHIRE_DIR11, INDEX_CACHE_FILE2, CLAIM_PUSH_MARKER, REPO_CONTINUITY_NUDGE_MARKER, API_URL, CLAIM_SYNC_BASE4, CLAIM_CONSENT_VERSION, CLAIM_POLL_INTERVAL_MS, CLAIM_POLL_TIMEOUT_MS, CLAIM_SYNC_WRITE_TIMEOUT_MS, GH_API2, GH_HEADERS2, CONTENTION_HINT, AI_DISCLOSURE_NOTE, pExecFile, VALUE_FLAGS, BASELINE_STATUSES, MIN_TEST_BUDGET_MINUTES, MAX_TEST_BUDGET_MINUTES, ASSIGNMENT_MARKER, STAKE_MARKER, STANDDOWN_MARKER, OUR_MARKERS, STAKE_POST_TIMEOUT_MS, STAKE_POSTING_GRACE_MS, TAKE_BOT_REPOS, SUBMIT_ACCEPTS, REVISE_RECOVERY_STATES, CLOSED_STATES, GH_SESSION_COOKIE, PUSH_TOKEN_REFUSAL, SYNC_BACKGROUND_PUSH_ACTIVE_FIELD, ISSUE_OUTCOME_TERMINAL, RUNS_POLL_INTERVAL_MS, RUNS_POLL_ATTEMPTS, OPENABLE_AGENTS, BRIEF_DIR, BRIEF_REL_PATH, VERIFY_REL_PATH, AGENTS_REL_PATH, BRIEF_EXCLUDE_LINE, PACK_SAFE_ID, CLAIM_EVENT_LABEL, LINE_BREAKS, CONTROL_CHARS3, FOUNDER_POSTING_ID, CLAIM_SCREENSHOT_PUT_TIMEOUT_MS, DEPENDENCY_SECTIONS2, SENDABLE_LOCKFILES, CLAIM_RESOLUTION_REASONS, SETUP_FAILED_REQUIREMENTS, POSTING_LEVEL_RESOLUTION_REASONS, RESOLUTION_REASON_BLURB;
|
|
45758
45872
|
var init_jpi_claim = __esm({
|
|
45759
45873
|
"bin/jpi-claim.js"() {
|
|
45760
45874
|
"use strict";
|
|
@@ -45770,6 +45884,7 @@ var init_jpi_claim = __esm({
|
|
|
45770
45884
|
init_claim_push_bg();
|
|
45771
45885
|
init_founder_verdict_sync();
|
|
45772
45886
|
init_founder_note_sync();
|
|
45887
|
+
init_review_mode_copy();
|
|
45773
45888
|
TERMINALHIRE_DIR11 = process.env.TERMINALHIRE_DIR || join32(homedir15(), ".terminalhire");
|
|
45774
45889
|
INDEX_CACHE_FILE2 = join32(TERMINALHIRE_DIR11, "index-cache.json");
|
|
45775
45890
|
CLAIM_PUSH_MARKER = join32(TERMINALHIRE_DIR11, "claim-push.json");
|
|
@@ -45887,6 +46002,16 @@ var init_jpi_claim = __esm({
|
|
|
45887
46002
|
CONTROL_CHARS3 = /[\u0000-\u001F\u007F-\u009F]/g;
|
|
45888
46003
|
FOUNDER_POSTING_ID = /^fb_[A-Za-z0-9_-]{1,80}$/;
|
|
45889
46004
|
CLAIM_SCREENSHOT_PUT_TIMEOUT_MS = 2e4;
|
|
46005
|
+
DEPENDENCY_SECTIONS2 = [
|
|
46006
|
+
"dependencies",
|
|
46007
|
+
"devDependencies",
|
|
46008
|
+
"optionalDependencies",
|
|
46009
|
+
"peerDependencies"
|
|
46010
|
+
];
|
|
46011
|
+
SENDABLE_LOCKFILES = [
|
|
46012
|
+
["package-lock.json", "npm install"],
|
|
46013
|
+
["yarn.lock", "yarn install"]
|
|
46014
|
+
];
|
|
45890
46015
|
CLAIM_RESOLUTION_REASONS = [
|
|
45891
46016
|
"not-my-stack",
|
|
45892
46017
|
"out-of-time",
|
package/dist/bin/jpi-run.js
CHANGED
|
@@ -5424,7 +5424,8 @@ var init_result = __esm({
|
|
|
5424
5424
|
"leakState",
|
|
5425
5425
|
"venue",
|
|
5426
5426
|
"refusalOrigin",
|
|
5427
|
-
"stoppedAt"
|
|
5427
|
+
"stoppedAt",
|
|
5428
|
+
"installFrozen"
|
|
5428
5429
|
];
|
|
5429
5430
|
RENDER_NONE = null;
|
|
5430
5431
|
FIELD_VIEWS = {
|
|
@@ -5489,7 +5490,10 @@ var init_result = __esm({
|
|
|
5489
5490
|
// side refused in words a developer reads.
|
|
5490
5491
|
refusalOrigin: RENDER_NONE,
|
|
5491
5492
|
// Only when the run did not pass: on a green run "the last step" is just the last step.
|
|
5492
|
-
stoppedAt: (r) => r.stoppedAt === null || r.outcome === "completed" ? null : `last step ${r.stoppedAt} (the last package script named in the output)
|
|
5493
|
+
stoppedAt: (r) => r.stoppedAt === null || r.outcome === "completed" ? null : `last step ${r.stoppedAt} (the last package script named in the output)`,
|
|
5494
|
+
// The run already prints the unfrozen note while it runs (`installUnfrozenNote`); this is
|
|
5495
|
+
// the record of it for the worker and the intake.
|
|
5496
|
+
installFrozen: RENDER_NONE
|
|
5493
5497
|
};
|
|
5494
5498
|
}
|
|
5495
5499
|
});
|
|
@@ -9527,6 +9531,10 @@ function nodeInstallCommand(repo) {
|
|
|
9527
9531
|
return null;
|
|
9528
9532
|
}
|
|
9529
9533
|
function lockfileGaps(repo) {
|
|
9534
|
+
const read = readLockfileGaps(repo);
|
|
9535
|
+
return read === null || read.missing.length === 0 ? null : { lockfile: read.lockfile, missing: read.missing };
|
|
9536
|
+
}
|
|
9537
|
+
function readLockfileGaps(repo) {
|
|
9530
9538
|
const pkg = readJsonObject(repo, "package.json");
|
|
9531
9539
|
if (pkg === null)
|
|
9532
9540
|
return null;
|
|
@@ -9553,7 +9561,7 @@ function lockfileGaps(repo) {
|
|
|
9553
9561
|
missing.push(`${n}@${r} (${dir})`);
|
|
9554
9562
|
}
|
|
9555
9563
|
}
|
|
9556
|
-
return
|
|
9564
|
+
return { lockfile, missing, rootRead: rootListing !== null };
|
|
9557
9565
|
}
|
|
9558
9566
|
function wantedDependencies(pkg) {
|
|
9559
9567
|
const wanted = [];
|
|
@@ -12229,7 +12237,9 @@ function refusedRun(fields) {
|
|
|
12229
12237
|
venue: null,
|
|
12230
12238
|
refusalOrigin: fields.origin,
|
|
12231
12239
|
// No test step ran, so there is no output to read a step from.
|
|
12232
|
-
stoppedAt: null
|
|
12240
|
+
stoppedAt: null,
|
|
12241
|
+
// Refused before any install step ran.
|
|
12242
|
+
installFrozen: null
|
|
12233
12243
|
};
|
|
12234
12244
|
}
|
|
12235
12245
|
function refusalOriginOf(refusal2) {
|
|
@@ -12313,7 +12323,29 @@ function installUnfrozenNote(spec) {
|
|
|
12313
12323
|
const u = spec.installUnfrozen;
|
|
12314
12324
|
if (u === void 0)
|
|
12315
12325
|
return null;
|
|
12316
|
-
return `${u.lockfile} does not list ${u.missing.join(", ")}, so the install ran as \`${String(spec.installCommand)}\` without its frozen-lockfile check.
|
|
12326
|
+
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.`;
|
|
12327
|
+
}
|
|
12328
|
+
function isFrozenInstallCommand(command) {
|
|
12329
|
+
const lead = /^(?:(?:sudo|time)\s+|env(?:\s+[A-Za-z_]\w*=\S*)*\s+)*/.exec(command)?.[0] ?? "";
|
|
12330
|
+
const install = command.slice(lead.length).split(/;|&&|\|\|/)[0]?.trim() ?? "";
|
|
12331
|
+
if (/^npm ci(\s|$)/.test(install))
|
|
12332
|
+
return true;
|
|
12333
|
+
if (/^(yarn|pnpm|bun)\b/.test(install) && /\s--frozen-lockfile(?=\s|$)/.test(install)) {
|
|
12334
|
+
return true;
|
|
12335
|
+
}
|
|
12336
|
+
return /^yarn\b/.test(install) && /\s--immutable(?=\s|$)/.test(install);
|
|
12337
|
+
}
|
|
12338
|
+
function installFrozenFor(spec, install) {
|
|
12339
|
+
if (install === null)
|
|
12340
|
+
return null;
|
|
12341
|
+
const launched = install.exitCode !== INSTALL_NEVER_STARTED && (install.exitCode !== null || install.timedOut);
|
|
12342
|
+
if (!launched)
|
|
12343
|
+
return null;
|
|
12344
|
+
if (spec.runtime !== "node")
|
|
12345
|
+
return null;
|
|
12346
|
+
if (spec.installUnfrozen !== void 0)
|
|
12347
|
+
return false;
|
|
12348
|
+
return isFrozenInstallCommand(install.command);
|
|
12317
12349
|
}
|
|
12318
12350
|
async function verifyWorkingDiff(req) {
|
|
12319
12351
|
const ctx = {
|
|
@@ -12682,7 +12714,8 @@ async function runVerification(req, ctx) {
|
|
|
12682
12714
|
// A run that reached a verdict was not refused, so neither side refused it.
|
|
12683
12715
|
refusalOrigin: null,
|
|
12684
12716
|
// Read from the full test output, not `outputTail`, which is an excerpt.
|
|
12685
|
-
stoppedAt: readStoppedAt(verdict.test?.stdout ?? "", verdict.test?.stderr ?? "")
|
|
12717
|
+
stoppedAt: readStoppedAt(verdict.test?.stdout ?? "", verdict.test?.stderr ?? ""),
|
|
12718
|
+
installFrozen: installFrozenFor(spec, verdict.install)
|
|
12686
12719
|
};
|
|
12687
12720
|
let later = null;
|
|
12688
12721
|
if (req.screenshots !== void 0) {
|
|
@@ -12881,7 +12914,7 @@ async function prepareBaseTree(o) {
|
|
|
12881
12914
|
throw err;
|
|
12882
12915
|
}
|
|
12883
12916
|
}
|
|
12884
|
-
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;
|
|
12917
|
+
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;
|
|
12885
12918
|
var init_thrun = __esm({
|
|
12886
12919
|
"../../packages/envrun/dist/thrun.js"() {
|
|
12887
12920
|
"use strict";
|
|
@@ -12970,6 +13003,7 @@ var init_thrun = __esm({
|
|
|
12970
13003
|
FAILURE_LINE = /^(?:[ \t]*(?:not ok |FAILED |FAIL )|E {3}|# fail [1-9])/m;
|
|
12971
13004
|
REDACTED_TARGET_REPO = "(refused before the target was accepted)";
|
|
12972
13005
|
REDACTED_TARGET_SHA = "(refused)";
|
|
13006
|
+
INSTALL_NEVER_STARTED = 125;
|
|
12973
13007
|
}
|
|
12974
13008
|
});
|
|
12975
13009
|
|
|
@@ -13871,6 +13905,7 @@ __export(dist_exports, {
|
|
|
13871
13905
|
imageRepo: () => imageRepo,
|
|
13872
13906
|
imageVariantFor: () => imageVariantFor,
|
|
13873
13907
|
installCommandFor: () => installCommandFor,
|
|
13908
|
+
installFrozenFor: () => installFrozenFor,
|
|
13874
13909
|
installLocalMigrationTooling: () => installLocalMigrationTooling,
|
|
13875
13910
|
installUnfrozenNote: () => installUnfrozenNote,
|
|
13876
13911
|
isBookkeepingTable: () => isBookkeepingTable,
|
|
@@ -25318,6 +25353,17 @@ var init_founder_note_sync = __esm({
|
|
|
25318
25353
|
}
|
|
25319
25354
|
});
|
|
25320
25355
|
|
|
25356
|
+
// bin/review-mode-copy.js
|
|
25357
|
+
var POSTER_REVIEWED, CLAIMANT_NOTICE, HISTORY_LINE;
|
|
25358
|
+
var init_review_mode_copy = __esm({
|
|
25359
|
+
"bin/review-mode-copy.js"() {
|
|
25360
|
+
"use strict";
|
|
25361
|
+
POSTER_REVIEWED = "poster";
|
|
25362
|
+
CLAIMANT_NOTICE = "The poster reviews this work by hand. We don't run tests on it.";
|
|
25363
|
+
HISTORY_LINE = "Submitted for the poster's review.";
|
|
25364
|
+
}
|
|
25365
|
+
});
|
|
25366
|
+
|
|
25321
25367
|
// ../../packages/core/src/policy-audit.ts
|
|
25322
25368
|
function fence(nonce, body) {
|
|
25323
25369
|
return `<<<UNTRUSTED-${nonce}
|
|
@@ -40251,6 +40297,7 @@ __export(jpi_claim_exports, {
|
|
|
40251
40297
|
resolveBounty: () => resolveBounty,
|
|
40252
40298
|
resolveDeliveryDir: () => resolveDeliveryDir,
|
|
40253
40299
|
resolveSubmitWorktree: () => resolveSubmitWorktree,
|
|
40300
|
+
reviewModeLine: () => reviewModeLine,
|
|
40254
40301
|
reviseRecoveryCommand: () => reviseRecoveryCommand,
|
|
40255
40302
|
revokeFailureAction: () => revokeFailureAction,
|
|
40256
40303
|
run: () => run,
|
|
@@ -40718,9 +40765,15 @@ function extractClaimableFields(job) {
|
|
|
40718
40765
|
// poster saw. Null when the index carries none.
|
|
40719
40766
|
runRequirements: b.runRequirements && typeof b.runRequirements === "object" ? b.runRequirements : null,
|
|
40720
40767
|
// TERM-1308. Present only when the index row carries them; no key otherwise.
|
|
40721
|
-
...b.bountySource === "founder" ? baselineFields(b) : {}
|
|
40768
|
+
...b.bountySource === "founder" ? baselineFields(b) : {},
|
|
40769
|
+
// TERM-1344. The index carries `reviewMode` only for a poster-reviewed posting; any
|
|
40770
|
+
// other value is dropped rather than carried, the same as a malformed baseline field.
|
|
40771
|
+
...b.bountySource === "founder" && b.reviewMode === POSTER_REVIEWED ? { reviewMode: POSTER_REVIEWED } : {}
|
|
40722
40772
|
};
|
|
40723
40773
|
}
|
|
40774
|
+
function reviewModeLine(b) {
|
|
40775
|
+
return b?.reviewMode === POSTER_REVIEWED ? CLAIMANT_NOTICE : null;
|
|
40776
|
+
}
|
|
40724
40777
|
function parseGitHubUrl(url) {
|
|
40725
40778
|
const m = String(url ?? "").match(/github\.com\/([^/]+)\/([^/]+)\/(?:issues|pull)\/(\d+)/);
|
|
40726
40779
|
if (!m) return null;
|
|
@@ -41326,7 +41379,7 @@ async function resolveBounty(arg) {
|
|
|
41326
41379
|
if (freshPool) job = findByShortRefInPool(freshPool, arg);
|
|
41327
41380
|
}
|
|
41328
41381
|
if (job) {
|
|
41329
|
-
let testBudgetMinutes, baselineStatus, baselineSha;
|
|
41382
|
+
let testBudgetMinutes, baselineStatus, baselineSha, reviewMode;
|
|
41330
41383
|
({
|
|
41331
41384
|
bountyId,
|
|
41332
41385
|
title,
|
|
@@ -41340,12 +41393,15 @@ async function resolveBounty(arg) {
|
|
|
41340
41393
|
runRequirements,
|
|
41341
41394
|
testBudgetMinutes,
|
|
41342
41395
|
baselineStatus,
|
|
41343
|
-
baselineSha
|
|
41396
|
+
baselineSha,
|
|
41397
|
+
reviewMode
|
|
41344
41398
|
} = extractClaimableFields(job));
|
|
41345
41399
|
baseline = {
|
|
41346
41400
|
...testBudgetMinutes === void 0 ? {} : { testBudgetMinutes },
|
|
41347
41401
|
...baselineStatus === void 0 ? {} : { baselineStatus },
|
|
41348
|
-
...baselineSha === void 0 ? {} : { baselineSha }
|
|
41402
|
+
...baselineSha === void 0 ? {} : { baselineSha },
|
|
41403
|
+
// TERM-1344. Rides with the baseline fields: index-only, and no key when absent.
|
|
41404
|
+
...reviewMode === void 0 ? {} : { reviewMode }
|
|
41349
41405
|
};
|
|
41350
41406
|
indexNativeId = bountyId;
|
|
41351
41407
|
} else {
|
|
@@ -42105,6 +42161,8 @@ async function cmdPreview(arg, { json } = {}) {
|
|
|
42105
42161
|
contested: isContested(b),
|
|
42106
42162
|
// TERM-1308. The posting's test budget and baseline, only when the index carried them.
|
|
42107
42163
|
...baselineFields(b),
|
|
42164
|
+
// TERM-1344. Only for a poster-reviewed posting; absent means tests.
|
|
42165
|
+
...b.reviewMode === POSTER_REVIEWED ? { reviewMode: POSTER_REVIEWED } : {},
|
|
42108
42166
|
// Absent on a founder posting — see the scan above. A consumer must read
|
|
42109
42167
|
// "no policy key" as "no policy step exists here", never as "clean".
|
|
42110
42168
|
...policy ? {
|
|
@@ -42135,8 +42193,8 @@ async function cmdPreview(arg, { json } = {}) {
|
|
|
42135
42193
|
console.log(fmtOpenPRsLine(b));
|
|
42136
42194
|
const previewContested = fmtContestedWarning(b);
|
|
42137
42195
|
if (previewContested) console.log(previewContested);
|
|
42138
|
-
const
|
|
42139
|
-
if (
|
|
42196
|
+
const previewTests = reviewModeLine(b) ?? baselineLine(b);
|
|
42197
|
+
if (previewTests) console.log(` tests: ${previewTests}`);
|
|
42140
42198
|
if (policy) printPolicySection(policy);
|
|
42141
42199
|
if (process.stdout.isTTY) {
|
|
42142
42200
|
try {
|
|
@@ -43392,7 +43450,8 @@ function renderRunView(run3, message2, extra = {}) {
|
|
|
43392
43450
|
const rateLimitCap = extra.rateLimitCap ?? run3.rateLimitCap ?? 5;
|
|
43393
43451
|
const rateLimitCount = extra.rateLimitCount ?? run3.rateLimitCount;
|
|
43394
43452
|
if (claimState) {
|
|
43395
|
-
|
|
43453
|
+
const stateText = claimState === "poster-review" ? HISTORY_LINE : terminalSafeInline(claimState);
|
|
43454
|
+
lines.push(` state: ${stateText}`);
|
|
43396
43455
|
}
|
|
43397
43456
|
if (unverifiedCause) {
|
|
43398
43457
|
lines.push(` cause: ${terminalSafeInline(unverifiedCause)}`);
|
|
@@ -43438,7 +43497,8 @@ function renderClaimHistory(attempts, timeline) {
|
|
|
43438
43497
|
for (const a of runs) {
|
|
43439
43498
|
const sha = a.commitSha ? String(a.commitSha).slice(0, 10) : "";
|
|
43440
43499
|
const jobs = Array.isArray(a.failingJobs) && a.failingJobs.length > 0 ? ` \u2014 ${a.failingJobs.map(terminalSafeInline).join(", ")}` : "";
|
|
43441
|
-
const
|
|
43500
|
+
const note = typeof a.note === "string" ? terminalSafeInline(a.note).trim() : "";
|
|
43501
|
+
const outcome = a.conclusion ? `checks ${terminalSafeInline(a.conclusion)}${jobs}` : note !== "" ? note : a.status === "no-ci" ? "no checks ran" : "checks running";
|
|
43442
43502
|
lines.push(` attempt ${a.attemptNumber} ${sha} ${outcome} ${shortWhen(a.at)}`);
|
|
43443
43503
|
}
|
|
43444
43504
|
for (const e of told) {
|
|
@@ -44188,6 +44248,57 @@ async function uploadClaimScreenshots(intake, uploads) {
|
|
|
44188
44248
|
);
|
|
44189
44249
|
}
|
|
44190
44250
|
}
|
|
44251
|
+
async function packageJsonAt(wt, rev, path5) {
|
|
44252
|
+
let text;
|
|
44253
|
+
try {
|
|
44254
|
+
({ stdout: text } = await pExecFile("git", ["-C", wt, "show", `${rev}:${path5}`], {
|
|
44255
|
+
shell: false,
|
|
44256
|
+
maxBuffer: 16 * 1024 * 1024
|
|
44257
|
+
}));
|
|
44258
|
+
} catch {
|
|
44259
|
+
return {};
|
|
44260
|
+
}
|
|
44261
|
+
try {
|
|
44262
|
+
const parsed = JSON.parse(String(text));
|
|
44263
|
+
return parsed !== null && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
|
|
44264
|
+
} catch {
|
|
44265
|
+
return null;
|
|
44266
|
+
}
|
|
44267
|
+
}
|
|
44268
|
+
function sectionKey(pkg, section) {
|
|
44269
|
+
const value = pkg[section];
|
|
44270
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
44271
|
+
return JSON.stringify(value ?? null);
|
|
44272
|
+
}
|
|
44273
|
+
return JSON.stringify(Object.keys(value).sort().map((k) => [k, value[k]]));
|
|
44274
|
+
}
|
|
44275
|
+
async function patchChangesDependencies(wt, base, touched) {
|
|
44276
|
+
for (const path5 of touched) {
|
|
44277
|
+
if (path5.split("/").pop() !== "package.json") continue;
|
|
44278
|
+
const before = await packageJsonAt(wt, base, path5);
|
|
44279
|
+
const after = await packageJsonAt(wt, "HEAD", path5);
|
|
44280
|
+
if (before === null || after === null) continue;
|
|
44281
|
+
if (DEPENDENCY_SECTIONS2.some((s) => sectionKey(before, s) !== sectionKey(after, s))) return true;
|
|
44282
|
+
}
|
|
44283
|
+
return false;
|
|
44284
|
+
}
|
|
44285
|
+
async function dependencyLockfileWarnings(wt, base, touched) {
|
|
44286
|
+
if (!await patchChangesDependencies(wt, base, touched)) return [];
|
|
44287
|
+
const warnings = [];
|
|
44288
|
+
for (const [lockfile, cmd] of SENDABLE_LOCKFILES) {
|
|
44289
|
+
let present;
|
|
44290
|
+
try {
|
|
44291
|
+
present = (await sh("git", ["-C", wt, "ls-tree", "--name-only", base, "--", lockfile])).trim() === lockfile;
|
|
44292
|
+
} catch {
|
|
44293
|
+
present = false;
|
|
44294
|
+
}
|
|
44295
|
+
if (!present || touched.includes(lockfile)) continue;
|
|
44296
|
+
warnings.push(
|
|
44297
|
+
` \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.`
|
|
44298
|
+
);
|
|
44299
|
+
}
|
|
44300
|
+
return warnings;
|
|
44301
|
+
}
|
|
44191
44302
|
async function submitFounderPatch({ claims, claim, id, wt, flags }) {
|
|
44192
44303
|
let roots;
|
|
44193
44304
|
try {
|
|
@@ -44238,6 +44349,9 @@ async function submitFounderPatch({ claims, claim, id, wt, flags }) {
|
|
|
44238
44349
|
);
|
|
44239
44350
|
process.exit(1);
|
|
44240
44351
|
}
|
|
44352
|
+
const lockfileWarnings = await dependencyLockfileWarnings(wt, base, touched);
|
|
44353
|
+
if (lockfileWarnings.length > 0) console.log(`
|
|
44354
|
+
${lockfileWarnings.join("\n")}`);
|
|
44241
44355
|
const authorName = await sh("git", ["-C", wt, "log", "-1", "--format=%an"]);
|
|
44242
44356
|
const authorEmail = await sh("git", ["-C", wt, "log", "-1", "--format=%ae"]);
|
|
44243
44357
|
const shots = flags.screenshots === void 0 ? null : loadClaimScreenshots(flags.screenshots);
|
|
@@ -45747,7 +45861,7 @@ async function run() {
|
|
|
45747
45861
|
process.exit(1);
|
|
45748
45862
|
}
|
|
45749
45863
|
}
|
|
45750
|
-
var TERMINALHIRE_DIR11, INDEX_CACHE_FILE2, CLAIM_PUSH_MARKER, REPO_CONTINUITY_NUDGE_MARKER, API_URL, CLAIM_SYNC_BASE4, CLAIM_CONSENT_VERSION, CLAIM_POLL_INTERVAL_MS, CLAIM_POLL_TIMEOUT_MS, CLAIM_SYNC_WRITE_TIMEOUT_MS, GH_API2, GH_HEADERS2, CONTENTION_HINT, AI_DISCLOSURE_NOTE, pExecFile, VALUE_FLAGS, BASELINE_STATUSES, MIN_TEST_BUDGET_MINUTES, MAX_TEST_BUDGET_MINUTES, ASSIGNMENT_MARKER, STAKE_MARKER, STANDDOWN_MARKER, OUR_MARKERS, STAKE_POST_TIMEOUT_MS, STAKE_POSTING_GRACE_MS, TAKE_BOT_REPOS, SUBMIT_ACCEPTS, REVISE_RECOVERY_STATES, CLOSED_STATES, GH_SESSION_COOKIE, PUSH_TOKEN_REFUSAL, SYNC_BACKGROUND_PUSH_ACTIVE_FIELD, ISSUE_OUTCOME_TERMINAL, RUNS_POLL_INTERVAL_MS, RUNS_POLL_ATTEMPTS, OPENABLE_AGENTS, BRIEF_DIR, BRIEF_REL_PATH, VERIFY_REL_PATH, AGENTS_REL_PATH, BRIEF_EXCLUDE_LINE, PACK_SAFE_ID, CLAIM_EVENT_LABEL, LINE_BREAKS, CONTROL_CHARS3, FOUNDER_POSTING_ID, CLAIM_SCREENSHOT_PUT_TIMEOUT_MS, CLAIM_RESOLUTION_REASONS, SETUP_FAILED_REQUIREMENTS, POSTING_LEVEL_RESOLUTION_REASONS, RESOLUTION_REASON_BLURB;
|
|
45864
|
+
var TERMINALHIRE_DIR11, INDEX_CACHE_FILE2, CLAIM_PUSH_MARKER, REPO_CONTINUITY_NUDGE_MARKER, API_URL, CLAIM_SYNC_BASE4, CLAIM_CONSENT_VERSION, CLAIM_POLL_INTERVAL_MS, CLAIM_POLL_TIMEOUT_MS, CLAIM_SYNC_WRITE_TIMEOUT_MS, GH_API2, GH_HEADERS2, CONTENTION_HINT, AI_DISCLOSURE_NOTE, pExecFile, VALUE_FLAGS, BASELINE_STATUSES, MIN_TEST_BUDGET_MINUTES, MAX_TEST_BUDGET_MINUTES, ASSIGNMENT_MARKER, STAKE_MARKER, STANDDOWN_MARKER, OUR_MARKERS, STAKE_POST_TIMEOUT_MS, STAKE_POSTING_GRACE_MS, TAKE_BOT_REPOS, SUBMIT_ACCEPTS, REVISE_RECOVERY_STATES, CLOSED_STATES, GH_SESSION_COOKIE, PUSH_TOKEN_REFUSAL, SYNC_BACKGROUND_PUSH_ACTIVE_FIELD, ISSUE_OUTCOME_TERMINAL, RUNS_POLL_INTERVAL_MS, RUNS_POLL_ATTEMPTS, OPENABLE_AGENTS, BRIEF_DIR, BRIEF_REL_PATH, VERIFY_REL_PATH, AGENTS_REL_PATH, BRIEF_EXCLUDE_LINE, PACK_SAFE_ID, CLAIM_EVENT_LABEL, LINE_BREAKS, CONTROL_CHARS3, FOUNDER_POSTING_ID, CLAIM_SCREENSHOT_PUT_TIMEOUT_MS, DEPENDENCY_SECTIONS2, SENDABLE_LOCKFILES, CLAIM_RESOLUTION_REASONS, SETUP_FAILED_REQUIREMENTS, POSTING_LEVEL_RESOLUTION_REASONS, RESOLUTION_REASON_BLURB;
|
|
45751
45865
|
var init_jpi_claim = __esm({
|
|
45752
45866
|
"bin/jpi-claim.js"() {
|
|
45753
45867
|
"use strict";
|
|
@@ -45763,6 +45877,7 @@ var init_jpi_claim = __esm({
|
|
|
45763
45877
|
init_claim_push_bg();
|
|
45764
45878
|
init_founder_verdict_sync();
|
|
45765
45879
|
init_founder_note_sync();
|
|
45880
|
+
init_review_mode_copy();
|
|
45766
45881
|
TERMINALHIRE_DIR11 = process.env.TERMINALHIRE_DIR || join33(homedir15(), ".terminalhire");
|
|
45767
45882
|
INDEX_CACHE_FILE2 = join33(TERMINALHIRE_DIR11, "index-cache.json");
|
|
45768
45883
|
CLAIM_PUSH_MARKER = join33(TERMINALHIRE_DIR11, "claim-push.json");
|
|
@@ -45880,6 +45995,16 @@ var init_jpi_claim = __esm({
|
|
|
45880
45995
|
CONTROL_CHARS3 = /[\u0000-\u001F\u007F-\u009F]/g;
|
|
45881
45996
|
FOUNDER_POSTING_ID = /^fb_[A-Za-z0-9_-]{1,80}$/;
|
|
45882
45997
|
CLAIM_SCREENSHOT_PUT_TIMEOUT_MS = 2e4;
|
|
45998
|
+
DEPENDENCY_SECTIONS2 = [
|
|
45999
|
+
"dependencies",
|
|
46000
|
+
"devDependencies",
|
|
46001
|
+
"optionalDependencies",
|
|
46002
|
+
"peerDependencies"
|
|
46003
|
+
];
|
|
46004
|
+
SENDABLE_LOCKFILES = [
|
|
46005
|
+
["package-lock.json", "npm install"],
|
|
46006
|
+
["yarn.lock", "yarn install"]
|
|
46007
|
+
];
|
|
45883
46008
|
CLAIM_RESOLUTION_REASONS = [
|
|
45884
46009
|
"not-my-stack",
|
|
45885
46010
|
"out-of-time",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "terminalhire",
|
|
3
|
-
"version": "0.42.
|
|
3
|
+
"version": "0.42.43",
|
|
4
4
|
"description": "Developer jobs and paid bounties, matched in the terminal — ambient matches in the Claude Code spinner. Claim a scoped bounty and get paid when the poster accepts it.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|