@profullstack/threatcrush 0.2.0 → 0.2.1

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/index.js CHANGED
@@ -3336,10 +3336,18 @@ var require_commander = __commonJS({
3336
3336
  // src/core/state.ts
3337
3337
  function initStateDB(dbPath = "/var/lib/threatcrush/state.db") {
3338
3338
  if (db) return db;
3339
+ if (dbUnavailable) {
3340
+ throw new Error("state db unavailable (previous init failed)");
3341
+ }
3339
3342
  try {
3340
- db = new import_better_sqlite3.default(dbPath);
3341
- } catch {
3342
- db = new import_better_sqlite3.default(":memory:");
3343
+ try {
3344
+ db = new import_better_sqlite3.default(dbPath);
3345
+ } catch {
3346
+ db = new import_better_sqlite3.default(":memory:");
3347
+ }
3348
+ } catch (err) {
3349
+ dbUnavailable = true;
3350
+ throw err;
3343
3351
  }
3344
3352
  db.pragma("journal_mode = WAL");
3345
3353
  db.exec(`
@@ -3375,7 +3383,8 @@ function initStateDB(dbPath = "/var/lib/threatcrush/state.db") {
3375
3383
  return db;
3376
3384
  }
3377
3385
  function insertEvent(event) {
3378
- const database = db || initStateDB();
3386
+ const database = tryDb();
3387
+ if (!database) return -1;
3379
3388
  const stmt = database.prepare(`
3380
3389
  INSERT INTO events (timestamp, module, category, severity, message, source_ip, details)
3381
3390
  VALUES (?, ?, ?, ?, ?, ?, ?)
@@ -3391,22 +3400,34 @@ function insertEvent(event) {
3391
3400
  );
3392
3401
  return result.lastInsertRowid;
3393
3402
  }
3403
+ function tryDb() {
3404
+ if (db) return db;
3405
+ if (dbUnavailable) return null;
3406
+ try {
3407
+ return initStateDB();
3408
+ } catch {
3409
+ return null;
3410
+ }
3411
+ }
3394
3412
  function getRecentEvents(limit = 50) {
3395
- const database = db || initStateDB();
3413
+ const database = tryDb();
3414
+ if (!database) return [];
3396
3415
  const rows = database.prepare(`
3397
3416
  SELECT * FROM events ORDER BY timestamp DESC LIMIT ?
3398
3417
  `).all(limit);
3399
3418
  return rows.map(rowToEvent);
3400
3419
  }
3401
3420
  function getEventCount(since) {
3402
- const database = db || initStateDB();
3421
+ const database = tryDb();
3422
+ if (!database) return 0;
3403
3423
  if (since) {
3404
3424
  return database.prepare(`SELECT COUNT(*) as count FROM events WHERE timestamp >= ?`).get(since.toISOString()).count;
3405
3425
  }
3406
3426
  return database.prepare(`SELECT COUNT(*) as count FROM events`).get().count;
3407
3427
  }
3408
3428
  function getThreatCount(since) {
3409
- const database = db || initStateDB();
3429
+ const database = tryDb();
3430
+ if (!database) return 0;
3410
3431
  const severities = "('medium','high','critical')";
3411
3432
  if (since) {
3412
3433
  return database.prepare(
@@ -3418,13 +3439,30 @@ function getThreatCount(since) {
3418
3439
  ).get().count;
3419
3440
  }
3420
3441
  function getTopSources(limit = 10) {
3421
- const database = db || initStateDB();
3442
+ const database = tryDb();
3443
+ if (!database) return [];
3422
3444
  return database.prepare(`
3423
3445
  SELECT source_ip as ip, COUNT(*) as count FROM events
3424
3446
  WHERE source_ip IS NOT NULL
3425
3447
  GROUP BY source_ip ORDER BY count DESC LIMIT ?
3426
3448
  `).all(limit);
3427
3449
  }
3450
+ function getModuleState(module2, key) {
3451
+ const database = db || initStateDB();
3452
+ const row = database.prepare(`SELECT value FROM module_state WHERE module = ? AND key = ?`).get(module2, key);
3453
+ if (!row) return void 0;
3454
+ try {
3455
+ return JSON.parse(row.value);
3456
+ } catch {
3457
+ return row.value;
3458
+ }
3459
+ }
3460
+ function setModuleState(module2, key, value) {
3461
+ const database = db || initStateDB();
3462
+ database.prepare(`
3463
+ INSERT OR REPLACE INTO module_state (module, key, value) VALUES (?, ?, ?)
3464
+ `).run(module2, key, JSON.stringify(value));
3465
+ }
3428
3466
  function rowToEvent(row) {
3429
3467
  return {
3430
3468
  id: row.id,
@@ -3443,12 +3481,13 @@ function closeDB() {
3443
3481
  db = null;
3444
3482
  }
3445
3483
  }
3446
- var import_better_sqlite3, db;
3484
+ var import_better_sqlite3, db, dbUnavailable;
3447
3485
  var init_state = __esm({
3448
3486
  "src/core/state.ts"() {
3449
3487
  "use strict";
3450
3488
  import_better_sqlite3 = __toESM(require("better-sqlite3"));
3451
3489
  db = null;
3490
+ dbUnavailable = false;
3452
3491
  }
3453
3492
  });
3454
3493
 
@@ -8220,7 +8259,7 @@ var source_default = chalk;
8220
8259
 
8221
8260
  // src/index.ts
8222
8261
  var import_readline = __toESM(require("readline"));
8223
- var import_node_child_process6 = require("child_process");
8262
+ var import_node_child_process7 = require("child_process");
8224
8263
  var import_node_fs22 = require("fs");
8225
8264
  var import_node_path15 = require("path");
8226
8265
  var import_node_os8 = require("os");
@@ -10836,7 +10875,14 @@ async function pentestCommand(targetUrl) {
10836
10875
  } catch (err) {
10837
10876
  spinner.fail(`Failed to reach target: ${err.message}`);
10838
10877
  console.log(source_default.gray(" Check the URL and try again.\n"));
10839
- return;
10878
+ return {
10879
+ type: "pentest",
10880
+ target: targetUrl,
10881
+ findings: [],
10882
+ severity_summary: { critical: 0, high: 0, medium: 0, low: 0, info: 0 },
10883
+ summary: `Failed to reach target: ${err.message}`,
10884
+ error: err.message
10885
+ };
10840
10886
  }
10841
10887
  const sqliSpinner = ora({ text: "Testing SQL injection vectors...", color: "green" }).start();
10842
10888
  const sqliPayloads = ["' OR 1=1--", "1' UNION SELECT NULL--", "' AND '1'='1"];
@@ -11377,7 +11423,7 @@ async function sshConnect(options) {
11377
11423
  }
11378
11424
 
11379
11425
  // src/commands/daemon.ts
11380
- var import_node_child_process4 = require("child_process");
11426
+ var import_node_child_process5 = require("child_process");
11381
11427
  var import_node_fs18 = require("fs");
11382
11428
  var import_node_path12 = require("path");
11383
11429
  var import_node_fs19 = require("fs");
@@ -11581,6 +11627,7 @@ var IpcServer = class {
11581
11627
  // src/daemon/module-host.ts
11582
11628
  var import_node_fs16 = require("fs");
11583
11629
  var import_node_path10 = require("path");
11630
+ var import_node_url = require("url");
11584
11631
  var import_toml4 = __toESM(require_toml());
11585
11632
  init_paths();
11586
11633
 
@@ -11721,21 +11768,143 @@ var LogWatcher = class {
11721
11768
  }
11722
11769
  };
11723
11770
 
11771
+ // src/daemon/watchers/journal-watcher.ts
11772
+ var import_node_child_process4 = require("child_process");
11773
+ init_state();
11774
+ var JournalWatcher = class _JournalWatcher {
11775
+ constructor(bus2) {
11776
+ this.bus = bus2;
11777
+ }
11778
+ bus;
11779
+ proc = null;
11780
+ buffer = "";
11781
+ moduleName = "user-journal";
11782
+ active = false;
11783
+ static isAvailable() {
11784
+ const probe = (0, import_node_child_process4.spawnSync)("journalctl", ["--user", "-n", "0", "--no-pager"], {
11785
+ stdio: ["ignore", "ignore", "ignore"]
11786
+ });
11787
+ return probe.status === 0;
11788
+ }
11789
+ start() {
11790
+ if (!_JournalWatcher.isAvailable()) return false;
11791
+ const child = (0, import_node_child_process4.spawn)(
11792
+ "journalctl",
11793
+ ["--user", "-o", "json", "-f", "--since", "now"],
11794
+ { stdio: ["ignore", "pipe", "pipe"] }
11795
+ );
11796
+ if (!child.stdout) return false;
11797
+ child.stdout.setEncoding("utf-8");
11798
+ child.stdout.on("data", (chunk) => this.onData(chunk));
11799
+ child.on("exit", () => {
11800
+ this.proc = null;
11801
+ this.active = false;
11802
+ });
11803
+ this.proc = child;
11804
+ this.active = true;
11805
+ return true;
11806
+ }
11807
+ stop() {
11808
+ if (this.proc) {
11809
+ try {
11810
+ this.proc.kill("SIGTERM");
11811
+ } catch {
11812
+ }
11813
+ this.proc = null;
11814
+ }
11815
+ this.active = false;
11816
+ }
11817
+ isActive() {
11818
+ return this.active;
11819
+ }
11820
+ moduleNameValue() {
11821
+ return this.moduleName;
11822
+ }
11823
+ onData(chunk) {
11824
+ this.buffer += chunk;
11825
+ let idx;
11826
+ while ((idx = this.buffer.indexOf("\n")) >= 0) {
11827
+ const line = this.buffer.slice(0, idx);
11828
+ this.buffer = this.buffer.slice(idx + 1);
11829
+ if (!line.trim()) continue;
11830
+ this.handleLine(line);
11831
+ }
11832
+ }
11833
+ handleLine(line) {
11834
+ let entry;
11835
+ try {
11836
+ entry = JSON.parse(line);
11837
+ } catch {
11838
+ return;
11839
+ }
11840
+ const message = entry.MESSAGE;
11841
+ if (!message) return;
11842
+ const priority = parseInt(entry.PRIORITY ?? "6", 10);
11843
+ const severity = priorityToSeverity(priority);
11844
+ const ident = entry.SYSLOG_IDENTIFIER || entry._COMM || "journal";
11845
+ const bumpedSeverity = bumpForIdent(ident, message, severity);
11846
+ const event = {
11847
+ timestamp: realtimeToDate(entry.__REALTIME_TIMESTAMP) || /* @__PURE__ */ new Date(),
11848
+ module: this.moduleName,
11849
+ category: "system",
11850
+ severity: bumpedSeverity,
11851
+ message: `[${ident}] ${message}`.slice(0, 500)
11852
+ };
11853
+ try {
11854
+ insertEvent(event);
11855
+ } catch {
11856
+ }
11857
+ this.bus.publish(event);
11858
+ }
11859
+ };
11860
+ function priorityToSeverity(priority) {
11861
+ if (priority <= 2) return "critical";
11862
+ if (priority === 3) return "high";
11863
+ if (priority === 4) return "medium";
11864
+ if (priority === 5) return "low";
11865
+ return "info";
11866
+ }
11867
+ function bumpForIdent(ident, message, base) {
11868
+ if (/sudo/i.test(ident) && /authentication failure|incorrect password|FAILED/i.test(message)) {
11869
+ return "high";
11870
+ }
11871
+ if (/sshd/i.test(ident) && /failed|invalid user|break-in/i.test(message)) {
11872
+ return "high";
11873
+ }
11874
+ return base;
11875
+ }
11876
+ function realtimeToDate(rt) {
11877
+ if (!rt) return null;
11878
+ const us = parseInt(rt, 10);
11879
+ if (!Number.isFinite(us)) return null;
11880
+ return new Date(Math.floor(us / 1e3));
11881
+ }
11882
+
11724
11883
  // src/daemon/module-host.ts
11884
+ init_state();
11725
11885
  var ModuleHost = class {
11726
11886
  constructor(bus2) {
11727
11887
  this.bus = bus2;
11728
11888
  bus2.on("event", (event) => {
11729
11889
  const mod = this.modules.get(event.module);
11730
11890
  if (mod) mod.events++;
11891
+ for (const hosted of this.modules.values()) {
11892
+ if (hosted.status !== "running" || !hosted.instance?.onEvent) continue;
11893
+ void hosted.instance.onEvent(event).catch((err) => {
11894
+ hosted.status = "error";
11895
+ hosted.detail = `onEvent failed: ${String(err.message || err)}`;
11896
+ this.bus.announceModule(hosted.name, "error", hosted.detail);
11897
+ });
11898
+ }
11731
11899
  });
11732
11900
  }
11733
11901
  bus;
11734
11902
  modules = /* @__PURE__ */ new Map();
11735
11903
  logWatcher = null;
11904
+ journalWatcher = null;
11736
11905
  async start() {
11737
11906
  this.registerBuiltins();
11738
- this.discoverInstalled();
11907
+ await this.discoverAndStartInstalled();
11739
11908
  this.logWatcher = new LogWatcher(this.bus);
11740
11909
  const watched = this.logWatcher.start();
11741
11910
  for (const modName of this.logWatcher.activeModules()) {
@@ -11746,10 +11915,30 @@ var ModuleHost = class {
11746
11915
  this.bus.announceModule(modName, "running", mod.detail);
11747
11916
  }
11748
11917
  }
11918
+ this.journalWatcher = new JournalWatcher(this.bus);
11919
+ if (this.journalWatcher.start()) {
11920
+ const mod = this.modules.get("user-journal");
11921
+ if (mod) {
11922
+ mod.status = "running";
11923
+ mod.detail = "tailing journalctl --user";
11924
+ this.bus.announceModule("user-journal", "running", mod.detail);
11925
+ }
11926
+ }
11749
11927
  }
11750
11928
  async stop() {
11751
11929
  this.logWatcher?.stop();
11930
+ this.journalWatcher?.stop();
11752
11931
  for (const mod of this.modules.values()) {
11932
+ try {
11933
+ if (mod.instance && mod.status === "running") {
11934
+ await mod.instance.stop();
11935
+ }
11936
+ } catch (err) {
11937
+ mod.status = "error";
11938
+ mod.detail = `stop failed: ${String(err.message || err)}`;
11939
+ this.bus.announceModule(mod.name, "error", mod.detail);
11940
+ continue;
11941
+ }
11753
11942
  mod.status = "loaded";
11754
11943
  this.bus.announceModule(mod.name, "stopped");
11755
11944
  }
@@ -11765,12 +11954,14 @@ var ModuleHost = class {
11765
11954
  registerBuiltins() {
11766
11955
  const builtins = [
11767
11956
  { name: "log-watcher", version: "0.1.0", source: "builtin", status: "loaded", events: 0 },
11768
- { name: "ssh-guard", version: "0.1.0", source: "builtin", status: "loaded", events: 0 }
11957
+ { name: "ssh-guard", version: "0.1.0", source: "builtin", status: "loaded", events: 0 },
11958
+ { name: "user-journal", version: "0.1.0", source: "builtin", status: "loaded", events: 0 }
11769
11959
  ];
11770
11960
  for (const m of builtins) this.modules.set(m.name, m);
11771
11961
  }
11772
- discoverInstalled() {
11962
+ async discoverAndStartInstalled() {
11773
11963
  if (!(0, import_node_fs16.existsSync)(PATHS.moduleDir)) return;
11964
+ const configs = loadModuleConfigs(PATHS.confD);
11774
11965
  const entries = (0, import_node_fs16.readdirSync)(PATHS.moduleDir, { withFileTypes: true });
11775
11966
  for (const entry of entries) {
11776
11967
  if (!entry.isDirectory()) continue;
@@ -11779,16 +11970,113 @@ var ModuleHost = class {
11779
11970
  try {
11780
11971
  const manifest = import_toml4.default.parse((0, import_node_fs16.readFileSync)(manifestPath, "utf-8"));
11781
11972
  const name = manifest.module?.name || entry.name;
11782
- this.modules.set(name, {
11973
+ const defaults = manifest.module?.config?.defaults || {};
11974
+ const config = {
11975
+ enabled: true,
11976
+ ...defaults,
11977
+ ...configs.get(name) || {}
11978
+ };
11979
+ const hosted = {
11783
11980
  name,
11784
11981
  version: manifest.module?.version || "0.0.0",
11785
11982
  source: "installed",
11786
- status: "loaded",
11787
- events: 0
11983
+ status: config.enabled === false ? "disabled" : "loaded",
11984
+ events: 0,
11985
+ path: (0, import_node_path10.join)(PATHS.moduleDir, entry.name),
11986
+ config
11987
+ };
11988
+ this.modules.set(name, hosted);
11989
+ if (config.enabled === false) continue;
11990
+ await this.startInstalled(hosted);
11991
+ } catch (err) {
11992
+ const name = entry.name;
11993
+ this.modules.set(name, {
11994
+ name,
11995
+ version: "0.0.0",
11996
+ source: "installed",
11997
+ status: "error",
11998
+ events: 0,
11999
+ detail: `manifest load failed: ${String(err.message || err)}`,
12000
+ path: (0, import_node_path10.join)(PATHS.moduleDir, entry.name)
11788
12001
  });
12002
+ }
12003
+ }
12004
+ }
12005
+ async startInstalled(hosted) {
12006
+ const entrypoint = this.installedEntrypoint(hosted.path);
12007
+ if (!entrypoint) {
12008
+ hosted.status = "loaded";
12009
+ hosted.detail = "no built entrypoint found; run npm install && npm run build in the module directory";
12010
+ return;
12011
+ }
12012
+ try {
12013
+ const imported = await import((0, import_node_url.pathToFileURL)(entrypoint).href);
12014
+ const exported = imported.default || imported.module || imported;
12015
+ const instance = typeof exported === "function" ? new exported() : exported;
12016
+ if (!this.isThreatCrushModule(instance)) {
12017
+ throw new Error("entrypoint does not export a ThreatCrush module");
12018
+ }
12019
+ hosted.instance = instance;
12020
+ await instance.init(this.contextFor(hosted));
12021
+ await instance.start();
12022
+ hosted.status = "running";
12023
+ hosted.detail = `started from ${entrypoint}`;
12024
+ this.bus.announceModule(hosted.name, "running", hosted.detail);
12025
+ } catch (err) {
12026
+ hosted.status = "error";
12027
+ hosted.detail = String(err.message || err);
12028
+ this.bus.announceModule(hosted.name, "error", hosted.detail);
12029
+ }
12030
+ }
12031
+ installedEntrypoint(modulePath) {
12032
+ const packageJson = (0, import_node_path10.join)(modulePath, "package.json");
12033
+ const candidates = [];
12034
+ if ((0, import_node_fs16.existsSync)(packageJson)) {
12035
+ try {
12036
+ const pkg = JSON.parse((0, import_node_fs16.readFileSync)(packageJson, "utf-8"));
12037
+ if (pkg.main) candidates.push((0, import_node_path10.join)(modulePath, pkg.main));
11789
12038
  } catch {
11790
12039
  }
11791
12040
  }
12041
+ candidates.push((0, import_node_path10.join)(modulePath, "dist", "index.js"), (0, import_node_path10.join)(modulePath, "index.js"));
12042
+ return candidates.find((candidate) => (0, import_node_fs16.existsSync)(candidate)) || null;
12043
+ }
12044
+ isThreatCrushModule(value) {
12045
+ return Boolean(
12046
+ value && typeof value === "object" && typeof value.init === "function" && typeof value.start === "function" && typeof value.stop === "function"
12047
+ );
12048
+ }
12049
+ contextFor(hosted) {
12050
+ return {
12051
+ config: hosted.config || { enabled: true },
12052
+ logger: this.loggerFor(hosted.name),
12053
+ emit: (event) => this.bus.publish(event),
12054
+ subscribe: (eventType, handler) => {
12055
+ this.bus.on("event", (event) => {
12056
+ if (event.category === eventType || event.module === eventType) handler(event);
12057
+ });
12058
+ },
12059
+ alert: (alert) => {
12060
+ this.bus.emit("alert", alert.event || {
12061
+ timestamp: /* @__PURE__ */ new Date(),
12062
+ module: hosted.name,
12063
+ category: "system",
12064
+ severity: alert.severity,
12065
+ message: alert.title,
12066
+ details: alert.body ? { body: alert.body } : void 0
12067
+ });
12068
+ },
12069
+ getState: (key) => getModuleState(hosted.name, key),
12070
+ setState: (key, value) => setModuleState(hosted.name, key, value)
12071
+ };
12072
+ }
12073
+ loggerFor(moduleName) {
12074
+ return {
12075
+ debug: (msg, ...args) => console.debug(`[${moduleName}] ${msg}`, ...args),
12076
+ info: (msg, ...args) => console.info(`[${moduleName}] ${msg}`, ...args),
12077
+ warn: (msg, ...args) => console.warn(`[${moduleName}] ${msg}`, ...args),
12078
+ error: (msg, ...args) => console.error(`[${moduleName}] ${msg}`, ...args)
12079
+ };
11792
12080
  }
11793
12081
  };
11794
12082
 
@@ -12211,7 +12499,7 @@ async function daemonStart() {
12211
12499
  }
12212
12500
  const out = (0, import_node_fs19.openSync)(PATHS.logFile, "a");
12213
12501
  const err = (0, import_node_fs19.openSync)(PATHS.logFile, "a");
12214
- const child = (0, import_node_child_process4.spawn)(process.execPath, [DAEMON_ENTRY], {
12502
+ const child = (0, import_node_child_process5.spawn)(process.execPath, [DAEMON_ENTRY], {
12215
12503
  detached: true,
12216
12504
  stdio: ["ignore", out, err],
12217
12505
  env: { ...process.env, THREATCRUSH_DAEMON: "1" }
@@ -12276,7 +12564,7 @@ async function daemonStop() {
12276
12564
  }
12277
12565
 
12278
12566
  // src/commands/service.ts
12279
- var import_node_child_process5 = require("child_process");
12567
+ var import_node_child_process6 = require("child_process");
12280
12568
  var import_node_fs20 = require("fs");
12281
12569
  var import_node_path13 = require("path");
12282
12570
  var UNIT_PATH = "/etc/systemd/system/threatcrushd.service";
@@ -12291,7 +12579,7 @@ function resolveBinPath() {
12291
12579
  const arg = process.argv[1];
12292
12580
  if (arg && (0, import_node_fs20.existsSync)(arg)) return arg;
12293
12581
  try {
12294
- return (0, import_node_child_process5.execSync)("command -v threatcrush", { encoding: "utf-8" }).trim();
12582
+ return (0, import_node_child_process6.execSync)("command -v threatcrush", { encoding: "utf-8" }).trim();
12295
12583
  } catch {
12296
12584
  return "threatcrush";
12297
12585
  }
@@ -12313,8 +12601,8 @@ async function installServiceCommand() {
12313
12601
  (0, import_node_fs20.writeFileSync)(UNIT_PATH, unit, { mode: 420 });
12314
12602
  console.log(source_default.green(` \u2713 Installed unit file: ${UNIT_PATH}`));
12315
12603
  try {
12316
- (0, import_node_child_process5.execSync)("systemctl daemon-reload", { stdio: "inherit" });
12317
- (0, import_node_child_process5.execSync)("systemctl enable threatcrushd.service", { stdio: "inherit" });
12604
+ (0, import_node_child_process6.execSync)("systemctl daemon-reload", { stdio: "inherit" });
12605
+ (0, import_node_child_process6.execSync)("systemctl enable threatcrushd.service", { stdio: "inherit" });
12318
12606
  console.log(source_default.green(" \u2713 Service enabled on boot."));
12319
12607
  console.log(source_default.dim(" Start now with: systemctl start threatcrushd"));
12320
12608
  console.log(source_default.dim(" View logs with: journalctl -u threatcrushd -f"));
@@ -12333,22 +12621,22 @@ async function uninstallServiceCommand() {
12333
12621
  return;
12334
12622
  }
12335
12623
  try {
12336
- (0, import_node_child_process5.execSync)("systemctl stop threatcrushd.service", { stdio: "inherit" });
12624
+ (0, import_node_child_process6.execSync)("systemctl stop threatcrushd.service", { stdio: "inherit" });
12337
12625
  } catch {
12338
12626
  }
12339
12627
  try {
12340
- (0, import_node_child_process5.execSync)("systemctl disable threatcrushd.service", { stdio: "inherit" });
12628
+ (0, import_node_child_process6.execSync)("systemctl disable threatcrushd.service", { stdio: "inherit" });
12341
12629
  } catch {
12342
12630
  }
12343
12631
  try {
12344
12632
  if ((0, import_node_fs20.existsSync)(UNIT_PATH)) {
12345
- (0, import_node_child_process5.execSync)(`rm -f ${UNIT_PATH}`);
12633
+ (0, import_node_child_process6.execSync)(`rm -f ${UNIT_PATH}`);
12346
12634
  console.log(source_default.green(` \u2713 Removed unit file: ${UNIT_PATH}`));
12347
12635
  }
12348
12636
  } catch {
12349
12637
  }
12350
12638
  try {
12351
- (0, import_node_child_process5.execSync)("systemctl daemon-reload", { stdio: "inherit" });
12639
+ (0, import_node_child_process6.execSync)("systemctl daemon-reload", { stdio: "inherit" });
12352
12640
  } catch {
12353
12641
  }
12354
12642
  console.log(source_default.green(" \u2713 threatcrushd service removed."));
@@ -12908,22 +13196,22 @@ var DESKTOP_PKG_NAME = "@profullstack/threatcrush-desktop";
12908
13196
  var INSTALL_CONFIG_PATH = (0, import_node_path15.join)((0, import_node_os8.homedir)(), ".threatcrush", "install.json");
12909
13197
  function detectPackageManager() {
12910
13198
  try {
12911
- const npmGlobal = (0, import_node_child_process6.execSync)("npm ls -g --depth=0 --json 2>/dev/null", { encoding: "utf-8" });
13199
+ const npmGlobal = (0, import_node_child_process7.execSync)("npm ls -g --depth=0 --json 2>/dev/null", { encoding: "utf-8" });
12912
13200
  if (npmGlobal.includes(PKG_NAME)) return "npm";
12913
13201
  } catch {
12914
13202
  }
12915
13203
  try {
12916
- (0, import_node_child_process6.execSync)("pnpm --version", { stdio: "pipe" });
13204
+ (0, import_node_child_process7.execSync)("pnpm --version", { stdio: "pipe" });
12917
13205
  return "pnpm";
12918
13206
  } catch {
12919
13207
  }
12920
13208
  try {
12921
- (0, import_node_child_process6.execSync)("yarn --version", { stdio: "pipe" });
13209
+ (0, import_node_child_process7.execSync)("yarn --version", { stdio: "pipe" });
12922
13210
  return "yarn";
12923
13211
  } catch {
12924
13212
  }
12925
13213
  try {
12926
- (0, import_node_child_process6.execSync)("bun --version", { stdio: "pipe" });
13214
+ (0, import_node_child_process7.execSync)("bun --version", { stdio: "pipe" });
12927
13215
  return "bun";
12928
13216
  } catch {
12929
13217
  }
@@ -12969,7 +13257,7 @@ function packageLooksInstalled(pm, pkgName) {
12969
13257
  yarn: `yarn global list --pattern ${pkgName}`,
12970
13258
  bun: `bun pm ls -g`
12971
13259
  };
12972
- const output = (0, import_node_child_process6.execSync)(listCommands[pm] || listCommands.npm, {
13260
+ const output = (0, import_node_child_process7.execSync)(listCommands[pm] || listCommands.npm, {
12973
13261
  encoding: "utf-8",
12974
13262
  stdio: ["pipe", "pipe", "pipe"]
12975
13263
  });
@@ -13071,7 +13359,7 @@ program2.command("logs").description("Tail daemon logs").action(async () => {
13071
13359
  console.log(source_default.green(` Tailing ${logPath}...
13072
13360
  `));
13073
13361
  console.log(source_default.gray(" Press Ctrl+C to stop\n"));
13074
- (0, import_node_child_process6.execSync)(`tail -f ${logPath}`, { stdio: "inherit" });
13362
+ (0, import_node_child_process7.execSync)(`tail -f ${logPath}`, { stdio: "inherit" });
13075
13363
  });
13076
13364
  program2.command("activate").description("Activate your license key").action(async () => {
13077
13365
  console.log(LOGO2);
@@ -13121,7 +13409,7 @@ program2.command("update").description("Update ThreatCrush CLI and installed bun
13121
13409
  for (const cmd of commands2) {
13122
13410
  console.log(source_default.green(` \u2192 ${cmd}
13123
13411
  `));
13124
- (0, import_node_child_process6.execSync)(cmd, { stdio: "inherit" });
13412
+ (0, import_node_child_process7.execSync)(cmd, { stdio: "inherit" });
13125
13413
  }
13126
13414
  console.log(source_default.green("\n \u2713 Modules updated successfully!\n"));
13127
13415
  } catch (err) {
@@ -13147,7 +13435,7 @@ program2.command("update").description("Update ThreatCrush CLI and installed bun
13147
13435
  for (const cmd of commands) {
13148
13436
  console.log(source_default.green(` \u2192 ${cmd}
13149
13437
  `));
13150
- (0, import_node_child_process6.execSync)(cmd, { stdio: "inherit" });
13438
+ (0, import_node_child_process7.execSync)(cmd, { stdio: "inherit" });
13151
13439
  }
13152
13440
  console.log(source_default.green("\n \u2713 ThreatCrush updated successfully!\n"));
13153
13441
  if (installMode === "desktop") {
@@ -13191,7 +13479,7 @@ program2.command("remove").description("Uninstall ThreatCrush and the installed
13191
13479
  for (const cmd of commands) {
13192
13480
  console.log(source_default.green(` \u2192 ${cmd}
13193
13481
  `));
13194
- (0, import_node_child_process6.execSync)(cmd, { stdio: "inherit" });
13482
+ (0, import_node_child_process7.execSync)(cmd, { stdio: "inherit" });
13195
13483
  }
13196
13484
  console.log(source_default.green("\n \u2713 ThreatCrush has been uninstalled.\n"));
13197
13485
  console.log(source_default.dim(" We're sorry to see you go! \u{1F44B}\n"));