dsh-git-badge 0.7.0 → 0.9.0
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 -3
- package/README.md +12 -4
- package/lib/client.js +499 -107
- package/lib/index.js +623 -18
- package/package.json +8 -2
- package/seam/anchors.js +138 -0
- package/seam/apply.js +304 -0
- package/seam/stub-index.js +11 -0
package/CHANGELOG.md
CHANGED
|
@@ -8,14 +8,158 @@ this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
|
|
|
8
8
|
Versions before 0.6.0 predate this file; their history is in `git log` and on
|
|
9
9
|
npm. 0.6.0 is the first release recorded here.
|
|
10
10
|
|
|
11
|
-
## [
|
|
11
|
+
## [0.9.0] - 2026-09-14
|
|
12
|
+
|
|
13
|
+
### Added
|
|
14
|
+
|
|
15
|
+
- **The seam patcher ships in the package** as the `dsh-git-badge-seam` bin, so a
|
|
16
|
+
market install can add the sidebar session-row badges without cloning the
|
|
17
|
+
repository: `npx dsh-git-badge-seam apply`, then restart. Pure Node (no
|
|
18
|
+
python3), anchor-based like the repo tooling it replaces, with the same
|
|
19
|
+
refusal semantics: it writes nothing unless every anchor resolves exactly
|
|
20
|
+
once, upgrades its own older artifacts by marker revision, and reverts to the
|
|
21
|
+
bytes as found before patching. When the seam is absent the plugin's boot log
|
|
22
|
+
now says so and names the command.
|
|
23
|
+
|
|
24
|
+
### Added
|
|
25
|
+
|
|
26
|
+
- **A session's badge follows the worktree its work is in.** A conversation's
|
|
27
|
+
directory is fixed when it is created, and DSH records no session→worktree link
|
|
28
|
+
at all (`attachSession` requires the stored cwd to equal the workspace path), so
|
|
29
|
+
a conversation started in the main checkout reported `main` — including "no pull
|
|
30
|
+
request" — while its work and its PR lived in a linked worktree.
|
|
31
|
+
Now, when a **session**-targeted badge resolves to a main checkout whose
|
|
32
|
+
repository has exactly one linked worktree whose branch has an **open** pull
|
|
33
|
+
request, the badge describes that worktree instead: its branch, dirty counts,
|
|
34
|
+
ahead/behind, tree-shaped mark, and PR/CI token. The `workspace` id in the
|
|
35
|
+
response is unchanged, so SSE attribution is unaffected.
|
|
36
|
+
The selection is deliberately the only one that cannot be ambiguous — one open
|
|
37
|
+
PR is a candidate, two are a reason to say nothing — the worktree is **named**
|
|
38
|
+
on the chip even when the branch would make the name look redundant, the mark's
|
|
39
|
+
accessible name states that the checkout was inferred, and the hover card gains
|
|
40
|
+
a `checkout` row carrying the conversation's OWN directory (branch · files ·
|
|
41
|
+
sync) so the main checkout's state stays visible. A workspace-targeted sidebar
|
|
42
|
+
row never follows a worktree: a row surveys the checkout the registry owns.
|
|
43
|
+
- **An inferred worktree is watched.** Its working tree and git dir get the same
|
|
44
|
+
event-driven treatment as a registered workspace's, and its events carry the
|
|
45
|
+
**owning workspace id**, so the badge refreshes within ~1s of a stage, commit or
|
|
46
|
+
checkout in the tree — including a worktree that is not itself a registered
|
|
47
|
+
workspace, which the main checkout's recursive watch would never see.
|
|
48
|
+
- **Identical concurrent status reads are collapsed** into one `git status` per
|
|
49
|
+
directory, which is the shape a burst of badges mounting together produces.
|
|
50
|
+
`statusCacheMs` (default 0) optionally extends that to serial bursts; the 0
|
|
51
|
+
default keeps a read taken after a mutation honest. New config: `worktreeStatus`
|
|
52
|
+
(`"auto"` | `"off"`), `prListLimit`, `statusCacheMs`.
|
|
53
|
+
- The repository-wide open-PR read (`gh pr list`) happens at most once per TTL per
|
|
54
|
+
repository, and never at all for a repository with no linked worktree.
|
|
55
|
+
|
|
56
|
+
### Changed
|
|
57
|
+
|
|
58
|
+
- **The sidebar session row is an ACTION token, not a status badge.** It shows
|
|
59
|
+
the one thing that conversation needs — `merge`, `fix CI`, `review`, `resolve`,
|
|
60
|
+
`pull`, `push` — and nothing when there is nothing to do. `merge` keys on
|
|
61
|
+
GitHub's own `mergeStateStatus: CLEAN` rather than a verdict assembled here; a
|
|
62
|
+
draft, blocked, behind, unstable or unknown PR stays silent, because waiting is
|
|
63
|
+
not an action. This is deliberately a trade: the row no longer shows local
|
|
64
|
+
status or the worktree's tree shape, and the hover line — which now names the
|
|
65
|
+
pull request as well as the checkout — is where that detail lives. The word floats right so a column of actions lines
|
|
66
|
+
up down the sidebar, sits heavier than the timestamp beside it, and is coloured
|
|
67
|
+
by SEVERITY with the app's own state tokens — error for `resolve` and `fix CI`,
|
|
68
|
+
warn for `review`, success for `merge`, quiet secondary for `pull` and `push` —
|
|
69
|
+
so the loud rows keep meaning something. The chip is unchanged. Revert this
|
|
70
|
+
commit to go back to the mark-plus-token row.
|
|
71
|
+
- **The sidebar badge moved from the workspace row to the session row.** A
|
|
72
|
+
workspace row cannot know which worktree its conversations are using, so a
|
|
73
|
+
per-workspace badge could only guess or report the main checkout. Each session
|
|
74
|
+
row now carries the status mark plus the PR/CI token when the branch has one
|
|
75
|
+
(`🌳 PR#391 ✓`), and never a branch — hovering the row adds a line naming the
|
|
76
|
+
checkout that badge describes (`checkout: hotfix-tree on feat/x`, and for an
|
|
77
|
+
inferred worktree, why it was followed). Rows still issue no request of their
|
|
78
|
+
own beyond the badge's: the hover line resolves to the same cache key, so a card
|
|
79
|
+
that mounts for every row cannot multiply git or forge work.
|
|
80
|
+
- The `seam/` patch now declares `sidebar.workspaces.sessionRow` and
|
|
81
|
+
`sidebar.workspaces.sessionRow.detail` instead of the old
|
|
82
|
+
`sidebar.workspaces.row` pair, and the row is rendered from the **tree** call
|
|
83
|
+
site only, which keeps the flat and search lists badge-free with no guard of
|
|
84
|
+
their own. `seam/apply.sh` recognises its own older artifacts by a marker
|
|
85
|
+
comment (and the previous hash), so rebuilding the patch installs it instead of
|
|
86
|
+
being skipped as "upstream landed" — and `revert` now restores the upstream
|
|
87
|
+
baseline rather than an older patch.
|
|
88
|
+
|
|
89
|
+
### Fixed
|
|
90
|
+
|
|
91
|
+
- **A failing seam occupant could blank the whole sidebar.** The host guards each
|
|
92
|
+
registered *entry* with an error boundary, but not the outlet a row renders
|
|
93
|
+
itself, so a throw in an occupant's render path reached the workspace browser —
|
|
94
|
+
and the shell abdicates that entry, removing the entire sidebar region about a
|
|
95
|
+
second after boot. The seam patch now wraps both session-row renders in its own
|
|
96
|
+
boundary: a broken occupant loses its badge and logs the error instead.
|
|
97
|
+
- **The PR cache served the wrong branch.** `prStatusFor` was keyed by toplevel
|
|
98
|
+
only, so a checkout that changed branch inside the TTL window was served the
|
|
99
|
+
previous branch's pull request. It is now keyed by toplevel **and** branch.
|
|
100
|
+
|
|
101
|
+
## [0.8.0] - 2026-09-12
|
|
102
|
+
|
|
103
|
+
### Added
|
|
104
|
+
|
|
105
|
+
- **A hover card on the input chip.** Resting a pointer on the chip now shows what
|
|
106
|
+
the chip has no room for: the file breakdown (`✎3` split into staged / unstaged
|
|
107
|
+
/ unmerged / untracked, so *ready to commit* is distinguishable from *not staged
|
|
108
|
+
yet*), the last three commits with their ages, and the stash count. When the
|
|
109
|
+
untracked walk fell back to git's collapsed count the card says `(collapsed)`
|
|
110
|
+
rather than presenting an under-count as exact.
|
|
111
|
+
The card consumes the `detail=1` payload the node half has carried unused since
|
|
112
|
+
0.6.0, and it is **lazy**: the extra fields cost a `log -3` plus a stash list, so
|
|
113
|
+
they are fetched only once a pointer rests on the chip and then kept fresh over
|
|
114
|
+
the same SSE path. A badge refresh fires on every file edit, and the everyday
|
|
115
|
+
chip still pays for none of it. It uses the shell's own seeded `Tooltip`
|
|
116
|
+
primitive — no new dependency, no seam patch — and if that primitive is ever
|
|
117
|
+
absent the chip renders uncarded rather than not at all. The boot log reports
|
|
118
|
+
which path was taken (`[dsh-git-badge] hover card = on (shell Tooltip
|
|
119
|
+
primitive).`), because the guard that keeps the badge working would otherwise
|
|
120
|
+
make a missing seed look like a missing feature.
|
|
121
|
+
- **A PR / CI token on the input chip.** When the branch has a GitHub pull
|
|
122
|
+
request the chip carries `PR#142` with the rollup state (`✓` passing, `…`
|
|
123
|
+
running, `✗` failing) and a `draft` marker. It reads the PR through the user's
|
|
124
|
+
own `gh` CLI, so the plugin never handles a credential. The rollup is reduced to
|
|
125
|
+
one worst-case state (a single failure outweighs any number of successes), the
|
|
126
|
+
token carries an accessible name naming the state, and the hover card spells out
|
|
127
|
+
the check state, draft and review decision.
|
|
128
|
+
- **The PR token links to the pull request.** When `gh` reports an http(s) URL the
|
|
129
|
+
token is an anchor that opens the PR in a new tab, so this browser tab keeps the
|
|
130
|
+
conversation. It underlines on hover or focus only — the at-rest signal is the
|
|
131
|
+
pointer cursor — and keeps the chip's own colour instead of the browser's link
|
|
132
|
+
blue, so it still reads as one row. Being an anchor, it is also keyboard-reachable
|
|
133
|
+
now, which the text token was not. The protocol is checked on both halves: only
|
|
134
|
+
`http:`/`https:` is carried or rendered, so a payload value can never become a
|
|
135
|
+
`javascript:` href.
|
|
136
|
+
- `?pr=1` on the status route. PR/CI is asked for by the **chip only**, so a
|
|
137
|
+
sidebar that surveys twenty workspaces never spawns twenty `gh` processes. The
|
|
138
|
+
read is TTL-bounded (~90s per repository), refreshed out of band exactly like
|
|
139
|
+
the existing fetch, and notifies subscribers only when the state actually
|
|
140
|
+
changes.
|
|
141
|
+
- **PR/CI degrades to an absent field, never an error.** No `gh`, a logged-out
|
|
142
|
+
`gh`, a non-GitHub remote, an offline network, a rate limit, unparseable output
|
|
143
|
+
and a timed-out call all render the unchanged chip: a caller cannot tell "no PR"
|
|
144
|
+
from "no `gh`", because neither changes what should be displayed.
|
|
145
|
+
- A `runCli` helper the git and `gh` invocations now share, so `gh` inherits the
|
|
146
|
+
same timeout / missing-binary / exit-code semantics (and `GIT_TERMINAL_PROMPT`'s
|
|
147
|
+
analogue, `GH_PROMPT_DISABLED`, keeps an auth prompt from hanging a refresh).
|
|
148
|
+
|
|
149
|
+
### Changed
|
|
150
|
+
|
|
151
|
+
- The `detail=1` payload has a consumer at last. Its annotation said "no surface
|
|
152
|
+
consumes this yet"; the input chip's hover card is that surface, so the
|
|
153
|
+
branch/last-commits/stash fields are no longer speculative.
|
|
154
|
+
- `config` gains `prStatus` (`"auto"` / `"off"`), `prTtlMs`, `prTimeoutMs` and a
|
|
155
|
+
`prRunner` test seam mirroring `gitRunner`.
|
|
12
156
|
|
|
13
157
|
## [0.7.0] - 2026-09-12
|
|
14
158
|
|
|
15
159
|
### Changed
|
|
16
160
|
|
|
17
161
|
- **Both surfaces draw the same status mark.** The input chip no longer leads with
|
|
18
|
-
a 🔴/🟡/🟢 emoji dot: it renders the SAME
|
|
162
|
+
a 🔴/🟡/🟢 emoji dot: it renders the SAME SVG mark as the sidebar row — a
|
|
19
163
|
filled **circle**, or a **tree** for a linked `git worktree` — so the shape says
|
|
20
164
|
*worktree or not* and the fill says *status*, identically wherever the badge
|
|
21
165
|
appears. The `⑂` worktree glyph is gone with the emoji: the tree shape already
|
|
@@ -136,6 +280,7 @@ npm. 0.6.0 is the first release recorded here.
|
|
|
136
280
|
- `detail=1` is annotated as having no consumer yet (the hover card remains
|
|
137
281
|
pending). Its comment previously claimed `log -1` while the code ran `log -3`.
|
|
138
282
|
|
|
139
|
-
[Unreleased]: https://github.com/Kevin-McIsaac/dsh-workspace-git-badge/compare/v0.
|
|
283
|
+
[Unreleased]: https://github.com/Kevin-McIsaac/dsh-workspace-git-badge/compare/v0.8.0...HEAD
|
|
284
|
+
[0.8.0]: https://github.com/Kevin-McIsaac/dsh-workspace-git-badge/releases/tag/v0.8.0
|
|
140
285
|
[0.7.0]: https://github.com/Kevin-McIsaac/dsh-workspace-git-badge/releases/tag/v0.7.0
|
|
141
286
|
[0.6.0]: https://github.com/Kevin-McIsaac/dsh-workspace-git-badge/releases/tag/v0.6.0
|
package/README.md
CHANGED
|
@@ -3,11 +3,19 @@
|
|
|
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
|
-
- **
|
|
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.
|
|
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
|
+
- **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. When exactly one linked worktree of that repository has an open pull request, 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, says it was inferred, and adds a `checkout` row with the conversation's own directory, so the main checkout's branch and dirty state stay one hover away. One candidate only — two open PRs across worktrees is a reason to say nothing rather than guess — and a session row always reports the checkout that session is working in.
|
|
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.
|
|
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.
|
|
7
11
|
|
|
8
|
-
The leading **mark**
|
|
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.)
|
|
9
13
|
|
|
10
|
-
Event-driven freshness: working trees are watched and updates push over SSE — badges flip within ~1s of any commit, stage, or edit. One `git status --porcelain=v2`
|
|
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 that is only inferred. 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 and one repository-wide open-PR list 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.
|
|
15
|
+
|
|
16
|
+
Diagrams, the hover card's full field list and a walkthrough for git newcomers live
|
|
17
|
+
in the [repo README](https://github.com/Kevin-McIsaac/dsh-workspace-git-badge) —
|
|
18
|
+
this file is the npm-facing summary.
|
|
11
19
|
|
|
12
20
|
## Install
|
|
13
21
|
|
|
@@ -15,7 +23,7 @@ Event-driven freshness: working trees are watched and updates push over SSE —
|
|
|
15
23
|
dsh plugin --profile web add dsh-git-badge
|
|
16
24
|
```
|
|
17
25
|
|
|
18
|
-
Restart the web process, refresh the browser. Requires Node ≥ 20 and `git` on PATH.
|
|
26
|
+
Restart the web process, refresh the browser. Requires Node ≥ 20 and `git` on PATH. `gh`, on PATH and authenticated, is optional — it only enables the PR/CI token.
|
|
19
27
|
|
|
20
28
|
Seam details: [github.com/Kevin-McIsaac/dsh-workspace-git-badge](https://github.com/Kevin-McIsaac/dsh-workspace-git-badge) (SEAM.md / PR.md).
|
|
21
29
|
|