Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 34 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,39 @@
# Changelog

## [Unreleased]
## 0.3.2 — 2026-07-24

No user-facing change. This release carries dependency updates and the internal foundations
for the list + preview workspace ([ADR 0024](docs/adr/0024-list-preview-workspace.md)); the
workspace itself is not enabled yet.

### Internal
- **Detail text composition is extracted into pure formatters.** `PrDetailFormatter` and
`WorkItemDetailFormatter` render a detail view-model at a given width and tier
(`Summary`/`Full`); the PR and work-item dialogs delegate to them instead of composing their
text inline. Behaviour is unchanged and pinned byte-for-byte by snapshot tests — the point is
that the coming preview pane renders from the same function rather than growing a second,
drifting implementation.
- **A shell-wide two-pane layout calculator.** `WorkspaceLayout.Compute(width)` decides whether
a preview pane is shown and how the width splits, as pure unit-tested thresholds. The diff
dialog's `ResponsiveLayout` is untouched — the two surfaces share the shape, not the table.
- **The [ADR 0008](docs/adr/0008-client-side-diff-and-line-comments.md) load invariants are now
types rather than conventions.** `SingleFlightCache<K,V>` owns a single cancellation token
source and a monotonic supersede stamp, so a superseded fetch can neither publish its stale
result nor leak its fault to the crash log; `Published<T>` makes a torn read of a paired state
impossible by construction. Both generalize patterns that were previously re-copied by hand —
the source of four earlier wrong-file bugs.
- **Workspace pane focus is an explicit view-model.** `WorkspaceViewModel` owns the focused pane
and the key-routing decision, so routing is unit-tested headlessly instead of inferred from
Terminal.Gui focus. `Tab` is bound to pane cycling in the two list scopes but falls back to
today's tab behaviour while the preview is hidden — which it always is until the workspace
ships, hence no visible change here.

### Dependencies
- `Microsoft.Extensions.Http.Resilience` and `Microsoft.Extensions.TimeProvider.Testing`
10.7.0 → 10.8.0, `Microsoft.NET.Test.Sdk` 18.7.0 → 18.8.1, `Microsoft.SourceLink.GitHub`
10.0.300 → 10.0.301; `actions/setup-dotnet` v5 → v6 in CI.

## 0.3.1 — 2026-07-23

### Fixed
- **A diff-review render could pair one file's diff with another's path.** The render path read
Expand Down
2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ an interactive browser sign-in.

