feat(mobile): v1.8 tab switcher + branch indicator + git_status tool

Mobile header is now two rows. Row 1: hamburger | project · branch
indicator (live via GET /api/projects/:id/git, 30s poll) | ModelPicker |
FolderTree. Row 2: pane-switcher pill (hand-rolled BottomSheet) +
NewPaneMenu. Chat-within-pane navigation hidden on mobile; users switch
panes via the sheet. Cross-tab status sync via chat_status frames
published from inference.ts at working/idle/error transitions; StatusDot
component renders amber-pulse/green/red/gray on each pane row and on
desktop ChatTabBar tabs. Level 1 git awareness exposes a read-only
git_status tool to the model, backed by services/git_meta.ts (execFile
+ 2s timeout + 30s cache). Workspace.tsx now receives panes/chats hooks
as props (hoisted into Session.tsx) so the header pill shares state
with the pane grid.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-16 20:07:53 +00:00
parent 92bd3b1cdf
commit 2bce4d85fa
19 changed files with 1217 additions and 622 deletions

View File

@@ -9,6 +9,7 @@ import type {
ListDirResult,
ViewFileResult,
AgentsResponse,
GitMeta,
} from './types';
export class ApiError extends Error {
@@ -87,6 +88,8 @@ export const api = {
request<ViewFileResult>(`/api/projects/${id}/view_file?path=${encodeURIComponent(path)}`),
files: (id: string) =>
request<{ files: string[] }>(`/api/projects/${id}/files`),
git: (id: string) =>
request<GitMeta>(`/api/projects/${id}/git`),
},
sessions: {

View File

@@ -175,6 +175,15 @@ export interface PaneUpdateRequest {
position?: number;
}
// v1.8 mobile-tabs: shape returned by GET /api/projects/:id/git. Mirrors
// services/git_meta.ts on the server. branch=null means "not a git repo".
export interface GitMeta {
branch: string | null;
is_dirty: boolean;
ahead: number;
behind: number;
}
export type WorkspacePaneKind = 'chat' | 'terminal' | 'agent' | 'empty';
export interface WorkspacePane {