nexo-brain 5.3.13 → 5.3.15
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/bin/nexo-brain.js +52 -1
- package/package.json +1 -1
- package/src/crons/sync.py +18 -4
- 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/_entities.py +1 -1
- 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/agents.py +10 -3
- 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/schedule.py +2 -1
- 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/requirements.txt +1 -1
- 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/runtime_power.py +18 -1
- 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-cron-wrapper.sh +7 -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.auto-close-sessions.plist +1 -1
- package/templates/launchagents/com.nexo.catchup 2.plist +39 -0
- package/templates/launchagents/com.nexo.catchup.plist +1 -1
- 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.dashboard.plist +1 -1
- package/templates/launchagents/com.nexo.deep-sleep 2.plist +43 -0
- package/templates/launchagents/com.nexo.deep-sleep.plist +1 -1
- package/templates/launchagents/com.nexo.evolution 2.plist +44 -0
- package/templates/launchagents/com.nexo.evolution.plist +1 -1
- package/templates/launchagents/com.nexo.followup-hygiene 2.plist +45 -0
- package/templates/launchagents/com.nexo.followup-hygiene.plist +1 -1
- package/templates/launchagents/com.nexo.immune 2.plist +41 -0
- package/templates/launchagents/com.nexo.immune.plist +1 -1
- package/templates/launchagents/com.nexo.postmortem 2.plist +45 -0
- package/templates/launchagents/com.nexo.postmortem.plist +1 -1
- package/templates/launchagents/com.nexo.self-audit 2.plist +47 -0
- package/templates/launchagents/com.nexo.self-audit.plist +1 -1
- package/templates/launchagents/com.nexo.synthesis 2.plist +45 -0
- package/templates/launchagents/com.nexo.synthesis.plist +1 -1
- package/templates/launchagents/com.nexo.watchdog 2.plist +37 -0
- package/templates/launchagents/com.nexo.watchdog.plist +1 -1
- 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/script-template.py +5 -4
- package/templates/skill-script-template 2.py +48 -0
- package/templates/skill-script-template.py +2 -1
- package/templates/skill-template 2.md +33 -0
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# nexo-update.sh — Standalone NEXO update script
|
|
3
|
+
# Same logic as the MCP tool but usable when the server itself needs updating.
|
|
4
|
+
#
|
|
5
|
+
# Usage:
|
|
6
|
+
# nexo-update.sh # pull from origin main
|
|
7
|
+
# nexo-update.sh origin beta # pull from origin beta
|
|
8
|
+
# NEXO_HOME=/path nexo-update.sh # custom NEXO_HOME
|
|
9
|
+
|
|
10
|
+
set -euo pipefail
|
|
11
|
+
|
|
12
|
+
# --- Configuration ---
|
|
13
|
+
REMOTE="${1:-origin}"
|
|
14
|
+
BRANCH="${2:-main}"
|
|
15
|
+
NEXO_HOME="${NEXO_HOME:-$HOME/.nexo}"
|
|
16
|
+
|
|
17
|
+
# Determine repo directory: script is at src/scripts/, repo root is ../../
|
|
18
|
+
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
19
|
+
REPO_DIR="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
|
20
|
+
SRC_DIR="$REPO_DIR/src"
|
|
21
|
+
PACKAGE_JSON="$REPO_DIR/package.json"
|
|
22
|
+
|
|
23
|
+
# --- Helpers ---
|
|
24
|
+
RED='\033[0;31m'
|
|
25
|
+
GREEN='\033[0;32m'
|
|
26
|
+
YELLOW='\033[1;33m'
|
|
27
|
+
NC='\033[0m'
|
|
28
|
+
|
|
29
|
+
log() { echo -e "${GREEN}[nexo-update]${NC} $*"; }
|
|
30
|
+
warn() { echo -e "${YELLOW}[nexo-update]${NC} $*"; }
|
|
31
|
+
err() { echo -e "${RED}[nexo-update]${NC} $*" >&2; }
|
|
32
|
+
|
|
33
|
+
read_version() {
|
|
34
|
+
python3 -c "import json; print(json.load(open('$PACKAGE_JSON')).get('version','unknown'))" 2>/dev/null || echo "unknown"
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
# --- Check if this is a git repo ---
|
|
38
|
+
if [ ! -d "$REPO_DIR/.git" ] && [ ! -f "$REPO_DIR/.git" ]; then
|
|
39
|
+
err "ABORTED: Not a git repository at $REPO_DIR"
|
|
40
|
+
err "For packaged installs, use: npm update -g nexo-brain"
|
|
41
|
+
exit 1
|
|
42
|
+
fi
|
|
43
|
+
|
|
44
|
+
# --- Step 1: Check for uncommitted changes in entire worktree ---
|
|
45
|
+
log "Checking for uncommitted changes..."
|
|
46
|
+
cd "$REPO_DIR"
|
|
47
|
+
|
|
48
|
+
if [ -n "$(git status --porcelain 2>/dev/null)" ]; then
|
|
49
|
+
err "ABORTED: Uncommitted changes in worktree"
|
|
50
|
+
git status --short
|
|
51
|
+
exit 1
|
|
52
|
+
fi
|
|
53
|
+
log "Working tree clean."
|
|
54
|
+
|
|
55
|
+
# Record current state
|
|
56
|
+
OLD_VERSION="$(read_version)"
|
|
57
|
+
OLD_COMMIT="$(git rev-parse HEAD)"
|
|
58
|
+
REQ_FILE="$SRC_DIR/requirements.txt"
|
|
59
|
+
OLD_REQ_HASH=""
|
|
60
|
+
if [ -f "$REQ_FILE" ]; then
|
|
61
|
+
OLD_REQ_HASH="$(shasum -a 256 "$REQ_FILE" | cut -d' ' -f1)"
|
|
62
|
+
fi
|
|
63
|
+
log "Current: v${OLD_VERSION} (${OLD_COMMIT:0:8})"
|
|
64
|
+
|
|
65
|
+
# --- Step 2: Backup databases ---
|
|
66
|
+
TIMESTAMP="$(date +%Y-%m-%d-%H%M)"
|
|
67
|
+
BACKUP_DIR="$NEXO_HOME/backups/pre-update-$TIMESTAMP"
|
|
68
|
+
|
|
69
|
+
backup_dbs() {
|
|
70
|
+
local found=0
|
|
71
|
+
# Check data/, NEXO_HOME root, and src/ for .db files
|
|
72
|
+
for dir in "$NEXO_HOME/data" "$NEXO_HOME" "$SRC_DIR"; do
|
|
73
|
+
if [ -d "$dir" ]; then
|
|
74
|
+
for db in "$dir"/*.db; do
|
|
75
|
+
[ -f "$db" ] || continue
|
|
76
|
+
found=1
|
|
77
|
+
mkdir -p "$BACKUP_DIR"
|
|
78
|
+
cp "$db" "$BACKUP_DIR/$(basename "$db")"
|
|
79
|
+
log " Backed up: $(basename "$db")"
|
|
80
|
+
done
|
|
81
|
+
fi
|
|
82
|
+
done
|
|
83
|
+
if [ "$found" -eq 0 ]; then
|
|
84
|
+
log " No databases found to backup."
|
|
85
|
+
fi
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
log "Backing up databases..."
|
|
89
|
+
backup_dbs
|
|
90
|
+
|
|
91
|
+
# --- Step 3: git pull ---
|
|
92
|
+
log "Pulling from ${REMOTE}/${BRANCH}..."
|
|
93
|
+
PULL_OUTPUT="$(git pull "$REMOTE" "$BRANCH" 2>&1)" || {
|
|
94
|
+
err "git pull failed:"
|
|
95
|
+
err "$PULL_OUTPUT"
|
|
96
|
+
exit 1
|
|
97
|
+
}
|
|
98
|
+
log "$PULL_OUTPUT"
|
|
99
|
+
|
|
100
|
+
if echo "$PULL_OUTPUT" | grep -q "Already up to date"; then
|
|
101
|
+
log "Already up to date (v${OLD_VERSION}). Done."
|
|
102
|
+
exit 0
|
|
103
|
+
fi
|
|
104
|
+
|
|
105
|
+
# --- Step 4: Check version ---
|
|
106
|
+
NEW_VERSION="$(read_version)"
|
|
107
|
+
log "New version: v${NEW_VERSION}"
|
|
108
|
+
|
|
109
|
+
# --- Step 4b: Reinstall Python dependencies if requirements.txt changed ---
|
|
110
|
+
NEW_REQ_HASH=""
|
|
111
|
+
if [ -f "$REQ_FILE" ]; then
|
|
112
|
+
NEW_REQ_HASH="$(shasum -a 256 "$REQ_FILE" | cut -d' ' -f1)"
|
|
113
|
+
fi
|
|
114
|
+
|
|
115
|
+
DEPS_CHANGED=false
|
|
116
|
+
if [ "$OLD_REQ_HASH" != "$NEW_REQ_HASH" ]; then
|
|
117
|
+
DEPS_CHANGED=true
|
|
118
|
+
fi
|
|
119
|
+
|
|
120
|
+
reinstall_pip_deps() {
|
|
121
|
+
local VENV_PIP="$NEXO_HOME/.venv/bin/pip"
|
|
122
|
+
if [ -f "$REQ_FILE" ]; then
|
|
123
|
+
if [ -x "$VENV_PIP" ]; then
|
|
124
|
+
"$VENV_PIP" install --quiet -r "$REQ_FILE" || return 1
|
|
125
|
+
else
|
|
126
|
+
python3 -m pip install --quiet -r "$REQ_FILE" --break-system-packages 2>/dev/null || return 1
|
|
127
|
+
fi
|
|
128
|
+
fi
|
|
129
|
+
return 0
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
if [ "$DEPS_CHANGED" = true ] || [ "$OLD_VERSION" != "$NEW_VERSION" ]; then
|
|
133
|
+
log "Reinstalling Python dependencies..."
|
|
134
|
+
if ! reinstall_pip_deps; then
|
|
135
|
+
err "pip install failed! Rolling back..."
|
|
136
|
+
git reset --hard "$OLD_COMMIT"
|
|
137
|
+
reinstall_pip_deps || warn "pip rollback also had issues"
|
|
138
|
+
if [ -d "$BACKUP_DIR" ]; then
|
|
139
|
+
for db in "$BACKUP_DIR"/*.db; do
|
|
140
|
+
[ -f "$db" ] || continue
|
|
141
|
+
BASENAME="$(basename "$db")"
|
|
142
|
+
for candidate in "$NEXO_HOME/data/$BASENAME" "$NEXO_HOME/$BASENAME" "$SRC_DIR/$BASENAME"; do
|
|
143
|
+
if [ -f "$candidate" ]; then
|
|
144
|
+
cp "$db" "$candidate"
|
|
145
|
+
warn " Restored: $BASENAME"
|
|
146
|
+
break
|
|
147
|
+
fi
|
|
148
|
+
done
|
|
149
|
+
done
|
|
150
|
+
fi
|
|
151
|
+
err "Rolled back to ${OLD_COMMIT:0:8}. Databases restored."
|
|
152
|
+
exit 1
|
|
153
|
+
fi
|
|
154
|
+
log "Python dependencies updated."
|
|
155
|
+
fi
|
|
156
|
+
|
|
157
|
+
# --- Step 5: Run migrations if version changed ---
|
|
158
|
+
if [ "$OLD_VERSION" != "$NEW_VERSION" ]; then
|
|
159
|
+
log "Version changed: ${OLD_VERSION} -> ${NEW_VERSION}"
|
|
160
|
+
log "Running migrations..."
|
|
161
|
+
if ! (cd "$SRC_DIR" && python3 -c "import db; db.init_db()" 2>&1); then
|
|
162
|
+
err "Migration failed! Rolling back..."
|
|
163
|
+
git reset --hard "$OLD_COMMIT"
|
|
164
|
+
# Reinstall pip deps from restored old requirements.txt
|
|
165
|
+
reinstall_pip_deps || warn "pip rollback also had issues"
|
|
166
|
+
# Restore DB backups
|
|
167
|
+
if [ -d "$BACKUP_DIR" ]; then
|
|
168
|
+
for db in "$BACKUP_DIR"/*.db; do
|
|
169
|
+
[ -f "$db" ] || continue
|
|
170
|
+
BASENAME="$(basename "$db")"
|
|
171
|
+
for candidate in "$NEXO_HOME/data/$BASENAME" "$NEXO_HOME/$BASENAME" "$SRC_DIR/$BASENAME"; do
|
|
172
|
+
if [ -f "$candidate" ]; then
|
|
173
|
+
cp "$db" "$candidate"
|
|
174
|
+
warn " Restored: $BASENAME"
|
|
175
|
+
break
|
|
176
|
+
fi
|
|
177
|
+
done
|
|
178
|
+
done
|
|
179
|
+
fi
|
|
180
|
+
err "Rolled back to ${OLD_COMMIT:0:8}. Databases and deps restored."
|
|
181
|
+
exit 1
|
|
182
|
+
fi
|
|
183
|
+
log "Migrations applied."
|
|
184
|
+
else
|
|
185
|
+
log "Version unchanged (${OLD_VERSION}), skipping migrations."
|
|
186
|
+
fi
|
|
187
|
+
|
|
188
|
+
# --- Step 6: Verify import ---
|
|
189
|
+
log "Verifying server.py import..."
|
|
190
|
+
if ! (cd "$SRC_DIR" && python3 -c "import server" 2>&1); then
|
|
191
|
+
err "Import verification failed! Rolling back..."
|
|
192
|
+
git reset --hard "$OLD_COMMIT"
|
|
193
|
+
# Reinstall pip deps from restored old requirements.txt
|
|
194
|
+
reinstall_pip_deps || warn "pip rollback also had issues"
|
|
195
|
+
if [ -d "$BACKUP_DIR" ]; then
|
|
196
|
+
for db in "$BACKUP_DIR"/*.db; do
|
|
197
|
+
[ -f "$db" ] || continue
|
|
198
|
+
BASENAME="$(basename "$db")"
|
|
199
|
+
for candidate in "$NEXO_HOME/data/$BASENAME" "$NEXO_HOME/$BASENAME" "$SRC_DIR/$BASENAME"; do
|
|
200
|
+
if [ -f "$candidate" ]; then
|
|
201
|
+
cp "$db" "$candidate"
|
|
202
|
+
warn " Restored: $BASENAME"
|
|
203
|
+
break
|
|
204
|
+
fi
|
|
205
|
+
done
|
|
206
|
+
done
|
|
207
|
+
fi
|
|
208
|
+
err "Rolled back to ${OLD_COMMIT:0:8}. Databases and deps restored."
|
|
209
|
+
exit 1
|
|
210
|
+
fi
|
|
211
|
+
|
|
212
|
+
# --- Step 7: Sync hooks to NEXO_HOME ---
|
|
213
|
+
HOOKS_SRC="$SRC_DIR/hooks"
|
|
214
|
+
HOOKS_DEST="$NEXO_HOME/hooks"
|
|
215
|
+
if [ -d "$HOOKS_SRC" ]; then
|
|
216
|
+
mkdir -p "$HOOKS_DEST"
|
|
217
|
+
SYNCED=0
|
|
218
|
+
for hook in "$HOOKS_SRC"/*.sh; do
|
|
219
|
+
[ -f "$hook" ] || continue
|
|
220
|
+
cp "$hook" "$HOOKS_DEST/$(basename "$hook")"
|
|
221
|
+
chmod 755 "$HOOKS_DEST/$(basename "$hook")"
|
|
222
|
+
SYNCED=$((SYNCED + 1))
|
|
223
|
+
done
|
|
224
|
+
if [ "$SYNCED" -gt 0 ]; then
|
|
225
|
+
log "Synced $SYNCED hook(s) to $HOOKS_DEST"
|
|
226
|
+
fi
|
|
227
|
+
fi
|
|
228
|
+
|
|
229
|
+
# --- Step 8: Sync cron definitions with manifest ---
|
|
230
|
+
CRON_SYNC="$SRC_DIR/crons/sync.py"
|
|
231
|
+
CRON_SYNC_OK=false
|
|
232
|
+
if [ -f "$CRON_SYNC" ]; then
|
|
233
|
+
log "Syncing cron definitions..."
|
|
234
|
+
if NEXO_HOME="$NEXO_HOME" NEXO_CODE="$SRC_DIR" python3 "$CRON_SYNC" 2>&1; then
|
|
235
|
+
log "Cron definitions synced."
|
|
236
|
+
CRON_SYNC_OK=true
|
|
237
|
+
else
|
|
238
|
+
warn "Cron sync failed (non-fatal). Installed manifest NOT refreshed to avoid divergence."
|
|
239
|
+
fi
|
|
240
|
+
fi
|
|
241
|
+
|
|
242
|
+
# --- Step 8b: Refresh installed manifest for catchup/watchdog (only if sync succeeded) ---
|
|
243
|
+
if $CRON_SYNC_OK && [ -d "$SRC_DIR/crons" ]; then
|
|
244
|
+
mkdir -p "$NEXO_HOME/crons"
|
|
245
|
+
cp -f "$SRC_DIR/crons/"*.json "$NEXO_HOME/crons/" 2>/dev/null
|
|
246
|
+
cp -f "$SRC_DIR/crons/"*.py "$NEXO_HOME/crons/" 2>/dev/null
|
|
247
|
+
log "Refreshed installed crons manifest."
|
|
248
|
+
fi
|
|
249
|
+
|
|
250
|
+
# --- Step 9: Sync shared client configs ---
|
|
251
|
+
CLIENT_SYNC="$SRC_DIR/scripts/nexo-sync-clients.py"
|
|
252
|
+
if [ -f "$CLIENT_SYNC" ]; then
|
|
253
|
+
log "Syncing shared client configs..."
|
|
254
|
+
CLIENT_SYNC_ARGS=()
|
|
255
|
+
if [ -f "$NEXO_HOME/config/schedule.json" ]; then
|
|
256
|
+
while IFS= read -r line; do
|
|
257
|
+
[ -n "$line" ] && CLIENT_SYNC_ARGS+=("--enabled-client" "$line")
|
|
258
|
+
done < <(
|
|
259
|
+
NEXO_HOME="$NEXO_HOME" NEXO_CODE="$SRC_DIR" python3 - <<'PY'
|
|
260
|
+
import json
|
|
261
|
+
import os
|
|
262
|
+
import sys
|
|
263
|
+
from pathlib import Path
|
|
264
|
+
|
|
265
|
+
sys.path.insert(0, os.environ["NEXO_CODE"])
|
|
266
|
+
from client_preferences import normalize_client_preferences
|
|
267
|
+
|
|
268
|
+
schedule_file = Path(os.environ["NEXO_HOME"]) / "config" / "schedule.json"
|
|
269
|
+
schedule_payload = json.loads(schedule_file.read_text()) if schedule_file.exists() else {}
|
|
270
|
+
prefs = normalize_client_preferences(schedule_payload)
|
|
271
|
+
if prefs != {key: schedule_payload.get(key) for key in prefs}:
|
|
272
|
+
merged = dict(schedule_payload)
|
|
273
|
+
merged.update(prefs)
|
|
274
|
+
schedule_file.parent.mkdir(parents=True, exist_ok=True)
|
|
275
|
+
schedule_file.write_text(json.dumps(merged, indent=2, ensure_ascii=False) + "\n")
|
|
276
|
+
enabled = [key for key, value in prefs.get("interactive_clients", {}).items() if value]
|
|
277
|
+
if prefs.get("automation_enabled", True):
|
|
278
|
+
backend = prefs.get("automation_backend")
|
|
279
|
+
if backend and backend != "none" and backend not in enabled:
|
|
280
|
+
enabled.append(backend)
|
|
281
|
+
for item in enabled:
|
|
282
|
+
print(item)
|
|
283
|
+
PY
|
|
284
|
+
)
|
|
285
|
+
fi
|
|
286
|
+
if NEXO_HOME="$NEXO_HOME" NEXO_CODE="$SRC_DIR" python3 "$CLIENT_SYNC" --nexo-home "$NEXO_HOME" --runtime-root "$SRC_DIR" "${CLIENT_SYNC_ARGS[@]}" --json >/dev/null 2>&1; then
|
|
287
|
+
log "Shared client configs synced."
|
|
288
|
+
else
|
|
289
|
+
warn "Client config sync failed (non-fatal). Run 'nexo clients sync' later."
|
|
290
|
+
fi
|
|
291
|
+
fi
|
|
292
|
+
|
|
293
|
+
# --- Done ---
|
|
294
|
+
echo ""
|
|
295
|
+
log "========================================="
|
|
296
|
+
log " UPDATE SUCCESSFUL"
|
|
297
|
+
if [ "$OLD_VERSION" != "$NEW_VERSION" ]; then
|
|
298
|
+
log " Version: ${OLD_VERSION} -> ${NEW_VERSION}"
|
|
299
|
+
else
|
|
300
|
+
log " Version: ${OLD_VERSION} (unchanged)"
|
|
301
|
+
fi
|
|
302
|
+
log " Branch: ${REMOTE}/${BRANCH}"
|
|
303
|
+
log " Backup: ${BACKUP_DIR}"
|
|
304
|
+
log "========================================="
|
|
305
|
+
echo ""
|
|
306
|
+
warn "MCP server restart needed to load new code."
|