aether-colony 5.1.0 → 5.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/.aether/aether-utils.sh +122 -42
  2. package/.aether/commands/colonize.yaml +4 -0
  3. package/.aether/commands/council.yaml +205 -0
  4. package/.aether/commands/init.yaml +46 -13
  5. package/.aether/commands/insert-phase.yaml +4 -0
  6. package/.aether/commands/plan.yaml +53 -2
  7. package/.aether/commands/quick.yaml +104 -0
  8. package/.aether/commands/resume-colony.yaml +6 -4
  9. package/.aether/commands/resume.yaml +9 -0
  10. package/.aether/commands/run.yaml +37 -1
  11. package/.aether/commands/seal.yaml +9 -0
  12. package/.aether/commands/status.yaml +45 -1
  13. package/.aether/docs/command-playbooks/build-full.md +2 -1
  14. package/.aether/docs/command-playbooks/build-prep.md +2 -1
  15. package/.aether/docs/command-playbooks/continue-full.md +1 -0
  16. package/.aether/docs/command-playbooks/continue-verify.md +1 -0
  17. package/.aether/utils/council.sh +425 -0
  18. package/.aether/utils/error-handler.sh +3 -3
  19. package/.aether/utils/flag.sh +23 -12
  20. package/.aether/utils/hive.sh +2 -2
  21. package/.aether/utils/immune.sh +508 -0
  22. package/.aether/utils/learning.sh +2 -2
  23. package/.aether/utils/midden.sh +178 -0
  24. package/.aether/utils/queen.sh +29 -17
  25. package/.aether/utils/session.sh +264 -0
  26. package/.aether/utils/spawn-tree.sh +7 -7
  27. package/.aether/utils/spawn.sh +2 -2
  28. package/.aether/utils/state-api.sh +191 -1
  29. package/.claude/commands/ant/colonize.md +2 -0
  30. package/.claude/commands/ant/council.md +205 -0
  31. package/.claude/commands/ant/init.md +46 -13
  32. package/.claude/commands/ant/insert-phase.md +4 -0
  33. package/.claude/commands/ant/plan.md +27 -1
  34. package/.claude/commands/ant/quick.md +100 -0
  35. package/.claude/commands/ant/resume-colony.md +3 -2
  36. package/.claude/commands/ant/resume.md +9 -0
  37. package/.claude/commands/ant/run.md +37 -1
  38. package/.claude/commands/ant/seal.md +9 -0
  39. package/.claude/commands/ant/status.md +45 -1
  40. package/.opencode/commands/ant/colonize.md +2 -0
  41. package/.opencode/commands/ant/council.md +143 -0
  42. package/.opencode/commands/ant/init.md +46 -13
  43. package/.opencode/commands/ant/insert-phase.md +4 -0
  44. package/.opencode/commands/ant/plan.md +26 -1
  45. package/.opencode/commands/ant/quick.md +91 -0
  46. package/.opencode/commands/ant/resume-colony.md +3 -2
  47. package/.opencode/commands/ant/resume.md +9 -0
  48. package/.opencode/commands/ant/run.md +37 -1
  49. package/.opencode/commands/ant/status.md +2 -0
  50. package/CHANGELOG.md +90 -0
  51. package/README.md +23 -0
  52. package/package.json +10 -2
@@ -44,6 +44,8 @@ CURRENT_LOCK=${CURRENT_LOCK:-""}
44
44
  [[ -f "$SCRIPT_DIR/utils/pheromone.sh" ]] && source "$SCRIPT_DIR/utils/pheromone.sh"
45
45
  [[ -f "$SCRIPT_DIR/utils/scan.sh" ]] && source "$SCRIPT_DIR/utils/scan.sh"
46
46
  [[ -f "$SCRIPT_DIR/utils/emoji-audit.sh" ]] && source "$SCRIPT_DIR/utils/emoji-audit.sh"
47
+ [[ -f "$SCRIPT_DIR/utils/immune.sh" ]] && source "$SCRIPT_DIR/utils/immune.sh"
48
+ [[ -f "$SCRIPT_DIR/utils/council.sh" ]] && source "$SCRIPT_DIR/utils/council.sh"
47
49
 
48
50
  # Fallback error constants if error-handler.sh wasn't sourced
49
51
  # This prevents "unbound variable" errors in older installations
@@ -106,7 +108,7 @@ if ! type json_err &>/dev/null; then
106
108
  local code="${1:-E_UNKNOWN}"
107
109
  local message="${2:-An unknown error occurred}"
108
110
  printf '[aether] Warning: error-handler.sh not loaded — using minimal fallback\n' >&2
109
- printf '{"ok":false,"error":{"code":"%s","message":"%s"}}\n' "$code" "$message" >&2
111
+ printf '%s\n' "$(jq -nc --arg c "$code" --arg m "$message" '{ok:false,error:{code:$c,message:$m}}')" >&2
110
112
  exit 1
111
113
  }
112
114
  fi
@@ -570,7 +572,7 @@ Git Commits: 0
570
572
 
571
573
  **Colony Memory Active** 🧠🐜
572
574
  EOF
573
- json_ok "{\"updated\":true,\"action\":\"init\",\"file\":\"$ctx_file\"}"
575
+ json_ok "$(jq -nc --arg file "$ctx_file" '{updated:true,action:"init",file:$file}')"
574
576
  ;;
575
577
 
576
578
  update-phase)
@@ -586,7 +588,7 @@ EOF
586
588
  sed -i.bak "s/| \*\*Phase Name\*\* | .*/| **Phase Name** | $new_phase_name |/" "$ctx_file" && rm -f "$ctx_file.bak"
