feat: cut over rust web main shell
This commit is contained in:
@@ -0,0 +1,125 @@
|
||||
"use strict";
|
||||
|
||||
const BASE_URL = (process.env.MNOTE_UI_BASE_URL || "http://127.0.0.1:3000").replace(/\/+$/, "");
|
||||
const REQUEST_TIMEOUT_MS = Number(process.env.MNOTE_SMOKE_TIMEOUT_MS || 20_000);
|
||||
|
||||
function assert(condition, message) {
|
||||
if (!condition) {
|
||||
throw new Error(message);
|
||||
}
|
||||
}
|
||||
|
||||
async function fetchWithTimeout(path, init = {}) {
|
||||
const controller = new AbortController();
|
||||
const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);
|
||||
try {
|
||||
return await fetch(`${BASE_URL}${path}`, {
|
||||
...init,
|
||||
signal: controller.signal,
|
||||
});
|
||||
} finally {
|
||||
clearTimeout(timeout);
|
||||
}
|
||||
}
|
||||
|
||||
async function readTextResponse(path, init) {
|
||||
const response = await fetchWithTimeout(path, init);
|
||||
const text = await response.text();
|
||||
assert(response.ok, `${path} 请求失败: ${response.status} ${text.slice(0, 200)}`);
|
||||
return { response, text };
|
||||
}
|
||||
|
||||
function runtimeInputToolPlan() {
|
||||
return {
|
||||
kind: "tool",
|
||||
context: {
|
||||
deploymentId: null,
|
||||
projectId: null,
|
||||
workspaceId: "ws_task116",
|
||||
requestId: "req_task116",
|
||||
traceId: "trace_task116",
|
||||
actor: {
|
||||
actorType: "user",
|
||||
actorId: "task116-user",
|
||||
sessionId: null,
|
||||
},
|
||||
source: {
|
||||
channel: "rust-web",
|
||||
client: "task116-smoke",
|
||||
},
|
||||
tenantId: null,
|
||||
authToken: null,
|
||||
idempotencyKey: null,
|
||||
validateOnly: false,
|
||||
dryRun: false,
|
||||
},
|
||||
tool: {
|
||||
tool: "docs_search",
|
||||
kind: "query",
|
||||
mode: "plan",
|
||||
argsJson: { query: "Rust Web islands" },
|
||||
target: null,
|
||||
reason: "task116 owner smoke",
|
||||
refs: ["task-025"],
|
||||
},
|
||||
data: null,
|
||||
};
|
||||
}
|
||||
|
||||
async function checkSearchShell() {
|
||||
const { response, text } = await readTextResponse("/search?workspaceId=ws_task116&q=Rust");
|
||||
assert(response.headers.get("x-mnote-web-owner") === "mnote-web", "Search shell 缺少 mnote-web owner header");
|
||||
assert(response.headers.get("x-mnote-web-shell") === "search", "Search shell 缺少 search shell header");
|
||||
assert(text.includes("mnote.search_shell.v1"), "Search shell 缺少 contract schema");
|
||||
assert(text.includes("react_search_palette"), "Search shell 缺少 search palette island");
|
||||
return { owner: "mnote-web", shell: "search", island: "react_search_palette" };
|
||||
}
|
||||
|
||||
async function checkAiBridge() {
|
||||
const { response, text } = await readTextResponse("/api/hermes/bridge", {
|
||||
method: "POST",
|
||||
headers: { "content-type": "application/json" },
|
||||
body: JSON.stringify(runtimeInputToolPlan()),
|
||||
});
|
||||
assert(response.headers.get("x-mnote-web-owner") === "mnote-web", "AI bridge 缺少 mnote-web owner header");
|
||||
assert(response.headers.get("x-mnote-ai-bridge-owner") === "rust-web-hermes", "AI bridge 缺少 rust-web-hermes owner header");
|
||||
const payload = JSON.parse(text);
|
||||
assert(payload?.contract?.schema === "mnote.ai_bridge.v1", "AI bridge 缺少 contract schema");
|
||||
assert(payload?.contract?.toolEventOwner === "rust-web-hermes", "AI bridge tool event owner 未固定到 Hermes");
|
||||
return { owner: "mnote-web", bridgeOwner: "rust-web-hermes", schema: payload.contract.schema };
|
||||
}
|
||||
|
||||
async function checkMindmapShell() {
|
||||
const { response, text } = await readTextResponse("/mindmap/doc_task116/mind_task116");
|
||||
assert(response.headers.get("x-mnote-web-owner") === "mnote-web", "Mindmap shell 缺少 mnote-web owner header");
|
||||
assert(response.headers.get("x-mnote-web-shell") === "mindmap", "Mindmap shell 缺少 mindmap shell header");
|
||||
assert(text.includes("mnote.mindmap_shell.v1"), "Mindmap shell 缺少 contract schema");
|
||||
assert(text.includes('data-react-island="mindmap_runtime"'), "Mindmap shell 缺少 mindmap runtime island");
|
||||
return { owner: "mnote-web", shell: "mindmap", island: "mindmap_runtime" };
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const search = await checkSearchShell();
|
||||
const aiBridge = await checkAiBridge();
|
||||
const mindmap = await checkMindmapShell();
|
||||
console.log(
|
||||
JSON.stringify(
|
||||
{
|
||||
ok: true,
|
||||
baseUrl: BASE_URL,
|
||||
results: {
|
||||
search,
|
||||
aiBridge,
|
||||
mindmap,
|
||||
},
|
||||
},
|
||||
null,
|
||||
2,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
main().catch((error) => {
|
||||
console.error(error instanceof Error ? error.stack || error.message : String(error));
|
||||
process.exit(1);
|
||||
});
|
||||
Reference in New Issue
Block a user