fix(packages): load bundled Pi runtime for local installs

This commit is contained in:
2026-09-02 22:46:58 +08:00
parent 28e1690038
commit 5a2f0eb678
9 changed files with 356 additions and 19 deletions

View File

@@ -11,6 +11,14 @@ import { PiProcessBudget } from '../../electron/coding-runtime/pi/worker-pool';
import type { AgentBrowserModule } from '../../electron/agent-browser';
import { CodingAttachmentStore } from '../../electron/coding-projects/attachment-store';
import { PiProductTools } from '../../electron/coding-runtime/pi/product-tools';
import {
DevicePackageError,
type DevicePackageManager,
} from '../../electron/coding-packages/device-package-manager';
import {
DEVICE_PACKAGE_TOOL_DEFINITIONS,
DevicePackageTools,
} from '../../electron/coding-packages/device-package-tools';
import { CodingCapabilityRegistryImpl } from '../../electron/coding-plugins/registry';
import type { PluginPolicyClientState } from '../../electron/services/plugin-policy-client';
import {
@@ -48,6 +56,79 @@ afterEach(async () => {
});
describe('Makelore Pi extension bundle', () => {
it('preserves a closed Device Package failure through the real worker bridge', async () => {
const root = await mkdtemp(path.join(tmpdir(), 'makelore-pi-device-package-error-'));
roots.push(root);
const manager = {
async prepare() {
throw new DevicePackageError(
'local_package_dependency_failed',
'Bundled Pi package manager is unavailable',
);
},
} as unknown as DevicePackageManager;
const host = new PiManagedExtensionHost();
host.configureProductTools(new PiProductTools({
browser: {} as AgentBrowserModule,
attachments: new CodingAttachmentStore(path.join(root, 'attachments')),
bundledSkillsDir: path.resolve('resources/coding-skills'),
devicePackageTools: new DevicePackageTools(manager),
}));
hosts.push(host);
const prepareTool = DEVICE_PACKAGE_TOOL_DEFINITIONS.find(
({ name }) => name === 'local_package_prepare',
);
if (!prepareTool) throw new Error('Device Package prepare definition missing');
const worker = await host.registerWorker({
conversationId: 'device-package-conversation',
generation: 1,
projectId: 'project-a',
projectPath: root,
extensionsDir: root,
tools: [prepareTool],
});
await host.bindRun('device-package-conversation', 1, 'device-package-run');
const previous = {
bridge: process.env.MAKELORE_PI_BRIDGE_URL,
token: process.env.MAKELORE_PI_WORKER_TOKEN,
context: process.env.MAKELORE_PI_CONTEXT_FILE,
role: process.env.MAKELORE_PI_WORKER_ROLE,
};
Object.assign(process.env, worker.env);
try {
const module = await import(
/* @vite-ignore */ `${pathToFileURL(worker.extensionPath).href}?device-package=${Date.now()}`
) as {
default(factory: {
registerTool(tool: ExtensionTool): void;
on(event: string, handler: ExtensionHandler): void;
}): void | Promise<void>;
};
const tools = new Map<string, ExtensionTool>();
await module.default({
registerTool: (tool) => tools.set(tool.name, tool),
on: () => undefined,
});
await expect(tools.get('local_package_prepare')?.execute?.(
'prepare-a',
{ source: 'npm:pi-web-search' },
new AbortController().signal,
)).rejects.toThrow(
'local_package_dependency_failed: Bundled Pi package manager is unavailable',
);
} finally {
for (const [key, value] of Object.entries(previous)) {
const environmentKey = key === 'bridge' ? 'MAKELORE_PI_BRIDGE_URL'
: key === 'token' ? 'MAKELORE_PI_WORKER_TOKEN'
: key === 'context' ? 'MAKELORE_PI_CONTEXT_FILE'
: 'MAKELORE_PI_WORKER_ROLE';
if (value === undefined) delete process.env[environmentKey];
else process.env[environmentKey] = value;
}
}
});
it('hydrates persisted Pi identity through reconnect and event replay into the capability registry', async () => {
const root = await mkdtemp(path.join(tmpdir(), 'makelore-pi-persisted-identity-'));
roots.push(root);