@rafiqui987/markode 0.3.1 → 0.4.1

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 (99) hide show
  1. package/README.md +16 -1
  2. package/dist/cli.js +243 -88
  3. package/dist/web/assets/{abnfDiagram-WEYOIA3C-C-xz1zhH.js → abnfDiagram-WEYOIA3C-B-3Lcktj.js} +1 -1
  4. package/dist/web/assets/{arc-0NKn9s7n.js → arc-B1vQQwbr.js} +1 -1
  5. package/dist/web/assets/{architecture-WOLXFQ4H-yvNPw04L.js → architecture-WOLXFQ4H-D8_qhlNG.js} +1 -1
  6. package/dist/web/assets/{architectureDiagram-ZHVYKT53-DiNkPsUS.js → architectureDiagram-ZHVYKT53-B4uGFnQg.js} +1 -1
  7. package/dist/web/assets/{blockDiagram-RJAE7QA3-Bm5an-ZR.js → blockDiagram-RJAE7QA3-B1PRI2Fk.js} +1 -1
  8. package/dist/web/assets/{c4Diagram-XDPPPE54-DCIkW1i3.js → c4Diagram-XDPPPE54-BOSiNgn_.js} +1 -1
  9. package/dist/web/assets/channel-ggr2Mduz.js +1 -0
  10. package/dist/web/assets/{chunk-2E7WHVMD-w-cvaztJ.js → chunk-2E7WHVMD-B2TT-9T2.js} +1 -1
  11. package/dist/web/assets/{chunk-4EMNKR2T-Dz1c4ddf.js → chunk-4EMNKR2T-BJStHb31.js} +1 -1
  12. package/dist/web/assets/{chunk-55XCU76K-BkW2QTCZ.js → chunk-55XCU76K-CGSdzfU6.js} +1 -1
  13. package/dist/web/assets/{chunk-7S6XSTFO-SqLAsU6N.js → chunk-7S6XSTFO-D7U3aXUK.js} +1 -1
  14. package/dist/web/assets/{chunk-AQDTSKZB-DwIPdMmQ.js → chunk-AQDTSKZB-C6fkREWV.js} +1 -1
  15. package/dist/web/assets/{chunk-DSNLSHJZ-BNEo5raG.js → chunk-DSNLSHJZ-C0Wri32R.js} +1 -1
  16. package/dist/web/assets/{chunk-HAGFOTED-BokAjJjC.js → chunk-HAGFOTED-dS3yjqSY.js} +1 -1
  17. package/dist/web/assets/{chunk-HNE4Q36P-BlJCzrNG.js → chunk-HNE4Q36P-B0HJeFYe.js} +1 -1
  18. package/dist/web/assets/{chunk-NQOKRVIF-CK1D9VKN.js → chunk-NQOKRVIF-DCR-ZD6p.js} +1 -1
  19. package/dist/web/assets/{chunk-UHW7PFBP-ycMkWOji.js → chunk-UHW7PFBP-DvXVrsgg.js} +1 -1
  20. package/dist/web/assets/{chunk-VQ5W62QI-CNI8j3BI.js → chunk-VQ5W62QI-mU_IBCXT.js} +1 -1
  21. package/dist/web/assets/{chunk-WQQL4CDK-DvQQgYrd.js → chunk-WQQL4CDK-DnyUQt3W.js} +1 -1
  22. package/dist/web/assets/{chunk-XXDRQBXY-cFqAbOh1.js → chunk-XXDRQBXY-DNhISORq.js} +1 -1
  23. package/dist/web/assets/{chunk-YZO67HFG-CkfGL1zX.js → chunk-YZO67HFG-C_oEIdWe.js} +1 -1
  24. package/dist/web/assets/{chunk-ZAUX2LTX-BwdZydyj.js → chunk-ZAUX2LTX-D5aMvPiJ.js} +1 -1
  25. package/dist/web/assets/{chunk-ZCHMQSOR-CXDXBIC6.js → chunk-ZCHMQSOR-B5J6sRpu.js} +1 -1
  26. package/dist/web/assets/{classDiagram-v2-4MYWR3UA-B95ypqg8.js → classDiagram-v2-4MYWR3UA-D4-o3iga.js} +1 -1
  27. package/dist/web/assets/{cose-bilkent-JH36ORCC-C8-ToTGn.js → cose-bilkent-JH36ORCC-CqNUB7G6.js} +1 -1
  28. package/dist/web/assets/{cynefin-EF2NZ3EQ-CHth0Nt9.js → cynefin-EF2NZ3EQ-BLBtXLl2.js} +1 -1
  29. package/dist/web/assets/{cynefinDiagram-WF24UDRP-CMcwwxC8.js → cynefinDiagram-WF24UDRP-BlytpdKL.js} +1 -1
  30. package/dist/web/assets/{dagre-NK4GIZVX-BZzAgRpg.js → dagre-NK4GIZVX-DIUkOqo_.js} +1 -1
  31. package/dist/web/assets/{diagram-CBK3MWTC-DGwxJbVy.js → diagram-CBK3MWTC-4WJqLswq.js} +1 -1
  32. package/dist/web/assets/{diagram-I5XIIV2D-B17CYdAP.js → diagram-I5XIIV2D-s1EUO6xt.js} +1 -1
  33. package/dist/web/assets/{diagram-ODIL2UCW-CYPFYS2M.js → diagram-ODIL2UCW-GvgDR4t8.js} +1 -1
  34. package/dist/web/assets/{diagram-PFBEJUXE-BQMumROl.js → diagram-PFBEJUXE-B6J9SedW.js} +1 -1
  35. package/dist/web/assets/{diagram-RJA3I4VV-vHTuDO1-.js → diagram-RJA3I4VV-CqA7qcNf.js} +1 -1
  36. package/dist/web/assets/{diagram-TYUNFSNR-C_WYz7qL.js → diagram-TYUNFSNR-Cln9POlx.js} +1 -1
  37. package/dist/web/assets/{dist-DFcDEdTm.js → dist--fImHE6g.js} +1 -1
  38. package/dist/web/assets/{dist-BOCA4kQq.js → dist-Bg-QtHy9.js} +1 -1
  39. package/dist/web/assets/{dist-cSM0Lli0.js → dist-BghTt_37.js} +1 -1
  40. package/dist/web/assets/{dist-PwT2nxki.js → dist-CU6eXj3N.js} +1 -1
  41. package/dist/web/assets/{dist-B1oQ1VTT.js → dist-CVF0b6Yz.js} +1 -1
  42. package/dist/web/assets/{dist-B5uXb_Wi.js → dist-Cd1DR3ly.js} +1 -1
  43. package/dist/web/assets/{dist-8k6FSdRu.js → dist-CoioyMmF.js} +1 -1
  44. package/dist/web/assets/{dist-DV0HO3Fe.js → dist-CykDxBaO.js} +1 -1
  45. package/dist/web/assets/{dist-QI7QavRs.js → dist-DpqggjJG.js} +1 -1
  46. package/dist/web/assets/{dist-DZQ_bwip.js → dist-YudOLIZ5.js} +1 -1
  47. package/dist/web/assets/{dist-BT3nK1GA.js → dist-xGXJDvke.js} +1 -1
  48. package/dist/web/assets/{ebnfDiagram-V4P3TTPT-DLMwyX-U.js → ebnfDiagram-V4P3TTPT-BusXM5tX.js} +1 -1
  49. package/dist/web/assets/{elk-QONTBCTQ-DVvxbtF4.js → elk-QONTBCTQ-B9oq7Tkq.js} +1 -1
  50. package/dist/web/assets/{erDiagram-KYQIGQAA-DPXicJ1t.js → erDiagram-KYQIGQAA-CmL9SAnh.js} +1 -1
  51. package/dist/web/assets/{eventmodeling-K75KTNOO-DpHVZP_6.js → eventmodeling-K75KTNOO-R6NmozzN.js} +1 -1
  52. package/dist/web/assets/flowDiagram-IUGLLWBU-CkUCRx3C.js +1 -0
  53. package/dist/web/assets/{ganttDiagram-R7GPNTJY-Ch6NDX5Q.js → ganttDiagram-R7GPNTJY-DRa2V_Qe.js} +1 -1
  54. package/dist/web/assets/{gitGraph-VSP46ZUC-CIhLB663.js → gitGraph-VSP46ZUC-CdFMO2LD.js} +1 -1
  55. package/dist/web/assets/{gitGraphDiagram-PDYL7XHY-Ci_MIbqs.js → gitGraphDiagram-PDYL7XHY-C-xmUbl1.js} +1 -1
  56. package/dist/web/assets/{index-CxwfaWVo.js → index-BFpTDsCp.js} +4 -4
  57. package/dist/web/assets/{info-OHQRW6UA-Dau8xD88.js → info-OHQRW6UA-CnPUMAqS.js} +1 -1
  58. package/dist/web/assets/{infoDiagram-MVDRKAX5-4spgggd7.js → infoDiagram-MVDRKAX5-DxouwrN7.js} +1 -1
  59. package/dist/web/assets/{ishikawaDiagram-HPEHV2GE-DgFczAdB.js → ishikawaDiagram-HPEHV2GE-qrLpOq3_.js} +1 -1
  60. package/dist/web/assets/{journeyDiagram-BOSHW7O7-CJKwCuyG.js → journeyDiagram-BOSHW7O7-BDTfHWHd.js} +1 -1
  61. package/dist/web/assets/{kanban-definition-FNSA4HC5-B_HPa_Q8.js → kanban-definition-FNSA4HC5-CTBgSpp6.js} +1 -1
  62. package/dist/web/assets/{line-Bil8yI0B.js → line-D8R5RRtF.js} +1 -1
  63. package/dist/web/assets/{linear-DJSxHb3I.js → linear-BCL193tG.js} +1 -1
  64. package/dist/web/assets/{mermaid-parser.core-ByEdgqAb.js → mermaid-parser.core-C1XIxySl.js} +3 -3
  65. package/dist/web/assets/{mermaid.core-CXUI3iYT.js → mermaid.core-C-385ykR.js} +4 -4
  66. package/dist/web/assets/{mindmap-definition-6OY57UG3-w7xG6UiS.js → mindmap-definition-6OY57UG3-BnCvQFLY.js} +1 -1
  67. package/dist/web/assets/{packet-JDAUHWVQ-YvTb_dXP.js → packet-JDAUHWVQ-DVCRx-wc.js} +1 -1
  68. package/dist/web/assets/{pegDiagram-ECIUJNBX-D5FI1bVJ.js → pegDiagram-ECIUJNBX-CIDVz_ln.js} +1 -1
  69. package/dist/web/assets/{pie-XZMESJXO-BH2bih-K.js → pie-XZMESJXO-BHXvmR-y.js} +1 -1
  70. package/dist/web/assets/{pieDiagram-GNMPY74T-DUR82NlG.js → pieDiagram-GNMPY74T-Bb_l0cKd.js} +1 -1
  71. package/dist/web/assets/{quadrantDiagram-D57K4MC3-DauAEIyL.js → quadrantDiagram-D57K4MC3-Dqq4AGQt.js} +1 -1
  72. package/dist/web/assets/{radar-ABXABTNO-CdUXfEdf.js → radar-ABXABTNO-Ba5vnnQ7.js} +1 -1
  73. package/dist/web/assets/{railroad-I3PHUGI6-Djt90nhE.js → railroad-I3PHUGI6-CxoMtJ5h.js} +1 -1
  74. package/dist/web/assets/{railroad-abnf-LNEFI6M7-XqY0pGCO.js → railroad-abnf-LNEFI6M7-BXxErwiU.js} +1 -1
  75. package/dist/web/assets/{railroad-ebnf-DWYD2UWJ-BNSOgId4.js → railroad-ebnf-DWYD2UWJ-C_9H5arK.js} +1 -1
  76. package/dist/web/assets/{railroad-peg-JR7BVNR7-DW2TRqOr.js → railroad-peg-JR7BVNR7-50KHJESB.js} +1 -1
  77. package/dist/web/assets/{railroadDiagram-Y72NRBL7-CTDNRHBf.js → railroadDiagram-Y72NRBL7-9w1amWMc.js} +1 -1
  78. package/dist/web/assets/{requirementDiagram-EQYSW5RA-DJ5H8uqE.js → requirementDiagram-EQYSW5RA-D3XygoSz.js} +1 -1
  79. package/dist/web/assets/{sankeyDiagram-SY24JHO5-Xa_3Bd4U.js → sankeyDiagram-SY24JHO5-C68crPY9.js} +1 -1
  80. package/dist/web/assets/{sequenceDiagram-BLEHNHQU-2jNpfI3_.js → sequenceDiagram-BLEHNHQU-BNcJ1wfc.js} +1 -1
  81. package/dist/web/assets/{src-DgNmQVK4.js → src-okGi814h.js} +1 -1
  82. package/dist/web/assets/{stateDiagram-v2-A6IESKWZ-DtxzihUG.js → stateDiagram-v2-A6IESKWZ-DX7rAO1j.js} +1 -1
  83. package/dist/web/assets/{swimlanes-B3ENRKFQ-DJBCOj2u.js → swimlanes-B3ENRKFQ-DGSmz_ab.js} +1 -1
  84. package/dist/web/assets/swimlanesDiagram-AYQRV4AK-D8bRrq1P.js +8 -0
  85. package/dist/web/assets/{timeline-definition-JXYKGLGB-C-ixUm6b.js → timeline-definition-JXYKGLGB-5COU2ouX.js} +1 -1
  86. package/dist/web/assets/{treeView-D4JQ5SDB-yWRFH4mR.js → treeView-D4JQ5SDB-BgrtWP9w.js} +1 -1
  87. package/dist/web/assets/{treemap-SAJKECNS-q3FZ9UjJ.js → treemap-SAJKECNS-CLZcktWl.js} +1 -1
  88. package/dist/web/assets/{usecaseDiagram-WPOLBNNX-Ch9QG7L1.js → usecaseDiagram-WPOLBNNX-BbJ7QjYR.js} +1 -1
  89. package/dist/web/assets/{vennDiagram-Q3Y3IDCW-85m0XMhF.js → vennDiagram-Q3Y3IDCW-IhZTghFG.js} +1 -1
  90. package/dist/web/assets/{wardley-7MLQ67FV-S2NRiIdM.js → wardley-7MLQ67FV-XjDz9vxn.js} +1 -1
  91. package/dist/web/assets/{wardleyDiagram-IVAIDKWA-q8ZLrvVG.js → wardleyDiagram-IVAIDKWA-DTcLR0T-.js} +1 -1
  92. package/dist/web/assets/{xychartDiagram-4URNHDU4-eSUy1iT7.js → xychartDiagram-4URNHDU4-Dja-ugvw.js} +1 -1
  93. package/dist/web/index.html +1 -1
  94. package/package.json +1 -1
  95. package/templates/proposals/SKILL.md +2 -1
  96. package/templates/skill/SKILL.md +18 -1
  97. package/dist/web/assets/channel-BkrEjK89.js +0 -1
  98. package/dist/web/assets/flowDiagram-IUGLLWBU-DrcHkm4d.js +0 -1
  99. package/dist/web/assets/swimlanesDiagram-AYQRV4AK-_cBuwUIk.js +0 -8
