nexo-brain 5.3.26 → 5.3.27

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.
Files changed (211) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/package.json +1 -1
  3. package/src/server.py +3 -0
  4. package/src/tools_sessions.py +6 -1
  5. package/src/dashboard/static/favicon 2.svg +0 -32
  6. package/src/dashboard/static/nexo-logo 2.png +0 -0
  7. package/src/dashboard/static/nexo-logo 2.svg +0 -40
  8. package/src/dashboard/static/style 2.css +0 -2458
  9. package/src/dashboard/templates/adaptive 2.html +0 -118
  10. package/src/dashboard/templates/artifacts 2.html +0 -133
  11. package/src/dashboard/templates/backups 2.html +0 -136
  12. package/src/dashboard/templates/base 2.html +0 -417
  13. package/src/dashboard/templates/calendar 2.html +0 -591
  14. package/src/dashboard/templates/chat 2.html +0 -356
  15. package/src/dashboard/templates/claims 2.html +0 -259
  16. package/src/dashboard/templates/cortex 2.html +0 -321
  17. package/src/dashboard/templates/credentials 2.html +0 -128
  18. package/src/dashboard/templates/crons 2.html +0 -370
  19. package/src/dashboard/templates/dashboard 2.html +0 -494
  20. package/src/dashboard/templates/dreams 2.html +0 -252
  21. package/src/dashboard/templates/email 2.html +0 -160
  22. package/src/dashboard/templates/evolution 2.html +0 -189
  23. package/src/dashboard/templates/feed 2.html +0 -249
  24. package/src/dashboard/templates/followup_health 2.html +0 -170
  25. package/src/dashboard/templates/graph 2.html +0 -201
  26. package/src/dashboard/templates/guard 2.html +0 -259
  27. package/src/dashboard/templates/inbox 2.html +0 -251
  28. package/src/dashboard/templates/memory 2.html +0 -420
  29. package/src/dashboard/templates/operations 2.html +0 -608
  30. package/src/dashboard/templates/plugins 2.html +0 -185
  31. package/src/dashboard/templates/protocol 2.html +0 -199
  32. package/src/dashboard/templates/rules 2.html +0 -246
  33. package/src/dashboard/templates/sentiment 2.html +0 -247
  34. package/src/dashboard/templates/sessions 2.html +0 -218
  35. package/src/dashboard/templates/skills 2.html +0 -329
  36. package/src/dashboard/templates/somatic 2.html +0 -73
  37. package/src/dashboard/templates/triggers 2.html +0 -133
  38. package/src/dashboard/templates/trust 2.html +0 -360
  39. package/src/db/__init__ 2.py +0 -259
  40. package/src/db/_core 2.py +0 -437
  41. package/src/db/_credentials 2.py +0 -124
  42. package/src/db/_episodic 2.py +0 -762
  43. package/src/db/_evolution 2.py +0 -54
  44. package/src/db/_fts 2.py +0 -406
  45. package/src/db/_goal_profiles 2.py +0 -376
  46. package/src/db/_hot_context 2.py +0 -660
  47. package/src/db/_outcomes 2.py +0 -800
  48. package/src/db/_personal_scripts 2.py +0 -582
  49. package/src/db/_sessions 2.py +0 -330
  50. package/src/db/_tasks 2.py +0 -91
  51. package/src/db/_watchers 2.py +0 -173
  52. package/src/doctor/formatters 2.py +0 -52
  53. package/src/doctor/models 2.py +0 -69
  54. package/src/doctor/planes 2.py +0 -87
  55. package/src/doctor/providers/__init__ 2.py +0 -1
  56. package/src/doctor/providers/deep 2.py +0 -367
  57. package/src/evolution_cycle 2.py +0 -519
  58. package/src/hooks/auto_capture 2.py +0 -208
  59. package/src/hooks/caffeinate-guard 2.sh +0 -8
  60. package/src/hooks/capture-session 2.sh +0 -21
  61. package/src/hooks/capture-tool-logs 2.sh +0 -158
  62. package/src/hooks/daily-briefing-check 2.sh +0 -33
  63. package/src/hooks/heartbeat-enforcement 2.py +0 -90
  64. package/src/hooks/heartbeat-posttool 2.sh +0 -18
  65. package/src/hooks/inbox-hook 2.sh +0 -76
  66. package/src/hooks/post-compact 2.sh +0 -152
  67. package/src/hooks/pre-compact 2.sh +0 -169
  68. package/src/hooks/protocol-guardrail 2.sh +0 -10
  69. package/src/hooks/protocol-pretool-guardrail 2.sh +0 -9
  70. package/src/hooks/session-stop 2.sh +0 -52
  71. package/src/kg_populate 2.py +0 -292
  72. package/src/maintenance 2.py +0 -53
  73. package/src/memory_backends 2.py +0 -71
  74. package/src/migrate_embeddings 2.py +0 -124
  75. package/src/nexo_sdk 2.py +0 -103
  76. package/src/observability 2.py +0 -199
  77. package/src/plugin_loader 2.py +0 -217
  78. package/src/plugins/__init__ 2.py +0 -0
  79. package/src/plugins/artifact_registry 2.py +0 -450
  80. package/src/plugins/backup 2.py +0 -127
  81. package/src/plugins/claims_tools 2.py +0 -119
  82. package/src/plugins/cognitive_memory 2.py +0 -609
  83. package/src/plugins/core_rules 2.py +0 -252
  84. package/src/plugins/cortex 2.py +0 -1155
  85. package/src/plugins/entities 2.py +0 -67
  86. package/src/plugins/episodic_memory 2.py +0 -560
  87. package/src/plugins/evolution 2.py +0 -167
  88. package/src/plugins/goal_engine 2.py +0 -142
  89. package/src/plugins/guard 2.py +0 -862
  90. package/src/plugins/impact 2.py +0 -29
  91. package/src/plugins/knowledge_graph_tools 2.py +0 -137
  92. package/src/plugins/media_memory_tools 2.py +0 -98
  93. package/src/plugins/memory_export 2.py +0 -196
  94. package/src/plugins/outcomes 2.py +0 -130
  95. package/src/plugins/personal_scripts 2.py +0 -117
  96. package/src/plugins/preferences 2.py +0 -47
  97. package/src/plugins/protocol 2.py +0 -1449
  98. package/src/plugins/simple_api 2.py +0 -106
  99. package/src/plugins/skills 2.py +0 -341
  100. package/src/plugins/state_watchers 2.py +0 -79
  101. package/src/plugins/update 2.py +0 -986
  102. package/src/plugins/user_state_tools 2.py +0 -43
  103. package/src/plugins/workflow 2.py +0 -588
  104. package/src/protocol_settings 2.py +0 -59
  105. package/src/public_contribution 2.py +0 -466
  106. package/src/public_evolution_queue 2.py +0 -241
  107. package/src/requirements 2.txt +0 -14
  108. package/src/retroactive_learnings 2.py +0 -373
  109. package/src/rules/__init__ 2.py +0 -0
  110. package/src/rules/core-rules 2.json +0 -331
  111. package/src/rules/migrate 2.py +0 -207
  112. package/src/runtime_power 2.py +0 -874
  113. package/src/script_registry 2.py +0 -1559
  114. package/src/scripts/check-context 2.py +0 -272
  115. package/src/scripts/deep-sleep/apply_findings 2.py +0 -2327
  116. package/src/scripts/deep-sleep/collect 2.py +0 -928
  117. package/src/scripts/deep-sleep/extract 2.py +0 -330
  118. package/src/scripts/deep-sleep/extract-prompt 2.md +0 -285
  119. package/src/scripts/deep-sleep/synthesize 2.py +0 -312
  120. package/src/scripts/deep-sleep/synthesize-prompt 2.md +0 -336
  121. package/src/scripts/nexo-agent-run 2.py +0 -75
  122. package/src/scripts/nexo-auto-update 2.py +0 -6
  123. package/src/scripts/nexo-backup 2.sh +0 -25
  124. package/src/scripts/nexo-brain-activation 2.sh +0 -140
  125. package/src/scripts/nexo-catchup 2.py +0 -300
  126. package/src/scripts/nexo-cognitive-decay 2.py +0 -257
  127. package/src/scripts/nexo-cortex-cycle 2.py +0 -293
  128. package/src/scripts/nexo-cron-wrapper 2.sh +0 -53
  129. package/src/scripts/nexo-daily-self-audit 2.py +0 -2161
  130. package/src/scripts/nexo-dashboard 2.sh +0 -29
  131. package/src/scripts/nexo-deep-sleep 2.sh +0 -86
  132. package/src/scripts/nexo-evolution-run 2.py +0 -1664
  133. package/src/scripts/nexo-followup-hygiene 2.py +0 -139
  134. package/src/scripts/nexo-hook-record 2.py +0 -42
  135. package/src/scripts/nexo-immune 2.py +0 -936
  136. package/src/scripts/nexo-impact-scorer 2.py +0 -117
  137. package/src/scripts/nexo-inbox-hook 2.sh +0 -74
  138. package/src/scripts/nexo-install 2.py +0 -6
  139. package/src/scripts/nexo-learning-housekeep 2.py +0 -401
  140. package/src/scripts/nexo-learning-validator 2.py +0 -266
  141. package/src/scripts/nexo-migrate 2.py +0 -260
  142. package/src/scripts/nexo-outcome-checker 2.py +0 -127
  143. package/src/scripts/nexo-postmortem-consolidator 2.py +0 -456
  144. package/src/scripts/nexo-pre-commit 2.py +0 -120
  145. package/src/scripts/nexo-prevent-sleep 2.sh +0 -35
  146. package/src/scripts/nexo-proactive-dashboard 2.py +0 -354
  147. package/src/scripts/nexo-reflection 2.py +0 -256
  148. package/src/scripts/nexo-runtime-preflight 2.py +0 -274
  149. package/src/scripts/nexo-sleep 2.py +0 -631
  150. package/src/scripts/nexo-snapshot-restore 2.sh +0 -35
  151. package/src/scripts/nexo-sync-clients 2.py +0 -16
  152. package/src/scripts/nexo-synthesis 2.py +0 -475
  153. package/src/scripts/nexo-tcc-approve 2.sh +0 -79
  154. package/src/scripts/nexo-update 2.sh +0 -306
  155. package/src/scripts/nexo-watchdog 2.sh +0 -1207
  156. package/src/scripts/nexo-watchdog-smoke 2.py +0 -119
  157. package/src/scripts/rehydrate_learnings_from_archive 2.py +0 -245
  158. package/src/server 2.py +0 -1296
  159. package/src/skills/run-nexo-audit-phase/guide 2.md +0 -43
  160. package/src/skills/run-nexo-audit-phase/skill 2.json +0 -59
  161. package/src/skills/run-nexo-core-fix-cycle/guide 2.md +0 -17
  162. package/src/skills/run-nexo-core-fix-cycle/script 2.py +0 -276
  163. package/src/skills/run-nexo-core-fix-cycle/skill 2.json +0 -58
  164. package/src/skills/run-release-final-audit/guide 2.md +0 -16
  165. package/src/skills/run-release-final-audit/script 2.py +0 -259
  166. package/src/skills/run-release-final-audit/skill 2.json +0 -77
  167. package/src/skills/run-runtime-doctor/guide 2.md +0 -12
  168. package/src/skills/run-runtime-doctor/script 2.py +0 -21
  169. package/src/skills/run-runtime-doctor/skill 2.json +0 -25
  170. package/src/skills_runtime 2.py +0 -932
  171. package/src/state_watchers_runtime 2.py +0 -475
  172. package/src/storage_router 2.py +0 -32
  173. package/src/system_catalog 2.py +0 -786
  174. package/src/tools_coordination 2.py +0 -103
  175. package/src/tools_credentials 2.py +0 -68
  176. package/src/tools_drive 2.py +0 -487
  177. package/src/tools_hot_context 2.py +0 -163
  178. package/src/tools_learnings 2.py +0 -612
  179. package/src/tools_menu 2.py +0 -229
  180. package/src/tools_reminders 2.py +0 -88
  181. package/src/tools_reminders_crud 2.py +0 -363
  182. package/src/tools_sessions 2.py +0 -1054
  183. package/src/tools_system_catalog 2.py +0 -19
  184. package/src/tools_task_history 2.py +0 -57
  185. package/src/tools_transcripts 2.py +0 -98
  186. package/src/transcript_utils 2.py +0 -412
  187. package/src/user_context 2.py +0 -46
  188. package/src/user_data_portability 2.py +0 -328
  189. package/src/user_state_model 2.py +0 -170
  190. package/templates/CLAUDE.md 2.template +0 -108
  191. package/templates/CODEX.AGENTS.md 2.template +0 -66
  192. package/templates/launchagents/README 2.md +0 -132
  193. package/templates/launchagents/com.nexo.auto-close-sessions 2.plist +0 -39
  194. package/templates/launchagents/com.nexo.catchup 2.plist +0 -39
  195. package/templates/launchagents/com.nexo.cognitive-decay 2.plist +0 -40
  196. package/templates/launchagents/com.nexo.dashboard 2.plist +0 -43
  197. package/templates/launchagents/com.nexo.deep-sleep 2.plist +0 -43
  198. package/templates/launchagents/com.nexo.evolution 2.plist +0 -44
  199. package/templates/launchagents/com.nexo.followup-hygiene 2.plist +0 -45
  200. package/templates/launchagents/com.nexo.immune 2.plist +0 -41
  201. package/templates/launchagents/com.nexo.postmortem 2.plist +0 -45
  202. package/templates/launchagents/com.nexo.self-audit 2.plist +0 -47
  203. package/templates/launchagents/com.nexo.synthesis 2.plist +0 -45
  204. package/templates/launchagents/com.nexo.watchdog 2.plist +0 -37
  205. package/templates/nexo_helper 2.py +0 -301
  206. package/templates/openclaw 2.json +0 -13
  207. package/templates/plugin-template 2.py +0 -40
  208. package/templates/script-template 2.py +0 -59
  209. package/templates/script-template 2.sh +0 -13
  210. package/templates/skill-script-template 2.py +0 -48
  211. package/templates/skill-template 2.md +0 -33
