vinta-ai-workflows 0.7.0-alpha3 → 0.7.0-alpha5
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 +178 -0
- package/package.json +8 -9
- package/skills/vinta-derive-skills/resources/foundation-skills/open-pr-from-context/scripts/open-pr.sh +0 -0
- package/skills/vinta-derive-skills/resources/foundation-skills/prepare-worktree/scripts/claude-worktree-write-guard.py +0 -0
- package/skills/vinta-derive-skills/resources/foundation-skills/prepare-worktree/scripts/gen-claude-sandbox-settings.sh +0 -0
- package/skills/vinta-derive-skills/resources/foundation-skills/prepare-worktree/scripts/gen-compose-worktree-override.sh +0 -0
- package/skills/vinta-derive-skills/resources/foundation-skills/prepare-worktree/scripts/sandbox-run.sh +0 -0
- package/skills/vinta-install-ai-tools-setup/resources/setup-ai-tools.mjs +0 -0
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-alpha5 on 2026-09-13 -->
|
|
11
|
+
<!-- pre-release: 0.7.0-alpha4 on 2026-09-13 -->
|
|
10
12
|
<!-- pre-release: 0.7.0-alpha3 on 2026-09-12 -->
|
|
11
13
|
<!-- pre-release: 0.7.0-alpha2 on 2026-09-12 -->
|
|
12
14
|
<!-- pre-release: 0.7.0-alpha1 on 2026-09-11 -->
|
|
@@ -218,6 +220,182 @@ the project follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
|
218
220
|
|
|
219
221
|
### Fixed
|
|
220
222
|
|
|
223
|
+
- **Four places the UI asked the operator to work around it.** The transcript
|
|
224
|
+
opened at the *oldest* row it held, so a live agent's newest line — the one
|
|
225
|
+
the panel was opened to read — sat below the fold and every arriving entry
|
|
226
|
+
pushed it further down; it now opens at the newest and stays there, but only
|
|
227
|
+
while the operator is already at the bottom, because scrolling up is reading.
|
|
228
|
+
The `git diff` command overflowed its panel, uncopyable without selecting
|
|
229
|
+
blind, and now wraps. The shell's bounded column went from 1280px to 1600px:
|
|
230
|
+
1280 is a reading measure, and the Nodes table's columns are ids, lane names
|
|
231
|
+
and branch names, none of which can be abbreviated without losing what
|
|
232
|
+
identifies them. And the notification interval said "Remind every 5 min"
|
|
233
|
+
without ever saying what it would remind anyone about — it repeats the
|
|
234
|
+
notification for a phase that stopped to ask the operator something, until
|
|
235
|
+
they answer, which is what the options say now.
|
|
236
|
+
|
|
237
|
+
- **A killed terminal releases its directory on Windows.** Two PTY tests failed
|
|
238
|
+
teardown with `EBUSY: rmdir`: killing a process there is not synchronous with
|
|
239
|
+
releasing what it held, so the conpty and its background child are gone as far
|
|
240
|
+
as the test is concerned while the OS still has the working directory open.
|
|
241
|
+
|
|
242
|
+
- **A failed phase can be retried instead of ending the run.** `run` takes
|
|
243
|
+
`--on-failure <stop|ask>`. `stop` is the default and is what every run has
|
|
244
|
+
always done — the phase fails, its dependents block, the run finishes. `ask`
|
|
245
|
+
parks the node on a question instead: retry, retry with another member of the
|
|
246
|
+
crew, or stop.
|
|
247
|
+
|
|
248
|
+
It exists because the failures worth retrying are overwhelmingly
|
|
249
|
+
environmental — a permission wall, a grant nobody made, a gate whose service
|
|
250
|
+
was not up — and the only recovery was to start the whole plan again, running
|
|
251
|
+
every phase that had already succeeded a second time. Only pass `ask` when
|
|
252
|
+
somebody is watching: the run waits, which is exactly why it is not the
|
|
253
|
+
default.
|
|
254
|
+
|
|
255
|
+
The alternatives offered are **members of the crew, not models**. A staffed
|
|
256
|
+
run has no free-floating models in it — a phase is taken by a member, and the
|
|
257
|
+
tier floor that decides who may take it is the assigned member's own — so a
|
|
258
|
+
model is something the plan cannot express and nobody could be found to hold.
|
|
259
|
+
A member below the phase's tier is never offered: an operator answering a
|
|
260
|
+
question is not a reason to hand a phase to somebody the plan judged too
|
|
261
|
+
junior for it.
|
|
262
|
+
|
|
263
|
+
The retry starts **cold**, and everything the node held goes back before it
|
|
264
|
+
waits (§6.1) — an operator at lunch must not be holding a lane another phase
|
|
265
|
+
could use.
|
|
266
|
+
|
|
267
|
+
- **A refusal nobody was asked about is now said out loud.** The adapter knew
|
|
268
|
+
about `permission_request`, a question waiting for an answer, and nothing
|
|
269
|
+
else. The refusal an operator actually hits is not a question: a read outside
|
|
270
|
+
the working directory is decided by the CLI and announced as
|
|
271
|
+
`permission_denied`, with no request to reply to. That frame was dropped at
|
|
272
|
+
the first `switch` — no event, no journal row, no transcript line. The new
|
|
273
|
+
`permission_denied` event carries the decision token (`workingDir`, `mode`)
|
|
274
|
+
and never the vendor's prose, which names the file being read (§11).
|
|
275
|
+
|
|
276
|
+
- **A turn that ended blocked is no longer a turn that succeeded.** The CLI
|
|
277
|
+
says `status_category: "blocked"` one frame before reporting
|
|
278
|
+
`is_error: false`, and both are true from its side: it was asked for
|
|
279
|
+
something it could not do and said so. Taking the second at its word is how a
|
|
280
|
+
phase passed having written no code and then failed two steps later under
|
|
281
|
+
another name. A session that reported an error no longer ends `ok` — which
|
|
282
|
+
also makes a reviewer fail closed, since its verdict is read back out of a
|
|
283
|
+
transcript whose session did not end cleanly.
|
|
284
|
+
|
|
285
|
+
- **An agent still could not write in its own lane.** The entry below passed
|
|
286
|
+
claude-code `--permission-mode auto`, which matched our own vocabulary for
|
|
287
|
+
"works unattended" and is not what the vendor means by the word: `auto` still
|
|
288
|
+
routes a write to a permission prompt, and in `-p` there is nobody to answer
|
|
289
|
+
one. Run against the CLI, a `Write` to the agent's *own working directory*
|
|
290
|
+
comes back denied with no reason attached — the same dead end, wearing the
|
|
291
|
+
word that made it look closed. `acceptEdits` is the mode under which that
|
|
292
|
+
write succeeds, and is what `auto` now maps to. The test covering this
|
|
293
|
+
asserted the word rather than the behaviour, so it pinned the bug in place.
|
|
294
|
+
|
|
295
|
+
- **A phase can read the operator's checkout.** A lane is a worktree cut from a
|
|
296
|
+
branch, so anything uncommitted — a plan written this morning, a spec that
|
|
297
|
+
never leaves the operator's machine — is present where they are and absent
|
|
298
|
+
from every lane. Reaching for it was refused before the model saw a byte, with
|
|
299
|
+
a message that reads like a prompt awaiting an answer ("Claude requested
|
|
300
|
+
permissions to read from …, but you haven't granted it yet") when in fact
|
|
301
|
+
nothing is asking: the CLI denies it outright, emits no permission request,
|
|
302
|
+
and the session then ends *successfully*, having written nothing.
|
|
303
|
+
|
|
304
|
+
The repository root is now granted to every claude-code agent for **reading**.
|
|
305
|
+
Granting a directory also grants writing in it, and the lane sits inside the
|
|
306
|
+
directory being granted, so the grant is paired with a deny list that keeps
|
|
307
|
+
the lane the only writable place under it — the operator's source and every
|
|
308
|
+
sibling lane stay refused. That list names the *siblings* at each level down
|
|
309
|
+
to the lane rather than the root itself, because the vendor resolves deny
|
|
310
|
+
before allow with no carve-out: `deny: <repo>/**` plus `allow: <lane>/**`
|
|
311
|
+
refuses the lane too. Each of those facts was established by running the CLI.
|
|
312
|
+
|
|
313
|
+
**This covers the file-editing tools and not `Bash`.** A shell redirection was
|
|
314
|
+
never confined to the working directory and is not confined now; that boundary
|
|
315
|
+
is the OS's, and the vendor's sandbox that enforces it also switches off the
|
|
316
|
+
network a phase needs to install anything.
|
|
317
|
+
|
|
318
|
+
codex needed nothing: under `--approve-for-me` it already reads anywhere on
|
|
319
|
+
disk, which was confirmed the same way.
|
|
320
|
+
|
|
321
|
+
- **An agent can write in its own lane.** Every adapter declared
|
|
322
|
+
`permissionControl: true` and passed no policy at all: claude-code was spawned
|
|
323
|
+
as `-p --output-format stream-json …` with no `--permission-mode`, and codex as
|
|
324
|
+
`exec --json` with no sandbox and no approval flag, under a comment saying it
|
|
325
|
+
took both on the command line. So a headless run asked before its first write,
|
|
326
|
+
emitted a `permission_request`, rendered it in the transcript — and nothing
|
|
327
|
+
anywhere answered. The phase failed reporting a permission system it could not
|
|
328
|
+
see, having written nothing.
|
|
329
|
+
|
|
330
|
+
`run` and `serve` now take `--permission <ask|auto|full>`, defaulting to
|
|
331
|
+
`auto`. **The operator sets it, never the workflow document**: the document is
|
|
332
|
+
committed and shared, and a file in a repository should not be able to tell
|
|
333
|
+
someone else's machine to run agents without approvals.
|
|
334
|
+
|
|
335
|
+
Both CLIs refuse combinations that looked reasonable, and both were found by
|
|
336
|
+
running them rather than reading them: codex rejects `--sandbox` alongside
|
|
337
|
+
`--approve-for-me`, and `codex exec resume` accepts neither — passing the
|
|
338
|
+
fresh-spawn policy there turned a `stale_session` refusal, which the scheduler
|
|
339
|
+
retries cold, into a `fatal` one that fails the node.
|
|
340
|
+
|
|
341
|
+
This reverses a documented decision. The README said the daemon passed no
|
|
342
|
+
permission flags and that a committed `.claude/settings.json` was what made a
|
|
343
|
+
run able to write; that is now the narrowing layer on top of a mode, not the
|
|
344
|
+
only thing standing between an agent and a blocked lane.
|
|
345
|
+
- **`purge --lanes --branches` clears what a failed run leaves behind.** A run's
|
|
346
|
+
lane worktrees are not under `runs/`, so no purge ever reached them: three
|
|
347
|
+
failed attempts at one plan left twelve worktrees, twelve summaries, and a set
|
|
348
|
+
of `plan/<id>/phase-*` branches still checked out — which is what makes the
|
|
349
|
+
*next* run of that plan impossible, since git refuses to check out a branch a
|
|
350
|
+
second worktree holds.
|
|
351
|
+
|
|
352
|
+
One rule decides both: **never delete the only copy of work.** A phase can
|
|
353
|
+
leave work committed on its branch or uncommitted in its worktree, and both
|
|
354
|
+
count — so a branch carrying commits no other branch has is kept, a lane with
|
|
355
|
+
a dirty tree is kept, and each is listed with the command to remove it by
|
|
356
|
+
hand. Untracked files count as work: a phase that wrote three new modules and
|
|
357
|
+
never committed them is exactly the case worth protecting.
|
|
358
|
+
|
|
359
|
+
Emptiness is measured as "carries no commit another branch does not already
|
|
360
|
+
have", not as "merged into HEAD". The latter is relative to wherever the
|
|
361
|
+
operator is standing, so on a feature branch — the checkout this is most often
|
|
362
|
+
run from — every empty phase branch looked unmerged and nothing was ever
|
|
363
|
+
cleaned up.
|
|
364
|
+
|
|
365
|
+
`--dry-run` and `--yes` work as they already did, and a worktree that will not
|
|
366
|
+
go is named rather than counted.
|
|
367
|
+
|
|
368
|
+
- **`doctor` now catches, before a lane exists, the failures that used to take a
|
|
369
|
+
run each.** Four consecutive runs of one plan failed four different ways, and
|
|
370
|
+
every one of them was knowable at minute zero from the workflow and the repo.
|
|
371
|
+
- **Every `prompt_ref` and `plan_context_ref` is resolved against
|
|
372
|
+
`base_branch`**, with `git cat-file -e`, which reads the branch's tree and
|
|
373
|
+
so cannot be satisfied by a working-tree copy — the working tree being
|
|
374
|
+
exactly what a lane will not have. It distinguishes the three cases, because
|
|
375
|
+
they have three different fixes: never committed, **staged but never
|
|
376
|
+
committed** (`git add` alone does not put a file in a branch), and committed
|
|
377
|
+
on a different branch. The last offers both routes out — merge it, or point
|
|
378
|
+
`base_branch` at the branch that has it — since only the operator knows
|
|
379
|
+
which they want.
|
|
380
|
+
- **Phase branches held by another worktree** are reported with the directory
|
|
381
|
+
to remove. Lane directories are named per run and phase branches per
|
|
382
|
+
workflow, so a failed run leaves worktrees holding the branch names the next
|
|
383
|
+
run will try to cut, and git refuses to check out a branch twice. Nothing
|
|
384
|
+
cleans those up: `purge` deletes run state under `.vinta-ai-maestro/runs/`,
|
|
385
|
+
and lane worktrees are not there. `doctor` does not delete them either — a
|
|
386
|
+
failed lane's worktree is the only place its state survives — but it now
|
|
387
|
+
names each one and the exact command.
|
|
388
|
+
|
|
389
|
+
- **A failed node records why.** `node_status` carried `{"status":"failed"}` and
|
|
390
|
+
nothing else, so two runs failing for two unrelated reasons produced identical
|
|
391
|
+
journal rows and the cause survived only in the operator's terminal. The
|
|
392
|
+
reason is now persisted — **sanitized**, not raw: errors the package builds
|
|
393
|
+
itself are identifiers by construction and are kept verbatim, and anything
|
|
394
|
+
else is reduced to its kind, the rule `recycleStage` already followed. The
|
|
395
|
+
journal is durable and API-served, and an exception message from a dependency
|
|
396
|
+
is exactly how repository content gets into one. Blocked dependents record
|
|
397
|
+
which node blocked them.
|
|
398
|
+
|
|
221
399
|
- **Two diagnostics that named the symptom and hid the cause.** Both came out of
|
|
222
400
|
one real run, and neither was a wrong answer — just an unusable one.
|
|
223
401
|
- **A phase whose plan is not committed** failed with `prompt_ref "…" names no
|
package/package.json
CHANGED
|
@@ -1,16 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vinta-ai-workflows",
|
|
3
|
-
"version": "0.7.0-
|
|
3
|
+
"version": "0.7.0-alpha5",
|
|
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+
|
|
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
|
+
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|