You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
A new native part kind renders a parent issue and its nested sub-issues as
a tight rail tree with a progress rollup the viewer computes (done ÷ total
over descendants, never stored). The shape is the normalized, recursive
Issue model — `root.children` are more issues — so a tree nests across
providers (a Linear epic owning a GitHub sub-issue and a Sentry leaf).
Threaded through every tier: types + recursive zod validation (strict
rejects, loose tolerates/drops), the Solid renderer, MCP/HTTP/CLI
(`sideshow issue-tree`, `--issue-tree`), the design guide, AGENTS, and the
README gallery. Adds an `--ok` status-green chrome token (themed via
viewerVars, with a styles.css fallback).
Hardening from review:
- bound nesting (MAX_ISSUE_TREE_DEPTH/NODES) with an iterative pre-check so
a deep tree is a clean 400 (loose drops it), not a stack-overflow 500;
plus an app.onError safety net.
- sanitize node.url (safeHref allowlist) so javascript:/data: never render
as an executable link in the trusted viewer origin.
- drop coerced-empty loose children so phantom rows can't skew the rollup.
- memoize the rollup walk; progressbar aria; recursive JSON-schema children.
Tests: depth rejection, loose state/child coercion, update→issue-tree
history, partsByteLength recursion, store-contract deep round-trip, CLI
publish + envelope error, and e2e (render, structural nesting depth, and
javascript:-url safety).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add an `issue-tree` surface part. Agents hand over a `root` issue whose `children` are more issues of the same shape, and the viewer renders it natively as a tight rail/elbow tree with a progress rollup computed (`done ÷ total` over descendants) — never stored, so editing a leaf moves the bar. Each node is `{ ref, title, state, source?, note?, url?, children? }`; `state` is one of `open | in-progress | blocked | done | closed`, and `source` (github / linear / jira / gitlab / sentry / …) drives a source chip — so a tree can nest across providers (a Linear epic owning a GitHub sub-issue and a Sentry leaf). Available on all three tiers: an `issue-tree` part over MCP and `POST /api/surfaces`, plus the CLI (`sideshow issue-tree`, and `--issue-tree` on `sideshow publish`). Rendered from data, not sandboxed markup; the viewer themes it (light and dark) from chrome tokens, including a new `--ok` status green.
Copy file name to clipboardExpand all lines: README.md
+7Lines changed: 7 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -114,6 +114,13 @@ viewer. A surface is an ordered list of **parts**; one card can carry several.
114
114
<p><b>Parts compose.</b> One card can carry several — here a <code>markdown</code> rationale stacked above its <code>diff</code>, so a single surface holds the why and the what.</p>
115
115
</td>
116
116
</tr>
117
+
<tr>
118
+
<td width="50%" valign="top">
119
+
<img src="docs/surfaces/09-issue-tree.png" width="100%" alt="issue-tree part — nested sub-issues with a computed progress rollup">
120
+
<p><b><code>issue-tree</code></b> — a parent issue and its nested sub-issues, rendered as a rail tree with a rollup the viewer computes. Nests across providers — a Linear epic can own a GitHub sub-issue and a Sentry error.</p>
0 commit comments