#!/usr/bin/env node "use strict"; const assert = require("node:assert/strict"); const fs = require("node:fs"); const os = require("node:os"); const path = require("node:path"); const { spawnSync } = require("node:child_process"); const repoRoot = path.resolve(__dirname, ".."); const tmpRoot = fs.mkdtempSync(path.join(os.tmpdir(), "mnote-convex-export-")); const fixturePath = path.join(tmpRoot, "fixture.json"); const outRoot = path.join(tmpRoot, "local-workspace"); const fixture = { workspace: { id: "ws_legacy_1", name: "旧云端空间", ownerId: "user_1", }, documents: [ { id: "doc_root", title: "Project", parent_id: null, sort_order: 1, content: "# Project\n\n![logo](/api/media/sign?assetId=asset_logo)\n", wide_layout: true, created_at: "2026-05-01T00:00:00.000Z", updated_at: "2026-05-02T00:00:00.000Z", }, { id: "doc_child", title: "Child Spec", parent_id: "doc_root", sort_order: 1, content: "Child body with [file](/api/media/sign?assetId=asset_pdf).\n", created_at: "2026-05-01T00:00:00.000Z", updated_at: "2026-05-02T00:00:00.000Z", }, ], mediaAssets: [ { id: "asset_logo", fileName: "logo.png", contentBase64: Buffer.from("PNG-FIXTURE").toString("base64"), }, { id: "asset_pdf", fileName: "spec.pdf", content: "PDF-FIXTURE", }, ], aiSessions: [ { sessionId: "sess_1", visibility: "private", events: [ { eventType: "session.created", sessionId: "sess_1", userId: "user_1" }, { eventType: "run.completed", sessionId: "sess_1", status: "completed" }, ], }, ], }; fs.writeFileSync(fixturePath, JSON.stringify(fixture, null, 2), "utf8"); const result = spawnSync( process.execPath, [ path.join(repoRoot, "scripts", "export-convex-workspace-to-local.js"), "--fixture", fixturePath, "--out", outRoot, ], { cwd: repoRoot, encoding: "utf8" }, ); assert.equal(result.status, 0, result.stderr || result.stdout); const projectMd = fs.readFileSync(path.join(outRoot, "pages", "Project.md"), "utf8"); const childMd = fs.readFileSync(path.join(outRoot, "pages", "Project", "Child Spec.md"), "utf8"); const pageIds = JSON.parse(fs.readFileSync(path.join(outRoot, ".mnote", "page-ids.json"), "utf8")); const pageOptions = JSON.parse(fs.readFileSync(path.join(outRoot, ".mnote", "page-options.json"), "utf8")); const resourceIndex = JSON.parse(fs.readFileSync(path.join(outRoot, ".mnote", "resource-index.json"), "utf8")); const sessionJsonl = fs.readFileSync(path.join(outRoot, "ai-sessions", "private", "sess_1.jsonl"), "utf8"); assert.match(projectMd, /mnote_id: doc_root/); assert.match(projectMd, /!\[logo\]\(Project\.assets\/logo\.png\)/); assert.match(childMd, /\[file\]\(Child Spec\.assets\/spec\.pdf\)/); assert.equal(pageIds.pages["pages/Project.md"], "local-mdid:doc_root"); assert.equal(pageIds.pages["pages/Project/Child Spec.md"], "local-mdid:doc_child"); assert.equal(pageOptions.pages["local-mdid:doc_root"].wideLayout, true); assert.equal(resourceIndex.assets.asset_logo.relativePath, "pages/Project.assets/logo.png"); assert.match(sessionJsonl, /"eventType":"run.completed"/); assert.equal(fs.readFileSync(path.join(outRoot, "pages", "Project.assets", "logo.png"), "utf8"), "PNG-FIXTURE"); assert.equal(fs.readFileSync(path.join(outRoot, "pages", "Project", "Child Spec.assets", "spec.pdf"), "utf8"), "PDF-FIXTURE"); fs.rmSync(tmpRoot, { recursive: true, force: true }); console.log(JSON.stringify({ ok: true, smoke: "task444-convex-workspace-export-local-fixture" }, null, 2));