cowork-harness 0.7.0 → 0.7.1
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 +13 -0
- package/dist/assert.js +9 -2
- package/dist/run/cassette.js +5 -4
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,19 @@ All notable changes to this project are documented here. The format is based on
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [0.7.1] — 2026-06-20
|
|
10
|
+
|
|
11
|
+
### Fixed
|
|
12
|
+
|
|
13
|
+
- **`file_exists` and `user_visible_artifact` now pass for truncated (large) cassette artifacts.**
|
|
14
|
+
A truncated manifest entry (`truncated: true`) carries `path`, `bytes`, and `sha256` — positive
|
|
15
|
+
proof the file existed at record time. 0.7.0 incorrectly failed these existence/promotion
|
|
16
|
+
assertions with `"was truncated in the cassette — content was not committed; assertion cannot
|
|
17
|
+
pass"`, producing false-REDs for any cassette whose artifacts exceeded the 64 KiB inline cap.
|
|
18
|
+
Only **content** assertions (`artifact_json`) require the inlined body; existence assertions
|
|
19
|
+
now correctly pass from the manifest. `artifact_json` on a truncated artifact continues to fail
|
|
20
|
+
(the 0-byte placeholder is not valid JSON). Regression test added.
|
|
21
|
+
|
|
9
22
|
## [0.7.0] — 2026-06-19
|
|
10
23
|
|
|
11
24
|
### Added
|
package/dist/assert.js
CHANGED
|
@@ -192,7 +192,9 @@ function check(a, ctx) {
|
|
|
192
192
|
else {
|
|
193
193
|
const relPath = relative(resolve(ctx.workRoot), abs);
|
|
194
194
|
if (truncated.has(relPath)) {
|
|
195
|
-
|
|
195
|
+
// A truncated manifest entry carries path+bytes+sha256 — positive proof the file existed at
|
|
196
|
+
// record time. Existence is provable without the inlined body; only content assertions need it.
|
|
197
|
+
results.push(ok());
|
|
196
198
|
}
|
|
197
199
|
else {
|
|
198
200
|
// Bug 37: verify the real path (after symlink resolution) is still under workRoot.
|
|
@@ -214,7 +216,12 @@ function check(a, ctx) {
|
|
|
214
216
|
else {
|
|
215
217
|
const rel = relative(resolve(ctx.workRoot), abs); // normalized, guaranteed under workRoot
|
|
216
218
|
if (truncated.has(rel)) {
|
|
217
|
-
|
|
219
|
+
// Truncated entry proves existence (path+bytes+sha256 recorded). Promotion is a path-prefix
|
|
220
|
+
// property — also knowable without the body. Pass if under a user-visible prefix.
|
|
221
|
+
const visible = ctx.userVisiblePrefixes.some((pre) => rel === pre || rel.startsWith(pre + "/"));
|
|
222
|
+
results.push(visible
|
|
223
|
+
? ok()
|
|
224
|
+
: fail(`"${p}" is not under a user-visible prefix (${ctx.userVisiblePrefixes.join(", ")}) — invisible to the user in Cowork`));
|
|
218
225
|
}
|
|
219
226
|
else {
|
|
220
227
|
const visible = ctx.userVisiblePrefixes.some((pre) => rel === pre || rel.startsWith(pre + "/"));
|
package/dist/run/cassette.js
CHANGED
|
@@ -107,10 +107,11 @@ function decodeBody(e) {
|
|
|
107
107
|
}
|
|
108
108
|
/** #1: materialize a manifest into a temp work root so replay can run the filesystem assertions against it.
|
|
109
109
|
* Small files get their inlined body (decoded per its encoding marker); hash-only (truncated)
|
|
110
|
-
* files get an empty placeholder
|
|
111
|
-
*
|
|
112
|
-
*
|
|
113
|
-
*
|
|
110
|
+
* files get an empty placeholder. A truncated entry carries path+bytes+sha256 — positive proof the
|
|
111
|
+
* file existed at record time — so file_exists and user_visible_artifact PASS from the manifest;
|
|
112
|
+
* only artifact_json fails loud (it needs the inlined body). each path is containment-checked before
|
|
113
|
+
* writing so a hostile cassette entry can't escape the temp root. every non-truncated body is verified
|
|
114
|
+
* against its recorded sha256 (over the decoded RAW bytes) — a mismatch fails replay (throws). */
|
|
114
115
|
export function materializeManifest(entries) {
|
|
115
116
|
const workRoot = mkdtempSync(join(tmpdir(), "cwh-replay-"));
|
|
116
117
|
const truncatedPaths = new Set();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cowork-harness",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.1",
|
|
4
4
|
"description": "Scriptable, CI-friendly harness for Claude Cowork's runtime contract for testing skills across scenarios — same agent, mounts, egress allowlist, permission protocol, and sandbox limitations.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|