@bitcobblers/wod-wiki-tools 0.36.2134 → 0.36.2136
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin/wod.cjs +274 -69
- package/dist/bin/wod.cjs.map +1 -1
- package/dist/bin/wod.mjs +5 -14
- package/dist/bin/wod.mjs.map +1 -1
- package/dist/{chunk-B3QJYJVI.mjs → chunk-6QNX4FED.mjs} +217 -52
- package/dist/chunk-6QNX4FED.mjs.map +1 -0
- package/dist/{chunk-EUQWEX6Z.mjs → chunk-CYKNTEGY.mjs} +3 -3
- package/dist/chunk-CYKNTEGY.mjs.map +1 -0
- package/dist/{compiler-KT6P3AC6.mjs → chunk-FZKXOYMJ.mjs} +4 -5
- package/dist/chunk-FZKXOYMJ.mjs.map +1 -0
- package/dist/{chunk-32FASQP5.mjs → chunk-MA6BBTWC.mjs} +54 -12
- package/dist/chunk-MA6BBTWC.mjs.map +1 -0
- package/dist/{chunk-K3GZZFAC.mjs → chunk-V23POHG2.mjs} +10 -9
- package/dist/chunk-V23POHG2.mjs.map +1 -0
- package/dist/compiler-CTPLIZJK.mjs +9 -0
- package/dist/compiler-CTPLIZJK.mjs.map +1 -0
- package/dist/index.cjs +274 -58
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.mjs +5 -4
- package/dist/server/app.cjs +7 -6
- package/dist/server/app.cjs.map +1 -1
- package/dist/server/app.mjs +1 -1
- package/dist/server-JXECWS4A.mjs +11 -0
- package/dist/{server-3TJZDKQC.mjs.map → server-JXECWS4A.mjs.map} +1 -1
- package/dist/web/playground/assets/main-B-bffxwE.css +2 -0
- package/dist/web/playground/assets/main-iLSeEl2E.js +188 -0
- package/dist/web/playground/assets/{statementBuilderFlow-DXlHS86r.js → statementBuilderFlow-ugwi0fu0.js} +2 -2
- package/dist/web/playground/assets/{vendor-codemirror-BtJgoBjf.js → vendor-codemirror-C41SFn-r.js} +2 -2
- package/dist/web/playground/assets/vendor-g-NJOjvC.js +198 -0
- package/dist/web/playground/index.html +4 -4
- package/dist/web/playground/seed/core/chunks/canvas.20048125.json +1 -0
- package/dist/web/playground/seed/core/manifest.json +7 -7
- package/dist/web/playground/seed/core/report.html +11 -11
- package/dist/web/server/assets/main-B-bffxwE.css +2 -0
- package/dist/web/server/assets/main-CRyLxlPN.js +187 -0
- package/dist/web/server/assets/{statementBuilderFlow-CXugzTXB.js → statementBuilderFlow-40WaYjdq.js} +2 -2
- package/dist/web/server/assets/{vendor-codemirror-BtJgoBjf.js → vendor-codemirror-C41SFn-r.js} +2 -2
- package/dist/web/server/assets/vendor-g-NJOjvC.js +198 -0
- package/dist/web/server/index.html +4 -4
- package/dist/web/server/seed/core/chunks/canvas.20048125.json +1 -0
- package/dist/web/server/seed/core/manifest.json +7 -7
- package/dist/web/server/seed/core/report.html +9 -9
- package/package.json +6 -8
- package/dist/chunk-32FASQP5.mjs.map +0 -1
- package/dist/chunk-B3QJYJVI.mjs.map +0 -1
- package/dist/chunk-EUQWEX6Z.mjs.map +0 -1
- package/dist/chunk-K3GZZFAC.mjs.map +0 -1
- package/dist/compiler-KT6P3AC6.mjs.map +0 -1
- package/dist/server-3TJZDKQC.mjs +0 -11
- package/dist/web/playground/assets/main-Bhn9NHgQ.css +0 -2
- package/dist/web/playground/assets/main-Bj_mxNMk.js +0 -212
- package/dist/web/playground/assets/vendor-BlJqgFME.js +0 -201
- package/dist/web/playground/seed/core/chunks/canvas.054cd7db.json +0 -1
- package/dist/web/server/assets/main-Bhn9NHgQ.css +0 -2
- package/dist/web/server/assets/main-CfAVkURA.js +0 -211
- package/dist/web/server/assets/vendor-BlJqgFME.js +0 -201
- package/dist/web/server/seed/core/chunks/canvas.054cd7db.json +0 -1
package/dist/bin/wod.cjs
CHANGED
|
@@ -9,12 +9,17 @@ var path = require('path');
|
|
|
9
9
|
var wodWikiWql = require('@bitcobblers/wod-wiki-wql');
|
|
10
10
|
var crypto = require('crypto');
|
|
11
11
|
var promises = require('fs/promises');
|
|
12
|
+
var stream = require('stream');
|
|
12
13
|
var sql = require('@bitcobblers/wod-wiki-storage/sql');
|
|
13
14
|
var wodWikiStorage = require('@bitcobblers/wod-wiki-storage');
|
|
14
|
-
var
|
|
15
|
+
var http = require('http');
|
|
15
16
|
var wodWikiEngine = require('@bitcobblers/wod-wiki-engine');
|
|
16
17
|
|
|
17
18
|
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
|
19
|
+
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
20
|
+
|
|
21
|
+
var http__default = /*#__PURE__*/_interopDefault(http);
|
|
22
|
+
|
|
18
23
|
var __defProp = Object.defineProperty;
|
|
19
24
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
20
25
|
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
@@ -1067,10 +1072,10 @@ var init_errors = __esm({
|
|
|
1067
1072
|
};
|
|
1068
1073
|
}
|
|
1069
1074
|
});
|
|
1070
|
-
function
|
|
1071
|
-
const
|
|
1072
|
-
if (
|
|
1073
|
-
return
|
|
1075
|
+
function streamFile(path) {
|
|
1076
|
+
const bun = globalThis.Bun;
|
|
1077
|
+
if (bun?.file) return bun.file(path);
|
|
1078
|
+
return stream.Readable.toWeb(fs.createReadStream(path));
|
|
1074
1079
|
}
|
|
1075
1080
|
function jsonParam(url, name) {
|
|
1076
1081
|
const raw = qget(url, name);
|
|
@@ -1159,14 +1164,14 @@ async function realpathSafe(path) {
|
|
|
1159
1164
|
async function serveFile(real, rel) {
|
|
1160
1165
|
const cache = rel.includes("seed/chunks/") ? "public, max-age=31536000, immutable" : "no-cache";
|
|
1161
1166
|
const ext = rel.slice(rel.lastIndexOf(".") + 1).toLowerCase();
|
|
1162
|
-
return new Response(
|
|
1167
|
+
return new Response(streamFile(real), {
|
|
1163
1168
|
headers: { "content-type": MIME[ext] ?? "application/octet-stream", "cache-control": cache }
|
|
1164
1169
|
});
|
|
1165
1170
|
}
|
|
1166
1171
|
async function serveSpaShell(distRoot) {
|
|
1167
1172
|
const index = await realpathSafe(path.join(distRoot, "index.html"));
|
|
1168
1173
|
if (index && (index === distRoot || index.startsWith(distRoot + path.sep)) && await promises.stat(index).then((s) => s.isFile(), () => false)) {
|
|
1169
|
-
return new Response(
|
|
1174
|
+
return new Response(streamFile(index), {
|
|
1170
1175
|
headers: { "content-type": MIME.html, "cache-control": "no-cache" }
|
|
1171
1176
|
});
|
|
1172
1177
|
}
|
|
@@ -1353,12 +1358,55 @@ var server_exports = {};
|
|
|
1353
1358
|
__export(server_exports, {
|
|
1354
1359
|
runCliServer: () => runCliServer
|
|
1355
1360
|
});
|
|
1356
|
-
function
|
|
1361
|
+
function withResolvers() {
|
|
1362
|
+
let resolve2;
|
|
1363
|
+
let reject;
|
|
1364
|
+
const promise = new Promise((res, rej) => {
|
|
1365
|
+
resolve2 = res;
|
|
1366
|
+
reject = rej;
|
|
1367
|
+
});
|
|
1368
|
+
return { promise, resolve: resolve2, reject };
|
|
1369
|
+
}
|
|
1370
|
+
function startHttpServer(handler, host, port) {
|
|
1357
1371
|
const b = globalThis.Bun;
|
|
1358
|
-
if (
|
|
1359
|
-
|
|
1372
|
+
if (b?.serve) {
|
|
1373
|
+
const s = b.serve({ port, hostname: host, fetch: handler });
|
|
1374
|
+
return Promise.resolve({ stop: () => s.stop() });
|
|
1360
1375
|
}
|
|
1361
|
-
|
|
1376
|
+
const { promise, resolve: resolve2, reject } = withResolvers();
|
|
1377
|
+
const server = http__default.default.createServer(async (req, res) => {
|
|
1378
|
+
try {
|
|
1379
|
+
const url = new URL(req.url || "/", `http://${req.headers.host || `${host}:${port}`}`);
|
|
1380
|
+
const hasBody = req.method !== "GET" && req.method !== "HEAD";
|
|
1381
|
+
const webReq = new Request(url, {
|
|
1382
|
+
method: req.method,
|
|
1383
|
+
headers: req.headers,
|
|
1384
|
+
body: hasBody ? stream.Readable.toWeb(req) : null,
|
|
1385
|
+
...hasBody ? { duplex: "half" } : {}
|
|
1386
|
+
});
|
|
1387
|
+
const webRes = await handler(webReq);
|
|
1388
|
+
res.writeHead(webRes.status, Object.fromEntries(webRes.headers.entries()));
|
|
1389
|
+
if (webRes.body) {
|
|
1390
|
+
stream.Readable.fromWeb(webRes.body).pipe(res);
|
|
1391
|
+
} else {
|
|
1392
|
+
res.end();
|
|
1393
|
+
}
|
|
1394
|
+
} catch {
|
|
1395
|
+
res.statusCode = 500;
|
|
1396
|
+
res.end("internal server error");
|
|
1397
|
+
}
|
|
1398
|
+
});
|
|
1399
|
+
server.once("error", reject);
|
|
1400
|
+
server.listen(port, host, () => {
|
|
1401
|
+
resolve2({
|
|
1402
|
+
stop: () => {
|
|
1403
|
+
const close = withResolvers();
|
|
1404
|
+
server.close(() => close.resolve());
|
|
1405
|
+
return close.promise;
|
|
1406
|
+
}
|
|
1407
|
+
});
|
|
1408
|
+
});
|
|
1409
|
+
return promise;
|
|
1362
1410
|
}
|
|
1363
1411
|
function moduleDir() {
|
|
1364
1412
|
const p = nodePath();
|
|
@@ -1412,7 +1460,6 @@ function resolveBind(mode, options) {
|
|
|
1412
1460
|
return { host, port };
|
|
1413
1461
|
}
|
|
1414
1462
|
async function runCliServer(mode, options, writeOut) {
|
|
1415
|
-
const runtime = bun();
|
|
1416
1463
|
const { host, port } = resolveBind(mode, options);
|
|
1417
1464
|
let db;
|
|
1418
1465
|
let dbLabel = "no database";
|
|
@@ -1433,7 +1480,7 @@ async function runCliServer(mode, options, writeOut) {
|
|
|
1433
1480
|
try {
|
|
1434
1481
|
const dist = resolveDist(mode, options);
|
|
1435
1482
|
const handler = createHandler(db?.db ?? null, { playgroundDist: dist });
|
|
1436
|
-
server =
|
|
1483
|
+
server = await startHttpServer(handler, host, port);
|
|
1437
1484
|
if (mode === "server") {
|
|
1438
1485
|
writeOut(`wod server: http://${host}:${port} \u2014 ${dbLabel} \xB7 dist ${dist}`);
|
|
1439
1486
|
} else {
|
|
@@ -2131,18 +2178,24 @@ async function saveSource(db, options, startTime) {
|
|
|
2131
2178
|
throw new Error(`Stale Note source revision for ${noteId}; expected ${expected}`);
|
|
2132
2179
|
}
|
|
2133
2180
|
let sourceRevision = existing?.rawContent === options.source ? existing.sourceRevision : (existing?.sourceRevision ?? 0) + 1;
|
|
2181
|
+
const history = await tx.readonly("block_revisions").getAllFromIndex("by-note", noteId);
|
|
2182
|
+
const latest = /* @__PURE__ */ new Map();
|
|
2183
|
+
for (const row of history) {
|
|
2184
|
+
if ((latest.get(row.blockId)?.version ?? 0) < row.version) latest.set(row.blockId, row);
|
|
2185
|
+
}
|
|
2186
|
+
let ordinal = 0;
|
|
2134
2187
|
const blocks = wodWikiCore.reconcileNoteBlocks(options.source, {
|
|
2135
2188
|
sourceRevision,
|
|
2136
2189
|
blocks: options.blocks ?? (existing?.rawContent === options.source ? existing.blocks : void 0),
|
|
2137
2190
|
registeredWidgets,
|
|
2138
|
-
createId:
|
|
2191
|
+
createId: () => {
|
|
2192
|
+
while (true) {
|
|
2193
|
+
const candidate = uuid5(CLI_UUID_NAMESPACE, `${noteId}:block:${ordinal++}`);
|
|
2194
|
+
if (!latest.has(candidate)) return candidate;
|
|
2195
|
+
}
|
|
2196
|
+
}
|
|
2139
2197
|
});
|
|
2140
2198
|
wodWikiCore.validateNoteBlocks(options.source, blocks, sourceRevision, { registeredWidgets });
|
|
2141
|
-
const history = await tx.readonly("block_revisions").getAllFromIndex("by-note", noteId);
|
|
2142
|
-
const latest = /* @__PURE__ */ new Map();
|
|
2143
|
-
for (const row of history) {
|
|
2144
|
-
if ((latest.get(row.blockId)?.version ?? 0) < row.version) latest.set(row.blockId, row);
|
|
2145
|
-
}
|
|
2146
2199
|
const revisions = [];
|
|
2147
2200
|
for (const block of Object.values(blocks)) {
|
|
2148
2201
|
const saved = latest.get(block.id);
|
|
@@ -2164,6 +2217,8 @@ async function saveSource(db, options, startTime) {
|
|
|
2164
2217
|
sourceRevision++;
|
|
2165
2218
|
for (const block of Object.values(blocks)) block.sourceRevision = sourceRevision;
|
|
2166
2219
|
}
|
|
2220
|
+
const fm = wodWikiEngine.readFrontmatterMeta(options.source);
|
|
2221
|
+
const catalog = typeof fm["catalog"] === "string" && fm["catalog"].trim() || typeof fm["collection"] === "string" && fm["collection"].trim() || existing?.catalog;
|
|
2167
2222
|
const note = {
|
|
2168
2223
|
...existing,
|
|
2169
2224
|
id: noteId,
|
|
@@ -2173,7 +2228,8 @@ async function saveSource(db, options, startTime) {
|
|
|
2173
2228
|
createdAt: existing?.createdAt ?? now,
|
|
2174
2229
|
rawContent: options.source,
|
|
2175
2230
|
sourceRevision,
|
|
2176
|
-
blocks
|
|
2231
|
+
blocks,
|
|
2232
|
+
...catalog ? { catalog } : {}
|
|
2177
2233
|
};
|
|
2178
2234
|
const priorRows = await tx.readonly("block_index").getAllFromIndex("by-note", noteId);
|
|
2179
2235
|
const priorEfforts = await tx.readonly("block_efforts").getAllFromIndex("by-note", noteId);
|
|
@@ -2201,6 +2257,7 @@ async function saveSource(db, options, startTime) {
|
|
|
2201
2257
|
noteTitle: note.title,
|
|
2202
2258
|
createdAt: prior?.createdAt ?? now,
|
|
2203
2259
|
blockContentId: fingerprint,
|
|
2260
|
+
...catalog ? { catalog } : {},
|
|
2204
2261
|
...note.sourceId ? { sourceId: note.sourceId } : {}
|
|
2205
2262
|
});
|
|
2206
2263
|
if (block.kind === "wod") {
|
|
@@ -2418,6 +2475,136 @@ function defaultSeedDirs(cwd) {
|
|
|
2418
2475
|
return ["core", "community"].map((id) => nodePath().resolve(base, id)).filter((dir) => nodeFs().existsSync(nodePath().resolve(dir, "manifest.json")));
|
|
2419
2476
|
}
|
|
2420
2477
|
|
|
2478
|
+
// src/cli/publish.ts
|
|
2479
|
+
init_db();
|
|
2480
|
+
init_contract();
|
|
2481
|
+
init_compiler();
|
|
2482
|
+
init_report();
|
|
2483
|
+
async function publishCatalogSeed(db, options) {
|
|
2484
|
+
const t0 = Date.now();
|
|
2485
|
+
const fs = nodeFs();
|
|
2486
|
+
const path = nodePath();
|
|
2487
|
+
const allNotes = await db.storage.readonly("notes").getAll();
|
|
2488
|
+
if (allNotes.length === 0) {
|
|
2489
|
+
throw new Error(`[wod publish] No notes found in database ${db.path}`);
|
|
2490
|
+
}
|
|
2491
|
+
const notesByCatalog = /* @__PURE__ */ new Map();
|
|
2492
|
+
for (const note of allNotes) {
|
|
2493
|
+
const fm = wodWikiEngine.readFrontmatterMeta(note.rawContent);
|
|
2494
|
+
const cat = typeof fm["catalog"] === "string" && fm["catalog"].trim() || typeof fm["collection"] === "string" && fm["collection"].trim() || note.catalog || wodWikiWql.catalogOfItem(note);
|
|
2495
|
+
const key = cat || "__uncataloged__";
|
|
2496
|
+
const list = notesByCatalog.get(key) ?? [];
|
|
2497
|
+
list.push(note);
|
|
2498
|
+
notesByCatalog.set(key, list);
|
|
2499
|
+
}
|
|
2500
|
+
const targetCatalogs = /* @__PURE__ */ new Map();
|
|
2501
|
+
if (options.catalog) {
|
|
2502
|
+
const matching = notesByCatalog.get(options.catalog);
|
|
2503
|
+
if (matching) {
|
|
2504
|
+
targetCatalogs.set(options.catalog, matching);
|
|
2505
|
+
} else if (notesByCatalog.has("__uncataloged__") && notesByCatalog.size === 1) {
|
|
2506
|
+
targetCatalogs.set(options.catalog, notesByCatalog.get("__uncataloged__"));
|
|
2507
|
+
} else {
|
|
2508
|
+
const available = [...notesByCatalog.keys()].filter((k) => k !== "__uncataloged__");
|
|
2509
|
+
throw new Error(
|
|
2510
|
+
`[wod publish] Catalog "${options.catalog}" not found in ${db.path}.` + (available.length > 0 ? ` Available catalogs: ${available.join(", ")}` : "")
|
|
2511
|
+
);
|
|
2512
|
+
}
|
|
2513
|
+
} else {
|
|
2514
|
+
for (const [cat, notes] of notesByCatalog.entries()) {
|
|
2515
|
+
targetCatalogs.set(cat === "__uncataloged__" ? "default" : cat, notes);
|
|
2516
|
+
}
|
|
2517
|
+
}
|
|
2518
|
+
const allIndexRows = await db.storage.readonly("block_index").getAll();
|
|
2519
|
+
const allEffortRows = await db.storage.readonly("block_efforts").getAll();
|
|
2520
|
+
const indexByNote = /* @__PURE__ */ new Map();
|
|
2521
|
+
for (const row of allIndexRows) {
|
|
2522
|
+
const list = indexByNote.get(row.noteId) ?? [];
|
|
2523
|
+
list.push(row);
|
|
2524
|
+
indexByNote.set(row.noteId, list);
|
|
2525
|
+
}
|
|
2526
|
+
const effortsByNote = /* @__PURE__ */ new Map();
|
|
2527
|
+
for (const row of allEffortRows) {
|
|
2528
|
+
const list = effortsByNote.get(row.noteId) ?? [];
|
|
2529
|
+
list.push(row);
|
|
2530
|
+
effortsByNote.set(row.noteId, list);
|
|
2531
|
+
}
|
|
2532
|
+
const outDir = path.resolve(process.cwd(), options.outDir);
|
|
2533
|
+
const chunksDir = path.join(outDir, "chunks");
|
|
2534
|
+
fs.mkdirSync(chunksDir, { recursive: true });
|
|
2535
|
+
const manifestChunks = [];
|
|
2536
|
+
let totalNotes = 0;
|
|
2537
|
+
const publishedCatalogs = [];
|
|
2538
|
+
for (const [catalogName, notes] of targetCatalogs.entries()) {
|
|
2539
|
+
publishedCatalogs.push(catalogName);
|
|
2540
|
+
const chunkRows = [];
|
|
2541
|
+
for (const note of notes) {
|
|
2542
|
+
const stem = (note.title || note.id).toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/(^-|-$)/g, "") || "note";
|
|
2543
|
+
const notePath = note.sourcePath ?? `markdown/collections/${catalogName}/${stem}.md`;
|
|
2544
|
+
const noteBlockIndex = indexByNote.get(note.id) ?? [];
|
|
2545
|
+
const noteBlockEfforts = effortsByNote.get(note.id) ?? [];
|
|
2546
|
+
const blockIndex = noteBlockIndex.length > 0 ? noteBlockIndex.map((b) => ({
|
|
2547
|
+
...b,
|
|
2548
|
+
isStatic: true,
|
|
2549
|
+
sourceId: b.sourceId ?? `collection:${catalogName}/${stem}`,
|
|
2550
|
+
sourcePath: b.sourcePath ?? notePath,
|
|
2551
|
+
catalog: catalogName
|
|
2552
|
+
})) : compileSeedRow(notePath, note.rawContent, {
|
|
2553
|
+
routeId: `${catalogName}/${stem}`,
|
|
2554
|
+
sourceId: `collection:${catalogName}/${stem}`,
|
|
2555
|
+
createdAt: note.createdAt,
|
|
2556
|
+
noteTitle: note.title
|
|
2557
|
+
}).blockIndex;
|
|
2558
|
+
const blockEfforts = noteBlockEfforts.map((e) => ({
|
|
2559
|
+
...e,
|
|
2560
|
+
isStatic: true,
|
|
2561
|
+
sourcePath: e.sourcePath ?? notePath
|
|
2562
|
+
}));
|
|
2563
|
+
chunkRows.push({
|
|
2564
|
+
path: notePath,
|
|
2565
|
+
content: note.rawContent,
|
|
2566
|
+
blocks: note.blocks,
|
|
2567
|
+
blockIndex,
|
|
2568
|
+
blockEfforts
|
|
2569
|
+
});
|
|
2570
|
+
}
|
|
2571
|
+
const chunkId = `collection.${catalogName}`;
|
|
2572
|
+
const json2 = JSON.stringify(chunkRows);
|
|
2573
|
+
const digest = nodeCrypto().createHash("sha256").update(json2).digest();
|
|
2574
|
+
const sha = [...digest].map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
2575
|
+
const chunkFile = `chunks/${chunkId}.${sha.slice(0, 8)}.json`;
|
|
2576
|
+
fs.writeFileSync(path.join(outDir, chunkFile), json2, "utf-8");
|
|
2577
|
+
manifestChunks.push({
|
|
2578
|
+
id: chunkId,
|
|
2579
|
+
path: chunkFile,
|
|
2580
|
+
sha256: sha,
|
|
2581
|
+
bytes: Buffer.byteLength(json2, "utf8"),
|
|
2582
|
+
count: chunkRows.length,
|
|
2583
|
+
kind: "notes"
|
|
2584
|
+
});
|
|
2585
|
+
totalNotes += chunkRows.length;
|
|
2586
|
+
}
|
|
2587
|
+
const manifest = {
|
|
2588
|
+
schema: SEED_SCHEMA2,
|
|
2589
|
+
version: options.version ?? 1,
|
|
2590
|
+
versionLabel: `v${options.version ?? 1}`,
|
|
2591
|
+
builtAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2592
|
+
chunks: manifestChunks
|
|
2593
|
+
};
|
|
2594
|
+
fs.writeFileSync(path.join(outDir, "manifest.json"), JSON.stringify(manifest, null, 2) + "\n", "utf-8");
|
|
2595
|
+
writeBuildReport(outDir, {
|
|
2596
|
+
manifest,
|
|
2597
|
+
totalMs: Date.now() - t0,
|
|
2598
|
+
passMs: { scan: 0, blockIndex: 0, parseGate: 0, blockEfforts: 0, write: Date.now() - t0 },
|
|
2599
|
+
fileCount: totalNotes});
|
|
2600
|
+
return {
|
|
2601
|
+
manifest,
|
|
2602
|
+
outDir,
|
|
2603
|
+
catalogs: publishedCatalogs,
|
|
2604
|
+
totalNotes
|
|
2605
|
+
};
|
|
2606
|
+
}
|
|
2607
|
+
|
|
2421
2608
|
// src/cli/formatters.ts
|
|
2422
2609
|
function escapeCsvField(field) {
|
|
2423
2610
|
if (field === void 0 || field === null) return "";
|
|
@@ -2708,7 +2895,7 @@ ${escapeCsvField(data.parsed.metric)},${data.scalar},${escapeCsvField(data.unit
|
|
|
2708
2895
|
}
|
|
2709
2896
|
|
|
2710
2897
|
// src/version.ts
|
|
2711
|
-
var VERSION = "0.36.
|
|
2898
|
+
var VERSION = "0.36.2136";
|
|
2712
2899
|
|
|
2713
2900
|
// src/cli/runner.ts
|
|
2714
2901
|
function getFs2() {
|
|
@@ -2853,9 +3040,16 @@ function parseCliArgs(args) {
|
|
|
2853
3040
|
i++;
|
|
2854
3041
|
} else if (arg.startsWith("--dir=")) {
|
|
2855
3042
|
result.dir = arg.slice("--dir=".length);
|
|
3043
|
+
} else if (arg === "--seed-version") {
|
|
3044
|
+
const v = Number(args[++i]);
|
|
3045
|
+
if (Number.isSafeInteger(v) && v >= 0) result.seedVersion = v;
|
|
3046
|
+
i++;
|
|
3047
|
+
} else if (arg.startsWith("--seed-version=")) {
|
|
3048
|
+
const v = Number(arg.slice("--seed-version=".length));
|
|
3049
|
+
if (Number.isSafeInteger(v) && v >= 0) result.seedVersion = v;
|
|
2856
3050
|
i++;
|
|
2857
3051
|
} else if (!result.subcommand) {
|
|
2858
|
-
if (arg === "parse" || arg === "run" || arg === "query" || arg === "download" || arg === "import" || arg === "build" || arg === "seed" || arg === "reset" || arg === "init" || arg === "server" || arg === "serve" || arg === "playground" || arg === "help" || arg === "version") {
|
|
3052
|
+
if (arg === "parse" || arg === "run" || arg === "query" || arg === "download" || arg === "export" || arg === "import" || arg === "publish" || arg === "build" || arg === "seed" || arg === "reset" || arg === "init" || arg === "server" || arg === "serve" || arg === "playground" || arg === "help" || arg === "version") {
|
|
2859
3053
|
result.subcommand = arg;
|
|
2860
3054
|
} else {
|
|
2861
3055
|
result.target = arg;
|
|
@@ -2881,9 +3075,9 @@ function parseCliArgs(args) {
|
|
|
2881
3075
|
function readBunStdinText() {
|
|
2882
3076
|
const g = globalThis;
|
|
2883
3077
|
if (g && typeof g === "object" && "Bun" in g) {
|
|
2884
|
-
const
|
|
2885
|
-
if (
|
|
2886
|
-
const stdin =
|
|
3078
|
+
const bun = g.Bun;
|
|
3079
|
+
if (bun && typeof bun === "object" && "stdin" in bun) {
|
|
3080
|
+
const stdin = bun.stdin;
|
|
2887
3081
|
if (stdin && typeof stdin === "object" && "text" in stdin) {
|
|
2888
3082
|
const text = stdin.text;
|
|
2889
3083
|
if (typeof text === "function") return text;
|
|
@@ -2916,8 +3110,10 @@ USAGE:
|
|
|
2916
3110
|
wod parse <file | -> [options]
|
|
2917
3111
|
wod run <file | -> [options]
|
|
2918
3112
|
wod query '<wql-string>' [options]
|
|
2919
|
-
wod
|
|
2920
|
-
wod
|
|
3113
|
+
wod export <note|playground|session|effort|equipment> <id> [options]
|
|
3114
|
+
wod download <note|playground|session|effort|equipment> <id> [options]
|
|
3115
|
+
wod import <note|playground|session|effort|equipment> <file> [options]
|
|
3116
|
+
wod publish [catalog] [options]
|
|
2921
3117
|
wod build [dir] [options]
|
|
2922
3118
|
wod seed [options]
|
|
2923
3119
|
wod reset [options]
|
|
@@ -2937,23 +3133,23 @@ SUBCOMMANDS:
|
|
|
2937
3133
|
execution-log IR
|
|
2938
3134
|
query '<wql>' Evaluate WQL against the database (or an explicit
|
|
2939
3135
|
dataset) and emit QueryResult / RowsQueryResult IR
|
|
2940
|
-
|
|
3136
|
+
export note <id> Export the note's authored markdown to <id>.md.
|
|
3137
|
+
(alias: export playground, download note).
|
|
2941
3138
|
The frontmatter identity stamp allows re-import.
|
|
2942
3139
|
Frontmatter tags (general + typed equipment/quality/\u2026)
|
|
2943
3140
|
are materialized into the tag graph on parse/import.
|
|
2944
|
-
|
|
3141
|
+
export session <id>
|
|
2945
3142
|
Write the session's generated metrics (event + summary
|
|
2946
3143
|
rows, one CSV row per metric) to <id>.csv. Import back
|
|
2947
|
-
with 'wod import session'.
|
|
2948
|
-
|
|
3144
|
+
with 'wod import session'. (alias: download session).
|
|
3145
|
+
export effort <slug>
|
|
2949
3146
|
Write the effort registry row as corpus-style markdown
|
|
2950
|
-
(frontmatter id/slug/label/aliases/baseAttributes + body)
|
|
2951
3147
|
to <slug>.md. Import back with 'wod import effort'.
|
|
2952
|
-
|
|
2953
|
-
Write every equipment tag as a one-column CSV to
|
|
3148
|
+
export equipment Write every equipment tag as a one-column CSV to
|
|
2954
3149
|
equipment.csv. Import back with 'wod import equipment'.
|
|
2955
|
-
|
|
2956
|
-
|
|
3150
|
+
download \u2026 Accepted alias for 'wod export'.
|
|
3151
|
+
import note <file> Re-import exported note markdown (alias: import playground;
|
|
3152
|
+
same as parse with the stamped identity).
|
|
2957
3153
|
import session <file>
|
|
2958
3154
|
Import a session + its events from a downloaded CSV.
|
|
2959
3155
|
The exact saved block revision must already exist.
|
|
@@ -2961,6 +3157,10 @@ SUBCOMMANDS:
|
|
|
2961
3157
|
Upsert an effort registry row from corpus-style markdown.
|
|
2962
3158
|
import equipment <file>
|
|
2963
3159
|
Create/upgrade equipment tags (CSV, one label per row).
|
|
3160
|
+
publish [catalog] Publish catalog notes from the database into a configured
|
|
3161
|
+
seed directory (manifest.json, chunks/, report.html)
|
|
3162
|
+
compatible with 'wod seed --source <dir>'. Override target
|
|
3163
|
+
with -o/--out/--output (defaults to ./dist/seed/<catalog>).
|
|
2964
3164
|
build [dir] Compile a seed corpus: validate every .md under
|
|
2965
3165
|
<dir>/markdown (parity gate + dashboard format gate) and
|
|
2966
3166
|
write manifest.json + content-hashed chunks/ +
|
|
@@ -3009,9 +3209,9 @@ DATABASE (init / parse / run / query / download / import / seed / reset / server
|
|
|
3009
3209
|
an error. Without it: ./.env when present, otherwise
|
|
3010
3210
|
the workspace-root .env. Credentials are never logged.
|
|
3011
3211
|
|
|
3012
|
-
HOSTING (for 'server' / 'playground';
|
|
3212
|
+
HOSTING (for 'server' / 'playground'; supported on Node and Bun):
|
|
3013
3213
|
server HTTP API over the configured database plus the frontend
|
|
3014
|
-
packaged inside the
|
|
3214
|
+
packaged inside the tools module. Requires an
|
|
3015
3215
|
initialized database. ('serve' is an accepted alias.)
|
|
3016
3216
|
playground Serves the playground app backed by browser IndexedDB;
|
|
3017
3217
|
the configured database is not touched.
|
|
@@ -3271,21 +3471,22 @@ async function cliMain(argv = process.argv.slice(2), io = {}) {
|
|
|
3271
3471
|
writeDebugFile("query", ir);
|
|
3272
3472
|
return 0;
|
|
3273
3473
|
}
|
|
3274
|
-
if (parsed.subcommand === "download") {
|
|
3474
|
+
if (parsed.subcommand === "download" || parsed.subcommand === "export") {
|
|
3475
|
+
const verb = parsed.subcommand;
|
|
3275
3476
|
const kind = parsed.target;
|
|
3276
3477
|
const id = parsed.target2;
|
|
3277
|
-
const DOWNLOAD_KINDS = ["note", "session", "effort", "equipment"];
|
|
3478
|
+
const DOWNLOAD_KINDS = ["note", "playground", "session", "effort", "equipment"];
|
|
3278
3479
|
if (!id && kind !== "equipment" || !DOWNLOAD_KINDS.includes(kind ?? "")) {
|
|
3279
|
-
writeErr(
|
|
3480
|
+
writeErr(`[wod ${verb}] Usage: wod ${verb} <note|playground|session|effort|equipment> <id> [-o <path>]`);
|
|
3280
3481
|
return 1;
|
|
3281
3482
|
}
|
|
3282
3483
|
const targetId = id;
|
|
3283
3484
|
const db = await openCliDb(cliDb());
|
|
3284
3485
|
try {
|
|
3285
|
-
if (kind === "note") {
|
|
3486
|
+
if (kind === "note" || kind === "playground") {
|
|
3286
3487
|
const bundle = await getNoteBundle(db.db, targetId);
|
|
3287
3488
|
if (!bundle.note) {
|
|
3288
|
-
writeErr(`[wod
|
|
3489
|
+
writeErr(`[wod ${verb}] Note not found in ${db.path}: ${id}`);
|
|
3289
3490
|
return 1;
|
|
3290
3491
|
}
|
|
3291
3492
|
const markdown = wodWikiEngine.composeNoteMarkdown(bundle.note);
|
|
@@ -3295,11 +3496,11 @@ async function cliMain(argv = process.argv.slice(2), io = {}) {
|
|
|
3295
3496
|
} else {
|
|
3296
3497
|
nodeFs().writeFileSync(target, markdown, "utf-8");
|
|
3297
3498
|
}
|
|
3298
|
-
if (parsed.output !== "-") writeOut(`[wod
|
|
3499
|
+
if (parsed.output !== "-") writeOut(`[wod ${verb}] ${kind} ${id} \u2192 ${target}`);
|
|
3299
3500
|
} else if (kind === "session") {
|
|
3300
3501
|
const bundle = await getSessionBundle(db.db, targetId);
|
|
3301
3502
|
if (!bundle) {
|
|
3302
|
-
writeErr(`[wod
|
|
3503
|
+
writeErr(`[wod ${verb}] Session not found in ${db.path}: ${id}`);
|
|
3303
3504
|
return 1;
|
|
3304
3505
|
}
|
|
3305
3506
|
const csv = wodWikiEngine.sessionToCsv(bundle.session, bundle.events);
|
|
@@ -3309,11 +3510,11 @@ async function cliMain(argv = process.argv.slice(2), io = {}) {
|
|
|
3309
3510
|
} else {
|
|
3310
3511
|
nodeFs().writeFileSync(target, csv, "utf-8");
|
|
3311
3512
|
}
|
|
3312
|
-
if (parsed.output !== "-") writeOut(`[wod
|
|
3513
|
+
if (parsed.output !== "-") writeOut(`[wod ${verb}] session ${id} \u2192 ${target} (${bundle.events.length} events)`);
|
|
3313
3514
|
} else if (kind === "effort") {
|
|
3314
3515
|
const effort = await getEffortBySlug(db.db, targetId);
|
|
3315
3516
|
if (!effort) {
|
|
3316
|
-
writeErr(`[wod
|
|
3517
|
+
writeErr(`[wod ${verb}] Effort not found in ${db.path}: ${id}`);
|
|
3317
3518
|
return 1;
|
|
3318
3519
|
}
|
|
3319
3520
|
const markdown = wodWikiEngine.effortToMarkdown(effort);
|
|
@@ -3323,7 +3524,7 @@ async function cliMain(argv = process.argv.slice(2), io = {}) {
|
|
|
3323
3524
|
} else {
|
|
3324
3525
|
nodeFs().writeFileSync(target, markdown, "utf-8");
|
|
3325
3526
|
}
|
|
3326
|
-
writeOut(`[wod
|
|
3527
|
+
writeOut(`[wod ${verb}] effort ${id} \u2192 ${target}`);
|
|
3327
3528
|
} else {
|
|
3328
3529
|
const labels = (await listTagsByType(db.db, "equipment")).map((t) => t.label).sort();
|
|
3329
3530
|
const csv = wodWikiEngine.equipmentToCsv(labels);
|
|
@@ -3333,7 +3534,7 @@ async function cliMain(argv = process.argv.slice(2), io = {}) {
|
|
|
3333
3534
|
} else {
|
|
3334
3535
|
nodeFs().writeFileSync(target, csv, "utf-8");
|
|
3335
3536
|
}
|
|
3336
|
-
writeOut(`[wod
|
|
3537
|
+
writeOut(`[wod ${verb}] equipment \u2192 ${target} (${labels.length} labels)`);
|
|
3337
3538
|
}
|
|
3338
3539
|
} finally {
|
|
3339
3540
|
await db.close();
|
|
@@ -3343,9 +3544,9 @@ async function cliMain(argv = process.argv.slice(2), io = {}) {
|
|
|
3343
3544
|
if (parsed.subcommand === "import") {
|
|
3344
3545
|
const kind = parsed.target;
|
|
3345
3546
|
const file = parsed.target2;
|
|
3346
|
-
const IMPORT_KINDS = ["note", "session", "effort", "equipment"];
|
|
3547
|
+
const IMPORT_KINDS = ["note", "playground", "session", "effort", "equipment"];
|
|
3347
3548
|
if (!file || !IMPORT_KINDS.includes(kind ?? "")) {
|
|
3348
|
-
writeErr("[wod import] Usage: wod import <note|session|effort|equipment> <file>");
|
|
3549
|
+
writeErr("[wod import] Usage: wod import <note|playground|session|effort|equipment> <file>");
|
|
3349
3550
|
return 1;
|
|
3350
3551
|
}
|
|
3351
3552
|
const fs = nodeFs();
|
|
@@ -3353,7 +3554,7 @@ async function cliMain(argv = process.argv.slice(2), io = {}) {
|
|
|
3353
3554
|
writeErr(`[wod import] File not found: ${file}`);
|
|
3354
3555
|
return 1;
|
|
3355
3556
|
}
|
|
3356
|
-
if (kind === "note") {
|
|
3557
|
+
if (kind === "note" || kind === "playground") {
|
|
3357
3558
|
const source = fs.readFileSync(file, "utf-8");
|
|
3358
3559
|
const identity = wodWikiEngine.extractNoteIdentity(source);
|
|
3359
3560
|
const tags = wodWikiEngine.extractTypedTags(source);
|
|
@@ -3367,7 +3568,7 @@ async function cliMain(argv = process.argv.slice(2), io = {}) {
|
|
|
3367
3568
|
tags
|
|
3368
3569
|
});
|
|
3369
3570
|
writeOut(
|
|
3370
|
-
`[wod import]
|
|
3571
|
+
`[wod import] ${kind} ${persisted.noteId}${persisted.created ? "" : " (updated)"} \u2014 ${persisted.blocks} blocks${persisted.tags > 0 ? `, ${persisted.tags} tags` : ""} \u2192 ${db2.path}`
|
|
3371
3572
|
);
|
|
3372
3573
|
} finally {
|
|
3373
3574
|
await db2.close();
|
|
@@ -3416,6 +3617,26 @@ async function cliMain(argv = process.argv.slice(2), io = {}) {
|
|
|
3416
3617
|
}
|
|
3417
3618
|
return 0;
|
|
3418
3619
|
}
|
|
3620
|
+
if (parsed.subcommand === "publish") {
|
|
3621
|
+
const isDir = (s) => Boolean(s && (s.startsWith(".") || s.startsWith("/") || s.includes("/") || s.includes("\\")));
|
|
3622
|
+
const catalog = isDir(parsed.target) ? void 0 : parsed.target;
|
|
3623
|
+
const targetDir = isDir(parsed.target) ? parsed.target : parsed.target2;
|
|
3624
|
+
const outDir = parsed.output ?? targetDir ?? (catalog ? `./dist/seed/${catalog}` : "./dist/seed");
|
|
3625
|
+
const db = await openCliDb(cliDb());
|
|
3626
|
+
try {
|
|
3627
|
+
const result = await publishCatalogSeed(db, {
|
|
3628
|
+
catalog,
|
|
3629
|
+
outDir,
|
|
3630
|
+
version: parsed.seedVersion
|
|
3631
|
+
});
|
|
3632
|
+
writeOut(
|
|
3633
|
+
`[wod publish] published ${result.catalogs.join(", ")} (${result.totalNotes} notes) \u2192 ${result.outDir} (manifest schema v${result.manifest.schema}, version ${result.manifest.version})`
|
|
3634
|
+
);
|
|
3635
|
+
} finally {
|
|
3636
|
+
await db.close();
|
|
3637
|
+
}
|
|
3638
|
+
return 0;
|
|
3639
|
+
}
|
|
3419
3640
|
if (parsed.subcommand === "build") {
|
|
3420
3641
|
const cwd = process.cwd();
|
|
3421
3642
|
const root = nodePath().resolve(cwd, parsed.dir ?? parsed.target ?? ".");
|
|
@@ -3492,12 +3713,6 @@ async function cliMain(argv = process.argv.slice(2), io = {}) {
|
|
|
3492
3713
|
return 0;
|
|
3493
3714
|
}
|
|
3494
3715
|
if (parsed.subcommand === "server" || parsed.subcommand === "serve" || parsed.subcommand === "playground") {
|
|
3495
|
-
if (!("Bun" in globalThis)) {
|
|
3496
|
-
writeErr(
|
|
3497
|
-
`[wod ${parsed.subcommand}] Error: hosting requires the Bun runtime (https://bun.sh). Install Bun to host: https://bun.sh`
|
|
3498
|
-
);
|
|
3499
|
-
return 1;
|
|
3500
|
-
}
|
|
3501
3716
|
const mode = parsed.subcommand === "playground" ? "playground" : "server";
|
|
3502
3717
|
const { runCliServer: runCliServer2 } = await Promise.resolve().then(() => (init_server(), server_exports));
|
|
3503
3718
|
const options = { env: cliEnv() };
|
|
@@ -3525,16 +3740,6 @@ async function cliMain(argv = process.argv.slice(2), io = {}) {
|
|
|
3525
3740
|
}
|
|
3526
3741
|
|
|
3527
3742
|
// src/bin/wod.ts
|
|
3528
|
-
var isBun = typeof globalThis.Bun !== "undefined";
|
|
3529
|
-
if (!isBun) {
|
|
3530
|
-
const check = child_process.spawnSync("bun", ["--version"], { stdio: "ignore" });
|
|
3531
|
-
if (check.status === 0) {
|
|
3532
|
-
const res = child_process.spawnSync("bun", ["--no-env-file", url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('wod.cjs', document.baseURI).href))), ...process.argv.slice(2)], {
|
|
3533
|
-
stdio: "inherit"
|
|
3534
|
-
});
|
|
3535
|
-
process.exit(res.status ?? 0);
|
|
3536
|
-
}
|
|
3537
|
-
}
|
|
3538
3743
|
void (async () => {
|
|
3539
3744
|
const exitCode = await cliMain(process.argv.slice(2));
|
|
3540
3745
|
process.exitCode = exitCode;
|