@profullstack/threatcrush 0.1.14 → 0.1.15
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/README.md +26 -4
- package/package.json +1 -1
- 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,7 +14,7 @@
|
|
|
10
14
|
|
|
11
15
|
<h1 align="center">
|
|
12
16
|
<br>
|
|
13
|
-
|
|
17
|
+
ThreatCrush
|
|
14
18
|
<br>
|
|
15
19
|
</h1>
|
|
16
20
|
|
|
@@ -43,15 +47,33 @@ $ threatcrush monitor
|
|
|
43
47
|
|
|
44
48
|
## Install
|
|
45
49
|
|
|
50
|
+
**Preferred install:**
|
|
51
|
+
|
|
46
52
|
```bash
|
|
47
|
-
|
|
53
|
+
curl -fsSL https://threatcrush.com/install.sh | sh
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
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.
|
|
57
|
+
|
|
58
|
+
- **Linux server** → installs the CLI
|
|
59
|
+
- **Linux desktop** → installs the CLI + desktop app
|
|
60
|
+
- **Windows desktop** → installs the desktop app to connect to a ThreatCrush server elsewhere
|
|
61
|
+
- **macOS desktop** → desktop-oriented install for connecting to a ThreatCrush server
|
|
62
|
+
|
|
63
|
+
After install, the supported lifecycle commands are:
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
threatcrush update # upgrades the installed bundle
|
|
67
|
+
threatcrush remove # removes the installed bundle
|
|
48
68
|
```
|
|
49
69
|
|
|
50
|
-
|
|
70
|
+
Manual package-manager installs still work:
|
|
51
71
|
|
|
52
72
|
```bash
|
|
73
|
+
npm i -g @profullstack/threatcrush
|
|
53
74
|
pnpm add -g @profullstack/threatcrush
|
|
54
75
|
yarn global add @profullstack/threatcrush
|
|
76
|
+
bun add -g @profullstack/threatcrush
|
|
55
77
|
```
|
|
56
78
|
|
|
57
79
|
## Usage
|
|
@@ -66,7 +88,7 @@ threatcrush init # Auto-detect services, generate config
|
|
|
66
88
|
threatcrush status # Show daemon status & loaded modules
|
|
67
89
|
threatcrush modules # Manage security modules
|
|
68
90
|
threatcrush store # Browse the module marketplace
|
|
69
|
-
threatcrush update #
|
|
91
|
+
threatcrush update # Upgrade the CLI using the supported path
|
|
70
92
|
```
|
|
71
93
|
|
|
72
94
|
## Features
|
package/package.json
CHANGED
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
|
|
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
|
-
|
|
240
|
+
const installConfig = readInstallConfig();
|
|
241
|
+
const installMode = opts.cli ? "server" : (opts.desktop ? "desktop" : installConfig.installMode || "server");
|
|
183
242
|
|
|
184
|
-
|
|
185
|
-
|
|
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
|
|
192
|
-
|
|
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
|
-
|
|
196
|
-
|
|
253
|
+
for (const cmd of commands) {
|
|
254
|
+
console.log(chalk.green(` → ${cmd}\n`));
|
|
255
|
+
execSync(cmd, { stdio: "inherit" });
|
|
256
|
+
}
|
|
197
257
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
294
|
+
const installConfig = readInstallConfig();
|
|
295
|
+
const installMode = installConfig.installMode || "server";
|
|
296
|
+
const commands = [getGlobalInstallCommand(pm, PKG_NAME, "remove")];
|
|
237
297
|
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
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
|
-
|
|
246
|
-
console.log(chalk.
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
318
|
+
for (const cmd of commands) {
|
|
319
|
+
console.log(chalk.dim(` ${cmd}`));
|
|
320
|
+
}
|
|
321
|
+
console.log();
|
|
258
322
|
}
|
|
259
323
|
});
|
|
260
324
|
|