Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Haze <hazeone@users.noreply.github.com>
105 lines
3.8 KiB
TypeScript
105 lines
3.8 KiB
TypeScript
// @vitest-environment node
|
|
import { afterEach, describe, expect, it } from 'vitest';
|
|
import { mkdtemp, mkdir, readFile, rm, writeFile } from 'node:fs/promises';
|
|
import { existsSync } from 'node:fs';
|
|
import { tmpdir } from 'node:os';
|
|
import path from 'node:path';
|
|
import {
|
|
patchExtensionOpenClawSelfImports,
|
|
rewriteOpenClawPluginSdkSpecifiers,
|
|
toImportSpecifier,
|
|
} from '../../scripts/openclaw-self-import-patch.mjs';
|
|
|
|
const tempRoots: string[] = [];
|
|
|
|
async function createTempOpenClawBundle(): Promise<string> {
|
|
const root = await mkdtemp(path.join(tmpdir(), 'clawx-openclaw-self-import-'));
|
|
tempRoots.push(root);
|
|
return root;
|
|
}
|
|
|
|
afterEach(async () => {
|
|
await Promise.all(tempRoots.splice(0).map((root) => rm(root, { recursive: true, force: true })));
|
|
});
|
|
|
|
describe('openclaw self-import bundle patch', () => {
|
|
it('converts OpenClaw plugin-sdk package specifiers to bundled relative paths', async () => {
|
|
const root = await createTempOpenClawBundle();
|
|
const distDir = path.join(root, 'dist');
|
|
const pluginSdkDir = path.join(distDir, 'plugin-sdk');
|
|
const extensionDir = path.join(distDir, 'extensions', 'codex');
|
|
await mkdir(pluginSdkDir, { recursive: true });
|
|
await mkdir(extensionDir, { recursive: true });
|
|
await writeFile(path.join(pluginSdkDir, 'provider-model-shared.js'), 'export const ok = true;\n');
|
|
|
|
const promptOverlayPath = path.join(extensionDir, 'prompt-overlay.js');
|
|
await writeFile(
|
|
promptOverlayPath,
|
|
[
|
|
'import { ok } from "openclaw/plugin-sdk/provider-model-shared";',
|
|
"export { ok };",
|
|
'',
|
|
].join('\n'),
|
|
);
|
|
|
|
const result = patchExtensionOpenClawSelfImports(root);
|
|
|
|
expect(result).toMatchObject({
|
|
filesPatched: 1,
|
|
specifiersPatched: 1,
|
|
});
|
|
await expect(readFile(promptOverlayPath, 'utf8')).resolves.toContain(
|
|
'from "../../plugin-sdk/provider-model-shared.js"',
|
|
);
|
|
});
|
|
|
|
it('leaves extension files without OpenClaw self-imports untouched', async () => {
|
|
const root = await createTempOpenClawBundle();
|
|
const extensionDir = path.join(root, 'dist', 'extensions', 'telegram');
|
|
await mkdir(extensionDir, { recursive: true });
|
|
|
|
const filePath = path.join(extensionDir, 'runtime.js');
|
|
const source = 'export const runtime = true;\n';
|
|
await writeFile(filePath, source);
|
|
|
|
const result = patchExtensionOpenClawSelfImports(root);
|
|
|
|
expect(result.filesScanned).toBe(1);
|
|
expect(result.filesPatched).toBe(0);
|
|
expect(result.specifiersPatched).toBe(0);
|
|
await expect(readFile(filePath, 'utf8')).resolves.toBe(source);
|
|
});
|
|
|
|
it('throws when the bundled plugin-sdk target is missing', () => {
|
|
const root = path.join(tmpdir(), 'missing-target-openclaw-bundle');
|
|
const distDir = path.join(root, 'dist');
|
|
const filePath = path.join(distDir, 'extensions', 'codex', 'prompt-overlay.js');
|
|
|
|
expect(() => rewriteOpenClawPluginSdkSpecifiers(
|
|
'import "openclaw/plugin-sdk/provider-model-shared";',
|
|
{ filePath, distDir },
|
|
)).toThrow(/missing bundled SDK target/);
|
|
});
|
|
|
|
it('formats same-directory import paths with an explicit relative prefix', () => {
|
|
expect(toImportSpecifier('provider-model-shared.js')).toBe('./provider-model-shared.js');
|
|
expect(toImportSpecifier('../plugin-sdk/provider-model-shared.js')).toBe(
|
|
'../plugin-sdk/provider-model-shared.js',
|
|
);
|
|
});
|
|
|
|
it('returns an empty patch summary when the extensions directory is absent', async () => {
|
|
const root = await createTempOpenClawBundle();
|
|
await mkdir(path.join(root, 'dist', 'plugin-sdk'), { recursive: true });
|
|
|
|
const result = patchExtensionOpenClawSelfImports(root);
|
|
|
|
expect(existsSync(path.join(root, 'dist', 'extensions'))).toBe(false);
|
|
expect(result).toEqual({
|
|
filesScanned: 0,
|
|
filesPatched: 0,
|
|
specifiersPatched: 0,
|
|
});
|
|
});
|
|
});
|