Skip to content

Show unsent draft markers in the sidebar#260

Merged
SDSLeon merged 1 commit into
nextfrom
lightcode/bright-ibis-e4f6db28
Jul 8, 2026
Merged

Show unsent draft markers in the sidebar#260
SDSLeon merged 1 commit into
nextfrom
lightcode/bright-ibis-e4f6db28

Conversation

@SDSLeon

@SDSLeon SDSLeon commented Jul 8, 2026

Copy link
Copy Markdown
Owner
  • Feature: surface unsent draft state in sidebar thread rows and the new-thread entry with a subtle indicator, so draft presence is visible at a glance.
  • Normalize draft detection around a shared non-empty draft check, keeping sidebar indicators and composer state aligned.
  • Improve sidebar tooltip behavior for truncated labels that include trailing markers.
  • Add and localize the new draft indicator copy across all supported languages.

- add a shared draft-non-empty check and reuse it across composer and sidebar logic
- render an unsent-draft indicator for thread rows and the new thread button
- update sidebar item tests and localized strings for the new indicator
@vercel

vercel Bot commented Jul 8, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
lightcode-landing Ready Ready Preview, Comment Jul 8, 2026 5:02pm

@SDSLeon
SDSLeon merged commit cc48ce7 into next Jul 8, 2026
2 checks passed
@SDSLeon
SDSLeon deleted the lightcode/bright-ibis-e4f6db28 branch July 8, 2026 17:05
SDSLeon added a commit that referenced this pull request Jul 13, 2026
* brand: finalize Poracode identity (P + indigo Pora-dot, Geist, dark/moonlight)

Finalized rebrand from Lightcode → Poracode on this branch (assets only;
code rename is a separate, gated step).

- branding/BRAND.md — authoritative brand guide: naming architecture
  (Poracode, Inc. → Poracode / Poracode CLI / Poracode Cloud), logo + the
  "Pora dot" motif, color, typography (Geist), voice, asset inventory.
- SVG masters (icon / light / nightly / glyph / wordmark) + build-icons.mjs
  (uses repo sharp + macOS iconutil) → out/{build,website}: icns/ico/png
  ladder + favicons.
- Concept gallery + rendered-asset preview (Geist, baseline dot, indigo accent).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* brand: add full brand book (all variants, cases & UI examples)

Single-page showcase: logo variants/mono/sizes/clearspace, wordmark & family
lockups, the dot motif, full color + contrast, Geist type specimens, UI
components (buttons/inputs/pills/tabs/toast), in-context mocks (app window,
dock, browser tab, avatar, OG card), do/don't, naming & asset index.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* brand: fix wordmark dot (round circle, not Geist's square period) + contrast

- Replace the font-period "dot" (Geist draws periods square) with a true round
  Pora-dot drawn as its own element across all wordmark lockups (showcase,
  concepts, preview) and the wordmark SVG master (now a <circle>).
- Bump "code" weight 500 -> 600 for stronger presence/contrast.
- Document the round-dot rule in BRAND.md (never the font period).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* brand: reseat wordmark dot on the baseline (fix misalignment)

The dot's bottom margin was lifting it off the baseline. Remove it so the
round Pora-dot rests on the baseline like a period, optically centered in the
gap — in the wordmark SVG (circle at cy=137) and all HTML lockups.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* brand: fix HTML dot baseline alignment (inline SVG, render-verified)

Root cause: the dot was an empty inline-block; vertical-align:baseline on an
empty box doesn't sit on the *text* baseline (Chromium uses the box's own
edge), so it floated mid-letter. Replaced with an inline <svg> circle and
empirically tuned the position (cy=93) by rendering the page in Electron until
the dot rests on the baseline. Verified in the actual brand book.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* brand: lower wordmark dot to the baseline + optically center it

Render-tuned against a real baseline reference (a period glyph) in Electron:
- cy 93 -> 100 so the dot bottom rests on the baseline (was floating high).
- asymmetric margin (more space on the "Pora" side) so the dot is optically
  centered in the gap rather than hugging "Pora" (the "c" of code has open
  left bearing).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* brand: nudge wordmark dot up to sit exactly on the baseline (cy 100->98)

cy=100 read slightly low; 96 was high. 98 lands the dot bottom on the
baseline (verified in Electron against a reference period glyph).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* brand: set wordmark dot to cy=100 (per preference)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* brand: dot cy=96; primary button white text on deeper indigo