587
589
  sed -i.bak "s/| \*\*Safe to Clear?\*\* | .*/| **Safe to Clear?** | $safe_clear — $safe_reason |/" "$ctx_file" && rm -f "$ctx_file.bak"
588
590
 
589
- json_ok "{\"updated\":true,\"action\":\"update-phase\",\"phase\":$new_phase}"
591
+ json_ok "$(jq -nc --argjson phase "$new_phase" '{updated:true,action:"update-phase",phase:$phase}')"
590
592
  ;;
591
593
 
592
594
  activity)
@@ -613,7 +615,7 @@ EOF
613
615
  ' "$ctx_file" > "$ctx_tmp"
614
616
 
615
617
  mv "$ctx_tmp" "$ctx_file"
616
- json_ok "{\"updated\":true,\"action\":\"activity\",\"command\":\"$cmd\"}"
618
+ json_ok "$(jq -nc --arg cmd "$cmd" '{updated:true,action:"activity",command:$cmd}')"
617
619
  ;;
618
620
 
619
621
  safe-to-clear)
@@ -625,7 +627,7 @@ EOF
625
627
  sed -i.bak "s/| \*\*Last Updated\*\* | .*/| **Last Updated** | $ctx_ts |/" "$ctx_file" && rm -f "$ctx_file.bak"
626
628
  sed -i.bak "s/| \*\*Safe to Clear?\*\* | .*/| **Safe to Clear?** | $safe — $reason |/" "$ctx_file" && rm -f "$ctx_file.bak"
627
629
 
628
- json_ok "{\"updated\":true,\"action\":\"safe-to-clear\",\"safe\":\"$safe\"}"
630
+ json_ok "$(jq -nc --arg safe "$safe" '{updated:true,action:"safe-to-clear",safe:$safe}')"
629
631
  ;;
630
632
 
631
633
  constraint)
@@ -651,7 +653,7 @@ EOF
651
653
  }" "$ctx_file" && rm -f "$ctx_file.bak"
652
654
  fi
653
655
 
654
- json_ok "{\"updated\":true,\"action\":\"constraint\",\"type\":\"$c_type\"}"
656
+ json_ok "$(jq -nc --arg type "$c_type" '{updated:true,action:"constraint",type:$type}')"
655
657
  ;;
656
658
 
657
659
  decision)
@@ -692,7 +694,7 @@ EOF
692
694
  --ttl "30d" 2>/dev/null \
693
695
  || _aether_log_error "Could not emit feedback signal for decision" # SUPPRESS:OK -- read-default: returns fallback on failure
694
696
 
695
- json_ok "{\"updated\":true,\"action\":\"decision\"}"
697
+ json_ok "$(jq -nc '{updated:true,action:"decision"}')"
696
698
  ;;
697
699
 
698
700
  build-start)
@@ -706,7 +708,7 @@ EOF
706
708
  sed -i.bak "s/## 📍 What's In Progress/## 📍 What's In Progress\n\n**Phase $phase_id Build IN PROGRESS**\n- Workers: $worker_count | Tasks: $tasks_count\n- Started: $ctx_ts/" "$ctx_file" && rm -f "$ctx_file.bak"
707
709
  sed -i.bak "s/| \*\*Safe to Clear?\*\* | .*/| **Safe to Clear?** | ⚠️ NO — Build in progress |/" "$ctx_file" && rm -f "$ctx_file.bak"
708
710
 
709
- json_ok "{\"updated\":true,\"action\":\"build-start\",\"workers\":$worker_count}"
711
+ json_ok "$(jq -nc --argjson workers "$worker_count" '{updated:true,action:"build-start",workers:$workers}')"
710
712
  ;;
711
713
 
712
714
  worker-spawn)
@@ -727,7 +729,7 @@ EOF
727
729
  { print }
728
730
  ' "$ctx_file" > "$ctx_tmp" && mv "$ctx_tmp" "$ctx_file"
729
731
 
730
- json_ok "{\"updated\":true,\"action\":\"worker-spawn\",\"ant\":\"$ant_name\"}"
732
+ json_ok "$(jq -nc --arg ant "$ant_name" '{updated:true,action:"worker-spawn",ant:$ant}')"
731
733
  ;;
732
734
 
733
735
  worker-complete)
@@ -738,7 +740,7 @@ EOF
738
740
 
739
741
  sed -i.bak "s/- .*$ant_name .*$/- $ant_name: $status (updated $ctx_ts)/" "$ctx_file" && rm -f "$ctx_file.bak"
740
742
 
741
- json_ok "{\"updated\":true,\"action\":\"worker-complete\",\"ant\":\"$ant_name\"}"
743
+ json_ok "$(jq -nc --arg ant "$ant_name" '{updated:true,action:"worker-complete",ant:$ant}')"
742
744
  ;;
743
745
 
744
746
  build-progress)
@@ -750,7 +752,7 @@ EOF
750
752
 
751
753
  sed -i.bak "s/Build IN PROGRESS/Build IN PROGRESS ($percentage% complete)/" "$ctx_file" && rm -f "$ctx_file.bak"
752
754
 
753
- json_ok "{\"updated\":true,\"action\":\"build-progress\",\"percent\":$percentage}"
755
+ json_ok "$(jq -nc --argjson percent "$percentage" '{updated:true,action:"build-progress",percent:$percent}')"
754
756
  ;;
755
757
 
756
758
  build-complete)
@@ -776,7 +778,7 @@ EOF
776
778
 
