volute 0.8.3 → 0.10.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-YORVRB6I.js → agent-ECRX44DB.js} +10 -10
- package/dist/{agent-manager-CMMH5KQQ.js → agent-manager-MRHHKAB6.js} +2 -2
- package/dist/api-client-YPKOZP2O.js +10 -0
- package/dist/{channel-RDGHBFSI.js → channel-2WHBRDTD.js} +66 -81
- package/dist/chunk-4RQBJWQX.js +17 -0
- package/dist/{chunk-YNNK4QN2.js → chunk-FYQGANL6.js} +40 -2
- package/dist/chunk-R3VB7NF5.js +205 -0
- package/dist/{chunk-23L3MKEV.js → chunk-STOEJOJO.js} +18 -4
- package/dist/cli.js +14 -14
- package/dist/{connector-ZP6MEFF4.js → connector-L2HBLZBW.js} +37 -20
- package/dist/create-VBZZNJOG.js +38 -0
- package/dist/{daemon-client-54J3EIZD.js → daemon-client-P44NU3KU.js} +1 -1
- package/dist/daemon-restart-QCLR6ZZV.js +61 -0
- package/dist/daemon.js +1732 -214
- package/dist/delete-BOTVU4YO.js +35 -0
- package/dist/{down-4DGRZRJU.js → down-4LIQG3CE.js} +3 -1
- package/dist/{env-KMNYGVZ2.js → env-CGORIKVF.js} +86 -37
- package/dist/{history-PXJVYLVY.js → history-NI5QP27M.js} +11 -8
- package/dist/import-2BZUWT23.js +21 -0
- package/dist/logs-APWVWGNX.js +77 -0
- package/dist/{package-2S7APQBC.js → package-ERGXEDAF.js} +1 -1
- package/dist/{restart-KVH3TK5N.js → restart-CCYM3MEC.js} +10 -4
- package/dist/{schedule-HCUCBNQI.js → schedule-E4MFGYSA.js} +24 -8
- package/dist/{send-BNC2S5BY.js → send-X6OQGSD6.js} +36 -28
- package/dist/{start-QU73YTJW.js → start-6YRS6FF6.js} +7 -2
- package/dist/{status-Q6ZQJXNI.js → status-SIMKH3ZE.js} +8 -3
- package/dist/{stop-N7U5N6A7.js → stop-UQSNF4CG.js} +7 -2
- package/dist/{up-RZJMSVQS.js → up-MNNPCMFF.js} +1 -1
- package/dist/upgrade-RSE4CZNE.js +55 -0
- package/dist/variant-7IZF6OWO.js +215 -0
- package/package.json +1 -1
- package/dist/chunk-ECPQXRLB.js +0 -264
- package/dist/chunk-NETNFBA5.js +0 -28
- package/dist/chunk-XUA3JUFK.js +0 -121
- package/dist/create-HGJHLABX.js +0 -96
- package/dist/daemon-restart-IMNCBWFV.js +0 -28
- package/dist/delete-45TGQC4N.js +0 -67
- package/dist/import-CNEDF3TD.js +0 -532
- package/dist/logs-TZB3MTLZ.js +0 -37
- package/dist/upgrade-CZF6PN7Y.js +0 -224
- package/dist/variant-RKXPN5DH.js +0 -476
- package/dist/{chunk-6RDCTVQK.js → chunk-4NAGJV3I.js} +0 -0
- package/dist/{chunk-W6TMWYU3.js → chunk-WV4W7BAT.js} +3 -3
- package/dist/{service-56CY4S6Z.js → service-OW35VZ5G.js} +3 -3
- package/dist/{setup-7SPMWF2O.js → setup-ABMZK6LS.js} +3 -3
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
resolveAgentName
|
|
4
|
+
} from "./chunk-AZEL2IEK.js";
|
|
5
|
+
import {
|
|
6
|
+
parseArgs
|
|
7
|
+
} from "./chunk-D424ZQGI.js";
|
|
8
|
+
import "./chunk-K3NQKI34.js";
|
|
9
|
+
|
|
10
|
+
// src/commands/upgrade.ts
|
|
11
|
+
async function run(args) {
|
|
12
|
+
const { positional, flags } = parseArgs(args, {
|
|
13
|
+
template: { type: "string" },
|
|
14
|
+
continue: { type: "boolean" }
|
|
15
|
+
});
|
|
16
|
+
const agentName = resolveAgentName({ agent: positional[0] });
|
|
17
|
+
const { daemonFetch } = await import("./daemon-client-P44NU3KU.js");
|
|
18
|
+
const { getClient, urlOf } = await import("./api-client-YPKOZP2O.js");
|
|
19
|
+
const client = getClient();
|
|
20
|
+
const res = await daemonFetch(
|
|
21
|
+
urlOf(client.api.agents[":name"].upgrade.$url({ param: { name: agentName } })),
|
|
22
|
+
{
|
|
23
|
+
method: "POST",
|
|
24
|
+
headers: { "Content-Type": "application/json" },
|
|
25
|
+
body: JSON.stringify({
|
|
26
|
+
template: flags.template,
|
|
27
|
+
continue: flags.continue
|
|
28
|
+
})
|
|
29
|
+
}
|
|
30
|
+
);
|
|
31
|
+
const data = await res.json();
|
|
32
|
+
if (!res.ok && !data.conflicts) {
|
|
33
|
+
console.error(data.error ?? "Failed to upgrade agent");
|
|
34
|
+
process.exit(1);
|
|
35
|
+
}
|
|
36
|
+
if (data.conflicts) {
|
|
37
|
+
console.log("\nMerge conflicts detected. Resolve them in:");
|
|
38
|
+
console.log(` ${data.worktreeDir}`);
|
|
39
|
+
console.log(`
|
|
40
|
+
Then run:`);
|
|
41
|
+
console.log(` volute agent upgrade ${agentName} --continue`);
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
console.log(`
|
|
45
|
+
Upgrade variant running on port ${data.port}`);
|
|
46
|
+
console.log(`
|
|
47
|
+
Next steps:`);
|
|
48
|
+
console.log(
|
|
49
|
+
` volute send @${agentName}@${data.variant} "hello" # chat with upgraded variant`
|
|
50
|
+
);
|
|
51
|
+
console.log(` volute variant merge ${data.variant} # merge back when satisfied`);
|
|
52
|
+
}
|
|
53
|
+
export {
|
|
54
|
+
run
|
|
55
|
+
};
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
resolveAgentName
|
|
4
|
+
} from "./chunk-AZEL2IEK.js";
|
|
5
|
+
import {
|
|
6
|
+
parseArgs
|
|
7
|
+
} from "./chunk-D424ZQGI.js";
|
|
8
|
+
import {
|
|
9
|
+
checkHealth,
|
|
10
|
+
readVariants,
|
|
11
|
+
resolveAgent,
|
|
12
|
+
writeVariants
|
|
13
|
+
} from "./chunk-DP2DX4WV.js";
|
|
14
|
+
import "./chunk-K3NQKI34.js";
|
|
15
|
+
|
|
16
|
+
// src/commands/variant.ts
|
|
17
|
+
async function run(args) {
|
|
18
|
+
const subcommand = args[0];
|
|
19
|
+
switch (subcommand) {
|
|
20
|
+
case "create":
|
|
21
|
+
await createVariant(args.slice(1));
|
|
22
|
+
break;
|
|
23
|
+
case "list":
|
|
24
|
+
await listVariants(args.slice(1));
|
|
25
|
+
break;
|
|
26
|
+
case "merge":
|
|
27
|
+
await mergeVariant(args.slice(1));
|
|
28
|
+
break;
|
|
29
|
+
case "delete":
|
|
30
|
+
await deleteVariant(args.slice(1));
|
|
31
|
+
break;
|
|
32
|
+
case "--help":
|
|
33
|
+
case "-h":
|
|
34
|
+
case void 0:
|
|
35
|
+
printUsage();
|
|
36
|
+
break;
|
|
37
|
+
default:
|
|
38
|
+
printUsage();
|
|
39
|
+
process.exit(1);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
function printUsage() {
|
|
43
|
+
console.log(`Usage:
|
|
44
|
+
volute variant create <variant> [--agent <name>] [--soul "..."] [--port N] [--no-start] [--json]
|
|
45
|
+
volute variant list [--agent <name>] [--json]
|
|
46
|
+
volute variant merge <variant> [--agent <name>] [--summary "..." --memory "..."] [--skip-verify]
|
|
47
|
+
volute variant delete <variant> [--agent <name>]`);
|
|
48
|
+
}
|
|
49
|
+
async function createVariant(args) {
|
|
50
|
+
const { positional, flags } = parseArgs(args, {
|
|
51
|
+
agent: { type: "string" },
|
|
52
|
+
soul: { type: "string" },
|
|
53
|
+
port: { type: "number" },
|
|
54
|
+
"no-start": { type: "boolean" },
|
|
55
|
+
json: { type: "boolean" }
|
|
56
|
+
});
|
|
57
|
+
const agentName = resolveAgentName(flags);
|
|
58
|
+
const variantName = positional[0];
|
|
59
|
+
const { soul, port, json } = flags;
|
|
60
|
+
const noStart = flags["no-start"];
|
|
61
|
+
if (!variantName) {
|
|
62
|
+
console.error(
|
|
63
|
+
'Usage: volute variant create <variant> [--agent <name>] [--soul "..."] [--port N] [--no-start] [--json]'
|
|
64
|
+
);
|
|
65
|
+
process.exit(1);
|
|
66
|
+
}
|
|
67
|
+
if (!json) console.log("Creating variant via daemon...");
|
|
68
|
+
const { daemonFetch } = await import("./daemon-client-P44NU3KU.js");
|
|
69
|
+
const { getClient, urlOf } = await import("./api-client-YPKOZP2O.js");
|
|
70
|
+
const client = getClient();
|
|
71
|
+
const res = await daemonFetch(
|
|
72
|
+
urlOf(client.api.agents[":name"].variants.$url({ param: { name: agentName } })),
|
|
73
|
+
{
|
|
74
|
+
method: "POST",
|
|
75
|
+
headers: { "Content-Type": "application/json" },
|
|
76
|
+
body: JSON.stringify({
|
|
77
|
+
name: variantName,
|
|
78
|
+
...soul && { soul },
|
|
79
|
+
...port && { port },
|
|
80
|
+
...noStart && { noStart }
|
|
81
|
+
})
|
|
82
|
+
}
|
|
83
|
+
);
|
|
84
|
+
const data = await res.json();
|
|
85
|
+
if (!res.ok) {
|
|
86
|
+
console.error(data.error ?? "Failed to create variant");
|
|
87
|
+
process.exit(1);
|
|
88
|
+
}
|
|
89
|
+
if (json) {
|
|
90
|
+
console.log(JSON.stringify(data.variant, null, 2));
|
|
91
|
+
} else {
|
|
92
|
+
console.log(`
|
|
93
|
+
Variant created: ${variantName}`);
|
|
94
|
+
console.log(` Branch: ${data.variant?.branch}`);
|
|
95
|
+
console.log(` Path: ${data.variant?.path}`);
|
|
96
|
+
console.log(` Port: ${data.variant?.port}`);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
async function listVariants(args) {
|
|
100
|
+
const { flags } = parseArgs(args, {
|
|
101
|
+
agent: { type: "string" },
|
|
102
|
+
json: { type: "boolean" }
|
|
103
|
+
});
|
|
104
|
+
const agentName = resolveAgentName(flags);
|
|
105
|
+
const { json } = flags;
|
|
106
|
+
resolveAgent(agentName);
|
|
107
|
+
const variants = readVariants(agentName);
|
|
108
|
+
if (variants.length === 0) {
|
|
109
|
+
if (json) {
|
|
110
|
+
console.log("[]");
|
|
111
|
+
} else {
|
|
112
|
+
console.log("No variants.");
|
|
113
|
+
}
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
const results = await Promise.all(
|
|
117
|
+
variants.map(async (v) => {
|
|
118
|
+
if (!v.port) return { ...v, status: "no-server" };
|
|
119
|
+
const health = await checkHealth(v.port);
|
|
120
|
+
return { ...v, status: health.ok ? "running" : "dead" };
|
|
121
|
+
})
|
|
122
|
+
);
|
|
123
|
+
const updated = results.map(({ status, ...v }) => ({
|
|
124
|
+
...v,
|
|
125
|
+
running: status === "running"
|
|
126
|
+
}));
|
|
127
|
+
writeVariants(agentName, updated);
|
|
128
|
+
if (json) {
|
|
129
|
+
console.log(JSON.stringify(results, null, 2));
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
const nameW = Math.max(4, ...results.map((r) => r.name.length));
|
|
133
|
+
const portW = Math.max(4, ...results.map((r) => String(r.port || "-").length));
|
|
134
|
+
console.log(`${"NAME".padEnd(nameW)} ${"PORT".padEnd(portW)} ${"STATUS".padEnd(10)} BRANCH`);
|
|
135
|
+
for (const r of results) {
|
|
136
|
+
console.log(
|
|
137
|
+
`${r.name.padEnd(nameW)} ${String(r.port || "-").padEnd(portW)} ${r.status.padEnd(10)} ${r.branch}`
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
async function mergeVariant(args) {
|
|
142
|
+
const { positional, flags } = parseArgs(args, {
|
|
143
|
+
agent: { type: "string" },
|
|
144
|
+
summary: { type: "string" },
|
|
145
|
+
justification: { type: "string" },
|
|
146
|
+
memory: { type: "string" },
|
|
147
|
+
"skip-verify": { type: "boolean" }
|
|
148
|
+
});
|
|
149
|
+
const agentName = resolveAgentName(flags);
|
|
150
|
+
const variantName = positional[0];
|
|
151
|
+
if (!variantName) {
|
|
152
|
+
console.error(
|
|
153
|
+
"Usage: volute variant merge <variant> [--agent <name>] [--summary '...'] [--justification '...'] [--memory '...'] [--skip-verify]"
|
|
154
|
+
);
|
|
155
|
+
process.exit(1);
|
|
156
|
+
}
|
|
157
|
+
console.log(`Merging variant ${variantName}...`);
|
|
158
|
+
const { daemonFetch } = await import("./daemon-client-P44NU3KU.js");
|
|
159
|
+
const { getClient, urlOf } = await import("./api-client-YPKOZP2O.js");
|
|
160
|
+
const client = getClient();
|
|
161
|
+
const res = await daemonFetch(
|
|
162
|
+
urlOf(
|
|
163
|
+
client.api.agents[":name"].variants[":variant"].merge.$url({
|
|
164
|
+
param: { name: agentName, variant: variantName }
|
|
165
|
+
})
|
|
166
|
+
),
|
|
167
|
+
{
|
|
168
|
+
method: "POST",
|
|
169
|
+
headers: { "Content-Type": "application/json" },
|
|
170
|
+
body: JSON.stringify({
|
|
171
|
+
...flags.summary && { summary: flags.summary },
|
|
172
|
+
...flags.justification && { justification: flags.justification },
|
|
173
|
+
...flags.memory && { memory: flags.memory },
|
|
174
|
+
...flags["skip-verify"] && { skipVerify: true }
|
|
175
|
+
})
|
|
176
|
+
}
|
|
177
|
+
);
|
|
178
|
+
const data = await res.json();
|
|
179
|
+
if (!res.ok) {
|
|
180
|
+
console.error(data.error ?? "Failed to merge variant");
|
|
181
|
+
process.exit(1);
|
|
182
|
+
}
|
|
183
|
+
console.log(`Variant ${variantName} merged and cleaned up.`);
|
|
184
|
+
}
|
|
185
|
+
async function deleteVariant(args) {
|
|
186
|
+
const { positional, flags } = parseArgs(args, {
|
|
187
|
+
agent: { type: "string" }
|
|
188
|
+
});
|
|
189
|
+
const agentName = resolveAgentName(flags);
|
|
190
|
+
const variantName = positional[0];
|
|
191
|
+
if (!variantName) {
|
|
192
|
+
console.error("Usage: volute variant delete <variant> [--agent <name>]");
|
|
193
|
+
process.exit(1);
|
|
194
|
+
}
|
|
195
|
+
const { daemonFetch } = await import("./daemon-client-P44NU3KU.js");
|
|
196
|
+
const { getClient, urlOf } = await import("./api-client-YPKOZP2O.js");
|
|
197
|
+
const client = getClient();
|
|
198
|
+
const res = await daemonFetch(
|
|
199
|
+
urlOf(
|
|
200
|
+
client.api.agents[":name"].variants[":variant"].$url({
|
|
201
|
+
param: { name: agentName, variant: variantName }
|
|
202
|
+
})
|
|
203
|
+
),
|
|
204
|
+
{ method: "DELETE" }
|
|
205
|
+
);
|
|
206
|
+
const data = await res.json();
|
|
207
|
+
if (!res.ok) {
|
|
208
|
+
console.error(data.error ?? "Failed to delete variant");
|
|
209
|
+
process.exit(1);
|
|
210
|
+
}
|
|
211
|
+
console.log(`Variant ${variantName} deleted.`);
|
|
212
|
+
}
|
|
213
|
+
export {
|
|
214
|
+
run
|
|
215
|
+
};
|
package/package.json
CHANGED
package/dist/chunk-ECPQXRLB.js
DELETED
|
@@ -1,264 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
voluteHome
|
|
4
|
-
} from "./chunk-DP2DX4WV.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
|
-
sender: text("sender"),
|
|
64
|
-
content: text("content").notNull(),
|
|
65
|
-
created_at: text("created_at").notNull().default(sql`(datetime('now'))`)
|
|
66
|
-
},
|
|
67
|
-
(table) => [
|
|
68
|
-
index("idx_agent_messages_agent").on(table.agent),
|
|
69
|
-
index("idx_agent_messages_channel").on(table.agent, table.channel)
|
|
70
|
-
]
|
|
71
|
-
);
|
|
72
|
-
var conversationParticipants = sqliteTable(
|
|
73
|
-
"conversation_participants",
|
|
74
|
-
{
|
|
75
|
-
conversation_id: text("conversation_id").notNull().references(() => conversations.id, { onDelete: "cascade" }),
|
|
76
|
-
user_id: integer("user_id").notNull().references(() => users.id, { onDelete: "cascade" }),
|
|
77
|
-
role: text("role").notNull().default("member"),
|
|
78
|
-
joined_at: text("joined_at").notNull().default(sql`(datetime('now'))`)
|
|
79
|
-
},
|
|
80
|
-
(table) => [
|
|
81
|
-
uniqueIndex("idx_cp_unique").on(table.conversation_id, table.user_id),
|
|
82
|
-
index("idx_cp_user_id").on(table.user_id)
|
|
83
|
-
]
|
|
84
|
-
);
|
|
85
|
-
var sessions = sqliteTable("sessions", {
|
|
86
|
-
id: text("id").primaryKey(),
|
|
87
|
-
userId: integer("user_id").references(() => users.id, { onDelete: "cascade" }).notNull(),
|
|
88
|
-
createdAt: integer("created_at").notNull()
|
|
89
|
-
});
|
|
90
|
-
var messages = sqliteTable(
|
|
91
|
-
"messages",
|
|
92
|
-
{
|
|
93
|
-
id: integer("id").primaryKey({ autoIncrement: true }),
|
|
94
|
-
conversation_id: text("conversation_id").notNull().references(() => conversations.id, { onDelete: "cascade" }),
|
|
95
|
-
role: text("role").notNull(),
|
|
96
|
-
sender_name: text("sender_name"),
|
|
97
|
-
content: text("content").notNull(),
|
|
98
|
-
created_at: text("created_at").notNull().default(sql`(datetime('now'))`)
|
|
99
|
-
},
|
|
100
|
-
(table) => [index("idx_messages_conversation_id").on(table.conversation_id)]
|
|
101
|
-
);
|
|
102
|
-
|
|
103
|
-
// src/lib/db.ts
|
|
104
|
-
var __dirname = dirname(fileURLToPath(import.meta.url));
|
|
105
|
-
var migrationsFolder = existsSync(resolve(__dirname, "../drizzle")) ? resolve(__dirname, "../drizzle") : resolve(__dirname, "../../drizzle");
|
|
106
|
-
var db = null;
|
|
107
|
-
async function getDb() {
|
|
108
|
-
if (db) return db;
|
|
109
|
-
const dbPath = process.env.VOLUTE_DB_PATH || resolve(voluteHome(), "volute.db");
|
|
110
|
-
db = drizzle({ connection: { url: `file:${dbPath}` }, schema: schema_exports });
|
|
111
|
-
await migrate(db, { migrationsFolder });
|
|
112
|
-
try {
|
|
113
|
-
chmodSync(dbPath, 384);
|
|
114
|
-
} catch (err) {
|
|
115
|
-
console.error(
|
|
116
|
-
`[volute] WARNING: Failed to restrict database file permissions on ${dbPath}:`,
|
|
117
|
-
err
|
|
118
|
-
);
|
|
119
|
-
}
|
|
120
|
-
return db;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
// src/lib/auth.ts
|
|
124
|
-
async function createUser(username, password) {
|
|
125
|
-
const db2 = await getDb();
|
|
126
|
-
const hash = hashSync(password, 10);
|
|
127
|
-
const [{ value }] = await db2.select({ value: count() }).from(users).where(eq(users.user_type, "human"));
|
|
128
|
-
const role = value === 0 ? "admin" : "pending";
|
|
129
|
-
const [result] = await db2.insert(users).values({ username, password_hash: hash, role }).returning({
|
|
130
|
-
id: users.id,
|
|
131
|
-
username: users.username,
|
|
132
|
-
role: users.role,
|
|
133
|
-
user_type: users.user_type,
|
|
134
|
-
created_at: users.created_at
|
|
135
|
-
});
|
|
136
|
-
return result;
|
|
137
|
-
}
|
|
138
|
-
async function verifyUser(username, password) {
|
|
139
|
-
const db2 = await getDb();
|
|
140
|
-
const row = await db2.select().from(users).where(eq(users.username, username)).get();
|
|
141
|
-
if (!row) return null;
|
|
142
|
-
if (row.user_type === "agent") return null;
|
|
143
|
-
if (!compareSync(password, row.password_hash)) return null;
|
|
144
|
-
const { password_hash: _, ...user } = row;
|
|
145
|
-
return user;
|
|
146
|
-
}
|
|
147
|
-
async function getUser(id) {
|
|
148
|
-
const db2 = await getDb();
|
|
149
|
-
const row = await db2.select({
|
|
150
|
-
id: users.id,
|
|
151
|
-
username: users.username,
|
|
152
|
-
role: users.role,
|
|
153
|
-
user_type: users.user_type,
|
|
154
|
-
created_at: users.created_at
|
|
155
|
-
}).from(users).where(eq(users.id, id)).get();
|
|
156
|
-
return row ?? null;
|
|
157
|
-
}
|
|
158
|
-
async function getUserByUsername(username) {
|
|
159
|
-
const db2 = await getDb();
|
|
160
|
-
const row = await db2.select({
|
|
161
|
-
id: users.id,
|
|
162
|
-
username: users.username,
|
|
163
|
-
role: users.role,
|
|
164
|
-
user_type: users.user_type,
|
|
165
|
-
created_at: users.created_at
|
|
166
|
-
}).from(users).where(eq(users.username, username)).get();
|
|
167
|
-
return row ?? null;
|
|
168
|
-
}
|
|
169
|
-
async function listUsers() {
|
|
170
|
-
const db2 = await getDb();
|
|
171
|
-
return db2.select({
|
|
172
|
-
id: users.id,
|
|
173
|
-
username: users.username,
|
|
174
|
-
role: users.role,
|
|
175
|
-
user_type: users.user_type,
|
|
176
|
-
created_at: users.created_at
|
|
177
|
-
}).from(users).orderBy(users.created_at).all();
|
|
178
|
-
}
|
|
179
|
-
async function listPendingUsers() {
|
|
180
|
-
const db2 = await getDb();
|
|
181
|
-
return db2.select({
|
|
182
|
-
id: users.id,
|
|
183
|
-
username: users.username,
|
|
184
|
-
role: users.role,
|
|
185
|
-
user_type: users.user_type,
|
|
186
|
-
created_at: users.created_at
|
|
187
|
-
}).from(users).where(eq(users.role, "pending")).orderBy(users.created_at).all();
|
|
188
|
-
}
|
|
189
|
-
async function listUsersByType(userType) {
|
|
190
|
-
const db2 = await getDb();
|
|
191
|
-
return db2.select({
|
|
192
|
-
id: users.id,
|
|
193
|
-
username: users.username,
|
|
194
|
-
role: users.role,
|
|
195
|
-
user_type: users.user_type,
|
|
196
|
-
created_at: users.created_at
|
|
197
|
-
}).from(users).where(eq(users.user_type, userType)).orderBy(users.created_at).all();
|
|
198
|
-
}
|
|
199
|
-
async function getOrCreateAgentUser(agentName) {
|
|
200
|
-
const db2 = await getDb();
|
|
201
|
-
const existing = await db2.select({
|
|
202
|
-
id: users.id,
|
|
203
|
-
username: users.username,
|
|
204
|
-
role: users.role,
|
|
205
|
-
user_type: users.user_type,
|
|
206
|
-
created_at: users.created_at
|
|
207
|
-
}).from(users).where(and(eq(users.username, agentName), eq(users.user_type, "agent"))).get();
|
|
208
|
-
if (existing) return existing;
|
|
209
|
-
try {
|
|
210
|
-
const [result] = await db2.insert(users).values({
|
|
211
|
-
username: agentName,
|
|
212
|
-
password_hash: "!agent",
|
|
213
|
-
role: "agent",
|
|
214
|
-
user_type: "agent"
|
|
215
|
-
}).returning({
|
|
216
|
-
id: users.id,
|
|
217
|
-
username: users.username,
|
|
218
|
-
role: users.role,
|
|
219
|
-
user_type: users.user_type,
|
|
220
|
-
created_at: users.created_at
|
|
221
|
-
});
|
|
222
|
-
return result;
|
|
223
|
-
} catch (err) {
|
|
224
|
-
if (err instanceof Error && err.message.includes("UNIQUE constraint")) {
|
|
225
|
-
const retried = await db2.select({
|
|
226
|
-
id: users.id,
|
|
227
|
-
username: users.username,
|
|
228
|
-
role: users.role,
|
|
229
|
-
user_type: users.user_type,
|
|
230
|
-
created_at: users.created_at
|
|
231
|
-
}).from(users).where(and(eq(users.username, agentName), eq(users.user_type, "agent"))).get();
|
|
232
|
-
if (retried) return retried;
|
|
233
|
-
}
|
|
234
|
-
throw err;
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
async function deleteAgentUser(agentName) {
|
|
238
|
-
const db2 = await getDb();
|
|
239
|
-
await db2.delete(users).where(and(eq(users.username, agentName), eq(users.user_type, "agent")));
|
|
240
|
-
}
|
|
241
|
-
async function approveUser(id) {
|
|
242
|
-
const db2 = await getDb();
|
|
243
|
-
await db2.update(users).set({ role: "user" }).where(and(eq(users.id, id), eq(users.role, "pending")));
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
export {
|
|
247
|
-
users,
|
|
248
|
-
conversations,
|
|
249
|
-
agentMessages,
|
|
250
|
-
conversationParticipants,
|
|
251
|
-
sessions,
|
|
252
|
-
messages,
|
|
253
|
-
getDb,
|
|
254
|
-
createUser,
|
|
255
|
-
verifyUser,
|
|
256
|
-
getUser,
|
|
257
|
-
getUserByUsername,
|
|
258
|
-
listUsers,
|
|
259
|
-
listPendingUsers,
|
|
260
|
-
listUsersByType,
|
|
261
|
-
getOrCreateAgentUser,
|
|
262
|
-
deleteAgentUser,
|
|
263
|
-
approveUser
|
|
264
|
-
};
|
package/dist/chunk-NETNFBA5.js
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
// src/lib/volute-config.ts
|
|
4
|
-
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
5
|
-
import { dirname, resolve } from "path";
|
|
6
|
-
function readJson(path) {
|
|
7
|
-
if (!existsSync(path)) return null;
|
|
8
|
-
try {
|
|
9
|
-
return JSON.parse(readFileSync(path, "utf-8"));
|
|
10
|
-
} catch {
|
|
11
|
-
return null;
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
function readVoluteConfig(agentDir) {
|
|
15
|
-
const path = resolve(agentDir, "home/.config/volute.json");
|
|
16
|
-
return readJson(path);
|
|
17
|
-
}
|
|
18
|
-
function writeVoluteConfig(agentDir, config) {
|
|
19
|
-
const path = resolve(agentDir, "home/.config/volute.json");
|
|
20
|
-
mkdirSync(dirname(path), { recursive: true });
|
|
21
|
-
writeFileSync(path, `${JSON.stringify(config, null, 2)}
|
|
22
|
-
`);
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export {
|
|
26
|
-
readVoluteConfig,
|
|
27
|
-
writeVoluteConfig
|
|
28
|
-
};
|
package/dist/chunk-XUA3JUFK.js
DELETED
|
@@ -1,121 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
// src/lib/template.ts
|
|
4
|
-
import {
|
|
5
|
-
cpSync,
|
|
6
|
-
existsSync,
|
|
7
|
-
mkdirSync,
|
|
8
|
-
readdirSync,
|
|
9
|
-
readFileSync,
|
|
10
|
-
renameSync,
|
|
11
|
-
rmSync,
|
|
12
|
-
statSync,
|
|
13
|
-
writeFileSync
|
|
14
|
-
} from "fs";
|
|
15
|
-
import { tmpdir } from "os";
|
|
16
|
-
import { dirname, join, relative, resolve } from "path";
|
|
17
|
-
function findTemplatesRoot() {
|
|
18
|
-
let dir = dirname(new URL(import.meta.url).pathname);
|
|
19
|
-
for (let i = 0; i < 5; i++) {
|
|
20
|
-
const candidate = resolve(dir, "templates");
|
|
21
|
-
if (existsSync(resolve(candidate, "_base"))) return candidate;
|
|
22
|
-
dir = dirname(dir);
|
|
23
|
-
}
|
|
24
|
-
console.error(
|
|
25
|
-
"Templates directory not found. Searched up from:",
|
|
26
|
-
dirname(new URL(import.meta.url).pathname)
|
|
27
|
-
);
|
|
28
|
-
process.exit(1);
|
|
29
|
-
}
|
|
30
|
-
function composeTemplate(templatesRoot, templateName) {
|
|
31
|
-
const baseDir = resolve(templatesRoot, "_base");
|
|
32
|
-
const templateDir = resolve(templatesRoot, templateName);
|
|
33
|
-
if (!existsSync(baseDir)) {
|
|
34
|
-
console.error("Base template not found:", baseDir);
|
|
35
|
-
process.exit(1);
|
|
36
|
-
}
|
|
37
|
-
if (!existsSync(templateDir)) {
|
|
38
|
-
console.error(`Template not found: ${templateName}`);
|
|
39
|
-
process.exit(1);
|
|
40
|
-
}
|
|
41
|
-
const composedDir = resolve(tmpdir(), `volute-template-${Date.now()}`);
|
|
42
|
-
mkdirSync(composedDir, { recursive: true });
|
|
43
|
-
cpSync(baseDir, composedDir, { recursive: true });
|
|
44
|
-
for (const file of listFiles(templateDir)) {
|
|
45
|
-
const src = resolve(templateDir, file);
|
|
46
|
-
const dest = resolve(composedDir, file);
|
|
47
|
-
mkdirSync(dirname(dest), { recursive: true });
|
|
48
|
-
cpSync(src, dest);
|
|
49
|
-
}
|
|
50
|
-
const manifestPath = resolve(composedDir, "volute-template.json");
|
|
51
|
-
if (!existsSync(manifestPath)) {
|
|
52
|
-
rmSync(composedDir, { recursive: true, force: true });
|
|
53
|
-
console.error(`Template manifest not found: ${templateName}/volute-template.json`);
|
|
54
|
-
process.exit(1);
|
|
55
|
-
}
|
|
56
|
-
const manifest = JSON.parse(readFileSync(manifestPath, "utf-8"));
|
|
57
|
-
const skillsSrc = resolve(composedDir, "_skills");
|
|
58
|
-
if (existsSync(skillsSrc)) {
|
|
59
|
-
const skillsDest = resolve(composedDir, manifest.skillsDir);
|
|
60
|
-
mkdirSync(skillsDest, { recursive: true });
|
|
61
|
-
cpSync(skillsSrc, skillsDest, { recursive: true });
|
|
62
|
-
rmSync(skillsSrc, { recursive: true, force: true });
|
|
63
|
-
}
|
|
64
|
-
rmSync(manifestPath);
|
|
65
|
-
return { composedDir, manifest };
|
|
66
|
-
}
|
|
67
|
-
function copyTemplateToDir(composedDir, destDir, agentName, manifest) {
|
|
68
|
-
cpSync(composedDir, destDir, { recursive: true });
|
|
69
|
-
for (const [from, to] of Object.entries(manifest.rename)) {
|
|
70
|
-
const fromPath = resolve(destDir, from);
|
|
71
|
-
if (existsSync(fromPath)) {
|
|
72
|
-
renameSync(fromPath, resolve(destDir, to));
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
for (const file of manifest.substitute) {
|
|
76
|
-
const path = resolve(destDir, file);
|
|
77
|
-
if (existsSync(path)) {
|
|
78
|
-
const content = readFileSync(path, "utf-8");
|
|
79
|
-
writeFileSync(path, content.replaceAll("{{name}}", agentName));
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
function applyInitFiles(destDir) {
|
|
84
|
-
const initDir = resolve(destDir, ".init");
|
|
85
|
-
if (!existsSync(initDir)) return;
|
|
86
|
-
const homeDir = resolve(destDir, "home");
|
|
87
|
-
for (const file of listFiles(initDir)) {
|
|
88
|
-
const src = resolve(initDir, file);
|
|
89
|
-
const dest = resolve(homeDir, file);
|
|
90
|
-
const parent = dirname(dest);
|
|
91
|
-
if (!existsSync(parent)) {
|
|
92
|
-
mkdirSync(parent, { recursive: true });
|
|
93
|
-
}
|
|
94
|
-
cpSync(src, dest);
|
|
95
|
-
}
|
|
96
|
-
rmSync(initDir, { recursive: true, force: true });
|
|
97
|
-
}
|
|
98
|
-
function listFiles(dir) {
|
|
99
|
-
const results = [];
|
|
100
|
-
function walk(current) {
|
|
101
|
-
for (const entry of readdirSync(current)) {
|
|
102
|
-
const full = join(current, entry);
|
|
103
|
-
if (statSync(full).isDirectory()) {
|
|
104
|
-
if (entry === ".git") continue;
|
|
105
|
-
walk(full);
|
|
106
|
-
} else {
|
|
107
|
-
results.push(relative(dir, full));
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
walk(dir);
|
|
112
|
-
return results;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
export {
|
|
116
|
-
findTemplatesRoot,
|
|
117
|
-
composeTemplate,
|
|
118
|
-
copyTemplateToDir,
|
|
119
|
-
applyInitFiles,
|
|
120
|
-
listFiles
|
|
121
|
-
};
|