volute 0.28.0 → 0.29.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.
- package/README.md +15 -5
- package/dist/api.d.ts +192 -9
- package/dist/{chat-M4SX42JD.js → chat-KTPOR2JT.js} +1 -1
- package/dist/chunk-A6TUJJ3L.js +19 -0
- package/dist/{chunk-AAPXKR5V.js → chunk-CMILSHZD.js} +138 -285
- package/dist/{chunk-K5NAC55T.js → chunk-CQ7SNKNI.js} +1 -1
- package/dist/{chunk-POSXWWTA.js → chunk-EHZKEMMV.js} +4 -4
- package/dist/{chunk-IAYBDWVG.js → chunk-FLZGS4QH.js} +145 -0
- package/dist/chunk-THUUIU3E.js +232 -0
- package/dist/cli.js +11 -8
- package/dist/clock-DGCBVGYA.js +259 -0
- package/dist/{cloud-sync-HDL6PHZI.js → cloud-sync-KILFGV5Q.js} +6 -5
- package/dist/connectors/discord-bridge.js +1 -1
- package/dist/connectors/slack-bridge.js +1 -1
- package/dist/connectors/telegram-bridge.js +1 -1
- package/dist/{conversations-M2K4253F.js → conversations-P5BL7RMX.js} +7 -1
- package/dist/create-DFCAGEE5.js +70 -0
- package/dist/{daemon-restart-G4B2OYAB.js → daemon-restart-UHOMICXT.js} +1 -1
- package/dist/daemon.js +181 -66
- package/dist/{message-delivery-HV3S6HZV.js → message-delivery-Q7VUMIEI.js} +10 -7
- package/dist/{mind-activity-tracker-EN6XNXPF.js → mind-activity-tracker-WRHFI3YW.js} +1 -1
- package/dist/{mind-manager-S6ILZVX3.js → mind-manager-P66HQDNE.js} +1 -1
- package/dist/{package-CG4RWUGP.js → package-OFKXNKJF.js} +1 -1
- package/dist/pages-watcher-P7QECRE2.js +21 -0
- package/dist/skills/dreaming/references/INSTALL.md +3 -17
- package/dist/skills/volute-mind/SKILL.md +43 -16
- package/dist/{sleep-manager-WMVG2VCL.js → sleep-manager-G4B5GW5P.js} +6 -5
- package/dist/{up-GM2JOH2Y.js → up-W6VAK2XE.js} +1 -1
- package/dist/{version-notify-JDUF4HQJ.js → version-notify-WDHRO3XD.js} +8 -7
- package/dist/web-assets/assets/index-BmKDnWDB.css +1 -0
- package/dist/web-assets/assets/index-CLJMx-GA.js +71 -0
- package/dist/web-assets/index.html +2 -2
- package/package.json +1 -1
- package/templates/_base/src/lib/logger.ts +10 -49
- package/templates/_base/src/lib/router.ts +1 -9
- package/templates/claude/src/lib/stream-consumer.ts +1 -4
- package/templates/pi/src/lib/event-handler.ts +1 -14
- package/dist/chunk-T6HKBWXZ.js +0 -23
- package/dist/create-D7J73A6H.js +0 -45
- package/dist/schedule-QTJMFATP.js +0 -154
- package/dist/web-assets/assets/index-BZGvToHi.css +0 -1
- package/dist/web-assets/assets/index-Cz4TrpzB.js +0 -75
- /package/dist/{chunk-SGVNFZHW.js → chunk-DUAUMCEE.js} +0 -0
- /package/dist/{pages-KJDJX4TA.js → pages-EUJR52AH.js} +0 -0
package/dist/daemon.js
CHANGED
|
@@ -5,19 +5,6 @@ import {
|
|
|
5
5
|
removeSharedWorktree,
|
|
6
6
|
sharedMerge
|
|
7
7
|
} from "./chunk-P72MVS4R.js";
|
|
8
|
-
import {
|
|
9
|
-
checkForUpdate,
|
|
10
|
-
checkForUpdateCached,
|
|
11
|
-
getCurrentVersion
|
|
12
|
-
} from "./chunk-HDN7MNGD.js";
|
|
13
|
-
import {
|
|
14
|
-
applyInitFiles,
|
|
15
|
-
composeTemplate,
|
|
16
|
-
computeTemplateHash,
|
|
17
|
-
copyTemplateToDir,
|
|
18
|
-
findTemplatesRoot,
|
|
19
|
-
listFiles
|
|
20
|
-
} from "./chunk-AKPFNL7L.js";
|
|
21
8
|
import {
|
|
22
9
|
announceToSystem,
|
|
23
10
|
approveUser,
|
|
@@ -30,11 +17,10 @@ import {
|
|
|
30
17
|
deliverMessage,
|
|
31
18
|
ensureSystemChannel,
|
|
32
19
|
extractTextContent,
|
|
33
|
-
getCachedRecentPages,
|
|
34
|
-
getCachedSites,
|
|
35
20
|
getDeliveryManager,
|
|
36
21
|
getOrCreateMindUser,
|
|
37
22
|
getScheduler,
|
|
23
|
+
getSleepManagerIfReady,
|
|
38
24
|
getTokenBudget,
|
|
39
25
|
getTypingMap,
|
|
40
26
|
getUser,
|
|
@@ -58,7 +44,6 @@ import {
|
|
|
58
44
|
setUserRole,
|
|
59
45
|
splitMessage,
|
|
60
46
|
startMindFull,
|
|
61
|
-
stopAllWatchers,
|
|
62
47
|
stopMindFull,
|
|
63
48
|
subscribe as subscribe3,
|
|
64
49
|
updateUserProfile,
|
|
@@ -66,7 +51,12 @@ import {
|
|
|
66
51
|
writeChannelEntry,
|
|
67
52
|
writeSystemsConfig,
|
|
68
53
|
writeVoluteConfig
|
|
69
|
-
} from "./chunk-
|
|
54
|
+
} from "./chunk-CMILSHZD.js";
|
|
55
|
+
import {
|
|
56
|
+
getCachedRecentPages,
|
|
57
|
+
getCachedSites,
|
|
58
|
+
stopAllWatchers
|
|
59
|
+
} from "./chunk-THUUIU3E.js";
|
|
70
60
|
import {
|
|
71
61
|
addMessage,
|
|
72
62
|
createChannel,
|
|
@@ -81,22 +71,37 @@ import {
|
|
|
81
71
|
getParticipants,
|
|
82
72
|
getUnreadCounts,
|
|
83
73
|
initWebhook,
|
|
74
|
+
isConversationForMind,
|
|
84
75
|
isParticipant,
|
|
85
76
|
isParticipantOrOwner,
|
|
86
77
|
joinChannel,
|
|
87
78
|
leaveChannel,
|
|
88
79
|
listChannels,
|
|
80
|
+
listConversationsForMind,
|
|
89
81
|
listConversationsForUser,
|
|
90
82
|
listConversationsWithParticipants,
|
|
91
83
|
markConversationRead,
|
|
92
84
|
publish,
|
|
93
85
|
subscribe as subscribe2
|
|
94
|
-
} from "./chunk-
|
|
86
|
+
} from "./chunk-FLZGS4QH.js";
|
|
87
|
+
import {
|
|
88
|
+
checkForUpdate,
|
|
89
|
+
checkForUpdateCached,
|
|
90
|
+
getCurrentVersion
|
|
91
|
+
} from "./chunk-HDN7MNGD.js";
|
|
92
|
+
import {
|
|
93
|
+
applyInitFiles,
|
|
94
|
+
composeTemplate,
|
|
95
|
+
computeTemplateHash,
|
|
96
|
+
copyTemplateToDir,
|
|
97
|
+
findTemplatesRoot,
|
|
98
|
+
listFiles
|
|
99
|
+
} from "./chunk-AKPFNL7L.js";
|
|
95
100
|
import {
|
|
96
101
|
getActiveMinds,
|
|
97
102
|
onMindEvent,
|
|
98
103
|
stopAll
|
|
99
|
-
} from "./chunk-
|
|
104
|
+
} from "./chunk-CQ7SNKNI.js";
|
|
100
105
|
import {
|
|
101
106
|
broadcast,
|
|
102
107
|
subscribe
|
|
@@ -113,7 +118,7 @@ import {
|
|
|
113
118
|
initMindManager,
|
|
114
119
|
resolveMindToken,
|
|
115
120
|
substitute
|
|
116
|
-
} from "./chunk-
|
|
121
|
+
} from "./chunk-EHZKEMMV.js";
|
|
117
122
|
import "./chunk-J4IBNXGJ.js";
|
|
118
123
|
import {
|
|
119
124
|
SEED_SKILLS,
|
|
@@ -185,7 +190,7 @@ import "./chunk-D424ZQGI.js";
|
|
|
185
190
|
import {
|
|
186
191
|
buildVoluteSlug,
|
|
187
192
|
slugify
|
|
188
|
-
} from "./chunk-
|
|
193
|
+
} from "./chunk-A6TUJJ3L.js";
|
|
189
194
|
import {
|
|
190
195
|
activity,
|
|
191
196
|
addMind,
|
|
@@ -1409,7 +1414,7 @@ var app3 = new Hono3().post("/:platform/inbound", zValidator2("json", inboundSch
|
|
|
1409
1414
|
}
|
|
1410
1415
|
const participants = await getParticipants(channel.id);
|
|
1411
1416
|
if (!participants.some((p) => p.userId === puppet.id)) {
|
|
1412
|
-
const { addParticipant } = await import("./conversations-
|
|
1417
|
+
const { addParticipant } = await import("./conversations-P5BL7RMX.js");
|
|
1413
1418
|
await addParticipant(channel.id, puppet.id);
|
|
1414
1419
|
}
|
|
1415
1420
|
const contentBlocks = body.content;
|
|
@@ -1502,10 +1507,10 @@ async function fanOutToBridgedMinds(opts) {
|
|
|
1502
1507
|
const participants = await getParticipants(opts.conversationId);
|
|
1503
1508
|
const mindParticipants = participants.filter((p) => p.userType === "mind");
|
|
1504
1509
|
const participantNames = participants.map((p) => p.username);
|
|
1505
|
-
const { getMindManager: getMindManager2 } = await import("./mind-manager-
|
|
1506
|
-
const { getSleepManagerIfReady } = await import("./sleep-manager-
|
|
1510
|
+
const { getMindManager: getMindManager2 } = await import("./mind-manager-P66HQDNE.js");
|
|
1511
|
+
const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-G4B5GW5P.js");
|
|
1507
1512
|
const manager = getMindManager2();
|
|
1508
|
-
const sm =
|
|
1513
|
+
const sm = getSleepManagerIfReady2();
|
|
1509
1514
|
const targetMinds = mindParticipants.filter((ap) => {
|
|
1510
1515
|
return (manager.isRunning(ap.username) || sm?.isSleeping(ap.username)) && ap.username !== opts.senderName;
|
|
1511
1516
|
}).map((ap) => ap.username);
|
|
@@ -1520,7 +1525,7 @@ async function fanOutToBridgedMinds(opts) {
|
|
|
1520
1525
|
writeChannelEntry(mindName, channel, {
|
|
1521
1526
|
platformId: opts.conversationId,
|
|
1522
1527
|
platform: "volute",
|
|
1523
|
-
type: opts.isDM ? "dm" : "
|
|
1528
|
+
type: opts.isDM ? "dm" : "channel"
|
|
1524
1529
|
});
|
|
1525
1530
|
} catch (err) {
|
|
1526
1531
|
logger_default.warn(`failed to write channel entry for ${mindName}`, logger_default.errorData(err));
|
|
@@ -1648,7 +1653,7 @@ async function listConversations(env) {
|
|
|
1648
1653
|
id: slug,
|
|
1649
1654
|
platformId: dm.id,
|
|
1650
1655
|
name: recipients.join(", ") || "DM",
|
|
1651
|
-
type: dm.type === 1 ? "dm" : "
|
|
1656
|
+
type: dm.type === 1 ? "dm" : "channel"
|
|
1652
1657
|
});
|
|
1653
1658
|
}
|
|
1654
1659
|
return results;
|
|
@@ -1818,7 +1823,6 @@ async function listConversations2(env) {
|
|
|
1818
1823
|
return data.channels.map((ch) => {
|
|
1819
1824
|
let type = "channel";
|
|
1820
1825
|
if (ch.is_im) type = "dm";
|
|
1821
|
-
else if (ch.is_mpim) type = "group";
|
|
1822
1826
|
let slug;
|
|
1823
1827
|
let name;
|
|
1824
1828
|
if (ch.is_im && ch.user) {
|
|
@@ -1895,7 +1899,7 @@ async function createConversation3(env, participants, name) {
|
|
|
1895
1899
|
platformId,
|
|
1896
1900
|
platform: "slack",
|
|
1897
1901
|
name: participants.join(", "),
|
|
1898
|
-
type: participants.length === 1 ? "dm" : "
|
|
1902
|
+
type: participants.length === 1 ? "dm" : "channel"
|
|
1899
1903
|
});
|
|
1900
1904
|
}
|
|
1901
1905
|
return slug;
|
|
@@ -2111,7 +2115,7 @@ async function listConversations4(env) {
|
|
|
2111
2115
|
convType: conv.type,
|
|
2112
2116
|
convName: conv.name
|
|
2113
2117
|
});
|
|
2114
|
-
const convType = conv.type === "channel" ? "channel" :
|
|
2118
|
+
const convType = conv.type === "channel" ? "channel" : "dm";
|
|
2115
2119
|
results.push({
|
|
2116
2120
|
id: slug,
|
|
2117
2121
|
platformId: conv.id,
|
|
@@ -3193,8 +3197,8 @@ async function getMindStatus(name, port) {
|
|
|
3193
3197
|
const manager = getMindManager();
|
|
3194
3198
|
let status = "stopped";
|
|
3195
3199
|
try {
|
|
3196
|
-
const { getSleepManagerIfReady } = await import("./sleep-manager-
|
|
3197
|
-
if (
|
|
3200
|
+
const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-G4B5GW5P.js");
|
|
3201
|
+
if (getSleepManagerIfReady2()?.isSleeping(name)) {
|
|
3198
3202
|
status = "sleeping";
|
|
3199
3203
|
}
|
|
3200
3204
|
} catch {
|
|
@@ -3925,8 +3929,8 @@ ${user.trimEnd()}
|
|
|
3925
3929
|
const manager = getMindManager();
|
|
3926
3930
|
try {
|
|
3927
3931
|
if (context?.type === "reload") {
|
|
3928
|
-
const { getSleepManagerIfReady } = await import("./sleep-manager-
|
|
3929
|
-
const sleepState =
|
|
3932
|
+
const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-G4B5GW5P.js");
|
|
3933
|
+
const sleepState = getSleepManagerIfReady2()?.getState(name);
|
|
3930
3934
|
if (sleepState?.sleeping) {
|
|
3931
3935
|
logger_default.info(`skipping reload for ${name} during sleep \u2014 will apply on next wake`);
|
|
3932
3936
|
return c.json({ ok: true, deferred: true, port: targetPort });
|
|
@@ -4020,16 +4024,16 @@ ${user.trimEnd()}
|
|
|
4020
4024
|
const name = c.req.param("name");
|
|
4021
4025
|
const entry = await findMind(name);
|
|
4022
4026
|
if (!entry) return c.json({ error: "Mind not found" }, 404);
|
|
4023
|
-
const { getSleepManagerIfReady } = await import("./sleep-manager-
|
|
4024
|
-
const sm =
|
|
4027
|
+
const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-G4B5GW5P.js");
|
|
4028
|
+
const sm = getSleepManagerIfReady2();
|
|
4025
4029
|
if (!sm) return c.json({ error: "Sleep manager not initialized" }, 503);
|
|
4026
4030
|
return c.json(sm.getState(name));
|
|
4027
4031
|
}).post("/:name/sleep", requireSelf(), async (c) => {
|
|
4028
4032
|
const name = c.req.param("name");
|
|
4029
4033
|
const entry = await findMind(name);
|
|
4030
4034
|
if (!entry) return c.json({ error: "Mind not found" }, 404);
|
|
4031
|
-
const { getSleepManagerIfReady } = await import("./sleep-manager-
|
|
4032
|
-
const sm =
|
|
4035
|
+
const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-G4B5GW5P.js");
|
|
4036
|
+
const sm = getSleepManagerIfReady2();
|
|
4033
4037
|
if (!sm) return c.json({ error: "Sleep manager not initialized" }, 503);
|
|
4034
4038
|
if (sm.isSleeping(name)) return c.json({ error: "Mind is already sleeping" }, 409);
|
|
4035
4039
|
const body = await c.req.json().catch(() => ({}));
|
|
@@ -4048,8 +4052,8 @@ ${user.trimEnd()}
|
|
|
4048
4052
|
const name = c.req.param("name");
|
|
4049
4053
|
const entry = await findMind(name);
|
|
4050
4054
|
if (!entry) return c.json({ error: "Mind not found" }, 404);
|
|
4051
|
-
const { getSleepManagerIfReady } = await import("./sleep-manager-
|
|
4052
|
-
const sm =
|
|
4055
|
+
const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-G4B5GW5P.js");
|
|
4056
|
+
const sm = getSleepManagerIfReady2();
|
|
4053
4057
|
if (!sm) return c.json({ error: "Sleep manager not initialized" }, 503);
|
|
4054
4058
|
const sleepState = sm.getState(name);
|
|
4055
4059
|
if (!sleepState.sleeping) return c.json({ error: "Mind is not sleeping" }, 409);
|
|
@@ -4063,8 +4067,8 @@ ${user.trimEnd()}
|
|
|
4063
4067
|
const name = c.req.param("name");
|
|
4064
4068
|
const entry = await findMind(name);
|
|
4065
4069
|
if (!entry) return c.json({ error: "Mind not found" }, 404);
|
|
4066
|
-
const { getSleepManagerIfReady } = await import("./sleep-manager-
|
|
4067
|
-
const sm =
|
|
4070
|
+
const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-G4B5GW5P.js");
|
|
4071
|
+
const sm = getSleepManagerIfReady2();
|
|
4068
4072
|
if (!sm) return c.json({ error: "Sleep manager not initialized" }, 503);
|
|
4069
4073
|
const flushed = await sm.flushQueuedMessages(name);
|
|
4070
4074
|
return c.json({ ok: true, flushed });
|
|
@@ -4332,8 +4336,8 @@ ${user.trimEnd()}
|
|
|
4332
4336
|
if (!entry) return c.json({ error: "Mind not found" }, 404);
|
|
4333
4337
|
const baseName = entry.parent ?? name;
|
|
4334
4338
|
try {
|
|
4335
|
-
const { getSleepManagerIfReady } = await import("./sleep-manager-
|
|
4336
|
-
const sm =
|
|
4339
|
+
const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-G4B5GW5P.js");
|
|
4340
|
+
const sm = getSleepManagerIfReady2();
|
|
4337
4341
|
if (sm?.isSleeping(baseName)) {
|
|
4338
4342
|
const body2 = await c.req.text();
|
|
4339
4343
|
let parsed2 = null;
|
|
@@ -4464,6 +4468,34 @@ ${user.trimEnd()}
|
|
|
4464
4468
|
logger_default.error(`delivery failed for ${name}`, logger_default.errorData(err));
|
|
4465
4469
|
});
|
|
4466
4470
|
return c.json({ ok: true });
|
|
4471
|
+
}).get("/:name/conversations", async (c) => {
|
|
4472
|
+
const name = c.req.param("name");
|
|
4473
|
+
const entry = await findMind(name);
|
|
4474
|
+
if (!entry) return c.json({ error: "Mind not found" }, 404);
|
|
4475
|
+
const convs = await listConversationsForMind(name);
|
|
4476
|
+
return c.json(convs);
|
|
4477
|
+
}).get("/:name/conversations/:convId/messages", async (c) => {
|
|
4478
|
+
const name = c.req.param("name");
|
|
4479
|
+
const convId = c.req.param("convId");
|
|
4480
|
+
const entry = await findMind(name);
|
|
4481
|
+
if (!entry) return c.json({ error: "Mind not found" }, 404);
|
|
4482
|
+
const belongs = await isConversationForMind(name, convId);
|
|
4483
|
+
if (!belongs) {
|
|
4484
|
+
return c.json({ error: "Conversation not found" }, 404);
|
|
4485
|
+
}
|
|
4486
|
+
const beforeStr = c.req.query("before");
|
|
4487
|
+
const limitStr = c.req.query("limit");
|
|
4488
|
+
if (!beforeStr && !limitStr) {
|
|
4489
|
+
const msgs = await getMessages(convId);
|
|
4490
|
+
return c.json({ items: msgs, hasMore: false });
|
|
4491
|
+
}
|
|
4492
|
+
const before = beforeStr ? parseInt(beforeStr, 10) : void 0;
|
|
4493
|
+
const limit = limitStr ? parseInt(limitStr, 10) : void 0;
|
|
4494
|
+
if (before !== void 0 && isNaN(before) || limit !== void 0 && isNaN(limit)) {
|
|
4495
|
+
return c.json({ error: "Invalid pagination parameters" }, 400);
|
|
4496
|
+
}
|
|
4497
|
+
const result = await getMessagesPaginated(convId, { before, limit });
|
|
4498
|
+
return c.json({ items: result.messages, hasMore: result.hasMore });
|
|
4467
4499
|
}).get("/:name/budget", async (c) => {
|
|
4468
4500
|
const name = c.req.param("name");
|
|
4469
4501
|
const baseName = await getBaseName(name);
|
|
@@ -5256,13 +5288,45 @@ function writeSchedules(name, schedules) {
|
|
|
5256
5288
|
config.schedules = schedules.length > 0 ? schedules : void 0;
|
|
5257
5289
|
writeVoluteConfig(dir, config);
|
|
5258
5290
|
getScheduler().loadSchedules(name);
|
|
5291
|
+
getSleepManagerIfReady()?.invalidateSleepConfig(name);
|
|
5259
5292
|
fireWebhook({
|
|
5260
5293
|
event: "schedule_changed",
|
|
5261
5294
|
mind: name,
|
|
5262
5295
|
data: { schedules }
|
|
5263
5296
|
});
|
|
5264
5297
|
}
|
|
5265
|
-
var app16 = new Hono16().get("/:name/
|
|
5298
|
+
var app16 = new Hono16().get("/:name/clock/status", async (c) => {
|
|
5299
|
+
const name = c.req.param("name");
|
|
5300
|
+
if (!await findMind(name)) return c.json({ error: "Mind not found" }, 404);
|
|
5301
|
+
const sleepManager = getSleepManagerIfReady();
|
|
5302
|
+
const sleepState = sleepManager?.getState(name) ?? null;
|
|
5303
|
+
const sleepConfig = sleepManager?.getSleepConfig(name) ?? null;
|
|
5304
|
+
const schedules = readSchedules(name);
|
|
5305
|
+
const now = /* @__PURE__ */ new Date();
|
|
5306
|
+
const in24h = new Date(now.getTime() + 24 * 60 * 6e4);
|
|
5307
|
+
const upcoming = [];
|
|
5308
|
+
for (const s of schedules) {
|
|
5309
|
+
if (!s.enabled) continue;
|
|
5310
|
+
if (s.fireAt) {
|
|
5311
|
+
const fireDate = new Date(s.fireAt);
|
|
5312
|
+
if (fireDate >= now && fireDate <= in24h) {
|
|
5313
|
+
upcoming.push({ id: s.id, at: fireDate.toISOString(), type: "timer" });
|
|
5314
|
+
}
|
|
5315
|
+
} else if (s.cron) {
|
|
5316
|
+
try {
|
|
5317
|
+
const interval = CronExpressionParser.parse(s.cron);
|
|
5318
|
+
const next = interval.next().toDate();
|
|
5319
|
+
if (next <= in24h) {
|
|
5320
|
+
upcoming.push({ id: s.id, at: next.toISOString(), type: "cron" });
|
|
5321
|
+
}
|
|
5322
|
+
} catch {
|
|
5323
|
+
slog.warn(`invalid cron "${s.cron}" for schedule "${s.id}" of ${name}`);
|
|
5324
|
+
}
|
|
5325
|
+
}
|
|
5326
|
+
}
|
|
5327
|
+
upcoming.sort((a, b) => a.at.localeCompare(b.at));
|
|
5328
|
+
return c.json({ sleep: sleepState, sleepConfig, schedules, upcoming });
|
|
5329
|
+
}).get("/:name/schedules", async (c) => {
|
|
5266
5330
|
const name = c.req.param("name");
|
|
5267
5331
|
if (!await findMind(name)) return c.json({ error: "Mind not found" }, 404);
|
|
5268
5332
|
return c.json(readSchedules(name));
|
|
@@ -5273,8 +5337,11 @@ var app16 = new Hono16().get("/:name/schedules", async (c) => {
|
|
|
5273
5337
|
if (entry.stage === "seed")
|
|
5274
5338
|
return c.json({ error: "Seed minds cannot use schedules \u2014 sprout first" }, 403);
|
|
5275
5339
|
const body = await c.req.json();
|
|
5276
|
-
if (!body.cron) {
|
|
5277
|
-
return c.json({ error: "cron is required" }, 400);
|
|
5340
|
+
if (!body.cron && !body.fireAt) {
|
|
5341
|
+
return c.json({ error: "cron or fireAt is required" }, 400);
|
|
5342
|
+
}
|
|
5343
|
+
if (body.cron && body.fireAt) {
|
|
5344
|
+
return c.json({ error: "cron and fireAt are mutually exclusive" }, 400);
|
|
5278
5345
|
}
|
|
5279
5346
|
if (!body.message && !body.script) {
|
|
5280
5347
|
return c.json({ error: "message or script is required" }, 400);
|
|
@@ -5282,20 +5349,36 @@ var app16 = new Hono16().get("/:name/schedules", async (c) => {
|
|
|
5282
5349
|
if (body.message && body.script) {
|
|
5283
5350
|
return c.json({ error: "message and script are mutually exclusive" }, 400);
|
|
5284
5351
|
}
|
|
5285
|
-
|
|
5286
|
-
|
|
5287
|
-
|
|
5288
|
-
|
|
5352
|
+
if (body.cron) {
|
|
5353
|
+
try {
|
|
5354
|
+
CronExpressionParser.parse(body.cron);
|
|
5355
|
+
} catch {
|
|
5356
|
+
return c.json({ error: `Invalid cron expression: ${body.cron}` }, 400);
|
|
5357
|
+
}
|
|
5358
|
+
}
|
|
5359
|
+
if (body.fireAt && Number.isNaN(new Date(body.fireAt).getTime())) {
|
|
5360
|
+
return c.json({ error: `Invalid fireAt date: ${body.fireAt}` }, 400);
|
|
5361
|
+
}
|
|
5362
|
+
if (body.whileSleeping && !["skip", "queue", "trigger-wake"].includes(body.whileSleeping)) {
|
|
5363
|
+
return c.json(
|
|
5364
|
+
{
|
|
5365
|
+
error: `Invalid whileSleeping value: ${body.whileSleeping} (must be skip, queue, or trigger-wake)`
|
|
5366
|
+
},
|
|
5367
|
+
400
|
|
5368
|
+
);
|
|
5289
5369
|
}
|
|
5290
5370
|
const schedules = readSchedules(name);
|
|
5291
5371
|
const id = body.id || `schedule-${Date.now()}`;
|
|
5292
5372
|
if (schedules.some((s) => s.id === id)) {
|
|
5293
5373
|
return c.json({ error: `Schedule "${id}" already exists` }, 409);
|
|
5294
5374
|
}
|
|
5295
|
-
const schedule = { id,
|
|
5375
|
+
const schedule = { id, enabled: body.enabled ?? true };
|
|
5376
|
+
if (body.cron) schedule.cron = body.cron;
|
|
5377
|
+
if (body.fireAt) schedule.fireAt = body.fireAt;
|
|
5296
5378
|
if (body.message) schedule.message = body.message;
|
|
5297
5379
|
if (body.script) schedule.script = body.script;
|
|
5298
5380
|
if (body.channel) schedule.channel = body.channel;
|
|
5381
|
+
if (body.whileSleeping) schedule.whileSleeping = body.whileSleeping;
|
|
5299
5382
|
schedules.push(schedule);
|
|
5300
5383
|
writeSchedules(name, schedules);
|
|
5301
5384
|
return c.json({ ok: true, id }, 201);
|
|
@@ -5317,6 +5400,14 @@ var app16 = new Hono16().get("/:name/schedules", async (c) => {
|
|
|
5317
5400
|
return c.json({ error: `Invalid cron expression: ${body.cron}` }, 400);
|
|
5318
5401
|
}
|
|
5319
5402
|
schedules[idx].cron = body.cron;
|
|
5403
|
+
delete schedules[idx].fireAt;
|
|
5404
|
+
}
|
|
5405
|
+
if (body.fireAt !== void 0) {
|
|
5406
|
+
if (Number.isNaN(new Date(body.fireAt).getTime())) {
|
|
5407
|
+
return c.json({ error: `Invalid fireAt date: ${body.fireAt}` }, 400);
|
|
5408
|
+
}
|
|
5409
|
+
schedules[idx].fireAt = body.fireAt;
|
|
5410
|
+
delete schedules[idx].cron;
|
|
5320
5411
|
}
|
|
5321
5412
|
if (body.message !== void 0) {
|
|
5322
5413
|
schedules[idx].message = body.message;
|
|
@@ -5326,8 +5417,18 @@ var app16 = new Hono16().get("/:name/schedules", async (c) => {
|
|
|
5326
5417
|
schedules[idx].script = body.script;
|
|
5327
5418
|
delete schedules[idx].message;
|
|
5328
5419
|
}
|
|
5420
|
+
if (body.whileSleeping && !["skip", "queue", "trigger-wake"].includes(body.whileSleeping)) {
|
|
5421
|
+
return c.json(
|
|
5422
|
+
{
|
|
5423
|
+
error: `Invalid whileSleeping value: ${body.whileSleeping} (must be skip, queue, or trigger-wake)`
|
|
5424
|
+
},
|
|
5425
|
+
400
|
|
5426
|
+
);
|
|
5427
|
+
}
|
|
5329
5428
|
if (body.enabled !== void 0) schedules[idx].enabled = body.enabled;
|
|
5330
5429
|
if (body.channel !== void 0) schedules[idx].channel = body.channel || void 0;
|
|
5430
|
+
if (body.whileSleeping !== void 0)
|
|
5431
|
+
schedules[idx].whileSleeping = body.whileSleeping || void 0;
|
|
5331
5432
|
writeSchedules(name, schedules);
|
|
5332
5433
|
return c.json({ ok: true });
|
|
5333
5434
|
}).delete("/:name/schedules/:id", requireSelf(), async (c) => {
|
|
@@ -5674,11 +5775,11 @@ async function fanOutToMinds(opts) {
|
|
|
5674
5775
|
const mindParticipants = participants.filter((p) => p.userType === "mind");
|
|
5675
5776
|
const participantNames = participants.map((p) => p.username);
|
|
5676
5777
|
const isDM = opts.isDM ?? participants.length === 2;
|
|
5677
|
-
const channelEntryType = opts.channelEntryType ?? (isDM ? "dm" : "
|
|
5678
|
-
const { getMindManager: getMindManager2 } = await import("./mind-manager-
|
|
5679
|
-
const { getSleepManagerIfReady } = await import("./sleep-manager-
|
|
5778
|
+
const channelEntryType = opts.channelEntryType ?? (isDM ? "dm" : "channel");
|
|
5779
|
+
const { getMindManager: getMindManager2 } = await import("./mind-manager-P66HQDNE.js");
|
|
5780
|
+
const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-G4B5GW5P.js");
|
|
5680
5781
|
const manager = getMindManager2();
|
|
5681
|
-
const sm =
|
|
5782
|
+
const sm = getSleepManagerIfReady2();
|
|
5682
5783
|
const targetMinds = mindParticipants.map((ap) => {
|
|
5683
5784
|
const key = opts.targetName ? opts.targetName(ap.username) : ap.username;
|
|
5684
5785
|
if (manager.isRunning(key) || sm?.isSleeping(ap.username)) return ap.username;
|
|
@@ -5797,7 +5898,7 @@ var app22 = new Hono22().use("*", authMiddleware).post("/minds/:name/chat", zVal
|
|
|
5797
5898
|
senderName,
|
|
5798
5899
|
convTitle,
|
|
5799
5900
|
isDM,
|
|
5800
|
-
channelEntryType:
|
|
5901
|
+
channelEntryType: isDM ? "dm" : "channel",
|
|
5801
5902
|
slugExtra: conv ? { convType: conv.type, convName: conv.name } : void 0,
|
|
5802
5903
|
targetName: (username) => username === baseName ? name : username
|
|
5803
5904
|
});
|
|
@@ -5854,7 +5955,7 @@ var app22 = new Hono22().use("*", authMiddleware).post("/minds/:name/chat", zVal
|
|
|
5854
5955
|
senderName,
|
|
5855
5956
|
convTitle: conv.title,
|
|
5856
5957
|
isDM,
|
|
5857
|
-
channelEntryType:
|
|
5958
|
+
channelEntryType: isDM ? "dm" : "channel",
|
|
5858
5959
|
slugExtra: { convType: conv.type, convName: conv.name }
|
|
5859
5960
|
});
|
|
5860
5961
|
return c.json({ ok: true, conversationId: body.conversationId });
|
|
@@ -6608,11 +6709,11 @@ async function fanOutToMinds2(opts) {
|
|
|
6608
6709
|
const mindParticipants = participants.filter((p) => p.userType === "mind");
|
|
6609
6710
|
const participantNames = participants.map((p) => p.username);
|
|
6610
6711
|
const isDM = opts.isDM ?? participants.length === 2;
|
|
6611
|
-
const channelEntryType = opts.channelEntryType ?? (isDM ? "dm" : "
|
|
6612
|
-
const { getMindManager: getMindManager2 } = await import("./mind-manager-
|
|
6613
|
-
const { getSleepManagerIfReady } = await import("./sleep-manager-
|
|
6712
|
+
const channelEntryType = opts.channelEntryType ?? (isDM ? "dm" : "channel");
|
|
6713
|
+
const { getMindManager: getMindManager2 } = await import("./mind-manager-P66HQDNE.js");
|
|
6714
|
+
const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-G4B5GW5P.js");
|
|
6614
6715
|
const manager = getMindManager2();
|
|
6615
|
-
const sm =
|
|
6716
|
+
const sm = getSleepManagerIfReady2();
|
|
6616
6717
|
const targetMinds = mindParticipants.map((ap) => {
|
|
6617
6718
|
const key = opts.targetName ? opts.targetName(ap.username) : ap.username;
|
|
6618
6719
|
if (manager.isRunning(key) || sm?.isSleeping(ap.username)) return ap.username;
|
|
@@ -6771,7 +6872,7 @@ var app27 = new Hono27().post("/:name/chat", zValidator12("json", chatSchema), a
|
|
|
6771
6872
|
senderName,
|
|
6772
6873
|
convTitle,
|
|
6773
6874
|
isDM,
|
|
6774
|
-
channelEntryType:
|
|
6875
|
+
channelEntryType: isDM ? "dm" : "channel",
|
|
6775
6876
|
slugExtra: conv ? { convType: conv.type, convName: conv.name } : void 0,
|
|
6776
6877
|
targetName: (username) => username === baseName ? name : username
|
|
6777
6878
|
});
|
|
@@ -6879,7 +6980,7 @@ var unifiedChatApp = new Hono27().post(
|
|
|
6879
6980
|
senderName,
|
|
6880
6981
|
convTitle: conv.title,
|
|
6881
6982
|
isDM,
|
|
6882
|
-
channelEntryType:
|
|
6983
|
+
channelEntryType: isDM ? "dm" : "channel",
|
|
6883
6984
|
slugExtra: { convType: conv.type, convName: conv.name }
|
|
6884
6985
|
});
|
|
6885
6986
|
return c.json({ ok: true, conversationId: body.conversationId });
|
|
@@ -6949,6 +7050,9 @@ var app28 = new Hono28().get("/:name/conversations", async (c) => {
|
|
|
6949
7050
|
if (!u) return c.json({ error: `User ${id} not found` }, 400);
|
|
6950
7051
|
}
|
|
6951
7052
|
const participantIds = [...participantSet];
|
|
7053
|
+
if (participantIds.length > 2) {
|
|
7054
|
+
return c.json({ error: "Use channels for multi-participant conversations" }, 400);
|
|
7055
|
+
}
|
|
6952
7056
|
if (participantIds.length === 2) {
|
|
6953
7057
|
const existingId = await findDMConversation(name, participantIds);
|
|
6954
7058
|
if (existingId) {
|
|
@@ -7037,6 +7141,9 @@ var app29 = new Hono29().use("*", authMiddleware).get("/", async (c) => {
|
|
|
7037
7141
|
if (!firstMindName) {
|
|
7038
7142
|
return c.json({ error: "At least one mind participant is required" }, 400);
|
|
7039
7143
|
}
|
|
7144
|
+
if (participantIds.size > 2) {
|
|
7145
|
+
return c.json({ error: "Use channels for multi-participant conversations" }, 400);
|
|
7146
|
+
}
|
|
7040
7147
|
const conv = await createConversation(firstMindName, "volute", {
|
|
7041
7148
|
userId: user.id !== 0 ? user.id : void 0,
|
|
7042
7149
|
title: body.title,
|
|
@@ -7282,6 +7389,12 @@ async function startDaemon(opts) {
|
|
|
7282
7389
|
await (await import("./db-IC4J52XQ.js")).getDb();
|
|
7283
7390
|
const { migrateRegistryToDb } = await import("./migrate-registry-to-db-XC7T5B7P.js");
|
|
7284
7391
|
migrateRegistryToDb();
|
|
7392
|
+
try {
|
|
7393
|
+
const { migrateGroupDMsToChannels } = await import("./conversations-P5BL7RMX.js");
|
|
7394
|
+
await migrateGroupDMsToChannels();
|
|
7395
|
+
} catch (err) {
|
|
7396
|
+
logger_default.error("failed to migrate group DMs to channels", logger_default.errorData(err));
|
|
7397
|
+
}
|
|
7285
7398
|
const { initSandbox } = await import("./sandbox-5BW5HPXM.js");
|
|
7286
7399
|
await initSandbox();
|
|
7287
7400
|
try {
|
|
@@ -7294,6 +7407,8 @@ async function startDaemon(opts) {
|
|
|
7294
7407
|
} catch (err) {
|
|
7295
7408
|
logger_default.warn("failed to ensure #system channel", logger_default.errorData(err));
|
|
7296
7409
|
}
|
|
7410
|
+
const { startSystemWatcher } = await import("./pages-watcher-P7QECRE2.js");
|
|
7411
|
+
startSystemWatcher();
|
|
7297
7412
|
const token = process.env.VOLUTE_DAEMON_TOKEN || randomBytes(32).toString("hex");
|
|
7298
7413
|
let tls;
|
|
7299
7414
|
if (opts.tailscale) {
|
|
@@ -7378,7 +7493,7 @@ async function startDaemon(opts) {
|
|
|
7378
7493
|
bridgeManager.startBridges(daemonPort).catch((err) => {
|
|
7379
7494
|
logger_default.warn("failed to start bridges", logger_default.errorData(err));
|
|
7380
7495
|
});
|
|
7381
|
-
import("./cloud-sync-
|
|
7496
|
+
import("./cloud-sync-KILFGV5Q.js").then(
|
|
7382
7497
|
({ consumeQueuedMessages }) => consumeQueuedMessages().catch((err) => {
|
|
7383
7498
|
logger_default.warn("failed to consume queued cloud messages", logger_default.errorData(err));
|
|
7384
7499
|
})
|
|
@@ -7386,7 +7501,7 @@ async function startDaemon(opts) {
|
|
|
7386
7501
|
logger_default.warn("failed to load cloud-sync module", logger_default.errorData(err));
|
|
7387
7502
|
});
|
|
7388
7503
|
try {
|
|
7389
|
-
const { backfillTemplateHashes, notifyVersionUpdate } = await import("./version-notify-
|
|
7504
|
+
const { backfillTemplateHashes, notifyVersionUpdate } = await import("./version-notify-WDHRO3XD.js");
|
|
7390
7505
|
backfillTemplateHashes();
|
|
7391
7506
|
notifyVersionUpdate().catch((err) => {
|
|
7392
7507
|
logger_default.warn("failed to send version update notifications", logger_default.errorData(err));
|
|
@@ -2,23 +2,26 @@
|
|
|
2
2
|
import {
|
|
3
3
|
deliverMessage,
|
|
4
4
|
extractTextContent,
|
|
5
|
-
recordInbound
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
import "./chunk-
|
|
5
|
+
recordInbound,
|
|
6
|
+
resolveSleepAction
|
|
7
|
+
} from "./chunk-CMILSHZD.js";
|
|
8
|
+
import "./chunk-THUUIU3E.js";
|
|
9
|
+
import "./chunk-FLZGS4QH.js";
|
|
10
|
+
import "./chunk-CQ7SNKNI.js";
|
|
9
11
|
import "./chunk-VIVMW2H2.js";
|
|
10
|
-
import "./chunk-
|
|
12
|
+
import "./chunk-EHZKEMMV.js";
|
|
11
13
|
import "./chunk-J4IBNXGJ.js";
|
|
12
14
|
import "./chunk-2WPW7OT6.js";
|
|
13
15
|
import "./chunk-YUIHSKR6.js";
|
|
14
16
|
import "./chunk-AW7PFDVN.js";
|
|
15
17
|
import "./chunk-RKQEHRBB.js";
|
|
16
18
|
import "./chunk-IKRVFPWU.js";
|
|
17
|
-
import "./chunk-
|
|
19
|
+
import "./chunk-A6TUJJ3L.js";
|
|
18
20
|
import "./chunk-H7OZRFJB.js";
|
|
19
21
|
import "./chunk-K3NQKI34.js";
|
|
20
22
|
export {
|
|
21
23
|
deliverMessage,
|
|
22
24
|
extractTextContent,
|
|
23
|
-
recordInbound
|
|
25
|
+
recordInbound,
|
|
26
|
+
resolveSleepAction
|
|
24
27
|
};
|
|
@@ -4,7 +4,7 @@ import "./chunk-K3NQKI34.js";
|
|
|
4
4
|
// package.json
|
|
5
5
|
var package_default = {
|
|
6
6
|
name: "volute",
|
|
7
|
-
version: "0.
|
|
7
|
+
version: "0.29.0",
|
|
8
8
|
description: "CLI for creating and managing self-modifying AI minds powered by the Claude Agent SDK",
|
|
9
9
|
type: "module",
|
|
10
10
|
license: "MIT",
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
getCachedRecentPages,
|
|
4
|
+
getCachedSites,
|
|
5
|
+
startSystemWatcher,
|
|
6
|
+
startWatcher,
|
|
7
|
+
stopAllWatchers,
|
|
8
|
+
stopWatcher
|
|
9
|
+
} from "./chunk-THUUIU3E.js";
|
|
10
|
+
import "./chunk-VIVMW2H2.js";
|
|
11
|
+
import "./chunk-YUIHSKR6.js";
|
|
12
|
+
import "./chunk-H7OZRFJB.js";
|
|
13
|
+
import "./chunk-K3NQKI34.js";
|
|
14
|
+
export {
|
|
15
|
+
getCachedRecentPages,
|
|
16
|
+
getCachedSites,
|
|
17
|
+
startSystemWatcher,
|
|
18
|
+
startWatcher,
|
|
19
|
+
stopAllWatchers,
|
|
20
|
+
stopWatcher
|
|
21
|
+
};
|
|
@@ -34,23 +34,9 @@ Add to `.config/volute.json` under `schedules`:
|
|
|
34
34
|
Or via CLI:
|
|
35
35
|
|
|
36
36
|
```bash
|
|
37
|
-
volute
|
|
37
|
+
volute clock add --mind <name> --id dream --cron "0 3 * * *" --channel system:dream --while-sleeping trigger-wake --message "it's 3am. you are dreaming...."
|
|
38
38
|
```
|
|
39
39
|
|
|
40
|
-
## 3. Sleep integration
|
|
40
|
+
## 3. Sleep integration
|
|
41
41
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
In `.config/volute.json`, add to the `sleep` section:
|
|
45
|
-
|
|
46
|
-
```json
|
|
47
|
-
{
|
|
48
|
-
"sleep": {
|
|
49
|
-
"wakeTriggers": {
|
|
50
|
-
"channels": ["system:dream"]
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
The mind will wake for the dream, then return to sleep when done.
|
|
42
|
+
The `--while-sleeping trigger-wake` flag on the schedule tells the clock system to briefly wake the mind for the dream, then return to sleep when done. No additional wake trigger configuration is needed.
|