Commit Graph
519 Commits
Author SHA1 Message Date
jpmschweitzerandClaude c56b60622b open markdown files in the reader, not the editor
The files panel and the Claude Config tab called ipc.request('editor.open')
for every file, which targets the editor — so a .md click never reached the
right-side markdown reader (it opens only when something publishes
('builtin.markdown','selection')). Route .md clicks from the files panel
(tree + filtered rows), the Config tab's file-backed rows, and .md wiki links
in the viewer to that channel; non-.md files still open in the editor. Also
remove the dead DaemonEvent fallback that listened for 'editor.buffer_activated'
(the registry emits 'editor.active-changed').

T-187.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-05-31 16:16:34 +02:00
jpmschweitzerandClaude 4340dc38d0 add pumpAsync test helper — bounded settle for async widget tests
A reusable helper in the shared harness that drains microtasks + advances
one short fake-time tick, replacing the two patterns that have repeatedly
wedged the suite (and the pre-push gate) for ~10 minutes each: pumpAndSettle
(loops until quiescent — hangs on perpetual animation / overlapping async)
and `await Future.delayed(Duration.zero)` inside testWidgets (a real timer
that never fires under fake-async). Bounded by construction — cannot hang.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-05-31 16:15:51 +02:00
jpmschweitzerandClaude 3c8bcef5c7 sync governance question index
Regenerated by `pql decisions sync` — moves resolved questions (Q-6, Q-19,
Q-21, Q-22) into a Resolved section.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-05-31 16:15:30 +02:00
jpmschweitzerandClaude 968686c4c8 fix whats-next: pql ticket --status is single-valued
Dogfooding the skill surfaced it: `--status backlog,ready` is not a comma
list — it matches nothing and silently returns [], which would make batch
selection lie. Use a single `--status backlog` and note the `--unblocked`
filter still surfaces prose-"blocked on upstream" tickets (e.g. T-158).

Co-Authored-By: Claude <noreply@anthropic.com>
2026-05-31 13:12:47 +02:00
jpmschweitzerandClaude 08b88bc841 use pql 1.6.0 built-ins in the whats-next skill
Batch selection no longer walks blockers per ticket or post-processes
JSON: read the landscape with `ticket show --tree`, select actionable
work with the composable `ticket list --under <epic> --leaf --unblocked
--status backlog,ready`, and record refinements with `ticket append`
instead of re-sending the whole description through `refine write`.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-05-31 13:01:03 +02:00
jpmschweitzerandClaude 6168a59c4b cover the Phase 2 Claude surface to clear the 95% floor
The team cockpit / chat / config-tab work landed under-tested and pulled
total line coverage to 94.32%. Add tests for the team chat sidebar + pane
(@-completion, overlay, interrupt, message rows), the config loaders, the
stream-json MCP/streaming/rate-limit paths, and the conversation/prompt
card variants — restoring the total to 95.06%.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-05-31 12:54:04 +02:00
jpmschweitzerandClaude e866da9fd8 capture a forked session's real id from its init event
A --fork-session branch is spawned without --session-id, so claude mints
a new session id that only arrives in the init event; the ManagedSession
was left holding its placeholder. StreamJsonSession now captures
session_id from the first event that carries it and exposes it via
claudeSessionId / sessionIdResolved; the orchestrator folds that back into
ManagedSession.sessionId (idempotent for normal sessions). A fork can now
itself be resumed or forked.

T-185.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-05-31 12:21:56 +02:00
jpmschweitzerandClaude d0ad8ed4aa stream Claude replies token-by-token from stream_event deltas
A live capture against claude 2.1.150 (both --print and the interactive
stream-json transport clide uses) confirms --include-partial-messages
emits the in-progress reply as stream_event envelopes wrapping Anthropic
streaming deltas — NOT assistant events with partial:true, which is what
T-168 assumed, so that handler never fired and streaming was inert.

