shieldcortex 2.19.0 → 2.19.3

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 (94) hide show
  1. package/dashboard/.next/standalone/dashboard/.next/BUILD_ID +1 -1
  2. package/dashboard/.next/standalone/dashboard/.next/build-manifest.json +2 -2
  3. package/dashboard/.next/standalone/dashboard/.next/prerender-manifest.json +3 -3
  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/page_client-reference-manifest.js +1 -1
  12. package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.html +1 -1
  13. package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.rsc +2 -2
  14. package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.segments/_full.segment.rsc +2 -2
  15. package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  16. package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.segments/_index.segment.rsc +2 -2
  17. package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  18. package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  19. package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  20. package/dashboard/.next/standalone/dashboard/.next/server/app/index.html +1 -1
  21. package/dashboard/.next/standalone/dashboard/.next/server/app/index.rsc +3 -3
  22. package/dashboard/.next/standalone/dashboard/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  23. package/dashboard/.next/standalone/dashboard/.next/server/app/index.segments/_full.segment.rsc +3 -3
  24. package/dashboard/.next/standalone/dashboard/.next/server/app/index.segments/_head.segment.rsc +1 -1
  25. package/dashboard/.next/standalone/dashboard/.next/server/app/index.segments/_index.segment.rsc +2 -2
  26. package/dashboard/.next/standalone/dashboard/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  27. package/dashboard/.next/standalone/dashboard/.next/server/app/page_client-reference-manifest.js +1 -1
  28. package/dashboard/.next/standalone/dashboard/.next/server/chunks/ssr/dashboard_25b1b286._.js +1 -1
  29. package/dashboard/.next/standalone/dashboard/.next/server/pages/404.html +1 -1
  30. package/dashboard/.next/standalone/dashboard/.next/server/pages/500.html +2 -2
  31. package/dashboard/.next/standalone/dashboard/.next/server/server-reference-manifest.js +1 -1
  32. package/dashboard/.next/standalone/dashboard/.next/server/server-reference-manifest.json +1 -1
  33. package/dashboard/.next/standalone/dashboard/.next/static/chunks/{6bf7d89d34068ecb.js → 7d04c140073d99aa.js} +3 -3
  34. package/dashboard/.next/standalone/dashboard/.next/static/chunks/94d1921c4f61a608.css +3 -0
  35. package/dashboard/.next/standalone/dashboard/.next/static/chunks/cac330f9511d34e5.js +1 -0
  36. package/dist/api/control.d.ts +28 -11
  37. package/dist/api/control.d.ts.map +1 -1
  38. package/dist/api/control.js +120 -19
  39. package/dist/api/control.js.map +1 -1
  40. package/dist/api/events.d.ts +12 -1
  41. package/dist/api/events.d.ts.map +1 -1
  42. package/dist/api/events.js +9 -0
  43. package/dist/api/events.js.map +1 -1
  44. package/dist/api/visualization-server.d.ts.map +1 -1
  45. package/dist/api/visualization-server.js +88 -36
  46. package/dist/api/visualization-server.js.map +1 -1
  47. package/dist/cloud/quarantine-sync.d.ts +3 -0
  48. package/dist/cloud/quarantine-sync.d.ts.map +1 -1
  49. package/dist/cloud/quarantine-sync.js +7 -0
  50. package/dist/cloud/quarantine-sync.js.map +1 -1
  51. package/dist/cloud/sync.d.ts +11 -0
  52. package/dist/cloud/sync.d.ts.map +1 -1
  53. package/dist/cloud/sync.js +37 -0
  54. package/dist/cloud/sync.js.map +1 -1
  55. package/dist/defence/index.d.ts +2 -0
  56. package/dist/defence/index.d.ts.map +1 -1
  57. package/dist/defence/index.js +2 -0
  58. package/dist/defence/index.js.map +1 -1
  59. package/dist/defence/input-sanitisation/index.d.ts +28 -0
  60. package/dist/defence/input-sanitisation/index.d.ts.map +1 -0
  61. package/dist/defence/input-sanitisation/index.js +71 -0
  62. package/dist/defence/input-sanitisation/index.js.map +1 -0
  63. package/dist/defence/iron-dome/config.js +5 -5
  64. package/dist/defence/iron-dome/config.js.map +1 -1
  65. package/dist/defence/iron-dome/index.d.ts +6 -0
  66. package/dist/defence/iron-dome/index.d.ts.map +1 -1
  67. package/dist/defence/iron-dome/index.js +19 -0
  68. package/dist/defence/iron-dome/index.js.map +1 -1
  69. package/dist/defence/pipeline.d.ts.map +1 -1
  70. package/dist/defence/pipeline.js +21 -11
  71. package/dist/defence/pipeline.js.map +1 -1
  72. package/dist/index.d.ts.map +1 -1
  73. package/dist/index.js +59 -0
  74. package/dist/index.js.map +1 -1
  75. package/dist/lib.d.ts +2 -0
  76. package/dist/lib.d.ts.map +1 -1
  77. package/dist/lib.js +2 -0
  78. package/dist/lib.js.map +1 -1
  79. package/dist/license/keys.d.ts +1 -1
  80. package/dist/license/keys.js +1 -1
  81. package/dist/server.d.ts.map +1 -1
  82. package/dist/server.js +193 -45
  83. package/dist/server.js.map +1 -1
  84. package/dist/tools/context.d.ts +4 -4
  85. package/dist/tools/forget.d.ts +4 -4
  86. package/dist/tools/recall.d.ts +9 -9
  87. package/dist/tools/remember.d.ts +4 -4
  88. package/hooks/openclaw/cortex-memory/handler.ts +8 -18
  89. package/package.json +1 -1
  90. package/dashboard/.next/standalone/dashboard/.next/static/chunks/1a71c9a52f0c9b16.css +0 -3
  91. package/dashboard/.next/standalone/dashboard/.next/static/chunks/d0dcb5e0e04ae015.js +0 -1
  92. /package/dashboard/.next/standalone/dashboard/.next/static/{OfvwyqIJFP9N3Qdb23S-6 → x5pEZRSDizF1dS-qqTezT}/_buildManifest.js +0 -0
  93. /package/dashboard/.next/standalone/dashboard/.next/static/{OfvwyqIJFP9N3Qdb23S-6 → x5pEZRSDizF1dS-qqTezT}/_clientMiddlewareManifest.json +0 -0
  94. /package/dashboard/.next/standalone/dashboard/.next/static/{OfvwyqIJFP9N3Qdb23S-6 → x5pEZRSDizF1dS-qqTezT}/_ssgManifest.js +0 -0
@@ -21,7 +21,7 @@ import { detectContradictions, getContradictionsFor } from '../memory/contradict
21
21
  import { enrichMemory } from '../memory/store.js';
22
22
  import { memoryEvents, emitDecayTick, emitConsolidation, getUnprocessedEvents, markEventsProcessed, cleanupOldEvents, } from './events.js';
23
23
  import { BrainWorker } from '../worker/brain-worker.js';
24
- import { pause, resume, getControlStatus } from './control.js';
24
+ import { pause, resume, getControlStatus, isKillSwitchActive, getKillSwitchMeta, activateKillSwitch, deactivateKillSwitch } from './control.js';
25
25
  import { getCurrentVersion, getRunningVersion, checkForUpdates, performUpdate, scheduleRestart } from './version.js';
26
26
  import { runDefencePipeline } from '../defence/pipeline.js';
27
27
  import { DEFAULT_DEFENCE_CONFIG } from '../defence/types.js';
@@ -129,6 +129,23 @@ export function startVisualizationServer(dbPath) {
129
129
  res.json({ token });
130
130
  });
131
131
  // ============================================
132
+ // KILL SWITCH GUARD MIDDLEWARE
133
+ // ============================================
134
+ /**
135
+ * Express middleware that blocks requests when the kill switch is active.
136
+ * Returns 423 Locked with kill switch metadata.
137
+ */
138
+ function requireNotLocked(_req, res, next) {
139
+ if (!isKillSwitchActive())
140
+ return next();
141
+ const meta = getKillSwitchMeta();
142
+ res.status(423).json({
143
+ error: 'Kill switch active — operation blocked',
144
+ code: 'KILL_SWITCH_ACTIVE',
145
+ killSwitch: meta,
146
+ });
147
+ }
148
+ // ============================================
132
149
  // REST API ENDPOINTS
133
150
  // ============================================
134
151
  // Health check
@@ -142,7 +159,7 @@ export function startVisualizationServer(dbPath) {
142
159
  res.json({ total, byFeature: { ...gatedCounters } });
143
160
  });
144
161
  // Get all memories with filters and pagination
145
- app.get('/api/memories', async (req, res) => {
162
+ app.get('/api/memories', requireNotLocked, async (req, res) => {
146
163
  try {
147
164
  // Extract query params as strings
148
165
  const project = typeof req.query.project === 'string' ? req.query.project : undefined;
@@ -204,7 +221,7 @@ export function startVisualizationServer(dbPath) {
204
221
  }
205
222
  });
206
223
  // Activity data for heatmap (must be before :id route)
207
- app.get('/api/memories/activity', (req, res) => {
224
+ app.get('/api/memories/activity', requireNotLocked, (req, res) => {
208
225
  try {
209
226
  const project = typeof req.query.project === 'string' ? req.query.project : undefined;
210
227
  const db = getDatabase();
@@ -229,7 +246,7 @@ export function startVisualizationServer(dbPath) {
229
246
  }
230
247
  });
231
248
  // Memory quality analysis (must be before :id route)
232
- app.get('/api/memories/quality', (req, res) => {
249
+ app.get('/api/memories/quality', requireNotLocked, (req, res) => {
233
250
  try {
234
251
  const project = typeof req.query.project === 'string' ? req.query.project : undefined;
235
252
  const db = getDatabase();
@@ -265,7 +282,7 @@ export function startVisualizationServer(dbPath) {
265
282
  }
266
283
  });
267
284
  // Get single memory by ID
268
- app.get('/api/memories/:id', (req, res) => {
285
+ app.get('/api/memories/:id', requireNotLocked, (req, res) => {
269
286
  try {
270
287
  const id = parseInt(req.params.id);
271
288
  const memory = getMemoryById(id);
@@ -282,7 +299,7 @@ export function startVisualizationServer(dbPath) {
282
299
  }
283
300
  });
284
301
  // Create memory
285
- app.post('/api/memories', (req, res) => {
302
+ app.post('/api/memories', requireNotLocked, (req, res) => {
286
303
  try {
287
304
  const { title, content, type, category, project, tags, salience } = req.body;
288
305
  if (!title || !content) {
@@ -312,7 +329,7 @@ export function startVisualizationServer(dbPath) {
312
329
  }
313
330
  });
314
331
  // Delete memory
315
- app.delete('/api/memories/:id', (req, res) => {
332
+ app.delete('/api/memories/:id', requireNotLocked, (req, res) => {
316
333
  try {
317
334
  const id = parseInt(req.params.id);
318
335
  const success = deleteMemory(id);
@@ -326,7 +343,7 @@ export function startVisualizationServer(dbPath) {
326
343
  }
327
344
  });
328
345
  // Access/reinforce memory
329
- app.post('/api/memories/:id/access', (req, res) => {
346
+ app.post('/api/memories/:id/access', requireNotLocked, (req, res) => {
330
347
  try {
331
348
  const id = parseInt(req.params.id);
332
349
  const memory = accessMemory(id);
@@ -382,7 +399,7 @@ export function startVisualizationServer(dbPath) {
382
399
  }
383
400
  });
384
401
  // Get currently activated memories (spreading activation)
385
- app.get('/api/activation', (_req, res) => {
402
+ app.get('/api/activation', requireNotLocked, (_req, res) => {
386
403
  try {
387
404
  const activeMemories = getActiveMemories();
388
405
  const stats = getActivationStats();
@@ -400,7 +417,7 @@ export function startVisualizationServer(dbPath) {
400
417
  // ORGANIC BRAIN ENDPOINTS (Phase 3)
401
418
  // ============================================
402
419
  // Get detected contradictions
403
- app.get('/api/contradictions', (req, res) => {
420
+ app.get('/api/contradictions', requireNotLocked, (req, res) => {
404
421
  try {
405
422
  const project = typeof req.query.project === 'string' ? req.query.project : undefined;
406
423
  const category = typeof req.query.category === 'string' ? req.query.category : undefined;
@@ -433,7 +450,7 @@ export function startVisualizationServer(dbPath) {
433
450
  }
434
451
  });
435
452
  // Get contradictions for a specific memory
436
- app.get('/api/memories/:id/contradictions', (req, res) => {
453
+ app.get('/api/memories/:id/contradictions', requireNotLocked, (req, res) => {
437
454
  try {
438
455
  const id = parseInt(req.params.id);
439
456
  if (isNaN(id)) {
@@ -457,7 +474,7 @@ export function startVisualizationServer(dbPath) {
457
474
  }
458
475
  });
459
476
  // Manually enrich a memory with new context
460
- app.post('/api/memories/:id/enrich', (req, res) => {
477
+ app.post('/api/memories/:id/enrich', requireNotLocked, (req, res) => {
461
478
  try {
462
479
  const id = parseInt(req.params.id);
463
480
  if (isNaN(id)) {
@@ -513,9 +530,12 @@ export function startVisualizationServer(dbPath) {
513
530
  res.status(500).json({ error: error.message });
514
531
  }
515
532
  });
516
- // Pause memory creation
533
+ // Pause memory creation (soft pause — kill switch takes precedence)
517
534
  app.post('/api/control/pause', (_req, res) => {
518
535
  try {
536
+ if (isKillSwitchActive()) {
537
+ return res.status(409).json({ error: 'Kill switch is active — use /api/iron-dome/resume to deactivate first', code: 'KILL_SWITCH_ACTIVE' });
538
+ }
519
539
  pause();
520
540
  res.json({ paused: true, message: 'Memory creation paused' });
521
541
  }
@@ -523,9 +543,12 @@ export function startVisualizationServer(dbPath) {
523
543
  res.status(500).json({ error: error.message });
524
544
  }
525
545
  });
526
- // Resume memory creation
546
+ // Resume memory creation (soft resume — cannot override kill switch)
527
547
  app.post('/api/control/resume', (_req, res) => {
528
548
  try {
549
+ if (isKillSwitchActive()) {
550
+ return res.status(409).json({ error: 'Kill switch is active — use /api/iron-dome/resume to deactivate first', code: 'KILL_SWITCH_ACTIVE' });
551
+ }
529
552
  resume();
530
553
  res.json({ paused: false, message: 'Memory creation resumed' });
531
554
  }
@@ -727,7 +750,7 @@ export function startVisualizationServer(dbPath) {
727
750
  }
728
751
  });
729
752
  // Get memory links/relationships
730
- app.get('/api/links', (req, res) => {
753
+ app.get('/api/links', requireNotLocked, (req, res) => {
731
754
  try {
732
755
  const project = typeof req.query.project === 'string' ? req.query.project : undefined;
733
756
  const db = getDatabase();
@@ -780,7 +803,7 @@ export function startVisualizationServer(dbPath) {
780
803
  // SQL CONSOLE ENDPOINT
781
804
  // ============================================
782
805
  // Execute SQL query (with safety restrictions)
783
- app.post('/api/sql', (req, res) => {
806
+ app.post('/api/sql', requireNotLocked, (req, res) => {
784
807
  try {
785
808
  const { query, allowWrite } = req.body;
786
809
  if (!query || typeof query !== 'string') {
@@ -837,7 +860,7 @@ export function startVisualizationServer(dbPath) {
837
860
  }
838
861
  });
839
862
  // Trigger consolidation
840
- app.post('/api/consolidate', (_req, res) => {
863
+ app.post('/api/consolidate', requireNotLocked, (_req, res) => {
841
864
  try {
842
865
  const result = consolidate();
843
866
  // Emit event for Activity log
@@ -852,7 +875,7 @@ export function startVisualizationServer(dbPath) {
852
875
  }
853
876
  });
854
877
  // Get context summary
855
- app.get('/api/context', async (req, res) => {
878
+ app.get('/api/context', requireNotLocked, async (req, res) => {
856
879
  try {
857
880
  const project = typeof req.query.project === 'string' ? req.query.project : undefined;
858
881
  const summary = await generateContextSummary(project);
@@ -867,7 +890,7 @@ export function startVisualizationServer(dbPath) {
867
890
  }
868
891
  });
869
892
  // Get search suggestions (for autocomplete)
870
- app.get('/api/suggestions', (req, res) => {
893
+ app.get('/api/suggestions', requireNotLocked, (req, res) => {
871
894
  try {
872
895
  const query = typeof req.query.q === 'string' ? req.query.q : '';
873
896
  const limit = typeof req.query.limit === 'string' ? parseInt(req.query.limit) : 10;
@@ -926,7 +949,7 @@ export function startVisualizationServer(dbPath) {
926
949
  // GRAPH / ONTOLOGY ENDPOINTS
927
950
  // ============================================
928
951
  // List entities with optional filters and pagination
929
- app.get('/api/graph/entities', (req, res) => {
952
+ app.get('/api/graph/entities', requireNotLocked, (req, res) => {
930
953
  try {
931
954
  const db = getDatabase();
932
955
  const type = typeof req.query.type === 'string' ? req.query.type : undefined;
@@ -971,7 +994,7 @@ export function startVisualizationServer(dbPath) {
971
994
  }
972
995
  });
973
996
  // Get triples for a specific entity
974
- app.get('/api/graph/entities/:id/triples', (req, res) => {
997
+ app.get('/api/graph/entities/:id/triples', requireNotLocked, (req, res) => {
975
998
  try {
976
999
  const db = getDatabase();
977
1000
  const id = parseInt(req.params.id);
@@ -994,7 +1017,7 @@ export function startVisualizationServer(dbPath) {
994
1017
  }
995
1018
  });
996
1019
  // Get memories linked to a specific entity
997
- app.get('/api/graph/entities/:id/memories', (req, res) => {
1020
+ app.get('/api/graph/entities/:id/memories', requireNotLocked, (req, res) => {
998
1021
  try {
999
1022
  const db = getDatabase();
1000
1023
  const id = parseInt(req.params.id);
@@ -1016,7 +1039,7 @@ export function startVisualizationServer(dbPath) {
1016
1039
  }
1017
1040
  });
1018
1041
  // List triples with optional predicate filter and pagination
1019
- app.get('/api/graph/triples', (req, res) => {
1042
+ app.get('/api/graph/triples', requireNotLocked, (req, res) => {
1020
1043
  try {
1021
1044
  const db = getDatabase();
1022
1045
  const predicate = typeof req.query.predicate === 'string' ? req.query.predicate : undefined;
@@ -1047,7 +1070,7 @@ export function startVisualizationServer(dbPath) {
1047
1070
  }
1048
1071
  });
1049
1072
  // Search entities by name
1050
- app.get('/api/graph/search', (req, res) => {
1073
+ app.get('/api/graph/search', requireNotLocked, (req, res) => {
1051
1074
  try {
1052
1075
  const db = getDatabase();
1053
1076
  const q = typeof req.query.q === 'string' ? req.query.q : '';
@@ -1078,7 +1101,7 @@ export function startVisualizationServer(dbPath) {
1078
1101
  }
1079
1102
  });
1080
1103
  // Find path between two entities using BFS
1081
- app.get('/api/graph/paths', (req, res) => {
1104
+ app.get('/api/graph/paths', requireNotLocked, (req, res) => {
1082
1105
  try {
1083
1106
  const db = getDatabase();
1084
1107
  const fromName = typeof req.query.from === 'string' ? req.query.from : '';
@@ -1164,7 +1187,7 @@ export function startVisualizationServer(dbPath) {
1164
1187
  // BRAIN CONTROL CENTRE
1165
1188
  // ============================================
1166
1189
  // Boost memory salience (+0.15, capped at 1.0)
1167
- app.post('/api/memories/:id/boost', (req, res) => {
1190
+ app.post('/api/memories/:id/boost', requireNotLocked, (req, res) => {
1168
1191
  try {
1169
1192
  const id = parseInt(req.params.id);
1170
1193
  const memory = getMemoryById(id);
@@ -1180,7 +1203,7 @@ export function startVisualizationServer(dbPath) {
1180
1203
  }
1181
1204
  });
1182
1205
  // Demote memory salience (-0.15, floor at 0.05)
1183
- app.post('/api/memories/:id/demote', (req, res) => {
1206
+ app.post('/api/memories/:id/demote', requireNotLocked, (req, res) => {
1184
1207
  try {
1185
1208
  const id = parseInt(req.params.id);
1186
1209
  const memory = getMemoryById(id);
@@ -1196,7 +1219,7 @@ export function startVisualizationServer(dbPath) {
1196
1219
  }
1197
1220
  });
1198
1221
  // Promote memory from STM to LTM
1199
- app.post('/api/memories/:id/promote', (req, res) => {
1222
+ app.post('/api/memories/:id/promote', requireNotLocked, (req, res) => {
1200
1223
  try {
1201
1224
  const id = parseInt(req.params.id);
1202
1225
  const memory = promoteMemory(id);
@@ -1210,7 +1233,7 @@ export function startVisualizationServer(dbPath) {
1210
1233
  }
1211
1234
  });
1212
1235
  // Update memory (partial: title, content, tags, category)
1213
- app.patch('/api/memories/:id', (req, res) => {
1236
+ app.patch('/api/memories/:id', requireNotLocked, (req, res) => {
1214
1237
  try {
1215
1238
  const id = parseInt(req.params.id);
1216
1239
  const updated = updateMemory(id, req.body);
@@ -1224,7 +1247,7 @@ export function startVisualizationServer(dbPath) {
1224
1247
  }
1225
1248
  });
1226
1249
  // Quarantine a memory (move to quarantine table, delete original)
1227
- app.post('/api/memories/:id/quarantine', (req, res) => {
1250
+ app.post('/api/memories/:id/quarantine', requireNotLocked, (req, res) => {
1228
1251
  try {
1229
1252
  const id = parseInt(req.params.id);
1230
1253
  const memory = getMemoryById(id);
@@ -1242,7 +1265,7 @@ export function startVisualizationServer(dbPath) {
1242
1265
  }
1243
1266
  });
1244
1267
  // Create a manual link between two memories
1245
- app.post('/api/links', (req, res) => {
1268
+ app.post('/api/links', requireNotLocked, (req, res) => {
1246
1269
  try {
1247
1270
  const { sourceId, targetId, relationship, strength } = req.body;
1248
1271
  if (!sourceId || !targetId || !relationship) {
@@ -1447,6 +1470,35 @@ export function startVisualizationServer(dbPath) {
1447
1470
  res.status(500).json({ error: error.message });
1448
1471
  }
1449
1472
  });
1473
+ // Emergency Stop — activates kill switch, blocks ALL agent operations
1474
+ app.post('/api/iron-dome/emergency-stop', (_req, res) => {
1475
+ try {
1476
+ activateKillSwitch({ source: 'manual' });
1477
+ res.json({
1478
+ stopped: true,
1479
+ killSwitchActive: true,
1480
+ message: 'Kill switch activated. All agent operations blocked. Iron Dome remains active. Investigate before resuming.',
1481
+ });
1482
+ }
1483
+ catch (error) {
1484
+ res.status(500).json({ error: error.message });
1485
+ }
1486
+ });
1487
+ // Resume agent operations after investigation (requires reason)
1488
+ app.post('/api/iron-dome/resume', (req, res) => {
1489
+ try {
1490
+ const reason = req.body?.reason || 'Resumed via dashboard';
1491
+ deactivateKillSwitch(reason);
1492
+ res.json({
1493
+ resumed: true,
1494
+ killSwitchActive: false,
1495
+ message: 'Kill switch deactivated. Agent operations resumed. Iron Dome continues protecting.',
1496
+ });
1497
+ }
1498
+ catch (error) {
1499
+ res.status(500).json({ error: error.message });
1500
+ }
1501
+ });
1450
1502
  app.post('/api/iron-dome/scan', (req, res) => {
1451
1503
  try {
1452
1504
  const { text } = req.body;
@@ -1648,7 +1700,7 @@ export function startVisualizationServer(dbPath) {
1648
1700
  }
1649
1701
  });
1650
1702
  // Approve quarantined item
1651
- app.post('/api/v1/quarantine/:id/approve', (req, res) => {
1703
+ app.post('/api/v1/quarantine/:id/approve', requireNotLocked, (req, res) => {
1652
1704
  try {
1653
1705
  const db = getDatabase();
1654
1706
  const id = parseInt(req.params.id, 10);
@@ -1664,7 +1716,7 @@ export function startVisualizationServer(dbPath) {
1664
1716
  }
1665
1717
  });
1666
1718
  // Reject quarantined item
1667
- app.post('/api/v1/quarantine/:id/reject', (req, res) => {
1719
+ app.post('/api/v1/quarantine/:id/reject', requireNotLocked, (req, res) => {
1668
1720
  try {
1669
1721
  const db = getDatabase();
1670
1722
  const id = parseInt(req.params.id, 10);
@@ -1681,7 +1733,7 @@ export function startVisualizationServer(dbPath) {
1681
1733
  }
1682
1734
  });
1683
1735
  // Retroactive sync: push existing quarantine items to cloud
1684
- app.post('/api/quarantine/sync-to-cloud', async (_req, res) => {
1736
+ app.post('/api/quarantine/sync-to-cloud', requireNotLocked, async (_req, res) => {
1685
1737
  try {
1686
1738
  const config = getCloudConfig();
1687
1739
  if (!config.cloudEnabled || !config.cloudApiKey) {
@@ -1752,7 +1804,7 @@ export function startVisualizationServer(dbPath) {
1752
1804
  }
1753
1805
  });
1754
1806
  // Manually trigger light tick (for testing)
1755
- app.post('/api/worker/trigger-light', async (_req, res) => {
1807
+ app.post('/api/worker/trigger-light', requireNotLocked, async (_req, res) => {
1756
1808
  try {
1757
1809
  const result = await brainWorker.triggerLightTick();
1758
1810
  res.json({
@@ -1766,7 +1818,7 @@ export function startVisualizationServer(dbPath) {
1766
1818
  }
1767
1819
  });
1768
1820
  // Manually trigger medium tick (for testing)
1769
- app.post('/api/worker/trigger-medium', async (_req, res) => {
1821
+ app.post('/api/worker/trigger-medium', requireNotLocked, async (_req, res) => {
1770
1822
  try {
1771
1823
  const result = await brainWorker.triggerMediumTick();
1772
1824
  res.json({