vinta-ai-workflows 0.7.0-alpha4 → 0.7.0-alpha6

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
@@ -7,6 +7,8 @@ the project follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
8
  ## [0.7.0] — YYYY-MM-DD
9
9
 
10
+ <!-- pre-release: 0.7.0-alpha6 on 2026-09-13 -->
11
+ <!-- pre-release: 0.7.0-alpha5 on 2026-09-13 -->
10
12
  <!-- pre-release: 0.7.0-alpha4 on 2026-09-13 -->
11
13
  <!-- pre-release: 0.7.0-alpha3 on 2026-09-12 -->
12
14
  <!-- pre-release: 0.7.0-alpha2 on 2026-09-12 -->
@@ -219,6 +221,140 @@ the project follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
219
221
 
220
222
  ### Fixed
221
223
 
224
+ - **An agent can run a shell command.** `auto` mapped to the vendor's
225
+ `acceptEdits`, which accepts file *edits* and nothing else — a shell command
226
+ still goes to a permission prompt, and in `-p` there is nobody to answer one.
227
+ A run of eight phases died of it: the agents wrote their code and were then
228
+ refused `ruff`, `pytest`, `git add` and `docker compose`, **69 denials across
229
+ two lanes**, every gate failing on work that was never allowed to be checked.
230
+ `auto` now allows `Bash` in the policy file it already writes.
231
+
232
+ What that costs is worth stating plainly: **`Bash` was never confined to the
233
+ lane.** The deny list covers the file-editing tools and a shell redirection
234
+ walks through it, so allowing the shell allows commands on the machine.
235
+ `auto` has always promised exactly this in words — "the agent works unattended
236
+ inside its lane" — and this is the first version where the words are true.
237
+ `ask` still does not allow it: that mode exists for a human at the browser,
238
+ and the prompt is its purpose.
239
+
240
+ - **A refusal says why, in the words the harness used.** `permission_denied`
241
+ carried a decision token and deliberately dropped the sentence beside it, on
242
+ §11 grounds. Then a run failed with forty-five denials reading
243
+ `reason: "other"`, and finding out what that meant cost an afternoon and a
244
+ rebuilt reproduction — the sentence said "this Bash command contains multiple
245
+ operations; the following parts require approval". §11 keeps repository
246
+ *contents* out of the record; a refusal's own explanation is not contents, and
247
+ the `tool_use` row above it already carries the path and the command verbatim.
248
+ Withholding it protected nothing and hid the one fact worth having.
249
+
250
+ - **`serve` opens a run that has already finished.** The API resolved a run from
251
+ the in-memory registry *and* the journal and required both, so a daemon
252
+ started with nothing running listed the operator's history — the list reads
253
+ the journal — and then answered 404 for every run in it, under a message
254
+ saying the daemon was not running. Reads now need only the journal, which is
255
+ where a run's whole record lives and which outlives the daemon by design
256
+ (§5.3). Steering a finished run is still refused, with `409` rather than
257
+ `404`: the run exists, and saying it does not sends the operator hunting for a
258
+ typo instead of reading the status in front of them.
259
+
260
+ - **Four places the UI asked the operator to work around it.** The transcript
261
+ opened at the *oldest* row it held, so a live agent's newest line — the one
262
+ the panel was opened to read — sat below the fold and every arriving entry
263
+ pushed it further down; it now opens at the newest and stays there, but only
264
+ while the operator is already at the bottom, because scrolling up is reading.
265
+ The `git diff` command overflowed its panel, uncopyable without selecting
266
+ blind, and now wraps. The shell's bounded column went from 1280px to 1600px:
267
+ 1280 is a reading measure, and the Nodes table's columns are ids, lane names
268
+ and branch names, none of which can be abbreviated without losing what
269
+ identifies them. And the notification interval said "Remind every 5 min"
270
+ without ever saying what it would remind anyone about — it repeats the
271
+ notification for a phase that stopped to ask the operator something, until
272
+ they answer, which is what the options say now.
273
+
274
+ - **A killed terminal releases its directory on Windows.** Two PTY tests failed
275
+ teardown with `EBUSY: rmdir`: killing a process there is not synchronous with
276
+ releasing what it held, so the conpty and its background child are gone as far
277
+ as the test is concerned while the OS still has the working directory open.
278
+
279
+ - **A failed phase can be retried instead of ending the run.** `run` takes
280
+ `--on-failure <stop|ask>`. `stop` is the default and is what every run has
281
+ always done — the phase fails, its dependents block, the run finishes. `ask`
282
+ parks the node on a question instead: retry, retry with another member of the
283
+ crew, or stop.
284
+
285
+ It exists because the failures worth retrying are overwhelmingly
286
+ environmental — a permission wall, a grant nobody made, a gate whose service
287
+ was not up — and the only recovery was to start the whole plan again, running
288
+ every phase that had already succeeded a second time. Only pass `ask` when
289
+ somebody is watching: the run waits, which is exactly why it is not the
290
+ default.
291
+
292
+ The alternatives offered are **members of the crew, not models**. A staffed
293
+ run has no free-floating models in it — a phase is taken by a member, and the
294
+ tier floor that decides who may take it is the assigned member's own — so a
295
+ model is something the plan cannot express and nobody could be found to hold.
296
+ A member below the phase's tier is never offered: an operator answering a
297
+ question is not a reason to hand a phase to somebody the plan judged too
298
+ junior for it.
299
+
300
+ The retry starts **cold**, and everything the node held goes back before it
301
+ waits (§6.1) — an operator at lunch must not be holding a lane another phase
302
+ could use.
303
+
304
+ - **A refusal nobody was asked about is now said out loud.** The adapter knew
305
+ about `permission_request`, a question waiting for an answer, and nothing
306
+ else. The refusal an operator actually hits is not a question: a read outside
307
+ the working directory is decided by the CLI and announced as
308
+ `permission_denied`, with no request to reply to. That frame was dropped at
309
+ the first `switch` — no event, no journal row, no transcript line. The new
310
+ `permission_denied` event carries the decision token (`workingDir`, `mode`)
311
+ and never the vendor's prose, which names the file being read (§11).
312
+
313
+ - **A turn that ended blocked is no longer a turn that succeeded.** The CLI
314
+ says `status_category: "blocked"` one frame before reporting
315
+ `is_error: false`, and both are true from its side: it was asked for
316
+ something it could not do and said so. Taking the second at its word is how a
317
+ phase passed having written no code and then failed two steps later under
318
+ another name. A session that reported an error no longer ends `ok` — which
319
+ also makes a reviewer fail closed, since its verdict is read back out of a
320
+ transcript whose session did not end cleanly.
321
+
322
+ - **An agent still could not write in its own lane.** The entry below passed
323
+ claude-code `--permission-mode auto`, which matched our own vocabulary for
324
+ "works unattended" and is not what the vendor means by the word: `auto` still
325
+ routes a write to a permission prompt, and in `-p` there is nobody to answer
326
+ one. Run against the CLI, a `Write` to the agent's *own working directory*
327
+ comes back denied with no reason attached — the same dead end, wearing the
328
+ word that made it look closed. `acceptEdits` is the mode under which that
329
+ write succeeds, and is what `auto` now maps to. The test covering this
330
+ asserted the word rather than the behaviour, so it pinned the bug in place.
331
+
332
+ - **A phase can read the operator's checkout.** A lane is a worktree cut from a
333
+ branch, so anything uncommitted — a plan written this morning, a spec that
334
+ never leaves the operator's machine — is present where they are and absent
335
+ from every lane. Reaching for it was refused before the model saw a byte, with
336
+ a message that reads like a prompt awaiting an answer ("Claude requested
337
+ permissions to read from …, but you haven't granted it yet") when in fact
338
+ nothing is asking: the CLI denies it outright, emits no permission request,
339
+ and the session then ends *successfully*, having written nothing.
340
+
341
+ The repository root is now granted to every claude-code agent for **reading**.
342
+ Granting a directory also grants writing in it, and the lane sits inside the
343
+ directory being granted, so the grant is paired with a deny list that keeps
344
+ the lane the only writable place under it — the operator's source and every
345
+ sibling lane stay refused. That list names the *siblings* at each level down
346
+ to the lane rather than the root itself, because the vendor resolves deny
347
+ before allow with no carve-out: `deny: <repo>/**` plus `allow: <lane>/**`
348
+ refuses the lane too. Each of those facts was established by running the CLI.
349
+
350
+ **This covers the file-editing tools and not `Bash`.** A shell redirection was
351
+ never confined to the working directory and is not confined now; that boundary
352
+ is the OS's, and the vendor's sandbox that enforces it also switches off the
353
+ network a phase needs to install anything.
354
+
355
+ codex needed nothing: under `--approve-for-me` it already reads anywhere on
356
+ disk, which was confirmed the same way.
357
+
222
358
  - **An agent can write in its own lane.** Every adapter declared
223
359
  `permissionControl: true` and passed no policy at all: claude-code was spawned
224
360
  as `-p --output-format stream-json …` with no `--permission-mode`, and codex as
package/package.json CHANGED
@@ -1,16 +1,11 @@
1
1
  {
2
2
  "name": "vinta-ai-workflows",
3
- "version": "0.7.0-alpha4",
3
+ "version": "0.7.0-alpha6",
4
4
  "description": "Bootstrap AI tooling (AGENTS.md, skills, sub-agents) across Claude Code, Codex, Cursor, and VS Code + GitHub Copilot.",
5
5
  "type": "module",
6
- "packageManager": "pnpm@10.33.0",
7
6
  "bin": {
8
7
  "vinta-ai-workflows": "./vinta-ai-workflows.mjs"
9
8
  },
10
- "scripts": {
11
- "check-ai-models": "node scripts/check-ai-models.mjs",
12
- "test": "node --test tests/*.test.mjs"
13
- },
14
9
  "devDependencies": {
15
10
  "yaml": "^2.4.0"
16
11
  },
@@ -26,10 +21,14 @@
26
21
  },
27
22
  "repository": {
28
23
  "type": "git",
29
- "url": "git+ssh://git@github.com:vintasoftware/vinta-ai-workflows.git"
24
+ "url": "git+https://github.com/vintasoftware/vinta-ai-workflows.git"
30
25
  },
31
26
  "publishConfig": {
32
27
  "access": "public"
33
28
  },
34
- "license": "MIT"
35
- }
29
+ "license": "MIT",
30
+ "scripts": {
31
+ "check-ai-models": "node scripts/check-ai-models.mjs",
32
+ "test": "node --test tests/*.test.mjs"
33
+ }
34
+ }