Replace it: accumulate content_block_delta text per message id (tracked
from message_start, since deltas carry no id) and emit a placeholder under
a stable partial-<id> uuid the controller upserts in place; the matching
single-text-block assistant event reuses that uuid to finalize, while
tool_use / thinking blocks keep their own uuids and append in order. Tests
rewritten against the captured shape; spike doc records it.

T-184.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-05-31 12:16:52 +02:00
jpmschweitzerandClaude 494a6f13a5 build the Config sidebar tab
The Config sub-tab grows from a static settings table into a browser of
the Claude environment: the pinned settings table stays, and below it
expandable accordions list the full (never-truncated) sets of skills,
agents, commands, hooks, permissions (grouped + colour-coded by allow/
ask/deny), and MCP servers. File-backed entries are clickable and open
their .md via editor.open. ClaudeConfig gains agents, hooks, and
mcpServers loaders plus path fields on skills/commands, kept live by the
existing .claude file watcher.

T-183.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-05-31 11:30:02 +02:00
jpmschweitzerandClaude a0636c2e5a add the team chat inbox over the broker
Renders broker traffic as a chat timeline and makes the user a first-class
participant. The broker grows a Stream<TeamMessage> and a recipient field,
auto-registers a virtual `user` member, and gains sendAsUser. A Flutter-free
TeamChatModel (owned by the orchestrator) accumulates the feed and exposes
postAsUser with @-routing (a new at_commands helper mirroring slash) and an
optional interrupt that cancels the target's turn before delivery. One model
backs two surfaces: a compact cockpit widget that pops out into a full
workspace chat pane. CLI parity via clide.team-chat.open / .post.

T-180.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-05-31 10:49:04 +02:00
jpmschweitzerandClaude e3c0b0146b fork a Claude conversation into a new pane
Adds fork-into-a-pane: /fork in the composer, a roster Fork button, and a
clide.agent.fork command all branch a session via
--resume <source> --fork-session, so the branch gets its own claude
session id and diverges without touching the original. SpawnSpec/
ManagedSession gain forkSourceSessionId; the orchestrator selects the
fork argv via a new forkSessionArgs helper; the session host opens the
fork as a new secondary pane.

The branch's real claude session-id (assigned by --fork-session, arriving
in the init event) is not yet captured back — tracked as T-185.

T-172.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-05-30 23:34:50 +02:00
jpmschweitzerandClaude 2888efbe5f add per-agent permission-mode badge to the cockpit roster
Each roster row shows a D/A/P mode badge reflecting the session's live
permission mode. Click cycles the safe trio default -> acceptEdits ->
plan and sends a set_permission_mode control_request to that session
(mirrors interrupt(); fire-and-forget). bypassPermissions is a footgun,
so it is reachable only on Shift-click and behind an inline confirm. A
clide.agent.set-permission-mode command gives the CLI parity.

T-181.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-05-30 23:25:07 +02:00
jpmschweitzerandClaude 4220d97a49 add the Claude team cockpit: roster controls + live task list
The meta sidebar's Team tab becomes a control surface for clide-managed
agents instead of a read-only roster. Each row gains show/hide, mute,
close, and inject-a-message; a live task list renders from the broker
with reassign. The broker grows a Dart change-stream (kept Flutter-free
for dart test) plus tasks/reassign; the orchestrator gains mute/unmute,
injectMessage, and member-name session resolution. Every new UI action
has a matching clide command (D-6 parity).

T-171.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-05-30 23:11:22 +02:00
jpmschweitzerandClaude 80401a3228 make conversation card actions keyboard-reachable
The copy button and custom message actions only rendered on hover, so
they were unreachable by keyboard or assistive tech. Keep them in the
tree always — revealed via opacity on hover OR focus — and route each
through ClideTappable (Tab traversal + Enter/Space activation) with a
Semantics button label and onTap so AT can discover and invoke them.
alwaysIncludeSemantics keeps them in the semantics tree while hidden.

