@tangle-network/agent-runtime 6.0.5 → 6.0.7
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/CHANGELOG.md +8 -0
- package/dist/{activation-kpRQffeo.js → activation-Bb2ovvM5.js} +4 -4
- package/dist/{activation-kpRQffeo.js.map → activation-Bb2ovvM5.js.map} +1 -1
- package/dist/{activation-DEKw9CDD.d.ts → activation-DPz8kGpT.d.ts} +2 -2
- package/dist/agent.d.ts +1 -1
- package/dist/agent.js +2 -2
- package/dist/{bundle-BET6gl5r.js → bundle-Cy5igJdv.js} +2 -2
- package/dist/{bundle-BET6gl5r.js.map → bundle-Cy5igJdv.js.map} +1 -1
- package/dist/candidate-execution/index.js +4 -4
- package/dist/{coordination-manager-ds4pn4IC.js → coordination-manager-Cow3jgu1.js} +4 -4
- package/dist/{coordination-manager-ds4pn4IC.js.map → coordination-manager-Cow3jgu1.js.map} +1 -1
- package/dist/{delegate-B2Z1CueR.js → delegate-zUOoWutU.js} +2 -2
- package/dist/{delegate-B2Z1CueR.js.map → delegate-zUOoWutU.js.map} +1 -1
- package/dist/durable.d.ts +1 -1
- package/dist/durable.js +8 -8
- package/dist/{graph-flrNgUfu.js → graph-BS9p0hHV.js} +5 -5
- package/dist/{graph-flrNgUfu.js.map → graph-BS9p0hHV.js.map} +1 -1
- package/dist/{improve-DEkdGeQV.js → improve-Ca4PSA2z.js} +7 -7
- package/dist/{improve-DEkdGeQV.js.map → improve-Ca4PSA2z.js.map} +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.js +61 -13
- package/dist/index.js.map +1 -1
- package/dist/intelligence.d.ts +2 -2
- package/dist/intelligence.js +7 -7
- package/dist/kernel.d.ts +2 -2
- package/dist/kernel.js +13 -13
- package/dist/{loop-runner-CDad0CCY.d.ts → loop-runner-9surW8mg.d.ts} +2 -2
- package/dist/{loop-runner-CrEq3gmu.js → loop-runner-B_K3oLGC.js} +2 -2
- package/dist/{loop-runner-CrEq3gmu.js.map → loop-runner-B_K3oLGC.js.map} +1 -1
- package/dist/loop-runner-bin.d.ts +1 -1
- package/dist/loop-runner-bin.js +1 -1
- package/dist/mcp/bin.js +3 -3
- package/dist/mcp/index.d.ts +1 -1
- package/dist/mcp/index.js +5 -5
- package/dist/{prepare-O1HbzOqs.js → prepare-Dtfk_Wi_.js} +3 -3
- package/dist/{prepare-O1HbzOqs.js.map → prepare-Dtfk_Wi_.js.map} +1 -1
- package/dist/{profile-DcRoyryP.js → profile-CNSQjOes.js} +2 -2
- package/dist/{profile-DcRoyryP.js.map → profile-CNSQjOes.js.map} +1 -1
- package/dist/profiles.d.ts +1 -1
- package/dist/{provision-supervisor-CuX82sFT.js → provision-supervisor-ZG-ZxIe9.js} +4 -4
- package/dist/{provision-supervisor-CuX82sFT.js.map → provision-supervisor-ZG-ZxIe9.js.map} +1 -1
- package/dist/{run-cancellation-ZmRSYLu5.js → run-cancellation-CqF01-zj.js} +2 -2
- package/dist/{run-cancellation-ZmRSYLu5.js.map → run-cancellation-CqF01-zj.js.map} +1 -1
- package/dist/{run-state-Dt-v0Fr8.js → run-state-CeMgqULw.js} +4 -4
- package/dist/{run-state-Dt-v0Fr8.js.map → run-state-CeMgqULw.js.map} +1 -1
- package/dist/{runtime-BNSsSOZ7.js → runtime-CBt8PWn5.js} +419 -54
- package/dist/runtime-CBt8PWn5.js.map +1 -0
- package/dist/{scope-DSm2RW5I.js → scope-BF3RUg3U.js} +2 -2
- package/dist/{scope-DSm2RW5I.js.map → scope-BF3RUg3U.js.map} +1 -1
- package/dist/{search-executor-CpQIJAdh.js → search-executor-CoLgtigZ.js} +4 -4
- package/dist/{search-executor-CpQIJAdh.js.map → search-executor-CoLgtigZ.js.map} +1 -1
- package/dist/{server-umzSNbPI.js → server-Dv_wLT9_.js} +3 -3
- package/dist/{server-umzSNbPI.js.map → server-Dv_wLT9_.js.map} +1 -1
- package/dist/{structural-rollout-B8PkKbfv.js → structural-rollout-ccetqcnq.js} +4 -4
- package/dist/{structural-rollout-B8PkKbfv.js.map → structural-rollout-ccetqcnq.js.map} +1 -1
- package/dist/{supervise-B3hzcqVU.js → supervise-BMqPWSv7.js} +5 -5
- package/dist/{supervise-B3hzcqVU.js.map → supervise-BMqPWSv7.js.map} +1 -1
- package/dist/{supervision-discovery-BNChDps7.js → supervision-discovery-mF3cWh36.js} +2 -2
- package/dist/{supervision-discovery-BNChDps7.js.map → supervision-discovery-mF3cWh36.js.map} +1 -1
- package/dist/{supervisor-DpWSUrwB.js → supervisor-CigTbS9A.js} +21 -20
- package/dist/supervisor-CigTbS9A.js.map +1 -0
- package/dist/testing.d.ts +1 -1
- package/dist/testing.js +13 -13
- package/dist/{top-web-CQNkrh_j.js → top-web-DBhkr1lN.js} +4 -4
- package/dist/{top-web-CQNkrh_j.js.map → top-web-DBhkr1lN.js.map} +1 -1
- package/dist/tui/bin.js +3 -3
- package/dist/tui/index.d.ts +1 -1
- package/dist/tui/index.js +2 -2
- package/dist/{types-niKnm6ux.d.ts → types-DmJTtmgm.d.ts} +54 -4
- package/dist/{workspace-streams-uB9rRbms.js → workspace-streams-B7yNMahl.js} +2 -2
- package/dist/{workspace-streams-uB9rRbms.js.map → workspace-streams-B7yNMahl.js.map} +1 -1
- package/package.json +1 -1
- package/dist/runtime-BNSsSOZ7.js.map +0 -1
- package/dist/supervisor-DpWSUrwB.js.map +0 -1
|
@@ -1,25 +1,25 @@
|
|
|
1
|
-
import { A as isTraceAnalysisStore, Br as executableAgentProfileSnapshot, G as settledToIteration, Mt as coordinationProfileToolPrefix, Vr as executableAgentSpecSnapshot, X as rollingDispatch, ei as runAbortable, rn as insideCursorNamespace } from "./scope-
|
|
1
|
+
import { A as isTraceAnalysisStore, Br as executableAgentProfileSnapshot, G as settledToIteration, Mt as coordinationProfileToolPrefix, Vr as executableAgentSpecSnapshot, X as rollingDispatch, ei as runAbortable, rn as insideCursorNamespace } from "./scope-BF3RUg3U.js";
|
|
2
2
|
import { i as ConfigError, m as ValidationError, n as AnalystError, s as PlannerError } from "./errors-AzSuGI23.js";
|
|
3
|
-
import { D as runAgentic, E as refine, M as renderReport, N as profileChatClient, O as sample, j as observe, k as ObservationError, v as loadAuthoredStrategy, x as strategyAuthorContract, y as requestStrategySource } from "./structural-rollout-
|
|
3
|
+
import { D as runAgentic, E as refine, M as renderReport, N as profileChatClient, O as sample, j as observe, k as ObservationError, v as loadAuthoredStrategy, x as strategyAuthorContract, y as requestStrategySource } from "./structural-rollout-ccetqcnq.js";
|
|
4
4
|
import { I as armDeadlineTimer, T as zeroSpend, a as cloneSpend, c as errorMessage, d as isAbortError, f as isAsyncIterable, h as randomSuffix, i as chargedTokens, l as fnv1a32Hex, n as addSpend, p as mapWithConcurrency, u as hasCompleteCacheBreakdown, v as sleep, y as stringifySafe } from "./util-C_cdPNC4.js";
|
|
5
5
|
import { M as contentAddress, _t as notifySandboxEventObserver, pt as createSandboxTurnEventCollector, r as runtimeFailureCauseSchema } from "./failure-cause-BzjUUsRz.js";
|
|
6
6
|
import { n as detachedSnapshot, t as detachedFrozen } from "./snapshot-Cgj2Wzi6.js";
|
|
7
|
-
import { C as createExecutor, D as runAgentRounds, O as assertBoxlessPromptOptions, P as defaultSelectWinner, V as routerBrain, _ as withDriverExecutor, b as createExecutorRegistry, bt as verdictFromJudgeScore, gt as CheckUnavailableError, j as createSandboxLineage, k as readPromptOptions, n as createSupervisor, q as createWorktreeCliExecutor, v as InMemoryResultBlobStore, vt as gateOnDeliverable, y as InMemorySpawnJournal, yt as mapExecutorResult } from "./supervisor-
|
|
7
|
+
import { C as createExecutor, D as runAgentRounds, O as assertBoxlessPromptOptions, P as defaultSelectWinner, V as routerBrain, _ as withDriverExecutor, b as createExecutorRegistry, bt as verdictFromJudgeScore, gt as CheckUnavailableError, j as createSandboxLineage, k as readPromptOptions, n as createSupervisor, q as createWorktreeCliExecutor, v as InMemoryResultBlobStore, vt as gateOnDeliverable, y as InMemorySpawnJournal, yt as mapExecutorResult } from "./supervisor-CigTbS9A.js";
|
|
8
8
|
import { a as concreteProfileModel, c as profileModelExecutionSettings, i as concreteModelId, l as profileProviderModel, o as enforceTokenLimits, p as canonicalObservedModelParts, t as assertExecutableAgentProfile, v as harnessRunsAgent } from "./model-policy-JOcg3NRs.js";
|
|
9
9
|
import { a as readCommittedJsonLines, c as appendCommittedJsonLine, i as readCommittedJsonFile, o as upsertCommittedJsonLine, s as withJsonlFileLock, t as isNoEntError } from "./jsonl-file-BeUa5EDx.js";
|
|
10
|
-
import {
|
|
10
|
+
import { A as markPutStreamVerified, L as immutableCandidateValue, N as canonicalCandidateDigest$1, S as captureMaterializedWorkspace, T as scanMaterializedWorkspaceManifest, g as persistCandidateOutputArtifact, y as WorkspaceScanLimitError, z as sha256Bytes$1 } from "./workspace-streams-B7yNMahl.js";
|
|
11
11
|
import { a as writeAtomicDurableFile } from "./durable-file-DstVeHcj.js";
|
|
12
12
|
import { i as notifyRuntimeHookEvent } from "./runtime-hooks-CsW2pfFk.js";
|
|
13
|
-
import { a as reconcileInterruptedSearchCalls, c as searchExecutor, r as dedicatedLane, x as runtimeShipDecision } from "./search-executor-
|
|
14
|
-
import { y as foldCoordinationRecords } from "./run-cancellation-
|
|
15
|
-
import { a as downMessageRefusalReasons, p as createInMemoryRunContext } from "./coordination-manager-
|
|
16
|
-
import { M as kernelPromptRegistry, S as validateFlowGraph, T as validateGraphTopology, h as runBrainLoop, p as coordinationControlToolNames, t as supervise } from "./supervise-
|
|
13
|
+
import { a as reconcileInterruptedSearchCalls, c as searchExecutor, r as dedicatedLane, x as runtimeShipDecision } from "./search-executor-CoLgtigZ.js";
|
|
14
|
+
import { y as foldCoordinationRecords } from "./run-cancellation-CqF01-zj.js";
|
|
15
|
+
import { a as downMessageRefusalReasons, p as createInMemoryRunContext } from "./coordination-manager-Cow3jgu1.js";
|
|
16
|
+
import { M as kernelPromptRegistry, S as validateFlowGraph, T as validateGraphTopology, h as runBrainLoop, p as coordinationControlToolNames, t as supervise } from "./supervise-BMqPWSv7.js";
|
|
17
17
|
import { _ as compileGraphParameters, a as graphRegistry, b as graphRouteWhenSchema, d as recordGraphRun, g as bindGraphParameters, h as assertGraphTriggerBindings, i as graphFromStored, l as lookupGraph, m as taskShapeDigest, o as graphRunsFor, r as graphDigest, t as digestOfGraph, v as graphTriggerBindingsSchema, y as graphFileSchema } from "./graph-registry-DbCwfHMY.js";
|
|
18
|
-
import "./run-state-
|
|
18
|
+
import "./run-state-CeMgqULw.js";
|
|
19
19
|
import { i as redactProtectedValue, r as redactProtectedReason } from "./protected-redaction-DilFZch5.js";
|
|
20
|
-
import "./provision-supervisor-
|
|
21
|
-
import "./delegate-
|
|
22
|
-
import "./graph-
|
|
20
|
+
import "./provision-supervisor-ZG-ZxIe9.js";
|
|
21
|
+
import "./delegate-zUOoWutU.js";
|
|
22
|
+
import "./graph-BS9p0hHV.js";
|
|
23
23
|
import { agentProfileSchema, canonicalAgentProfileDigest, canonicalCandidateDigest, sha256Bytes, validateAgentProfileSecurity } from "@tangle-network/agent-interface";
|
|
24
24
|
import { CODING_HARNESSES, DEFAULT_TRACE_ANALYST_KINDS, InMemoryTraceStore, OUTPUT_VALUE, benjaminiHochberg, buildTrajectory, computeFindingId as computeFindingId$1, confidenceInterval, createTraceAnalyst, expandProfileAxes, makeFinding as makeFinding$1, pairedBootstrap, paretoFrontier, wilcoxonSignedRank, wilson } from "@tangle-network/agent-eval";
|
|
25
25
|
import { createAgentRunOutcomeTracker } from "@tangle-network/sandbox/runtime";
|
|
@@ -735,6 +735,267 @@ function deterministicCompletion(check) {
|
|
|
735
735
|
};
|
|
736
736
|
} };
|
|
737
737
|
}
|
|
738
|
+
// src/runtime/isolated-checker-outputs.ts
|
|
739
|
+
const MAX_FILES = 16;
|
|
740
|
+
const MAX_BYTES = 67108864;
|
|
741
|
+
const MAX_TIMEOUT_MS = 12e4;
|
|
742
|
+
/** Validate authored declarations before starting a check. The returned paths are detached and frozen. */
|
|
743
|
+
function validateIsolatedCheckOutputs(value) {
|
|
744
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) throw new ValidationError("check outputs must be a declaration object");
|
|
745
|
+
const item = value;
|
|
746
|
+
if (Object.keys(item).some((key) => ![
|
|
747
|
+
"paths",
|
|
748
|
+
"maxFileBytes",
|
|
749
|
+
"maxTotalBytes",
|
|
750
|
+
"timeoutMs"
|
|
751
|
+
].includes(key))) throw new ValidationError("check outputs has an unknown field");
|
|
752
|
+
if (!Array.isArray(item.paths) || item.paths.length < 1 || item.paths.length > MAX_FILES) throw new ValidationError("check outputs must name between 1 and 16 files");
|
|
753
|
+
const paths = [];
|
|
754
|
+
for (const path of item.paths) {
|
|
755
|
+
if (typeof path !== "string" || path.length > 512 || !/^[A-Za-z0-9._-]+(?:\/[A-Za-z0-9._-]+)*$/u.test(path) || path.split("/").some((part) => part === "." || part === ".." || part === ".git" || part === ".sidecar") || paths.some((prior) => prior === path || prior.startsWith(`${path}/`) || path.startsWith(`${prior}/`))) throw new ValidationError("check outputs paths must be distinct portable relative files");
|
|
756
|
+
paths.push(path);
|
|
757
|
+
}
|
|
758
|
+
for (const key of ["maxFileBytes", "maxTotalBytes"]) if (typeof item[key] !== "number" || !Number.isSafeInteger(item[key]) || item[key] < 1 || item[key] > MAX_BYTES) throw new ValidationError("check output byte limits must be positive integers at most 64 MiB");
|
|
759
|
+
const maxFileBytes = item.maxFileBytes;
|
|
760
|
+
const maxTotalBytes = item.maxTotalBytes;
|
|
761
|
+
if (maxFileBytes > maxTotalBytes) throw new ValidationError("check outputs maxFileBytes must not exceed maxTotalBytes");
|
|
762
|
+
if (item.timeoutMs !== void 0 && (typeof item.timeoutMs !== "number" || !Number.isSafeInteger(item.timeoutMs) || item.timeoutMs < 1 || item.timeoutMs > MAX_TIMEOUT_MS)) throw new ValidationError("check outputs timeoutMs must be a positive integer at most 120000");
|
|
763
|
+
return Object.freeze({
|
|
764
|
+
paths: Object.freeze(paths),
|
|
765
|
+
maxFileBytes,
|
|
766
|
+
maxTotalBytes,
|
|
767
|
+
...item.timeoutMs === void 0 ? {} : { timeoutMs: item.timeoutMs }
|
|
768
|
+
});
|
|
769
|
+
}
|
|
770
|
+
/** Resolve and validate trusted ports before any isolated work starts. */
|
|
771
|
+
function prepareIsolatedCheckOutputs(options) {
|
|
772
|
+
if (options === void 0) return void 0;
|
|
773
|
+
const { executionId, artifacts, ...declaration } = options;
|
|
774
|
+
const validated = validateIsolatedCheckOutputs(declaration);
|
|
775
|
+
if (typeof executionId !== "string" || executionId.trim() === "" || executionId.length > 200 || /\p{Cc}/u.test(executionId)) throw new ValidationError("check outputs executionId must be a nonempty bounded identifier");
|
|
776
|
+
if (typeof artifacts?.put !== "function" || typeof artifacts?.read !== "function") throw new ValidationError("check outputs requires a readable output artifact port");
|
|
777
|
+
return Object.freeze({
|
|
778
|
+
...validated,
|
|
779
|
+
executionId,
|
|
780
|
+
artifacts
|
|
781
|
+
});
|
|
782
|
+
}
|
|
783
|
+
var OutputCaptureError = class extends Error {
|
|
784
|
+
reason;
|
|
785
|
+
constructor(reason) {
|
|
786
|
+
super(reason);
|
|
787
|
+
this.reason = reason;
|
|
788
|
+
}
|
|
789
|
+
};
|
|
790
|
+
/** Capture runs after command settlement, even on command failure or cancellation. There are no retries. */
|
|
791
|
+
async function retainIsolatedCheckOutputs(options, inputDigest, read) {
|
|
792
|
+
const controller = new AbortController();
|
|
793
|
+
const clearTimer = armDeadlineTimer(options.timeoutMs ?? 3e4, () => controller.abort(), true);
|
|
794
|
+
const files = [];
|
|
795
|
+
const missing = [];
|
|
796
|
+
let totalBytes = 0;
|
|
797
|
+
try {
|
|
798
|
+
for (const path of options.paths) {
|
|
799
|
+
let phase = "capture-failed";
|
|
800
|
+
try {
|
|
801
|
+
const bytes = await runAbortable(() => read(path, Math.min(options.maxFileBytes, options.maxTotalBytes - totalBytes), controller.signal), controller.signal, "output capture deadline exceeded");
|
|
802
|
+
totalBytes += bytes.byteLength;
|
|
803
|
+
phase = "store-failed";
|
|
804
|
+
const artifact = await runAbortable(() => persistCandidateOutputArtifact(options.artifacts, {
|
|
805
|
+
executionId: options.executionId,
|
|
806
|
+
purpose: "grader-evidence",
|
|
807
|
+
bytes,
|
|
808
|
+
signal: controller.signal
|
|
809
|
+
}), controller.signal, "output persistence deadline exceeded");
|
|
810
|
+
files.push({
|
|
811
|
+
path,
|
|
812
|
+
artifact
|
|
813
|
+
});
|
|
814
|
+
} catch (error) {
|
|
815
|
+
missing.push({
|
|
816
|
+
path,
|
|
817
|
+
reason: controller.signal.aborted ? "timeout" : error instanceof OutputCaptureError ? error.reason : phase
|
|
818
|
+
});
|
|
819
|
+
}
|
|
820
|
+
}
|
|
821
|
+
} finally {
|
|
822
|
+
clearTimer();
|
|
823
|
+
}
|
|
824
|
+
return Object.freeze({
|
|
825
|
+
executionId: options.executionId,
|
|
826
|
+
inputDigest,
|
|
827
|
+
status: missing.length === 0 ? "retained" : "incomplete",
|
|
828
|
+
files: Object.freeze(files.map((file) => Object.freeze(file))),
|
|
829
|
+
missing: Object.freeze(missing.map((file) => Object.freeze(file)))
|
|
830
|
+
});
|
|
831
|
+
}
|
|
832
|
+
/** The local namespace has exited; the trusted host must keep its private copy stable. */
|
|
833
|
+
function localCheckOutputReader(root) {
|
|
834
|
+
return async (path, maxBytes, signal) => {
|
|
835
|
+
try {
|
|
836
|
+
const rootInfo = await lstat(root);
|
|
837
|
+
if (!rootInfo.isDirectory() || rootInfo.isSymbolicLink()) throw new OutputCaptureError("unsafe-path");
|
|
838
|
+
let current = root;
|
|
839
|
+
const parts = path.split("/");
|
|
840
|
+
let expected;
|
|
841
|
+
for (let index = 0; index < parts.length; index++) {
|
|
842
|
+
current = join(current, parts[index]);
|
|
843
|
+
const info = await lstat(current, { bigint: true });
|
|
844
|
+
if (info.isSymbolicLink() || (index < parts.length - 1 ? !info.isDirectory() : !info.isFile() || info.nlink !== 1n)) throw new OutputCaptureError("unsafe-path");
|
|
845
|
+
expected = info;
|
|
846
|
+
}
|
|
847
|
+
signal.throwIfAborted();
|
|
848
|
+
const file = await open(current, constants.O_RDONLY | constants.O_NOFOLLOW | constants.O_NONBLOCK);
|
|
849
|
+
try {
|
|
850
|
+
const before = await file.stat({ bigint: true });
|
|
851
|
+
if (!before.isFile() || before.nlink !== 1n || before.dev !== expected?.dev || before.ino !== expected?.ino) throw new OutputCaptureError("unsafe-path");
|
|
852
|
+
if (before.size > BigInt(maxBytes)) throw new OutputCaptureError("size-limit");
|
|
853
|
+
const chunks = [];
|
|
854
|
+
let total = 0;
|
|
855
|
+
const buffer = Buffer.allocUnsafe(Math.min(65536, maxBytes + 1));
|
|
856
|
+
while (true) {
|
|
857
|
+
signal.throwIfAborted();
|
|
858
|
+
const { bytesRead } = await file.read(buffer, 0, Math.min(buffer.length, maxBytes - total + 1), null);
|
|
859
|
+
if (bytesRead === 0) break;
|
|
860
|
+
total += bytesRead;
|
|
861
|
+
if (total > maxBytes) throw new OutputCaptureError("size-limit");
|
|
862
|
+
chunks.push(Buffer.from(buffer.subarray(0, bytesRead)));
|
|
863
|
+
}
|
|
864
|
+
const after = await file.stat({ bigint: true });
|
|
865
|
+
if (before.size !== BigInt(total) || before.size !== after.size || before.mtimeNs !== after.mtimeNs || before.ctimeNs !== after.ctimeNs || after.nlink !== 1n) throw new OutputCaptureError("capture-failed");
|
|
866
|
+
return Buffer.concat(chunks, total);
|
|
867
|
+
} finally {
|
|
868
|
+
await file.close();
|
|
869
|
+
}
|
|
870
|
+
} catch (error) {
|
|
871
|
+
if (error?.code === "ENOENT") throw new OutputCaptureError("missing");
|
|
872
|
+
if (["ELOOP", "ENOTDIR"].includes(error?.code ?? "")) throw new OutputCaptureError("unsafe-path");
|
|
873
|
+
throw error;
|
|
874
|
+
}
|
|
875
|
+
};
|
|
876
|
+
}
|
|
877
|
+
/** Preserve a whole box only after its native lifecycle owner confirms stopped state. */
|
|
878
|
+
async function stopCheckBoxForRecovery(box) {
|
|
879
|
+
const controller = new AbortController();
|
|
880
|
+
const clearTimer = armDeadlineTimer(3e4, () => controller.abort(), true);
|
|
881
|
+
try {
|
|
882
|
+
await runAbortable(() => box.stop({
|
|
883
|
+
wait: true,
|
|
884
|
+
signal: controller.signal
|
|
885
|
+
}), controller.signal, "check recovery stop deadline exceeded");
|
|
886
|
+
return true;
|
|
887
|
+
} catch {
|
|
888
|
+
return false;
|
|
889
|
+
} finally {
|
|
890
|
+
clearTimer();
|
|
891
|
+
}
|
|
892
|
+
}
|
|
893
|
+
/** Whether kill and process exit were confirmed; recovery custody still needs a whole-box stop. */
|
|
894
|
+
async function stopCheckProcess(child) {
|
|
895
|
+
const controller = new AbortController();
|
|
896
|
+
const clearTimer = armDeadlineTimer(5e3, () => controller.abort(), true);
|
|
897
|
+
try {
|
|
898
|
+
await runAbortable(async () => {
|
|
899
|
+
await child.kill("SIGKILL", { tree: true });
|
|
900
|
+
await child.wait();
|
|
901
|
+
}, controller.signal, "check process stop deadline exceeded");
|
|
902
|
+
return true;
|
|
903
|
+
} catch {
|
|
904
|
+
return false;
|
|
905
|
+
} finally {
|
|
906
|
+
clearTimer();
|
|
907
|
+
}
|
|
908
|
+
}
|
|
909
|
+
const isolatedCheckOutputCaptureProgram = `import base64, errno, hashlib, json, os, stat, sys
|
|
910
|
+
fds=[]
|
|
911
|
+
def fail(reason):
|
|
912
|
+
print(json.dumps({'error':reason})); sys.exit(0)
|
|
913
|
+
try:
|
|
914
|
+
root,path,limit=sys.argv[1],sys.argv[2],int(sys.argv[3])
|
|
915
|
+
directory=os.open(root,os.O_RDONLY|os.O_DIRECTORY|os.O_NOFOLLOW); fds.append(directory)
|
|
916
|
+
parts=path.split('/')
|
|
917
|
+
for part in parts[:-1]:
|
|
918
|
+
directory=os.open(part,os.O_RDONLY|os.O_DIRECTORY|os.O_NOFOLLOW,dir_fd=directory); fds.append(directory)
|
|
919
|
+
before=os.stat(parts[-1],dir_fd=directory,follow_symlinks=False)
|
|
920
|
+
if not stat.S_ISREG(before.st_mode) or before.st_nlink!=1: fail('unsafe-path')
|
|
921
|
+
fd=os.open(parts[-1],os.O_RDONLY|os.O_NOFOLLOW|os.O_NONBLOCK,dir_fd=directory); fds.append(fd)
|
|
922
|
+
opened=os.fstat(fd)
|
|
923
|
+
if not stat.S_ISREG(opened.st_mode) or opened.st_nlink!=1 or (before.st_dev,before.st_ino)!=(opened.st_dev,opened.st_ino): fail('unsafe-path')
|
|
924
|
+
if opened.st_size>limit: fail('size-limit')
|
|
925
|
+
chunks=[]; total=0
|
|
926
|
+
while True:
|
|
927
|
+
chunk=os.read(fd,min(1048576,limit-total+1))
|
|
928
|
+
if not chunk: break
|
|
929
|
+
total+=len(chunk)
|
|
930
|
+
if total>limit: fail('size-limit')
|
|
931
|
+
chunks.append(chunk)
|
|
932
|
+
after=os.fstat(fd)
|
|
933
|
+
if (opened.st_size,opened.st_mtime_ns,opened.st_ctime_ns,opened.st_nlink)!=(after.st_size,after.st_mtime_ns,after.st_ctime_ns,after.st_nlink) or total!=opened.st_size: fail('capture-failed')
|
|
934
|
+
data=b''.join(chunks)
|
|
935
|
+
print(json.dumps({'content':base64.b64encode(data).decode('ascii'),'sha256':'sha256:'+hashlib.sha256(data).hexdigest()}))
|
|
936
|
+
except OSError as error:
|
|
937
|
+
fail('missing' if error.errno==errno.ENOENT else 'unsafe-path' if error.errno in (errno.ELOOP,errno.ENOTDIR) else 'capture-failed')
|
|
938
|
+
finally:
|
|
939
|
+
for fd in reversed(fds): os.close(fd)
|
|
940
|
+
`;
|
|
941
|
+
/** A box with declared outputs needs python3; missing capture tooling fails closed and keeps custody. */
|
|
942
|
+
function boxCheckOutputReader(box, root, timeoutMs) {
|
|
943
|
+
return async (path, maxBytes, signal) => {
|
|
944
|
+
const child = await box.process.spawnExact("/usr/bin/python3", [
|
|
945
|
+
"-I",
|
|
946
|
+
"-S",
|
|
947
|
+
"-c",
|
|
948
|
+
isolatedCheckOutputCaptureProgram,
|
|
949
|
+
root,
|
|
950
|
+
path,
|
|
951
|
+
String(maxBytes)
|
|
952
|
+
], {
|
|
953
|
+
env: {
|
|
954
|
+
PATH: "/usr/bin:/bin",
|
|
955
|
+
LANG: "C"
|
|
956
|
+
},
|
|
957
|
+
inheritEnv: false,
|
|
958
|
+
timeoutMs
|
|
959
|
+
});
|
|
960
|
+
let stopping;
|
|
961
|
+
const stop = () => {
|
|
962
|
+
stopping ??= stopCheckProcess(child);
|
|
963
|
+
};
|
|
964
|
+
signal.addEventListener("abort", stop, { once: true });
|
|
965
|
+
if (signal.aborted) stop();
|
|
966
|
+
const chunks = [];
|
|
967
|
+
const limit = Math.ceil(maxBytes / 3) * 4 + 2048;
|
|
968
|
+
let length = 0;
|
|
969
|
+
let overflow = false;
|
|
970
|
+
const collect = async (stream, keep) => {
|
|
971
|
+
for await (const text of stream) {
|
|
972
|
+
length += Buffer.byteLength(text);
|
|
973
|
+
if (length > limit) {
|
|
974
|
+
overflow = true;
|
|
975
|
+
stop();
|
|
976
|
+
} else if (keep) chunks.push(text);
|
|
977
|
+
}
|
|
978
|
+
};
|
|
979
|
+
try {
|
|
980
|
+
await Promise.all([collect(child.stdout(), true), collect(child.stderr(), false)]);
|
|
981
|
+
if (overflow || await child.wait() !== 0) throw new OutputCaptureError("capture-failed");
|
|
982
|
+
signal.throwIfAborted();
|
|
983
|
+
const value = JSON.parse(chunks.join(""));
|
|
984
|
+
if (value.error === "missing" || value.error === "unsafe-path" || value.error === "size-limit" || value.error === "capture-failed") throw new OutputCaptureError(value.error);
|
|
985
|
+
if (typeof value.content !== "string" || typeof value.sha256 !== "string") throw new OutputCaptureError("capture-failed");
|
|
986
|
+
const bytes = Buffer.from(value.content, "base64");
|
|
987
|
+
if (bytes.byteLength > maxBytes) throw new OutputCaptureError("size-limit");
|
|
988
|
+
if (sha256Bytes$1(bytes) !== value.sha256) throw new OutputCaptureError("capture-failed");
|
|
989
|
+
return bytes;
|
|
990
|
+
} catch (error) {
|
|
991
|
+
stop();
|
|
992
|
+
throw error;
|
|
993
|
+
} finally {
|
|
994
|
+
signal.removeEventListener("abort", stop);
|
|
995
|
+
await stopping;
|
|
996
|
+
}
|
|
997
|
+
};
|
|
998
|
+
}
|
|
738
999
|
// src/runtime/isolated-checker.ts
|
|
739
1000
|
const toolchains = [
|
|
740
1001
|
"/usr",
|
|
@@ -752,20 +1013,26 @@ const contains = (parent, child) => {
|
|
|
752
1013
|
*
|
|
753
1014
|
* Bubblewrap requires /usr/bin/bwrap and permission to create Linux namespaces.
|
|
754
1015
|
* Only trusted system toolchains, private proc/dev/tmp, and the writable copy are mounted.
|
|
755
|
-
* The canonical input path remains the working directory
|
|
1016
|
+
* The canonical input path remains the working directory. Requested output files are retained
|
|
1017
|
+
* before cleanup; otherwise copy writes are discarded.
|
|
756
1018
|
* Time and output are bounded; input copy bytes and entries are bounded when requested.
|
|
757
1019
|
* The command's memory and generated files require a resource-limited placement.
|
|
758
1020
|
* Callers must keep the input and trusted toolchains stable while preparing the check.
|
|
759
1021
|
*
|
|
760
1022
|
* A box check creates one fresh box with no owner secrets and blocked egress (or strict egress to
|
|
761
1023
|
* the placement's named domains), delivers the tree's regular files verified by sha256, runs the
|
|
762
|
-
* command there with only the environment `env` names, and deletes the box
|
|
1024
|
+
* command there with only the environment `env` names, and deletes the box after successful
|
|
1025
|
+
* requested retention. Incomplete retention returns private recovery custody only after the
|
|
1026
|
+
* native owner confirms the box stopped. Box file capture requires /usr/bin/python3. Local recovery scratch is the
|
|
1027
|
+
* caller's responsibility; the resource-limited placement requirement still applies.
|
|
763
1028
|
*/
|
|
764
1029
|
async function runIsolatedCheck(options) {
|
|
765
1030
|
if (options.box) return runInBox(options, options.box);
|
|
766
1031
|
let scratch;
|
|
1032
|
+
let outputs;
|
|
767
1033
|
let result;
|
|
768
1034
|
try {
|
|
1035
|
+
const retention = prepareIsolatedCheckOutputs(options.outputs);
|
|
769
1036
|
if (process.platform !== "linux") throw new Error("Linux Bubblewrap namespaces are required");
|
|
770
1037
|
const { timeoutMs, maxOutputBytes, maxInputBytes, maxInputEntries } = checkLimits(options);
|
|
771
1038
|
if (options.signal?.aborted) return {
|
|
@@ -791,6 +1058,8 @@ async function runIsolatedCheck(options) {
|
|
|
791
1058
|
if (contains(tree, scratch)) throw new Error("Temporary storage must be outside the input tree");
|
|
792
1059
|
const copy = join(scratch, "tree");
|
|
793
1060
|
await copyBoundedTree(tree, copy, maxInputBytes, maxInputEntries);
|
|
1061
|
+
const input = retention ? await scanMaterializedWorkspaceManifest(copy) : void 0;
|
|
1062
|
+
if (retention && input) assertOutputPathsUnoccupied(retention.paths, input);
|
|
794
1063
|
result = await execute([
|
|
795
1064
|
"--unshare-all",
|
|
796
1065
|
"--die-with-parent",
|
|
@@ -827,6 +1096,17 @@ async function runIsolatedCheck(options) {
|
|
|
827
1096
|
"--",
|
|
828
1097
|
...options.command
|
|
829
1098
|
], timeoutMs, maxOutputBytes, options.signal);
|
|
1099
|
+
if (retention && input && (result.succeeded || result.reason !== "refused")) {
|
|
1100
|
+
outputs = await retainIsolatedCheckOutputs(retention, canonicalCandidateDigest(input), localCheckOutputReader(copy));
|
|
1101
|
+
if (outputs.status === "incomplete") outputs = {
|
|
1102
|
+
...outputs,
|
|
1103
|
+
source: {
|
|
1104
|
+
kind: "local",
|
|
1105
|
+
path: scratch
|
|
1106
|
+
}
|
|
1107
|
+
};
|
|
1108
|
+
result = withRetainedOutputs(result, outputs);
|
|
1109
|
+
}
|
|
830
1110
|
} catch (error) {
|
|
831
1111
|
result = {
|
|
832
1112
|
succeeded: false,
|
|
@@ -834,7 +1114,7 @@ async function runIsolatedCheck(options) {
|
|
|
834
1114
|
diagnostic: String(error)
|
|
835
1115
|
};
|
|
836
1116
|
}
|
|
837
|
-
if (scratch) try {
|
|
1117
|
+
if (scratch && outputs?.status !== "incomplete") try {
|
|
838
1118
|
await removeScratch(scratch);
|
|
839
1119
|
} catch (error) {
|
|
840
1120
|
const cleanupDiagnostic = String(error);
|
|
@@ -850,7 +1130,29 @@ async function runIsolatedCheck(options) {
|
|
|
850
1130
|
cleanupDiagnostic
|
|
851
1131
|
};
|
|
852
1132
|
}
|
|
853
|
-
return
|
|
1133
|
+
return outputs ? {
|
|
1134
|
+
...result,
|
|
1135
|
+
outputs
|
|
1136
|
+
} : result;
|
|
1137
|
+
}
|
|
1138
|
+
/** A preexisting input file must never masquerade as newly produced evaluator evidence. */
|
|
1139
|
+
function assertOutputPathsUnoccupied(paths, input) {
|
|
1140
|
+
for (const path of paths) if (input.files.some((file) => file.path === path || file.path.startsWith(`${path}/`) || path.startsWith(`${file.path}/`))) throw new Error("Declared check output path overlaps an input file");
|
|
1141
|
+
}
|
|
1142
|
+
function withRetainedOutputs(result, outputs) {
|
|
1143
|
+
if (!result.succeeded || outputs.status === "retained") return {
|
|
1144
|
+
...result,
|
|
1145
|
+
outputs
|
|
1146
|
+
};
|
|
1147
|
+
return {
|
|
1148
|
+
succeeded: false,
|
|
1149
|
+
reason: "failed",
|
|
1150
|
+
diagnostic: "Check outputs were not completely retained",
|
|
1151
|
+
stdout: result.value.stdout,
|
|
1152
|
+
stderr: result.value.stderr,
|
|
1153
|
+
exitCode: 0,
|
|
1154
|
+
outputs
|
|
1155
|
+
};
|
|
854
1156
|
}
|
|
855
1157
|
function checkLimits(options) {
|
|
856
1158
|
const timeoutMs = options.timeoutMs ?? 3e4;
|
|
@@ -929,7 +1231,7 @@ async function protectedTree(options) {
|
|
|
929
1231
|
}
|
|
930
1232
|
/** Box-workspace-relative directory that receives the tree and is the command's cwd. */
|
|
931
1233
|
const BOX_TREE = "tree";
|
|
932
|
-
/**
|
|
1234
|
+
/** Setup headroom in the requested native lifetime policy; this is not a deletion guarantee. */
|
|
933
1235
|
const BOX_SETUP_SECONDS = 900;
|
|
934
1236
|
/** The box's own process timeout is a backstop behind this module's deadline. */
|
|
935
1237
|
const BOX_PROCESS_BACKSTOP_MS = 3e4;
|
|
@@ -938,9 +1240,16 @@ const BOX_EXEC_FAILURE = "process-supervisor: exec failed";
|
|
|
938
1240
|
async function runInBox(options, placement) {
|
|
939
1241
|
let box;
|
|
940
1242
|
let evidence;
|
|
1243
|
+
let outputs;
|
|
1244
|
+
let retention;
|
|
1245
|
+
let maxLifetimeSeconds;
|
|
1246
|
+
let commandAttempted = false;
|
|
1247
|
+
let commandSettled = false;
|
|
941
1248
|
let result;
|
|
942
1249
|
try {
|
|
1250
|
+
retention = prepareIsolatedCheckOutputs(options.outputs);
|
|
943
1251
|
const { timeoutMs, maxOutputBytes, maxInputBytes, maxInputEntries } = checkLimits(options);
|
|
1252
|
+
maxLifetimeSeconds = Math.ceil(timeoutMs / 1e3) + BOX_SETUP_SECONDS;
|
|
944
1253
|
if (options.signal?.aborted) return {
|
|
945
1254
|
succeeded: false,
|
|
946
1255
|
reason: "cancelled",
|
|
@@ -953,6 +1262,7 @@ async function runInBox(options, placement) {
|
|
|
953
1262
|
maxFileBytes: maxInputBytes ?? Number.MAX_SAFE_INTEGER,
|
|
954
1263
|
maxTotalFileBytes: maxInputBytes ?? Number.MAX_SAFE_INTEGER
|
|
955
1264
|
} });
|
|
1265
|
+
if (retention) assertOutputPathsUnoccupied(retention.paths, captured.manifest);
|
|
956
1266
|
if (placement.builderAccounts.length === 0 || placement.builderAccounts.some((id) => !id)) throw new Error("builderAccounts must name the account of every key the judged run holds");
|
|
957
1267
|
const memoryMB = placement.resources?.memoryMB;
|
|
958
1268
|
if (memoryMB !== void 0 && (!Number.isSafeInteger(memoryMB) || memoryMB < 1 || placement.resources?.advisory === true || placement.resources?.advisoryFields?.includes("memoryMB"))) throw new Error("Check box requires an explicit finite resources.memoryMB limit");
|
|
@@ -967,7 +1277,7 @@ async function runInBox(options, placement) {
|
|
|
967
1277
|
ephemeral: placement.containers !== true,
|
|
968
1278
|
egressPolicy: egressFor(placement),
|
|
969
1279
|
...placement.resources ? { resources: placement.resources } : {},
|
|
970
|
-
maxLifetimeSeconds
|
|
1280
|
+
maxLifetimeSeconds,
|
|
971
1281
|
idempotencyKey: `agent-runtime-check-${randomUUID()}`
|
|
972
1282
|
}, options.signal ? { signal: options.signal } : void 0);
|
|
973
1283
|
const receipt = box.createReceipt();
|
|
@@ -1000,7 +1310,10 @@ async function runInBox(options, placement) {
|
|
|
1000
1310
|
input: captured.manifest,
|
|
1001
1311
|
inputDigest: canonicalCandidateDigest(captured.manifest)
|
|
1002
1312
|
};
|
|
1003
|
-
|
|
1313
|
+
commandAttempted = true;
|
|
1314
|
+
const execution = await executeInBox(box, options.command, timeoutMs, maxOutputBytes, options.env ?? {}, options.signal);
|
|
1315
|
+
result = execution.result;
|
|
1316
|
+
commandSettled = execution.commandSettled;
|
|
1004
1317
|
} catch (error) {
|
|
1005
1318
|
result = {
|
|
1006
1319
|
succeeded: false,
|
|
@@ -1008,7 +1321,34 @@ async function runInBox(options, placement) {
|
|
|
1008
1321
|
diagnostic: String(error)
|
|
1009
1322
|
};
|
|
1010
1323
|
}
|
|
1011
|
-
if (box)
|
|
1324
|
+
if (box && evidence && retention && maxLifetimeSeconds !== void 0 && commandAttempted && (!commandSettled || result.succeeded || result.reason !== "refused")) {
|
|
1325
|
+
outputs = commandSettled ? await retainIsolatedCheckOutputs(retention, evidence.inputDigest, boxCheckOutputReader(box, BOX_TREE, retention.timeoutMs ?? 3e4)) : {
|
|
1326
|
+
executionId: retention.executionId,
|
|
1327
|
+
inputDigest: evidence.inputDigest,
|
|
1328
|
+
status: "incomplete",
|
|
1329
|
+
files: [],
|
|
1330
|
+
missing: retention.paths.map((path) => ({
|
|
1331
|
+
path,
|
|
1332
|
+
reason: "capture-failed"
|
|
1333
|
+
}))
|
|
1334
|
+
};
|
|
1335
|
+
result = withRetainedOutputs(result, outputs);
|
|
1336
|
+
if (outputs.status === "incomplete") {
|
|
1337
|
+
if (await stopCheckBoxForRecovery(box)) outputs = {
|
|
1338
|
+
...outputs,
|
|
1339
|
+
source: {
|
|
1340
|
+
kind: "sandbox",
|
|
1341
|
+
sandboxId: box.id,
|
|
1342
|
+
state: "stopped"
|
|
1343
|
+
}
|
|
1344
|
+
};
|
|
1345
|
+
else if (!result.succeeded) result = {
|
|
1346
|
+
...result,
|
|
1347
|
+
cleanupDiagnostic: "Recovery source stop was not confirmed; box deletion was requested"
|
|
1348
|
+
};
|
|
1349
|
+
}
|
|
1350
|
+
}
|
|
1351
|
+
if (box && outputs?.source?.kind !== "sandbox") try {
|
|
1012
1352
|
await box.delete();
|
|
1013
1353
|
} catch (error) {
|
|
1014
1354
|
const cleanupDiagnostic = `Check box ${box.id} was not deleted: ${String(error)}`;
|
|
@@ -1021,13 +1361,14 @@ async function runInBox(options, placement) {
|
|
|
1021
1361
|
exitCode: 0
|
|
1022
1362
|
} : {
|
|
1023
1363
|
...result,
|
|
1024
|
-
cleanupDiagnostic
|
|
1364
|
+
cleanupDiagnostic: [result.cleanupDiagnostic, cleanupDiagnostic].filter(Boolean).join("; ")
|
|
1025
1365
|
};
|
|
1026
1366
|
}
|
|
1027
|
-
return
|
|
1367
|
+
return {
|
|
1028
1368
|
...result,
|
|
1029
|
-
box: evidence
|
|
1030
|
-
|
|
1369
|
+
...evidence ? { box: evidence } : {},
|
|
1370
|
+
...outputs ? { outputs } : {}
|
|
1371
|
+
};
|
|
1031
1372
|
}
|
|
1032
1373
|
/** Refuse unless the box reads each file with its manifest digest. `find` names the files: a box
|
|
1033
1374
|
* process takes 256 arguments at most. A name holding a newline or backslash, which coreutils
|
|
@@ -1067,25 +1408,18 @@ function egressFor(placement) {
|
|
|
1067
1408
|
}
|
|
1068
1409
|
async function executeInBox(box, command, timeoutMs, limit, env, signal) {
|
|
1069
1410
|
const [executable, ...args] = command;
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
env: {
|
|
1073
|
-
PATH: "/usr/bin:/bin",
|
|
1074
|
-
HOME: "/tmp",
|
|
1075
|
-
LANG: "C",
|
|
1076
|
-
...env
|
|
1077
|
-
},
|
|
1078
|
-
inheritEnv: false,
|
|
1079
|
-
timeoutMs: timeoutMs + BOX_PROCESS_BACKSTOP_MS
|
|
1080
|
-
});
|
|
1411
|
+
let child;
|
|
1412
|
+
const deadline = new AbortController();
|
|
1081
1413
|
const stdout = [];
|
|
1082
1414
|
const stderr = [];
|
|
1083
1415
|
let bytes = 0;
|
|
1084
1416
|
let failure;
|
|
1085
1417
|
let stopping;
|
|
1418
|
+
let stopped = false;
|
|
1086
1419
|
const stop = (reason) => {
|
|
1087
1420
|
failure ??= reason;
|
|
1088
|
-
|
|
1421
|
+
deadline.abort();
|
|
1422
|
+
if (child) stopping ??= stopCheckProcess(child);
|
|
1089
1423
|
};
|
|
1090
1424
|
const clearTimer = armDeadlineTimer(timeoutMs, () => stop("timeout"), true);
|
|
1091
1425
|
const cancel = () => stop("cancelled");
|
|
@@ -1093,6 +1427,7 @@ async function executeInBox(box, command, timeoutMs, limit, env, signal) {
|
|
|
1093
1427
|
if (signal?.aborted) cancel();
|
|
1094
1428
|
const capture = async (stream, target) => {
|
|
1095
1429
|
for await (const text of stream) {
|
|
1430
|
+
if (deadline.signal.aborted) break;
|
|
1096
1431
|
const chunk = Buffer.from(text);
|
|
1097
1432
|
const remaining = Math.max(0, limit - bytes);
|
|
1098
1433
|
bytes += chunk.length;
|
|
@@ -1100,55 +1435,85 @@ async function executeInBox(box, command, timeoutMs, limit, env, signal) {
|
|
|
1100
1435
|
if (bytes > limit) stop("output-limit");
|
|
1101
1436
|
}
|
|
1102
1437
|
};
|
|
1103
|
-
let
|
|
1104
|
-
let exitSignal;
|
|
1438
|
+
let completion;
|
|
1105
1439
|
try {
|
|
1106
|
-
await
|
|
1107
|
-
|
|
1108
|
-
|
|
1440
|
+
child = await runAbortable(() => {
|
|
1441
|
+
const launching = box.process.spawnExact(executable, args, {
|
|
1442
|
+
cwd: BOX_TREE,
|
|
1443
|
+
env: {
|
|
1444
|
+
PATH: "/usr/bin:/bin",
|
|
1445
|
+
HOME: "/tmp",
|
|
1446
|
+
LANG: "C",
|
|
1447
|
+
...env
|
|
1448
|
+
},
|
|
1449
|
+
inheritEnv: false,
|
|
1450
|
+
timeoutMs: timeoutMs + BOX_PROCESS_BACKSTOP_MS
|
|
1451
|
+
});
|
|
1452
|
+
launching.then((late) => {
|
|
1453
|
+
if (deadline.signal.aborted) stopCheckProcess(late);
|
|
1454
|
+
}, () => void 0);
|
|
1455
|
+
return launching;
|
|
1456
|
+
}, deadline.signal, "Check interrupted");
|
|
1457
|
+
const running = child;
|
|
1458
|
+
completion = await runAbortable(async () => {
|
|
1459
|
+
await Promise.all([capture(running.stdout(), stdout), capture(running.stderr(), stderr)]);
|
|
1460
|
+
return {
|
|
1461
|
+
exitCode: await running.wait(),
|
|
1462
|
+
exitSignal: (await running.status()).exitSignal
|
|
1463
|
+
};
|
|
1464
|
+
}, deadline.signal, "Check interrupted");
|
|
1465
|
+
} catch (error) {
|
|
1466
|
+
if (child) stopping ??= stopCheckProcess(child);
|
|
1467
|
+
if (!failure) throw error;
|
|
1109
1468
|
} finally {
|
|
1110
1469
|
clearTimer();
|
|
1111
1470
|
signal?.removeEventListener("abort", cancel);
|
|
1112
|
-
await stopping;
|
|
1471
|
+
stopped = await stopping === true;
|
|
1113
1472
|
}
|
|
1114
1473
|
const out = Buffer.concat(stdout).toString();
|
|
1115
1474
|
const err = Buffer.concat(stderr).toString();
|
|
1475
|
+
const exitCode = completion?.exitCode ?? null;
|
|
1476
|
+
const exitSignal = completion?.exitSignal;
|
|
1116
1477
|
const evidence = {
|
|
1117
1478
|
stdout: out,
|
|
1118
1479
|
stderr: err,
|
|
1119
1480
|
exitCode: exitSignal ? null : exitCode
|
|
1120
1481
|
};
|
|
1121
|
-
|
|
1482
|
+
const finish = (result) => ({
|
|
1483
|
+
result,
|
|
1484
|
+
commandSettled: completion !== void 0 || stopped
|
|
1485
|
+
});
|
|
1486
|
+
if (failure) return finish({
|
|
1122
1487
|
succeeded: false,
|
|
1123
1488
|
reason: failure,
|
|
1124
1489
|
diagnostic: err || failure,
|
|
1125
1490
|
...evidence
|
|
1126
|
-
};
|
|
1127
|
-
if (exitCode === 127 && err.startsWith(BOX_EXEC_FAILURE)) return {
|
|
1491
|
+
});
|
|
1492
|
+
if (exitCode === 127 && err.startsWith(BOX_EXEC_FAILURE)) return finish({
|
|
1128
1493
|
succeeded: false,
|
|
1129
1494
|
reason: "refused",
|
|
1130
1495
|
diagnostic: err,
|
|
1131
1496
|
...evidence
|
|
1132
|
-
};
|
|
1133
|
-
if (exitSignal) return {
|
|
1497
|
+
});
|
|
1498
|
+
if (exitSignal) return finish({
|
|
1134
1499
|
succeeded: false,
|
|
1135
1500
|
reason: "failed",
|
|
1136
1501
|
diagnostic: err || `Check killed by ${exitSignal}`,
|
|
1137
1502
|
...evidence
|
|
1138
|
-
};
|
|
1139
|
-
if (exitCode !== 0) return {
|
|
1503
|
+
});
|
|
1504
|
+
if (exitCode !== 0) return finish({
|
|
1140
1505
|
succeeded: false,
|
|
1141
1506
|
reason: "failed",
|
|
1142
1507
|
diagnostic: err || out || `Check exited ${exitCode}`,
|
|
1143
1508
|
...evidence
|
|
1144
|
-
};
|
|
1145
|
-
return {
|
|
1509
|
+
});
|
|
1510
|
+
return finish({
|
|
1146
1511
|
succeeded: true,
|
|
1147
1512
|
value: {
|
|
1148
1513
|
stdout: out,
|
|
1149
1514
|
stderr: err
|
|
1150
1515
|
}
|
|
1151
|
-
};
|
|
1516
|
+
});
|
|
1152
1517
|
}
|
|
1153
1518
|
function execute(args, timeoutMs, limit, signal) {
|
|
1154
1519
|
return new Promise((done) => {
|
|
@@ -10097,6 +10462,6 @@ async function runInWorkspace(ws, body, opts = {}) {
|
|
|
10097
10462
|
function tail(s) {
|
|
10098
10463
|
return s.slice(-400);
|
|
10099
10464
|
}
|
|
10100
|
-
export { runBenchmark as $,
|
|
10465
|
+
export { runBenchmark as $, pairwiseSignificance as $t, searchPresets as A, sanitizeMcpToolSchema as At, graphFromSessionFacts as B, assertDeclaredCheck as Bt, withUntrackedArtifacts as C, harvestCorpus as Ct, SEARCH_SPEC_CORRELATION_KEY as D, connectStdioMcp as Dt, createFencedSqlRunContext as E, McpSpawnFault as Et, loadProfile as F, secretEnvOfMcpServer as Ft, chatWorkerSeam as G, readDeclaredCheck as Gt, loadGraphFile as H, declaredCheckDeliverable as Ht, pickBestProfile as I, inlineSandboxClient as It, strategyTournament as J, completionAuthorizes as Jt, createChatSessionStore as K, runIsolatedCheck as Kt, profileRegistry as L, loopCampaignDispatch as Lt, connectRemoteSupervisor as M, mcpSecretEnvMetadataKey as Mt, connectRemoteSupervisorControl as N, resolveMcpServerLaunch as Nt, assertSearchSpec as O, materializeLocalMcp as Ot, bestProfileFor as P, resolveSecretEnv as Pt, printBenchmarkReport as Q, leaderboard as Qt, profileRunsForName as R, loopDispatch as Rt, copyUntrackedIntoClone as S, HarvestError as St, validateStoredGraph as T, resolveSandboxClient as Tt, graphDesignerExtraTools as U, declaredCheckDigest as Ut, GraphFileResolutionError as V, checkProgramDigest as Vt, chatTransportExecutor as W, declaredCheckJudge as Wt, openSandboxRun as X, sentinelCompletion as Xt, SandboxRunAbortError as Y, deterministicCompletion as Yt, createS3PrivateCasStore as Z, stopSentinel as Zt, NOTE_MAX_CHARS as _, buildSteerContext as _t, localShell as a, openSqlRunStore as an, FileCorpus as at, composeWorkerEvidence as b, observationFromRegistry as bt, createVerifierEnvironment as c, fanout as ct, harvestSurfaceDiffs as d, panel as dt, renderLeaderboardHtml as en, createPrivateCasArtifactPort as et, analystsFromRegistry as f, pipeline as ft, EVIDENCE_MAX_CHARS as g, assertTraceDerivedFindings as gt, runCoderChecks as h, widen as ht, jjWorkspace as i, SqlRunOwnershipError as in, runPersonified as it, searchSpecDigest as j, envKeyProvider as jt, compileSearchSpec as k, createMcpEnvironment as kt, boxSurfaceReader as l, flatWidenGate as lt, worktreeFanout as m, verify as mt, makeFinding$1 as n, renderLeaderboardSvg as nn, trajectoryReport as nt, runInWorkspace as o, InMemoryCorpus as ot, failuresAnalyst as p, selectValidWinner as pt, runStrategyEvolution as q, validateIsolatedCheckOutputs as qt, gitWorkspace as r, renderPairwiseMarkdown as rn, definePersona as rt, createWaterfallCollector as s, renderCorpusToInstructions as st, computeFindingId$1 as t, renderLeaderboardMarkdown as tn, equalKOnCost as tt, fsSurfaceReader as u, loopUntil as ut, VERIFY_TAIL_CHARS as v, createScopeAnalyst as vt, analyzeTrace as w, defineLeaderboard as wt, settledWorkerOut as x, inProcessSandboxClient as xt, closingWorkerNote as y, registryScopeAnalyst as yt, recordProfileRun as z, superviseDispatch as zt };
|
|
10101
10466
|
|
|
10102
|
-
//# sourceMappingURL=runtime-
|
|
10467
|
+
//# sourceMappingURL=runtime-CBt8PWn5.js.map
|