cowork-harness 1.0.0 → 1.0.2
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/.claude/skills/cowork-harness/SKILL.md +5 -5
- package/.claude/skills/cowork-harness/references/ci-recipe.md +5 -5
- package/.claude/skills/cowork-harness/references/fidelity-and-answers.md +1 -1
- package/.claude/skills/cowork-harness/references/scenario-schema.md +1 -1
- package/CHANGELOG.md +35 -1
- package/README.md +6 -6
- package/RELEASING.md +12 -7
- package/SECURITY.md +1 -1
- package/SPEC.md +2 -2
- package/docs/maintenance.md +2 -2
- package/examples/replays/README.md +1 -1
- package/package.json +1 -1
- package/scripts/bump-version.ts +2 -1
- package/scripts/check-versions.ts +11 -0
|
@@ -3,8 +3,8 @@ name: cowork-harness
|
|
|
3
3
|
description: Test or debug a Claude Code skill/plugin under Claude Cowork's runtime — sandboxed agent, default-deny egress, the can_use_tool permission/question protocol — using the cowork-harness CLI. Use when validating or regression-testing a skill, authoring or debugging a scenario YAML (prompt + scripted answers + assert:), choosing a fidelity tier, scripting AskUserQuestion / tool-permission answers, or asserting artifacts, egress, or sub-agent dispatch. Especially when a harness run no-ops an assertion, fails on an unanswered gate, false-greens, a steered answer never reaches the model, or a web_fetch is unexpectedly denied or gated. NOT for generic unit testing (pytest/vitest of your own scripts) or non-Cowork CI. Covers the skill / run / chat / record / replay / trace / decide / assertions / scaffold commands and the session-vs-scenario split.
|
|
4
4
|
metadata:
|
|
5
5
|
author: cowork-harness
|
|
6
|
-
version: 1.0.
|
|
7
|
-
tracks-harness: cowork-harness 1.0.
|
|
6
|
+
version: 1.0.2
|
|
7
|
+
tracks-harness: cowork-harness 1.0.2 (baseline desktop-1.20186.1)
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# cowork-harness
|
|
@@ -22,7 +22,7 @@ flagged with a loud `::warning::`, not silent — auto-answer a gate, observe an
|
|
|
22
22
|
allowlist). This skill exists mostly to keep you out of those traps — the Gotchas section below is
|
|
23
23
|
the highest-value part. Read it.
|
|
24
24
|
|
|
25
|
-
> **Version note:** the facts and `file:line` pointers here track `cowork-harness 1.0.
|
|
25
|
+
> **Version note:** the facts and `file:line` pointers here track `cowork-harness 1.0.2` (baseline
|
|
26
26
|
> `desktop-1.20186.1`). If your checkout is newer, prefer the live `--help` and — in a repo checkout —
|
|
27
27
|
> `SPEC.md` / `docs/*.md` over this snapshot, and re-run the bundled linter.
|
|
28
28
|
|
|
@@ -39,9 +39,9 @@ Before the first command, confirm the CLI is reachable and **fail loud** (never
|
|
|
39
39
|
|
|
40
40
|
- **One-shot check.** Run `cowork-harness doctor [--tier <tier>]` first — a read-only prerequisite check that inspects Docker, the staged agent, the token, and the baseline in one pass. The bullets below explain each thing it checks (and how to fix it).
|
|
41
41
|
- **Replay-only? Skip `doctor`.** Replaying committed cassettes needs no Docker, no staged agent, and no token — and every tier's `doctor` validates the auth token (the live tiers also Docker + the staged agent), so a ✗ there is expected, not a blocker. Go straight to `cowork-harness replay <cassette>`.
|
|
42
|
-
- **CLI on PATH, recent enough?** Run `cowork-harness --version` — this skill needs **≥ 1.0.
|
|
42
|
+
- **CLI on PATH, recent enough?** Run `cowork-harness --version` — this skill needs **≥ 1.0.2**. If it's missing or older, prefix every command with the version floor `npx "cowork-harness@>=1.0.2" <cmd>` (Node ≥ 20), or install once with `npm i -g "cowork-harness@>=1.0.2"`. **Pin `@>=1.0.2`, never `@latest`** — `@latest` can silently fetch an older CLI and the new commands fail as "unknown command", whereas the floor **fails loud** if no compatible version is published.
|
|
43
43
|
|
|
44
|
-
What the ≥ 1.0.
|
|
44
|
+
What the ≥ 1.0.2 floor gates, by release:
|
|
45
45
|
|
|
46
46
|
- **core set (pre-0.21.0 vintage, or mixed):** `assertions --list`, `scaffold <run-id>`, `trace --view dispatches`, `artifact_json` incl. the `in:` operator (passes when the resolved value deep-equals one of the listed members — value ∈ your list, not the reverse), `verify-cassettes` incl. the `--allow-domain`/`--allow-email`/`--allow-patterns-file` allows (`--allow-patterns-file <path>` is a FILE of patterns, one regex per line — not a path to allow, unlike `--allow <regex>`), batch `record <dir>`/`--rerecord-stale`, `record --concurrency <N>`, record-time redaction, multiSelect/`answer:`, `verify-run` answer-coverage, `record --max-artifact-bytes`, live record-time deciders, scenario `skills:` staleness scoping with `COWORK_HARNESS_AGENT_SCOPE=skill`, `chat --plugin`, and `/help` in the REPL.
|
|
47
47
|
- **0.21.0:** `verify-cassettes --allow-path` (`path` — local absolute filesystem paths — is the scanner's 4th class), and `hostloop`'s native host/VM process split with its `allow_host_writes:` consent field.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# CI recipe — replay vs live lanes
|
|
2
2
|
|
|
3
|
-
Self-contained reference. Tracks `cowork-harness 1.0.
|
|
3
|
+
Self-contained reference. Tracks `cowork-harness 1.0.2` (baseline `desktop-1.20186.1`).
|
|
4
4
|
|
|
5
5
|
**Fastest path: the packaged Action.** One step gets you `replay`/`lint`/`verify-cassettes` plus a PR
|
|
6
6
|
job-summary reporter (verdict table, staleness findings, cost/turns when available):
|
|
@@ -13,7 +13,7 @@ job-summary reporter (verdict table, staleness findings, cost/turns when availab
|
|
|
13
13
|
```
|
|
14
14
|
|
|
15
15
|
The Action's `version` input defaults to `latest` — intentional so a copy-pasted recipe tracks the current
|
|
16
|
-
release; pin an exact version (e.g. `version: "1.0.
|
|
16
|
+
release; pin an exact version (e.g. `version: "1.0.2"`) for reproducible CI.
|
|
17
17
|
|
|
18
18
|
Reach for the manual multi-step form below only when you need per-step control the Action's inputs don't
|
|
19
19
|
cover (a custom flag combination, a different runner matrix per step, or `lint`/`verify-cassettes` gated
|
|
@@ -57,7 +57,7 @@ sha256-*checked* but not hard-blocking on mismatch — it's advisory for an inte
|
|
|
57
57
|
GitHub-hosted runners, no token/Docker/agent:
|
|
58
58
|
|
|
59
59
|
```yaml
|
|
60
|
-
- run: npm i -g "cowork-harness@>=1.0.
|
|
60
|
+
- run: npm i -g "cowork-harness@>=1.0.2"
|
|
61
61
|
- run: cowork-harness lint scenarios/*.yaml # no silent false-greens
|
|
62
62
|
- run: cowork-harness verify-cassettes cassettes/ # privacy + staleness
|
|
63
63
|
- run: cowork-harness replay cassettes/ # token-free content/structure
|
|
@@ -197,7 +197,7 @@ jobs:
|
|
|
197
197
|
with: { node-version: '20' }
|
|
198
198
|
- uses: actions/setup-python@v5
|
|
199
199
|
with: { python-version: '3.x' } # python3 only — PyYAML is bundled with the linter
|
|
200
|
-
- run: npm i -g "cowork-harness@>=1.0.
|
|
200
|
+
- run: npm i -g "cowork-harness@>=1.0.2"
|
|
201
201
|
- run: cowork-harness lint scenarios/*.yaml # no-silent-false-green (needs python3; PyYAML bundled)
|
|
202
202
|
- run: cowork-harness verify-cassettes cassettes/ --output-format json # privacy + staleness gate
|
|
203
203
|
- run: cowork-harness replay cassettes/ --output-format json # token-free content/structure
|
|
@@ -226,7 +226,7 @@ jobs:
|
|
|
226
226
|
echo "live=true" >> "$GITHUB_OUTPUT"
|
|
227
227
|
fi
|
|
228
228
|
- if: steps.guard.outputs.live == 'true'
|
|
229
|
-
run: npm i -g "cowork-harness@>=1.0.
|
|
229
|
+
run: npm i -g "cowork-harness@>=1.0.2"
|
|
230
230
|
- if: steps.guard.outputs.live == 'true'
|
|
231
231
|
run: cowork-harness run scenarios/ --output-format json
|
|
232
232
|
env:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Scenario & session schema, assertion catalog, web_fetch, full gotchas
|
|
2
2
|
|
|
3
|
-
Self-contained reference for authoring `cowork-harness` scenarios. Tracks `cowork-harness 1.0.
|
|
3
|
+
Self-contained reference for authoring `cowork-harness` scenarios. Tracks `cowork-harness 1.0.2`
|
|
4
4
|
(baseline `desktop-1.20186.1`). If your checkout is newer, prefer the live `docs/scenario.md`,
|
|
5
5
|
`docs/session.md`, and `SPEC.md`.
|
|
6
6
|
|
package/CHANGELOG.md
CHANGED
|
@@ -2,10 +2,44 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project are documented here. The format is based on
|
|
4
4
|
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/). The project uses
|
|
5
|
-
[Semantic Versioning](https://semver.org/);
|
|
5
|
+
[Semantic Versioning](https://semver.org/); as of 1.0.0, a backwards-incompatible change to a covered surface ([SPEC.md §12](./SPEC.md#12-versioning--the-10-compatibility-contract)) requires a major bump.
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [1.0.2] — 2026-07-14
|
|
10
|
+
|
|
11
|
+
Patch: shorten the Action's Marketplace tagline. No runtime/API change.
|
|
12
|
+
|
|
13
|
+
### Fixed
|
|
14
|
+
|
|
15
|
+
- `action.yml`'s `description` is now under GitHub Marketplace's 125-character limit (the full
|
|
16
|
+
token-free-vs-live-lane detail is retained as comments above it), so the packaged Action can be
|
|
17
|
+
published to the Marketplace. `1.0.1`'s description was too long and blocked the listing.
|
|
18
|
+
|
|
19
|
+
## [1.0.1] — 2026-07-14
|
|
20
|
+
|
|
21
|
+
Patch: Action Marketplace branding + a release-tooling fix. No runtime/API change.
|
|
22
|
+
|
|
23
|
+
### Added
|
|
24
|
+
|
|
25
|
+
- `action.yml` now declares Marketplace `branding` (`shield` / `orange`) so the packaged GitHub Action
|
|
26
|
+
can be listed on the GitHub Actions Marketplace. No change to the Action's inputs, outputs, or runtime.
|
|
27
|
+
|
|
28
|
+
### Fixed
|
|
29
|
+
|
|
30
|
+
- `npm run bump` now rewrites the bare `` `Pin `@>=X`` `` floor in `SKILL.md` — it previously bumped only
|
|
31
|
+
the `cowork-harness@>=`-prefixed floors, so that one line stayed stale (it had drifted since `0.33.0`
|
|
32
|
+
and shipped stale in `1.0.0`). A new `check:versions` invariant (5b) fails on any `@>=X` in `SKILL.md`
|
|
33
|
+
that doesn't match the floor, and a regression test covers the bump path.
|
|
34
|
+
|
|
35
|
+
### Changed
|
|
36
|
+
|
|
37
|
+
- `RELEASING.md` documents maintaining the moving `v1` / `v1.0` tags on each release, so
|
|
38
|
+
`uses: yaniv-golan/cowork-harness@v1` resolves to the latest 1.x.
|
|
39
|
+
- Pruned stale pre-1.0 versioning language now that the compatibility contract is in force
|
|
40
|
+
(README, `SPEC.md`, `RELEASING.md`, `docs/maintenance.md`, this file); `SECURITY.md` now states
|
|
41
|
+
that only the latest published release is supported.
|
|
42
|
+
|
|
9
43
|
## [1.0.0] — 2026-07-13
|
|
10
44
|
|
|
11
45
|
**First stable release.** The compatibility contract in
|
package/README.md
CHANGED
|
@@ -91,7 +91,7 @@ node dist/cli.js replay examples/replays/example-pdf-skill.cassette.json
|
|
|
91
91
|
|
|
92
92
|
> **Installed globally instead?** Once linked/installed, the same command is `cowork-harness replay
|
|
93
93
|
> <cassette>` — but the relative path above only resolves from a source checkout's `examples/replays/`.
|
|
94
|
-
> From a global install (`npm i -g "cowork-harness@>=1.0.
|
|
94
|
+
> From a global install (`npm i -g "cowork-harness@>=1.0.2"`), point at the package root instead:
|
|
95
95
|
> `cowork-harness replay "$(npm root -g)/cowork-harness/examples/replays/example-pdf-skill.cassette.json"`
|
|
96
96
|
> (or copy the cassette into your own project and pass that path).
|
|
97
97
|
|
|
@@ -101,7 +101,7 @@ Live `run`/`skill` need the prerequisites in the next section — note the `prot
|
|
|
101
101
|
> - **Replay only (zero setup):** `cowork-harness replay <cassette>` — no token, no Docker, no agent. The command above.
|
|
102
102
|
> - **`protocol` (real model, no Docker):** needs only the auth token (item 3 below).
|
|
103
103
|
> - **Live `container` / `microvm` / `hostloop` / `cowork`:** needs Docker (or Lima for `microvm`), a staged agent, and the token — run `cowork-harness doctor` first.
|
|
104
|
-
> - **Invocation:** from a source checkout, `node dist/cli.js <cmd>` (or `npm link` to get the `cowork-harness` command); from a global install, `cowork-harness <cmd>`; the companion skill falls back to `npx "cowork-harness@>=1.0.
|
|
104
|
+
> - **Invocation:** from a source checkout, `node dist/cli.js <cmd>` (or `npm link` to get the `cowork-harness` command); from a global install, `cowork-harness <cmd>`; the companion skill falls back to `npx "cowork-harness@>=1.0.2"`.
|
|
105
105
|
|
|
106
106
|
Two more worked examples worth knowing about: `examples/scenarios/protocol-smoke.yaml` (zero-Docker smoke
|
|
107
107
|
test) and `examples/scenarios/skill-loads.yaml` (container-tier acceptance check) — see
|
|
@@ -126,7 +126,7 @@ claude plugin marketplace add yaniv-golan/cowork-harness
|
|
|
126
126
|
claude plugin install cowork-harness@cowork-harness
|
|
127
127
|
```
|
|
128
128
|
|
|
129
|
-
The skill **self-bootstraps the CLI**: if `cowork-harness` isn't on your PATH it falls back to `npx "cowork-harness@>=1.0.
|
|
129
|
+
The skill **self-bootstraps the CLI**: if `cowork-harness` isn't on your PATH it falls back to `npx "cowork-harness@>=1.0.2"` (a version floor that fails loud rather than silently fetching a too-old CLI; Node ≥ 20). Tiers above `protocol` still need Docker/Lima and a Claude Desktop agent binary — see the prerequisites below.
|
|
130
130
|
|
|
131
131
|
It also follows the open [Agent Skills](https://agentskills.io) spec, so it installs cross-editor (Cursor, Codex, OpenCode, …) via [`npx skills`](https://github.com/vercel-labs/skills) (Vercel Labs' CLI implementation of that spec):
|
|
132
132
|
|
|
@@ -147,7 +147,7 @@ A global install is enough for CI `lint`, reading the teaching skill, and replay
|
|
|
147
147
|
To `run` the worked examples live or copy them as a starting point, use a source checkout. (The marketplace
|
|
148
148
|
skill install itself only pulls `.claude/skills/cowork-harness/` — SKILL.md + `references/` + `scenario.py`/
|
|
149
149
|
assertion keys, per `.claude-plugin/marketplace.json`'s `source` — not the rest of this table; the full set
|
|
150
|
-
above becomes available once the skill's first command self-bootstraps `npx "cowork-harness@>=1.0.
|
|
150
|
+
above becomes available once the skill's first command self-bootstraps `npx "cowork-harness@>=1.0.2"` — see
|
|
151
151
|
[above](#drive-it-from-claude-code-companion-skill) — which pulls the same npm package as the global-install row.)
|
|
152
152
|
|
|
153
153
|
### Prerequisites for anything above `protocol` fidelity
|
|
@@ -665,7 +665,7 @@ jobs:
|
|
|
665
665
|
anthropic-api-key: ${{ secrets.ANTHROPIC_API_KEY }}
|
|
666
666
|
```
|
|
667
667
|
|
|
668
|
-
Every run writes a Markdown verdict table (scenario, pass/fail, signals, cost/turns when available, staleness findings, and the replay-skipped-assertions honesty line) to the job summary. Inputs: `command`, `path` (required), `version` (npm dist-tag/version, default `latest` — intentional so recipes track the current release; pin an exact version for reproducible CI. The companion skill's `cowork-harness@>=1.0.
|
|
668
|
+
Every run writes a Markdown verdict table (scenario, pass/fail, signals, cost/turns when available, staleness findings, and the replay-skipped-assertions honesty line) to the job summary. Inputs: `command`, `path` (required), `version` (npm dist-tag/version, default `latest` — intentional so recipes track the current release; pin an exact version for reproducible CI. The companion skill's `cowork-harness@>=1.0.2` floor guidance applies to ad-hoc CLI installs, not this input), `strict` (applies to `replay` (staleness findings), `lint`/`lint-skill` (WARN/INFO), and `analyze-skill` (any advisory finding); IGNORED — not forwarded — for `verify-cassettes`/`run`, which don't accept the flag), `fail-on-skill-drift` (**`replay`-only** — never forwarded to the analyzers), `extra-args`, `summary` (default `true`), `anthropic-api-key` (live lane only). See [`action.yml`](./action.yml) for the full input reference.
|
|
669
669
|
|
|
670
670
|
The provided [GitHub Actions workflow](.github/workflows/ci.yml) runs a **six-stage pipeline**. The **unit** stage is the token-free gate you can copy into your skill repo; the `action-self-test`, `python`, `boundary`, `scenarios`, and `parity-drift` stages are this repo's own fidelity self-tests and are not directly portable (they build the harness's Docker image and run harness-specific e2e scenarios — see [`ci-recipe.md`](./.claude/skills/cowork-harness/references/ci-recipe.md) for the skill-repo template):
|
|
671
671
|
|
|
@@ -821,7 +821,7 @@ From `1.0.0` this project follows [semver](https://semver.org/). What that cover
|
|
|
821
821
|
exit codes, the scenario/session/baseline/`RunResult`/cassette/protocol schemas, the documented
|
|
822
822
|
`COWORK_HARNESS_*` (+ `COWORK_AGENT_BINARY`/`COWORK_AGENT_IMAGE`) env vars, and the packaged Action's
|
|
823
823
|
inputs/outputs. Human-readable terminal text is explicitly **not** part of the contract — parse the
|
|
824
|
-
`--output-format json` envelope, not stdout.
|
|
824
|
+
`--output-format json` envelope, not stdout. As of 1.0.0, a backwards-incompatible change to a covered surface is a major bump.
|
|
825
825
|
|
|
826
826
|
## Status
|
|
827
827
|
|
package/RELEASING.md
CHANGED
|
@@ -79,16 +79,14 @@ When you query runs by SHA, use the **full 40-char SHA** (`git rev-parse HEAD`)
|
|
|
79
79
|
release run. Running `npm run preflight -- --for-tag` right before the tag push mechanically catches
|
|
80
80
|
this (it asserts `HEAD == origin/main` and that a push-event `ci.yml` run succeeded for `HEAD`).
|
|
81
81
|
|
|
82
|
-
## Versioning (semver
|
|
82
|
+
## Versioning (semver)
|
|
83
83
|
|
|
84
|
-
|
|
85
|
-
backwards-compatible bug fixes only. New commands/flags, or changes to existing behavior (e.g. a
|
|
86
|
-
stricter privacy gate, a changed cassette/staleness hash), are a **minor**.
|
|
87
|
-
|
|
88
|
-
From `1.0.0`, semver is enforced against the **covered surfaces enumerated in
|
|
84
|
+
As of `1.0.0`, semver is enforced against the **covered surfaces enumerated in
|
|
89
85
|
[SPEC.md §12](./SPEC.md#12-versioning--the-10-compatibility-contract)** (CLI + exit codes, the
|
|
90
86
|
scenario/session/baseline/run-result/cassette/protocol schemas, the documented env vars, and the
|
|
91
|
-
packaged Action's inputs/outputs)
|
|
87
|
+
packaged Action's inputs/outputs): a backwards-incompatible change to a covered surface is a
|
|
88
|
+
**major**; a new command/flag or other additive change is a **minor**; a backwards-compatible bug
|
|
89
|
+
fix is a **patch**. Human-readable text output is explicitly NOT covered.
|
|
92
90
|
|
|
93
91
|
**Surface drift is partly automated.** `test/surface-contract.test.ts` snapshots the *structured*
|
|
94
92
|
surfaces — every `schema/*.json` (field paths + enums, including exit-code enums), `action.yml`
|
|
@@ -180,6 +178,13 @@ tagging `1.0.0`, deliberately review and freeze the surfaces with no machine-rea
|
|
|
180
178
|
gh run watch $(gh run list --workflow=release.yml --limit 1 --json databaseId --jq '.[0].databaseId')
|
|
181
179
|
```
|
|
182
180
|
- [ ] **Clean up**: `git push origin --delete release/X.Y.Z && git branch -d release/X.Y.Z`
|
|
181
|
+
- [ ] **Move the major/minor tags** (so `uses: yaniv-golan/cowork-harness@v1` and `@v1.0` resolve to
|
|
182
|
+
this release — the packaged Action's Marketplace consumers pin those):
|
|
183
|
+
```
|
|
184
|
+
git tag -f vX vX.Y.Z && git tag -f vX.Y vX.Y.Z # e.g. v1 and v1.0 → v1.2.3
|
|
185
|
+
git push -f origin vX vX.Y
|
|
186
|
+
```
|
|
187
|
+
(Force-moving these ALIAS tags is expected; never force-move the immutable `vX.Y.Z` release tag.)
|
|
183
188
|
- [ ] Smoke the published artifact: `npx cowork-harness@X.Y.Z --version` and
|
|
184
189
|
`npx cowork-harness@X.Y.Z doctor --tier protocol`.
|
|
185
190
|
|
package/SECURITY.md
CHANGED
package/SPEC.md
CHANGED
|
@@ -678,8 +678,8 @@ entries (CB-5), adding major European, Asian, and Latin American ccTLDs
|
|
|
678
678
|
|
|
679
679
|
From `1.0.0` the project follows [semver](https://semver.org/). The surfaces below are the **covered
|
|
680
680
|
contract**: a backwards-incompatible change to any of them is a MAJOR bump. Everything else — most
|
|
681
|
-
importantly human-readable text — is explicitly NOT covered and may change in any release.
|
|
682
|
-
|
|
681
|
+
importantly human-readable text — is explicitly NOT covered and may change in any release.
|
|
682
|
+
Covered-surface changes follow semver as of `1.0.0` — see [RELEASING.md](./RELEASING.md).
|
|
683
683
|
|
|
684
684
|
**Covered (semver-guaranteed):**
|
|
685
685
|
|
package/docs/maintenance.md
CHANGED
|
@@ -182,8 +182,8 @@ The sync extractor currently targets macOS paths (`~/Library/Application Support
|
|
|
182
182
|
> locations, the branch → PR → tag → publish flow, the checklist) lives in [RELEASING.md](../RELEASING.md).
|
|
183
183
|
> The notes here only cover how a *parity sync* relates to versioning.
|
|
184
184
|
|
|
185
|
-
Versioning follows [SemVer](https://semver.org/);
|
|
186
|
-
(baseline-schema or CLI-contract changes count
|
|
185
|
+
Versioning follows [SemVer](https://semver.org/); as of 1.0.0 a backwards-incompatible change to a
|
|
186
|
+
covered surface (baseline-schema or CLI-contract changes count) is a major bump. A parity-baseline *content* update (a new
|
|
187
187
|
Desktop release) is **not** a package version bump on its own — it ships in a normal patch/minor.
|
|
188
188
|
|
|
189
189
|
Release flow — CD via `.github/workflows/release.yml`, published with **npm Trusted Publishing (OIDC)**
|
|
@@ -16,7 +16,7 @@ DOES exercise a real gate exchange, see `example-multiselect-gate.cassette.json`
|
|
|
16
16
|
|
|
17
17
|
Run it with:
|
|
18
18
|
|
|
19
|
-
> Assumes the `cowork-harness` CLI is available — from a source checkout run `npm ci && npm run build && npm link` first, or `npm i -g "cowork-harness@>=1.0.
|
|
19
|
+
> Assumes the `cowork-harness` CLI is available — from a source checkout run `npm ci && npm run build && npm link` first, or `npm i -g "cowork-harness@>=1.0.2"`. (`replay` itself needs nothing else — no token, no Docker.)
|
|
20
20
|
|
|
21
21
|
```sh
|
|
22
22
|
cowork-harness replay examples/replays/example-pdf-skill.cassette.json
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cowork-harness",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
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",
|
package/scripts/bump-version.ts
CHANGED
|
@@ -42,7 +42,7 @@ function bumpHarnessFloors(content: string, newVersion: string): string {
|
|
|
42
42
|
return content.replace(/cowork-harness@>=\d+\.\d+\.\d+/g, `cowork-harness@>=${newVersion}`);
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
-
/** A bare, backtick-delimited `` `@>=X.Y.Z` `` floor with no `cowork-harness` prefix (README.md
|
|
45
|
+
/** A bare, backtick-delimited `` `@>=X.Y.Z` `` floor with no `cowork-harness` prefix (README's Action-inputs mention + SKILL.md's `Pin `@>=X`` phrase). */
|
|
46
46
|
function bumpBareFloors(content: string, newVersion: string): string {
|
|
47
47
|
return content.replace(/`@>=\d+\.\d+\.\d+`/g, `\`@>=${newVersion}\``);
|
|
48
48
|
}
|
|
@@ -138,6 +138,7 @@ export function rewriteFileContent(relPath: string, content: string, newVersion:
|
|
|
138
138
|
next = bumpNeedsFloor(next, newVersion);
|
|
139
139
|
next = bumpFloorGatesHeading(next, newVersion);
|
|
140
140
|
next = bumpHarnessFloors(next, newVersion);
|
|
141
|
+
next = bumpBareFloors(next, newVersion); // the `Pin `@>=X`` phrase — a bare floor, like README's
|
|
141
142
|
return next;
|
|
142
143
|
}
|
|
143
144
|
|
|
@@ -13,6 +13,9 @@
|
|
|
13
13
|
// can publish (else the skill ships ahead of npm).
|
|
14
14
|
// 5. README floor === floor: every `cowork-harness@>=X.Y.Z` in README.md matches the SKILL.md floor
|
|
15
15
|
// (README is not version-controlled by the package; it drifts silently otherwise).
|
|
16
|
+
// 5b. SKILL floors === floor: every `@>=X.Y.Z` in SKILL.md (incl. a BARE `Pin `@>=X`` with no
|
|
17
|
+
// `cowork-harness` prefix) matches the floor — invariant 3 reads only the
|
|
18
|
+
// first prefixed match, so a bare floor drifted silently (stale 0.33.0→1.0.0).
|
|
16
19
|
// 6. ref stamps === tracks: each `references/*.md` "Tracks `cowork-harness X.Y.Z`" matches tracks-harness.
|
|
17
20
|
// 7. baseline pins agree: SKILL.md's `(baseline desktop-X.Y.Z)` and README.md's "latest shipped
|
|
18
21
|
// baseline" sentence agree with each other AND are not behind the max
|
|
@@ -115,6 +118,14 @@ export function checkVersions(): { ok: boolean; errors: string[]; values: Record
|
|
|
115
118
|
for (const f of readmeFloors) if (f !== floor) errors.push(`README.md floor "@>=${f}" != SKILL.md floor "@>=${floor}"`);
|
|
116
119
|
}
|
|
117
120
|
|
|
121
|
+
// 5b. EVERY `@>=X.Y.Z` inside SKILL.md must equal the floor — including a BARE `Pin `@>=X`` with no
|
|
122
|
+
// `cowork-harness` prefix. Invariant 3 reads only the FIRST `cowork-harness@>=` match, so a bare
|
|
123
|
+
// floor drifted silently (it shipped stale from 0.33.0 through 1.0.0). This catches all of them.
|
|
124
|
+
if (floor) {
|
|
125
|
+
const skillFloors = [...skillMd.matchAll(/@>=(\d+\.\d+\.\d+)/g)].map((m) => m[1]);
|
|
126
|
+
for (const f of skillFloors) if (f !== floor) errors.push(`SKILL.md floor "@>=${f}" != SKILL.md bootstrap floor "@>=${floor}" (a bare \`@>=X\` drifted — bump it)`);
|
|
127
|
+
}
|
|
128
|
+
|
|
118
129
|
// 6. Each reference doc's "Tracks `cowork-harness X.Y.Z`" stamp must match tracks-harness.
|
|
119
130
|
const refFiles = [
|
|
120
131
|
".claude/skills/cowork-harness/references/ci-recipe.md",
|