kennel 0.2.31 → 0.2.33
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/cli/dispatch.js +10 -0
- package/dist/cli/usage.js +9 -0
- package/dist/core/runtime.js +531 -197
- package/dist/llm/clipboard.d.ts +1 -0
- package/dist/llm/clipboard.js +59 -0
- package/dist/llm/command.d.ts +1 -0
- package/dist/llm/command.js +226 -0
- package/dist/llm/worker.d.ts +19 -0
- package/dist/llm/worker.js +1131 -0
- package/dist/notes/command.d.ts +1 -0
- package/dist/notes/command.js +556 -0
- package/dist/package/preview.js +554 -219
- package/dist/plugins/external.d.ts +6 -0
- package/dist/plugins/external.js +16 -0
- package/dist/site/server-plugins.d.ts +12 -0
- package/dist/site/server-plugins.js +132 -11
- package/package.json +4 -2
- package/schemas/config.schema.json +11 -0
- package/templates/plugin/package.json +1 -0
- package/templates/plugin/server.ts +43 -0
- package/templates/plugin/tsconfig.json +1 -1
- package/web/assets/{abnfDiagram-VRR7QNED-DPZyna8O.js → abnfDiagram-VRR7QNED-CpP1VHKI.js} +1 -1
- package/web/assets/{arc-BAcU9y_V.js → arc-kL4AxfvR.js} +1 -1
- package/web/assets/{architectureDiagram-ZJ3FMSHR-D5yd7Cag.js → architectureDiagram-ZJ3FMSHR-BWaRktRJ.js} +1 -1
- package/web/assets/{ask-tray-PMT6VVXN-C4dJH21Q.js → ask-tray-PMT6VVXN-FqPDpwtw.js} +3 -3
- package/web/assets/{blockDiagram-677ZJIJ3-C7LSGyxV.js → blockDiagram-677ZJIJ3-B07uVoPU.js} +1 -1
- package/web/assets/{c4Diagram-LMCZKHZV-BW2KfoQr.js → c4Diagram-LMCZKHZV-uvoaQC09.js} +1 -1
- package/web/assets/channel-Djmf1Ik1.js +1 -0
- package/web/assets/{chunk-2Q5K7J3B-4Og6VAFG.js → chunk-2Q5K7J3B-BH3SaHqk.js} +1 -1
- package/web/assets/{chunk-32BRIVSS-BYOowQl5.js → chunk-32BRIVSS-SPD8Eraw.js} +1 -1
- package/web/assets/{chunk-5VM5RSS4-C1m-lq64.js → chunk-5VM5RSS4-DNeOgOuZ.js} +1 -1
- package/web/assets/{chunk-EX3LRPZG-B2hriRpJ.js → chunk-EX3LRPZG-SJQ-vKGz.js} +1 -1
- package/web/assets/{chunk-JWPE2WC7-C6RsnzVA.js → chunk-JWPE2WC7-Dy_9wZ2Y.js} +1 -1
- package/web/assets/{chunk-MOJQB5TN-yKbMmUWf.js → chunk-MOJQB5TN-CuIx80Vn.js} +1 -1
- package/web/assets/{chunk-RYQCIY6F-BOokm3Qc.js → chunk-RYQCIY6F-DDG61RKR.js} +1 -1
- package/web/assets/{chunk-V7JOEXUC-CKW-H5An.js → chunk-V7JOEXUC-7OMVhaoH.js} +1 -1
- package/web/assets/{chunk-VR4S4FIN-BU5pFrup.js → chunk-VR4S4FIN-Y-HNaSmV.js} +1 -1
- package/web/assets/{chunk-XXDRQBXY-DYtdSJHU.js → chunk-XXDRQBXY-CtG0MPgC.js} +1 -1
- package/web/assets/classDiagram-OUVF2IWQ-hlDS9RWf.js +1 -0
- package/web/assets/classDiagram-v2-EOCWNBFH-hlDS9RWf.js +1 -0
- package/web/assets/{cose-bilkent-JH36ORCC-BZeXtC6E.js → cose-bilkent-JH36ORCC-BZaPMYcl.js} +1 -1
- package/web/assets/{cynefin-VYW2F7L2-BSDVyzMI.js → cynefin-VYW2F7L2-DxAlRHA1.js} +1 -1
- package/web/assets/{cynefinDiagram-TSTJHNR4-CReoDBYo.js → cynefinDiagram-TSTJHNR4-gjgzmagS.js} +1 -1
- package/web/assets/{dagre-VKFMJZFB-CBLLzMxd.js → dagre-VKFMJZFB-DvLPeYuw.js} +1 -1
- package/web/assets/{diagram-FQU43EPY-BcGWiZXZ.js → diagram-FQU43EPY-443LFnzG.js} +1 -1
- package/web/assets/{diagram-G47NLZAW-BXUYZA9N.js → diagram-G47NLZAW-CqfUewot.js} +1 -1
- package/web/assets/{diagram-NH7WQ7WH-BrvrZs7N.js → diagram-NH7WQ7WH-D-FElUGW.js} +1 -1
- package/web/assets/{diagram-OA4YK3LP-7lnVcjXL.js → diagram-OA4YK3LP-DbidUAp5.js} +1 -1
- package/web/assets/{diagram-WEI45ONY-s58_bMFf.js → diagram-WEI45ONY-CPLeckCZ.js} +1 -1
- package/web/assets/{ebnfDiagram-CCIWWBDH-BemWecoD.js → ebnfDiagram-CCIWWBDH-DR0rqZzN.js} +1 -1
- package/web/assets/{entity-search-page-G6QEQNXT--sKP5dP3.js → entity-search-page-G6QEQNXT-CnG8d-at.js} +1 -1
- package/web/assets/{erDiagram-Q63AITRT-ClVJddch.js → erDiagram-Q63AITRT-DMXv_8Tj.js} +1 -1
- package/web/assets/{flowDiagram-23GEKE2U-xzUJu-i_.js → flowDiagram-23GEKE2U-DnbQjZs0.js} +1 -1
- package/web/assets/{ganttDiagram-NO4QXBWP-CXQmtF5g.js → ganttDiagram-NO4QXBWP-DBKIrjj8.js} +1 -1
- package/web/assets/{gitGraphDiagram-IHSO6WYX-DCdljcLl.js → gitGraphDiagram-IHSO6WYX-BqqxKWT_.js} +1 -1
- package/web/assets/{index-CtTx1o2d.js → index-Bd3ghcW-.js} +5 -5
- package/web/assets/{index-vjrhIAJn.css → index-Dt8OzQCe.css} +1 -1
- package/web/assets/{infoDiagram-FWYZ7A6U-B11SJYSK.js → infoDiagram-FWYZ7A6U-Ba6Fs17y.js} +1 -1
- package/web/assets/{ishikawaDiagram-FXEZZL3T-B2CCGlAm.js → ishikawaDiagram-FXEZZL3T-D3BOtFjy.js} +1 -1
- package/web/assets/{journeyDiagram-5HDEW3XC-CBPETzOk.js → journeyDiagram-5HDEW3XC-MbzFPQm8.js} +1 -1
- package/web/assets/{kanban-definition-HUTT4EX6-unhQ3RPE.js → kanban-definition-HUTT4EX6-CurBmwu1.js} +1 -1
- package/web/assets/{linear-DuP_pG51.js → linear-CQIr4JjI.js} +1 -1
- package/web/assets/{linked-session-header-M7WY6IGF-DwlNCJlj.js → linked-session-header-M7WY6IGF-BBgN8zTq.js} +1 -1
- package/web/assets/{mermaid.core-BlYNzkpn.js → mermaid.core-bE6Vl3bZ.js} +4 -4
- package/web/assets/{mindmap-definition-LN4V7U3C-CtKHN6O1.js → mindmap-definition-LN4V7U3C-C1a46OGU.js} +1 -1
- package/web/assets/{pegDiagram-2B236MQR-CRyz6XWY.js → pegDiagram-2B236MQR-DZxMOxek.js} +1 -1
- package/web/assets/{pieDiagram-ENE6RG2P-BXfkPm3Q.js → pieDiagram-ENE6RG2P-BN0XOKLi.js} +1 -1
- package/web/assets/{plugin-host-modules-5NQgs5Cq.js → plugin-host-modules-CaRD5_5q.js} +1 -1
- package/web/assets/{project-search-dialog-HJFGW4DG-DPly4OiB.js → project-search-dialog-HJFGW4DG-h_dHeh7g.js} +1 -1
- package/web/assets/{project-search-page-NKQEBGPF-Cc6HV7BN.js → project-search-page-NKQEBGPF-2AzjjLEC.js} +1 -1
- package/web/assets/{quadrantDiagram-ABIIQ3AL-Drb_qWex.js → quadrantDiagram-ABIIQ3AL-C6IegTP-.js} +1 -1
- package/web/assets/{railroadDiagram-RFXS5EU6-DCKk2Pix.js → railroadDiagram-RFXS5EU6-bsjyAl-q.js} +1 -1
- package/web/assets/{requirementDiagram-TGXJPOKE-6WwZwcpD.js → requirementDiagram-TGXJPOKE-Cl8EZWy7.js} +1 -1
- package/web/assets/{sankeyDiagram-HTMAVEWB-DGGk3WCE.js → sankeyDiagram-HTMAVEWB-DhK4rRux.js} +1 -1
- package/web/assets/{selection-popup-532EHNCZ-yPhTrk7L.js → selection-popup-532EHNCZ-E2iQ2gQQ.js} +1 -1
- package/web/assets/{sequenceDiagram-DBY2YBRQ-a4tGi3DH.js → sequenceDiagram-DBY2YBRQ-DQTaPSD6.js} +1 -1
- package/web/assets/{sizeCapture-X5ZJPWSS-CHehBmy9.js → sizeCapture-X5ZJPWSS-k77bZ1zg.js} +1 -1
- package/web/assets/{stateDiagram-2N3HPSRC-Bn9GSWgV.js → stateDiagram-2N3HPSRC-Cv_5WuZJ.js} +1 -1
- package/web/assets/{stateDiagram-v2-6OUMAXLB-DI7fdBd7.js → stateDiagram-v2-6OUMAXLB-DJ1Lrskh.js} +1 -1
- package/web/assets/{swimlanes-5IMT3BWC-BX0WRzfR.js → swimlanes-5IMT3BWC-gBtAjG3z.js} +2 -2
- package/web/assets/swimlanesDiagram-G3AALYLV-DF1K9voG.js +8 -0
- package/web/assets/{timeline-definition-FHXFAJF6-9Ni2kIzq.js → timeline-definition-FHXFAJF6-CFjnM1Qq.js} +1 -1
- package/web/assets/{vennDiagram-L72KCM5P-rfBSNh3U.js → vennDiagram-L72KCM5P-CeMWrThY.js} +1 -1
- package/web/assets/{wardleyDiagram-EHGQE667-CzziImCC.js → wardleyDiagram-EHGQE667-R-ZaAOAI.js} +1 -1
- package/web/assets/{xychartDiagram-FW5EYKEG-DTLI4h5R.js → xychartDiagram-FW5EYKEG-BFXoMXiN.js} +1 -1
- package/web/index.html +2 -2
- package/web/assets/channel-um92dqpm.js +0 -1
- package/web/assets/classDiagram-OUVF2IWQ-h7sFEJBg.js +0 -1
- package/web/assets/classDiagram-v2-EOCWNBFH-h7sFEJBg.js +0 -1
- package/web/assets/swimlanesDiagram-G3AALYLV-OGHC9nqi.js +0 -8
package/dist/package/preview.js
CHANGED
|
@@ -38305,17 +38305,215 @@ var init_server2 = __esm(() => {
|
|
|
38305
38305
|
init_node3();
|
|
38306
38306
|
});
|
|
38307
38307
|
|
|
38308
|
-
// packages/
|
|
38309
|
-
import {
|
|
38308
|
+
// packages/notes/src/store.ts
|
|
38309
|
+
import { execFile as execFile2 } from "node:child_process";
|
|
38310
|
+
import {
|
|
38311
|
+
mkdir as mkdir3,
|
|
38312
|
+
readdir as readdir3,
|
|
38313
|
+
readFile as readFile5,
|
|
38314
|
+
realpath as realpath3,
|
|
38315
|
+
rename as rename2,
|
|
38316
|
+
rm as rm2,
|
|
38317
|
+
stat as stat3,
|
|
38318
|
+
writeFile as writeFile3
|
|
38319
|
+
} from "node:fs/promises";
|
|
38310
38320
|
import { homedir as homedir2 } from "node:os";
|
|
38321
|
+
import { basename as basename5, dirname as dirname6, join as join2, relative as relative7, resolve as resolve7, sep as sep4 } from "node:path";
|
|
38322
|
+
import { promisify } from "node:util";
|
|
38323
|
+
function kennelConfigHome() {
|
|
38324
|
+
const xdg = process.env.XDG_CONFIG_HOME?.trim();
|
|
38325
|
+
return xdg ? xdg : join2(homedir2(), ".config");
|
|
38326
|
+
}
|
|
38327
|
+
function kennelConfigFile() {
|
|
38328
|
+
return join2(kennelConfigHome(), "kennel", "config.json");
|
|
38329
|
+
}
|
|
38330
|
+
function repositoryNotesRoot() {
|
|
38331
|
+
return join2(kennelConfigHome(), "kennel", "repos");
|
|
38332
|
+
}
|
|
38333
|
+
function isRepositoryId(value) {
|
|
38334
|
+
return typeof value === "string" && UUID.test(value);
|
|
38335
|
+
}
|
|
38336
|
+
function managedNotesDirectory(id) {
|
|
38337
|
+
if (!isRepositoryId(id)) {
|
|
38338
|
+
throw new RepositoryNotesError("invalid-id", `Invalid repository id: ${id}`);
|
|
38339
|
+
}
|
|
38340
|
+
return join2(repositoryNotesRoot(), id);
|
|
38341
|
+
}
|
|
38342
|
+
async function readRepositoryNotesSettings() {
|
|
38343
|
+
const file = kennelConfigFile();
|
|
38344
|
+
let text;
|
|
38345
|
+
try {
|
|
38346
|
+
text = await readFile5(file, "utf8");
|
|
38347
|
+
} catch (error) {
|
|
38348
|
+
if (error.code === "ENOENT") {
|
|
38349
|
+
return { enabled: false };
|
|
38350
|
+
}
|
|
38351
|
+
throw new RepositoryNotesError("config-invalid", `Cannot read ${file}: ${errorMessage(error)}`);
|
|
38352
|
+
}
|
|
38353
|
+
let value;
|
|
38354
|
+
try {
|
|
38355
|
+
value = JSON.parse(text);
|
|
38356
|
+
} catch (error) {
|
|
38357
|
+
throw new RepositoryNotesError("config-invalid", `Invalid JSON in ${file}: ${errorMessage(error)}`);
|
|
38358
|
+
}
|
|
38359
|
+
if (!isRecord(value)) {
|
|
38360
|
+
throw new RepositoryNotesError("config-invalid", `${file} must hold an object`);
|
|
38361
|
+
}
|
|
38362
|
+
const section = value.repositoryNotes;
|
|
38363
|
+
if (section === undefined)
|
|
38364
|
+
return { enabled: false };
|
|
38365
|
+
if (!isRecord(section) || section.enabled !== undefined && typeof section.enabled !== "boolean") {
|
|
38366
|
+
throw new RepositoryNotesError("config-invalid", `${file}: repositoryNotes must be an object with a boolean "enabled" field`);
|
|
38367
|
+
}
|
|
38368
|
+
return { enabled: section.enabled === true };
|
|
38369
|
+
}
|
|
38370
|
+
async function git(args, cwd) {
|
|
38371
|
+
const { stdout } = await run("git", args, {
|
|
38372
|
+
cwd,
|
|
38373
|
+
env: { ...process.env, GIT_OPTIONAL_LOCKS: "0", GIT_TERMINAL_PROMPT: "0" },
|
|
38374
|
+
maxBuffer: 1024 * 1024
|
|
38375
|
+
});
|
|
38376
|
+
return stdout.replace(/\r?\n$/u, "");
|
|
38377
|
+
}
|
|
38378
|
+
function gitExitCode(error) {
|
|
38379
|
+
const code = error.code;
|
|
38380
|
+
return typeof code === "number" ? code : undefined;
|
|
38381
|
+
}
|
|
38382
|
+
async function resolveCheckout(folder) {
|
|
38383
|
+
let start;
|
|
38384
|
+
try {
|
|
38385
|
+
start = await realpath3(resolve7(folder));
|
|
38386
|
+
if (!(await stat3(start)).isDirectory())
|
|
38387
|
+
start = dirname6(start);
|
|
38388
|
+
} catch {
|
|
38389
|
+
throw new RepositoryNotesError("not-git", `Folder does not exist: ${folder}`);
|
|
38390
|
+
}
|
|
38391
|
+
let output;
|
|
38392
|
+
try {
|
|
38393
|
+
output = await git(["rev-parse", "--path-format=absolute", "--show-toplevel", "--git-common-dir"], start);
|
|
38394
|
+
} catch (error) {
|
|
38395
|
+
if (gitExitCode(error) === 128) {
|
|
38396
|
+
throw new RepositoryNotesError("not-git", `Not a Git repository: ${start}. Repository notes need a Git checkout.`);
|
|
38397
|
+
}
|
|
38398
|
+
throw error;
|
|
38399
|
+
}
|
|
38400
|
+
const [top, common] = output.split(/\r?\n/u);
|
|
38401
|
+
if (!top || !common) {
|
|
38402
|
+
throw new RepositoryNotesError("not-git", `Not a Git work tree: ${start}`);
|
|
38403
|
+
}
|
|
38404
|
+
const root = await realpath3(top);
|
|
38405
|
+
const commonDir = await realpath3(common);
|
|
38406
|
+
return { root, commonDir, configFile: join2(commonDir, "config") };
|
|
38407
|
+
}
|
|
38408
|
+
async function readBinding(checkout) {
|
|
38409
|
+
let value;
|
|
38410
|
+
try {
|
|
38411
|
+
value = await git(["config", "--file", checkout.configFile, "--get", REPOSITORY_ID_KEY], checkout.root);
|
|
38412
|
+
} catch (error) {
|
|
38413
|
+
if (gitExitCode(error) === 1)
|
|
38414
|
+
return;
|
|
38415
|
+
throw error;
|
|
38416
|
+
}
|
|
38417
|
+
const id = value.trim();
|
|
38418
|
+
if (!id)
|
|
38419
|
+
return;
|
|
38420
|
+
if (!isRepositoryId(id)) {
|
|
38421
|
+
throw new RepositoryNotesError("invalid-binding", `${checkout.configFile} has an invalid ${REPOSITORY_ID_KEY} value. Remove it or run "kennel notes new-identity".`);
|
|
38422
|
+
}
|
|
38423
|
+
return id;
|
|
38424
|
+
}
|
|
38425
|
+
function isRecord(value) {
|
|
38426
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
38427
|
+
}
|
|
38428
|
+
function errorMessage(error) {
|
|
38429
|
+
return error instanceof Error ? error.message : String(error);
|
|
38430
|
+
}
|
|
38431
|
+
async function lookupRepositoryNotes(folder) {
|
|
38432
|
+
let checkout;
|
|
38433
|
+
try {
|
|
38434
|
+
checkout = await resolveCheckout(folder);
|
|
38435
|
+
} catch (error) {
|
|
38436
|
+
if (error instanceof RepositoryNotesError && error.code === "not-git") {
|
|
38437
|
+
return { status: "not-git", folder };
|
|
38438
|
+
}
|
|
38439
|
+
throw error;
|
|
38440
|
+
}
|
|
38441
|
+
const id = await readBinding(checkout);
|
|
38442
|
+
if (!id)
|
|
38443
|
+
return { status: "unregistered", checkout, root: checkout.root };
|
|
38444
|
+
return {
|
|
38445
|
+
status: "registered",
|
|
38446
|
+
checkout,
|
|
38447
|
+
id,
|
|
38448
|
+
notesDirectory: managedNotesDirectory(id),
|
|
38449
|
+
root: checkout.root
|
|
38450
|
+
};
|
|
38451
|
+
}
|
|
38452
|
+
async function listManagedNotes(directory) {
|
|
38453
|
+
const notes = [];
|
|
38454
|
+
const visit = async (current) => {
|
|
38455
|
+
let entries;
|
|
38456
|
+
try {
|
|
38457
|
+
entries = await readdir3(current, { withFileTypes: true });
|
|
38458
|
+
} catch (error) {
|
|
38459
|
+
if (error.code === "ENOENT")
|
|
38460
|
+
return;
|
|
38461
|
+
throw error;
|
|
38462
|
+
}
|
|
38463
|
+
for (const entry of entries) {
|
|
38464
|
+
if (entry.name.startsWith(".") || entry.isSymbolicLink())
|
|
38465
|
+
continue;
|
|
38466
|
+
const path = join2(current, entry.name);
|
|
38467
|
+
if (entry.isDirectory()) {
|
|
38468
|
+
await visit(path);
|
|
38469
|
+
continue;
|
|
38470
|
+
}
|
|
38471
|
+
if (!entry.isFile())
|
|
38472
|
+
continue;
|
|
38473
|
+
const dot = entry.name.lastIndexOf(".");
|
|
38474
|
+
const extension = dot === -1 ? "" : entry.name.slice(dot).toLowerCase();
|
|
38475
|
+
if (!markdownExtensions.has(extension))
|
|
38476
|
+
continue;
|
|
38477
|
+
const details = await stat3(path);
|
|
38478
|
+
notes.push({
|
|
38479
|
+
activityAt: details.mtimeMs,
|
|
38480
|
+
name: dot === -1 ? entry.name : entry.name.slice(0, dot),
|
|
38481
|
+
path,
|
|
38482
|
+
relativePath: relative7(directory, path).split(sep4).join("/"),
|
|
38483
|
+
size: details.size
|
|
38484
|
+
});
|
|
38485
|
+
}
|
|
38486
|
+
};
|
|
38487
|
+
await visit(directory);
|
|
38488
|
+
return notes.sort((left, right) => right.activityAt - left.activityAt);
|
|
38489
|
+
}
|
|
38490
|
+
var run, REPOSITORY_ID_KEY = "kennel.repoId", UUID, markdownExtensions, caseInsensitiveHosts, RepositoryNotesError;
|
|
38491
|
+
var init_store = __esm(() => {
|
|
38492
|
+
run = promisify(execFile2);
|
|
38493
|
+
UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/u;
|
|
38494
|
+
markdownExtensions = new Set([".md", ".markdown"]);
|
|
38495
|
+
caseInsensitiveHosts = new Set(["github.com", "gitlab.com", "bitbucket.org"]);
|
|
38496
|
+
RepositoryNotesError = class RepositoryNotesError extends Error {
|
|
38497
|
+
code;
|
|
38498
|
+
constructor(code, message) {
|
|
38499
|
+
super(message);
|
|
38500
|
+
this.name = "RepositoryNotesError";
|
|
38501
|
+
this.code = code;
|
|
38502
|
+
}
|
|
38503
|
+
};
|
|
38504
|
+
});
|
|
38505
|
+
|
|
38506
|
+
// packages/api/src/server/entity-folder.ts
|
|
38507
|
+
import { readdir as readdir4, readFile as readFile6, realpath as realpath4, stat as stat4 } from "node:fs/promises";
|
|
38508
|
+
import { homedir as homedir3 } from "node:os";
|
|
38311
38509
|
import {
|
|
38312
|
-
basename as
|
|
38313
|
-
dirname as
|
|
38510
|
+
basename as basename6,
|
|
38511
|
+
dirname as dirname7,
|
|
38314
38512
|
extname as extname2,
|
|
38315
38513
|
isAbsolute as isAbsolute4,
|
|
38316
|
-
join as
|
|
38317
|
-
relative as
|
|
38318
|
-
resolve as
|
|
38514
|
+
join as join3,
|
|
38515
|
+
relative as relative8,
|
|
38516
|
+
resolve as resolve8
|
|
38319
38517
|
} from "node:path";
|
|
38320
38518
|
function parseMarkdown(source) {
|
|
38321
38519
|
if (!source.startsWith(`---
|
|
@@ -38350,11 +38548,11 @@ function paragraph(body) {
|
|
|
38350
38548
|
}
|
|
38351
38549
|
function configPath() {
|
|
38352
38550
|
const xdg = process.env.XDG_CONFIG_HOME?.trim();
|
|
38353
|
-
return xdg ?
|
|
38551
|
+
return xdg ? join3(xdg, CONFIG_FILE) : join3(homedir3(), ".config", CONFIG_FILE);
|
|
38354
38552
|
}
|
|
38355
38553
|
async function readConfig(path) {
|
|
38356
38554
|
try {
|
|
38357
|
-
return parseConfig(await
|
|
38555
|
+
return parseConfig(await readFile6(path, "utf8"));
|
|
38358
38556
|
} catch (error) {
|
|
38359
38557
|
if (error && typeof error === "object" && "code" in error && error.code === "ENOENT")
|
|
38360
38558
|
return null;
|
|
@@ -38371,6 +38569,8 @@ function parseConfig(source) {
|
|
|
38371
38569
|
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
38372
38570
|
throw new Error("Invalid Kennel entity root config");
|
|
38373
38571
|
const roots = value.allowedRoots;
|
|
38572
|
+
if (roots === undefined)
|
|
38573
|
+
return {};
|
|
38374
38574
|
if (!Array.isArray(roots))
|
|
38375
38575
|
throw new Error("Invalid Kennel entity root config");
|
|
38376
38576
|
const allowedRoots = roots.map((root) => {
|
|
@@ -38382,12 +38582,12 @@ function parseConfig(source) {
|
|
|
38382
38582
|
}
|
|
38383
38583
|
async function allowedRoots(currentWorkspaceRoot) {
|
|
38384
38584
|
const config = await readConfig(configPath());
|
|
38385
|
-
if (config)
|
|
38585
|
+
if (config?.allowedRoots)
|
|
38386
38586
|
return config.allowedRoots;
|
|
38387
38587
|
return currentWorkspaceRoot?.trim() ? [currentWorkspaceRoot] : [];
|
|
38388
38588
|
}
|
|
38389
38589
|
function inside4(root, path) {
|
|
38390
|
-
const local =
|
|
38590
|
+
const local = relative8(root, path);
|
|
38391
38591
|
return local === "" || !local.startsWith("..") && !isAbsolute4(local);
|
|
38392
38592
|
}
|
|
38393
38593
|
async function normalizeRoot(rootPath, currentWorkspaceRoot) {
|
|
@@ -38395,13 +38595,13 @@ async function normalizeRoot(rootPath, currentWorkspaceRoot) {
|
|
|
38395
38595
|
const fallback = currentWorkspaceRoot?.trim();
|
|
38396
38596
|
if (!trimmed && !fallback)
|
|
38397
38597
|
return null;
|
|
38398
|
-
const requested =
|
|
38399
|
-
const resolved = await
|
|
38400
|
-
const info = await
|
|
38598
|
+
const requested = resolve8(trimmed || fallback);
|
|
38599
|
+
const resolved = await realpath4(requested);
|
|
38600
|
+
const info = await stat4(resolved);
|
|
38401
38601
|
if (!info.isDirectory())
|
|
38402
38602
|
throw new Error(`${resolved} is not a folder`);
|
|
38403
38603
|
const roots = await allowedRoots(currentWorkspaceRoot);
|
|
38404
|
-
const realAllowedRoots = await Promise.all(roots.map((root) =>
|
|
38604
|
+
const realAllowedRoots = await Promise.all(roots.map((root) => realpath4(root)));
|
|
38405
38605
|
const allowed = realAllowedRoots.some((root) => inside4(root, resolved));
|
|
38406
38606
|
if (!allowed)
|
|
38407
38607
|
throw new Error("Entity root is outside the configured roots");
|
|
@@ -38410,11 +38610,11 @@ async function normalizeRoot(rootPath, currentWorkspaceRoot) {
|
|
|
38410
38610
|
async function markdownFiles(folderPath) {
|
|
38411
38611
|
const files = [];
|
|
38412
38612
|
async function walk(currentPath) {
|
|
38413
|
-
const entries = await
|
|
38613
|
+
const entries = await readdir4(currentPath, { withFileTypes: true });
|
|
38414
38614
|
for (const entry of entries.sort((left, right) => left.name.localeCompare(right.name))) {
|
|
38415
38615
|
if (entry.name.startsWith(".") || IGNORED_DIRECTORIES.has(entry.name))
|
|
38416
38616
|
continue;
|
|
38417
|
-
const entryPath =
|
|
38617
|
+
const entryPath = join3(currentPath, entry.name);
|
|
38418
38618
|
if (entry.isDirectory()) {
|
|
38419
38619
|
if (entryPath !== folderPath && await hasIndex(entryPath))
|
|
38420
38620
|
continue;
|
|
@@ -38429,36 +38629,36 @@ async function markdownFiles(folderPath) {
|
|
|
38429
38629
|
return files;
|
|
38430
38630
|
}
|
|
38431
38631
|
async function hasIndex(folderPath) {
|
|
38432
|
-
return
|
|
38632
|
+
return stat4(join3(folderPath, "index.md")).then((value) => value.isFile()).catch(() => false);
|
|
38433
38633
|
}
|
|
38434
38634
|
async function schemaPath(folderPath, rootPath) {
|
|
38435
38635
|
let current = folderPath;
|
|
38436
38636
|
while (current === rootPath || current.startsWith(`${rootPath}/`)) {
|
|
38437
38637
|
for (const name of ["schema.json", "_schema.json"]) {
|
|
38438
|
-
const candidate =
|
|
38439
|
-
if (await
|
|
38638
|
+
const candidate = join3(current, name);
|
|
38639
|
+
if (await stat4(candidate).then((value) => value.isFile()).catch(() => false))
|
|
38440
38640
|
return candidate;
|
|
38441
38641
|
}
|
|
38442
38642
|
if (current === rootPath)
|
|
38443
38643
|
return null;
|
|
38444
|
-
current =
|
|
38644
|
+
current = dirname7(current);
|
|
38445
38645
|
}
|
|
38446
38646
|
return null;
|
|
38447
38647
|
}
|
|
38448
38648
|
async function readEntity(folderPath, rootPath) {
|
|
38449
|
-
const indexPath =
|
|
38450
|
-
const index = parseMarkdown(await
|
|
38649
|
+
const indexPath = join3(folderPath, "index.md");
|
|
38650
|
+
const index = parseMarkdown(await readFile6(indexPath, "utf8"));
|
|
38451
38651
|
const files = await markdownFiles(folderPath);
|
|
38452
38652
|
const documents = await Promise.all(files.map(async (filePath) => {
|
|
38453
|
-
const document2 = parseMarkdown(await
|
|
38653
|
+
const document2 = parseMarkdown(await readFile6(filePath, "utf8"));
|
|
38454
38654
|
return {
|
|
38455
38655
|
content: document2.body,
|
|
38456
|
-
path:
|
|
38457
|
-
title: stringValue(document2.frontmatter.title) ?? heading(document2.body) ??
|
|
38656
|
+
path: relative8(folderPath, filePath),
|
|
38657
|
+
title: stringValue(document2.frontmatter.title) ?? heading(document2.body) ?? basename6(filePath, extname2(filePath))
|
|
38458
38658
|
};
|
|
38459
38659
|
}));
|
|
38460
|
-
const title = stringValue(index.frontmatter.title) ?? heading(index.body) ??
|
|
38461
|
-
const relativePath =
|
|
38660
|
+
const title = stringValue(index.frontmatter.title) ?? heading(index.body) ?? basename6(folderPath);
|
|
38661
|
+
const relativePath = relative8(rootPath, folderPath) || ".";
|
|
38462
38662
|
return {
|
|
38463
38663
|
aliases: stringValues(index.frontmatter.aliases),
|
|
38464
38664
|
content: [
|
|
@@ -38486,11 +38686,11 @@ async function discover(rootPath) {
|
|
|
38486
38686
|
async function walk(folderPath) {
|
|
38487
38687
|
if (await hasIndex(folderPath))
|
|
38488
38688
|
folders.push(folderPath);
|
|
38489
|
-
const entries = await
|
|
38689
|
+
const entries = await readdir4(folderPath, { withFileTypes: true });
|
|
38490
38690
|
for (const entry of entries) {
|
|
38491
38691
|
if (!entry.isDirectory() || entry.name.startsWith(".") || IGNORED_DIRECTORIES.has(entry.name))
|
|
38492
38692
|
continue;
|
|
38493
|
-
await walk(
|
|
38693
|
+
await walk(join3(folderPath, entry.name));
|
|
38494
38694
|
}
|
|
38495
38695
|
}
|
|
38496
38696
|
await walk(rootPath);
|
|
@@ -38529,7 +38729,7 @@ async function loadEntityWorkspace(root, query, selectedPath, currentWorkspaceRo
|
|
|
38529
38729
|
var CONFIG_FILE, IGNORED_DIRECTORIES;
|
|
38530
38730
|
var init_entity_folder = __esm(() => {
|
|
38531
38731
|
init_dist3();
|
|
38532
|
-
CONFIG_FILE =
|
|
38732
|
+
CONFIG_FILE = join3("kennel", "config.json");
|
|
38533
38733
|
IGNORED_DIRECTORIES = new Set([
|
|
38534
38734
|
".git",
|
|
38535
38735
|
".gtl",
|
|
@@ -38549,20 +38749,20 @@ function replaceSelection(content, start, end, replacement) {
|
|
|
38549
38749
|
// packages/api/src/server/api/document-edit.ts
|
|
38550
38750
|
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
38551
38751
|
import {
|
|
38552
|
-
readFile as
|
|
38553
|
-
realpath as
|
|
38554
|
-
rename as
|
|
38555
|
-
stat as
|
|
38752
|
+
readFile as readFile7,
|
|
38753
|
+
realpath as realpath5,
|
|
38754
|
+
rename as rename3,
|
|
38755
|
+
stat as stat5,
|
|
38556
38756
|
unlink as unlink2,
|
|
38557
|
-
writeFile as
|
|
38757
|
+
writeFile as writeFile4
|
|
38558
38758
|
} from "node:fs/promises";
|
|
38559
38759
|
import {
|
|
38560
|
-
dirname as
|
|
38760
|
+
dirname as dirname8,
|
|
38561
38761
|
extname as extname3,
|
|
38562
38762
|
isAbsolute as isAbsolute5,
|
|
38563
|
-
relative as
|
|
38564
|
-
resolve as
|
|
38565
|
-
sep as
|
|
38763
|
+
relative as relative9,
|
|
38764
|
+
resolve as resolve9,
|
|
38765
|
+
sep as sep5
|
|
38566
38766
|
} from "node:path";
|
|
38567
38767
|
async function editDocument(folder, input) {
|
|
38568
38768
|
const { path, original, start, end, replacement } = input;
|
|
@@ -38570,10 +38770,10 @@ async function editDocument(folder, input) {
|
|
|
38570
38770
|
throw apiError("bad-request", "Invalid document edit.");
|
|
38571
38771
|
if (![".md", ".markdown"].includes(extname3(path).toLowerCase()))
|
|
38572
38772
|
throw apiError("bad-request", "Only Markdown notes can be edited.");
|
|
38573
|
-
const root = await
|
|
38574
|
-
const target = await
|
|
38575
|
-
const local =
|
|
38576
|
-
if (!local || local === ".." || local.startsWith(`..${
|
|
38773
|
+
const root = await realpath5(folder);
|
|
38774
|
+
const target = await realpath5(resolve9(root, path));
|
|
38775
|
+
const local = relative9(root, target);
|
|
38776
|
+
if (!local || local === ".." || local.startsWith(`..${sep5}`) || isAbsolute5(local))
|
|
38577
38777
|
throw apiError("forbidden", "The document must be inside its folder.");
|
|
38578
38778
|
let content;
|
|
38579
38779
|
try {
|
|
@@ -38583,20 +38783,20 @@ async function editDocument(folder, input) {
|
|
|
38583
38783
|
}
|
|
38584
38784
|
const previous = pending.get(target) ?? Promise.resolve();
|
|
38585
38785
|
const operation = previous.catch(() => {}).then(async () => {
|
|
38586
|
-
const details = await
|
|
38786
|
+
const details = await stat5(target);
|
|
38587
38787
|
if (!details.isFile() || details.nlink !== 1)
|
|
38588
38788
|
throw apiError("forbidden", "Only regular, unlinked files can be edited.");
|
|
38589
|
-
if (await
|
|
38789
|
+
if (await readFile7(target, "utf8") !== original)
|
|
38590
38790
|
throw apiError("conflict", "This note changed on disk. Close this preview, reload the note, and try again.");
|
|
38591
|
-
const temporary =
|
|
38791
|
+
const temporary = resolve9(dirname8(target), `.kennel-edit-${randomUUID3()}.tmp`);
|
|
38592
38792
|
try {
|
|
38593
|
-
await
|
|
38793
|
+
await writeFile4(temporary, content, {
|
|
38594
38794
|
flag: "wx",
|
|
38595
38795
|
mode: details.mode & 511
|
|
38596
38796
|
});
|
|
38597
|
-
if (await
|
|
38797
|
+
if (await readFile7(target, "utf8") !== original)
|
|
38598
38798
|
throw apiError("conflict", "This note changed on disk. Reload before applying an edit.");
|
|
38599
|
-
await
|
|
38799
|
+
await rename3(temporary, target);
|
|
38600
38800
|
} finally {
|
|
38601
38801
|
await unlink2(temporary).catch(() => {});
|
|
38602
38802
|
}
|
|
@@ -38624,7 +38824,7 @@ var init_document_edit = __esm(() => {
|
|
|
38624
38824
|
throw apiError("bad-request", "Invalid document edit.");
|
|
38625
38825
|
const input = parsed.data;
|
|
38626
38826
|
const folder = context.authorize(input.folder);
|
|
38627
|
-
if (context.lockedFile && (typeof input.path !== "string" || await
|
|
38827
|
+
if (context.lockedFile && (typeof input.path !== "string" || await realpath5(resolve9(folder, input.path)) !== context.lockedFile))
|
|
38628
38828
|
throw apiError("forbidden", "Only the selected document can be edited.");
|
|
38629
38829
|
await editDocument(folder, input);
|
|
38630
38830
|
jsonResponse(response, 200, routes.documentEdit.response.parse({ saved: true }));
|
|
@@ -38633,8 +38833,8 @@ var init_document_edit = __esm(() => {
|
|
|
38633
38833
|
});
|
|
38634
38834
|
|
|
38635
38835
|
// packages/api/src/server/api/create-agent-file.ts
|
|
38636
|
-
import { writeFile as
|
|
38637
|
-
import { resolve as
|
|
38836
|
+
import { writeFile as writeFile5 } from "node:fs/promises";
|
|
38837
|
+
import { resolve as resolve10 } from "node:path";
|
|
38638
38838
|
var createAgentFileRoute;
|
|
38639
38839
|
var init_create_agent_file = __esm(() => {
|
|
38640
38840
|
init_endpoint();
|
|
@@ -38648,9 +38848,9 @@ var init_create_agent_file = __esm(() => {
|
|
|
38648
38848
|
} catch (error) {
|
|
38649
38849
|
throw apiError("not-found", error instanceof Error ? error.message : "Folder not found");
|
|
38650
38850
|
}
|
|
38651
|
-
const target =
|
|
38851
|
+
const target = resolve10(folder, "AGENTS.md");
|
|
38652
38852
|
try {
|
|
38653
|
-
await
|
|
38853
|
+
await writeFile5(target, "", { flag: "wx" });
|
|
38654
38854
|
} catch (error) {
|
|
38655
38855
|
if (error && typeof error === "object" && "code" in error && error.code === "EEXIST") {
|
|
38656
38856
|
throw apiError("conflict", "AGENTS.md already exists in this folder");
|
|
@@ -38663,7 +38863,7 @@ var init_create_agent_file = __esm(() => {
|
|
|
38663
38863
|
});
|
|
38664
38864
|
|
|
38665
38865
|
// packages/api/src/server/api/open-path.ts
|
|
38666
|
-
import { execFile as
|
|
38866
|
+
import { execFile as execFile3 } from "node:child_process";
|
|
38667
38867
|
var openPathRoute;
|
|
38668
38868
|
var init_open_path = __esm(() => {
|
|
38669
38869
|
init_endpoint();
|
|
@@ -38677,7 +38877,7 @@ var init_open_path = __esm(() => {
|
|
|
38677
38877
|
throw apiError("not-found", error instanceof Error ? error.message : "Path not found");
|
|
38678
38878
|
}
|
|
38679
38879
|
await new Promise((done, fail) => {
|
|
38680
|
-
|
|
38880
|
+
execFile3("/usr/bin/open", [target], (error) => {
|
|
38681
38881
|
if (error)
|
|
38682
38882
|
fail(apiError("failed", "Could not open path"));
|
|
38683
38883
|
else
|
|
@@ -38696,11 +38896,11 @@ var init_favicon2 = __esm(() => {
|
|
|
38696
38896
|
});
|
|
38697
38897
|
|
|
38698
38898
|
// packages/api/src/server/folder-favicon.ts
|
|
38699
|
-
import { readFile as
|
|
38700
|
-
import { join as
|
|
38899
|
+
import { readFile as readFile8 } from "node:fs/promises";
|
|
38900
|
+
import { join as join4 } from "node:path";
|
|
38701
38901
|
async function folderWebsite(folder) {
|
|
38702
38902
|
for (const name of ["AGENTS.md", "README.md"]) {
|
|
38703
|
-
const content = await
|
|
38903
|
+
const content = await readFile8(join4(folder, name), "utf8").catch(() => "");
|
|
38704
38904
|
const entry = markdownMetadata(content).entries.find(([key]) => key === "website");
|
|
38705
38905
|
if (entry)
|
|
38706
38906
|
return websiteHost(entry[1]);
|
|
@@ -38714,7 +38914,7 @@ var init_folder_favicon = __esm(() => {
|
|
|
38714
38914
|
|
|
38715
38915
|
// packages/api/src/server/folder-icons.ts
|
|
38716
38916
|
import { createHash as createHash4 } from "node:crypto";
|
|
38717
|
-
import { readFile as
|
|
38917
|
+
import { readFile as readFile9, stat as stat6 } from "node:fs/promises";
|
|
38718
38918
|
import { extname as extname4 } from "node:path";
|
|
38719
38919
|
import { discoverFolderIcon } from "@raggle-ai/local";
|
|
38720
38920
|
function assetKey(value) {
|
|
@@ -38733,13 +38933,13 @@ function iconUrl(folder, hash, mediaType) {
|
|
|
38733
38933
|
async function folderIcon(folder, assets, assetFiles, fallback) {
|
|
38734
38934
|
const icon = discoverFolderIcon(folder);
|
|
38735
38935
|
const mediaType = icon ? iconTypes.get(extname4(icon).toLowerCase()) : null;
|
|
38736
|
-
const details = icon && mediaType ? await
|
|
38936
|
+
const details = icon && mediaType ? await stat6(icon).catch(() => {
|
|
38737
38937
|
return;
|
|
38738
38938
|
}) : undefined;
|
|
38739
38939
|
if (!icon || !mediaType || !details?.size || details.size > maxIconBytes2) {
|
|
38740
38940
|
return fallback ? await fallback(folder, assets) : undefined;
|
|
38741
38941
|
}
|
|
38742
|
-
const data = await
|
|
38942
|
+
const data = await readFile9(icon);
|
|
38743
38943
|
const hash = assetKey(data);
|
|
38744
38944
|
const key = `local:${hash}`;
|
|
38745
38945
|
assetFiles.set(hash, { mediaType, path: icon });
|
|
@@ -38758,12 +38958,12 @@ async function searchIconDataUrl(icon) {
|
|
|
38758
38958
|
const mediaType = searchIconTypes.get(extname4(icon).toLowerCase());
|
|
38759
38959
|
if (!mediaType)
|
|
38760
38960
|
return;
|
|
38761
|
-
const details = await
|
|
38961
|
+
const details = await stat6(icon).catch(() => {
|
|
38762
38962
|
return;
|
|
38763
38963
|
});
|
|
38764
38964
|
if (!details?.size || details.size > maxSearchIconBytes)
|
|
38765
38965
|
return;
|
|
38766
|
-
return `data:${mediaType};base64,${(await
|
|
38966
|
+
return `data:${mediaType};base64,${(await readFile9(icon)).toString("base64")}`;
|
|
38767
38967
|
}
|
|
38768
38968
|
async function faviconAsset(folderName, assets) {
|
|
38769
38969
|
if (process.env.KENNEL_EXTERNAL_ICONS !== "1")
|
|
@@ -38847,53 +39047,128 @@ var init_manifest = __esm(() => {
|
|
|
38847
39047
|
});
|
|
38848
39048
|
|
|
38849
39049
|
// packages/notes/src/server.ts
|
|
38850
|
-
import { readdir as
|
|
38851
|
-
import {
|
|
39050
|
+
import { readdir as readdir5, realpath as realpath6, stat as stat7 } from "node:fs/promises";
|
|
39051
|
+
import {
|
|
39052
|
+
basename as basename7,
|
|
39053
|
+
extname as extname5,
|
|
39054
|
+
isAbsolute as isAbsolute6,
|
|
39055
|
+
relative as relative10,
|
|
39056
|
+
resolve as resolve11,
|
|
39057
|
+
sep as sep6
|
|
39058
|
+
} from "node:path";
|
|
38852
39059
|
async function listMarkdownFiles(folder) {
|
|
38853
39060
|
const files = [];
|
|
38854
39061
|
const visit = async (current) => {
|
|
38855
|
-
const entries = await
|
|
39062
|
+
const entries = await readdir5(current, { withFileTypes: true }).catch(() => []);
|
|
38856
39063
|
for (const entry of entries) {
|
|
38857
39064
|
if (entry.name === "node_modules" || entry.name.startsWith("."))
|
|
38858
39065
|
continue;
|
|
38859
|
-
const path =
|
|
39066
|
+
const path = resolve11(current, entry.name);
|
|
38860
39067
|
if (entry.isDirectory()) {
|
|
38861
39068
|
await visit(path);
|
|
38862
39069
|
continue;
|
|
38863
39070
|
}
|
|
38864
|
-
if (!entry.isFile() || !
|
|
39071
|
+
if (!entry.isFile() || !markdownExtensions2.has(extname5(entry.name))) {
|
|
38865
39072
|
continue;
|
|
38866
39073
|
}
|
|
38867
|
-
const details = await
|
|
39074
|
+
const details = await stat7(path).catch(() => {
|
|
38868
39075
|
return;
|
|
38869
39076
|
});
|
|
38870
39077
|
files.push({
|
|
38871
39078
|
activityAt: details?.mtimeMs ?? 0,
|
|
38872
|
-
name:
|
|
38873
|
-
relativePath:
|
|
39079
|
+
name: basename7(entry.name, extname5(entry.name)),
|
|
39080
|
+
relativePath: relative10(folder, path).split(sep6).join("/")
|
|
38874
39081
|
});
|
|
38875
39082
|
}
|
|
38876
39083
|
};
|
|
38877
39084
|
await visit(folder);
|
|
38878
39085
|
return files.sort((left, right) => right.activityAt - left.activityAt);
|
|
38879
39086
|
}
|
|
38880
|
-
|
|
39087
|
+
function inside5(path, root) {
|
|
39088
|
+
const local = relative10(root, path);
|
|
39089
|
+
return local === "" || !local.startsWith("..") && !isAbsolute6(local);
|
|
39090
|
+
}
|
|
39091
|
+
async function withoutManaged(groups, managedRoots) {
|
|
39092
|
+
if (!managedRoots.length)
|
|
39093
|
+
return groups;
|
|
39094
|
+
const roots = await Promise.all(managedRoots.map(canonical));
|
|
39095
|
+
return Promise.all(groups.map(async (group) => {
|
|
39096
|
+
if (roots.includes(await canonical(group.folder))) {
|
|
39097
|
+
return { ...group, files: [] };
|
|
39098
|
+
}
|
|
39099
|
+
const files = await Promise.all(group.files.map(async (file) => {
|
|
39100
|
+
const real = await canonical(resolve11(group.folder, file.relativePath));
|
|
39101
|
+
return roots.some((root) => inside5(real, root)) ? undefined : file;
|
|
39102
|
+
}));
|
|
39103
|
+
return { ...group, files: files.filter((file) => file !== undefined) };
|
|
39104
|
+
}));
|
|
39105
|
+
}
|
|
39106
|
+
async function loadNotes(folder, linkedFolders = [], managedFolders = []) {
|
|
38881
39107
|
const localFiles = await listMarkdownFiles(folder);
|
|
38882
|
-
const
|
|
38883
|
-
files: await listMarkdownFiles(
|
|
38884
|
-
folder:
|
|
39108
|
+
const listGroups = (folders) => Promise.all(folders.map(async (source) => ({
|
|
39109
|
+
files: await listMarkdownFiles(source),
|
|
39110
|
+
folder: source
|
|
38885
39111
|
})));
|
|
39112
|
+
const [managed, linked] = await Promise.all([
|
|
39113
|
+
listGroups(managedFolders),
|
|
39114
|
+
listGroups(linkedFolders).then((groups) => withoutManaged(groups, managedFolders))
|
|
39115
|
+
]);
|
|
38886
39116
|
return {
|
|
38887
39117
|
files: {
|
|
38888
39118
|
items: [
|
|
38889
39119
|
...localFiles,
|
|
38890
|
-
...linked.flatMap((group) => group.files.map((file) => ({ ...file, folder: group.folder })))
|
|
39120
|
+
...[...managed, ...linked].flatMap((group) => group.files.map((file) => ({ ...file, folder: group.folder })))
|
|
38891
39121
|
]
|
|
38892
39122
|
},
|
|
38893
39123
|
folder,
|
|
38894
39124
|
status: "available"
|
|
38895
39125
|
};
|
|
38896
39126
|
}
|
|
39127
|
+
function codeSpan(text) {
|
|
39128
|
+
const escaped = text.replace(/[\u0000-\u001f\u007f-\u009f\u2028\u2029]/gu, (character) => `\\u${character.charCodeAt(0).toString(16).padStart(4, "0")}`);
|
|
39129
|
+
const longest = Math.max(0, ...(escaped.match(/`+/g) ?? []).map((run) => run.length));
|
|
39130
|
+
const fence = "`".repeat(longest + 1);
|
|
39131
|
+
const pad = escaped.startsWith("`") || escaped.endsWith("`") ? " " : "";
|
|
39132
|
+
return `${fence}${pad}${escaped}${pad}${fence}`;
|
|
39133
|
+
}
|
|
39134
|
+
async function notesLlmSections({
|
|
39135
|
+
folder,
|
|
39136
|
+
linkedFolders = [],
|
|
39137
|
+
managedFolders = [],
|
|
39138
|
+
signal
|
|
39139
|
+
}) {
|
|
39140
|
+
const groups = [];
|
|
39141
|
+
const notes = [];
|
|
39142
|
+
const seen = new Set;
|
|
39143
|
+
for (const source of [folder, ...managedFolders, ...linkedFolders]) {
|
|
39144
|
+
signal.throwIfAborted();
|
|
39145
|
+
const identity = await canonical(source);
|
|
39146
|
+
if (seen.has(identity))
|
|
39147
|
+
continue;
|
|
39148
|
+
seen.add(identity);
|
|
39149
|
+
const files = await listMarkdownFiles(source);
|
|
39150
|
+
const paths = files.map((file) => resolve11(source, file.relativePath));
|
|
39151
|
+
groups.push({ folder: source, paths });
|
|
39152
|
+
files.forEach((file, index) => notes.push({ activityAt: file.activityAt, path: paths[index] }));
|
|
39153
|
+
}
|
|
39154
|
+
if (notes.length === 0)
|
|
39155
|
+
return [];
|
|
39156
|
+
const recent = notes.sort((left, right) => right.activityAt - left.activityAt || (left.path < right.path ? -1 : left.path > right.path ? 1 : 0)).slice(0, llmNoteLimit);
|
|
39157
|
+
return [
|
|
39158
|
+
{
|
|
39159
|
+
id: "notes",
|
|
39160
|
+
title: "Markdown notes",
|
|
39161
|
+
lines: [
|
|
39162
|
+
...groups.filter((group) => group.paths.length > 0).map((group) => `- Source: ${codeSpan(group.folder)} (${group.paths.length} ${group.paths.length === 1 ? "note" : "notes"})`),
|
|
39163
|
+
`- Total notes: ${notes.length}`,
|
|
39164
|
+
"",
|
|
39165
|
+
`Most recently changed (${recent.length} of ${notes.length}):`,
|
|
39166
|
+
"",
|
|
39167
|
+
...recent.map((note) => `- ${codeSpan(note.path)}`)
|
|
39168
|
+
]
|
|
39169
|
+
}
|
|
39170
|
+
];
|
|
39171
|
+
}
|
|
38897
39172
|
function createNotesPlugin() {
|
|
38898
39173
|
return {
|
|
38899
39174
|
...notesManifest,
|
|
@@ -38905,22 +39180,28 @@ function createNotesPlugin() {
|
|
|
38905
39180
|
},
|
|
38906
39181
|
async handle({
|
|
38907
39182
|
folder,
|
|
38908
|
-
linkedFolders
|
|
39183
|
+
linkedFolders,
|
|
39184
|
+
managedFolders
|
|
38909
39185
|
}) {
|
|
38910
|
-
return {
|
|
38911
|
-
|
|
39186
|
+
return {
|
|
39187
|
+
data: await loadNotes(folder, linkedFolders, managedFolders),
|
|
39188
|
+
kind: "available"
|
|
39189
|
+
};
|
|
39190
|
+
},
|
|
39191
|
+
llm: notesLlmSections
|
|
38912
39192
|
};
|
|
38913
39193
|
}
|
|
38914
|
-
var
|
|
39194
|
+
var markdownExtensions2, llmNoteLimit = 20, canonical = (path) => realpath6(path).catch(() => path);
|
|
38915
39195
|
var init_server3 = __esm(() => {
|
|
38916
39196
|
init_manifest();
|
|
38917
|
-
|
|
39197
|
+
markdownExtensions2 = new Set([".md", ".markdown"]);
|
|
38918
39198
|
});
|
|
38919
39199
|
|
|
38920
39200
|
// packages/api/src/server/plugins.ts
|
|
38921
39201
|
import { pathToFileURL } from "node:url";
|
|
38922
39202
|
import { existsSync as existsSync4 } from "node:fs";
|
|
38923
|
-
import {
|
|
39203
|
+
import { mkdir as mkdir4, readFile as readFile10, stat as stat8, writeFile as writeFile6 } from "node:fs/promises";
|
|
39204
|
+
import { dirname as dirname9, resolve as resolve12, sep as sep7 } from "node:path";
|
|
38924
39205
|
function configuredFolderServerRegistry(registry, resolvedConfig) {
|
|
38925
39206
|
const disabled = new Set(resolvedConfig.plugins.disable);
|
|
38926
39207
|
const orderedIds = resolvedConfig.plugins.order.filter((id) => registry.has(id) && !disabled.has(id));
|
|
@@ -38930,6 +39211,41 @@ function configuredFolderServerRegistry(registry, resolvedConfig) {
|
|
|
38930
39211
|
];
|
|
38931
39212
|
return new Map(ids.map((id) => [id, registry.get(id)]));
|
|
38932
39213
|
}
|
|
39214
|
+
function stringArray(value) {
|
|
39215
|
+
return Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
|
|
39216
|
+
}
|
|
39217
|
+
function parsePluginRegistryConfig(content) {
|
|
39218
|
+
const parsed = JSON.parse(content);
|
|
39219
|
+
const config = parsed && typeof parsed === "object" ? parsed : {};
|
|
39220
|
+
return {
|
|
39221
|
+
plugins: {
|
|
39222
|
+
disable: stringArray(config.plugins?.disable),
|
|
39223
|
+
order: stringArray(config.plugins?.order)
|
|
39224
|
+
}
|
|
39225
|
+
};
|
|
39226
|
+
}
|
|
39227
|
+
async function nearestKennelConfig(folder) {
|
|
39228
|
+
for (let current = folder;; current = dirname9(current)) {
|
|
39229
|
+
const candidate = resolve12(current, "kennel.json");
|
|
39230
|
+
const details = await stat8(candidate).catch(() => {
|
|
39231
|
+
return;
|
|
39232
|
+
});
|
|
39233
|
+
if (details?.isFile())
|
|
39234
|
+
return candidate;
|
|
39235
|
+
if (dirname9(current) === current)
|
|
39236
|
+
return;
|
|
39237
|
+
}
|
|
39238
|
+
}
|
|
39239
|
+
async function folderPluginRegistryConfig(folder) {
|
|
39240
|
+
const path = await nearestKennelConfig(folder);
|
|
39241
|
+
if (!path)
|
|
39242
|
+
return defaultPluginRegistryConfig;
|
|
39243
|
+
try {
|
|
39244
|
+
return parsePluginRegistryConfig(await readFile10(path, "utf8"));
|
|
39245
|
+
} catch {
|
|
39246
|
+
return defaultPluginRegistryConfig;
|
|
39247
|
+
}
|
|
39248
|
+
}
|
|
38933
39249
|
function createFolderServerPlugins() {
|
|
38934
39250
|
return [createNotesPlugin()];
|
|
38935
39251
|
}
|
|
@@ -38973,7 +39289,7 @@ async function folderServerRegistryAsync() {
|
|
|
38973
39289
|
...server,
|
|
38974
39290
|
async detect(context) {
|
|
38975
39291
|
const detection = await server.detect(context);
|
|
38976
|
-
if (detection.status === "unavailable" && existsSync4(
|
|
39292
|
+
if (detection.status === "unavailable" && existsSync4(resolve12(context.folder, entry.trigger))) {
|
|
38977
39293
|
return { status: "available" };
|
|
38978
39294
|
}
|
|
38979
39295
|
return detection;
|
|
@@ -39010,15 +39326,19 @@ async function externalApiHandlers() {
|
|
|
39010
39326
|
}
|
|
39011
39327
|
return handlers;
|
|
39012
39328
|
}
|
|
39329
|
+
var defaultPluginRegistryConfig;
|
|
39013
39330
|
var init_plugins = __esm(() => {
|
|
39014
39331
|
init_server3();
|
|
39332
|
+
defaultPluginRegistryConfig = {
|
|
39333
|
+
plugins: { disable: [], order: [] }
|
|
39334
|
+
};
|
|
39015
39335
|
});
|
|
39016
39336
|
|
|
39017
39337
|
// packages/api/src/server/linked-folder-discovery.ts
|
|
39018
|
-
import { execFile as
|
|
39338
|
+
import { execFile as execFile4 } from "node:child_process";
|
|
39019
39339
|
import { existsSync as existsSync5 } from "node:fs";
|
|
39020
39340
|
import { createRequire as createRequire2 } from "node:module";
|
|
39021
|
-
import { dirname as
|
|
39341
|
+
import { dirname as dirname10, join as join5 } from "node:path";
|
|
39022
39342
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
39023
39343
|
function resolveLocalModule(from = import.meta.url) {
|
|
39024
39344
|
const require2 = createRequire2(from);
|
|
@@ -39026,19 +39346,19 @@ function resolveLocalModule(from = import.meta.url) {
|
|
|
39026
39346
|
try {
|
|
39027
39347
|
candidates.push(require2.resolve("@raggle-ai/local"));
|
|
39028
39348
|
} catch {}
|
|
39029
|
-
let directory =
|
|
39030
|
-
while (
|
|
39031
|
-
if (existsSync5(
|
|
39349
|
+
let directory = dirname10(fileURLToPath2(from));
|
|
39350
|
+
while (dirname10(directory) !== directory) {
|
|
39351
|
+
if (existsSync5(join5(directory, "raggle.json"))) {
|
|
39032
39352
|
for (const candidate of [
|
|
39033
|
-
|
|
39034
|
-
|
|
39353
|
+
join5(dirname10(directory), "raggle-ai-scout", "packages", "local"),
|
|
39354
|
+
join5(directory, "..", "..", "raggle-ai-scout", "packages", "local")
|
|
39035
39355
|
]) {
|
|
39036
39356
|
if (!candidates.includes(candidate))
|
|
39037
39357
|
candidates.push(candidate);
|
|
39038
39358
|
}
|
|
39039
39359
|
break;
|
|
39040
39360
|
}
|
|
39041
|
-
directory =
|
|
39361
|
+
directory = dirname10(directory);
|
|
39042
39362
|
}
|
|
39043
39363
|
for (const candidate of candidates) {
|
|
39044
39364
|
try {
|
|
@@ -39047,11 +39367,11 @@ function resolveLocalModule(from = import.meta.url) {
|
|
|
39047
39367
|
return candidate;
|
|
39048
39368
|
} catch {}
|
|
39049
39369
|
}
|
|
39050
|
-
return candidates[0] ??
|
|
39370
|
+
return candidates[0] ?? join5(dirname10(fileURLToPath2(from)), "..", "..", "..", "raggle-ai-scout", "packages", "local");
|
|
39051
39371
|
}
|
|
39052
39372
|
function discoverLinkedFolders(folder, signal, modulePath = resolveLocalModule()) {
|
|
39053
39373
|
return new Promise((resolve, reject) => {
|
|
39054
|
-
|
|
39374
|
+
execFile4(process.execPath, ["-e", script, modulePath, folder], {
|
|
39055
39375
|
signal,
|
|
39056
39376
|
timeout: 60000,
|
|
39057
39377
|
maxBuffer: 8 * 1024 * 1024,
|
|
@@ -39147,10 +39467,10 @@ const { stat } = require('node:fs/promises');
|
|
|
39147
39467
|
var init_linked_folder_discovery = () => {};
|
|
39148
39468
|
|
|
39149
39469
|
// packages/api/src/server/project-discovery.ts
|
|
39150
|
-
import { execFile as
|
|
39470
|
+
import { execFile as execFile5 } from "node:child_process";
|
|
39151
39471
|
function discoverProjects(folder, signal) {
|
|
39152
39472
|
return new Promise((resolve, reject) => {
|
|
39153
|
-
|
|
39473
|
+
execFile5(process.execPath, ["-e", script2, resolveLocalModule(), folder], {
|
|
39154
39474
|
signal,
|
|
39155
39475
|
timeout: 60000,
|
|
39156
39476
|
maxBuffer: 8 * 1024 * 1024,
|
|
@@ -39237,24 +39557,24 @@ var init_project_discovery = __esm(() => {
|
|
|
39237
39557
|
// packages/api/src/server/folder-metadata-plugin.ts
|
|
39238
39558
|
import { createHash as createHash5 } from "node:crypto";
|
|
39239
39559
|
import { realpathSync as realpathSync2 } from "node:fs";
|
|
39240
|
-
import { readdir as
|
|
39241
|
-
import { homedir as
|
|
39560
|
+
import { readdir as readdir6, readFile as readFile11, realpath as realpath7, stat as stat9 } from "node:fs/promises";
|
|
39561
|
+
import { homedir as homedir4 } from "node:os";
|
|
39242
39562
|
import {
|
|
39243
|
-
basename as
|
|
39244
|
-
dirname as
|
|
39563
|
+
basename as basename8,
|
|
39564
|
+
dirname as dirname11,
|
|
39245
39565
|
extname as extname6,
|
|
39246
|
-
isAbsolute as
|
|
39247
|
-
relative as
|
|
39248
|
-
resolve as
|
|
39249
|
-
sep as
|
|
39566
|
+
isAbsolute as isAbsolute7,
|
|
39567
|
+
relative as relative12,
|
|
39568
|
+
resolve as resolve13,
|
|
39569
|
+
sep as sep8
|
|
39250
39570
|
} from "node:path";
|
|
39251
|
-
import { execFile as
|
|
39571
|
+
import { execFile as execFile6 } from "node:child_process";
|
|
39252
39572
|
import local from "@raggle-ai/local";
|
|
39253
39573
|
function metadataFile(path, root) {
|
|
39254
|
-
const candidate =
|
|
39255
|
-
if (!candidate || candidate.startsWith("..") ||
|
|
39574
|
+
const candidate = relative12(root, path);
|
|
39575
|
+
if (!candidate || candidate.startsWith("..") || isAbsolute7(candidate))
|
|
39256
39576
|
return false;
|
|
39257
|
-
const parts = candidate.split(
|
|
39577
|
+
const parts = candidate.split(sep8);
|
|
39258
39578
|
if (parts.some((part) => part === "node_modules"))
|
|
39259
39579
|
return false;
|
|
39260
39580
|
return metadataExtensions.has(extname6(candidate).toLowerCase());
|
|
@@ -39265,11 +39585,11 @@ async function configuredAiInputModule(folder) {
|
|
|
39265
39585
|
return typeof module === "string" && module.trim() ? module.trim() : null;
|
|
39266
39586
|
}
|
|
39267
39587
|
function folderPath(value, root, lockedRoot) {
|
|
39268
|
-
const folder = realpathSync2(
|
|
39588
|
+
const folder = realpathSync2(resolve13(value ?? root));
|
|
39269
39589
|
if (!lockedRoot)
|
|
39270
39590
|
return folder;
|
|
39271
|
-
const path =
|
|
39272
|
-
if (!path || !path.startsWith("..") && !
|
|
39591
|
+
const path = relative12(lockedRoot, folder);
|
|
39592
|
+
if (!path || !path.startsWith("..") && !isAbsolute7(path))
|
|
39273
39593
|
return folder;
|
|
39274
39594
|
throw new Error(`Folder is outside the viewer root: ${folder}`);
|
|
39275
39595
|
}
|
|
@@ -39333,15 +39653,15 @@ function unique(values) {
|
|
|
39333
39653
|
return [...new Set(values)];
|
|
39334
39654
|
}
|
|
39335
39655
|
function isMachineRoot(folder) {
|
|
39336
|
-
return folder ===
|
|
39656
|
+
return folder === homedir4() || dirname11(folder) === folder;
|
|
39337
39657
|
}
|
|
39338
39658
|
async function shallowMetadata(folder) {
|
|
39339
|
-
const entries = await
|
|
39659
|
+
const entries = await readdir6(folder, { withFileTypes: true });
|
|
39340
39660
|
const visible = entries.filter((entry) => !entry.name.startsWith(".") && entry.name !== "node_modules");
|
|
39341
39661
|
const files = await Promise.all(visible.filter((entry) => entry.isFile() && [".markdown", ".md"].includes(extname6(entry.name).toLowerCase())).map(async (entry) => {
|
|
39342
|
-
const path =
|
|
39343
|
-
const details = await
|
|
39344
|
-
const content = await
|
|
39662
|
+
const path = resolve13(folder, entry.name);
|
|
39663
|
+
const details = await stat9(path);
|
|
39664
|
+
const content = await readFile11(path, "utf8").catch(() => "");
|
|
39345
39665
|
const title = markdownMetadata(content).title;
|
|
39346
39666
|
return {
|
|
39347
39667
|
activityAt: details.mtimeMs,
|
|
@@ -39354,10 +39674,10 @@ async function shallowMetadata(folder) {
|
|
|
39354
39674
|
};
|
|
39355
39675
|
}));
|
|
39356
39676
|
const projects = visible.filter((entry) => entry.isDirectory()).map((entry) => ({
|
|
39357
|
-
id: createHash5("sha1").update(
|
|
39677
|
+
id: createHash5("sha1").update(resolve13(folder, entry.name)).digest("hex"),
|
|
39358
39678
|
name: entry.name,
|
|
39359
39679
|
relativePath: entry.name,
|
|
39360
|
-
worktree:
|
|
39680
|
+
worktree: resolve13(folder, entry.name)
|
|
39361
39681
|
})).sort((left, right) => left.name.localeCompare(right.name));
|
|
39362
39682
|
return {
|
|
39363
39683
|
changes: { items: [] },
|
|
@@ -39383,8 +39703,8 @@ async function loadFolderData(folder) {
|
|
|
39383
39703
|
items: projects.map((project) => ({
|
|
39384
39704
|
id: project.id,
|
|
39385
39705
|
worktree: project.worktree,
|
|
39386
|
-
name: project.name ??
|
|
39387
|
-
relativePath:
|
|
39706
|
+
name: project.name ?? basename8(project.worktree),
|
|
39707
|
+
relativePath: relative12(folder, project.worktree)
|
|
39388
39708
|
}))
|
|
39389
39709
|
}
|
|
39390
39710
|
};
|
|
@@ -39392,10 +39712,10 @@ async function loadFolderData(folder) {
|
|
|
39392
39712
|
async function notesFiles(folder, files, origin) {
|
|
39393
39713
|
return {
|
|
39394
39714
|
items: await Promise.all(files.map(async (file) => {
|
|
39395
|
-
const path = file.path ?? (file.relativePath ?
|
|
39715
|
+
const path = file.path ?? (file.relativePath ? resolve13(folder, file.relativePath) : undefined);
|
|
39396
39716
|
if (!path)
|
|
39397
39717
|
return origin ? { ...file, folder: origin } : file;
|
|
39398
|
-
const content = [".markdown", ".md"].includes(extname6(path).toLowerCase()) ? await
|
|
39718
|
+
const content = [".markdown", ".md"].includes(extname6(path).toLowerCase()) ? await readFile11(path, "utf8").catch(() => "") : "";
|
|
39399
39719
|
const title = content ? markdownMetadata(content).title : undefined;
|
|
39400
39720
|
return {
|
|
39401
39721
|
...file,
|
|
@@ -39406,6 +39726,30 @@ async function notesFiles(folder, files, origin) {
|
|
|
39406
39726
|
}))
|
|
39407
39727
|
};
|
|
39408
39728
|
}
|
|
39729
|
+
async function managedNotesFiles(directory) {
|
|
39730
|
+
const notes = await listManagedNotes(directory);
|
|
39731
|
+
return Promise.all(notes.map(async (note) => {
|
|
39732
|
+
const content = await readFile11(note.path, "utf8").catch(() => "");
|
|
39733
|
+
const title = content ? markdownMetadata(content).title : undefined;
|
|
39734
|
+
return {
|
|
39735
|
+
...note,
|
|
39736
|
+
folder: directory,
|
|
39737
|
+
name: title ?? note.name,
|
|
39738
|
+
openHref: openPathHref(note.path)
|
|
39739
|
+
};
|
|
39740
|
+
}));
|
|
39741
|
+
}
|
|
39742
|
+
function insideFolder(path, root) {
|
|
39743
|
+
const local = relative12(root, path);
|
|
39744
|
+
return local === "" || !local.startsWith("..") && !isAbsolute7(local);
|
|
39745
|
+
}
|
|
39746
|
+
async function withoutManagedFiles(items, managedRoot) {
|
|
39747
|
+
if (!managedRoot)
|
|
39748
|
+
return items;
|
|
39749
|
+
const root = await canonicalPath(managedRoot);
|
|
39750
|
+
const outside = await Promise.all(items.map(async (item) => !item.path || !insideFolder(await canonicalPath(item.path), root)));
|
|
39751
|
+
return items.filter((_, index) => outside[index]);
|
|
39752
|
+
}
|
|
39409
39753
|
async function localProjectSearchCache(cache) {
|
|
39410
39754
|
if (cache && Date.now() - cache.loadedAt < projectSearchCacheMs)
|
|
39411
39755
|
return cache;
|
|
@@ -39428,16 +39772,16 @@ async function localProjectSearchCache(cache) {
|
|
|
39428
39772
|
function mediaTarget(folder, file, lockedTarget) {
|
|
39429
39773
|
if (!file)
|
|
39430
39774
|
return;
|
|
39431
|
-
const rootReal = realpathSync2(
|
|
39432
|
-
const path =
|
|
39775
|
+
const rootReal = realpathSync2(resolve13(folder));
|
|
39776
|
+
const path = resolve13(folder, file);
|
|
39433
39777
|
let pathReal;
|
|
39434
39778
|
try {
|
|
39435
39779
|
pathReal = realpathSync2(path);
|
|
39436
39780
|
} catch {
|
|
39437
39781
|
return;
|
|
39438
39782
|
}
|
|
39439
|
-
const rel =
|
|
39440
|
-
if (rel.startsWith("..") ||
|
|
39783
|
+
const rel = relative12(rootReal, pathReal);
|
|
39784
|
+
if (rel.startsWith("..") || isAbsolute7(rel))
|
|
39441
39785
|
return;
|
|
39442
39786
|
if (lockedTarget && pathReal !== lockedTarget)
|
|
39443
39787
|
return;
|
|
@@ -39476,16 +39820,16 @@ function documentError(response) {
|
|
|
39476
39820
|
function documentTarget(folder, file, lockedTarget) {
|
|
39477
39821
|
if (!file)
|
|
39478
39822
|
return;
|
|
39479
|
-
const rootReal = realpathSync2(
|
|
39480
|
-
const path =
|
|
39823
|
+
const rootReal = realpathSync2(resolve13(folder));
|
|
39824
|
+
const path = resolve13(folder, file);
|
|
39481
39825
|
let pathReal;
|
|
39482
39826
|
try {
|
|
39483
39827
|
pathReal = realpathSync2(path);
|
|
39484
39828
|
} catch {
|
|
39485
39829
|
return;
|
|
39486
39830
|
}
|
|
39487
|
-
const rel =
|
|
39488
|
-
if (rel.startsWith("..") ||
|
|
39831
|
+
const rel = relative12(rootReal, pathReal);
|
|
39832
|
+
if (rel.startsWith("..") || isAbsolute7(rel))
|
|
39489
39833
|
return;
|
|
39490
39834
|
if (lockedTarget && pathReal !== lockedTarget)
|
|
39491
39835
|
return;
|
|
@@ -39513,41 +39857,6 @@ async function projectSearchItem(project, match) {
|
|
|
39513
39857
|
worktree: project.worktree
|
|
39514
39858
|
};
|
|
39515
39859
|
}
|
|
39516
|
-
function stringArray(value) {
|
|
39517
|
-
return Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
|
|
39518
|
-
}
|
|
39519
|
-
function parsePluginRegistryConfig(content) {
|
|
39520
|
-
const parsed = JSON.parse(content);
|
|
39521
|
-
const config = parsed && typeof parsed === "object" ? parsed : {};
|
|
39522
|
-
return {
|
|
39523
|
-
plugins: {
|
|
39524
|
-
disable: stringArray(config.plugins?.disable),
|
|
39525
|
-
order: stringArray(config.plugins?.order)
|
|
39526
|
-
}
|
|
39527
|
-
};
|
|
39528
|
-
}
|
|
39529
|
-
async function nearestKennelConfig(folder) {
|
|
39530
|
-
for (let current = folder;; current = dirname10(current)) {
|
|
39531
|
-
const candidate = resolve12(current, "kennel.json");
|
|
39532
|
-
const details = await stat7(candidate).catch(() => {
|
|
39533
|
-
return;
|
|
39534
|
-
});
|
|
39535
|
-
if (details?.isFile())
|
|
39536
|
-
return candidate;
|
|
39537
|
-
if (dirname10(current) === current)
|
|
39538
|
-
return;
|
|
39539
|
-
}
|
|
39540
|
-
}
|
|
39541
|
-
async function folderPluginRegistryConfig(folder) {
|
|
39542
|
-
const path = await nearestKennelConfig(folder);
|
|
39543
|
-
if (!path)
|
|
39544
|
-
return defaultPluginRegistryConfig;
|
|
39545
|
-
try {
|
|
39546
|
-
return parsePluginRegistryConfig(await readFile9(path, "utf8"));
|
|
39547
|
-
} catch {
|
|
39548
|
-
return defaultPluginRegistryConfig;
|
|
39549
|
-
}
|
|
39550
|
-
}
|
|
39551
39860
|
function pluginConfigWarnings(registry, config) {
|
|
39552
39861
|
const ids = unique([...config.plugins.disable, ...config.plugins.order]);
|
|
39553
39862
|
return ids.filter((id) => !registry.has(id)).map((id) => `unknown plugin id "${id}" — not installed in this build`);
|
|
@@ -39598,6 +39907,18 @@ function createFolderApi({
|
|
|
39598
39907
|
const linkedDiscovery = createLinkedFolderDiscovery(linkedFolderLoader, (folder) => discoveryChanged(folder));
|
|
39599
39908
|
const linkedState = (folder) => lockedRoot || isMachineRoot(folder) ? { folders: [], status: "ready" } : linkedDiscovery.read(folder);
|
|
39600
39909
|
const resolveLinkedFolders = (folder) => lockedRoot || isMachineRoot(folder) ? Promise.resolve([]) : linkedDiscovery.folders(folder);
|
|
39910
|
+
const managedNotesFolder = async (folder) => {
|
|
39911
|
+
if (lockedRoot || lockedTarget || isMachineRoot(folder))
|
|
39912
|
+
return;
|
|
39913
|
+
try {
|
|
39914
|
+
if (!(await readRepositoryNotesSettings()).enabled)
|
|
39915
|
+
return;
|
|
39916
|
+
const lookup = await lookupRepositoryNotes(folder);
|
|
39917
|
+
return lookup.status === "registered" ? lookup.notesDirectory : undefined;
|
|
39918
|
+
} catch {
|
|
39919
|
+
return;
|
|
39920
|
+
}
|
|
39921
|
+
};
|
|
39601
39922
|
const favicon = faviconService();
|
|
39602
39923
|
return {
|
|
39603
39924
|
name: "kennel-folder-metadata",
|
|
@@ -39640,7 +39961,7 @@ function createFolderApi({
|
|
|
39640
39961
|
if (!folder)
|
|
39641
39962
|
return;
|
|
39642
39963
|
server.emit({
|
|
39643
|
-
data: { path:
|
|
39964
|
+
data: { path: relative12(folder, path) },
|
|
39644
39965
|
event: "kennel:metadata-changed",
|
|
39645
39966
|
type: "custom"
|
|
39646
39967
|
});
|
|
@@ -39723,7 +40044,7 @@ function createFolderApi({
|
|
|
39723
40044
|
"Content-Type": asset.mediaType,
|
|
39724
40045
|
ETag: `"${hash}"`
|
|
39725
40046
|
});
|
|
39726
|
-
response.end(await
|
|
40047
|
+
response.end(await readFile11(asset.path));
|
|
39727
40048
|
} catch (error) {
|
|
39728
40049
|
response.writeHead(404, {
|
|
39729
40050
|
"Content-Type": "text/plain; charset=utf-8"
|
|
@@ -39788,21 +40109,21 @@ function createFolderApi({
|
|
|
39788
40109
|
}
|
|
39789
40110
|
const folder = folderPath(url.searchParams.get("path"), root, lockedRoot);
|
|
39790
40111
|
const command = process.platform === "darwin" ? "open" : process.platform === "win32" ? "explorer.exe" : "xdg-open";
|
|
39791
|
-
await new Promise((done, fail) =>
|
|
40112
|
+
await new Promise((done, fail) => execFile6(command, [folder], (error) => error ? fail(error) : done()));
|
|
39792
40113
|
response.writeHead(204);
|
|
39793
40114
|
response.end();
|
|
39794
40115
|
return;
|
|
39795
40116
|
}
|
|
39796
40117
|
if (url.pathname === "/api/documents") {
|
|
39797
40118
|
const folder = folderPath(url.searchParams.get("path"), root, lockedRoot);
|
|
39798
|
-
const target = lockedTarget ? documentTarget(folder,
|
|
40119
|
+
const target = lockedTarget ? documentTarget(folder, relative12(folder, lockedTarget), lockedTarget) : undefined;
|
|
39799
40120
|
const dataset = lockedTarget ? {
|
|
39800
40121
|
root: folder,
|
|
39801
40122
|
documents: target ? [
|
|
39802
40123
|
{
|
|
39803
|
-
path:
|
|
40124
|
+
path: relative12(folder, target.path),
|
|
39804
40125
|
kind: target.kind,
|
|
39805
|
-
content: previewTextKind(target.kind) ? await
|
|
40126
|
+
content: previewTextKind(target.kind) ? await readFile11(target.path, "utf8") : ""
|
|
39806
40127
|
}
|
|
39807
40128
|
] : []
|
|
39808
40129
|
} : await readFolder(folder);
|
|
@@ -39818,7 +40139,7 @@ function createFolderApi({
|
|
|
39818
40139
|
documentError(response);
|
|
39819
40140
|
return;
|
|
39820
40141
|
}
|
|
39821
|
-
const details = await
|
|
40142
|
+
const details = await stat9(target.path);
|
|
39822
40143
|
if (!details.isFile()) {
|
|
39823
40144
|
documentError(response);
|
|
39824
40145
|
return;
|
|
@@ -39830,16 +40151,16 @@ function createFolderApi({
|
|
|
39830
40151
|
return;
|
|
39831
40152
|
}
|
|
39832
40153
|
watch(folder);
|
|
39833
|
-
const content = previewTextKind(target.kind) ? await
|
|
40154
|
+
const content = previewTextKind(target.kind) ? await readFile11(target.path, "utf8") : "";
|
|
39834
40155
|
sendContract(response, url, {
|
|
39835
40156
|
content,
|
|
39836
40157
|
kind: target.kind,
|
|
39837
|
-
path:
|
|
40158
|
+
path: relative12(target.root, target.path),
|
|
39838
40159
|
root: folder,
|
|
39839
40160
|
...previewTextKind(target.kind) ? {} : {
|
|
39840
40161
|
rawUrl: `/api/raw?${new URLSearchParams({
|
|
39841
40162
|
path: folder,
|
|
39842
|
-
file:
|
|
40163
|
+
file: relative12(target.root, target.path)
|
|
39843
40164
|
})}`
|
|
39844
40165
|
}
|
|
39845
40166
|
}, {
|
|
@@ -39859,7 +40180,7 @@ function createFolderApi({
|
|
|
39859
40180
|
documentError(response);
|
|
39860
40181
|
return;
|
|
39861
40182
|
}
|
|
39862
|
-
const details = await
|
|
40183
|
+
const details = await stat9(target.path);
|
|
39863
40184
|
if (!details.isFile()) {
|
|
39864
40185
|
documentError(response);
|
|
39865
40186
|
return;
|
|
@@ -39880,10 +40201,10 @@ function createFolderApi({
|
|
|
39880
40201
|
ETag: etag,
|
|
39881
40202
|
"X-Content-Type-Options": "nosniff",
|
|
39882
40203
|
...download ? {
|
|
39883
|
-
"Content-Disposition": `attachment; filename="${
|
|
40204
|
+
"Content-Disposition": `attachment; filename="${basename8(target.path)}"`
|
|
39884
40205
|
} : {}
|
|
39885
40206
|
});
|
|
39886
|
-
response.end(await
|
|
40207
|
+
response.end(await readFile11(target.path));
|
|
39887
40208
|
} catch (error) {
|
|
39888
40209
|
documentError(response);
|
|
39889
40210
|
}
|
|
@@ -39897,7 +40218,7 @@ function createFolderApi({
|
|
|
39897
40218
|
documentError(response);
|
|
39898
40219
|
return;
|
|
39899
40220
|
}
|
|
39900
|
-
const details = await
|
|
40221
|
+
const details = await stat9(target.path);
|
|
39901
40222
|
if (!details.isFile()) {
|
|
39902
40223
|
documentError(response);
|
|
39903
40224
|
return;
|
|
@@ -39909,7 +40230,7 @@ function createFolderApi({
|
|
|
39909
40230
|
return;
|
|
39910
40231
|
}
|
|
39911
40232
|
watch(folder);
|
|
39912
|
-
const data = await
|
|
40233
|
+
const data = await readFile11(target.path);
|
|
39913
40234
|
const baseHeaders = {
|
|
39914
40235
|
"Accept-Ranges": "bytes",
|
|
39915
40236
|
"Cache-Control": "private, max-age=0, must-revalidate",
|
|
@@ -39963,9 +40284,13 @@ function createFolderApi({
|
|
|
39963
40284
|
if (!lockedRoot && !isMachineRoot(folder) && request.headers["x-kennel-retry-linked"] === "1")
|
|
39964
40285
|
linkedDiscovery.retry(folder);
|
|
39965
40286
|
const discovery = linkedState(folder);
|
|
40287
|
+
const managed = await managedNotesFolder(folder);
|
|
40288
|
+
if (managed)
|
|
40289
|
+
watch(managed);
|
|
39966
40290
|
const result = await plugin.handle({
|
|
39967
40291
|
folder,
|
|
39968
|
-
linkedFolders: discovery.folders
|
|
40292
|
+
linkedFolders: discovery.folders,
|
|
40293
|
+
...managed ? { managedFolders: [managed] } : {}
|
|
39969
40294
|
}, subpath);
|
|
39970
40295
|
if (result.kind === "unavailable") {
|
|
39971
40296
|
response.writeHead(200, {
|
|
@@ -40068,7 +40393,7 @@ function createFolderApi({
|
|
|
40068
40393
|
workspace.breadcrumbs = await workspaceBreadcrumbIcons(workspace.breadcrumbs ?? [], assetFiles);
|
|
40069
40394
|
const files = [
|
|
40070
40395
|
workspace.configPath,
|
|
40071
|
-
|
|
40396
|
+
resolve13(workspace.root, "raggle.json")
|
|
40072
40397
|
].filter((path) => Boolean(path));
|
|
40073
40398
|
for (const path of files)
|
|
40074
40399
|
contexts.add(path);
|
|
@@ -40092,7 +40417,14 @@ function createFolderApi({
|
|
|
40092
40417
|
const machine = isMachineRoot(folder);
|
|
40093
40418
|
if (part === "notes") {
|
|
40094
40419
|
const scope = url.searchParams.get("notesScope");
|
|
40420
|
+
const managed = await managedNotesFolder(folder);
|
|
40095
40421
|
const localFiles = scope === "linked" ? Promise.resolve({ items: [] }) : (machine ? shallowMetadata(folder).then((data) => data.files.items) : listLocalMarkdownFiles({ folder, limit: 200 })).then((files) => notesFiles(folder, files));
|
|
40422
|
+
const managedFiles = async () => {
|
|
40423
|
+
if (scope === "linked" || !managed)
|
|
40424
|
+
return [];
|
|
40425
|
+
watch(managed);
|
|
40426
|
+
return managedNotesFiles(managed);
|
|
40427
|
+
};
|
|
40096
40428
|
const linkedFiles = async () => {
|
|
40097
40429
|
if (scope === "local" || machine || lockedRoot)
|
|
40098
40430
|
return [];
|
|
@@ -40103,20 +40435,25 @@ function createFolderApi({
|
|
|
40103
40435
|
throw new Error("Linked notes discovery failed. Retry to try again.");
|
|
40104
40436
|
return Promise.all(linkedFolders.map(async (linkedFolder) => {
|
|
40105
40437
|
watch(linkedFolder);
|
|
40106
|
-
|
|
40438
|
+
const group = await notesFiles(linkedFolder, await listLocalMarkdownFiles({
|
|
40107
40439
|
folder: linkedFolder,
|
|
40108
40440
|
limit: 200
|
|
40109
40441
|
}), linkedFolder);
|
|
40442
|
+
return {
|
|
40443
|
+
items: await withoutManagedFiles(group.items, managed)
|
|
40444
|
+
};
|
|
40110
40445
|
}));
|
|
40111
40446
|
};
|
|
40112
|
-
const [files, linked] = await Promise.all([
|
|
40447
|
+
const [files, managedItems, linked] = await Promise.all([
|
|
40113
40448
|
localFiles,
|
|
40449
|
+
managedFiles(),
|
|
40114
40450
|
linkedFiles()
|
|
40115
40451
|
]);
|
|
40116
40452
|
sendContract(response, url, {
|
|
40117
40453
|
files: {
|
|
40118
40454
|
items: [
|
|
40119
40455
|
...files.items,
|
|
40456
|
+
...managedItems,
|
|
40120
40457
|
...linked.flatMap((group) => group.items)
|
|
40121
40458
|
]
|
|
40122
40459
|
},
|
|
@@ -40197,7 +40534,7 @@ function createFolderApi({
|
|
|
40197
40534
|
}
|
|
40198
40535
|
};
|
|
40199
40536
|
}
|
|
40200
|
-
var applyProjectFavorites, buildProjectCatalog, buildProjectSearchIndex, catalogProjectToLocalProject, discoverProjectIcon, discoverProjectsUnderFolder, listLocalMarkdownFiles, projectRepositoryAccessory, projectSubtitle, projectTitle, readRaggleUserSettings, gitRemoteUrl, githubRepositoryPath, repositoryDisplayName, searchProjectIndex, sortProjectList, projectSearchCacheMs = 5000, metadataExtensions, loopbackServerHosts,
|
|
40537
|
+
var applyProjectFavorites, buildProjectCatalog, buildProjectSearchIndex, catalogProjectToLocalProject, discoverProjectIcon, discoverProjectsUnderFolder, listLocalMarkdownFiles, projectRepositoryAccessory, projectSubtitle, projectTitle, readRaggleUserSettings, gitRemoteUrl, githubRepositoryPath, repositoryDisplayName, searchProjectIndex, sortProjectList, projectSearchCacheMs = 5000, metadataExtensions, loopbackServerHosts, canonicalPath = (path) => realpath7(path).catch(() => path);
|
|
40201
40538
|
var init_folder_metadata_plugin = __esm(() => {
|
|
40202
40539
|
init_contracts();
|
|
40203
40540
|
init_markdown();
|
|
@@ -40207,6 +40544,7 @@ var init_folder_metadata_plugin = __esm(() => {
|
|
|
40207
40544
|
init_server();
|
|
40208
40545
|
init_workspace2();
|
|
40209
40546
|
init_server2();
|
|
40547
|
+
init_store();
|
|
40210
40548
|
init_entity_folder();
|
|
40211
40549
|
init_document_edit();
|
|
40212
40550
|
init_create_agent_file();
|
|
@@ -40254,38 +40592,35 @@ var init_folder_metadata_plugin = __esm(() => {
|
|
|
40254
40592
|
undefined,
|
|
40255
40593
|
false
|
|
40256
40594
|
]);
|
|
40257
|
-
defaultPluginRegistryConfig = {
|
|
40258
|
-
plugins: { disable: [], order: [] }
|
|
40259
|
-
};
|
|
40260
40595
|
});
|
|
40261
40596
|
|
|
40262
40597
|
// packages/api/src/server/index.ts
|
|
40263
40598
|
import {
|
|
40264
40599
|
createServer
|
|
40265
40600
|
} from "node:http";
|
|
40266
|
-
import { readFile as
|
|
40267
|
-
import { extname as extname7, isAbsolute as
|
|
40601
|
+
import { readFile as readFile12, realpath as realpath8, stat as stat10 } from "node:fs/promises";
|
|
40602
|
+
import { extname as extname7, isAbsolute as isAbsolute8, relative as relative13, resolve as resolve14 } from "node:path";
|
|
40268
40603
|
async function sendFile(request, response, directory, pathname, fallback) {
|
|
40269
|
-
const root = await
|
|
40604
|
+
const root = await realpath8(directory);
|
|
40270
40605
|
const inside = (path) => {
|
|
40271
|
-
const local =
|
|
40272
|
-
return local !== ".." && !local.startsWith("../") && !
|
|
40606
|
+
const local = relative13(root, path);
|
|
40607
|
+
return local !== ".." && !local.startsWith("../") && !isAbsolute8(local);
|
|
40273
40608
|
};
|
|
40274
|
-
let target =
|
|
40609
|
+
let target = resolve14(root, `.${decodeURIComponent(pathname)}`);
|
|
40275
40610
|
if (!inside(target)) {
|
|
40276
40611
|
response.writeHead(403);
|
|
40277
40612
|
response.end();
|
|
40278
40613
|
return;
|
|
40279
40614
|
}
|
|
40280
|
-
if (!(await
|
|
40615
|
+
if (!(await stat10(target).catch(() => null))?.isFile()) {
|
|
40281
40616
|
if (!fallback) {
|
|
40282
40617
|
response.writeHead(404);
|
|
40283
40618
|
response.end();
|
|
40284
40619
|
return;
|
|
40285
40620
|
}
|
|
40286
|
-
target =
|
|
40621
|
+
target = resolve14(root, fallback);
|
|
40287
40622
|
}
|
|
40288
|
-
target = await
|
|
40623
|
+
target = await realpath8(target);
|
|
40289
40624
|
if (!inside(target)) {
|
|
40290
40625
|
response.writeHead(403);
|
|
40291
40626
|
response.end();
|
|
@@ -40295,7 +40630,7 @@ async function sendFile(request, response, directory, pathname, fallback) {
|
|
|
40295
40630
|
"Content-Type": contentTypes[extname7(target)] ?? "application/octet-stream",
|
|
40296
40631
|
"X-Content-Type-Options": "nosniff"
|
|
40297
40632
|
});
|
|
40298
|
-
response.end(request.method === "HEAD" ? undefined : await
|
|
40633
|
+
response.end(request.method === "HEAD" ? undefined : await readFile12(target));
|
|
40299
40634
|
}
|
|
40300
40635
|
function createKennelApi(options) {
|
|
40301
40636
|
const remote = options.remoteAccess || !isLoopbackServerHost(options.host);
|
|
@@ -40471,7 +40806,7 @@ var init_server4 = __esm(() => {
|
|
|
40471
40806
|
import { execFileSync as execFileSync3 } from "node:child_process";
|
|
40472
40807
|
import { existsSync as existsSync6, realpathSync as realpathSync3, statSync as statSync3 } from "node:fs";
|
|
40473
40808
|
import { createServer as createServer2 } from "node:net";
|
|
40474
|
-
import { dirname as
|
|
40809
|
+
import { dirname as dirname12, isAbsolute as isAbsolute9, relative as relative14, resolve as resolve15 } from "node:path";
|
|
40475
40810
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
40476
40811
|
function isLoopbackHost(host) {
|
|
40477
40812
|
return loopbackHosts.has(host) || host.startsWith("127.");
|
|
@@ -40550,7 +40885,7 @@ function splitViewerArgs(input) {
|
|
|
40550
40885
|
}
|
|
40551
40886
|
if (arg.startsWith("-"))
|
|
40552
40887
|
throw new Error(`Unknown viewer option: ${arg}`);
|
|
40553
|
-
const candidate =
|
|
40888
|
+
const candidate = resolve15(arg);
|
|
40554
40889
|
const isDirectory = existsSync6(candidate) && statSync3(candidate).isDirectory();
|
|
40555
40890
|
if (isDirectory) {
|
|
40556
40891
|
if (hasRoot)
|
|
@@ -40561,7 +40896,7 @@ function splitViewerArgs(input) {
|
|
|
40561
40896
|
}
|
|
40562
40897
|
if (hasRoot)
|
|
40563
40898
|
throw new Error("kennel accepts one folder");
|
|
40564
|
-
options.root =
|
|
40899
|
+
options.root = dirname12(candidate);
|
|
40565
40900
|
options.target = candidate;
|
|
40566
40901
|
hasRoot = true;
|
|
40567
40902
|
}
|
|
@@ -40602,7 +40937,7 @@ function popUrl(host, port, options) {
|
|
|
40602
40937
|
url.pathname = `/folder/${encodeBase64Url2(options.root)}/notes`;
|
|
40603
40938
|
return url.href;
|
|
40604
40939
|
}
|
|
40605
|
-
url.pathname = `/folder/${encodeBase64Url2(options.root)}/document/${encodeBase64Url2(
|
|
40940
|
+
url.pathname = `/folder/${encodeBase64Url2(options.root)}/document/${encodeBase64Url2(relative14(options.root, options.target))}`;
|
|
40606
40941
|
if (options.watch)
|
|
40607
40942
|
url.searchParams.set("watch", "1");
|
|
40608
40943
|
return url.href;
|
|
@@ -40613,8 +40948,8 @@ function viewerPortWasExplicit(input) {
|
|
|
40613
40948
|
function isSameOrDescendant(parent, child) {
|
|
40614
40949
|
const parentReal = realpathSync3(parent);
|
|
40615
40950
|
const childReal = realpathSync3(child);
|
|
40616
|
-
const childRelative =
|
|
40617
|
-
return childRelative === "" || !childRelative.startsWith("..") && !
|
|
40951
|
+
const childRelative = relative14(parentReal, childReal);
|
|
40952
|
+
return childRelative === "" || !childRelative.startsWith("..") && !isAbsolute9(childRelative);
|
|
40618
40953
|
}
|
|
40619
40954
|
async function runningViewer(url) {
|
|
40620
40955
|
try {
|
|
@@ -40675,8 +41010,8 @@ async function viewer(input) {
|
|
|
40675
41010
|
await hotViewer(options);
|
|
40676
41011
|
return;
|
|
40677
41012
|
}
|
|
40678
|
-
const web =
|
|
40679
|
-
if (!existsSync6(
|
|
41013
|
+
const web = resolve15(dirname12(fileURLToPath3(import.meta.url)), "../../web");
|
|
41014
|
+
if (!existsSync6(resolve15(web, "index.html"))) {
|
|
40680
41015
|
throw new Error(`Kennel web app not found. Run the CLI build first.`);
|
|
40681
41016
|
}
|
|
40682
41017
|
const remote = options.tailscale || !isLoopbackHost(options.host);
|
|
@@ -40815,14 +41150,14 @@ async function startProtectedShare(handle) {
|
|
|
40815
41150
|
var init_protected_share = () => {};
|
|
40816
41151
|
|
|
40817
41152
|
// packages/preview/src/tailscale-share.ts
|
|
40818
|
-
import { execFile as
|
|
40819
|
-
import { promisify } from "node:util";
|
|
41153
|
+
import { execFile as execFile7 } from "node:child_process";
|
|
41154
|
+
import { promisify as promisify2 } from "node:util";
|
|
40820
41155
|
async function serveConfig() {
|
|
40821
|
-
const { stdout } = await
|
|
41156
|
+
const { stdout } = await run2("tailscale", ["serve", "status", "--json"]);
|
|
40822
41157
|
return JSON.parse(stdout);
|
|
40823
41158
|
}
|
|
40824
41159
|
async function tailscaleHostname() {
|
|
40825
|
-
const { stdout } = await
|
|
41160
|
+
const { stdout } = await run2("tailscale", ["status", "--json"]);
|
|
40826
41161
|
const status = JSON.parse(stdout);
|
|
40827
41162
|
const host = status.Self?.DNSName?.replace(/\.$/, "");
|
|
40828
41163
|
if (status.BackendState !== "Running" || !host || !host.endsWith(".ts.net")) {
|
|
@@ -40841,11 +41176,11 @@ async function startTailscaleProxy(host, port) {
|
|
|
40841
41176
|
const current = await serveConfig();
|
|
40842
41177
|
const handlers = current.Web?.[authority]?.Handlers;
|
|
40843
41178
|
if (handlers?.["/"]?.Proxy === target && Object.keys(handlers).length === 1) {
|
|
40844
|
-
await
|
|
41179
|
+
await run2("tailscale", ["serve", `--https=${port}`, "off"]);
|
|
40845
41180
|
}
|
|
40846
41181
|
};
|
|
40847
41182
|
try {
|
|
40848
|
-
await
|
|
41183
|
+
await run2("tailscale", ["serve", "--bg", "--yes", `--https=${port}`, target], { timeout: 30000 });
|
|
40849
41184
|
const current = await serveConfig();
|
|
40850
41185
|
if (current.AllowFunnel?.[authority] || current.Web?.[authority]?.Handlers?.["/"]?.Proxy !== target) {
|
|
40851
41186
|
throw new Error("Tailscale did not create the expected private HTTPS proxy");
|
|
@@ -40856,13 +41191,13 @@ async function startTailscaleProxy(host, port) {
|
|
|
40856
41191
|
throw error;
|
|
40857
41192
|
}
|
|
40858
41193
|
}
|
|
40859
|
-
var
|
|
41194
|
+
var run2;
|
|
40860
41195
|
var init_tailscale_share = __esm(() => {
|
|
40861
|
-
|
|
41196
|
+
run2 = promisify2(execFile7);
|
|
40862
41197
|
});
|
|
40863
41198
|
|
|
40864
41199
|
// packages/preview/src/share.ts
|
|
40865
|
-
import { dirname as
|
|
41200
|
+
import { dirname as dirname13, resolve as resolve16 } from "node:path";
|
|
40866
41201
|
import { existsSync as existsSync7, realpathSync as realpathSync4 } from "node:fs";
|
|
40867
41202
|
import { fileURLToPath as fileURLToPath4 } from "node:url";
|
|
40868
41203
|
function splitShareArgs(input) {
|
|
@@ -40914,7 +41249,7 @@ function splitShareArgs(input) {
|
|
|
40914
41249
|
if (folder && !existsSync7(folder)) {
|
|
40915
41250
|
throw new Error(`Folder not found: ${folder}`);
|
|
40916
41251
|
}
|
|
40917
|
-
options.folder = folder ?
|
|
41252
|
+
options.folder = folder ? resolve16(folder) : undefined;
|
|
40918
41253
|
return options;
|
|
40919
41254
|
}
|
|
40920
41255
|
async function runningViewerRoot(port = plainViewerPort) {
|
|
@@ -40935,8 +41270,8 @@ async function runningViewerRoot(port = plainViewerPort) {
|
|
|
40935
41270
|
}
|
|
40936
41271
|
async function startPreviewShare(target) {
|
|
40937
41272
|
const root = realpathSync4(target.root);
|
|
40938
|
-
const web =
|
|
40939
|
-
if (!existsSync7(
|
|
41273
|
+
const web = resolve16(dirname13(fileURLToPath4(import.meta.url)), "../../web");
|
|
41274
|
+
if (!existsSync7(resolve16(web, "index.html"))) {
|
|
40940
41275
|
throw new Error("Kennel web app not found. Run the CLI build first.");
|
|
40941
41276
|
}
|
|
40942
41277
|
const host = await tailscaleHostname();
|