fix(coding): remediate data service review findings

This commit is contained in:
2026-08-27 00:49:59 +08:00
parent 239e20d2cf
commit 38843e091f
15 changed files with 449 additions and 194 deletions

View File

@@ -237,6 +237,7 @@ describe.each(ASSETS)('generated Data Service SDK (%s)', (assetName) => {
describe('bundled Data Service Skill packaging', () => {
it('ships both canonical assets and an ordered workflow with explicit completion criteria', async () => {
const skill = await readFile(path.resolve('resources/coding-skills/data-service/SKILL.md'), 'utf8');
const readme = await readFile(path.resolve('README.md'), 'utf8');
const tsAsset = await readFile(path.join(ASSET_ROOT, 'makelore-data.ts'), 'utf8');
const jsAsset = await readFile(path.join(ASSET_ROOT, 'makelore-data.js'), 'utf8');
@@ -254,9 +255,14 @@ describe('bundled Data Service Skill packaging', () => {
expect(skill.indexOf('read-back')).toBeLessThan(skill.indexOf('report'));
expect(skill).toContain('src/lib/makelore-data.js');
expect(skill).toContain('makelore-data.js');
expect(skill).toContain('injectProjectData: true');
expect(skill).not.toContain('inject_project_data');
expect(skill).toContain('逐字复制');
expect(skill).toContain('no-op');
expect(skill).toContain('冲突');
expect(readme).toContain('data-service');
expect(readme).toContain('显式请求');
expect(readme).toContain('预览');
const packaged = await listProductCodingSkills(path.resolve('resources/coding-skills'));
const dataService = packaged.find(({ id }) => id === 'data-service');
expect(dataService).toMatchObject({ id: 'data-service', name: 'data-service' });

View File

@@ -14,5 +14,6 @@ describe('Data Service Host API registration', () => {
const worksIndex = routeList?.[1].indexOf('handleWorksRoutes') ?? -1;
expect(dataServiceIndex).toBeGreaterThanOrEqual(0);
expect(worksIndex).toBeGreaterThan(dataServiceIndex);
expect(source).not.toContain('handleDataServiceRoute = handleDataServiceRoutes');
});
});

View File

@@ -244,7 +244,7 @@ describe('Pi worker process', () => {
'--no-context-files',
'--no-approve',
'--tools',
'read,bash,edit,write,grep,find,ls,ask_user,subagent,agent_browser,game_asset_browser,game_asset_review,task_state,changed_file,runtime_context',
'read,bash,edit,write,grep,find,ls,ask_user,subagent,agent_browser,game_asset_browser,game_asset_review,task_state,changed_file,runtime_context,data_service_configure,data_service_inspect,data_service_list_projects,data_service_get_document,data_service_list_documents,data_service_put_document,data_service_delete_document,data_service_remove_collection,data_service_reset,data_service_remove_project',
'--model', 'model-a',
]);
expect(buildPiRpcArgs('sessions', ['--no-session'], ['read', 'grep', 'find', 'ls']))

View File

@@ -292,6 +292,16 @@ describe('locked Pi worker process smoke', () => {
'task_state',
'changed_file',
'runtime_context',
'data_service_configure',
'data_service_inspect',
'data_service_list_projects',
'data_service_get_document',
'data_service_list_documents',
'data_service_put_document',
'data_service_delete_document',
'data_service_remove_collection',
'data_service_reset',
'data_service_remove_project',
]));
expect(worker.stderrDiagnostic).not.toContain('Failed to load extension');
await expect(worker.stop('test_injection')).resolves.toMatchObject({ mode: 'stdin-close', code: 0 });

View File

@@ -127,13 +127,58 @@ describe('preview data session manager', () => {
expect(manager.getSnapshot()).toBeNull();
});
it('requires an HTTP loopback Origin and invalidates on browser lifecycle events', async () => {
it('accepts HTTP/HTTPS loopback Origins, including their default ports', async () => {
const { manager, projectPath } = await createManager();
for (const origin of [
'http://localhost',
'http://localhost:80',
'https://localhost',
'https://localhost:443',
'http://127.0.0.1',
'https://127.0.0.1:443',
'http://[::1]',
'https://[::1]:443',
]) {
await expect(manager.open({ projectPath, origin, browserGeneration: 1 }))
.resolves.toMatchObject({ origin: new URL(origin).origin });
}
await expect(manager.open({
projectPath,
origin: 'https://example.com:443',
browserGeneration: 1,
})).rejects.toMatchObject({ code: 'invalid_origin' });
await expect(manager.open({
projectPath,
origin: 'http://localhost:80/path',
browserGeneration: 1,
})).rejects.toMatchObject({ code: 'invalid_origin' });
});
it('requires matching browser generation before invalidating lifecycle events', async () => {
const { manager, projectPath } = await createManager();
await manager.open({ projectPath, origin: 'http://127.0.0.1:13210', browserGeneration: 2 });
manager.handleAgentBrowserLifecycle({
type: 'closed',
projectId: '11111111-1111-4111-8111-111111111111',
projectPath,
generation: 1,
url: 'http://127.0.0.1:13210/',
});
expect(manager.getSnapshot()).not.toBeNull();
manager.handleAgentBrowserLifecycle({
type: 'closed',
projectId: '11111111-1111-4111-8111-111111111111',
projectPath,
generation: 2,
url: 'http://127.0.0.1:13210/',
});
expect(manager.getSnapshot()).toBeNull();
});
it('invalidates on browser lifecycle events from the current generation', async () => {
const { manager, projectPath } = await createManager();
const lifecycleTypes: AgentBrowserLifecycleEvent['type'][] = [
'cross-origin-navigation',