@hardikg/mdview 0.6.2 → 0.7.0

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 (56) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/README.md +8 -10
  3. package/bin/mdview.mjs +123 -44
  4. package/dist/client/assets/{arc-DjKPIdc5.js → arc-ycQp8V_W.js} +1 -1
  5. package/dist/client/assets/{architectureDiagram-3BPJPVTR-_OLcSJC-.js → architectureDiagram-3BPJPVTR-CGT8FovT.js} +1 -1
  6. package/dist/client/assets/{blockDiagram-GPEHLZMM-BxHKbhSj.js → blockDiagram-GPEHLZMM-N8A4M5KF.js} +1 -1
  7. package/dist/client/assets/{c4Diagram-AAUBKEIU-DiBLe7ZZ.js → c4Diagram-AAUBKEIU-GOIrZjrm.js} +1 -1
  8. package/dist/client/assets/channel-DsJAWOzB.js +1 -0
  9. package/dist/client/assets/{chunk-2J33WTMH-4B03UoyK.js → chunk-2J33WTMH-DMiX8NYo.js} +1 -1
  10. package/dist/client/assets/{chunk-4BX2VUAB-Dw7jUHGw.js → chunk-4BX2VUAB-BXnUK3rw.js} +1 -1
  11. package/dist/client/assets/{chunk-55IACEB6-AZdo8c-x.js → chunk-55IACEB6-BkF4Ba-V.js} +1 -1
  12. package/dist/client/assets/{chunk-727SXJPM-g0GurlcS.js → chunk-727SXJPM-DKPIb06m.js} +1 -1
  13. package/dist/client/assets/{chunk-AQP2D5EJ-eqTzq7th.js → chunk-AQP2D5EJ-BFOc87IV.js} +1 -1
  14. package/dist/client/assets/{chunk-FMBD7UC4-D4omRKrC.js → chunk-FMBD7UC4-IM3YKAF3.js} +1 -1
  15. package/dist/client/assets/{chunk-ND2GUHAM-mVdFtWqM.js → chunk-ND2GUHAM-UF3KQYdE.js} +1 -1
  16. package/dist/client/assets/{chunk-QZHKN3VN-CyPMaN41.js → chunk-QZHKN3VN-OHnkQvdC.js} +1 -1
  17. package/dist/client/assets/classDiagram-4FO5ZUOK-BD7T43t0.js +1 -0
  18. package/dist/client/assets/classDiagram-v2-Q7XG4LA2-BD7T43t0.js +1 -0
  19. package/dist/client/assets/{cose-bilkent-S5V4N54A-BjlwoH6Y.js → cose-bilkent-S5V4N54A-D0XjEe4_.js} +1 -1
  20. package/dist/client/assets/{dagre-BM42HDAG-DBF5W9Tk.js → dagre-BM42HDAG-1wR5aSmA.js} +1 -1
  21. package/dist/client/assets/{diagram-2AECGRRQ-D9gwS4tw.js → diagram-2AECGRRQ-B8L1OTOq.js} +1 -1
  22. package/dist/client/assets/{diagram-5GNKFQAL-DTpIgGjI.js → diagram-5GNKFQAL-BPGoGDNx.js} +1 -1
  23. package/dist/client/assets/{diagram-KO2AKTUF-ByLH9Z83.js → diagram-KO2AKTUF-Zu0g_DOV.js} +1 -1
  24. package/dist/client/assets/{diagram-LMA3HP47-Dkd4KfnW.js → diagram-LMA3HP47-bPbOm4sL.js} +1 -1
  25. package/dist/client/assets/{diagram-OG6HWLK6-C-mJW1Tv.js → diagram-OG6HWLK6-DWW4aJ4C.js} +1 -1
  26. package/dist/client/assets/{erDiagram-TEJ5UH35-DmyZPB5P.js → erDiagram-TEJ5UH35-CUsMs05D.js} +1 -1
  27. package/dist/client/assets/{flowDiagram-I6XJVG4X-D6RrsDb6.js → flowDiagram-I6XJVG4X-DZCURXAw.js} +1 -1
  28. package/dist/client/assets/{ganttDiagram-6RSMTGT7-CP_O3OdU.js → ganttDiagram-6RSMTGT7-CzMfUd_H.js} +1 -1
  29. package/dist/client/assets/{gitGraphDiagram-PVQCEYII-DZgdWY-6.js → gitGraphDiagram-PVQCEYII-Du_KX2ik.js} +1 -1
  30. package/dist/client/assets/index-BCdIdRge.js +2 -0
  31. package/dist/client/assets/{infoDiagram-5YYISTIA-BAp5orio.js → infoDiagram-5YYISTIA-D81JEsUe.js} +1 -1
  32. package/dist/client/assets/{ishikawaDiagram-YF4QCWOH-DgqFJxLz.js → ishikawaDiagram-YF4QCWOH-DwkHFgb8.js} +1 -1
  33. package/dist/client/assets/{journeyDiagram-JHISSGLW-BFlCgna7.js → journeyDiagram-JHISSGLW-nEajRNFZ.js} +1 -1
  34. package/dist/client/assets/{kanban-definition-UN3LZRKU-Ck0sh2an.js → kanban-definition-UN3LZRKU-Dvn5P58B.js} +1 -1
  35. package/dist/client/assets/{linear-CfOau-eX.js → linear-BYNRmGYt.js} +1 -1
  36. package/dist/client/assets/{mermaid.core-BUwfPdjt.js → mermaid.core-BJg17JjK.js} +4 -4
  37. package/dist/client/assets/{mindmap-definition-RKZ34NQL-tpaiyCEI.js → mindmap-definition-RKZ34NQL-WIFgsLLz.js} +1 -1
  38. package/dist/client/assets/{pieDiagram-4H26LBE5-DaNIMGBH.js → pieDiagram-4H26LBE5-DMgTQVGJ.js} +1 -1
  39. package/dist/client/assets/{quadrantDiagram-W4KKPZXB-BUZRyB7p.js → quadrantDiagram-W4KKPZXB-B0Gh1bMy.js} +1 -1
  40. package/dist/client/assets/{requirementDiagram-4Y6WPE33-D70DEVyJ.js → requirementDiagram-4Y6WPE33-DcIINxfV.js} +1 -1
  41. package/dist/client/assets/{sankeyDiagram-5OEKKPKP-DckSl4S7.js → sankeyDiagram-5OEKKPKP-CDnHepHs.js} +1 -1
  42. package/dist/client/assets/{sequenceDiagram-3UESZ5HK-If3g75AG.js → sequenceDiagram-3UESZ5HK-D7MMEHjm.js} +1 -1
  43. package/dist/client/assets/{stateDiagram-AJRCARHV-C-83rolJ.js → stateDiagram-AJRCARHV-Dvdvjjk8.js} +1 -1
  44. package/dist/client/assets/stateDiagram-v2-BHNVJYJU-I2g3TqMC.js +1 -0
  45. package/dist/client/assets/{timeline-definition-PNZ67QCA-DIFKx0ow.js → timeline-definition-PNZ67QCA-DYWt9asA.js} +1 -1
  46. package/dist/client/assets/{vennDiagram-CIIHVFJN-BGLU5r80.js → vennDiagram-CIIHVFJN-Bt0VUni_.js} +1 -1
  47. package/dist/client/assets/{wardley-L42UT6IY-qocA9kr0.js → wardley-L42UT6IY-DVy2v9KS.js} +1 -1
  48. package/dist/client/assets/{wardleyDiagram-YWT4CUSO-CWhmOVum.js → wardleyDiagram-YWT4CUSO-Ch7IIKOr.js} +1 -1
  49. package/dist/client/assets/{xychartDiagram-2RQKCTM6-D2Sc4Taz.js → xychartDiagram-2RQKCTM6-Byds5kce.js} +1 -1
  50. package/dist/client/index.html +1 -1
  51. package/package.json +1 -1
  52. package/dist/client/assets/channel-oDRyuYVi.js +0 -1
  53. package/dist/client/assets/classDiagram-4FO5ZUOK-Dn5QR1VE.js +0 -1
  54. package/dist/client/assets/classDiagram-v2-Q7XG4LA2-Dn5QR1VE.js +0 -1
  55. package/dist/client/assets/index-DFYTyxkU.js +0 -2
  56. package/dist/client/assets/stateDiagram-v2-BHNVJYJU-BeI0-mGo.js +0 -1
