volute 0.21.0 → 0.23.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 (58) hide show
  1. package/dist/api.d.ts +4294 -0
  2. package/dist/chunk-G5KRTU2F.js +76 -0
  3. package/dist/chunk-ISWZ6QUK.js +2691 -0
  4. package/dist/{chunk-J5A3DF2U.js → chunk-JG4CCJOA.js} +1 -1
  5. package/dist/{chunk-IPJXU366.js → chunk-JTDFJWI2.js} +1 -0
  6. package/dist/{chunk-7LPTHFIL.js → chunk-M5CNKH4J.js} +55 -5
  7. package/dist/{chunk-L3LHXZD7.js → chunk-PHHKNGA3.js} +1 -1
  8. package/dist/{chunk-Q7AITQ44.js → chunk-QIXPN3OO.js} +1 -1
  9. package/dist/{chunk-PC6R6UUW.js → chunk-RK627D57.js} +36 -59
  10. package/dist/{chunk-5462YKWP.js → chunk-TFS25FIM.js} +1 -1
  11. package/dist/{chunk-QUJUKM4U.js → chunk-VT5QODNE.js} +1 -1
  12. package/dist/chunk-XLC342FO.js +29 -0
  13. package/dist/cli.js +10 -10
  14. package/dist/cloud-sync-PI47U2LT.js +96 -0
  15. package/dist/{daemon-restart-BH67ZOTE.js → daemon-restart-RMGOOGPE.js} +4 -4
  16. package/dist/daemon.js +1216 -1822
  17. package/dist/{down-LIOQ5JDH.js → down-WSUASL5E.js} +3 -3
  18. package/dist/{import-E433B4KG.js → import-EAXTHHXL.js} +2 -1
  19. package/dist/message-delivery-FHV4NO2F.js +23 -0
  20. package/dist/{mind-BIDOF65R.js → mind-BTXR5B3C.js} +13 -5
  21. package/dist/{mind-manager-3V2NXX4I.js → mind-manager-KMY4GA2J.js} +1 -1
  22. package/dist/mind-sleep-FWRBIFBS.js +41 -0
  23. package/dist/mind-wake-LJK2YU5X.js +36 -0
  24. package/dist/{package-HQR52XSG.js → package-CUBJ4PKS.js} +10 -1
  25. package/dist/{pages-KQBR5TAZ.js → pages-YSTRWJR4.js} +1 -1
  26. package/dist/{publish-OJ4QMXVZ.js → publish-BZNHKUUK.js} +2 -2
  27. package/dist/{service-TVNEORO7.js → service-7BFXDI6J.js} +4 -4
  28. package/dist/{setup-OZDYCKDI.js → setup-SSIIXQMI.js} +2 -2
  29. package/dist/sleep-manager-2TMQ65E4.js +27 -0
  30. package/dist/{sprout-6Z6C42YM.js → sprout-UKCYBGHK.js} +2 -2
  31. package/dist/{status-Z7NAFMBI.js → status-H2MKDN6L.js} +2 -2
  32. package/dist/{up-7BGDMFRT.js → up-Z5JRG2M2.js} +3 -3
  33. package/dist/{update-4WT7VWHW.js → update-ELC6MEUT.js} +2 -2
  34. package/dist/{upgrade-ZEC2GGFO.js → upgrade-GXW2EQY3.js} +11 -2
  35. package/dist/{version-notify-TFS2U5CF.js → version-notify-LKABEJSA.js} +11 -3
  36. package/dist/web-assets/assets/index-CZ26vsyY.js +69 -0
  37. package/dist/web-assets/assets/index-DyyAvJwW.css +1 -0
  38. package/dist/web-assets/index.html +2 -2
  39. package/package.json +10 -1
  40. package/templates/_base/.init/.config/prompts.json +1 -0
  41. package/templates/_base/home/.config/config.json.tmpl +4 -1
  42. package/templates/_base/src/lib/file-handler.ts +6 -1
  43. package/templates/_base/src/lib/logger.ts +68 -23
  44. package/templates/_base/src/lib/startup.ts +12 -3
  45. package/templates/claude/src/agent.ts +150 -29
  46. package/templates/claude/src/lib/hooks/pre-compact.ts +18 -4
  47. package/templates/claude/src/lib/message-channel.ts +6 -0
  48. package/templates/claude/src/lib/stream-consumer.ts +17 -1
  49. package/templates/claude/src/server.ts +3 -1
  50. package/templates/pi/home/.config/config.json.tmpl +4 -1
  51. package/templates/pi/src/agent.ts +87 -0
  52. package/templates/pi/src/lib/content.ts +18 -3
  53. package/templates/pi/src/lib/event-handler.ts +22 -2
  54. package/templates/pi/src/server.ts +3 -1
  55. package/dist/chunk-OGZYB5GL.js +0 -847
  56. package/dist/web-assets/assets/index-BR3gtK3E.css +0 -1
  57. package/dist/web-assets/assets/index-CWmrZRQd.js +0 -64
  58. /package/dist/{shared-DCQ2UXOM.js → shared-2OGT3NSL.js} +0 -0
