Skip to content

Releases: Drakon-Systems-Ltd/ShieldCortex

v4.20.0 — drop openclaw.extensions from main package

22 May 07:47

Choose a tag to compare

Stop the OpenClaw duplicate plugin id detected warning at its source.

OpenClaw's npm discovery is gated on a package having openclaw.extensions in its package.json. Pre-v4.20.0 both the main shieldcortex package AND the dedicated @drakon-systems/shieldcortex-realtime plugin declared one, so OpenClaw scanned both copies (the bare main package gets pulled in alongside as the realtime plugin's peerDependencies.shieldcortex), registered both under pluginId: shieldcortex-realtime, deduplicated, and emitted duplicate plugin id detected; global plugin will be overridden by global plugin on every openclaw update. Functionally fine (the right dist/index.js always won) but cosmetic noise on every fleet box.

This release drops openclaw.extensions from the main package's package.json. The bare shieldcortex is now invisible to OpenClaw's npm discovery — no duplicate registration, no warning. The dedicated realtime plugin remains the only discovery target.

Changed

  • openclaw.extensions removed from the main package.json (kept openclaw.hooks for the documented openclaw hooks install flow).
  • Packaging test inverted to pin the new contract.
  • Plugin README clarified — Packaging note now documents v4.20.0 contract and the full history.

Unchanged

  • doctor check OpenClaw plugin pkg keeps its full matrix — older fleet boxes that still drag in pre-v4.20.0 shieldcortex via the realtime peer-dep continue to be diagnosed correctly.
  • openclaw hooks install flow still works.
  • Dedicated realtime plugin's own openclaw.extensions untouched — that's the legitimate plugin declaration.

Why this is a minor (4.20.0), not a patch

Removing a package.json field that external tooling could in principle key on counts as an interface change to the OpenClaw integration surface. In practice the only consumer was OpenClaw's own discovery (which we WANT to stop indexing the main package) — but the SemVer-correct bump is minor.

Published manually from local (cyborgninja): npm shieldcortex@4.20.0 + @drakon-systems/shieldcortex-realtime@4.20.0.

v4.19.1 — doctor INFO (not WARN) for the expected shieldcortex peer-dep state

22 May 06:14

Choose a tag to compare

Doctor: stop crying wolf about the expected shieldcortex peer-dep in OpenClaw's plugin tree.

Since v4.18.3, the bare shieldcortex landing at ~/.openclaw/npm/node_modules/shieldcortex is the expected steady state of a healthy install: OpenClaw resolves @drakon-systems/shieldcortex-realtime's peerDependencies.shieldcortex by installing the main package alongside in its npm tree, and the 4.18.3 root-manifest fix made this safe (OpenClaw dedupes by pluginId). shieldcortex doctor still reported the state as WARN because the v4.18.2 check author (correctly, at the time) was being conservative — the Jarvis 2026-05-15 crash mechanism was unconfirmed. With weeks of healthy fleet evidence we now narrow the diagnostic without losing the safety net.

Changed

  • OpenClaw plugin pkg check: downgraded from WARN to INFO when bare shieldcortex version matches installed @drakon-systems/shieldcortex-realtime AND the root openclaw.plugin.json exists. Healthy fleet boxes now report INFO instead of WARN.

Unchanged

  • FAIL still fires when the bare package's extension entry is missing on disk (the real crash-loop precursor).
  • WARN still fires for genuine surprises: version mismatch, missing realtime peer, missing root manifest, unparseable package.json.

Tests

  • 4 new cases (1 INFO + 3 WARN edge cases). Full suite 1188 passing (unrelated mcp-registration flake unchanged).

Published manually from local (cyborgninja): npm shieldcortex@4.19.1 + @drakon-systems/shieldcortex-realtime@4.19.1.

v4.19.0 — Living Constellation knowledge graph

21 May 19:22

Choose a tag to compare

[4.19.0] - 2026-05-21

Living Constellation: the knowledge graph now feels alive.

