kennel 0.2.44 → 0.2.45
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/core/api-client.d.ts +1 -1
- package/dist/core/api-client.js +35 -2
- package/dist/core/runtime.js +548 -99
- package/dist/llm/worker.js +11 -2
- package/dist/notes/command.js +20 -4
- package/dist/package/preview.d.ts +1 -1
- package/dist/package/preview.js +760 -495
- package/dist/site/hot-viewer.js +4 -4
- package/dist/site/server-plugins.js +468 -30
- package/dist/site/viewer.d.ts +0 -3
- package/dist/site/viewer.js +11 -41
- package/dist/tui/launcher.d.ts +11 -0
- package/dist/{site/terminal.js → tui/launcher.js} +60 -15
- package/package.json +2 -2
- package/web/assets/{abnfDiagram-VRR7QNED-ooA_TyhC.js → abnfDiagram-VRR7QNED-D8mHNUwf.js} +1 -1
- package/web/assets/{arc-DqQkY48J.js → arc-DORR-Lbn.js} +1 -1
- package/web/assets/{architectureDiagram-ZJ3FMSHR-DaXzRGP0.js → architectureDiagram-ZJ3FMSHR-CnmL2DAX.js} +1 -1
- package/web/assets/ask-tray-KUTWZ4MV-VQJJAsDn.js +1 -0
- package/web/assets/{blockDiagram-677ZJIJ3-Br5Y_dbP.js → blockDiagram-677ZJIJ3-_SWUT5nP.js} +1 -1
- package/web/assets/{c4Diagram-LMCZKHZV-CWIy0S0N.js → c4Diagram-LMCZKHZV-r7ghc180.js} +1 -1
- package/web/assets/channel-r9-1szjb.js +1 -0
- package/web/assets/{chunk-2Q5K7J3B-8dxcuNwr.js → chunk-2Q5K7J3B-D_LeMwFJ.js} +1 -1
- package/web/assets/{chunk-32BRIVSS-DB27hz0Y.js → chunk-32BRIVSS-AeVZw1It.js} +1 -1
- package/web/assets/{chunk-5VM5RSS4-CTNxGtbA.js → chunk-5VM5RSS4-Bp_epQ8r.js} +1 -1
- package/web/assets/{chunk-EX3LRPZG-oKNLktOC.js → chunk-EX3LRPZG-Dz4n-DeM.js} +1 -1
- package/web/assets/{chunk-JWPE2WC7-DeQNmWoS.js → chunk-JWPE2WC7-B0MQp8TQ.js} +1 -1
- package/web/assets/{chunk-MOJQB5TN-BrW33Mrb.js → chunk-MOJQB5TN-Bkomqk1x.js} +1 -1
- package/web/assets/{chunk-RYQCIY6F-DEkTU6j-.js → chunk-RYQCIY6F-B0F7WMyE.js} +1 -1
- package/web/assets/{chunk-V7JOEXUC-BuDLgwdB.js → chunk-V7JOEXUC-BDifU9oY.js} +1 -1
- package/web/assets/{chunk-VR4S4FIN-BsNgrrKe.js → chunk-VR4S4FIN-Bgd4HCG_.js} +1 -1
- package/web/assets/{chunk-XXDRQBXY-DjT1Bydl.js → chunk-XXDRQBXY-BK8FhRs4.js} +1 -1
- package/web/assets/classDiagram-OUVF2IWQ-L_jmDmNd.js +1 -0
- package/web/assets/classDiagram-v2-EOCWNBFH-L_jmDmNd.js +1 -0
- package/web/assets/client-5Q4VI7ZT-BkTtFalV.js +52 -0
- package/web/assets/{cose-bilkent-JH36ORCC-BtAklxrd.js → cose-bilkent-JH36ORCC-Dm3k2U47.js} +1 -1
- package/web/assets/{cynefin-VYW2F7L2-DabtZWZy.js → cynefin-VYW2F7L2-DCnilF1f.js} +1 -1
- package/web/assets/{cynefinDiagram-TSTJHNR4-DVk8uQ8L.js → cynefinDiagram-TSTJHNR4-BrulEEQ9.js} +1 -1
- package/web/assets/{dagre-VKFMJZFB-CiAbBCor.js → dagre-VKFMJZFB-Dda61i4h.js} +1 -1
- package/web/assets/{diagram-FQU43EPY-DWp-OzJz.js → diagram-FQU43EPY-sTmDEDMM.js} +1 -1
- package/web/assets/{diagram-G47NLZAW-YDllS_1P.js → diagram-G47NLZAW-d-KQnPrm.js} +1 -1
- package/web/assets/{diagram-NH7WQ7WH-BH3l4yRj.js → diagram-NH7WQ7WH-DcRxa_ps.js} +1 -1
- package/web/assets/{diagram-OA4YK3LP-CszBvxdr.js → diagram-OA4YK3LP-CYzWtWvV.js} +1 -1
- package/web/assets/{diagram-WEI45ONY-bEhZeER6.js → diagram-WEI45ONY-FI3V_N07.js} +1 -1
- package/web/assets/document-view-TGFRNHKS-VSJS3BGw.js +24 -0
- package/web/assets/{ebnfDiagram-CCIWWBDH-DlpoUUO5.js → ebnfDiagram-CCIWWBDH-DcvVmQhu.js} +1 -1
- package/web/assets/{entity-search-page-YP4SPMBC-WryWZNPk.js → entity-search-page-RIYQYIJJ-Bed3y-5Q.js} +5 -5
- package/web/assets/{erDiagram-Q63AITRT-DROgehIM.js → erDiagram-Q63AITRT-DI5DBlBp.js} +1 -1
- package/web/assets/{flowDiagram-23GEKE2U-63pYiBzl.js → flowDiagram-23GEKE2U-Bz1AbRxB.js} +1 -1
- package/web/assets/{ganttDiagram-NO4QXBWP-tc34wKHJ.js → ganttDiagram-NO4QXBWP-ChKlhxeo.js} +1 -1
- package/web/assets/{gitGraphDiagram-IHSO6WYX-GOjqt583.js → gitGraphDiagram-IHSO6WYX-BtTqLSyY.js} +1 -1
- package/web/assets/{index-qmu99cjp.js → index-CDAH4UPU.js} +157 -157
- package/web/assets/{infoDiagram-FWYZ7A6U-CD5BwkLQ.js → infoDiagram-FWYZ7A6U-COpIz9uZ.js} +1 -1
- package/web/assets/{ishikawaDiagram-FXEZZL3T-yIweY6wR.js → ishikawaDiagram-FXEZZL3T-CB7Bdsfr.js} +1 -1
- package/web/assets/{journeyDiagram-5HDEW3XC-D3MeUGvn.js → journeyDiagram-5HDEW3XC-BMytnJBE.js} +1 -1
- package/web/assets/{kanban-definition-HUTT4EX6-CnZ5N79y.js → kanban-definition-HUTT4EX6-BFS4G0g-.js} +1 -1
- package/web/assets/{linear-s5G6iOMz.js → linear-DMUO2qBp.js} +1 -1
- package/web/assets/{linked-session-header-DOEX4FYM-CtTOXcZn.js → linked-session-header-7BUTWROP-DzEcA4Fq.js} +1 -1
- package/web/assets/{mermaid.core-BpUKp9r_.js → mermaid.core-BAj-Ltr-.js} +4 -4
- package/web/assets/{mindmap-definition-LN4V7U3C-Bp2QH5sN.js → mindmap-definition-LN4V7U3C-CjymOEvH.js} +1 -1
- package/web/assets/{pegDiagram-2B236MQR-lx1jDUmt.js → pegDiagram-2B236MQR-D64jiUPu.js} +1 -1
- package/web/assets/{pieDiagram-ENE6RG2P--kf2YNbw.js → pieDiagram-ENE6RG2P-CCbI5U6o.js} +1 -1
- package/web/assets/{plugin-host-modules-BKbxlu7U.js → plugin-host-modules-D7pHtNJn.js} +2 -2
- package/web/assets/{project-search-page-TZG7AZBQ-3W40ayYn.js → project-search-page-O6YRLDGU-1bPrifgb.js} +2 -2
- package/web/assets/{quadrantDiagram-ABIIQ3AL-Vr7zWQYV.js → quadrantDiagram-ABIIQ3AL-B7dN_Kn5.js} +1 -1
- package/web/assets/{railroadDiagram-RFXS5EU6-CqWD8KUC.js → railroadDiagram-RFXS5EU6-BPjAzqcL.js} +1 -1
- package/web/assets/{requirementDiagram-TGXJPOKE-BHUBdOVh.js → requirementDiagram-TGXJPOKE-BFhnnUWa.js} +1 -1
- package/web/assets/{sankeyDiagram-HTMAVEWB-Cw_ZddWI.js → sankeyDiagram-HTMAVEWB-W2UguUjW.js} +1 -1
- package/web/assets/{selection-popup-ABYH3A27-Gc-RFSWj.js → selection-popup-ABYH3A27-DsiLbG7S.js} +4 -4
- package/web/assets/{sequenceDiagram-DBY2YBRQ-CyCbkAfM.js → sequenceDiagram-DBY2YBRQ-DcOakOD4.js} +1 -1
- package/web/assets/{sizeCapture-X5ZJPWSS-BG6RM8rb.js → sizeCapture-X5ZJPWSS-D3N248Z6.js} +1 -1
- package/web/assets/{stateDiagram-2N3HPSRC-DKpZl5UU.js → stateDiagram-2N3HPSRC-Cir3yiDe.js} +1 -1
- package/web/assets/{stateDiagram-v2-6OUMAXLB-DHUy-0iS.js → stateDiagram-v2-6OUMAXLB-BwL0KYLn.js} +1 -1
- package/web/assets/{swimlanes-5IMT3BWC-D14uyHMH.js → swimlanes-5IMT3BWC-Dhq7FmZr.js} +2 -2
- package/web/assets/swimlanesDiagram-G3AALYLV-D4q-nPpB.js +8 -0
- package/web/assets/{timeline-definition-FHXFAJF6-f4WPhEXS.js → timeline-definition-FHXFAJF6-CMa1wjsI.js} +1 -1
- package/web/assets/{vennDiagram-L72KCM5P-lr4A8guw.js → vennDiagram-L72KCM5P-DvglazwQ.js} +1 -1
- package/web/assets/{wardleyDiagram-EHGQE667-CR-Im585.js → wardleyDiagram-EHGQE667-DcogrL32.js} +1 -1
- package/web/assets/{xychartDiagram-FW5EYKEG-DeNQfP7k.js → xychartDiagram-FW5EYKEG-BlsDcr_U.js} +1 -1
- package/web/index.html +1 -1
- package/dist/site/terminal.d.ts +0 -14
- package/web/assets/ask-tray-KUTWZ4MV-Ckn1y1Zw.js +0 -24
- package/web/assets/channel-BQxXBpeY.js +0 -1
- package/web/assets/classDiagram-OUVF2IWQ-BT1TSwZs.js +0 -1
- package/web/assets/classDiagram-v2-EOCWNBFH-BT1TSwZs.js +0 -1
- package/web/assets/swimlanesDiagram-G3AALYLV-C5riej52.js +0 -8
package/dist/package/preview.js
CHANGED
|
@@ -210,10 +210,119 @@ var init_document_kinds = __esm(() => {
|
|
|
210
210
|
};
|
|
211
211
|
});
|
|
212
212
|
|
|
213
|
-
// packages/
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
213
|
+
// packages/plugins/src/client.ts
|
|
214
|
+
function folderPathId(path) {
|
|
215
|
+
const bytes = new TextEncoder().encode(path);
|
|
216
|
+
let binary = "";
|
|
217
|
+
for (const byte of bytes)
|
|
218
|
+
binary += String.fromCharCode(byte);
|
|
219
|
+
return btoa(binary).replaceAll("+", "-").replaceAll("/", "_").replaceAll("=", "");
|
|
220
|
+
}
|
|
221
|
+
var init_client = () => {};
|
|
222
|
+
|
|
223
|
+
// packages/api/src/shared/viewer-route.ts
|
|
224
|
+
function decodeBase64Url(value) {
|
|
225
|
+
const padded = `${value}${"=".repeat((4 - value.length % 4) % 4)}`;
|
|
226
|
+
const binary = atob(padded.replaceAll("-", "+").replaceAll("_", "/"));
|
|
227
|
+
return new TextDecoder().decode(Uint8Array.from(binary, (character) => character.charCodeAt(0)));
|
|
228
|
+
}
|
|
229
|
+
function url(value) {
|
|
230
|
+
if (/^https?:\/\//.test(value))
|
|
231
|
+
return new URL(value);
|
|
232
|
+
if (value.startsWith("?"))
|
|
233
|
+
return new URL(`/${value}`, "http://127.0.0.1");
|
|
234
|
+
return new URL(value || "/", "http://127.0.0.1");
|
|
235
|
+
}
|
|
236
|
+
function tabSection(tab) {
|
|
237
|
+
if (tab === "files")
|
|
238
|
+
return "notes";
|
|
239
|
+
if (tab === "projects" || tab === "sessions")
|
|
240
|
+
return tab;
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
243
|
+
function folderPathId2(path) {
|
|
244
|
+
return folderPathId(path);
|
|
245
|
+
}
|
|
246
|
+
function decodeFolderPathId(id) {
|
|
247
|
+
return decodeBase64Url(id);
|
|
248
|
+
}
|
|
249
|
+
function folderHomeHref(folder) {
|
|
250
|
+
return `/folder/${folderPathId2(folder)}`;
|
|
251
|
+
}
|
|
252
|
+
function folderPluginHref(folder, pluginId, subpath = "") {
|
|
253
|
+
const base = `/folder/${folderPathId2(folder)}/views/${encodeURIComponent(pluginId)}`;
|
|
254
|
+
return subpath ? `${base}/${encodeURIComponent(subpath)}` : base;
|
|
255
|
+
}
|
|
256
|
+
function folderUrl(base, folder, options = {}) {
|
|
257
|
+
const current = new URL(base);
|
|
258
|
+
current.pathname = options.view ? folderPluginHref(folder, options.view.pluginId, options.view.subpath) : options.document ? folderDocumentHref(folder, options.document) : folderHomeHref(folder);
|
|
259
|
+
current.searchParams.delete("folder");
|
|
260
|
+
if (options.document && options.watch && !options.view) {
|
|
261
|
+
current.searchParams.set("watch", "1");
|
|
262
|
+
}
|
|
263
|
+
return current;
|
|
264
|
+
}
|
|
265
|
+
function folderDocumentHref(folder, document2) {
|
|
266
|
+
return `/folder/${folderPathId2(folder)}/document/${folderPathId2(document2)}`;
|
|
267
|
+
}
|
|
268
|
+
function parseViewerRoute(value) {
|
|
269
|
+
const current = url(value);
|
|
270
|
+
const session = current.searchParams.get("session") ?? undefined;
|
|
271
|
+
const folder = current.searchParams.get("folder");
|
|
272
|
+
if (folder) {
|
|
273
|
+
return {
|
|
274
|
+
document: current.searchParams.get("document") ?? current.searchParams.get("file") ?? undefined,
|
|
275
|
+
embedded: current.searchParams.get("embedded") === "1",
|
|
276
|
+
folder,
|
|
277
|
+
panel: current.searchParams.get("panel") === "1",
|
|
278
|
+
section: tabSection(current.searchParams.get("tab")) ?? "notes",
|
|
279
|
+
...session ? { session } : {}
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
const parts = current.pathname.split("/").filter(Boolean);
|
|
283
|
+
if (parts[0] !== "folder" || !parts[1]) {
|
|
284
|
+
return {
|
|
285
|
+
document: current.searchParams.get("file") ?? current.searchParams.get("document") ?? undefined,
|
|
286
|
+
embedded: current.searchParams.get("embedded") === "1",
|
|
287
|
+
folder: undefined,
|
|
288
|
+
panel: current.searchParams.get("panel") === "1",
|
|
289
|
+
section: tabSection(current.searchParams.get("tab")),
|
|
290
|
+
...session ? { session } : {}
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
const section = parts[2];
|
|
294
|
+
const route = {
|
|
295
|
+
embedded: current.searchParams.get("embedded") === "1",
|
|
296
|
+
folder: decodeFolderPathId(parts[1]),
|
|
297
|
+
panel: current.searchParams.get("panel") === "1",
|
|
298
|
+
...session ? { session } : {}
|
|
299
|
+
};
|
|
300
|
+
if (section === "collections" && parts[3]) {
|
|
301
|
+
return { ...route, collectionId: decodeFolderPathId(parts[3]) };
|
|
302
|
+
}
|
|
303
|
+
if (section === "views" && parts[3]) {
|
|
304
|
+
return {
|
|
305
|
+
...route,
|
|
306
|
+
view: {
|
|
307
|
+
pluginId: decodeURIComponent(parts[3]),
|
|
308
|
+
...parts[4] ? { subpath: parts[4] } : {}
|
|
309
|
+
}
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
if (section === "notes" || section === "projects" || section === "sessions") {
|
|
313
|
+
return { ...route, section };
|
|
314
|
+
}
|
|
315
|
+
if (section === "document" && parts[3]) {
|
|
316
|
+
return { ...route, document: decodeFolderPathId(parts[3]) };
|
|
317
|
+
}
|
|
318
|
+
return route;
|
|
319
|
+
}
|
|
320
|
+
var init_viewer_route = __esm(() => {
|
|
321
|
+
init_client();
|
|
322
|
+
});
|
|
323
|
+
|
|
324
|
+
// packages/preview/src/runtime.ts
|
|
325
|
+
import { execFile } from "node:child_process";
|
|
217
326
|
function openPreview(url) {
|
|
218
327
|
const command = process.platform === "darwin" ? "/usr/bin/open" : process.platform === "win32" ? "explorer.exe" : "xdg-open";
|
|
219
328
|
execFile(command, [url], (error) => {
|
|
@@ -221,212 +330,21 @@ function openPreview(url) {
|
|
|
221
330
|
console.error(`Could not open browser: ${error.message}`);
|
|
222
331
|
});
|
|
223
332
|
}
|
|
224
|
-
function
|
|
225
|
-
const command = process.platform === "darwin" ? "/usr/bin/pbcopy" : process.platform === "win32" ? "clip" : process.env.WAYLAND_DISPLAY ? "wl-copy" : "xclip";
|
|
226
|
-
const args = command === "xclip" ? ["-selection", "clipboard"] : [];
|
|
227
|
-
return new Promise((done, fail) => {
|
|
228
|
-
const child = execFile(command, args, (error) => error ? fail(error) : done());
|
|
229
|
-
child.stdin?.on("error", fail);
|
|
230
|
-
child.stdin?.end(url);
|
|
231
|
-
});
|
|
232
|
-
}
|
|
233
|
-
function repositoryName(folder) {
|
|
234
|
-
try {
|
|
235
|
-
const root = execFileSync("git", ["-C", folder, "rev-parse", "--show-toplevel"], {
|
|
236
|
-
encoding: "utf8",
|
|
237
|
-
stdio: ["ignore", "pipe", "ignore"],
|
|
238
|
-
timeout: 1000
|
|
239
|
-
});
|
|
240
|
-
return terminalText(basename(root.trim()));
|
|
241
|
-
} catch {
|
|
242
|
-
return;
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
function previewTerminal(url, target, startShare, views) {
|
|
246
|
-
url = new URL(url).href;
|
|
247
|
-
const input = process.stdin;
|
|
248
|
-
const output = process.stdout;
|
|
249
|
-
const terminal = Boolean(output.isTTY && process.env.TERM !== "dumb");
|
|
250
|
-
const interactive = terminal && Boolean(input.isTTY);
|
|
251
|
-
const name = terminalText(basename(target.target ?? target.root) || target.root);
|
|
252
|
-
const title = terminalText(basename(target.root) || target.root);
|
|
253
|
-
const repository = interactive ? repositoryName(target.root) : undefined;
|
|
254
|
-
const color = terminal && process.env.NO_COLOR === undefined && output.hasColors();
|
|
255
|
-
const accent = (text) => color ? `\x1B[32m${text}\x1B[39m` : text;
|
|
256
|
-
const linkTo = (label, href, plain = `${label}
|
|
257
|
-
${href}`) => terminal ? `\x1B]8;;${href}\x07${accent(label)}\x1B]8;;\x07` : plain;
|
|
258
|
-
const link = (label) => linkTo(label, url);
|
|
259
|
-
const wasRaw = Boolean(input.isRaw);
|
|
260
|
-
const wasFlowing = input.readableFlowing === true;
|
|
333
|
+
function viewerLifetime() {
|
|
261
334
|
let resolveClosed;
|
|
262
335
|
const closed = new Promise((resolve) => {
|
|
263
336
|
resolveClosed = resolve;
|
|
264
337
|
});
|
|
265
|
-
let finished = false;
|
|
266
|
-
let busy = false;
|
|
267
|
-
let selected = 0;
|
|
268
|
-
let status = "";
|
|
269
|
-
let share;
|
|
270
|
-
const render = () => {
|
|
271
|
-
if (!interactive || finished)
|
|
272
|
-
return;
|
|
273
|
-
cursorTo(output, 0, 0);
|
|
274
|
-
clearScreenDown(output);
|
|
275
|
-
const width = Math.max(1, (output.columns || 80) - 1);
|
|
276
|
-
const fit = (text) => {
|
|
277
|
-
const characters = Array.from(terminalText(text));
|
|
278
|
-
return characters.length > width ? characters.slice(0, width - 1).join("") + "…" : characters.join("");
|
|
279
|
-
};
|
|
280
|
-
const choices = [];
|
|
281
|
-
actions.forEach((item, index) => {
|
|
282
|
-
const label = fit(item.shortcut ? `[${item.shortcut}] ${item.label}` : item.label);
|
|
283
|
-
let text = index === selected ? accent(`› ${label}`) : ` ${label}`;
|
|
284
|
-
if (item.view !== undefined)
|
|
285
|
-
text = linkTo(text, item.view, accent(text));
|
|
286
|
-
choices.push(text);
|
|
287
|
-
});
|
|
288
|
-
output.write([
|
|
289
|
-
`\x1B[1m${link(fit(title))}\x1B[22m`,
|
|
290
|
-
...repository ? [`${color ? "\x1B[2m" : ""}${fit(repository)}${color ? "\x1B[22m" : ""}`] : [],
|
|
291
|
-
...target.target ? [`File: ${fit(name)}`] : [],
|
|
292
|
-
"",
|
|
293
|
-
...choices,
|
|
294
|
-
"",
|
|
295
|
-
"↑ ↓ to move · Enter to choose · Esc or Ctrl+C to exit",
|
|
296
|
-
...status ? ["", status] : [],
|
|
297
|
-
""
|
|
298
|
-
].join(`
|
|
299
|
-
`));
|
|
300
|
-
};
|
|
301
|
-
const shareFolder = async (password = false) => {
|
|
302
|
-
status = "Preparing a private Tailscale link…";
|
|
303
|
-
render();
|
|
304
|
-
try {
|
|
305
|
-
share ??= startShare(password);
|
|
306
|
-
let active;
|
|
307
|
-
try {
|
|
308
|
-
active = await share;
|
|
309
|
-
} catch (error) {
|
|
310
|
-
share = undefined;
|
|
311
|
-
throw error;
|
|
312
|
-
}
|
|
313
|
-
if (finished)
|
|
314
|
-
return;
|
|
315
|
-
status = active.password ? `Tailscale link: ${active.url}
|
|
316
|
-
Username: ${active.username} · Password: ${active.password}
|
|
317
|
-
Password required. Send the password separately.
|
|
318
|
-
Connect Tailscale on your phone to the same tailnet.
|
|
319
|
-
Trusted HTTPS; no certificate installation required.
|
|
320
|
-
Keep this command running. Ctrl+C stops sharing.` : `Tailscale link: ${active.url}
|
|
321
|
-
Connect Tailscale on your phone to the same tailnet.
|
|
322
|
-
Trusted HTTPS; no password required on the tailnet.
|
|
323
|
-
Keep this command running. Ctrl+C stops sharing.`;
|
|
324
|
-
render();
|
|
325
|
-
try {
|
|
326
|
-
await copyPreviewLink(active.url);
|
|
327
|
-
status += `
|
|
328
|
-
Tailscale link copied to clipboard (without the password).`;
|
|
329
|
-
} catch (error) {
|
|
330
|
-
status += `
|
|
331
|
-
Could not copy link: ${terminalText(error instanceof Error ? error.message : String(error))}`;
|
|
332
|
-
}
|
|
333
|
-
} catch (error) {
|
|
334
|
-
status = `Could not share folder: ${terminalText(error instanceof Error ? error.message : String(error))}`;
|
|
335
|
-
}
|
|
336
|
-
};
|
|
337
338
|
const close = () => {
|
|
338
|
-
if (finished)
|
|
339
|
-
return;
|
|
340
|
-
finished = true;
|
|
341
339
|
process.off("SIGINT", close);
|
|
342
340
|
process.off("SIGTERM", close);
|
|
343
|
-
|
|
344
|
-
if (interactive) {
|
|
345
|
-
input.off("keypress", keypress);
|
|
346
|
-
input.off("end", close);
|
|
347
|
-
output.off("resize", render);
|
|
348
|
-
output.write("\x1B[?25h\x1B[?1049l");
|
|
349
|
-
input.setRawMode(wasRaw);
|
|
350
|
-
if (!wasFlowing)
|
|
351
|
-
input.pause();
|
|
352
|
-
}
|
|
353
|
-
if (share) {
|
|
354
|
-
share.then((active) => active.close()).catch((error) => {
|
|
355
|
-
console.error(` Could not stop the Tailscale share: ${error instanceof Error ? error.message : error}`);
|
|
356
|
-
}).finally(() => resolveClosed());
|
|
357
|
-
} else
|
|
358
|
-
resolveClosed();
|
|
359
|
-
};
|
|
360
|
-
const actions = [
|
|
361
|
-
...(views ?? []).map((view) => ({ label: view.id, run: () => {
|
|
362
|
-
openPreview(view.url);
|
|
363
|
-
status = "Browser open requested.";
|
|
364
|
-
}, view: view.url })),
|
|
365
|
-
{ label: "Open in browser", shortcut: "o", run: () => {
|
|
366
|
-
openPreview(url);
|
|
367
|
-
status = "Browser open requested.";
|
|
368
|
-
} },
|
|
369
|
-
{ label: "Share to another device", shortcut: "s", run: () => shareFolder(false) },
|
|
370
|
-
{ label: "Share link with password", shortcut: "p", run: () => shareFolder(true) },
|
|
371
|
-
{ label: "Exit", shortcut: "q", run: close }
|
|
372
|
-
];
|
|
373
|
-
const activate = async () => {
|
|
374
|
-
busy = true;
|
|
375
|
-
try {
|
|
376
|
-
await actions[selected].run();
|
|
377
|
-
} catch (error) {
|
|
378
|
-
status = `Could not complete action: ${terminalText(error instanceof Error ? error.message : String(error))}`;
|
|
379
|
-
} finally {
|
|
380
|
-
busy = false;
|
|
381
|
-
render();
|
|
382
|
-
}
|
|
383
|
-
};
|
|
384
|
-
const keypress = (_text, key) => {
|
|
385
|
-
if (key.name === "escape" || key.ctrl && (key.name === "c" || key.name === "d")) {
|
|
386
|
-
close();
|
|
387
|
-
return;
|
|
388
|
-
}
|
|
389
|
-
if (busy || finished)
|
|
390
|
-
return;
|
|
391
|
-
const shortcut = !key.ctrl && !key.meta ? actions.findIndex((item) => item.shortcut === key.name) : -1;
|
|
392
|
-
if (shortcut !== -1) {
|
|
393
|
-
selected = shortcut;
|
|
394
|
-
activate();
|
|
395
|
-
return;
|
|
396
|
-
}
|
|
397
|
-
if (key.name === "up")
|
|
398
|
-
selected = (selected - 1 + actions.length) % actions.length;
|
|
399
|
-
else if (key.name === "down")
|
|
400
|
-
selected = (selected + 1) % actions.length;
|
|
401
|
-
else if (key.name === "return") {
|
|
402
|
-
activate();
|
|
403
|
-
return;
|
|
404
|
-
} else
|
|
405
|
-
return;
|
|
406
|
-
render();
|
|
341
|
+
resolveClosed();
|
|
407
342
|
};
|
|
408
343
|
process.once("SIGINT", close);
|
|
409
344
|
process.once("SIGTERM", close);
|
|
410
|
-
|
|
411
|
-
if (interactive) {
|
|
412
|
-
output.write("\x1B[?1049h\x1B[?25l");
|
|
413
|
-
output.on("resize", render);
|
|
414
|
-
emitKeypressEvents(input);
|
|
415
|
-
input.setRawMode(true);
|
|
416
|
-
input.on("keypress", keypress);
|
|
417
|
-
input.once("end", close);
|
|
418
|
-
input.resume();
|
|
419
|
-
}
|
|
420
|
-
if (interactive)
|
|
421
|
-
render();
|
|
422
|
-
else
|
|
423
|
-
console.log(`
|
|
424
|
-
${link(name)}
|
|
425
|
-
`);
|
|
426
|
-
return { close, closed, interactive };
|
|
345
|
+
return { close, closed };
|
|
427
346
|
}
|
|
428
|
-
var
|
|
429
|
-
var init_terminal = () => {};
|
|
347
|
+
var init_runtime = () => {};
|
|
430
348
|
|
|
431
349
|
// node_modules/.bun/openapi-fetch@0.17.0/node_modules/openapi-fetch/dist/index.mjs
|
|
432
350
|
function randomID() {
|
|
@@ -5792,6 +5710,7 @@ var init_schemas3 = __esm(() => {
|
|
|
5792
5710
|
icon: object({ paths: array(string2().min(1)).min(1) }).optional(),
|
|
5793
5711
|
id: string2(),
|
|
5794
5712
|
label: string2(),
|
|
5713
|
+
pages: array(object({ id: string2(), label: string2() })).optional(),
|
|
5795
5714
|
subpath: string2().optional()
|
|
5796
5715
|
});
|
|
5797
5716
|
plugins = object({
|
|
@@ -5999,83 +5918,6 @@ var init_schemas3 = __esm(() => {
|
|
|
5999
5918
|
};
|
|
6000
5919
|
});
|
|
6001
5920
|
|
|
6002
|
-
// packages/api/src/shared/viewer-route.ts
|
|
6003
|
-
function decodeBase64Url(value) {
|
|
6004
|
-
const padded = `${value}${"=".repeat((4 - value.length % 4) % 4)}`;
|
|
6005
|
-
const binary = atob(padded.replaceAll("-", "+").replaceAll("_", "/"));
|
|
6006
|
-
return new TextDecoder().decode(Uint8Array.from(binary, (character) => character.charCodeAt(0)));
|
|
6007
|
-
}
|
|
6008
|
-
function url(value) {
|
|
6009
|
-
if (/^https?:\/\//.test(value))
|
|
6010
|
-
return new URL(value);
|
|
6011
|
-
if (value.startsWith("?"))
|
|
6012
|
-
return new URL(`/${value}`, "http://127.0.0.1");
|
|
6013
|
-
return new URL(value || "/", "http://127.0.0.1");
|
|
6014
|
-
}
|
|
6015
|
-
function tabSection(tab) {
|
|
6016
|
-
if (tab === "files")
|
|
6017
|
-
return "notes";
|
|
6018
|
-
if (tab === "projects" || tab === "sessions")
|
|
6019
|
-
return tab;
|
|
6020
|
-
return;
|
|
6021
|
-
}
|
|
6022
|
-
function decodeFolderPathId(id) {
|
|
6023
|
-
return decodeBase64Url(id);
|
|
6024
|
-
}
|
|
6025
|
-
function parseViewerRoute(value) {
|
|
6026
|
-
const current = url(value);
|
|
6027
|
-
const session = current.searchParams.get("session") ?? undefined;
|
|
6028
|
-
const folder = current.searchParams.get("folder");
|
|
6029
|
-
if (folder) {
|
|
6030
|
-
return {
|
|
6031
|
-
document: current.searchParams.get("document") ?? current.searchParams.get("file") ?? undefined,
|
|
6032
|
-
embedded: current.searchParams.get("embedded") === "1",
|
|
6033
|
-
folder,
|
|
6034
|
-
panel: current.searchParams.get("panel") === "1",
|
|
6035
|
-
section: tabSection(current.searchParams.get("tab")) ?? "notes",
|
|
6036
|
-
...session ? { session } : {}
|
|
6037
|
-
};
|
|
6038
|
-
}
|
|
6039
|
-
const parts = current.pathname.split("/").filter(Boolean);
|
|
6040
|
-
if (parts[0] !== "folder" || !parts[1]) {
|
|
6041
|
-
return {
|
|
6042
|
-
document: current.searchParams.get("file") ?? current.searchParams.get("document") ?? undefined,
|
|
6043
|
-
embedded: current.searchParams.get("embedded") === "1",
|
|
6044
|
-
folder: undefined,
|
|
6045
|
-
panel: current.searchParams.get("panel") === "1",
|
|
6046
|
-
section: tabSection(current.searchParams.get("tab")),
|
|
6047
|
-
...session ? { session } : {}
|
|
6048
|
-
};
|
|
6049
|
-
}
|
|
6050
|
-
const section = parts[2];
|
|
6051
|
-
const route = {
|
|
6052
|
-
embedded: current.searchParams.get("embedded") === "1",
|
|
6053
|
-
folder: decodeFolderPathId(parts[1]),
|
|
6054
|
-
panel: current.searchParams.get("panel") === "1",
|
|
6055
|
-
...session ? { session } : {}
|
|
6056
|
-
};
|
|
6057
|
-
if (section === "collections" && parts[3]) {
|
|
6058
|
-
return { ...route, collectionId: decodeFolderPathId(parts[3]) };
|
|
6059
|
-
}
|
|
6060
|
-
if (section === "views" && parts[3]) {
|
|
6061
|
-
return {
|
|
6062
|
-
...route,
|
|
6063
|
-
view: {
|
|
6064
|
-
pluginId: parts[3],
|
|
6065
|
-
...parts[4] ? { subpath: parts[4] } : {}
|
|
6066
|
-
}
|
|
6067
|
-
};
|
|
6068
|
-
}
|
|
6069
|
-
if (section === "notes" || section === "projects" || section === "sessions") {
|
|
6070
|
-
return { ...route, section };
|
|
6071
|
-
}
|
|
6072
|
-
if (section === "document" && parts[3]) {
|
|
6073
|
-
return { ...route, document: decodeFolderPathId(parts[3]) };
|
|
6074
|
-
}
|
|
6075
|
-
return { ...route, section: "notes" };
|
|
6076
|
-
}
|
|
6077
|
-
var init_viewer_route = () => {};
|
|
6078
|
-
|
|
6079
5921
|
// packages/api-client/src/errors.ts
|
|
6080
5922
|
async function expectedError(response) {
|
|
6081
5923
|
const body = await response.text().catch(() => "");
|
|
@@ -6228,13 +6070,14 @@ var init_src = __esm(() => {
|
|
|
6228
6070
|
init_schemas3();
|
|
6229
6071
|
init_viewer_route();
|
|
6230
6072
|
init_errors3();
|
|
6073
|
+
init_viewer_route();
|
|
6231
6074
|
init_errors3();
|
|
6232
6075
|
init_responses();
|
|
6233
6076
|
api2 = createKennelClient();
|
|
6234
6077
|
});
|
|
6235
6078
|
|
|
6236
6079
|
// packages/preview/src/hot-viewer.ts
|
|
6237
|
-
import { execFileSync
|
|
6080
|
+
import { execFileSync, spawn } from "node:child_process";
|
|
6238
6081
|
import { randomUUID } from "node:crypto";
|
|
6239
6082
|
import { existsSync } from "node:fs";
|
|
6240
6083
|
import { mkdir, readFile, rm, writeFile } from "node:fs/promises";
|
|
@@ -6283,13 +6126,13 @@ function startupLock(host, port) {
|
|
|
6283
6126
|
return resolve(tmpdir(), `kennel-hot-viewer-${name}.lock`);
|
|
6284
6127
|
}
|
|
6285
6128
|
function lanHost() {
|
|
6286
|
-
const route =
|
|
6129
|
+
const route = execFileSync("/sbin/route", ["-n", "get", "default"], {
|
|
6287
6130
|
encoding: "utf8"
|
|
6288
6131
|
});
|
|
6289
6132
|
const device = route.match(/interface:\s+(\S+)/)?.[1];
|
|
6290
6133
|
if (!device)
|
|
6291
6134
|
throw new Error("kennel could not find the local network interface");
|
|
6292
|
-
const host =
|
|
6135
|
+
const host = execFileSync("/usr/sbin/ipconfig", ["getifaddr", device], {
|
|
6293
6136
|
encoding: "utf8"
|
|
6294
6137
|
}).trim();
|
|
6295
6138
|
if (!host)
|
|
@@ -6350,18 +6193,9 @@ async function hotViewer(options) {
|
|
|
6350
6193
|
return;
|
|
6351
6194
|
}
|
|
6352
6195
|
const reuse = async () => {
|
|
6353
|
-
|
|
6354
|
-
await Promise.resolve().then(() => init_share());
|
|
6355
|
-
return startPreviewShare(options);
|
|
6356
|
-
});
|
|
6196
|
+
console.log(viewerUrl);
|
|
6357
6197
|
if (options.open)
|
|
6358
6198
|
openPreview(viewerUrl);
|
|
6359
|
-
try {
|
|
6360
|
-
if (terminal.interactive)
|
|
6361
|
-
await terminal.closed;
|
|
6362
|
-
} finally {
|
|
6363
|
-
terminal.close();
|
|
6364
|
-
}
|
|
6365
6199
|
};
|
|
6366
6200
|
const status = await viewerStatus(url);
|
|
6367
6201
|
if (status === "running") {
|
|
@@ -6409,11 +6243,9 @@ async function hotViewer(options) {
|
|
|
6409
6243
|
},
|
|
6410
6244
|
stdio: ["ignore", "inherit", "inherit"]
|
|
6411
6245
|
});
|
|
6412
|
-
const
|
|
6413
|
-
|
|
6414
|
-
|
|
6415
|
-
});
|
|
6416
|
-
terminal.closed.then(() => {
|
|
6246
|
+
const lifetime = viewerLifetime();
|
|
6247
|
+
console.log(viewerUrl);
|
|
6248
|
+
lifetime.closed.then(() => {
|
|
6417
6249
|
if (child.exitCode === null && child.signalCode === null)
|
|
6418
6250
|
child.kill("SIGTERM");
|
|
6419
6251
|
});
|
|
@@ -6424,7 +6256,7 @@ async function hotViewer(options) {
|
|
|
6424
6256
|
done();
|
|
6425
6257
|
return;
|
|
6426
6258
|
}
|
|
6427
|
-
|
|
6259
|
+
lifetime.close();
|
|
6428
6260
|
if (await viewerRunning(url, 20, true)) {
|
|
6429
6261
|
await reuse();
|
|
6430
6262
|
done();
|
|
@@ -6433,12 +6265,12 @@ async function hotViewer(options) {
|
|
|
6433
6265
|
fail(new Error(`Kennel hot viewer stopped with exit code ${code ?? "unknown"}`));
|
|
6434
6266
|
});
|
|
6435
6267
|
}).finally(async () => {
|
|
6436
|
-
|
|
6268
|
+
lifetime.close();
|
|
6437
6269
|
await releaseLock(lock, token);
|
|
6438
6270
|
});
|
|
6439
6271
|
}
|
|
6440
6272
|
var init_hot_viewer = __esm(() => {
|
|
6441
|
-
|
|
6273
|
+
init_runtime();
|
|
6442
6274
|
init_src();
|
|
6443
6275
|
});
|
|
6444
6276
|
|
|
@@ -28324,7 +28156,7 @@ var init_server = __esm(() => {
|
|
|
28324
28156
|
// packages/schemas/src/data/workspace.ts
|
|
28325
28157
|
import { existsSync as existsSync3, readFileSync, realpathSync, statSync as statSync2 } from "node:fs";
|
|
28326
28158
|
import {
|
|
28327
|
-
basename
|
|
28159
|
+
basename,
|
|
28328
28160
|
dirname as dirname3,
|
|
28329
28161
|
isAbsolute,
|
|
28330
28162
|
relative as relative3,
|
|
@@ -28385,7 +28217,7 @@ function folderWorkspace(input, { allowMissingSchemas = false } = {}) {
|
|
|
28385
28217
|
for (let current = folder;inside(root, current); current = dirname3(current)) {
|
|
28386
28218
|
breadcrumbs.unshift({
|
|
28387
28219
|
path: current,
|
|
28388
|
-
title:
|
|
28220
|
+
title: basename(current),
|
|
28389
28221
|
schema: schemaRoots.some((owner) => inside(owner, current))
|
|
28390
28222
|
});
|
|
28391
28223
|
if (current === root)
|
|
@@ -37934,7 +37766,7 @@ var init_load = __esm(() => {
|
|
|
37934
37766
|
// packages/schemas/src/node.ts
|
|
37935
37767
|
import { readdir as readdir2, readFile as readFile4, realpath as realpath2, stat as stat2 } from "node:fs/promises";
|
|
37936
37768
|
import {
|
|
37937
|
-
basename as
|
|
37769
|
+
basename as basename2,
|
|
37938
37770
|
dirname as dirname5,
|
|
37939
37771
|
isAbsolute as isAbsolute3,
|
|
37940
37772
|
relative as relative5,
|
|
@@ -37967,7 +37799,7 @@ function createCoreFolderIndex() {
|
|
|
37967
37799
|
affected.add(scope);
|
|
37968
37800
|
}
|
|
37969
37801
|
}
|
|
37970
|
-
if (inside3(path, scope) ||
|
|
37802
|
+
if (inside3(path, scope) || basename2(path) === "raggle.json" && inside3(dirname5(path), scope) || ["schema.json", "_schema.json"].includes(basename2(path)) && dirname5(path) === scope)
|
|
37971
37803
|
affected.add(scope);
|
|
37972
37804
|
}
|
|
37973
37805
|
for (const file of records.keys())
|
|
@@ -38076,7 +37908,7 @@ function createCoreFolderIndex() {
|
|
|
38076
37908
|
path,
|
|
38077
37909
|
relativePath: localPath,
|
|
38078
37910
|
modifiedAt: info.mtimeMs,
|
|
38079
|
-
title: text(fieldValue(parsed.fields, primary)) ?? text(parsed.fields.title) ?? parsed.heading ??
|
|
37911
|
+
title: text(fieldValue(parsed.fields, primary)) ?? text(parsed.fields.title) ?? parsed.heading ?? basename2(path, ".md"),
|
|
38080
37912
|
fields: parsed.fields,
|
|
38081
37913
|
validationErrors,
|
|
38082
37914
|
icon: await recordIcon(parsed.fields, path, entry.folder, parsed.body)
|
|
@@ -38102,7 +37934,7 @@ function createCoreFolderIndex() {
|
|
|
38102
37934
|
const data = {
|
|
38103
37935
|
id,
|
|
38104
37936
|
...entry,
|
|
38105
|
-
title: text(schema?.title) ?? config.title ??
|
|
37937
|
+
title: text(schema?.title) ?? config.title ?? basename2(entry.folder),
|
|
38106
37938
|
navLabel: config.ui?.navLabel,
|
|
38107
37939
|
icon: config.icon,
|
|
38108
37940
|
count: indexedRecords.length,
|
|
@@ -38173,7 +38005,7 @@ var init_node3 = __esm(() => {
|
|
|
38173
38005
|
|
|
38174
38006
|
// packages/schemas/src/server.ts
|
|
38175
38007
|
import { createHash as createHash3 } from "node:crypto";
|
|
38176
|
-
import { basename as
|
|
38008
|
+
import { basename as basename3, relative as relative6 } from "node:path";
|
|
38177
38009
|
function createSchemaCollectionServer(host, options = {}) {
|
|
38178
38010
|
const collectionIndex = createCoreFolderIndex();
|
|
38179
38011
|
const collectionScopes = new Set;
|
|
@@ -38223,7 +38055,7 @@ function createSchemaCollectionServer(host, options = {}) {
|
|
|
38223
38055
|
};
|
|
38224
38056
|
const invalidate = (path) => {
|
|
38225
38057
|
const affected = collectionIndex.invalidate(path);
|
|
38226
|
-
if (affected.length ||
|
|
38058
|
+
if (affected.length || basename3(path) === "raggle.json" && collectionScopes.size) {
|
|
38227
38059
|
clearTimeout(collectionRefresh);
|
|
38228
38060
|
collectionRefresh = setTimeout(() => {
|
|
38229
38061
|
host.emit({
|
|
@@ -38329,7 +38161,7 @@ import {
|
|
|
38329
38161
|
writeFile as writeFile3
|
|
38330
38162
|
} from "node:fs/promises";
|
|
38331
38163
|
import { homedir as homedir2 } from "node:os";
|
|
38332
|
-
import { basename as
|
|
38164
|
+
import { basename as basename4, dirname as dirname6, join as join2, relative as relative7, resolve as resolve7, sep as sep4 } from "node:path";
|
|
38333
38165
|
import { promisify } from "node:util";
|
|
38334
38166
|
function kennelConfigHome() {
|
|
38335
38167
|
const xdg = process.env.XDG_CONFIG_HOME?.trim();
|
|
@@ -38403,7 +38235,12 @@ async function resolveCheckout(folder) {
|
|
|
38403
38235
|
}
|
|
38404
38236
|
let output;
|
|
38405
38237
|
try {
|
|
38406
|
-
output = await git([
|
|
38238
|
+
output = await git([
|
|
38239
|
+
"rev-parse",
|
|
38240
|
+
"--path-format=absolute",
|
|
38241
|
+
"--show-toplevel",
|
|
38242
|
+
"--git-common-dir"
|
|
38243
|
+
], start);
|
|
38407
38244
|
} catch (error) {
|
|
38408
38245
|
if (gitExitCode(error) === 128) {
|
|
38409
38246
|
throw new RepositoryNotesError("not-git", `Not a Git repository: ${start}. Repository notes need a Git checkout.`);
|
|
@@ -38505,7 +38342,11 @@ var init_store = __esm(() => {
|
|
|
38505
38342
|
run = promisify(execFile2);
|
|
38506
38343
|
UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/u;
|
|
38507
38344
|
markdownExtensions = new Set([".md", ".markdown"]);
|
|
38508
|
-
caseInsensitiveHosts = new Set([
|
|
38345
|
+
caseInsensitiveHosts = new Set([
|
|
38346
|
+
"github.com",
|
|
38347
|
+
"gitlab.com",
|
|
38348
|
+
"bitbucket.org"
|
|
38349
|
+
]);
|
|
38509
38350
|
RepositoryNotesError = class RepositoryNotesError extends Error {
|
|
38510
38351
|
code;
|
|
38511
38352
|
constructor(code, message) {
|
|
@@ -38520,7 +38361,7 @@ var init_store = __esm(() => {
|
|
|
38520
38361
|
import { readdir as readdir4, readFile as readFile6, realpath as realpath4, stat as stat4 } from "node:fs/promises";
|
|
38521
38362
|
import { homedir as homedir3 } from "node:os";
|
|
38522
38363
|
import {
|
|
38523
|
-
basename as
|
|
38364
|
+
basename as basename5,
|
|
38524
38365
|
dirname as dirname7,
|
|
38525
38366
|
extname as extname2,
|
|
38526
38367
|
isAbsolute as isAbsolute4,
|
|
@@ -38667,10 +38508,10 @@ async function readEntity(folderPath, rootPath) {
|
|
|
38667
38508
|
return {
|
|
38668
38509
|
content: document2.body,
|
|
38669
38510
|
path: relative8(folderPath, filePath),
|
|
38670
|
-
title: stringValue(document2.frontmatter.title) ?? heading(document2.body) ??
|
|
38511
|
+
title: stringValue(document2.frontmatter.title) ?? heading(document2.body) ?? basename5(filePath, extname2(filePath))
|
|
38671
38512
|
};
|
|
38672
38513
|
}));
|
|
38673
|
-
const title = stringValue(index.frontmatter.title) ?? heading(index.body) ??
|
|
38514
|
+
const title = stringValue(index.frontmatter.title) ?? heading(index.body) ?? basename5(folderPath);
|
|
38674
38515
|
const relativePath = relative8(rootPath, folderPath) || ".";
|
|
38675
38516
|
return {
|
|
38676
38517
|
aliases: stringValues(index.frontmatter.aliases),
|
|
@@ -39043,9 +38884,461 @@ var init_folder_icons = __esm(() => {
|
|
|
39043
38884
|
]);
|
|
39044
38885
|
});
|
|
39045
38886
|
|
|
38887
|
+
// packages/knl/src/folder-guard.ts
|
|
38888
|
+
import { existsSync as existsSync4, realpathSync as realpathSync2 } from "node:fs";
|
|
38889
|
+
import { realpath as realpath6 } from "node:fs/promises";
|
|
38890
|
+
import { dirname as dirname9, resolve as resolve11, sep as sep6 } from "node:path";
|
|
38891
|
+
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
38892
|
+
async function knlRealRoot(owner) {
|
|
38893
|
+
const expected = resolve11(await realpath6(owner), "knl");
|
|
38894
|
+
const real = await realpath6(resolve11(owner, "knl"));
|
|
38895
|
+
if (real !== expected)
|
|
38896
|
+
throw new Error("knl/ must be a folder, not a link to another place.");
|
|
38897
|
+
return real;
|
|
38898
|
+
}
|
|
38899
|
+
async function knlReadRoots(owner) {
|
|
38900
|
+
const packages = await Promise.all(knlHostPackageFolders.map((folder) => realpath6(folder).catch(() => {
|
|
38901
|
+
return;
|
|
38902
|
+
})));
|
|
38903
|
+
return [
|
|
38904
|
+
await knlRealRoot(owner),
|
|
38905
|
+
...packages.filter((folder) => Boolean(folder))
|
|
38906
|
+
];
|
|
38907
|
+
}
|
|
38908
|
+
function isKnlReadable(file, roots) {
|
|
38909
|
+
let real;
|
|
38910
|
+
try {
|
|
38911
|
+
real = realpathSync2(file);
|
|
38912
|
+
} catch {
|
|
38913
|
+
real = resolve11(file);
|
|
38914
|
+
}
|
|
38915
|
+
return roots.some((root) => real === root || real.startsWith(`${root}${sep6}`));
|
|
38916
|
+
}
|
|
38917
|
+
function knlReadError(file) {
|
|
38918
|
+
return `KNL pages can only use files in knl/ and installed packages: ${file}`;
|
|
38919
|
+
}
|
|
38920
|
+
function assertKnlReadable(file, roots) {
|
|
38921
|
+
if (!isKnlReadable(file, roots))
|
|
38922
|
+
throw new Error(knlReadError(file));
|
|
38923
|
+
}
|
|
38924
|
+
var knlHostResolveDir, knlHostPackageFolders;
|
|
38925
|
+
var init_folder_guard = __esm(() => {
|
|
38926
|
+
knlHostResolveDir = dirname9(fileURLToPath2(import.meta.url));
|
|
38927
|
+
knlHostPackageFolders = (() => {
|
|
38928
|
+
const folders = [];
|
|
38929
|
+
let current = knlHostResolveDir;
|
|
38930
|
+
while (true) {
|
|
38931
|
+
const nodeModules = resolve11(current, "node_modules");
|
|
38932
|
+
if (existsSync4(nodeModules))
|
|
38933
|
+
folders.push(nodeModules);
|
|
38934
|
+
const parent = dirname9(current);
|
|
38935
|
+
if (parent === current)
|
|
38936
|
+
return folders;
|
|
38937
|
+
current = parent;
|
|
38938
|
+
}
|
|
38939
|
+
})();
|
|
38940
|
+
});
|
|
38941
|
+
|
|
38942
|
+
// packages/knl/src/tailwind.ts
|
|
38943
|
+
import { readFile as readFile10 } from "node:fs/promises";
|
|
38944
|
+
import { createRequire as createRequire2 } from "node:module";
|
|
38945
|
+
import { dirname as dirname10, resolve as resolve12 } from "node:path";
|
|
38946
|
+
import { compile } from "@tailwindcss/node";
|
|
38947
|
+
import { Scanner } from "@tailwindcss/oxide";
|
|
38948
|
+
function starterKnlStyles() {
|
|
38949
|
+
return `@layer theme, utilities;
|
|
38950
|
+
@import "tailwindcss/theme.css" layer(theme) prefix(knl);
|
|
38951
|
+
@import "tailwindcss/utilities.css" layer(utilities) source(none);
|
|
38952
|
+
|
|
38953
|
+
@theme {
|
|
38954
|
+
--font-sans: system-ui, sans-serif;
|
|
38955
|
+
}
|
|
38956
|
+
`;
|
|
38957
|
+
}
|
|
38958
|
+
async function compileKnlCss(js, stylesheet, roots) {
|
|
38959
|
+
const base = dirname10(stylesheet);
|
|
38960
|
+
assertKnlReadable(stylesheet, roots);
|
|
38961
|
+
const css = await readFile10(stylesheet, "utf8").catch((error) => {
|
|
38962
|
+
if (error.code === "ENOENT")
|
|
38963
|
+
return starterKnlStyles();
|
|
38964
|
+
throw error;
|
|
38965
|
+
});
|
|
38966
|
+
const compiler = await compile(css, {
|
|
38967
|
+
base,
|
|
38968
|
+
from: stylesheet,
|
|
38969
|
+
onDependency: (path) => assertKnlReadable(path, roots),
|
|
38970
|
+
customJsResolver: async (id) => {
|
|
38971
|
+
throw new Error(`KNL does not load Tailwind plugins or configs (${id}).`);
|
|
38972
|
+
},
|
|
38973
|
+
customCssResolver: async (id) => id === "tailwindcss" || id.startsWith("tailwindcss/") ? require2.resolve(id) : undefined
|
|
38974
|
+
});
|
|
38975
|
+
const sources = [...compiler.sources];
|
|
38976
|
+
if (compiler.root !== "none") {
|
|
38977
|
+
sources.push({
|
|
38978
|
+
...compiler.root ?? { base, pattern: "**/*" },
|
|
38979
|
+
negated: false
|
|
38980
|
+
});
|
|
38981
|
+
}
|
|
38982
|
+
for (const source of sources) {
|
|
38983
|
+
if (source.negated)
|
|
38984
|
+
continue;
|
|
38985
|
+
const fixed = source.pattern.split("/");
|
|
38986
|
+
const glob = fixed.findIndex((part) => /[*?[{]/.test(part));
|
|
38987
|
+
assertKnlReadable(resolve12(source.base, fixed.slice(0, glob < 0 ? undefined : glob).join("/")), roots);
|
|
38988
|
+
}
|
|
38989
|
+
const scanner = new Scanner({ sources });
|
|
38990
|
+
const candidates = [
|
|
38991
|
+
...scanner.scan(),
|
|
38992
|
+
...scanner.scanFiles([{ content: js, extension: "js" }])
|
|
38993
|
+
];
|
|
38994
|
+
return compiler.build(candidates);
|
|
38995
|
+
}
|
|
38996
|
+
var require2;
|
|
38997
|
+
var init_tailwind = __esm(() => {
|
|
38998
|
+
init_folder_guard();
|
|
38999
|
+
require2 = createRequire2(import.meta.url);
|
|
39000
|
+
});
|
|
39001
|
+
|
|
39002
|
+
// packages/knl/src/knl.ts
|
|
39003
|
+
import { readdir as readdir5, stat as stat7 } from "node:fs/promises";
|
|
39004
|
+
import { basename as basename6, dirname as dirname11, relative as relative10, resolve as resolve13, sep as sep7 } from "node:path";
|
|
39005
|
+
import * as esbuild from "esbuild";
|
|
39006
|
+
function sourceFor(file, knlRoot, scanRoot, owner) {
|
|
39007
|
+
const id = toModuleId(file, knlRoot);
|
|
39008
|
+
return {
|
|
39009
|
+
id,
|
|
39010
|
+
file,
|
|
39011
|
+
relative: relative10(scanRoot, file).split(sep7).join("/"),
|
|
39012
|
+
folder: dirname11(file),
|
|
39013
|
+
owner
|
|
39014
|
+
};
|
|
39015
|
+
}
|
|
39016
|
+
function toModuleId(file, knlRoot) {
|
|
39017
|
+
const relativeKnl = relative10(knlRoot, file).split(sep7).join("/");
|
|
39018
|
+
return relativeKnl.replace(/\/?index\.(tsx|ts)$/, "") || "index";
|
|
39019
|
+
}
|
|
39020
|
+
async function collectKnlSources(scanRoot, owner) {
|
|
39021
|
+
const knlRoot = resolve13(scanRoot, KNK_FOLDER);
|
|
39022
|
+
const knlEntries = await readdir5(knlRoot, { withFileTypes: true }).catch(() => []);
|
|
39023
|
+
const sources = [];
|
|
39024
|
+
const addModule = async (folder) => {
|
|
39025
|
+
for (const candidate of MODULE_FILES) {
|
|
39026
|
+
const file = resolve13(folder, candidate);
|
|
39027
|
+
if (await stat7(file).then((d) => d.isFile()).catch(() => false)) {
|
|
39028
|
+
sources.push(sourceFor(file, knlRoot, scanRoot, owner));
|
|
39029
|
+
return;
|
|
39030
|
+
}
|
|
39031
|
+
}
|
|
39032
|
+
};
|
|
39033
|
+
await addModule(knlRoot);
|
|
39034
|
+
for (const entry of knlEntries) {
|
|
39035
|
+
if (!entry.isDirectory())
|
|
39036
|
+
continue;
|
|
39037
|
+
if (entry.name.startsWith(".") || entry.name === "node_modules")
|
|
39038
|
+
continue;
|
|
39039
|
+
await addModule(resolve13(knlRoot, entry.name));
|
|
39040
|
+
}
|
|
39041
|
+
return sources.sort((left, right) => {
|
|
39042
|
+
const rank = (left.id === "index" ? 0 : 1) - (right.id === "index" ? 0 : 1);
|
|
39043
|
+
return rank !== 0 ? rank : left.id.localeCompare(right.id);
|
|
39044
|
+
});
|
|
39045
|
+
}
|
|
39046
|
+
async function loadKnlSources(viewRoot, linkedFolders = []) {
|
|
39047
|
+
const sources = [
|
|
39048
|
+
...await collectKnlSources(viewRoot, viewRoot),
|
|
39049
|
+
...(await Promise.all(linkedFolders.map(async (folder) => (await collectKnlSources(folder, folder)).map((source) => ({
|
|
39050
|
+
...source,
|
|
39051
|
+
id: `${basename6(folder)}:${source.id}`,
|
|
39052
|
+
relative: `${basename6(folder)}/${source.relative}`
|
|
39053
|
+
}))))).flat()
|
|
39054
|
+
];
|
|
39055
|
+
return { sources };
|
|
39056
|
+
}
|
|
39057
|
+
function knlNodePaths(knlRoot) {
|
|
39058
|
+
return [resolve13(knlRoot, "node_modules"), ...knlHostPackageFolders];
|
|
39059
|
+
}
|
|
39060
|
+
async function compileKnlSource(source) {
|
|
39061
|
+
const sourceBytes = (await stat7(source.file)).size;
|
|
39062
|
+
const tooLarge = (bytes, what) => ({
|
|
39063
|
+
id: source.id,
|
|
39064
|
+
relative: source.relative,
|
|
39065
|
+
js: "",
|
|
39066
|
+
css: "",
|
|
39067
|
+
issues: [
|
|
39068
|
+
{
|
|
39069
|
+
path: source.relative,
|
|
39070
|
+
message: `Module ${what} is too large (${bytes} bytes; limit ${MAX_SOURCE_BYTES}).`
|
|
39071
|
+
}
|
|
39072
|
+
]
|
|
39073
|
+
});
|
|
39074
|
+
if (sourceBytes > MAX_SOURCE_BYTES)
|
|
39075
|
+
return tooLarge(sourceBytes, "source");
|
|
39076
|
+
const cached = compileCache.get(source.file);
|
|
39077
|
+
const unchanged = cached && (await Promise.all(cached.dependencies.map(async ({ file, mtimeMs }) => (await stat7(file).catch(() => {
|
|
39078
|
+
return;
|
|
39079
|
+
}))?.mtimeMs === mtimeMs))).every(Boolean);
|
|
39080
|
+
const knlRoot = resolve13(source.owner, KNK_FOLDER);
|
|
39081
|
+
let issuePath = source.relative;
|
|
39082
|
+
try {
|
|
39083
|
+
const nodePaths = knlNodePaths(knlRoot);
|
|
39084
|
+
const roots = await knlReadRoots(source.owner);
|
|
39085
|
+
assertKnlReadable(source.file, roots);
|
|
39086
|
+
let js;
|
|
39087
|
+
if (cached && unchanged) {
|
|
39088
|
+
js = cached.js;
|
|
39089
|
+
} else {
|
|
39090
|
+
const result = await esbuild.build({
|
|
39091
|
+
absWorkingDir: source.folder,
|
|
39092
|
+
stdin: {
|
|
39093
|
+
contents: `import { createElement } from "react"
|
|
39094
|
+
import { createRoot } from "react-dom/client"
|
|
39095
|
+
import Component from ${JSON.stringify(source.file)}
|
|
39096
|
+
|
|
39097
|
+
globalThis.__knlMount = (container, context, onError) => {
|
|
39098
|
+
const root = createRoot(container, { onUncaughtError: onError })
|
|
39099
|
+
root.render(createElement(Component, context))
|
|
39100
|
+
}
|
|
39101
|
+
`,
|
|
39102
|
+
sourcefile: `${source.file}.mount.ts`,
|
|
39103
|
+
loader: "ts",
|
|
39104
|
+
resolveDir: source.folder
|
|
39105
|
+
},
|
|
39106
|
+
bundle: true,
|
|
39107
|
+
format: "iife",
|
|
39108
|
+
target: "es2022",
|
|
39109
|
+
jsx: "automatic",
|
|
39110
|
+
platform: "browser",
|
|
39111
|
+
write: false,
|
|
39112
|
+
minify: false,
|
|
39113
|
+
sourcemap: false,
|
|
39114
|
+
logLevel: "silent",
|
|
39115
|
+
metafile: true,
|
|
39116
|
+
nodePaths,
|
|
39117
|
+
plugins: [readGuard(roots)]
|
|
39118
|
+
});
|
|
39119
|
+
js = result.outputFiles?.[0]?.text ?? "";
|
|
39120
|
+
const files = new Set([
|
|
39121
|
+
resolve13(knlRoot, "package.json"),
|
|
39122
|
+
...Object.keys(result.metafile.inputs).map((file) => resolve13(source.folder, file)).filter((file) => file !== `${source.file}.mount.ts`)
|
|
39123
|
+
]);
|
|
39124
|
+
const dependencies = await Promise.all([...files].map(async (file) => ({
|
|
39125
|
+
file,
|
|
39126
|
+
mtimeMs: (await stat7(file).catch(() => {
|
|
39127
|
+
return;
|
|
39128
|
+
}))?.mtimeMs
|
|
39129
|
+
})));
|
|
39130
|
+
compileCache.delete(source.file);
|
|
39131
|
+
compileCache.set(source.file, { js, dependencies });
|
|
39132
|
+
if (compileCache.size > MAX_CACHED_MODULES)
|
|
39133
|
+
compileCache.delete(compileCache.keys().next().value);
|
|
39134
|
+
}
|
|
39135
|
+
const stylesheet = resolve13(knlRoot, "style.css");
|
|
39136
|
+
issuePath = relative10(source.owner, stylesheet).split(sep7).join("/");
|
|
39137
|
+
const css = await compileKnlCss(js, stylesheet, roots);
|
|
39138
|
+
issuePath = source.relative;
|
|
39139
|
+
if (js.length + css.length > MAX_JS_BYTES) {
|
|
39140
|
+
return {
|
|
39141
|
+
id: source.id,
|
|
39142
|
+
relative: source.relative,
|
|
39143
|
+
js: "",
|
|
39144
|
+
css: "",
|
|
39145
|
+
issues: [
|
|
39146
|
+
{
|
|
39147
|
+
path: source.relative,
|
|
39148
|
+
message: `Compiled module is too large (${js.length + css.length} bytes; limit ${MAX_JS_BYTES}).`
|
|
39149
|
+
}
|
|
39150
|
+
]
|
|
39151
|
+
};
|
|
39152
|
+
}
|
|
39153
|
+
return { id: source.id, relative: source.relative, js, css, issues: [] };
|
|
39154
|
+
} catch (error) {
|
|
39155
|
+
return {
|
|
39156
|
+
id: source.id,
|
|
39157
|
+
relative: source.relative,
|
|
39158
|
+
js: "",
|
|
39159
|
+
css: "",
|
|
39160
|
+
issues: knlBuildIssues(error, issuePath, source)
|
|
39161
|
+
};
|
|
39162
|
+
}
|
|
39163
|
+
}
|
|
39164
|
+
function readGuard(roots) {
|
|
39165
|
+
return {
|
|
39166
|
+
name: "knl-read-guard",
|
|
39167
|
+
setup(build) {
|
|
39168
|
+
build.onResolve({ filter: /.*/ }, async (args) => {
|
|
39169
|
+
if (args.pluginData === guardResolve)
|
|
39170
|
+
return;
|
|
39171
|
+
const resolveFrom = (resolveDir) => build.resolve(args.path, {
|
|
39172
|
+
importer: args.importer,
|
|
39173
|
+
kind: args.kind,
|
|
39174
|
+
pluginData: guardResolve,
|
|
39175
|
+
resolveDir
|
|
39176
|
+
});
|
|
39177
|
+
const readable = (result) => result.namespace !== "file" || !result.path || isKnlReadable(result.path, roots);
|
|
39178
|
+
let result = await resolveFrom(args.resolveDir);
|
|
39179
|
+
const bare = !/^(?:\.{1,2}(?:\/|$)|\/)/.test(args.path);
|
|
39180
|
+
if (bare && result.errors.length === 0 && !readable(result))
|
|
39181
|
+
result = await resolveFrom(knlHostResolveDir);
|
|
39182
|
+
if (result.errors.length > 0)
|
|
39183
|
+
return { errors: result.errors };
|
|
39184
|
+
if (!readable(result))
|
|
39185
|
+
return { errors: [{ text: knlReadError(args.path) }] };
|
|
39186
|
+
return result;
|
|
39187
|
+
});
|
|
39188
|
+
}
|
|
39189
|
+
};
|
|
39190
|
+
}
|
|
39191
|
+
function knlBuildIssues(error, relativePath, source) {
|
|
39192
|
+
const failures = error?.errors;
|
|
39193
|
+
if (Array.isArray(failures) && failures.length > 0) {
|
|
39194
|
+
const first = failures[0];
|
|
39195
|
+
const file = first?.location?.file ? relative10(source.owner, resolve13(source.folder, first.location.file)).split(sep7).join("/") : relativePath;
|
|
39196
|
+
const location = first?.location ? `${file}:${first.location.line ?? "?"}` : relativePath;
|
|
39197
|
+
return [
|
|
39198
|
+
{ path: location, message: first?.text ?? "Module failed to compile." }
|
|
39199
|
+
];
|
|
39200
|
+
}
|
|
39201
|
+
return [
|
|
39202
|
+
{
|
|
39203
|
+
path: relativePath,
|
|
39204
|
+
message: error instanceof Error && error.message ? error.message : "Module failed to compile."
|
|
39205
|
+
}
|
|
39206
|
+
];
|
|
39207
|
+
}
|
|
39208
|
+
function starterKnlSource() {
|
|
39209
|
+
return `// knl/index.tsx — this folder's homepage (KNL folder web framework).
|
|
39210
|
+
// Every other page lives in its own folder: knl/<page>/index.tsx.
|
|
39211
|
+
import * as React from "react"
|
|
39212
|
+
|
|
39213
|
+
export default function Home() {
|
|
39214
|
+
return (
|
|
39215
|
+
<div className="knl:p-4 knl:font-sans">
|
|
39216
|
+
<h1 className="knl:m-0 knl:text-2xl">Home</h1>
|
|
39217
|
+
<p>Edit this file to build the homepage.</p>
|
|
39218
|
+
</div>
|
|
39219
|
+
)
|
|
39220
|
+
}
|
|
39221
|
+
`;
|
|
39222
|
+
}
|
|
39223
|
+
var KNK_FOLDER = "knl", MAX_SOURCE_BYTES, MAX_JS_BYTES, MODULE_FILES, MAX_CACHED_MODULES = 200, compileCache, guardResolve;
|
|
39224
|
+
var init_knl = __esm(() => {
|
|
39225
|
+
init_folder_guard();
|
|
39226
|
+
init_tailwind();
|
|
39227
|
+
MAX_SOURCE_BYTES = 512 * 1024;
|
|
39228
|
+
MAX_JS_BYTES = 5 * 1024 * 1024;
|
|
39229
|
+
MODULE_FILES = ["index.tsx", "index.ts"];
|
|
39230
|
+
compileCache = new Map;
|
|
39231
|
+
guardResolve = Symbol("knl-guard");
|
|
39232
|
+
});
|
|
39233
|
+
|
|
39234
|
+
// packages/knl/src/manifest.ts
|
|
39235
|
+
var knlManifest;
|
|
39236
|
+
var init_manifest = __esm(() => {
|
|
39237
|
+
knlManifest = {
|
|
39238
|
+
id: "knl",
|
|
39239
|
+
label: "KNL"
|
|
39240
|
+
};
|
|
39241
|
+
});
|
|
39242
|
+
|
|
39243
|
+
// packages/knl/src/server.ts
|
|
39244
|
+
import { stat as stat8 } from "node:fs/promises";
|
|
39245
|
+
import { join as join5 } from "node:path";
|
|
39246
|
+
function createKnlPlugin() {
|
|
39247
|
+
return {
|
|
39248
|
+
...knlManifest,
|
|
39249
|
+
async detect(context) {
|
|
39250
|
+
const hasKnlFolder = await stat8(join5(context.folder, KNK_FOLDER)).then((entry) => entry.isDirectory()).catch(() => false);
|
|
39251
|
+
if (!hasKnlFolder)
|
|
39252
|
+
return { status: "unavailable" };
|
|
39253
|
+
const { sources } = await loadKnlSources(context.folder, context.linkedFolders ?? []);
|
|
39254
|
+
if (!sources.some((source) => source.id === "index"))
|
|
39255
|
+
return { status: "unavailable" };
|
|
39256
|
+
return {
|
|
39257
|
+
count: sources.length,
|
|
39258
|
+
pages: sources.filter((source) => source.id !== "index" && !source.id.endsWith(":index")).map((source) => ({
|
|
39259
|
+
id: source.id,
|
|
39260
|
+
label: source.id.replaceAll(/[-_]/g, " ").replace(/^./, (letter) => letter.toUpperCase())
|
|
39261
|
+
})),
|
|
39262
|
+
status: "available"
|
|
39263
|
+
};
|
|
39264
|
+
},
|
|
39265
|
+
async handle(context, subpath) {
|
|
39266
|
+
const { sources } = await loadKnlSources(context.folder, context.linkedFolders ?? []);
|
|
39267
|
+
const folder = context.folder;
|
|
39268
|
+
if (sources.length === 0) {
|
|
39269
|
+
return { kind: "available", data: { folder, status: "unavailable" } };
|
|
39270
|
+
}
|
|
39271
|
+
const requested = subpath.trim() || "index";
|
|
39272
|
+
const selected = sources.filter((source) => source.id === requested);
|
|
39273
|
+
if (selected.length === 0) {
|
|
39274
|
+
return {
|
|
39275
|
+
kind: "available",
|
|
39276
|
+
data: {
|
|
39277
|
+
folder,
|
|
39278
|
+
status: "error",
|
|
39279
|
+
message: `KNL page not found: ${requested}`
|
|
39280
|
+
}
|
|
39281
|
+
};
|
|
39282
|
+
}
|
|
39283
|
+
const compiled = await Promise.all(selected.map(compileKnlSource));
|
|
39284
|
+
const entries = compiled.map((result) => {
|
|
39285
|
+
const source = sources.find((item) => item.id === result.id);
|
|
39286
|
+
return {
|
|
39287
|
+
id: result.id,
|
|
39288
|
+
relative: result.relative,
|
|
39289
|
+
...result.js ? { js: result.js } : {},
|
|
39290
|
+
css: result.css,
|
|
39291
|
+
...result.issues.length > 0 ? { issues: result.issues } : {},
|
|
39292
|
+
owner: source?.owner ?? folder
|
|
39293
|
+
};
|
|
39294
|
+
});
|
|
39295
|
+
const failing = entries.filter((entry) => entry.issues?.length);
|
|
39296
|
+
if (failing.length > 0) {
|
|
39297
|
+
return {
|
|
39298
|
+
kind: "available",
|
|
39299
|
+
data: {
|
|
39300
|
+
folder,
|
|
39301
|
+
status: "error",
|
|
39302
|
+
entries,
|
|
39303
|
+
issues: failing[0]?.issues
|
|
39304
|
+
}
|
|
39305
|
+
};
|
|
39306
|
+
}
|
|
39307
|
+
return {
|
|
39308
|
+
kind: "available",
|
|
39309
|
+
data: {
|
|
39310
|
+
folder,
|
|
39311
|
+
status: "available",
|
|
39312
|
+
entries
|
|
39313
|
+
}
|
|
39314
|
+
};
|
|
39315
|
+
},
|
|
39316
|
+
async init() {
|
|
39317
|
+
return {
|
|
39318
|
+
files: [
|
|
39319
|
+
{ path: "knl/index.tsx", content: starterKnlSource() },
|
|
39320
|
+
{ path: "knl/style.css", content: starterKnlStyles() },
|
|
39321
|
+
{
|
|
39322
|
+
path: "knl/package.json",
|
|
39323
|
+
content: `${JSON.stringify({ private: true, type: "module" }, null, 2)}
|
|
39324
|
+
`
|
|
39325
|
+
},
|
|
39326
|
+
{ path: "knl/.gitignore", content: `node_modules/
|
|
39327
|
+
` }
|
|
39328
|
+
]
|
|
39329
|
+
};
|
|
39330
|
+
}
|
|
39331
|
+
};
|
|
39332
|
+
}
|
|
39333
|
+
var init_server3 = __esm(() => {
|
|
39334
|
+
init_knl();
|
|
39335
|
+
init_manifest();
|
|
39336
|
+
init_tailwind();
|
|
39337
|
+
});
|
|
39338
|
+
|
|
39046
39339
|
// packages/notes/src/manifest.ts
|
|
39047
39340
|
var notesManifest;
|
|
39048
|
-
var
|
|
39341
|
+
var init_manifest2 = __esm(() => {
|
|
39049
39342
|
notesManifest = {
|
|
39050
39343
|
id: "notes",
|
|
39051
39344
|
icon: {
|
|
@@ -39060,23 +39353,23 @@ var init_manifest = __esm(() => {
|
|
|
39060
39353
|
});
|
|
39061
39354
|
|
|
39062
39355
|
// packages/notes/src/server.ts
|
|
39063
|
-
import { readdir as
|
|
39356
|
+
import { readdir as readdir6, realpath as realpath7, stat as stat9 } from "node:fs/promises";
|
|
39064
39357
|
import {
|
|
39065
39358
|
basename as basename7,
|
|
39066
39359
|
extname as extname5,
|
|
39067
39360
|
isAbsolute as isAbsolute6,
|
|
39068
|
-
relative as
|
|
39069
|
-
resolve as
|
|
39070
|
-
sep as
|
|
39361
|
+
relative as relative11,
|
|
39362
|
+
resolve as resolve14,
|
|
39363
|
+
sep as sep8
|
|
39071
39364
|
} from "node:path";
|
|
39072
39365
|
async function listMarkdownFiles(folder) {
|
|
39073
39366
|
const files = [];
|
|
39074
39367
|
const visit = async (current) => {
|
|
39075
|
-
const entries = await
|
|
39368
|
+
const entries = await readdir6(current, { withFileTypes: true }).catch(() => []);
|
|
39076
39369
|
for (const entry of entries) {
|
|
39077
39370
|
if (entry.name === "node_modules" || entry.name.startsWith("."))
|
|
39078
39371
|
continue;
|
|
39079
|
-
const path =
|
|
39372
|
+
const path = resolve14(current, entry.name);
|
|
39080
39373
|
if (entry.isDirectory()) {
|
|
39081
39374
|
await visit(path);
|
|
39082
39375
|
continue;
|
|
@@ -39084,13 +39377,13 @@ async function listMarkdownFiles(folder) {
|
|
|
39084
39377
|
if (!entry.isFile() || !markdownExtensions2.has(extname5(entry.name))) {
|
|
39085
39378
|
continue;
|
|
39086
39379
|
}
|
|
39087
|
-
const details = await
|
|
39380
|
+
const details = await stat9(path).catch(() => {
|
|
39088
39381
|
return;
|
|
39089
39382
|
});
|
|
39090
39383
|
files.push({
|
|
39091
39384
|
activityAt: details?.mtimeMs ?? 0,
|
|
39092
39385
|
name: basename7(entry.name, extname5(entry.name)),
|
|
39093
|
-
relativePath:
|
|
39386
|
+
relativePath: relative11(folder, path).split(sep8).join("/")
|
|
39094
39387
|
});
|
|
39095
39388
|
}
|
|
39096
39389
|
};
|
|
@@ -39098,7 +39391,7 @@ async function listMarkdownFiles(folder) {
|
|
|
39098
39391
|
return files.sort((left, right) => right.activityAt - left.activityAt);
|
|
39099
39392
|
}
|
|
39100
39393
|
function inside5(path, root) {
|
|
39101
|
-
const local =
|
|
39394
|
+
const local = relative11(root, path);
|
|
39102
39395
|
return local === "" || !local.startsWith("..") && !isAbsolute6(local);
|
|
39103
39396
|
}
|
|
39104
39397
|
async function withoutManaged(groups, managedRoots) {
|
|
@@ -39110,7 +39403,7 @@ async function withoutManaged(groups, managedRoots) {
|
|
|
39110
39403
|
return { ...group, files: [] };
|
|
39111
39404
|
}
|
|
39112
39405
|
const files = await Promise.all(group.files.map(async (file) => {
|
|
39113
|
-
const real = await canonical(
|
|
39406
|
+
const real = await canonical(resolve14(group.folder, file.relativePath));
|
|
39114
39407
|
return roots.some((root) => inside5(real, root)) ? undefined : file;
|
|
39115
39408
|
}));
|
|
39116
39409
|
return { ...group, files: files.filter((file) => file !== undefined) };
|
|
@@ -39160,7 +39453,7 @@ async function notesLlmSections({
|
|
|
39160
39453
|
continue;
|
|
39161
39454
|
seen.add(identity);
|
|
39162
39455
|
const files = await listMarkdownFiles(source);
|
|
39163
|
-
const paths = files.map((file) =>
|
|
39456
|
+
const paths = files.map((file) => resolve14(source, file.relativePath));
|
|
39164
39457
|
groups.push({ folder: source, paths });
|
|
39165
39458
|
files.forEach((file, index) => notes.push({ activityAt: file.activityAt, path: paths[index] }));
|
|
39166
39459
|
}
|
|
@@ -39204,17 +39497,17 @@ function createNotesPlugin() {
|
|
|
39204
39497
|
llm: notesLlmSections
|
|
39205
39498
|
};
|
|
39206
39499
|
}
|
|
39207
|
-
var markdownExtensions2, llmNoteLimit = 20, canonical = (path) =>
|
|
39208
|
-
var
|
|
39209
|
-
|
|
39500
|
+
var markdownExtensions2, llmNoteLimit = 20, canonical = (path) => realpath7(path).catch(() => path);
|
|
39501
|
+
var init_server4 = __esm(() => {
|
|
39502
|
+
init_manifest2();
|
|
39210
39503
|
markdownExtensions2 = new Set([".md", ".markdown"]);
|
|
39211
39504
|
});
|
|
39212
39505
|
|
|
39213
39506
|
// packages/api/src/server/plugins.ts
|
|
39214
39507
|
import { pathToFileURL } from "node:url";
|
|
39215
|
-
import { existsSync as
|
|
39216
|
-
import { mkdir as mkdir4, readFile as
|
|
39217
|
-
import { dirname as
|
|
39508
|
+
import { existsSync as existsSync5 } from "node:fs";
|
|
39509
|
+
import { mkdir as mkdir4, readFile as readFile11, stat as stat10, writeFile as writeFile6 } from "node:fs/promises";
|
|
39510
|
+
import { dirname as dirname12, resolve as resolve15, sep as sep9 } from "node:path";
|
|
39218
39511
|
function configuredFolderServerRegistry(registry, resolvedConfig) {
|
|
39219
39512
|
const disabled = new Set(resolvedConfig.plugins.disable);
|
|
39220
39513
|
const orderedIds = resolvedConfig.plugins.order.filter((id) => registry.has(id) && !disabled.has(id));
|
|
@@ -39238,14 +39531,14 @@ function parsePluginRegistryConfig(content) {
|
|
|
39238
39531
|
};
|
|
39239
39532
|
}
|
|
39240
39533
|
async function nearestKennelConfig(folder) {
|
|
39241
|
-
for (let current = folder;; current =
|
|
39242
|
-
const candidate =
|
|
39243
|
-
const details = await
|
|
39534
|
+
for (let current = folder;; current = dirname12(current)) {
|
|
39535
|
+
const candidate = resolve15(current, "kennel.json");
|
|
39536
|
+
const details = await stat10(candidate).catch(() => {
|
|
39244
39537
|
return;
|
|
39245
39538
|
});
|
|
39246
39539
|
if (details?.isFile())
|
|
39247
39540
|
return candidate;
|
|
39248
|
-
if (
|
|
39541
|
+
if (dirname12(current) === current)
|
|
39249
39542
|
return;
|
|
39250
39543
|
}
|
|
39251
39544
|
}
|
|
@@ -39254,13 +39547,13 @@ async function folderPluginRegistryConfig(folder) {
|
|
|
39254
39547
|
if (!path)
|
|
39255
39548
|
return defaultPluginRegistryConfig;
|
|
39256
39549
|
try {
|
|
39257
|
-
return parsePluginRegistryConfig(await
|
|
39550
|
+
return parsePluginRegistryConfig(await readFile11(path, "utf8"));
|
|
39258
39551
|
} catch {
|
|
39259
39552
|
return defaultPluginRegistryConfig;
|
|
39260
39553
|
}
|
|
39261
39554
|
}
|
|
39262
39555
|
function createFolderServerPlugins() {
|
|
39263
|
-
return [createNotesPlugin()];
|
|
39556
|
+
return [createNotesPlugin(), createKnlPlugin()];
|
|
39264
39557
|
}
|
|
39265
39558
|
function folderServerRegistry() {
|
|
39266
39559
|
return new Map(createFolderServerPlugins().map((plugin) => [plugin.id, plugin]));
|
|
@@ -39302,7 +39595,7 @@ async function folderServerRegistryAsync() {
|
|
|
39302
39595
|
...server,
|
|
39303
39596
|
async detect(context) {
|
|
39304
39597
|
const detection = await server.detect(context);
|
|
39305
|
-
if (detection.status === "unavailable" &&
|
|
39598
|
+
if (detection.status === "unavailable" && existsSync5(resolve15(context.folder, entry.trigger))) {
|
|
39306
39599
|
return { status: "available" };
|
|
39307
39600
|
}
|
|
39308
39601
|
return detection;
|
|
@@ -39342,6 +39635,7 @@ async function externalApiHandlers() {
|
|
|
39342
39635
|
var defaultPluginRegistryConfig;
|
|
39343
39636
|
var init_plugins = __esm(() => {
|
|
39344
39637
|
init_server3();
|
|
39638
|
+
init_server4();
|
|
39345
39639
|
defaultPluginRegistryConfig = {
|
|
39346
39640
|
plugins: { disable: [], order: [] }
|
|
39347
39641
|
};
|
|
@@ -39349,29 +39643,29 @@ var init_plugins = __esm(() => {
|
|
|
39349
39643
|
|
|
39350
39644
|
// packages/api/src/server/linked-folder-discovery.ts
|
|
39351
39645
|
import { execFile as execFile4 } from "node:child_process";
|
|
39352
|
-
import { existsSync as
|
|
39353
|
-
import { createRequire as
|
|
39354
|
-
import { dirname as
|
|
39355
|
-
import { fileURLToPath as
|
|
39646
|
+
import { existsSync as existsSync6 } from "node:fs";
|
|
39647
|
+
import { createRequire as createRequire3 } from "node:module";
|
|
39648
|
+
import { dirname as dirname13, join as join6 } from "node:path";
|
|
39649
|
+
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
39356
39650
|
function resolveLocalModule(from = import.meta.url) {
|
|
39357
|
-
const require2 =
|
|
39651
|
+
const require2 = createRequire3(from);
|
|
39358
39652
|
const candidates = [];
|
|
39359
39653
|
try {
|
|
39360
39654
|
candidates.push(require2.resolve("@raggle-ai/local"));
|
|
39361
39655
|
} catch {}
|
|
39362
|
-
let directory =
|
|
39363
|
-
while (
|
|
39364
|
-
if (
|
|
39656
|
+
let directory = dirname13(fileURLToPath3(from));
|
|
39657
|
+
while (dirname13(directory) !== directory) {
|
|
39658
|
+
if (existsSync6(join6(directory, "raggle.json"))) {
|
|
39365
39659
|
for (const candidate of [
|
|
39366
|
-
|
|
39367
|
-
|
|
39660
|
+
join6(dirname13(directory), "raggle-ai-scout", "packages", "local"),
|
|
39661
|
+
join6(directory, "..", "..", "raggle-ai-scout", "packages", "local")
|
|
39368
39662
|
]) {
|
|
39369
39663
|
if (!candidates.includes(candidate))
|
|
39370
39664
|
candidates.push(candidate);
|
|
39371
39665
|
}
|
|
39372
39666
|
break;
|
|
39373
39667
|
}
|
|
39374
|
-
directory =
|
|
39668
|
+
directory = dirname13(directory);
|
|
39375
39669
|
}
|
|
39376
39670
|
for (const candidate of candidates) {
|
|
39377
39671
|
try {
|
|
@@ -39380,7 +39674,7 @@ function resolveLocalModule(from = import.meta.url) {
|
|
|
39380
39674
|
return candidate;
|
|
39381
39675
|
} catch {}
|
|
39382
39676
|
}
|
|
39383
|
-
return candidates[0] ??
|
|
39677
|
+
return candidates[0] ?? join6(dirname13(fileURLToPath3(from)), "..", "..", "..", "raggle-ai-scout", "packages", "local");
|
|
39384
39678
|
}
|
|
39385
39679
|
function discoverLinkedFolders(folder, signal, modulePath = resolveLocalModule()) {
|
|
39386
39680
|
return new Promise((resolve, reject) => {
|
|
@@ -39569,25 +39863,25 @@ var init_project_discovery = __esm(() => {
|
|
|
39569
39863
|
|
|
39570
39864
|
// packages/api/src/server/folder-metadata-plugin.ts
|
|
39571
39865
|
import { createHash as createHash5 } from "node:crypto";
|
|
39572
|
-
import { realpathSync as
|
|
39573
|
-
import { readdir as
|
|
39866
|
+
import { realpathSync as realpathSync3 } from "node:fs";
|
|
39867
|
+
import { readdir as readdir7, readFile as readFile12, realpath as realpath8, stat as stat11 } from "node:fs/promises";
|
|
39574
39868
|
import { homedir as homedir4 } from "node:os";
|
|
39575
39869
|
import {
|
|
39576
39870
|
basename as basename8,
|
|
39577
|
-
dirname as
|
|
39871
|
+
dirname as dirname14,
|
|
39578
39872
|
extname as extname6,
|
|
39579
39873
|
isAbsolute as isAbsolute7,
|
|
39580
|
-
relative as
|
|
39581
|
-
resolve as
|
|
39582
|
-
sep as
|
|
39874
|
+
relative as relative13,
|
|
39875
|
+
resolve as resolve16,
|
|
39876
|
+
sep as sep10
|
|
39583
39877
|
} from "node:path";
|
|
39584
39878
|
import { execFile as execFile6 } from "node:child_process";
|
|
39585
39879
|
import local from "@raggle-ai/local";
|
|
39586
39880
|
function metadataFile(path, root) {
|
|
39587
|
-
const candidate =
|
|
39881
|
+
const candidate = relative13(root, path);
|
|
39588
39882
|
if (!candidate || candidate.startsWith("..") || isAbsolute7(candidate))
|
|
39589
39883
|
return false;
|
|
39590
|
-
const parts = candidate.split(
|
|
39884
|
+
const parts = candidate.split(sep10);
|
|
39591
39885
|
if (parts.some((part) => part === "node_modules"))
|
|
39592
39886
|
return false;
|
|
39593
39887
|
return metadataExtensions.has(extname6(candidate).toLowerCase());
|
|
@@ -39598,10 +39892,10 @@ async function configuredAiInputModule(folder) {
|
|
|
39598
39892
|
return typeof module === "string" && module.trim() ? module.trim() : null;
|
|
39599
39893
|
}
|
|
39600
39894
|
function folderPath(value, root, lockedRoot) {
|
|
39601
|
-
const folder =
|
|
39895
|
+
const folder = realpathSync3(resolve16(value ?? root));
|
|
39602
39896
|
if (!lockedRoot)
|
|
39603
39897
|
return folder;
|
|
39604
|
-
const path =
|
|
39898
|
+
const path = relative13(lockedRoot, folder);
|
|
39605
39899
|
if (!path || !path.startsWith("..") && !isAbsolute7(path))
|
|
39606
39900
|
return folder;
|
|
39607
39901
|
throw new Error(`Folder is outside the viewer root: ${folder}`);
|
|
@@ -39666,15 +39960,15 @@ function unique(values) {
|
|
|
39666
39960
|
return [...new Set(values)];
|
|
39667
39961
|
}
|
|
39668
39962
|
function isMachineRoot(folder) {
|
|
39669
|
-
return folder === homedir4() ||
|
|
39963
|
+
return folder === homedir4() || dirname14(folder) === folder;
|
|
39670
39964
|
}
|
|
39671
39965
|
async function shallowMetadata(folder) {
|
|
39672
|
-
const entries = await
|
|
39966
|
+
const entries = await readdir7(folder, { withFileTypes: true });
|
|
39673
39967
|
const visible = entries.filter((entry) => !entry.name.startsWith(".") && entry.name !== "node_modules");
|
|
39674
39968
|
const files = await Promise.all(visible.filter((entry) => entry.isFile() && [".markdown", ".md"].includes(extname6(entry.name).toLowerCase())).map(async (entry) => {
|
|
39675
|
-
const path =
|
|
39676
|
-
const details = await
|
|
39677
|
-
const content = await
|
|
39969
|
+
const path = resolve16(folder, entry.name);
|
|
39970
|
+
const details = await stat11(path);
|
|
39971
|
+
const content = await readFile12(path, "utf8").catch(() => "");
|
|
39678
39972
|
const title = markdownMetadata(content).title;
|
|
39679
39973
|
return {
|
|
39680
39974
|
activityAt: details.mtimeMs,
|
|
@@ -39687,10 +39981,10 @@ async function shallowMetadata(folder) {
|
|
|
39687
39981
|
};
|
|
39688
39982
|
}));
|
|
39689
39983
|
const projects = visible.filter((entry) => entry.isDirectory()).map((entry) => ({
|
|
39690
|
-
id: createHash5("sha1").update(
|
|
39984
|
+
id: createHash5("sha1").update(resolve16(folder, entry.name)).digest("hex"),
|
|
39691
39985
|
name: entry.name,
|
|
39692
39986
|
relativePath: entry.name,
|
|
39693
|
-
worktree:
|
|
39987
|
+
worktree: resolve16(folder, entry.name)
|
|
39694
39988
|
})).sort((left, right) => left.name.localeCompare(right.name));
|
|
39695
39989
|
return {
|
|
39696
39990
|
changes: { items: [] },
|
|
@@ -39717,7 +40011,7 @@ async function loadFolderData(folder) {
|
|
|
39717
40011
|
id: project.id,
|
|
39718
40012
|
worktree: project.worktree,
|
|
39719
40013
|
name: project.name ?? basename8(project.worktree),
|
|
39720
|
-
relativePath:
|
|
40014
|
+
relativePath: relative13(folder, project.worktree)
|
|
39721
40015
|
}))
|
|
39722
40016
|
}
|
|
39723
40017
|
};
|
|
@@ -39725,10 +40019,10 @@ async function loadFolderData(folder) {
|
|
|
39725
40019
|
async function notesFiles(folder, files, origin) {
|
|
39726
40020
|
return {
|
|
39727
40021
|
items: await Promise.all(files.map(async (file) => {
|
|
39728
|
-
const path = file.path ?? (file.relativePath ?
|
|
40022
|
+
const path = file.path ?? (file.relativePath ? resolve16(folder, file.relativePath) : undefined);
|
|
39729
40023
|
if (!path)
|
|
39730
40024
|
return origin ? { ...file, folder: origin } : file;
|
|
39731
|
-
const content = [".markdown", ".md"].includes(extname6(path).toLowerCase()) ? await
|
|
40025
|
+
const content = [".markdown", ".md"].includes(extname6(path).toLowerCase()) ? await readFile12(path, "utf8").catch(() => "") : "";
|
|
39732
40026
|
const title = content ? markdownMetadata(content).title : undefined;
|
|
39733
40027
|
return {
|
|
39734
40028
|
...file,
|
|
@@ -39742,7 +40036,7 @@ async function notesFiles(folder, files, origin) {
|
|
|
39742
40036
|
async function managedNotesFiles(directory) {
|
|
39743
40037
|
const notes = await listManagedNotes(directory);
|
|
39744
40038
|
return Promise.all(notes.map(async (note) => {
|
|
39745
|
-
const content = await
|
|
40039
|
+
const content = await readFile12(note.path, "utf8").catch(() => "");
|
|
39746
40040
|
const title = content ? markdownMetadata(content).title : undefined;
|
|
39747
40041
|
return {
|
|
39748
40042
|
...note,
|
|
@@ -39753,7 +40047,7 @@ async function managedNotesFiles(directory) {
|
|
|
39753
40047
|
}));
|
|
39754
40048
|
}
|
|
39755
40049
|
function insideFolder(path, root) {
|
|
39756
|
-
const local =
|
|
40050
|
+
const local = relative13(root, path);
|
|
39757
40051
|
return local === "" || !local.startsWith("..") && !isAbsolute7(local);
|
|
39758
40052
|
}
|
|
39759
40053
|
async function withoutManagedFiles(items, managedRoot) {
|
|
@@ -39785,15 +40079,15 @@ async function localProjectSearchCache(cache) {
|
|
|
39785
40079
|
function mediaTarget(folder, file, lockedTarget) {
|
|
39786
40080
|
if (!file)
|
|
39787
40081
|
return;
|
|
39788
|
-
const rootReal =
|
|
39789
|
-
const path =
|
|
40082
|
+
const rootReal = realpathSync3(resolve16(folder));
|
|
40083
|
+
const path = resolve16(folder, file);
|
|
39790
40084
|
let pathReal;
|
|
39791
40085
|
try {
|
|
39792
|
-
pathReal =
|
|
40086
|
+
pathReal = realpathSync3(path);
|
|
39793
40087
|
} catch {
|
|
39794
40088
|
return;
|
|
39795
40089
|
}
|
|
39796
|
-
const rel =
|
|
40090
|
+
const rel = relative13(rootReal, pathReal);
|
|
39797
40091
|
if (rel.startsWith("..") || isAbsolute7(rel))
|
|
39798
40092
|
return;
|
|
39799
40093
|
if (lockedTarget && pathReal !== lockedTarget)
|
|
@@ -39833,15 +40127,15 @@ function documentError(response) {
|
|
|
39833
40127
|
function documentTarget(folder, file, lockedTarget) {
|
|
39834
40128
|
if (!file)
|
|
39835
40129
|
return;
|
|
39836
|
-
const rootReal =
|
|
39837
|
-
const path =
|
|
40130
|
+
const rootReal = realpathSync3(resolve16(folder));
|
|
40131
|
+
const path = resolve16(folder, file);
|
|
39838
40132
|
let pathReal;
|
|
39839
40133
|
try {
|
|
39840
|
-
pathReal =
|
|
40134
|
+
pathReal = realpathSync3(path);
|
|
39841
40135
|
} catch {
|
|
39842
40136
|
return;
|
|
39843
40137
|
}
|
|
39844
|
-
const rel =
|
|
40138
|
+
const rel = relative13(rootReal, pathReal);
|
|
39845
40139
|
if (rel.startsWith("..") || isAbsolute7(rel))
|
|
39846
40140
|
return;
|
|
39847
40141
|
if (lockedTarget && pathReal !== lockedTarget)
|
|
@@ -39899,7 +40193,8 @@ async function pluginAvailability(registry, folder, linkedFolders, configWarning
|
|
|
39899
40193
|
error,
|
|
39900
40194
|
icon: plugin.icon,
|
|
39901
40195
|
id: plugin.id,
|
|
39902
|
-
label: plugin.label
|
|
40196
|
+
label: plugin.label,
|
|
40197
|
+
...detection.status === "available" && detection.pages ? { pages: detection.pages } : {}
|
|
39903
40198
|
});
|
|
39904
40199
|
}
|
|
39905
40200
|
} catch {}
|
|
@@ -39914,8 +40209,8 @@ function createFolderApi({
|
|
|
39914
40209
|
remoteAccess = false,
|
|
39915
40210
|
lockedFile
|
|
39916
40211
|
}) {
|
|
39917
|
-
let lockedRoot = restrictToRoot ?
|
|
39918
|
-
const lockedTarget = lockedFile ?
|
|
40212
|
+
let lockedRoot = restrictToRoot ? realpathSync3(root) : undefined;
|
|
40213
|
+
const lockedTarget = lockedFile ? realpathSync3(lockedFile) : undefined;
|
|
39919
40214
|
let basePlugins;
|
|
39920
40215
|
let baseExternalApiHandlers;
|
|
39921
40216
|
const assetFiles = new Map;
|
|
@@ -39953,7 +40248,7 @@ function createFolderApi({
|
|
|
39953
40248
|
const serverHost = server.host;
|
|
39954
40249
|
const remote = remoteAccess || serverHost === true || typeof serverHost === "string" && !isLoopbackServerHost(serverHost);
|
|
39955
40250
|
if (remote)
|
|
39956
|
-
lockedRoot = lockedRoot ??
|
|
40251
|
+
lockedRoot = lockedRoot ?? realpathSync3(root);
|
|
39957
40252
|
const collectionServer = createSchemaCollectionServer(server, {
|
|
39958
40253
|
boundary: lockedRoot,
|
|
39959
40254
|
lockedTarget
|
|
@@ -39979,7 +40274,7 @@ function createFolderApi({
|
|
|
39979
40274
|
if (!folder)
|
|
39980
40275
|
return;
|
|
39981
40276
|
server.emit({
|
|
39982
|
-
data: { path:
|
|
40277
|
+
data: { path: relative13(folder, path) },
|
|
39983
40278
|
event: "kennel:metadata-changed",
|
|
39984
40279
|
type: "custom"
|
|
39985
40280
|
});
|
|
@@ -40062,7 +40357,7 @@ function createFolderApi({
|
|
|
40062
40357
|
"Content-Type": asset.mediaType,
|
|
40063
40358
|
ETag: `"${hash}"`
|
|
40064
40359
|
});
|
|
40065
|
-
response.end(await
|
|
40360
|
+
response.end(await readFile12(asset.path));
|
|
40066
40361
|
} catch (error) {
|
|
40067
40362
|
response.writeHead(404, {
|
|
40068
40363
|
"Content-Type": "text/plain; charset=utf-8"
|
|
@@ -40134,14 +40429,14 @@ function createFolderApi({
|
|
|
40134
40429
|
}
|
|
40135
40430
|
if (url.pathname === "/api/documents") {
|
|
40136
40431
|
const folder = folderPath(url.searchParams.get("path"), root, lockedRoot);
|
|
40137
|
-
const target = lockedTarget ? documentTarget(folder,
|
|
40432
|
+
const target = lockedTarget ? documentTarget(folder, relative13(folder, lockedTarget), lockedTarget) : undefined;
|
|
40138
40433
|
const dataset = lockedTarget ? {
|
|
40139
40434
|
root: folder,
|
|
40140
40435
|
documents: target ? [
|
|
40141
40436
|
{
|
|
40142
|
-
path:
|
|
40437
|
+
path: relative13(folder, target.path),
|
|
40143
40438
|
kind: target.kind,
|
|
40144
|
-
content: previewTextKind(target.kind) ? await
|
|
40439
|
+
content: previewTextKind(target.kind) ? await readFile12(target.path, "utf8") : ""
|
|
40145
40440
|
}
|
|
40146
40441
|
] : []
|
|
40147
40442
|
} : await readFolder(folder);
|
|
@@ -40157,7 +40452,7 @@ function createFolderApi({
|
|
|
40157
40452
|
documentError(response);
|
|
40158
40453
|
return;
|
|
40159
40454
|
}
|
|
40160
|
-
const details = await
|
|
40455
|
+
const details = await stat11(target.path);
|
|
40161
40456
|
if (!details.isFile()) {
|
|
40162
40457
|
documentError(response);
|
|
40163
40458
|
return;
|
|
@@ -40169,16 +40464,16 @@ function createFolderApi({
|
|
|
40169
40464
|
return;
|
|
40170
40465
|
}
|
|
40171
40466
|
watch(folder);
|
|
40172
|
-
const content = previewTextKind(target.kind) ? await
|
|
40467
|
+
const content = previewTextKind(target.kind) ? await readFile12(target.path, "utf8") : "";
|
|
40173
40468
|
sendContract(response, url, {
|
|
40174
40469
|
content,
|
|
40175
40470
|
kind: target.kind,
|
|
40176
|
-
path:
|
|
40471
|
+
path: relative13(target.root, target.path),
|
|
40177
40472
|
root: folder,
|
|
40178
40473
|
...previewTextKind(target.kind) ? {} : {
|
|
40179
40474
|
rawUrl: `/api/raw?${new URLSearchParams({
|
|
40180
40475
|
path: folder,
|
|
40181
|
-
file:
|
|
40476
|
+
file: relative13(target.root, target.path)
|
|
40182
40477
|
})}`
|
|
40183
40478
|
}
|
|
40184
40479
|
}, {
|
|
@@ -40198,7 +40493,7 @@ function createFolderApi({
|
|
|
40198
40493
|
documentError(response);
|
|
40199
40494
|
return;
|
|
40200
40495
|
}
|
|
40201
|
-
const details = await
|
|
40496
|
+
const details = await stat11(target.path);
|
|
40202
40497
|
if (!details.isFile()) {
|
|
40203
40498
|
documentError(response);
|
|
40204
40499
|
return;
|
|
@@ -40222,7 +40517,7 @@ function createFolderApi({
|
|
|
40222
40517
|
"Content-Disposition": `attachment; filename="${basename8(target.path)}"`
|
|
40223
40518
|
} : {}
|
|
40224
40519
|
});
|
|
40225
|
-
response.end(await
|
|
40520
|
+
response.end(await readFile12(target.path));
|
|
40226
40521
|
} catch (error) {
|
|
40227
40522
|
documentError(response);
|
|
40228
40523
|
}
|
|
@@ -40236,7 +40531,7 @@ function createFolderApi({
|
|
|
40236
40531
|
documentError(response);
|
|
40237
40532
|
return;
|
|
40238
40533
|
}
|
|
40239
|
-
const details = await
|
|
40534
|
+
const details = await stat11(target.path);
|
|
40240
40535
|
if (!details.isFile()) {
|
|
40241
40536
|
documentError(response);
|
|
40242
40537
|
return;
|
|
@@ -40248,7 +40543,7 @@ function createFolderApi({
|
|
|
40248
40543
|
return;
|
|
40249
40544
|
}
|
|
40250
40545
|
watch(folder);
|
|
40251
|
-
const data = await
|
|
40546
|
+
const data = await readFile12(target.path);
|
|
40252
40547
|
const baseHeaders = {
|
|
40253
40548
|
"Accept-Ranges": "bytes",
|
|
40254
40549
|
"Cache-Control": "private, max-age=0, must-revalidate",
|
|
@@ -40411,7 +40706,7 @@ function createFolderApi({
|
|
|
40411
40706
|
workspace.breadcrumbs = await workspaceBreadcrumbIcons(workspace.breadcrumbs ?? [], assetFiles);
|
|
40412
40707
|
const files = [
|
|
40413
40708
|
workspace.configPath,
|
|
40414
|
-
|
|
40709
|
+
resolve16(workspace.root, "raggle.json")
|
|
40415
40710
|
].filter((path) => Boolean(path));
|
|
40416
40711
|
for (const path of files)
|
|
40417
40712
|
contexts.add(path);
|
|
@@ -40552,7 +40847,7 @@ function createFolderApi({
|
|
|
40552
40847
|
}
|
|
40553
40848
|
};
|
|
40554
40849
|
}
|
|
40555
|
-
var applyProjectFavorites, buildProjectCatalog, buildProjectSearchIndex, catalogProjectToLocalProject, discoverProjectIcon, discoverProjectsUnderFolder, listLocalMarkdownFiles, projectRepositoryAccessory, projectSubtitle, projectTitle, readRaggleUserSettings, gitRemoteUrl, githubRepositoryPath, repositoryDisplayName, searchProjectIndex, sortProjectList, projectSearchCacheMs = 5000, metadataExtensions, loopbackServerHosts, canonicalPath = (path) =>
|
|
40850
|
+
var applyProjectFavorites, buildProjectCatalog, buildProjectSearchIndex, catalogProjectToLocalProject, discoverProjectIcon, discoverProjectsUnderFolder, listLocalMarkdownFiles, projectRepositoryAccessory, projectSubtitle, projectTitle, readRaggleUserSettings, gitRemoteUrl, githubRepositoryPath, repositoryDisplayName, searchProjectIndex, sortProjectList, projectSearchCacheMs = 5000, metadataExtensions, loopbackServerHosts, canonicalPath = (path) => realpath8(path).catch(() => path);
|
|
40556
40851
|
var init_folder_metadata_plugin = __esm(() => {
|
|
40557
40852
|
init_contracts();
|
|
40558
40853
|
init_markdown();
|
|
@@ -40616,29 +40911,29 @@ var init_folder_metadata_plugin = __esm(() => {
|
|
|
40616
40911
|
import {
|
|
40617
40912
|
createServer
|
|
40618
40913
|
} from "node:http";
|
|
40619
|
-
import { readFile as
|
|
40620
|
-
import { extname as extname7, isAbsolute as isAbsolute8, relative as
|
|
40914
|
+
import { readFile as readFile13, realpath as realpath9, stat as stat12 } from "node:fs/promises";
|
|
40915
|
+
import { extname as extname7, isAbsolute as isAbsolute8, relative as relative14, resolve as resolve17 } from "node:path";
|
|
40621
40916
|
async function sendFile(request, response, directory, pathname, fallback) {
|
|
40622
|
-
const root = await
|
|
40917
|
+
const root = await realpath9(directory);
|
|
40623
40918
|
const inside = (path) => {
|
|
40624
|
-
const local =
|
|
40919
|
+
const local = relative14(root, path);
|
|
40625
40920
|
return local !== ".." && !local.startsWith("../") && !isAbsolute8(local);
|
|
40626
40921
|
};
|
|
40627
|
-
let target =
|
|
40922
|
+
let target = resolve17(root, `.${decodeURIComponent(pathname)}`);
|
|
40628
40923
|
if (!inside(target)) {
|
|
40629
40924
|
response.writeHead(403);
|
|
40630
40925
|
response.end();
|
|
40631
40926
|
return;
|
|
40632
40927
|
}
|
|
40633
|
-
if (!(await
|
|
40928
|
+
if (!(await stat12(target).catch(() => null))?.isFile()) {
|
|
40634
40929
|
if (!fallback) {
|
|
40635
40930
|
response.writeHead(404);
|
|
40636
40931
|
response.end();
|
|
40637
40932
|
return;
|
|
40638
40933
|
}
|
|
40639
|
-
target =
|
|
40934
|
+
target = resolve17(root, fallback);
|
|
40640
40935
|
}
|
|
40641
|
-
target = await
|
|
40936
|
+
target = await realpath9(target);
|
|
40642
40937
|
if (!inside(target)) {
|
|
40643
40938
|
response.writeHead(403);
|
|
40644
40939
|
response.end();
|
|
@@ -40648,7 +40943,7 @@ async function sendFile(request, response, directory, pathname, fallback) {
|
|
|
40648
40943
|
"Content-Type": contentTypes[extname7(target)] ?? "application/octet-stream",
|
|
40649
40944
|
"X-Content-Type-Options": "nosniff"
|
|
40650
40945
|
});
|
|
40651
|
-
response.end(request.method === "HEAD" ? undefined : await
|
|
40946
|
+
response.end(request.method === "HEAD" ? undefined : await readFile13(target));
|
|
40652
40947
|
}
|
|
40653
40948
|
function createKennelApi(options) {
|
|
40654
40949
|
const remote = options.remoteAccess || !isLoopbackServerHost(options.host);
|
|
@@ -40800,7 +41095,7 @@ data: ${JSON.stringify(event.data)}
|
|
|
40800
41095
|
};
|
|
40801
41096
|
}
|
|
40802
41097
|
var contentTypes;
|
|
40803
|
-
var
|
|
41098
|
+
var init_server5 = __esm(() => {
|
|
40804
41099
|
init_watcher();
|
|
40805
41100
|
init_folder_metadata_plugin();
|
|
40806
41101
|
contentTypes = {
|
|
@@ -40820,18 +41115,31 @@ var init_server4 = __esm(() => {
|
|
|
40820
41115
|
};
|
|
40821
41116
|
});
|
|
40822
41117
|
|
|
41118
|
+
// packages/preview/src/share.ts
|
|
41119
|
+
import { dirname as dirname16, resolve as resolve19, join as join7 } from "node:path";
|
|
41120
|
+
import { homedir as homedir5 } from "node:os";
|
|
41121
|
+
import { readFileSync as readFileSync2 } from "node:fs";
|
|
41122
|
+
import { existsSync as existsSync8, realpathSync as realpathSync5 } from "node:fs";
|
|
41123
|
+
import { fileURLToPath as fileURLToPath5 } from "node:url";
|
|
41124
|
+
|
|
40823
41125
|
// packages/preview/src/viewer.ts
|
|
40824
|
-
|
|
40825
|
-
|
|
41126
|
+
init_document_kinds();
|
|
41127
|
+
init_viewer_route();
|
|
41128
|
+
init_runtime();
|
|
41129
|
+
import { execFileSync as execFileSync2 } from "node:child_process";
|
|
41130
|
+
import { existsSync as existsSync7, realpathSync as realpathSync4, statSync as statSync3 } from "node:fs";
|
|
40826
41131
|
import { createServer as createServer2 } from "node:net";
|
|
40827
|
-
import { dirname as
|
|
40828
|
-
import { fileURLToPath as
|
|
41132
|
+
import { dirname as dirname15, isAbsolute as isAbsolute9, relative as relative15, resolve as resolve18 } from "node:path";
|
|
41133
|
+
import { fileURLToPath as fileURLToPath4 } from "node:url";
|
|
41134
|
+
var loopbackHosts = new Set([
|
|
41135
|
+
"127.0.0.1",
|
|
41136
|
+
"::1",
|
|
41137
|
+
"::ffff:127.0.0.1",
|
|
41138
|
+
"localhost"
|
|
41139
|
+
]);
|
|
40829
41140
|
function isLoopbackHost(host) {
|
|
40830
41141
|
return loopbackHosts.has(host) || host.startsWith("127.");
|
|
40831
41142
|
}
|
|
40832
|
-
function encodeBase64Url2(value) {
|
|
40833
|
-
return Buffer.from(value, "utf8").toString("base64").replaceAll("+", "-").replaceAll("/", "_").replaceAll("=", "");
|
|
40834
|
-
}
|
|
40835
41143
|
function splitViewerArgs(input) {
|
|
40836
41144
|
let hasHost = false;
|
|
40837
41145
|
let hasRoot = false;
|
|
@@ -40907,8 +41215,8 @@ function splitViewerArgs(input) {
|
|
|
40907
41215
|
}
|
|
40908
41216
|
if (arg.startsWith("-"))
|
|
40909
41217
|
throw new Error(`Unknown viewer option: ${arg}`);
|
|
40910
|
-
const candidate =
|
|
40911
|
-
const isDirectory =
|
|
41218
|
+
const candidate = resolve18(arg);
|
|
41219
|
+
const isDirectory = existsSync7(candidate) && statSync3(candidate).isDirectory();
|
|
40912
41220
|
if (isDirectory) {
|
|
40913
41221
|
if (hasRoot)
|
|
40914
41222
|
throw new Error("kennel accepts one folder");
|
|
@@ -40918,7 +41226,7 @@ function splitViewerArgs(input) {
|
|
|
40918
41226
|
}
|
|
40919
41227
|
if (hasRoot)
|
|
40920
41228
|
throw new Error("kennel accepts one folder");
|
|
40921
|
-
options.root =
|
|
41229
|
+
options.root = dirname15(candidate);
|
|
40922
41230
|
options.target = candidate;
|
|
40923
41231
|
hasRoot = true;
|
|
40924
41232
|
}
|
|
@@ -40937,7 +41245,7 @@ function splitViewerArgs(input) {
|
|
|
40937
41245
|
}
|
|
40938
41246
|
if (options.lan)
|
|
40939
41247
|
options.host = "0.0.0.0";
|
|
40940
|
-
if (!
|
|
41248
|
+
if (!existsSync7(options.root) || !statSync3(options.root).isDirectory()) {
|
|
40941
41249
|
throw new Error(`Folder not found: ${options.root}`);
|
|
40942
41250
|
}
|
|
40943
41251
|
if (options.target) {
|
|
@@ -40954,23 +41262,18 @@ function splitViewerArgs(input) {
|
|
|
40954
41262
|
function popUrl(host, port, options) {
|
|
40955
41263
|
const scheme = options.tailscale ? "https" : "http";
|
|
40956
41264
|
const authority = options.tailscale ? host : `${host}:${port}`;
|
|
40957
|
-
|
|
40958
|
-
|
|
40959
|
-
|
|
40960
|
-
|
|
40961
|
-
}
|
|
40962
|
-
url.pathname = `/folder/${encodeBase64Url2(options.root)}/document/${encodeBase64Url2(relative14(options.root, options.target))}`;
|
|
40963
|
-
if (options.watch)
|
|
40964
|
-
url.searchParams.set("watch", "1");
|
|
40965
|
-
return url.href;
|
|
41265
|
+
return folderUrl(`${scheme}://${authority}/`, options.root, {
|
|
41266
|
+
document: options.target ? relative15(options.root, options.target) : undefined,
|
|
41267
|
+
watch: options.watch
|
|
41268
|
+
}).href;
|
|
40966
41269
|
}
|
|
40967
41270
|
function viewerPortWasExplicit(input) {
|
|
40968
41271
|
return input.some((arg) => arg === "--port" || arg.startsWith("--port="));
|
|
40969
41272
|
}
|
|
40970
41273
|
function isSameOrDescendant(parent, child) {
|
|
40971
|
-
const parentReal =
|
|
40972
|
-
const childReal =
|
|
40973
|
-
const childRelative =
|
|
41274
|
+
const parentReal = realpathSync4(parent);
|
|
41275
|
+
const childReal = realpathSync4(child);
|
|
41276
|
+
const childRelative = relative15(parentReal, childReal);
|
|
40974
41277
|
return childRelative === "" || !childRelative.startsWith("..") && !isAbsolute9(childRelative);
|
|
40975
41278
|
}
|
|
40976
41279
|
async function runningViewer(url) {
|
|
@@ -41004,13 +41307,13 @@ async function availableViewerPort(start, host) {
|
|
|
41004
41307
|
throw new Error(`Kennel could not find a free port at or above ${start}`);
|
|
41005
41308
|
}
|
|
41006
41309
|
function lanHost2() {
|
|
41007
|
-
const route =
|
|
41310
|
+
const route = execFileSync2("/sbin/route", ["-n", "get", "default"], {
|
|
41008
41311
|
encoding: "utf8"
|
|
41009
41312
|
});
|
|
41010
41313
|
const device = route.match(/interface:\s+(\S+)/)?.[1];
|
|
41011
41314
|
if (!device)
|
|
41012
41315
|
throw new Error("kennel could not find the local network interface");
|
|
41013
|
-
const host =
|
|
41316
|
+
const host = execFileSync2("/usr/sbin/ipconfig", ["getifaddr", device], {
|
|
41014
41317
|
encoding: "utf8"
|
|
41015
41318
|
}).trim();
|
|
41016
41319
|
if (!host)
|
|
@@ -41018,7 +41321,7 @@ function lanHost2() {
|
|
|
41018
41321
|
return host;
|
|
41019
41322
|
}
|
|
41020
41323
|
function tailscaleHost() {
|
|
41021
|
-
const status = JSON.parse(
|
|
41324
|
+
const status = JSON.parse(execFileSync2("tailscale", ["status", "--json"], { encoding: "utf8" }));
|
|
41022
41325
|
const host = typeof status.Self?.DNSName === "string" ? status.Self.DNSName.replace(/\.$/, "") : "";
|
|
41023
41326
|
if (host)
|
|
41024
41327
|
return host;
|
|
@@ -41032,13 +41335,13 @@ async function viewer(input) {
|
|
|
41032
41335
|
await hotViewer(options);
|
|
41033
41336
|
return;
|
|
41034
41337
|
}
|
|
41035
|
-
const web =
|
|
41036
|
-
if (!
|
|
41338
|
+
const web = resolve18(dirname15(fileURLToPath4(import.meta.url)), "../../web");
|
|
41339
|
+
if (!existsSync7(resolve18(web, "index.html"))) {
|
|
41037
41340
|
throw new Error(`Kennel web app not found. Run the CLI build first.`);
|
|
41038
41341
|
}
|
|
41039
41342
|
const remote = options.tailscale || !isLoopbackHost(options.host);
|
|
41040
|
-
const lockedTarget = options.target ?
|
|
41041
|
-
await Promise.resolve().then(() =>
|
|
41343
|
+
const lockedTarget = options.target ? realpathSync4(options.target) : undefined;
|
|
41344
|
+
await Promise.resolve().then(() => init_server5());
|
|
41042
41345
|
const displayHost = options.tailscale ? tailscaleHost() : options.lan ? lanHost2() : options.host;
|
|
41043
41346
|
if (remote)
|
|
41044
41347
|
process.env.KENNEL_VIEWER_HOSTS = [
|
|
@@ -41049,18 +41352,9 @@ async function viewer(input) {
|
|
|
41049
41352
|
const existing = await runningViewer(initialViewerUrl);
|
|
41050
41353
|
if (existing && isSameOrDescendant(existing.root, options.root)) {
|
|
41051
41354
|
const viewerUrl = popUrl(displayHost, options.port, options);
|
|
41052
|
-
|
|
41053
|
-
await Promise.resolve().then(() => init_share());
|
|
41054
|
-
return startPreviewShare(options);
|
|
41055
|
-
});
|
|
41355
|
+
console.log(viewerUrl);
|
|
41056
41356
|
if (options.open)
|
|
41057
41357
|
openPreview(viewerUrl);
|
|
41058
|
-
try {
|
|
41059
|
-
if (terminal.interactive)
|
|
41060
|
-
await terminal.closed;
|
|
41061
|
-
} finally {
|
|
41062
|
-
terminal.close();
|
|
41063
|
-
}
|
|
41064
41358
|
return;
|
|
41065
41359
|
}
|
|
41066
41360
|
if (!portExplicit) {
|
|
@@ -41077,38 +41371,25 @@ async function viewer(input) {
|
|
|
41077
41371
|
try {
|
|
41078
41372
|
await api.listen(Number(options.port));
|
|
41079
41373
|
if (options.tailscale) {
|
|
41080
|
-
|
|
41374
|
+
execFileSync2("tailscale", ["serve", "--bg", "--yes", options.port]);
|
|
41081
41375
|
}
|
|
41082
41376
|
const viewerUrl = popUrl(displayHost, options.port, options);
|
|
41083
|
-
const
|
|
41084
|
-
await Promise.resolve().then(() => init_share());
|
|
41085
|
-
return startPreviewShare(options);
|
|
41086
|
-
});
|
|
41087
|
-
if (options.open)
|
|
41088
|
-
openPreview(viewerUrl);
|
|
41377
|
+
const lifetime = viewerLifetime();
|
|
41089
41378
|
try {
|
|
41090
|
-
|
|
41379
|
+
console.log(viewerUrl);
|
|
41380
|
+
if (options.open)
|
|
41381
|
+
openPreview(viewerUrl);
|
|
41382
|
+
await lifetime.closed;
|
|
41091
41383
|
} finally {
|
|
41092
|
-
|
|
41384
|
+
lifetime.close();
|
|
41093
41385
|
}
|
|
41094
41386
|
} finally {
|
|
41095
41387
|
await api.close();
|
|
41096
41388
|
}
|
|
41097
41389
|
if (options.tailscale) {
|
|
41098
|
-
|
|
41390
|
+
execFileSync2("tailscale", ["serve", "--https=443", "off"]);
|
|
41099
41391
|
}
|
|
41100
41392
|
}
|
|
41101
|
-
var loopbackHosts;
|
|
41102
|
-
var init_viewer = __esm(() => {
|
|
41103
|
-
init_document_kinds();
|
|
41104
|
-
init_terminal();
|
|
41105
|
-
loopbackHosts = new Set([
|
|
41106
|
-
"127.0.0.1",
|
|
41107
|
-
"::1",
|
|
41108
|
-
"::ffff:127.0.0.1",
|
|
41109
|
-
"localhost"
|
|
41110
|
-
]);
|
|
41111
|
-
});
|
|
41112
41393
|
|
|
41113
41394
|
// packages/preview/src/protected-share.ts
|
|
41114
41395
|
import { createHash as createHash6, randomBytes, timingSafeEqual } from "node:crypto";
|
|
@@ -41169,11 +41450,11 @@ async function startProtectedShare(handle) {
|
|
|
41169
41450
|
throw error;
|
|
41170
41451
|
}
|
|
41171
41452
|
}
|
|
41172
|
-
var init_protected_share = () => {};
|
|
41173
41453
|
|
|
41174
41454
|
// packages/preview/src/tailscale-share.ts
|
|
41175
41455
|
import { execFile as execFile7 } from "node:child_process";
|
|
41176
41456
|
import { promisify as promisify2 } from "node:util";
|
|
41457
|
+
var run2 = promisify2(execFile7);
|
|
41177
41458
|
async function serveConfig() {
|
|
41178
41459
|
const { stdout } = await run2("tailscale", ["serve", "status", "--json"]);
|
|
41179
41460
|
return JSON.parse(stdout);
|
|
@@ -41213,17 +41494,9 @@ async function startTailscaleProxy(host, port) {
|
|
|
41213
41494
|
throw error;
|
|
41214
41495
|
}
|
|
41215
41496
|
}
|
|
41216
|
-
var run2;
|
|
41217
|
-
var init_tailscale_share = __esm(() => {
|
|
41218
|
-
run2 = promisify2(execFile7);
|
|
41219
|
-
});
|
|
41220
41497
|
|
|
41221
41498
|
// packages/preview/src/share.ts
|
|
41222
|
-
|
|
41223
|
-
import { homedir as homedir5 } from "node:os";
|
|
41224
|
-
import { readFileSync as readFileSync2 } from "node:fs";
|
|
41225
|
-
import { existsSync as existsSync7, realpathSync as realpathSync4 } from "node:fs";
|
|
41226
|
-
import { fileURLToPath as fileURLToPath4 } from "node:url";
|
|
41499
|
+
var plainViewerPort = "5180";
|
|
41227
41500
|
function splitShareArgs(input) {
|
|
41228
41501
|
const options = {
|
|
41229
41502
|
folder: undefined,
|
|
@@ -41275,10 +41548,10 @@ function splitShareArgs(input) {
|
|
|
41275
41548
|
if (options.port && !/^\d+$/.test(options.port)) {
|
|
41276
41549
|
throw new Error("kennel share requires a numeric port");
|
|
41277
41550
|
}
|
|
41278
|
-
if (folder && !
|
|
41551
|
+
if (folder && !existsSync8(folder)) {
|
|
41279
41552
|
throw new Error(`Folder not found: ${folder}`);
|
|
41280
41553
|
}
|
|
41281
|
-
options.folder = folder ?
|
|
41554
|
+
options.folder = folder ? resolve19(folder) : undefined;
|
|
41282
41555
|
return options;
|
|
41283
41556
|
}
|
|
41284
41557
|
async function runningViewerRoot(port = plainViewerPort) {
|
|
@@ -41298,27 +41571,27 @@ async function runningViewerRoot(port = plainViewerPort) {
|
|
|
41298
41571
|
return;
|
|
41299
41572
|
}
|
|
41300
41573
|
async function startPreviewShare(target) {
|
|
41301
|
-
const root =
|
|
41302
|
-
const configPath =
|
|
41574
|
+
const root = realpathSync5(target.root);
|
|
41575
|
+
const configPath = join7(process.env.XDG_CONFIG_HOME?.trim() || join7(homedir5(), ".config"), "kennel", "config.json");
|
|
41303
41576
|
let configuredPassword = false;
|
|
41304
41577
|
try {
|
|
41305
41578
|
const config = JSON.parse(readFileSync2(configPath, "utf8"));
|
|
41306
41579
|
configuredPassword = config.linkSharing?.password === true;
|
|
41307
41580
|
} catch {}
|
|
41308
41581
|
const password = target.password ?? configuredPassword;
|
|
41309
|
-
const web =
|
|
41310
|
-
if (!
|
|
41582
|
+
const web = resolve19(dirname16(fileURLToPath5(import.meta.url)), "../../web");
|
|
41583
|
+
if (!existsSync8(resolve19(web, "index.html"))) {
|
|
41311
41584
|
throw new Error("Kennel web app not found. Run the CLI build first.");
|
|
41312
41585
|
}
|
|
41313
41586
|
const host = await tailscaleHostname();
|
|
41314
|
-
await Promise.resolve().then(() =>
|
|
41587
|
+
await Promise.resolve().then(() => init_server5());
|
|
41315
41588
|
process.env.KENNEL_VIEWER_HOSTS = [process.env.KENNEL_VIEWER_HOSTS, host].filter(Boolean).join(",");
|
|
41316
41589
|
const api = createKennelApi({
|
|
41317
41590
|
root,
|
|
41318
41591
|
host: "127.0.0.1",
|
|
41319
41592
|
remoteAccess: true,
|
|
41320
41593
|
restrictToRoot: true,
|
|
41321
|
-
lockedFile: target.target ?
|
|
41594
|
+
lockedFile: target.target ? realpathSync5(target.target) : undefined,
|
|
41322
41595
|
webRoot: web
|
|
41323
41596
|
});
|
|
41324
41597
|
let shared;
|
|
@@ -41398,7 +41671,7 @@ async function share(input) {
|
|
|
41398
41671
|
console.log(`Sharing ${folder}`);
|
|
41399
41672
|
if (options.dryRun) {
|
|
41400
41673
|
const port = options.port ?? "5181";
|
|
41401
|
-
const url = options.tailscale ? `https://<tailnet-name>.ts.net/folder/${Buffer.from(folder).toString("base64url")}
|
|
41674
|
+
const url = options.tailscale ? `https://<tailnet-name>.ts.net/folder/${Buffer.from(folder).toString("base64url")}` : popUrl(lanHost2(), port, { dryRun: true, host: "0.0.0.0", hot: false, lan: true, open: false, root: folder, port, tailscale: false, watch: false, password: false });
|
|
41402
41675
|
console.log(url);
|
|
41403
41676
|
console.log(`kennel serve --static ${options.tailscale ? "--tailscale" : "--lan"}${options.password ? " --password" : ""}${options.port ? ` --port ${options.port}` : ""} ${folder}`);
|
|
41404
41677
|
return;
|
|
@@ -41411,14 +41684,6 @@ async function share(input) {
|
|
|
41411
41684
|
folder
|
|
41412
41685
|
]);
|
|
41413
41686
|
}
|
|
41414
|
-
var plainViewerPort = "5180";
|
|
41415
|
-
var init_share = __esm(() => {
|
|
41416
|
-
init_viewer();
|
|
41417
|
-
init_protected_share();
|
|
41418
|
-
init_tailscale_share();
|
|
41419
|
-
});
|
|
41420
|
-
init_share();
|
|
41421
|
-
|
|
41422
41687
|
export {
|
|
41423
41688
|
plainViewerPort,
|
|
41424
41689
|
runningViewerRoot,
|