shieldcortex 4.1.0 → 4.2.0
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/audit/dependency-scanner.d.ts +30 -1
- package/dist/audit/dependency-scanner.js +84 -2
- package/dist/audit/index.d.ts +1 -1
- package/dist/audit/index.js +1 -1
- package/dist/cli/audit.d.ts +3 -0
- package/dist/cli/audit.js +129 -2
- package/dist/license/gate.d.ts +1 -1
- package/dist/license/gate.js +18 -0
- package/package.json +1 -1
|
@@ -14,13 +14,42 @@
|
|
|
14
14
|
* shieldcortex audit --deps # scan ./node_modules
|
|
15
15
|
* shieldcortex audit --deps-global # scan global npm prefix
|
|
16
16
|
* shieldcortex audit --deps-path /some/path # scan specific path
|
|
17
|
+
* shieldcortex audit --deps --quarantine # scan + quarantine CRITICAL/HIGH
|
|
18
|
+
* shieldcortex audit --deps --clean --force # scan + permanently delete CRITICAL
|
|
19
|
+
* shieldcortex audit --deps --auto-protect # scan + auto-quarantine CRITICAL
|
|
17
20
|
*/
|
|
18
|
-
import type { ScannerResult } from './types.js';
|
|
21
|
+
import type { AuditFinding, ScannerResult } from './types.js';
|
|
19
22
|
/**
|
|
20
23
|
* Compute Levenshtein distance between two strings.
|
|
21
24
|
* Standard dynamic-programming implementation, no external deps.
|
|
22
25
|
*/
|
|
23
26
|
export declare function levenshtein(a: string, b: string): number;
|
|
27
|
+
export interface QuarantineManifest {
|
|
28
|
+
packageName: string;
|
|
29
|
+
version: string;
|
|
30
|
+
reason: string;
|
|
31
|
+
originalPath: string;
|
|
32
|
+
quarantinedAt: string;
|
|
33
|
+
severity: string;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Quarantine a package by moving it from node_modules to
|
|
37
|
+
* ~/.shieldcortex/quarantine/deps/<pkg>-<timestamp>/.
|
|
38
|
+
*
|
|
39
|
+
* Creates a manifest.json alongside the quarantined files.
|
|
40
|
+
* Only acts on CRITICAL and HIGH findings.
|
|
41
|
+
*
|
|
42
|
+
* @returns The quarantine destination path, or null if not quarantined.
|
|
43
|
+
*/
|
|
44
|
+
export declare function quarantinePackage(finding: AuditFinding, nodeModulesPath: string): string | null;
|
|
45
|
+
/**
|
|
46
|
+
* Permanently delete a malicious package from node_modules.
|
|
47
|
+
*
|
|
48
|
+
* Only acts on CRITICAL findings (known malicious packages from blocklist).
|
|
49
|
+
*
|
|
50
|
+
* @returns The package name that was deleted, or null if not deleted.
|
|
51
|
+
*/
|
|
52
|
+
export declare function cleanPackage(finding: AuditFinding, nodeModulesPath: string): string | null;
|
|
24
53
|
export interface DependencyScanOptions {
|
|
25
54
|
/** Absolute path to node_modules directory */
|
|
26
55
|
nodeModulesPath: string;
|
|
@@ -14,10 +14,14 @@
|
|
|
14
14
|
* shieldcortex audit --deps # scan ./node_modules
|
|
15
15
|
* shieldcortex audit --deps-global # scan global npm prefix
|
|
16
16
|
* shieldcortex audit --deps-path /some/path # scan specific path
|
|
17
|
+
* shieldcortex audit --deps --quarantine # scan + quarantine CRITICAL/HIGH
|
|
18
|
+
* shieldcortex audit --deps --clean --force # scan + permanently delete CRITICAL
|
|
19
|
+
* shieldcortex audit --deps --auto-protect # scan + auto-quarantine CRITICAL
|
|
17
20
|
*/
|
|
18
|
-
import { readdirSync, readFileSync, existsSync } from 'fs';
|
|
19
|
-
import { join } from 'path';
|
|
21
|
+
import { readdirSync, readFileSync, existsSync, mkdirSync, renameSync, rmSync, writeFileSync } from 'fs';
|
|
22
|
+
import { join, resolve } from 'path';
|
|
20
23
|
import { execSync } from 'child_process';
|
|
24
|
+
import { homedir } from 'os';
|
|
21
25
|
const LEARN_MORE_MALICIOUS = 'https://shieldcortex.ai/docs/threats/supply-chain';
|
|
22
26
|
const LEARN_MORE_TYPOSQUAT = 'https://shieldcortex.ai/docs/threats/typosquatting';
|
|
23
27
|
const LEARN_MORE_POSTINSTALL = 'https://shieldcortex.ai/docs/threats/malicious-scripts';
|
|
@@ -208,6 +212,84 @@ function checkPackageAge(pkg) {
|
|
|
208
212
|
const sevenDaysMs = 7 * 24 * 60 * 60 * 1000;
|
|
209
213
|
return ageMs < sevenDaysMs;
|
|
210
214
|
}
|
|
215
|
+
/**
|
|
216
|
+
* Quarantine a package by moving it from node_modules to
|
|
217
|
+
* ~/.shieldcortex/quarantine/deps/<pkg>-<timestamp>/.
|
|
218
|
+
*
|
|
219
|
+
* Creates a manifest.json alongside the quarantined files.
|
|
220
|
+
* Only acts on CRITICAL and HIGH findings.
|
|
221
|
+
*
|
|
222
|
+
* @returns The quarantine destination path, or null if not quarantined.
|
|
223
|
+
*/
|
|
224
|
+
export function quarantinePackage(finding, nodeModulesPath) {
|
|
225
|
+
// Only quarantine CRITICAL and HIGH
|
|
226
|
+
if (finding.severity !== 'critical' && finding.severity !== 'high') {
|
|
227
|
+
return null;
|
|
228
|
+
}
|
|
229
|
+
// Extract package name from the finding title heuristically
|
|
230
|
+
// Title examples:
|
|
231
|
+
// "Known malicious package: plain-crypto-js"
|
|
232
|
+
// "Possible typosquat: "axois" → "axios""
|
|
233
|
+
// "Suspicious install script in "bad-pkg""
|
|
234
|
+
const nameMatch = finding.title.match(/^Known malicious package:\s+(.+)$/) ??
|
|
235
|
+
finding.title.match(/^Possible typosquat:\s+"([^"]+)"/) ??
|
|
236
|
+
finding.title.match(/^Suspicious install script in\s+"([^"]+)"/);
|
|
237
|
+
const pkgName = nameMatch?.[1]?.trim();
|
|
238
|
+
if (!pkgName)
|
|
239
|
+
return null;
|
|
240
|
+
// Resolve source path
|
|
241
|
+
const pkgParts = pkgName.split('/');
|
|
242
|
+
const srcPath = resolve(join(nodeModulesPath, ...pkgParts));
|
|
243
|
+
if (!existsSync(srcPath))
|
|
244
|
+
return null;
|
|
245
|
+
// Determine version from package.json
|
|
246
|
+
const pkg = readPackageJson(srcPath);
|
|
247
|
+
const version = pkg?.version ?? 'unknown';
|
|
248
|
+
// Build quarantine destination
|
|
249
|
+
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
|
|
250
|
+
const safeName = pkgName.replace(/\//g, '__');
|
|
251
|
+
const quarantineBase = join(homedir(), '.shieldcortex', 'quarantine', 'deps');
|
|
252
|
+
const destDir = join(quarantineBase, `${safeName}-${timestamp}`);
|
|
253
|
+
const pkgDestDir = join(destDir, 'pkg');
|
|
254
|
+
mkdirSync(destDir, { recursive: true });
|
|
255
|
+
// Move the package directory
|
|
256
|
+
renameSync(srcPath, pkgDestDir);
|
|
257
|
+
// Write manifest
|
|
258
|
+
const manifest = {
|
|
259
|
+
packageName: pkgName,
|
|
260
|
+
version,
|
|
261
|
+
reason: finding.title,
|
|
262
|
+
originalPath: srcPath,
|
|
263
|
+
quarantinedAt: new Date().toISOString(),
|
|
264
|
+
severity: finding.severity,
|
|
265
|
+
};
|
|
266
|
+
writeFileSync(join(destDir, 'manifest.json'), JSON.stringify(manifest, null, 2));
|
|
267
|
+
return destDir;
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* Permanently delete a malicious package from node_modules.
|
|
271
|
+
*
|
|
272
|
+
* Only acts on CRITICAL findings (known malicious packages from blocklist).
|
|
273
|
+
*
|
|
274
|
+
* @returns The package name that was deleted, or null if not deleted.
|
|
275
|
+
*/
|
|
276
|
+
export function cleanPackage(finding, nodeModulesPath) {
|
|
277
|
+
// Only clean CRITICAL findings
|
|
278
|
+
if (finding.severity !== 'critical') {
|
|
279
|
+
return null;
|
|
280
|
+
}
|
|
281
|
+
// Extract package name from the finding title
|
|
282
|
+
const nameMatch = finding.title.match(/^Known malicious package:\s+(.+)$/);
|
|
283
|
+
const pkgName = nameMatch?.[1]?.trim();
|
|
284
|
+
if (!pkgName)
|
|
285
|
+
return null;
|
|
286
|
+
const pkgParts = pkgName.split('/');
|
|
287
|
+
const srcPath = resolve(join(nodeModulesPath, ...pkgParts));
|
|
288
|
+
if (!existsSync(srcPath))
|
|
289
|
+
return null;
|
|
290
|
+
rmSync(srcPath, { recursive: true, force: true });
|
|
291
|
+
return pkgName;
|
|
292
|
+
}
|
|
211
293
|
export function scanDependencies(opts) {
|
|
212
294
|
const start = Date.now();
|
|
213
295
|
const { nodeModulesPath } = opts;
|
package/dist/audit/index.d.ts
CHANGED
|
@@ -8,7 +8,7 @@ export { scanMemories } from './memory-scanner.js';
|
|
|
8
8
|
export { scanMcpConfigs } from './mcp-config-scanner.js';
|
|
9
9
|
export { scanEnvFiles } from './env-scanner.js';
|
|
10
10
|
export { scanRulesFiles } from './rules-file-scanner.js';
|
|
11
|
-
export { scanDependencies, resolveNodeModulesPath } from './dependency-scanner.js';
|
|
11
|
+
export { scanDependencies, resolveNodeModulesPath, quarantinePackage, cleanPackage } from './dependency-scanner.js';
|
|
12
12
|
export { formatTerminalReport, formatMarkdownReport, formatJsonReport } from './report-formatter.js';
|
|
13
13
|
export { calculateGrade } from './types.js';
|
|
14
14
|
export type { AuditFinding, AuditReport, AuditGrade, AuditSeverity, ScannerResult, } from './types.js';
|
package/dist/audit/index.js
CHANGED
|
@@ -8,6 +8,6 @@ export { scanMemories } from './memory-scanner.js';
|
|
|
8
8
|
export { scanMcpConfigs } from './mcp-config-scanner.js';
|
|
9
9
|
export { scanEnvFiles } from './env-scanner.js';
|
|
10
10
|
export { scanRulesFiles } from './rules-file-scanner.js';
|
|
11
|
-
export { scanDependencies, resolveNodeModulesPath } from './dependency-scanner.js';
|
|
11
|
+
export { scanDependencies, resolveNodeModulesPath, quarantinePackage, cleanPackage } from './dependency-scanner.js';
|
|
12
12
|
export { formatTerminalReport, formatMarkdownReport, formatJsonReport } from './report-formatter.js';
|
|
13
13
|
export { calculateGrade } from './types.js';
|
package/dist/cli/audit.d.ts
CHANGED
|
@@ -12,6 +12,9 @@
|
|
|
12
12
|
* npx shieldcortex audit --deps # Also scan ./node_modules for malicious packages
|
|
13
13
|
* npx shieldcortex audit --deps-global # Also scan global npm node_modules
|
|
14
14
|
* npx shieldcortex audit --deps-path /p # Also scan specific node_modules path
|
|
15
|
+
* npx shieldcortex audit --deps --quarantine # Scan + quarantine CRITICAL/HIGH
|
|
16
|
+
* npx shieldcortex audit --deps --clean --force # Scan + permanently delete CRITICAL
|
|
17
|
+
* npx shieldcortex audit --deps --auto-protect # Scan + auto-quarantine CRITICAL
|
|
15
18
|
*/
|
|
16
19
|
/**
|
|
17
20
|
* Run the full audit.
|
package/dist/cli/audit.js
CHANGED
|
@@ -12,14 +12,22 @@
|
|
|
12
12
|
* npx shieldcortex audit --deps # Also scan ./node_modules for malicious packages
|
|
13
13
|
* npx shieldcortex audit --deps-global # Also scan global npm node_modules
|
|
14
14
|
* npx shieldcortex audit --deps-path /p # Also scan specific node_modules path
|
|
15
|
+
* npx shieldcortex audit --deps --quarantine # Scan + quarantine CRITICAL/HIGH
|
|
16
|
+
* npx shieldcortex audit --deps --clean --force # Scan + permanently delete CRITICAL
|
|
17
|
+
* npx shieldcortex audit --deps --auto-protect # Scan + auto-quarantine CRITICAL
|
|
15
18
|
*/
|
|
16
|
-
import {
|
|
19
|
+
import { requireFeature, FeatureGatedError } from '../license/gate.js';
|
|
20
|
+
import { scanMemories, scanMcpConfigs, scanEnvFiles, scanRulesFiles, scanDependencies, resolveNodeModulesPath, quarantinePackage, cleanPackage, formatTerminalReport, formatMarkdownReport, formatJsonReport, calculateGrade, } from '../audit/index.js';
|
|
17
21
|
function parseAuditArgs(args) {
|
|
18
22
|
const options = {
|
|
19
23
|
format: 'terminal',
|
|
20
24
|
ci: false,
|
|
21
25
|
deps: false,
|
|
22
26
|
depsMode: 'local',
|
|
27
|
+
quarantine: false,
|
|
28
|
+
clean: false,
|
|
29
|
+
autoProtect: false,
|
|
30
|
+
force: false,
|
|
23
31
|
};
|
|
24
32
|
for (let i = 0; i < args.length; i++) {
|
|
25
33
|
const arg = args[i];
|
|
@@ -50,6 +58,21 @@ function parseAuditArgs(args) {
|
|
|
50
58
|
i++; // consume path argument
|
|
51
59
|
}
|
|
52
60
|
}
|
|
61
|
+
else if (arg === '--quarantine') {
|
|
62
|
+
options.quarantine = true;
|
|
63
|
+
options.deps = true;
|
|
64
|
+
}
|
|
65
|
+
else if (arg === '--clean') {
|
|
66
|
+
options.clean = true;
|
|
67
|
+
options.deps = true;
|
|
68
|
+
}
|
|
69
|
+
else if (arg === '--auto-protect') {
|
|
70
|
+
options.autoProtect = true;
|
|
71
|
+
options.deps = true;
|
|
72
|
+
}
|
|
73
|
+
else if (arg === '--force') {
|
|
74
|
+
options.force = true;
|
|
75
|
+
}
|
|
53
76
|
}
|
|
54
77
|
return options;
|
|
55
78
|
}
|
|
@@ -59,6 +82,13 @@ function parseAuditArgs(args) {
|
|
|
59
82
|
export async function handleAuditCommand(args) {
|
|
60
83
|
const options = parseAuditArgs(args);
|
|
61
84
|
const start = Date.now();
|
|
85
|
+
// --clean without --force: print warning and exit
|
|
86
|
+
if (options.clean && !options.force && !options.ci) {
|
|
87
|
+
console.error('\x1b[33m⚠ Are you sure? Use --force to confirm.\x1b[0m\n' +
|
|
88
|
+
' --clean permanently deletes CRITICAL packages from node_modules.\n' +
|
|
89
|
+
' Run: shieldcortex audit --deps --clean --force');
|
|
90
|
+
process.exit(1);
|
|
91
|
+
}
|
|
62
92
|
// Get version from package.json
|
|
63
93
|
let version = 'unknown';
|
|
64
94
|
try {
|
|
@@ -110,8 +140,9 @@ export async function handleAuditCommand(args) {
|
|
|
110
140
|
if (options.format === 'terminal')
|
|
111
141
|
process.stdout.write(`\r \x1b[32m[4/${totalSteps}]\x1b[0m Rules files \x1b[2m${rulesResult.durationMs}ms\x1b[0m\n`);
|
|
112
142
|
// Optional: dependency scan
|
|
143
|
+
let nodeModulesPath = '';
|
|
113
144
|
if (options.deps) {
|
|
114
|
-
|
|
145
|
+
nodeModulesPath = resolveNodeModulesPath(options.depsMode, options.depsPath);
|
|
115
146
|
if (options.format === 'terminal') {
|
|
116
147
|
process.stdout.write(` \x1b[2m[5/${totalSteps}] Dependencies (${nodeModulesPath})...\x1b[0m`);
|
|
117
148
|
}
|
|
@@ -160,6 +191,102 @@ export async function handleAuditCommand(args) {
|
|
|
160
191
|
console.log(formatTerminalReport(report));
|
|
161
192
|
break;
|
|
162
193
|
}
|
|
194
|
+
// ── Post-scan actions ────────────────────────────────────────────────────
|
|
195
|
+
const depFindings = allFindings.filter(f => f.scanner === 'dependency');
|
|
196
|
+
if (options.quarantine && depFindings.length > 0) {
|
|
197
|
+
try {
|
|
198
|
+
requireFeature('deps_quarantine');
|
|
199
|
+
}
|
|
200
|
+
catch (e) {
|
|
201
|
+
if (e instanceof FeatureGatedError) {
|
|
202
|
+
console.error('\n' + e.message);
|
|
203
|
+
process.exit(1);
|
|
204
|
+
}
|
|
205
|
+
throw e;
|
|
206
|
+
}
|
|
207
|
+
const eligible = depFindings.filter(f => f.severity === 'critical' || f.severity === 'high');
|
|
208
|
+
if (eligible.length === 0) {
|
|
209
|
+
if (options.format === 'terminal') {
|
|
210
|
+
console.log('\n\x1b[32m✓ No CRITICAL or HIGH dependency findings to quarantine.\x1b[0m');
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
else {
|
|
214
|
+
if (options.format === 'terminal') {
|
|
215
|
+
console.log(`\n\x1b[33m⚠ Quarantining ${eligible.length} package(s)...\x1b[0m`);
|
|
216
|
+
}
|
|
217
|
+
for (const finding of eligible) {
|
|
218
|
+
const dest = quarantinePackage(finding, nodeModulesPath);
|
|
219
|
+
if (dest && options.format === 'terminal') {
|
|
220
|
+
console.log(` \x1b[31m✗\x1b[0m Quarantined: ${finding.title}`);
|
|
221
|
+
console.log(` → ${dest}`);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
if (options.clean && depFindings.length > 0) {
|
|
227
|
+
try {
|
|
228
|
+
requireFeature('deps_clean');
|
|
229
|
+
}
|
|
230
|
+
catch (e) {
|
|
231
|
+
if (e instanceof FeatureGatedError) {
|
|
232
|
+
console.error('\n' + e.message);
|
|
233
|
+
process.exit(1);
|
|
234
|
+
}
|
|
235
|
+
throw e;
|
|
236
|
+
}
|
|
237
|
+
const criticals = depFindings.filter(f => f.severity === 'critical');
|
|
238
|
+
if (criticals.length === 0) {
|
|
239
|
+
if (options.format === 'terminal') {
|
|
240
|
+
console.log('\n\x1b[32m✓ No CRITICAL dependency findings to clean.\x1b[0m');
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
else {
|
|
244
|
+
if (options.format === 'terminal') {
|
|
245
|
+
console.log(`\n\x1b[31m🗑 Cleaning ${criticals.length} CRITICAL package(s)...\x1b[0m`);
|
|
246
|
+
}
|
|
247
|
+
for (const finding of criticals) {
|
|
248
|
+
const deleted = cleanPackage(finding, nodeModulesPath);
|
|
249
|
+
if (deleted && options.format === 'terminal') {
|
|
250
|
+
console.log(` \x1b[31m✗\x1b[0m Deleted: ${deleted}`);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
if (options.autoProtect && depFindings.length > 0) {
|
|
256
|
+
try {
|
|
257
|
+
requireFeature('deps_auto_protect');
|
|
258
|
+
}
|
|
259
|
+
catch (e) {
|
|
260
|
+
if (e instanceof FeatureGatedError) {
|
|
261
|
+
console.error('\n' + e.message);
|
|
262
|
+
process.exit(1);
|
|
263
|
+
}
|
|
264
|
+
throw e;
|
|
265
|
+
}
|
|
266
|
+
const criticals = depFindings.filter(f => f.severity === 'critical');
|
|
267
|
+
const highs = depFindings.filter(f => f.severity === 'high');
|
|
268
|
+
if (criticals.length > 0) {
|
|
269
|
+
if (options.format === 'terminal') {
|
|
270
|
+
console.log(`\n\x1b[33m⚠ Auto-protect: quarantining ${criticals.length} CRITICAL package(s)...\x1b[0m`);
|
|
271
|
+
}
|
|
272
|
+
for (const finding of criticals) {
|
|
273
|
+
const dest = quarantinePackage(finding, nodeModulesPath);
|
|
274
|
+
if (dest && options.format === 'terminal') {
|
|
275
|
+
console.log(` \x1b[31m✗\x1b[0m Quarantined: ${finding.title}`);
|
|
276
|
+
console.log(` → ${dest}`);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
if (highs.length > 0 && options.format === 'terminal') {
|
|
281
|
+
console.log(`\n\x1b[33m⚠ Auto-protect: ${highs.length} HIGH finding(s) detected (manual review required):\x1b[0m`);
|
|
282
|
+
for (const finding of highs) {
|
|
283
|
+
console.log(` \x1b[33m!\x1b[0m ${finding.title}`);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
if (criticals.length === 0 && highs.length === 0 && options.format === 'terminal') {
|
|
287
|
+
console.log('\n\x1b[32m✓ Auto-protect: no CRITICAL or HIGH dependency findings.\x1b[0m');
|
|
288
|
+
}
|
|
289
|
+
}
|
|
163
290
|
// Exit code
|
|
164
291
|
if (options.ci) {
|
|
165
292
|
// In CI mode: fail on critical or high findings
|
package/dist/license/gate.d.ts
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* isFeatureEnabled('cloud_sync'); // returns boolean (soft check)
|
|
7
7
|
*/
|
|
8
8
|
import { type LicenseTier } from './keys.js';
|
|
9
|
-
export type GatedFeature = 'custom_injection_patterns' | 'custom_iron_dome_policies' | 'custom_firewall_rules' | 'audit_export' | 'skill_scanner_deep' | 'cloud_sync' | 'team_management' | 'shared_patterns' | 'cortex_learning';
|
|
9
|
+
export type GatedFeature = 'custom_injection_patterns' | 'custom_iron_dome_policies' | 'custom_firewall_rules' | 'audit_export' | 'skill_scanner_deep' | 'cloud_sync' | 'team_management' | 'shared_patterns' | 'cortex_learning' | 'deps_quarantine' | 'deps_clean' | 'deps_auto_protect' | 'deps_global_scan' | 'memory_types' | 'memory_scopes' | 'dream_mode' | 'llm_reranking' | 'positive_feedback';
|
|
10
10
|
export declare class FeatureGatedError extends Error {
|
|
11
11
|
feature: GatedFeature;
|
|
12
12
|
requiredTier: LicenseTier;
|
package/dist/license/gate.js
CHANGED
|
@@ -17,6 +17,15 @@ const FEATURE_TIERS = {
|
|
|
17
17
|
team_management: 'team',
|
|
18
18
|
shared_patterns: 'team',
|
|
19
19
|
cortex_learning: 'pro',
|
|
20
|
+
deps_quarantine: 'pro',
|
|
21
|
+
deps_clean: 'pro',
|
|
22
|
+
deps_auto_protect: 'pro',
|
|
23
|
+
deps_global_scan: 'pro',
|
|
24
|
+
memory_types: 'pro',
|
|
25
|
+
memory_scopes: 'team',
|
|
26
|
+
dream_mode: 'pro',
|
|
27
|
+
llm_reranking: 'pro',
|
|
28
|
+
positive_feedback: 'pro',
|
|
20
29
|
};
|
|
21
30
|
const FEATURE_DESCRIPTIONS = {
|
|
22
31
|
custom_injection_patterns: 'Define up to 50 custom regex patterns for detecting domain-specific threats.',
|
|
@@ -28,6 +37,15 @@ const FEATURE_DESCRIPTIONS = {
|
|
|
28
37
|
team_management: 'Manage team members, invites, and shared security policies.',
|
|
29
38
|
shared_patterns: 'Share custom injection patterns and policies across your team.',
|
|
30
39
|
cortex_learning: 'Systematic mistake learning with pre-flight checks, pattern detection, and rule graduation.',
|
|
40
|
+
deps_quarantine: 'Quarantine malicious packages — move threats to a safe holding area.',
|
|
41
|
+
deps_clean: 'Permanently remove known malicious packages from your project.',
|
|
42
|
+
deps_auto_protect: 'Automated scan + quarantine of critical threats on every install.',
|
|
43
|
+
deps_global_scan: 'Scan global npm installations for supply chain threats.',
|
|
44
|
+
memory_types: 'Typed memories (user/feedback/project/reference) for structured knowledge.',
|
|
45
|
+
memory_scopes: 'Private vs team memory scopes for multi-agent deployments.',
|
|
46
|
+
dream_mode: 'Background memory consolidation — merge duplicates, archive stale, detect contradictions.',
|
|
47
|
+
llm_reranking: 'LLM-powered memory reranking for precision recall.',
|
|
48
|
+
positive_feedback: 'Capture what worked, not just what failed — learn from success.',
|
|
31
49
|
};
|
|
32
50
|
// ── Error class ──────────────────────────────────────────
|
|
33
51
|
export class FeatureGatedError extends Error {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "shieldcortex",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.2.0",
|
|
4
4
|
"description": "Trustworthy memory and security for AI agents. Recall debugging, review queue, OpenClaw session capture, and memory poisoning defence for Claude Code, Codex, OpenClaw, LangChain, and MCP agents.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|