dsh-git-badge 0.17.4 → 0.18.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 CHANGED
@@ -10,6 +10,47 @@ npm. 0.6.0 is the first release recorded here.
10
10
 
11
11
  ## [Unreleased]
12
12
 
13
+ ## [0.18.0] - 2026-10-12
14
+
15
+ ### Fixed
16
+
17
+ - **The sidebar seam patch works again on DSH 0.2.0-rc.2.** That release rewrote
18
+ `dsh-client-ui-workspace/lib/client.js` (2821 → 4425 lines) and moved 8 of the
19
+ 9 anchors the patcher pinned, so `npx dsh-git-badge status` reported `drift`
20
+ and `apply` refused to write. The anchor set is rewritten for the new upstream:
21
+ the patch is three anchors and **+48/−0** (was nine anchors and +74/−5).
22
+
23
+ ### Changed
24
+
25
+ - **The session-row action token is a pill now.** It was grey text beside the
26
+ relative time, which made `push` — the one row that wants a decision — read as
27
+ metadata. It is now a severity-tinted pill with a leading glyph and a heavier
28
+ weight: `↑ push`, `↓ pull`, `✓ merge`, `✗ fix CI`, `! resolve`, `◆ review`.
29
+ Routine sync also moved off grey onto the app's business-blue token, so the
30
+ severity ramp is four steps (red, amber, green, blue) rather than three plus
31
+ silence. The glyph is `aria-hidden`, so a screen reader still reads the word
32
+ alone.
33
+ - **The patch is one seam now, not two.** DSH 0.2.0-rc.2 threads `renderSlot`
34
+ into `SessionNodeItem` and `SessionHoverContent` itself and declares
35
+ `sidebar.session.row.hover`, so the hover card's provenance line rides that
36
+ upstream seat. The patched `sidebar.workspaces.sessionRow.detail` seam, the
37
+ `SessionTree`/`SessionNodeItem` `renderSlot` threading, and the `workspaceId`
38
+ owner-share field are all retired. The one remaining patched seam is
39
+ `sidebar.workspaces.sessionRow`: the always-visible row token after the title,
40
+ which no upstream seat can host (`sidebar.workspaces.session.row.action` is
41
+ `display:none` until hover, and `sidebar.session.row.leading` is a 16px cell
42
+ that renders only while the row is idle).
43
+ - **The row token now shows in the flat grouping too.** The old patch passed
44
+ `workspaceId` from the tree call site only, which kept flat rows bare. Upstream
45
+ no longer passes a workspace id to `SessionNodeItem`, so the token renders
46
+ wherever a session row does. Search results are unaffected.
47
+ - **The hover-card provenance line works on an unpatched install.** It no longer
48
+ depends on this package's seam patch.
49
+ - `PATCH_REV` is now `3`, so an installed rev-2 artifact is recognised as stale
50
+ rather than skipped. Because the anchors moved with upstream's rewrite, a rev-2
51
+ install cannot be re-patched in place: `apply` refuses and tells you to
52
+ reinstall the DSH package first.
53
+
13
54
  ## [0.17.4] - 2026-09-18
14
55
 
15
56
  ### Fixed
package/README.md CHANGED
@@ -6,7 +6,7 @@ Git status badges for [DeepSeek Harness](https://github.com/deepseek-ai/deepseek
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 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. 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.
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 for the row token itself; without it the row stays bare and the plugin logs what's active to the browser console. The hover-card line does **not** need the patch — it renders through upstream's own `sidebar.session.row.hover` seat.
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.)
package/lib/client.js CHANGED
@@ -10,9 +10,9 @@
10
10
  * and the PR/CI token, immediately after the session title. Deliberately shows
11
11
  * NO branch and no worktree name: the row lists conversations, and which
12
12
  * checkout the badge describes is the hover card's business.
13
- * - sidebar.workspaces.sessionRow.detail (seam): the hover-card line that names
14
- * that checkout, rendered inside the card upstream ALREADY shows for a session
15
- * row rather than in a tooltip nested inside it.
13
+ * - sidebar.session.row.hover (upstream, no patch): the hover-card line that
14
+ * names that checkout, rendered inside the card upstream ALREADY shows for a
15
+ * session row rather than in a tooltip nested inside it.
16
16
  * - conversation.input.left (upstream): chip — status mark + branch + a
