External MCP clients (Cursor, Windsurf, Copilot) can now drive clide. The
MCP server's tools/list is generated from the co-registered command+schema
registry (D-74) that already feeds the CLI and palette — the full
mcp__clide__* namespace with no hand-maintained second surface (D-86). Each
command's CommandSchema maps to a JSON-Schema inputSchema; tools/call routes
mcp__clide__<cmd> to dispatcher.dispatch and renders the IpcResponse as MCP
content (data as JSON, errors with isError).
register() gains a mcpExpose flag (default true); pane.tail opts out as a
poor request/response fit. tail/events are server-intercepted so they're
naturally absent. The two /ide stubs (getDiagnostics, executeCode) are left
as stubs — making them real (analyzer hook, Jupyter eval) is out of scope
per the ticket. Transport unchanged (SSE, D-73).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The one-shot request/response complement to the never-returning
`tail --events` stream — what an agent poll loop wants. The IPC server now
keeps a single global, arrival-ordered event log keyed by a monotonic
cursor (alongside the per-subsystem replay ring), bounded by eventLogDepth
with drop-oldest back-pressure (D-85: producer never blocks).
`clide events [--since <cursor>] [--filter X]` returns events after the
cursor, a high-water `cursor` to poll from next, and `gap: true` (+
oldestCursor) when the requested cursor predates the retained window so a
caller detects loss instead of silently missing dropped events. Repeated
polls neither drop nor duplicate. No on-disk persistence.
`events` is handled in the IPC server like `tail` (not the dispatcher);
added to the argv umbrella set. bindingWhen/CommandContribution untouched.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
T-223 (clide events --since) and T-225 (MCP surface) picked up — both
refined and unblocked by D-85/D-86. T-23 (command palette keybinding) was
ready but already complete per its body; marked done.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
panel.focusMode.exit is bound to Escape in the contributions layer, which
outranks the active preset. In Vim insert/visual mode that shadowed the
vim preset's `escape → vim.mode.normal` binding, so Esc closed the editor
instead of returning to normal mode.
Add an optional when-clause to a CommandContribution's defaultBinding
(plumbed through to KeymapService.registerCommandBinding, which already
accepts one) and guard focusMode.exit's escape with
`!vim.insert && !vim.visual` — symmetric with vim.yaml's vim.mode.normal.
Esc still exits focus / closes the editor in normal and non-Vim modes.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Running newest-first log of install and environment friction, seeded
with the pql hooks issue: pql init wrote delegators into .git/hooks
while core.hooksPath was unset, silently disabling the repo's pre-push
gate. Documents the make-hooks fix and the pql-init pitfall.
Co-Authored-By: Claude <noreply@anthropic.com>
Pressing Esc to leave insert/visual mode closes the active file/pane
instead of returning to Vim normal mode. The unconditional
escape->dismiss binding in default.yaml shadows the when-scoped
escape->vim.mode.normal binding, contradicting T-207's contract.
Co-Authored-By: Claude <noreply@anthropic.com>
Restores the coverage floor (94.85% → 95.19%). The diff-panel work landed
with diff_view.dart at 59% — the hunk header, the addition/removal/context
line rows, the new/deleted/renamed/binary metadata, and the error and
empty-state branches were never exercised. Adds four widget tests over an
injected controller; diff_view.dart goes 59% → 96%.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Adds the two missing cases that left lib/kernel/src/cli_install.dart:74
(default-environment constructor branch) and the builtin extension's
stale-GUI activation warning uncovered.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The Install-clide-command entry ran to 105 words; the rationale and the
stale-symlink detail live in the commit body and D-83/T-212. Keep the
changelog line to user-facing impact.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
clean-house sweep over governance/ (validate green, 0 broken refs before
and after):
- RULE-ANCHOR-DRIFT (37): rewrote inline cross-reference links left over
from before the decisions/questions/rejected subdir split — flat naming
(questions-architecture.md, questions-process.md, rejected.md) and bare
same-dir paths that were actually cross-type — to canonical
subdir-relative form with current slugs. pql resolved these by ID so they
were never broken to the tooling, only to GitHub anchor navigation.
- RULE-RECORD-SORT (1): reordered decisions/architecture.md D-records to
strictly ascending (the D-1..D-6 block had been appended after D-41); pure
block move, line count unchanged, content identical.
- RULE-FILE-OVER-THRESHOLD: deferred (architecture.md 435 > 350; splitting
would re-churn the anchors just fixed).
- EOF/whitespace and Q↔D backlinks clean.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Fixes 11 distinct inline anchor slugs that drifted from the generated
canonical form: em-dash titles render `--` (single-hyphen links were stale),
plus several truncated/old slugs (D-5, D-10, D-21, D-39, D-40, D-43, D-68,
Q-1, Q-32, Q-33). pql resolves cross-refs by ID so these were never "broken"
to the tooling, but they'd fail GitHub markdown anchor navigation. Verified:
every inline anchor now matches the README index; pql decisions sync reports
0 broken refs.
Does NOT touch the separate stale-path class (flat `questions-*.md` /
`rejected.md` naming from before the DQR subdir split) — surfaced for a
follow-up.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
D-85 — event bus delivery semantics, resolving Q-2 + Q-3: bounded
per-subscriber ring buffer with drop-oldest back-pressure (producer never
blocks, subscribers never killed) and a gap marker so a pull reader detects
loss; in-memory cursor retention serves `clide events --since`; if
persistence is ever needed it is bus-owned, not a subscriber-subsystem —
reversing ADR 0006's unreasoned open-questions footer.
D-86 — MCP tool surface, resolving Q-32: expose the full mcp__clide__*
namespace but generate tools/list from the co-registered command registry
(D-74) that already feeds CLI + palette, so breadth costs no second
maintained surface; per-command MCP opt-out for poor-fit verbs.
Q-33 drift-fixed: was already closed by D-73 (SSE only) but the index still
listed it open; re-confirmed SSE-only, stdio/WS not added.
Refines T-223 (cursor pull events) and T-225 (MCP reachable) — both now
unblocked and scoped. Index regenerated by pql decisions sync.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Captured during T-212. The install affordance and `make run` resolve the
dev-tree C client; on a dev machine `clide` on PATH should prefer the
properly-installed production build. Low priority, no user-facing breakage.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
A command-palette / `clide` CLI verb (`clide.installCli`) copies the
bundled C client into ~/.local/bin, VS Code "Install code command" style,
so a user who runs the app without `make install` can still reach the CLI
from a shell. On launch the app detects when `clide` is missing from PATH
or resolves to a stale symlink into the Flutter GUI bundle (the dogfood
footgun: a bare `clide` launched a second app instead of querying the
socket) and notifies with a pointer to the command. `make build` now ships
the C client inside the app bundle so the affordance can self-install from
it; `make run` points it at the dev-tree client via CLIDE_CLI_BIN.
Detection and the copy live in the Flutter-free CliInstaller
(kernel/src/cli_install.dart) so they run under unit tests without a real
install.
Closes epic T-209 (ship the clide CLI on PATH).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Persist the pql changelog: T-255 (animate the in-flight "running…"
indicator with rotating Claude-CLI-style status verbs), alongside the
other board edits already pending in the changelog (T-253, T-254, and
T-212/T-233 status changes).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
A live test of ui open diff surfaced that the workspace slot hardcoded
the Claude pane (primary = claude ?? active), so activating diff.view
flipped the registry but never rendered. Generalise _WorkspaceSlot: when
a non-Claude, non-editor workspace tab is the active one, reveal it in
the split region above Claude with a close affordance back to full-Claude
— so clide ui open diff actually shows the diff alongside the
conversation. Fixes the reveal for terminal/team-chat tabs too.
Closes T-233.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Adds diff as a fourth ui.open target. The diff extension now retains an
app-scoped DiffController and subscribes to its builtin.diff/selection
channel: a selection reveals the diff tab and focuses the file, which
the view scrolls into view and highlights. Retaining the controller in
the extension (not the view) lets a focus survive the tab being
revealed/remounted, mirroring the ReaderNav viewers.
Closes T-233.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The pql skill (installed by pql, shared across all repos) is the right
home for guidance about the .pql/changelog auto-commit, not this repo's
CLAUDE.md.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Shared guidance so agents on any machine stop narrating that a ticket
change leaves .pql/changelog uncommitted — a local-memory note only
helped this system.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Drives an image inline into the Claude conversation log over the same
bus-publish path as ui.toast/ui.open, keeping the dispatcher handler
Flutter-free. The card is display-only per D-78; the verb registers a
CommandSchema so it surfaces in clide capabilities for T-248 discovery.
Closes T-249.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Parity guarantees a verb exists for every UI action, but a verb is
unreachable if nothing advertises it. Add `clide capabilities` — it
reflects the live dispatcher registry to JSON (subsystem, verb, arg
schema) so the surface is discoverable and can't drift from what
dispatches. A thin /clide skill points Claude at it rather than
hard-coding a verb list, so new panels become reachable the moment
they register.
Co-Authored-By: Claude <noreply@anthropic.com>
setPermissionMode only wrote the control_request; the mode was never
folded back into the session status, so the badge and Ctrl/Cmd+M looked
dead. Optimistically merge + emit the new mode immediately; the next
system/init still reconciles.
Co-Authored-By: Claude <noreply@anthropic.com>
Completes the command-palette acceptance: the filter is now a
subsequence fuzzy match (was substring), and recently-invoked commands
float to the top and break score ties. The subsequence matcher is
extracted to a shared fuzzy helper so the palette and quick-open file
finder use one implementation instead of a private copy each.
Pinned commands and cross-session recency persistence are left as a
follow-up (they need a pin affordance + settings storage).
Co-Authored-By: Claude <noreply@anthropic.com>
The status-bar popover already handles quick theme switching, so a
separate theme-only modal was redundant. Repurpose it as a general
Settings surface whose first (currently only) section is Appearance:
base themes, sorted, with a High-contrast toggle for -hc siblings,
reusing the theme_families helpers shared with the popover.
Command id stays theme.pick (the welcome theme-link and tests
reference it); only the title and the view it opens change.
Co-Authored-By: Claude <noreply@anthropic.com>
Ticket was fixed and pushed earlier but left in_progress; persist the
done transition that only lived in the local pql.db.
Co-Authored-By: Claude <noreply@anthropic.com>
Persist three new tickets to the planning changelog:
- T-244: Claude pane shows no UI/status-bar progress while compacting (D-77)
- T-246: pane list omits the loaded subject; CLI can't tell which
ticket/decision/file a detail pane shows (D-6)
- T-247: clide CLI ignores CLIDE_SOCK and auto-discovers; stale sockets
orphaned in the runtime dir (D-6)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The drive-half complement to the toast system (D-6 parity, like ui.open):
`clide ui toast "msg" [--severity success|warning|error|info] [--duration MS]`
publishes a message on the kernel MessageBus 'toast' channel, which the
ToastService consumes — so a hosted Claude session or any script can surface
"done/failed" on the user's screen. The channel literal is kept in ui_command
(not imported from the kernel) so the daemon command stays Flutter-free.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Non-modal operation-feedback toasts, bottom-right: a ClideToast card per
severity (success/warning/error/info), auto-dismiss (errors linger), queue
with a visible cap, slide+fade in, manual dismiss, live-region a11y.
ToastService is a MessageBus consumer — components raise a toast by publishing
to the 'toast' channel (publishToast helper), so emitters stay decoupled from
the UI. GitController's push/pull are the first emitters. ToastOverlay mounts
in the app-root Stack.
Also adds comprehensive GitController coverage: importing it for the toast
emitter test first pulled the whole file into the coverage denominator, so the
controller is now tested end to end (status/stage/commit/stash/push/pull).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
T-122: WelcomeView "hangs when recents are non-empty" was not a render/marquee
bug — SettingsStore.set does real file I/O, and awaiting settings.set +
loadRecents inside a testWidgets body runs it in fake-async, trapping the
completion so the await never returns. Fix: seed via tester.runAsync. Un-skip
the welcome recents test; add render/sticky/open-recent coverage.
Coverage: new test/app_test.dart covers the app shell (RootLayout, slots,
rails, spines, editor split, hat bar, intents, keymap, project switcher +
dialogs); welcome recents + events/types fill the rest. Total 92.04% -> 95.13%.
Also fixes a real bug found en route: the recent-project row (welcome +
switcher) overflowed instead of ellipsizing a long path (T-122).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Record that this solo-dev repo lands routine work straight on main and
does not use a branch-first flow, so the generic assistant default of
branching before committing on the default branch does not apply here.
Co-Authored-By: Claude <noreply@anthropic.com>
The pre-D-15 plan snapshot is no longer read — planning state lives in
.pql/changelog/ and is replayed into pql.db on clone/merge. pql plan
import only touches this file behind --legacy, so it is dead weight.
Co-Authored-By: Claude <noreply@anthropic.com>
These five were stuck in_progress locally while the source machine had
already closed them, but that machine's close never reached the
git-tracked changelog (no done-transition in .pql/changelog/, all remotes
in sync) — likely a write-through/hook gap in its pql bookkeeping.
Closed here after confirming the work is genuinely complete: each
ticket's acceptance criteria were verified against the code and the
backing tests run green (130 passing across the vim preset, Claude
sidebar sub-tabs, and the reader back/forward, pin, and edit-pencil
suites).
Co-Authored-By: Claude <noreply@anthropic.com>
Per demo feedback on the T-234 status-bar popover: collapse the -hc
theme rows into a single 'High contrast' toggle at the top (applies the
chosen base theme's -hc sibling live, falling back to the base when none
exists); list base themes only, sorted by display name; widen 240->280
and ellipsize rows so 'Catppuccin Mocha' no longer wraps; swap the swatch
dot for the Phosphor palette icon; lowercase the bar label to match the
all-lowercase status bar (proper case kept in the a11y label).
New pure theme_families helpers (base/sibling/resolve), unit-tested.
Modal picker_view consistency + the status-bar right-alignment remain on
T-237.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
A heavy agent turn buried user/Claude prose under a wall of tool-call/
result rows. A pure grouping pass (activity_cluster.dart) folds runs of
consecutive meta items into clusters; the conversation view renders each
cluster as one collapsible activity card — collapsed by default with a
live one-line ticker of the latest step + a step count, click/Enter to
expand the steps in order. Sticky items (user messages, Claude prose,
and FAILED results) render first-class and seal the cluster.
Fold level is switchable (FoldLevel none/tools/thinking/everything);
default L1 folds tool calls+results while keeping diffs and thinking
first-class. The grouping logic is fully unit-tested; the card is
keyboard + screen-reader accessible. Persisting the level via a user
setting + control is the tracked follow-up T-235.
Closes T-230 (under T-132).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>