volute 0.26.0 → 0.28.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 +18 -18
- package/dist/accept-666DIZX2.js +41 -0
- package/dist/{activity-events-ZMBAKLUF.js → activity-events-BBIEA2F4.js} +2 -3
- package/dist/api.d.ts +510 -299
- package/dist/{archive-4ZQYK5MN.js → archive-UA4BDFXQ.js} +2 -2
- package/dist/bridge-FQHZL3MC.js +206 -0
- package/dist/chat-M4SX42JD.js +68 -0
- package/dist/{chunk-PHU4DEAJ.js → chunk-2WPW7OT6.js} +3 -3
- package/dist/{chunk-5Y3PBKW6.js → chunk-2YP2TVDT.js} +138 -56
- package/dist/{chunk-3CFRE2VC.js → chunk-AAPXKR5V.js} +435 -1090
- package/dist/{chunk-YJA7P64S.js → chunk-AW7PFDVN.js} +5 -5
- package/dist/{chunk-OZFKBXD6.js → chunk-EHYDTZTF.js} +6 -6
- package/dist/{chunk-WBHMQ5OZ.js → chunk-H7OZRFJB.js} +192 -12
- package/dist/{chunk-ON3FF5JA.js → chunk-HDN7MNGD.js} +3 -3
- package/dist/chunk-IAYBDWVG.js +477 -0
- package/dist/{chunk-TZKJLDQN.js → chunk-IKRVFPWU.js} +14 -9
- package/dist/{chunk-UTL75LP6.js → chunk-J4IBNXGJ.js} +20 -22
- package/dist/{chunk-WGOGUMPO.js → chunk-JGFVMROS.js} +13 -6
- package/dist/{chunk-NWI2425I.js → chunk-K5NAC55T.js} +1 -1
- package/dist/chunk-KTLFDYPT.js +61 -0
- package/dist/{chunk-V63B7DX3.js → chunk-LAC664WU.js} +7 -4
- package/dist/chunk-MD4C26II.js +128 -0
- package/dist/{chunk-USNBKHYG.js → chunk-NI5FFCCS.js} +12 -7
- package/dist/{chunk-3TV4GLFO.js → chunk-P72MVS4R.js} +4 -43
- package/dist/{chunk-2VO7453N.js → chunk-POSXWWTA.js} +30 -54
- package/dist/{chunk-XOXLRRR2.js → chunk-RKQEHRBB.js} +4 -3
- package/dist/{chunk-LX22GRG7.js → chunk-SGVNFZHW.js} +11 -8
- package/dist/chunk-T6HKBWXZ.js +23 -0
- package/dist/{chunk-J2CO4WEV.js → chunk-VIVMW2H2.js} +4 -4
- package/dist/{chunk-KTJGZ7M7.js → chunk-XBLSAVJF.js} +1 -1
- package/dist/cli.js +32 -49
- package/dist/{cloud-sync-NI2K3C7G.js → cloud-sync-HDL6PHZI.js} +14 -14
- package/dist/connectors/discord-bridge.js +158 -0
- package/dist/connectors/slack-bridge.js +119 -0
- package/dist/connectors/telegram-bridge.js +133 -0
- package/dist/conversations-M2K4253F.js +55 -0
- package/dist/create-D7J73A6H.js +45 -0
- package/dist/{create-4YBRTTJS.js → create-QWV73WXD.js} +1 -1
- package/dist/{daemon-client-Z7FAJ6JW.js → daemon-client-I42FK2BF.js} +2 -2
- package/dist/{daemon-restart-BJZ3O4U4.js → daemon-restart-G4B2OYAB.js} +7 -7
- package/dist/daemon.js +1889 -1216
- package/dist/db-IC4J52XQ.js +8 -0
- package/dist/{delete-27OYNK25.js → delete-4JYGD4VN.js} +1 -1
- package/dist/down-LVBXEULC.js +14 -0
- package/dist/{env-M336ONDP.js → env-YJMUMFIY.js} +2 -2
- package/dist/{export-HP4G5DQC.js → export-BOJQWBMA.js} +4 -4
- package/dist/files-M546TKVN.js +46 -0
- package/dist/{history-B64GTFTD.js → history-ALPTNB3I.js} +5 -5
- package/dist/{import-XIB7UV4S.js → import-SRTQXBGH.js} +4 -4
- package/dist/join-J4QU42DL.js +66 -0
- package/dist/list-R73GENNL.js +40 -0
- package/dist/{login-B5E7N7MY.js → login-3QZNR2DF.js} +4 -4
- package/dist/{login-6U7U6BNG.js → login-BKP3AFWN.js} +8 -18
- package/dist/logout-IQK7FNEK.js +20 -0
- package/dist/{logout-XSJRYS3U.js → logout-T53VKCPU.js} +4 -4
- package/dist/message-delivery-HV3S6HZV.js +24 -0
- package/dist/migrate-registry-to-db-XC7T5B7P.js +110 -0
- package/dist/{mind-HZ3QSDDJ.js → mind-S5V6CK5W.js} +29 -34
- package/dist/{mind-activity-tracker-4G6FURY2.js → mind-activity-tracker-EN6XNXPF.js} +3 -4
- package/dist/mind-list-UPJ75GPI.js +29 -0
- package/dist/mind-manager-S6ILZVX3.js +18 -0
- package/dist/{mind-sleep-DTV7L44D.js → mind-sleep-BTSWQNAC.js} +4 -4
- package/dist/mind-status-TK5AETEM.js +55 -0
- package/dist/{mind-wake-PFN4FN3T.js → mind-wake-SBAKIDVP.js} +4 -4
- package/dist/{notes-37FW2UR2.js → notes-XCER3I7M.js} +11 -21
- package/dist/{package-VZWLXPHV.js → package-CG4RWUGP.js} +1 -1
- package/dist/{pages-DIIT5HMQ.js → pages-KJDJX4TA.js} +5 -5
- package/dist/{publish-HQV7YREB.js → publish-ZZB33WP4.js} +9 -20
- package/dist/read-36UFXN3G.js +46 -0
- package/dist/{register-EFND67FQ.js → register-CHREOMJ3.js} +6 -25
- package/dist/{registry-D2BSQ2X5.js → registry-NDNOOYG4.js} +15 -9
- package/dist/reject-LXIZFJ4Q.js +39 -0
- package/dist/{restart-CCK7D6TV.js → restart-6ESL3NBO.js} +5 -5
- package/dist/{sandbox-EHGFF52K.js → sandbox-5BW5HPXM.js} +3 -3
- package/dist/{schedule-6F7ELB2M.js → schedule-QTJMFATP.js} +5 -5
- package/dist/{seed-E5OQGWX3.js → seed-SSUCYYDF.js} +2 -2
- package/dist/{send-IH6XZKPC.js → send-TAOEZ4NH.js} +87 -23
- package/dist/{setup-YGAAIKKZ.js → setup-JHL5ZEST.js} +2 -2
- package/dist/{setup-F6TWFYGQ.js → setup-RXYVGGT7.js} +9 -9
- package/dist/{skill-42LGFBQC.js → skill-AUAQTSP5.js} +5 -5
- package/dist/skills/dreaming/references/INSTALL.md +2 -2
- package/dist/skills/orientation/SKILL.md +3 -3
- package/dist/skills/shared-files/SKILL.md +44 -0
- package/dist/skills/shared-files/scripts/merge.ts +72 -0
- package/dist/skills/shared-files/scripts/pull.ts +52 -0
- package/dist/skills/volute-mind/SKILL.md +35 -34
- package/dist/sleep-manager-WMVG2VCL.js +28 -0
- package/dist/split-TKJ5OT3P.js +63 -0
- package/dist/{sprout-QL74KR2X.js → sprout-UNT7LKKE.js} +6 -7
- package/dist/{start-O5JQASRC.js → start-EUJSS5R4.js} +2 -2
- package/dist/status-NQJYR4BG.js +114 -0
- package/dist/{status-LV34BG6G.js → status-S7UUPNRW.js} +4 -14
- package/dist/{stop-2SOG5NYF.js → stop-3XAITBBF.js} +5 -5
- package/dist/systems-SMEFSHTA.js +60 -0
- package/dist/{tailscale-AJ4VL5XK.js → tailscale-NY5MUMY3.js} +1 -1
- package/dist/up-GM2JOH2Y.js +17 -0
- package/dist/{update-5VUDAI3D.js → update-PTSH22AZ.js} +9 -9
- package/dist/{update-check-F5Z3ALXX.js → update-check-64FWC4Y2.js} +2 -2
- package/dist/{upgrade-QCCO33BK.js → upgrade-HA47CS4C.js} +12 -5
- package/dist/variant-7TGZHOU3.js +41 -0
- package/dist/{version-notify-USFZBWMG.js → version-notify-JDUF4HQJ.js} +24 -29
- package/dist/web-assets/assets/index-BZGvToHi.css +1 -0
- package/dist/web-assets/assets/index-Cz4TrpzB.js +75 -0
- package/dist/web-assets/favicon.png +0 -0
- package/dist/web-assets/index.html +2 -2
- package/drizzle/0017_minds.sql +16 -0
- package/drizzle/meta/_journal.json +7 -0
- package/package.json +1 -1
- package/templates/_base/.init/.config/prompts.json +2 -2
- package/templates/_base/home/VOLUTE.md +5 -5
- package/templates/_base/src/lib/logger.ts +0 -4
- package/templates/_base/src/lib/startup.ts +2 -2
- package/dist/auth-4TV573WE.js +0 -37
- package/dist/channel-ZVZV42UD.js +0 -260
- package/dist/chunk-B2CPS4QU.js +0 -283
- package/dist/chunk-HFCBO2GL.js +0 -50
- package/dist/chunk-RWKVSSLY.js +0 -26
- package/dist/chunk-SIAG3QMM.js +0 -42
- package/dist/chunk-WSLPZF72.js +0 -173
- package/dist/connector-G722WXAU.js +0 -147
- package/dist/connectors/discord.js +0 -177
- package/dist/connectors/slack.js +0 -181
- package/dist/connectors/telegram.js +0 -187
- package/dist/down-7UKFMJJZ.js +0 -14
- package/dist/file-HUDKTRAS.js +0 -204
- package/dist/log-PBFNILJ4.js +0 -39
- package/dist/logout-UKD5LA37.js +0 -18
- package/dist/logs-3CART7O7.js +0 -77
- package/dist/merge-VK2HSKMA.js +0 -46
- package/dist/message-delivery-MS5JYPZX.js +0 -25
- package/dist/mind-manager-VVK67AY3.js +0 -19
- package/dist/pull-2MB4SK3C.js +0 -39
- package/dist/service-LLBV3R7M.js +0 -122
- package/dist/shared-UMO4S7CC.js +0 -39
- package/dist/sleep-manager-EE4NRN2Q.js +0 -29
- package/dist/status-FZBEBM7Q.js +0 -70
- package/dist/status-WXD4HXRL.js +0 -35
- package/dist/up-SDMCSVI3.js +0 -17
- package/dist/variant-WWLDY6D5.js +0 -207
- package/dist/web-assets/assets/index-CUQ31ieL.js +0 -69
- package/dist/web-assets/assets/index-CW8NSl1o.css +0 -1
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/connectors/bridge-sdk.ts
|
|
4
|
+
function loadBridgeEnv() {
|
|
5
|
+
const daemonUrl = process.env.VOLUTE_DAEMON_URL;
|
|
6
|
+
const daemonToken = process.env.VOLUTE_DAEMON_TOKEN;
|
|
7
|
+
const platform = process.env.VOLUTE_BRIDGE_PLATFORM;
|
|
8
|
+
if (!daemonUrl || !daemonToken || !platform) {
|
|
9
|
+
console.error(
|
|
10
|
+
"Missing required env vars: VOLUTE_DAEMON_URL, VOLUTE_DAEMON_TOKEN, VOLUTE_BRIDGE_PLATFORM"
|
|
11
|
+
);
|
|
12
|
+
process.exit(1);
|
|
13
|
+
}
|
|
14
|
+
return { daemonUrl, daemonToken, platform };
|
|
15
|
+
}
|
|
16
|
+
function getHeaders(env) {
|
|
17
|
+
return {
|
|
18
|
+
"Content-Type": "application/json",
|
|
19
|
+
Authorization: `Bearer ${env.daemonToken}`,
|
|
20
|
+
Origin: env.daemonUrl
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
async function sendToBridge(env, message) {
|
|
24
|
+
const url = `${env.daemonUrl}/api/bridges/${env.platform}/inbound`;
|
|
25
|
+
try {
|
|
26
|
+
const res = await fetch(url, {
|
|
27
|
+
method: "POST",
|
|
28
|
+
headers: getHeaders(env),
|
|
29
|
+
body: JSON.stringify(message)
|
|
30
|
+
});
|
|
31
|
+
if (!res.ok) {
|
|
32
|
+
const body = await res.text().catch(() => "");
|
|
33
|
+
console.error(`Bridge inbound returned ${res.status}: ${body}`);
|
|
34
|
+
return { ok: false, error: `Bridge returned ${res.status}` };
|
|
35
|
+
}
|
|
36
|
+
return await res.json();
|
|
37
|
+
} catch (err) {
|
|
38
|
+
const detail = err instanceof Error ? err.message : String(err);
|
|
39
|
+
console.error(`Failed to send bridge message: ${detail}`);
|
|
40
|
+
return { ok: false, error: `Failed to reach daemon: ${detail}` };
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
function onShutdown(cleanup) {
|
|
44
|
+
const handler = () => {
|
|
45
|
+
Promise.resolve(cleanup()).then(
|
|
46
|
+
() => process.exit(0),
|
|
47
|
+
(err) => {
|
|
48
|
+
console.error(`Shutdown error: ${err}`);
|
|
49
|
+
process.exit(1);
|
|
50
|
+
}
|
|
51
|
+
);
|
|
52
|
+
};
|
|
53
|
+
process.on("SIGINT", handler);
|
|
54
|
+
process.on("SIGTERM", handler);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export {
|
|
58
|
+
loadBridgeEnv,
|
|
59
|
+
sendToBridge,
|
|
60
|
+
onShutdown
|
|
61
|
+
};
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
execInherit
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-AW7PFDVN.js";
|
|
5
5
|
import {
|
|
6
|
-
voluteHome
|
|
7
|
-
|
|
6
|
+
voluteHome,
|
|
7
|
+
voluteSystemDir
|
|
8
|
+
} from "./chunk-H7OZRFJB.js";
|
|
8
9
|
|
|
9
10
|
// src/lib/service-mode.ts
|
|
10
11
|
import { execFileSync } from "child_process";
|
|
@@ -151,7 +152,9 @@ async function restartService(mode) {
|
|
|
151
152
|
}
|
|
152
153
|
}
|
|
153
154
|
function readDaemonConfig() {
|
|
154
|
-
const
|
|
155
|
+
const newPath = resolve(voluteSystemDir(), "daemon.json");
|
|
156
|
+
const legacyPath = resolve(voluteHome(), "daemon.json");
|
|
157
|
+
const configPath = existsSync(newPath) ? newPath : legacyPath;
|
|
155
158
|
if (!existsSync(configPath)) return { hostname: "127.0.0.1", port: 1618 };
|
|
156
159
|
try {
|
|
157
160
|
const config = JSON.parse(readFileSync(configPath, "utf-8"));
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
stateDir
|
|
4
|
+
} from "./chunk-H7OZRFJB.js";
|
|
5
|
+
|
|
6
|
+
// src/lib/file-sharing.ts
|
|
7
|
+
import { randomBytes } from "crypto";
|
|
8
|
+
import { existsSync, mkdirSync, readdirSync, readFileSync, rmSync, writeFileSync } from "fs";
|
|
9
|
+
import { basename, join, normalize, resolve } from "path";
|
|
10
|
+
function validateFilePath(filePath) {
|
|
11
|
+
if (!filePath) return "File path is required";
|
|
12
|
+
const normalized = normalize(filePath);
|
|
13
|
+
if (normalized.startsWith("/") || normalized.startsWith("\\")) {
|
|
14
|
+
return "Absolute paths are not allowed";
|
|
15
|
+
}
|
|
16
|
+
if (normalized.includes("..")) {
|
|
17
|
+
return "Path traversal (..) is not allowed";
|
|
18
|
+
}
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
function pendingDir(receiver) {
|
|
22
|
+
return resolve(stateDir(receiver), "pending-files");
|
|
23
|
+
}
|
|
24
|
+
function validateId(id) {
|
|
25
|
+
if (!id || id.includes("/") || id.includes("\\") || id.includes("..")) {
|
|
26
|
+
throw new Error("Invalid pending file id");
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
function generateId(sender) {
|
|
30
|
+
const ts = Date.now();
|
|
31
|
+
const rand = randomBytes(2).toString("hex");
|
|
32
|
+
return `${sender}-${ts}-${rand}`;
|
|
33
|
+
}
|
|
34
|
+
function stageFile(receiver, sender, filename, content, originalPath) {
|
|
35
|
+
const err = validateFilePath(filename);
|
|
36
|
+
if (err) throw new Error(err);
|
|
37
|
+
if (sender.includes("/") || sender.includes("\\")) {
|
|
38
|
+
throw new Error("Invalid sender name");
|
|
39
|
+
}
|
|
40
|
+
const id = generateId(sender);
|
|
41
|
+
const dir = resolve(pendingDir(receiver), id);
|
|
42
|
+
mkdirSync(dir, { recursive: true });
|
|
43
|
+
const metadata = {
|
|
44
|
+
id,
|
|
45
|
+
sender,
|
|
46
|
+
filename: basename(filename),
|
|
47
|
+
originalPath,
|
|
48
|
+
size: content.length,
|
|
49
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
50
|
+
};
|
|
51
|
+
writeFileSync(resolve(dir, "metadata.json"), `${JSON.stringify(metadata, null, 2)}
|
|
52
|
+
`);
|
|
53
|
+
writeFileSync(resolve(dir, "data"), content);
|
|
54
|
+
return { id };
|
|
55
|
+
}
|
|
56
|
+
function listPending(receiver) {
|
|
57
|
+
const dir = pendingDir(receiver);
|
|
58
|
+
if (!existsSync(dir)) return [];
|
|
59
|
+
const entries = readdirSync(dir, { withFileTypes: true });
|
|
60
|
+
const result = [];
|
|
61
|
+
for (const entry of entries) {
|
|
62
|
+
if (!entry.isDirectory()) continue;
|
|
63
|
+
const metaPath = resolve(dir, entry.name, "metadata.json");
|
|
64
|
+
if (!existsSync(metaPath)) continue;
|
|
65
|
+
try {
|
|
66
|
+
result.push(JSON.parse(readFileSync(metaPath, "utf-8")));
|
|
67
|
+
} catch (err) {
|
|
68
|
+
console.warn(`[file-sharing] skipping malformed pending entry ${entry.name}:`, err);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return result.sort((a, b) => a.createdAt.localeCompare(b.createdAt));
|
|
72
|
+
}
|
|
73
|
+
function getPending(receiver, id) {
|
|
74
|
+
validateId(id);
|
|
75
|
+
const metaPath = resolve(pendingDir(receiver), id, "metadata.json");
|
|
76
|
+
if (!existsSync(metaPath)) return null;
|
|
77
|
+
try {
|
|
78
|
+
return JSON.parse(readFileSync(metaPath, "utf-8"));
|
|
79
|
+
} catch (err) {
|
|
80
|
+
console.warn(`[file-sharing] failed to read pending metadata for ${id}:`, err);
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
function deliverFile(receiverDir, sender, filename, content, inboxPath) {
|
|
85
|
+
const err = validateFilePath(filename);
|
|
86
|
+
if (err) throw new Error(err);
|
|
87
|
+
const inbox = inboxPath ?? "inbox";
|
|
88
|
+
const inboxErr = validateFilePath(inbox);
|
|
89
|
+
if (inboxErr) throw new Error(`Invalid inboxPath: ${inboxErr}`);
|
|
90
|
+
if (sender.includes("/") || sender.includes("\\")) {
|
|
91
|
+
throw new Error("Invalid sender name");
|
|
92
|
+
}
|
|
93
|
+
const destDir = resolve(receiverDir, "home", inbox, sender);
|
|
94
|
+
mkdirSync(destDir, { recursive: true });
|
|
95
|
+
const destPath = resolve(destDir, basename(filename));
|
|
96
|
+
writeFileSync(destPath, content);
|
|
97
|
+
return join(inbox, sender, basename(filename));
|
|
98
|
+
}
|
|
99
|
+
function acceptPending(receiver, id, receiverDir, dest) {
|
|
100
|
+
const meta = getPending(receiver, id);
|
|
101
|
+
if (!meta) throw new Error(`Pending file not found: ${id}`);
|
|
102
|
+
const dataPath = resolve(pendingDir(receiver), id, "data");
|
|
103
|
+
const content = readFileSync(dataPath);
|
|
104
|
+
const inboxPath = dest ?? "inbox";
|
|
105
|
+
const destPath = deliverFile(receiverDir, meta.sender, meta.filename, content, inboxPath);
|
|
106
|
+
rmSync(resolve(pendingDir(receiver), id), { recursive: true });
|
|
107
|
+
return { sender: meta.sender, filename: meta.filename, destPath };
|
|
108
|
+
}
|
|
109
|
+
function rejectPending(receiver, id) {
|
|
110
|
+
const meta = getPending(receiver, id);
|
|
111
|
+
if (!meta) throw new Error(`Pending file not found: ${id}`);
|
|
112
|
+
rmSync(resolve(pendingDir(receiver), id), { recursive: true });
|
|
113
|
+
return { sender: meta.sender, filename: meta.filename };
|
|
114
|
+
}
|
|
115
|
+
function formatFileSize(bytes) {
|
|
116
|
+
if (bytes < 1024) return `${bytes} B`;
|
|
117
|
+
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
|
|
118
|
+
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
export {
|
|
122
|
+
validateFilePath,
|
|
123
|
+
stageFile,
|
|
124
|
+
listPending,
|
|
125
|
+
acceptPending,
|
|
126
|
+
rejectPending,
|
|
127
|
+
formatFileSize
|
|
128
|
+
};
|
|
@@ -1,18 +1,16 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
getDb,
|
|
4
|
-
sharedSkills
|
|
5
|
-
} from "./chunk-WBHMQ5OZ.js";
|
|
6
2
|
import {
|
|
7
3
|
logger_default
|
|
8
4
|
} from "./chunk-YUIHSKR6.js";
|
|
9
5
|
import {
|
|
10
6
|
exec,
|
|
11
7
|
gitExec
|
|
12
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-AW7PFDVN.js";
|
|
13
9
|
import {
|
|
10
|
+
getDb,
|
|
11
|
+
sharedSkills,
|
|
14
12
|
voluteHome
|
|
15
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-H7OZRFJB.js";
|
|
16
14
|
|
|
17
15
|
// src/lib/skills.ts
|
|
18
16
|
import { createHash } from "crypto";
|
|
@@ -30,7 +28,14 @@ import { basename, dirname, join, resolve } from "path";
|
|
|
30
28
|
import { eq, sql } from "drizzle-orm";
|
|
31
29
|
var VALID_SKILL_ID = /^[a-zA-Z0-9_-]+$/;
|
|
32
30
|
var SEED_SKILLS = ["orientation", "memory"];
|
|
33
|
-
var STANDARD_SKILLS = [
|
|
31
|
+
var STANDARD_SKILLS = [
|
|
32
|
+
"volute-mind",
|
|
33
|
+
"memory",
|
|
34
|
+
"sessions",
|
|
35
|
+
"notes",
|
|
36
|
+
"dreaming",
|
|
37
|
+
"shared-files"
|
|
38
|
+
];
|
|
34
39
|
function validateSkillId(id) {
|
|
35
40
|
if (!id || !VALID_SKILL_ID.test(id)) {
|
|
36
41
|
throw new Error(`Invalid skill ID: ${id}`);
|
|
@@ -4,14 +4,14 @@ import {
|
|
|
4
4
|
} from "./chunk-YUIHSKR6.js";
|
|
5
5
|
import {
|
|
6
6
|
gitExec
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-AW7PFDVN.js";
|
|
8
8
|
import {
|
|
9
9
|
isIsolationEnabled,
|
|
10
10
|
mindUserName
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-RKQEHRBB.js";
|
|
12
12
|
import {
|
|
13
13
|
voluteHome
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-H7OZRFJB.js";
|
|
15
15
|
|
|
16
16
|
// src/lib/shared.ts
|
|
17
17
|
import { execFileSync } from "child_process";
|
|
@@ -178,50 +178,11 @@ async function sharedMerge(mindName, mindDir, message) {
|
|
|
178
178
|
return { ok: true };
|
|
179
179
|
});
|
|
180
180
|
}
|
|
181
|
-
async function sharedPull(mindName, mindDir) {
|
|
182
|
-
return withSharedLock(async () => {
|
|
183
|
-
const worktreePath = resolve(mindDir, "home", "shared");
|
|
184
|
-
const status = (await gitExec(["status", "--porcelain"], { cwd: worktreePath })).trim();
|
|
185
|
-
if (status) {
|
|
186
|
-
await gitExec(["add", "-A"], { cwd: worktreePath });
|
|
187
|
-
await gitExec(
|
|
188
|
-
["commit", "--author", `${mindName} <${mindName}@volute>`, "-m", `wip: ${mindName}`],
|
|
189
|
-
{ cwd: worktreePath }
|
|
190
|
-
);
|
|
191
|
-
}
|
|
192
|
-
try {
|
|
193
|
-
await gitExec(["rebase", "main"], { cwd: worktreePath });
|
|
194
|
-
rechownWorktree(worktreePath, mindName);
|
|
195
|
-
return { ok: true };
|
|
196
|
-
} catch {
|
|
197
|
-
try {
|
|
198
|
-
await gitExec(["rebase", "--abort"], { cwd: worktreePath });
|
|
199
|
-
} catch {
|
|
200
|
-
return {
|
|
201
|
-
ok: false,
|
|
202
|
-
message: "Rebase failed and abort failed \u2014 shared worktree may need manual repair"
|
|
203
|
-
};
|
|
204
|
-
}
|
|
205
|
-
return { ok: false, message: "Rebase failed \u2014 conflicts with main" };
|
|
206
|
-
}
|
|
207
|
-
});
|
|
208
|
-
}
|
|
209
|
-
async function sharedLog(limit = 20) {
|
|
210
|
-
const dir = sharedDir();
|
|
211
|
-
return gitExec(["log", "--oneline", "-n", String(limit), "main"], { cwd: dir });
|
|
212
|
-
}
|
|
213
|
-
async function sharedStatus(mindName) {
|
|
214
|
-
const dir = sharedDir();
|
|
215
|
-
return gitExec(["diff", `main...${mindName}`, "--stat"], { cwd: dir });
|
|
216
|
-
}
|
|
217
181
|
|
|
218
182
|
export {
|
|
219
183
|
sharedDir,
|
|
220
184
|
ensureSharedRepo,
|
|
221
185
|
addSharedWorktree,
|
|
222
186
|
removeSharedWorktree,
|
|
223
|
-
sharedMerge
|
|
224
|
-
sharedPull,
|
|
225
|
-
sharedLog,
|
|
226
|
-
sharedStatus
|
|
187
|
+
sharedMerge
|
|
227
188
|
};
|
|
@@ -2,32 +2,28 @@
|
|
|
2
2
|
import {
|
|
3
3
|
isSandboxEnabled,
|
|
4
4
|
wrapForSandbox
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-J4IBNXGJ.js";
|
|
6
6
|
import {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
systemPrompts
|
|
10
|
-
} from "./chunk-WBHMQ5OZ.js";
|
|
7
|
+
loadMergedEnv
|
|
8
|
+
} from "./chunk-2WPW7OT6.js";
|
|
11
9
|
import {
|
|
12
10
|
logger_default
|
|
13
11
|
} from "./chunk-YUIHSKR6.js";
|
|
14
|
-
import {
|
|
15
|
-
loadMergedEnv
|
|
16
|
-
} from "./chunk-PHU4DEAJ.js";
|
|
17
12
|
import {
|
|
18
13
|
chownMindDir,
|
|
19
14
|
isIsolationEnabled,
|
|
20
15
|
wrapForIsolation
|
|
21
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-RKQEHRBB.js";
|
|
22
17
|
import {
|
|
23
18
|
findMind,
|
|
24
|
-
|
|
19
|
+
getDb,
|
|
25
20
|
mindDir,
|
|
21
|
+
mindHistory,
|
|
26
22
|
setMindRunning,
|
|
27
|
-
setVariantRunning,
|
|
28
23
|
stateDir,
|
|
29
|
-
|
|
30
|
-
|
|
24
|
+
systemPrompts,
|
|
25
|
+
voluteSystemDir
|
|
26
|
+
} from "./chunk-H7OZRFJB.js";
|
|
31
27
|
|
|
32
28
|
// src/lib/daemon/mind-manager.ts
|
|
33
29
|
import { execFile, spawn } from "child_process";
|
|
@@ -144,7 +140,7 @@ Have a conversation with the human. Explore what kind of mind you want to be. Wh
|
|
|
144
140
|
category: "mind"
|
|
145
141
|
},
|
|
146
142
|
reply_instructions: {
|
|
147
|
-
content: 'To reply to this message, use: volute send ${channel} "your message"',
|
|
143
|
+
content: 'To reply to this message, use: volute chat send ${channel} "your message"',
|
|
148
144
|
description: "First-message reply hint injected via hook",
|
|
149
145
|
variables: ["channel"],
|
|
150
146
|
category: "mind"
|
|
@@ -160,7 +156,7 @@ Further messages will be saved to \${filePath}
|
|
|
160
156
|
|
|
161
157
|
To accept, add to .config/routes.json:
|
|
162
158
|
Rule: { "channel": "\${channel}", "session": "\${suggestedSession}" }
|
|
163
|
-
\${batchRecommendation}To respond, use: volute send \${channel} "your message"
|
|
159
|
+
\${batchRecommendation}To respond, use: volute chat send \${channel} "your message"
|
|
164
160
|
To reject, delete \${filePath}`,
|
|
165
161
|
description: "New channel notification template",
|
|
166
162
|
variables: [
|
|
@@ -313,9 +309,6 @@ function revokeMindToken(mindName) {
|
|
|
313
309
|
function resolveMindToken(token) {
|
|
314
310
|
return tokenToMind.get(token) ?? null;
|
|
315
311
|
}
|
|
316
|
-
function getMindToken(mindName) {
|
|
317
|
-
return mindToToken.get(mindName) ?? null;
|
|
318
|
-
}
|
|
319
312
|
|
|
320
313
|
// src/lib/daemon/restart-tracker.ts
|
|
321
314
|
var DEFAULT_MAX_ATTEMPTS = 5;
|
|
@@ -374,25 +367,23 @@ var MindManager = class {
|
|
|
374
367
|
shuttingDown = false;
|
|
375
368
|
restartTracker = new RestartTracker();
|
|
376
369
|
pendingContext = /* @__PURE__ */ new Map();
|
|
377
|
-
resolveTarget(name) {
|
|
378
|
-
const
|
|
379
|
-
|
|
380
|
-
if (
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
if (!variant) throw new Error(`Unknown variant: ${variantName} (mind: ${baseName})`);
|
|
384
|
-
return { dir: variant.path, port: variant.port, isVariant: true, baseName, variantName };
|
|
370
|
+
async resolveTarget(name) {
|
|
371
|
+
const entry = await findMind(name);
|
|
372
|
+
if (!entry) throw new Error(`Unknown mind: ${name}`);
|
|
373
|
+
if (entry.parent) {
|
|
374
|
+
if (!entry.dir) throw new Error(`Variant ${name} has no directory`);
|
|
375
|
+
return { dir: entry.dir, port: entry.port, baseName: entry.parent };
|
|
385
376
|
}
|
|
386
|
-
const dir = mindDir(
|
|
377
|
+
const dir = mindDir(name);
|
|
387
378
|
if (!existsSync3(dir)) throw new Error(`Mind directory missing: ${dir}`);
|
|
388
|
-
return { dir, port: entry.port,
|
|
379
|
+
return { dir, port: entry.port, baseName: name };
|
|
389
380
|
}
|
|
390
381
|
async startMind(name) {
|
|
391
382
|
if (this.minds.has(name)) {
|
|
392
383
|
throw new Error(`Mind ${name} is already running`);
|
|
393
384
|
}
|
|
394
|
-
const target = this.resolveTarget(name);
|
|
395
|
-
const { dir,
|
|
385
|
+
const target = await this.resolveTarget(name);
|
|
386
|
+
const { dir, baseName } = target;
|
|
396
387
|
const port = target.port;
|
|
397
388
|
const pidFile = mindPidPath(name);
|
|
398
389
|
try {
|
|
@@ -463,7 +454,7 @@ var MindManager = class {
|
|
|
463
454
|
let spawnCmd;
|
|
464
455
|
let spawnArgs;
|
|
465
456
|
if (isIsolationEnabled()) {
|
|
466
|
-
[spawnCmd, spawnArgs] = wrapForIsolation(tsxBin, tsxArgs, name);
|
|
457
|
+
[spawnCmd, spawnArgs] = await wrapForIsolation(tsxBin, tsxArgs, name);
|
|
467
458
|
} else if (isSandboxEnabled()) {
|
|
468
459
|
[spawnCmd, spawnArgs] = await wrapForSandbox(tsxBin, tsxArgs, dir, name);
|
|
469
460
|
} else {
|
|
@@ -519,11 +510,7 @@ var MindManager = class {
|
|
|
519
510
|
}
|
|
520
511
|
if (this.restartTracker.reset(name)) this.saveCrashAttempts();
|
|
521
512
|
this.setupCrashRecovery(name, child);
|
|
522
|
-
|
|
523
|
-
setVariantRunning(baseName, variantName, true);
|
|
524
|
-
} else {
|
|
525
|
-
setMindRunning(name, true);
|
|
526
|
-
}
|
|
513
|
+
await setMindRunning(name, true);
|
|
527
514
|
mlog.info(`started mind ${name} on port ${port}`);
|
|
528
515
|
await this.deliverPendingContext(name);
|
|
529
516
|
}
|
|
@@ -581,7 +568,7 @@ var MindManager = class {
|
|
|
581
568
|
if (this.shuttingDown || this.stopping.has(name)) return;
|
|
582
569
|
mlog.error(`mind ${name} exited with code ${code}`);
|
|
583
570
|
try {
|
|
584
|
-
const { getSleepManagerIfReady } = await import("./sleep-manager-
|
|
571
|
+
const { getSleepManagerIfReady } = await import("./sleep-manager-WMVG2VCL.js");
|
|
585
572
|
const sleepState = getSleepManagerIfReady()?.getState(name);
|
|
586
573
|
if (sleepState?.sleeping) {
|
|
587
574
|
mlog.info(`${name} is sleeping \u2014 skipping crash recovery`);
|
|
@@ -590,20 +577,15 @@ var MindManager = class {
|
|
|
590
577
|
} catch (err) {
|
|
591
578
|
mlog.warn(`failed to check sleep state for ${name}`, logger_default.errorData(err));
|
|
592
579
|
}
|
|
593
|
-
import("./mind-activity-tracker-
|
|
594
|
-
import("./activity-events-
|
|
580
|
+
import("./mind-activity-tracker-EN6XNXPF.js").then(({ markIdle }) => markIdle(name)).catch((err) => mlog.warn(`failed to mark ${name} idle after crash`, logger_default.errorData(err)));
|
|
581
|
+
import("./activity-events-BBIEA2F4.js").then(
|
|
595
582
|
({ publish }) => publish({ type: "mind_stopped", mind: name, summary: `${name} crashed (exit ${code})` })
|
|
596
583
|
).catch((err) => mlog.warn(`failed to publish crash event for ${name}`, logger_default.errorData(err)));
|
|
597
584
|
const { shouldRestart, delay, attempt } = this.restartTracker.recordCrash(name);
|
|
598
585
|
this.saveCrashAttempts();
|
|
599
586
|
if (!shouldRestart) {
|
|
600
587
|
mlog.error(`${name} crashed ${attempt} times \u2014 giving up on restart`);
|
|
601
|
-
|
|
602
|
-
if (variant) {
|
|
603
|
-
setVariantRunning(base, variant, false);
|
|
604
|
-
} else {
|
|
605
|
-
setMindRunning(name, false);
|
|
606
|
-
}
|
|
588
|
+
await setMindRunning(name, false);
|
|
607
589
|
return;
|
|
608
590
|
}
|
|
609
591
|
mlog.info(
|
|
@@ -643,12 +625,7 @@ var MindManager = class {
|
|
|
643
625
|
if (this.restartTracker.reset(name)) this.saveCrashAttempts();
|
|
644
626
|
rmSync2(mindPidPath(name), { force: true });
|
|
645
627
|
if (!this.shuttingDown) {
|
|
646
|
-
|
|
647
|
-
if (variantName) {
|
|
648
|
-
setVariantRunning(baseName, variantName, false);
|
|
649
|
-
} else {
|
|
650
|
-
setMindRunning(name, false);
|
|
651
|
-
}
|
|
628
|
+
await setMindRunning(name, false);
|
|
652
629
|
}
|
|
653
630
|
mlog.info(`stopped mind ${name}`);
|
|
654
631
|
}
|
|
@@ -668,7 +645,7 @@ var MindManager = class {
|
|
|
668
645
|
return [...this.minds.keys()];
|
|
669
646
|
}
|
|
670
647
|
get crashAttemptsPath() {
|
|
671
|
-
return resolve(
|
|
648
|
+
return resolve(voluteSystemDir(), "crash-attempts.json");
|
|
672
649
|
}
|
|
673
650
|
loadCrashAttempts() {
|
|
674
651
|
this.restartTracker.load(loadJsonMap(this.crashAttemptsPath));
|
|
@@ -721,8 +698,6 @@ function getMindManager() {
|
|
|
721
698
|
|
|
722
699
|
export {
|
|
723
700
|
RotatingLog,
|
|
724
|
-
resolveMindToken,
|
|
725
|
-
getMindToken,
|
|
726
701
|
RestartTracker,
|
|
727
702
|
PROMPT_KEYS,
|
|
728
703
|
PROMPT_DEFAULTS,
|
|
@@ -733,6 +708,7 @@ export {
|
|
|
733
708
|
loadJsonMap,
|
|
734
709
|
saveJsonMap,
|
|
735
710
|
clearJsonMap,
|
|
711
|
+
resolveMindToken,
|
|
736
712
|
MindManager,
|
|
737
713
|
initMindManager,
|
|
738
714
|
getMindManager
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
|
+
getBaseName,
|
|
3
4
|
validateMindName
|
|
4
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-H7OZRFJB.js";
|
|
5
6
|
|
|
6
7
|
// src/lib/isolation.ts
|
|
7
8
|
import { execFileSync } from "child_process";
|
|
@@ -138,9 +139,9 @@ function deleteMindUser(name) {
|
|
|
138
139
|
} catch {
|
|
139
140
|
}
|
|
140
141
|
}
|
|
141
|
-
function wrapForIsolation(cmd, args, mindName) {
|
|
142
|
+
async function wrapForIsolation(cmd, args, mindName) {
|
|
142
143
|
if (!isIsolationEnabled()) return [cmd, args];
|
|
143
|
-
const baseName = mindName
|
|
144
|
+
const baseName = await getBaseName(mindName);
|
|
144
145
|
const user = mindUserName(baseName);
|
|
145
146
|
if (process.platform === "darwin") {
|
|
146
147
|
return ["sudo", ["-u", user, "--", cmd, ...args]];
|
|
@@ -4,16 +4,17 @@ import {
|
|
|
4
4
|
modeLabel,
|
|
5
5
|
pollHealth,
|
|
6
6
|
startService
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-LAC664WU.js";
|
|
8
|
+
import {
|
|
9
|
+
readGlobalConfig
|
|
10
|
+
} from "./chunk-IKRVFPWU.js";
|
|
8
11
|
import {
|
|
9
12
|
parseArgs
|
|
10
13
|
} from "./chunk-D424ZQGI.js";
|
|
11
14
|
import {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
voluteHome
|
|
16
|
-
} from "./chunk-B2CPS4QU.js";
|
|
15
|
+
voluteHome,
|
|
16
|
+
voluteSystemDir
|
|
17
|
+
} from "./chunk-H7OZRFJB.js";
|
|
17
18
|
|
|
18
19
|
// src/commands/up.ts
|
|
19
20
|
import { spawn } from "child_process";
|
|
@@ -51,7 +52,8 @@ async function run(args) {
|
|
|
51
52
|
const port = flags.port ?? config.port ?? 1618;
|
|
52
53
|
const hostname = flags.host ?? config.hostname ?? "127.0.0.1";
|
|
53
54
|
const home = voluteHome();
|
|
54
|
-
const
|
|
55
|
+
const systemDir = voluteSystemDir();
|
|
56
|
+
const pidPath = resolve(systemDir, "daemon.pid");
|
|
55
57
|
if (existsSync(pidPath)) {
|
|
56
58
|
try {
|
|
57
59
|
const pid = parseInt(readFileSync(pidPath, "utf-8").trim(), 10);
|
|
@@ -103,7 +105,8 @@ async function run(args) {
|
|
|
103
105
|
process.exit(1);
|
|
104
106
|
}
|
|
105
107
|
mkdirSync(home, { recursive: true });
|
|
106
|
-
|
|
108
|
+
mkdirSync(systemDir, { recursive: true });
|
|
109
|
+
const logFile = resolve(systemDir, "daemon.log");
|
|
107
110
|
const logFd = openSync(logFile, "a");
|
|
108
111
|
const daemonArgs = [daemonModule, "--port", String(port), "--host", hostname];
|
|
109
112
|
if (flags.tailscale) daemonArgs.push("--tailscale");
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/lib/slugify.ts
|
|
4
|
+
function slugify(text) {
|
|
5
|
+
return text.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
|
|
6
|
+
}
|
|
7
|
+
function buildVoluteSlug(opts) {
|
|
8
|
+
if (opts.convType === "channel" && opts.convName) {
|
|
9
|
+
return `volute:#${opts.convName}`;
|
|
10
|
+
}
|
|
11
|
+
const isDM = opts.participants.length === 2;
|
|
12
|
+
if (isDM) {
|
|
13
|
+
const other = opts.participants.find((p) => p.username !== opts.mindUsername);
|
|
14
|
+
const otherSlug = other ? slugify(other.username) : "";
|
|
15
|
+
return otherSlug ? `volute:@${otherSlug}` : `volute:${opts.conversationId}`;
|
|
16
|
+
}
|
|
17
|
+
return opts.convTitle ? `volute:${slugify(opts.convTitle)}` : `volute:${opts.conversationId}`;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export {
|
|
21
|
+
slugify,
|
|
22
|
+
buildVoluteSlug
|
|
23
|
+
};
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
activity,
|
|
4
|
-
getDb
|
|
5
|
-
} from "./chunk-WBHMQ5OZ.js";
|
|
6
2
|
import {
|
|
7
3
|
logger_default
|
|
8
4
|
} from "./chunk-YUIHSKR6.js";
|
|
5
|
+
import {
|
|
6
|
+
activity,
|
|
7
|
+
getDb
|
|
8
|
+
} from "./chunk-H7OZRFJB.js";
|
|
9
9
|
|
|
10
10
|
// src/lib/events/activity-events.ts
|
|
11
11
|
var subscribers = /* @__PURE__ */ new Set();
|