@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.
- package/README.md +16 -1
- package/dist/cli.js +243 -88
- package/dist/web/assets/{abnfDiagram-WEYOIA3C-C-xz1zhH.js → abnfDiagram-WEYOIA3C-B-3Lcktj.js} +1 -1
- package/dist/web/assets/{arc-0NKn9s7n.js → arc-B1vQQwbr.js} +1 -1
- package/dist/web/assets/{architecture-WOLXFQ4H-yvNPw04L.js → architecture-WOLXFQ4H-D8_qhlNG.js} +1 -1
- package/dist/web/assets/{architectureDiagram-ZHVYKT53-DiNkPsUS.js → architectureDiagram-ZHVYKT53-B4uGFnQg.js} +1 -1
- package/dist/web/assets/{blockDiagram-RJAE7QA3-Bm5an-ZR.js → blockDiagram-RJAE7QA3-B1PRI2Fk.js} +1 -1
- package/dist/web/assets/{c4Diagram-XDPPPE54-DCIkW1i3.js → c4Diagram-XDPPPE54-BOSiNgn_.js} +1 -1
- package/dist/web/assets/channel-ggr2Mduz.js +1 -0
- package/dist/web/assets/{chunk-2E7WHVMD-w-cvaztJ.js → chunk-2E7WHVMD-B2TT-9T2.js} +1 -1
- package/dist/web/assets/{chunk-4EMNKR2T-Dz1c4ddf.js → chunk-4EMNKR2T-BJStHb31.js} +1 -1
- package/dist/web/assets/{chunk-55XCU76K-BkW2QTCZ.js → chunk-55XCU76K-CGSdzfU6.js} +1 -1
- package/dist/web/assets/{chunk-7S6XSTFO-SqLAsU6N.js → chunk-7S6XSTFO-D7U3aXUK.js} +1 -1
- package/dist/web/assets/{chunk-AQDTSKZB-DwIPdMmQ.js → chunk-AQDTSKZB-C6fkREWV.js} +1 -1
- package/dist/web/assets/{chunk-DSNLSHJZ-BNEo5raG.js → chunk-DSNLSHJZ-C0Wri32R.js} +1 -1
- package/dist/web/assets/{chunk-HAGFOTED-BokAjJjC.js → chunk-HAGFOTED-dS3yjqSY.js} +1 -1
- package/dist/web/assets/{chunk-HNE4Q36P-BlJCzrNG.js → chunk-HNE4Q36P-B0HJeFYe.js} +1 -1
- package/dist/web/assets/{chunk-NQOKRVIF-CK1D9VKN.js → chunk-NQOKRVIF-DCR-ZD6p.js} +1 -1
- package/dist/web/assets/{chunk-UHW7PFBP-ycMkWOji.js → chunk-UHW7PFBP-DvXVrsgg.js} +1 -1
- package/dist/web/assets/{chunk-VQ5W62QI-CNI8j3BI.js → chunk-VQ5W62QI-mU_IBCXT.js} +1 -1
- package/dist/web/assets/{chunk-WQQL4CDK-DvQQgYrd.js → chunk-WQQL4CDK-DnyUQt3W.js} +1 -1
- package/dist/web/assets/{chunk-XXDRQBXY-cFqAbOh1.js → chunk-XXDRQBXY-DNhISORq.js} +1 -1
- package/dist/web/assets/{chunk-YZO67HFG-CkfGL1zX.js → chunk-YZO67HFG-C_oEIdWe.js} +1 -1
- package/dist/web/assets/{chunk-ZAUX2LTX-BwdZydyj.js → chunk-ZAUX2LTX-D5aMvPiJ.js} +1 -1
- package/dist/web/assets/{chunk-ZCHMQSOR-CXDXBIC6.js → chunk-ZCHMQSOR-B5J6sRpu.js} +1 -1
- package/dist/web/assets/{classDiagram-v2-4MYWR3UA-B95ypqg8.js → classDiagram-v2-4MYWR3UA-D4-o3iga.js} +1 -1
- package/dist/web/assets/{cose-bilkent-JH36ORCC-C8-ToTGn.js → cose-bilkent-JH36ORCC-CqNUB7G6.js} +1 -1
- package/dist/web/assets/{cynefin-EF2NZ3EQ-CHth0Nt9.js → cynefin-EF2NZ3EQ-BLBtXLl2.js} +1 -1
- package/dist/web/assets/{cynefinDiagram-WF24UDRP-CMcwwxC8.js → cynefinDiagram-WF24UDRP-BlytpdKL.js} +1 -1
- package/dist/web/assets/{dagre-NK4GIZVX-BZzAgRpg.js → dagre-NK4GIZVX-DIUkOqo_.js} +1 -1
- package/dist/web/assets/{diagram-CBK3MWTC-DGwxJbVy.js → diagram-CBK3MWTC-4WJqLswq.js} +1 -1
- package/dist/web/assets/{diagram-I5XIIV2D-B17CYdAP.js → diagram-I5XIIV2D-s1EUO6xt.js} +1 -1
- package/dist/web/assets/{diagram-ODIL2UCW-CYPFYS2M.js → diagram-ODIL2UCW-GvgDR4t8.js} +1 -1
- package/dist/web/assets/{diagram-PFBEJUXE-BQMumROl.js → diagram-PFBEJUXE-B6J9SedW.js} +1 -1
- package/dist/web/assets/{diagram-RJA3I4VV-vHTuDO1-.js → diagram-RJA3I4VV-CqA7qcNf.js} +1 -1
- package/dist/web/assets/{diagram-TYUNFSNR-C_WYz7qL.js → diagram-TYUNFSNR-Cln9POlx.js} +1 -1
- package/dist/web/assets/{dist-DFcDEdTm.js → dist--fImHE6g.js} +1 -1
- package/dist/web/assets/{dist-BOCA4kQq.js → dist-Bg-QtHy9.js} +1 -1
- package/dist/web/assets/{dist-cSM0Lli0.js → dist-BghTt_37.js} +1 -1
- package/dist/web/assets/{dist-PwT2nxki.js → dist-CU6eXj3N.js} +1 -1
- package/dist/web/assets/{dist-B1oQ1VTT.js → dist-CVF0b6Yz.js} +1 -1
- package/dist/web/assets/{dist-B5uXb_Wi.js → dist-Cd1DR3ly.js} +1 -1
- package/dist/web/assets/{dist-8k6FSdRu.js → dist-CoioyMmF.js} +1 -1
- package/dist/web/assets/{dist-DV0HO3Fe.js → dist-CykDxBaO.js} +1 -1
- package/dist/web/assets/{dist-QI7QavRs.js → dist-DpqggjJG.js} +1 -1
- package/dist/web/assets/{dist-DZQ_bwip.js → dist-YudOLIZ5.js} +1 -1
- package/dist/web/assets/{dist-BT3nK1GA.js → dist-xGXJDvke.js} +1 -1
- package/dist/web/assets/{ebnfDiagram-V4P3TTPT-DLMwyX-U.js → ebnfDiagram-V4P3TTPT-BusXM5tX.js} +1 -1
- package/dist/web/assets/{elk-QONTBCTQ-DVvxbtF4.js → elk-QONTBCTQ-B9oq7Tkq.js} +1 -1
- package/dist/web/assets/{erDiagram-KYQIGQAA-DPXicJ1t.js → erDiagram-KYQIGQAA-CmL9SAnh.js} +1 -1
- package/dist/web/assets/{eventmodeling-K75KTNOO-DpHVZP_6.js → eventmodeling-K75KTNOO-R6NmozzN.js} +1 -1
- package/dist/web/assets/flowDiagram-IUGLLWBU-CkUCRx3C.js +1 -0
- package/dist/web/assets/{ganttDiagram-R7GPNTJY-Ch6NDX5Q.js → ganttDiagram-R7GPNTJY-DRa2V_Qe.js} +1 -1
- package/dist/web/assets/{gitGraph-VSP46ZUC-CIhLB663.js → gitGraph-VSP46ZUC-CdFMO2LD.js} +1 -1
- package/dist/web/assets/{gitGraphDiagram-PDYL7XHY-Ci_MIbqs.js → gitGraphDiagram-PDYL7XHY-C-xmUbl1.js} +1 -1
- package/dist/web/assets/{index-CxwfaWVo.js → index-BFpTDsCp.js} +4 -4
- package/dist/web/assets/{info-OHQRW6UA-Dau8xD88.js → info-OHQRW6UA-CnPUMAqS.js} +1 -1
- package/dist/web/assets/{infoDiagram-MVDRKAX5-4spgggd7.js → infoDiagram-MVDRKAX5-DxouwrN7.js} +1 -1
- package/dist/web/assets/{ishikawaDiagram-HPEHV2GE-DgFczAdB.js → ishikawaDiagram-HPEHV2GE-qrLpOq3_.js} +1 -1
- package/dist/web/assets/{journeyDiagram-BOSHW7O7-CJKwCuyG.js → journeyDiagram-BOSHW7O7-BDTfHWHd.js} +1 -1
- package/dist/web/assets/{kanban-definition-FNSA4HC5-B_HPa_Q8.js → kanban-definition-FNSA4HC5-CTBgSpp6.js} +1 -1
- package/dist/web/assets/{line-Bil8yI0B.js → line-D8R5RRtF.js} +1 -1
- package/dist/web/assets/{linear-DJSxHb3I.js → linear-BCL193tG.js} +1 -1
- package/dist/web/assets/{mermaid-parser.core-ByEdgqAb.js → mermaid-parser.core-C1XIxySl.js} +3 -3
- package/dist/web/assets/{mermaid.core-CXUI3iYT.js → mermaid.core-C-385ykR.js} +4 -4
- package/dist/web/assets/{mindmap-definition-6OY57UG3-w7xG6UiS.js → mindmap-definition-6OY57UG3-BnCvQFLY.js} +1 -1
- package/dist/web/assets/{packet-JDAUHWVQ-YvTb_dXP.js → packet-JDAUHWVQ-DVCRx-wc.js} +1 -1
- package/dist/web/assets/{pegDiagram-ECIUJNBX-D5FI1bVJ.js → pegDiagram-ECIUJNBX-CIDVz_ln.js} +1 -1
- package/dist/web/assets/{pie-XZMESJXO-BH2bih-K.js → pie-XZMESJXO-BHXvmR-y.js} +1 -1
- package/dist/web/assets/{pieDiagram-GNMPY74T-DUR82NlG.js → pieDiagram-GNMPY74T-Bb_l0cKd.js} +1 -1
- package/dist/web/assets/{quadrantDiagram-D57K4MC3-DauAEIyL.js → quadrantDiagram-D57K4MC3-Dqq4AGQt.js} +1 -1
- package/dist/web/assets/{radar-ABXABTNO-CdUXfEdf.js → radar-ABXABTNO-Ba5vnnQ7.js} +1 -1
- package/dist/web/assets/{railroad-I3PHUGI6-Djt90nhE.js → railroad-I3PHUGI6-CxoMtJ5h.js} +1 -1
- package/dist/web/assets/{railroad-abnf-LNEFI6M7-XqY0pGCO.js → railroad-abnf-LNEFI6M7-BXxErwiU.js} +1 -1
- package/dist/web/assets/{railroad-ebnf-DWYD2UWJ-BNSOgId4.js → railroad-ebnf-DWYD2UWJ-C_9H5arK.js} +1 -1
- package/dist/web/assets/{railroad-peg-JR7BVNR7-DW2TRqOr.js → railroad-peg-JR7BVNR7-50KHJESB.js} +1 -1
- package/dist/web/assets/{railroadDiagram-Y72NRBL7-CTDNRHBf.js → railroadDiagram-Y72NRBL7-9w1amWMc.js} +1 -1
- package/dist/web/assets/{requirementDiagram-EQYSW5RA-DJ5H8uqE.js → requirementDiagram-EQYSW5RA-D3XygoSz.js} +1 -1
- package/dist/web/assets/{sankeyDiagram-SY24JHO5-Xa_3Bd4U.js → sankeyDiagram-SY24JHO5-C68crPY9.js} +1 -1
- package/dist/web/assets/{sequenceDiagram-BLEHNHQU-2jNpfI3_.js → sequenceDiagram-BLEHNHQU-BNcJ1wfc.js} +1 -1
- package/dist/web/assets/{src-DgNmQVK4.js → src-okGi814h.js} +1 -1
- package/dist/web/assets/{stateDiagram-v2-A6IESKWZ-DtxzihUG.js → stateDiagram-v2-A6IESKWZ-DX7rAO1j.js} +1 -1
- package/dist/web/assets/{swimlanes-B3ENRKFQ-DJBCOj2u.js → swimlanes-B3ENRKFQ-DGSmz_ab.js} +1 -1
- package/dist/web/assets/swimlanesDiagram-AYQRV4AK-D8bRrq1P.js +8 -0
- package/dist/web/assets/{timeline-definition-JXYKGLGB-C-ixUm6b.js → timeline-definition-JXYKGLGB-5COU2ouX.js} +1 -1
- package/dist/web/assets/{treeView-D4JQ5SDB-yWRFH4mR.js → treeView-D4JQ5SDB-BgrtWP9w.js} +1 -1
- package/dist/web/assets/{treemap-SAJKECNS-q3FZ9UjJ.js → treemap-SAJKECNS-CLZcktWl.js} +1 -1
- package/dist/web/assets/{usecaseDiagram-WPOLBNNX-Ch9QG7L1.js → usecaseDiagram-WPOLBNNX-BbJ7QjYR.js} +1 -1
- package/dist/web/assets/{vennDiagram-Q3Y3IDCW-85m0XMhF.js → vennDiagram-Q3Y3IDCW-IhZTghFG.js} +1 -1
- package/dist/web/assets/{wardley-7MLQ67FV-S2NRiIdM.js → wardley-7MLQ67FV-XjDz9vxn.js} +1 -1
- package/dist/web/assets/{wardleyDiagram-IVAIDKWA-q8ZLrvVG.js → wardleyDiagram-IVAIDKWA-DTcLR0T-.js} +1 -1
- package/dist/web/assets/{xychartDiagram-4URNHDU4-eSUy1iT7.js → xychartDiagram-4URNHDU4-Dja-ugvw.js} +1 -1
- package/dist/web/index.html +1 -1
- package/package.json +1 -1
- package/templates/proposals/SKILL.md +2 -1
- package/templates/skill/SKILL.md +18 -1
- package/dist/web/assets/channel-BkrEjK89.js +0 -1
- package/dist/web/assets/flowDiagram-IUGLLWBU-DrcHkm4d.js +0 -1
- 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
|
|
5
|
-
import
|
|
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/
|
|
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) =>
|
|
1840
|
-
var pidFile = (root2, rel) =>
|
|
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
|
|
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 =
|
|
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(
|
|
1864
|
-
return
|
|
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 =
|
|
1869
|
-
|
|
1956
|
+
const abs = path19.join(root2, rel);
|
|
1957
|
+
fs19.mkdirSync(waitsDir(root2), { recursive: true });
|
|
1870
1958
|
assertInside(pidFile(root2, rel));
|
|
1871
|
-
|
|
1872
|
-
const cleanup = () =>
|
|
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 =
|
|
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 =
|
|
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
|
|
2055
|
+
import crypto3 from "crypto";
|
|
2056
|
+
import fs20 from "fs";
|
|
1968
2057
|
import http from "http";
|
|
1969
|
-
import
|
|
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 (!
|
|
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:
|
|
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(
|
|
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": (
|
|
2098
|
-
const l = viewLang(
|
|
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": (
|
|
2105
|
-
const rel = mdPath(
|
|
2106
|
-
const l = viewLang(
|
|
2107
|
-
const source =
|
|
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 (
|
|
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
|
-
|
|
2208
|
+
fs20.mkdirSync(path20.dirname(file), { recursive: true });
|
|
2120
2209
|
const content = String(body.content ?? "");
|
|
2121
|
-
if (!l && featureState(root2).agent) logSave(root2, rel,
|
|
2122
|
-
|
|
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 (
|
|
2129
|
-
|
|
2130
|
-
const title =
|
|
2131
|
-
|
|
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 (
|
|
2142
|
-
|
|
2143
|
-
return { ok: true, path: toPosix(
|
|
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": (
|
|
2146
|
-
const abs = deletable(
|
|
2147
|
-
if (!
|
|
2148
|
-
const files =
|
|
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": (
|
|
2152
|
-
const rel = toPosix(
|
|
2153
|
-
|
|
2154
|
-
for (const l of config().langs)
|
|
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": (
|
|
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 &&
|
|
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": (
|
|
2176
|
-
deleteRule(
|
|
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": (
|
|
2186
|
-
const skill = getSkill(root2,
|
|
2187
|
-
return { path: skill.key, content:
|
|
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
|
-
|
|
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(
|
|
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
|
|
2217
|
-
const route = routes[`${req.method} ${
|
|
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(
|
|
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" &&
|
|
2229
|
-
|
|
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[
|
|
2240
|
-
if (!type || !
|
|
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
|
-
|
|
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(
|
|
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 =
|
|
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(
|
|
2268
|
-
const i18n = toPosix(
|
|
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
|
-
|
|
2382
|
+
recordServer(root2, actualPort);
|
|
2383
|
+
const url2 = `http://localhost:${actualPort}`;
|
|
2273
2384
|
console.log(`
|
|
2274
|
-
${pc.bold("markode")} ${pc.dim("\u2192")} ${pc.cyan(
|
|
2385
|
+
${pc.bold("markode")} ${pc.dim("\u2192")} ${pc.cyan(url2)} ${pc.dim(root2)}
|
|
2275
2386
|
`);
|
|
2276
|
-
if (!
|
|
2277
|
-
else if (openBrowser) open(
|
|
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 =
|
|
2291
|
-
if (!file.startsWith(WEB_DIR) || !
|
|
2292
|
-
if (!
|
|
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[
|
|
2297
|
-
|
|
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
|
|
2302
|
-
import
|
|
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 (
|
|
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) =>
|
|
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(
|
|
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(
|
|
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(
|
|
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 =
|
|
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 =
|
|
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(
|
|
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 (
|
|
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(
|
|
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 || !
|
|
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;
|
package/dist/web/assets/{abnfDiagram-WEYOIA3C-C-xz1zhH.js → abnfDiagram-WEYOIA3C-B-3Lcktj.js}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{m as e,t}from"./mermaid-parser.core-
|
|
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};
|