T-174.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-05-30 23:09:57 +02:00
jpmschweitzerandClaude c5e58733a2 render typed tool cards and live session status from stream-json
The conversation pane now exploits the structured stream instead of
dumping tool input as JSON. ConversationController indexes tool_use by id
so a tool_result pairs back to its call and renders the Edit/Write diff or
is_error failure in place; per-tool bodies (Bash command+output, Read/Grep
file/query) reuse the shared renderers factored out of the permission
card. SessionStatus gains cost + contextWindow + rate-limit, read straight
off the init/result/rate_limit_event events, so the in-pane status line
reflects live state without the config probe.

Partial-message streaming is wired behind --include-partial-messages but
its event shape is unverified against the live binary and degrades to a
no-op if it differs — see T-184.

T-168.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-05-30 13:44:19 +02:00
jpmschweitzerandClaude f6b88f503f retire tmux for Claude sessions
Session lifecycle now runs entirely on the stream-json model: argv
selection picks --resume <id> for an existing transcript and
--session-id <uuid> for a fresh one, and the managed-session orchestrator
owns spawn/close. With the transport off tmux, remove the tmux session
lifecycle (reaping, kill-all-for-repo) and the tmux-polling team observer;
kill-all-sessions now closes sessions through the orchestrator. Team
membership is orchestrator-driven since the coordination broker landed.

Amends D-41 (tmux persistence -> --resume). T-167.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-05-30 13:05:41 +02:00
jpmschweitzerandClaude 7b9861a097 give the status-bar context slot a flexible share
StatusbarHost laid every item at intrinsic width, so once the focused-pane
context line grew long (a model/mode/context/skills summary) the row's
content exceeded the bar width and overflowed instead of letting the slot
shrink. Add an opt-in flex factor to StatusItemContribution; the host wraps
flex>0 items in Flexible(loose) so they yield width when the bar is tight,
and the marquee then receives a bounded viewport and scrolls. Drops the
fixed maxWidth cap on the pane-context item.

T-160.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-05-30 13:04:59 +02:00
jpmschweitzerandClaude 4761b5c12d escape the NUL in the Other-choice sentinel
_kOther carried a literal NUL byte so a real option labelled "other"
could never collide with the sentinel. The raw byte made the source
read as binary: git showed a binary diff and grep/file treated it as
data. Write it as a unicode escape instead — identical runtime value,
plain-text source again.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-05-30 12:47:45 +02:00
jpmschweitzerandClaude d5bf831e1a suppress duplicate file_path on Write/Edit permission cards
Claude often sends the file path itself as the tool description for
Write/Edit. The card body already renders that path, so printing the
description line above it showed the same path twice. Suppress the
description when it just repeats file_path.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-05-30 12:46:48 +02:00
Jeroen SchweitzerandClaude ba5d738b9c track .pql/pql-plan.json as the planning backup
pql 1.5 re-introduced .pql/pql-plan.json as the canonical planning-
state export (regenerated on every decisions/ticket mutation). Bring
the un-ignore back so the backup rides commits across clones —
add028e dropped it when the file was dead under pql 1.4, but the
export is live again. Hooks stay ignored (still per-clone, absolute
paths baked in).

