volute 0.6.0 → 0.7.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/{agent-X7GJLBLW.js → agent-7JF7MT73.js} +1 -1
- package/dist/{agent-manager-JDVXU3ON.js → agent-manager-IMZ7ZMBF.js} +1 -1
- package/dist/{chunk-G6ZNGLUX.js → chunk-62X577Y7.js} +7 -5
- package/dist/chunk-7ACDT3P2.js +265 -0
- package/dist/{up-CSX3ZUIU.js → chunk-EG45HBSJ.js} +1 -1
- package/dist/{down-FXWAN66A.js → chunk-LLJNZPCU.js} +47 -12
- package/dist/{chunk-AOKAQGO4.js → chunk-NKXULRSW.js} +1 -0
- package/dist/cli.js +10 -6
- package/dist/connectors/discord.js +8 -4
- package/dist/daemon-restart-4HVEKYFY.js +23 -0
- package/dist/daemon.js +143 -347
- package/dist/{delete-2PH2CGDY.js → delete-UOU4AFQN.js} +4 -0
- package/dist/down-AZVH5TCD.js +11 -0
- package/dist/{package-4DP4Y4UO.js → package-T2WAVJOU.js} +1 -1
- package/dist/up-RWZF6MLT.js +12 -0
- package/dist/{update-XSIX3GGP.js → update-F7QWV2LB.js} +1 -1
- package/dist/{update-check-5ZADDHCK.js → update-check-B4J6IEQ4.js} +1 -1
- package/dist/web-assets/assets/index-B1CqjUYD.js +308 -0
- package/dist/web-assets/index.html +1 -1
- package/package.json +1 -1
- package/dist/web-assets/assets/index-D5PzIndO.js +0 -308
|
@@ -18,7 +18,7 @@ async function run(args) {
|
|
|
18
18
|
await import("./restart-O4ETYLJF.js").then((m) => m.run(args.slice(1)));
|
|
19
19
|
break;
|
|
20
20
|
case "delete":
|
|
21
|
-
await import("./delete-
|
|
21
|
+
await import("./delete-UOU4AFQN.js").then((m) => m.run(args.slice(1)));
|
|
22
22
|
break;
|
|
23
23
|
case "list":
|
|
24
24
|
await import("./status-QAJWXKMZ.js").then((m) => m.run(args.slice(1)));
|
|
@@ -285,11 +285,13 @@ var AgentManager = class {
|
|
|
285
285
|
});
|
|
286
286
|
this.stopping.delete(name);
|
|
287
287
|
if (this.restartAttempts.delete(name)) this.saveCrashAttempts();
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
288
|
+
if (!this.shuttingDown) {
|
|
289
|
+
const [baseName, variantName] = name.split("@", 2);
|
|
290
|
+
if (variantName) {
|
|
291
|
+
setVariantRunning(baseName, variantName, false);
|
|
292
|
+
} else {
|
|
293
|
+
setAgentRunning(name, false);
|
|
294
|
+
}
|
|
293
295
|
}
|
|
294
296
|
console.error(`[daemon] stopped agent ${name}`);
|
|
295
297
|
}
|
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
voluteHome
|
|
4
|
+
} from "./chunk-UWHWAPGO.js";
|
|
5
|
+
import {
|
|
6
|
+
__export
|
|
7
|
+
} from "./chunk-K3NQKI34.js";
|
|
8
|
+
|
|
9
|
+
// src/lib/auth.ts
|
|
10
|
+
import { compareSync, hashSync } from "bcryptjs";
|
|
11
|
+
import { and, count, eq } from "drizzle-orm";
|
|
12
|
+
|
|
13
|
+
// src/lib/db.ts
|
|
14
|
+
import { chmodSync, existsSync } from "fs";
|
|
15
|
+
import { dirname, resolve } from "path";
|
|
16
|
+
import { fileURLToPath } from "url";
|
|
17
|
+
import { drizzle } from "drizzle-orm/libsql";
|
|
18
|
+
import { migrate } from "drizzle-orm/libsql/migrator";
|
|
19
|
+
|
|
20
|
+
// src/lib/schema.ts
|
|
21
|
+
var schema_exports = {};
|
|
22
|
+
__export(schema_exports, {
|
|
23
|
+
agentMessages: () => agentMessages,
|
|
24
|
+
conversationParticipants: () => conversationParticipants,
|
|
25
|
+
conversations: () => conversations,
|
|
26
|
+
messages: () => messages,
|
|
27
|
+
sessions: () => sessions,
|
|
28
|
+
users: () => users
|
|
29
|
+
});
|
|
30
|
+
import { sql } from "drizzle-orm";
|
|
31
|
+
import { index, integer, sqliteTable, text, uniqueIndex } from "drizzle-orm/sqlite-core";
|
|
32
|
+
var users = sqliteTable("users", {
|
|
33
|
+
id: integer("id").primaryKey({ autoIncrement: true }),
|
|
34
|
+
username: text("username").unique().notNull(),
|
|
35
|
+
password_hash: text("password_hash").notNull(),
|
|
36
|
+
role: text("role").notNull().default("pending"),
|
|
37
|
+
user_type: text("user_type").notNull().default("human"),
|
|
38
|
+
created_at: text("created_at").notNull().default(sql`(datetime('now'))`)
|
|
39
|
+
});
|
|
40
|
+
var conversations = sqliteTable(
|
|
41
|
+
"conversations",
|
|
42
|
+
{
|
|
43
|
+
id: text("id").primaryKey(),
|
|
44
|
+
agent_name: text("agent_name").notNull(),
|
|
45
|
+
channel: text("channel").notNull(),
|
|
46
|
+
user_id: integer("user_id").references(() => users.id),
|
|
47
|
+
title: text("title"),
|
|
48
|
+
created_at: text("created_at").notNull().default(sql`(datetime('now'))`),
|
|
49
|
+
updated_at: text("updated_at").notNull().default(sql`(datetime('now'))`)
|
|
50
|
+
},
|
|
51
|
+
(table) => [
|
|
52
|
+
index("idx_conversations_agent_name").on(table.agent_name),
|
|
53
|
+
index("idx_conversations_user_id").on(table.user_id),
|
|
54
|
+
index("idx_conversations_updated_at").on(table.updated_at)
|
|
55
|
+
]
|
|
56
|
+
);
|
|
57
|
+
var agentMessages = sqliteTable(
|
|
58
|
+
"agent_messages",
|
|
59
|
+
{
|
|
60
|
+
id: integer("id").primaryKey({ autoIncrement: true }),
|
|
61
|
+
agent: text("agent").notNull(),
|
|
62
|
+
channel: text("channel").notNull(),
|
|
63
|
+
role: text("role").notNull(),
|
|
64
|
+
sender: text("sender"),
|
|
65
|
+
content: text("content").notNull(),
|
|
66
|
+
created_at: text("created_at").notNull().default(sql`(datetime('now'))`)
|
|
67
|
+
},
|
|
68
|
+
(table) => [
|
|
69
|
+
index("idx_agent_messages_agent").on(table.agent),
|
|
70
|
+
index("idx_agent_messages_channel").on(table.agent, table.channel)
|
|
71
|
+
]
|
|
72
|
+
);
|
|
73
|
+
var conversationParticipants = sqliteTable(
|
|
74
|
+
"conversation_participants",
|
|
75
|
+
{
|
|
76
|
+
conversation_id: text("conversation_id").notNull().references(() => conversations.id, { onDelete: "cascade" }),
|
|
77
|
+
user_id: integer("user_id").notNull().references(() => users.id, { onDelete: "cascade" }),
|
|
78
|
+
role: text("role").notNull().default("member"),
|
|
79
|
+
joined_at: text("joined_at").notNull().default(sql`(datetime('now'))`)
|
|
80
|
+
},
|
|
81
|
+
(table) => [
|
|
82
|
+
uniqueIndex("idx_cp_unique").on(table.conversation_id, table.user_id),
|
|
83
|
+
index("idx_cp_user_id").on(table.user_id)
|
|
84
|
+
]
|
|
85
|
+
);
|
|
86
|
+
var sessions = sqliteTable("sessions", {
|
|
87
|
+
id: text("id").primaryKey(),
|
|
88
|
+
userId: integer("user_id").references(() => users.id, { onDelete: "cascade" }).notNull(),
|
|
89
|
+
createdAt: integer("created_at").notNull()
|
|
90
|
+
});
|
|
91
|
+
var messages = sqliteTable(
|
|
92
|
+
"messages",
|
|
93
|
+
{
|
|
94
|
+
id: integer("id").primaryKey({ autoIncrement: true }),
|
|
95
|
+
conversation_id: text("conversation_id").notNull().references(() => conversations.id, { onDelete: "cascade" }),
|
|
96
|
+
role: text("role").notNull(),
|
|
97
|
+
sender_name: text("sender_name"),
|
|
98
|
+
content: text("content").notNull(),
|
|
99
|
+
created_at: text("created_at").notNull().default(sql`(datetime('now'))`)
|
|
100
|
+
},
|
|
101
|
+
(table) => [index("idx_messages_conversation_id").on(table.conversation_id)]
|
|
102
|
+
);
|
|
103
|
+
|
|
104
|
+
// src/lib/db.ts
|
|
105
|
+
var __dirname = dirname(fileURLToPath(import.meta.url));
|
|
106
|
+
var migrationsFolder = existsSync(resolve(__dirname, "../drizzle")) ? resolve(__dirname, "../drizzle") : resolve(__dirname, "../../drizzle");
|
|
107
|
+
var db = null;
|
|
108
|
+
async function getDb() {
|
|
109
|
+
if (db) return db;
|
|
110
|
+
const dbPath = process.env.VOLUTE_DB_PATH || resolve(voluteHome(), "volute.db");
|
|
111
|
+
db = drizzle({ connection: { url: `file:${dbPath}` }, schema: schema_exports });
|
|
112
|
+
await migrate(db, { migrationsFolder });
|
|
113
|
+
try {
|
|
114
|
+
chmodSync(dbPath, 384);
|
|
115
|
+
} catch (err) {
|
|
116
|
+
console.error(
|
|
117
|
+
`[volute] WARNING: Failed to restrict database file permissions on ${dbPath}:`,
|
|
118
|
+
err
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
return db;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// src/lib/auth.ts
|
|
125
|
+
async function createUser(username, password) {
|
|
126
|
+
const db2 = await getDb();
|
|
127
|
+
const hash = hashSync(password, 10);
|
|
128
|
+
const [{ value }] = await db2.select({ value: count() }).from(users).where(eq(users.user_type, "human"));
|
|
129
|
+
const role = value === 0 ? "admin" : "pending";
|
|
130
|
+
const [result] = await db2.insert(users).values({ username, password_hash: hash, role }).returning({
|
|
131
|
+
id: users.id,
|
|
132
|
+
username: users.username,
|
|
133
|
+
role: users.role,
|
|
134
|
+
user_type: users.user_type,
|
|
135
|
+
created_at: users.created_at
|
|
136
|
+
});
|
|
137
|
+
return result;
|
|
138
|
+
}
|
|
139
|
+
async function verifyUser(username, password) {
|
|
140
|
+
const db2 = await getDb();
|
|
141
|
+
const row = await db2.select().from(users).where(eq(users.username, username)).get();
|
|
142
|
+
if (!row) return null;
|
|
143
|
+
if (row.user_type === "agent") return null;
|
|
144
|
+
if (!compareSync(password, row.password_hash)) return null;
|
|
145
|
+
const { password_hash: _, ...user } = row;
|
|
146
|
+
return user;
|
|
147
|
+
}
|
|
148
|
+
async function getUser(id) {
|
|
149
|
+
const db2 = await getDb();
|
|
150
|
+
const row = await db2.select({
|
|
151
|
+
id: users.id,
|
|
152
|
+
username: users.username,
|
|
153
|
+
role: users.role,
|
|
154
|
+
user_type: users.user_type,
|
|
155
|
+
created_at: users.created_at
|
|
156
|
+
}).from(users).where(eq(users.id, id)).get();
|
|
157
|
+
return row ?? null;
|
|
158
|
+
}
|
|
159
|
+
async function getUserByUsername(username) {
|
|
160
|
+
const db2 = await getDb();
|
|
161
|
+
const row = await db2.select({
|
|
162
|
+
id: users.id,
|
|
163
|
+
username: users.username,
|
|
164
|
+
role: users.role,
|
|
165
|
+
user_type: users.user_type,
|
|
166
|
+
created_at: users.created_at
|
|
167
|
+
}).from(users).where(eq(users.username, username)).get();
|
|
168
|
+
return row ?? null;
|
|
169
|
+
}
|
|
170
|
+
async function listUsers() {
|
|
171
|
+
const db2 = await getDb();
|
|
172
|
+
return db2.select({
|
|
173
|
+
id: users.id,
|
|
174
|
+
username: users.username,
|
|
175
|
+
role: users.role,
|
|
176
|
+
user_type: users.user_type,
|
|
177
|
+
created_at: users.created_at
|
|
178
|
+
}).from(users).orderBy(users.created_at).all();
|
|
179
|
+
}
|
|
180
|
+
async function listPendingUsers() {
|
|
181
|
+
const db2 = await getDb();
|
|
182
|
+
return db2.select({
|
|
183
|
+
id: users.id,
|
|
184
|
+
username: users.username,
|
|
185
|
+
role: users.role,
|
|
186
|
+
user_type: users.user_type,
|
|
187
|
+
created_at: users.created_at
|
|
188
|
+
}).from(users).where(eq(users.role, "pending")).orderBy(users.created_at).all();
|
|
189
|
+
}
|
|
190
|
+
async function listUsersByType(userType) {
|
|
191
|
+
const db2 = await getDb();
|
|
192
|
+
return db2.select({
|
|
193
|
+
id: users.id,
|
|
194
|
+
username: users.username,
|
|
195
|
+
role: users.role,
|
|
196
|
+
user_type: users.user_type,
|
|
197
|
+
created_at: users.created_at
|
|
198
|
+
}).from(users).where(eq(users.user_type, userType)).orderBy(users.created_at).all();
|
|
199
|
+
}
|
|
200
|
+
async function getOrCreateAgentUser(agentName) {
|
|
201
|
+
const db2 = await getDb();
|
|
202
|
+
const existing = await db2.select({
|
|
203
|
+
id: users.id,
|
|
204
|
+
username: users.username,
|
|
205
|
+
role: users.role,
|
|
206
|
+
user_type: users.user_type,
|
|
207
|
+
created_at: users.created_at
|
|
208
|
+
}).from(users).where(and(eq(users.username, agentName), eq(users.user_type, "agent"))).get();
|
|
209
|
+
if (existing) return existing;
|
|
210
|
+
try {
|
|
211
|
+
const [result] = await db2.insert(users).values({
|
|
212
|
+
username: agentName,
|
|
213
|
+
password_hash: "!agent",
|
|
214
|
+
role: "agent",
|
|
215
|
+
user_type: "agent"
|
|
216
|
+
}).returning({
|
|
217
|
+
id: users.id,
|
|
218
|
+
username: users.username,
|
|
219
|
+
role: users.role,
|
|
220
|
+
user_type: users.user_type,
|
|
221
|
+
created_at: users.created_at
|
|
222
|
+
});
|
|
223
|
+
return result;
|
|
224
|
+
} catch (err) {
|
|
225
|
+
if (err instanceof Error && err.message.includes("UNIQUE constraint")) {
|
|
226
|
+
const retried = await db2.select({
|
|
227
|
+
id: users.id,
|
|
228
|
+
username: users.username,
|
|
229
|
+
role: users.role,
|
|
230
|
+
user_type: users.user_type,
|
|
231
|
+
created_at: users.created_at
|
|
232
|
+
}).from(users).where(and(eq(users.username, agentName), eq(users.user_type, "agent"))).get();
|
|
233
|
+
if (retried) return retried;
|
|
234
|
+
}
|
|
235
|
+
throw err;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
async function deleteAgentUser(agentName) {
|
|
239
|
+
const db2 = await getDb();
|
|
240
|
+
await db2.delete(users).where(and(eq(users.username, agentName), eq(users.user_type, "agent")));
|
|
241
|
+
}
|
|
242
|
+
async function approveUser(id) {
|
|
243
|
+
const db2 = await getDb();
|
|
244
|
+
await db2.update(users).set({ role: "user" }).where(and(eq(users.id, id), eq(users.role, "pending")));
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
export {
|
|
248
|
+
users,
|
|
249
|
+
conversations,
|
|
250
|
+
agentMessages,
|
|
251
|
+
conversationParticipants,
|
|
252
|
+
sessions,
|
|
253
|
+
messages,
|
|
254
|
+
getDb,
|
|
255
|
+
createUser,
|
|
256
|
+
verifyUser,
|
|
257
|
+
getUser,
|
|
258
|
+
getUserByUsername,
|
|
259
|
+
listUsers,
|
|
260
|
+
listPendingUsers,
|
|
261
|
+
listUsersByType,
|
|
262
|
+
getOrCreateAgentUser,
|
|
263
|
+
deleteAgentUser,
|
|
264
|
+
approveUser
|
|
265
|
+
};
|
|
@@ -5,7 +5,6 @@ import {
|
|
|
5
5
|
import {
|
|
6
6
|
voluteHome
|
|
7
7
|
} from "./chunk-UWHWAPGO.js";
|
|
8
|
-
import "./chunk-K3NQKI34.js";
|
|
9
8
|
|
|
10
9
|
// src/commands/up.ts
|
|
11
10
|
import { spawn } from "child_process";
|
|
@@ -103,6 +102,7 @@ async function run(args) {
|
|
|
103
102
|
console.error(`Check logs: ${logFile}`);
|
|
104
103
|
process.exit(1);
|
|
105
104
|
}
|
|
105
|
+
|
|
106
106
|
export {
|
|
107
107
|
readGlobalConfig,
|
|
108
108
|
run
|
|
@@ -2,12 +2,11 @@
|
|
|
2
2
|
import {
|
|
3
3
|
voluteHome
|
|
4
4
|
} from "./chunk-UWHWAPGO.js";
|
|
5
|
-
import "./chunk-K3NQKI34.js";
|
|
6
5
|
|
|
7
6
|
// src/commands/down.ts
|
|
8
7
|
import { existsSync, readFileSync, unlinkSync } from "fs";
|
|
9
8
|
import { resolve } from "path";
|
|
10
|
-
async function
|
|
9
|
+
async function stopDaemon() {
|
|
11
10
|
const home = voluteHome();
|
|
12
11
|
const pidPath = resolve(home, "daemon.pid");
|
|
13
12
|
if (!existsSync(pidPath)) {
|
|
@@ -28,16 +27,21 @@ async function run(_args) {
|
|
|
28
27
|
url.port = String(port);
|
|
29
28
|
const res = await fetch(`${url.origin}/api/health`);
|
|
30
29
|
if (res.ok) {
|
|
31
|
-
|
|
32
|
-
console.error(`Kill the process manually: lsof -ti :${port} | xargs kill`);
|
|
33
|
-
process.exit(1);
|
|
30
|
+
return { stopped: false, reason: "orphan", port };
|
|
34
31
|
}
|
|
35
32
|
} catch {
|
|
36
33
|
}
|
|
37
|
-
|
|
38
|
-
process.exit(1);
|
|
34
|
+
return { stopped: false, reason: "not-running" };
|
|
39
35
|
}
|
|
40
36
|
const pid = parseInt(readFileSync(pidPath, "utf-8").trim(), 10);
|
|
37
|
+
if (!Number.isInteger(pid) || pid <= 0) {
|
|
38
|
+
console.error(`Stale or corrupt PID file (${pidPath}), removing.`);
|
|
39
|
+
try {
|
|
40
|
+
unlinkSync(pidPath);
|
|
41
|
+
} catch {
|
|
42
|
+
}
|
|
43
|
+
return { stopped: false, reason: "not-running" };
|
|
44
|
+
}
|
|
41
45
|
try {
|
|
42
46
|
process.kill(pid, 0);
|
|
43
47
|
} catch {
|
|
@@ -46,21 +50,28 @@ async function run(_args) {
|
|
|
46
50
|
} catch {
|
|
47
51
|
}
|
|
48
52
|
console.log("Daemon was not running (cleaned up stale PID file).");
|
|
49
|
-
return;
|
|
53
|
+
return { stopped: false, reason: "not-running" };
|
|
50
54
|
}
|
|
51
55
|
try {
|
|
52
56
|
process.kill(-pid, "SIGTERM");
|
|
53
57
|
console.log(`Sent SIGTERM to daemon group (pid ${pid})`);
|
|
54
58
|
} catch {
|
|
55
|
-
|
|
56
|
-
|
|
59
|
+
try {
|
|
60
|
+
process.kill(pid, "SIGTERM");
|
|
61
|
+
console.log(`Sent SIGTERM to daemon (pid ${pid})`);
|
|
62
|
+
} catch (e) {
|
|
63
|
+
console.error(
|
|
64
|
+
`Failed to send SIGTERM to daemon (pid ${pid}): ${e instanceof Error ? e.message : e}`
|
|
65
|
+
);
|
|
66
|
+
return { stopped: false, reason: "kill-failed", port: pid };
|
|
67
|
+
}
|
|
57
68
|
}
|
|
58
69
|
const maxWait = 1e4;
|
|
59
70
|
const start = Date.now();
|
|
60
71
|
while (Date.now() - start < maxWait) {
|
|
61
72
|
if (!existsSync(pidPath)) {
|
|
62
73
|
console.log("Daemon stopped.");
|
|
63
|
-
return;
|
|
74
|
+
return { stopped: true, clean: true };
|
|
64
75
|
}
|
|
65
76
|
await new Promise((r) => setTimeout(r, 200));
|
|
66
77
|
}
|
|
@@ -69,11 +80,35 @@ async function run(_args) {
|
|
|
69
80
|
} catch {
|
|
70
81
|
try {
|
|
71
82
|
process.kill(pid, "SIGKILL");
|
|
72
|
-
} catch {
|
|
83
|
+
} catch (e) {
|
|
84
|
+
console.error(
|
|
85
|
+
`Failed to force-kill daemon (pid ${pid}): ${e instanceof Error ? e.message : e}`
|
|
86
|
+
);
|
|
87
|
+
console.error(`The daemon may still be running. Kill it manually: kill -9 ${pid}`);
|
|
88
|
+
return { stopped: false, reason: "kill-failed" };
|
|
73
89
|
}
|
|
74
90
|
}
|
|
91
|
+
try {
|
|
92
|
+
unlinkSync(pidPath);
|
|
93
|
+
} catch {
|
|
94
|
+
}
|
|
95
|
+
await new Promise((r) => setTimeout(r, 500));
|
|
75
96
|
console.error("Daemon did not exit cleanly, sent SIGKILL.");
|
|
97
|
+
return { stopped: true, clean: false };
|
|
76
98
|
}
|
|
99
|
+
async function run(_args) {
|
|
100
|
+
const result = await stopDaemon();
|
|
101
|
+
if (result.stopped) return;
|
|
102
|
+
if (result.reason === "orphan") {
|
|
103
|
+
console.error(`Daemon appears to be running on port ${result.port} but PID file is missing.`);
|
|
104
|
+
console.error(`Kill the process manually: lsof -ti :${result.port} | xargs kill`);
|
|
105
|
+
} else if (result.reason === "not-running") {
|
|
106
|
+
console.error("Daemon is not running (no PID file found).");
|
|
107
|
+
}
|
|
108
|
+
process.exit(1);
|
|
109
|
+
}
|
|
110
|
+
|
|
77
111
|
export {
|
|
112
|
+
stopDaemon,
|
|
78
113
|
run
|
|
79
114
|
};
|
|
@@ -28,6 +28,7 @@ function writeCache(latest) {
|
|
|
28
28
|
function getCurrentVersion() {
|
|
29
29
|
const thisDir = new URL(".", import.meta.url).pathname;
|
|
30
30
|
const candidates = [
|
|
31
|
+
resolve(thisDir, "../package.json"),
|
|
31
32
|
resolve(thisDir, "../../package.json"),
|
|
32
33
|
resolve(thisDir, "../../../package.json")
|
|
33
34
|
];
|
package/dist/cli.js
CHANGED
|
@@ -9,13 +9,13 @@ if (!process.env.VOLUTE_HOME) {
|
|
|
9
9
|
var command = process.argv[2];
|
|
10
10
|
var args = process.argv.slice(3);
|
|
11
11
|
if (command === "--version" || command === "-v") {
|
|
12
|
-
const { default: pkg } = await import("./package-
|
|
12
|
+
const { default: pkg } = await import("./package-T2WAVJOU.js");
|
|
13
13
|
console.log(pkg.version);
|
|
14
14
|
process.exit(0);
|
|
15
15
|
}
|
|
16
16
|
switch (command) {
|
|
17
17
|
case "agent":
|
|
18
|
-
await import("./agent-
|
|
18
|
+
await import("./agent-7JF7MT73.js").then((m) => m.run(args));
|
|
19
19
|
break;
|
|
20
20
|
case "message":
|
|
21
21
|
await import("./message-SCOQDR3P.js").then((m) => m.run(args));
|
|
@@ -36,10 +36,13 @@ switch (command) {
|
|
|
36
36
|
await import("./env-7GLUJCWS.js").then((m) => m.run(args));
|
|
37
37
|
break;
|
|
38
38
|
case "up":
|
|
39
|
-
await import("./up-
|
|
39
|
+
await import("./up-RWZF6MLT.js").then((m) => m.run(args));
|
|
40
40
|
break;
|
|
41
41
|
case "down":
|
|
42
|
-
await import("./down-
|
|
42
|
+
await import("./down-AZVH5TCD.js").then((m) => m.run(args));
|
|
43
|
+
break;
|
|
44
|
+
case "restart":
|
|
45
|
+
await import("./daemon-restart-4HVEKYFY.js").then((m) => m.run(args));
|
|
43
46
|
break;
|
|
44
47
|
case "setup":
|
|
45
48
|
await import("./setup-F4TCWVSP.js").then((m) => m.run(args));
|
|
@@ -48,7 +51,7 @@ switch (command) {
|
|
|
48
51
|
await import("./service-HZNIDNJF.js").then((m) => m.run(args));
|
|
49
52
|
break;
|
|
50
53
|
case "update":
|
|
51
|
-
await import("./update-
|
|
54
|
+
await import("./update-F7QWV2LB.js").then((m) => m.run(args));
|
|
52
55
|
break;
|
|
53
56
|
case "--help":
|
|
54
57
|
case "-h":
|
|
@@ -92,6 +95,7 @@ Commands:
|
|
|
92
95
|
|
|
93
96
|
volute up [--port N] Start the daemon (default: 4200)
|
|
94
97
|
volute down Stop the daemon
|
|
98
|
+
volute restart [--port N] Restart the daemon
|
|
95
99
|
|
|
96
100
|
volute service install [--port N] Install as system service (auto-start)
|
|
97
101
|
volute service uninstall Remove system service
|
|
@@ -114,7 +118,7 @@ Run 'volute --help' for usage.`);
|
|
|
114
118
|
process.exit(1);
|
|
115
119
|
}
|
|
116
120
|
if (command !== "update") {
|
|
117
|
-
import("./update-check-
|
|
121
|
+
import("./update-check-B4J6IEQ4.js").then((m) => m.checkForUpdate()).then((result) => {
|
|
118
122
|
if (result.updateAvailable) {
|
|
119
123
|
console.error(`
|
|
120
124
|
Update available: ${result.current} \u2192 ${result.latest}`);
|
|
@@ -122,6 +122,7 @@ client.on(Events.MessageCreate, async (message) => {
|
|
|
122
122
|
...message.guild?.name ? { serverName: message.guild.name } : {},
|
|
123
123
|
...participantCount ? { participantCount } : {}
|
|
124
124
|
};
|
|
125
|
+
reportTyping(env, channelKey, senderName, false);
|
|
125
126
|
if (isFollowedChannel && !isMentioned) {
|
|
126
127
|
await fireAndForget(env, payload);
|
|
127
128
|
return;
|
|
@@ -130,7 +131,7 @@ client.on(Events.MessageCreate, async (message) => {
|
|
|
130
131
|
});
|
|
131
132
|
client.on(Events.TypingStart, (typing) => {
|
|
132
133
|
if (typing.user.bot) return;
|
|
133
|
-
const sender = typing.
|
|
134
|
+
const sender = typing.user.displayName || typing.user.username || typing.user.id || "unknown";
|
|
134
135
|
const typingChannel = typing.guild ? `discord:${slugify(typing.guild.name)}/${slugify("name" in typing.channel ? String(typing.channel.name) : typing.channel.id)}` : `discord:@${slugify(typing.user.username ?? typing.user.id)}`;
|
|
135
136
|
reportTyping(env, typingChannel, sender, true);
|
|
136
137
|
});
|
|
@@ -138,10 +139,12 @@ async function handleDiscordMessage(message, payload) {
|
|
|
138
139
|
const channel = message.channel;
|
|
139
140
|
if (!("sendTyping" in channel)) return;
|
|
140
141
|
const typingInterval = setInterval(() => {
|
|
141
|
-
channel.sendTyping().catch(() => {
|
|
142
|
+
channel.sendTyping().catch((err) => {
|
|
143
|
+
console.warn(`[discord] sendTyping failed: ${err}`);
|
|
142
144
|
});
|
|
143
145
|
}, TYPING_INTERVAL_MS);
|
|
144
|
-
channel.sendTyping().catch(() => {
|
|
146
|
+
channel.sendTyping().catch((err) => {
|
|
147
|
+
console.warn(`[discord] sendTyping failed: ${err}`);
|
|
145
148
|
});
|
|
146
149
|
let replied = false;
|
|
147
150
|
try {
|
|
@@ -182,7 +185,8 @@ async function handleDiscordMessage(message, payload) {
|
|
|
182
185
|
}
|
|
183
186
|
},
|
|
184
187
|
onError: async (msg) => {
|
|
185
|
-
await message.reply(msg).catch(() => {
|
|
188
|
+
await message.reply(msg).catch((err) => {
|
|
189
|
+
console.error(`[discord] failed to send error reply: ${err}`);
|
|
186
190
|
});
|
|
187
191
|
}
|
|
188
192
|
});
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
run
|
|
4
|
+
} from "./chunk-EG45HBSJ.js";
|
|
5
|
+
import {
|
|
6
|
+
stopDaemon
|
|
7
|
+
} from "./chunk-LLJNZPCU.js";
|
|
8
|
+
import "./chunk-D424ZQGI.js";
|
|
9
|
+
import "./chunk-UWHWAPGO.js";
|
|
10
|
+
import "./chunk-K3NQKI34.js";
|
|
11
|
+
|
|
12
|
+
// src/commands/daemon-restart.ts
|
|
13
|
+
async function run2(args) {
|
|
14
|
+
const result = await stopDaemon();
|
|
15
|
+
if (!result.stopped && result.reason === "kill-failed") {
|
|
16
|
+
console.error("Cannot restart: failed to stop the running daemon.");
|
|
17
|
+
process.exit(1);
|
|
18
|
+
}
|
|
19
|
+
await run(args);
|
|
20
|
+
}
|
|
21
|
+
export {
|
|
22
|
+
run2 as run
|
|
23
|
+
};
|