ever-brain / packages /cli /test /cli-commands.test.ts
AlexKurian's picture
feat: complete Ever-Brain engine, MCP server, CLI evb mcp command, Dockerfile and release workflow
61b1da1
Raw History Blame Contribute Delete
5.49 kB
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
import fs from 'node:fs';
import path from 'node:path';
import os from 'node:os';
import { projectConfigManager } from '../src/config/project-config.js';
import { cacheService, computeSha256 } from '../src/services/cache-service.js';
import { syncService } from '../src/services/sync-service.js';
import { handleStatus } from '../src/commands/status.js';
import { handleDiff } from '../src/commands/diff.js';
import { handleReset } from '../src/commands/reset.js';
import { handleKnowledgeList, handleKnowledgeShow } from '../src/commands/knowledge.js';
import { handleSkillsList, handleSkillsShow } from '../src/commands/skills.js';
describe('CLI Commands & Workflows', () => {
let testDir: string;
let originalCwd: string;
beforeEach(() => {
testDir = fs.mkdtempSync(path.join(os.tmpdir(), 'evb-cmd-test-'));
originalCwd = process.cwd();
process.chdir(testDir);
// Initialize clean mock workspace
projectConfigManager.writeConfig(testDir, {
version: 1,
source: {
repository: 'https://github.com/acme/project-intelligence',
branch: 'main',
},
});
const fileContent = '# Authentication Architecture\nDetails about JWT.';
cacheService.writeCachedFile(testDir, 'knowledge/auth.md', fileContent);
cacheService.writeCachedFile(
testDir,
'skills/deploy/SKILL.md',
'---\nname: deploy\ndescription: Production deployment runbook\n---\n# Deploy Runbook'
);
projectConfigManager.writeState(testDir, {
last_sync: new Date().toISOString(),
source_revision: 'main',
cached_files: 2,
files: {
'knowledge/auth.md': computeSha256(fileContent),
'skills/deploy/SKILL.md': computeSha256(
'---\nname: deploy\ndescription: Production deployment runbook\n---\n# Deploy Runbook'
),
},
});
});
afterEach(() => {
process.chdir(originalCwd);
fs.rmSync(testDir, { recursive: true, force: true });
vi.restoreAllMocks();
});
it('runs evb status in JSON mode', async () => {
const consoleSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
await handleStatus({ json: true });
expect(consoleSpy).toHaveBeenCalled();
const output = JSON.parse(consoleSpy.mock.calls[0][0]);
expect(output.repository).toBe('https://github.com/acme/project-intelligence');
expect(output.isDirty).toBe(false);
expect(output.cachedFilesCount).toBe(2);
expect(output.knowledgeCount).toBe(1);
expect(output.skillsCount).toBe(1);
});
it('detects dirty state on status and diff after local edit', async () => {
cacheService.writeCachedFile(testDir, 'knowledge/auth.md', '# Auth v2 with RS256');
const statusSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
await handleStatus({ json: true });
const statusJson = JSON.parse(statusSpy.mock.calls[0][0]);
expect(statusJson.isDirty).toBe(true);
expect(statusJson.modifications.modified).toEqual(['knowledge/auth.md']);
// Check diff
const diffSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
await handleDiff(undefined, { json: true });
const diffJson = JSON.parse(diffSpy.mock.calls[0][0]);
expect(diffJson.isDirty).toBe(true);
expect(diffJson.diffs).toHaveLength(1);
expect(diffJson.diffs[0].file).toBe('knowledge/auth.md');
expect(diffJson.diffs[0].type).toBe('modified');
});
it('runs evb knowledge list and show', async () => {
const listSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
await handleKnowledgeList({ json: true });
const listJson = JSON.parse(listSpy.mock.calls[0][0]);
expect(listJson.total).toBe(2); // auth.md and deploy/SKILL.md
expect(listJson.documents.some((d: any) => d.path === 'knowledge/auth.md')).toBe(true);
const showSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
await handleKnowledgeShow('knowledge/auth.md', { json: true });
const showJson = JSON.parse(showSpy.mock.calls[0][0]);
expect(showJson.content).toContain('Authentication Architecture');
});
it('runs evb skills list and show', async () => {
const listSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
await handleSkillsList({ json: true });
const listJson = JSON.parse(listSpy.mock.calls[0][0]);
expect(listJson.total).toBe(1);
expect(listJson.skills[0].id).toBe('deploy');
expect(listJson.skills[0].description).toBe('Production deployment runbook');
const showSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
await handleSkillsShow('deploy', { json: true });
const showJson = JSON.parse(showSpy.mock.calls[0][0]);
expect(showJson.content).toContain('Deploy Runbook');
});
it('resets local modifications with evb reset', async () => {
cacheService.writeCachedFile(testDir, 'knowledge/auth.md', '# Dirty modifications');
expect(cacheService.computeDirtyState(testDir).isDirty).toBe(true);
// Mock syncService.sync
vi.spyOn(syncService, 'sync').mockResolvedValue({
updated: 1,
unchanged: 1,
removed: 0,
total: 2,
});
const resetSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
await handleReset({ yes: true, json: true });
expect(resetSpy).toHaveBeenCalled();
const result = JSON.parse(resetSpy.mock.calls[0][0]);
expect(result.status).toBe('reset_complete');
});
});