Commit Graph

1702 Commits

Author SHA1 Message Date
Mohamed Boudra
0748149ec9 feat(providers): expose custom agent selection (#1700) 2026-06-24 16:39:48 +08:00
Mohamed Boudra
2ef119c24b Fix OMP slash commands and skills loading (#1698)
* Fix OMP slash command discovery

Keep Pi on get_commands while allowing the OMP-backed provider to use get_available_commands. Both providers reject the other command without echoing an id, so the adapter needs an explicit command-list RPC setting instead of a timeout-based fallback.

* Address OMP command test review
2026-06-24 15:11:05 +08:00
Mohamed Boudra
79be6d8dba Stop OpenCode helper servers from leaking (#1697)
* Fix OpenCode helper server ownership

Own OpenCode helper generations as soon as spawn returns so startup timeout and shutdown clean up through the manager/reaper path. Collapse the OpenCode runtime wrapper so the provider talks to the server manager directly.

* Protect dedicated OpenCode server startup
2026-06-24 14:44:43 +08:00
Mohamed Boudra
7a817774b7 chore(release): cut 0.1.99 2026-06-23 22:47:51 +07:00
Mohamed Boudra
f94b488c4f Fix ACP user message echo dedupe 2026-06-23 22:25:16 +07:00
Mohamed Boudra
1970a14349 Keep provider diagnostics and model lists in sync (#1660)
* fix(server): align provider catalog diagnostics

* fix(server): preserve catalog profile models

* refactor: unify provider catalog discovery under AgentClient.fetchCatalog

Remove listModels/listModes from AgentClient and fetchModels/fetchModes
from ProviderDefinition. All provider runtime discovery now flows through
a single fetchCatalog(options) => ProviderCatalog API.

ProviderSnapshotManager.listModels/listModes remain as cached snapshot
conveniences only. Provider implementations (acp, codex, opencode, pi,
claude, mock) updated accordingly; agent-manager default model resolution
now calls fetchCatalog.

Reshape step toward issue pi-model-list-empty.

* refactor: remove remaining provider listModels/listModes runtime API residue

Migrate remaining AgentClient/provider-client implementations and tests to
fetchCatalog. Remove obsolete ListModelsOptions/ListModesOptions interfaces.
Update ProviderSnapshotManager.getProviderDiagnostic to materialize clients
via ensureClient(provider, definition) so diagnostics self-heal the settings
sheet instead of failing when providerClients[provider] is absent.

Allowed to remain: ProviderSnapshotManager.listModels/listModes as cached
snapshot readers; protocol/client legacy list_provider_models names; unrelated
local helper in create-agent-mode.

* test(server): repair test clients after fetchCatalog refactor

- Restore TestAgentClient.fetchCatalog with proper model list and resumeSession.
- Restore NativeArchiveRecordingClient and EnvProbeAgentClient removed during refactor.
- Fix ResumeCaptureClient.fetchCatalog and resumeSession.
- Fix stream-coalescing TestAgentClient.fetchCatalog shape and isAvailable.
- Mock accessible OpenCode provider in full-access mode tests so fetchCatalog does not throw.

* refactor(app): update stable discovered models ref directly during render
2026-06-23 17:55:47 +08:00
Mohamed Boudra
26b2f25050 refactor(server): decompose session.ts into per-domain subsystems (#1646)
* refactor(server): move checkout write handlers into CheckoutSession

The checkout read side moved into session/checkout/checkout-session.ts in
#1644; the 17 inline write/PR/stash handlers stayed on the Session god-object.
This carves them into the same subsystem behind an expanded CheckoutSessionHost,
so dispatchCheckoutMessage becomes pure delegation and session.ts drops ~800
lines.

Moved into CheckoutSession (verbatim, only this.X -> this.host.X rewiring):
switch/rename branch, commit, merge, merge-from-base, pull, push, PR
create/merge, github auto-merge/check-details, PR status/timeline, github
search, stash save/pop/list, plus resolveCurrentPullRequest and the
PR-timeline helpers.

CheckoutSessionHost gains the Session-owned, non-checkout collaborators these
handlers orchestrate (notifyGitMutation, emitWorkspaceUpdateForCwd,
handleWorkspaceGitBranchSnapshot, renameCurrentBranch, checkoutExistingBranch,
and the LLM commit/PR-text generators); paseoHome/worktreesRoot join the
options bag. GitMutationRefreshReason moves to utils/checkout-git.ts so both
the shell and the subsystem share one canonical type.

session.test.ts checkout tests now drive the handlers through the public
handleMessage boundary instead of reaching into private methods; new mock-free
fake-host tests cover the moved handlers directly in checkout-session.test.ts.

Behavior-preserving: full session.test.ts + checkout-session.test.ts green,
typecheck/lint/format clean.

* refactor(server): extract chat/schedule/loop handlers into ChatScheduleLoopSession

Move the 7 chat/*, 9 schedule/*, and 5 loop/* request handlers, the three
rpc-error emitters (kept separate), and toScheduleSummary out of the Session
god-object into session/chat/chat-schedule-loop-session.ts, mirroring the shipped
CheckoutSession/VoiceSession deep-module-with-narrow-Host pattern. The least-coupled
remaining domain: stateless request/response over chatService/scheduleService/
loopService, reaching the shell only through a narrow ChatScheduleLoopSessionHost
(emit + agent-roster reads + the mention-fanout send). session.ts drops ~590 lines.

The two dispatch switches collapse into one: schedule/* was previously reached only
via the chat dispatcher's default fall-through arm — now all 21 types are explicit
delegation cases, removing that fragility.

Behavior-preserving: a new routing test drives the real Session.handleMessage for all
21 types (guards against a silently-dropped case), green before and after the move; a
collocated subsystem test covers the mention-fanout send seam, the fanout-limit error
code, the self->agent target remap, and the toScheduleSummary runs-stripping.

* refactor(server): extract provider catalog handlers into ProviderCatalogSession

Move the 8 provider-catalog handlers (model/mode/feature listing, providers
snapshot pull/refresh, diagnostic, usage) plus emitProviderDisabledResponse,
getProviderSnapshotEntryForRead, buildDraftAgentSessionConfig, the two mode-icon
downgrade helpers, and the providers_snapshot_update PUSH wiring out of session.ts
into session/provider/provider-catalog-session.ts behind a narrow
ProviderCatalogSessionHost seam — the same deep-module pattern as ChatScheduleLoopSession,
CheckoutSession, and VoiceSession.

The PUSH (start) and every PULL gate provider visibility and downgrade mode icons
through the SAME injected predicates (isProviderVisibleToClient + supportsCustomModeIcons),
both reading appVersion/clientCapabilities live — the COMPAT invariant the shell could
only enforce by code proximity before. dispatchProviderMessage collapses to delegation;
start()/dispose() wire into subscribeToOptionalManagers/cleanup at the same ordinal.

session.ts drops ~372 lines. Behavior-preservation gate (provider routing through the
real Session.handleMessage) green before and after; full session.test.ts 115/115; new
collocated subsystem test covers the PUSH/PULL parity seam, the disabled-provider path,
and the usage/feature error envelopes.

* refactor(server): extract workspace file-access handlers into WorkspaceFilesSession

Move the file-explorer, file-upload, file-transfer-frame, project-icon and
file-download-token handlers out of session.ts into
session/files/workspace-files-session.ts behind a narrow WorkspaceFilesSessionHost
seam (emit/emitBinary/hasBinaryChannel), matching the deep-module-with-Host shape
used by CheckoutSession/ChatScheduleLoopSession/ProviderCatalogSession.

The new module owns the FileUploadStore and is injected the daemon's
DownloadTokenStore; the shell's dispatch cases and the file_transfer binary route
collapse to delegation. The five handlers touch no workspace-git observer,
registry or subscription state, so this is a clean self-contained slice of the
workspace domain. session.ts drops 240 lines (7316 -> 7076).

Behavior-preservation tests (file explorer list/read/binary, download token
success + empty-cwd, project icon, upload round-trip) added to session.test.ts and
run green against the pre- and post-refactor Session; a collocated
workspace-files-session.test.ts exercises the module via a fake host with real
upload/download stores (no module mocks).

* refactor(server): extract agent-config setters into AgentConfigSession

Move the four agent-config setters (set_agent_mode/model/feature/thinking)
out of the session god-object into session/agent-config/, collapsing their
four near-identical try/log/emit envelopes into one applyConfigChange helper
behind a narrow { emit } host plus an AgentConfigOperations port.

Behavior-preserving: the dispatch cases delegate unchanged, setAgentModeCommand
still routes the mode path, and model/feature still emit no notice. Adds the
previously-absent failure-envelope coverage: 8 gate tests in session.test.ts
(success + forced failure per setter, asserting the *_response envelope and the
activity_log-before-response ordering) green before and after the carve, plus a
collocated agent-config-session.test.ts (typed fake operations + fake host, no
module mocks). session.ts drops ~173 lines.

* refactor(server): extract project-config handlers into ProjectConfigSession

Move read/write_project_config handlers, their failure emitters, and the
root-resolution helpers (resolveKnownProjectRootForConfig, canonicalizeConfigRoot,
stripTrailingPathSeparators) out of session.ts into session/project-config/, behind
a narrow { emit } host plus a projectRegistry port — matching the established
session/<domain>/ pattern. Also corrects a misfiling: project-config was dispatched
inside dispatchAgentConfigMessage despite being its own domain.

session.ts drops 155 lines (6903 -> 6748). The handleMessage-driven gate in
session.test.ts (project config RPC authorization) is green before and after; new
collocated project-config-session.test.ts covers the subsystem with a fake host and
fake registry over a real filesystem (no module mocks).

* refactor(server): extract daemon status/pairing handlers into DaemonSession

Move the two daemon.* RPC handlers (daemon.get_status, daemon.get_pairing_offer)
out of session.ts into session/daemon/daemon-session.ts behind a narrow
{ emit } host + injected reads (paseoHome, serverId, daemonVersion,
daemonRuntimeConfig, listProviderAvailability). These were misfiled inside
dispatchAgentConfigMessage despite being daemon- not agent-scoped; the slice
also removes the now-dead serverId/daemonVersion/daemonRuntimeConfig fields and
the getPidLockInfo/generateLocalPairingOffer imports from the god-file, and
collapses the inline daemonRuntimeConfig type into a named DaemonRuntimeConfig.

The daemon-config get/set handlers stay inline: daemonConfigStore is a
listener-bearing, cross-domain hub (read by structured-generation,
websocket-server, bootstrap, archive-if-safe), so moving it would double-own it.

session.ts: 6748 -> 6662 lines. Gate: new session.test.ts daemon round-trips
(status success + listing-rejects fallback, pairing relay-disabled) pass before
and after; new collocated daemon-session.test.ts (fake host + injected reads
over a real temp dir, no module mocks) 4/4. typecheck/lint/format clean.
2026-06-22 10:44:07 +08:00
Mohamed Boudra
2b5cc727f0 refactor(server): move VoiceSession into session/voice/ to match CheckoutSession (#1645)
#1640 extracted the voice subsystem to server/voice/ (a peer of session.ts);
#1644 extracted the checkout read side to session/checkout/. The two carves
landed in inconsistent homes, so there was no single place to find "what has
session.ts been carved into."

Relocate server/voice/ -> server/session/voice/ so all session subsystems share
one home alongside session/checkout/. Pure relocation: git-tracked renames with
import-depth bumped one level (../ -> ../../); the only external touch point is
the import path in session.ts. Behavior preserved verbatim — the 17 voice unit
tests pass unchanged before and after.

Also record the actual shipped layout and the next carve (the checkout mutation
handlers still inline in session.ts -> session/checkout/checkout-session.ts) in
the decomposition plan, and fix its now-stale voice path.
2026-06-21 20:45:26 +08:00
Mohamed Boudra
18f880e561 refactor(server): extract checkout read subsystem into CheckoutSession (#1644)
Extract the checkout read & live-stream side (status, branch validate/suggest, manual refresh, diff + status subscriptions) out of session.ts into session/checkout/checkout-session.ts behind a narrow CheckoutSessionHost seam and a CheckoutDiffSubscriber port. session.ts -234 net lines; 12 unit tests via injected fakes (no module mocks); 6 session tests moved onto the public handleMessage path. Also fixes a pre-existing tilde-resolution bug in the refresh handler (TDD).
2026-06-21 19:37:48 +08:00
Mohamed Boudra
617cf8a7bf refactor(server): extract voice mode subsystem into VoiceSession (#1640)
* refactor(server): extract voice mode subsystem into VoiceSession

session.ts was a 10.5k-line god object and the most-churned file in the
repo. ~1,100 of those lines were an entire voice/audio subsystem — the
STT/TTS/dictation managers, the barge-in audio-buffering state machine,
voice-turn orchestration, and the MCP voice bridge — interleaved field by
field and method by method with workspace/git/agent/provider concerns.

Move the whole subsystem into a new VoiceSession deep module. Session now
holds one `voiceSession` field, constructs it once, and delegates the
voice/dictation/abort message types, the permission auto-allow gate, and
cleanup to it. VoiceSession owns all 18 voice fields and ~25 methods and
reaches back into the agent run only through a narrow VoiceSessionHost
seam (emit, loadAgent, reloadAgentSession, sendSpokenInput,
interruptAgentIfRunning, hasActiveAgentRun).

Behavior is preserved (verbatim method moves); deleting voice-session.ts
now removes the feature mechanically. The voice unit tests drive the
VoiceSession boundary instead of reaching into Session internals, so
future voice tests can construct a VoiceSession with a fake host.

session.ts: 10,468 -> 9,272 lines.

* refactor(server): move VoiceSession into voice/ and test it at the boundary

Address Greptile review on #1640:

- Move voice-session.ts into the existing voice/ subdirectory, alongside
  voice-turn-controller.ts, instead of adding another peer to the 30+ file
  server/ directory. The directory now carries the domain.
- Add voice/voice-session.test.ts beside the module: it constructs a
  VoiceSession with a fake VoiceSessionHost and drives it through the public
  API (handleSetVoiceMode, then turn-detection/STT events), asserting on the
  host seam (sendSpokenInput) and emitted messages. No Session, no private
  field/method access.
- Remove the voice tests from session.test.ts that reached through Session's
  private voiceSession field into VoiceSession internals.

Same three behaviors are covered (streaming final -> agent, finalization
timeout empty path, low-confidence filtering); driving handleSetVoiceMode
additionally exercises the enable path the old tests bypassed.
2026-06-21 07:14:23 +00:00
Mohamed Boudra
fbd86564dd chore(release): cut 0.1.98 2026-06-21 00:30:25 +07:00
Mohamed Boudra
02838ca8bc Stub unarchiveSnapshot in stale AgentManager test doubles
Commit 25252d1b8 added AgentManager.unarchiveSnapshot, now called from
the shared unarchiveAgentState helper. The hand-rolled manager doubles in
the session-workspaces and import-sessions suites were not updated, so the
refresh/import RPC paths hit an unstubbed method and failed. Add the
method to those doubles; no production change.
2026-06-20 23:24:03 +07:00
Mohamed Boudra
a924059daf Show live context usage during active turns 2026-06-20 23:20:10 +07:00
Mohamed Boudra
c2d7796b78 Isolate Kimi usage home lookup in tests (#1636) 2026-06-20 22:54:41 +08:00
Mohamed Boudra
25252d1b86 Fix archived agent reload failures
Unarchive provider storage before clearing Paseo's archived flag so failed native restores keep the snapshot archived. Keep initial history sync errors visible instead of falling back to the loading state.
2026-06-20 21:33:25 +07:00
Mohamed Boudra
27ecb3a7a9 Merge branch 'main' of github.com:getpaseo/paseo 2026-06-20 21:30:07 +07:00
Mohamed Boudra
fd2fed03a6 Fix subagent context usage reporting
Task-level usage reports processed work, not the parent session's active context. Prefer current context data and parent stream usage before falling back to result totals.
2026-06-20 21:08:50 +07:00
Mohamed Boudra
b0e6dbceef Clean up owned helper processes on daemon startup (#1632)
Record provider-owned helper processes (currently the OpenCode `serve` helper) in a daemon ledger and reconcile it in the background on startup: terminate validated leftovers, drop dead or PID-reused records without killing anything, and keep a record whose process can't be inspected for the next reconcile. Termination stops as soon as the process exits instead of always escalating to SIGKILL.
2026-06-20 22:05:12 +08:00
Mohamed Boudra
0718e7c914 Support split worktree agent launches
Expose the workspace id from worktree creation and let agent creation attach to an existing workspace, so callers can split worktree setup from agent launch without reusing the caller workspace.

Keep worktreeSlug as the worktree path slug and add branchName for branch-off targets.
2026-06-20 19:38:57 +07:00
Mohamed Boudra
2c4e443ad7 Fix exact workspace file suggestions
Resolve exact suffix path queries before falling back to broad search, and keep broad hidden-directory traversal limited to known workspace config dirs.
2026-06-20 19:13:25 +07:00
Mohamed Boudra
6a3856b639 Fix Kimi usage credential lookup 2026-06-20 19:10:40 +07:00
Mohamed Boudra
80fc11541f Clean up MCP agent orchestration inputs
Require relationship and workspace on create_agent, and reuse the same worktree target union for create_worktree. Agent-scoped prompt follow-ups now default to background finish notifications so callers can continue without polling.
2026-06-20 16:59:09 +07:00
Mohamed Boudra
ba8fe261ee fix(server): set opencode serve cwd to home dir to stop full-filesystem scan (#1626)
When the Paseo daemon is launched as a macOS GUI app (via launchd), its
working directory is `/`. The `opencode serve` process inherited that cwd,
causing opencode's fff_search to scan and watch the entire filesystem,
leading to 300%+ CPU and 1GB+ RAM usage.

Fix: pass `cwd: os.homedir()` when spawning `opencode serve` so it never
inherits `/`. The per-session working directory is unaffected — it is
passed separately via the OpenCode SDK's `session.create({ directory })`.

Fixes #1617
2026-06-20 15:21:40 +08:00
Mohamed Boudra
4534754617 Add projects without creating workspaces
Keep the legacy open-project request creating a workspace for old clients; new clients now add projects and create workspaces through separate flows.
2026-06-20 11:56:28 +07:00
Aditya Borakati
acea7f3d24 feat: live multi-provider quota panel (#1278)
* 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>
2026-06-20 12:19:50 +08:00
Mohamed Boudra
2b0740ff84 Add Claude Ultracode with setting-change notices (#1625)
* Add Claude Ultracode mode notices

* Share provider notice definitions

* Test Claude Ultracode through public turn API
2026-06-20 04:15:04 +00:00
Mohamed Boudra
7af92120fe Detach subagents without archiving them (#1612)
* Add detach action for subagents

* Translate detached subagent connection error

* Address subagent detach review feedback

* Fix subagent integration test import

* Focus detached subagents as tabs
2026-06-19 17:19:05 +08:00
Mohamed Boudra
cda66ae5f3 Make provider diagnostics easier to share (#1611)
* Show PATH matches in provider diagnostics

* Add copyable provider command probes

* Fix provider diagnostic path reporting

* Clean up command probe diagnostics
2026-06-19 12:46:39 +08:00
Mohamed Boudra
e73b1c4724 Fix hidden workspace file suggestions (#1609) 2026-06-19 11:56:22 +08:00
Matt Cowger
ccb8714a71 fix(opencode): trust discovered modes, don't inject hardcoded defaults (#1366)
* fix(opencode): trust discovered modes instead of always injecting defaults

When OpenCode reports its available agents, respect that list exactly
rather than seeding from DEFAULT_MODES first. This means users who have
intentionally disabled modes (e.g. Plan) in their OpenCode config will
no longer see those modes surfaced in Paseo.

DEFAULT_MODES is still used as a fallback when discovery returns nothing
(e.g. OpenCode unreachable or no agents configured).

* test(opencode): update mode discovery expectations

* test(opencode): expect discovered custom modes only
2026-06-19 11:20:26 +08:00
Matt Cowger
b90baaff71 fix: daemon warns instead of crashing on missing OpenAI speech credentials (#1368)
* fix: daemon warns instead of crashing on missing OpenAI speech credentials

validateOpenAiCredentialRequirements was throwing an error when
OpenAI speech providers were configured without credentials,
causing the daemon to crash before it could start serving health
checks. Changed to log a warning instead — the daemon starts
successfully and reports speech services as unavailable.

Closes #1367

* chore: address Greptile review feedback

- Remove duplicate warning in initializeOpenAiSpeechServices when
  all credentials are missing (already warned by validate)
- Strengthen test assertions: check getListenTarget() after start
- Wrap daemon start/stop in try/finally for proper cleanup on failure
2026-06-19 11:09:39 +08:00
Mohamed Boudra
60cf566b79 chore(release): cut 0.1.97 2026-06-19 05:47:43 +07:00
Mohamed Boudra
112f1ace65 Fix legacy workspace compatibility 2026-06-19 04:14:12 +07:00
Mohamed Boudra
9a09ccb3d6 Fix sidebar project removal
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.
2026-06-19 00:46:40 +07:00
Mohamed Boudra
2064e308a7 Update server tests for current workspace behavior 2026-06-18 23:02:27 +07:00
Mohamed Boudra
00c57617d5 Fix History restore and diff truncation edge cases 2026-06-18 20:44:57 +07:00
Mohamed Boudra
b3f81c0bf4 Recreate deleted worktrees from their branch on restore
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.
2026-06-18 20:44:57 +07:00
Mohamed Boudra
31fcde2ea6 Restore an archived workspace when its agent is reopened
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.
2026-06-18 20:44:56 +07:00
Mohamed Boudra
fe15b68e06 Fix per-file diff size gating 2026-06-18 20:44:56 +07:00
Mohamed Boudra
df18bbc43a Migrate monorepo to Zod 4 2026-06-18 15:02:42 +08:00
Mohamed Boudra
e4da3693e9 chore(release): cut 0.1.97-beta.3 2026-06-18 11:40:27 +07:00
Mohamed Boudra
6c0b5c7640 Fix provider snapshot warm reads 2026-06-18 11:26:27 +07:00
Mohamed Boudra
6fc52d85cb chore(release): cut 0.1.97-beta.2 2026-06-17 17:15:23 +07:00
Mohamed Boudra
fc4c2aa367 Decouple metadata prompt contract from overridable style
Metadata prompts (workspace title + branch, commit message, PR) mixed the
functional contract with style guidance in one block, and project-owner
instructions from paseo.json were appended after the defaults with an
"override where they conflict" notice — so custom wording competed with the
built-in style instead of replacing it.

Each prompt is now a non-overridable contract (what to produce, the JSON
shape, correctness/safety rules) plus style slots that paseo.json
instructions replace wholesale. Title and branch style are now separate
keys (metadataGeneration.title vs .branchName); previously branchName
instructions also shaped the title.
2026-06-17 16:48:24 +07:00
Mohamed Boudra
2bc48993a5 Generate shorter, task-shaped workspace titles
Auto-generated titles were full sentences that overflowed the sidebar.
The titling prompt now targets ~4 words, drops generic "do" verbs (Fix,
Add, Diagnose...), and keeps only specific operation verbs, with good and
bad examples.
2026-06-17 15:54:51 +07:00
Mohamed Boudra
0c9802b22b Show prompt titles immediately for new workspaces (#1567)
* Set workspace prompt titles at creation

* Cover existing workspace prompt titles

* Fix rewind E2E prompt selector
2026-06-17 15:30:32 +08:00
Mohamed Boudra
1340a80144 Fix New Workspace PR worktree creation (#1565)
* Fix PR worktree creation from New Workspace

* Use fixture default branch in GitHub E2E clone
2026-06-17 15:15:58 +08:00
Mohamed Boudra
14743fa0b0 Update Agent MCP redaction smoke test (#1566) 2026-06-17 14:14:14 +08:00
Mohamed Boudra
69741e0770 Make the agent MCP server stateless to fix session leak
The agent-facing MCP server (/mcp/agents) ran in stateful session mode,
keeping a StreamableHTTPServerTransport plus its full Server and Zod tool
schemas alive per agent connection, keyed by session id. The map was only
pruned on the SDK's onclose/onsessionclosed callbacks, which fire only on a
clean DELETE. Agents that are killed or exit without one never get reaped, so
dead sessions accumulate for the life of the daemon (observed ~77MB across 132
stale transports in a heap snapshot).

Listing and calling tools needs no cross-request state, so each request now
builds a fresh server + transport and tears both down when the response closes.
Per-request cost is ~0.6-0.9ms and ~760KB of short-lived allocation; nothing is
retained between requests. GET and DELETE return 405, which the MCP client
tolerates (it never receives a session id).
2026-06-17 09:18:29 +07:00
Mohamed Boudra
8c509017ff chore(release): cut 0.1.97-beta.1 2026-06-17 08:24:25 +07:00