dsh-git-badge 0.16.1 → 0.17.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -10,6 +10,138 @@ npm. 0.6.0 is the first release recorded here.
10
10
 
11
11
  ## [Unreleased]
12
12
 
13
+ ## [0.17.1] - 2026-09-17
14
+
15
+ ### Fixed
16
+
17
+ - **The branch, file-count and PR hovers open on the FIRST hover.** Those three
18
+ surfaces were only wrapped in the shell's `Tooltip` once the lazy `detail=1`
19
+ payload arrived. That primitive is uncontrolled — it has no `open` prop and
20
+ opens from a `mouseenter` it attaches to its child — so a wrapper mounted after
21
+ the pointer had already arrived could never open for that visit: the first hover
22
+ did nothing, and worked only after leaving and returning (or after hovering the
23
+ status mark had already warmed the cache). All four surfaces are now wrapped
24
+ from the first render, and a label whose detail is still in flight degrades to
25
+ the base response instead of claiming an empty list — the count restates the
26
+ file breakdown, the PR token names the PR. The branch's hover child also stays a
27
+ `span`, so the compare link appearing underneath a resting pointer cannot
28
+ remount it. The status mark's own card was never affected.
29
+
30
+ ### Changed
31
+
32
+ - **Internal simplification pass, no user-facing change** (#52): one
33
+ `singleFlight` now backs the status cache and its in-flight coalescing, one
34
+ patch engine (`seam/patch.js`) backs both `seam/apply.js` and
35
+ `seam/postinstall.js`, and the server returns one `nextActions` shape
36
+ (`{actions, next}`) for the row's action list.
37
+
38
+ ## [0.17.0] - 2026-09-16
39
+
40
+ ### Added
41
+
42
+ - **The PR token has its own hover: the commits in that pull request.** `PR#47 ✓`
43
+ now shows the commits on the branch that are not on the base
44
+ (`git log <base>..HEAD`, capped at 10 with "… and k more"), in the same line
45
+ format as the branch hover's list — hash, subject, compressed age, full-width
46
+ with ellipsis. Nothing else rides it: the token already states the number and
47
+ CI state, so the one question left is what is in it. Hover-gated with the rest
48
+ of `detail=1`, and the total reuses the ahead count already computed.
49
+ - **`/gh clean [<path>...]` appears in the `/gh` menu behind a risk gate.** The
50
+ menu is built from status, not from this skill's prose, so the verb is offered
51
+ there whenever untracked files exist — always last, never as the badge's
52
+ suggested action, and carrying the host's own `RiskConfirmation`: Confirm
53
+ stays disabled until "I understand untracked files cannot be recovered" is
54
+ ticked. That gate names the risk; the agent then names the files
55
+ (`git clean -n`, quoted back) and asks again before `git clean -f`.
56
+ - **A `/gh clean [<path>...]` verb, confirm-first by construction.** Removing
57
+ untracked files is the one operation with no reflog and no stash entry, so the
58
+ verb's first step is always `git clean -n -- <paths>` with the output quoted
59
+ back verbatim (the user approves the list, not the idea), then an explicit yes,
60
+ then `git clean -f -- <paths>` on named paths only. `-x`, `-d` and bare
61
+ `git clean -f` are forbidden — ignored files are often credentials and `-d`
62
+ turns one path into a tree. It stays out of the badge's ranked suggestions: a
63
+ destructive action the agent cannot infer intent for is never suggested, only
64
+ available on request.
65
+
66
+ ### Changed
67
+
68
+ - **The session row's action token only appears when the session is idle.** A turn
69
+ in flight is exactly when a git suggestion is noise: the checkout is still
70
+ moving and the agent has not finished. The row reads its run state from the
71
+ shell's standard kit — `useSessions`, the same selector hook the workspace UI
72
+ itself uses — and renders nothing while that session is `running`. The filter is
73
+ on render, not on the fetch, so the row's hover line is unaffected. On a shell
74
+ that seeds no such hook the row behaves as before, and the console says which of
75
+ the two it got.
76
+ - **The PR/CI token stops lagging behind the forge.** The forge read is
77
+ TTL-bounded and its refresh is request-driven, while an idle chip only asks
78
+ every 60s — so the old 90s `prTtlMs` silently suppressed every other poll, and
79
+ a pull request that appeared on GitHub with no local git event to announce it
80
+ could take ~2.5 minutes to show up. At 20s the TTL no longer outlives the
81
+ client's poll, so the first refresh after the forge changes picks it up and the
82
+ worst case falls to roughly the poll interval. Cost: up to one `gh pr view` per
83
+ open chip per minute, where it was one per ~2 minutes.
84
+ - **The branch hover shows only the merge axis.** `upstream` and `sync` are gone
85
+ — they stated the same divergence against the branch's own remote, in arrows,
86
+ when `merge` already states it against the base branch in words. The `merge`
87
+ row now ALWAYS renders: `ready to merge`, `blocked: draft | review required |
88
+ checks failing`, `no pull request`, each joined with `N ahead, M behind main`
89
+ when those counts are known. A row that can be absent is a row the reader has
90
+ to reconstruct.
91
+ - The commit cells lost their trailing colon (a later change had reintroduced it
92
+ after the earlier removal), so both hovers read `abc1234 subject · 2h ago`.
93
+ - **One action list, built by the server.** Both halves used to derive the
94
+ pull/push/commit/pr conditions, and the copies drifted: the card once promoted
95
+ a client-only extra into its action row, and `/gh pr` was offered on the
96
+ default branch. The node half now publishes `actions` — the ranked rules in the
97
+ configured order with the top entry flagged `primary` (also served as `next`,
98
+ on every response), then the standing options (`pr view <n>`, `pr`, and the
99
+ flagged `clean`). `merge <n>` becomes a standing entry whenever the PR is
100
+ mergeable, so it now appears alongside a primary `push`/`pull` instead of only
101
+ when it wins the ranking. The client renders the list verbatim and keeps only
102
+ presentation — labels and the clean risk gate; `actions` rides the `pr=1`
103
+ payload only, so sidebar rows stay lean. Net: ~65 lines of duplicated client
104
+ rules deleted, and the conditions are unit-tested where the data lives.
105
+ - **The upstream sync numbers ride the branch's hover and link.** `↑a ↓b` were
106
+ rendered inside the file count's names tooltip and outside the branch's compare
107
+ link, though they are the branch's standing against its upstream — so they now
108
+ sit with the branch name: same lineage hover, same compare-view link, and the
109
+ link's accessible name says "N ahead and M behind upstream". `✎n` keeps its own
110
+ names tooltip. Visible side effect: the arrows render before a paused-operation
111
+ token rather than after it.
112
+
113
+ ### Fixed
114
+
115
+ - **The PR token's hover lines its commits up like the branch hover.** Both lists
116
+ now come from one renderer: a fixed-width monospace hash cell, so every
117
+ description starts on the same column and the list reads as a table. The PR
118
+ list had reused the card's label style, whose `minWidth` and `flex` only apply
119
+ inside a flex row — on a plain inline span they did nothing, so the hash sat
120
+ flush against its description with the columns ragged.
121
+ - **The PR token's hover is reachable by hovering the token itself.** The commits
122
+ it lists are detail-only, and only the status mark and the branch name enabled
123
+ the `detail=1` fetch — so a pointer that went straight to `PR#47 ✓` had rested
124
+ on nothing that fetches, and its hover could not open until the mark had been
125
+ hovered first. The token is now its own detail gate, in both its linked and
126
+ plain forms.
127
+ - **No more "open a pull request" on `main`, and the hover card shows only the
128
+ server's verdict.** Two layers disagreed: the node half correctly returned
129
+ nothing to do for a clean, synced default branch, while the client's extras
130
+ still offered `/gh pr` — and the card promoted that extra into its `action:`
131
+ row, so a checkout with nothing to do displayed a suggestion. The node half now
132
+ resolves the repository's default branch (`refs/remotes/origin/HEAD`,
133
+ TTL-cached and refreshed out of band like the fetch, so the hot path pays
134
+ nothing) and flags it on the response; the `pr` extra is suppressed when the
135
+ branch IS that default; and the card's action row reads the server's `next`
136
+ directly, leaving the extras to the `/gh` picker where they belong.
137
+ - **The seam suite no longer writes into your real `~/.dsh/git-badge-seam`.**
138
+ One block spawned the postinstall hook without `SEAM_DATA_DIR`, so the hook
139
+ resolved its store to the machine's actual data directory: a test run
140
+ overwrote the real `backup-client.js`/`backup-index.js` and left a
141
+ `restart-pending.json` behind. It passed on CI only because the runner's
142
+ `$HOME` is writable — under a read-only `$HOME` it failed with EROFS. The
143
+ block now takes a throwaway data dir like the rest of the file.
144
+
13
145
  ## [0.16.1] - 2026-09-16
