nexo-brain 5.3.26 → 5.3.28
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/hook_guardrails.py +44 -0
- package/src/server.py +3 -0
- package/src/tools_sessions.py +6 -1
- package/src/dashboard/static/favicon 2.svg +0 -32
- package/src/dashboard/static/nexo-logo 2.png +0 -0
- package/src/dashboard/static/nexo-logo 2.svg +0 -40
- package/src/dashboard/static/style 2.css +0 -2458
- package/src/dashboard/templates/adaptive 2.html +0 -118
- package/src/dashboard/templates/artifacts 2.html +0 -133
- package/src/dashboard/templates/backups 2.html +0 -136
- package/src/dashboard/templates/base 2.html +0 -417
- package/src/dashboard/templates/calendar 2.html +0 -591
- package/src/dashboard/templates/chat 2.html +0 -356
- package/src/dashboard/templates/claims 2.html +0 -259
- package/src/dashboard/templates/cortex 2.html +0 -321
- package/src/dashboard/templates/credentials 2.html +0 -128
- package/src/dashboard/templates/crons 2.html +0 -370
- package/src/dashboard/templates/dashboard 2.html +0 -494
- package/src/dashboard/templates/dreams 2.html +0 -252
- package/src/dashboard/templates/email 2.html +0 -160
- package/src/dashboard/templates/evolution 2.html +0 -189
- package/src/dashboard/templates/feed 2.html +0 -249
- package/src/dashboard/templates/followup_health 2.html +0 -170
- package/src/dashboard/templates/graph 2.html +0 -201
- package/src/dashboard/templates/guard 2.html +0 -259
- package/src/dashboard/templates/inbox 2.html +0 -251
- package/src/dashboard/templates/memory 2.html +0 -420
- package/src/dashboard/templates/operations 2.html +0 -608
- package/src/dashboard/templates/plugins 2.html +0 -185
- package/src/dashboard/templates/protocol 2.html +0 -199
- package/src/dashboard/templates/rules 2.html +0 -246
- package/src/dashboard/templates/sentiment 2.html +0 -247
- package/src/dashboard/templates/sessions 2.html +0 -218
- package/src/dashboard/templates/skills 2.html +0 -329
- package/src/dashboard/templates/somatic 2.html +0 -73
- package/src/dashboard/templates/triggers 2.html +0 -133
- package/src/dashboard/templates/trust 2.html +0 -360
- package/src/db/__init__ 2.py +0 -259
- package/src/db/_core 2.py +0 -437
- package/src/db/_credentials 2.py +0 -124
- package/src/db/_episodic 2.py +0 -762
- package/src/db/_evolution 2.py +0 -54
- package/src/db/_fts 2.py +0 -406
- package/src/db/_goal_profiles 2.py +0 -376
- package/src/db/_hot_context 2.py +0 -660
- package/src/db/_outcomes 2.py +0 -800
- package/src/db/_personal_scripts 2.py +0 -582
- package/src/db/_sessions 2.py +0 -330
- package/src/db/_tasks 2.py +0 -91
- package/src/db/_watchers 2.py +0 -173
- package/src/doctor/formatters 2.py +0 -52
- package/src/doctor/models 2.py +0 -69
- package/src/doctor/planes 2.py +0 -87
- package/src/doctor/providers/__init__ 2.py +0 -1
- package/src/doctor/providers/deep 2.py +0 -367
- package/src/evolution_cycle 2.py +0 -519
- package/src/hooks/auto_capture 2.py +0 -208
- package/src/hooks/caffeinate-guard 2.sh +0 -8
- package/src/hooks/capture-session 2.sh +0 -21
- package/src/hooks/capture-tool-logs 2.sh +0 -158
- package/src/hooks/daily-briefing-check 2.sh +0 -33
- package/src/hooks/heartbeat-enforcement 2.py +0 -90
- package/src/hooks/heartbeat-posttool 2.sh +0 -18
- package/src/hooks/inbox-hook 2.sh +0 -76
- package/src/hooks/post-compact 2.sh +0 -152
- package/src/hooks/pre-compact 2.sh +0 -169
- package/src/hooks/protocol-guardrail 2.sh +0 -10
- package/src/hooks/protocol-pretool-guardrail 2.sh +0 -9
- package/src/hooks/session-stop 2.sh +0 -52
- package/src/kg_populate 2.py +0 -292
- package/src/maintenance 2.py +0 -53
- package/src/memory_backends 2.py +0 -71
- package/src/migrate_embeddings 2.py +0 -124
- package/src/nexo_sdk 2.py +0 -103
- package/src/observability 2.py +0 -199
- package/src/plugin_loader 2.py +0 -217
- package/src/plugins/__init__ 2.py +0 -0
- package/src/plugins/artifact_registry 2.py +0 -450
- package/src/plugins/backup 2.py +0 -127
- package/src/plugins/claims_tools 2.py +0 -119
- package/src/plugins/cognitive_memory 2.py +0 -609
- package/src/plugins/core_rules 2.py +0 -252
- package/src/plugins/cortex 2.py +0 -1155
- package/src/plugins/entities 2.py +0 -67
- package/src/plugins/episodic_memory 2.py +0 -560
- package/src/plugins/evolution 2.py +0 -167
- package/src/plugins/goal_engine 2.py +0 -142
- package/src/plugins/guard 2.py +0 -862
- package/src/plugins/impact 2.py +0 -29
- package/src/plugins/knowledge_graph_tools 2.py +0 -137
- package/src/plugins/media_memory_tools 2.py +0 -98
- package/src/plugins/memory_export 2.py +0 -196
- package/src/plugins/outcomes 2.py +0 -130
- package/src/plugins/personal_scripts 2.py +0 -117
- package/src/plugins/preferences 2.py +0 -47
- package/src/plugins/protocol 2.py +0 -1449
- package/src/plugins/simple_api 2.py +0 -106
- package/src/plugins/skills 2.py +0 -341
- package/src/plugins/state_watchers 2.py +0 -79
- package/src/plugins/update 2.py +0 -986
- package/src/plugins/user_state_tools 2.py +0 -43
- package/src/plugins/workflow 2.py +0 -588
- package/src/protocol_settings 2.py +0 -59
- package/src/public_contribution 2.py +0 -466
- package/src/public_evolution_queue 2.py +0 -241
- package/src/requirements 2.txt +0 -14
- package/src/retroactive_learnings 2.py +0 -373
- package/src/rules/__init__ 2.py +0 -0
- package/src/rules/core-rules 2.json +0 -331
- package/src/rules/migrate 2.py +0 -207
- package/src/runtime_power 2.py +0 -874
- package/src/script_registry 2.py +0 -1559
- package/src/scripts/check-context 2.py +0 -272
- package/src/scripts/deep-sleep/apply_findings 2.py +0 -2327
- package/src/scripts/deep-sleep/collect 2.py +0 -928
- package/src/scripts/deep-sleep/extract 2.py +0 -330
- package/src/scripts/deep-sleep/extract-prompt 2.md +0 -285
- package/src/scripts/deep-sleep/synthesize 2.py +0 -312
- package/src/scripts/deep-sleep/synthesize-prompt 2.md +0 -336
- package/src/scripts/nexo-agent-run 2.py +0 -75
- package/src/scripts/nexo-auto-update 2.py +0 -6
- package/src/scripts/nexo-backup 2.sh +0 -25
- package/src/scripts/nexo-brain-activation 2.sh +0 -140
- package/src/scripts/nexo-catchup 2.py +0 -300
- package/src/scripts/nexo-cognitive-decay 2.py +0 -257
- package/src/scripts/nexo-cortex-cycle 2.py +0 -293
- package/src/scripts/nexo-cron-wrapper 2.sh +0 -53
- package/src/scripts/nexo-daily-self-audit 2.py +0 -2161
- package/src/scripts/nexo-dashboard 2.sh +0 -29
- package/src/scripts/nexo-deep-sleep 2.sh +0 -86
- package/src/scripts/nexo-evolution-run 2.py +0 -1664
- package/src/scripts/nexo-followup-hygiene 2.py +0 -139
- package/src/scripts/nexo-hook-record 2.py +0 -42
- package/src/scripts/nexo-immune 2.py +0 -936
- package/src/scripts/nexo-impact-scorer 2.py +0 -117
- package/src/scripts/nexo-inbox-hook 2.sh +0 -74
- package/src/scripts/nexo-install 2.py +0 -6
- package/src/scripts/nexo-learning-housekeep 2.py +0 -401
- package/src/scripts/nexo-learning-validator 2.py +0 -266
- package/src/scripts/nexo-migrate 2.py +0 -260
- package/src/scripts/nexo-outcome-checker 2.py +0 -127
- package/src/scripts/nexo-postmortem-consolidator 2.py +0 -456
- package/src/scripts/nexo-pre-commit 2.py +0 -120
- package/src/scripts/nexo-prevent-sleep 2.sh +0 -35
- package/src/scripts/nexo-proactive-dashboard 2.py +0 -354
- package/src/scripts/nexo-reflection 2.py +0 -256
- package/src/scripts/nexo-runtime-preflight 2.py +0 -274
- package/src/scripts/nexo-sleep 2.py +0 -631
- package/src/scripts/nexo-snapshot-restore 2.sh +0 -35
- package/src/scripts/nexo-sync-clients 2.py +0 -16
- package/src/scripts/nexo-synthesis 2.py +0 -475
- package/src/scripts/nexo-tcc-approve 2.sh +0 -79
- package/src/scripts/nexo-update 2.sh +0 -306
- package/src/scripts/nexo-watchdog 2.sh +0 -1207
- package/src/scripts/nexo-watchdog-smoke 2.py +0 -119
- package/src/scripts/rehydrate_learnings_from_archive 2.py +0 -245
- package/src/server 2.py +0 -1296
- package/src/skills/run-nexo-audit-phase/guide 2.md +0 -43
- package/src/skills/run-nexo-audit-phase/skill 2.json +0 -59
- package/src/skills/run-nexo-core-fix-cycle/guide 2.md +0 -17
- package/src/skills/run-nexo-core-fix-cycle/script 2.py +0 -276
- package/src/skills/run-nexo-core-fix-cycle/skill 2.json +0 -58
- package/src/skills/run-release-final-audit/guide 2.md +0 -16
- package/src/skills/run-release-final-audit/script 2.py +0 -259
- package/src/skills/run-release-final-audit/skill 2.json +0 -77
- package/src/skills/run-runtime-doctor/guide 2.md +0 -12
- package/src/skills/run-runtime-doctor/script 2.py +0 -21
- package/src/skills/run-runtime-doctor/skill 2.json +0 -25
- package/src/skills_runtime 2.py +0 -932
- package/src/state_watchers_runtime 2.py +0 -475
- package/src/storage_router 2.py +0 -32
- package/src/system_catalog 2.py +0 -786
- package/src/tools_coordination 2.py +0 -103
- package/src/tools_credentials 2.py +0 -68
- package/src/tools_drive 2.py +0 -487
- package/src/tools_hot_context 2.py +0 -163
- package/src/tools_learnings 2.py +0 -612
- package/src/tools_menu 2.py +0 -229
- package/src/tools_reminders 2.py +0 -88
- package/src/tools_reminders_crud 2.py +0 -363
- package/src/tools_sessions 2.py +0 -1054
- package/src/tools_system_catalog 2.py +0 -19
- package/src/tools_task_history 2.py +0 -57
- package/src/tools_transcripts 2.py +0 -98
- package/src/transcript_utils 2.py +0 -412
- package/src/user_context 2.py +0 -46
- package/src/user_data_portability 2.py +0 -328
- package/src/user_state_model 2.py +0 -170
- package/templates/CLAUDE.md 2.template +0 -108
- package/templates/CODEX.AGENTS.md 2.template +0 -66
- package/templates/launchagents/README 2.md +0 -132
- package/templates/launchagents/com.nexo.auto-close-sessions 2.plist +0 -39
- package/templates/launchagents/com.nexo.catchup 2.plist +0 -39
- package/templates/launchagents/com.nexo.cognitive-decay 2.plist +0 -40
- package/templates/launchagents/com.nexo.dashboard 2.plist +0 -43
- package/templates/launchagents/com.nexo.deep-sleep 2.plist +0 -43
- package/templates/launchagents/com.nexo.evolution 2.plist +0 -44
- package/templates/launchagents/com.nexo.followup-hygiene 2.plist +0 -45
- package/templates/launchagents/com.nexo.immune 2.plist +0 -41
- package/templates/launchagents/com.nexo.postmortem 2.plist +0 -45
- package/templates/launchagents/com.nexo.self-audit 2.plist +0 -47
- package/templates/launchagents/com.nexo.synthesis 2.plist +0 -45
- package/templates/launchagents/com.nexo.watchdog 2.plist +0 -37
- package/templates/nexo_helper 2.py +0 -301
- package/templates/openclaw 2.json +0 -13
- package/templates/plugin-template 2.py +0 -40
- package/templates/script-template 2.py +0 -59
- package/templates/script-template 2.sh +0 -13
- package/templates/skill-script-template 2.py +0 -48
- package/templates/skill-template 2.md +0 -33
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nexo-brain",
|
|
3
|
-
"version": "5.3.
|
|
3
|
+
"version": "5.3.28",
|
|
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.28",
|
|
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/hook_guardrails.py
CHANGED
|
@@ -225,6 +225,23 @@ def _session_has_guard_check(conn, sid: str) -> bool:
|
|
|
225
225
|
return bool(row)
|
|
226
226
|
|
|
227
227
|
|
|
228
|
+
def _session_has_guard_for_file(conn, sid: str, filepath: str) -> bool:
|
|
229
|
+
"""Check if guard_check was called for a specific file in this session."""
|
|
230
|
+
if not filepath:
|
|
231
|
+
return False
|
|
232
|
+
normalized = _normalize_file_path(filepath)
|
|
233
|
+
basename = os.path.basename(filepath)
|
|
234
|
+
# guard_checks.files is a comma-separated or JSON list of paths/areas
|
|
235
|
+
row = conn.execute(
|
|
236
|
+
"""SELECT 1 FROM guard_checks
|
|
237
|
+
WHERE session_id = ?
|
|
238
|
+
AND (files LIKE ? OR files LIKE ? OR files LIKE ?)
|
|
239
|
+
LIMIT 1""",
|
|
240
|
+
(sid, f"%{normalized}%", f"%{basename}%", f"%{filepath}%"),
|
|
241
|
+
).fetchone()
|
|
242
|
+
return bool(row)
|
|
243
|
+
|
|
244
|
+
|
|
228
245
|
def _find_open_debt(conn, *, session_id: str, task_id: str, debt_type: str, file_token: str) -> dict | None:
|
|
229
246
|
row = conn.execute(
|
|
230
247
|
"""SELECT *
|
|
@@ -548,6 +565,28 @@ def process_pre_tool_event(payload: dict) -> dict:
|
|
|
548
565
|
"reason_code": "guard_unacknowledged",
|
|
549
566
|
}
|
|
550
567
|
)
|
|
568
|
+
continue
|
|
569
|
+
|
|
570
|
+
# Check if guard_check was called for this specific file
|
|
571
|
+
if not _session_has_guard_for_file(conn, sid, filepath):
|
|
572
|
+
debt = _ensure_protocol_debt(
|
|
573
|
+
conn,
|
|
574
|
+
session_id=sid,
|
|
575
|
+
task_id=task["task_id"],
|
|
576
|
+
debt_type="write_without_file_guard_check",
|
|
577
|
+
severity="warn",
|
|
578
|
+
evidence=f"{tool_name} attempted on {filepath} without a prior guard_check covering that file.",
|
|
579
|
+
file_token=filepath,
|
|
580
|
+
)
|
|
581
|
+
blocks.append(
|
|
582
|
+
{
|
|
583
|
+
"file": filepath,
|
|
584
|
+
"task_id": task["task_id"],
|
|
585
|
+
"debt_id": debt.get("id"),
|
|
586
|
+
"debt_type": "write_without_file_guard_check",
|
|
587
|
+
"reason_code": "missing_file_guard",
|
|
588
|
+
}
|
|
589
|
+
)
|
|
551
590
|
|
|
552
591
|
return {
|
|
553
592
|
"ok": True,
|
|
@@ -728,6 +767,11 @@ def format_pretool_block_message(result: dict) -> str:
|
|
|
728
767
|
lines.append(
|
|
729
768
|
f"- {file_note}: task {item['task_id']} still has blocking guard debt. Acknowledge it with `nexo_task_acknowledge_guard` before retrying."
|
|
730
769
|
)
|
|
770
|
+
elif item.get("reason_code") == "missing_file_guard":
|
|
771
|
+
lines.append(
|
|
772
|
+
f"- {file_note}: `nexo_guard_check` obligatorio antes de editar. "
|
|
773
|
+
f"Run `nexo_guard_check(files='{file_note}')` first, then retry the edit."
|
|
774
|
+
)
|
|
731
775
|
elif strictness == "learning":
|
|
732
776
|
lines.append(
|
|
733
777
|
f"- {file_note}: open `nexo_task_open(task_type='edit', files=['{file_note}'])` first, then rerun the edit."
|
package/src/server.py
CHANGED
|
@@ -304,6 +304,9 @@ def nexo_heartbeat(sid: str, task: str, context_hint: str = '') -> str:
|
|
|
304
304
|
"""Update session task, check inbox and pending questions. Auto-detects trust events.
|
|
305
305
|
|
|
306
306
|
Call this at the START of every user interaction (before doing work).
|
|
307
|
+
Output always begins with a NOW_UTC line (ISO-8601, UTC) — use it as the
|
|
308
|
+
authoritative wall-clock time for any artifact (emails, diaries, followups)
|
|
309
|
+
to avoid date/day-of-week drift across long sessions.
|
|
307
310
|
Args:
|
|
308
311
|
sid: Your session ID from nexo_startup.
|
|
309
312
|
task: Brief description of current work (5-10 words).
|
package/src/tools_sessions.py
CHANGED
|
@@ -431,7 +431,12 @@ def _handle_heartbeat_inner(sid: str, task: str, context_hint: str = '') -> str:
|
|
|
431
431
|
"""Inner body of handle_heartbeat — wrapped by tool_span above."""
|
|
432
432
|
from db import get_db
|
|
433
433
|
update_session(sid, task)
|
|
434
|
-
|
|
434
|
+
|
|
435
|
+
# Temporal anchor — surface authoritative UTC time so clients never drift
|
|
436
|
+
# on date/day-of-week across long sessions. Neutral ISO-8601, no locale,
|
|
437
|
+
# no timezone assumption: clients format per operator preferences.
|
|
438
|
+
_now_iso = datetime.now(timezone.utc).strftime('%Y-%m-%dT%H:%M:%SZ')
|
|
439
|
+
parts = [f"NOW_UTC: {_now_iso}", f"OK: {sid} — {task}"]
|
|
435
440
|
|
|
436
441
|
inbox = get_inbox(sid)
|
|
437
442
|
if inbox:
|
|
@@ -1,32 +0,0 @@
|
|
|
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
|
|
@@ -1,40 +0,0 @@
|
|
|
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>
|