Skip to content

feat: add persistent workspace state, first-class terminals, and setup streaming#230

Open
boudra wants to merge 98 commits intomainfrom
dev
Open

feat: add persistent workspace state, first-class terminals, and setup streaming#230
boudra wants to merge 98 commits intomainfrom
dev

Conversation

@boudra
Copy link
Copy Markdown
Collaborator

@boudra boudra commented Apr 10, 2026

Continuation of #197 (branch renamed from merge/main-into-dev to dev).

Summary

  • SQLite-backed persistence for agents, timelines, projects, and workspaces
  • First-class terminals replacing terminal-agent flows
  • Streaming workspace setup flow
  • Service health/routing and CI visibility in sidebar and hover card
  • Composer, provider, and workspace UX parity fixes

See #197 for full description.

boudra and others added 30 commits March 29, 2026 23:20
- Remove orphaned PID lock code from bootstrap (moved to supervisor)
- Fix worktree archive adapter to look up workspace by directory
- Replace registerWorktreeWorkspaceRecord with inline SQLite implementation
- Remove unused imports (stat, createPersistedWorkspaceRecord, PersistedProjectRecord)
Services defined in paseo.json get reverse-proxied through the daemon
via hostname-based routing on *.localhost. Each service receives $PORT,
$HOST, and $PASEO_SERVICE_URL env vars, and is accessible at
{service}.localhost:6767 (main) or {branch}.{service}.localhost:6767
(worktrees).
Built-in service proxy with branch-based URLs, service health
monitoring, workspace hover card with service status, and
"Forget about ports" homepage section.
# Conflicts:
#	nix/package.nix
#	packages/app/src/app/_layout.tsx
#	packages/app/src/components/sidebar-workspace-list.tsx
#	packages/app/src/hooks/use-command-center.ts
#	packages/app/src/screens/agent/draft-agent-screen.tsx
#	packages/app/src/screens/workspace/workspace-desktop-tabs-row.tsx
#	packages/app/src/screens/workspace/workspace-screen.tsx
#	packages/server/src/server/session.ts
#	packages/server/src/server/session.workspaces.test.ts
#	packages/server/src/terminal/terminal.test.ts
#	packages/server/src/terminal/terminal.ts
# Conflicts:
#	packages/app/e2e/helpers/workspace-setup.ts
#	packages/app/src/components/sidebar-workspace-list.tsx
#	packages/app/src/contexts/session-context.tsx
#	packages/app/src/hooks/use-sidebar-workspaces-list.test.ts
#	packages/app/src/screens/workspace/workspace-tab-menu.ts
#	packages/app/src/stores/workspace-setup-store.ts
#	packages/app/src/stores/workspace-tabs-store.ts
#	packages/app/src/utils/sidebar-project-row-model.test.ts
#	packages/app/src/utils/sidebar-shortcuts.test.ts
#	packages/app/src/utils/workspace-tab-identity.ts
#	packages/server/src/server/bootstrap.ts
#	packages/server/src/server/worktree-session.ts
- Align portless code with storage branch's numeric workspace IDs and new field names
- Update workspace kind comparisons (local_checkout → checkout/worktree)
- Add missing services, supportsTerminalMode, terminal fields to test fixtures
- Fix archive timestamp assertions to match dynamic archiveSnapshot flow
- Fix dictation, voice runtime, and service health monitor test timing
- Add xterm-addon-ligatures type declaration for terminal emulator
Remove the "agent can be a terminal" branching from the entire codebase.
An agent is now always a session-backed chat agent. Standalone terminal
infrastructure (terminal component, ANSI handling, terminal-stream-protocol)
is preserved.

Server: delete ManagedTerminalAgent, AgentKind, TerminalExitDetails,
launchTerminalAgent, registerTerminalAgent, handleTerminalAgentExited,
supportsTerminalMode capability, buildTerminalCreate/ResumeCommand from
all providers, terminal agent persistence/projections.

App: delete terminal-agent-panel.tsx, terminal-agent-reopen-store.ts,
terminal/terminalExit fields on agent state, "Terminal Agents" launcher
section, terminal-agent workspace setup flow, terminal badge in agent list.

CLI: remove terminal column from ls, terminal-agent error from send.

60 files changed, -3592 lines
Reuse existing project when a matching git remote is found instead of
creating duplicates. Detect git worktrees via --git-common-dir and set
workspace kind accordingly.
# Conflicts:
#	nix/package.nix
#	packages/app/src/components/icons/opencode-icon.tsx
#	packages/app/src/components/provider-icons.ts
#	packages/app/src/panels/agent-panel.tsx
#	packages/cli/src/commands/provider/ls.ts
#	packages/server/src/server/agent/provider-manifest.ts
#	packages/server/src/server/agent/provider-registry.ts
#	packages/server/src/server/agent/providers/claude-agent.test.ts
#	packages/server/src/server/agent/providers/claude-agent.ts
#	packages/server/src/server/persistence-hooks.ts
#	packages/server/src/server/session.ts
Surgical merge of 74 commits from main into dev. Key features ported:

