volute 0.42.1 → 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.
Files changed (98) hide show
  1. package/dist/{activity-events-KFKVRZE3.js → activity-events-UISXY4Y5.js} +3 -3
  2. package/dist/{ai-service-3GBOJGUA.js → ai-service-FBCCEYF5.js} +8 -4
  3. package/dist/{archive-4PPYF7LL.js → archive-I32WHCJB.js} +3 -3
  4. package/dist/{auth-EAASQPTN.js → auth-3RIG6GKN.js} +4 -4
  5. package/dist/{chat-LYL5CWJV.js → chat-SDSX5TVV.js} +2 -2
  6. package/dist/{chunk-M2YMNTHK.js → chunk-2HIVYZDB.js} +1 -1
  7. package/dist/{chunk-BWZHX46O.js → chunk-3WLWKOGM.js} +21 -6
  8. package/dist/{chunk-QPTQKGGF.js → chunk-57LBQ7JX.js} +1 -1
  9. package/dist/{chunk-43K5UWF7.js → chunk-65OLHBCL.js} +13 -12
  10. package/dist/{chunk-K547QOCM.js → chunk-7G2EEYXX.js} +2 -2
  11. package/dist/{chunk-E7XWFDZL.js → chunk-AD46AYZQ.js} +1 -1
  12. package/dist/{chunk-P6DPB33N.js → chunk-ATEX3ZPG.js} +2 -2
  13. package/dist/{chunk-WR7CSHQ4.js → chunk-C6ESRQZ7.js} +1 -1
  14. package/dist/{chunk-BR6KFHVT.js → chunk-EE7SZJON.js} +2 -2
  15. package/dist/{chunk-5QG36RV7.js → chunk-EFL5UOY4.js} +3 -3
  16. package/dist/{chunk-M3T3Y6FT.js → chunk-FSSUANZJ.js} +5 -5
  17. package/dist/{chunk-JPDN6ZRJ.js → chunk-FZ5TH5PF.js} +8 -8
  18. package/dist/{chunk-OEJFZHZZ.js → chunk-GZJFC76M.js} +1 -1
  19. package/dist/{chunk-KUJVCDWT.js → chunk-JVK6QQIC.js} +2 -2
  20. package/dist/{chunk-YLTIEEVL.js → chunk-K4EHBHPE.js} +3 -3
  21. package/dist/{chunk-MHFAWJCC.js → chunk-L3IV23ZG.js} +12 -1
  22. package/dist/{chunk-VBKRZCR7.js → chunk-M3PGGSBH.js} +1 -1
  23. package/dist/{chunk-NSGIVS5T.js → chunk-O3DXAR44.js} +2 -2
  24. package/dist/{chunk-KZAL7HEQ.js → chunk-ONM2AZFL.js} +1 -1
  25. package/dist/{chunk-6G7R2LPI.js → chunk-PF2AB7VJ.js} +568 -378
  26. package/dist/chunk-PGPLCJPK.js +272 -0
  27. package/dist/{chunk-62ICA2FF.js → chunk-SPLPKBES.js} +17 -1
  28. package/dist/{chunk-BLOAJLGI.js → chunk-XDTKJNW5.js} +1 -1
  29. package/dist/{chunk-IUZ3EV2D.js → chunk-YAMO2U3N.js} +1 -1
  30. package/dist/{chunk-4ZSUUBG5.js → chunk-YSV3VJQK.js} +55 -2
  31. package/dist/{chunk-JU5GWO77.js → chunk-ZO7IQJKO.js} +3 -3
  32. package/dist/cli.js +15 -15
  33. package/dist/{cloud-sync-E3ZL5SZ4.js → cloud-sync-FRYNWKCR.js} +16 -17
  34. package/dist/{conversations-FSZCUUYO.js → conversations-67WWW25C.js} +4 -4
  35. package/dist/{create-ERNQYOCK.js → create-7W3LV3J7.js} +1 -1
  36. package/dist/{daemon-restart-QBZOMILO.js → daemon-restart-5GVZ5V3X.js} +7 -8
  37. package/dist/daemon.js +524 -433
  38. package/dist/{db-ZJJJYJBU.js → db-CZV62BOQ.js} +2 -2
  39. package/dist/delivery-manager-5J2BE22P.js +32 -0
  40. package/dist/{delivery-router-FDBZJQOY.js → delivery-router-HXBHYHJM.js} +7 -5
  41. package/dist/down-RRNYIGCU.js +16 -0
  42. package/dist/echo-text-XKBJM6RV.js +32 -0
  43. package/dist/{exec-ZDD7NEB4.js → exec-SJK7VUTC.js} +3 -4
  44. package/dist/{export-WYI3E3TB.js → export-7LPCIB5J.js} +3 -3
  45. package/dist/{extensions-X6MKBJLB.js → extensions-76EGTMFY.js} +16 -17
  46. package/dist/{files-COTCVBGO.js → files-LV7VAKPC.js} +3 -3
  47. package/dist/{import-EPK6WCYS.js → import-XPECCRQ7.js} +6 -6
  48. package/dist/{isolation-F7ABZMDA.js → isolation-5AYEY55P.js} +5 -3
  49. package/dist/{login-GPBXOU4D.js → login-KJSN4JDA.js} +2 -2
  50. package/dist/{logout-DNNTIYE2.js → logout-TMJGUQV2.js} +2 -2
  51. package/dist/message-delivery-WJBZFALY.js +34 -0
  52. package/dist/{mind-K5PZHPBR.js → mind-QEWCR7FA.js} +5 -5
  53. package/dist/{mind-activity-tracker-HWVFE533.js → mind-activity-tracker-JHAT6456.js} +4 -4
  54. package/dist/mind-service-ZBVUMJ5H.js +36 -0
  55. package/dist/{package-G4AM2IDZ.js → package-ZOI2KAYC.js} +1 -1
  56. package/dist/{registry-MDLNPTTI.js → registry-7LQHTRUX.js} +2 -2
  57. package/dist/{sandbox-E7RWZDVG.js → sandbox-SJH3XOPZ.js} +4 -4
  58. package/dist/scheduler-BR6C6B3E.js +30 -0
  59. package/dist/{schema-HHYJDG7B.js → schema-LRUTFOER.js} +1 -1
  60. package/dist/{seed-SKVSWF7S.js → seed-KOG6KJAO.js} +1 -1
  61. package/dist/{seed-cmd-D2H5VLB4.js → seed-cmd-GJFENEJH.js} +2 -2
  62. package/dist/{seed-create-BUSKQ5II.js → seed-create-YXO6R4KE.js} +3 -3
  63. package/dist/{seed-sprout-R2IZPITD.js → seed-sprout-BBU64QXP.js} +7 -8
  64. package/dist/{send-SLDFRSTL.js → send-ZBZWIH5V.js} +3 -3
  65. package/dist/{service-ZDOSEQCE.js → service-4EVZKGSA.js} +4 -5
  66. package/dist/{service-install-2HZPDHEY.js → service-install-SHRM6NHK.js} +5 -6
  67. package/dist/{setup-IYOUPCIK.js → setup-25MMJ3J4.js} +3 -3
  68. package/dist/{setup-IU3ID7II.js → setup-354PDHUF.js} +8 -10
  69. package/dist/{skills-P6RGGASV.js → skills-DPI3WZPQ.js} +5 -6
  70. package/dist/sleep-manager-BVU5D2AE.js +34 -0
  71. package/dist/{spirit-XLD6QXSS.js → spirit-JQQHUVWR.js} +7 -8
  72. package/dist/{sprout-QV2RJM5W.js → sprout-4WAYBUVV.js} +1 -1
  73. package/dist/{status-QAKAPDYW.js → status-WTU2WHXY.js} +5 -6
  74. package/dist/system-chat-KMQIP7VH.js +34 -0
  75. package/dist/{tailscale-TIRTGM6E.js → tailscale-Q7ZJL7S7.js} +2 -2
  76. package/dist/{turn-tracker-Z5UJC4BY.js → turn-tracker-2GMKJQTN.js} +7 -5
  77. package/dist/up-7RSBEKW6.js +18 -0
  78. package/dist/{update-NY3XBVAJ.js → update-EJ7Q77ZX.js} +5 -6
  79. package/dist/{update-check-OG27AL4Z.js → update-check-ACYYNKTW.js} +3 -3
  80. package/dist/{version-notify-P7UAR7HZ.js → version-notify-DCAIXXZB.js} +17 -18
  81. package/dist/web-assets/assets/{index-CrFAsfiE.js → index-DTDmEfPU.js} +2 -2
  82. package/dist/web-assets/index.html +1 -1
  83. package/drizzle/0010_delivery_queue_redrive.sql +10 -0
  84. package/drizzle/meta/_journal.json +7 -0
  85. package/package.json +1 -1
  86. package/templates/codex/src/server.ts +2 -8
  87. package/dist/chunk-GN52E2DP.js +0 -59
  88. package/dist/chunk-TFBQESH7.js +0 -179
  89. package/dist/delivery-manager-J3BRHXUF.js +0 -33
  90. package/dist/down-DSRWSCXY.js +0 -17
  91. package/dist/echo-text-3HBQUWPX.js +0 -33
  92. package/dist/message-delivery-4ZWFDBAY.js +0 -41
  93. package/dist/mind-manager-6DSY5IJW.js +0 -33
  94. package/dist/mind-service-R2FM53KD.js +0 -37
  95. package/dist/scheduler-2FKQCRCM.js +0 -31
  96. package/dist/sleep-manager-F5KWIFOX.js +0 -35
  97. package/dist/system-chat-EQIH6JVL.js +0 -35
  98. package/dist/up-ZTPGC7HB.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
