Skip to content

GitPulse v0.0.8

Choose a tag to compare

@github-actions github-actions released this 08 Sep 00:09

Fixed

  • Code → Map no longer pane-crashes on duplicate dead-symbol ids. Real
    repo_map.json files can list the same dead_symbol_candidates entry more
    than once; Svelte 5's keyed {#each} then threw each_key_duplicate and the
    Map pane's error boundary reported a pane-crash (six times in diagnostics on
    open). Dead / unwired / unreachable lists are deduped before render, and
    keyed lists across Map, Work, stacks, harness, and the setup wizard use
    index-suffixed keys so a duplicate payload cannot take the pane down again.

Added

  • Optional Manvi / DevMap install ladder. Settings → Agents, Code → Map, the MANVI
    harness pane, and a resumable Setup wizard can install or update devmap and
    manvi without treating them as required. Resolution order: configured binary →
    PATH / ~/.cargo/bin → checksum-verified GitHub release asset → remote
    install script → local source (cargo install --path …/devmap-cli --locked --force,
    go -C …/manvi install ./cmd/manvi). Progress is cancellable. Broken
    GITPULSE_*_BIN / GITPULSE_*_ROOT overrides are refused rather than searched past;
    clone missing checkouts via onboarding. Override roots with
    GITPULSE_DEVCOUNCIL_ROOT / GITPULSE_MANVI_ROOT.

  • devmap doctor --json verify on status. Tool status prefers the doctor JSON
    contract (expected_schema_version, code-graph schema) over scraping --version
    prose, so schema drift is named instead of a silent mismatch with the vendored store.

  • Capability gating when optional tools are absent. Map / harness UI degrades to
    explicit “not installed” empty states and CTAs instead of empty panels that look like
    “nothing found”. Wizard and palette entry: “Set up optional tools (devmap / manvi)”.

Changed

  • Dependency refresh (2026-09-07). Frontend floors raised to current stable
    (svelte ^5.57.0, @tauri-apps/api ^2.11.1, @tauri-apps/cli ^2.11.4,
    @tauri-apps/plugin-opener ^2.5.5). Rust direct reqs raised where already
    resolved (rayon 1.12, notify 8.2, regex 1.13, tempfile 3.27) and
    cargo update pulled latest compatible transitive crates. Intentionally
    unchanged: classic typescript@~6.0.3 + @typescript/native-preview@7.0.0-dev.20260707.2
    (svelte-check peers still ^5|^6; tsgo split preserved), Tauri git pin
    406feea… (crates.io still 2.11.5; unpublished 2.12 line keeps urlpattern 0.6),
    rusqlite 0.31 (vendored dc-store / devmap-store), notify 8.x (9.0 is RC),
    libc 0.2 (1.0 is alpha). No rust-toolchain pin; toolchain left alone. No
    re-vendor.

  • Typecheck uses tsgo (TypeScript 7 native preview) for Node/script configs.
    npm run check still runs svelte-check against classic typescript@~6.0.3
    because svelte-check@4.7.6 peers only typescript ^5|^6 and does not drive
    tsgo. The former tsc -p tsconfig.node.json --noEmit step is now
    npm run typecheck → tsgo -p tsconfig.node.json --noEmit via
    @typescript/native-preview@7.0.0-dev.20260707.2. App .svelte typing
    remains on svelte-check until it accepts TypeScript 7 / tsgo.

Note

  • v0.0.7 was tagged then withdrawn after the Map pane-crash above was found in
    the local build. It was never published as a GitHub Release; this cut is the
    first ship of that work.

Added

  • DevMap code intelligence works again at store schema 19, with a handshake that names drift. The
    vendored devmap-* crates now match the on-disk .devcouncil/codeintel/devmap.sqlite stores every
    sibling repo already builds (schema 19). A mismatched build reports map built by schema N, this
    build reads M
    rather than a raw SQLite refusal, and npm run check:vendor-schema fails ci:local
    when the installed devmap CLI and the vendored constant disagree.

  • Build, refresh, status, and edit preview are driven by the installed devmap CLI. GitPulse still
    queries the store in-process; it shells out for indexing (build / incremental refresh / status --json / preview --file … --content -). Lookup reports which path answered (env override vs
    PATH / ~/.cargo/bin), refuses a configured path that does not resolve, bounds wall clock and
    stdout, and refuses a second build for the same repo while one is in flight.

  • Pre-commit blast radius: what this commit would break. The commit composer and the diff file rail
    share one devmap preview batch over staged paths. Each file carries parse status, degradation,
    compared-against, and broken callers — and a walk that stopped early or a file with no grammar is
    marked unreliable rather than shown as "nothing breaks".

  • CI:local can scope tests to the change set, and fails closed to the full suite. Affected-test
    seeds come from the working-tree status; results are test files, chunked at the kernel's neighbor
    target cap. A stale map, incomplete walk, or unmatched seed runs the full suite and says so — the
    GitHub CI panel never badges a fail-closed full suite as "affected tests passed".

  • Layered blast radius and a resolution-rung filter on Diff. Change-set impact is composed over
    changed files by hop (impact_layered), rendering each band's sample and nodes_omitted /
    node_count. Flat impact offers a min-rung filter plus a rung histogram ("what you did not see");
    the control is suppressed wherever layered impact is active, because the kernel refuses that pairing.

  • Code → Map: subsystem navigator, code/doc graph canvas, and repo docs. A third Code section
    (⌥3 when Code is active) reads .devcouncil/repo_map.json with capped samples named as such,
    draws code-graph and map-preview canvases (and a MarkDev doc graph), and searches tracked markdown
    plus broken links / cross-repo link candidates. Freshness comes from devmap status; Build /
    Refresh live on the status strip.

  • The code map refreshes from the file watcher. Debounced repo-changed events ask for an
    incremental refresh when status says the index is stale, with the same single-build-per-repo guard.

  • MarkDev's Rust core owns markdown parse/render and dual-backend highlighting. The file viewer
    uses the flat UTF-16 model (no TypeScript reimplementation). Tree-sitter covers rust / JS / TS /
    Python / JSON / shell; everything else stays on the existing regex tokenizer under one owner in
    diff/highlight.ts. Commit message bodies and MANVI verdict detail render through the same path.
    The docs vault is built from git ls-files of markdown (not a filesystem walk), with backlinks in
    the viewer; rename is git mv plus staged link rewrites via MarkDev's pure rewriter.

  • Open tabs register in DevMap's workspace for cross-repo search. Palette :: searches symbols
    across registered repos (trailing ~ requests TF-IDF name ranking); bare : stays single-repo.
    Truncation and unavailable repos are named on the result strip.

