feat(coding): add plugin capability policy registry

This commit is contained in:
brother7 committed 2026-08-27 16:32:03 +08:00
1 parent d9c9a2b0dd
commit a0361a3cda
14 files changed
+2169 -245

No files matched your search

+65 -29
View File
@@ -18,6 +18,7 @@ import {
} from '../../electron/coding-projects/skill-registry';
import { PiProductTools } from '../../electron/coding-runtime/pi/product-tools';
import { productToolDetails } from '../../electron/coding-runtime/product-tool-protocol';
import type { CodingCapabilityRegistry } from '../../electron/coding-plugins/registry';
import type { DataServiceOperations } from '../../electron/services/data-service-client';
const exec = promisify(execFile);
@@ -233,35 +234,38 @@ describe('PI-090 product tools', () => {
})).toBeNull();
expect(productToolDetails({ schema: 'task-state.v1', tasks: [] })).toBeNull();
expect(productToolDetails({
schema: 'data-service.v1',
operation: 'data_service_inspect',
schema: 'makelore-capability.v1',
plugin_id: 'makelore.data-service',
plugin_version: '1.0.0',
capability_id: 'data-service.control',
operation: 'inspect',
request_id: 'pi:run-a:resource-a',
success: true,
status: 200,
code: null,
error: null,
retryable: false,
billing: { mode: 'included', status: 'included' },
payload_schema: 'data-service.v1',
data: { instance_id: 'instance-a' },
owner: 'must-be-dropped',
})).toEqual({
schema: 'data-service.v1',
operation: 'data_service_inspect',
success: true,
status: 200,
code: null,
error: null,
retryable: false,
data: { instance_id: 'instance-a' },
});
expect(productToolDetails({
schema: 'data-service.v1',
operation: 'data_service_unknown',
success: true,
status: 200,
code: null,
error: null,
retryable: false,
data: null,
})).toBeNull();
expect(productToolDetails({
schema: 'makelore-capability.v1',
plugin_id: 'makelore.data-service',
plugin_version: '1.0.0',
capability_id: 'data-service.control',
operation: 'inspect',
request_id: 'pi:run-a:resource-a',
success: true,
status: 200,
code: null,
error: null,
retryable: false,
billing: { mode: 'included', status: 'included' },
payload_schema: 'data-service.v1',
data: null,
})).toMatchObject({ schema: 'makelore-capability.v1', operation: 'inspect' });
});
it('stores browser screenshots as attachment ids and never returns base64', async () => {
@@ -413,12 +417,42 @@ describe('PI-090 product tools', () => {
expect(dataService.reset).toHaveBeenCalledWith({ confirmed: true }, root);
expect(dataService.removeProject).toHaveBeenCalledWith({ confirmed: true }, root);
expect(removed.details).toMatchObject({
schema: 'data-service.v1', operation: 'data_service_remove_project',
schema: 'makelore-capability.v1', operation: 'remove_project',
plugin_id: 'makelore.data-service', request_id: 'pi:run-a:resource-a',
billing: { mode: 'included', status: 'included' }, payload_schema: 'data-service.v1',
success: true, status: 200, data: { removed: true },
});
expect(JSON.stringify(removed)).not.toContain(root);
});
it('delegates any non-core product tool to the capability registry', async () => {
const root = await temporaryRoot('makelore-pi-generic-plugin-');
const invoke = vi.fn().mockResolvedValue({
content: [{ type: 'text', text: 'plugin-result' }],
details: {
schema: 'makelore-capability.v1', plugin_id: 'makelore.example', plugin_version: '1.0.0',
capability_id: 'example.capability', operation: 'run', request_id: 'pi:run-a:resource-a',
success: true, status: 200, code: null, error: null, retryable: false,
billing: { mode: 'included', status: 'included' }, payload_schema: 'example.v1', data: {},
},
});
const registry = { invoke } as unknown as CodingCapabilityRegistry;
const tools = new PiProductTools({
browser: {} as AgentBrowserModule,
attachments: new CodingAttachmentStore(path.join(root, 'attachments')),
bundledSkillsDir: path.resolve('resources/coding-skills'),
capabilityRegistry: registry,
});
const context = {
conversationId: 'conversation-a', runId: 'run-a', resourceId: 'resource-a',
projectId: 'local-project-a', projectPath: root, skillIds: [],
};
await tools.execute('example_tool', context, { value: 1 });
expect(invoke).toHaveBeenCalledWith({
toolName: 'example_tool', context, workerRole: 'parent', effectiveSkillIds: [], value: { value: 1 },
});
});
it('rejects forbidden tool fields and destructive calls without literal confirmation', async () => {
const root = await temporaryRoot('makelore-pi-data-input-');
const dataService = {
@@ -438,15 +472,17 @@ describe('PI-090 product tools', () => {
projectId: 'local-project-a', projectPath: root, skillIds: [],
};
await expect(tools.execute('data_service_inspect', context, { owner: 'owner-a' })).rejects.toThrow(
'Data Service tool input is invalid',
);
await expect(tools.execute('data_service_inspect', context, { owner: 'owner-a' })).resolves.toMatchObject({
details: { schema: 'makelore-capability.v1', code: 'plugin_input_invalid', status: 422 },
});
await expect(tools.execute('data_service_put_document', context, {
collection: 'todos', document_id: 'one', data: {}, path: root,
})).rejects.toThrow('Data Service tool input is invalid');
await expect(tools.execute('data_service_remove_project', context, { confirmed: false })).rejects.toThrow(
'Data Service tool input is invalid',
);
})).resolves.toMatchObject({
details: { schema: 'makelore-capability.v1', code: 'plugin_input_invalid', status: 422 },
});
await expect(tools.execute('data_service_remove_project', context, { confirmed: false })).resolves.toMatchObject({
details: { schema: 'makelore-capability.v1', code: 'plugin_input_invalid', status: 422 },
});
expect(dataService.inspect).not.toHaveBeenCalled();
expect(dataService.removeProject).not.toHaveBeenCalled();
});