dsh-git-badge 0.9.1 → 0.10.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 +36 -0
- package/lib/client.js +26 -0
- package/package.json +5 -3
- package/seam/apply.js +22 -6
- package/seam/postinstall.js +91 -0
package/CHANGELOG.md
CHANGED
|
@@ -8,6 +8,42 @@ 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
|
+
## [Unreleased]
|
|
12
|
+
|
|
13
|
+
## [0.10.1] - 2026-09-14
|
|
14
|
+
|
|
15
|
+
### Fixed
|
|
16
|
+
|
|
17
|
+
- **Revert backups now live in a stable, user-level store.** They defaulted to
|
|
18
|
+
the patcher's own directory — which for `npx dsh-git-badge` is a cache entry
|
|
19
|
+
keyed by package version, so a backup written by one `apply` was invisible to
|
|
20
|
+
the next `revert`, which then had to refuse ("patched but no backup exists")
|
|
21
|
+
even though the bytes were on disk somewhere. The default is now
|
|
22
|
+
`$DSH_HOME/git-badge-seam` (else `~/.dsh/git-badge-seam`), shared by npx
|
|
23
|
+
runs, the profile bin, the repo wrapper and the postinstall hook;
|
|
24
|
+
`SEAM_DATA_DIR` still overrides. Backups written by older versions to their
|
|
25
|
+
install directories are not migrated — the no-backup refusal now says so and
|
|
26
|
+
names both remaining routes (the repo wrapper's backup, or reinstalling the
|
|
27
|
+
DSH package).
|
|
28
|
+
|
|
29
|
+
## [0.10.0] - 2026-09-14
|
|
30
|
+
|
|
31
|
+
### Added
|
|
32
|
+
|
|
33
|
+
- **The install flow now tells you about the one manual step, everywhere it can.**
|
|
34
|
+
A market install activates the input chip immediately, but the sidebar
|
|
35
|
+
session-row badges additionally need the seam patch — and nothing said so.
|
|
36
|
+
Now: the market-listing description names the step; the README leads with the
|
|
37
|
+
two-command install order; a guarded `postinstall` applies the seam at
|
|
38
|
+
install time **when pnpm allows it** (opt-in via `allowBuilds` — DSH's plugin
|
|
39
|
+
installer prints that instruction whenever pnpm blocks a build) and only ever
|
|
40
|
+
in the one safe state (pristine upstream, all anchors resolving — anything
|
|
41
|
+
else just prints, and the hook can never fail an install); and when the seam
|
|
42
|
+
is still absent ~5s after boot, every input chip gains a tooltip naming the
|
|
43
|
+
command — the first message visible in the product rather than the console.
|
|
44
|
+
Restart stays manual by design: an install script restarting the host that is
|
|
45
|
+
installing it is not safe to automate.
|
|
46
|
+
|
|
11
47
|
## [0.9.1] - 2026-09-14
|
|
12
48
|
|
|
13
49
|
### Fixed
|
package/lib/client.js
CHANGED
|
@@ -695,6 +695,14 @@ window.__ModuleLoader__.load({
|
|
|
695
695
|
* always, `detail=1` on hover), because it is the only one that renders
|
|
696
696
|
* them — see targetQuery.
|
|
697
697
|
*/
|
|
698
|
+
/**
|
|
699
|
+
* Set LATE (see apply) — never at apply() time, because the workspace
|
|
700
|
+
* browser may not have declared the seam yet and a hint set then would
|
|
701
|
+
* lie to patched installs for the whole session. Every chip render reads
|
|
702
|
+
* it, so it reaches the DOM on the next refresh after it is set.
|
|
703
|
+
*/
|
|
704
|
+
let seamHint = null;
|
|
705
|
+
|
|
698
706
|
function ComposerGitChip({ sessionId }) {
|
|
699
707
|
const target = sessionId === void 0 ? void 0 : { kind: "session", id: sessionId };
|
|
700
708
|
// the PR/CI token is always on the chip, so its fetch is not gated
|
|
@@ -730,6 +738,11 @@ window.__ModuleLoader__.load({
|
|
|
730
738
|
whiteSpace: "nowrap",
|
|
731
739
|
cursor: "default"
|
|
732
740
|
},
|
|
741
|
+
// the only in-product message a market user gets when the seam is
|
|
742
|
+
// absent: hover the chip you CAN see to learn the one command that
|
|
743
|
+
// turns on the rows you cannot. null until the delayed check in
|
|
744
|
+
// apply() proves the seam never appeared.
|
|
745
|
+
title: seamHint === null ? undefined : seamHint,
|
|
733
746
|
// the card is fetched for a pointer that RESTS here, not one that
|
|
734
747
|
// merely crosses the chip
|
|
735
748
|
onPointerEnter: () => setHovered(true),
|
|
@@ -851,6 +864,19 @@ window.__ModuleLoader__.load({
|
|
|
851
864
|
// The patcher ships IN this package — no clone needed.
|
|
852
865
|
"off (seam absent) — run `npx dsh-git-badge apply` to add them, then restart dsh web.")
|
|
853
866
|
);
|
|
867
|
+
// The chip tooltip can only be set LATE. At apply() time the workspace
|
|
868
|
+
// browser may not have declared the seam yet (the boot race documented
|
|
869
|
+
// above), so claiming absence here would lie to patched installs for the
|
|
870
|
+
// whole session — the exact mistake that made the old one-shot line
|
|
871
|
+
// claim "sidebar rows = off" while five row badges were rendering. Give
|
|
872
|
+
// the composed graph a beat to settle; only a seam that is STILL absent
|
|
873
|
+
// earns the hint, and every chip render after that carries it.
|
|
874
|
+
setTimeout(() => {
|
|
875
|
+
if (rowsReported) return; // seam present; badges rendered — nothing to hint about
|
|
876
|
+
if (ctx.slots.spec("sidebar.workspaces.sessionRow") !== void 0) return;
|
|
877
|
+
seamHint =
|
|
878
|
+
"Session-row badges are off: run `npx dsh-git-badge apply`, then restart dsh web. (Input-chip badges are unaffected.)";
|
|
879
|
+
}, 5000);
|
|
854
880
|
// The hover card depends on a primitive the SHELL seeds, not on anything
|
|
855
881
|
// this plugin declares. Report the outcome rather than letting a missing
|
|
856
882
|
// seed look like a missing feature: the try/catch above deliberately keeps
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-git-badge",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Git status badges for DeepSeek Harness: sidebar session
|
|
3
|
+
"version": "0.10.1",
|
|
4
|
+
"description": "Git status badges for DeepSeek Harness: an input-row chip on every install, plus sidebar session-row badges (git status, PR/CI action tokens) after one manual step: `npx dsh-git-badge apply`, then restart dsh web. Event-driven freshness over SSE.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|
|
7
7
|
"bin": {
|
|
@@ -13,7 +13,8 @@
|
|
|
13
13
|
"./package.json": "./package.json"
|
|
14
14
|
},
|
|
15
15
|
"scripts": {
|
|
16
|
-
"test": "node --test"
|
|
16
|
+
"test": "node --test",
|
|
17
|
+
"postinstall": "node seam/postinstall.js"
|
|
17
18
|
},
|
|
18
19
|
"dsh": {
|
|
19
20
|
"bundle": {
|
|
@@ -50,6 +51,7 @@
|
|
|
50
51
|
"lib/client.js",
|
|
51
52
|
"seam/apply.js",
|
|
52
53
|
"seam/anchors.js",
|
|
54
|
+
"seam/postinstall.js",
|
|
53
55
|
"seam/stub-index.js",
|
|
54
56
|
"cordis.patch.yml",
|
|
55
57
|
"package.json",
|
package/seam/apply.js
CHANGED
|
@@ -33,8 +33,10 @@
|
|
|
33
33
|
*
|
|
34
34
|
* Environment:
|
|
35
35
|
* DSH_INSTALL the DSH package root. Default: `<global npm root>/@deepseek-ai/dsh`.
|
|
36
|
-
* SEAM_DATA_DIR where revert backups are written. Default:
|
|
37
|
-
*
|
|
36
|
+
* SEAM_DATA_DIR where revert backups are written. Default:
|
|
37
|
+
* `$DSH_HOME/git-badge-seam` (else `~/.dsh/git-badge-seam`) —
|
|
38
|
+
* a stable, user-level store shared by every way this tool
|
|
39
|
+
* can run. See the note at the definition below.
|
|
38
40
|
*
|
|
39
41
|
* Usage: apply.js apply | apply.js revert | apply.js status
|
|
40
42
|
*/
|
|
@@ -54,7 +56,17 @@ import {
|
|
|
54
56
|
} from "./anchors.js";
|
|
55
57
|
|
|
56
58
|
const HERE = dirname(fileURLToPath(import.meta.url));
|
|
57
|
-
|
|
59
|
+
/**
|
|
60
|
+
* Where revert backups live. A STABLE, user-level directory by default — NOT
|
|
61
|
+
* this script's own directory. For an npx run that directory is a cache entry
|
|
62
|
+
* keyed by package version: a backup written by one `npx dsh-git-badge apply`
|
|
63
|
+
* was invisible to the next `npx dsh-git-badge revert`, which then had to
|
|
64
|
+
* refuse ("patched but no backup exists") even though the bytes were on disk
|
|
65
|
+
* somewhere. Sharing one store across npx runs, the profile bin and the repo
|
|
66
|
+
* wrapper makes the apply→revert round trip reliable for everyone. Override
|
|
67
|
+
* with SEAM_DATA_DIR (the test suite does, to stay hermetic).
|
|
68
|
+
*/
|
|
69
|
+
const DATA_DIR = process.env.SEAM_DATA_DIR || join(process.env.DSH_HOME || join(process.env.HOME || "", ".dsh"), "git-badge-seam");
|
|
58
70
|
|
|
59
71
|
// sha256 of the upstream build the anchors were last verified against. ADVISORY:
|
|
60
72
|
// status prints it for orientation; apply does NOT require it.
|
|
@@ -291,9 +303,13 @@ if (verb === "apply") {
|
|
|
291
303
|
} else {
|
|
292
304
|
const r = inspect();
|
|
293
305
|
if (r.state === "ours-current" || r.state === "ours-stale" || r.state === "ours-corrupt") {
|
|
294
|
-
console.error("REFUSING: the installed file is patched but no backup exists
|
|
295
|
-
console.error(
|
|
296
|
-
console.error("
|
|
306
|
+
console.error("REFUSING: the installed file is patched but no backup exists in");
|
|
307
|
+
console.error(`${DATA_DIR}, so the original bytes are unknown here. Options:`);
|
|
308
|
+
console.error(" 1. If you applied from a clone of the plugin's repository, run its");
|
|
309
|
+
console.error(" wrapper instead — it keeps its own backup:");
|
|
310
|
+
console.error(" <clone>/seam/apply.sh revert");
|
|
311
|
+
console.error(" 2. Otherwise reinstall the package — pristine files, guaranteed:");
|
|
312
|
+
console.error(" npm i -g @deepseek-ai/dsh@latest");
|
|
297
313
|
process.exit(1);
|
|
298
314
|
}
|
|
299
315
|
console.log("no backup present and nothing of ours installed; client.js left untouched.");
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* postinstall hook — best-effort seam apply at plugin-install time.
|
|
4
|
+
*
|
|
5
|
+
* WHY THIS EXISTS: a market install activates the input chip immediately, but
|
|
6
|
+
* the sidebar session-row badges additionally need the seam patch on the DSH
|
|
7
|
+
* package itself, and nothing in the install flow told the user so. When pnpm
|
|
8
|
+
* allows this script (the user approves it under `allowBuilds` — DSH's plugin
|
|
9
|
+
* installer prints exactly that instruction when pnpm blocks it), the seam is
|
|
10
|
+
* applied right here; otherwise the plugin's boot log and the chip tooltip name
|
|
11
|
+
* the same one manual command.
|
|
12
|
+
*
|
|
13
|
+
* GUARDRAILS — this script may never break an install:
|
|
14
|
+
* - it runs ONLY when the installed DSH client.js is pristine upstream AND
|
|
15
|
+
* every anchor resolves exactly once (`patchable`); any other state —
|
|
16
|
+
* already patched, drifted, upstream-landed, DSH not found — just prints
|
|
17
|
+
* - it never throws: every failure path prints the manual command and exits 0
|
|
18
|
+
* - it cannot restart dsh web; the printed message says to
|
|
19
|
+
*
|
|
20
|
+
* The restart is deliberately manual: the running dsh web process rebuilds its
|
|
21
|
+
* client bundle at boot, and an install script restarting the host that is
|
|
22
|
+
* installing it is not safe to automate.
|
|
23
|
+
*/
|
|
24
|
+
import { execSync } from "node:child_process";
|
|
25
|
+
import { copyFileSync, existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
26
|
+
import { dirname, join } from "node:path";
|
|
27
|
+
import { fileURLToPath } from "node:url";
|
|
28
|
+
import { applyPatch, firstFailure, isOurs, seamPresent } from "./anchors.js";
|
|
29
|
+
|
|
30
|
+
const HERE = dirname(fileURLToPath(import.meta.url));
|
|
31
|
+
const HINT = "Sidebar session-row badges need one manual step: `npx dsh-git-badge apply`, then restart dsh web.";
|
|
32
|
+
/**
|
|
33
|
+
* Same stable backup store apply.js defaults to — the backup this hook takes
|
|
34
|
+
* must be findable by a LATER `npx dsh-git-badge revert` running from a
|
|
35
|
+
* different cache entry. SEAM_DATA_DIR overrides (test suite).
|
|
36
|
+
*/
|
|
37
|
+
const DATA_DIR = process.env.SEAM_DATA_DIR || join(process.env.DSH_HOME || join(process.env.HOME || "", ".dsh"), "git-badge-seam");
|
|
38
|
+
|
|
39
|
+
function dshClientPath() {
|
|
40
|
+
try {
|
|
41
|
+
const root = process.env.DSH_INSTALL || join(execSync("npm root -g", { encoding: "utf8" }).trim(), "@deepseek-ai", "dsh");
|
|
42
|
+
return join(root, "node_modules", "@deepseek-ai", "dsh-client-ui-workspace", "lib", "client.js");
|
|
43
|
+
} catch {
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function main() {
|
|
49
|
+
const client = dshClientPath();
|
|
50
|
+
if (client === null || !existsSync(client)) {
|
|
51
|
+
console.log(`[dsh-git-badge] DSH install not found; skipping seam setup. ${HINT}`);
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
// the index stub is copied with the client on apply (see apply.js)
|
|
55
|
+
const index = join(dirname(client), "index.js");
|
|
56
|
+
const text = readFileSync(client, "utf8");
|
|
57
|
+
|
|
58
|
+
// Already ours (any rev): nothing to do here; apply.js upgrade rules govern.
|
|
59
|
+
if (isOurs(text)) {
|
|
60
|
+
console.log("[dsh-git-badge] seam already applied — sidebar session-row badges active after restart.");
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
// Upstream landed the seam: the patch is retired.
|
|
64
|
+
if (seamPresent(text)) {
|
|
65
|
+
console.log("[dsh-git-badge] DSH declares the seam itself — no patch needed.");
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
// Pristine, but the anchors no longer resolve: a DSH update moved anchored
|
|
69
|
+
// code. Never patch half of anything — print, and let a patched anchors.js
|
|
70
|
+
// do it.
|
|
71
|
+
const fail = firstFailure(text);
|
|
72
|
+
if (fail !== null) {
|
|
73
|
+
console.log(`[dsh-git-badge] DSH build drifted from the patch anchors (${fail.name}); skipping. ${HINT}`);
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
// The one state we act on: pristine upstream, anchors resolve.
|
|
77
|
+
mkdirSync(DATA_DIR, { recursive: true });
|
|
78
|
+
copyFileSync(client, join(DATA_DIR, "backup-client.js"));
|
|
79
|
+
copyFileSync(index, join(DATA_DIR, "backup-index.js"));
|
|
80
|
+
writeFileSync(client, applyPatch(text));
|
|
81
|
+
copyFileSync(join(HERE, "stub-index.js"), index);
|
|
82
|
+
console.log("[dsh-git-badge] seam applied — RESTART dsh web to get sidebar session-row badges.");
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
try {
|
|
86
|
+
main();
|
|
87
|
+
} catch (error) {
|
|
88
|
+
// An install hook must never fail the install over the seam.
|
|
89
|
+
console.log(`[dsh-git-badge] seam setup skipped (${String(error && error.message ? error.message : error)}). ${HINT}`);
|
|
90
|
+
}
|
|
91
|
+
process.exit(0);
|