kennel 0.2.44 → 0.2.46

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (88) hide show
  1. package/dist/core/api-client.d.ts +1 -1
  2. package/dist/core/api-client.js +69 -3
  3. package/dist/core/runtime.js +649 -140
  4. package/dist/llm/worker.js +11 -2
  5. package/dist/notes/command.js +20 -4
  6. package/dist/package/preview.d.ts +1 -1
  7. package/dist/package/preview.js +881 -540
  8. package/dist/site/hot-viewer.js +4 -4
  9. package/dist/site/server-plugins.js +468 -30
  10. package/dist/site/viewer.d.ts +0 -3
  11. package/dist/site/viewer.js +11 -41
  12. package/dist/tui/launcher.d.ts +11 -0
  13. package/dist/{site/terminal.js → tui/launcher.js} +60 -15
  14. package/package.json +2 -2
  15. package/web/assets/{abnfDiagram-VRR7QNED-ooA_TyhC.js → abnfDiagram-VRR7QNED-BOm3iBSE.js} +1 -1
  16. package/web/assets/{arc-DqQkY48J.js → arc-D_zfnjJW.js} +1 -1
  17. package/web/assets/{architectureDiagram-ZJ3FMSHR-DaXzRGP0.js → architectureDiagram-ZJ3FMSHR-CTXAbDtC.js} +1 -1
  18. package/web/assets/ask-tray-CT6DQRTC-DfTc3bnC.js +1 -0
  19. package/web/assets/{blockDiagram-677ZJIJ3-Br5Y_dbP.js → blockDiagram-677ZJIJ3-CcPWOAKO.js} +1 -1
  20. package/web/assets/{c4Diagram-LMCZKHZV-CWIy0S0N.js → c4Diagram-LMCZKHZV-B_eNO2-f.js} +1 -1
  21. package/web/assets/channel-Dlb_u_Yk.js +1 -0
  22. package/web/assets/{chunk-2Q5K7J3B-8dxcuNwr.js → chunk-2Q5K7J3B-BtQX_f5i.js} +1 -1
  23. package/web/assets/{chunk-32BRIVSS-DB27hz0Y.js → chunk-32BRIVSS-BBtfsm8_.js} +1 -1
  24. package/web/assets/{chunk-5VM5RSS4-CTNxGtbA.js → chunk-5VM5RSS4-CG0bf9ML.js} +1 -1
  25. package/web/assets/{chunk-EX3LRPZG-oKNLktOC.js → chunk-EX3LRPZG-DS2H7ilP.js} +1 -1
  26. package/web/assets/{chunk-JWPE2WC7-DeQNmWoS.js → chunk-JWPE2WC7-CGLMMKkr.js} +1 -1
  27. package/web/assets/{chunk-MOJQB5TN-BrW33Mrb.js → chunk-MOJQB5TN-C76lqDkU.js} +1 -1
  28. package/web/assets/{chunk-RYQCIY6F-DEkTU6j-.js → chunk-RYQCIY6F-ZY-EzC5l.js} +1 -1
  29. package/web/assets/{chunk-V7JOEXUC-BuDLgwdB.js → chunk-V7JOEXUC-sBv90hIh.js} +1 -1
  30. package/web/assets/{chunk-VR4S4FIN-BsNgrrKe.js → chunk-VR4S4FIN-jW9aFTp3.js} +1 -1
  31. package/web/assets/{chunk-XXDRQBXY-DjT1Bydl.js → chunk-XXDRQBXY-FPtE6zce.js} +1 -1
  32. package/web/assets/classDiagram-OUVF2IWQ-CinFzRGQ.js +1 -0
  33. package/web/assets/classDiagram-v2-EOCWNBFH-CinFzRGQ.js +1 -0
  34. package/web/assets/client-5Q4VI7ZT-DYH5SwVp.js +52 -0
  35. package/web/assets/{cose-bilkent-JH36ORCC-BtAklxrd.js → cose-bilkent-JH36ORCC-NdJGLzeJ.js} +1 -1
  36. package/web/assets/{cynefin-VYW2F7L2-DabtZWZy.js → cynefin-VYW2F7L2-D-o_obcW.js} +1 -1
  37. package/web/assets/{cynefinDiagram-TSTJHNR4-DVk8uQ8L.js → cynefinDiagram-TSTJHNR4-RA4QYrtB.js} +1 -1
  38. package/web/assets/{dagre-VKFMJZFB-CiAbBCor.js → dagre-VKFMJZFB-Bq4DfO16.js} +1 -1
  39. package/web/assets/{diagram-FQU43EPY-DWp-OzJz.js → diagram-FQU43EPY-bPnACaba.js} +1 -1
  40. package/web/assets/{diagram-G47NLZAW-YDllS_1P.js → diagram-G47NLZAW-cPca5hvp.js} +1 -1
  41. package/web/assets/{diagram-NH7WQ7WH-BH3l4yRj.js → diagram-NH7WQ7WH-DHyP34H8.js} +1 -1
  42. package/web/assets/{diagram-OA4YK3LP-CszBvxdr.js → diagram-OA4YK3LP-hVk7mHu1.js} +1 -1
  43. package/web/assets/{diagram-WEI45ONY-bEhZeER6.js → diagram-WEI45ONY-Cd3AEJO3.js} +1 -1
  44. package/web/assets/document-view-VX2ZTQM5-CDdtofzz.js +24 -0
  45. package/web/assets/{ebnfDiagram-CCIWWBDH-DlpoUUO5.js → ebnfDiagram-CCIWWBDH-BxtDx2MR.js} +1 -1
  46. package/web/assets/{entity-search-page-YP4SPMBC-WryWZNPk.js → entity-search-page-RIYQYIJJ-IvZzjXvt.js} +5 -5
  47. package/web/assets/{erDiagram-Q63AITRT-DROgehIM.js → erDiagram-Q63AITRT-CtdOkrpo.js} +1 -1
  48. package/web/assets/{flowDiagram-23GEKE2U-63pYiBzl.js → flowDiagram-23GEKE2U-BDHfaJo6.js} +1 -1
  49. package/web/assets/{ganttDiagram-NO4QXBWP-tc34wKHJ.js → ganttDiagram-NO4QXBWP-BhV7JFJA.js} +1 -1
  50. package/web/assets/{gitGraphDiagram-IHSO6WYX-GOjqt583.js → gitGraphDiagram-IHSO6WYX-BVRBRDVk.js} +1 -1
  51. package/web/assets/index-BxCXNDe6.css +1 -0
  52. package/web/assets/index-Cl-kcrk3.js +502 -0
  53. package/web/assets/{infoDiagram-FWYZ7A6U-CD5BwkLQ.js → infoDiagram-FWYZ7A6U-BKuFQe6t.js} +1 -1
  54. package/web/assets/{ishikawaDiagram-FXEZZL3T-yIweY6wR.js → ishikawaDiagram-FXEZZL3T-lNbhlHEo.js} +1 -1
  55. package/web/assets/{journeyDiagram-5HDEW3XC-D3MeUGvn.js → journeyDiagram-5HDEW3XC-CoGf_pSm.js} +1 -1
  56. package/web/assets/{kanban-definition-HUTT4EX6-CnZ5N79y.js → kanban-definition-HUTT4EX6-Cgp0WGrq.js} +1 -1
  57. package/web/assets/{linear-s5G6iOMz.js → linear-B3UMk7TK.js} +1 -1
  58. package/web/assets/{linked-session-header-DOEX4FYM-CtTOXcZn.js → linked-session-header-7BUTWROP-Coqn-Dz0.js} +1 -1
  59. package/web/assets/{mermaid.core-BpUKp9r_.js → mermaid.core-6bZ5bkAq.js} +4 -4
  60. package/web/assets/{mindmap-definition-LN4V7U3C-Bp2QH5sN.js → mindmap-definition-LN4V7U3C-BowQNgIG.js} +1 -1
  61. package/web/assets/{pegDiagram-2B236MQR-lx1jDUmt.js → pegDiagram-2B236MQR-DrhWFvfI.js} +1 -1
  62. package/web/assets/{pieDiagram-ENE6RG2P--kf2YNbw.js → pieDiagram-ENE6RG2P-DNOg53mu.js} +1 -1
  63. package/web/assets/{plugin-host-modules-BKbxlu7U.js → plugin-host-modules-NvyHieUX.js} +26 -26
  64. package/web/assets/{project-search-page-TZG7AZBQ-3W40ayYn.js → project-search-page-O6YRLDGU-CFA4lf0c.js} +2 -2
  65. package/web/assets/{quadrantDiagram-ABIIQ3AL-Vr7zWQYV.js → quadrantDiagram-ABIIQ3AL-BOJ4UGbk.js} +1 -1
  66. package/web/assets/{railroadDiagram-RFXS5EU6-CqWD8KUC.js → railroadDiagram-RFXS5EU6-_UJ9_AEC.js} +1 -1
  67. package/web/assets/{requirementDiagram-TGXJPOKE-BHUBdOVh.js → requirementDiagram-TGXJPOKE-BFa61FSa.js} +1 -1
  68. package/web/assets/{sankeyDiagram-HTMAVEWB-Cw_ZddWI.js → sankeyDiagram-HTMAVEWB-V1J9w6jl.js} +1 -1
  69. package/web/assets/{selection-popup-ABYH3A27-Gc-RFSWj.js → selection-popup-ZX4VUZ3A-Duh9LSP2.js} +4 -4
  70. package/web/assets/{sequenceDiagram-DBY2YBRQ-CyCbkAfM.js → sequenceDiagram-DBY2YBRQ-xdS7JpTx.js} +1 -1
  71. package/web/assets/{sizeCapture-X5ZJPWSS-BG6RM8rb.js → sizeCapture-X5ZJPWSS-DBULLaws.js} +1 -1
  72. package/web/assets/{stateDiagram-2N3HPSRC-DKpZl5UU.js → stateDiagram-2N3HPSRC-DfBpQAQb.js} +1 -1
  73. package/web/assets/{stateDiagram-v2-6OUMAXLB-DHUy-0iS.js → stateDiagram-v2-6OUMAXLB-C-dC_PIX.js} +1 -1
  74. package/web/assets/{swimlanes-5IMT3BWC-D14uyHMH.js → swimlanes-5IMT3BWC-L-RTYuhP.js} +2 -2
  75. package/web/assets/swimlanesDiagram-G3AALYLV-BErklojq.js +8 -0
  76. package/web/assets/{timeline-definition-FHXFAJF6-f4WPhEXS.js → timeline-definition-FHXFAJF6-CAEbvdzk.js} +1 -1
  77. package/web/assets/{vennDiagram-L72KCM5P-lr4A8guw.js → vennDiagram-L72KCM5P-J10bFP8c.js} +1 -1
  78. package/web/assets/{wardleyDiagram-EHGQE667-CR-Im585.js → wardleyDiagram-EHGQE667-Bm0goK-9.js} +1 -1
  79. package/web/assets/{xychartDiagram-FW5EYKEG-DeNQfP7k.js → xychartDiagram-FW5EYKEG-BAH4TTVb.js} +1 -1
  80. package/web/index.html +2 -2
  81. package/dist/site/terminal.d.ts +0 -14
  82. package/web/assets/ask-tray-KUTWZ4MV-Ckn1y1Zw.js +0 -24
  83. package/web/assets/channel-BQxXBpeY.js +0 -1
  84. package/web/assets/classDiagram-OUVF2IWQ-BT1TSwZs.js +0 -1
  85. package/web/assets/classDiagram-v2-EOCWNBFH-BT1TSwZs.js +0 -1
  86. package/web/assets/index-Di6pguZz.css +0 -1
  87. package/web/assets/index-qmu99cjp.js +0 -493
  88. package/web/assets/swimlanesDiagram-G3AALYLV-C5riej52.js +0 -8
