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.
Files changed (147) hide show
  1. package/README.md +14 -10
  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/server/app/_global-error.html +2 -2
  6. package/dashboard/.next/standalone/dashboard/.next/server/app/_global-error.rsc +1 -1
  7. package/dashboard/.next/standalone/dashboard/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  8. package/dashboard/.next/standalone/dashboard/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  9. package/dashboard/.next/standalone/dashboard/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  10. package/dashboard/.next/standalone/dashboard/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  11. package/dashboard/.next/standalone/dashboard/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  12. package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  13. package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.html +1 -1
  14. package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.rsc +2 -2
  15. package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.segments/_full.segment.rsc +2 -2
  16. package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  17. package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.segments/_index.segment.rsc +2 -2
  18. package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  19. package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  20. package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  21. package/dashboard/.next/standalone/dashboard/.next/server/app/index.html +1 -1
  22. package/dashboard/.next/standalone/dashboard/.next/server/app/index.rsc +3 -3
  23. package/dashboard/.next/standalone/dashboard/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  24. package/dashboard/.next/standalone/dashboard/.next/server/app/index.segments/_full.segment.rsc +3 -3
  25. package/dashboard/.next/standalone/dashboard/.next/server/app/index.segments/_head.segment.rsc +1 -1
  26. package/dashboard/.next/standalone/dashboard/.next/server/app/index.segments/_index.segment.rsc +2 -2
  27. package/dashboard/.next/standalone/dashboard/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  28. package/dashboard/.next/standalone/dashboard/.next/server/app/page/react-loadable-manifest.json +3 -3
  29. package/dashboard/.next/standalone/dashboard/.next/server/app/page_client-reference-manifest.js +1 -1
  30. package/dashboard/.next/standalone/dashboard/.next/server/chunks/ssr/dashboard_25b1b286._.js +1 -1
  31. package/dashboard/.next/standalone/dashboard/.next/server/pages/404.html +1 -1
  32. package/dashboard/.next/standalone/dashboard/.next/server/pages/500.html +2 -2
  33. package/dashboard/.next/standalone/dashboard/.next/server/server-reference-manifest.js +1 -1
  34. package/dashboard/.next/standalone/dashboard/.next/server/server-reference-manifest.json +1 -1
  35. package/dashboard/.next/standalone/dashboard/.next/static/chunks/26118d592a545e00.js +3 -0
  36. package/dashboard/.next/standalone/dashboard/.next/static/chunks/6a6ccfb7834de00a.js +9 -0
  37. package/dashboard/.next/standalone/dashboard/.next/static/chunks/6b11a7d29e9abffd.js +1 -0
  38. package/dashboard/.next/standalone/dashboard/.next/static/chunks/ab13d81ce0e121f2.css +3 -0
  39. package/dashboard/.next/standalone/dashboard/.next/static/chunks/cf05262adfab5818.js +1 -0
  40. package/dist/api/control.d.ts +28 -11
  41. package/dist/api/control.d.ts.map +1 -1
  42. package/dist/api/control.js +120 -19
  43. package/dist/api/control.js.map +1 -1
  44. package/dist/api/events.d.ts +12 -1
  45. package/dist/api/events.d.ts.map +1 -1
  46. package/dist/api/events.js +9 -0
  47. package/dist/api/events.js.map +1 -1
  48. package/dist/api/visualization-server.d.ts.map +1 -1
  49. package/dist/api/visualization-server.js +306 -39
  50. package/dist/api/visualization-server.js.map +1 -1
  51. package/dist/cli/doctor.d.ts +6 -0
  52. package/dist/cli/doctor.d.ts.map +1 -0
  53. package/dist/cli/doctor.js +469 -0
  54. package/dist/cli/doctor.js.map +1 -0
  55. package/dist/cloud/quarantine-sync.d.ts +3 -0
  56. package/dist/cloud/quarantine-sync.d.ts.map +1 -1
  57. package/dist/cloud/quarantine-sync.js +7 -0
  58. package/dist/cloud/quarantine-sync.js.map +1 -1
  59. package/dist/cloud/sync.d.ts +11 -0
  60. package/dist/cloud/sync.d.ts.map +1 -1
  61. package/dist/cloud/sync.js +37 -0
  62. package/dist/cloud/sync.js.map +1 -1
  63. package/dist/database/init.d.ts +8 -0
  64. package/dist/database/init.d.ts.map +1 -1
  65. package/dist/database/init.js +208 -4
  66. package/dist/database/init.js.map +1 -1
  67. package/dist/defence/index.d.ts +2 -0
  68. package/dist/defence/index.d.ts.map +1 -1
  69. package/dist/defence/index.js +2 -0
  70. package/dist/defence/index.js.map +1 -1
  71. package/dist/defence/input-sanitisation/index.d.ts +28 -0
  72. package/dist/defence/input-sanitisation/index.d.ts.map +1 -0
  73. package/dist/defence/input-sanitisation/index.js +71 -0
  74. package/dist/defence/input-sanitisation/index.js.map +1 -0
  75. package/dist/defence/iron-dome/config.js +5 -5
  76. package/dist/defence/iron-dome/config.js.map +1 -1
  77. package/dist/defence/iron-dome/index.d.ts +6 -0
  78. package/dist/defence/iron-dome/index.d.ts.map +1 -1
  79. package/dist/defence/iron-dome/index.js +19 -0
  80. package/dist/defence/iron-dome/index.js.map +1 -1
  81. package/dist/defence/pipeline.d.ts.map +1 -1
  82. package/dist/defence/pipeline.js +21 -11
  83. package/dist/defence/pipeline.js.map +1 -1
  84. package/dist/events/webhooks.d.ts +21 -0
  85. package/dist/events/webhooks.d.ts.map +1 -0
  86. package/dist/events/webhooks.js +61 -0
  87. package/dist/events/webhooks.js.map +1 -0
  88. package/dist/graph/backfill.d.ts +6 -2
  89. package/dist/graph/backfill.d.ts.map +1 -1
  90. package/dist/graph/backfill.js +32 -4
  91. package/dist/graph/backfill.js.map +1 -1
  92. package/dist/graph/extract.d.ts.map +1 -1
  93. package/dist/graph/extract.js +105 -37
  94. package/dist/graph/extract.js.map +1 -1
  95. package/dist/index.d.ts.map +1 -1
  96. package/dist/index.js +67 -5
  97. package/dist/index.js.map +1 -1
  98. package/dist/lib.d.ts +2 -0
  99. package/dist/lib.d.ts.map +1 -1
  100. package/dist/lib.js +2 -0
  101. package/dist/lib.js.map +1 -1
  102. package/dist/memory/consolidate.d.ts +23 -0
  103. package/dist/memory/consolidate.d.ts.map +1 -1
  104. package/dist/memory/consolidate.js +239 -2
  105. package/dist/memory/consolidate.js.map +1 -1
  106. package/dist/memory/decay.d.ts.map +1 -1
  107. package/dist/memory/decay.js +9 -0
  108. package/dist/memory/decay.js.map +1 -1
  109. package/dist/memory/embedding-cache.d.ts +21 -0
  110. package/dist/memory/embedding-cache.d.ts.map +1 -0
  111. package/dist/memory/embedding-cache.js +92 -0
  112. package/dist/memory/embedding-cache.js.map +1 -0
  113. package/dist/memory/embedding.d.ts +37 -0
  114. package/dist/memory/embedding.d.ts.map +1 -0
  115. package/dist/memory/embedding.js +86 -0
  116. package/dist/memory/embedding.js.map +1 -0
  117. package/dist/memory/expiry.d.ts +26 -0
  118. package/dist/memory/expiry.d.ts.map +1 -0
  119. package/dist/memory/expiry.js +109 -0
  120. package/dist/memory/expiry.js.map +1 -0
  121. package/dist/memory/store.d.ts +14 -0
  122. package/dist/memory/store.d.ts.map +1 -1
  123. package/dist/memory/store.js +82 -0
  124. package/dist/memory/store.js.map +1 -1
  125. package/dist/memory/types.d.ts +1 -0
  126. package/dist/memory/types.d.ts.map +1 -1
  127. package/dist/memory/types.js.map +1 -1
  128. package/dist/server.d.ts.map +1 -1
  129. package/dist/server.js +193 -45
  130. package/dist/server.js.map +1 -1
  131. package/dist/tools/context.d.ts +4 -4
  132. package/dist/tools/forget.d.ts +4 -4
  133. package/dist/tools/recall.d.ts +9 -9
  134. package/dist/tools/recall.d.ts.map +1 -1
  135. package/dist/tools/recall.js +25 -1
  136. package/dist/tools/recall.js.map +1 -1
  137. package/dist/tools/remember.d.ts +6 -6
  138. package/hooks/openclaw/cortex-memory/handler.ts +8 -18
  139. package/package.json +1 -1
  140. package/dashboard/.next/standalone/dashboard/.next/static/chunks/1a71c9a52f0c9b16.css +0 -3
  141. package/dashboard/.next/standalone/dashboard/.next/static/chunks/6bf7d89d34068ecb.js +0 -9
  142. package/dashboard/.next/standalone/dashboard/.next/static/chunks/a3989d0e6629bcf8.js +0 -3
  143. package/dashboard/.next/standalone/dashboard/.next/static/chunks/d0dcb5e0e04ae015.js +0 -1
  144. package/dashboard/.next/standalone/dashboard/.next/static/chunks/fc2dbf641aad1448.js +0 -1
  145. /package/dashboard/.next/standalone/dashboard/.next/static/{vxPliVFK4FIBIPl1JPL0U → aFo1BShJENvQZgqpWRJaw}/_buildManifest.js +0 -0
  146. /package/dashboard/.next/standalone/dashboard/.next/static/{vxPliVFK4FIBIPl1JPL0U → aFo1BShJENvQZgqpWRJaw}/_clientMiddlewareManifest.json +0 -0
  147. /package/dashboard/.next/standalone/dashboard/.next/static/{vxPliVFK4FIBIPl1JPL0U → aFo1BShJENvQZgqpWRJaw}/_ssgManifest.js +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"events.js","sourceRoot":"","sources":["../../src/api/events.ts"],"names":[],"mappings":"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"}
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;AA2HlD,yCAAyC;AACzC,MAAM,kBAAmB,SAAQ,YAAY;IAC3C,IAAI,CAAC,KAAsB,EAAE,IAAyB;QACpD,MAAM,OAAO,GAAgB;YAC3B,IAAI,EAAE,KAAK;YACX,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YACnC,IAAI;SACL,CAAC;QACF,OAAO,KAAK,CAAC,IAAI,CAAC,cAAc,EAAE,OAAO,CAAC,CAAC;IAC7C,CAAC;IAED,aAAa,CAAC,QAAsC;QAClD,IAAI,CAAC,EAAE,CAAC,cAAc,EAAE,QAAQ,CAAC,CAAC;IACpC,CAAC;IAED,cAAc,CAAC,QAAsC;QACnD,IAAI,CAAC,GAAG,CAAC,cAAc,EAAE,QAAQ,CAAC,CAAC;IACrC,CAAC;CACF;AAED,qBAAqB;AACrB,MAAM,CAAC,MAAM,YAAY,GAAG,IAAI,kBAAkB,EAAE,CAAC;AAErD,kCAAkC;AAClC,MAAM,UAAU,iBAAiB,CAAC,MAAc;IAC9C,YAAY,CAAC,IAAI,CAAC,gBAAgB,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC;AAClD,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,MAAc,EAAE,WAAmB;IACpE,YAAY,CAAC,IAAI,CAAC,iBAAiB,EAAE;QACnC,QAAQ,EAAE,MAAM,CAAC,EAAE;QACnB,MAAM;QACN,WAAW;KACZ,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,MAAc;IAC9C,YAAY,CAAC,IAAI,CAAC,gBAAgB,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC;AAClD,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,QAAgB,EAAE,KAAa;IAC/D,YAAY,CAAC,IAAI,CAAC,gBAAgB,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAC;AAC3D,CAAC;AAED,MAAM,UAAU,iBAAiB,CAC/B,MAA2B,EAC3B,mBAA6B,EAAE,EAC/B,kBAA4B,EAAE;IAE9B,YAAY,CAAC,IAAI,CAAC,wBAAwB,EAAE;QAC1C,GAAG,MAAM;QACT,gBAAgB;QAChB,eAAe;KAChB,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,aAAa,CAC3B,OAAwE;IAExE,YAAY,CAAC,IAAI,CAAC,YAAY,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC;AAC/C,CAAC;AAED,iCAAiC;AACjC,MAAM,UAAU,mBAAmB,CAAC,IAInC;IACC,YAAY,CAAC,IAAI,CAAC,mBAAmB,EAAE;QACrC,GAAG,IAAI;QACP,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,WAAW,EAAE;KACxC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,IAMpC;IACC,YAAY,CAAC,IAAI,CAAC,oBAAoB,EAAE;QACtC,GAAG,IAAI;QACP,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,WAAW,EAAE;KACxC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,IAKlC;IACC,YAAY,CAAC,IAAI,CAAC,iBAAiB,EAAE,IAAI,CAAC,CAAC;AAC7C,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,IAShC;IACC,YAAY,CAAC,IAAI,CAAC,eAAe,EAAE,IAAI,CAAC,CAAC;AAC3C,CAAC;AAED,MAAM,UAAU,2BAA2B,CAAC,IAI3C;IACC,YAAY,CAAC,IAAI,CAAC,0BAA0B,EAAE,IAAI,CAAC,CAAC;AACtD,CAAC;AAED,6BAA6B;AAC7B,MAAM,UAAU,uBAAuB,CAAC,IAMvC;IACC,YAAY,CAAC,IAAI,CAAC,uBAAuB,EAAE,IAAI,CAAC,CAAC;IACjD,YAAY,CAAC,uBAAuB,EAAE,IAAI,CAAC,CAAC;AAC9C,CAAC;AAED,MAAM,UAAU,yBAAyB,CAAC,IAGzC;IACC,YAAY,CAAC,IAAI,CAAC,yBAAyB,EAAE,IAAI,CAAC,CAAC;IACnD,YAAY,CAAC,yBAAyB,EAAE,IAAI,CAAC,CAAC;AAChD,CAAC;AAED,+EAA+E;AAC/E,iCAAiC;AACjC,+EAA+E;AAE/E;;;;GAIG;AACH,MAAM,UAAU,YAAY,CAAC,IAAqB,EAAE,IAAc;IAChE,IAAI,CAAC;QACH,MAAM,EAAE,GAAG,WAAW,EAAE,CAAC;QACzB,MAAM,IAAI,GAAG,EAAE,CAAC,OAAO,CAAC;;;KAGvB,CAAC,CAAC;QACH,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,CAAC;IAC/E,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,yDAAyD;QACzD,OAAO,CAAC,KAAK,CAAC,mCAAmC,EAAE,KAAK,CAAC,CAAC;IAC5D,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,oBAAoB,CAAC,KAAK,GAAG,GAAG;IAM9C,IAAI,CAAC;QACH,MAAM,EAAE,GAAG,WAAW,EAAE,CAAC;QACzB,MAAM,IAAI,GAAG,EAAE,CAAC,OAAO,CAAC;;;;;;KAMvB,CAAC,CAAC;QACH,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAKzB,CAAC;QACH,OAAO,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YACtB,EAAE,EAAE,GAAG,CAAC,EAAE;YACV,IAAI,EAAE,GAAG,CAAC,IAAuB;YACjC,IAAI,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI;YAC5C,SAAS,EAAE,GAAG,CAAC,SAAS;SACzB,CAAC,CAAC,CAAC;IACN,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,gCAAgC,EAAE,KAAK,CAAC,CAAC;QACvD,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,mBAAmB,CAAC,GAAa;IAC/C,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO;IAC7B,IAAI,CAAC;QACH,MAAM,EAAE,GAAG,WAAW,EAAE,CAAC;QACzB,MAAM,YAAY,GAAG,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAClD,EAAE,CAAC,OAAO,CAAC,gDAAgD,YAAY,GAAG,CAAC,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,CAAC;IAC1F,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,2CAA2C,EAAE,KAAK,CAAC,CAAC;IACpE,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,gBAAgB;IAC9B,IAAI,CAAC;QACH,MAAM,EAAE,GAAG,WAAW,EAAE,CAAC;QACzB,MAAM,MAAM,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC;QACxE,MAAM,MAAM,GAAG,EAAE,CAAC,OAAO,CAAC,0DAA0D,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAClG,IAAI,MAAM,CAAC,OAAO,GAAG,CAAC,EAAE,CAAC;YACvB,OAAO,CAAC,GAAG,CAAC,uBAAuB,MAAM,CAAC,OAAO,aAAa,CAAC,CAAC;QAClE,CAAC;IACH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,oCAAoC,EAAE,KAAK,CAAC,CAAC;IAC7D,CAAC;AACH,CAAC"}
@@ -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,CA62E9D"}
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), 500) : 100;
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 updated = updateMemory(id, req.body);
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({