@bitcobblers/wod-wiki-tools 0.36.2135 → 0.37.2137
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 +299 -16
- package/dist/bin/wod.cjs.map +1 -1
- package/dist/bin/wod.mjs +3 -2
- package/dist/bin/wod.mjs.map +1 -1
- package/dist/{chunk-OTJAPVT2.mjs → chunk-GBBJBDLS.mjs} +29 -11
- package/dist/chunk-GBBJBDLS.mjs.map +1 -0
- package/dist/{chunk-FZKXOYMJ.mjs → chunk-NATJMTAW.mjs} +47 -4
- package/dist/chunk-NATJMTAW.mjs.map +1 -0
- package/dist/chunk-SQAI6B4P.mjs +12 -0
- package/dist/chunk-SQAI6B4P.mjs.map +1 -0
- package/dist/{compiler-CTPLIZJK.mjs → compiler-B77PITYH.mjs} +3 -3
- package/dist/{compiler-CTPLIZJK.mjs.map → compiler-B77PITYH.mjs.map} +1 -1
- package/dist/index.cjs +299 -16
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.mjs +3 -2
- package/dist/scaffoldCatalog-LQOUCJ4X.mjs +205 -0
- package/dist/scaffoldCatalog-LQOUCJ4X.mjs.map +1 -0
- package/dist/web/playground/assets/main-CFDrblxn.css +2 -0
- package/dist/web/playground/assets/main-OGIV1avF.js +188 -0
- package/dist/web/playground/assets/{statementBuilderFlow-CCaLco1R.js → statementBuilderFlow-BL8OKlcb.js} +2 -2
- package/dist/web/playground/assets/{vendor-g-NJOjvC.js → vendor-CTANVdPW.js} +19 -19
- package/dist/web/playground/assets/{vendor-codemirror-C41SFn-r.js → vendor-codemirror-BlXDdJID.js} +8 -8
- package/dist/web/playground/index.html +4 -4
- package/dist/web/playground/seed/core/chunks/{canvas.2d3e2e0e.json → canvas.a2e32d8c.json} +1 -1
- package/dist/web/playground/seed/core/manifest.json +8 -5
- package/dist/web/playground/seed/core/report.html +9 -9
- package/dist/web/server/assets/main-BdUrlkaF.js +187 -0
- package/dist/web/server/assets/main-CFDrblxn.css +2 -0
- package/dist/web/server/assets/{statementBuilderFlow-MCfILbWE.js → statementBuilderFlow-xqsK_3T8.js} +2 -2
- package/dist/web/server/assets/{vendor-g-NJOjvC.js → vendor-CTANVdPW.js} +19 -19
- package/dist/web/server/assets/{vendor-codemirror-C41SFn-r.js → vendor-codemirror-BlXDdJID.js} +8 -8
- package/dist/web/server/index.html +4 -4
- package/dist/web/server/seed/core/chunks/{canvas.2d3e2e0e.json → canvas.a2e32d8c.json} +1 -1
- package/dist/web/server/seed/core/manifest.json +8 -5
- package/dist/web/server/seed/core/report.html +9 -9
- package/package.json +6 -6
- package/dist/chunk-FZKXOYMJ.mjs.map +0 -1
- package/dist/chunk-OTJAPVT2.mjs.map +0 -1
- package/dist/web/playground/assets/main-Bhn9NHgQ.css +0 -2
- package/dist/web/playground/assets/main-Bod1taHc.js +0 -188
- package/dist/web/server/assets/main-Bhn9NHgQ.css +0 -2
- package/dist/web/server/assets/main-DtiBHHer.js +0 -187
package/dist/index.cjs
CHANGED
|
@@ -160,7 +160,7 @@ function sqliteEventStore(db) {
|
|
|
160
160
|
getEventsByTimeRange: async (start, end) => (await all()).filter((r) => r.timestamp >= start && r.timestamp <= end),
|
|
161
161
|
getEventsByResult: async (resultId) => (await all()).filter((r) => r.resultId === resultId),
|
|
162
162
|
getEventsForNote: async (noteId) => (await all()).filter((r) => r.noteId === noteId),
|
|
163
|
-
getEventsByContent: async (
|
|
163
|
+
getEventsByContent: async (blockContentId5) => (await all()).filter((r) => r.blockContentId === blockContentId5),
|
|
164
164
|
scanAll: all,
|
|
165
165
|
appendEvents: async (appended) => {
|
|
166
166
|
const sql = await loadSql();
|
|
@@ -613,6 +613,31 @@ var init_report = __esm({
|
|
|
613
613
|
"src/seedbuild/report.ts"() {
|
|
614
614
|
}
|
|
615
615
|
});
|
|
616
|
+
function object(value) {
|
|
617
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
618
|
+
}
|
|
619
|
+
function nonnegative(value) {
|
|
620
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
|
|
621
|
+
}
|
|
622
|
+
function assertSeedManifest2(value) {
|
|
623
|
+
if (!object(value) || value.schema !== SEED_SCHEMA2) throw new Error("Incompatible seed schema; rebuild seed artifacts");
|
|
624
|
+
if (!nonnegative(value.version) || typeof value.builtAt !== "string" || !Number.isFinite(Date.parse(value.builtAt)) || !Array.isArray(value.chunks)) throw new Error("seed manifest failed shape validation");
|
|
625
|
+
for (const key of ["versionLabel", "commit", "name", "description"]) if (value[key] !== void 0 && typeof value[key] !== "string") throw new Error("invalid seed manifest metadata");
|
|
626
|
+
if (value.repositoryUrl !== void 0 && (typeof value.repositoryUrl !== "string" || !/^https:\/\//.test(value.repositoryUrl) || new URL(value.repositoryUrl).username || new URL(value.repositoryUrl).password)) throw new Error("invalid seed repository URL");
|
|
627
|
+
if (value.dirty !== void 0 && typeof value.dirty !== "boolean") throw new Error("invalid seed manifest metadata");
|
|
628
|
+
const ids = /* @__PURE__ */ new Set(), paths = /* @__PURE__ */ new Set();
|
|
629
|
+
for (const chunk of value.chunks) {
|
|
630
|
+
if (!object(chunk) || typeof chunk.id !== "string" || !chunk.id || typeof chunk.path !== "string" || !/^chunks\/[a-zA-Z0-9._-]+\.json$/.test(chunk.path) || typeof chunk.sha256 !== "string" || !/^[0-9a-f]{64}$/.test(chunk.sha256) || !nonnegative(chunk.bytes) || !nonnegative(chunk.count) || chunk.kind !== void 0 && chunk.kind !== "notes" || ids.has(chunk.id) || paths.has(chunk.path)) throw new Error("seed manifest failed shape validation");
|
|
631
|
+
ids.add(chunk.id);
|
|
632
|
+
paths.add(chunk.path);
|
|
633
|
+
}
|
|
634
|
+
return value;
|
|
635
|
+
}
|
|
636
|
+
var init_validation = __esm({
|
|
637
|
+
"src/seedbuild/validation.ts"() {
|
|
638
|
+
init_contract();
|
|
639
|
+
}
|
|
640
|
+
});
|
|
616
641
|
|
|
617
642
|
// src/seedbuild/compiler.ts
|
|
618
643
|
var compiler_exports = {};
|
|
@@ -624,6 +649,7 @@ __export(compiler_exports, {
|
|
|
624
649
|
compileSeedRow: () => compileSeedRow,
|
|
625
650
|
discoverUncatalogedEfforts: () => discoverUncatalogedEfforts,
|
|
626
651
|
feedDateToCreatedAt: () => feedDateToCreatedAt,
|
|
652
|
+
frontmatterDateToCreatedAt: () => frontmatterDateToCreatedAt,
|
|
627
653
|
generateSeed: () => generateSeed,
|
|
628
654
|
loadExistingEffortMap: () => loadExistingEffortMap,
|
|
629
655
|
partitionIntoChunks: () => partitionIntoChunks,
|
|
@@ -725,6 +751,18 @@ function getFileCreatedAt(file, repoRoot) {
|
|
|
725
751
|
return 0;
|
|
726
752
|
}
|
|
727
753
|
}
|
|
754
|
+
function frontmatterDateToCreatedAt(raw, path) {
|
|
755
|
+
const value = getScalar(parseFrontmatter(raw).meta, "date");
|
|
756
|
+
if (value === void 0 || value === "") return void 0;
|
|
757
|
+
const text = String(value);
|
|
758
|
+
const parts = text.match(/^(\d{4})-(\d{2})-(\d{2})$/);
|
|
759
|
+
const ts = parts ? Date.parse(`${text}T12:00:00Z`) : NaN;
|
|
760
|
+
const valid = !!parts && Number.isFinite(ts) && new Date(ts).getUTCMonth() === Number(parts[2]) - 1 && new Date(ts).getUTCDate() === Number(parts[3]);
|
|
761
|
+
if (!valid) {
|
|
762
|
+
throw new Error(`[wod build] invalid frontmatter date '${text}' in '${path}' \u2014 expected a real calendar day (YYYY-MM-DD)`);
|
|
763
|
+
}
|
|
764
|
+
return ts;
|
|
765
|
+
}
|
|
728
766
|
function feedDateToCreatedAt(dateKey) {
|
|
729
767
|
if (!/^\d{4}-\d{2}-\d{2}$/.test(dateKey)) return 0;
|
|
730
768
|
const ts = Date.parse(`${dateKey}T00:00:00Z`);
|
|
@@ -752,7 +790,7 @@ function buildBlockIndexRows(markdownDir, corpusRoot) {
|
|
|
752
790
|
const catalog = parts[2];
|
|
753
791
|
const routeId = chunkId === "canvas" ? canvasRouteSlug(content) ?? void 0 : chunkId.startsWith("collection.") ? stem.toLowerCase() === "readme" ? catalog : `${catalog}/${stem}` : chunkId.startsWith("feed.") ? parts.slice(1).join("/").replace(/\.md$/, "") : void 0;
|
|
754
792
|
const sourceId = seedNoteSourceId(path$1, content, chunkId);
|
|
755
|
-
const createdAt = chunkId.startsWith("feed.") ? feedDateToCreatedAt(parts.at(-2) ?? "") : getFileCreatedAt(path$1, corpusRoot);
|
|
793
|
+
const createdAt = frontmatterDateToCreatedAt(content, path$1) ?? (chunkId.startsWith("feed.") ? feedDateToCreatedAt(parts.at(-2) ?? "") : getFileCreatedAt(path$1, corpusRoot));
|
|
756
794
|
rows.push(...compileSeedRow(path$1, content, { routeId, sourceId, createdAt }).blockIndex);
|
|
757
795
|
}
|
|
758
796
|
return rows;
|
|
@@ -912,6 +950,13 @@ function generateSeed(options = {}) {
|
|
|
912
950
|
const markdownDir = options.markdownDir ?? path.join(corpusRoot, "markdown");
|
|
913
951
|
const outDir = options.outDir ?? path.join(corpusRoot, "dist");
|
|
914
952
|
const gitVersion = options.version !== void 0 ? { ...resolveGitVersion(corpusRoot), version: options.version } : resolveGitVersion(corpusRoot);
|
|
953
|
+
const packageFile = path.join(corpusRoot, "package.json");
|
|
954
|
+
const packageMetadata = fs.existsSync(packageFile) ? JSON.parse(fs.readFileSync(packageFile, "utf8")) : {};
|
|
955
|
+
const metadata = packageMetadata && typeof packageMetadata === "object" ? packageMetadata : {};
|
|
956
|
+
const repository = "repository" in metadata ? metadata.repository : void 0;
|
|
957
|
+
const repositoryUrl = typeof repository === "string" ? repository : repository && typeof repository === "object" && "url" in repository && typeof repository.url === "string" ? repository.url : void 0;
|
|
958
|
+
const webRepositoryUrl = repositoryUrl?.replace(/^git\+/, "").replace(/\.git$/, "");
|
|
959
|
+
const repositoryLink = webRepositoryUrl && URL.canParse(webRepositoryUrl) ? new URL(webRepositoryUrl) : void 0;
|
|
915
960
|
if (options.scaffoldDiscoveredEfforts) {
|
|
916
961
|
const discovered = discoverUncatalogedEfforts(markdownDir, corpusRoot);
|
|
917
962
|
if (discovered.length > 0) {
|
|
@@ -980,6 +1025,9 @@ ${shown}${more}`);
|
|
|
980
1025
|
}
|
|
981
1026
|
passMs.write = Date.now() - tWrite;
|
|
982
1027
|
const manifest = {
|
|
1028
|
+
name: "name" in metadata && typeof metadata.name === "string" ? metadata.name : void 0,
|
|
1029
|
+
description: "description" in metadata && typeof metadata.description === "string" ? metadata.description : void 0,
|
|
1030
|
+
repositoryUrl: repositoryLink?.protocol === "https:" && !repositoryLink.username && !repositoryLink.password ? repositoryLink.href : void 0,
|
|
983
1031
|
schema: SEED_SCHEMA2,
|
|
984
1032
|
version: gitVersion.version,
|
|
985
1033
|
versionLabel: gitVersion.versionLabel,
|
|
@@ -988,6 +1036,7 @@ ${shown}${more}`);
|
|
|
988
1036
|
builtAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
989
1037
|
chunks: manifestChunks
|
|
990
1038
|
};
|
|
1039
|
+
assertSeedManifest2(manifest);
|
|
991
1040
|
fs.writeFileSync(path.join(outDir, "manifest.json"), JSON.stringify(manifest, null, 2) + "\n");
|
|
992
1041
|
const reportPath = writeBuildReport(outDir, {
|
|
993
1042
|
manifest,
|
|
@@ -1006,6 +1055,7 @@ var init_compiler = __esm({
|
|
|
1006
1055
|
init_git_version();
|
|
1007
1056
|
init_report();
|
|
1008
1057
|
init_frontmatter();
|
|
1058
|
+
init_validation();
|
|
1009
1059
|
NON_EFFORT_SLUGS = {
|
|
1010
1060
|
"amrap": true,
|
|
1011
1061
|
"emom": true,
|
|
@@ -1055,6 +1105,219 @@ var init_compiler = __esm({
|
|
|
1055
1105
|
}
|
|
1056
1106
|
});
|
|
1057
1107
|
|
|
1108
|
+
// src/version.ts
|
|
1109
|
+
var VERSION;
|
|
1110
|
+
var init_version = __esm({
|
|
1111
|
+
"src/version.ts"() {
|
|
1112
|
+
VERSION = "0.37.2137";
|
|
1113
|
+
}
|
|
1114
|
+
});
|
|
1115
|
+
|
|
1116
|
+
// src/cli/scaffoldCatalog.ts
|
|
1117
|
+
var scaffoldCatalog_exports = {};
|
|
1118
|
+
__export(scaffoldCatalog_exports, {
|
|
1119
|
+
scaffoldCatalog: () => scaffoldCatalog,
|
|
1120
|
+
validateCatalogName: () => validateCatalogName
|
|
1121
|
+
});
|
|
1122
|
+
function validateCatalogName(name) {
|
|
1123
|
+
if (name.length === 0 || name === "." || name === "..") {
|
|
1124
|
+
throw new Error("Catalog name must be a single non-empty directory name");
|
|
1125
|
+
}
|
|
1126
|
+
if (name.includes("/") || name.includes("\\") || name.includes("\0")) {
|
|
1127
|
+
throw new Error(`Invalid catalog name '${name}': must be a single directory name (no path separators or traversal)`);
|
|
1128
|
+
}
|
|
1129
|
+
if (/^(?:[A-Za-z]:)?[/\\]/.test(name)) {
|
|
1130
|
+
throw new Error(`Invalid catalog name '${name}': absolute paths are not allowed`);
|
|
1131
|
+
}
|
|
1132
|
+
if (name.length > 214 || !/^[a-z0-9][a-z0-9._-]*$/.test(name)) {
|
|
1133
|
+
throw new Error(
|
|
1134
|
+
`Invalid catalog name '${name}': must be a valid npm package name (lowercase letters, digits, dots, hyphens, underscores; no leading dot/hyphen)`
|
|
1135
|
+
);
|
|
1136
|
+
}
|
|
1137
|
+
return name;
|
|
1138
|
+
}
|
|
1139
|
+
function scaffoldCatalog(name, opts = {}) {
|
|
1140
|
+
validateCatalogName(name);
|
|
1141
|
+
const dir = path.resolve(opts.cwd ?? process.cwd(), name);
|
|
1142
|
+
try {
|
|
1143
|
+
fs.mkdirSync(dir);
|
|
1144
|
+
} catch (error) {
|
|
1145
|
+
if (error.code === "EEXIST") {
|
|
1146
|
+
throw new Error(`Refusing to overwrite '${dir}': destination already exists`, { cause: error });
|
|
1147
|
+
}
|
|
1148
|
+
throw error;
|
|
1149
|
+
}
|
|
1150
|
+
const date = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
1151
|
+
const files = [
|
|
1152
|
+
["package.json", `${JSON.stringify(
|
|
1153
|
+
{
|
|
1154
|
+
name,
|
|
1155
|
+
version: "0.1.0",
|
|
1156
|
+
private: true,
|
|
1157
|
+
type: "module",
|
|
1158
|
+
description: `WOD Wiki workout catalog: ${name}`,
|
|
1159
|
+
scripts: {
|
|
1160
|
+
build: "wod build . --output dist"
|
|
1161
|
+
},
|
|
1162
|
+
devDependencies: {
|
|
1163
|
+
"@bitcobblers/wod-wiki-tools": `^${VERSION}`
|
|
1164
|
+
}
|
|
1165
|
+
},
|
|
1166
|
+
null,
|
|
1167
|
+
2
|
|
1168
|
+
)}
|
|
1169
|
+
`],
|
|
1170
|
+
[".gitignore", "node_modules/\ndist/\n"],
|
|
1171
|
+
[".github/workflows/publish-catalog.yml", publishWorkflow()],
|
|
1172
|
+
["markdown/collections/example/README.md", collectionReadme(name)],
|
|
1173
|
+
[`markdown/collections/example/morning-session.md`, exampleWorkout(date)],
|
|
1174
|
+
["README.md", catalogReadme(name)]
|
|
1175
|
+
];
|
|
1176
|
+
try {
|
|
1177
|
+
for (const [rel, content] of files) {
|
|
1178
|
+
const target = path.join(dir, rel);
|
|
1179
|
+
fs.mkdirSync(path.dirname(target), { recursive: true });
|
|
1180
|
+
fs.writeFileSync(target, content, "utf-8");
|
|
1181
|
+
}
|
|
1182
|
+
} catch (error) {
|
|
1183
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
1184
|
+
throw error;
|
|
1185
|
+
}
|
|
1186
|
+
return { dir, files: files.map(([rel]) => rel) };
|
|
1187
|
+
}
|
|
1188
|
+
var publishWorkflow, collectionReadme, exampleWorkout, catalogReadme;
|
|
1189
|
+
var init_scaffoldCatalog = __esm({
|
|
1190
|
+
"src/cli/scaffoldCatalog.ts"() {
|
|
1191
|
+
init_version();
|
|
1192
|
+
publishWorkflow = () => `name: Publish catalog
|
|
1193
|
+
|
|
1194
|
+
# Compile the catalog with the wod CLI and deploy dist/ to GitHub Pages.
|
|
1195
|
+
# Requires Pages enabled: repo Settings \u2192 Pages \u2192 Source: "GitHub Actions".
|
|
1196
|
+
|
|
1197
|
+
on:
|
|
1198
|
+
push:
|
|
1199
|
+
branches: [main]
|
|
1200
|
+
workflow_dispatch:
|
|
1201
|
+
|
|
1202
|
+
permissions:
|
|
1203
|
+
contents: read
|
|
1204
|
+
pages: write
|
|
1205
|
+
id-token: write
|
|
1206
|
+
|
|
1207
|
+
concurrency:
|
|
1208
|
+
group: pages
|
|
1209
|
+
cancel-in-progress: true
|
|
1210
|
+
|
|
1211
|
+
jobs:
|
|
1212
|
+
publish:
|
|
1213
|
+
runs-on: ubuntu-latest
|
|
1214
|
+
environment:
|
|
1215
|
+
name: github-pages
|
|
1216
|
+
url: \${{ steps.deployment.outputs.page_url }}
|
|
1217
|
+
steps:
|
|
1218
|
+
- uses: actions/checkout@v4
|
|
1219
|
+
with:
|
|
1220
|
+
# Full history: seed manifest version stamps derive from git commit count.
|
|
1221
|
+
fetch-depth: 0
|
|
1222
|
+
|
|
1223
|
+
- name: Set up Bun
|
|
1224
|
+
uses: oven-sh/setup-bun@v2
|
|
1225
|
+
with:
|
|
1226
|
+
bun-version: 1.4.x
|
|
1227
|
+
|
|
1228
|
+
- name: Install dependencies
|
|
1229
|
+
run: bun install
|
|
1230
|
+
|
|
1231
|
+
- name: Build seed
|
|
1232
|
+
run: bunx wod build . --output dist
|
|
1233
|
+
|
|
1234
|
+
- uses: actions/configure-pages@v5
|
|
1235
|
+
|
|
1236
|
+
- name: Upload dist
|
|
1237
|
+
uses: actions/upload-pages-artifact@v3
|
|
1238
|
+
with:
|
|
1239
|
+
path: dist
|
|
1240
|
+
|
|
1241
|
+
- id: deployment
|
|
1242
|
+
uses: actions/deploy-pages@v4
|
|
1243
|
+
`;
|
|
1244
|
+
collectionReadme = (name) => `# ${name}
|
|
1245
|
+
|
|
1246
|
+
Example benchmark collection. Each \`.md\` file in this directory becomes part of
|
|
1247
|
+
the \`example\` collection chunk; \`README.md\` is the collection's landing page.
|
|
1248
|
+
|
|
1249
|
+
Add one file per workout:
|
|
1250
|
+
|
|
1251
|
+
\`\`\`\`markdown
|
|
1252
|
+
---
|
|
1253
|
+
title: My workout
|
|
1254
|
+
date: 2026-01-01
|
|
1255
|
+
---
|
|
1256
|
+
|
|
1257
|
+
# My workout
|
|
1258
|
+
|
|
1259
|
+
\`\`\`time
|
|
1260
|
+
(21-15-9)
|
|
1261
|
+
Thrusters @95lb
|
|
1262
|
+
Pull-ups
|
|
1263
|
+
\`\`\`
|
|
1264
|
+
\`\`\`\`
|
|
1265
|
+
|
|
1266
|
+
The \`date:\` frontmatter field sets the workout's chronological placement
|
|
1267
|
+
(regardless of filename or directory).
|
|
1268
|
+
`;
|
|
1269
|
+
exampleWorkout = (date) => `---
|
|
1270
|
+
title: Morning session
|
|
1271
|
+
date: ${date}
|
|
1272
|
+
---
|
|
1273
|
+
|
|
1274
|
+
# Morning session
|
|
1275
|
+
|
|
1276
|
+
\`\`\`time
|
|
1277
|
+
(21-15-9)
|
|
1278
|
+
Thrusters @95lb
|
|
1279
|
+
Pull-ups
|
|
1280
|
+
\`\`\`
|
|
1281
|
+
`;
|
|
1282
|
+
catalogReadme = (name) => `# ${name}
|
|
1283
|
+
|
|
1284
|
+
A [WOD Wiki](https://github.com/bitcobblers/wod-wiki) workout catalog: plain
|
|
1285
|
+
Markdown workouts compiled to static, version-stamped seed chunks and published
|
|
1286
|
+
via GitHub Pages.
|
|
1287
|
+
|
|
1288
|
+
## Develop
|
|
1289
|
+
|
|
1290
|
+
\`\`\`sh
|
|
1291
|
+
bun install
|
|
1292
|
+
bunx wod build . --output dist
|
|
1293
|
+
\`\`\`
|
|
1294
|
+
|
|
1295
|
+
Workouts live under \`markdown/\` \u2014 this scaffold starts with one example
|
|
1296
|
+
collection. Validate everything with \`bunx wod build\`: it gates every file on
|
|
1297
|
+
the Whiteboard grammar and corpus layout before writing \`dist/\`.
|
|
1298
|
+
|
|
1299
|
+
## Publish
|
|
1300
|
+
|
|
1301
|
+
Push to GitHub and enable Pages (**Settings \u2192 Pages \u2192 Source: GitHub
|
|
1302
|
+
Actions**). The bundled workflow (\`.github/workflows/publish-catalog.yml\`)
|
|
1303
|
+
builds the catalog on every push to \`main\` and deploys \`dist/\`.
|
|
1304
|
+
|
|
1305
|
+
## Share
|
|
1306
|
+
|
|
1307
|
+
Once published, anyone can subscribe to this catalog from a WOD Wiki instance
|
|
1308
|
+
at:
|
|
1309
|
+
|
|
1310
|
+
\`\`\`
|
|
1311
|
+
<app-url>/subscribe?source=<url-encoded published catalog URL>
|
|
1312
|
+
\`\`\`
|
|
1313
|
+
|
|
1314
|
+
For \`owner\`/\`repo\` on GitHub Pages the catalog URL is the deployed
|
|
1315
|
+
directory, \`https://owner.github.io/repo/\`, e.g.
|
|
1316
|
+
\`/subscribe?source=https%3A%2F%2Fowner.github.io%2Frepo%2F\`.
|
|
1317
|
+
`;
|
|
1318
|
+
}
|
|
1319
|
+
});
|
|
1320
|
+
|
|
1058
1321
|
// src/server/errors.ts
|
|
1059
1322
|
var HttpError;
|
|
1060
1323
|
var init_errors = __esm({
|
|
@@ -1358,13 +1621,13 @@ __export(server_exports, {
|
|
|
1358
1621
|
runCliServer: () => runCliServer
|
|
1359
1622
|
});
|
|
1360
1623
|
function withResolvers() {
|
|
1361
|
-
let
|
|
1624
|
+
let resolve3;
|
|
1362
1625
|
let reject;
|
|
1363
1626
|
const promise = new Promise((res, rej) => {
|
|
1364
|
-
|
|
1627
|
+
resolve3 = res;
|
|
1365
1628
|
reject = rej;
|
|
1366
1629
|
});
|
|
1367
|
-
return { promise, resolve:
|
|
1630
|
+
return { promise, resolve: resolve3, reject };
|
|
1368
1631
|
}
|
|
1369
1632
|
function startHttpServer(handler, host, port) {
|
|
1370
1633
|
const b = globalThis.Bun;
|
|
@@ -1372,7 +1635,7 @@ function startHttpServer(handler, host, port) {
|
|
|
1372
1635
|
const s = b.serve({ port, hostname: host, fetch: handler });
|
|
1373
1636
|
return Promise.resolve({ stop: () => s.stop() });
|
|
1374
1637
|
}
|
|
1375
|
-
const { promise, resolve:
|
|
1638
|
+
const { promise, resolve: resolve3, reject } = withResolvers();
|
|
1376
1639
|
const server = http__default.default.createServer(async (req, res) => {
|
|
1377
1640
|
try {
|
|
1378
1641
|
const url = new URL(req.url || "/", `http://${req.headers.host || `${host}:${port}`}`);
|
|
@@ -1397,7 +1660,7 @@ function startHttpServer(handler, host, port) {
|
|
|
1397
1660
|
});
|
|
1398
1661
|
server.once("error", reject);
|
|
1399
1662
|
server.listen(port, host, () => {
|
|
1400
|
-
|
|
1663
|
+
resolve3({
|
|
1401
1664
|
stop: () => {
|
|
1402
1665
|
const close = withResolvers();
|
|
1403
1666
|
server.close(() => close.resolve());
|
|
@@ -1873,8 +2136,8 @@ async function loadLanguagePack(moduleSpec) {
|
|
|
1873
2136
|
try {
|
|
1874
2137
|
let importPath = moduleSpec;
|
|
1875
2138
|
if (moduleSpec.startsWith(".") || moduleSpec.startsWith("/") || moduleSpec.includes("\\") || moduleSpec.endsWith(".ts") || moduleSpec.endsWith(".js") || moduleSpec.endsWith(".mjs")) {
|
|
1876
|
-
const { resolve:
|
|
1877
|
-
const resolved =
|
|
2139
|
+
const { resolve: resolve3, pathToFileURL } = getPathUtils();
|
|
2140
|
+
const resolved = resolve3(process.cwd(), moduleSpec);
|
|
1878
2141
|
importPath = pathToFileURL(resolved).href;
|
|
1879
2142
|
}
|
|
1880
2143
|
const imported = await import(
|
|
@@ -2551,7 +2814,9 @@ async function publishCatalogSeed(db, options) {
|
|
|
2551
2814
|
})) : compileSeedRow(notePath, note.rawContent, {
|
|
2552
2815
|
routeId: `${catalogName}/${stem}`,
|
|
2553
2816
|
sourceId: `collection:${catalogName}/${stem}`,
|
|
2554
|
-
|
|
2817
|
+
// Authored frontmatter date first — exports keep the post's own
|
|
2818
|
+
// day, never the import/publish time.
|
|
2819
|
+
createdAt: note.date ?? note.createdAt,
|
|
2555
2820
|
noteTitle: note.title
|
|
2556
2821
|
}).blockIndex;
|
|
2557
2822
|
const blockEfforts = noteBlockEfforts.map((e) => ({
|
|
@@ -2893,10 +3158,8 @@ ${escapeCsvField(data.parsed.metric)},${data.scalar},${escapeCsvField(data.unit
|
|
|
2893
3158
|
return lines.join("\n");
|
|
2894
3159
|
}
|
|
2895
3160
|
|
|
2896
|
-
// src/version.ts
|
|
2897
|
-
var VERSION = "0.36.2135";
|
|
2898
|
-
|
|
2899
3161
|
// src/cli/runner.ts
|
|
3162
|
+
init_version();
|
|
2900
3163
|
function getFs2() {
|
|
2901
3164
|
if (typeof globalThis.process?.versions?.node === "undefined" && typeof globalThis.Bun === "undefined") {
|
|
2902
3165
|
throw new Error("File system operations are only supported in Node / Bun environments");
|
|
@@ -3048,7 +3311,7 @@ function parseCliArgs(args) {
|
|
|
3048
3311
|
if (Number.isSafeInteger(v) && v >= 0) result.seedVersion = v;
|
|
3049
3312
|
i++;
|
|
3050
3313
|
} else if (!result.subcommand) {
|
|
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") {
|
|
3314
|
+
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 === "init-catalog" || arg === "help" || arg === "version") {
|
|
3052
3315
|
result.subcommand = arg;
|
|
3053
3316
|
} else {
|
|
3054
3317
|
result.target = arg;
|
|
@@ -3088,13 +3351,13 @@ function readBunStdinText() {
|
|
|
3088
3351
|
async function readStdin() {
|
|
3089
3352
|
const bunText = readBunStdinText();
|
|
3090
3353
|
if (bunText) return bunText();
|
|
3091
|
-
return new Promise((
|
|
3354
|
+
return new Promise((resolve3, reject) => {
|
|
3092
3355
|
const chunks = [];
|
|
3093
3356
|
process.stdin.on("data", (chunk) => {
|
|
3094
3357
|
chunks.push(typeof chunk === "string" ? Buffer.from(chunk) : chunk);
|
|
3095
3358
|
});
|
|
3096
3359
|
process.stdin.on("end", () => {
|
|
3097
|
-
|
|
3360
|
+
resolve3(Buffer.concat(chunks).toString("utf-8"));
|
|
3098
3361
|
});
|
|
3099
3362
|
process.stdin.on("error", (err) => {
|
|
3100
3363
|
reject(err);
|
|
@@ -3114,6 +3377,10 @@ USAGE:
|
|
|
3114
3377
|
wod import <note|playground|session|effort|equipment> <file> [options]
|
|
3115
3378
|
wod publish [catalog] [options]
|
|
3116
3379
|
wod build [dir] [options]
|
|
3380
|
+
wod init-catalog <name>
|
|
3381
|
+
Scaffold a new catalog repository (package.json, example
|
|
3382
|
+
collection, GitHub Actions Pages workflow). Refuses an
|
|
3383
|
+
existing destination.
|
|
3117
3384
|
wod seed [options]
|
|
3118
3385
|
wod reset [options]
|
|
3119
3386
|
wod init Initialize the configured database (idempotent)
|
|
@@ -3316,6 +3583,22 @@ async function cliMain(argv = process.argv.slice(2), io = {}) {
|
|
|
3316
3583
|
}
|
|
3317
3584
|
};
|
|
3318
3585
|
try {
|
|
3586
|
+
if (parsed.subcommand === "init-catalog") {
|
|
3587
|
+
if (!parsed.target) {
|
|
3588
|
+
writeErr("[wod init-catalog] Error: Missing catalog name (a single new directory name)");
|
|
3589
|
+
return 1;
|
|
3590
|
+
}
|
|
3591
|
+
const { scaffoldCatalog: scaffoldCatalog2 } = await Promise.resolve().then(() => (init_scaffoldCatalog(), scaffoldCatalog_exports));
|
|
3592
|
+
try {
|
|
3593
|
+
const result = scaffoldCatalog2(parsed.target);
|
|
3594
|
+
writeOut(`[wod init-catalog] Created ${result.dir} (${result.files.length} files)`);
|
|
3595
|
+
writeOut(`Next: cd ${parsed.target} && bun install && bunx wod build . --output dist`);
|
|
3596
|
+
return 0;
|
|
3597
|
+
} catch (error) {
|
|
3598
|
+
writeErr(`[wod init-catalog] ${error.message}`);
|
|
3599
|
+
return 1;
|
|
3600
|
+
}
|
|
3601
|
+
}
|
|
3319
3602
|
if (parsed.subcommand === "parse") {
|
|
3320
3603
|
if (!parsed.target) {
|
|
3321
3604
|
writeErr('[wod parse] Error: Missing input file or "-" for stdin');
|