Spaces:
Sleeping
Sleeping
feat: complete Ever-Brain engine, MCP server, CLI evb mcp command, Dockerfile and release workflow
61b1da1 Download packages/cli/src/commands/diff.ts from projectsorg/ever-brain: direct link, hf CLI and curl.
- Browser
- Download file 4.59 kB
-
https://huggingface.co/spaces/projectsorg/ever-brain/resolve/main/packages/cli/src/commands/diff.ts
- Command line
-
hf download hf://spaces/projectsorg/ever-brain/packages/cli/src/commands/diff.ts
-
curl -L -o diff.ts https://huggingface.co/spaces/projectsorg/ever-brain/resolve/main/packages/cli/src/commands/diff.ts
4.59 kB
| import pc from 'picocolors'; | |
| import { createTwoFilesPatch } from 'diff'; | |
| import { projectConfigManager } from '../config/project-config.js'; | |
| import { cacheService, normalizePosixPath } from '../services/cache-service.js'; | |
| import { CliApiClient } from '../client/api-client.js'; | |
| import { parseRepoUrl } from '../services/sync-service.js'; | |
| import { outputResult, outputError, OutputOptions } from '../utils/output.js'; | |
| export interface DiffEntry { | |
| file: string; | |
| type: 'modified' | 'added' | 'deleted'; | |
| patch: string; | |
| } | |
| export async function handleDiff( | |
| targetPath?: string, | |
| options: OutputOptions = {} | |
| ): Promise<void> { | |
| const workspaceRoot = projectConfigManager.findEvbRoot(); | |
| if (!workspaceRoot) { | |
| return outputError( | |
| 'Not inside an Ever-Brain project. Run `evb init <repo>` first.', | |
| 'NOT_IN_WORKSPACE', | |
| options | |
| ); | |
| } | |
| try { | |
| const config = projectConfigManager.readConfig(workspaceRoot); | |
| const state = projectConfigManager.readState(workspaceRoot); | |
| const dirty = cacheService.computeDirtyState(workspaceRoot); | |
| const { owner, repo } = parseRepoUrl(config.source.repository); | |
| const targetBranch = config.source.branch; | |
| const apiUrl = projectConfigManager.getApiUrl(workspaceRoot); | |
| const client = new CliApiClient(apiUrl); | |
| let filesToDiff: Array<{ file: string; type: 'modified' | 'added' | 'deleted' }> = []; | |
| if (targetPath) { | |
| const cleanTarget = normalizePosixPath(targetPath); | |
| if (dirty.modified.includes(cleanTarget)) { | |
| filesToDiff.push({ file: cleanTarget, type: 'modified' }); | |
| } else if (dirty.added.includes(cleanTarget)) { | |
| filesToDiff.push({ file: cleanTarget, type: 'added' }); | |
| } else if (dirty.deleted.includes(cleanTarget)) { | |
| filesToDiff.push({ file: cleanTarget, type: 'deleted' }); | |
| } else { | |
| // Unmodified | |
| outputResult({ diffs: [], message: `File '${cleanTarget}' is clean.` }, options, () => { | |
| console.log(`File '${cleanTarget}' has no uncommitted modifications.`); | |
| }); | |
| return; | |
| } | |
| } else { | |
| for (const m of dirty.modified) filesToDiff.push({ file: m, type: 'modified' }); | |
| for (const a of dirty.added) filesToDiff.push({ file: a, type: 'added' }); | |
| for (const d of dirty.deleted) filesToDiff.push({ file: d, type: 'deleted' }); | |
| } | |
| if (filesToDiff.length === 0) { | |
| outputResult({ diffs: [], isDirty: false }, options, () => { | |
| console.log(pc.green('No local modifications (working tree clean).')); | |
| }); | |
| return; | |
| } | |
| const diffEntries: DiffEntry[] = []; | |
| for (const item of filesToDiff) { | |
| let oldContent = ''; | |
| let newContent = ''; | |
| if (item.type === 'modified') { | |
| try { | |
| const remote = await client.getFileContent(owner, repo, item.file, targetBranch); | |
| oldContent = remote.content; | |
| } catch { | |
| oldContent = ''; | |
| } | |
| newContent = cacheService.readCachedFile(workspaceRoot, item.file) || ''; | |
| } else if (item.type === 'added') { | |
| oldContent = ''; | |
| newContent = cacheService.readCachedFile(workspaceRoot, item.file) || ''; | |
| } else if (item.type === 'deleted') { | |
| try { | |
| const remote = await client.getFileContent(owner, repo, item.file, targetBranch); | |
| oldContent = remote.content; | |
| } catch { | |
| oldContent = ''; | |
| } | |
| newContent = ''; | |
| } | |
| const patch = createTwoFilesPatch( | |
| `a/${item.file}`, | |
| `b/${item.file}`, | |
| oldContent, | |
| newContent, | |
| `remote:${targetBranch}`, | |
| 'local:cache' | |
| ); | |
| diffEntries.push({ | |
| file: item.file, | |
| type: item.type, | |
| patch, | |
| }); | |
| } | |
| outputResult({ diffs: diffEntries, isDirty: true }, options, () => { | |
| for (const entry of diffEntries) { | |
| console.log(pc.bold(pc.cyan(`\n--- diff: ${entry.file} (${entry.type}) ---`))); | |
| const lines = entry.patch.split('\n'); | |
| for (const line of lines) { | |
| if (line.startsWith('+') && !line.startsWith('+++')) { | |
| console.log(pc.green(line)); | |
| } else if (line.startsWith('-') && !line.startsWith('---')) { | |
| console.log(pc.red(line)); | |
| } else if (line.startsWith('@@')) { | |
| console.log(pc.cyan(line)); | |
| } else { | |
| console.log(pc.dim(line)); | |
| } | |
| } | |
| } | |
| }); | |
| } catch (err: unknown) { | |
| const message = err instanceof Error ? err.message : String(err); | |
| outputError(message, 'DIFF_ERROR', options); | |
| } | |
| } | |