+ };
@@ -4,7 +4,7 @@ import {
4
4
  } from "./chunk-T2TP6ZC6.js";
5
5
  import {
6
6
  mindDir
7
- } from "./chunk-IUZ3EV2D.js";
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
  stateDir,
4
4
  voluteSystemDir
5
- } from "./chunk-IUZ3EV2D.js";
5
+ } from "./chunk-YAMO2U3N.js";
6
6
 
7
7
  // packages/daemon/src/lib/config/env.ts
8
8
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  minds,
4
4
  schema_exports
5
- } from "./chunk-MHFAWJCC.js";
5
+ } from "./chunk-L3IV23ZG.js";
6
6
 
7
7
  // packages/daemon/src/lib/db.ts
8
8
  import { chmodSync, existsSync } from "fs";
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  readGlobalConfig,
4
4
  writeGlobalConfig
5
- } from "./chunk-KZAL7HEQ.js";
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
- ai.models = ai.models.filter((mid) => mid !== id);
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-P6DPB33N.js";
10
+ } from "./chunk-ATEX3ZPG.js";
11
11
  import {
12
12
  readGlobalConfig
13
- } from "./chunk-KZAL7HEQ.js";
13
+ } from "./chunk-ONM2AZFL.js";
14
14
  import {
15
15
  voluteHome,
16
16
  voluteSystemDir
17
- } from "./chunk-IUZ3EV2D.js";
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-G4AM2IDZ.js");
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-IYOUPCIK.js");
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,16 +39,16 @@ if (!ungatedCommands.has(command)) {
39
39
  }
