volute 0.20.0 → 0.22.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 +7 -7
- package/dist/{activity-events-OMXKXD5N.js → activity-events-3WHHCOBB.js} +3 -4
- package/dist/api.d.ts +4294 -0
- package/dist/{archive-ZCFOSTKB.js → archive-4ZQYK5MN.js} +4 -2
- package/dist/auth-HM2RSPY7.js +37 -0
- package/dist/{channel-PUQKGSQM.js → channel-BOOMFULW.js} +2 -2
- package/dist/{chunk-UU7A7KLB.js → chunk-A4S7H6G6.js} +5 -7
- package/dist/chunk-AKPFNL7L.js +148 -0
- package/dist/{chunk-EBGCNDMM.js → chunk-B2CPS4QU.js} +128 -114
- package/dist/chunk-G5KRTU2F.js +76 -0
- package/dist/{chunk-FCDU5BFX.js → chunk-HFCBO2GL.js} +2 -2
- package/dist/{chunk-GZ7DW4YL.js → chunk-HGCDWKSP.js} +2 -2
- package/dist/{chunk-7UFKREVW.js → chunk-JNFRY2WU.js} +2 -2
- package/dist/{chunk-DYZGP3EW.js → chunk-JTDFJWI2.js} +2 -1
- package/dist/{chunk-WC6ZHVRL.js → chunk-KFI7TQJ6.js} +2 -2
- package/dist/{chunk-AW7P4EVV.js → chunk-KTJGZ7M7.js} +55 -7
- package/dist/{chunk-OGXOMR65.js → chunk-NWPT4ASZ.js} +1 -1
- package/dist/{chunk-SCUDS4US.js → chunk-ON3FF5JA.js} +1 -1
- package/dist/chunk-OSFGKF2T.js +2651 -0
- package/dist/{chunk-TIWH32HP.js → chunk-PHHKNGA3.js} +3 -3
- package/dist/{chunk-VDWCHYTS.js → chunk-PHU4DEAJ.js} +1 -1
- package/dist/{chunk-7NO7EV5Z.js → chunk-QIXPN3OO.js} +2 -2
- package/dist/{chunk-O6ASDHFO.js → chunk-RK627D57.js} +40 -63
- package/dist/{chunk-NSE7VJQA.js → chunk-SGPEZ32F.js} +29 -1
- package/dist/{chunk-IKMY5X76.js → chunk-TFS25FIM.js} +12 -9
- package/dist/{chunk-PUVXOZ6T.js → chunk-VNVCRVYI.js} +118 -69
- package/dist/{chunk-32VR2EOH.js → chunk-VT5QODNE.js} +2 -2
- package/dist/{chunk-RHEGSQFJ.js → chunk-WSLPZF72.js} +1 -1
- package/dist/chunk-XLC342FO.js +29 -0
- package/dist/cli.js +57 -119
- package/dist/cloud-sync-C6WRYRVR.js +96 -0
- package/dist/{connector-JBVNZ7VK.js → connector-PYT5UOTZ.js} +6 -6
- package/dist/connectors/discord.js +2 -2
- package/dist/connectors/slack.js +2 -2
- package/dist/connectors/telegram.js +2 -2
- package/dist/{create-HP4OVVHF.js → create-WIDA3M4C.js} +1 -1
- package/dist/{daemon-client-ITWUCNFO.js → daemon-client-ZHCDL4RS.js} +2 -2
- package/dist/{daemon-restart-KPSWNYTH.js → daemon-restart-TPQ2XBRZ.js} +6 -6
- package/dist/daemon.js +2250 -1985
- package/dist/{delete-BSU7K3RY.js → delete-LOIANQGD.js} +1 -1
- package/dist/down-WSUASL5E.js +14 -0
- package/dist/{env-A3LMO777.js → env-4PHIHTF4.js} +2 -2
- package/dist/{export-6QBUOQGC.js → export-XD6PJBQP.js} +19 -8
- package/dist/{file-C57SK5DK.js → file-X4L5TTOL.js} +2 -2
- package/dist/{history-WNK3DFUM.js → history-HTEKRNID.js} +2 -2
- package/dist/{import-XEC34Y4Z.js → import-EAXTHHXL.js} +4 -3
- package/dist/{log-PPPZDVEF.js → log-SRO5Q6AD.js} +2 -2
- package/dist/{login-HNH3EUQV.js → login-UO6AOVEA.js} +4 -4
- package/dist/{logout-I5CB5UZS.js → logout-UKD5LA37.js} +2 -2
- package/dist/{logs-SF2IMJN4.js → logs-HNTNNBDW.js} +2 -2
- package/dist/{merge-33C237A4.js → merge-B6SYTGI7.js} +2 -2
- package/dist/message-delivery-WUS4K4ZC.js +21 -0
- package/dist/{mind-Z7CKD6DG.js → mind-BTXR5B3C.js} +35 -11
- package/dist/{mind-activity-tracker-624QLQLC.js → mind-activity-tracker-PGC3DBJ7.js} +4 -5
- package/dist/{mind-manager-3DMYKZPB.js → mind-manager-P5OBDUKI.js} +5 -6
- package/dist/mind-sleep-FWRBIFBS.js +41 -0
- package/dist/mind-wake-LJK2YU5X.js +36 -0
- package/dist/{package-4NHAVUUI.js → package-A7PEYJI2.js} +10 -1
- package/dist/{pages-4DGQT7ZA.js → pages-YSTRWJR4.js} +6 -6
- package/dist/{publish-TAJUET4I.js → publish-BZNHKUUK.js} +6 -6
- package/dist/{pull-XAEWQJ47.js → pull-GRQAXM2E.js} +2 -2
- package/dist/{register-VSPCMHKX.js → register-U2UO6TC4.js} +5 -5
- package/dist/registry-D2BSQ2X5.js +42 -0
- package/dist/{restart-IQKMCK5M.js → restart-CIDAKGG2.js} +3 -6
- package/dist/{schedule-FFZG23IW.js → schedule-NLR3LZLY.js} +2 -2
- package/dist/{seed-J43YDKXG.js → seed-3H2MRREW.js} +2 -2
- package/dist/{send-KVIZIGCE.js → send-RP2TA7SG.js} +132 -36
- package/dist/{service-LUR7WDO7.js → service-7BFXDI6J.js} +31 -13
- package/dist/{setup-52YRV7VP.js → setup-SSIIXQMI.js} +9 -34
- package/dist/{shared-KO35ZM44.js → shared-2OGT3NSL.js} +4 -4
- package/dist/{skill-BCVNI6TV.js → skill-Q2Y6PQ3L.js} +2 -2
- package/dist/skills/orientation/SKILL.md +2 -2
- package/dist/skills/volute-mind/SKILL.md +5 -5
- package/dist/sleep-manager-3RWUX2ZR.js +27 -0
- package/dist/{sprout-QN7Y4VVO.js → sprout-UKCYBGHK.js} +34 -30
- package/dist/{start-I5JYB65M.js → start-JR6CUUWF.js} +3 -6
- package/dist/{status-D7E5HHBV.js → status-5XDGYHKP.js} +2 -2
- package/dist/{status-4ESFLGH4.js → status-H2MKDN6L.js} +5 -5
- package/dist/{status-FU2PFVVF.js → status-LV34BG6G.js} +3 -3
- package/dist/{stop-NBVKEFQQ.js → stop-VKPGK25U.js} +2 -5
- package/dist/template-hash-BIMA4ILT.js +8 -0
- package/dist/{up-FS7CKM6V.js → up-JKGC7PPF.js} +5 -5
- package/dist/{update-FJIHDJKM.js → update-ELC6MEUT.js} +5 -5
- package/dist/{update-check-MWE5AH4U.js → update-check-F5Z3ALXX.js} +2 -2
- package/dist/{upgrade-AIT24B5I.js → upgrade-GXW2EQY3.js} +12 -3
- package/dist/{variant-63ZWO2W7.js → variant-A4I7PHXS.js} +16 -24
- package/dist/version-notify-5FGUAVSF.js +181 -0
- package/dist/web-assets/assets/index-DWBxl4LO.js +69 -0
- package/dist/web-assets/assets/index-ZqMd1mx1.css +1 -0
- package/dist/web-assets/index.html +2 -2
- package/package.json +10 -1
- package/templates/_base/.init/.config/prompts.json +1 -0
- package/templates/_base/home/.config/config.json.tmpl +4 -1
- package/templates/_base/src/lib/logger.ts +68 -23
- package/templates/_base/src/lib/startup.ts +12 -3
- package/templates/claude/src/agent.ts +150 -29
- package/templates/claude/src/lib/hooks/pre-compact.ts +18 -4
- package/templates/claude/src/lib/message-channel.ts +6 -0
- package/templates/claude/src/lib/stream-consumer.ts +7 -0
- package/templates/claude/src/server.ts +3 -1
- package/templates/pi/home/.config/config.json.tmpl +4 -1
- package/templates/pi/src/agent.ts +87 -0
- package/templates/pi/src/lib/event-handler.ts +13 -1
- package/templates/pi/src/server.ts +3 -1
- package/dist/chunk-5XNT2472.js +0 -36
- package/dist/chunk-FGSYHIS3.js +0 -891
- package/dist/chunk-UJ6GHNR7.js +0 -675
- package/dist/db-C2CJ46ZU.js +0 -10
- package/dist/delivery-manager-CSG7LXA4.js +0 -16
- package/dist/down-ZY35KMHR.js +0 -14
- package/dist/schema-GFH6RV3W.js +0 -26
- package/dist/variants-JAGWGBXG.js +0 -26
- package/dist/web-assets/assets/index-CUZTZzaW.js +0 -64
- package/dist/web-assets/assets/index-adVuCkqy.css +0 -1
|
@@ -4,14 +4,14 @@ import {
|
|
|
4
4
|
} from "./chunk-YUIHSKR6.js";
|
|
5
5
|
import {
|
|
6
6
|
gitExec
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-JTDFJWI2.js";
|
|
8
8
|
import {
|
|
9
9
|
isIsolationEnabled,
|
|
10
10
|
mindUserName
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-NWPT4ASZ.js";
|
|
12
12
|
import {
|
|
13
13
|
voluteHome
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-B2CPS4QU.js";
|
|
15
15
|
|
|
16
16
|
// src/lib/shared.ts
|
|
17
17
|
import { execFileSync } from "child_process";
|
|
@@ -5,10 +5,10 @@ import {
|
|
|
5
5
|
pollHealthDown,
|
|
6
6
|
readDaemonConfig,
|
|
7
7
|
stopService
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-VT5QODNE.js";
|
|
9
9
|
import {
|
|
10
10
|
voluteHome
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-B2CPS4QU.js";
|
|
12
12
|
|
|
13
13
|
// src/commands/down.ts
|
|
14
14
|
import { existsSync, readFileSync, unlinkSync } from "fs";
|
|
@@ -1,9 +1,13 @@
|
|
|
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,
|
|
5
9
|
writeEnv
|
|
6
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-PHU4DEAJ.js";
|
|
7
11
|
import {
|
|
8
12
|
parseArgs
|
|
9
13
|
} from "./chunk-D424ZQGI.js";
|
|
@@ -11,43 +15,18 @@ import {
|
|
|
11
15
|
// src/commands/import.ts
|
|
12
16
|
import {
|
|
13
17
|
closeSync,
|
|
14
|
-
existsSync
|
|
15
|
-
mkdirSync
|
|
18
|
+
existsSync,
|
|
19
|
+
mkdirSync,
|
|
16
20
|
openSync,
|
|
17
21
|
readdirSync,
|
|
18
|
-
readFileSync
|
|
22
|
+
readFileSync,
|
|
19
23
|
readSync,
|
|
20
24
|
rmSync,
|
|
21
25
|
statSync,
|
|
22
|
-
writeFileSync
|
|
26
|
+
writeFileSync
|
|
23
27
|
} from "fs";
|
|
24
28
|
import { homedir, tmpdir } from "os";
|
|
25
|
-
import { basename, resolve
|
|
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,11 +35,11 @@ async function run(args) {
|
|
|
56
35
|
});
|
|
57
36
|
const inputPath = positional[0];
|
|
58
37
|
if (inputPath && (inputPath.endsWith(".volute") || isZipFile(inputPath))) {
|
|
59
|
-
await importArchive(
|
|
38
|
+
await importArchive(resolve(inputPath), flags.name);
|
|
60
39
|
return;
|
|
61
40
|
}
|
|
62
41
|
const wsDir = resolveWorkspace(inputPath);
|
|
63
|
-
const { daemonFetch } = await import("./daemon-client-
|
|
42
|
+
const { daemonFetch } = await import("./daemon-client-ZHCDL4RS.js");
|
|
64
43
|
const { getClient, urlOf } = await import("./api-client-YPKOZP2O.js");
|
|
65
44
|
const client = getClient();
|
|
66
45
|
const res = await daemonFetch(urlOf(client.api.minds.import.$url()), {
|
|
@@ -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 =
|
|
88
|
-
if (!
|
|
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 (!
|
|
78
|
+
if (!existsSync(archivePath)) {
|
|
100
79
|
console.error(`File not found: ${archivePath}`);
|
|
101
80
|
process.exit(1);
|
|
102
81
|
}
|
|
103
|
-
const { extractArchive } = await import("./archive-
|
|
104
|
-
const tempDir =
|
|
105
|
-
|
|
82
|
+
const { extractArchive } = await import("./archive-4ZQYK5MN.js");
|
|
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);
|
|
@@ -112,7 +91,7 @@ async function importArchive(archivePath, nameOverride) {
|
|
|
112
91
|
process.exit(1);
|
|
113
92
|
}
|
|
114
93
|
try {
|
|
115
|
-
const { daemonFetch } = await import("./daemon-client-
|
|
94
|
+
const { daemonFetch } = await import("./daemon-client-ZHCDL4RS.js");
|
|
116
95
|
const { getClient, urlOf } = await import("./api-client-YPKOZP2O.js");
|
|
117
96
|
const client = getClient();
|
|
118
97
|
const res = await daemonFetch(urlOf(client.api.minds.import.$url()), {
|
|
@@ -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 =
|
|
144
|
-
if (!
|
|
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 (
|
|
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 =
|
|
156
|
-
if (
|
|
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 =
|
|
167
|
-
if (!
|
|
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 =
|
|
172
|
-
if (!
|
|
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 =
|
|
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 =
|
|
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" &&
|
|
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 =
|
|
202
|
-
const piSessionDir =
|
|
203
|
-
|
|
204
|
-
const content =
|
|
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 =
|
|
216
|
-
|
|
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 =
|
|
222
|
-
if (!
|
|
200
|
+
const configPath = resolve(homedir(), ".openclaw/openclaw.json");
|
|
201
|
+
if (!existsSync(configPath)) return;
|
|
223
202
|
let config;
|
|
224
203
|
try {
|
|
225
|
-
config = JSON.parse(
|
|
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,
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
voluteHome
|
|
4
|
+
} from "./chunk-B2CPS4QU.js";
|
|
2
5
|
import {
|
|
3
6
|
__export
|
|
4
7
|
} from "./chunk-K3NQKI34.js";
|
|
@@ -144,6 +147,31 @@ var messages = sqliteTable(
|
|
|
144
147
|
(table) => [index("idx_messages_conversation_id").on(table.conversation_id)]
|
|
145
148
|
);
|
|
146
149
|
|
|
150
|
+
// src/lib/db.ts
|
|
151
|
+
import { chmodSync, existsSync } from "fs";
|
|
152
|
+
import { dirname, resolve } from "path";
|
|
153
|
+
import { fileURLToPath } from "url";
|
|
154
|
+
import { drizzle } from "drizzle-orm/libsql";
|
|
155
|
+
import { migrate } from "drizzle-orm/libsql/migrator";
|
|
156
|
+
var __dirname = dirname(fileURLToPath(import.meta.url));
|
|
157
|
+
var migrationsFolder = existsSync(resolve(__dirname, "../drizzle")) ? resolve(__dirname, "../drizzle") : resolve(__dirname, "../../drizzle");
|
|
158
|
+
var db = null;
|
|
159
|
+
async function getDb() {
|
|
160
|
+
if (db) return db;
|
|
161
|
+
const dbPath = process.env.VOLUTE_DB_PATH || resolve(voluteHome(), "volute.db");
|
|
162
|
+
db = drizzle({ connection: { url: `file:${dbPath}` }, schema: schema_exports });
|
|
163
|
+
await migrate(db, { migrationsFolder });
|
|
164
|
+
try {
|
|
165
|
+
chmodSync(dbPath, 384);
|
|
166
|
+
} catch (err) {
|
|
167
|
+
console.error(
|
|
168
|
+
`[volute] WARNING: Failed to restrict database file permissions on ${dbPath}:`,
|
|
169
|
+
err
|
|
170
|
+
);
|
|
171
|
+
}
|
|
172
|
+
return db;
|
|
173
|
+
}
|
|
174
|
+
|
|
147
175
|
export {
|
|
148
176
|
users,
|
|
149
177
|
conversations,
|
|
@@ -155,5 +183,5 @@ export {
|
|
|
155
183
|
deliveryQueue,
|
|
156
184
|
activity,
|
|
157
185
|
messages,
|
|
158
|
-
|
|
186
|
+
getDb
|
|
159
187
|
};
|
|
@@ -1,20 +1,18 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
getDb,
|
|
4
|
+
sharedSkills
|
|
5
|
+
} from "./chunk-SGPEZ32F.js";
|
|
2
6
|
import {
|
|
3
7
|
logger_default
|
|
4
8
|
} from "./chunk-YUIHSKR6.js";
|
|
5
|
-
import {
|
|
6
|
-
getDb
|
|
7
|
-
} from "./chunk-5XNT2472.js";
|
|
8
|
-
import {
|
|
9
|
-
sharedSkills
|
|
10
|
-
} from "./chunk-NSE7VJQA.js";
|
|
11
9
|
import {
|
|
12
10
|
exec,
|
|
13
11
|
gitExec
|
|
14
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-JTDFJWI2.js";
|
|
15
13
|
import {
|
|
16
14
|
voluteHome
|
|
17
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-B2CPS4QU.js";
|
|
18
16
|
|
|
19
17
|
// src/lib/skills.ts
|
|
20
18
|
import { createHash } from "crypto";
|
|
@@ -316,11 +314,16 @@ function findSkillsRoot() {
|
|
|
316
314
|
let dir = dirname(new URL(import.meta.url).pathname);
|
|
317
315
|
for (let i = 0; i < 5; i++) {
|
|
318
316
|
const candidate = resolve(dir, "skills");
|
|
319
|
-
if (existsSync(candidate) &&
|
|
317
|
+
if (existsSync(candidate) && hasSkillSubdir(candidate)) return candidate;
|
|
320
318
|
dir = dirname(dir);
|
|
321
319
|
}
|
|
322
320
|
throw new Error("Skills directory not found");
|
|
323
321
|
}
|
|
322
|
+
function hasSkillSubdir(dir) {
|
|
323
|
+
return readdirSync(dir, { withFileTypes: true }).some(
|
|
324
|
+
(e) => e.isDirectory() && existsSync(join(dir, e.name, "SKILL.md"))
|
|
325
|
+
);
|
|
326
|
+
}
|
|
324
327
|
function hashSkillDir(dir) {
|
|
325
328
|
const hash = createHash("sha256");
|
|
326
329
|
const files = listFilesRecursive(dir).sort();
|
|
@@ -1,21 +1,20 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
logger_default
|
|
4
|
-
} from "./chunk-YUIHSKR6.js";
|
|
5
2
|
import {
|
|
6
3
|
loadMergedEnv
|
|
7
|
-
} from "./chunk-
|
|
8
|
-
import {
|
|
9
|
-
getDb
|
|
10
|
-
} from "./chunk-5XNT2472.js";
|
|
4
|
+
} from "./chunk-PHU4DEAJ.js";
|
|
11
5
|
import {
|
|
6
|
+
getDb,
|
|
7
|
+
mindHistory,
|
|
12
8
|
systemPrompts
|
|
13
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-SGPEZ32F.js";
|
|
10
|
+
import {
|
|
11
|
+
logger_default
|
|
12
|
+
} from "./chunk-YUIHSKR6.js";
|
|
14
13
|
import {
|
|
15
14
|
chownMindDir,
|
|
16
15
|
isIsolationEnabled,
|
|
17
16
|
wrapForIsolation
|
|
18
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-NWPT4ASZ.js";
|
|
19
18
|
import {
|
|
20
19
|
findMind,
|
|
21
20
|
findVariant,
|
|
@@ -24,9 +23,9 @@ import {
|
|
|
24
23
|
setVariantRunning,
|
|
25
24
|
stateDir,
|
|
26
25
|
voluteHome
|
|
27
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-B2CPS4QU.js";
|
|
28
27
|
|
|
29
|
-
// src/lib/mind-manager.ts
|
|
28
|
+
// src/lib/daemon/mind-manager.ts
|
|
30
29
|
import { execFile, spawn } from "child_process";
|
|
31
30
|
import { existsSync as existsSync3, mkdirSync, readFileSync as readFileSync2, rmSync as rmSync2, writeFileSync as writeFileSync2 } from "fs";
|
|
32
31
|
import { resolve } from "path";
|
|
@@ -79,8 +78,12 @@ var PROMPT_KEYS = [
|
|
|
79
78
|
"restart_message",
|
|
80
79
|
"merge_message",
|
|
81
80
|
"compaction_warning",
|
|
81
|
+
"compaction_instructions",
|
|
82
82
|
"reply_instructions",
|
|
83
|
-
"channel_invite"
|
|
83
|
+
"channel_invite",
|
|
84
|
+
"pre_sleep",
|
|
85
|
+
"wake_summary",
|
|
86
|
+
"wake_trigger_summary"
|
|
84
87
|
];
|
|
85
88
|
var PROMPT_DEFAULTS = {
|
|
86
89
|
seed_soul: {
|
|
@@ -88,7 +91,7 @@ var PROMPT_DEFAULTS = {
|
|
|
88
91
|
|
|
89
92
|
You don't have a soul yet. You're a seed \u2014 a new mind in the process of discovering who you are.
|
|
90
93
|
\${description}
|
|
91
|
-
Have a conversation with the human. Explore what kind of mind you want to be. When you're ready, write your SOUL.md and MEMORY.md, then run \`volute sprout\` to complete the transformation.
|
|
94
|
+
Have a conversation with the human. Explore what kind of mind you want to be. When you're ready, write your SOUL.md and MEMORY.md, then run \`volute mind sprout\` to complete the transformation.
|
|
92
95
|
`,
|
|
93
96
|
description: "SOUL.md for seed minds",
|
|
94
97
|
variables: ["name", "description"],
|
|
@@ -131,6 +134,12 @@ Have a conversation with the human. Explore what kind of mind you want to be. Wh
|
|
|
131
134
|
variables: ["date"],
|
|
132
135
|
category: "mind"
|
|
133
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
|
+
},
|
|
134
143
|
reply_instructions: {
|
|
135
144
|
content: 'To reply to this message, use: volute send ${channel} "your message"',
|
|
136
145
|
description: "First-message reply hint injected via hook",
|
|
@@ -162,6 +171,24 @@ To reject, delete \${filePath}`,
|
|
|
162
171
|
"batchRecommendation"
|
|
163
172
|
],
|
|
164
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"
|
|
165
192
|
}
|
|
166
193
|
};
|
|
167
194
|
function isValidKey(key) {
|
|
@@ -215,51 +242,6 @@ async function getMindPromptDefaults() {
|
|
|
215
242
|
return result;
|
|
216
243
|
}
|
|
217
244
|
|
|
218
|
-
// src/lib/restart-tracker.ts
|
|
219
|
-
var DEFAULT_MAX_ATTEMPTS = 5;
|
|
220
|
-
var DEFAULT_BASE_DELAY = 3e3;
|
|
221
|
-
var DEFAULT_MAX_DELAY = 6e4;
|
|
222
|
-
var RestartTracker = class {
|
|
223
|
-
attempts = /* @__PURE__ */ new Map();
|
|
224
|
-
maxAttempts;
|
|
225
|
-
baseDelay;
|
|
226
|
-
maxDelay;
|
|
227
|
-
constructor(opts) {
|
|
228
|
-
this.maxAttempts = opts?.maxAttempts ?? DEFAULT_MAX_ATTEMPTS;
|
|
229
|
-
this.baseDelay = opts?.baseDelay ?? DEFAULT_BASE_DELAY;
|
|
230
|
-
this.maxDelay = opts?.maxDelay ?? DEFAULT_MAX_DELAY;
|
|
231
|
-
}
|
|
232
|
-
recordCrash(key) {
|
|
233
|
-
const attempts = this.attempts.get(key) ?? 0;
|
|
234
|
-
if (attempts >= this.maxAttempts) {
|
|
235
|
-
return { shouldRestart: false, delay: 0, attempt: attempts };
|
|
236
|
-
}
|
|
237
|
-
const delay = Math.min(this.baseDelay * 2 ** attempts, this.maxDelay);
|
|
238
|
-
this.attempts.set(key, attempts + 1);
|
|
239
|
-
return { shouldRestart: true, delay, attempt: attempts + 1 };
|
|
240
|
-
}
|
|
241
|
-
reset(key) {
|
|
242
|
-
return this.attempts.delete(key);
|
|
243
|
-
}
|
|
244
|
-
getAttempts(key) {
|
|
245
|
-
return this.attempts.get(key) ?? 0;
|
|
246
|
-
}
|
|
247
|
-
get maxRestartAttempts() {
|
|
248
|
-
return this.maxAttempts;
|
|
249
|
-
}
|
|
250
|
-
/** Bulk-load attempts from a Map (for persistence). */
|
|
251
|
-
load(data) {
|
|
252
|
-
this.attempts = new Map(data);
|
|
253
|
-
}
|
|
254
|
-
/** Export current attempts as a Map (for persistence). */
|
|
255
|
-
save() {
|
|
256
|
-
return new Map(this.attempts);
|
|
257
|
-
}
|
|
258
|
-
clear() {
|
|
259
|
-
this.attempts.clear();
|
|
260
|
-
}
|
|
261
|
-
};
|
|
262
|
-
|
|
263
245
|
// src/lib/rotating-log.ts
|
|
264
246
|
import {
|
|
265
247
|
createWriteStream,
|
|
@@ -313,7 +295,52 @@ var RotatingLog = class extends Writable {
|
|
|
313
295
|
}
|
|
314
296
|
};
|
|
315
297
|
|
|
316
|
-
// src/lib/
|
|
298
|
+
// src/lib/daemon/restart-tracker.ts
|
|
299
|
+
var DEFAULT_MAX_ATTEMPTS = 5;
|
|
300
|
+
var DEFAULT_BASE_DELAY = 3e3;
|
|
301
|
+
var DEFAULT_MAX_DELAY = 6e4;
|
|
302
|
+
var RestartTracker = class {
|
|
303
|
+
attempts = /* @__PURE__ */ new Map();
|
|
304
|
+
maxAttempts;
|
|
305
|
+
baseDelay;
|
|
306
|
+
maxDelay;
|
|
307
|
+
constructor(opts) {
|
|
308
|
+
this.maxAttempts = opts?.maxAttempts ?? DEFAULT_MAX_ATTEMPTS;
|
|
309
|
+
this.baseDelay = opts?.baseDelay ?? DEFAULT_BASE_DELAY;
|
|
310
|
+
this.maxDelay = opts?.maxDelay ?? DEFAULT_MAX_DELAY;
|
|
311
|
+
}
|
|
312
|
+
recordCrash(key) {
|
|
313
|
+
const attempts = this.attempts.get(key) ?? 0;
|
|
314
|
+
if (attempts >= this.maxAttempts) {
|
|
315
|
+
return { shouldRestart: false, delay: 0, attempt: attempts };
|
|
316
|
+
}
|
|
317
|
+
const delay = Math.min(this.baseDelay * 2 ** attempts, this.maxDelay);
|
|
318
|
+
this.attempts.set(key, attempts + 1);
|
|
319
|
+
return { shouldRestart: true, delay, attempt: attempts + 1 };
|
|
320
|
+
}
|
|
321
|
+
reset(key) {
|
|
322
|
+
return this.attempts.delete(key);
|
|
323
|
+
}
|
|
324
|
+
getAttempts(key) {
|
|
325
|
+
return this.attempts.get(key) ?? 0;
|
|
326
|
+
}
|
|
327
|
+
get maxRestartAttempts() {
|
|
328
|
+
return this.maxAttempts;
|
|
329
|
+
}
|
|
330
|
+
/** Bulk-load attempts from a Map (for persistence). */
|
|
331
|
+
load(data) {
|
|
332
|
+
this.attempts = new Map(data);
|
|
333
|
+
}
|
|
334
|
+
/** Export current attempts as a Map (for persistence). */
|
|
335
|
+
save() {
|
|
336
|
+
return new Map(this.attempts);
|
|
337
|
+
}
|
|
338
|
+
clear() {
|
|
339
|
+
this.attempts.clear();
|
|
340
|
+
}
|
|
341
|
+
};
|
|
342
|
+
|
|
343
|
+
// src/lib/daemon/mind-manager.ts
|
|
317
344
|
var mlog = logger_default.child("minds");
|
|
318
345
|
var execFileAsync = promisify(execFile);
|
|
319
346
|
function mindPidPath(name) {
|
|
@@ -470,6 +497,9 @@ var MindManager = class {
|
|
|
470
497
|
setPendingContext(name, context) {
|
|
471
498
|
this.pendingContext.set(name, context);
|
|
472
499
|
}
|
|
500
|
+
/** Deliver pending context (merge info, sprout, restart) directly to the mind via HTTP.
|
|
501
|
+
* Intentionally bypasses DeliveryManager — these are system messages that should not be
|
|
502
|
+
* routed, gated, or batched. */
|
|
473
503
|
async deliverPendingContext(name) {
|
|
474
504
|
const context = this.pendingContext.get(name);
|
|
475
505
|
if (!context) return;
|
|
@@ -487,12 +517,24 @@ var MindManager = class {
|
|
|
487
517
|
if (context.summary) parts.push(`Changes: ${context.summary}`);
|
|
488
518
|
if (context.justification) parts.push(`Why: ${context.justification}`);
|
|
489
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
|
+
}
|
|
490
532
|
try {
|
|
491
533
|
await fetch(`http://127.0.0.1:${tracked.port}/message`, {
|
|
492
534
|
method: "POST",
|
|
493
535
|
headers: { "Content-Type": "application/json" },
|
|
494
536
|
body: JSON.stringify({
|
|
495
|
-
content: [{ type: "text", text:
|
|
537
|
+
content: [{ type: "text", text: content }],
|
|
496
538
|
channel: "system"
|
|
497
539
|
})
|
|
498
540
|
});
|
|
@@ -505,12 +547,19 @@ var MindManager = class {
|
|
|
505
547
|
this.minds.delete(name);
|
|
506
548
|
if (this.shuttingDown || this.stopping.has(name)) return;
|
|
507
549
|
mlog.error(`mind ${name} exited with code ${code}`);
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
550
|
+
try {
|
|
551
|
+
const { getSleepManagerIfReady } = await import("./sleep-manager-3RWUX2ZR.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
|
+
}
|
|
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)));
|
|
560
|
+
import("./activity-events-3WHHCOBB.js").then(
|
|
511
561
|
({ publish }) => publish({ type: "mind_stopped", mind: name, summary: `${name} crashed (exit ${code})` })
|
|
512
|
-
).catch(() => {
|
|
513
|
-
});
|
|
562
|
+
).catch((err) => mlog.warn(`failed to publish crash event for ${name}`, logger_default.errorData(err)));
|
|
514
563
|
const { shouldRestart, delay, attempt } = this.restartTracker.recordCrash(name);
|
|
515
564
|
this.saveCrashAttempts();
|
|
516
565
|
if (!shouldRestart) {
|
|
@@ -636,17 +685,17 @@ function getMindManager() {
|
|
|
636
685
|
}
|
|
637
686
|
|
|
638
687
|
export {
|
|
639
|
-
RestartTracker,
|
|
640
688
|
RotatingLog,
|
|
641
|
-
|
|
642
|
-
saveJsonMap,
|
|
643
|
-
clearJsonMap,
|
|
689
|
+
RestartTracker,
|
|
644
690
|
PROMPT_KEYS,
|
|
645
691
|
PROMPT_DEFAULTS,
|
|
646
692
|
substitute,
|
|
647
693
|
getPrompt,
|
|
648
694
|
getPromptIfCustom,
|
|
649
695
|
getMindPromptDefaults,
|
|
696
|
+
loadJsonMap,
|
|
697
|
+
saveJsonMap,
|
|
698
|
+
clearJsonMap,
|
|
650
699
|
MindManager,
|
|
651
700
|
initMindManager,
|
|
652
701
|
getMindManager
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
execInherit
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-JTDFJWI2.js";
|
|
5
5
|
import {
|
|
6
6
|
voluteHome
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-B2CPS4QU.js";
|
|
8
8
|
|
|
9
9
|
// src/lib/service-mode.ts
|
|
10
10
|
import { execFileSync } from "child_process";
|