aether-colony 5.1.0 → 5.3.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 +157 -42
- package/.aether/agents/aether-ambassador.md +140 -0
- package/.aether/agents/aether-archaeologist.md +108 -0
- package/.aether/agents/aether-architect.md +133 -0
- package/.aether/agents/aether-auditor.md +144 -0
- package/.aether/agents/aether-builder.md +184 -0
- package/.aether/agents/aether-chaos.md +115 -0
- package/.aether/agents/aether-chronicler.md +122 -0
- package/.aether/agents/aether-gatekeeper.md +116 -0
- package/.aether/agents/aether-includer.md +117 -0
- package/.aether/agents/aether-keeper.md +177 -0
- package/.aether/agents/aether-measurer.md +128 -0
- package/.aether/agents/aether-oracle.md +137 -0
- package/.aether/agents/aether-probe.md +133 -0
- package/.aether/agents/aether-queen.md +286 -0
- package/.aether/agents/aether-route-setter.md +130 -0
- package/.aether/agents/aether-sage.md +106 -0
- package/.aether/agents/aether-scout.md +101 -0
- package/.aether/agents/aether-surveyor-disciplines.md +391 -0
- package/.aether/agents/aether-surveyor-nest.md +329 -0
- package/.aether/agents/aether-surveyor-pathogens.md +264 -0
- package/.aether/agents/aether-surveyor-provisions.md +334 -0
- package/.aether/agents/aether-tracker.md +137 -0
- package/.aether/agents/aether-watcher.md +174 -0
- package/.aether/agents/aether-weaver.md +130 -0
- package/.aether/commands/claude/archaeology.md +334 -0
- package/.aether/commands/claude/build.md +65 -0
- package/.aether/commands/claude/chaos.md +336 -0
- package/.aether/commands/claude/colonize.md +259 -0
- package/.aether/commands/claude/continue.md +60 -0
- package/.aether/commands/claude/council.md +507 -0
- package/.aether/commands/claude/data-clean.md +81 -0
- package/.aether/commands/claude/dream.md +268 -0
- package/.aether/commands/claude/entomb.md +498 -0
- package/.aether/commands/claude/export-signals.md +57 -0
- package/.aether/commands/claude/feedback.md +96 -0
- package/.aether/commands/claude/flag.md +151 -0
- package/.aether/commands/claude/flags.md +169 -0
- package/.aether/commands/claude/focus.md +76 -0
- package/.aether/commands/claude/help.md +154 -0
- package/.aether/commands/claude/history.md +140 -0
- package/.aether/commands/claude/import-signals.md +71 -0
- package/.aether/commands/claude/init.md +505 -0
- package/.aether/commands/claude/insert-phase.md +105 -0
- package/.aether/commands/claude/interpret.md +278 -0
- package/.aether/commands/claude/lay-eggs.md +210 -0
- package/.aether/commands/claude/maturity.md +113 -0
- package/.aether/commands/claude/memory-details.md +77 -0
- package/.aether/commands/claude/migrate-state.md +171 -0
- package/.aether/commands/claude/oracle.md +642 -0
- package/.aether/commands/claude/organize.md +232 -0
- package/.aether/commands/claude/patrol.md +620 -0
- package/.aether/commands/claude/pause-colony.md +233 -0
- package/.aether/commands/claude/phase.md +115 -0
- package/.aether/commands/claude/pheromones.md +156 -0
- package/.aether/commands/claude/plan.md +693 -0
- package/.aether/commands/claude/preferences.md +65 -0
- package/.aether/commands/claude/quick.md +100 -0
- package/.aether/commands/claude/redirect.md +76 -0
- package/.aether/commands/claude/resume-colony.md +197 -0
- package/.aether/commands/claude/resume.md +388 -0
- package/.aether/commands/claude/run.md +231 -0
- package/.aether/commands/claude/seal.md +774 -0
- package/.aether/commands/claude/skill-create.md +286 -0
- package/.aether/commands/claude/status.md +410 -0
- package/.aether/commands/claude/swarm.md +349 -0
- package/.aether/commands/claude/tunnels.md +426 -0
- package/.aether/commands/claude/update.md +132 -0
- package/.aether/commands/claude/verify-castes.md +143 -0
- package/.aether/commands/claude/watch.md +239 -0
- package/.aether/commands/colonize.yaml +4 -0
- package/.aether/commands/council.yaml +205 -0
- package/.aether/commands/init.yaml +46 -13
- package/.aether/commands/insert-phase.yaml +4 -0
- package/.aether/commands/opencode/archaeology.md +331 -0
- package/.aether/commands/opencode/build.md +1168 -0
- package/.aether/commands/opencode/chaos.md +329 -0
- package/.aether/commands/opencode/colonize.md +195 -0
- package/.aether/commands/opencode/continue.md +1436 -0
- package/.aether/commands/opencode/council.md +437 -0
- package/.aether/commands/opencode/data-clean.md +77 -0
- package/.aether/commands/opencode/dream.md +260 -0
- package/.aether/commands/opencode/entomb.md +377 -0
- package/.aether/commands/opencode/export-signals.md +54 -0
- package/.aether/commands/opencode/feedback.md +99 -0
- package/.aether/commands/opencode/flag.md +149 -0
- package/.aether/commands/opencode/flags.md +167 -0
- package/.aether/commands/opencode/focus.md +73 -0
- package/.aether/commands/opencode/help.md +157 -0
- package/.aether/commands/opencode/history.md +136 -0
- package/.aether/commands/opencode/import-signals.md +68 -0
- package/.aether/commands/opencode/init.md +518 -0
- package/.aether/commands/opencode/insert-phase.md +111 -0
- package/.aether/commands/opencode/interpret.md +272 -0
- package/.aether/commands/opencode/lay-eggs.md +213 -0
- package/.aether/commands/opencode/maturity.md +108 -0
- package/.aether/commands/opencode/memory-details.md +83 -0
- package/.aether/commands/opencode/migrate-state.md +165 -0
- package/.aether/commands/opencode/oracle.md +593 -0
- package/.aether/commands/opencode/organize.md +226 -0
- package/.aether/commands/opencode/patrol.md +626 -0
- package/.aether/commands/opencode/pause-colony.md +203 -0
- package/.aether/commands/opencode/phase.md +113 -0
- package/.aether/commands/opencode/pheromones.md +162 -0
- package/.aether/commands/opencode/plan.md +684 -0
- package/.aether/commands/opencode/preferences.md +71 -0
- package/.aether/commands/opencode/quick.md +91 -0
- package/.aether/commands/opencode/redirect.md +84 -0
- package/.aether/commands/opencode/resume-colony.md +190 -0
- package/.aether/commands/opencode/resume.md +394 -0
- package/.aether/commands/opencode/run.md +237 -0
- package/.aether/commands/opencode/seal.md +452 -0
- package/.aether/commands/opencode/skill-create.md +63 -0
- package/.aether/commands/opencode/status.md +307 -0
- package/.aether/commands/opencode/swarm.md +15 -0
- package/.aether/commands/opencode/tunnels.md +400 -0
- package/.aether/commands/opencode/update.md +127 -0
- package/.aether/commands/opencode/verify-castes.md +139 -0
- package/.aether/commands/opencode/watch.md +227 -0
- package/.aether/commands/plan.yaml +53 -2
- package/.aether/commands/quick.yaml +104 -0
- package/.aether/commands/resume-colony.yaml +6 -4
- package/.aether/commands/resume.yaml +9 -0
- package/.aether/commands/run.yaml +37 -1
- package/.aether/commands/seal.yaml +9 -0
- package/.aether/commands/status.yaml +45 -1
- package/.aether/docs/command-playbooks/build-full.md +3 -2
- package/.aether/docs/command-playbooks/build-prep.md +12 -4
- package/.aether/docs/command-playbooks/build-verify.md +51 -0
- package/.aether/docs/command-playbooks/continue-advance.md +115 -6
- package/.aether/docs/command-playbooks/continue-full.md +1 -0
- package/.aether/docs/command-playbooks/continue-verify.md +33 -0
- package/.aether/utils/clash-detect.sh +239 -0
- package/.aether/utils/council.sh +425 -0
- package/.aether/utils/error-handler.sh +3 -3
- package/.aether/utils/flag.sh +23 -12
- package/.aether/utils/hive.sh +2 -2
- package/.aether/utils/hooks/clash-pre-tool-use.js +99 -0
- package/.aether/utils/immune.sh +508 -0
- package/.aether/utils/learning.sh +2 -2
- package/.aether/utils/merge-driver-lockfile.sh +35 -0
- package/.aether/utils/midden.sh +712 -0
- package/.aether/utils/pheromone.sh +1376 -108
- package/.aether/utils/queen.sh +31 -21
- package/.aether/utils/session.sh +264 -0
- package/.aether/utils/spawn-tree.sh +7 -7
- package/.aether/utils/spawn.sh +2 -2
- package/.aether/utils/state-api.sh +216 -5
- package/.aether/utils/swarm.sh +1 -1
- package/.aether/utils/worktree.sh +189 -0
- package/.claude/commands/ant/colonize.md +2 -0
- package/.claude/commands/ant/council.md +205 -0
- package/.claude/commands/ant/init.md +53 -14
- package/.claude/commands/ant/insert-phase.md +4 -0
- package/.claude/commands/ant/plan.md +27 -1
- package/.claude/commands/ant/quick.md +100 -0
- package/.claude/commands/ant/resume-colony.md +3 -2
- package/.claude/commands/ant/resume.md +9 -0
- package/.claude/commands/ant/run.md +37 -1
- package/.claude/commands/ant/seal.md +9 -0
- package/.claude/commands/ant/status.md +45 -1
- package/.opencode/commands/ant/colonize.md +2 -0
- package/.opencode/commands/ant/council.md +143 -0
- package/.opencode/commands/ant/init.md +53 -13
- package/.opencode/commands/ant/insert-phase.md +4 -0
- package/.opencode/commands/ant/plan.md +26 -1
- package/.opencode/commands/ant/quick.md +91 -0
- package/.opencode/commands/ant/resume-colony.md +3 -2
- package/.opencode/commands/ant/resume.md +9 -0
- package/.opencode/commands/ant/run.md +37 -1
- package/.opencode/commands/ant/status.md +2 -0
- package/CHANGELOG.md +116 -0
- package/README.md +34 -8
- package/bin/cli.js +103 -61
- package/bin/lib/banner.js +14 -0
- package/bin/lib/init.js +8 -7
- package/bin/lib/interactive-setup.js +251 -0
- package/bin/npx-entry.js +21 -0
- package/bin/npx-install.js +9 -167
- package/bin/validate-package.sh +23 -0
- package/package.json +11 -3
- package/.aether/docs/plans/pheromone-display-plan.md +0 -257
- package/.aether/schemas/example-prompt-builder.xml +0 -234
- package/.aether/scripts/incident-test-add.sh +0 -47
- package/.aether/scripts/weekly-audit.sh +0 -79
|
@@ -0,0 +1,508 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Immune response system — trophallaxis repair and scarification
|
|
3
|
+
# Provides: _trophallaxis_diagnose, _trophallaxis_retry, _scar_add, _scar_list,
|
|
4
|
+
# _scar_check, _immune_auto_scar
|
|
5
|
+
#
|
|
6
|
+
# These functions are sourced by aether-utils.sh at startup.
|
|
7
|
+
# All shared infrastructure (json_ok, json_err, atomic_write, acquire_lock,
|
|
8
|
+
# release_lock, LOCK_DIR, COLONY_DATA_DIR, error constants) is available.
|
|
9
|
+
|
|
10
|
+
# ---------------------------------------------------------------------------
|
|
11
|
+
# Internal helpers
|
|
12
|
+
# ---------------------------------------------------------------------------
|
|
13
|
+
|
|
14
|
+
_immune_data_dir() {
|
|
15
|
+
echo "$COLONY_DATA_DIR/immune"
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
_immune_scars_file() {
|
|
19
|
+
echo "$COLONY_DATA_DIR/immune/scars.json"
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
_immune_retry_log_file() {
|
|
23
|
+
echo "$COLONY_DATA_DIR/immune/retry-log.json"
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
_immune_ensure_dir() {
|
|
27
|
+
mkdir -p "$(_immune_data_dir)"
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
_immune_ensure_scars_file() {
|
|
31
|
+
local sf
|
|
32
|
+
sf="$(_immune_scars_file)"
|
|
33
|
+
_immune_ensure_dir
|
|
34
|
+
if [[ ! -f "$sf" ]]; then
|
|
35
|
+
printf '%s\n' '{"version":"1.0","scars":[]}' > "$sf"
|
|
36
|
+
fi
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
_immune_ensure_retry_log() {
|
|
40
|
+
local rf
|
|
41
|
+
rf="$(_immune_retry_log_file)"
|
|
42
|
+
_immune_ensure_dir
|
|
43
|
+
if [[ ! -f "$rf" ]]; then
|
|
44
|
+
printf '%s\n' '{"version":"1.0","tasks":{}}' > "$rf"
|
|
45
|
+
fi
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
# ---------------------------------------------------------------------------
|
|
49
|
+
# _trophallaxis_diagnose
|
|
50
|
+
# Usage: trophallaxis-diagnose --task-id <id> --failure <desc> [--phase N]
|
|
51
|
+
# ---------------------------------------------------------------------------
|
|
52
|
+
_trophallaxis_diagnose() {
|
|
53
|
+
local td_task_id=""
|
|
54
|
+
local td_failure=""
|
|
55
|
+
local td_phase=""
|
|
56
|
+
|
|
57
|
+
while [[ $# -gt 0 ]]; do
|
|
58
|
+
case "$1" in
|
|
59
|
+
--task-id) td_task_id="${2:-}"; shift 2 ;;
|
|
60
|
+
--failure) td_failure="${2:-}"; shift 2 ;;
|
|
61
|
+
--phase) td_phase="${2:-}"; shift 2 ;;
|
|
62
|
+
*) shift ;;
|
|
63
|
+
esac
|
|
64
|
+
done
|
|
65
|
+
|
|
66
|
+
if [[ -z "$td_task_id" ]]; then
|
|
67
|
+
json_err "$E_VALIDATION_FAILED" "trophallaxis-diagnose requires --task-id"
|
|
68
|
+
return
|
|
69
|
+
fi
|
|
70
|
+
|
|
71
|
+
if [[ -z "$td_failure" ]]; then
|
|
72
|
+
json_err "$E_VALIDATION_FAILED" "trophallaxis-diagnose requires --failure"
|
|
73
|
+
return
|
|
74
|
+
fi
|
|
75
|
+
|
|
76
|
+
local td_midden_file="$COLONY_DATA_DIR/midden/midden.json"
|
|
77
|
+
local td_related=0
|
|
78
|
+
local td_related_entries="[]"
|
|
79
|
+
local td_approach=""
|
|
80
|
+
|
|
81
|
+
# Search midden for related entries using keywords from failure description
|
|
82
|
+
if [[ -f "$td_midden_file" ]]; then
|
|
83
|
+
# Extract first keyword (longest word >= 4 chars) for search
|
|
84
|
+
local td_keyword
|
|
85
|
+
td_keyword=$(echo "$td_failure" | tr '[:upper:]' '[:lower:]' | \
|
|
86
|
+
grep -oE '[a-z]{4,}' | sort -rn -k1,1 | head -1 || echo "")
|
|
87
|
+
|
|
88
|
+
if [[ -n "$td_keyword" ]]; then
|
|
89
|
+
td_related=$(jq \
|
|
90
|
+
--arg q "$td_keyword" \
|
|
91
|
+
'[.entries // [] | .[] |
|
|
92
|
+
select(.acknowledged != true) |
|
|
93
|
+
select(.message | ascii_downcase | contains($q))
|
|
94
|
+
] | length' "$td_midden_file" 2>/dev/null || echo "0")
|
|
95
|
+
|
|
96
|
+
td_related_entries=$(jq \
|
|
97
|
+
--arg q "$td_keyword" \
|
|
98
|
+
'[.entries // [] | .[] |
|
|
99
|
+
select(.acknowledged != true) |
|
|
100
|
+
select(.message | ascii_downcase | contains($q)) |
|
|
101
|
+
{id, timestamp, category, source, message}
|
|
102
|
+
] | .[:5]' "$td_midden_file" 2>/dev/null || echo "[]")
|
|
103
|
+
else
|
|
104
|
+
# No usable keyword — scan all recent entries
|
|
105
|
+
td_related=$(jq '[.entries // [] | .[] | select(.acknowledged != true)] | length' \
|
|
106
|
+
"$td_midden_file" 2>/dev/null || echo "0")
|
|
107
|
+
fi
|
|
108
|
+
fi
|
|
109
|
+
|
|
110
|
+
# Build diagnosis text
|
|
111
|
+
local td_diagnosis
|
|
112
|
+
if [[ "$td_related" -gt 0 ]]; then
|
|
113
|
+
td_diagnosis="Found $td_related related failure(s) in midden matching: $td_failure"
|
|
114
|
+
td_approach="Review related midden entries for patterns. Address root cause before retrying."
|
|
115
|
+
else
|
|
116
|
+
td_diagnosis="No related failures found in midden for: $td_failure"
|
|
117
|
+
td_approach="Investigate failure from first principles. Check logs and dependencies."
|
|
118
|
+
fi
|
|
119
|
+
|
|
120
|
+
# Confidence: higher when related failures exist
|
|
121
|
+
local td_confidence
|
|
122
|
+
if [[ "$td_related" -ge 3 ]]; then
|
|
123
|
+
td_confidence="0.9"
|
|
124
|
+
elif [[ "$td_related" -ge 1 ]]; then
|
|
125
|
+
td_confidence="0.7"
|
|
126
|
+
else
|
|
127
|
+
td_confidence="0.4"
|
|
128
|
+
fi
|
|
129
|
+
|
|
130
|
+
json_ok "$(jq -n \
|
|
131
|
+
--arg task_id "$td_task_id" \
|
|
132
|
+
--arg failure "$td_failure" \
|
|
133
|
+
--arg diagnosis "$td_diagnosis" \
|
|
134
|
+
--argjson related_failures "$td_related" \
|
|
135
|
+
--arg suggested_approach "$td_approach" \
|
|
136
|
+
--argjson confidence "$td_confidence" \
|
|
137
|
+
--argjson related_entries "$td_related_entries" \
|
|
138
|
+
'{
|
|
139
|
+
task_id: $task_id,
|
|
140
|
+
failure: $failure,
|
|
141
|
+
diagnosis: $diagnosis,
|
|
142
|
+
related_failures: $related_failures,
|
|
143
|
+
suggested_approach: $suggested_approach,
|
|
144
|
+
confidence: $confidence,
|
|
145
|
+
related_entries: $related_entries
|
|
146
|
+
}')"
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
# ---------------------------------------------------------------------------
|
|
150
|
+
# _trophallaxis_retry
|
|
151
|
+
# Usage: trophallaxis-retry --task-id <id> --diagnosis <json>
|
|
152
|
+
# ---------------------------------------------------------------------------
|
|
153
|
+
_trophallaxis_retry() {
|
|
154
|
+
local tr_task_id=""
|
|
155
|
+
local tr_diagnosis=""
|
|
156
|
+
|
|
157
|
+
while [[ $# -gt 0 ]]; do
|
|
158
|
+
case "$1" in
|
|
159
|
+
--task-id) tr_task_id="${2:-}"; shift 2 ;;
|
|
160
|
+
--diagnosis) tr_diagnosis="${2:-}"; shift 2 ;;
|
|
161
|
+
*) shift ;;
|
|
162
|
+
esac
|
|
163
|
+
done
|
|
164
|
+
|
|
165
|
+
if [[ -z "$tr_task_id" ]]; then
|
|
166
|
+
json_err "$E_VALIDATION_FAILED" "trophallaxis-retry requires --task-id"
|
|
167
|
+
return
|
|
168
|
+
fi
|
|
169
|
+
|
|
170
|
+
_immune_ensure_retry_log
|
|
171
|
+
|
|
172
|
+
local tr_log_file
|
|
173
|
+
tr_log_file="$(_immune_retry_log_file)"
|
|
174
|
+
local tr_timestamp
|
|
175
|
+
tr_timestamp=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
|
|
176
|
+
|
|
177
|
+
# Read current retry count for this task
|
|
178
|
+
local tr_current_count
|
|
179
|
+
tr_current_count=$(jq -r --arg tid "$tr_task_id" \
|
|
180
|
+
'.tasks[$tid].retry_count // 0' "$tr_log_file" 2>/dev/null || echo "0")
|
|
181
|
+
local tr_new_count=$(( tr_current_count + 1 ))
|
|
182
|
+
|
|
183
|
+
# Validate diagnosis JSON (graceful: use empty object if invalid)
|
|
184
|
+
local tr_diag_json
|
|
185
|
+
if echo "$tr_diagnosis" | jq empty 2>/dev/null; then
|
|
186
|
+
tr_diag_json="$tr_diagnosis"
|
|
187
|
+
else
|
|
188
|
+
tr_diag_json="{}"
|
|
189
|
+
fi
|
|
190
|
+
|
|
191
|
+
# Build the retry entry
|
|
192
|
+
local tr_entry
|
|
193
|
+
tr_entry=$(jq -n \
|
|
194
|
+
--arg ts "$tr_timestamp" \
|
|
195
|
+
--argjson retry_count "$tr_new_count" \
|
|
196
|
+
--argjson diagnosis "$tr_diag_json" \
|
|
197
|
+
'{timestamp: $ts, retry_count: $retry_count, diagnosis: $diagnosis}')
|
|
198
|
+
|
|
199
|
+
# Update log with locking
|
|
200
|
+
local tr_updated
|
|
201
|
+
if acquire_lock "$tr_log_file" 2>/dev/null; then
|
|
202
|
+
tr_updated=$(jq \
|
|
203
|
+
--arg tid "$tr_task_id" \
|
|
204
|
+
--argjson entry "$tr_entry" \
|
|
205
|
+
--argjson new_count "$tr_new_count" \
|
|
206
|
+
'.tasks[$tid] = {
|
|
207
|
+
retry_count: $new_count,
|
|
208
|
+
last_attempt: $entry.timestamp,
|
|
209
|
+
last_diagnosis: $entry.diagnosis,
|
|
210
|
+
history: ((.tasks[$tid].history // []) + [$entry])
|
|
211
|
+
}' "$tr_log_file" 2>/dev/null)
|
|
212
|
+
|
|
213
|
+
if [[ -n "$tr_updated" ]]; then
|
|
214
|
+
atomic_write "$tr_log_file" "$tr_updated"
|
|
215
|
+
fi
|
|
216
|
+
release_lock 2>/dev/null || true
|
|
217
|
+
else
|
|
218
|
+
# Lockless fallback
|
|
219
|
+
tr_updated=$(jq \
|
|
220
|
+
--arg tid "$tr_task_id" \
|
|
221
|
+
--argjson entry "$tr_entry" \
|
|
222
|
+
--argjson new_count "$tr_new_count" \
|
|
223
|
+
'.tasks[$tid] = {
|
|
224
|
+
retry_count: $new_count,
|
|
225
|
+
last_attempt: $entry.timestamp,
|
|
226
|
+
last_diagnosis: $entry.diagnosis,
|
|
227
|
+
history: ((.tasks[$tid].history // []) + [$entry])
|
|
228
|
+
}' "$tr_log_file" 2>/dev/null)
|
|
229
|
+
|
|
230
|
+
if [[ -n "$tr_updated" ]]; then
|
|
231
|
+
atomic_write "$tr_log_file" "$tr_updated"
|
|
232
|
+
fi
|
|
233
|
+
fi
|
|
234
|
+
|
|
235
|
+
json_ok "$(jq -n \
|
|
236
|
+
--arg task_id "$tr_task_id" \
|
|
237
|
+
--argjson retry_count "$tr_new_count" \
|
|
238
|
+
'{task_id: $task_id, retry_count: $retry_count, diagnosis_injected: true}')"
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
# ---------------------------------------------------------------------------
|
|
242
|
+
# _scar_add
|
|
243
|
+
# Usage: scar-add --pattern <desc> --severity <low|medium|high> [--phase N] [--source <src>]
|
|
244
|
+
# ---------------------------------------------------------------------------
|
|
245
|
+
_scar_add() {
|
|
246
|
+
local sa_pattern=""
|
|
247
|
+
local sa_severity=""
|
|
248
|
+
local sa_phase=""
|
|
249
|
+
local sa_source="unknown"
|
|
250
|
+
|
|
251
|
+
while [[ $# -gt 0 ]]; do
|
|
252
|
+
case "$1" in
|
|
253
|
+
--pattern) sa_pattern="${2:-}"; shift 2 ;;
|
|
254
|
+
--severity) sa_severity="${2:-}"; shift 2 ;;
|
|
255
|
+
--phase) sa_phase="${2:-}"; shift 2 ;;
|
|
256
|
+
--source) sa_source="${2:-}"; shift 2 ;;
|
|
257
|
+
*) shift ;;
|
|
258
|
+
esac
|
|
259
|
+
done
|
|
260
|
+
|
|
261
|
+
if [[ -z "$sa_pattern" ]]; then
|
|
262
|
+
json_err "$E_VALIDATION_FAILED" "scar-add requires --pattern"
|
|
263
|
+
return
|
|
264
|
+
fi
|
|
265
|
+
|
|
266
|
+
# Default severity if not provided
|
|
267
|
+
if [[ -z "$sa_severity" ]]; then
|
|
268
|
+
sa_severity="medium"
|
|
269
|
+
fi
|
|
270
|
+
|
|
271
|
+
# Validate severity
|
|
272
|
+
case "$sa_severity" in
|
|
273
|
+
low|medium|high) ;;
|
|
274
|
+
*)
|
|
275
|
+
json_err "$E_VALIDATION_FAILED" "scar-add --severity must be low, medium, or high"
|
|
276
|
+
return
|
|
277
|
+
;;
|
|
278
|
+
esac
|
|
279
|
+
|
|
280
|
+
_immune_ensure_scars_file
|
|
281
|
+
|
|
282
|
+
local sa_scars_file
|
|
283
|
+
sa_scars_file="$(_immune_scars_file)"
|
|
284
|
+
local sa_timestamp
|
|
285
|
+
sa_timestamp=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
|
|
286
|
+
local sa_id
|
|
287
|
+
sa_id="scar_$(date +%s)_$$"
|
|
288
|
+
|
|
289
|
+
# Build phase value for JSON
|
|
290
|
+
local sa_phase_val
|
|
291
|
+
if [[ -n "$sa_phase" ]]; then
|
|
292
|
+
sa_phase_val="$sa_phase"
|
|
293
|
+
else
|
|
294
|
+
sa_phase_val="null"
|
|
295
|
+
fi
|
|
296
|
+
|
|
297
|
+
local sa_new_scar
|
|
298
|
+
sa_new_scar=$(jq -n \
|
|
299
|
+
--arg id "$sa_id" \
|
|
300
|
+
--arg pattern "$sa_pattern" \
|
|
301
|
+
--arg severity "$sa_severity" \
|
|
302
|
+
--arg phase "$sa_phase_val" \
|
|
303
|
+
--arg source "$sa_source" \
|
|
304
|
+
--arg created_at "$sa_timestamp" \
|
|
305
|
+
'{
|
|
306
|
+
id: $id,
|
|
307
|
+
pattern: $pattern,
|
|
308
|
+
severity: $severity,
|
|
309
|
+
phase: (if $phase == "null" then null else ($phase | tonumber? // $phase) end),
|
|
310
|
+
source: $source,
|
|
311
|
+
created_at: $created_at,
|
|
312
|
+
retry_count: 0,
|
|
313
|
+
active: true
|
|
314
|
+
}')
|
|
315
|
+
|
|
316
|
+
local sa_updated
|
|
317
|
+
if acquire_lock "$sa_scars_file" 2>/dev/null; then
|
|
318
|
+
sa_updated=$(jq \
|
|
319
|
+
--argjson scar "$sa_new_scar" \
|
|
320
|
+
'.scars += [$scar]' "$sa_scars_file" 2>/dev/null)
|
|
321
|
+
if [[ -n "$sa_updated" ]]; then
|
|
322
|
+
atomic_write "$sa_scars_file" "$sa_updated"
|
|
323
|
+
fi
|
|
324
|
+
release_lock 2>/dev/null || true
|
|
325
|
+
else
|
|
326
|
+
sa_updated=$(jq \
|
|
327
|
+
--argjson scar "$sa_new_scar" \
|
|
328
|
+
'.scars += [$scar]' "$sa_scars_file" 2>/dev/null)
|
|
329
|
+
if [[ -n "$sa_updated" ]]; then
|
|
330
|
+
atomic_write "$sa_scars_file" "$sa_updated"
|
|
331
|
+
fi
|
|
332
|
+
fi
|
|
333
|
+
|
|
334
|
+
local sa_count
|
|
335
|
+
sa_count=$(jq '[.scars[]] | length' "$sa_scars_file" 2>/dev/null || echo "1")
|
|
336
|
+
|
|
337
|
+
json_ok "$(jq -n \
|
|
338
|
+
--arg id "$sa_id" \
|
|
339
|
+
--argjson scar_count "$sa_count" \
|
|
340
|
+
'{id: $id, scar_count: $scar_count}')"
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
# ---------------------------------------------------------------------------
|
|
344
|
+
# _scar_list
|
|
345
|
+
# Usage: scar-list [--active] [--severity <level>]
|
|
346
|
+
# ---------------------------------------------------------------------------
|
|
347
|
+
_scar_list() {
|
|
348
|
+
local sl_active_only=false
|
|
349
|
+
local sl_severity=""
|
|
350
|
+
|
|
351
|
+
while [[ $# -gt 0 ]]; do
|
|
352
|
+
case "$1" in
|
|
353
|
+
--active) sl_active_only=true; shift ;;
|
|
354
|
+
--severity) sl_severity="${2:-}"; shift 2 ;;
|
|
355
|
+
*) shift ;;
|
|
356
|
+
esac
|
|
357
|
+
done
|
|
358
|
+
|
|
359
|
+
local sl_scars_file
|
|
360
|
+
sl_scars_file="$(_immune_scars_file)"
|
|
361
|
+
|
|
362
|
+
if [[ ! -f "$sl_scars_file" ]]; then
|
|
363
|
+
json_ok '{"total":0,"active":0,"scars":[]}'
|
|
364
|
+
return 0
|
|
365
|
+
fi
|
|
366
|
+
|
|
367
|
+
local sl_result
|
|
368
|
+
sl_result=$(jq \
|
|
369
|
+
--argjson active_only "$sl_active_only" \
|
|
370
|
+
--arg severity "$sl_severity" \
|
|
371
|
+
'
|
|
372
|
+
[.scars // [] | .[] |
|
|
373
|
+
if $active_only then select(.active == true) else . end |
|
|
374
|
+
if ($severity | length) > 0 then select(.severity == $severity) else . end
|
|
375
|
+
] |
|
|
376
|
+
. as $filtered |
|
|
377
|
+
{
|
|
378
|
+
total: ($filtered | length),
|
|
379
|
+
active: ($filtered | map(select(.active == true)) | length),
|
|
380
|
+
scars: $filtered
|
|
381
|
+
}
|
|
382
|
+
' "$sl_scars_file" 2>/dev/null)
|
|
383
|
+
|
|
384
|
+
if [[ -z "$sl_result" ]]; then
|
|
385
|
+
json_ok '{"total":0,"active":0,"scars":[]}'
|
|
386
|
+
return 0
|
|
387
|
+
fi
|
|
388
|
+
|
|
389
|
+
json_ok "$sl_result"
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
# ---------------------------------------------------------------------------
|
|
393
|
+
# _scar_check
|
|
394
|
+
# Usage: scar-check --task <desc>
|
|
395
|
+
# ---------------------------------------------------------------------------
|
|
396
|
+
_scar_check() {
|
|
397
|
+
local sc_task=""
|
|
398
|
+
|
|
399
|
+
while [[ $# -gt 0 ]]; do
|
|
400
|
+
case "$1" in
|
|
401
|
+
--task) sc_task="${2:-}"; shift 2 ;;
|
|
402
|
+
*) shift ;;
|
|
403
|
+
esac
|
|
404
|
+
done
|
|
405
|
+
|
|
406
|
+
if [[ -z "$sc_task" ]]; then
|
|
407
|
+
json_err "$E_VALIDATION_FAILED" "scar-check requires --task"
|
|
408
|
+
return
|
|
409
|
+
fi
|
|
410
|
+
|
|
411
|
+
local sc_scars_file
|
|
412
|
+
sc_scars_file="$(_immune_scars_file)"
|
|
413
|
+
|
|
414
|
+
if [[ ! -f "$sc_scars_file" ]]; then
|
|
415
|
+
json_ok '{"matches":0,"scars":[]}'
|
|
416
|
+
return 0
|
|
417
|
+
fi
|
|
418
|
+
|
|
419
|
+
local sc_result
|
|
420
|
+
sc_result=$(jq \
|
|
421
|
+
--arg task "$sc_task" \
|
|
422
|
+
'
|
|
423
|
+
[.scars // [] | .[] |
|
|
424
|
+
select(.active == true) |
|
|
425
|
+
# Split pattern into words, check if any word from pattern appears in task
|
|
426
|
+
select(
|
|
427
|
+
(.pattern | ascii_downcase) as $pat |
|
|
428
|
+
($pat | split(" ") | .[] | select(length >= 3)) as $word |
|
|
429
|
+
($task | ascii_downcase) | contains($word)
|
|
430
|
+
)
|
|
431
|
+
] |
|
|
432
|
+
. as $matches |
|
|
433
|
+
{
|
|
434
|
+
matches: ($matches | length),
|
|
435
|
+
scars: $matches
|
|
436
|
+
}
|
|
437
|
+
' "$sc_scars_file" 2>/dev/null)
|
|
438
|
+
|
|
439
|
+
if [[ -z "$sc_result" ]]; then
|
|
440
|
+
json_ok '{"matches":0,"scars":[]}'
|
|
441
|
+
return 0
|
|
442
|
+
fi
|
|
443
|
+
|
|
444
|
+
json_ok "$sc_result"
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
# ---------------------------------------------------------------------------
|
|
448
|
+
# _immune_auto_scar
|
|
449
|
+
# Usage: immune-auto-scar --task-id <id>
|
|
450
|
+
# ---------------------------------------------------------------------------
|
|
451
|
+
_immune_auto_scar() {
|
|
452
|
+
local ias_task_id=""
|
|
453
|
+
|
|
454
|
+
while [[ $# -gt 0 ]]; do
|
|
455
|
+
case "$1" in
|
|
456
|
+
--task-id) ias_task_id="${2:-}"; shift 2 ;;
|
|
457
|
+
*) shift ;;
|
|
458
|
+
esac
|
|
459
|
+
done
|
|
460
|
+
|
|
461
|
+
if [[ -z "$ias_task_id" ]]; then
|
|
462
|
+
json_err "$E_VALIDATION_FAILED" "immune-auto-scar requires --task-id"
|
|
463
|
+
return
|
|
464
|
+
fi
|
|
465
|
+
|
|
466
|
+
local ias_log_file
|
|
467
|
+
ias_log_file="$(_immune_retry_log_file)"
|
|
468
|
+
|
|
469
|
+
if [[ ! -f "$ias_log_file" ]]; then
|
|
470
|
+
json_ok '{"auto_scarred":false,"retry_count":0}'
|
|
471
|
+
return 0
|
|
472
|
+
fi
|
|
473
|
+
|
|
474
|
+
local ias_retry_count
|
|
475
|
+
ias_retry_count=$(jq -r --arg tid "$ias_task_id" \
|
|
476
|
+
'.tasks[$tid].retry_count // 0' "$ias_log_file" 2>/dev/null || echo "0")
|
|
477
|
+
|
|
478
|
+
if [[ "$ias_retry_count" -lt 3 ]]; then
|
|
479
|
+
json_ok "$(jq -n \
|
|
480
|
+
--argjson retry_count "$ias_retry_count" \
|
|
481
|
+
'{auto_scarred: false, retry_count: $retry_count}')"
|
|
482
|
+
return 0
|
|
483
|
+
fi
|
|
484
|
+
|
|
485
|
+
# Auto-create a scar for this task
|
|
486
|
+
local ias_last_diagnosis
|
|
487
|
+
ias_last_diagnosis=$(jq -r --arg tid "$ias_task_id" \
|
|
488
|
+
'.tasks[$tid].last_diagnosis.failure // ""' "$ias_log_file" 2>/dev/null || echo "")
|
|
489
|
+
|
|
490
|
+
local ias_pattern
|
|
491
|
+
if [[ -n "$ias_last_diagnosis" ]]; then
|
|
492
|
+
ias_pattern="$ias_last_diagnosis"
|
|
493
|
+
else
|
|
494
|
+
ias_pattern="task $ias_task_id failed persistently (auto-scarred after $ias_retry_count retries)"
|
|
495
|
+
fi
|
|
496
|
+
|
|
497
|
+
# Determine severity based on retry count
|
|
498
|
+
local ias_severity="medium"
|
|
499
|
+
if [[ "$ias_retry_count" -ge 5 ]]; then
|
|
500
|
+
ias_severity="high"
|
|
501
|
+
fi
|
|
502
|
+
|
|
503
|
+
_scar_add --pattern "$ias_pattern" --severity "$ias_severity" --source "immune-auto-scar" >/dev/null
|
|
504
|
+
|
|
505
|
+
json_ok "$(jq -n \
|
|
506
|
+
--argjson retry_count "$ias_retry_count" \
|
|
507
|
+
'{auto_scarred: true, retry_count: $retry_count}')"
|
|
508
|
+
}
|
|
@@ -431,11 +431,11 @@ _learning_promote_auto() {
|
|
|
431
431
|
# SUPPRESS:OK -- read-default: returns fallback on failure
|
|
432
432
|
--evidence "Auto-promoted after $observation_count observations (confidence: $lp_confidence)" 2>/dev/null \
|
|
433
433
|
|| _aether_log_error "Could not create instinct from promoted learning"
|
|
434
|
-
json_ok "$(jq -
|
|
434
|
+
json_ok "$(jq -nc --argjson pt "$policy_threshold" --argjson oc "$observation_count" --argjson cc "$colony_count" --arg et "$event_type" '{promoted: true, mode: "auto", policy_threshold: $pt, observation_count: $oc, colony_count: $cc, event_type: $et}')"
|
|
435
435
|
else
|
|
436
436
|
# SUPPRESS:OK -- read-default: query may return empty
|
|
437
437
|
promote_msg=$(echo "$promote_result" | jq -r '.error.message // "promotion_failed"' 2>/dev/null || echo "promotion_failed")
|
|
438
|
-
result=$(jq -
|
|
438
|
+
result=$(jq -nc \
|
|
439
439
|
--arg reason "promotion_failed" \
|
|
440
440
|
--arg message "$promote_msg" \
|
|
441
441
|
--argjson policy_threshold "$policy_threshold" \
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Merge Driver: npm lockfile auto-merge
|
|
3
|
+
#
|
|
4
|
+
# Resolves package-lock.json merge conflicts by keeping "ours" (the branch
|
|
5
|
+
# being merged into). Lockfiles are deterministic outputs of package.json,
|
|
6
|
+
# so the correct resolution is always to regenerate from the target branch's
|
|
7
|
+
# package.json, which effectively means keeping "ours".
|
|
8
|
+
#
|
|
9
|
+
# Usage: merge-driver-lockfile.sh %O %A %B
|
|
10
|
+
# %O = ancestor (base version)
|
|
11
|
+
# %A = ours (current branch, the version we want to keep)
|
|
12
|
+
# %B = theirs (incoming branch)
|
|
13
|
+
#
|
|
14
|
+
# Git merge driver contract:
|
|
15
|
+
# Exit 0 = conflict resolved (merge continues)
|
|
16
|
+
# Exit non-zero = conflict unresolved
|
|
17
|
+
#
|
|
18
|
+
# This driver is configured via:
|
|
19
|
+
# git config merge.lockfile.name "npm lockfile auto-merge"
|
|
20
|
+
# git config merge.lockfile.driver "bash .aether/utils/merge-driver-lockfile.sh %O %A %B"
|
|
21
|
+
|
|
22
|
+
set -euo pipefail
|
|
23
|
+
|
|
24
|
+
ANCESTOR="${1:-}"
|
|
25
|
+
OURS="${2:-}"
|
|
26
|
+
THEIRS="${3:-}"
|
|
27
|
+
|
|
28
|
+
# Strategy: keep "ours" unchanged.
|
|
29
|
+
# The "ours" file already contains the correct content on disk.
|
|
30
|
+
# We do nothing -- git considers the file resolved when we exit 0.
|
|
31
|
+
#
|
|
32
|
+
# Log for debugging (to stderr so it does not pollute merge output)
|
|
33
|
+
echo "[aether] merge-driver: resolved package-lock.json conflict (kept ours)" >&2
|
|
34
|
+
|
|
35
|
+
exit 0
|