@@ -17027,8 +17027,8 @@ var require__2020 = __commonJS(function(exports, module) {
17027
17027
  import {
17028
17028
  createServer
17029
17029
  } from "node:http";
17030
- import { readFile as readFile11, realpath as realpath8, stat as stat10 } from "node:fs/promises";
17031
- import { extname as extname7, isAbsolute as isAbsolute8, relative as relative12, resolve as resolve13 } from "node:path";
17030
+ import { readFile as readFile12, realpath as realpath10, stat as stat13 } from "node:fs/promises";
17031
+ import { extname as extname8, isAbsolute as isAbsolute9, relative as relative14, resolve as resolve17 } from "node:path";
17032
17032
 
17033
17033
  // packages/api/src/server/watcher.ts
17034
17034
  import { existsSync, statSync, watch } from "node:fs";
@@ -21739,6 +21739,7 @@ var plugin = object({
21739
21739
  icon: object({ paths: array(string2().min(1)).min(1) }).optional(),
21740
21740
  id: string2(),
21741
21741
  label: string2(),
21742
+ pages: array(object({ id: string2(), label: string2() })).optional(),
21742
21743
  subpath: string2().optional()
21743
21744
  });
21744
21745
  var plugins = object({
@@ -21795,6 +21796,10 @@ var metadataQuerySchema = object({
21795
21796
  sort: _enum(["alpha", "recent"]).optional(),
21796
21797
  schema: string2().optional()
21797
21798
  });
21799
+ var deleteNoteSchema = object({
21800
+ folder: string2(),
21801
+ path: string2()
21802
+ });
21798
21803
  var documentEditSchema = object({
21799
21804
  folder: string2(),
21800
21805
  path: string2(),
@@ -21854,7 +21859,11 @@ var routes = {
21854
21859
  path: "/api/health",
21855
21860
  method: "get",
21856
21861
  query: emptyQuery,
21857
- response: object({ viewer: string2(), root: string2(), kernelKey: string2() })
21862
+ response: object({
21863
+ viewer: string2(),
21864
+ root: string2(),
21865
+ kernelKey: string2()
21866
+ })
21858
21867
  },
21859
21868
  capabilities: {
21860
21869
  path: "/api/capabilities",
@@ -21942,6 +21951,13 @@ var routes = {
21942
21951
  path: "/api/open-path",
21943
21952
  method: "get",
21944
21953
  query: object({ path: string2() })
21954
+ },
21955
+ deleteNote: {
21956
+ path: "/api/delete-note",
21957
+ method: "post",
21958
+ query: emptyQuery,
21959
+ body: deleteNoteSchema,
21960
+ response: object({ deleted: literal(true) })
21945
21961
  }
21946
21962
  };
21947
21963
 
@@ -21993,17 +22009,17 @@ function sendContract(response, url, body, headers = {}) {
21993
22009
  }
21994
22010
 
21995
22011
  // packages/api/src/server/folder-metadata-plugin.ts
21996
- import { realpathSync as realpathSync2 } from "node:fs";
21997
- import { readdir as readdir6, readFile as readFile10, realpath as realpath7, stat as stat9 } from "node:fs/promises";
22012
+ import { realpathSync as realpathSync3 } from "node:fs";
22013
+ import { readdir as readdir7, readFile as readFile11, realpath as realpath9, stat as stat12 } from "node:fs/promises";
21998
22014
  import { homedir as homedir4 } from "node:os";
21999
22015
  import {
22000
- basename as basename7,
22001
- dirname as dirname10,
22002
- extname as extname6,
22003
- isAbsolute as isAbsolute7,
22004
- relative as relative11,
22005
- resolve as resolve12,
22006
- sep as sep8
22016
+ basename as basename8,
22017
+ dirname as dirname13,
22018
+ extname as extname7,
22019
+ isAbsolute as isAbsolute8,
22020
+ relative as relative13,
22021
+ resolve as resolve16,
22022
+ sep as sep11
22007
22023
  } from "node:path";
22008
22024
 
22009
22025
  // node_modules/.bun/@raggle-ai+barkdown@0.7.1+22117d1132b05fb8/node_modules/@raggle-ai/barkdown/dist/react.js
@@ -36708,7 +36724,11 @@ var run = promisify(execFile);
36708
36724
  var REPOSITORY_ID_KEY = "kennel.repoId";
36709
36725
  var UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/u;
36710
36726
  var markdownExtensions = new Set([".md", ".markdown"]);
36711
- var caseInsensitiveHosts = new Set(["github.com", "gitlab.com", "bitbucket.org"]);
36727
+ var caseInsensitiveHosts = new Set([
36728
+ "github.com",
36729
+ "gitlab.com",
36730
+ "bitbucket.org"
36731
+ ]);
36712
36732
  class RepositoryNotesError extends Error {
36713
36733
  code;
36714
36734
  constructor(code, message) {
@@ -36789,7 +36809,12 @@ async function resolveCheckout(folder) {
36789
36809
  }
36790
36810
  let output;
36791
36811
  try {
36792
- output = await git(["rev-parse", "--path-format=absolute", "--show-toplevel", "--git-common-dir"], start);
36812
+ output = await git([
36813
+ "rev-parse",
36814
+ "--path-format=absolute",
36815
+ "--show-toplevel",
36816
+ "--git-common-dir"
36817
+ ], start);
36793
36818
  } catch (error) {
36794
36819
  if (gitExitCode(error) === 128) {
36795
36820
  throw new RepositoryNotesError("not-git", `Not a Git repository: ${start}. Repository notes need a Git checkout.`);
@@ -37119,23 +37144,55 @@ async function loadEntityWorkspace(root, query, selectedPath, currentWorkspaceRo
37119
37144
  return { entities, query, rootPath, selected };
37120
37145
  }
37121
37146
 
37147
+ // packages/api/src/server/api/delete-note.ts
37148
+ import { realpath as realpath5, stat as stat5, unlink as unlink2 } from "node:fs/promises";
37149
+ import { extname as extname3, isAbsolute as isAbsolute5, relative as relative8, resolve as resolve8, sep as sep5 } from "node:path";
37150
+ var markdownExtensions2 = new Set([".md", ".markdown"]);
37151
+ var deleteNoteRoute = {
37152
+ method: "POST",
37153
+ maxBodyBytes: 4 * 1024,
37154
+ async handle({ body, context, response }) {
37155
+ const parsed = deleteNoteSchema.safeParse(parseJsonBody(body));
37156
+ if (!parsed.success)
37157
+ throw apiError("bad-request", "Invalid delete request.");
37158
+ const folder = context.authorize(parsed.data.folder);
37159
+ if (!markdownExtensions2.has(extname3(parsed.data.path).toLowerCase()))
37160
+ throw apiError("bad-request", "Only Markdown notes can be deleted.");
37161
+ const target = await containedTarget(parsed.data.path, folder);
37162
+ const details = await stat5(target).catch(() => {
37163
+ return;
37164
+ });
37165
+ if (!details?.isFile() || details.nlink !== 1)
37166
+ throw apiError("forbidden", "Only regular, unlinked files can be deleted.");
37167
+ await unlink2(target);
37168
+ jsonResponse(response, 200, routes.deleteNote.response.parse({ deleted: true }));
37169
+ }
37170
+ };
37171
+ async function containedTarget(path, folder) {
37172
+ const target = await realpath5(resolve8(folder, path));
37173
+ const local = relative8(folder, target);
37174
+ if (!local || local === ".." || local.startsWith(`..${sep5}`) || isAbsolute5(local))
37175
+ throw apiError("forbidden", "The note must be inside its folder.");
37176
+ return target;
37177
+ }
37178
+
37122
37179
  // packages/api/src/server/api/document-edit.ts
37123
37180
  import { randomUUID as randomUUID2 } from "node:crypto";
37124
37181
  import {
37125
37182
  readFile as readFile6,
37126
- realpath as realpath5,
37183
+ realpath as realpath6,
37127
37184
  rename as rename3,
37128
- stat as stat5,
37129
- unlink as unlink2,
37185
+ stat as stat6,
37186
+ unlink as unlink3,
37130
37187
  writeFile as writeFile3
37131
37188
  } from "node:fs/promises";
37132
37189
  import {
37133
37190
  dirname as dirname7,
37134
- extname as extname3,
37135
- isAbsolute as isAbsolute5,
37136
- relative as relative8,
37137
- resolve as resolve8,
37138
- sep as sep5
37191
+ extname as extname4,
37192
+ isAbsolute as isAbsolute6,
37193
+ relative as relative9,
37194
+ resolve as resolve9,
37195
+ sep as sep6
37139
37196
  } from "node:path";
37140
37197
 
37141
37198
  // packages/api/src/shared/selection.ts
@@ -37151,12 +37208,12 @@ async function editDocument(folder, input) {
37151
37208
  const { path, original, start, end, replacement } = input;
37152
37209
  if (typeof path !== "string" || typeof original !== "string" || typeof replacement !== "string" || typeof start !== "number" || typeof end !== "number")
37153
37210
  throw apiError("bad-request", "Invalid document edit.");
37154
- if (![".md", ".markdown"].includes(extname3(path).toLowerCase()))
37211
+ if (![".md", ".markdown"].includes(extname4(path).toLowerCase()))
37155
37212
  throw apiError("bad-request", "Only Markdown notes can be edited.");
37156
- const root = await realpath5(folder);
37157
- const target = await realpath5(resolve8(root, path));
37158
- const local = relative8(root, target);
37159
- if (!local || local === ".." || local.startsWith(`..${sep5}`) || isAbsolute5(local))
37213
+ const root = await realpath6(folder);
37214
+ const target = await realpath6(resolve9(root, path));
37215
+ const local = relative9(root, target);
37216
+ if (!local || local === ".." || local.startsWith(`..${sep6}`) || isAbsolute6(local))
37160
37217
  throw apiError("forbidden", "The document must be inside its folder.");
37161
37218
  let content;
37162
37219
  try {
@@ -37166,12 +37223,12 @@ async function editDocument(folder, input) {
37166
37223
  }
37167
37224
  const previous = pending.get(target) ?? Promise.resolve();
37168
37225
  const operation = previous.catch(() => {}).then(async () => {
37169
- const details = await stat5(target);
37226
+ const details = await stat6(target);
37170
37227
  if (!details.isFile() || details.nlink !== 1)
37171
37228
  throw apiError("forbidden", "Only regular, unlinked files can be edited.");
37172
37229
  if (await readFile6(target, "utf8") !== original)
37173
37230
  throw apiError("conflict", "This note changed on disk. Close this preview, reload the note, and try again.");
37174
- const temporary = resolve8(dirname7(target), `.kennel-edit-${randomUUID2()}.tmp`);
37231
+ const temporary = resolve9(dirname7(target), `.kennel-edit-${randomUUID2()}.tmp`);
37175
37232
  try {
37176
37233
  await writeFile3(temporary, content, {
37177
37234
  flag: "wx",
@@ -37181,7 +37238,7 @@ async function editDocument(folder, input) {
37181
37238
  throw apiError("conflict", "This note changed on disk. Reload before applying an edit.");
37182
37239
  await rename3(temporary, target);
37183
37240
  } finally {
37184
- await unlink2(temporary).catch(() => {});
37241
+ await unlink3(temporary).catch(() => {});
37185
37242
  }
37186
37243
  return content;
37187
37244
  });
@@ -37202,7 +37259,7 @@ var documentEditRoute = {
37202
37259
  throw apiError("bad-request", "Invalid document edit.");
37203
37260
  const input = parsed.data;
37204
37261
  const folder = context.authorize(input.folder);
37205
- if (context.lockedFile && (typeof input.path !== "string" || await realpath5(resolve8(folder, input.path)) !== context.lockedFile))
37262
+ if (context.lockedFile && (typeof input.path !== "string" || await realpath6(resolve9(folder, input.path)) !== context.lockedFile))
37206
37263
  throw apiError("forbidden", "Only the selected document can be edited.");
37207
37264
  await editDocument(folder, input);
37208
37265
  jsonResponse(response, 200, routes.documentEdit.response.parse({ saved: true }));
@@ -37211,7 +37268,7 @@ var documentEditRoute = {
37211
37268
 
37212
37269
  // packages/api/src/server/api/create-agent-file.ts
37213
37270
  import { writeFile as writeFile4 } from "node:fs/promises";
37214
- import { resolve as resolve9 } from "node:path";
37271
+ import { resolve as resolve10 } from "node:path";
37215
37272
  var createAgentFileRoute = {
37216
37273
  method: "POST",
37217
37274
  maxBodyBytes: 0,
@@ -37222,7 +37279,7 @@ var createAgentFileRoute = {
37222
37279
  } catch (error) {
37223
37280
  throw apiError("not-found", error instanceof Error ? error.message : "Folder not found");
37224
37281
  }
37225
- const target = resolve9(folder, "AGENTS.md");
37282
+ const target = resolve10(folder, "AGENTS.md");
37226
37283
  try {
37227
37284
  await writeFile4(target, "", { flag: "wx" });
37228
37285
  } catch (error) {
@@ -37274,8 +37331,8 @@ async function folderWebsite(folder) {
37274
37331
 
37275
37332
  // packages/api/src/server/folder-icons.ts
37276
37333
  import { createHash as createHash4 } from "node:crypto";
37277
- import { readFile as readFile8, stat as stat6 } from "node:fs/promises";
37278
- import { extname as extname4 } from "node:path";
37334
+ import { readFile as readFile8, stat as stat7 } from "node:fs/promises";
37335
+ import { extname as extname5 } from "node:path";
37279
37336
  import { discoverFolderIcon } from "@raggle-ai/local";
37280
37337
  var maxIconBytes2 = 4 * 1024 * 1024;
37281
37338
  var iconTypes = new Map([
@@ -37312,8 +37369,8 @@ function iconUrl(folder, hash, mediaType) {
37312
37369
  }
37313
37370
  async function folderIcon(folder, assets, assetFiles, fallback) {
37314
37371
  const icon = discoverFolderIcon(folder);
37315
- const mediaType = icon ? iconTypes.get(extname4(icon).toLowerCase()) : null;
37316
- const details = icon && mediaType ? await stat6(icon).catch(() => {
37372
+ const mediaType = icon ? iconTypes.get(extname5(icon).toLowerCase()) : null;
37373
+ const details = icon && mediaType ? await stat7(icon).catch(() => {
37317
37374
  return;
37318
37375
  }) : undefined;
37319
37376
  if (!icon || !mediaType || !details?.size || details.size > maxIconBytes2) {
@@ -37335,10 +37392,10 @@ async function searchIconDataUrl(icon) {
37335
37392
  return;
37336
37393
  if (icon.startsWith("data:"))
37337
37394
  return icon;
37338
- const mediaType = searchIconTypes.get(extname4(icon).toLowerCase());
37395
+ const mediaType = searchIconTypes.get(extname5(icon).toLowerCase());
37339
37396
  if (!mediaType)
37340
37397
  return;
37341
- const details = await stat6(icon).catch(() => {
37398
+ const details = await stat7(icon).catch(() => {
37342
37399
  return;
37343
37400
  });
37344
37401
  if (!details?.size || details.size > maxSearchIconBytes)
@@ -37388,19 +37445,457 @@ async function workspaceBreadcrumbIcons(breadcrumbs, assetFiles, assets = {}) {
37388
37445
 
37389
37446
  // packages/api/src/server/plugins.ts
37390
37447
  import { pathToFileURL } from "node:url";
37391
- import { existsSync as existsSync3 } from "node:fs";
37392
- import { mkdir as mkdir3, readFile as readFile9, stat as stat8, writeFile as writeFile5 } from "node:fs/promises";
37448
+ import { existsSync as existsSync4 } from "node:fs";
37449
+ import { mkdir as mkdir3, readFile as readFile10, stat as stat11, writeFile as writeFile5 } from "node:fs/promises";
37450
+ import { dirname as dirname11, resolve as resolve15, sep as sep10 } from "node:path";
37451
+
37452
+ // packages/knl/src/server.ts
37453
+ import { stat as stat9 } from "node:fs/promises";
37454
+ import { join as join5 } from "node:path";
37455
+
37456
+ // packages/knl/src/knl.ts
37457
+ import { readdir as readdir5, stat as stat8 } from "node:fs/promises";
37458
+ import { basename as basename6, dirname as dirname10, relative as relative10, resolve as resolve13, sep as sep8 } from "node:path";
37459
+ import * as esbuild from "esbuild";
37460
+
37461
+ // packages/knl/src/folder-guard.ts
37462
+ import { existsSync as existsSync3, realpathSync as realpathSync2 } from "node:fs";
37463
+ import { realpath as realpath7 } from "node:fs/promises";
37393
37464
  import { dirname as dirname8, resolve as resolve11, sep as sep7 } from "node:path";
37465
+ import { fileURLToPath } from "node:url";
37466
+ var knlHostResolveDir = dirname8(fileURLToPath(import.meta.url));
37467
+ var knlHostPackageFolders = (() => {
37468
+ const folders = [];
37469
+ let current = knlHostResolveDir;
37470
+ while (true) {
37471
+ const nodeModules = resolve11(current, "node_modules");
37472
+ if (existsSync3(nodeModules))
37473
+ folders.push(nodeModules);
37474
+ const parent = dirname8(current);
37475
+ if (parent === current)
37476
+ return folders;
37477
+ current = parent;
37478
+ }
37479
+ })();
37480
+ async function knlRealRoot(owner) {
37481
+ const expected = resolve11(await realpath7(owner), "knl");
37482
+ const real = await realpath7(resolve11(owner, "knl"));
37483
+ if (real !== expected)
37484
+ throw new Error("knl/ must be a folder, not a link to another place.");
37485
+ return real;
37486
+ }
37487
+ async function knlReadRoots(owner) {
37488
+ const packages = await Promise.all(knlHostPackageFolders.map((folder) => realpath7(folder).catch(() => {
37489
+ return;
37490
+ })));
37491
+ return [
37492
+ await knlRealRoot(owner),
37493
+ ...packages.filter((folder) => Boolean(folder))
37494
+ ];
37495
+ }
37496
+ function isKnlReadable(file, roots) {
37497
+ let real;
37498
+ try {
37499
+ real = realpathSync2(file);
37500
+ } catch {
37501
+ real = resolve11(file);
37502
+ }
37503
+ return roots.some((root) => real === root || real.startsWith(`${root}${sep7}`));
37504
+ }
37505
+ function knlReadError(file) {
37506
+ return `KNL pages can only use files in knl/ and installed packages: ${file}`;
37507
+ }
37508
+ function assertKnlReadable(file, roots) {
37509
+ if (!isKnlReadable(file, roots))
37510
+ throw new Error(knlReadError(file));
37511
+ }
37512
+
37513
+ // packages/knl/src/tailwind.ts
37514
+ import { readFile as readFile9 } from "node:fs/promises";
37515
+ import { createRequire as createRequire2 } from "node:module";
37516
+ import { dirname as dirname9, resolve as resolve12 } from "node:path";
37517
+ import { compile } from "@tailwindcss/node";
37518
+ import { Scanner } from "@tailwindcss/oxide";
37519
+ var require2 = createRequire2(import.meta.url);
37520
+ function starterKnlStyles() {
37521
+ return `@layer theme, utilities;
37522
+ @import "tailwindcss/theme.css" layer(theme) prefix(knl);
37523
+ @import "tailwindcss/utilities.css" layer(utilities) source(none);
37524
+
37525
+ @theme {
37526
+ --font-sans: system-ui, sans-serif;
37527
+ }
37528
+ `;
37529
+ }
37530
+ async function compileKnlCss(js, stylesheet, roots) {
37531
+ const base = dirname9(stylesheet);
37532
+ assertKnlReadable(stylesheet, roots);
37533
+ const css = await readFile9(stylesheet, "utf8").catch((error) => {
37534
+ if (error.code === "ENOENT")
37535
+ return starterKnlStyles();
37536
+ throw error;
37537
+ });
37538
+ const compiler = await compile(css, {
37539
+ base,
37540
+ from: stylesheet,
37541
+ onDependency: (path) => assertKnlReadable(path, roots),
37542
+ customJsResolver: async (id) => {
37543
+ throw new Error(`KNL does not load Tailwind plugins or configs (${id}).`);
37544
+ },
37545
+ customCssResolver: async (id) => id === "tailwindcss" || id.startsWith("tailwindcss/") ? require2.resolve(id) : undefined
37546
+ });
37547
+ const sources = [...compiler.sources];
37548
+ if (compiler.root !== "none") {
37549
+ sources.push({
37550
+ ...compiler.root ?? { base, pattern: "**/*" },
37551
+ negated: false
37552
+ });
37553
+ }
37554
+ for (const source of sources) {
37555
+ if (source.negated)
37556
+ continue;
37557
+ const fixed = source.pattern.split("/");
37558
+ const glob = fixed.findIndex((part) => /[*?[{]/.test(part));
37559
+ assertKnlReadable(resolve12(source.base, fixed.slice(0, glob < 0 ? undefined : glob).join("/")), roots);
37560
+ }
37561
+ const scanner = new Scanner({ sources });
37562
+ const candidates = [
37563
+ ...scanner.scan(),
37564
+ ...scanner.scanFiles([{ content: js, extension: "js" }])
37565
+ ];
37566
+ return compiler.build(candidates);
37567
+ }
37568
+
37569
+ // packages/knl/src/knl.ts
37570
+ var KNK_FOLDER = "knl";
37571
+ var MAX_SOURCE_BYTES = 512 * 1024;
37572
+ var MAX_JS_BYTES = 5 * 1024 * 1024;
37573
+ var MODULE_FILES = ["index.tsx", "index.ts"];
37574
+ function sourceFor(file, knlRoot, scanRoot, owner) {
37575
+ const id = toModuleId(file, knlRoot);
37576
+ return {
37577
+ id,
37578
+ file,
37579
+ relative: relative10(scanRoot, file).split(sep8).join("/"),
37580
+ folder: dirname10(file),
37581
+ owner
37582
+ };
37583
+ }
37584
+ function toModuleId(file, knlRoot) {
37585
+ const relativeKnl = relative10(knlRoot, file).split(sep8).join("/");
37586
+ return relativeKnl.replace(/\/?index\.(tsx|ts)$/, "") || "index";
37587
+ }
37588
+ async function collectKnlSources(scanRoot, owner) {
37589
+ const knlRoot = resolve13(scanRoot, KNK_FOLDER);
37590
+ const knlEntries = await readdir5(knlRoot, { withFileTypes: true }).catch(() => []);
37591
+ const sources = [];
37592
+ const addModule = async (folder) => {
37593
+ for (const candidate of MODULE_FILES) {
37594
+ const file = resolve13(folder, candidate);
37595
+ if (await stat8(file).then((d) => d.isFile()).catch(() => false)) {
37596
+ sources.push(sourceFor(file, knlRoot, scanRoot, owner));
37597
+ return;
37598
+ }
37599
+ }
37600
+ };
37601
+ await addModule(knlRoot);
37602
+ for (const entry of knlEntries) {
37603
+ if (!entry.isDirectory())
37604
+ continue;
37605
+ if (entry.name.startsWith(".") || entry.name === "node_modules")
37606
+ continue;
37607
+ await addModule(resolve13(knlRoot, entry.name));
37608
+ }
37609
+ return sources.sort((left, right) => {
37610
+ const rank = (left.id === "index" ? 0 : 1) - (right.id === "index" ? 0 : 1);
37611
+ return rank !== 0 ? rank : left.id.localeCompare(right.id);
37612
+ });
37613
+ }
37614
+ async function loadKnlSources(viewRoot, linkedFolders = []) {
37615
+ const sources = [
37616
+ ...await collectKnlSources(viewRoot, viewRoot),
37617
+ ...(await Promise.all(linkedFolders.map(async (folder) => (await collectKnlSources(folder, folder)).map((source) => ({
37618
+ ...source,
37619
+ id: `${basename6(folder)}:${source.id}`,
37620
+ relative: `${basename6(folder)}/${source.relative}`
37621
+ }))))).flat()
37622
+ ];
37623
+ return { sources };
37624
+ }
37625
+ var MAX_CACHED_MODULES = 200;
37626
+ var compileCache = new Map;
37627
+ function knlNodePaths(knlRoot) {
37628
+ return [resolve13(knlRoot, "node_modules"), ...knlHostPackageFolders];
37629
+ }
37630
+ async function compileKnlSource(source) {
37631
+ const sourceBytes = (await stat8(source.file)).size;
37632
+ const tooLarge = (bytes, what) => ({
37633
+ id: source.id,
37634
+ relative: source.relative,
37635
+ js: "",
37636
+ css: "",
37637
+ issues: [
37638
+ {
37639
+ path: source.relative,
37640
+ message: `Module ${what} is too large (${bytes} bytes; limit ${MAX_SOURCE_BYTES}).`
37641
+ }
37642
+ ]
37643
+ });
37644
+ if (sourceBytes > MAX_SOURCE_BYTES)
37645
+ return tooLarge(sourceBytes, "source");
37646
+ const cached = compileCache.get(source.file);
37647
+ const unchanged = cached && (await Promise.all(cached.dependencies.map(async ({ file, mtimeMs }) => (await stat8(file).catch(() => {
37648
+ return;
37649
+ }))?.mtimeMs === mtimeMs))).every(Boolean);
37650
+ const knlRoot = resolve13(source.owner, KNK_FOLDER);
37651
+ let issuePath = source.relative;
37652
+ try {
37653
+ const nodePaths = knlNodePaths(knlRoot);
37654
+ const roots = await knlReadRoots(source.owner);
37655
+ assertKnlReadable(source.file, roots);
37656
+ let js;
37657
+ if (cached && unchanged) {
37658
+ js = cached.js;
37659
+ } else {
37660
+ const result = await esbuild.build({
37661
+ absWorkingDir: source.folder,
37662
+ stdin: {
37663
+ contents: `import { createElement } from "react"
37664
+ import { createRoot } from "react-dom/client"
37665
+ import Component from ${JSON.stringify(source.file)}
37666
+
37667
+ globalThis.__knlMount = (container, context, onError) => {
37668
+ const root = createRoot(container, { onUncaughtError: onError })
37669
+ root.render(createElement(Component, context))
37670
+ }
37671
+ `,
37672
+ sourcefile: `${source.file}.mount.ts`,
37673
+ loader: "ts",
37674
+ resolveDir: source.folder
37675
+ },
37676
+ bundle: true,
37677
+ format: "iife",
37678
+ target: "es2022",
37679
+ jsx: "automatic",
37680
+ platform: "browser",
37681
+ write: false,
37682
+ minify: false,
37683
+ sourcemap: false,
37684
+ logLevel: "silent",
37685
+ metafile: true,
37686
+ nodePaths,
37687
+ plugins: [readGuard(roots)]
37688
+ });
37689
+ js = result.outputFiles?.[0]?.text ?? "";
37690
+ const files = new Set([
37691
+ resolve13(knlRoot, "package.json"),
37692
+ ...Object.keys(result.metafile.inputs).map((file) => resolve13(source.folder, file)).filter((file) => file !== `${source.file}.mount.ts`)
37693
+ ]);
37694
+ const dependencies = await Promise.all([...files].map(async (file) => ({
37695
+ file,
37696
+ mtimeMs: (await stat8(file).catch(() => {
37697
+ return;
37698
+ }))?.mtimeMs
37699
+ })));
37700
+ compileCache.delete(source.file);
37701
+ compileCache.set(source.file, { js, dependencies });
37702
+ if (compileCache.size > MAX_CACHED_MODULES)
37703
+ compileCache.delete(compileCache.keys().next().value);
37704
+ }
37705
+ const stylesheet = resolve13(knlRoot, "style.css");
37706
+ issuePath = relative10(source.owner, stylesheet).split(sep8).join("/");
37707
+ const css = await compileKnlCss(js, stylesheet, roots);
37708
+ issuePath = source.relative;
37709
+ if (js.length + css.length > MAX_JS_BYTES) {
37710
+ return {
37711
+ id: source.id,
37712
+ relative: source.relative,
37713
+ js: "",
37714
+ css: "",
37715
+ issues: [
37716
+ {
37717
+ path: source.relative,
37718
+ message: `Compiled module is too large (${js.length + css.length} bytes; limit ${MAX_JS_BYTES}).`
37719
+ }
37720
+ ]
37721
+ };
37722
+ }
37723
+ return { id: source.id, relative: source.relative, js, css, issues: [] };
37724
+ } catch (error) {
37725
+ return {
37726
+ id: source.id,
37727
+ relative: source.relative,
37728
+ js: "",
37729
+ css: "",
37730
+ issues: knlBuildIssues(error, issuePath, source)
37731
+ };
37732
+ }
37733
+ }
37734
+ var guardResolve = Symbol("knl-guard");
37735
+ function readGuard(roots) {
37736
+ return {
37737
+ name: "knl-read-guard",
37738
+ setup(build) {
37739
+ build.onResolve({ filter: /.*/ }, async (args) => {
37740
+ if (args.pluginData === guardResolve)
37741
+ return;
37742
+ const resolveFrom = (resolveDir) => build.resolve(args.path, {
37743
+ importer: args.importer,
37744
+ kind: args.kind,
37745
+ pluginData: guardResolve,
37746
+ resolveDir
37747
+ });
37748
+ const readable = (result) => result.namespace !== "file" || !result.path || isKnlReadable(result.path, roots);
37749
+ let result = await resolveFrom(args.resolveDir);
37750
+ const bare = !/^(?:\.{1,2}(?:\/|$)|\/)/.test(args.path);
37751
+ if (bare && result.errors.length === 0 && !readable(result))
37752
+ result = await resolveFrom(knlHostResolveDir);
37753
+ if (result.errors.length > 0)
37754
+ return { errors: result.errors };
37755
+ if (!readable(result))
37756
+ return { errors: [{ text: knlReadError(args.path) }] };
37757
+ return result;
37758
+ });
37759
+ }
37760
+ };
37761
+ }
37762
+ function knlBuildIssues(error, relativePath, source) {
37763
+ const failures = error?.errors;
37764
+ if (Array.isArray(failures) && failures.length > 0) {
37765
+ const first = failures[0];
37766
+ const file = first?.location?.file ? relative10(source.owner, resolve13(source.folder, first.location.file)).split(sep8).join("/") : relativePath;
37767
+ const location = first?.location ? `${file}:${first.location.line ?? "?"}` : relativePath;
37768
+ return [
37769
+ { path: location, message: first?.text ?? "Module failed to compile." }
37770
+ ];
37771
+ }
37772
+ return [
37773
+ {
37774
+ path: relativePath,
37775
+ message: error instanceof Error && error.message ? error.message : "Module failed to compile."
37776
+ }
37777
+ ];
37778
+ }
37779
+ function starterKnlSource() {
37780
+ return `// knl/index.tsx — this folder's homepage (KNL folder web framework).
37781
+ // Every other page lives in its own folder: knl/<page>/index.tsx.
37782
+ import * as React from "react"
37783
+
37784
+ export default function Home() {
37785
+ return (
37786
+ <div className="knl:p-4 knl:font-sans">
37787
+ <h1 className="knl:m-0 knl:text-2xl">Home</h1>
37788
+ <p>Edit this file to build the homepage.</p>
37789
+ </div>
37790
+ )
37791
+ }
37792
+ `;
37793
+ }
37794
+
37795
+ // packages/knl/src/manifest.ts
37796
+ var knlManifest = {
37797
+ id: "knl",
37798
+ label: "KNL"
37799
+ };
37800
+
37801
+ // packages/knl/src/server.ts
37802
+ function createKnlPlugin() {
37803
+ return {
37804
+ ...knlManifest,
37805
+ async detect(context) {
37806
+ const hasKnlFolder = await stat9(join5(context.folder, KNK_FOLDER)).then((entry) => entry.isDirectory()).catch(() => false);
37807
+ if (!hasKnlFolder)
37808
+ return { status: "unavailable" };
37809
+ const { sources } = await loadKnlSources(context.folder, context.linkedFolders ?? []);
37810
+ if (!sources.some((source) => source.id === "index"))
37811
+ return { status: "unavailable" };
37812
+ return {
37813
+ count: sources.length,
37814
+ pages: sources.filter((source) => source.id !== "index" && !source.id.endsWith(":index")).map((source) => ({
37815
+ id: source.id,
37816
+ label: source.id.replaceAll(/[-_]/g, " ").replace(/^./, (letter) => letter.toUpperCase())
37817
+ })),
37818
+ status: "available"
37819
+ };
37820
+ },
37821
+ async handle(context, subpath) {
37822
+ const { sources } = await loadKnlSources(context.folder, context.linkedFolders ?? []);
37823
+ const folder = context.folder;
37824
+ if (sources.length === 0) {
37825
+ return { kind: "available", data: { folder, status: "unavailable" } };
37826
+ }
37827
+ const requested = subpath.trim() || "index";
37828
+ const selected = sources.filter((source) => source.id === requested);
37829
+ if (selected.length === 0) {
37830
+ return {
37831
+ kind: "available",
37832
+ data: {
37833
+ folder,
37834
+ status: "error",
37835
+ message: `KNL page not found: ${requested}`
37836
+ }
37837
+ };
37838
+ }
37839
+ const compiled = await Promise.all(selected.map(compileKnlSource));
37840
+ const entries = compiled.map((result) => {
37841
+ const source = sources.find((item) => item.id === result.id);
37842
+ return {
37843
+ id: result.id,
37844
+ relative: result.relative,
37845
+ ...result.js ? { js: result.js } : {},
37846
+ css: result.css,
37847
+ ...result.issues.length > 0 ? { issues: result.issues } : {},
37848
+ owner: source?.owner ?? folder
37849
+ };
37850
+ });
37851
+ const failing = entries.filter((entry) => entry.issues?.length);
37852
+ if (failing.length > 0) {
37853
+ return {
37854
+ kind: "available",
37855
+ data: {
37856
+ folder,
37857
+ status: "error",
37858
+ entries,
37859
+ issues: failing[0]?.issues
37860
+ }
37861
+ };
37862
+ }
37863
+ return {
37864
+ kind: "available",
37865
+ data: {
37866
+ folder,
37867
+ status: "available",
37868
+ entries
37869
+ }
37870
+ };
37871
+ },
37872
+ async init() {
37873
+ return {
37874
+ files: [
37875
+ { path: "knl/index.tsx", content: starterKnlSource() },
37876
+ { path: "knl/style.css", content: starterKnlStyles() },
37877
+ {
37878
+ path: "knl/package.json",
37879
+ content: `${JSON.stringify({ private: true, type: "module" }, null, 2)}
37880
+ `
37881
+ },
37882
+ { path: "knl/.gitignore", content: `node_modules/
37883
+ ` }
37884
+ ]
37885
+ };
37886
+ }
37887
+ };
37888
+ }
37394
37889
 
37395
37890
  // packages/notes/src/server.ts
37396
- import { readdir as readdir5, realpath as realpath6, stat as stat7 } from "node:fs/promises";
37891
+ import { readdir as readdir6, realpath as realpath8, stat as stat10 } from "node:fs/promises";
37397
37892
  import {
37398
- basename as basename6,
37399
- extname as extname5,
37400
- isAbsolute as isAbsolute6,
37401
- relative as relative9,
37402
- resolve as resolve10,
37403
- sep as sep6
37893
+ basename as basename7,
37894
+ extname as extname6,
37895
+ isAbsolute as isAbsolute7,
37896
+ relative as relative11,
37897
+ resolve as resolve14,
37898
+ sep as sep9
37404
37899
  } from "node:path";
37405
37900
 
37406
37901
  // packages/notes/src/manifest.ts
@@ -37417,40 +37912,40 @@ var notesManifest = {
37417
37912
  };
37418
37913
 
37419
37914
  // packages/notes/src/server.ts
37420
- var markdownExtensions2 = new Set([".md", ".markdown"]);
37915
+ var markdownExtensions3 = new Set([".md", ".markdown"]);
37421
37916
  var llmNoteLimit = 20;
37422
37917
  async function listMarkdownFiles(folder) {
37423
37918
  const files = [];
37424
37919
  const visit = async (current) => {
37425
- const entries = await readdir5(current, { withFileTypes: true }).catch(() => []);
37920
+ const entries = await readdir6(current, { withFileTypes: true }).catch(() => []);
37426
37921
  for (const entry of entries) {
37427
37922
  if (entry.name === "node_modules" || entry.name.startsWith("."))
37428
37923
  continue;
37429
- const path = resolve10(current, entry.name);
37924
+ const path = resolve14(current, entry.name);
37430
37925
  if (entry.isDirectory()) {
37431
37926
  await visit(path);
37432
37927
  continue;
37433
37928
  }
37434
- if (!entry.isFile() || !markdownExtensions2.has(extname5(entry.name))) {
37929
+ if (!entry.isFile() || !markdownExtensions3.has(extname6(entry.name))) {
37435
37930
  continue;
37436
37931
  }
37437
- const details = await stat7(path).catch(() => {
37932
+ const details = await stat10(path).catch(() => {
37438
37933
  return;
37439
37934
  });
37440
37935
  files.push({
37441
37936
  activityAt: details?.mtimeMs ?? 0,
37442
- name: basename6(entry.name, extname5(entry.name)),
37443
- relativePath: relative9(folder, path).split(sep6).join("/")
37937
+ name: basename7(entry.name, extname6(entry.name)),
37938
+ relativePath: relative11(folder, path).split(sep9).join("/")
37444
37939
  });
37445
37940
  }
37446
37941
  };
37447
37942
  await visit(folder);
37448
37943
  return files.sort((left, right) => right.activityAt - left.activityAt);
37449
37944
  }
37450
- var canonical = (path) => realpath6(path).catch(() => path);
37945
+ var canonical = (path) => realpath8(path).catch(() => path);
37451
37946
  function inside5(path, root) {
37452
- const local = relative9(root, path);
37453
- return local === "" || !local.startsWith("..") && !isAbsolute6(local);
37947
+ const local = relative11(root, path);
37948
+ return local === "" || !local.startsWith("..") && !isAbsolute7(local);
37454
37949
  }
37455
37950
  async function withoutManaged(groups, managedRoots) {
37456
37951
  if (!managedRoots.length)
@@ -37461,7 +37956,7 @@ async function withoutManaged(groups, managedRoots) {
37461
37956
  return { ...group, files: [] };
37462
37957
  }
37463
37958
  const files = await Promise.all(group.files.map(async (file) => {
37464
- const real = await canonical(resolve10(group.folder, file.relativePath));
37959
+ const real = await canonical(resolve14(group.folder, file.relativePath));
37465
37960
  return roots.some((root) => inside5(real, root)) ? undefined : file;
37466
37961
  }));
37467
37962
  return { ...group, files: files.filter((file) => file !== undefined) };
@@ -37511,7 +38006,7 @@ async function notesLlmSections({
37511
38006
  continue;
37512
38007
  seen.add(identity);
37513
38008
  const files = await listMarkdownFiles(source);
37514
- const paths = files.map((file) => resolve10(source, file.relativePath));
38009
+ const paths = files.map((file) => resolve14(source, file.relativePath));
37515
38010
  groups.push({ folder: source, paths });
37516
38011
  files.forEach((file, index) => notes.push({ activityAt: file.activityAt, path: paths[index] }));
37517
38012
  }
@@ -37583,14 +38078,14 @@ function parsePluginRegistryConfig(content) {
37583
38078
  };
37584
38079
  }
37585
38080
  async function nearestKennelConfig(folder) {
37586
- for (let current = folder;; current = dirname8(current)) {
37587
- const candidate = resolve11(current, "kennel.json");
37588
- const details = await stat8(candidate).catch(() => {
38081
+ for (let current = folder;; current = dirname11(current)) {
38082
+ const candidate = resolve15(current, "kennel.json");
38083
+ const details = await stat11(candidate).catch(() => {
37589
38084
  return;
37590
38085
  });
37591
38086
  if (details?.isFile())
37592
38087
  return candidate;
37593
- if (dirname8(current) === current)
38088
+ if (dirname11(current) === current)
37594
38089
  return;
37595
38090
  }
37596
38091
  }
@@ -37599,13 +38094,13 @@ async function folderPluginRegistryConfig(folder) {
37599
38094
  if (!path)
37600
38095
  return defaultPluginRegistryConfig;
37601
38096
  try {
37602
- return parsePluginRegistryConfig(await readFile9(path, "utf8"));
38097
+ return parsePluginRegistryConfig(await readFile10(path, "utf8"));
37603
38098
  } catch {
37604
38099
  return defaultPluginRegistryConfig;
37605
38100
  }
37606
38101
  }
37607
38102
  function createFolderServerPlugins() {
37608
- return [createNotesPlugin()];
38103
+ return [createNotesPlugin(), createKnlPlugin()];
37609
38104
  }
37610
38105
  function folderServerRegistry() {
37611
38106
  return new Map(createFolderServerPlugins().map((plugin) => [plugin.id, plugin]));
@@ -37647,7 +38142,7 @@ async function folderServerRegistryAsync() {
37647
38142
  ...server,
37648
38143
  async detect(context) {
37649
38144
  const detection = await server.detect(context);
37650
- if (detection.status === "unavailable" && existsSync3(resolve11(context.folder, entry.trigger))) {
38145
+ if (detection.status === "unavailable" && existsSync4(resolve15(context.folder, entry.trigger))) {
37651
38146
  return { status: "available" };
37652
38147
  }
37653
38148
  return detection;
@@ -37690,10 +38185,10 @@ import { execFile as execFile4 } from "node:child_process";
37690
38185
 
37691
38186
  // packages/api/src/server/linked-folder-discovery.ts
37692
38187
  import { execFile as execFile3 } from "node:child_process";
37693
- import { existsSync as existsSync4 } from "node:fs";
37694
- import { createRequire as createRequire2 } from "node:module";
37695
- import { dirname as dirname9, join as join5 } from "node:path";
37696
- import { fileURLToPath } from "node:url";
38188
+ import { existsSync as existsSync5 } from "node:fs";
38189
+ import { createRequire as createRequire3 } from "node:module";
38190
+ import { dirname as dirname12, join as join6 } from "node:path";
38191
+ import { fileURLToPath as fileURLToPath2 } from "node:url";
37697
38192
  var script = `
37698
38193
  const local = require(process.argv[1]);
37699
38194
  const { stat } = require('node:fs/promises');
@@ -37710,24 +38205,24 @@ const { stat } = require('node:fs/promises');
37710
38205
  })().catch(error => { console.error(error); process.exitCode = 1; });
37711
38206
  `;
37712
38207
  function resolveLocalModule(from = import.meta.url) {
37713
- const require2 = createRequire2(from);
38208
+ const require2 = createRequire3(from);
37714
38209
  const candidates = [];
37715
38210
  try {
37716
38211
  candidates.push(require2.resolve("@raggle-ai/local"));
37717
38212
  } catch {}
37718
- let directory = dirname9(fileURLToPath(from));
37719
- while (dirname9(directory) !== directory) {
37720
- if (existsSync4(join5(directory, "raggle.json"))) {
38213
+ let directory = dirname12(fileURLToPath2(from));
38214
+ while (dirname12(directory) !== directory) {
38215
+ if (existsSync5(join6(directory, "raggle.json"))) {
37721
38216
  for (const candidate of [
37722
- join5(dirname9(directory), "raggle-ai-scout", "packages", "local"),
37723
- join5(directory, "..", "..", "raggle-ai-scout", "packages", "local")
38217
+ join6(dirname12(directory), "raggle-ai-scout", "packages", "local"),
38218
+ join6(directory, "..", "..", "raggle-ai-scout", "packages", "local")
37724
38219
  ]) {
37725
38220
  if (!candidates.includes(candidate))
37726
38221
  candidates.push(candidate);
37727
38222
  }
37728
38223
  break;
37729
38224
  }
37730
- directory = dirname9(directory);
38225
+ directory = dirname12(directory);
37731
38226
  }
37732
38227
  for (const candidate of candidates) {
37733
38228
  try {
@@ -37736,7 +38231,7 @@ function resolveLocalModule(from = import.meta.url) {
37736
38231
  return candidate;
37737
38232
  } catch {}
37738
38233
  }
37739
- return candidates[0] ?? join5(dirname9(fileURLToPath(from)), "..", "..", "..", "raggle-ai-scout", "packages", "local");
38234
+ return candidates[0] ?? join6(dirname12(fileURLToPath2(from)), "..", "..", "..", "raggle-ai-scout", "packages", "local");
37740
38235
  }
37741
38236
  function discoverLinkedFolders(folder, signal, modulePath = resolveLocalModule()) {
37742
38237
  return new Promise((resolve, reject) => {
@@ -38088,13 +38583,13 @@ var metadataExtensions = new Set([
38088
38583
  ".txt"
38089
38584
  ]);
38090
38585
  function metadataFile(path, root) {
38091
- const candidate = relative11(root, path);
38092
- if (!candidate || candidate.startsWith("..") || isAbsolute7(candidate))
38586
+ const candidate = relative13(root, path);
38587
+ if (!candidate || candidate.startsWith("..") || isAbsolute8(candidate))
38093
38588
  return false;
38094
- const parts = candidate.split(sep8);
38589
+ const parts = candidate.split(sep11);
38095
38590
  if (parts.some((part) => part === "node_modules"))
38096
38591
  return false;
38097
- return metadataExtensions.has(extname6(candidate).toLowerCase());
38592
+ return metadataExtensions.has(extname7(candidate).toLowerCase());
38098
38593
  }
38099
38594
  async function configuredAiInputModule(folder) {
38100
38595
  const config = folderWorkspace(folder).config;
@@ -38102,11 +38597,11 @@ async function configuredAiInputModule(folder) {
38102
38597
  return typeof module === "string" && module.trim() ? module.trim() : null;
38103
38598
  }
38104
38599
  function folderPath(value, root, lockedRoot) {
38105
- const folder = realpathSync2(resolve12(value ?? root));
38600
+ const folder = realpathSync3(resolve16(value ?? root));
38106
38601
  if (!lockedRoot)
38107
38602
  return folder;
38108
- const path = relative11(lockedRoot, folder);
38109
- if (!path || !path.startsWith("..") && !isAbsolute7(path))
38603
+ const path = relative13(lockedRoot, folder);
38604
+ if (!path || !path.startsWith("..") && !isAbsolute8(path))
38110
38605
  return folder;
38111
38606
  throw new Error(`Folder is outside the viewer root: ${folder}`);
38112
38607
  }
@@ -38177,15 +38672,15 @@ function unique(values) {
38177
38672
  return [...new Set(values)];
38178
38673
  }
38179
38674
  function isMachineRoot(folder) {
38180
- return folder === homedir4() || dirname10(folder) === folder;
38675
+ return folder === homedir4() || dirname13(folder) === folder;
38181
38676
  }
38182
38677
  async function shallowMetadata(folder) {
38183
- const entries = await readdir6(folder, { withFileTypes: true });
38678
+ const entries = await readdir7(folder, { withFileTypes: true });
38184
38679
  const visible = entries.filter((entry) => !entry.name.startsWith(".") && entry.name !== "node_modules");
38185
- const files = await Promise.all(visible.filter((entry) => entry.isFile() && [".markdown", ".md"].includes(extname6(entry.name).toLowerCase())).map(async (entry) => {
38186
- const path = resolve12(folder, entry.name);
38187
- const details = await stat9(path);
38188
- const content = await readFile10(path, "utf8").catch(() => "");
38680
+ const files = await Promise.all(visible.filter((entry) => entry.isFile() && [".markdown", ".md"].includes(extname7(entry.name).toLowerCase())).map(async (entry) => {
38681
+ const path = resolve16(folder, entry.name);
38682
+ const details = await stat12(path);
38683
+ const content = await readFile11(path, "utf8").catch(() => "");
38189
38684
  const title = markdownMetadata(content).title;
38190
38685
  return {
38191
38686
  activityAt: details.mtimeMs,
@@ -38198,10 +38693,10 @@ async function shallowMetadata(folder) {
38198
38693
  };
38199
38694
  }));
38200
38695
  const projects = visible.filter((entry) => entry.isDirectory()).map((entry) => ({
38201
- id: createHash5("sha1").update(resolve12(folder, entry.name)).digest("hex"),
38696
+ id: createHash5("sha1").update(resolve16(folder, entry.name)).digest("hex"),
38202
38697
  name: entry.name,
38203
38698
  relativePath: entry.name,
38204
- worktree: resolve12(folder, entry.name)
38699
+ worktree: resolve16(folder, entry.name)
38205
38700
  })).sort((left, right) => left.name.localeCompare(right.name));
38206
38701
  return {
38207
38702
  changes: { items: [] },
@@ -38227,8 +38722,8 @@ async function loadFolderData(folder) {
38227
38722
  items: projects.map((project) => ({
38228
38723
  id: project.id,
38229
38724
  worktree: project.worktree,
38230
- name: project.name ?? basename7(project.worktree),
38231
- relativePath: relative11(folder, project.worktree)
38725
+ name: project.name ?? basename8(project.worktree),
38726
+ relativePath: relative13(folder, project.worktree)
38232
38727
  }))
38233
38728
  }
38234
38729
  };
@@ -38236,10 +38731,10 @@ async function loadFolderData(folder) {
38236
38731
  async function notesFiles(folder, files, origin) {
38237
38732
  return {
38238
38733
  items: await Promise.all(files.map(async (file) => {
38239
- const path = file.path ?? (file.relativePath ? resolve12(folder, file.relativePath) : undefined);
38734
+ const path = file.path ?? (file.relativePath ? resolve16(folder, file.relativePath) : undefined);
38240
38735
  if (!path)
38241
38736
  return origin ? { ...file, folder: origin } : file;
38242
- const content = [".markdown", ".md"].includes(extname6(path).toLowerCase()) ? await readFile10(path, "utf8").catch(() => "") : "";
38737
+ const content = [".markdown", ".md"].includes(extname7(path).toLowerCase()) ? await readFile11(path, "utf8").catch(() => "") : "";
38243
38738
  const title = content ? markdownMetadata(content).title : undefined;
38244
38739
  return {
38245
38740
  ...file,
@@ -38253,7 +38748,7 @@ async function notesFiles(folder, files, origin) {
38253
38748
  async function managedNotesFiles(directory) {
38254
38749
  const notes = await listManagedNotes(directory);
38255
38750
  return Promise.all(notes.map(async (note) => {
38256
- const content = await readFile10(note.path, "utf8").catch(() => "");
38751
+ const content = await readFile11(note.path, "utf8").catch(() => "");
38257
38752
  const title = content ? markdownMetadata(content).title : undefined;
38258
38753
  return {
38259
38754
  ...note,
@@ -38263,10 +38758,10 @@ async function managedNotesFiles(directory) {
38263
38758
  };
38264
38759
  }));
38265
38760
  }
38266
- var canonicalPath = (path) => realpath7(path).catch(() => path);
38761
+ var canonicalPath = (path) => realpath9(path).catch(() => path);
38267
38762
  function insideFolder(path, root) {
38268
- const local = relative11(root, path);
38269
- return local === "" || !local.startsWith("..") && !isAbsolute7(local);
38763
+ const local = relative13(root, path);
38764
+ return local === "" || !local.startsWith("..") && !isAbsolute8(local);
38270
38765
  }
38271
38766
  async function withoutManagedFiles(items, managedRoot) {
38272
38767
  if (!managedRoot)
@@ -38297,16 +38792,16 @@ async function localProjectSearchCache(cache) {
38297
38792
  function mediaTarget(folder, file, lockedTarget) {
38298
38793
  if (!file)
38299
38794
  return;
38300
- const rootReal = realpathSync2(resolve12(folder));
38301
- const path = resolve12(folder, file);
38795
+ const rootReal = realpathSync3(resolve16(folder));
38796
+ const path = resolve16(folder, file);
38302
38797
  let pathReal;
38303
38798
  try {
38304
- pathReal = realpathSync2(path);
38799
+ pathReal = realpathSync3(path);
38305
38800
  } catch {
38306
38801
  return;
38307
38802
  }
38308
- const rel = relative11(rootReal, pathReal);
38309
- if (rel.startsWith("..") || isAbsolute7(rel))
38803
+ const rel = relative13(rootReal, pathReal);
38804
+ if (rel.startsWith("..") || isAbsolute8(rel))
38310
38805
  return;
38311
38806
  if (lockedTarget && pathReal !== lockedTarget)
38312
38807
  return;
@@ -38345,16 +38840,16 @@ function documentError(response) {
38345
38840
  function documentTarget(folder, file, lockedTarget) {
38346
38841
  if (!file)
38347
38842
  return;
38348
- const rootReal = realpathSync2(resolve12(folder));
38349
- const path = resolve12(folder, file);
38843
+ const rootReal = realpathSync3(resolve16(folder));
38844
+ const path = resolve16(folder, file);
38350
38845
  let pathReal;
38351
38846
  try {
38352
- pathReal = realpathSync2(path);
38847
+ pathReal = realpathSync3(path);
38353
38848
  } catch {
38354
38849
  return;
38355
38850
  }
38356
- const rel = relative11(rootReal, pathReal);
38357
- if (rel.startsWith("..") || isAbsolute7(rel))
38851
+ const rel = relative13(rootReal, pathReal);
38852
+ if (rel.startsWith("..") || isAbsolute8(rel))
38358
38853
  return;
38359
38854
  if (lockedTarget && pathReal !== lockedTarget)
38360
38855
  return;
@@ -38411,7 +38906,8 @@ async function pluginAvailability(registry, folder, linkedFolders, configWarning
38411
38906
  error,
38412
38907
  icon: plugin.icon,
38413
38908
  id: plugin.id,
38414
- label: plugin.label
38909
+ label: plugin.label,
38910
+ ...detection.status === "available" && detection.pages ? { pages: detection.pages } : {}
38415
38911
  });
38416
38912
  }
38417
38913
  } catch {}
@@ -38426,8 +38922,8 @@ function createFolderApi({
38426
38922
  remoteAccess = false,
38427
38923
  lockedFile
38428
38924
  }) {
38429
- let lockedRoot = restrictToRoot ? realpathSync2(root) : undefined;
38430
- const lockedTarget = lockedFile ? realpathSync2(lockedFile) : undefined;
38925
+ let lockedRoot = restrictToRoot ? realpathSync3(root) : undefined;
38926
+ const lockedTarget = lockedFile ? realpathSync3(lockedFile) : undefined;
38431
38927
  let basePlugins;
38432
38928
  let baseExternalApiHandlers;
38433
38929
  const assetFiles = new Map;
@@ -38465,7 +38961,7 @@ function createFolderApi({
38465
38961
  const serverHost = server.host;
38466
38962
  const remote = remoteAccess || serverHost === true || typeof serverHost === "string" && !isLoopbackServerHost(serverHost);
38467
38963
  if (remote)
38468
- lockedRoot = lockedRoot ?? realpathSync2(root);
38964
+ lockedRoot = lockedRoot ?? realpathSync3(root);
38469
38965
  const collectionServer = createSchemaCollectionServer(server, {
38470
38966
  boundary: lockedRoot,
38471
38967
  lockedTarget
@@ -38491,7 +38987,7 @@ function createFolderApi({
38491
38987
  if (!folder)
38492
38988
  return;
38493
38989
  server.emit({
38494
- data: { path: relative11(folder, path) },
38990
+ data: { path: relative13(folder, path) },
38495
38991
  event: "kennel:metadata-changed",
38496
38992
  type: "custom"
38497
38993
  });
@@ -38574,7 +39070,7 @@ function createFolderApi({
38574
39070
  "Content-Type": asset.mediaType,
38575
39071
  ETag: `"${hash}"`
38576
39072
  });
38577
- response.end(await readFile10(asset.path));
39073
+ response.end(await readFile11(asset.path));
38578
39074
  } catch (error) {
38579
39075
  response.writeHead(404, {
38580
39076
  "Content-Type": "text/plain; charset=utf-8"
@@ -38646,14 +39142,14 @@ function createFolderApi({
38646
39142
  }
38647
39143
  if (url.pathname === "/api/documents") {
38648
39144
  const folder = folderPath(url.searchParams.get("path"), root, lockedRoot);
38649
- const target = lockedTarget ? documentTarget(folder, relative11(folder, lockedTarget), lockedTarget) : undefined;
39145
+ const target = lockedTarget ? documentTarget(folder, relative13(folder, lockedTarget), lockedTarget) : undefined;
38650
39146
  const dataset = lockedTarget ? {
38651
39147
  root: folder,
38652
39148
  documents: target ? [
38653
39149
  {
38654
- path: relative11(folder, target.path),
39150
+ path: relative13(folder, target.path),
38655
39151
  kind: target.kind,
38656
- content: previewTextKind(target.kind) ? await readFile10(target.path, "utf8") : ""
39152
+ content: previewTextKind(target.kind) ? await readFile11(target.path, "utf8") : ""
38657
39153
  }
38658
39154
  ] : []
38659
39155
  } : await readFolder(folder);
@@ -38669,7 +39165,7 @@ function createFolderApi({
38669
39165
  documentError(response);
38670
39166
  return;
38671
39167
  }
38672
- const details = await stat9(target.path);
39168
+ const details = await stat12(target.path);
38673
39169
  if (!details.isFile()) {
38674
39170
  documentError(response);
38675
39171
  return;
@@ -38681,16 +39177,16 @@ function createFolderApi({
38681
39177
  return;
38682
39178
  }
38683
39179
  watch(folder);
38684
- const content = previewTextKind(target.kind) ? await readFile10(target.path, "utf8") : "";
39180
+ const content = previewTextKind(target.kind) ? await readFile11(target.path, "utf8") : "";
38685
39181
  sendContract(response, url, {
38686
39182
  content,
38687
39183
  kind: target.kind,
38688
- path: relative11(target.root, target.path),
39184
+ path: relative13(target.root, target.path),
38689
39185
  root: folder,
38690
39186
  ...previewTextKind(target.kind) ? {} : {
38691
39187
  rawUrl: `/api/raw?${new URLSearchParams({
38692
39188
  path: folder,
38693
- file: relative11(target.root, target.path)
39189
+ file: relative13(target.root, target.path)
38694
39190
  })}`
38695
39191
  }
38696
39192
  }, {
@@ -38710,7 +39206,7 @@ function createFolderApi({
38710
39206
  documentError(response);
38711
39207
  return;
38712
39208
  }
38713
- const details = await stat9(target.path);
39209
+ const details = await stat12(target.path);
38714
39210
  if (!details.isFile()) {
38715
39211
  documentError(response);
38716
39212
  return;
@@ -38731,10 +39227,10 @@ function createFolderApi({
38731
39227
  ETag: etag,
38732
39228
  "X-Content-Type-Options": "nosniff",
38733
39229
  ...download ? {
38734
- "Content-Disposition": `attachment; filename="${basename7(target.path)}"`
39230
+ "Content-Disposition": `attachment; filename="${basename8(target.path)}"`
38735
39231
  } : {}
38736
39232
  });
38737
- response.end(await readFile10(target.path));
39233
+ response.end(await readFile11(target.path));
38738
39234
  } catch (error) {
38739
39235
  documentError(response);
38740
39236
  }
@@ -38748,7 +39244,7 @@ function createFolderApi({
38748
39244
  documentError(response);
38749
39245
  return;
38750
39246
  }
38751
- const details = await stat9(target.path);
39247
+ const details = await stat12(target.path);
38752
39248
  if (!details.isFile()) {
38753
39249
  documentError(response);
38754
39250
  return;
@@ -38760,7 +39256,7 @@ function createFolderApi({
38760
39256
  return;
38761
39257
  }
38762
39258
  watch(folder);
38763
- const data = await readFile10(target.path);
39259
+ const data = await readFile11(target.path);
38764
39260
  const baseHeaders = {
38765
39261
  "Accept-Ranges": "bytes",
38766
39262
  "Cache-Control": "private, max-age=0, must-revalidate",
@@ -38869,6 +39365,19 @@ function createFolderApi({
38869
39365
  }))
38870
39366
  return;
38871
39367
  }
39368
+ if (url.pathname === "/api/delete-note") {
39369
+ if (remote) {
39370
+ response.writeHead(403, {
39371
+ "Content-Type": "text/plain; charset=utf-8"
39372
+ });
39373
+ response.end("Host actions are disabled for remote access");
39374
+ return;
39375
+ }
39376
+ await runApiRoute(request, response, url, deleteNoteRoute, {
39377
+ authorize: (folder) => folderPath(folder, root, lockedRoot)
39378
+ });
39379
+ return;
39380
+ }
38872
39381
  if (url.pathname === "/api/create-agent-file") {
38873
39382
  if (remote) {
38874
39383
  response.writeHead(403, {
@@ -38923,7 +39432,7 @@ function createFolderApi({
38923
39432
  workspace.breadcrumbs = await workspaceBreadcrumbIcons(workspace.breadcrumbs ?? [], assetFiles);
38924
39433
  const files = [
38925
39434
  workspace.configPath,
38926
- resolve12(workspace.root, "raggle.json")
39435
+ resolve16(workspace.root, "raggle.json")
38927
39436
  ].filter((path) => Boolean(path));
38928
39437
  for (const path of files)
38929
39438
  contexts.add(path);
@@ -39082,36 +39591,36 @@ var contentTypes = {
39082
39591
  ".ttf": "font/ttf"
39083
39592
  };
39084
39593
  async function sendFile(request, response, directory, pathname, fallback) {
39085
- const root = await realpath8(directory);
39594
+ const root = await realpath10(directory);
39086
39595
  const inside = (path) => {
39087
- const local = relative12(root, path);
39088
- return local !== ".." && !local.startsWith("../") && !isAbsolute8(local);
39596
+ const local = relative14(root, path);
39597
+ return local !== ".." && !local.startsWith("../") && !isAbsolute9(local);
39089
39598
  };
39090
- let target = resolve13(root, `.${decodeURIComponent(pathname)}`);
39599
+ let target = resolve17(root, `.${decodeURIComponent(pathname)}`);
39091
39600
  if (!inside(target)) {
39092
39601
  response.writeHead(403);
39093
39602
  response.end();
39094
39603
  return;
39095
39604
  }
39096
- if (!(await stat10(target).catch(() => null))?.isFile()) {
39605
+ if (!(await stat13(target).catch(() => null))?.isFile()) {
39097
39606
  if (!fallback) {
39098
39607
  response.writeHead(404);
39099
39608
  response.end();
39100
39609
  return;
39101
39610
  }
39102
- target = resolve13(root, fallback);
39611
+ target = resolve17(root, fallback);
39103
39612
  }
39104
- target = await realpath8(target);
39613
+ target = await realpath10(target);
39105
39614
  if (!inside(target)) {
39106
39615
  response.writeHead(403);
39107
39616
  response.end();
39108
39617
  return;
39109
39618
  }
39110
39619
  response.writeHead(200, {
39111
- "Content-Type": contentTypes[extname7(target)] ?? "application/octet-stream",
39620
+ "Content-Type": contentTypes[extname8(target)] ?? "application/octet-stream",
39112
39621
  "X-Content-Type-Options": "nosniff"
39113
39622
  });
39114
- response.end(request.method === "HEAD" ? undefined : await readFile11(target));
39623
+ response.end(request.method === "HEAD" ? undefined : await readFile12(target));
39115
39624
  }
39116
39625
  function createKennelApi(options) {
39117
39626
  const remote = options.remoteAccess || !isLoopbackServerHost(options.host);