```sh
dotnet build Cobalt.slnx # build all (src + tests)
dotnet test Cobalt.slnx # full suite (~750 tests)
dotnet test Cobalt.slnx # full suite (~1,200 tests)
dotnet run --project src/Cobalt -- --help # run the CLI/TUI

# run a single test / class / trait
Expand Down
9 changes: 5 additions & 4 deletions Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,12 @@
<NoWarn>$(NoWarn);CS1591</NoWarn>
<PublishRepositoryUrl>true</PublishRepositoryUrl>
<EmbedUntrackedSources>true</EmbedUntrackedSources>
<VersionPrefix>0.3.0</VersionPrefix>
<VersionPrefix>0.3.2</VersionPrefix>
<!-- Every build is a prerelease unless it sets Version explicitly. release.yml does exactly that on
a tag push (/p:Version=${GITHUB_REF_NAME#v}), so a tagged release still packs a clean 0.3.0 while
local and branch builds stay 0.3.0-alpha — a dev build can't be mistaken for, or installed over,
a released one. -->
a tag push (/p:Version=${GITHUB_REF_NAME#v}), so a tagged release still packs a clean 0.3.2 while
local and branch builds stay 0.3.2-alpha — a dev build can't be mistaken for, or installed over,
a released one. Bump this with the CHANGELOG section it belongs to: left trailing the newest tag
(as it was through 0.3.1), dev builds report a LOWER version than the release they follow. -->
<VersionSuffix>alpha</VersionSuffix>
<Authors>jinyeow</Authors>
<RepositoryUrl>https://github.com/jinyeow/cobalt</RepositoryUrl>
Expand Down
15 changes: 8 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@
A vim-flavored terminal UI for Azure DevOps: work items, pull requests,
reviews, and votes — without leaving your terminal.

Status: **v0.1.0** — feature-complete for the agreed v1 (work items, pull
requests, diff review with line comments). The agreed specification lives in
Status: **v0.3.2** — feature-complete for the agreed v1 (work items, pull requests,
diff review with line comments) and iterating past it; the
[CHANGELOG](CHANGELOG.md) records what each release added. The agreed specification lives in
[docs/SPEC.md](docs/SPEC.md), the milestone plan in [docs/PLAN.md](docs/PLAN.md),
and design decisions in [docs/adr/](docs/adr/).

Built with a UI-free `Cobalt.Core` and a view-model layer that never references
Terminal.Gui, so the interesting logic is unit-tested (808 tests). See
Terminal.Gui, so the interesting logic is unit-tested (1,208 tests). See
[docs/adr/0004](docs/adr/0004-terminal-gui-v2-with-viewmodels.md) and
[0007](docs/adr/0007-vim-input-as-testable-data.md).

Expand Down Expand Up @@ -321,24 +322,24 @@ Release, so Debug misses the ~16 ms frame budget on every redraw and the UI feel
responsiveness only from a Release build; a Debug build tells you nothing about how it will feel.

**Or install your build as the `cobalt` global tool.** **Watch the cache:** an unreleased build
packs as `0.3.0-alpha` every time and NuGet caches packages *by version*, so `dotnet tool
packs as `0.3.2-alpha` every time and NuGet caches packages *by version*, so `dotnet tool
update`/`install --add-source` can silently reuse a **stale** cached build — which looks
exactly like "my change didn't take". Give each build a unique version so the install
can't hit the cache:

```sh
dotnet tool uninstall -g cobalt-tui
dotnet pack src/Cobalt/Cobalt.csproj -c Release -o ./artifacts \
-p:PackageVersion=0.3.0-local1 -p:PublishRepositoryUrl=false -p:EmbedUntrackedSources=false
dotnet tool install -g cobalt-tui --add-source ./artifacts --version 0.3.0-local1
-p:PackageVersion=0.3.2-local1 -p:PublishRepositoryUrl=false -p:EmbedUntrackedSources=false
dotnet tool install -g cobalt-tui --add-source ./artifacts --version 0.3.2-local1
```

Bump `local1` → `local2` … on each rebuild. To keep the same version instead, delete the
cached package first: `rm -rf ~/.nuget/packages/cobalt-tui` (Windows:
`rmdir /s /q "%USERPROFILE%\.nuget\packages\cobalt-tui"`).

**Check what you're actually running:** `cobalt --version` prints the version *and* the commit —
`0.3.0-alpha+fd36e1b` for a branch build, a clean `0.3.0+<sha>` only for a tagged release. The
`0.3.2-alpha+fd36e1b` for a branch build, a clean `0.3.2+<sha>` only for a tagged release. The
`-alpha` marks any build that isn't a release, so a dev build can't be mistaken for one. If the
sha isn't the commit you expect, you're running a stale install — that mistake is invisible
without this, because every build between two releases carries the same number.
Expand Down
3 changes: 2 additions & 1 deletion docs/testing/manual-verification.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,8 @@ Record each as: `Result: Pass / Fail — notes:`
Check exit codes with `echo $?` immediately after each command.

- [ ] **A1 — version.** Run `cobalt --version` (and `cobalt -v`).
Expect: prints `0.1.0` (no git-hash suffix), exit `0`.
Expect: the version *with* its 7-char source revision — `0.3.2+<sha>` from a tagged-release
install, `0.3.2-alpha+<sha>` from any local or branch build — and exit `0`.
Result: ______
- [ ] **A2 — help.** Run `cobalt --help` (and `-h`).
Expect: usage block starting `cobalt — a vim-flavored terminal UI for Azure
Expand Down