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,291 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# generate-commands.sh - Sync commands between Claude Code and OpenCode
|
|
3
|
+
#
|
|
4
|
+
# This script helps keep commands in sync between the two platforms.
|
|
5
|
+
# Currently it provides a simple diff-based sync, with plans for full
|
|
6
|
+
# YAML-based generation in the future.
|
|
7
|
+
#
|
|
8
|
+
# Usage:
|
|
9
|
+
# ./bin/generate-commands.sh [check|sync|diff]
|
|
10
|
+
#
|
|
11
|
+
# Commands:
|
|
12
|
+
# check - Check if commands are in sync (exit 1 if not)
|
|
13
|
+
# sync - Copy Claude Code commands to OpenCode (with tool name translation)
|
|
14
|
+
# diff - Show differences between command sets
|
|
15
|
+
|
|
16
|
+
set -e
|
|
17
|
+
|
|
18
|
+
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
19
|
+
PROJECT_DIR="$(dirname "$SCRIPT_DIR")"
|
|
20
|
+
|
|
21
|
+
CLAUDE_DIR="$PROJECT_DIR/.claude/commands/ant"
|
|
22
|
+
OPENCODE_DIR="$PROJECT_DIR/.opencode/commands/ant"
|
|
23
|
+
|
|
24
|
+
# Colors for output
|
|
25
|
+
RED='\033[0;31m'
|
|
26
|
+
GREEN='\033[0;32m'
|
|
27
|
+
YELLOW='\033[1;33m'
|
|
28
|
+
NC='\033[0m' # No Color
|
|
29
|
+
|
|
30
|
+
log_info() {
|
|
31
|
+
echo -e "${GREEN}[INFO]${NC} $1"
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
log_warn() {
|
|
35
|
+
echo -e "${YELLOW}[WARN]${NC} $1"
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
log_error() {
|
|
39
|
+
echo -e "${RED}[ERROR]${NC} $1"
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
# Compute SHA hash with error handling
|
|
43
|
+
# Returns 0 on success, 1 on failure
|
|
44
|
+
# Echoes hash on success, error message on failure
|
|
45
|
+
compute_hash() {
|
|
46
|
+
local file="$1"
|
|
47
|
+
|
|
48
|
+
if [[ ! -r "$file" ]]; then
|
|
49
|
+
echo "NOT_READABLE"
|
|
50
|
+
return 1
|
|
51
|
+
fi
|
|
52
|
+
|
|
53
|
+
local hash
|
|
54
|
+
hash=$(shasum "$file" 2>/dev/null | cut -d' ' -f1)
|
|
55
|
+
if [[ -z "$hash" ]]; then
|
|
56
|
+
echo "HASH_FAILED"
|
|
57
|
+
return 1
|
|
58
|
+
fi
|
|
59
|
+
|
|
60
|
+
echo "$hash"
|
|
61
|
+
return 0
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
# Count commands in each directory
|
|
65
|
+
count_commands() {
|
|
66
|
+
local dir="$1"
|
|
67
|
+
if [[ -d "$dir" ]]; then
|
|
68
|
+
find "$dir" -name "*.md" | wc -l | tr -d ' '
|
|
69
|
+
else
|
|
70
|
+
echo "0"
|
|
71
|
+
fi
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
# List command files (PLAN-006 fix #13 - warn about non-.md files)
|
|
75
|
+
list_commands() {
|
|
76
|
+
local dir="$1"
|
|
77
|
+
if [[ -d "$dir" ]]; then
|
|
78
|
+
# Check for non-.md files and warn
|
|
79
|
+
local non_md_count
|
|
80
|
+
non_md_count=$(find "$dir" -type f ! -name "*.md" 2>/dev/null | wc -l | tr -d ' ')
|
|
81
|
+
if [[ "$non_md_count" -gt 0 ]]; then
|
|
82
|
+
log_warn "$non_md_count non-.md file(s) found in $dir (ignored)"
|
|
83
|
+
fi
|
|
84
|
+
|
|
85
|
+
find "$dir" -name "*.md" -exec basename {} \; | sort
|
|
86
|
+
fi
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
# Check if directories are in sync (by file count and names)
|
|
90
|
+
check_sync() {
|
|
91
|
+
log_info "Checking command sync status..."
|
|
92
|
+
|
|
93
|
+
local claude_count=$(count_commands "$CLAUDE_DIR")
|
|
94
|
+
local opencode_count=$(count_commands "$OPENCODE_DIR")
|
|
95
|
+
|
|
96
|
+
echo "Claude Code commands: $claude_count"
|
|
97
|
+
echo "OpenCode commands: $opencode_count"
|
|
98
|
+
|
|
99
|
+
# PLAN-006 fix #10 - warn about empty directories
|
|
100
|
+
if [[ "$claude_count" -eq 0 ]] && [[ "$opencode_count" -eq 0 ]]; then
|
|
101
|
+
log_warn "Both command directories are empty"
|
|
102
|
+
echo "This may indicate a misconfiguration"
|
|
103
|
+
fi
|
|
104
|
+
|
|
105
|
+
# PLAN-006 fix #11 - warn about large command counts
|
|
106
|
+
local max_commands=500
|
|
107
|
+
if [[ "$claude_count" -gt "$max_commands" ]] || [[ "$opencode_count" -gt "$max_commands" ]]; then
|
|
108
|
+
log_warn "Large number of commands ($claude_count/$opencode_count)"
|
|
109
|
+
echo "This may cause performance issues during sync checks"
|
|
110
|
+
fi
|
|
111
|
+
|
|
112
|
+
if [[ "$claude_count" != "$opencode_count" ]]; then
|
|
113
|
+
log_error "Command counts don't match!"
|
|
114
|
+
return 1
|
|
115
|
+
fi
|
|
116
|
+
|
|
117
|
+
# Check file names match
|
|
118
|
+
local claude_files=$(list_commands "$CLAUDE_DIR")
|
|
119
|
+
local opencode_files=$(list_commands "$OPENCODE_DIR")
|
|
120
|
+
|
|
121
|
+
if [[ "$claude_files" != "$opencode_files" ]]; then
|
|
122
|
+
log_error "Command file names don't match!"
|
|
123
|
+
echo ""
|
|
124
|
+
echo "Only in Claude Code:"
|
|
125
|
+
comm -23 <(echo "$claude_files") <(echo "$opencode_files") | sed 's/^/ /'
|
|
126
|
+
echo ""
|
|
127
|
+
echo "Only in OpenCode:"
|
|
128
|
+
comm -13 <(echo "$claude_files") <(echo "$opencode_files") | sed 's/^/ /'
|
|
129
|
+
return 1
|
|
130
|
+
fi
|
|
131
|
+
|
|
132
|
+
log_info "Commands are in sync ($claude_count commands)"
|
|
133
|
+
return 0
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
# Check content-level sync using checksums (Pass 2)
|
|
137
|
+
# Compares each matching file pair by SHA-1 hash and reports diffs
|
|
138
|
+
check_content() {
|
|
139
|
+
log_info "Checking content-level sync (checksums)..."
|
|
140
|
+
|
|
141
|
+
local drift_count=0
|
|
142
|
+
local error_count=0
|
|
143
|
+
local match_count=0
|
|
144
|
+
local drift_files=""
|
|
145
|
+
local error_files=""
|
|
146
|
+
|
|
147
|
+
# Use null delimiter for safe iteration (handles filenames with spaces)
|
|
148
|
+
while IFS= read -r -d '' claude_file; do
|
|
149
|
+
local file
|
|
150
|
+
file=$(basename "$claude_file")
|
|
151
|
+
local opencode_file="$OPENCODE_DIR/$file"
|
|
152
|
+
|
|
153
|
+
# Skip if OpenCode file doesn't exist (already caught by Pass 1)
|
|
154
|
+
if [[ ! -f "$opencode_file" ]]; then
|
|
155
|
+
continue
|
|
156
|
+
fi
|
|
157
|
+
|
|
158
|
+
# Compute hashes with error handling
|
|
159
|
+
local claude_hash opencode_hash
|
|
160
|
+
claude_hash=$(compute_hash "$claude_file")
|
|
161
|
+
if [[ $? -ne 0 ]]; then
|
|
162
|
+
log_error "Cannot hash $claude_file ($claude_hash)"
|
|
163
|
+
error_files="${error_files} ${file} (${claude_hash})\n"
|
|
164
|
+
error_count=$((error_count + 1))
|
|
165
|
+
continue
|
|
166
|
+
fi
|
|
167
|
+
|
|
168
|
+
opencode_hash=$(compute_hash "$opencode_file")
|
|
169
|
+
if [[ $? -ne 0 ]]; then
|
|
170
|
+
log_error "Cannot hash $opencode_file ($opencode_hash)"
|
|
171
|
+
error_files="${error_files} ${file} (${opencode_hash})\n"
|
|
172
|
+
error_count=$((error_count + 1))
|
|
173
|
+
continue
|
|
174
|
+
fi
|
|
175
|
+
|
|
176
|
+
if [[ "$claude_hash" != "$opencode_hash" ]]; then
|
|
177
|
+
drift_count=$((drift_count + 1))
|
|
178
|
+
drift_files="${drift_files} ${file}\n"
|
|
179
|
+
|
|
180
|
+
log_warn "Content drift: $file"
|
|
181
|
+
echo " Claude: $claude_hash"
|
|
182
|
+
echo " OpenCode: $opencode_hash"
|
|
183
|
+
|
|
184
|
+
# PLAN-006 fix #12 - improved diff error handling
|
|
185
|
+
echo " ---"
|
|
186
|
+
local diff_output
|
|
187
|
+
if diff_output=$(diff -u "$claude_file" "$opencode_file" 2>&1); then
|
|
188
|
+
# Files are same (shouldn't happen if hashes differ, but handle it)
|
|
189
|
+
echo "$diff_output" | head -20
|
|
190
|
+
else
|
|
191
|
+
local diff_exit=$?
|
|
192
|
+
if [[ "$diff_output" == *"diff:"* && "$diff_output" == *"No such file"* ]]; then
|
|
193
|
+
log_error "diff failed: $diff_output"
|
|
194
|
+
else
|
|
195
|
+
# Normal diff output (exit 1 means files differ)
|
|
196
|
+
echo "$diff_output" | head -20
|
|
197
|
+
fi
|
|
198
|
+
fi
|
|
199
|
+
echo " ---"
|
|
200
|
+
echo ""
|
|
201
|
+
else
|
|
202
|
+
match_count=$((match_count + 1))
|
|
203
|
+
fi
|
|
204
|
+
done < <(find "$CLAUDE_DIR" -name "*.md" -type f -print0 2>/dev/null | sort -z)
|
|
205
|
+
|
|
206
|
+
# Report results
|
|
207
|
+
if [[ "$error_count" -gt 0 ]]; then
|
|
208
|
+
echo ""
|
|
209
|
+
log_error "Hash errors in $error_count file(s):"
|
|
210
|
+
echo -e "$error_files"
|
|
211
|
+
fi
|
|
212
|
+
|
|
213
|
+
if [[ "$drift_count" -gt 0 ]]; then
|
|
214
|
+
echo ""
|
|
215
|
+
log_warn "Content drift detected in $drift_count file(s) (non-blocking):"
|
|
216
|
+
echo -e "$drift_files"
|
|
217
|
+
# Content drift is advisory — structural sync is what matters
|
|
218
|
+
fi
|
|
219
|
+
|
|
220
|
+
if [[ "$error_count" -gt 0 ]]; then
|
|
221
|
+
return 1
|
|
222
|
+
fi
|
|
223
|
+
|
|
224
|
+
log_info "All file contents match (checksums verified: $match_count files)"
|
|
225
|
+
return 0
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
# Show diff between command sets
|
|
229
|
+
show_diff() {
|
|
230
|
+
log_info "Comparing command sets..."
|
|
231
|
+
|
|
232
|
+
# Use null delimiter for safe iteration (handles filenames with spaces)
|
|
233
|
+
while IFS= read -r -d '' claude_file; do
|
|
234
|
+
local file
|
|
235
|
+
file=$(basename "$claude_file")
|
|
236
|
+
local opencode_file="$OPENCODE_DIR/$file"
|
|
237
|
+
|
|
238
|
+
if [[ ! -f "$opencode_file" ]]; then
|
|
239
|
+
log_warn "$file exists only in Claude Code"
|
|
240
|
+
continue
|
|
241
|
+
fi
|
|
242
|
+
|
|
243
|
+
# Compare file sizes as a quick check
|
|
244
|
+
local claude_size=$(wc -l < "$claude_file" | tr -d ' ')
|
|
245
|
+
local opencode_size=$(wc -l < "$opencode_file" | tr -d ' ')
|
|
246
|
+
|
|
247
|
+
if [[ "$claude_size" != "$opencode_size" ]]; then
|
|
248
|
+
echo "$file: $claude_size lines (Claude) vs $opencode_size lines (OpenCode)"
|
|
249
|
+
fi
|
|
250
|
+
done < <(find "$CLAUDE_DIR" -name "*.md" -type f -print0 2>/dev/null | sort -z)
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
# Display help
|
|
254
|
+
show_help() {
|
|
255
|
+
echo "Aether Command Sync Tool"
|
|
256
|
+
echo ""
|
|
257
|
+
echo "Usage: $0 [command]"
|
|
258
|
+
echo ""
|
|
259
|
+
echo "Commands:"
|
|
260
|
+
echo " check Check if commands are in sync"
|
|
261
|
+
echo " diff Show differences between command sets"
|
|
262
|
+
echo " help Show this help message"
|
|
263
|
+
echo ""
|
|
264
|
+
echo "Directories:"
|
|
265
|
+
echo " Claude Code: $CLAUDE_DIR"
|
|
266
|
+
echo " OpenCode: $OPENCODE_DIR"
|
|
267
|
+
echo ""
|
|
268
|
+
echo "Note: Commands are maintained manually in both directories."
|
|
269
|
+
echo "Use this tool to verify they stay in sync."
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
# Main
|
|
273
|
+
case "${1:-check}" in
|
|
274
|
+
check)
|
|
275
|
+
# Pass 1: file count + name check
|
|
276
|
+
check_sync
|
|
277
|
+
# Pass 2: content-level checksum comparison
|
|
278
|
+
check_content
|
|
279
|
+
;;
|
|
280
|
+
diff)
|
|
281
|
+
show_diff
|
|
282
|
+
;;
|
|
283
|
+
help|--help|-h)
|
|
284
|
+
show_help
|
|
285
|
+
;;
|
|
286
|
+
*)
|
|
287
|
+
log_error "Unknown command: $1"
|
|
288
|
+
show_help
|
|
289
|
+
exit 1
|
|
290
|
+
;;
|
|
291
|
+
esac
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Caste Color Definitions Module
|
|
4
|
+
*
|
|
5
|
+
* Centralized caste styling with colors and emojis for consistent
|
|
6
|
+
* theming across the Aether colony system.
|
|
7
|
+
*
|
|
8
|
+
* Caste Colors (ANSI + picocolors):
|
|
9
|
+
* - builder: blue (🔨) - Construction, implementation
|
|
10
|
+
* - watcher: green (👁️) - Observation, monitoring
|
|
11
|
+
* - scout: yellow (🔍) - Exploration, investigation
|
|
12
|
+
* - chaos: red (🎲) - Testing, disruption
|
|
13
|
+
* - prime: magenta (👑) - Coordination, leadership
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
const pc = require('picocolors');
|
|
17
|
+
|
|
18
|
+
// Caste definitions with colors and emojis (per CONTEXT.md decisions)
|
|
19
|
+
const CASTE_STYLES = {
|
|
20
|
+
builder: { color: 'blue', emoji: '🔨🐜', ansi: '\033[34m', pc: pc.blue },
|
|
21
|
+
watcher: { color: 'green', emoji: '👁️🐜', ansi: '\033[32m', pc: pc.green },
|
|
22
|
+
scout: { color: 'yellow', emoji: '🔍🐜', ansi: '\033[33m', pc: pc.yellow },
|
|
23
|
+
chaos: { color: 'red', emoji: '🎲🐜', ansi: '\033[31m', pc: pc.red },
|
|
24
|
+
prime: { color: 'magenta',emoji: '👑🐜', ansi: '\033[35m', pc: pc.magenta }
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
// Get style for a caste (case-insensitive)
|
|
28
|
+
function getCasteStyle(caste) {
|
|
29
|
+
const key = caste.toLowerCase();
|
|
30
|
+
return CASTE_STYLES[key] || { color: 'reset', emoji: '🐜', ansi: '\033[0m', pc: (s) => s };
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Format ant name with color and emoji: "🔨 Builder" (both colored)
|
|
34
|
+
function formatAnt(name, caste) {
|
|
35
|
+
const style = getCasteStyle(caste);
|
|
36
|
+
return `${style.emoji} ${style.pc(name)}`;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Format with ANSI codes (for bash scripts)
|
|
40
|
+
function formatAntAnsi(name, caste) {
|
|
41
|
+
const style = getCasteStyle(caste);
|
|
42
|
+
const reset = '\x1b[0m';
|
|
43
|
+
return `${style.ansi}${style.emoji} ${name}${reset}`;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Get all castes for iteration
|
|
47
|
+
function getCastes() {
|
|
48
|
+
return Object.keys(CASTE_STYLES);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
module.exports = {
|
|
52
|
+
CASTE_STYLES,
|
|
53
|
+
getCasteStyle,
|
|
54
|
+
formatAnt,
|
|
55
|
+
formatAntAnsi,
|
|
56
|
+
getCastes
|
|
57
|
+
};
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Aether Color Palette Module
|
|
4
|
+
*
|
|
5
|
+
* Centralized color definitions for consistent CLI theming.
|
|
6
|
+
* Uses picocolors for lightweight, NO_COLOR-friendly terminal colors.
|
|
7
|
+
*
|
|
8
|
+
* Aether Brand Colors:
|
|
9
|
+
* - queen: magenta (Queen ant)
|
|
10
|
+
* - colony: cyan (Colony/nest)
|
|
11
|
+
* - worker: yellow (Workers)
|
|
12
|
+
* - success: green
|
|
13
|
+
* - warning: yellow
|
|
14
|
+
* - error: red
|
|
15
|
+
* - info: blue
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
const pc = require('picocolors');
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Detect if color output is enabled
|
|
22
|
+
* Checks --no-color flag and NO_COLOR environment variable
|
|
23
|
+
* @returns {boolean} True if colors should be enabled
|
|
24
|
+
*/
|
|
25
|
+
function isColorEnabled() {
|
|
26
|
+
// Check explicit --no-color flag
|
|
27
|
+
if (process.argv.includes('--no-color')) {
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
// Check environment variable (NO_COLOR set to any non-empty value disables colors)
|
|
31
|
+
if (process.env.NO_COLOR && process.env.NO_COLOR !== '') {
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
// Check if stdout is TTY (disable colors when piped)
|
|
35
|
+
if (!process.stdout.isTTY) {
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
return true;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const enabled = isColorEnabled();
|
|
42
|
+
const p = enabled ? pc : pc.createColors(false);
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Aether brand color palette
|
|
46
|
+
* Semantic naming based on ant colony hierarchy and message types
|
|
47
|
+
*/
|
|
48
|
+
module.exports = {
|
|
49
|
+
// Aether brand - ant colony hierarchy
|
|
50
|
+
queen: p.magenta, // Queen ant - magenta
|
|
51
|
+
colony: p.cyan, // Colony/nest - cyan
|
|
52
|
+
worker: p.yellow, // Workers - yellow
|
|
53
|
+
|
|
54
|
+
// Semantic message colors
|
|
55
|
+
success: p.green,
|
|
56
|
+
warning: p.yellow,
|
|
57
|
+
error: p.red,
|
|
58
|
+
info: p.blue,
|
|
59
|
+
|
|
60
|
+
// Text styles
|
|
61
|
+
bold: p.bold,
|
|
62
|
+
dim: p.dim,
|
|
63
|
+
italic: p.italic,
|
|
64
|
+
underline: p.underline,
|
|
65
|
+
strikethrough: p.strikethrough,
|
|
66
|
+
|
|
67
|
+
// Headers (combined styles)
|
|
68
|
+
header: (text) => p.bold(p.cyan(text)),
|
|
69
|
+
subheader: (text) => p.bold(text),
|
|
70
|
+
|
|
71
|
+
// Utility
|
|
72
|
+
isEnabled: () => enabled,
|
|
73
|
+
|
|
74
|
+
// Raw picocolors access for advanced usage
|
|
75
|
+
raw: p
|
|
76
|
+
};
|
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Aether Error Class Hierarchy
|
|
4
|
+
*
|
|
5
|
+
* Centralized error handling for the Aether Colony CLI.
|
|
6
|
+
* Provides structured JSON output, error codes, and recovery suggestions.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Error codes enum - categorized by error type
|
|
11
|
+
*/
|
|
12
|
+
const ErrorCodes = {
|
|
13
|
+
// System errors (1-99)
|
|
14
|
+
E_HUB_NOT_FOUND: 'E_HUB_NOT_FOUND',
|
|
15
|
+
E_REPO_NOT_INITIALIZED: 'E_REPO_NOT_INITIALIZED',
|
|
16
|
+
E_FILE_SYSTEM: 'E_FILE_SYSTEM',
|
|
17
|
+
E_GIT_ERROR: 'E_GIT_ERROR',
|
|
18
|
+
|
|
19
|
+
// Validation errors (100-199)
|
|
20
|
+
E_INVALID_STATE: 'E_INVALID_STATE',
|
|
21
|
+
E_MANIFEST_INVALID: 'E_MANIFEST_INVALID',
|
|
22
|
+
E_JSON_PARSE: 'E_JSON_PARSE',
|
|
23
|
+
|
|
24
|
+
// Runtime errors (200-299)
|
|
25
|
+
E_UPDATE_FAILED: 'E_UPDATE_FAILED',
|
|
26
|
+
E_LOCK_TIMEOUT: 'E_LOCK_TIMEOUT',
|
|
27
|
+
E_ATOMIC_WRITE_FAILED: 'E_ATOMIC_WRITE_FAILED',
|
|
28
|
+
|
|
29
|
+
// Unexpected errors (300-399)
|
|
30
|
+
E_UNEXPECTED: 'E_UNEXPECTED',
|
|
31
|
+
E_UNCAUGHT_EXCEPTION: 'E_UNCAUGHT_EXCEPTION',
|
|
32
|
+
E_UNHANDLED_REJECTION: 'E_UNHANDLED_REJECTION',
|
|
33
|
+
|
|
34
|
+
// Configuration errors (400-499)
|
|
35
|
+
E_CONFIG: 'E_CONFIG',
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Base AetherError class
|
|
40
|
+
* All application errors extend this class for consistent handling
|
|
41
|
+
*/
|
|
42
|
+
class AetherError extends Error {
|
|
43
|
+
/**
|
|
44
|
+
* @param {string} code - Error code from ErrorCodes
|
|
45
|
+
* @param {string} message - Human-readable error message
|
|
46
|
+
* @param {object} details - Additional error context
|
|
47
|
+
* @param {string|null} recovery - Recovery suggestion for user
|
|
48
|
+
*/
|
|
49
|
+
constructor(code, message, details = {}, recovery = null) {
|
|
50
|
+
super(message);
|
|
51
|
+
this.name = 'AetherError';
|
|
52
|
+
this.code = code;
|
|
53
|
+
this.details = details;
|
|
54
|
+
this.recovery = recovery;
|
|
55
|
+
this.timestamp = new Date().toISOString();
|
|
56
|
+
|
|
57
|
+
// Maintain proper stack trace in V8 environments
|
|
58
|
+
if (Error.captureStackTrace) {
|
|
59
|
+
Error.captureStackTrace(this, AetherError);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Convert error to structured JSON object
|
|
65
|
+
* @returns {object} Structured error representation
|
|
66
|
+
*/
|
|
67
|
+
toJSON() {
|
|
68
|
+
return {
|
|
69
|
+
error: {
|
|
70
|
+
code: this.code,
|
|
71
|
+
message: this.message,
|
|
72
|
+
details: this.details,
|
|
73
|
+
recovery: this.recovery,
|
|
74
|
+
timestamp: this.timestamp,
|
|
75
|
+
},
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Convert error to string for console output
|
|
81
|
+
* @returns {string} Formatted error string
|
|
82
|
+
*/
|
|
83
|
+
toString() {
|
|
84
|
+
let str = `${this.code}: ${this.message}`;
|
|
85
|
+
if (this.recovery) {
|
|
86
|
+
str += `\n Recovery: ${this.recovery}`;
|
|
87
|
+
}
|
|
88
|
+
return str;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* HubError - Hub-related errors (distribution hub not found, corrupted, etc.)
|
|
94
|
+
*/
|
|
95
|
+
class HubError extends AetherError {
|
|
96
|
+
constructor(message, details = {}) {
|
|
97
|
+
super(
|
|
98
|
+
ErrorCodes.E_HUB_NOT_FOUND,
|
|
99
|
+
message,
|
|
100
|
+
details,
|
|
101
|
+
'Run: aether install'
|
|
102
|
+
);
|
|
103
|
+
this.name = 'HubError';
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* RepoError - Repository initialization errors
|
|
109
|
+
*/
|
|
110
|
+
class RepoError extends AetherError {
|
|
111
|
+
constructor(message, details = {}) {
|
|
112
|
+
super(
|
|
113
|
+
ErrorCodes.E_REPO_NOT_INITIALIZED,
|
|
114
|
+
message,
|
|
115
|
+
details,
|
|
116
|
+
'Run /ant:init in this repo first'
|
|
117
|
+
);
|
|
118
|
+
this.name = 'RepoError';
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* GitError - Git operation errors
|
|
124
|
+
*/
|
|
125
|
+
class GitError extends AetherError {
|
|
126
|
+
constructor(message, details = {}) {
|
|
127
|
+
super(
|
|
128
|
+
ErrorCodes.E_GIT_ERROR,
|
|
129
|
+
message,
|
|
130
|
+
details,
|
|
131
|
+
'Check git status and resolve conflicts'
|
|
132
|
+
);
|
|
133
|
+
this.name = 'GitError';
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* ValidationError - State validation errors
|
|
139
|
+
*/
|
|
140
|
+
class ValidationError extends AetherError {
|
|
141
|
+
constructor(message, details = {}) {
|
|
142
|
+
super(
|
|
143
|
+
ErrorCodes.E_INVALID_STATE,
|
|
144
|
+
message,
|
|
145
|
+
details,
|
|
146
|
+
'Check the state file and fix validation errors'
|
|
147
|
+
);
|
|
148
|
+
this.name = 'ValidationError';
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* FileSystemError - File operation errors
|
|
154
|
+
*/
|
|
155
|
+
class FileSystemError extends AetherError {
|
|
156
|
+
constructor(message, details = {}) {
|
|
157
|
+
super(
|
|
158
|
+
ErrorCodes.E_FILE_SYSTEM,
|
|
159
|
+
message,
|
|
160
|
+
details,
|
|
161
|
+
'Check file permissions and available disk space'
|
|
162
|
+
);
|
|
163
|
+
this.name = 'FileSystemError';
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* ConfigurationError - Environment/configuration errors
|
|
169
|
+
*/
|
|
170
|
+
class ConfigurationError extends AetherError {
|
|
171
|
+
constructor(message, details = {}) {
|
|
172
|
+
super(
|
|
173
|
+
ErrorCodes.E_CONFIG,
|
|
174
|
+
message,
|
|
175
|
+
details,
|
|
176
|
+
'Check environment variables and configuration'
|
|
177
|
+
);
|
|
178
|
+
this.name = 'ConfigurationError';
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* StateSchemaError - State file schema validation errors (PLAN-007 Fix 3)
|
|
184
|
+
*/
|
|
185
|
+
class StateSchemaError extends AetherError {
|
|
186
|
+
constructor(message, details = {}) {
|
|
187
|
+
super(
|
|
188
|
+
ErrorCodes.E_INVALID_STATE,
|
|
189
|
+
message,
|
|
190
|
+
details,
|
|
191
|
+
'Check state file structure and fix schema errors, or restore from backup'
|
|
192
|
+
);
|
|
193
|
+
this.name = 'StateSchemaError';
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Map error codes to sysexits.h exit codes
|
|
199
|
+
* @param {string} code - Error code
|
|
200
|
+
* @returns {number} Exit code (0-255)
|
|
201
|
+
*/
|
|
202
|
+
function getExitCode(code) {
|
|
203
|
+
switch (code) {
|
|
204
|
+
case ErrorCodes.E_HUB_NOT_FOUND:
|
|
205
|
+
return 69; // EX_UNAVAILABLE - service unavailable
|
|
206
|
+
case ErrorCodes.E_REPO_NOT_INITIALIZED:
|
|
207
|
+
return 78; // EX_CONFIG - configuration error
|
|
208
|
+
case ErrorCodes.E_INVALID_STATE:
|
|
209
|
+
case ErrorCodes.E_MANIFEST_INVALID:
|
|
210
|
+
case ErrorCodes.E_JSON_PARSE:
|
|
211
|
+
return 65; // EX_DATAERR - data format error
|
|
212
|
+
case ErrorCodes.E_FILE_SYSTEM:
|
|
213
|
+
case ErrorCodes.E_ATOMIC_WRITE_FAILED:
|
|
214
|
+
return 74; // EX_IOERR - I/O error
|
|
215
|
+
case ErrorCodes.E_GIT_ERROR:
|
|
216
|
+
return 70; // EX_SOFTWARE - internal software error
|
|
217
|
+
case ErrorCodes.E_LOCK_TIMEOUT:
|
|
218
|
+
return 73; // EX_CANTCREAT - can't create (lock) file
|
|
219
|
+
case ErrorCodes.E_CONFIG:
|
|
220
|
+
return 78; // EX_CONFIG - configuration error
|
|
221
|
+
default:
|
|
222
|
+
return 1; // Generic error
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Wrap a plain Error in an AetherError
|
|
228
|
+
* @param {Error} error - Plain error to wrap
|
|
229
|
+
* @returns {AetherError} Wrapped error
|
|
230
|
+
*/
|
|
231
|
+
function wrapError(error) {
|
|
232
|
+
if (error instanceof AetherError) {
|
|
233
|
+
return error;
|
|
234
|
+
}
|
|
235
|
+
return new AetherError(
|
|
236
|
+
ErrorCodes.E_UNEXPECTED,
|
|
237
|
+
error.message,
|
|
238
|
+
{ stack: error.stack, name: error.name },
|
|
239
|
+
'Please report this issue with the error details'
|
|
240
|
+
);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
module.exports = {
|
|
244
|
+
AetherError,
|
|
245
|
+
HubError,
|
|
246
|
+
RepoError,
|
|
247
|
+
GitError,
|
|
248
|
+
ValidationError,
|
|
249
|
+
FileSystemError,
|
|
250
|
+
ConfigurationError,
|
|
251
|
+
StateSchemaError,
|
|
252
|
+
ErrorCodes,
|
|
253
|
+
getExitCode,
|
|
254
|
+
wrapError,
|
|
255
|
+
};
|