opencode-harness-kit 0.5.3 → 0.5.5

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 CHANGED
@@ -12,25 +12,194 @@ is not happening.
12
12
 
13
13
  ---
14
14
 
15
- ## [0.5.2] — 2026-10-21
15
+ ## [0.5.5] — 2026-10-21
16
16
 
17
- **Not published.** The tag was cut and pushed, the publish job ran, and npm
18
- refused the publish - so there is no 0.5.2 on the registry. The changes
19
- written for it shipped in 0.5.3.
17
+ Published. The tag is what cut it: `git tag v0.5.5 && git push origin main
18
+ v0.5.5`, and the publish job watches for exactly that.
20
19
 
21
- What npm said was `OIDC token exchange error - package not found`, which
22
- reads like a missing package. The package was there; the trusted publisher
23
- was not, because npm looks a publisher up by (package, repository) and the
24
- repository had just been renamed. The stored entry still named
25
- `pham-canh/space-harness`; the claim the runner presents names
26
- `pham-canh/opencode-harness-kit`. The package's name is in the error, and
27
- the field that was wrong is not.
20
+ A patch, and a large one: thirty-odd defects, nearly all of them the kind
21
+ this kit exists to catch - a command that reported success while the thing
22
+ it promised was not happening. Most of them were found by reading the code
23
+ with the question "what does this say when it did nothing?", and every one
24
+ of them now has a test that fails without the fix.
28
25
 