package/CHANGELOG.md CHANGED
@@ -7,6 +7,27 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.7.0] — 2026-05-28
11
+
12
+ CLI prereqs for an upcoming VS Code extension. New, additive surface — browser-mode runs are unchanged.
13
+
14
+ ### Added
15
+ - **`--vscode` flag** — opts the CLI into "embedded in VS Code" mode. Bundles four behaviors so the future extension has a single, named entry point: (1) relaxes the HTML response's `frame-ancestors` CSP directive (see **Security** below); (2) emits a structured one-line JSON ready signal on stdout (`{"event":"ready","url":"…","port":…}`) instead of the legacy two human lines; (3) implies `--no-open` (the extension owns the URL); (4) tells the SPA it is embedded so it can swap behaviors via the `?embed=vscode` query. Default browser invocations are unaffected; the flag must be passed explicitly.
16
+ - **`--palette <name>`** — override the palette for a single run without touching `.mdview.json`. Accepts `classic | paper | nord | solarized | high-contrast`. Invalid values are rejected at parse time with an explicit error listing the allowed set.
17
+ - **`--port 0`** — kernel-assigned ephemeral port. Previously the parser refused any port ≤ 0; now `0` is permitted and the actual bound port is read from `app.server.address()` after listen. Under `--vscode` the bound port is reported in the ready-signal JSON. Useful when the parent process (extension, CI) needs a free port without coordinating with mdview about ranges.
18
+ - **`data-source-line` on every rendered heading** (`<h1>` through `<h6>`) — 0-based file-line number including any frontmatter that was stripped. Enables future editor↔preview cursor sync. Additive attribute; harmless if unused.
19
+ - **SPA embed-mode** — when the SPA loads with `?embed=vscode` *and* is running inside an iframe (`window.parent !== window`), it activates a handshake-driven postMessage protocol with its parent (origin-validated, one-shot `parentOrigin` capture, message-type allow-list), hides the left-hand file-tree pane (VS Code's Explorer already provides one), and routes internal-link clicks and outline-heading clicks back to the parent via `mdview/internal-link-clicked` / `mdview/heading-clicked` messages instead of navigating in-page. The `?embed=vscode` query is preserved across all SPA-internal navigation.
20
+
21
+ ### Security
22
+ - **`frame-ancestors` relaxed to `*` *only* when `--vscode` is passed.** Default browser runs still emit `frame-ancestors 'none'` byte-for-byte. All other CSP directives (`default-src 'self'`, `script-src 'self'`, `style-src 'self' 'unsafe-inline'`, `img-src 'self' data: blob:`, `font-src 'self' data:`, `connect-src 'self'`, `base-uri 'none'`, `form-action 'none'`) are unchanged in both modes — a regression test in `tests/server/embed-mode.test.ts` enforces this. Justification: the loopback bind (`127.0.0.1`) is the real network-layer boundary; `frame-ancestors` is defense-in-depth on top. Enumerating VS Code webview origins (which vary across desktop, web, and Codespaces) is brittle and not portable; `frame-ancestors *` gated by the explicit `--vscode` flag is the conservative middle ground.
23
+
24
+ ### Changed
25
+ - Under `--vscode`, stdout emits a single line of JSON (`{"event":"ready",…}`) rather than the legacy `mdview → <url>` and `watching: <root>` human lines. Default mode is unchanged.
26
+
27
+ ### Fixed
28
+ - `npm install -g` no longer silently no-ops on certain platforms. The new "only run `main()` when invoked as the entry point" guard now resolves symlinks (via `realpathSync`) on both sides of the comparison, so a globally-installed mdview (which lives behind a symlink in the global bin directory) still runs as expected.
29
+ - `data-source-line` line counts are robust across CRLF-authored sources and frontmatter blocks with trailing blank lines — computed directly from `raw` via a line-walk rather than relying on `gray-matter`'s internal byte representation.
30
+
10
31
  ## [0.6.2] — 2026-05-19
11
32
 
12
33
  ### Fixed
package/README.md CHANGED
@@ -22,6 +22,14 @@ Reading long markdown docs is hard:
22
22
 
23
23
  `mdview` is built for that. It's a single-machine, single-user, read-only viewer with editorial typography, persistent navigation, and live reload.
24
24
 
25
+ ## Install
26
+
27
+ ```bash
28
+ npm install -g @hardikg/mdview
29
+ ```
30
+
31
+ Requires Node >= 20. The `mdview` binary lands on your `PATH`.
32
+
25
33
  ## Install from source
26
34
 
27
35
  ```bash
@@ -51,16 +59,6 @@ Send them the `.tgz` (Slack/Drive/AirDrop). They install with:
51
59
  npm install -g ./mdview-0.6.0.tgz
52
60
  ```
53
61
 
54
- Or skip the tarball entirely:
55
-
56
- ```bash
57
- npm install -g github:hardikg2907/mdview
58
- # or one-shot
59
- npx github:hardikg2907/mdview ./docs
60
- ```
61
-
62
- The `prepare` script auto-builds on their machine if `bin/` is absent.
63
-
64
62
  ## Usage
65
63
 
66
64
  ```bash
package/bin/mdview.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/cli.ts
4
- import { existsSync, readFileSync, statSync } from "fs";
4
+ import { existsSync, readFileSync, realpathSync, statSync } from "fs";
5
5
  import path11 from "path";
6
6
  import { fileURLToPath } from "url";
7
7
  import openBrowser from "open";
@@ -430,18 +430,38 @@ import { readFile as readFile3, stat as stat2 } from "fs/promises";
430
430
  import matter from "gray-matter";
431
431
  function parseFrontmatter(raw) {
432
432
  if (!raw.startsWith("---")) {
433
- return { data: null, body: raw };
433
+ return { data: null, body: raw, bodyStartLine: 0 };
434
434
  }
435
435
  try {
436
436
  const parsed = matter(raw);
437
+ const body = parsed.content.replace(/^(?:\r?\n)+/, "");
438
+ const bodyStartLine = computeBodyStartLine(raw);
437
439
  return {
438
440
  data: parsed.data ?? null,
439
- body: parsed.content.replace(/^\n+/, "")
441
+ body,
442
+ bodyStartLine
440
443
  };
441
444
  } catch {
442
- return { data: null, body: raw };
445
+ return { data: null, body: raw, bodyStartLine: 0 };
443
446
  }
444
447
  }
448
+ function computeBodyStartLine(raw) {
449
+ const lines = raw.split(/\r?\n/);
450
+ if (lines[0] !== "---") return 0;
451
+ let closingIdx = -1;
452
+ for (let i = 1; i < lines.length; i++) {
453
+ if (lines[i] === "---") {
454
+ closingIdx = i;
455
+ break;
456
+ }
457
+ }
458
+ if (closingIdx < 0) return 0;
459
+ let bodyLine = closingIdx + 1;
460
+ while (bodyLine < lines.length && lines[bodyLine] === "") {
461
+ bodyLine++;
462
+ }
463
+ return bodyLine;
464
+ }
445
465
 
446
466
  // src/render/links.ts
447
467
  import path6 from "path/posix";
@@ -649,9 +669,12 @@ md.use(anchor, {
649
669
  });
650
670
  md.use(taskLists, { enabled: false, label: false });
651
671
  md.use(mathPlugin);
652
- async function renderMarkdown(source) {
672
+ async function renderMarkdown(source, bodyStartLine = 0) {
653
673
  const tokens = md.parse(source, {});
654
674
  for (const token of tokens) {
675
+ if (token.type === "heading_open" && token.map) {
676
+ token.attrSet("data-source-line", String(token.map[0] + bodyStartLine));
677
+ }
655
678
  if (token.type === "fence") {
656
679
  const lang = token.info.trim().split(/\s+/)[0] || "text";
657
680
  if (lang === "mermaid") {
@@ -738,8 +761,8 @@ function registerApiFile(app, rootAbsPath, rootInfo) {
738
761
  } catch {
739
762
  return reply.code(404).send({ error: "File not found" });
740
763
  }
741
- const { data, body } = parseFrontmatter(raw);
742
- const { html: rawHtml, tokens } = await renderMarkdown(body);
764
+ const { data, body, bodyStartLine } = parseFrontmatter(raw);
765
+ const { html: rawHtml, tokens } = await renderMarkdown(body, bodyStartLine);
743
766
  const html = rewriteImageSrc(tagInternalLinks(rawHtml, relPath), relPath);
744
767
  const outline = extractOutline(tokens);
745
768
  const title = (typeof data?.title === "string" ? data.title : null) ?? outline[0]?.text ?? null;
@@ -1005,9 +1028,13 @@ function registerApiSearch(app, rootAbsPath, rootInfo, configState) {
1005
1028
 
1006
1029
  // src/server/routes/api-tree.ts
1007
1030
  import path8 from "path";
1031
+ function applyOverrides(config, paletteOverride) {
1032
+ if (!paletteOverride) return config;
1033
+ return { ...config ?? {}, palette: paletteOverride };
1034
+ }
1008
1035
  function registerApiTree(app, rootAbsPath, rootInfo, configState) {
1009
1036
  app.get("/api/tree", async (_req, reply) => {
1010
- const config = configState.current;
1037
+ const config = applyOverrides(configState.current, configState.paletteOverride);
1011
1038
  if (rootInfo.rootKind === "file") {
1012
1039
  const single = [
1013
1040
  {
@@ -1119,25 +1146,29 @@ function createWatcher(rootAbsPath, opts = {}) {
1119
1146
  }
1120
1147
 
1121
1148
  // src/server/index.ts
1122
- var CSP_HTML = [
1123
- "default-src 'self'",
1124
- "script-src 'self'",
1125
- // KaTeX + mermaid inject inline styles into rendered output; the rest of
1126
- // the policy is strict.
1127
- "style-src 'self' 'unsafe-inline'",
1128
- "img-src 'self' data: blob:",
1129
- "font-src 'self' data:",
1130
- "connect-src 'self'",
1131
- "frame-ancestors 'none'",
1132
- "base-uri 'none'",
1133
- "form-action 'none'"
1134
- ].join("; ");
1149
+ function buildCspHtml(embedMode) {
1150
+ const frameAncestors = embedMode ? "*" : "'none'";
1151
+ return [
1152
+ "default-src 'self'",
1153
+ "script-src 'self'",
1154
+ // KaTeX + mermaid inject inline styles into rendered output; the rest of
1155
+ // the policy is strict.
1156
+ "style-src 'self' 'unsafe-inline'",
1157
+ "img-src 'self' data: blob:",
1158
+ "font-src 'self' data:",
1159
+ "connect-src 'self'",
1160
+ `frame-ancestors ${frameAncestors}`,
1161
+ "base-uri 'none'",
1162
+ "form-action 'none'"
1163
+ ].join("; ");
1164
+ }
1135
1165
  async function createServer(opts) {
1136
1166
  const app = Fastify({ logger: false });
1167
+ const cspHtml = buildCspHtml(opts.embedMode ?? false);
1137
1168
  app.addHook("onSend", async (_req, reply, payload) => {
1138
1169
  const ct = String(reply.getHeader("content-type") ?? "");
1139
1170
  if (ct.startsWith("text/html")) {
1140
- reply.header("content-security-policy", CSP_HTML);
1171
+ reply.header("content-security-policy", cspHtml);
1141
1172
  reply.header("x-content-type-options", "nosniff");
1142
1173
  reply.header("referrer-policy", "no-referrer");
1143
1174
  }
@@ -1145,7 +1176,11 @@ async function createServer(opts) {
1145
1176
  });
1146
1177
  const initialConfig = await loadEffectiveConfig(opts.rootAbsPath);
1147
1178
  const ignoreSet = buildIgnoreSet(initialConfig?.ignore ?? []);
1148
- const configState = { current: initialConfig, ignoreSet };
1179
+ const configState = {
1180
+ current: initialConfig,
1181
+ ignoreSet,
1182
+ paletteOverride: opts.paletteOverride
1183
+ };
1149
1184
  const watcher = createWatcher(opts.rootAbsPath, { ignore: ignoreSet });
1150
1185
  const configPath = path10.join(opts.rootAbsPath, CONFIG_FILENAME);
1151
1186
  const configWatcher = chokidar2.watch(configPath, {
@@ -1208,6 +1243,7 @@ Usage:
1208
1243
  Options:
1209
1244
  --port <n> Port to listen on (default: 7331; auto-fallback)
1210
1245
  --no-open Don't auto-launch the browser
1246
+ --palette <name> Override the palette for this run (one of: ${PALETTES.join(", ")})
1211
1247
  --version, -v Print version and exit
1212
1248
  --help, -h Show this help
1213
1249
 
@@ -1236,7 +1272,7 @@ function readVersion() {
1236
1272
  return "unknown";
1237
1273
  }
1238
1274
  function parseArgs(argv) {
1239
- const args = { target: ".", port: 7331, portExplicit: false, open: true };
1275
+ const args = { target: ".", port: 7331, portExplicit: false, open: true, embedMode: false };
1240
1276
  let targetSet = false;
1241
1277
  for (let i = 0; i < argv.length; i++) {
1242
1278
  const a = argv[i];
@@ -1246,19 +1282,33 @@ function parseArgs(argv) {
1246
1282
  args.open = false;
1247
1283
  continue;
1248
1284
  }
1285
+ if (a === "--vscode") {
1286
+ args.embedMode = true;
1287
+ continue;
1288
+ }
1249
1289
  if (a === "--port") {
1250
1290
  const v = argv[++i];
1251
1291
  if (!v) throw new Error("--port requires a number");
1252
1292
  args.port = Number(v);
1253
- if (!Number.isInteger(args.port) || args.port <= 0) throw new Error("Invalid --port");
1293
+ if (!Number.isInteger(args.port) || args.port < 0) throw new Error("Invalid --port");
1254
1294
  args.portExplicit = true;
1255
1295
  continue;
1256
1296
  }
1297
+ if (a === "--palette") {
1298
+ const v = argv[++i];
1299
+ if (!v) throw new Error("--palette requires a value");
1300
+ if (!PALETTES.includes(v)) {
1301
+ throw new Error(`Invalid --palette '${v}'. Valid: ${PALETTES.join(", ")}`);
1302
+ }
1303
+ args.palette = v;
1304
+ continue;
1305
+ }
1257
1306
  if (a.startsWith("-")) throw new Error(`Unknown flag: ${a}`);
1258
1307
  if (targetSet) throw new Error(`Unexpected argument: ${a}`);
1259
1308
  args.target = a;
1260
1309
  targetSet = true;
1261
1310
  }
1311
+ if (args.embedMode) args.open = false;
1262
1312
  return { kind: "run", args };
1263
1313
  }
1264
1314
  function detectRoot(target) {
@@ -1299,7 +1349,8 @@ async function listen(app, port, explicit) {
1299
1349
  if (explicit) {
1300
1350
  try {
1301
1351
  await app.listen({ host: "127.0.0.1", port });
1302
- return port;
1352
+ const addr = app.server.address();
1353
+ return typeof addr === "object" && addr !== null ? addr.port : port;
1303
1354
  } catch (err) {
1304
1355
  if (err.code === "EADDRINUSE") {
1305
1356
  throw new Error(
@@ -1318,7 +1369,8 @@ Find the process with: ${portFinderHint(port)}`
1318
1369
  if (attempt > 0) {
1319
1370
  console.log(`port ${port} in use, using ${tryPort} instead`);
1320
1371
  }
1321
- return tryPort;
1372
+ const addr = app.server.address();
1373
+ return typeof addr === "object" && addr !== null ? addr.port : tryPort;
1322
1374
  } catch (err) {
1323
1375
  if (err.code !== "EADDRINUSE") throw err;
1324
1376
  }
