diff --git a/apps/kimi-web/dev/stub-daemon.mjs b/apps/kimi-web/dev/stub-daemon.mjs index 1651939e4..ca5280236 100644 --- a/apps/kimi-web/dev/stub-daemon.mjs +++ b/apps/kimi-web/dev/stub-daemon.mjs @@ -1460,6 +1460,36 @@ const server = http.createServer((req, res) => { return res.end(ok(gs)); } + // ---- fs:diff ---- + // POST /api/v1/sessions/{id}/fs:diff body: { path } + if (seg[0] === 'sessions' && seg[2] === 'fs:diff' && seg.length === 3 && method === 'POST') { + const session = sessions.find((s) => s.id === sid); + if (!session) return res.end(fail(40401, `session ${sid} does not exist`)); + const b = json(); + if (!b.path) return res.end(fail(40001, 'path: required')); + // Deterministic fake unified diff so the Changed → diff flow is demoable. + const diff = [ + `diff --git a/${b.path} b/${b.path}`, + 'index 1111111..2222222 100644', + `--- a/${b.path}`, + `+++ b/${b.path}`, + '@@ -1,7 +1,9 @@', + ` // ${b.path}`, + ' ', + '-export function oldImpl(input) {', + '- return null;', + '+export function newImpl(input) {', + '+ // handle the empty-state branch the old impl missed', + '+ if (!input) return fallback();', + '+ return compute(input);', + ' }', + ' ', + ' export const VERSION = 2;', + '', + ].join('\n'); + return res.end(ok({ path: b.path, diff, truncated: false })); + } + // ---- fs:list ---- // POST /api/v1/sessions/{id}/fs:list body: { path, depth?, include_git_status? } if (seg[0] === 'sessions' && seg[2] === 'fs:list' && seg.length === 3 && method === 'POST') { diff --git a/apps/kimi-web/src/api/daemon/client.ts b/apps/kimi-web/src/api/daemon/client.ts index c3a28ac4b..54e9b6be5 100644 --- a/apps/kimi-web/src/api/daemon/client.ts +++ b/apps/kimi-web/src/api/daemon/client.ts @@ -734,13 +734,11 @@ export class DaemonKimiWebApi implements KimiWebApi { async getFileDiff( sessionId: string, - path?: string, + path: string, ): Promise<{ path: string; diff: string }> { - const body: Record = {}; - if (path !== undefined) body['path'] = path; const data = await this.http.post( `/sessions/${encodeURIComponent(sessionId)}/fs:diff`, - body, + { path }, ); return { path: data.path, diff: data.diff }; } diff --git a/apps/kimi-web/src/api/types.ts b/apps/kimi-web/src/api/types.ts index 000be382d..43ed16089 100644 --- a/apps/kimi-web/src/api/types.ts +++ b/apps/kimi-web/src/api/types.ts @@ -493,7 +493,7 @@ export interface KimiWebApi { searchFiles(sessionId: string, input: { query: string; limit?: number }): Promise<{ items: Array<{ path: string; name: string; kind: FsKind; score: number; matchPositions: number[] }>; truncated: boolean }>; grepFiles(sessionId: string, input: { pattern: string; regex?: boolean; caseSensitive?: boolean }): Promise<{ files: Array<{ path: string; matches: Array<{ line: number; col: number; text: string; before: string[]; after: string[] }> }>; filesScanned: number; truncated: boolean; elapsedMs: number }>; getGitStatus(sessionId: string, paths?: string[]): Promise<{ branch: string; ahead: number; behind: number; entries: Record }>; - getFileDiff(sessionId: string, path?: string): Promise<{ path: string; diff: string }>; + getFileDiff(sessionId: string, path: string): Promise<{ path: string; diff: string }>; getFileDownloadUrl(sessionId: string, path: string): string; openFile(sessionId: string, input: { path: string; line?: number }): Promise<{ opened: true }>; revealFile(sessionId: string, input: { path: string }): Promise<{ revealed: true }>; diff --git a/apps/kimi-web/src/components/ConversationPane.vue b/apps/kimi-web/src/components/ConversationPane.vue index ede783b44..cf6e45fe7 100644 --- a/apps/kimi-web/src/components/ConversationPane.vue +++ b/apps/kimi-web/src/components/ConversationPane.vue @@ -185,6 +185,11 @@ async function handleFileSelect(entry: FsEntry): Promise { // --------------------------------------------------------------------------- const changedView = ref<'changed' | 'all'>('changed'); +// Non-git workspace (gitInfo is null): there is no Changed view to offer — +// the Changed|All toggle is hidden and the full file tree shows directly. +const hasGit = computed(() => (props.gitInfo ?? null) !== null); +const filesView = computed<'changed' | 'all'>(() => (hasGit.value ? changedView.value : 'all')); + // The "Changed" navigator can show a flat list or a directory tree (persisted). const CHANGED_LAYOUT_KEY = 'kimi-web.changed-layout'; function loadChangedLayout(): 'list' | 'tree' { @@ -680,7 +685,7 @@ onUnmounted(() => { half is visible; the divider only exists on desktop). -->