Honesty (read these as product rules, not caveats)

  • walk_incomplete means the list is a floor, not a complete answer.
  • Capped samples carry shown/total/truncated (repo map, graph legend, docs search, broken links).
  • Schema mismatch and missing/devmap binary failures are named; they are not empty "all clear" panels.
  • Affected-tests scoping that cannot prove coverage runs the full suite and says why.

Added

  • Tags now say where their work stands, so work parked on a tag is no longer invisible. A tag is a
    ref, so the graph walks it and draws its commit a lane — one shaped exactly like an unmerged branch.
    But list_branches and the cleanup plan read only refs/heads and refs/remotes, so nothing in the
    app could answer "is this merged?" for a commit held by a tag alone, which is exactly what a
    retired/… tag does. TagInfo now carries commits_ahead_of_base, commits_behind_base and
    compared_to, measured against the same default base branches are measured against and read in the
    same single git tag -l process via %(ahead-behind:). The sidebar shows a +N chip on a tag that
    holds commits the base does not, and the tooltip says either how far ahead it is or that every commit
    is already in the base. compared_to: null means the comparison could not be made — an old git, or a
    tag that does not peel to a commit — and is never rendered as "merged".

  • Ops now reports what the repository retains on tags, which branch cleanup counts nowhere. A new
    Tag retention card splits every tag into "holding commits the base does not have" and "every commit
    already in the base — safe to delete", with per-tag counts and the existing tag-delete path behind a
    confirmation. A tag the comparison could not be made for is reported as its own number and is never
    proposed for deletion, and all three caps (the tag listing, the retained rows, the deletable rows)
    say so rather than letting a sample read as the whole repository. No tag is pre-selected: unlike a
    merged branch, a tag is usually kept on purpose. Deletion is disabled unless the three buckets add
    up to the tag total, mirroring the branch plan's own coverage guard.

  • Graph tag chips carry the count too. A tag lane is shaped exactly like an unmerged branch lane,
    so the chip on the commit row and in the graph tooltip now reads +N for a tag holding commits the
    base does not have, and its hover says either that or that every commit has already landed. It reuses
    the tag listing the sidebar has already loaded, so the graph pays no extra command on a path that
    reruns on every repo switch, and a tag past the listing cap simply says nothing rather than implying
    its work has landed. ManviOpsPanel joins the runtime harness (harness/stress.html?c=ManviOpsPanel),

  • Language breakdown now supports on-demand rescan. The language segment dropdown now provides a manual
    rescan button (locMetric.refresh with force: true) with an active spin indicator, allowing instant
    recalculation of code percentages after checking out branches or generating code without requiring a full
    repository switch.

  • Scroll cues now surface overflow on clipped panels. A new overlay component (ScrollCue)
    and DOM observer (observeOverflow) add edge chevrons and gradient fade cues to scrollers whose
    overflow was otherwise silent, including BranchList, FileViewer, DiffFileRail, TerminalPanel,
    RepoTabBar, and VirtualList. The graph layout's horizontal gutter overflow calculation now shares
    the same canonical resolveOverflowHint logic.

  • Soft pill dividers and high-contrast section borders unify panel styling. Replaced harsh full-width hairline
    borders with centered pill dividers (.gp-separator, .gp-menu-sep) and solid high-contrast borders
    (.gp-section-edge) across modals, panels, and dropdowns to improve visual hierarchy and contrast in both
    dark mode and forced-colors accessibility modes.

