import { mkdtempSync } from "node:fs"; import { tmpdir } from "node:os"; import { join } from "node:path"; import { loadConfig, type AppConfig } from "../src/config.js"; import type { Logger } from "../src/logger.js"; import { SkillCatalog } from "../src/skills/catalog.js"; import type { SkillRepository, StoredSkill, StoredSkillConfig } from "../src/skills/repository.js"; export const silentLogger: Logger = { debug: () => {}, info: () => {}, warn: () => {}, error: () => {}, }; export function tempRoot(prefix = "laimiao-v2-"): string { return mkdtempSync(join(tmpdir(), prefix)); } export class FakeSkillRepository implements SkillRepository { constructor(private skills: StoredSkill[]) {} async ensureSchema(): Promise {} async listSkills(): Promise { return this.skills; } setSkills(skills: StoredSkill[]): void { this.skills = skills; } async close(): Promise {} } export interface SkillFixture { key: string; name?: string; description?: string; content?: string; triggerKeywords?: string; libraryEnabled?: boolean; config?: Partial | null; } export function skillFixture(fixture: SkillFixture): StoredSkill { const config: StoredSkillConfig | undefined = fixture.config === null ? undefined : { pricePerImage: 10, enabled: true, ...fixture.config, }; return { key: fixture.key, name: fixture.name ?? `Test ${fixture.key}`, industry: "test", description: fixture.description ?? `Test skill ${fixture.key}`, triggerKeywords: fixture.triggerKeywords ?? "", content: fixture.content ?? `# ${fixture.key}\n\nUse this skill for tests.\n`, libraryEnabled: fixture.libraryEnabled ?? true, config, }; } export async function makeCatalog( skills: StoredSkill[], options: { defaultPrice?: number; defaultModel?: string; defaultSize?: string } = {}, ): Promise { return new SkillCatalog({ repository: new FakeSkillRepository(skills), defaultPrice: options.defaultPrice ?? 10, defaultModel: options.defaultModel ?? "gpt-image-2", defaultSize: options.defaultSize ?? "1024x1024", currency: "credits", logger: silentLogger, }).load(); } export function testConfig(root: string, overrides: Record = {}): AppConfig { return loadConfig({ APP_ROOT: root, DATA_DIR: "data", LOG_LEVEL: "error", GATEWAY_MOCK: "true", GATEWAY_POLL_INTERVAL_MS: "10", BILLING_MODE: "dry_run", ...overrides, }); }