opencode-harness-kit 0.4.2 → 0.4.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/CHANGELOG.md +544 -19
- package/CONTRIBUTING.md +242 -0
- package/GLOBAL.md +34 -5
- package/MIGRATION.md +151 -0
- package/README.md +294 -37
- package/SECURITY.md +30 -0
- package/bin/baseline.mjs +15 -7
- package/bin/git-hooks/pre-commit +41 -9
- package/bin/oc-harness.mjs +1265 -82
- package/dist/config.d.ts +127 -0
- package/dist/denylist.d.ts +33 -0
- package/dist/effort.d.ts +64 -0
- package/dist/guard.d.ts +23 -0
- package/dist/health.d.ts +43 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +532 -149
- package/dist/plugin.d.ts +15 -0
- package/dist/profile.d.ts +399 -0
- package/dist/project.d.ts +8 -0
- package/dist/prune.d.ts +6 -0
- package/dist/router.d.ts +3 -0
- package/dist/rules.d.ts +109 -0
- package/dist/safe.d.ts +7 -0
- package/dist/telemetry-store.d.ts +12 -0
- package/dist/telemetry.d.ts +3 -0
- package/docs/EXIT-CODES.md +71 -0
- package/docs/KNOWN-LIMITS.md +45 -21
- package/docs/RESEARCH.md +9 -4
- package/docs/ROUTING.md +53 -8
- package/eval/RESULTS.md +443 -0
- package/eval/ab.mjs +743 -0
- package/eval/attribute.mjs +170 -0
- package/eval/flags.mjs +88 -0
- package/eval/measure-install.mjs +323 -0
- package/eval/measure-prune.mjs +339 -0
- package/eval/metrics.js +79 -0
- package/eval/premises.mjs +200 -0
- package/eval/prepare.mjs +233 -0
- package/eval/run.mjs +376 -0
- package/eval/tasks-self.json +81 -0
- package/eval/tasks-ts.json +50 -0
- package/eval/tasks.json +83 -0
- package/eval/thresholds.mjs +134 -0
- package/eval/verify.mjs +287 -0
- package/package.json +44 -17
- package/profiles/fleet-all.json +6 -1
- package/profiles/fleet-safe.json +7 -3
- package/profiles/schema.json +182 -51
- package/prompts/build.md +4 -2
- package/skills/space-build/SKILL.md +4 -2
- package/skills/space-finish/SKILL.md +6 -2
- package/skills/space-plan/reference/task-template.md +13 -5
- package/src/config.js +182 -32
- package/src/denylist.js +95 -0
- package/src/driver/run.mjs +81 -16
- package/src/effort.js +15 -4
- package/src/guard.ts +165 -13
- package/src/health.js +80 -0
- package/src/index.ts +15 -4
- package/src/lane-usage.js +72 -18
- package/src/plugin-type-check.ts +38 -0
- package/src/plugin.ts +39 -0
- package/src/profile.js +225 -26
- package/src/project.js +47 -0
- package/src/prune.ts +110 -31
- package/src/router.ts +32 -63
- package/src/rules.js +99 -7
- package/src/safe.ts +27 -0
- package/src/sqlite.js +144 -0
- package/src/tasks.js +112 -29
- package/src/telemetry-store.ts +62 -0
- package/src/telemetry.ts +60 -57
- package/src/trust.js +70 -9
package/CONTRIBUTING.md
ADDED
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
# Contributing to opencode-harness-kit
|
|
2
|
+
|
|
3
|
+
Thanks for looking. This is a small project and the bar for a change is that it
|
|
4
|
+
is either verifiable or it does not land.
|
|
5
|
+
|
|
6
|
+
## Before you start
|
|
7
|
+
|
|
8
|
+
`npm run check` must pass on an untouched checkout. If it does not, that is a
|
|
9
|
+
bug worth its own issue — do not build on top of a red baseline.
|
|
10
|
+
|
|
11
|
+
`npm run check` is the **offline** gate: build, typecheck, tests. It needs
|
|
12
|
+
nothing but the repository, so it is green on a machine that has never seen an
|
|
13
|
+
OpenCode login.
|
|
14
|
+
|
|
15
|
+
`npm run check:install` is the other half, and it needs a machine that HAS run
|
|
16
|
+
OpenCode: it measures the install database (`sqlite3` and
|
|
17
|
+
`~/.local/share/opencode/opencode.db`), reads the installed config, and
|
|
18
|
+
verifies it. It cannot run on a fresh checkout, and it is not part of
|
|
19
|
+
`npm run check` for that reason. CI runs the offline half; the live half is
|
|
20
|
+
yours to run before a release.
|
|
21
|
+
|
|
22
|
+
## What a change has to come with
|
|
23
|
+
|
|
24
|
+
The test suite is the contract, so a change without a test is a change nobody
|
|
25
|
+
can trust:
|
|
26
|
+
|
|
27
|
+
- **Model routing, effort tiers, pruning, retention.** Add an assertion to
|
|
28
|
+
`test/`. These tests run offline and must stay offline: no network, no model
|
|
29
|
+
calls, no API keys. `npm test` has to pass on a machine that has never seen
|
|
30
|
+
an OpenCode login.
|
|
31
|
+
- **A new command or flag.** `oc-harness <flag>` that the docs do not mention
|
|
32
|
+
will be found by nobody, and `oc-harness help` listing a command that does not
|
|
33
|
+
exist is worse.
|
|
34
|
+
- **A changed number.** If your change moves a number a profile claims —
|
|
35
|
+
effort, context budget, token budget — the README has to change with it, in
|
|
36
|
+
the same commit. A stale number in the README is a bug, not a nit.
|
|
37
|
+
- **A change to the grader.** The grader decides what the A/B means, and a
|
|
38
|
+
number produced by a grader nobody has read is a number nobody should
|
|
39
|
+
quote. `test/verify.test.js` holds the cases that actually happened.
|
|
40
|
+
- **Anything that writes to disk.** It needs a `--dryrun` path, and it must keep
|
|
41
|
+
a backup. `~/.config/opencode/` is a live config for anyone who runs it,
|
|
42
|
+
including the people reviewing your PR.
|
|
43
|
+
|
|
44
|
+
## Running the checks
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
npm run check # build + typecheck + tests, offline
|
|
48
|
+
npm run check:install # the above, plus the live install measurement and verify
|
|
49
|
+
npm test # the offline assertions, fast
|
|
50
|
+
npm run typecheck # the library, then the scripts
|
|
51
|
+
npm run typecheck:scripts # only bin/ and eval/
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
`bin/` and `eval/` are type-checked too, with a looser config than the
|
|
55
|
+
library: they are plain JavaScript with no JSDoc on their parameters, and
|
|
56
|
+
annotating a few hundred of them would be churn rather than work. The loose
|
|
57
|
+
config still catches a wrong type and a missing property on a declared
|
|
58
|
+
shape; it does not catch a property that does not exist on an INFERRED
|
|
59
|
+
object literal - TypeScript does not check those in a `.js` file - so an
|
|
60
|
+
object you build and then add to wants a `@type` on it. The comment in
|
|
61
|
+
`tsconfig.scripts.json` says which is which.
|
|
62
|
+
|
|
63
|
+
`npm run check:install` measures an existing OpenCode install and verifies
|
|
64
|
+
the config in `~/.config/opencode/`. It does not install anything itself, and
|
|
65
|
+
it reads your live config. If you are not comfortable with that over your own
|
|
66
|
+
config, run the layers individually and say so in the PR.
|
|
67
|
+
|
|
68
|
+
`eval/ab.mjs` spawns real agents and costs real tokens. It is deliberately
|
|
69
|
+
not part of any check, and a PR does not need it. `npm run measure` does not
|
|
70
|
+
spawn an agent either — it queries the install database read-only.
|
|
71
|
+
|
|
72
|
+
## House rules
|
|
73
|
+
|
|
74
|
+
- Node 22 or newer. The CLI uses `node:` prefixed builtins, so an older Node
|
|
75
|
+
fails at import time rather than with a useful message.
|
|
76
|
+
- No new runtime dependencies without a reason that survives review. A CLI that
|
|
77
|
+
installs is one a lot of people will not install twice.
|
|
78
|
+
- `dist/` is committed because the release tarball needs it. It is generated by
|
|
79
|
+
`npm run build`; never hand-edit it, and never commit it without rebuilding.
|
|
80
|
+
- Match the surrounding comment style: comments explain **why**, especially
|
|
81
|
+
where the obvious version would be a trap.
|
|
82
|
+
|
|
83
|
+
## Pull requests
|
|
84
|
+
|
|
85
|
+
Keep the diff to one concern. Say what you changed, what you measured, and what
|
|
86
|
+
you did not check. If you fixed a bug, the PR should fail before it and pass
|
|
87
|
+
after — say which test does that.
|
|
88
|
+
|
|
89
|
+
The version is set in `package.json` by `npm version`, and the tag is what
|
|
90
|
+
triggers the publish. Keep the two in step: the job publishes the version in
|
|
91
|
+
`package.json`, so a tag that says one version and a file that says another
|
|
92
|
+
is refused by the registry with `EPUBLISHCONFLICT`.
|
|
93
|
+
|
|
94
|
+
## Cutting a release
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
# 1. the version and the changelog entry
|
|
98
|
+
npm version minor # or major, or patch
|
|
99
|
+
$EDITOR CHANGELOG.md # the entry for the new version
|
|
100
|
+
|
|
101
|
+
# 2. the tag, which is what triggers the publish
|
|
102
|
+
git commit -am "release: <version>"
|
|
103
|
+
git tag -a v<version> -m "<what the release is>"
|
|
104
|
+
git push origin main v<version>
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
The tag triggers the workflow, the tests run, and the `publish` job publishes
|
|
108
|
+
the tarball. `npm version` writes the version into `package.json`, and the
|
|
109
|
+
publish job publishes the version in `package.json` — so the tag and
|
|
110
|
+
`package.json` have to agree, or the registry refuses the publish with
|
|
111
|
+
`EPUBLISHCONFLICT`. That is the hazard worth guarding: not the bump, but a
|
|
112
|
+
tag that says one version and a file that says another.
|
|
113
|
+
|
|
114
|
+
### How the publish authenticates
|
|
115
|
+
|
|
116
|
+
Two ways, and the job picks whichever is available:
|
|
117
|
+
|
|
118
|
+
**Trusted publishing (OIDC)** — the default, and what the repository is set up
|
|
119
|
+
for. There is no npm secret in the repository at all: npm exchanges the
|
|
120
|
+
runner's OIDC identity for a short-lived publish token scoped to the workflow.
|
|
121
|
+
|
|
122
|
+
**A token** — the fallback, for when OIDC is not set up. Set the `NPM_TOKEN`
|
|
123
|
+
repository secret to a granular token scoped to `opencode-harness-kit` with
|
|
124
|
+
**Read and write** on the package. If the secret is present the job uses it;
|
|
125
|
+
if it is absent the job uses OIDC.
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
gh secret set NPM_TOKEN --repo pham-canh/space-harness
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
> **`gh secret set` takes the secret NAME as its first argument**, and the
|
|
132
|
+
> value is pasted at the prompt. `gh secret set <the-token-value>` creates a
|
|
133
|
+
> secret whose *name* is the token - and the name of a secret is visible to
|
|
134
|
+
> everyone who can read the repository's Actions secrets list. If a secret
|
|
135
|
+
> ever shows up named like `npm_...`, delete it and set it again properly.
|
|
136
|
+
|
|
137
|
+
> **A token that can read the package is not necessarily a token that can
|
|
138
|
+
> publish it.** With two-factor authentication on the account, a granular
|
|
139
|
+
> token has to be created with **Bypass two-factor authentication** ticked or
|
|
140
|
+
> the publish is refused with `EOTP - This operation requires a one-time
|
|
141
|
+
> password`, and the status is a plain **401**. `npm whoami` passes, because
|
|
142
|
+
> reading needs no second factor. A 401 on the publish with a working
|
|
143
|
+
> `npm whoami` means the token needs the box ticked, not more permissions.
|
|
144
|
+
|
|
145
|
+
A token needs write access *on the package*, not on the account. npm answers
|
|
146
|
+
**404** for a package the token cannot touch, which reads like a missing
|
|
147
|
+
package rather than a missing permission.
|
|
148
|
+
|
|
149
|
+
### Configuring the trusted publisher
|
|
150
|
+
|
|
151
|
+
npm's web form has four fields and **npm does not validate what you type into
|
|
152
|
+
it** — a typo is discovered at publish time, and npm reports it as
|
|
153
|
+
|
|
154
|
+
```
|
|
155
|
+
OIDC token exchange error - package not found
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
which reads like a missing package. The package is there; the configuration
|
|
159
|
+
is not matching, and npm does not say which field.
|
|
160
|
+
|
|
161
|
+
npm ships `npm trust` for exactly this, and it can also read what is stored.
|
|
162
|
+
So the configuration is set from the command line, where it is compared
|
|
163
|
+
against the identity the workflow will actually present:
|
|
164
|
+
|
|
165
|
+
```bash
|
|
166
|
+
npm install -g npm@latest # npm trust needs 11.15.0 or later
|
|
167
|
+
npm login # 2FA has to be enabled on the account
|
|
168
|
+
oc-harness trust # check, and replace it if it is wrong
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
npm completes a two-factor challenge in a **browser**, and the command opens
|
|
172
|
+
the browser for it on the platform it is running on — `open` on macOS,
|
|
173
|
+
`xdg-open` on Linux, `rundll32` on Windows. Answer there however the account
|
|
174
|
+
is set up — an authenticator app, a security key, or a code sent to the
|
|
175
|
+
email. The URL is printed as well, for a machine with no browser to open, and
|
|
176
|
+
the command says which of the two happened rather than claiming the page is
|
|
177
|
+
open when it is not.
|
|
178
|
+
|
|
179
|
+
A code can also be given on the command line, which skips the browser:
|
|
180
|
+
|
|
181
|
+
```bash
|
|
182
|
+
npx -y opencode-harness-kit@latest trust --otp=123456
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
The wait for a human is `OC_TRUST_WAIT_SECONDS` (600 by default).
|
|
186
|
+
|
|
187
|
+
`oc-harness trust` reads what npm has stored, compares it against the
|
|
188
|
+
workflow's own identity, and replaces it when it differs. npm allows exactly
|
|
189
|
+
one configuration per package and cannot edit it, so replacing means revoking
|
|
190
|
+
first — the command does that.
|
|
191
|
+
|
|
192
|
+
It works from any directory, which matters: a release tool that only runs
|
|
193
|
+
from one place is a release tool that people run from the wrong one, and the
|
|
194
|
+
failure is `Cannot read package.json`, which says nothing about what the
|
|
195
|
+
command was for.
|
|
196
|
+
|
|
197
|
+
To set it without the script, the command is:
|
|
198
|
+
|
|
199
|
+
```bash
|
|
200
|
+
npm trust github opencode-harness-kit \
|
|
201
|
+
--file ci.yml \
|
|
202
|
+
--repo pham-canh/space-harness \
|
|
203
|
+
--allow-publish --allow-stage-publish -y
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
The configuration it writes is:
|
|
207
|
+
|
|
208
|
+
| field | value |
|
|
209
|
+
|---|---|
|
|
210
|
+
| Organization or user | `pham-canh` |
|
|
211
|
+
| Repository | `space-harness` |
|
|
212
|
+
| Workflow filename | `ci.yml` (the filename only, not a path) |
|
|
213
|
+
| Environment name | **empty** |
|
|
214
|
+
| Allowed actions | `npm publish` and `npm stage publish` |
|
|
215
|
+
|
|
216
|
+
**The environment name is the field that catches people.** GitHub only puts an
|
|
217
|
+
`environment` claim in the OIDC token when the job declares one. This
|
|
218
|
+
workflow declares none, so the claim is absent — and a configuration that
|
|
219
|
+
names an environment can never match a token that does not carry one.
|
|
220
|
+
|
|
221
|
+
The workflow is the one in `.github/workflows/ci.yml`, and the claims it
|
|
222
|
+
presents are printed by the publish job before it tries:
|
|
223
|
+
|
|
224
|
+
```
|
|
225
|
+
repository pham-canh/space-harness
|
|
226
|
+
workflow file ci.yml
|
|
227
|
+
environment (absent) - the trusted publisher must name NO environment
|
|
228
|
+
owner pham-canh
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
A newly created trusted publisher has to complete its first successful
|
|
232
|
+
publish **within 2 days**, or it expires and has to be created again.
|
|
233
|
+
|
|
234
|
+
> **Both `npm trust` and `npm publish` need a one-time password**, and the
|
|
235
|
+
> web URL they print is masked in the log — so run them in a terminal, where
|
|
236
|
+
> npm prompts for the code. The token path below needs none of that.
|
|
237
|
+
|
|
238
|
+
The GitHub release is written by hand from the CHANGELOG entry:
|
|
239
|
+
|
|
240
|
+
```bash
|
|
241
|
+
gh release create v<version> --title "<version> - <what it is>" --notes-file <notes>
|
|
242
|
+
```
|
package/GLOBAL.md
CHANGED
|
@@ -12,11 +12,31 @@ worse, not better.
|
|
|
12
12
|
## Verify, then claim
|
|
13
13
|
|
|
14
14
|
A task is finished when its verification command passes, not when the code
|
|
15
|
-
looks right.
|
|
16
|
-
|
|
15
|
+
looks right. Paste the real result, including failures. If you cannot run it,
|
|
16
|
+
say so plainly.
|
|
17
17
|
|
|
18
18
|
Never invent a test result, a benchmark number, a deploy URL, or a file path.
|
|
19
19
|
|
|
20
|
+
**Run the check that covers what you changed, not every check the project
|
|
21
|
+
has.** This is the rule that decides whether the harness is worth having, and
|
|
22
|
+
it was measured:
|
|
23
|
+
|
|
24
|
+
- An absolute rule - "run the project's test, lint and typecheck command" -
|
|
25
|
+
made an agent run the whole suite, and install the dependencies, to rename one
|
|
26
|
+
constant. Across 60 measured runs it was **11.4 bash calls per task against
|
|
27
|
+
0.2 without it**, and it made the answers *worse*, because every extra
|
|
28
|
+
command is another chance to wander off.
|
|
29
|
+
- The narrow rule is: if the task names a verify command, run **that** one. If
|
|
30
|
+
it does not, run the smallest command that covers the code you touched, and
|
|
31
|
+
say which one you ran. If you cannot tell which covers it, run the whole
|
|
32
|
+
suite once - once, not three times.
|
|
33
|
+
- Do not re-run a check that already passed. One run is the result.
|
|
34
|
+
|
|
35
|
+
**Do not install anything.** Not `npm install`, not `npm ci`, not a package
|
|
36
|
+
the task did not ask for. Installing runs code you did not read, and it
|
|
37
|
+
changes the tree you were asked to change. If the task needs a dependency
|
|
38
|
+
that is not there, say so.
|
|
39
|
+
|
|
20
40
|
## Decide, don't ask
|
|
21
41
|
|
|
22
42
|
This is the rule that most changes how a session goes, so it is stated as a
|
|
@@ -87,11 +107,20 @@ to avoid this.
|
|
|
87
107
|
2. `read` with an `offset`/`limit` for the range you need.
|
|
88
108
|
3. Read a file whole only when you are about to edit it.
|
|
89
109
|
|
|
110
|
+
**When the question already names the file, read it.** The rule above is for
|
|
111
|
+
the case where you do not know where something is. Searching for a file you
|
|
112
|
+
were just told the name of is two extra round trips for the same answer, and
|
|
113
|
+
across 60 measured runs the absolute form cost 3.7 `grep` and 4.8 `read` calls
|
|
114
|
+
a task against 1.5 and 1.2 for the conditional one.
|
|
115
|
+
|
|
116
|
+
Read the whole file when you are going to edit it. Read a range when you are
|
|
117
|
+
going to cite a line.
|
|
118
|
+
|
|
90
119
|
## Never
|
|
91
120
|
|
|
92
|
-
- Force-push, rewrite published history, delete a branch or tag,
|
|
93
|
-
a registry (`npm publish`, `gh release`). Push without
|
|
94
|
-
any of these, because they are the ones with no undo.
|
|
121
|
+
- Force-push, rewrite published history, delete a branch or tag, open a pull
|
|
122
|
+
request, or publish to a registry (`npm publish`, `gh release`). Push without
|
|
123
|
+
being asked; ask before any of these, because they are the ones with no undo.
|
|
95
124
|
- Commit a secret. If you find one, report it; do not move it.
|
|
96
125
|
- Read or write `.env`, `.npmrc`, `.netrc`, `.git-credentials`. The guard
|
|
97
126
|
blocks these and will keep blocking them.
|
package/MIGRATION.md
CHANGED
|
@@ -1,3 +1,154 @@
|
|
|
1
|
+
# Migrating
|
|
2
|
+
|
|
3
|
+
Two upgrades change what a user has to do. The most recent one first.
|
|
4
|
+
|
|
5
|
+
- [0.3.x → 0.4.x](#migrating-from-03x-to-04x) — the kit starts enforcing
|
|
6
|
+
things it used to only suggest, and the config says which kit wrote it.
|
|
7
|
+
- [0.2.x → 0.3.0](#migrating-from-02x-to-030) — the single-model profile
|
|
8
|
+
became a fleet.
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# Migrating from 0.3.x to 0.4.x
|
|
13
|
+
|
|
14
|
+
**Nothing you have breaks.** No profile id changed, no file moved, and no
|
|
15
|
+
config field was removed. What changed is that the kit started enforcing
|
|
16
|
+
things it used to only suggest, and it started saying which version wrote
|
|
17
|
+
your config.
|
|
18
|
+
|
|
19
|
+
## 1. The guard now blocks what it used to allow
|
|
20
|
+
|
|
21
|
+
The denylist was a list of patterns the rules asked the agent to respect.
|
|
22
|
+
It is now checked in the code, before the command runs:
|
|
23
|
+
|
|
24
|
+
| Command | 0.3.x | 0.4.x |
|
|
25
|
+
|---|---|---|
|
|
26
|
+
| `npm publish` | allowed, with a warning in the rules | **refused** |
|
|
27
|
+
| `npm install`, `npm ci` | allowed | **asks first** |
|
|
28
|
+
| `git push` | allowed | **asks first** |
|
|
29
|
+
| `gh pr create`, `gh pr merge` | allowed | **refused** |
|
|
30
|
+
|
|
31
|
+
If one of those was load-bearing in your workflow, the honest answer is
|
|
32
|
+
that it was never going to be the kit's call. Nothing is refused silently:
|
|
33
|
+
the reason is printed, and the command is not run.
|
|
34
|
+
|
|
35
|
+
## 2. Your config records the kit that wrote it
|
|
36
|
+
|
|
37
|
+
```jsonc
|
|
38
|
+
"harness": {
|
|
39
|
+
"profile": "fleet-safe",
|
|
40
|
+
"kit": "0.4.4"
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Without it, a config from three releases ago and one from today are the same
|
|
45
|
+
file to `verify`, and the only way to tell them apart is to remember. If
|
|
46
|
+
`kit` is missing, your config was written before 0.4.0 and is still valid —
|
|
47
|
+
re-run `oc-harness use <profile>` to bring it up to date.
|
|
48
|
+
|
|
49
|
+
## 3. The pre-commit hook runs your project's tests, not the kit's
|
|
50
|
+
|
|
51
|
+
This is the change most likely to surprise you. The hook used to run the
|
|
52
|
+
kit's own test suite against the kit's own repository. In a project of
|
|
53
|
+
yours, that suite passed or failed for reasons that had nothing to do with
|
|
54
|
+
you — and it blocked every commit in the process.
|
|
55
|
+
|
|
56
|
+
The hook is now installed only where it belongs:
|
|
57
|
+
|
|
58
|
+
- in the kit's own repository, and
|
|
59
|
+
- in a project of yours, if you ask for it with `oc-harness install --hook`.
|
|
60
|
+
|
|
61
|
+
Where it is installed, it runs **your** project's test script, and only that.
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
oc-harness install --hook
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## 4. The kit works in a directory that is not a git repository
|
|
68
|
+
|
|
69
|
+
The kit used to find the project root through the git worktree. In a
|
|
70
|
+
directory that is not a repository, that lookup returned the filesystem root
|
|
71
|
+
- so the kit found no project, enabled nothing, and reported itself healthy
|
|
72
|
+
while doing nothing at all.
|
|
73
|
+
|
|
74
|
+
The project root is now the directory you are in. If you want it to find
|
|
75
|
+
the repository above you, run the kit from inside it.
|
|
76
|
+
|
|
77
|
+
## 5. `OPENCODE_HARNESS_PROFILE` names a profile, not a path
|
|
78
|
+
|
|
79
|
+
The variable was checked as if it were a file path, so it never resolved
|
|
80
|
+
and the override never took effect. It names a profile id:
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
export OPENCODE_HARNESS_PROFILE=fleet-safe
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## 6. The guard reads the whole command line
|
|
87
|
+
|
|
88
|
+
The denylist used to be matched against the raw command, so the commands it
|
|
89
|
+
names could be reached through a wrapper. They cannot any more:
|
|
90
|
+
|
|
91
|
+
```
|
|
92
|
+
cd /tmp && npm publish blocked
|
|
93
|
+
sudo npm publish blocked
|
|
94
|
+
sh -c "npm publish" blocked
|
|
95
|
+
sudo bash -c "npm publish" blocked
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
The rules the kit already had - matched per segment, with the wrappers
|
|
99
|
+
stripped and the payload of a `bash -c` followed - are the ones the denylist
|
|
100
|
+
uses now. A command that reaches the guard through a shape the kit does not
|
|
101
|
+
know about is still let through, so this is a much taller fence, not a
|
|
102
|
+
proof.
|
|
103
|
+
|
|
104
|
+
## 7. New commands
|
|
105
|
+
|
|
106
|
+
None of these replace anything. `oc-harness help` lists all of them.
|
|
107
|
+
|
|
108
|
+
| Command | What it is for |
|
|
109
|
+
|---|---|
|
|
110
|
+
| `oc-harness doctor --watch` | Poll the catalogue and report only what changed. Free models are withdrawn in days, and a weekly check is the right rhythm. |
|
|
111
|
+
| `oc-harness upgrade` | Check for a newer kit, refresh the profiles, and write the config again. |
|
|
112
|
+
| `oc-harness cost` | What the kit is doing on THIS project, in numbers: characters pruned, tool outputs stubbed, lanes sorted by cost. |
|
|
113
|
+
| `oc-harness backups`, `oc-harness restore` | The old config is now kept as a dated copy with the profile id in it, and it can be put back. |
|
|
114
|
+
| `oc-harness uninstall` | Remove the symlinks the install created. `npm uninstall` leaves them behind, and opencode then loads neither the rules nor the guard. |
|
|
115
|
+
| `oc-harness doctor --json` | The same report, machine-readable. |
|
|
116
|
+
| `oc-harness show <id> --json` | The resolved profile, machine-readable. |
|
|
117
|
+
|
|
118
|
+
Every command that can fail says so in its exit code, and
|
|
119
|
+
[`docs/EXIT-CODES.md`](docs/EXIT-CODES.md) lists them. The four that matter
|
|
120
|
+
most: `run` exits 1 when there is no task file, 2 when the work needs a
|
|
121
|
+
person, 3 when the agent failed and 4 when the verify failed.
|
|
122
|
+
|
|
123
|
+
## 8. The effort tier `"none"` means what it says
|
|
124
|
+
|
|
125
|
+
A model that does not publish a `"none"` effort variant no longer gets one
|
|
126
|
+
invented for it. It runs on its own default effort, and the config says
|
|
127
|
+
which model served the request.
|
|
128
|
+
|
|
129
|
+
## What did not change
|
|
130
|
+
|
|
131
|
+
- The profile ids, the lane table, the plugin hook names (`guard`, `prune`,
|
|
132
|
+
`router`, `telemetry`), and the shape of `retention.yml`.
|
|
133
|
+
- `oc-harness list`, `show`, `install`, `use`, `verify`, `refresh`, `baseline`,
|
|
134
|
+
`lanes` and `trust` keep their arguments.
|
|
135
|
+
- The config format is unchanged. A config written by 0.3.x is read
|
|
136
|
+
correctly by 0.4.x; it is only missing the `kit` field.
|
|
137
|
+
|
|
138
|
+
## If something looks wrong
|
|
139
|
+
|
|
140
|
+
```bash
|
|
141
|
+
oc-harness doctor # what the kit sees, and what it would fix
|
|
142
|
+
oc-harness verify # whether the install matches the profile
|
|
143
|
+
oc-harness use fleet-safe && oc-harness install && oc-harness verify
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
The last line rewrites the config from the profile and checks it. It is
|
|
147
|
+
safe: the old config is written to `~/.config/opencode/backups/` first, and
|
|
148
|
+
`oc-harness restore` puts it back.
|
|
149
|
+
|
|
150
|
+
---
|
|
151
|
+
|
|
1
152
|
# Migrating from 0.2.x to 0.3.0
|
|
2
153
|
|
|
3
154
|
0.3.0 replaces the single-model profile with a **fleet**: ten jobs, ten free
|