777
779
  sed -i.bak "s/| \*\*Safe to Clear?\*\* | .*/| **Safe to Clear?** | ✅ YES — Build $status |/" "$ctx_file" && rm -f "$ctx_file.bak"
778
780
 
779
- json_ok "{\"updated\":true,\"action\":\"build-complete\",\"status\":\"$status\"}"
781
+ json_ok "$(jq -nc --arg status "$status" '{updated:true,action:"build-complete",status:$status}')"
780
782
  ;;
781
783
 
782
784
  *)
@@ -953,7 +955,7 @@ EOF
953
955
  # Atomically replace the file
954
956
  mv "$temp_file" "$changelog_file"
955
957
 
956
- json_ok '{"appended":true,"date":"'"$date_str"'","phase":"'"$phase"'","plan":"'"$plan"'"}'
958
+ json_ok "$(jq -nc --arg date "$date_str" --arg phase "$phase" --arg plan "$plan" '{appended:true,date:$date,phase:$phase,plan:$plan}')"
957
959
  }
958
960
 
959
961
  # Collect plan data for changelog entry
@@ -1174,7 +1176,7 @@ case "$cmd" in
1174
1176
  cat <<'HELP_EOF'
1175
1177
  {
1176
1178
  "ok": true,
1177
- "commands": ["help","version","validate-state","validate-oracle-state","load-state","unload-state","error-add","error-pattern-check","error-summary","activity-log","activity-log-init","activity-log-read","learning-promote","learning-inject","learning-observe","learning-check-promotion","learning-promote-auto","memory-capture","queen-thresholds","context-capsule","rolling-summary","generate-ant-name","spawn-log","spawn-complete","spawn-can-spawn","spawn-get-depth","spawn-tree-load","spawn-tree-active","spawn-tree-depth","spawn-efficiency","validate-worker-response","update-progress","check-antipattern","error-flag-pattern","signature-scan","signature-match","flag-add","flag-check-blockers","flag-resolve","flag-acknowledge","flag-list","flag-auto-resolve","autofix-checkpoint","autofix-rollback","spawn-can-spawn-swarm","swarm-findings-init","swarm-findings-add","swarm-findings-read","swarm-solution-set","swarm-cleanup","swarm-activity-log","swarm-display-init","swarm-display-update","swarm-display-get","swarm-display-text","swarm-timing-start","swarm-timing-get","swarm-timing-eta","view-state-init","view-state-get","view-state-set","view-state-toggle","view-state-expand","view-state-collapse","grave-add","grave-check","phase-insert","generate-commit-message","version-check","registry-add","registry-list","bootstrap-system","chamber-create","chamber-verify","chamber-list","milestone-detect","queen-init","queen-read","queen-promote","incident-rule-add","survey-load","survey-verify","pheromone-export","pheromone-write","pheromone-count","pheromone-read","instinct-read","instinct-create","instinct-apply","pheromone-prime","colony-prime","pheromone-expire","eternal-init","eternal-store","pheromone-export-xml","pheromone-import-xml","pheromone-validate-xml","wisdom-export-xml","wisdom-import-xml","registry-export-xml","registry-import-xml","memory-metrics","midden-recent-failures","midden-review","midden-acknowledge","entropy-score","force-unlock","changelog-append","changelog-collect-plan-data","suggest-approve","suggest-quick-dismiss","data-clean","autopilot-init","autopilot-update","autopilot-status","autopilot-stop","autopilot-check-replan","hive-init","hive-store","hive-read","hive-abstract","hive-promote","init-research","charter-write","colony-name","emoji-audit"],
1179
+ "commands": ["help","version","validate-state","validate-oracle-state","load-state","unload-state","error-add","error-pattern-check","error-summary","activity-log","activity-log-init","activity-log-read","learning-promote","learning-inject","learning-observe","learning-check-promotion","learning-promote-auto","memory-capture","queen-thresholds","context-capsule","rolling-summary","generate-ant-name","spawn-log","spawn-complete","spawn-can-spawn","spawn-get-depth","spawn-tree-load","spawn-tree-active","spawn-tree-depth","spawn-efficiency","validate-worker-response","update-progress","check-antipattern","error-flag-pattern","signature-scan","signature-match","flag-add","flag-check-blockers","flag-resolve","flag-acknowledge","flag-list","flag-auto-resolve","autofix-checkpoint","autofix-rollback","spawn-can-spawn-swarm","swarm-findings-init","swarm-findings-add","swarm-findings-read","swarm-solution-set","swarm-cleanup","swarm-activity-log","swarm-display-init","swarm-display-update","swarm-display-get","swarm-display-text","swarm-timing-start","swarm-timing-get","swarm-timing-eta","view-state-init","view-state-get","view-state-set","view-state-toggle","view-state-expand","view-state-collapse","grave-add","grave-check","phase-insert","generate-commit-message","version-check","registry-add","registry-list","bootstrap-system","chamber-create","chamber-verify","chamber-list","milestone-detect","queen-init","queen-read","queen-promote","incident-rule-add","survey-load","survey-verify","pheromone-export","pheromone-write","pheromone-count","pheromone-read","instinct-read","instinct-create","instinct-apply","pheromone-prime","colony-prime","pheromone-expire","eternal-init","eternal-store","pheromone-export-xml","pheromone-import-xml","pheromone-validate-xml","wisdom-export-xml","wisdom-import-xml","registry-export-xml","registry-import-xml","memory-metrics","midden-recent-failures","midden-review","midden-acknowledge","midden-search","midden-tag","entropy-score","force-unlock","changelog-append","changelog-collect-plan-data","suggest-approve","suggest-quick-dismiss","data-clean","autopilot-init","autopilot-update","autopilot-status","autopilot-stop","autopilot-check-replan","autopilot-set-headless","autopilot-headless-check","pending-decision-add","pending-decision-list","pending-decision-resolve","hive-init","hive-store","hive-read","hive-abstract","hive-promote","init-research","charter-write","colony-name","colony-vital-signs","emoji-audit","trophallaxis-diagnose","trophallaxis-retry","scar-add","scar-list","scar-check","immune-auto-scar","council-deliberate","council-advocate","council-challenger","council-sage","council-history","council-budget-check"],
1178
1180
  "sections": {
1179
1181
  "Core": [
1180
1182
  {"name": "help", "description": "List all available commands with sections"},
@@ -1271,7 +1273,10 @@ case "$cmd" in
1271
1273
  {"name": "midden-recent-failures", "description": "Read recent failure signals from midden"},
1272
1274
  {"name": "midden-review", "description": "Review unacknowledged midden entries grouped by category"},
1273
1275
  {"name": "midden-acknowledge", "description": "Acknowledge midden entries by id or category"},
1276
+ {"name": "midden-search", "description": "Search midden entries by keyword with optional category/source filters"},
1277
+ {"name": "midden-tag", "description": "Add or remove a tag from a midden entry"},
1274
1278
  {"name": "entropy-score", "description": "Compute colony entropy score (0-100)"},
1279
+ {"name": "colony-vital-signs", "description": "Compute colony health metrics from existing data (velocity, errors, signals, memory, overall score)"},
1275
1280
  {"name": "force-unlock", "description": "Emergency unlock — remove stale lock files"}
1276
1281
  ],
1277
1282
  "Changelog": [
@@ -1290,7 +1295,12 @@ case "$cmd" in
1290
1295
  {"name": "autopilot-update", "description": "Update autopilot state after phase action"},
1291
1296
  {"name": "autopilot-status", "description": "Return current autopilot state"},
1292
1297
  {"name": "autopilot-stop", "description": "Stop or complete an autopilot run with reason"},
1293
- {"name": "autopilot-check-replan", "description": "Check if replan trigger should fire based on completed phases"}
1298
+ {"name": "autopilot-check-replan", "description": "Check if replan trigger should fire based on completed phases"},
1299
+ {"name": "autopilot-set-headless", "description": "Set headless mode flag in run-state.json (true or false)"},
1300
+ {"name": "autopilot-headless-check", "description": "Check if autopilot is running in headless mode"},
1301
+ {"name": "pending-decision-add", "description": "Queue a deferred decision for later review"},
1302
+ {"name": "pending-decision-list", "description": "List pending decisions, optionally filtered by type or status"},
1303
+ {"name": "pending-decision-resolve", "description": "Mark a pending decision as resolved with a resolution note"}
1294
1304
  ],
1295
1305
  "Hive Intelligence": [
1296
1306
  {"name": "hive-init", "description": "Initialize ~/.aether/hive/ directory and wisdom.json schema"},
@@ -1318,6 +1328,22 @@ case "$cmd" in
1318
1328
  "Emoji Audit": [
1319
1329
  {"name": "emoji-audit", "description": "Audit emoji usage in command files against the canonical colony-visuals reference map"}
1320
1330
  ],
1331
+ "Immune System": [
1332
+ {"name": "trophallaxis-diagnose", "description": "Diagnose a task failure by searching midden for related failures and suggesting an approach"},
1333
+ {"name": "trophallaxis-retry", "description": "Record a retry attempt for a task with diagnosis context injected"},
1334
+ {"name": "scar-add", "description": "Record a persistent failure pattern as a scar to warn future workers"},
1335
+ {"name": "scar-list", "description": "List scars, optionally filtered by active status or severity"},
1336
+ {"name": "scar-check", "description": "Check if a task description matches any active scar patterns"},
1337
+ {"name": "immune-auto-scar", "description": "Auto-create a scar if a task has been retried 3 or more times"}
1338
+ ],
1339
+ "Council": [
1340
+ {"name": "council-deliberate", "description": "Start a new deliberation with Advocate/Challenger/Sage model and spawn budget guard"},
1341
+ {"name": "council-advocate", "description": "Record an advocate argument (FOR) for a deliberation"},
1342
+ {"name": "council-challenger", "description": "Record a challenger argument (AGAINST) for a deliberation"},
1343
+ {"name": "council-sage", "description": "Record sage synthesis and recommendation, marks deliberation complete"},
1344
+ {"name": "council-history", "description": "List past deliberations with their outcomes"},
1345
+ {"name": "council-budget-check", "description": "Check if current spawn budget allows N more spawns"}
1346
+ ],
1321
1347
  "Deprecated": [
1322
1348
  {"name": "checkpoint-check", "description": "Check dirty files against allowlist [DEPRECATED]"},
1323
1349
  {"name": "error-pattern-check", "description": "Check for error anti-patterns [DEPRECATED]"},
@@ -1348,7 +1374,7 @@ HELP_EOF
1348
1374
  _pkg_json="$SCRIPT_DIR/../package.json"
1349
1375
  if [[ -f "$_pkg_json" ]] && command -v jq >/dev/null 2>&1; then # SUPPRESS:OK -- cleanup: output suppression for clean operation
1350
1376
  _ver=$(jq -r '.version // "unknown"' "$_pkg_json" 2>/dev/null) # SUPPRESS:OK -- read-default: file may not exist yet
1351
- json_ok "\"$_ver\""
1377
+ json_ok "$(jq -nc --arg v "$_ver" '$v')"
1352
1378
  else
1353
1379
  json_ok '"1.1.5"'
1354
1380
  fi
@@ -1381,6 +1407,7 @@ HELP_EOF
1381
1407
  ;;
1382
1408
  constraints)
1383
1409
  [[ -f "$COLONY_DATA_DIR/constraints.json" ]] || json_err "$E_FILE_NOT_FOUND" "constraints.json not found" '{"file":"constraints.json"}'
1410
+ [[ -s "$COLONY_DATA_DIR/constraints.json" ]] || { json_ok '{"file":"constraints.json","checks":["pass","pass"],"pass":true}'; exit 0; }
1384
1411
  json_ok "$(jq '
1385
1412
  def arr(f): if has(f) and (.[f]|type) == "array" then "pass" else "fail: \(f) not array" end;
1386
1413
  {file:"constraints.json", checks:[
@@ -1428,7 +1455,7 @@ HELP_EOF
1428
1455
  json_err "$E_FEATURE_UNAVAILABLE" "create_backup function not available -- atomic-write.sh may not be sourced"
1429
1456
  fi
1430
1457
 
1431
- json_ok "{\"checkpointed\":true,\"reason\":\"$sc_reason\"}"
1458
+ json_ok "$(jq -nc --arg reason "$sc_reason" '{checkpointed:true,reason:$reason}')"
1432
1459
  ;;
1433
1460
  state-write)
1434
1461
  # MIGRATE: direct COLONY_STATE.json access -- use _state_write instead
@@ -1670,7 +1697,7 @@ HELP_EOF
1670
1697
  if (.errors.records|length) > 50 then .errors.records = .errors.records[-50:] else . end
1671
1698
  ' >/dev/null
1672
1699
 
1673
- json_ok "\"$ea_id\""
1700
+ json_ok "$(jq -nc --arg id "$ea_id" '$id')"
1674
1701
  ;;
1675
1702
  error-pattern-check)
1676
1703
  _deprecation_warning "error-pattern-check"
@@ -1707,6 +1734,12 @@ HELP_EOF
1707
1734
  exit 0
1708
1735
  fi
1709
1736
 
1737
+ # Skip writes during test runs to prevent test noise in activity.log
1738
+ if [[ "${AETHER_TESTING:-}" == "1" ]]; then
1739
+ json_ok '"logged"'
1740
+ exit 0
1741
+ fi
1742
+
1710
1743
  log_file="$COLONY_DATA_DIR/activity.log"
1711
1744
  mkdir -p "$COLONY_DATA_DIR"
1712
1745
  ts=$(date -u +"%H:%M:%S")
@@ -1857,7 +1890,7 @@ EOF
1857
1890
  json_err "$E_UNKNOWN" "Failed to write error patterns file"
1858
1891
  }
1859
1892
  count=$(echo "$updated" | jq --arg name "$pattern_name" '.patterns[] | select(.name == $name) | .occurrences')
1860
- json_ok "{\"updated\":true,\"pattern\":\"$pattern_name\",\"occurrences\":$count}"
1893
+ json_ok "$(jq -nc --arg p "$pattern_name" --argjson c "$count" '{updated:true,pattern:$p,occurrences:$c}')"
1861
1894
  else
1862
1895
  # Add new pattern
1863
1896
  updated=$(jq --arg name "$pattern_name" --arg desc "$description" --arg sev "$severity" --arg ts "$ts" --arg proj "$project_name" '
@@ -1876,7 +1909,7 @@ EOF
1876
1909
  _aether_log_error "Could not save new error pattern"
1877
1910
  json_err "$E_UNKNOWN" "Failed to write error patterns file"
1878
1911
  }
1879
- json_ok "{\"created\":true,\"pattern\":\"$pattern_name\"}"
1912
+ json_ok "$(jq -nc --arg p "$pattern_name" '{created:true,pattern:$p}')"
1880
1913
  fi
1881
1914
  ;;
1882
1915
  error-patterns-check)
@@ -2159,7 +2192,7 @@ EOF
2159
2192
  prefix="${prefixes[$idx]}"
2160
2193
  num=$((RANDOM % 99 + 1))
2161
2194
  name="${prefix}-${num}"
2162
- json_ok "\"$name\""
2195
+ json_ok "$(jq -nc --arg n "$name" '$n')"
2163
2196
  ;;
2164
2197
 
2165
2198
  validate-worker-response)
