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
@@ -0,0 +1,502 @@
1
+ import { getDatabase } from '../../database/init.js';
2
+ import { getCloudConfig } from '../../cloud/config.js';
3
+ import { queryAgentOperations, queryAgentRegistry, queryAgentTimeline, queryAuditLogs, getAuditStats } from '../../defence/audit/queries.js';
4
+ import { getLicense, activateLicense, deactivateLicense } from '../../license/store.js';
5
+ import { listFeatures } from '../../license/gate.js';
6
+ import { validateOnceNow } from '../../license/validate.js';
7
+ export function registerAdminRoutes(app, deps) {
8
+ const { brainWorker, requireNotLocked, requireProFeature } = deps;
9
+ app.get('/api/v1/audit', (req, res) => {
10
+ try {
11
+ const options = {};
12
+ if (req.query.startTime)
13
+ options.startTime = req.query.startTime;
14
+ if (req.query.endTime)
15
+ options.endTime = req.query.endTime;
16
+ if (req.query.source)
17
+ options.source = req.query.source;
18
+ if (req.query.firewallResult)
19
+ options.firewallResult = req.query.firewallResult;
20
+ if (req.query.limit)
21
+ options.limit = parseInt(req.query.limit, 10);
22
+ if (req.query.project)
23
+ options.project = req.query.project;
24
+ const logs = queryAuditLogs(options);
25
+ res.json({ logs, total: logs.length });
26
+ }
27
+ catch (error) {
28
+ res.status(500).json({ error: error.message });
29
+ }
30
+ });
31
+ app.get('/api/v1/audit/stats', (req, res) => {
32
+ try {
33
+ const timeRange = req.query.timeRange ?? '24h';
34
+ const project = req.query.project;
35
+ res.json(getAuditStats(timeRange, project));
36
+ }
37
+ catch (error) {
38
+ res.status(500).json({ error: error.message });
39
+ }
40
+ });
41
+ app.get('/api/v1/agents', (req, res) => {
42
+ try {
43
+ const timeRange = req.query.timeRange ?? '24h';
44
+ const project = req.query.project;
45
+ res.json({ agents: queryAgentRegistry(timeRange, project) });
46
+ }
47
+ catch (error) {
48
+ res.status(500).json({ error: error.message });
49
+ }
50
+ });
51
+ app.get('/api/v1/agents/:identifier/timeline', (req, res) => {
52
+ try {
53
+ const identifier = decodeURIComponent(req.params.identifier);
54
+ const timeRange = req.query.timeRange ?? '24h';
55
+ const project = req.query.project;
56
+ res.json({ points: queryAgentTimeline(identifier, timeRange, project) });
57
+ }
58
+ catch (error) {
59
+ res.status(500).json({ error: error.message });
60
+ }
61
+ });
62
+ app.get('/api/v1/agents/:identifier/operations', (req, res) => {
63
+ try {
64
+ const identifier = decodeURIComponent(req.params.identifier);
65
+ const limit = parseInt(req.query.limit, 10) || 50;
66
+ const offset = parseInt(req.query.offset, 10) || 0;
67
+ const firewallResult = req.query.firewallResult;
68
+ const project = req.query.project;
69
+ res.json({
70
+ entries: queryAgentOperations(identifier, { limit, offset, project, firewallResult }),
71
+ limit,
72
+ offset,
73
+ });
74
+ }
75
+ catch (error) {
76
+ res.status(500).json({ error: error.message });
77
+ }
78
+ });
79
+ app.get('/api/v1/quarantine', (req, res) => {
80
+ try {
81
+ const db = getDatabase();
82
+ const status = req.query.status ?? 'pending';
83
+ const limit = parseInt(req.query.limit, 10) || 50;
84
+ const project = req.query.project;
85
+ const sql = project
86
+ ? 'SELECT * FROM quarantine WHERE status = ? AND project = ? ORDER BY created_at DESC LIMIT ?'
87
+ : 'SELECT * FROM quarantine WHERE status = ? ORDER BY created_at DESC LIMIT ?';
88
+ const params = project ? [status, project, limit] : [status, limit];
89
+ const rows = db.prepare(sql).all(...params);
90
+ res.json({
91
+ items: rows.map((row) => ({
92
+ ...row,
93
+ title: row.original_title,
94
+ content: row.original_content,
95
+ })),
96
+ total: rows.length,
97
+ });
98
+ }
99
+ catch (error) {
100
+ res.status(500).json({ error: error.message });
101
+ }
102
+ });
103
+ app.post('/api/v1/quarantine/:id/approve', requireNotLocked, (req, res) => {
104
+ try {
105
+ const db = getDatabase();
106
+ const id = parseInt(req.params.id, 10);
107
+ const reviewedBy = req.body?.reviewedBy ?? 'api';
108
+ const result = db.prepare('UPDATE quarantine SET status = ?, reviewed_at = ?, reviewed_by = ? WHERE id = ? AND status = ?').run('approved', new Date().toISOString(), reviewedBy, id, 'pending');
109
+ if (result.changes === 0) {
110
+ return res.status(404).json({ error: 'Quarantine entry not found or already reviewed' });
111
+ }
112
+ res.json({ success: true, id, status: 'approved' });
113
+ }
114
+ catch (error) {
115
+ res.status(500).json({ error: error.message });
116
+ }
117
+ });
118
+ app.post('/api/v1/quarantine/:id/reject', requireNotLocked, (req, res) => {
119
+ try {
120
+ const db = getDatabase();
121
+ const id = parseInt(req.params.id, 10);
122
+ const reviewedBy = req.body?.reviewedBy ?? 'api';
123
+ const result = db.prepare('UPDATE quarantine SET status = ?, reviewed_at = ?, reviewed_by = ? WHERE id = ? AND status = ?').run('rejected', new Date().toISOString(), reviewedBy, id, 'pending');
124
+ if (result.changes === 0) {
125
+ return res.status(404).json({ error: 'Quarantine entry not found or already reviewed' });
126
+ }
127
+ res.json({ success: true, id, status: 'rejected' });
128
+ }
129
+ catch (error) {
130
+ res.status(500).json({ error: error.message });
131
+ }
132
+ });
133
+ app.post('/api/v1/quarantine/bulk-approve', requireNotLocked, (req, res) => {
134
+ try {
135
+ const db = getDatabase();
136
+ const ids = req.body?.ids;
137
+ if (!Array.isArray(ids) || ids.length === 0) {
138
+ return res.status(400).json({ error: 'ids must be a non-empty array of numbers' });
139
+ }
140
+ const reviewedBy = req.body?.reviewedBy ?? 'dashboard';
141
+ const now = new Date().toISOString();
142
+ const stmt = db.prepare('UPDATE quarantine SET status = ?, reviewed_at = ?, reviewed_by = ? WHERE id = ? AND status = ?');
143
+ let updated = 0;
144
+ db.transaction(() => {
145
+ for (const id of ids) {
146
+ updated += stmt.run('approved', now, reviewedBy, id, 'pending').changes;
147
+ }
148
+ })();
149
+ res.json({ success: true, updated, total: ids.length });
150
+ }
151
+ catch (error) {
152
+ res.status(500).json({ error: error.message });
153
+ }
154
+ });
155
+ app.post('/api/v1/quarantine/bulk-reject', requireNotLocked, (req, res) => {
156
+ try {
157
+ const db = getDatabase();
158
+ const ids = req.body?.ids;
159
+ if (!Array.isArray(ids) || ids.length === 0) {
160
+ return res.status(400).json({ error: 'ids must be a non-empty array of numbers' });
161
+ }
162
+ const reviewedBy = req.body?.reviewedBy ?? 'dashboard';
163
+ const now = new Date().toISOString();
164
+ const stmt = db.prepare('UPDATE quarantine SET status = ?, reviewed_at = ?, reviewed_by = ? WHERE id = ? AND status = ?');
165
+ let updated = 0;
166
+ db.transaction(() => {
167
+ for (const id of ids) {
168
+ updated += stmt.run('rejected', now, reviewedBy, id, 'pending').changes;
169
+ }
170
+ })();
171
+ res.json({ success: true, updated, total: ids.length });
172
+ }
173
+ catch (error) {
174
+ res.status(500).json({ error: error.message });
175
+ }
176
+ });
177
+ app.post('/api/quarantine/sync-to-cloud', requireNotLocked, async (_req, res) => {
178
+ try {
179
+ const config = getCloudConfig();
180
+ if (!config.cloudEnabled || !config.cloudApiKey) {
181
+ return res.status(400).json({ error: 'Cloud not configured. Enable cloud sync first.' });
182
+ }
183
+ const db = getDatabase();
184
+ const rows = db.prepare('SELECT * FROM quarantine WHERE status = ? ORDER BY created_at ASC')
185
+ .all('pending');
186
+ if (rows.length === 0) {
187
+ return res.json({ synced: 0, message: 'No pending quarantine items to sync.' });
188
+ }
189
+ let synced = 0;
190
+ const errors = [];
191
+ for (const row of rows) {
192
+ try {
193
+ const indicators = (() => {
194
+ try {
195
+ return JSON.parse(row.threat_indicators ?? '[]');
196
+ }
197
+ catch {
198
+ return [];
199
+ }
200
+ })();
201
+ const response = await fetch(`${config.cloudBaseUrl}/v1/quarantine/ingest`, {
202
+ method: 'POST',
203
+ headers: {
204
+ 'Content-Type': 'application/json',
205
+ Authorization: `Bearer ${config.cloudApiKey}`,
206
+ },
207
+ body: JSON.stringify({
208
+ original_content: row.original_content,
209
+ original_title: row.original_title ?? undefined,
210
+ source_type: row.source_type ?? 'unknown',
211
+ source_identifier: row.source_identifier ?? 'unknown',
212
+ reason: row.reason ?? 'Unknown reason',
213
+ threat_indicators: indicators,
214
+ anomaly_score: row.anomaly_score ?? 0,
215
+ firewall_result: row.firewall_result ?? 'QUARANTINE',
216
+ }),
217
+ signal: AbortSignal.timeout(10_000),
218
+ });
219
+ if (response.ok) {
220
+ synced++;
221
+ }
222
+ else {
223
+ const body = await response.text().catch(() => '');
224
+ errors.push(`Item ${row.id}: ${response.status} ${body.substring(0, 100)}`);
225
+ }
226
+ }
227
+ catch (error) {
228
+ errors.push(`Item ${row.id}: ${error.message}`);
229
+ }
230
+ }
231
+ res.json({ synced, total: rows.length, errors: errors.length > 0 ? errors : undefined });
232
+ }
233
+ catch (error) {
234
+ res.status(500).json({ error: error.message });
235
+ }
236
+ });
237
+ app.get('/api/worker/status', (_req, res) => {
238
+ try {
239
+ res.json(brainWorker.getStatus());
240
+ }
241
+ catch (error) {
242
+ res.status(500).json({ error: error.message });
243
+ }
244
+ });
245
+ app.post('/api/worker/trigger-light', requireNotLocked, async (_req, res) => {
246
+ try {
247
+ const result = await brainWorker.triggerLightTick();
248
+ res.json({ success: true, ...result, timestamp: result.timestamp.toISOString() });
249
+ }
250
+ catch (error) {
251
+ res.status(500).json({ error: error.message });
252
+ }
253
+ });
254
+ app.post('/api/worker/trigger-medium', requireNotLocked, async (_req, res) => {
255
+ try {
256
+ const result = await brainWorker.triggerMediumTick();
257
+ res.json({ success: true, ...result, timestamp: result.timestamp.toISOString() });
258
+ }
259
+ catch (error) {
260
+ res.status(500).json({ error: error.message });
261
+ }
262
+ });
263
+ app.get('/api/license/status', (_req, res) => {
264
+ try {
265
+ const info = getLicense();
266
+ res.json({
267
+ tier: info.tier,
268
+ valid: info.valid,
269
+ email: info.email,
270
+ expiresAt: info.expiresAt?.toISOString() ?? null,
271
+ daysUntilExpiry: info.daysUntilExpiry,
272
+ teamId: info.teamId,
273
+ features: listFeatures(),
274
+ });
275
+ }
276
+ catch (error) {
277
+ res.status(500).json({ error: error.message });
278
+ }
279
+ });
280
+ app.post('/api/license/activate', async (req, res) => {
281
+ try {
282
+ const { key } = req.body;
283
+ if (!key || typeof key !== 'string') {
284
+ return res.status(400).json({ error: 'License key is required' });
285
+ }
286
+ const info = activateLicense(key.trim());
287
+ const validationStatus = await validateOnceNow();
288
+ res.json({
289
+ success: true,
290
+ tier: info.tier,
291
+ valid: info.valid,
292
+ email: info.email,
293
+ expiresAt: info.expiresAt?.toISOString() ?? null,
294
+ daysUntilExpiry: info.daysUntilExpiry,
295
+ validationStatus,
296
+ features: listFeatures(),
297
+ });
298
+ }
299
+ catch (error) {
300
+ res.status(400).json({ error: error.message });
301
+ }
302
+ });
303
+ app.post('/api/license/deactivate', (_req, res) => {
304
+ try {
305
+ deactivateLicense();
306
+ res.json({ success: true, tier: 'free', features: listFeatures() });
307
+ }
308
+ catch (error) {
309
+ res.status(500).json({ error: error.message });
310
+ }
311
+ });
312
+ app.get('/api/firewall-rules', requireProFeature('custom_firewall_rules'), async (_req, res) => {
313
+ try {
314
+ const { listFirewallRules } = await import('../../defence/custom-rules/store.js');
315
+ const rules = listFirewallRules();
316
+ res.json({ rules, total: rules.length });
317
+ }
318
+ catch (error) {
319
+ res.status(500).json({ error: error.message });
320
+ }
321
+ });
322
+ app.post('/api/firewall-rules', requireProFeature('custom_firewall_rules'), async (req, res) => {
323
+ try {
324
+ const { createFirewallRule } = await import('../../defence/custom-rules/store.js');
325
+ const { name, priority, condition_type, condition_value, action } = req.body;
326
+ if (!name || !condition_type || !condition_value || !action) {
327
+ return res.status(400).json({ error: 'name, condition_type, condition_value, and action are required' });
328
+ }
329
+ const rule = createFirewallRule({ name, priority: priority ?? 100, condition_type, condition_value, action });
330
+ res.status(201).json(rule);
331
+ }
332
+ catch (error) {
333
+ const msg = error.message;
334
+ res.status(msg.includes('Maximum') ? 400 : 500).json({ error: msg });
335
+ }
336
+ });
337
+ app.patch('/api/firewall-rules/:id', requireProFeature('custom_firewall_rules'), async (req, res) => {
338
+ try {
339
+ const { updateFirewallRule } = await import('../../defence/custom-rules/store.js');
340
+ const rule = updateFirewallRule(Number(req.params.id), req.body);
341
+ if (!rule)
342
+ return res.status(404).json({ error: 'Rule not found' });
343
+ res.json(rule);
344
+ }
345
+ catch (error) {
346
+ res.status(500).json({ error: error.message });
347
+ }
348
+ });
349
+ app.delete('/api/firewall-rules/:id', requireProFeature('custom_firewall_rules'), async (req, res) => {
350
+ try {
351
+ const { deleteFirewallRule } = await import('../../defence/custom-rules/store.js');
352
+ const deleted = deleteFirewallRule(Number(req.params.id));
353
+ if (!deleted)
354
+ return res.status(404).json({ error: 'Rule not found' });
355
+ res.json({ success: true, id: Number(req.params.id) });
356
+ }
357
+ catch (error) {
358
+ res.status(500).json({ error: error.message });
359
+ }
360
+ });
361
+ app.get('/api/patterns', requireProFeature('custom_injection_patterns'), async (_req, res) => {
362
+ try {
363
+ const { listCustomPatterns } = await import('../../defence/custom-patterns/store.js');
364
+ const patterns = listCustomPatterns();
365
+ res.json({ patterns, total: patterns.length });
366
+ }
367
+ catch (error) {
368
+ res.status(500).json({ error: error.message });
369
+ }
370
+ });
371
+ app.post('/api/patterns', requireProFeature('custom_injection_patterns'), async (req, res) => {
372
+ try {
373
+ const { createCustomPattern, validateRegex } = await import('../../defence/custom-patterns/store.js');
374
+ const { name, category, severity, regex, description } = req.body;
375
+ if (!name || !regex) {
376
+ return res.status(400).json({ error: 'name and regex are required' });
377
+ }
378
+ const validation = validateRegex(regex);
379
+ if (!validation.valid) {
380
+ return res.status(400).json({ error: validation.error });
381
+ }
382
+ const pattern = createCustomPattern({
383
+ name,
384
+ category: category || 'custom',
385
+ severity: severity || 'medium',
386
+ regex,
387
+ description,
388
+ });
389
+ res.status(201).json(pattern);
390
+ }
391
+ catch (error) {
392
+ const msg = error.message;
393
+ const status = msg.includes('Maximum') || msg.includes('Invalid') || msg.includes('rejected') ? 400 : 500;
394
+ res.status(status).json({ error: msg });
395
+ }
396
+ });
397
+ app.delete('/api/patterns/:id', requireProFeature('custom_injection_patterns'), async (req, res) => {
398
+ try {
399
+ const { deleteCustomPattern } = await import('../../defence/custom-patterns/store.js');
400
+ const deleted = deleteCustomPattern(Number(req.params.id));
401
+ if (!deleted)
402
+ return res.status(404).json({ error: 'Pattern not found' });
403
+ res.json({ success: true, id: Number(req.params.id) });
404
+ }
405
+ catch (error) {
406
+ res.status(500).json({ error: error.message });
407
+ }
408
+ });
409
+ app.post('/api/patterns/:id/test', requireProFeature('custom_injection_patterns'), async (req, res) => {
410
+ try {
411
+ const { testPattern } = await import('../../defence/custom-patterns/store.js');
412
+ const { text } = req.body;
413
+ if (!text)
414
+ return res.status(400).json({ error: 'text is required' });
415
+ res.json(testPattern(Number(req.params.id), text));
416
+ }
417
+ catch (error) {
418
+ res.status(500).json({ error: error.message });
419
+ }
420
+ });
421
+ app.get('/api/iron-dome/policies', requireProFeature('custom_iron_dome_policies'), async (_req, res) => {
422
+ try {
423
+ const { listIronDomePolicies } = await import('../../defence/iron-dome/custom-policies.js');
424
+ const policies = listIronDomePolicies();
425
+ res.json({ policies, total: policies.length });
426
+ }
427
+ catch (error) {
428
+ res.status(500).json({ error: error.message });
429
+ }
430
+ });
431
+ app.post('/api/iron-dome/policies', requireProFeature('custom_iron_dome_policies'), async (req, res) => {
432
+ try {
433
+ const { createIronDomePolicy } = await import('../../defence/iron-dome/custom-policies.js');
434
+ const { name, description, config } = req.body;
435
+ if (!name)
436
+ return res.status(400).json({ error: 'name is required' });
437
+ res.status(201).json(createIronDomePolicy({ name, description, config: config || {} }));
438
+ }
439
+ catch (error) {
440
+ const msg = error.message;
441
+ res.status(msg.includes('Maximum') ? 400 : 500).json({ error: msg });
442
+ }
443
+ });
444
+ app.delete('/api/iron-dome/policies/:id', requireProFeature('custom_iron_dome_policies'), async (req, res) => {
445
+ try {
446
+ const { deleteIronDomePolicy } = await import('../../defence/iron-dome/custom-policies.js');
447
+ const deleted = deleteIronDomePolicy(Number(req.params.id));
448
+ if (!deleted)
449
+ return res.status(404).json({ error: 'Policy not found' });
450
+ res.json({ success: true, id: Number(req.params.id) });
451
+ }
452
+ catch (error) {
453
+ res.status(500).json({ error: error.message });
454
+ }
455
+ });
456
+ app.put('/api/iron-dome/policies/:id/activate', requireProFeature('custom_iron_dome_policies'), async (req, res) => {
457
+ try {
458
+ const { activateIronDomePolicy } = await import('../../defence/iron-dome/custom-policies.js');
459
+ const policy = activateIronDomePolicy(Number(req.params.id));
460
+ if (!policy)
461
+ return res.status(404).json({ error: 'Policy not found' });
462
+ res.json(policy);
463
+ }
464
+ catch (error) {
465
+ res.status(500).json({ error: error.message });
466
+ }
467
+ });
468
+ app.get('/api/audit/export', requireProFeature('audit_export'), async (req, res) => {
469
+ try {
470
+ const { exportAuditJSON, exportAuditCSV } = await import('../../defence/audit/export.js');
471
+ const format = req.query.format || 'json';
472
+ const startTime = req.query.startTime;
473
+ const endTime = req.query.endTime;
474
+ if (format === 'csv') {
475
+ const csv = exportAuditCSV(startTime, endTime);
476
+ res.setHeader('Content-Type', 'text/csv');
477
+ res.setHeader('Content-Disposition', `attachment; filename="shieldcortex-audit-${Date.now()}.csv"`);
478
+ return res.send(csv);
479
+ }
480
+ const json = exportAuditJSON(startTime, endTime);
481
+ res.setHeader('Content-Type', 'application/json');
482
+ res.setHeader('Content-Disposition', `attachment; filename="shieldcortex-audit-${Date.now()}.json"`);
483
+ res.send(json);
484
+ }
485
+ catch (error) {
486
+ res.status(500).json({ error: error.message });
487
+ }
488
+ });
489
+ app.post('/api/skills/deep-scan', requireProFeature('skill_scanner_deep'), async (req, res) => {
490
+ try {
491
+ const { runDeepScan } = await import('../../defence/skill-scanner/deep-scan.js');
492
+ const { files } = req.body;
493
+ if (!files || !Array.isArray(files) || files.length === 0) {
494
+ return res.status(400).json({ error: 'files array is required (each with name and content)' });
495
+ }
496
+ res.json(await runDeepScan(files));
497
+ }
498
+ catch (error) {
499
+ res.status(500).json({ error: error.message });
500
+ }
501
+ });
502
+ }
@@ -0,0 +1,4 @@
1
+ import type { Express, Request, Response } from 'express';
2
+ type Middleware = (_req: Request, res: Response, next: (err?: unknown) => void) => void;
3
+ export declare function registerGraphRoutes(app: Express, requireNotLocked: Middleware): void;
4
+ export {};