29
- The entry this release was going to carry said that "the npm trusted
30
- publisher was re-pointed at the new name". It had not been. The re-point is
31
- an account change on npm and it needs the account's second factor, and a
32
- changelog that says a thing has been done that has not been done is worse
33
- than one that says nothing.
26
+ ### Fixed
27
+
28
+ **The installer**
29
+
30
+ - **The install said "installed into" when it had linked nothing.** A link
31
+ that could not be created was a warning in a corner of the output, and the
32
+ command exited 0. A config directory the user could not write to produced a
33
+ green install and a kit that was not there. A failed link is now exit 1.
34
+
35
+ - **A file of the user's own was left alone, and the install said
36
+ "installed".** The installer refuses to destroy a file it did not put
37
+ there, which is right; the tick was not. A target that was left alone is
38
+ now named, in place of the tick, and `verify` reports the file that is not
39
+ the kit's.
40
+
41
+ - **Answering "yes" at the overwrite prompt replaced nothing.** The answer
42
+ was collected and thrown away: the linker refused to replace a real file
43
+ whatever the user had said. "yes" now replaces the file, and "no" leaves
44
+ it.
45
+
46
+ - **`verify` called a prompt installed when it was the user's own file.** The
47
+ check asked whether a file existed at the path, not whether it was the
48
+ kit's - so a user with their own `prompts/build.md` had a lane running on
49
+ their own instructions, with a green tick next to it. The same is now
50
+ checked for `GLOBAL.md` and for the kit's skills.
51
+
52
+ - **`verify` failed an agent file that mentioned its own config.** The
53
+ pattern read `opencode/opencode.jsonc` as a model that was not in the
54
+ profile.
55
+
56
+ - **`verify` called a relative instruction path resolved.** opencode ignores
57
+ relative instruction paths, and the check resolved it against the
58
+ directory the command happened to be run from - so the verdict was a
59
+ statement about the shell's working directory.
60
+
61
+ - **`uninstall` reported links it could not remove.** A directory the user
62
+ could not write to was reported as "removed prompts/ (10 link(s))" while
63
+ all ten links were still there.
64
+
65
+ - **`use` overwrote the config when the backup could not be written.** The
66
+ prompt promises "a dated backup is kept in backups/", and the backup was
67
+ best-effort: a failure was not even mentioned. The overwrite is refused
68
+ now, and the backups directory keeps ten configs instead of one.
69
+
70
+ - **One malformed line lost the whole prune log.** The parse was wrapped
71
+ around the loop, so a single bad record threw the file away and `cost`
72
+ said the pruner had never run.
73
+
74
+ **The guard**
75
+
76
+ - **The pipe-to-a-shell rule missed `curl … | sh; echo done`.** A `;` inside
77
+ a pipe stage left the shell's name glued to the punctuation, so the stage
78
+ was not read as a shell - and the guard was the only layer that had it.
79
+
80
+ - **`bash -c"rm -rf /"` was never inspected.** The glued form of the flag
81
+ defeated the payload extraction.
82
+
83
+ - **A wrapper named by its path defeated the prefix stripping.**
84
+ `/usr/bin/env rm -rf /` was allowed, while `env rm -rf /` was blocked.
85
+
86
+ - **`rm --recursive --force /` was allowed** by the rule that exists to
87
+ block it, which knew only the short flags.
88
+
89
+ - **A credential name with a prefix was not a credential name.**
90
+ `GITHUB_TOKEN=$(curl …)` was allowed, because the word boundary never
91
+ fires after an underscore.
92
+
93
+ - **`chmod 0777` was allowed** by the rule that blocks `chmod 777`.
94
+
95
+ - **A tool's own global flags stepped over the denylist.**
96
+ `gh -R owner/repo pr create` and `npm --prefix /tmp publish` were allowed.
97
+
98
+ - **A patch that deleted a file outside the project was allowed.** The
99
+ deletion names the file in the `---` header, and that header was not read,
100
+ so the path was never scope-checked.
101
+
102
+ **The merge and the profiles**
103
+
104
+ - **The user's own bash rules were deleted from their config.** The kit's
105
+ allowlist and denylist replaced the map wholesale, so every rule the user
106
+ had was gone after the next `oc-harness use`. The user's rules are merged
107
+ in, and the kit's deny rules still win.
108
+
109
+ - **A string-valued `instructions` was dropped** from the user's config.
110
+
111
+ - **The utility route was not counted towards the retention the file
112
+ claimed.** A may-train model could be written into the config as
113
+ `small_model` while the header said "zero-retention" - and the file says
114
+ "zero-retention" to a human who reads it.
115
+
116
+ - **`resolveEffort` could snap a request to `none`**, which is reasoning
117
+ off rather than a rung.
118
+
119
+ - **`validate()` accepted a limit that was not an integer** (a context of
120
+ `1.5` produced a negative prune threshold), an effort level that is not
121
+ on the scale, a retention of "unknown", a base model nobody had recorded,
122
+ and a retention claim that was safer than the models allowed. A claim that
123
+ is *worse* than reality is still allowed: cautious is not wrong.
124
+
125
+ - **A profile whose `id` did not match its file name was loaded anyway**,
126
+ and the config then told the user to edit a file that does not exist.
127
+
128
+ **The runtime**
129
+
130
+ - **The router never recorded a spent route.** It read the model from
131
+ `properties.modelID`, and no opencode event carries a model there - the
132
+ event that has one nests it under `properties.info`. So the failover was
133
+ dead code: the health file was never written, the warning never fired, and
134
+ the fallback chain was never walked.
135
+
136
+ - **Any "429" anywhere in an event spent a live route.** The classifier ran
137
+ over the whole serialised event, so a message whose token count was 429
138
+ was recorded as a failed route.
139
+
140
+ - **A spent route never came back.** The entry carries a timestamp and
141
+ nothing ever read it, so one transient rate limit demoted the model for
142
+ the life of the project directory. The window is the provider's day.
143
+
144
+ - **The pruner booked a saving on turns where the request got bigger.** The
145
+ stub's own metadata is part of the request that goes out, and the log
146
+ measured the text inside the part - so the number was a claim about
147
+ something other than the request. It is the request's size now, and a turn
148
+ that grew reports a negative saving.
149
+
150
+ - **A task marked `blocked` lost its block** when it had an `output:` field:
151
+ the status line was written inside the output block, and the parser folded
152
+ the output back into it. A task nested under another task's output was
153
+ DELETED by the rewrite.
154
+
155
+ - **The telemetry rotation destroyed the previous generation.** The writer
156
+ renamed the current file straight to `.1`, and a rename replaces the
157
+ destination - so the oldest history was gone after two rotations and the
158
+ third generation the reader looks for never existed.
159
+
160
+ - **The trusted-publishing setup could hang for hours.** The wait for the
161
+ browser answer had no timeout, so the documented window did not bound it.
162
+ The list of trusted publishers is also read in npm's own format now, which
163
+ is one JSON object per line rather than an array.
164
+
165
+ - **The two sqlite backends disagreed** about a query with two statements:
166
+ the command line ran both and the python fallback refused.
167
+
168
+ ### Changed
169
+
170
+ - **The install's exit code follows `docs/EXIT-CODES.md`**: a target left
171
+ alone is exit 0 with the reason printed, and a step that failed is exit 1.
172
+
173
+ - **`savedChars` is the request's size delta**, not the text delta, and it
174
+ can be negative. `cost` says "characters ADDED" when it is negative,
175
+ because a number with the wrong sign on it is a lie in a different
176
+ direction.
177
+
178
+ ## [0.5.4] — 2026-10-21
179
+
180
+ Published. The tag is what cut it: `git tag v0.5.4 && git push origin main
181
+ v0.5.4`, and the publish job watches for exactly that.
182
+
183
+ A patch, and the patch is the publish path. 0.5.3 was the first release to
184
+ reach the registry since the rename, and it reached it through trusted
185
+ publishing with a signed provenance statement - so the path works, and this
186
+ release is the one that says so where a reader will look for it.
187
+
188
+ ### Changed
189
+
190
+ - **The npm trusted publisher is configured for
191
+ `pham-canh/opencode-harness-kit`**: `ci.yml`, no environment, publish and
192
+ stage. It is the one thing that was missing when 0.5.2 was refused, and it
193
+ is set now. The re-point is an account change on npm, so it needed the
194
+ account's second factor - and a rename is not a thing npm does for you.
195
+
196
+ - **The publish token secret is gone.** The job can publish with a token
197
+ when there is one, and the secret was set while 0.5.3 was cut, because a
198
+ release that cannot publish is not a release. It is removed now that the
199
+ OIDC path is proven: a long-lived token in the repository is a secret to
200
+ rotate for a path that is not being used, and npm is restricting the
201
+ tokens that bypass two-factor authentication for direct publishing in
202
+ January 2027, so the token path was on its way out anyway.
34
203
 
