terminalhire 0.42.19 → 0.42.20
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 +126 -22
- package/dist/bin/jpi-dispatch.js +259 -32
- package/dist/bin/jpi-mcp.js +126 -22
- package/dist/bin/jpi-run.js +406 -123
- package/package.json +1 -1
package/dist/bin/jpi-claim.js
CHANGED
|
@@ -28557,6 +28557,18 @@ var init_gceIdentity = __esm({
|
|
|
28557
28557
|
}
|
|
28558
28558
|
});
|
|
28559
28559
|
|
|
28560
|
+
// ../../packages/attest/dist/confidentialSpace.js
|
|
28561
|
+
import { createHash as createHash7, createPublicKey as createPublicKey3, verify as cryptoVerify3 } from "crypto";
|
|
28562
|
+
var CONFIDENTIAL_SPACE_ISSUER, CONFIDENTIAL_SPACE_OIDC_DISCOVERY_URL;
|
|
28563
|
+
var init_confidentialSpace = __esm({
|
|
28564
|
+
"../../packages/attest/dist/confidentialSpace.js"() {
|
|
28565
|
+
"use strict";
|
|
28566
|
+
init_gceIdentity();
|
|
28567
|
+
CONFIDENTIAL_SPACE_ISSUER = "https://confidentialcomputing.googleapis.com";
|
|
28568
|
+
CONFIDENTIAL_SPACE_OIDC_DISCOVERY_URL = `${CONFIDENTIAL_SPACE_ISSUER}/.well-known/openid-configuration`;
|
|
28569
|
+
}
|
|
28570
|
+
});
|
|
28571
|
+
|
|
28560
28572
|
// ../../packages/attest/dist/venueInstanceName.js
|
|
28561
28573
|
function venueInstanceName(runId) {
|
|
28562
28574
|
return `th-run-${runId}`.replace(/_/g, "-").toLowerCase().slice(0, 62);
|
|
@@ -28591,6 +28603,7 @@ var init_dist2 = __esm({
|
|
|
28591
28603
|
init_attestation();
|
|
28592
28604
|
init_nonce();
|
|
28593
28605
|
init_gceIdentity();
|
|
28606
|
+
init_confidentialSpace();
|
|
28594
28607
|
init_venueInstanceName();
|
|
28595
28608
|
init_verify();
|
|
28596
28609
|
}
|
|
@@ -28841,7 +28854,7 @@ var init_result = __esm({
|
|
|
28841
28854
|
});
|
|
28842
28855
|
|
|
28843
28856
|
// ../../packages/envrun/dist/attestation.js
|
|
28844
|
-
import { createHash as
|
|
28857
|
+
import { createHash as createHash8, randomBytes as randomBytes10 } from "crypto";
|
|
28845
28858
|
function contradicts(outcome, counts, exitCode) {
|
|
28846
28859
|
const budget = OUTCOME_TO_BUDGET[outcome];
|
|
28847
28860
|
if (budget === null)
|
|
@@ -28883,7 +28896,7 @@ function imageDigestOf(ref) {
|
|
|
28883
28896
|
return at === -1 ? null : ref.slice(at + 1);
|
|
28884
28897
|
}
|
|
28885
28898
|
function sha256Hex(data) {
|
|
28886
|
-
return
|
|
28899
|
+
return createHash8("sha256").update(typeof data === "string" ? Buffer.from(data, "utf8") : data).digest("hex");
|
|
28887
28900
|
}
|
|
28888
28901
|
function toTestRunResult(result, outputSha256) {
|
|
28889
28902
|
return {
|
|
@@ -29506,6 +29519,49 @@ var init_boundary = __esm({
|
|
|
29506
29519
|
});
|
|
29507
29520
|
|
|
29508
29521
|
// ../../packages/envrun/dist/gcpPlacement.js
|
|
29522
|
+
function assertWorkloadImage(fn, value) {
|
|
29523
|
+
if (typeof value !== "string" || !WORKLOAD_IMAGE_REFERENCE.test(value)) {
|
|
29524
|
+
throw new GcpPlacementError(`${fn}: the workload image is missing or is not one plain image reference (${String(WORKLOAD_IMAGE_REFERENCE)}). It lands inside a comma-separated --metadata= list, so anything that could start a second key is refused.`);
|
|
29525
|
+
}
|
|
29526
|
+
}
|
|
29527
|
+
function venueImageFromEnv(env) {
|
|
29528
|
+
const image = env["VENUE_IMAGE"] ?? "";
|
|
29529
|
+
if (image === "" || image === "cos-stable")
|
|
29530
|
+
return { venueImage: "cos-stable" };
|
|
29531
|
+
if (image !== "confidential-space") {
|
|
29532
|
+
throw new GcpPlacementError("VENUE_IMAGE is set to something other than cos-stable or confidential-space. An unknown value is refused rather than booted as the default.");
|
|
29533
|
+
}
|
|
29534
|
+
const workloadImage = env["VENUE_WORKLOAD_IMAGE"] ?? "";
|
|
29535
|
+
if (workloadImage === "") {
|
|
29536
|
+
throw new GcpPlacementError("VENUE_IMAGE=confidential-space needs VENUE_WORKLOAD_IMAGE, the image reference the Confidential Space launcher runs. Nothing boots without one.");
|
|
29537
|
+
}
|
|
29538
|
+
assertWorkloadImage("venueImageFromEnv", workloadImage);
|
|
29539
|
+
return { venueImage: "confidential-space", workloadImage };
|
|
29540
|
+
}
|
|
29541
|
+
function bootImageFlags(p) {
|
|
29542
|
+
const image = p.venueImage ?? "cos-stable";
|
|
29543
|
+
if (image === "cos-stable")
|
|
29544
|
+
return ["--image-family=cos-stable", "--image-project=cos-cloud"];
|
|
29545
|
+
if (image !== "confidential-space") {
|
|
29546
|
+
throw new GcpPlacementError("gcpBootArgv: venueImage is not one of cos-stable, confidential-space. An unknown image is refused rather than booted as the default.");
|
|
29547
|
+
}
|
|
29548
|
+
const workloadImage = p.workloadImage;
|
|
29549
|
+
assertWorkloadImage("gcpBootArgv", workloadImage);
|
|
29550
|
+
return [
|
|
29551
|
+
// The production family. The debug family reports `dbgstat: enabled`, which the
|
|
29552
|
+
// intake's verifier refuses, so a debug boot could never produce a run we record.
|
|
29553
|
+
"--image-family=confidential-space",
|
|
29554
|
+
"--image-project=confidential-space-images",
|
|
29555
|
+
"--confidential-compute-type=SEV",
|
|
29556
|
+
// The deploy-workloads page says N2D with SEV may set MIGRATE for live migration,
|
|
29557
|
+
// and every other machine type needs TERMINATE. The spec chose TERMINATE: a
|
|
29558
|
+
// maintenance event ends the VM instead of moving it, which for a VM that lives at
|
|
29559
|
+
// most GCP_MAX_RUN_DURATION_SECONDS costs one run. Whether GCE boots this exact
|
|
29560
|
+
// combination is phase 5's measurement.
|
|
29561
|
+
"--maintenance-policy=TERMINATE",
|
|
29562
|
+
`--metadata=tee-image-reference=${workloadImage},tee-container-log-redirect=true`
|
|
29563
|
+
];
|
|
29564
|
+
}
|
|
29509
29565
|
function assertInstanceIdentity(fn, id) {
|
|
29510
29566
|
const fields = [
|
|
29511
29567
|
["vmName", id.vmName, GCE_INSTANCE_NAME],
|
|
@@ -29531,8 +29587,8 @@ function gcpBootArgv(p) {
|
|
|
29531
29587
|
`--project=${p.project}`,
|
|
29532
29588
|
`--zone=${p.zone}`,
|
|
29533
29589
|
`--machine-type=${p.machineType}`,
|
|
29534
|
-
|
|
29535
|
-
|
|
29590
|
+
// What the VM boots, and the one part of this argv the two images do not share.
|
|
29591
|
+
...bootImageFlags(p),
|
|
29536
29592
|
// ── THE OUTER REAP. This, not the `finally` below, is what bounds the bill. ──
|
|
29537
29593
|
//
|
|
29538
29594
|
// An in-process `finally` is a best effort, not a reap. SIGKILL, a crashed
|
|
@@ -29610,7 +29666,7 @@ function gcpDeleteArgv(p) {
|
|
|
29610
29666
|
"--quiet"
|
|
29611
29667
|
];
|
|
29612
29668
|
}
|
|
29613
|
-
var DEFAULT_GCP_PROJECT, DEFAULT_GCP_ZONE, DEFAULT_GCP_MACHINE_TYPE, GcpPlacementError, GCP_MAX_RUN_DURATION_SECONDS, GCP_MANAGED_LABEL_KEY, GCP_RUN_LABEL_KEY, GCP_LABEL_VALUE, GCE_INSTANCE_NAME, GCP_RESOURCE_ID;
|
|
29669
|
+
var DEFAULT_GCP_PROJECT, DEFAULT_GCP_ZONE, DEFAULT_GCP_MACHINE_TYPE, GcpPlacementError, GCP_MAX_RUN_DURATION_SECONDS, GCP_MANAGED_LABEL_KEY, GCP_RUN_LABEL_KEY, CONFIDENTIAL_SPACE_MACHINE_TYPE, WORKLOAD_IMAGE_REFERENCE, GCP_LABEL_VALUE, GCE_INSTANCE_NAME, GCP_RESOURCE_ID;
|
|
29614
29670
|
var init_gcpPlacement = __esm({
|
|
29615
29671
|
"../../packages/envrun/dist/gcpPlacement.js"() {
|
|
29616
29672
|
"use strict";
|
|
@@ -29627,6 +29683,8 @@ var init_gcpPlacement = __esm({
|
|
|
29627
29683
|
GCP_MAX_RUN_DURATION_SECONDS = 3600;
|
|
29628
29684
|
GCP_MANAGED_LABEL_KEY = "th-managed";
|
|
29629
29685
|
GCP_RUN_LABEL_KEY = "th-run";
|
|
29686
|
+
CONFIDENTIAL_SPACE_MACHINE_TYPE = "n2d-standard-2";
|
|
29687
|
+
WORKLOAD_IMAGE_REFERENCE = /^[A-Za-z0-9][A-Za-z0-9._/:@-]{0,511}$/;
|
|
29630
29688
|
GCP_LABEL_VALUE = /^[a-z0-9_-]{1,63}$/;
|
|
29631
29689
|
GCE_INSTANCE_NAME = /^[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?$/;
|
|
29632
29690
|
GCP_RESOURCE_ID = /^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/;
|
|
@@ -30209,6 +30267,7 @@ function hostedVenue(opts = {}, io = defaultHostedVenueIo) {
|
|
|
30209
30267
|
const zone = opts.zone ?? DEFAULT_GCP_ZONE;
|
|
30210
30268
|
const gcloudConfig = opts.gcloudConfig ?? VENUE_GCLOUD_CONFIG;
|
|
30211
30269
|
const keyFile = resolveServiceAccountKeyFile(opts);
|
|
30270
|
+
const image = venueImageFromEnv(process.env);
|
|
30212
30271
|
const env = venueGcloudEnv(gcloudConfig);
|
|
30213
30272
|
return {
|
|
30214
30273
|
kind: "hosted-pool",
|
|
@@ -30220,7 +30279,8 @@ function hostedVenue(opts = {}, io = defaultHostedVenueIo) {
|
|
|
30220
30279
|
project,
|
|
30221
30280
|
zone,
|
|
30222
30281
|
runId,
|
|
30223
|
-
machineType: opts.machineType ?? DEFAULT_GCP_MACHINE_TYPE
|
|
30282
|
+
machineType: opts.machineType ?? (image.venueImage === "confidential-space" ? CONFIDENTIAL_SPACE_MACHINE_TYPE : DEFAULT_GCP_MACHINE_TYPE),
|
|
30283
|
+
...image
|
|
30224
30284
|
});
|
|
30225
30285
|
ensureVenueServiceCredentials(gcloudConfig, keyFile, io);
|
|
30226
30286
|
const boot = io.exec("gcloud", bootArgv, BOOT_TIMEOUT_MS, env);
|
|
@@ -32346,13 +32406,16 @@ function git(repoDir, args, allowNonZero = false) {
|
|
|
32346
32406
|
}
|
|
32347
32407
|
return res.stdout ?? "";
|
|
32348
32408
|
}
|
|
32349
|
-
function collectWorkingDiff(repoDir) {
|
|
32409
|
+
function collectWorkingDiff(repoDir, opts = {}) {
|
|
32350
32410
|
if (!existsSync12(join26(repoDir, ".git"))) {
|
|
32351
32411
|
throw new ThRunError(`${repoDir} is not a git checkout (no .git). \`th run\` ships the working diff, so it needs a repository to read one from.`);
|
|
32352
32412
|
}
|
|
32353
32413
|
const headSha = git(repoDir, ["rev-parse", "HEAD"]).trim();
|
|
32354
|
-
const
|
|
32355
|
-
const
|
|
32414
|
+
const diffBase = opts.base === void 0 ? headSha : assertDiffBase(repoDir, opts.base);
|
|
32415
|
+
const trackedArgs = opts.base === void 0 ? ["diff", "HEAD"] : ["diff", diffBase];
|
|
32416
|
+
const pathsEnd = opts.base === void 0 ? [] : ["--"];
|
|
32417
|
+
const tracked = git(repoDir, [...trackedArgs, "--binary", ...pathsEnd]);
|
|
32418
|
+
const trackedChanged = git(repoDir, [...trackedArgs, "--name-only", ...pathsEnd]).split("\n").map((s) => s.trim()).filter((s) => s.length > 0);
|
|
32356
32419
|
const untracked = git(repoDir, ["ls-files", "--others", "--exclude-standard"]).split("\n").map((s) => s.trim()).filter((s) => s.length > 0);
|
|
32357
32420
|
const parts = [];
|
|
32358
32421
|
if (tracked.trim() !== "")
|
|
@@ -32362,7 +32425,17 @@ function collectWorkingDiff(repoDir) {
|
|
|
32362
32425
|
if (one.trim() !== "")
|
|
32363
32426
|
parts.push(one.replace(/\n*$/, "\n"));
|
|
32364
32427
|
}
|
|
32365
|
-
return { patch: parts.join(""), headSha, trackedChanged, untracked };
|
|
32428
|
+
return { patch: parts.join(""), headSha, diffBase, trackedChanged, untracked };
|
|
32429
|
+
}
|
|
32430
|
+
function assertDiffBase(repoDir, base) {
|
|
32431
|
+
if (!FULL_COMMIT_ID.test(base)) {
|
|
32432
|
+
throw new ThRunError(`the diff base must be a full 40-character commit id, got ${JSON.stringify(base)}.`);
|
|
32433
|
+
}
|
|
32434
|
+
const resolved = git(repoDir, ["rev-parse", "--verify", "--quiet", `${base}^{commit}`], true);
|
|
32435
|
+
if (resolved.trim() !== base) {
|
|
32436
|
+
throw new ThRunError(`the diff base ${base} is not a commit in ${repoDir}.`);
|
|
32437
|
+
}
|
|
32438
|
+
return base;
|
|
32366
32439
|
}
|
|
32367
32440
|
function isLocalPath(p) {
|
|
32368
32441
|
return !UNC_PATH.test(p) && (p.startsWith("/") || WINDOWS_ABSOLUTE.test(p));
|
|
@@ -32934,8 +33007,9 @@ async function runVerification(req, ctx) {
|
|
|
32934
33007
|
let diff = null;
|
|
32935
33008
|
if (source.kind === "working-diff") {
|
|
32936
33009
|
progress("collect", `reading the working diff from ${source.localRepoDir}`);
|
|
32937
|
-
diff = collectWorkingDiff(source.localRepoDir);
|
|
32938
|
-
|
|
33010
|
+
diff = collectWorkingDiff(source.localRepoDir, source.diffBase === void 0 ? {} : { base: source.diffBase });
|
|
33011
|
+
const from = source.diffBase === void 0 ? "" : `, from delivered baseline ${diff.diffBase.slice(0, 12)}`;
|
|
33012
|
+
progress("collect", `${String(diff.trackedChanged.length)} tracked, ${String(diff.untracked.length)} untracked, ${String(diff.patch.length)} bytes${from}`);
|
|
32939
33013
|
} else {
|
|
32940
33014
|
progress("collect", "dispatched run: the tree is the stored commit itself");
|
|
32941
33015
|
}
|
|
@@ -33137,7 +33211,7 @@ async function runVerification(req, ctx) {
|
|
|
33137
33211
|
await releaseWithoutThrowing(lease, progress);
|
|
33138
33212
|
}
|
|
33139
33213
|
}
|
|
33140
|
-
var ThRunError, OUTPUT_TAIL_BYTES, 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, FAILURE_LINE, REDACTED_TARGET_REPO, REDACTED_TARGET_SHA;
|
|
33214
|
+
var ThRunError, OUTPUT_TAIL_BYTES, 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, FAILURE_LINE, REDACTED_TARGET_REPO, REDACTED_TARGET_SHA;
|
|
33141
33215
|
var init_thrun = __esm({
|
|
33142
33216
|
"../../packages/envrun/dist/thrun.js"() {
|
|
33143
33217
|
"use strict";
|
|
@@ -33155,6 +33229,7 @@ var init_thrun = __esm({
|
|
|
33155
33229
|
ThRunError = class extends Error {
|
|
33156
33230
|
};
|
|
33157
33231
|
OUTPUT_TAIL_BYTES = 4e3;
|
|
33232
|
+
FULL_COMMIT_ID = /^[0-9a-f]{40}$/;
|
|
33158
33233
|
ALLOWED_URL_SCHEMES = /* @__PURE__ */ new Set(["https", "http", "ssh", "git"]);
|
|
33159
33234
|
SCP_STYLE = /^[A-Za-z0-9._~+-]+@[A-Za-z0-9._-]+:[^:]/;
|
|
33160
33235
|
URL_SCHEME = /^([A-Za-z][A-Za-z0-9+.-]*):\/\//;
|
|
@@ -34013,6 +34088,7 @@ __export(dist_exports, {
|
|
|
34013
34088
|
ALEMBIC_IMAGE: () => ALEMBIC_IMAGE,
|
|
34014
34089
|
ATTEST_REFUSAL_REASONS: () => ATTEST_REFUSAL_REASONS,
|
|
34015
34090
|
BOOKKEEPING_TABLES: () => BOOKKEEPING_TABLES,
|
|
34091
|
+
CONFIDENTIAL_SPACE_MACHINE_TYPE: () => CONFIDENTIAL_SPACE_MACHINE_TYPE,
|
|
34016
34092
|
CONTAINMENT_UNAVAILABLE_PREFIX: () => CONTAINMENT_UNAVAILABLE_PREFIX,
|
|
34017
34093
|
CloneUnavailableError: () => CloneUnavailableError,
|
|
34018
34094
|
DAEMON_FACTS_FORMAT: () => DAEMON_FACTS_FORMAT,
|
|
@@ -34154,6 +34230,7 @@ __export(dist_exports, {
|
|
|
34154
34230
|
toolingImageFor: () => toolingImageFor,
|
|
34155
34231
|
unquoteDiffPath: () => unquoteDiffPath,
|
|
34156
34232
|
venueGcloudEnv: () => venueGcloudEnv,
|
|
34233
|
+
venueImageFromEnv: () => venueImageFromEnv,
|
|
34157
34234
|
venueStagePaths: () => venueStagePaths,
|
|
34158
34235
|
verifyWorkingDiff: () => verifyWorkingDiff
|
|
34159
34236
|
});
|
|
@@ -34465,7 +34542,7 @@ import {
|
|
|
34465
34542
|
readdirSync as readdirSync3
|
|
34466
34543
|
} from "fs";
|
|
34467
34544
|
import { join as join28, dirname as dirname8, isAbsolute as isAbsolute4, resolve as pathResolve } from "path";
|
|
34468
|
-
import { createHash as
|
|
34545
|
+
import { createHash as createHash9 } from "crypto";
|
|
34469
34546
|
import { homedir as homedir14, hostname as osHostname } from "os";
|
|
34470
34547
|
import { execFile as execFile3, execFileSync as execFileSync2, spawnSync as spawnSync8 } from "child_process";
|
|
34471
34548
|
import { promisify as promisify3 } from "util";
|
|
@@ -37849,16 +37926,26 @@ function writePackFile(destDir, relPath, content, what) {
|
|
|
37849
37926
|
return { written: true, reason: null, sha256: sha256OfUtf8(content) };
|
|
37850
37927
|
}
|
|
37851
37928
|
function sha256OfUtf8(content) {
|
|
37852
|
-
return
|
|
37929
|
+
return createHash9("sha256").update(content, "utf8").digest("hex");
|
|
37853
37930
|
}
|
|
37854
|
-
function writeWorkspacePack(destDir, spec, claim) {
|
|
37931
|
+
function writeWorkspacePack(destDir, spec, claim, delivery) {
|
|
37932
|
+
if (delivery !== "full" && delivery !== "sparse") {
|
|
37933
|
+
throw new TypeError(
|
|
37934
|
+
`writeWorkspacePack: delivery must be 'full' or 'sparse', got ${String(delivery)}`
|
|
37935
|
+
);
|
|
37936
|
+
}
|
|
37855
37937
|
const gate = ensureExcludedPackDir(destDir);
|
|
37856
37938
|
if (!gate.ok) {
|
|
37857
37939
|
const refused = { written: false, reason: gate.reason };
|
|
37858
37940
|
return { brief: refused, verify: refused, agents: refused };
|
|
37859
37941
|
}
|
|
37860
37942
|
const brief = typeof spec !== "string" || spec.trim() === "" ? { written: false, reason: "the server sent no task for this posting" } : writePackFile(destDir, BRIEF_REL_PATH, spec, "task");
|
|
37861
|
-
const verify = writePackFile(
|
|
37943
|
+
const verify = writePackFile(
|
|
37944
|
+
destDir,
|
|
37945
|
+
VERIFY_REL_PATH,
|
|
37946
|
+
renderVerifyDoc(claim, delivery),
|
|
37947
|
+
"verify note"
|
|
37948
|
+
);
|
|
37862
37949
|
const agents = writePackFile(
|
|
37863
37950
|
destDir,
|
|
37864
37951
|
AGENTS_REL_PATH,
|
|
@@ -37872,20 +37959,30 @@ function packSafeId(claim) {
|
|
|
37872
37959
|
const id = String(claim?.id ?? "");
|
|
37873
37960
|
return PACK_SAFE_ID.test(id) ? id : "<your claim id \u2014 see: terminalhire claim list>";
|
|
37874
37961
|
}
|
|
37875
|
-
function renderVerifyDoc(claim) {
|
|
37962
|
+
function renderVerifyDoc(claim, delivery) {
|
|
37876
37963
|
const id = packSafeId(claim);
|
|
37964
|
+
const runStep2 = delivery === "full" ? ` ${nextStep("terminalhire run")}
|
|
37965
|
+
|
|
37966
|
+
It tests every change since the delivered baseline, committed or not, which
|
|
37967
|
+
is what submit sends once it is all committed.` : ` ${nextStep("terminalhire run --target <clone URL of the full repository>")}
|
|
37968
|
+
|
|
37969
|
+
It tests every change since the delivered baseline, committed or not, which
|
|
37970
|
+
is what submit sends once it is all committed. This delivery contains only the
|
|
37971
|
+
files you were granted, so the local run needs the whole repository; if you
|
|
37972
|
+
don't have access to it, skip to step 4, because the poster-side run in step 5
|
|
37973
|
+
is the verdict that counts.`;
|
|
37877
37974
|
return `# Verifying claim ${id}
|
|
37878
37975
|
|
|
37879
37976
|
This workspace was delivered by terminalhire for a posting. "Done" is
|
|
37880
37977
|
judged on the diff: the submitted patch is the change from the delivered
|
|
37881
37978
|
baseline (this repo's root commit) to HEAD, so only committed, tracked changes
|
|
37882
|
-
count.
|
|
37979
|
+
count. Submit needs a clean tree; run does not.
|
|
37883
37980
|
|
|
37884
37981
|
1. Read the poster's task first, when there is one: ${BRIEF_REL_PATH}
|
|
37885
37982
|
2. Work on the claim branch this delivery checked out, committing as you go.
|
|
37886
37983
|
3. To verify locally in terminalhire's sandboxed runner, from this directory:
|
|
37887
37984
|
|
|
37888
|
-
|
|
37985
|
+
${runStep2}
|
|
37889
37986
|
|
|
37890
37987
|
4. Submit \u2014 the only step that sends anything off this machine. It prints what it
|
|
37891
37988
|
is about to send first, and asks y/N only at an interactive terminal:
|
|
@@ -38264,11 +38361,13 @@ async function cmdSliceFullTier(claims, id, local, fullTierBody, flags, cloneRep
|
|
|
38264
38361
|
);
|
|
38265
38362
|
process.exit(1);
|
|
38266
38363
|
}
|
|
38267
|
-
const pack = writeWorkspacePack(dest, body.spec, claim);
|
|
38364
|
+
const pack = writeWorkspacePack(dest, body.spec, claim, "full");
|
|
38268
38365
|
const working = claims.updateClaim(claim.id, {
|
|
38269
38366
|
worktreePath: dest,
|
|
38270
38367
|
branch,
|
|
38271
38368
|
state: "working",
|
|
38369
|
+
// `terminalhire run` clones this commit when run from the workspace (TERM-1098).
|
|
38370
|
+
baseSha,
|
|
38272
38371
|
workspacePack: {
|
|
38273
38372
|
brief: pack.brief.written === true,
|
|
38274
38373
|
verify: pack.verify.written === true,
|
|
@@ -38424,7 +38523,7 @@ async function attemptSliceDelivery(id, flags = {}) {
|
|
|
38424
38523
|
let pack;
|
|
38425
38524
|
try {
|
|
38426
38525
|
await sh("git", ["-C", dest, "init"]);
|
|
38427
|
-
pack = writeWorkspacePack(dest, body.spec, claim);
|
|
38526
|
+
pack = writeWorkspacePack(dest, body.spec, claim, "sparse");
|
|
38428
38527
|
await sh("git", ["-C", dest, "add", "-A"]);
|
|
38429
38528
|
await sh("git", [
|
|
38430
38529
|
"-C",
|
|
@@ -38461,6 +38560,11 @@ async function attemptSliceDelivery(id, flags = {}) {
|
|
|
38461
38560
|
worktreePath: dest,
|
|
38462
38561
|
branch,
|
|
38463
38562
|
state: "working",
|
|
38563
|
+
// The commit these files were cut from, so `terminalhire run` can clone it unasked
|
|
38564
|
+
// (TERM-1098). Recorded only when it is a full sha: a slice confirmed before the
|
|
38565
|
+
// server kept one answers null, and a value of any other shape is not a commit we
|
|
38566
|
+
// could clone, so neither is written and `run` asks for `--sha` instead.
|
|
38567
|
+
...typeof body.baseSha === "string" && /^[0-9a-f]{40}$/.test(body.baseSha) ? { baseSha: body.baseSha } : {},
|
|
38464
38568
|
workspacePack: {
|
|
38465
38569
|
brief: pack.brief.written === true,
|
|
38466
38570
|
verify: pack.verify.written === true,
|