@profullstack/threatcrush 0.1.14 → 0.1.16

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.
Files changed (3) hide show
  1. package/README.md +37 -4
  2. package/package.json +1 -1
  3. package/src/index.ts +101 -37
package/README.md CHANGED
@@ -1,3 +1,7 @@
1
+ <p align="center">
2
+ <a href="https://threatcrush.com"><img src="https://threatcrush.com/logo.svg" alt="ThreatCrush" width="120" /></a>
3
+ </p>
4
+
1
5
  <p align="center">
2
6
  <a href="https://www.npmjs.com/package/@profullstack/threatcrush"><img src="https://img.shields.io/npm/v/@profullstack/threatcrush?color=00ff41&style=flat-square&label=version" alt="npm version" /></a>
3
7
  <a href="https://www.npmjs.com/package/@profullstack/threatcrush"><img src="https://img.shields.io/npm/dm/@profullstack/threatcrush?color=00ff41&style=flat-square&label=downloads" alt="downloads" /></a>
@@ -10,12 +14,23 @@
10
14
 
11
15
  <h1 align="center">
12
16
  <br>
13
- 🛡️ ThreatCrush
17
+ ThreatCrush
14
18
  <br>
15
19
  </h1>
16
20
 
17
21
  <h4 align="center">All-in-one security agent — monitor, detect, scan, and protect servers in real-time.</h4>
18
22
 
23
+ <p align="center">
24
+ <img src="https://threatcrush.com/images/gallery-cli.png" alt="ThreatCrush CLI" width="48%" />
25
+ <img src="https://threatcrush.com/images/gallery-tui.png" alt="ThreatCrush TUI" width="48%" />
26
+ </p>
27
+ <p align="center">
28
+ <img src="https://threatcrush.com/images/gallery-desktop.png" alt="ThreatCrush Desktop" width="60%" />
29
+ </p>
30
+ <p align="center">
31
+ <img src="https://threatcrush.com/images/gallery-mobile.png" alt="ThreatCrush Mobile" width="30%" />
32
+ </p>
33
+
19
34
  <p align="center">
20
35
  <a href="https://threatcrush.com">Website</a> •
21
36
  <a href="#install">Install</a> •
@@ -43,15 +58,33 @@ $ threatcrush monitor
43
58
 
44
59
  ## Install
45
60
 
61
+ **Preferred install:**
62
+
46
63
  ```bash
47
- npm i -g @profullstack/threatcrush
64
+ curl -fsSL https://threatcrush.com/install.sh | sh
48
65
  ```
49
66
 
50
- Or with your preferred package manager:
67
+ The installer detects whether the machine is a server or desktop, uses your existing package manager when available, and can bootstrap Node.js with `mise` on bare machines.
68
+
69
+ - **Linux server** → installs the CLI
70
+ - **Linux desktop** → installs the CLI + desktop app
71
+ - **Windows desktop** → installs the desktop app to connect to a ThreatCrush server elsewhere
72
+ - **macOS desktop** → desktop-oriented install for connecting to a ThreatCrush server
73
+
74
+ After install, the supported lifecycle commands are:
51
75
 
52
76
  ```bash
77
+ threatcrush update # upgrades the installed bundle
78
+ threatcrush remove # removes the installed bundle
79
+ ```
80
+
81
+ Manual package-manager installs still work:
82
+
83
+ ```bash
84
+ npm i -g @profullstack/threatcrush
53
85
  pnpm add -g @profullstack/threatcrush
54
86
  yarn global add @profullstack/threatcrush
87
+ bun add -g @profullstack/threatcrush
55
88
  ```
56
89
 
57
90
  ## Usage
@@ -66,7 +99,7 @@ threatcrush init # Auto-detect services, generate config
66
99
  threatcrush status # Show daemon status & loaded modules
67
100
  threatcrush modules # Manage security modules
68
101
  threatcrush store # Browse the module marketplace
