volute 0.48.0 → 0.50.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 +79 -328
- package/dist/{accept-KYNC5X3U.js → accept-5NK5XJB5.js} +2 -1
- package/dist/{activity-events-MIOK3IOU.js → activity-events-H7YI3BTF.js} +4 -4
- package/dist/{ai-service-643TNFPH.js → ai-service-V4CTNGI3.js} +6 -5
- package/dist/{archive-6Z4GFQPH.js → archive-ORM3ENHI.js} +3 -3
- package/dist/{auth-A4VGHADI.js → auth-DT7GY7EZ.js} +11 -7
- package/dist/{avatar-image-Y45R7LW5.js → avatar-image-QEPAP3A5.js} +4 -4
- package/dist/{backup-UDH4GMSW.js → backup-IE6PMXJO.js} +17 -18
- package/dist/{bridge-3FNSWLNQ.js → bridge-YK7NTRU5.js} +2 -1
- package/dist/{channels-SGQZHNQJ.js → channels-FSAHOQWI.js} +2 -1
- package/dist/{chat-X43VYHH2.js → chat-W5K6HCBE.js} +9 -9
- package/dist/{chunk-LTLFOSA4.js → chunk-3BAFMGCJ.js} +3 -3
- package/dist/{chunk-XVBSFLM7.js → chunk-4CN7OCJE.js} +2 -2
- package/dist/{chunk-HPGN6XRT.js → chunk-574M6I7F.js} +39 -6
- package/dist/{chunk-FJ2MZ5PH.js → chunk-5FVANDON.js} +2 -2
- package/dist/{chunk-2MJ7EOMT.js → chunk-5IIVOWSP.js} +28 -19
- package/dist/{chunk-4FCL4DVZ.js → chunk-5PKFJHCR.js} +2 -2
- package/dist/{chunk-MOERAQXH.js → chunk-5TPC4KCV.js} +38 -31
- package/dist/{chunk-YNBXEQAP.js → chunk-632FJ23O.js} +24 -20
- package/dist/{chunk-T4VS7UDW.js → chunk-636GFQNE.js} +12 -12
- package/dist/{chunk-EIQDZC43.js → chunk-6BM2I736.js} +25 -6
- package/dist/{chunk-WARH6GIV.js → chunk-74T3CEXK.js} +17 -15
- package/dist/{chunk-OQJMTHEH.js → chunk-77IZUVBB.js} +2 -2
- package/dist/{chunk-USD45JKR.js → chunk-7DXLIYPY.js} +77 -64
- package/dist/chunk-7FDWPQCU.js +289 -0
- package/dist/chunk-7OZWKHA3.js +548 -0
- package/dist/{chunk-IJPMIEVE.js → chunk-7UWXAJMK.js} +1 -1
- package/dist/{chunk-SZJCJVXV.js → chunk-7XDOTN4R.js} +2 -2
- package/dist/{chunk-YKA7DCVW.js → chunk-AFSLNUTT.js} +1 -1
- package/dist/{chunk-DGGZVZTM.js → chunk-AJWFDIEY.js} +17 -2
- package/dist/chunk-ALIVXDM4.js +1014 -0
- package/dist/chunk-CAIYV33P.js +523 -0
- package/dist/{chunk-MTRMQFCQ.js → chunk-E5S3ILVA.js} +2 -2
- package/dist/{chunk-SHKM5RGD.js → chunk-EEOMA4DX.js} +1 -1
- package/dist/chunk-EQKSRVDE.js +2857 -0
- package/dist/chunk-FNJCBRD3.js +31 -0
- package/dist/chunk-HW6Q7AMB.js +113 -0
- package/dist/chunk-JI67D7O2.js +1222 -0
- package/dist/{chunk-3YUBFTDN.js → chunk-KAEZOVP6.js} +1 -1
- package/dist/chunk-LNNI3MS4.js +54 -0
- package/dist/{chunk-BCG45AQB.js → chunk-M74I3HHF.js} +15 -5
- package/dist/chunk-MLZBBLMT.js +109 -0
- package/dist/{chunk-5T5YMX6S.js → chunk-PW65BXY5.js} +5 -0
- package/dist/{chunk-2OIYNHWO.js → chunk-QFVGPKJI.js} +1 -1
- package/dist/{chunk-T2TP6ZC6.js → chunk-QUSMYGNQ.js} +6 -0
- package/dist/{chunk-HNGFKPNS.js → chunk-SFRYRW37.js} +85 -36
- package/dist/{chunk-7KRIHYLR.js → chunk-SSNZ6ZNN.js} +2 -2
- package/dist/{chunk-HUNDXZBZ.js → chunk-TGJHGVBZ.js} +48 -19
- package/dist/{chunk-PJVPDY2Z.js → chunk-U3EJJ7JN.js} +2 -2
- package/dist/{chunk-ODDGGLM6.js → chunk-UC6BNMGT.js} +43 -13
- package/dist/{chunk-Q7HOAVFR.js → chunk-WBBKYUGF.js} +4 -6
- package/dist/{chunk-WQ46E33M.js → chunk-X67VT4QO.js} +2 -2
- package/dist/{chunk-MJRXFUMS.js → chunk-YQOYZ6G7.js} +3 -5
- package/dist/{chunk-VZRA5TYO.js → chunk-ZUG76D3P.js} +36 -6
- package/dist/cli.js +34 -27
- package/dist/{clock-CNRF6F7T.js → clock-LH7UFNLJ.js} +5 -4
- package/dist/{cloud-sync-WHKCB4CD.js → cloud-sync-IDJFVDEP.js} +23 -20
- package/dist/{config-RPSLA2HX.js → config-UGJS57VT.js} +3 -3
- package/dist/{conversations-C7IKYSHD.js → conversations-S2232Y5I.js} +9 -5
- package/dist/{create-GJKHABJB.js → create-2M7DAHQX.js} +2 -2
- package/dist/{create-VIQVP3QB.js → create-M727VUDF.js} +2 -1
- package/dist/{daemon-client-ZFY5MOAL.js → daemon-client-VVYFZI2D.js} +2 -1
- package/dist/{daemon-restart-7KUHVZIN.js → daemon-restart-2AAGYFHE.js} +6 -7
- package/dist/daemon.js +2166 -833
- package/dist/{db-FO6LXYCW.js → db-QAY45Z56.js} +2 -2
- package/dist/{delete-ESEP7NGQ.js → delete-O7PEFQDF.js} +1 -1
- package/dist/delivery-manager-B4OKWD2P.js +33 -0
- package/dist/{delivery-router-3QFG2ZEX.js → delivery-router-JE7SHYNU.js} +10 -6
- package/dist/{down-G6IADJXV.js → down-D4IRNEMJ.js} +5 -5
- package/dist/echo-text-WYAAODBV.js +39 -0
- package/dist/{env-C7Z55QCJ.js → env-ABM5IMA7.js} +8 -7
- package/dist/{env-6TGPO5WG.js → env-AZK5X4W7.js} +3 -3
- package/dist/{exec-QIFYZG4C.js → exec-2H65LMTA.js} +3 -3
- package/dist/{export-C2K3NIRD.js → export-3E3EL6W3.js} +4 -4
- package/dist/{extension-J4ZQ2GHV.js → extension-MRYJWSMV.js} +2 -1
- package/dist/{extensions-GEKF47A4.js → extensions-7KP3X6G7.js} +23 -20
- package/dist/{files-LXQSQOFG.js → files-6BMKVG5G.js} +5 -4
- package/dist/{import-SX3ZXHB4.js → import-UPNTEBBT.js} +9 -9
- package/dist/{isolation-MCT4ZYLT.js → isolation-OKDFM6WA.js} +5 -3
- package/dist/{join-34TR2GXQ.js → join-PYA36HEC.js} +1 -1
- package/dist/{list-PMUXZNAM.js → list-4BVGH7AN.js} +8 -3
- package/dist/{login-CL4IT2ED.js → login-MOXVLULE.js} +7 -6
- package/dist/{login-ARRZ4ORJ.js → login-RJJTCVR3.js} +4 -3
- package/dist/{logout-YZRMZ3O2.js → logout-BYV433X6.js} +2 -1
- package/dist/{logout-HZYJCYCA.js → logout-DWD3OQVT.js} +4 -3
- package/dist/message-delivery-3456PXB7.js +43 -0
- package/dist/migrate-thread-config-4A5LW36Z.js +90 -0
- package/dist/{mind-46AOK373.js → mind-NYRALSV2.js} +19 -19
- package/dist/{mind-activity-tracker-YVZPC4A5.js → mind-activity-tracker-L7GCYXQR.js} +5 -5
- package/dist/{mind-contacts-GV7XYL5D.js → mind-contacts-QYU4TPEA.js} +8 -7
- package/dist/{mind-history-TTGA5BHZ.js → mind-history-NXXOOTX6.js} +34 -11
- package/dist/{mind-list-OTHV4ZO4.js → mind-list-SYRA7CH5.js} +3 -2
- package/dist/{mind-profile-LUG353ZT.js → mind-profile-MRCVZPYT.js} +1 -1
- package/dist/mind-service-5TA7UJAT.js +47 -0
- package/dist/{mind-sleep-DV7KP255.js → mind-sleep-TH6BRQ5X.js} +5 -4
- package/dist/{mind-status-BJNPGXKC.js → mind-status-Z2LQFA6F.js} +3 -2
- package/dist/{mind-wake-LVTZ55EZ.js → mind-wake-LDGPRA42.js} +2 -1
- package/dist/{package-RTN2PS7O.js → package-XYSV7NUT.js} +27 -26
- package/dist/prompts-QKFPX6DQ.js +24 -0
- package/dist/{read-YSWUXYL7.js → read-ZXGUT4QC.js} +5 -3
- package/dist/{register-42VBJKTP.js → register-OX4HRSGC.js} +4 -3
- package/dist/{registry-UMMDRPRM.js → registry-4UF6OCOE.js} +10 -4
- package/dist/{reject-SXGCYN4A.js → reject-TWB4QJHG.js} +2 -1
- package/dist/{restart-YYEGZJDD.js → restart-AGEGNSYQ.js} +6 -5
- package/dist/{sandbox-5VQ454XP.js → sandbox-EGEU5GGE.js} +8 -5
- package/dist/scheduler-UV6RUJ7P.js +25 -0
- package/dist/{schema-VEVO7HG6.js → schema-C2GIPD4V.js} +3 -3
- package/dist/{seed-F2HXZQU4.js → seed-3IMBOAGK.js} +1 -1
- package/dist/{seed-check-TYD7RRZY.js → seed-check-NRJEQZST.js} +14 -5
- package/dist/{seed-cmd-MLCTGSX5.js → seed-cmd-U73XVQMI.js} +3 -3
- package/dist/{seed-create-KQ7OILWB.js → seed-create-FBLNVSUP.js} +4 -4
- package/dist/{seed-readiness-RBPGOLSZ.js → seed-readiness-QRA46ZJQ.js} +4 -5
- package/dist/{seed-sprout-HVYCFJLA.js → seed-sprout-3B4SZX7J.js} +12 -12
- package/dist/{send-TD2X5U3K.js → send-NBRZJXKX.js} +34 -12
- package/dist/{service-CVZMQYK6.js → service-XMXAXGJD.js} +4 -4
- package/dist/{service-install-VCRMFWX5.js → service-install-MOKTEG7B.js} +5 -5
- package/dist/{setup-5ECWTYKG.js → setup-CAJFOR2N.js} +12 -3
- package/dist/{setup-AE4CVUC4.js → setup-JGYAXXW7.js} +6 -7
- package/dist/{skill-UUM4JZRF.js → skill-NXIHDQCG.js} +7 -6
- package/dist/skills/dreaming/references/INSTALL.md +2 -2
- package/dist/skills/imagegen/SKILL.md +21 -4
- package/dist/skills/imagegen/scripts/imagegen.ts +124 -21
- package/dist/skills/tending/SKILL.md +7 -7
- package/dist/skills/volute-mind/SKILL.md +6 -6
- package/dist/skills/volute-mind/references/integrations.md +2 -2
- package/dist/skills/volute-mind/references/routing.md +19 -18
- package/dist/skills/volute-mind/references/variants.md +48 -14
- package/dist/{skills-B3SVDCEB.js → skills-5MSMT7PT.js} +7 -6
- package/dist/sleep-manager-LIEPO6WG.js +41 -0
- package/dist/spirit-IL5EMWYZ.js +34 -0
- package/dist/spirit-availability-YFEGJNJ2.js +42 -0
- package/dist/{split-SKZ4Y2D6.js → split-BU5VWX6P.js} +5 -2
- package/dist/{sprout-KQ43BWZJ.js → sprout-UPXGJ5HX.js} +1 -1
- package/dist/{src-YH6PQ7LJ.js → src-HGNE2XG4.js} +7 -1
- package/dist/{src-WLJE73NP.js → src-LCSOQY6Z.js} +60 -54
- package/dist/{src-JAOVXO5W.js → src-UDMJZ6MH.js} +8 -8
- package/dist/{start-O6UKK7BG.js → start-MUMNFR52.js} +4 -3
- package/dist/{status-F4PGREUU.js → status-IL67CYM4.js} +7 -6
- package/dist/{stop-UBX6X5RA.js → stop-EKERNYTX.js} +6 -5
- package/dist/system-events-A6IGCEC3.js +46 -0
- package/dist/system-install-YZSWCPDK.js +8 -0
- package/dist/{systems-JJNGQHAO.js → systems-VDRUZXNF.js} +5 -4
- package/dist/{tailscale-MCLY5GYE.js → tailscale-SJUW2ETR.js} +3 -3
- package/dist/{template-staleness-EMQORSGG.js → template-staleness-T27VCGYA.js} +4 -4
- package/dist/{turn-tracker-KLPV3PAU.js → turn-tracker-6EI2EL7G.js} +7 -7
- package/dist/{up-RVGDE6CQ.js → up-CLL4665A.js} +5 -6
- package/dist/{update-OXQEGGXD.js → update-HVAUCQPN.js} +5 -5
- package/dist/{update-check-266R4ZSY.js → update-check-2MGBBAFF.js} +3 -3
- package/dist/{upgrade-K5FIQPQD.js → upgrade-LIE46UBB.js} +1 -1
- package/dist/variant-cleanup-HJ7Z75R6.js +22 -0
- package/dist/{version-notify-73YURTFR.js → version-notify-7BUHWZNT.js} +11 -28
- package/dist/web-assets/assets/index-ClsUcXiW.js +95 -0
- package/dist/web-assets/assets/index-Dz3wTbtR.css +1 -0
- package/dist/web-assets/index.html +2 -2
- package/dist/xai-P42CRCZA.js +129 -0
- package/drizzle/0013_variant_purpose.sql +3 -0
- package/drizzle/0014_system_events.sql +26 -0
- package/drizzle/0015_rename_session_to_thread.sql +12 -0
- package/drizzle/0016_brain_to_human.sql +4 -0
- package/drizzle/0017_event_history_rows.sql +9 -0
- package/drizzle/meta/_journal.json +35 -0
- package/package.json +27 -26
- package/packages/extensions/notes/dist/ui/assets/index-BBs8pyel.js +67 -0
- package/packages/extensions/notes/dist/ui/index.html +1 -1
- package/packages/extensions/pages/dist/ui/assets/index-B589e8Xe.js +2 -0
- package/packages/extensions/pages/dist/ui/index.html +1 -1
- package/packages/extensions/plan/dist/ui/assets/index-B8s8wxyt.js +67 -0
- package/packages/extensions/plan/dist/ui/index.html +1 -1
- package/templates/_base/.init/.config/prompts.json +1 -0
- package/templates/_base/.init/.local/hooks/startup-context.ts +34 -2
- package/templates/_base/home/.config/routes.json +2 -2
- package/templates/_base/home/VOLUTE.md +30 -5
- package/templates/_base/src/lib/daemon-client.ts +28 -8
- package/templates/_base/src/lib/event-turn.ts +39 -0
- package/templates/_base/src/lib/format-prefix.ts +21 -2
- package/templates/_base/src/lib/router.ts +6 -2
- package/templates/_base/src/lib/routing.ts +8 -8
- package/templates/_base/src/lib/startup.ts +9 -1
- package/templates/_base/src/lib/types.ts +7 -1
- package/templates/_base/src/lib/volute-server.ts +30 -1
- package/templates/claude/.init/.config/routes.json +3 -3
- package/templates/claude/.init/CLAUDE.md +1 -1
- package/templates/claude/package.json.tmpl +4 -4
- package/templates/claude/src/agent.ts +5 -2
- package/templates/claude/src/lib/hooks/identity-reload.ts +12 -3
- package/templates/claude/src/lib/hooks/reply-instructions.ts +26 -1
- package/templates/codex/.init/.config/routes.json +3 -3
- package/templates/codex/.init/AGENTS.md +1 -1
- package/templates/codex/package.json.tmpl +4 -4
- package/templates/codex/src/agent.ts +11 -11
- package/templates/codex/src/lib/turn-context.ts +51 -0
- package/templates/pi/.init/.config/routes.json +3 -3
- package/templates/pi/.init/MINDS.md +1 -1
- package/templates/pi/package.json.tmpl +6 -6
- package/templates/pi/src/agent.ts +9 -1
- package/templates/pi/src/lib/event-handler.ts +47 -6
- package/templates/pi/src/lib/reply-instructions-extension.ts +28 -1
- package/dist/chunk-5KXCM5AW.js +0 -169
- package/dist/chunk-IYCV34IU.js +0 -158
- package/dist/chunk-VB2QXUJQ.js +0 -5260
- package/dist/chunk-WW6C3PLV.js +0 -280
- package/dist/delivery-manager-HZTT5SJR.js +0 -36
- package/dist/echo-text-H3SH337Q.js +0 -36
- package/dist/message-delivery-GPQ5SE5N.js +0 -40
- package/dist/mind-service-2ARGJNKP.js +0 -44
- package/dist/notices-2KU5NTRY.js +0 -25
- package/dist/scheduler-I7JZCT47.js +0 -34
- package/dist/sleep-manager-Z27R3WTW.js +0 -38
- package/dist/spirit-WXS3HCLN.js +0 -25
- package/dist/system-chat-63ABFF6V.js +0 -40
- package/dist/web-assets/assets/index-WdZ60R6c.css +0 -1
- package/dist/web-assets/assets/index-taX6Ezfa.js +0 -92
- package/packages/extensions/notes/dist/ui/assets/index-D0-DgYyj.js +0 -67
- package/packages/extensions/pages/dist/ui/assets/index-DtzftuPA.js +0 -2
- package/packages/extensions/plan/dist/ui/assets/index-Cfzs-0G9.js +0 -67
|
@@ -137,15 +137,28 @@ export function createEventHandler(session: EventSession, options: EventHandlerO
|
|
|
137
137
|
|
|
138
138
|
if (event.type === "agent_end") {
|
|
139
139
|
flushBuffers();
|
|
140
|
-
|
|
141
|
-
|
|
140
|
+
// Capture the turn's message context before clearing it: the ordered error/done
|
|
141
|
+
// emits below run asynchronously, but currentMessageId must be reset synchronously
|
|
142
|
+
// so the next turn shifts a fresh id (see the currentMessageId guard above).
|
|
143
|
+
const messageId = session.currentMessageId;
|
|
144
|
+
if (messageId) {
|
|
145
|
+
session.messageChannels.delete(messageId);
|
|
142
146
|
}
|
|
147
|
+
const channel = messageId ? session.messageChannels.get(messageId)?.channel : undefined;
|
|
143
148
|
log("mind", `session "${session.name}": turn done`);
|
|
144
|
-
//
|
|
149
|
+
// Collect any agent-level errors (e.g. a provider 401 reported inside agent_end).
|
|
150
|
+
// Warn-logging alone left the failure invisible at every host surface (#619);
|
|
151
|
+
// we emit a turn_error to the daemon too — mirroring the dispatch-rejection path in
|
|
152
|
+
// agent.ts — so classify() tags it and chat status + lastError surface it. Dedupe
|
|
153
|
+
// identical messages so a turn with several failed messages records one notice.
|
|
154
|
+
const errorMessages: string[] = [];
|
|
145
155
|
if (event.messages) {
|
|
156
|
+
const seen = new Set<string>();
|
|
146
157
|
for (const msg of event.messages as AgentEndMessage[]) {
|
|
147
|
-
if (msg.errorMessage) {
|
|
158
|
+
if (msg.errorMessage && !seen.has(msg.errorMessage)) {
|
|
159
|
+
seen.add(msg.errorMessage);
|
|
148
160
|
warn("mind", `session "${session.name}": agent error: ${msg.errorMessage}`);
|
|
161
|
+
errorMessages.push(msg.errorMessage);
|
|
149
162
|
}
|
|
150
163
|
}
|
|
151
164
|
}
|
|
@@ -175,14 +188,42 @@ export function createEventHandler(session: EventSession, options: EventHandlerO
|
|
|
175
188
|
}
|
|
176
189
|
}
|
|
177
190
|
options.broadcast({ type: "done" });
|
|
178
|
-
emit(session, { type: "done" });
|
|
179
191
|
session.currentMessageId = undefined;
|
|
192
|
+
// Emit any errors BEFORE done, awaiting each in turn. daemonEmit is fire-and-forget,
|
|
193
|
+
// so without ordered awaits the daemon could process `done` before `error`:
|
|
194
|
+
// markErrored would land after done consumed the errored flag, leaking it into the
|
|
195
|
+
// next turn (whose clean done then wrongly skips clearing delivered notices). This
|
|
196
|
+
// mirrors agent.ts's awaited error-then-done ordering. Message context is captured
|
|
197
|
+
// above rather than read from the (now-cleared) session.
|
|
198
|
+
void (async () => {
|
|
199
|
+
for (const content of errorMessages) {
|
|
200
|
+
const ev = filterEvent(preset, {
|
|
201
|
+
type: "error",
|
|
202
|
+
session: session.name,
|
|
203
|
+
channel,
|
|
204
|
+
messageId,
|
|
205
|
+
content,
|
|
206
|
+
});
|
|
207
|
+
if (ev) await daemonEmit(ev);
|
|
208
|
+
}
|
|
209
|
+
const doneEv = filterEvent(preset, {
|
|
210
|
+
type: "done",
|
|
211
|
+
session: session.name,
|
|
212
|
+
channel,
|
|
213
|
+
messageId,
|
|
214
|
+
});
|
|
215
|
+
if (doneEv) await daemonEmit(doneEv);
|
|
216
|
+
})().catch((err) =>
|
|
217
|
+
warn("mind", `session "${session.name}": error/done emit failed:`, err),
|
|
218
|
+
);
|
|
180
219
|
flushFileChanges(options.cwd)
|
|
181
220
|
.then(() => options.onTurnEnd?.())
|
|
182
221
|
.catch((err) => log("mind", `session "${session.name}": flush/turn-end error:`, err));
|
|
183
222
|
}
|
|
184
223
|
} catch (err) {
|
|
185
|
-
|
|
224
|
+
// warn-level: this block now drives turn-completion (error/done emission), so a throw
|
|
225
|
+
// here can hang a turn — it must not be buried at debug level.
|
|
226
|
+
warn("mind", `session "${session.name}": event handler error (${event?.type}):`, err);
|
|
186
227
|
}
|
|
187
228
|
};
|
|
188
229
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { ExtensionFactory } from "@earendil-works/pi-coding-agent";
|
|
2
2
|
import type { EventSession } from "./event-handler.js";
|
|
3
|
+
import { firstReplyableEntry, isEventTurn } from "./event-turn.js";
|
|
3
4
|
import { log } from "./logger.js";
|
|
4
5
|
import { loadPrompts } from "./startup.js";
|
|
5
6
|
|
|
@@ -14,11 +15,37 @@ export function createReplyInstructionsExtension(
|
|
|
14
15
|
const prompts = loadPrompts();
|
|
15
16
|
return (pi) => {
|
|
16
17
|
let fired = false;
|
|
18
|
+
let eventNoteFired = false;
|
|
17
19
|
pi.on("before_agent_start", () => {
|
|
18
20
|
try {
|
|
21
|
+
const entries = [...messageChannels.values()];
|
|
22
|
+
|
|
23
|
+
// System-event turn: ambient, from the environment, with no channel to reply to.
|
|
24
|
+
// The note fires once per session (see event-turn.ts for why).
|
|
25
|
+
if (isEventTurn(entries)) {
|
|
26
|
+
if (eventNoteFired) return {};
|
|
27
|
+
eventNoteFired = true;
|
|
28
|
+
const content = prompts.event_instructions;
|
|
29
|
+
if (emitContext && session) {
|
|
30
|
+
emitContext(session, {
|
|
31
|
+
type: "context",
|
|
32
|
+
content,
|
|
33
|
+
metadata: { source: "event-instructions" },
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
return {
|
|
37
|
+
message: {
|
|
38
|
+
customType: "event-instructions",
|
|
39
|
+
content,
|
|
40
|
+
display: true,
|
|
41
|
+
},
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
|
|
19
45
|
if (fired) return {};
|
|
20
46
|
|
|
21
|
-
|
|
47
|
+
// Reply instructions must name a channel the mind can actually send to.
|
|
48
|
+
const entry = firstReplyableEntry(entries);
|
|
22
49
|
if (!entry) return {};
|
|
23
50
|
|
|
24
51
|
fired = true;
|
package/dist/chunk-5KXCM5AW.js
DELETED
|
@@ -1,169 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
voluteSystemDir
|
|
4
|
-
} from "./chunk-WW6C3PLV.js";
|
|
5
|
-
|
|
6
|
-
// packages/daemon/src/lib/config/setup.ts
|
|
7
|
-
import { chmodSync, existsSync, mkdirSync, readFileSync, statSync, writeFileSync } from "fs";
|
|
8
|
-
import { resolve } from "path";
|
|
9
|
-
function configPath() {
|
|
10
|
-
return resolve(voluteSystemDir(), "config.json");
|
|
11
|
-
}
|
|
12
|
-
function secretsPath() {
|
|
13
|
-
return resolve(voluteSystemDir(), "secrets.json");
|
|
14
|
-
}
|
|
15
|
-
function hasEntries(obj) {
|
|
16
|
-
return !!obj && Object.keys(obj).length > 0;
|
|
17
|
-
}
|
|
18
|
-
function splitConfig(config) {
|
|
19
|
-
const publicConfig = { ...config };
|
|
20
|
-
const secrets = {};
|
|
21
|
-
if (config.ai) {
|
|
22
|
-
const { providers, ...rest } = config.ai;
|
|
23
|
-
publicConfig.ai = { ...rest, providers: {} };
|
|
24
|
-
if (hasEntries(providers)) secrets.ai = { providers };
|
|
25
|
-
}
|
|
26
|
-
if (config.imagegen) {
|
|
27
|
-
const { providers, ...rest } = config.imagegen;
|
|
28
|
-
publicConfig.imagegen = { ...rest };
|
|
29
|
-
if (providers && Object.keys(providers).length > 0) secrets.imagegen = { providers };
|
|
30
|
-
}
|
|
31
|
-
if (config.backup) {
|
|
32
|
-
const { password, env, ...rest } = config.backup;
|
|
33
|
-
publicConfig.backup = { ...rest };
|
|
34
|
-
if (password || hasEntries(env)) {
|
|
35
|
-
secrets.backup = {};
|
|
36
|
-
if (password) secrets.backup.password = password;
|
|
37
|
-
if (hasEntries(env)) secrets.backup.env = env;
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
return { publicConfig, secrets };
|
|
41
|
-
}
|
|
42
|
-
function mergeSecrets(publicConfig, secrets) {
|
|
43
|
-
const merged = { ...publicConfig };
|
|
44
|
-
if (secrets.ai?.providers) {
|
|
45
|
-
merged.ai = { ...merged.ai ?? { providers: {} }, providers: secrets.ai.providers };
|
|
46
|
-
}
|
|
47
|
-
if (secrets.imagegen?.providers) {
|
|
48
|
-
merged.imagegen = { ...merged.imagegen ?? {}, providers: secrets.imagegen.providers };
|
|
49
|
-
}
|
|
50
|
-
if (secrets.backup) {
|
|
51
|
-
merged.backup = { ...merged.backup ?? {}, ...secrets.backup };
|
|
52
|
-
}
|
|
53
|
-
return merged;
|
|
54
|
-
}
|
|
55
|
-
function readSecrets() {
|
|
56
|
-
const path = secretsPath();
|
|
57
|
-
if (!existsSync(path)) return {};
|
|
58
|
-
try {
|
|
59
|
-
return JSON.parse(readFileSync(path, "utf-8"));
|
|
60
|
-
} catch {
|
|
61
|
-
return {};
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
var _cachedConfig = null;
|
|
65
|
-
var CONFIG_CACHE_TTL = 2e3;
|
|
66
|
-
function _resetConfigCache() {
|
|
67
|
-
_cachedConfig = null;
|
|
68
|
-
}
|
|
69
|
-
function readGlobalConfig() {
|
|
70
|
-
if (_cachedConfig && Date.now() - _cachedConfig.ts < CONFIG_CACHE_TTL) {
|
|
71
|
-
return { ..._cachedConfig.config };
|
|
72
|
-
}
|
|
73
|
-
const path = configPath();
|
|
74
|
-
if (!existsSync(path)) {
|
|
75
|
-
_cachedConfig = null;
|
|
76
|
-
return {};
|
|
77
|
-
}
|
|
78
|
-
let publicConfig;
|
|
79
|
-
try {
|
|
80
|
-
publicConfig = JSON.parse(readFileSync(path, "utf-8"));
|
|
81
|
-
} catch (err) {
|
|
82
|
-
console.error(`Failed to parse ${path}: ${err instanceof Error ? err.message : err}`);
|
|
83
|
-
return {};
|
|
84
|
-
}
|
|
85
|
-
const config = mergeSecrets(publicConfig, readSecrets());
|
|
86
|
-
_cachedConfig = { config, ts: Date.now() };
|
|
87
|
-
return config;
|
|
88
|
-
}
|
|
89
|
-
function writeGlobalConfig(config) {
|
|
90
|
-
mkdirSync(voluteSystemDir(), { recursive: true });
|
|
91
|
-
const { publicConfig, secrets } = splitConfig(config);
|
|
92
|
-
const cfgPath = configPath();
|
|
93
|
-
writeFileSync(cfgPath, `${JSON.stringify(publicConfig, null, 2)}
|
|
94
|
-
`, { mode: 420 });
|
|
95
|
-
chmodSync(cfgPath, 420);
|
|
96
|
-
const secPath = secretsPath();
|
|
97
|
-
writeFileSync(secPath, `${JSON.stringify(secrets, null, 2)}
|
|
98
|
-
`, { mode: 384 });
|
|
99
|
-
chmodSync(secPath, 384);
|
|
100
|
-
_cachedConfig = { config, ts: Date.now() };
|
|
101
|
-
}
|
|
102
|
-
function migrateConfigSecrets() {
|
|
103
|
-
const path = configPath();
|
|
104
|
-
if (!existsSync(path)) return;
|
|
105
|
-
let raw;
|
|
106
|
-
try {
|
|
107
|
-
raw = readFileSync(path, "utf-8");
|
|
108
|
-
} catch {
|
|
109
|
-
return;
|
|
110
|
-
}
|
|
111
|
-
let parsed;
|
|
112
|
-
try {
|
|
113
|
-
parsed = JSON.parse(raw);
|
|
114
|
-
} catch {
|
|
115
|
-
return;
|
|
116
|
-
}
|
|
117
|
-
const embedsSecrets = hasEntries(parsed.ai?.providers) || hasEntries(parsed.imagegen?.providers) || !!parsed.backup?.password || hasEntries(parsed.backup?.env);
|
|
118
|
-
const mode = statSync(path).mode & 511;
|
|
119
|
-
if (!embedsSecrets && mode === 420) return;
|
|
120
|
-
_resetConfigCache();
|
|
121
|
-
writeGlobalConfig(readGlobalConfig());
|
|
122
|
-
}
|
|
123
|
-
function setupStatus() {
|
|
124
|
-
const config = readGlobalConfig();
|
|
125
|
-
if (config.setupCompleted === true) return "complete";
|
|
126
|
-
if (config.setup != null && config.setupCompleted == null) return "complete";
|
|
127
|
-
if (config.setup != null) return "in-progress";
|
|
128
|
-
return "none";
|
|
129
|
-
}
|
|
130
|
-
function isSetupComplete() {
|
|
131
|
-
return setupStatus() === "complete";
|
|
132
|
-
}
|
|
133
|
-
function setupUrl() {
|
|
134
|
-
const config = readGlobalConfig();
|
|
135
|
-
const port = config.port || 1618;
|
|
136
|
-
let host = config.hostname || "127.0.0.1";
|
|
137
|
-
if (host === "0.0.0.0" || host === "::") host = "localhost";
|
|
138
|
-
if (host.includes(":") && !host.startsWith("[")) host = `[${host}]`;
|
|
139
|
-
return `http://${host}:${port}`;
|
|
140
|
-
}
|
|
141
|
-
function isImagegenEnabled() {
|
|
142
|
-
const config = readGlobalConfig();
|
|
143
|
-
const ig = config.imagegen;
|
|
144
|
-
if (!ig) return false;
|
|
145
|
-
if (ig.enabled === true) return true;
|
|
146
|
-
if (ig.providers && Object.keys(ig.providers).length > 0) return true;
|
|
147
|
-
return false;
|
|
148
|
-
}
|
|
149
|
-
function migrateSetupCompleted() {
|
|
150
|
-
const config = readGlobalConfig();
|
|
151
|
-
if (config.setup != null && config.setupCompleted == null) {
|
|
152
|
-
config.setupCompleted = true;
|
|
153
|
-
writeGlobalConfig(config);
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
export {
|
|
158
|
-
configPath,
|
|
159
|
-
secretsPath,
|
|
160
|
-
_resetConfigCache,
|
|
161
|
-
readGlobalConfig,
|
|
162
|
-
writeGlobalConfig,
|
|
163
|
-
migrateConfigSecrets,
|
|
164
|
-
setupStatus,
|
|
165
|
-
isSetupComplete,
|
|
166
|
-
setupUrl,
|
|
167
|
-
isImagegenEnabled,
|
|
168
|
-
migrateSetupCompleted
|
|
169
|
-
};
|
package/dist/chunk-IYCV34IU.js
DELETED
|
@@ -1,158 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
logger_default
|
|
4
|
-
} from "./chunk-T2TP6ZC6.js";
|
|
5
|
-
import {
|
|
6
|
-
getDb
|
|
7
|
-
} from "./chunk-WW6C3PLV.js";
|
|
8
|
-
import {
|
|
9
|
-
mindNotices,
|
|
10
|
-
turns
|
|
11
|
-
} from "./chunk-2MJ7EOMT.js";
|
|
12
|
-
|
|
13
|
-
// packages/daemon/src/lib/daemon/notices.ts
|
|
14
|
-
import { and, asc, desc, eq, gt, inArray, lte, or, sql } from "drizzle-orm";
|
|
15
|
-
var nlog = logger_default.child("notices");
|
|
16
|
-
var MIND_LEVEL_SESSION = "";
|
|
17
|
-
var MAX_NOTICES_PER_SESSION = 100;
|
|
18
|
-
async function recordNotice(input) {
|
|
19
|
-
try {
|
|
20
|
-
const db = await getDb();
|
|
21
|
-
await db.insert(mindNotices).values({
|
|
22
|
-
mind: input.mind,
|
|
23
|
-
session: input.session,
|
|
24
|
-
kind: input.kind,
|
|
25
|
-
reason: input.reason,
|
|
26
|
-
detail: input.detail,
|
|
27
|
-
raw: input.raw ?? null
|
|
28
|
-
});
|
|
29
|
-
await db.run(
|
|
30
|
-
sql`DELETE FROM mind_notices WHERE mind = ${input.mind} AND session = ${input.session} AND id NOT IN (SELECT id FROM mind_notices WHERE mind = ${input.mind} AND session = ${input.session} ORDER BY id DESC LIMIT ${MAX_NOTICES_PER_SESSION})`
|
|
31
|
-
);
|
|
32
|
-
} catch (err) {
|
|
33
|
-
nlog.error(`failed to record notice for ${input.mind}:${input.session}`, logger_default.errorData(err));
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
async function drainNotices(mind, session, limit = MAX_NOTICES_PER_SESSION) {
|
|
37
|
-
const db = await getDb();
|
|
38
|
-
return db.select().from(mindNotices).where(
|
|
39
|
-
and(
|
|
40
|
-
eq(mindNotices.mind, mind),
|
|
41
|
-
or(eq(mindNotices.session, session), eq(mindNotices.session, MIND_LEVEL_SESSION))
|
|
42
|
-
)
|
|
43
|
-
).orderBy(asc(mindNotices.id)).limit(limit);
|
|
44
|
-
}
|
|
45
|
-
var FAILURE_KINDS = ["turn_error", "crash", "startup"];
|
|
46
|
-
var failureReadErrorLogged = false;
|
|
47
|
-
async function latestFailureNotice(mind) {
|
|
48
|
-
try {
|
|
49
|
-
const db = await getDb();
|
|
50
|
-
const rows = await db.select().from(mindNotices).where(and(eq(mindNotices.mind, mind), inArray(mindNotices.kind, [...FAILURE_KINDS]))).orderBy(desc(mindNotices.id)).limit(1);
|
|
51
|
-
const n = rows[0];
|
|
52
|
-
if (!n) return null;
|
|
53
|
-
const recovered = await db.select({ id: turns.id }).from(turns).where(
|
|
54
|
-
and(eq(turns.mind, mind), eq(turns.status, "complete"), gt(turns.created_at, n.created_at))
|
|
55
|
-
).limit(1);
|
|
56
|
-
if (recovered.length > 0) return null;
|
|
57
|
-
return {
|
|
58
|
-
kind: n.kind,
|
|
59
|
-
reason: n.reason,
|
|
60
|
-
detail: n.detail,
|
|
61
|
-
at: n.created_at
|
|
62
|
-
};
|
|
63
|
-
} catch (err) {
|
|
64
|
-
if (!failureReadErrorLogged) {
|
|
65
|
-
failureReadErrorLogged = true;
|
|
66
|
-
nlog.error(`failed to read latest failure notice for ${mind}`, logger_default.errorData(err));
|
|
67
|
-
}
|
|
68
|
-
return null;
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
async function latestNotice(mind) {
|
|
72
|
-
const db = await getDb();
|
|
73
|
-
const row = await db.select().from(mindNotices).where(eq(mindNotices.mind, mind)).orderBy(desc(mindNotices.id)).limit(1).get();
|
|
74
|
-
return row ?? null;
|
|
75
|
-
}
|
|
76
|
-
async function hasUndeliveredNotice(mind, reason) {
|
|
77
|
-
const db = await getDb();
|
|
78
|
-
const row = await db.select({ id: mindNotices.id }).from(mindNotices).where(and(eq(mindNotices.mind, mind), eq(mindNotices.reason, reason))).limit(1).get();
|
|
79
|
-
return row != null;
|
|
80
|
-
}
|
|
81
|
-
async function clearDeliveredNotices(mind, session, uptoId) {
|
|
82
|
-
try {
|
|
83
|
-
const db = await getDb();
|
|
84
|
-
await db.delete(mindNotices).where(
|
|
85
|
-
and(
|
|
86
|
-
eq(mindNotices.mind, mind),
|
|
87
|
-
or(eq(mindNotices.session, session), eq(mindNotices.session, MIND_LEVEL_SESSION)),
|
|
88
|
-
lte(mindNotices.id, uptoId)
|
|
89
|
-
)
|
|
90
|
-
);
|
|
91
|
-
} catch (err) {
|
|
92
|
-
nlog.warn(`failed to clear delivered notices for ${mind}:${session}`, logger_default.errorData(err));
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
var NOTICE_HEADER = "[Notices] While you were unavailable, one or more turns failed. You're back now:";
|
|
96
|
-
function formatNotices(notices) {
|
|
97
|
-
if (notices.length === 0) return null;
|
|
98
|
-
const failures = notices.filter((n) => n.kind !== "extension" && n.kind !== "budget");
|
|
99
|
-
const budgets = notices.filter((n) => n.kind === "budget");
|
|
100
|
-
const extensions = notices.filter((n) => n.kind === "extension");
|
|
101
|
-
const blocks = [];
|
|
102
|
-
if (failures.length > 0) {
|
|
103
|
-
const groups = /* @__PURE__ */ new Map();
|
|
104
|
-
for (const n of failures) {
|
|
105
|
-
const time = localHM(n.created_at);
|
|
106
|
-
const g = groups.get(n.reason);
|
|
107
|
-
if (g) {
|
|
108
|
-
g.count += 1;
|
|
109
|
-
g.detail = n.detail;
|
|
110
|
-
g.last = time;
|
|
111
|
-
} else {
|
|
112
|
-
groups.set(n.reason, { count: 1, detail: n.detail, first: time, last: time });
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
const lines = [...groups.values()].map((g) => {
|
|
116
|
-
const span = g.first === g.last ? g.first : `${g.first}\u2013${g.last}`;
|
|
117
|
-
const plural = g.count === 1 ? "turn" : "turns";
|
|
118
|
-
return `- ${g.count} ${plural} failed (${span}): ${g.detail}`;
|
|
119
|
-
});
|
|
120
|
-
blocks.push(`${NOTICE_HEADER}
|
|
121
|
-
${lines.join("\n")}`);
|
|
122
|
-
}
|
|
123
|
-
if (budgets.length > 0) {
|
|
124
|
-
const lines = budgets.map((n) => `- ${localHM(n.created_at)} ${n.detail}`);
|
|
125
|
-
blocks.push(`[Budget]
|
|
126
|
-
${lines.join("\n")}`);
|
|
127
|
-
}
|
|
128
|
-
if (extensions.length > 0) {
|
|
129
|
-
const byExt = /* @__PURE__ */ new Map();
|
|
130
|
-
for (const n of extensions) {
|
|
131
|
-
const arr = byExt.get(n.reason);
|
|
132
|
-
if (arr) arr.push(n);
|
|
133
|
-
else byExt.set(n.reason, [n]);
|
|
134
|
-
}
|
|
135
|
-
for (const [ext, items] of byExt) {
|
|
136
|
-
const header = `[${ext.charAt(0).toUpperCase()}${ext.slice(1)}]`;
|
|
137
|
-
const lines = items.map((n) => `- ${localHM(n.created_at)} ${n.detail}`);
|
|
138
|
-
blocks.push(`${header}
|
|
139
|
-
${lines.join("\n")}`);
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
return blocks.join("\n\n");
|
|
143
|
-
}
|
|
144
|
-
function localHM(createdAt) {
|
|
145
|
-
const iso = createdAt.endsWith("Z") ? createdAt : `${createdAt.replace(" ", "T")}Z`;
|
|
146
|
-
return new Date(iso).toLocaleTimeString("en-GB", { hour: "2-digit", minute: "2-digit" });
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
export {
|
|
150
|
-
MIND_LEVEL_SESSION,
|
|
151
|
-
recordNotice,
|
|
152
|
-
drainNotices,
|
|
153
|
-
latestFailureNotice,
|
|
154
|
-
latestNotice,
|
|
155
|
-
hasUndeliveredNotice,
|
|
156
|
-
clearDeliveredNotices,
|
|
157
|
-
formatNotices
|
|
158
|
-
};
|