17
17
  * worktree's name + in-progress operation token + sync/dirty suffix + the
18
18
  * PR/CI token, with a HOVER CARD carrying the breakdown the chip has no room
@@ -536,18 +536,35 @@ window.__ModuleLoader__.load({
536
536
  /**
537
537
  * Action -> colour. Colour here means SEVERITY — how much this needs you —
538
538
  * rather than identity: a broken build and a conflict are the loud ones, a
539
- * requested review is a nudge, `merge` is the all-clear, and routine sync
540
- * stays quiet so the loud rows keep meaning something. The WORD remains the
541
- * channel (colour only reinforces it), and the tokens are the app's own, so
542
- * both themes work.
539
+ * requested review is a nudge, `merge` is the all-clear, and routine sync is
540
+ * the quiet end of the same ramp rather than outside it. That last move is
541
+ * deliberate: grey put `push` below the threshold of notice, so the one row
542
+ * that wanted a decision read as a timestamp. The WORD remains the channel
543
+ * (colour only reinforces it), and the tokens are the app's own, so both
544
+ * themes work.
543
545
  */
544
546
  const ACTION_COLOUR = {
545
547
  resolve: "var(--dsw-alias-state-error-primary, #e5484d)",
546
548
  "fix CI": "var(--dsw-alias-state-error-primary, #e5484d)",
547
549
  review: "var(--dsw-alias-state-warn-primary, #d29922)",
548
550
  merge: "var(--dsw-alias-state-success-primary, #30a46c)",
549
- pull: "var(--dsw-alias-label-secondary, #5b6570)",
550
- push: "var(--dsw-alias-label-secondary, #5b6570)"
551
+ pull: "var(--dsw-alias-state-business-primary, #3b82f6)",
552
+ push: "var(--dsw-alias-state-business-primary, #3b82f6)"
553
+ };
554
+
555
+ /**
556
+ * Action -> glyph. The SHAPE channel, beside the colour: a glyph makes the
557
+ * row readable before the word is parsed, and it survives a monochrome or
558
+ * colour-blind view where the tint alone would not. Keys mirror
559
+ * ACTION_COLOUR exactly; a missing entry degrades to the bare word.
560
+ */
561
+ const ACTION_GLYPH = {
562
+ resolve: "!",
563
+ "fix CI": "\u2717",
564
+ review: "\u25C6",
565
+ merge: "\u2713",
566
+ pull: "\u2193",
567
+ push: "\u2191"
551
568
  };
552
569
 
553
570
  /**
@@ -556,10 +573,21 @@ window.__ModuleLoader__.load({
556
573
  * the sidebar — that alignment is what makes the list scannable;
557
574
  * - `marginRight` keeps it clear of the relative time beside it (the first cut
558
575
  * sat flush and read `merge11m`);
559
- * - weight 500 rather than the timestamp's own treatment, because an action
560
- * rendered in tertiary grey reads as metadata.
576
+ * - weight 600 plus a little padding make it a PILL, so the token reads as a
577
+ * tag rather than as loose text the eye can skip;
578
+ * - the radius is the app's own small one, so the pill belongs to the shell.
579
+ *
580
+ * The FILL is not set here: it is the action's own colour at low alpha, which
581
+ * only SessionGitBadge can build.
561
582
  */
562
- const ACTION_STYLE = { flex: "none", marginLeft: "auto", marginRight: "8px", fontWeight: 500 };
583
+ const ACTION_STYLE = {
584
+ flex: "none",
585
+ marginLeft: "auto",
586
+ marginRight: "8px",
587
+ fontWeight: 600,
588
+ padding: "0 6px",
589
+ borderRadius: "var(--dsw-radius-sm, 4px)"
590
+ };
563
591
 
564
592
  /**
565
593
  * The row's own run state, from the shell's standard kit.
@@ -598,9 +626,9 @@ window.__ModuleLoader__.load({
598
626
  }
599
627
 
600
628
  /**
601
- * The action badge: floated, weighted, and coloured by severity — and shown
602
- * only when the session is IDLE. A turn in flight is precisely when a git
603
- * suggestion is noise: the checkout is still moving and the agent has not
629
+ * The action badge: a severity-tinted pill carrying a glyph and the word — and
630
+ * shown only when the session is IDLE. A turn in flight is precisely when a
631
+ * git suggestion is noise: the checkout is still moving and the agent has not
604
632
  * finished, so the action describes a state that is about to change. Nothing
605
633
  * about the action itself changes; the gate is the whole feature.
606
634
  *
@@ -616,17 +644,33 @@ window.__ModuleLoader__.load({
616
644
  const action = actionToken(info);
617
645
  if (action === "") return null;
618
646
  const colour = ACTION_COLOUR[action];
619
- return react_jsx_runtime.jsx("span", {
620
- style: colour === void 0 ? { ...META_STYLE, ...ACTION_STYLE } : { ...META_STYLE, ...ACTION_STYLE, color: colour },
621
- children: action
647
+ const style = { ...META_STYLE, ...ACTION_STYLE };
648
+ if (colour !== void 0) {
649
+ style.color = colour;
650
+ // The pill's fill is the action's own colour at low alpha, so severity is
651
+ // a wash a row can carry rather than a shout. color-mix is a current-browser
652
+ // feature: where it is unsupported the pill keeps its geometry, colour,
653
+ // glyph and weight, and only the tint is lost.
654
+ style.background = `color-mix(in srgb, ${colour} 18%, transparent)`;
655
+ }
656
+ // The glyph is DECORATION: `aria-hidden` keeps the accessible name the bare
657
+ // word, and the trailing space in its own text separates the two on screen
658
+ // without a margin. A missing glyph entry degrades to the word alone.
659
+ const glyph = ACTION_GLYPH[action];
660
+ return react_jsx_runtime.jsxs("span", {
661
+ style,
662
+ children:
663
+ glyph === void 0
664
+ ? action
665
+ : [react_jsx_runtime.jsx("span", { "aria-hidden": true, children: `${glyph} ` }, "glyph"), action]
622
666
  });
623
667
  }
624
668
 
625
669
  /**
626
670
  * Session-row hover-card line — everything the action word cannot say: which
627
671
  * checkout the row's status describes, and which pull request the action
628
- * refers to. It renders through the sessionRow.detail seam, inside the card
629
- * upstream already opens for a row.
672
+ * refers to. It renders through the upstream sidebar.session.row.hover
673
+ * seat, inside the card upstream already opens for a row.
630
674
  *
631
675
  * This matters MORE now that the row shows only an imperative: `merge` with no
632
676
  * way to see merge WHAT would be a nag rather than a hint, so the line appears
@@ -1765,11 +1809,13 @@ window.__ModuleLoader__.load({
1765
1809
  }, SessionGitBadge);
1766
1810
  });
1767
1811
  // The row is ALREADY a HoverCard anchor upstream, so a badge that opened
1768
- // its own tooltip would nest two cards. This additive slot renders the
1769
- // provenance line inside that card instead — the same pattern the
1770
- // workspace-row detail slot used. It issues no request of its own.
1771
- ctx.slots.inject("sidebar.workspaces.sessionRow.detail", () => ctx.slots.register({
1772
- name: "sidebar.workspaces.sessionRow.detail",
1812
+ // its own tooltip would nest two cards. This renders the provenance line
1813
+ // inside that card instead, through the hover seat upstream declares
1814
+ // itself (sidebar.session.row.hover) — no seam patch and no request of
1815
+ // its own. Upstream 0.2.0-rc.2 threads renderSlot into the card and adds
1816
+ // the seat; before that this needed a patched sessionRow.detail seam.
1817
+ ctx.slots.inject("sidebar.session.row.hover", () => ctx.slots.register({
1818
+ name: "sidebar.session.row.hover",
1773
1819
  id: "git-badge-row-detail"
1774
1820
  }, SessionGitDetail));
1775
1821
  // Input-row chip: upstream additive slot rendered in the input bar's
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-git-badge",
3
- "version": "0.17.4",
3
+ "version": "0.18.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",
package/seam/anchors.js CHANGED
@@ -12,6 +12,12 @@
12
12
  * that moves one of the anchors does — and the failure names the anchor that
13
13
  * moved instead of reporting an opaque hash mismatch.
14
14
  *
15
+ * ONE seam, not two (rev 3). Upstream 0.2.0-rc.2 threads `renderSlot` into
16
+ * SessionNodeItem and SessionHoverContent itself and declares its own
17
+ * `sidebar.session.row.hover` hover-card seat, so the badge's provenance line
18
+ * rides that upstream seat and needs no patch. The seat upstream still lacks is
19
+ * the always-visible row token after the title: these three anchors add it.
20
+ *
15
21
  * Tabs matter: the target is a bundled, tab-indented file. The strings below
16
22
  * use \t escapes so a reader cannot mistake them for spaces. When upstream
17
23
  * moves an anchor, edit that entry's `old` (and `new`, if the insertion point
@@ -22,7 +28,7 @@ export const MARKER = "dsh-git-badge:seam-patch";
22
28
  // Bumped whenever the anchor set changes shape. An installed file carrying the
23
29
  // MARKER without this revision is OUR older artifact: apply restores its backup
24
30
  // and re-patches rather than refusing.
25
- export const PATCH_REV = "2";
31
+ export const PATCH_REV = "3";
26
32
  export const REV_COMMENT = `${MARKER} rev ${PATCH_REV}`;
27
33
 
28
34
  // The seam strings upstream would declare if the patch were merged. Present in
@@ -37,59 +43,20 @@ export const PATCHES = [
37
43
  // --- 1. Session-row seam helper, inserted with the row component's props ---
38
44
  [
39
45
  "SessionNodeItem header + seam helpers",
40
- "\t\tfunction SessionNodeItem({ node, currentId, now, onOpen, onRename, onFork, onArchive, onReveal, drag, flat = false, t }) {",
41
- "\t\t/* dsh-git-badge:seam-patch rev 2 — seam/apply.sh recognises its own artifact by this\n\t\t * marker, which upstream would never carry. */\n\t\t/**\n\t\t* Seam entry boundary. The host wraps each registered ENTRY in its own error\n\t\t* boundary, but the outlet a row renders is NOT covered by it, so a throw\n\t\t* anywhere in an occupant's render path would propagate into the workspace\n\t\t* browser itself — and the shell ABDICATES that browser entry, blanking the\n\t\t* whole sidebar. A seam must not be able to do that: this keeps the blast\n\t\t* radius at \"no badge\", and logs what happened instead of swallowing it.\n\t\t*/\n\t\tclass SeamBoundary extends react.Component {\n\t\t\tconstructor(props) {\n\t\t\t\tsuper(props);\n\t\t\t\tthis.state = { failed: false };\n\t\t\t}\n\t\t\tstatic getDerivedStateFromError() {\n\t\t\t\treturn { failed: true };\n\t\t\t}\n\t\t\tcomponentDidCatch(error) {\n\t\t\t\tconsole.error(\"[dsh-git-badge] seam entry failed; badge omitted:\", error);\n\t\t\t}\n\t\t\trender() {\n\t\t\t\treturn this.state.failed ? null : this.props.children;\n\t\t\t}\n\t\t}\n\t\t/** Seam entry bodies, so the boundary above ENCLOSES the renderSlot call. */\n\t\tfunction SessionRowSeam({ renderSlot, sessionId, workspaceId, label }) {\n\t\t\treturn renderSlot(\"sidebar.workspaces.sessionRow\", { sessionId, workspaceId, label });\n\t\t}\n\t\tfunction SessionRowDetailSeam({ renderSlot, sessionId, workspaceId, label }) {\n\t\t\treturn renderSlot(\"sidebar.workspaces.sessionRow.detail\", { sessionId, workspaceId, label });\n\t\t}\n\t\t/**\n\t\t* Session-row seam (sidebar.workspaces.sessionRow): renders the additive\n\t\t* list-slot entries for one session row with the row owner share\n\t\t* ({ sessionId, workspaceId, label }).\n\t\t*\n\t\t* Returns null — not a fallback element — when no plugin occupies the seam,\n\t\t* so a pristine install renders exactly as upstream. `workspaceId` is only\n\t\t* ever passed from the TREE call site: the flat \"all sessions\" list and the\n\t\t* search-result list render this component without it, which is what keeps\n\t\t* badges off those lists without either of them needing a guard.\n\t\t*/\n\t\tfunction renderSessionRowSeam(renderSlot, sessionId, workspaceId, label) {\n\t\t\tif (renderSlot === void 0 || workspaceId === void 0) return null;\n\t\t\treturn (0, react_jsx_runtime.jsx)(SeamBoundary, {\n\t\t\t\tchildren: (0, react_jsx_runtime.jsx)(SessionRowSeam, { renderSlot, sessionId, workspaceId, label })\n\t\t\t});\n\t\t}\n\t\tfunction SessionNodeItem({ node, currentId, now, onOpen, onRename, onFork, onArchive, onReveal, drag, flat = false, t, renderSlot, workspaceId }) {",
46
+ "\t\tfunction SessionNodeItem({ node, currentId, now, onOpen, onRenameRequest, renderSlot, onReveal, drag, t }) {",
47
+ "\t\t/* dsh-git-badge:seam-patch rev 3 — seam/apply.sh recognises its own artifact by this\n\t\t * marker, which upstream would never carry. */\n\t\t/**\n\t\t* Seam entry boundary. The host wraps each registered ENTRY in its own error\n\t\t* boundary, but the outlet a row renders is NOT covered by it, so a throw\n\t\t* anywhere in an occupant's render path would propagate into the workspace\n\t\t* browser itself — and the shell ABDICATES that browser entry, blanking the\n\t\t* whole sidebar. A seam must not be able to do that: this keeps the blast\n\t\t* radius at \"no badge\", and logs what happened instead of swallowing it.\n\t\t*/\n\t\tclass SeamBoundary extends react.Component {\n\t\t\tconstructor(props) {\n\t\t\t\tsuper(props);\n\t\t\t\tthis.state = { failed: false };\n\t\t\t}\n\t\t\tstatic getDerivedStateFromError() {\n\t\t\t\treturn { failed: true };\n\t\t\t}\n\t\t\tcomponentDidCatch(error) {\n\t\t\t\tconsole.error(\"[dsh-git-badge] seam entry failed; badge omitted:\", error);\n\t\t\t}\n\t\t\trender() {\n\t\t\t\treturn this.state.failed ? null : this.props.children;\n\t\t\t}\n\t\t}\n\t\t/** Seam entry body, so the boundary above ENCLOSES the renderSlot call. */\n\t\tfunction SessionRowSeam({ renderSlot, sessionId, label }) {\n\t\t\treturn renderSlot(\"sidebar.workspaces.sessionRow\", { sessionId, label });\n\t\t}\n\t\t/**\n\t\t* Session-row seam (sidebar.workspaces.sessionRow): renders the additive\n\t\t* list-slot entries for one session row with the row owner share\n\t\t* ({ sessionId, label }).\n\t\t*\n\t\t* Returns null — not a fallback element — when no plugin occupies the seam,\n\t\t* so a pristine install renders exactly as upstream.\n\t\t*/\n\t\tfunction renderSessionRowSeam(renderSlot, sessionId, label) {\n\t\t\tif (renderSlot === void 0) return null;\n\t\t\treturn (0, react_jsx_runtime.jsx)(SeamBoundary, {\n\t\t\t\tchildren: (0, react_jsx_runtime.jsx)(SessionRowSeam, { renderSlot, sessionId, label })\n\t\t\t});\n\t\t}\n\t\tfunction SessionNodeItem({ node, currentId, now, onOpen, onRenameRequest, renderSlot, onReveal, drag, t }) {"
42
48
  ],
43
- // --- 2. The badge sits with the title, before the schedule/time cluster ---
49
+ // --- 2. The token sits with the title, before the time cluster ---
44
50
  [
45
51
  "title span + badge render",
46
- '\t\t\t\t\t\t(0, react_jsx_runtime.jsx)("span", {\n\t\t\t\t\t\t\tclassName: Rows_module_css_default.title,\n\t\t\t\t\t\t\tchildren: title\n\t\t\t\t\t\t}),',
47
- '\t\t\t\t\t\t(0, react_jsx_runtime.jsx)("span", {\n\t\t\t\t\t\t\tclassName: Rows_module_css_default.title,\n\t\t\t\t\t\t\tchildren: title\n\t\t\t\t\t\t}),\n\t\t\t\t\t\trenderSessionRowSeam(renderSlot, node.id, workspaceId, title),',
48
- ],
49
- // --- 3. The hover card gains the detail seam ---
50
- [
51
- "SessionHoverContent call-site props",
52
- '\t\t\t\tcontent: (0, react_jsx_runtime.jsx)(SessionHoverContent, {\n\t\t\t\t\tnode,\n\t\t\t\t\tnow,\n\t\t\t\t\tt\n\t\t\t\t}),',
53
- '\t\t\t\tcontent: (0, react_jsx_runtime.jsx)(SessionHoverContent, {\n\t\t\t\t\tnode,\n\t\t\t\t\tnow,\n\t\t\t\t\tt,\n\t\t\t\t\trenderSlot,\n\t\t\t\t\tworkspaceId\n\t\t\t\t}),',
54
- ],
55
- [
56
- "SessionHoverContent header",
57
- "\t\tfunction SessionHoverContent({ node, now, t }) {",
58
- "\t\tfunction SessionHoverContent({ node, now, t, renderSlot, workspaceId }) {",
59
- ],
60
- [
61
- "hover card detail row",
62
- "\t\t\t\t\t}, status.label))\n\t\t\t\t]\n\t\t\t});\n\t\t}",
63
- '\t\t\t\t\t}, status.label)),\n\t\t\t\t\trenderSlot !== void 0 && workspaceId !== void 0 ? (0, react_jsx_runtime.jsx)("div", {\n\t\t\t\t\t\tclassName: Rows_module_css_default.hoverStatus,\n\t\t\t\t\t\tchildren: (0, react_jsx_runtime.jsx)(SeamBoundary, {\n\t\t\t\t\t\t\tchildren: (0, react_jsx_runtime.jsx)(SessionRowDetailSeam, { renderSlot, sessionId: node.id, workspaceId, label: displayTitle(node, t) })\n\t\t\t\t\t\t})\n\t\t\t\t\t}) : null\n\t\t\t\t]\n\t\t\t});\n\t\t}',
64
- ],
65
- // --- 4. Thread renderSlot: WorkspaceBrowser -> SessionTree ---
66
- // A bare `renderSlot` at the SessionNodeItem call site resolves in THIS scope.
67
- // The first cut of this patch threaded it into SessionNodeItem but not into
68
- // SessionTree, so the row render threw `ReferenceError: renderSlot is not
69
- // defined` the moment sessions appeared — and the shell abdicated the whole
70
- // sidebar with it. Any prop a patched call site reads by shorthand must arrive
71
- // through every intermediate scope.
72
- [
73
- "SessionTree header",
74
- "\t\tfunction SessionTree({ useSessions, useSessionPendingInteraction, startSession, open, forkSession, workspaces, archivedSessionIds, workspaceReady, usePanelInfo, onRenameRequest, onDeleteRequest, onSessionRename, onSessionArchive, insertWorkspaceBefore, insertSessionBefore, orderBy, groupExpansion, setGroupExpanded, sessionOrderByAccount, sessionUpdatedAtByAccount, syncSessionOrderAccount, setSessionOrder, home, t, revealSessionId, onSessionRevealed }) {",
75
- "\t\tfunction SessionTree({ useSessions, useSessionPendingInteraction, startSession, open, forkSession, workspaces, archivedSessionIds, workspaceReady, usePanelInfo, onRenameRequest, onDeleteRequest, onSessionRename, onSessionArchive, insertWorkspaceBefore, insertSessionBefore, orderBy, groupExpansion, setGroupExpanded, sessionOrderByAccount, sessionUpdatedAtByAccount, syncSessionOrderAccount, setSessionOrder, home, t, renderSlot, revealSessionId, onSessionRevealed }) {",
76
- ],
77
- [
78
- "SessionTree call site",
79
- "(0, react_jsx_runtime.jsx)(SessionTree, {\n\t\t\t\t\t\t\tusePanelInfo,",
80
- "(0, react_jsx_runtime.jsx)(SessionTree, {\n\t\t\t\t\t\t\trenderSlot,\n\t\t\t\t\t\t\tusePanelInfo,",
81
- ],
82
- // --- 5. Thread renderSlot + the owning workspace id from the TREE call site only ---
83
- [
84
- "SessionNodeItem call site",
85
- "\t\t\t\t\t\t\t\t\t\treturn (0, react_jsx_runtime.jsx)(SessionNodeItem, {\n\t\t\t\t\t\t\t\t\t\t\tnode,\n\t\t\t\t\t\t\t\t\t\t\tcurrentId: current,",
86
- "\t\t\t\t\t\t\t\t\t\treturn (0, react_jsx_runtime.jsx)(SessionNodeItem, {\n\t\t\t\t\t\t\t\t\t\t\tnode,\n\t\t\t\t\t\t\t\t\t\t\tcurrentId: current,\n\t\t\t\t\t\t\t\t\t\t\trenderSlot,\n\t\t\t\t\t\t\t\t\t\t\t// only the tree knows which workspace a row belongs to; the\n\t\t\t\t\t\t\t\t\t\t\t// flat and search lists pass neither prop, so they stay bare\n\t\t\t\t\t\t\t\t\t\t\tworkspaceId: group.workspaceId,",
52
+ "\t\t\t\t\t\t(0, react_jsx_runtime.jsx)(\"span\", {\n\t\t\t\t\t\t\tref: titleRef,\n\t\t\t\t\t\t\tclassName: Rows_module_css_default.title,\n\t\t\t\t\t\t\tonDoubleClick: row.blank ? void 0 : (e) => {\n\t\t\t\t\t\t\t\te.stopPropagation();\n\t\t\t\t\t\t\t\tonRenameRequest(node.id, row.title);\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tchildren: title\n\t\t\t\t\t\t}),",
53
+ "\t\t\t\t\t\t(0, react_jsx_runtime.jsx)(\"span\", {\n\t\t\t\t\t\t\tref: titleRef,\n\t\t\t\t\t\t\tclassName: Rows_module_css_default.title,\n\t\t\t\t\t\t\tonDoubleClick: row.blank ? void 0 : (e) => {\n\t\t\t\t\t\t\t\te.stopPropagation();\n\t\t\t\t\t\t\t\tonRenameRequest(node.id, row.title);\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tchildren: title\n\t\t\t\t\t\t}),\n\t\t\t\t\t\trenderSessionRowSeam(renderSlot, node.id, title),"
87
54
  ],
88
- // --- 6. Declare the two seam children on the sidebar.workspaces registration ---
55
+ // --- 3. Declare the one seam child on the sidebar.workspaces registration ---
89
56
  [
90
57
  "seam children registration",
91
- '\t\t\t\tchildren: { "sidebar.workspaces.directoryFlow": {\n\t\t\t\t\tkind: "single",\n\t\t\t\t\tscope: "root"\n\t\t\t\t} },',
92
- '\t\t\t\tchildren: { "sidebar.workspaces.directoryFlow": {\n\t\t\t\t\tkind: "single",\n\t\t\t\t\tscope: "root"\n\t\t\t\t}, "sidebar.workspaces.sessionRow": {\n\t\t\t\t\tkind: "list",\n\t\t\t\t\tscope: "root"\n\t\t\t\t}, "sidebar.workspaces.sessionRow.detail": {\n\t\t\t\t\tkind: "list",\n\t\t\t\t\tscope: "root"\n\t\t\t\t} },',
58
+ "\t\t\t\t\t\"sidebar.workspaces.directoryFlow\": {\n\t\t\t\t\t\tkind: \"single\",\n\t\t\t\t\t\tscope: \"root\"\n\t\t\t\t\t},",
59
+ "\t\t\t\t\t\"sidebar.workspaces.directoryFlow\": {\n\t\t\t\t\t\tkind: \"single\",\n\t\t\t\t\t\tscope: \"root\"\n\t\t\t\t\t},\n\t\t\t\t\t\"sidebar.workspaces.sessionRow\": {\n\t\t\t\t\t\tkind: \"list\",\n\t\t\t\t\t\tscope: \"root\"\n\t\t\t\t\t},"
93
60
  ],
94
61
  ];
95
62
 
package/seam/patch.js CHANGED
@@ -22,7 +22,7 @@ const HERE = dirname(fileURLToPath(import.meta.url));
22
22
 
23
23
  // sha256 of the upstream build the anchors were last verified against. ADVISORY:
24
24
  // status prints it for orientation; apply does NOT require it.
25
- export const KNOWN_GOOD_HASH = "383b9ef779366c13d818500b6488896328b189f156addbaa480c835e902edd5f";
25
+ export const KNOWN_GOOD_HASH = "e784543780fb8ac7c38c853afd26b9b1713c6907eec2b07eff37461e07bd3be9";
26
26
 
27
27
  /** Locate the installed DSH package root; null when it cannot be found. */
28
28
  export function dshRoot() {