Document the VSCode-like local-first product shape, demote Convex to a control-plane role, and retire stale architecture drafts. Add local workspace migration/export references plus smoke coverage for no-Convex managed workspace startup, local markdown title/body/options persistence, asset upload behavior, and Convex fixture export. Verification: git diff --cached --check; node scripts/check-local-first-convex-guard.js --staged; node scripts/task444-convex-workspace-export-local-fixture-smoke.js; node scripts/task166-local-first-managed-workspace-no-convex-smoke.js; node scripts/task167-local-markdown-title-body-options-no-convex-smoke.js
102 lines
3.6 KiB
JavaScript
102 lines
3.6 KiB
JavaScript
#!/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\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));
|