skillo 0.2.1 → 0.2.3
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 +210 -568
- 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/dist/{tray-62I5KIFE.js → tray-RZQV6GDP.js} +28 -9
- package/dist/tray-RZQV6GDP.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/tray-62I5KIFE.js.map +0 -1
- /package/dist/{api-client-WO6NUCIJ.js.map → api-client-KUQW7FSC.js.map} +0 -0
package/dist/cli.js
CHANGED
|
@@ -1,12 +1,17 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
|
-
|
|
3
|
+
SkilloDatabase
|
|
4
|
+
} from "./chunk-2CVEPT6U.js";
|
|
5
|
+
import {
|
|
6
|
+
getApiClient
|
|
7
|
+
} from "./chunk-ODOZM4QV.js";
|
|
8
|
+
import {
|
|
4
9
|
getConfigValue,
|
|
5
10
|
getDefaultConfig,
|
|
6
11
|
loadConfig,
|
|
7
12
|
saveConfig,
|
|
8
13
|
setConfigValue
|
|
9
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-CPL3P2OF.js";
|
|
10
15
|
import {
|
|
11
16
|
ensureDirectory,
|
|
12
17
|
getActiveSessionsDir,
|
|
@@ -25,462 +30,9 @@ import {
|
|
|
25
30
|
import { Command as Command14 } from "commander";
|
|
26
31
|
|
|
27
32
|
// src/commands/init.ts
|
|
28
|
-
import { existsSync
|
|
33
|
+
import { existsSync } from "fs";
|
|
29
34
|
import { Command } from "commander";
|
|
30
35
|
|
|
31
|
-
// src/core/database.ts
|
|
32
|
-
import initSqlJs from "sql.js";
|
|
33
|
-
import { readFileSync, writeFileSync, existsSync } from "fs";
|
|
34
|
-
import { randomUUID } from "crypto";
|
|
35
|
-
import { dirname } from "path";
|
|
36
|
-
var SQL = null;
|
|
37
|
-
async function getSqlJs() {
|
|
38
|
-
if (!SQL) {
|
|
39
|
-
SQL = await initSqlJs();
|
|
40
|
-
}
|
|
41
|
-
return SQL;
|
|
42
|
-
}
|
|
43
|
-
var SkilloDatabase = class {
|
|
44
|
-
db = null;
|
|
45
|
-
dbPath;
|
|
46
|
-
initialized = false;
|
|
47
|
-
constructor(dbPath) {
|
|
48
|
-
this.dbPath = dbPath || getDbPath();
|
|
49
|
-
ensureDirectory(dirname(this.dbPath));
|
|
50
|
-
}
|
|
51
|
-
async getDb() {
|
|
52
|
-
if (!this.db) {
|
|
53
|
-
const SQL2 = await getSqlJs();
|
|
54
|
-
if (existsSync(this.dbPath)) {
|
|
55
|
-
const buffer = readFileSync(this.dbPath);
|
|
56
|
-
this.db = new SQL2.Database(buffer);
|
|
57
|
-
} else {
|
|
58
|
-
this.db = new SQL2.Database();
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
return this.db;
|
|
62
|
-
}
|
|
63
|
-
save() {
|
|
64
|
-
if (this.db) {
|
|
65
|
-
const data = this.db.export();
|
|
66
|
-
const buffer = Buffer.from(data);
|
|
67
|
-
writeFileSync(this.dbPath, buffer);
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
async initialize() {
|
|
71
|
-
if (this.initialized) return;
|
|
72
|
-
const db = await this.getDb();
|
|
73
|
-
const schema = `
|
|
74
|
-
-- Command history
|
|
75
|
-
CREATE TABLE IF NOT EXISTS commands (
|
|
76
|
-
id TEXT PRIMARY KEY,
|
|
77
|
-
timestamp DATETIME NOT NULL,
|
|
78
|
-
command TEXT NOT NULL,
|
|
79
|
-
normalized TEXT NOT NULL,
|
|
80
|
-
variables TEXT,
|
|
81
|
-
cwd TEXT NOT NULL,
|
|
82
|
-
exit_code INTEGER,
|
|
83
|
-
duration_ms INTEGER,
|
|
84
|
-
session_id TEXT NOT NULL,
|
|
85
|
-
project_id TEXT,
|
|
86
|
-
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
87
|
-
);
|
|
88
|
-
|
|
89
|
-
CREATE INDEX IF NOT EXISTS idx_commands_session ON commands(session_id);
|
|
90
|
-
CREATE INDEX IF NOT EXISTS idx_commands_timestamp ON commands(timestamp);
|
|
91
|
-
CREATE INDEX IF NOT EXISTS idx_commands_normalized ON commands(normalized);
|
|
92
|
-
|
|
93
|
-
-- Terminal sessions
|
|
94
|
-
CREATE TABLE IF NOT EXISTS sessions (
|
|
95
|
-
id TEXT PRIMARY KEY,
|
|
96
|
-
started_at DATETIME NOT NULL,
|
|
97
|
-
ended_at DATETIME,
|
|
98
|
-
shell TEXT NOT NULL,
|
|
99
|
-
project_path TEXT,
|
|
100
|
-
command_count INTEGER DEFAULT 0,
|
|
101
|
-
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
102
|
-
);
|
|
103
|
-
|
|
104
|
-
-- Conversations (Claude Code)
|
|
105
|
-
CREATE TABLE IF NOT EXISTS conversations (
|
|
106
|
-
id TEXT PRIMARY KEY,
|
|
107
|
-
project_path TEXT,
|
|
108
|
-
started_at DATETIME,
|
|
109
|
-
updated_at DATETIME,
|
|
110
|
-
message_count INTEGER DEFAULT 0,
|
|
111
|
-
tool_calls TEXT,
|
|
112
|
-
files_touched TEXT,
|
|
113
|
-
intent_summary TEXT,
|
|
114
|
-
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
115
|
-
);
|
|
116
|
-
|
|
117
|
-
CREATE INDEX IF NOT EXISTS idx_conversations_project ON conversations(project_path);
|
|
118
|
-
|
|
119
|
-
-- Detected patterns
|
|
120
|
-
CREATE TABLE IF NOT EXISTS patterns (
|
|
121
|
-
id TEXT PRIMARY KEY,
|
|
122
|
-
source_type TEXT NOT NULL,
|
|
123
|
-
description TEXT NOT NULL,
|
|
124
|
-
count INTEGER DEFAULT 1,
|
|
125
|
-
first_seen DATETIME NOT NULL,
|
|
126
|
-
last_seen DATETIME NOT NULL,
|
|
127
|
-
data TEXT NOT NULL,
|
|
128
|
-
status TEXT DEFAULT 'active',
|
|
129
|
-
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
130
|
-
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
131
|
-
);
|
|
132
|
-
|
|
133
|
-
CREATE INDEX IF NOT EXISTS idx_patterns_status ON patterns(status);
|
|
134
|
-
CREATE INDEX IF NOT EXISTS idx_patterns_count ON patterns(count);
|
|
135
|
-
|
|
136
|
-
-- Generated skills
|
|
137
|
-
CREATE TABLE IF NOT EXISTS skills (
|
|
138
|
-
id TEXT PRIMARY KEY,
|
|
139
|
-
name TEXT UNIQUE NOT NULL,
|
|
140
|
-
path TEXT NOT NULL,
|
|
141
|
-
source_patterns TEXT,
|
|
142
|
-
source_type TEXT NOT NULL,
|
|
143
|
-
trigger_phrase TEXT,
|
|
144
|
-
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
145
|
-
usage_count INTEGER DEFAULT 0,
|
|
146
|
-
last_used_at DATETIME
|
|
147
|
-
);
|
|
148
|
-
|
|
149
|
-
CREATE INDEX IF NOT EXISTS idx_skills_name ON skills(name);
|
|
150
|
-
|
|
151
|
-
-- Configuration
|
|
152
|
-
CREATE TABLE IF NOT EXISTS config (
|
|
153
|
-
key TEXT PRIMARY KEY,
|
|
154
|
-
value TEXT NOT NULL,
|
|
155
|
-
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
156
|
-
);
|
|
157
|
-
|
|
158
|
-
-- Ignored patterns
|
|
159
|
-
CREATE TABLE IF NOT EXISTS ignored_patterns (
|
|
160
|
-
pattern_hash TEXT PRIMARY KEY,
|
|
161
|
-
reason TEXT,
|
|
162
|
-
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
163
|
-
);
|
|
164
|
-
|
|
165
|
-
-- Notifications
|
|
166
|
-
CREATE TABLE IF NOT EXISTS notifications (
|
|
167
|
-
id TEXT PRIMARY KEY,
|
|
168
|
-
type TEXT NOT NULL,
|
|
169
|
-
title TEXT NOT NULL,
|
|
170
|
-
message TEXT,
|
|
171
|
-
data TEXT,
|
|
172
|
-
is_read INTEGER DEFAULT 0,
|
|
173
|
-
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
174
|
-
);
|
|
175
|
-
`;
|
|
176
|
-
db.run(schema);
|
|
177
|
-
this.save();
|
|
178
|
-
this.initialized = true;
|
|
179
|
-
}
|
|
180
|
-
close() {
|
|
181
|
-
if (this.db) {
|
|
182
|
-
this.save();
|
|
183
|
-
this.db.close();
|
|
184
|
-
this.db = null;
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
// Command operations
|
|
188
|
-
async addCommand(params) {
|
|
189
|
-
const db = await this.getDb();
|
|
190
|
-
const id = randomUUID();
|
|
191
|
-
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
192
|
-
db.run(
|
|
193
|
-
`INSERT INTO commands (id, timestamp, command, normalized, variables, cwd, exit_code, duration_ms, session_id, project_id)
|
|
194
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
195
|
-
[
|
|
196
|
-
id,
|
|
197
|
-
timestamp,
|
|
198
|
-
params.command,
|
|
199
|
-
params.normalized,
|
|
200
|
-
params.variables ? JSON.stringify(params.variables) : null,
|
|
201
|
-
params.cwd,
|
|
202
|
-
params.exitCode ?? null,
|
|
203
|
-
params.durationMs ?? null,
|
|
204
|
-
params.sessionId,
|
|
205
|
-
params.projectId ?? null
|
|
206
|
-
]
|
|
207
|
-
);
|
|
208
|
-
this.save();
|
|
209
|
-
return id;
|
|
210
|
-
}
|
|
211
|
-
async getRecentCommands(options) {
|
|
212
|
-
const db = await this.getDb();
|
|
213
|
-
const limit = options?.limit ?? 100;
|
|
214
|
-
let query = "SELECT * FROM commands";
|
|
215
|
-
const params = [];
|
|
216
|
-
const conditions = [];
|
|
217
|
-
if (options?.sessionId) {
|
|
218
|
-
conditions.push("session_id = ?");
|
|
219
|
-
params.push(options.sessionId);
|
|
220
|
-
}
|
|
221
|
-
if (options?.days) {
|
|
222
|
-
const cutoff = /* @__PURE__ */ new Date();
|
|
223
|
-
cutoff.setDate(cutoff.getDate() - options.days);
|
|
224
|
-
conditions.push("timestamp >= ?");
|
|
225
|
-
params.push(cutoff.toISOString());
|
|
226
|
-
}
|
|
227
|
-
if (conditions.length > 0) {
|
|
228
|
-
query += " WHERE " + conditions.join(" AND ");
|
|
229
|
-
}
|
|
230
|
-
query += " ORDER BY timestamp DESC LIMIT ?";
|
|
231
|
-
params.push(limit);
|
|
232
|
-
const results = db.exec(query, params);
|
|
233
|
-
if (results.length === 0) return [];
|
|
234
|
-
return results[0].values.map((row) => this.mapCommand(results[0].columns, row));
|
|
235
|
-
}
|
|
236
|
-
// Session operations
|
|
237
|
-
async createSession(shell, projectPath) {
|
|
238
|
-
const db = await this.getDb();
|
|
239
|
-
const id = randomUUID();
|
|
240
|
-
const startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
241
|
-
db.run(
|
|
242
|
-
`INSERT INTO sessions (id, started_at, shell, project_path) VALUES (?, ?, ?, ?)`,
|
|
243
|
-
[id, startedAt, shell, projectPath ?? null]
|
|
244
|
-
);
|
|
245
|
-
this.save();
|
|
246
|
-
return id;
|
|
247
|
-
}
|
|
248
|
-
async endSession(sessionId) {
|
|
249
|
-
const db = await this.getDb();
|
|
250
|
-
const endedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
251
|
-
db.run(
|
|
252
|
-
`UPDATE sessions
|
|
253
|
-
SET ended_at = ?, command_count = (SELECT COUNT(*) FROM commands WHERE session_id = ?)
|
|
254
|
-
WHERE id = ?`,
|
|
255
|
-
[endedAt, sessionId, sessionId]
|
|
256
|
-
);
|
|
257
|
-
this.save();
|
|
258
|
-
}
|
|
259
|
-
async getSession(sessionId) {
|
|
260
|
-
const db = await this.getDb();
|
|
261
|
-
const results = db.exec("SELECT * FROM sessions WHERE id = ?", [sessionId]);
|
|
262
|
-
if (results.length === 0 || results[0].values.length === 0) return null;
|
|
263
|
-
return this.mapSession(results[0].columns, results[0].values[0]);
|
|
264
|
-
}
|
|
265
|
-
// Pattern operations
|
|
266
|
-
async addPattern(params) {
|
|
267
|
-
const db = await this.getDb();
|
|
268
|
-
const patternId = params.patternHash || randomUUID();
|
|
269
|
-
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
270
|
-
const existing = db.exec("SELECT id, count FROM patterns WHERE id = ?", [patternId]);
|
|
271
|
-
if (existing.length > 0 && existing[0].values.length > 0) {
|
|
272
|
-
db.run(`UPDATE patterns SET count = count + 1, last_seen = ?, updated_at = ? WHERE id = ?`, [
|
|
273
|
-
now,
|
|
274
|
-
now,
|
|
275
|
-
patternId
|
|
276
|
-
]);
|
|
277
|
-
} else {
|
|
278
|
-
db.run(
|
|
279
|
-
`INSERT INTO patterns (id, source_type, description, data, first_seen, last_seen)
|
|
280
|
-
VALUES (?, ?, ?, ?, ?, ?)`,
|
|
281
|
-
[patternId, params.sourceType, params.description, JSON.stringify(params.data), now, now]
|
|
282
|
-
);
|
|
283
|
-
}
|
|
284
|
-
this.save();
|
|
285
|
-
return patternId;
|
|
286
|
-
}
|
|
287
|
-
async getPatterns(options) {
|
|
288
|
-
const db = await this.getDb();
|
|
289
|
-
const minCount = options?.minCount ?? 1;
|
|
290
|
-
const limit = options?.limit ?? 50;
|
|
291
|
-
let query = "SELECT * FROM patterns WHERE count >= ?";
|
|
292
|
-
const params = [minCount];
|
|
293
|
-
if (options?.type) {
|
|
294
|
-
query += " AND source_type = ?";
|
|
295
|
-
params.push(options.type);
|
|
296
|
-
}
|
|
297
|
-
if (options?.status) {
|
|
298
|
-
query += " AND status = ?";
|
|
299
|
-
params.push(options.status);
|
|
300
|
-
}
|
|
301
|
-
query += " ORDER BY count DESC, last_seen DESC LIMIT ?";
|
|
302
|
-
params.push(limit);
|
|
303
|
-
const results = db.exec(query, params);
|
|
304
|
-
if (results.length === 0) return [];
|
|
305
|
-
return results[0].values.map((row) => this.mapPattern(results[0].columns, row));
|
|
306
|
-
}
|
|
307
|
-
async getPattern(patternId) {
|
|
308
|
-
const db = await this.getDb();
|
|
309
|
-
let results = db.exec("SELECT * FROM patterns WHERE id = ?", [patternId]);
|
|
310
|
-
if (results.length === 0 || results[0].values.length === 0) {
|
|
311
|
-
results = db.exec("SELECT * FROM patterns WHERE id LIKE ?", [`${patternId}%`]);
|
|
312
|
-
}
|
|
313
|
-
if (results.length === 0 || results[0].values.length === 0) return null;
|
|
314
|
-
return this.mapPattern(results[0].columns, results[0].values[0]);
|
|
315
|
-
}
|
|
316
|
-
async updatePatternStatus(patternId, status) {
|
|
317
|
-
const db = await this.getDb();
|
|
318
|
-
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
319
|
-
db.run(`UPDATE patterns SET status = ?, updated_at = ? WHERE id = ? OR id LIKE ?`, [
|
|
320
|
-
status,
|
|
321
|
-
now,
|
|
322
|
-
patternId,
|
|
323
|
-
`${patternId}%`
|
|
324
|
-
]);
|
|
325
|
-
this.save();
|
|
326
|
-
}
|
|
327
|
-
async addIgnoredPattern(patternHash, reason) {
|
|
328
|
-
const db = await this.getDb();
|
|
329
|
-
db.run(`INSERT OR REPLACE INTO ignored_patterns (pattern_hash, reason) VALUES (?, ?)`, [
|
|
330
|
-
patternHash,
|
|
331
|
-
reason ?? null
|
|
332
|
-
]);
|
|
333
|
-
this.save();
|
|
334
|
-
}
|
|
335
|
-
async isPatternIgnored(patternHash) {
|
|
336
|
-
const db = await this.getDb();
|
|
337
|
-
const results = db.exec("SELECT 1 FROM ignored_patterns WHERE pattern_hash = ?", [patternHash]);
|
|
338
|
-
return results.length > 0 && results[0].values.length > 0;
|
|
339
|
-
}
|
|
340
|
-
// Skill operations
|
|
341
|
-
async registerSkill(params) {
|
|
342
|
-
const db = await this.getDb();
|
|
343
|
-
const id = randomUUID();
|
|
344
|
-
db.run(
|
|
345
|
-
`INSERT INTO skills (id, name, path, source_patterns, source_type, trigger_phrase)
|
|
346
|
-
VALUES (?, ?, ?, ?, ?, ?)`,
|
|
347
|
-
[
|
|
348
|
-
id,
|
|
349
|
-
params.name,
|
|
350
|
-
params.path,
|
|
351
|
-
params.sourcePatterns ? JSON.stringify(params.sourcePatterns) : null,
|
|
352
|
-
params.sourceType,
|
|
353
|
-
params.triggerPhrase ?? null
|
|
354
|
-
]
|
|
355
|
-
);
|
|
356
|
-
this.save();
|
|
357
|
-
return id;
|
|
358
|
-
}
|
|
359
|
-
async getSkills(options) {
|
|
360
|
-
const db = await this.getDb();
|
|
361
|
-
const sortMap = {
|
|
362
|
-
name: "name",
|
|
363
|
-
created: "created_at",
|
|
364
|
-
usage: "usage_count DESC"
|
|
365
|
-
};
|
|
366
|
-
const order = sortMap[options?.sortBy ?? "name"];
|
|
367
|
-
let query = "SELECT * FROM skills";
|
|
368
|
-
const params = [];
|
|
369
|
-
if (options?.source) {
|
|
370
|
-
query += " WHERE source_type = ?";
|
|
371
|
-
params.push(options.source);
|
|
372
|
-
}
|
|
373
|
-
query += ` ORDER BY ${order}`;
|
|
374
|
-
const results = db.exec(query, params);
|
|
375
|
-
if (results.length === 0) return [];
|
|
376
|
-
return results[0].values.map((row) => this.mapSkill(results[0].columns, row));
|
|
377
|
-
}
|
|
378
|
-
async getSkill(name) {
|
|
379
|
-
const db = await this.getDb();
|
|
380
|
-
const results = db.exec("SELECT * FROM skills WHERE name = ?", [name]);
|
|
381
|
-
if (results.length === 0 || results[0].values.length === 0) return null;
|
|
382
|
-
return this.mapSkill(results[0].columns, results[0].values[0]);
|
|
383
|
-
}
|
|
384
|
-
async deleteSkill(name) {
|
|
385
|
-
const db = await this.getDb();
|
|
386
|
-
db.run("DELETE FROM skills WHERE name = ?", [name]);
|
|
387
|
-
this.save();
|
|
388
|
-
}
|
|
389
|
-
async recordSkillUsage(name) {
|
|
390
|
-
const db = await this.getDb();
|
|
391
|
-
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
392
|
-
db.run(`UPDATE skills SET usage_count = usage_count + 1, last_used_at = ? WHERE name = ?`, [
|
|
393
|
-
now,
|
|
394
|
-
name
|
|
395
|
-
]);
|
|
396
|
-
this.save();
|
|
397
|
-
}
|
|
398
|
-
// Statistics
|
|
399
|
-
async getStats() {
|
|
400
|
-
const db = await this.getDb();
|
|
401
|
-
const today = /* @__PURE__ */ new Date();
|
|
402
|
-
today.setHours(0, 0, 0, 0);
|
|
403
|
-
const todayIso = today.toISOString();
|
|
404
|
-
const getCount = (query, params = []) => {
|
|
405
|
-
const results = db.exec(query, params);
|
|
406
|
-
if (results.length === 0 || results[0].values.length === 0) return 0;
|
|
407
|
-
return results[0].values[0][0];
|
|
408
|
-
};
|
|
409
|
-
return {
|
|
410
|
-
commandsToday: getCount("SELECT COUNT(*) FROM commands WHERE timestamp >= ?", [todayIso]),
|
|
411
|
-
commandsTotal: getCount("SELECT COUNT(*) FROM commands"),
|
|
412
|
-
patternsActive: getCount("SELECT COUNT(*) FROM patterns WHERE status = 'active'"),
|
|
413
|
-
skillsTotal: getCount("SELECT COUNT(*) FROM skills"),
|
|
414
|
-
conversationsTotal: getCount("SELECT COUNT(*) FROM conversations")
|
|
415
|
-
};
|
|
416
|
-
}
|
|
417
|
-
// Mapping helpers
|
|
418
|
-
mapCommand(columns, values) {
|
|
419
|
-
const row = this.toObject(columns, values);
|
|
420
|
-
return {
|
|
421
|
-
id: row.id,
|
|
422
|
-
timestamp: row.timestamp,
|
|
423
|
-
command: row.command,
|
|
424
|
-
normalized: row.normalized,
|
|
425
|
-
variables: row.variables,
|
|
426
|
-
cwd: row.cwd,
|
|
427
|
-
exitCode: row.exit_code,
|
|
428
|
-
durationMs: row.duration_ms,
|
|
429
|
-
sessionId: row.session_id,
|
|
430
|
-
projectId: row.project_id,
|
|
431
|
-
createdAt: row.created_at
|
|
432
|
-
};
|
|
433
|
-
}
|
|
434
|
-
mapSession(columns, values) {
|
|
435
|
-
const row = this.toObject(columns, values);
|
|
436
|
-
return {
|
|
437
|
-
id: row.id,
|
|
438
|
-
startedAt: row.started_at,
|
|
439
|
-
endedAt: row.ended_at,
|
|
440
|
-
shell: row.shell,
|
|
441
|
-
projectPath: row.project_path,
|
|
442
|
-
commandCount: row.command_count,
|
|
443
|
-
createdAt: row.created_at
|
|
444
|
-
};
|
|
445
|
-
}
|
|
446
|
-
mapPattern(columns, values) {
|
|
447
|
-
const row = this.toObject(columns, values);
|
|
448
|
-
return {
|
|
449
|
-
id: row.id,
|
|
450
|
-
sourceType: row.source_type,
|
|
451
|
-
description: row.description,
|
|
452
|
-
count: row.count,
|
|
453
|
-
firstSeen: row.first_seen,
|
|
454
|
-
lastSeen: row.last_seen,
|
|
455
|
-
data: JSON.parse(row.data),
|
|
456
|
-
status: row.status,
|
|
457
|
-
createdAt: row.created_at,
|
|
458
|
-
updatedAt: row.updated_at
|
|
459
|
-
};
|
|
460
|
-
}
|
|
461
|
-
mapSkill(columns, values) {
|
|
462
|
-
const row = this.toObject(columns, values);
|
|
463
|
-
return {
|
|
464
|
-
id: row.id,
|
|
465
|
-
name: row.name,
|
|
466
|
-
path: row.path,
|
|
467
|
-
sourcePatterns: row.source_patterns,
|
|
468
|
-
sourceType: row.source_type,
|
|
469
|
-
triggerPhrase: row.trigger_phrase,
|
|
470
|
-
createdAt: row.created_at,
|
|
471
|
-
usageCount: row.usage_count,
|
|
472
|
-
lastUsedAt: row.last_used_at
|
|
473
|
-
};
|
|
474
|
-
}
|
|
475
|
-
toObject(columns, values) {
|
|
476
|
-
const obj = {};
|
|
477
|
-
columns.forEach((col, i) => {
|
|
478
|
-
obj[col] = values[i];
|
|
479
|
-
});
|
|
480
|
-
return obj;
|
|
481
|
-
}
|
|
482
|
-
};
|
|
483
|
-
|
|
484
36
|
// src/utils/logger.ts
|
|
485
37
|
import chalk from "chalk";
|
|
486
38
|
var logger = {
|
|
@@ -552,7 +104,7 @@ var initCommand = new Command("init").description("Initialize Skillo configurati
|
|
|
552
104
|
const configDir = getConfigDir();
|
|
553
105
|
const skillsDir = getSkillsDir();
|
|
554
106
|
const configFile = getConfigFile();
|
|
555
|
-
if (
|
|
107
|
+
if (existsSync(configFile) && !options.force) {
|
|
556
108
|
logger_default.warn("Skillo is already initialized.");
|
|
557
109
|
logger_default.dim("Use --force to reinitialize and overwrite configuration.");
|
|
558
110
|
return;
|
|
@@ -593,11 +145,11 @@ var initCommand = new Command("init").description("Initialize Skillo configurati
|
|
|
593
145
|
});
|
|
594
146
|
|
|
595
147
|
// src/commands/status.ts
|
|
596
|
-
import { existsSync as
|
|
148
|
+
import { existsSync as existsSync3, readFileSync as readFileSync2 } from "fs";
|
|
597
149
|
import { Command as Command2 } from "commander";
|
|
598
150
|
|
|
599
151
|
// src/utils/os-service.ts
|
|
600
|
-
import { existsSync as
|
|
152
|
+
import { existsSync as existsSync2, writeFileSync, unlinkSync, mkdirSync, readdirSync } from "fs";
|
|
601
153
|
import { join } from "path";
|
|
602
154
|
import { homedir, platform } from "os";
|
|
603
155
|
import { execSync } from "child_process";
|
|
@@ -647,7 +199,7 @@ function findSkilloBin() {
|
|
|
647
199
|
join(homedir(), "AppData", "Local", "fnm_multishells")
|
|
648
200
|
];
|
|
649
201
|
for (const c of candidates) {
|
|
650
|
-
if (
|
|
202
|
+
if (existsSync2(c)) return c;
|
|
651
203
|
}
|
|
652
204
|
} else {
|
|
653
205
|
const candidates = [
|
|
@@ -655,7 +207,7 @@ function findSkilloBin() {
|
|
|
655
207
|
"/usr/bin/skillo"
|
|
656
208
|
];
|
|
657
209
|
for (const c of candidates) {
|
|
658
|
-
if (
|
|
210
|
+
if (existsSync2(c)) return c;
|
|
659
211
|
}
|
|
660
212
|
}
|
|
661
213
|
return "skillo";
|
|
@@ -673,15 +225,15 @@ function buildPath() {
|
|
|
673
225
|
const nvmSymlink = process.env.NVM_SYMLINK;
|
|
674
226
|
if (nvmSymlink) paths.add(nvmSymlink);
|
|
675
227
|
const fnmDir = join(home, ".fnm");
|
|
676
|
-
if (
|
|
228
|
+
if (existsSync2(fnmDir)) paths.add(fnmDir);
|
|
677
229
|
} else {
|
|
678
230
|
const nvmDir = process.env.NVM_DIR || join(home, ".nvm");
|
|
679
|
-
if (
|
|
231
|
+
if (existsSync2(nvmDir)) {
|
|
680
232
|
try {
|
|
681
233
|
const defaultAlias = join(nvmDir, "alias", "default");
|
|
682
|
-
if (
|
|
234
|
+
if (existsSync2(defaultAlias)) {
|
|
683
235
|
const versionsDir = join(nvmDir, "versions", "node");
|
|
684
|
-
if (
|
|
236
|
+
if (existsSync2(versionsDir)) {
|
|
685
237
|
const versions = readdirSync(versionsDir);
|
|
686
238
|
for (const v of versions) {
|
|
687
239
|
paths.add(join(versionsDir, v, "bin"));
|
|
@@ -848,9 +400,9 @@ async function installService(options) {
|
|
|
848
400
|
try {
|
|
849
401
|
if (os2 === "darwin") {
|
|
850
402
|
const agentsDir = getLaunchAgentsDir();
|
|
851
|
-
if (!
|
|
403
|
+
if (!existsSync2(agentsDir)) mkdirSync(agentsDir, { recursive: true });
|
|
852
404
|
const daemonPlist = getDaemonPlistPath();
|
|
853
|
-
|
|
405
|
+
writeFileSync(daemonPlist, generateDaemonPlist(skilloBin, envPath), "utf-8");
|
|
854
406
|
try {
|
|
855
407
|
execSync(`launchctl unload "${daemonPlist}" 2>/dev/null`);
|
|
856
408
|
} catch {
|
|
@@ -858,7 +410,7 @@ async function installService(options) {
|
|
|
858
410
|
execSync(`launchctl load "${daemonPlist}"`);
|
|
859
411
|
if (includeTray) {
|
|
860
412
|
const trayPlist = getTrayPlistPath();
|
|
861
|
-
|
|
413
|
+
writeFileSync(trayPlist, generateTrayPlist(skilloBin, envPath), "utf-8");
|
|
862
414
|
try {
|
|
863
415
|
execSync(`launchctl unload "${trayPlist}" 2>/dev/null`);
|
|
864
416
|
} catch {
|
|
@@ -868,13 +420,13 @@ async function installService(options) {
|
|
|
868
420
|
return { success: true };
|
|
869
421
|
} else if (os2 === "linux") {
|
|
870
422
|
const systemdDir = getSystemdUserDir();
|
|
871
|
-
if (!
|
|
872
|
-
|
|
423
|
+
if (!existsSync2(systemdDir)) mkdirSync(systemdDir, { recursive: true });
|
|
424
|
+
writeFileSync(getDaemonServicePath(), generateDaemonUnit(skilloBin, envPath), "utf-8");
|
|
873
425
|
execSync("systemctl --user daemon-reload");
|
|
874
426
|
execSync("systemctl --user enable skillo-daemon.service");
|
|
875
427
|
execSync("systemctl --user start skillo-daemon.service");
|
|
876
428
|
if (includeTray) {
|
|
877
|
-
|
|
429
|
+
writeFileSync(getTrayServicePath(), generateTrayUnit(skilloBin, envPath), "utf-8");
|
|
878
430
|
execSync("systemctl --user daemon-reload");
|
|
879
431
|
execSync("systemctl --user enable skillo-tray.service");
|
|
880
432
|
try {
|
|
@@ -885,9 +437,9 @@ async function installService(options) {
|
|
|
885
437
|
return { success: true };
|
|
886
438
|
} else if (os2 === "win32") {
|
|
887
439
|
const dataDir = getSkilloDataDir();
|
|
888
|
-
if (!
|
|
440
|
+
if (!existsSync2(dataDir)) mkdirSync(dataDir, { recursive: true });
|
|
889
441
|
const vbsPath = getWinDaemonVbsPath();
|
|
890
|
-
|
|
442
|
+
writeFileSync(vbsPath, generateDaemonVbs(skilloBin), "utf-8");
|
|
891
443
|
winRegAdd(WIN_DAEMON_VALUE, `wscript.exe "${vbsPath}"`);
|
|
892
444
|
if (includeTray) {
|
|
893
445
|
winRegAdd(WIN_TRAY_VALUE, `"${skilloBin}" tray`);
|
|
@@ -905,7 +457,7 @@ async function uninstallService() {
|
|
|
905
457
|
try {
|
|
906
458
|
if (os2 === "darwin") {
|
|
907
459
|
const daemonPlist = getDaemonPlistPath();
|
|
908
|
-
if (
|
|
460
|
+
if (existsSync2(daemonPlist)) {
|
|
909
461
|
try {
|
|
910
462
|
execSync(`launchctl unload "${daemonPlist}" 2>/dev/null`);
|
|
911
463
|
} catch {
|
|
@@ -913,7 +465,7 @@ async function uninstallService() {
|
|
|
913
465
|
unlinkSync(daemonPlist);
|
|
914
466
|
}
|
|
915
467
|
const trayPlist = getTrayPlistPath();
|
|
916
|
-
if (
|
|
468
|
+
if (existsSync2(trayPlist)) {
|
|
917
469
|
try {
|
|
918
470
|
execSync(`launchctl unload "${trayPlist}" 2>/dev/null`);
|
|
919
471
|
} catch {
|
|
@@ -923,7 +475,7 @@ async function uninstallService() {
|
|
|
923
475
|
return { success: true };
|
|
924
476
|
} else if (os2 === "linux") {
|
|
925
477
|
const daemonService = getDaemonServicePath();
|
|
926
|
-
if (
|
|
478
|
+
if (existsSync2(daemonService)) {
|
|
927
479
|
try {
|
|
928
480
|
execSync("systemctl --user stop skillo-daemon.service 2>/dev/null");
|
|
929
481
|
} catch {
|
|
@@ -935,7 +487,7 @@ async function uninstallService() {
|
|
|
935
487
|
unlinkSync(daemonService);
|
|
936
488
|
}
|
|
937
489
|
const trayService = getTrayServicePath();
|
|
938
|
-
if (
|
|
490
|
+
if (existsSync2(trayService)) {
|
|
939
491
|
try {
|
|
940
492
|
execSync("systemctl --user stop skillo-tray.service 2>/dev/null");
|
|
941
493
|
} catch {
|
|
@@ -955,7 +507,7 @@ async function uninstallService() {
|
|
|
955
507
|
winRegDelete(WIN_DAEMON_VALUE);
|
|
956
508
|
winRegDelete(WIN_TRAY_VALUE);
|
|
957
509
|
const vbsPath = getWinDaemonVbsPath();
|
|
958
|
-
if (
|
|
510
|
+
if (existsSync2(vbsPath)) {
|
|
959
511
|
try {
|
|
960
512
|
unlinkSync(vbsPath);
|
|
961
513
|
} catch {
|
|
@@ -972,8 +524,8 @@ async function uninstallService() {
|
|
|
972
524
|
function getServiceStatus() {
|
|
973
525
|
const os2 = platform();
|
|
974
526
|
if (os2 === "darwin") {
|
|
975
|
-
const daemonInstalled =
|
|
976
|
-
const trayInstalled =
|
|
527
|
+
const daemonInstalled = existsSync2(getDaemonPlistPath());
|
|
528
|
+
const trayInstalled = existsSync2(getTrayPlistPath());
|
|
977
529
|
let daemonLoaded = false;
|
|
978
530
|
let trayLoaded = false;
|
|
979
531
|
try {
|
|
@@ -988,8 +540,8 @@ function getServiceStatus() {
|
|
|
988
540
|
tray: { installed: trayInstalled, loaded: trayLoaded }
|
|
989
541
|
};
|
|
990
542
|
} else if (os2 === "linux") {
|
|
991
|
-
const daemonInstalled =
|
|
992
|
-
const trayInstalled =
|
|
543
|
+
const daemonInstalled = existsSync2(getDaemonServicePath());
|
|
544
|
+
const trayInstalled = existsSync2(getTrayServicePath());
|
|
993
545
|
let daemonLoaded = false;
|
|
994
546
|
let trayLoaded = false;
|
|
995
547
|
try {
|
|
@@ -1026,11 +578,11 @@ function getServiceStatus() {
|
|
|
1026
578
|
// src/commands/status.ts
|
|
1027
579
|
function isDaemonRunning() {
|
|
1028
580
|
const pidFile = getPidFile();
|
|
1029
|
-
if (!
|
|
581
|
+
if (!existsSync3(pidFile)) {
|
|
1030
582
|
return { running: false, pid: null };
|
|
1031
583
|
}
|
|
1032
584
|
try {
|
|
1033
|
-
const pidStr =
|
|
585
|
+
const pidStr = readFileSync2(pidFile, "utf-8").trim();
|
|
1034
586
|
const pid = parseInt(pidStr, 10);
|
|
1035
587
|
if (isNaN(pid)) {
|
|
1036
588
|
return { running: false, pid: null };
|
|
@@ -1065,7 +617,7 @@ var statusCommand = new Command2("status").description("Show daemon status and s
|
|
|
1065
617
|
if (!running) return;
|
|
1066
618
|
logger_default.blank();
|
|
1067
619
|
const dbPath = getDbPath();
|
|
1068
|
-
if (!
|
|
620
|
+
if (!existsSync3(dbPath)) {
|
|
1069
621
|
logger_default.warn("Database not found. Run 'skillo init' first.");
|
|
1070
622
|
return;
|
|
1071
623
|
}
|
|
@@ -1082,10 +634,10 @@ var statusCommand = new Command2("status").description("Show daemon status and s
|
|
|
1082
634
|
]);
|
|
1083
635
|
logger_default.blank();
|
|
1084
636
|
const logFile = getLogFile();
|
|
1085
|
-
if (
|
|
637
|
+
if (existsSync3(logFile)) {
|
|
1086
638
|
logger_default.dim("Recent log entries:");
|
|
1087
639
|
try {
|
|
1088
|
-
const content =
|
|
640
|
+
const content = readFileSync2(logFile, "utf-8");
|
|
1089
641
|
const lines = content.split("\n").filter(Boolean).slice(-5);
|
|
1090
642
|
lines.forEach((line) => {
|
|
1091
643
|
logger_default.dim(` ${line}`);
|
|
@@ -1097,7 +649,7 @@ var statusCommand = new Command2("status").description("Show daemon status and s
|
|
|
1097
649
|
});
|
|
1098
650
|
|
|
1099
651
|
// src/commands/config.ts
|
|
1100
|
-
import { existsSync as
|
|
652
|
+
import { existsSync as existsSync4, readFileSync as readFileSync3 } from "fs";
|
|
1101
653
|
import { Command as Command3 } from "commander";
|
|
1102
654
|
import YAML from "yaml";
|
|
1103
655
|
var configCommand = new Command3("config").description(
|
|
@@ -1105,12 +657,12 @@ var configCommand = new Command3("config").description(
|
|
|
1105
657
|
);
|
|
1106
658
|
configCommand.command("show").description("Show current configuration").action(async () => {
|
|
1107
659
|
const configFile = getConfigFile();
|
|
1108
|
-
if (!
|
|
660
|
+
if (!existsSync4(configFile)) {
|
|
1109
661
|
logger_default.error("Configuration not found.");
|
|
1110
662
|
logger_default.dim("Run 'skillo init' first.");
|
|
1111
663
|
process.exit(1);
|
|
1112
664
|
}
|
|
1113
|
-
const content =
|
|
665
|
+
const content = readFileSync3(configFile, "utf-8");
|
|
1114
666
|
logger_default.blank();
|
|
1115
667
|
logger_default.bold(`Configuration file: ${configFile}`);
|
|
1116
668
|
logger_default.blank();
|
|
@@ -1118,7 +670,7 @@ configCommand.command("show").description("Show current configuration").action(a
|
|
|
1118
670
|
});
|
|
1119
671
|
configCommand.command("get <key>").description("Get a configuration value (use dot notation, e.g., patternDetection.minCount)").action(async (key) => {
|
|
1120
672
|
const configFile = getConfigFile();
|
|
1121
|
-
if (!
|
|
673
|
+
if (!existsSync4(configFile)) {
|
|
1122
674
|
logger_default.error("Configuration not found.");
|
|
1123
675
|
process.exit(1);
|
|
1124
676
|
}
|
|
@@ -1136,7 +688,7 @@ configCommand.command("get <key>").description("Get a configuration value (use d
|
|
|
1136
688
|
});
|
|
1137
689
|
configCommand.command("set <key> <value>").description("Set a configuration value").action(async (key, value) => {
|
|
1138
690
|
const configFile = getConfigFile();
|
|
1139
|
-
if (!
|
|
691
|
+
if (!existsSync4(configFile)) {
|
|
1140
692
|
logger_default.error("Configuration not found.");
|
|
1141
693
|
process.exit(1);
|
|
1142
694
|
}
|
|
@@ -1178,7 +730,7 @@ configCommand.command("path").description("Show configuration file path").action
|
|
|
1178
730
|
});
|
|
1179
731
|
|
|
1180
732
|
// src/commands/patterns.ts
|
|
1181
|
-
import { existsSync as
|
|
733
|
+
import { existsSync as existsSync5 } from "fs";
|
|
1182
734
|
import { Command as Command4 } from "commander";
|
|
1183
735
|
import chalk2 from "chalk";
|
|
1184
736
|
var patternsCommand = new Command4("patterns").description(
|
|
@@ -1186,7 +738,7 @@ var patternsCommand = new Command4("patterns").description(
|
|
|
1186
738
|
);
|
|
1187
739
|
patternsCommand.command("list").description("List detected patterns").option("-t, --type <type>", "Filter by type (terminal, conversation)").option("-s, --status <status>", "Filter by status (active, converted, ignored)").option("-n, --limit <number>", "Number of patterns to show", "20").action(async (options) => {
|
|
1188
740
|
const dbPath = getDbPath();
|
|
1189
|
-
if (!
|
|
741
|
+
if (!existsSync5(dbPath)) {
|
|
1190
742
|
logger_default.error("Database not found. Run 'skillo init' first.");
|
|
1191
743
|
process.exit(1);
|
|
1192
744
|
}
|
|
@@ -1223,7 +775,7 @@ patternsCommand.command("list").description("List detected patterns").option("-t
|
|
|
1223
775
|
});
|
|
1224
776
|
patternsCommand.command("show <id>").description("Show pattern details").action(async (id) => {
|
|
1225
777
|
const dbPath = getDbPath();
|
|
1226
|
-
if (!
|
|
778
|
+
if (!existsSync5(dbPath)) {
|
|
1227
779
|
logger_default.error("Database not found. Run 'skillo init' first.");
|
|
1228
780
|
process.exit(1);
|
|
1229
781
|
}
|
|
@@ -1266,7 +818,7 @@ patternsCommand.command("show <id>").description("Show pattern details").action(
|
|
|
1266
818
|
});
|
|
1267
819
|
patternsCommand.command("ignore <id>").description("Ignore a pattern (never suggest again)").option("-r, --reason <reason>", "Reason for ignoring").action(async (id, options) => {
|
|
1268
820
|
const dbPath = getDbPath();
|
|
1269
|
-
if (!
|
|
821
|
+
if (!existsSync5(dbPath)) {
|
|
1270
822
|
logger_default.error("Database not found. Run 'skillo init' first.");
|
|
1271
823
|
process.exit(1);
|
|
1272
824
|
}
|
|
@@ -1287,12 +839,12 @@ patternsCommand.command("ignore <id>").description("Ignore a pattern (never sugg
|
|
|
1287
839
|
}
|
|
1288
840
|
});
|
|
1289
841
|
patternsCommand.command("generate <id>").description("Generate a skill from a pattern").option("-n, --name <name>", "Custom skill name").option("--dry-run", "Preview without creating").action(async (id, options) => {
|
|
1290
|
-
const { getApiClient: getApiClient2 } = await import("./api-client-
|
|
1291
|
-
const { writeFileSync:
|
|
842
|
+
const { getApiClient: getApiClient2 } = await import("./api-client-KUQW7FSC.js");
|
|
843
|
+
const { writeFileSync: writeFileSync7, mkdirSync: mkdirSync3 } = await import("fs");
|
|
1292
844
|
const { join: join7 } = await import("path");
|
|
1293
845
|
const { getSkillsDir: getSkillsDir2, ensureDirectory: ensureDirectory2 } = await import("./paths-INOKEM66.js");
|
|
1294
846
|
const dbPath = getDbPath();
|
|
1295
|
-
if (!
|
|
847
|
+
if (!existsSync5(dbPath)) {
|
|
1296
848
|
logger_default.error("Database not found. Run 'skillo init' first.");
|
|
1297
849
|
process.exit(1);
|
|
1298
850
|
}
|
|
@@ -1346,7 +898,7 @@ patternsCommand.command("generate <id>").description("Generate a skill from a pa
|
|
|
1346
898
|
const skillDir = join7(skillsDir, skill.slug);
|
|
1347
899
|
const skillFile = join7(skillDir, "SKILL.md");
|
|
1348
900
|
mkdirSync3(skillDir, { recursive: true });
|
|
1349
|
-
|
|
901
|
+
writeFileSync7(skillFile, skill.content, "utf-8");
|
|
1350
902
|
await db.updatePatternStatus(id, "converted");
|
|
1351
903
|
logger_default.success(`Skill saved to: ~/.claude/skills/${skill.slug}/SKILL.md`);
|
|
1352
904
|
logger_default.blank();
|
|
@@ -1361,7 +913,7 @@ patternsCommand.command("clear").description("Clear all patterns").option("-f, -
|
|
|
1361
913
|
return;
|
|
1362
914
|
}
|
|
1363
915
|
const dbPath = getDbPath();
|
|
1364
|
-
if (!
|
|
916
|
+
if (!existsSync5(dbPath)) {
|
|
1365
917
|
logger_default.error("Database not found.");
|
|
1366
918
|
process.exit(1);
|
|
1367
919
|
}
|
|
@@ -1369,7 +921,7 @@ patternsCommand.command("clear").description("Clear all patterns").option("-f, -
|
|
|
1369
921
|
});
|
|
1370
922
|
|
|
1371
923
|
// src/commands/skills.ts
|
|
1372
|
-
import { existsSync as
|
|
924
|
+
import { existsSync as existsSync6, readdirSync as readdirSync2, rmSync } from "fs";
|
|
1373
925
|
import { join as join2 } from "path";
|
|
1374
926
|
import { Command as Command5 } from "commander";
|
|
1375
927
|
import chalk3 from "chalk";
|
|
@@ -1378,7 +930,7 @@ var skillsCommand = new Command5("skills").description(
|
|
|
1378
930
|
);
|
|
1379
931
|
skillsCommand.command("list").description("List all skills").option("-s, --source <source>", "Filter by source (pattern, imported, manual)").option("--sort <by>", "Sort by (name, created, usage)", "name").action(async (options) => {
|
|
1380
932
|
const dbPath = getDbPath();
|
|
1381
|
-
if (!
|
|
933
|
+
if (!existsSync6(dbPath)) {
|
|
1382
934
|
logger_default.error("Database not found. Run 'skillo init' first.");
|
|
1383
935
|
process.exit(1);
|
|
1384
936
|
}
|
|
@@ -1391,11 +943,11 @@ skillsCommand.command("list").description("List all skills").option("-s, --sourc
|
|
|
1391
943
|
db.close();
|
|
1392
944
|
const skillsDir = getSkillsDir();
|
|
1393
945
|
const fsSkills = [];
|
|
1394
|
-
if (
|
|
946
|
+
if (existsSync6(skillsDir)) {
|
|
1395
947
|
const entries = readdirSync2(skillsDir, { withFileTypes: true });
|
|
1396
948
|
entries.filter((e) => e.isDirectory() && !e.name.startsWith(".")).forEach((e) => {
|
|
1397
949
|
const skillMd = join2(skillsDir, e.name, "SKILL.md");
|
|
1398
|
-
if (
|
|
950
|
+
if (existsSync6(skillMd)) {
|
|
1399
951
|
fsSkills.push(e.name);
|
|
1400
952
|
}
|
|
1401
953
|
});
|
|
@@ -1435,7 +987,7 @@ skillsCommand.command("list").description("List all skills").option("-s, --sourc
|
|
|
1435
987
|
});
|
|
1436
988
|
skillsCommand.command("show <name>").description("Show skill details").action(async (name) => {
|
|
1437
989
|
const dbPath = getDbPath();
|
|
1438
|
-
if (!
|
|
990
|
+
if (!existsSync6(dbPath)) {
|
|
1439
991
|
logger_default.error("Database not found. Run 'skillo init' first.");
|
|
1440
992
|
process.exit(1);
|
|
1441
993
|
}
|
|
@@ -1445,7 +997,7 @@ skillsCommand.command("show <name>").description("Show skill details").action(as
|
|
|
1445
997
|
db.close();
|
|
1446
998
|
if (!skill) {
|
|
1447
999
|
const skillPath = join2(getSkillsDir(), name, "SKILL.md");
|
|
1448
|
-
if (
|
|
1000
|
+
if (existsSync6(skillPath)) {
|
|
1449
1001
|
logger_default.blank();
|
|
1450
1002
|
logger_default.bold(name);
|
|
1451
1003
|
logger_default.blank();
|
|
@@ -1476,7 +1028,7 @@ skillsCommand.command("show <name>").description("Show skill details").action(as
|
|
|
1476
1028
|
});
|
|
1477
1029
|
skillsCommand.command("delete <name>").description("Delete a skill").option("-f, --force", "Skip confirmation").action(async (name, options) => {
|
|
1478
1030
|
const dbPath = getDbPath();
|
|
1479
|
-
if (!
|
|
1031
|
+
if (!existsSync6(dbPath)) {
|
|
1480
1032
|
logger_default.error("Database not found.");
|
|
1481
1033
|
process.exit(1);
|
|
1482
1034
|
}
|
|
@@ -1484,7 +1036,7 @@ skillsCommand.command("delete <name>").description("Delete a skill").option("-f,
|
|
|
1484
1036
|
await db.initialize();
|
|
1485
1037
|
const skill = await db.getSkill(name);
|
|
1486
1038
|
const skillDir = skill?.path || join2(getSkillsDir(), name);
|
|
1487
|
-
if (!skill && !
|
|
1039
|
+
if (!skill && !existsSync6(skillDir)) {
|
|
1488
1040
|
db.close();
|
|
1489
1041
|
logger_default.error(`Skill not found: ${name}`);
|
|
1490
1042
|
process.exit(1);
|
|
@@ -1495,7 +1047,7 @@ skillsCommand.command("delete <name>").description("Delete a skill").option("-f,
|
|
|
1495
1047
|
db.close();
|
|
1496
1048
|
return;
|
|
1497
1049
|
}
|
|
1498
|
-
if (
|
|
1050
|
+
if (existsSync6(skillDir)) {
|
|
1499
1051
|
rmSync(skillDir, { recursive: true, force: true });
|
|
1500
1052
|
}
|
|
1501
1053
|
if (skill) {
|
|
@@ -1509,7 +1061,7 @@ skillsCommand.command("path").description("Show skills directory path").action(a
|
|
|
1509
1061
|
});
|
|
1510
1062
|
skillsCommand.command("open").description("Open skills directory in file manager").action(async () => {
|
|
1511
1063
|
const skillsDir = getSkillsDir();
|
|
1512
|
-
if (!
|
|
1064
|
+
if (!existsSync6(skillsDir)) {
|
|
1513
1065
|
logger_default.error("Skills directory not found. Run 'skillo init' first.");
|
|
1514
1066
|
process.exit(1);
|
|
1515
1067
|
}
|
|
@@ -1524,7 +1076,7 @@ skillsCommand.command("open").description("Open skills directory in file manager
|
|
|
1524
1076
|
});
|
|
1525
1077
|
|
|
1526
1078
|
// src/commands/shell.ts
|
|
1527
|
-
import { existsSync as
|
|
1079
|
+
import { existsSync as existsSync7, writeFileSync as writeFileSync2, readFileSync as readFileSync4, appendFileSync } from "fs";
|
|
1528
1080
|
import { spawn } from "child_process";
|
|
1529
1081
|
import { homedir as homedir2 } from "os";
|
|
1530
1082
|
import { join as join3 } from "path";
|
|
@@ -1564,7 +1116,7 @@ function normalizeCommand(cmd) {
|
|
|
1564
1116
|
return { normalized: normalized.trim(), variables };
|
|
1565
1117
|
}
|
|
1566
1118
|
var shellCommand = new Command6("shell").description("Start a tracked terminal session").option("-s, --shell <shell>", "Shell to use (default: $SHELL or cmd on Windows)").option("-p, --project <path>", "Project path to track").action(async (options) => {
|
|
1567
|
-
if (!
|
|
1119
|
+
if (!existsSync7(getConfigFile())) {
|
|
1568
1120
|
logger_default.error("Skillo not initialized. Run 'skillo init' first.");
|
|
1569
1121
|
process.exit(1);
|
|
1570
1122
|
}
|
|
@@ -1639,7 +1191,7 @@ var recordCommand = new Command6("record").description("Record a command (used b
|
|
|
1639
1191
|
db.close();
|
|
1640
1192
|
if (options.sync !== false) {
|
|
1641
1193
|
try {
|
|
1642
|
-
const { getApiClient: getApiClient2 } = await import("./api-client-
|
|
1194
|
+
const { getApiClient: getApiClient2 } = await import("./api-client-KUQW7FSC.js");
|
|
1643
1195
|
const client = getApiClient2();
|
|
1644
1196
|
if (client.hasApiKey()) {
|
|
1645
1197
|
await client.syncCommands([{
|
|
@@ -1857,7 +1409,7 @@ $null = Register-EngineEvent -SourceIdentifier PowerShell.Exiting -Action {
|
|
|
1857
1409
|
Write-Host "Skillo: Command tracking enabled" -ForegroundColor DarkGray
|
|
1858
1410
|
`;
|
|
1859
1411
|
const psScriptFile = join3(scriptPath, "skillo.ps1");
|
|
1860
|
-
|
|
1412
|
+
writeFileSync2(psScriptFile, psScript, "utf-8");
|
|
1861
1413
|
logger_default.success(`Created ${psScriptFile}`);
|
|
1862
1414
|
const profilePath = join3(home, "Documents", "WindowsPowerShell", "Microsoft.PowerShell_profile.ps1");
|
|
1863
1415
|
const profileDir = join3(home, "Documents", "WindowsPowerShell");
|
|
@@ -1866,8 +1418,8 @@ Write-Host "Skillo: Command tracking enabled" -ForegroundColor DarkGray
|
|
|
1866
1418
|
# Skillo CLI Integration
|
|
1867
1419
|
. "${psScriptFile}"
|
|
1868
1420
|
`;
|
|
1869
|
-
if (
|
|
1870
|
-
const content =
|
|
1421
|
+
if (existsSync7(profilePath)) {
|
|
1422
|
+
const content = readFileSync4(profilePath, "utf-8");
|
|
1871
1423
|
if (!content.includes("Skillo CLI Integration")) {
|
|
1872
1424
|
appendFileSync(profilePath, sourceLine);
|
|
1873
1425
|
logger_default.success("Added to PowerShell profile");
|
|
@@ -1875,7 +1427,7 @@ Write-Host "Skillo: Command tracking enabled" -ForegroundColor DarkGray
|
|
|
1875
1427
|
logger_default.dim("Already in PowerShell profile");
|
|
1876
1428
|
}
|
|
1877
1429
|
} else {
|
|
1878
|
-
|
|
1430
|
+
writeFileSync2(profilePath, sourceLine, "utf-8");
|
|
1879
1431
|
logger_default.success("Created PowerShell profile");
|
|
1880
1432
|
}
|
|
1881
1433
|
} else if (shell === "bash") {
|
|
@@ -1946,15 +1498,15 @@ Write-Host "Skillo: Command tracking enabled" -ForegroundColor DarkGray
|
|
|
1946
1498
|
'echo -e "\\033[90mSkillo: Command tracking enabled\\033[0m"'
|
|
1947
1499
|
].join("\n");
|
|
1948
1500
|
const bashScriptFile = join3(scriptPath, "skillo.bash");
|
|
1949
|
-
|
|
1501
|
+
writeFileSync2(bashScriptFile, bashScript, "utf-8");
|
|
1950
1502
|
logger_default.success(`Created ${bashScriptFile}`);
|
|
1951
1503
|
const bashrcPath = join3(home, ".bashrc");
|
|
1952
1504
|
const sourceLine = `
|
|
1953
1505
|
# Skillo CLI Integration
|
|
1954
1506
|
[ -f "${bashScriptFile}" ] && source "${bashScriptFile}"
|
|
1955
1507
|
`;
|
|
1956
|
-
if (
|
|
1957
|
-
const content =
|
|
1508
|
+
if (existsSync7(bashrcPath)) {
|
|
1509
|
+
const content = readFileSync4(bashrcPath, "utf-8");
|
|
1958
1510
|
if (!content.includes("Skillo CLI Integration")) {
|
|
1959
1511
|
appendFileSync(bashrcPath, sourceLine);
|
|
1960
1512
|
logger_default.success("Added to ~/.bashrc");
|
|
@@ -1962,7 +1514,7 @@ Write-Host "Skillo: Command tracking enabled" -ForegroundColor DarkGray
|
|
|
1962
1514
|
logger_default.dim("Already in ~/.bashrc");
|
|
1963
1515
|
}
|
|
1964
1516
|
} else {
|
|
1965
|
-
|
|
1517
|
+
writeFileSync2(bashrcPath, sourceLine, "utf-8");
|
|
1966
1518
|
logger_default.success("Created ~/.bashrc");
|
|
1967
1519
|
}
|
|
1968
1520
|
} else if (shell === "zsh") {
|
|
@@ -2029,15 +1581,15 @@ Write-Host "Skillo: Command tracking enabled" -ForegroundColor DarkGray
|
|
|
2029
1581
|
'echo -e "\\033[90mSkillo: Command tracking enabled\\033[0m"'
|
|
2030
1582
|
].join("\n");
|
|
2031
1583
|
const zshScriptFile = join3(scriptPath, "skillo.zsh");
|
|
2032
|
-
|
|
1584
|
+
writeFileSync2(zshScriptFile, zshScript, "utf-8");
|
|
2033
1585
|
logger_default.success(`Created ${zshScriptFile}`);
|
|
2034
1586
|
const zshrcPath = join3(home, ".zshrc");
|
|
2035
1587
|
const sourceLine = `
|
|
2036
1588
|
# Skillo CLI Integration
|
|
2037
1589
|
[ -f "${zshScriptFile}" ] && source "${zshScriptFile}"
|
|
2038
1590
|
`;
|
|
2039
|
-
if (
|
|
2040
|
-
const content =
|
|
1591
|
+
if (existsSync7(zshrcPath)) {
|
|
1592
|
+
const content = readFileSync4(zshrcPath, "utf-8");
|
|
2041
1593
|
if (!content.includes("Skillo CLI Integration")) {
|
|
2042
1594
|
appendFileSync(zshrcPath, sourceLine);
|
|
2043
1595
|
logger_default.success("Added to ~/.zshrc");
|
|
@@ -2045,7 +1597,7 @@ Write-Host "Skillo: Command tracking enabled" -ForegroundColor DarkGray
|
|
|
2045
1597
|
logger_default.dim("Already in ~/.zshrc");
|
|
2046
1598
|
}
|
|
2047
1599
|
} else {
|
|
2048
|
-
|
|
1600
|
+
writeFileSync2(zshrcPath, sourceLine, "utf-8");
|
|
2049
1601
|
logger_default.success("Created ~/.zshrc");
|
|
2050
1602
|
}
|
|
2051
1603
|
} else if (shell === "fish") {
|
|
@@ -2064,7 +1616,7 @@ Write-Host "Skillo: Command tracking enabled" -ForegroundColor DarkGray
|
|
|
2064
1616
|
'echo -e "\\033[90mSkillo: Command tracking enabled\\033[0m"'
|
|
2065
1617
|
].join("\n");
|
|
2066
1618
|
const fishScriptFile = join3(scriptPath, "skillo.fish");
|
|
2067
|
-
|
|
1619
|
+
writeFileSync2(fishScriptFile, fishScript, "utf-8");
|
|
2068
1620
|
logger_default.success(`Created ${fishScriptFile}`);
|
|
2069
1621
|
const fishConfigDir = join3(home, ".config", "fish");
|
|
2070
1622
|
ensureDirectory(fishConfigDir);
|
|
@@ -2075,8 +1627,8 @@ if test -f "${fishScriptFile}"
|
|
|
2075
1627
|
source "${fishScriptFile}"
|
|
2076
1628
|
end
|
|
2077
1629
|
`;
|
|
2078
|
-
if (
|
|
2079
|
-
const content =
|
|
1630
|
+
if (existsSync7(fishConfigPath)) {
|
|
1631
|
+
const content = readFileSync4(fishConfigPath, "utf-8");
|
|
2080
1632
|
if (!content.includes("Skillo CLI Integration")) {
|
|
2081
1633
|
appendFileSync(fishConfigPath, sourceLine);
|
|
2082
1634
|
logger_default.success("Added to ~/.config/fish/config.fish");
|
|
@@ -2084,17 +1636,17 @@ end
|
|
|
2084
1636
|
logger_default.dim("Already in fish config");
|
|
2085
1637
|
}
|
|
2086
1638
|
} else {
|
|
2087
|
-
|
|
1639
|
+
writeFileSync2(fishConfigPath, sourceLine, "utf-8");
|
|
2088
1640
|
logger_default.success("Created fish config");
|
|
2089
1641
|
}
|
|
2090
1642
|
}
|
|
2091
1643
|
}
|
|
2092
1644
|
async function uninstallShellIntegration(shell, home) {
|
|
2093
1645
|
const removeFromFile = (filePath) => {
|
|
2094
|
-
if (!
|
|
2095
|
-
let content =
|
|
1646
|
+
if (!existsSync7(filePath)) return;
|
|
1647
|
+
let content = readFileSync4(filePath, "utf-8");
|
|
2096
1648
|
content = content.replace(/\n# Skillo CLI Integration\n[^\n]*\n/g, "\n");
|
|
2097
|
-
|
|
1649
|
+
writeFileSync2(filePath, content, "utf-8");
|
|
2098
1650
|
};
|
|
2099
1651
|
if (shell === "powershell") {
|
|
2100
1652
|
const profilePath = join3(home, "Documents", "WindowsPowerShell", "Microsoft.PowerShell_profile.ps1");
|
|
@@ -2109,16 +1661,16 @@ async function uninstallShellIntegration(shell, home) {
|
|
|
2109
1661
|
}
|
|
2110
1662
|
|
|
2111
1663
|
// src/commands/daemon.ts
|
|
2112
|
-
import { existsSync as
|
|
1664
|
+
import { existsSync as existsSync8, readFileSync as readFileSync5, writeFileSync as writeFileSync3, unlinkSync as unlinkSync2 } from "fs";
|
|
2113
1665
|
import { fork } from "child_process";
|
|
2114
1666
|
import { Command as Command7 } from "commander";
|
|
2115
1667
|
function isDaemonRunning2() {
|
|
2116
1668
|
const pidFile = getPidFile();
|
|
2117
|
-
if (!
|
|
1669
|
+
if (!existsSync8(pidFile)) {
|
|
2118
1670
|
return { running: false, pid: null };
|
|
2119
1671
|
}
|
|
2120
1672
|
try {
|
|
2121
|
-
const pidStr =
|
|
1673
|
+
const pidStr = readFileSync5(pidFile, "utf-8").trim();
|
|
2122
1674
|
const pid = parseInt(pidStr, 10);
|
|
2123
1675
|
if (isNaN(pid)) {
|
|
2124
1676
|
return { running: false, pid: null };
|
|
@@ -2149,20 +1701,107 @@ function startDaemonProcess() {
|
|
|
2149
1701
|
});
|
|
2150
1702
|
child.unref();
|
|
2151
1703
|
if (child.pid) {
|
|
2152
|
-
|
|
1704
|
+
writeFileSync3(getPidFile(), String(child.pid));
|
|
2153
1705
|
return child.pid;
|
|
2154
1706
|
}
|
|
2155
1707
|
return null;
|
|
2156
1708
|
}
|
|
1709
|
+
async function ensureInitialized() {
|
|
1710
|
+
if (existsSync8(getConfigFile())) return;
|
|
1711
|
+
const { getDefaultConfig: getDefaultConfig2, saveConfig: saveConfig2 } = await import("./config-P5EM5L7N.js");
|
|
1712
|
+
const { SkilloDatabase: SkilloDatabase2 } = await import("./database-F3BFFZKG.js");
|
|
1713
|
+
const { getConfigDir: getConfigDir2, getSkillsDir: getSkillsDir2 } = await import("./paths-INOKEM66.js");
|
|
1714
|
+
ensureDirectory(getDataDir());
|
|
1715
|
+
ensureDirectory(getConfigDir2());
|
|
1716
|
+
ensureDirectory(getSkillsDir2());
|
|
1717
|
+
saveConfig2(getDefaultConfig2());
|
|
1718
|
+
const db = new SkilloDatabase2();
|
|
1719
|
+
await db.initialize();
|
|
1720
|
+
db.close();
|
|
1721
|
+
logger_default.dim("Skillo initialized.");
|
|
1722
|
+
}
|
|
1723
|
+
async function ensureLoggedIn() {
|
|
1724
|
+
const { getApiClient: getApiClient2 } = await import("./api-client-KUQW7FSC.js");
|
|
1725
|
+
const client = getApiClient2();
|
|
1726
|
+
if (client.hasApiKey()) {
|
|
1727
|
+
const result = await client.authenticate();
|
|
1728
|
+
if (result.success) return true;
|
|
1729
|
+
client.clearApiKey();
|
|
1730
|
+
logger_default.warn("Session expired. Logging in again...");
|
|
1731
|
+
}
|
|
1732
|
+
logger_default.blank();
|
|
1733
|
+
logger_default.info("Login required. Opening browser...");
|
|
1734
|
+
logger_default.blank();
|
|
1735
|
+
const { hostname: hostname2 } = await import("os");
|
|
1736
|
+
const deviceName = `CLI on ${hostname2()}`;
|
|
1737
|
+
const deviceAuthResult = await client.startDeviceAuth(deviceName);
|
|
1738
|
+
if (!deviceAuthResult.success || !deviceAuthResult.data) {
|
|
1739
|
+
logger_default.error("Failed to start authentication: " + (deviceAuthResult.error || "Unknown error"));
|
|
1740
|
+
logger_default.dim("You can also login manually: skillo login <api-key>");
|
|
1741
|
+
return false;
|
|
1742
|
+
}
|
|
1743
|
+
const { code, verification_url, interval } = deviceAuthResult.data;
|
|
1744
|
+
logger_default.highlight(` ${verification_url}`);
|
|
1745
|
+
logger_default.blank();
|
|
1746
|
+
try {
|
|
1747
|
+
const { exec: execCb } = await import("child_process");
|
|
1748
|
+
const { promisify } = await import("util");
|
|
1749
|
+
const execAsync = promisify(execCb);
|
|
1750
|
+
const openCmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? 'start ""' : "xdg-open";
|
|
1751
|
+
await execAsync(`${openCmd} "${verification_url}"`);
|
|
1752
|
+
logger_default.dim("Browser opened. Waiting for authorization...");
|
|
1753
|
+
} catch {
|
|
1754
|
+
logger_default.dim("Open the URL above in your browser to authorize.");
|
|
1755
|
+
}
|
|
1756
|
+
logger_default.dim("(Press Ctrl+C to cancel)");
|
|
1757
|
+
const maxAttempts = 120;
|
|
1758
|
+
for (let i = 0; i < maxAttempts; i++) {
|
|
1759
|
+
await new Promise((r) => setTimeout(r, interval * 1e3));
|
|
1760
|
+
const statusResult = await client.checkTokenStatus(code);
|
|
1761
|
+
if (!statusResult.success) continue;
|
|
1762
|
+
const status = statusResult.data?.status;
|
|
1763
|
+
if (status === "ready") {
|
|
1764
|
+
const tokenResult = await client.exchangeToken(code, deviceName);
|
|
1765
|
+
if (tokenResult.success && tokenResult.data) {
|
|
1766
|
+
client.saveApiKey(tokenResult.data.api_key);
|
|
1767
|
+
const authResult = await client.authenticate();
|
|
1768
|
+
logger_default.blank();
|
|
1769
|
+
logger_default.success("Login successful!");
|
|
1770
|
+
if (authResult.success && authResult.data) {
|
|
1771
|
+
logger_default.info(`Welcome, ${authResult.data.user.name}!`);
|
|
1772
|
+
}
|
|
1773
|
+
logger_default.blank();
|
|
1774
|
+
return true;
|
|
1775
|
+
}
|
|
1776
|
+
logger_default.error("Failed to complete login: " + (tokenResult.error || "Unknown error"));
|
|
1777
|
+
return false;
|
|
1778
|
+
}
|
|
1779
|
+
if (status === "expired" || status === "used" || status === "not_found") {
|
|
1780
|
+
logger_default.error(`Authorization ${status}. Please try again.`);
|
|
1781
|
+
return false;
|
|
1782
|
+
}
|
|
1783
|
+
}
|
|
1784
|
+
logger_default.error("Authorization timed out.");
|
|
1785
|
+
return false;
|
|
1786
|
+
}
|
|
2157
1787
|
var startCommand = new Command7("start").description("Start the Skillo daemon").option("-f, --foreground", "Run in foreground (don't daemonize)").action(async (options) => {
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
1788
|
+
await ensureInitialized();
|
|
1789
|
+
if (!options.foreground) {
|
|
1790
|
+
const loggedIn = await ensureLoggedIn();
|
|
1791
|
+
if (!loggedIn) {
|
|
1792
|
+
process.exit(1);
|
|
1793
|
+
}
|
|
2162
1794
|
}
|
|
2163
1795
|
const { running, pid } = isDaemonRunning2();
|
|
2164
1796
|
if (running) {
|
|
2165
|
-
logger_default.
|
|
1797
|
+
logger_default.success(`Daemon is already running (PID: ${pid})`);
|
|
1798
|
+
const serviceStatus = getServiceStatus();
|
|
1799
|
+
if (!serviceStatus.daemon.installed) {
|
|
1800
|
+
const serviceResult = await installService({ includeTray: true });
|
|
1801
|
+
if (serviceResult.success) {
|
|
1802
|
+
logger_default.dim("Auto-start service installed.");
|
|
1803
|
+
}
|
|
1804
|
+
}
|
|
2166
1805
|
return;
|
|
2167
1806
|
}
|
|
2168
1807
|
if (options.foreground) {
|
|
@@ -2173,17 +1812,20 @@ var startCommand = new Command7("start").description("Start the Skillo daemon").
|
|
|
2173
1812
|
} else {
|
|
2174
1813
|
logger_default.info("Starting Skillo daemon...");
|
|
2175
1814
|
if (process.platform === "win32") {
|
|
2176
|
-
logger_default.
|
|
2177
|
-
logger_default.dim("Running in foreground mode...");
|
|
1815
|
+
logger_default.dim("Running in foreground mode on Windows...");
|
|
2178
1816
|
logger_default.blank();
|
|
1817
|
+
const serviceResult = await installService({ includeTray: true });
|
|
1818
|
+
if (serviceResult.success) {
|
|
1819
|
+
logger_default.dim("Auto-start service installed. Daemon will run in background on next login.");
|
|
1820
|
+
}
|
|
2179
1821
|
await runDaemonForeground();
|
|
2180
1822
|
} else {
|
|
2181
1823
|
const daemonPid = startDaemonProcess();
|
|
2182
1824
|
if (daemonPid) {
|
|
2183
1825
|
logger_default.success(`Daemon started (PID: ${daemonPid})`);
|
|
2184
|
-
const serviceResult = await installService({ includeTray:
|
|
1826
|
+
const serviceResult = await installService({ includeTray: true });
|
|
2185
1827
|
if (serviceResult.success) {
|
|
2186
|
-
logger_default.dim("Auto-start service installed. Daemon will survive reboots.");
|
|
1828
|
+
logger_default.dim("Auto-start & tray service installed. Daemon will survive reboots.");
|
|
2187
1829
|
}
|
|
2188
1830
|
logger_default.blank();
|
|
2189
1831
|
logger_default.dim("Use 'skillo status' to check daemon status");
|
|
@@ -2219,7 +1861,7 @@ var stopCommand = new Command7("stop").description("Stop the Skillo daemon").act
|
|
|
2219
1861
|
}
|
|
2220
1862
|
}
|
|
2221
1863
|
const pidFile = getPidFile();
|
|
2222
|
-
if (
|
|
1864
|
+
if (existsSync8(pidFile)) {
|
|
2223
1865
|
try {
|
|
2224
1866
|
unlinkSync2(pidFile);
|
|
2225
1867
|
} catch {
|
|
@@ -2228,7 +1870,7 @@ var stopCommand = new Command7("stop").description("Stop the Skillo daemon").act
|
|
|
2228
1870
|
});
|
|
2229
1871
|
var logsCommand = new Command7("logs").description("Show daemon logs").option("-n, --lines <number>", "Number of lines to show", "50").option("-f, --follow", "Follow log output").action(async (options) => {
|
|
2230
1872
|
const logFile = getLogFile();
|
|
2231
|
-
if (!
|
|
1873
|
+
if (!existsSync8(logFile)) {
|
|
2232
1874
|
logger_default.dim("No logs found.");
|
|
2233
1875
|
return;
|
|
2234
1876
|
}
|
|
@@ -2247,7 +1889,7 @@ var logsCommand = new Command7("logs").description("Show daemon logs").option("-
|
|
|
2247
1889
|
}
|
|
2248
1890
|
});
|
|
2249
1891
|
function showLogs(logFile, numLines) {
|
|
2250
|
-
const content =
|
|
1892
|
+
const content = readFileSync5(logFile, "utf-8");
|
|
2251
1893
|
const lines = content.split("\n").filter(Boolean);
|
|
2252
1894
|
const lastLines = lines.slice(-numLines);
|
|
2253
1895
|
lastLines.forEach((line) => console.log(line));
|
|
@@ -2301,14 +1943,14 @@ var serviceCommand = new Command7("service").description("Manage auto-start serv
|
|
|
2301
1943
|
);
|
|
2302
1944
|
async function runDaemonForeground() {
|
|
2303
1945
|
const pidFile = getPidFile();
|
|
2304
|
-
|
|
1946
|
+
writeFileSync3(pidFile, String(process.pid));
|
|
2305
1947
|
logger_default.dim(`Daemon PID: ${process.pid}`);
|
|
2306
1948
|
logger_default.dim(`Log file: ${getLogFile()}`);
|
|
2307
1949
|
logger_default.blank();
|
|
2308
1950
|
const cleanup = () => {
|
|
2309
1951
|
logger_default.blank();
|
|
2310
1952
|
logger_default.info("Shutting down daemon...");
|
|
2311
|
-
if (
|
|
1953
|
+
if (existsSync8(pidFile)) {
|
|
2312
1954
|
try {
|
|
2313
1955
|
unlinkSync2(pidFile);
|
|
2314
1956
|
} catch {
|
|
@@ -2319,7 +1961,7 @@ async function runDaemonForeground() {
|
|
|
2319
1961
|
process.on("SIGINT", cleanup);
|
|
2320
1962
|
process.on("SIGTERM", cleanup);
|
|
2321
1963
|
const config = loadConfig();
|
|
2322
|
-
const { getApiClient: getApiClient2 } = await import("./api-client-
|
|
1964
|
+
const { getApiClient: getApiClient2 } = await import("./api-client-KUQW7FSC.js");
|
|
2323
1965
|
const client = getApiClient2();
|
|
2324
1966
|
if (!client.hasApiKey()) {
|
|
2325
1967
|
logger_default.error("Not logged in. Run 'skillo login' first.");
|
|
@@ -2362,7 +2004,7 @@ async function runDaemonForeground() {
|
|
|
2362
2004
|
|
|
2363
2005
|
// src/commands/session.ts
|
|
2364
2006
|
import { Command as Command8 } from "commander";
|
|
2365
|
-
import { existsSync as
|
|
2007
|
+
import { existsSync as existsSync9, readFileSync as readFileSync6, writeFileSync as writeFileSync4, unlinkSync as unlinkSync3 } from "fs";
|
|
2366
2008
|
var sessionCommand = new Command8("session").description("Manage terminal sessions");
|
|
2367
2009
|
sessionCommand.command("start").description("Start a new terminal session (for standalone terminals)").option("--shell <shell>", "Shell type (powershell, bash, zsh, cmd)", "powershell").action(async (options) => {
|
|
2368
2010
|
try {
|
|
@@ -2415,18 +2057,18 @@ var sessionAutoCommand = new Command8("session-auto").description("Auto-detect p
|
|
|
2415
2057
|
const sessionsDir = getActiveSessionsDir();
|
|
2416
2058
|
const sessionFile = `${sessionsDir}/${terminalPid}.json`;
|
|
2417
2059
|
let currentSession = null;
|
|
2418
|
-
if (
|
|
2060
|
+
if (existsSync9(sessionFile)) {
|
|
2419
2061
|
try {
|
|
2420
|
-
currentSession = JSON.parse(
|
|
2062
|
+
currentSession = JSON.parse(readFileSync6(sessionFile, "utf-8"));
|
|
2421
2063
|
} catch {
|
|
2422
2064
|
currentSession = null;
|
|
2423
2065
|
}
|
|
2424
2066
|
}
|
|
2425
2067
|
const cacheFile = getTrackedProjectsCacheFile();
|
|
2426
2068
|
let matchedProject = null;
|
|
2427
|
-
if (
|
|
2069
|
+
if (existsSync9(cacheFile)) {
|
|
2428
2070
|
try {
|
|
2429
|
-
const cache = JSON.parse(
|
|
2071
|
+
const cache = JSON.parse(readFileSync6(cacheFile, "utf-8"));
|
|
2430
2072
|
const normalizedCwd = cwd.toLowerCase().replace(/\/+$/, "");
|
|
2431
2073
|
for (const project of cache.projects || []) {
|
|
2432
2074
|
const normalizedPath = project.path.toLowerCase().replace(/\/+$/, "");
|
|
@@ -2460,7 +2102,7 @@ var sessionAutoCommand = new Command8("session-auto").description("Auto-detect p
|
|
|
2460
2102
|
const result = await client.startSession(shell, matchedProject.path);
|
|
2461
2103
|
if (result.success && result.data?.sessionId) {
|
|
2462
2104
|
ensureDirectory(sessionsDir);
|
|
2463
|
-
|
|
2105
|
+
writeFileSync4(sessionFile, JSON.stringify({
|
|
2464
2106
|
sessionId: result.data.sessionId,
|
|
2465
2107
|
projectPath: matchedProject.path,
|
|
2466
2108
|
projectName: matchedProject.name,
|
|
@@ -2758,11 +2400,11 @@ Synced to platform: ${response.data.sessions.length} recent sessions`);
|
|
|
2758
2400
|
|
|
2759
2401
|
// src/commands/project.ts
|
|
2760
2402
|
import { Command as Command10 } from "commander";
|
|
2761
|
-
import { existsSync as
|
|
2403
|
+
import { existsSync as existsSync11, writeFileSync as writeFileSync5 } from "fs";
|
|
2762
2404
|
|
|
2763
2405
|
// src/utils/git.ts
|
|
2764
2406
|
import { execSync as execSync2 } from "child_process";
|
|
2765
|
-
import { join as join5, dirname as
|
|
2407
|
+
import { join as join5, dirname as dirname2, basename as basename2 } from "path";
|
|
2766
2408
|
function getGitInfo(projectPath) {
|
|
2767
2409
|
const result = {
|
|
2768
2410
|
isGitRepo: false,
|
|
@@ -2888,7 +2530,7 @@ var trackCommand = new Command10("track").description("Enable tracking for the c
|
|
|
2888
2530
|
projects: listResult.data.projects.filter((p) => p.trackingEnabled).map((p) => ({ path: p.path, name: p.name }))
|
|
2889
2531
|
};
|
|
2890
2532
|
ensureDirectory(getDataDir());
|
|
2891
|
-
|
|
2533
|
+
writeFileSync5(getTrackedProjectsCacheFile(), JSON.stringify(cacheData, null, 2));
|
|
2892
2534
|
}
|
|
2893
2535
|
} catch {
|
|
2894
2536
|
}
|
|
@@ -2903,7 +2545,7 @@ var trackCommand = new Command10("track").description("Enable tracking for the c
|
|
|
2903
2545
|
}
|
|
2904
2546
|
}
|
|
2905
2547
|
const shellIntegrationDir = getShellIntegrationDir();
|
|
2906
|
-
if (!
|
|
2548
|
+
if (!existsSync11(shellIntegrationDir) || !existsSync11(resolve(shellIntegrationDir, "skillo.zsh"))) {
|
|
2907
2549
|
logger_default.blank();
|
|
2908
2550
|
logger_default.dim("Tip: Run 'skillo setup-shell' to enable terminal auto-detection.");
|
|
2909
2551
|
}
|
|
@@ -3226,7 +2868,7 @@ var whoamiCommand = new Command11("whoami").description("Show current login stat
|
|
|
3226
2868
|
});
|
|
3227
2869
|
|
|
3228
2870
|
// src/commands/sync.ts
|
|
3229
|
-
import { existsSync as
|
|
2871
|
+
import { existsSync as existsSync12, writeFileSync as writeFileSync6, mkdirSync as mkdirSync2 } from "fs";
|
|
3230
2872
|
import { join as join6 } from "path";
|
|
3231
2873
|
import { Command as Command12 } from "commander";
|
|
3232
2874
|
var syncCommand = new Command12("sync").description("Sync data with Skillo platform").option("--push", "Push local data to platform").option("--pull", "Pull data from platform").option("--patterns", "Sync patterns only").option("--skills", "Sync skills only").option("--commands", "Sync commands only").action(
|
|
@@ -3243,7 +2885,7 @@ var syncCommand = new Command12("sync").description("Sync data with Skillo platf
|
|
|
3243
2885
|
const syncSkills = options.skills || !options.patterns && !options.skills && !options.commands;
|
|
3244
2886
|
const syncCommands = options.commands || !options.patterns && !options.skills && !options.commands;
|
|
3245
2887
|
const dbPath = getDbPath();
|
|
3246
|
-
if (!
|
|
2888
|
+
if (!existsSync12(dbPath)) {
|
|
3247
2889
|
logger_default.error("Database not found. Run 'skillo init' first.");
|
|
3248
2890
|
return;
|
|
3249
2891
|
}
|
|
@@ -3347,10 +2989,10 @@ async function pullSkills(skills) {
|
|
|
3347
2989
|
if (!skill.content) continue;
|
|
3348
2990
|
const skillDir = join6(skillsDir, skill.slug);
|
|
3349
2991
|
const skillFile = join6(skillDir, "SKILL.md");
|
|
3350
|
-
if (!
|
|
2992
|
+
if (!existsSync12(skillDir)) {
|
|
3351
2993
|
mkdirSync2(skillDir, { recursive: true });
|
|
3352
2994
|
}
|
|
3353
|
-
|
|
2995
|
+
writeFileSync6(skillFile, skill.content, "utf-8");
|
|
3354
2996
|
downloaded++;
|
|
3355
2997
|
logger_default.dim(` Downloaded: ${skill.name}`);
|
|
3356
2998
|
}
|
|
@@ -3361,7 +3003,7 @@ async function pullSkills(skills) {
|
|
|
3361
3003
|
import { Command as Command13 } from "commander";
|
|
3362
3004
|
var trayCommand = new Command13("tray").description("Start the system tray icon").action(async () => {
|
|
3363
3005
|
try {
|
|
3364
|
-
const { startTray } = await import("./tray-
|
|
3006
|
+
const { startTray } = await import("./tray-RZQV6GDP.js");
|
|
3365
3007
|
await startTray();
|
|
3366
3008
|
} catch (error) {
|
|
3367
3009
|
if (error instanceof Error && error.message.includes("Cannot find module")) {
|
|
@@ -3375,7 +3017,7 @@ var trayCommand = new Command13("tray").description("Start the system tray icon"
|
|
|
3375
3017
|
});
|
|
3376
3018
|
|
|
3377
3019
|
// src/cli.ts
|
|
3378
|
-
var VERSION = "0.2.
|
|
3020
|
+
var VERSION = "0.2.3";
|
|
3379
3021
|
var program = new Command14();
|
|
3380
3022
|
program.name("skillo").description(
|
|
3381
3023
|
`Skillo - Learn workflows by observation, not explanation.
|