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:
41
apps/web/src/hooks/useProjectGit.ts
Normal file
41
apps/web/src/hooks/useProjectGit.ts
Normal file
@@ -0,0 +1,41 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { api } from '@/api/client';
|
||||
import type { GitMeta } from '@/api/types';
|
||||
|
||||
const POLL_INTERVAL_MS = 30_000;
|
||||
|
||||
// Live-ish git meta for the project header indicator. Backed by the server's
|
||||
// 30s cache, so a 30s client poll plus the cache TTL bounds total staleness
|
||||
// to ~60s in the worst case. Returns null while the first fetch is in flight
|
||||
// or if the request failed.
|
||||
export function useProjectGit(projectId: string | null | undefined): GitMeta | null {
|
||||
const [meta, setMeta] = useState<GitMeta | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (!projectId) {
|
||||
setMeta(null);
|
||||
return;
|
||||
}
|
||||
let cancelled = false;
|
||||
|
||||
const fetchOnce = () => {
|
||||
api.projects
|
||||
.git(projectId)
|
||||
.then((m) => {
|
||||
if (!cancelled) setMeta(m);
|
||||
})
|
||||
.catch(() => {
|
||||
if (!cancelled) setMeta(null);
|
||||
});
|
||||
};
|
||||
|
||||
fetchOnce();
|
||||
const t = setInterval(fetchOnce, POLL_INTERVAL_MS);
|
||||
return () => {
|
||||
cancelled = true;
|
||||
clearInterval(t);
|
||||
};
|
||||
}, [projectId]);
|
||||
|
||||
return meta;
|
||||
}
|
||||
Reference in New Issue
Block a user