14
146
 
15
147
  ### Fixed
@@ -171,22 +303,18 @@ npm. 0.6.0 is the first release recorded here.
171
303
 
172
304
  ## [0.14.1] - 2026-09-15
173
305
 
306
+ ### Changed
307
+
174
308
  - **Skill alignment:** the `gh` skill gains an explicit handoff — one verb per
175
309
  invocation is its whole job; the multi-step PR lifecycle (review, merge,
176
310
  verify, cleanup) belongs to the `gh-pr` skill. The `gh-pr` skill states the
177
311
  mirror scope: one-shot verbs are `gh`'s, lifecycle is its own. The catalog
178
312
  stays global-only; repo conventions stay in `AGENTS.md`.
179
-
180
313
  - **The hover card is 33% wider** (360px → 480px) and its `action:` row now
181
314
  carries a trailing what-comment in git-comment convention — e.g.
182
315
  `action: /gh push # push local commits to the remote` — so the row says
183
316
  what the invocation does, not just which invocation it is. The picker in the
184
317
  (+) menu shares the same descriptions.
185
-
186
- ## [0.14.1] - 2026-09-15
187
-
188
- ### Changed
189
-
190
318
  - **The chip's hover card top line is now an `action:` row** — the gh skill
191
319
  invocation the checkout justifies (e.g. `/gh push`), in the card's ordinary