40
40
  switch (command) {
41
41
  case "setup":
42
- await import("./setup-IU3ID7II.js").then((m) => m.run(args));
42
+ await import("./setup-354PDHUF.js").then((m) => m.run(args));
43
43
  break;
44
44
  case "mind":
45
- await import("./mind-K5PZHPBR.js").then((m) => m.run(args));
45
+ await import("./mind-QEWCR7FA.js").then((m) => m.run(args));
46
46
  break;
47
47
  case "seed":
48
- await import("./seed-cmd-D2H5VLB4.js").then((m) => m.run(args));
48
+ await import("./seed-cmd-GJFENEJH.js").then((m) => m.run(args));
49
49
  break;
50
50
  case "chat":
51
- await import("./chat-LYL5CWJV.js").then((m) => m.run(args));
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));
@@ -66,19 +66,19 @@ switch (command) {
66
66
  await import("./config-TJLYUV3U.js").then((m) => m.run(args));
67
67
  break;
68
68
  case "up":
69
- await import("./up-ZTPGC7HB.js").then((m) => m.run(args));
69
+ await import("./up-7RSBEKW6.js").then((m) => m.run(args));
70
70
  break;
71
71
  case "down":
72
- await import("./down-DSRWSCXY.js").then((m) => m.run(args));
72
+ await import("./down-RRNYIGCU.js").then((m) => m.run(args));
73
73
  break;
74
74
  case "restart":
75
- await import("./daemon-restart-QBZOMILO.js").then((m) => m.run(args));
75
+ await import("./daemon-restart-5GVZ5V3X.js").then((m) => m.run(args));
76
76
  break;
77
77
  case "update":
78
- await import("./update-NY3XBVAJ.js").then((m) => m.run(args));
78
+ await import("./update-EJ7Q77ZX.js").then((m) => m.run(args));
79
79
  break;
80
80
  case "status":
81
- await import("./status-QAKAPDYW.js").then((m) => m.run(args));
81
+ await import("./status-WTU2WHXY.js").then((m) => m.run(args));
82
82
  break;
83
83
  case "extension":
84
84
  await import("./extension-SEID47SR.js").then((m) => m.run(args));
@@ -87,13 +87,13 @@ switch (command) {
87
87
  await import("./systems-VNB5WKSS.js").then((m) => m.run(args));
88
88
  break;
89
89
  case "login":
90
- await import("./login-GPBXOU4D.js").then((m) => m.run(args));
90
+ await import("./login-KJSN4JDA.js").then((m) => m.run(args));
91
91
  break;
92
92
  case "logout":
93
- await import("./logout-DNNTIYE2.js").then((m) => m.run(args));
93
+ await import("./logout-TMJGUQV2.js").then((m) => m.run(args));
94
94
  break;
95
95
  case "service":
96
- await import("./service-ZDOSEQCE.js").then((m) => m.run(args));
96
+ await import("./service-4EVZKGSA.js").then((m) => m.run(args));
97
97
  break;
98
98
  case "--help":
99
99
  case "-h":
@@ -264,7 +264,7 @@ Run 'volute --help' for usage.`);
264
264
  }
265
265
  }
266
266
  if (command !== "update") {
267
- import("./update-check-OG27AL4Z.js").then((m) => m.checkForUpdate()).then((result) => {
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}`);
@@ -1,31 +1,30 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  deliverMessage
4
- } from "./chunk-6G7R2LPI.js";
5
- import "./chunk-BLOAJLGI.js";
6
- import "./chunk-43K5UWF7.js";
4
+ } from "./chunk-PF2AB7VJ.js";
5
+ import "./chunk-XDTKJNW5.js";
6
+ import "./chunk-65OLHBCL.js";
7
7
  import "./chunk-QLWG3C2Z.js";
