volute 0.24.0 → 0.25.0

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 (40) hide show
  1. package/dist/api.d.ts +113 -4
  2. package/dist/{chunk-4TJ72QQ3.js → chunk-BOTQ25QT.js} +1 -1
  3. package/dist/{chunk-P3W36ZGD.js → chunk-DG7TO7EE.js} +30 -2
  4. package/dist/{chunk-OOW675I3.js → chunk-PMX4EIJK.js} +39 -20
  5. package/dist/{chunk-NOBRGACV.js → chunk-SHSWYG2J.js} +1 -1
  6. package/dist/{chunk-XLC342FO.js → chunk-SIAG3QMM.js} +14 -1
  7. package/dist/cli.js +6 -6
  8. package/dist/{cloud-sync-DIU3OCPV.js → cloud-sync-PPBBJDY6.js} +3 -3
  9. package/dist/{daemon-restart-YMPEATQH.js → daemon-restart-FDNOZEAD.js} +1 -1
  10. package/dist/daemon.js +453 -239
  11. package/dist/{import-FRDPQPJ2.js → import-TH26J76F.js} +2 -2
  12. package/dist/{message-delivery-S7BCNV6Y.js → message-delivery-XMGV3FUM.js} +3 -3
  13. package/dist/{mind-KPLCRKQA.js → mind-YVWAHL2A.js} +2 -2
  14. package/dist/{mind-manager-ZNRIYEK3.js → mind-manager-4NDNAYAB.js} +1 -1
  15. package/dist/{package-S5YF25XV.js → package-3HF5MXU2.js} +2 -1
  16. package/dist/{pages-TWR6U7DS.js → pages-Y6DRWUOJ.js} +1 -1
  17. package/dist/{publish-BZNHKUUK.js → publish-EEKTZBHW.js} +1 -1
  18. package/dist/{skill-BQOFACEI.js → skill-T3EMR6IR.js} +10 -2
  19. package/dist/skills/imagegen/SKILL.md +37 -0
  20. package/dist/skills/imagegen/references/INSTALL.md +13 -0
  21. package/dist/skills/imagegen/scripts/imagegen.ts +136 -0
  22. package/dist/skills/resonance/SKILL.md +73 -0
  23. package/dist/skills/resonance/assets/default-config.json +21 -0
  24. package/dist/skills/resonance/references/INSTALL.md +23 -0
  25. package/dist/skills/resonance/scripts/resonance.ts +1250 -0
  26. package/dist/skills/volute-mind/SKILL.md +23 -3
  27. package/dist/{sleep-manager-XXSWQQLE.js → sleep-manager-RKTFZPD3.js} +3 -3
  28. package/dist/{sprout-CGSW4CF5.js → sprout-QJVGJDSH.js} +1 -1
  29. package/dist/{up-OMHACRJL.js → up-CJ26KQLN.js} +1 -1
  30. package/dist/{version-notify-SZ75QRGO.js → version-notify-AZQMC32A.js} +3 -3
  31. package/dist/web-assets/assets/index-CGPSVu19.js +69 -0
  32. package/dist/web-assets/assets/index-V_rNDsM8.css +1 -0
  33. package/dist/web-assets/favicon.png +0 -0
  34. package/dist/web-assets/index.html +5 -4
  35. package/dist/web-assets/logo.png +0 -0
  36. package/package.json +2 -1
  37. package/templates/_base/home/public/.gitkeep +0 -0
  38. package/dist/web-assets/assets/index-Bx9WDoaQ.js +0 -69
  39. package/dist/web-assets/assets/index-Clz8OhmJ.css +0 -1
  40. /package/dist/{chunk-TQDITGES.js → chunk-ZSH4G2P5.js} +0 -0
package/dist/daemon.js CHANGED
@@ -78,9 +78,11 @@ import {
78
78
  subscribe2 as subscribe3,
79
79
  updateUserProfile,
80
80
  verifyUser
81
- } from "./chunk-OOW675I3.js";
81
+ } from "./chunk-PMX4EIJK.js";
82
82
  import {
83
- readSystemsConfig
83
+ deleteSystemsConfig,
84
+ readSystemsConfig,
85
+ writeSystemsConfig
84
86
  } from "./chunk-HFCBO2GL.js";