The dashboard graph used to be a static cluster of dots. Five things were missing — there was no centre, no sense of flow, no visible link between memory activity and what you saw, no glow on the connections, and the controls fought you. This release rebuilds the renderer around those gaps. A high-mass entity is pinned at the canvas centre as a "sun" you can click to re-orbit; every node breathes subtly so the graph never freezes; memory.created emits a short spike on the affected entities, memory.accessed paints a warm recall ring; the hottest few edges show drifting particles to make the data flow legible; links draw as additive-blended gradient strokes that bloom where they overlap. Drag-release pins a node where you drop it (shift-click unpins, double-click empty space refits). A Settings → Graph Motion selector lets you pick Subtle / Moderate / Strong without reload, and prefers-reduced-motion short-circuits the lot.

The 527-line ConstellationGraph.tsx monolith is now a ~150-line wirer composing seven small modules under dashboard/src/components/graph/constellation/, each independently unit-tested (40 jest cases). Cluster nebula rendering — two-layer halo, golden-angle star scatter, hover dashed ring, type label — is preserved verbatim inside the wirer so cluster mode looks unchanged.

Added

  • PulseDriver energy model (dashboard/src/components/graph/constellation/pulse.ts) — three composable layers: A (memory-created spike, decayCreate), B (memory-accessed warm glow, decayRecall), C (always-on sinusoidal breathing). Per-node breathing phase is derived from a stable FNV-1a hash so the same id always lands in the same phase. pickParticleEdges(links, anchorId, overrideCap?) ranks edges by max(srcEnergy, dstEnergy) with anchor-adjacency as the tie-break.
  • Anchor selection + pin (anchor.ts) — pickAnchor ranks by memoryCount × edgeCount with a memoryCount-only fallback for lone or all-isolated graphs; applyAnchor<T extends PinnableNode> pins the new sun at (0, 0) and releases the previous one without touching user drag-pins.
  • Pure render math (renderMath.ts) — computeNodeRadius, computeLinkAlpha, computeLinkWidth. Unit-tested without any canvas.
  • Canvas drawersrenderNodes.ts (entity + anchor sun + recall ring + breathing modulation, exposes _paintHook for future RTL tests) and renderLinks.ts (gradient stroke with globalCompositeOperation = 'lighter').
  • Controls (controls.ts) — wireControls(graphRef, opts) exposes handleNodeDragEnd (drag-to-pin), handleNodeClick (single/double/shift-click verdicts), handleBackgroundDoubleClick (reset + zoom-to-fit). 300ms synthesised double-click on nodes triggers a smooth zoom.
  • useGraphPulse(driver) hook (dashboard/src/hooks/useGraphPulse.ts) — subscribes the driver to /ws/events and dispatches memory.created / memory.accessed pulses, with GET /api/memories?mode=recent&limit=50 polling at 10s as the fallback when WS closes or errors.
  • Settings → Graph Motion selector — 3-radio Subtle / Moderate / Strong, per-browser via localStorage, broadcasts a shieldcortex:intensity-changed CustomEvent so the live graph updates without reload.
  • prefers-reduced-motion support — when the OS-level setting is on, breathing stops, particles disappear (particleCap: 0), spike/recall decays vanish in one frame, and zoom tweens become instant.
  • Dev-only pulse debug panellocalStorage.SHIELDCORTEX_DEBUG_PULSE = '1' reveals a small overlay that fires memory.created / memory.accessed against an entity id for manual testing.

Changed

  • addMemory reorder + payload extension (src/memory/store.ts) — entity extraction now runs before the memory_created emit/persist/webhook calls so the event carries entity_ids: number[]. Without this, the new pulse layer's WebSocket subscriber had no way to map an event to a graph node and Layer A would silently never fire on real data. The auto-link block (detectRelationships) stays in its original position — it doesn't depend on entity ids.
  • memory_created / memory_accessed event types (src/api/events.ts) extended with entity_ids: number[]. emitMemoryCreated and emitMemoryAccessed helper signatures take the new arg.
  • GET /api/memories (src/api/routes/memories.ts) now returns entity_ids: number[] per row. Implemented as a single batched IN (?, ?, …) query — no N+1.