Fixed

  • A branch whose ahead/behind git never filled in would have read as merged. list_branches parsed
    the %(ahead-behind:) field leniently, turning an empty or malformed value into (0, 0) beside a
    named base — the wire shape for "every commit is already in the base". Unreachable for branch refs,
    which are always commit-ish, but the safety of that lenient path was an argument rather than a check.
    Both listings now share one strict parser: an unparsable field leaves the row uncompared instead,
    and branch_refs_always_yield_two_counts pins the assumption. The lenient parser and its private
    tokeniser are gone.

  • An annotated tag reported its own object id where a commit id was expected. list_tags read
    %(objectname), which for an annotated tag is the tag object, not the commit it points at, so the id
    shown in the tag tooltip matched nothing on the graph. It now peels through %(*objectname), as the
    graph's own decoration listing already did.

  • The storage trend sparkline ignored the chosen accent and always drew the same purple. It
    read var(--accent, #8b5cf6), and --accent is defined nowhere — the token is --accent-color.
    A misspelt custom property is invisible in a way a misspelt class is not: CSS resolves to the
    literal after the comma and paints a plausible colour, so the line looked designed rather than
    broken. A sweep of every var() and every scripted token read across src/ found this as the
    only unresolved reference of 51; src/lib/ui/cssTokens.contract.test.ts now holds both surfaces
    to tokens something actually defines.

  • Every row in the coverage file list read the same, because the paths were truncated from the
    wrong end.
    The list is flat and the paths share a prefix, so right-truncating the whole path
    produced rows identical up to the ellipsis (rust-port/crates/devmap-e…) and clipped away the
    file name, which is the only part that distinguishes them. The name now comes first with the
    directory dimmed after it, so truncation eats the half that repeats, and the full path is on the
    row's tooltip — the same shape DiffFileRail already used.

  • The work-in-progress indicator and its details dropdown rendered too transparently over underlying content.
    Sitting on the translucent repository tab bar, the button carried no border, no background fill, and
    only a 10% amber hover state, making it read as ghosted or see-through over the glass chrome. It now
    wears the shared .gp-btn pill geometry in both states — an outlined surface pill with subtle emerald
    indicator when all clear, and a defined, tinted amber pill (!bg-amber-500/20 light, dark:!bg-amber-500/25)
    with WCAG-accessible contrast text (text-amber-700 dark:text-amber-300) and active state when work
    is in progress. Furthermore, its details popover panel previously used .gp-card without shadow-float,
    causing it to miss the macOS float blur tier (compositing with 0px blur) and 50% opacity directly over
    underlying code and diffs. It now correctly carries shadow-float for proper float-tier backdrop blur
    and a dense bg-surface/95 background with border border-border/80 so content behind it does not
    bleed through.

Internal

  • Two Rust tests asserted POSIX behaviour on every platform, and the Windows suite had never run
    to reach them.
    the_user_shell_starts_as_a_login_shell expected -l, which login_flag
    deliberately never returns on Windows; it is now #[cfg(unix)], the gate its sibling
    login_flag_covers_known_shells_only already carried.
    a_slow_call_does_not_delay_the_answer_to_a_fast_one made its slow call with repo_path: "/tmp",
    which is not an absolute path on Windows — the call was rejected before doing any work
    (duration_ms: 0) and answered instantly, so it beat the "fast" request and failed the test for
    the exact opposite of the condition it exists to catch. The slow call now scans a directory that
    is absolute on every platform, with Unix keeping /tmp verbatim because the timing was tuned
    against it.
  • Windows clippy failed on unix-only test and bench code, and had been hidden behind an earlier
    failing step.
    -D warnings promotes unused_imports and dead_code to errors, and six items
    reachable only from #[cfg(unix)] code were declared ungated: two imports in the analyzer::deps
    tests, two in the procguard tests, the Registration::slot test accessor, and the whole
    preamble of benches/process_spawn.rs (whose not(unix) main deliberately measures nothing).
    Each is now gated to the platform that uses it. CI steps also stopped at the first failure, so
    this sat invisible behind a Vitest failure on the same leg and each fix revealed the next one a
    push later; the independent checks now run under !cancelled() so one run reports all of them —
    the reasoning --no-fail-fast already applied to cargo, one level up.
  • CI was red on main for two checks that could not run, on platforms where nothing was wrong.
    pre-push-hook-contract executed .githooks/pre-push directly, and Windows cannot exec a file
    by its shebang — spawnSync ENOENT failed a case that had never started. Git reaches hooks
    through a shell there (the sh bundled with Git for Windows), so the case now invokes bash by
    name with a relative path, which is both how git runs the hook and the one spelling that works on
    all three platforms; without any bash it is skipped rather than passed.
    spawn_resolution_finds_rust_toolchain_in_cargo_bin asserted that rustup resolves to a fixture
    in a temporary ~/.cargo/bin, but that directory is the last GUI-launch fallback, behind real
    system directories the test cannot sandbox. A macOS runner with a Homebrew rustup resolved
    /opt/homebrew/bin/rustup — the right answer on that machine — and failed a test that meant to
    ask something else. The regression is now asserted where the host cannot reach it (the directory
    is in gui_launch_fallback_dirs) plus one uniquely-named probe proving resolution walks that far.
    Neither production path changed; the fallback ordering is deliberate and still stands.