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.
Files changed (3) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/lib/client.js +77 -123
  3. 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
- * The restart affordance for a seam change made while the host was
708
- * running. dshmarket cannot see host-file mutations (its restart banner
709
- * tracks only its own package bookkeeping), so the flag this reads is
710
- * written by our own postinstall/apply — see seam/store.js. The Restart
711
- * button calls dshmarket's PUBLIC, documented v1 restart endpoint
712
- * (UPDATE-API-V1.md): feature-detected via capabilities, same-origin, and
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
- async function marketRestartSupported() {
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
- // The restart affordance: idle → checking (capabilities) → restarting.
761
- // One status refresh carries seamRestartPending at a time; when the
762
- // restart lands, the marker is cleared at the new boot and this reverts.
763
- const [restarting, setRestarting] = react.useState(false);
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 only in-product message a market user gets when the seam is
863
- // absent: hover the chip you CAN see to learn the one command that
864
- // turns on the rows you cannot. null until the delayed check in
865
- // apply() proves the seam never appeared.
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
- restartNotice
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.11.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",