feat: remove legacy OpenCode runtime
Cut product flows over to Coding/Pi and retain only the migration-owned v1 boundary. Promote supported native optional packages because electron-builder omitted pnpm transitive optional closure from the packaged ASAR.
This commit is contained in:
@@ -13,12 +13,13 @@ import path from 'node:path';
|
||||
import { afterEach, describe, expect, it, vi } from 'vitest';
|
||||
import type { ProjectAgentConfig, ProjectConfig } from '../../shared/project-config';
|
||||
import {
|
||||
buildProjectAgentManifest,
|
||||
normalizeProjectConfig,
|
||||
} from '../../electron/opencode/project-config';
|
||||
buildLegacyProjectAgentManifest,
|
||||
normalizeLegacyProjectConfigV1,
|
||||
} from '../../electron/coding-projects/legacy-v1';
|
||||
import { atomicWriteJson } from '../../electron/coding-projects/atomic-json';
|
||||
import {
|
||||
acknowledgeLegacyConversationNotice,
|
||||
createCodingProjectConfigV2,
|
||||
readCodingProjectConfigV2,
|
||||
} from '../../electron/coding-projects/project-config';
|
||||
import { migrateCodingProjectToV2 } from '../../electron/coding-projects/migration';
|
||||
@@ -107,7 +108,7 @@ async function stageLegacyProject(options: { conversations?: boolean } = {}): Pr
|
||||
]);
|
||||
const projectSource = `${JSON.stringify(config, null, 2)}\n`;
|
||||
await writeFile(projectFile, projectSource, 'utf8');
|
||||
for (const entry of buildProjectAgentManifest(normalizeProjectConfig(config)).entries) {
|
||||
for (const entry of buildLegacyProjectAgentManifest(normalizeLegacyProjectConfigV1(config))) {
|
||||
await writeFile(path.join(projectPath, '.opencode', entry.relativePath), entry.content, 'utf8');
|
||||
}
|
||||
await writeFile(path.join(projectPath, '.opencode', 'skills', 'keep.md'), 'keep me', 'utf8');
|
||||
@@ -130,6 +131,35 @@ afterEach(async () => {
|
||||
});
|
||||
|
||||
describe('coding project v1 to v2 migration', () => {
|
||||
it('leaves legacy directories inert once project v2 is valid', async () => {
|
||||
const projectPath = await mkdtemp(path.join(tmpdir(), 'makelore-current-v2-'));
|
||||
scratchRoots.push(projectPath);
|
||||
const projectFile = path.join(projectPath, '.niancode', 'project.json');
|
||||
const legacyFile = path.join(projectPath, '.opencode', 'agent', 'legacy.md');
|
||||
await Promise.all([
|
||||
mkdir(path.dirname(projectFile), { recursive: true }),
|
||||
mkdir(path.dirname(legacyFile), { recursive: true }),
|
||||
]);
|
||||
await writeFile(projectFile, JSON.stringify(
|
||||
createCodingProjectConfigV2(CREATED, 'custom'),
|
||||
null,
|
||||
2,
|
||||
));
|
||||
await writeFile(legacyFile, 'must remain untouched\n', 'utf8');
|
||||
const resolveLegacyModel = vi.fn(async () => MODEL);
|
||||
const copy = vi.fn(copyFile);
|
||||
|
||||
const result = await migrateCodingProjectToV2(projectPath, {
|
||||
resolveLegacyModel,
|
||||
copyFile: copy,
|
||||
});
|
||||
|
||||
expect(result.status).toBe('already-current');
|
||||
expect(resolveLegacyModel).not.toHaveBeenCalled();
|
||||
expect(copy).not.toHaveBeenCalled();
|
||||
expect(await readFile(legacyFile, 'utf8')).toBe('must remain untouched\n');
|
||||
});
|
||||
|
||||
it('backs up v1, maps unique models, requires unresolved selection, and hides old sessions', async () => {
|
||||
const staged = await stageLegacyProject();
|
||||
const unresolvedFile = path.join(staged.projectPath, '.opencode', 'agent', 'unresolved.md');
|
||||
@@ -172,7 +202,7 @@ describe('coding project v1 to v2 migration', () => {
|
||||
]);
|
||||
expect(resolveLegacyModel).toHaveBeenCalledTimes(2);
|
||||
expect(result.removedGeneratedAgents.sort()).toEqual(['no-account.md', 'unique.md']);
|
||||
expect(result.backedUpUncertainAgents.sort()).toEqual(['custom.md', 'unresolved.md']);
|
||||
expect(result.backedUpUncertainAgents).toEqual(['unresolved.md']);
|
||||
expect(JSON.parse(await readFile(
|
||||
path.join(staged.projectPath, '.niancode', 'conversations.json'),
|
||||
'utf8',
|
||||
@@ -185,12 +215,8 @@ describe('coding project v1 to v2 migration', () => {
|
||||
path.join(result.backupDirectory, '.opencode', 'agent', 'unresolved.md'),
|
||||
'utf8',
|
||||
)).toBe('locally modified Agent\n');
|
||||
expect(await readFile(
|
||||
path.join(result.backupDirectory, '.opencode', 'agent', 'custom.md'),
|
||||
'utf8',
|
||||
)).toBe('unknown Agent\n');
|
||||
await expect(readFile(unresolvedFile, 'utf8')).rejects.toMatchObject({ code: 'ENOENT' });
|
||||
await expect(readFile(customFile, 'utf8')).rejects.toMatchObject({ code: 'ENOENT' });
|
||||
expect(await readFile(customFile, 'utf8')).toBe('unknown Agent\n');
|
||||
expect(await readFile(path.join(staged.projectPath, '.opencode', 'skills', 'keep.md'), 'utf8'))
|
||||
.toBe('keep me');
|
||||
|
||||
@@ -243,7 +269,7 @@ describe('coding project v1 to v2 migration', () => {
|
||||
.toBe(staged.projectSource);
|
||||
expect(await readFile(path.join(staged.projectPath, '.niancode', 'conversations.json'), 'utf8'))
|
||||
.toBe(staged.conversationSource);
|
||||
for (const entry of buildProjectAgentManifest(normalizeProjectConfig(staged.config)).entries) {
|
||||
for (const entry of buildLegacyProjectAgentManifest(normalizeLegacyProjectConfigV1(staged.config))) {
|
||||
expect(await readFile(path.join(staged.projectPath, '.opencode', entry.relativePath), 'utf8'))
|
||||
.toBe(entry.content);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user