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/cli.js CHANGED
@@ -1,12 +1,17 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
- getApiClient,
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-SYULMYPN.js";
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 as existsSync2 } from "fs";
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 (existsSync2(configFile) && !options.force) {
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 existsSync4, readFileSync as readFileSync3 } from "fs";
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 existsSync3, writeFileSync as writeFileSync2, unlinkSync, mkdirSync, readdirSync } from "fs";
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 (existsSync3(c)) return c;
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 (existsSync3(c)) return c;
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 (existsSync3(fnmDir)) paths.add(fnmDir);
228
+ if (existsSync2(fnmDir)) paths.add(fnmDir);
677
229
  } else {
678
230
  const nvmDir = process.env.NVM_DIR || join(home, ".nvm");
679
- if (existsSync3(nvmDir)) {
231
+ if (existsSync2(nvmDir)) {
680
232
  try {
681
233
  const defaultAlias = join(nvmDir, "alias", "default");
682
- if (existsSync3(defaultAlias)) {
234
+ if (existsSync2(defaultAlias)) {
683
235
  const versionsDir = join(nvmDir, "versions", "node");
684
- if (existsSync3(versionsDir)) {
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 (!existsSync3(agentsDir)) mkdirSync(agentsDir, { recursive: true });
403
+ if (!existsSync2(agentsDir)) mkdirSync(agentsDir, { recursive: true });
852
404
  const daemonPlist = getDaemonPlistPath();
853
- writeFileSync2(daemonPlist, generateDaemonPlist(skilloBin, envPath), "utf-8");
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
- writeFileSync2(trayPlist, generateTrayPlist(skilloBin, envPath), "utf-8");
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 (!existsSync3(systemdDir)) mkdirSync(systemdDir, { recursive: true });
872
- writeFileSync2(getDaemonServicePath(), generateDaemonUnit(skilloBin, envPath), "utf-8");
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
- writeFileSync2(getTrayServicePath(), generateTrayUnit(skilloBin, envPath), "utf-8");
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 (!existsSync3(dataDir)) mkdirSync(dataDir, { recursive: true });
440
+ if (!existsSync2(dataDir)) mkdirSync(dataDir, { recursive: true });
889
441
  const vbsPath = getWinDaemonVbsPath();
890
- writeFileSync2(vbsPath, generateDaemonVbs(skilloBin), "utf-8");
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 (existsSync3(daemonPlist)) {
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 (existsSync3(trayPlist)) {
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 (existsSync3(daemonService)) {
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 (existsSync3(trayService)) {
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 (existsSync3(vbsPath)) {
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 = existsSync3(getDaemonPlistPath());
976
- const trayInstalled = existsSync3(getTrayPlistPath());
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 = existsSync3(getDaemonServicePath());
992
- const trayInstalled = existsSync3(getTrayServicePath());
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 (!existsSync4(pidFile)) {
581
+ if (!existsSync3(pidFile)) {
1030
582
  return { running: false, pid: null };
1031
583
  }
1032
584
  try {
1033
- const pidStr = readFileSync3(pidFile, "utf-8").trim();
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 (!existsSync4(dbPath)) {
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 (existsSync4(logFile)) {
637
+ if (existsSync3(logFile)) {
1086
638
  logger_default.dim("Recent log entries:");
1087
639
  try {
1088
- const content = readFileSync3(logFile, "utf-8");
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 existsSync5, readFileSync as readFileSync4 } from "fs";
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 (!existsSync5(configFile)) {
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 = readFileSync4(configFile, "utf-8");
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 (!existsSync5(configFile)) {
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 (!existsSync5(configFile)) {
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 existsSync6 } from "fs";
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 (!existsSync6(dbPath)) {
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 (!existsSync6(dbPath)) {
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 (!existsSync6(dbPath)) {
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-WO6NUCIJ.js");
1291
- const { writeFileSync: writeFileSync8, mkdirSync: mkdirSync3 } = await import("fs");
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 (!existsSync6(dbPath)) {
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
- writeFileSync8(skillFile, skill.content, "utf-8");
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 (!existsSync6(dbPath)) {
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 existsSync7, readdirSync as readdirSync2, rmSync } from "fs";
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 (!existsSync7(dbPath)) {
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 (existsSync7(skillsDir)) {
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 (existsSync7(skillMd)) {
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 (!existsSync7(dbPath)) {
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 (existsSync7(skillPath)) {
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 (!existsSync7(dbPath)) {
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 && !existsSync7(skillDir)) {
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 (existsSync7(skillDir)) {
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 (!existsSync7(skillsDir)) {
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 existsSync8, writeFileSync as writeFileSync3, readFileSync as readFileSync5, appendFileSync } from "fs";
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 (!existsSync8(getConfigFile())) {
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-WO6NUCIJ.js");
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
- writeFileSync3(psScriptFile, psScript, "utf-8");
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 (existsSync8(profilePath)) {
1870
- const content = readFileSync5(profilePath, "utf-8");
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
- writeFileSync3(profilePath, sourceLine, "utf-8");
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
- writeFileSync3(bashScriptFile, bashScript, "utf-8");
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 (existsSync8(bashrcPath)) {
1957
- const content = readFileSync5(bashrcPath, "utf-8");
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
- writeFileSync3(bashrcPath, sourceLine, "utf-8");
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
- writeFileSync3(zshScriptFile, zshScript, "utf-8");
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 (existsSync8(zshrcPath)) {
2040
- const content = readFileSync5(zshrcPath, "utf-8");
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
- writeFileSync3(zshrcPath, sourceLine, "utf-8");
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
- writeFileSync3(fishScriptFile, fishScript, "utf-8");
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 (existsSync8(fishConfigPath)) {
2079
- const content = readFileSync5(fishConfigPath, "utf-8");
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
- writeFileSync3(fishConfigPath, sourceLine, "utf-8");
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 (!existsSync8(filePath)) return;
2095
- let content = readFileSync5(filePath, "utf-8");
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
- writeFileSync3(filePath, content, "utf-8");
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 existsSync9, readFileSync as readFileSync6, writeFileSync as writeFileSync4, unlinkSync as unlinkSync2 } from "fs";
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 (!existsSync9(pidFile)) {
1669
+ if (!existsSync8(pidFile)) {
2118
1670
  return { running: false, pid: null };
2119
1671
  }
2120
1672
  try {
2121
- const pidStr = readFileSync6(pidFile, "utf-8").trim();
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
- writeFileSync4(getPidFile(), String(child.pid));
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
- if (!existsSync9(getConfigFile())) {
2159
- logger_default.error("Skillo not initialized.");
2160
- logger_default.dim("Run 'skillo init' first.");
2161
- process.exit(1);
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.warn(`Daemon is already running (PID: ${pid})`);
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.warn("Background daemon not fully supported on Windows.");
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: false });
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 (existsSync9(pidFile)) {
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 (!existsSync9(logFile)) {
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 = readFileSync6(logFile, "utf-8");
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
- writeFileSync4(pidFile, String(process.pid));
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 (existsSync9(pidFile)) {
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-WO6NUCIJ.js");
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 existsSync10, readFileSync as readFileSync7, writeFileSync as writeFileSync5, unlinkSync as unlinkSync3 } from "fs";
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 (existsSync10(sessionFile)) {
2060
+ if (existsSync9(sessionFile)) {
2419
2061
  try {
2420
- currentSession = JSON.parse(readFileSync7(sessionFile, "utf-8"));
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 (existsSync10(cacheFile)) {
2069
+ if (existsSync9(cacheFile)) {
2428
2070
  try {
2429
- const cache = JSON.parse(readFileSync7(cacheFile, "utf-8"));
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
- writeFileSync5(sessionFile, JSON.stringify({
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 existsSync12, writeFileSync as writeFileSync6 } from "fs";
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 dirname3, basename as basename2 } from "path";
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
- writeFileSync6(getTrackedProjectsCacheFile(), JSON.stringify(cacheData, null, 2));
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 (!existsSync12(shellIntegrationDir) || !existsSync12(resolve(shellIntegrationDir, "skillo.zsh"))) {
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 existsSync13, writeFileSync as writeFileSync7, mkdirSync as mkdirSync2 } from "fs";
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 (!existsSync13(dbPath)) {
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 (!existsSync13(skillDir)) {
2992
+ if (!existsSync12(skillDir)) {
3351
2993
  mkdirSync2(skillDir, { recursive: true });
3352
2994
  }
3353
- writeFileSync7(skillFile, skill.content, "utf-8");
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-62I5KIFE.js");
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.1";
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.