Skip to content

v0.20.3

Latest

Choose a tag to compare

@skhan75 skhan75 released this 04 Sep 23:19
· 1 commit to main since this release

Added — the in-loop duplicate check sees what the session wrote

  • A session overlay index. The baseline's duplicate index is built at scan time and never grew during a session; on a recorded session two byte-identical functions written fifteen minutes apart raised no flag, and a real duplicate was paired with the wrong counterpart because the right one was written after the scan. After every checked edit the file's functions are now signed like the baseline's and kept in a per-session .overlay.json sidecar (500 functions, oldest file evicted first); other files' entries join the queried index, newest first and only up to the headroom under the 2,000-entry inline gate, so a duplicate of something written minutes ago is flagged and named with where it was first written. A file never matches itself; re-check semantics are unchanged.
  • A stale baseline rebuilds itself at Stop. When a session has written code the persisted baseline never saw and no rebuild was started in the last ten minutes, the Stop hook spawns a detached full rebuild, so the next session's checks compare against the current tree.

Added — the Claude Code plugin ships the Drift Sessions hooks

  • No repo-local install needed with the plugin. hooks/hooks.json declares the same five hook groups watch-session installs, run through hooks/vibedrift-hook with --source=plugin. They capture nothing until a repo is activated (vibedrift enable or /vibedrift:setup; only the one-time SessionStart nudge speaks before that). With the plugin installed and enabled, enable and the MCP enable tool record the activation without writing a repo-local hook install (result field hooksVia: "plugin"); an existing repo-local install is kept, upgraded, and owns capture, so a repo is never captured twice. The wrapper uses a plugin-aware global CLI when present, skips an older one, otherwise runs npx -y @vibedrift/cli session-hook (a new hidden subcommand), and fails open.
  • src/session/hook-entry.ts is now a thin watchdog around src/session/hook-main.ts, which the CLI subcommand shares.

Added — Drift Sessions see edits made through Bash

  • A PostToolUse hook group for Bash. An agent in Claude Code's bypass-permissions mode is steered to change files through Bash (python heredocs, sed -i, cat >) rather than the edit tools; on a recorded session that moved about two thirds of file changes out of the hook's sight, every fix made in answer to a flag included, so no re-check ever ran and no finding could resolve. After each Bash call the hook now finds checkable source files modified since its previous run (a per-session clock in a .hookclock.json sidecar; a bounded walk, no git dependency) and pushes each through the same path as an edit-tool write: inline check, an edit event with toolName: "Bash", the finding-scoped re-check, dedupe, one advisory. Files byte-identical to the baseline's copy are skipped (a touch, a formatter that changed nothing). The per-file checks get a 1.2 s budget per Bash call; files past it are recorded as edits the check did not run on (checked: false), never dropped. The Bash command text is never recorded.
  • Existing installs upgrade in place. vibedrift watch-session --status reports a missing hook group; a plain vibedrift watch-session (or --yes --no-watch), vibedrift enable, and the MCP enable tool each add the Bash group to an older install without a new consent prompt.

Added — vibedrift recheck-session

  • Close out findings the hook could never resolve. A finding resolves in-loop only when a later hook-visible edit of the same file drops the flagged construct; on a recorded session every fix went through Bash before the hook watched Bash, so 21 findings sat "open, no call recorded" whatever had happened to them since. vibedrift recheck-session [path] re-checks every open finding against the tree as it stands with the same finding-scoped predicate the hook uses, and records the ones whose construct is gone (on that session, 2 of the 21; the other 19 stay open because their flagged code is still on disk). Each clear is a resolve event tagged via: "recheck" and counted apart from in-loop fixes on the dashboard ("cleared on re-check"), so "fixed · verified" keeps its meaning. --dry-run, --session <id>, --json; unreadable files leave their findings open and are listed.

Fixed — Drift Sessions durability and honesty

  • vibedrift enable no longer trusts a plugin that ships no hooks. With the Claude Code plugin installed, enable skips the repo-local hook install and lets the plugin capture. But the plugin only gained the session hooks in this release, so a machine that installed it earlier had it installed and enabled while the copy on disk carried none: enable reported success, wrote nothing, and the repo listened to nothing. Found by enabling four repositories on a real machine with a 0.20.1 plugin cache and seeing zero events. The check now also requires the installed copy to carry hooks/hooks.json, and falls back to the repo-local install when it does not.

  • recheck-session never clears a finding it cannot fairly judge. A finding's anchor stores the normalized tokens of the flagged construct, and the tokenizer changed in 0.20.2, so the same untouched code now normalizes differently. Measured across that change on this repository: 5% of anchors stop matching their own byte-identical body, and a sweep using anchors from the previous build cleared one finding whose code had not changed at all. Anchors now record which vocabulary wrote them; one written by any other build is left open and reported as "raised by an older build" instead of guessed at. For the same reason the command refuses a baseline built by a different version of VibeDrift and asks you to rescan first: its presence checks are OR'd, so a stale index can only clear findings, never hold them open.

  • The session clock and overlay sidecars are written atomically. Both used a plain write that truncates the file in place, and the hook arms a two-second self-timeout that can kill it mid-write. A half-written clock reads as no clock, so the next Bash call detects nothing; a half-written overlay reads as no overlay, so same-session duplicates stop being caught. Both now write through a temporary file and rename, like every other per-session sidecar.

Changed — Drift Sessions advisories

  • Every messaged advisory now ends with an ask. "Fix it, or record your call with respond_to_flag (accept / park / decline) and one reason; if that tool is unavailable, say the reason in your reply." The line used to end with a hint and no instruction; in a recorded session the agent declined two flags and accepted two in plain chat and none of it reached the ledger. The recorded msgToAgent is the exact text delivered, ask included.
  • Duplicate advisories name both functions with their lines. your ymOf (src/components/OpensOnCalendar.tsx:16) duplicates monthOf (src/components/calendar-utils.ts:8), 0.91 similar; prefer importing it. (a real line from a recorded session; the delivered text is prefixed with the file and DF-<n> id and ends with the ask). The old line named only the counterpart, and an agent told "duplicates daysInMonth" removed a different function than the one the detector had matched. When only the whole-file query matched, the line says "this edit". A counterpart that moved lines since the baseline was built now keeps its query site, so the advisory still names the agent's function and the finding still gets an anchor; before, a moved counterpart silently lost both.
  • Experimental scope flags are recorded but no longer messaged. Measured on a real session: 22 scope flags in 7.5 hours, every one raised against an intent lock taken on a resume prompt with zero file anchors, 20 of them delivered alongside 14 real advisories in the same window (21 over the whole eight-day session). The flag stays in the ledger (the dashboard already excludes experimental flags); the agent-facing line is withheld until the check is calibrated.
    Full changelog: CHANGELOG.md