Spaces:
Sleeping
Sleeping
File size: 5,485 Bytes
a5d1c1b 61b1da1 a5d1c1b 61b1da1 a5d1c1b 61b1da1 a5d1c1b 61b1da1 a5d1c1b 61b1da1 a5d1c1b | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 | 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');
});
});
|