Skip to content

GitPulse v1.3.0

Choose a tag to compare

@github-actions github-actions released this 22 Sep 15:57

A consolidation release. It joins live delivery observability — GitHub Actions
workflow runs and Firebase App Hosting rollouts tied directly to repository
commits — with the bodies of work that were in flight beside it: native
notifications for agent sessions, Claude Code supervised in the managed lane,
code-age history in Blame, a terminal dock that belongs to a repository rather
than the workspace, terminal output whose links are safe to click and land where
they point, and walkthrough replay moved out of the title bar.

Re-cut on 2026-09-21 over a wider tree, adding native notifications for agent
sessions, quiet hours and sound control, managed Claude Code runs hosted over
stream-json, regression suspects from the code graph, a Health view that reaches
a verdict, repository tab groups, and the coverage and impact surfaces reduced
to what they can actually claim. Two process-lifecycle defects are fixed behind
them: an ordinary policy-harness shutdown that leaked whatever the harness had
forked, and a test suite whose verdict depended on how busy the machine was.

Added

  • Native notifications for agent sessions. An agent running in a GitPulse
    terminal tab was completely silent: Claude Code only sends desktop
    notifications in a handful of terminals it recognises, Codex's OSC 9 probe
    recognises a similar short list, and GitPulse's terminal matched neither — so
    the only signal a waiting agent could give was an unread dot on a tab you had
    to be looking at. Three layers now carry it, each independently sufficient:

    • GitPulse reads the PTY itself and understands every notification convention
      a terminal program has to choose between — BEL, OSC 9, OSC 777 and kitty's
      chunked OSC 99 — so a CLI that signals any of them is heard, whatever it
      is. ConEmu's OSC 9 sub-commands for progress and working directory, which
      Claude Code's progress bar emits continuously, are not notifications and are
      not treated as any.
    • Sessions GitPulse launches are given each CLI's own documented notification
      flag (claude --settings, codex -c tui.notifications) for that session
      only — no file of yours is written — so the CLIs actually emit something.
      Turn it off under Configure agent CLIs GitPulse launches.
    • The GitPulse plugin's Notification and StopFailure hooks report why an
      agent stopped — permission, idle, input, finished, asking, error — over a
      private local socket, which also covers a Claude Code running outside a
      GitPulse tab.
  • Quiet hours, sound and per-kind control for those notifications, and a
    counter panel that distinguishes a notice suppressed by a rule you set from
    one that was lost. Notifications are suppressed while you are looking at the
    session they are about.

  • Claude Code runs in the managed lane. Previously only Codex could be
    supervised by GitPulse — every Claude Code handoff opened a terminal and
    GitPulse stepped back. A managed Claude run is now hosted over Claude Code's
    own stream-json protocol, so its permission requests arrive as structured
    approvals you answer in GitPulse, its output is captured, and its completion
    is a receipt rather than a guess. All six permission modes map to real Claude
    Code modes, and the one that does not round-trip (ask is reported by the CLI
    as default) is verified as such rather than assumed.

    Two honest differences from managed Codex, both visible in the run's recorded
    configuration: Claude Code has no OS sandbox, so the record says so instead of
    naming a confinement that does not exist — a managed Claude run is supervised,
    not confined — and its model is not in that record, because the CLI names it
    only after the record has been written and made immutable. Repository settings
    files are deliberately not loaded for a managed run, so a checkout cannot
    widen the permissions of the run inspecting it.

  • Claude Code is now the default agent for a new task handoff, and leads the
    provider list. The connection still defaults to a terminal in ask mode: a
    first launch should be the reversible one, and the managed lane stays a
    deliberate choice. An existing remembered preference is untouched.

  • Platform coverage is written down. Platform
    coverage
    separates what is known
    absent
    off macOS — desktop notifications for activity and agent sessions, the
    agent hook socket, the menu-bar status item — from what is merely unverified
    there, such as managed runs. macOS is the platform GitPulse is developed and
    hand-tested on, and the docs now say so instead of leaving it to be discovered.

  • Regression suspects — which commits could have caused this? Blame joined to
    the code graph, and the order of operations is the whole argument: a
    blame-first tool reads a file's gutter and ranks by recency, this reads the
    graph first, so candidates are ranked by what actually reaches the symptom.
    Ships as two vendored crates (dc-regress, dc-regress-store) so every host
    asks the same question of the same graph, plus a Regression Suspects panel.

  • The Health view gives a verdict, rather than a wall of readings for you to
    add up, and every repeated decision behind it now has one owner instead of a
    copy per caller.

  • Repository tab groups. Open repositories can be grouped and named, so a
    workspace with a dozen checkouts is navigable rather than merely complete.

  • Markup and stylesheet extraction. A template file's HTML and CSS halves go
    through a real grammar, closing the gap left when only its <script> blocks
    did.

  • A substance gate for verification. Every other gate answers "is something
    wrong with this change"; this one answers "is there anything in it", which
    nothing did before.

  • Live GitHub Actions Run Polling: Automated, bounded polling for in-flight
    workflow runs that refreshes only while runs are queued or executing, backing
    off on failures, pausing while the window is hidden, and announcing newly
    failed runs via dismissible notices.

  • Delivery Timelines: Visual duration and outcome timeline for workflow runs
    and Firebase App Hosting rollouts, scaled to sample bounds with pass rates,
    median execution times, and clean handling of queue time vs execution time.

  • Firebase App Hosting Rollout Monitoring: On-demand live refresh for
    authorized project and backend pairs, providing live rollout status alongside
    commit history.

  • Action Dispatch & Rerun Controls: Enhanced GitHub Actions panel with rerun
    actions, branch filtering, and granular status reporting.

  • Clickable terminal output. A URL opens in the OS browser only when its
    scheme is http or https, verified with a real URL parse at both detection and
    activation. A file reference opens in the code viewer only when it resolves
    inside the session's repository, with containment checked on normalised path
    segments — a string prefix test calls /repo-evil/x and /repo/../etc/passwd
    inside /repo, and segments do not. A span GitPulse will refuse to open is
    never decorated as a link: underlining it and then doing nothing teaches
    people to distrust the underline instead of the output. OSC 8 hyperlinks obey
    the same allowlist, judged on the escape sequence's target rather than its
    display text.

  • A file reference lands on the line it names, with the line selected; one
    naming a line past the end of the file opens near the end rather than
    refusing. The line travels as a one-shot request with an explicit consume, not
    on the repository session: "scroll to line 12" is a navigation intent that must
    not survive a restart or replay when the file is reopened for another reason.

  • Screen reader support in the terminal. The terminal had no accessible
    text at all — screenReaderMode appeared nowhere — so a preference now builds
    xterm's row tree and applies to running sessions. The Console command field had
    no accessible name either; a placeholder is a hint, not a name.

  • The terminal harness is CI-gated. npm run test:browser -- --harness terminal (and --webkit) runs in the automated sweep instead of waiting for
    someone to press a button, with 75 real-DOM checks over the production
    components and a simulated PTY transport.

  • Code-age timeline in Blame: a chronological axis above the gutter showing
    what percentage of the open file was last changed in each period. Resolution
    adapts to the file's history (daily through yearly) and is bounded; a history
    too long for even a yearly axis folds its oldest lines into the leading column
    and says so. Clicking a column filters the gutter to exactly the lines that
    column counted — the picture and the filter share one classifier, so a column
    cannot claim a share it would not select. Quiet periods are drawn as empty
    columns rather than omitted.

  • Off-axis lines are named rather than dropped: worktree-only, clock-skewed
    and undated lines carry their own labelled, selectable shares beside the axis.
    Columns plus chips account for 100% of the file.

  • Commit blocks in the gutter: consecutive lines from one commit state their
    hash and author once at the head of the block, keep the hash reachable on
    hover or focus, and mark the whole commit down the left edge when hovered.

  • Line age in the gutter: each line's commit age, following the shared
    timestamp preference, with the other form on hover. docs/FEATURES.md had
    described this since the page was written; it was never drawn.

  • Code-age rail in Blame: a heat strip down the right edge showing where
    in the file each age lives, with a band marking what is on screen and
    click/drag to navigate. It maps the list actually drawn, so a filter re-maps
    it; the freshest tone wins each bucket and the mark's intensity says how much
    of the bucket that tone really is. Geometry is the diff minimap's, reused
    rather than re-derived.

  • The legend now carries the distribution and filters on it: each age band
    states its share of the file and selects those lines. Period columns,
    off-axis chips and age bands are one selection model with one matching rule.

  • Blame browser harness: npm run test:browser -- --harness blame (and
    --webkit) mounts the production pane over fixture IPC, 59 real-DOM checks.

  • Go to, in the cross-repository Sessions list. The list could already name
    every shell across every open repository; now it can bring one on screen —
    switching repository tabs and opening that repository's dock when the session
    lives in another one.

  • Live-session marks on repository tabs. A repository tab carries a terminal
    glyph while it holds sessions, with a count past the first, so a shell running
    where you are not looking is visible — and so "what is using the 32 slots" is
    answerable at a glance.

  • Command palette entries for each launcher — New Terminal Session, New
    Claude Session
    , New Manvi Session, New Codex Session — which open this
    repository's dock if it is hidden and start the session in one step. Starting a
    session previously required opening the dock and then finding the launcher
    dropdown and the + beside it.