@@ -2260,7 +2293,7 @@ EOF
2260
2293
  json_err "$E_VALIDATION_FAILED" "Worker response failed schema validation" "{\"caste\":\"$vw_caste\"}"
2261
2294
  fi
2262
2295
 
2263
- json_ok "{\"valid\":true,\"caste\":\"$vw_caste\"}"
2296
+ json_ok "$(jq -nc --arg c "$vw_caste" '{valid:true,caste:$c}')"
2264
2297
  ;;
2265
2298
 
2266
2299
  # ============================================
@@ -2315,7 +2348,7 @@ EOF
2315
2348
  if (.graveyards | length) > 30 then .graveyards = .graveyards[-30:] else . end
2316
2349
  ' >/dev/null
2317
2350
 
2318
- json_ok "\"$ga_id\""
2351
+ json_ok "$(jq -nc --arg id "$ga_id" '$id')"
2319
2352
  ;;
2320
2353
 
2321
2354
  grave-check)
@@ -2414,7 +2447,7 @@ Files: ${files_changed} files changed"
2414
2447
  fi
2415
2448
 
2416
2449
  # Return enhanced JSON with additional metadata
2417
- json_ok "{\"message\":\"$message\",\"body\":\"$body\",\"files_changed\":$files_changed,\"subsystem\":\"$subsystem\",\"scope\":\"${phase_id}.${plan_num}\"}"
2450
+ json_ok "$(jq -nc --arg msg "$message" --arg body "$body" --arg sub "$subsystem" --arg scope "${phase_id}.${plan_num}" '{message:$msg,body:$body,files_changed:'"$files_changed"',subsystem:$sub,scope:$scope}')"
2418
2451
  exit 0
2419
2452
  ;;
2420
2453
  seal)
@@ -2436,7 +2469,7 @@ Files: ${files_changed} files changed"
2436
2469
  message="${message:0:69}..."
2437
2470
  fi
2438
2471
 
2439
- json_ok "{\"message\":\"$message\",\"body\":\"$body\",\"files_changed\":$files_changed}"
2472
+ json_ok "$(jq -nc --arg msg "$message" --arg body "$body" '{message:$msg,body:$body,files_changed:'"$files_changed"'}')"
2440
2473
  exit 0
2441
2474
  ;;
2442
2475
  *)
@@ -2450,7 +2483,7 @@ Files: ${files_changed} files changed"
2450
2483
  message="${message:0:69}..."
2451
2484
  fi
2452
2485
 
2453
- json_ok "{\"message\":\"$message\",\"body\":\"$body\",\"files_changed\":$files_changed}"
2486
+ json_ok "$(jq -nc --arg msg "$message" --arg body "$body" '{message:$msg,body:$body,files_changed:'"$files_changed"'}')"
2454
2487
  ;;
2455
2488
 
2456
2489
  # ============================================
@@ -2502,7 +2535,7 @@ Files: ${files_changed} files changed"
2502
2535
  json_ok '""'
2503
2536
  else
2504
2537
  printf -v msg 'Update available: %s to %s (run /ant:update)' "$local_ver" "$hub_ver"
