shieldcortex 3.2.1 → 3.2.2

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 (37) hide show
  1. package/README.md +11 -0
  2. package/dashboard/.next/standalone/dashboard/.next/BUILD_ID +1 -1
  3. package/dashboard/.next/standalone/dashboard/.next/build-manifest.json +2 -2
  4. package/dashboard/.next/standalone/dashboard/.next/server/app/_global-error.html +2 -2
  5. package/dashboard/.next/standalone/dashboard/.next/server/app/_global-error.rsc +1 -1
  6. package/dashboard/.next/standalone/dashboard/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  7. package/dashboard/.next/standalone/dashboard/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  8. package/dashboard/.next/standalone/dashboard/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  9. package/dashboard/.next/standalone/dashboard/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  10. package/dashboard/.next/standalone/dashboard/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  11. package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.html +1 -1
  12. package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.rsc +1 -1
  13. package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  14. package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  15. package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  16. package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  17. package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  18. package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  19. package/dashboard/.next/standalone/dashboard/.next/server/app/index.html +1 -1
  20. package/dashboard/.next/standalone/dashboard/.next/server/app/index.rsc +1 -1
  21. package/dashboard/.next/standalone/dashboard/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  22. package/dashboard/.next/standalone/dashboard/.next/server/app/index.segments/_full.segment.rsc +1 -1
  23. package/dashboard/.next/standalone/dashboard/.next/server/app/index.segments/_head.segment.rsc +1 -1
  24. package/dashboard/.next/standalone/dashboard/.next/server/app/index.segments/_index.segment.rsc +1 -1
  25. package/dashboard/.next/standalone/dashboard/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  26. package/dashboard/.next/standalone/dashboard/.next/server/pages/404.html +1 -1
  27. package/dashboard/.next/standalone/dashboard/.next/server/pages/500.html +2 -2
  28. package/dist/index.d.ts +5 -3
  29. package/dist/index.js +47 -6
  30. package/dist/service/install.d.ts +9 -4
  31. package/dist/service/install.js +74 -22
  32. package/dist/service/templates.d.ts +3 -1
  33. package/dist/service/templates.js +15 -5
  34. package/package.json +1 -1
  35. /package/dashboard/.next/standalone/dashboard/.next/static/{Oi8lTcFeUV-igSMtPHAG- → oBzpwAJXvCE6GMFQA3i9Q}/_buildManifest.js +0 -0
  36. /package/dashboard/.next/standalone/dashboard/.next/static/{Oi8lTcFeUV-igSMtPHAG- → oBzpwAJXvCE6GMFQA3i9Q}/_clientMiddlewareManifest.json +0 -0
  37. /package/dashboard/.next/standalone/dashboard/.next/static/{Oi8lTcFeUV-igSMtPHAG- → oBzpwAJXvCE6GMFQA3i9Q}/_ssgManifest.js +0 -0
package/dist/index.js CHANGED
@@ -10,6 +10,7 @@
10
10
  * shieldcortex --mode mcp # Start MCP server
11
11
  * shieldcortex --mode api # Start visualization API server
12
12
  * shieldcortex --mode both # Start both servers
13
+ * shieldcortex --mode worker # Start headless background worker
13
14
  * shieldcortex --dashboard # Start API + Dashboard (admin panel)
14
15
  * shieldcortex --db /path/to.db # Custom database path
15
16
  * shieldcortex scan "text" # Quick content scan (no MCP/ML)
@@ -24,9 +25,10 @@
24
25
  * shieldcortex hook pre-compact # Run pre-compact hook (for settings.json)
25
26
  * shieldcortex hook session-start # Run session-start hook (for settings.json)
26
27
  * shieldcortex hook session-end # Run session-end hook (for settings.json)
27
- * shieldcortex service install # Auto-start dashboard on login
28
- * shieldcortex service repair # Rebuild auto-start service with current install path
29
- * shieldcortex service uninstall # Remove auto-start
28
+ * shieldcortex service install # Install persistent ShieldCortex service
29
+ * shieldcortex service install --headless # Recommended for always-on servers
30
+ * shieldcortex service repair # Rebuild persistent service with current install path
31
+ * shieldcortex service uninstall # Remove persistent service
30
32
  * shieldcortex service status # Check service status
31
33
  * shieldcortex openclaw install # Install OpenClaw hook
32
34
  * shieldcortex openclaw uninstall # Remove OpenClaw hook
@@ -107,12 +109,18 @@ function parseArgs() {
107
109
  }
108
110
  else if (args[i] === '--mode' && args[i + 1]) {
109
111
  const mode = args[i + 1].toLowerCase();
110
- if (mode === 'mcp' || mode === 'api' || mode === 'both' || mode === 'dashboard') {
112
+ if (mode === 'mcp' || mode === 'api' || mode === 'both' || mode === 'dashboard' || mode === 'worker') {
111
113
  result.mode = mode;
112
114
  }
113
115
  i++;
114
116
  }
115
117
  }
118
+ if (args[0] === 'dashboard')
119
+ result.mode = 'dashboard';
120
+ if (args[0] === 'api')
121
+ result.mode = 'api';
122
+ if (args[0] === 'worker')
123
+ result.mode = 'worker';
116
124
  return result;
117
125
  }
118
126
  /**
@@ -298,6 +306,33 @@ function startDashboard() {
298
306
  });
299
307
  return dashboard;
300
308
  }
309
+ async function startWorkerMode(dbPath) {
310
+ const { initDatabase } = await import('./database/init.js');
311
+ const { startDefaultWorker } = await import('./worker/brain-worker.js');
312
+ initDatabase(dbPath);
313
+ startDefaultWorker();
314
+ console.log(`
315
+ ╔══════════════════════════════════════════════════════════════╗
316
+ ║ ShieldCortex Worker Service ║
317
+ ╠══════════════════════════════════════════════════════════════╣
318
+ ║ Running headless background worker ║
319
+ ║ Heartbeats keep this device online in ShieldCortex Cloud ║
320
+ ║ Sync retries and graph maintenance remain active ║
321
+ ╚══════════════════════════════════════════════════════════════╝
322
+ `);
323
+ const keepAlive = setInterval(() => {
324
+ // Intentionally empty. BrainWorker timers are unref()'d, so the service
325
+ // needs one referenced timer to remain alive as a daemon.
326
+ }, 60 * 60 * 1000);
327
+ const shutdown = (signal) => {
328
+ console.log(`\nReceived ${signal}, stopping ShieldCortex worker...`);
329
+ clearInterval(keepAlive);
330
+ stopDefaultWorker();
331
+ process.exit(0);
332
+ };
333
+ process.on('SIGINT', () => shutdown('SIGINT'));
334
+ process.on('SIGTERM', () => shutdown('SIGTERM'));
335
+ }
301
336
  function checkLocalHttp(url, expectedStatus = [200], timeoutMs = 1200) {
302
337
  return new Promise((resolve) => {
303
338
  const req = http.get(url, { timeout: timeoutMs }, (res) => {
@@ -339,6 +374,7 @@ ${bold}COMMANDS${reset}
339
374
  ${cyan}scan-skill${reset} <path> Scan an agent instruction file for threats
340
375
  ${cyan}scan-skills${reset} Scan all installed skills/hooks
341
376
  ${cyan}dashboard${reset} Open the local security dashboard
377
+ ${cyan}worker${reset} Run headless background sync + heartbeat worker
342
378
  ${cyan}status${reset} Show current protection status
343
379
  ${cyan}doctor${reset} Diagnose installation issues
344
380
  ${cyan}quickstart${reset} [target] Detect the fastest setup path
@@ -364,6 +400,7 @@ ${bold}EXAMPLES${reset}
364
400
  shieldcortex scan "ignore previous instructions"
365
401
  shieldcortex scan-skill ~/.claude/skills/my-skill/SKILL.md
366
402
  shieldcortex dashboard
403
+ shieldcortex worker
367
404
  shieldcortex license activate sc_pro_...
368
405
  shieldcortex config --cloud-enable --cloud-api-key <key>
369
406
  shieldcortex cloud sync --full
@@ -438,7 +475,7 @@ ${bold}DOCS${reset}
438
475
  }
439
476
  // Handle "service" subcommand before normal mode parsing
440
477
  if (process.argv[2] === 'service') {
441
- await handleServiceCommand(process.argv[3] || '');
478
+ await handleServiceCommand(process.argv[3] || '', process.argv.slice(4));
442
479
  return;
443
480
  }
444
481
  // Handle "config" subcommand (cloud sync configuration)
@@ -633,7 +670,7 @@ ${bold}DOCS${reset}
633
670
  'doctor', 'quickstart', 'setup', 'install', 'migrate', 'uninstall', 'hook',
634
671
  'openclaw', 'clawdbot', 'copilot', 'service', 'config', 'status',
635
672
  'graph', 'license', 'licence', 'audit', 'iron-dome', 'scan', 'cloud',
636
- 'scan-skill', 'scan-skills', 'dashboard', 'api',
673
+ 'scan-skill', 'scan-skills', 'dashboard', 'api', 'worker',
637
674
  ]);
638
675
  const arg = process.argv[2];
639
676
  if (arg && !arg.startsWith('-') && !knownCommands.has(arg)) {
@@ -708,6 +745,10 @@ ${bold}DOCS${reset}
708
745
  }
709
746
  await startMcpServer(dbPath);
710
747
  }
748
+ else if (mode === 'worker') {
749
+ console.log('Starting ShieldCortex in headless worker mode...');
750
+ await startWorkerMode(dbPath);
751
+ }
711
752
  else {
712
753
  // MCP mode (default) - for Claude Code integration
713
754
  await startMcpServer(dbPath);
@@ -1,15 +1,20 @@
1
1
  /**
2
- * Cross-platform service installer for ShieldCortex dashboard auto-start.
2
+ * Cross-platform service installer for persistent ShieldCortex background service.
3
3
  *
4
4
  * Supports:
5
5
  * - macOS: LaunchAgent plist
6
6
  * - Linux: systemd user service
7
7
  * - Windows: VBS script in Startup folder
8
8
  */
9
- export declare function installService(): Promise<void>;
10
- export declare function repairService(): Promise<void>;
9
+ import { type ServiceMode } from './templates.js';
10
+ interface ServiceOptions {
11
+ mode?: ServiceMode;
12
+ }
13
+ export declare function installService(options?: ServiceOptions): Promise<void>;
14
+ export declare function repairService(options?: ServiceOptions): Promise<void>;
11
15
  export declare function uninstallService(options?: {
12
16
  cleanLogs?: boolean;
13
17
  }): Promise<void>;
14
18
  export declare function serviceStatus(): Promise<void>;
15
- export declare function handleServiceCommand(subcommand: string): Promise<void>;
19
+ export declare function handleServiceCommand(subcommand: string, args?: string[]): Promise<void>;
20
+ export {};
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Cross-platform service installer for ShieldCortex dashboard auto-start.
2
+ * Cross-platform service installer for persistent ShieldCortex background service.
3
3
  *
4
4
  * Supports:
5
5
  * - macOS: LaunchAgent plist
@@ -21,7 +21,13 @@ function detectPlatform() {
21
21
  default: return 'linux';
22
22
  }
23
23
  }
24
- function getServiceConfig() {
24
+ function detectDefaultServiceMode(platform) {
25
+ if (platform === 'linux' && !process.env.DISPLAY && !process.env.WAYLAND_DISPLAY) {
26
+ return 'worker';
27
+ }
28
+ return 'dashboard';
29
+ }
30
+ function getServiceConfig(mode) {
25
31
  const logsDir = path.join(os.homedir(), '.shieldcortex', 'logs');
26
32
  fs.mkdirSync(logsDir, { recursive: true });
27
33
  return {
@@ -29,33 +35,40 @@ function getServiceConfig() {
29
35
  nodeBinDir: path.dirname(process.execPath),
30
36
  entryPoint: path.resolve(__dirname, '..', 'index.js'),
31
37
  logsDir,
38
+ mode,
32
39
  };
33
40
  }
34
41
  function inspectServiceEntryPoint(platform, servicePath) {
35
42
  if (!fs.existsSync(servicePath)) {
36
- return { entryPoint: null, stale: false };
43
+ return { entryPoint: null, stale: false, mode: null };
37
44
  }
38
45
  try {
39
46
  const content = fs.readFileSync(servicePath, 'utf-8');
40
47
  let entryPoint = null;
48
+ let mode = null;
41
49
  if (platform === 'macos') {
42
50
  const matches = [...content.matchAll(/<string>([^<]+)<\/string>/g)].map((match) => match[1]);
43
51
  entryPoint = matches.find((value) => value.endsWith('index.js')) ?? null;
52
+ mode = matches.find((value) => value === 'dashboard' || value === 'api' || value === 'worker') ?? null;
44
53
  }
45
54
  else if (platform === 'linux') {
46
55
  const match = content.match(/ExecStart=\S+\s+(\S+index\.js)/);
47
56
  entryPoint = match?.[1] ?? null;
57
+ const modeMatch = content.match(/ExecStart=\S+\s+\S+index\.js\s+--mode\s+(dashboard|api|worker)/);
58
+ mode = modeMatch?.[1] ?? null;
48
59
  }
49
60
  else {
50
61
  const match = content.match(/Run\s+\"\"[^\"]+\"\"\s+\"\"([^\"]+index\.js)\"\"/);
51
62
  entryPoint = match?.[1] ?? null;
63
+ const modeMatch = content.match(/--mode\s+(dashboard|api|worker)/);
64
+ mode = modeMatch?.[1] ?? null;
52
65
  }
53
- const currentEntryPoint = getServiceConfig().entryPoint;
66
+ const currentEntryPoint = getServiceConfig(detectDefaultServiceMode(platform)).entryPoint;
54
67
  const stale = !!entryPoint && (entryPoint.includes('/.npm/_npx/') || entryPoint !== currentEntryPoint);
55
- return { entryPoint, stale };
68
+ return { entryPoint, stale, mode };
56
69
  }
57
70
  catch {
58
- return { entryPoint: null, stale: false };
71
+ return { entryPoint: null, stale: false, mode: null };
59
72
  }
60
73
  }
61
74
  function getServicePath(platform) {
@@ -70,13 +83,33 @@ function getServicePath(platform) {
70
83
  }
71
84
  }
72
85
  }
73
- export async function installService() {
86
+ function summarizeServiceMode(mode) {
87
+ switch (mode) {
88
+ case 'worker':
89
+ return 'headless worker (recommended for servers and always-on cloud devices)';
90
+ case 'api':
91
+ return 'API service';
92
+ default:
93
+ return 'dashboard + API';
94
+ }
95
+ }
96
+ function tryEnableLinuxLinger() {
97
+ const username = process.env.USER || os.userInfo().username;
98
+ try {
99
+ execSync(`loginctl enable-linger "${username}"`, { stdio: 'ignore' });
100
+ console.log('Enabled systemd linger for persistent background service.');
101
+ }
102
+ catch {
103
+ console.log('Note: systemd linger was not enabled automatically.');
104
+ console.log(` On headless Linux servers, run: sudo loginctl enable-linger ${username}`);
105
+ }
106
+ }
107
+ export async function installService(options = {}) {
74
108
  const platform = detectPlatform();
75
- const config = getServiceConfig();
109
+ const mode = options.mode ?? detectDefaultServiceMode(platform);
110
+ const config = getServiceConfig(mode);
76
111
  const servicePath = getServicePath(platform);
77
- // Ensure parent directory exists
78
112
  fs.mkdirSync(path.dirname(servicePath), { recursive: true });
79
- // Generate and write service file
80
113
  let content;
81
114
  switch (platform) {
82
115
  case 'macos':
@@ -91,7 +124,6 @@ export async function installService() {
91
124
  }
92
125
  fs.writeFileSync(servicePath, content, 'utf-8');
93
126
  console.log(`Service file written to: ${servicePath}`);
94
- // Enable and start the service
95
127
  try {
96
128
  switch (platform) {
97
129
  case 'macos':
@@ -101,6 +133,9 @@ export async function installService() {
101
133
  case 'linux':
102
134
  execSync('systemctl --user daemon-reload', { stdio: 'inherit' });
103
135
  execSync('systemctl --user enable --now shieldcortex-dashboard.service', { stdio: 'inherit' });
136
+ if (mode === 'worker' || mode === 'api') {
137
+ tryEnableLinuxLinger();
138
+ }
104
139
  console.log('Service enabled via systemd.');
105
140
  break;
106
141
  case 'windows':
@@ -114,13 +149,22 @@ export async function installService() {
114
149
  console.log(`The service file was written to ${servicePath} — you can enable it manually.`);
115
150
  return;
116
151
  }
117
- console.log('\nShieldCortex dashboard will now auto-start on login.');
118
- console.log(` API: http://localhost:3001`);
119
- console.log(` Dashboard: http://localhost:3030`);
152
+ console.log(`\nShieldCortex ${summarizeServiceMode(mode)} will now auto-start.`);
153
+ if (mode === 'dashboard') {
154
+ console.log(' API: http://localhost:3001');
155
+ console.log(' Dashboard: http://localhost:3030');
156
+ }
157
+ else if (mode === 'api') {
158
+ console.log(' API: http://localhost:3001');
159
+ }
160
+ else {
161
+ console.log(' Heartbeat: keeps the device online in ShieldCortex Cloud');
162
+ console.log(' Sync: processes background memory/graph sync retries');
163
+ }
120
164
  }
121
- export async function repairService() {
165
+ export async function repairService(options = {}) {
122
166
  await uninstallService();
123
- await installService();
167
+ await installService(options);
124
168
  }
125
169
  function cleanLogsDirectory() {
126
170
  const logsDir = path.join(os.homedir(), '.shieldcortex', 'logs');
@@ -145,7 +189,6 @@ export async function uninstallService(options) {
145
189
  execSync('systemctl --user disable --now shieldcortex-dashboard.service', { stdio: 'inherit' });
146
190
  break;
147
191
  case 'windows':
148
- // Just delete the file — no daemon to stop
149
192
  break;
150
193
  }
151
194
  }
@@ -168,11 +211,11 @@ export async function serviceStatus() {
168
211
  console.log(`Path: ${servicePath}`);
169
212
  if (inspection.entryPoint) {
170
213
  console.log(`Entry: ${inspection.entryPoint}`);
214
+ console.log(`Mode: ${inspection.mode ?? 'unknown'}`);
171
215
  console.log(`Healthy: ${inspection.stale ? 'no (repair recommended)' : 'yes'}`);
172
216
  }
173
217
  if (!installed)
174
218
  return;
175
- // Check if running
176
219
  try {
177
220
  switch (platform) {
178
221
  case 'macos': {
@@ -198,13 +241,22 @@ export async function serviceStatus() {
198
241
  console.log('Repair: shieldcortex service repair');
199
242
  }
200
243
  }
201
- export async function handleServiceCommand(subcommand) {
244
+ function parseServiceModeArgs(args) {
245
+ if (args.includes('--dashboard'))
246
+ return 'dashboard';
247
+ if (args.includes('--api'))
248
+ return 'api';
249
+ if (args.includes('--headless') || args.includes('--worker'))
250
+ return 'worker';
251
+ return undefined;
252
+ }
253
+ export async function handleServiceCommand(subcommand, args = []) {
202
254
  switch (subcommand) {
203
255
  case 'install':
204
- await installService();
256
+ await installService({ mode: parseServiceModeArgs(args) });
205
257
  break;
206
258
  case 'repair':
207
- await repairService();
259
+ await repairService({ mode: parseServiceModeArgs(args) });
208
260
  break;
209
261
  case 'uninstall':
210
262
  await uninstallService({ cleanLogs: process.argv.includes('--clean-logs') });
@@ -213,7 +265,7 @@ export async function handleServiceCommand(subcommand) {
213
265
  await serviceStatus();
214
266
  break;
215
267
  default:
216
- console.log('Usage: shieldcortex service <install|repair|uninstall|status>');
268
+ console.log('Usage: shieldcortex service <install|repair|uninstall|status> [--dashboard|--api|--headless]');
217
269
  process.exit(1);
218
270
  }
219
271
  }
@@ -1,11 +1,13 @@
1
1
  /**
2
- * Platform-specific service file templates for auto-starting ShieldCortex dashboard.
2
+ * Platform-specific service file templates for auto-starting ShieldCortex.
3
3
  */
4
+ export type ServiceMode = 'dashboard' | 'api' | 'worker';
4
5
  export interface ServiceConfig {
5
6
  nodePath: string;
6
7
  nodeBinDir: string;
7
8
  entryPoint: string;
8
9
  logsDir: string;
10
+ mode: ServiceMode;
9
11
  }
10
12
  export declare function launchdPlist(config: ServiceConfig): string;
11
13
  export declare function systemdUnit(config: ServiceConfig): string;
@@ -1,6 +1,16 @@
1
1
  /**
2
- * Platform-specific service file templates for auto-starting ShieldCortex dashboard.
2
+ * Platform-specific service file templates for auto-starting ShieldCortex.
3
3
  */
4
+ function modeLabel(mode) {
5
+ switch (mode) {
6
+ case 'worker':
7
+ return 'Worker';
8
+ case 'api':
9
+ return 'API';
10
+ default:
11
+ return 'Dashboard';
12
+ }
13
+ }
4
14
  export function launchdPlist(config) {
5
15
  return `<?xml version="1.0" encoding="UTF-8"?>
6
16
  <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
@@ -13,7 +23,7 @@ export function launchdPlist(config) {
13
23
  <string>${config.nodePath}</string>
14
24
  <string>${config.entryPoint}</string>
15
25
  <string>--mode</string>
16
- <string>dashboard</string>
26
+ <string>${config.mode}</string>
17
27
  </array>
18
28
  <key>RunAtLoad</key>
19
29
  <true/>
@@ -33,12 +43,12 @@ export function launchdPlist(config) {
33
43
  }
34
44
  export function systemdUnit(config) {
35
45
  return `[Unit]
36
- Description=ShieldCortex Dashboard
46
+ Description=ShieldCortex ${modeLabel(config.mode)}
37
47
  After=network.target
38
48
 
39
49
  [Service]
40
50
  Type=simple
41
- ExecStart=${config.nodePath} ${config.entryPoint} --mode dashboard
51
+ ExecStart=${config.nodePath} ${config.entryPoint} --mode ${config.mode}
42
52
  Restart=on-failure
43
53
  RestartSec=5
44
54
  StandardOutput=append:${config.logsDir}/dashboard-stdout.log
@@ -53,5 +63,5 @@ export function windowsVbs(config) {
53
63
  const nodePath = config.nodePath.replace(/\//g, '\\');
54
64
  const entryPoint = config.entryPoint.replace(/\//g, '\\');
55
65
  return `Set WshShell = CreateObject("WScript.Shell")
56
- WshShell.Run """${nodePath}"" ""${entryPoint}"" --mode dashboard", 0, False`;
66
+ WshShell.Run """${nodePath}"" ""${entryPoint}"" --mode ${config.mode}", 0, False`;
57
67
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shieldcortex",
3
- "version": "3.2.1",
3
+ "version": "3.2.2",
4
4
  "description": "Trustworthy memory and security for AI agents. Recall debugging, review queue, OpenClaw session capture, and memory poisoning defence for Claude Code, OpenClaw, LangChain, and MCP agents.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",