diffwiki 0.2.0-rc.f44d17c → 0.3.0-rc.202607211217.f5290fa

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.
Files changed (2) hide show
  1. package/dist/bin.js +142 -0
  2. package/package.json +2 -2
package/dist/bin.js CHANGED
@@ -45,11 +45,112 @@ function withErrors(fn) {
45
45
  var collect = (value, previous) => previous.concat([value]);
46
46
  var splitTags = (raw) => raw.flatMap((t) => t.split(",")).map((t) => t.trim()).filter((t) => t.length > 0);
47
47
 
48
+ // src/ui-server.ts
49
+ import { spawn } from "child_process";
50
+ import { platform } from "os";
51
+ import fs from "fs/promises";
52
+ import path from "path";
53
+ import http from "http";
54
+ import { resolveHome } from "diffwiki-core";
55
+ var DEFAULT_PORT = 4321;
56
+ function statePath() {
57
+ return path.join(resolveHome(), "ui.json");
58
+ }
59
+ async function readState() {
60
+ try {
61
+ return JSON.parse(await fs.readFile(statePath(), "utf8"));
62
+ } catch {
63
+ return void 0;
64
+ }
65
+ }
66
+ async function writeState(state) {
67
+ await fs.mkdir(resolveHome(), { recursive: true });
68
+ await fs.writeFile(statePath(), `${JSON.stringify(state, null, 2)}
69
+ `, "utf8");
70
+ }
71
+ async function clearState() {
72
+ await fs.rm(statePath(), { force: true });
73
+ }
74
+ function isAlive(pid) {
75
+ try {
76
+ process.kill(pid, 0);
77
+ return true;
78
+ } catch {
79
+ return false;
80
+ }
81
+ }
82
+ function openCommand() {
83
+ switch (platform()) {
84
+ case "darwin":
85
+ return { cmd: "open", args: (u) => [u] };
86
+ case "win32":
87
+ return { cmd: "cmd", args: (u) => ["/c", "start", "", u] };
88
+ default:
89
+ return { cmd: "xdg-open", args: (u) => [u] };
90
+ }
91
+ }
92
+ function openBrowser(url) {
93
+ const { cmd, args } = openCommand();
94
+ spawn(cmd, args(url), { stdio: "ignore", detached: true }).unref();
95
+ }
96
+ function waitForServer(url, timeoutMs = 3e4) {
97
+ const deadline = Date.now() + timeoutMs;
98
+ return new Promise((resolve) => {
99
+ const tick = () => {
100
+ const req = http.get(url, (res) => {
101
+ res.resume();
102
+ resolve(true);
103
+ });
104
+ req.on("error", () => {
105
+ if (Date.now() > deadline) resolve(false);
106
+ else setTimeout(tick, 500);
107
+ });
108
+ };
109
+ tick();
110
+ });
111
+ }
112
+ async function startUi(port = DEFAULT_PORT) {
113
+ const child = spawn("npx", ["-y", "diffwiki-app@latest", "--port", String(port)], {
114
+ env: { ...process.env, PORT: String(port), HOST: "127.0.0.1" },
115
+ detached: true,
116
+ stdio: "ignore"
117
+ });
118
+ if (child.pid === void 0) {
119
+ throw new Error("failed to spawn diffwiki-app");
120
+ }
121
+ child.on("close", () => {
122
+ void clearState();
123
+ });
124
+ child.unref();
125
+ const state = {
126
+ pid: child.pid,
127
+ port,
128
+ url: `http://127.0.0.1:${port}`,
129
+ startedAt: (/* @__PURE__ */ new Date()).toISOString()
130
+ };
131
+ await writeState(state);
132
+ return state;
133
+ }
134
+ async function stopUi() {
135
+ const state = await readState();
136
+ if (!state) return void 0;
137
+ try {
138
+ if (platform() === "win32") process.kill(state.pid);
139
+ else process.kill(-state.pid);
140
+ } catch {
141
+ }
142
+ await clearState();
143
+ return state;
144
+ }
145
+
48
146
  // src/cli.ts
49
147
  var icon = (level) => level === "ok" ? "\u2713" : level === "warn" ? "!" : "\u2716";
50
148
  function createProgram() {
51
149
  const program = new Command();
52
150
  program.name("diffwiki").description("A git-based knowledge base").version(version).showHelpAfterError();
151
+ program.action(() => {
152
+ program.outputHelp();
153
+ });
53
154
  program.command("list").description("List all collections").action(
54
155
  withErrors(async () => {
55
156
  const collections = await listCollections();
@@ -144,6 +245,47 @@ function createProgram() {
144
245
  }
145
246
  })
146
247
  );
248
+ program.command("up").description("Start the diffwiki UI (latest published diffwiki-app)").option("-p, --port <port>", "port to serve on", "4321").action(
249
+ withErrors(async (opts) => {
250
+ const existing = await readState();
251
+ if (existing && isAlive(existing.pid)) {
252
+ console.log(`UI already running at ${existing.url} (pid ${existing.pid})`);
253
+ return;
254
+ }
255
+ const state = await startUi(Number(opts.port));
256
+ const ok = await waitForServer(state.url);
257
+ console.log(
258
+ ok ? `UI started at ${state.url} (pid ${state.pid})` : `Launched (pid ${state.pid}) but ${state.url} did not respond yet \u2014 check \`diffwiki status\``
259
+ );
260
+ })
261
+ );
262
+ program.command("down").description("Stop the running diffwiki UI").action(
263
+ withErrors(async () => {
264
+ const stopped = await stopUi();
265
+ console.log(stopped ? `Stopped UI (pid ${stopped.pid})` : "UI is not running.");
266
+ })
267
+ );
268
+ program.command("status").description("Show whether the diffwiki UI is running").action(
269
+ withErrors(async () => {
270
+ const state = await readState();
271
+ if (state && isAlive(state.pid)) {
272
+ console.log(`running \xB7 ${state.url} \xB7 pid ${state.pid} \xB7 since ${state.startedAt}`);
273
+ } else {
274
+ console.log("stopped");
275
+ }
276
+ })
277
+ );
278
+ program.command("open").description("Open the diffwiki UI in the browser (starting it if needed)").option("-p, --port <port>", "port to serve on", "4321").action(
279
+ withErrors(async (opts) => {
280
+ let state = await readState();
281
+ if (!state || !isAlive(state.pid)) {
282
+ state = await startUi(Number(opts.port));
283
+ await waitForServer(state.url);
284
+ }
285
+ openBrowser(state.url);
286
+ console.log(`Opening ${state.url}`);
287
+ })
288
+ );
147
289
  return program;
148
290
  }
149
291
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "diffwiki",
3
- "version": "0.2.0-rc.f44d17c",
3
+ "version": "0.3.0-rc.202607211217.f5290fa",
4
4
  "description": "diffwiki command-line interface",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -15,7 +15,7 @@
15
15
  },
16
16
  "dependencies": {
17
17
  "commander": "^13.0.0",
18
- "diffwiki-core": "0.2.0-rc.f44d17c"
18
+ "diffwiki-core": "0.3.0-rc.202607211217.f5290fa"
19
19
  },
20
20
  "devDependencies": {
21
21
  "@types/node": "^22.0.0"