Co-Authored-By: Claude <noreply@anthropic.com>
2026-05-28 11:06:39 +02:00
Jeroen SchweitzerandClaude 6e4c3c4bf4 seed resumed Claude session from the transcript tail
claude --resume keeps the model's prior context but emits no past
turns over stream-json, so the pane was visually empty until the
user sent a new prompt. The orchestrator now reads the last 256 KB
of the on-disk transcript JSONL when SpawnSpec.resume is true and
seeds the ConversationController with the parsed items before the
stream subscription starts. Best-effort: missing or unreadable file
just falls back to the previous empty-pane behaviour.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-05-28 10:17:32 +02:00
Jeroen SchweitzerandClaude 762d66e819 shape permission-prompt input rendering per tool
Bash, Write, and Edit/MultiEdit each get a tool-appropriate body in
the permission card instead of the indented-JSON dump: Bash renders
the command as a shell code block with a background/timeout footer,
Write shows path + content syntax-highlighted from the extension, and
Edit shows path + before/after blocks. Unknown tools keep the JSON
fallback.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-05-28 09:52:20 +02:00
jpmschweitzerandClaude Opus 4.7 25c11c1edb split the Claude meta sidebar into Activity / Team / Config sub-tabs
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 34s
The sidebar had outgrown one scroll (stats + roster + config don't fit). A
sub-tab strip now switches between three surfaces: Activity (usage stats +
the primary session's live runtime), Team (the member roster, auto-fronted
when a team spawns and otherwise quiet), and Config (the Claude-environment
settings table over ClaudeConfig).

Activity and Config render their key→value rows through one shared table
(same label column + row pitch + header style) so toggling tabs doesn't move
anything. The expandable skills/agents/commands/permissions/MCP browser on
the Config tab is the follow-up (T-183). Exposes StreamJsonSession.status so
the runtime row can seed from the session's current state.

T-182, D-77.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-25 22:07:45 +02:00
jpmschweitzerandClaude Opus 4.7 6c5c67f6dc add a clide-hosted team coordination broker over the MCP control channel
Claude's tmux team mode let teammates message each other and share a task
list; that mode is undocumented and unavailable headless. clide rebuilds
the same behavior over its own managed sessions, as the broker.

Verified live against claude 2.1.150 that a spawner can host an in-process
("SDK") MCP server entirely over the stream-json control channel — no
subprocess, no --mcp-config, no socket: declare the server name in the
initialize handshake's sdkMcpServers, answer the mcp_message JSON-RPC
round-trips (initialize / tools/list / tools/call) under
response.response.mcp_response. SDK tool calls are permission-gated through
the existing can_use_tool path. Documented in the 2.1.150 spike §6.

StreamJsonSession gains an McpServer hosting seam; TeamBroker + TeamMcpServer
expose send_message / broadcast / list_teammates / inbox / claim_task /
task_status, all routed through one shared broker. The orchestrator owns the
broker, registers each team session, delivers a message into the target's
next turn on its stdin, and injects roster + role via --append-system-prompt.
Solo sessions are unchanged (no MCP server, no initialize handshake).

T-170, D-77.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-25 21:37:53 +02:00
jpmschweitzerandClaude Opus 4.7 3e7b600815 add an interrupt path for a running Claude turn
test / unit + widget + golden + a11y (push) Failing after 31s
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 29s
A runaway turn had no escape: Escape was unbound once the slash typeahead
was closed, and there was no Stop affordance. Now the composer interrupts
the in-flight turn — Escape (when no typeahead is open) or a Stop button
shown while busy — over the stream-json control channel.

StreamJsonSession gains interrupt() (writes a {subtype: interrupt}
control_request; claude cancels the turn and ends it with a result) and a
busy/busyStream signal driven true on send and false on the next result.
The pane binds onInterrupt to the session and reflects busy reactively.

D-78.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-25 14:08:40 +02:00
jpmschweitzerandClaude Opus 4.7 e0fa081cb9 wire the Claude pane onto the session orchestrator (T-169)
The pane no longer spawns/owns its StreamJsonSession — it spawns-or-binds
through the app-wide ClaudeSessionOrchestrator by a stable pane key, and
the orchestrator owns the session + conversation. Consequences: disposing
a pane no longer kills its session (a kept-alive/hidden pane keeps it);
the primary re-binds to its live session on remount (conversation
survives); closing a secondary tab closes that session; /clear and
/resume close + respawn through the orchestrator. The extension owns the
orchestrator (set on activate, disposed on deactivate).

Remaining for T-169: re-point TeamObserver from tmux-polling to
orchestrating managed sessions, and roster-driven show/hide.

T-169.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-25 13:24:19 +02:00
jpmschweitzerandClaude Opus 4.7 a79a78fc8f add the clide-managed session orchestrator (T-169 core)
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
test / dart doc (lib API) (push) Failing after 29s
ClaudeSessionOrchestrator owns a registry of ManagedSessions, decoupling
a session's lifecycle from any pane: spawn() starts + registers a
stream-json process, show()/hide() toggle visibility WITHOUT killing the
process, and close() tears it down. This is the one primitive Phase 2's
teammate / secondary-tab / forked-branch panes all become (D-77). The
process factory is injectable so the lifecycle is unit-tested without a
real claude. Not yet wired into the pane — that re-pointing is the next
T-169 step.

T-169.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-25 12:52:04 +02:00
jpmschweitzerandClaude Opus 4.7 1fb08afa30 align pql client to the 1.5 exit-code contract; unvendor its skill
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
test / dart doc (lib API) (push) Failing after 31s
pql 1.5 returns exit 0 with an empty `[]` for zero matches (older pql
used exit 2), so the wrapper's "exit 2 = empty, not an error" carve-out
is obsolete — and risky, since a future exit 2 could mean a real error.
Any non-zero exit is now an error.

Also removed the repo's vendored .claude/skills/pql: it's generated by
`pql init` (which CONTRIBUTING already lists in setup, installing at user
scope), so a committed snapshot just shadows the current global skill
with stale content and drifts on every pql bump — this copy was a whole
version behind. Other vendored skills are clide-owned; pql's is pql's.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-25 11:50:48 +02:00
jpmschweitzerandClaude Opus 4.7 6e988ca816 trim the prompts changelog bullet under the 60-word cap
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 33s
The native-prompts Added entry ran over the changelog gate's per-bullet
word ceiling; tightened it to the user-facing essentials.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-25 11:40:24 +02:00
jpmschweitzerandClaude Opus 4.7 11ccd0f246 activity tab uses the same label→value table as config settings
So toggling Activity↔Config doesn't visually jump: both render on one
two-column table (label left, value at a shared x, same row pitch +
section headers). T-182 notes the shared geometry.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-25 11:38:15 +02:00
jpmschweitzerandClaude Opus 4.7 0d377dfbae config tab: settings table on top, full expandable lists
Settings is a fixed, short set, so it's a key->value table pinned at the
top, not an accordion. Variable-length groups (skills, agents, commands,
hooks, permissions, MCP servers) expand to their COMPLETE list rather than
a truncated first-N + "…" — a truncated list falsely prioritises its first
entries. Permissions expand grouped by allow/ask/deny. T-183 scope synced.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-25 11:35:54 +02:00
jpmschweitzerandClaude Opus 4.7 da803e17e3 config sidebar wireframe: expandable lists, click-to-open .md
The Config tab is a browser, not a summary: each category (skills,
agents, commands, hooks, …) is an expandable accordion of the full list,
and file-backed entries open their .md in the right-side reader rather
than truncating to a one-line "…". Updates the T-183 scope to match.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-25 11:31:49 +02:00
jpmschweitzerandClaude Opus 4.7 af02ae39c4 add team cockpit + sidebar sub-tab wireframes (frame0)
Phase-2 interaction-model wireframes (D-77): the team cockpit sidebar and
the expanded team-chat pane (message inbox, @-routing, interrupt tickbox,
per-agent permission-mode badge), and the Claude sidebar reorganised into
Activity / Team / Config sub-tabs. Referenced by T-180..T-183.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-25 11:26:48 +02:00
jpmschweitzerandClaude Opus 4.7 2243237b13 refine the prompt/log UX: show commands, de-emphasize injects
Two spot-check fixes (T-178, T-179), both grounded in a boundary test of
the stream-json wire (findings folded into the spike doc):

- Harness-injected user messages (skill loads, slash-command expansions,
  system reminders) carry isSynthetic on the wire (isMeta in the
  transcript). They were rendering as blue "you" cards though the user
  never typed them; now UserMessage.injected flags them and the view
  shows a muted, collapsed "context" card instead.
- Permission prompts now show the command/input being permitted (a
  capped, scrollable code block) so you can see what you approve. Instead
  of fully hiding a prompted tool-use, once resolved it collapses to a
  one-line summary with a green (approved) or red (denied) border; the
  session tracks per-tool_use_id outcome and the view colours it. The
  result is kept.

Corrects an earlier wrong assumption: the Skill tool is auto-allowed
(no permission prompt); the inject only appears once the Skill tool is
actually invoked, which is why deny-captures missed it.

T-178, T-179, D-78.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-25 10:26:33 +02:00
jpmschweitzerandClaude Opus 4.7 c30a707b41 hide prompted tool-use payloads from the conversation log
A permission-gated tool or AskUserQuestion already surfaces as a prompt
in the composer zone, so its raw tool-use card was redundant noise. The
session now tracks which tool_use_ids surfaced as a prompt; the
conversation view hides those tool-use cards. AskUserQuestion also hides
its result (the chosen answer is logged separately); permission-tool
results are kept — that's the useful outcome. The pane rebuilds the
view on each prompt change so the payload vanishes the moment its prompt
appears.

T-176, T-177, D-78.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-25 09:50:39 +02:00
jpmschweitzerandClaude Opus 4.7 de264e7141 flesh out the Claude prompt UX: options, stepper, collapse
Builds on the in-composer prompt surface (D-78):

- Permission prompts (T-175): Allow / Allow-and-don't-ask-again / Deny.
  "Don't ask again" appears only when the request carries a
  permission_suggestion and echoes it back as updatedPermissions. An
  optional note rides Deny as the message, or Allow as a follow-up user
  message (the protocol has no allow-with-message).
- AskUserQuestion picker (T-176): a single question renders bare; 2-4
  questions step one at a time (nav shows "N · Header", ✓ when answered)
  then a review/confirm screen. Each question offers an "Other" free-text
  choice and a per-choice note; multi-select joins labels. A "chat
  instead" escape denies the prompt so the user can type freely. On
  submit the answer is echoed into the log, since the card is ephemeral.
- Collapsed tool cards (T-177): multi-line tool_use / tool_result start
  collapsed behind a one-line summary; one-line output renders inline.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-25 09:30:50 +02:00
jpmschweitzerandClaude Opus 4.7 fbf5a720a8 add Claude prompt UX wireframes (frame0)
Wireframes for the in-composer prompt surface (D-78): single
AskUserQuestion (bare), multi-question stepper, the review/confirm step,
and the permission Allow / Allow-and-remember / Deny prompt. Authored as
JSON, rendered + exported via the frame0-wireframe skill.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-25 09:30:40 +02:00
jpmschweitzerandClaude Opus 4.7 39f9ed018c drive the Claude pane over stream-json with native prompts
Replaces the Claude pane's tmux-TUI + transcript-tail backend with
Claude Code's stream-json control protocol (D-77/D-78). A
StreamJsonSession owns the `claude` process: its event stream feeds the
existing ConversationController, and permission / AskUserQuestion
prompts arrive as can_use_tool control_requests. Those surface as a
ToolPrompt in the composer zone — the pane swaps the text input for an
Allow/Deny card or an option picker while a prompt is open, so
interaction stays out of the conversation stream and the prompt buttons
don't fight the message-card hover chrome. The decision is written back
as a control_response (allow echoes updatedInput; AskUserQuestion
answers go in updatedInput.answers). Unsupported control subtypes are
answered with an error so a turn never hangs.

Session continuity is --resume (existing transcript) vs --session-id
(new); /clear and /resume respawn the process. The transcript reader
still backs the sidebar/status/team surfaces. T-165, T-166.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-25 08:40:18 +02:00
jpmschweitzerandClaude Opus 4.7 8310730506 document the stream-json control protocol + D-78
Empirical spike against claude 2.1.150 (driving the real CLI over
stdin/stdout + reading the shipped binary's zod schemas) pinned the
wire shapes for the stream-json control protocol: the can_use_tool
permission request, the control_response envelope, the
--permission-prompt-tool stdio enabler (without it "ask" tools silently
auto-deny), the allow-requires-updatedInput quirk, and AskUserQuestion
answered via updatedInput.answers. Captured in a version-pinned spike
note with a resilience section (detection canaries + a ranked fallback
menu) so a future Anthropic change to this undocumented contract doesn't
leave us at a blank slate.

D-78 records the decision: permissions ride the stdio control channel,
not MCP (MCP is reserved for capability/tool provision); refines D-77.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-25 08:40:05 +02:00
jpmschweitzerandClaude Opus 4.7 e672f1a77b render every conversation turn through one card primitive
test / unit + widget + golden + a11y (push) Failing after 24s
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 25s
The Claude pane's conversation view hand-rolled a separate card layout
per message kind (user/assistant/thinking/tool-use/tool-result), so any
shared chrome had to be added five times. ConversationCard is one
template with three variants (stripe/bordered/bare) that wires the
chrome once: a copy button revealed on hover (yielding the turn's raw
text), an always-visible collapse/expand caret for collapsible turns,
and an extensible MessageAction list. It's decoupled from
ConversationItem — the view maps each item to (variant, accent, label,
body, copyText, actions) — so the typed event cards coming with the
stream-json work reuse the same chrome with a different body.

T-173.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-24 19:10:02 +02:00
jpmschweitzerandClaude Opus 4.7 1e77d72361 add StreamJsonSession transport (T-165 foundation)
test / unit + widget + golden + a11y (push) Failing after 25s
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 23s
The testable core of the stream-json pivot (D-77): StreamJsonSession drives
a claude process in stream-json mode — parsing its line-delimited events into
the existing ConversationItem / SessionStatus types (reusing
parseTranscriptChunk, since stream-json assistant/user events share the
transcript's message.content shapes), pulling permission-mode off the init
event, and sending user input as stream-json over stdin (with a local echo
so the user's own message renders immediately). The process is abstracted
behind StreamJsonProcess so it unit-tests without spawning; the real
ClaudeStreamJsonProcess wraps Process.start.

Not yet wired into the pane — the claude_pane integration (replace the
tmux/PTY spawn + TranscriptReader feed, route input through send) and live
verification are the next step.

T-165.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-24 18:41:34 +02:00
jpmschweitzerandClaude Opus 4.7 4489765db9 add D-77: drive Claude via stream-json; clide-owned unified session model
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 27s
Accepted (phased). Pivot the Claude pane from the interactive tmux TUI to
the stream-json control protocol: structured events instead of transcript
tailing, permissions + AskUserQuestion handled natively via canUseTool,
persistence via --resume. Claude's tmux agent-team mode is headless-
incompatible, so teams become clide-orchestrated — N managed sessions
coordinated by a clide-hosted MCP broker, with team-awareness injected via
--append-system-prompt/--agents.

Captures the unified-session-model upside: teammate / secondary tab /
forked branch / inline subagent collapse into one primitive (a managed
session rendered as a pane), with the sidebar as the cockpit. Amends D-41
(persistence) and evolves D-75 (rendering source). Phase 1 single-agent
first; phase 2 the unified model.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-24 18:25:33 +02:00
jpmschweitzerandClaude Opus 4.7 0d45416bb8 resume existing Claude sessions with --resume, not --session-id
test / unit + widget + golden + a11y (push) Failing after 32s
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 32s
Confirmed root cause of the dead-pane bug: `claude --session-id <id>`
rejects an id that already exists ("Session ID … is already in use") and
exits. The primary pane uses a deterministic id to resume across restarts,
and /resume re-binds to an existing id — both relaunched with --session-id,
so whenever the tmux session wasn't already alive (clean boot, or after
/clear+/resume) Claude exited instantly and the pane had no live backend:
typed input vanished while the transcript still rendered. The pane now
launches an existing session (transcript on disk) with `--resume <id>` and
only a brand-new one with `--session-id <id>`. Fresh secondaries and /clear
(fresh ids) were always fine. Verified empirically against a live session.

T-161.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-24 11:45:03 +02:00
jpmschweitzerandClaude Opus 4.7 b8168d8ffe fix ClidePane notifying focus listeners during build
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
test / dart doc (lib API) (push) Failing after 28s
ClidePane.didChangeDependencies/didUpdateWidget run in the build phase and
called FocusTracker.setStatusWidget -> notifyListeners() synchronously,
rebuilding the focus-listening status-bar item mid-build — Flutter threw
"markNeedsBuild called during build" on every frame once a Claude pane was
focused. The convey now defers to a post-frame callback when mid-build
(re-checking focus then) and applies immediately otherwise. The T-150
widget tests missed this because no focus listener was in their tree;
added a regression test with PaneContextStatusItem present.

T-159.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-24 10:54:26 +02:00
jpmschweitzerandClaude Opus 4.7 6e4f357c09 show live per-member status in the team sidebar
test / unit + widget + golden + a11y (push) Failing after 31s
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 29s
The teammate status was emitted by each TranscriptPublisher's statusStream
but never reached the bus. The observer now forwards it onto a shared
member-status channel ({agentId, model, permissionMode, contextTokens});
the meta sidebar subscribes and folds each member's live permission-mode
and context-token count into its roster row. No re-tailing — reuses the
existing stream (D-75).

T-157.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-23 22:57:01 +02:00
jpmschweitzerandClaude Opus 4.7 3038cd5eed add Claude meta sidebar — activity + team roster
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
test / dart doc (lib API) (push) Failing after 25s
An always-pickable left-panel tab. Shows Claude activity read from
~/.claude/stats-cache.json (latest day's messages/sessions/tool-calls +
lifetime totals, polled) and, when a tmux agent team is running, a roster
of its members (colour · name · agent type · model) from the observer's
join/left events — nothing re-tailed here.

Scoped down from the original ticket: the account/team token budget isn't
programmatically exposed under subscription auth (TUI-only; upstream
#44328) and live per-member status needs the teammate status stream wired
onto the bus — filed as T-158 and T-157 respectively.

T-141.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-23 22:49:37 +02:00
jpmschweitzerandClaude Opus 4.7 8907abeca7 add Claude session storage view with user-driven cleanup
The claude.session-storage command opens a modal listing the workspace's
session transcripts with their on-disk sizes (the <id>.jsonl plus the
<id>/ subagents dir) and a total. Each row deletes with a deliberate
two-click confirm; deletion is guarded against unsafe ids and clide never
removes transcripts on its own. SessionSummary gains a sizeBytes field and
session_index gains formatBytes + deleteSession.

T-148.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-23 17:02:20 +02:00
jpmschweitzerandClaude Opus 4.7 849024b7ee show the configured skills count in the Claude status line
The status slot showed only live session fields (model/mode/context).
It now also shows the configured skills count from ClaudeConfig — the
environment side alongside the live session — and the pane rebuilds when
the config changes so the count appears once skills load and tracks
.claude edits.

T-154.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-23 16:50:09 +02:00
jpmschweitzerandClaude Opus 4.7 2fd911d01d auto-load extension i18n catalogs; add the missing tab-title ones
Five builtins (tickets, decisions, git, pql, problems) declared a
localized tab title but shipped no catalog and weren't in the hand-kept
preload list, so each logged "namespace not registered" on boot.
ExtensionManager now loads the i18n namespace of every localized
TabContribution when its extension activates — no manual list edit for a
new tab — and the five missing en_US catalogs are added.

T-155.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-23 16:49:56 +02:00
jpmschweitzerandClaude Opus 4.7 e5fa6302d3 handle /resume in clide with a native session picker
test / unit + widget + golden + a11y (push) Failing after 24s
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 26s
Like /clear (T-156), Claude Code's /resume forks to a session the
transcript reader can't follow. clide now owns it: /resume opens a modal
picker of the workspace's recorded sessions — each labelled by its first
… last user prompt and last-active time — and re-binds the pane to the
chosen session-id (killing the current tmux session and respawning on the
picked id). Session enumeration reads bookend prompts from a bounded
window at each end of the transcript, so even multi-MB sessions summarise
cheaply.

T-156.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-23 14:05:03 +02:00