import assert from "node:assert/strict"; import fs from "node:fs"; import path from "node:path"; import { fileURLToPath, pathToFileURL } from "node:url"; import { assertCloudWebDistFresh, buildCloudWebDist, readCloudWebAppSource } from "./dist-contract.ts"; const rootDir = path.resolve(path.dirname(fileURLToPath(import.meta.url)), ".."); const repoRoot = path.resolve(rootDir, "../.."); const requiredFiles = Object.freeze([ "index.html", "styles.css", "app.ts", "app-device-pod.ts", "app-conversation.ts", "app-trace.ts", "app-helpers.ts", "auth.ts", "code-agent-facts.ts", "code-agent-status.ts", "message-markdown.ts", "live-status.ts", "runtime.ts", "favicon.svg", "favicon.ico", "help.md", "third_party/marked/marked.esm.js", "third_party/marked/LICENSE" ]); for (const file of requiredFiles) { const filePath = path.resolve(rootDir, file); if (!fs.existsSync(filePath)) throw new Error(`missing web asset: ${file}`); } await buildCloudWebDist(rootDir); await assertCloudWebDistFresh(rootDir); const html = readWeb("index.html"); const styles = readWeb("styles.css"); const app = readCloudWebAppSource(rootDir); assertTraceHelpersBound(readWeb("app-trace.ts")); const liveStatus = readWeb("live-status.ts"); const helpMarkdown = readWeb("help.md"); const faviconSvg = readWeb("favicon.svg"); const faviconIco = readWeb("favicon.ico"); const distContractScript = readWeb("scripts/dist-contract.ts"); const cloudApiServer = readRepo("internal/cloud/server.ts"); const cloudApiPayloads = readRepo("internal/cloud/server-rest-payloads.ts"); const devicePodData = readRepo("internal/device-pod/fake-data.mjs"); const devicePodService = readRepo("cmd/hwlab-device-pod/main.ts"); const protocol = readRepo("internal/protocol/index.mjs"); const deployJson = readRepo("deploy/deploy.json"); const artifactCatalog = readRepo("deploy/artifact-catalog.dev.json"); const rightSidebar = sectionById(html, "aside", "device-pod-sidebar"); assert.ok(rightSidebar, "Device Pod right sidebar must exist"); for (const term of [ "Device Pod", "设备目标看板", "id=\"device-pod-select\"", "id=\"device-pod-summary\"", "data-device-detail=\"pod\"", "id=\"device-pod-interfaces\"", "id=\"device-event-scroll\"", "id=\"device-event-text\"", "id=\"device-detail-dialog\"" ]) { assertIncludes(rightSidebar, term, `right sidebar missing ${term}`); } assert.doesNotMatch(rightSidebar, /]*role="button"[^>]*tabindex="0"/u, "Pod summary is a click/keyboard summary tile"); assert.match(rightSidebar, /