test / unit + widget + golden + a11y (push) Failing after 29s
test / integration_test (xvfb) (push) Has been skipped
test / bundle smoke (xvfb 5s) (push) Has been skipped
test / daemon subprocess + web WASM smoke (push) Has been skipped
test / dart doc (lib API) (push) Failing after 1m1s
Stale path references from the move in 63195d1:
- CLAUDE.md: 8 D-record links, the layout tree, the open-questions
pointer, all rewritten to governance/.
- docs/design/multitab-pane.md + docs/claude-design/README.md:
cross-references updated.
- lib/clide.dart: doc-comment refs.
- lib/builtin/problems: user-facing message string.
- Makefile: decisions-validate target docstring.
Note: lib/builtin/decisions/ (the in-app decisions panel package)
keeps its name — it's a feature name, not a filesystem-path mirror.
Co-Authored-By: Claude <noreply@anthropic.com>
Complete three overdue cleanups discovered during macOS health check:
D-56 daemon dissolution: delete bin/clide.dart, DaemonServer,
and orphaned tests (test/cli/, subprocess_test, in_process_test).
Update stale "clide --daemon" references in i18n catalogs, error
messages, editor_commands, CI scripts, and decision records.
ptyc retirement: delete ptyc/ source tree, PtySession, scm_rights.
Remove from Toolchain resolution, ToolCheck gate, backend
serialization, testmode harness, Makefile, CI, and sandbox
entitlements. PTY spawning uses NativePty (Dart FFI forkpty) since
the terminal was absorbed in-tree. D-5 amended.
Golden tests: wire the existing but never-applied clideGoldenConfig
via flutter_test_config.dart. Disable CI goldens (Skia anti-aliasing
differs between macOS/Linux even with Ahem). Keep platform-keyed
goldens only — goldens/linux/ and goldens/macos/ each run on their
own OS.
Test suite: 826 pass, 0 fail on macOS (was 829 pass, 11 fail).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
test / unit + widget + golden + a11y (push) Failing after 35s
test / integration_test (xvfb) (push) Has been skipped
test / bundle smoke (xvfb 5s) (push) Has been skipped
test / daemon subprocess + web WASM smoke (push) Has been skipped
test / dart doc (lib API) (push) Failing after 1m0s
Clears the 19 misc lint hits left after the test_app print sweep
+ libc.dart suppression. By rule:
- `withOpacity(α)` → `withValues(alpha: α)` (deprecated_member_use)
in `painter.dart:187` and `terminal_view.dart:318`.
- `Pointer.elementAt(n)` → `Pointer + n` (deprecated_member_use)
in `native_pty.dart:306` and `session.dart:187`.
- Brace single-statement for/if bodies in `native_pty.dart`
(×3) and `decisions_view.dart` (curly_braces_in_flow_control_
structures).
- `IsolateClient` and `InProcessClient` constructors switched to
`super.log` / `super.events` parameters (use_super_parameters);
associated unused imports of `kernel/src/log.dart` and
`kernel/src/events/bus.dart` removed in the same files.
- `InProcessClient._dispatcher` field + getter/setter pair folded
into a single mutable public `dispatcher` field
(unnecessary_getters_setters).
- `_buildDispatcher` local in `lib/main.dart` renamed to
`buildDispatcher` (no_leading_underscores_for_local_identifiers).
- `_onTapDown(_)` in `terminal_view.dart` typed as
`TapDownDetails _` (strict_top_level_inference).
- `operator []=(...)` in `circular_buffer.dart` given an explicit
`void` return type (strict_top_level_inference).
- `CustomKeyboardListener` and `TerminalGestureDetector` callsites
reordered so `child:` lands last (sort_child_properties_last).
- `CustomTextEdit` constructor declared `const`
(prefer_const_constructors_in_immutables).
- `LinkedHashMap<K, V>()` in `paragraph_cache.dart` collapsed to a
`<K, V>{}` literal (prefer_collection_literals); the now-unused
`dart:collection` import dropped.
Project analyze: 19 → 0 issues. `make test` stays green; coverage
unchanged at 52.72%.
Co-Authored-By: Claude <noreply@anthropic.com>
12 imports flagged by `unnecessary_import` because the symbols
they bring in are also re-exported by the umbrella import already
present in the same file:
- bin/clide.dart: src/git/client.dart, src/pql/client.dart
(covered by package:clide/clide.dart).
- lib/builtin/decisions/, lib/builtin/tickets/ (4 files):
kernel/src/events/message_bus.dart (covered by kernel.dart).
- lib/kernel/src/ipc/in_process.dart: src/daemon/dispatcher.dart
(covered by clide.dart).
- lib/main.dart: kernel/src/toolchain.dart (covered by kernel.dart).
- test/builtin/ipc_status/widget_test.dart:
builtin/ipc_status/src/status_item.dart (covered by
ipc_status.dart).
- test/daemon/{git,pql}_commands_test.dart: src/git/client.dart and
src/pql/client.dart (covered by clide.dart).
- test/widgets/multitab_pane_test.dart: widgets/src/icons/x.dart
(covered by widgets.dart).
Mechanical change — every removed line was already a no-op for
symbol resolution; the umbrella imports define the public surface
each file is actually using.
Co-Authored-By: Claude <noreply@anthropic.com>
Mechanical `dart format` sweep across files that drifted from the
formatter's output (mostly trailing-comma and line-wrap differences
from a Dart SDK / formatter version bump). No semantic changes.
Caught because the pre-push gate now actually fires.
Co-Authored-By: Claude <noreply@anthropic.com>
Eight unresolved doc references and broken README-rewritten links
that surfaced under `dart doc --validate-links`:
- Library-scope refs `[spawn]`, `[openProject]` qualified to
`[Backend.spawn]` / `[Backend.openProject]`; same treatment for
`[resolvePaths]` / `[applyResolved]` on Toolchain.
- `[D-41]` was a decision ID, not a Dart symbol — drop the brackets.
- `[from]` from I18n.interpolated qualified to `[I18nReplacer.from]`.
- `[DefaultSurfaceMap]` was a stale name (private `_defaultSurfaceMap`
in resolver.dart); switch to backticked path reference since
dartdoc can't link private members.
- `[icons/]` was a directory, not a symbol; backticked path.
- README links to `legacy/`, `docs/initial-plan.md`, `decisions/`,
`LICENSE` rewritten as absolute github.com/postmeridiem/clide URLs
so dartdoc stops re-rooting them into the doc tree.
Co-Authored-By: Claude <noreply@anthropic.com>
Three remaining acceptance criteria for T-87:
1. Cold-start reap. The Claude extension's activate() now kills
every leftover secondary tmux session for the current repo
before any new spawn. activate runs before any UI mounts, so
_nextSecondary's starting value of 1 is correct even when a
previous run died abruptly (kill -9, OOM, force-quit). The
deactivate() hook also calls reapSecondaries as a courtesy on
explicit extension teardown — but Flutter's deactivate doesn't
fire on app quit, so activate is the load-bearing path.
2. claude.kill-all-sessions actually kills server-side. The
command previously called pane.close on every claude pane,
which only kills the tmux client. It now also calls
tmux.killAllForRepo to kill the sessions on the clide socket.
3. Tests. test/builtin/claude/tmux_session_test.dart covers
killSession, listClideSessions, reapSecondaries, and
killAllForRepo via the TmuxRunner override — no real shell-out
in tests.
Co-Authored-By: Claude <noreply@anthropic.com>
Adds lib/builtin/claude/src/tmux_session.dart with helpers for the
clide-socket tmux server: killSession, listClideSessions,
reapSecondaries, killAllForRepo. The runner is overrideable via a
TmuxRunner typedef so tests don't shell out for real.
Wires ClaudePane.dispose() to call killSession(sessionName) for
secondary panes. Primary panes are left alone — D-41 keeps the
primary's tmux session alive across clide restarts so the next
launch re-attaches via `tmux new-session -A`.
Imports the helpers in the Claude extension as groundwork for the
app-shutdown reap and the existing claude.kill-all-sessions
command — wiring those uses lands separately.
Co-Authored-By: Claude <noreply@anthropic.com>
ClaudeSessionHost replaces its bespoke tab strip / add button /
close handler with a MultitabPane<_Session> in keepAlive mode.
The primary tab is seeded as non-closeable and non-reorderable
per D-41; secondaries spawn via the existing addSecondary()
entry point and gain drag-to-reorder for free.
Drops ~100 lines of custom _TabRow / _Tab / _AddButton code in
favour of the shared widget. Behaviour is preserved: primary
persists across clide restarts, secondaries can be closed, and
PTY state survives tab switches because IndexedStack keeps every
ClaudePane mounted.
Co-Authored-By: Claude <noreply@anthropic.com>
Six common keybindings (Quick open, Command palette, Toggle
sidebar, Toggle context, Switch theme, New Claude session) shown
as a 3x2 grid card spanning the same 850px content column as the
two action columns above. LayoutBuilder gates the card on viewport
height (>640px) so on shorter windows the centered START / RECENT
columns stay the focus and the tips drop out cleanly.
Co-Authored-By: Claude <noreply@anthropic.com>
clide is an IDE for the Claude Code CLI. The previous tagline
"Flutter desktop IDE for Claude Code" overemphasized the host
toolkit (Flutter is implementation detail, immediately obvious to
contributors) and was ambiguous about whether the integration
target is the CLI specifically.
Updates the welcome subtitle (i18n catalog + widget test + view),
the project description in pubspec.yaml, README and CLAUDE.md, the
CLI banner, and the web manifest/index.
Co-Authored-By: Claude <noreply@anthropic.com>
Spawn `claude` directly as the tmux command with
CLAUDE_CODE_NO_FLICKER=1 so Claude Code runs in its fullscreen TUI
mode (input box pinned at bottom, owns its own scrollback). Mouse
wheel events are converted to PgUp/PgDown key input — universal
scroll signal that Claude, less, vim normal mode all respect, and
sidesteps the mouse-mode-but-no-scroll dead end where TUI apps
capture mouse without binding the wheel.
Drops the 1000-row tmux canvas + SingleChildScrollView experiment
in favor of viewport-sized tmux and Claude's native bottom-pinning.
Makefile install target now kills the clide tmux server so the
new config takes effect immediately. Marked TEMP — to be removed
once we no longer need the rapid-iteration loop.
Co-Authored-By: Claude <noreply@anthropic.com>
Extract bundled tmux.conf to ~/.config/clide/tmux.conf on first
spawn and pass via -f. Use -L clide for a dedicated tmux server
so clide sessions don't inherit the user's tmux settings.
Terminal maxLines bumped from 5k to 50k.
Co-Authored-By: Claude <noreply@anthropic.com>
Replace the xterm pub.dev package with owned code under
lib/src/terminal/. Based on xterm.dart v4.0.0 by xuty (MIT).
Quiver LRU replaced with hand-rolled LinkedHashMap cache.
Scrollable removed from TerminalView — scroll events are forwarded
via Listener.onPointerSignal instead. zmodem, debugger, and
suggestion modules stripped as unused.
Also: bundle clide.tmux.conf (no status bar, 50k scrollback,
mouse on, zero escape delay, isolated -L clide socket), bump PTY
read buffer to 64KB, add 2px terminal padding, drop bold
JetBrains Mono registration.
Co-Authored-By: Claude <noreply@anthropic.com>
Unused _resolvePtycPath (bin/clide.dart), _TrafficDot (app.dart
and clide_column_hat.dart), stale @override on _spawned field
(claude_pane.dart), duplicate import and unused local in
test_app.dart, unnecessary non-null assertions in project.dart.
Co-Authored-By: Claude <noreply@anthropic.com>
test / unit + widget + golden + a11y (push) Failing after 28s
test / integration_test (xvfb) (push) Has been skipped
test / bundle smoke (xvfb 5s) (push) Has been skipped
test / daemon subprocess + web WASM smoke (push) Has been skipped
tmux determines window size from its client, not the PTY winsize.
TIOCSWINSZ + SIGWINCH on the master fd has no effect on tmux's
internal dimensions. Use tmux resize-window -t <session> -x -y
to explicitly set the window size on resize.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
test / unit + widget + golden + a11y (push) Failing after 27s
test / integration_test (xvfb) (push) Has been skipped
test / bundle smoke (xvfb 5s) (push) Has been skipped
test / daemon subprocess + web WASM smoke (push) Has been skipped
tmux doesn't re-read the PTY winsize on SIGWINCH. After the ioctl
resize, call tmux refresh-client -C cols,rows to update tmux's
internal window dimensions.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
test / unit + widget + golden + a11y (push) Failing after 27s
test / integration_test (xvfb) (push) Has been skipped
test / bundle smoke (xvfb 5s) (push) Has been skipped
test / daemon subprocess + web WASM smoke (push) Has been skipped
tmux running inside a PTY without a traditional terminal client
defaults to a huge window size (2000+ cols, 10000 rows). Pass
explicit -x and -y flags matching the TerminalView dimensions.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
test / unit + widget + golden + a11y (push) Failing after 34s
test / integration_test (xvfb) (push) Has been skipped
test / bundle smoke (xvfb 5s) (push) Has been skipped
test / daemon subprocess + web WASM smoke (push) Has been skipped
Reverts the bare-shell diagnostic. Spawns tmux new-session -A -s
<sessionName> for persistence. Claude command will be added back
after tmux + resize are stable.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
test / unit + widget + golden + a11y (push) Failing after 28s
test / integration_test (xvfb) (push) Has been skipped
test / bundle smoke (xvfb 5s) (push) Has been skipped
test / daemon subprocess + web WASM smoke (push) Has been skipped
top fails with "Error opening terminal: xterm-256color" because the
PTY child can't find terminfo. Set TERMINFO=/usr/share/terminfo
explicitly in the pane environment.
Output flush changed from 16ms Timer to Duration.zero (next event
loop turn) for tighter batching of escape sequences.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
test / unit + widget + golden + a11y (push) Failing after 29s
test / integration_test (xvfb) (push) Has been skipped
test / bundle smoke (xvfb 5s) (push) Has been skipped
test / daemon subprocess + web WASM smoke (push) Has been skipped
Split escape sequences caused rendering artifacts (visible % prompt
mark, garbled lines between commands). Two fixes from the legacy
Python implementation:
1. Read buffer increased from 4096 to 65536 bytes. Larger reads mean
fewer chunk boundaries that can split multi-byte escape sequences.
2. Output writes throttled to ~60fps via a 16ms Timer. Multiple PTY
reads within one frame window are batched into a single
terminal.write() call, so the xterm parser sees complete sequences
instead of fragments that render as garbage between frames.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
test / unit + widget + golden + a11y (push) Failing after 28s
test / integration_test (xvfb) (push) Has been skipped
test / bundle smoke (xvfb 5s) (push) Has been skipped
test / daemon subprocess + web WASM smoke (push) Has been skipped
Rapid resize during window drag sends many SIGWINCH signals causing
the shell to redraw repeatedly, corrupting xterm's render. Debounce
to 150ms so only the final size is sent.
NativePty.resize now explicitly sends SIGWINCH (signal 28) after
TIOCSWINSZ, matching the legacy Python implementation.
Removed 8px padding from ClidePtyView to eliminate potential
dimension mismatch between widget size and PTY cols/rows.
Default window size increased to 1600x900.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
test / unit + widget + golden + a11y (push) Failing after 1m57s
test / integration_test (xvfb) (push) Has been skipped
test / bundle smoke (xvfb 5s) (push) Has been skipped
test / daemon subprocess + web WASM smoke (push) Has been skipped
The PTY was spawning at 80x24 defaults before TerminalView had laid
out, then the real resize caused visual artifacts (ghost lines, broken
reflow). Now spawn triggers on the first onResize callback when real
dimensions are known — matching the pty-spike's proven pattern.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
test / unit + widget + golden + a11y (push) Failing after 28s
test / integration_test (xvfb) (push) Has been skipped
test / bundle smoke (xvfb 5s) (push) Has been skipped
test / daemon subprocess + web WASM smoke (push) Has been skipped
The context panel was hidden or collapsed when a decision or ticket
was selected. activateTab alone doesn't make the panel visible.
Now both extensions explicitly setVisible + setCollapsed before
activating the detail tab.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
test / unit + widget + golden + a11y (push) Failing after 28s
test / integration_test (xvfb) (push) Has been skipped
test / bundle smoke (xvfb 5s) (push) Has been skipped
test / daemon subprocess + web WASM smoke (push) Has been skipped
The IsolateClient and KernelServices now share the same DaemonBus.
Previously, backend events (pane.output, git.changed) went to a
separate bus that widgets couldn't see.
ClaudePane._spawnWhenReady waits for ProjectOpened before sending
pane.spawn, preventing "No project active" errors.
Recents loaded before runApp so the welcome screen shows them.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Toolchain centralizes binary resolution — replaces five ad-hoc
mechanisms (expandedPath, _resolveGit, _resolve, _resolvePtyc,
_existsOnPath). Resolves via Future.delayed after runApp to avoid
blocking the merged UI/platform thread on macOS.
GitClient wraps all git operations with a typed API. Every subprocess
call goes through _run() using toolchain.git + toolchain.gitEnv.
Replaces free functions in operations.dart.
Native directory picker: NSOpenPanel on macOS (method channel in
AppDelegate), GtkFileChooserDialog on Linux. Falls back to text-input
dialog on web or MissingPluginException. Shows "No git repo found"
dialog when the selected directory is not a git repository.
PqlClient and pane commands updated to use Toolchain. ToolCheck
replaced by Toolchain.missing/allOk. All IPC handlers now catch
GitException to prevent unhandled exceptions on the merged thread.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
test / unit + widget + golden + a11y (push) Failing after 26s
test / integration_test (xvfb) (push) Has been skipped
test / bundle smoke (xvfb 5s) (push) Has been skipped
test / daemon subprocess + web WASM smoke (push) Has been skipped
Replaces the N+1 parent-chain walk (one IPC call per ancestor, one
per decision ref) with a single pql ticket show --with-context call.
pql now returns ancestors and decisions arrays inline.
Updates PqlClient.ticketShow to accept withContext/withChildren flags,
removes the obsolete withDecision flag.
Co-Authored-By: Claude <noreply@anthropic.com>
Decisions: file-change subscription for decisions/*.md plus 1-minute
scheduler tick. Tickets: 1-minute scheduler tick plus changed-event
subscription from status button clicks. PQL markdown tab: file-change
subscription for *.md files. All panels get a manual refresh button.
Accordion sections use pin/focus logic: manually toggled sections are
pinned and stay open; the focused item's section auto-opens; unpinned
sections without focus auto-collapse. Both decisions and tickets views
use ClideAccordion with this pattern.
Ticket sidebar split into six status sections (IN PROGRESS, REVIEW,
READY, BACKLOG, DONE, CANCELLED) matching pql's actual statuses.
Status changes scroll the ticket into its new section.
Co-Authored-By: Claude <noreply@anthropic.com>
Status buttons in the detail view now call pql.tickets.status IPC,
publish a changed event to refresh the sidebar list, and reload the
detail. Disabled for the current status. IPC handler accepts ids as
a list for batch transitions. PqlClient.ticketSetStatus takes
List<String> and joins with comma per pql CLI contract.
Co-Authored-By: Claude <noreply@anthropic.com>
test / unit + widget + golden + a11y (push) Failing after 33s
test / integration_test (xvfb) (push) Has been skipped
test / bundle smoke (xvfb 5s) (push) Has been skipped
test / daemon subprocess + web WASM smoke (push) Has been skipped
Search tab defaults to ranked text search via pql search — debounced
300ms, scored results with visual score bar. DSL toggle switches to
raw PQL query mode for SQL-like queries. Clicking a search result
opens it in the markdown context viewer.
Adds pql.search IPC command and PqlClient.search method. Controller
gains SearchMode enum and search() method alongside existing runQuery.
Co-Authored-By: Claude <noreply@anthropic.com>
Search (PQL DSL query) is now the default left tab; Markdown (filtered
to .md files) on the right. Clicking a markdown file publishes on
the message bus; the markdown extension activates the context panel
viewer and re-publishes on a load channel after the frame so the
viewer is guaranteed to be mounted. Viewer subscribes to load channel
and editor buffer events, publishes focus for sidebar highlighting.
Co-Authored-By: Claude <noreply@anthropic.com>
Each ClideCodeBlock and EditorView created its own TreeSitterService,
each allocating a WASM engine, store, parser, and cursor via FFI.
When widgets were disposed, multiple instances freeing the same
underlying native resources caused double-free corruption on startup.
Single shared instance for the app lifetime. Also fixes overlapping
tree-sitter spans that caused duplicated text in code blocks — spans
are now clipped to avoid re-emitting already-rendered characters.
Co-Authored-By: Claude <noreply@anthropic.com>
All sidebar and detail panes use clideFontSmall/clideFontBadge/
clideFontCaption instead of hardcoded sizes — single place to tune.
Decision detail view subscribes to the message bus for selection
events (same pattern as ticket controller) and publishes focus after
loading. Both decisions and tickets sidebar views subscribe to the
focus channel, expand the accordion section, highlight the active
card, and scroll it into view.
Clickable DQRT links wired in decision detail, ticket detail, and
markdown viewer via onRecordTap. Ticket descriptions now render
through ClideMarkdown instead of plain text.
Co-Authored-By: Claude <noreply@anthropic.com>
Both tickets and decisions extensions now uncontribute and
re-contribute the detail tab on every selection, passing the
selected ID via initialId. This guarantees the view loads
immediately — no first-click miss from the widget not being
built when the message fires.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
New pql.decisions.read IPC verb returns the full markdown section
body. Decision detail view now shows: title card, full decision
text (rationale, cost, cross-references), and clickable ref cards
for cross-reference navigation.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Clicking a parent ticket in the tree publishes
builtin.tickets/selection — loads that ticket in the detail view.
Clicking a decision ref publishes builtin.decisions/selection —
switches context panel to the decision detail. Both show hover
highlight. Enables full cross-reference navigation without
leaving the context panel.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Detail controller publishes builtin.tickets/focus with the loaded
ticket ID after every load. Ticket list subscribes and highlights
the matching card with selected background and accent border.
Works regardless of what triggered the detail load — sidebar
click, parent tree navigation, or future command palette.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Extension listens to its own selection channel and activates the
detail tab in the context panel — fixes the chicken-and-egg where
the controller only subscribes after the widget builds. Registration
order in main.dart now determines sidebar icon rail order: tickets
first, then decisions, files, git, pql, problems.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Icons now declared on TabContribution via the icon field — the
hardcoded switch in _BottomRail is a fallback only. All sidebar
and context extensions set their Phosphor icon explicitly.
PanelRegistry supports setTabOrder(slot, List<String>) — tabs
render in the order specified by project.layout.sidebar.order /
context.order in settings.yaml. Falls back to registration order.
Priority field removed from all contributions.
Context tabs are static again — persist with their last content,
selection just loads new data and switches focus. No spawn/despawn.
Tickets sidebar priority set to -200 (leftmost, default open).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Two flow fixes:
1. First click now works — extension passes initialId to the
detail view constructor, which loads immediately in
didChangeDependencies. No second click needed.
2. Tab despawns when user navigates away — extension listens to
PanelRegistry changes, despawns detail tab when it's no longer
the active context panel tab.
Each selection re-creates the tab with a fresh initialId so the
view always matches the selection. Applied to both tickets and
decisions.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Context panel tabs are no longer static. Extensions spawn them
dynamically when relevant and despawn on deactivate:
- Tickets: detail tab spawns on builtin.tickets/selection
- Decisions: detail tab spawns on builtin.decisions/selection
- Backlinks: spawns when editor opens a file
- Markdown viewer: spawns when editor opens a .md file
- Graph: removed from static context (will be command-spawnable)
The icon rail only shows what's active — no empty tabs sitting
there waiting for content.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Click a decision card in the sidebar → publishes on
builtin.decisions/selection → detail view loads full record →
context panel activates decisions.detail tab and renders:
- Type dot with tooltip, ID colored by type, domain badge
- Title, date
- Status badge for resolved questions
Same MessageBus pattern as ticket detail.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Click a ticket card in the sidebar → publishes on
builtin.tickets/selection → detail controller loads full ticket,
walks parent chain, resolves decision refs → context panel
activates tickets.detail tab and renders:
- Full ticket header with type dot, ID, priority
- Status controls (tappable row to change status)
- Description
- Parent tree (indented compact cards)
- Referenced D-records as cards
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
DaemonBus (was EventBus): typed events for system/IPC layer.
MessageBus: channel-based pub/sub for UI/extension coordination.
Messages carry publisher (auto-stamped from extension ID),
channel (required), timestamp, and payload. Subscribe by
publisher, channel, or both — zero collision across extensions.
Extension context gains publish() and subscribe() convenience
methods that auto-stamp the extension's ID as publisher.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Both views now group items into collapsible accordion sections:
- Decisions: CONFIRMED/QUESTIONS/REJECTED with colored dots
- Tickets: ACTIVE/BACKLOG/DONE/OTHER with caret toggle
Cards show type dot with tooltip, ID in mono, domain badge
(decisions), parent reference (tickets), wrapping title, and
status badges. Search filter forces all sections open. ACTIVE
and BACKLOG default expanded; DONE default collapsed.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
TicketTypeColors maps initiative/epic/story/task/bug to distinct
colors, with dark and light presets auto-selected from the active
theme. Ticket IDs are now color-coded by type (purple initiative,
blue epic, green story, muted task, red bug). Status dot remains
for state. Pattern documented in theme-ui skill as the standard
for extension-owned domain colors.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Both views were calling pql.exec (not registered). Switched to
pql.decisions.list and pql.tickets.list which are registered
IPC handlers. Response parsing updated to read structured data
instead of parsing JSON from stdout.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>