@@ -1359,11 +1411,15 @@ async function main() {
1359
1411
  console.error("Client bundle not found. Run `npm run build:client` first.");
1360
1412
  process.exit(1);
1361
1413
  }
1362
- const app = await createServer({ rootAbsPath, rootInfo, clientDir });
1414
+ const app = await createServer({ rootAbsPath, rootInfo, clientDir, paletteOverride: args.palette, embedMode: args.embedMode });
1363
1415
  const boundPort = await listen(app, args.port, args.portExplicit);
1364
1416
  const url = rootInfo.rootKind === "file" ? `http://127.0.0.1:${boundPort}/?file=${encodeURIComponent(rootInfo.rootRelPath)}` : `http://127.0.0.1:${boundPort}/`;
1365
- console.log(`mdview \u2192 ${url}`);
1366
- console.log(`watching: ${rootAbsPath}`);
1417
+ if (args.embedMode) {
1418
+ process.stdout.write(JSON.stringify({ event: "ready", url, port: boundPort }) + "\n");
1419
+ } else {
1420
+ console.log(`mdview \u2192 ${url}`);
1421
+ console.log(`watching: ${rootAbsPath}`);
1422
+ }
1367
1423
  if (args.open) await openBrowser(url);
1368
1424
  let shuttingDown = false;
