aether-colony 1.1.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/CONTEXT.md +160 -0
- package/.aether/QUEEN.md +84 -0
- package/.aether/aether-utils.sh +7749 -0
- package/.aether/docs/QUEEN-SYSTEM.md +211 -0
- package/.aether/docs/README.md +68 -0
- package/.aether/docs/caste-system.md +48 -0
- package/.aether/docs/disciplines/DISCIPLINES.md +93 -0
- package/.aether/docs/disciplines/coding-standards.md +197 -0
- package/.aether/docs/disciplines/debugging.md +207 -0
- package/.aether/docs/disciplines/learning.md +254 -0
- package/.aether/docs/disciplines/tdd.md +257 -0
- package/.aether/docs/disciplines/verification-loop.md +167 -0
- package/.aether/docs/disciplines/verification.md +116 -0
- package/.aether/docs/error-codes.md +268 -0
- package/.aether/docs/known-issues.md +233 -0
- package/.aether/docs/pheromones.md +205 -0
- package/.aether/docs/queen-commands.md +97 -0
- package/.aether/exchange/colony-registry.xml +11 -0
- package/.aether/exchange/pheromone-xml.sh +575 -0
- package/.aether/exchange/pheromones.xml +87 -0
- package/.aether/exchange/queen-wisdom.xml +14 -0
- package/.aether/exchange/registry-xml.sh +273 -0
- package/.aether/exchange/wisdom-xml.sh +319 -0
- package/.aether/midden/approach-changes.md +5 -0
- package/.aether/midden/build-failures.md +5 -0
- package/.aether/midden/test-failures.md +5 -0
- package/.aether/model-profiles.yaml +100 -0
- package/.aether/rules/aether-colony.md +134 -0
- package/.aether/schemas/aether-types.xsd +255 -0
- package/.aether/schemas/colony-registry.xsd +309 -0
- package/.aether/schemas/example-prompt-builder.xml +234 -0
- package/.aether/schemas/pheromone.xsd +163 -0
- package/.aether/schemas/prompt.xsd +416 -0
- package/.aether/schemas/queen-wisdom.xsd +325 -0
- package/.aether/schemas/worker-priming.xsd +276 -0
- package/.aether/templates/QUEEN.md.template +79 -0
- package/.aether/templates/colony-state-reset.jq.template +22 -0
- package/.aether/templates/colony-state.template.json +35 -0
- package/.aether/templates/constraints.template.json +9 -0
- package/.aether/templates/crowned-anthill.template.md +36 -0
- package/.aether/templates/handoff-build-error.template.md +30 -0
- package/.aether/templates/handoff-build-success.template.md +39 -0
- package/.aether/templates/handoff.template.md +40 -0
- package/.aether/templates/learning-observations.template.json +6 -0
- package/.aether/templates/midden.template.json +7 -0
- package/.aether/templates/pheromones.template.json +6 -0
- package/.aether/templates/session.template.json +9 -0
- package/.aether/utils/atomic-write.sh +219 -0
- package/.aether/utils/chamber-compare.sh +193 -0
- package/.aether/utils/chamber-utils.sh +297 -0
- package/.aether/utils/colorize-log.sh +132 -0
- package/.aether/utils/error-handler.sh +212 -0
- package/.aether/utils/file-lock.sh +158 -0
- package/.aether/utils/queen-to-md.xsl +395 -0
- package/.aether/utils/semantic-cli.sh +413 -0
- package/.aether/utils/spawn-tree.sh +428 -0
- package/.aether/utils/spawn-with-model.sh +56 -0
- package/.aether/utils/state-loader.sh +215 -0
- package/.aether/utils/swarm-display.sh +268 -0
- package/.aether/utils/watch-spawn-tree.sh +253 -0
- package/.aether/utils/xml-compose.sh +253 -0
- package/.aether/utils/xml-convert.sh +273 -0
- package/.aether/utils/xml-core.sh +186 -0
- package/.aether/utils/xml-query.sh +201 -0
- package/.aether/utils/xml-utils.sh +110 -0
- package/.aether/workers.md +765 -0
- package/.claude/agents/ant/aether-ambassador.md +264 -0
- package/.claude/agents/ant/aether-archaeologist.md +322 -0
- package/.claude/agents/ant/aether-auditor.md +266 -0
- package/.claude/agents/ant/aether-builder.md +187 -0
- package/.claude/agents/ant/aether-chaos.md +268 -0
- package/.claude/agents/ant/aether-chronicler.md +304 -0
- package/.claude/agents/ant/aether-gatekeeper.md +325 -0
- package/.claude/agents/ant/aether-includer.md +373 -0
- package/.claude/agents/ant/aether-keeper.md +271 -0
- package/.claude/agents/ant/aether-measurer.md +317 -0
- package/.claude/agents/ant/aether-probe.md +210 -0
- package/.claude/agents/ant/aether-queen.md +325 -0
- package/.claude/agents/ant/aether-route-setter.md +173 -0
- package/.claude/agents/ant/aether-sage.md +353 -0
- package/.claude/agents/ant/aether-scout.md +142 -0
- package/.claude/agents/ant/aether-surveyor-disciplines.md +416 -0
- package/.claude/agents/ant/aether-surveyor-nest.md +354 -0
- package/.claude/agents/ant/aether-surveyor-pathogens.md +288 -0
- package/.claude/agents/ant/aether-surveyor-provisions.md +359 -0
- package/.claude/agents/ant/aether-tracker.md +265 -0
- package/.claude/agents/ant/aether-watcher.md +244 -0
- package/.claude/agents/ant/aether-weaver.md +247 -0
- package/.claude/commands/ant/archaeology.md +341 -0
- package/.claude/commands/ant/build.md +1160 -0
- package/.claude/commands/ant/chaos.md +349 -0
- package/.claude/commands/ant/colonize.md +270 -0
- package/.claude/commands/ant/continue.md +1070 -0
- package/.claude/commands/ant/council.md +309 -0
- package/.claude/commands/ant/dream.md +265 -0
- package/.claude/commands/ant/entomb.md +487 -0
- package/.claude/commands/ant/feedback.md +78 -0
- package/.claude/commands/ant/flag.md +139 -0
- package/.claude/commands/ant/flags.md +155 -0
- package/.claude/commands/ant/focus.md +58 -0
- package/.claude/commands/ant/help.md +122 -0
- package/.claude/commands/ant/history.md +137 -0
- package/.claude/commands/ant/init.md +409 -0
- package/.claude/commands/ant/interpret.md +267 -0
- package/.claude/commands/ant/lay-eggs.md +201 -0
- package/.claude/commands/ant/maturity.md +102 -0
- package/.claude/commands/ant/memory-details.md +77 -0
- package/.claude/commands/ant/migrate-state.md +165 -0
- package/.claude/commands/ant/oracle.md +387 -0
- package/.claude/commands/ant/organize.md +227 -0
- package/.claude/commands/ant/pause-colony.md +247 -0
- package/.claude/commands/ant/phase.md +126 -0
- package/.claude/commands/ant/plan.md +544 -0
- package/.claude/commands/ant/redirect.md +58 -0
- package/.claude/commands/ant/resume-colony.md +182 -0
- package/.claude/commands/ant/resume.md +363 -0
- package/.claude/commands/ant/seal.md +306 -0
- package/.claude/commands/ant/status.md +272 -0
- package/.claude/commands/ant/swarm.md +361 -0
- package/.claude/commands/ant/tunnels.md +425 -0
- package/.claude/commands/ant/update.md +209 -0
- package/.claude/commands/ant/verify-castes.md +95 -0
- package/.claude/commands/ant/watch.md +238 -0
- package/.opencode/agents/aether-ambassador.md +140 -0
- package/.opencode/agents/aether-archaeologist.md +108 -0
- package/.opencode/agents/aether-auditor.md +144 -0
- package/.opencode/agents/aether-builder.md +184 -0
- package/.opencode/agents/aether-chaos.md +115 -0
- package/.opencode/agents/aether-chronicler.md +122 -0
- package/.opencode/agents/aether-gatekeeper.md +116 -0
- package/.opencode/agents/aether-includer.md +117 -0
- package/.opencode/agents/aether-keeper.md +177 -0
- package/.opencode/agents/aether-measurer.md +128 -0
- package/.opencode/agents/aether-probe.md +133 -0
- package/.opencode/agents/aether-queen.md +286 -0
- package/.opencode/agents/aether-route-setter.md +130 -0
- package/.opencode/agents/aether-sage.md +106 -0
- package/.opencode/agents/aether-scout.md +101 -0
- package/.opencode/agents/aether-surveyor-disciplines.md +386 -0
- package/.opencode/agents/aether-surveyor-nest.md +324 -0
- package/.opencode/agents/aether-surveyor-pathogens.md +259 -0
- package/.opencode/agents/aether-surveyor-provisions.md +329 -0
- package/.opencode/agents/aether-tracker.md +137 -0
- package/.opencode/agents/aether-watcher.md +174 -0
- package/.opencode/agents/aether-weaver.md +130 -0
- package/.opencode/commands/ant/archaeology.md +338 -0
- package/.opencode/commands/ant/build.md +1200 -0
- package/.opencode/commands/ant/chaos.md +346 -0
- package/.opencode/commands/ant/colonize.md +202 -0
- package/.opencode/commands/ant/continue.md +938 -0
- package/.opencode/commands/ant/council.md +305 -0
- package/.opencode/commands/ant/dream.md +262 -0
- package/.opencode/commands/ant/entomb.md +367 -0
- package/.opencode/commands/ant/feedback.md +80 -0
- package/.opencode/commands/ant/flag.md +137 -0
- package/.opencode/commands/ant/flags.md +153 -0
- package/.opencode/commands/ant/focus.md +56 -0
- package/.opencode/commands/ant/help.md +124 -0
- package/.opencode/commands/ant/history.md +127 -0
- package/.opencode/commands/ant/init.md +337 -0
- package/.opencode/commands/ant/interpret.md +256 -0
- package/.opencode/commands/ant/lay-eggs.md +141 -0
- package/.opencode/commands/ant/maturity.md +92 -0
- package/.opencode/commands/ant/memory-details.md +77 -0
- package/.opencode/commands/ant/migrate-state.md +153 -0
- package/.opencode/commands/ant/oracle.md +338 -0
- package/.opencode/commands/ant/organize.md +224 -0
- package/.opencode/commands/ant/pause-colony.md +220 -0
- package/.opencode/commands/ant/phase.md +123 -0
- package/.opencode/commands/ant/plan.md +531 -0
- package/.opencode/commands/ant/redirect.md +67 -0
- package/.opencode/commands/ant/resume-colony.md +178 -0
- package/.opencode/commands/ant/resume.md +363 -0
- package/.opencode/commands/ant/seal.md +247 -0
- package/.opencode/commands/ant/status.md +272 -0
- package/.opencode/commands/ant/swarm.md +357 -0
- package/.opencode/commands/ant/tunnels.md +406 -0
- package/.opencode/commands/ant/update.md +191 -0
- package/.opencode/commands/ant/verify-castes.md +85 -0
- package/.opencode/commands/ant/watch.md +220 -0
- package/.opencode/opencode.json +3 -0
- package/CHANGELOG.md +325 -0
- package/DISCLAIMER.md +74 -0
- package/LICENSE +21 -0
- package/README.md +258 -0
- package/bin/cli.js +2436 -0
- package/bin/generate-commands.sh +291 -0
- package/bin/lib/caste-colors.js +57 -0
- package/bin/lib/colors.js +76 -0
- package/bin/lib/errors.js +255 -0
- package/bin/lib/event-types.js +190 -0
- package/bin/lib/file-lock.js +695 -0
- package/bin/lib/init.js +454 -0
- package/bin/lib/logger.js +242 -0
- package/bin/lib/model-profiles.js +445 -0
- package/bin/lib/model-verify.js +288 -0
- package/bin/lib/nestmate-loader.js +130 -0
- package/bin/lib/proxy-health.js +253 -0
- package/bin/lib/spawn-logger.js +266 -0
- package/bin/lib/state-guard.js +602 -0
- package/bin/lib/state-sync.js +516 -0
- package/bin/lib/telemetry.js +441 -0
- package/bin/lib/update-transaction.js +1454 -0
- package/bin/npx-install.js +178 -0
- package/bin/sync-to-runtime.sh +6 -0
- package/bin/validate-package.sh +88 -0
- package/package.json +70 -0
|
@@ -0,0 +1,413 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Semantic CLI - Shell interface to Python semantic layer
|
|
3
|
+
#
|
|
4
|
+
# Provides semantic search and indexing capabilities for Aether colony.
|
|
5
|
+
# Uses Python semantic_layer.py for embeddings and similarity search.
|
|
6
|
+
#
|
|
7
|
+
# Usage:
|
|
8
|
+
# source .aether/utils/semantic-cli.sh
|
|
9
|
+
# semantic-init # Initialize semantic store
|
|
10
|
+
# semantic-index "text" # Add text to index
|
|
11
|
+
# semantic-search "query" # Find similar entries
|
|
12
|
+
# semantic-rebuild # Rebuild from all sources
|
|
13
|
+
|
|
14
|
+
# Only set strict mode when executed directly, not when sourced
|
|
15
|
+
if [[ "${BASH_SOURCE[0]:-$0}" == "${0}" ]]; then
|
|
16
|
+
set -euo pipefail
|
|
17
|
+
fi
|
|
18
|
+
|
|
19
|
+
# Get script directory for relative paths
|
|
20
|
+
# Fallback for when BASH_SOURCE isn't set (non-interactive sourcing)
|
|
21
|
+
if [[ -n "${BASH_SOURCE[0]:-}" ]]; then
|
|
22
|
+
SEMANTIC_CLI_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
23
|
+
else
|
|
24
|
+
# Try to find .aether directory from current location
|
|
25
|
+
if [[ -d ".aether" ]]; then
|
|
26
|
+
SEMANTIC_CLI_DIR="$(pwd)/.aether/utils"
|
|
27
|
+
elif [[ -d "../.aether" ]]; then
|
|
28
|
+
SEMANTIC_CLI_DIR="$(cd .. && pwd)/.aether/utils"
|
|
29
|
+
else
|
|
30
|
+
# Last resort - use aether-utils.sh's detected AETHER_DIR if available
|
|
31
|
+
SEMANTIC_CLI_DIR="${AETHER_DIR:-$HOME/.aether/system}/utils"
|
|
32
|
+
fi
|
|
33
|
+
fi
|
|
34
|
+
AETHER_DIR="$(dirname "$SEMANTIC_CLI_DIR")"
|
|
35
|
+
PROJECT_ROOT="$(dirname "$AETHER_DIR")"
|
|
36
|
+
|
|
37
|
+
# Data directory for semantic store
|
|
38
|
+
SEMANTIC_DATA_DIR="${AETHER_DIR}/data/semantic"
|
|
39
|
+
SEMANTIC_EMBEDDINGS_FILE="${SEMANTIC_DATA_DIR}/embeddings.json"
|
|
40
|
+
|
|
41
|
+
# Check if Python dependencies are available
|
|
42
|
+
semantic-check-deps() {
|
|
43
|
+
python3 -c "import sys; sys.path.insert(0, '$AETHER_DIR'); from semantic_layer import EmbeddingModel; print('ok')" 2>/dev/null
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
# Initialize semantic store directory
|
|
47
|
+
semantic-init() {
|
|
48
|
+
mkdir -p "$SEMANTIC_DATA_DIR"
|
|
49
|
+
|
|
50
|
+
if [[ ! -f "$SEMANTIC_DATA_DIR/index.json" ]]; then
|
|
51
|
+
cat > "$SEMANTIC_DATA_DIR/index.json" << 'EOF'
|
|
52
|
+
{
|
|
53
|
+
"version": "1.0",
|
|
54
|
+
"entries": [],
|
|
55
|
+
"last_updated": null,
|
|
56
|
+
"stats": {
|
|
57
|
+
"total_entries": 0,
|
|
58
|
+
"by_source": {}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
EOF
|
|
62
|
+
fi
|
|
63
|
+
|
|
64
|
+
if [[ ! -f "$SEMANTIC_EMBEDDINGS_FILE" ]]; then
|
|
65
|
+
echo '{"embeddings":{}}' > "$SEMANTIC_EMBEDDINGS_FILE"
|
|
66
|
+
fi
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
# Index a single text entry
|
|
70
|
+
# Usage: semantic-index <text> <source> [entry_id]
|
|
71
|
+
semantic-index() {
|
|
72
|
+
local text="${1:-}"
|
|
73
|
+
local source="${2:-unknown}"
|
|
74
|
+
local entry_id="${3:-}"
|
|
75
|
+
|
|
76
|
+
if [[ -z "$text" ]]; then
|
|
77
|
+
json_err 1 "semantic-index requires text argument"
|
|
78
|
+
return 1
|
|
79
|
+
fi
|
|
80
|
+
|
|
81
|
+
semantic-init
|
|
82
|
+
|
|
83
|
+
# Generate entry ID if not provided
|
|
84
|
+
if [[ -z "$entry_id" ]]; then
|
|
85
|
+
entry_id="${source}_$(date +%s)_$((RANDOM % 10000))"
|
|
86
|
+
fi
|
|
87
|
+
|
|
88
|
+
local timestamp
|
|
89
|
+
timestamp=$(date -u +%Y-%m-%dT%H:%M:%SZ)
|
|
90
|
+
|
|
91
|
+
# Call Python to compute embedding and save everything
|
|
92
|
+
python3 << PYTHON_SCRIPT 2>/dev/null
|
|
93
|
+
import sys
|
|
94
|
+
import json
|
|
95
|
+
sys.path.insert(0, '$AETHER_DIR')
|
|
96
|
+
from semantic_layer import EmbeddingModel
|
|
97
|
+
|
|
98
|
+
# Compute embedding
|
|
99
|
+
model = EmbeddingModel()
|
|
100
|
+
embedding = model.encode('''$text''')
|
|
101
|
+
|
|
102
|
+
# Load existing embeddings
|
|
103
|
+
try:
|
|
104
|
+
with open('$SEMANTIC_EMBEDDINGS_FILE', 'r') as f:
|
|
105
|
+
emb_store = json.load(f)
|
|
106
|
+
except:
|
|
107
|
+
emb_store = {'embeddings': {}}
|
|
108
|
+
|
|
109
|
+
# Store embedding
|
|
110
|
+
emb_store['embeddings']['$entry_id'] = {
|
|
111
|
+
'embedding': embedding,
|
|
112
|
+
'text': '''$text''',
|
|
113
|
+
'source': '$source',
|
|
114
|
+
'indexed_at': '$timestamp'
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
# Save embeddings
|
|
118
|
+
with open('$SEMANTIC_EMBEDDINGS_FILE', 'w') as f:
|
|
119
|
+
json.dump(emb_store, f)
|
|
120
|
+
|
|
121
|
+
# Update index
|
|
122
|
+
try:
|
|
123
|
+
with open('$SEMANTIC_DATA_DIR/index.json', 'r') as f:
|
|
124
|
+
index = json.load(f)
|
|
125
|
+
except:
|
|
126
|
+
index = {'version': '1.0', 'entries': [], 'stats': {}}
|
|
127
|
+
|
|
128
|
+
index['entries'].append({
|
|
129
|
+
'id': '$entry_id',
|
|
130
|
+
'source': '$source',
|
|
131
|
+
'text_preview': '''${text:0:200}''',
|
|
132
|
+
'indexed_at': '$timestamp'
|
|
133
|
+
})
|
|
134
|
+
index['last_updated'] = '$timestamp'
|
|
135
|
+
index['stats']['total_entries'] = len(index['entries'])
|
|
136
|
+
|
|
137
|
+
by_source = {}
|
|
138
|
+
for e in index['entries']:
|
|
139
|
+
src = e.get('source', 'unknown')
|
|
140
|
+
by_source[src] = by_source.get(src, 0) + 1
|
|
141
|
+
index['stats']['by_source'] = by_source
|
|
142
|
+
|
|
143
|
+
with open('$SEMANTIC_DATA_DIR/index.json', 'w') as f:
|
|
144
|
+
json.dump(index, f, indent=2)
|
|
145
|
+
|
|
146
|
+
print(json.dumps({
|
|
147
|
+
'ok': True,
|
|
148
|
+
'entry_id': '$entry_id',
|
|
149
|
+
'embedding_dim': len(embedding),
|
|
150
|
+
'source': '$source'
|
|
151
|
+
}))
|
|
152
|
+
PYTHON_SCRIPT
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
# Search for similar entries
|
|
156
|
+
# Usage: semantic-search <query> [top_k] [threshold] [source_filter]
|
|
157
|
+
semantic-search() {
|
|
158
|
+
local query="${1:-}"
|
|
159
|
+
local top_k="${2:-5}"
|
|
160
|
+
local threshold="${3:-0.5}"
|
|
161
|
+
local source_filter="${4:-}"
|
|
162
|
+
|
|
163
|
+
if [[ -z "$query" ]]; then
|
|
164
|
+
json_err 1 "semantic-search requires query argument"
|
|
165
|
+
return 1
|
|
166
|
+
fi
|
|
167
|
+
|
|
168
|
+
if [[ ! -f "$SEMANTIC_EMBEDDINGS_FILE" ]]; then
|
|
169
|
+
json_ok '{"results":[]}' "No semantic index found. Run semantic-init first."
|
|
170
|
+
return 0
|
|
171
|
+
fi
|
|
172
|
+
|
|
173
|
+
# Call Python to search
|
|
174
|
+
python3 << PYTHON_SCRIPT 2>/dev/null
|
|
175
|
+
import sys
|
|
176
|
+
import json
|
|
177
|
+
import math
|
|
178
|
+
sys.path.insert(0, '$AETHER_DIR')
|
|
179
|
+
from semantic_layer import EmbeddingModel
|
|
180
|
+
|
|
181
|
+
def cosine_similarity(v1, v2):
|
|
182
|
+
dot = sum(a*b for a,b in zip(v1, v2))
|
|
183
|
+
norm1 = math.sqrt(sum(a*a for a in v1))
|
|
184
|
+
norm2 = math.sqrt(sum(b*b for b in v2))
|
|
185
|
+
if norm1 == 0 or norm2 == 0:
|
|
186
|
+
return 0.0
|
|
187
|
+
return dot / (norm1 * norm2)
|
|
188
|
+
|
|
189
|
+
# Compute query embedding
|
|
190
|
+
model = EmbeddingModel()
|
|
191
|
+
query_emb = model.encode('''$query''')
|
|
192
|
+
|
|
193
|
+
# Load stored embeddings
|
|
194
|
+
with open('$SEMANTIC_EMBEDDINGS_FILE', 'r') as f:
|
|
195
|
+
emb_store = json.load(f)
|
|
196
|
+
|
|
197
|
+
# Search
|
|
198
|
+
results = []
|
|
199
|
+
for entry_id, data in emb_store.get('embeddings', {}).items():
|
|
200
|
+
# Source filter
|
|
201
|
+
source = data.get('source', '')
|
|
202
|
+
if '$source_filter' and source != '$source_filter':
|
|
203
|
+
continue
|
|
204
|
+
|
|
205
|
+
stored_emb = data.get('embedding', [])
|
|
206
|
+
if not stored_emb:
|
|
207
|
+
continue
|
|
208
|
+
|
|
209
|
+
similarity = cosine_similarity(query_emb, stored_emb)
|
|
210
|
+
|
|
211
|
+
if similarity >= $threshold:
|
|
212
|
+
results.append({
|
|
213
|
+
'id': entry_id,
|
|
214
|
+
'text': data.get('text', ''),
|
|
215
|
+
'source': source,
|
|
216
|
+
'similarity': round(similarity, 3),
|
|
217
|
+
'indexed_at': data.get('indexed_at', '')
|
|
218
|
+
})
|
|
219
|
+
|
|
220
|
+
# Sort by similarity
|
|
221
|
+
results.sort(key=lambda x: x['similarity'], reverse=True)
|
|
222
|
+
results = results[:$top_k]
|
|
223
|
+
|
|
224
|
+
print(json.dumps({
|
|
225
|
+
'ok': True,
|
|
226
|
+
'query': '''$query''',
|
|
227
|
+
'count': len(results),
|
|
228
|
+
'results': results
|
|
229
|
+
}))
|
|
230
|
+
PYTHON_SCRIPT
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
# Find similar entries to check for duplicates
|
|
234
|
+
semantic-find-duplicate() {
|
|
235
|
+
local text="${1:-}"
|
|
236
|
+
local threshold="${2:-0.85}"
|
|
237
|
+
|
|
238
|
+
if [[ -z "$text" ]]; then
|
|
239
|
+
json_err 1 "semantic-find-duplicate requires text argument"
|
|
240
|
+
return 1
|
|
241
|
+
fi
|
|
242
|
+
|
|
243
|
+
local result
|
|
244
|
+
result=$(semantic-search "$text" 3 "$threshold")
|
|
245
|
+
|
|
246
|
+
local count
|
|
247
|
+
count=$(echo "$result" | jq -r '.count // 0')
|
|
248
|
+
|
|
249
|
+
if [[ "$count" -gt 0 ]]; then
|
|
250
|
+
echo "$result" | jq '. + {"is_duplicate": true}'
|
|
251
|
+
else
|
|
252
|
+
json_ok "[]" "No duplicates found"
|
|
253
|
+
fi
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
# Rebuild entire index from all Aether data sources
|
|
257
|
+
semantic-rebuild() {
|
|
258
|
+
echo "Rebuilding semantic index from all sources..."
|
|
259
|
+
|
|
260
|
+
# Reset
|
|
261
|
+
rm -rf "$SEMANTIC_DATA_DIR"/*
|
|
262
|
+
semantic-init
|
|
263
|
+
|
|
264
|
+
local count=0
|
|
265
|
+
|
|
266
|
+
# Index flags
|
|
267
|
+
if [[ -f "$AETHER_DIR/data/flags.json" ]]; then
|
|
268
|
+
echo " Indexing flags..."
|
|
269
|
+
local flags_json
|
|
270
|
+
flags_json=$(jq -c '.flags[]' "$AETHER_DIR/data/flags.json" 2>/dev/null || echo "")
|
|
271
|
+
|
|
272
|
+
while IFS= read -r flag; do
|
|
273
|
+
[[ -z "$flag" ]] && continue
|
|
274
|
+
local flag_id flag_title flag_desc
|
|
275
|
+
flag_id=$(echo "$flag" | jq -r '.id // empty')
|
|
276
|
+
flag_title=$(echo "$flag" | jq -r '.title // empty')
|
|
277
|
+
flag_desc=$(echo "$flag" | jq -r '.description // empty')
|
|
278
|
+
|
|
279
|
+
if [[ -n "$flag_title" ]]; then
|
|
280
|
+
semantic-index "$flag_title: $flag_desc" "flags" "$flag_id" >/dev/null 2>&1 || true
|
|
281
|
+
((count++)) || true
|
|
282
|
+
fi
|
|
283
|
+
done <<< "$flags_json"
|
|
284
|
+
fi
|
|
285
|
+
|
|
286
|
+
# Index dreams
|
|
287
|
+
if [[ -d "$AETHER_DIR/dreams" ]]; then
|
|
288
|
+
echo " Indexing dreams..."
|
|
289
|
+
for dream in "$AETHER_DIR/dreams"/*.md; do
|
|
290
|
+
[[ -f "$dream" ]] || continue
|
|
291
|
+
local dream_id dream_content
|
|
292
|
+
dream_id=$(basename "$dream" .md)
|
|
293
|
+
dream_content=$(head -100 "$dream" | tr '\n' ' ')
|
|
294
|
+
|
|
295
|
+
if [[ -n "$dream_content" ]]; then
|
|
296
|
+
semantic-index "$dream_content" "dreams" "$dream_id" >/dev/null 2>&1 || true
|
|
297
|
+
((count++)) || true
|
|
298
|
+
fi
|
|
299
|
+
done
|
|
300
|
+
fi
|
|
301
|
+
|
|
302
|
+
# Index pheromones
|
|
303
|
+
if [[ -f "$AETHER_DIR/data/pheromones.json" ]]; then
|
|
304
|
+
echo " Indexing pheromones..."
|
|
305
|
+
local signals_json
|
|
306
|
+
signals_json=$(jq -c '.signals[]' "$AETHER_DIR/data/pheromones.json" 2>/dev/null || echo "")
|
|
307
|
+
|
|
308
|
+
while IFS= read -r signal; do
|
|
309
|
+
[[ -z "$signal" ]] && continue
|
|
310
|
+
local sig_id sig_type sig_content
|
|
311
|
+
sig_id=$(echo "$signal" | jq -r '.id // empty')
|
|
312
|
+
sig_type=$(echo "$signal" | jq -r '.type // empty')
|
|
313
|
+
sig_content=$(echo "$signal" | jq -r '.content.text // .content // empty')
|
|
314
|
+
|
|
315
|
+
if [[ -n "$sig_content" ]]; then
|
|
316
|
+
semantic-index "[$sig_type] $sig_content" "pheromones" "$sig_id" >/dev/null 2>&1 || true
|
|
317
|
+
((count++)) || true
|
|
318
|
+
fi
|
|
319
|
+
done <<< "$signals_json"
|
|
320
|
+
fi
|
|
321
|
+
|
|
322
|
+
# Index QUEEN.md if exists
|
|
323
|
+
if [[ -f "$AETHER_DIR/data/QUEEN.md" ]]; then
|
|
324
|
+
echo " Indexing QUEEN.md..."
|
|
325
|
+
local queen_content
|
|
326
|
+
queen_content=$(cat "$AETHER_DIR/data/QUEEN.md" | tr '\n' ' ')
|
|
327
|
+
semantic-index "$queen_content" "queen" "queen-wisdom" >/dev/null 2>&1 || true
|
|
328
|
+
((count++)) || true
|
|
329
|
+
fi
|
|
330
|
+
|
|
331
|
+
echo "✅ Indexed $count entries"
|
|
332
|
+
jq -c '.stats' "$SEMANTIC_DATA_DIR/index.json"
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
# Get context relevant to a task (for worker injection)
|
|
336
|
+
semantic-get-context() {
|
|
337
|
+
local task="${1:-}"
|
|
338
|
+
local max_results="${2:-3}"
|
|
339
|
+
|
|
340
|
+
if [[ -z "$task" ]]; then
|
|
341
|
+
echo ""
|
|
342
|
+
return 0
|
|
343
|
+
fi
|
|
344
|
+
|
|
345
|
+
if ! semantic-check-deps >/dev/null 2>&1; then
|
|
346
|
+
echo ""
|
|
347
|
+
return 0
|
|
348
|
+
fi
|
|
349
|
+
|
|
350
|
+
local result
|
|
351
|
+
result=$(semantic-search "$task" "$max_results" 0.5 2>/dev/null || echo '{"results":[]}')
|
|
352
|
+
|
|
353
|
+
local count
|
|
354
|
+
count=$(echo "$result" | jq -r '.count // 0')
|
|
355
|
+
|
|
356
|
+
if [[ "$count" -eq 0 ]]; then
|
|
357
|
+
echo ""
|
|
358
|
+
return 0
|
|
359
|
+
fi
|
|
360
|
+
|
|
361
|
+
echo "---"
|
|
362
|
+
echo "## Relevant Context (semantic search)"
|
|
363
|
+
echo ""
|
|
364
|
+
echo "$result" | jq -r '.results[] | "### \(.source // "unknown") (similarity: \(.similarity))\n\(.text[:200] // .text)\n"'
|
|
365
|
+
echo "---"
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
# Check semantic layer status
|
|
369
|
+
semantic-status() {
|
|
370
|
+
if [[ ! -f "$SEMANTIC_DATA_DIR/index.json" ]]; then
|
|
371
|
+
json_ok '{"initialized": false, "message": "Run semantic-init to initialize"}'
|
|
372
|
+
return 0
|
|
373
|
+
fi
|
|
374
|
+
|
|
375
|
+
local deps_ok
|
|
376
|
+
if semantic-check-deps >/dev/null 2>&1; then
|
|
377
|
+
deps_ok="true"
|
|
378
|
+
else
|
|
379
|
+
deps_ok="false"
|
|
380
|
+
fi
|
|
381
|
+
|
|
382
|
+
local entry_count
|
|
383
|
+
entry_count=$(jq '.entries | length' "$SEMANTIC_DATA_DIR/index.json" 2>/dev/null || echo "0")
|
|
384
|
+
|
|
385
|
+
jq -n --arg deps_ok "$deps_ok" --arg entries "$entry_count" \
|
|
386
|
+
'{"initialized": true, "dependencies_ok": ($deps_ok == "true"), "total_entries": ($entries | tonumber)}'
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
# Helper: Output JSON OK response
|
|
390
|
+
json_ok() {
|
|
391
|
+
local result="${1:-}"
|
|
392
|
+
local message="${2:-}"
|
|
393
|
+
jq -n --argjson result "$result" --arg message "$message" \
|
|
394
|
+
'{"ok": true, "result": $result, "message": $message}'
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
# Helper: Output JSON error response
|
|
398
|
+
json_err() {
|
|
399
|
+
local code="${1:-1}"
|
|
400
|
+
local message="${2:-Unknown error}"
|
|
401
|
+
jq -n --arg code "$code" --arg message "$message" \
|
|
402
|
+
'{"ok": false, "error": {"code": $code, "message": $message}}'
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
# Export functions
|
|
406
|
+
export -f semantic-init
|
|
407
|
+
export -f semantic-index
|
|
408
|
+
export -f semantic-search
|
|
409
|
+
export -f semantic-find-duplicate
|
|
410
|
+
export -f semantic-rebuild
|
|
411
|
+
export -f semantic-get-context
|
|
412
|
+
export -f semantic-status
|
|
413
|
+
export -f semantic-check-deps
|