* feat(providers): remove custom providers from settings
Add a destructive removal flow so mistaken custom providers can be deleted from config.json instead of only disabled.
* test(app): cover provider removal with e2e
Move provider removal coverage out of mocked component tests and into the real Settings flow.
* fix(providers): keep removal live after config updates
* fix(settings): show daemon update failures
React Native web ignores Alert.alert, so failed remote updates reset to an enabled button without any user-visible explanation. Keep updater progress and failure as explicit rendered state, including the daemon's error, and cover the real browser-to-daemon failure path.
* test(settings): harden daemon update regression
* fix(settings): disable Desktop-managed daemon updates
Desktop-bundled daemons advertised npm self-update even though the install-origin checks always rejected it. Report Desktop ownership to clients, render actionable guidance, and refuse stale requests before touching npm.
* feat(desktop): share persistent browser data across tabs
Keep browser sign-ins and site storage across tabs and app restarts, with a Settings action to clear the shared profile.
* fix(settings): prevent duplicate browser data clears
* fix(desktop): complete browser data cleanup
Clear legacy per-tab profiles after upgrades and localize the browser data settings in every supported language.
* fix(desktop): close browser profile cleanup races
Individual tool outcomes remain visible in the expanded list. The aggregate header no longer treats a handled tool result as a failure of the overall work.
* feat(subagents): archive finished children and show native names
Keep native provider sessions intact while letting users clear completed children from the track. Persist dismissed provider child IDs so history replay does not restore them.
* fix(subagents): cover persistence and naming edge cases
* fix(subagents): preserve active descendants and native names
* fix(subagents): retain dismissed timelines and trim paths
* fix(subagents): retain history across hydration
* test(subagents): expect normalized native descriptions
* fix(subagents): separate hidden rows from retained history
* fix(subagents): preserve restored hidden tabs safely
* fix(subagents): integrate archive with run state
* test(codex): expect normalized child name
* fix(subagents): retain dismissed tabs on reload
* fix(subagents): hide finished native agents locally
Keep the header action presentation-only so it does not mutate agent lifecycle or expand the runtime protocol.
* fix(subagents): humanize native agent names
* fix(subagents): preserve names in Codex history
* fix(subagents): retain hidden rows across reloads
* feat(app): refine tool call summaries and scrolling
Keep summary groups stable from the first tool call, preserve live activity feedback, and scroll expanded groups to the latest entry. Consolidate web scrollbar styling around the native browser mechanism.
* refactor(app): reuse tool call height constant
* fix(app): preserve tool call summary state
* fix(app): refresh web tool groups on expand
* fix(app): preserve grouped tool errors
* feat(ui): improve changelog and help navigation
Make release notes easier to scan and reach from the app. Also keep the homepage marquee within the layout viewport so it cannot create horizontal scrolling.
* fix(website): reject duplicate release anchors
* feat(app): add sidebar help and support menu
Give users a single place to run diagnostics, find shortcuts, and reach the support channels. Share one global diagnostic sheet between Settings and the sidebar so both entry points collect the same report.
* fix(app): keep cloned workspace navigation atomic
A newly merged clone flow still used the previous navigation signature and opened its draft tab separately. Route the cloned workspace and its draft target through the unified navigation command so attention selection cannot replace the intended tab.
* test(app): harden sidebar help coverage
Accept both the Discord invite URL and its canonical redirect, assert placement through real element geometry, and remove an unnecessary diagnostic-host callback.
* test(app): cover support redirect variants
Keep the help-menu E2E stable across prerelease versions and the valid redirect forms returned by Discord and GitHub.
* feat(app): pin projects to top of the sidebar
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat(app): dedicated Pinned sidebar section with UX fixes
Replaces the invisible float-in-place pinning with a Codex-style Pinned
section at the top of the sidebar that hoists pinned chats and projects.
- Pin-aware keyboard shortcut numbering (badges match visual order)
- Pinned chats show their project name as subtitle (context after hoisting)
- Pinned entries ordered most-recently-pinned first
- Collapsible Pinned section (persisted)
- Double-click guard on workspace pin toggle
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat(app): move Pinned section above the Workspaces header
Pinned now sits at the top of the scroll, above the "Workspaces" section
header (which moves into the scroll below it), matching the market-standard
sidebar layout. Chevron sits beside the "Pinned" label.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat(app): reveal Pinned collapse chevron on hover only
Extracts PinnedSectionHeader with its own hover state; the chevron hides
until hover on web and stays visible on touch/compact.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat(app): pin the active chat via keyboard shortcut and inline pin button
Adds a ⌘⇧P / Ctrl+Shift+P shortcut that pins the selected chat, mirroring
the worktree.archive action across actions/dispatcher/route-shortcut, gated
by `selected && supportsWorkspacePinning`. Also surfaces an inline pin button
on row hover (always-on for touch) alongside the kebab in the shared trailing
overlay, swapping Pin/PinOff by pinned state.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* refactor(server): unify project and workspace pin handlers
Collapses the two near-identical pin.set handlers into a shared
handlePinSetRequest that owns control flow, error handling and the
workspace-update fan-out; each caller only supplies its registry apply
step and typed response payload.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(app): drop empty pinned project shells and empty Workspaces header
Pinning every chat of a project hoisted them into Pinned but left an empty
project header (plus its new-workspace ghost row) below, duplicating the
project. Skip projects emptied by pinning while keeping genuinely empty
projects. Also hide the "Workspaces" section header when no unpinned projects
remain, so it no longer floats above nothing.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(protocol): correct workspacePinning COMPAT version to v0.1.105
Feature ships in 0.1.105 per the changelog, not the placeholder v0.1.103.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(app): hide redundant chat pin control inside pinned projects
A pinned project already hoists all its chats to the top, so the per-chat pin
was a no-op that just toggled a dead icon. Suppress the inline pin button, the
kebab pin item, and the pin keyboard shortcut on chats whose project is pinned;
they still work for chats in unpinned projects.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(app): hide project pin control on empty projects
Project pin state is derived from workspace descriptors, so a project with no
workspaces would set pinnedAt on the server but emit no descriptor update — the
pin silently never surfaced and the user got no feedback. Offer the pin only
once the project has a chat, matching how chat pins are suppressed inside
already-pinned projects.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(app): drop collapsed Pinned rows from keyboard shortcut numbering
When the Pinned section is collapsed its chats and projects are hidden, but the
shortcut model kept counting them: visible unpinned rows showed off-by-N badge
numbers and pressing a number key jumped to a hidden pinned chat. Exclude the
pinned rows from numbering when Pinned is collapsed, matching what renders.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(app): hydrate pinned sidebar rows
* fix(app): keep filtered workspace controls reachable
* feat(app): scope sidebar pinning to chats, drop project pinning
Per PR review: pinning whole projects overlapped with project reordering
and mixed projects into the pinned list. Keep chat pinning only.
- Remove the project.pin.set RPC, its server handler, the projectPinnedAt
descriptor field, and the client setProjectPinned method.
- Drop the project pin control, isProjectPinned reads, and the suppressPin
plumbing (its only source — a pinned project — is gone).
- Fold pin-aware shortcut ordering into SidebarModelProvider (the live
shortcut owner) and delete the orphaned use-sidebar-shortcut-model hook,
so pinned chats and their shortcut numbers share one projection.
- Prune the now-unused project pin i18n keys across all locales.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* refactor(server): inline the pin handler into the workspace path
With project pinning gone, handlePinSetRequest had a single caller. Fold it
back into handleWorkspacePinSetRequest and drop the project/workspace
generalization.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* revert: keep main's use-sidebar-shortcut-model untouched
This hook (and its test) already live on main. The scope-down had deleted
them, but that's out of scope for this PR — the pin-aware shortcut ordering
lives in SidebarModelProvider now, so main's hook is left exactly as it was.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* chore(protocol): align workspacePinning COMPAT version in websocket-server
Match the v0.1.105 version already corrected in messages.ts.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(app): reshape pinned sidebar updates
* chore(app): remove stale pin button styles
* refactor(app): simplify pinned workspace rows
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Mohamed Boudra <boudra.moha@gmail.com>
* feat(app): expose archive for every workspace
Workspace actions now archive one workspace by id. The daemon remains responsible for backing-specific cleanup, including removing a managed worktree only after its final workspace is archived.
* refactor(app): clarify archive descriptor name
* fix(app): preserve workspace archive safety
* fix(app): allow archive without upstream
* refactor(app): remove stale archive callback
* test(app): cover workspace archive ownership
* feat(app): restore compact Changes diff controls
Keep the folder tree behind a view toggle while preserving the flat file list as the default.
Move secondary diff options into the overflow menu so the Changes toolbar stays compact.
* fix(app): mirror whitespace diff option copy
* fix(app): polish diff controls review follow-up
Group changed files in the Changes view into a collapsible directory
tree instead of a flat list, on every form factor — consistent with the
Files explorer, which already renders a directory tree on mobile.
Folders are collapsible and expanded by default, single-child directory
chains are compressed into one row (packages/app/src), and folder rows
show aggregate +/- stats.
Client-only, built entirely from the existing ParsedDiffFile paths:
- diff-tree.ts: pure build/compress/flatten of the directory hierarchy,
keyed by full uncompressed dir path so collapse state survives
compression changes as the diff mutates.
- diff-flat-items.ts: pure buildDiffFlatItems + sumHeightsBefore. The
function retains a flat mode (showTree=false) as a tested seam for a
possible future flat/tree toggle; sticky header indices are
file-headers-only, derived from the post-collapse list.
- panel-store: diffCollapsedFoldersByWorkspace slice (collapsed-set, so
folders default to expanded), persisted via version 12. The set is
reconciled against the current diff so folders that leave and reappear
default to expanded and the stored set stays bounded.
Presentation primitives (chevron, indent guides, indent constant) are
extracted into components/tree-primitives and shared with the Files
explorer, which drops its private copies (and a banned useUnistyles
call site). The two trees now render identical rows; only the
tree-building stays separate (server listings vs. diff paths).
The toolbar's expand-all stays file-diffs-only (renamed
allFileDiffsExpanded); a separate control collapses/expands all folders.
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
* feat(settings): consolidate daemon management into the host page
The app-level Daemon section and the localhost host page rendered the
same daemon card in two places. The host page is now the single home:
the Host sidebar group leads with Overview, and a desktop-only "Enable
built-in daemon" option in the host switcher recovers a removed
localhost connection. Old settings/daemon deep links redirect
(COMPAT-tagged).
* fix(settings): hide daemon recovery option when the server id probe fails
Review feedback: !query.isLoading treated an errored IPC probe as
resolved, so the recovery affordance could show without knowing the
local server id. Replace the resolved-boolean hook with a single
discriminated state hook (loading | error | resolved) — errors hide the
affordance and fall back to the settings root in the redirect. Also
collapses the two query subscriptions per caller into one.
* fix(settings): keep daemon recovery reachable when no hosts remain
Review feedback: removing localhost as the only host takes the settings
sidebar down its no-host branch, which never mounts the host picker —
so the "Enable built-in daemon" option was unreachable in the most
common recovery case. The sidebar now owns the single hook call, passes
it to the picker, and renders the same action as a sidebar row next to
"Add host" when no hosts exist.
* test(e2e): update settings host header to Overview
Test drift: the host section's sidebar/header label was intentionally
renamed to "Overview"; the spec still asserted the old "Host" title.
Also assert the retired app-level Daemon row stays absent.
Element annotation is now free-text: dropped the Fix/Change/Question/
Approve intent pills and the intent field, so the user just says what
they want. The card uses the shared Button and is titled "Annotate
element".
Toolbar: the element picker and DevTools are no longer dev-gated and
work in prod; DevTools uses a wrench icon, and the old clipboard "grab"
is now a Camera "Screenshot element" tool. Each toolbar button
highlights only its own mode, and the copy toast reflects whether a
screenshot image was actually captured.
* feat: add Schedules screen to manage scheduled agents
Adds a Schedules section in the sidebar header (below Sessions) for viewing
and managing new-agent schedules: recurring jobs that spawn an agent on a
cron or interval cadence.
- Borderless table showing provider icon, model, cadence, next run, and
status, with row actions to edit, pause/resume, run now, and delete.
- Create/edit sheet that reuses the agent provider/model/mode/working-
directory pickers, plus an interval/cron cadence editor with presets,
validation, and a UTC preview.
- Responsive: hover-revealed row actions on desktop, an always-visible
action menu on mobile.
- Data layer over the existing schedule RPCs (list/create/update/pause/
resume/delete/run-once) with optimistic pause, resume, and delete.
Scope is limited to new-agent schedules for now.
* Make the schedule form controls visually consistent
Merge the provider and model pickers into the single nested selector the
draft screen uses, render it as a full-width field, mute the placeholder,
proportion the cadence segmented controls, unify the cron preset chips,
and route the sheet scroll through the themed scrollbar.
* Address schedules review feedback
* Translate schedule hook client fallback errors
* Make schedules global and project scoped
* Stabilize project settings transport E2E
* Reset schedule model on cross-host project change
* Reject malformed cron step expressions
* Tighten schedules project query freshness
* refactor(schedules): clean up review feedback
* test(schedules): extract fake host setup
* refactor(schedules): share cron expression parsing
Use one structural cron parser for app previews and daemon cadence validation so the accepted grammar cannot drift between surfaces.
Remove the unused host-scoped schedules redirect while keeping the global schedules route.
* feat(browser): inspect, annotate, and grab page elements for the agent
Build a design-review flow on top of the in-app Electron browser so users
can send page elements to their coding agent with context.
- Annotate: pick an element, write a comment, choose an intent
(fix/change/question/approve); the element context + intent + comment go
to the agent as text, and a cropped screenshot rides along as an image.
- Grab: pick an element to copy its info + screenshot straight to the
system clipboard (no comment), with a toast on success/failure.
- Hover inspector: in select mode each element shows a floating label with
tag, id/class, React component name, and pixel size.
- Page markers: annotated elements on the current page get numbered badges
that track scroll/resize.
- Device sizes: a viewport-size menu (responsive + 13 common device presets)
renders the page centered in a fixed-size frame.
- Toolbar buttons now expose hover tooltips and no longer get squeezed out
on narrow panes; the element selector is available to all desktop users
(previously dev-only).
Screenshots and clipboard writes go through new Electron main-process IPCs
(capturePage + clipboard) so they work regardless of webview focus. Element
screenshots are referenced by id in the workspace attachment store and are
protected from the draft-store attachment GC. All new strings are
translated across the six supported locales.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(browser): write element clipboard exactly once
Resolve the image before writing so a combined text+image grab no longer
does a redundant text-only writeText() first (which flashed an intermediate
clipboard state). Addresses greptile review feedback.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* i18n: add browser annotate/grab/devices strings for ja and pt-BR
main added Japanese and Brazilian Portuguese locales after this branch was
created; add the browser annotation, grab, and device-size keys to keep all
locales in sync with en. resources.test.ts parity passes.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(desktop): report found app updates during manual checks
Manual checks could reuse cached update state while the renderer discarded pending update details. Keep found update versions visible while downloads prepare, and reserve install affordances for ready updates.
* test(desktop): cover manual update retry after errors
* fix(desktop): keep ready updates ready on recheck
* fix(desktop): show app update check feedback
Manual desktop app update checks now leave visible status feedback even when the shared update state is pending or available. Updater check and preparation errors are carried through the existing result path so the settings row and callout can show the failure instead of only logging it.
* fix(desktop): make update retries perform fresh checks
Manual retries now clear runtime errors emitted by a failed check so the next click calls the updater again. Background checks also skip while a visible manual check is active, and last-checked update copy uses complete localized strings.
* fix(desktop): punctuate update check timestamp copy
* fix(desktop): share runtime update errors
* fix(desktop): preserve update preparation errors
* fix(desktop): settle update check review races
* fix(desktop): settle quiet update check errors
* fix(desktop): handle overlapping update checks
* fix(desktop): preserve preparation errors during checks
* fix(app): show add project search loading state
The Add Project picker now treats a typed value that is ahead of the debounced directory search as an active search, so empty results show a loading message instead of the initial prompt or a blank list.
* fix(app): avoid overlapping project picker states
* feat: add remote daemon self-update from client
Adds a daemon.update.request RPC that lets the client trigger a remote
daemon update over WebSocket. The daemon runs npm update -g @getpaseo/cli,
reports progress via daemon_update_progress status events, then restarts
through the supervisor to load the new code.
New feature flag server_info.features.daemonSelfUpdate gates the UI.
The UpdateDaemonCard appears on the host settings page when the daemon
supports self-update and the app/daemon versions differ.
* fix: clean up progress subscription on unmount, use typed phase cast
Address Greptile review:
- P1: store unsubscribe ref and clean up on component unmount to prevent
listener leak during in-flight update
- P2: use DaemonUpdateProgressStatusPayload type instead of { phase?: string }
* fix: use npm install@latest and global concurrency guard
Address Greptile review:
- npm update -g can silently exit 0 without resolving major-version
gaps; switch to npm install -g @getpaseo/cli@latest
- Move daemonUpdateInProgress from per-session instance to module-level
variable so concurrent clients share the same guard
* feat(daemon): harden remote self-update
Probe the global npm CLI install before updating, keep request handling in a daemon self-update session controller, and emit scoped daemon.update.progress messages.
* test(daemon): make self-update paths platform-stable
---------
Co-authored-by: Mohamed Boudra <boudra.moha@gmail.com>
* feat(i18n): add Japanese (ja) locale
- Add packages/app/src/i18n/resources/ja.ts with 1287 keys matching en.ts
- Register ja in i18next.ts, locales.ts (SupportedLocale, LANGUAGE_OPTIONS,
SUPPORTED_LANGUAGES, LANGUAGE_NATIVE_NAMES, LANGUAGE_NAMES_BY_LOCALE,
resolveSupportedLocale)
- Add ja label key to all six existing locale files (ar, en, es, fr, ru, zh-CN)
- Update locales.test.ts to cover ja in all relevant assertions
Translation reviewed by Codex across four passes; terminology, placeholder
parity, and naturalness confirmed clean.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(i18n): add ja to resources.test.ts and fix test descriptions
- Import ja and add to key-parity, fallback-ratio, interpolation, and
model-count assertions in resources.test.ts
- Update test descriptions to say "all supported language(s)" instead of
"UN official language(s)" (ja is not a UN official language)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* docs: add Japanese README (README.ja.md)
Add README.ja.md translated from the English source, reviewed by Codex
across two passes. Link it in the language navigation of README.md and
README.zh-CN.md.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix: apply oxfmt formatting to locales.ts and ja.ts
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(app): add toolbar and loading states to the GitHub PR panel
Adds a toolbar under the PR title with a refresh button (refreshes git
and GitHub status + timeline in one tap), an always-visible View Pull
Request button, and a Merge control with a method dropdown that is
disabled-with-reason when the PR can't be merged yet.
The merge control reuses the existing git-actions policy verbatim via a
new buildPrPanelMergeActions selector fed into GitActionsSplitButton, so
no merge readiness/squash/auto-merge logic is duplicated.
Also replaces the empty-state flash with skeletons: a full-panel
skeleton while PR status loads and an activity skeleton while the
timeline loads, with empty states shown only when loaded-and-empty and
an error state with retry.
* refactor(app): tidy PR panel skeleton (i18n, shared pulse, index)
Addresses review feedback on the PR panel work:
- Localize the skeleton's "Checks" label via t() instead of hardcoding.
- Hoist the shared SkeletonPulse + useSkeletonPulse into activity-skeleton
so pane-skeleton reuses them instead of duplicating the pulse driver.
- Export PullRequestPaneError/Skeleton from the module index and import
them through it, matching the module's existing public surface.
* test(app): remove mock-based PR pane test
* fix(app): simplify PR panel toolbar
* fix(app): report PR panel retry failures
* feat: live provider quota panel (Claude + Codex)
Adds Claude and Codex plan usage to the context window percentage circle tooltip, querying their respective APIs directly using existing CLI auth tokens.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix: address review feedback - restore quota trigger, guard NaN date
- Re-add triggerFetch() on agent idle/error in agent status subscription
- Guard formatResetsAtLabel against NaN from malformed API date strings
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix: resolve composer conflict and stub subscribe in websocket tests
* feat(quota): add cursor, copilot, zai, grok, and kimi quota UI and improve type safety
* feat(quota): make Claude and Codex pluggable, and map additional quota/credits metrics
* security(quota): fix shell injection vulnerability by migrating exec to execFile
* revert: restore original scripts/dev.ps1 and packages/desktop/scripts/dev.ps1
* Fix i18n resource test expectation
* Fix quota tooltip empty-provider state
* Preserve zero values in Grok quota
* Fix empty quota fetch state
* Ignore quota frames in relay reconnect tests
* Persist refreshed Codex tokens to source auth file
* fix(quota): read Claude OAuth credentials from the macOS login Keychain
On macOS, Claude Code stores its OAuth credential in the login Keychain
(generic-password item, service "Claude Code-credentials"), not in
~/.claude/.credentials.json — that file usually does not exist there, so the
Claude provider's existsSync check failed and macOS users silently got no
Claude quota. Read it via the macOS `security` CLI (its ACL only trusts
/usr/bin/security to decrypt; a native Keychain read would prompt), and stay
read-only there since Claude Code owns the refresh/persist. Linux and Windows
keep using ~/.claude/.credentials.json unchanged.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* Fix quota keychain timeout and local host reconciliation
* Fix terminal notification test quota stub
* Ignore quota frames in terminal notification tests
* fix(quota): bypass Claude token refresh on macOS Keychain-backed logins
* fix(dev): update local dev daemon port to 6768 on Windows scripts/dev.ps1
* fix(dev): bypass Unix dev-daemon.sh on Windows in dev.ps1
* fix(client): handle and dispatch provider_quota event in DaemonClient
* fix(desktop): fix PowerShell quote stripping in desktop dev.ps1 config seeding
* fix(desktop): execute config update via temp file to avoid PowerShell quoting bugs
* fix(desktop): fix concurrently command invocation on Windows in dev.ps1
* fix(desktop): resolve path escaping and environment setting syntax errors in dev.ps1 for Windows
* Add on-demand provider usage views
* Fix Cursor usage billing dates
* Move provider usage renderer coverage to e2e
* Use provider manifest for quota fetchers
* Add provider usage fetch timeouts
* Reshape provider usage fetchers
---------
Co-authored-by: ABorakati <ABorakati@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Mohamed Boudra <boudra.moha@gmail.com>
Co-authored-by: lumingjun <lumingjun@bytedance.com>
Remove projects through a daemon RPC so the sidebar can delete the project
record after archiving its active workspaces. Reopening a removed directory
recreates the missing project record so local projects keep their derived
basename, and History skips orphaned archived workspace rows.
Fixes#1583.
Archiving a Paseo-owned worktree deletes its directory, so reopening its
agent previously dead-ended even after the workspace record came back —
there was no folder to return to.
Restore now recreates the worktree at its original path from the kept
branch (the branch is never deleted on archive), re-points the same
workspace record, and clears archivedAt — preserving the workspaceId so
the agent stays linked. The directory is recreated before the un-archive
so the reconciler can't re-archive it for a missing directory. A deleted
or already-checked-out branch surfaces a typed failure and leaves the
workspace archived.
Gated behind a worktreeRestore capability flag; older hosts get an
explicit "update your host" state instead of a misleading failure.
Reopening an archived agent previously dead-ended at "workspace not
found": the agent record was un-archived but its workspace stayed
archived and was never sent to the client.
The daemon now un-archives the owning workspace alongside the agent when
its backing directory still exists, and the app auto-fires the restore
ahead of the missing-workspace gate so the user lands back in the
workspace rather than a dead end.
Worktrees whose directory was deleted on archive are not yet restorable
(recreating them from their branch is a follow-up); the workspace record
now persists its base branch as groundwork for that.
The local/worktree choice was unstored component state and reset on every
remount of the New Workspace screen (e.g. after creating a workspace).
Persist it in the create-form preferences (FormPreferences.isolation).
Also rename the app-layer "backing" to "isolation" to match its UI label.
Isolation is the create-time intent; it stays distinct from workspaceKind,
the git-derived persisted property, and the wire's source.kind.
* Name agents by their first prompt line instead of an LLM summary
The workspace title already captures the task; the LLM-generated agent
title just restated the same prompt. Drop the generator and keep the
provisional title (first prompt line), so the agent label stays
deterministic and explicit titles still win.
* Remove the no-op agent-title setting and leftover generator plumbing
Deleting the agent-title generator left its whole surface dangling: a
configurable "Agent titles" project setting that no longer did anything,
dead create-path plumbing, generator-only import/MCP deps, and the mock
provider's agent-title parser. Remove all of it, plus a dead test mock
and timing sleeps that guarded the deleted background job. Replace them
with a no-mock lifecycle test asserting the title stays the first prompt
line across create and settle.
Old paseo.json files with metadataGeneration.agentTitle still parse via
schema passthrough — see COMPAT(projectMetadataAgentTitle).
* Remove a worktree when its last workspace is archived
Archiving is now workspace-centric: the UI always archives a workspace,
and a worktree's directory is removed only when its last referencing
workspace is archived (derived from ownership + a single reference
count). The "remove the worktree from disk?" prompt is gone; archiving
warns only when the workspace is dirty or has unpushed commits.
MCP archive_worktree and the CLI keep the explicit lower-level behavior:
archive every workspace backing the directory, then remove it.
Auto-archive-after-merge and create-agent auto-archive respect the
reference count like any other workspace archival.
The policy now lives in two modules - a server archive service and a
client archive hook - with the reference-count check in exactly one
place. The deleteWorktreeFromDisk request field is retained but ignored
for wire back-compat.
* Tidy archive-policy internals and close test gaps
Follow-up polish on the archive-policy consolidation; no behavior change.
Structure: the server archive service is renamed to reflect that it now
owns all archive policy (the file and its types no longer say "worktree"
where they mean "archive"); the client archive input derives the
workspace kind from the canonical type instead of re-listing it; the
not-found target is typed string|null instead of an empty-string
sentinel; a redundant workspace-update emit and the ambiguous
worktrees-root naming are cleaned up. Wire, SDK, and keybinding names are
deliberately left unchanged for back-compat.
Tests: re-home the archiving-state lifecycle and per-workspace snapshot
assertions; pin worktree-kind acceptance through archive_workspace, the
ignored deleteWorktreeFromDisk field, and three-workspace archive-all;
add a Playwright spec for the dirty/unpushed worktree archive flow (the
warning gates it, confirming removes the directory) and the bulk
remove-project confirm branch.
* Fix the hanging worktree-archive risk-warning e2e spec
The spec added in the previous commit hung deterministically, locally and
in CI. Two test-only bugs, no product change.
The archive click opens a synchronous window.confirm(); the spec
registered a passive dialog waiter but only dismissed the dialog after
awaiting the click, so the click never resolved (Playwright won't settle
a click while a dialog is open) - a circular wait. Answer the dialog
inline via page.once("dialog", ...) before the click resolves, matching
the proven worktree-archive spec.
The seed also committed on a never-pushed branch, so aheadOfOrigin was
null and the "1 unpushed commit" warning never appeared. Push the branch
to set its upstream before the local commit, so it reports exactly one
unpushed commit.
Verified: the spec now passes in ~6s (was a 45s timeout); both the
dismiss-gates and accept-removes paths run.
Cmd+N (Ctrl+N off mac) navigates to the new-workspace route through a
global handler keyed on the active host. The sidebar header row surfaces
the shortcut hint on hover, replacing the redundant "+" button that
duplicated the action in the Workspaces section header.
Multiple workspaces can share one checkout directory. Agent and terminal
status, sidebar tabs, and ownership now attribute strictly by workspace ID,
so a running or blocked agent in one workspace no longer shows up on its
same-directory siblings.
A one-time startup migration backfills workspace IDs onto legacy agents, and
every agent and terminal is created with one thereafter. Directory lookups
remain only for genuinely folder-derived git facts (branch, diff) and the
archive-by-path adapter.