8
- import "./chunk-M3T3Y6FT.js";
8
+ import "./chunk-FSSUANZJ.js";
9
9
  import {
10
10
  getAuthHeaders,
11
11
  getWebhookUrl
12
- } from "./chunk-YLTIEEVL.js";
12
+ } from "./chunk-K4EHBHPE.js";
13
13
  import "./chunk-CU6OFXMM.js";
14
- import "./chunk-WR7CSHQ4.js";
15
- import "./chunk-VBKRZCR7.js";
16
- import "./chunk-62ICA2FF.js";
17
- import "./chunk-BWZHX46O.js";
18
- import "./chunk-GN52E2DP.js";
19
- import "./chunk-TFBQESH7.js";
20
- import "./chunk-4ZSUUBG5.js";
21
- import "./chunk-KZAL7HEQ.js";
22
- import "./chunk-5QG36RV7.js";
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-IUZ3EV2D.js";
28
- import "./chunk-MHFAWJCC.js";
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
@@ -29,11 +29,11 @@ import {
29
29
  removeParticipant,
30
30
  setConversationPrivate,
31
31
  updateChannelSettings
32
- } from "./chunk-YLTIEEVL.js";
33
- import "./chunk-K547QOCM.js";
32
+ } from "./chunk-K4EHBHPE.js";
33
+ import "./chunk-7G2EEYXX.js";
34
34
  import "./chunk-T2TP6ZC6.js";
35
- import "./chunk-IUZ3EV2D.js";
36
- import "./chunk-MHFAWJCC.js";
35
+ import "./chunk-YAMO2U3N.js";
36
+ import "./chunk-L3IV23ZG.js";
37
37
  import "./chunk-K3NQKI34.js";
38
38
  export {
39
39
  addMessage,
@@ -21,7 +21,7 @@ var cmd = command({
21
21
  const name = args.name;
22
22
  let template = flags.template;
23
23
  if (!template) {
24
- const { resolveTemplate } = await import("./ai-service-3GBOJGUA.js");
24
+ const { resolveTemplate } = await import("./ai-service-FBCCEYF5.js");
25
25
  template = await resolveTemplate();
26
26
  }
27
27
  const skills = flags.skills === "none" ? [] : flags.skills ? flags.skills.split(",") : void 0;
@@ -1,10 +1,10 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  stopDaemon
4
- } from "./chunk-NSGIVS5T.js";
4
+ } from "./chunk-O3DXAR44.js";
5
5
  import {
6
6
  run
7
- } from "./chunk-JU5GWO77.js";
7
+ } from "./chunk-ZO7IQJKO.js";
8
8
  import {
9
9
  command
10
10
  } from "./chunk-TXSA4Q3V.js";
@@ -15,12 +15,11 @@ import {
15
15
  pollHealth,
16
16
  readDaemonConfig,
17
17
  restartService
18
- } from "./chunk-P6DPB33N.js";
19
- import "./chunk-GN52E2DP.js";
20
- import "./chunk-TFBQESH7.js";
21
- import "./chunk-KZAL7HEQ.js";
22
- import "./chunk-IUZ3EV2D.js";
23
- import "./chunk-MHFAWJCC.js";
18
+ } from "./chunk-ATEX3ZPG.js";
19
+ import "./chunk-PGPLCJPK.js";
20
+ import "./chunk-ONM2AZFL.js";
21
+ import "./chunk-YAMO2U3N.js";
22
+ import "./chunk-L3IV23ZG.js";
24
23
  import "./chunk-K3NQKI34.js";
25
24
 
26
25
  // src/commands/daemon-restart.ts