volute 0.42.0 → 0.43.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/dist/{accept-7YVHZKRD.js → accept-N5XULCXK.js} +1 -1
- package/dist/{activity-events-KFKVRZE3.js → activity-events-UISXY4Y5.js} +3 -3
- package/dist/{ai-service-3GBOJGUA.js → ai-service-FBCCEYF5.js} +8 -4
- package/dist/{archive-4PPYF7LL.js → archive-I32WHCJB.js} +3 -3
- package/dist/{auth-EAASQPTN.js → auth-3RIG6GKN.js} +4 -4
- package/dist/{bridge-WPYSOQKR.js → bridge-2PO3AI5D.js} +1 -1
- package/dist/{chat-7DOENBY2.js → chat-SDSX5TVV.js} +8 -8
- package/dist/{chunk-M2YMNTHK.js → chunk-2HIVYZDB.js} +1 -1
- package/dist/{chunk-TKOWXAHG.js → chunk-3WLWKOGM.js} +21 -6
- package/dist/{chunk-QPTQKGGF.js → chunk-57LBQ7JX.js} +1 -1
- package/dist/{chunk-VSUZE2PD.js → chunk-65OLHBCL.js} +13 -12
- package/dist/{chunk-K547QOCM.js → chunk-7G2EEYXX.js} +2 -2
- package/dist/{chunk-E7XWFDZL.js → chunk-AD46AYZQ.js} +1 -1
- package/dist/{chunk-CGPESELY.js → chunk-ATEX3ZPG.js} +21 -5
- package/dist/{chunk-WR7CSHQ4.js → chunk-C6ESRQZ7.js} +1 -1
- package/dist/{chunk-OSUF75I7.js → chunk-EE7SZJON.js} +2 -2
- package/dist/{chunk-5QG36RV7.js → chunk-EFL5UOY4.js} +3 -3
- package/dist/{chunk-JLX3GC7T.js → chunk-FSSUANZJ.js} +5 -5
- package/dist/{chunk-2YRTSK5K.js → chunk-FZ5TH5PF.js} +14 -11
- package/dist/{chunk-OEJFZHZZ.js → chunk-GZJFC76M.js} +1 -1
- package/dist/{chunk-KUJVCDWT.js → chunk-JVK6QQIC.js} +2 -2
- package/dist/{chunk-YLTIEEVL.js → chunk-K4EHBHPE.js} +3 -3
- package/dist/{chunk-MHFAWJCC.js → chunk-L3IV23ZG.js} +12 -1
- package/dist/{chunk-VBKRZCR7.js → chunk-M3PGGSBH.js} +1 -1
- package/dist/{chunk-G777ME4L.js → chunk-O3DXAR44.js} +2 -2
- package/dist/{chunk-KZAL7HEQ.js → chunk-ONM2AZFL.js} +1 -1
- package/dist/{chunk-52NMCDBS.js → chunk-PF2AB7VJ.js} +568 -378
- package/dist/chunk-PGPLCJPK.js +272 -0
- package/dist/{chunk-IFNSAOA4.js → chunk-RBNMDAKB.js} +4 -0
- package/dist/{chunk-62ICA2FF.js → chunk-SPLPKBES.js} +17 -1
- package/dist/{chunk-BLOAJLGI.js → chunk-XDTKJNW5.js} +1 -1
- package/dist/{chunk-IUZ3EV2D.js → chunk-YAMO2U3N.js} +1 -1
- package/dist/{chunk-4ZSUUBG5.js → chunk-YSV3VJQK.js} +55 -2
- package/dist/{chunk-RKBYFLOR.js → chunk-ZO7IQJKO.js} +3 -3
- package/dist/cli.js +22 -22
- package/dist/{clock-HP2TGMG5.js → clock-K43IMROX.js} +3 -3
- package/dist/{cloud-sync-3OPHFOYQ.js → cloud-sync-FRYNWKCR.js} +16 -17
- package/dist/{config-W7MS3PWY.js → config-TJLYUV3U.js} +3 -3
- package/dist/{conversations-FSZCUUYO.js → conversations-67WWW25C.js} +4 -4
- package/dist/{create-YNBZWD34.js → create-7W3LV3J7.js} +2 -2
- package/dist/{create-CJ2SR4EU.js → create-DF3KISTW.js} +1 -1
- package/dist/{daemon-client-EWDPOOHC.js → daemon-client-IYR4KCPU.js} +3 -1
- package/dist/{daemon-restart-RAKGR56L.js → daemon-restart-5GVZ5V3X.js} +7 -8
- package/dist/daemon.js +541 -440
- package/dist/{db-ZJJJYJBU.js → db-CZV62BOQ.js} +2 -2
- package/dist/{delete-4ND5PLE7.js → delete-BFMIGAIB.js} +1 -1
- package/dist/delivery-manager-5J2BE22P.js +32 -0
- package/dist/{delivery-router-FDBZJQOY.js → delivery-router-HXBHYHJM.js} +7 -5
- package/dist/down-RRNYIGCU.js +16 -0
- package/dist/echo-text-XKBJM6RV.js +32 -0
- package/dist/{env-XX2MBZCZ.js → env-VZ4MLFQW.js} +1 -1
- package/dist/{exec-ZDD7NEB4.js → exec-SJK7VUTC.js} +3 -4
- package/dist/{export-5DOQV2WM.js → export-7LPCIB5J.js} +4 -4
- package/dist/{extension-BCFYXI7A.js → extension-SEID47SR.js} +1 -1
- package/dist/{extensions-BTNIUS5J.js → extensions-76EGTMFY.js} +16 -17
- package/dist/{files-K2MEMV3W.js → files-LV7VAKPC.js} +4 -4
- package/dist/{import-V6QEHMPQ.js → import-XPECCRQ7.js} +8 -8
- package/dist/{isolation-F7ABZMDA.js → isolation-5AYEY55P.js} +5 -3
- package/dist/{join-4S3KT7NE.js → join-RXPXGV4L.js} +1 -1
- package/dist/{list-XJB5WII6.js → list-OXIAY3W7.js} +1 -1
- package/dist/{login-PHMTLNUF.js → login-KJSN4JDA.js} +3 -3
- package/dist/{login-YWD6PUOT.js → login-MY6ETFYB.js} +1 -1
- package/dist/{logout-Q2WICH4V.js → logout-NCG3TMDL.js} +1 -1
- package/dist/{logout-BP3R3CAA.js → logout-TMJGUQV2.js} +3 -3
- package/dist/message-delivery-WJBZFALY.js +34 -0
- package/dist/{mind-VXV6ZYZY.js → mind-QEWCR7FA.js} +18 -18
- package/dist/{mind-activity-tracker-HWVFE533.js → mind-activity-tracker-JHAT6456.js} +4 -4
- package/dist/{mind-history-TDUQFYAG.js → mind-history-VRO5A76U.js} +1 -1
- package/dist/{mind-list-2T353Q5G.js → mind-list-4D7J4CHD.js} +1 -1
- package/dist/{mind-profile-2HHR7LZ7.js → mind-profile-PEQYASQX.js} +1 -1
- package/dist/mind-service-ZBVUMJ5H.js +36 -0
- package/dist/{mind-sleep-4NXV4J4U.js → mind-sleep-YMBR3I35.js} +1 -1
- package/dist/{mind-status-CG66OXDK.js → mind-status-UO34ASXZ.js} +1 -1
- package/dist/{mind-wake-TNB54DBR.js → mind-wake-LCLGTXA2.js} +1 -1
- package/dist/{package-UWH5IM76.js → package-ZOI2KAYC.js} +1 -1
- package/dist/{read-JLR4NQXU.js → read-QVAXMTPV.js} +1 -1
- package/dist/{register-IQ2M4UO6.js → register-Y2H4PY5R.js} +1 -1
- package/dist/{registry-MDLNPTTI.js → registry-7LQHTRUX.js} +2 -2
- package/dist/{reject-N2D4CZND.js → reject-EV35X64Y.js} +1 -1
- package/dist/{restart-43A5MBGV.js → restart-FJQ662XJ.js} +1 -1
- package/dist/{sandbox-E7RWZDVG.js → sandbox-SJH3XOPZ.js} +4 -4
- package/dist/scheduler-BR6C6B3E.js +30 -0
- package/dist/{schema-HHYJDG7B.js → schema-LRUTFOER.js} +1 -1
- package/dist/{seed-YQAOIXIY.js → seed-KOG6KJAO.js} +1 -1
- package/dist/{seed-check-N5ALJBT6.js → seed-check-VLTVILOV.js} +1 -1
- package/dist/{seed-cmd-7KJS4LCA.js → seed-cmd-GJFENEJH.js} +3 -3
- package/dist/{seed-create-Z7NDRRGP.js → seed-create-YXO6R4KE.js} +4 -4
- package/dist/{seed-sprout-PYDMVVUL.js → seed-sprout-BBU64QXP.js} +8 -9
- package/dist/{send-KQECN2EL.js → send-ZBZWIH5V.js} +4 -4
- package/dist/{service-Q5OVY5AK.js → service-4EVZKGSA.js} +4 -5
- package/dist/{service-install-GTDUHP6R.js → service-install-SHRM6NHK.js} +5 -6
- package/dist/{setup-IYOUPCIK.js → setup-25MMJ3J4.js} +3 -3
- package/dist/{setup-VARJ7N6Z.js → setup-354PDHUF.js} +8 -10
- package/dist/{skill-E43BI34Y.js → skill-FKFHIJRR.js} +1 -1
- package/dist/{skills-YBCYVOPQ.js → skills-DPI3WZPQ.js} +5 -6
- package/dist/sleep-manager-BVU5D2AE.js +34 -0
- package/dist/{spirit-NJFAY5CZ.js → spirit-JQQHUVWR.js} +7 -8
- package/dist/{split-5IBUODEE.js → split-WBMZXBHF.js} +1 -1
- package/dist/{sprout-B27C2WGE.js → sprout-4WAYBUVV.js} +1 -1
- package/dist/{start-5AYFGNS7.js → start-5JE3TV66.js} +1 -1
- package/dist/{status-ECZHHSY5.js → status-WTU2WHXY.js} +12 -9
- package/dist/{stop-WJ6IG6OK.js → stop-AAMTG3TU.js} +1 -1
- package/dist/system-chat-KMQIP7VH.js +34 -0
- package/dist/{systems-5MA57Q7G.js → systems-VNB5WKSS.js} +4 -4
- package/dist/{tailscale-TIRTGM6E.js → tailscale-Q7ZJL7S7.js} +2 -2
- package/dist/{turn-tracker-W4TASMR7.js → turn-tracker-2GMKJQTN.js} +7 -5
- package/dist/up-7RSBEKW6.js +18 -0
- package/dist/{update-OPR4KU4M.js → update-EJ7Q77ZX.js} +9 -10
- package/dist/{update-check-OG27AL4Z.js → update-check-ACYYNKTW.js} +3 -3
- package/dist/{upgrade-QB7AHIKX.js → upgrade-37DAGF6H.js} +1 -1
- package/dist/{version-notify-TCKAX7ZA.js → version-notify-DCAIXXZB.js} +17 -18
- package/dist/web-assets/assets/{index-CrFAsfiE.js → index-DTDmEfPU.js} +2 -2
- package/dist/web-assets/index.html +1 -1
- package/drizzle/0010_delivery_queue_redrive.sql +10 -0
- package/drizzle/meta/_journal.json +7 -0
- package/package.json +1 -1
- package/templates/codex/src/server.ts +2 -8
- package/dist/chunk-GN52E2DP.js +0 -59
- package/dist/chunk-TFBQESH7.js +0 -179
- package/dist/delivery-manager-5Y35DOX3.js +0 -33
- package/dist/down-DS6WCT34.js +0 -17
- package/dist/echo-text-YP3JVLNA.js +0 -32
- package/dist/message-delivery-FPIL26WV.js +0 -41
- package/dist/mind-manager-OYOIBGK6.js +0 -33
- package/dist/mind-service-PR4PR4XI.js +0 -37
- package/dist/scheduler-KXUY2I7W.js +0 -31
- package/dist/sleep-manager-FJLASHHW.js +0 -35
- package/dist/system-chat-P6KVGW4T.js +0 -35
- package/dist/up-POJX6S5Y.js +0 -19
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
getBaseName,
|
|
4
|
+
validateMindName
|
|
5
|
+
} from "./chunk-YAMO2U3N.js";
|
|
6
|
+
|
|
7
|
+
// packages/daemon/src/lib/mind/isolation.ts
|
|
8
|
+
import { execFileSync as execFileSync2 } from "child_process";
|
|
9
|
+
import { existsSync, readdirSync, statSync } from "fs";
|
|
10
|
+
import { resolve } from "path";
|
|
11
|
+
|
|
12
|
+
// packages/daemon/src/lib/util/exec.ts
|
|
13
|
+
import { execFile as execFileCb, execFileSync, spawn } from "child_process";
|
|
14
|
+
async function exec(cmd, args, options) {
|
|
15
|
+
const [wrappedCmd, wrappedArgs] = options?.mindName ? await wrapForIsolation(cmd, args, options.mindName) : [cmd, args];
|
|
16
|
+
return new Promise((resolve2, reject) => {
|
|
17
|
+
execFileCb(
|
|
18
|
+
wrappedCmd,
|
|
19
|
+
wrappedArgs,
|
|
20
|
+
{ cwd: options?.cwd, env: options?.env },
|
|
21
|
+
(err, stdout, stderr) => {
|
|
22
|
+
if (err) {
|
|
23
|
+
err.stderr = stderr;
|
|
24
|
+
err.stdout = stdout;
|
|
25
|
+
reject(err);
|
|
26
|
+
} else {
|
|
27
|
+
resolve2(stdout);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
);
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
function gitExec(args, options) {
|
|
34
|
+
const fullArgs = process.env.VOLUTE_ISOLATION === "user" ? ["-c", "safe.directory=*", ...args] : args;
|
|
35
|
+
return exec("git", fullArgs, options);
|
|
36
|
+
}
|
|
37
|
+
function resolveVoluteBin() {
|
|
38
|
+
try {
|
|
39
|
+
return execFileSync("which", ["volute"], { encoding: "utf-8" }).trim();
|
|
40
|
+
} catch {
|
|
41
|
+
throw new Error("Could not find volute binary on PATH");
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
async function execInherit(cmd, args, options) {
|
|
45
|
+
const [wrappedCmd, wrappedArgs] = options?.mindName ? await wrapForIsolation(cmd, args, options.mindName) : [cmd, args];
|
|
46
|
+
return new Promise((resolve2, reject) => {
|
|
47
|
+
const child = spawn(wrappedCmd, wrappedArgs, {
|
|
48
|
+
cwd: options?.cwd,
|
|
49
|
+
env: options?.env,
|
|
50
|
+
stdio: "inherit"
|
|
51
|
+
});
|
|
52
|
+
child.on("error", reject);
|
|
53
|
+
child.on("close", (code) => {
|
|
54
|
+
if (code === 0) resolve2();
|
|
55
|
+
else reject(new Error(`${cmd} ${args.join(" ")} exited with code ${code}`));
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// packages/daemon/src/lib/mind/isolation.ts
|
|
61
|
+
function isIsolationEnabled() {
|
|
62
|
+
return process.env.VOLUTE_ISOLATION === "user";
|
|
63
|
+
}
|
|
64
|
+
function mindUserName(mindName) {
|
|
65
|
+
const err = validateMindName(mindName);
|
|
66
|
+
if (err && mindName !== "volute") {
|
|
67
|
+
throw new Error(`Invalid mind name for isolation: ${err}`);
|
|
68
|
+
}
|
|
69
|
+
const prefix = process.env.VOLUTE_USER_PREFIX ?? "mind-";
|
|
70
|
+
return `${prefix}${mindName}`;
|
|
71
|
+
}
|
|
72
|
+
function findNextMacId(type) {
|
|
73
|
+
const idField = type === "Users" ? "UniqueID" : "PrimaryGroupID";
|
|
74
|
+
let output;
|
|
75
|
+
try {
|
|
76
|
+
output = execFileSync2("dscl", [".", "-list", `/${type}`, idField], { encoding: "utf-8" });
|
|
77
|
+
} catch (err) {
|
|
78
|
+
throw new Error(
|
|
79
|
+
`Failed to query ${type} via dscl: ${err instanceof Error ? err.message : err}`
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
const ids = /* @__PURE__ */ new Set();
|
|
83
|
+
for (const line of output.split("\n")) {
|
|
84
|
+
const parts = line.trim().split(/\s+/);
|
|
85
|
+
const id = parseInt(parts[parts.length - 1], 10);
|
|
86
|
+
if (!Number.isNaN(id)) ids.add(id);
|
|
87
|
+
}
|
|
88
|
+
let next = 401;
|
|
89
|
+
while (ids.has(next)) next++;
|
|
90
|
+
return next;
|
|
91
|
+
}
|
|
92
|
+
function getVoluteGroupGid() {
|
|
93
|
+
if (process.platform === "darwin") {
|
|
94
|
+
const output2 = execFileSync2("dscl", [".", "-read", "/Groups/volute", "PrimaryGroupID"], {
|
|
95
|
+
encoding: "utf-8"
|
|
96
|
+
});
|
|
97
|
+
const match = output2.match(/PrimaryGroupID:\s*(\d+)/);
|
|
98
|
+
if (!match) throw new Error("Could not read volute group GID");
|
|
99
|
+
return parseInt(match[1], 10);
|
|
100
|
+
}
|
|
101
|
+
const output = execFileSync2("getent", ["group", "volute"], { encoding: "utf-8" });
|
|
102
|
+
const gid = parseInt(output.split(":")[2], 10);
|
|
103
|
+
if (Number.isNaN(gid)) throw new Error("Could not read volute group GID");
|
|
104
|
+
return gid;
|
|
105
|
+
}
|
|
106
|
+
function ensureVoluteGroup(opts) {
|
|
107
|
+
if (!opts?.force && !isIsolationEnabled()) return;
|
|
108
|
+
if (process.platform === "darwin") {
|
|
109
|
+
try {
|
|
110
|
+
execFileSync2("dscl", [".", "-read", "/Groups/volute"], { stdio: "ignore" });
|
|
111
|
+
return;
|
|
112
|
+
} catch {
|
|
113
|
+
}
|
|
114
|
+
const gid = findNextMacId("Groups");
|
|
115
|
+
try {
|
|
116
|
+
execFileSync2("dscl", [".", "-create", "/Groups/volute"]);
|
|
117
|
+
execFileSync2("dscl", [".", "-create", "/Groups/volute", "PrimaryGroupID", String(gid)]);
|
|
118
|
+
execFileSync2("dscl", [".", "-create", "/Groups/volute", "Password", "*"]);
|
|
119
|
+
} catch (err) {
|
|
120
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
121
|
+
throw new Error(`Failed to create volute group on macOS: ${msg}`);
|
|
122
|
+
}
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
try {
|
|
126
|
+
execFileSync2("getent", ["group", "volute"], { stdio: "ignore" });
|
|
127
|
+
} catch {
|
|
128
|
+
try {
|
|
129
|
+
execFileSync2("groupadd", ["volute"], { stdio: ["ignore", "ignore", "pipe"] });
|
|
130
|
+
} catch (err) {
|
|
131
|
+
const stderr = err?.stderr?.toString().trim();
|
|
132
|
+
throw new Error(`Failed to create volute group${stderr ? `: ${stderr}` : ""}`);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
function createMindUser(name, homeDir) {
|
|
137
|
+
if (!isIsolationEnabled()) return;
|
|
138
|
+
const user = mindUserName(name);
|
|
139
|
+
try {
|
|
140
|
+
execFileSync2("id", [user], { stdio: "ignore" });
|
|
141
|
+
return;
|
|
142
|
+
} catch {
|
|
143
|
+
}
|
|
144
|
+
if (process.platform === "darwin") {
|
|
145
|
+
const uid = findNextMacId("Users");
|
|
146
|
+
const gid = getVoluteGroupGid();
|
|
147
|
+
const home = homeDir ?? "/var/empty";
|
|
148
|
+
try {
|
|
149
|
+
execFileSync2("dscl", [".", "-create", `/Users/${user}`]);
|
|
150
|
+
execFileSync2("dscl", [".", "-create", `/Users/${user}`, "UniqueID", String(uid)]);
|
|
151
|
+
execFileSync2("dscl", [".", "-create", `/Users/${user}`, "PrimaryGroupID", String(gid)]);
|
|
152
|
+
execFileSync2("dscl", [".", "-create", `/Users/${user}`, "UserShell", "/usr/bin/false"]);
|
|
153
|
+
execFileSync2("dscl", [".", "-create", `/Users/${user}`, "NFSHomeDirectory", home]);
|
|
154
|
+
execFileSync2("dscl", [".", "-create", `/Users/${user}`, "RealName", `Volute Mind: ${name}`]);
|
|
155
|
+
execFileSync2("dscl", [".", "-create", `/Users/${user}`, "IsHidden", "1"]);
|
|
156
|
+
execFileSync2("dscl", [".", "-append", "/Groups/volute", "GroupMembership", user]);
|
|
157
|
+
} catch (err) {
|
|
158
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
159
|
+
throw new Error(`Failed to create user ${user} on macOS: ${msg}`);
|
|
160
|
+
}
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
try {
|
|
164
|
+
const args = ["-r", "-M", "-G", "volute", "-s", "/usr/sbin/nologin"];
|
|
165
|
+
if (homeDir) args.push("-d", homeDir);
|
|
166
|
+
args.push(user);
|
|
167
|
+
execFileSync2("useradd", args, {
|
|
168
|
+
stdio: ["ignore", "ignore", "pipe"]
|
|
169
|
+
});
|
|
170
|
+
} catch (err) {
|
|
171
|
+
const stderr = err?.stderr?.toString().trim();
|
|
172
|
+
throw new Error(`Failed to create user ${user}${stderr ? `: ${stderr}` : ""}`);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
function deleteMindUser(name) {
|
|
176
|
+
if (!isIsolationEnabled()) return;
|
|
177
|
+
const user = mindUserName(name);
|
|
178
|
+
if (process.platform === "darwin") {
|
|
179
|
+
try {
|
|
180
|
+
execFileSync2("dscl", [".", "-delete", `/Users/${user}`], { stdio: "ignore" });
|
|
181
|
+
} catch {
|
|
182
|
+
}
|
|
183
|
+
try {
|
|
184
|
+
execFileSync2("dscl", [".", "-delete", "/Groups/volute", "GroupMembership", user], {
|
|
185
|
+
stdio: "ignore"
|
|
186
|
+
});
|
|
187
|
+
} catch {
|
|
188
|
+
}
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
try {
|
|
192
|
+
execFileSync2("userdel", [user], { stdio: "ignore" });
|
|
193
|
+
} catch {
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
async function wrapForIsolation(cmd, args, mindName) {
|
|
197
|
+
if (!isIsolationEnabled()) return [cmd, args];
|
|
198
|
+
const baseName = await getBaseName(mindName);
|
|
199
|
+
const user = mindUserName(baseName);
|
|
200
|
+
if (process.platform === "darwin") {
|
|
201
|
+
return ["sudo", ["-u", user, "--", cmd, ...args]];
|
|
202
|
+
}
|
|
203
|
+
return ["runuser", ["-u", user, "--", cmd, ...args]];
|
|
204
|
+
}
|
|
205
|
+
async function userUid(user) {
|
|
206
|
+
try {
|
|
207
|
+
const uid = parseInt((await exec("id", ["-u", user])).trim(), 10);
|
|
208
|
+
return Number.isNaN(uid) ? null : uid;
|
|
209
|
+
} catch {
|
|
210
|
+
return null;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
function ownedBy(path, uid) {
|
|
214
|
+
try {
|
|
215
|
+
return statSync(path).uid === uid;
|
|
216
|
+
} catch {
|
|
217
|
+
return false;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
async function chownTargets(dir, user) {
|
|
221
|
+
const nodeModules = resolve(dir, "node_modules");
|
|
222
|
+
const home = resolve(dir, "home");
|
|
223
|
+
if (existsSync(nodeModules) && existsSync(home)) {
|
|
224
|
+
const uid = await userUid(user);
|
|
225
|
+
if (uid !== null && ownedBy(nodeModules, uid)) {
|
|
226
|
+
return readdirSync(dir).filter((entry) => entry !== "node_modules").map((entry) => resolve(dir, entry));
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
return [dir];
|
|
230
|
+
}
|
|
231
|
+
async function chownMindDir(dir, name) {
|
|
232
|
+
if (!isIsolationEnabled()) return;
|
|
233
|
+
const user = mindUserName(name);
|
|
234
|
+
const group = process.platform === "darwin" ? "volute" : user;
|
|
235
|
+
for (const target of await chownTargets(dir, user)) {
|
|
236
|
+
try {
|
|
237
|
+
await exec("chown", ["-R", `${user}:${group}`, target]);
|
|
238
|
+
} catch (err) {
|
|
239
|
+
const stderr = String(err?.stderr ?? "").trim();
|
|
240
|
+
throw new Error(
|
|
241
|
+
`Failed to chown ${target} to ${user}:${group}${stderr ? `: ${stderr}` : ""}`
|
|
242
|
+
);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
try {
|
|
246
|
+
await exec("chown", [`${user}:${group}`, dir]);
|
|
247
|
+
} catch (err) {
|
|
248
|
+
const stderr = String(err?.stderr ?? "").trim();
|
|
249
|
+
throw new Error(`Failed to chown ${dir} to ${user}:${group}${stderr ? `: ${stderr}` : ""}`);
|
|
250
|
+
}
|
|
251
|
+
try {
|
|
252
|
+
await exec("chmod", ["700", dir]);
|
|
253
|
+
} catch (err) {
|
|
254
|
+
const stderr = String(err?.stderr ?? "").trim();
|
|
255
|
+
throw new Error(`Failed to chmod ${dir}${stderr ? `: ${stderr}` : ""}`);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
export {
|
|
260
|
+
isIsolationEnabled,
|
|
261
|
+
mindUserName,
|
|
262
|
+
ensureVoluteGroup,
|
|
263
|
+
createMindUser,
|
|
264
|
+
deleteMindUser,
|
|
265
|
+
wrapForIsolation,
|
|
266
|
+
chownTargets,
|
|
267
|
+
chownMindDir,
|
|
268
|
+
exec,
|
|
269
|
+
gitExec,
|
|
270
|
+
resolveVoluteBin,
|
|
271
|
+
execInherit
|
|
272
|
+
};
|
|
@@ -82,6 +82,9 @@ function resolveDaemonUrl() {
|
|
|
82
82
|
if (session?.daemonUrl) return session.daemonUrl;
|
|
83
83
|
return buildUrl(readDaemonConfig());
|
|
84
84
|
}
|
|
85
|
+
function getAuthToken() {
|
|
86
|
+
return process.env.VOLUTE_MIND_TOKEN ?? readCliSession()?.sessionId;
|
|
87
|
+
}
|
|
85
88
|
async function daemonFetch(path, options) {
|
|
86
89
|
const url = resolveDaemonUrl();
|
|
87
90
|
const headers = new Headers(options?.headers);
|
|
@@ -125,5 +128,6 @@ export {
|
|
|
125
128
|
daemonDispatcher,
|
|
126
129
|
readSessionFile,
|
|
127
130
|
resolveDaemonUrl,
|
|
131
|
+
getAuthToken,
|
|
128
132
|
daemonFetch
|
|
129
133
|
};
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
} from "./chunk-T2TP6ZC6.js";
|
|
5
5
|
import {
|
|
6
6
|
mindDir
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-YAMO2U3N.js";
|
|
8
8
|
|
|
9
9
|
// packages/daemon/src/lib/delivery/delivery-router.ts
|
|
10
10
|
import { readFileSync, statSync } from "fs";
|
|
@@ -20,6 +20,18 @@ var configCache = /* @__PURE__ */ new Map();
|
|
|
20
20
|
var statCheckCache = /* @__PURE__ */ new Map();
|
|
21
21
|
var STAT_TTL_MS = 5e3;
|
|
22
22
|
var dlog = logger_default.child("delivery-router");
|
|
23
|
+
var routesChangeListener;
|
|
24
|
+
function setRoutesChangeListener(fn) {
|
|
25
|
+
routesChangeListener = fn;
|
|
26
|
+
}
|
|
27
|
+
function notifyRoutesChanged(mind) {
|
|
28
|
+
if (!routesChangeListener) return;
|
|
29
|
+
try {
|
|
30
|
+
routesChangeListener(mind);
|
|
31
|
+
} catch (err) {
|
|
32
|
+
dlog.warn(`routes change listener failed for ${mind}`, logger_default.errorData(err));
|
|
33
|
+
}
|
|
34
|
+
}
|
|
23
35
|
var dirOverrides = /* @__PURE__ */ new Map();
|
|
24
36
|
function registerMindDir(name, dir) {
|
|
25
37
|
dirOverrides.set(name, dir);
|
|
@@ -50,7 +62,9 @@ function getRoutingConfig(mindName) {
|
|
|
50
62
|
}
|
|
51
63
|
try {
|
|
52
64
|
const config = JSON.parse(readFileSync(path, "utf-8"));
|
|
65
|
+
const changed = cached != null && cached.mtime !== mtime;
|
|
53
66
|
configCache.set(mindName, { config, mtime });
|
|
67
|
+
if (changed) notifyRoutesChanged(mindName);
|
|
54
68
|
return config;
|
|
55
69
|
} catch (err) {
|
|
56
70
|
dlog.warn(`failed to load routes.json for ${mindName}`, logger_default.errorData(err));
|
|
@@ -63,6 +77,7 @@ function clearConfigCache(mindName) {
|
|
|
63
77
|
if (mindName) {
|
|
64
78
|
configCache.delete(mindName);
|
|
65
79
|
statCheckCache.delete(mindName);
|
|
80
|
+
notifyRoutesChanged(mindName);
|
|
66
81
|
} else {
|
|
67
82
|
configCache.clear();
|
|
68
83
|
statCheckCache.clear();
|
|
@@ -200,6 +215,7 @@ function resolveDeliveryMode(config, sessionName, rule) {
|
|
|
200
215
|
|
|
201
216
|
export {
|
|
202
217
|
extractTextContent,
|
|
218
|
+
setRoutesChangeListener,
|
|
203
219
|
registerMindDir,
|
|
204
220
|
getRoutingConfig,
|
|
205
221
|
clearConfigCache,
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import {
|
|
3
3
|
readGlobalConfig,
|
|
4
4
|
writeGlobalConfig
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-ONM2AZFL.js";
|
|
6
6
|
import {
|
|
7
7
|
logger_default
|
|
8
8
|
} from "./chunk-T2TP6ZC6.js";
|
|
@@ -141,6 +141,42 @@ function setEnabledModels(modelIds) {
|
|
|
141
141
|
const config = readGlobalConfig();
|
|
142
142
|
writeGlobalConfig({ ...config, ai });
|
|
143
143
|
}
|
|
144
|
+
function migrateAiModelQualification() {
|
|
145
|
+
const config = readGlobalConfig();
|
|
146
|
+
const ai = config.ai;
|
|
147
|
+
const isBare = (id) => id != null && !id.includes(":");
|
|
148
|
+
const hasBareInList = (ai?.models ?? []).some(isBare);
|
|
149
|
+
if (!hasBareInList && !isBare(config.spiritModel) && !isBare(ai?.utilityModel)) return;
|
|
150
|
+
const providers = ai ? Object.keys(ai.providers) : [];
|
|
151
|
+
const customModels = ai?.customModels ?? [];
|
|
152
|
+
const providersServing = (bareId) => providers.filter(
|
|
153
|
+
(p) => getBuiltinModel(p, bareId) != null || customModels.some((cm) => cm.provider === p && cm.id === bareId)
|
|
154
|
+
);
|
|
155
|
+
let changed = false;
|
|
156
|
+
if (ai?.models) {
|
|
157
|
+
const expanded = [];
|
|
158
|
+
for (const id of ai.models) {
|
|
159
|
+
if (!isBare(id)) {
|
|
160
|
+
expanded.push(id);
|
|
161
|
+
continue;
|
|
162
|
+
}
|
|
163
|
+
changed = true;
|
|
164
|
+
for (const p of providersServing(id)) expanded.push(`${p}:${id}`);
|
|
165
|
+
}
|
|
166
|
+
ai.models = expanded.length > 0 ? [...new Set(expanded)] : void 0;
|
|
167
|
+
if (!ai.models) delete ai.models;
|
|
168
|
+
}
|
|
169
|
+
const qualifyOne = (id) => {
|
|
170
|
+
if (!isBare(id)) return id;
|
|
171
|
+
const [provider] = providersServing(id);
|
|
172
|
+
if (!provider) return id;
|
|
173
|
+
changed = true;
|
|
174
|
+
return `${provider}:${id}`;
|
|
175
|
+
};
|
|
176
|
+
config.spiritModel = qualifyOne(config.spiritModel);
|
|
177
|
+
if (ai) ai.utilityModel = qualifyOne(ai.utilityModel);
|
|
178
|
+
if (changed) writeGlobalConfig(config);
|
|
179
|
+
}
|
|
144
180
|
function getCustomModels() {
|
|
145
181
|
return getAiConfig()?.customModels ?? [];
|
|
146
182
|
}
|
|
@@ -163,7 +199,8 @@ function removeCustomModel(provider, id) {
|
|
|
163
199
|
ai.customModels = customModels.length > 0 ? customModels : void 0;
|
|
164
200
|
if (!ai.customModels) delete ai.customModels;
|
|
165
201
|
if (ai.models) {
|
|
166
|
-
|
|
202
|
+
const qualified = `${provider}:${id}`;
|
|
203
|
+
ai.models = ai.models.filter((mid) => mid !== qualified);
|
|
167
204
|
if (ai.models.length === 0) delete ai.models;
|
|
168
205
|
}
|
|
169
206
|
const config = readGlobalConfig();
|
|
@@ -266,6 +303,20 @@ function unqualifyModelId(modelId) {
|
|
|
266
303
|
return idx >= 0 ? modelId.slice(idx + 1) : modelId;
|
|
267
304
|
}
|
|
268
305
|
function findModel(modelId) {
|
|
306
|
+
const colon = modelId.indexOf(":");
|
|
307
|
+
if (colon >= 0) {
|
|
308
|
+
const provider = modelId.slice(0, colon);
|
|
309
|
+
const bareId = modelId.slice(colon + 1);
|
|
310
|
+
const built = getBuiltinModel(provider, bareId);
|
|
311
|
+
if (built) return built;
|
|
312
|
+
for (const cm of getCustomModels()) {
|
|
313
|
+
if (cm.provider === provider && cm.id === bareId) {
|
|
314
|
+
const model = buildCustomModel(cm.provider, cm.id, cm.name);
|
|
315
|
+
if (model) return model;
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
return void 0;
|
|
319
|
+
}
|
|
269
320
|
for (const provider of getBuiltinProviders()) {
|
|
270
321
|
const model = getBuiltinModel(provider, modelId);
|
|
271
322
|
if (model) return model;
|
|
@@ -331,6 +382,7 @@ export {
|
|
|
331
382
|
resolveTemplate,
|
|
332
383
|
getEnabledModels,
|
|
333
384
|
setEnabledModels,
|
|
385
|
+
migrateAiModelQualification,
|
|
334
386
|
getCustomModels,
|
|
335
387
|
addCustomModel,
|
|
336
388
|
removeCustomModel,
|
|
@@ -339,5 +391,6 @@ export {
|
|
|
339
391
|
resolveApiKey,
|
|
340
392
|
qualifyModelId,
|
|
341
393
|
unqualifyModelId,
|
|
394
|
+
findModel,
|
|
342
395
|
aiComplete
|
|
343
396
|
};
|
|
@@ -7,14 +7,14 @@ import {
|
|
|
7
7
|
modeLabel,
|
|
8
8
|
pollHealth,
|
|
9
9
|
startService
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-ATEX3ZPG.js";
|
|
11
11
|
import {
|
|
12
12
|
readGlobalConfig
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-ONM2AZFL.js";
|
|
14
14
|
import {
|
|
15
15
|
voluteHome,
|
|
16
16
|
voluteSystemDir
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-YAMO2U3N.js";
|
|
18
18
|
|
|
19
19
|
// src/commands/up.ts
|
|
20
20
|
import { spawn } from "child_process";
|
package/dist/cli.js
CHANGED
|
@@ -10,7 +10,7 @@ if (!process.env.VOLUTE_HOME) {
|
|
|
10
10
|
var command = process.argv[2];
|
|
11
11
|
var args = process.argv.slice(3);
|
|
12
12
|
if (command === "--version" || command === "-v") {
|
|
13
|
-
const { default: pkg } = await import("./package-
|
|
13
|
+
const { default: pkg } = await import("./package-ZOI2KAYC.js");
|
|
14
14
|
console.log(pkg.version);
|
|
15
15
|
process.exit(0);
|
|
16
16
|
}
|
|
@@ -31,7 +31,7 @@ var ungatedCommands = /* @__PURE__ */ new Set([
|
|
|
31
31
|
void 0
|
|
32
32
|
]);
|
|
33
33
|
if (!ungatedCommands.has(command)) {
|
|
34
|
-
const { isSetupComplete } = await import("./setup-
|
|
34
|
+
const { isSetupComplete } = await import("./setup-25MMJ3J4.js");
|
|
35
35
|
if (!isSetupComplete()) {
|
|
36
36
|
console.error("Volute is not set up. Run `volute setup` first.");
|
|
37
37
|
process.exit(1);
|
|
@@ -39,61 +39,61 @@ if (!ungatedCommands.has(command)) {
|
|
|
39
39
|
}
|
|
40
40
|
switch (command) {
|
|
41
41
|
case "setup":
|
|
42
|
-
await import("./setup-
|
|
42
|
+
await import("./setup-354PDHUF.js").then((m) => m.run(args));
|
|
43
43
|
break;
|
|
44
44
|
case "mind":
|
|
45
|
-
await import("./mind-
|
|
45
|
+
await import("./mind-QEWCR7FA.js").then((m) => m.run(args));
|
|
46
46
|
break;
|
|
47
47
|
case "seed":
|
|
48
|
-
await import("./seed-cmd-
|
|
48
|
+
await import("./seed-cmd-GJFENEJH.js").then((m) => m.run(args));
|
|
49
49
|
break;
|
|
50
50
|
case "chat":
|
|
51
|
-
await import("./chat-
|
|
51
|
+
await import("./chat-SDSX5TVV.js").then((m) => m.run(args));
|
|
52
52
|
break;
|
|
53
53
|
case "variant":
|
|
54
54
|
await import("./variant-HHDTW74J.js").then((m) => m.run(args));
|
|
55
55
|
break;
|
|
56
56
|
case "clock":
|
|
57
|
-
await import("./clock-
|
|
57
|
+
await import("./clock-K43IMROX.js").then((m) => m.run(args));
|
|
58
58
|
break;
|
|
59
59
|
case "skill":
|
|
60
|
-
await import("./skill-
|
|
60
|
+
await import("./skill-FKFHIJRR.js").then((m) => m.run(args));
|
|
61
61
|
break;
|
|
62
62
|
case "env":
|
|
63
|
-
await import("./env-
|
|
63
|
+
await import("./env-VZ4MLFQW.js").then((m) => m.run(args));
|
|
64
64
|
break;
|
|
65
65
|
case "config":
|
|
66
|
-
await import("./config-
|
|
66
|
+
await import("./config-TJLYUV3U.js").then((m) => m.run(args));
|
|
67
67
|
break;
|
|
68
68
|
case "up":
|
|
69
|
-
await import("./up-
|
|
69
|
+
await import("./up-7RSBEKW6.js").then((m) => m.run(args));
|
|
70
70
|
break;
|
|
71
71
|
case "down":
|
|
72
|
-
await import("./down-
|
|
72
|
+
await import("./down-RRNYIGCU.js").then((m) => m.run(args));
|
|
73
73
|
break;
|
|
74
74
|
case "restart":
|
|
75
|
-
await import("./daemon-restart-
|
|
75
|
+
await import("./daemon-restart-5GVZ5V3X.js").then((m) => m.run(args));
|
|
76
76
|
break;
|
|
77
77
|
case "update":
|
|
78
|
-
await import("./update-
|
|
78
|
+
await import("./update-EJ7Q77ZX.js").then((m) => m.run(args));
|
|
79
79
|
break;
|
|
80
80
|
case "status":
|
|
81
|
-
await import("./status-
|
|
81
|
+
await import("./status-WTU2WHXY.js").then((m) => m.run(args));
|
|
82
82
|
break;
|
|
83
83
|
case "extension":
|
|
84
|
-
await import("./extension-
|
|
84
|
+
await import("./extension-SEID47SR.js").then((m) => m.run(args));
|
|
85
85
|
break;
|
|
86
86
|
case "systems":
|
|
87
|
-
await import("./systems-
|
|
87
|
+
await import("./systems-VNB5WKSS.js").then((m) => m.run(args));
|
|
88
88
|
break;
|
|
89
89
|
case "login":
|
|
90
|
-
await import("./login-
|
|
90
|
+
await import("./login-KJSN4JDA.js").then((m) => m.run(args));
|
|
91
91
|
break;
|
|
92
92
|
case "logout":
|
|
93
|
-
await import("./logout-
|
|
93
|
+
await import("./logout-TMJGUQV2.js").then((m) => m.run(args));
|
|
94
94
|
break;
|
|
95
95
|
case "service":
|
|
96
|
-
await import("./service-
|
|
96
|
+
await import("./service-4EVZKGSA.js").then((m) => m.run(args));
|
|
97
97
|
break;
|
|
98
98
|
case "--help":
|
|
99
99
|
case "-h":
|
|
@@ -150,7 +150,7 @@ use --mind <name> or VOLUTE_MIND env var to identify the mind.`);
|
|
|
150
150
|
default: {
|
|
151
151
|
let isExtensionCommand = false;
|
|
152
152
|
try {
|
|
153
|
-
const { daemonFetch } = await import("./daemon-client-
|
|
153
|
+
const { daemonFetch } = await import("./daemon-client-IYR4KCPU.js");
|
|
154
154
|
const res = await daemonFetch("/api/extensions/commands");
|
|
155
155
|
if (res.ok) {
|
|
156
156
|
const extCommands = await res.json();
|
|
@@ -264,7 +264,7 @@ Run 'volute --help' for usage.`);
|
|
|
264
264
|
}
|
|
265
265
|
}
|
|
266
266
|
if (command !== "update") {
|
|
267
|
-
import("./update-check-
|
|
267
|
+
import("./update-check-ACYYNKTW.js").then((m) => m.checkForUpdate()).then((result) => {
|
|
268
268
|
if (result.updateAvailable) {
|
|
269
269
|
console.error(`
|
|
270
270
|
Update available: ${result.current} \u2192 ${result.latest}`);
|
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
} from "./chunk-BTY4WNFE.js";
|
|
9
9
|
import {
|
|
10
10
|
daemonFetch
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-RBNMDAKB.js";
|
|
12
12
|
import {
|
|
13
13
|
getClient,
|
|
14
14
|
urlOf
|
|
@@ -274,11 +274,11 @@ var cmd = subcommands({
|
|
|
274
274
|
},
|
|
275
275
|
sleep: {
|
|
276
276
|
description: "Put a mind to sleep",
|
|
277
|
-
run: (args) => import("./mind-sleep-
|
|
277
|
+
run: (args) => import("./mind-sleep-YMBR3I35.js").then((m) => m.run(args))
|
|
278
278
|
},
|
|
279
279
|
wake: {
|
|
280
280
|
description: "Wake a sleeping mind",
|
|
281
|
-
run: (args) => import("./mind-wake-
|
|
281
|
+
run: (args) => import("./mind-wake-LCLGTXA2.js").then((m) => m.run(args))
|
|
282
282
|
}
|
|
283
283
|
},
|
|
284
284
|
footer: "Use --mind <name> or VOLUTE_MIND to identify the mind."
|
|
@@ -1,31 +1,30 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
deliverMessage
|
|
4
|
-
} from "./chunk-
|
|
5
|
-
import "./chunk-
|
|
6
|
-
import "./chunk-
|
|
4
|
+
} from "./chunk-PF2AB7VJ.js";
|
|
5
|
+
import "./chunk-XDTKJNW5.js";
|
|
6
|
+
import "./chunk-65OLHBCL.js";
|
|
7
7
|
import "./chunk-QLWG3C2Z.js";
|
|
8
|
-
import "./chunk-
|
|
8
|
+
import "./chunk-FSSUANZJ.js";
|
|
9
9
|
import {
|
|
10
10
|
getAuthHeaders,
|
|
11
11
|
getWebhookUrl
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-K4EHBHPE.js";
|
|
13
13
|
import "./chunk-CU6OFXMM.js";
|
|
14
|
-
import "./chunk-
|
|
15
|
-
import "./chunk-
|
|
16
|
-
import "./chunk-
|
|
17
|
-
import "./chunk-
|
|
18
|
-
import "./chunk-
|
|
19
|
-
import "./chunk-
|
|
20
|
-
import "./chunk-
|
|
21
|
-
import "./chunk-
|
|
22
|
-
import "./chunk-
|
|
23
|
-
import "./chunk-K547QOCM.js";
|
|
14
|
+
import "./chunk-C6ESRQZ7.js";
|
|
15
|
+
import "./chunk-M3PGGSBH.js";
|
|
16
|
+
import "./chunk-SPLPKBES.js";
|
|
17
|
+
import "./chunk-3WLWKOGM.js";
|
|
18
|
+
import "./chunk-PGPLCJPK.js";
|
|
19
|
+
import "./chunk-YSV3VJQK.js";
|
|
20
|
+
import "./chunk-ONM2AZFL.js";
|
|
21
|
+
import "./chunk-EFL5UOY4.js";
|
|
22
|
+
import "./chunk-7G2EEYXX.js";
|
|
24
23
|
import {
|
|
25
24
|
logger_default
|
|
26
25
|
} from "./chunk-T2TP6ZC6.js";
|
|
27
|
-
import "./chunk-
|
|
28
|
-
import "./chunk-
|
|
26
|
+
import "./chunk-YAMO2U3N.js";
|
|
27
|
+
import "./chunk-L3IV23ZG.js";
|
|
29
28
|
import "./chunk-K3NQKI34.js";
|
|
30
29
|
|
|
31
30
|
// packages/daemon/src/lib/cloud-sync.ts
|