package/dist/cli.js CHANGED
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/cli/index.ts
4
- import fs20 from "fs";
5
- import path20 from "path";
4
+ import fs22 from "fs";
5
+ import path22 from "path";
6
6
 
7
7
  // src/core/changes.ts
8
8
  import crypto from "crypto";
@@ -1832,12 +1832,100 @@ function keepLanguage(root2, rel) {
1832
1832
  return detected;
1833
1833
  }
1834
1834
 
1835
- // src/core/wait.ts
1835
+ // src/core/server.ts
1836
+ import { spawn } from "child_process";
1836
1837
  import fs17 from "fs";
1837
1838
  import path17 from "path";
1839
+ var serverFile = (root2) => path17.join(stateDir(root2), "server.json");
1840
+ var isAlive = (pid) => {
1841
+ try {
1842
+ process.kill(pid, 0);
1843
+ return true;
1844
+ } catch {
1845
+ return false;
1846
+ }
1847
+ };
1848
+ function recordServer(root2, port) {
1849
+ const file = serverFile(root2);
1850
+ fs17.mkdirSync(path17.dirname(file), { recursive: true });
1851
+ assertInside(file);
1852
+ fs17.writeFileSync(file, JSON.stringify({ port, pid: process.pid }));
1853
+ process.once("exit", () => {
1854
+ if (runningServer(root2)?.pid === process.pid) fs17.rmSync(file, { force: true });
1855
+ });
1856
+ for (const sig of ["SIGINT", "SIGTERM", "SIGHUP"]) process.once(sig, () => process.exit(130));
1857
+ }
1858
+ function runningServer(root2) {
1859
+ try {
1860
+ const s = JSON.parse(fs17.readFileSync(serverFile(root2), "utf8"));
1861
+ return Number.isInteger(s.port) && Number.isInteger(s.pid) && isAlive(s.pid) ? { port: s.port, pid: s.pid } : null;
1862
+ } catch {
1863
+ return null;
1864
+ }
1865
+ }
1866
+ async function responds(port) {
1867
+ try {
1868
+ return (await fetch(`http://127.0.0.1:${port}/api/info`, { signal: AbortSignal.timeout(1e3) })).ok;
1869
+ } catch {
1870
+ return false;
1871
+ }
1872
+ }
1873
+ async function ensureServer(root2, cli2, port) {
1874
+ const running = runningServer(root2);
1875
+ if (running && await responds(running.port)) return running;
1876
+ const child = spawn(process.execPath, [...process.execArgv, cli2, "serve", "--no-open", "--port", String(port)], {
1877
+ cwd: root2,
1878
+ env: { ...process.env, MARKODE_ROOT: root2 },
1879
+ detached: true,
1880
+ stdio: "ignore"
1881
+ });
1882
+ child.unref();
1883
+ for (let i = 0; i < 100; i++) {
1884
+ await new Promise((r) => setTimeout(r, 100));
1885
+ const s = runningServer(root2);
1886
+ if (s && s.pid === child.pid && await responds(s.port)) return s;
1887
+ }
1888
+ throw new Error("The editor did not start; run `markode serve` to see why.");
1889
+ }
1890
+ var editorUrl = (port, doc) => `http://localhost:${port}/${doc ? `open?path=${encodeURIComponent(doc).replace(/%2F/g, "/")}` : ""}`;
1891
+
1892
+ // src/core/update.ts
1893
+ import { spawnSync as spawnSync2 } from "child_process";
1894
+ import fs18 from "fs";
1895
+ import path18 from "path";
1896
+ var PKG = JSON.parse(fs18.readFileSync(path18.join(PKG_ROOT, "package.json"), "utf8"));
1897
+ var CURRENT_VERSION = PKG.version;
1898
+ function installer() {
1899
+ const dir = PKG_ROOT.split(path18.sep).join("/");
1900
+ if (dir.includes("/_npx/")) return "npx";
1901
+ if (!dir.includes("/node_modules/")) return null;
1902
+ return dir.includes("/pnpm/") || dir.includes("/.pnpm/") ? "pnpm" : "npm";
1903
+ }
1904
+ async function latestVersion() {
1905
+ const res = await fetch(`https://registry.npmjs.org/${PKG.name}/latest`, { headers: { accept: "application/json" }, signal: AbortSignal.timeout(15e3) });
1906
+ if (!res.ok) throw new Error(`The npm registry answered ${res.status}`);
1907
+ return (await res.json()).version;
1908
+ }
1909
+ function isNewer(a, b) {
1910
+ const pa = a.split(".").map((n) => parseInt(n, 10));
1911
+ const pb = b.split(".").map((n) => parseInt(n, 10));
1912
+ for (let i = 0; i < 3; i++) if ((pa[i] ?? 0) !== (pb[i] ?? 0)) return (pa[i] ?? 0) > (pb[i] ?? 0);
1913
+ return false;
1914
+ }
1915
+ function installCommand2(via, version) {
1916
+ const spec = `${PKG.name}@${version}`;
1917
+ return via === "pnpm" ? ["pnpm", "add", "-g", spec, "--config.minimum-release-age=0"] : ["npm", "install", "-g", spec, "--min-release-age=0", "--prefer-online"];
1918
+ }
1919
+ function runInstall(cmd) {
1920
+ return spawnSync2(cmd[0], cmd.slice(1), { stdio: "inherit", shell: process.platform === "win32" }).status === 0;
1921
+ }
1922
+
1923
+ // src/core/wait.ts
1924
+ import fs19 from "fs";
1925
+ import path19 from "path";
1838
1926
  import YAML5 from "yaml";