85
87
  import {
86
88
  getActiveMinds,
@@ -101,17 +103,17 @@ import {
101
103
  getPromptIfCustom,
102
104
  initMindManager,
103
105
  substitute
104
- } from "./chunk-NOBRGACV.js";
106
+ } from "./chunk-SHSWYG2J.js";
105
107
  import {
106
108
  findOpenClawSession,
107
109
  importOpenClawConnectors,
108
110
  importPiSession,
109
111
  parseNameFromIdentity
110
- } from "./chunk-4TJ72QQ3.js";
112
+ } from "./chunk-BOTQ25QT.js";
111
113
  import {
112
114
  readVoluteConfig,
113
115
  writeVoluteConfig
114
- } from "./chunk-XLC342FO.js";
116
+ } from "./chunk-SIAG3QMM.js";
115
117
  import {
116
118
  loadMergedEnv,
117
119
  mindEnvPath,
@@ -137,7 +139,7 @@ import {
137
139
  syncBuiltinSkills,
138
140
  uninstallSkill,
139
141
  updateSkill
140
- } from "./chunk-P3W36ZGD.js";
142
+ } from "./chunk-DG7TO7EE.js";
141
143
  import {
142
144
  activity,
143
145
  conversations,
@@ -210,7 +212,7 @@ import {
210
212
  import { randomBytes as randomBytes2 } from "crypto";
211
213
  import { mkdirSync as mkdirSync9, readFileSync as readFileSync11, unlinkSync, writeFileSync as writeFileSync9 } from "fs";
212
214
  import { homedir as homedir2 } from "os";
213
- import { resolve as resolve18 } from "path";
215
+ import { resolve as resolve19 } from "path";
214
216
  import { format } from "util";
215
217
 
216
218
  // src/lib/migrate-agents-to-minds.ts
@@ -360,6 +362,17 @@ function migrateDotVoluteDir(name) {
360
362
  console.warn(`[migrate] both .volute/ and .mind/ exist for ${name}, skipping rename`);
361
363
  }
362
364
  }
365
+ function migratePagesDirToPublic(name) {
366
+ const dir = mindDir(name);
367
+ const oldPagesDir = resolve2(dir, "home", "pages");
368
+ const newPublicDir = resolve2(dir, "home", "public");
369
+ const newPagesDir = resolve2(newPublicDir, "pages");
370
+ if (existsSync2(oldPagesDir) && !existsSync2(newPagesDir)) {
371
+ mkdirSync(newPublicDir, { recursive: true });
372
+ renameSync2(oldPagesDir, newPagesDir);
373
+ logger_default.info(`migrated pages/ \u2192 public/pages/ for ${name}`);
374
+ }
375
+ }
363
376
  function migrateMindState(name) {
364
377
  const src = resolve2(mindDir(name), ".mind");
365
378
  if (!existsSync2(src)) return;
@@ -396,7 +409,7 @@ function isValidDaemonToken(token) {
396
409
  if (!expected || token.length !== expected.length) return false;
397
410
  return timingSafeEqual(Buffer.from(token), Buffer.from(expected));
398
411
  }
399
- var SESSION_MAX_AGE = 864e5;
412
+ var SESSION_MAX_AGE = 365 * 24 * 60 * 60 * 1e3;
400
413
  var SESSION_CACHE_TTL = 5 * 60 * 1e3;
401
414
  var sessionCache = /* @__PURE__ */ new Map();
402
415
  function invalidateSessionCache(sessionId) {
@@ -480,13 +493,13 @@ var authMiddleware = createMiddleware(async (c, next) => {
480
493
 
481
494
  // src/web/server.ts
482
495
  import { existsSync as existsSync13 } from "fs";
483
- import { readFile as readFile3, stat as stat3 } from "fs/promises";
496
+ import { readFile as readFile4, stat as stat4 } from "fs/promises";
484
497
  import { createServer as createHttpsServer } from "https";
485
- import { dirname, extname as extname4, resolve as resolve17 } from "path";
498
+ import { dirname, extname as extname5, resolve as resolve18 } from "path";
486
499
  import { serve } from "@hono/node-server";
487
500
 
488
501
  // src/web/app.ts
489
- import { Hono as Hono28 } from "hono";
502
+ import { Hono as Hono29 } from "hono";
490
503
  import { bodyLimit } from "hono/body-limit";
491
504
  import { csrf } from "hono/csrf";
492
505
  import { HTTPException } from "hono/http-exception";
@@ -553,8 +566,8 @@ var app = new Hono().get("/events", async (c) => {
553
566
  });
554
567
  }, 15e3);
555
568
  cleanups.push(() => clearInterval(keepAlive));
556
- await new Promise((resolve19) => {
557
- stream.onAbort(() => resolve19());
569
+ await new Promise((resolve20) => {
570
+ stream.onAbort(() => resolve20());
558
571
  });
559
572
  } finally {
560
573
  for (const cleanup of cleanups) {
@@ -575,6 +588,12 @@ import { zValidator } from "@hono/zod-validator";
575
588
  import { Hono as Hono2 } from "hono";
576
589
  import { deleteCookie, getCookie as getCookie2, setCookie } from "hono/cookie";
577
590
  import { z } from "zod";
591
+ var SESSION_COOKIE_OPTIONS = {
592
+ path: "/",
593
+ httpOnly: true,
594
+ sameSite: "Lax",
595
+ maxAge: Math.floor(SESSION_MAX_AGE / 1e3)
596
+ };
578
597
  var credentialsSchema = z.object({
579
598
  username: z.string().min(1),
580
599
  password: z.string().min(1)
@@ -610,6 +629,11 @@ var authenticated = new Hono2().use(authMiddleware).post("/change-password", zVa
610
629
  await updateUserProfile(user.id, body);
611
630
  const sessionId = getCookie2(c, "volute_session");
612
631
  if (sessionId) invalidateSessionCache(sessionId);
632
+ broadcast({
633
+ type: "profile_updated",
634
+ mind: user.username,
635
+ summary: `${user.username} profile updated`
636
+ });
613
637
  return c.json({ ok: true });
614
638
  }).post("/avatar", async (c) => {
615
639
  const user = c.get("user");
@@ -637,6 +661,11 @@ var authenticated = new Hono2().use(authMiddleware).post("/change-password", zVa
637
661
  await updateUserProfile(user.id, { avatar: filename });
638
662
  const sessionId = getCookie2(c, "volute_session");
639
663
  if (sessionId) invalidateSessionCache(sessionId);
664
+ broadcast({
665
+ type: "profile_updated",
666
+ mind: user.username,
667
+ summary: `${user.username} avatar updated`
668
+ });
640
669
  return c.json({ ok: true, avatar: filename });
641
670
  }).delete("/avatar", async (c) => {
642
671
  const user = c.get("user");
@@ -647,6 +676,11 @@ var authenticated = new Hono2().use(authMiddleware).post("/change-password", zVa
647
676
  await updateUserProfile(user.id, { avatar: null });
648
677
  const sessionId = getCookie2(c, "volute_session");
649
678
  if (sessionId) invalidateSessionCache(sessionId);
679
+ broadcast({
680
+ type: "profile_updated",
681
+ mind: user.username,
682
+ summary: `${user.username} avatar removed`
683
+ });
650
684
  return c.json({ ok: true });
651
685
  });
652
686
  var admin = new Hono2().use(authMiddleware).get("/users", async (c) => {
@@ -700,6 +734,14 @@ var admin = new Hono2().use(authMiddleware).get("/users", async (c) => {
700
734
  if (Number.isNaN(id)) return c.json({ error: "Invalid user ID" }, 400);
701
735
  const body = c.req.valid("json");
702
736
  await updateUserProfile(id, body);
737
+ const updatedUser = await getUser(id);
738
+ if (updatedUser) {
739
+ broadcast({
740
+ type: "profile_updated",
741
+ mind: updatedUser.username,
742
+ summary: `${updatedUser.username} profile updated`
743
+ });
744
+ }
703
745
  return c.json({ ok: true });
704
746
  }).delete("/users/:id", async (c) => {
705
747
  const user = c.get("user");
@@ -728,7 +770,7 @@ var app2 = new Hono2().post("/register", zValidator("json", credentialsSchema),
728
770
  const user = await createUser(username, password);
729
771
  if (user.role === "admin") {
730
772
  const sessionId = await createSession(user.id);
731
- setCookie(c, "volute_session", sessionId, { path: "/", httpOnly: true, sameSite: "Lax" });
773
+ setCookie(c, "volute_session", sessionId, SESSION_COOKIE_OPTIONS);
732
774
  }
733
775
  return c.json({ id: user.id, username: user.username, role: user.role });
734
776
  }).post("/login", zValidator("json", credentialsSchema), async (c) => {
@@ -738,7 +780,7 @@ var app2 = new Hono2().post("/register", zValidator("json", credentialsSchema),
738
780
  return c.json({ error: "Invalid credentials" }, 401);
739
781
  }
740
782
  const sessionId = await createSession(user.id);
741
- setCookie(c, "volute_session", sessionId, { path: "/", httpOnly: true, sameSite: "Lax" });
783
+ setCookie(c, "volute_session", sessionId, SESSION_COOKIE_OPTIONS);
742
784
  return c.json({ id: user.id, username: user.username, role: user.role });
743
785
  }).post("/logout", async (c) => {
744
786
  const sessionId = getCookie2(c, "volute_session");
@@ -1886,13 +1928,13 @@ var app6 = new Hono6().post("/:name/files/send", async (c) => {
1886
1928
  if (pathErr) return c.json({ error: pathErr }, 400);
1887
1929
  const senderDir = mindDir(senderName);
1888
1930
  const filePath = resolve6(senderDir, "home", body.filePath);
1889
- const MAX_FILE_SIZE = 50 * 1024 * 1024;
1890
- const stat4 = statSync(filePath, { throwIfNoEntry: false });
1891
- if (!stat4) return c.json({ error: `File not found: ${body.filePath}` }, 404);
1892
- if (stat4.size > MAX_FILE_SIZE) {
1931
+ const MAX_FILE_SIZE2 = 50 * 1024 * 1024;
1932
+ const stat5 = statSync(filePath, { throwIfNoEntry: false });
1933
+ if (!stat5) return c.json({ error: `File not found: ${body.filePath}` }, 404);
1934
+ if (stat5.size > MAX_FILE_SIZE2) {
1893
1935
  return c.json(
1894
1936
  {
1895
- error: `File too large (${formatFileSize(stat4.size)}, max ${formatFileSize(MAX_FILE_SIZE)})`
1937
+ error: `File too large (${formatFileSize(stat5.size)}, max ${formatFileSize(MAX_FILE_SIZE2)})`
1896
1938
  },
1897
1939
  413
1898
1940
  );
@@ -2020,12 +2062,12 @@ var app7 = new Hono7().get("/:name/avatar", async (c) => {
2020
2062
  if (!entry) return c.json({ error: "Mind not found" }, 404);
2021
2063
  const dir = mindDir(name);
2022
2064
  const config = readVoluteConfig(dir);
2023
- if (!config?.avatar) return c.json({ error: "No avatar configured" }, 404);
2024
- const ext = extname2(config.avatar).toLowerCase();
2065
+ if (!config?.profile?.avatar) return c.json({ error: "No avatar configured" }, 404);
2066
+ const ext = extname2(config.profile.avatar).toLowerCase();
2025
2067
  const mime = AVATAR_MIME2[ext];
2026
2068
  if (!mime) return c.json({ error: "Invalid avatar extension" }, 400);
2027
2069
  const homeDir = resolve7(dir, "home");
2028
- const avatarPath = resolve7(homeDir, config.avatar);
2070
+ const avatarPath = resolve7(homeDir, config.profile.avatar);
2029
2071
  if (!avatarPath.startsWith(`${homeDir}/`)) return c.json({ error: "Invalid avatar path" }, 400);
2030
2072
  let realAvatarPath;
2031
2073
  try {
@@ -2197,9 +2239,9 @@ var app9 = new Hono9().get("/:name/logs", async (c) => {
2197
2239
  stream.onAbort(() => {
2198
2240
  tail.kill();
2199
2241
  });
2200
- await new Promise((resolve19) => {
2201
- tail.on("exit", resolve19);
2202
- stream.onAbort(resolve19);
2242
+ await new Promise((resolve20) => {
2243
+ tail.on("exit", resolve20);
2244
+ stream.onAbort(resolve20);
2203
2245
  });
2204
2246
  });
2205
2247
  }).get("/:name/logs/tail", async (c) => {
@@ -2217,8 +2259,8 @@ var app9 = new Hono9().get("/:name/logs", async (c) => {
2217
2259
  tail.stdout.on("data", (data) => {
2218
2260
  output += data.toString();
2219
2261
  });
2220
- await new Promise((resolve19) => {
2221
- tail.on("exit", resolve19);
2262
+ await new Promise((resolve20) => {
2263
+ tail.on("exit", resolve20);
2222
2264
  });
2223
2265
  return c.text(output);
2224
2266
  });
@@ -2246,12 +2288,12 @@ var app10 = new Hono10().get("/:name/skills", async (c) => {
2246
2288
  const { skillId } = c.req.valid("json");
2247
2289
  const dir = mindDir(name);
2248
2290
  try {
2249
- await installSkill(name, dir, skillId);
2291
+ const result = await installSkill(name, dir, skillId);
2292
+ return c.json({ ok: true, ...result });
2250
2293
  } catch (e) {
2251
2294
  const msg = e instanceof Error ? e.message : String(e);
2252
2295
  return c.json({ error: msg }, 400);
2253
2296
  }
2254
- return c.json({ ok: true });
2255
2297
  }
2256
2298
  ).post(
2257
2299
  "/:name/skills/update",
@@ -2606,7 +2648,7 @@ async function getMindStatus(name, port) {
2606
2648
  const manager = getMindManager();
2607
2649
  let status = "stopped";
2608
2650
  try {
2609
- const { getSleepManagerIfReady } = await import("./sleep-manager-XXSWQQLE.js");
2651
+ const { getSleepManagerIfReady } = await import("./sleep-manager-RKTFZPD3.js");
2610
2652
  if (getSleepManagerIfReady()?.isSleeping(name)) {
2611
2653
  status = "sleeping";
2612
2654
  }
@@ -2641,9 +2683,9 @@ async function getMindStatus(name, port) {
2641
2683
  return {
2642
2684
  status,
2643
2685
  channels,
2644
- displayName: config?.displayName,
2645
- description: config?.description,
2646
- avatar: config?.avatar
2686
+ displayName: config?.profile?.displayName,
2687
+ description: config?.profile?.description,
2688
+ avatar: config?.profile?.avatar
2647
2689
  };
2648
2690
  }
2649
2691
  var TEMPLATE_BRANCH = "volute/template";
@@ -3007,7 +3049,7 @@ var app11 = new Hono11().post("/", requireAdmin, zValidator3("json", createMindS
3007
3049
  if (body.description) {
3008
3050
  const seedConfig = readVoluteConfig(dest);
3009
3051
  if (!seedConfig) throw new Error("Failed to read volute.json after identity generation");
3010
- seedConfig.description = body.description;
3052
+ seedConfig.profile = { ...seedConfig.profile, description: body.description };
3011
3053
  writeVoluteConfig(dest, seedConfig);
3012
3054
  }
3013
3055
  if (body.model) {
@@ -3247,7 +3289,7 @@ ${user.trimEnd()}
3247
3289
  const minds = await Promise.all(
3248
3290
  entries.map(async (entry) => {
3249
3291
  const mindStatus = await getMindStatus(entry.name, entry.port);
3250
- const hasPages = existsSync10(resolve12(mindDir(entry.name), "home", "pages"));
3292
+ const hasPages = existsSync10(resolve12(mindDir(entry.name), "home", "public", "pages"));
3251
3293
  return {
3252
3294
  ...entry,
3253
3295
  ...mindStatus,
@@ -3280,7 +3322,7 @@ ${user.trimEnd()}
3280
3322
  return { name: v.name, port: v.port, status: variantStatus };
3281
3323
  })
3282
3324
  );
3283
- const hasPages = existsSync10(resolve12(mindDir(name), "home", "pages"));
3325
+ const hasPages = existsSync10(resolve12(mindDir(name), "home", "public", "pages"));
3284
3326
  return c.json({ ...entry, ...mindStatus, variants: variantStatuses, hasPages });
3285
3327
  }).post("/:name/start", requireAdmin, async (c) => {
3286
3328
  const name = c.req.param("name");
@@ -3380,7 +3422,7 @@ ${user.trimEnd()}
3380
3422
  }
3381
3423
  }
3382
3424
  }
3383
- if (context) {
3425
+ if (context && context.type !== "reload") {
3384
3426
  manager.setPendingContext(name, context);
3385
3427
  }
3386
3428
  if (context?.type === "sprouted" && !variantName) {
@@ -3424,7 +3466,7 @@ ${user.trimEnd()}
3424
3466
  const name = c.req.param("name");
3425
3467
  const entry = findMind(name);
3426
3468
  if (!entry) return c.json({ error: "Mind not found" }, 404);
3427
- const { getSleepManagerIfReady } = await import("./sleep-manager-XXSWQQLE.js");
3469
+ const { getSleepManagerIfReady } = await import("./sleep-manager-RKTFZPD3.js");
3428
3470
  const sm = getSleepManagerIfReady();
3429
3471
  if (!sm) return c.json({ error: "Sleep manager not initialized" }, 503);
3430
3472
  return c.json(sm.getState(name));
@@ -3432,7 +3474,7 @@ ${user.trimEnd()}
3432
3474
  const name = c.req.param("name");
3433
3475
  const entry = findMind(name);
3434
3476
  if (!entry) return c.json({ error: "Mind not found" }, 404);
3435
- const { getSleepManagerIfReady } = await import("./sleep-manager-XXSWQQLE.js");
3477
+ const { getSleepManagerIfReady } = await import("./sleep-manager-RKTFZPD3.js");
3436
3478
  const sm = getSleepManagerIfReady();
3437
3479
  if (!sm) return c.json({ error: "Sleep manager not initialized" }, 503);
3438
3480
  if (sm.isSleeping(name)) return c.json({ error: "Mind is already sleeping" }, 409);
@@ -3452,7 +3494,7 @@ ${user.trimEnd()}
3452
3494
  const name = c.req.param("name");
3453
3495
  const entry = findMind(name);
3454
3496
  if (!entry) return c.json({ error: "Mind not found" }, 404);
3455
- const { getSleepManagerIfReady } = await import("./sleep-manager-XXSWQQLE.js");
3497
+ const { getSleepManagerIfReady } = await import("./sleep-manager-RKTFZPD3.js");
3456
3498
  const sm = getSleepManagerIfReady();
3457
3499
  if (!sm) return c.json({ error: "Sleep manager not initialized" }, 503);
3458
3500
  if (!sm.isSleeping(name)) return c.json({ error: "Mind is not sleeping" }, 409);
@@ -3462,7 +3504,7 @@ ${user.trimEnd()}
3462
3504
  const name = c.req.param("name");
3463
3505
  const entry = findMind(name);
3464
3506
  if (!entry) return c.json({ error: "Mind not found" }, 404);
3465
- const { getSleepManagerIfReady } = await import("./sleep-manager-XXSWQQLE.js");
3507
+ const { getSleepManagerIfReady } = await import("./sleep-manager-RKTFZPD3.js");
3466
3508
  const sm = getSleepManagerIfReady();
3467
3509
  if (!sm) return c.json({ error: "Sleep manager not initialized" }, 503);
3468
3510
  const flushed = await sm.flushQueuedMessages(name);
@@ -3680,7 +3722,7 @@ ${user.trimEnd()}
3680
3722
  if (!variant) return c.json({ error: `Unknown variant: ${variantName}` }, 404);
3681
3723
  }
3682
3724
  try {
3683
- const { getSleepManagerIfReady } = await import("./sleep-manager-XXSWQQLE.js");
3725
+ const { getSleepManagerIfReady } = await import("./sleep-manager-RKTFZPD3.js");
3684
3726
  const sm = getSleepManagerIfReady();
3685
3727
  if (sm?.isSleeping(baseName)) {
3686
3728
  const body2 = await c.req.text();
@@ -4114,7 +4156,7 @@ var app12 = new Hono12().get("/:name/*", async (c) => {
4114
4156
  pagesRoot = resolve13(voluteHome(), "shared", "pages");
4115
4157
  } else {
4116
4158
  if (!findMind(name)) return c.text("Not found", 404);
4117
- pagesRoot = resolve13(mindDir(name), "home", "pages");
4159
+ pagesRoot = resolve13(mindDir(name), "home", "public", "pages");
4118
4160
  }
4119
4161
  const wildcard = c.req.path.replace(`/pages/${name}`, "") || "/";
4120
4162
  const requestedPath = resolve13(pagesRoot, wildcard.slice(1));
@@ -4190,9 +4232,98 @@ var app13 = new Hono13().get("/", async (c) => {
4190
4232
  });
4191
4233
  var prompts_default = app13;
4192
4234
 
4235
+ // src/web/api/public-files.ts
4236
+ import { readdir as readdir2, readFile as readFile3, stat as stat3 } from "fs/promises";
4237
+ import { extname as extname4, resolve as resolve14 } from "path";
4238
+ import { Hono as Hono14 } from "hono";
4239
+ var MAX_FILE_SIZE = 50 * 1024 * 1024;
4240
+ function resolvePublicRoot(name) {
4241
+ if (name === "_system") return resolve14(voluteHome(), "shared");
4242
+ if (!findMind(name)) return null;
4243
+ return resolve14(mindDir(name), "home", "public");
4244
+ }
4245
+ function hasDotSegment(relativePath) {
4246
+ return relativePath.split("/").some((seg) => seg.startsWith("."));
4247
+ }
4248
+ var MIME_TYPES2 = {
4249
+ ".html": "text/html",
4250
+ ".js": "application/javascript",
4251
+ ".css": "text/css",
4252
+ ".json": "application/json",
4253
+ ".svg": "image/svg+xml",
4254
+ ".png": "image/png",
4255
+ ".jpg": "image/jpeg",
4256
+ ".jpeg": "image/jpeg",
4257
+ ".gif": "image/gif",
4258
+ ".ico": "image/x-icon",
4259
+ ".woff": "font/woff",
4260
+ ".woff2": "font/woff2",
4261
+ ".txt": "text/plain",
4262
+ ".xml": "application/xml",
4263
+ ".md": "text/markdown",
4264
+ ".webp": "image/webp"
4265
+ };
4266
+ async function listDir(dirPath) {
4267
+ let entries;
4268
+ try {
4269
+ entries = await readdir2(dirPath, { withFileTypes: true });
4270
+ } catch (err) {
4271
+ if (err?.code === "ENOENT") return [];
4272
+ throw err;
4273
+ }
4274
+ return entries.filter((e) => !e.name.startsWith(".")).map((e) => ({
4275
+ name: e.name,
4276
+ type: e.isDirectory() ? "directory" : "file"
4277
+ }));
4278
+ }
4279
+ var app14 = new Hono14().get("/:name/", async (c) => {
4280
+ const name = c.req.param("name");
4281
+ const publicRoot = resolvePublicRoot(name);
4282
+ if (!publicRoot) return c.json({ error: "Not found" }, 404);
4283
+ return c.json(await listDir(publicRoot));
4284
+ }).get("/:name/*", async (c) => {
4285
+ const name = c.req.param("name");
4286
+ const publicRoot = resolvePublicRoot(name);
4287
+ if (!publicRoot) return c.text("Not found", 404);
4288
+ const wildcard = c.req.path.replace(`/public/${name}`, "") || "/";
4289
+ const relativePath = wildcard.slice(1);
4290
+ const requestedPath = resolve14(publicRoot, relativePath);
4291
+ if (!requestedPath.startsWith(publicRoot)) return c.text("Forbidden", 403);
4292
+ if (hasDotSegment(relativePath)) return c.text("Forbidden", 403);
4293
+ let fileStat;
4294
+ try {
4295
+ fileStat = await stat3(requestedPath);
4296
+ } catch (err) {
4297
+ if (err?.code === "ENOENT") return c.text("Not found", 404);
4298
+ if (err?.code === "EACCES") return c.text("Forbidden", 403);
4299
+ return c.text("Internal server error", 500);
4300
+ }
4301
+ if (fileStat.isDirectory()) {
4302
+ if (wildcard.endsWith("/")) {
4303
+ return c.json(await listDir(requestedPath));
4304
+ }
4305
+ return c.text("Not found", 404);
4306
+ }
4307
+ if (fileStat.isFile()) {
4308
+ if (fileStat.size > MAX_FILE_SIZE) return c.text("File too large", 413);
4309
+ const ext = extname4(requestedPath);
4310
+ const mime = MIME_TYPES2[ext] || "application/octet-stream";
4311
+ try {
4312
+ const body = await readFile3(requestedPath);
4313
+ return c.body(body, 200, { "Content-Type": mime });
4314
+ } catch (err) {
4315
+ if (err?.code === "ENOENT") return c.text("Not found", 404);
4316
+ if (err?.code === "EACCES") return c.text("Forbidden", 403);
4317
+ return c.text("Failed to read file", 500);
4318
+ }
4319
+ }
4320
+ return c.text("Not found", 404);
4321
+ });
4322
+ var public_files_default = app14;
4323
+
4193
4324
  // src/web/api/schedules.ts
4194
4325
  import { CronExpressionParser } from "cron-parser";
4195
- import { Hono as Hono14 } from "hono";
4326
+ import { Hono as Hono15 } from "hono";
4196
4327
  var slog = logger_default.child("schedules");
4197
4328
  function readSchedules(name) {
4198
4329
  return readVoluteConfig(mindDir(name))?.schedules ?? [];
@@ -4209,7 +4340,7 @@ function writeSchedules(name, schedules) {
4209
4340
  data: { schedules }
4210
4341
  });
4211
4342
  }
4212
- var app14 = new Hono14().get("/:name/schedules", (c) => {
4343
+ var app15 = new Hono15().get("/:name/schedules", (c) => {
4213
4344
  const name = c.req.param("name");
4214
4345
  if (!findMind(name)) return c.json({ error: "Mind not found" }, 404);
4215
4346
  return c.json(readSchedules(name));
@@ -4312,11 +4443,11 @@ var app14 = new Hono14().get("/:name/schedules", (c) => {
4312
4443
  return c.json({ error: "Failed to reach mind" }, 502);
4313
4444
  }
4314
4445
  });
4315
- var schedules_default = app14;
4446
+ var schedules_default = app15;
4316
4447
 
4317
4448
  // src/web/api/shared.ts
4318
- import { Hono as Hono15 } from "hono";
4319
- var app15 = new Hono15().post("/:name/shared/merge", requireAdmin, async (c) => {
4449
+ import { Hono as Hono16 } from "hono";
4450
+ var app16 = new Hono16().post("/:name/shared/merge", requireAdmin, async (c) => {
4320
4451
  const name = c.req.param("name");
4321
4452
  const entry = findMind(name);
4322
4453
  if (!entry) return c.json({ error: "Mind not found" }, 404);
@@ -4365,15 +4496,15 @@ var app15 = new Hono15().post("/:name/shared/merge", requireAdmin, async (c) =>
4365
4496
  return c.json({ error: err instanceof Error ? err.message : "Failed to get status" }, 500);
4366
4497
  }
4367
4498
  });
4368
- var shared_default = app15;
4499
+ var shared_default = app16;
4369
4500
 
4370
4501
  // src/web/api/skills.ts
4371
4502
  import { existsSync as existsSync11, mkdtempSync, readdirSync as readdirSync5, rmSync as rmSync5 } from "fs";
4372
4503
  import { tmpdir } from "os";
4373
- import { join as join2, resolve as resolve14 } from "path";
4504
+ import { join as join2, resolve as resolve15 } from "path";
4374
4505
  import AdmZip from "adm-zip";
4375
- import { Hono as Hono16 } from "hono";
4376
- var app16 = new Hono16().get("/", async (c) => {
4506
+ import { Hono as Hono17 } from "hono";
4507
+ var app17 = new Hono17().get("/", async (c) => {
4377
4508
  const skills = await listSharedSkills();
4378
4509
  return c.json(skills);
4379
4510
  }).get("/:id", async (c) => {
@@ -4397,7 +4528,7 @@ var app16 = new Hono16().get("/", async (c) => {
4397
4528
  try {
4398
4529
  const zip = new AdmZip(buffer2);
4399
4530
  for (const entry of zip.getEntries()) {
4400
- const target = resolve14(tmpDir, entry.entryName);
4531
+ const target = resolve15(tmpDir, entry.entryName);
4401
4532
  if (!target.startsWith(tmpDir)) {
4402
4533
  return c.json({ error: "Invalid zip: paths must not escape archive" }, 400);
4403
4534
  }
@@ -4438,12 +4569,15 @@ var app16 = new Hono16().get("/", async (c) => {
4438
4569
  }
4439
4570
  return c.json({ ok: true });
4440
4571
  });
4441
- var skills_default = app16;
4572
+ var skills_default = app17;
4442
4573
 
4443
4574
  // src/web/api/system.ts
4444
- import { Hono as Hono17 } from "hono";
4575
+ import { zValidator as zValidator5 } from "@hono/zod-validator";
4576
+ import { Hono as Hono18 } from "hono";
4445
4577
  import { streamSSE as streamSSE3 } from "hono/streaming";
4446
- var app17 = new Hono17().post("/restart", requireAdmin, (c) => {
4578
+ import { z as z5 } from "zod";
4579
+ var DEFAULT_API_URL = "https://volute.systems";
4580
+ var app18 = new Hono18().post("/restart", requireAdmin, (c) => {
4447
4581
  setTimeout(() => process.exit(1), 200);
4448
4582
  return c.json({ ok: true });
4449
4583
  }).post("/stop", requireAdmin, (c) => {
@@ -4460,29 +4594,107 @@ var app17 = new Hono17().post("/restart", requireAdmin, (c) => {
4460
4594
  stream.writeSSE({ data: JSON.stringify(entry) }).catch(() => {
4461
4595
  });
4462
4596
  });
4463
- await new Promise((resolve19) => {
4597
+ await new Promise((resolve20) => {
4464
4598
  stream.onAbort(() => {
4465
4599
  unsubscribe();
4466
- resolve19();
4600
+ resolve20();
4467
4601
  });
4468
4602
  });
4469
4603
  });
4470
4604
  }).get("/info", (c) => {
4471
4605
  const config = readSystemsConfig();
4472
4606
  return c.json({ system: config?.system ?? null });
4607
+ }).post(
4608
+ "/register",
4609
+ requireAdmin,
4610
+ zValidator5("json", z5.object({ name: z5.string().min(1) })),
4611
+ async (c) => {
4612
+ const existing = readSystemsConfig();
4613
+ if (existing) {
4614
+ return c.json({ error: `Already registered as "${existing.system}"` }, 400);
4615
+ }
4616
+ const { name } = c.req.valid("json");
4617
+ const apiUrl = process.env.VOLUTE_SYSTEMS_URL || DEFAULT_API_URL;
4618
+ let apiKey;
4619
+ let system;
4620
+ try {
4621
+ const res = await fetch(`${apiUrl}/api/register`, {
4622
+ method: "POST",
4623
+ headers: { "Content-Type": "application/json" },
4624
+ body: JSON.stringify({ name: name.trim() })
4625
+ });
4626
+ if (!res.ok) {
4627
+ const err = await res.json().catch(() => ({ error: `HTTP ${res.status}` }));
4628
+ return c.json({ error: err.error }, 502);
4629
+ }
4630
+ ({ apiKey, system } = await res.json());
4631
+ } catch (err) {
4632
+ return c.json({ error: `Connection failed: ${err.message}` }, 502);
4633
+ }
4634
+ try {
4635
+ writeSystemsConfig({ apiKey, system, apiUrl });
4636
+ } catch (err) {
4637
+ return c.json(
4638
+ {
4639
+ error: `Registered as "${system}" but failed to save config: ${err.message}`
4640
+ },
4641
+ 500
4642
+ );
4643
+ }
4644
+ return c.json({ system });
4645
+ }
4646
+ ).post(
4647
+ "/login",
4648
+ requireAdmin,
4649
+ zValidator5("json", z5.object({ key: z5.string().min(1) })),
4650
+ async (c) => {
4651
+ const existing = readSystemsConfig();
4652
+ if (existing) {
4653
+ return c.json({ error: `Already logged in as "${existing.system}"` }, 400);
4654
+ }
4655
+ const { key } = c.req.valid("json");
4656
+ const apiUrl = process.env.VOLUTE_SYSTEMS_URL || DEFAULT_API_URL;
4657
+ let system;
4658
+ try {
4659
+ const res = await fetch(`${apiUrl}/api/whoami`, {
4660
+ headers: { Authorization: `Bearer ${key.trim()}` }
4661
+ });
4662
+ if (!res.ok) {
4663
+ const err = await res.json().catch(() => ({ error: `HTTP ${res.status}` }));
4664
+ return c.json({ error: err.error }, 502);
4665
+ }
4666
+ ({ system } = await res.json());
4667
+ } catch (err) {
4668
+ return c.json({ error: `Connection failed: ${err.message}` }, 502);
4669
+ }
4670
+ try {
4671
+ writeSystemsConfig({ apiKey: key.trim(), system, apiUrl });
4672
+ } catch (err) {
4673
+ return c.json(
4674
+ {
4675
+ error: `Logged in as "${system}" but failed to save config: ${err.message}`
4676
+ },
4677
+ 500
4678
+ );
4679
+ }
4680
+ return c.json({ system });
4681
+ }
4682
+ ).post("/logout", requireAdmin, (c) => {
4683
+ deleteSystemsConfig();
4684
+ return c.json({ ok: true });
4473
4685
  });
4474
- var system_default = app17;
4686
+ var system_default = app18;
4475
4687
 
4476
4688
  // src/web/api/typing.ts
4477
- import { zValidator as zValidator5 } from "@hono/zod-validator";
4478
- import { Hono as Hono18 } from "hono";
4479
- import { z as z5 } from "zod";
4480
- var typingSchema = z5.object({
4481
- channel: z5.string().min(1),
4482
- sender: z5.string().min(1),
4483
- active: z5.boolean()
4689
+ import { zValidator as zValidator6 } from "@hono/zod-validator";
4690
+ import { Hono as Hono19 } from "hono";
4691
+ import { z as z6 } from "zod";
4692
+ var typingSchema = z6.object({
4693
+ channel: z6.string().min(1),
4694
+ sender: z6.string().min(1),
4695
+ active: z6.boolean()
4484
4696
  });
4485
- var app18 = new Hono18().post("/:name/typing", zValidator5("json", typingSchema), (c) => {
4697
+ var app19 = new Hono19().post("/:name/typing", zValidator6("json", typingSchema), (c) => {
4486
4698
  const { channel, sender, active } = c.req.valid("json");
4487
4699
  const map = getTypingMap();
4488
4700
  if (active) {
@@ -4504,13 +4716,13 @@ var app18 = new Hono18().post("/:name/typing", zValidator5("json", typingSchema)
4504
4716
  const map = getTypingMap();
4505
4717
  return c.json({ typing: map.get(channel) });
4506
4718
  });
4507
- var typing_default = app18;
4719
+ var typing_default = app19;
4508
4720
 
4509
4721
  // src/web/api/update.ts
4510
4722
  import { spawn as spawn2 } from "child_process";
4511
- import { Hono as Hono19 } from "hono";
4723
+ import { Hono as Hono20 } from "hono";
4512
4724
  var bin;
4513
- var app19 = new Hono19().get("/update", async (c) => {
4725
+ var app20 = new Hono20().get("/update", async (c) => {
4514
4726
  const result = await checkForUpdate();
4515
4727
  return c.json(result);
4516
4728
  }).post("/update", requireAdmin, async (c) => {
@@ -4525,21 +4737,21 @@ var app19 = new Hono19().get("/update", async (c) => {
4525
4737
  child.unref();
4526
4738
  return c.json({ ok: true, message: "Updating..." });
4527
4739
  });
4528
- var update_default = app19;
4740
+ var update_default = app20;
4529
4741
 
4530
4742
  // src/web/api/v1/chat.ts
4531
- import { zValidator as zValidator6 } from "@hono/zod-validator";
4532
- import { Hono as Hono20 } from "hono";
4743
+ import { zValidator as zValidator7 } from "@hono/zod-validator";
4744
+ import { Hono as Hono21 } from "hono";
4533
4745
  import { streamSSE as streamSSE4 } from "hono/streaming";
4534
- import { z as z6 } from "zod";
4746
+ import { z as z7 } from "zod";
4535
4747
  async function fanOutToMinds(opts) {
4536
4748
  const participants = await getParticipants(opts.conversationId);
4537
4749
  const mindParticipants = participants.filter((p) => p.userType === "mind");
4538
4750
  const participantNames = participants.map((p) => p.username);
4539
4751
  const isDM = opts.isDM ?? participants.length === 2;
4540
4752
  const channelEntryType = opts.channelEntryType ?? (isDM ? "dm" : "group");
4541
- const { getMindManager: getMindManager2 } = await import("./mind-manager-ZNRIYEK3.js");
4542
- const { getSleepManagerIfReady } = await import("./sleep-manager-XXSWQQLE.js");
4753
+ const { getMindManager: getMindManager2 } = await import("./mind-manager-4NDNAYAB.js");
4754
+ const { getSleepManagerIfReady } = await import("./sleep-manager-RKTFZPD3.js");
4543
4755
  const manager = getMindManager2();
4544
4756
  const sm = getSleepManagerIfReady();
4545
4757
  const targetMinds = mindParticipants.map((ap) => {
@@ -4588,18 +4800,18 @@ async function fanOutToMinds(opts) {
4588
4800
  });
4589
4801
  }
4590
4802
  }
4591
- var mindChatSchema = z6.object({
4592
- message: z6.string().optional(),
4593
- conversationId: z6.string().optional(),
4594
- sender: z6.string().optional(),
4595
- images: z6.array(z6.object({ media_type: z6.string(), data: z6.string() })).optional()
4803
+ var mindChatSchema = z7.object({
4804
+ message: z7.string().optional(),
4805
+ conversationId: z7.string().optional(),
4806
+ sender: z7.string().optional(),
4807
+ images: z7.array(z7.object({ media_type: z7.string(), data: z7.string() })).optional()
4596
4808
  });
4597
- var unifiedChatSchema = z6.object({
4598
- message: z6.string().optional(),
4599
- conversationId: z6.string(),
4600
- images: z6.array(z6.object({ media_type: z6.string(), data: z6.string() })).optional()
4809
+ var unifiedChatSchema = z7.object({
4810
+ message: z7.string().optional(),
4811
+ conversationId: z7.string(),
4812
+ images: z7.array(z7.object({ media_type: z7.string(), data: z7.string() })).optional()
4601
4813
  });
4602
- var app20 = new Hono20().use("*", authMiddleware).post("/minds/:name/chat", zValidator6("json", mindChatSchema), async (c) => {
4814
+ var app21 = new Hono21().use("*", authMiddleware).post("/minds/:name/chat", zValidator7("json", mindChatSchema), async (c) => {
4603
4815
  const name = c.req.param("name");
4604
4816
  const [baseName] = name.split("@", 2);
4605
4817
  const entry = findMind(baseName);
@@ -4682,15 +4894,15 @@ var app20 = new Hono20().use("*", authMiddleware).post("/minds/:name/chat", zVal
4682
4894
  if (!stream.aborted) logger_default.error("[v1-chat] SSE ping error:", logger_default.errorData(err));
4683
4895
  });
4684
4896
  }, 15e3);
4685
- await new Promise((resolve19) => {
4897
+ await new Promise((resolve20) => {
4686
4898
  stream.onAbort(() => {
4687
4899
  unsubscribe();
4688
4900
  clearInterval(keepAlive);
4689
- resolve19();
4901
+ resolve20();
4690
4902
  });
4691
4903
  });
4692
4904
  });
4693
- }).post("/chat", zValidator6("json", unifiedChatSchema), async (c) => {
4905
+ }).post("/chat", zValidator7("json", unifiedChatSchema), async (c) => {
4694
4906
  const user = c.get("user");
4695
4907
  const body = c.req.valid("json");
4696
4908
  if (!body.message && (!body.images || body.images.length === 0)) {
@@ -4722,17 +4934,17 @@ var app20 = new Hono20().use("*", authMiddleware).post("/minds/:name/chat", zVal
4722
4934
  });
4723
4935
  return c.json({ ok: true, conversationId: body.conversationId });
4724
4936
  });
4725
- var chat_default = app20;
4937
+ var chat_default = app21;
4726
4938
 
4727
4939
  // src/web/api/v1/conversations.ts
4728
- import { zValidator as zValidator7 } from "@hono/zod-validator";
4729
- import { Hono as Hono21 } from "hono";
4730
- import { z as z7 } from "zod";
4731
- var createSchema = z7.object({
4732
- title: z7.string().optional(),
4733
- participantNames: z7.array(z7.string()).min(1)
4940
+ import { zValidator as zValidator8 } from "@hono/zod-validator";
4941
+ import { Hono as Hono22 } from "hono";
4942
+ import { z as z8 } from "zod";
4943
+ var createSchema = z8.object({
4944
+ title: z8.string().optional(),
4945
+ participantNames: z8.array(z8.string()).min(1)
4734
4946
  });
4735
- var app21 = new Hono21().use("*", authMiddleware).get("/", async (c) => {
4947
+ var app22 = new Hono22().use("*", authMiddleware).get("/", async (c) => {
4736
4948
  const user = c.get("user");
4737
4949
  const convs = await listConversationsWithParticipants(user.id);
4738
4950
  return c.json(convs);
@@ -4763,7 +4975,7 @@ var app21 = new Hono21().use("*", authMiddleware).get("/", async (c) => {
4763
4975
  }
4764
4976
  const participants = await getParticipants(id);
4765
4977
  return c.json(participants);
4766
- }).post("/", zValidator7("json", createSchema), async (c) => {
4978
+ }).post("/", zValidator8("json", createSchema), async (c) => {
4767
4979
  const user = c.get("user");
4768
4980
  const body = c.req.valid("json");
4769
4981
  const participantIds = /* @__PURE__ */ new Set();
@@ -4809,11 +5021,11 @@ var app21 = new Hono21().use("*", authMiddleware).get("/", async (c) => {
4809
5021
  if (!deleted) return c.json({ error: "Conversation not found" }, 404);
4810
5022
  return c.json({ ok: true });
4811
5023
  });
4812
- var conversations_default = app21;
5024
+ var conversations_default = app22;
4813
5025
 
4814
5026
  // src/web/api/v1/events.ts
4815
5027
  import { desc as desc3 } from "drizzle-orm";
4816
- import { Hono as Hono22 } from "hono";
5028
+ import { Hono as Hono23 } from "hono";
4817
5029
  import { streamSSE as streamSSE5 } from "hono/streaming";
4818
5030
 
4819
5031
  // src/lib/events/brain-presence.ts
@@ -4860,7 +5072,7 @@ function getEventsSince(sinceId) {
4860
5072
  }
4861
5073
 
4862
5074
  // src/web/api/v1/events.ts
4863
- var app22 = new Hono22().use("*", authMiddleware).get("/", async (c) => {
5075
+ var app23 = new Hono23().use("*", authMiddleware).get("/", async (c) => {
4864
5076
  const user = c.get("user");
4865
5077
  const since = c.req.query("since");
4866
5078
  const sinceId = since ? Number(since) : 0;
@@ -4954,8 +5166,8 @@ var app22 = new Hono22().use("*", authMiddleware).get("/", async (c) => {
4954
5166
  });
4955
5167
  }, 15e3);
4956
5168
  cleanups.push(() => clearInterval(keepAlive));
4957
- await new Promise((resolve19) => {
4958
- stream.onAbort(() => resolve19());
5169
+ await new Promise((resolve20) => {
5170
+ stream.onAbort(() => resolve20());
4959
5171
  });
4960
5172
  } finally {
4961
5173
  for (const cleanup of cleanups) {
@@ -4967,19 +5179,19 @@ var app22 = new Hono22().use("*", authMiddleware).get("/", async (c) => {
4967
5179
  }
4968
5180
  });
4969
5181
  });
4970
- var events_default = app22;
5182
+ var events_default = app23;
4971
5183
 
4972
5184
  // src/web/api/variants.ts
4973
5185
  import { existsSync as existsSync12, mkdirSync as mkdirSync8, writeFileSync as writeFileSync8 } from "fs";
4974
- import { resolve as resolve16 } from "path";
4975
- import { Hono as Hono23 } from "hono";
5186
+ import { resolve as resolve17 } from "path";
5187
+ import { Hono as Hono24 } from "hono";
4976
5188
 
4977
5189
  // src/lib/spawn-server.ts
4978
5190
  import { spawn as spawn3 } from "child_process";
4979
5191
  import { closeSync, mkdirSync as mkdirSync7, openSync, readFileSync as readFileSync10 } from "fs";
4980
- import { resolve as resolve15 } from "path";
5192
+ import { resolve as resolve16 } from "path";
4981
5193
  function tsxBin(cwd) {
4982
- return resolve15(cwd, "node_modules", ".bin", "tsx");
5194
+ return resolve16(cwd, "node_modules", ".bin", "tsx");
4983
5195
  }
4984
5196
  function spawnServer(cwd, port, options) {
4985
5197
  if (options?.detached) {
@@ -4992,31 +5204,31 @@ function spawnAttached(cwd, port) {
4992
5204
  cwd,
4993
5205
  stdio: ["ignore", "pipe", "pipe"]
4994
5206
  });
4995
- return new Promise((resolve19) => {
4996
- const timeout = setTimeout(() => resolve19(null), 3e4);
5207
+ return new Promise((resolve20) => {
5208
+ const timeout = setTimeout(() => resolve20(null), 3e4);
4997
5209
  function checkOutput(data) {
4998
5210
  const match = data.toString().match(/listening on :(\d+)/);
4999
5211
  if (match) {
5000
5212
  clearTimeout(timeout);
5001
- resolve19({ child, actualPort: parseInt(match[1], 10) });
5213
+ resolve20({ child, actualPort: parseInt(match[1], 10) });
5002
5214
  }
5003
5215
  }
5004
5216
  child.stdout?.on("data", checkOutput);
5005
5217
  child.stderr?.on("data", checkOutput);
5006
5218
  child.on("error", () => {
5007
5219
  clearTimeout(timeout);
5008
- resolve19(null);
5220
+ resolve20(null);
5009
5221
  });
5010
5222
  child.on("exit", () => {
5011
5223
  clearTimeout(timeout);
5012
- resolve19(null);
5224
+ resolve20(null);
5013
5225
  });
5014
5226
  });
5015
5227
  }
5016
5228
  function spawnDetached(cwd, port, logDir) {
5017
- const logsDir = logDir ?? resolve15(cwd, ".mind", "logs");
5229
+ const logsDir = logDir ?? resolve16(cwd, ".mind", "logs");
5018
5230
  mkdirSync7(logsDir, { recursive: true });
5019
- const logPath = resolve15(logsDir, "mind.log");
5231
+ const logPath = resolve16(logsDir, "mind.log");
5020
5232
  const logFd = openSync(logPath, "a");
5021
5233
  const child = spawn3(tsxBin(cwd), ["src/server.ts", "--port", String(port)], {
5022
5234
  cwd,
@@ -5088,7 +5300,7 @@ async function verify2(port) {
5088
5300
  }
5089
5301
 
5090
5302
  // src/web/api/variants.ts
5091
- var app23 = new Hono23().get("/:name/variants", async (c) => {
5303
+ var app24 = new Hono24().get("/:name/variants", async (c) => {
5092
5304
  const name = c.req.param("name");
5093
5305
  const entry = findMind(name);
5094
5306
  if (!entry) return c.json({ error: "Mind not found" }, 404);
@@ -5128,11 +5340,11 @@ var app23 = new Hono23().get("/:name/variants", async (c) => {
5128
5340
  const err = validateBranchName(variantName);
5129
5341
  if (err) return c.json({ error: err }, 400);
5130
5342
  const projectRoot = mindDir(mindName);
5131
- const variantDir = resolve16(projectRoot, ".variants", variantName);
5343
+ const variantDir = resolve17(projectRoot, ".variants", variantName);
5132
5344
  if (existsSync12(variantDir)) {
5133
5345
  return c.json({ error: `Variant directory already exists: ${variantDir}` }, 409);
5134
5346
  }
5135
- mkdirSync8(resolve16(projectRoot, ".variants"), { recursive: true });
5347
+ mkdirSync8(resolve17(projectRoot, ".variants"), { recursive: true });
5136
5348
  try {
5137
5349
  await gitExec(["worktree", "add", "-b", variantName, variantDir], { cwd: projectRoot });
5138
5350
  } catch (e) {
@@ -5145,7 +5357,7 @@ var app23 = new Hono23().get("/:name/variants", async (c) => {
5145
5357
  const [cmd, args] = wrapForIsolation("npm", ["install"], mindName);
5146
5358
  await exec(cmd, args, {
5147
5359
  cwd: variantDir,
5148
- env: { ...process.env, HOME: resolve16(variantDir, "home") }
5360
+ env: { ...process.env, HOME: resolve17(variantDir, "home") }
5149
5361
  });
5150
5362
  } else {
5151
5363
  await exec("npm", ["install"], { cwd: variantDir });
@@ -5155,7 +5367,7 @@ var app23 = new Hono23().get("/:name/variants", async (c) => {
5155
5367
  return c.json({ error: `npm install failed: ${msg}` }, 500);
5156
5368
  }
5157
5369
  if (body.soul) {
5158
- writeFileSync8(resolve16(variantDir, "home/SOUL.md"), body.soul);
5370
+ writeFileSync8(resolve17(variantDir, "home/SOUL.md"), body.soul);
5159
5371
  }
5160
5372
  const variantPort = body.port ?? nextPort();
5161
5373
  const variant = {
@@ -5266,7 +5478,7 @@ var app23 = new Hono23().get("/:name/variants", async (c) => {
5266
5478
  const [cmd, args] = wrapForIsolation("npm", ["install"], mindName);
5267
5479
  await exec(cmd, args, {
5268
5480
  cwd: projectRoot,
5269
- env: { ...process.env, HOME: resolve16(projectRoot, "home") }
5481
+ env: { ...process.env, HOME: resolve17(projectRoot, "home") }
5270
5482
  });
5271
5483
  } else {
5272
5484
  await exec("npm", ["install"], { cwd: projectRoot });
@@ -5304,19 +5516,19 @@ var app23 = new Hono23().get("/:name/variants", async (c) => {
5304
5516
  await cleanupVariant(mindName, variantName, projectRoot, variant.path, { stop: true });
5305
5517
  return c.json({ ok: true });
5306
5518
  });
5307
- var variants_default = app23;
5519
+ var variants_default = app24;
5308
5520
 
5309
5521
  // src/web/api/volute/channels.ts
5310
- import { zValidator as zValidator8 } from "@hono/zod-validator";
5311
- import { Hono as Hono24 } from "hono";
5312
- import { z as z8 } from "zod";
5313
- var createSchema2 = z8.object({
5314
- name: z8.string().min(1).max(50).regex(/^[a-z0-9][a-z0-9-]*$/, "Channel names must be lowercase alphanumeric with hyphens")
5522
+ import { zValidator as zValidator9 } from "@hono/zod-validator";
5523
+ import { Hono as Hono25 } from "hono";
5524
+ import { z as z9 } from "zod";
5525
+ var createSchema2 = z9.object({
5526
+ name: z9.string().min(1).max(50).regex(/^[a-z0-9][a-z0-9-]*$/, "Channel names must be lowercase alphanumeric with hyphens")
5315
5527
  });
5316
- var inviteSchema = z8.object({
5317
- username: z8.string().min(1)
5528
+ var inviteSchema = z9.object({
5529
+ username: z9.string().min(1)
5318
5530
  });
5319
- var app24 = new Hono24().get("/", async (c) => {
5531
+ var app25 = new Hono25().get("/", async (c) => {
5320
5532
  const user = c.get("user");
5321
5533
  const channels = await listChannels();
5322
5534
  const results = await Promise.all(
@@ -5327,7 +5539,7 @@ var app24 = new Hono24().get("/", async (c) => {
5327
5539
  })
5328
5540
  );
5329
5541
  return c.json(results);
5330
- }).post("/", zValidator8("json", createSchema2), async (c) => {
5542
+ }).post("/", zValidator9("json", createSchema2), async (c) => {
5331
5543
  const user = c.get("user");
5332
5544
  const body = c.req.valid("json");
5333
5545
  try {
@@ -5360,7 +5572,7 @@ var app24 = new Hono24().get("/", async (c) => {
5360
5572
  if (!ch) return c.json({ error: "Channel not found" }, 404);
5361
5573
  const participants = await getParticipants(ch.id);
5362
5574
  return c.json(participants);
5363
- }).post("/:name/invite", zValidator8("json", inviteSchema), async (c) => {
5575
+ }).post("/:name/invite", zValidator9("json", inviteSchema), async (c) => {
5364
5576
  const name = c.req.param("name");
5365
5577
  const inviter = c.get("user");
5366
5578
  const { username } = c.req.valid("json");
@@ -5380,21 +5592,21 @@ var app24 = new Hono24().get("/", async (c) => {
5380
5592
  ]);
5381
5593
  return c.json({ ok: true });
5382
5594
  });
5383
- var channels_default2 = app24;
5595
+ var channels_default2 = app25;
5384
5596
 
5385
5597
  // src/web/api/volute/chat.ts
5386
- import { zValidator as zValidator9 } from "@hono/zod-validator";
5387
- import { Hono as Hono25 } from "hono";
5598
+ import { zValidator as zValidator10 } from "@hono/zod-validator";
5599
+ import { Hono as Hono26 } from "hono";
5388
5600
  import { streamSSE as streamSSE6 } from "hono/streaming";
5389
- import { z as z9 } from "zod";
5601
+ import { z as z10 } from "zod";
5390
5602
  async function fanOutToMinds2(opts) {
5391
5603
  const participants = await getParticipants(opts.conversationId);
5392
5604
  const mindParticipants = participants.filter((p) => p.userType === "mind");
5393
5605
  const participantNames = participants.map((p) => p.username);
5394
5606
  const isDM = opts.isDM ?? participants.length === 2;
5395
5607
  const channelEntryType = opts.channelEntryType ?? (isDM ? "dm" : "group");
5396
- const { getMindManager: getMindManager2 } = await import("./mind-manager-ZNRIYEK3.js");
5397
- const { getSleepManagerIfReady } = await import("./sleep-manager-XXSWQQLE.js");
5608
+ const { getMindManager: getMindManager2 } = await import("./mind-manager-4NDNAYAB.js");
5609
+ const { getSleepManagerIfReady } = await import("./sleep-manager-RKTFZPD3.js");
5398
5610
  const manager = getMindManager2();
5399
5611
  const sm = getSleepManagerIfReady();
5400
5612
  const targetMinds = mindParticipants.map((ap) => {
@@ -5442,18 +5654,18 @@ async function fanOutToMinds2(opts) {
5442
5654
  });
5443
5655
  }
5444
5656
  }
5445
- var chatSchema = z9.object({
5446
- message: z9.string().optional(),
5447
- conversationId: z9.string().optional(),
5448
- sender: z9.string().optional(),
5449
- images: z9.array(
5450
- z9.object({
5451
- media_type: z9.string(),
5452
- data: z9.string()
5657
+ var chatSchema = z10.object({
5658
+ message: z10.string().optional(),
5659
+ conversationId: z10.string().optional(),
5660
+ sender: z10.string().optional(),
5661
+ images: z10.array(
5662
+ z10.object({
5663
+ media_type: z10.string(),
5664
+ data: z10.string()
5453
5665
  })
5454
5666
  ).optional()
5455
5667
  });
5456
- var app25 = new Hono25().post("/:name/chat", zValidator9("json", chatSchema), async (c) => {
5668
+ var app26 = new Hono26().post("/:name/chat", zValidator10("json", chatSchema), async (c) => {
5457
5669
  const name = c.req.param("name");
5458
5670
  const [baseName] = name.split("@", 2);
5459
5671
  const entry = findMind(baseName);
@@ -5540,23 +5752,23 @@ var app25 = new Hono25().post("/:name/chat", zValidator9("json", chatSchema), as
5540
5752
  if (!stream.aborted) console.error("[chat] SSE ping error:", err);
5541
5753
  });
5542
5754
  }, 15e3);
5543
- await new Promise((resolve19) => {
5755
+ await new Promise((resolve20) => {
5544
5756
  stream.onAbort(() => {
5545
5757
  unsubscribe();
5546
5758
  clearInterval(keepAlive);
5547
- resolve19();
5759
+ resolve20();
5548
5760
  });
5549
5761
  });
5550
5762
  });
5551
5763
  });
5552
- var unifiedChatSchema2 = z9.object({
5553
- message: z9.string().optional(),
5554
- conversationId: z9.string(),
5555
- images: z9.array(z9.object({ media_type: z9.string(), data: z9.string() })).optional()
5764
+ var unifiedChatSchema2 = z10.object({
5765
+ message: z10.string().optional(),
5766
+ conversationId: z10.string(),
5767
+ images: z10.array(z10.object({ media_type: z10.string(), data: z10.string() })).optional()
5556
5768
  });
5557
- var unifiedChatApp = new Hono25().post(
5769
+ var unifiedChatApp = new Hono26().post(
5558
5770
  "/chat",
5559
- zValidator9("json", unifiedChatSchema2),
5771
+ zValidator10("json", unifiedChatSchema2),
5560
5772
  async (c) => {
5561
5773
  const user = c.get("user");
5562
5774
  const body = c.req.valid("json");
@@ -5590,18 +5802,18 @@ var unifiedChatApp = new Hono25().post(
5590
5802
  return c.json({ ok: true, conversationId: body.conversationId });
5591
5803
  }
5592
5804
  );
5593
- var chat_default2 = app25;
5805
+ var chat_default2 = app26;
5594
5806
 
5595
5807
  // src/web/api/volute/conversations.ts
5596
- import { zValidator as zValidator10 } from "@hono/zod-validator";
5597
- import { Hono as Hono26 } from "hono";
5598
- import { z as z10 } from "zod";
5599
- var createConvSchema = z10.object({
5600
- title: z10.string().optional(),
5601
- participantIds: z10.array(z10.number()).optional(),
5602
- participantNames: z10.array(z10.string()).optional()
5808
+ import { zValidator as zValidator11 } from "@hono/zod-validator";
5809
+ import { Hono as Hono27 } from "hono";
5810
+ import { z as z11 } from "zod";
5811
+ var createConvSchema = z11.object({
5812
+ title: z11.string().optional(),
5813
+ participantIds: z11.array(z11.number()).optional(),
5814
+ participantNames: z11.array(z11.string()).optional()
5603
5815
  });
5604
- var app26 = new Hono26().get("/:name/conversations", async (c) => {
5816
+ var app27 = new Hono27().get("/:name/conversations", async (c) => {
5605
5817
  const name = c.req.param("name");
5606
5818
  const user = c.get("user");
5607
5819
  let lookupId = user.id;
@@ -5612,7 +5824,7 @@ var app26 = new Hono26().get("/:name/conversations", async (c) => {
5612
5824
  const all = await listConversationsForUser(lookupId);
5613
5825
  const convs = all.filter((c2) => c2.mind_name === name || c2.type === "channel");
5614
5826
  return c.json(convs);
5615
- }).post("/:name/conversations", zValidator10("json", createConvSchema), async (c) => {
5827
+ }).post("/:name/conversations", zValidator11("json", createConvSchema), async (c) => {
5616
5828
  const name = c.req.param("name");
5617
5829
  const user = c.get("user");
5618
5830
  const body = c.req.valid("json");
@@ -5686,18 +5898,18 @@ var app26 = new Hono26().get("/:name/conversations", async (c) => {
5686
5898
  if (!deleted) return c.json({ error: "Conversation not found" }, 404);
5687
5899
  return c.json({ ok: true });
5688
5900
  });
5689
- var conversations_default2 = app26;
5901
+ var conversations_default2 = app27;
5690
5902
 
5691
5903
  // src/web/api/volute/user-conversations.ts
5692
- import { zValidator as zValidator11 } from "@hono/zod-validator";
5693
- import { Hono as Hono27 } from "hono";
5904
+ import { zValidator as zValidator12 } from "@hono/zod-validator";
5905
+ import { Hono as Hono28 } from "hono";
5694
5906
  import { streamSSE as streamSSE7 } from "hono/streaming";
5695
- import { z as z11 } from "zod";
5696
- var createSchema3 = z11.object({
5697
- title: z11.string().optional(),
5698
- participantNames: z11.array(z11.string()).min(1)
5907
+ import { z as z12 } from "zod";
5908
+ var createSchema3 = z12.object({
5909
+ title: z12.string().optional(),
5910
+ participantNames: z12.array(z12.string()).min(1)
5699
5911
  });
5700
- var app27 = new Hono27().use("*", authMiddleware).get("/", async (c) => {
5912
+ var app28 = new Hono28().use("*", authMiddleware).get("/", async (c) => {
5701
5913
  const user = c.get("user");
5702
5914
  const convs = await listConversationsWithParticipants(user.id);
5703
5915
  return c.json(convs);
@@ -5709,7 +5921,7 @@ var app27 = new Hono27().use("*", authMiddleware).get("/", async (c) => {
5709
5921
  }
5710
5922
  const msgs = await getMessages(id);
5711
5923
  return c.json(msgs);
5712
- }).post("/", zValidator11("json", createSchema3), async (c) => {
5924
+ }).post("/", zValidator12("json", createSchema3), async (c) => {
5713
5925
  const user = c.get("user");
5714
5926
  const body = c.req.valid("json");
5715
5927
  const participantIds = /* @__PURE__ */ new Set();
@@ -5756,11 +5968,11 @@ var app27 = new Hono27().use("*", authMiddleware).get("/", async (c) => {
5756
5968
  if (!stream.aborted) console.error("[chat] SSE ping error:", err);
5757
5969
  });
5758
5970
  }, 15e3);
5759
- await new Promise((resolve19) => {
5971
+ await new Promise((resolve20) => {
5760
5972
  stream.onAbort(() => {
5761
5973
  unsubscribe();
5762
5974
  clearInterval(keepAlive);
5763
- resolve19();
5975
+ resolve20();
5764
5976
  });
5765
5977
  });
5766
5978
  });
@@ -5771,12 +5983,12 @@ var app27 = new Hono27().use("*", authMiddleware).get("/", async (c) => {
5771
5983
  if (!deleted) return c.json({ error: "Conversation not found" }, 404);
5772
5984
  return c.json({ ok: true });
5773
5985
  });
5774
- var user_conversations_default = app27;
5986
+ var user_conversations_default = app28;
5775
5987
 
5776
5988
  // src/web/app.ts
5777
5989
  var httpLog = logger_default.child("http");
5778
- var app28 = new Hono28();
5779
- app28.onError((err, c) => {
5990
+ var app29 = new Hono29();
5991
+ app29.onError((err, c) => {
5780
5992
  if (err instanceof HTTPException) {
5781
5993
  return err.getResponse();
5782
5994
  }
@@ -5787,10 +5999,10 @@ app28.onError((err, c) => {
5787
5999
  });
5788
6000
  return c.json({ error: "Internal server error" }, 500);
5789
6001
  });
5790
- app28.notFound((c) => {
6002
+ app29.notFound((c) => {
5791
6003
  return c.json({ error: "Not found" }, 404);
5792
6004
  });
5793
- app28.use("*", async (c, next) => {
6005
+ app29.use("*", async (c, next) => {
5794
6006
  const start = Date.now();
5795
6007
  await next();
5796
6008
  const duration = Date.now() - start;
@@ -5801,7 +6013,7 @@ app28.use("*", async (c, next) => {
5801
6013
  httpLog.debug("request", data);
5802
6014
  }
5803
6015
  });
5804
- app28.get("/api/health", (c) => {
6016
+ app29.get("/api/health", (c) => {
5805
6017
  let version = "unknown";
5806
6018
  let cached = null;
5807
6019
  try {
@@ -5816,38 +6028,39 @@ app28.get("/api/health", (c) => {
5816
6028
  ...cached?.updateAvailable ? { updateAvailable: true, latest: cached.latest } : {}
5817
6029
  });
5818
6030
  });
5819
- app28.use("/api/*", bodyLimit({ maxSize: 10 * 1024 * 1024 }));
5820
- app28.use("/api/*", csrf());
5821
- app28.use("/api/activity/*", authMiddleware);
5822
- app28.use("/api/minds/*", authMiddleware);
5823
- app28.use("/api/conversations/*", authMiddleware);
5824
- app28.use("/api/volute/*", authMiddleware);
5825
- app28.use("/api/system/*", authMiddleware);
5826
- app28.use("/api/env/*", authMiddleware);
5827
- app28.use("/api/prompts/*", authMiddleware);
5828
- app28.use("/api/skills/*", authMiddleware);
5829
- app28.use("/api/v1/*", authMiddleware);
5830
- app28.route("/pages", pages_default);
5831
- var routes = app28.route("/api/activity", activity_default).route("/api/keys", keys_default).route("/api/auth", auth_default).route("/api/system", system_default).route("/api/system", update_default).route("/api/minds", minds_default).route("/api/minds", chat_default2).route("/api/minds", connectors_default).route("/api/minds", schedules_default).route("/api/minds", logs_default).route("/api/minds", typing_default).route("/api/minds", variants_default).route("/api/minds", file_sharing_default).route("/api/minds", files_default).route("/api/minds", channels_default).route("/api/minds", shared_default).route("/api/minds", env_default).route("/api/minds", mind_skills_default).route("/api/minds", conversations_default2).route("/api/env", sharedEnvApp).route("/api/prompts", prompts_default).route("/api/skills", skills_default).route("/api/conversations", user_conversations_default).route("/api/volute/channels", channels_default2).route("/api/volute", unifiedChatApp).route("/api/v1/conversations", conversations_default).route("/api/v1/events", events_default).route("/api/v1", chat_default);
5832
- app28.route("/api/v1/minds", minds_default);
5833
- app28.route("/api/v1/minds", typing_default);
5834
- app28.route("/api/v1/minds", variants_default);
5835
- app28.route("/api/v1/minds", files_default);
5836
- app28.route("/api/v1/minds", env_default);
5837
- app28.route("/api/v1/minds", mind_skills_default);
5838
- app28.route("/api/v1/minds", connectors_default);
5839
- app28.route("/api/v1/minds", schedules_default);
5840
- app28.route("/api/v1/minds", logs_default);
5841
- app28.route("/api/v1/system", system_default);
5842
- app28.route("/api/v1/system", update_default);
5843
- app28.route("/api/v1/prompts", prompts_default);
5844
- app28.route("/api/v1/skills", skills_default);
5845
- app28.route("/api/v1/env", sharedEnvApp);
5846
- app28.route("/api/v1/channels", channels_default2);
5847
- var app_default = app28;
6031
+ app29.use("/api/*", bodyLimit({ maxSize: 10 * 1024 * 1024 }));
6032
+ app29.use("/api/*", csrf());
6033
+ app29.use("/api/activity/*", authMiddleware);
6034
+ app29.use("/api/minds/*", authMiddleware);
6035
+ app29.use("/api/conversations/*", authMiddleware);
6036
+ app29.use("/api/volute/*", authMiddleware);
6037
+ app29.use("/api/system/*", authMiddleware);
6038
+ app29.use("/api/env/*", authMiddleware);
6039
+ app29.use("/api/prompts/*", authMiddleware);
6040
+ app29.use("/api/skills/*", authMiddleware);
6041
+ app29.use("/api/v1/*", authMiddleware);
6042
+ app29.route("/pages", pages_default);
6043
+ app29.route("/public", public_files_default);
6044
+ var routes = app29.route("/api/activity", activity_default).route("/api/keys", keys_default).route("/api/auth", auth_default).route("/api/system", system_default).route("/api/system", update_default).route("/api/minds", minds_default).route("/api/minds", chat_default2).route("/api/minds", connectors_default).route("/api/minds", schedules_default).route("/api/minds", logs_default).route("/api/minds", typing_default).route("/api/minds", variants_default).route("/api/minds", file_sharing_default).route("/api/minds", files_default).route("/api/minds", channels_default).route("/api/minds", shared_default).route("/api/minds", env_default).route("/api/minds", mind_skills_default).route("/api/minds", conversations_default2).route("/api/env", sharedEnvApp).route("/api/prompts", prompts_default).route("/api/skills", skills_default).route("/api/conversations", user_conversations_default).route("/api/volute/channels", channels_default2).route("/api/volute", unifiedChatApp).route("/api/v1/conversations", conversations_default).route("/api/v1/events", events_default).route("/api/v1", chat_default);
6045
+ app29.route("/api/v1/minds", minds_default);
6046
+ app29.route("/api/v1/minds", typing_default);
6047
+ app29.route("/api/v1/minds", variants_default);
6048
+ app29.route("/api/v1/minds", files_default);
6049
+ app29.route("/api/v1/minds", env_default);
6050
+ app29.route("/api/v1/minds", mind_skills_default);
6051
+ app29.route("/api/v1/minds", connectors_default);
6052
+ app29.route("/api/v1/minds", schedules_default);
6053
+ app29.route("/api/v1/minds", logs_default);
6054
+ app29.route("/api/v1/system", system_default);
6055
+ app29.route("/api/v1/system", update_default);
6056
+ app29.route("/api/v1/prompts", prompts_default);
6057
+ app29.route("/api/v1/skills", skills_default);
6058
+ app29.route("/api/v1/env", sharedEnvApp);
6059
+ app29.route("/api/v1/channels", channels_default2);
6060
+ var app_default = app29;
5848
6061
 
5849
6062
  // src/web/server.ts
5850
- var MIME_TYPES2 = {
6063
+ var MIME_TYPES3 = {
5851
6064
  ".html": "text/html",
5852
6065
  ".js": "application/javascript",
5853
6066
  ".css": "text/css",
@@ -5864,7 +6077,7 @@ async function startServer({
5864
6077
  let assetsDir = "";
5865
6078
  let searchDir = dirname(new URL(import.meta.url).pathname);
5866
6079
  for (let i = 0; i < 5; i++) {
5867
- const candidate = resolve17(searchDir, "dist", "web-assets");
6080
+ const candidate = resolve18(searchDir, "dist", "web-assets");
5868
6081
  if (existsSync13(candidate)) {
5869
6082
  assetsDir = candidate;
5870
6083
  break;
@@ -5875,19 +6088,19 @@ async function startServer({
5875
6088
  app_default.get("*", async (c) => {
5876
6089
  const urlPath = new URL(c.req.url).pathname;
5877
6090
  if (urlPath.startsWith("/api/")) return c.notFound();
5878
- const filePath = resolve17(assetsDir, urlPath.slice(1));
6091
+ const filePath = resolve18(assetsDir, urlPath.slice(1));
5879
6092
  if (!filePath.startsWith(assetsDir)) return c.text("Forbidden", 403);
5880
- const s = await stat3(filePath).catch(() => null);
6093
+ const s = await stat4(filePath).catch(() => null);
5881
6094
  if (s?.isFile()) {
5882
- const ext = extname4(filePath);
5883
- const mime = MIME_TYPES2[ext] || "application/octet-stream";
5884
- const body = await readFile3(filePath);
6095
+ const ext = extname5(filePath);
6096
+ const mime = MIME_TYPES3[ext] || "application/octet-stream";
6097
+ const body = await readFile4(filePath);
5885
6098
  return c.body(body, 200, { "Content-Type": mime });
5886
6099
  }
5887
- const indexPath = resolve17(assetsDir, "index.html");
5888
- const indexStat = await stat3(indexPath).catch(() => null);
6100
+ const indexPath = resolve18(assetsDir, "index.html");
6101
+ const indexStat = await stat4(indexPath).catch(() => null);
5889
6102
  if (indexStat?.isFile()) {
5890
- const body = await readFile3(indexPath, "utf-8");
6103
+ const body = await readFile4(indexPath, "utf-8");
5891
6104
  return c.html(body);
5892
6105
  }
5893
6106
  return c.text("Not found", 404);
@@ -5901,10 +6114,10 @@ async function startServer({
5901
6114
  createServer: createHttpsServer,
5902
6115
  serverOptions: { key: tls.key, cert: tls.cert }
5903
6116
  });
5904
- await new Promise((resolve19, reject) => {
6117
+ await new Promise((resolve20, reject) => {
5905
6118
  server2.on("listening", () => {
5906
6119
  logger_default.info("Volute UI running (https)", { hostname, port });
5907
- resolve19();
6120
+ resolve20();
5908
6121
  });
5909
6122
  server2.on("error", (err) => {
5910
6123
  reject(err);
@@ -5912,13 +6125,13 @@ async function startServer({
5912
6125
  });
5913
6126
  const internalPort = port + 1;
5914
6127
  const internalServer = serve({ fetch: app_default.fetch, port: internalPort, hostname: "127.0.0.1" });
5915
- await new Promise((resolve19, reject) => {
6128
+ await new Promise((resolve20, reject) => {
5916
6129
  internalServer.on("listening", () => {
5917
6130
  logger_default.info("Volute API running (http, internal)", {
5918
6131
  hostname: "127.0.0.1",
5919
6132
  port: internalPort
5920
6133
  });
5921
- resolve19();
6134
+ resolve20();
5922
6135
  });
5923
6136
  internalServer.on("error", (err) => {
5924
6137
  reject(err);
@@ -5927,10 +6140,10 @@ async function startServer({
5927
6140
  return { server: server2, internalPort };
5928
6141
  }
5929
6142
  const server = serve({ fetch: app_default.fetch, port, hostname });
5930
- await new Promise((resolve19, reject) => {
6143
+ await new Promise((resolve20, reject) => {
5931
6144
  server.on("listening", () => {
5932
6145
  logger_default.info("Volute API running (http)", { hostname, port });
5933
- resolve19();
6146
+ resolve20();
5934
6147
  });
5935
6148
  server.on("error", (err) => {
5936
6149
  reject(err);
@@ -5941,7 +6154,7 @@ async function startServer({
5941
6154
 
5942
6155
  // src/daemon.ts
5943
6156
  if (!process.env.VOLUTE_HOME) {
5944
- process.env.VOLUTE_HOME = resolve18(homedir2(), ".volute");
6157
+ process.env.VOLUTE_HOME = resolve19(homedir2(), ".volute");
5945
6158
  }
5946
6159
  if (process.env.VOLUTE_TIMEZONE && !process.env.TZ) {
5947
6160
  process.env.TZ = process.env.VOLUTE_TIMEZONE;
@@ -5951,7 +6164,7 @@ async function startDaemon(opts) {
5951
6164
  const myPid = String(process.pid);
5952
6165
  const home = voluteHome();
5953
6166
  if (!opts.foreground) {
5954
- const rotatingLog = new RotatingLog(resolve18(home, "daemon.log"));
6167
+ const rotatingLog = new RotatingLog(resolve19(home, "daemon.log"));
5955
6168
  logger_default.setOutput((line) => rotatingLog.write(`${line}
5956
6169
  `));
5957
6170
  const write = (...args) => rotatingLog.write(`${format(...args)}
@@ -5961,8 +6174,8 @@ async function startDaemon(opts) {
5961
6174
  console.warn = write;
5962
6175
  console.info = write;
5963
6176
  }
5964
- const DAEMON_PID_PATH = resolve18(home, "daemon.pid");
5965
- const DAEMON_JSON_PATH = resolve18(home, "daemon.json");
6177
+ const DAEMON_PID_PATH = resolve19(home, "daemon.pid");
6178
+ const DAEMON_JSON_PATH = resolve19(home, "daemon.json");
5966
6179
  mkdirSync9(home, { recursive: true });
5967
6180
  migrateAgentsToMinds();
5968
6181
  try {
@@ -6021,11 +6234,12 @@ async function startDaemon(opts) {
6021
6234
  const unsubscribeWebhook = initWebhook();
6022
6235
  const registry = readRegistry();
6023
6236
  for (const entry of registry) {
6024
- try {
6025
- migrateDotVoluteDir(entry.name);
6026
- migrateMindState(entry.name);
6027
- } catch (err) {
6028
- logger_default.warn(`failed to migrate state for ${entry.name}`, logger_default.errorData(err));
6237
+ for (const migrate of [migrateDotVoluteDir, migrateMindState, migratePagesDirToPublic]) {
6238
+ try {
6239
+ migrate(entry.name);
6240
+ } catch (err) {
6241
+ logger_default.warn(`failed to migrate state for ${entry.name}`, logger_default.errorData(err));
6242
+ }
6029
6243
  }
6030
6244
  }
6031
6245
  const runningEntries = registry.filter((e) => e.running);
@@ -6075,7 +6289,7 @@ async function startDaemon(opts) {
6075
6289
  });
6076
6290
  await Promise.all(workers);
6077
6291
  }
6078
- import("./cloud-sync-DIU3OCPV.js").then(
6292
+ import("./cloud-sync-PPBBJDY6.js").then(
6079
6293
  ({ consumeQueuedMessages }) => consumeQueuedMessages().catch((err) => {
6080
6294
  logger_default.warn("failed to consume queued cloud messages", logger_default.errorData(err));
6081
6295
  })
@@ -6083,7 +6297,7 @@ async function startDaemon(opts) {
6083
6297
  logger_default.warn("failed to load cloud-sync module", logger_default.errorData(err));
6084
6298
  });
6085
6299
  try {
6086
- const { backfillTemplateHashes, notifyVersionUpdate } = await import("./version-notify-SZ75QRGO.js");
6300
+ const { backfillTemplateHashes, notifyVersionUpdate } = await import("./version-notify-AZQMC32A.js");
6087
6301
  backfillTemplateHashes();
6088
6302
  notifyVersionUpdate().catch((err) => {
6089
6303
  logger_default.warn("failed to send version update notifications", logger_default.errorData(err));