Changed

  • Coverage headers collapsed from five bands to three, and the measurement now
    names what qualifies it instead of presenting a number as unconditional.

  • The impact question is answered in one line instead of reprinting the
    engine's prose, and that prose is bounded where it enters rather than where it
    is rendered — a cap at the render site leaves the oversized string already in
    memory and in the payload.

  • One owner for collapse-and-expand in long rail listings. Workflows, run
    cards and the delivery timeline all previewed then expanded, each with its own
    copy of the logic.

  • The Task pane has one owner for what it shows and in what order.

  • The terminal dock belongs to a repository tab, not the workspace. Opening a
    shell in one repository no longer opens the dock over every other repository you
    switch to. Because hosting a terminal panel starts a shell, it also no longer
    spawns a PTY — and spends one of the 32 global session slots — in repositories
    you were only reading. Each repository remembers whether its dock was showing,
    across a restart, and its dock reappears when you return to it. `Ctrl+``, the
    status bar button, the command palette entry and the native Show/Hide Terminal
    menu item all act on the active repository. Persisted additively on the existing
    workspace schema, so an older build reads the same session file unchanged.

    After upgrading, every repository starts with its dock closed once; the previous
    workspace-wide preference is not carried over.

  • The blame age scale (row tint, timeline column fill, legend and rail) now
    comes from one table and one per-line classifier instead of a colour function
    beside a hand-listed legend.

  • A blame line with no knowable age — worktree-only, undated, or dated after
    now by a skewed clock — carries no row tint. It used to tint as the freshest
    code in the file, which also disagreed with the band filter that excludes it.

  • Walkthrough moved out of the title bar: the persistent Walkthrough
    pill no longer sits in the header. Replay now lives in Settings →
    Appearance → Guided walkthrough
    , beside First-run coach marks, and
    Settings closes as the tour opens so the guide is not drawn underneath it.
    The first-run tour itself is unchanged.

Fixed

  • The notification bridge no longer fails Windows clippy. Its socket
    is Unix-only, but the accept-loop timeouts and the rejection counter were
    still compiled everywhere, so -D warnings treated them as dead code.
  • Quiet hours compile on Windows. The local clock is read through libc,
    and that dependency was declared only for Unix. localtime_s, the Windows
    spelling of the same call, was already written, but the crate was not linked,
    so the Windows CI leg stopped at clippy before any test ran.
  • Windows CI can finish, which the release gate requires before it will
    prepare a draft.
    Three failures on the last main run would have refused
    v1.3.0 at release-state ready: clippy -D warnings on Unix-only devmap
    test seams that were still compiled for Windows, a watcher fixture whose
    relative path cannot exist when the temp directory and the runner cwd are
    different volumes, and a terminal-hosting stress test that crossed Vitest's
    5s default on a loaded Ubuntu runner. The seams are cfg(unix) with their
    callers, the fixture is created on the cwd's volume, and that stress test
    has room past the default timeout. The same run's menu-payload and issue-task
    stress tests crossed their limits once coverage instrumentation was on, so
    those limits moved with the work. The process-admission storm that failed
    the same run because every spawn was refused — a result that proves nothing
    — is retried, and an escape still fails on the first attempt.
  • The activity ledger recorded any shell whose path merely contained an agent's
    name — /Users/claude/bin/zsh — as an agent session. It now matches the
    program actually launched.
  • Managed Codex could not start at all against codex-cli 0.153.4. The harness
    still passed --listen stdio://, which that build no longer accepts; rather
    than failing it exits successfully having written nothing, so the run reported
    only "managed provider connection ended" and named no cause.
  • An ordinary policy-harness shutdown no longer leaks process groups. Closing
    the sidecar escalated with a kill aimed at the direct child only, so anything
    manvi serve had forked survived — observed outliving the process that started
    it, reparented to init. The whole group is now signalled, and signalled in the
    one order that is safe: while nothing has waited on the pid, because the pid is
    the group id and a reaped pid may be recycled. A graceful wait that polls
    try_wait reaps as it watches, and so had nothing left to signal by the time
    it knew the child was gone.
  • Blame rows now honour the density setting. Rows carried a fixed 24 px
    height while VirtualList positioned them from rowHeight("blame", …), so at
    Compact density every row overhung its 20 px slot and drew over its neighbour.
  • A long blame line has somewhere to go. Lines were clipped at the pane edge
    with no scrollbar to reach the rest; the pane now shares one horizontal
    scroller, as the diff does.
  • Blame pane continuous flashing and state loss eliminated. Background status
    polls and content revision updates no longer unmount the code-age timeline strip
    or replace the VirtualList with a loading screen. Implemented a stale-while-revalidate
    (SWR) architecture, deep line equality checking (areBlameLinesEqual), and
    subject-aware state tracking that preserves the user's scroll position and active
    timeline filter selections across background revalidations.

Hardened

  • The Rust suite is a gate again. Nineteen tests decided their outcome by
    whether a child process answered inside a deadline, so a busy machine failed
    them and a quiet one passed; they now assert the property directly, at the seam.
    The rest of the cascade was not flakiness at all: one test installed a
    process-global stub-binary override and cleared it on its last line, so a
    timeout there left every later test in the run pointing at a deleted temporary
    directory — one slow test presenting as nineteen failures across seven
    unrelated modules, each of which passed when run alone. The override is now an
    RAII binding that cannot outlive the test that took it.
  • Native menu main-thread safety and command gate stress test coverage.
  • Serde/TypeScript type sync expanded to 1188 data fields across 169 structs and 225 IPC handlers.
  • Closing a repository tab that holds live shells now asks first, and says how many
    will be ended. Close Other Tabs and Close Tabs to the Right are covered
    too, counting every repository they would discard; both bypassed the single-tab
    close path entirely. The check fails open if the session count is unavailable —
    an unclosable repository tab is worse than a missing warning.
  • The harness pages are typechecked. They are the real-UI verification layer and
    sat outside tsconfig.json's include, so a harness host referencing a store it
    no longer imported typechecked clean and surfaced only as a browser-run timeout.
  • Randomized-sequence coverage for the terminal hosting rule, asserting over
    hundreds of open/close/switch steps that no repository is ever hosted — and so
    no shell ever started — without the user opening a terminal on it.

Removed

  • The showWalkthroughButton preference and its Layout toggle, which
    existed only to hide the pill. Stored copies in existing profiles are
    ignored on read.