1839
- var waitsDir = (root2) => path17.join(stateDir(root2), "waits");
1840
- var pidFile = (root2, rel) => path17.join(waitsDir(root2), `${encodeURIComponent(rel)}.pid`);
1927
+ var waitsDir = (root2) => path19.join(stateDir(root2), "waits");
1928
+ var pidFile = (root2, rel) => path19.join(waitsDir(root2), `${encodeURIComponent(rel)}.pid`);
1841
1929
  var frontmatter2 = (text3) => {
1842
1930
  try {
1843
1931
  return YAML5.parse(/^---\r?\n([\s\S]*?)\r?\n---/.exec(text3)?.[1] ?? "", { logLevel: "error" }) ?? {};
@@ -1845,7 +1933,7 @@ var frontmatter2 = (text3) => {
1845
1933
  return {};
1846
1934
  }
1847
1935
  };
1848
- var isAlive = (pid) => {
1936
+ var isAlive2 = (pid) => {
1849
1937
  try {
1850
1938
  process.kill(pid, 0);
1851
1939
  return true;
@@ -1856,27 +1944,27 @@ var isAlive = (pid) => {
1856
1944
  function waitingOn(root2) {
1857
1945
  let names2 = [];
1858
1946
  try {
1859
- names2 = fs17.readdirSync(waitsDir(root2)).filter((f) => f.endsWith(".pid"));
1947
+ names2 = fs19.readdirSync(waitsDir(root2)).filter((f) => f.endsWith(".pid"));
1860
1948
  } catch {
1861
1949
  }
1862
1950
  return names2.flatMap((f) => {
1863
- const pid = Number(fs17.readFileSync(path17.join(waitsDir(root2), f), "utf8"));
1864
- return isAlive(pid) ? [decodeURIComponent(f.slice(0, -4))] : [];
1951
+ const pid = Number(fs19.readFileSync(path19.join(waitsDir(root2), f), "utf8"));
1952
+ return isAlive2(pid) ? [decodeURIComponent(f.slice(0, -4))] : [];
1865
1953
  });
1866
1954
  }
1867
1955
  function waitForAnswer(root2, rel) {
1868
- const abs = path17.join(root2, rel);
1869
- fs17.mkdirSync(waitsDir(root2), { recursive: true });
1956
+ const abs = path19.join(root2, rel);
1957
+ fs19.mkdirSync(waitsDir(root2), { recursive: true });
1870
1958
  assertInside(pidFile(root2, rel));
1871
- fs17.writeFileSync(pidFile(root2, rel), String(process.pid));
1872
- const cleanup = () => fs17.rmSync(pidFile(root2, rel), { force: true });
1959
+ fs19.writeFileSync(pidFile(root2, rel), String(process.pid));
1960
+ const cleanup = () => fs19.rmSync(pidFile(root2, rel), { force: true });
1873
1961
  process.once("exit", cleanup);
1874
1962
  for (const sig of ["SIGINT", "SIGTERM", "SIGHUP"]) process.once(sig, () => process.exit(130));
1875
1963
  return new Promise((resolve) => {
1876
1964
  const poll = () => {
1877
1965
  let text3;
1878
1966
  try {
1879
- text3 = fs17.readFileSync(abs, "utf8");
1967
+ text3 = fs19.readFileSync(abs, "utf8");
1880
1968
  } catch {
1881
1969
  return resolve("gone");
1882
1970
  }
@@ -1890,7 +1978,7 @@ function waitForAnswer(root2, rel) {
1890
1978
  }
1891
1979
  var COMMENT = /^\s*<!-- (comment|reply) by (.+?), (\d{4}-\d{2}-\d{2})(?:, on "((?:[^"\\]|\\.)*)")?:\s?([\s\S]*?)\s*-->\s*$/;
1892
1980
  function answerSummary(root2, rel) {
1893
- const text3 = fs17.readFileSync(path17.join(root2, rel), "utf8");
1981
+ const text3 = fs19.readFileSync(path19.join(root2, rel), "utf8");
1894
1982
  const fm = frontmatter2(text3);
1895
1983
  const body = text3.replace(/^---\r?\n[\s\S]*?\r?\n---\r?\n?/, "");
1896
1984
  const lines = body.split("\n");
@@ -1964,9 +2052,10 @@ function answerSummary(root2, rel) {
1964
2052
  }
1965
2053
 
1966
2054
  // src/server/index.ts
1967
- import fs18 from "fs";
2055
+ import crypto3 from "crypto";
2056
+ import fs20 from "fs";
1968
2057
  import http from "http";
1969
- import path18 from "path";
2058
+ import path20 from "path";
1970
2059
  import { watch } from "chokidar";
1971
2060
  import open from "open";
1972
2061
  import pc from "picocolors";
@@ -2034,7 +2123,7 @@ async function startServer({ root: root2, port, open: openBrowser }) {
2034
2123
  if (typeof rel !== "string" || !rel.trim()) throw new HttpError(400, "Expected a path");
2035
2124
  const abs = safeResolve(root2, rel);
2036
2125
  if (abs === root2) throw new HttpError(400, "Refusing to delete the project root");
2037
- if (!fs18.existsSync(abs)) throw new HttpError(404, "Not found");
2126
+ if (!fs20.existsSync(abs)) throw new HttpError(404, "Not found");
2038
2127
  return abs;
2039
2128
  };
2040
2129
  const translationFile = (lang, rel) => {
@@ -2046,7 +2135,7 @@ async function startServer({ root: root2, port, open: openBrowser }) {
2046
2135
  "GET /api/info": () => {
2047
2136
  const c = config();
2048
2137
  return {
2049
- name: path18.basename(root2),
2138
+ name: path20.basename(root2),
2050
2139
  mainDoc: c.mainDoc ?? null,
2051
2140
  sourceLang: sourceLang(),
2052
2141
  langs: langs().filter((l) => l !== sourceLang()),
@@ -2073,7 +2162,7 @@ async function startServer({ root: root2, port, open: openBrowser }) {
2073
2162
  }
2074
2163
  if (isLang(body.sourceLang) && body.sourceLang !== sourceLang()) {
2075
2164
  if (!c.mainDoc) throw new HttpError(400, "No main document configured; run `markode init`");
2076
- applyRulesToFile(path18.join(root2, c.mainDoc), void 0, body.sourceLang);
2165
+ applyRulesToFile(path20.join(root2, c.mainDoc), void 0, body.sourceLang);
2077
2166
  }
2078
2167
  writeConfig(root2, c);
2079
2168
  return { ...c, langs: c.langs.filter((l) => l !== sourceLang()) };
@@ -2094,20 +2183,20 @@ async function startServer({ root: root2, port, open: openBrowser }) {
2094
2183
  "GET /api/waiting": () => ({ paths: waitingOn(root2) }),
2095
2184
  "GET /api/settings": () => readSettings(),
2096
2185
  "PUT /api/settings": (_, body) => writeSettings(body),
2097
- "GET /api/tree": (url2) => {
2098
- const l = viewLang(url2.searchParams.get("lang"));
2186
+ "GET /api/tree": (url3) => {
2187
+ const l = viewLang(url3.searchParams.get("lang"));
2099
2188
  const sync2 = l ? Object.fromEntries(allStatuses(root2, l).map((e) => [e.path, e.status])) : {};
2100
2189
  const foreign = featureState(root2).translations ? Object.fromEntries(foreignFiles(root2, sourceLang()).map((f) => [f.path, f.detected])) : {};
2101
2190
  return { tree: scanTree(root2), git: gitStatuses(root2), sync: sync2, foreign };
2102
2191
  },
2103
2192
  "POST /api/keep-language": (_, body) => ({ lang: keepLanguage(root2, mdPath(body.path)) }),
2104
- "GET /api/file": (url2) => {
2105
- const rel = mdPath(url2.searchParams.get("path"));
2106
- const l = viewLang(url2.searchParams.get("lang"));
2107
- const source = fs18.readFileSync(safeResolve(root2, rel), "utf8");
2193
+ "GET /api/file": (url3) => {
2194
+ const rel = mdPath(url3.searchParams.get("path"));
2195
+ const l = viewLang(url3.searchParams.get("lang"));
2196
+ const source = fs20.readFileSync(safeResolve(root2, rel), "utf8");
2108
2197
  if (l) {
2109
2198
  const tPath = translationFile(l, rel);
2110
- if (fs18.existsSync(tPath)) return { path: rel, content: fs18.readFileSync(tPath, "utf8"), target: "translation", status: fileStatus(root2, l, rel) };
2199
+ if (fs20.existsSync(tPath)) return { path: rel, content: fs20.readFileSync(tPath, "utf8"), target: "translation", status: fileStatus(root2, l, rel) };
2111
2200
  return { path: rel, content: source, target: "source", status: "missing" };
2112
2201
  }
2113
2202
  return { path: rel, content: source, target: "source", status: null };
@@ -2116,19 +2205,19 @@ async function startServer({ root: root2, port, open: openBrowser }) {
2116
2205
  const rel = mdPath(body.path);
2117
2206
  const l = viewLang(body.lang);
2118
2207
  const file = body.target === "translation" && l ? translationFile(l, rel) : safeResolve(root2, rel);
2119
- fs18.mkdirSync(path18.dirname(file), { recursive: true });
2208
+ fs20.mkdirSync(path20.dirname(file), { recursive: true });
2120
2209
  const content = String(body.content ?? "");
2121
- if (!l && featureState(root2).agent) logSave(root2, rel, fs18.existsSync(file) ? fs18.readFileSync(file, "utf8") : "", content);
2122
- fs18.writeFileSync(file, content);
2210
+ if (!l && featureState(root2).agent) logSave(root2, rel, fs20.existsSync(file) ? fs20.readFileSync(file, "utf8") : "", content);
2211
+ fs20.writeFileSync(file, content);
2123
2212
  return { ok: true, status: l ? fileStatus(root2, l, rel) : null };
2124
2213
  },
2125
2214
  "POST /api/file": (_, body) => {
2126
2215
  const rel = mdPath(body.path);
2127
2216
  const file = safeResolve(root2, rel);
2128
- if (fs18.existsSync(file)) throw new HttpError(409, "File already exists");
2129
- fs18.mkdirSync(path18.dirname(file), { recursive: true });
2130
- const title = path18.basename(rel, ".md").replace(/^\d+[-_]/, "").replace(/[-_]/g, " ");
2131
- fs18.writeFileSync(file, `# ${title.charAt(0).toUpperCase() + title.slice(1)}
2217
+ if (fs20.existsSync(file)) throw new HttpError(409, "File already exists");
2218
+ fs20.mkdirSync(path20.dirname(file), { recursive: true });
2219
+ const title = path20.basename(rel, ".md").replace(/^\d+[-_]/, "").replace(/[-_]/g, " ");
2220
+ fs20.writeFileSync(file, `# ${title.charAt(0).toUpperCase() + title.slice(1)}
2132
2221
 
2133
2222
  `);
2134
2223
  return { ok: true, path: rel };
@@ -2138,20 +2227,20 @@ async function startServer({ root: root2, port, open: openBrowser }) {
2138
2227
  if (typeof body.path !== "string" || !body.path.trim()) throw new HttpError(400, "Expected a path");
2139
2228
  const dir = safeResolve(root2, body.path);
2140
2229
  if (dir === root2) throw new HttpError(400, "Expected a path");
2141
- if (fs18.existsSync(dir)) throw new HttpError(409, "A file or folder with that name already exists");
2142
- fs18.mkdirSync(dir, { recursive: true });
2143
- return { ok: true, path: toPosix(path18.relative(root2, dir)) };
2230
+ if (fs20.existsSync(dir)) throw new HttpError(409, "A file or folder with that name already exists");
2231
+ fs20.mkdirSync(dir, { recursive: true });
2232
+ return { ok: true, path: toPosix(path20.relative(root2, dir)) };
2144
2233
  },
2145
- "GET /api/delete-preview": (url2) => {
2146
- const abs = deletable(url2.searchParams.get("path"));
2147
- if (!fs18.statSync(abs).isDirectory()) return { kind: "file", files: 1, md: 1 };
2148
- const files = fs18.readdirSync(abs, { recursive: true, withFileTypes: true }).filter((e) => e.isFile());
2234
+ "GET /api/delete-preview": (url3) => {
2235
+ const abs = deletable(url3.searchParams.get("path"));
2236
+ if (!fs20.statSync(abs).isDirectory()) return { kind: "file", files: 1, md: 1 };
2237
+ const files = fs20.readdirSync(abs, { recursive: true, withFileTypes: true }).filter((e) => e.isFile());
2149
2238
  return { kind: "dir", files: files.length, md: files.filter((e) => e.name.toLowerCase().endsWith(".md")).length };
2150
2239
  },
2151
- "DELETE /api/path": (url2) => {
2152
- const rel = toPosix(path18.relative(root2, deletable(url2.searchParams.get("path"))));
2153
- fs18.rmSync(safeResolve(root2, rel), { recursive: true });
2154
- for (const l of config().langs) fs18.rmSync(translationFile(l, rel), { recursive: true, force: true });
2240
+ "DELETE /api/path": (url3) => {
2241
+ const rel = toPosix(path20.relative(root2, deletable(url3.searchParams.get("path"))));
2242
+ fs20.rmSync(safeResolve(root2, rel), { recursive: true });
2243
+ for (const l of config().langs) fs20.rmSync(translationFile(l, rel), { recursive: true, force: true });
2155
2244
  return { ok: true };
2156
2245
  },
2157
2246
  "POST /api/ignore": (_, body) => {
@@ -2160,7 +2249,7 @@ async function startServer({ root: root2, port, open: openBrowser }) {
2160
2249
  setIgnored(root2, body.path, body.kind === "dir" ? "dir" : "file", !!body.ignored);
2161
2250
  return { ok: true };
2162
2251
  },
2163
- "GET /api/diff": (url2) => ({ diff: gitDiff(root2, mdPath(url2.searchParams.get("path"))) }),
2252
+ "GET /api/diff": (url3) => ({ diff: gitDiff(root2, mdPath(url3.searchParams.get("path"))) }),
2164
2253
  "GET /api/dashboard": () => {
2165
2254
  const sdd = summarizeSdd(root2);
2166
2255
  const shown = sddPrefixes(sdd);
@@ -2168,12 +2257,12 @@ async function startServer({ root: root2, port, open: openBrowser }) {
2168
2257
  },
2169
2258
  "GET /api/rules": () => {
2170
2259
  const mainDoc = readConfig(root2)?.mainDoc;
2171
- const text3 = mainDoc && fs18.existsSync(path18.join(root2, mainDoc)) ? fs18.readFileSync(path18.join(root2, mainDoc), "utf8") : "";
2260
+ const text3 = mainDoc && fs20.existsSync(path20.join(root2, mainDoc)) ? fs20.readFileSync(path20.join(root2, mainDoc), "utf8") : "";
2172
2261
  return { rules: listRules(), applied: appliedRuleIds(text3), mainDoc: mainDoc ?? null };
2173
2262
  },
2174
2263
  "PUT /api/rules": (_, body) => saveRule(body),
2175
- "DELETE /api/rules": (url2) => {
2176
- deleteRule(url2.searchParams.get("id") ?? "");
2264
+ "DELETE /api/rules": (url3) => {
2265
+ deleteRule(url3.searchParams.get("id") ?? "");
2177
2266
  return { ok: true };
2178
2267
  },
2179
2268
  // Global skills: reads and writes are limited to SKILL.md of discovered skill folders.
@@ -2182,14 +2271,14 @@ async function startServer({ root: root2, port, open: openBrowser }) {
2182
2271
  if (typeof body.name !== "string" || !Array.isArray(body.tags)) throw new HttpError(400, "Expected name and tags");
2183
2272
  return { tags: setSkillTags(body.name, body.tags.map(String)) };
2184
2273
  },
2185
- "GET /api/skills/file": (url2) => {
2186
- const skill = getSkill(root2, url2.searchParams.get("key"));
2187
- return { path: skill.key, content: fs18.readFileSync(path18.join(skill.key, "SKILL.md"), "utf8"), target: "source", status: null };
2274
+ "GET /api/skills/file": (url3) => {
2275
+ const skill = getSkill(root2, url3.searchParams.get("key"));
2276
+ return { path: skill.key, content: fs20.readFileSync(path20.join(skill.key, "SKILL.md"), "utf8"), target: "source", status: null };
2188
2277
  },
2189
2278
  "PUT /api/skills/file": (_, body) => {
2190
2279
  const skill = getSkill(root2, body.key);
2191
2280
  if (skill.managed) throw new HttpError(403, "This skill is managed by the app that installed it");
2192
- fs18.writeFileSync(path18.join(skill.key, "SKILL.md"), String(body.content ?? ""));
2281
+ fs20.writeFileSync(path20.join(skill.key, "SKILL.md"), String(body.content ?? ""));
2193
2282
  return { ok: true, status: null };
2194
2283
  },
2195
2284
  "POST /api/skills/install": (_, body) => {
@@ -2202,7 +2291,7 @@ async function startServer({ root: root2, port, open: openBrowser }) {
2202
2291
  "POST /api/rules/apply": (_, body) => {
2203
2292
  const mainDoc = readConfig(root2)?.mainDoc;
2204
2293
  if (!mainDoc) throw new HttpError(400, "No main document configured; run `markode init`");
2205
- applyRulesToFile(path18.join(root2, mainDoc), body.ids ?? []);
2294
+ applyRulesToFile(path20.join(root2, mainDoc), body.ids ?? []);
2206
2295
  return { ok: true };
2207
2296
  }
2208
2297
  };
@@ -2213,11 +2302,11 @@ async function startServer({ root: root2, port, open: openBrowser }) {
2213
2302
  res.writeHead(403).end("Forbidden");
2214
2303
  return;
2215
2304
  }
2216
- const url2 = new URL(req.url ?? "/", "http://localhost");
2217
- const route = routes[`${req.method} ${url2.pathname}`];
2305
+ const url3 = new URL(req.url ?? "/", "http://localhost");
2306
+ const route = routes[`${req.method} ${url3.pathname}`];
2218
2307
  if (route) {
2219
2308
  try {
2220
- const result = await route(url2, req.method === "GET" || req.method === "DELETE" ? {} : await readBody(req));
2309
+ const result = await route(url3, req.method === "GET" || req.method === "DELETE" ? {} : await readBody(req));
2221
2310
  res.writeHead(200, { "content-type": "application/json" }).end(JSON.stringify(result));
2222
2311
  } catch (err) {
2223
2312
  const status = err instanceof HttpError ? err.status : err.code === "ENOENT" ? 404 : 500;
@@ -2225,8 +2314,9 @@ async function startServer({ root: root2, port, open: openBrowser }) {
2225
2314
  }
2226
2315
  return;
2227
2316
  }
2228
- if (req.method === "GET" && url2.pathname === "/api/asset") return serveAsset(url2.searchParams.get("path") ?? "", res);
2229
- serveStatic(url2.pathname, res);
2317
+ if (req.method === "GET" && url3.pathname === "/api/asset") return serveAsset(url3.searchParams.get("path") ?? "", res);
2318
+ if (req.method === "GET" && url3.pathname === "/open") return openDoc(url3.searchParams.get("path") ?? "", res);
2319
+ serveStatic(url3.pathname, res);
2230
2320
  });
2231
2321
  function serveAsset(rel, res) {
2232
2322
  let file;
@@ -2236,13 +2326,33 @@ async function startServer({ root: root2, port, open: openBrowser }) {
2236
2326
  res.writeHead(404).end();
2237
2327
  return;
2238
2328
  }
2239
- const type = IMAGE_MIME[path18.extname(file).toLowerCase()];
2240
- if (!type || !fs18.existsSync(file) || !fs18.statSync(file).isFile()) {
2329
+ const type = IMAGE_MIME[path20.extname(file).toLowerCase()];
2330
+ if (!type || !fs20.existsSync(file) || !fs20.statSync(file).isFile()) {
2241
2331
  res.writeHead(404).end();
2242
2332
  return;
2243
2333
  }
2244
2334
  res.writeHead(200, { "content-type": type, "cache-control": "no-cache", "content-security-policy": "sandbox; frame-ancestors 'none'" });
2245
- fs18.createReadStream(file).pipe(res);
2335
+ fs20.createReadStream(file).pipe(res);
2336
+ }
2337
+ function openDoc(rel, res) {
2338
+ let doc;
2339
+ try {
2340
+ doc = mdPath(rel);
2341
+ } catch {
2342
+ res.writeHead(400).end("Expected a .md path");
2343
+ return;
2344
+ }
2345
+ const hash2 = `/#/${encodeURI(doc)}`;
2346
+ if (!wss.clients.size) {
2347
+ res.writeHead(302, { location: hash2 }).end();
2348
+ return;
2349
+ }
2350
+ broadcast({ type: "open", path: doc });
2351
+ const text3 = OPENED_TEXT[readSettings().uiLang] ?? OPENED_TEXT.en;
2352
+ const page = `<!doctype html><meta charset="utf-8"><title>markode</title><body style="font:15px system-ui;padding:2rem;color-scheme:light dark">
2353
+ <p>${text3.shown}</p><p><a href="${hash2}">${text3.here}</a></p><script>window.close()</script>`;
2354
+ res.writeHead(200, { "content-type": "text/html; charset=utf-8", "cache-control": "no-store", "content-security-policy": "frame-ancestors 'none'; script-src 'sha256-" + CLOSE_HASH + "'" });
2355
+ res.end(page);
2246
2356
  }
2247
2357
  const actualPort = await listen(server, port);
2248
2358
  const wss = new WebSocketServer({ server, path: "/ws", verifyClient: ({ req }) => isLocalRequest(req) });
@@ -2256,27 +2366,34 @@ async function startServer({ root: root2, port, open: openBrowser }) {
2256
2366
  // Unreadable folders (e.g. caches owned by another user) are skipped instead of failing.
2257
2367
  ignorePermissionErrors: true,
2258
2368
  ignored: (p3, stats) => {
2259
- const rel = toPosix(path18.relative(root2, p3));
2369
+ const rel = toPosix(path20.relative(root2, p3));
2260
2370
  if (rel === ".markode") return false;
2261
2371
  if (rel.startsWith(".markode/")) return !rel.startsWith(".markode/i18n") && rel !== ".markode/state.json" && rel !== ".markode/config.json";
2262
2372
  return skips(rel, stats ? stats.isDirectory() : void 0);
2263
2373
  }
2264
2374
  }).on("error", (err) => console.warn(pc.yellow(` file watcher: ${err.message}`))).on("all", (event, file) => {
2265
- const abs = path18.resolve(file);
2375
+ const abs = path20.resolve(file);
2266
2376
  if (!abs.endsWith(".md") && !abs.endsWith(".json") && !abs.endsWith(".markodeignore") && event !== "addDir" && event !== "unlinkDir") return;
2267
- let rel = toPosix(path18.relative(root2, abs));
2268
- const i18n = toPosix(path18.relative(root2, path18.join(stateDir(root2), "i18n")));
2377
+ let rel = toPosix(path20.relative(root2, abs));
2378
+ const i18n = toPosix(path20.relative(root2, path20.join(stateDir(root2), "i18n")));
2269
2379
  if (rel.startsWith(i18n + "/")) rel = rel.split("/").slice(3).join("/");
2270
2380
  broadcast({ type: "fs", event, path: rel });
2271
2381
  });
2272
- const url = `http://localhost:${actualPort}`;
2382
+ recordServer(root2, actualPort);
2383
+ const url2 = `http://localhost:${actualPort}`;
2273
2384
  console.log(`
2274
- ${pc.bold("markode")} ${pc.dim("\u2192")} ${pc.cyan(url)} ${pc.dim(root2)}
2385
+ ${pc.bold("markode")} ${pc.dim("\u2192")} ${pc.cyan(url2)} ${pc.dim(root2)}
2275
2386
  `);
2276
- if (!fs18.existsSync(WEB_DIR)) console.log(pc.yellow(" Web UI not built: run `pnpm build`, or `pnpm dev` and open http://localhost:4320\n"));
2277
- else if (openBrowser) open(url).catch(() => {
2387
+ if (!fs20.existsSync(WEB_DIR)) console.log(pc.yellow(" Web UI not built: run `pnpm build`, or `pnpm dev` and open http://localhost:4320\n"));
2388
+ else if (openBrowser) open(url2).catch(() => {
2278
2389
  });
2279
2390
  }
2391
+ var OPENED_TEXT = {
2392
+ en: { shown: "Opened in your markode tab. You can close this one.", here: "Open it here instead" },
2393
+ es: { shown: "Abierto en tu pesta\xF1a de markode. Puedes cerrar esta.", here: "Abrirlo aqu\xED" },
2394
+ fr: { shown: "Ouvert dans ton onglet markode. Tu peux fermer celui-ci.", here: "L\u2019ouvrir ici" }
2395
+ };
2396
+ var CLOSE_HASH = crypto3.createHash("sha256").update("window.close()").digest("base64");
2280
2397
  function listen(server, port) {
2281
2398
  return new Promise((resolve, reject) => {
2282
2399
  server.once("error", (err) => {
@@ -2287,19 +2404,19 @@ function listen(server, port) {
2287
2404
  });
2288
2405
  }
2289
2406
  function serveStatic(pathname, res) {
2290
- let file = path18.join(WEB_DIR, path18.normalize(pathname).replace(/^(\.\.[/\\])+/, ""));
2291
- if (!file.startsWith(WEB_DIR) || !fs18.existsSync(file) || fs18.statSync(file).isDirectory()) file = path18.join(WEB_DIR, "index.html");
2292
- if (!fs18.existsSync(file)) {
2407
+ let file = path20.join(WEB_DIR, path20.normalize(pathname).replace(/^(\.\.[/\\])+/, ""));
2408
+ if (!file.startsWith(WEB_DIR) || !fs20.existsSync(file) || fs20.statSync(file).isDirectory()) file = path20.join(WEB_DIR, "index.html");
2409
+ if (!fs20.existsSync(file)) {
2293
2410
  res.writeHead(404).end("Web UI not built. Run `pnpm build`.");
2294
2411
  return;
2295
2412
  }
2296
- res.writeHead(200, { "content-type": MIME[path18.extname(file)] ?? "application/octet-stream", "content-security-policy": "frame-ancestors 'none'" });
2297
- fs18.createReadStream(file).pipe(res);
2413
+ res.writeHead(200, { "content-type": MIME[path20.extname(file)] ?? "application/octet-stream", "content-security-policy": "frame-ancestors 'none'" });
2414
+ fs20.createReadStream(file).pipe(res);
2298
2415
  }
2299
2416
 
2300
2417
  // src/cli/init.ts
2301
- import fs19 from "fs";
2302
- import path19 from "path";
2418
+ import fs21 from "fs";
2419
+ import path21 from "path";
2303
2420
  import * as p from "@clack/prompts";
2304
2421
  import pc2 from "picocolors";
2305
2422
  function check(value) {
@@ -2310,12 +2427,12 @@ function check(value) {
2310
2427
  return value;
2311
2428
  }
2312
2429
  async function offerClaudeLink(root2, d) {
2313
- if (fs19.existsSync(path19.join(root2, "CLAUDE.md"))) return;
2430
+ if (fs21.existsSync(path21.join(root2, "CLAUDE.md"))) return;
2314
2431
  const link2 = d ? d.mainDoc === "CLAUDE.md" : check(await p.confirm({ message: "Claude Code reads CLAUDE.md, not AGENTS.md. Add a CLAUDE.md that imports AGENTS.md?", initialValue: true }));
2315
2432
  if (link2 && linkAgentsDoc(root2)) p.log.success("Created CLAUDE.md (imports AGENTS.md)");
2316
2433
  }
2317
2434
  async function chooseMainDoc(root2, d) {
2318
- const existing = MAIN_DOCS.filter((d2) => fs19.existsSync(path19.join(root2, d2)) && !isPointer(fs19.readFileSync(path19.join(root2, d2), "utf8"), d2));
2435
+ const existing = MAIN_DOCS.filter((d2) => fs21.existsSync(path21.join(root2, d2)) && !isPointer(fs21.readFileSync(path21.join(root2, d2), "utf8"), d2));
2319
2436
  if (d) {
2320
2437
  if (existing.length === 1 && existing[0] === "AGENTS.md") await offerClaudeLink(root2, d);
2321
2438
  if (existing.length) return existing.includes(d.mainDoc) ? d.mainDoc : existing[0];
@@ -2432,7 +2549,7 @@ async function chooseAreas(root2) {
2432
2549
  return areas;
2433
2550
  }
2434
2551
  async function chooseKind(root2, dir) {
2435
- const guess = guessKind(path19.join(root2, dir));
2552
+ const guess = guessKind(path21.join(root2, dir));
2436
2553
  if (!guess.unclear) return guess.kind;
2437
2554
  const where = dir ? `${dir}/` : "this project";
2438
2555
  const seen = guess.signals.length ? `found: ${guess.signals.join(", ")}` : "no code yet";
@@ -2445,7 +2562,7 @@ async function chooseKind(root2, dir) {
2445
2562
  );
2446
2563
  }
2447
2564
  async function askProfile(root2, dir, kind) {
2448
- const base = detectProfile(path19.join(root2, dir), kind);
2565
+ const base = detectProfile(path21.join(root2, dir), kind);
2449
2566
  if (kind === "app") return base;
2450
2567
  const where = dir ? ` (${dir}/)` : "";
2451
2568
  if (kind === "library") return { kind, published: check(await p.confirm({ message: `Is the library${where} published (npm, PyPI\u2026)?`, initialValue: base.published })) };
@@ -2522,7 +2639,7 @@ async function chooseWorkflow(root2, mainDoc, previous, quiet) {
2522
2639
  const profile = areas.length ? void 0 : await askProfile(root2, "", await chooseKind(root2, ""));
2523
2640
  const created = scaffoldMethod(root2, mainDoc, areas);
2524
2641
  installMethodSkills(root2);
2525
- applyWorkflowToFile(path19.join(root2, mainDoc), "markode", methodSection(areas, root2, { profile, contracts, existing }));
2642
+ applyWorkflowToFile(path21.join(root2, mainDoc), "markode", methodSection(areas, root2, { profile, contracts, existing }));
2526
2643
  const big = !areas.length && flattenFiles(scanTree(root2)).length > 40;
2527
2644
  const layout = areas.length ? "structured" : !big ? "general" : check(await p.select({ message: PROPOSALS_QUESTION, options: PROPOSAL_OPTIONS }));
2528
2645
  activateProposals(root2, layout, mainDoc);
@@ -2587,10 +2704,10 @@ async function runInit(root2, plan2) {
2587
2704
  let workflow = previous?.workflow ?? "none";
2588
2705
  if (has2("agent")) {
2589
2706
  mainDoc = await chooseMainDoc(root2, d);
2590
- const mainFile = path19.join(root2, mainDoc);
2707
+ const mainFile = path21.join(root2, mainDoc);
2591
2708
  if (has2("dashboard")) workflow = await chooseWorkflow(root2, mainDoc, previous?.workflow, d);
2592
2709
  if (workflow === "openspec" || workflow === "speckit") applyWorkflowToFile(mainFile, workflow);
2593
- const mainText = fs19.readFileSync(mainFile, "utf8");
2710
+ const mainText = fs21.readFileSync(mainFile, "utf8");
2594
2711
  const sourceLang = d ? SOURCE_LANG_MARK.test(mainText) ? sourceLangOf(mainText) : detectedLang : check(await p.select({ message: SOURCE_LANG_QUESTION, options: LANG_OPTIONS, initialValue: SOURCE_LANG_MARK.test(mainText) ? sourceLangOf(mainText) : detectedLang }));
2595
2712
  const rules = listRules();
2596
2713
  const applied = appliedRuleIds(mainText);
@@ -2605,7 +2722,7 @@ async function runInit(root2, plan2) {
2605
2722
  required: false
2606
2723
  })
2607
2724
  );
2608
- for (const dir of targets) applyRulesToFile(contentDoc(path19.join(root2, dir)), selected, sourceLang);
2725
+ for (const dir of targets) applyRulesToFile(contentDoc(path21.join(root2, dir)), selected, sourceLang);
2609
2726
  }
2610
2727
  installAgentSkill(root2);
2611
2728
  const proposals = proposalsState(root2);
@@ -2752,6 +2869,8 @@ Usage
2752
2869
  markode features list the modules and whether they are on in this project
2753
2870
  markode features <module> on|off turn a module on or off (same as Settings \u2192 Features)
2754
2871
  markode serve open the editor without running init
2872
+ markode url [<doc.md>] the editor's link (or a doc's), starting it in the background if it isn't running
2873
+ markode stop stop the editor running in the background for this project
2755
2874
  markode translate choose languages to review the docs in (or: markode --translate)
2756
2875
  markode check [--json] what /markode sync fixes: answered proposals, phases vs tasks, projects table, broken links
2757
2876
  markode wait <proposal> wait until the user answers a proposal in markode, then print the answer
@@ -2760,6 +2879,8 @@ Usage
2760
2879
  markode changes [--json] what the user edited or commented in markode since the agent was last told
2761
2880
  markode changes --start a new agent session: what happened before is old news
2762
2881
  markode changes --hook <event> the same, as Claude Code hook output (silent when nothing changed)
2882
+ markode update [--check] install the latest version now, without the day npm/pnpm wait for new releases
2883
+ markode update --pnpm|--npm the same, choosing the package manager to install it with
2763
2884
 
2764
2885
  For the agent's /markode translate:
2765
2886
  markode translate --status [--json] translations + files not in the source language
@@ -2785,16 +2906,20 @@ var option = (name) => {
2785
2906
  var command = args[0] && !args[0].startsWith("-") ? args[0] : "start";
2786
2907
  var root = process.env.MARKODE_ROOT ?? process.cwd();
2787
2908
  async function main() {
2788
- if (fs20.existsSync(root)) setProjectRoot(root);
2909
+ if (fs22.existsSync(root)) setProjectRoot(root);
2789
2910
  if (flag("--help") || flag("-h")) return console.log(HELP);
2790
- if (flag("--version") || flag("-v")) return console.log(JSON.parse(fs20.readFileSync(path20.join(PKG_ROOT, "package.json"), "utf8")).version);
2911
+ if (flag("--version") || flag("-v")) return console.log(JSON.parse(fs22.readFileSync(path22.join(PKG_ROOT, "package.json"), "utf8")).version);
2791
2912
  const translation = flag("--status") || flag("--mark") || flag("--keep");
2792
2913
  if ((command === "sync" || command === "translate") && translation) return sync();
2793
2914
  if (command === "translate" || flag("--translate")) return runTranslate(root);
2915
+ if (["check", "url", "link"].includes(command) || command === "changes" && flag("--start")) refreshInstalled(root);
2794
2916
  if (command === "check") return check3();
2795
2917
  if (command === "wait") return wait();
2796
2918
  if (command === "link") return link();
2797
2919
  if (command === "changes") return changes();
2920
+ if (command === "url") return url();
2921
+ if (command === "stop") return stop();
2922
+ if (command === "update") return update();
2798
2923
  if (command === "features") return features();
2799
2924
  if (command === "setup") {
2800
2925
  await runSetup(false, flag("--custom"));
@@ -2880,6 +3005,36 @@ function link() {
2880
3005
  if (flag("--dry-run")) return console.log(missing.map((m) => `would create ${m.path} \u2192 ${m.pointsTo}`).join("\n"));
2881
3006
  for (const p3 of linkMainDocs(root)) console.log(`created ${p3}`);
2882
3007
  }
3008
+ async function url() {
3009
+ const doc = args[1] && !args[1].startsWith("-") ? args[1] : void 0;
3010
+ if (doc && (!doc.toLowerCase().endsWith(".md") || !fs22.existsSync(path22.join(root, doc)))) {
3011
+ console.error(`Usage: markode url [<doc.md>] (relative to ${root})`);
3012
+ process.exitCode = 1;
3013
+ return;
3014
+ }
3015
+ const { port } = await ensureServer(root, process.argv[1], Number(option("--port") ?? 4319));
3016
+ console.log(editorUrl(port, doc));
3017
+ }
3018
+ function stop() {
3019
+ const running = runningServer(root);
3020
+ if (!running) return console.log("The editor is not running for this project.");
3021
+ process.kill(running.pid);
3022
+ console.log(`Stopped the editor on port ${running.port}.`);
3023
+ }
3024
+ async function update() {
3025
+ const latest = await latestVersion();
3026
+ if (!isNewer(latest, CURRENT_VERSION)) return console.log(`markode ${CURRENT_VERSION} is the latest version.`);
3027
+ console.log(`markode ${latest} is out (you have ${CURRENT_VERSION}).`);
3028
+ if (flag("--check")) return;
3029
+ const via = flag("--pnpm") ? "pnpm" : flag("--npm") ? "npm" : installer();
3030
+ if (via === "npx") return console.log(`Running through npx: use \`npx -y @rafiqui987/markode@${latest}\` once to fetch it, or install it with \`markode update --pnpm\` (or --npm).`);
3031
+ if (!via) return console.log("This copy runs from a clone of the repository: pull and build it, or install it with `markode update --pnpm` (or --npm).");
3032
+ const cmd = installCommand2(via, latest);
3033
+ console.log(`$ ${cmd.join(" ")}`);
3034
+ if (runInstall(cmd)) return console.log(`Updated to ${latest}. A running editor keeps the old version until \`markode stop\`.`);
3035
+ console.error("The install failed; the output above says why.");
3036
+ process.exitCode = 1;
3037
+ }
2883
3038
  function changes() {
2884
3039
  if (flag("--start")) return startSession(root);
2885
3040
  const list = takeChanges(root);
@@ -2894,7 +3049,7 @@ function changes() {
2894
3049
  }
2895
3050
  async function wait() {
2896
3051
  const rel = args[1];
2897
- if (!rel || !fs20.existsSync(path20.join(root, rel))) {
3052
+ if (!rel || !fs22.existsSync(path22.join(root, rel))) {
2898
3053
  console.error(`Usage: markode wait <proposal.md> (relative to ${root})`);
2899
3054
  process.exitCode = 1;
2900
3055
  return;
@@ -1 +1 @@
1
- import{m as e,t}from"./mermaid-parser.core-ByEdgqAb.js";import{n}from"./chunk-Y2CYZVJY-DsF7k-Jl.js";import{m as r}from"./src-DgNmQVK4.js";import"./chunk-DSNLSHJZ-BNEo5raG.js";import{n as i,r as a,t as o}from"./chunk-2E7WHVMD-w-cvaztJ.js";import{t as s}from"./chunk-JWPE2WC7-DVXcaiue.js";import"./mermaid.core-CXUI3iYT.js";var c=e().RailroadAbnf.parser.LangiumParser,l=n(e=>{let t=e.alternatives.map(u);return t.length===1?t[0]:{type:`choice`,alternatives:t}},`transformAlternation`),u=n(e=>{let t=e.elements.map(f);return t.length===1?t[0]:{type:`sequence`,elements:t}},`transformConcatenation`),d=n(e=>{if(e.includes(`*`)){let[t,n]=e.split(`*`);return{min:t?parseInt(t,10):0,max:n?parseInt(n,10):1/0}}let t=parseInt(e,10);return{min:t,max:t}},`parseRepeat`),f=n(e=>{let t=p(e.primary);if(!e.repeat)return t;let{min:n,max:r}=d(e.repeat);return n===0&&r===1?{type:`optional`,element:t}:{type:`repetition`,element:t,min:n,max:r}},`transformElement`),p=n(e=>{switch(e.$type){case`AbnfStringLiteral`:return{type:`terminal`,value:e.value};case`AbnfNumVal`:return{type:`terminal`,value:e.value};case`AbnfRuleName`:return{type:`nonterminal`,name:e.name};case`AbnfGroup`:return l(e.element);case`AbnfOptionalGroup`:return{type:`optional`,element:l(e.element)};default:throw Error(`Unsupported ABNF primary node: ${e.$type}`)}},`transformPrimary`),m=n(e=>({name:e.name,definition:l(e.definition)}),`transformRule`),h=n(e=>{s(e,o),e.title&&o.setTitle(e.title),e.rules.map(e=>o.addRule(m(e)))},`populateDb`),g={parser:{parse:n(e=>{o.clear(),r.debug(`[ABNF Parser] Starting Langium parse`);let n=c.parse(e);if(n.lexerErrors.length>0||n.parserErrors.length>0)throw new t(n);let i=n.value;r.debug(`[ABNF Parser] Parsed rules:`,i.rules.length),h(i),r.debug(`[ABNF Parser] Parse complete`)},`parse`),parser:{yy:o}},db:o,renderer:a,styles:i};export{g as diagram};
1
+ import{m as e,t}from"./mermaid-parser.core-C1XIxySl.js";import{n}from"./chunk-Y2CYZVJY-DsF7k-Jl.js";import{m as r}from"./src-okGi814h.js";import"./chunk-DSNLSHJZ-C0Wri32R.js";import{n as i,r as a,t as o}from"./chunk-2E7WHVMD-B2TT-9T2.js";import{t as s}from"./chunk-JWPE2WC7-DVXcaiue.js";import"./mermaid.core-C-385ykR.js";var c=e().RailroadAbnf.parser.LangiumParser,l=n(e=>{let t=e.alternatives.map(u);return t.length===1?t[0]:{type:`choice`,alternatives:t}},`transformAlternation`),u=n(e=>{let t=e.elements.map(f);return t.length===1?t[0]:{type:`sequence`,elements:t}},`transformConcatenation`),d=n(e=>{if(e.includes(`*`)){let[t,n]=e.split(`*`);return{min:t?parseInt(t,10):0,max:n?parseInt(n,10):1/0}}let t=parseInt(e,10);return{min:t,max:t}},`parseRepeat`),f=n(e=>{let t=p(e.primary);if(!e.repeat)return t;let{min:n,max:r}=d(e.repeat);return n===0&&r===1?{type:`optional`,element:t}:{type:`repetition`,element:t,min:n,max:r}},`transformElement`),p=n(e=>{switch(e.$type){case`AbnfStringLiteral`:return{type:`terminal`,value:e.value};case`AbnfNumVal`:return{type:`terminal`,value:e.value};case`AbnfRuleName`:return{type:`nonterminal`,name:e.name};case`AbnfGroup`:return l(e.element);case`AbnfOptionalGroup`:return{type:`optional`,element:l(e.element)};default:throw Error(`Unsupported ABNF primary node: ${e.$type}`)}},`transformPrimary`),m=n(e=>({name:e.name,definition:l(e.definition)}),`transformRule`),h=n(e=>{s(e,o),e.title&&o.setTitle(e.title),e.rules.map(e=>o.addRule(m(e)))},`populateDb`),g={parser:{parse:n(e=>{o.clear(),r.debug(`[ABNF Parser] Starting Langium parse`);let n=c.parse(e);if(n.lexerErrors.length>0||n.parserErrors.length>0)throw new t(n);let i=n.value;r.debug(`[ABNF Parser] Parsed rules:`,i.rules.length),h(i),r.debug(`[ABNF Parser] Parse complete`)},`parse`),parser:{yy:o}},db:o,renderer:a,styles:i};export{g as diagram};