@maintainer-pro/ai-cli 0.1.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/db-entry.cjs +388 -0
- package/dist/db-entry.d.cts +43 -0
- package/dist/db-entry.d.ts +43 -0
- package/dist/db-entry.js +238 -0
- package/dist/index.cjs +1117 -0
- package/dist/index.d.cts +239 -0
- package/dist/index.d.ts +239 -0
- package/dist/index.js +1057 -0
- package/dist/mysql-EKKUF6CP.js +34 -0
- package/dist/pg-QSUOKTP3.js +33 -0
- package/dist/sqlite-6L33HVYQ.js +28 -0
- package/drizzle/mysql/0001_init.sql +24 -0
- package/drizzle/postgres/0001_init.sql +26 -0
- package/drizzle/sqlite/0001_init.sql +26 -0
- package/package.json +64 -0
package/dist/db-entry.js
ADDED
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
// src/db/client.ts
|
|
2
|
+
import { randomUUID } from "crypto";
|
|
3
|
+
import { eq } from "drizzle-orm";
|
|
4
|
+
function toStored(row) {
|
|
5
|
+
return {
|
|
6
|
+
id: row.id,
|
|
7
|
+
conversationId: row.conversationId,
|
|
8
|
+
role: row.role,
|
|
9
|
+
content: row.content,
|
|
10
|
+
provider: row.provider,
|
|
11
|
+
createdAt: row.createdAt instanceof Date ? row.createdAt : new Date(row.createdAt)
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
async function createPostgresStore(url) {
|
|
15
|
+
const { drizzle } = await import("drizzle-orm/postgres-js");
|
|
16
|
+
const postgres = (await import("postgres")).default;
|
|
17
|
+
const schema = await import("./pg-QSUOKTP3.js");
|
|
18
|
+
const client = postgres(url);
|
|
19
|
+
const db = drizzle(client, { schema });
|
|
20
|
+
return {
|
|
21
|
+
async ensureConversation(id) {
|
|
22
|
+
await db.insert(schema.conversations).values({ id }).onConflictDoNothing();
|
|
23
|
+
},
|
|
24
|
+
async saveMessage(input) {
|
|
25
|
+
const [row] = await db.insert(schema.messages).values({
|
|
26
|
+
conversationId: input.conversationId,
|
|
27
|
+
role: input.role,
|
|
28
|
+
content: input.content,
|
|
29
|
+
provider: input.provider
|
|
30
|
+
}).returning();
|
|
31
|
+
return toStored(row);
|
|
32
|
+
},
|
|
33
|
+
async listMessages(conversationId) {
|
|
34
|
+
const rows = await db.select().from(schema.messages).where(eq(schema.messages.conversationId, conversationId));
|
|
35
|
+
return rows.map(toStored);
|
|
36
|
+
},
|
|
37
|
+
async saveToolEvents(conversationId, events) {
|
|
38
|
+
if (events.length === 0) return;
|
|
39
|
+
await db.insert(schema.toolEvents).values(
|
|
40
|
+
events.map((e) => ({
|
|
41
|
+
conversationId,
|
|
42
|
+
tool: e.tool,
|
|
43
|
+
args: e.args
|
|
44
|
+
}))
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
async function createMysqlStore(url) {
|
|
50
|
+
const { drizzle } = await import("drizzle-orm/mysql2");
|
|
51
|
+
const mysql = await import("mysql2/promise");
|
|
52
|
+
const schema = await import("./mysql-EKKUF6CP.js");
|
|
53
|
+
const pool = mysql.createPool(url);
|
|
54
|
+
const db = drizzle(pool, { schema, mode: "default" });
|
|
55
|
+
return {
|
|
56
|
+
async ensureConversation(id) {
|
|
57
|
+
await db.insert(schema.conversations).values({ id }).onDuplicateKeyUpdate({
|
|
58
|
+
set: { updatedAt: /* @__PURE__ */ new Date() }
|
|
59
|
+
});
|
|
60
|
+
},
|
|
61
|
+
async saveMessage(input) {
|
|
62
|
+
const id = randomUUID();
|
|
63
|
+
await db.insert(schema.messages).values({
|
|
64
|
+
id,
|
|
65
|
+
conversationId: input.conversationId,
|
|
66
|
+
role: input.role,
|
|
67
|
+
content: input.content,
|
|
68
|
+
provider: input.provider ?? null
|
|
69
|
+
});
|
|
70
|
+
return {
|
|
71
|
+
id,
|
|
72
|
+
conversationId: input.conversationId,
|
|
73
|
+
role: input.role,
|
|
74
|
+
content: input.content,
|
|
75
|
+
provider: input.provider ?? null,
|
|
76
|
+
createdAt: /* @__PURE__ */ new Date()
|
|
77
|
+
};
|
|
78
|
+
},
|
|
79
|
+
async listMessages(conversationId) {
|
|
80
|
+
const rows = await db.select().from(schema.messages).where(eq(schema.messages.conversationId, conversationId));
|
|
81
|
+
return rows.map(
|
|
82
|
+
(row) => toStored({
|
|
83
|
+
...row,
|
|
84
|
+
provider: row.provider ?? null
|
|
85
|
+
})
|
|
86
|
+
);
|
|
87
|
+
},
|
|
88
|
+
async saveToolEvents(conversationId, events) {
|
|
89
|
+
if (events.length === 0) return;
|
|
90
|
+
await db.insert(schema.toolEvents).values(
|
|
91
|
+
events.map((e) => ({
|
|
92
|
+
id: randomUUID(),
|
|
93
|
+
conversationId,
|
|
94
|
+
tool: e.tool,
|
|
95
|
+
args: e.args
|
|
96
|
+
}))
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
async function createSqliteStore(url) {
|
|
102
|
+
const { drizzle } = await import("drizzle-orm/better-sqlite3");
|
|
103
|
+
const Database = (await import("better-sqlite3")).default;
|
|
104
|
+
const schema = await import("./sqlite-6L33HVYQ.js");
|
|
105
|
+
const file = url.replace(/^file:/, "");
|
|
106
|
+
const sqlite = new Database(file);
|
|
107
|
+
const db = drizzle(sqlite, { schema });
|
|
108
|
+
return {
|
|
109
|
+
async ensureConversation(id) {
|
|
110
|
+
await db.insert(schema.conversations).values({ id }).onConflictDoNothing();
|
|
111
|
+
},
|
|
112
|
+
async saveMessage(input) {
|
|
113
|
+
const id = randomUUID();
|
|
114
|
+
const [row] = await db.insert(schema.messages).values({
|
|
115
|
+
id,
|
|
116
|
+
conversationId: input.conversationId,
|
|
117
|
+
role: input.role,
|
|
118
|
+
content: input.content,
|
|
119
|
+
provider: input.provider ?? null
|
|
120
|
+
}).returning();
|
|
121
|
+
return toStored({
|
|
122
|
+
...row,
|
|
123
|
+
provider: row.provider ?? null
|
|
124
|
+
});
|
|
125
|
+
},
|
|
126
|
+
async listMessages(conversationId) {
|
|
127
|
+
const rows = await db.select().from(schema.messages).where(eq(schema.messages.conversationId, conversationId));
|
|
128
|
+
return rows.map(
|
|
129
|
+
(row) => toStored({
|
|
130
|
+
...row,
|
|
131
|
+
provider: row.provider ?? null
|
|
132
|
+
})
|
|
133
|
+
);
|
|
134
|
+
},
|
|
135
|
+
async saveToolEvents(conversationId, events) {
|
|
136
|
+
if (events.length === 0) return;
|
|
137
|
+
await db.insert(schema.toolEvents).values(
|
|
138
|
+
events.map((e) => ({
|
|
139
|
+
id: randomUUID(),
|
|
140
|
+
conversationId,
|
|
141
|
+
tool: e.tool,
|
|
142
|
+
args: e.args
|
|
143
|
+
}))
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
async function createAiCliDb(options) {
|
|
149
|
+
switch (options.dialect) {
|
|
150
|
+
case "postgres":
|
|
151
|
+
return createPostgresStore(options.url);
|
|
152
|
+
case "mysql":
|
|
153
|
+
return createMysqlStore(options.url);
|
|
154
|
+
case "sqlite":
|
|
155
|
+
return createSqliteStore(options.url);
|
|
156
|
+
default:
|
|
157
|
+
throw new Error(`Unsupported dialect: ${options.dialect}`);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
function createAiCliDbFromEnv() {
|
|
161
|
+
const url = process.env.AI_CLI_DB_URL?.trim();
|
|
162
|
+
const dialect = process.env.AI_CLI_DB_DIALECT?.trim();
|
|
163
|
+
if (!url || !dialect) return null;
|
|
164
|
+
if (dialect !== "postgres" && dialect !== "mysql" && dialect !== "sqlite") {
|
|
165
|
+
throw new Error(
|
|
166
|
+
`Invalid AI_CLI_DB_DIALECT="${dialect}". Use postgres|mysql|sqlite.`
|
|
167
|
+
);
|
|
168
|
+
}
|
|
169
|
+
return createAiCliDb({ dialect, url });
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// src/db/migrate.ts
|
|
173
|
+
import fs from "fs";
|
|
174
|
+
import path from "path";
|
|
175
|
+
function migrationsDir() {
|
|
176
|
+
const candidates = [
|
|
177
|
+
path.join(__dirname, "..", "drizzle"),
|
|
178
|
+
path.join(process.cwd(), "drizzle"),
|
|
179
|
+
path.join(process.cwd(), "packages", "ai-cli", "drizzle")
|
|
180
|
+
];
|
|
181
|
+
for (const dir of candidates) {
|
|
182
|
+
if (fs.existsSync(dir)) return dir;
|
|
183
|
+
}
|
|
184
|
+
throw new Error("Could not locate ai-cli drizzle migrations folder");
|
|
185
|
+
}
|
|
186
|
+
async function runMigrations(options) {
|
|
187
|
+
const sqlPath = path.join(migrationsDir(), options.dialect, "0001_init.sql");
|
|
188
|
+
if (!fs.existsSync(sqlPath)) {
|
|
189
|
+
throw new Error(`Migration file missing: ${sqlPath}`);
|
|
190
|
+
}
|
|
191
|
+
const sql = fs.readFileSync(sqlPath, "utf8");
|
|
192
|
+
if (options.dialect === "postgres") {
|
|
193
|
+
const postgres = (await import("postgres")).default;
|
|
194
|
+
const client = postgres(options.url, { max: 1 });
|
|
195
|
+
try {
|
|
196
|
+
await client.unsafe(sql);
|
|
197
|
+
} finally {
|
|
198
|
+
await client.end();
|
|
199
|
+
}
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
if (options.dialect === "mysql") {
|
|
203
|
+
const mysql = await import("mysql2/promise");
|
|
204
|
+
const conn = await mysql.createConnection(options.url);
|
|
205
|
+
try {
|
|
206
|
+
for (const statement of sql.split(";").map((s) => s.trim()).filter(Boolean)) {
|
|
207
|
+
await conn.query(statement);
|
|
208
|
+
}
|
|
209
|
+
} finally {
|
|
210
|
+
await conn.end();
|
|
211
|
+
}
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
const Database = (await import("better-sqlite3")).default;
|
|
215
|
+
const file = options.url.replace(/^file:/, "");
|
|
216
|
+
const db = new Database(file);
|
|
217
|
+
try {
|
|
218
|
+
db.exec(sql);
|
|
219
|
+
} finally {
|
|
220
|
+
db.close();
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
async function runMigrationsFromEnv() {
|
|
224
|
+
const url = process.env.AI_CLI_DB_URL?.trim();
|
|
225
|
+
const dialect = process.env.AI_CLI_DB_DIALECT?.trim();
|
|
226
|
+
if (!url || !dialect) {
|
|
227
|
+
throw new Error(
|
|
228
|
+
"Set AI_CLI_DB_URL and AI_CLI_DB_DIALECT to run migrations"
|
|
229
|
+
);
|
|
230
|
+
}
|
|
231
|
+
await runMigrations({ dialect, url });
|
|
232
|
+
}
|
|
233
|
+
export {
|
|
234
|
+
createAiCliDb,
|
|
235
|
+
createAiCliDbFromEnv,
|
|
236
|
+
runMigrations,
|
|
237
|
+
runMigrationsFromEnv
|
|
238
|
+
};
|