aether-colony 5.2.1 → 5.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.aether/aether-utils.sh +35 -0
- package/.aether/agents/aether-ambassador.md +140 -0
- package/.aether/agents/aether-archaeologist.md +108 -0
- package/.aether/agents/aether-architect.md +133 -0
- package/.aether/agents/aether-auditor.md +144 -0
- package/.aether/agents/aether-builder.md +184 -0
- package/.aether/agents/aether-chaos.md +115 -0
- package/.aether/agents/aether-chronicler.md +122 -0
- package/.aether/agents/aether-gatekeeper.md +116 -0
- package/.aether/agents/aether-includer.md +117 -0
- package/.aether/agents/aether-keeper.md +177 -0
- package/.aether/agents/aether-measurer.md +128 -0
- package/.aether/agents/aether-oracle.md +137 -0
- package/.aether/agents/aether-probe.md +133 -0
- package/.aether/agents/aether-queen.md +286 -0
- package/.aether/agents/aether-route-setter.md +130 -0
- package/.aether/agents/aether-sage.md +106 -0
- package/.aether/agents/aether-scout.md +101 -0
- package/.aether/agents/aether-surveyor-disciplines.md +391 -0
- package/.aether/agents/aether-surveyor-nest.md +329 -0
- package/.aether/agents/aether-surveyor-pathogens.md +264 -0
- package/.aether/agents/aether-surveyor-provisions.md +334 -0
- package/.aether/agents/aether-tracker.md +137 -0
- package/.aether/agents/aether-watcher.md +174 -0
- package/.aether/agents/aether-weaver.md +130 -0
- package/.aether/commands/claude/archaeology.md +334 -0
- package/.aether/commands/claude/build.md +65 -0
- package/.aether/commands/claude/chaos.md +336 -0
- package/.aether/commands/claude/colonize.md +259 -0
- package/.aether/commands/claude/continue.md +60 -0
- package/.aether/commands/claude/council.md +507 -0
- package/.aether/commands/claude/data-clean.md +81 -0
- package/.aether/commands/claude/dream.md +268 -0
- package/.aether/commands/claude/entomb.md +498 -0
- package/.aether/commands/claude/export-signals.md +57 -0
- package/.aether/commands/claude/feedback.md +96 -0
- package/.aether/commands/claude/flag.md +151 -0
- package/.aether/commands/claude/flags.md +169 -0
- package/.aether/commands/claude/focus.md +76 -0
- package/.aether/commands/claude/help.md +154 -0
- package/.aether/commands/claude/history.md +140 -0
- package/.aether/commands/claude/import-signals.md +71 -0
- package/.aether/commands/claude/init.md +505 -0
- package/.aether/commands/claude/insert-phase.md +105 -0
- package/.aether/commands/claude/interpret.md +278 -0
- package/.aether/commands/claude/lay-eggs.md +210 -0
- package/.aether/commands/claude/maturity.md +113 -0
- package/.aether/commands/claude/memory-details.md +77 -0
- package/.aether/commands/claude/migrate-state.md +171 -0
- package/.aether/commands/claude/oracle.md +642 -0
- package/.aether/commands/claude/organize.md +232 -0
- package/.aether/commands/claude/patrol.md +620 -0
- package/.aether/commands/claude/pause-colony.md +233 -0
- package/.aether/commands/claude/phase.md +115 -0
- package/.aether/commands/claude/pheromones.md +156 -0
- package/.aether/commands/claude/plan.md +693 -0
- package/.aether/commands/claude/preferences.md +65 -0
- package/.aether/commands/claude/quick.md +100 -0
- package/.aether/commands/claude/redirect.md +76 -0
- package/.aether/commands/claude/resume-colony.md +197 -0
- package/.aether/commands/claude/resume.md +388 -0
- package/.aether/commands/claude/run.md +231 -0
- package/.aether/commands/claude/seal.md +774 -0
- package/.aether/commands/claude/skill-create.md +286 -0
- package/.aether/commands/claude/status.md +410 -0
- package/.aether/commands/claude/swarm.md +349 -0
- package/.aether/commands/claude/tunnels.md +426 -0
- package/.aether/commands/claude/update.md +132 -0
- package/.aether/commands/claude/verify-castes.md +143 -0
- package/.aether/commands/claude/watch.md +239 -0
- package/.aether/commands/opencode/archaeology.md +331 -0
- package/.aether/commands/opencode/build.md +1168 -0
- package/.aether/commands/opencode/chaos.md +329 -0
- package/.aether/commands/opencode/colonize.md +195 -0
- package/.aether/commands/opencode/continue.md +1436 -0
- package/.aether/commands/opencode/council.md +437 -0
- package/.aether/commands/opencode/data-clean.md +77 -0
- package/.aether/commands/opencode/dream.md +260 -0
- package/.aether/commands/opencode/entomb.md +377 -0
- package/.aether/commands/opencode/export-signals.md +54 -0
- package/.aether/commands/opencode/feedback.md +99 -0
- package/.aether/commands/opencode/flag.md +149 -0
- package/.aether/commands/opencode/flags.md +167 -0
- package/.aether/commands/opencode/focus.md +73 -0
- package/.aether/commands/opencode/help.md +157 -0
- package/.aether/commands/opencode/history.md +136 -0
- package/.aether/commands/opencode/import-signals.md +68 -0
- package/.aether/commands/opencode/init.md +518 -0
- package/.aether/commands/opencode/insert-phase.md +111 -0
- package/.aether/commands/opencode/interpret.md +272 -0
- package/.aether/commands/opencode/lay-eggs.md +213 -0
- package/.aether/commands/opencode/maturity.md +108 -0
- package/.aether/commands/opencode/memory-details.md +83 -0
- package/.aether/commands/opencode/migrate-state.md +165 -0
- package/.aether/commands/opencode/oracle.md +593 -0
- package/.aether/commands/opencode/organize.md +226 -0
- package/.aether/commands/opencode/patrol.md +626 -0
- package/.aether/commands/opencode/pause-colony.md +203 -0
- package/.aether/commands/opencode/phase.md +113 -0
- package/.aether/commands/opencode/pheromones.md +162 -0
- package/.aether/commands/opencode/plan.md +684 -0
- package/.aether/commands/opencode/preferences.md +71 -0
- package/.aether/commands/opencode/quick.md +91 -0
- package/.aether/commands/opencode/redirect.md +84 -0
- package/.aether/commands/opencode/resume-colony.md +190 -0
- package/.aether/commands/opencode/resume.md +394 -0
- package/.aether/commands/opencode/run.md +237 -0
- package/.aether/commands/opencode/seal.md +452 -0
- package/.aether/commands/opencode/skill-create.md +63 -0
- package/.aether/commands/opencode/status.md +307 -0
- package/.aether/commands/opencode/swarm.md +15 -0
- package/.aether/commands/opencode/tunnels.md +400 -0
- package/.aether/commands/opencode/update.md +127 -0
- package/.aether/commands/opencode/verify-castes.md +139 -0
- package/.aether/commands/opencode/watch.md +227 -0
- package/.aether/docs/command-playbooks/build-full.md +1 -1
- package/.aether/docs/command-playbooks/build-prep.md +10 -3
- package/.aether/docs/command-playbooks/build-verify.md +51 -0
- package/.aether/docs/command-playbooks/continue-advance.md +115 -6
- package/.aether/docs/command-playbooks/continue-verify.md +32 -0
- package/.aether/utils/clash-detect.sh +239 -0
- package/.aether/utils/hooks/clash-pre-tool-use.js +99 -0
- package/.aether/utils/merge-driver-lockfile.sh +35 -0
- package/.aether/utils/midden.sh +534 -0
- package/.aether/utils/pheromone.sh +1376 -108
- package/.aether/utils/queen.sh +2 -4
- package/.aether/utils/state-api.sh +25 -4
- package/.aether/utils/swarm.sh +1 -1
- package/.aether/utils/worktree.sh +189 -0
- package/.claude/commands/ant/init.md +9 -3
- package/.opencode/commands/ant/init.md +9 -2
- package/CHANGELOG.md +26 -0
- package/README.md +11 -8
- package/bin/cli.js +103 -61
- package/bin/lib/banner.js +14 -0
- package/bin/lib/init.js +8 -7
- package/bin/lib/interactive-setup.js +251 -0
- package/bin/npx-entry.js +21 -0
- package/bin/npx-install.js +9 -167
- package/bin/validate-package.sh +23 -0
- package/package.json +2 -2
- package/.aether/docs/plans/pheromone-display-plan.md +0 -257
- package/.aether/schemas/example-prompt-builder.xml +0 -234
- package/.aether/scripts/incident-test-add.sh +0 -47
- package/.aether/scripts/weekly-audit.sh +0 -79
package/.aether/utils/queen.sh
CHANGED
|
@@ -1391,8 +1391,7 @@ _colony_depth() {
|
|
|
1391
1391
|
local new_depth="${2:-}"
|
|
1392
1392
|
case "$new_depth" in
|
|
1393
1393
|
light|standard|deep|full)
|
|
1394
|
-
|
|
1395
|
-
jq --arg d "$new_depth" '.colony_depth = $d' "$DATA_DIR/COLONY_STATE.json" > "$tmp" && mv "$tmp" "$DATA_DIR/COLONY_STATE.json"
|
|
1394
|
+
NEW_DEPTH="$new_depth" _state_mutate '.colony_depth = env.NEW_DEPTH'
|
|
1396
1395
|
json_ok "$(jq -n --arg depth "$new_depth" '{depth: $depth, updated: true}')"
|
|
1397
1396
|
;;
|
|
1398
1397
|
*)
|
|
@@ -1476,8 +1475,7 @@ _queen_write_charter() {
|
|
|
1476
1475
|
local current_name
|
|
1477
1476
|
current_name=$(jq -r '.colony_name // empty' "$DATA_DIR/COLONY_STATE.json" 2>/dev/null) || true
|
|
1478
1477
|
if [[ -z "$current_name" && -n "$cw_colony_name" ]]; then
|
|
1479
|
-
|
|
1480
|
-
jq --arg cn "$cw_colony_name" '.colony_name = $cn' "$DATA_DIR/COLONY_STATE.json" > "$tmp_state" && mv "$tmp_state" "$DATA_DIR/COLONY_STATE.json"
|
|
1478
|
+
CW_COLONY_NAME="$cw_colony_name" _state_mutate '.colony_name = env.CW_COLONY_NAME'
|
|
1481
1479
|
fi
|
|
1482
1480
|
fi
|
|
1483
1481
|
|
|
@@ -96,11 +96,32 @@ _state_write() {
|
|
|
96
96
|
|
|
97
97
|
_state_mutate() {
|
|
98
98
|
# Read-modify-write COLONY_STATE.json with a jq expression
|
|
99
|
-
# Usage: state-mutate '<jq_expression>'
|
|
99
|
+
# Usage: state-mutate [--arg NAME VALUE] [--argjson NAME VALUE] '<jq_expression>'
|
|
100
|
+
# Supports jq --arg, --argjson, --slurpfile, --rawfile flags (forwarded to jq)
|
|
100
101
|
# Acquires lock, creates backup, applies jq, validates, writes atomically
|
|
101
102
|
# Returns: json_ok with mutated:true, or json_err on failure
|
|
102
103
|
|
|
103
|
-
|
|
104
|
+
# Parse jq flags (--arg, --argjson, --slurpfile, --rawfile) from arguments
|
|
105
|
+
# The jq expression is always the last argument (after all flags)
|
|
106
|
+
local sm_jq_flags=()
|
|
107
|
+
local sm_expr=""
|
|
108
|
+
local i=0
|
|
109
|
+
local args=("$@")
|
|
110
|
+
|
|
111
|
+
while [[ $i -lt ${#args[@]} ]]; do
|
|
112
|
+
case "${args[$i]}" in
|
|
113
|
+
--arg|--argjson|--slurpfile|--rawfile)
|
|
114
|
+
# Flag requires a name and value — consume next two args
|
|
115
|
+
sm_jq_flags+=("${args[$i]}" "${args[$((i+1))]}" "${args[$((i+2))]}")
|
|
116
|
+
i=$((i + 3))
|
|
117
|
+
;;
|
|
118
|
+
*)
|
|
119
|
+
# Last argument is the jq expression
|
|
120
|
+
sm_expr="${args[$i]}"
|
|
121
|
+
i=$((i + 1))
|
|
122
|
+
;;
|
|
123
|
+
esac
|
|
124
|
+
done
|
|
104
125
|
|
|
105
126
|
if [[ -z "$sm_expr" ]]; then
|
|
106
127
|
json_err "$E_VALIDATION_FAILED" "state-mutate requires a jq expression argument"
|
|
@@ -122,8 +143,8 @@ _state_mutate() {
|
|
|
122
143
|
fi
|
|
123
144
|
fi
|
|
124
145
|
|
|
125
|
-
# Apply jq expression to current state
|
|
126
|
-
sm_updated=$(jq "$sm_expr" "$sm_state_file" 2>/dev/null) || {
|
|
146
|
+
# Apply jq expression to current state (with forwarded flags)
|
|
147
|
+
sm_updated=$(jq ${sm_jq_flags[@]+"${sm_jq_flags[@]}"} "$sm_expr" "$sm_state_file" 2>/dev/null) || {
|
|
127
148
|
release_lock 2>/dev/null || true # SUPPRESS:OK -- cleanup: lock may not be held
|
|
128
149
|
json_err "$E_JSON_INVALID" "jq expression failed: $sm_expr"
|
|
129
150
|
}
|
package/.aether/utils/swarm.sh
CHANGED
|
@@ -32,7 +32,7 @@ _autofix_checkpoint() {
|
|
|
32
32
|
label="${1:-autofix-$(date +%s)}"
|
|
33
33
|
stash_name="aether-checkpoint: $label"
|
|
34
34
|
# Only stash Aether-managed directories, never touch user files
|
|
35
|
-
if git stash push -m "$stash_name" -- $target_dirs >/dev/null 2>&1; then # SUPPRESS:OK -- existence-test: stash operation may fail
|
|
35
|
+
if git stash push -m "$stash_name" -- $target_dirs ":(exclude).aether/data/" >/dev/null 2>&1; then # SUPPRESS:OK -- existence-test: stash operation may fail
|
|
36
36
|
json_ok "$(jq -n --arg ref "$stash_name" '{type: "stash", ref: $ref}')"
|
|
37
37
|
else
|
|
38
38
|
# Stash failed (possibly due to conflicts), record commit hash
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Worktree utility functions -- extracted from aether-utils.sh
|
|
3
|
+
# Provides: _worktree_create, _worktree_cleanup
|
|
4
|
+
#
|
|
5
|
+
# These functions are sourced by aether-utils.sh at startup.
|
|
6
|
+
# All shared infrastructure (json_ok, json_err, atomic_write, acquire_lock,
|
|
7
|
+
# release_lock, DATA_DIR, COLONY_DATA_DIR, SCRIPT_DIR, AETHER_ROOT, error
|
|
8
|
+
# constants) is available.
|
|
9
|
+
|
|
10
|
+
# Default worktree location relative to AETHER_ROOT
|
|
11
|
+
WORKTREE_BASE_DIR="${AETHER_ROOT}/.aether/worktrees"
|
|
12
|
+
|
|
13
|
+
# _worktree_create
|
|
14
|
+
# Creates a git worktree for an agent working on a specific task.
|
|
15
|
+
#
|
|
16
|
+
# Usage: _worktree_create --branch <branch-name> [--base <base-branch>] [--task-id <task-id>]
|
|
17
|
+
# Returns JSON: {ok:true, result:{path, branch, base, worktree_dir, task_id}}
|
|
18
|
+
_worktree_create() {
|
|
19
|
+
local branch=""
|
|
20
|
+
local base=""
|
|
21
|
+
local task_id=""
|
|
22
|
+
|
|
23
|
+
# Parse arguments
|
|
24
|
+
while [[ $# -gt 0 ]]; do
|
|
25
|
+
case "$1" in
|
|
26
|
+
--branch) branch="${2:-}"; shift 2 ;;
|
|
27
|
+
--base) base="${2:-}"; shift 2 ;;
|
|
28
|
+
--task-id) task_id="${2:-}"; shift 2 ;;
|
|
29
|
+
*) shift ;;
|
|
30
|
+
esac
|
|
31
|
+
done
|
|
32
|
+
|
|
33
|
+
# Validate required arguments
|
|
34
|
+
if [[ -z "$branch" ]]; then
|
|
35
|
+
json_err "$E_VALIDATION_FAILED" "Usage: worktree-create --branch <branch-name> [--base <base-branch>] [--task-id <task-id>]"
|
|
36
|
+
fi
|
|
37
|
+
|
|
38
|
+
# Sanitize branch name: reject obviously dangerous patterns
|
|
39
|
+
if [[ "$branch" == *..* ]] || [[ "$branch" == */* ]] || [[ "$branch" == *\\* ]]; then
|
|
40
|
+
json_err "$E_VALIDATION_FAILED" "Branch name must not contain '..', '/', or backslashes"
|
|
41
|
+
fi
|
|
42
|
+
|
|
43
|
+
# Default base to current branch
|
|
44
|
+
if [[ -z "$base" ]]; then
|
|
45
|
+
base=$(git -C "$AETHER_ROOT" rev-parse --abbrev-ref HEAD 2>/dev/null || echo "main")
|
|
46
|
+
fi
|
|
47
|
+
|
|
48
|
+
local worktree_dir="$WORKTREE_BASE_DIR/$branch"
|
|
49
|
+
|
|
50
|
+
# Check if worktree already exists
|
|
51
|
+
if [[ -d "$worktree_dir" ]]; then
|
|
52
|
+
json_err "$E_VALIDATION_FAILED" "Worktree already exists for branch '$branch' at $worktree_dir"
|
|
53
|
+
fi
|
|
54
|
+
|
|
55
|
+
# Check if branch already exists as a git branch (would indicate duplicate)
|
|
56
|
+
if git -C "$AETHER_ROOT" show-ref --verify --quiet "refs/heads/$branch" 2>/dev/null; then
|
|
57
|
+
json_err "$E_VALIDATION_FAILED" "Branch '$branch' already exists"
|
|
58
|
+
fi
|
|
59
|
+
|
|
60
|
+
# Ensure base branch exists
|
|
61
|
+
if ! git -C "$AETHER_ROOT" show-ref --verify --quiet "refs/heads/$base" 2>/dev/null; then
|
|
62
|
+
json_err "$E_GIT_ERROR" "Base branch '$base' does not exist"
|
|
63
|
+
fi
|
|
64
|
+
|
|
65
|
+
# Ensure parent directory exists
|
|
66
|
+
mkdir -p "$WORKTREE_BASE_DIR"
|
|
67
|
+
|
|
68
|
+
# Create the worktree (git worktree add creates the branch automatically)
|
|
69
|
+
if ! git -C "$AETHER_ROOT" worktree add "$worktree_dir" -b "$branch" "$base" >/dev/null 2>&1; then
|
|
70
|
+
json_err "$E_GIT_ERROR" "Failed to create worktree for branch '$branch'"
|
|
71
|
+
fi
|
|
72
|
+
|
|
73
|
+
# Copy .aether/data/ structure to the new worktree so the agent has colony context
|
|
74
|
+
# Per state-contract-design.md, branch-local state lives in .aether/data/ (gitignored)
|
|
75
|
+
# and each worktree gets its own independent copy for colony context isolation.
|
|
76
|
+
if [[ -d "$AETHER_ROOT/.aether/data" ]]; then
|
|
77
|
+
mkdir -p "$worktree_dir/.aether/data"
|
|
78
|
+
cp -r "$AETHER_ROOT/.aether/data/." "$worktree_dir/.aether/data/" 2>/dev/null || true # SUPPRESS:OK -- copy: data dir may be empty
|
|
79
|
+
fi
|
|
80
|
+
|
|
81
|
+
# Copy exchange scripts so xml-utils.sh can source pheromone-xml.sh etc.
|
|
82
|
+
if [[ -d "$AETHER_ROOT/.aether/exchange" ]]; then
|
|
83
|
+
mkdir -p "$worktree_dir/.aether/exchange"
|
|
84
|
+
cp -r "$AETHER_ROOT/.aether/exchange/." "$worktree_dir/.aether/exchange/" 2>/dev/null || true
|
|
85
|
+
fi
|
|
86
|
+
|
|
87
|
+
# Inject main's pheromone signals into the worktree (per D-01)
|
|
88
|
+
# Non-blocking: if injection fails, worktree still works without injected signals
|
|
89
|
+
if [[ -f "$worktree_dir/.aether/data/pheromones.json" ]]; then
|
|
90
|
+
local main_head
|
|
91
|
+
main_head=$(git -C "$AETHER_ROOT" rev-parse HEAD 2>/dev/null || echo "unknown")
|
|
92
|
+
(
|
|
93
|
+
cd "$worktree_dir" 2>/dev/null && \
|
|
94
|
+
DATA_DIR="$worktree_dir/.aether/data" \
|
|
95
|
+
COLONY_DATA_DIR="$worktree_dir/.aether/data" \
|
|
96
|
+
bash "$AETHER_ROOT/.aether/aether-utils.sh" \
|
|
97
|
+
pheromone-snapshot-inject --from-branch "$base" --from-commit "$main_head" \
|
|
98
|
+
>/dev/null 2>&1 || true
|
|
99
|
+
)
|
|
100
|
+
fi
|
|
101
|
+
|
|
102
|
+
# Build result JSON
|
|
103
|
+
local result
|
|
104
|
+
result=$(jq -n \
|
|
105
|
+
--arg path "$worktree_dir" \
|
|
106
|
+
--arg branch "$branch" \
|
|
107
|
+
--arg base "$base" \
|
|
108
|
+
--arg worktree_dir "$worktree_dir" \
|
|
109
|
+
--arg task_id "${task_id:-null}" \
|
|
110
|
+
'{
|
|
111
|
+
path: $path,
|
|
112
|
+
branch: $branch,
|
|
113
|
+
base: $base,
|
|
114
|
+
worktree_dir: $worktree_dir,
|
|
115
|
+
task_id: (if $task_id == "null" then null else $task_id end)
|
|
116
|
+
}')
|
|
117
|
+
|
|
118
|
+
json_ok "$result"
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
# _worktree_cleanup
|
|
122
|
+
# Removes a git worktree and cleans up tracking.
|
|
123
|
+
#
|
|
124
|
+
# Usage: _worktree_cleanup --branch <branch-name> [--force]
|
|
125
|
+
# Returns JSON: {ok:true, result:{removed, branch, path}}
|
|
126
|
+
_worktree_cleanup() {
|
|
127
|
+
local branch=""
|
|
128
|
+
local force=false
|
|
129
|
+
|
|
130
|
+
# Parse arguments
|
|
131
|
+
while [[ $# -gt 0 ]]; do
|
|
132
|
+
case "$1" in
|
|
133
|
+
--branch) branch="${2:-}"; shift 2 ;;
|
|
134
|
+
--force) force=true; shift ;;
|
|
135
|
+
*) shift ;;
|
|
136
|
+
esac
|
|
137
|
+
done
|
|
138
|
+
|
|
139
|
+
# Validate required arguments
|
|
140
|
+
if [[ -z "$branch" ]]; then
|
|
141
|
+
json_err "$E_VALIDATION_FAILED" "Usage: worktree-cleanup --branch <branch-name> [--force]"
|
|
142
|
+
fi
|
|
143
|
+
|
|
144
|
+
# Sanitize branch name
|
|
145
|
+
if [[ "$branch" == *..* ]] || [[ "$branch" == */* ]] || [[ "$branch" == *\\* ]]; then
|
|
146
|
+
json_err "$E_VALIDATION_FAILED" "Branch name must not contain '..', '/', or backslashes"
|
|
147
|
+
fi
|
|
148
|
+
|
|
149
|
+
local worktree_dir="$WORKTREE_BASE_DIR/$branch"
|
|
150
|
+
|
|
151
|
+
# Check if worktree exists
|
|
152
|
+
if [[ ! -d "$worktree_dir" ]]; then
|
|
153
|
+
json_err "$E_RESOURCE_NOT_FOUND" "No worktree found for branch '$branch'"
|
|
154
|
+
fi
|
|
155
|
+
|
|
156
|
+
# Check for uncommitted changes (unless --force)
|
|
157
|
+
# Exclude .aether/ files since they are branch-local state copies, not user changes
|
|
158
|
+
if [[ "$force" == "false" ]]; then
|
|
159
|
+
local dirty_count
|
|
160
|
+
dirty_count=$(git -C "$worktree_dir" status --porcelain 2>/dev/null \
|
|
161
|
+
| grep -v '\.aether/' \
|
|
162
|
+
| wc -l \
|
|
163
|
+
| tr -d ' ') || dirty_count=0
|
|
164
|
+
|
|
165
|
+
if [[ "$dirty_count" -gt 0 ]]; then
|
|
166
|
+
json_err "$E_VALIDATION_FAILED" "Worktree '$branch' has $dirty_count uncommitted changes. Use --force to remove anyway."
|
|
167
|
+
fi
|
|
168
|
+
fi
|
|
169
|
+
|
|
170
|
+
# Remove the worktree using git worktree remove
|
|
171
|
+
if ! git -C "$AETHER_ROOT" worktree remove "$worktree_dir" --force 2>/dev/null; then
|
|
172
|
+
# Fallback: manual cleanup if git worktree remove fails
|
|
173
|
+
rm -rf "$worktree_dir" 2>/dev/null || true
|
|
174
|
+
# Also prune stale worktree entries
|
|
175
|
+
git -C "$AETHER_ROOT" worktree prune 2>/dev/null || true
|
|
176
|
+
fi
|
|
177
|
+
|
|
178
|
+
# Attempt to delete the branch (best-effort -- may fail if branch is checked out elsewhere)
|
|
179
|
+
git -C "$AETHER_ROOT" branch -D "$branch" >/dev/null 2>&1 || true
|
|
180
|
+
|
|
181
|
+
# Build result JSON
|
|
182
|
+
local result
|
|
183
|
+
result=$(jq -n \
|
|
184
|
+
--arg branch "$branch" \
|
|
185
|
+
--arg path "$worktree_dir" \
|
|
186
|
+
'{removed: true, branch: $branch, path: $path}')
|
|
187
|
+
|
|
188
|
+
json_ok "$result"
|
|
189
|
+
}
|
|
@@ -41,7 +41,6 @@ Do not touch during init:
|
|
|
41
41
|
- .aether/dreams/ (user notes)
|
|
42
42
|
- .aether/chambers/ (archived colonies)
|
|
43
43
|
- .env* files
|
|
44
|
-
- .claude/settings.json
|
|
45
44
|
- .github/workflows/
|
|
46
45
|
</read_only>
|
|
47
46
|
|
|
@@ -365,7 +364,14 @@ domain_tags=$(bash .aether/aether-utils.sh domain-detect 2>/dev/null | jq -r '.r
|
|
|
365
364
|
bash .aether/aether-utils.sh registry-add "$(pwd)" "$(jq -r '.version // "unknown"' ~/.aether/version.json 2>/dev/null || echo 'unknown')" --goal "{approved_intent}" --active true --tags "$domain_tags" 2>/dev/null || true
|
|
366
365
|
cp ~/.aether/version.json .aether/version.json 2>/dev/null || true
|
|
367
366
|
```
|
|
368
|
-
11.
|
|
367
|
+
11. Install clash detection hook and merge driver (non-blocking):
|
|
368
|
+
```bash
|
|
369
|
+
# Install PreToolUse hook to detect file conflicts across worktrees
|
|
370
|
+
bash .aether/aether-utils.sh clash-setup --install 2>/dev/null || true
|
|
371
|
+
# Register lockfile merge driver (keeps "ours" on package-lock.json conflicts)
|
|
372
|
+
git config merge.lockfile.driver "bash .aether/utils/merge-driver-lockfile.sh %O %A %B" 2>/dev/null || true
|
|
373
|
+
```
|
|
374
|
+
12. Seed QUEEN.md from hive (non-blocking):
|
|
369
375
|
```bash
|
|
370
376
|
domain_tags=$(jq -r --arg repo "$(pwd)" \
|
|
371
377
|
'[.repos[] | select(.path == $repo) | .domain_tags // []] | .[0] // [] | join(",")' \
|
|
@@ -375,7 +381,7 @@ seed_args="queen-seed-from-hive --limit 5"
|
|
|
375
381
|
seed_result=$(bash .aether/aether-utils.sh $seed_args 2>/dev/null || echo '{}')
|
|
376
382
|
seeded_count=$(echo "$seed_result" | jq -r '.result.seeded // 0' 2>/dev/null || echo "0")
|
|
377
383
|
```
|
|
378
|
-
|
|
384
|
+
13. Run `bash .aether/aether-utils.sh session-init "{session_id}" "{approved_intent}"`
|
|
379
385
|
|
|
380
386
|
**Pheromone auto-apply (referenced by both re-init and fresh init paths above):**
|
|
381
387
|
|
|
@@ -377,7 +377,14 @@ domain_tags=$(bash .aether/aether-utils.sh domain-detect 2>/dev/null | jq -r '.r
|
|
|
377
377
|
bash .aether/aether-utils.sh registry-add "$(pwd)" "$(jq -r '.version // "unknown"' ~/.aether/version.json 2>/dev/null || echo 'unknown')" --goal "{approved_intent}" --active true --tags "$domain_tags" 2>/dev/null || true
|
|
378
378
|
cp ~/.aether/version.json .aether/version.json 2>/dev/null || true
|
|
379
379
|
```
|
|
380
|
-
11.
|
|
380
|
+
11. Install clash detection hook and merge driver (non-blocking):
|
|
381
|
+
```bash
|
|
382
|
+
# Install PreToolUse hook to detect file conflicts across worktrees
|
|
383
|
+
bash .aether/aether-utils.sh clash-setup --install 2>/dev/null || true
|
|
384
|
+
# Register lockfile merge driver (keeps "ours" on package-lock.json conflicts)
|
|
385
|
+
git config merge.lockfile.driver "bash .aether/utils/merge-driver-lockfile.sh %O %A %B" 2>/dev/null || true
|
|
386
|
+
```
|
|
387
|
+
12. Seed QUEEN.md from hive (non-blocking):
|
|
381
388
|
```bash
|
|
382
389
|
domain_tags=$(jq -r --arg repo "$(pwd)" \
|
|
383
390
|
'[.repos[] | select(.path == $repo) | .domain_tags // []] | .[0] // [] | join(",")' \
|
|
@@ -387,7 +394,7 @@ seed_args="queen-seed-from-hive --limit 5"
|
|
|
387
394
|
seed_result=$(bash .aether/aether-utils.sh $seed_args 2>/dev/null || echo '{}')
|
|
388
395
|
seeded_count=$(echo "$seed_result" | jq -r '.result.seeded // 0' 2>/dev/null || echo "0")
|
|
389
396
|
```
|
|
390
|
-
|
|
397
|
+
13. Run `bash .aether/aether-utils.sh session-init "{session_id}" "{approved_intent}"`
|
|
391
398
|
|
|
392
399
|
**Pheromone auto-apply (referenced by both re-init and fresh init paths above):**
|
|
393
400
|
|
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,32 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [5.3.0] - 2026-03-31
|
|
11
|
+
|
|
12
|
+
Aether v2.7 — PR Workflow + Stability. Six phases (39-44) adding multi-branch safety, clash detection, and release hardening.
|
|
13
|
+
|
|
14
|
+
### Added
|
|
15
|
+
- **Pheromone propagation** — Signals flow across git branches via `pheromone-snapshot-inject` and `pheromone-merge-back`; worktree creation auto-copies active pheromones
|
|
16
|
+
- **Midden collection** — Failure records from merged branches collected into main via `midden-collect` with idempotent dedup; cross-PR pattern detection via `midden-cross-pr-analysis`; revert-aware tagging via `midden-handle-revert`
|
|
17
|
+
- **Clash detection** — PreToolUse hook (`clash-pre-tool-use.js`) blocks edits to files modified in other active worktrees; `.aether/data/` files allowlisted (branch-local state)
|
|
18
|
+
- **Worktree utilities** — `_worktree_create` auto-copies colony context (COLONY_STATE.json, pheromones.json) and runs pheromone-snapshot-inject
|
|
19
|
+
- **Merge driver** — `.gitattributes` merge driver resolves package-lock.json conflicts by keeping "ours" via `merge-driver-lockfile.sh`
|
|
20
|
+
- **Midden wiring** — `midden-collect` and `midden-cross-pr-analysis` wired into `/ant:continue` playbooks (non-blocking, follows pheromone merge-back pattern)
|
|
21
|
+
- **Interactive installer** — `npx aether-colony` now shows a 3-option menu (Full setup / Global only / Repo only) with environment detection and context-sensitive defaults; supports `--global`, `--repo`, `--yes` flags for scripting
|
|
22
|
+
- **`aether setup` command** — CLI equivalent of `/ant:lay-eggs` for setting up Aether in a repo without Claude Code open
|
|
23
|
+
|
|
24
|
+
### Changed
|
|
25
|
+
- **Package validation** — `validate-package.sh` expanded from 15 to 38+ required file entries (100% coverage of packaged utils)
|
|
26
|
+
- **NPX installer** — Replaced `npx-install.js` with interactive `npx-entry.js`; old installer kept as deprecation redirect
|
|
27
|
+
- **Package cleanliness** — 8 dev-only files excluded from npm tarball (scripts/, design docs, example schemas)
|
|
28
|
+
- **CLAUDE.md** — Full accuracy audit: version bumped to v2.7.0, all counts verified (5,500 lines, 35 utils, 45 commands, 509 tests)
|
|
29
|
+
- **README.md** — Architecture counts updated (35 utils, 45 commands, ~5,500 lines)
|
|
30
|
+
- **YAML commands** — 6 stale command files regenerated from YAML sources (init, plan, seal for Claude and OpenCode)
|
|
31
|
+
|
|
32
|
+
### Fixed
|
|
33
|
+
- **Clash detection dispatcher** — `clash-detect.sh` and `worktree.sh` wired into `aether-utils.sh` dispatcher (source lines, dispatch cases, help JSON)
|
|
34
|
+
- **Init command** — Clash detection hook verification and read-only worktree list integrated into `/ant:init` Step 7.6
|
|
35
|
+
|
|
10
36
|
## [2.1.0] - 2026-03-24
|
|
11
37
|
|
|
12
38
|
Six phases of production hardening (Phases 9-14) targeting reliability, maintainability, and developer experience.
|
package/README.md
CHANGED
|
@@ -18,7 +18,7 @@ Spawn a colony of 24 AI specialists that self-organize around your goal using ph
|
|
|
18
18
|
*The whole is greater than the sum of its ants.*
|
|
19
19
|
|
|
20
20
|
```bash
|
|
21
|
-
|
|
21
|
+
npx aether-colony
|
|
22
22
|
```
|
|
23
23
|
|
|
24
24
|
</div>
|
|
@@ -72,7 +72,10 @@ The colony **remembers**. Wisdom, learnings, and instincts persist across sessio
|
|
|
72
72
|
## 🚀 Quick Start
|
|
73
73
|
|
|
74
74
|
```bash
|
|
75
|
-
#
|
|
75
|
+
# Interactive setup (recommended)
|
|
76
|
+
npx aether-colony
|
|
77
|
+
|
|
78
|
+
# Or install globally
|
|
76
79
|
npm install -g aether-colony
|
|
77
80
|
|
|
78
81
|
# In your project repo:
|
|
@@ -88,7 +91,7 @@ That's it. Five commands from zero to shipped.
|
|
|
88
91
|
## ✨ Key Features
|
|
89
92
|
|
|
90
93
|
- 🐜 **24 Specialized Agents** — Real subagents spawned via Task tool, from builders to archaeologists
|
|
91
|
-
- ⚡ **
|
|
94
|
+
- ⚡ **45 Slash Commands** — Full lifecycle management across Claude Code and OpenCode
|
|
92
95
|
- 🎯 **Pheromone System** — Guide the colony with FOCUS, REDIRECT, FEEDBACK signals
|
|
93
96
|
- 🧠 **Colony Memory** — Learnings persist across sessions via QUEEN.md wisdom
|
|
94
97
|
- 🌐 **Hive Brain** — Cross-colony wisdom sharing with domain-scoped retrieval
|
|
@@ -212,10 +215,10 @@ That's it. Five commands from zero to shipped.
|
|
|
212
215
|
|
|
213
216
|
```
|
|
214
217
|
.aether/ # 🐜 Colony files (repo-local)
|
|
215
|
-
├── aether-utils.sh # ⚡ Dispatcher (~5,
|
|
216
|
-
├── utils/ # 🔧
|
|
218
|
+
├── aether-utils.sh # ⚡ Dispatcher (~5,500 lines, ~130+ subcommands)
|
|
219
|
+
├── utils/ # 🔧 35 modular scripts
|
|
217
220
|
├── skills/ # 📚 28 skills (10 colony + 18 domain)
|
|
218
|
-
├── commands/ # 📖
|
|
221
|
+
├── commands/ # 📖 45 YAML command sources
|
|
219
222
|
├── exchange/ # 📤 XML exchange modules
|
|
220
223
|
├── docs/ # 📝 Documentation
|
|
221
224
|
├── templates/ # 📋 12 templates
|
|
@@ -229,8 +232,8 @@ That's it. Five commands from zero to shipped.
|
|
|
229
232
|
|
|
230
233
|
## 🔌 Works With
|
|
231
234
|
|
|
232
|
-
- **[Claude Code](https://docs.anthropic.com/en/docs/claude-code)** —
|
|
233
|
-
- **[OpenCode](https://github.com/opencode-ai/opencode)** —
|
|
235
|
+
- **[Claude Code](https://docs.anthropic.com/en/docs/claude-code)** — 45 slash commands + 24 agent definitions
|
|
236
|
+
- **[OpenCode](https://github.com/opencode-ai/opencode)** — 45 slash commands + agent definitions
|
|
234
237
|
|
|
235
238
|
## ❤️ Support Aether
|
|
236
239
|
|
package/bin/cli.js
CHANGED
|
@@ -1313,79 +1313,111 @@ program.on('option:quiet', () => {
|
|
|
1313
1313
|
globalQuiet = true;
|
|
1314
1314
|
});
|
|
1315
1315
|
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
log(` Commands: ${result.copied} files -> ${COMMANDS_DEST}`);
|
|
1330
|
-
if (result.removed.length > 0) {
|
|
1331
|
-
log(` Commands: removed ${result.removed.length} stale files`);
|
|
1332
|
-
for (const f of result.removed) log(` - ${f}`);
|
|
1333
|
-
}
|
|
1334
|
-
} else {
|
|
1335
|
-
console.error(' Commands source not found. Skipping.');
|
|
1336
|
-
}
|
|
1337
|
-
} else {
|
|
1338
|
-
const result = syncDirWithCleanup(COMMANDS_SRC, COMMANDS_DEST);
|
|
1316
|
+
/**
|
|
1317
|
+
* Perform a global installation of commands, agents, and hub setup.
|
|
1318
|
+
* Extracted so it can be called from the interactive installer.
|
|
1319
|
+
*/
|
|
1320
|
+
async function performGlobalInstall() {
|
|
1321
|
+
log(c.header(`aether-colony v${VERSION} — installing...`));
|
|
1322
|
+
|
|
1323
|
+
// Sync commands to ~/.claude/commands/ant/ (with orphan cleanup)
|
|
1324
|
+
if (!fs.existsSync(COMMANDS_SRC)) {
|
|
1325
|
+
// Running from source repo — commands are in .claude/commands/ant/
|
|
1326
|
+
const repoCommands = path.join(PACKAGE_DIR, '.claude', 'commands', 'ant');
|
|
1327
|
+
if (fs.existsSync(repoCommands)) {
|
|
1328
|
+
const result = syncDirWithCleanup(repoCommands, COMMANDS_DEST);
|
|
1339
1329
|
log(` Commands: ${result.copied} files -> ${COMMANDS_DEST}`);
|
|
1340
1330
|
if (result.removed.length > 0) {
|
|
1341
1331
|
log(` Commands: removed ${result.removed.length} stale files`);
|
|
1342
1332
|
for (const f of result.removed) log(` - ${f}`);
|
|
1343
1333
|
}
|
|
1334
|
+
} else {
|
|
1335
|
+
console.error(' Commands source not found. Skipping.');
|
|
1336
|
+
}
|
|
1337
|
+
} else {
|
|
1338
|
+
const result = syncDirWithCleanup(COMMANDS_SRC, COMMANDS_DEST);
|
|
1339
|
+
log(` Commands: ${result.copied} files -> ${COMMANDS_DEST}`);
|
|
1340
|
+
if (result.removed.length > 0) {
|
|
1341
|
+
log(` Commands: removed ${result.removed.length} stale files`);
|
|
1342
|
+
for (const f of result.removed) log(` - ${f}`);
|
|
1344
1343
|
}
|
|
1344
|
+
}
|
|
1345
1345
|
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
}
|
|
1346
|
+
// Sync agents to ~/.claude/agents/ant/ (with orphan cleanup)
|
|
1347
|
+
const repoAgents = path.join(PACKAGE_DIR, '.claude', 'agents', 'ant');
|
|
1348
|
+
if (fs.existsSync(repoAgents)) {
|
|
1349
|
+
const result = syncDirWithCleanup(repoAgents, AGENTS_DEST);
|
|
1350
|
+
log(` Agents (claude): ${result.copied} files -> ${AGENTS_DEST}`);
|
|
1351
|
+
if (result.removed.length > 0) {
|
|
1352
|
+
log(` Agents (claude): removed ${result.removed.length} stale files`);
|
|
1353
|
+
for (const f of result.removed) log(` - ${f}`);
|
|
1355
1354
|
}
|
|
1355
|
+
}
|
|
1356
1356
|
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
}
|
|
1357
|
+
// Sync OpenCode commands to ~/.opencode/command/ (with orphan cleanup)
|
|
1358
|
+
const opencodeCmdsSrc = path.join(PACKAGE_DIR, '.opencode', 'commands', 'ant');
|
|
1359
|
+
if (fs.existsSync(opencodeCmdsSrc)) {
|
|
1360
|
+
const result = syncDirWithCleanup(opencodeCmdsSrc, OPENCODE_COMMANDS_DEST);
|
|
1361
|
+
log(` Commands (opencode): ${result.copied} files -> ${OPENCODE_COMMANDS_DEST}`);
|
|
1362
|
+
if (result.removed.length > 0) {
|
|
1363
|
+
log(` Commands (opencode): removed ${result.removed.length} stale files`);
|
|
1364
|
+
for (const f of result.removed) log(` - ${f}`);
|
|
1366
1365
|
}
|
|
1366
|
+
}
|
|
1367
1367
|
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
}
|
|
1368
|
+
// Sync OpenCode agents to ~/.opencode/agent/ (with orphan cleanup)
|
|
1369
|
+
const opencodeAgentsSrc = path.join(PACKAGE_DIR, '.opencode', 'agents');
|
|
1370
|
+
if (fs.existsSync(opencodeAgentsSrc)) {
|
|
1371
|
+
const result = syncDirWithCleanup(opencodeAgentsSrc, OPENCODE_AGENTS_DEST);
|
|
1372
|
+
log(` Agents (opencode): ${result.copied} files -> ${OPENCODE_AGENTS_DEST}`);
|
|
1373
|
+
if (result.removed.length > 0) {
|
|
1374
|
+
log(` Agents (opencode): removed ${result.removed.length} stale files`);
|
|
1375
|
+
for (const f of result.removed) log(` - ${f}`);
|
|
1377
1376
|
}
|
|
1377
|
+
}
|
|
1378
1378
|
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1379
|
+
// Set up distribution hub at ~/.aether/
|
|
1380
|
+
log('');
|
|
1381
|
+
log(c.colony('Setting up distribution hub...'));
|
|
1382
|
+
setupHub();
|
|
1383
1383
|
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1384
|
+
log('');
|
|
1385
|
+
log(c.success('Install complete.'));
|
|
1386
|
+
log(` ${c.queen('Claude Code:')} run /ant to get started`);
|
|
1387
|
+
log(` ${c.colony('OpenCode:')} run /ant to get started`);
|
|
1388
|
+
log(` ${c.colony('Hub:')} ${c.dim('~/.aether/')} (for coordinated updates across repos)`);
|
|
1389
|
+
}
|
|
1390
|
+
|
|
1391
|
+
// Install command
|
|
1392
|
+
program
|
|
1393
|
+
.command('install')
|
|
1394
|
+
.description('Install commands and agents to ~/.claude/ and set up distribution hub')
|
|
1395
|
+
.action(wrapCommand(performGlobalInstall));
|
|
1396
|
+
|
|
1397
|
+
// Setup command — set up Aether in the current directory from hub
|
|
1398
|
+
program
|
|
1399
|
+
.command('setup')
|
|
1400
|
+
.description('Set up Aether in the current directory (copies system files from hub)')
|
|
1401
|
+
.option('-f, --force', 'Overwrite existing setup')
|
|
1402
|
+
.action(wrapCommand(async (options) => {
|
|
1403
|
+
if (!fs.existsSync(HUB_VERSION)) {
|
|
1404
|
+
console.error('Aether hub not installed.');
|
|
1405
|
+
console.error('Run "npx aether-colony" or "aether install" to install the hub first.');
|
|
1406
|
+
process.exit(1);
|
|
1407
|
+
}
|
|
1408
|
+
const repoPath = process.cwd();
|
|
1409
|
+
log(c.header('Setting up Aether in this directory...'));
|
|
1410
|
+
const result = await initializeRepo(repoPath, { setupOnly: true });
|
|
1411
|
+
if (result.success) {
|
|
1412
|
+
log('');
|
|
1413
|
+
log(c.success('Aether is ready.'));
|
|
1414
|
+
log(` ${result.filesCopied} system files synced to .aether/`);
|
|
1415
|
+
log('');
|
|
1416
|
+
log(' Next steps:');
|
|
1417
|
+
log(' In Claude Code: /ant:init "your goal"');
|
|
1418
|
+
log(' Or terminal: aether init --goal "your goal"');
|
|
1419
|
+
log('');
|
|
1420
|
+
}
|
|
1389
1421
|
}));
|
|
1390
1422
|
|
|
1391
1423
|
// Update command
|
|
@@ -2172,10 +2204,20 @@ module.exports = {
|
|
|
2172
2204
|
syncDirWithCleanup,
|
|
2173
2205
|
syncSkillsToHub,
|
|
2174
2206
|
listFilesRecursive,
|
|
2175
|
-
cleanEmptyDirs
|
|
2207
|
+
cleanEmptyDirs,
|
|
2208
|
+
performGlobalInstall,
|
|
2209
|
+
run
|
|
2176
2210
|
};
|
|
2177
2211
|
|
|
2212
|
+
/**
|
|
2213
|
+
* Parse CLI arguments. Called automatically when run directly,
|
|
2214
|
+
* or explicitly by npx-entry.js when delegating a subcommand.
|
|
2215
|
+
*/
|
|
2216
|
+
function run() {
|
|
2217
|
+
program.parse();
|
|
2218
|
+
}
|
|
2219
|
+
|
|
2178
2220
|
// Parse command line arguments only when run directly (not when required as a module)
|
|
2179
2221
|
if (require.main === module) {
|
|
2180
|
-
|
|
2222
|
+
run();
|
|
2181
2223
|
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared ASCII banner for Aether installers.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
const BANNER = `
|
|
6
|
+
█████╗ ███████╗████████╗██╗ ██╗███████╗██████╗
|
|
7
|
+
██╔══██╗██╔════╝╚══██╔══╝██║ ██║██╔════╝██╔══██╗
|
|
8
|
+
███████║█████╗ ██║ ███████║█████╗ ██████╔╝
|
|
9
|
+
██╔══██║██╔══╝ ██║ ██╔══██║██╔══╝ ██╔══██╗
|
|
10
|
+
██║ ██║███████╗ ██║ ██║ ██║███████╗██║ ██║
|
|
11
|
+
╚═╝ ╚═╝╚══════╝ ╚═╝ ╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝
|
|
12
|
+
`;
|
|
13
|
+
|
|
14
|
+
module.exports = { BANNER };
|
package/bin/lib/init.js
CHANGED
|
@@ -321,7 +321,7 @@ function validateInitialization(repoPath) {
|
|
|
321
321
|
* @returns {object} Result: { success: boolean, stateFile: string|null, message: string }
|
|
322
322
|
*/
|
|
323
323
|
async function initializeRepo(repoPath, options = {}) {
|
|
324
|
-
const { goal, skipIfExists = false, quiet = false } = options;
|
|
324
|
+
const { goal, skipIfExists = false, quiet = false, setupOnly = false } = options;
|
|
325
325
|
|
|
326
326
|
// Check if already initialized
|
|
327
327
|
if (isInitialized(repoPath) && skipIfExists) {
|
|
@@ -411,12 +411,13 @@ locks/
|
|
|
411
411
|
`;
|
|
412
412
|
fs.writeFileSync(gitignorePath, gitignoreContent);
|
|
413
413
|
|
|
414
|
-
// Create initial state
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
414
|
+
// Create initial colony state (skipped in setupOnly mode)
|
|
415
|
+
let stateFile = null;
|
|
416
|
+
if (!setupOnly) {
|
|
417
|
+
const state = createInitialState(goal);
|
|
418
|
+
stateFile = path.join(repoPath, '.aether', 'data', 'COLONY_STATE.json');
|
|
419
|
+
fs.writeFileSync(stateFile, JSON.stringify(state, null, 2) + '\n');
|
|
420
|
+
}
|
|
420
421
|
|
|
421
422
|
// Get hub version
|
|
422
423
|
const hubVersion = readJsonSafe(HUB_VERSION);
|