@@ -4,7 +4,7 @@ import {
4
4
  modeLabel,
5
5
  pollHealth,
6
6
  startService
7
- } from "./chunk-QUJUKM4U.js";
7
+ } from "./chunk-VT5QODNE.js";
8
8
  import {
9
9
  parseArgs
10
10
  } from "./chunk-D424ZQGI.js";
@@ -15,6 +15,7 @@ function exec(cmd, args, options) {
15
15
  (err, stdout, stderr) => {
16
16
  if (err) {
17
17
  err.stderr = stderr;
18
+ err.stdout = stdout;
18
19
  reject(err);
19
20
  } else {
20
21
  resolve(stdout);
@@ -4,6 +4,7 @@ import {
4
4
  } from "./chunk-PHU4DEAJ.js";
5
5
  import {
6
6
  getDb,
7
+ mindHistory,
7
8
  systemPrompts
8
9
  } from "./chunk-SGPEZ32F.js";
9
10
  import {
@@ -77,8 +78,12 @@ var PROMPT_KEYS = [
77
78
  "restart_message",
78
79
  "merge_message",
79
80
  "compaction_warning",
81
+ "compaction_instructions",
80
82
  "reply_instructions",
81
- "channel_invite"
83
+ "channel_invite",
84
+ "pre_sleep",
85
+ "wake_summary",
86
+ "wake_trigger_summary"
82
87
  ];
83
88
  var PROMPT_DEFAULTS = {
84
89
  seed_soul: {
@@ -129,6 +134,12 @@ Have a conversation with the human. Explore what kind of mind you want to be. Wh
129
134
  variables: ["date"],
130
135
  category: "mind"
131
136
  },
137
+ compaction_instructions: {
138
+ content: "Preserve your sense of who you are, what matters to you, what happened in this conversation, and the threads of thought and connection you'd want to return to.",
139
+ description: "Custom instructions for the compaction summarizer",
140
+ variables: [],
141
+ category: "mind"
142
+ },
132
143
  reply_instructions: {
133
144
  content: 'To reply to this message, use: volute send ${channel} "your message"',
134
145
  description: "First-message reply hint injected via hook",
@@ -160,6 +171,24 @@ To reject, delete \${filePath}`,
160
171
  "batchRecommendation"
161
172
  ],
162
173
  category: "mind"
174
+ },
175
+ pre_sleep: {
176
+ content: "It's time to sleep. Save anything important to memory or your journal before resting.\nYou'll wake at ${wakeTime}. ${queuedInfo}",
177
+ description: "Pre-sleep message sent before stopping the mind",
178
+ variables: ["wakeTime", "queuedInfo"],
179
+ category: "system"
180
+ },
181
+ wake_summary: {
182
+ content: "Good morning \u2014 it's ${currentDate}. You slept from ${sleepTime} to now (${duration}).\n${queuedSummary}",
183
+ description: "Wake-up summary after scheduled sleep",
184
+ variables: ["currentDate", "sleepTime", "duration", "queuedSummary"],
185
+ category: "system"
186
+ },
187
+ wake_trigger_summary: {
188
+ content: "You were woken at ${currentDate} by a message on ${triggerChannel}.\nYou've been sleeping since ${sleepTime} (${duration}). ${queuedSummary}\nYou'll go back to sleep after handling this.",
189
+ description: "Wake-up summary when woken by a trigger message",
190
+ variables: ["currentDate", "triggerChannel", "sleepTime", "duration", "queuedSummary"],
191
+ category: "system"
163
192
  }
164
193
  };
165
194
  function isValidKey(key) {
@@ -488,12 +517,24 @@ var MindManager = class {
488
517
  if (context.summary) parts.push(`Changes: ${context.summary}`);
489
518
  if (context.justification) parts.push(`Why: ${context.justification}`);
490
519
  if (context.memory) parts.push(`Context: ${context.memory}`);
520
+ const content = parts.join("\n");
521
+ try {
522
+ const db = await getDb();
523
+ await db.insert(mindHistory).values({
524
+ mind: name,
525
+ type: "inbound",
526
+ channel: "system",
527
+ content
528
+ });
529
+ } catch (err) {
530
+ mlog.error(`failed to persist pending context for ${name}`, logger_default.errorData(err));
531
+ }
491
532
  try {
492
533
  await fetch(`http://127.0.0.1:${tracked.port}/message`, {
493
534
  method: "POST",
494
535
  headers: { "Content-Type": "application/json" },
495
536
  body: JSON.stringify({
496
- content: [{ type: "text", text: parts.join("\n") }],
537
+ content: [{ type: "text", text: content }],
497
538
  channel: "system"
498
539
  })
499
540
  });
@@ -506,6 +547,15 @@ var MindManager = class {
506
547
  this.minds.delete(name);
507
548
  if (this.shuttingDown || this.stopping.has(name)) return;
508
549
  mlog.error(`mind ${name} exited with code ${code}`);
550
+ try {
551
+ const { getSleepManagerIfReady } = await import("./sleep-manager-2TMQ65E4.js");
552
+ if (getSleepManagerIfReady()?.isSleeping(name)) {
553
+ mlog.info(`${name} is sleeping \u2014 skipping crash recovery`);
554
+ return;
555
+ }
556
+ } catch (err) {
557
+ mlog.warn(`failed to check sleep state for ${name}`, logger_default.errorData(err));
558
+ }
509
559
  import("./mind-activity-tracker-PGC3DBJ7.js").then(({ markIdle }) => markIdle(name)).catch((err) => mlog.warn(`failed to mark ${name} idle after crash`, logger_default.errorData(err)));
510
560
  import("./activity-events-3WHHCOBB.js").then(
511
561
  ({ publish }) => publish({ type: "mind_stopped", mind: name, summary: `${name} crashed (exit ${code})` })
@@ -637,15 +687,15 @@ function getMindManager() {
637
687
  export {
638
688
  RotatingLog,
639
689
  RestartTracker,
640
- loadJsonMap,
641
- saveJsonMap,
642
- clearJsonMap,
643
690
  PROMPT_KEYS,
644
691
  PROMPT_DEFAULTS,
645
692
  substitute,
646
693
  getPrompt,
647
694
  getPromptIfCustom,
648
695
  getMindPromptDefaults,
696
+ loadJsonMap,
697
+ saveJsonMap,
698
+ clearJsonMap,
649
699
  MindManager,
650
700
  initMindManager,
651
701
  getMindManager
@@ -4,7 +4,7 @@ import {
4
4
  } from "./chunk-YUIHSKR6.js";
5
5
  import {
6
6
  gitExec
7
- } from "./chunk-IPJXU366.js";
7
+ } from "./chunk-JTDFJWI2.js";
8
8
  import {
9
9
  isIsolationEnabled,
10
10
  mindUserName
@@ -5,7 +5,7 @@ import {
5
5
  pollHealthDown,
6
6
  readDaemonConfig,
7
7
  stopService
8
- } from "./chunk-QUJUKM4U.js";
8
+ } from "./chunk-VT5QODNE.js";
9
9
  import {
10
10
  voluteHome
11
11
  } from "./chunk-B2CPS4QU.js";
@@ -1,4 +1,8 @@
1
1
  #!/usr/bin/env node
2
+ import {
3
+ readVoluteConfig,
4
+ writeVoluteConfig
5
+ } from "./chunk-XLC342FO.js";
2
6
  import {
3
7
  mindEnvPath,
4
8
  readEnv,
@@ -11,43 +15,18 @@ import {
11
15
  // src/commands/import.ts
12
16
  import {
13
17
  closeSync,
14
- existsSync as existsSync2,
15
- mkdirSync as mkdirSync2,
18
+ existsSync,
19
+ mkdirSync,
16
20
  openSync,
17
21
  readdirSync,
18
- readFileSync as readFileSync2,
22
+ readFileSync,
19
23
  readSync,
20
24
  rmSync,
21
25
  statSync,
22
- writeFileSync as writeFileSync2
26
+ writeFileSync
23
27
  } from "fs";
24
28
  import { homedir, tmpdir } from "os";
25
- import { basename, resolve as resolve2 } from "path";
26
-
27
- // src/lib/volute-config.ts
28
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
29
- import { dirname, resolve } from "path";
30
- function readJson(path) {
31
- if (!existsSync(path)) return null;
32
- try {
33
- return JSON.parse(readFileSync(path, "utf-8"));
34
- } catch (err) {
35
- console.error(`[volute-config] failed to parse ${path}: ${err}`);
36
- return null;
37
- }
38
- }
39
- function readVoluteConfig(mindDir) {
40
- const path = resolve(mindDir, "home/.config/volute.json");
41
- return readJson(path);
42
- }
43
- function writeVoluteConfig(mindDir, config) {
44
- const path = resolve(mindDir, "home/.config/volute.json");
45
- mkdirSync(dirname(path), { recursive: true });
46
- writeFileSync(path, `${JSON.stringify(config, null, 2)}
47
- `);
48
- }
49
-
50
- // src/commands/import.ts
29
+ import { basename, resolve } from "path";
51
30
  async function run(args) {
52
31
  const { positional, flags } = parseArgs(args, {
53
32
  name: { type: "string" },
@@ -56,7 +35,7 @@ async function run(args) {
56
35
  });
57
36
  const inputPath = positional[0];
58
37
  if (inputPath && (inputPath.endsWith(".volute") || isZipFile(inputPath))) {
59
- await importArchive(resolve2(inputPath), flags.name);
38
+ await importArchive(resolve(inputPath), flags.name);
60
39
  return;
61
40
  }
62
41
  const wsDir = resolveWorkspace(inputPath);
@@ -84,8 +63,8 @@ ${data.message ?? `Imported mind: ${data.name} (port ${data.port})`}`);
84
63
  volute mind start ${data.name}`);
85
64
  }
86
65
  function isZipFile(path) {
87
- const resolved = resolve2(path);
88
- if (!existsSync2(resolved)) return false;
66
+ const resolved = resolve(path);
67
+ if (!existsSync(resolved)) return false;
89
68
  const fd = openSync(resolved, "r");
90
69
  try {
91
70
  const buf = Buffer.alloc(4);
@@ -96,13 +75,13 @@ function isZipFile(path) {
96
75
  }
97
76
  }
98
77
  async function importArchive(archivePath, nameOverride) {
99
- if (!existsSync2(archivePath)) {
78
+ if (!existsSync(archivePath)) {
100
79
  console.error(`File not found: ${archivePath}`);
101
80
  process.exit(1);
102
81
  }
103
82
  const { extractArchive } = await import("./archive-4ZQYK5MN.js");
104
- const tempDir = resolve2(tmpdir(), `volute-import-${Date.now()}`);
105
- mkdirSync2(tempDir, { recursive: true });
83
+ const tempDir = resolve(tmpdir(), `volute-import-${Date.now()}`);
84
+ mkdirSync(tempDir, { recursive: true });
106
85
  let extracted;
107
86
  try {
108
87
  extracted = extractArchive(archivePath, tempDir);
@@ -140,20 +119,20 @@ ${data.message ?? `Imported mind: ${data.name} (port ${data.port})`}`);
140
119
  }
141
120
  function resolveWorkspace(explicitPath) {
142
121
  if (explicitPath) {
143
- const wsDir = resolve2(explicitPath);
144
- if (!existsSync2(resolve2(wsDir, "SOUL.md")) || !existsSync2(resolve2(wsDir, "IDENTITY.md"))) {
122
+ const wsDir = resolve(explicitPath);
123
+ if (!existsSync(resolve(wsDir, "SOUL.md")) || !existsSync(resolve(wsDir, "IDENTITY.md"))) {
145
124
  console.error("Not a valid OpenClaw workspace: missing SOUL.md or IDENTITY.md");
146
125
  process.exit(1);
147
126
  }
148
127
  return wsDir;
149
128
  }
150
129
  const cwd = process.cwd();
151
- if (existsSync2(resolve2(cwd, "SOUL.md")) && existsSync2(resolve2(cwd, "IDENTITY.md"))) {
130
+ if (existsSync(resolve(cwd, "SOUL.md")) && existsSync(resolve(cwd, "IDENTITY.md"))) {
152
131
  console.log(`Using workspace: ${cwd}`);
153
132
  return cwd;
154
133
  }
155
- const openclawWs = resolve2(homedir(), ".openclaw/workspace");
156
- if (existsSync2(resolve2(openclawWs, "SOUL.md")) && existsSync2(resolve2(openclawWs, "IDENTITY.md"))) {
134
+ const openclawWs = resolve(homedir(), ".openclaw/workspace");
135
+ if (existsSync(resolve(openclawWs, "SOUL.md")) && existsSync(resolve(openclawWs, "IDENTITY.md"))) {
157
136
  console.log(`Using workspace: ${openclawWs}`);
158
137
  return openclawWs;
159
138
  }
@@ -163,16 +142,16 @@ function resolveWorkspace(explicitPath) {
163
142
  process.exit(1);
164
143
  }
165
144
  function findOpenClawSession(workspaceDir) {
166
- const ocAgentsDir = resolve2(homedir(), ".openclaw/agents");
167
- if (!existsSync2(ocAgentsDir)) return void 0;
145
+ const ocAgentsDir = resolve(homedir(), ".openclaw/agents");
146
+ if (!existsSync(ocAgentsDir)) return void 0;
168
147
  const matches = [];
169
148
  try {
170
149
  for (const entry of readdirSync(ocAgentsDir)) {
171
- const sessionsDir = resolve2(ocAgentsDir, entry, "sessions");
172
- if (!existsSync2(sessionsDir)) continue;
150
+ const sessionsDir = resolve(ocAgentsDir, entry, "sessions");
151
+ if (!existsSync(sessionsDir)) continue;
173
152
  for (const file of readdirSync(sessionsDir)) {
174
153
  if (!file.endsWith(".jsonl")) continue;
175
- const fullPath = resolve2(sessionsDir, file);
154
+ const fullPath = resolve(sessionsDir, file);
176
155
  if (sessionMatchesWorkspace(fullPath, workspaceDir)) {
177
156
  matches.push({ path: fullPath, mtime: statSync(fullPath).mtimeMs });
178
157
  }
@@ -189,19 +168,19 @@ function findOpenClawSession(workspaceDir) {
189
168
  }
190
169
  function sessionMatchesWorkspace(sessionPath, workspaceDir) {
191
170
  try {
192
- const fd = readFileSync2(sessionPath, "utf-8");
171
+ const fd = readFileSync(sessionPath, "utf-8");
193
172
  const firstLine = fd.slice(0, fd.indexOf("\n"));
194
173
  const header = JSON.parse(firstLine);
195
- return header.type === "session" && resolve2(header.cwd) === resolve2(workspaceDir);
174
+ return header.type === "session" && resolve(header.cwd) === resolve(workspaceDir);
196
175
  } catch {
197
176
  return false;
198
177
  }
199
178
  }
200
179
  function importPiSession(sessionFile, mindDirPath) {
201
- const homeDir = resolve2(mindDirPath, "home");
202
- const piSessionDir = resolve2(mindDirPath, ".mind/pi-sessions/main");
203
- mkdirSync2(piSessionDir, { recursive: true });
204
- const content = readFileSync2(sessionFile, "utf-8");
180
+ const homeDir = resolve(mindDirPath, "home");
181
+ const piSessionDir = resolve(mindDirPath, ".mind/pi-sessions/main");
182
+ mkdirSync(piSessionDir, { recursive: true });
183
+ const content = readFileSync(sessionFile, "utf-8");
205
184
  const lines = content.trim().split("\n");
206
185
  try {
207
186
  const header = JSON.parse(lines[0]);
@@ -212,17 +191,17 @@ function importPiSession(sessionFile, mindDirPath) {
212
191
  } catch {
213
192
  }
214
193
  const filename = basename(sessionFile);
215
- const destPath = resolve2(piSessionDir, filename);
216
- writeFileSync2(destPath, `${lines.join("\n")}
194
+ const destPath = resolve(piSessionDir, filename);
195
+ writeFileSync(destPath, `${lines.join("\n")}
217
196
  `);
218
197
  console.log(`Imported session (${lines.length} entries)`);
219
198
  }
220
199
  function importOpenClawConnectors(name, mindDirPath) {
221
- const configPath = resolve2(homedir(), ".openclaw/openclaw.json");
222
- if (!existsSync2(configPath)) return;
200
+ const configPath = resolve(homedir(), ".openclaw/openclaw.json");
201
+ if (!existsSync(configPath)) return;
223
202
  let config;
224
203
  try {
225
- config = JSON.parse(readFileSync2(configPath, "utf-8"));
204
+ config = JSON.parse(readFileSync(configPath, "utf-8"));
226
205
  } catch (err) {
227
206
  console.warn("Warning: failed to parse openclaw.json:", err);
228
207
  return;
@@ -266,8 +245,6 @@ function parseNameFromIdentity(identity) {
266
245
  }
267
246
 
268
247
  export {
269
- readVoluteConfig,
270
- writeVoluteConfig,
271
248
  run,
272
249
  findOpenClawSession,
273
250
  sessionMatchesWorkspace,
@@ -9,7 +9,7 @@ import {
9
9
  import {
10
10
  exec,
11
11
  gitExec
12
- } from "./chunk-IPJXU366.js";
12
+ } from "./chunk-JTDFJWI2.js";
13
13
  import {
14
14
  voluteHome
15
15
  } from "./chunk-B2CPS4QU.js";
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  execInherit
4
- } from "./chunk-IPJXU366.js";
4
+ } from "./chunk-JTDFJWI2.js";
5
5
  import {
6
6
  voluteHome
7
7
  } from "./chunk-B2CPS4QU.js";
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/lib/volute-config.ts
4
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
5
+ import { dirname, resolve } from "path";
6
+ function readJson(path) {
7
+ if (!existsSync(path)) return null;
8
+ try {
9
+ return JSON.parse(readFileSync(path, "utf-8"));
10
+ } catch (err) {
11
+ console.error(`[volute-config] failed to parse ${path}: ${err}`);
12
+ return null;
13
+ }
14
+ }
15
+ function readVoluteConfig(mindDir) {
16
+ const path = resolve(mindDir, "home/.config/volute.json");
17
+ return readJson(path);
18
+ }
19
+ function writeVoluteConfig(mindDir, config) {
20
+ const path = resolve(mindDir, "home/.config/volute.json");
21
+ mkdirSync(dirname(path), { recursive: true });
22
+ writeFileSync(path, `${JSON.stringify(config, null, 2)}
23
+ `);
24
+ }
25
+
26
+ export {
27
+ readVoluteConfig,
28
+ writeVoluteConfig
29
+ };
package/dist/cli.js CHANGED
@@ -9,13 +9,13 @@ if (!process.env.VOLUTE_HOME) {
9
9
  var command = process.argv[2];
10
10
  var args = process.argv.slice(3);
11
11
  if (command === "--version" || command === "-v") {
12
- const { default: pkg } = await import("./package-HQR52XSG.js");
12
+ const { default: pkg } = await import("./package-CUBJ4PKS.js");
13
13
  console.log(pkg.version);
14
14
  process.exit(0);
15
15
  }
16
16
  switch (command) {
17
17
  case "mind":
18
- await import("./mind-BIDOF65R.js").then((m) => m.run(args));
18
+ await import("./mind-BTXR5B3C.js").then((m) => m.run(args));
19
19
  break;
20
20
  case "send":
21
21
  await import("./send-RP2TA7SG.js").then((m) => m.run(args));
@@ -36,7 +36,7 @@ switch (command) {
36
36
  await import("./skill-Q2Y6PQ3L.js").then((m) => m.run(args));
37
37
  break;
38
38
  case "shared":
39
- await import("./shared-DCQ2UXOM.js").then((m) => m.run(args));
39
+ await import("./shared-2OGT3NSL.js").then((m) => m.run(args));
40
40
  break;
41
41
  case "file":
42
42
  await import("./file-X4L5TTOL.js").then((m) => m.run(args));
@@ -45,25 +45,25 @@ switch (command) {
45
45
  await import("./env-4PHIHTF4.js").then((m) => m.run(args));
46
46
  break;
47
47
  case "up":
48
- await import("./up-7BGDMFRT.js").then((m) => m.run(args));
48
+ await import("./up-Z5JRG2M2.js").then((m) => m.run(args));
49
49
  break;
50
50
  case "down":
51
- await import("./down-LIOQ5JDH.js").then((m) => m.run(args));
51
+ await import("./down-WSUASL5E.js").then((m) => m.run(args));
52
52
  break;
53
53
  case "restart":
54
- await import("./daemon-restart-BH67ZOTE.js").then((m) => m.run(args));
54
+ await import("./daemon-restart-RMGOOGPE.js").then((m) => m.run(args));
55
55
  break;
56
56
  case "service":
57
- await import("./service-TVNEORO7.js").then((m) => m.run(args));
57
+ await import("./service-7BFXDI6J.js").then((m) => m.run(args));
58
58
  break;
59
59
  case "update":
60
- await import("./update-4WT7VWHW.js").then((m) => m.run(args));
60
+ await import("./update-ELC6MEUT.js").then((m) => m.run(args));
61
61
  break;
62
62
  case "status":
63
- await import("./status-Z7NAFMBI.js").then((m) => m.run(args));
63
+ await import("./status-H2MKDN6L.js").then((m) => m.run(args));
64
64
  break;
65
65
  case "pages":
66
- await import("./pages-KQBR5TAZ.js").then((m) => m.run(args));
66
+ await import("./pages-YSTRWJR4.js").then((m) => m.run(args));
67
67
  break;
68
68
  case "auth":
69
69
  await import("./auth-HM2RSPY7.js").then((m) => m.run(args));
@@ -0,0 +1,96 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ getAuthHeaders,
4
+ getWebhookUrl
5
+ } from "./chunk-G5KRTU2F.js";
6
+ import {
7
+ deliverMessage
8
+ } from "./chunk-ISWZ6QUK.js";
9
+ import "./chunk-HFCBO2GL.js";
10
+ import "./chunk-HGCDWKSP.js";
11
+ import "./chunk-A4S7H6G6.js";
12
+ import "./chunk-M5CNKH4J.js";
13
+ import "./chunk-XLC342FO.js";
14
+ import "./chunk-PHU4DEAJ.js";
15
+ import "./chunk-SGPEZ32F.js";
16
+ import {
17
+ logger_default
18
+ } from "./chunk-YUIHSKR6.js";
19
+ import "./chunk-JTDFJWI2.js";
20
+ import "./chunk-NWPT4ASZ.js";
21
+ import "./chunk-B2CPS4QU.js";
22
+ import "./chunk-K3NQKI34.js";
23
+
24
+ // src/lib/cloud-sync.ts
25
+ var slog = logger_default.child("cloud-sync");
26
+ function getQueueUrl() {
27
+ const base = getWebhookUrl();
28
+ if (!base) return void 0;
29
+ return `${base.replace(/\/$/, "")}/queue`;
30
+ }
31
+ async function consumeQueuedMessages() {
32
+ const queueUrl = getQueueUrl();
33
+ if (!queueUrl) return;
34
+ slog.info("checking cloud queue for pending messages");
35
+ let items;
36
+ try {
37
+ const res = await fetch(queueUrl, { headers: getAuthHeaders() });
38
+ if (!res.ok) {
39
+ slog.warn(`cloud queue returned HTTP ${res.status}`);
40
+ return;
41
+ }
42
+ const body = await res.json();
43
+ if (!Array.isArray(body) || body.length === 0) {
44
+ slog.info("no queued cloud messages");
45
+ return;
46
+ }
47
+ items = body;
48
+ } catch (err) {
49
+ slog.warn("failed to fetch cloud queue", logger_default.errorData(err));
50
+ return;
51
+ }
52
+ slog.info(`processing ${items.length} queued cloud message(s)`);
53
+ const acknowledged = [];
54
+ for (const raw of items) {
55
+ const msg = raw;
56
+ if (!msg.id || typeof msg.id !== "string" || !msg.mind || typeof msg.mind !== "string" || !msg.channel || typeof msg.channel !== "string") {
57
+ slog.warn("skipping malformed queued message", { msg: JSON.stringify(msg).slice(0, 200) });
58
+ continue;
59
+ }
60
+ try {
61
+ await deliverMessage(msg.mind, {
62
+ channel: msg.channel,
63
+ sender: msg.sender ?? null,
64
+ content: msg.content,
65
+ conversationId: msg.conversationId
66
+ });
67
+ acknowledged.push(msg.id);
68
+ } catch (err) {
69
+ slog.warn(`failed to process queued message ${msg.id}`, logger_default.errorData(err));
70
+ }
71
+ }
72
+ if (acknowledged.length > 0) {
73
+ try {
74
+ const res = await fetch(queueUrl, {
75
+ method: "DELETE",
76
+ headers: getAuthHeaders(),
77
+ body: JSON.stringify({ ids: acknowledged })
78
+ });
79
+ if (!res.ok) {
80
+ slog.error(
81
+ `failed to acknowledge ${acknowledged.length} queued messages (HTTP ${res.status}) \u2014 these will be re-delivered on next startup`
82
+ );
83
+ } else {
84
+ slog.info(`acknowledged ${acknowledged.length} queued message(s)`);
85
+ }
86
+ } catch (err) {
87
+ slog.error(
88
+ `failed to acknowledge ${acknowledged.length} queued messages \u2014 these will be re-delivered on next startup`,
89
+ logger_default.errorData(err)
90
+ );
91
+ }
92
+ }
93
+ }
94
+ export {
95
+ consumeQueuedMessages
96
+ };
@@ -1,19 +1,19 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  run
4
- } from "./chunk-J5A3DF2U.js";
4
+ } from "./chunk-JG4CCJOA.js";
5
5
  import {
6
6
  stopDaemon
7
- } from "./chunk-Q7AITQ44.js";
7
+ } from "./chunk-QIXPN3OO.js";
8
8
  import {
9
9
  getServiceMode,
10
10
  modeLabel,
11
11
  pollHealth,
12
12
  readDaemonConfig,
13
13
  restartService
14
- } from "./chunk-QUJUKM4U.js";
14
+ } from "./chunk-VT5QODNE.js";
15
15
  import "./chunk-D424ZQGI.js";
16
- import "./chunk-IPJXU366.js";
16
+ import "./chunk-JTDFJWI2.js";
17
17
  import "./chunk-NWPT4ASZ.js";
18
18
  import "./chunk-B2CPS4QU.js";
19
19
  import "./chunk-K3NQKI34.js";