1369
1425
  const shutdown = async () => {
@@ -1382,6 +1438,15 @@ async function main() {
1382
1438
  process.on("SIGINT", shutdown);
1383
1439
  process.on("SIGTERM", shutdown);
1384
1440
  if (process.platform !== "win32") process.on("SIGHUP", shutdown);
1441
+ if (args.embedMode) {
1442
+ process.stdin.on("end", () => {
1443
+ void shutdown();
1444
+ });
1445
+ process.stdin.on("error", () => {
1446
+ void shutdown();
1447
+ });
1448
+ process.stdin.resume();
1449
+ }
1385
1450
  }
1386
1451
  function formatError(err) {
1387
1452
  if (!(err instanceof Error)) return null;
@@ -1400,19 +1465,33 @@ function formatError(err) {
1400
1465
  }
1401
1466
  return null;
1402
1467
  }
1403
- main().catch((err) => {
1404
- const known = formatError(err);
1405
- if (known) {
1406
- console.error(known.message);
1407
- process.exit(known.code);
1408
- }
1409
- const message = err instanceof Error ? err.message : String(err);
1410
- console.error(`mdview: unexpected error: ${message}`);
1411
- if (process.env.MDVIEW_DEBUG === "1" && err instanceof Error && err.stack) {
1412
- console.error(err.stack);
1413
- } else {
1414
- console.error("(set MDVIEW_DEBUG=1 for full stack)");
1468
+ var isEntryPoint = (() => {
1469
+ const argv1 = process.argv[1];
1470
+ if (!argv1) return false;
1471
+ try {
1472
+ return realpathSync(fileURLToPath(import.meta.url)) === realpathSync(argv1);
1473
+ } catch {
1474
+ return false;
1415
1475
  }
1416
- process.exit(1);
1417
- });
1476
+ })();
1477
+ if (isEntryPoint) {
1478
+ main().catch((err) => {
1479
+ const known = formatError(err);
1480
+ if (known) {
1481
+ console.error(known.message);
1482
+ process.exit(known.code);
1483
+ }
1484
+ const message = err instanceof Error ? err.message : String(err);
1485
+ console.error(`mdview: unexpected error: ${message}`);
1486
+ if (process.env.MDVIEW_DEBUG === "1" && err instanceof Error && err.stack) {
1487
+ console.error(err.stack);
1488
+ } else {
1489
+ console.error("(set MDVIEW_DEBUG=1 for full stack)");
1490
+ }
1491
+ process.exit(1);
1492
+ });
1493
+ }
1494
+ export {
1495
+ parseArgs
1496
+ };
1418
1497
  //# sourceMappingURL=mdview.mjs.map
@@ -1 +1 @@
1
- import{a0 as ln,a1 as an,a2 as H,a3 as q,a4 as B,a5 as un,a6 as y,a7 as tn,a8 as L,a9 as _,aa as rn,ab as o,ac as on,ad as sn,ae as fn}from"./mermaid.core-BUwfPdjt.js";function cn(l){return l.innerRadius}function yn(l){return l.outerRadius}function gn(l){return l.startAngle}function dn(l){return l.endAngle}function mn(l){return l&&l.padAngle}function pn(l,h,I,D,v,A,C,a){var O=I-l,i=D-h,n=C-v,d=a-A,u=d*O-n*i;if(!(u*u<y))return u=(n*(h-A)-d*(l-v))/u,[l+u*O,h+u*i]}function W(l,h,I,D,v,A,C){var a=l-I,O=h-D,i=(C?A:-A)/L(a*a+O*O),n=i*O,d=-i*a,u=l+n,s=h+d,f=I+n,c=D+d,F=(u+f)/2,t=(s+c)/2,m=f-u,g=c-s,R=m*m+g*g,T=v-A,P=u*c-f*s,S=(g<0?-1:1)*L(on(0,T*T*R-P*P)),j=(P*g-m*S)/R,z=(-P*m-g*S)/R,w=(P*g+m*S)/R,p=(-P*m+g*S)/R,x=j-F,e=z-t,r=w-F,G=p-t;return x*x+e*e>r*r+G*G&&(j=w,z=p),{cx:j,cy:z,x01:-n,y01:-d,x11:j*(v/T-1),y11:z*(v/T-1)}}function hn(){var l=cn,h=yn,I=B(0),D=null,v=gn,A=dn,C=mn,a=null,O=ln(i);function i(){var n,d,u=+l.apply(this,arguments),s=+h.apply(this,arguments),f=v.apply(this,arguments)-un,c=A.apply(this,arguments)-un,F=rn(c-f),t=c>f;if(a||(a=n=O()),s<u&&(d=s,s=u,u=d),!(s>y))a.moveTo(0,0);else if(F>tn-y)a.moveTo(s*H(f),s*q(f)),a.arc(0,0,s,f,c,!t),u>y&&(a.moveTo(u*H(c),u*q(c)),a.arc(0,0,u,c,f,t));else{var m=f,g=c,R=f,T=c,P=F,S=F,j=C.apply(this,arguments)/2,z=j>y&&(D?+D.apply(this,arguments):L(u*u+s*s)),w=_(rn(s-u)/2,+I.apply(this,arguments)),p=w,x=w,e,r;if(z>y){var G=sn(z/u*q(j)),M=sn(z/s*q(j));(P-=G*2)>y?(G*=t?1:-1,R+=G,T-=G):(P=0,R=T=(f+c)/2),(S-=M*2)>y?(M*=t?1:-1,m+=M,g-=M):(S=0,m=g=(f+c)/2)}var J=s*H(m),K=s*q(m),N=u*H(T),Q=u*q(T);if(w>y){var U=s*H(g),V=s*q(g),X=u*H(R),Y=u*q(R),E;if(F<an)if(E=pn(J,K,X,Y,U,V,N,Q)){var Z=J-E[0],$=K-E[1],b=U-E[0],k=V-E[1],nn=1/q(fn((Z*b+$*k)/(L(Z*Z+$*$)*L(b*b+k*k)))/2),en=L(E[0]*E[0]+E[1]*E[1]);p=_(w,(u-en)/(nn-1)),x=_(w,(s-en)/(nn+1))}else p=x=0}S>y?x>y?(e=W(X,Y,J,K,s,x,t),r=W(U,V,N,Q,s,x,t),a.moveTo(e.cx+e.x01,e.cy+e.y01),x<w?a.arc(e.cx,e.cy,x,o(e.y01,e.x01),o(r.y01,r.x01),!t):(a.arc(e.cx,e.cy,x,o(e.y01,e.x01),o(e.y11,e.x11),!t),a.arc(0,0,s,o(e.cy+e.y11,e.cx+e.x11),o(r.cy+r.y11,r.cx+r.x11),!t),a.arc(r.cx,r.cy,x,o(r.y11,r.x11),o(r.y01,r.x01),!t))):(a.moveTo(J,K),a.arc(0,0,s,m,g,!t)):a.moveTo(J,K),!(u>y)||!(P>y)?a.lineTo(N,Q):p>y?(e=W(N,Q,U,V,u,-p,t),r=W(J,K,X,Y,u,-p,t),a.lineTo(e.cx+e.x01,e.cy+e.y01),p<w?a.arc(e.cx,e.cy,p,o(e.y01,e.x01),o(r.y01,r.x01),!t):(a.arc(e.cx,e.cy,p,o(e.y01,e.x01),o(e.y11,e.x11),!t),a.arc(0,0,u,o(e.cy+e.y11,e.cx+e.x11),o(r.cy+r.y11,r.cx+r.x11),t),a.arc(r.cx,r.cy,p,o(r.y11,r.x11),o(r.y01,r.x01),!t))):a.arc(0,0,u,T,R,t)}if(a.closePath(),n)return a=null,n+""||null}return i.centroid=function(){var n=(+l.apply(this,arguments)+ +h.apply(this,arguments))/2,d=(+v.apply(this,arguments)+ +A.apply(this,arguments))/2-an/2;return[H(d)*n,q(d)*n]},i.innerRadius=function(n){return arguments.length?(l=typeof n=="function"?n:B(+n),i):l},i.outerRadius=function(n){return arguments.length?(h=typeof n=="function"?n:B(+n),i):h},i.cornerRadius=function(n){return arguments.length?(I=typeof n=="function"?n:B(+n),i):I},i.padRadius=function(n){return arguments.length?(D=n==null?null:typeof n=="function"?n:B(+n),i):D},i.startAngle=function(n){return arguments.length?(v=typeof n=="function"?n:B(+n),i):v},i.endAngle=function(n){return arguments.length?(A=typeof n=="function"?n:B(+n),i):A},i.padAngle=function(n){return arguments.length?(C=typeof n=="function"?n:B(+n),i):C},i.context=function(n){return arguments.length?(a=n??null,i):a},i}export{hn as d};
1
+ import{a0 as ln,a1 as an,a2 as H,a3 as q,a4 as B,a5 as un,a6 as y,a7 as tn,a8 as L,a9 as _,aa as rn,ab as o,ac as on,ad as sn,ae as fn}from"./mermaid.core-BJg17JjK.js";function cn(l){return l.innerRadius}function yn(l){return l.outerRadius}function gn(l){return l.startAngle}function dn(l){return l.endAngle}function mn(l){return l&&l.padAngle}function pn(l,h,I,D,v,A,C,a){var O=I-l,i=D-h,n=C-v,d=a-A,u=d*O-n*i;if(!(u*u<y))return u=(n*(h-A)-d*(l-v))/u,[l+u*O,h+u*i]}function W(l,h,I,D,v,A,C){var a=l-I,O=h-D,i=(C?A:-A)/L(a*a+O*O),n=i*O,d=-i*a,u=l+n,s=h+d,f=I+n,c=D+d,F=(u+f)/2,t=(s+c)/2,m=f-u,g=c-s,R=m*m+g*g,T=v-A,P=u*c-f*s,S=(g<0?-1:1)*L(on(0,T*T*R-P*P)),j=(P*g-m*S)/R,z=(-P*m-g*S)/R,w=(P*g+m*S)/R,p=(-P*m+g*S)/R,x=j-F,e=z-t,r=w-F,G=p-t;return x*x+e*e>r*r+G*G&&(j=w,z=p),{cx:j,cy:z,x01:-n,y01:-d,x11:j*(v/T-1),y11:z*(v/T-1)}}function hn(){var l=cn,h=yn,I=B(0),D=null,v=gn,A=dn,C=mn,a=null,O=ln(i);function i(){var n,d,u=+l.apply(this,arguments),s=+h.apply(this,arguments),f=v.apply(this,arguments)-un,c=A.apply(this,arguments)-un,F=rn(c-f),t=c>f;if(a||(a=n=O()),s<u&&(d=s,s=u,u=d),!(s>y))a.moveTo(0,0);else if(F>tn-y)a.moveTo(s*H(f),s*q(f)),a.arc(0,0,s,f,c,!t),u>y&&(a.moveTo(u*H(c),u*q(c)),a.arc(0,0,u,c,f,t));else{var m=f,g=c,R=f,T=c,P=F,S=F,j=C.apply(this,arguments)/2,z=j>y&&(D?+D.apply(this,arguments):L(u*u+s*s)),w=_(rn(s-u)/2,+I.apply(this,arguments)),p=w,x=w,e,r;if(z>y){var G=sn(z/u*q(j)),M=sn(z/s*q(j));(P-=G*2)>y?(G*=t?1:-1,R+=G,T-=G):(P=0,R=T=(f+c)/2),(S-=M*2)>y?(M*=t?1:-1,m+=M,g-=M):(S=0,m=g=(f+c)/2)}var J=s*H(m),K=s*q(m),N=u*H(T),Q=u*q(T);if(w>y){var U=s*H(g),V=s*q(g),X=u*H(R),Y=u*q(R),E;if(F<an)if(E=pn(J,K,X,Y,U,V,N,Q)){var Z=J-E[0],$=K-E[1],b=U-E[0],k=V-E[1],nn=1/q(fn((Z*b+$*k)/(L(Z*Z+$*$)*L(b*b+k*k)))/2),en=L(E[0]*E[0]+E[1]*E[1]);p=_(w,(u-en)/(nn-1)),x=_(w,(s-en)/(nn+1))}else p=x=0}S>y?x>y?(e=W(X,Y,J,K,s,x,t),r=W(U,V,N,Q,s,x,t),a.moveTo(e.cx+e.x01,e.cy+e.y01),x<w?a.arc(e.cx,e.cy,x,o(e.y01,e.x01),o(r.y01,r.x01),!t):(a.arc(e.cx,e.cy,x,o(e.y01,e.x01),o(e.y11,e.x11),!t),a.arc(0,0,s,o(e.cy+e.y11,e.cx+e.x11),o(r.cy+r.y11,r.cx+r.x11),!t),a.arc(r.cx,r.cy,x,o(r.y11,r.x11),o(r.y01,r.x01),!t))):(a.moveTo(J,K),a.arc(0,0,s,m,g,!t)):a.moveTo(J,K),!(u>y)||!(P>y)?a.lineTo(N,Q):p>y?(e=W(N,Q,U,V,u,-p,t),r=W(J,K,X,Y,u,-p,t),a.lineTo(e.cx+e.x01,e.cy+e.y01),p<w?a.arc(e.cx,e.cy,p,o(e.y01,e.x01),o(r.y01,r.x01),!t):(a.arc(e.cx,e.cy,p,o(e.y01,e.x01),o(e.y11,e.x11),!t),a.arc(0,0,u,o(e.cy+e.y11,e.cx+e.x11),o(r.cy+r.y11,r.cx+r.x11),t),a.arc(r.cx,r.cy,p,o(r.y11,r.x11),o(r.y01,r.x01),!t))):a.arc(0,0,u,T,R,t)}if(a.closePath(),n)return a=null,n+""||null}return i.centroid=function(){var n=(+l.apply(this,arguments)+ +h.apply(this,arguments))/2,d=(+v.apply(this,arguments)+ +A.apply(this,arguments))/2-an/2;return[H(d)*n,q(d)*n]},i.innerRadius=function(n){return arguments.length?(l=typeof n=="function"?n:B(+n),i):l},i.outerRadius=function(n){return arguments.length?(h=typeof n=="function"?n:B(+n),i):h},i.cornerRadius=function(n){return arguments.length?(I=typeof n=="function"?n:B(+n),i):I},i.padRadius=function(n){return arguments.length?(D=n==null?null:typeof n=="function"?n:B(+n),i):D},i.startAngle=function(n){return arguments.length?(v=typeof n=="function"?n:B(+n),i):v},i.endAngle=function(n){return arguments.length?(A=typeof n=="function"?n:B(+n),i):A},i.padAngle=function(n){return arguments.length?(C=typeof n=="function"?n:B(+n),i):C},i.context=function(n){return arguments.length?(a=n??null,i):a},i}export{hn as d};