@@ -1,106 +0,0 @@
1
- """Minimal public API wrappers for the core NEXO mental model."""
2
-
3
- from __future__ import annotations
4
-
5
- import hashlib
6
- import json
7
-
8
- import cognitive
9
-
10
- from plugins.episodic_memory import handle_recall
11
- from plugins.workflow import handle_workflow_open
12
-
13
-
14
- def handle_remember(
15
- content: str,
16
- title: str = "",
17
- domain: str = "",
18
- source_type: str = "note",
19
- tags: str = "",
20
- bypass_gate: bool = True,
21
- ) -> str:
22
- """Store one durable memory item with a single high-level call."""
23
- clean_content = (content or "").strip()
24
- if not clean_content:
25
- return json.dumps({"ok": False, "error": "content is required"}, ensure_ascii=False, indent=2)
26
-
27
- clean_title = (title or "").strip()[:120]
28
- # Content fingerprint for deterministic dedup id — not security-sensitive.
29
- source_id = hashlib.sha1(
30
- f"{clean_title}|{clean_content}".encode("utf-8"), usedforsecurity=False
31
- ).hexdigest()[:12]
32
- memory_id = cognitive.ingest_to_ltm(
33
- clean_content,
34
- source_type=(source_type or "note").strip()[:40],
35
- source_id=source_id,
36
- source_title=clean_title or clean_content[:80],
37
- domain=(domain or "").strip()[:120],
38
- tags=(tags or "").strip()[:200],
39
- bypass_gate=bool(bypass_gate),
40
- )
41
- return json.dumps(
42
- {
43
- "ok": bool(memory_id),
44
- "memory_id": int(memory_id or 0),
45
- "source_type": (source_type or "note").strip()[:40],
46
- "title": clean_title or clean_content[:80],
47
- "domain": (domain or "").strip()[:120],
48
- },
49
- ensure_ascii=False,
50
- indent=2,
51
- )
52
-
53
-
54
- def handle_memory_recall(query: str, days: int = 30) -> str:
55
- """High-level memory lookup wrapper around nexo_recall."""
56
- return handle_recall((query or "").strip(), days=max(1, int(days or 30)))
57
-
58
-
59
- def handle_consolidate(
60
- max_insights: int = 12,
61
- threshold: float = 0.9,
62
- dry_run: bool = False,
63
- ) -> str:
64
- """Run the core memory consolidation cycle explicitly."""
65
- promoted = cognitive.promote_stm_to_ltm()
66
- quarantine = cognitive.process_quarantine()
67
- dreamed = cognitive.dream_cycle(max_insights=max(1, int(max_insights or 12)))
68
- semantic = cognitive.consolidate_semantic(threshold=float(threshold or 0.9), dry_run=bool(dry_run))
69
- payload = {
70
- "ok": True,
71
- "promoted_to_ltm": int(promoted or 0),
72
- "quarantine": quarantine,
73
- "dream_cycle": dreamed,
74
- "semantic_consolidation": semantic,
75
- "dry_run": bool(dry_run),
76
- }
77
- return json.dumps(payload, ensure_ascii=False, indent=2)
78
-
79
-
80
- def handle_run_workflow(
81
- sid: str,
82
- goal: str,
83
- steps: str = "[]",
84
- goal_id: str = "",
85
- shared_state: str = "{}",
86
- owner: str = "",
87
- idempotency_key: str = "",
88
- ) -> str:
89
- """Open a durable workflow with the public mental-model naming."""
90
- return handle_workflow_open(
91
- sid=sid,
92
- goal=goal,
93
- steps=steps,
94
- goal_id=goal_id,
95
- shared_state=shared_state,
96
- owner=owner,
97
- idempotency_key=idempotency_key,
98
- )
99
-
100
-
101
- TOOLS = [
102
- (handle_remember, "nexo_remember", "High-level memory write: store one durable memory item."),
103
- (handle_memory_recall, "nexo_memory_recall", "High-level memory lookup wrapper around nexo_recall."),
104
- (handle_consolidate, "nexo_consolidate", "Run NEXO memory consolidation explicitly: promote, process quarantine, dream, consolidate."),
105
- (handle_run_workflow, "nexo_run_workflow", "High-level durable workflow entry point for the public API surface."),
106
- ]
@@ -1,341 +0,0 @@
1
- """Skills plugin — reusable procedures, executable skills, and feedback loops."""
2
-
3
- from __future__ import annotations
4
-
5
- import json
6
-
7
- from db import (
8
- create_skill,
9
- delete_skill,
10
- get_skill,
11
- get_skill_stats,
12
- list_skills,
13
- match_skills,
14
- merge_skills,
15
- record_skill_usage,
16
- search_skills,
17
- update_skill,
18
- )
19
- from skills_runtime import (
20
- apply_skill,
21
- approve_skill_execution,
22
- compose_skills,
23
- detect_skill_coactivation_candidates,
24
- get_featured_skill_summaries,
25
- list_evolution_candidates,
26
- materialize_outcome_pattern_skill,
27
- promote_skill,
28
- review_skill_outcomes,
29
- retire_skill,
30
- sync_skills,
31
- test_skill,
32
- )
33
-
34
-
35
- def handle_skill_create(
36
- id: str,
37
- name: str,
38
- description: str = "",
39
- level: str = "draft",
40
- tags: str = "[]",
41
- trigger_patterns: str = "[]",
42
- source_sessions: str = "[]",
43
- linked_learnings: str = "[]",
44
- file_path: str = "",
45
- mode: str = "",
46
- source_kind: str = "personal",
47
- execution_level: str = "none",
48
- approval_required: bool = False,
49
- params_schema: str = "{}",
50
- command_template: str = "{}",
51
- executable_entry: str = "",
52
- ) -> str:
53
- if not id.startswith("SK-"):
54
- return "ERROR: Skill ID must start with 'SK-' (e.g., SK-DEPLOY-CHROME-EXT)"
55
- if get_skill(id):
56
- return f"ERROR: Skill {id} already exists. Use nexo_skill_update to modify."
57
-
58
- result = create_skill(
59
- skill_id=id,
60
- name=name,
61
- description=description,
62
- level=level,
63
- tags=tags,
64
- trigger_patterns=trigger_patterns,
65
- source_sessions=source_sessions,
66
- linked_learnings=linked_learnings,
67
- file_path=file_path,
68
- mode=mode,
69
- source_kind=source_kind,
70
- execution_level=execution_level,
71
- approval_required=approval_required,
72
- params_schema=params_schema,
73
- command_template=command_template,
74
- executable_entry=executable_entry,
75
- )
76
- if "error" in result:
77
- return f"ERROR: {result['error']}"
78
-
79
- return (
80
- f"Skill {id} created ({result['level']}, {result.get('mode', 'guide')}, trust={result.get('trust_score', 50)}).\n"
81
- f" Name: {name}\n"
82
- f" Source: {result.get('source_kind', source_kind)}\n"
83
- f" Execution: {result.get('execution_level', execution_level)}"
84
- )
85
-
86
-
87
- def handle_skill_match(task: str, level: str = "") -> str:
88
- matches = match_skills(task, level=level)
89
- if not matches:
90
- return f"No skills found for: '{task}'"
91
-
92
- lines = [f"SKILLS MATCHED ({len(matches)}) for '{task}':"]
93
- for match in matches:
94
- match_method = match.pop("_match", "unknown")
95
- lines.append(
96
- f" [{match['id']}] {match['name']} ({match['level']}, {match.get('mode', 'guide')}, "
97
- f"{match.get('source_kind', 'personal')}, trust={match['trust_score']}, used={match['use_count']}x) "
98
- f"via {match_method}"
99
- )
100
- lines.append(f" {match['description'][:140]}")
101
- return "\n".join(lines)
102
-
103
-
104
- def handle_skill_get(id: str) -> str:
105
- skill = get_skill(id)
106
- if not skill:
107
- return f"ERROR: Skill {id} not found."
108
-
109
- lines = [
110
- f"SKILL: {skill['id']}",
111
- f" Name: {skill['name']}",
112
- f" Description: {skill['description']}",
113
- f" Level: {skill['level']}",
114
- f" Mode: {skill.get('mode', 'guide')}",
115
- f" Source: {skill.get('source_kind', 'personal')}",
116
- f" Trust: {skill['trust_score']}",
117
- f" Execution level: {skill.get('execution_level', 'none')}",
118
- f" Approval required: {bool(skill.get('approval_required', 0))}",
119
- f" Approved at: {skill.get('approved_at') or 'no'}",
120
- f" Definition: {skill.get('definition_path') or '(none)'}",
121
- f" File: {skill.get('file_path') or '(none)'}",
122
- f" Params schema: {skill.get('params_schema', '{}')}",
123
- f" Triggers: {skill['trigger_patterns']}",
124
- f" Stats: {skill['use_count']} uses, {skill['success_count']} success, {skill['fail_count']} fail",
125
- ]
126
- return "\n".join(lines)
127
-
128
-
129
- def handle_skill_result(id: str, success: bool = True, context: str = "", notes: str = "") -> str:
130
- result = record_skill_usage(skill_id=id, success=success, context=context, notes=notes)
131
- if "error" in result:
132
- return f"ERROR: {result['error']}"
133
-
134
- promotion = result.get("_promotion")
135
- msg = f"Skill {id} usage recorded: {'SUCCESS' if success else 'FAILURE'} (trust={result['trust_score']})"
136
- if promotion:
137
- msg += f"\n ⚡ PROMOTION: {promotion}"
138
- return msg
139
-
140
-
141
- def handle_skill_list(level: str = "", tag: str = "", source_kind: str = "") -> str:
142
- skills = list_skills(level=level, tag=tag, source_kind=source_kind)
143
- if not skills:
144
- return "No skills found."
145
-
146
- lines = [f"SKILLS ({len(skills)}):"]
147
- for skill in skills:
148
- lines.append(
149
- f" [{skill['id']}] {skill['name']} ({skill['level']}, {skill.get('mode', 'guide')}, "
150
- f"{skill.get('source_kind', 'personal')}, trust={skill['trust_score']}, used={skill['use_count']}x)"
151
- )
152
- return "\n".join(lines)
153
-
154
-
155
- def handle_skill_merge(id1: str, id2: str, keep_id: str = "") -> str:
156
- result = merge_skills(id1, id2, keep_id=keep_id)
157
- if "error" in result:
158
- return f"ERROR: {result['error']}"
159
- return (
160
- f"Skills merged. Kept {result['id']}, deleted {result['_merged_from']}.\n"
161
- f" Trust: {result['trust_score']}, Uses: {result['use_count']}"
162
- )
163
-
164
-
165
- def handle_skill_stats() -> str:
166
- stats = get_skill_stats()
167
- return (
168
- "SKILL STATS:\n"
169
- f" Total: {stats['total']}\n"
170
- f" By level: {', '.join(f'{k}={v}' for k, v in sorted(stats['by_level'].items()))}\n"
171
- f" Avg trust: {stats['avg_trust']}\n"
172
- f" Total uses: {stats['total_uses']} (success rate: {stats['success_rate']}%)\n"
173
- f" Uses last 7d: {stats['uses_last_7d']}\n"
174
- f" Reuse rate: {stats['skill_reuse_rate']}\n"
175
- f" Outcome-backed skills: {stats['outcome_backed_skills']} (avg success: {stats['outcome_backed_success_rate']}%)\n"
176
- f" Promoted from evidence: {stats['promoted_from_evidence_count']}\n"
177
- f" Retired for poor outcomes: {stats['retired_for_poor_outcomes_count']}"
178
- )
179
-
180
-
181
- def handle_skill_apply(id: str, params: str = "{}", mode: str = "auto", dry_run: bool = False, context: str = "") -> str:
182
- return json.dumps(apply_skill(id, params=params, mode=mode, dry_run=dry_run, context=context), ensure_ascii=False)
183
-
184
-
185
- def handle_skill_test(id: str, params: str = "{}", mode: str = "auto", context: str = "") -> str:
186
- return json.dumps(test_skill(id, params=params, mode=mode, context=context), ensure_ascii=False)
187
-
188
-
189
- def handle_skill_approve(id: str, execution_level: str = "", approved_by: str = "") -> str:
190
- result = approve_skill_execution(id, execution_level=execution_level, approved_by=approved_by)
191
- if "error" in result:
192
- return f"ERROR: {result['error']}"
193
- return (
194
- f"Skill {id} approved.\n"
195
- f" Execution level: {result.get('execution_level', 'none')}\n"
196
- f" Approved at: {result.get('approved_at', '')}\n"
197
- f" Approved by: {result.get('approved_by', '')}"
198
- )
199
-
200
-
201
- def handle_skill_sync() -> str:
202
- result = sync_skills()
203
- return json.dumps(result, ensure_ascii=False)
204
-
205
-
206
- def handle_skill_featured(limit: int = 5) -> str:
207
- return json.dumps(get_featured_skill_summaries(limit=limit), ensure_ascii=False)
208
-
209
-
210
- def handle_skill_evolution_candidates() -> str:
211
- return json.dumps(list_evolution_candidates(), ensure_ascii=False)
212
-
213
-
214
- def handle_skill_compose_candidates(
215
- min_co_occurrence: int = 3,
216
- min_success_rate: float = 0.6,
217
- limit: int = 20,
218
- ) -> str:
219
- """List Voyager-style composition candidates from skill_usage co-activation.
220
-
221
- Closes Fase 5 item 5. Detects pairs of skills that fire together
222
- in the same session repeatedly and could become a single composite.
223
- Returns the candidates sorted by co-occurrence count, with a
224
- suggested deterministic skill_id (SK-COMPOSE-<a>+<b>) that
225
- nexo_skill_compose can take as input.
226
-
227
- Args:
228
- min_co_occurrence: minimum sessions where both skills fired (default 3).
229
- min_success_rate: minimum joint success rate (default 0.6).
230
- limit: max candidates to return (default 20).
231
- """
232
- return json.dumps(
233
- detect_skill_coactivation_candidates(
234
- min_co_occurrence=int(min_co_occurrence),
235
- min_success_rate=float(min_success_rate),
236
- limit=int(limit),
237
- ),
238
- ensure_ascii=False,
239
- indent=2,
240
- )
241
-
242
-
243
- def handle_skill_seed_from_outcome_pattern(pattern_key: str) -> str:
244
- return json.dumps(materialize_outcome_pattern_skill(pattern_key), ensure_ascii=False)
245
-
246
-
247
- def handle_skill_outcome_review(id: str, auto_apply: bool = False) -> str:
248
- return json.dumps(review_skill_outcomes(id, auto_apply=auto_apply), ensure_ascii=False)
249
-
250
-
251
- def handle_skill_promote(id: str, target_level: str = "published", reason: str = "") -> str:
252
- return json.dumps(promote_skill(id, target_level=target_level, reason=reason), ensure_ascii=False)
253
-
254
-
255
- def handle_skill_retire(id: str, replacement_id: str = "", reason: str = "") -> str:
256
- return json.dumps(retire_skill(id, replacement_id=replacement_id, reason=reason), ensure_ascii=False)
257
-
258
-
259
- def handle_skill_compose(
260
- new_id: str,
261
- name: str,
262
- component_ids: str = "[]",
263
- description: str = "",
264
- level: str = "draft",
265
- mode: str = "guide",
266
- tags: str = "[]",
267
- trigger_patterns: str = "[]",
268
- ) -> str:
269
- try:
270
- component_list = json.loads(component_ids) if str(component_ids or "").strip().startswith("[") else [
271
- item.strip() for item in str(component_ids or "").split(",") if item.strip()
272
- ]
273
- except json.JSONDecodeError:
274
- component_list = []
275
- try:
276
- tags_list = json.loads(tags) if str(tags or "").strip().startswith("[") else [
277
- item.strip() for item in str(tags or "").split(",") if item.strip()
278
- ]
279
- except json.JSONDecodeError:
280
- tags_list = []
281
- try:
282
- trigger_list = json.loads(trigger_patterns) if str(trigger_patterns or "").strip().startswith("[") else [
283
- item.strip() for item in str(trigger_patterns or "").split(",") if item.strip()
284
- ]
285
- except json.JSONDecodeError:
286
- trigger_list = []
287
- return json.dumps(
288
- compose_skills(
289
- new_skill_id=new_id,
290
- name=name,
291
- component_ids=component_list,
292
- description=description,
293
- level=level,
294
- mode=mode,
295
- tags=tags_list,
296
- trigger_patterns=trigger_list,
297
- ),
298
- ensure_ascii=False,
299
- )
300
-
301
-
302
- TOOLS = [
303
- (handle_skill_create, "nexo_skill_create",
304
- "Create a new skill with guide/execute/hybrid metadata, triggers, params schema, and execution level."),
305
- (handle_skill_match, "nexo_skill_match",
306
- "Find skills matching a task description. Call before multi-step tasks."),
307
- (handle_skill_get, "nexo_skill_get",
308
- "Get a skill's full details, including execution metadata and approval state."),
309
- (handle_skill_result, "nexo_skill_result",
310
- "Record the result of using a skill. Updates trust and promotions."),
311
- (handle_skill_list, "nexo_skill_list",
312
- "List skills, optionally filtered by level, tag, or source kind."),
313
- (handle_skill_merge, "nexo_skill_merge",
314
- "Merge two similar skills into one."),
315
- (handle_skill_stats, "nexo_skill_stats",
316
- "Show aggregate skill statistics."),
317
- (handle_skill_apply, "nexo_skill_apply",
318
- "Apply a skill in guide, execute, or hybrid mode. Execution goes through the stable nexo scripts runtime."),
319
- (handle_skill_test, "nexo_skill_test",
320
- "Test a skill through the canonical runtime in dry-run mode before wider use."),
321
- (handle_skill_approve, "nexo_skill_approve",
322
- "Approve a local/remote executable skill so it can run."),
323
- (handle_skill_sync, "nexo_skill_sync",
324
- "Sync filesystem skill definitions from personal/core/community directories into SQLite."),
325
- (handle_skill_featured, "nexo_skill_featured",
326
- "Return featured published/stable skills for startup discovery."),
327
- (handle_skill_evolution_candidates, "nexo_skill_evolution_candidates",
328
- "Return candidates for skill improvement or text-to-script evolution."),
329
- (handle_skill_seed_from_outcome_pattern, "nexo_skill_seed_from_outcome_pattern",
330
- "Materialize a draft skill candidate from a repeated successful outcome pattern with linked evidence."),
331
- (handle_skill_outcome_review, "nexo_skill_outcome_review",
332
- "Review whether a skill should be promoted, deprioritized, or retired based on sustained outcome evidence."),
333
- (handle_skill_promote, "nexo_skill_promote",
334
- "Promote a skill to a stronger published/stable lifecycle stage."),
335
- (handle_skill_retire, "nexo_skill_retire",
336
- "Retire a skill cleanly so it leaves the active lifecycle."),
337
- (handle_skill_compose, "nexo_skill_compose",
338
- "Compose multiple existing skills into one higher-level reusable skill."),
339
- (handle_skill_compose_candidates, "nexo_skill_compose_candidates",
340
- "Voyager-style detection: list skill pairs that fired together in 3+ sessions with 60%+ joint success and could become a single composite (closes Fase 5 item 5)."),
341
- ]
@@ -1,79 +0,0 @@
1
- """State watchers plugin — persistent drift/health/expiry watchers."""
2
-
3
- from __future__ import annotations
4
-
5
- import json
6
-
7
- from db import create_state_watcher, list_state_watchers, update_state_watcher
8
- from state_watchers_runtime import run_state_watchers
9
-
10
-
11
- def handle_state_watcher_create(
12
- watcher_type: str,
13
- title: str,
14
- target: str = "",
15
- severity: str = "warn",
16
- status: str = "active",
17
- config: str = "{}",
18
- ) -> str:
19
- """Create a persistent state watcher for drift, health, or expiry."""
20
- try:
21
- watcher = create_state_watcher(
22
- watcher_type,
23
- title,
24
- target=target,
25
- severity=severity,
26
- status=status,
27
- config=json.loads(config) if str(config).strip() else {},
28
- )
29
- except (ValueError, json.JSONDecodeError) as exc:
30
- return json.dumps({"ok": False, "error": str(exc)}, ensure_ascii=False, indent=2)
31
- return json.dumps({"ok": True, "watcher": watcher}, ensure_ascii=False, indent=2)
32
-
33
-
34
- def handle_state_watcher_update(
35
- watcher_id: str,
36
- title: str = "",
37
- target: str = "",
38
- severity: str = "",
39
- status: str = "",
40
- config: str = "",
41
- ) -> str:
42
- """Update an existing state watcher."""
43
- payload = None
44
- if str(config).strip():
45
- try:
46
- payload = json.loads(config)
47
- except json.JSONDecodeError as exc:
48
- return json.dumps({"ok": False, "error": str(exc)}, ensure_ascii=False, indent=2)
49
- watcher = update_state_watcher(
50
- watcher_id,
51
- title=(title or None),
52
- target=(target or None),
53
- severity=(severity or None),
54
- status=(status or None),
55
- config=payload,
56
- )
57
- if not watcher:
58
- return json.dumps({"ok": False, "error": f"Unknown watcher_id: {watcher_id}"}, ensure_ascii=False, indent=2)
59
- return json.dumps({"ok": True, "watcher": watcher}, ensure_ascii=False, indent=2)
60
-
61
-
62
- def handle_state_watcher_list(status: str = "", watcher_type: str = "", limit: int = 50) -> str:
63
- """List configured state watchers."""
64
- watchers = list_state_watchers(status=status, watcher_type=watcher_type, limit=max(1, int(limit or 50)))
65
- return json.dumps({"ok": True, "count": len(watchers), "watchers": watchers}, ensure_ascii=False, indent=2)
66
-
67
-
68
- def handle_state_watcher_run(status: str = "active", persist: bool = True) -> str:
69
- """Run active state watchers and return their current health."""
70
- summary = run_state_watchers(status=status or "active", persist=bool(persist))
71
- return json.dumps({"ok": True, **summary}, ensure_ascii=False, indent=2)
72
-
73
-
74
- TOOLS = [
75
- (handle_state_watcher_create, "nexo_state_watcher_create", "Create a persistent state watcher for repo drift, cron drift, API health, environment drift, or expiry."),
76
- (handle_state_watcher_update, "nexo_state_watcher_update", "Update an existing persistent state watcher."),
77
- (handle_state_watcher_list, "nexo_state_watcher_list", "List persistent state watchers."),
78
- (handle_state_watcher_run, "nexo_state_watcher_run", "Run persistent state watchers and return their current health summary."),
79
- ]