192
320
  label/value layout, replacing the next-step line's why-plus-copy-chip. The
@@ -578,7 +706,20 @@ npm. 0.6.0 is the first release recorded here.
578
706
  - `detail=1` is annotated as having no consumer yet (the hover card remains
579
707
  pending). Its comment previously claimed `log -1` while the code ran `log -3`.
580
708
 
581
- [Unreleased]: https://github.com/Kevin-McIsaac/dsh-workspace-git-badge/compare/v0.8.0...HEAD
709
+ [Unreleased]: https://github.com/Kevin-McIsaac/dsh-workspace-git-badge/compare/v0.17.0...HEAD
710
+ [0.17.0]: https://github.com/Kevin-McIsaac/dsh-workspace-git-badge/releases/tag/v0.17.0
711
+ [0.16.1]: https://github.com/Kevin-McIsaac/dsh-workspace-git-badge/releases/tag/v0.16.1
712
+ [0.16.0]: https://github.com/Kevin-McIsaac/dsh-workspace-git-badge/releases/tag/v0.16.0
713
+ [0.15.0]: https://github.com/Kevin-McIsaac/dsh-workspace-git-badge/releases/tag/v0.15.0
714
+ [0.14.1]: https://github.com/Kevin-McIsaac/dsh-workspace-git-badge/releases/tag/v0.14.1
715
+ [0.14.0]: https://github.com/Kevin-McIsaac/dsh-workspace-git-badge/releases/tag/v0.14.0
716
+ [0.13.0]: https://github.com/Kevin-McIsaac/dsh-workspace-git-badge/releases/tag/v0.13.0
717
+ [0.12.0]: https://github.com/Kevin-McIsaac/dsh-workspace-git-badge/releases/tag/v0.12.0
718
+ [0.11.0]: https://github.com/Kevin-McIsaac/dsh-workspace-git-badge/releases/tag/v0.11.0
719
+ [0.10.1]: https://github.com/Kevin-McIsaac/dsh-workspace-git-badge/releases/tag/v0.10.1
720
+ [0.10.0]: https://github.com/Kevin-McIsaac/dsh-workspace-git-badge/releases/tag/v0.10.0
721
+ [0.9.1]: https://github.com/Kevin-McIsaac/dsh-workspace-git-badge/releases/tag/v0.9.1
722
+ [0.9.0]: https://github.com/Kevin-McIsaac/dsh-workspace-git-badge/releases/tag/v0.9.0
582
723
  [0.8.0]: https://github.com/Kevin-McIsaac/dsh-workspace-git-badge/releases/tag/v0.8.0
583
724
  [0.7.0]: https://github.com/Kevin-McIsaac/dsh-workspace-git-badge/releases/tag/v0.7.0
584
725
  [0.6.0]: https://github.com/Kevin-McIsaac/dsh-workspace-git-badge/releases/tag/v0.6.0
package/README.md CHANGED
@@ -3,15 +3,15 @@
3
3
  Git status badges for [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness):
4
4
 
5
5
  - **Input-row chip** — `● main ↑0 ↓2 ✎3` next to the access picker, showing the git state of the workspace the current conversation is attached to. Works on every install.
