aether-colony 5.3.2 → 5.3.3
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/.aether/aether-utils.sh +181 -5
- package/.aether/commands/build.yaml +35 -0
- package/.aether/commands/entomb.yaml +1 -1
- package/.aether/commands/init.yaml +29 -12
- package/.aether/commands/oracle.yaml +70 -0
- package/.aether/commands/patrol.yaml +2 -2
- package/.aether/commands/run.yaml +3 -3
- package/.aether/commands/swarm.yaml +1 -1
- package/.aether/docs/command-playbooks/build-complete.md +41 -8
- package/.aether/docs/command-playbooks/build-full.md +7 -7
- package/.aether/docs/command-playbooks/build-prep.md +1 -1
- package/.aether/docs/command-playbooks/continue-advance.md +33 -0
- package/.aether/docs/command-playbooks/continue-finalize.md +15 -1
- package/.aether/docs/command-playbooks/continue-full.md +15 -1
- package/.aether/docs/source-of-truth-map.md +10 -10
- package/.aether/docs/structural-learning-stack.md +283 -0
- package/.aether/utils/consolidation-seal.sh +196 -0
- package/.aether/utils/consolidation.sh +127 -0
- package/.aether/utils/curation-ants/archivist.sh +97 -0
- package/.aether/utils/curation-ants/critic.sh +214 -0
- package/.aether/utils/curation-ants/herald.sh +102 -0
- package/.aether/utils/curation-ants/janitor.sh +121 -0
- package/.aether/utils/curation-ants/librarian.sh +99 -0
- package/.aether/utils/curation-ants/nurse.sh +153 -0
- package/.aether/utils/curation-ants/orchestrator.sh +181 -0
- package/.aether/utils/curation-ants/scribe.sh +164 -0
- package/.aether/utils/curation-ants/sentinel.sh +119 -0
- package/.aether/utils/event-bus.sh +301 -0
- package/.aether/utils/graph.sh +559 -0
- package/.aether/utils/instinct-store.sh +401 -0
- package/.aether/utils/learning.sh +79 -7
- package/.aether/utils/session.sh +13 -0
- package/.aether/utils/state-api.sh +1 -1
- package/.aether/utils/trust-scoring.sh +347 -0
- package/.aether/utils/worktree.sh +97 -0
- package/.claude/commands/ant/entomb.md +1 -1
- package/.claude/commands/ant/init.md +29 -12
- package/.claude/commands/ant/oracle.md +35 -0
- package/.claude/commands/ant/patrol.md +2 -2
- package/.claude/commands/ant/run.md +3 -3
- package/.claude/commands/ant/swarm.md +1 -1
- package/.opencode/commands/ant/build.md +35 -0
- package/.opencode/commands/ant/init.md +29 -12
- package/.opencode/commands/ant/oracle.md +35 -0
- package/.opencode/commands/ant/patrol.md +2 -2
- package/.opencode/commands/ant/run.md +3 -3
- package/CHANGELOG.md +83 -0
- package/README.md +22 -9
- package/bin/lib/update-transaction.js +8 -3
- package/bin/npx-entry.js +0 -0
- package/package.json +1 -1
- package/.aether/agents/aether-ambassador.md +0 -140
- package/.aether/agents/aether-archaeologist.md +0 -108
- package/.aether/agents/aether-architect.md +0 -133
- package/.aether/agents/aether-auditor.md +0 -144
- package/.aether/agents/aether-builder.md +0 -184
- package/.aether/agents/aether-chaos.md +0 -115
- package/.aether/agents/aether-chronicler.md +0 -122
- package/.aether/agents/aether-gatekeeper.md +0 -116
- package/.aether/agents/aether-includer.md +0 -117
- package/.aether/agents/aether-keeper.md +0 -177
- package/.aether/agents/aether-measurer.md +0 -128
- package/.aether/agents/aether-oracle.md +0 -137
- package/.aether/agents/aether-probe.md +0 -133
- package/.aether/agents/aether-queen.md +0 -286
- package/.aether/agents/aether-route-setter.md +0 -130
- package/.aether/agents/aether-sage.md +0 -106
- package/.aether/agents/aether-scout.md +0 -101
- package/.aether/agents/aether-surveyor-disciplines.md +0 -391
- package/.aether/agents/aether-surveyor-nest.md +0 -329
- package/.aether/agents/aether-surveyor-pathogens.md +0 -264
- package/.aether/agents/aether-surveyor-provisions.md +0 -334
- package/.aether/agents/aether-tracker.md +0 -137
- package/.aether/agents/aether-watcher.md +0 -174
- package/.aether/agents/aether-weaver.md +0 -130
- package/.aether/commands/claude/archaeology.md +0 -334
- package/.aether/commands/claude/build.md +0 -65
- package/.aether/commands/claude/chaos.md +0 -336
- package/.aether/commands/claude/colonize.md +0 -259
- package/.aether/commands/claude/continue.md +0 -60
- package/.aether/commands/claude/council.md +0 -507
- package/.aether/commands/claude/data-clean.md +0 -81
- package/.aether/commands/claude/dream.md +0 -268
- package/.aether/commands/claude/entomb.md +0 -498
- package/.aether/commands/claude/export-signals.md +0 -57
- package/.aether/commands/claude/feedback.md +0 -96
- package/.aether/commands/claude/flag.md +0 -151
- package/.aether/commands/claude/flags.md +0 -169
- package/.aether/commands/claude/focus.md +0 -76
- package/.aether/commands/claude/help.md +0 -154
- package/.aether/commands/claude/history.md +0 -140
- package/.aether/commands/claude/import-signals.md +0 -71
- package/.aether/commands/claude/init.md +0 -505
- package/.aether/commands/claude/insert-phase.md +0 -105
- package/.aether/commands/claude/interpret.md +0 -278
- package/.aether/commands/claude/lay-eggs.md +0 -210
- package/.aether/commands/claude/maturity.md +0 -113
- package/.aether/commands/claude/memory-details.md +0 -77
- package/.aether/commands/claude/migrate-state.md +0 -171
- package/.aether/commands/claude/oracle.md +0 -642
- package/.aether/commands/claude/organize.md +0 -232
- package/.aether/commands/claude/patrol.md +0 -620
- package/.aether/commands/claude/pause-colony.md +0 -233
- package/.aether/commands/claude/phase.md +0 -115
- package/.aether/commands/claude/pheromones.md +0 -156
- package/.aether/commands/claude/plan.md +0 -693
- package/.aether/commands/claude/preferences.md +0 -65
- package/.aether/commands/claude/quick.md +0 -100
- package/.aether/commands/claude/redirect.md +0 -76
- package/.aether/commands/claude/resume-colony.md +0 -197
- package/.aether/commands/claude/resume.md +0 -388
- package/.aether/commands/claude/run.md +0 -231
- package/.aether/commands/claude/seal.md +0 -774
- package/.aether/commands/claude/skill-create.md +0 -286
- package/.aether/commands/claude/status.md +0 -410
- package/.aether/commands/claude/swarm.md +0 -349
- package/.aether/commands/claude/tunnels.md +0 -426
- package/.aether/commands/claude/update.md +0 -132
- package/.aether/commands/claude/verify-castes.md +0 -143
- package/.aether/commands/claude/watch.md +0 -239
- package/.aether/commands/opencode/archaeology.md +0 -331
- package/.aether/commands/opencode/build.md +0 -1168
- package/.aether/commands/opencode/chaos.md +0 -329
- package/.aether/commands/opencode/colonize.md +0 -195
- package/.aether/commands/opencode/continue.md +0 -1436
- package/.aether/commands/opencode/council.md +0 -437
- package/.aether/commands/opencode/data-clean.md +0 -77
- package/.aether/commands/opencode/dream.md +0 -260
- package/.aether/commands/opencode/entomb.md +0 -377
- package/.aether/commands/opencode/export-signals.md +0 -54
- package/.aether/commands/opencode/feedback.md +0 -99
- package/.aether/commands/opencode/flag.md +0 -149
- package/.aether/commands/opencode/flags.md +0 -167
- package/.aether/commands/opencode/focus.md +0 -73
- package/.aether/commands/opencode/help.md +0 -157
- package/.aether/commands/opencode/history.md +0 -136
- package/.aether/commands/opencode/import-signals.md +0 -68
- package/.aether/commands/opencode/init.md +0 -518
- package/.aether/commands/opencode/insert-phase.md +0 -111
- package/.aether/commands/opencode/interpret.md +0 -272
- package/.aether/commands/opencode/lay-eggs.md +0 -213
- package/.aether/commands/opencode/maturity.md +0 -108
- package/.aether/commands/opencode/memory-details.md +0 -83
- package/.aether/commands/opencode/migrate-state.md +0 -165
- package/.aether/commands/opencode/oracle.md +0 -593
- package/.aether/commands/opencode/organize.md +0 -226
- package/.aether/commands/opencode/patrol.md +0 -626
- package/.aether/commands/opencode/pause-colony.md +0 -203
- package/.aether/commands/opencode/phase.md +0 -113
- package/.aether/commands/opencode/pheromones.md +0 -162
- package/.aether/commands/opencode/plan.md +0 -684
- package/.aether/commands/opencode/preferences.md +0 -71
- package/.aether/commands/opencode/quick.md +0 -91
- package/.aether/commands/opencode/redirect.md +0 -84
- package/.aether/commands/opencode/resume-colony.md +0 -190
- package/.aether/commands/opencode/resume.md +0 -394
- package/.aether/commands/opencode/run.md +0 -237
- package/.aether/commands/opencode/seal.md +0 -452
- package/.aether/commands/opencode/skill-create.md +0 -63
- package/.aether/commands/opencode/status.md +0 -307
- package/.aether/commands/opencode/swarm.md +0 -15
- package/.aether/commands/opencode/tunnels.md +0 -400
- package/.aether/commands/opencode/update.md +0 -127
- package/.aether/commands/opencode/verify-castes.md +0 -139
- package/.aether/commands/opencode/watch.md +0 -227
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Librarian curation ant — inventory statistics across all memory stores
|
|
3
|
+
# Provides: _curation_librarian
|
|
4
|
+
#
|
|
5
|
+
# These functions are sourced by aether-utils.sh at startup.
|
|
6
|
+
# All shared infrastructure (json_ok, json_err, COLONY_DATA_DIR, error constants)
|
|
7
|
+
# is available.
|
|
8
|
+
#
|
|
9
|
+
# Subcommand: curation-librarian
|
|
10
|
+
# Generates inventory statistics for all colony memory stores.
|
|
11
|
+
|
|
12
|
+
# ============================================================================
|
|
13
|
+
# _curation_librarian
|
|
14
|
+
# Generate inventory statistics across all memory stores.
|
|
15
|
+
#
|
|
16
|
+
# Usage: curation-librarian
|
|
17
|
+
#
|
|
18
|
+
# Output:
|
|
19
|
+
# {
|
|
20
|
+
# observations: N,
|
|
21
|
+
# instincts: {total: N, active: N, archived: N},
|
|
22
|
+
# graph_edges: N,
|
|
23
|
+
# events: N,
|
|
24
|
+
# signals: {active: N, total: N},
|
|
25
|
+
# midden: N,
|
|
26
|
+
# generated_at: "ISO8601"
|
|
27
|
+
# }
|
|
28
|
+
# ============================================================================
|
|
29
|
+
_curation_librarian() {
|
|
30
|
+
local obs_file="$COLONY_DATA_DIR/learning-observations.json"
|
|
31
|
+
local inst_file="$COLONY_DATA_DIR/instincts.json"
|
|
32
|
+
local graph_file="$COLONY_DATA_DIR/instinct-graph.json"
|
|
33
|
+
local event_file="$COLONY_DATA_DIR/event-bus.jsonl"
|
|
34
|
+
local pheromone_file="$COLONY_DATA_DIR/pheromones.json"
|
|
35
|
+
local midden_file="$COLONY_DATA_DIR/midden/midden.json"
|
|
36
|
+
|
|
37
|
+
# Observations count
|
|
38
|
+
local obs_count=0
|
|
39
|
+
if [[ -f "$obs_file" ]]; then
|
|
40
|
+
obs_count=$(jq '[.observations[]] | length' "$obs_file" 2>/dev/null || echo 0)
|
|
41
|
+
fi
|
|
42
|
+
|
|
43
|
+
# Instinct counts: total, active, archived
|
|
44
|
+
local inst_total=0 inst_active=0 inst_archived=0
|
|
45
|
+
if [[ -f "$inst_file" ]]; then
|
|
46
|
+
inst_total=$(jq '[.instincts[]] | length' "$inst_file" 2>/dev/null || echo 0)
|
|
47
|
+
inst_active=$(jq '[.instincts[] | select(.archived == false)] | length' "$inst_file" 2>/dev/null || echo 0)
|
|
48
|
+
inst_archived=$(jq '[.instincts[] | select(.archived == true)] | length' "$inst_file" 2>/dev/null || echo 0)
|
|
49
|
+
fi
|
|
50
|
+
|
|
51
|
+
# Graph edge count
|
|
52
|
+
local edge_count=0
|
|
53
|
+
if [[ -f "$graph_file" ]]; then
|
|
54
|
+
edge_count=$(jq '[.edges[]] | length' "$graph_file" 2>/dev/null || echo 0)
|
|
55
|
+
fi
|
|
56
|
+
|
|
57
|
+
# Event count (JSONL — count non-empty lines)
|
|
58
|
+
local event_count=0
|
|
59
|
+
if [[ -f "$event_file" ]]; then
|
|
60
|
+
event_count=$(grep -c '.' "$event_file" 2>/dev/null || echo 0)
|
|
61
|
+
fi
|
|
62
|
+
|
|
63
|
+
# Signal counts: active, total
|
|
64
|
+
local sig_active=0 sig_total=0
|
|
65
|
+
if [[ -f "$pheromone_file" ]]; then
|
|
66
|
+
sig_total=$(jq '[.signals[]] | length' "$pheromone_file" 2>/dev/null || echo 0)
|
|
67
|
+
sig_active=$(jq '[.signals[] | select(.active == true)] | length' "$pheromone_file" 2>/dev/null || echo 0)
|
|
68
|
+
fi
|
|
69
|
+
|
|
70
|
+
# Midden entry count
|
|
71
|
+
local midden_count=0
|
|
72
|
+
if [[ -f "$midden_file" ]]; then
|
|
73
|
+
midden_count=$(jq '[.entries[]] | length' "$midden_file" 2>/dev/null || echo 0)
|
|
74
|
+
fi
|
|
75
|
+
|
|
76
|
+
local generated_at
|
|
77
|
+
generated_at=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
|
|
78
|
+
|
|
79
|
+
json_ok "$(jq -n \
|
|
80
|
+
--argjson obs "$obs_count" \
|
|
81
|
+
--argjson inst_total "$inst_total" \
|
|
82
|
+
--argjson inst_active "$inst_active" \
|
|
83
|
+
--argjson inst_archived "$inst_archived" \
|
|
84
|
+
--argjson edges "$edge_count" \
|
|
85
|
+
--argjson events "$event_count" \
|
|
86
|
+
--argjson sig_active "$sig_active" \
|
|
87
|
+
--argjson sig_total "$sig_total" \
|
|
88
|
+
--argjson midden "$midden_count" \
|
|
89
|
+
--arg generated_at "$generated_at" \
|
|
90
|
+
'{
|
|
91
|
+
observations: $obs,
|
|
92
|
+
instincts: {total: $inst_total, active: $inst_active, archived: $inst_archived},
|
|
93
|
+
graph_edges: $edges,
|
|
94
|
+
events: $events,
|
|
95
|
+
signals: {active: $sig_active, total: $sig_total},
|
|
96
|
+
midden: $midden,
|
|
97
|
+
generated_at: $generated_at
|
|
98
|
+
}')"
|
|
99
|
+
}
|
|
@@ -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
|
+
}
|