mirror of
https://github.com/NeuralNomadsAI/CodeNomad.git
synced 2026-10-31 19:10:30 +00:00
## Summary - Update the main README for the shared OpenCode V2 service, current features, managed desktop setup, minimum/recommended OpenCode versions, and explicit service restart behavior. - Correct release links, actual Electron/Tauri artifact formats and architectures, Node guidance, remote authentication and SideCar configuration fields. - Align server and contributor documentation with the 0.20 baseline. - Replace the old hero screenshot with a current 1600x900 workspace rendered using real Solid components and synthetic demo data. - Include a reproducible Chromium capture script and provenance notes; external traffic is blocked and no user backend, daemon or provider is used. ## Preview  ## Validation - UI typecheck passes. - Chromium capture passes transcript, connected-state, agent, timeline and MCP readiness checks, with no uncaught renderer errors. - Resulting image inspected visually. - 20 local Markdown/image targets verified. - Staged git diff --check passes. Regenerate with: node packages/ui/scripts/capture-readme.mjs Documentation and capture tooling only; CI is not being monitored.
64 lines
3.6 KiB
JavaScript
64 lines
3.6 KiB
JavaScript
import assert from "node:assert/strict"
|
|
import { fileURLToPath } from "node:url"
|
|
import { mkdir } from "node:fs/promises"
|
|
import path from "node:path"
|
|
import { chromium } from "playwright"
|
|
import { createServer } from "vite"
|
|
import solid from "vite-plugin-solid"
|
|
|
|
const root = fileURLToPath(new URL("..", import.meta.url))
|
|
const output = path.resolve(root, "../../docs/screenshots/workspace-0.20.png")
|
|
const server = await createServer({ configFile: false, root, logLevel: "error",
|
|
plugins: [solid(), { name: "readme-capture", configureServer(server) {
|
|
server.middlewares.use("/api/events", (req, res) => {
|
|
res.writeHead(200, { "Content-Type": "text/event-stream", "Cache-Control": "no-cache" })
|
|
res.write(": documentation fixture\n\n")
|
|
req.on("close", () => res.end())
|
|
})
|
|
server.middlewares.use("/readme", async (_req, res) => {
|
|
res.setHeader("Content-Type", "text/html")
|
|
res.end(await server.transformIndexHtml("/readme", '<html lang="en"><head><title>CodeNomad — demo workspace</title></head><body><div id="root"></div><script type="module" src="/tests/browser/fixtures/readme-workspace.tsx"></script></body></html>'))
|
|
})
|
|
} }], resolve: { dedupe: ["solid-js"] }, optimizeDeps: { exclude: ["lucide-solid"] },
|
|
server: { host: "127.0.0.1", port: 0, hmr: false, watch: null },
|
|
})
|
|
let browser
|
|
try {
|
|
await server.listen()
|
|
const origin = `http://127.0.0.1:${server.httpServer.address().port}`
|
|
browser = await chromium.launch({ executablePath: process.env.CODENOMAD_BROWSER_PATH || undefined })
|
|
const page = await browser.newPage({ viewport: { width: 1600, height: 900 }, deviceScaleFactor: 1, colorScheme: "dark", timezoneId: "UTC" })
|
|
const errors = []
|
|
page.on("pageerror", error => { errors.push(error.message); console.error(error.message) })
|
|
page.on("console", message => { if (message.type() === "error") console.error(message.text()) })
|
|
// No user backend, shared daemon, provider, or external website is contacted.
|
|
await page.route("**/*", async route => {
|
|
const url = new URL(route.request().url())
|
|
if (url.origin !== origin) return route.abort()
|
|
if (url.pathname === "/api/events") return route.continue()
|
|
if (url.pathname.includes("/api/") || url.pathname.startsWith("/workspaces/")) {
|
|
return route.fulfill({ contentType: "application/json", body: "{}" })
|
|
}
|
|
return route.continue()
|
|
})
|
|
await page.goto(`${origin}/readme`)
|
|
await page.getByText("Keyboard navigation is ready", { exact: true }).waitFor()
|
|
await page.getByText("Connected", { exact: true }).waitFor()
|
|
await page.getByText("project-docs", { exact: true }).waitFor()
|
|
await page.getByRole("button", { name: "Agent: Build", exact: true }).waitFor()
|
|
assert.equal(await page.locator("[data-app-tab-id]").count(), 8, "Show all eight demo projects")
|
|
await page.getByText("Add workspace notifications", { exact: true }).waitFor()
|
|
await page.waitForFunction(() => Number(document.querySelector(".message-timeline")?.getAttribute("data-segment-count")) >= 180)
|
|
await page.locator('.message-timeline-segment[data-message-id="msg_01"]').waitFor()
|
|
await page.evaluate(() => document.fonts.ready)
|
|
await page.waitForTimeout(1500)
|
|
assert.equal(await page.locator(".keyboard-hints:visible, .kbd-hint:visible").count(), 0,
|
|
"Keyboard shortcut hints must remain hidden with the default preference")
|
|
assert.deepEqual(errors, [], "The documentation fixture must render without uncaught errors")
|
|
await mkdir(path.dirname(output), { recursive: true })
|
|
await page.screenshot({ path: output, animations: "disabled" })
|
|
console.log(output)
|
|
} finally {
|
|
await browser?.close()
|
|
await server.close()
|
|
}
|