volute 0.16.0 → 0.18.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/chunk-AYB7XAWO.js +812 -0
- package/dist/{chunk-3FD4ZZUL.js → chunk-FW5API7X.js} +116 -10
- package/dist/{chunk-3FC42ZBM.js → chunk-GK4E7LM7.js} +3 -0
- package/dist/cli.js +18 -6
- package/dist/connectors/discord.js +1 -1
- package/dist/connectors/slack.js +1 -1
- package/dist/connectors/telegram.js +1 -1
- package/dist/{daemon-restart-MS5FI44G.js → daemon-restart-2HVTHZAT.js} +1 -1
- package/dist/daemon.js +1443 -592
- package/dist/history-YUEKTJ2N.js +108 -0
- package/dist/{mind-manager-PN5SUDJ4.js → mind-manager-Z7O7PN2O.js} +1 -1
- package/dist/{package-3QGV3KX6.js → package-OKLFO7UY.js} +8 -9
- package/dist/{send-KBBZNYG6.js → send-BNDTLUPM.js} +41 -9
- package/dist/skill-2Y42P4JY.js +287 -0
- package/dist/{up-GZLWZAQE.js → up-7B3BWF2U.js} +1 -1
- package/dist/web-assets/assets/index-CtiimdWK.css +1 -0
- package/dist/web-assets/assets/index-kt1_EcuO.js +63 -0
- package/dist/web-assets/index.html +2 -1
- package/drizzle/0006_mind_history.sql +20 -0
- package/drizzle/0007_system_prompts.sql +5 -0
- package/drizzle/0008_volute_channels.sql +24 -0
- package/drizzle/0009_shared_skills.sql +9 -0
- package/drizzle/meta/0006_snapshot.json +7 -0
- package/drizzle/meta/0007_snapshot.json +7 -0
- package/drizzle/meta/0008_snapshot.json +7 -0
- package/drizzle/meta/0009_snapshot.json +7 -0
- package/drizzle/meta/_journal.json +28 -0
- package/package.json +8 -9
- package/templates/_base/.init/.config/prompts.json +5 -0
- package/templates/_base/_skills/volute-mind/SKILL.md +19 -5
- package/templates/_base/src/lib/daemon-client.ts +45 -0
- package/templates/_base/src/lib/logger.ts +19 -0
- package/templates/_base/src/lib/router.ts +48 -41
- package/templates/_base/src/lib/routing.ts +5 -8
- package/templates/_base/src/lib/startup.ts +43 -0
- package/templates/_base/src/lib/transparency.ts +89 -0
- package/templates/_base/src/lib/types.ts +0 -1
- package/templates/_base/src/lib/volute-server.ts +3 -35
- package/templates/claude/src/agent.ts +9 -22
- package/templates/claude/src/lib/hooks/reply-instructions.ts +6 -9
- package/templates/claude/src/lib/stream-consumer.ts +39 -12
- package/templates/pi/src/agent.ts +9 -22
- package/templates/pi/src/lib/event-handler.ts +58 -7
- package/templates/pi/src/lib/reply-instructions-extension.ts +6 -9
- package/dist/chunk-J52CJCVI.js +0 -447
- package/dist/history-LKCJJMUV.js +0 -50
- package/dist/web-assets/assets/index-B1XIIGCh.js +0 -307
- package/templates/_base/src/lib/auto-reply.ts +0 -38
- /package/dist/{chunk-LLBBVTEY.js → chunk-6DVBMLVN.js} +0 -0
package/dist/chunk-J52CJCVI.js
DELETED
|
@@ -1,447 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
loadMergedEnv
|
|
4
|
-
} from "./chunk-OYSZNX5I.js";
|
|
5
|
-
import {
|
|
6
|
-
chownMindDir,
|
|
7
|
-
isIsolationEnabled,
|
|
8
|
-
wrapForIsolation
|
|
9
|
-
} from "./chunk-ZCEYUUID.js";
|
|
10
|
-
import {
|
|
11
|
-
findMind,
|
|
12
|
-
findVariant,
|
|
13
|
-
mindDir,
|
|
14
|
-
setMindRunning,
|
|
15
|
-
setVariantRunning,
|
|
16
|
-
stateDir,
|
|
17
|
-
voluteHome
|
|
18
|
-
} from "./chunk-M77QBTEH.js";
|
|
19
|
-
|
|
20
|
-
// src/lib/mind-manager.ts
|
|
21
|
-
import { execFile, spawn } from "child_process";
|
|
22
|
-
import { existsSync as existsSync3, mkdirSync, readFileSync as readFileSync2, rmSync as rmSync2, writeFileSync as writeFileSync2 } from "fs";
|
|
23
|
-
import { resolve } from "path";
|
|
24
|
-
import { promisify } from "util";
|
|
25
|
-
|
|
26
|
-
// src/lib/json-state.ts
|
|
27
|
-
import { existsSync, readFileSync, unlinkSync, writeFileSync } from "fs";
|
|
28
|
-
function loadJsonMap(path) {
|
|
29
|
-
const map = /* @__PURE__ */ new Map();
|
|
30
|
-
try {
|
|
31
|
-
if (existsSync(path)) {
|
|
32
|
-
const data = JSON.parse(readFileSync(path, "utf-8"));
|
|
33
|
-
for (const [key, value] of Object.entries(data)) {
|
|
34
|
-
if (typeof value === "number") map.set(key, value);
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
} catch (err) {
|
|
38
|
-
console.warn(`[state] failed to load ${path}:`, err);
|
|
39
|
-
}
|
|
40
|
-
return map;
|
|
41
|
-
}
|
|
42
|
-
function saveJsonMap(path, map) {
|
|
43
|
-
const data = {};
|
|
44
|
-
for (const [key, value] of map) {
|
|
45
|
-
data[key] = value;
|
|
46
|
-
}
|
|
47
|
-
try {
|
|
48
|
-
writeFileSync(path, `${JSON.stringify(data)}
|
|
49
|
-
`);
|
|
50
|
-
} catch (err) {
|
|
51
|
-
console.warn(`[state] failed to save ${path}:`, err);
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
function clearJsonMap(path, map) {
|
|
55
|
-
map.clear();
|
|
56
|
-
try {
|
|
57
|
-
if (existsSync(path)) unlinkSync(path);
|
|
58
|
-
} catch (err) {
|
|
59
|
-
console.warn(`[state] failed to clear ${path}:`, err);
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
// src/lib/rotating-log.ts
|
|
64
|
-
import {
|
|
65
|
-
createWriteStream,
|
|
66
|
-
existsSync as existsSync2,
|
|
67
|
-
renameSync,
|
|
68
|
-
rmSync,
|
|
69
|
-
statSync
|
|
70
|
-
} from "fs";
|
|
71
|
-
import { Writable } from "stream";
|
|
72
|
-
var MAX_SIZE = 10 * 1024 * 1024;
|
|
73
|
-
var RotatingLog = class extends Writable {
|
|
74
|
-
constructor(path, maxSize = MAX_SIZE, maxFiles = 5) {
|
|
75
|
-
super();
|
|
76
|
-
this.path = path;
|
|
77
|
-
this.maxSize = maxSize;
|
|
78
|
-
this.maxFiles = maxFiles;
|
|
79
|
-
this.on("error", () => {
|
|
80
|
-
});
|
|
81
|
-
try {
|
|
82
|
-
this.size = existsSync2(path) ? statSync(path).size : 0;
|
|
83
|
-
} catch {
|
|
84
|
-
this.size = 0;
|
|
85
|
-
}
|
|
86
|
-
this.stream = createWriteStream(path, { flags: "a" });
|
|
87
|
-
}
|
|
88
|
-
stream;
|
|
89
|
-
size;
|
|
90
|
-
_write(chunk, _encoding, callback) {
|
|
91
|
-
this.size += chunk.length;
|
|
92
|
-
if (this.size > this.maxSize) {
|
|
93
|
-
try {
|
|
94
|
-
const oldest = `${this.path}.${this.maxFiles}`;
|
|
95
|
-
if (existsSync2(oldest)) rmSync(oldest);
|
|
96
|
-
for (let i = this.maxFiles - 1; i >= 1; i--) {
|
|
97
|
-
const from = `${this.path}.${i}`;
|
|
98
|
-
const to = `${this.path}.${i + 1}`;
|
|
99
|
-
if (existsSync2(from)) renameSync(from, to);
|
|
100
|
-
}
|
|
101
|
-
renameSync(this.path, `${this.path}.1`);
|
|
102
|
-
const oldStream = this.stream;
|
|
103
|
-
this.stream = createWriteStream(this.path);
|
|
104
|
-
this.size = chunk.length;
|
|
105
|
-
oldStream.end();
|
|
106
|
-
} catch {
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
this.stream.write(chunk, callback);
|
|
110
|
-
}
|
|
111
|
-
_final(callback) {
|
|
112
|
-
this.stream.end(callback);
|
|
113
|
-
}
|
|
114
|
-
};
|
|
115
|
-
|
|
116
|
-
// src/lib/mind-manager.ts
|
|
117
|
-
var execFileAsync = promisify(execFile);
|
|
118
|
-
function mindPidPath(name) {
|
|
119
|
-
return resolve(stateDir(name), "mind.pid");
|
|
120
|
-
}
|
|
121
|
-
var MAX_RESTART_ATTEMPTS = 5;
|
|
122
|
-
var BASE_RESTART_DELAY = 3e3;
|
|
123
|
-
var MAX_RESTART_DELAY = 6e4;
|
|
124
|
-
var MindManager = class {
|
|
125
|
-
minds = /* @__PURE__ */ new Map();
|
|
126
|
-
stopping = /* @__PURE__ */ new Set();
|
|
127
|
-
shuttingDown = false;
|
|
128
|
-
restartAttempts = /* @__PURE__ */ new Map();
|
|
129
|
-
pendingContext = /* @__PURE__ */ new Map();
|
|
130
|
-
resolveTarget(name) {
|
|
131
|
-
const [baseName, variantName] = name.split("@", 2);
|
|
132
|
-
const entry = findMind(baseName);
|
|
133
|
-
if (!entry) throw new Error(`Unknown mind: ${baseName}`);
|
|
134
|
-
if (variantName) {
|
|
135
|
-
const variant = findVariant(baseName, variantName);
|
|
136
|
-
if (!variant) throw new Error(`Unknown variant: ${variantName} (mind: ${baseName})`);
|
|
137
|
-
return { dir: variant.path, port: variant.port, isVariant: true, baseName, variantName };
|
|
138
|
-
}
|
|
139
|
-
const dir = mindDir(baseName);
|
|
140
|
-
if (!existsSync3(dir)) throw new Error(`Mind directory missing: ${dir}`);
|
|
141
|
-
return { dir, port: entry.port, isVariant: false, baseName };
|
|
142
|
-
}
|
|
143
|
-
async startMind(name) {
|
|
144
|
-
if (this.minds.has(name)) {
|
|
145
|
-
throw new Error(`Mind ${name} is already running`);
|
|
146
|
-
}
|
|
147
|
-
const target = this.resolveTarget(name);
|
|
148
|
-
const { dir, isVariant, baseName, variantName } = target;
|
|
149
|
-
const port = target.port;
|
|
150
|
-
const pidFile = mindPidPath(name);
|
|
151
|
-
try {
|
|
152
|
-
if (existsSync3(pidFile)) {
|
|
153
|
-
const stalePid = parseInt(readFileSync2(pidFile, "utf-8").trim(), 10);
|
|
154
|
-
if (stalePid > 0) {
|
|
155
|
-
try {
|
|
156
|
-
process.kill(stalePid, 0);
|
|
157
|
-
const { stdout } = await execFileAsync("ps", ["-p", String(stalePid), "-o", "args="]);
|
|
158
|
-
if (stdout.includes("server.ts")) {
|
|
159
|
-
console.error(`[daemon] killing stale mind process ${stalePid} for ${name}`);
|
|
160
|
-
process.kill(-stalePid, "SIGTERM");
|
|
161
|
-
await new Promise((r) => setTimeout(r, 500));
|
|
162
|
-
} else {
|
|
163
|
-
console.error(
|
|
164
|
-
`[daemon] stale PID ${stalePid} for ${name} is not a mind process, skipping`
|
|
165
|
-
);
|
|
166
|
-
}
|
|
167
|
-
} catch (err) {
|
|
168
|
-
if (err.code !== "ESRCH") {
|
|
169
|
-
console.error(`[daemon] failed to check/kill stale process for ${name}:`, err);
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
rmSync2(pidFile, { force: true });
|
|
174
|
-
}
|
|
175
|
-
} catch (err) {
|
|
176
|
-
console.error(`[daemon] failed to read PID file for ${name}:`, err);
|
|
177
|
-
}
|
|
178
|
-
try {
|
|
179
|
-
const res = await fetch(`http://127.0.0.1:${port}/health`);
|
|
180
|
-
if (res.ok) {
|
|
181
|
-
console.error(`[daemon] killing orphan process on port ${port}`);
|
|
182
|
-
await killProcessOnPort(port);
|
|
183
|
-
await new Promise((r) => setTimeout(r, 500));
|
|
184
|
-
}
|
|
185
|
-
} catch {
|
|
186
|
-
}
|
|
187
|
-
const mindStateDir = stateDir(name);
|
|
188
|
-
const logsDir = resolve(mindStateDir, "logs");
|
|
189
|
-
mkdirSync(logsDir, { recursive: true });
|
|
190
|
-
if (isIsolationEnabled()) {
|
|
191
|
-
try {
|
|
192
|
-
chownMindDir(mindStateDir, baseName);
|
|
193
|
-
} catch (err) {
|
|
194
|
-
throw new Error(
|
|
195
|
-
`Cannot start mind ${name}: failed to set ownership on state directory ${mindStateDir}: ${err instanceof Error ? err.message : err}`
|
|
196
|
-
);
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
const logStream = new RotatingLog(resolve(logsDir, "mind.log"));
|
|
200
|
-
const mindEnv = loadMergedEnv(name);
|
|
201
|
-
const env = {
|
|
202
|
-
...process.env,
|
|
203
|
-
...mindEnv,
|
|
204
|
-
VOLUTE_MIND: name,
|
|
205
|
-
VOLUTE_STATE_DIR: stateDir(name),
|
|
206
|
-
VOLUTE_MIND_DIR: dir,
|
|
207
|
-
VOLUTE_MIND_PORT: String(port),
|
|
208
|
-
// Strip CLAUDECODE so the Agent SDK can spawn Claude Code subprocesses
|
|
209
|
-
CLAUDECODE: void 0
|
|
210
|
-
};
|
|
211
|
-
if (isIsolationEnabled()) {
|
|
212
|
-
env.HOME = resolve(dir, "home");
|
|
213
|
-
}
|
|
214
|
-
const tsxBin = resolve(dir, "node_modules", ".bin", "tsx");
|
|
215
|
-
const tsxArgs = ["src/server.ts", "--port", String(port)];
|
|
216
|
-
const [spawnCmd, spawnArgs] = wrapForIsolation(tsxBin, tsxArgs, name);
|
|
217
|
-
const spawnOpts = {
|
|
218
|
-
cwd: dir,
|
|
219
|
-
stdio: ["ignore", "pipe", "pipe"],
|
|
220
|
-
detached: true,
|
|
221
|
-
env
|
|
222
|
-
};
|
|
223
|
-
const child = spawn(spawnCmd, spawnArgs, spawnOpts);
|
|
224
|
-
this.minds.set(name, { child, port });
|
|
225
|
-
child.stdout?.pipe(logStream);
|
|
226
|
-
child.stderr?.pipe(logStream);
|
|
227
|
-
try {
|
|
228
|
-
await new Promise((resolve2, reject) => {
|
|
229
|
-
const timeout = setTimeout(() => {
|
|
230
|
-
reject(new Error(`Mind ${name} did not start within 30s`));
|
|
231
|
-
}, 3e4);
|
|
232
|
-
function checkOutput(data) {
|
|
233
|
-
if (data.toString().match(/listening on :\d+/)) {
|
|
234
|
-
clearTimeout(timeout);
|
|
235
|
-
resolve2();
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
child.stdout?.on("data", checkOutput);
|
|
239
|
-
child.stderr?.on("data", checkOutput);
|
|
240
|
-
child.on("error", (err) => {
|
|
241
|
-
clearTimeout(timeout);
|
|
242
|
-
reject(err);
|
|
243
|
-
});
|
|
244
|
-
child.on("exit", (code) => {
|
|
245
|
-
clearTimeout(timeout);
|
|
246
|
-
reject(new Error(`Mind ${name} exited with code ${code} during startup`));
|
|
247
|
-
});
|
|
248
|
-
});
|
|
249
|
-
} catch (err) {
|
|
250
|
-
this.minds.delete(name);
|
|
251
|
-
try {
|
|
252
|
-
child.kill();
|
|
253
|
-
} catch {
|
|
254
|
-
}
|
|
255
|
-
throw err;
|
|
256
|
-
}
|
|
257
|
-
if (child.pid) {
|
|
258
|
-
try {
|
|
259
|
-
writeFileSync2(pidFile, String(child.pid));
|
|
260
|
-
} catch (err) {
|
|
261
|
-
console.error(`[daemon] failed to write PID file for ${name}:`, err);
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
if (this.restartAttempts.delete(name)) this.saveCrashAttempts();
|
|
265
|
-
this.setupCrashRecovery(name, child);
|
|
266
|
-
if (isVariant) {
|
|
267
|
-
setVariantRunning(baseName, variantName, true);
|
|
268
|
-
} else {
|
|
269
|
-
setMindRunning(name, true);
|
|
270
|
-
}
|
|
271
|
-
console.error(`[daemon] started mind ${name} on port ${port}`);
|
|
272
|
-
await this.deliverPendingContext(name);
|
|
273
|
-
}
|
|
274
|
-
setPendingContext(name, context) {
|
|
275
|
-
this.pendingContext.set(name, context);
|
|
276
|
-
}
|
|
277
|
-
async deliverPendingContext(name) {
|
|
278
|
-
const context = this.pendingContext.get(name);
|
|
279
|
-
if (!context) return;
|
|
280
|
-
const tracked = this.minds.get(name);
|
|
281
|
-
if (!tracked) return;
|
|
282
|
-
this.pendingContext.delete(name);
|
|
283
|
-
const parts = [];
|
|
284
|
-
if (context.type === "merge" || context.type === "merged") {
|
|
285
|
-
parts.push(`[system] Variant "${context.name}" has been merged and you have been restarted.`);
|
|
286
|
-
} else if (context.type === "sprouted") {
|
|
287
|
-
parts.push(
|
|
288
|
-
"[system] You've sprouted. You now have full capabilities \u2014 connectors, schedules, variants, and the complete volute CLI. Check your new skills for details."
|
|
289
|
-
);
|
|
290
|
-
} else {
|
|
291
|
-
parts.push("[system] You have been restarted.");
|
|
292
|
-
}
|
|
293
|
-
if (context.summary) parts.push(`Changes: ${context.summary}`);
|
|
294
|
-
if (context.justification) parts.push(`Why: ${context.justification}`);
|
|
295
|
-
if (context.memory) parts.push(`Context: ${context.memory}`);
|
|
296
|
-
try {
|
|
297
|
-
await fetch(`http://127.0.0.1:${tracked.port}/message`, {
|
|
298
|
-
method: "POST",
|
|
299
|
-
headers: { "Content-Type": "application/json" },
|
|
300
|
-
body: JSON.stringify({
|
|
301
|
-
content: [{ type: "text", text: parts.join("\n") }],
|
|
302
|
-
channel: "system"
|
|
303
|
-
})
|
|
304
|
-
});
|
|
305
|
-
} catch (err) {
|
|
306
|
-
console.error(`[daemon] failed to deliver pending context to ${name}:`, err);
|
|
307
|
-
}
|
|
308
|
-
}
|
|
309
|
-
setupCrashRecovery(name, child) {
|
|
310
|
-
child.on("exit", async (code) => {
|
|
311
|
-
this.minds.delete(name);
|
|
312
|
-
if (this.shuttingDown || this.stopping.has(name)) return;
|
|
313
|
-
console.error(`[daemon] mind ${name} exited with code ${code}`);
|
|
314
|
-
const attempts = this.restartAttempts.get(name) ?? 0;
|
|
315
|
-
if (attempts >= MAX_RESTART_ATTEMPTS) {
|
|
316
|
-
console.error(`[daemon] ${name} crashed ${attempts} times \u2014 giving up on restart`);
|
|
317
|
-
const [base, variant] = name.split("@", 2);
|
|
318
|
-
if (variant) {
|
|
319
|
-
setVariantRunning(base, variant, false);
|
|
320
|
-
} else {
|
|
321
|
-
setMindRunning(name, false);
|
|
322
|
-
}
|
|
323
|
-
return;
|
|
324
|
-
}
|
|
325
|
-
const delay = Math.min(BASE_RESTART_DELAY * 2 ** attempts, MAX_RESTART_DELAY);
|
|
326
|
-
this.restartAttempts.set(name, attempts + 1);
|
|
327
|
-
this.saveCrashAttempts();
|
|
328
|
-
console.error(
|
|
329
|
-
`[daemon] crash recovery for ${name} \u2014 attempt ${attempts + 1}/${MAX_RESTART_ATTEMPTS}, restarting in ${delay}ms`
|
|
330
|
-
);
|
|
331
|
-
setTimeout(() => {
|
|
332
|
-
if (this.shuttingDown) return;
|
|
333
|
-
this.startMind(name).catch((err) => {
|
|
334
|
-
console.error(`[daemon] failed to restart ${name}:`, err);
|
|
335
|
-
});
|
|
336
|
-
}, delay);
|
|
337
|
-
});
|
|
338
|
-
}
|
|
339
|
-
async stopMind(name) {
|
|
340
|
-
const tracked = this.minds.get(name);
|
|
341
|
-
if (!tracked) return;
|
|
342
|
-
this.stopping.add(name);
|
|
343
|
-
const { child } = tracked;
|
|
344
|
-
this.minds.delete(name);
|
|
345
|
-
await new Promise((resolve2) => {
|
|
346
|
-
child.on("exit", () => resolve2());
|
|
347
|
-
try {
|
|
348
|
-
process.kill(-child.pid, "SIGTERM");
|
|
349
|
-
} catch {
|
|
350
|
-
resolve2();
|
|
351
|
-
}
|
|
352
|
-
setTimeout(() => {
|
|
353
|
-
try {
|
|
354
|
-
process.kill(-child.pid, "SIGKILL");
|
|
355
|
-
} catch {
|
|
356
|
-
}
|
|
357
|
-
resolve2();
|
|
358
|
-
}, 5e3);
|
|
359
|
-
});
|
|
360
|
-
this.stopping.delete(name);
|
|
361
|
-
if (this.restartAttempts.delete(name)) this.saveCrashAttempts();
|
|
362
|
-
rmSync2(mindPidPath(name), { force: true });
|
|
363
|
-
if (!this.shuttingDown) {
|
|
364
|
-
const [baseName, variantName] = name.split("@", 2);
|
|
365
|
-
if (variantName) {
|
|
366
|
-
setVariantRunning(baseName, variantName, false);
|
|
367
|
-
} else {
|
|
368
|
-
setMindRunning(name, false);
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
|
-
console.error(`[daemon] stopped mind ${name}`);
|
|
372
|
-
}
|
|
373
|
-
async restartMind(name) {
|
|
374
|
-
await this.stopMind(name);
|
|
375
|
-
await this.startMind(name);
|
|
376
|
-
}
|
|
377
|
-
async stopAll() {
|
|
378
|
-
this.shuttingDown = true;
|
|
379
|
-
const names = [...this.minds.keys()];
|
|
380
|
-
await Promise.all(names.map((name) => this.stopMind(name)));
|
|
381
|
-
}
|
|
382
|
-
isRunning(name) {
|
|
383
|
-
return this.minds.has(name);
|
|
384
|
-
}
|
|
385
|
-
getRunningMinds() {
|
|
386
|
-
return [...this.minds.keys()];
|
|
387
|
-
}
|
|
388
|
-
get crashAttemptsPath() {
|
|
389
|
-
return resolve(voluteHome(), "crash-attempts.json");
|
|
390
|
-
}
|
|
391
|
-
loadCrashAttempts() {
|
|
392
|
-
this.restartAttempts = loadJsonMap(this.crashAttemptsPath);
|
|
393
|
-
}
|
|
394
|
-
saveCrashAttempts() {
|
|
395
|
-
saveJsonMap(this.crashAttemptsPath, this.restartAttempts);
|
|
396
|
-
}
|
|
397
|
-
clearCrashAttempts() {
|
|
398
|
-
clearJsonMap(this.crashAttemptsPath, this.restartAttempts);
|
|
399
|
-
}
|
|
400
|
-
};
|
|
401
|
-
async function killProcessOnPort(port) {
|
|
402
|
-
try {
|
|
403
|
-
const { stdout } = await execFileAsync("lsof", ["-ti", `:${port}`, "-sTCP:LISTEN"]);
|
|
404
|
-
const pids = /* @__PURE__ */ new Set();
|
|
405
|
-
for (const line of stdout.trim().split("\n").filter(Boolean)) {
|
|
406
|
-
const pid = parseInt(line, 10);
|
|
407
|
-
pids.add(pid);
|
|
408
|
-
try {
|
|
409
|
-
const { stdout: psOut } = await execFileAsync("ps", ["-p", String(pid), "-o", "pgid="]);
|
|
410
|
-
const pgid = parseInt(psOut.trim(), 10);
|
|
411
|
-
if (pgid > 1) pids.add(pgid);
|
|
412
|
-
} catch {
|
|
413
|
-
}
|
|
414
|
-
}
|
|
415
|
-
for (const pid of pids) {
|
|
416
|
-
try {
|
|
417
|
-
process.kill(-pid, "SIGTERM");
|
|
418
|
-
} catch {
|
|
419
|
-
}
|
|
420
|
-
try {
|
|
421
|
-
process.kill(pid, "SIGTERM");
|
|
422
|
-
} catch {
|
|
423
|
-
}
|
|
424
|
-
}
|
|
425
|
-
} catch {
|
|
426
|
-
}
|
|
427
|
-
}
|
|
428
|
-
var instance = null;
|
|
429
|
-
function initMindManager() {
|
|
430
|
-
if (instance) throw new Error("MindManager already initialized");
|
|
431
|
-
instance = new MindManager();
|
|
432
|
-
return instance;
|
|
433
|
-
}
|
|
434
|
-
function getMindManager() {
|
|
435
|
-
if (!instance) instance = new MindManager();
|
|
436
|
-
return instance;
|
|
437
|
-
}
|
|
438
|
-
|
|
439
|
-
export {
|
|
440
|
-
RotatingLog,
|
|
441
|
-
loadJsonMap,
|
|
442
|
-
saveJsonMap,
|
|
443
|
-
clearJsonMap,
|
|
444
|
-
MindManager,
|
|
445
|
-
initMindManager,
|
|
446
|
-
getMindManager
|
|
447
|
-
};
|
package/dist/history-LKCJJMUV.js
DELETED
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
resolveMindName
|
|
4
|
-
} from "./chunk-NAOW2CLO.js";
|
|
5
|
-
import {
|
|
6
|
-
parseArgs
|
|
7
|
-
} from "./chunk-D424ZQGI.js";
|
|
8
|
-
import {
|
|
9
|
-
daemonFetch
|
|
10
|
-
} from "./chunk-OJQ47SCA.js";
|
|
11
|
-
import "./chunk-M77QBTEH.js";
|
|
12
|
-
import {
|
|
13
|
-
getClient,
|
|
14
|
-
urlOf
|
|
15
|
-
} from "./chunk-4RQBJWQX.js";
|
|
16
|
-
import "./chunk-K3NQKI34.js";
|
|
17
|
-
|
|
18
|
-
// src/commands/history.ts
|
|
19
|
-
async function run(args) {
|
|
20
|
-
const { flags } = parseArgs(args, {
|
|
21
|
-
mind: { type: "string" },
|
|
22
|
-
channel: { type: "string" },
|
|
23
|
-
limit: { type: "string" }
|
|
24
|
-
});
|
|
25
|
-
const name = resolveMindName(flags);
|
|
26
|
-
const client = getClient();
|
|
27
|
-
const url = client.api.minds[":name"].history.$url({ param: { name } });
|
|
28
|
-
if (flags.channel) url.searchParams.set("channel", flags.channel);
|
|
29
|
-
if (flags.limit) url.searchParams.set("limit", flags.limit);
|
|
30
|
-
const res = await daemonFetch(urlOf(url));
|
|
31
|
-
if (!res.ok) {
|
|
32
|
-
let errorMsg = `Failed to get history: ${res.status}`;
|
|
33
|
-
try {
|
|
34
|
-
const data = await res.json();
|
|
35
|
-
if (data.error) errorMsg = data.error;
|
|
36
|
-
} catch {
|
|
37
|
-
}
|
|
38
|
-
console.error(errorMsg);
|
|
39
|
-
process.exit(1);
|
|
40
|
-
}
|
|
41
|
-
const rows = await res.json();
|
|
42
|
-
for (const row of rows.reverse()) {
|
|
43
|
-
const time = new Date(row.created_at).toLocaleString();
|
|
44
|
-
const sender = row.sender ?? "assistant";
|
|
45
|
-
console.log(`[${time}] [${row.channel}] ${sender}: ${row.content}`);
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
export {
|
|
49
|
-
run
|
|
50
|
-
};
|