69
- threatcrush update # Update CLI & all modules
102
+ threatcrush update # Upgrade the CLI using the supported path
70
103
  ```
71
104
 
72
105
  ## Features
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@profullstack/threatcrush",
3
- "version": "0.1.14",
3
+ "version": "0.1.16",
4
4
  "description": "All-in-one security agent daemon — monitor, detect, scan, and protect servers in real-time",
5
5
  "bin": {
6
6
  "threatcrush": "./dist/index.js"
package/src/index.ts CHANGED
@@ -26,6 +26,8 @@ ${chalk.dim(" C R U S H")}
26
26
 
27
27
  const API_URL = process.env.THREATCRUSH_API_URL || "https://threatcrush.com";
28
28
  const PKG_NAME = "@profullstack/threatcrush";
29
+ const DESKTOP_PKG_NAME = "@profullstack/threatcrush-desktop";
30
+ const INSTALL_CONFIG_PATH = join(homedir(), ".threatcrush", "install.json");
29
31
 
30
32
  // ─── Helpers ───
31
33
 
@@ -96,6 +98,61 @@ function detectPackageManager(): string {
96
98
  return "npm";
97
99
  }
98
100
 
101
+ function readInstallConfig(): { installMode?: string; packageManager?: string; installMethod?: string } {
102
+ try {
103
+ return JSON.parse(readFileSync(INSTALL_CONFIG_PATH, "utf-8"));
104
+ } catch {
105
+ return {};
106
+ }
107
+ }
108
+
109
+ function getGlobalInstallCommand(pm: string, pkgName: string, action: "install" | "update" | "remove"): string {
110
+ const commands: Record<string, Record<string, string>> = {
111
+ npm: {
112
+ install: `npm i -g ${pkgName}`,
113
+ update: `npm update -g ${pkgName}`,
114
+ remove: `npm uninstall -g ${pkgName}`,
115
+ },
116
+ pnpm: {
117
+ install: `pnpm add -g ${pkgName}`,
118
+ update: `pnpm update -g ${pkgName}`,
119
+ remove: `pnpm remove -g ${pkgName}`,
120
+ },
121
+ yarn: {
122
+ install: `yarn global add ${pkgName}`,
123
+ update: `yarn global upgrade ${pkgName}`,
124
+ remove: `yarn global remove ${pkgName}`,
125
+ },
126
+ bun: {
127
+ install: `bun add -g ${pkgName}`,
128
+ update: `bun update -g ${pkgName}`,
129
+ remove: `bun remove -g ${pkgName}`,
130
+ },
131
+ };
132
+
133
+ return commands[pm]?.[action] || commands.npm[action];
134
+ }
135
+
136
+ function packageLooksInstalled(pm: string, pkgName: string): boolean {
137
+ try {
138
+ const listCommands: Record<string, string> = {
139
+ npm: `npm ls -g ${pkgName} --depth=0`,
140
+ pnpm: `pnpm list -g ${pkgName} --depth=0`,
141
+ yarn: `yarn global list --pattern ${pkgName}`,
142
+ bun: `bun pm ls -g`,
143
+ };
144
+
145
+ const output = execSync(listCommands[pm] || listCommands.npm, {
146
+ encoding: "utf-8",
147
+ stdio: ["pipe", "pipe", "pipe"],
148
+ });
149
+
150
+ return output.includes(pkgName);
151
+ } catch {
152
+ return false;
153
+ }
154
+ }
155
+
99
156
  // ─── Program ───
100
157
 
101
158
  const program = new Command();
@@ -167,9 +224,10 @@ gatedCommand("activate", "Activate your license key");
167
224
 
168
225
  program
169
226
  .command("update")
170
- .description("Update ThreatCrush CLI and all installed modules")
227
+ .description("Update ThreatCrush CLI and installed bundle")
171
228
  .option("--cli", "Update CLI only")
172
229
  .option("--modules", "Update modules only")
230
+ .option("--desktop", "Update desktop app too")
173
231
  .action(async (opts) => {
174
232
  console.log(LOGO);
175
233
 
@@ -179,42 +237,42 @@ program
179
237
  }
180
238
 
181
239
  const pm = detectPackageManager();
182
- console.log(chalk.dim(` Detected package manager: ${pm}\n`));
240
+ const installConfig = readInstallConfig();
241
+ const installMode = opts.cli ? "server" : (opts.desktop ? "desktop" : installConfig.installMode || "server");
183
242
 
184
- const commands: Record<string, string> = {
185
- npm: `npm update -g ${PKG_NAME}`,
186
- pnpm: `pnpm update -g ${PKG_NAME}`,
187
- yarn: `yarn global upgrade ${PKG_NAME}`,
188
- bun: `bun update -g ${PKG_NAME}`,
189
- };
243
+ console.log(chalk.dim(` Detected package manager: ${pm}`));
244
+ console.log(chalk.dim(` Install mode: ${installMode}\n`));
190
245
 
191
- const cmd = commands[pm] || commands.npm;
192
- console.log(chalk.green(` → ${cmd}\n`));
246
+ const commands = [getGlobalInstallCommand(pm, PKG_NAME, "update")];
247
+
248
+ if (installMode === "desktop") {
249
+ commands.push(getGlobalInstallCommand(pm, DESKTOP_PKG_NAME, "update"));
250
+ }
193
251
 
194
252
  try {
195
- execSync(cmd, { stdio: "inherit" });
196
- console.log(chalk.green("\n ThreatCrush updated successfully!\n"));
253
+ for (const cmd of commands) {
254
+ console.log(chalk.green(` ${cmd}\n`));
255
+ execSync(cmd, { stdio: "inherit" });
256
+ }
197
257
 
198
- // Show new version
199
- try {
200
- const newVersion = execSync(`${pm === "npm" ? "npm" : pm} list -g ${PKG_NAME} --depth=0`, {
201
- encoding: "utf-8",
202
- stdio: ["pipe", "pipe", "pipe"],
203
- });
204
- const match = newVersion.match(/@[\d.]+/);
205
- if (match) {
206
- console.log(chalk.dim(` Version: ${match[0]}\n`));
207
- }
208
- } catch {}
258
+ console.log(chalk.green("\n ✓ ThreatCrush updated successfully!\n"));
259
+ if (installMode === "desktop") {
260
+ console.log(chalk.dim(" Updated bundle: CLI + desktop app\n"));
261
+ } else {
262
+ console.log(chalk.dim(" Updated bundle: CLI only\n"));
263
+ }
209
264
  } catch (err) {
210
265
  console.log(chalk.red("\n ✗ Update failed. Try manually:\n"));
211
- console.log(chalk.dim(` ${cmd}\n`));
266
+ for (const cmd of commands) {
267
+ console.log(chalk.dim(` ${cmd}`));
268
+ }
269
+ console.log();
212
270
  }
213
271
  });
214
272
 
215
273
  program
216
274
  .command("remove")
217
- .description("Uninstall ThreatCrush CLI completely")
275
+ .description("Uninstall ThreatCrush and the installed bundle")
218
276
  .alias("uninstall")
219
277
  .action(async () => {
220
278
  console.log(LOGO);
@@ -233,28 +291,34 @@ program
233
291
  }
234
292
 
235
293
  const pm = detectPackageManager();
236
- console.log(chalk.dim(`\n Detected package manager: ${pm}\n`));
294
+ const installConfig = readInstallConfig();
295
+ const installMode = installConfig.installMode || "server";
296
+ const commands = [getGlobalInstallCommand(pm, PKG_NAME, "remove")];
237
297
 
238
- const commands: Record<string, string> = {
239
- npm: `npm uninstall -g ${PKG_NAME}`,
240
- pnpm: `pnpm remove -g ${PKG_NAME}`,
241
- yarn: `yarn global remove ${PKG_NAME}`,
242
- bun: `bun remove -g ${PKG_NAME}`,
243
- };
298
+ if (installMode === "desktop" && packageLooksInstalled(pm, DESKTOP_PKG_NAME)) {
299
+ commands.push(getGlobalInstallCommand(pm, DESKTOP_PKG_NAME, "remove"));
300
+ }
244
301
 
245
- const cmd = commands[pm] || commands.npm;
246
- console.log(chalk.green(` ${cmd}\n`));
302
+ console.log(chalk.dim(`\n Detected package manager: ${pm}`));
303
+ console.log(chalk.dim(` Install mode: ${installMode}\n`));
247
304
 
248
305
  try {
249
- execSync(cmd, { stdio: "inherit" });
306
+ for (const cmd of commands) {
307
+ console.log(chalk.green(` → ${cmd}\n`));
308
+ execSync(cmd, { stdio: "inherit" });
309
+ }
250
310
  console.log(chalk.green("\n ✓ ThreatCrush has been uninstalled.\n"));
251
311
  console.log(chalk.dim(" We're sorry to see you go! 👋\n"));
252
312
  console.log(chalk.dim(" Config files may remain at /etc/threatcrush/"));
253
313
  console.log(chalk.dim(" Logs may remain at /var/log/threatcrush/"));
254
- console.log(chalk.dim(" State may remain at /var/lib/threatcrush/\n"));
314
+ console.log(chalk.dim(" State may remain at /var/lib/threatcrush/"));
315
+ console.log(chalk.dim(` Local install metadata may remain at ${INSTALL_CONFIG_PATH}\n`));
255
316
  } catch (err) {
256
317
  console.log(chalk.red("\n ✗ Uninstall failed. Try manually:\n"));
257
- console.log(chalk.dim(` ${cmd}\n`));
318
+ for (const cmd of commands) {
319
+ console.log(chalk.dim(` ${cmd}`));
320
+ }
321
+ console.log();
258
322
  }
259
323
  });
260
324