nexo-brain 2.0.0 → 2.2.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.
- package/README.md +143 -44
- package/bin/nexo-brain.js +53 -26
- package/package.json +15 -3
- package/scripts/migrate-to-unified 2.sh +813 -0
- package/scripts/migrate-v1.5-to-v1.6 2.py +778 -0
- package/scripts/migrate-v1.7-to-v1.8 2.py +214 -0
- package/scripts/pre-commit-check 2.sh +55 -0
- package/src/__pycache__/auto_update.cpython-310.pyc +0 -0
- package/src/__pycache__/hnsw_index.cpython-310.pyc +0 -0
- package/src/__pycache__/kg_populate.cpython-310.pyc +0 -0
- package/src/__pycache__/knowledge_graph.cpython-310.pyc +0 -0
- package/src/__pycache__/plugin_loader.cpython-310.pyc +0 -0
- package/src/__pycache__/tools_coordination.cpython-310.pyc +0 -0
- package/src/__pycache__/tools_credentials.cpython-310.pyc +0 -0
- package/src/__pycache__/tools_learnings.cpython-310.pyc +0 -0
- package/src/__pycache__/tools_menu.cpython-310.pyc +0 -0
- package/src/__pycache__/tools_reminders.cpython-310.pyc +0 -0
- package/src/__pycache__/tools_reminders_crud.cpython-310.pyc +0 -0
- package/src/__pycache__/tools_sessions.cpython-310.pyc +0 -0
- package/src/__pycache__/tools_task_history.cpython-310.pyc +0 -0
- package/src/auto_close_sessions 2.py +159 -0
- package/src/auto_update 2.py +634 -0
- package/src/claim_graph 2.py +323 -0
- package/src/cognitive/__init__ 2.py +62 -0
- package/src/cognitive/__pycache__/__init__.cpython-310.pyc +0 -0
- package/src/cognitive/__pycache__/_core.cpython-310.pyc +0 -0
- package/src/cognitive/__pycache__/_decay.cpython-310.pyc +0 -0
- package/src/cognitive/__pycache__/_ingest.cpython-310.pyc +0 -0
- package/src/cognitive/__pycache__/_memory.cpython-310.pyc +0 -0
- package/src/cognitive/__pycache__/_search.cpython-310.pyc +0 -0
- package/src/cognitive/__pycache__/_trust.cpython-310.pyc +0 -0
- package/src/cognitive/_core 2.py +567 -0
- package/src/cognitive/_decay 2.py +382 -0
- package/src/cognitive/_ingest 2.py +892 -0
- package/src/cognitive/_memory 2.py +912 -0
- package/src/cognitive/_search 2.py +949 -0
- package/src/cognitive/_trust 2.py +464 -0
- package/src/cognitive/_trust.py +10 -36
- package/src/crons/manifest 2.json +106 -0
- package/src/crons/manifest.json +106 -0
- package/src/crons/sync 2.py +217 -0
- package/src/crons/sync.py +217 -0
- package/src/dashboard/__init__ 2.py +0 -0
- package/src/dashboard/__pycache__/__init__.cpython-310.pyc +0 -0
- package/src/dashboard/__pycache__/app.cpython-310.pyc +0 -0
- package/src/dashboard/app 2.py +789 -0
- package/src/dashboard/app.py +16 -2
- package/src/dashboard/templates/dashboard.html +3 -2
- package/src/db/__init__ 2.py +89 -0
- package/src/db/__pycache__/__init__.cpython-310.pyc +0 -0
- package/src/db/__pycache__/__init__.cpython-312.pyc +0 -0
- package/src/db/__pycache__/__init__.cpython-314.pyc +0 -0
- package/src/db/__pycache__/_core.cpython-310.pyc +0 -0
- package/src/db/__pycache__/_core.cpython-312.pyc +0 -0
- package/src/db/__pycache__/_core.cpython-314.pyc +0 -0
- package/src/db/__pycache__/_credentials.cpython-310.pyc +0 -0
- package/src/db/__pycache__/_credentials.cpython-312.pyc +0 -0
- package/src/db/__pycache__/_credentials.cpython-314.pyc +0 -0
- package/src/db/__pycache__/_entities.cpython-310.pyc +0 -0
- package/src/db/__pycache__/_entities.cpython-312.pyc +0 -0
- package/src/db/__pycache__/_entities.cpython-314.pyc +0 -0
- package/src/db/__pycache__/_episodic.cpython-310.pyc +0 -0
- package/src/db/__pycache__/_episodic.cpython-312.pyc +0 -0
- package/src/db/__pycache__/_episodic.cpython-314.pyc +0 -0
- package/src/db/__pycache__/_evolution.cpython-310.pyc +0 -0
- package/src/db/__pycache__/_evolution.cpython-312.pyc +0 -0
- package/src/db/__pycache__/_evolution.cpython-314.pyc +0 -0
- package/src/db/__pycache__/_fts.cpython-310.pyc +0 -0
- package/src/db/__pycache__/_fts.cpython-312.pyc +0 -0
- package/src/db/__pycache__/_fts.cpython-314.pyc +0 -0
- package/src/db/__pycache__/_learnings.cpython-310.pyc +0 -0
- package/src/db/__pycache__/_learnings.cpython-312.pyc +0 -0
- package/src/db/__pycache__/_learnings.cpython-314.pyc +0 -0
- package/src/db/__pycache__/_reminders.cpython-310.pyc +0 -0
- package/src/db/__pycache__/_reminders.cpython-312.pyc +0 -0
- package/src/db/__pycache__/_reminders.cpython-314.pyc +0 -0
- package/src/db/__pycache__/_schema.cpython-310.pyc +0 -0
- package/src/db/__pycache__/_schema.cpython-312.pyc +0 -0
- package/src/db/__pycache__/_schema.cpython-314.pyc +0 -0
- package/src/db/__pycache__/_sessions.cpython-310.pyc +0 -0
- package/src/db/__pycache__/_sessions.cpython-312.pyc +0 -0
- package/src/db/__pycache__/_sessions.cpython-314.pyc +0 -0
- package/src/db/__pycache__/_tasks.cpython-310.pyc +0 -0
- package/src/db/__pycache__/_tasks.cpython-312.pyc +0 -0
- package/src/db/__pycache__/_tasks.cpython-314.pyc +0 -0
- package/src/db/_core 2.py +417 -0
- package/src/db/_credentials 2.py +124 -0
- package/src/db/_entities 2.py +178 -0
- package/src/db/_episodic 2.py +738 -0
- package/src/db/_episodic.py +1 -1
- package/src/db/_evolution 2.py +54 -0
- package/src/db/_fts 2.py +406 -0
- package/src/db/_learnings 2.py +168 -0
- package/src/db/_reminders 2.py +338 -0
- package/src/db/_reminders.py +9 -5
- package/src/db/_schema 2.py +364 -0
- package/src/db/_sessions 2.py +300 -0
- package/src/db/_tasks 2.py +91 -0
- package/src/evolution_cycle 2.py +266 -0
- package/src/hnsw_index 2.py +254 -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-session.sh +2 -0
- package/src/hooks/capture-tool-logs 2.sh +127 -0
- package/src/hooks/capture-tool-logs.sh +3 -2
- package/src/hooks/daily-briefing-check 2.sh +33 -0
- package/src/hooks/inbox-hook 2.sh +76 -0
- package/src/hooks/inbox-hook.sh +3 -2
- package/src/hooks/post-compact 2.sh +148 -0
- package/src/hooks/post-compact.sh +1 -1
- package/src/hooks/pre-compact 2.sh +151 -0
- package/src/hooks/pre-compact.sh +1 -1
- package/src/hooks/session-start 2.sh +268 -0
- package/src/hooks/session-start.sh +6 -3
- package/src/hooks/session-stop 2.sh +140 -0
- package/src/hooks/session-stop.sh +3 -2
- package/src/kg_populate 2.py +290 -0
- package/src/knowledge_graph 2.py +257 -0
- package/src/maintenance 2.py +59 -0
- package/src/migrate_embeddings 2.py +122 -0
- package/src/plugin_loader 2.py +202 -0
- package/src/plugins/__init__ 2.py +0 -0
- package/src/plugins/__pycache__/__init__ 2.cpython-310.pyc +0 -0
- package/src/plugins/__pycache__/__init__.cpython-310.pyc +0 -0
- package/src/plugins/__pycache__/adaptive_mode 2.cpython-310.pyc +0 -0
- package/src/plugins/__pycache__/adaptive_mode.cpython-310.pyc +0 -0
- package/src/plugins/__pycache__/agents 2.cpython-310.pyc +0 -0
- package/src/plugins/__pycache__/agents.cpython-310.pyc +0 -0
- package/src/plugins/__pycache__/artifact_registry 2.cpython-310.pyc +0 -0
- package/src/plugins/__pycache__/artifact_registry.cpython-310.pyc +0 -0
- package/src/plugins/__pycache__/backup 2.cpython-310.pyc +0 -0
- package/src/plugins/__pycache__/backup.cpython-310.pyc +0 -0
- package/src/plugins/__pycache__/cognitive_memory 2.cpython-310.pyc +0 -0
- package/src/plugins/__pycache__/cognitive_memory.cpython-310.pyc +0 -0
- package/src/plugins/__pycache__/core_rules 2.cpython-310.pyc +0 -0
- package/src/plugins/__pycache__/core_rules.cpython-310.pyc +0 -0
- package/src/plugins/__pycache__/cortex 2.cpython-310.pyc +0 -0
- package/src/plugins/__pycache__/cortex.cpython-310.pyc +0 -0
- package/src/plugins/__pycache__/entities 2.cpython-310.pyc +0 -0
- package/src/plugins/__pycache__/entities.cpython-310.pyc +0 -0
- package/src/plugins/__pycache__/episodic_memory 2.cpython-310.pyc +0 -0
- package/src/plugins/__pycache__/episodic_memory.cpython-310.pyc +0 -0
- package/src/plugins/__pycache__/evolution 2.cpython-310.pyc +0 -0
- package/src/plugins/__pycache__/evolution.cpython-310.pyc +0 -0
- package/src/plugins/__pycache__/guard 2.cpython-310.pyc +0 -0
- package/src/plugins/__pycache__/guard.cpython-310.pyc +0 -0
- package/src/plugins/__pycache__/knowledge_graph_tools 2.cpython-310.pyc +0 -0
- package/src/plugins/__pycache__/knowledge_graph_tools.cpython-310.pyc +0 -0
- package/src/plugins/__pycache__/preferences 2.cpython-310.pyc +0 -0
- package/src/plugins/__pycache__/preferences.cpython-310.pyc +0 -0
- package/src/plugins/__pycache__/update 2.cpython-310.pyc +0 -0
- package/src/plugins/__pycache__/update.cpython-310.pyc +0 -0
- package/src/plugins/adaptive_mode 2.py +805 -0
- package/src/plugins/agents 2.py +52 -0
- package/src/plugins/artifact_registry 2.py +450 -0
- package/src/plugins/backup 2.py +104 -0
- package/src/plugins/cognitive_memory 2.py +564 -0
- package/src/plugins/core_rules 2.py +252 -0
- package/src/plugins/core_rules.py +34 -17
- package/src/plugins/cortex 2.py +299 -0
- package/src/plugins/entities 2.py +67 -0
- package/src/plugins/episodic_memory 2.py +533 -0
- package/src/plugins/evolution 2.py +115 -0
- package/src/plugins/guard 2.py +746 -0
- package/src/plugins/knowledge_graph_tools 2.py +105 -0
- package/src/plugins/preferences 2.py +47 -0
- package/src/plugins/update 2.py +256 -0
- package/src/plugins/update.py +18 -0
- package/src/requirements 2.txt +12 -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/scripts/check-context 2.py +264 -0
- package/src/scripts/check-context.py +4 -7
- package/src/scripts/deep-sleep/apply_findings.py +570 -167
- package/src/scripts/deep-sleep/collect.py +480 -0
- package/src/scripts/deep-sleep/extract-prompt.md +233 -0
- package/src/scripts/deep-sleep/extract.py +249 -0
- package/src/scripts/deep-sleep/synthesize-prompt.md +197 -0
- package/src/scripts/deep-sleep/synthesize.py +191 -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 +242 -0
- package/src/scripts/nexo-catchup.py +5 -8
- package/src/scripts/nexo-cognitive-decay 2.py +182 -0
- package/src/scripts/nexo-daily-self-audit 2.py +552 -0
- package/src/scripts/nexo-daily-self-audit.py +28 -19
- package/src/scripts/nexo-deep-sleep 2.sh +97 -0
- package/src/scripts/nexo-deep-sleep.sh +31 -16
- package/src/scripts/nexo-evolution-run 2.py +597 -0
- package/src/scripts/nexo-evolution-run.py +5 -20
- package/src/scripts/nexo-followup-hygiene 2.py +112 -0
- package/src/scripts/nexo-followup-hygiene.py +4 -2
- package/src/scripts/nexo-github-monitor 2.py +256 -0
- package/src/scripts/nexo-github-monitor.py +6 -9
- package/src/scripts/nexo-immune 2.py +927 -0
- package/src/scripts/nexo-immune.py +4 -17
- 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 +245 -0
- package/src/scripts/nexo-learning-validator 2.py +207 -0
- package/src/scripts/nexo-learning-validator.py +0 -29
- package/src/scripts/nexo-migrate 2.py +232 -0
- package/src/scripts/nexo-postmortem-consolidator 2.py +421 -0
- package/src/scripts/nexo-postmortem-consolidator.py +9 -20
- package/src/scripts/nexo-pre-commit 2.py +120 -0
- package/src/scripts/nexo-prevent-sleep 2.sh +29 -0
- package/src/scripts/nexo-proactive-dashboard 2.py +345 -0
- package/src/scripts/nexo-proactive-dashboard.py +1 -0
- package/src/scripts/nexo-reflection 2.py +253 -0
- package/src/scripts/nexo-runtime-preflight 2.py +274 -0
- package/src/scripts/nexo-send-email 2.py +25 -0
- package/src/scripts/nexo-send-reply 2.py +178 -0
- package/src/scripts/nexo-sleep 2.py +592 -0
- package/src/scripts/nexo-sleep.py +8 -18
- package/src/scripts/nexo-snapshot-restore 2.sh +35 -0
- package/src/scripts/nexo-synthesis 2.py +253 -0
- package/src/scripts/nexo-synthesis.py +8 -19
- package/src/scripts/nexo-tcc-approve 2.sh +79 -0
- package/src/scripts/nexo-update 2.sh +161 -0
- package/src/scripts/nexo-watchdog 2.sh +878 -0
- package/src/scripts/nexo-watchdog-smoke 2.py +119 -0
- package/src/server 2.py +733 -0
- package/src/server.py +6 -1
- package/src/storage_router 2.py +32 -0
- package/src/tools_coordination 2.py +102 -0
- package/src/tools_credentials 2.py +68 -0
- package/src/tools_learnings 2.py +220 -0
- package/src/tools_menu 2.py +227 -0
- package/src/tools_menu.py +1 -1
- package/src/tools_reminders 2.py +86 -0
- package/src/tools_reminders_crud 2.py +159 -0
- package/src/tools_reminders_crud.py +7 -0
- package/src/tools_sessions 2.py +476 -0
- package/src/tools_sessions.py +67 -0
- package/src/tools_task_history 2.py +57 -0
- package/templates/CLAUDE.md 2.template +63 -0
- package/templates/openclaw 2.json +13 -0
- package/tests/__init__ 2.py +0 -0
- package/tests/conftest 2.py +71 -0
- package/tests/test_cognitive 2.py +205 -0
- package/tests/test_knowledge_graph 2.py +140 -0
- package/tests/test_migrations 2.py +137 -0
- package/src/__pycache__/auto_close_sessions.cpython-310.pyc +0 -0
- package/src/__pycache__/auto_close_sessions.cpython-314.pyc +0 -0
- package/src/__pycache__/auto_update.cpython-314.pyc +0 -0
- package/src/__pycache__/claim_graph.cpython-310.pyc +0 -0
- package/src/__pycache__/claim_graph.cpython-314.pyc +0 -0
- package/src/__pycache__/evolution_cycle.cpython-310.pyc +0 -0
- package/src/__pycache__/evolution_cycle.cpython-314.pyc +0 -0
- package/src/__pycache__/hnsw_index.cpython-314.pyc +0 -0
- package/src/__pycache__/kg_populate.cpython-314.pyc +0 -0
- package/src/__pycache__/knowledge_graph.cpython-314.pyc +0 -0
- package/src/__pycache__/maintenance.cpython-310.pyc +0 -0
- package/src/__pycache__/maintenance.cpython-314.pyc +0 -0
- package/src/__pycache__/migrate_embeddings.cpython-310.pyc +0 -0
- package/src/__pycache__/migrate_embeddings.cpython-314.pyc +0 -0
- package/src/__pycache__/plugin_loader.cpython-314.pyc +0 -0
- package/src/__pycache__/server.cpython-310.pyc +0 -0
- package/src/__pycache__/server.cpython-314.pyc +0 -0
- package/src/__pycache__/storage_router.cpython-310.pyc +0 -0
- package/src/__pycache__/storage_router.cpython-314.pyc +0 -0
- package/src/__pycache__/tools_coordination.cpython-314.pyc +0 -0
- package/src/__pycache__/tools_credentials.cpython-314.pyc +0 -0
- package/src/__pycache__/tools_learnings.cpython-314.pyc +0 -0
- package/src/__pycache__/tools_menu.cpython-314.pyc +0 -0
- package/src/__pycache__/tools_reminders.cpython-314.pyc +0 -0
- package/src/__pycache__/tools_reminders_crud.cpython-314.pyc +0 -0
- package/src/__pycache__/tools_sessions.cpython-314.pyc +0 -0
- package/src/__pycache__/tools_task_history.cpython-314.pyc +0 -0
- package/src/cognitive/__pycache__/__init__.cpython-314.pyc +0 -0
- package/src/cognitive/__pycache__/_core.cpython-314.pyc +0 -0
- package/src/cognitive/__pycache__/_decay.cpython-314.pyc +0 -0
- package/src/cognitive/__pycache__/_ingest.cpython-314.pyc +0 -0
- package/src/cognitive/__pycache__/_memory.cpython-314.pyc +0 -0
- package/src/cognitive/__pycache__/_search.cpython-314.pyc +0 -0
- package/src/cognitive/__pycache__/_trust.cpython-314.pyc +0 -0
- package/src/dashboard/__pycache__/__init__.cpython-314.pyc +0 -0
- package/src/dashboard/__pycache__/app.cpython-314.pyc +0 -0
- package/src/hooks/__pycache__/auto_capture.cpython-310.pyc +0 -0
- package/src/hooks/__pycache__/auto_capture.cpython-314.pyc +0 -0
- package/src/plugins/__pycache__/__init__.cpython-314.pyc +0 -0
- package/src/plugins/__pycache__/adaptive_mode.cpython-314.pyc +0 -0
- package/src/plugins/__pycache__/agents.cpython-314.pyc +0 -0
- package/src/plugins/__pycache__/artifact_registry.cpython-314.pyc +0 -0
- package/src/plugins/__pycache__/backup.cpython-314.pyc +0 -0
- package/src/plugins/__pycache__/cognitive_memory.cpython-314.pyc +0 -0
- package/src/plugins/__pycache__/core_rules.cpython-314.pyc +0 -0
- package/src/plugins/__pycache__/cortex.cpython-314.pyc +0 -0
- package/src/plugins/__pycache__/entities.cpython-314.pyc +0 -0
- package/src/plugins/__pycache__/episodic_memory.cpython-314.pyc +0 -0
- package/src/plugins/__pycache__/evolution.cpython-314.pyc +0 -0
- package/src/plugins/__pycache__/guard.cpython-314.pyc +0 -0
- package/src/plugins/__pycache__/knowledge_graph_tools.cpython-314.pyc +0 -0
- package/src/plugins/__pycache__/preferences.cpython-314.pyc +0 -0
- package/src/rules/__pycache__/__init__.cpython-310.pyc +0 -0
- package/src/rules/__pycache__/__init__.cpython-314.pyc +0 -0
- package/src/rules/__pycache__/migrate.cpython-310.pyc +0 -0
- package/src/rules/__pycache__/migrate.cpython-314.pyc +0 -0
- package/src/scripts/__pycache__/check-context.cpython-310.pyc +0 -0
- package/src/scripts/__pycache__/check-context.cpython-314.pyc +0 -0
- package/src/scripts/__pycache__/nexo-auto-update.cpython-310.pyc +0 -0
- package/src/scripts/__pycache__/nexo-auto-update.cpython-314.pyc +0 -0
- package/src/scripts/__pycache__/nexo-catchup.cpython-310.pyc +0 -0
- package/src/scripts/__pycache__/nexo-catchup.cpython-314.pyc +0 -0
- package/src/scripts/__pycache__/nexo-cognitive-decay.cpython-310.pyc +0 -0
- package/src/scripts/__pycache__/nexo-cognitive-decay.cpython-314.pyc +0 -0
- package/src/scripts/__pycache__/nexo-daily-self-audit.cpython-310.pyc +0 -0
- package/src/scripts/__pycache__/nexo-daily-self-audit.cpython-314.pyc +0 -0
- package/src/scripts/__pycache__/nexo-evolution-run.cpython-310.pyc +0 -0
- package/src/scripts/__pycache__/nexo-evolution-run.cpython-314.pyc +0 -0
- package/src/scripts/__pycache__/nexo-followup-hygiene.cpython-310.pyc +0 -0
- package/src/scripts/__pycache__/nexo-followup-hygiene.cpython-314.pyc +0 -0
- package/src/scripts/__pycache__/nexo-github-monitor.cpython-310.pyc +0 -0
- package/src/scripts/__pycache__/nexo-github-monitor.cpython-314.pyc +0 -0
- package/src/scripts/__pycache__/nexo-immune.cpython-310.pyc +0 -0
- package/src/scripts/__pycache__/nexo-immune.cpython-314.pyc +0 -0
- package/src/scripts/__pycache__/nexo-install.cpython-310.pyc +0 -0
- package/src/scripts/__pycache__/nexo-install.cpython-314.pyc +0 -0
- package/src/scripts/__pycache__/nexo-learning-housekeep.cpython-310.pyc +0 -0
- package/src/scripts/__pycache__/nexo-learning-housekeep.cpython-314.pyc +0 -0
- package/src/scripts/__pycache__/nexo-learning-validator.cpython-310.pyc +0 -0
- package/src/scripts/__pycache__/nexo-learning-validator.cpython-314.pyc +0 -0
- package/src/scripts/__pycache__/nexo-migrate.cpython-310.pyc +0 -0
- package/src/scripts/__pycache__/nexo-migrate.cpython-314.pyc +0 -0
- package/src/scripts/__pycache__/nexo-postmortem-consolidator.cpython-310.pyc +0 -0
- package/src/scripts/__pycache__/nexo-postmortem-consolidator.cpython-314.pyc +0 -0
- package/src/scripts/__pycache__/nexo-pre-commit.cpython-310.pyc +0 -0
- package/src/scripts/__pycache__/nexo-pre-commit.cpython-314.pyc +0 -0
- package/src/scripts/__pycache__/nexo-proactive-dashboard.cpython-310.pyc +0 -0
- package/src/scripts/__pycache__/nexo-proactive-dashboard.cpython-314.pyc +0 -0
- package/src/scripts/__pycache__/nexo-reflection.cpython-310.pyc +0 -0
- package/src/scripts/__pycache__/nexo-reflection.cpython-314.pyc +0 -0
- package/src/scripts/__pycache__/nexo-runtime-preflight.cpython-310.pyc +0 -0
- package/src/scripts/__pycache__/nexo-runtime-preflight.cpython-314.pyc +0 -0
- package/src/scripts/__pycache__/nexo-send-email.cpython-310.pyc +0 -0
- package/src/scripts/__pycache__/nexo-send-email.cpython-314.pyc +0 -0
- package/src/scripts/__pycache__/nexo-send-reply.cpython-310.pyc +0 -0
- package/src/scripts/__pycache__/nexo-send-reply.cpython-314.pyc +0 -0
- package/src/scripts/__pycache__/nexo-sleep.cpython-310.pyc +0 -0
- package/src/scripts/__pycache__/nexo-sleep.cpython-314.pyc +0 -0
- package/src/scripts/__pycache__/nexo-synthesis.cpython-310.pyc +0 -0
- package/src/scripts/__pycache__/nexo-synthesis.cpython-314.pyc +0 -0
- package/src/scripts/__pycache__/nexo-watchdog-smoke.cpython-310.pyc +0 -0
- package/src/scripts/__pycache__/nexo-watchdog-smoke.cpython-314.pyc +0 -0
- package/src/scripts/deep-sleep/__pycache__/analyze_session.cpython-310.pyc +0 -0
- package/src/scripts/deep-sleep/__pycache__/analyze_session.cpython-314.pyc +0 -0
- package/src/scripts/deep-sleep/__pycache__/apply_findings.cpython-310.pyc +0 -0
- package/src/scripts/deep-sleep/__pycache__/apply_findings.cpython-314.pyc +0 -0
- package/src/scripts/deep-sleep/__pycache__/collect_transcripts.cpython-310.pyc +0 -0
- package/src/scripts/deep-sleep/__pycache__/collect_transcripts.cpython-314.pyc +0 -0
- package/src/scripts/deep-sleep/analyze_session.py +0 -217
- package/src/scripts/deep-sleep/collect_transcripts.py +0 -145
- package/src/scripts/deep-sleep/prompt.md +0 -109
- package/tests/__pycache__/__init__.cpython-310.pyc +0 -0
- package/tests/__pycache__/__init__.cpython-314.pyc +0 -0
- package/tests/__pycache__/conftest.cpython-310-pytest-9.0.2.pyc +0 -0
- package/tests/__pycache__/conftest.cpython-310.pyc +0 -0
- package/tests/__pycache__/conftest.cpython-314-pytest-9.0.2.pyc +0 -0
- package/tests/__pycache__/test_cognitive.cpython-310-pytest-9.0.2.pyc +0 -0
- package/tests/__pycache__/test_cognitive.cpython-310.pyc +0 -0
- package/tests/__pycache__/test_cognitive.cpython-314-pytest-9.0.2.pyc +0 -0
- package/tests/__pycache__/test_knowledge_graph.cpython-310-pytest-9.0.2.pyc +0 -0
- package/tests/__pycache__/test_knowledge_graph.cpython-310.pyc +0 -0
- package/tests/__pycache__/test_knowledge_graph.cpython-314-pytest-9.0.2.pyc +0 -0
- package/tests/__pycache__/test_migrations.cpython-310-pytest-9.0.2.pyc +0 -0
- package/tests/__pycache__/test_migrations.cpython-310.pyc +0 -0
- package/tests/__pycache__/test_migrations.cpython-314-pytest-9.0.2.pyc +0 -0
|
@@ -0,0 +1,480 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Deep Sleep v2 -- Phase 1: Collect all context for overnight analysis.
|
|
4
|
+
|
|
5
|
+
Gathers transcripts, DB data, logs, and discovered files into a single
|
|
6
|
+
plain-text context file that subsequent phases read via Claude's Read tool.
|
|
7
|
+
|
|
8
|
+
Environment variables:
|
|
9
|
+
NEXO_HOME -- root of the NEXO installation (default: ~/.nexo)
|
|
10
|
+
NEXO_CODE -- path to the NEXO source repo (optional, for self-analysis)
|
|
11
|
+
"""
|
|
12
|
+
import json
|
|
13
|
+
import os
|
|
14
|
+
import sqlite3
|
|
15
|
+
import sys
|
|
16
|
+
from datetime import datetime, timedelta
|
|
17
|
+
from pathlib import Path
|
|
18
|
+
|
|
19
|
+
NEXO_HOME = Path(os.environ.get("NEXO_HOME", str(Path.home() / ".nexo")))
|
|
20
|
+
NEXO_CODE = Path(os.environ.get("NEXO_CODE", ""))
|
|
21
|
+
DEEP_SLEEP_DIR = NEXO_HOME / "operations" / "deep-sleep"
|
|
22
|
+
NEXO_DB = NEXO_HOME / "data" / "nexo.db"
|
|
23
|
+
COGNITIVE_DB = NEXO_HOME / "data" / "cognitive.db"
|
|
24
|
+
|
|
25
|
+
MIN_USER_MESSAGES = 3 # Skip trivial sessions
|
|
26
|
+
|
|
27
|
+
# ── Transcript collection (kept from collect_transcripts.py) ──────────────
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def find_session_dirs() -> list[Path]:
|
|
31
|
+
"""Find all Claude Code project directories that contain .jsonl files."""
|
|
32
|
+
claude_dir = Path.home() / ".claude" / "projects"
|
|
33
|
+
if not claude_dir.exists():
|
|
34
|
+
return []
|
|
35
|
+
dirs = set()
|
|
36
|
+
for jsonl in claude_dir.rglob("*.jsonl"):
|
|
37
|
+
dirs.add(jsonl.parent)
|
|
38
|
+
return list(dirs)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def extract_session(jsonl_path: Path) -> dict | None:
|
|
42
|
+
"""Extract clean transcript from a session JSONL file."""
|
|
43
|
+
messages = []
|
|
44
|
+
tool_uses = []
|
|
45
|
+
user_msg_count = 0
|
|
46
|
+
|
|
47
|
+
try:
|
|
48
|
+
with open(jsonl_path, "r") as f:
|
|
49
|
+
for line_no, line in enumerate(f, 1):
|
|
50
|
+
line = line.strip()
|
|
51
|
+
if not line:
|
|
52
|
+
continue
|
|
53
|
+
try:
|
|
54
|
+
d = json.loads(line)
|
|
55
|
+
except json.JSONDecodeError:
|
|
56
|
+
continue
|
|
57
|
+
|
|
58
|
+
msg_type = d.get("type")
|
|
59
|
+
|
|
60
|
+
# User messages
|
|
61
|
+
if msg_type == "user":
|
|
62
|
+
content = d.get("message", {}).get("content", "")
|
|
63
|
+
if isinstance(content, str) and content.strip():
|
|
64
|
+
if content.startswith("<system-reminder>"):
|
|
65
|
+
continue
|
|
66
|
+
messages.append({
|
|
67
|
+
"role": "user",
|
|
68
|
+
"index": line_no,
|
|
69
|
+
"text": content[:5000],
|
|
70
|
+
"uuid": d.get("uuid", "")
|
|
71
|
+
})
|
|
72
|
+
user_msg_count += 1
|
|
73
|
+
|
|
74
|
+
# Assistant messages
|
|
75
|
+
elif msg_type in ("message", "assistant"):
|
|
76
|
+
msg = d.get("message", {})
|
|
77
|
+
content_blocks = msg.get("content", [])
|
|
78
|
+
text_parts = []
|
|
79
|
+
for block in content_blocks:
|
|
80
|
+
if isinstance(block, dict):
|
|
81
|
+
if block.get("type") == "text":
|
|
82
|
+
text_parts.append(block.get("text", ""))
|
|
83
|
+
elif block.get("type") == "tool_use":
|
|
84
|
+
tool_input = block.get("input", {})
|
|
85
|
+
tool_uses.append({
|
|
86
|
+
"tool": block.get("name", ""),
|
|
87
|
+
"input_keys": list(tool_input.keys()) if isinstance(tool_input, dict) else [],
|
|
88
|
+
"file": (
|
|
89
|
+
tool_input.get("file_path", "")
|
|
90
|
+
or str(tool_input.get("command", ""))[:100]
|
|
91
|
+
) if isinstance(tool_input, dict) else ""
|
|
92
|
+
})
|
|
93
|
+
if text_parts:
|
|
94
|
+
combined = "\n".join(text_parts)[:5000]
|
|
95
|
+
messages.append({
|
|
96
|
+
"role": "assistant",
|
|
97
|
+
"index": line_no,
|
|
98
|
+
"text": combined
|
|
99
|
+
})
|
|
100
|
+
|
|
101
|
+
except Exception as e:
|
|
102
|
+
print(f" [collect] Error reading {jsonl_path}: {e}", file=sys.stderr)
|
|
103
|
+
return None
|
|
104
|
+
|
|
105
|
+
if user_msg_count < MIN_USER_MESSAGES:
|
|
106
|
+
return None
|
|
107
|
+
|
|
108
|
+
return {
|
|
109
|
+
"session_file": jsonl_path.name,
|
|
110
|
+
"session_path": str(jsonl_path),
|
|
111
|
+
"message_count": len(messages),
|
|
112
|
+
"user_message_count": user_msg_count,
|
|
113
|
+
"tool_use_count": len(tool_uses),
|
|
114
|
+
"messages": messages,
|
|
115
|
+
"tool_uses": tool_uses
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def collect_transcripts(target_date: str) -> list[dict]:
|
|
120
|
+
"""Collect all sessions modified on the target date."""
|
|
121
|
+
sessions = []
|
|
122
|
+
for sdir in find_session_dirs():
|
|
123
|
+
for f in sdir.glob("*.jsonl"):
|
|
124
|
+
try:
|
|
125
|
+
mtime = datetime.fromtimestamp(f.stat().st_mtime)
|
|
126
|
+
except OSError:
|
|
127
|
+
continue
|
|
128
|
+
if mtime.strftime("%Y-%m-%d") == target_date:
|
|
129
|
+
session = extract_session(f)
|
|
130
|
+
if session:
|
|
131
|
+
session["modified"] = mtime.isoformat()
|
|
132
|
+
sessions.append(session)
|
|
133
|
+
sessions.sort(key=lambda s: s["modified"])
|
|
134
|
+
return sessions
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
# ── Database queries ──────────────────────────────────────────────────────
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
def safe_query(db_path: Path, query: str, params: tuple = ()) -> list[dict]:
|
|
141
|
+
"""Run a query and return rows as dicts. Returns [] on any error."""
|
|
142
|
+
if not db_path.exists():
|
|
143
|
+
return []
|
|
144
|
+
try:
|
|
145
|
+
conn = sqlite3.connect(str(db_path))
|
|
146
|
+
conn.row_factory = sqlite3.Row
|
|
147
|
+
rows = conn.execute(query, params).fetchall()
|
|
148
|
+
result = [dict(r) for r in rows]
|
|
149
|
+
conn.close()
|
|
150
|
+
return result
|
|
151
|
+
except Exception as e:
|
|
152
|
+
print(f" [collect] DB query error ({db_path.name}): {e}", file=sys.stderr)
|
|
153
|
+
return []
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
def collect_followups() -> list[dict]:
|
|
157
|
+
"""Active followups from nexo.db."""
|
|
158
|
+
return safe_query(
|
|
159
|
+
NEXO_DB,
|
|
160
|
+
"SELECT * FROM followups WHERE status NOT IN ('COMPLETED', 'CANCELLED') ORDER BY date ASC"
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
def collect_learnings() -> list[dict]:
|
|
165
|
+
"""Active learnings from nexo.db."""
|
|
166
|
+
return safe_query(NEXO_DB, "SELECT * FROM learnings ORDER BY updated_at DESC LIMIT 200")
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
def collect_diaries(target_date: str) -> list[dict]:
|
|
170
|
+
"""Today's session diaries."""
|
|
171
|
+
# Diaries store created_at as unix timestamp or ISO string -- handle both
|
|
172
|
+
start_ts = datetime.strptime(target_date, "%Y-%m-%d").timestamp()
|
|
173
|
+
end_ts = start_ts + 86400
|
|
174
|
+
rows = safe_query(
|
|
175
|
+
NEXO_DB,
|
|
176
|
+
"SELECT * FROM session_diary WHERE created_at >= ? AND created_at < ? ORDER BY created_at ASC",
|
|
177
|
+
(start_ts, end_ts)
|
|
178
|
+
)
|
|
179
|
+
if not rows:
|
|
180
|
+
# Try ISO format
|
|
181
|
+
rows = safe_query(
|
|
182
|
+
NEXO_DB,
|
|
183
|
+
"SELECT * FROM session_diary WHERE created_at >= ? AND created_at < ? ORDER BY created_at ASC",
|
|
184
|
+
(target_date + "T00:00:00", target_date + "T23:59:59")
|
|
185
|
+
)
|
|
186
|
+
return rows
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
def collect_trust_score() -> list[dict]:
|
|
190
|
+
"""Current trust score and 7-day history from cognitive.db."""
|
|
191
|
+
return safe_query(
|
|
192
|
+
COGNITIVE_DB,
|
|
193
|
+
"SELECT * FROM trust_score ORDER BY rowid DESC LIMIT 1"
|
|
194
|
+
)
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
# ── Discovery: scan NEXO_HOME for non-core content ───────────────────────
|
|
198
|
+
|
|
199
|
+
CORE_DIRS = {"data", "operations", "logs", "coordination", "brain"}
|
|
200
|
+
CORE_FILES = {"config.json", "nexo.db", "cognitive.db"}
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
def discover_extras() -> list[dict]:
|
|
204
|
+
"""Scan NEXO_HOME for non-core directories and files."""
|
|
205
|
+
extras = []
|
|
206
|
+
if not NEXO_HOME.exists():
|
|
207
|
+
return extras
|
|
208
|
+
|
|
209
|
+
for item in sorted(NEXO_HOME.iterdir()):
|
|
210
|
+
name = item.name
|
|
211
|
+
if name.startswith("."):
|
|
212
|
+
continue
|
|
213
|
+
if name in CORE_DIRS or name in CORE_FILES:
|
|
214
|
+
continue
|
|
215
|
+
|
|
216
|
+
entry = {"name": name, "path": str(item), "type": "dir" if item.is_dir() else "file"}
|
|
217
|
+
|
|
218
|
+
if item.is_dir():
|
|
219
|
+
# Count contents and list interesting files
|
|
220
|
+
files = list(item.rglob("*"))
|
|
221
|
+
entry["file_count"] = len([f for f in files if f.is_file()])
|
|
222
|
+
entry["notable_files"] = [
|
|
223
|
+
str(f.relative_to(item))
|
|
224
|
+
for f in files
|
|
225
|
+
if f.is_file() and f.suffix in (".py", ".sh", ".json", ".db", ".log", ".sqlite")
|
|
226
|
+
][:20]
|
|
227
|
+
elif item.is_file():
|
|
228
|
+
entry["size"] = item.stat().st_size
|
|
229
|
+
|
|
230
|
+
extras.append(entry)
|
|
231
|
+
|
|
232
|
+
return extras
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
# ── LaunchAgent logs ──────────────────────────────────────────────────────
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
def collect_error_logs(target_date: str) -> list[dict]:
|
|
239
|
+
"""Scan NEXO_HOME/logs/ for lines containing errors from today."""
|
|
240
|
+
log_dir = NEXO_HOME / "logs"
|
|
241
|
+
if not log_dir.exists():
|
|
242
|
+
return []
|
|
243
|
+
|
|
244
|
+
errors = []
|
|
245
|
+
for log_file in sorted(log_dir.glob("*.log")):
|
|
246
|
+
try:
|
|
247
|
+
lines = log_file.read_text(errors="replace").splitlines()
|
|
248
|
+
except Exception:
|
|
249
|
+
continue
|
|
250
|
+
|
|
251
|
+
file_errors = []
|
|
252
|
+
for i, line in enumerate(lines):
|
|
253
|
+
# Match lines from today that contain error indicators
|
|
254
|
+
if target_date in line and any(
|
|
255
|
+
kw in line.lower() for kw in ("error", "exception", "traceback", "failed", "fatal", "critical")
|
|
256
|
+
):
|
|
257
|
+
# Include surrounding context (1 line before, 2 after)
|
|
258
|
+
start = max(0, i - 1)
|
|
259
|
+
end = min(len(lines), i + 3)
|
|
260
|
+
file_errors.append({
|
|
261
|
+
"line": i + 1,
|
|
262
|
+
"context": "\n".join(lines[start:end])
|
|
263
|
+
})
|
|
264
|
+
|
|
265
|
+
if file_errors:
|
|
266
|
+
errors.append({
|
|
267
|
+
"file": log_file.name,
|
|
268
|
+
"path": str(log_file),
|
|
269
|
+
"errors": file_errors[:50] # Cap per file
|
|
270
|
+
})
|
|
271
|
+
|
|
272
|
+
return errors
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
# ── Format output as plain text ───────────────────────────────────────────
|
|
276
|
+
|
|
277
|
+
|
|
278
|
+
def format_section(title: str, data, indent: int = 0) -> str:
|
|
279
|
+
"""Format a data section as readable plain text."""
|
|
280
|
+
prefix = " " * indent
|
|
281
|
+
lines = [f"\n{'=' * 70}", f"{title}", f"{'=' * 70}"]
|
|
282
|
+
|
|
283
|
+
if isinstance(data, list):
|
|
284
|
+
if not data:
|
|
285
|
+
lines.append(f"{prefix}(none)")
|
|
286
|
+
else:
|
|
287
|
+
for i, item in enumerate(data):
|
|
288
|
+
lines.append(f"\n{prefix}--- [{i + 1}] ---")
|
|
289
|
+
if isinstance(item, dict):
|
|
290
|
+
for k, v in item.items():
|
|
291
|
+
val_str = str(v)
|
|
292
|
+
if len(val_str) > 500:
|
|
293
|
+
val_str = val_str[:500] + "..."
|
|
294
|
+
lines.append(f"{prefix} {k}: {val_str}")
|
|
295
|
+
else:
|
|
296
|
+
lines.append(f"{prefix} {item}")
|
|
297
|
+
elif isinstance(data, dict):
|
|
298
|
+
for k, v in data.items():
|
|
299
|
+
val_str = str(v)
|
|
300
|
+
if len(val_str) > 500:
|
|
301
|
+
val_str = val_str[:500] + "..."
|
|
302
|
+
lines.append(f"{prefix}{k}: {val_str}")
|
|
303
|
+
elif isinstance(data, str):
|
|
304
|
+
lines.append(data)
|
|
305
|
+
else:
|
|
306
|
+
lines.append(str(data))
|
|
307
|
+
|
|
308
|
+
return "\n".join(lines)
|
|
309
|
+
|
|
310
|
+
|
|
311
|
+
def format_transcripts(sessions: list[dict]) -> str:
|
|
312
|
+
"""Format transcripts in a readable way for Claude to analyze."""
|
|
313
|
+
lines = [f"\n{'=' * 70}", "SESSION TRANSCRIPTS", f"{'=' * 70}"]
|
|
314
|
+
lines.append(f"Total sessions: {len(sessions)}")
|
|
315
|
+
|
|
316
|
+
for i, session in enumerate(sessions):
|
|
317
|
+
lines.append(f"\n{'─' * 60}")
|
|
318
|
+
lines.append(f"SESSION {i + 1}: {session['session_file']}")
|
|
319
|
+
lines.append(f"Modified: {session['modified']}")
|
|
320
|
+
lines.append(f"Messages: {session['message_count']}, Tool uses: {session['tool_use_count']}")
|
|
321
|
+
lines.append(f"{'─' * 60}")
|
|
322
|
+
|
|
323
|
+
for msg in session["messages"]:
|
|
324
|
+
role = "USER" if msg["role"] == "user" else "AGENT"
|
|
325
|
+
idx = msg.get("index", "?")
|
|
326
|
+
lines.append(f"\n[{role} @{idx}]")
|
|
327
|
+
lines.append(msg["text"])
|
|
328
|
+
|
|
329
|
+
if session["tool_uses"]:
|
|
330
|
+
lines.append(f"\n -- Tool usage log --")
|
|
331
|
+
for tu in session["tool_uses"]:
|
|
332
|
+
file_info = f" [{tu['file'][:80]}]" if tu.get("file") else ""
|
|
333
|
+
lines.append(f" - {tu['tool']}{file_info}")
|
|
334
|
+
|
|
335
|
+
return "\n".join(lines)
|
|
336
|
+
|
|
337
|
+
|
|
338
|
+
# ── Main ──────────────────────────────────────────────────────────────────
|
|
339
|
+
|
|
340
|
+
|
|
341
|
+
def main():
|
|
342
|
+
target_date = sys.argv[1] if len(sys.argv) > 1 else datetime.now().strftime("%Y-%m-%d")
|
|
343
|
+
DEEP_SLEEP_DIR.mkdir(parents=True, exist_ok=True)
|
|
344
|
+
|
|
345
|
+
print(f"[collect] Phase 1: Collecting context for {target_date}")
|
|
346
|
+
|
|
347
|
+
# 1. Transcripts
|
|
348
|
+
print("[collect] Gathering transcripts...")
|
|
349
|
+
sessions = collect_transcripts(target_date)
|
|
350
|
+
print(f" Found {len(sessions)} sessions")
|
|
351
|
+
|
|
352
|
+
if not sessions:
|
|
353
|
+
print(f"[collect] No sessions found for {target_date}. Writing minimal context file.")
|
|
354
|
+
output_file = DEEP_SLEEP_DIR / f"{target_date}-context.txt"
|
|
355
|
+
output_file.write_text(
|
|
356
|
+
f"Deep Sleep Context for {target_date}\n\nNo sessions found for this date.\n"
|
|
357
|
+
)
|
|
358
|
+
print(f"[collect] Output: {output_file}")
|
|
359
|
+
return
|
|
360
|
+
|
|
361
|
+
# 2. Core DB data
|
|
362
|
+
print("[collect] Querying databases...")
|
|
363
|
+
followups = collect_followups()
|
|
364
|
+
print(f" Active followups: {len(followups)}")
|
|
365
|
+
|
|
366
|
+
learnings = collect_learnings()
|
|
367
|
+
print(f" Learnings: {len(learnings)}")
|
|
368
|
+
|
|
369
|
+
diaries = collect_diaries(target_date)
|
|
370
|
+
print(f" Diaries today: {len(diaries)}")
|
|
371
|
+
|
|
372
|
+
trust_history = collect_trust_score()
|
|
373
|
+
print(f" Trust events (7d): {len(trust_history)}")
|
|
374
|
+
|
|
375
|
+
# 3. Discovery
|
|
376
|
+
print("[collect] Scanning for non-core content...")
|
|
377
|
+
extras = discover_extras()
|
|
378
|
+
print(f" Discovered {len(extras)} extra items")
|
|
379
|
+
|
|
380
|
+
# 4. Error logs
|
|
381
|
+
print("[collect] Checking error logs...")
|
|
382
|
+
error_logs = collect_error_logs(target_date)
|
|
383
|
+
print(f" Log files with errors: {len(error_logs)}")
|
|
384
|
+
|
|
385
|
+
# 5. Build per-session files + shared context
|
|
386
|
+
date_dir = DEEP_SLEEP_DIR / target_date
|
|
387
|
+
date_dir.mkdir(parents=True, exist_ok=True)
|
|
388
|
+
print(f"[collect] Writing session files to {date_dir}/")
|
|
389
|
+
|
|
390
|
+
# Shared context (followups, learnings, diaries, etc.) — one file
|
|
391
|
+
shared_parts = [
|
|
392
|
+
f"Deep Sleep Shared Context -- {target_date}",
|
|
393
|
+
f"Generated at: {datetime.now().isoformat()}",
|
|
394
|
+
f"NEXO_HOME: {NEXO_HOME}",
|
|
395
|
+
f"Sessions: {len(sessions)}",
|
|
396
|
+
]
|
|
397
|
+
shared_parts.append(format_section("ACTIVE FOLLOWUPS", followups))
|
|
398
|
+
shared_parts.append(format_section("LEARNINGS (recent 200)", learnings))
|
|
399
|
+
shared_parts.append(format_section("SESSION DIARIES TODAY", diaries))
|
|
400
|
+
shared_parts.append(format_section("TRUST SCORE HISTORY (7d)", trust_history))
|
|
401
|
+
shared_parts.append(format_section("DISCOVERED NON-CORE CONTENT", extras))
|
|
402
|
+
shared_parts.append(format_section("ERROR LOGS", error_logs))
|
|
403
|
+
|
|
404
|
+
shared_text = "\n".join(shared_parts)
|
|
405
|
+
shared_file = date_dir / "shared-context.txt"
|
|
406
|
+
shared_file.write_text(shared_text, encoding="utf-8")
|
|
407
|
+
print(f" Shared context: {len(shared_text) / 1024:.0f} KB")
|
|
408
|
+
|
|
409
|
+
# Individual session files
|
|
410
|
+
session_files_written = []
|
|
411
|
+
total_size = len(shared_text.encode("utf-8"))
|
|
412
|
+
for i, session in enumerate(sessions):
|
|
413
|
+
sid_short = session["session_file"].replace(".jsonl", "")[:20]
|
|
414
|
+
filename = f"session-{i+1:02d}-{sid_short}.txt"
|
|
415
|
+
session_path = date_dir / filename
|
|
416
|
+
|
|
417
|
+
lines = [
|
|
418
|
+
f"Session: {session['session_file']}",
|
|
419
|
+
f"Modified: {session['modified']}",
|
|
420
|
+
f"Messages: {session['message_count']}, Tool uses: {session['tool_use_count']}",
|
|
421
|
+
f"{'─' * 60}",
|
|
422
|
+
]
|
|
423
|
+
for msg in session["messages"]:
|
|
424
|
+
role = "USER" if msg["role"] == "user" else "AGENT"
|
|
425
|
+
idx = msg.get("index", "?")
|
|
426
|
+
lines.append(f"\n[{role} @{idx}]")
|
|
427
|
+
lines.append(msg["text"])
|
|
428
|
+
|
|
429
|
+
if session["tool_uses"]:
|
|
430
|
+
lines.append(f"\n -- Tool usage log --")
|
|
431
|
+
for tu in session["tool_uses"]:
|
|
432
|
+
file_info = f" [{tu['file'][:80]}]" if tu.get("file") else ""
|
|
433
|
+
lines.append(f" - {tu['tool']}{file_info}")
|
|
434
|
+
|
|
435
|
+
session_text = "\n".join(lines)
|
|
436
|
+
session_path.write_text(session_text, encoding="utf-8")
|
|
437
|
+
session_files_written.append(filename)
|
|
438
|
+
total_size += len(session_text.encode("utf-8"))
|
|
439
|
+
print(f" {filename}: {len(session_text) / 1024:.0f} KB")
|
|
440
|
+
|
|
441
|
+
# Also keep legacy single context file for backwards compat
|
|
442
|
+
legacy_parts = [
|
|
443
|
+
f"Deep Sleep Context -- {target_date}",
|
|
444
|
+
f"Generated at: {datetime.now().isoformat()}",
|
|
445
|
+
f"NEXO_HOME: {NEXO_HOME}",
|
|
446
|
+
f"Sessions: {len(sessions)}",
|
|
447
|
+
]
|
|
448
|
+
legacy_parts.append(format_transcripts(sessions))
|
|
449
|
+
legacy_parts.append(shared_text)
|
|
450
|
+
legacy_file = DEEP_SLEEP_DIR / f"{target_date}-context.txt"
|
|
451
|
+
legacy_file.write_text("\n".join(legacy_parts), encoding="utf-8")
|
|
452
|
+
|
|
453
|
+
# Metadata JSON
|
|
454
|
+
meta = {
|
|
455
|
+
"date": target_date,
|
|
456
|
+
"sessions_found": len(sessions),
|
|
457
|
+
"session_files": [s["session_file"] for s in sessions],
|
|
458
|
+
"session_txt_files": session_files_written,
|
|
459
|
+
"total_messages": sum(s["message_count"] for s in sessions),
|
|
460
|
+
"total_tool_uses": sum(s["tool_use_count"] for s in sessions),
|
|
461
|
+
"followups_active": len(followups),
|
|
462
|
+
"learnings_count": len(learnings),
|
|
463
|
+
"diaries_today": len(diaries),
|
|
464
|
+
"error_log_files": len(error_logs),
|
|
465
|
+
"date_dir": str(date_dir),
|
|
466
|
+
"shared_context_file": str(shared_file),
|
|
467
|
+
"context_file": str(legacy_file),
|
|
468
|
+
"total_size_bytes": total_size,
|
|
469
|
+
}
|
|
470
|
+
meta_file = DEEP_SLEEP_DIR / f"{target_date}-meta.json"
|
|
471
|
+
with open(meta_file, "w") as f:
|
|
472
|
+
json.dump(meta, f, indent=2, ensure_ascii=False)
|
|
473
|
+
|
|
474
|
+
print(f"\n[collect] Done. {len(session_files_written)} session files + shared context ({total_size / 1024:.0f} KB total)")
|
|
475
|
+
print(f"[collect] Dir: {date_dir}")
|
|
476
|
+
print(f"[collect] Meta: {meta_file}")
|
|
477
|
+
|
|
478
|
+
|
|
479
|
+
if __name__ == "__main__":
|
|
480
|
+
main()
|