Now that the editor split actually opens (T-197), it exposed latent
issues, plus a coincidental Claude-session crash in the same log:
- T-203: the _EditorDragHandle's slider Semantics had value +
onIncrease/onDecrease but no increased/decreasedValue, so Flutter
asserted on every semantics flush — add them. And opening the split
reparented the Claude pane (direct child → Column/Expanded), tearing
down its SelectableRegion mid selection-update ('selectable not in
this registrar' / 'inactive element'); a stable GlobalKey on the
workspace primary makes Flutter move the element instead.
- T-202: rate_limit_event.resetsAt arrives as a unix-epoch number but
was cast `as String?`, throwing in the stream-json line parser. Accept
a num (epoch) or an ISO string.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1204 lines
74 KiB
Markdown
1204 lines
74 KiB
Markdown
# Changelog
|
||
|
||
All notable changes to clide are documented in this file.
|
||
|
||
The format follows [Keep a Changelog 1.1.0](https://keepachangelog.com/en/1.1.0/),
|
||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||
|
||
This changelog tracks the Flutter rebuild at the repo root. The Python
|
||
Textual implementation's changelog is preserved under
|
||
[`legacy/CHANGELOG.md`](legacy/CHANGELOG.md).
|
||
|
||
Versions are tracked in [`pubspec.yaml`](pubspec.yaml) under `version:`,
|
||
which is the single source of truth. Cutting a release means (a) moving
|
||
the entries below from `## [Unreleased]` under a new dated version
|
||
heading, and (b) bumping `pubspec.yaml` `version:` in the same commit.
|
||
|
||
## [Unreleased]
|
||
|
||
### Added
|
||
|
||
- Search-and-replace across the workspace: enter a replacement in the search
|
||
panel to preview each rewritten line, then Replace all (regex capture groups
|
||
supported). Guarded by a clean-git-tree gate — git is the undo — and a
|
||
confirmation. New `search.replace` command (preview + apply). (T-53)
|
||
- Find-in-files sidebar panel (Ctrl/Cmd+Shift+F): search the workspace with
|
||
regex and case toggles plus include/exclude globs; results stream in grouped
|
||
by file and clicking a match opens the editor at that line. (T-52)
|
||
- Workspace content-search engine with `search.grep` / `search.cancel` commands:
|
||
a pure-Dart, isolate-parallel grep (literal or regex, case + include/exclude
|
||
glob filters) that streams matches and honours the `ignore_files:` chain. The
|
||
engine is in-process — no ripgrep dependency (D-79). (T-52)
|
||
- `editor.open` accepts an optional 1-based `line` to position the initial
|
||
selection on open (backs find-in-files click-to-line). (T-52)
|
||
- Quick-open file finder (Ctrl/Cmd+P): a fuzzy file picker overlay over the
|
||
whole workspace, separate from the command palette. Empty query lists recent
|
||
files; Enter opens `.md` in the markdown reader and other files in the editor.
|
||
(T-51)
|
||
- Workspace ignore now follows the `ignore_files:` list in `.pql/config.yaml`
|
||
(ordered, later-wins, per D-4) instead of a hardcoded `.gitignore` +
|
||
`.clideignore` pair — the single ignore knob clide owns. (T-52)
|
||
- `files.walk` command — a recursive, ignore-pruned, capped flat file listing
|
||
of the workspace, backing quick-open and search. (T-51, T-52)
|
||
- Sidebar readers (markdown, decision, ticket) gain chrome: a pin/unpin toggle
|
||
before the title (separate from navigation), plus a right-hand navigator
|
||
(back, forward, jump-to-pin) and edit pencil. The ticket reader also joins the
|
||
shared retained nav. (T-189, T-190, T-191, T-198, T-199)
|
||
|
||
### Changed
|
||
|
||
- The pql search panel merged into the Search tab, which now has modes: Find
|
||
(content grep), Vault (pql ranked search), Query (PQL DSL), and Markdown (the
|
||
synced file listing). The standalone pql sidebar tab is gone; Backlinks stays
|
||
in the context panel. (T-201)
|
||
|
||
### Fixed
|
||
|
||
- Opening the editor split no longer floods exceptions: the resize handle's
|
||
slider semantics now carry increased/decreased values, and the Claude pane
|
||
keeps a stable identity across the reparent so its text-selection region
|
||
isn't torn down mid-update. (T-203)
|
||
- A `rate_limit_event` whose `resetsAt` is a numeric epoch no longer crashes the
|
||
Claude session — it was cast as a string. (T-202)
|
||
- Filter/search inputs show their hint as visible placeholder text, and the
|
||
search-glass icon is now optional — so the Search tab's Find fields (search,
|
||
replace, include/exclude globs) are distinguishable instead of four identical
|
||
empty boxes. (T-201)
|
||
- The sidebar icon rail no longer overflows when there are more tabs than fit:
|
||
it centers the icons when they fit and scrolls horizontally otherwise. (T-200)
|
||
- The editor pane now opens over the Claude pane when a file is opened — the
|
||
reader's edit pencil, a file-tree click, or a decision's edit all reveal the
|
||
editor tab now (it was contributed but never activated). (T-197)
|
||
- Clicking a decision opens it on the first click. The right-pane readers
|
||
(markdown + decisions) now share a retained back/forward nav history that
|
||
survives the tab switch, so the selection that reveals a reader is no longer
|
||
lost before the widget subscribes; back/forward re-emit through that history.
|
||
(T-196)
|
||
- The markdown reader can now open user-scope Claude config files (skills /
|
||
agents / commands under `~/.claude`), not just repo-local ones. `files.read`
|
||
gained a read allow-list covering the workspace plus the trusted Claude config
|
||
roots; writes stay repo-confined and off-root paths are still rejected. (T-195,
|
||
D-80)
|
||
- The markdown reader opens files given an absolute path again (e.g. a skill's
|
||
`SKILL.md` from the Claude Config tab). `resolveUnderRoot` no longer doubles an
|
||
absolute path onto the workspace root; absolute-under-root resolves, while
|
||
paths outside the root are still rejected. (T-194)
|
||
- The composer slash typeahead now lists clide-owned commands — `/resume` and
|
||
`/fork` (and `/clear`) surface even though the CLI probe doesn't advertise
|
||
them, unioned onto whatever command source the composer uses. (T-162)
|
||
- Clicking a decision opens it in the decision reader again — the decisions
|
||
extension no longer tears down and re-contributes its panel tab on every
|
||
selection; it activates a static tab and reveals the panel like the ticket
|
||
panel. (T-188)
|
||
- Clicking a markdown file opens it in the right-side markdown reader again —
|
||
the files panel, the Claude Config tab, and wiki `.md` links now publish to
|
||
the reader instead of the editor. (T-187)
|
||
- A forked Claude session now reports its real session id (captured from the
|
||
branch's `init` event) instead of the placeholder it was spawned with, so a
|
||
fork can itself be resumed/forked. (T-185)
|
||
- Claude replies now stream token-by-token. The `--include-partial-messages`
|
||
output arrives as `stream_event` deltas (not `assistant`+`partial:true` as
|
||
first assumed), so the previous handler never fired; the session now reads the
|
||
real shape, growing a placeholder in place and finalizing it from the matching
|
||
`assistant` event. (T-184)
|
||
- Claude conversation card actions (copy + custom) are now keyboard-focusable
|
||
and always reachable — revealed on hover or focus, activatable by Tab +
|
||
Enter/Space, with Semantics labels for assistive tech (T-174).
|
||
- Status bar no longer overflows when the focused-pane context line is long
|
||
— the in-pane slot now takes a flexible share of the bar and marquee-scrolls
|
||
within it instead of pushing the row past its width.
|
||
- Write/Edit permission cards no longer print the file path twice — the
|
||
description line is suppressed when it just repeats `file_path`.
|
||
- Resumed Claude session no longer starts with an empty pane — `claude
|
||
--resume` carries Claude's prior context but emits no past turns over
|
||
stream-json, so the orchestrator now seeds the conversation by reading
|
||
the tail (up to 256 KB) of the transcript JSONL on disk.
|
||
|
||
### Changed
|
||
|
||
- Claude conversation tool cards are now typed — Edit/Write render a diff,
|
||
Bash shows the command and its output, Read/Grep show the file/query, and
|
||
each tool result pairs back to its call to render the diff or error in
|
||
place instead of an indented JSON dump (T-168).
|
||
- Claude status line reflects live session state from stream-json events —
|
||
model, permission mode, context size, and turn cost come straight off the
|
||
init/result events rather than a separate config probe (T-168).
|
||
- Claude session persistence now rides on `claude --resume` instead of tmux
|
||
(T-167, amends D-41). A restart resumes the primary session, `/clear`
|
||
starts a fresh one, and `/resume` reopens a picked session — all without
|
||
tmux.
|
||
- Permission prompt cards render the tool input in the shape that fits the
|
||
tool — Bash shows the command as a shell code block (with a footer for
|
||
`run_in_background` / `timeout`), Write shows the path plus the content
|
||
highlighted from its extension, Edit shows the path plus before/after
|
||
blocks. Unknown tools fall back to the indented-JSON dump.
|
||
- Claude meta sidebar is now tabbed — Activity / Team / Config (T-182).
|
||
Activity shows usage stats plus the primary session's live runtime; Team
|
||
holds the roster and auto-fronts when a team spawns; Config shows the
|
||
environment settings table. Activity and Config share one table geometry so
|
||
switching doesn't jump.
|
||
|
||
### Removed
|
||
|
||
- tmux is no longer used for Claude sessions (T-167) — the tmux session
|
||
lifecycle and the tmux-polling team observer are gone, replaced by the
|
||
managed-session orchestrator. tmux is still used for the general-purpose
|
||
terminal pane.
|
||
|
||
### Added
|
||
|
||
- Claude team cockpit — the meta sidebar's Team tab gains live controls for
|
||
clide-managed agents: show/hide, mute, close, and inject-a-message per
|
||
roster row, plus a live shared task list with reassign. Each action has a
|
||
matching `clide` command (D-6 parity). (T-171, D-77)
|
||
- Per-agent permission-mode badge in the cockpit roster — click cycles the
|
||
safe trio default → acceptEdits → plan and sends `set_permission_mode` to
|
||
that session; Shift-click reaches `bypassPermissions` behind a confirm.
|
||
The badge reflects the live mode. (T-181, D-77)
|
||
- Fork a Claude conversation into a new pane — `/fork` (or a roster Fork
|
||
button / `clide.agent.fork`) branches a session via `--resume … --fork-session`,
|
||
opening an independent continuation that leaves the original untouched. (T-172, D-77)
|
||
- Team chat inbox — broker traffic renders as a chat timeline (colour-coded
|
||
sender chips), in a compact cockpit widget that pops out to a full pane. The
|
||
user is a first-class participant: post with `@name` routing (or broadcast),
|
||
with an interrupt tickbox that cancels the target's turn before delivery. (T-180, D-77)
|
||
- Config sidebar tab — a pinned settings table plus expandable, never-truncated
|
||
sections for skills / agents / commands / hooks / permissions (colour-coded by
|
||
kind) / MCP servers; file-backed entries open their `.md` in the reader. ClaudeConfig
|
||
now also surfaces agents, hooks, MCP servers, and file paths. (T-183, D-76)
|
||
- Team coordination broker (T-170, D-77) — clide hosts an in-process MCP
|
||
server (`clide-team`) for managed sessions over the stream-json control
|
||
channel, giving agents tools to message each other, broadcast, see the
|
||
roster, read an inbox, and share a task list. Each agent's role and the
|
||
roster are injected into its system prompt.
|
||
- Interrupt a running Claude turn (D-78) — Escape in the composer (when no
|
||
typeahead is open) or a Stop button shown while busy cancels the current
|
||
turn over the stream-json control channel. The escape hatch from a
|
||
runaway turn.
|
||
- Native permission & AskUserQuestion prompts (T-166, T-175, T-176, T-179,
|
||
D-78) — the composer becomes a prompt: Allow / Allow-and-don't-ask-again /
|
||
Deny showing the command, or an AskUserQuestion option picker (single or
|
||
stepped, with "Other" free-text and per-choice notes). Closes the tmux
|
||
prompt gap.
|
||
- Conversation message cards (T-173) — every turn in the Claude pane now
|
||
renders through one card template with a copy button on hover and a
|
||
collapse/expand caret for tool calls, results, and thinking.
|
||
- Collapsed-by-default tool cards (T-177) — multi-line tool calls and
|
||
results start collapsed behind a one-line summary; one-line output stays
|
||
inline so a caret never hides a single line.
|
||
- Prompted tool calls are quieter in the log (T-179) — a permission request
|
||
shows the command in the prompt, not as a raw tool-use card; once decided
|
||
it collapses to a one-line summary with a green (approved) or red (denied)
|
||
border, and the result is kept. AskUserQuestion's tool-use + result are
|
||
replaced by the logged answer.
|
||
- Harness-injected messages are de-emphasized (T-178) — skill loads,
|
||
slash-command expansions, and system reminders (Claude's `isSynthetic`
|
||
messages) render as a muted, collapsed "context" card instead of a blue
|
||
"you" message, since they weren't typed by the user.
|
||
- Claude meta sidebar (T-141, T-157) — an always-pickable left-panel tab
|
||
showing Claude activity (the latest day's messages/sessions/tool-calls
|
||
plus lifetime totals, from `stats-cache.json`) and, when a tmux team is
|
||
running, a roster of its members (colour · name · agent type · model)
|
||
with each member's live permission-mode and context once it's active.
|
||
- Claude session storage view (T-148) — the `claude.session-storage`
|
||
command opens a modal listing the workspace's session transcripts with
|
||
their on-disk sizes and a total, each removable with a two-click
|
||
confirm. User-driven only; clide never deletes transcripts on its own.
|
||
- Slash-command typeahead in the Claude composer (T-152) — typing `/`
|
||
(anywhere in the message, not just at the start) pops a list of
|
||
matching commands and skills sourced from the Claude environment;
|
||
arrow keys move, Enter/Tab completes, Escape dismisses.
|
||
- Claude environment service (T-151) — clide reads skills, commands,
|
||
settings, and permissions from `~/.claude` and the repo's `.claude`
|
||
(layered), and caches the slash-command list per claude version. Backs
|
||
the typeahead and command-aware send.
|
||
- Per-session status in the bottom status bar (T-145, T-150, T-154) — the
|
||
active Claude pane shows its model · permission mode (accept-edits /
|
||
plan / …) · context-token count · configured skills count, swapping to
|
||
the focused pane on tab switch and clearing on blur. Long status text
|
||
marquee-scrolls within the slot.
|
||
- tmux agent teams surface as native teammate tiles (T-139, T-140) —
|
||
when a Claude team is running, each teammate shows as a live
|
||
conversation tile beside the lead in a grid that wraps 1→2→3 columns,
|
||
with a resizable split. Identity and lifecycle come from the team
|
||
config; per-teammate content streams over the MessageBus.
|
||
- Native composer in the Claude pane (T-138) — type below the
|
||
conversation and press Enter to send (Shift+Enter for a newline).
|
||
Submits via the tmux server (bracketed paste + Enter), so input
|
||
reaches Claude even when no tmux client is attached; multi-line goes
|
||
as one message.
|
||
- File and image paste in the composer (T-138, T-142) — Ctrl/Cmd+V of a
|
||
copied file or clipboard image adds a removable chip (image thumbnail
|
||
or file icon) above the input; on send its `@path` is appended to the
|
||
message. Plain text pastes inline. Backed by a native `clide/clipboard`
|
||
channel (GTK + macOS).
|
||
- Claude pane renders natively from the transcript (T-137, D-75) — the
|
||
conversation shows as native cards (user / assistant markdown /
|
||
thinking / tool-use / result) instead of a terminal, with text
|
||
selection + copy across cards. Claude still runs in tmux; the terminal
|
||
builtin stays for general use.
|
||
- Multi-file editor tabs — the editor pane now shows one tab per open
|
||
buffer (filename + a dot when unsaved) via the shared tab strip;
|
||
opening a second file no longer replaces the first. Click a tab to
|
||
switch, × to close. Backed by the daemon's existing multi-buffer
|
||
model.
|
||
- Typed IPC command-schema framework (T-119/T-120, D-74) — commands
|
||
register an argument schema beside their handler; the dispatcher
|
||
normalises argv into named args, coerces types, and validates
|
||
(charset, leading-dash, ranges, caps) before the handler runs.
|
||
- `clide panel resize <slot>` CLI verb (T-119) — set an absolute size
|
||
with `--to` or nudge with `--by`; `editor` targets the split ratio.
|
||
Completes user/Claude parity (D-6) with T-111's keyboard resize.
|
||
- Unix-domain IPC socket server in the Flutter app (T-99 / T-124).
|
||
Per-workspace path (D-70: `$XDG_RUNTIME_DIR/clide/<hash>.sock` on
|
||
Linux, `~/Library/Caches/clide/<hash>.sock` on macOS). 0600 socket
|
||
+ 0700 parent (D-71). Multi-connection accept loop with serial
|
||
dispatch through `DaemonDispatcher` (D-72). Foundation for the C
|
||
`clide` client (T-126) and MCP (T-130). No client yet — testable
|
||
via `socat - UNIX-CONNECT:$SOCK`.
|
||
- argv→IpcRequest translator (`lib/src/cli/argv_to_request.dart`) —
|
||
parses `clide SUBSYSTEM VERB [pos...] [--flag] [-- passthrough]` and
|
||
the umbrella commands (`status`, `tail`, `version`, `ping`) per D-6
|
||
into the wire envelope. Pure Dart; lets the C client (T-126) stay a
|
||
dumb pipe (T-99 / T-125).
|
||
- `DaemonClient.reconnectAt(newPath)` — swap an active client onto a
|
||
different socket without restart (project switch in T-127).
|
||
- Event streaming over the IPC socket (T-99 / T-129) — `clide tail
|
||
--events [--filter X]` opens a long-lived subscription, replays up
|
||
to 16 recent matching events per subsystem (D-6), and streams new
|
||
ones as JSON lines. C client loops on `data.streaming` ack. Slow /
|
||
broken subscribers drop themselves without blocking the bus.
|
||
- MCP server over HTTP+SSE (T-99 / T-130, per D-68 / D-73). Localhost
|
||
HTTP listener advertises via `$HOME/.claude/ide/<pid>.lock` so
|
||
Claude Code's `/ide` discovers it. JSON-RPC 2.0 with the two
|
||
minimum `/ide` tools shipped as stubs
|
||
(`mcp__ide__getDiagnostics`, `mcp__ide__executeCode`); real
|
||
implementations follow.
|
||
- C `clide` shell client at `native/clide-cli/clide.c`. Walks CWD up
|
||
to the git root, hashes to the per-workspace socket (D-70), ships
|
||
argv. `make clide-cli` builds it; on PATH, `clide status` works
|
||
from any clide-workspace directory once the app is up (T-99,
|
||
T-126).
|
||
- Startup project picker — clide now opens to the welcome screen by
|
||
default instead of auto-opening the last project. A per-row
|
||
"always open this project on launch" checkbox in welcome's RECENT
|
||
list sets a sticky-startup flag; if exactly one project has it,
|
||
that one opens directly. Two or more, or none ⇒ picker (T-115).
|
||
- CONTRIBUTING.md "Running clide from the shell" section — documents
|
||
the shell verbs, exit-code contract per D-68, and Claude Code
|
||
`/ide` MCP discovery via `~/.claude/ide/<pid>.lock` (T-131).
|
||
|
||
### Changed
|
||
|
||
- The empty Claude pane now shows a native startup banner — clide logo,
|
||
session role, workspace, and tmux status — instead of a bare "Waiting
|
||
for Claude…" (T-149).
|
||
- User and Claude turns in the conversation now render as distinct
|
||
accent-striped cards over a filled background — your prompts in the
|
||
theme focus colour, Claude's replies in Claude's brand orange
|
||
(T-143, T-144).
|
||
- Claude conversation content now flows through the kernel MessageBus —
|
||
a reader tails the transcript and publishes items; the pane subscribes.
|
||
Decouples reading from rendering so the upcoming team panels can show
|
||
one lead plus a tile per teammate (T-137).
|
||
- In-process IPC dispatch swapped for socket loopback (T-127). The
|
||
Flutter UI's `DaemonClient` now talks to its own `IpcServer` over
|
||
the same per-workspace Unix socket the C `clide` client uses — one
|
||
transport, one contract.
|
||
- D-56 / D-68 amended with implementation notes — both decisions now
|
||
link out to T-99's eight slices (T-124–T-131) and the D-70/71/72/73
|
||
records they spawned (T-131).
|
||
|
||
### Deprecated
|
||
|
||
### Removed
|
||
|
||
- `lib/kernel/src/ipc/in_process.dart` (`InProcessClient`) — replaced
|
||
by the socket-loopback `DaemonClient` (T-127).
|
||
- `lib/kernel/src/backend.dart`, `lib/kernel/src/backend_entry.dart`,
|
||
`lib/kernel/src/ipc/isolate_client.dart` — the third unused IPC
|
||
path (a backend-isolate model that was never wired through). Only
|
||
the socket model survives now (T-128).
|
||
|
||
### Fixed
|
||
|
||
- Claude pane is no longer dead-on-arrival when resuming a session (T-161).
|
||
The primary pane (and `/resume`) relaunched Claude with `--session-id
|
||
<existing-id>`, which Claude rejects as "already in use" — so the pane had
|
||
no live backend and typed input vanished. clide now uses `--resume` for an
|
||
existing session and `--session-id` only for a brand-new one.
|
||
- Claude pane no longer floods the console with "markNeedsBuild called
|
||
during build" (T-159) — a focused pane surfacing its status-bar widget
|
||
now defers the notification out of the build phase instead of rebuilding
|
||
the status item mid-build.
|
||
- The git / tickets / decisions / pql / problems tabs no longer log
|
||
`i18n: namespace not registered` on boot (T-155). An extension's
|
||
localized tab title is now loaded automatically on activation, and the
|
||
five missing catalogs were added.
|
||
- Slash commands sent from the Claude composer now actually run (T-153).
|
||
Recognised commands are delivered as typed input so Claude's TUI parses
|
||
them; other input (and stray leading slashes like a `/tmp` path) stays
|
||
bracketed-pasted as literal text.
|
||
- `/clear` is now handled by clide — it resets the Claude pane to a fresh,
|
||
empty session — instead of being forwarded to Claude Code, whose `/clear`
|
||
forked to a new session clide couldn't follow and left the pane
|
||
unresponsive (T-156).
|
||
- `/resume` is now handled by clide too (T-156): it opens a picker of the
|
||
workspace's past sessions — each labelled by its first … last user message
|
||
and when it was last active — and re-binds the pane to the chosen one,
|
||
instead of forwarding Claude Code's session-forking `/resume`.
|
||
- Claude secondary panes no longer flash a false "session exited" while
|
||
the session is alive (a transient tmux client exit is now verified
|
||
against the live session), and the tab and banner agree on the label
|
||
("session N") (T-149).
|
||
- Claude pane no longer gets stuck on "Waiting for Claude…" when its
|
||
session can't be bound (T-147) — e.g. a session left over from before
|
||
session-id binding, or a fresh machine. It now retires that stale
|
||
clide session and starts a clean one. Only clide's own `-L clide`
|
||
sessions are touched (never a terminal Claude, never transcript files).
|
||
- Secondary Claude tabs showed the primary's conversation instead of
|
||
their own (T-146). Each pane now binds to its own session via
|
||
`claude --session-id`, so concurrent sessions in one workspace stop
|
||
colliding on the newest transcript — the primary keeps a stable id
|
||
(resumes), secondaries get a fresh one (clean session).
|
||
- Claude pane no longer freezes the app on open — the transcript reader
|
||
caps its initial read to the recent tail, parses off the UI isolate,
|
||
and coalesces view notifications into one rebuild per burst (T-137).
|
||
- Daemon-not-connected on startup — panels and the Claude pane raced
|
||
the socket loopback. Requests now wait briefly for an in-flight
|
||
connection, the server isn't restarted for the same workspace, and
|
||
the client connects once instead of twice.
|
||
|
||
### Security
|
||
|
||
## [2.1.0] — 2026-05-18
|
||
|
||
### Added
|
||
|
||
- Contrast gate split — baseline `canonicalPairs` every theme passes,
|
||
strict `extendedPairs` (muted/status/syntax/focus-border) gated to
|
||
`-hc` / `-cb` variants. Ships `clide-hc`, `midnight-hc`, `paper-hc`,
|
||
`terminal-hc` siblings of the named themes (D-69, T-114, T-118).
|
||
- Pre-push coverage gate — `make push-check` runs `ci/coverage_gate.sh`,
|
||
which fails if total line coverage drops below `coverage_floor:` in
|
||
`pubspec.yaml`. Floor ratchets up only; target 95% (D-66).
|
||
- Pre-push changelog gate — `ci/changelog_gate.sh` fails on any
|
||
`## [Unreleased]` bullet over 60 words. Enforces the Keep-a-Changelog
|
||
conciseness rule in the git-commit skill.
|
||
- Keymap layer (`KeymapService`) — typed Intents, YAML presets,
|
||
VS-Code-style when-clauses, layered preset → user file → settings
|
||
overlay. Default preset ships; vim/vscode/jetbrains unblocked
|
||
(T-117, supersedes T-110).
|
||
- Keyboard operability — `ClideTappable` is now Tab-focusable with a
|
||
focus ring and Enter/Space activation; `ClidePalette` adds arrow
|
||
nav, Escape dismiss, and selection highlight (T-100).
|
||
- Panel-to-panel focus traversal — each `SlotHost` wraps in a
|
||
`FocusScope` + `FocusTraversalGroup`; `F6` / `Shift+F6` cycle
|
||
sidebar → workspace → context. `FocusTracker` integrates with
|
||
Flutter focus rather than paralleling it (T-105).
|
||
- Event-driven test waits — PTY + watcher tests await stream events
|
||
instead of fixed sleeps; `onTimeout` callbacks now `fail()` loudly
|
||
with diagnostic context. `RecordingEventSink` exposes a broadcast
|
||
stream for the same pattern (T-108).
|
||
- Code-quality cleanups — `TreeSitterLib` exposes a last-error
|
||
diagnostic instead of swallowing dlopen failures; `ExtensionManager`
|
||
surfaces a `failedExtensions` map for UI degradation; PTY constants
|
||
consolidated in `libc.dart` + `PosixErrno`; `test_app.dart` gated
|
||
behind `kDebugMode` (T-112).
|
||
- Test sweep — `keybindings`, `toolchain_paths`, and several
|
||
`widgets/src/` primitives (tooltip, palette, multitab, markdown).
|
||
- `tree_sitter_service` sweep — fake-FFI + real-library smoke,
|
||
17% → 96%. Crosses the 95% global target (T-91).
|
||
- Staged `dart doc` CI job — generates and uploads an HTML API
|
||
reference for the public `lib/` surface. The step wraps
|
||
`dart doc --validate-links` and grep-fails the build on any warning.
|
||
Inert with the rest of the workflow until Gitea Actions activates.
|
||
- Mouse wheel scrolling in Claude pane — converts scroll events to
|
||
PgUp/PgDown so TUI apps scroll their history naturally.
|
||
- Welcome screen Tips card — six common keybindings shown below the
|
||
START / RECENT row when the viewport is tall enough.
|
||
- `MultitabPane` widget + `MultitabController` for panes that host
|
||
N runtime tab instances of the same kind. Generic over a payload
|
||
type, supports pinned/non-closeable tabs, drag-reorder, close × on
|
||
hover, and an optional `+` add button.
|
||
- `MultitabPane.keepAlive` mode — entry bodies stay mounted via
|
||
IndexedStack so switching tabs preserves their state (PTY
|
||
connections, scroll position, etc.).
|
||
- `CONTRIBUTING.md` — human-addressed contributor guide covering
|
||
clone / build / test / DQR / tickets / commit conventions. The
|
||
`[Unreleased]` section is reorganised to one subsection per kind
|
||
per Keep a Changelog 1.1.0 (T-109).
|
||
- `make verify` — no-tests sweep (analyze + format + decisions +
|
||
changelog gate). For mid-edit checks; `make push-check` stays the
|
||
full pre-push pipeline.
|
||
|
||
### Changed
|
||
|
||
- Terminal mouse wheel forwards as proper xterm wheel-button escapes
|
||
when the inner program declares a mouse mode (?1000h / ?1002h /
|
||
?1003h, optionally +?1006h SGR). Falls back to PgUp/PgDown only
|
||
when no mouse mode is active. vim mouse=a / htop / less mouse modes
|
||
now react to the wheel (T-74).
|
||
- `lib/src/terminal/` cleaned to the project bar — commented-out
|
||
`print()` debugging stubs stripped from `custom_text_edit.dart`,
|
||
stale TODOs in `parser.dart` + `keytab.dart` replaced with clear
|
||
"not implemented" notes (G2/G3 charsets, VT52 records), and the
|
||
one `// ignore: invalid_use_of_protected_member` in
|
||
`terminal_view.dart` gets an inline reason explaining why
|
||
TerminalView owns its own ShortcutManager. Parser split deferred
|
||
to T-123 (T-107).
|
||
- Window-control close-button red, white close glyph, and palette
|
||
ambient shadow are now tokens (`windowControl.closeHover*`,
|
||
`shadow.ambient`) instead of hard-coded hex. Light themes get a
|
||
softer ink-tinted shadow (T-114).
|
||
- Text-zoom (Ctrl +/-/0) is now a kernel `TextZoom` service and shows
|
||
up in the palette as `View: Zoom In/Out/Reset Zoom` (T-114).
|
||
- `make gen-build-info` bakes `lib/src/build_info.g.dart` (name,
|
||
tagline, version, repository, commit, date) and rewrites
|
||
`assets/licenses.yaml` `self.version:` from `pubspec.yaml` on every
|
||
build/run/test target. Welcome banner / status line / window title
|
||
/ project switcher labels all read from those constants — one
|
||
source of truth, no manual sync, no `--dart-define` plumbing.
|
||
New `tagline:` field in pubspec for the short user-facing line
|
||
(welcome subtitle, future web meta).
|
||
- Panel splitters (sidebar / context / editor-split) are tab-focusable;
|
||
arrow keys nudge by 10 px, Shift+arrow by 50 px (2% / 10% for the
|
||
editor split). Exposed as slider Semantics nodes so screen readers
|
||
announce the current size. CLI verb deferred to T-99 (T-111).
|
||
- Changelog gate is binary — dropped the soft 40-word warning, kept
|
||
the 60-word hard cap. Warnings that never blocked just normalised
|
||
drift.
|
||
- PTY spawning uses `posix_openpt` + `posix_spawn` instead of
|
||
`forkpty` — closes a ~5% deadlock window in the multithreaded Dart
|
||
VM (T-96, D-5 amended). Missing exe/cwd now throw `PtyException` at
|
||
spawn time. Drops the `libutil.so.1` dependency.
|
||
- Coverage floor ratcheted to 95% — D-66 target hit.
|
||
- `TreeSitterService` and `TreeSitterLib` accept injectable FFI + asset
|
||
loaders for fake-driven tests; production paths unchanged.
|
||
- Tidied test imports flagged by `unnecessary_import`.
|
||
- `README.md` rewritten to match current architecture;
|
||
`docs/initial-plan.md` bannered as historical; new
|
||
`docs/architecture.md` describes today's shape (T-101).
|
||
- `SchedulerService._stopTicker` now awaits the in-flight isolate spawn
|
||
before killing — closes the same race shape we fixed in PTY (T-106).
|
||
- `make push-check-full` added — runs `push-check` plus integration +
|
||
smoke for pre-release checks. Integration tests skip the hanging
|
||
theme_picker case until that's fixed (T-103, T-116).
|
||
- Governance bookkeeping: D-66 amended (floor at `coverage_floor:` in
|
||
`pubspec.yaml`); `licenses.yaml` reconciled with `pubspec.yaml`;
|
||
Q-1/Q-2/Q-3/Q-25 triaged; `.claude/skills/README.md` inventory
|
||
added; `--no-fatal-infos` dropped from `ci/test.sh` (T-113).
|
||
- Terminal panes render bold attributes with a real bold weight —
|
||
bundled JetBrainsMono Bold + BoldItalic registered with the
|
||
`JetBrainsMono` family at `weight: 700`. The painter's bold
|
||
suppression workaround is gone.
|
||
- Claude pane uses `MultitabPane` for primary + secondaries — drops
|
||
~100 lines of bespoke tab-strip code, gains drag-to-reorder.
|
||
- UI spacing constants live in `lib/widgets/src/spacing.dart` —
|
||
`clideInset*` for paddings, `clideGap*` for sibling distances,
|
||
`clideIcon*` / `clideControlHeight` for control sizes.
|
||
- Tagline reads "IDE for Claude Code CLI" everywhere (welcome
|
||
subtitle, README, CLAUDE.md, pubspec, web manifest, CLI banner).
|
||
- Inline terminal emulator based on xterm.dart v4.0.0 — replaces the
|
||
pub.dev dependency with owned code under `lib/src/terminal/`. Drops
|
||
three transitive dependencies (xterm, quiver, zmodem).
|
||
- Bundle clide-specific tmux.conf for Claude pane sessions: no status
|
||
bar, 50k scrollback, mouse on, zero escape delay, isolated socket.
|
||
- Claude pane spawns `claude` directly inside tmux with
|
||
`CLAUDE_CODE_NO_FLICKER=1` to enable Claude's fullscreen TUI mode.
|
||
- PTY read buffer increased from 4 KB to 64 KB.
|
||
- Terminal view 2 px padding on all sides.
|
||
|
||
### Removed
|
||
|
||
- **`bin/clide.dart` + `DaemonServer`** — completing the D-56
|
||
dissolution. The separate daemon process was dissolved on 2026-04-23
|
||
but the entry point and socket server class were never deleted.
|
||
Gone now, along with orphaned tests, stale i18n strings, and
|
||
"start `clide --daemon`" error messages.
|
||
- **`ptyc/` source tree + `PtySession` + `scm_rights.dart`** — PTY
|
||
spawning migrated to Dart FFI `forkpty()` (`NativePty`) but the old
|
||
C helper and its Dart wiring were never cleaned up. Removed from
|
||
toolchain resolution, `ToolCheck` gate, backend serialization,
|
||
testmode harness, CI scripts, Makefile, and sandbox entitlements.
|
||
D-5 amended to record the retirement.
|
||
- CI golden images (`test/goldens/goldens/ci/`) — Skia anti-aliasing
|
||
of geometric shapes differs between macOS and Linux even with the
|
||
Ahem font. Replaced with platform-keyed goldens (`goldens/linux/`,
|
||
`goldens/macos/`).
|
||
- Bold JetBrains Mono font registration that prevented glyph-width
|
||
mismatch in terminal rendering — superseded by the Bold/BoldItalic
|
||
re-registration above.
|
||
|
||
### Fixed
|
||
|
||
- Welcome status line no longer overflows on narrow viewports —
|
||
whole-row `FittedBox(scaleDown)` instead of fixed sibling widths.
|
||
Inline `fontSize:` literals replaced with the typography
|
||
constants. Version label reads `clideVersion` so the status line
|
||
stays in sync with `pubspec.yaml` (T-116).
|
||
- Integration test `theme_picker_test.dart` no longer deadlocks —
|
||
was `await`ing `services.commands.execute('theme.pick')` whose
|
||
Future doesn't complete until the dialog is dismissed. Now
|
||
fire-and-forget around `pumpAndSettle` (T-116).
|
||
- `TerminalView.onTapUp` now actually fires on primary tap — was
|
||
wired to a dead code path (T-93). Dead `onTapUp` surface on
|
||
`TerminalGestureHandler` / `TerminalGestureDetector` removed.
|
||
- `BufferLine.eraseRange` no longer panics when called with `end == 0`.
|
||
Real trigger: `Terminal.eraseDisplayAbove` with the cursor at
|
||
column 0 — common after `ESC[H\x1b[1J` (home + erase-above).
|
||
- Terminal selections no longer vanish when resizing narrower —
|
||
reflow's tail-anchor handler left anchors detached past the
|
||
trimmed range. Common triggers: Ctrl+A then resize, drag past a
|
||
partially-filled line (T-92).
|
||
- `BufferLine.removeCells` / `insertCells` / `dispose` no longer skip
|
||
anchors due to concurrent list modification during iteration —
|
||
iteration now snapshots the list first (T-91).
|
||
- Closing a secondary Claude pane tab now kills its tmux session on
|
||
the clide socket, honouring D-41's lifecycle. Previously
|
||
`pane.close` only killed the ptyc-spawned tmux client.
|
||
- Cold-start reap: every clide launch kills any leftover secondary
|
||
tmux sessions for the current repo before spawning new ones, so
|
||
D-41's "secondary numbering resets between runs" holds.
|
||
- `claude.kill-all-sessions` command now actually kills the
|
||
server-side tmux sessions for the repo, not just the panes.
|
||
- Terminal cell grid no longer drifts on bold text — bold rendering
|
||
is suppressed at the painter level since synthetic bold (with no
|
||
Bold.ttf registered) shifts glyph advance widths.
|
||
- PTY surfaces errno on `forkpty` / `write` / `ioctl` failures
|
||
instead of swallowing. `execve` failures write a diagnostic to the
|
||
slave before `_exit`. `NativePty.write` and `PtySession.write`
|
||
loop on short writes; both throw `PtyException` on hard errors.
|
||
- PTY teardown order fixed — kill child first so the master fd
|
||
returns EOF, await reader isolate exit, then close the fd.
|
||
- Reader isolate spawn errors in `NativePty` / `PtySession` are now
|
||
surfaced via the output stream instead of silently dropped.
|
||
`_recvFdAsync` no longer leaks the `ReceivePort` on spawn throw.
|
||
- IPC server hardening: per-request 60s timeout (configurable),
|
||
broadcast/response write failures logged instead of swallowed,
|
||
client dropped on response-write failure, and the stale-socket
|
||
retry now probes for a live daemon before unlinking the socket.
|
||
- `pane.spawn` and `editor.open` map POSIX errno values to actionable
|
||
IPC error kinds (ENOENT → `not_found`, EACCES/EPERM → `user_error`,
|
||
EISDIR/ENOTDIR/EEXIST → distinct kinds, EMFILE/ENFILE →
|
||
`tool_error` with an fd-limit hint).
|
||
|
||
### Security
|
||
|
||
- IPC: `git.checkout`, `git.push` reject branch/remote args starting
|
||
with `-` (closes the `--upload-pack=...` argv-injection vector).
|
||
`files.read` rejects files over 10 MB. `git.log` caps `count` at
|
||
1000; `git.diff` / `git.stage` cap paths at 256 (T-104).
|
||
- Toolchain no longer resolves the dugite git binary against the open
|
||
workspace — a malicious repo could plant `native/dugite/bin/git`
|
||
and clide would run it on auto-fired `git.status`. Dugite now
|
||
resolves against the install dir + `CLIDE_DUGITE_DIR` env override
|
||
only (T-98).
|
||
- `files.read` and `files.ls` reject symlinks whose targets live
|
||
outside the workspace — closes a path-safety bypass via in-repo
|
||
symlinks (T-102).
|
||
- `files.read` and `files.ls` reject paths that resolve outside the
|
||
workspace root. Previously a relative path containing `..` could
|
||
read arbitrary files via path traversal.
|
||
|
||
## [2.0.0] — 2026-05-03
|
||
|
||
### Fixed
|
||
|
||
- PTY FFI constants now platform-dispatched: `TIOCSWINSZ` (`0x80087467`
|
||
macOS / `0x5414` Linux), `O_NONBLOCK` (`0x0004` / `0x0800`), and
|
||
`MsghdrDarwin` struct with correct 4-byte field widths for macOS
|
||
`recvmsg()`.
|
||
|
||
- App settings directory uses `~/Library/Application Support/clide` on
|
||
macOS instead of `~/.config/clide`.
|
||
|
||
- Removed hardcoded `TERMINFO=/usr/share/terminfo` from pane spawn
|
||
environment — let the system resolve terminfo per platform.
|
||
|
||
- Panel `tabsFor()` now sorts by contribution priority when no user
|
||
order is set.
|
||
|
||
### Changed
|
||
|
||
- Canonical upstream moved from Gitea to GitHub
|
||
(`github.com/postmeridiem/clide`).
|
||
|
||
- README rewritten to reflect current single-process Flutter
|
||
architecture, built-in extensions, and build commands.
|
||
|
||
- Renamed desktop binary from `clide_app` to `clide` (Linux + macOS).
|
||
|
||
- macOS app icon uses the black-circle variant matching the Linux
|
||
desktop icon.
|
||
|
||
- ClideTestApp expanded to three test categories (toolchain, ipc,
|
||
extensions) with JSON summary, non-zero exit on failure, and
|
||
`make run-testmode TESTMODE_CATEGORY=<cat>` for selective runs.
|
||
|
||
### Added
|
||
|
||
- `make install` / `make uninstall` — builds the release bundle and
|
||
installs it to `~/.local/` with XDG desktop entry, icon registration
|
||
at seven sizes, and icon cache refresh. macOS installs to
|
||
`~/Applications/clide.app`.
|
||
|
||
- Backend isolate — all subprocess and file I/O runs in a dedicated
|
||
isolate, keeping the merged UI/platform thread on macOS free for
|
||
rendering. Communicates via SendPort using the existing IPC protocol.
|
||
Two-phase boot: resolve toolchain on spawn, initialize services on
|
||
project open. Scheduler ticker only runs while a project is active.
|
||
|
||
- Toolchain — centralized binary resolution replacing five ad-hoc
|
||
mechanisms. Resolves git, pql, tmux, ptyc, shell once at boot via
|
||
background isolate. Status bar reads `toolchain.missing` directly.
|
||
|
||
- GitClient — typed Dart API wrapping all git operations. Every
|
||
subprocess call goes through `_run()` with toolchain-resolved path
|
||
and environment. Replaces scattered `Process.run('git', ...)` calls.
|
||
|
||
- Native directory picker — macOS NSOpenPanel via method channel in
|
||
AppDelegate, GTK file chooser on Linux. Falls back to text-input
|
||
dialog on web. Shows "No git repo found" dialog on invalid selection.
|
||
|
||
- macOS desktop target — OS-detecting Makefile (`make run` works on
|
||
macOS/Linux/Windows), 1280x720 default window, squared app icons,
|
||
sandbox entitlements with SBPL exceptions, `_DARWIN_C_SOURCE` for
|
||
ptyc compilation, native traffic dots skipped (macOS titlebar owns
|
||
them), expanded PATH for Homebrew and `~/.local/bin` on GUI apps.
|
||
|
||
- Shared ClideFilterBox widget with search icon, clear button, and
|
||
debounced input. Applied consistently across all sidebar panes:
|
||
Files (path filter with flat results), Git (filter staged/unstaged
|
||
by path), Decisions (filter by ID/title/domain), Tickets (filter
|
||
by ID/title/status), Problems (filter by source/message), and
|
||
pql Query (replaces custom input).
|
||
|
||
- Interaction model from Wireframe Flows v3: eight new D-records
|
||
(D-47 through D-54) and five Q-records (Q-26 through Q-30)
|
||
codifying layout invariants, chrome budget, editor mode, context
|
||
auto-behavior, collapse spine, focus mode, state persistence, and
|
||
the canonical keyboard map.
|
||
|
||
- Panel collapse spine — collapsed side panels render as a 12px
|
||
vertical spine with rotated label, hover highlight, and badge dot
|
||
for pending context (D-51, T-30).
|
||
|
||
- Focus mode — `Ctrl+.` takes the active panel full-window;
|
||
`Escape` restores the prior layout with collapse states and
|
||
divider positions intact (D-52, T-31).
|
||
|
||
- Canonical keyboard shortcuts from the interaction model: collapse
|
||
toggles (`Ctrl+Shift+1/3`), panel focus (`Ctrl+1/2/3`), sidebar
|
||
section switching (`Alt+1–5`), focus mode, and `Escape` dismiss
|
||
(D-54, T-33).
|
||
|
||
- Right panel (context) icon rail — bottom section switcher matching
|
||
the left sidebar rail pattern (D-47, T-34).
|
||
|
||
- Editor-above-Claude mode — `Ctrl+E` opens the editor as a split
|
||
above Claude in the middle column with a draggable divider;
|
||
`Ctrl+W` or `Escape` closes it. Prompt bar Y stays fixed
|
||
(D-49, T-35).
|
||
|
||
- Layout state persists across sessions — collapse state, sidebar
|
||
and context panel sizes, active sections, and editor split ratio
|
||
saved to `.clide/settings.yaml` (D-53, T-32).
|
||
|
||
- Phosphor Icons font (v2.0.8, MIT) — regular, bold, and fill
|
||
weights. Replaces hand-painted CustomPaint icons in sidebar and
|
||
context panel icon rails.
|
||
|
||
- Decisions panel in sidebar — lists confirmed D-records from
|
||
`pql decisions list` with ID and title (T-37).
|
||
|
||
- Tickets panel in sidebar — lists tickets from `pql ticket list`
|
||
with status dot color-coded by state (T-37).
|
||
|
||
- Markdown viewer in context panel — shows raw content of the
|
||
active .md file, auto-updating on buffer switch (T-38).
|
||
|
||
- Clickable DQRT record links in markdown — `[D-56]`, `[T-43]` etc.
|
||
rendered as tappable links that navigate to the decision or ticket
|
||
detail pane via the message bus.
|
||
|
||
- Ctrl+Plus / Ctrl+Minus / Ctrl+0 text zoom (5% steps, 60%–200%
|
||
range) via `MediaQuery.textScaler`. Resets on app restart.
|
||
|
||
- Sidebar focus indicators — selecting a ticket or decision
|
||
highlights the active card in the sidebar list, auto-expands the
|
||
accordion section if collapsed, and scrolls the card into view.
|
||
|
||
- Typography scale constants `clideFontSmall` (12) and
|
||
`clideFontBadge` (11) for sidebar metadata and status badges.
|
||
`clideLineHeight` (1.25) applied app-wide via `DefaultTextStyle`.
|
||
|
||
- `files.read` IPC command for reading file content by path.
|
||
|
||
- pql sidebar restructured: Search tab is the default left tab with
|
||
ranked text search (debounced, scored results with score bar) and
|
||
a DSL toggle for raw PQL query mode; Markdown tab (filtered to
|
||
`.md` files) on the right. Clicking a result opens it in the
|
||
context panel markdown viewer with bidirectional focus highlighting.
|
||
|
||
- Kernel scheduler service with tiered timers (1min, 10min, 15min,
|
||
1hr, midnight) running on a background isolate. Emits `SchedulerTick`
|
||
events on the `DaemonBus`. Extensions subscribe by tier (T-61).
|
||
|
||
- Auto-refresh for sidebar panels: decisions refresh on file changes
|
||
to `decisions/*.md` and on 1-minute scheduler tick; tickets refresh
|
||
on 1-minute tick and on status change events (T-62).
|
||
|
||
- Manual refresh button (arrowClockwise icon) in decisions, tickets,
|
||
and pql markdown panels (T-63).
|
||
|
||
- `ClideAccordion` shared widget — extracted from tickets and
|
||
decisions views. Supports optional `leading` widget (color dot).
|
||
Pin/focus accordion logic: manually toggled sections are pinned;
|
||
the focused item's section auto-opens; unpinned sections without
|
||
focus auto-collapse.
|
||
|
||
- Ticket status buttons wired to `pql ticket status` — clicking a
|
||
status in the detail view transitions the ticket, refreshes the
|
||
sidebar list, and scrolls the ticket into its new section.
|
||
|
||
- `pql.tickets.status` IPC command accepting a list of IDs for
|
||
batch status transitions.
|
||
|
||
- Ticket sidebar sections split into individual statuses: IN
|
||
PROGRESS, REVIEW, READY, BACKLOG, DONE, CANCELLED (was four
|
||
coarse groups).
|
||
|
||
- Phosphor Icons codepoint reference CSV at
|
||
`assets/fonts/phosphor/codepoints.csv` — full mapping of all
|
||
1512 icon glyphs to kebab-case and PascalCase names.
|
||
|
||
- Graph view in context panel — lists files with inbound/outbound
|
||
link counts from `pql search --connections` (T-39).
|
||
|
||
- Welcome screen redesigned as full-screen overlay with two-column
|
||
layout: START actions (open folder, clone, Claude session) with
|
||
keyboard shortcuts, and RECENT projects list showing path, branch,
|
||
and relative timestamps. Status line shows version, daemon
|
||
connection, and active theme.
|
||
|
||
- Recent projects history persisted to user settings (up to 10
|
||
entries with path, branch, and last-opened timestamp). Last
|
||
project auto-restored on boot; falls back to cwd, then welcome.
|
||
|
||
### Changed
|
||
|
||
- Workspace renders Claude as the always-visible primary surface
|
||
instead of showing a tab bar (D-47, D-48). The editor is a
|
||
split overlay, not a tab.
|
||
|
||
- Syntax highlighting via tree-sitter (dart:ffi to vendored
|
||
libtree-sitter.so with embedded wasmtime). 48 grammar WASM files,
|
||
48 highlight queries. Colors map to theme syntax tokens.
|
||
|
||
- ClideMarkdown renderer — inline grouping for tight list items,
|
||
proper HTML entity unescaping after AST parse, Josefin Sans Light
|
||
with 1.25 line height, 16px body text. Inline code sized to
|
||
`clideFontMono` to match surrounding text weight.
|
||
|
||
- Default sidebar and context panel widths widened to 400px and
|
||
420px respectively (previous maximums). Context panel max raised
|
||
to 1000px.
|
||
|
||
- Ticket detail loading uses `pql ticket show --with-context` for
|
||
a single-call fetch of ancestors, decisions, and children.
|
||
Replaces N+1 parent-chain walk. `--with-decision` and
|
||
`--with-children` flags consolidated into `--with-context`.
|
||
|
||
- Ticket descriptions render through ClideMarkdown instead of plain
|
||
text, with clickable DQRT record links.
|
||
|
||
- Decision detail view subscribes to the message bus for navigation
|
||
(same pattern as tickets), enabling navigation from any source.
|
||
|
||
- TreeSitterService is now a shared singleton — eliminates native
|
||
double-free crashes from multiple WASM engine instances.
|
||
|
||
- Code block syntax highlighting fixes overlapping tree-sitter spans
|
||
that caused duplicated text (e.g. `makemake` instead of `make`).
|
||
|
||
- Context panel drag resize fixed — dragging left now correctly
|
||
grows the right panel instead of shrinking it.
|
||
|
||
- POLICY.md — project-wide rules for runtime behavior, dependency
|
||
vetting, vendored binary management, telemetry, and licensing.
|
||
|
||
### Changed
|
||
|
||
- Line length set to 160 across .editorconfig and dart formatter.
|
||
|
||
- Core frame vs shipped extension boundary defined (D-46). Builtins
|
||
are frame infrastructure only; content extensions are bundled but
|
||
architecturally removable.
|
||
|
||
### Removed
|
||
|
||
- `builtin.jira` stub — Jira integration belongs as a third-party
|
||
extension, not a frame builtin.
|
||
- `wasm_run` and `wasm_run_flutter` dependencies — replaced by
|
||
vendored libtree-sitter.so via dart:ffi. Eliminates runtime network
|
||
download that violated POLICY.md.
|
||
|
||
### Added
|
||
|
||
- pql skill installed via `pql init --with-skill=yes`
|
||
(`.claude/skills/pql/SKILL.md`). Covers vault queries and the
|
||
planning surface (decisions + tickets).
|
||
|
||
- `Bash(pql)` and `Bash(pql *)` permissions in
|
||
`.claude/settings.json`.
|
||
|
||
- pql daemon subsystem (`lib/src/pql/`). `PqlClient` wraps the pql
|
||
CLI per D-3. IPC verbs `pql.files | meta | backlinks | outlinks
|
||
| tags | schema | query | doctor | decisions.sync | decisions.list
|
||
| decisions.show | decisions.coverage | tickets.list | tickets.show
|
||
| tickets.board | plan.status`. 15 new core tests.
|
||
|
||
- `builtin.pql` — sidebar panel with four views: Files (pql-indexed
|
||
file listing), Query (PQL DSL input + results), Decisions (synced
|
||
D/Q/R records colour-coded by type), Tickets (kanban board columns).
|
||
Context panel tab showing backlinks + outlinks for the active file,
|
||
auto-refreshing on `editor.active-changed` events.
|
||
|
||
- `builtin.problems` — sidebar panel aggregating diagnostics from
|
||
`pql.doctor` and `pql.decisions.sync`. Surfaces missing index DB,
|
||
stale skill installs, and broken decision cross-references with
|
||
actionable hints.
|
||
|
||
- Git subsystem in the daemon (`lib/src/git/`). Status parser
|
||
(`git status --porcelain`), unified-diff parser, and operations
|
||
(stage, unstage, stage-hunk, discard, commit, stash, log, pull,
|
||
push). IPC verbs `git.status | diff | stage | stage-all | unstage
|
||
| stage-hunk | unstage-hunk | discard | commit | stash | stash-pop
|
||
| log | pull | push` with `git.changed` events on mutations.
|
||
42 new core tests cover parsing, operations, and dispatcher
|
||
round-trips.
|
||
|
||
- `clide git …` CLI shortcuts: `git status`, `git diff [--staged]`,
|
||
`git stage <paths>`, `git stage-all`, `git unstage`, `git discard`,
|
||
`git commit "<msg>"`, `git log [--count N]`, `git stash`,
|
||
`git stash-pop`, `git pull`, `git push`.
|
||
|
||
- `builtin.git` — sidebar panel showing staged, unstaged, untracked,
|
||
and conflicted file groups. Per-file stage/unstage/discard on hover.
|
||
Inline commit message input with Commit button. Branch + ahead/behind
|
||
display with Pull/Push actions. Auto-refreshes on `git.changed`
|
||
events.
|
||
|
||
- `builtin.diff` — workspace tab rendering unified diffs with
|
||
old/new line numbers, addition/removal colouring, and binary/rename
|
||
metadata. Staged/Unstaged toggle toolbar. Auto-refreshes on
|
||
`git.changed` events.
|
||
|
||
- `builtin.editor` — Tier-2 editor tab wired up. Contributes a
|
||
single `Editor` workspace tab that renders the daemon's active
|
||
buffer via a new `EditorController`. Hydrates on mount
|
||
(`editor.active` → `editor.read`), subscribes to
|
||
`editor.opened | active-changed | edited | saved | closed`, and
|
||
propagates user edits back through `editor.set-content`. Small
|
||
echo-suppression guard avoids clobbering the caret when the
|
||
daemon's authoritative edit echo comes back. Text surface is
|
||
Flutter's `EditableText` primitive — no `TextField` / Material —
|
||
so the D-7 "no Material root" stance carries into the editor;
|
||
JetBrainsMono via the shared `clideMonoFamily` constants, cursor
|
||
+ selection colours bind to the theme.
|
||
|
||
- File-tree click in `builtin.files` now opens the clicked file in
|
||
the editor via `ipc.request('editor.open', {path})`. No local
|
||
command hop — the dispatch goes straight to the daemon and the
|
||
UI reconciles through the `editor.active-changed` event.
|
||
|
||
- CLI shortcuts per CLAUDE.md's Tier-2 list: `clide open <path>`,
|
||
`clide active`, `clide insert <text | ->`, `clide replace-selection
|
||
<text | ->`, `clide save`, `clide tail --events [--filter
|
||
SUBSYSTEM[:ID]]`. A lone `-` on insert / replace-selection reads
|
||
text from stdin (pipe-friendly). `tail` reads the event-broadcast
|
||
stream and prints JSON lines until SIGINT; `--filter` narrows by
|
||
subsystem or subsystem+id. 5 new end-to-end CLI tests spin up real
|
||
daemon subprocesses via a per-test `CLIDE_SOCKET_PATH` override (new
|
||
env knob on `defaultSocketPath`) so tests run in parallel without
|
||
colliding.
|
||
|
||
- Editor subsystem in the daemon (`lib/src/editor/`). `EditorBuffer`
|
||
holds path + content + cursor/selection + dirty flag;
|
||
`EditorRegistry` owns the open-buffer set, active-buffer tracking,
|
||
and file I/O. IPC verbs land alongside (`editor.open | active |
|
||
activate | list | read | insert | replace-selection | set-selection
|
||
| set-content | save | close`) with matching events (`editor.opened
|
||
| active-changed | selection-changed | edited | saved | closed`).
|
||
Omitting `id` on mutating verbs targets the active buffer so the
|
||
tier-2 CLI shortcuts (`clide insert "…"`, `clide replace-selection
|
||
"…"`) read naturally. 16 new core tests cover the lifecycle +
|
||
dispatcher round-trips.
|
||
|
||
- `builtin.claude` — Tier-1 stub upgraded to the real Claude pane per
|
||
D-41. Contributes a primary `Claude` tab in the workspace slot that
|
||
spawns `tmux new-session -A -s clide-claude-<hash> -- claude` via
|
||
IPC `pane.spawn`, with `<hash>` derived from the git root path so
|
||
reopening the app re-attaches to the running conversation. Primary
|
||
has no close affordance; closing the tab doesn't kill the session.
|
||
Command `claude.new-secondary` is registered for the palette wiring
|
||
that's coming next. If tmux isn't on PATH, falls back to spawning
|
||
`claude` directly and surfaces "no-tmux · fresh every launch" in
|
||
the header subtitle. Accompanied by D-41 in
|
||
[`decisions/architecture.md`](decisions/architecture.md#d-41-claude-panes-one-primary-per-repo-tmux-backed).
|
||
|
||
- `builtin.files` — workspace filesystem panel in the sidebar. Lazy
|
||
tree rooted at the git root, expand/collapse, click-to-open plumbed
|
||
to a future `editor.open` command. Backed by a new daemon-side
|
||
`files.*` IPC subsystem (`files.root`, `files.ls`, `files.watch`)
|
||
and a `FileWatcher` that wraps `Directory.watch(recursive: true)`
|
||
with ignore-file filtering. Ignore set composes clide's built-in
|
||
hide list (`.git/`, `.pql/`, `.clide/`, `.dart_tool/`, `build/`,
|
||
`node_modules/`) with `.gitignore` / `.clideignore` at the root per
|
||
D-4. `IgnoreSet` + `IgnorePattern` support line-per-pattern, `#`
|
||
comments, anchored / directory-only / negated forms, and `**` across
|
||
directories. 11 new unit tests on the matcher; 5 new dispatcher
|
||
tests; 171 app tests still green.
|
||
|
||
- `builtin.terminal` — general-purpose terminal pane, Tier-1 stub
|
||
upgraded to a working implementation. Contributes a `Terminal` tab
|
||
in the workspace slot that spawns `$SHELL -l` via IPC
|
||
`pane.spawn`, streams `pane.output` events into `xterm.dart`, and
|
||
routes user input through `pane.write`. Resize propagates via
|
||
`pane.resize` on viewport change. `initState` → spawn;
|
||
`dispose` → `pane.close`. Error-state surface for "daemon not
|
||
connected" / "shell exited." No Claude-specific behaviour — that
|
||
lives in `builtin.claude` + D-41.
|
||
|
||
- Shared pane widgets under `app/lib/widgets/`: `ClidePtyView` wraps
|
||
`xterm.dart` with clide-theme token bindings, JetBrains Mono as the
|
||
face, and a Semantics live-region wrapper; `ClidePaneChrome` is the
|
||
reusable title strip + optional close button. Consumers of the new
|
||
widgets (`builtin.terminal`, `builtin.claude`) drive the xterm
|
||
`Terminal` model and route bytes through IPC `pane.write` /
|
||
`pane.output` events themselves — the widgets are rendering only,
|
||
no IPC coupling.
|
||
|
||
- `xterm: 4.0.0` Dart dependency on the Flutter app — MIT, listed in
|
||
`licenses.yaml` per D-42. Hand-rolling a VT100 / xterm / truecolour
|
||
parser + renderer would be weeks for no fidelity win.
|
||
|
||
- `Q-23` — open question on SSH-remote development (run clide against
|
||
a workspace on another host). Local-first stays the Tier-1 target;
|
||
this records the constraint so the daemon / IPC / extension seams
|
||
don't unknowingly accrete local-only assumptions.
|
||
|
||
- IPC `pane` subsystem in the daemon (per D-6). Commands:
|
||
`pane.spawn | list | focus | close | write | resize | tail`. Events:
|
||
`pane.spawned`, `pane.output` (base64-framed), `pane.exit`,
|
||
`pane.resized`, `pane.focused`, `pane.closed`. `PaneRegistry` owns
|
||
per-pane `PtySession` lifecycles + id generation (`p_N`); a
|
||
`DaemonEventSink` seam lets handlers emit events without depending
|
||
on the IPC server package. `DaemonServer.broadcast()` fans events
|
||
out to every connected client (a later pass adds per-client
|
||
`--filter` scoping). Panes carry a `kind:` field — `terminal` today,
|
||
`claude` ready for step 7. Covered by 14 new Dart core tests
|
||
exercising the real registry + dispatcher against the `ptyc` helper.
|
||
|
||
- `PtySession` in the Dart core (`lib/src/pty/`) — spawns a child
|
||
under a PTY via the `ptyc` supporter tool, receives the master fd
|
||
over `SCM_RIGHTS`, and exposes a byte stream, write, resize, and
|
||
kill. A background isolate loops on blocking `read(fd)` and posts
|
||
chunks to the main isolate. `close()` sends SIGTERM to the child
|
||
so the PTY's EOF wakes the isolate cleanly, then falls through to
|
||
SIGKILL + fd close + isolate kill as a safety net. Child env is
|
||
built via `mergePtyEnv()` which stamps clide's true-colour defaults
|
||
(`TERM=xterm-256color`, `COLORTERM=truecolor`, `CLICOLOR_FORCE=1`).
|
||
Test coverage: echo round-trip, cat write/readback, env stamping
|
||
verification, idempotent close.
|
||
|
||
- `ffi: 2.1.3` as a runtime dependency on the Dart core — justified
|
||
in `pubspec.yaml` + documented in `licenses.yaml` per D-42. Used
|
||
by `lib/src/pty/ffi/` for `socketpair`, `recvmsg` with `SCM_RIGHTS`,
|
||
`read`/`write` on raw fds, and `ioctl(TIOCSWINSZ)`.
|
||
|
||
- `ci/test_core.sh` + `make test-core` — runs the Flutter-free core
|
||
Dart tests (`test/`) under a 120s hard timeout with process-group
|
||
cleanup. Wired into `push-check` ahead of the app test suite so a
|
||
hung PTY test can't block the pre-push gate.
|
||
|
||
- Josefin Sans bundled as `app/assets/fonts/josefin_sans/` as the
|
||
application UI face — variable-font pair (upright + italic, weight
|
||
range 100-700), OFL-licensed. Declared as the `JosefinSans` family
|
||
in `app/pubspec.yaml`. `_AppRoot` installs it as the ambient
|
||
`DefaultTextStyle` at weight `w300` (Light) per the project's
|
||
aesthetic direction; callers can still pass an explicit
|
||
`fontWeight` on `ClideText` to get bolder emphasis.
|
||
|
||
- JetBrains Mono bundled as `app/assets/fonts/jetbrains_mono/` —
|
||
Regular / Italic / Bold / BoldItalic weights (OFL-licensed,
|
||
license file checked in alongside). Declared as the `JetBrainsMono`
|
||
family in `app/pubspec.yaml`. `app/lib/widgets/src/typography.dart`
|
||
exposes `clideUiFamily` + `clideMonoFamily` plus platform-ordered
|
||
fallback chains for both faces, for web builds and harnesses that
|
||
don't load asset fonts.
|
||
|
||
- `app/assets/licenses.yaml` — canonical manifest of every bundled
|
||
third-party artefact (fonts today; Dart packages + native tools as
|
||
they land). Schema has name, kind, version, homepage, license,
|
||
`license_file` pointer, and a one-line purpose. Bundled alongside
|
||
the per-dep license texts. The About screen (Tier 6) will render
|
||
this file verbatim. Accompanied by
|
||
[`D-42`](decisions/tooling.md#d-42-bundled-dependencies-documented-in-licensesyaml):
|
||
adding a dep is a two-step commit (artefact + `licenses.yaml`
|
||
entry in the same changeset).
|
||
|
||
### Changed
|
||
|
||
- CLAUDE.md "Dependencies & supply chain" section gains the
|
||
"document every bundled dependency" rule, pointing at
|
||
`app/assets/licenses.yaml` and `D-42`.
|
||
|
||
- `ptyc/` — the C PTY-spawn helper, peer of `pql` per
|
||
[`D-5`](decisions/architecture.md#d-5-dart-core-sidecar-dissolved-ptyc-as-pql-peer).
|
||
One-shot, libc-only, ~400 LOC. Reads a JSON request on stdin
|
||
(`argv`, optional `cwd`/`env`/`cols`/`rows`), does
|
||
`posix_openpt` + `fork` + `execvp`, and hands the master fd back
|
||
to the caller over a unix socket via `SCM_RIGHTS`. Socket fd
|
||
defaults to 3; override via `PTYC_SOCK_FD` for language runtimes
|
||
that shuffle pipe fds through the low numbers (Python's
|
||
`subprocess` with `stdout=PIPE` does this). Exec-failure pipe
|
||
(CLOEXEC) reports child-side errors to the parent without leaking
|
||
zombies. Root Makefile gains `ptyc-test` target in addition to
|
||
`ptyc-build` / `ptyc-clean`.
|
||
|
||
- Migrated the `docs/ADRs/` content into `decisions/` as D/R records:
|
||
ADR 0001 → `D-1`, ADR 0002 → `R-2` (superseded by `D-5`), ADR
|
||
0003 → `D-3`, ADR 0004 → `D-4`, ADR 0005 → `D-5`, ADR 0006 →
|
||
`D-6`. Titles preserved; ADR 0006's trailing open questions moved
|
||
to `questions-architecture.md` as `Q-1` / `Q-2` / `Q-3`. The
|
||
originals are preserved in git history.
|
||
|
||
- `decisions/` at the repo root — Q&D record system ported from
|
||
settled-reach and adapted for clide's domains. Confirmed decisions
|
||
(`D-NNN`) live under domain files (`architecture.md`, `extensions.md`,
|
||
`accessibility.md`, `testing.md`, `tooling.md`, `process.md`); open
|
||
questions (`Q-NNN`) live under parallel `questions-<domain>.md`;
|
||
rejected alternatives (`R-NNN`) live in `rejected.md`. Record shape,
|
||
claiming rules, and the eventual pql-side tooling plan are documented
|
||
in `decisions/README.md`. Migration of the existing `docs/ADRs/` into
|
||
these files lands in a follow-up commit.
|
||
- `DECISIONS.md` one-line pointer at the repo root (matches
|
||
settled-reach's convention).
|
||
|
||
- `tools/scripts/plan` — Python stopgap entrypoint for `decisions`
|
||
and `ticket` subcommands, writing to `.pql/pql.db` (gitignored).
|
||
Supports `decisions sync | validate | claim | list | show | coverage`
|
||
and `ticket new | list | show | status | assign | team | block |
|
||
unblock | label | search | board`, plus `sqlite-query`. Verb shape
|
||
and output format mirror the eventual `pql` subcommands so migration
|
||
when pql ships feature parity is a call-site find-replace
|
||
(`tools/scripts/plan ` → `pql `). Ported from settled-reach with
|
||
the Scrum layer stripped; ticket IDs are `T-NNN` (TEXT PKs) and
|
||
there's no `sprints` table. Time-limited per
|
||
[`D-40`](decisions/process.md#d-40-python-stopgap-under-toolsscriptsplan)
|
||
/ [`R-11`](decisions/rejected.md#r-11-permanent-stopgap).
|
||
|
||
- `make decisions-validate` — cheap parser dry-run wired into
|
||
`push-check`. Catches malformed records before push.
|
||
|
||
- Reserved extension slots — `builtin.decisions`, `builtin.tickets`,
|
||
`builtin.claude-control`. Id-reserving stubs under
|
||
`app/lib/builtin/` with no contributions yet. Implementations land
|
||
once [`Q-21`](decisions/questions-architecture.md#q-21-pql-absorbs-planning-vs-keeps-separate)
|
||
resolves (decisions + tickets) or when the claude-control tier
|
||
arrives (`.claude/` first-class surface — distinct from the
|
||
existing `builtin.claude` PTY-pane stub).
|
||
|
||
- `CLAUDE.md` — new "Decision discipline" guardrail pointing at
|
||
`decisions/`.
|
||
|
||
### Changed
|
||
|
||
- `CLAUDE.md` — inline ADR links rewritten to point at the migrated
|
||
`decisions/` records; bottom "Open questions" section collapsed to
|
||
a pointer at `decisions/questions-*.md`; parent-project note
|
||
updated to reference `decisions/architecture.md` instead of the
|
||
deleted `docs/ADRs/`.
|
||
|
||
- `make decisions-validate` rewired from `tools/scripts/plan` to
|
||
`pql decisions validate`.
|
||
|
||
- Decision discipline guardrail in CLAUDE.md now points at
|
||
`pql decisions claim` instead of the Python stopgap.
|
||
|
||
### Removed
|
||
|
||
- `tools/scripts/plan` — Python stopgap planning scripts, superseded
|
||
by `pql` 1.0 native `decisions` and `ticket` subcommands. Sunset
|
||
condition from
|
||
[`D-40`](decisions/process.md#d-40-python-stopgap-under-toolsscriptsplan)
|
||
met; deletion per
|
||
[`R-11`](decisions/rejected.md#r-11-permanent-stopgap).
|
||
|
||
### Removed
|
||
|
||
- `docs/ADRs/` directory — content lifted into `decisions/` as D/R
|
||
records (see Added above). Originals preserved in git history.
|
||
|
||
- Go sidecar skeleton under `sidecar/` — `cmd/clide/main.go`, `go.mod`, and the `internal/*` packages (`cli`, `daemon`, `diag`, `git`, `ipc`, `pql`, `proc`, `pty`, `version`). Deleted wholesale per [ADR 0005](docs/ADRs/0005-dart-core-ptyc-peer.md): the "sidecar language: Go" premise no longer holds once the core is Dart. All functionality listed for those packages will be reimplemented under `lib/` as part of Tier 0.
|
||
- Go-specific Makefile targets (`lint`, `vuln`, `test-race`, `fmt`, `tidy`, `snapshot`, `tools`, `install` via Go), the `govulncheck`/`goimports`/`golangci-lint` version pins, and the pre-push hook's `GOBIN` PATH injection. Replaced with Dart/Flutter equivalents (`analyze`, `format`, `test`, `test-integration`, `build` via `dart compile exe`).
|
||
- `module:` and `go_version:` from `pubspec.yaml` — single-language core means no Go module path to track.
|
||
|
||
### Changed
|
||
|
||
- [ADR 0002](docs/ADRs/0002-sidecar-language-go.md) marked **superseded** by [ADR 0005](docs/ADRs/0005-dart-core-ptyc-peer.md). The "sidecar language: Go" guardrail is retired. CLAUDE.md's guardrails, dependency notes, and command reference are updated to reflect the Dart-core direction.
|
||
- `.gitignore` retargeted: Flutter/Dart output at the repo root (`.dart_tool/`, `build/`, platform ephemeral dirs, `bin/clide`), plus a `ptyc/` section for the C helper's build artefacts. Go-specific rules removed.
|
||
- `ci/lint.sh`, `ci/test.sh`, `ci/security.sh`, and `.githooks/pre-push` rewritten for the Dart toolchain — no Go shell-outs, no `GOBIN` PATH dance.
|
||
|
||
### Added
|
||
|
||
- Testing docs under `docs/testing/`: `README.md` (what each layer covers, how to run, local vs CI flow), `a11y-manual.md` (15-minute Orca + VoiceOver checklist run at every tier cut), `claude-ui-workflow.md` (how Claude Code drives the app through the Playwright harness, including the `flt-semantics-placeholder` quirk).
|
||
- Makefile targets for every test layer and the UI harness: `test`, `test-a11y`, `test-integration`, `test-e2e`, `test-all`, `coverage`, `smoke-bundle`, `ui-dev`, `ui-stop`, `ui-smoke`. `push-check` now runs `test + test-a11y` (fast pre-push gate, <90s).
|
||
- Per-layer CI shell scripts under `ci/`: `test.sh` (analyze + format + unit + widget + golden, ~5s), `test_a11y.sh` (a11y contract), `test_integration.sh` (integration_test one file at a time — desktop can't batch them reliably), `test_e2e.sh` (daemon subprocess + browser WASM Playwright smoke), `smoke_bundle.sh` (xvfb-run the Linux release bundle for 5s; catches dynamic-linker / asset-bundle / plugin-init regressions that widget tests can't see), `coverage.sh` (flutter test --coverage + lcov summary).
|
||
- `.gitea/workflows/test.yml` — four-job pipeline (`unit`, `integration`, `startup-bundle`, `e2e`) that shells out to the `ci/*.sh` scripts. **Not activated yet** — Gitea Actions has to be enabled in the instance settings first. GitHub-Actions-syntax-compatible, so copying to `.github/workflows/` is a one-file move when the repo migrates.
|
||
- Web WASM harness under `tools/ui/` — Playwright driver so Claude Code (and humans) can drive the Flutter build in a real browser via the Semantics tree. `build.sh` / `serve.sh` / `stop.sh` manage a local `http.server` on `:4280` with port-based reclaim and kill (so orphaned listeners from earlier runs get swept). `driver.ts` exposes `ClideDriver` with `byLabel` / `click` / `type` / `readText` / `screenshot` / `dumpSemanticsTree` / `waitUntilReady` (auto-clicks the `flt-semantics-placeholder` to enable the semantics tree). First Playwright test `smoke.spec.ts` asserts welcome + disconnected labels render in the browser.
|
||
- Integration tests under `app/integration_test/`, run with the `integration_test` package against the real built app (not an in-memory widget pump). The load-bearing startup gate lives here: `app_starts_test.dart` boots `ClideApp`, waits for the root shell to settle, and asserts the three-column layout + welcome tab + statusbar connection indicator all render. Also covers theme-picker modal open/select/dismiss (`theme_picker_test.dart`) and extension enable/disable lifecycle with contributions mounting/unmounting (`extension_lifecycle_test.dart`).
|
||
- App-level test suite under `app/test/` — 168 tests across four layers:
|
||
- **Unit** (`kernel/`, `extension/`) — events bus, settings (scope + YAML round-trip), log, i18n fallback chain matrix, theme resolver + loader + controller, panel registry + arrangement, command registry + keybinding parser + palette filter, extension-manager dep-order / cycle detection / enable-disable, manifest loader, extension scanner.
|
||
- **Widget** (`widgets/`, `builtin/`) — every primitive's Semantics presence + token consumption + hover/press states; each Tier 0 built-in's contributions, view, and locale-switch re-render.
|
||
- **Golden** (`goldens/`) — widget primitives only, Alchemist + Ahem font; PNG fixtures checked in under `_files/ci/` and `_files/linux/`.
|
||
- **A11y** (`a11y/`) — `semantic_coverage_test.dart` (contract-level check that every built-in carries title + version + label-ready contributions), `contrast_test.dart` (WCAG-AA ratio gate on every bundled theme's canonical token pairs), `i18n_coverage_test.dart` (asserts every Tier-0-referenced key is present in its `en_US` catalog), `keyboard_traversal_test.dart` (focusability smoke).
|
||
- Test helpers under `app/test/helpers/` — `KernelFixture` (boots a KernelServices with in-memory defaults + a fake daemon for widget-level tests), `FakeDaemonClient` (subclasses the real client, no socket, drivable connected-state), `golden_harness` (Alchemist config with Ahem font for cross-platform pixel stability), `widget_harness` (wraps a widget in Directionality + ClideKernel + ClideTheme + MediaQuery).
|
||
- Flutter desktop app scaffold under `app/` with a bare `WidgetsApp` root (no Material, no Cupertino) and the Tier 0 three-column layout.
|
||
- **Kernel** (`app/lib/kernel/`) — 18 services consumed by every extension: `settings` (scope-resolved get/set across `app.*`/`project.*`/`ext.*`), `project`, `extensions`, `theme`, `panels` (slot registry + arrangement), `events`, `ipc`, `commands` (+ palette + keybinding resolver), `clipboard`, `files`, `notify`, `dialog` (single-at-a-time modal router), `tray`, `secrets`, `os`, `net`, `focus`, and `log`. Unified in a `ClideKernel` `InheritedWidget`.
|
||
- **i18n** (`app/lib/kernel/src/i18n/`) — text-driven lookup ported from [fframe](https://github.com/postmeridiem/fframe)'s `L10n`: namespaced JSON catalogs, `string()` / `interpolated()` calls with caller-supplied placeholders, and a proper locale fallback chain (exact → language → default-country → default-language → placeholder). Improves on fframe's design by adding the chain, which fframe lacks.
|
||
- **A11y from Tier 0** — `Semantics(label:, hint:, button:)` on every interactive primitive; `SemanticsBinding.ensureSemantics()` at boot; a `theme/contrast.dart` helper exposes token pairs that the a11y suite walks for WCAG-AA compliance.
|
||
- **Extension contract** (`app/lib/extension/`) — abstract `ClideExtension`, sealed `ContributionPoint` hierarchy (`TabContribution`, `StatusItemContribution`, `ToolbarButtonContribution`, `CommandContribution`, `TrayItemContribution`, `LayoutPresetContribution`). Each extension ships one manifest contributing N atoms into kernel slots. Priority-based ordering within a slot, dependency-aware activation, YAML manifest loader + scanner for `~/.clide/extensions/`.
|
||
- **Three-tier theme pipeline** — palette (named colors) → semantic roles → ~60 VS-Code-style surface tokens, each layer with defaults so palette-only themes ship. Ported `summer-night` as the first bundled theme; muted value calibrated for WCAG-AA contrast.
|
||
- **Widget primitives** (`app/lib/widgets/`) — `ClideSurface`, `ClideText`, `ClideButton`, `ClideTabBar`, `ClideDivider`, `ClideScrollbar`, `ClideTooltip`, `ClideIcon` + eight `CustomPainter`-rendered icons (folder, gear, x, chevron-left/right, dot, check, plug). All token-consuming, all Semantics-wrapped.
|
||
- **Tier 0 built-in extensions** — `builtin.default-layout` (classic three-column preset + reset command), `builtin.welcome` (workspace placeholder), `builtin.ipc-status` (live-region statusbar indicator), `builtin.theme-picker` (command + modal, bound to `ctrl+k`). Plus 17 id-reserving stubs (`builtin.claude`, `builtin.terminal`, `builtin.files`, `builtin.editor`, `builtin.git`, ...) so later tiers can fill in without rename churn.
|
||
- **Lua runtime boundary** — `app/lib/lua/` ships as typed stubs (`host`, `adapter`, `capability_api`, `render_intent`) so third-party Lua extensions can plug in at Tier 6 without retrofitting.
|
||
- `.gitignore` extended to cover `app/` sub-package artefacts (`app/.dart_tool`, `app/build`, per-platform ephemeral dirs, `app/*.iml`) and the Playwright harness under `tools/ui/` (`node_modules`, `out`, test-results).
|
||
- Dart core package at the repo root: `bin/clide.dart` (one binary, `--daemon` and one-shot subcommand modes), `lib/clide.dart` barrel exporting the shared IPC types, `lib/src/ipc/` (`envelope.dart`, `server.dart`, `paths.dart`, `schema_v1.dart`), and `lib/src/daemon/dispatcher.dart`. `clide --daemon` listens on a unix socket; `clide ping` / `clide version` round-trip through it with the ADR 0006 exit-code contract (`0/1/2/3/4`). Includes `test/ipc/` and `test/daemon/` suites covering envelope parsing, the in-process server, and a subprocess smoke that verifies signal-driven shutdown + socket unlink.
|
||
- `scripts/bazzite-flutter-setup.sh` — one-shot installer for the Flutter SDK + desktop build deps on Bazzite / Fedora Silverblue. Drops the SDK under `~/opt/flutter`, wires PATH in the user's shell rc files, and layers the Linux desktop build deps via `rpm-ostree install`.
|
||
- [ADR 0005](docs/ADRs/0005-dart-core-ptyc-peer.md) — Dart core; sidecar directory dissolved; `ptyc` as pql-peer. Establishes one Dart AOT binary for both CLI and daemon, `lib/` as the shared core, and promotes the C PTY helper to a standalone supporter tool on the same footing as pql.
|
||
- [ADR 0006](docs/ADRs/0006-cli-and-event-surface.md) — CLI and event surface contract. Defines the subsystem list (`pane`, `tab`, `editor`, `panel`, `tree`, `git`, `pql`, `canvas`, `graph`, `theme`, `settings`, `project`), the command shape, the versioned JSON event schema, the pql-style exit-code contract, and the command↔event duality rule that operationalises user/Claude parity.
|
||
|
||
- Architectural decision records carried forward from the short-lived
|
||
`claudian` plugin project (discarded in favour of this Flutter
|
||
rebuild):
|
||
[ADR 0001](docs/ADRs/0001-cli-first-not-mcp.md) — CLI-first, not MCP.
|
||
[ADR 0002](docs/ADRs/0002-sidecar-language-go.md) — Sidecar language: Go.
|
||
[ADR 0003](docs/ADRs/0003-pql-as-supporter-tool.md) — pql as supporter tool; wrap, don't duplicate; pql is a Clide subsystem when present.
|
||
[ADR 0004](docs/ADRs/0004-ignore-file-strategy.md) — Ignore file strategy (`ignore_files:` in `.pql/config.yaml`, layered).
|
||
- Pre-push quality gate: `.githooks/pre-push` runs `make push-check` (lint + test + test-race + test-integration + vuln + app-analyze + app-test) so bad pushes are caught locally before they hit Gitea. The app-side targets gracefully noop until Flutter is scaffolded. Install with `make hooks` (sets `git config core.hooksPath .githooks`); the hook prepends `$GOBIN`/`$HOME/go/bin` to PATH so govulncheck resolves without the user touching their shell profile.
|
||
- Go sidecar/CLI skeleton under `sidecar/` (module `git.schweitz.net/jpmschweitzer/clide/sidecar`): `cmd/clide/main.go`, `internal/cli` with a stdlib-flag dispatch, `internal/diag` mirroring pql's exit-code + stderr-JSON contract, `internal/version` with ldflag-stamped build info, and placeholder packages for `daemon`, `pty`, `proc`, `git`, `ipc`, `pql` awaiting their tier. `clide --version` emits JSON build-info today.
|
||
- Root `Makefile` drives both the Go sidecar and the Flutter app under one toolchain. Version is read from `pubspec.yaml` via awk and stamped into the sidecar via `-ldflags -X`. Flutter targets gracefully noop before the app is scaffolded so the Makefile is usable from day one. Pinned Go tooling (govulncheck, goimports, golangci-lint) installs via `make tools`.
|
||
- `ci/` entry scripts: `test.sh`, `lint.sh` (includes the supply-chain gate — no green lint without a green CVE scan), `security.sh`, `release.sh` (stub).
|
||
- Project identity files for the Flutter rebuild at the repo root: `pubspec.yaml` (single source of truth for version + module path, version 2.0.0-dev), a fresh `README.md`, MIT `LICENSE`, and `.editorconfig`. The Python clide's manifest and README are preserved under `legacy/`.
|
||
- [`docs/initial-plan.md`](docs/initial-plan.md) — the north-star design document for the Flutter rebuild. Captures what we kept from Python Clide (pane model, git skills, Claude-always-visible), what we took from Obsidian (canvas and graph — no vault, no bases, no plugin inheritance), what Claudian's short experiment contributed (Go sidecar, CLI-first, pql-as-subsystem, ignore-file strategy), and the tier roadmap (Tier 0 app+sidecar handshake → Tier 5 canvas+graph).
|
||
- [`CLAUDE.md`](CLAUDE.md) orientation doc for future Claude Code instances: project identity, guardrails as one-liners, tier ordering, parent-project pointers, commands, dependencies & supply chain, open questions. Points at the design doc and ADRs rather than restating their content.
|
||
- Claude Code configuration under `.claude/`: project-level
|
||
allow/deny permissions and two skills — `skill-create` (generic
|
||
skill authoring guidance) and `git-commit` (this repo's commit
|
||
conventions: no Conventional Commits, Keep a Changelog discipline,
|
||
`pubspec.yaml`-and-changelog-bumped-together rule, attribution
|
||
trailer, safety reminders).
|