- Wordmark dot cy -> 96.
- Primary button: white text on a deeper indigo (#6F5CF0) instead of dark text
  on bright indigo — white on the bright accent was ~3:1 (weak); on the deeper
  fill it's ~4.8:1 and reads clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* brand: primary button neutral (dark fill + white text), not accent-filled

Reserve indigo for the dot, links, and active/focus states only — buttons are
a neutral/tertiary style with white text instead of an accent fill.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* chore(rebrand): rename Lightcode to Poracode

- Update app, website, and packaging metadata to the new brand
- Refresh icons, favicon assets, and bundled Geist fonts
- Revise shared text, tests, and i18n catalogs for the rename

* feat(rebrand): migrate Lightcode to Poracode

- Rename app, website, repo, and packaging identifiers to Poracode
- Move user data, worktree, plugin, and WSL paths to the new brand
- Update renderer copy, theme presets, and localization catalogs
- Refresh marketing site content, screenshots, and shared branding components
- Add migration coverage for existing data and update affected tests/docs

* feat(subagents): cross-provider subagent spawning via in-process MCP server

Any agent running in a Lightcode thread can now discover the other
connected agents and spawn them as subagents (e.g. Claude Code running
Codex or OpenCode), through a supervisor-hosted "subagents" MCP server
injected over the same per-provider rails as the browser MCP.

- Supervisor: SubagentMcpIngress (localhost Streamable-HTTP MCP with
  per-thread bearer tokens), toolRegistry (list_agents, spawn_agent,
  wait_for_agent, run_agent, get_status, cancel), SubagentRunManager
  (detached child structured sessions, synthetic subagent tile item,
  child event re-tagging into the parent stream, output capture,
  concurrency cap, recursion guard, interrupt propagation).
- Providers: Claude SDK mcpServers merge, Codex -c mcp_servers args with
  token via LIGHTCODE_SUBAGENT_MCP_TOKEN, ACP newSession.mcpServers for
  Cursor/Copilot/Grok/acp-generic. Children run in the parent's project
  location and inherit its approval/sandbox posture.
- Renderer: registry-driven "MCP servers" section in the composer +
  menu (Browser + Subagents toggles, generic McpChip), subagentMcp
  thread-config flag, and a "Subagent routing guide" setting appended
  to the MCP instructions so users steer agent/model selection.
- Tests: unit coverage for ingress/run manager/provider builders plus a
  live opt-in integration test (tests/integration) that spawns a real
  Claude child through the MCP endpoint.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(claude): support background subagents in structured sessions (#244)

The Claude Code SDK now launches subagents via the background Agent tool:
the launch tool_result returns immediately while the subagent keeps
running past the main turn's result, reporting through task_started/
task_progress/task_updated/task_notification lifecycle events and
forwarded parent-attributed messages. The structured adapter predated
this model and broke on four fronts (all probed against SDK 0.3.197):

- Keep subagent parent tool_calls alive from task_started until the
  authoritative task_notification closes them, instead of completing and
  evicting them on the instant launch ack. Restores the composer dock
  tiles, live progress on the pill, and lifecycle event routing. Live
  parents (and their in-flight children) also survive closeClaudeOpenItems
  and new-turn resets; dangling children of a dead subagent are flushed
  with a completion instead of leaking as running rows.
- Drop parent-attributed stream_event partials and render forwarded whole
  subagent messages as self-contained child items — concurrent subagent
  streams no longer clobber the shared block-index lane and leak into the
  main timeline.
- Never open a resumed turn (or take resume anchors) from subagent
  messages arriving after the main result — kills the spurious
  turn.started/turn.completed churn per subagent.
- Steer without interrupt: new capability-based steerTurn on
  StructuredSessionHandle enqueues the user message onto the running turn
  (query.interrupt() kills background subagents, injects "[Request
  interrupted by user]" and errors the turn). Both steer entry points use
  it when available; interrupt remains for the explicit Stop action, and
  providers without the capability keep the interrupt-drain path.

Also handle previously-unmapped task_updated events and recognize
Agent/Task/Workflow tool names via one shared isSubAgentToolName helper.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>

* feat(subagents): complete follow-ups — all-provider hosting, child approvals, WSL, tier hints

- Gemini + OpenCode now host the subagents MCP tools: merge-safe staged
  settings.json / opencode.json syncs so browser and subagents entries
  coexist; Gemini GUI scope matches browser, OpenCode gets a visible
  per-thread toggle (launch) since subagents has no global setting.
- Child approval/user-input requests forward into the parent thread's
  request panel (request ids namespaced runId::id) and resolutions route
  back to the child handle; stale prompts auto-dismiss when a run
  settles or is cancelled.
- Raw run_agent/spawn_agent MCP tool rows are suppressed in ChatPane
  across all provider naming forms — the subagent tile is the single
  representation; list_agents/wait/get_status/cancel rows stay visible.
- list_agents models now carry a tier hint (fast-cheap | balanced |
  max-capability) via whole-word keyword classification for routing.
- WSL threads can reach the ingress: 0.0.0.0 bind on Windows only
  (bearer token remains the auth boundary, mirroring BrowserMcpIngress)
  plus WSL host-gateway-IP URL rewrite at launch; inert on macOS/Linux.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* feat(mobile): Poracode PWA — remote access, live threads, composer polish (#245)

* feat(mobile): add remote-access server and mobile PWA client

- main/remote: embedded HTTP/WebSocket remote-access server with pairing, auth, identity, browser gateway, and static mobile app hosting
- mobile: new PWA (TanStack Router) — threads, git review, PR pages, browser mirror, terminal, settings sync, QR pairing, and remote desktop hook
- shared/remote: remote protocol, git procedures, and thread-command contracts shared across desktop and mobile
- renderer: RemoteAccessSettings panel, remote git summaries, lazy voice input, terminal thread content, and iOS touch-scroll handling for git review
- settings: refactor SettingsOverlay sections and sidebar; add remote-access section and shared-settings apply path
- build: mobile Vite target, Capacitor native config, PWA manifest/service-worker/icons, Vercel config, and release-mobile CI workflow
- docs: mobile review and release guides

* feat(mobile): localize mobile PWA UI with lingui i18n

- wrap mobile views, components, and PR pages in Trans/useLingui macros
- add msg descriptors for settings sections, presentation, and labels
- bootstrap app locale from cache in mobile entry point
- add "(no branch)" and other extracted strings across all locale catalogs
- include src/mobile in renderer vitest project; drop redundant test imports

* feat(mobile): expand PWA with files, workspace, terminal, and git surfaces

- add FilesView, WorkspaceView, TerminalAccessory, and HighlightedEditor screens with tests
- wire terminal geometry fallback and resize through remote protocol and supervisor
- extend remote git procedures, browser gateway, and pairing endpoint normalization
- rework GitView, ThreadView, ThreadsView, and PR overview with action sheets and toasts
- refactor renderer settings panels and add coverage; extend git review conflict resolver
- add worktree group deletion, openExternal util, and runtime request actions
- update locale catalogs for new strings

* feat(remote): add remote access toggle and mobile thread startup

- add IPC, settings, and server support for enabling/disabling remote access
- update mobile remote client and route handling to start new remote threads
- extract shared thread title generation and refresh renderer/sidebar copy
- expand tests and localized strings for the new remote-access flow

* feat(remote): add standalone remote access and relay support

- Add headless remote host and relay CLIs plus shared client/protocol plumbing
- Expose remote servers management in renderer settings and sidebar
- Add mobile project management and remote thread views
- Cover the new remote flows with tests and localized UI strings

* feat(remote): add relay-backed remote access and mobile UI

- Add relay host/server protocol support, bounded HTTP reads, and auth/client metadata handling
- Implement mobile pairing, remote desktop, thread usage, keyboard offset, and host folder picker flows
- Refresh renderer menus, selectors, file editor, review popover, and i18n catalogs for new labels
- Add server native prepare script plus DB/native binding support and related tests

* fix(remote): harden remote access and mobile sync

- Add protocol versioning, scope filtering, and relay/host hijack checks.
- Tighten server CLI, native DB binding resolution, and server-native packaging.
- Improve mobile remote desktop flows, snapshot pruning, settings navigation, and portaled UI.
- Update remote architecture docs and localized strings for the new UI text.

* fix(remote): preserve PWA browser notifications

* feat(mobile): add push-driven live activities and remote access

- Add the mobile push lifecycle, Live Activity bridge, and floating composer UX
- Extend remote access with Tailscale, pairing, relay, and push gateway support
- Update shared IPC, protocol, settings, and tests for the new remote flow

* feat(mobile): rebrand PWA to Poracode with moonlight theme

Rename the mobile PWA to plain "Poracode" (manifest, mobile.html,
Capacitor appName, pairing shell, device labels) and align its shell
colors with the new default moonlight theme (#070709 bg, #8b7bff
accent). Regenerate PWA icons from the new brand mark, including
maskable and apple-touch variants. Mobile UI strings rebranded and
translated across all 12 locales; legacy "Lightcode on …" device
labels are still stripped for pre-rebrand pairings.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(mobile): stabilize composer keyboard and remote access UI

- Add guarded keyboard debug tracing, ghost-tap suppression, and new composer dock tests.
- Rework mobile composer focus/scroll locking, remote desktop resume handling, and thread view behavior.
- Update remote access settings, theme accents, and localized strings across catalogs.

* chore(mobile): gate composer keyboard debug logging behind flag

Drop the temporary FORCE_DEBUG override used while diagnosing the
first-focus page pan; tracing is silent unless the
lightcode-mobile-keyboard-debug localStorage flag is set.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>

* feat(composer): MCP servers submenu with switches; opencode subagents hosting off

- The composer + menu now shows a single "MCP servers" item opening a
  nested submenu (HeroUI Dropdown.SubmenuTrigger, same idiom as context
  menus) with a toggle switch per server; toggling keeps the menu open.
  Hidden entirely when no MCP is available for the agent/presentation.
- Revert OpenCode subagents hosting scope to "none": opencode.json is
  global and the GUI server is pooled per project, so a per-thread
  bearer token written there would be clobbered by the next launch and
  could attribute one thread's subagent spawns to another thread. The
  browser MCP tolerates this only because its token is app-global.
  OpenCode remains spawnable as a subagent child.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* Fix Claude usage limits and screenshot capture (#246)

* fix(agents-usage): read Claude per-model weekly limits from the limits array

Newer /api/oauth/usage responses report per-model weekly windows (Fable,
Opus, Sonnet) only via the generic limits[] array as weekly_scoped entries;
the top-level seven_day_<model> fields come back null. Map those entries
onto the canonical weekly-* window ids, keeping the top-level fields
authoritative when both are present, and fall back to limits[] for the
session/weekly_all windows too.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* docs(changelog): add 1.4.3 release notes

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* chore: bump to next patch version

* fix(interactive-testing): stop padding full-viewport CDP screenshots with dead space

Page.captureScreenshot with captureBeyondViewport: true captures the whole
compositor surface, which can be larger than the visible viewport (e.g. while
a device-metrics override is active). Full-viewport shots came out 4x the
app size with the content stuck in the top-left corner. Keep the flag only
for element clips, which may extend below the fold.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* feat(opencode): host subagents MCP via dedicated per-thread server

OpenCode GUI threads can now host the subagents tools. A thread launched
with subagentMcp acquires a DEDICATED `opencode serve` (pool key extended
with the thread id, reusing refcount/idle/crash lifecycle) and registers
the server at runtime via client.mcp.add + mcp.connect — mirroring the
browser MCP sync — so the per-thread bearer token never touches the
global opencode.json and never shares a pooled server with sibling
threads. Threads without the toggle (including run-manager children)
keep the shared pool.

Terminal stays "none": {env:VAR} substitution works for url/headers on
OpenCode 1.17.11 but `enabled` cannot be templated, so the required
always-on global template entry would surface a broken subagents server
to every shared-pool GUI instance.

Live-verified: integration test connects a real dedicated opencode
server to the live ingress and asserts mcp status "connected".

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* feat(supervisor): route subagents through one-shot child lane

- Add one-shot child execution plumbing and env snapshotting for subagent runs
- Gate MCP browser/subagent transports by agent capabilities and structured runtime support
- Resolve WSL host access for Windows-bound MCP ingress and update provider timeouts/args

* fix(supervisor): stop primed env capture appending newline to last var

The login-shell env dump ends with a newline, so splitting produced a
trailing empty line that the multiline-value heuristic appended to the
last variable (e.g. GH_HOST="github.com\n"), corrupting it in every
spawned process and breaking gh URL building (PR creation failed with
'invalid control character in URL'). Trim trailing empty lines before
parsing; add regression tests.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(wsl): resolve Browser MCP upstream by networking mode

* fix(chat): flatten same-file tool edit diffs (#248)

* fix(claude): show resolved subagent model in progress (#249)

- Fold child assistant model ids onto parent Task progress
- Strip dated Claude release suffixes from subagent model labels

* fix(agents-usage): reconcile Cursor API dollars with usage percent (#250)

* fix(shared): keep large line diffs minimal (#251)

* Support Cursor ACP task subagent extensions (#252)

* feat(cursor): support ACP task subagent extensions

- Add ACP extension notification plumbing for vendor events
- Map Cursor `cursor/task` metadata into subagent runtime events
- Cover task enrichment and subagent mapping with tests

* test: align platform and Gemini timeout expectations

- Derive remote project location kind from the host platform
- Skip POSIX-only auth file permission assertion on Windows
- Expect 300s Gemini subagent MCP timeout

* feat(subagent-mcp): add orchestrator thread support (#253)

- Add orchestrator thread manager, tool catalog, and transcript buffering for `create_thread`/`read_thread` flows
- Bridge orchestrator thread creation through main, supervisor runtime, and IPC with persisted thread metadata
- Share worktree branch generation between renderer branch selection and orchestrator thread creation
- Update child thread config inheritance and add integration coverage for subagent MCP behavior

* refactor: split large runtime and service modules (#254)

- Split browser MCP tools, database access, and remote server routing
- Extract agent canonical mappers for ACP, Claude, and Codex
- Break runtime session management into focused services
- Move SingleAgentSettings into component-specific modules

* Refactor thread, remote sync, and supervisor internals (#255)

* refactor(agents): dedupe newItemId into shared contextUsage module

Four byte-identical `${prefix}-${randomUUID()}` copies (claude/codex/acp/opencode)
collapsed into one export on contextUsage.ts. The three provider state/helper
files re-export it so every existing `from "./state"` / `from "./helpers"` import
site keeps resolving; opencode folds it into its existing contextUsage import.

Co-Authored-By: Claude <noreply@anthropic.com>

* refactor(renderer): back panelResizeSignal with a Zustand store

Replaces the hand-rolled `Set<listener>` + manual notify loop with a one-field
Zustand store, matching the store machinery used across the other ~32 renderer
stores. All four public functions (isPanelResizing / beginPanelResize /
endPanelResize / subscribePanelResize) keep identical signatures and behavior, so
ChatPane's imperative transition-subscription (drag-end layout reconcile) and
effect-event read are left unchanged — they are the correct pattern for that
imperative layout work, not a reactive read useSyncExternalStore would replace.

Co-Authored-By: Claude <noreply@anthropic.com>

* refactor(auth): dedupe shouldPreferTerminalLogin into shared acpRegistryAuth

Two byte-identical `status.kind === "grok" && Boolean(status.loginCommand)`
helpers (authHelpers.ts + ThreadAuthRequiredDock.tsx) collapsed into one export
on the shared acpRegistryAuth utils, imported by both call sites.

Pure dedupe — behavior unchanged. The single `kind === "grok"` reference stays
for now: fully removing it needs an adapter-contributed flag routed through the
CapabilitiesProbeResult → AgentStatus detection-engine plumbing, which is
disproportionate to a low-severity leak and is deferred.

Co-Authored-By: Claude <noreply@anthropic.com>

* refactor(agents): remove two dead @deprecated shims

- base/index.ts: drop wrapWslCommand (zero production callers; every real site
  uses buildAgentCommand). base.test.ts is migrated to buildAgentCommand
  (identical signature) — the describe block + 5 call sites renamed.
- opencode/sdkServer.ts: drop disposeOpenCodeServerHandlesForShutdown alias
  (zero callers; the process-exit cleanup already uses the canonical name).

These were the only two @deprecated markers in src/. Removing them keeps the
deprecated signal meaningful.

Co-Authored-By: Claude <noreply@anthropic.com>

* refactor(cursor): consume shared detectTerminalStatusFromHints

Replaces cursor/terminal.ts's hand-rolled "global regex, track last match,
highest index wins" loop with the shared detectTerminalStatusFromHints (the same
findBestHint sweep antigravity/commandcode/opencode/copilot already use). All
three cursor hints are equal-priority, so they ride as strong hints with an empty
fallback — behavior-identical (detectTerminalStatusFromHints slices the same
-1200 tail cursor did). cursor.test.ts (41 tests) stays green.

Co-Authored-By: Claude <noreply@anthropic.com>

* refactor(opencode): split sdkCanonicalMapping into canonicalMapping/ subdir

Mirrors the split commit #254 already applied to the claude/codex/acp mappers:
opencode was the lone holdout with a 1105-line monolith. Extracted 10 focused
domain modules under canonicalMapping/ (readers, fileChangeKind, toolClassification,
toolPayload, permissions, questions, usage, subAgents, textItems, dispatch);
sdkCanonicalMapping.ts becomes a 26-line barrel preserving the exact public
surface (state re-exports + mapOpenCodeEvent + closeOpenItems), so sdkSession.ts
and the 35-case sdkCanonicalMapping.test.ts import unchanged.

Pure file move — no logic edits. Verified: 35 mapper tests + 19 sdkSession tests
green, typecheck exit 0, lint 0/0.

Co-Authored-By: Claude <noreply@anthropic.com>

* refactor(github): extract pure Pr*/GitHub* mappers into githubMappers.ts

Moves the 11 payload-shaping mappers (mapPrState, aggregateChecksStatus,
mapPrData, mapPrAuthor, mapPrCommit, mapPrComment, mapPrReview, mapStatusCheck,
mapPrDetails, parseGhAuthAccounts, mapGitHubApiRepo) out of github.ts into a new
githubMappers.ts leaf module. github.ts imports the four it calls directly
(mapPrData/mapPrDetails/parseGhAuthAccounts/mapGitHubApiRepo) and re-exports the
three public ones, so the module's public surface is unchanged. github.ts drops
from 1035 to 776 lines and now composes over the mappers instead of co-owning
~250 lines of raw payload handling.

Pure move — no logic edits. github.test.ts (57 cases) green, lint 0/0.

Co-Authored-By: Claude <noreply@anthropic.com>

* refactor(projectTree): extract search index into ProjectSearchIndex.ts

Moves the self-contained search subsystem (build/rank/search + LRU cache + the 4
free helpers cacheKeyForSearchConfig/partitionExcludePatterns/expandDirPatterns/
pathHitsIgnoredName) off ProjectTreeService into a new ProjectSearchIndex class,
threaded with its deps (WslBridgeClient, resolveEntryPath callback). projectTree.ts
drops 1106->870; search/rank logic now has an isolatable home with its own cache
so it can be unit-tested (previously zero coverage). Pure structural move —
ranking, cache keying, LRU eviction, and invalidation prefix-matching byte-identical.
projectTree.test.ts (18) green.

Co-Authored-By: Claude <noreply@anthropic.com>

* refactor(state): extract pure reducers out of runtimeEventSlice + threadSlice

Mirrors the supervisor runtime/ split for the renderer slices. Pure reducer
logic (applyRuntimeEventToRuntimeState + coalesce/merge/prune/mergeContextUsage
helpers, ~500L) moves to runtimeEventReducer.ts; thread turn-timing helpers
(parseTurnIso/appendCompletedTurnIfClosed/resolveCompletedTurnAnchorItemId/
deriveTurnTiming) move to threadTurnHelpers.ts. The slice factories stay as thin
wrappers. runtimeEventSlice 933->440, threadSlice 851->739. The i18n macro user
(terminateSubAgentItem) and the runtimePersistenceDirtyListeners set stay behind
(not pure). runtimeEventSlice.test.ts (24) + appStore.test.ts (56) green.

Co-Authored-By: Claude <noreply@anthropic.com>

* refactor(ChatPane): extract tool-categorization into pure toolCallCategorization.ts

Moves the pure categorization/summarization cluster (categorizeItem/ToolName/
CommandExecution/VerbPrefix/PersistedSummary, summarizeToolCalls/SameFileEditGroup,
GroupCategory/CategoryMeta/CATEGORY_META/SUMMARY_CATEGORY_LABELS, isToolGroupItem/
isToolLikeItem, normalizeEditGroupPath/readEditGroupPath) plus the shared payload
readers (getToolLikePayload, readCommandPayloadCommand, isEditLikeToolPayload) out
of ToolCallGroup.tsx into a React-free toolCallCategorization.ts, with a new
focused unit test (12 cases). ToolCallGroup.tsx drops 965->660 and imports the
pure module one-directionally (no cycle). Behavior-preserving; the row builders +
their helpers stay in the .tsx. ToolCallGroup.test.tsx (23) green.

Co-Authored-By: Claude <noreply@anthropic.com>

* test(threadSession): unit-test cliHookArgs argv-merge helpers

Adds cliHookArgs.test.ts covering mergeCliHookExtraArgs across the codex
launch/resume/resume+prompt, claude with/without prompt, and generic-fallback
matrix, plus applyClaudeMergedSettingsRewrite's passthrough branches and the
--settings swap (with prepareClaudeMergedSettingsFile mocked). These helpers
decide the final argv on every spawn and resume; this is the safety net for the
deferred spawn-pipeline extraction.

Co-Authored-By: Claude <noreply@anthropic.com>

* refactor(supervisor): rename runtime.ts -> supervisorRuntime.ts

Breaks the file-vs-directory naming collision: src/supervisor/runtime.ts sat
beside src/supervisor/runtime/, so "@/supervisor/runtime" was ambiguous to grep,
go-to-definition, and newcomers. The SupervisorRuntime god-facade is now
supervisorRuntime.ts; "@/supervisor/runtime" unambiguously means the directory.
Updates 6 importers. The wsl/runtime module is unrelated and untouched. Pure
rename; typecheck green. The full dissolve of the delegate facade (~110 one-line
delegates) is deferred (requires reworking 31 integration tests + the typed
SupervisorIpcHandlerMap).

Co-Authored-By: Claude <noreply@anthropic.com>

* refactor(acp): extract terminal subsystem into terminalManager.ts

Moves the 9 ACP terminal handlers + the 4 per-session terminal-state maps off
AcpStructuredSession into a new AcpTerminalManager, injected via a context
{ projectLocation, cwd, assertRequestSession }. session.ts drops 1583->1425.
The records/env helpers (sessionTerminal.ts, sessionTerminalLaunch.ts) were
already extracted; only the handler bodies moved. Manager never imports session
(one-directional). Behavior-preserving; session.test.ts (62) +
canonicalMapping.test.ts (47) green.

Co-Authored-By: Claude <noreply@anthropic.com>

* refactor(composer): extract ThreadComposerDocks + model-picker helpers

Pulls the 9-dock fixedContent tree into a new presentational ThreadComposerDocks
component (receives visibility flags + data + callbacks as props) and moves the
pure normalizeCursorComposerConfig/buildControls into the existing
buildModelPickerControls.tsx. ThreadComposerSection.tsx drops 1112->945;
submitPrompt and its closures stay (deferred). Pure component/config extraction
— JSX, prop names, ordering, and Lingui macros preserved verbatim.
ThreadComposerSection.test.tsx (25) green.

Co-Authored-By: Claude <noreply@anthropic.com>

* refactor(usage): replace providerId switch with a resolver map

createNativeCredentialStore's getOAuthToken/refreshOAuthToken switches over
providerId across the 8 providers; replace with in-file Record<providerId,
resolver> tables. Adding a usage-tracked provider is now a one-line registration
(factory/zai have no adapter, so this stays in-file rather than
adapter-contributed). Behavior-identical; resolveFactoryCliToken (sync) is
wrapped so every entry shares the () => Promise<OAuthToken | undefined> shape.

Co-Authored-By: Claude <noreply@anthropic.com>

* refactor(ChatPane): extract ChatScrollControls into its own module

Moves the ~307-line ChatScrollControls forwardRef (+ ChatScrollControlsHandle +
USER_SCROLL_INTENT_MS) out of ChatPane.tsx into ChatScrollControls.tsx.
ChatPane.tsx drops 926->597; the trailing helpers stay (none are referenced by
the scroll component). Pure component extraction — exact body, props, ref
handle, and scroll math preserved; the lone Lingui aria-label traveled with the
JSX. ChatPane.test.tsx (41) green.

Co-Authored-By: Claude <noreply@anthropic.com>

* refactor(state): break renderer/mobile import cycle via shared remote/ module

Relocates the desktop-shared snapshot primitives (applyThreadSnapshot,
dispatchRemoteSupervisorEvent, collectRuntimeEventsFromSupervisoryMessage,
shouldReplaceRuntimeItemsFromSnapshot) from @/mobile/storeSync into a new
src/renderer/state/remote/ module, killing the @/mobile -> @/renderer/state ->
@/mobile cycle (grep -rn "@/mobile" src/renderer is now empty). Resolves the
TODO(phase-4) at remoteServersStore.ts:26.

The mobile fan-out (emitTerminalReset/Exited, notifyLiveActivityThreadState,
useGitSummariesStore) is split from the core mutation via RemoteDispatchHooks:
the shared core runs the state mutation then fires optional hooks; mobile wraps
the core with its hooks, desktop calls it with none. Behavior identical on both
paths (mobile side-effect ordering preserved; desktop fan-outs were already
inert). storeSync.ts 316->99. remoteServersStore.test.ts (32) + mobile (193) +
app.test.tsx (14) green.

Co-Authored-By: Claude <noreply@anthropic.com>

* refactor(thread): move submit/server-request/config actions out of the view chain

Extracts onSubmitInput / onResolveServerRequest / onConfigChange from the
ThreadPane -> ThreadView -> ThreadComposerSection prop-drilling chain into
src/renderer/actions/threadRuntimeActions.ts (sibling to threadActions.ts),
taking (threadId, ...) and reading useAppStore.getState() + readBridge().
ThreadComposerSection invokes them directly; ThreadPane/ThreadView/ThreadContent
drop the handler props. The submit action is a byte-equivalent lift of
ThreadPane.onSubmitInput (optimistic paint, working-state flip,
captureFileCheckpoint, sendThreadInput, error rollback forceCloseActiveTurn,
analytics, touchThread) — now reachable for unit testing instead of buried in
an untested view-wiring file. ThreadPane.tsx 226->130.

Mobile dedup deferred (sendPrompt in useRemoteDesktop.ts needs a transport seam
+ dock-collapse notification that don't compose cleanly with the shared core).
ThreadView (24) + ThreadComposerSection (25) + app.test.tsx (14) + mobile (12)
green.

Co-Authored-By: Claude <noreply@anthropic.com>

* refactor(thread): centralize thread runtime project resolution

- Remove mobile server request prop plumbing
- Let composer docks call runtime actions directly
- Reuse shared project location resolution across thread views

---------

Co-authored-by: Claude <noreply@anthropic.com>

* refactor(chat): unify tool activity row styling (#256)

- Add shared chat row primitives for tool and workflow items
- Adjust Moonlight text and active row contrast

* Refactor runtime and provider adapter boundaries (#257)

* refactor(supervisor): extract SpawnPipeline and StructuredTurnQueue from threadSessionManager

Finishes the split started in #254: the ~800-line spawn orchestration core
moves out of the 2,092-line threadSessionManager into two focused modules.

- threadSession/spawnPipeline.ts: startThreadInner, restartThread,
  spawnThread (runtime-session assembly + listener wiring),
  createStructuredSession, browser/subagent MCP launch resolution, and a
  single composeLaunchOptions replacing the launchOptionsWith* trio. The
  manager keeps session bookkeeping, terminal I/O, dispose, and
  invalid-session-ref recovery, wired in via SpawnPipelineContext.
- threadSession/structuredTurnQueue.ts: startStructuredTurn, the queued
  launch-prompt drain, and the optimistic user_message paint.
- Manager shrinks 2,092 -> 1,026 lines with behavior unchanged; the
  test-only spawn seam in supervisorRuntime now goes through an explicit
  spawnThreadForTests delegate instead of a private-method cast.

Enabler tests written before the extraction:

- threadSessionManager.restartTerminal.test.ts: terminal/PTY restart via
  buildResumeArgv, CLI-hook-extras argv/env merge, the kept structured
  session on server-controlled terminal restarts, and all 8
  isCurrentSession() race-guard branches in restartThread.
- threadSessionManager.recoverInvalidSession.test.ts: dispose -> kill ->
  respawn ordering, fresh buildLaunchArgv without the stale sessionRef,
  recovery idempotence, and the 4 race guards.

Fixes a latent ordering bug the recovery tests exposed: handlePtyData
flipped launching -> idle before both detectInvalidSessionRef checks (which
require status launching), so invalid-session-ref recovery could never
trigger from PTY output. Detection now runs before the flip via
detectsInvalidSessionRefOnLaunch; the two dead inline checks are removed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* refactor: move provider-specific branches behind the adapter/capability contract

Removes per-provider if/else from shared runtime, contracts, and renderer
code; each provider now contributes the behavior through its adapter or
registry entry. Seven serialized changes, smallest first:

1. terminalEnv iTerm2: getIterm2StatusL2TerminalEnv keys off the adapter —
   partialL1 (Copilot) keeps the spoof unconditionally, and a new
   AgentTerminalObserver.spoofsIterm2StatusEnv flag (Claude, Gemini)
   replaces the agentKind switch. Claude profiles now inherit the spoof via
   the shared factory (the old strict kind check missed them).
2. grok preferTerminalLogin: probe-reported via CapabilitiesProbeResult →
   AgentStatus.preferTerminalLogin; shouldPreferTerminalLogin reads the
   status flag instead of kind === "grok". STATUS_CACHE_VERSION → 5.
3. cliHookArgs: new AgentLauncher.extraArgsPosition (default append) and
   rewriteLaunchArgsForConfig hooks; codex/claude implementations live in
   their argv modules and the codex/claude branches in
   threadSession/cliHookArgs.ts are gone (isClaudeAdapterKind deleted).
4. browserMcpScope/subagentMcpScope: adapter-declared per-presentation
   scopes on AgentCapability; both renderer shadow tables deleted. Absent
   scopes default to the old generic mapping (terminal none / gui launch).
5. SingleAgentSettings: antigravity/claude/opencode branches collapse into
   NATIVE_AGENT_REGISTRY_ENTRIES via settingsPanel / ownsAuthUi /
   accountResolver slots; the settings sidebar nests instance-scoped kinds
   under their installed base agent generically instead of hardcoding
   Claude profiles.
6. Antigravity RPC: getAntigravityAccount → resolveAgentAccount(agentKind)
   backed by a new AgentDetector.resolveAccount hook (renamed end-to-end
   across contracts, procedures, ipcHandlers, runtime, renderer, with a
   per-kind account cache); the four antigravity*.ts runtime modules move
   into agents/antigravity/.
7. UsageService: Claude profile collection, the estimated-cost merge, and
   the auth-miss stale-while-revalidate rule extracted into
   agents/claude/claudeUsageProfiles.ts with semantics preserved verbatim
   (auth-miss after a prior displayable read returns the previous snapshot
   unchanged, old fetchedAt included, so the poller keeps retrying).

Gate: grep for kind === "<provider>" in src/shared, src/renderer, and
src/supervisor/runtime is clean (remaining cursor model-id migration logic
in buildModelPickerControls is out of scope; the ModelVisibilityDropdown
cursor label became a showProviderLabel prop driven by provider count).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* refactor: consolidate cross-provider dedupes behind shared modules

- readStringField: five per-provider variants collapse into one shared
  reader in fileChangeSummary.ts. New pinned semantic (fileChangeSummary
  .test.ts): trimmed, blank-as-absent, first matching key wins. Codex
  call sites move from the raw value-based variant to the keyed form,
  so codex cwd/path/optionId values are now trimmed and empty strings
  fall through to fallbacks.

- inferFileChangeKind: the ACP implementation is promoted to a shared
  agents/fileChangeKind.ts consumed by acp, codex, and opencode. The
  mixed-structured-changes divergence is decided as edit (codex
  semantic) and pinned in fileChangeKind.test.ts; modify/move types,
  the direct `type` field, and args/input recursion are unified in.

- panelStore, sidebarUiStore, sidebarOverlayStore now persist via
  zustand persist(createJSONStorage(localStorage)) with versioned
  envelopes and partialized slices (git review context, drawer width,
  collapsed projects, sidebar collapsed). Legacy hand-rolled keys stay
  as the initial seed so existing installs keep their state.
  sharedSettingsStore (two-tier) and gitStore (TTL) are untouched.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* refactor: dissolve runtime facade, dedupe mobile submit and model labels

- SupervisorRuntime facade dissolved: the service cluster (git, github,
  checkpoints, project tree, file index, registry, usage, generation,
  threads, lsp, hook plugins) is public and createSupervisorIpcHandlers
  maps IPC procedures straight onto the services with payload unpacking
  inline. The runtime keeps only wiring plus genuine cross-service
  orchestration (worktree removal/prune, relocate, sync, project
  snapshot, setup-script detection, clone, dispose) and the test seams.
  supervisorRuntime.ts drops from 1,352 to ~660 lines. The 31 runtime/
  auth/status-cache/providers-lifecycle integration tests now target
  runtime.threadSessionManager / agentRegistryService /
  agentStatusService directly.

- Mobile onSubmitInput dedup: performThreadInputSubmit in
  threadRuntimeActions is the single submit core (optimistic paint,
  working flip, rollback, touch) with the transport injected — desktop
  passes the IPC bridge + checkpoint capture, the PWA passes the remote
  desktop client. It rejects on failure so the mobile dock-collapse
  wrapper still only fires on successful sends.

- ThreadComposerSection submitPrompt (~150 lines) extracted to
  threadComposerSubmit.ts behind a ComposerSubmitContext param object;
  the component builds the context per call.

- Cursor/codex model-label formatting consolidated into
  src/shared/modelLabels.ts (bracket params, Codex-family names, Cursor
  base labels) — used by ProviderModelMenu, sub-agent progress chips,
  and the supervisor Cursor ACP capability builder; menu labels gain
  the Claude/Gemini-family names the supervisor already produced.

- threadOutputPipeline: branch tests pin the launch-time invalid
  session-ref detection (fires before the launching-to-idle flip, gate
  conditions, prevChunk combination, home-cursor slicing).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* perf(renderer): persist only changed store slices

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>

* feat(mobile): mobile app hardening, security fixes, and architecture pass

Five review loops over the mobile PWA plus follow-up architecture work:

- ~34 verified fixes with regression tests: remote-transport recovery/coalescing,
  deep-link pairing now requires explicit confirmation, transactional desktop
  storage, push lifecycle (desktop-switch fingerprint reset, cancel guards,
  unregister-on-unpair), view data-loss/race fixes (FilesView save, ThreadView
  reload, BrowserView backfill)
- God-file splits: RootLayout -> NarrowShell/WideShell/useHeldThreadHeader/chrome,
  FilesView -> useFileTree/useOpenFile, shared keyboardFocusShared core,
  threadSearch/threadGrouping helpers
- remoteContext split into remote-session + chrome contexts so scroll-driven
  chrome state no longer re-renders every route
- tokenVault: bearer tokens at rest in the OS keystore on native, WebCrypto
  AES-GCM (non-extractable key) on web, with lazy migration off plaintext rows
- remote server: /api/git/call requires bearer auth before body parse/allowlist
  (closes a pre-auth enumeration oracle)
- plus in-progress next-branch staging work (renderer chat/git-review polish,
  main-process db/persistence, mobile dev tooling and docs)

Native shells (android/, ios/) intentionally left uncommitted pending a
.gitignore decision.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* chore(mobile): track Capacitor native projects (android/, ios/)

Only real project sources (~1.1 MB / 80 files): manifests, Gradle and Xcode
configs, MainActivity + PushSupportPlugin, icons and splash assets. Build
outputs, Pods, copied web assets, local.properties, and generated Capacitor
configs stay untracked via the template .gitignore files inside each dir.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(ios): register secure-storage plugin in SPM manifest via cap sync

cap sync picked up @aparajita/capacitor-secure-storage (added for the token
vault) into CapApp-SPM/Package.swift; without it the iOS build would not link
the keystore plugin. Also verified all native-project generators are
idempotent: build-native-assets.mjs and configure-mobile-native.mjs reproduce
tracked files byte-identically, and a second cap sync produces zero churn.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* feat(browser): add external Chrome MCP support (#258)

- Add Chrome extension, bridge server, external connection, and release workflow
- Wire Chrome MCP thread identity through supervisor and Claude sessions
- Add browser tab groups, group controls, localized labels, and IPC procedures
- Improve CDP tooling, screenshots, cursor overlay, and localhost handling
- Cover browser manager, external Chrome, UI, and shared helper behavior with tests

* fix(android): resolve Windows ADB and run debug APK

* fix(sidebar): handle manual group collapse defaults (#259)

- Default manual thread groups to expanded while worktrees stay collapsed
- Include collapsed groups when switching to adjacent threads

* feat(renderer): show unsent draft markers in sidebar (#260)

- add a shared draft-non-empty check and reuse it across composer and sidebar logic
- render an unsent-draft indicator for thread rows and the new thread button
- update sidebar item tests and localized strings for the new indicator

* feat(remote): add port forwarding support (#261)

- Add remote port-forward gateway, proxying, and protocol support
- Expose port forwarding in the mobile shell and Ports view
- Update relay and headless host handling plus test coverage
- Add localized strings for the new port forwarding UI

* fix(mobile): resolve iOS target and keyboard offsets

- add a target-resolving iOS Capacitor runner to avoid the interactive picker
- split mobile keyboard geometry into lift and visibility offsets
- adjust Android keyboard handling, layout, and composer positioning
- update mobile viewport behavior, docs, and SwiftPM dependency state
- add tests for keyboard geometry, composer docks, and thread views

* Refresh mobile UI, i18n catalogs, and website tooling (#263)

* chore: refresh mobile UI, i18n, and website tooling

- Update mobile shell, thread, PR, and dock interactions
- Localize and clean up renderer copy, layouts, and dialogs
- Rework website lint/typecheck setup and dependency locks

* fix(website): define webpack @ alias explicitly for Vercel builds

With typescript@7 installed, Next cannot read tsconfig paths for the
webpack build (needs the TS JS API, absent until 7.1), which broke the
Vercel deployment (vercel.json builds with --webpack). Define the alias
in next.config.js and acknowledge it with an empty turbopack config.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(website): satisfy Next's TS7 detection on isolated Vercel installs

Next's build-time TypeScript step requires the TS6 JS API and aborts
with typescript@7 unless it resolves @typescript/native-preview, its
native-compiler marker. Locally that resolved from a stale parent
node_modules; on Vercel's isolated install it did not, failing the
deploy. Alias @typescript/native-preview to the same GA typescript@7
package, and run the native tsc typecheck in the Vercel build command
since Next now skips build-time checking.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>

* fix(git): preserve staging status and decode quoted paths (#262)

- Force `core.quotepath=false` on git execs and unquote C-escaped paths in status parsing.
- Reconcile staged/unstaged status after `git add`/`git reset` so summary polls don't regress optimistic updates.
- Update git store refresh logic to sum staged stats correctly and cover the new behavior with tests.

* fix(mobile): keep compose dock clear of keyboard

* fix(git): make pull strategy explicit

- use `--no-rebase` for regular pulls
- add tests covering merge and rebase pull commands

* Dependency major migrations: Electron 43, ACP SDK 1.1, dnd-kit 0.5, jsonrpc 9 (#264)

* chore: refresh mobile UI, i18n, and website tooling

- Update mobile shell, thread, PR, and dock interactions
- Localize and clean up renderer copy, layouts, and dialogs
- Rework website lint/typecheck setup and dependency locks

* fix(website): define webpack @ alias explicitly for Vercel builds

With typescript@7 installed, Next cannot read tsconfig paths for the
webpack build (needs the TS JS API, absent until 7.1), which broke the
Vercel deployment (vercel.json builds with --webpack). Define the alias
in next.config.js and acknowledge it with an empty turbopack config.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(website): satisfy Next's TS7 detection on isolated Vercel installs

Next's build-time TypeScript step requires the TS6 JS API and aborts
with typescript@7 unless it resolves @typescript/native-preview, its
native-compiler marker. Locally that resolved from a stale parent
node_modules; on Vercel's isolated install it did not, failing the
deploy. Alias @typescript/native-preview to the same GA typescript@7
package, and run the native tsc typecheck in the Vercel build command
since Next now skips build-time checking.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* chore(deps): dedupe vscode-jsonrpc onto v9

vscode-languageserver-protocol 3.18.2 already depends on
vscode-jsonrpc 9.0.1; bumping our direct ^8.2.1 removes the duplicate
major. Only consumer (supervisor LSP serverInstance) uses an unchanged
API surface.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* chore(deps): bump @dnd-kit packages to 0.5.0

Additive release (independent drag/drop disabling, optimistic sorting
with non-contiguous indexes, overlay flicker fix); no API changes in
our usage.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* feat(acp): migrate to @agentclientprotocol/sdk 1.1.0

SDK 1.x removes the pre-1.0 @experimental model surface
(models/unstable_setSessionModel) that cursor-agent still speaks. Add a
single compat module (unstableModelCompat.ts) that reads the unofficial
models field via unknown-narrowing and sends session/set_model through
the SDK's raw request passthrough; configOptions "model" remains the
primary path. Handshake and protocol version unchanged; verified live
against installed cursor-agent (30 models, set_model accepted).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* feat(electron): upgrade to Electron 43

Node 24.17 / Chromium 150. No app code changes needed (42/43 breaking
changes audited: notification backend, OSR scaling, clearStorageData
quotas, dialog defaults — none used). ensure-native-deps already covers
the 42+ postinstall binary-download removal. Native modules rebuilt and
verified; react-devtools electron override retargeted; stale age-guard
exclusion removed. Runtime-smoke-tested: window, sqlite open, PTY
round-trip, zero console errors.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* build(deps): refresh ACP and UI package versions

- bump agentclientprotocol, claude-agent-sdk, HeroUI, Electron, and related types
- update workspace release-age allowlist and regenerate the pnpm lockfile
- align ACP elicitation normalization with the newer SDK helpers and request shape
- update session tests for enum item schemas and Claude request IDs

* fix(website): update dependency lockfile

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>

* fix(renderer): discard replaced draft content on project switch (#265)

- Clear stale draft state when opening another project’s draft or switching projects
- Preserve ordinary draft unmount saves while honoring explicit discard requests
- Add coverage for thread actions and slash-command composer behavior

* fix(chat-pane): align hover affordance for expandable rows (#266)

- Reuse the shared chat row hover class in tool call disclosures
- Switch expandable rows to foreground text highlighting on hover

* fix(renderer): drop transient error items from runtime snapshots (#267)

- Exclude error items during runtime snapshot persistence and hydration
- Add regression coverage for stale errors not resurfacing on reopen

* fix(renderer): treat bottom side tabs as git eclipse (#268)

* fix(chat): stabilize chat scrolling and collapsed item layouts (#269)

- refine scroll geometry and fade handling to avoid re-sticking and jitter
- cache collapsed headers and user-message overflow measurements across remounts
- batch runtime event application and update thread goal/todo state selection
- add coverage for scroll controls, geometry, collapsed headers, and runtime events

* fix(claude): sync model changes before steer turns (#270)

- apply live model updates in a shared helper for turn start and steer paths
- add coverage for steerTurn using a newly changed model on the next turn

* fix(grok): support Grok 0.2 session IDs and model ids (#271)

- switch conflict resolution to `grok-4.5` and forward effort for one-shots
- replace ACP session minting with native `-s`/`-r` session args
- update detection and session-file handling for `GROK_HOME`
- add coverage for argv, detection, session materialization, and adapter commands

* feat(codex): surface usable Fast-mode support in model menu (#272)

- Detect Fast-capable Codex models from probe metadata
- Pass the usable fast-mode flag through to provider model rows and UI hints
- Add coverage for Codex model detection and model menu shortcut labels
- Localize the new Fast-mode support label across all renderer catalogs

* fix(acp): defer unnamed tool calls and recover Cursor labels (#274)

- Stop fabricating tool names for bare ACP calls so the renderer can hide
  unnamed rows until a real label arrives
- Guarantee terminal tool calls get a name on completion so they cannot stay
  hidden
- Recover missing `title`/`kind` from Cursor `_toolName` metadata and cover the
  mapping with tests

* Add computer-use MCP for desktop control across providers (#273)

* feat(computer-use): add desktop-control MCP across providers

Port PR #142 onto the current runtime. Adds an Electron main-process
computer-use MCP (screenshots, window enumeration, input) with macOS and
Windows drivers, served over the shared StreamableHttpMcpIngress. Threads a
per-thread `computerUse` opt-in from composer through launch into every
provider's MCP wiring (claude/codex/gemini/opencode + all ACP providers),
with full parity across structured, terminal, and resume/recovery paths.

- Bind the computer-use ingress to 127.0.0.1 only (host input control must
  never be LAN/WSL reachable); browser ingress bind unchanged via bindHost.
- Disable computer use for WSL projects (loopback unreachable by design).
- Localize the new composer strings across all 12 catalogs.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix(computer-use): harden driver correctness, ergonomics, and security

Round 1 of critic-driven fixes across the ported computer-use MCP.

Windows driver: reliable window activation (AllowSetForegroundWindow +
alt-key + AttachThreadInput, retry, post-activation focus verification —
fail fast instead of typing into the void); stop SW_RESTORE un-maximizing
windows and re-capture the rect after activation so click coordinates match
the screenshot; honor the VkKeyScan shift bit so press_key types capitals
and shifted symbols; keep UTF-16 surrogate pairs intact when typing;
per-monitor DPI awareness; launch_app resolves and returns the new window
(bounded poll) and rejects UNC/URL targets; release stuck modifiers/mouse
on error; reject non-numeric coordinates instead of coercing to (0,0).

Registry/ergonomics: drop the always-failing set_value and
perform_secondary_action tools and the never-populated accessibility
fields; require app on get_window; document coordinate origin and
window-refresh recovery in tool descriptions.

macOS: honor mouse_button (no more silent left-click), horizontal scroll,
report real Retina pixel dimensions, and derive a move-stable window id
(flagged for on-device verification).

Security: scope the computer-use token to opted-in launches (was leaked
into every child process env), gate the ingress to supported platforms,
constant-time token comparison, Host-header allow-list, and unify the
provider MCP builders behind an internal enabled check.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* perf(computer-use): persistent PowerShell host + smaller screenshots

The Windows driver spawned a fresh powershell.exe per action, recompiling
the inline C# shim (Add-Type) every call — ~300ms of the ~425ms per-action
cost. Replace it with a long-lived host: compile once at startup, then serve
newline-delimited JSON requests over stdin/stdout with a correlated request
queue, per-request timeout (kill+respawn on hang), crash/exit recovery, and
disposal on ingress teardown. Steady-state per-action latency drops to
~75ms (cheap actions ~40x faster); concurrent requests serialize safely
over the single pipe.

get_window_state gains max_dimension (default 1280, aspect-preserving) and
format (jpeg default q75, png opt-in), reporting the true encoded pixel
dimensions and the downscale factor for coordinate mapping. A large-window
capture drops from ~9.5MB PNG to ~80KB JPEG while staying legible.

Adds dispose() to the driver interface (no-op on macOS/unsupported).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* feat(computer-use): add desktop overlay and chrome MCP routing

- Add the desktop overlay and interactive computer-use result plumbing for main-process ingress.
- Route Chrome MCP config across ACP, Codex, Gemini, and OpenCode sessions and installers.
- Track remote desktop host platform metadata and persist it through mobile storage and sync.
- Update composer mention/scoping, shared settings, and diagnostics for the new computer-use flow.

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>

* refactor: split provider, remote, and session runtime plumbing

- Extract provider manifests/registry/composer/slash-command helpers
- Add desktop remote access controller and mobile socket coordination
- Refactor ACP, Codex, OpenCode, and thread session lifecycle handling
- Rework git status parsing and Windows path normalization
- Refresh interactive-testing docs/scripts, lint rules, and i18n catalogs

* feat: improve startup, subagents, and chat UX

* Show inline reasoning previews while streaming (#275)

* feat(chat-pane): add inline reasoning previews and streaming viewports

- Fold reasoning into adjacent tool-call groups
- Add stick-to-bottom streaming behavior and preview extraction
- Expand chat pane coverage and localization references

* perf(chat-pane): optimize grouped row rendering and reasoning streams

- Reuse shared reasoning expansion and inline-row presentation
- Optimize virtualized streaming measurement and preview truncation
- Centralize tool-call category label derivation and grouping logic

* feat(quick-composer): add global shortcut composer window (#277)

- Add quick composer overlay with configurable global shortcut
- Harden window lifecycle, geometry, startup, tray, and IPC handling
- Suspend global shortcuts while composing and sync agent statuses
- Update settings, keybindings, localization, smoke scripts, and tests

* Add SSH remote desktop connections for mobile (#276)

* feat(mobile): add SSH remote desktop connections

- Add cross-platform native SSH bridge and secure credential storage
- Support remote runtime installation, pairing, forwarding, and terminal feeds
- Add SSH connection management UI and remote project workflows
- Update mobile builds, IPC, localization, and test coverage

* refactor(remote): share SSH bootstrap and terminal feed logic

- centralize remote thread appearance polling and terminal streaming
- optimize SSH runtime bundle staging and simplify connection flows
- extract remote Git metadata parsing and clean up session recovery state
- remove obsolete exports and unused provider integrations

* fix(thread): hide runtime debug controls in production

* feat(schedules): add scheduled tasks and app control MCP tools (#278)

- Add schedule persistence, execution, IPC, remote APIs, and UI
- Integrate app control MCP servers across supported providers
- Extend mobile navigation, permissions, localization, and smoke coverage
- Add tests for scheduling, remote access, MCP tools, and runtime flows

* fix(ui): exclude React Aria components from global focus ring

* feat(mcp): add configurable MCP server management and integration (#279)

- Add project and global MCP server settings with import, OAuth, probing, and validation
- Persist MCP configuration across shared settings, projects, IPC, remote access, and databases
- Integrate user MCP servers with supported agent adapters and session launch flows
- Add WSL probe packaging, build dependencies, localization, and comprehensive tests

* feat(codex): route and render sub-agent events

- Add Codex sub-agent routing and runtime event handling
- Update ChatPane progress, tool calls, reasoning, and overlays
- Expand coverage for mapping, routing, and UI behavior
- Update localized ChatPane messages

* fix(codex): unwrap Codex Apps MCP calls to inner apps (#280)

* fix(codex): identify rate-limit windows by duration

* feat(skills): add cross-provider skill management and injection (#281)

- add skill import, marketplace, settings, contracts, and supervisor service
- support provider skill roots, slash-command serialization, and prompt injection
- add MCP tool filtering, built-in tool controls, and WSL/remote packaging
- expand composer, MCP management, smoke coverage, and localized UI

* feat(rebrand): migrate Lightcode to Poracode (#282)

BREAKING CHANGE: Rename app identifiers, namespaces, packages, paths, IPC
channels, environment variables, plugins, and native mobile targets to Poracode.

* fix(codex): support WSL image view payloads and stabilize tests

* feat(website): improve localized homepage and social metadata

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant