aether-colony 5.3.2 → 5.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.aether/aether-utils.sh +181 -5
- package/.aether/commands/archaeology.yaml +3 -3
- package/.aether/commands/build.yaml +80 -45
- package/.aether/commands/chaos.yaml +7 -7
- package/.aether/commands/colonize.yaml +17 -17
- package/.aether/commands/continue.yaml +40 -40
- package/.aether/commands/council.yaml +6 -6
- package/.aether/commands/data-clean.yaml +3 -3
- package/.aether/commands/dream.yaml +2 -2
- package/.aether/commands/entomb.yaml +12 -12
- package/.aether/commands/export-signals.yaml +2 -2
- package/.aether/commands/feedback.yaml +6 -6
- package/.aether/commands/flag.yaml +2 -2
- package/.aether/commands/flags.yaml +4 -4
- package/.aether/commands/focus.yaml +6 -6
- package/.aether/commands/help.yaml +1 -1
- package/.aether/commands/history.yaml +1 -1
- package/.aether/commands/import-signals.yaml +2 -2
- package/.aether/commands/init.yaml +44 -27
- package/.aether/commands/insert-phase.yaml +1 -1
- package/.aether/commands/interpret.yaml +2 -2
- package/.aether/commands/lay-eggs.yaml +3 -3
- package/.aether/commands/maturity.yaml +2 -2
- package/.aether/commands/memory-details.yaml +1 -1
- package/.aether/commands/migrate-state.yaml +1 -1
- package/.aether/commands/oracle.yaml +147 -82
- package/.aether/commands/organize.yaml +5 -5
- package/.aether/commands/patrol.yaml +8 -8
- package/.aether/commands/pause-colony.yaml +7 -7
- package/.aether/commands/phase.yaml +1 -1
- package/.aether/commands/pheromones.yaml +1 -1
- package/.aether/commands/plan.yaml +14 -14
- package/.aether/commands/quick.yaml +4 -4
- package/.aether/commands/redirect.yaml +6 -6
- package/.aether/commands/resume-colony.yaml +9 -9
- package/.aether/commands/resume.yaml +5 -38
- package/.aether/commands/run.yaml +10 -10
- package/.aether/commands/seal.yaml +33 -33
- package/.aether/commands/skill-create.yaml +4 -4
- package/.aether/commands/status.yaml +14 -14
- package/.aether/commands/swarm.yaml +14 -14
- package/.aether/commands/tunnels.yaml +7 -7
- package/.aether/commands/update.yaml +1 -1
- package/.aether/commands/verify-castes.yaml +3 -3
- package/.aether/commands/watch.yaml +15 -15
- package/.aether/docs/command-playbooks/build-complete.md +48 -15
- package/.aether/docs/command-playbooks/build-context.md +11 -11
- package/.aether/docs/command-playbooks/build-full.md +76 -76
- package/.aether/docs/command-playbooks/build-prep.md +10 -10
- package/.aether/docs/command-playbooks/build-verify.md +27 -27
- package/.aether/docs/command-playbooks/build-wave.md +38 -38
- package/.aether/docs/command-playbooks/continue-advance.md +60 -27
- package/.aether/docs/command-playbooks/continue-finalize.md +25 -11
- package/.aether/docs/command-playbooks/continue-full.md +60 -46
- package/.aether/docs/command-playbooks/continue-gates.md +18 -18
- package/.aether/docs/command-playbooks/continue-verify.md +10 -10
- package/.aether/docs/source-of-truth-map.md +10 -10
- package/.aether/docs/structural-learning-stack.md +283 -0
- package/.aether/templates/colony-state-template.json +1 -0
- package/.aether/utils/consolidation-seal.sh +196 -0
- package/.aether/utils/consolidation.sh +127 -0
- package/.aether/utils/curation-ants/archivist.sh +97 -0
- package/.aether/utils/curation-ants/critic.sh +214 -0
- package/.aether/utils/curation-ants/herald.sh +102 -0
- package/.aether/utils/curation-ants/janitor.sh +121 -0
- package/.aether/utils/curation-ants/librarian.sh +99 -0
- package/.aether/utils/curation-ants/nurse.sh +153 -0
- package/.aether/utils/curation-ants/orchestrator.sh +181 -0
- package/.aether/utils/curation-ants/scribe.sh +164 -0
- package/.aether/utils/curation-ants/sentinel.sh +119 -0
- package/.aether/utils/event-bus.sh +301 -0
- package/.aether/utils/graph.sh +559 -0
- package/.aether/utils/instinct-store.sh +401 -0
- package/.aether/utils/learning.sh +79 -7
- package/.aether/utils/oracle/oracle-stop-hook.sh +896 -0
- package/.aether/utils/session.sh +13 -0
- package/.aether/utils/state-api.sh +1 -1
- package/.aether/utils/trust-scoring.sh +347 -0
- package/.aether/utils/worktree.sh +97 -0
- package/.claude/commands/ant/archaeology.md +2 -2
- package/.claude/commands/ant/chaos.md +4 -4
- package/.claude/commands/ant/colonize.md +9 -9
- package/.claude/commands/ant/council.md +6 -6
- package/.claude/commands/ant/data-clean.md +3 -3
- package/.claude/commands/ant/dream.md +2 -2
- package/.claude/commands/ant/entomb.md +9 -9
- package/.claude/commands/ant/export-signals.md +2 -2
- package/.claude/commands/ant/feedback.md +4 -4
- package/.claude/commands/ant/flag.md +2 -2
- package/.claude/commands/ant/flags.md +4 -4
- package/.claude/commands/ant/focus.md +4 -4
- package/.claude/commands/ant/help.md +1 -1
- package/.claude/commands/ant/history.md +1 -1
- package/.claude/commands/ant/import-signals.md +2 -2
- package/.claude/commands/ant/init.md +44 -27
- package/.claude/commands/ant/insert-phase.md +1 -1
- package/.claude/commands/ant/interpret.md +2 -2
- package/.claude/commands/ant/lay-eggs.md +2 -2
- package/.claude/commands/ant/maturity.md +2 -2
- package/.claude/commands/ant/memory-details.md +1 -1
- package/.claude/commands/ant/migrate-state.md +1 -1
- package/.claude/commands/ant/oracle.md +78 -42
- package/.claude/commands/ant/organize.md +3 -3
- package/.claude/commands/ant/patrol.md +8 -8
- package/.claude/commands/ant/pause-colony.md +5 -5
- package/.claude/commands/ant/phase.md +1 -1
- package/.claude/commands/ant/pheromones.md +1 -1
- package/.claude/commands/ant/plan.md +8 -8
- package/.claude/commands/ant/quick.md +4 -4
- package/.claude/commands/ant/redirect.md +4 -4
- package/.claude/commands/ant/resume-colony.md +5 -5
- package/.claude/commands/ant/resume.md +17 -29
- package/.claude/commands/ant/run.md +10 -10
- package/.claude/commands/ant/seal.md +25 -25
- package/.claude/commands/ant/skill-create.md +2 -2
- package/.claude/commands/ant/status.md +14 -14
- package/.claude/commands/ant/swarm.md +14 -14
- package/.claude/commands/ant/tunnels.md +4 -4
- package/.claude/commands/ant/update.md +1 -1
- package/.claude/commands/ant/verify-castes.md +2 -2
- package/.claude/commands/ant/watch.md +8 -8
- package/.opencode/commands/ant/archaeology.md +1 -1
- package/.opencode/commands/ant/build.md +80 -45
- package/.opencode/commands/ant/chaos.md +3 -3
- package/.opencode/commands/ant/colonize.md +8 -8
- package/.opencode/commands/ant/continue.md +40 -40
- package/.opencode/commands/ant/council.md +5 -5
- package/.opencode/commands/ant/data-clean.md +2 -2
- package/.opencode/commands/ant/dream.md +1 -1
- package/.opencode/commands/ant/entomb.md +3 -3
- package/.opencode/commands/ant/export-signals.md +1 -1
- package/.opencode/commands/ant/feedback.md +2 -2
- package/.opencode/commands/ant/flag.md +1 -1
- package/.opencode/commands/ant/flags.md +3 -3
- package/.opencode/commands/ant/focus.md +2 -2
- package/.opencode/commands/ant/import-signals.md +1 -1
- package/.opencode/commands/ant/init.md +44 -27
- package/.opencode/commands/ant/insert-phase.md +1 -1
- package/.opencode/commands/ant/interpret.md +1 -1
- package/.opencode/commands/ant/lay-eggs.md +2 -2
- package/.opencode/commands/ant/maturity.md +1 -1
- package/.opencode/commands/ant/memory-details.md +1 -1
- package/.opencode/commands/ant/oracle.md +69 -40
- package/.opencode/commands/ant/organize.md +2 -2
- package/.opencode/commands/ant/patrol.md +8 -8
- package/.opencode/commands/ant/pause-colony.md +2 -2
- package/.opencode/commands/ant/pheromones.md +1 -1
- package/.opencode/commands/ant/plan.md +6 -6
- package/.opencode/commands/ant/quick.md +4 -4
- package/.opencode/commands/ant/redirect.md +2 -2
- package/.opencode/commands/ant/resume-colony.md +4 -4
- package/.opencode/commands/ant/resume.md +5 -17
- package/.opencode/commands/ant/run.md +10 -10
- package/.opencode/commands/ant/seal.md +8 -8
- package/.opencode/commands/ant/skill-create.md +2 -2
- package/.opencode/commands/ant/status.md +10 -10
- package/.opencode/commands/ant/tunnels.md +3 -3
- package/.opencode/commands/ant/verify-castes.md +1 -1
- package/.opencode/commands/ant/watch.md +7 -7
- package/CHANGELOG.md +83 -0
- package/README.md +22 -9
- package/bin/cli.js +118 -3
- package/bin/lib/binary-downloader.js +267 -0
- package/bin/lib/update-transaction.js +27 -3
- package/bin/lib/version-gate.js +179 -0
- package/bin/npx-entry.js +0 -0
- package/package.json +1 -1
- package/.aether/agents/aether-ambassador.md +0 -140
- package/.aether/agents/aether-archaeologist.md +0 -108
- package/.aether/agents/aether-architect.md +0 -133
- package/.aether/agents/aether-auditor.md +0 -144
- package/.aether/agents/aether-builder.md +0 -184
- package/.aether/agents/aether-chaos.md +0 -115
- package/.aether/agents/aether-chronicler.md +0 -122
- package/.aether/agents/aether-gatekeeper.md +0 -116
- package/.aether/agents/aether-includer.md +0 -117
- package/.aether/agents/aether-keeper.md +0 -177
- package/.aether/agents/aether-measurer.md +0 -128
- package/.aether/agents/aether-oracle.md +0 -137
- package/.aether/agents/aether-probe.md +0 -133
- package/.aether/agents/aether-queen.md +0 -286
- package/.aether/agents/aether-route-setter.md +0 -130
- package/.aether/agents/aether-sage.md +0 -106
- package/.aether/agents/aether-scout.md +0 -101
- package/.aether/agents/aether-surveyor-disciplines.md +0 -391
- package/.aether/agents/aether-surveyor-nest.md +0 -329
- package/.aether/agents/aether-surveyor-pathogens.md +0 -264
- package/.aether/agents/aether-surveyor-provisions.md +0 -334
- package/.aether/agents/aether-tracker.md +0 -137
- package/.aether/agents/aether-watcher.md +0 -174
- package/.aether/agents/aether-weaver.md +0 -130
- package/.aether/commands/claude/archaeology.md +0 -334
- package/.aether/commands/claude/build.md +0 -65
- package/.aether/commands/claude/chaos.md +0 -336
- package/.aether/commands/claude/colonize.md +0 -259
- package/.aether/commands/claude/continue.md +0 -60
- package/.aether/commands/claude/council.md +0 -507
- package/.aether/commands/claude/data-clean.md +0 -81
- package/.aether/commands/claude/dream.md +0 -268
- package/.aether/commands/claude/entomb.md +0 -498
- package/.aether/commands/claude/export-signals.md +0 -57
- package/.aether/commands/claude/feedback.md +0 -96
- package/.aether/commands/claude/flag.md +0 -151
- package/.aether/commands/claude/flags.md +0 -169
- package/.aether/commands/claude/focus.md +0 -76
- package/.aether/commands/claude/help.md +0 -154
- package/.aether/commands/claude/history.md +0 -140
- package/.aether/commands/claude/import-signals.md +0 -71
- package/.aether/commands/claude/init.md +0 -505
- package/.aether/commands/claude/insert-phase.md +0 -105
- package/.aether/commands/claude/interpret.md +0 -278
- package/.aether/commands/claude/lay-eggs.md +0 -210
- package/.aether/commands/claude/maturity.md +0 -113
- package/.aether/commands/claude/memory-details.md +0 -77
- package/.aether/commands/claude/migrate-state.md +0 -171
- package/.aether/commands/claude/oracle.md +0 -642
- package/.aether/commands/claude/organize.md +0 -232
- package/.aether/commands/claude/patrol.md +0 -620
- package/.aether/commands/claude/pause-colony.md +0 -233
- package/.aether/commands/claude/phase.md +0 -115
- package/.aether/commands/claude/pheromones.md +0 -156
- package/.aether/commands/claude/plan.md +0 -693
- package/.aether/commands/claude/preferences.md +0 -65
- package/.aether/commands/claude/quick.md +0 -100
- package/.aether/commands/claude/redirect.md +0 -76
- package/.aether/commands/claude/resume-colony.md +0 -197
- package/.aether/commands/claude/resume.md +0 -388
- package/.aether/commands/claude/run.md +0 -231
- package/.aether/commands/claude/seal.md +0 -774
- package/.aether/commands/claude/skill-create.md +0 -286
- package/.aether/commands/claude/status.md +0 -410
- package/.aether/commands/claude/swarm.md +0 -349
- package/.aether/commands/claude/tunnels.md +0 -426
- package/.aether/commands/claude/update.md +0 -132
- package/.aether/commands/claude/verify-castes.md +0 -143
- package/.aether/commands/claude/watch.md +0 -239
- package/.aether/commands/opencode/archaeology.md +0 -331
- package/.aether/commands/opencode/build.md +0 -1168
- package/.aether/commands/opencode/chaos.md +0 -329
- package/.aether/commands/opencode/colonize.md +0 -195
- package/.aether/commands/opencode/continue.md +0 -1436
- package/.aether/commands/opencode/council.md +0 -437
- package/.aether/commands/opencode/data-clean.md +0 -77
- package/.aether/commands/opencode/dream.md +0 -260
- package/.aether/commands/opencode/entomb.md +0 -377
- package/.aether/commands/opencode/export-signals.md +0 -54
- package/.aether/commands/opencode/feedback.md +0 -99
- package/.aether/commands/opencode/flag.md +0 -149
- package/.aether/commands/opencode/flags.md +0 -167
- package/.aether/commands/opencode/focus.md +0 -73
- package/.aether/commands/opencode/help.md +0 -157
- package/.aether/commands/opencode/history.md +0 -136
- package/.aether/commands/opencode/import-signals.md +0 -68
- package/.aether/commands/opencode/init.md +0 -518
- package/.aether/commands/opencode/insert-phase.md +0 -111
- package/.aether/commands/opencode/interpret.md +0 -272
- package/.aether/commands/opencode/lay-eggs.md +0 -213
- package/.aether/commands/opencode/maturity.md +0 -108
- package/.aether/commands/opencode/memory-details.md +0 -83
- package/.aether/commands/opencode/migrate-state.md +0 -165
- package/.aether/commands/opencode/oracle.md +0 -593
- package/.aether/commands/opencode/organize.md +0 -226
- package/.aether/commands/opencode/patrol.md +0 -626
- package/.aether/commands/opencode/pause-colony.md +0 -203
- package/.aether/commands/opencode/phase.md +0 -113
- package/.aether/commands/opencode/pheromones.md +0 -162
- package/.aether/commands/opencode/plan.md +0 -684
- package/.aether/commands/opencode/preferences.md +0 -71
- package/.aether/commands/opencode/quick.md +0 -91
- package/.aether/commands/opencode/redirect.md +0 -84
- package/.aether/commands/opencode/resume-colony.md +0 -190
- package/.aether/commands/opencode/resume.md +0 -394
- package/.aether/commands/opencode/run.md +0 -237
- package/.aether/commands/opencode/seal.md +0 -452
- package/.aether/commands/opencode/skill-create.md +0 -63
- package/.aether/commands/opencode/status.md +0 -307
- package/.aether/commands/opencode/swarm.md +0 -15
- package/.aether/commands/opencode/tunnels.md +0 -400
- package/.aether/commands/opencode/update.md +0 -127
- package/.aether/commands/opencode/verify-castes.md +0 -139
- package/.aether/commands/opencode/watch.md +0 -227
|
@@ -0,0 +1,896 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Oracle Ant - In-Session Stop Hook
|
|
3
|
+
# Intercepts session exit when Oracle research is active.
|
|
4
|
+
# Re-feeds phase-aware prompts to continue the research loop.
|
|
5
|
+
#
|
|
6
|
+
# Modeled on the Ralph Loop Stop hook pattern:
|
|
7
|
+
# - Checks .aether/oracle/.loop-active for loop state
|
|
8
|
+
# - Session isolation via session_id
|
|
9
|
+
# - Outputs {"decision":"block","reason":"..."} to re-feed prompt
|
|
10
|
+
# - Outputs nothing (exit 0) to allow normal stop
|
|
11
|
+
#
|
|
12
|
+
# Completion criteria (any triggers synthesis pass):
|
|
13
|
+
# - Max iterations reached
|
|
14
|
+
# - overall_confidence >= target_confidence
|
|
15
|
+
# - <oracle>COMPLETE</oracle> in last assistant message
|
|
16
|
+
# - Convergence detected (composite score >= threshold + low novelty)
|
|
17
|
+
|
|
18
|
+
set -euo pipefail
|
|
19
|
+
|
|
20
|
+
# ---------------------------------------------------------------------------
|
|
21
|
+
# Configuration
|
|
22
|
+
# ---------------------------------------------------------------------------
|
|
23
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
24
|
+
AETHER_ROOT="$(cd "$SCRIPT_DIR/../../.." && pwd)"
|
|
25
|
+
ORACLE_DIR="$AETHER_ROOT/.aether/oracle"
|
|
26
|
+
MARKER_FILE="$ORACLE_DIR/.loop-active"
|
|
27
|
+
STATE_FILE="$ORACLE_DIR/state.json"
|
|
28
|
+
PLAN_FILE="$ORACLE_DIR/plan.json"
|
|
29
|
+
STOP_FILE="$ORACLE_DIR/.stop"
|
|
30
|
+
ORACLE_MD="$SCRIPT_DIR/oracle.md"
|
|
31
|
+
|
|
32
|
+
# Convergence thresholds (matching oracle.sh defaults)
|
|
33
|
+
CONV_THRESHOLD=${ORACLE_CONVERGENCE_THRESHOLD:-85}
|
|
34
|
+
DR_WINDOW=${ORACLE_DR_WINDOW:-3}
|
|
35
|
+
|
|
36
|
+
# ---------------------------------------------------------------------------
|
|
37
|
+
# Fast exit: no active loop
|
|
38
|
+
# ---------------------------------------------------------------------------
|
|
39
|
+
if [[ ! -f "$MARKER_FILE" ]]; then
|
|
40
|
+
exit 0
|
|
41
|
+
fi
|
|
42
|
+
|
|
43
|
+
# ---------------------------------------------------------------------------
|
|
44
|
+
# Read hook input from stdin
|
|
45
|
+
# ---------------------------------------------------------------------------
|
|
46
|
+
HOOK_INPUT=$(cat)
|
|
47
|
+
|
|
48
|
+
INPUT_SESSION_ID=$(echo "$HOOK_INPUT" | jq -r '.session_id // ""')
|
|
49
|
+
TRANSCRIPT_PATH=$(echo "$HOOK_INPUT" | jq -r '.transcript_path // ""')
|
|
50
|
+
|
|
51
|
+
# ---------------------------------------------------------------------------
|
|
52
|
+
# Parse marker file frontmatter
|
|
53
|
+
# ---------------------------------------------------------------------------
|
|
54
|
+
FRONTMATTER=$(sed -n '/^---$/,/^---$/{ /^---$/d; p; }' "$MARKER_FILE")
|
|
55
|
+
|
|
56
|
+
ITERATION=$(echo "$FRONTMATTER" | grep '^iteration:' | sed 's/iteration: *//')
|
|
57
|
+
MAX_ITERATIONS=$(echo "$FRONTMATTER" | grep '^max_iterations:' | sed 's/max_iterations: *//')
|
|
58
|
+
MARKER_SESSION_ID=$(echo "$FRONTMATTER" | grep '^session_id:' | sed 's/session_id: *//' || true)
|
|
59
|
+
CURRENT_PHASE=$(echo "$FRONTMATTER" | grep '^phase:' | sed 's/phase: *//' || echo "survey")
|
|
60
|
+
TARGET_CONFIDENCE=$(echo "$FRONTMATTER" | grep '^target_confidence:' | sed 's/target_confidence: *//' || echo "95")
|
|
61
|
+
SYNTHESIS_DONE=$(echo "$FRONTMATTER" | grep '^synthesis_done:' | sed 's/synthesis_done: *//' || echo "false")
|
|
62
|
+
|
|
63
|
+
# ---------------------------------------------------------------------------
|
|
64
|
+
# Validate numeric fields
|
|
65
|
+
# ---------------------------------------------------------------------------
|
|
66
|
+
if [[ ! "$ITERATION" =~ ^[0-9]+$ ]]; then
|
|
67
|
+
echo "Oracle hook: Invalid iteration in marker file. Removing." >&2
|
|
68
|
+
rm -f "$MARKER_FILE"
|
|
69
|
+
exit 0
|
|
70
|
+
fi
|
|
71
|
+
|
|
72
|
+
if [[ ! "$MAX_ITERATIONS" =~ ^[0-9]+$ ]]; then
|
|
73
|
+
echo "Oracle hook: Invalid max_iterations in marker file. Removing." >&2
|
|
74
|
+
rm -f "$MARKER_FILE"
|
|
75
|
+
exit 0
|
|
76
|
+
fi
|
|
77
|
+
|
|
78
|
+
# ---------------------------------------------------------------------------
|
|
79
|
+
# Session isolation
|
|
80
|
+
# ---------------------------------------------------------------------------
|
|
81
|
+
if [[ -n "$MARKER_SESSION_ID" ]] && [[ "$MARKER_SESSION_ID" != "$INPUT_SESSION_ID" ]]; then
|
|
82
|
+
# Different session started this loop -- don't interfere
|
|
83
|
+
exit 0
|
|
84
|
+
fi
|
|
85
|
+
|
|
86
|
+
# ---------------------------------------------------------------------------
|
|
87
|
+
# Check for user-requested stop
|
|
88
|
+
# ---------------------------------------------------------------------------
|
|
89
|
+
if [[ -f "$STOP_FILE" ]]; then
|
|
90
|
+
rm -f "$STOP_FILE"
|
|
91
|
+
rm -f "$MARKER_FILE"
|
|
92
|
+
echo "Oracle hook: Stop signal received. Ending research." >&2
|
|
93
|
+
exit 0
|
|
94
|
+
fi
|
|
95
|
+
|
|
96
|
+
# ---------------------------------------------------------------------------
|
|
97
|
+
# Validate state files exist
|
|
98
|
+
# ---------------------------------------------------------------------------
|
|
99
|
+
if [[ ! -f "$STATE_FILE" ]]; then
|
|
100
|
+
echo "Oracle hook: state.json missing. Ending research." >&2
|
|
101
|
+
rm -f "$MARKER_FILE"
|
|
102
|
+
exit 0
|
|
103
|
+
fi
|
|
104
|
+
|
|
105
|
+
# Validate state.json is valid JSON
|
|
106
|
+
if ! jq -e . "$STATE_FILE" >/dev/null 2>&1; then
|
|
107
|
+
echo "Oracle hook: state.json is corrupt. Ending research." >&2
|
|
108
|
+
rm -f "$MARKER_FILE"
|
|
109
|
+
exit 0
|
|
110
|
+
fi
|
|
111
|
+
|
|
112
|
+
# ---------------------------------------------------------------------------
|
|
113
|
+
# Read state from state.json
|
|
114
|
+
# ---------------------------------------------------------------------------
|
|
115
|
+
OVERALL_CONFIDENCE=$(jq '.overall_confidence // 0' "$STATE_FILE" 2>/dev/null || echo "0")
|
|
116
|
+
STATE_TARGET=$(jq '.target_confidence // 95' "$STATE_FILE" 2>/dev/null || echo "95")
|
|
117
|
+
# Prefer marker's target_confidence, fall back to state.json
|
|
118
|
+
TARGET=${TARGET_CONFIDENCE:-$STATE_TARGET}
|
|
119
|
+
|
|
120
|
+
# ---------------------------------------------------------------------------
|
|
121
|
+
# Read last assistant message from transcript for COMPLETE tag
|
|
122
|
+
# ---------------------------------------------------------------------------
|
|
123
|
+
COMPLETE_TAG_FOUND=false
|
|
124
|
+
if [[ -n "$TRANSCRIPT_PATH" ]] && [[ -f "$TRANSCRIPT_PATH" ]]; then
|
|
125
|
+
# Get last 100 assistant lines (bounded for performance)
|
|
126
|
+
LAST_LINES=$(grep '"role":"assistant"' "$TRANSCRIPT_PATH" | tail -n 100 2>/dev/null || echo "")
|
|
127
|
+
if [[ -n "$LAST_LINES" ]]; then
|
|
128
|
+
LAST_OUTPUT=$(echo "$LAST_LINES" | jq -rs '
|
|
129
|
+
map(.message.content[]? | select(.type == "text") | .text) | last // ""
|
|
130
|
+
' 2>/dev/null || echo "")
|
|
131
|
+
if echo "$LAST_OUTPUT" | grep -q "<oracle>COMPLETE</oracle>"; then
|
|
132
|
+
COMPLETE_TAG_FOUND=true
|
|
133
|
+
fi
|
|
134
|
+
fi
|
|
135
|
+
fi
|
|
136
|
+
|
|
137
|
+
# ---------------------------------------------------------------------------
|
|
138
|
+
# Convergence detection (ported from oracle.sh)
|
|
139
|
+
# ---------------------------------------------------------------------------
|
|
140
|
+
|
|
141
|
+
# Compute convergence metrics from plan.json
|
|
142
|
+
compute_convergence() {
|
|
143
|
+
local plan_file="$1"
|
|
144
|
+
local state_file="$2"
|
|
145
|
+
|
|
146
|
+
[[ -f "$plan_file" ]] || { echo '{"gap_resolution_pct":0,"coverage_pct":0,"novelty_delta":0,"total_findings":0}'; return 0; }
|
|
147
|
+
|
|
148
|
+
local total answered partial_high
|
|
149
|
+
total=$(jq '[.questions[]] | length' "$plan_file" 2>/dev/null || echo "0")
|
|
150
|
+
answered=$(jq '[.questions[] | select(.status == "answered")] | length' "$plan_file" 2>/dev/null || echo "0")
|
|
151
|
+
partial_high=$(jq '[.questions[] | select(.status == "partial" and .confidence >= 70)] | length' "$plan_file" 2>/dev/null || echo "0")
|
|
152
|
+
|
|
153
|
+
local gap_resolution=0
|
|
154
|
+
if [[ "$total" -gt 0 ]]; then
|
|
155
|
+
gap_resolution=$(( (answered + partial_high) * 100 / total ))
|
|
156
|
+
fi
|
|
157
|
+
|
|
158
|
+
local touched coverage=0
|
|
159
|
+
touched=$(jq '[.questions[] | select((.iterations_touched // []) | length > 0)] | length' "$plan_file" 2>/dev/null || echo "0")
|
|
160
|
+
if [[ "$total" -gt 0 ]]; then
|
|
161
|
+
coverage=$(( touched * 100 / total ))
|
|
162
|
+
fi
|
|
163
|
+
|
|
164
|
+
local current_findings prev_findings novelty_delta
|
|
165
|
+
current_findings=$(jq '[.questions[].key_findings | length] | add // 0' "$plan_file" 2>/dev/null || echo "0")
|
|
166
|
+
prev_findings=$(jq '.convergence.prev_findings_count // 0' "$state_file" 2>/dev/null || echo "0")
|
|
167
|
+
novelty_delta=$(( current_findings - prev_findings ))
|
|
168
|
+
|
|
169
|
+
jq -n --argjson gap "$gap_resolution" --argjson cov "$coverage" \
|
|
170
|
+
--argjson novelty "$novelty_delta" --argjson findings "$current_findings" \
|
|
171
|
+
'{gap_resolution_pct: $gap, coverage_pct: $cov, novelty_delta: $novelty, total_findings: $findings}'
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
# Check if research has converged
|
|
175
|
+
check_convergence() {
|
|
176
|
+
local state_file="$1"
|
|
177
|
+
|
|
178
|
+
local composite_score
|
|
179
|
+
composite_score=$(jq '.convergence.composite_score // 0' "$state_file" 2>/dev/null || echo "0")
|
|
180
|
+
|
|
181
|
+
if [[ "$composite_score" -lt "$CONV_THRESHOLD" ]]; then
|
|
182
|
+
return 1
|
|
183
|
+
fi
|
|
184
|
+
|
|
185
|
+
local history_len
|
|
186
|
+
history_len=$(jq '(.convergence.history // []) | length' "$state_file" 2>/dev/null || echo "0")
|
|
187
|
+
if [[ "$history_len" -lt 2 ]]; then
|
|
188
|
+
return 1
|
|
189
|
+
fi
|
|
190
|
+
|
|
191
|
+
local low_novelty_count
|
|
192
|
+
low_novelty_count=$(jq '[(.convergence.history // [])[-2:][] | select(.novelty_delta <= 1)] | length' "$state_file" 2>/dev/null || echo "0")
|
|
193
|
+
|
|
194
|
+
[[ "$low_novelty_count" -ge 2 ]]
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
# Detect diminishing returns
|
|
198
|
+
detect_diminishing_returns() {
|
|
199
|
+
local state_file="$1"
|
|
200
|
+
|
|
201
|
+
local history_len
|
|
202
|
+
history_len=$(jq '(.convergence.history // []) | length' "$state_file" 2>/dev/null || echo "0")
|
|
203
|
+
|
|
204
|
+
if [[ "$history_len" -lt "$DR_WINDOW" ]]; then
|
|
205
|
+
echo "continue"
|
|
206
|
+
return 0
|
|
207
|
+
fi
|
|
208
|
+
|
|
209
|
+
local novelty_threshold
|
|
210
|
+
case "$CURRENT_PHASE" in
|
|
211
|
+
investigate) novelty_threshold=0 ;;
|
|
212
|
+
*) novelty_threshold=1 ;;
|
|
213
|
+
esac
|
|
214
|
+
|
|
215
|
+
local low_change_count
|
|
216
|
+
low_change_count=$(jq --argjson window "$DR_WINDOW" --argjson threshold "$novelty_threshold" \
|
|
217
|
+
'[(.convergence.history // [])[-$window:][] | select(.novelty_delta <= $threshold)] | length' \
|
|
218
|
+
"$state_file" 2>/dev/null || echo "0")
|
|
219
|
+
|
|
220
|
+
if [[ "$low_change_count" -ge "$DR_WINDOW" ]]; then
|
|
221
|
+
case "$CURRENT_PHASE" in
|
|
222
|
+
survey|investigate) echo "strategy_change" ;;
|
|
223
|
+
synthesize|verify) echo "synthesize_now" ;;
|
|
224
|
+
*) echo "continue" ;;
|
|
225
|
+
esac
|
|
226
|
+
else
|
|
227
|
+
echo "continue"
|
|
228
|
+
fi
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
# Update convergence metrics in state.json
|
|
232
|
+
update_convergence_metrics() {
|
|
233
|
+
local state_file="$1"
|
|
234
|
+
local plan_file="$2"
|
|
235
|
+
local next_iteration="$3"
|
|
236
|
+
local next_phase="$4"
|
|
237
|
+
|
|
238
|
+
local metrics
|
|
239
|
+
metrics=$(compute_convergence "$plan_file" "$state_file")
|
|
240
|
+
|
|
241
|
+
local gap_pct coverage_pct novelty_delta total_findings
|
|
242
|
+
gap_pct=$(echo "$metrics" | jq '.gap_resolution_pct')
|
|
243
|
+
coverage_pct=$(echo "$metrics" | jq '.coverage_pct')
|
|
244
|
+
novelty_delta=$(echo "$metrics" | jq '.novelty_delta')
|
|
245
|
+
total_findings=$(echo "$metrics" | jq '.total_findings')
|
|
246
|
+
|
|
247
|
+
local current_confidence prev_confidence confidence_delta
|
|
248
|
+
current_confidence=$(jq '.overall_confidence // 0' "$state_file" 2>/dev/null || echo "0")
|
|
249
|
+
prev_confidence=$(jq '.convergence.prev_overall_confidence // 0' "$state_file" 2>/dev/null || echo "0")
|
|
250
|
+
confidence_delta=$(( current_confidence - prev_confidence ))
|
|
251
|
+
|
|
252
|
+
# Composite score: gap*0.4 + coverage*0.3 + (novelty<=1?100:0)*0.3
|
|
253
|
+
local novelty_component composite_score converged
|
|
254
|
+
if [[ "$novelty_delta" -le 1 ]]; then
|
|
255
|
+
novelty_component=100
|
|
256
|
+
else
|
|
257
|
+
novelty_component=0
|
|
258
|
+
fi
|
|
259
|
+
composite_score=$(( gap_pct * 40 / 100 + coverage_pct * 30 / 100 + novelty_component * 30 / 100 ))
|
|
260
|
+
|
|
261
|
+
if [[ "$composite_score" -ge "$CONV_THRESHOLD" ]]; then
|
|
262
|
+
converged="true"
|
|
263
|
+
else
|
|
264
|
+
converged="false"
|
|
265
|
+
fi
|
|
266
|
+
|
|
267
|
+
# Atomic write
|
|
268
|
+
jq --argjson prev_findings "$total_findings" \
|
|
269
|
+
--argjson prev_confidence "$current_confidence" \
|
|
270
|
+
--argjson iteration "$next_iteration" \
|
|
271
|
+
--argjson novelty "$novelty_delta" \
|
|
272
|
+
--argjson conf_delta "$confidence_delta" \
|
|
273
|
+
--argjson gap "$gap_pct" \
|
|
274
|
+
--argjson cov "$coverage_pct" \
|
|
275
|
+
--arg phase "$next_phase" \
|
|
276
|
+
--argjson composite "$composite_score" \
|
|
277
|
+
--argjson converged "$converged" \
|
|
278
|
+
'
|
|
279
|
+
.convergence = (.convergence // {}) |
|
|
280
|
+
.convergence.prev_findings_count = $prev_findings |
|
|
281
|
+
.convergence.prev_overall_confidence = $prev_confidence |
|
|
282
|
+
.convergence.history = ((.convergence.history // []) + [{
|
|
283
|
+
iteration: $iteration,
|
|
284
|
+
novelty_delta: $novelty,
|
|
285
|
+
confidence_delta: $conf_delta,
|
|
286
|
+
gap_resolution_pct: $gap,
|
|
287
|
+
coverage_pct: $cov,
|
|
288
|
+
phase: $phase
|
|
289
|
+
}]) |
|
|
290
|
+
.convergence.composite_score = $composite |
|
|
291
|
+
.convergence.converged = $converged
|
|
292
|
+
' "$state_file" > "$state_file.tmp" && mv "$state_file.tmp" "$state_file"
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
# Compute trust scores from plan.json source tracking
|
|
296
|
+
compute_trust_scores() {
|
|
297
|
+
local plan_file="$1"
|
|
298
|
+
|
|
299
|
+
[[ -f "$plan_file" ]] || return 0
|
|
300
|
+
|
|
301
|
+
local has_structured
|
|
302
|
+
has_structured=$(jq '
|
|
303
|
+
[.questions[].key_findings[] | type] | if length == 0 then false else any(. == "object") end
|
|
304
|
+
' "$plan_file" 2>/dev/null || echo "false")
|
|
305
|
+
|
|
306
|
+
if [[ "$has_structured" != "true" ]]; then
|
|
307
|
+
return 0
|
|
308
|
+
fi
|
|
309
|
+
|
|
310
|
+
local total_findings single_source multi_source
|
|
311
|
+
total_findings=$(jq '[.questions[].key_findings[]] | length' "$plan_file" 2>/dev/null || echo "0")
|
|
312
|
+
single_source=$(jq '[.questions[].key_findings[] | select(type == "object" and (.source_ids | length) == 1)] | length' "$plan_file" 2>/dev/null || echo "0")
|
|
313
|
+
multi_source=$(jq '[.questions[].key_findings[] | select(type == "object" and (.source_ids | length) >= 2)] | length' "$plan_file" 2>/dev/null || echo "0")
|
|
314
|
+
local no_source
|
|
315
|
+
no_source=$(jq '[.questions[].key_findings[] | select(type == "object" and ((.source_ids // []) | length) == 0)] | length' "$plan_file" 2>/dev/null || echo "0")
|
|
316
|
+
|
|
317
|
+
local trust_ratio=0
|
|
318
|
+
if [[ "$total_findings" -gt 0 ]]; then
|
|
319
|
+
trust_ratio=$(( multi_source * 100 / total_findings ))
|
|
320
|
+
fi
|
|
321
|
+
|
|
322
|
+
jq --argjson total "$total_findings" \
|
|
323
|
+
--argjson single "$single_source" \
|
|
324
|
+
--argjson multi "$multi_source" \
|
|
325
|
+
--argjson nosrc "$no_source" \
|
|
326
|
+
--argjson ratio "$trust_ratio" \
|
|
327
|
+
'.trust_summary = {
|
|
328
|
+
total_findings: $total,
|
|
329
|
+
single_source: $single,
|
|
330
|
+
multi_source: $multi,
|
|
331
|
+
no_source: $nosrc,
|
|
332
|
+
trust_ratio: $ratio
|
|
333
|
+
}' "$plan_file" > "$plan_file.tmp" && mv "$plan_file.tmp" "$plan_file"
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
# ---------------------------------------------------------------------------
|
|
337
|
+
# Determine next phase (ported from oracle.sh)
|
|
338
|
+
# ---------------------------------------------------------------------------
|
|
339
|
+
determine_next_phase() {
|
|
340
|
+
local state_file="$1"
|
|
341
|
+
local plan_file="$2"
|
|
342
|
+
|
|
343
|
+
[[ -f "$state_file" ]] || { echo "survey"; return 0; }
|
|
344
|
+
[[ -f "$plan_file" ]] || { echo "survey"; return 0; }
|
|
345
|
+
|
|
346
|
+
local total_questions touched_count avg_confidence below_50_count
|
|
347
|
+
|
|
348
|
+
total_questions=$(jq '[.questions[]] | length' "$plan_file" 2>/dev/null || echo "0")
|
|
349
|
+
if [[ "$total_questions" -eq 0 ]]; then
|
|
350
|
+
echo "survey"
|
|
351
|
+
return 0
|
|
352
|
+
fi
|
|
353
|
+
|
|
354
|
+
touched_count=$(jq '[.questions[] | select((.iterations_touched // []) | length > 0)] | length' "$plan_file" 2>/dev/null || echo "0")
|
|
355
|
+
avg_confidence=$(jq '[.questions[].confidence] | if length > 0 then (add / length) else 0 end | floor' "$plan_file" 2>/dev/null || echo "0")
|
|
356
|
+
below_50_count=$(jq '[.questions[] | select(.status != "answered" and .confidence < 50)] | length' "$plan_file" 2>/dev/null || echo "0")
|
|
357
|
+
|
|
358
|
+
if [[ "$avg_confidence" -ge 80 ]]; then
|
|
359
|
+
echo "verify"
|
|
360
|
+
return 0
|
|
361
|
+
fi
|
|
362
|
+
|
|
363
|
+
if [[ "$avg_confidence" -ge 60 ]] || [[ "$below_50_count" -lt 2 ]]; then
|
|
364
|
+
echo "synthesize"
|
|
365
|
+
return 0
|
|
366
|
+
fi
|
|
367
|
+
|
|
368
|
+
if [[ "$touched_count" -ge "$total_questions" ]] || [[ "$avg_confidence" -ge 25 ]]; then
|
|
369
|
+
echo "investigate"
|
|
370
|
+
return 0
|
|
371
|
+
fi
|
|
372
|
+
|
|
373
|
+
echo "survey"
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
# ---------------------------------------------------------------------------
|
|
377
|
+
# Phase directive generators (copied verbatim from oracle.sh)
|
|
378
|
+
# ---------------------------------------------------------------------------
|
|
379
|
+
phase_directive_survey() {
|
|
380
|
+
cat <<'DIRECTIVE'
|
|
381
|
+
## Current Phase: SURVEY
|
|
382
|
+
|
|
383
|
+
Cast a wide net -- get initial findings for every open question. Target untouched
|
|
384
|
+
questions first (those with empty iterations_touched arrays). Aim for 20-40%
|
|
385
|
+
confidence per question. List all discovered unknowns in gaps.md.
|
|
386
|
+
|
|
387
|
+
Do NOT go deep on any single question yet. Breadth over depth in this phase.
|
|
388
|
+
Your goal is to ensure every question has at least some initial findings before
|
|
389
|
+
the research moves to the investigation phase.
|
|
390
|
+
|
|
391
|
+
Source tracking is MANDATORY -- register sources and link every finding to source_ids.
|
|
392
|
+
|
|
393
|
+
---
|
|
394
|
+
|
|
395
|
+
DIRECTIVE
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
phase_directive_investigate() {
|
|
399
|
+
cat <<'DIRECTIVE'
|
|
400
|
+
## Current Phase: INVESTIGATE
|
|
401
|
+
|
|
402
|
+
Target the lowest-confidence question and go DEEP. You MUST reference existing
|
|
403
|
+
findings in synthesis.md and ADD NEW information, not restate what is already there.
|
|
404
|
+
Aim to push confidence above 70% for your target question.
|
|
405
|
+
|
|
406
|
+
Update gaps.md with specific remaining unknowns. If you find contradictions with
|
|
407
|
+
existing findings, document them explicitly. One thoroughly investigated question
|
|
408
|
+
per iteration is better than shallow passes on many.
|
|
409
|
+
|
|
410
|
+
Source tracking is MANDATORY this iteration. Every new finding must have at least one source_id.
|
|
411
|
+
|
|
412
|
+
---
|
|
413
|
+
|
|
414
|
+
DIRECTIVE
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
phase_directive_synthesize() {
|
|
418
|
+
cat <<'DIRECTIVE'
|
|
419
|
+
## Current Phase: SYNTHESIZE
|
|
420
|
+
|
|
421
|
+
Read ALL findings in synthesis.md before doing anything. Identify connections,
|
|
422
|
+
patterns, and contradictions ACROSS questions. Consolidate redundant findings.
|
|
423
|
+
Resolve contradictions with evidence. Push overall confidence toward the target.
|
|
424
|
+
|
|
425
|
+
Your job is NOT to find new information -- it is to make sense of what has already
|
|
426
|
+
been found. Cross-reference answers between questions. Strengthen weak claims
|
|
427
|
+
with evidence from other questions. Remove speculation that lacks support.
|
|
428
|
+
|
|
429
|
+
Verify source attribution is complete. Flag any findings missing source_ids.
|
|
430
|
+
|
|
431
|
+
---
|
|
432
|
+
|
|
433
|
+
DIRECTIVE
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
phase_directive_verify() {
|
|
437
|
+
cat <<'DIRECTIVE'
|
|
438
|
+
## Current Phase: VERIFY
|
|
439
|
+
|
|
440
|
+
Focus on claims in gaps.md contradictions section. Cross-reference key findings
|
|
441
|
+
with additional sources. Confirm or correct confidence scores. Mark well-supported
|
|
442
|
+
questions as answered with 90%+ confidence.
|
|
443
|
+
|
|
444
|
+
Final gaps.md should contain only genuinely unresolvable unknowns. If a contradiction
|
|
445
|
+
cannot be resolved, document both positions with evidence quality assessment.
|
|
446
|
+
This is the final quality pass before research completion.
|
|
447
|
+
|
|
448
|
+
Cross-reference source coverage. Ensure all key findings have 2+ independent sources.
|
|
449
|
+
|
|
450
|
+
---
|
|
451
|
+
|
|
452
|
+
DIRECTIVE
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
phase_directive_for() {
|
|
456
|
+
local phase="$1"
|
|
457
|
+
case "$phase" in
|
|
458
|
+
survey) phase_directive_survey ;;
|
|
459
|
+
investigate) phase_directive_investigate ;;
|
|
460
|
+
synthesize) phase_directive_synthesize ;;
|
|
461
|
+
verify) phase_directive_verify ;;
|
|
462
|
+
*) echo "## Current Phase: $phase"; echo ""; echo "---"; echo "" ;;
|
|
463
|
+
esac
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
# ---------------------------------------------------------------------------
|
|
467
|
+
# Strategy modifier (ported from oracle.sh)
|
|
468
|
+
# ---------------------------------------------------------------------------
|
|
469
|
+
strategy_modifier() {
|
|
470
|
+
local state_file="$1"
|
|
471
|
+
local strategy
|
|
472
|
+
strategy=$(jq -r '.strategy // "adaptive"' "$state_file" 2>/dev/null || echo "adaptive")
|
|
473
|
+
|
|
474
|
+
case "$strategy" in
|
|
475
|
+
breadth-first)
|
|
476
|
+
cat <<'STRATEGY'
|
|
477
|
+
|
|
478
|
+
STRATEGY NOTE: Breadth-first mode is active. Prioritize covering ALL questions
|
|
479
|
+
before going deep on any single one. Aim for broad coverage across the research
|
|
480
|
+
plan. When multiple questions are untouched, target the easiest-to-answer first
|
|
481
|
+
for maximum coverage.
|
|
482
|
+
|
|
483
|
+
STRATEGY
|
|
484
|
+
;;
|
|
485
|
+
depth-first)
|
|
486
|
+
cat <<'STRATEGY'
|
|
487
|
+
|
|
488
|
+
STRATEGY NOTE: Depth-first mode is active. Pick the single most important open
|
|
489
|
+
question and investigate it exhaustively. Push confidence to 80%+ before moving
|
|
490
|
+
to the next question. Prefer thorough, well-sourced answers over broad coverage.
|
|
491
|
+
|
|
492
|
+
STRATEGY
|
|
493
|
+
;;
|
|
494
|
+
*) ;; # adaptive: no modifier
|
|
495
|
+
esac
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
# ---------------------------------------------------------------------------
|
|
499
|
+
# Steering signals (ported from oracle.sh)
|
|
500
|
+
# ---------------------------------------------------------------------------
|
|
501
|
+
read_steering_signals() {
|
|
502
|
+
local utils="$AETHER_ROOT/.aether/aether-utils.sh"
|
|
503
|
+
|
|
504
|
+
[[ -f "$utils" ]] || return 0
|
|
505
|
+
|
|
506
|
+
local signals
|
|
507
|
+
signals=$(bash "$utils" pheromone-read 2>/dev/null || echo '{"signals":[]}')
|
|
508
|
+
|
|
509
|
+
local signal_array
|
|
510
|
+
signal_array=$(echo "$signals" | jq -c '.result.signals // .signals // []' 2>/dev/null || echo '[]')
|
|
511
|
+
|
|
512
|
+
local count
|
|
513
|
+
count=$(echo "$signal_array" | jq 'length' 2>/dev/null || echo "0")
|
|
514
|
+
|
|
515
|
+
[[ "$count" -gt 0 ]] || return 0
|
|
516
|
+
|
|
517
|
+
local directive=""
|
|
518
|
+
|
|
519
|
+
# REDIRECT (max 2)
|
|
520
|
+
local redirects
|
|
521
|
+
redirects=$(echo "$signal_array" | jq -r '
|
|
522
|
+
map(select(.type == "REDIRECT"))
|
|
523
|
+
| sort_by(-.effective_strength)
|
|
524
|
+
| .[:2]
|
|
525
|
+
| .[] | "- [" + ((.effective_strength * 100 | floor | tostring)) + "%] \"" + (.content.text // "") + "\""
|
|
526
|
+
' 2>/dev/null || echo "")
|
|
527
|
+
|
|
528
|
+
if [[ -n "$redirects" ]]; then
|
|
529
|
+
directive+="**REDIRECT (Hard constraints -- MUST follow):**"$'\n'"$redirects"$'\n\n'
|
|
530
|
+
fi
|
|
531
|
+
|
|
532
|
+
# FOCUS (max 3)
|
|
533
|
+
local focuses
|
|
534
|
+
focuses=$(echo "$signal_array" | jq -r '
|
|
535
|
+
map(select(.type == "FOCUS"))
|
|
536
|
+
| sort_by(-.effective_strength)
|
|
537
|
+
| .[:3]
|
|
538
|
+
| .[] | "- [" + ((.effective_strength * 100 | floor | tostring)) + "%] \"" + (.content.text // "") + "\""
|
|
539
|
+
' 2>/dev/null || echo "")
|
|
540
|
+
|
|
541
|
+
if [[ -n "$focuses" ]]; then
|
|
542
|
+
directive+="**FOCUS (Prioritize these areas):**"$'\n'"$focuses"$'\n\n'
|
|
543
|
+
fi
|
|
544
|
+
|
|
545
|
+
# FEEDBACK (max 2)
|
|
546
|
+
local feedbacks
|
|
547
|
+
feedbacks=$(echo "$signal_array" | jq -r '
|
|
548
|
+
map(select(.type == "FEEDBACK"))
|
|
549
|
+
| sort_by(-.effective_strength)
|
|
550
|
+
| .[:2]
|
|
551
|
+
| .[] | "- [" + ((.effective_strength * 100 | floor | tostring)) + "%] \"" + (.content.text // "") + "\""
|
|
552
|
+
' 2>/dev/null || echo "")
|
|
553
|
+
|
|
554
|
+
if [[ -n "$feedbacks" ]]; then
|
|
555
|
+
directive+="**FEEDBACK (Adjust approach):**"$'\n'"$feedbacks"$'\n\n'
|
|
556
|
+
fi
|
|
557
|
+
|
|
558
|
+
if [[ -n "$directive" ]]; then
|
|
559
|
+
echo "## Active Steering Signals"
|
|
560
|
+
echo ""
|
|
561
|
+
echo "$directive"
|
|
562
|
+
echo "When selecting your target question, PRIORITIZE questions related to FOCUS areas."
|
|
563
|
+
echo "REDIRECT signals are hard constraints -- adjust your approach to comply."
|
|
564
|
+
echo "FEEDBACK signals are suggestions -- incorporate where appropriate."
|
|
565
|
+
echo ""
|
|
566
|
+
echo "---"
|
|
567
|
+
echo ""
|
|
568
|
+
fi
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
# ---------------------------------------------------------------------------
|
|
572
|
+
# Synthesis prompt builder (ported from oracle.sh)
|
|
573
|
+
# ---------------------------------------------------------------------------
|
|
574
|
+
build_synthesis_prompt() {
|
|
575
|
+
local reason="$1"
|
|
576
|
+
local template
|
|
577
|
+
template=$(jq -r '.template // "custom"' "$STATE_FILE" 2>/dev/null || echo "custom")
|
|
578
|
+
|
|
579
|
+
cat <<SYNTHESIS_DIRECTIVE
|
|
580
|
+
## SYNTHESIS PASS (Final Report)
|
|
581
|
+
|
|
582
|
+
This is the final pass. The oracle loop has ended (reason: $reason).
|
|
583
|
+
Produce the best possible research report from the current state.
|
|
584
|
+
|
|
585
|
+
Read ALL of these files:
|
|
586
|
+
- .aether/oracle/state.json -- session metadata
|
|
587
|
+
- .aether/oracle/plan.json -- questions, findings, confidence, AND sources registry
|
|
588
|
+
- .aether/oracle/synthesis.md -- accumulated findings
|
|
589
|
+
- .aether/oracle/gaps.md -- remaining unknowns
|
|
590
|
+
|
|
591
|
+
If any state file is unreadable, skip it and work with what you have.
|
|
592
|
+
|
|
593
|
+
Then REWRITE synthesis.md as a structured final report.
|
|
594
|
+
|
|
595
|
+
SYNTHESIS_DIRECTIVE
|
|
596
|
+
|
|
597
|
+
# Template-specific sections
|
|
598
|
+
case "$template" in
|
|
599
|
+
tech-eval)
|
|
600
|
+
cat <<'TEMPLATE'
|
|
601
|
+
### Required Sections:
|
|
602
|
+
1. **Executive Summary** -- 2-3 paragraphs: what was evaluated, key conclusion, recommendation
|
|
603
|
+
2. **Comparison Matrix** -- Table comparing the evaluated technology against alternatives on key dimensions
|
|
604
|
+
3. **Pros and Cons** -- Bullet lists with evidence citations
|
|
605
|
+
4. **Adoption Assessment** -- Community size, maintenance status, release cadence
|
|
606
|
+
5. **Migration/Integration Path** -- Steps to adopt, estimated effort, risks
|
|
607
|
+
6. **Recommendation** -- Clear recommendation with confidence level
|
|
608
|
+
7. **Open Questions** -- Remaining gaps
|
|
609
|
+
8. **Sources** -- All sources with inline citations [S1], [S2] format
|
|
610
|
+
|
|
611
|
+
TEMPLATE
|
|
612
|
+
;;
|
|
613
|
+
architecture-review)
|
|
614
|
+
cat <<'TEMPLATE'
|
|
615
|
+
### Required Sections:
|
|
616
|
+
1. **Executive Summary** -- 2-3 paragraphs: system overview, key findings, critical risks
|
|
617
|
+
2. **Component Map** -- List of major components with responsibilities
|
|
618
|
+
3. **Dependency Analysis** -- How components connect, coupling assessment
|
|
619
|
+
4. **Risk Assessment** -- Single points of failure, complexity hotspots
|
|
620
|
+
5. **Scalability Analysis** -- Current capacity, growth limitations
|
|
621
|
+
6. **Improvement Recommendations** -- Prioritized list
|
|
622
|
+
7. **Open Questions** -- Remaining gaps
|
|
623
|
+
8. **Sources** -- All sources with inline citations [S1], [S2] format
|
|
624
|
+
|
|
625
|
+
TEMPLATE
|
|
626
|
+
;;
|
|
627
|
+
bug-investigation)
|
|
628
|
+
cat <<'TEMPLATE'
|
|
629
|
+
### Required Sections:
|
|
630
|
+
1. **Executive Summary** -- 1-2 paragraphs: bug description, root cause, recommended fix
|
|
631
|
+
2. **Reproduction Steps** -- Exact steps to reproduce
|
|
632
|
+
3. **Root Cause Analysis** -- What causes the bug, code paths involved
|
|
633
|
+
4. **Impact Assessment** -- Who is affected, severity
|
|
634
|
+
5. **Fix Recommendations** -- Proposed fixes ranked by safety and effort
|
|
635
|
+
6. **Related Issues** -- Similar bugs, regression risk
|
|
636
|
+
7. **Open Questions** -- Remaining gaps
|
|
637
|
+
8. **Sources** -- All sources with inline citations [S1], [S2] format
|
|
638
|
+
|
|
639
|
+
TEMPLATE
|
|
640
|
+
;;
|
|
641
|
+
best-practices)
|
|
642
|
+
cat <<'TEMPLATE'
|
|
643
|
+
### Required Sections:
|
|
644
|
+
1. **Executive Summary** -- 2-3 paragraphs: domain overview, key recommendations
|
|
645
|
+
2. **Best Practice Benchmark** -- What industry consensus considers best practice
|
|
646
|
+
3. **Current State Assessment** -- How the subject compares
|
|
647
|
+
4. **Gap Analysis** -- Specific gaps prioritized by impact
|
|
648
|
+
5. **Action Plan** -- Ordered steps to close gaps
|
|
649
|
+
6. **Open Questions** -- Remaining gaps
|
|
650
|
+
7. **Sources** -- All sources with inline citations [S1], [S2] format
|
|
651
|
+
|
|
652
|
+
TEMPLATE
|
|
653
|
+
;;
|
|
654
|
+
*)
|
|
655
|
+
cat <<'TEMPLATE'
|
|
656
|
+
### Required Sections:
|
|
657
|
+
1. **Executive Summary** -- 2-3 paragraphs summarizing what was found
|
|
658
|
+
2. **Findings by Question** -- organized by sub-question, with confidence %
|
|
659
|
+
3. **Open Questions** -- remaining gaps
|
|
660
|
+
4. **Methodology Notes** -- how many iterations, which phases completed
|
|
661
|
+
5. **Sources** -- List ALL sources from plan.json sources registry
|
|
662
|
+
|
|
663
|
+
TEMPLATE
|
|
664
|
+
;;
|
|
665
|
+
esac
|
|
666
|
+
|
|
667
|
+
# Common directives
|
|
668
|
+
cat <<'COMMON'
|
|
669
|
+
|
|
670
|
+
### Confidence Grouping:
|
|
671
|
+
Within each findings section, group findings by confidence level:
|
|
672
|
+
- **High confidence (80%+)** -- list first with full citations
|
|
673
|
+
- **Medium confidence (50-79%)** -- list with caveats
|
|
674
|
+
- **Low confidence (<50%)** -- list as tentative/unverified
|
|
675
|
+
|
|
676
|
+
Use inline citations [S1], [S2] linking findings to their sources.
|
|
677
|
+
Flag single-source findings with (single source) marker.
|
|
678
|
+
|
|
679
|
+
Also update state.json: set status to "complete" if reason is "converged",
|
|
680
|
+
or "stopped" otherwise.
|
|
681
|
+
|
|
682
|
+
COMMON
|
|
683
|
+
|
|
684
|
+
# Append the base oracle.md for tool access and rules
|
|
685
|
+
cat "$ORACLE_MD"
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
# ---------------------------------------------------------------------------
|
|
689
|
+
# Update marker file with new values
|
|
690
|
+
# ---------------------------------------------------------------------------
|
|
691
|
+
update_marker() {
|
|
692
|
+
local new_iteration="$1"
|
|
693
|
+
local new_phase="$2"
|
|
694
|
+
local new_synthesis_done="$3"
|
|
695
|
+
|
|
696
|
+
local oracle_md_body
|
|
697
|
+
oracle_md_body=$(awk '/^---$/{i++; next} i>=2' "$MARKER_FILE")
|
|
698
|
+
|
|
699
|
+
cat > "${MARKER_FILE}.tmp.$$" <<MARKER
|
|
700
|
+
---
|
|
701
|
+
iteration: $new_iteration
|
|
702
|
+
max_iterations: $MAX_ITERATIONS
|
|
703
|
+
session_id: $MARKER_SESSION_ID
|
|
704
|
+
phase: $new_phase
|
|
705
|
+
target_confidence: $TARGET_CONFIDENCE
|
|
706
|
+
synthesis_done: $new_synthesis_done
|
|
707
|
+
oracle_md_path: .aether/utils/oracle/oracle.md
|
|
708
|
+
---
|
|
709
|
+
$oracle_md_body
|
|
710
|
+
MARKER
|
|
711
|
+
mv "${MARKER_FILE}.tmp.$$" "$MARKER_FILE"
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
# ---------------------------------------------------------------------------
|
|
715
|
+
# Update state.json iteration and phase
|
|
716
|
+
# ---------------------------------------------------------------------------
|
|
717
|
+
update_state_json() {
|
|
718
|
+
local new_iteration="$1"
|
|
719
|
+
local new_phase="$2"
|
|
720
|
+
|
|
721
|
+
local ts
|
|
722
|
+
ts=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
|
|
723
|
+
|
|
724
|
+
jq --argjson iter "$new_iteration" \
|
|
725
|
+
--arg phase "$new_phase" \
|
|
726
|
+
--arg ts "$ts" \
|
|
727
|
+
'.iteration = $iter | .phase = $phase | .last_updated = $ts' \
|
|
728
|
+
"$STATE_FILE" > "$STATE_FILE.tmp" && mv "$STATE_FILE.tmp" "$STATE_FILE"
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
# ---------------------------------------------------------------------------
|
|
732
|
+
# MAIN DECISION LOGIC
|
|
733
|
+
# ---------------------------------------------------------------------------
|
|
734
|
+
|
|
735
|
+
NEXT_ITERATION=$((ITERATION + 1))
|
|
736
|
+
|
|
737
|
+
# Check completion conditions
|
|
738
|
+
IS_COMPLETE=false
|
|
739
|
+
COMPLETION_REASON=""
|
|
740
|
+
|
|
741
|
+
# 1. Max iterations reached
|
|
742
|
+
if [[ "$MAX_ITERATIONS" -gt 0 ]] && [[ "$NEXT_ITERATION" -gt "$MAX_ITERATIONS" ]]; then
|
|
743
|
+
IS_COMPLETE=true
|
|
744
|
+
COMPLETION_REASON="max_iterations"
|
|
745
|
+
fi
|
|
746
|
+
|
|
747
|
+
# 2. Confidence target met
|
|
748
|
+
if [[ "$OVERALL_CONFIDENCE" -ge "$TARGET" ]]; then
|
|
749
|
+
IS_COMPLETE=true
|
|
750
|
+
COMPLETION_REASON="${COMPLETION_REASON:-confidence_target}"
|
|
751
|
+
fi
|
|
752
|
+
|
|
753
|
+
# 3. AI signaled complete
|
|
754
|
+
if [[ "$COMPLETE_TAG_FOUND" == "true" ]]; then
|
|
755
|
+
IS_COMPLETE=true
|
|
756
|
+
COMPLETION_REASON="${COMPLETION_REASON:-ai_signal}"
|
|
757
|
+
fi
|
|
758
|
+
|
|
759
|
+
# 4. Convergence detected
|
|
760
|
+
if [[ -f "$PLAN_FILE" ]] && check_convergence "$STATE_FILE"; then
|
|
761
|
+
IS_COMPLETE=true
|
|
762
|
+
COMPLETION_REASON="${COMPLETION_REASON:-convergence}"
|
|
763
|
+
fi
|
|
764
|
+
|
|
765
|
+
# Handle synthesis pass
|
|
766
|
+
if [[ "$IS_COMPLETE" == "true" ]]; then
|
|
767
|
+
if [[ "$SYNTHESIS_DONE" == "true" ]]; then
|
|
768
|
+
# Research complete AND synthesis done -- allow stop
|
|
769
|
+
rm -f "$MARKER_FILE"
|
|
770
|
+
|
|
771
|
+
# Update state.json status
|
|
772
|
+
local final_status
|
|
773
|
+
case "$COMPLETION_REASON" in
|
|
774
|
+
max_iterations) final_status="stopped" ;;
|
|
775
|
+
convergence|confidence_target|ai_signal) final_status="complete" ;;
|
|
776
|
+
*) final_status="stopped" ;;
|
|
777
|
+
esac
|
|
778
|
+
jq --arg status "$final_status" --arg reason "$COMPLETION_REASON" \
|
|
779
|
+
'.status = $status | .stop_reason = $reason' \
|
|
780
|
+
"$STATE_FILE" > "$STATE_FILE.tmp" && mv "$STATE_FILE.tmp" "$STATE_FILE"
|
|
781
|
+
|
|
782
|
+
# Allow exit
|
|
783
|
+
exit 0
|
|
784
|
+
fi
|
|
785
|
+
|
|
786
|
+
# Complete but no synthesis yet -- trigger synthesis pass
|
|
787
|
+
update_marker "$NEXT_ITERATION" "synthesis-pass" "true"
|
|
788
|
+
update_state_json "$NEXT_ITERATION" "synthesis-pass"
|
|
789
|
+
|
|
790
|
+
# Build synthesis prompt
|
|
791
|
+
SYNTHESIS_PROMPT=$(build_synthesis_prompt "$COMPLETION_REASON")
|
|
792
|
+
|
|
793
|
+
SYSTEM_MSG="Oracle iteration $NEXT_ITERATION (SYNTHESIS PASS) -- Final report generation"
|
|
794
|
+
|
|
795
|
+
jq -n \
|
|
796
|
+
--arg prompt "$SYNTHESIS_PROMPT" \
|
|
797
|
+
--arg msg "$SYSTEM_MSG" \
|
|
798
|
+
'{
|
|
799
|
+
"decision": "block",
|
|
800
|
+
"reason": $prompt,
|
|
801
|
+
"systemMessage": $msg
|
|
802
|
+
}'
|
|
803
|
+
|
|
804
|
+
exit 0
|
|
805
|
+
fi
|
|
806
|
+
|
|
807
|
+
# ---------------------------------------------------------------------------
|
|
808
|
+
# NOT COMPLETE -- continue research loop
|
|
809
|
+
# ---------------------------------------------------------------------------
|
|
810
|
+
|
|
811
|
+
# Determine next phase from plan.json metrics
|
|
812
|
+
NEXT_PHASE=$(determine_next_phase "$STATE_FILE" "$PLAN_FILE")
|
|
813
|
+
|
|
814
|
+
# Check diminishing returns -- may force phase advancement
|
|
815
|
+
if [[ -f "$PLAN_FILE" ]]; then
|
|
816
|
+
DR_RESULT=$(detect_diminishing_returns "$STATE_FILE")
|
|
817
|
+
case "$DR_RESULT" in
|
|
818
|
+
strategy_change)
|
|
819
|
+
# Force synthesize phase
|
|
820
|
+
NEXT_PHASE="synthesize"
|
|
821
|
+
;;
|
|
822
|
+
synthesize_now)
|
|
823
|
+
# Force early synthesis completion
|
|
824
|
+
NEXT_PHASE="verify"
|
|
825
|
+
;;
|
|
826
|
+
esac
|
|
827
|
+
fi
|
|
828
|
+
|
|
829
|
+
# Update convergence metrics (reads plan.json, writes state.json)
|
|
830
|
+
if [[ -f "$PLAN_FILE" ]]; then
|
|
831
|
+
update_convergence_metrics "$STATE_FILE" "$PLAN_FILE" "$NEXT_ITERATION" "$NEXT_PHASE"
|
|
832
|
+
compute_trust_scores "$PLAN_FILE"
|
|
833
|
+
fi
|
|
834
|
+
|
|
835
|
+
# Update state files
|
|
836
|
+
update_marker "$NEXT_ITERATION" "$NEXT_PHASE" "$SYNTHESIS_DONE"
|
|
837
|
+
update_state_json "$NEXT_ITERATION" "$NEXT_PHASE"
|
|
838
|
+
|
|
839
|
+
# Generate research-plan.md summary
|
|
840
|
+
if [[ -f "$PLAN_FILE" ]]; then
|
|
841
|
+
{
|
|
842
|
+
echo "# Research Plan"
|
|
843
|
+
echo ""
|
|
844
|
+
local_topic=$(jq -r '.topic // "unknown"' "$STATE_FILE" 2>/dev/null || echo "unknown")
|
|
845
|
+
local_conf=$(jq '.overall_confidence // 0' "$STATE_FILE" 2>/dev/null || echo "0")
|
|
846
|
+
echo "**Topic:** $local_topic"
|
|
847
|
+
echo "**Status:** active | **Iteration:** $NEXT_ITERATION of $MAX_ITERATIONS"
|
|
848
|
+
echo "**Overall Confidence:** ${local_conf}%"
|
|
849
|
+
echo ""
|
|
850
|
+
echo "## Questions"
|
|
851
|
+
echo "| # | Question | Status | Confidence |"
|
|
852
|
+
echo "|---|----------|--------|------------|"
|
|
853
|
+
jq -r '.questions[] | "| \(.id) | \(.text) | \(.status) | \(.confidence)% |"' "$PLAN_FILE" 2>/dev/null || true
|
|
854
|
+
echo ""
|
|
855
|
+
echo "## Next Steps"
|
|
856
|
+
local_next
|
|
857
|
+
local_next=$(jq -r '[.questions[] | select(.status != "answered")] | sort_by(.confidence) | first | .text // "All questions answered"' "$PLAN_FILE" 2>/dev/null || echo "Continue research")
|
|
858
|
+
echo "Next investigation: $local_next"
|
|
859
|
+
echo ""
|
|
860
|
+
echo "---"
|
|
861
|
+
echo "*Generated from plan.json -- do not edit directly*"
|
|
862
|
+
} > "$ORACLE_DIR/research-plan.md"
|
|
863
|
+
fi
|
|
864
|
+
|
|
865
|
+
# Build the full iteration prompt
|
|
866
|
+
FULL_PROMPT=""
|
|
867
|
+
|
|
868
|
+
# Phase directive
|
|
869
|
+
FULL_PROMPT+=$(phase_directive_for "$NEXT_PHASE")
|
|
870
|
+
|
|
871
|
+
# Strategy modifier
|
|
872
|
+
FULL_PROMPT+=$(strategy_modifier "$STATE_FILE")
|
|
873
|
+
|
|
874
|
+
# Steering signals
|
|
875
|
+
STEERING=$(read_steering_signals "$AETHER_ROOT")
|
|
876
|
+
if [[ -n "$STEERING" ]]; then
|
|
877
|
+
FULL_PROMPT+="$STEERING"
|
|
878
|
+
fi
|
|
879
|
+
|
|
880
|
+
# Base oracle.md prompt
|
|
881
|
+
if [[ -f "$ORACLE_MD" ]]; then
|
|
882
|
+
FULL_PROMPT+=$(cat "$ORACLE_MD")
|
|
883
|
+
fi
|
|
884
|
+
|
|
885
|
+
SYSTEM_MSG="Oracle iteration $NEXT_ITERATION ($NEXT_PHASE phase) | Confidence: ${OVERALL_CONFIDENCE}% / ${TARGET}% | Iterations remaining: $((MAX_ITERATIONS - NEXT_ITERATION))"
|
|
886
|
+
|
|
887
|
+
jq -n \
|
|
888
|
+
--arg prompt "$FULL_PROMPT" \
|
|
889
|
+
--arg msg "$SYSTEM_MSG" \
|
|
890
|
+
'{
|
|
891
|
+
"decision": "block",
|
|
892
|
+
"reason": $prompt,
|
|
893
|
+
"systemMessage": $msg
|
|
894
|
+
}'
|
|
895
|
+
|
|
896
|
+
exit 0
|