aether-colony 5.3.2 → 5.4.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.
Files changed (281) hide show
  1. package/.aether/aether-utils.sh +181 -5
  2. package/.aether/commands/archaeology.yaml +3 -3
  3. package/.aether/commands/build.yaml +80 -45
  4. package/.aether/commands/chaos.yaml +7 -7
  5. package/.aether/commands/colonize.yaml +17 -17
  6. package/.aether/commands/continue.yaml +40 -40
  7. package/.aether/commands/council.yaml +6 -6
  8. package/.aether/commands/data-clean.yaml +3 -3
  9. package/.aether/commands/dream.yaml +2 -2
  10. package/.aether/commands/entomb.yaml +12 -12
  11. package/.aether/commands/export-signals.yaml +2 -2
  12. package/.aether/commands/feedback.yaml +6 -6
  13. package/.aether/commands/flag.yaml +2 -2
  14. package/.aether/commands/flags.yaml +4 -4
  15. package/.aether/commands/focus.yaml +6 -6
  16. package/.aether/commands/help.yaml +1 -1
  17. package/.aether/commands/history.yaml +1 -1
  18. package/.aether/commands/import-signals.yaml +2 -2
  19. package/.aether/commands/init.yaml +44 -27
  20. package/.aether/commands/insert-phase.yaml +1 -1
  21. package/.aether/commands/interpret.yaml +2 -2
  22. package/.aether/commands/lay-eggs.yaml +3 -3
  23. package/.aether/commands/maturity.yaml +2 -2
  24. package/.aether/commands/memory-details.yaml +1 -1
  25. package/.aether/commands/migrate-state.yaml +1 -1
  26. package/.aether/commands/oracle.yaml +147 -82
  27. package/.aether/commands/organize.yaml +5 -5
  28. package/.aether/commands/patrol.yaml +8 -8
  29. package/.aether/commands/pause-colony.yaml +7 -7
  30. package/.aether/commands/phase.yaml +1 -1
  31. package/.aether/commands/pheromones.yaml +1 -1
  32. package/.aether/commands/plan.yaml +14 -14
  33. package/.aether/commands/quick.yaml +4 -4
  34. package/.aether/commands/redirect.yaml +6 -6
  35. package/.aether/commands/resume-colony.yaml +9 -9
  36. package/.aether/commands/resume.yaml +5 -38
  37. package/.aether/commands/run.yaml +10 -10
  38. package/.aether/commands/seal.yaml +33 -33
  39. package/.aether/commands/skill-create.yaml +4 -4
  40. package/.aether/commands/status.yaml +14 -14
  41. package/.aether/commands/swarm.yaml +14 -14
  42. package/.aether/commands/tunnels.yaml +7 -7
  43. package/.aether/commands/update.yaml +1 -1
  44. package/.aether/commands/verify-castes.yaml +3 -3
  45. package/.aether/commands/watch.yaml +15 -15
  46. package/.aether/docs/command-playbooks/build-complete.md +48 -15
  47. package/.aether/docs/command-playbooks/build-context.md +11 -11
  48. package/.aether/docs/command-playbooks/build-full.md +76 -76
  49. package/.aether/docs/command-playbooks/build-prep.md +10 -10
  50. package/.aether/docs/command-playbooks/build-verify.md +27 -27
  51. package/.aether/docs/command-playbooks/build-wave.md +38 -38
  52. package/.aether/docs/command-playbooks/continue-advance.md +60 -27
  53. package/.aether/docs/command-playbooks/continue-finalize.md +25 -11
  54. package/.aether/docs/command-playbooks/continue-full.md +60 -46
  55. package/.aether/docs/command-playbooks/continue-gates.md +18 -18
  56. package/.aether/docs/command-playbooks/continue-verify.md +10 -10
  57. package/.aether/docs/source-of-truth-map.md +10 -10
  58. package/.aether/docs/structural-learning-stack.md +283 -0
  59. package/.aether/templates/colony-state-template.json +1 -0
  60. package/.aether/utils/consolidation-seal.sh +196 -0
  61. package/.aether/utils/consolidation.sh +127 -0
  62. package/.aether/utils/curation-ants/archivist.sh +97 -0
  63. package/.aether/utils/curation-ants/critic.sh +214 -0
  64. package/.aether/utils/curation-ants/herald.sh +102 -0
  65. package/.aether/utils/curation-ants/janitor.sh +121 -0
  66. package/.aether/utils/curation-ants/librarian.sh +99 -0
  67. package/.aether/utils/curation-ants/nurse.sh +153 -0
  68. package/.aether/utils/curation-ants/orchestrator.sh +181 -0
  69. package/.aether/utils/curation-ants/scribe.sh +164 -0
  70. package/.aether/utils/curation-ants/sentinel.sh +119 -0
  71. package/.aether/utils/event-bus.sh +301 -0
  72. package/.aether/utils/graph.sh +559 -0
  73. package/.aether/utils/instinct-store.sh +401 -0
  74. package/.aether/utils/learning.sh +79 -7
  75. package/.aether/utils/oracle/oracle-stop-hook.sh +896 -0
  76. package/.aether/utils/session.sh +13 -0
  77. package/.aether/utils/state-api.sh +1 -1
  78. package/.aether/utils/trust-scoring.sh +347 -0
  79. package/.aether/utils/worktree.sh +97 -0
  80. package/.claude/commands/ant/archaeology.md +2 -2
  81. package/.claude/commands/ant/chaos.md +4 -4
  82. package/.claude/commands/ant/colonize.md +9 -9
  83. package/.claude/commands/ant/council.md +6 -6
  84. package/.claude/commands/ant/data-clean.md +3 -3
  85. package/.claude/commands/ant/dream.md +2 -2
  86. package/.claude/commands/ant/entomb.md +9 -9
  87. package/.claude/commands/ant/export-signals.md +2 -2
  88. package/.claude/commands/ant/feedback.md +4 -4
  89. package/.claude/commands/ant/flag.md +2 -2
  90. package/.claude/commands/ant/flags.md +4 -4
  91. package/.claude/commands/ant/focus.md +4 -4
  92. package/.claude/commands/ant/help.md +1 -1
  93. package/.claude/commands/ant/history.md +1 -1
  94. package/.claude/commands/ant/import-signals.md +2 -2
  95. package/.claude/commands/ant/init.md +44 -27
  96. package/.claude/commands/ant/insert-phase.md +1 -1
  97. package/.claude/commands/ant/interpret.md +2 -2
  98. package/.claude/commands/ant/lay-eggs.md +2 -2
  99. package/.claude/commands/ant/maturity.md +2 -2
  100. package/.claude/commands/ant/memory-details.md +1 -1
  101. package/.claude/commands/ant/migrate-state.md +1 -1
  102. package/.claude/commands/ant/oracle.md +78 -42
  103. package/.claude/commands/ant/organize.md +3 -3
  104. package/.claude/commands/ant/patrol.md +8 -8
  105. package/.claude/commands/ant/pause-colony.md +5 -5
  106. package/.claude/commands/ant/phase.md +1 -1
  107. package/.claude/commands/ant/pheromones.md +1 -1
  108. package/.claude/commands/ant/plan.md +8 -8
  109. package/.claude/commands/ant/quick.md +4 -4
  110. package/.claude/commands/ant/redirect.md +4 -4
  111. package/.claude/commands/ant/resume-colony.md +5 -5
  112. package/.claude/commands/ant/resume.md +17 -29
  113. package/.claude/commands/ant/run.md +10 -10
  114. package/.claude/commands/ant/seal.md +25 -25
  115. package/.claude/commands/ant/skill-create.md +2 -2
  116. package/.claude/commands/ant/status.md +14 -14
  117. package/.claude/commands/ant/swarm.md +14 -14
  118. package/.claude/commands/ant/tunnels.md +4 -4
  119. package/.claude/commands/ant/update.md +1 -1
  120. package/.claude/commands/ant/verify-castes.md +2 -2
  121. package/.claude/commands/ant/watch.md +8 -8
  122. package/.opencode/commands/ant/archaeology.md +1 -1
  123. package/.opencode/commands/ant/build.md +80 -45
  124. package/.opencode/commands/ant/chaos.md +3 -3
  125. package/.opencode/commands/ant/colonize.md +8 -8
  126. package/.opencode/commands/ant/continue.md +40 -40
  127. package/.opencode/commands/ant/council.md +5 -5
  128. package/.opencode/commands/ant/data-clean.md +2 -2
  129. package/.opencode/commands/ant/dream.md +1 -1
  130. package/.opencode/commands/ant/entomb.md +3 -3
  131. package/.opencode/commands/ant/export-signals.md +1 -1
  132. package/.opencode/commands/ant/feedback.md +2 -2
  133. package/.opencode/commands/ant/flag.md +1 -1
  134. package/.opencode/commands/ant/flags.md +3 -3
  135. package/.opencode/commands/ant/focus.md +2 -2
  136. package/.opencode/commands/ant/import-signals.md +1 -1
  137. package/.opencode/commands/ant/init.md +44 -27
  138. package/.opencode/commands/ant/insert-phase.md +1 -1
  139. package/.opencode/commands/ant/interpret.md +1 -1
  140. package/.opencode/commands/ant/lay-eggs.md +2 -2
  141. package/.opencode/commands/ant/maturity.md +1 -1
  142. package/.opencode/commands/ant/memory-details.md +1 -1
  143. package/.opencode/commands/ant/oracle.md +69 -40
  144. package/.opencode/commands/ant/organize.md +2 -2
  145. package/.opencode/commands/ant/patrol.md +8 -8
  146. package/.opencode/commands/ant/pause-colony.md +2 -2
  147. package/.opencode/commands/ant/pheromones.md +1 -1
  148. package/.opencode/commands/ant/plan.md +6 -6
  149. package/.opencode/commands/ant/quick.md +4 -4
  150. package/.opencode/commands/ant/redirect.md +2 -2
  151. package/.opencode/commands/ant/resume-colony.md +4 -4
  152. package/.opencode/commands/ant/resume.md +5 -17
  153. package/.opencode/commands/ant/run.md +10 -10
  154. package/.opencode/commands/ant/seal.md +8 -8
  155. package/.opencode/commands/ant/skill-create.md +2 -2
  156. package/.opencode/commands/ant/status.md +10 -10
  157. package/.opencode/commands/ant/tunnels.md +3 -3
  158. package/.opencode/commands/ant/verify-castes.md +1 -1
  159. package/.opencode/commands/ant/watch.md +7 -7
  160. package/CHANGELOG.md +83 -0
  161. package/README.md +22 -9
  162. package/bin/cli.js +118 -3
  163. package/bin/lib/binary-downloader.js +267 -0
  164. package/bin/lib/update-transaction.js +27 -3
  165. package/bin/lib/version-gate.js +179 -0
  166. package/bin/npx-entry.js +0 -0
  167. package/package.json +1 -1
  168. package/.aether/agents/aether-ambassador.md +0 -140
  169. package/.aether/agents/aether-archaeologist.md +0 -108
  170. package/.aether/agents/aether-architect.md +0 -133
  171. package/.aether/agents/aether-auditor.md +0 -144
  172. package/.aether/agents/aether-builder.md +0 -184
  173. package/.aether/agents/aether-chaos.md +0 -115
  174. package/.aether/agents/aether-chronicler.md +0 -122
  175. package/.aether/agents/aether-gatekeeper.md +0 -116
  176. package/.aether/agents/aether-includer.md +0 -117
  177. package/.aether/agents/aether-keeper.md +0 -177
  178. package/.aether/agents/aether-measurer.md +0 -128
  179. package/.aether/agents/aether-oracle.md +0 -137
  180. package/.aether/agents/aether-probe.md +0 -133
  181. package/.aether/agents/aether-queen.md +0 -286
  182. package/.aether/agents/aether-route-setter.md +0 -130
  183. package/.aether/agents/aether-sage.md +0 -106
  184. package/.aether/agents/aether-scout.md +0 -101
  185. package/.aether/agents/aether-surveyor-disciplines.md +0 -391
  186. package/.aether/agents/aether-surveyor-nest.md +0 -329
  187. package/.aether/agents/aether-surveyor-pathogens.md +0 -264
  188. package/.aether/agents/aether-surveyor-provisions.md +0 -334
  189. package/.aether/agents/aether-tracker.md +0 -137
  190. package/.aether/agents/aether-watcher.md +0 -174
  191. package/.aether/agents/aether-weaver.md +0 -130
  192. package/.aether/commands/claude/archaeology.md +0 -334
  193. package/.aether/commands/claude/build.md +0 -65
  194. package/.aether/commands/claude/chaos.md +0 -336
  195. package/.aether/commands/claude/colonize.md +0 -259
  196. package/.aether/commands/claude/continue.md +0 -60
  197. package/.aether/commands/claude/council.md +0 -507
  198. package/.aether/commands/claude/data-clean.md +0 -81
  199. package/.aether/commands/claude/dream.md +0 -268
  200. package/.aether/commands/claude/entomb.md +0 -498
  201. package/.aether/commands/claude/export-signals.md +0 -57
  202. package/.aether/commands/claude/feedback.md +0 -96
  203. package/.aether/commands/claude/flag.md +0 -151
  204. package/.aether/commands/claude/flags.md +0 -169
  205. package/.aether/commands/claude/focus.md +0 -76
  206. package/.aether/commands/claude/help.md +0 -154
  207. package/.aether/commands/claude/history.md +0 -140
  208. package/.aether/commands/claude/import-signals.md +0 -71
  209. package/.aether/commands/claude/init.md +0 -505
  210. package/.aether/commands/claude/insert-phase.md +0 -105
  211. package/.aether/commands/claude/interpret.md +0 -278
  212. package/.aether/commands/claude/lay-eggs.md +0 -210
  213. package/.aether/commands/claude/maturity.md +0 -113
  214. package/.aether/commands/claude/memory-details.md +0 -77
  215. package/.aether/commands/claude/migrate-state.md +0 -171
  216. package/.aether/commands/claude/oracle.md +0 -642
  217. package/.aether/commands/claude/organize.md +0 -232
  218. package/.aether/commands/claude/patrol.md +0 -620
  219. package/.aether/commands/claude/pause-colony.md +0 -233
  220. package/.aether/commands/claude/phase.md +0 -115
  221. package/.aether/commands/claude/pheromones.md +0 -156
  222. package/.aether/commands/claude/plan.md +0 -693
  223. package/.aether/commands/claude/preferences.md +0 -65
  224. package/.aether/commands/claude/quick.md +0 -100
  225. package/.aether/commands/claude/redirect.md +0 -76
  226. package/.aether/commands/claude/resume-colony.md +0 -197
  227. package/.aether/commands/claude/resume.md +0 -388
  228. package/.aether/commands/claude/run.md +0 -231
  229. package/.aether/commands/claude/seal.md +0 -774
  230. package/.aether/commands/claude/skill-create.md +0 -286
  231. package/.aether/commands/claude/status.md +0 -410
  232. package/.aether/commands/claude/swarm.md +0 -349
  233. package/.aether/commands/claude/tunnels.md +0 -426
  234. package/.aether/commands/claude/update.md +0 -132
  235. package/.aether/commands/claude/verify-castes.md +0 -143
  236. package/.aether/commands/claude/watch.md +0 -239
  237. package/.aether/commands/opencode/archaeology.md +0 -331
  238. package/.aether/commands/opencode/build.md +0 -1168
  239. package/.aether/commands/opencode/chaos.md +0 -329
  240. package/.aether/commands/opencode/colonize.md +0 -195
  241. package/.aether/commands/opencode/continue.md +0 -1436
  242. package/.aether/commands/opencode/council.md +0 -437
  243. package/.aether/commands/opencode/data-clean.md +0 -77
  244. package/.aether/commands/opencode/dream.md +0 -260
  245. package/.aether/commands/opencode/entomb.md +0 -377
  246. package/.aether/commands/opencode/export-signals.md +0 -54
  247. package/.aether/commands/opencode/feedback.md +0 -99
  248. package/.aether/commands/opencode/flag.md +0 -149
  249. package/.aether/commands/opencode/flags.md +0 -167
  250. package/.aether/commands/opencode/focus.md +0 -73
  251. package/.aether/commands/opencode/help.md +0 -157
  252. package/.aether/commands/opencode/history.md +0 -136
  253. package/.aether/commands/opencode/import-signals.md +0 -68
  254. package/.aether/commands/opencode/init.md +0 -518
  255. package/.aether/commands/opencode/insert-phase.md +0 -111
  256. package/.aether/commands/opencode/interpret.md +0 -272
  257. package/.aether/commands/opencode/lay-eggs.md +0 -213
  258. package/.aether/commands/opencode/maturity.md +0 -108
  259. package/.aether/commands/opencode/memory-details.md +0 -83
  260. package/.aether/commands/opencode/migrate-state.md +0 -165
  261. package/.aether/commands/opencode/oracle.md +0 -593
  262. package/.aether/commands/opencode/organize.md +0 -226
  263. package/.aether/commands/opencode/patrol.md +0 -626
  264. package/.aether/commands/opencode/pause-colony.md +0 -203
  265. package/.aether/commands/opencode/phase.md +0 -113
  266. package/.aether/commands/opencode/pheromones.md +0 -162
  267. package/.aether/commands/opencode/plan.md +0 -684
  268. package/.aether/commands/opencode/preferences.md +0 -71
  269. package/.aether/commands/opencode/quick.md +0 -91
  270. package/.aether/commands/opencode/redirect.md +0 -84
  271. package/.aether/commands/opencode/resume-colony.md +0 -190
  272. package/.aether/commands/opencode/resume.md +0 -394
  273. package/.aether/commands/opencode/run.md +0 -237
  274. package/.aether/commands/opencode/seal.md +0 -452
  275. package/.aether/commands/opencode/skill-create.md +0 -63
  276. package/.aether/commands/opencode/status.md +0 -307
  277. package/.aether/commands/opencode/swarm.md +0 -15
  278. package/.aether/commands/opencode/tunnels.md +0 -400
  279. package/.aether/commands/opencode/update.md +0 -127
  280. package/.aether/commands/opencode/verify-castes.md +0 -139
  281. package/.aether/commands/opencode/watch.md +0 -227
