skillo 0.2.1 → 0.2.2
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/{api-client-WO6NUCIJ.js → api-client-KUQW7FSC.js} +3 -2
- package/dist/chunk-2CVEPT6U.js +463 -0
- package/dist/chunk-2CVEPT6U.js.map +1 -0
- package/dist/chunk-CPL3P2OF.js +183 -0
- package/dist/chunk-CPL3P2OF.js.map +1 -0
- package/dist/{chunk-SYULMYPN.js → chunk-ODOZM4QV.js} +4 -178
- package/dist/chunk-ODOZM4QV.js.map +1 -0
- package/dist/cli.js +209 -567
- package/dist/cli.js.map +1 -1
- package/dist/config-P5EM5L7N.js +17 -0
- package/dist/config-P5EM5L7N.js.map +1 -0
- package/dist/database-F3BFFZKG.js +9 -0
- package/dist/database-F3BFFZKG.js.map +1 -0
- package/package.json +1 -1
- package/scripts/postinstall.mjs +8 -11
- package/dist/chunk-SYULMYPN.js.map +0 -1
- /package/dist/{api-client-WO6NUCIJ.js.map → api-client-KUQW7FSC.js.map} +0 -0
|
@@ -2,10 +2,11 @@
|
|
|
2
2
|
import {
|
|
3
3
|
ApiClient,
|
|
4
4
|
getApiClient
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-ODOZM4QV.js";
|
|
6
|
+
import "./chunk-CPL3P2OF.js";
|
|
6
7
|
import "./chunk-WJKZWKER.js";
|
|
7
8
|
export {
|
|
8
9
|
ApiClient,
|
|
9
10
|
getApiClient
|
|
10
11
|
};
|
|
11
|
-
//# sourceMappingURL=api-client-
|
|
12
|
+
//# sourceMappingURL=api-client-KUQW7FSC.js.map
|
|
@@ -0,0 +1,463 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
ensureDirectory,
|
|
4
|
+
getDbPath
|
|
5
|
+
} from "./chunk-WJKZWKER.js";
|
|
6
|
+
|
|
7
|
+
// src/core/database.ts
|
|
8
|
+
import initSqlJs from "sql.js";
|
|
9
|
+
import { readFileSync, writeFileSync, existsSync } from "fs";
|
|
10
|
+
import { randomUUID } from "crypto";
|
|
11
|
+
import { dirname } from "path";
|
|
12
|
+
var SQL = null;
|
|
13
|
+
async function getSqlJs() {
|
|
14
|
+
if (!SQL) {
|
|
15
|
+
SQL = await initSqlJs();
|
|
16
|
+
}
|
|
17
|
+
return SQL;
|
|
18
|
+
}
|
|
19
|
+
var SkilloDatabase = class {
|
|
20
|
+
db = null;
|
|
21
|
+
dbPath;
|
|
22
|
+
initialized = false;
|
|
23
|
+
constructor(dbPath) {
|
|
24
|
+
this.dbPath = dbPath || getDbPath();
|
|
25
|
+
ensureDirectory(dirname(this.dbPath));
|
|
26
|
+
}
|
|
27
|
+
async getDb() {
|
|
28
|
+
if (!this.db) {
|
|
29
|
+
const SQL2 = await getSqlJs();
|
|
30
|
+
if (existsSync(this.dbPath)) {
|
|
31
|
+
const buffer = readFileSync(this.dbPath);
|
|
32
|
+
this.db = new SQL2.Database(buffer);
|
|
33
|
+
} else {
|
|
34
|
+
this.db = new SQL2.Database();
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return this.db;
|
|
38
|
+
}
|
|
39
|
+
save() {
|
|
40
|
+
if (this.db) {
|
|
41
|
+
const data = this.db.export();
|
|
42
|
+
const buffer = Buffer.from(data);
|
|
43
|
+
writeFileSync(this.dbPath, buffer);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
async initialize() {
|
|
47
|
+
if (this.initialized) return;
|
|
48
|
+
const db = await this.getDb();
|
|
49
|
+
const schema = `
|
|
50
|
+
-- Command history
|
|
51
|
+
CREATE TABLE IF NOT EXISTS commands (
|
|
52
|
+
id TEXT PRIMARY KEY,
|
|
53
|
+
timestamp DATETIME NOT NULL,
|
|
54
|
+
command TEXT NOT NULL,
|
|
55
|
+
normalized TEXT NOT NULL,
|
|
56
|
+
variables TEXT,
|
|
57
|
+
cwd TEXT NOT NULL,
|
|
58
|
+
exit_code INTEGER,
|
|
59
|
+
duration_ms INTEGER,
|
|
60
|
+
session_id TEXT NOT NULL,
|
|
61
|
+
project_id TEXT,
|
|
62
|
+
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
CREATE INDEX IF NOT EXISTS idx_commands_session ON commands(session_id);
|
|
66
|
+
CREATE INDEX IF NOT EXISTS idx_commands_timestamp ON commands(timestamp);
|
|
67
|
+
CREATE INDEX IF NOT EXISTS idx_commands_normalized ON commands(normalized);
|
|
68
|
+
|
|
69
|
+
-- Terminal sessions
|
|
70
|
+
CREATE TABLE IF NOT EXISTS sessions (
|
|
71
|
+
id TEXT PRIMARY KEY,
|
|
72
|
+
started_at DATETIME NOT NULL,
|
|
73
|
+
ended_at DATETIME,
|
|
74
|
+
shell TEXT NOT NULL,
|
|
75
|
+
project_path TEXT,
|
|
76
|
+
command_count INTEGER DEFAULT 0,
|
|
77
|
+
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
-- Conversations (Claude Code)
|
|
81
|
+
CREATE TABLE IF NOT EXISTS conversations (
|
|
82
|
+
id TEXT PRIMARY KEY,
|
|
83
|
+
project_path TEXT,
|
|
84
|
+
started_at DATETIME,
|
|
85
|
+
updated_at DATETIME,
|
|
86
|
+
message_count INTEGER DEFAULT 0,
|
|
87
|
+
tool_calls TEXT,
|
|
88
|
+
files_touched TEXT,
|
|
89
|
+
intent_summary TEXT,
|
|
90
|
+
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
CREATE INDEX IF NOT EXISTS idx_conversations_project ON conversations(project_path);
|
|
94
|
+
|
|
95
|
+
-- Detected patterns
|
|
96
|
+
CREATE TABLE IF NOT EXISTS patterns (
|
|
97
|
+
id TEXT PRIMARY KEY,
|
|
98
|
+
source_type TEXT NOT NULL,
|
|
99
|
+
description TEXT NOT NULL,
|
|
100
|
+
count INTEGER DEFAULT 1,
|
|
101
|
+
first_seen DATETIME NOT NULL,
|
|
102
|
+
last_seen DATETIME NOT NULL,
|
|
103
|
+
data TEXT NOT NULL,
|
|
104
|
+
status TEXT DEFAULT 'active',
|
|
105
|
+
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
106
|
+
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
107
|
+
);
|
|
108
|
+
|
|
109
|
+
CREATE INDEX IF NOT EXISTS idx_patterns_status ON patterns(status);
|
|
110
|
+
CREATE INDEX IF NOT EXISTS idx_patterns_count ON patterns(count);
|
|
111
|
+
|
|
112
|
+
-- Generated skills
|
|
113
|
+
CREATE TABLE IF NOT EXISTS skills (
|
|
114
|
+
id TEXT PRIMARY KEY,
|
|
115
|
+
name TEXT UNIQUE NOT NULL,
|
|
116
|
+
path TEXT NOT NULL,
|
|
117
|
+
source_patterns TEXT,
|
|
118
|
+
source_type TEXT NOT NULL,
|
|
119
|
+
trigger_phrase TEXT,
|
|
120
|
+
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
121
|
+
usage_count INTEGER DEFAULT 0,
|
|
122
|
+
last_used_at DATETIME
|
|
123
|
+
);
|
|
124
|
+
|
|
125
|
+
CREATE INDEX IF NOT EXISTS idx_skills_name ON skills(name);
|
|
126
|
+
|
|
127
|
+
-- Configuration
|
|
128
|
+
CREATE TABLE IF NOT EXISTS config (
|
|
129
|
+
key TEXT PRIMARY KEY,
|
|
130
|
+
value TEXT NOT NULL,
|
|
131
|
+
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
132
|
+
);
|
|
133
|
+
|
|
134
|
+
-- Ignored patterns
|
|
135
|
+
CREATE TABLE IF NOT EXISTS ignored_patterns (
|
|
136
|
+
pattern_hash TEXT PRIMARY KEY,
|
|
137
|
+
reason TEXT,
|
|
138
|
+
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
139
|
+
);
|
|
140
|
+
|
|
141
|
+
-- Notifications
|
|
142
|
+
CREATE TABLE IF NOT EXISTS notifications (
|
|
143
|
+
id TEXT PRIMARY KEY,
|
|
144
|
+
type TEXT NOT NULL,
|
|
145
|
+
title TEXT NOT NULL,
|
|
146
|
+
message TEXT,
|
|
147
|
+
data TEXT,
|
|
148
|
+
is_read INTEGER DEFAULT 0,
|
|
149
|
+
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
150
|
+
);
|
|
151
|
+
`;
|
|
152
|
+
db.run(schema);
|
|
153
|
+
this.save();
|
|
154
|
+
this.initialized = true;
|
|
155
|
+
}
|
|
156
|
+
close() {
|
|
157
|
+
if (this.db) {
|
|
158
|
+
this.save();
|
|
159
|
+
this.db.close();
|
|
160
|
+
this.db = null;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
// Command operations
|
|
164
|
+
async addCommand(params) {
|
|
165
|
+
const db = await this.getDb();
|
|
166
|
+
const id = randomUUID();
|
|
167
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
168
|
+
db.run(
|
|
169
|
+
`INSERT INTO commands (id, timestamp, command, normalized, variables, cwd, exit_code, duration_ms, session_id, project_id)
|
|
170
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
171
|
+
[
|
|
172
|
+
id,
|
|
173
|
+
timestamp,
|
|
174
|
+
params.command,
|
|
175
|
+
params.normalized,
|
|
176
|
+
params.variables ? JSON.stringify(params.variables) : null,
|
|
177
|
+
params.cwd,
|
|
178
|
+
params.exitCode ?? null,
|
|
179
|
+
params.durationMs ?? null,
|
|
180
|
+
params.sessionId,
|
|
181
|
+
params.projectId ?? null
|
|
182
|
+
]
|
|
183
|
+
);
|
|
184
|
+
this.save();
|
|
185
|
+
return id;
|
|
186
|
+
}
|
|
187
|
+
async getRecentCommands(options) {
|
|
188
|
+
const db = await this.getDb();
|
|
189
|
+
const limit = options?.limit ?? 100;
|
|
190
|
+
let query = "SELECT * FROM commands";
|
|
191
|
+
const params = [];
|
|
192
|
+
const conditions = [];
|
|
193
|
+
if (options?.sessionId) {
|
|
194
|
+
conditions.push("session_id = ?");
|
|
195
|
+
params.push(options.sessionId);
|
|
196
|
+
}
|
|
197
|
+
if (options?.days) {
|
|
198
|
+
const cutoff = /* @__PURE__ */ new Date();
|
|
199
|
+
cutoff.setDate(cutoff.getDate() - options.days);
|
|
200
|
+
conditions.push("timestamp >= ?");
|
|
201
|
+
params.push(cutoff.toISOString());
|
|
202
|
+
}
|
|
203
|
+
if (conditions.length > 0) {
|
|
204
|
+
query += " WHERE " + conditions.join(" AND ");
|
|
205
|
+
}
|
|
206
|
+
query += " ORDER BY timestamp DESC LIMIT ?";
|
|
207
|
+
params.push(limit);
|
|
208
|
+
const results = db.exec(query, params);
|
|
209
|
+
if (results.length === 0) return [];
|
|
210
|
+
return results[0].values.map((row) => this.mapCommand(results[0].columns, row));
|
|
211
|
+
}
|
|
212
|
+
// Session operations
|
|
213
|
+
async createSession(shell, projectPath) {
|
|
214
|
+
const db = await this.getDb();
|
|
215
|
+
const id = randomUUID();
|
|
216
|
+
const startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
217
|
+
db.run(
|
|
218
|
+
`INSERT INTO sessions (id, started_at, shell, project_path) VALUES (?, ?, ?, ?)`,
|
|
219
|
+
[id, startedAt, shell, projectPath ?? null]
|
|
220
|
+
);
|
|
221
|
+
this.save();
|
|
222
|
+
return id;
|
|
223
|
+
}
|
|
224
|
+
async endSession(sessionId) {
|
|
225
|
+
const db = await this.getDb();
|
|
226
|
+
const endedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
227
|
+
db.run(
|
|
228
|
+
`UPDATE sessions
|
|
229
|
+
SET ended_at = ?, command_count = (SELECT COUNT(*) FROM commands WHERE session_id = ?)
|
|
230
|
+
WHERE id = ?`,
|
|
231
|
+
[endedAt, sessionId, sessionId]
|
|
232
|
+
);
|
|
233
|
+
this.save();
|
|
234
|
+
}
|
|
235
|
+
async getSession(sessionId) {
|
|
236
|
+
const db = await this.getDb();
|
|
237
|
+
const results = db.exec("SELECT * FROM sessions WHERE id = ?", [sessionId]);
|
|
238
|
+
if (results.length === 0 || results[0].values.length === 0) return null;
|
|
239
|
+
return this.mapSession(results[0].columns, results[0].values[0]);
|
|
240
|
+
}
|
|
241
|
+
// Pattern operations
|
|
242
|
+
async addPattern(params) {
|
|
243
|
+
const db = await this.getDb();
|
|
244
|
+
const patternId = params.patternHash || randomUUID();
|
|
245
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
246
|
+
const existing = db.exec("SELECT id, count FROM patterns WHERE id = ?", [patternId]);
|
|
247
|
+
if (existing.length > 0 && existing[0].values.length > 0) {
|
|
248
|
+
db.run(`UPDATE patterns SET count = count + 1, last_seen = ?, updated_at = ? WHERE id = ?`, [
|
|
249
|
+
now,
|
|
250
|
+
now,
|
|
251
|
+
patternId
|
|
252
|
+
]);
|
|
253
|
+
} else {
|
|
254
|
+
db.run(
|
|
255
|
+
`INSERT INTO patterns (id, source_type, description, data, first_seen, last_seen)
|
|
256
|
+
VALUES (?, ?, ?, ?, ?, ?)`,
|
|
257
|
+
[patternId, params.sourceType, params.description, JSON.stringify(params.data), now, now]
|
|
258
|
+
);
|
|
259
|
+
}
|
|
260
|
+
this.save();
|
|
261
|
+
return patternId;
|
|
262
|
+
}
|
|
263
|
+
async getPatterns(options) {
|
|
264
|
+
const db = await this.getDb();
|
|
265
|
+
const minCount = options?.minCount ?? 1;
|
|
266
|
+
const limit = options?.limit ?? 50;
|
|
267
|
+
let query = "SELECT * FROM patterns WHERE count >= ?";
|
|
268
|
+
const params = [minCount];
|
|
269
|
+
if (options?.type) {
|
|
270
|
+
query += " AND source_type = ?";
|
|
271
|
+
params.push(options.type);
|
|
272
|
+
}
|
|
273
|
+
if (options?.status) {
|
|
274
|
+
query += " AND status = ?";
|
|
275
|
+
params.push(options.status);
|
|
276
|
+
}
|
|
277
|
+
query += " ORDER BY count DESC, last_seen DESC LIMIT ?";
|
|
278
|
+
params.push(limit);
|
|
279
|
+
const results = db.exec(query, params);
|
|
280
|
+
if (results.length === 0) return [];
|
|
281
|
+
return results[0].values.map((row) => this.mapPattern(results[0].columns, row));
|
|
282
|
+
}
|
|
283
|
+
async getPattern(patternId) {
|
|
284
|
+
const db = await this.getDb();
|
|
285
|
+
let results = db.exec("SELECT * FROM patterns WHERE id = ?", [patternId]);
|
|
286
|
+
if (results.length === 0 || results[0].values.length === 0) {
|
|
287
|
+
results = db.exec("SELECT * FROM patterns WHERE id LIKE ?", [`${patternId}%`]);
|
|
288
|
+
}
|
|
289
|
+
if (results.length === 0 || results[0].values.length === 0) return null;
|
|
290
|
+
return this.mapPattern(results[0].columns, results[0].values[0]);
|
|
291
|
+
}
|
|
292
|
+
async updatePatternStatus(patternId, status) {
|
|
293
|
+
const db = await this.getDb();
|
|
294
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
295
|
+
db.run(`UPDATE patterns SET status = ?, updated_at = ? WHERE id = ? OR id LIKE ?`, [
|
|
296
|
+
status,
|
|
297
|
+
now,
|
|
298
|
+
patternId,
|
|
299
|
+
`${patternId}%`
|
|
300
|
+
]);
|
|
301
|
+
this.save();
|
|
302
|
+
}
|
|
303
|
+
async addIgnoredPattern(patternHash, reason) {
|
|
304
|
+
const db = await this.getDb();
|
|
305
|
+
db.run(`INSERT OR REPLACE INTO ignored_patterns (pattern_hash, reason) VALUES (?, ?)`, [
|
|
306
|
+
patternHash,
|
|
307
|
+
reason ?? null
|
|
308
|
+
]);
|
|
309
|
+
this.save();
|
|
310
|
+
}
|
|
311
|
+
async isPatternIgnored(patternHash) {
|
|
312
|
+
const db = await this.getDb();
|
|
313
|
+
const results = db.exec("SELECT 1 FROM ignored_patterns WHERE pattern_hash = ?", [patternHash]);
|
|
314
|
+
return results.length > 0 && results[0].values.length > 0;
|
|
315
|
+
}
|
|
316
|
+
// Skill operations
|
|
317
|
+
async registerSkill(params) {
|
|
318
|
+
const db = await this.getDb();
|
|
319
|
+
const id = randomUUID();
|
|
320
|
+
db.run(
|
|
321
|
+
`INSERT INTO skills (id, name, path, source_patterns, source_type, trigger_phrase)
|
|
322
|
+
VALUES (?, ?, ?, ?, ?, ?)`,
|
|
323
|
+
[
|
|
324
|
+
id,
|
|
325
|
+
params.name,
|
|
326
|
+
params.path,
|
|
327
|
+
params.sourcePatterns ? JSON.stringify(params.sourcePatterns) : null,
|
|
328
|
+
params.sourceType,
|
|
329
|
+
params.triggerPhrase ?? null
|
|
330
|
+
]
|
|
331
|
+
);
|
|
332
|
+
this.save();
|
|
333
|
+
return id;
|
|
334
|
+
}
|
|
335
|
+
async getSkills(options) {
|
|
336
|
+
const db = await this.getDb();
|
|
337
|
+
const sortMap = {
|
|
338
|
+
name: "name",
|
|
339
|
+
created: "created_at",
|
|
340
|
+
usage: "usage_count DESC"
|
|
341
|
+
};
|
|
342
|
+
const order = sortMap[options?.sortBy ?? "name"];
|
|
343
|
+
let query = "SELECT * FROM skills";
|
|
344
|
+
const params = [];
|
|
345
|
+
if (options?.source) {
|
|
346
|
+
query += " WHERE source_type = ?";
|
|
347
|
+
params.push(options.source);
|
|
348
|
+
}
|
|
349
|
+
query += ` ORDER BY ${order}`;
|
|
350
|
+
const results = db.exec(query, params);
|
|
351
|
+
if (results.length === 0) return [];
|
|
352
|
+
return results[0].values.map((row) => this.mapSkill(results[0].columns, row));
|
|
353
|
+
}
|
|
354
|
+
async getSkill(name) {
|
|
355
|
+
const db = await this.getDb();
|
|
356
|
+
const results = db.exec("SELECT * FROM skills WHERE name = ?", [name]);
|
|
357
|
+
if (results.length === 0 || results[0].values.length === 0) return null;
|
|
358
|
+
return this.mapSkill(results[0].columns, results[0].values[0]);
|
|
359
|
+
}
|
|
360
|
+
async deleteSkill(name) {
|
|
361
|
+
const db = await this.getDb();
|
|
362
|
+
db.run("DELETE FROM skills WHERE name = ?", [name]);
|
|
363
|
+
this.save();
|
|
364
|
+
}
|
|
365
|
+
async recordSkillUsage(name) {
|
|
366
|
+
const db = await this.getDb();
|
|
367
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
368
|
+
db.run(`UPDATE skills SET usage_count = usage_count + 1, last_used_at = ? WHERE name = ?`, [
|
|
369
|
+
now,
|
|
370
|
+
name
|
|
371
|
+
]);
|
|
372
|
+
this.save();
|
|
373
|
+
}
|
|
374
|
+
// Statistics
|
|
375
|
+
async getStats() {
|
|
376
|
+
const db = await this.getDb();
|
|
377
|
+
const today = /* @__PURE__ */ new Date();
|
|
378
|
+
today.setHours(0, 0, 0, 0);
|
|
379
|
+
const todayIso = today.toISOString();
|
|
380
|
+
const getCount = (query, params = []) => {
|
|
381
|
+
const results = db.exec(query, params);
|
|
382
|
+
if (results.length === 0 || results[0].values.length === 0) return 0;
|
|
383
|
+
return results[0].values[0][0];
|
|
384
|
+
};
|
|
385
|
+
return {
|
|
386
|
+
commandsToday: getCount("SELECT COUNT(*) FROM commands WHERE timestamp >= ?", [todayIso]),
|
|
387
|
+
commandsTotal: getCount("SELECT COUNT(*) FROM commands"),
|
|
388
|
+
patternsActive: getCount("SELECT COUNT(*) FROM patterns WHERE status = 'active'"),
|
|
389
|
+
skillsTotal: getCount("SELECT COUNT(*) FROM skills"),
|
|
390
|
+
conversationsTotal: getCount("SELECT COUNT(*) FROM conversations")
|
|
391
|
+
};
|
|
392
|
+
}
|
|
393
|
+
// Mapping helpers
|
|
394
|
+
mapCommand(columns, values) {
|
|
395
|
+
const row = this.toObject(columns, values);
|
|
396
|
+
return {
|
|
397
|
+
id: row.id,
|
|
398
|
+
timestamp: row.timestamp,
|
|
399
|
+
command: row.command,
|
|
400
|
+
normalized: row.normalized,
|
|
401
|
+
variables: row.variables,
|
|
402
|
+
cwd: row.cwd,
|
|
403
|
+
exitCode: row.exit_code,
|
|
404
|
+
durationMs: row.duration_ms,
|
|
405
|
+
sessionId: row.session_id,
|
|
406
|
+
projectId: row.project_id,
|
|
407
|
+
createdAt: row.created_at
|
|
408
|
+
};
|
|
409
|
+
}
|
|
410
|
+
mapSession(columns, values) {
|
|
411
|
+
const row = this.toObject(columns, values);
|
|
412
|
+
return {
|
|
413
|
+
id: row.id,
|
|
414
|
+
startedAt: row.started_at,
|
|
415
|
+
endedAt: row.ended_at,
|
|
416
|
+
shell: row.shell,
|
|
417
|
+
projectPath: row.project_path,
|
|
418
|
+
commandCount: row.command_count,
|
|
419
|
+
createdAt: row.created_at
|
|
420
|
+
};
|
|
421
|
+
}
|
|
422
|
+
mapPattern(columns, values) {
|
|
423
|
+
const row = this.toObject(columns, values);
|
|
424
|
+
return {
|
|
425
|
+
id: row.id,
|
|
426
|
+
sourceType: row.source_type,
|
|
427
|
+
description: row.description,
|
|
428
|
+
count: row.count,
|
|
429
|
+
firstSeen: row.first_seen,
|
|
430
|
+
lastSeen: row.last_seen,
|
|
431
|
+
data: JSON.parse(row.data),
|
|
432
|
+
status: row.status,
|
|
433
|
+
createdAt: row.created_at,
|
|
434
|
+
updatedAt: row.updated_at
|
|
435
|
+
};
|
|
436
|
+
}
|
|
437
|
+
mapSkill(columns, values) {
|
|
438
|
+
const row = this.toObject(columns, values);
|
|
439
|
+
return {
|
|
440
|
+
id: row.id,
|
|
441
|
+
name: row.name,
|
|
442
|
+
path: row.path,
|
|
443
|
+
sourcePatterns: row.source_patterns,
|
|
444
|
+
sourceType: row.source_type,
|
|
445
|
+
triggerPhrase: row.trigger_phrase,
|
|
446
|
+
createdAt: row.created_at,
|
|
447
|
+
usageCount: row.usage_count,
|
|
448
|
+
lastUsedAt: row.last_used_at
|
|
449
|
+
};
|
|
450
|
+
}
|
|
451
|
+
toObject(columns, values) {
|
|
452
|
+
const obj = {};
|
|
453
|
+
columns.forEach((col, i) => {
|
|
454
|
+
obj[col] = values[i];
|
|
455
|
+
});
|
|
456
|
+
return obj;
|
|
457
|
+
}
|
|
458
|
+
};
|
|
459
|
+
|
|
460
|
+
export {
|
|
461
|
+
SkilloDatabase
|
|
462
|
+
};
|
|
463
|
+
//# sourceMappingURL=chunk-2CVEPT6U.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/core/database.ts"],"sourcesContent":["/**\n * Database operations for Skillo.\n * Uses sql.js for pure JavaScript SQLite (no native dependencies).\n */\n\nimport initSqlJs, { Database as SqlJsDatabase, SqlValue } from \"sql.js\";\nimport { readFileSync, writeFileSync, existsSync } from \"fs\";\nimport { randomUUID } from \"crypto\";\nimport { dirname } from \"path\";\nimport { ensureDirectory, getDbPath } from \"../utils/paths.js\";\n\nexport interface Command {\n id: string;\n timestamp: string;\n command: string;\n normalized: string;\n variables: string | null;\n cwd: string;\n exitCode: number | null;\n durationMs: number | null;\n sessionId: string;\n projectId: string | null;\n createdAt: string;\n}\n\nexport interface Session {\n id: string;\n startedAt: string;\n endedAt: string | null;\n shell: string;\n projectPath: string | null;\n commandCount: number;\n createdAt: string;\n}\n\nexport interface Pattern {\n id: string;\n sourceType: string;\n description: string;\n count: number;\n firstSeen: string;\n lastSeen: string;\n data: Record<string, unknown>;\n status: string;\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface Skill {\n id: string;\n name: string;\n path: string;\n sourcePatterns: string | null;\n sourceType: string;\n triggerPhrase: string | null;\n createdAt: string;\n usageCount: number;\n lastUsedAt: string | null;\n}\n\nexport interface Stats {\n commandsToday: number;\n commandsTotal: number;\n patternsActive: number;\n skillsTotal: number;\n conversationsTotal: number;\n}\n\nlet SQL: Awaited<ReturnType<typeof initSqlJs>> | null = null;\n\nasync function getSqlJs() {\n if (!SQL) {\n SQL = await initSqlJs();\n }\n return SQL;\n}\n\nexport class SkilloDatabase {\n private db: SqlJsDatabase | null = null;\n private dbPath: string;\n private initialized = false;\n\n constructor(dbPath?: string) {\n this.dbPath = dbPath || getDbPath();\n ensureDirectory(dirname(this.dbPath));\n }\n\n private async getDb(): Promise<SqlJsDatabase> {\n if (!this.db) {\n const SQL = await getSqlJs();\n\n if (existsSync(this.dbPath)) {\n const buffer = readFileSync(this.dbPath);\n this.db = new SQL.Database(buffer);\n } else {\n this.db = new SQL.Database();\n }\n }\n return this.db;\n }\n\n private save(): void {\n if (this.db) {\n const data = this.db.export();\n const buffer = Buffer.from(data);\n writeFileSync(this.dbPath, buffer);\n }\n }\n\n async initialize(): Promise<void> {\n if (this.initialized) return;\n\n const db = await this.getDb();\n\n const schema = `\n -- Command history\n CREATE TABLE IF NOT EXISTS commands (\n id TEXT PRIMARY KEY,\n timestamp DATETIME NOT NULL,\n command TEXT NOT NULL,\n normalized TEXT NOT NULL,\n variables TEXT,\n cwd TEXT NOT NULL,\n exit_code INTEGER,\n duration_ms INTEGER,\n session_id TEXT NOT NULL,\n project_id TEXT,\n created_at DATETIME DEFAULT CURRENT_TIMESTAMP\n );\n\n CREATE INDEX IF NOT EXISTS idx_commands_session ON commands(session_id);\n CREATE INDEX IF NOT EXISTS idx_commands_timestamp ON commands(timestamp);\n CREATE INDEX IF NOT EXISTS idx_commands_normalized ON commands(normalized);\n\n -- Terminal sessions\n CREATE TABLE IF NOT EXISTS sessions (\n id TEXT PRIMARY KEY,\n started_at DATETIME NOT NULL,\n ended_at DATETIME,\n shell TEXT NOT NULL,\n project_path TEXT,\n command_count INTEGER DEFAULT 0,\n created_at DATETIME DEFAULT CURRENT_TIMESTAMP\n );\n\n -- Conversations (Claude Code)\n CREATE TABLE IF NOT EXISTS conversations (\n id TEXT PRIMARY KEY,\n project_path TEXT,\n started_at DATETIME,\n updated_at DATETIME,\n message_count INTEGER DEFAULT 0,\n tool_calls TEXT,\n files_touched TEXT,\n intent_summary TEXT,\n created_at DATETIME DEFAULT CURRENT_TIMESTAMP\n );\n\n CREATE INDEX IF NOT EXISTS idx_conversations_project ON conversations(project_path);\n\n -- Detected patterns\n CREATE TABLE IF NOT EXISTS patterns (\n id TEXT PRIMARY KEY,\n source_type TEXT NOT NULL,\n description TEXT NOT NULL,\n count INTEGER DEFAULT 1,\n first_seen DATETIME NOT NULL,\n last_seen DATETIME NOT NULL,\n data TEXT NOT NULL,\n status TEXT DEFAULT 'active',\n created_at DATETIME DEFAULT CURRENT_TIMESTAMP,\n updated_at DATETIME DEFAULT CURRENT_TIMESTAMP\n );\n\n CREATE INDEX IF NOT EXISTS idx_patterns_status ON patterns(status);\n CREATE INDEX IF NOT EXISTS idx_patterns_count ON patterns(count);\n\n -- Generated skills\n CREATE TABLE IF NOT EXISTS skills (\n id TEXT PRIMARY KEY,\n name TEXT UNIQUE NOT NULL,\n path TEXT NOT NULL,\n source_patterns TEXT,\n source_type TEXT NOT NULL,\n trigger_phrase TEXT,\n created_at DATETIME DEFAULT CURRENT_TIMESTAMP,\n usage_count INTEGER DEFAULT 0,\n last_used_at DATETIME\n );\n\n CREATE INDEX IF NOT EXISTS idx_skills_name ON skills(name);\n\n -- Configuration\n CREATE TABLE IF NOT EXISTS config (\n key TEXT PRIMARY KEY,\n value TEXT NOT NULL,\n updated_at DATETIME DEFAULT CURRENT_TIMESTAMP\n );\n\n -- Ignored patterns\n CREATE TABLE IF NOT EXISTS ignored_patterns (\n pattern_hash TEXT PRIMARY KEY,\n reason TEXT,\n created_at DATETIME DEFAULT CURRENT_TIMESTAMP\n );\n\n -- Notifications\n CREATE TABLE IF NOT EXISTS notifications (\n id TEXT PRIMARY KEY,\n type TEXT NOT NULL,\n title TEXT NOT NULL,\n message TEXT,\n data TEXT,\n is_read INTEGER DEFAULT 0,\n created_at DATETIME DEFAULT CURRENT_TIMESTAMP\n );\n `;\n\n db.run(schema);\n this.save();\n this.initialized = true;\n }\n\n close(): void {\n if (this.db) {\n this.save();\n this.db.close();\n this.db = null;\n }\n }\n\n // Command operations\n async addCommand(params: {\n command: string;\n normalized: string;\n cwd: string;\n sessionId: string;\n exitCode?: number | null;\n durationMs?: number | null;\n variables?: Record<string, unknown> | null;\n projectId?: string | null;\n }): Promise<string> {\n const db = await this.getDb();\n const id = randomUUID();\n const timestamp = new Date().toISOString();\n\n db.run(\n `INSERT INTO commands (id, timestamp, command, normalized, variables, cwd, exit_code, duration_ms, session_id, project_id)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,\n [\n id,\n timestamp,\n params.command,\n params.normalized,\n params.variables ? JSON.stringify(params.variables) : null,\n params.cwd,\n params.exitCode ?? null,\n params.durationMs ?? null,\n params.sessionId,\n params.projectId ?? null,\n ]\n );\n\n this.save();\n return id;\n }\n\n async getRecentCommands(options?: {\n limit?: number;\n sessionId?: string;\n days?: number;\n }): Promise<Command[]> {\n const db = await this.getDb();\n const limit = options?.limit ?? 100;\n let query = \"SELECT * FROM commands\";\n const params: SqlValue[] = [];\n const conditions: string[] = [];\n\n if (options?.sessionId) {\n conditions.push(\"session_id = ?\");\n params.push(options.sessionId);\n }\n\n if (options?.days) {\n const cutoff = new Date();\n cutoff.setDate(cutoff.getDate() - options.days);\n conditions.push(\"timestamp >= ?\");\n params.push(cutoff.toISOString());\n }\n\n if (conditions.length > 0) {\n query += \" WHERE \" + conditions.join(\" AND \");\n }\n\n query += \" ORDER BY timestamp DESC LIMIT ?\";\n params.push(limit);\n\n const results = db.exec(query, params);\n if (results.length === 0) return [];\n\n return results[0].values.map((row) => this.mapCommand(results[0].columns, row as SqlValue[]));\n }\n\n // Session operations\n async createSession(shell: string, projectPath?: string | null): Promise<string> {\n const db = await this.getDb();\n const id = randomUUID();\n const startedAt = new Date().toISOString();\n\n db.run(\n `INSERT INTO sessions (id, started_at, shell, project_path) VALUES (?, ?, ?, ?)`,\n [id, startedAt, shell, projectPath ?? null]\n );\n\n this.save();\n return id;\n }\n\n async endSession(sessionId: string): Promise<void> {\n const db = await this.getDb();\n const endedAt = new Date().toISOString();\n\n db.run(\n `UPDATE sessions\n SET ended_at = ?, command_count = (SELECT COUNT(*) FROM commands WHERE session_id = ?)\n WHERE id = ?`,\n [endedAt, sessionId, sessionId]\n );\n\n this.save();\n }\n\n async getSession(sessionId: string): Promise<Session | null> {\n const db = await this.getDb();\n const results = db.exec(\"SELECT * FROM sessions WHERE id = ?\", [sessionId]);\n if (results.length === 0 || results[0].values.length === 0) return null;\n return this.mapSession(results[0].columns, results[0].values[0]);\n }\n\n // Pattern operations\n async addPattern(params: {\n sourceType: string;\n description: string;\n data: Record<string, unknown>;\n patternHash?: string;\n }): Promise<string> {\n const db = await this.getDb();\n const patternId = params.patternHash || randomUUID();\n const now = new Date().toISOString();\n\n // Check if pattern exists\n const existing = db.exec(\"SELECT id, count FROM patterns WHERE id = ?\", [patternId]);\n\n if (existing.length > 0 && existing[0].values.length > 0) {\n // Update count\n db.run(`UPDATE patterns SET count = count + 1, last_seen = ?, updated_at = ? WHERE id = ?`, [\n now,\n now,\n patternId,\n ]);\n } else {\n // Insert new\n db.run(\n `INSERT INTO patterns (id, source_type, description, data, first_seen, last_seen)\n VALUES (?, ?, ?, ?, ?, ?)`,\n [patternId, params.sourceType, params.description, JSON.stringify(params.data), now, now]\n );\n }\n\n this.save();\n return patternId;\n }\n\n async getPatterns(options?: {\n type?: string;\n status?: string;\n minCount?: number;\n limit?: number;\n }): Promise<Pattern[]> {\n const db = await this.getDb();\n const minCount = options?.minCount ?? 1;\n const limit = options?.limit ?? 50;\n\n let query = \"SELECT * FROM patterns WHERE count >= ?\";\n const params: SqlValue[] = [minCount];\n\n if (options?.type) {\n query += \" AND source_type = ?\";\n params.push(options.type);\n }\n\n if (options?.status) {\n query += \" AND status = ?\";\n params.push(options.status);\n }\n\n query += \" ORDER BY count DESC, last_seen DESC LIMIT ?\";\n params.push(limit);\n\n const results = db.exec(query, params);\n if (results.length === 0) return [];\n\n return results[0].values.map((row) => this.mapPattern(results[0].columns, row as SqlValue[]));\n }\n\n async getPattern(patternId: string): Promise<Pattern | null> {\n const db = await this.getDb();\n\n // Try exact match first\n let results = db.exec(\"SELECT * FROM patterns WHERE id = ?\", [patternId]);\n\n if (results.length === 0 || results[0].values.length === 0) {\n // Try partial match\n results = db.exec(\"SELECT * FROM patterns WHERE id LIKE ?\", [`${patternId}%`]);\n }\n\n if (results.length === 0 || results[0].values.length === 0) return null;\n return this.mapPattern(results[0].columns, results[0].values[0]);\n }\n\n async updatePatternStatus(patternId: string, status: string): Promise<void> {\n const db = await this.getDb();\n const now = new Date().toISOString();\n\n db.run(`UPDATE patterns SET status = ?, updated_at = ? WHERE id = ? OR id LIKE ?`, [\n status,\n now,\n patternId,\n `${patternId}%`,\n ]);\n\n this.save();\n }\n\n async addIgnoredPattern(patternHash: string, reason?: string | null): Promise<void> {\n const db = await this.getDb();\n\n db.run(`INSERT OR REPLACE INTO ignored_patterns (pattern_hash, reason) VALUES (?, ?)`, [\n patternHash,\n reason ?? null,\n ]);\n\n this.save();\n }\n\n async isPatternIgnored(patternHash: string): Promise<boolean> {\n const db = await this.getDb();\n const results = db.exec(\"SELECT 1 FROM ignored_patterns WHERE pattern_hash = ?\", [patternHash]);\n return results.length > 0 && results[0].values.length > 0;\n }\n\n // Skill operations\n async registerSkill(params: {\n name: string;\n path: string;\n sourceType: string;\n triggerPhrase?: string | null;\n sourcePatterns?: string[] | null;\n }): Promise<string> {\n const db = await this.getDb();\n const id = randomUUID();\n\n db.run(\n `INSERT INTO skills (id, name, path, source_patterns, source_type, trigger_phrase)\n VALUES (?, ?, ?, ?, ?, ?)`,\n [\n id,\n params.name,\n params.path,\n params.sourcePatterns ? JSON.stringify(params.sourcePatterns) : null,\n params.sourceType,\n params.triggerPhrase ?? null,\n ]\n );\n\n this.save();\n return id;\n }\n\n async getSkills(options?: {\n source?: string;\n sortBy?: \"name\" | \"created\" | \"usage\";\n }): Promise<Skill[]> {\n const db = await this.getDb();\n const sortMap = {\n name: \"name\",\n created: \"created_at\",\n usage: \"usage_count DESC\",\n };\n const order = sortMap[options?.sortBy ?? \"name\"];\n\n let query = \"SELECT * FROM skills\";\n const params: SqlValue[] = [];\n\n if (options?.source) {\n query += \" WHERE source_type = ?\";\n params.push(options.source);\n }\n\n query += ` ORDER BY ${order}`;\n\n const results = db.exec(query, params);\n if (results.length === 0) return [];\n\n return results[0].values.map((row) => this.mapSkill(results[0].columns, row as SqlValue[]));\n }\n\n async getSkill(name: string): Promise<Skill | null> {\n const db = await this.getDb();\n const results = db.exec(\"SELECT * FROM skills WHERE name = ?\", [name]);\n if (results.length === 0 || results[0].values.length === 0) return null;\n return this.mapSkill(results[0].columns, results[0].values[0]);\n }\n\n async deleteSkill(name: string): Promise<void> {\n const db = await this.getDb();\n db.run(\"DELETE FROM skills WHERE name = ?\", [name]);\n this.save();\n }\n\n async recordSkillUsage(name: string): Promise<void> {\n const db = await this.getDb();\n const now = new Date().toISOString();\n\n db.run(`UPDATE skills SET usage_count = usage_count + 1, last_used_at = ? WHERE name = ?`, [\n now,\n name,\n ]);\n\n this.save();\n }\n\n // Statistics\n async getStats(): Promise<Stats> {\n const db = await this.getDb();\n const today = new Date();\n today.setHours(0, 0, 0, 0);\n const todayIso = today.toISOString();\n\n const getCount = (query: string, params: SqlValue[] = []): number => {\n const results = db.exec(query, params);\n if (results.length === 0 || results[0].values.length === 0) return 0;\n return results[0].values[0][0] as number;\n };\n\n return {\n commandsToday: getCount(\"SELECT COUNT(*) FROM commands WHERE timestamp >= ?\", [todayIso]),\n commandsTotal: getCount(\"SELECT COUNT(*) FROM commands\"),\n patternsActive: getCount(\"SELECT COUNT(*) FROM patterns WHERE status = 'active'\"),\n skillsTotal: getCount(\"SELECT COUNT(*) FROM skills\"),\n conversationsTotal: getCount(\"SELECT COUNT(*) FROM conversations\"),\n };\n }\n\n // Mapping helpers\n private mapCommand(columns: string[], values: SqlValue[]): Command {\n const row = this.toObject(columns, values);\n return {\n id: row.id as string,\n timestamp: row.timestamp as string,\n command: row.command as string,\n normalized: row.normalized as string,\n variables: row.variables as string | null,\n cwd: row.cwd as string,\n exitCode: row.exit_code as number | null,\n durationMs: row.duration_ms as number | null,\n sessionId: row.session_id as string,\n projectId: row.project_id as string | null,\n createdAt: row.created_at as string,\n };\n }\n\n private mapSession(columns: string[], values: SqlValue[]): Session {\n const row = this.toObject(columns, values);\n return {\n id: row.id as string,\n startedAt: row.started_at as string,\n endedAt: row.ended_at as string | null,\n shell: row.shell as string,\n projectPath: row.project_path as string | null,\n commandCount: row.command_count as number,\n createdAt: row.created_at as string,\n };\n }\n\n private mapPattern(columns: string[], values: SqlValue[]): Pattern {\n const row = this.toObject(columns, values);\n return {\n id: row.id as string,\n sourceType: row.source_type as string,\n description: row.description as string,\n count: row.count as number,\n firstSeen: row.first_seen as string,\n lastSeen: row.last_seen as string,\n data: JSON.parse(row.data as string),\n status: row.status as string,\n createdAt: row.created_at as string,\n updatedAt: row.updated_at as string,\n };\n }\n\n private mapSkill(columns: string[], values: SqlValue[]): Skill {\n const row = this.toObject(columns, values);\n return {\n id: row.id as string,\n name: row.name as string,\n path: row.path as string,\n sourcePatterns: row.source_patterns as string | null,\n sourceType: row.source_type as string,\n triggerPhrase: row.trigger_phrase as string | null,\n createdAt: row.created_at as string,\n usageCount: row.usage_count as number,\n lastUsedAt: row.last_used_at as string | null,\n };\n }\n\n private toObject(columns: string[], values: SqlValue[]): Record<string, SqlValue> {\n const obj: Record<string, SqlValue> = {};\n columns.forEach((col, i) => {\n obj[col] = values[i];\n });\n return obj;\n }\n}\n"],"mappings":"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","names":["SQL"]}
|