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:
@@ -3,6 +3,7 @@ import { resolve, basename, relative } from 'node:path';
|
||||
import { z } from 'zod';
|
||||
import { pathGuard, PathScopeError } from './path_guard.js';
|
||||
import { grep as fileOpsGrep, findFiles as fileOpsFindFiles } from './file_ops.js';
|
||||
import { getGitMeta } from './git_meta.js';
|
||||
|
||||
const MAX_FILE_BYTES = 5 * 1024 * 1024;
|
||||
const DEFAULT_VIEW_LINES = 200;
|
||||
@@ -266,11 +267,45 @@ export const findFiles: ToolDef<FindFilesInputT> = {
|
||||
},
|
||||
};
|
||||
|
||||
// v1.8 Level 1 branch awareness: gives the model a read-only view of the
|
||||
// project's git state. No path input — operates on the inference-resolved
|
||||
// project root via getGitMeta. Subprocess runs with a 2s timeout (see git_meta).
|
||||
const GitStatusInput = z.object({}).strict();
|
||||
type GitStatusInputT = z.infer<typeof GitStatusInput>;
|
||||
|
||||
export const gitStatus: ToolDef<GitStatusInputT> = {
|
||||
name: 'git_status',
|
||||
description:
|
||||
"Returns the current git branch, whether the working tree is dirty, and ahead/behind counts vs upstream. Read-only. Use when you need to know which branch the user is currently working on.",
|
||||
inputSchema: GitStatusInput,
|
||||
jsonSchema: {
|
||||
type: 'function',
|
||||
function: {
|
||||
name: 'git_status',
|
||||
description:
|
||||
'Returns the current git branch, dirty flag, and ahead/behind counts vs upstream. Read-only.',
|
||||
parameters: {
|
||||
type: 'object',
|
||||
properties: {},
|
||||
additionalProperties: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
async execute(_input, projectRoot) {
|
||||
const meta = await getGitMeta(projectRoot);
|
||||
if (meta === null) {
|
||||
return { repo: false, branch: null, is_dirty: false, ahead: 0, behind: 0 };
|
||||
}
|
||||
return { repo: true, ...meta };
|
||||
},
|
||||
};
|
||||
|
||||
export const ALL_TOOLS: ReadonlyArray<ToolDef<unknown>> = [
|
||||
viewFile as ToolDef<unknown>,
|
||||
listDir as ToolDef<unknown>,
|
||||
grep as ToolDef<unknown>,
|
||||
findFiles as ToolDef<unknown>,
|
||||
gitStatus as ToolDef<unknown>,
|
||||
];
|
||||
|
||||
export const TOOLS_BY_NAME: Record<string, ToolDef<unknown>> = Object.fromEntries(
|
||||
|
||||
Reference in New Issue
Block a user