- Provider visibility gating (appVersion filtering for Pi/Copilot)
- Pi agent provider + Copilot re-enabled
- Provider-declared features system (Codex fast mode)
- Workspace dedup by worktree root (adapted to integer IDs)
- Bulk close archiving fix for stored agents
- Agent creation timeout increase to 60s
- Audio/voice crash fixes (external buffer copies)
- Multi-host setup fix
- Reload agent tab action

Dev architecture preserved: SQLite storage, service proxy,
workspace setup dialog, hover cards, removed launcher tabs.
Migration hardening:
- Back up JSON to $PASEO_HOME/backup/pre-migration/ before import
- Deduplicate projects/workspaces by path before insert
- Log per-batch progress during agent snapshot import
- Clear error messages for corrupt JSON files
- 5 new test cases for backup, dedup, progress, and error clarity

Post-merge fixes:
- Add worktreeRoot to session checkout result (type error fix)
- Port reload agent tab action from main
- Remove deleted useDelayedHistoryRefreshToast hook usage
boudra and others added 23 commits April 9, 2026 18:54
Claude Code writes local CLI command outputs (model switches, /context,
/compact, goodbye messages, etc.) as user entries in the JSONL history.
These were leaking through as user_message timeline items in Paseo.
- Rename findExecutable → findExecutableSync, add async findExecutable
  that uses promisified execFile instead of execFileSync
- Simplify Windows PATH resolution: rely on inherited env from Explorer
  instead of shelling out to PowerShell for registry PATH entries
- Add spawnProcess() helper that centralizes Windows shell/quoting concerns
- Update all agent providers and consumers to use async executable resolution
- Add windowsHide: true across all Windows child process calls
Replace truncating text with a read-only TextInput + copy button pattern
so the pairing URL doesn't get cut off. Increase QR code size from
200x200 to 320x320.
* Add WebStorm editor target

* Fix rebase type errors and add TODO date tag

- Await listAvailableEditorTargets() which became async on main
- Wrap sendAgentMessage callback to match Promise<void> return type
- Add TODO(2026-07) date to legacy editor target ids comment

---------

Co-authored-by: Mohamed Boudra <boudra.moha@gmail.com>
Prevents the daemon section from flashing "not running" / "PID —" while
IPC data loads. The whole card now shows a spinner until the first fetch
completes, and mutations (restart/stop/start) optimistically update the
query cache with the returned status.
Adds logic to process file parts and convert image attachments into data URLs for the OpenCode provider, replacing the previous behavior that stripped non-text parts.
On iPad, Combobox uses the desktop Modal path (no BottomSheet context)
since the breakpoint is "md"+, but ProviderSearchInput was checking
Platform.OS === "web" to choose the input component. This caused
BottomSheetTextInput to render outside a BottomSheet on iPad.

Align the check with Combobox's own isMobile breakpoint logic.
Adds ci.yml covering: biome format check, typecheck across all packages,
server tests (unit + integration), app unit tests, Playwright E2E,
relay tests, and CLI tests. Each job runs independently in parallel.
…m cleanup

- Persist snapshot before emitting closed agent to avoid data loss
- Flush after branch rename so state hits disk immediately
- Filter phantom whitespace-only files from ignore-whitespace diffs
- Only include ignoreWhitespace param when true to keep payloads clean
- Add createFeature test helper for AgentFeature construction
# Conflicts:
#	packages/app/src/components/combined-model-selector.tsx
#	packages/app/src/components/message-input.tsx
#	packages/app/src/components/sidebar-workspace-list.tsx
#	packages/app/src/screens/agent/draft-agent-screen.tsx
#	packages/app/src/screens/settings-screen.tsx
#	packages/desktop/src/main.ts
#	packages/server/src/server/agent/provider-launch-config.ts
#	packages/server/src/server/session.ts
#	packages/server/src/server/session.workspaces.test.ts
#	packages/server/src/shared/messages.ts
#	packages/server/src/utils/checkout-git.ts
return await initPromise;
} finally {
const current = pendingAgentBootstrapLoads.get(options.agentId);
if (current === initPromise) {
},
});
return true;
case "message-input.send":
case "message-input.dictation-cancel":
messageInputRef.current?.runKeyboardAction("dictation-cancel");
return true;
case "message-input.dictation-confirm":
Comment on lines +18 to +23
import {
connectTerminalClient,
waitForTerminalContent,
setupDeterministicPrompt,
type TerminalPerfDaemonClient,
} from "./helpers/terminal-perf";
} from "@/utils/workspace-execution";
import { WorkspaceHoverCard } from "@/components/workspace-hover-card";
import { GitHubIcon } from "@/components/icons/github-icon";
import { createNameId } from "mnemonic-id";
);
}

const isArchivingCurrentAgent = Boolean(agentId && isArchivingAgent({ serverId, agentId }));
const hasLog = commandLog.trim().length > 0;

// All non-running commands are expandable (completed/failed)
const isExpandable = command.status !== "running" || hasLog || !!hasError;
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.

3 participants