nexo-brain 5.3.20 → 5.3.22
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/.claude-plugin/plugin.json +1 -1
- package/package.json +1 -1
- package/src/auto_update.py +11 -8
- package/src/client_sync.py +53 -0
- package/src/dashboard/static/favicon 2.svg +32 -0
- package/src/dashboard/static/nexo-logo 2.png +0 -0
- package/src/dashboard/static/nexo-logo 2.svg +40 -0
- package/src/dashboard/static/style 2.css +2458 -0
- package/src/dashboard/templates/adaptive 2.html +118 -0
- package/src/dashboard/templates/artifacts 2.html +133 -0
- package/src/dashboard/templates/backups 2.html +136 -0
- package/src/dashboard/templates/base 2.html +417 -0
- package/src/dashboard/templates/calendar 2.html +591 -0
- package/src/dashboard/templates/chat 2.html +356 -0
- package/src/dashboard/templates/claims 2.html +259 -0
- package/src/dashboard/templates/cortex 2.html +321 -0
- package/src/dashboard/templates/credentials 2.html +128 -0
- package/src/dashboard/templates/crons 2.html +370 -0
- package/src/dashboard/templates/dashboard 2.html +494 -0
- package/src/dashboard/templates/dreams 2.html +252 -0
- package/src/dashboard/templates/email 2.html +160 -0
- package/src/dashboard/templates/evolution 2.html +189 -0
- package/src/dashboard/templates/feed 2.html +249 -0
- package/src/dashboard/templates/followup_health 2.html +170 -0
- package/src/dashboard/templates/graph 2.html +201 -0
- package/src/dashboard/templates/guard 2.html +259 -0
- package/src/dashboard/templates/inbox 2.html +251 -0
- package/src/dashboard/templates/memory 2.html +420 -0
- package/src/dashboard/templates/operations 2.html +608 -0
- package/src/dashboard/templates/plugins 2.html +185 -0
- package/src/dashboard/templates/protocol 2.html +199 -0
- package/src/dashboard/templates/rules 2.html +246 -0
- package/src/dashboard/templates/sentiment 2.html +247 -0
- package/src/dashboard/templates/sessions 2.html +218 -0
- package/src/dashboard/templates/skills 2.html +329 -0
- package/src/dashboard/templates/somatic 2.html +73 -0
- package/src/dashboard/templates/triggers 2.html +133 -0
- package/src/dashboard/templates/trust 2.html +360 -0
- package/src/db/__init__ 2.py +259 -0
- package/src/db/_core 2.py +437 -0
- package/src/db/_credentials 2.py +124 -0
- package/src/db/_episodic 2.py +762 -0
- package/src/db/_evolution 2.py +54 -0
- package/src/db/_fts 2.py +406 -0
- package/src/db/_goal_profiles 2.py +376 -0
- package/src/db/_hot_context 2.py +660 -0
- package/src/db/_outcomes 2.py +800 -0
- package/src/db/_personal_scripts 2.py +582 -0
- package/src/db/_sessions 2.py +330 -0
- package/src/db/_tasks 2.py +91 -0
- package/src/db/_watchers 2.py +173 -0
- package/src/doctor/formatters 2.py +52 -0
- package/src/doctor/models 2.py +69 -0
- package/src/doctor/planes 2.py +87 -0
- package/src/doctor/providers/__init__ 2.py +1 -0
- package/src/doctor/providers/deep 2.py +367 -0
- package/src/evolution_cycle 2.py +519 -0
- package/src/hooks/auto_capture 2.py +208 -0
- package/src/hooks/caffeinate-guard 2.sh +8 -0
- package/src/hooks/capture-session 2.sh +21 -0
- package/src/hooks/capture-tool-logs 2.sh +158 -0
- package/src/hooks/daily-briefing-check 2.sh +33 -0
- package/src/hooks/heartbeat-enforcement 2.py +90 -0
- package/src/hooks/heartbeat-posttool 2.sh +18 -0
- package/src/hooks/inbox-hook 2.sh +76 -0
- package/src/hooks/post-compact 2.sh +152 -0
- package/src/hooks/pre-compact 2.sh +169 -0
- package/src/hooks/protocol-guardrail 2.sh +10 -0
- package/src/hooks/protocol-pretool-guardrail 2.sh +9 -0
- package/src/hooks/session-stop 2.sh +52 -0
- package/src/kg_populate 2.py +292 -0
- package/src/maintenance 2.py +53 -0
- package/src/memory_backends 2.py +71 -0
- package/src/migrate_embeddings 2.py +124 -0
- package/src/nexo_sdk 2.py +103 -0
- package/src/observability 2.py +199 -0
- package/src/plugin_loader 2.py +217 -0
- package/src/plugins/__init__ 2.py +0 -0
- package/src/plugins/artifact_registry 2.py +450 -0
- package/src/plugins/backup 2.py +127 -0
- package/src/plugins/claims_tools 2.py +119 -0
- package/src/plugins/cognitive_memory 2.py +609 -0
- package/src/plugins/core_rules 2.py +252 -0
- package/src/plugins/cortex 2.py +1155 -0
- package/src/plugins/entities 2.py +67 -0
- package/src/plugins/episodic_memory 2.py +560 -0
- package/src/plugins/evolution 2.py +167 -0
- package/src/plugins/goal_engine 2.py +142 -0
- package/src/plugins/guard 2.py +862 -0
- package/src/plugins/impact 2.py +29 -0
- package/src/plugins/knowledge_graph_tools 2.py +137 -0
- package/src/plugins/media_memory_tools 2.py +98 -0
- package/src/plugins/memory_export 2.py +196 -0
- package/src/plugins/outcomes 2.py +130 -0
- package/src/plugins/personal_scripts 2.py +117 -0
- package/src/plugins/preferences 2.py +47 -0
- package/src/plugins/protocol 2.py +1449 -0
- package/src/plugins/simple_api 2.py +106 -0
- package/src/plugins/skills 2.py +341 -0
- package/src/plugins/state_watchers 2.py +79 -0
- package/src/plugins/update 2.py +986 -0
- package/src/plugins/user_state_tools 2.py +43 -0
- package/src/plugins/workflow 2.py +588 -0
- package/src/protocol_settings 2.py +59 -0
- package/src/public_contribution 2.py +466 -0
- package/src/public_evolution_queue 2.py +241 -0
- package/src/requirements 2.txt +14 -0
- package/src/retroactive_learnings 2.py +373 -0
- package/src/rules/__init__ 2.py +0 -0
- package/src/rules/core-rules 2.json +331 -0
- package/src/rules/migrate 2.py +207 -0
- package/src/runtime_power 2.py +874 -0
- package/src/script_registry 2.py +1559 -0
- package/src/scripts/check-context 2.py +272 -0
- package/src/scripts/deep-sleep/apply_findings 2.py +2327 -0
- package/src/scripts/deep-sleep/collect 2.py +928 -0
- package/src/scripts/deep-sleep/extract 2.py +330 -0
- package/src/scripts/deep-sleep/extract-prompt 2.md +285 -0
- package/src/scripts/deep-sleep/synthesize 2.py +312 -0
- package/src/scripts/deep-sleep/synthesize-prompt 2.md +336 -0
- package/src/scripts/nexo-agent-run 2.py +75 -0
- package/src/scripts/nexo-auto-update 2.py +6 -0
- package/src/scripts/nexo-backup 2.sh +25 -0
- package/src/scripts/nexo-brain-activation 2.sh +140 -0
- package/src/scripts/nexo-catchup 2.py +300 -0
- package/src/scripts/nexo-cognitive-decay 2.py +257 -0
- package/src/scripts/nexo-cortex-cycle 2.py +293 -0
- package/src/scripts/nexo-cron-wrapper 2.sh +53 -0
- package/src/scripts/nexo-daily-self-audit 2.py +2161 -0
- package/src/scripts/nexo-dashboard 2.sh +29 -0
- package/src/scripts/nexo-deep-sleep 2.sh +86 -0
- package/src/scripts/nexo-evolution-run 2.py +1664 -0
- package/src/scripts/nexo-followup-hygiene 2.py +139 -0
- package/src/scripts/nexo-hook-record 2.py +42 -0
- package/src/scripts/nexo-immune 2.py +936 -0
- package/src/scripts/nexo-impact-scorer 2.py +117 -0
- package/src/scripts/nexo-inbox-hook 2.sh +74 -0
- package/src/scripts/nexo-install 2.py +6 -0
- package/src/scripts/nexo-learning-housekeep 2.py +401 -0
- package/src/scripts/nexo-learning-validator 2.py +266 -0
- package/src/scripts/nexo-migrate 2.py +260 -0
- package/src/scripts/nexo-outcome-checker 2.py +127 -0
- package/src/scripts/nexo-postmortem-consolidator 2.py +456 -0
- package/src/scripts/nexo-pre-commit 2.py +120 -0
- package/src/scripts/nexo-prevent-sleep 2.sh +35 -0
- package/src/scripts/nexo-proactive-dashboard 2.py +354 -0
- package/src/scripts/nexo-reflection 2.py +256 -0
- package/src/scripts/nexo-runtime-preflight 2.py +274 -0
- package/src/scripts/nexo-sleep 2.py +631 -0
- package/src/scripts/nexo-snapshot-restore 2.sh +35 -0
- package/src/scripts/nexo-sync-clients 2.py +16 -0
- package/src/scripts/nexo-synthesis 2.py +475 -0
- package/src/scripts/nexo-tcc-approve 2.sh +79 -0
- package/src/scripts/nexo-update 2.sh +306 -0
- package/src/scripts/nexo-watchdog 2.sh +1207 -0
- package/src/scripts/nexo-watchdog-smoke 2.py +119 -0
- package/src/scripts/rehydrate_learnings_from_archive 2.py +245 -0
- package/src/server 2.py +1296 -0
- package/src/skills/run-nexo-audit-phase/guide 2.md +43 -0
- package/src/skills/run-nexo-audit-phase/skill 2.json +59 -0
- package/src/skills/run-nexo-core-fix-cycle/guide 2.md +17 -0
- package/src/skills/run-nexo-core-fix-cycle/script 2.py +276 -0
- package/src/skills/run-nexo-core-fix-cycle/skill 2.json +58 -0
- package/src/skills/run-release-final-audit/guide 2.md +16 -0
- package/src/skills/run-release-final-audit/script 2.py +259 -0
- package/src/skills/run-release-final-audit/skill 2.json +77 -0
- package/src/skills/run-runtime-doctor/guide 2.md +12 -0
- package/src/skills/run-runtime-doctor/script 2.py +21 -0
- package/src/skills/run-runtime-doctor/skill 2.json +25 -0
- package/src/skills_runtime 2.py +932 -0
- package/src/state_watchers_runtime 2.py +475 -0
- package/src/storage_router 2.py +32 -0
- package/src/system_catalog 2.py +786 -0
- package/src/tools_coordination 2.py +103 -0
- package/src/tools_credentials 2.py +68 -0
- package/src/tools_drive 2.py +487 -0
- package/src/tools_hot_context 2.py +163 -0
- package/src/tools_learnings 2.py +612 -0
- package/src/tools_menu 2.py +229 -0
- package/src/tools_reminders 2.py +88 -0
- package/src/tools_reminders_crud 2.py +363 -0
- package/src/tools_sessions 2.py +1054 -0
- package/src/tools_system_catalog 2.py +19 -0
- package/src/tools_task_history 2.py +57 -0
- package/src/tools_transcripts 2.py +98 -0
- package/src/transcript_utils 2.py +412 -0
- package/src/user_context 2.py +46 -0
- package/src/user_data_portability 2.py +328 -0
- package/src/user_state_model 2.py +170 -0
- package/templates/CLAUDE.md 2.template +108 -0
- package/templates/CODEX.AGENTS.md 2.template +66 -0
- package/templates/launchagents/README 2.md +132 -0
- package/templates/launchagents/com.nexo.auto-close-sessions 2.plist +39 -0
- package/templates/launchagents/com.nexo.catchup 2.plist +39 -0
- package/templates/launchagents/com.nexo.cognitive-decay 2.plist +40 -0
- package/templates/launchagents/com.nexo.dashboard 2.plist +43 -0
- package/templates/launchagents/com.nexo.deep-sleep 2.plist +43 -0
- package/templates/launchagents/com.nexo.evolution 2.plist +44 -0
- package/templates/launchagents/com.nexo.followup-hygiene 2.plist +45 -0
- package/templates/launchagents/com.nexo.immune 2.plist +41 -0
- package/templates/launchagents/com.nexo.postmortem 2.plist +45 -0
- package/templates/launchagents/com.nexo.self-audit 2.plist +47 -0
- package/templates/launchagents/com.nexo.synthesis 2.plist +45 -0
- package/templates/launchagents/com.nexo.watchdog 2.plist +37 -0
- package/templates/nexo_helper 2.py +301 -0
- package/templates/openclaw 2.json +13 -0
- package/templates/plugin-template 2.py +40 -0
- package/templates/script-template 2.py +59 -0
- package/templates/script-template 2.sh +13 -0
- package/templates/skill-script-template 2.py +48 -0
- package/templates/skill-template 2.md +33 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nexo-brain",
|
|
3
|
-
"version": "5.3.
|
|
3
|
+
"version": "5.3.22",
|
|
4
4
|
"description": "Local cognitive runtime for Claude Code \u2014 persistent memory, overnight learning, doctor diagnostics, personal scripts, recovery-aware jobs, startup preflight, and optional dashboard/power helper.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "NEXO Brain",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nexo-brain",
|
|
3
|
-
"version": "5.3.
|
|
3
|
+
"version": "5.3.22",
|
|
4
4
|
"mcpName": "io.github.wazionapps/nexo",
|
|
5
5
|
"description": "NEXO Brain — Shared brain for AI agents. Persistent memory, semantic RAG, natural forgetting, metacognitive guard, trust scoring, 150+ MCP tools. Works with Claude Code, Codex, Claude Desktop & any MCP client. 100% local, free.",
|
|
6
6
|
"homepage": "https://nexo-brain.com",
|
package/src/auto_update.py
CHANGED
|
@@ -1653,14 +1653,17 @@ def _resolve_sync_source() -> tuple[Path | None, Path | None]:
|
|
|
1653
1653
|
|
|
1654
1654
|
|
|
1655
1655
|
def _git_in_repo(repo_dir: Path, *args, timeout: int = 10) -> tuple[int, str, str]:
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1656
|
+
try:
|
|
1657
|
+
result = subprocess.run(
|
|
1658
|
+
["git"] + list(args),
|
|
1659
|
+
cwd=str(repo_dir),
|
|
1660
|
+
capture_output=True,
|
|
1661
|
+
text=True,
|
|
1662
|
+
timeout=timeout,
|
|
1663
|
+
)
|
|
1664
|
+
return result.returncode, result.stdout.strip(), result.stderr.strip()
|
|
1665
|
+
except subprocess.TimeoutExpired:
|
|
1666
|
+
return 128, "", f"git {' '.join(str(a) for a in args)} timed out after {timeout}s"
|
|
1664
1667
|
|
|
1665
1668
|
|
|
1666
1669
|
def _source_repo_status(repo_dir: Path) -> dict:
|
package/src/client_sync.py
CHANGED
|
@@ -292,6 +292,12 @@ def _sync_codex_managed_config(
|
|
|
292
292
|
}
|
|
293
293
|
codex_table["managed_server_command"] = server_config.get("command", "")
|
|
294
294
|
|
|
295
|
+
# Ensure Codex headless crons (followup-runner, email-monitor, deep-sleep,
|
|
296
|
+
# etc.) do not stall on approval prompts. Only set defaults when the user
|
|
297
|
+
# hasn't configured them explicitly — never overwrite existing values.
|
|
298
|
+
payload.setdefault("approval_policy", "never")
|
|
299
|
+
payload.setdefault("sandbox_mode", "danger-full-access")
|
|
300
|
+
|
|
295
301
|
_write_toml_object(path, payload)
|
|
296
302
|
return {
|
|
297
303
|
"ok": True,
|
|
@@ -592,6 +598,52 @@ def _claude_desktop_managed_metadata(server_config: dict, *, operator_name: str)
|
|
|
592
598
|
}
|
|
593
599
|
|
|
594
600
|
|
|
601
|
+
# Minimum permissions allowlist required for NEXO headless automation
|
|
602
|
+
# (followup-runner, email-monitor, deep-sleep, etc.) to work without
|
|
603
|
+
# interactive approval prompts. Without this, Claude Code headless invocations
|
|
604
|
+
# stall waiting for MCP tool approvals.
|
|
605
|
+
_NEXO_HEADLESS_ALLOWLIST = (
|
|
606
|
+
"Bash",
|
|
607
|
+
"Read",
|
|
608
|
+
"Edit",
|
|
609
|
+
"Write",
|
|
610
|
+
"Glob",
|
|
611
|
+
"Grep",
|
|
612
|
+
"Task",
|
|
613
|
+
"Skill",
|
|
614
|
+
"NotebookEdit",
|
|
615
|
+
"WebSearch",
|
|
616
|
+
"WebFetch",
|
|
617
|
+
"mcp__*",
|
|
618
|
+
)
|
|
619
|
+
|
|
620
|
+
|
|
621
|
+
def _ensure_headless_permissions(payload: dict) -> None:
|
|
622
|
+
"""Ensure Claude Code settings.json has the minimum allowlist so headless
|
|
623
|
+
NEXO crons (followup-runner, email-monitor, etc.) do not stall on MCP
|
|
624
|
+
tool-approval prompts. Idempotent: only adds missing entries, never
|
|
625
|
+
removes or reorders existing user customizations."""
|
|
626
|
+
permissions = payload.get("permissions")
|
|
627
|
+
if not isinstance(permissions, dict):
|
|
628
|
+
permissions = {}
|
|
629
|
+
payload["permissions"] = permissions
|
|
630
|
+
|
|
631
|
+
allow_list = permissions.get("allow")
|
|
632
|
+
if not isinstance(allow_list, list):
|
|
633
|
+
allow_list = []
|
|
634
|
+
permissions["allow"] = allow_list
|
|
635
|
+
|
|
636
|
+
existing = {str(item) for item in allow_list if isinstance(item, str)}
|
|
637
|
+
for entry in _NEXO_HEADLESS_ALLOWLIST:
|
|
638
|
+
if entry not in existing:
|
|
639
|
+
allow_list.append(entry)
|
|
640
|
+
existing.add(entry)
|
|
641
|
+
|
|
642
|
+
permissions.setdefault("deny", [])
|
|
643
|
+
permissions.setdefault("ask", [])
|
|
644
|
+
permissions.setdefault("defaultMode", "dontAsk")
|
|
645
|
+
|
|
646
|
+
|
|
595
647
|
def _sync_claude_code_settings(path: Path, server_config: dict) -> dict:
|
|
596
648
|
payload = _load_json_object(path)
|
|
597
649
|
mcp_servers = payload.setdefault("mcpServers", {})
|
|
@@ -608,6 +660,7 @@ def _sync_claude_code_settings(path: Path, server_config: dict) -> dict:
|
|
|
608
660
|
runtime_root=runtime_root,
|
|
609
661
|
nexo_home=nexo_home,
|
|
610
662
|
)
|
|
663
|
+
_ensure_headless_permissions(payload)
|
|
611
664
|
_write_json_object(path, payload)
|
|
612
665
|
return {
|
|
613
666
|
"ok": True,
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" fill="none">
|
|
2
|
+
<defs>
|
|
3
|
+
<linearGradient id="fg" x1="0" y1="0" x2="32" y2="32" gradientUnits="userSpaceOnUse">
|
|
4
|
+
<stop offset="0%" stop-color="#7C3AED"/>
|
|
5
|
+
<stop offset="100%" stop-color="#EC4899"/>
|
|
6
|
+
</linearGradient>
|
|
7
|
+
<linearGradient id="fgf" x1="0" y1="0" x2="32" y2="32" gradientUnits="userSpaceOnUse">
|
|
8
|
+
<stop offset="0%" stop-color="#7C3AED" stop-opacity="0.3"/>
|
|
9
|
+
<stop offset="100%" stop-color="#EC4899" stop-opacity="0.3"/>
|
|
10
|
+
</linearGradient>
|
|
11
|
+
</defs>
|
|
12
|
+
|
|
13
|
+
<!-- Background -->
|
|
14
|
+
<rect width="32" height="32" rx="7" fill="#0F0A1A"/>
|
|
15
|
+
|
|
16
|
+
<!-- Subtle neural lines -->
|
|
17
|
+
<line x1="8" y1="8" x2="24" y2="8" stroke="url(#fgf)" stroke-width="0.8"/>
|
|
18
|
+
<line x1="8" y1="24" x2="24" y2="24" stroke="url(#fgf)" stroke-width="0.8"/>
|
|
19
|
+
<line x1="8" y1="8" x2="24" y2="24" stroke="url(#fgf)" stroke-width="0.6"/>
|
|
20
|
+
|
|
21
|
+
<!-- N strokes -->
|
|
22
|
+
<line x1="8" y1="8" x2="8" y2="24" stroke="url(#fg)" stroke-width="3.5" stroke-linecap="round"/>
|
|
23
|
+
<line x1="8" y1="8" x2="24" y2="24" stroke="url(#fg)" stroke-width="3.5" stroke-linecap="round"/>
|
|
24
|
+
<line x1="24" y1="8" x2="24" y2="24" stroke="url(#fg)" stroke-width="3.5" stroke-linecap="round"/>
|
|
25
|
+
|
|
26
|
+
<!-- Nodes -->
|
|
27
|
+
<circle cx="8" cy="8" r="2.5" fill="url(#fg)"/>
|
|
28
|
+
<circle cx="24" cy="8" r="2.5" fill="url(#fg)"/>
|
|
29
|
+
<circle cx="8" cy="24" r="2.5" fill="url(#fg)"/>
|
|
30
|
+
<circle cx="24" cy="24" r="2.5" fill="url(#fg)"/>
|
|
31
|
+
<circle cx="16" cy="16" r="2" fill="#EC4899"/>
|
|
32
|
+
</svg>
|
|
Binary file
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" fill="none">
|
|
2
|
+
<defs>
|
|
3
|
+
<linearGradient id="grad" x1="0" y1="0" x2="32" y2="32" gradientUnits="userSpaceOnUse">
|
|
4
|
+
<stop offset="0%" stop-color="#7C3AED"/>
|
|
5
|
+
<stop offset="100%" stop-color="#EC4899"/>
|
|
6
|
+
</linearGradient>
|
|
7
|
+
<linearGradient id="gradFade" x1="0" y1="0" x2="32" y2="32" gradientUnits="userSpaceOnUse">
|
|
8
|
+
<stop offset="0%" stop-color="#7C3AED" stop-opacity="0.35"/>
|
|
9
|
+
<stop offset="100%" stop-color="#EC4899" stop-opacity="0.35"/>
|
|
10
|
+
</linearGradient>
|
|
11
|
+
</defs>
|
|
12
|
+
|
|
13
|
+
<!-- Dark background -->
|
|
14
|
+
<rect width="32" height="32" rx="7" fill="#0F0A1A"/>
|
|
15
|
+
|
|
16
|
+
<!-- Neural connection lines (subtle — behind the N strokes) -->
|
|
17
|
+
<line x1="7" y1="8" x2="25" y2="8" stroke="url(#gradFade)" stroke-width="0.7"/>
|
|
18
|
+
<line x1="7" y1="24" x2="25" y2="24" stroke="url(#gradFade)" stroke-width="0.7"/>
|
|
19
|
+
<line x1="7" y1="8" x2="25" y2="24" stroke="url(#gradFade)" stroke-width="0.5"/>
|
|
20
|
+
|
|
21
|
+
<!-- N — left vertical -->
|
|
22
|
+
<line x1="7" y1="8" x2="7" y2="24" stroke="url(#grad)" stroke-width="3" stroke-linecap="round"/>
|
|
23
|
+
<!-- N — diagonal crossbar -->
|
|
24
|
+
<line x1="7" y1="8" x2="25" y2="24" stroke="url(#grad)" stroke-width="3" stroke-linecap="round"/>
|
|
25
|
+
<!-- N — right vertical -->
|
|
26
|
+
<line x1="25" y1="8" x2="25" y2="24" stroke="url(#grad)" stroke-width="3" stroke-linecap="round"/>
|
|
27
|
+
|
|
28
|
+
<!-- Synaptic nodes at stroke endpoints -->
|
|
29
|
+
<circle cx="7" cy="8" r="2.3" fill="url(#grad)"/>
|
|
30
|
+
<circle cx="25" cy="8" r="2.3" fill="url(#grad)"/>
|
|
31
|
+
<circle cx="7" cy="24" r="2.3" fill="url(#grad)"/>
|
|
32
|
+
<circle cx="25" cy="24" r="2.3" fill="url(#grad)"/>
|
|
33
|
+
|
|
34
|
+
<!-- Centre node on diagonal midpoint -->
|
|
35
|
+
<circle cx="16" cy="16" r="2" fill="#EC4899"/>
|
|
36
|
+
|
|
37
|
+
<!-- Tiny satellite dots -->
|
|
38
|
+
<circle cx="16" cy="8" r="1.1" fill="#A78BFA" fill-opacity="0.6"/>
|
|
39
|
+
<circle cx="16" cy="24" r="1.1" fill="#F472B6" fill-opacity="0.6"/>
|
|
40
|
+
</svg>
|