moving
Some checks failed
Installer Smoke / installer-smoke (push) Has been cancelled

This commit is contained in:
Oleg Maslov
2026-09-02 10:10:29 +02:00
commit 0c3e2ead3b
3841 changed files with 970576 additions and 0 deletions

View File

@@ -0,0 +1,245 @@
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
import fs from 'node:fs';
import os from 'node:os';
import path from 'node:path';
import { WaggleConfig, type ProviderEntry, type TeamServerConfig } from '../src/config.js';
describe('WaggleConfig', () => {
const tempDirs: string[] = [];
function makeTempDir(): string {
const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'waggle-config-test-'));
tempDirs.push(dir);
return dir;
}
afterEach(() => {
for (const dir of tempDirs) {
fs.rmSync(dir, { recursive: true, force: true });
}
tempDirs.length = 0;
});
it('creates config directory if missing', () => {
const base = makeTempDir();
const configDir = path.join(base, 'nested', '.waggle');
new WaggleConfig(configDir);
expect(fs.existsSync(configDir)).toBe(true);
});
it('returns default config when no file exists', () => {
const configDir = makeTempDir();
const config = new WaggleConfig(configDir);
expect(config.getDefaultModel()).toBe('claude-sonnet-4-6');
expect(config.getProviders()).toEqual({});
expect(config.getMindPath()).toBe(path.join(configDir, 'default.mind'));
});
it('saves and loads provider config', () => {
const configDir = makeTempDir();
const config = new WaggleConfig(configDir);
const provider: ProviderEntry = {
apiKey: 'sk-test-key',
models: ['claude-sonnet-4-6', 'claude-haiku-3'],
baseUrl: 'https://api.anthropic.com',
};
config.setProvider('anthropic', provider);
config.save();
// Load fresh instance from same directory
const config2 = new WaggleConfig(configDir);
const providers = config2.getProviders();
expect(providers['anthropic']).toEqual(provider);
expect(providers['anthropic'].apiKey).toBe('sk-test-key');
expect(providers['anthropic'].models).toHaveLength(2);
});
it('sets and gets default model', () => {
const configDir = makeTempDir();
const config = new WaggleConfig(configDir);
config.setDefaultModel('gpt-4o');
config.save();
const config2 = new WaggleConfig(configDir);
expect(config2.getDefaultModel()).toBe('gpt-4o');
});
it('returns mind file path', () => {
const configDir = makeTempDir();
const config = new WaggleConfig(configDir);
expect(config.getMindPath()).toBe(path.join(configDir, 'default.mind'));
});
it('removes a provider', () => {
const configDir = makeTempDir();
const config = new WaggleConfig(configDir);
config.setProvider('anthropic', { apiKey: 'key1', models: ['m1'] });
config.setProvider('openai', { apiKey: 'key2', models: ['m2'] });
config.removeProvider('anthropic');
config.save();
const config2 = new WaggleConfig(configDir);
const providers = config2.getProviders();
expect(providers['anthropic']).toBeUndefined();
expect(providers['openai']).toBeDefined();
});
it('returns config directory path', () => {
const configDir = makeTempDir();
const config = new WaggleConfig(configDir);
expect(config.getConfigDir()).toBe(configDir);
});
describe('team server config', () => {
it('returns null when no team server configured', () => {
const configDir = makeTempDir();
const config = new WaggleConfig(configDir);
expect(config.getTeamServer()).toBeNull();
expect(config.isTeamConnected()).toBe(false);
});
it('sets and gets team server config', () => {
const configDir = makeTempDir();
const config = new WaggleConfig(configDir);
const teamConfig: TeamServerConfig = {
url: 'https://team.waggle.dev',
token: 'clerk-jwt-token',
userId: 'user-123',
displayName: 'Marko',
};
config.setTeamServer(teamConfig);
config.save();
const config2 = new WaggleConfig(configDir);
const loaded = config2.getTeamServer();
expect(loaded).toEqual(teamConfig);
expect(config2.isTeamConnected()).toBe(true);
});
it('clears team server config', () => {
const configDir = makeTempDir();
const config = new WaggleConfig(configDir);
config.setTeamServer({ url: 'https://team.waggle.dev' });
config.clearTeamServer();
config.save();
const config2 = new WaggleConfig(configDir);
expect(config2.getTeamServer()).toBeNull();
expect(config2.isTeamConnected()).toBe(false);
});
it('persists team server through save/load cycle', () => {
const configDir = makeTempDir();
const config = new WaggleConfig(configDir);
config.setTeamServer({ url: 'https://example.com', userId: 'u1' });
config.save();
const config2 = new WaggleConfig(configDir);
expect(config2.getTeamServer()!.url).toBe('https://example.com');
expect(config2.getTeamServer()!.userId).toBe('u1');
});
});
describe('governed CLI config', () => {
it('normalizes, deduplicates, and persists the CLI allowlist', () => {
const configDir = makeTempDir();
const config = new WaggleConfig(configDir);
config.setCliAllowlist([' node ', 'NODE', '', 'git']);
expect(config.getCliAllowlist()).toEqual(['node', 'git']);
config.save();
const config2 = new WaggleConfig(configDir);
expect(config2.getCliAllowlist()).toEqual(['node', 'git']);
});
});
describe('Model Pilot config fields', () => {
let tmpDir: string;
beforeEach(() => {
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'waggle-config-pilot-'));
});
afterEach(() => {
fs.rmSync(tmpDir, { recursive: true, force: true });
});
it('returns null for fallbackModel when not set', () => {
const config = new WaggleConfig(tmpDir);
expect(config.getFallbackModel()).toBeNull();
});
it('persists fallbackModel', () => {
const config = new WaggleConfig(tmpDir);
config.setFallbackModel('qwen/qwen3.6-plus:free');
config.save();
const config2 = new WaggleConfig(tmpDir);
expect(config2.getFallbackModel()).toBe('qwen/qwen3.6-plus:free');
});
it('returns null for budgetModel when not set', () => {
const config = new WaggleConfig(tmpDir);
expect(config.getBudgetModel()).toBeNull();
});
it('persists budgetModel', () => {
const config = new WaggleConfig(tmpDir);
config.setBudgetModel('deepseek/deepseek-chat-v3-0324:free');
config.save();
const config2 = new WaggleConfig(tmpDir);
expect(config2.getBudgetModel()).toBe('deepseek/deepseek-chat-v3-0324:free');
});
it('returns 0.8 as default budgetThreshold', () => {
const config = new WaggleConfig(tmpDir);
expect(config.getBudgetThreshold()).toBe(0.8);
});
it('persists budgetThreshold', () => {
const config = new WaggleConfig(tmpDir);
config.setBudgetThreshold(0.6);
config.save();
const config2 = new WaggleConfig(tmpDir);
expect(config2.getBudgetThreshold()).toBe(0.6);
});
it('clearFallbackModel removes the field', () => {
const config = new WaggleConfig(tmpDir);
config.setFallbackModel('test-model');
config.save();
config.clearFallbackModel();
config.save();
const config2 = new WaggleConfig(tmpDir);
expect(config2.getFallbackModel()).toBeNull();
});
it('returns 90 as default maxIterations', () => {
const config = new WaggleConfig(tmpDir);
expect(config.getMaxIterations()).toBe(90);
});
it('persists maxIterations', () => {
const config = new WaggleConfig(tmpDir);
config.setMaxIterations(50);
config.save();
const config2 = new WaggleConfig(tmpDir);
expect(config2.getMaxIterations()).toBe(50);
});
});
});