shieldcortex 3.0.3 → 3.1.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.
Files changed (135) hide show
  1. package/README.md +5 -2
  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/prerender-manifest.json +3 -3
  5. package/dashboard/.next/standalone/dashboard/.next/required-server-files.json +4 -4
  6. package/dashboard/.next/standalone/dashboard/.next/server/app/_global-error.html +2 -2
  7. package/dashboard/.next/standalone/dashboard/.next/server/app/_global-error.rsc +1 -1
  8. package/dashboard/.next/standalone/dashboard/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  9. package/dashboard/.next/standalone/dashboard/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  10. package/dashboard/.next/standalone/dashboard/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  11. package/dashboard/.next/standalone/dashboard/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  12. package/dashboard/.next/standalone/dashboard/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  13. package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  14. package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.html +1 -1
  15. package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.rsc +2 -2
  16. package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.segments/_full.segment.rsc +2 -2
  17. package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  18. package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.segments/_index.segment.rsc +2 -2
  19. package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  20. package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  21. package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  22. package/dashboard/.next/standalone/dashboard/.next/server/app/index.html +1 -1
  23. package/dashboard/.next/standalone/dashboard/.next/server/app/index.rsc +3 -3
  24. package/dashboard/.next/standalone/dashboard/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  25. package/dashboard/.next/standalone/dashboard/.next/server/app/index.segments/_full.segment.rsc +3 -3
  26. package/dashboard/.next/standalone/dashboard/.next/server/app/index.segments/_head.segment.rsc +1 -1
  27. package/dashboard/.next/standalone/dashboard/.next/server/app/index.segments/_index.segment.rsc +2 -2
  28. package/dashboard/.next/standalone/dashboard/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  29. package/dashboard/.next/standalone/dashboard/.next/server/app/page/react-loadable-manifest.json +1 -1
  30. package/dashboard/.next/standalone/dashboard/.next/server/app/page_client-reference-manifest.js +1 -1
  31. package/dashboard/.next/standalone/dashboard/.next/server/chunks/ssr/dashboard_3051539d._.js +1 -1
  32. package/dashboard/.next/standalone/dashboard/.next/server/pages/404.html +1 -1
  33. package/dashboard/.next/standalone/dashboard/.next/server/pages/500.html +2 -2
  34. package/dashboard/.next/standalone/dashboard/.next/server/server-reference-manifest.js +1 -1
  35. package/dashboard/.next/standalone/dashboard/.next/server/server-reference-manifest.json +1 -1
  36. package/dashboard/.next/standalone/dashboard/.next/static/chunks/0a69eb25d08447ee.js +1 -0
  37. package/dashboard/.next/standalone/dashboard/.next/static/chunks/9232a2d99b47b21f.js +3 -0
  38. package/dashboard/.next/standalone/dashboard/.next/static/chunks/97537d3db46c8467.css +3 -0
  39. package/dashboard/.next/standalone/dashboard/.next/static/chunks/aa6e9b8a52353969.js +9 -0
  40. package/dashboard/.next/standalone/dashboard/node_modules/@img/sharp-darwin-arm64/lib/sharp-darwin-arm64.node +0 -0
  41. package/dashboard/.next/standalone/{node_modules/@img/sharp-linux-x64 → dashboard/node_modules/@img/sharp-darwin-arm64}/package.json +7 -13
  42. package/dashboard/.next/standalone/dashboard/node_modules/@img/{sharp-libvips-linux-x64 → sharp-libvips-darwin-arm64}/README.md +2 -2
  43. package/dashboard/.next/standalone/dashboard/node_modules/@img/{sharp-libvips-linux-x64 → sharp-libvips-darwin-arm64}/lib/glib-2.0/include/glibconfig.h +8 -9
  44. package/dashboard/.next/standalone/dashboard/node_modules/@img/{sharp-libvips-linux-x64/lib/libvips-cpp.so.8.17.3 → sharp-libvips-darwin-arm64/lib/libvips-cpp.8.17.3.dylib} +0 -0
  45. package/dashboard/.next/standalone/dashboard/node_modules/@img/{sharp-libvips-linux-x64 → sharp-libvips-darwin-arm64}/package.json +5 -11
  46. package/dashboard/.next/standalone/dashboard/server.js +1 -1
  47. package/dashboard/.next/standalone/{dashboard/node_modules/@img/sharp-linux-x64 → node_modules/@img/sharp-darwin-arm64}/package.json +7 -13
  48. package/dashboard/.next/standalone/node_modules/@img/{sharp-libvips-linux-x64 → sharp-libvips-darwin-arm64}/package.json +5 -11
  49. package/dist/api/routes/admin.d.ts +12 -0
  50. package/dist/api/routes/admin.js +502 -0
  51. package/dist/api/routes/graph.d.ts +4 -0
  52. package/dist/api/routes/graph.js +333 -0
  53. package/dist/api/routes/incidents.d.ts +2 -0
  54. package/dist/api/routes/incidents.js +32 -0
  55. package/dist/api/routes/memories.d.ts +4 -0
  56. package/dist/api/routes/memories.js +659 -0
  57. package/dist/api/routes/recall.d.ts +4 -0
  58. package/dist/api/routes/recall.js +36 -0
  59. package/dist/api/routes/system.d.ts +9 -0
  60. package/dist/api/routes/system.js +266 -0
  61. package/dist/api/visualization-server.js +31 -1913
  62. package/dist/cloud/cli.d.ts +1 -0
  63. package/dist/cloud/cli.js +40 -0
  64. package/dist/cloud/config.d.ts +10 -0
  65. package/dist/cloud/config.js +54 -0
  66. package/dist/cloud/graph-sync.d.ts +45 -0
  67. package/dist/cloud/graph-sync.js +257 -0
  68. package/dist/cloud/memory-sync.d.ts +36 -0
  69. package/dist/cloud/memory-sync.js +183 -0
  70. package/dist/cloud/sync-queue.d.ts +24 -0
  71. package/dist/cloud/sync-queue.js +126 -7
  72. package/dist/database/init.js +24 -0
  73. package/dist/graph/backfill.js +3 -5
  74. package/dist/graph/resolve.d.ts +10 -0
  75. package/dist/graph/resolve.js +63 -1
  76. package/dist/index.d.ts +2 -0
  77. package/dist/index.js +61 -4
  78. package/dist/memory/search.d.ts +37 -0
  79. package/dist/memory/search.js +143 -0
  80. package/dist/memory/store.js +47 -171
  81. package/dist/memory/types.d.ts +2 -0
  82. package/dist/service/install.d.ts +1 -0
  83. package/dist/service/install.js +43 -1
  84. package/dist/tools/recall.d.ts +1 -1
  85. package/hooks/openclaw/cortex-memory/handler.ts +5 -141
  86. package/hooks/openclaw/cortex-memory/runtime.mjs +129 -0
  87. package/package.json +8 -4
  88. package/plugins/openclaw/dist/index.js +5 -39
  89. package/scripts/run-jest.mjs +25 -1
  90. package/dashboard/.next/standalone/dashboard/.next/static/chunks/be6970da20a17c0b.js +0 -9
  91. package/dashboard/.next/standalone/dashboard/.next/static/chunks/e63d2228780629dd.css +0 -3
  92. package/dashboard/.next/standalone/dashboard/.next/static/chunks/f69fd1c5e71fbbfd.js +0 -1
  93. package/dashboard/.next/standalone/dashboard/.next/static/chunks/fa5217550a8ab9a6.js +0 -3
  94. package/dashboard/.next/standalone/dashboard/node_modules/@img/sharp-libvips-linuxmusl-x64/README.md +0 -46
  95. package/dashboard/.next/standalone/dashboard/node_modules/@img/sharp-libvips-linuxmusl-x64/lib/glib-2.0/include/glibconfig.h +0 -221
  96. package/dashboard/.next/standalone/dashboard/node_modules/@img/sharp-libvips-linuxmusl-x64/lib/index.js +0 -1
  97. package/dashboard/.next/standalone/dashboard/node_modules/@img/sharp-libvips-linuxmusl-x64/lib/libvips-cpp.so.8.17.3 +0 -0
  98. package/dashboard/.next/standalone/dashboard/node_modules/@img/sharp-libvips-linuxmusl-x64/package.json +0 -42
  99. package/dashboard/.next/standalone/dashboard/node_modules/@img/sharp-libvips-linuxmusl-x64/versions.json +0 -30
  100. package/dashboard/.next/standalone/dashboard/node_modules/@img/sharp-linux-x64/lib/sharp-linux-x64.node +0 -0
  101. package/dashboard/.next/standalone/dashboard/node_modules/@img/sharp-linuxmusl-x64/lib/sharp-linuxmusl-x64.node +0 -0
  102. package/dashboard/.next/standalone/dashboard/node_modules/@img/sharp-linuxmusl-x64/package.json +0 -46
  103. package/dashboard/.next/standalone/dashboard/node_modules/typescript/lib/_tsc.js +0 -133818
  104. package/dashboard/.next/standalone/dashboard/node_modules/typescript/lib/_tsserver.js +0 -659
  105. package/dashboard/.next/standalone/dashboard/node_modules/typescript/lib/_typingsInstaller.js +0 -222
  106. package/dashboard/.next/standalone/dashboard/node_modules/typescript/lib/cs/diagnosticMessages.generated.json +0 -2122
  107. package/dashboard/.next/standalone/dashboard/node_modules/typescript/lib/de/diagnosticMessages.generated.json +0 -2122
  108. package/dashboard/.next/standalone/dashboard/node_modules/typescript/lib/es/diagnosticMessages.generated.json +0 -2122
  109. package/dashboard/.next/standalone/dashboard/node_modules/typescript/lib/fr/diagnosticMessages.generated.json +0 -2122
  110. package/dashboard/.next/standalone/dashboard/node_modules/typescript/lib/it/diagnosticMessages.generated.json +0 -2122
  111. package/dashboard/.next/standalone/dashboard/node_modules/typescript/lib/ja/diagnosticMessages.generated.json +0 -2122
  112. package/dashboard/.next/standalone/dashboard/node_modules/typescript/lib/ko/diagnosticMessages.generated.json +0 -2122
  113. package/dashboard/.next/standalone/dashboard/node_modules/typescript/lib/pl/diagnosticMessages.generated.json +0 -2122
  114. package/dashboard/.next/standalone/dashboard/node_modules/typescript/lib/pt-br/diagnosticMessages.generated.json +0 -2122
  115. package/dashboard/.next/standalone/dashboard/node_modules/typescript/lib/ru/diagnosticMessages.generated.json +0 -2122
  116. package/dashboard/.next/standalone/dashboard/node_modules/typescript/lib/tr/diagnosticMessages.generated.json +0 -2122
  117. package/dashboard/.next/standalone/dashboard/node_modules/typescript/lib/tsc.js +0 -8
  118. package/dashboard/.next/standalone/dashboard/node_modules/typescript/lib/tsserver.js +0 -8
  119. package/dashboard/.next/standalone/dashboard/node_modules/typescript/lib/tsserverlibrary.js +0 -21
  120. package/dashboard/.next/standalone/dashboard/node_modules/typescript/lib/typesMap.json +0 -497
  121. package/dashboard/.next/standalone/dashboard/node_modules/typescript/lib/typescript.js +0 -200276
  122. package/dashboard/.next/standalone/dashboard/node_modules/typescript/lib/typingsInstaller.js +0 -8
  123. package/dashboard/.next/standalone/dashboard/node_modules/typescript/lib/watchGuard.js +0 -53
  124. package/dashboard/.next/standalone/dashboard/node_modules/typescript/lib/zh-cn/diagnosticMessages.generated.json +0 -2122
  125. package/dashboard/.next/standalone/dashboard/node_modules/typescript/lib/zh-tw/diagnosticMessages.generated.json +0 -2122
  126. package/dashboard/.next/standalone/dashboard/node_modules/typescript/package.json +0 -120
  127. package/dashboard/.next/standalone/node_modules/@img/sharp-libvips-linuxmusl-x64/package.json +0 -42
  128. package/dashboard/.next/standalone/node_modules/@img/sharp-linuxmusl-x64/package.json +0 -46
  129. package/scripts/start-dashboard.sh +0 -41
  130. package/scripts/stop-dashboard.sh +0 -21
  131. /package/dashboard/.next/standalone/dashboard/.next/static/{THy6JENQ0c1sq6jQhvIDp → RnvqrTXo_jN8SuMdaNcIj}/_buildManifest.js +0 -0
  132. /package/dashboard/.next/standalone/dashboard/.next/static/{THy6JENQ0c1sq6jQhvIDp → RnvqrTXo_jN8SuMdaNcIj}/_clientMiddlewareManifest.json +0 -0
  133. /package/dashboard/.next/standalone/dashboard/.next/static/{THy6JENQ0c1sq6jQhvIDp → RnvqrTXo_jN8SuMdaNcIj}/_ssgManifest.js +0 -0
  134. /package/dashboard/.next/standalone/dashboard/node_modules/@img/{sharp-libvips-linux-x64 → sharp-libvips-darwin-arm64}/lib/index.js +0 -0
  135. /package/dashboard/.next/standalone/dashboard/node_modules/@img/{sharp-libvips-linux-x64 → sharp-libvips-darwin-arm64}/versions.json +0 -0
@@ -6,158 +6,22 @@
6
6
  * - Context injection on agent bootstrap
7
7
  * - Keyword-triggered memory saves
8
8
  */
9
- import { execFile } from "node:child_process";
10
9
  import { createHash } from "node:crypto";
11
10
  import fs from "node:fs/promises";
12
11
  import { homedir } from "node:os";
13
12
  import path from "node:path";
13
+ import { createOpenClawRuntime } from "./runtime.mjs";
14
14
 
15
15
  // ==================== SERVER COMMAND RESOLUTION ====================
16
16
 
17
- let _shieldConfig = null;
18
17
  let _autoMemoryNoticeShown = false;
19
-
20
- async function loadShieldConfig() {
21
- if (_shieldConfig) return _shieldConfig;
22
-
23
- try {
24
- const configPath = path.join(homedir(), ".shieldcortex", "config.json");
25
- _shieldConfig = JSON.parse(await fs.readFile(configPath, "utf-8"));
26
- } catch {
27
- _shieldConfig = {};
28
- }
29
-
30
- return _shieldConfig;
31
- }
18
+ const runtime = createOpenClawRuntime({ logPrefix: "[cortex-memory]" });
19
+ const loadShieldConfig = runtime.loadShieldConfig;
20
+ const callCortex = runtime.callCortex;
32
21
 
33
22
  async function isOpenClawAutoMemoryEnabled() {
34
23
  const config = await loadShieldConfig();
35
- // Default OFF — OpenClaw has its own memory system. User must explicitly opt in.
36
- return config?.openclawAutoMemory === true;
37
- }
38
-
39
- /**
40
- * Resolve the fastest way to invoke shieldcortex:
41
- * 1. ~/.shieldcortex/config.json "binaryPath" override
42
- * 2. Global install detected via `which shieldcortex`
43
- * 3. Fallback to `npx -y shieldcortex` (slow on ARM64)
44
- */
45
- let _resolvedServerCmd = null;
46
-
47
- async function resolveServerCmd() {
48
- if (_resolvedServerCmd) return _resolvedServerCmd;
49
-
50
- // 1. Check config for explicit binaryPath
51
- try {
52
- const config = await loadShieldConfig();
53
- if (config?.binaryPath) {
54
- await fs.access(config.binaryPath);
55
- _resolvedServerCmd = config.binaryPath;
56
- console.log(`[cortex-memory] Using configured binary: ${config.binaryPath}`);
57
- return _resolvedServerCmd;
58
- }
59
- } catch { /* Config not found, no binaryPath, or path invalid */ }
60
-
61
- // 2. Try to find global install via `which`
62
- try {
63
- const { execFileSync } = await import("node:child_process");
64
- const bin = execFileSync("which", ["shieldcortex"], {
65
- encoding: "utf-8",
66
- timeout: 3000,
67
- }).trim();
68
- if (bin) {
69
- _resolvedServerCmd = bin;
70
- console.log(`[cortex-memory] Using global install: ${bin}`);
71
- return _resolvedServerCmd;
72
- }
73
- } catch { /* Not in PATH */ }
74
-
75
- // 3. Fall back to npx (slow but always works)
76
- _resolvedServerCmd = "npx -y shieldcortex";
77
- console.log("[cortex-memory] Falling back to npx -y shieldcortex (slow path)");
78
- return _resolvedServerCmd;
79
- }
80
-
81
- // ==================== CORTEX MCP HELPER ====================
82
-
83
- let _lastCallErrorType = null;
84
-
85
- function classifyCallError(err) {
86
- if (err.killed || err.code === "ETIMEDOUT" || err.signal === "SIGTERM") return "timeout";
87
- if (/ENOENT|not found|command not found/i.test(err.message || "")) return "not-found";
88
- if (/mcporter/i.test(err.message || "")) return "mcporter";
89
- return "unknown";
90
- }
91
-
92
- /**
93
- * Call a ShieldCortex MCP tool via mcporter
94
- * @param {string} tool - Tool name (e.g., "remember", "recall", "get_context")
95
- * @param {Record<string, string>} args - Tool arguments as key:value pairs
96
- * @param {object} options - Options { retries: number, timeout: number }
97
- * @returns {Promise<string|null>} Raw stdout or null on error
98
- */
99
- async function callCortex(tool, args = {}, options = { retries: 1, timeout: 15000 }) {
100
- const serverCmd = await resolveServerCmd();
101
-
102
- return new Promise((resolve) => {
103
- const cmdArgs = [
104
- "mcporter", "call", "--stdio",
105
- serverCmd,
106
- tool,
107
- ];
108
- for (const [key, value] of Object.entries(args)) {
109
- // Escape single quotes by doubling them (FTS5-safe)
110
- const safe = String(value).replace(/'/g, "''");
111
- cmdArgs.push(`${key}:${safe}`);
112
- }
113
-
114
- let attempts = 0;
115
- const maxAttempts = (options.retries || 0) + 1;
116
-
117
- function attempt() {
118
- attempts++;
119
- execFile("npx", cmdArgs, {
120
- timeout: options.timeout || 15000,
121
- maxBuffer: 1024 * 256,
122
- }, (err, stdout) => {
123
- if (err) {
124
- // Distinguish timeout from other errors
125
- const isTimeout = err.killed || err.code === "ETIMEDOUT" || err.signal === "SIGTERM";
126
- const errorType = isTimeout ? "TIMEOUT" : "ERROR";
127
-
128
- if (attempts < maxAttempts) {
129
- console.warn(`[cortex-memory] ${errorType} on ${tool} (attempt ${attempts}/${maxAttempts}), retrying...`);
130
- setTimeout(attempt, 1000); // 1s delay before retry
131
- return;
132
- }
133
-
134
- // One-time categorised warning per error type (prevents spam)
135
- const category = classifyCallError(err);
136
- if (category !== _lastCallErrorType) {
137
- _lastCallErrorType = category;
138
- switch (category) {
139
- case "timeout":
140
- console.warn("[cortex-memory] ShieldCortex call timed out (15s). Memory may be under heavy load.");
141
- break;
142
- case "not-found":
143
- console.warn("[cortex-memory] ShieldCortex binary not found. Run: npm install -g shieldcortex");
144
- break;
145
- case "mcporter":
146
- console.warn("[cortex-memory] mcporter failed to reach ShieldCortex MCP server. Is it configured?");
147
- break;
148
- default:
149
- console.warn(`[cortex-memory] ShieldCortex call failed: ${err.message}`);
150
- }
151
- }
152
- resolve(null);
153
- return;
154
- }
155
- resolve(stdout?.trim() || null);
156
- });
157
- }
158
-
159
- attempt();
160
- });
24
+ return runtime.isOpenClawAutoMemoryEnabled(config);
161
25
  }
162
26
 
163
27
  // ==================== NOVELTY / DEDUPE GATE ====================
@@ -0,0 +1,129 @@
1
+ import { execFile } from "node:child_process";
2
+ import fs from "node:fs/promises";
3
+ import { homedir } from "node:os";
4
+ import path from "node:path";
5
+
6
+ export function createOpenClawRuntime({ logPrefix = "[shieldcortex]" } = {}) {
7
+ let shieldConfig = null;
8
+ let resolvedServerCmd = null;
9
+ let lastCallErrorType = null;
10
+
11
+ async function loadShieldConfig() {
12
+ if (shieldConfig) return shieldConfig;
13
+
14
+ try {
15
+ const configPath = path.join(homedir(), ".shieldcortex", "config.json");
16
+ shieldConfig = JSON.parse(await fs.readFile(configPath, "utf-8"));
17
+ } catch {
18
+ shieldConfig = {};
19
+ }
20
+
21
+ return shieldConfig;
22
+ }
23
+
24
+ function isOpenClawAutoMemoryEnabled(config) {
25
+ return config?.openclawAutoMemory === true;
26
+ }
27
+
28
+ function classifyCallError(err) {
29
+ if (err.killed || err.code === "ETIMEDOUT" || err.signal === "SIGTERM") return "timeout";
30
+ if (/ENOENT|not found|command not found/i.test(err.message || "")) return "not-found";
31
+ if (/mcporter/i.test(err.message || "")) return "mcporter";
32
+ return "unknown";
33
+ }
34
+
35
+ async function resolveServerCmd() {
36
+ if (resolvedServerCmd) return resolvedServerCmd;
37
+
38
+ try {
39
+ const config = await loadShieldConfig();
40
+ if (config?.binaryPath) {
41
+ await fs.access(config.binaryPath);
42
+ resolvedServerCmd = config.binaryPath;
43
+ console.log(`${logPrefix} Using configured binary: ${config.binaryPath}`);
44
+ return resolvedServerCmd;
45
+ }
46
+ } catch {}
47
+
48
+ try {
49
+ const { execFileSync } = await import("node:child_process");
50
+ const bin = execFileSync("which", ["shieldcortex"], {
51
+ encoding: "utf-8",
52
+ timeout: 3000,
53
+ }).trim();
54
+ if (bin) {
55
+ resolvedServerCmd = bin;
56
+ console.log(`${logPrefix} Using global install: ${bin}`);
57
+ return resolvedServerCmd;
58
+ }
59
+ } catch {}
60
+
61
+ resolvedServerCmd = "npx -y shieldcortex";
62
+ console.log(`${logPrefix} Falling back to npx -y shieldcortex (slow path)`);
63
+ return resolvedServerCmd;
64
+ }
65
+
66
+ async function callCortex(tool, args = {}, options = { retries: 0, timeout: 15000 }) {
67
+ const serverCmd = await resolveServerCmd();
68
+
69
+ return new Promise((resolve) => {
70
+ const cmdArgs = ["mcporter", "call", "--stdio", serverCmd, tool];
71
+ for (const [key, value] of Object.entries(args)) {
72
+ cmdArgs.push(`${key}:${String(value).replace(/'/g, "''")}`);
73
+ }
74
+
75
+ let attempts = 0;
76
+ const maxAttempts = (options.retries || 0) + 1;
77
+
78
+ function attempt() {
79
+ attempts++;
80
+ execFile("npx", cmdArgs, {
81
+ timeout: options.timeout || 15000,
82
+ maxBuffer: 256 * 1024,
83
+ }, (err, stdout) => {
84
+ if (err) {
85
+ const isTimeout = err.killed || err.code === "ETIMEDOUT" || err.signal === "SIGTERM";
86
+ const errorType = isTimeout ? "TIMEOUT" : "ERROR";
87
+
88
+ if (attempts < maxAttempts) {
89
+ console.warn(`${logPrefix} ${errorType} on ${tool} (attempt ${attempts}/${maxAttempts}), retrying...`);
90
+ setTimeout(attempt, 1000);
91
+ return;
92
+ }
93
+
94
+ const category = classifyCallError(err);
95
+ if (category !== lastCallErrorType) {
96
+ lastCallErrorType = category;
97
+ switch (category) {
98
+ case "timeout":
99
+ console.warn(`${logPrefix} ShieldCortex call timed out (15s). Memory may be under heavy load.`);
100
+ break;
101
+ case "not-found":
102
+ console.warn(`${logPrefix} ShieldCortex binary not found. Run: npm install -g shieldcortex`);
103
+ break;
104
+ case "mcporter":
105
+ console.warn(`${logPrefix} mcporter failed to reach ShieldCortex MCP server. Is it configured?`);
106
+ break;
107
+ default:
108
+ console.warn(`${logPrefix} ShieldCortex call failed: ${err.message}`);
109
+ }
110
+ }
111
+ resolve(null);
112
+ return;
113
+ }
114
+
115
+ resolve(stdout?.trim() || null);
116
+ });
117
+ }
118
+
119
+ attempt();
120
+ });
121
+ }
122
+
123
+ return {
124
+ callCortex,
125
+ isOpenClawAutoMemoryEnabled,
126
+ loadShieldConfig,
127
+ resolveServerCmd,
128
+ };
129
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shieldcortex",
3
- "version": "3.0.3",
3
+ "version": "3.1.0",
4
4
  "description": "Persistent brain for AI agents. Knowledge graphs, memory decay, contradiction detection, Iron Dome behaviour protection — plus the only defence pipeline that stops memory poisoning. Works with Claude Code, OpenClaw, LangChain, and any MCP agent.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -39,7 +39,7 @@
39
39
  "scripts": {
40
40
  "postinstall": "node scripts/postinstall.mjs",
41
41
  "build": "node -e \"fs.rmSync('dist', { recursive: true, force: true })\" && tsc -p tsconfig.build.json && cp plugins/openclaw/openclaw.plugin.json plugins/openclaw/dist/",
42
- "build:dashboard": "cd dashboard && npm run build && (cp -r .next/static .next/standalone/dashboard/.next/ 2>/dev/null || true) && (cp -r public .next/standalone/dashboard/ 2>/dev/null || true)",
42
+ "build:dashboard": "cd dashboard && npm run build && (cp -r .next/static .next/standalone/dashboard/.next/ 2>/dev/null || true) && (cp -r public .next/standalone/dashboard/ 2>/dev/null || true) && cd .. && node scripts/prune-dashboard-standalone.mjs",
43
43
  "build:all": "npm run build && npm run build:dashboard",
44
44
  "start": "node dist/index.js",
45
45
  "start:api": "node dist/index.js --mode api",
@@ -123,8 +123,12 @@
123
123
  "dist",
124
124
  "hooks/openclaw",
125
125
  "plugins/openclaw/dist",
126
- "scripts/*.mjs",
127
- "scripts/*.sh",
126
+ "scripts/postinstall.mjs",
127
+ "scripts/pre-compact-hook.mjs",
128
+ "scripts/run-jest.mjs",
129
+ "scripts/session-end-hook.mjs",
130
+ "scripts/session-start-hook.mjs",
131
+ "scripts/stop-hook.mjs",
128
132
  "dashboard/.next/standalone"
129
133
  ]
130
134
  }
@@ -4,61 +4,27 @@
4
4
  * Hooks into llm_input/llm_output for real-time defence scanning
5
5
  * and optional memory extraction. All operations are fire-and-forget.
6
6
  */
7
- import { execFile } from "node:child_process";
8
7
  import { createHash } from "node:crypto";
9
8
  import fs from "node:fs/promises";
10
9
  import path from "node:path";
11
10
  import { homedir } from "node:os";
11
+ import { createOpenClawRuntime } from "../../../hooks/openclaw/cortex-memory/runtime.mjs";
12
12
  let _config = null;
13
+ const runtime = createOpenClawRuntime({ logPrefix: "[shieldcortex]" });
13
14
  async function loadConfig() {
14
15
  if (_config)
15
16
  return _config;
16
- try {
17
- _config = JSON.parse(await fs.readFile(path.join(homedir(), ".shieldcortex", "config.json"), "utf-8"));
18
- }
19
- catch {
20
- _config = {};
21
- }
17
+ _config = await runtime.loadShieldConfig();
22
18
  return _config;
23
19
  }
24
20
  function isAutoMemoryEnabled(config) {
25
- return config.openclawAutoMemory === true;
21
+ return runtime.isOpenClawAutoMemoryEnabled(config);
26
22
  }
27
23
  function isAutoMemoryDedupeEnabled(config) {
28
24
  return config.openclawAutoMemoryDedupe !== false;
29
25
  }
30
- // ==================== SERVER CMD ====================
31
- let _serverCmd = null;
32
- async function resolveServerCmd() {
33
- if (_serverCmd)
34
- return _serverCmd;
35
- const config = await loadConfig();
36
- if (config.binaryPath) {
37
- try {
38
- await fs.access(config.binaryPath);
39
- return (_serverCmd = config.binaryPath);
40
- }
41
- catch { }
42
- }
43
- try {
44
- const { execFileSync } = await import("node:child_process");
45
- const bin = execFileSync("which", ["shieldcortex"], { encoding: "utf-8", timeout: 3000 }).trim();
46
- if (bin)
47
- return (_serverCmd = bin);
48
- }
49
- catch { }
50
- return (_serverCmd = "npx -y shieldcortex");
51
- }
52
- // ==================== MCP HELPER ====================
53
26
  function callCortex(tool, args = {}) {
54
- return resolveServerCmd().then(serverCmd => new Promise(resolve => {
55
- const cmdArgs = ["mcporter", "call", "--stdio", serverCmd, tool];
56
- for (const [k, v] of Object.entries(args))
57
- cmdArgs.push(`${k}:${String(v).replace(/'/g, "''")}`);
58
- execFile("npx", cmdArgs, { timeout: 15000, maxBuffer: 256 * 1024 }, (err, stdout) => {
59
- resolve(err ? null : stdout?.trim() || null);
60
- });
61
- }));
27
+ return runtime.callCortex(tool, args);
62
28
  }
63
29
  // ==================== DEFENCE PIPELINE ====================
64
30
  let _pipeline = null;
@@ -4,27 +4,51 @@ import { spawn } from 'child_process';
4
4
  import path from 'path';
5
5
 
6
6
  const jestBin = path.join(process.cwd(), 'node_modules', 'jest', 'bin', 'jest.js');
7
+ const localStorageFile = path.join(process.cwd(), '.jest-localstorage');
7
8
 
8
9
  function sanitizeNodeOptions(value) {
9
10
  if (!value) return undefined;
10
11
 
11
12
  const cleaned = value
12
13
  .replace(/(?:^|\s)--localstorage-file(?:=\S+)?(?=\s|$)/g, ' ')
14
+ .replace(/(?:^|\s)--disable-warning(?:=\S+)?(?=\s|$)/g, ' ')
13
15
  .replace(/\s+/g, ' ')
14
16
  .trim();
15
17
 
16
18
  return cleaned || undefined;
17
19
  }
18
20
 
21
+ function appendNodeOption(existing, option) {
22
+ return existing ? `${existing} ${option}` : option;
23
+ }
24
+
19
25
  const env = { ...process.env, SHIELDCORTEX_SKIP_EMBEDDINGS: '1' };
20
26
  delete env.ELECTRON_RUN_AS_NODE;
21
27
 
22
- const sanitizedNodeOptions = sanitizeNodeOptions(env.NODE_OPTIONS);
28
+ const combinedNodeOptions = [env.NODE_OPTIONS, env.npm_config_node_options]
29
+ .filter(Boolean)
30
+ .join(' ')
31
+ .trim();
32
+
33
+ let sanitizedNodeOptions = sanitizeNodeOptions(combinedNodeOptions);
34
+
35
+ if (process.allowedNodeEnvironmentFlags.has('--localstorage-file')) {
36
+ sanitizedNodeOptions = appendNodeOption(
37
+ sanitizedNodeOptions,
38
+ `--localstorage-file=${JSON.stringify(localStorageFile)}`,
39
+ );
40
+ }
41
+
42
+ if (process.allowedNodeEnvironmentFlags.has('--disable-warning')) {
43
+ sanitizedNodeOptions = appendNodeOption(sanitizedNodeOptions, '--disable-warning=ExperimentalWarning');
44
+ }
45
+
23
46
  if (sanitizedNodeOptions) {
24
47
  env.NODE_OPTIONS = sanitizedNodeOptions;
25
48
  } else {
26
49
  delete env.NODE_OPTIONS;
27
50
  }
51
+ delete env.npm_config_node_options;
28
52
 
29
53
  const child = spawn(
30
54
  process.execPath,