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 +148 -7
- package/README.md +3 -3
- package/lib/client.js +329 -184
- package/lib/index.js +215 -106
- package/package.json +2 -4
- package/seam/apply.js +34 -154
- package/seam/checkout.js +3 -5
- package/seam/patch.js +142 -0
- package/seam/postinstall.js +38 -50
- package/seam/store.js +8 -4
- package/skill/gh/SKILL.md +23 -1
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.
|
|
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
|
|
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 ~
|
|
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) —
|