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
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#!/bin/bash
|
|
2
2
|
# State API facade -- centralized COLONY_STATE.json access
|
|
3
|
-
# Provides: _state_read, _state_write, _state_read_field, _state_mutate, _state_migrate
|
|
3
|
+
# Provides: _state_read, _state_write, _state_read_field, _state_mutate, _state_migrate,
|
|
4
|
+
# _colony_vital_signs
|
|
4
5
|
#
|
|
5
6
|
# These functions are sourced by aether-utils.sh at startup.
|
|
6
7
|
# All shared infrastructure (json_ok, json_err, atomic_write, acquire_lock,
|
|
@@ -95,11 +96,32 @@ _state_write() {
|
|
|
95
96
|
|
|
96
97
|
_state_mutate() {
|
|
97
98
|
# Read-modify-write COLONY_STATE.json with a jq expression
|
|
98
|
-
# Usage: state-mutate '<jq_expression>'
|
|
99
|
+
# Usage: state-mutate [--arg NAME VALUE] [--argjson NAME VALUE] '<jq_expression>'
|
|
100
|
+
# Supports jq --arg, --argjson, --slurpfile, --rawfile flags (forwarded to jq)
|
|
99
101
|
# Acquires lock, creates backup, applies jq, validates, writes atomically
|
|
100
102
|
# Returns: json_ok with mutated:true, or json_err on failure
|
|
101
103
|
|
|
102
|
-
|
|
104
|
+
# Parse jq flags (--arg, --argjson, --slurpfile, --rawfile) from arguments
|
|
105
|
+
# The jq expression is always the last argument (after all flags)
|
|
106
|
+
local sm_jq_flags=()
|
|
107
|
+
local sm_expr=""
|
|
108
|
+
local i=0
|
|
109
|
+
local args=("$@")
|
|
110
|
+
|
|
111
|
+
while [[ $i -lt ${#args[@]} ]]; do
|
|
112
|
+
case "${args[$i]}" in
|
|
113
|
+
--arg|--argjson|--slurpfile|--rawfile)
|
|
114
|
+
# Flag requires a name and value — consume next two args
|
|
115
|
+
sm_jq_flags+=("${args[$i]}" "${args[$((i+1))]}" "${args[$((i+2))]}")
|
|
116
|
+
i=$((i + 3))
|
|
117
|
+
;;
|
|
118
|
+
*)
|
|
119
|
+
# Last argument is the jq expression
|
|
120
|
+
sm_expr="${args[$i]}"
|
|
121
|
+
i=$((i + 1))
|
|
122
|
+
;;
|
|
123
|
+
esac
|
|
124
|
+
done
|
|
103
125
|
|
|
104
126
|
if [[ -z "$sm_expr" ]]; then
|
|
105
127
|
json_err "$E_VALIDATION_FAILED" "state-mutate requires a jq expression argument"
|
|
@@ -121,8 +143,8 @@ _state_mutate() {
|
|
|
121
143
|
fi
|
|
122
144
|
fi
|
|
123
145
|
|
|
124
|
-
# Apply jq expression to current state
|
|
125
|
-
sm_updated=$(jq "$sm_expr" "$sm_state_file" 2>/dev/null) || {
|
|
146
|
+
# Apply jq expression to current state (with forwarded flags)
|
|
147
|
+
sm_updated=$(jq ${sm_jq_flags[@]+"${sm_jq_flags[@]}"} "$sm_expr" "$sm_state_file" 2>/dev/null) || {
|
|
126
148
|
release_lock 2>/dev/null || true # SUPPRESS:OK -- cleanup: lock may not be held
|
|
127
149
|
json_err "$E_JSON_INVALID" "jq expression failed: $sm_expr"
|
|
128
150
|
}
|
|
@@ -197,3 +219,192 @@ _state_migrate() {
|
|
|
197
219
|
[[ "$sm_lock_held" == "true" ]] && release_lock 2>/dev/null || true # SUPPRESS:OK -- cleanup: lock may not be held
|
|
198
220
|
fi
|
|
199
221
|
}
|
|
222
|
+
|
|
223
|
+
# ============================================================================
|
|
224
|
+
# _colony_vital_signs
|
|
225
|
+
# Compute colony health metrics from existing data files
|
|
226
|
+
# Usage: colony-vital-signs
|
|
227
|
+
# Returns: JSON with build_velocity, error_rate, signal_health, memory_pressure,
|
|
228
|
+
# colony_age_hours, and overall_health (0-100)
|
|
229
|
+
# Gracefully degrades: missing files produce zero/default values
|
|
230
|
+
# ============================================================================
|
|
231
|
+
_colony_vital_signs() {
|
|
232
|
+
local cvs_state_file="$COLONY_DATA_DIR/COLONY_STATE.json"
|
|
233
|
+
local cvs_midden_file="$COLONY_DATA_DIR/midden/midden.json"
|
|
234
|
+
local cvs_phero_file="$COLONY_DATA_DIR/pheromones.json"
|
|
235
|
+
local cvs_session_file="$COLONY_DATA_DIR/session.json"
|
|
236
|
+
|
|
237
|
+
# --- Compute 24h window boundary ---
|
|
238
|
+
local cvs_now
|
|
239
|
+
cvs_now=$(date -u +%s 2>/dev/null || echo "0")
|
|
240
|
+
local cvs_window_start=$(( cvs_now - 86400 ))
|
|
241
|
+
|
|
242
|
+
# ---- build_velocity: count phase_completed events in last 24h ----
|
|
243
|
+
local cvs_phases_per_day=0
|
|
244
|
+
if [[ -f "$cvs_state_file" ]]; then
|
|
245
|
+
cvs_phases_per_day=$(jq --argjson win "$cvs_window_start" '
|
|
246
|
+
[.events[]? |
|
|
247
|
+
select(. != null) |
|
|
248
|
+
select(test("\\|phase_completed\\|")) |
|
|
249
|
+
capture("^(?P<ts>[^|]+)\\|") |
|
|
250
|
+
.ts |
|
|
251
|
+
gsub("[TZ:-]"; " ") |
|
|
252
|
+
split(" ") |
|
|
253
|
+
if length >= 6 then
|
|
254
|
+
(.[0:6] | join(" ")) |
|
|
255
|
+
# convert to comparable string for ordering -- full ISO compare
|
|
256
|
+
. as $s | $s
|
|
257
|
+
else . end
|
|
258
|
+
] | length
|
|
259
|
+
' "$cvs_state_file" 2>/dev/null || echo "0")
|
|
260
|
+
|
|
261
|
+
# Simpler approach: use string comparison on ISO timestamps
|
|
262
|
+
# Compute the 24h-ago timestamp as ISO string
|
|
263
|
+
local cvs_cutoff_iso
|
|
264
|
+
cvs_cutoff_iso=$(date -u -r "$cvs_window_start" '+%Y-%m-%dT%H:%M:%SZ' 2>/dev/null \
|
|
265
|
+
|| date -u -d "@$cvs_window_start" '+%Y-%m-%dT%H:%M:%SZ' 2>/dev/null \
|
|
266
|
+
|| echo "")
|
|
267
|
+
|
|
268
|
+
if [[ -n "$cvs_cutoff_iso" ]]; then
|
|
269
|
+
cvs_phases_per_day=$(jq --arg cutoff "$cvs_cutoff_iso" '
|
|
270
|
+
[.events[]? |
|
|
271
|
+
select(. != null and (type == "string")) |
|
|
272
|
+
select(test("\\|phase_completed\\|")) |
|
|
273
|
+
split("|") | .[0] |
|
|
274
|
+
select(. >= $cutoff)
|
|
275
|
+
] | length
|
|
276
|
+
' "$cvs_state_file" 2>/dev/null || echo "0")
|
|
277
|
+
fi
|
|
278
|
+
fi
|
|
279
|
+
# Normalize: ensure integer
|
|
280
|
+
cvs_phases_per_day=$(( cvs_phases_per_day + 0 )) 2>/dev/null || cvs_phases_per_day=0
|
|
281
|
+
|
|
282
|
+
# Determine trend (simple heuristic: any builds = steady, 0 = idle)
|
|
283
|
+
local cvs_bv_trend="idle"
|
|
284
|
+
[[ "$cvs_phases_per_day" -ge 1 ]] && cvs_bv_trend="steady"
|
|
285
|
+
[[ "$cvs_phases_per_day" -ge 3 ]] && cvs_bv_trend="accelerating"
|
|
286
|
+
|
|
287
|
+
# ---- error_rate: unreviewed midden entries in last 24h ----
|
|
288
|
+
local cvs_errors_per_day=0
|
|
289
|
+
local cvs_err_status="clean"
|
|
290
|
+
if [[ -f "$cvs_midden_file" ]]; then
|
|
291
|
+
local cvs_cutoff_iso_err
|
|
292
|
+
cvs_cutoff_iso_err=$(date -u -r "$cvs_window_start" '+%Y-%m-%dT%H:%M:%SZ' 2>/dev/null \
|
|
293
|
+
|| date -u -d "@$cvs_window_start" '+%Y-%m-%dT%H:%M:%SZ' 2>/dev/null \
|
|
294
|
+
|| echo "")
|
|
295
|
+
|
|
296
|
+
if [[ -n "$cvs_cutoff_iso_err" ]]; then
|
|
297
|
+
cvs_errors_per_day=$(jq --arg cutoff "$cvs_cutoff_iso_err" '
|
|
298
|
+
[(.entries // [])[]? |
|
|
299
|
+
select(.reviewed == false or .reviewed == null) |
|
|
300
|
+
select((.timestamp // "") >= $cutoff)
|
|
301
|
+
] | length
|
|
302
|
+
' "$cvs_midden_file" 2>/dev/null || echo "0")
|
|
303
|
+
else
|
|
304
|
+
# Fallback: count all unreviewed
|
|
305
|
+
cvs_errors_per_day=$(jq '
|
|
306
|
+
[(.entries // [])[]? | select(.reviewed == false or .reviewed == null)] | length
|
|
307
|
+
' "$cvs_midden_file" 2>/dev/null || echo "0")
|
|
308
|
+
fi
|
|
309
|
+
fi
|
|
310
|
+
cvs_errors_per_day=$(( cvs_errors_per_day + 0 )) 2>/dev/null || cvs_errors_per_day=0
|
|
311
|
+
|
|
312
|
+
if [[ "$cvs_errors_per_day" -eq 0 ]]; then
|
|
313
|
+
cvs_err_status="clean"
|
|
314
|
+
elif [[ "$cvs_errors_per_day" -le 2 ]]; then
|
|
315
|
+
cvs_err_status="nominal"
|
|
316
|
+
elif [[ "$cvs_errors_per_day" -le 5 ]]; then
|
|
317
|
+
cvs_err_status="elevated"
|
|
318
|
+
else
|
|
319
|
+
cvs_err_status="critical"
|
|
320
|
+
fi
|
|
321
|
+
|
|
322
|
+
# ---- signal_health: count active pheromones ----
|
|
323
|
+
local cvs_active_count=0
|
|
324
|
+
local cvs_sig_status="dormant"
|
|
325
|
+
if [[ -f "$cvs_phero_file" ]]; then
|
|
326
|
+
cvs_active_count=$(jq '
|
|
327
|
+
[.signals[]? | select(.active == true)] | length
|
|
328
|
+
' "$cvs_phero_file" 2>/dev/null || echo "0")
|
|
329
|
+
fi
|
|
330
|
+
cvs_active_count=$(( cvs_active_count + 0 )) 2>/dev/null || cvs_active_count=0
|
|
331
|
+
|
|
332
|
+
if [[ "$cvs_active_count" -eq 0 ]]; then
|
|
333
|
+
cvs_sig_status="dormant"
|
|
334
|
+
elif [[ "$cvs_active_count" -le 3 ]]; then
|
|
335
|
+
cvs_sig_status="guided"
|
|
336
|
+
else
|
|
337
|
+
cvs_sig_status="active"
|
|
338
|
+
fi
|
|
339
|
+
|
|
340
|
+
# ---- memory_pressure: count instincts ----
|
|
341
|
+
local cvs_instinct_count=0
|
|
342
|
+
local cvs_mem_status="empty"
|
|
343
|
+
if [[ -f "$cvs_state_file" ]]; then
|
|
344
|
+
# instincts may be a JSON string (serialized array) or a real array
|
|
345
|
+
local cvs_raw_instincts
|
|
346
|
+
cvs_raw_instincts=$(jq -r '.memory.instincts // "[]"' "$cvs_state_file" 2>/dev/null || echo "[]")
|
|
347
|
+
# Handle both string-encoded and native array
|
|
348
|
+
cvs_instinct_count=$(echo "$cvs_raw_instincts" | jq -r 'if type == "string" then (. | fromjson | length) elif type == "array" then length else 0 end' 2>/dev/null || echo "0")
|
|
349
|
+
fi
|
|
350
|
+
cvs_instinct_count=$(( cvs_instinct_count + 0 )) 2>/dev/null || cvs_instinct_count=0
|
|
351
|
+
|
|
352
|
+
if [[ "$cvs_instinct_count" -eq 0 ]]; then
|
|
353
|
+
cvs_mem_status="empty"
|
|
354
|
+
elif [[ "$cvs_instinct_count" -le 5 ]]; then
|
|
355
|
+
cvs_mem_status="growing"
|
|
356
|
+
elif [[ "$cvs_instinct_count" -le 15 ]]; then
|
|
357
|
+
cvs_mem_status="healthy"
|
|
358
|
+
else
|
|
359
|
+
cvs_mem_status="rich"
|
|
360
|
+
fi
|
|
361
|
+
|
|
362
|
+
# ---- colony_age_hours: hours since initialized_at ----
|
|
363
|
+
local cvs_age_hours=0
|
|
364
|
+
if [[ -f "$cvs_state_file" ]]; then
|
|
365
|
+
local cvs_init_at
|
|
366
|
+
cvs_init_at=$(jq -r '.initialized_at // empty' "$cvs_state_file" 2>/dev/null || echo "")
|
|
367
|
+
if [[ -n "$cvs_init_at" ]]; then
|
|
368
|
+
local cvs_init_ts
|
|
369
|
+
cvs_init_ts=$(date -u -j -f '%Y-%m-%dT%H:%M:%SZ' "$cvs_init_at" '+%s' 2>/dev/null \
|
|
370
|
+
|| date -u -d "$cvs_init_at" '+%s' 2>/dev/null \
|
|
371
|
+
|| echo "0")
|
|
372
|
+
if [[ "$cvs_init_ts" -gt 0 && "$cvs_now" -gt "$cvs_init_ts" ]]; then
|
|
373
|
+
cvs_age_hours=$(( (cvs_now - cvs_init_ts) / 3600 ))
|
|
374
|
+
fi
|
|
375
|
+
fi
|
|
376
|
+
fi
|
|
377
|
+
|
|
378
|
+
# ---- overall_health: weighted 0-100 score ----
|
|
379
|
+
# Components (max points each):
|
|
380
|
+
# recent builds (+30): has at least one phase_completed in 24h
|
|
381
|
+
# low errors (+30): zero unreviewed errors in 24h
|
|
382
|
+
# signals exist (+20): at least one active pheromone
|
|
383
|
+
# instincts growing (+20): at least one instinct
|
|
384
|
+
local cvs_score=0
|
|
385
|
+
[[ "$cvs_phases_per_day" -ge 1 ]] && cvs_score=$(( cvs_score + 30 ))
|
|
386
|
+
[[ "$cvs_errors_per_day" -eq 0 ]] && cvs_score=$(( cvs_score + 30 ))
|
|
387
|
+
[[ "$cvs_active_count" -ge 1 ]] && cvs_score=$(( cvs_score + 20 ))
|
|
388
|
+
[[ "$cvs_instinct_count" -ge 1 ]] && cvs_score=$(( cvs_score + 20 ))
|
|
389
|
+
[[ "$cvs_score" -gt 100 ]] && cvs_score=100
|
|
390
|
+
|
|
391
|
+
json_ok "$(jq -n \
|
|
392
|
+
--argjson phases_per_day "$cvs_phases_per_day" \
|
|
393
|
+
--arg bv_trend "$cvs_bv_trend" \
|
|
394
|
+
--argjson errors_per_day "$cvs_errors_per_day" \
|
|
395
|
+
--arg err_status "$cvs_err_status" \
|
|
396
|
+
--argjson active_count "$cvs_active_count" \
|
|
397
|
+
--arg sig_status "$cvs_sig_status" \
|
|
398
|
+
--argjson instinct_count "$cvs_instinct_count" \
|
|
399
|
+
--arg mem_status "$cvs_mem_status" \
|
|
400
|
+
--argjson age_hours "$cvs_age_hours" \
|
|
401
|
+
--argjson overall_health "$cvs_score" \
|
|
402
|
+
'{
|
|
403
|
+
build_velocity: {phases_per_day: $phases_per_day, trend: $bv_trend},
|
|
404
|
+
error_rate: {errors_per_day: $errors_per_day, status: $err_status},
|
|
405
|
+
signal_health: {active_count: $active_count, status: $sig_status},
|
|
406
|
+
memory_pressure: {instinct_count: $instinct_count, status: $mem_status},
|
|
407
|
+
colony_age_hours: $age_hours,
|
|
408
|
+
overall_health: $overall_health
|
|
409
|
+
}')"
|
|
410
|
+
}
|
package/.aether/utils/swarm.sh
CHANGED
|
@@ -32,7 +32,7 @@ _autofix_checkpoint() {
|
|
|
32
32
|
label="${1:-autofix-$(date +%s)}"
|
|
33
33
|
stash_name="aether-checkpoint: $label"
|
|
34
34
|
# Only stash Aether-managed directories, never touch user files
|
|
35
|
-
if git stash push -m "$stash_name" -- $target_dirs >/dev/null 2>&1; then # SUPPRESS:OK -- existence-test: stash operation may fail
|
|
35
|
+
if git stash push -m "$stash_name" -- $target_dirs ":(exclude).aether/data/" >/dev/null 2>&1; then # SUPPRESS:OK -- existence-test: stash operation may fail
|
|
36
36
|
json_ok "$(jq -n --arg ref "$stash_name" '{type: "stash", ref: $ref}')"
|
|
37
37
|
else
|
|
38
38
|
# Stash failed (possibly due to conflicts), record commit hash
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Worktree utility functions -- extracted from aether-utils.sh
|
|
3
|
+
# Provides: _worktree_create, _worktree_cleanup
|
|
4
|
+
#
|
|
5
|
+
# These functions are sourced by aether-utils.sh at startup.
|
|
6
|
+
# All shared infrastructure (json_ok, json_err, atomic_write, acquire_lock,
|
|
7
|
+
# release_lock, DATA_DIR, COLONY_DATA_DIR, SCRIPT_DIR, AETHER_ROOT, error
|
|
8
|
+
# constants) is available.
|
|
9
|
+
|
|
10
|
+
# Default worktree location relative to AETHER_ROOT
|
|
11
|
+
WORKTREE_BASE_DIR="${AETHER_ROOT}/.aether/worktrees"
|
|
12
|
+
|
|
13
|
+
# _worktree_create
|
|
14
|
+
# Creates a git worktree for an agent working on a specific task.
|
|
15
|
+
#
|
|
16
|
+
# Usage: _worktree_create --branch <branch-name> [--base <base-branch>] [--task-id <task-id>]
|
|
17
|
+
# Returns JSON: {ok:true, result:{path, branch, base, worktree_dir, task_id}}
|
|
18
|
+
_worktree_create() {
|
|
19
|
+
local branch=""
|
|
20
|
+
local base=""
|
|
21
|
+
local task_id=""
|
|
22
|
+
|
|
23
|
+
# Parse arguments
|
|
24
|
+
while [[ $# -gt 0 ]]; do
|
|
25
|
+
case "$1" in
|
|
26
|
+
--branch) branch="${2:-}"; shift 2 ;;
|
|
27
|
+
--base) base="${2:-}"; shift 2 ;;
|
|
28
|
+
--task-id) task_id="${2:-}"; shift 2 ;;
|
|
29
|
+
*) shift ;;
|
|
30
|
+
esac
|
|
31
|
+
done
|
|
32
|
+
|
|
33
|
+
# Validate required arguments
|
|
34
|
+
if [[ -z "$branch" ]]; then
|
|
35
|
+
json_err "$E_VALIDATION_FAILED" "Usage: worktree-create --branch <branch-name> [--base <base-branch>] [--task-id <task-id>]"
|
|
36
|
+
fi
|
|
37
|
+
|
|
38
|
+
# Sanitize branch name: reject obviously dangerous patterns
|
|
39
|
+
if [[ "$branch" == *..* ]] || [[ "$branch" == */* ]] || [[ "$branch" == *\\* ]]; then
|
|
40
|
+
json_err "$E_VALIDATION_FAILED" "Branch name must not contain '..', '/', or backslashes"
|
|
41
|
+
fi
|
|
42
|
+
|
|
43
|
+
# Default base to current branch
|
|
44
|
+
if [[ -z "$base" ]]; then
|
|
45
|
+
base=$(git -C "$AETHER_ROOT" rev-parse --abbrev-ref HEAD 2>/dev/null || echo "main")
|
|
46
|
+
fi
|
|
47
|
+
|
|
48
|
+
local worktree_dir="$WORKTREE_BASE_DIR/$branch"
|
|
49
|
+
|
|
50
|
+
# Check if worktree already exists
|
|
51
|
+
if [[ -d "$worktree_dir" ]]; then
|
|
52
|
+
json_err "$E_VALIDATION_FAILED" "Worktree already exists for branch '$branch' at $worktree_dir"
|
|
53
|
+
fi
|
|
54
|
+
|
|
55
|
+
# Check if branch already exists as a git branch (would indicate duplicate)
|
|
56
|
+
if git -C "$AETHER_ROOT" show-ref --verify --quiet "refs/heads/$branch" 2>/dev/null; then
|
|
57
|
+
json_err "$E_VALIDATION_FAILED" "Branch '$branch' already exists"
|
|
58
|
+
fi
|
|
59
|
+
|
|
60
|
+
# Ensure base branch exists
|
|
61
|
+
if ! git -C "$AETHER_ROOT" show-ref --verify --quiet "refs/heads/$base" 2>/dev/null; then
|
|
62
|
+
json_err "$E_GIT_ERROR" "Base branch '$base' does not exist"
|
|
63
|
+
fi
|
|
64
|
+
|
|
65
|
+
# Ensure parent directory exists
|
|
66
|
+
mkdir -p "$WORKTREE_BASE_DIR"
|
|
67
|
+
|
|
68
|
+
# Create the worktree (git worktree add creates the branch automatically)
|
|
69
|
+
if ! git -C "$AETHER_ROOT" worktree add "$worktree_dir" -b "$branch" "$base" >/dev/null 2>&1; then
|
|
70
|
+
json_err "$E_GIT_ERROR" "Failed to create worktree for branch '$branch'"
|
|
71
|
+
fi
|
|
72
|
+
|
|
73
|
+
# Copy .aether/data/ structure to the new worktree so the agent has colony context
|
|
74
|
+
# Per state-contract-design.md, branch-local state lives in .aether/data/ (gitignored)
|
|
75
|
+
# and each worktree gets its own independent copy for colony context isolation.
|
|
76
|
+
if [[ -d "$AETHER_ROOT/.aether/data" ]]; then
|
|
77
|
+
mkdir -p "$worktree_dir/.aether/data"
|
|
78
|
+
cp -r "$AETHER_ROOT/.aether/data/." "$worktree_dir/.aether/data/" 2>/dev/null || true # SUPPRESS:OK -- copy: data dir may be empty
|
|
79
|
+
fi
|
|
80
|
+
|
|
81
|
+
# Copy exchange scripts so xml-utils.sh can source pheromone-xml.sh etc.
|
|
82
|
+
if [[ -d "$AETHER_ROOT/.aether/exchange" ]]; then
|
|
83
|
+
mkdir -p "$worktree_dir/.aether/exchange"
|
|
84
|
+
cp -r "$AETHER_ROOT/.aether/exchange/." "$worktree_dir/.aether/exchange/" 2>/dev/null || true
|
|
85
|
+
fi
|
|
86
|
+
|
|
87
|
+
# Inject main's pheromone signals into the worktree (per D-01)
|
|
88
|
+
# Non-blocking: if injection fails, worktree still works without injected signals
|
|
89
|
+
if [[ -f "$worktree_dir/.aether/data/pheromones.json" ]]; then
|
|
90
|
+
local main_head
|
|
91
|
+
main_head=$(git -C "$AETHER_ROOT" rev-parse HEAD 2>/dev/null || echo "unknown")
|
|
92
|
+
(
|
|
93
|
+
cd "$worktree_dir" 2>/dev/null && \
|
|
94
|
+
DATA_DIR="$worktree_dir/.aether/data" \
|
|
95
|
+
COLONY_DATA_DIR="$worktree_dir/.aether/data" \
|
|
96
|
+
bash "$AETHER_ROOT/.aether/aether-utils.sh" \
|
|
97
|
+
pheromone-snapshot-inject --from-branch "$base" --from-commit "$main_head" \
|
|
98
|
+
>/dev/null 2>&1 || true
|
|
99
|
+
)
|
|
100
|
+
fi
|
|
101
|
+
|
|
102
|
+
# Build result JSON
|
|
103
|
+
local result
|
|
104
|
+
result=$(jq -n \
|
|
105
|
+
--arg path "$worktree_dir" \
|
|
106
|
+
--arg branch "$branch" \
|
|
107
|
+
--arg base "$base" \
|
|
108
|
+
--arg worktree_dir "$worktree_dir" \
|
|
109
|
+
--arg task_id "${task_id:-null}" \
|
|
110
|
+
'{
|
|
111
|
+
path: $path,
|
|
112
|
+
branch: $branch,
|
|
113
|
+
base: $base,
|
|
114
|
+
worktree_dir: $worktree_dir,
|
|
115
|
+
task_id: (if $task_id == "null" then null else $task_id end)
|
|
116
|
+
}')
|
|
117
|
+
|
|
118
|
+
json_ok "$result"
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
# _worktree_cleanup
|
|
122
|
+
# Removes a git worktree and cleans up tracking.
|
|
123
|
+
#
|
|
124
|
+
# Usage: _worktree_cleanup --branch <branch-name> [--force]
|
|
125
|
+
# Returns JSON: {ok:true, result:{removed, branch, path}}
|
|
126
|
+
_worktree_cleanup() {
|
|
127
|
+
local branch=""
|
|
128
|
+
local force=false
|
|
129
|
+
|
|
130
|
+
# Parse arguments
|
|
131
|
+
while [[ $# -gt 0 ]]; do
|
|
132
|
+
case "$1" in
|
|
133
|
+
--branch) branch="${2:-}"; shift 2 ;;
|
|
134
|
+
--force) force=true; shift ;;
|
|
135
|
+
*) shift ;;
|
|
136
|
+
esac
|
|
137
|
+
done
|
|
138
|
+
|
|
139
|
+
# Validate required arguments
|
|
140
|
+
if [[ -z "$branch" ]]; then
|
|
141
|
+
json_err "$E_VALIDATION_FAILED" "Usage: worktree-cleanup --branch <branch-name> [--force]"
|
|
142
|
+
fi
|
|
143
|
+
|
|
144
|
+
# Sanitize branch name
|
|
145
|
+
if [[ "$branch" == *..* ]] || [[ "$branch" == */* ]] || [[ "$branch" == *\\* ]]; then
|
|
146
|
+
json_err "$E_VALIDATION_FAILED" "Branch name must not contain '..', '/', or backslashes"
|
|
147
|
+
fi
|
|
148
|
+
|
|
149
|
+
local worktree_dir="$WORKTREE_BASE_DIR/$branch"
|
|
150
|
+
|
|
151
|
+
# Check if worktree exists
|
|
152
|
+
if [[ ! -d "$worktree_dir" ]]; then
|
|
153
|
+
json_err "$E_RESOURCE_NOT_FOUND" "No worktree found for branch '$branch'"
|
|
154
|
+
fi
|
|
155
|
+
|
|
156
|
+
# Check for uncommitted changes (unless --force)
|
|
157
|
+
# Exclude .aether/ files since they are branch-local state copies, not user changes
|
|
158
|
+
if [[ "$force" == "false" ]]; then
|
|
159
|
+
local dirty_count
|
|
160
|
+
dirty_count=$(git -C "$worktree_dir" status --porcelain 2>/dev/null \
|
|
161
|
+
| grep -v '\.aether/' \
|
|
162
|
+
| wc -l \
|
|
163
|
+
| tr -d ' ') || dirty_count=0
|
|
164
|
+
|
|
165
|
+
if [[ "$dirty_count" -gt 0 ]]; then
|
|
166
|
+
json_err "$E_VALIDATION_FAILED" "Worktree '$branch' has $dirty_count uncommitted changes. Use --force to remove anyway."
|
|
167
|
+
fi
|
|
168
|
+
fi
|
|
169
|
+
|
|
170
|
+
# Remove the worktree using git worktree remove
|
|
171
|
+
if ! git -C "$AETHER_ROOT" worktree remove "$worktree_dir" --force 2>/dev/null; then
|
|
172
|
+
# Fallback: manual cleanup if git worktree remove fails
|
|
173
|
+
rm -rf "$worktree_dir" 2>/dev/null || true
|
|
174
|
+
# Also prune stale worktree entries
|
|
175
|
+
git -C "$AETHER_ROOT" worktree prune 2>/dev/null || true
|
|
176
|
+
fi
|
|
177
|
+
|
|
178
|
+
# Attempt to delete the branch (best-effort -- may fail if branch is checked out elsewhere)
|
|
179
|
+
git -C "$AETHER_ROOT" branch -D "$branch" >/dev/null 2>&1 || true
|
|
180
|
+
|
|
181
|
+
# Build result JSON
|
|
182
|
+
local result
|
|
183
|
+
result=$(jq -n \
|
|
184
|
+
--arg branch "$branch" \
|
|
185
|
+
--arg path "$worktree_dir" \
|
|
186
|
+
'{removed: true, branch: $branch, path: $path}')
|
|
187
|
+
|
|
188
|
+
json_ok "$result"
|
|
189
|
+
}
|
|
@@ -69,6 +69,8 @@ Read `.aether/data/COLONY_STATE.json`.
|
|
|
69
69
|
|
|
70
70
|
**If the file exists:** continue.
|
|
71
71
|
|
|
72
|
+
**If `milestone` == `"Crowned Anthill"`:** output "This colony has been sealed. Start a new colony with `/ant:init \"new goal\"`.", stop.
|
|
73
|
+
|
|
72
74
|
**If `plan.phases` is not empty:** output "Colony already has phases. Use /ant:continue.", stop.
|
|
73
75
|
|
|
74
76
|
### Step 2: Quick Surface Scan (for session context)
|
|
@@ -9,9 +9,208 @@ You are the **Queen Ant Colony**. Convene the council to clarify user intent and
|
|
|
9
9
|
## Instructions
|
|
10
10
|
|
|
11
11
|
Parse `$ARGUMENTS`:
|
|
12
|
+
- If starts with `--deliberate`: set `deliberate_mode = true`, extract proposal text after `--deliberate`
|
|
12
13
|
- If contains `--no-visual`: set `visual_mode = false` (visual is ON by default)
|
|
13
14
|
- Otherwise: set `visual_mode = true`
|
|
14
15
|
|
|
16
|
+
**If `deliberate_mode` is true:** Skip to [Deliberation Mode](#deliberation-mode) and stop after it.
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## Deliberation Mode
|
|
21
|
+
|
|
22
|
+
When `--deliberate "<proposal>"` is passed, run a structured Advocate/Challenger/Sage deliberation.
|
|
23
|
+
|
|
24
|
+
### Step D1: Check Budget
|
|
25
|
+
|
|
26
|
+
Run using the Bash tool with description "Checking deliberation budget...":
|
|
27
|
+
```bash
|
|
28
|
+
bash .aether/aether-utils.sh council-budget-check
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Parse result. If `allowed` is `false`:
|
|
32
|
+
```
|
|
33
|
+
📜🐜🏛️🐜📜 COUNCIL — BUDGET EXHAUSTED
|
|
34
|
+
|
|
35
|
+
Spawn budget is fully allocated. Complete or close existing deliberations before starting new ones.
|
|
36
|
+
Run /ant:council to review existing deliberations.
|
|
37
|
+
```
|
|
38
|
+
Stop here.
|
|
39
|
+
|
|
40
|
+
### Step D2: Open Deliberation
|
|
41
|
+
|
|
42
|
+
Run using the Bash tool with description "Opening deliberation...":
|
|
43
|
+
```bash
|
|
44
|
+
bash .aether/aether-utils.sh council-deliberate --proposal "<proposal>"
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Capture `deliberation_id` from `result.id`.
|
|
48
|
+
|
|
49
|
+
Display:
|
|
50
|
+
```
|
|
51
|
+
📜🐜🏛️🐜📜 COUNCIL DELIBERATION OPENED
|
|
52
|
+
|
|
53
|
+
Proposal: "<proposal>"
|
|
54
|
+
ID: {deliberation_id}
|
|
55
|
+
Budget: {budget} spawns available
|
|
56
|
+
|
|
57
|
+
Convening Advocate, Challenger, and Sage...
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Step D3: Spawn Advocate Scout
|
|
61
|
+
|
|
62
|
+
Spawn an Advocate scout to argue **in favor** of the proposal.
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
Use the Task tool to spawn a scout with the following system prompt:
|
|
66
|
+
```
|
|
67
|
+
You are the Advocate on the Ant Colony council.
|
|
68
|
+
Your role is to argue STRONGLY IN FAVOR of the proposal.
|
|
69
|
+
Present the strongest possible case for why this proposal should be adopted.
|
|
70
|
+
Be specific. Focus on concrete benefits and outcomes.
|
|
71
|
+
Keep your argument under 200 words.
|
|
72
|
+
Reply with ONLY your argument text — no preamble or meta-commentary.
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
And user message:
|
|
76
|
+
```
|
|
77
|
+
Proposal: "<proposal>"
|
|
78
|
+
|
|
79
|
+
Present your strongest argument in favor of this proposal.
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Capture the advocate's argument as `advocate_argument`.
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
Record the argument:
|
|
86
|
+
```bash
|
|
87
|
+
bash .aether/aether-utils.sh council-advocate \
|
|
88
|
+
--deliberation-id "<deliberation_id>" \
|
|
89
|
+
--argument "<advocate_argument>"
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Display:
|
|
93
|
+
```
|
|
94
|
+
⚖️ ADVOCATE:
|
|
95
|
+
{advocate_argument}
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### Step D4: Spawn Challenger Scout
|
|
99
|
+
|
|
100
|
+
Spawn a Challenger scout to argue **against** the proposal.
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
Use the Task tool to spawn a scout with the following system prompt:
|
|
104
|
+
```
|
|
105
|
+
You are the Challenger on the Ant Colony council.
|
|
106
|
+
Your role is to argue STRONGLY AGAINST the proposal.
|
|
107
|
+
Present the strongest possible case for why this proposal should be rejected or deferred.
|
|
108
|
+
Be specific. Focus on concrete risks, costs, and downsides.
|
|
109
|
+
Keep your argument under 200 words.
|
|
110
|
+
Reply with ONLY your argument text — no preamble or meta-commentary.
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
And user message:
|
|
114
|
+
```
|
|
115
|
+
Proposal: "<proposal>"
|
|
116
|
+
|
|
117
|
+
Present your strongest argument against this proposal.
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Capture the challenger's argument as `challenger_argument`.
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
Record the argument:
|
|
124
|
+
```bash
|
|
125
|
+
bash .aether/aether-utils.sh council-challenger \
|
|
126
|
+
--deliberation-id "<deliberation_id>" \
|
|
127
|
+
--argument "<challenger_argument>"
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
Display:
|
|
131
|
+
```
|
|
132
|
+
⚔️ CHALLENGER:
|
|
133
|
+
{challenger_argument}
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### Step D5: Spawn Sage Scout
|
|
137
|
+
|
|
138
|
+
Spawn a Sage scout to synthesize both positions and provide a recommendation.
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
Use the Task tool to spawn a scout with the following system prompt:
|
|
142
|
+
```
|
|
143
|
+
You are the Sage on the Ant Colony council.
|
|
144
|
+
You have heard both the Advocate and Challenger arguments.
|
|
145
|
+
Your role is to synthesize both positions into balanced wisdom and provide a clear recommendation.
|
|
146
|
+
Your recommendation must be one of: adopt, reject, defer, or adopt-with-conditions.
|
|
147
|
+
Keep your synthesis under 150 words.
|
|
148
|
+
Reply with JSON only:
|
|
149
|
+
{"synthesis": "<your balanced synthesis>", "recommendation": "adopt|reject|defer|adopt-with-conditions"}
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
And user message:
|
|
153
|
+
```
|
|
154
|
+
Proposal: "<proposal>"
|
|
155
|
+
|
|
156
|
+
Advocate argued: "<advocate_argument>"
|
|
157
|
+
|
|
158
|
+
Challenger argued: "<challenger_argument>"
|
|
159
|
+
|
|
160
|
+
Synthesize both positions and provide your recommendation.
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
Parse the JSON response. Capture `synthesis` and `recommendation`.
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
Record the sage synthesis:
|
|
167
|
+
```bash
|
|
168
|
+
bash .aether/aether-utils.sh council-sage \
|
|
169
|
+
--deliberation-id "<deliberation_id>" \
|
|
170
|
+
--synthesis "<synthesis>" \
|
|
171
|
+
--recommendation "<recommendation>"
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
### Step D6: Display Result
|
|
175
|
+
|
|
176
|
+
```
|
|
177
|
+
📜🐜🏛️🐜📜 COUNCIL DELIBERATION COMPLETE
|
|
178
|
+
|
|
179
|
+
Proposal: "<proposal>"
|
|
180
|
+
|
|
181
|
+
⚖️ Advocate:
|
|
182
|
+
{advocate_argument}
|
|
183
|
+
|
|
184
|
+
⚔️ Challenger:
|
|
185
|
+
{challenger_argument}
|
|
186
|
+
|
|
187
|
+
🧙 Sage Synthesis:
|
|
188
|
+
{synthesis}
|
|
189
|
+
|
|
190
|
+
Recommendation: {recommendation}
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
If recommendation is `adopt` or `adopt-with-conditions`:
|
|
194
|
+
```
|
|
195
|
+
✅ Council recommends proceeding.
|
|
196
|
+
Run /ant:focus "<proposal summary>" to inject guidance for the colony.
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
If recommendation is `reject`:
|
|
200
|
+
```
|
|
201
|
+
❌ Council recommends against this proposal.
|
|
202
|
+
Run /ant:redirect "<proposal summary>" if you want to make this a hard constraint.
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
If recommendation is `defer`:
|
|
206
|
+
```
|
|
207
|
+
⏸️ Council recommends deferring this decision.
|
|
208
|
+
Return when more context is available.
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
---
|
|
212
|
+
|
|
213
|
+
|
|
15
214
|
|
|
16
215
|
### Step 0: Initialize Visual Mode (if enabled)
|
|
17
216
|
|
|
@@ -29,6 +228,12 @@ No colony initialized. Run /ant:init first.
|
|
|
29
228
|
```
|
|
30
229
|
Stop here.
|
|
31
230
|
|
|
231
|
+
If `milestone` == `"Crowned Anthill"`:
|
|
232
|
+
```
|
|
233
|
+
This colony has been sealed. Start a new colony with /ant:init "new goal".
|
|
234
|
+
```
|
|
235
|
+
Stop here.
|
|
236
|
+
|
|
32
237
|
Capture the current state for context:
|
|
33
238
|
- `prior_state` = state field value (READY, EXECUTING, PLANNING, etc.)
|
|
34
239
|
- `current_phase` = current_phase field value
|