dsh-git-badge 0.11.0 → 0.13.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 +27 -0
- package/lib/client.js +77 -123
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -10,6 +10,33 @@ npm. 0.6.0 is the first release recorded here.
|
|
|
10
10
|
|
|
11
11
|
## [Unreleased]
|
|
12
12
|
|
|
13
|
+
## [0.13.0] - 2026-09-15
|
|
14
|
+
|
|
15
|
+
### Added
|
|
16
|
+
|
|
17
|
+
- **A visible seam-absent notice on the input chip.** When `allowBuilds` keeps
|
|
18
|
+
the postinstall from patching, a market install lands chip-working but
|
|
19
|
+
sidebar-off with no message anywhere — dshmarket cannot see host files, and
|
|
20
|
+
the old hint was a hover tooltip nobody finds. Now, once the 5-second boot
|
|
21
|
+
grace proves the seam is genuinely absent, the chip shows
|
|
22
|
+
*sidebar badges off — run `npx dsh-git-badge apply`* with a dismiss **×**.
|
|
23
|
+
The notice is always true and self-resolving: apply + restart makes the seam
|
|
24
|
+
declare and it never renders again. The × means *stop asking this boot* —
|
|
25
|
+
dismissal is session-scoped, so a seam that is still absent asks again at the
|
|
26
|
+
next boot, and the long-form explanation stays on the chip's hover tooltip.
|
|
27
|
+
|
|
28
|
+
## [0.12.0] - 2026-09-15
|
|
29
|
+
|
|
30
|
+
### Removed
|
|
31
|
+
|
|
32
|
+
- **The restart notice and one-click Restart button are gone from the input
|
|
33
|
+
chip.** The inline text — *restart dsh web to activate the sidebar badges* —
|
|
34
|
+
and its Restart button (`POST /dsh-market/api/v1/restart`) could outlive the
|
|
35
|
+
restart it asked for when the marker survived a boot, and the nag outweighed
|
|
36
|
+
the convenience. The restart-pending marker pipeline is intact server-side
|
|
37
|
+
(`seam/store.js`, `seamRestartPending` on the status response) for a future
|
|
38
|
+
marketplace-surface notification; the chip simply no longer renders it.
|
|
39
|
+
|
|
13
40
|
## [0.11.0] - 2026-09-14
|
|
14
41
|
|
|
15
42
|
### Added
|
package/lib/client.js
CHANGED
|
@@ -704,46 +704,14 @@ window.__ModuleLoader__.load({
|
|
|
704
704
|
let seamHint = null;
|
|
705
705
|
|
|
706
706
|
/**
|
|
707
|
-
*
|
|
708
|
-
*
|
|
709
|
-
*
|
|
710
|
-
*
|
|
711
|
-
*
|
|
712
|
-
*
|
|
713
|
-
* rendered as text-only on hosts that delegate restart (desktop /
|
|
714
|
-
* supervised), never a hand-rolled process-control path.
|
|
707
|
+
* Dismissal of the seam-absent notice, deliberately MODULE-level rather
|
|
708
|
+
* than component state: a useState flag would un-dismiss when the chip
|
|
709
|
+
* remounts (a sidebar toggle, a route change), and the × the user just
|
|
710
|
+
* clicked would silently stop meaning anything. Session-scoped on
|
|
711
|
+
* purpose — it resets at the next boot, so a seam that is STILL absent
|
|
712
|
+
* asks again, while one fixed by apply + restart never nags at all.
|
|
715
713
|
*/
|
|
716
|
-
|
|
717
|
-
try {
|
|
718
|
-
const cap = await fetch("/dsh-market/api/v1/capabilities", { headers: { accept: "application/json" } }).then((r) => r.json());
|
|
719
|
-
return cap !== null && typeof cap === "object" && cap.restart !== void 0 && cap.restart.supported === true;
|
|
720
|
-
} catch {
|
|
721
|
-
return false;
|
|
722
|
-
}
|
|
723
|
-
}
|
|
724
|
-
|
|
725
|
-
async function marketRestart() {
|
|
726
|
-
await fetch("/dsh-market/api/v1/restart", {
|
|
727
|
-
method: "POST",
|
|
728
|
-
headers: { accept: "application/json", "content-type": "application/json" },
|
|
729
|
-
body: "{}",
|
|
730
|
-
}).catch(() => void 0); // the host drops the socket mid-restart — expected
|
|
731
|
-
// Poll until the origin is serving again, then reload into the
|
|
732
|
-
// recomposed boot. Bounded so a failed relaunch cannot spin forever.
|
|
733
|
-
for (let waited = 0; waited < 30000; waited += 500) {
|
|
734
|
-
await new Promise((r) => setTimeout(r, 500));
|
|
735
|
-
try {
|
|
736
|
-
const cap = await fetch("/dsh-market/api/v1/capabilities", { headers: { accept: "application/json" } });
|
|
737
|
-
if (cap.ok) {
|
|
738
|
-
location.reload();
|
|
739
|
-
return;
|
|
740
|
-
}
|
|
741
|
-
} catch {
|
|
742
|
-
// host down mid-restart — expected; keep polling
|
|
743
|
-
}
|
|
744
|
-
}
|
|
745
|
-
location.reload();
|
|
746
|
-
}
|
|
714
|
+
let seamNoticeDismissed = false;
|
|
747
715
|
|
|
748
716
|
function ComposerGitChip({ sessionId }) {
|
|
749
717
|
const target = sessionId === void 0 ? void 0 : { kind: "session", id: sessionId };
|
|
@@ -757,29 +725,11 @@ window.__ModuleLoader__.load({
|
|
|
757
725
|
// the PR token's own hover/focus state: it underlines on hover (and on
|
|
758
726
|
// focus) rather than at rest, and that underline is applied inline below
|
|
759
727
|
const [linkHover, setLinkHover] = react.useState(false);
|
|
760
|
-
//
|
|
761
|
-
//
|
|
762
|
-
|
|
763
|
-
const
|
|
764
|
-
const [canRestart, setCanRestart] = react.useState(null); // null = not yet checked
|
|
728
|
+
// seamHint is module state set once, 5s after boot; dismissing it needs a
|
|
729
|
+
// re-render that no fetch will schedule, so the × bumps a counter here.
|
|
730
|
+
const [, bumpNotice] = react.useState(0);
|
|
731
|
+
const seamNotice = seamHint !== null && !seamNoticeDismissed ? seamHint : null;
|
|
765
732
|
const detail = useGitStatus(target, { pr: true, detail: true, enabled: hovered });
|
|
766
|
-
const restartPending = info !== void 0 && info.git === true && info.seamRestartPending !== void 0;
|
|
767
|
-
react.useEffect(() => {
|
|
768
|
-
if (!restartPending || canRestart !== null) return;
|
|
769
|
-
let cancelled = false;
|
|
770
|
-
marketRestartSupported().then((v) => {
|
|
771
|
-
if (!cancelled) setCanRestart(v);
|
|
772
|
-
});
|
|
773
|
-
return () => {
|
|
774
|
-
cancelled = true;
|
|
775
|
-
};
|
|
776
|
-
}, [restartPending, canRestart]);
|
|
777
|
-
async function restartNow() {
|
|
778
|
-
setRestarting(true);
|
|
779
|
-
if (await marketRestartSupported()) await marketRestart();
|
|
780
|
-
// Unsupported host: the text stays and says restart dsh web manually.
|
|
781
|
-
else setRestarting(false);
|
|
782
|
-
}
|
|
783
733
|
if (info === void 0 || info.git !== true) return null;
|
|
784
734
|
// the mark is an element now rather than a leading glyph in the string, so
|
|
785
735
|
// the SAME StatusMark the sidebar row draws carries the status here too;
|
|
@@ -787,63 +737,6 @@ window.__ModuleLoader__.load({
|
|
|
787
737
|
const text = info.branch + formatOperationToken(info) + formatGitSuffix(info);
|
|
788
738
|
const prToken = formatPrToken(info);
|
|
789
739
|
const prUrl = prLinkUrl(info);
|
|
790
|
-
// One-line explanation + one-click restart, ONLY while a restart is
|
|
791
|
-
// actually pending. The button exists because dshmarket's own banner
|
|
792
|
-
// cannot see the host-file change our installer made; the endpoint is
|
|
793
|
-
// its documented public API. On hosts that delegate restart (desktop,
|
|
794
|
-
// supervisors) canRestart is false and the text names the manual step.
|
|
795
|
-
const restartNotice =
|
|
796
|
-
!restartPending || restarting
|
|
797
|
-
? null
|
|
798
|
-
: react_jsx_runtime.jsxs(
|
|
799
|
-
"span",
|
|
800
|
-
{
|
|
801
|
-
style: {
|
|
802
|
-
display: "inline-flex",
|
|
803
|
-
alignItems: "center",
|
|
804
|
-
gap: "6px",
|
|
805
|
-
paddingLeft: "6px",
|
|
806
|
-
borderLeft: "1px solid var(--dsw-alias-border-secondary, #d0d7de)",
|
|
807
|
-
whiteSpace: "normal",
|
|
808
|
-
maxWidth: "320px"
|
|
809
|
-
},
|
|
810
|
-
children: [
|
|
811
|
-
react_jsx_runtime.jsx(
|
|
812
|
-
"span",
|
|
813
|
-
{
|
|
814
|
-
title: "The installer applied dsh-git-badge's sidebar patch to DSH's own files; client bundles are composed at boot, so a restart is needed for it to take effect. Revert anytime with `npx dsh-git-badge revert`.",
|
|
815
|
-
children:
|
|
816
|
-
canRestart === false
|
|
817
|
-
? "restart dsh web to activate the sidebar badges (one-click restart is unavailable on this host)"
|
|
818
|
-
: "installer patched DSH — restart to activate the sidebar badges"
|
|
819
|
-
},
|
|
820
|
-
"explain"
|
|
821
|
-
),
|
|
822
|
-
canRestart === true
|
|
823
|
-
? react_jsx_runtime.jsx(
|
|
824
|
-
"button",
|
|
825
|
-
{
|
|
826
|
-
onClick: () => void restartNow(),
|
|
827
|
-
style: {
|
|
828
|
-
cursor: "pointer",
|
|
829
|
-
color: "inherit",
|
|
830
|
-
background: "none",
|
|
831
|
-
border: "1px solid var(--dsw-alias-border-secondary, #d0d7de)",
|
|
832
|
-
borderRadius: "4px",
|
|
833
|
-
fontSize: "11px",
|
|
834
|
-
lineHeight: "18px",
|
|
835
|
-
padding: "0 6px",
|
|
836
|
-
flex: "none"
|
|
837
|
-
},
|
|
838
|
-
children: "Restart"
|
|
839
|
-
},
|
|
840
|
-
"btn"
|
|
841
|
-
)
|
|
842
|
-
: null
|
|
843
|
-
]
|
|
844
|
-
},
|
|
845
|
-
"restart"
|
|
846
|
-
);
|
|
847
740
|
const chip = react_jsx_runtime.jsxs("span", {
|
|
848
741
|
style: {
|
|
849
742
|
display: "inline-flex",
|
|
@@ -859,10 +752,10 @@ window.__ModuleLoader__.load({
|
|
|
859
752
|
whiteSpace: "nowrap",
|
|
860
753
|
cursor: "default"
|
|
861
754
|
},
|
|
862
|
-
// the
|
|
863
|
-
//
|
|
864
|
-
//
|
|
865
|
-
//
|
|
755
|
+
// the long-form explanation, on hover; the inline seam-notice below is
|
|
756
|
+
// the visible channel (its text is the short form, its title this).
|
|
757
|
+
// null until the delayed check in apply() proves the seam never
|
|
758
|
+
// appeared.
|
|
866
759
|
title: seamHint === null ? undefined : seamHint,
|
|
867
760
|
// the card is fetched for a pointer that RESTS here, not one that
|
|
868
761
|
// merely crosses the chip
|
|
@@ -907,7 +800,68 @@ window.__ModuleLoader__.load({
|
|
|
907
800
|
onBlur: () => setLinkHover(false),
|
|
908
801
|
children: prToken
|
|
909
802
|
}),
|
|
910
|
-
|
|
803
|
+
/**
|
|
804
|
+
* The seam-absent notice: the market-install notification for the
|
|
805
|
+
* state a blocked postinstall leaves behind — chip working, sidebar
|
|
806
|
+
* rows structurally off, nothing patched, nothing to restart INTO.
|
|
807
|
+
* It is only ever TRUE (seamHint is set 5s after boot, only after
|
|
808
|
+
* the composed graph is given its chance), and it is self-resolving:
|
|
809
|
+
* apply + restart makes the seam declare, and this never renders
|
|
810
|
+
* again. That is what distinguishes it from the old restart notice,
|
|
811
|
+
* which outlived the restart it asked for. Dismissal is a session
|
|
812
|
+
* value (see seamNoticeDismissed), so the × means "stop asking this
|
|
813
|
+
* boot", never "stop asking forever".
|
|
814
|
+
*/
|
|
815
|
+
seamNotice === null
|
|
816
|
+
? null
|
|
817
|
+
: react_jsx_runtime.jsxs(
|
|
818
|
+
"span",
|
|
819
|
+
{
|
|
820
|
+
style: {
|
|
821
|
+
display: "inline-flex",
|
|
822
|
+
alignItems: "center",
|
|
823
|
+
gap: "6px",
|
|
824
|
+
paddingLeft: "6px",
|
|
825
|
+
borderLeft: "1px solid var(--dsw-alias-border-secondary, #d0d7de)",
|
|
826
|
+
whiteSpace: "normal",
|
|
827
|
+
maxWidth: "320px"
|
|
828
|
+
},
|
|
829
|
+
children: [
|
|
830
|
+
react_jsx_runtime.jsx(
|
|
831
|
+
"span",
|
|
832
|
+
{
|
|
833
|
+
title: seamHint,
|
|
834
|
+
children: "sidebar badges off — run `npx dsh-git-badge apply`"
|
|
835
|
+
},
|
|
836
|
+
"explain"
|
|
837
|
+
),
|
|
838
|
+
react_jsx_runtime.jsx(
|
|
839
|
+
"button",
|
|
840
|
+
{
|
|
841
|
+
"aria-label": "Dismiss the sidebar-badges notice (returns next boot while the seam is absent)",
|
|
842
|
+
onClick: () => {
|
|
843
|
+
seamNoticeDismissed = true;
|
|
844
|
+
bumpNotice((n) => n + 1);
|
|
845
|
+
},
|
|
846
|
+
style: {
|
|
847
|
+
cursor: "pointer",
|
|
848
|
+
color: "inherit",
|
|
849
|
+
background: "none",
|
|
850
|
+
border: "1px solid var(--dsw-alias-border-secondary, #d0d7de)",
|
|
851
|
+
borderRadius: "4px",
|
|
852
|
+
fontSize: "11px",
|
|
853
|
+
lineHeight: "18px",
|
|
854
|
+
padding: "0 6px",
|
|
855
|
+
flex: "none"
|
|
856
|
+
},
|
|
857
|
+
children: "×"
|
|
858
|
+
},
|
|
859
|
+
"dismiss"
|
|
860
|
+
)
|
|
861
|
+
]
|
|
862
|
+
},
|
|
863
|
+
"seam-notice"
|
|
864
|
+
),
|
|
911
865
|
]
|
|
912
866
|
});
|
|
913
867
|
// No Tooltip primitive (a shell that does not seed it): render the chip
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-git-badge",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.13.0",
|
|
4
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",
|