6
- - **Hover card** — rest a pointer on the chip for what won't fit: the file breakdown (`✎3` split into staged / unstaged / untracked), the last three commits, and the stash. Fetched only on hover, so the everyday badge pays nothing for it. Works on every install.
6
+ - **Hover card** — rest a pointer on the chip for what won't fit: the file breakdown (`✎3` split into staged / unstaged / untracked), the last ten commits, and the stash. Fetched only on hover, so the everyday badge pays nothing for it. Works on every install.
7
7
  - **PR / CI token** — `● main ↑0 ↓2 PR#142 ✗` when the branch has a GitHub pull request, read through your own `gh` CLI (the plugin never handles a credential). The token **links to the PR** — it opens in a new tab, and underlines when you hover or focus it. Invisible when `gh` cannot answer: not installed, not logged in, no GitHub remote, offline or rate-limited all render the unchanged chip, and a token with no URL to link to stays plain text.
8
8
  - **Worktree-aware** — a conversation's directory is fixed when it is created, so a conversation that does its work in a linked `git worktree` would otherwise keep reporting the main checkout. The session registers its checkout (`npx dsh-git-badge-checkout <path>`, run by the git-worktree and `/gh checkout` paths), and the badge describes **that worktree** instead — its branch, counts, tree mark and PR/CI token (`🌳 chore/global-skills-tiering ↑0 ↓2 PR#391 ✓` rather than `● main`). The hover card names the tree in a `worktree` row and adds a `checkout` row with the conversation's own directory, so the main checkout's branch and dirty state stay one hover away. Registrations are advisory: git's own worktree list validates the path, entries expire after 24h, and a workspace-targeted row always reports the checkout the registry owns.
9
- - **Sidebar session-row action token** — each session row shows the ONE thing that conversation needs from you, or nothing at all: `merge`, `fix CI`, `review`, `resolve`, `pull`, `push`. It is triage rather than status: `merge` appears only when GitHub itself reports `mergeStateStatus: CLEAN`, and every waiting state (draft, blocked, behind, checks still running) stays silent. Hovering the row adds a line naming the checkout and the pull request the action refers to. The token floats to the right of the row, is set heavier than the timestamp beside it, and is coloured by how much it needs you — red for a conflict or a failing build, amber for a requested review, green for `merge`, quiet grey for routine sync. Requires the `sidebar.workspaces.sessionRow` seam; without it the plugin degrades to chip-only and logs what's active to the browser console.
9
+ - **Sidebar session-row action token** — each session row shows the ONE thing that conversation needs from you, or nothing at all: `merge`, `fix CI`, `review`, `resolve`, `pull`, `push`. It is triage rather than status: `merge` appears only when GitHub itself reports `mergeStateStatus: CLEAN`, and every waiting state (draft, blocked, behind, checks still running) stays silent. Hovering the row adds a line naming the checkout and the pull request the action refers to. The token floats to the right of the row, is set heavier than the timestamp beside it, and is coloured by how much it needs you — red for a conflict or a failing build, amber for a requested review, green for `merge`, quiet grey for routine sync. It appears only when the session is **idle** — while a turn is running the row stays quiet, because the checkout is still moving and a suggestion would describe a state that is about to change. Requires the `sidebar.workspaces.sessionRow` seam; without it the plugin degrades to chip-only and logs what's active to the browser console.
10
10
  - **Nothing on workspace rows.** A workspace cannot know which worktree its conversations are using, so a per-workspace badge could only guess or report the main checkout. The seam is on the session row for that reason.
11
11
 
12
12
  The leading **mark** belongs to the input chip: a circle filled with the status colour, or a **tree** when the checkout is a linked `git worktree`. The sidebar row deliberately carries no mark — see the row bullet above, where one word does the job a colour cannot. (`●`/`🌳` stand in for it here — it is a drawn SVG so that it can take the theme's status colours.)
13
13
 
14
- Event-driven freshness: working trees are watched and updates push over SSE — badges flip within ~1s of any commit, stage, or edit, including inside a linked worktree the session registered. One `git status --porcelain=v2` per sample, shared by every surface pointing at the same checkout, plus at most one `gh` read per repository-and-branch per ~90s. The status API takes **no path**: the caller passes a session id (chip and sidebar rows) or a workspace id, and the server resolves the directory itself.
14
+ Event-driven freshness: working trees are watched and updates push over SSE — badges flip within ~1s of any commit, stage, or edit, including inside a linked worktree the session registered. One `git status --porcelain=v2` per sample, shared by every surface pointing at the same checkout, plus at most one `gh` read per repository-and-branch per ~20s. The status API takes **no path**: the caller passes a session id (chip and sidebar rows) or a workspace id, and the server resolves the directory itself.
15
15
 
16
16
  Diagrams, the hover card's full field list and a walkthrough for git newcomers live
17
17
  in the [repo README](https://github.com/Kevin-McIsaac/dsh-workspace-git-badge) —