import { createRequire } from 'node:module'; import { mkdirSync, mkdtempSync, readFileSync, readdirSync, realpathSync, rmSync, writeFileSync, } from 'node:fs'; import { tmpdir } from 'node:os'; import { dirname, join } from 'node:path'; import { performance } from 'node:perf_hooks'; import { afterEach, beforeEach, describe, expect, it } from 'vitest'; import { ensureBundledCourseSkills } from '@electron/opencode/course-skills'; const require = createRequire(import.meta.url); const describeWindows = process.platform === 'win32' ? describe : describe.skip; const chineseUsername = '\u5362\u6b22'; function writeFixtureFile(filePath: string, content: string): void { mkdirSync(dirname(filePath), { recursive: true }); writeFileSync(filePath, content, 'utf8'); } function createFixture() { const root = mkdtempSync(join(tmpdir(), 'niancode-electron-unicode-')); const sources = join(root, 'sources'); const courseSkills = join(sources, 'course-skills'); const managedConfigDir = join( root, chineseUsername, 'AppData', 'Roaming', 'niancode', 'opencode', 'niancode-config', ); writeFixtureFile( join(courseSkills, 'pm-project-plan', 'SKILL.md'), '---\nname: pm-project-plan\n---\n', ); writeFixtureFile( join(courseSkills, 'pm-project-plan', 'references', 'guide.md'), '# planning guide\n', ); return { root, managedConfigDir, courseSkills, rootEntriesBeforeCopy: readdirSync(root).sort(), }; } function expectNoUnexpectedRootEntries(fixture: ReturnType): void { expect(readdirSync(fixture.root).sort()).toEqual([ ...fixture.rootEntriesBeforeCopy, chineseUsername, ].sort()); } function median(values: number[]): number { const sorted = [...values].sort((left, right) => left - right); return sorted[Math.floor(sorted.length / 2)]; } describeWindows('Windows Unicode runtime directory copies', () => { let fixture: ReturnType; beforeEach(() => { fixture = createFixture(); }); afterEach(() => { rmSync(fixture.root, { recursive: true, force: true, maxRetries: 3, retryDelay: 50, }); }); it('runs under this project local Electron runtime', () => { const localElectronExecutable = require('electron'); const localElectronPackage = JSON.parse(readFileSync( require.resolve('electron/package.json'), 'utf8', )); console.info(`[electron-runtime] ${JSON.stringify({ execPath: process.execPath, electron: process.versions.electron, node: process.versions.node, })}`); expect(process.platform).toBe('win32'); expect(process.env.ELECTRON_RUN_AS_NODE).toBe('1'); expect(process.versions.electron).toBeDefined(); expect(realpathSync(process.execPath)).toBe(realpathSync(localElectronExecutable)); expect(process.versions.electron).toBe(localElectronPackage.version); expect(process.versions.electron).toBe(process.env.NIANCODE_LOCAL_ELECTRON_VERSION); if (process.env.NIANCODE_VERIFY_RELEASE_RUNTIME === '1') { expect(process.versions.electron).toBe('40.10.6'); expect(process.versions.node).toBe('24.15.0'); } }); it('copies course Skills below a Chinese user path twice', () => { const unrelatedSkill = join( fixture.managedConfigDir, 'skills', 'user-owned-skill', 'SKILL.md', ); writeFixtureFile(unrelatedSkill, 'preserve-user-owned-skill\n'); expect(ensureBundledCourseSkills({ managedConfigDir: fixture.managedConfigDir, sourceDir: fixture.courseSkills, })).toBe(true); writeFixtureFile( join(fixture.courseSkills, 'pm-project-plan', 'references', 'guide.md'), '# updated planning guide\n', ); expect(ensureBundledCourseSkills({ managedConfigDir: fixture.managedConfigDir, sourceDir: fixture.courseSkills, })).toBe(true); expect(readFileSync( join(fixture.managedConfigDir, 'skills', 'pm-project-plan', 'references', 'guide.md'), 'utf8', )).toBe('# updated planning guide\n'); expect(readFileSync(unrelatedSkill, 'utf8')).toBe('preserve-user-owned-skill\n'); expectNoUnexpectedRootEntries(fixture); }); it('reports course copy timing without a brittle CI threshold', () => { const skillTimes: number[] = []; const actualSkills = join(process.cwd(), '.opencode', 'skills'); for (let run = 0; run < 7; run += 1) { const managedConfigDir = join( fixture.root, chineseUsername, 'performance', String(run), 'niancode-config', ); const skillStart = performance.now(); ensureBundledCourseSkills({ managedConfigDir, sourceDir: actualSkills }); skillTimes.push(performance.now() - skillStart); } const evidence = { skills: { medianMs: median(skillTimes), maxMs: Math.max(...skillTimes) }, }; console.info(`[runtime-copy-performance] ${JSON.stringify(evidence)}`); expect(evidence.skills.maxMs).toBeGreaterThanOrEqual(evidence.skills.medianMs); }); });