2505
- json_ok "$msg"
2538
+ json_ok "$(jq -nc --arg m "$msg" '$m')"
2506
2539
  fi
2507
2540
  ;;
2508
2541
 
@@ -2628,7 +2661,7 @@ Files: ${files_changed} files changed"
2628
2661
  json_err "$E_UNKNOWN" "Failed to write registry file"
2629
2662
  }
2630
2663
  release_lock "$registry_file" 2>/dev/null || true # SUPPRESS:OK -- cleanup: lock may not be held
2631
- json_ok "{\"registered\":true,\"path\":\"$repo_path\",\"version\":\"$repo_version\"}"
2664
+ json_ok "$(jq -nc --arg p "$repo_path" --arg v "$repo_version" '{registered:true,path:$p,version:$v}')"
2632
2665
  ;;
2633
2666
 
2634
2667
  registry-list)
@@ -2773,7 +2806,8 @@ Files: ${files_changed} files changed"
2773
2806
  if [[ $? -eq 0 ]]; then
2774
2807
  # Output success with handoff info if detected
2775
2808
  if [[ "$HANDOFF_DETECTED" == "true" ]]; then
2776
- json_ok "{\"loaded\":true,\"handoff_detected\":true,\"handoff_summary\":\"$(get_handoff_summary)\"}"
2809
+ _handoff_summary=$(get_handoff_summary)
2810
+ json_ok "$(jq -nc --arg hs "$_handoff_summary" '{loaded:true,handoff_detected:true,handoff_summary:$hs}')"
2777
2811
  else
2778
2812
  json_ok '{"loaded":true}'
2779
2813
  fi
@@ -3110,10 +3144,10 @@ Files: ${files_changed} files changed"
3110
3144
  json_ok "$(cat "$view_state_file")"
3111
3145
  elif [[ -z "$key" ]]; then
3112
3146
  # Return specific view
3113
- json_ok "$(jq ".${view_name} // {}" "$view_state_file")"
3147
+ json_ok "$(jq --arg v "$view_name" '.[$v] // {}' "$view_state_file")"
3114
3148
  else
3115
3149
  # Return specific key from view
3116
- json_ok "$(jq ".${view_name}.${key} // null" "$view_state_file")"
3150
+ json_ok "$(jq --arg v "$view_name" --arg k "$key" '.[$v][$k] // null' "$view_state_file")"
3117
3151
  fi
3118
3152
  ;;
3119
3153
 
@@ -3145,7 +3179,7 @@ Files: ${files_changed} files changed"
3145
3179
  fi
3146
3180
 
3147
3181
  atomic_write "$view_state_file" "$updated"
3148
- json_ok "$(echo "$updated" | jq ".${view_name}")"
3182
+ json_ok "$(echo "$updated" | jq --arg v "$view_name" '.[$v]')"
3149
3183
  ;;
3150
3184
 
3151
3185
  view-state-toggle)
@@ -3183,7 +3217,7 @@ Files: ${files_changed} files changed"
3183
3217
  fi
3184
3218
 
3185
3219
  atomic_write "$view_state_file" "$updated"
3186
- json_ok "{\"item\":\"$item\",\"state\":\"$new_state\",\"view\":\"$view_name\"}"
3220
+ json_ok "$(jq -nc --arg i "$item" --arg s "$new_state" --arg v "$view_name" '{item:$i,state:$s,view:$v}')"
3187
3221
  ;;
3188
3222
 
3189
3223
  view-state-expand)
