完成 Editor Agent Mock Agent P1 收尾

接入 Web Project 契约、SpacetimeDB 表与 api-server 控制面
新增 Mock Agent、静态构建 runner 与独立预览网关
补齐 /editor/agent 前端页面、服务客户端和 SSE 订阅
修复 sandbox 预览资源跨域加载并补充并发保护
接入本地 dev 预览端口漂移与服务身份初始化
更新 P1 技术方案、验收清单和 Hermes 共享记忆
This commit is contained in:
2026-06-16 17:31:25 +08:00
parent 80a382b034
commit 4b09ce3096
404 changed files with 14886 additions and 2497 deletions

View File

@@ -0,0 +1,139 @@
import type {
MockAgentTurnResponse,
WebProject,
WebProjectPatch,
WebProjectPreviewBuild,
WebProjectResponse,
WebProjectSnapshot,
WebProjectSnapshotResponse,
} from '../../../packages/shared/src/contracts/webProject';
import { requestJson, type ApiRequestOptions } from '../apiClient';
const WEB_PROJECT_CREATION_API_BASE = '/api/creation/web-project/projects';
const WEB_PROJECT_RUNTIME_API_BASE = '/api/runtime/web-project';
const WEB_PROJECT_REQUEST_OPTIONS = {
clearAuthOnUnauthorized: false,
notifyAuthStateChange: false,
} satisfies ApiRequestOptions;
type WebProjectPreviewBuildResponse = {
build: WebProjectPreviewBuild;
};
function jsonRequest(method: 'POST' | 'PATCH', body: Record<string, unknown>) {
return {
method,
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(body),
};
}
function projectUrl(projectId: string) {
return `${WEB_PROJECT_CREATION_API_BASE}/${encodeURIComponent(projectId)}`;
}
export async function createWebProject(input: { title?: string } = {}) {
const response = await requestJson<WebProjectResponse>(
WEB_PROJECT_CREATION_API_BASE,
jsonRequest('POST', { title: input.title }),
'创建 Web 工程失败',
WEB_PROJECT_REQUEST_OPTIONS,
);
return response.project;
}
export async function loadWebProject(projectId: string) {
const response = await requestJson<WebProjectResponse>(
projectUrl(projectId),
{ method: 'GET' },
'读取 Web 工程失败',
WEB_PROJECT_REQUEST_OPTIONS,
);
return response.project;
}
export async function loadActiveWebProjectSnapshot(projectId: string) {
const response = await requestJson<WebProjectSnapshotResponse>(
`${projectUrl(projectId)}/snapshot`,
{ method: 'GET' },
'读取 Web 工程快照失败',
WEB_PROJECT_REQUEST_OPTIONS,
);
return response.snapshot;
}
export async function saveWebProjectFiles(
projectId: string,
input: {
patch: WebProjectPatch;
baseSnapshotId: string;
summary?: string;
},
) {
const response = await requestJson<WebProjectSnapshotResponse>(
`${projectUrl(projectId)}/files`,
jsonRequest('PATCH', {
patch: input.patch,
baseSnapshotId: input.baseSnapshotId,
summary: input.summary,
}),
'保存 Web 工程文件失败',
WEB_PROJECT_REQUEST_OPTIONS,
);
return response.snapshot;
}
export async function submitMockAgentTurn(
projectId: string,
input: {
prompt: string;
baseSnapshotId: string;
},
) {
return requestJson<MockAgentTurnResponse>(
`${projectUrl(projectId)}/mock-agent-turns`,
jsonRequest('POST', {
prompt: input.prompt,
baseSnapshotId: input.baseSnapshotId,
}),
'提交 Mock Agent 指令失败',
WEB_PROJECT_REQUEST_OPTIONS,
);
}
export async function createWebProjectPreviewBuild(
projectId: string,
input: { snapshotId?: string } = {},
) {
const response = await requestJson<WebProjectPreviewBuildResponse>(
`${WEB_PROJECT_RUNTIME_API_BASE}/projects/${encodeURIComponent(projectId)}/preview-builds`,
jsonRequest('POST', { snapshotId: input.snapshotId }),
'创建 Web 工程预览构建失败',
WEB_PROJECT_REQUEST_OPTIONS,
);
return response.build;
}
export async function loadWebProjectPreviewBuild(jobId: string) {
const response = await requestJson<WebProjectPreviewBuildResponse>(
`${WEB_PROJECT_RUNTIME_API_BASE}/preview-builds/${encodeURIComponent(jobId)}`,
{ method: 'GET' },
'读取 Web 工程预览构建失败',
WEB_PROJECT_REQUEST_OPTIONS,
);
return response.build;
}
export type WebProjectClientSnapshotBundle = {
project: WebProject;
snapshot: WebProjectSnapshot;
};
export async function createWebProjectWithSnapshot(
input: { title?: string } = {},
): Promise<WebProjectClientSnapshotBundle> {
const project = await createWebProject(input);
const snapshot = await loadActiveWebProjectSnapshot(project.projectId);
return { project, snapshot };
}