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.
- package/.aether/aether-utils.sh +181 -5
- package/.aether/commands/archaeology.yaml +3 -3
- package/.aether/commands/build.yaml +80 -45
- package/.aether/commands/chaos.yaml +7 -7
- package/.aether/commands/colonize.yaml +17 -17
- package/.aether/commands/continue.yaml +40 -40
- package/.aether/commands/council.yaml +6 -6
- package/.aether/commands/data-clean.yaml +3 -3
- package/.aether/commands/dream.yaml +2 -2
- package/.aether/commands/entomb.yaml +12 -12
- package/.aether/commands/export-signals.yaml +2 -2
- package/.aether/commands/feedback.yaml +6 -6
- package/.aether/commands/flag.yaml +2 -2
- package/.aether/commands/flags.yaml +4 -4
- package/.aether/commands/focus.yaml +6 -6
- package/.aether/commands/help.yaml +1 -1
- package/.aether/commands/history.yaml +1 -1
- package/.aether/commands/import-signals.yaml +2 -2
- package/.aether/commands/init.yaml +44 -27
- package/.aether/commands/insert-phase.yaml +1 -1
- package/.aether/commands/interpret.yaml +2 -2
- package/.aether/commands/lay-eggs.yaml +3 -3
- package/.aether/commands/maturity.yaml +2 -2
- package/.aether/commands/memory-details.yaml +1 -1
- package/.aether/commands/migrate-state.yaml +1 -1
- package/.aether/commands/oracle.yaml +147 -82
- package/.aether/commands/organize.yaml +5 -5
- package/.aether/commands/patrol.yaml +8 -8
- package/.aether/commands/pause-colony.yaml +7 -7
- package/.aether/commands/phase.yaml +1 -1
- package/.aether/commands/pheromones.yaml +1 -1
- package/.aether/commands/plan.yaml +14 -14
- package/.aether/commands/quick.yaml +4 -4
- package/.aether/commands/redirect.yaml +6 -6
- package/.aether/commands/resume-colony.yaml +9 -9
- package/.aether/commands/resume.yaml +5 -38
- package/.aether/commands/run.yaml +10 -10
- package/.aether/commands/seal.yaml +33 -33
- package/.aether/commands/skill-create.yaml +4 -4
- package/.aether/commands/status.yaml +14 -14
- package/.aether/commands/swarm.yaml +14 -14
- package/.aether/commands/tunnels.yaml +7 -7
- package/.aether/commands/update.yaml +1 -1
- package/.aether/commands/verify-castes.yaml +3 -3
- package/.aether/commands/watch.yaml +15 -15
- package/.aether/docs/command-playbooks/build-complete.md +48 -15
- package/.aether/docs/command-playbooks/build-context.md +11 -11
- package/.aether/docs/command-playbooks/build-full.md +76 -76
- package/.aether/docs/command-playbooks/build-prep.md +10 -10
- package/.aether/docs/command-playbooks/build-verify.md +27 -27
- package/.aether/docs/command-playbooks/build-wave.md +38 -38
- package/.aether/docs/command-playbooks/continue-advance.md +60 -27
- package/.aether/docs/command-playbooks/continue-finalize.md +25 -11
- package/.aether/docs/command-playbooks/continue-full.md +60 -46
- package/.aether/docs/command-playbooks/continue-gates.md +18 -18
- package/.aether/docs/command-playbooks/continue-verify.md +10 -10
- package/.aether/docs/source-of-truth-map.md +10 -10
- package/.aether/docs/structural-learning-stack.md +283 -0
- package/.aether/templates/colony-state-template.json +1 -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/oracle/oracle-stop-hook.sh +896 -0
- 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/archaeology.md +2 -2
- package/.claude/commands/ant/chaos.md +4 -4
- package/.claude/commands/ant/colonize.md +9 -9
- package/.claude/commands/ant/council.md +6 -6
- package/.claude/commands/ant/data-clean.md +3 -3
- package/.claude/commands/ant/dream.md +2 -2
- package/.claude/commands/ant/entomb.md +9 -9
- package/.claude/commands/ant/export-signals.md +2 -2
- package/.claude/commands/ant/feedback.md +4 -4
- package/.claude/commands/ant/flag.md +2 -2
- package/.claude/commands/ant/flags.md +4 -4
- package/.claude/commands/ant/focus.md +4 -4
- package/.claude/commands/ant/help.md +1 -1
- package/.claude/commands/ant/history.md +1 -1
- package/.claude/commands/ant/import-signals.md +2 -2
- package/.claude/commands/ant/init.md +44 -27
- package/.claude/commands/ant/insert-phase.md +1 -1
- package/.claude/commands/ant/interpret.md +2 -2
- package/.claude/commands/ant/lay-eggs.md +2 -2
- package/.claude/commands/ant/maturity.md +2 -2
- package/.claude/commands/ant/memory-details.md +1 -1
- package/.claude/commands/ant/migrate-state.md +1 -1
- package/.claude/commands/ant/oracle.md +78 -42
- package/.claude/commands/ant/organize.md +3 -3
- package/.claude/commands/ant/patrol.md +8 -8
- package/.claude/commands/ant/pause-colony.md +5 -5
- package/.claude/commands/ant/phase.md +1 -1
- package/.claude/commands/ant/pheromones.md +1 -1
- package/.claude/commands/ant/plan.md +8 -8
- package/.claude/commands/ant/quick.md +4 -4
- package/.claude/commands/ant/redirect.md +4 -4
- package/.claude/commands/ant/resume-colony.md +5 -5
- package/.claude/commands/ant/resume.md +17 -29
- package/.claude/commands/ant/run.md +10 -10
- package/.claude/commands/ant/seal.md +25 -25
- package/.claude/commands/ant/skill-create.md +2 -2
- package/.claude/commands/ant/status.md +14 -14
- package/.claude/commands/ant/swarm.md +14 -14
- package/.claude/commands/ant/tunnels.md +4 -4
- package/.claude/commands/ant/update.md +1 -1
- package/.claude/commands/ant/verify-castes.md +2 -2
- package/.claude/commands/ant/watch.md +8 -8
- package/.opencode/commands/ant/archaeology.md +1 -1
- package/.opencode/commands/ant/build.md +80 -45
- package/.opencode/commands/ant/chaos.md +3 -3
- package/.opencode/commands/ant/colonize.md +8 -8
- package/.opencode/commands/ant/continue.md +40 -40
- package/.opencode/commands/ant/council.md +5 -5
- package/.opencode/commands/ant/data-clean.md +2 -2
- package/.opencode/commands/ant/dream.md +1 -1
- package/.opencode/commands/ant/entomb.md +3 -3
- package/.opencode/commands/ant/export-signals.md +1 -1
- package/.opencode/commands/ant/feedback.md +2 -2
- package/.opencode/commands/ant/flag.md +1 -1
- package/.opencode/commands/ant/flags.md +3 -3
- package/.opencode/commands/ant/focus.md +2 -2
- package/.opencode/commands/ant/import-signals.md +1 -1
- package/.opencode/commands/ant/init.md +44 -27
- package/.opencode/commands/ant/insert-phase.md +1 -1
- package/.opencode/commands/ant/interpret.md +1 -1
- package/.opencode/commands/ant/lay-eggs.md +2 -2
- package/.opencode/commands/ant/maturity.md +1 -1
- package/.opencode/commands/ant/memory-details.md +1 -1
- package/.opencode/commands/ant/oracle.md +69 -40
- package/.opencode/commands/ant/organize.md +2 -2
- package/.opencode/commands/ant/patrol.md +8 -8
- package/.opencode/commands/ant/pause-colony.md +2 -2
- package/.opencode/commands/ant/pheromones.md +1 -1
- package/.opencode/commands/ant/plan.md +6 -6
- package/.opencode/commands/ant/quick.md +4 -4
- package/.opencode/commands/ant/redirect.md +2 -2
- package/.opencode/commands/ant/resume-colony.md +4 -4
- package/.opencode/commands/ant/resume.md +5 -17
- package/.opencode/commands/ant/run.md +10 -10
- package/.opencode/commands/ant/seal.md +8 -8
- package/.opencode/commands/ant/skill-create.md +2 -2
- package/.opencode/commands/ant/status.md +10 -10
- package/.opencode/commands/ant/tunnels.md +3 -3
- package/.opencode/commands/ant/verify-castes.md +1 -1
- package/.opencode/commands/ant/watch.md +7 -7
- package/CHANGELOG.md +83 -0
- package/README.md +22 -9
- package/bin/cli.js +118 -3
- package/bin/lib/binary-downloader.js +267 -0
- package/bin/lib/update-transaction.js +27 -3
- package/bin/lib/version-gate.js +179 -0
- 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,97 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Curation Archivist — Low-Trust Instinct Archival
|
|
3
|
+
# Archives instincts that have decayed below a trust threshold.
|
|
4
|
+
#
|
|
5
|
+
# Functions:
|
|
6
|
+
# _curation_archivist
|
|
7
|
+
#
|
|
8
|
+
# These functions are sourced by aether-utils.sh at startup.
|
|
9
|
+
# All shared infrastructure (json_ok, json_err, atomic_write, COLONY_DATA_DIR,
|
|
10
|
+
# DATA_DIR, error constants) is available when sourced.
|
|
11
|
+
|
|
12
|
+
# ============================================================================
|
|
13
|
+
# _curation_archivist
|
|
14
|
+
# Archive active instincts with trust_score below threshold.
|
|
15
|
+
# Usage: curation-archivist [--threshold <float>] [--dry-run]
|
|
16
|
+
#
|
|
17
|
+
# Default threshold: 0.25
|
|
18
|
+
# Output: json_ok with {archived:N, below_threshold:N, dry_run:bool}
|
|
19
|
+
# ============================================================================
|
|
20
|
+
_curation_archivist() {
|
|
21
|
+
local ca_threshold="0.25"
|
|
22
|
+
local ca_dry_run="false"
|
|
23
|
+
|
|
24
|
+
while [[ $# -gt 0 ]]; do
|
|
25
|
+
case "$1" in
|
|
26
|
+
--threshold)
|
|
27
|
+
ca_threshold="${2:-0.25}"
|
|
28
|
+
shift 2
|
|
29
|
+
;;
|
|
30
|
+
--dry-run)
|
|
31
|
+
ca_dry_run="true"
|
|
32
|
+
shift
|
|
33
|
+
;;
|
|
34
|
+
*)
|
|
35
|
+
shift
|
|
36
|
+
;;
|
|
37
|
+
esac
|
|
38
|
+
done
|
|
39
|
+
|
|
40
|
+
local ca_data_dir="${COLONY_DATA_DIR:-${DATA_DIR:-}}"
|
|
41
|
+
if [[ -z "$ca_data_dir" ]]; then
|
|
42
|
+
json_err "$E_VALIDATION_FAILED" "curation-archivist: COLONY_DATA_DIR is not set"
|
|
43
|
+
fi
|
|
44
|
+
|
|
45
|
+
local ca_instincts_file="$ca_data_dir/instincts.json"
|
|
46
|
+
|
|
47
|
+
# No instincts file — nothing to archive
|
|
48
|
+
if [[ ! -f "$ca_instincts_file" ]]; then
|
|
49
|
+
json_ok "$(jq -nc \
|
|
50
|
+
--argjson archived 0 \
|
|
51
|
+
--argjson below_threshold 0 \
|
|
52
|
+
--argjson dry_run "$ca_dry_run" \
|
|
53
|
+
'{archived:$archived, below_threshold:$below_threshold, dry_run:$dry_run}')"
|
|
54
|
+
return 0
|
|
55
|
+
fi
|
|
56
|
+
|
|
57
|
+
if ! jq empty "$ca_instincts_file" 2>/dev/null; then
|
|
58
|
+
json_err "$E_JSON_INVALID" "curation-archivist: instincts.json is not valid JSON"
|
|
59
|
+
fi
|
|
60
|
+
|
|
61
|
+
# Count active instincts below threshold
|
|
62
|
+
local ca_below_threshold
|
|
63
|
+
ca_below_threshold=$(jq --argjson thresh "$ca_threshold" \
|
|
64
|
+
'[.instincts[] | select(.archived != true and (.trust_score // .confidence // 0) < $thresh)] | length' \
|
|
65
|
+
"$ca_instincts_file" 2>/dev/null || echo 0)
|
|
66
|
+
|
|
67
|
+
local ca_archived=0
|
|
68
|
+
|
|
69
|
+
if [[ "$ca_dry_run" == "false" && "$ca_below_threshold" -gt 0 ]]; then
|
|
70
|
+
local ca_ts
|
|
71
|
+
ca_ts=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
|
|
72
|
+
|
|
73
|
+
local ca_updated
|
|
74
|
+
ca_updated=$(jq \
|
|
75
|
+
--argjson thresh "$ca_threshold" \
|
|
76
|
+
--arg ts "$ca_ts" \
|
|
77
|
+
'.instincts |= [.[] | if (.archived != true and (.trust_score // .confidence // 0) < $thresh)
|
|
78
|
+
then . + {archived: true, updated_at: $ts}
|
|
79
|
+
else .
|
|
80
|
+
end]' \
|
|
81
|
+
"$ca_instincts_file" 2>/dev/null)
|
|
82
|
+
|
|
83
|
+
if [[ -n "$ca_updated" ]]; then
|
|
84
|
+
atomic_write "$ca_instincts_file" "$ca_updated" 2>/dev/null \
|
|
85
|
+
|| json_err "$E_UNKNOWN" "curation-archivist: failed to write instincts.json"
|
|
86
|
+
ca_archived="$ca_below_threshold"
|
|
87
|
+
fi
|
|
88
|
+
elif [[ "$ca_dry_run" == "true" ]]; then
|
|
89
|
+
ca_archived="$ca_below_threshold"
|
|
90
|
+
fi
|
|
91
|
+
|
|
92
|
+
json_ok "$(jq -nc \
|
|
93
|
+
--argjson archived "$ca_archived" \
|
|
94
|
+
--argjson below_threshold "$ca_below_threshold" \
|
|
95
|
+
--argjson dry_run "$ca_dry_run" \
|
|
96
|
+
'{archived:$archived, below_threshold:$below_threshold, dry_run:$dry_run}')"
|
|
97
|
+
}
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Critic curation ant — contradiction detection between instincts
|
|
3
|
+
# Provides: _curation_critic
|
|
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, error constants) is available.
|
|
8
|
+
#
|
|
9
|
+
# Subcommand: curation-critic [--auto-resolve]
|
|
10
|
+
# Finds contradicting instincts using text heuristics and graph edges.
|
|
11
|
+
|
|
12
|
+
# ============================================================================
|
|
13
|
+
# _curation_critic_opposing_words
|
|
14
|
+
# Internal helper: check if two action strings oppose each other.
|
|
15
|
+
# Detects "always"/"never" and "do"/"don't" opposites in the same domain.
|
|
16
|
+
# Outputs "true" if opposing, "false" otherwise.
|
|
17
|
+
# ============================================================================
|
|
18
|
+
_curation_critic_opposing_words() {
|
|
19
|
+
local action_a="$1"
|
|
20
|
+
local action_b="$2"
|
|
21
|
+
|
|
22
|
+
local low_a low_b
|
|
23
|
+
low_a=$(echo "$action_a" | tr '[:upper:]' '[:lower:]')
|
|
24
|
+
low_b=$(echo "$action_b" | tr '[:upper:]' '[:lower:]')
|
|
25
|
+
|
|
26
|
+
# "always" in one and "never" in the other
|
|
27
|
+
if [[ "$low_a" == *"always"* && "$low_b" == *"never"* ]]; then
|
|
28
|
+
echo "true"; return
|
|
29
|
+
fi
|
|
30
|
+
if [[ "$low_a" == *"never"* && "$low_b" == *"always"* ]]; then
|
|
31
|
+
echo "true"; return
|
|
32
|
+
fi
|
|
33
|
+
|
|
34
|
+
# "don't" or "do not" in one and plain action (no negation) in the other
|
|
35
|
+
if [[ "$low_a" == *"don't"* || "$low_a" == *"do not"* ]]; then
|
|
36
|
+
# Strip negation from a: "don't add X" -> "add X" — check overlap with b
|
|
37
|
+
local stripped_a
|
|
38
|
+
stripped_a=$(echo "$low_a" | sed "s/don't //g; s/do not //g")
|
|
39
|
+
if [[ "$low_b" == *"$stripped_a"* || "$stripped_a" == *"$low_b"* ]]; then
|
|
40
|
+
# Only flag if they share substantial content (>= 4 chars of overlap)
|
|
41
|
+
local overlap_len=${#stripped_a}
|
|
42
|
+
[[ "$overlap_len" -ge 4 ]] && echo "true" && return
|
|
43
|
+
fi
|
|
44
|
+
fi
|
|
45
|
+
if [[ "$low_b" == *"don't"* || "$low_b" == *"do not"* ]]; then
|
|
46
|
+
local stripped_b
|
|
47
|
+
stripped_b=$(echo "$low_b" | sed "s/don't //g; s/do not //g")
|
|
48
|
+
if [[ "$low_a" == *"$stripped_b"* || "$stripped_b" == *"$low_a"* ]]; then
|
|
49
|
+
local overlap_len=${#stripped_b}
|
|
50
|
+
[[ "$overlap_len" -ge 4 ]] && echo "true" && return
|
|
51
|
+
fi
|
|
52
|
+
fi
|
|
53
|
+
|
|
54
|
+
echo "false"
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
# ============================================================================
|
|
58
|
+
# _curation_critic
|
|
59
|
+
# Find contradicting instincts and optionally auto-resolve them.
|
|
60
|
+
#
|
|
61
|
+
# Usage: curation-critic [--auto-resolve]
|
|
62
|
+
#
|
|
63
|
+
# Contradiction criteria:
|
|
64
|
+
# - Same domain
|
|
65
|
+
# - Opposing triggers (same trigger text) with opposing action keywords
|
|
66
|
+
# - OR existing "contradicts" edge in the graph
|
|
67
|
+
#
|
|
68
|
+
# Auto-resolve: archive the lower-trust instinct, create "contradicts" graph edge.
|
|
69
|
+
#
|
|
70
|
+
# Output: {contradictions: [{instinct_a, instinct_b, reason, resolved}], count: N}
|
|
71
|
+
# ============================================================================
|
|
72
|
+
_curation_critic() {
|
|
73
|
+
local auto_resolve="false"
|
|
74
|
+
|
|
75
|
+
while [[ $# -gt 0 ]]; do
|
|
76
|
+
case "$1" in
|
|
77
|
+
--auto-resolve) auto_resolve="true"; shift ;;
|
|
78
|
+
*) shift ;;
|
|
79
|
+
esac
|
|
80
|
+
done
|
|
81
|
+
|
|
82
|
+
local inst_file="$COLONY_DATA_DIR/instincts.json"
|
|
83
|
+
|
|
84
|
+
if [[ ! -f "$inst_file" ]]; then
|
|
85
|
+
json_ok '{"contradictions":[],"count":0}'
|
|
86
|
+
return
|
|
87
|
+
fi
|
|
88
|
+
|
|
89
|
+
# Load all active instincts into a bash-friendly form
|
|
90
|
+
local active_instincts
|
|
91
|
+
active_instincts=$(jq -c '[.instincts[] | select(.archived == false)]' "$inst_file" 2>/dev/null || echo "[]")
|
|
92
|
+
|
|
93
|
+
local total_active
|
|
94
|
+
total_active=$(echo "$active_instincts" | jq 'length')
|
|
95
|
+
|
|
96
|
+
local contradictions_json="[]"
|
|
97
|
+
local resolved_ids=()
|
|
98
|
+
|
|
99
|
+
if [[ "$total_active" -ge 2 ]]; then
|
|
100
|
+
# Compare all pairs using indexed access
|
|
101
|
+
local i=0
|
|
102
|
+
while [[ $i -lt $((total_active - 1)) ]]; do
|
|
103
|
+
local inst_a
|
|
104
|
+
inst_a=$(echo "$active_instincts" | jq -c ".[$i]")
|
|
105
|
+
local id_a domain_a trigger_a action_a score_a
|
|
106
|
+
id_a=$(echo "$inst_a" | jq -r '.id')
|
|
107
|
+
domain_a=$(echo "$inst_a" | jq -r '.domain // ""')
|
|
108
|
+
trigger_a=$(echo "$inst_a" | jq -r '.trigger // ""')
|
|
109
|
+
action_a=$(echo "$inst_a" | jq -r '.action // ""')
|
|
110
|
+
score_a=$(echo "$inst_a" | jq -r '.trust_score // 0')
|
|
111
|
+
|
|
112
|
+
local j=$((i + 1))
|
|
113
|
+
while [[ $j -lt $total_active ]]; do
|
|
114
|
+
local inst_b
|
|
115
|
+
inst_b=$(echo "$active_instincts" | jq -c ".[$j]")
|
|
116
|
+
local id_b domain_b trigger_b action_b score_b
|
|
117
|
+
id_b=$(echo "$inst_b" | jq -r '.id')
|
|
118
|
+
domain_b=$(echo "$inst_b" | jq -r '.domain // ""')
|
|
119
|
+
trigger_b=$(echo "$inst_b" | jq -r '.trigger // ""')
|
|
120
|
+
action_b=$(echo "$inst_b" | jq -r '.action // ""')
|
|
121
|
+
score_b=$(echo "$inst_b" | jq -r '.trust_score // 0')
|
|
122
|
+
|
|
123
|
+
local contradiction_reason=""
|
|
124
|
+
|
|
125
|
+
# Heuristic 1: Same domain + similar trigger + opposing actions
|
|
126
|
+
if [[ -n "$domain_a" && "$domain_a" == "$domain_b" ]]; then
|
|
127
|
+
# Check if triggers are similar (first 40 chars match or substantial overlap)
|
|
128
|
+
local trig_prefix_a trig_prefix_b
|
|
129
|
+
trig_prefix_a=$(echo "$trigger_a" | cut -c1-40 | tr '[:upper:]' '[:lower:]')
|
|
130
|
+
trig_prefix_b=$(echo "$trigger_b" | cut -c1-40 | tr '[:upper:]' '[:lower:]')
|
|
131
|
+
|
|
132
|
+
if [[ "$trig_prefix_a" == "$trig_prefix_b" && -n "$trig_prefix_a" ]]; then
|
|
133
|
+
local opposing
|
|
134
|
+
opposing=$(_curation_critic_opposing_words "$action_a" "$action_b")
|
|
135
|
+
if [[ "$opposing" == "true" ]]; then
|
|
136
|
+
contradiction_reason="same domain and trigger with opposing actions"
|
|
137
|
+
fi
|
|
138
|
+
fi
|
|
139
|
+
fi
|
|
140
|
+
|
|
141
|
+
# Heuristic 2: Check existing "contradicts" graph edge
|
|
142
|
+
if [[ -z "$contradiction_reason" ]]; then
|
|
143
|
+
local graph_file="$COLONY_DATA_DIR/instinct-graph.json"
|
|
144
|
+
if [[ -f "$graph_file" ]]; then
|
|
145
|
+
local has_edge
|
|
146
|
+
has_edge=$(jq -r \
|
|
147
|
+
--arg a "$id_a" --arg b "$id_b" \
|
|
148
|
+
'[.edges[] | select(
|
|
149
|
+
.relationship == "contradicts" and (
|
|
150
|
+
(.source == $a and .target == $b) or
|
|
151
|
+
(.source == $b and .target == $a)
|
|
152
|
+
)
|
|
153
|
+
)] | length' "$graph_file" 2>/dev/null || echo 0)
|
|
154
|
+
if [[ "$has_edge" -gt 0 ]]; then
|
|
155
|
+
contradiction_reason="existing contradicts graph edge"
|
|
156
|
+
fi
|
|
157
|
+
fi
|
|
158
|
+
fi
|
|
159
|
+
|
|
160
|
+
if [[ -n "$contradiction_reason" ]]; then
|
|
161
|
+
local resolved="false"
|
|
162
|
+
|
|
163
|
+
if [[ "$auto_resolve" == "true" ]]; then
|
|
164
|
+
# Archive the lower-trust instinct
|
|
165
|
+
local lower_id higher_id
|
|
166
|
+
local cmp
|
|
167
|
+
cmp=$(awk "BEGIN{print ($score_a >= $score_b)}" 2>/dev/null || echo "1")
|
|
168
|
+
if [[ "$cmp" == "1" ]]; then
|
|
169
|
+
lower_id="$id_b"
|
|
170
|
+
higher_id="$id_a"
|
|
171
|
+
else
|
|
172
|
+
lower_id="$id_a"
|
|
173
|
+
higher_id="$id_b"
|
|
174
|
+
fi
|
|
175
|
+
|
|
176
|
+
# Only archive if not already scheduled (avoid double-archive)
|
|
177
|
+
local already_resolving="false"
|
|
178
|
+
for rid in "${resolved_ids[@]:-}"; do
|
|
179
|
+
[[ "$rid" == "$lower_id" ]] && already_resolving="true" && break
|
|
180
|
+
done
|
|
181
|
+
|
|
182
|
+
if [[ "$already_resolving" != "true" ]]; then
|
|
183
|
+
_instinct_archive --id "$lower_id" >/dev/null 2>&1 || true
|
|
184
|
+
resolved_ids+=("$lower_id")
|
|
185
|
+
resolved="true"
|
|
186
|
+
|
|
187
|
+
# Create "contradicts" graph edge (best effort)
|
|
188
|
+
_graph_link --source "$higher_id" --target "$lower_id" \
|
|
189
|
+
--relationship contradicts >/dev/null 2>&1 || true
|
|
190
|
+
fi
|
|
191
|
+
fi
|
|
192
|
+
|
|
193
|
+
contradictions_json=$(echo "$contradictions_json" | jq \
|
|
194
|
+
--arg a "$id_a" \
|
|
195
|
+
--arg b "$id_b" \
|
|
196
|
+
--arg reason "$contradiction_reason" \
|
|
197
|
+
--argjson resolved "$([ "$resolved" == "true" ] && echo true || echo false)" \
|
|
198
|
+
'. += [{instinct_a: $a, instinct_b: $b, reason: $reason, resolved: $resolved}]')
|
|
199
|
+
fi
|
|
200
|
+
|
|
201
|
+
j=$((j + 1))
|
|
202
|
+
done
|
|
203
|
+
i=$((i + 1))
|
|
204
|
+
done
|
|
205
|
+
fi
|
|
206
|
+
|
|
207
|
+
local count
|
|
208
|
+
count=$(echo "$contradictions_json" | jq 'length')
|
|
209
|
+
|
|
210
|
+
json_ok "$(jq -n \
|
|
211
|
+
--argjson contradictions "$contradictions_json" \
|
|
212
|
+
--argjson count "$count" \
|
|
213
|
+
'{contradictions: $contradictions, count: $count}')"
|
|
214
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Herald curation ant — QUEEN.md promotion of high-trust instincts
|
|
3
|
+
# Provides: _curation_herald
|
|
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, AETHER_ROOT, SCRIPT_DIR, error constants) is available.
|
|
8
|
+
#
|
|
9
|
+
# Subcommand: curation-herald [--min-trust <float>] [--dry-run]
|
|
10
|
+
# Promotes instincts with trust_score >= min-trust to QUEEN.md wisdom.
|
|
11
|
+
|
|
12
|
+
# ============================================================================
|
|
13
|
+
# _curation_herald
|
|
14
|
+
# Promote high-trust instincts to QUEEN.md.
|
|
15
|
+
#
|
|
16
|
+
# Usage: curation-herald [--min-trust <float>] [--dry-run]
|
|
17
|
+
# Default min-trust: 0.75
|
|
18
|
+
#
|
|
19
|
+
# Output: {eligible: N, promoted: N, already_in_queen: N, dry_run: bool}
|
|
20
|
+
# ============================================================================
|
|
21
|
+
_curation_herald() {
|
|
22
|
+
local min_trust="0.75"
|
|
23
|
+
local dry_run="false"
|
|
24
|
+
|
|
25
|
+
while [[ $# -gt 0 ]]; do
|
|
26
|
+
case "$1" in
|
|
27
|
+
--min-trust) min_trust="${2:-0.75}"; shift 2 ;;
|
|
28
|
+
--dry-run) dry_run="true"; shift ;;
|
|
29
|
+
*) shift ;;
|
|
30
|
+
esac
|
|
31
|
+
done
|
|
32
|
+
|
|
33
|
+
local inst_file="$COLONY_DATA_DIR/instincts.json"
|
|
34
|
+
|
|
35
|
+
if [[ ! -f "$inst_file" ]]; then
|
|
36
|
+
json_ok "$(jq -n --argjson dry "$([ "$dry_run" == "true" ] && echo true || echo false)" \
|
|
37
|
+
'{eligible: 0, promoted: 0, already_in_queen: 0, dry_run: $dry}')"
|
|
38
|
+
return
|
|
39
|
+
fi
|
|
40
|
+
|
|
41
|
+
# Collect eligible instincts: active, trust_score >= min_trust
|
|
42
|
+
local eligible_instincts
|
|
43
|
+
eligible_instincts=$(jq -c \
|
|
44
|
+
--argjson min "$min_trust" \
|
|
45
|
+
'[.instincts[] | select(.archived == false and .trust_score >= $min)]' \
|
|
46
|
+
"$inst_file" 2>/dev/null || echo "[]")
|
|
47
|
+
|
|
48
|
+
local eligible_count
|
|
49
|
+
eligible_count=$(echo "$eligible_instincts" | jq 'length')
|
|
50
|
+
|
|
51
|
+
local promoted=0
|
|
52
|
+
local already_in_queen=0
|
|
53
|
+
|
|
54
|
+
if [[ "$eligible_count" -gt 0 && "$dry_run" != "true" ]]; then
|
|
55
|
+
while IFS= read -r inst_json; do
|
|
56
|
+
local trigger action confidence domain
|
|
57
|
+
trigger=$(echo "$inst_json" | jq -r '.trigger // ""')
|
|
58
|
+
action=$(echo "$inst_json" | jq -r '.action // ""')
|
|
59
|
+
confidence=$(echo "$inst_json" | jq -r '.confidence // 0.75')
|
|
60
|
+
domain=$(echo "$inst_json" | jq -r '.domain // "workflow"')
|
|
61
|
+
|
|
62
|
+
[[ -z "$trigger" || -z "$action" ]] && continue
|
|
63
|
+
|
|
64
|
+
local promote_result
|
|
65
|
+
promote_result=$(_queen_promote_instinct "$trigger" "$action" "$confidence" "$domain" 2>/dev/null) || true
|
|
66
|
+
|
|
67
|
+
if echo "$promote_result" | jq -e '.ok == true' >/dev/null 2>&1; then
|
|
68
|
+
local was_promoted
|
|
69
|
+
was_promoted=$(echo "$promote_result" | jq -r '.result.promoted // false')
|
|
70
|
+
local reason
|
|
71
|
+
reason=$(echo "$promote_result" | jq -r '.result.reason // ""')
|
|
72
|
+
|
|
73
|
+
if [[ "$was_promoted" == "true" ]]; then
|
|
74
|
+
promoted=$((promoted + 1))
|
|
75
|
+
elif [[ "$reason" == "duplicate" ]]; then
|
|
76
|
+
already_in_queen=$((already_in_queen + 1))
|
|
77
|
+
fi
|
|
78
|
+
fi
|
|
79
|
+
done < <(echo "$eligible_instincts" | jq -c '.[]')
|
|
80
|
+
elif [[ "$eligible_count" -gt 0 && "$dry_run" == "true" ]]; then
|
|
81
|
+
# Dry run: count what would be promoted vs already present
|
|
82
|
+
local queen_file="${AETHER_ROOT:-}/.aether/QUEEN.md"
|
|
83
|
+
while IFS= read -r inst_json; do
|
|
84
|
+
local action
|
|
85
|
+
action=$(echo "$inst_json" | jq -r '.action // ""')
|
|
86
|
+
[[ -z "$action" ]] && continue
|
|
87
|
+
|
|
88
|
+
if [[ -f "$queen_file" ]] && grep -Fq -- "$action" "$queen_file" 2>/dev/null; then
|
|
89
|
+
already_in_queen=$((already_in_queen + 1))
|
|
90
|
+
else
|
|
91
|
+
promoted=$((promoted + 1))
|
|
92
|
+
fi
|
|
93
|
+
done < <(echo "$eligible_instincts" | jq -c '.[]')
|
|
94
|
+
fi
|
|
95
|
+
|
|
96
|
+
json_ok "$(jq -n \
|
|
97
|
+
--argjson eligible "$eligible_count" \
|
|
98
|
+
--argjson promoted "$promoted" \
|
|
99
|
+
--argjson already "$already_in_queen" \
|
|
100
|
+
--argjson dry "$([ "$dry_run" == "true" ] && echo true || echo false)" \
|
|
101
|
+
'{eligible: $eligible, promoted: $promoted, already_in_queen: $already, dry_run: $dry}')"
|
|
102
|
+
}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Curation Janitor — Expired Event/Archive Pruning
|
|
3
|
+
# Cleans up expired events and old archived instincts.
|
|
4
|
+
#
|
|
5
|
+
# Functions:
|
|
6
|
+
# _curation_janitor
|
|
7
|
+
#
|
|
8
|
+
# These functions are sourced by aether-utils.sh at startup.
|
|
9
|
+
# All shared infrastructure (json_ok, json_err, atomic_write, COLONY_DATA_DIR,
|
|
10
|
+
# DATA_DIR, error constants) is available when sourced.
|
|
11
|
+
|
|
12
|
+
# ============================================================================
|
|
13
|
+
# _curation_janitor
|
|
14
|
+
# Remove expired events and prune stale data.
|
|
15
|
+
# Usage: curation-janitor [--dry-run] [--max-age-days <N>]
|
|
16
|
+
#
|
|
17
|
+
# Default max-age-days: 90
|
|
18
|
+
# Output: json_ok with {events_removed:N, instincts_pruned:N,
|
|
19
|
+
# observations_pruned:N, dry_run:bool}
|
|
20
|
+
# ============================================================================
|
|
21
|
+
_curation_janitor() {
|
|
22
|
+
local cj_dry_run="false"
|
|
23
|
+
local cj_max_age_days=90
|
|
24
|
+
|
|
25
|
+
while [[ $# -gt 0 ]]; do
|
|
26
|
+
case "$1" in
|
|
27
|
+
--dry-run)
|
|
28
|
+
cj_dry_run="true"
|
|
29
|
+
shift
|
|
30
|
+
;;
|
|
31
|
+
--max-age-days)
|
|
32
|
+
cj_max_age_days="${2:-90}"
|
|
33
|
+
shift 2
|
|
34
|
+
;;
|
|
35
|
+
*)
|
|
36
|
+
shift
|
|
37
|
+
;;
|
|
38
|
+
esac
|
|
39
|
+
done
|
|
40
|
+
|
|
41
|
+
local cj_data_dir="${COLONY_DATA_DIR:-${DATA_DIR:-}}"
|
|
42
|
+
if [[ -z "$cj_data_dir" ]]; then
|
|
43
|
+
json_err "$E_VALIDATION_FAILED" "curation-janitor: COLONY_DATA_DIR is not set"
|
|
44
|
+
fi
|
|
45
|
+
|
|
46
|
+
# Step 1: Clean expired events via event-cleanup subcommand
|
|
47
|
+
local cj_events_removed=0
|
|
48
|
+
local cj_cleanup_dry_run_flag=""
|
|
49
|
+
[[ "$cj_dry_run" == "true" ]] && cj_cleanup_dry_run_flag="--dry-run"
|
|
50
|
+
|
|
51
|
+
local cj_cleanup_result
|
|
52
|
+
if [[ -n "$cj_cleanup_dry_run_flag" ]]; then
|
|
53
|
+
cj_cleanup_result=$(COLONY_DATA_DIR="$cj_data_dir" DATA_DIR="$cj_data_dir" \
|
|
54
|
+
bash "$0" event-cleanup "$cj_cleanup_dry_run_flag" 2>/dev/null) || true
|
|
55
|
+
else
|
|
56
|
+
cj_cleanup_result=$(COLONY_DATA_DIR="$cj_data_dir" DATA_DIR="$cj_data_dir" \
|
|
57
|
+
bash "$0" event-cleanup 2>/dev/null) || true
|
|
58
|
+
fi
|
|
59
|
+
if echo "$cj_cleanup_result" | jq -e '.ok == true' >/dev/null 2>&1; then
|
|
60
|
+
cj_events_removed=$(echo "$cj_cleanup_result" | jq '.result.removed // 0' 2>/dev/null || echo 0)
|
|
61
|
+
fi
|
|
62
|
+
|
|
63
|
+
# Step 2: Prune archived instincts older than max-age-days
|
|
64
|
+
local cj_instincts_pruned=0
|
|
65
|
+
local cj_instincts_file="$cj_data_dir/instincts.json"
|
|
66
|
+
|
|
67
|
+
if [[ -f "$cj_instincts_file" ]] && jq empty "$cj_instincts_file" 2>/dev/null; then
|
|
68
|
+
local cj_cutoff
|
|
69
|
+
cj_cutoff=$(date -u -v"-${cj_max_age_days}d" +%Y-%m-%dT%H:%M:%SZ 2>/dev/null \
|
|
70
|
+
|| date -u -d "-${cj_max_age_days} days" +%Y-%m-%dT%H:%M:%SZ 2>/dev/null \
|
|
71
|
+
|| echo "1970-01-01T00:00:00Z")
|
|
72
|
+
|
|
73
|
+
cj_instincts_pruned=$(jq --arg cutoff "$cj_cutoff" \
|
|
74
|
+
'[.instincts[] | select(.archived == true and (.updated_at // .created_at) < $cutoff)] | length' \
|
|
75
|
+
"$cj_instincts_file" 2>/dev/null || echo 0)
|
|
76
|
+
|
|
77
|
+
if [[ "$cj_dry_run" == "false" && "$cj_instincts_pruned" -gt 0 ]]; then
|
|
78
|
+
local cj_updated_instincts
|
|
79
|
+
cj_updated_instincts=$(jq --arg cutoff "$cj_cutoff" \
|
|
80
|
+
'.instincts |= [.[] | select(not (.archived == true and (.updated_at // .created_at) < $cutoff))]' \
|
|
81
|
+
"$cj_instincts_file" 2>/dev/null)
|
|
82
|
+
if [[ -n "$cj_updated_instincts" ]]; then
|
|
83
|
+
atomic_write "$cj_instincts_file" "$cj_updated_instincts" 2>/dev/null || true
|
|
84
|
+
fi
|
|
85
|
+
fi
|
|
86
|
+
fi
|
|
87
|
+
|
|
88
|
+
# Step 3: Prune stale learning-observations (observation_count=1, older than 90 days)
|
|
89
|
+
local cj_observations_pruned=0
|
|
90
|
+
local cj_obs_file="$cj_data_dir/learning-observations.json"
|
|
91
|
+
local cj_obs_cutoff_days=90
|
|
92
|
+
|
|
93
|
+
if [[ -f "$cj_obs_file" ]] && jq empty "$cj_obs_file" 2>/dev/null; then
|
|
94
|
+
local cj_obs_cutoff
|
|
95
|
+
cj_obs_cutoff=$(date -u -v"-${cj_obs_cutoff_days}d" +%Y-%m-%dT%H:%M:%SZ 2>/dev/null \
|
|
96
|
+
|| date -u -d "-${cj_obs_cutoff_days} days" +%Y-%m-%dT%H:%M:%SZ 2>/dev/null \
|
|
97
|
+
|| echo "1970-01-01T00:00:00Z")
|
|
98
|
+
|
|
99
|
+
cj_observations_pruned=$(jq --arg cutoff "$cj_obs_cutoff" \
|
|
100
|
+
'[.observations[] | select((.observation_count // 0) == 1 and (.last_observed // .observed_at // "") < $cutoff)] | length' \
|
|
101
|
+
"$cj_obs_file" 2>/dev/null || echo 0)
|
|
102
|
+
|
|
103
|
+
if [[ "$cj_dry_run" == "false" && "$cj_observations_pruned" -gt 0 ]]; then
|
|
104
|
+
local cj_updated_obs
|
|
105
|
+
cj_updated_obs=$(jq --arg cutoff "$cj_obs_cutoff" \
|
|
106
|
+
'.observations |= [.[] | select(not ((.observation_count // 0) == 1 and (.last_observed // .observed_at // "") < $cutoff))]' \
|
|
107
|
+
"$cj_obs_file" 2>/dev/null)
|
|
108
|
+
if [[ -n "$cj_updated_obs" ]]; then
|
|
109
|
+
atomic_write "$cj_obs_file" "$cj_updated_obs" 2>/dev/null || true
|
|
110
|
+
fi
|
|
111
|
+
fi
|
|
112
|
+
fi
|
|
113
|
+
|
|
114
|
+
json_ok "$(jq -nc \
|
|
115
|
+
--argjson events_removed "$cj_events_removed" \
|
|
116
|
+
--argjson instincts_pruned "$cj_instincts_pruned" \
|
|
117
|
+
--argjson observations_pruned "$cj_observations_pruned" \
|
|
118
|
+
--argjson dry_run "$cj_dry_run" \
|
|
119
|
+
'{events_removed:$events_removed, instincts_pruned:$instincts_pruned,
|
|
120
|
+
observations_pruned:$observations_pruned, dry_run:$dry_run}')"
|
|
121
|
+
}
|
|
@@ -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
|
+
}
|