Fixed

  • Native d3-force unpin via castreact-force-graph-2d's NodeObject<X> declares fx?: number (no null), so the d3-canonical "set fx/fy to null to release" assignment was rejected by tsc. Cast at the assignment site preserves the runtime contract.
  • Latent .js extension resolution in three constellation modules — from './renderMath.js' etc. compiled under tsc and ran under Jest but Next.js Turbopack resolved the literals and 500'd at runtime. Dropped to extensionless imports so all three resolvers agree.

Tests

  • 40 new jest cases across intensity.test.ts (9), anchor.test.ts (11), pulse.test.ts (12), renderMath.test.ts (8). One new src/__tests__/memory-event-entity-ids.test.ts locks the addMemory reorder by asserting the emitted event carries the extracted entity ids and the memory_entities table is populated at emit time.
  • Full repo suite: 1184 passing + 2 skipped + 1 pre-existing flake (mcp-registration teardown bug unchanged from prior releases). Zero regressions.
  • Dashboard npx tsc --noEmit: silent. npm run lint: 0 errors. npm run build: all 22 routes prerendered.

Architecture notes

  • The wirer keeps cluster paint (nebula halo, golden-angle star scatter, hover dashed ring, type label + entity count) inline rather than moving it into a new renderClusters.ts module. The spec's intent was preservation, and the cluster branch is naturally distinct from the entity branch — splitting it later remains an option.
  • controls.ts's centerAt/zoom smooth tweens on node double-click are not yet gated on prefers-reduced-motion; only the wirer's zoomToFit calls are. Small follow-up if reduced-motion users notice.

v4.18.5 — modern Node support (better-sqlite3 ^12) + guarded native loader

18 May 10:30

Choose a tag to compare

Modern Node support — no more cryptic native crash on Node 23/24/25/26.

engines.node was unbounded (>=18) while better-sqlite3 ^11 prebuilts stopped at older Node ABIs — newer-Node users without a compiler hit a bare libc++abi … Napi::Error crash-loop with zero guidance. Node-LTS users were unaffected; this closes the gap.

Changed

  • better-sqlite3 ^11^12 (prebuilts for Node 20/22/23/24/25/26 — no compiler needed on modern Node).
  • engines.node >=18>=20 (Node 18 EOL); SKILL.md minVersion aligned.

Added

  • Guarded native loader (single runtime load path) — on ABI mismatch prints one actionable message (npm rebuild better-sqlite3 + supported Node LTS) and exits cleanly instead of the opaque abort.
  • Postinstall smoke-check — surfaces the problem at install time with remediation.

Tests

  • 5 new formatter unit cases; full suite green (1143 passing). One unrelated pre-existing mcp-registration timeout flake (passes in CI) is not introduced by this change.

Published manually from local (cyborgninja): shieldcortex@4.18.5 + @drakon-systems/shieldcortex-realtime@4.18.5.

v4.18.4 — bound the cloud sync retry queue size

17 May 20:11

Choose a tag to compare

The cloud sync retry queue is now hard-bounded — it can't grow without limit on disk.

The 7-day TTL purge (purgeOldEntries) only runs while the brain worker is alive. MCP-only installs have no worker, so a long offline stretch could accumulate sync_queue rows indefinitely with nothing trimming them.

Fixed

  • sync_queue capped at 5,000 rows, enforced on every enqueue (and the worker purge path). Evicts synced → terminally-failed → oldest-pending first, once-per-hour warning. Fire-and-forget preserved.

Tests

  • 4 new cases; full suite green.

Published manually from local (cyborgninja): npm shieldcortex@4.18.4 + @drakon-systems/shieldcortex-realtime@4.18.4. CI publish workflow no-ops (version already on npm).

v4.18.3

17 May 14:43

Choose a tag to compare

Full Changelog: v4.18.2...v4.18.3

v4.18.2

15 May 23:59

Choose a tag to compare

Full Changelog: v4.18.1...v4.18.2

v4.18.1

14 May 21:16

Choose a tag to compare

Full Changelog: v4.18.0...v4.18.1

v4.18.0

14 May 19:35

Choose a tag to compare

Full Changelog: v4.17.0...v4.18.0

v4.17.0

13 May 13:06

Choose a tag to compare

Full Changelog: v4.16.0...v4.17.0