shieldcortex 4.2.3 → 4.2.4
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/setup/openclaw.js +9 -3
- package/package.json +1 -1
- package/plugins/openclaw/dist/index.js +91 -83
package/dist/setup/openclaw.js
CHANGED
|
@@ -195,7 +195,12 @@ function preferredHookDir(hooksDir) {
|
|
|
195
195
|
return path.join(hooksDir, HOOK_NAME);
|
|
196
196
|
}
|
|
197
197
|
function legacyHookDirs(hooksDir) {
|
|
198
|
-
return [
|
|
198
|
+
return [
|
|
199
|
+
// Legacy: top-level "shieldcortex" directory created by old installers
|
|
200
|
+
path.join(hooksDir, 'shieldcortex'),
|
|
201
|
+
// Legacy: internal/cortex-memory path from v3 and early v4
|
|
202
|
+
path.join(hooksDir, 'internal', HOOK_NAME),
|
|
203
|
+
];
|
|
199
204
|
}
|
|
200
205
|
function hasRequiredHookFiles(dir) {
|
|
201
206
|
return HOOK_FILES.every(file => fs.existsSync(path.join(dir, file)));
|
|
@@ -631,9 +636,8 @@ export async function installOpenClawHook(options = {}) {
|
|
|
631
636
|
for (const hooksDir of hooksDirs) {
|
|
632
637
|
const destDir = preferredHookDir(hooksDir);
|
|
633
638
|
try {
|
|
639
|
+
// Clean up legacy paths BEFORE installing to avoid duplicate hooks
|
|
634
640
|
const legacyDirsBeforeInstall = detectLegacyHookVariants(hooksDir);
|
|
635
|
-
copyHookFiles(HOOK_SOURCE, destDir);
|
|
636
|
-
console.log(`Installed cortex-memory hook to ${destDir}`);
|
|
637
641
|
if (legacyDirsBeforeInstall.length > 0) {
|
|
638
642
|
console.log(`Detected legacy OpenClaw hook layout in ${hooksDir} — migrating to ${destDir}`);
|
|
639
643
|
}
|
|
@@ -641,6 +645,8 @@ export async function installOpenClawHook(options = {}) {
|
|
|
641
645
|
console.log(`Removed legacy cortex-memory hook from ${removedDir}`);
|
|
642
646
|
migratedLegacy++;
|
|
643
647
|
}
|
|
648
|
+
copyHookFiles(HOOK_SOURCE, destDir);
|
|
649
|
+
console.log(`Installed cortex-memory hook to ${destDir}`);
|
|
644
650
|
installed++;
|
|
645
651
|
}
|
|
646
652
|
catch (err) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "shieldcortex",
|
|
3
|
-
"version": "4.2.
|
|
3
|
+
"version": "4.2.4",
|
|
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",
|
|
@@ -584,95 +584,103 @@ export default {
|
|
|
584
584
|
jsonSchema: PLUGIN_CONFIG_JSON_SCHEMA,
|
|
585
585
|
},
|
|
586
586
|
register(api) {
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
587
|
+
try {
|
|
588
|
+
applyPluginConfigOverride(api);
|
|
589
|
+
// --- Interceptor (lazy init) ---
|
|
590
|
+
let interceptorReady = null;
|
|
591
|
+
let interceptorInitAttempted = false;
|
|
592
|
+
async function initInterceptor() {
|
|
593
|
+
if (interceptorInitAttempted)
|
|
594
|
+
return interceptorReady;
|
|
595
|
+
interceptorInitAttempted = true;
|
|
596
|
+
try {
|
|
597
|
+
const scConfig = await loadConfig();
|
|
598
|
+
const rawInterceptorConfig = scConfig.interceptor;
|
|
599
|
+
const interceptorConfig = {
|
|
600
|
+
...DEFAULT_INTERCEPTOR_CONFIG,
|
|
601
|
+
...(rawInterceptorConfig && typeof rawInterceptorConfig === 'object' ? {
|
|
602
|
+
enabled: rawInterceptorConfig.enabled ?? DEFAULT_INTERCEPTOR_CONFIG.enabled,
|
|
603
|
+
severityActions: { ...DEFAULT_INTERCEPTOR_CONFIG.severityActions, ...rawInterceptorConfig.severityActions },
|
|
604
|
+
failurePolicy: { ...DEFAULT_INTERCEPTOR_CONFIG.failurePolicy, ...rawInterceptorConfig.failurePolicy },
|
|
605
|
+
} : {}),
|
|
606
|
+
logger: { info: api.logger?.info ?? console.log, warn: api.logger?.warn ?? console.warn },
|
|
607
|
+
};
|
|
608
|
+
if (!interceptorConfig.enabled)
|
|
609
|
+
return null;
|
|
610
|
+
// Dynamic import with string variable to prevent TypeScript from resolving
|
|
611
|
+
// at compile time — 'shieldcortex/defence' only exists at runtime when the
|
|
612
|
+
// package is installed globally, not during CI builds of the plugin itself.
|
|
613
|
+
const defenceModPath = 'shieldcortex' + '/defence';
|
|
614
|
+
const defenceMod = await import(/* webpackIgnore: true */ defenceModPath);
|
|
615
|
+
if (typeof defenceMod.runDefencePipeline !== 'function')
|
|
616
|
+
return null;
|
|
617
|
+
interceptorReady = createInterceptor(interceptorConfig, defenceMod.runDefencePipeline, {
|
|
618
|
+
onAuditEntry: (entry) => syncInterceptEvent(entry, {
|
|
619
|
+
cloudApiKey: scConfig.cloudApiKey ?? '',
|
|
620
|
+
cloudBaseUrl: scConfig.cloudBaseUrl ?? 'https://api.shieldcortex.ai',
|
|
621
|
+
cloudEnabled: scConfig.cloudEnabled ?? false,
|
|
622
|
+
}),
|
|
623
|
+
});
|
|
624
|
+
api.logger?.info?.('[shieldcortex] Interceptor active — watching: remember, mcp__memory__remember');
|
|
625
|
+
return interceptorReady;
|
|
626
|
+
}
|
|
627
|
+
catch (err) {
|
|
628
|
+
api.logger?.warn?.(`[shieldcortex] Interceptor init failed: ${err instanceof Error ? err.message : err}`);
|
|
615
629
|
return null;
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
// Register before_tool_call with lazy-init wrapper
|
|
633
|
+
api.registerHook('before_tool_call', async (context) => {
|
|
634
|
+
const interceptor = await initInterceptor();
|
|
635
|
+
if (interceptor)
|
|
636
|
+
await interceptor.handleToolCall(context);
|
|
637
|
+
}, {
|
|
638
|
+
name: 'shieldcortex-intercept-tool',
|
|
639
|
+
description: 'Active threat gating on tool calls',
|
|
640
|
+
});
|
|
641
|
+
// Try to register session_end for cache cleanup
|
|
642
|
+
try {
|
|
643
|
+
api.registerHook('session_end', () => { interceptorReady?.resetSession(); }, {
|
|
644
|
+
name: 'shieldcortex-session-cleanup',
|
|
645
|
+
description: 'Clear interceptor deny cache on session end',
|
|
622
646
|
});
|
|
623
|
-
api.logger?.info?.('[shieldcortex] Interceptor active — watching: remember, mcp__memory__remember');
|
|
624
|
-
return interceptorReady;
|
|
625
647
|
}
|
|
626
|
-
catch
|
|
627
|
-
|
|
628
|
-
return null;
|
|
648
|
+
catch {
|
|
649
|
+
// session_end may not be a supported hook — TTL safety net handles this
|
|
629
650
|
}
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
651
|
+
// Explicit capability registration (replaces legacy api.on)
|
|
652
|
+
api.registerHook("llm_input", handleLlmInput, {
|
|
653
|
+
name: "shieldcortex-scan-input",
|
|
654
|
+
description: "Real-time threat scanning on LLM input",
|
|
655
|
+
});
|
|
656
|
+
api.registerHook("llm_output", handleLlmOutput, {
|
|
657
|
+
name: "shieldcortex-scan-output",
|
|
658
|
+
description: "Memory extraction from LLM output",
|
|
659
|
+
});
|
|
660
|
+
// Register a lightweight status command so the plugin is not hook-only
|
|
661
|
+
api.registerCommand({
|
|
662
|
+
name: "shieldcortex-status",
|
|
663
|
+
description: "Show ShieldCortex real-time scanner status",
|
|
664
|
+
async handler() {
|
|
665
|
+
const cfg = await loadConfig();
|
|
666
|
+
const autoMemory = isAutoMemoryEnabled(cfg) ? "on" : "off";
|
|
667
|
+
const dedupe = isAutoMemoryDedupeEnabled(cfg) ? "on" : "off";
|
|
668
|
+
const cloud = cfg.cloudApiKey ? "configured" : "not configured";
|
|
669
|
+
return {
|
|
670
|
+
text: `ShieldCortex v${_version}\n` +
|
|
671
|
+
` Hooks: llm_input (scan), llm_output (memory)\n` +
|
|
672
|
+
` Auto memory: ${autoMemory} | Dedupe: ${dedupe}\n` +
|
|
673
|
+
` Cloud sync: ${cloud}`,
|
|
674
|
+
};
|
|
675
|
+
},
|
|
645
676
|
});
|
|
677
|
+
api.logger.info(`[shieldcortex] v${_version} registered (llm_input + llm_output + before_tool_call + /shieldcortex-status)`);
|
|
646
678
|
}
|
|
647
|
-
catch {
|
|
648
|
-
//
|
|
679
|
+
catch (err) {
|
|
680
|
+
// Plugin must never block channel startup — warn and bail gracefully
|
|
681
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
682
|
+
console.warn(`[shieldcortex] WARNING: Plugin failed to initialize: ${msg}`);
|
|
683
|
+
console.warn('[shieldcortex] Real-time scanning is disabled. Channels will start normally.');
|
|
649
684
|
}
|
|
650
|
-
// Explicit capability registration (replaces legacy api.on)
|
|
651
|
-
api.registerHook("llm_input", handleLlmInput, {
|
|
652
|
-
name: "shieldcortex-scan-input",
|
|
653
|
-
description: "Real-time threat scanning on LLM input",
|
|
654
|
-
});
|
|
655
|
-
api.registerHook("llm_output", handleLlmOutput, {
|
|
656
|
-
name: "shieldcortex-scan-output",
|
|
657
|
-
description: "Memory extraction from LLM output",
|
|
658
|
-
});
|
|
659
|
-
// Register a lightweight status command so the plugin is not hook-only
|
|
660
|
-
api.registerCommand({
|
|
661
|
-
name: "shieldcortex-status",
|
|
662
|
-
description: "Show ShieldCortex real-time scanner status",
|
|
663
|
-
async handler() {
|
|
664
|
-
const cfg = await loadConfig();
|
|
665
|
-
const autoMemory = isAutoMemoryEnabled(cfg) ? "on" : "off";
|
|
666
|
-
const dedupe = isAutoMemoryDedupeEnabled(cfg) ? "on" : "off";
|
|
667
|
-
const cloud = cfg.cloudApiKey ? "configured" : "not configured";
|
|
668
|
-
return {
|
|
669
|
-
text: `ShieldCortex v${_version}\n` +
|
|
670
|
-
` Hooks: llm_input (scan), llm_output (memory)\n` +
|
|
671
|
-
` Auto memory: ${autoMemory} | Dedupe: ${dedupe}\n` +
|
|
672
|
-
` Cloud sync: ${cloud}`,
|
|
673
|
-
};
|
|
674
|
-
},
|
|
675
|
-
});
|
|
676
|
-
api.logger.info(`[shieldcortex] v${_version} registered (llm_input + llm_output + before_tool_call + /shieldcortex-status)`);
|
|
677
685
|
},
|
|
678
686
|
};
|