Skip to content

Release v1.5.1 — update reports the truth, and the session says when you're behind - #53

Merged
r-bart merged 3 commits into
mainfrom
develop
Aug 20, 2026
Merged

Release v1.5.1 — update reports the truth, and the session says when you're behind#53
r-bart merged 3 commits into
mainfrom
develop

Conversation

@r-bart

@r-bart r-bart commented Aug 20, 2026

Copy link
Copy Markdown
Owner

Three changes, all found by trying to run devtronic update against this repository.

update announced ~50 files it was never going to write

update walks the template tree twice — once to report, once to apply — and only the apply
loop asked whether the install was in plugin or marketplace mode. Every marketplace user was
shown the whole skill and agent set as "New Files in This Version", confirmed adding them, and
saw none appear. Because the list was never empty, All files are up to date! could not fire
for a marketplace install however current it was.

Both loops now share isPluginManagedPath().

before                          after
Files to Update:  2             Files to Update:  2
New Files:       50             (none)

Migrating to the plugin left the old inline hooks behind

The plugin supplies the same hooks, so both sets ran: the SessionStart prompt fired twice per
session, and the unfiltered npx eslint --fix linted every markdown write alongside the
plugin's filtered auto-lint.sh. Running since the plugin migration, in every migrated
project.

registerGitHubPlugin() now strips them and reports which events it cleaned. Matching is by
signature and deliberately narrow: an unrecognised hook is one the user added, and removing it
takes work they cannot get back. Over half of stripDevtronicHooks()'s tests assert exactly
that.

The session now says when you're behind

A SessionStart hook runs version-check.sh: it compares the version in
.ai-template/manifest.json against the installed CLI and prints one line when they differ,
naming devtronic update or npm i -g devtronic@latest depending on which side is older.

Every part of this has existed since the manifest did. Nothing ran the comparison unless you
typed devtronic info — which is why this repository sat on 1.3.0 through two minor releases
without a word.

Detection only, on purpose. update retires files and asks about the ones you made yours;
applying that unattended is how work gets lost.

Verification

typecheck, lint, build clean. 1120 tests, 53 files.

46 tests cover the three changes, all mutation-checked:

Mutation Fails
Remove the detection guard the 50 phantom files return
Treat every hook as devtronic's the 4 tests protecting the user's hooks
sort -Vsort numeric version ordering (1.10.0 vs 1.9.0)
Append a byte to the bundled script the generated/bundled identity check

r-bart added 3 commits August 20, 2026 07:11
…r the duplicate hooks

`update` walks the template tree twice — once to report what it will do, once
to do it — and only the apply loop asked whether the install was in plugin or
marketplace mode. Every marketplace user was shown the whole skill and agent
set as "New Files in This Version", confirmed adding them, and then saw none
appear. Because the list was never empty, `All files are up to date!` could
not fire for a marketplace install however current it was. Both loops now
share `isPluginManagedPath()`.

The second one has been running silently since the plugin migration. Moving a
project to the plugin registered it and left devtronic's old inline hooks in
`.claude/settings.json`, so both sets ran: the same SessionStart prompt fired
twice per session, and the unfiltered `npx eslint --fix` linted every markdown
write alongside the plugin's filtered `auto-lint.sh`.
`registerGitHubPlugin()` now strips them and reports which events it cleaned.

Matching is by signature and narrow on purpose. An unrecognised hook is one
the user added, and removing it takes work they cannot get back — over half of
`stripDevtronicHooks`'s tests assert exactly that.

Found by running `devtronic update --dry-run` against this repository, which
proposed 50 files it would not have written.
Everything needed to know this has existed since the manifest did: the
manifest records the version that last wrote the project's files, and the CLI
knows its own. Nothing ran the comparison unless you typed `devtronic info`,
so this repository sat on 1.3.0 through two minor releases without a word.

A `SessionStart` hook now runs `version-check.sh`. It reads two version
strings, orders them with `sort -V`, and prints one line naming the command
that fixes the gap — `devtronic update` when the CLI is ahead, `npm i -g
devtronic@latest` when the project is. Silent when they agree, local, and
always exits 0: a session must never fail to start because of this check.

Detection only. `devtronic update` retires files and asks about the ones you
made yours, so applying it unattended is how work gets lost. The automatable
half is knowing you need to.

The script is one text in two places, so a test asserts the generated and
bundled copies are identical — the guard that hooks.json earned the hard way.
`docs/plugins.md` said the `PostToolUse` lint filter was a set of per-handler
`if:` conditions (`Edit(**/*.ts)`, …). That implementation was written and
then reverted during the 1.5.0 review — the filter lives in `auto-lint.sh`,
which reads the real `tool_input.file_path` — but the documentation kept the
version that never shipped.

The `SessionStart` section now covers the version check, with the line it
prints and why it reports rather than applies. Both READMEs name it, and the
overview box in the root README is aligned to its own border again.
@r-bart
r-bart merged commit 18b90a7 into main Aug 20, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant