shieldcortex 2.19.1 → 2.20.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.
- package/README.md +14 -10
- package/dashboard/.next/standalone/dashboard/.next/BUILD_ID +1 -1
- package/dashboard/.next/standalone/dashboard/.next/build-manifest.json +2 -2
- package/dashboard/.next/standalone/dashboard/.next/prerender-manifest.json +3 -3
- package/dashboard/.next/standalone/dashboard/.next/server/app/_global-error.html +2 -2
- package/dashboard/.next/standalone/dashboard/.next/server/app/_global-error.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.html +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.rsc +2 -2
- package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.segments/_full.segment.rsc +2 -2
- package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.segments/_index.segment.rsc +2 -2
- package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
- package/dashboard/.next/standalone/dashboard/.next/server/app/index.html +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/index.rsc +3 -3
- package/dashboard/.next/standalone/dashboard/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
- package/dashboard/.next/standalone/dashboard/.next/server/app/index.segments/_full.segment.rsc +3 -3
- package/dashboard/.next/standalone/dashboard/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/index.segments/_index.segment.rsc +2 -2
- package/dashboard/.next/standalone/dashboard/.next/server/app/index.segments/_tree.segment.rsc +2 -2
- package/dashboard/.next/standalone/dashboard/.next/server/app/page/react-loadable-manifest.json +3 -3
- package/dashboard/.next/standalone/dashboard/.next/server/app/page_client-reference-manifest.js +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/chunks/ssr/dashboard_25b1b286._.js +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/pages/404.html +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/pages/500.html +2 -2
- package/dashboard/.next/standalone/dashboard/.next/server/server-reference-manifest.js +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/server-reference-manifest.json +1 -1
- package/dashboard/.next/standalone/dashboard/.next/static/chunks/26118d592a545e00.js +3 -0
- package/dashboard/.next/standalone/dashboard/.next/static/chunks/6a6ccfb7834de00a.js +9 -0
- package/dashboard/.next/standalone/dashboard/.next/static/chunks/6b11a7d29e9abffd.js +1 -0
- package/dashboard/.next/standalone/dashboard/.next/static/chunks/ab13d81ce0e121f2.css +3 -0
- package/dashboard/.next/standalone/dashboard/.next/static/chunks/cf05262adfab5818.js +1 -0
- package/dist/api/control.d.ts +28 -11
- package/dist/api/control.d.ts.map +1 -1
- package/dist/api/control.js +120 -19
- package/dist/api/control.js.map +1 -1
- package/dist/api/events.d.ts +12 -1
- package/dist/api/events.d.ts.map +1 -1
- package/dist/api/events.js +9 -0
- package/dist/api/events.js.map +1 -1
- package/dist/api/visualization-server.d.ts.map +1 -1
- package/dist/api/visualization-server.js +306 -39
- package/dist/api/visualization-server.js.map +1 -1
- package/dist/cli/doctor.d.ts +6 -0
- package/dist/cli/doctor.d.ts.map +1 -0
- package/dist/cli/doctor.js +469 -0
- package/dist/cli/doctor.js.map +1 -0
- package/dist/cloud/quarantine-sync.d.ts +3 -0
- package/dist/cloud/quarantine-sync.d.ts.map +1 -1
- package/dist/cloud/quarantine-sync.js +7 -0
- package/dist/cloud/quarantine-sync.js.map +1 -1
- package/dist/cloud/sync.d.ts +11 -0
- package/dist/cloud/sync.d.ts.map +1 -1
- package/dist/cloud/sync.js +37 -0
- package/dist/cloud/sync.js.map +1 -1
- package/dist/database/init.d.ts +8 -0
- package/dist/database/init.d.ts.map +1 -1
- package/dist/database/init.js +208 -4
- package/dist/database/init.js.map +1 -1
- package/dist/defence/index.d.ts +2 -0
- package/dist/defence/index.d.ts.map +1 -1
- package/dist/defence/index.js +2 -0
- package/dist/defence/index.js.map +1 -1
- package/dist/defence/input-sanitisation/index.d.ts +28 -0
- package/dist/defence/input-sanitisation/index.d.ts.map +1 -0
- package/dist/defence/input-sanitisation/index.js +71 -0
- package/dist/defence/input-sanitisation/index.js.map +1 -0
- package/dist/defence/iron-dome/config.js +5 -5
- package/dist/defence/iron-dome/config.js.map +1 -1
- package/dist/defence/iron-dome/index.d.ts +6 -0
- package/dist/defence/iron-dome/index.d.ts.map +1 -1
- package/dist/defence/iron-dome/index.js +19 -0
- package/dist/defence/iron-dome/index.js.map +1 -1
- package/dist/defence/pipeline.d.ts.map +1 -1
- package/dist/defence/pipeline.js +21 -11
- package/dist/defence/pipeline.js.map +1 -1
- package/dist/events/webhooks.d.ts +21 -0
- package/dist/events/webhooks.d.ts.map +1 -0
- package/dist/events/webhooks.js +61 -0
- package/dist/events/webhooks.js.map +1 -0
- package/dist/graph/backfill.d.ts +6 -2
- package/dist/graph/backfill.d.ts.map +1 -1
- package/dist/graph/backfill.js +32 -4
- package/dist/graph/backfill.js.map +1 -1
- package/dist/graph/extract.d.ts.map +1 -1
- package/dist/graph/extract.js +105 -37
- package/dist/graph/extract.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +67 -5
- package/dist/index.js.map +1 -1
- package/dist/lib.d.ts +2 -0
- package/dist/lib.d.ts.map +1 -1
- package/dist/lib.js +2 -0
- package/dist/lib.js.map +1 -1
- package/dist/memory/consolidate.d.ts +23 -0
- package/dist/memory/consolidate.d.ts.map +1 -1
- package/dist/memory/consolidate.js +239 -2
- package/dist/memory/consolidate.js.map +1 -1
- package/dist/memory/decay.d.ts.map +1 -1
- package/dist/memory/decay.js +9 -0
- package/dist/memory/decay.js.map +1 -1
- package/dist/memory/embedding-cache.d.ts +21 -0
- package/dist/memory/embedding-cache.d.ts.map +1 -0
- package/dist/memory/embedding-cache.js +92 -0
- package/dist/memory/embedding-cache.js.map +1 -0
- package/dist/memory/embedding.d.ts +37 -0
- package/dist/memory/embedding.d.ts.map +1 -0
- package/dist/memory/embedding.js +86 -0
- package/dist/memory/embedding.js.map +1 -0
- package/dist/memory/expiry.d.ts +26 -0
- package/dist/memory/expiry.d.ts.map +1 -0
- package/dist/memory/expiry.js +109 -0
- package/dist/memory/expiry.js.map +1 -0
- package/dist/memory/store.d.ts +14 -0
- package/dist/memory/store.d.ts.map +1 -1
- package/dist/memory/store.js +82 -0
- package/dist/memory/store.js.map +1 -1
- package/dist/memory/types.d.ts +1 -0
- package/dist/memory/types.d.ts.map +1 -1
- package/dist/memory/types.js.map +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +193 -45
- package/dist/server.js.map +1 -1
- package/dist/tools/context.d.ts +4 -4
- package/dist/tools/forget.d.ts +4 -4
- package/dist/tools/recall.d.ts +9 -9
- package/dist/tools/recall.d.ts.map +1 -1
- package/dist/tools/recall.js +25 -1
- package/dist/tools/recall.js.map +1 -1
- package/dist/tools/remember.d.ts +6 -6
- package/hooks/openclaw/cortex-memory/handler.ts +8 -18
- package/package.json +1 -1
- package/dashboard/.next/standalone/dashboard/.next/static/chunks/1a71c9a52f0c9b16.css +0 -3
- package/dashboard/.next/standalone/dashboard/.next/static/chunks/6bf7d89d34068ecb.js +0 -9
- package/dashboard/.next/standalone/dashboard/.next/static/chunks/a3989d0e6629bcf8.js +0 -3
- package/dashboard/.next/standalone/dashboard/.next/static/chunks/d0dcb5e0e04ae015.js +0 -1
- package/dashboard/.next/standalone/dashboard/.next/static/chunks/fc2dbf641aad1448.js +0 -1
- /package/dashboard/.next/standalone/dashboard/.next/static/{vxPliVFK4FIBIPl1JPL0U → aFo1BShJENvQZgqpWRJaw}/_buildManifest.js +0 -0
- /package/dashboard/.next/standalone/dashboard/.next/static/{vxPliVFK4FIBIPl1JPL0U → aFo1BShJENvQZgqpWRJaw}/_clientMiddlewareManifest.json +0 -0
- /package/dashboard/.next/standalone/dashboard/.next/static/{vxPliVFK4FIBIPl1JPL0U → aFo1BShJENvQZgqpWRJaw}/_ssgManifest.js +0 -0
package/dist/api/events.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"events.js","sourceRoot":"","sources":["../../src/api/events.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AAEtC,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"events.js","sourceRoot":"","sources":["../../src/api/events.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"visualization-server.d.ts","sourceRoot":"","sources":["../../src/api/visualization-server.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAqGH;;GAEG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,
|
|
1
|
+
{"version":3,"file":"visualization-server.d.ts","sourceRoot":"","sources":["../../src/api/visualization-server.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAqGH;;GAEG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAmoF9D"}
|
|
@@ -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);
|
|
@@ -381,8 +398,81 @@ export function startVisualizationServer(dbPath) {
|
|
|
381
398
|
res.status(500).json({ error: error.message });
|
|
382
399
|
}
|
|
383
400
|
});
|
|
401
|
+
// Memory health score (composite metric)
|
|
402
|
+
app.get('/api/health-score', requireNotLocked, (_req, res) => {
|
|
403
|
+
try {
|
|
404
|
+
const db = getDatabase();
|
|
405
|
+
// ── Freshness ──
|
|
406
|
+
const totalCount = db.prepare('SELECT COUNT(*) as count FROM memories').get().count;
|
|
407
|
+
const freshCount = db.prepare('SELECT COUNT(*) as count FROM memories WHERE decayed_score > 0.3').get().count;
|
|
408
|
+
const freshnessScore = totalCount > 0 ? Math.round((freshCount / totalCount) * 100) : 100;
|
|
409
|
+
const freshPct = totalCount > 0 ? Math.round((freshCount / totalCount) * 100) : 100;
|
|
410
|
+
// ── Coverage ──
|
|
411
|
+
const linkedCount = db.prepare('SELECT COUNT(DISTINCT memory_id) as count FROM memory_entities').get().count;
|
|
412
|
+
const coverageScore = totalCount > 0 ? Math.round((linkedCount / totalCount) * 100) : 0;
|
|
413
|
+
// ── Consistency ──
|
|
414
|
+
const contradictionCount = db.prepare("SELECT COUNT(*) as count FROM memory_links WHERE relationship = 'contradicts'").get().count;
|
|
415
|
+
const consistencyScore = Math.max(0, 100 - (contradictionCount * 10));
|
|
416
|
+
// ── Consolidation ──
|
|
417
|
+
const lastConsolidated = db.prepare("SELECT created_at FROM memories WHERE type = 'long_term' AND tags LIKE '%auto-consolidated%' ORDER BY created_at DESC LIMIT 1").get();
|
|
418
|
+
let consolidationScore = 25;
|
|
419
|
+
if (lastConsolidated) {
|
|
420
|
+
const hoursAgo = (Date.now() - new Date(lastConsolidated.created_at).getTime()) / (1000 * 60 * 60);
|
|
421
|
+
if (hoursAgo <= 4)
|
|
422
|
+
consolidationScore = 100;
|
|
423
|
+
else if (hoursAgo <= 8)
|
|
424
|
+
consolidationScore = 75;
|
|
425
|
+
else if (hoursAgo <= 24)
|
|
426
|
+
consolidationScore = 50;
|
|
427
|
+
else
|
|
428
|
+
consolidationScore = 25;
|
|
429
|
+
}
|
|
430
|
+
// ── Overall (weighted average) ──
|
|
431
|
+
const overall = Math.round(freshnessScore * 0.3 +
|
|
432
|
+
coverageScore * 0.25 +
|
|
433
|
+
consistencyScore * 0.25 +
|
|
434
|
+
consolidationScore * 0.2);
|
|
435
|
+
// ── Consolidation detail text ──
|
|
436
|
+
let consolidationDetail = 'No consolidated memories found';
|
|
437
|
+
if (lastConsolidated) {
|
|
438
|
+
const hoursAgo = (Date.now() - new Date(lastConsolidated.created_at).getTime()) / (1000 * 60 * 60);
|
|
439
|
+
if (hoursAgo < 1)
|
|
440
|
+
consolidationDetail = 'Last consolidated less than 1 hour ago';
|
|
441
|
+
else
|
|
442
|
+
consolidationDetail = `Last consolidated ${Math.round(hoursAgo)} hours ago`;
|
|
443
|
+
}
|
|
444
|
+
res.json({
|
|
445
|
+
overall,
|
|
446
|
+
components: {
|
|
447
|
+
freshness: {
|
|
448
|
+
score: freshnessScore,
|
|
449
|
+
label: 'Memory Freshness',
|
|
450
|
+
detail: `${freshPct}% of memories above decay threshold`,
|
|
451
|
+
},
|
|
452
|
+
coverage: {
|
|
453
|
+
score: coverageScore,
|
|
454
|
+
label: 'Graph Coverage',
|
|
455
|
+
detail: `${coverageScore}% of memories have entity links`,
|
|
456
|
+
},
|
|
457
|
+
consistency: {
|
|
458
|
+
score: consistencyScore,
|
|
459
|
+
label: 'Consistency',
|
|
460
|
+
detail: `${contradictionCount} contradictions detected`,
|
|
461
|
+
},
|
|
462
|
+
consolidation: {
|
|
463
|
+
score: consolidationScore,
|
|
464
|
+
label: 'Consolidation',
|
|
465
|
+
detail: consolidationDetail,
|
|
466
|
+
},
|
|
467
|
+
},
|
|
468
|
+
});
|
|
469
|
+
}
|
|
470
|
+
catch (error) {
|
|
471
|
+
res.status(500).json({ error: error.message });
|
|
472
|
+
}
|
|
473
|
+
});
|
|
384
474
|
// Get currently activated memories (spreading activation)
|
|
385
|
-
app.get('/api/activation', (_req, res) => {
|
|
475
|
+
app.get('/api/activation', requireNotLocked, (_req, res) => {
|
|
386
476
|
try {
|
|
387
477
|
const activeMemories = getActiveMemories();
|
|
388
478
|
const stats = getActivationStats();
|
|
@@ -400,7 +490,7 @@ export function startVisualizationServer(dbPath) {
|
|
|
400
490
|
// ORGANIC BRAIN ENDPOINTS (Phase 3)
|
|
401
491
|
// ============================================
|
|
402
492
|
// Get detected contradictions
|
|
403
|
-
app.get('/api/contradictions', (req, res) => {
|
|
493
|
+
app.get('/api/contradictions', requireNotLocked, (req, res) => {
|
|
404
494
|
try {
|
|
405
495
|
const project = typeof req.query.project === 'string' ? req.query.project : undefined;
|
|
406
496
|
const category = typeof req.query.category === 'string' ? req.query.category : undefined;
|
|
@@ -433,7 +523,7 @@ export function startVisualizationServer(dbPath) {
|
|
|
433
523
|
}
|
|
434
524
|
});
|
|
435
525
|
// Get contradictions for a specific memory
|
|
436
|
-
app.get('/api/memories/:id/contradictions', (req, res) => {
|
|
526
|
+
app.get('/api/memories/:id/contradictions', requireNotLocked, (req, res) => {
|
|
437
527
|
try {
|
|
438
528
|
const id = parseInt(req.params.id);
|
|
439
529
|
if (isNaN(id)) {
|
|
@@ -457,7 +547,7 @@ export function startVisualizationServer(dbPath) {
|
|
|
457
547
|
}
|
|
458
548
|
});
|
|
459
549
|
// Manually enrich a memory with new context
|
|
460
|
-
app.post('/api/memories/:id/enrich', (req, res) => {
|
|
550
|
+
app.post('/api/memories/:id/enrich', requireNotLocked, (req, res) => {
|
|
461
551
|
try {
|
|
462
552
|
const id = parseInt(req.params.id);
|
|
463
553
|
if (isNaN(id)) {
|
|
@@ -513,9 +603,12 @@ export function startVisualizationServer(dbPath) {
|
|
|
513
603
|
res.status(500).json({ error: error.message });
|
|
514
604
|
}
|
|
515
605
|
});
|
|
516
|
-
// Pause memory creation
|
|
606
|
+
// Pause memory creation (soft pause — kill switch takes precedence)
|
|
517
607
|
app.post('/api/control/pause', (_req, res) => {
|
|
518
608
|
try {
|
|
609
|
+
if (isKillSwitchActive()) {
|
|
610
|
+
return res.status(409).json({ error: 'Kill switch is active — use /api/iron-dome/resume to deactivate first', code: 'KILL_SWITCH_ACTIVE' });
|
|
611
|
+
}
|
|
519
612
|
pause();
|
|
520
613
|
res.json({ paused: true, message: 'Memory creation paused' });
|
|
521
614
|
}
|
|
@@ -523,9 +616,12 @@ export function startVisualizationServer(dbPath) {
|
|
|
523
616
|
res.status(500).json({ error: error.message });
|
|
524
617
|
}
|
|
525
618
|
});
|
|
526
|
-
// Resume memory creation
|
|
619
|
+
// Resume memory creation (soft resume — cannot override kill switch)
|
|
527
620
|
app.post('/api/control/resume', (_req, res) => {
|
|
528
621
|
try {
|
|
622
|
+
if (isKillSwitchActive()) {
|
|
623
|
+
return res.status(409).json({ error: 'Kill switch is active — use /api/iron-dome/resume to deactivate first', code: 'KILL_SWITCH_ACTIVE' });
|
|
624
|
+
}
|
|
529
625
|
resume();
|
|
530
626
|
res.json({ paused: false, message: 'Memory creation resumed' });
|
|
531
627
|
}
|
|
@@ -727,7 +823,7 @@ export function startVisualizationServer(dbPath) {
|
|
|
727
823
|
}
|
|
728
824
|
});
|
|
729
825
|
// Get memory links/relationships
|
|
730
|
-
app.get('/api/links', (req, res) => {
|
|
826
|
+
app.get('/api/links', requireNotLocked, (req, res) => {
|
|
731
827
|
try {
|
|
732
828
|
const project = typeof req.query.project === 'string' ? req.query.project : undefined;
|
|
733
829
|
const db = getDatabase();
|
|
@@ -780,7 +876,7 @@ export function startVisualizationServer(dbPath) {
|
|
|
780
876
|
// SQL CONSOLE ENDPOINT
|
|
781
877
|
// ============================================
|
|
782
878
|
// Execute SQL query (with safety restrictions)
|
|
783
|
-
app.post('/api/sql', (req, res) => {
|
|
879
|
+
app.post('/api/sql', requireNotLocked, (req, res) => {
|
|
784
880
|
try {
|
|
785
881
|
const { query, allowWrite } = req.body;
|
|
786
882
|
if (!query || typeof query !== 'string') {
|
|
@@ -837,7 +933,7 @@ export function startVisualizationServer(dbPath) {
|
|
|
837
933
|
}
|
|
838
934
|
});
|
|
839
935
|
// Trigger consolidation
|
|
840
|
-
app.post('/api/consolidate', (_req, res) => {
|
|
936
|
+
app.post('/api/consolidate', requireNotLocked, (_req, res) => {
|
|
841
937
|
try {
|
|
842
938
|
const result = consolidate();
|
|
843
939
|
// Emit event for Activity log
|
|
@@ -852,7 +948,7 @@ export function startVisualizationServer(dbPath) {
|
|
|
852
948
|
}
|
|
853
949
|
});
|
|
854
950
|
// Get context summary
|
|
855
|
-
app.get('/api/context', async (req, res) => {
|
|
951
|
+
app.get('/api/context', requireNotLocked, async (req, res) => {
|
|
856
952
|
try {
|
|
857
953
|
const project = typeof req.query.project === 'string' ? req.query.project : undefined;
|
|
858
954
|
const summary = await generateContextSummary(project);
|
|
@@ -867,7 +963,7 @@ export function startVisualizationServer(dbPath) {
|
|
|
867
963
|
}
|
|
868
964
|
});
|
|
869
965
|
// Get search suggestions (for autocomplete)
|
|
870
|
-
app.get('/api/suggestions', (req, res) => {
|
|
966
|
+
app.get('/api/suggestions', requireNotLocked, (req, res) => {
|
|
871
967
|
try {
|
|
872
968
|
const query = typeof req.query.q === 'string' ? req.query.q : '';
|
|
873
969
|
const limit = typeof req.query.limit === 'string' ? parseInt(req.query.limit) : 10;
|
|
@@ -926,7 +1022,7 @@ export function startVisualizationServer(dbPath) {
|
|
|
926
1022
|
// GRAPH / ONTOLOGY ENDPOINTS
|
|
927
1023
|
// ============================================
|
|
928
1024
|
// List entities with optional filters and pagination
|
|
929
|
-
app.get('/api/graph/entities', (req, res) => {
|
|
1025
|
+
app.get('/api/graph/entities', requireNotLocked, (req, res) => {
|
|
930
1026
|
try {
|
|
931
1027
|
const db = getDatabase();
|
|
932
1028
|
const type = typeof req.query.type === 'string' ? req.query.type : undefined;
|
|
@@ -971,7 +1067,7 @@ export function startVisualizationServer(dbPath) {
|
|
|
971
1067
|
}
|
|
972
1068
|
});
|
|
973
1069
|
// Get triples for a specific entity
|
|
974
|
-
app.get('/api/graph/entities/:id/triples', (req, res) => {
|
|
1070
|
+
app.get('/api/graph/entities/:id/triples', requireNotLocked, (req, res) => {
|
|
975
1071
|
try {
|
|
976
1072
|
const db = getDatabase();
|
|
977
1073
|
const id = parseInt(req.params.id);
|
|
@@ -994,7 +1090,7 @@ export function startVisualizationServer(dbPath) {
|
|
|
994
1090
|
}
|
|
995
1091
|
});
|
|
996
1092
|
// Get memories linked to a specific entity
|
|
997
|
-
app.get('/api/graph/entities/:id/memories', (req, res) => {
|
|
1093
|
+
app.get('/api/graph/entities/:id/memories', requireNotLocked, (req, res) => {
|
|
998
1094
|
try {
|
|
999
1095
|
const db = getDatabase();
|
|
1000
1096
|
const id = parseInt(req.params.id);
|
|
@@ -1015,12 +1111,112 @@ export function startVisualizationServer(dbPath) {
|
|
|
1015
1111
|
res.status(500).json({ error: error.message });
|
|
1016
1112
|
}
|
|
1017
1113
|
});
|
|
1114
|
+
// Get neighbourhood of an entity: the entity, its direct neighbours, and connecting triples
|
|
1115
|
+
app.get('/api/graph/entities/:id/neighbourhood', requireNotLocked, (req, res) => {
|
|
1116
|
+
try {
|
|
1117
|
+
const db = getDatabase();
|
|
1118
|
+
const id = parseInt(req.params.id);
|
|
1119
|
+
if (isNaN(id)) {
|
|
1120
|
+
return res.status(400).json({ error: 'Invalid entity ID' });
|
|
1121
|
+
}
|
|
1122
|
+
// Get the focal entity
|
|
1123
|
+
const focal = db.prepare('SELECT id, name, type, memory_count as memoryCount, aliases FROM entities WHERE id = ?').get(id);
|
|
1124
|
+
if (!focal) {
|
|
1125
|
+
return res.status(404).json({ error: 'Entity not found' });
|
|
1126
|
+
}
|
|
1127
|
+
focal.aliases = JSON.parse(focal.aliases || '[]');
|
|
1128
|
+
// Get all triples involving this entity (exclude related_to noise — only meaningful predicates)
|
|
1129
|
+
const triplesAll = db.prepare(`
|
|
1130
|
+
SELECT t.id, t.subject_id, t.object_id, t.predicate,
|
|
1131
|
+
s.name as subject_name, s.type as subject_type, s.memory_count as subject_count,
|
|
1132
|
+
o.name as object_name, o.type as object_type, o.memory_count as object_count
|
|
1133
|
+
FROM triples t
|
|
1134
|
+
JOIN entities s ON s.id = t.subject_id
|
|
1135
|
+
JOIN entities o ON o.id = t.object_id
|
|
1136
|
+
WHERE (t.subject_id = ? OR t.object_id = ?)
|
|
1137
|
+
ORDER BY
|
|
1138
|
+
CASE WHEN t.predicate != 'related_to' THEN 0 ELSE 1 END,
|
|
1139
|
+
CASE WHEN t.subject_id = ? THEN o.memory_count ELSE s.memory_count END DESC
|
|
1140
|
+
`).all(id, id, id);
|
|
1141
|
+
// Collect unique neighbour IDs, prioritising meaningful predicates
|
|
1142
|
+
const neighbourIds = new Map();
|
|
1143
|
+
const meaningfulTriples = [];
|
|
1144
|
+
const relatedToTriples = [];
|
|
1145
|
+
for (const t of triplesAll) {
|
|
1146
|
+
const neighbourId = t.subject_id === id ? t.object_id : t.subject_id;
|
|
1147
|
+
const count = t.subject_id === id ? t.object_count : t.subject_count;
|
|
1148
|
+
if (neighbourId === id)
|
|
1149
|
+
continue;
|
|
1150
|
+
if (t.predicate !== 'related_to') {
|
|
1151
|
+
meaningfulTriples.push(t);
|
|
1152
|
+
if (!neighbourIds.has(neighbourId)) {
|
|
1153
|
+
neighbourIds.set(neighbourId, { predicate: t.predicate, count });
|
|
1154
|
+
}
|
|
1155
|
+
}
|
|
1156
|
+
else {
|
|
1157
|
+
relatedToTriples.push(t);
|
|
1158
|
+
}
|
|
1159
|
+
}
|
|
1160
|
+
// Add related_to neighbours up to a cap (prefer high memory count)
|
|
1161
|
+
for (const t of relatedToTriples) {
|
|
1162
|
+
if (neighbourIds.size >= 25)
|
|
1163
|
+
break;
|
|
1164
|
+
const neighbourId = t.subject_id === id ? t.object_id : t.subject_id;
|
|
1165
|
+
const count = t.subject_id === id ? t.object_count : t.subject_count;
|
|
1166
|
+
if (!neighbourIds.has(neighbourId)) {
|
|
1167
|
+
neighbourIds.set(neighbourId, { predicate: 'related_to', count });
|
|
1168
|
+
}
|
|
1169
|
+
}
|
|
1170
|
+
// Build triples list (only for included neighbours)
|
|
1171
|
+
const includedTriples = [
|
|
1172
|
+
...meaningfulTriples.filter(t => {
|
|
1173
|
+
const nid = t.subject_id === id ? t.object_id : t.subject_id;
|
|
1174
|
+
return neighbourIds.has(nid);
|
|
1175
|
+
}),
|
|
1176
|
+
...relatedToTriples.filter(t => {
|
|
1177
|
+
const nid = t.subject_id === id ? t.object_id : t.subject_id;
|
|
1178
|
+
return neighbourIds.has(nid);
|
|
1179
|
+
}),
|
|
1180
|
+
];
|
|
1181
|
+
// Deduplicate triples by id
|
|
1182
|
+
const seenTriples = new Set();
|
|
1183
|
+
const uniqueTriples = includedTriples.filter(t => {
|
|
1184
|
+
if (seenTriples.has(t.id))
|
|
1185
|
+
return false;
|
|
1186
|
+
seenTriples.add(t.id);
|
|
1187
|
+
return true;
|
|
1188
|
+
});
|
|
1189
|
+
// Fetch neighbour entities
|
|
1190
|
+
const neighbourEntities = [];
|
|
1191
|
+
if (neighbourIds.size > 0) {
|
|
1192
|
+
const ids = [...neighbourIds.keys()];
|
|
1193
|
+
const placeholders = ids.map(() => '?').join(',');
|
|
1194
|
+
const rows = db.prepare(`
|
|
1195
|
+
SELECT id, name, type, memory_count as memoryCount, aliases
|
|
1196
|
+
FROM entities WHERE id IN (${placeholders})
|
|
1197
|
+
`).all(...ids);
|
|
1198
|
+
for (const r of rows) {
|
|
1199
|
+
r.aliases = JSON.parse(r.aliases || '[]');
|
|
1200
|
+
neighbourEntities.push(r);
|
|
1201
|
+
}
|
|
1202
|
+
}
|
|
1203
|
+
res.json({
|
|
1204
|
+
focal,
|
|
1205
|
+
neighbours: neighbourEntities,
|
|
1206
|
+
triples: uniqueTriples,
|
|
1207
|
+
totalConnections: triplesAll.length,
|
|
1208
|
+
});
|
|
1209
|
+
}
|
|
1210
|
+
catch (error) {
|
|
1211
|
+
res.status(500).json({ error: error.message });
|
|
1212
|
+
}
|
|
1213
|
+
});
|
|
1018
1214
|
// List triples with optional predicate filter and pagination
|
|
1019
|
-
app.get('/api/graph/triples', (req, res) => {
|
|
1215
|
+
app.get('/api/graph/triples', requireNotLocked, (req, res) => {
|
|
1020
1216
|
try {
|
|
1021
1217
|
const db = getDatabase();
|
|
1022
1218
|
const predicate = typeof req.query.predicate === 'string' ? req.query.predicate : undefined;
|
|
1023
|
-
const limit = typeof req.query.limit === 'string' ? Math.min(parseInt(req.query.limit),
|
|
1219
|
+
const limit = typeof req.query.limit === 'string' ? Math.min(parseInt(req.query.limit), 10000) : 100;
|
|
1024
1220
|
const offset = typeof req.query.offset === 'string' ? parseInt(req.query.offset) : 0;
|
|
1025
1221
|
let whereClause = '';
|
|
1026
1222
|
const params = [];
|
|
@@ -1028,6 +1224,8 @@ export function startVisualizationServer(dbPath) {
|
|
|
1028
1224
|
whereClause = 'WHERE t.predicate = ?';
|
|
1029
1225
|
params.push(predicate);
|
|
1030
1226
|
}
|
|
1227
|
+
// For large triple sets, only return triples involving the top 500 entities
|
|
1228
|
+
// to keep response sizes manageable
|
|
1031
1229
|
const totalRow = db.prepare(`SELECT COUNT(*) as count FROM triples t ${whereClause}`).get(...params);
|
|
1032
1230
|
const total = totalRow.count;
|
|
1033
1231
|
const rows = db.prepare(`
|
|
@@ -1047,7 +1245,7 @@ export function startVisualizationServer(dbPath) {
|
|
|
1047
1245
|
}
|
|
1048
1246
|
});
|
|
1049
1247
|
// Search entities by name
|
|
1050
|
-
app.get('/api/graph/search', (req, res) => {
|
|
1248
|
+
app.get('/api/graph/search', requireNotLocked, (req, res) => {
|
|
1051
1249
|
try {
|
|
1052
1250
|
const db = getDatabase();
|
|
1053
1251
|
const q = typeof req.query.q === 'string' ? req.query.q : '';
|
|
@@ -1078,7 +1276,7 @@ export function startVisualizationServer(dbPath) {
|
|
|
1078
1276
|
}
|
|
1079
1277
|
});
|
|
1080
1278
|
// Find path between two entities using BFS
|
|
1081
|
-
app.get('/api/graph/paths', (req, res) => {
|
|
1279
|
+
app.get('/api/graph/paths', requireNotLocked, (req, res) => {
|
|
1082
1280
|
try {
|
|
1083
1281
|
const db = getDatabase();
|
|
1084
1282
|
const fromName = typeof req.query.from === 'string' ? req.query.from : '';
|
|
@@ -1164,7 +1362,7 @@ export function startVisualizationServer(dbPath) {
|
|
|
1164
1362
|
// BRAIN CONTROL CENTRE
|
|
1165
1363
|
// ============================================
|
|
1166
1364
|
// Boost memory salience (+0.15, capped at 1.0)
|
|
1167
|
-
app.post('/api/memories/:id/boost', (req, res) => {
|
|
1365
|
+
app.post('/api/memories/:id/boost', requireNotLocked, (req, res) => {
|
|
1168
1366
|
try {
|
|
1169
1367
|
const id = parseInt(req.params.id);
|
|
1170
1368
|
const memory = getMemoryById(id);
|
|
@@ -1180,7 +1378,7 @@ export function startVisualizationServer(dbPath) {
|
|
|
1180
1378
|
}
|
|
1181
1379
|
});
|
|
1182
1380
|
// Demote memory salience (-0.15, floor at 0.05)
|
|
1183
|
-
app.post('/api/memories/:id/demote', (req, res) => {
|
|
1381
|
+
app.post('/api/memories/:id/demote', requireNotLocked, (req, res) => {
|
|
1184
1382
|
try {
|
|
1185
1383
|
const id = parseInt(req.params.id);
|
|
1186
1384
|
const memory = getMemoryById(id);
|
|
@@ -1196,7 +1394,7 @@ export function startVisualizationServer(dbPath) {
|
|
|
1196
1394
|
}
|
|
1197
1395
|
});
|
|
1198
1396
|
// Promote memory from STM to LTM
|
|
1199
|
-
app.post('/api/memories/:id/promote', (req, res) => {
|
|
1397
|
+
app.post('/api/memories/:id/promote', requireNotLocked, (req, res) => {
|
|
1200
1398
|
try {
|
|
1201
1399
|
const id = parseInt(req.params.id);
|
|
1202
1400
|
const memory = promoteMemory(id);
|
|
@@ -1209,11 +1407,51 @@ export function startVisualizationServer(dbPath) {
|
|
|
1209
1407
|
res.status(500).json({ error: error.message });
|
|
1210
1408
|
}
|
|
1211
1409
|
});
|
|
1212
|
-
// Update memory (partial: title, content, tags, category)
|
|
1213
|
-
app.patch('/api/memories/:id', (req, res) => {
|
|
1410
|
+
// Update memory (partial: title, content, tags, category, importance/salience)
|
|
1411
|
+
app.patch('/api/memories/:id', requireNotLocked, (req, res) => {
|
|
1214
1412
|
try {
|
|
1215
1413
|
const id = parseInt(req.params.id);
|
|
1216
|
-
const
|
|
1414
|
+
const { title, content, category, tags, importance } = req.body;
|
|
1415
|
+
// Validate provided fields
|
|
1416
|
+
if (title !== undefined) {
|
|
1417
|
+
if (typeof title !== 'string' || title.trim().length === 0) {
|
|
1418
|
+
return res.status(400).json({ error: 'Title must be a non-empty string' });
|
|
1419
|
+
}
|
|
1420
|
+
}
|
|
1421
|
+
if (content !== undefined) {
|
|
1422
|
+
if (typeof content !== 'string') {
|
|
1423
|
+
return res.status(400).json({ error: 'Content must be a string' });
|
|
1424
|
+
}
|
|
1425
|
+
}
|
|
1426
|
+
const validCategories = ['architecture', 'pattern', 'preference', 'error', 'context', 'learning', 'todo', 'note', 'relationship', 'custom'];
|
|
1427
|
+
if (category !== undefined) {
|
|
1428
|
+
if (!validCategories.includes(category)) {
|
|
1429
|
+
return res.status(400).json({ error: `Category must be one of: ${validCategories.join(', ')}` });
|
|
1430
|
+
}
|
|
1431
|
+
}
|
|
1432
|
+
if (tags !== undefined) {
|
|
1433
|
+
if (!Array.isArray(tags) || !tags.every((t) => typeof t === 'string')) {
|
|
1434
|
+
return res.status(400).json({ error: 'Tags must be an array of strings' });
|
|
1435
|
+
}
|
|
1436
|
+
}
|
|
1437
|
+
if (importance !== undefined) {
|
|
1438
|
+
if (typeof importance !== 'number' || importance < 0 || importance > 1) {
|
|
1439
|
+
return res.status(400).json({ error: 'Importance must be a number between 0 and 1' });
|
|
1440
|
+
}
|
|
1441
|
+
}
|
|
1442
|
+
// Build clean updates object (map importance → salience)
|
|
1443
|
+
const updates = {};
|
|
1444
|
+
if (title !== undefined)
|
|
1445
|
+
updates.title = title.trim();
|
|
1446
|
+
if (content !== undefined)
|
|
1447
|
+
updates.content = content;
|
|
1448
|
+
if (category !== undefined)
|
|
1449
|
+
updates.category = category;
|
|
1450
|
+
if (tags !== undefined)
|
|
1451
|
+
updates.tags = tags;
|
|
1452
|
+
if (importance !== undefined)
|
|
1453
|
+
updates.salience = importance;
|
|
1454
|
+
const updated = updateMemory(id, updates);
|
|
1217
1455
|
if (!updated) {
|
|
1218
1456
|
return res.status(404).json({ error: 'Memory not found' });
|
|
1219
1457
|
}
|
|
@@ -1224,7 +1462,7 @@ export function startVisualizationServer(dbPath) {
|
|
|
1224
1462
|
}
|
|
1225
1463
|
});
|
|
1226
1464
|
// Quarantine a memory (move to quarantine table, delete original)
|
|
1227
|
-
app.post('/api/memories/:id/quarantine', (req, res) => {
|
|
1465
|
+
app.post('/api/memories/:id/quarantine', requireNotLocked, (req, res) => {
|
|
1228
1466
|
try {
|
|
1229
1467
|
const id = parseInt(req.params.id);
|
|
1230
1468
|
const memory = getMemoryById(id);
|
|
@@ -1242,7 +1480,7 @@ export function startVisualizationServer(dbPath) {
|
|
|
1242
1480
|
}
|
|
1243
1481
|
});
|
|
1244
1482
|
// Create a manual link between two memories
|
|
1245
|
-
app.post('/api/links', (req, res) => {
|
|
1483
|
+
app.post('/api/links', requireNotLocked, (req, res) => {
|
|
1246
1484
|
try {
|
|
1247
1485
|
const { sourceId, targetId, relationship, strength } = req.body;
|
|
1248
1486
|
if (!sourceId || !targetId || !relationship) {
|
|
@@ -1447,6 +1685,35 @@ export function startVisualizationServer(dbPath) {
|
|
|
1447
1685
|
res.status(500).json({ error: error.message });
|
|
1448
1686
|
}
|
|
1449
1687
|
});
|
|
1688
|
+
// Emergency Stop — activates kill switch, blocks ALL agent operations
|
|
1689
|
+
app.post('/api/iron-dome/emergency-stop', (_req, res) => {
|
|
1690
|
+
try {
|
|
1691
|
+
activateKillSwitch({ source: 'manual' });
|
|
1692
|
+
res.json({
|
|
1693
|
+
stopped: true,
|
|
1694
|
+
killSwitchActive: true,
|
|
1695
|
+
message: 'Kill switch activated. All agent operations blocked. Iron Dome remains active. Investigate before resuming.',
|
|
1696
|
+
});
|
|
1697
|
+
}
|
|
1698
|
+
catch (error) {
|
|
1699
|
+
res.status(500).json({ error: error.message });
|
|
1700
|
+
}
|
|
1701
|
+
});
|
|
1702
|
+
// Resume agent operations after investigation (requires reason)
|
|
1703
|
+
app.post('/api/iron-dome/resume', (req, res) => {
|
|
1704
|
+
try {
|
|
1705
|
+
const reason = req.body?.reason || 'Resumed via dashboard';
|
|
1706
|
+
deactivateKillSwitch(reason);
|
|
1707
|
+
res.json({
|
|
1708
|
+
resumed: true,
|
|
1709
|
+
killSwitchActive: false,
|
|
1710
|
+
message: 'Kill switch deactivated. Agent operations resumed. Iron Dome continues protecting.',
|
|
1711
|
+
});
|
|
1712
|
+
}
|
|
1713
|
+
catch (error) {
|
|
1714
|
+
res.status(500).json({ error: error.message });
|
|
1715
|
+
}
|
|
1716
|
+
});
|
|
1450
1717
|
app.post('/api/iron-dome/scan', (req, res) => {
|
|
1451
1718
|
try {
|
|
1452
1719
|
const { text } = req.body;
|
|
@@ -1648,7 +1915,7 @@ export function startVisualizationServer(dbPath) {
|
|
|
1648
1915
|
}
|
|
1649
1916
|
});
|
|
1650
1917
|
// Approve quarantined item
|
|
1651
|
-
app.post('/api/v1/quarantine/:id/approve', (req, res) => {
|
|
1918
|
+
app.post('/api/v1/quarantine/:id/approve', requireNotLocked, (req, res) => {
|
|
1652
1919
|
try {
|
|
1653
1920
|
const db = getDatabase();
|
|
1654
1921
|
const id = parseInt(req.params.id, 10);
|
|
@@ -1664,7 +1931,7 @@ export function startVisualizationServer(dbPath) {
|
|
|
1664
1931
|
}
|
|
1665
1932
|
});
|
|
1666
1933
|
// Reject quarantined item
|
|
1667
|
-
app.post('/api/v1/quarantine/:id/reject', (req, res) => {
|
|
1934
|
+
app.post('/api/v1/quarantine/:id/reject', requireNotLocked, (req, res) => {
|
|
1668
1935
|
try {
|
|
1669
1936
|
const db = getDatabase();
|
|
1670
1937
|
const id = parseInt(req.params.id, 10);
|
|
@@ -1681,7 +1948,7 @@ export function startVisualizationServer(dbPath) {
|
|
|
1681
1948
|
}
|
|
1682
1949
|
});
|
|
1683
1950
|
// Retroactive sync: push existing quarantine items to cloud
|
|
1684
|
-
app.post('/api/quarantine/sync-to-cloud', async (_req, res) => {
|
|
1951
|
+
app.post('/api/quarantine/sync-to-cloud', requireNotLocked, async (_req, res) => {
|
|
1685
1952
|
try {
|
|
1686
1953
|
const config = getCloudConfig();
|
|
1687
1954
|
if (!config.cloudEnabled || !config.cloudApiKey) {
|
|
@@ -1752,7 +2019,7 @@ export function startVisualizationServer(dbPath) {
|
|
|
1752
2019
|
}
|
|
1753
2020
|
});
|
|
1754
2021
|
// Manually trigger light tick (for testing)
|
|
1755
|
-
app.post('/api/worker/trigger-light', async (_req, res) => {
|
|
2022
|
+
app.post('/api/worker/trigger-light', requireNotLocked, async (_req, res) => {
|
|
1756
2023
|
try {
|
|
1757
2024
|
const result = await brainWorker.triggerLightTick();
|
|
1758
2025
|
res.json({
|
|
@@ -1766,7 +2033,7 @@ export function startVisualizationServer(dbPath) {
|
|
|
1766
2033
|
}
|
|
1767
2034
|
});
|
|
1768
2035
|
// Manually trigger medium tick (for testing)
|
|
1769
|
-
app.post('/api/worker/trigger-medium', async (_req, res) => {
|
|
2036
|
+
app.post('/api/worker/trigger-medium', requireNotLocked, async (_req, res) => {
|
|
1770
2037
|
try {
|
|
1771
2038
|
const result = await brainWorker.triggerMediumTick();
|
|
1772
2039
|
res.json({
|