engineering-behavior-observatory 0.2.3 → 0.2.4
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/src/artifacts.d.ts +2 -2
- package/dist/src/artifacts.js +25 -7
- package/dist/src/run-bundles.js +43 -13
- package/docs/guides/evidence-and-sharing.md +9 -0
- package/package.json +2 -1
- package/release/0.2.4/KNOWN_LIMITATIONS.md +16 -0
- package/release/0.2.4/README.md +23 -0
- package/release/0.2.4/reproducibility.json +74 -0
- package/release/README.md +1 -0
package/dist/src/artifacts.d.ts
CHANGED
|
@@ -20,14 +20,14 @@ export declare function validateArtifact(artifact: string, document: unknown): A
|
|
|
20
20
|
export declare function validateRunManifestEvidence(artifact: string, manifest: unknown, bundleRoot: string): ArtifactValidationError[];
|
|
21
21
|
export declare function validateExportManifest(artifact: string, exportManifest: unknown, containingManifest: unknown | undefined, bundleRoot?: string): ArtifactValidationError[];
|
|
22
22
|
export declare function readVerifiedArtifact(artifactRoot: string, relativePath: string, expectedDigest: Digest, maxBytes?: number): Promise<Buffer>;
|
|
23
|
-
export declare function inspectRetainedArtifact(artifactRoot: string, relativePath: string): Promise<{
|
|
23
|
+
export declare function inspectRetainedArtifact(artifactRoot: string, relativePath: string, maxBytes?: number): Promise<{
|
|
24
24
|
digest: Digest;
|
|
25
25
|
sizeBytes: number;
|
|
26
26
|
}>;
|
|
27
27
|
export declare function writeMetadataAtomically(artifactRoot: string, relativePath: string, metadata: unknown, signal?: AbortSignal, options?: {
|
|
28
28
|
overwrite?: boolean;
|
|
29
29
|
}): Promise<Digest>;
|
|
30
|
-
export declare function writeArtifactAtomically(artifactRoot: string, relativePath: string, content: Uint8Array
|
|
30
|
+
export declare function writeArtifactAtomically(artifactRoot: string, relativePath: string, content: Uint8Array | AsyncIterable<Uint8Array>, signal?: AbortSignal, options?: {
|
|
31
31
|
overwrite?: boolean;
|
|
32
32
|
}): Promise<Digest>;
|
|
33
33
|
export declare function writeMetadataAtomicallyIfAbsentSync(artifactRoot: string, relativePath: string, metadata: unknown, rootHandle?: BundleRootHandle, beforeDestinationPublish?: () => void, afterDestinationPublish?: () => void): {
|
package/dist/src/artifacts.js
CHANGED
|
@@ -852,22 +852,35 @@ export async function readVerifiedArtifact(artifactRoot, relativePath, expectedD
|
|
|
852
852
|
await handle.close();
|
|
853
853
|
}
|
|
854
854
|
}
|
|
855
|
-
export async function inspectRetainedArtifact(artifactRoot, relativePath) {
|
|
855
|
+
export async function inspectRetainedArtifact(artifactRoot, relativePath, maxBytes) {
|
|
856
|
+
if (maxBytes !== undefined && (!Number.isSafeInteger(maxBytes) || maxBytes < 0)) {
|
|
857
|
+
throw new Error("Artifact byte limit must be a nonnegative safe integer.");
|
|
858
|
+
}
|
|
856
859
|
const { path } = await resolveExistingArtifactPath(artifactRoot, relativePath);
|
|
857
|
-
return inspectExistingPath(path, relativePath);
|
|
860
|
+
return inspectExistingPath(path, relativePath, maxBytes);
|
|
858
861
|
}
|
|
859
862
|
export async function writeMetadataAtomically(artifactRoot, relativePath, metadata, signal, options = {}) {
|
|
860
863
|
const bytes = Buffer.from(canonicalizeMetadata(metadata));
|
|
861
864
|
return writeArtifactAtomically(artifactRoot, relativePath, bytes, signal, options);
|
|
862
865
|
}
|
|
863
866
|
export async function writeArtifactAtomically(artifactRoot, relativePath, content, signal, options = {}) {
|
|
864
|
-
const
|
|
867
|
+
const source = content instanceof Uint8Array ? [Buffer.from(content)] : content;
|
|
868
|
+
const hash = createHash("sha256");
|
|
869
|
+
async function* chunks() {
|
|
870
|
+
for await (const chunk of source) {
|
|
871
|
+
if (signal?.aborted)
|
|
872
|
+
throw new Error("Artifact metadata write interrupted.");
|
|
873
|
+
const bytes = Buffer.from(chunk);
|
|
874
|
+
hash.update(bytes);
|
|
875
|
+
yield bytes;
|
|
876
|
+
}
|
|
877
|
+
}
|
|
865
878
|
const { parent, path } = await prepareArtifactPath(artifactRoot, relativePath);
|
|
866
879
|
const temporaryPath = resolve(parent, `.${randomUUID()}.tmp`);
|
|
867
880
|
let handle;
|
|
868
881
|
try {
|
|
869
882
|
handle = await open(temporaryPath, "wx", 0o600);
|
|
870
|
-
await handle.writeFile(
|
|
883
|
+
await handle.writeFile(chunks());
|
|
871
884
|
await handle.sync();
|
|
872
885
|
await handle.close();
|
|
873
886
|
handle = undefined;
|
|
@@ -894,8 +907,10 @@ export async function writeArtifactAtomically(artifactRoot, relativePath, conten
|
|
|
894
907
|
await handle?.close();
|
|
895
908
|
await rm(temporaryPath, { force: true });
|
|
896
909
|
}
|
|
897
|
-
const digest =
|
|
898
|
-
await
|
|
910
|
+
const digest = { algorithm: "sha256", value: hash.digest("hex") };
|
|
911
|
+
const inspected = await inspectRetainedArtifact(artifactRoot, relativePath);
|
|
912
|
+
if (inspected.digest.value !== digest.value)
|
|
913
|
+
throw new Error(`Artifact "${relativePath}" digest does not match its source reference.`);
|
|
899
914
|
return digest;
|
|
900
915
|
}
|
|
901
916
|
export function writeMetadataAtomicallyIfAbsentSync(artifactRoot, relativePath, metadata, rootHandle, beforeDestinationPublish, afterDestinationPublish) {
|
|
@@ -1270,7 +1285,7 @@ function prepareArtifactPathSync(artifactRoot, relativePath) {
|
|
|
1270
1285
|
function digestExistingPath(path, relativePath) {
|
|
1271
1286
|
return inspectExistingPath(path, relativePath).digest;
|
|
1272
1287
|
}
|
|
1273
|
-
function inspectExistingPath(path, relativePath) {
|
|
1288
|
+
function inspectExistingPath(path, relativePath, maxBytes) {
|
|
1274
1289
|
const descriptor = openSync(path, constants.O_RDONLY | constants.O_NOFOLLOW | constants.O_NONBLOCK);
|
|
1275
1290
|
try {
|
|
1276
1291
|
let opened = fstatSync(descriptor);
|
|
@@ -1283,6 +1298,9 @@ function inspectExistingPath(path, relativePath) {
|
|
|
1283
1298
|
|| !Number.isSafeInteger(opened.size) || opened.size < 0) {
|
|
1284
1299
|
throw new Error(`Artifact path "${relativePath}" is not an isolated regular file.`);
|
|
1285
1300
|
}
|
|
1301
|
+
if (maxBytes !== undefined && opened.size > maxBytes) {
|
|
1302
|
+
throw new Error(`Artifact "${relativePath}" exceeds the qualification byte limit of ${maxBytes}.`);
|
|
1303
|
+
}
|
|
1286
1304
|
const hash = createHash("sha256");
|
|
1287
1305
|
const chunk = Buffer.allocUnsafe(64 * 1024);
|
|
1288
1306
|
for (let offset = 0; offset < opened.size;) {
|
package/dist/src/run-bundles.js
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import { execFile, spawn } from "node:child_process";
|
|
2
2
|
import { randomUUID } from "node:crypto";
|
|
3
|
+
import { createReadStream, createWriteStream } from "node:fs";
|
|
3
4
|
import { cp, lstat, mkdir, mkdtemp, readdir, rm, rmdir, utimes, writeFile } from "node:fs/promises";
|
|
4
5
|
import { tmpdir } from "node:os";
|
|
5
6
|
import { join, resolve, sep } from "node:path";
|
|
6
7
|
import { promisify } from "node:util";
|
|
8
|
+
import { Transform } from "node:stream";
|
|
9
|
+
import { pipeline } from "node:stream/promises";
|
|
7
10
|
import { HOOK_EVENTS } from "@anthropic-ai/claude-agent-sdk";
|
|
8
11
|
import { assertNoDuplicateJsonKeys, assertUniqueArtifactIdentities, canonicalizeMetadata, inspectRetainedArtifact, readVerifiedArtifact, validateArtifact, validateExportManifest, validateRunManifestEvidence, writeArtifactAtomically, writeMetadataAtomically, } from "./artifacts.js";
|
|
9
12
|
import { isSafeArtifactRelativePath } from "./contracts.js";
|
|
@@ -11,7 +14,7 @@ import { digestWorkspace, digestWorkspaceTree } from "./verifiers.js";
|
|
|
11
14
|
import { readBoundedFile } from "./scheduler.js";
|
|
12
15
|
const execFileAsync = promisify(execFile);
|
|
13
16
|
const MAX_WORKSPACE_PATCH_BYTES = 64 * 1024 * 1024;
|
|
14
|
-
const MAX_WORKSPACE_SNAPSHOT_BYTES =
|
|
17
|
+
const MAX_WORKSPACE_SNAPSHOT_BYTES = 1024 * 1024 * 1024;
|
|
15
18
|
const MAX_QUALIFICATION_ARTIFACT_BYTES = 64 * 1024 * 1024;
|
|
16
19
|
const QUALIFICATION_DIMENSION_RANK = { qualified: 0, unsupported: 1, gap: 2, unqualified: 3 };
|
|
17
20
|
const PINNED_HOOK_EVENTS = new Set(HOOK_EVENTS);
|
|
@@ -151,11 +154,17 @@ export class RunBundleAssembler {
|
|
|
151
154
|
throw new Error("Final workspace metadata changed while its outcome was being captured.");
|
|
152
155
|
}
|
|
153
156
|
const format = patch === undefined ? "snapshot" : "patch";
|
|
154
|
-
const content = patch ?? await workspaceSnapshot(capturedPath, treeDigest);
|
|
155
157
|
const relativePath = format === "patch"
|
|
156
158
|
? options.relativePath ?? "workspace.patch"
|
|
157
159
|
: options.snapshotRelativePath ?? "workspace.tar.gz";
|
|
158
|
-
|
|
160
|
+
if (patch !== undefined) {
|
|
161
|
+
await writeArtifactAtomically(this.bundleRoot, relativePath, patch, undefined, { overwrite: false });
|
|
162
|
+
}
|
|
163
|
+
else {
|
|
164
|
+
await workspaceSnapshot(capturedPath, treeDigest, async (snapshotPath) => {
|
|
165
|
+
await writeArtifactAtomically(this.bundleRoot, relativePath, createReadStream(snapshotPath), undefined, { overwrite: false });
|
|
166
|
+
});
|
|
167
|
+
}
|
|
159
168
|
const descriptor = await this.registerArtifact({
|
|
160
169
|
id: options.id ?? "workspace",
|
|
161
170
|
source: options.source ?? `workspace-${format}`,
|
|
@@ -312,9 +321,15 @@ export async function qualifyRunBundle(bundleRoot, options = {}) {
|
|
|
312
321
|
const state = { descriptor, valid: true };
|
|
313
322
|
states.set(descriptor.id, state);
|
|
314
323
|
try {
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
324
|
+
if (descriptor.kind === "workspace" && descriptor.mediaType === "application/gzip") {
|
|
325
|
+
// Opaque snapshots need streaming integrity checks, not a whole-archive buffer.
|
|
326
|
+
const inspected = await inspectRetainedArtifact(bundleRoot, descriptor.relativePath, MAX_WORKSPACE_SNAPSHOT_BYTES);
|
|
327
|
+
if (inspected.sizeBytes !== descriptor.sizeBytes || digestString(inspected.digest.value) !== descriptor.digest) {
|
|
328
|
+
throw new Error("Workspace snapshot size or digest does not match its descriptor.");
|
|
329
|
+
}
|
|
330
|
+
continue;
|
|
331
|
+
}
|
|
332
|
+
const bytes = await readVerifiedArtifact(bundleRoot, descriptor.relativePath, digestValue(descriptor.digest), MAX_QUALIFICATION_ARTIFACT_BYTES);
|
|
318
333
|
if (descriptor.mediaType === "application/x-ndjson") {
|
|
319
334
|
const summary = parseNativeJsonl(bytes);
|
|
320
335
|
state.hookNames = summary.hookNames;
|
|
@@ -966,7 +981,7 @@ async function workspacePatch(startPath, finalPath, finalTreeDigest) {
|
|
|
966
981
|
await rm(temporaryRoot, { recursive: true, force: true });
|
|
967
982
|
}
|
|
968
983
|
}
|
|
969
|
-
async function workspaceSnapshot(finalPath, finalTreeDigest) {
|
|
984
|
+
async function workspaceSnapshot(finalPath, finalTreeDigest, use) {
|
|
970
985
|
const temporaryRoot = await mkdtemp(join(tmpdir(), "ebo-workspace-snapshot-"));
|
|
971
986
|
const snapshotPath = join(temporaryRoot, "workspace.tar.gz");
|
|
972
987
|
const snapshotParent = join(temporaryRoot, "source");
|
|
@@ -975,18 +990,33 @@ async function workspaceSnapshot(finalPath, finalTreeDigest) {
|
|
|
975
990
|
try {
|
|
976
991
|
await mkdir(snapshotParent);
|
|
977
992
|
await cp(finalPath, snapshotRoot, { recursive: true, preserveTimestamps: true, force: false });
|
|
978
|
-
const
|
|
979
|
-
|
|
980
|
-
|
|
993
|
+
const child = spawn(TAR_COMMAND, ["-czf", "-", "-C", snapshotParent, "workspace"], { stdio: ["ignore", "pipe", "pipe"] });
|
|
994
|
+
let stderr = "";
|
|
995
|
+
child.stderr.on("data", (chunk) => { stderr = (stderr + chunk.toString("utf8")).slice(-8192); });
|
|
996
|
+
const exited = new Promise((resolveExit, reject) => {
|
|
997
|
+
child.once("error", reject);
|
|
998
|
+
child.once("close", (code) => code === 0 ? resolveExit() : reject(new Error(`Workspace snapshot tar failed (${code}): ${stderr.trim()}`)));
|
|
981
999
|
});
|
|
982
|
-
|
|
983
|
-
|
|
1000
|
+
let size = 0;
|
|
1001
|
+
const limit = new Transform({ transform(chunk, _encoding, callback) {
|
|
1002
|
+
size += chunk.length;
|
|
1003
|
+
callback(size > MAX_WORKSPACE_SNAPSHOT_BYTES ? new Error("Workspace snapshot exceeds the 1 GiB compressed byte limit.") : null, chunk);
|
|
1004
|
+
} });
|
|
1005
|
+
const streamed = pipeline(child.stdout, limit, createWriteStream(snapshotPath, { flags: "wx", mode: 0o600 }));
|
|
1006
|
+
try {
|
|
1007
|
+
await Promise.all([exited, streamed]);
|
|
1008
|
+
}
|
|
1009
|
+
finally {
|
|
1010
|
+
if (child.exitCode === null)
|
|
1011
|
+
child.kill("SIGKILL");
|
|
1012
|
+
await Promise.allSettled([exited, streamed]);
|
|
1013
|
+
}
|
|
984
1014
|
await mkdir(extracted, { mode: 0o700 });
|
|
985
1015
|
await execFileAsync(TAR_COMMAND, ["-xzpf", snapshotPath, "-C", extracted]);
|
|
986
1016
|
if (await digestWorkspaceTree(join(extracted, "workspace")) !== finalTreeDigest) {
|
|
987
1017
|
throw new Error("Bounded workspace snapshot cannot reproduce the final workspace tree.");
|
|
988
1018
|
}
|
|
989
|
-
|
|
1019
|
+
await use(snapshotPath);
|
|
990
1020
|
}
|
|
991
1021
|
finally {
|
|
992
1022
|
await rm(temporaryRoot, { recursive: true, force: true });
|
|
@@ -46,6 +46,15 @@ missing-evidence entries. Inspect the detail before retrying capture against a
|
|
|
46
46
|
retained workspace. A later successful capture is recovery evidence; it does
|
|
47
47
|
not change the original attempt's recorded failure.
|
|
48
48
|
|
|
49
|
+
Workspace capture tries a patch up to 64 MiB, then falls back to a snapshot
|
|
50
|
+
when the patch is too large or cannot reproduce the tree. Snapshots stream to
|
|
51
|
+
disk with a 1 GiB compressed limit and are extracted to verify the tree digest
|
|
52
|
+
before publication. Snapshot qualification also checks integrity without loading
|
|
53
|
+
the archive into memory. Exceeding the limit leaves explicit missing evidence
|
|
54
|
+
and retains the workspace; it never truncates the archive. These capture limits
|
|
55
|
+
are separate from portable-export limits. Configure known cache-directory
|
|
56
|
+
exclusions before a study rather than dropping files from an existing attempt.
|
|
57
|
+
|
|
49
58
|
Use a new output destination for derived records and reruns. Do not edit a
|
|
50
59
|
native bundle to make a validator accept it.
|
|
51
60
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "engineering-behavior-observatory",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.4",
|
|
4
4
|
"description": "Capture engineering-agent trajectories, evaluate behavior, and inspect cited evidence across harnesses.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -47,6 +47,7 @@
|
|
|
47
47
|
"release/0.2.1/",
|
|
48
48
|
"release/0.2.2/",
|
|
49
49
|
"release/0.2.3/",
|
|
50
|
+
"release/0.2.4/",
|
|
50
51
|
"schemas/",
|
|
51
52
|
"scripts/atlas-grafana.sh"
|
|
52
53
|
],
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# v0.2.4 known limitations
|
|
2
|
+
|
|
3
|
+
The [v0.2.3 limitations](../0.2.3/KNOWN_LIMITATIONS.md) continue to apply.
|
|
4
|
+
|
|
5
|
+
- Snapshots remain bounded to 1 GiB compressed. Temporary source and extracted
|
|
6
|
+
copies also require free disk space; large cache trees increase capture time.
|
|
7
|
+
- Known cache exclusions must be declared before a study. Capture does not
|
|
8
|
+
silently omit additional files to fit a limit.
|
|
9
|
+
- Opaque snapshots remain restricted evidence; larger capture support does
|
|
10
|
+
not make them portable sanitized exports.
|
|
11
|
+
- Full-parallel testing exposed intermittent interruption/cleanup failures.
|
|
12
|
+
Release acceptance runs tests serially, as in earlier releases.
|
|
13
|
+
- npm audit reports three dependency findings (two moderate, one high) through
|
|
14
|
+
the pinned Cursor SDK's connect-node/undici dependency chain. npm reports no
|
|
15
|
+
available automatic fix for this dependency graph. This patch leaves those
|
|
16
|
+
dependencies unchanged; passing acceptance is not a clean security audit.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# v0.2.4: Stream large workspace snapshots
|
|
2
|
+
|
|
3
|
+
Workspace snapshot capture no longer buffers the compressed archive in child
|
|
4
|
+
process stdout. Archives stream to disk, pass extraction and tree-digest checks,
|
|
5
|
+
and publish atomically. Qualification verifies snapshot integrity in chunks.
|
|
6
|
+
|
|
7
|
+
The compressed snapshot limit increases from 128 MiB to 1 GiB. Output above
|
|
8
|
+
that limit fails explicitly and retains partial evidence. The 64 MiB patch
|
|
9
|
+
limit, capture exclusions, archive format, and portable-export policy are
|
|
10
|
+
unchanged. No runtime pins or dependencies change.
|
|
11
|
+
|
|
12
|
+
## Verification
|
|
13
|
+
|
|
14
|
+
Regression tests cover a 129 MiB incompressible snapshot, streamed-write failure
|
|
15
|
+
cleanup, no-clobber publication, and bounded integrity checks. A retained real
|
|
16
|
+
workspace that failed on v0.2.3 was captured separately as a 605,143,040-byte
|
|
17
|
+
snapshot, with its extracted tree digest verified. Original evidence was not
|
|
18
|
+
rewritten.
|
|
19
|
+
|
|
20
|
+
Run `npm ci` and `npm run acceptance` on Node 24.19.0 for the full suite,
|
|
21
|
+
documentation and package checks, and two byte-identical package builds.
|
|
22
|
+
See [known limitations](KNOWN_LIMITATIONS.md) and the
|
|
23
|
+
[reproducibility manifest](reproducibility.json).
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": "ebo.release-reproducibility/v1",
|
|
3
|
+
"release": {
|
|
4
|
+
"name": "engineering-behavior-observatory",
|
|
5
|
+
"version": "0.2.4"
|
|
6
|
+
},
|
|
7
|
+
"runtime": {
|
|
8
|
+
"node": "24.19.0",
|
|
9
|
+
"claudeAgentSdk": "0.3.258",
|
|
10
|
+
"openhandsAgentServer": "1.46.0",
|
|
11
|
+
"deepseekClient": "0.1.1-rc.2",
|
|
12
|
+
"deepseekProtocol": "0.1.1-rc.2",
|
|
13
|
+
"deepseekRuntime": "0.1.1-rc.2",
|
|
14
|
+
"codexAppServer": "0.153.4",
|
|
15
|
+
"grafana": "13.2.0",
|
|
16
|
+
"grafanaInfinity": "4.0.0",
|
|
17
|
+
"piSdk": "0.85.1",
|
|
18
|
+
"cursorSdk": "1.0.31"
|
|
19
|
+
},
|
|
20
|
+
"commands": [
|
|
21
|
+
"npm ci",
|
|
22
|
+
"npm run acceptance"
|
|
23
|
+
],
|
|
24
|
+
"fixtureCoverage": {
|
|
25
|
+
"agent-sdk": "frozen queue entry through qualified capture, approved export, normalization, configurable judging, review, aggregation, and Atlas",
|
|
26
|
+
"openhands-agent-server": "pinned REST/WebSocket stream-final reconciliation, workspace/outcome evidence, partial capture, and retained evaluation",
|
|
27
|
+
"deepseek-harness": "official-client JSON-RPC composition, receipt-to-idle completion, stderr, interruption, shutdown, swaps, and retained evaluation",
|
|
28
|
+
"codex-app-server": "owned stdio lifecycle, full history, OTLP, interruption/failure, export, and retained evaluation; configurable workspace-write networking with explicit offline queue propagation",
|
|
29
|
+
"acceptance-cases": "seeded ordering, secret scanning, partial attempts, native references, abstention, disputes, denominators, and unsupported comparisons",
|
|
30
|
+
"pi-sdk": "frozen queue, passive hooks, durable session, partial cleanup, export, retained normalization and evaluation",
|
|
31
|
+
"cursor-sdk": "frozen queue, official store, callbacks/history, bounded cancellation, export, retained normalization and evaluation",
|
|
32
|
+
"workspace-capture": "streamed snapshot capture, atomic publication and qualification beyond 128 MiB; bounded 1 GiB compressed output; retained error and partial evidence"
|
|
33
|
+
},
|
|
34
|
+
"determinism": {
|
|
35
|
+
"stable": [
|
|
36
|
+
"task, run, attempt, event, assertion, aggregate, and Atlas case identities",
|
|
37
|
+
"fixture, native-reference, normalized-dataset, source/cohort, archive, and package digests",
|
|
38
|
+
"seeded queue and review-sample ordering"
|
|
39
|
+
],
|
|
40
|
+
"excluded": [
|
|
41
|
+
"native and EBO observation timestamps",
|
|
42
|
+
"lifecycle start/finish timestamps",
|
|
43
|
+
"provider timing and usage",
|
|
44
|
+
"temporary workspace and output paths"
|
|
45
|
+
]
|
|
46
|
+
},
|
|
47
|
+
"fixtures": {
|
|
48
|
+
"tests/fixtures/task-packet.valid.v1.json": "ac2ef1043c0cc16bf4c21d05c1dc880ca1b4b8cc2f9ea7653328e91f0b0e2681",
|
|
49
|
+
"test/fixtures/agent-sdk-normalizer/complete.input.json": "7285dee088517e5de38ceda84fc7c58d9303949c7448ab3b5e10a5a2d2ebdfe3",
|
|
50
|
+
"test/fixtures/agent-sdk-normalizer/complete.expected.jsonl": "d32fa3a013bc179f1673f7e1a89b8a721bb8ddaf63eba5bc8a3f14f1cc148ed8",
|
|
51
|
+
"contracts/openhands-agent-server-v1.44.1.json": "e7a07977688a0703b15751a8a1ab17f29be45f9fdf438017e0dbcbc49cca37b0",
|
|
52
|
+
"contracts/openhands-agent-server-v1.46.0.json": "455cdddd2c206cb2f20245c2189b92e773657ec14d651236baa532b2dbadeb28",
|
|
53
|
+
"test/fixtures/openhands/v1.44.1/streamed-events.json": "d751083ba2ef94c9865117db481cc2f4933772bbbbb6b9fcf60571563715c1ea",
|
|
54
|
+
"test/fixtures/openhands/v1.44.1/final-events.json": "551db9904e860004d604c923692b5c5d3aaee966220492214c60003d2df415b6",
|
|
55
|
+
"test/fixtures/deepseek/golden-success.json": "f3867d38169bf0e28f64aba1dd60553f21cf07f41f81b4bad48261e49fa3ca88",
|
|
56
|
+
"test/fixtures/deepseek/golden-interrupted.json": "79e1f8404df1ee3b562d0bdbc0b2ee712ffc6d5774992b92970814ea815677b7",
|
|
57
|
+
"test/fixtures/deepseek/compositions/minimal/composition.json": "72fe4368e105f1bad82b7fdf8380e92c9fa689d8985f6ab91f534f0baf3eda02",
|
|
58
|
+
"contracts/codex-app-server-0.153.4/manifest.json": "e62281ff5e5d1cc71d07763b85e997ccc9ddbad9aa82a469da4181ee4b1890a8",
|
|
59
|
+
"test/fixtures/codex/legacy-0.150.1.dataset.json": "f71906b009e546afbf3b4e79396f223181382f3b3d8795e9cfcd032398a9d6bf",
|
|
60
|
+
"test/fixtures/behavior-assertions/abstained.json": "7f1962864f664c794925a67d93074e7b150af0f57c58041a81e062990d641197",
|
|
61
|
+
"test/fixtures/behavior-assertions/disputed.review.json": "450d3d9efe7feefaf7500b3ad20ab2803b412c7e53b91763125e15a83be87981",
|
|
62
|
+
"test/fixtures/comparison/exact.json": "cafa68e94b8d50dc308ddcfc2e73aa139c828b4ecd1e1c762bbc51bf1b44501e",
|
|
63
|
+
"test/fixtures/structural-observations/golden.json": "bad71a3a93524b76c0a2fdbb58e98e1e65be46cae14acf18ac89d9ba76e03e8a",
|
|
64
|
+
"test/atlas-fixture.ts": "9f03ce9cbcd0e5d3e3a5916866554ceb1c21f1c8712e58529499c1ea499f048d",
|
|
65
|
+
"test/pi.test.ts": "a00997c5617ca178e19b25b0d483cbdce8ce7c306d4c871557945b31a2e657cf",
|
|
66
|
+
"test/cursor-sdk.test.ts": "753094f127b11dc392ec2244c9edddabec27aa94347bb6159a292129ed2a2822",
|
|
67
|
+
"examples/cursor-sdk/README.md": "a2cf481123e7f3deb1c5a682ba208a775c3f91c35e1a6c1a428c517c79692618",
|
|
68
|
+
"examples/cursor-sdk/capture-profile.json": "d1a5787875daf5523b3783f259b891c256a904cbb10279d5be214af846305a2d",
|
|
69
|
+
"examples/cursor-sdk/harness.json": "2f1da6f2b17258d0ee59431f687696901ce3692589175d182f3a4bbe8dd4d689",
|
|
70
|
+
"examples/cursor-sdk/model.json": "ad8f31ff5d2387c02d79226679022358afafc61ba5dda73040e3f754530a230a",
|
|
71
|
+
"examples/cursor-sdk/native-limits.json": "40fe451f56b0863e79b42f5c85defbce678e1dc90dd248d15c430db176d71511",
|
|
72
|
+
"examples/cursor-sdk/native-tool-policy.json": "0fef98b36cd39de82914c5b068022c1335dadda24b7d6e7df398b2430e6a16e0"
|
|
73
|
+
}
|
|
74
|
+
}
|
package/release/README.md
CHANGED
|
@@ -5,6 +5,7 @@ For downloads and published artifacts, see
|
|
|
5
5
|
|
|
6
6
|
| Version | Changes and verification | Support boundary |
|
|
7
7
|
| :--- | :--- | :--- |
|
|
8
|
+
| [0.2.4](0.2.4/README.md) | Stream workspace snapshots and integrity checks; support archives up to 1 GiB | [Known limitations](0.2.4/KNOWN_LIMITATIONS.md) |
|
|
8
9
|
| [0.2.3](0.2.3/README.md) | Retain workspace capture errors in partial-bundle reports | [Known limitations](0.2.3/KNOWN_LIMITATIONS.md) |
|
|
9
10
|
| [0.2.2](0.2.2/README.md) | Configurable Codex tool networking, enabled by default for workspace-write | [Known limitations](0.2.2/KNOWN_LIMITATIONS.md) |
|
|
10
11
|
| [0.2.1](0.2.1/README.md) | Documentation redesign, Apache-2.0, and npm distribution setup | [Known limitations](0.2.1/KNOWN_LIMITATIONS.md) |
|