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:
@@ -493,6 +493,9 @@ async function handleAbortOrError(
|
||||
RETURNING project_id, name, updated_at
|
||||
`;
|
||||
ctx.publishUser({ type: 'session_updated', session_id: sessionId, project_id: failSessRow!.project_id, name: failSessRow!.name, updated_at: failSessRow!.updated_at });
|
||||
// v1.8 mobile-tabs: cancellation is a user-initiated stop, treat as idle;
|
||||
// genuine errors flip the dot red.
|
||||
ctx.publishUser({ type: 'chat_status', chat_id: chatId, status: isAbort ? 'idle' : 'error', at: new Date().toISOString() });
|
||||
if (isAbort) {
|
||||
ctx.publish(sessionId, {
|
||||
type: 'message_complete',
|
||||
@@ -638,6 +641,7 @@ async function finalizeCompletion(
|
||||
RETURNING project_id, name, updated_at
|
||||
`;
|
||||
ctx.publishUser({ type: 'session_updated', session_id: sessionId, project_id: completeSessRow!.project_id, name: completeSessRow!.name, updated_at: completeSessRow!.updated_at });
|
||||
ctx.publishUser({ type: 'chat_status', chat_id: chatId, status: 'idle', at: new Date().toISOString() });
|
||||
ctx.publish(sessionId, {
|
||||
type: 'message_complete',
|
||||
message_id: assistantMessageId,
|
||||
@@ -683,6 +687,7 @@ async function runAssistantTurn(
|
||||
chat_id: chatId,
|
||||
error: 'tool loop depth exceeded',
|
||||
});
|
||||
ctx.publishUser({ type: 'chat_status', chat_id: chatId, status: 'error', at: new Date().toISOString() });
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -820,6 +825,9 @@ export function createInferenceRunner(
|
||||
...ctx,
|
||||
publishUser: (frame) => publishUserFn(user, frame),
|
||||
};
|
||||
// v1.8 mobile-tabs: announce working before the async loop starts so
|
||||
// every device subscribed to the user channel sees the amber dot.
|
||||
callCtx.publishUser({ type: 'chat_status', chat_id: chatId, status: 'working', at: new Date().toISOString() });
|
||||
const controller = new AbortController();
|
||||
let resolveCompleted!: () => void;
|
||||
const completed = new Promise<void>((res) => { resolveCompleted = res; });
|
||||
|
||||
Reference in New Issue
Block a user