@@ -3205,7 +3239,7 @@ Files: ${files_changed} files changed"
3205
3239
  ' "$view_state_file") || json_err "$E_JSON_INVALID" "Failed to update view state"
3206
3240
 
3207
3241
  atomic_write "$view_state_file" "$updated"
3208
- json_ok "{\"item\":\"$item\",\"state\":\"expanded\",\"view\":\"$view_name\"}"
3242
+ json_ok "$(jq -nc --arg i "$item" --arg v "$view_name" '{item:$i,state:"expanded",view:$v}')"
3209
3243
  ;;
3210
3244
 
3211
3245
  view-state-collapse)
@@ -3227,7 +3261,7 @@ Files: ${files_changed} files changed"
3227
3261
  ' "$view_state_file") || json_err "$E_JSON_INVALID" "Failed to update view state"
3228
3262
 
3229
3263
  atomic_write "$view_state_file" "$updated"
3230
- json_ok "{\"item\":\"$item\",\"state\":\"collapsed\",\"view\":\"$view_name\"}"
3264
+ json_ok "$(jq -nc --arg i "$item" --arg v "$view_name" '{item:$i,state:"collapsed",view:$v}')"
3231
3265
  ;;
3232
3266
 
3233
3267
  queen-init) _queen_init "$@" ;;
@@ -3294,7 +3328,7 @@ Files: ${files_changed} files changed"
3294
3328
  bar="[$bar]"
3295
3329
  fi
3296
3330
 
3297
- json_ok "{\"bar\":\"$bar\",\"count\":$obs_count,\"threshold\":$threshold}"
3331
+ json_ok "$(jq -nc --arg b "$bar" --argjson c "$obs_count" --argjson t "$threshold" '{bar:$b,count:$c,threshold:$t}')"
3298
3332
  ;;
3299
3333
 
3300
3334
  parse-selection)
@@ -3501,7 +3535,7 @@ Files: ${files_changed} files changed"
3501
3535
  ;;
3502
3536
  esac
3503
3537
 
3504
- json_ok "{\"incident_id\":\"$ir_incident_id\",\"rule_type\":\"$ir_rule_type\",\"added\":true,\"timestamp\":\"$ir_ts\"}"
3538
+ json_ok "$(jq -nc --arg id "$ir_incident_id" --arg rt "$ir_rule_type" --arg ts "$ir_ts" '{incident_id:$id,rule_type:$rt,added:true,timestamp:$ts}')"
3505
3539
  ;;
3506
3540
 
3507
3541
  queen-promote) _queen_promote "$@" ;;
@@ -3630,7 +3664,7 @@ Files: ${files_changed} files changed"
3630
3664
  bash "$0" rolling-summary add "$mc_event" "$mc_content" "$mc_source" >/dev/null 2>&1 \
3631
3665
  || _aether_log_error "Could not update rolling summary"
3632
3666
 
3633
- json_ok "{\"event_type\":\"$mc_event\",\"wisdom_type\":\"$mc_wisdom_type\",\"observation_count\":$obs_count,\"threshold\":$obs_threshold,\"threshold_met\":$obs_threshold_met,\"pheromone_created\":$pheromone_created,\"signal_id\":\"$pheromone_signal_id\",\"auto_promoted\":$auto_promoted,\"promotion_reason\":\"$auto_reason\"}"
3667
+ json_ok "$(jq -nc --arg et "$mc_event" --arg wt "$mc_wisdom_type" --argjson oc "$obs_count" --argjson th "$obs_threshold" --argjson tm "$obs_threshold_met" --argjson pc "$pheromone_created" --arg sid "$pheromone_signal_id" --argjson ap "$auto_promoted" --arg pr "$auto_reason" '{event_type:$et,wisdom_type:$wt,observation_count:$oc,threshold:$th,threshold_met:$tm,pheromone_created:$pc,signal_id:$sid,auto_promoted:$ap,promotion_reason:$pr}')"
3634
3668
  ;;
3635
3669
 
3636
3670
  learning-display-proposals) _learning_display_proposals "$@" ;;
@@ -3675,7 +3709,7 @@ Files: ${files_changed} files changed"
3675
3709
  ;;
3676
3710
  esac
3677
3711
 
3678
- json_ok "{\"ok\":true,\"docs\":\"$docs\",\"dir\":\"$survey_dir\"}"
3712
+ json_ok "$(jq -nc --arg d "$docs" --arg dir "$survey_dir" '{ok:true,docs:$d,dir:$dir}')"
3679
3713
  ;;
3680
3714
 
3681
3715
  survey-verify)
@@ -3697,7 +3731,7 @@ Files: ${files_changed} files changed"
3697
3731
  json_err "$E_FILE_NOT_FOUND" "Missing survey documents" "{\"missing\":\"$missing\"}"
3698
3732
  fi
3699
3733
 
3700
- json_ok "{\"ok\":true,\"counts\":\"$counts\"}"
3734
+ json_ok "$(jq -nc --arg c "$counts" '{ok:true,counts:$c}')"
3701
3735
  ;;
3702
3736
 
3703
3737
  checkpoint-check)
@@ -4101,7 +4135,7 @@ Files: ${files_changed} files changed"
4101
4135
  json_err "$E_UNKNOWN" "Failed to finalize rolling summary file"
4102
4136
  }
4103
4137
 
4104
- json_ok "{\"added\":true,\"event\":\"$rs_clean_event\",\"source\":\"$rs_clean_source\"}"
4138
+ json_ok "$(jq -nc --arg e "$rs_clean_event" --arg s "$rs_clean_source" '{added:true,event:$e,source:$s}')"
4105
4139
  ;;