35
204
  ## [0.5.3] — 2026-10-21
36
205
 
@@ -90,6 +259,25 @@ rename was written for - never reached the registry.
90
259
  the moment the thing it films changes. The recording guide is on the
91
260
  machine that records.
92
261
 
262
+ ## [0.5.2] — 2026-10-21
263
+
264
+ **Not published.** The tag was cut and pushed, the publish job ran, and npm
265
+ refused the publish - so there is no 0.5.2 on the registry. The changes
266
+ written for it shipped in 0.5.3.
267
+
268
+ What npm said was `OIDC token exchange error - package not found`, which
269
+ reads like a missing package. The package was there. The trusted publisher
270
+ was not: npm reports no trusted publisher configured for this package, and
271
+ the repository had been renamed, so a publisher that named the old
272
+ repository would not have matched the claim the runner presents either. The
273
+ package's name is in the error, and the field that was wrong is not.
274
+
275
+ The entry this release was going to carry said that "the npm trusted
276
+ publisher was re-pointed at the new name". It had not been. The re-point is
277
+ an account change on npm and it needs the account's second factor, and
278
+ nothing had done it. A changelog that says a thing has been done that has
279
+ not been done is worse than one that says nothing.
280
+
93
281
  ## [0.5.1] — 2026-10-21
94
282
 
95
283
  Published. The tag is what cut it: `git tag v0.5.1 && git push origin main
@@ -1208,7 +1396,9 @@ silent in the worst way:
1208
1396
 
1209
1397
  ---
1210
1398
 
1211
- [Unreleased]: https://github.com/pham-canh/opencode-harness-kit/compare/v0.5.3...HEAD
1399
+ [Unreleased]: https://github.com/pham-canh/opencode-harness-kit/compare/v0.5.5...HEAD
1400
+ [0.5.5]: https://github.com/pham-canh/opencode-harness-kit/compare/v0.5.4...v0.5.5
1401
+ [0.5.4]: https://github.com/pham-canh/opencode-harness-kit/compare/v0.5.3...v0.5.4
1212
1402
  [0.5.3]: https://github.com/pham-canh/opencode-harness-kit/compare/v0.5.2...v0.5.3
1213
1403
  [0.5.2]: https://github.com/pham-canh/opencode-harness-kit/compare/v0.5.1...v0.5.2
1214
1404
  [0.5.1]: https://github.com/pham-canh/opencode-harness-kit/compare/v0.5.0...v0.5.1