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