4106
4140
 
4107
4141
  read)
@@ -4330,7 +4364,7 @@ Files: ${files_changed} files changed"
4330
4364
 
4331
4365
  cc_words=$(printf '%s' "$cc_section" | wc -w | tr -d ' ')
4332
4366
  cc_prompt_json=$(printf '%s' "$cc_section" | jq -Rs '.' 2>/dev/null || echo '""') # SUPPRESS:OK -- read-default: returns fallback if missing
4333
- json_ok "{\"exists\":true,\"state\":\"$cc_state\",\"next_action\":\"$cc_next_action\",\"word_count\":$cc_words,\"prompt_section\":$cc_prompt_json}"
4367
+ json_ok "$(jq -nc --arg st "$cc_state" --arg na "$cc_next_action" --argjson wc "$cc_words" --argjson ps "$cc_prompt_json" '{exists:true,state:$st,next_action:$na,word_count:$wc,prompt_section:$ps}')"
4334
4368
  ;;
4335
4369
 
4336
4370
  session-init) _session_init "$@" ;;
@@ -4341,6 +4375,13 @@ Files: ${files_changed} files changed"
4341
4375
  session-mark-resumed) _session_mark_resumed "$@" ;;
4342
4376
  session-summary) _session_summary "$@" ;;
4343
4377
 
4378
+ pending-decision-add) _pending_decision_add "$@" ;;
4379
+ pending-decision-list) _pending_decision_list "$@" ;;
4380
+ pending-decision-resolve) _pending_decision_resolve "$@" ;;
4381
+
4382
+ autopilot-headless-check) _autopilot_headless_check "$@" ;;
4383
+ autopilot-set-headless) _autopilot_set_headless "$@" ;;
4384
+
4344
4385
  generate-progress-bar)
4345
4386
  generate-progress-bar "$@"
4346
4387
  ;;
@@ -4717,6 +4758,35 @@ EOF
4717
4758
 
4718
4759
  midden-acknowledge) _midden_acknowledge "$@" ;;
4719
4760
 
4761
+ midden-search) _midden_search "$@" ;;
4762
+
4763
+ midden-tag) _midden_tag "$@" ;;
4764
+
4765
+ trophallaxis-diagnose) _trophallaxis_diagnose "$@" ;;
4766
+
4767
+ trophallaxis-retry) _trophallaxis_retry "$@" ;;
4768
+
4769
+ scar-add) _scar_add "$@" ;;
4770
+
4771
+ scar-list) _scar_list "$@" ;;
4772
+
4773
+ scar-check) _scar_check "$@" ;;
4774
+
4775
+ immune-auto-scar) _immune_auto_scar "$@" ;;
4776
+
4777
+ # ── Council Deliberation ────────────────────────────────────────────────────
4778
+ council-deliberate) _council_deliberate "$@" ;;
4779
+
4780
+ council-advocate) _council_advocate "$@" ;;
4781
+
4782
+ council-challenger) _council_challenger "$@" ;;
4783
+
4784
+ council-sage) _council_sage "$@" ;;
4785
+
4786
+ council-history) _council_history "$@" ;;
4787
+
4788
+ council-budget-check) _council_budget_check "$@" ;;
4789
+
4720
4790
  resume-dashboard)
4721
4791
  # Generate dashboard data for /ant:resume command
4722
4792
  # Usage: resume-dashboard
@@ -4798,6 +4868,14 @@ EOF
4798
4868
  exit 0
4799
4869
  ;;
4800
4870
 
4871
+ colony-vital-signs)
4872
+ # Compute colony health metrics from existing data files
4873
+ # Usage: colony-vital-signs
4874
+ # Returns: JSON with build_velocity, error_rate, signal_health, memory_pressure,
4875
+ # colony_age_hours, and overall_health (0-100)
4876
+ _colony_vital_signs
4877
+ ;;
4878
+
4801
4879
  data-safety-stats)
4802
4880
  # Read data safety statistics from safety-stats.json
4803
4881
  # Usage: data-safety-stats
@@ -4820,6 +4898,8 @@ EOF
4820
4898
  exit 0
4821
4899
  ;;
4822
4900
 
4901
+ # colony-vital-signs handled above (dispatches to _colony_vital_signs in state-api.sh)
4902
+
4823
4903
  suggest-analyze) _suggest_analyze "$@" ;;
4824
4904
  suggest-record) _suggest_record "$@" ;;
4825
4905
  suggest-check) _suggest_check "$@" ;;
@@ -66,6 +66,8 @@ body_claude: |
66
66
 
67
67
  **If the file exists:** continue.
68
68
 
69
+ **If `milestone` == `"Crowned Anthill"`:** output "This colony has been sealed. Start a new colony with `/ant:init \"new goal\"`.", stop.
70
+
69
71
  **If `plan.phases` is not empty:** output "Colony already has phases. Use /ant:continue.", stop.
70
72
 
71
73
  ### Step 2: Quick Surface Scan (for session context)
@@ -287,6 +289,8 @@ body_opencode: |
287
289
 
288
290
  **If the file exists:** continue.
289
291
 
292
+ **If `milestone` == `"Crowned Anthill"`:** output "This colony has been sealed. Start a new colony with `/ant:init \"new goal\"`.", stop.
293
+
290
294
  **If `plan.phases` is not empty:** output "Colony already has phases. Use /ant:continue.", stop.
291
295
 
292
296
  ### Step 2: Quick Surface Scan (for session context)