@@ -0,0 +1,153 @@
1
+ #!/bin/bash
2
+ # Nurse curation ant — trust recalculation for observations and instincts
3
+ # Provides: _curation_nurse
4
+ #
5
+ # These functions are sourced by aether-utils.sh at startup.
6
+ # All shared infrastructure (json_ok, json_err, atomic_write,
7
+ # COLONY_DATA_DIR, SCRIPT_DIR, error constants) is available.
8
+ #
9
+ # Subcommand: curation-nurse [--dry-run]
10
+ # Recalculates trust scores for all observations (that have source_type/evidence_type)
11
+ # and applies trust-decay to instincts based on days since created_at.
12
+
13
+ # ============================================================================
14
+ # _curation_nurse
15
+ # Recalculate trust scores across observations and instincts.
16
+ #
17
+ # Usage: curation-nurse [--dry-run]
18
+ #
19
+ # Output: {observations_updated: N, instincts_updated: N, dry_run: bool}
20
+ # ============================================================================
21
+ _curation_nurse() {
22
+ local dry_run="false"
23
+
24
+ while [[ $# -gt 0 ]]; do
25
+ case "$1" in
26
+ --dry-run) dry_run="true"; shift ;;
27
+ *) shift ;;
28
+ esac
29
+ done
30
+
31
+ local obs_updated=0
32
+ local inst_updated=0
33
+ local obs_file="$COLONY_DATA_DIR/learning-observations.json"
34
+ local inst_file="$COLONY_DATA_DIR/instincts.json"
35
+ local now_epoch
36
+ now_epoch=$(date -u +%s)
37
+
38
+ # ── Recalculate observation trust scores ──────────────────────────────────
39
+ if [[ -f "$obs_file" ]]; then
40
+ local obs_count
41
+ obs_count=$(jq '[.observations[] | select(.source_type != null and .evidence_type != null)] | length' "$obs_file" 2>/dev/null || echo 0)
42
+
43
+ if [[ "$obs_count" -gt 0 ]]; then
44
+ local updated_obs
45
+ updated_obs=$(jq -c '[.observations[]]' "$obs_file" 2>/dev/null || echo "[]")
46
+
47
+ local new_obs_array="[]"
48
+ while IFS= read -r obs_json; do
49
+ local source_type evidence_type last_seen
50
+ source_type=$(echo "$obs_json" | jq -r '.source_type // empty')
51
+ evidence_type=$(echo "$obs_json" | jq -r '.evidence_type // empty')
52
+ last_seen=$(echo "$obs_json" | jq -r '.last_seen // empty')
53
+
54
+ if [[ -z "$source_type" || -z "$evidence_type" ]]; then
55
+ new_obs_array=$(echo "$new_obs_array" | jq --argjson entry "$obs_json" '. += [$entry]')
56
+ continue
57
+ fi
58
+
59
+ local days_since=0
60
+ if [[ -n "$last_seen" ]]; then
61
+ local last_epoch
62
+ last_epoch=$(date -u -d "$last_seen" +%s 2>/dev/null || date -u -j -f "%Y-%m-%dT%H:%M:%SZ" "$last_seen" +%s 2>/dev/null || echo "$now_epoch")
63
+ days_since=$(( (now_epoch - last_epoch) / 86400 ))
64
+ [[ "$days_since" -lt 0 ]] && days_since=0
65
+ fi
66
+
67
+ local trust_result trust_score trust_tier
68
+ trust_result=$(_trust_calculate --source "$source_type" --evidence "$evidence_type" --days-since "$days_since" 2>/dev/null) || true
69
+ if echo "$trust_result" | jq -e '.ok == true' >/dev/null 2>&1; then
70
+ trust_score=$(echo "$trust_result" | jq -r '.result.score')
71
+ trust_tier=$(echo "$trust_result" | jq -r '.result.tier')
72
+ local updated_entry
73
+ updated_entry=$(echo "$obs_json" | jq \
74
+ --argjson score "$trust_score" \
75
+ --arg tier "$trust_tier" \
76
+ '. + {trust_score: $score, trust_tier: $tier}')
77
+ new_obs_array=$(echo "$new_obs_array" | jq --argjson entry "$updated_entry" '. += [$entry]')
78
+ obs_updated=$((obs_updated + 1))
79
+ else
80
+ new_obs_array=$(echo "$new_obs_array" | jq --argjson entry "$obs_json" '. += [$entry]')
81
+ fi
82
+ done < <(echo "$updated_obs" | jq -c '.[]')
83
+
84
+ if [[ "$dry_run" != "true" ]]; then
85
+ local final_obs
86
+ final_obs=$(jq --argjson obs "$new_obs_array" '.observations = $obs' "$obs_file" 2>/dev/null) || true
87
+ [[ -n "$final_obs" ]] && atomic_write "$obs_file" "$final_obs"
88
+ fi
89
+ fi
90
+ fi
91
+
92
+ # ── Apply trust-decay to instincts ────────────────────────────────────────
93
+ if [[ -f "$inst_file" ]]; then
94
+ local active_count
95
+ active_count=$(jq '[.instincts[] | select(.archived == false)] | length' "$inst_file" 2>/dev/null || echo 0)
96
+
97
+ if [[ "$active_count" -gt 0 ]]; then
98
+ local updated_inst_array="[]"
99
+ local all_inst
100
+ all_inst=$(jq -c '[.instincts[]]' "$inst_file" 2>/dev/null || echo "[]")
101
+
102
+ while IFS= read -r inst_json; do
103
+ local archived
104
+ archived=$(echo "$inst_json" | jq -r '.archived // false')
105
+
106
+ if [[ "$archived" == "true" ]]; then
107
+ updated_inst_array=$(echo "$updated_inst_array" | jq --argjson entry "$inst_json" '. += [$entry]')
108
+ continue
109
+ fi
110
+
111
+ local created_at days_inst=0
112
+ created_at=$(echo "$inst_json" | jq -r '.provenance.created_at // empty')
113
+ if [[ -n "$created_at" ]]; then
114
+ local created_epoch
115
+ created_epoch=$(date -u -d "$created_at" +%s 2>/dev/null || date -u -j -f "%Y-%m-%dT%H:%M:%SZ" "$created_at" +%s 2>/dev/null || echo "$now_epoch")
116
+ days_inst=$(( (now_epoch - created_epoch) / 86400 ))
117
+ [[ "$days_inst" -lt 0 ]] && days_inst=0
118
+ fi
119
+
120
+ local current_score
121
+ current_score=$(echo "$inst_json" | jq -r '.trust_score // 0.5')
122
+ local decay_result decayed_score new_tier
123
+ decay_result=$(_trust_decay --score "$current_score" --days "$days_inst" 2>/dev/null) || true
124
+
125
+ if echo "$decay_result" | jq -e '.ok == true' >/dev/null 2>&1; then
126
+ decayed_score=$(echo "$decay_result" | jq -r '.result.decayed')
127
+ new_tier=$(_trust_score_to_tier "$decayed_score" 2>/dev/null || echo "dormant")
128
+ local updated_entry
129
+ updated_entry=$(echo "$inst_json" | jq \
130
+ --argjson score "$decayed_score" \
131
+ --arg tier "$new_tier" \
132
+ '.trust_score = $score | .trust_tier = $tier')
133
+ updated_inst_array=$(echo "$updated_inst_array" | jq --argjson entry "$updated_entry" '. += [$entry]')
134
+ inst_updated=$((inst_updated + 1))
135
+ else
136
+ updated_inst_array=$(echo "$updated_inst_array" | jq --argjson entry "$inst_json" '. += [$entry]')
137
+ fi
138
+ done < <(echo "$all_inst" | jq -c '.[]')
139
+
140
+ if [[ "$dry_run" != "true" ]]; then
141
+ local final_inst
142
+ final_inst=$(jq --argjson insts "$updated_inst_array" '.instincts = $insts' "$inst_file" 2>/dev/null) || true
143
+ [[ -n "$final_inst" ]] && atomic_write "$inst_file" "$final_inst"
144
+ fi
145
+ fi
146
+ fi
147
+
148
+ json_ok "$(jq -n \
149
+ --argjson obs "$obs_updated" \
150
+ --argjson inst "$inst_updated" \
151
+ --argjson dry "$([ "$dry_run" == "true" ] && echo true || echo false)" \
152
+ '{observations_updated: $obs, instincts_updated: $inst, dry_run: $dry}')"
153
+ }
@@ -0,0 +1,181 @@
1
+ #!/bin/bash
2
+ # Curation Orchestrator — runs all 8 curation ants in sequence
3
+ # Provides: _curation_run
4
+ #
5
+ # These functions are sourced by aether-utils.sh at startup.
6
+ # All shared infrastructure (json_ok, json_err, COLONY_DATA_DIR, DATA_DIR,
7
+ # error constants) is available when sourced.
8
+
9
+ # ============================================================================
10
+ # _curation_run
11
+ # Run all 8 curation ants in the correct order.
12
+ #
13
+ # Usage: curation-run [--dry-run] [--verbose]
14
+ #
15
+ # Execution order:
16
+ # 1. sentinel — health check (abort if corrupt)
17
+ # 2. nurse — recalculate trust scores
18
+ # 3. critic — detect contradictions
19
+ # 4. herald — promote high-trust to QUEEN.md
20
+ # 5. janitor — clean expired events/archives
21
+ # 6. archivist — archive low-trust instincts
22
+ # 7. librarian — inventory stats
23
+ # 8. scribe — generate report
24
+ #
25
+ # Output: json_ok with {steps, total_steps, succeeded, failed, dry_run,
26
+ # report_path, duration_ms}
27
+ # ============================================================================
28
+ _curation_run() {
29
+ local dry_run="false"
30
+
31
+ while [[ $# -gt 0 ]]; do
32
+ case "$1" in
33
+ --dry-run) dry_run="true"; shift ;;
34
+ --verbose) shift ;;
35
+ *) shift ;;
36
+ esac
37
+ done
38
+
39
+ # Portable millisecond timer: try python3, fall back to seconds*1000
40
+ local start_ms
41
+ start_ms=$(python3 -c "import time; print(int(time.time()*1000))" 2>/dev/null \
42
+ || echo $(( $(date +%s) * 1000 )))
43
+
44
+ local steps_json="[]"
45
+ local succeeded=0
46
+ local failed=0
47
+ local report_path="null"
48
+ # Shared variable: holds the raw JSON result of the last step executed
49
+ local _CR_LAST_RESULT=""
50
+
51
+ # _cr_step <name> [extra_args...]
52
+ # Runs curation-<name> (with --dry-run if set), updates steps_json,
53
+ # succeeded/failed counters, and sets _CR_LAST_RESULT.
54
+ # Must be called WITHOUT command substitution so variable mutations persist.
55
+ _cr_step() {
56
+ local step_name="$1"
57
+ shift
58
+
59
+ local cmd="curation-${step_name}"
60
+
61
+ # Build the args list (avoid empty-array nounset issues)
62
+ local step_result step_status step_summary
63
+ if [[ "$dry_run" == "true" && $# -gt 0 ]]; then
64
+ step_result=$(bash "$0" "$cmd" "--dry-run" "$@" 2>/dev/null) || true
65
+ elif [[ "$dry_run" == "true" ]]; then
66
+ step_result=$(bash "$0" "$cmd" "--dry-run" 2>/dev/null) || true
67
+ elif [[ $# -gt 0 ]]; then
68
+ step_result=$(bash "$0" "$cmd" "$@" 2>/dev/null) || true
69
+ else
70
+ step_result=$(bash "$0" "$cmd" 2>/dev/null) || true
71
+ fi
72
+
73
+ _CR_LAST_RESULT="$step_result"
74
+
75
+ if echo "$step_result" | jq -e '.ok == true' >/dev/null 2>&1; then
76
+ step_status="ok"
77
+ step_summary=$(echo "$step_result" | jq -r '
78
+ .result |
79
+ if type == "object" then
80
+ [ to_entries[] | "\(.key) \(.value)" ] | join(", ")
81
+ else
82
+ tostring
83
+ end
84
+ ' 2>/dev/null | head -c 120 || echo "ok")
85
+ [[ -z "$step_summary" ]] && step_summary="ok"
86
+ succeeded=$(( succeeded + 1 ))
87
+ else
88
+ step_status="failed"
89
+ local err_msg
90
+ err_msg=$(echo "$step_result" | jq -r '.error // "unknown error"' 2>/dev/null || echo "unknown error")
91
+ step_summary="$err_msg"
92
+ failed=$(( failed + 1 ))
93
+ fi
94
+
95
+ steps_json=$(echo "$steps_json" | jq \
96
+ --arg name "$step_name" \
97
+ --arg status "$step_status" \
98
+ --arg summary "$step_summary" \
99
+ '. += [{"name": $name, "status": $status, "summary": $summary}]')
100
+ }
101
+
102
+ # ── Step 1: Sentinel — health check ─────────────────────────────────────
103
+ _cr_step "sentinel"
104
+
105
+ # Abort remaining steps if sentinel found critical corruption
106
+ local sentinel_status
107
+ sentinel_status=$(echo "$steps_json" | jq -r '.[-1].status')
108
+ if [[ "$sentinel_status" == "ok" ]]; then
109
+ local corrupt_count
110
+ corrupt_count=$(echo "$_CR_LAST_RESULT" | jq '[.result.checks[]? | select(.status == "corrupt")] | length' 2>/dev/null || echo 0)
111
+ if [[ "$corrupt_count" -gt 0 ]]; then
112
+ for skipped_step in nurse critic herald janitor archivist librarian scribe; do
113
+ steps_json=$(echo "$steps_json" | jq \
114
+ --arg name "$skipped_step" \
115
+ '. += [{"name": $name, "status": "skipped", "summary": "skipped: sentinel detected corrupt stores"}]')
116
+ done
117
+
118
+ local end_ms
119
+ end_ms=$(python3 -c "import time; print(int(time.time()*1000))" 2>/dev/null \
120
+ || echo $(( $(date +%s) * 1000 )))
121
+ local duration_ms=$(( end_ms - start_ms ))
122
+
123
+ json_ok "$(jq -n \
124
+ --argjson steps "$steps_json" \
125
+ --argjson total 8 \
126
+ --argjson succeeded "$succeeded" \
127
+ --argjson failed "$failed" \
128
+ --argjson dry "$([ "$dry_run" == "true" ] && echo true || echo false)" \
129
+ --argjson dur "$duration_ms" \
130
+ '{steps:$steps, total_steps:$total, succeeded:$succeeded, failed:$failed,
131
+ dry_run:$dry, report_path:null, duration_ms:$dur}')"
132
+ return
133
+ fi
134
+ fi
135
+
136
+ # ── Step 2: Nurse — recalculate trust scores ─────────────────────────────
137
+ _cr_step "nurse"
138
+
139
+ # ── Step 3: Critic — detect contradictions ───────────────────────────────
140
+ _cr_step "critic"
141
+
142
+ # ── Step 4: Herald — promote high-trust to QUEEN.md ─────────────────────
143
+ _cr_step "herald"
144
+
145
+ # ── Step 5: Janitor — clean expired events and archives ──────────────────
146
+ _cr_step "janitor"
147
+
148
+ # ── Step 6: Archivist — archive low-trust instincts ─────────────────────
149
+ _cr_step "archivist"
150
+
151
+ # ── Step 7: Librarian — inventory stats ──────────────────────────────────
152
+ _cr_step "librarian"
153
+
154
+ # ── Step 8: Scribe — generate report ─────────────────────────────────────
155
+ _cr_step "scribe"
156
+
157
+ # Extract report_path from scribe result
158
+ if echo "$_CR_LAST_RESULT" | jq -e '.ok == true' >/dev/null 2>&1; then
159
+ local raw_path
160
+ raw_path=$(echo "$_CR_LAST_RESULT" | jq -r '.result.report_path // empty' 2>/dev/null || echo "")
161
+ if [[ -n "$raw_path" ]]; then
162
+ report_path=$(printf '%s' "$raw_path" | jq -Rs '.')
163
+ fi
164
+ fi
165
+
166
+ local end_ms
167
+ end_ms=$(python3 -c "import time; print(int(time.time()*1000))" 2>/dev/null \
168
+ || echo $(( $(date +%s) * 1000 )))
169
+ local duration_ms=$(( end_ms - start_ms ))
170
+
171
+ json_ok "$(jq -n \
172
+ --argjson steps "$steps_json" \
173
+ --argjson total 8 \
174
+ --argjson succeeded "$succeeded" \
175
+ --argjson failed "$failed" \
176
+ --argjson dry "$([ "$dry_run" == "true" ] && echo true || echo false)" \
177
+ --argjson report_path "$report_path" \
178
+ --argjson dur "$duration_ms" \
179
+ '{steps:$steps, total_steps:$total, succeeded:$succeeded, failed:$failed,
180
+ dry_run:$dry, report_path:$report_path, duration_ms:$dur}')"
181
+ }
@@ -0,0 +1,164 @@
1
+ #!/bin/bash
2
+ # Curation Scribe — Memory Consolidation Report Generation
3
+ # Generates a markdown report of the memory consolidation state.
4
+ #
5
+ # Functions:
6
+ # _curation_scribe
7
+ #
8
+ # These functions are sourced by aether-utils.sh at startup.
9
+ # All shared infrastructure (json_ok, json_err, COLONY_DATA_DIR, DATA_DIR,
10
+ # error constants) is available when sourced.
11
+
12
+ # ============================================================================
13
+ # _curation_scribe
14
+ # Generate a markdown report of memory consolidation state.
15
+ # Usage: curation-scribe [--output <path>]
16
+ #
17
+ # Default output: $COLONY_DATA_DIR/curation-report.md
18
+ # Output: json_ok with {report_path:string, sections:N, generated_at:"ISO"}
19
+ # ============================================================================
20
+ _curation_scribe() {
21
+ local csc_output=""
22
+
23
+ while [[ $# -gt 0 ]]; do
24
+ case "$1" in
25
+ --output)
26
+ csc_output="${2:-}"
27
+ shift 2
28
+ ;;
29
+ *)
30
+ shift
31
+ ;;
32
+ esac
33
+ done
34
+
35
+ local csc_data_dir="${COLONY_DATA_DIR:-${DATA_DIR:-}}"
36
+ if [[ -z "$csc_data_dir" ]]; then
37
+ json_err "$E_VALIDATION_FAILED" "curation-scribe: COLONY_DATA_DIR is not set"
38
+ fi
39
+
40
+ [[ -z "$csc_output" ]] && csc_output="$csc_data_dir/curation-report.md"
41
+
42
+ local csc_ts
43
+ csc_ts=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
44
+ local csc_ts_human
45
+ csc_ts_human=$(date -u +"%Y-%m-%d %H:%M UTC")
46
+
47
+ # Step 1: Gather librarian stats (via curation-librarian subcommand if available)
48
+ local csc_total_instincts=0
49
+ local csc_active_instincts=0
50
+ local csc_archived_instincts=0
51
+ local csc_total_observations=0
52
+ local csc_total_events=0
53
+
54
+ local csc_lib_result
55
+ if csc_lib_result=$(COLONY_DATA_DIR="$csc_data_dir" DATA_DIR="$csc_data_dir" \
56
+ bash "$0" curation-librarian 2>/dev/null); then
57
+ if echo "$csc_lib_result" | jq -e '.ok == true' >/dev/null 2>&1; then
58
+ csc_total_instincts=$(echo "$csc_lib_result" | jq '.result.total_instincts // 0')
59
+ csc_active_instincts=$(echo "$csc_lib_result" | jq '.result.active_instincts // 0')
60
+ csc_archived_instincts=$(echo "$csc_lib_result"| jq '.result.archived_instincts // 0')
61
+ csc_total_observations=$(echo "$csc_lib_result"| jq '.result.total_observations // 0')
62
+ csc_total_events=$(echo "$csc_lib_result" | jq '.result.total_events // 0')
63
+ fi
64
+ else
65
+ # Gather stats directly if librarian is not yet available
66
+ local csc_instincts_file="$csc_data_dir/instincts.json"
67
+ if [[ -f "$csc_instincts_file" ]] && jq empty "$csc_instincts_file" 2>/dev/null; then
68
+ csc_total_instincts=$(jq '.instincts | length' "$csc_instincts_file" 2>/dev/null || echo 0)
69
+ csc_active_instincts=$(jq '[.instincts[] | select(.archived != true)] | length' "$csc_instincts_file" 2>/dev/null || echo 0)
70
+ csc_archived_instincts=$(jq '[.instincts[] | select(.archived == true)] | length' "$csc_instincts_file" 2>/dev/null || echo 0)
71
+ fi
72
+
73
+ local csc_obs_file="$csc_data_dir/learning-observations.json"
74
+ if [[ -f "$csc_obs_file" ]] && jq empty "$csc_obs_file" 2>/dev/null; then
75
+ csc_total_observations=$(jq '.observations | length' "$csc_obs_file" 2>/dev/null || echo 0)
76
+ fi
77
+
78
+ local csc_eb_file="$csc_data_dir/event-bus.jsonl"
79
+ if [[ -f "$csc_eb_file" ]]; then
80
+ csc_total_events=$(wc -l < "$csc_eb_file" | tr -d ' ')
81
+ fi
82
+ fi
83
+
84
+ # Step 2: Gather top 5 trusted instincts
85
+ local csc_top_instincts=""
86
+ local csc_instincts_file="$csc_data_dir/instincts.json"
87
+ if [[ -f "$csc_instincts_file" ]] && jq empty "$csc_instincts_file" 2>/dev/null; then
88
+ csc_top_instincts=$(jq -r \
89
+ '[.instincts[] | select(.archived != true)] | sort_by(-.trust_score // -.confidence // 0) | .[0:5][] |
90
+ "- **[\(.trust_score // .confidence // 0 | . * 100 | floor)%]** \(.trigger // "unknown trigger")"' \
91
+ "$csc_instincts_file" 2>/dev/null || echo "")
92
+ fi
93
+ [[ -z "$csc_top_instincts" ]] && csc_top_instincts="_No instincts found._"
94
+
95
+ # Step 3: Gather recent events (last 10)
96
+ local csc_recent_events=""
97
+ local csc_eb_file="$csc_data_dir/event-bus.jsonl"
98
+ if [[ -f "$csc_eb_file" ]] && [[ -s "$csc_eb_file" ]]; then
99
+ csc_recent_events=$(tail -10 "$csc_eb_file" | \
100
+ jq -r '"- [\(.timestamp // "?")] **\(.topic // "unknown")**: \(.source // "system")"' \
101
+ 2>/dev/null || echo "")
102
+ fi
103
+ [[ -z "$csc_recent_events" ]] && csc_recent_events="_No recent events._"
104
+
105
+ # Step 4: Generate recommendations
106
+ local csc_recommendations=""
107
+ if [[ "$csc_active_instincts" -gt 40 ]]; then
108
+ csc_recommendations+="- Run \`curation-archivist\` to archive low-trust instincts (capacity at ${csc_active_instincts}/50)."$'\n'
109
+ fi
110
+ if [[ "$csc_total_events" -gt 100 ]]; then
111
+ csc_recommendations+="- Run \`curation-janitor\` to clean up expired events (${csc_total_events} events on bus)."$'\n'
112
+ fi
113
+ if [[ "$csc_total_observations" -gt 200 ]]; then
114
+ csc_recommendations+="- Consider pruning stale learning observations (${csc_total_observations} total)."$'\n'
115
+ fi
116
+ [[ -z "$csc_recommendations" ]] && csc_recommendations="_Memory stores are healthy. No immediate action needed._"
117
+
118
+ # Step 5: Write report
119
+ mkdir -p "$(dirname "$csc_output")"
120
+
121
+ cat > "$csc_output" <<REPORT
122
+ # Memory Consolidation Report
123
+
124
+ _Generated: ${csc_ts_human}_
125
+
126
+ ---
127
+
128
+ ## Memory Health Summary
129
+
130
+ | Store | Count |
131
+ |-------|-------|
132
+ | Total instincts | ${csc_total_instincts} |
133
+ | Active instincts | ${csc_active_instincts} |
134
+ | Archived instincts | ${csc_archived_instincts} |
135
+ | Learning observations | ${csc_total_observations} |
136
+ | Events on bus | ${csc_total_events} |
137
+
138
+ ---
139
+
140
+ ## Top Trusted Instincts
141
+
142
+ ${csc_top_instincts}
143
+
144
+ ---
145
+
146
+ ## Recent Events
147
+
148
+ ${csc_recent_events}
149
+
150
+ ---
151
+
152
+ ## Recommendations
153
+
154
+ ${csc_recommendations}
155
+ REPORT
156
+
157
+ local csc_sections=4
158
+
159
+ json_ok "$(jq -nc \
160
+ --arg report_path "$csc_output" \
161
+ --argjson sections "$csc_sections" \
162
+ --arg generated_at "$csc_ts" \
163
+ '{report_path:$report_path, sections:$sections, generated_at:$generated_at}')"
164
+ }
@@ -0,0 +1,119 @@
1
+ #!/bin/bash
2
+ # Curation Sentinel — Memory Health Monitoring
3
+ # Checks health of all memory stores and reports issues.
4
+ #
5
+ # Functions:
6
+ # _curation_sentinel
7
+ #
8
+ # These functions are sourced by aether-utils.sh at startup.
9
+ # All shared infrastructure (json_ok, json_err, COLONY_DATA_DIR, DATA_DIR,
10
+ # error constants) is available when sourced.
11
+
12
+ # ============================================================================
13
+ # _curation_sentinel
14
+ # Check health of all memory stores.
15
+ # Usage: curation-sentinel
16
+ #
17
+ # Output: json_ok with {checks:[{store,status,details}], healthy:N, issues:N}
18
+ # ============================================================================
19
+ _curation_sentinel() {
20
+ local cs_data_dir="${COLONY_DATA_DIR:-${DATA_DIR:-}}"
21
+ if [[ -z "$cs_data_dir" ]]; then
22
+ json_err "$E_VALIDATION_FAILED" "curation-sentinel: COLONY_DATA_DIR is not set"
23
+ fi
24
+
25
+ local cs_checks_json="[]"
26
+ local cs_healthy=0
27
+ local cs_issues=0
28
+
29
+ # Helper: append a check entry
30
+ # status "healthy" increments healthy; "optional_missing" is neutral;
31
+ # all other statuses (missing, corrupt, empty) increment issues.
32
+ _cs_add_check() {
33
+ local store="$1"
34
+ local status="$2"
35
+ local details="$3"
36
+
37
+ cs_checks_json=$(echo "$cs_checks_json" | jq \
38
+ --arg store "$store" \
39
+ --arg status "$status" \
40
+ --arg details "$details" \
41
+ '. += [{store:$store, status:$status, details:$details}]')
42
+
43
+ if [[ "$status" == "healthy" ]]; then
44
+ cs_healthy=$(( cs_healthy + 1 ))
45
+ elif [[ "$status" != "optional_missing" ]]; then
46
+ cs_issues=$(( cs_issues + 1 ))
47
+ fi
48
+ }
49
+
50
+ # Helper: check a JSON file
51
+ _cs_check_json_file() {
52
+ local store="$1"
53
+ local filepath="$2"
54
+ local required="${3:-false}"
55
+
56
+ if [[ ! -f "$filepath" ]]; then
57
+ if [[ "$required" == "true" ]]; then
58
+ _cs_add_check "$store" "missing" "Required file not found: $filepath"
59
+ else
60
+ _cs_add_check "$store" "optional_missing" "Optional file not found: $filepath"
61
+ fi
62
+ return
63
+ fi
64
+
65
+ if [[ ! -s "$filepath" ]]; then
66
+ _cs_add_check "$store" "empty" "File exists but is empty: $filepath"
67
+ return
68
+ fi
69
+
70
+ if ! jq empty "$filepath" 2>/dev/null; then
71
+ _cs_add_check "$store" "corrupt" "File contains invalid JSON: $filepath"
72
+ return
73
+ fi
74
+
75
+ _cs_add_check "$store" "healthy" "OK"
76
+ }
77
+
78
+ # 1. learning-observations.json
79
+ _cs_check_json_file "learning-observations" \
80
+ "$cs_data_dir/learning-observations.json" "false"
81
+
82
+ # 2. instincts.json (optional)
83
+ _cs_check_json_file "instincts" \
84
+ "$cs_data_dir/instincts.json" "false"
85
+
86
+ # 3. instinct-graph.json (optional)
87
+ _cs_check_json_file "instinct-graph" \
88
+ "$cs_data_dir/instinct-graph.json" "false"
89
+
90
+ # 4. event-bus.jsonl (optional — check last line if exists)
91
+ local eb_file="$cs_data_dir/event-bus.jsonl"
92
+ if [[ ! -f "$eb_file" ]]; then
93
+ _cs_add_check "event-bus" "optional_missing" "Optional file not found: $eb_file"
94
+ elif [[ ! -s "$eb_file" ]]; then
95
+ _cs_add_check "event-bus" "healthy" "File is empty (no events)"
96
+ else
97
+ local last_line
98
+ last_line=$(tail -1 "$eb_file")
99
+ if echo "$last_line" | jq empty 2>/dev/null; then
100
+ _cs_add_check "event-bus" "healthy" "OK"
101
+ else
102
+ _cs_add_check "event-bus" "corrupt" "Last line is not valid JSON"
103
+ fi
104
+ fi
105
+
106
+ # 5. pheromones.json (required)
107
+ _cs_check_json_file "pheromones" \
108
+ "$cs_data_dir/pheromones.json" "true"
109
+
110
+ # 6. COLONY_STATE.json (required)
111
+ _cs_check_json_file "COLONY_STATE" \
112
+ "$cs_data_dir/COLONY_STATE.json" "true"
113
+
114
+ json_ok "$(jq -nc \
115
+ --argjson checks "$cs_checks_json" \
116
+ --argjson healthy "$cs_healthy" \
117
+ --argjson issues "$cs_issues" \
118
+ '{checks:$checks, healthy:$healthy, issues:$issues}')"
119
+ }