diffwiki 0.17.0 → 0.17.1-rc.202608210907.d3afab7
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.js +112 -61
- package/package.json +2 -2
package/dist/bin.js
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
+
// src/bin.ts
|
|
4
|
+
import { ensureHome } from "diffwiki-core";
|
|
5
|
+
|
|
3
6
|
// src/cli.ts
|
|
4
7
|
import { spawn as spawn4 } from "child_process";
|
|
5
|
-
import
|
|
6
|
-
import { fileURLToPath as
|
|
8
|
+
import path5 from "path";
|
|
9
|
+
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
7
10
|
import { Command, Option } from "commander";
|
|
8
11
|
import {
|
|
9
12
|
addExternalCollection,
|
|
@@ -72,12 +75,40 @@ var splitTags = (raw) => raw.flatMap((t) => t.split(",")).map((t) => t.trim()).f
|
|
|
72
75
|
import { spawn } from "child_process";
|
|
73
76
|
import { platform } from "os";
|
|
74
77
|
import fs from "fs/promises";
|
|
75
|
-
import
|
|
78
|
+
import path2 from "path";
|
|
76
79
|
import http from "http";
|
|
77
80
|
import { resolveHome } from "diffwiki-core";
|
|
81
|
+
|
|
82
|
+
// src/app.ts
|
|
83
|
+
import { existsSync } from "fs";
|
|
84
|
+
import path from "path";
|
|
85
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
86
|
+
var APP_SPEC = `diffwiki-app@${version}`;
|
|
87
|
+
function workspaceAppBin(localBin) {
|
|
88
|
+
const candidates = [
|
|
89
|
+
path.resolve(path.dirname(fileURLToPath2(import.meta.url)), "../../../apps/wiki/bin", localBin),
|
|
90
|
+
path.resolve(process.cwd(), "apps/wiki/bin", localBin)
|
|
91
|
+
];
|
|
92
|
+
return candidates.find((p) => existsSync(p));
|
|
93
|
+
}
|
|
94
|
+
function resolveAppLaunch(opts = {}) {
|
|
95
|
+
const localBin = opts.localBin ?? "wiki-server.mjs";
|
|
96
|
+
const override = process.env.DIFFWIKI_APP_CMD;
|
|
97
|
+
if (override) {
|
|
98
|
+
const [cmd, ...args] = override.split(" ");
|
|
99
|
+
return { cmd, args, source: "override", spec: override };
|
|
100
|
+
}
|
|
101
|
+
const spec = process.env.DIFFWIKI_APP_SPEC;
|
|
102
|
+
if (spec) return { cmd: "npx", args: ["-y", spec], source: "spec", spec };
|
|
103
|
+
const local = workspaceAppBin(localBin);
|
|
104
|
+
if (local) return { cmd: "node", args: [local], source: "local", spec: local };
|
|
105
|
+
return { cmd: "npx", args: ["-y", APP_SPEC], source: "npx", spec: APP_SPEC };
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// src/ui-server.ts
|
|
78
109
|
var DEFAULT_PORT = 4321;
|
|
79
110
|
function statePath() {
|
|
80
|
-
return
|
|
111
|
+
return path2.join(resolveHome(), "ui.json");
|
|
81
112
|
}
|
|
82
113
|
async function readState() {
|
|
83
114
|
try {
|
|
@@ -132,8 +163,24 @@ function waitForServer(url, timeoutMs = 3e4) {
|
|
|
132
163
|
tick();
|
|
133
164
|
});
|
|
134
165
|
}
|
|
166
|
+
function childExited(child, timeoutMs = 0) {
|
|
167
|
+
if (timeoutMs === 0) return Promise.resolve(child.exitCode !== null || child.signalCode !== null);
|
|
168
|
+
return new Promise((resolve) => {
|
|
169
|
+
const onExit = () => {
|
|
170
|
+
clearTimeout(timer);
|
|
171
|
+
resolve(true);
|
|
172
|
+
};
|
|
173
|
+
const timer = setTimeout(() => {
|
|
174
|
+
child.off("exit", onExit);
|
|
175
|
+
resolve(false);
|
|
176
|
+
}, timeoutMs);
|
|
177
|
+
child.once("exit", onExit);
|
|
178
|
+
if (child.exitCode !== null || child.signalCode !== null) onExit();
|
|
179
|
+
});
|
|
180
|
+
}
|
|
135
181
|
async function startUi(port = DEFAULT_PORT) {
|
|
136
|
-
const
|
|
182
|
+
const { cmd, args } = resolveAppLaunch();
|
|
183
|
+
const child = spawn(cmd, [...args, "--port", String(port)], {
|
|
137
184
|
env: { ...process.env, PORT: String(port), HOST: "127.0.0.1" },
|
|
138
185
|
detached: true,
|
|
139
186
|
stdio: "ignore"
|
|
@@ -152,7 +199,7 @@ async function startUi(port = DEFAULT_PORT) {
|
|
|
152
199
|
startedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
153
200
|
};
|
|
154
201
|
await writeState(state);
|
|
155
|
-
return state;
|
|
202
|
+
return { state, child };
|
|
156
203
|
}
|
|
157
204
|
async function stopUi() {
|
|
158
205
|
const state = await readState();
|
|
@@ -168,20 +215,11 @@ async function stopUi() {
|
|
|
168
215
|
|
|
169
216
|
// src/exporter.ts
|
|
170
217
|
import { spawn as spawn2 } from "child_process";
|
|
171
|
-
import
|
|
172
|
-
import path2 from "path";
|
|
173
|
-
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
218
|
+
import path3 from "path";
|
|
174
219
|
import { listCollections, resolveCollectionSelection, InvalidExportSelectionError } from "diffwiki-core";
|
|
175
220
|
var splitGlobs = (v) => (v ?? "").split(",").map((s) => s.trim()).filter(Boolean);
|
|
176
|
-
function localAppExporter() {
|
|
177
|
-
const candidates = [
|
|
178
|
-
path2.resolve(path2.dirname(fileURLToPath2(import.meta.url)), "../../../apps/wiki/bin/export.mjs"),
|
|
179
|
-
path2.resolve(process.cwd(), "apps/wiki/bin/export.mjs")
|
|
180
|
-
];
|
|
181
|
-
return candidates.find((p) => fs2.existsSync(p));
|
|
182
|
-
}
|
|
183
221
|
async function runExport(opts) {
|
|
184
|
-
const out =
|
|
222
|
+
const out = path3.resolve(opts.out);
|
|
185
223
|
const filter = splitGlobs(opts.filter);
|
|
186
224
|
const exclude = splitGlobs(opts.exclude);
|
|
187
225
|
if (!opts.project && (filter.length > 0 || exclude.length > 0)) {
|
|
@@ -189,19 +227,17 @@ async function runExport(opts) {
|
|
|
189
227
|
const { errors } = resolveCollectionSelection(names, { filter, exclude });
|
|
190
228
|
if (errors.length > 0) throw new InvalidExportSelectionError(errors);
|
|
191
229
|
}
|
|
192
|
-
const
|
|
193
|
-
const
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
if (opts.filter) args.push("--filter", opts.filter);
|
|
197
|
-
if (opts.exclude) args.push("--exclude", opts.exclude);
|
|
230
|
+
const { cmd, args, source, spec } = resolveAppLaunch({ localBin: "export.mjs" });
|
|
231
|
+
const appArgs = [...args, "export", "--out", out, "--base", opts.base];
|
|
232
|
+
if (opts.filter) appArgs.push("--filter", opts.filter);
|
|
233
|
+
if (opts.exclude) appArgs.push("--exclude", opts.exclude);
|
|
198
234
|
if (opts.project) {
|
|
199
|
-
|
|
200
|
-
if (typeof opts.project === "string")
|
|
235
|
+
appArgs.push("--project");
|
|
236
|
+
if (typeof opts.project === "string") appArgs.push(opts.project);
|
|
201
237
|
}
|
|
202
|
-
if (override) console.log(`Exporting via ${
|
|
238
|
+
if (source === "override") console.log(`Exporting via ${spec}`);
|
|
203
239
|
await new Promise((resolve, reject) => {
|
|
204
|
-
const child = spawn2(cmd,
|
|
240
|
+
const child = spawn2(cmd, appArgs, { stdio: "inherit", env: process.env });
|
|
205
241
|
child.on("error", reject);
|
|
206
242
|
child.on("close", (code) => code === 0 ? resolve() : reject(new Error(`export failed (exit ${code})`)));
|
|
207
243
|
});
|
|
@@ -209,12 +245,10 @@ async function runExport(opts) {
|
|
|
209
245
|
}
|
|
210
246
|
|
|
211
247
|
// src/preview.ts
|
|
212
|
-
import
|
|
213
|
-
import fs3 from "fs/promises";
|
|
248
|
+
import fs2 from "fs/promises";
|
|
214
249
|
import net from "net";
|
|
215
|
-
import
|
|
250
|
+
import path4 from "path";
|
|
216
251
|
import { spawn as spawn3 } from "child_process";
|
|
217
|
-
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
218
252
|
import { seedProjectHome } from "diffwiki-core";
|
|
219
253
|
async function findFreePort(start, host = "127.0.0.1") {
|
|
220
254
|
const isFree = (port) => new Promise((resolve) => {
|
|
@@ -228,29 +262,16 @@ async function findFreePort(start, host = "127.0.0.1") {
|
|
|
228
262
|
}
|
|
229
263
|
throw new Error(`No free port available in ${start}..${start + 99}`);
|
|
230
264
|
}
|
|
231
|
-
function launchCommand() {
|
|
232
|
-
const override = process.env.DIFFWIKI_APP_CMD;
|
|
233
|
-
if (override) {
|
|
234
|
-
const [cmd, ...prefix] = override.split(" ");
|
|
235
|
-
return { cmd, prefix };
|
|
236
|
-
}
|
|
237
|
-
const candidates = [
|
|
238
|
-
path3.resolve(path3.dirname(fileURLToPath3(import.meta.url)), "../../../apps/wiki/bin/wiki-server.mjs"),
|
|
239
|
-
path3.resolve(process.cwd(), "apps/wiki/bin/wiki-server.mjs")
|
|
240
|
-
];
|
|
241
|
-
const local = candidates.find((p) => existsSync(p));
|
|
242
|
-
return local ? { cmd: "node", prefix: [local] } : { cmd: "npx", prefix: ["-y", "diffwiki-app@latest"] };
|
|
243
|
-
}
|
|
244
265
|
async function runPreview(opts) {
|
|
245
|
-
const root =
|
|
266
|
+
const root = path4.resolve(opts.cwd);
|
|
246
267
|
const { home, entries } = await seedProjectHome(root);
|
|
247
|
-
const { cmd,
|
|
268
|
+
const { cmd, args } = resolveAppLaunch();
|
|
248
269
|
const port = await findFreePort(opts.port);
|
|
249
270
|
const url = `http://127.0.0.1:${port}`;
|
|
250
|
-
console.log(`Previewing ${entries.length} collection(s) from ${
|
|
271
|
+
console.log(`Previewing ${entries.length} collection(s) from ${path4.join(root, "diffwiki.yaml")}`);
|
|
251
272
|
if (port !== opts.port) console.log(`Port ${opts.port} is in use \u2014 using ${port} instead.`);
|
|
252
273
|
console.log(`Starting UI at ${url} \u2026 (Ctrl-C to stop)`);
|
|
253
|
-
const child = spawn3(cmd, [...
|
|
274
|
+
const child = spawn3(cmd, [...args, "--port", String(port)], {
|
|
254
275
|
env: {
|
|
255
276
|
...process.env,
|
|
256
277
|
DIFFWIKI_HOME: home,
|
|
@@ -289,7 +310,7 @@ async function runPreview(opts) {
|
|
|
289
310
|
const finish = () => {
|
|
290
311
|
process.off("SIGINT", stop);
|
|
291
312
|
process.off("SIGTERM", stop);
|
|
292
|
-
void
|
|
313
|
+
void fs2.rm(home, { recursive: true, force: true });
|
|
293
314
|
resolve();
|
|
294
315
|
};
|
|
295
316
|
child.on("close", finish);
|
|
@@ -493,7 +514,7 @@ async function doctorAction(opts) {
|
|
|
493
514
|
}
|
|
494
515
|
}
|
|
495
516
|
function bundledTemplatesDir() {
|
|
496
|
-
return
|
|
517
|
+
return path5.resolve(path5.dirname(fileURLToPath3(import.meta.url)), "..", "templates");
|
|
497
518
|
}
|
|
498
519
|
async function templatesInitAction() {
|
|
499
520
|
const { seeded, skipped, dir } = await seedTemplates(bundledTemplatesDir());
|
|
@@ -570,17 +591,45 @@ async function lintAction(opts) {
|
|
|
570
591
|
${result.fileCount} file(s), ${result.errorCount} error(s), ${result.warnCount} warning(s)`);
|
|
571
592
|
if (result.errorCount > 0) process.exitCode = 1;
|
|
572
593
|
}
|
|
594
|
+
function exitReason(child) {
|
|
595
|
+
if (child.exitCode !== null) return `exit ${child.exitCode}`;
|
|
596
|
+
if (child.signalCode !== null) return `signal ${child.signalCode}`;
|
|
597
|
+
return "unexpectedly";
|
|
598
|
+
}
|
|
573
599
|
async function upAction(opts) {
|
|
574
600
|
const existing = await readState();
|
|
575
601
|
if (existing && isAlive(existing.pid)) {
|
|
576
602
|
console.log(`UI already running at ${existing.url} (pid ${existing.pid})`);
|
|
577
603
|
return;
|
|
578
604
|
}
|
|
579
|
-
const state = await startUi(Number(opts.port));
|
|
605
|
+
const { state, child } = await startUi(Number(opts.port));
|
|
580
606
|
const ok = await waitForServer(state.url);
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
607
|
+
const exited = await childExited(child, ok ? 2e3 : 0);
|
|
608
|
+
if (exited) {
|
|
609
|
+
await stopUi();
|
|
610
|
+
if (ok) {
|
|
611
|
+
const held = await waitForServer(state.url, 1500);
|
|
612
|
+
if (held) {
|
|
613
|
+
console.error(`Port ${state.port} is already in use by another process \u2014 the diffwiki app could not bind.`);
|
|
614
|
+
console.error(`Stop that process, or start the UI on a free port: \`diffwiki ui up --port <port>\`.`);
|
|
615
|
+
} else {
|
|
616
|
+
console.error(
|
|
617
|
+
`The diffwiki app started serving on ${state.url} but exited again (${exitReason(child)}) \u2014 check \`diffwiki ui status\`.`
|
|
618
|
+
);
|
|
619
|
+
}
|
|
620
|
+
} else {
|
|
621
|
+
console.error(
|
|
622
|
+
`The diffwiki app exited (${exitReason(child)}) before it could serve ${state.url} \u2014 check \`diffwiki ui status\`.`
|
|
623
|
+
);
|
|
624
|
+
}
|
|
625
|
+
process.exitCode = 1;
|
|
626
|
+
return;
|
|
627
|
+
}
|
|
628
|
+
if (ok) {
|
|
629
|
+
console.log(`UI started at ${state.url} (pid ${state.pid})`);
|
|
630
|
+
return;
|
|
631
|
+
}
|
|
632
|
+
console.log(`Launched (pid ${state.pid}) but ${state.url} did not respond yet \u2014 check \`diffwiki ui status\``);
|
|
584
633
|
}
|
|
585
634
|
async function downAction() {
|
|
586
635
|
const stopped = await stopUi();
|
|
@@ -597,7 +646,8 @@ async function statusAction() {
|
|
|
597
646
|
async function openAction(opts) {
|
|
598
647
|
let state = await readState();
|
|
599
648
|
if (!state || !isAlive(state.pid)) {
|
|
600
|
-
|
|
649
|
+
const started = await startUi(Number(opts.port));
|
|
650
|
+
state = started.state;
|
|
601
651
|
await waitForServer(state.url);
|
|
602
652
|
}
|
|
603
653
|
const coll = await resolveCwdCollection(process.cwd());
|
|
@@ -686,7 +736,7 @@ function createProgram() {
|
|
|
686
736
|
);
|
|
687
737
|
site.command("preview").description("Preview the site from the repo diffwiki.yaml (ignores global collections)").option("-p, --port <port>", "port to serve on", "4321").action(withErrors((opts) => previewAction(opts)));
|
|
688
738
|
const ui = program.command("ui").description("Run the local diffwiki app server");
|
|
689
|
-
ui.command("up").description("Start the diffwiki UI (
|
|
739
|
+
ui.command("up").description("Start the diffwiki UI (runs the matching published diffwiki-app)").option("-p, --port <port>", "port to serve on", "4321").action(withErrors((opts) => upAction(opts)));
|
|
690
740
|
ui.command("down").description("Stop the running diffwiki UI").action(withErrors(downAction));
|
|
691
741
|
ui.command("status").description("Show whether the diffwiki UI is running").action(withErrors(statusAction));
|
|
692
742
|
ui.command("open").description("Open the diffwiki UI in the browser (starting it if needed)").option("-p, --port <port>", "port to serve on", "4321").action(withErrors((opts) => openAction(opts)));
|
|
@@ -709,14 +759,14 @@ function createProgram() {
|
|
|
709
759
|
// src/logging.ts
|
|
710
760
|
import { mkdirSync } from "fs";
|
|
711
761
|
import os from "os";
|
|
712
|
-
import
|
|
762
|
+
import path6 from "path";
|
|
713
763
|
import { configureSync, getConfig } from "@logtape/logtape";
|
|
714
764
|
import { getRotatingFileSink } from "@logtape/file";
|
|
715
765
|
import { resolveLogLevel } from "diffwiki-core";
|
|
716
766
|
var configured = false;
|
|
717
767
|
function diffwikiHome() {
|
|
718
768
|
const override = process.env.DIFFWIKI_HOME;
|
|
719
|
-
return override && override.length > 0 ? override :
|
|
769
|
+
return override && override.length > 0 ? override : path6.join(os.homedir(), ".diffwiki");
|
|
720
770
|
}
|
|
721
771
|
function resolveCliLevel(argv) {
|
|
722
772
|
if (argv.includes("-v") || argv.includes("--verbose")) return "debug";
|
|
@@ -733,9 +783,9 @@ function configureCliLogging(argv = process.argv) {
|
|
|
733
783
|
if (configured || getConfig() != null) return;
|
|
734
784
|
configured = true;
|
|
735
785
|
const level = resolveCliLevel(argv);
|
|
736
|
-
const logsDir =
|
|
786
|
+
const logsDir = path6.join(diffwikiHome(), "logs");
|
|
737
787
|
mkdirSync(logsDir, { recursive: true });
|
|
738
|
-
const logFile =
|
|
788
|
+
const logFile = path6.join(logsDir, "diffwiki.log");
|
|
739
789
|
const stderrSink = (record) => {
|
|
740
790
|
process.stderr.write(formatLine(record) + "\n");
|
|
741
791
|
};
|
|
@@ -754,4 +804,5 @@ function configureCliLogging(argv = process.argv) {
|
|
|
754
804
|
|
|
755
805
|
// src/bin.ts
|
|
756
806
|
configureCliLogging(process.argv);
|
|
757
|
-
|
|
807
|
+
await ensureHome();
|
|
808
|
+
await createProgram().parseAsync(process.argv);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "diffwiki",
|
|
3
|
-
"version": "0.17.
|
|
3
|
+
"version": "0.17.1-rc.202608210907.d3afab7",
|
|
4
4
|
"description": "diffwiki command-line interface",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"@logtape/logtape": "^2.2.4",
|
|
19
19
|
"@logtape/file": "^2.2.4",
|
|
20
20
|
"commander": "^13.0.0",
|
|
21
|
-
"diffwiki-core": "0.17.
|
|
21
|
+
"diffwiki-core": "0.17.1-rc.202608210907.d3afab7"
|
|
22
22
|
},
|
|
23
23
|
"devDependencies": {
|
|
24
24
|
"@types/node": "^22.0.0"
|