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,22 @@
|
|
|
1
|
+
# colony-state-reset.jq.template — Reset colony state fields for entomb
|
|
2
|
+
# Usage: jq -f .aether/templates/colony-state-reset.jq.template STATE.json.bak > STATE.json
|
|
3
|
+
# Version: 1.0
|
|
4
|
+
|
|
5
|
+
.goal = null |
|
|
6
|
+
.state = "IDLE" |
|
|
7
|
+
.current_phase = 0 |
|
|
8
|
+
.plan.phases = [] |
|
|
9
|
+
.plan.generated_at = null |
|
|
10
|
+
.plan.confidence = null |
|
|
11
|
+
.build_started_at = null |
|
|
12
|
+
.session_id = null |
|
|
13
|
+
.initialized_at = null |
|
|
14
|
+
.milestone = null |
|
|
15
|
+
.events = [] |
|
|
16
|
+
.errors.records = [] |
|
|
17
|
+
.errors.flagged_patterns = [] |
|
|
18
|
+
.signals = [] |
|
|
19
|
+
.graveyards = [] |
|
|
20
|
+
.memory.instincts = [] |
|
|
21
|
+
.memory.phase_learnings = [] |
|
|
22
|
+
.memory.decisions = []
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"_template": "colony-state",
|
|
3
|
+
"_version": "3.0",
|
|
4
|
+
"_instructions": "Write this file to .aether/data/COLONY_STATE.json. Replace every __PLACEHOLDER__ value with real data (see _comment_* fields for details). After filling all placeholders, remove every key whose name starts with underscore (_template, _version, _instructions, and all _comment_*) before writing the final file.",
|
|
5
|
+
"_comment_goal": "Replace __GOAL__ with the user's goal string exactly as provided to /ant:init.",
|
|
6
|
+
"_comment_session": "Replace __SESSION_ID__ with a generated ID in the format: session_{unix_timestamp}_{random}. Replace __ISO8601_TIMESTAMP__ with the current UTC time in ISO-8601 format (e.g., 2026-02-20T00:00:00Z). The same timestamp value is used in both 'initialized_at' and the events array entry.",
|
|
7
|
+
"_comment_memory": "Replace __PHASE_LEARNINGS__ with a JSON array (e.g., [] if no prior colony found, or [{...}, ...] if inherited from completion-report.md). Replace __INSTINCTS__ with a JSON array (e.g., [] or [{...}, ...]). IMPORTANT: both must be JSON arrays, not strings — write [] not \"[]\".",
|
|
8
|
+
"_comment_events": "The events array records colony lifecycle events. Each entry is a pipe-delimited string: 'ISO8601_TIMESTAMP|event_type|source|description'. The initialization event uses the same __ISO8601_TIMESTAMP__ as 'initialized_at'. Do not add extra events during init — the single initialization entry is correct.",
|
|
9
|
+
"version": "3.0",
|
|
10
|
+
"goal": "__GOAL__",
|
|
11
|
+
"state": "READY",
|
|
12
|
+
"current_phase": 0,
|
|
13
|
+
"session_id": "__SESSION_ID__",
|
|
14
|
+
"initialized_at": "__ISO8601_TIMESTAMP__",
|
|
15
|
+
"build_started_at": null,
|
|
16
|
+
"plan": {
|
|
17
|
+
"generated_at": null,
|
|
18
|
+
"confidence": null,
|
|
19
|
+
"phases": []
|
|
20
|
+
},
|
|
21
|
+
"memory": {
|
|
22
|
+
"phase_learnings": "__PHASE_LEARNINGS__",
|
|
23
|
+
"decisions": [],
|
|
24
|
+
"instincts": "__INSTINCTS__"
|
|
25
|
+
},
|
|
26
|
+
"errors": {
|
|
27
|
+
"records": [],
|
|
28
|
+
"flagged_patterns": []
|
|
29
|
+
},
|
|
30
|
+
"signals": [],
|
|
31
|
+
"graveyards": [],
|
|
32
|
+
"events": [
|
|
33
|
+
"__ISO8601_TIMESTAMP__|colony_initialized|init|Colony initialized with goal: __GOAL__"
|
|
34
|
+
]
|
|
35
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
{
|
|
2
|
+
"_template": "constraints",
|
|
3
|
+
"_version": "1.0",
|
|
4
|
+
"_instructions": "Write this file to .aether/data/constraints.json. No placeholder substitution needed — copy the data keys as-is. Remove all keys whose names start with underscore (_template, _version, _instructions, _comment_*) before writing the final file.",
|
|
5
|
+
"_comment_purpose": "constraints.json stores user pheromone signals. 'focus' holds FOCUS signals (areas of attention set via /ant:focus). 'constraints' holds REDIRECT signals (hard constraints set via /ant:redirect). Both start as empty arrays and accumulate signals over the colony's lifetime.",
|
|
6
|
+
"version": "1.0",
|
|
7
|
+
"focus": [],
|
|
8
|
+
"constraints": []
|
|
9
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
<!-- Template: crowned-anthill | Version: 2.0 -->
|
|
2
|
+
<!-- Instructions: Fill all {{PLACEHOLDER}} values with real colony data. Remove this comment block before writing to .aether/CROWNED-ANTHILL.md -->
|
|
3
|
+
|
|
4
|
+
# Crowned Anthill — {{GOAL}}
|
|
5
|
+
|
|
6
|
+
**Sealed:** {{SEAL_DATE}}
|
|
7
|
+
**Milestone:** Crowned Anthill
|
|
8
|
+
**Version:** {{VERSION}}
|
|
9
|
+
|
|
10
|
+
## The Achievement
|
|
11
|
+
|
|
12
|
+
This colony set out to accomplish something real — and it did. Every phase pushed the anthill higher. Now it stands crowned.
|
|
13
|
+
|
|
14
|
+
## Colony Stats
|
|
15
|
+
- Total Phases: {{TOTAL_PHASES}}
|
|
16
|
+
- Phases Completed: {{PHASES_COMPLETED}} of {{TOTAL_PHASES}}
|
|
17
|
+
- Colony Age: {{COLONY_AGE_DAYS}} days of focused work
|
|
18
|
+
- Wisdom Promoted: {{PROMOTIONS_MADE}} entries carried forward
|
|
19
|
+
|
|
20
|
+
## Phase Recap
|
|
21
|
+
|
|
22
|
+
Every phase below is a chapter in the story of this anthill's rise:
|
|
23
|
+
|
|
24
|
+
{{PHASE_RECAP}}
|
|
25
|
+
|
|
26
|
+
## Pheromone Legacy
|
|
27
|
+
|
|
28
|
+
The colony's hard-won wisdom doesn't stop here. {{PROMOTIONS_MADE}} validated learnings and instincts have been promoted to QUEEN.md — a living record that will guide future colonies before they take their first steps.
|
|
29
|
+
|
|
30
|
+
What this colony learned, the next colony inherits.
|
|
31
|
+
|
|
32
|
+
## The Work
|
|
33
|
+
|
|
34
|
+
{{GOAL}}
|
|
35
|
+
|
|
36
|
+
The anthill stands crowned. The work endures.
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
<!-- Template: handoff-build-error | Version: 1.0 -->
|
|
2
|
+
<!-- Instructions: Fill all {{PLACEHOLDER}} values with real colony data. Remove this comment block before writing to .aether/HANDOFF.md -->
|
|
3
|
+
|
|
4
|
+
# Colony Session — Build Errors
|
|
5
|
+
|
|
6
|
+
## Build Status: ISSUES DETECTED
|
|
7
|
+
|
|
8
|
+
**Phase:** {{PHASE_NUMBER}} — {{PHASE_NAME}}
|
|
9
|
+
**Status:** Build completed with failures
|
|
10
|
+
**Updated:** {{BUILD_TIMESTAMP}}
|
|
11
|
+
|
|
12
|
+
## Failed Workers
|
|
13
|
+
|
|
14
|
+
{{FAILED_WORKERS}}
|
|
15
|
+
|
|
16
|
+
## Grave Markers Placed
|
|
17
|
+
|
|
18
|
+
{{GRAVE_MARKERS}}
|
|
19
|
+
|
|
20
|
+
## Recovery Options
|
|
21
|
+
|
|
22
|
+
1. Review failures: Check `.aether/data/activity.log`
|
|
23
|
+
2. Fix and retry: `/ant:build {{PHASE_NUMBER}}`
|
|
24
|
+
3. Swarm fix: `/ant:swarm` for auto-repair
|
|
25
|
+
4. Manual fix: Address issues, then `/ant:continue`
|
|
26
|
+
|
|
27
|
+
## Session Note
|
|
28
|
+
|
|
29
|
+
Build completed but workers failed. Grave markers placed.
|
|
30
|
+
Review failures before advancing.
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
<!-- Template: handoff-build-success | Version: 1.0 -->
|
|
2
|
+
<!-- Instructions: Fill all {{PLACEHOLDER}} values with real colony data. Remove this comment block before writing to .aether/HANDOFF.md -->
|
|
3
|
+
|
|
4
|
+
# Colony Session — Build Complete
|
|
5
|
+
|
|
6
|
+
## Quick Resume
|
|
7
|
+
|
|
8
|
+
Run `/ant:continue` to advance phase, or `/ant:resume-colony` to restore full context.
|
|
9
|
+
|
|
10
|
+
## State at Build Completion
|
|
11
|
+
|
|
12
|
+
- Goal: "{{GOAL}}"
|
|
13
|
+
- Phase: {{PHASE_NUMBER}} — {{PHASE_NAME}}
|
|
14
|
+
- Build Status: {{BUILD_STATUS}}
|
|
15
|
+
- Updated: {{BUILD_TIMESTAMP}}
|
|
16
|
+
|
|
17
|
+
## Build Summary
|
|
18
|
+
|
|
19
|
+
{{BUILD_SUMMARY}}
|
|
20
|
+
|
|
21
|
+
## Tasks
|
|
22
|
+
|
|
23
|
+
- Completed: {{TASKS_COMPLETED}}
|
|
24
|
+
- Failed: {{TASKS_FAILED}}
|
|
25
|
+
|
|
26
|
+
## Files Changed
|
|
27
|
+
|
|
28
|
+
- Created: {{FILES_CREATED}} files
|
|
29
|
+
- Modified: {{FILES_MODIFIED}} files
|
|
30
|
+
|
|
31
|
+
## Next Steps
|
|
32
|
+
|
|
33
|
+
- If verification passed: `/ant:continue` to advance to next phase
|
|
34
|
+
- If issues found: `/ant:flags` to review blockers
|
|
35
|
+
- To pause: `/ant:pause-colony`
|
|
36
|
+
|
|
37
|
+
## Session Note
|
|
38
|
+
|
|
39
|
+
{{SESSION_NOTE}}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
<!-- Template: handoff | Version: 2.0 -->
|
|
2
|
+
<!-- Instructions: Fill all {{PLACEHOLDER}} values with real colony data. Remove this comment block before writing to .aether/HANDOFF.md -->
|
|
3
|
+
|
|
4
|
+
# Colony Session — {{CHAMBER_NAME}}
|
|
5
|
+
|
|
6
|
+
## A Colony's Rest
|
|
7
|
+
|
|
8
|
+
This colony has been entombed. Its work is complete, its story told.
|
|
9
|
+
What began with a goal has ended with a chamber — a place of quiet preservation.
|
|
10
|
+
|
|
11
|
+
**Chamber:** .aether/chambers/{{CHAMBER_NAME}}/
|
|
12
|
+
|
|
13
|
+
## Colony Summary
|
|
14
|
+
|
|
15
|
+
- Goal: "{{GOAL}}"
|
|
16
|
+
- Phases: {{PHASES_COMPLETED}} completed of {{TOTAL_PHASES}}
|
|
17
|
+
- Milestone reached: {{MILESTONE}}
|
|
18
|
+
- Entombed at: {{ENTOMB_TIMESTAMP}}
|
|
19
|
+
|
|
20
|
+
## Chamber Contents
|
|
21
|
+
|
|
22
|
+
Everything the colony built and learned rests here now:
|
|
23
|
+
|
|
24
|
+
- colony-state.json — Full colony state
|
|
25
|
+
- manifest.json — Archive metadata
|
|
26
|
+
- CROWNED-ANTHILL.md — Seal ceremony record
|
|
27
|
+
- pheromones.json — Pheromone signals
|
|
28
|
+
- activity.log — Colony activity history
|
|
29
|
+
- spawn-tree.txt — Worker spawn records
|
|
30
|
+
- dreams/ — Dream journal (if existed)
|
|
31
|
+
|
|
32
|
+
## Session Note
|
|
33
|
+
|
|
34
|
+
The active colony has been reset. The chambers hold what was.
|
|
35
|
+
The learnings have been carried forward to QUEEN.md — the next colony won't start from nothing.
|
|
36
|
+
|
|
37
|
+
When you are ready to begin again:
|
|
38
|
+
|
|
39
|
+
To start anew: /ant:lay-eggs "<new goal>"
|
|
40
|
+
To revisit what came before: /ant:tunnels
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
{
|
|
2
|
+
"_template": "session",
|
|
3
|
+
"_version": "1.0",
|
|
4
|
+
"_instructions": "Write to .aether/data/session.json. Replace __SESSION_ID__, __GOAL__, __TIMESTAMP__. Remove underscore-prefixed keys.",
|
|
5
|
+
"session_id": "__SESSION_ID__",
|
|
6
|
+
"colony_goal": "__GOAL__",
|
|
7
|
+
"started_at": "__TIMESTAMP__",
|
|
8
|
+
"last_activity": "__TIMESTAMP__"
|
|
9
|
+
}
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Aether Atomic Write Utility
|
|
3
|
+
# Implements atomic write pattern (temp file + rename) for corruption safety
|
|
4
|
+
#
|
|
5
|
+
# Usage:
|
|
6
|
+
# source .aether/utils/atomic-write.sh
|
|
7
|
+
# atomic_write /path/to/file.json "content"
|
|
8
|
+
# atomic_write_from_file /path/to/target.json /path/to/temp.json
|
|
9
|
+
|
|
10
|
+
# Source required utilities
|
|
11
|
+
# Get the directory where this script is located
|
|
12
|
+
_AETHER_UTILS_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
13
|
+
# If BASH_SOURCE[0] is empty (can happen in some contexts), use repo-local path
|
|
14
|
+
if [ -z "$_AETHER_UTILS_DIR" ] || [ "$_AETHER_UTILS_DIR" = "$(pwd)" ]; then
|
|
15
|
+
if git rev-parse --show-toplevel >/dev/null 2>&1; then
|
|
16
|
+
_AETHER_UTILS_DIR="$(git rev-parse --show-toplevel)/.aether/utils"
|
|
17
|
+
else
|
|
18
|
+
_AETHER_UTILS_DIR="$PWD/.aether/utils"
|
|
19
|
+
fi
|
|
20
|
+
fi
|
|
21
|
+
# Verify the path exists and file-lock.sh is there
|
|
22
|
+
if [ ! -f "$_AETHER_UTILS_DIR/file-lock.sh" ]; then
|
|
23
|
+
# Try one more fallback - relative to script location
|
|
24
|
+
_AETHER_UTILS_DIR="$(dirname "${BASH_SOURCE[0]}")"
|
|
25
|
+
fi
|
|
26
|
+
source "$_AETHER_UTILS_DIR/file-lock.sh"
|
|
27
|
+
|
|
28
|
+
# Aether root detection - use git root if available, otherwise use current directory
|
|
29
|
+
if git rev-parse --show-toplevel >/dev/null 2>&1; then
|
|
30
|
+
AETHER_ROOT="$(git rev-parse --show-toplevel)"
|
|
31
|
+
else
|
|
32
|
+
AETHER_ROOT="$(pwd)"
|
|
33
|
+
fi
|
|
34
|
+
|
|
35
|
+
TEMP_DIR="$AETHER_ROOT/.aether/temp"
|
|
36
|
+
BACKUP_DIR="$AETHER_ROOT/.aether/data/backups"
|
|
37
|
+
|
|
38
|
+
# Create directories
|
|
39
|
+
mkdir -p "$TEMP_DIR" "$BACKUP_DIR"
|
|
40
|
+
|
|
41
|
+
# Number of backups to keep
|
|
42
|
+
MAX_BACKUPS=3
|
|
43
|
+
|
|
44
|
+
# Atomic write: write content to file via temporary file
|
|
45
|
+
# Arguments: target_file, content
|
|
46
|
+
# Returns: 0 on success, 1 on failure
|
|
47
|
+
atomic_write() {
|
|
48
|
+
local target_file="$1"
|
|
49
|
+
local content="$2"
|
|
50
|
+
|
|
51
|
+
# Ensure target directory exists
|
|
52
|
+
local target_dir=$(dirname "$target_file")
|
|
53
|
+
mkdir -p "$target_dir"
|
|
54
|
+
|
|
55
|
+
# Create unique temp file
|
|
56
|
+
local temp_file="${TEMP_DIR}/$(basename "$target_file").$$.$(date +%s%N).tmp"
|
|
57
|
+
|
|
58
|
+
# Write content to temp file
|
|
59
|
+
if ! echo "$content" > "$temp_file"; then
|
|
60
|
+
echo "Failed to write to temp file: $temp_file"
|
|
61
|
+
rm -f "$temp_file"
|
|
62
|
+
return 1
|
|
63
|
+
fi
|
|
64
|
+
|
|
65
|
+
# Create backup if target exists (do this BEFORE validation to avoid race condition)
|
|
66
|
+
if [ -f "$target_file" ]; then
|
|
67
|
+
create_backup "$target_file"
|
|
68
|
+
fi
|
|
69
|
+
|
|
70
|
+
# Validate JSON if it's a JSON file
|
|
71
|
+
if [[ "$target_file" == *.json ]]; then
|
|
72
|
+
if ! python3 -c "import json; json.load(open('$temp_file'))" 2>/dev/null; then
|
|
73
|
+
echo "Invalid JSON in temp file: $temp_file"
|
|
74
|
+
rm -f "$temp_file"
|
|
75
|
+
return 1
|
|
76
|
+
fi
|
|
77
|
+
fi
|
|
78
|
+
|
|
79
|
+
# Atomic rename (overwrites target if exists)
|
|
80
|
+
if ! mv "$temp_file" "$target_file"; then
|
|
81
|
+
echo "Failed to rename temp file to target: $target_file"
|
|
82
|
+
rm -f "$temp_file"
|
|
83
|
+
return 1
|
|
84
|
+
fi
|
|
85
|
+
|
|
86
|
+
# Sync to disk
|
|
87
|
+
if command -v sync >/dev/null 2>&1; then
|
|
88
|
+
sync "$target_file" 2>/dev/null || true
|
|
89
|
+
fi
|
|
90
|
+
|
|
91
|
+
return 0
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
# Atomic write from source file to target
|
|
95
|
+
# Arguments: target_file, source_file
|
|
96
|
+
# Returns: 0 on success, 1 on failure
|
|
97
|
+
atomic_write_from_file() {
|
|
98
|
+
local target_file="$1"
|
|
99
|
+
local source_file="$2"
|
|
100
|
+
|
|
101
|
+
if [ ! -f "$source_file" ]; then
|
|
102
|
+
echo "Source file does not exist: $source_file"
|
|
103
|
+
return 1
|
|
104
|
+
fi
|
|
105
|
+
|
|
106
|
+
# Ensure target directory exists
|
|
107
|
+
local target_dir=$(dirname "$target_file")
|
|
108
|
+
mkdir -p "$target_dir"
|
|
109
|
+
|
|
110
|
+
# Create unique temp file
|
|
111
|
+
local temp_file="${TEMP_DIR}/$(basename "$target_file").$$.$(date +%s%N).tmp"
|
|
112
|
+
|
|
113
|
+
# Copy source to temp
|
|
114
|
+
if ! cp "$source_file" "$temp_file"; then
|
|
115
|
+
echo "Failed to copy source to temp: $source_file -> $temp_file"
|
|
116
|
+
rm -f "$temp_file"
|
|
117
|
+
return 1
|
|
118
|
+
fi
|
|
119
|
+
|
|
120
|
+
# Create backup BEFORE validation (mirrors atomic_write ordering — LOCK-03)
|
|
121
|
+
if [ -f "$target_file" ]; then
|
|
122
|
+
create_backup "$target_file"
|
|
123
|
+
fi
|
|
124
|
+
|
|
125
|
+
# Validate JSON if it's a JSON file
|
|
126
|
+
if [[ "$target_file" == *.json ]]; then
|
|
127
|
+
if ! python3 -c "import json; json.load(open('$temp_file'))" 2>/dev/null; then
|
|
128
|
+
echo "Invalid JSON in temp file: $temp_file"
|
|
129
|
+
rm -f "$temp_file"
|
|
130
|
+
return 1
|
|
131
|
+
fi
|
|
132
|
+
fi
|
|
133
|
+
|
|
134
|
+
# Atomic rename
|
|
135
|
+
if ! mv "$temp_file" "$target_file"; then
|
|
136
|
+
echo "Failed to rename temp file to target: $target_file"
|
|
137
|
+
rm -f "$temp_file"
|
|
138
|
+
return 1
|
|
139
|
+
fi
|
|
140
|
+
|
|
141
|
+
# Sync to disk
|
|
142
|
+
if command -v sync >/dev/null 2>&1; then
|
|
143
|
+
sync "$target_file" 2>/dev/null || true
|
|
144
|
+
fi
|
|
145
|
+
|
|
146
|
+
return 0
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
# Create backup of file
|
|
150
|
+
# Arguments: file_path
|
|
151
|
+
create_backup() {
|
|
152
|
+
local file_path="$1"
|
|
153
|
+
local base_name=$(basename "$file_path")
|
|
154
|
+
local timestamp=$(date +%Y%m%d_%H%M%S)
|
|
155
|
+
local backup_file="${BACKUP_DIR}/${base_name}.${timestamp}.backup"
|
|
156
|
+
|
|
157
|
+
cp "$file_path" "$backup_file" 2>/dev/null || return 1
|
|
158
|
+
|
|
159
|
+
# Rotate old backups
|
|
160
|
+
rotate_backups "$base_name"
|
|
161
|
+
|
|
162
|
+
return 0
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
# Rotate backups, keeping only MAX_BACKUPS
|
|
166
|
+
# Arguments: base_name
|
|
167
|
+
rotate_backups() {
|
|
168
|
+
local base_name="$1"
|
|
169
|
+
local backups=$(ls -t "${BACKUP_DIR}/${base_name}".*.backup 2>/dev/null | wc -l)
|
|
170
|
+
|
|
171
|
+
if [ "$backups" -gt "$MAX_BACKUPS" ]; then
|
|
172
|
+
ls -t "${BACKUP_DIR}/${base_name}".*.backup 2>/dev/null \
|
|
173
|
+
| tail -n +$((MAX_BACKUPS + 1)) \
|
|
174
|
+
| while IFS= read -r file; do rm -f "$file"; done
|
|
175
|
+
fi
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
# Restore from backup
|
|
179
|
+
# Arguments: target_file, [backup_number]
|
|
180
|
+
# Returns: 0 on success, 1 on failure
|
|
181
|
+
restore_backup() {
|
|
182
|
+
local target_file="$1"
|
|
183
|
+
local backup_num="${2:-1}" # Default to most recent backup
|
|
184
|
+
local base_name=$(basename "$target_file")
|
|
185
|
+
|
|
186
|
+
local backup_file=$(ls -t "${BACKUP_DIR}/${base_name}".*.backup 2>/dev/null | sed -n "${backup_num}p")
|
|
187
|
+
|
|
188
|
+
if [ -z "$backup_file" ] || [ ! -f "$backup_file" ]; then
|
|
189
|
+
echo "No backup found for: $target_file"
|
|
190
|
+
return 1
|
|
191
|
+
fi
|
|
192
|
+
|
|
193
|
+
if ! atomic_write_from_file "$target_file" "$backup_file"; then
|
|
194
|
+
echo "Failed to restore from backup: $backup_file"
|
|
195
|
+
return 1
|
|
196
|
+
fi
|
|
197
|
+
|
|
198
|
+
echo "Restored from: $backup_file"
|
|
199
|
+
return 0
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
# List available backups
|
|
203
|
+
# Arguments: file_path
|
|
204
|
+
list_backups() {
|
|
205
|
+
local file_path="$1"
|
|
206
|
+
local base_name=$(basename "$file_path")
|
|
207
|
+
|
|
208
|
+
echo "Available backups for $base_name:"
|
|
209
|
+
ls -lh "${BACKUP_DIR}/${base_name}".*.backup 2>/dev/null || echo "No backups found"
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
# Cleanup temp files older than 1 hour
|
|
213
|
+
cleanup_temp_files() {
|
|
214
|
+
find "$TEMP_DIR" -name "*.tmp" -mtime +1/24 -delete 2>/dev/null || true
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
# Export functions
|
|
218
|
+
export -f atomic_write atomic_write_from_file create_backup rotate_backups
|
|
219
|
+
export -f restore_backup list_backups cleanup_temp_files
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Chamber comparison utilities
|
|
3
|
+
# Usage: bash chamber-compare.sh <chamber_a> <chamber_b>
|
|
4
|
+
|
|
5
|
+
set -euo pipefail
|
|
6
|
+
|
|
7
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
8
|
+
CHAMBERS_DIR="${CHAMBERS_DIR:-.aether/chambers}"
|
|
9
|
+
|
|
10
|
+
# Source error-handler.sh for E_* constants and enhanced json_err
|
|
11
|
+
[[ -f "$SCRIPT_DIR/error-handler.sh" ]] && source "$SCRIPT_DIR/error-handler.sh"
|
|
12
|
+
|
|
13
|
+
# Fallback E_* constants (no-ops when error-handler.sh is already loaded)
|
|
14
|
+
: "${E_UNKNOWN:=E_UNKNOWN}"
|
|
15
|
+
: "${E_FILE_NOT_FOUND:=E_FILE_NOT_FOUND}"
|
|
16
|
+
: "${E_VALIDATION_FAILED:=E_VALIDATION_FAILED}"
|
|
17
|
+
|
|
18
|
+
# JSON output helpers
|
|
19
|
+
json_ok() { printf '{"ok":true,"result":%s}\n' "$1"; }
|
|
20
|
+
|
|
21
|
+
# Guard: yield to error-handler.sh's enhanced json_err when already loaded
|
|
22
|
+
if ! type json_err &>/dev/null; then
|
|
23
|
+
json_err() {
|
|
24
|
+
local code="${1:-E_UNKNOWN}"
|
|
25
|
+
local message="${2:-An unknown error occurred}"
|
|
26
|
+
printf '{"ok":false,"error":{"code":"%s","message":"%s"}}\n' "$code" "$message" >&2
|
|
27
|
+
exit 1
|
|
28
|
+
}
|
|
29
|
+
fi
|
|
30
|
+
|
|
31
|
+
# Load chamber manifest
|
|
32
|
+
load_chamber() {
|
|
33
|
+
local chamber_name="$1"
|
|
34
|
+
local manifest_file="$CHAMBERS_DIR/$chamber_name/manifest.json"
|
|
35
|
+
|
|
36
|
+
if [[ ! -f "$manifest_file" ]]; then
|
|
37
|
+
json_err "$E_FILE_NOT_FOUND" "Chamber not found: $chamber_name. Try: check the chamber name with /ant:tunnels."
|
|
38
|
+
fi
|
|
39
|
+
|
|
40
|
+
cat "$manifest_file"
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
# Compare two chambers
|
|
44
|
+
cmd="${1:-help}"
|
|
45
|
+
shift 2>/dev/null || true
|
|
46
|
+
|
|
47
|
+
case "$cmd" in
|
|
48
|
+
help)
|
|
49
|
+
cat <<'EOF'
|
|
50
|
+
{"ok":true,"commands":["compare","diff","stats"],"description":"Chamber comparison utilities"}
|
|
51
|
+
EOF
|
|
52
|
+
;;
|
|
53
|
+
|
|
54
|
+
compare)
|
|
55
|
+
chamber_a="${1:-}"
|
|
56
|
+
chamber_b="${2:-}"
|
|
57
|
+
[[ -z "$chamber_a" || -z "$chamber_b" ]] && json_err "$E_VALIDATION_FAILED" "Missing arguments. Try: compare <chamber_a> <chamber_b>."
|
|
58
|
+
|
|
59
|
+
# Load both manifests
|
|
60
|
+
manifest_a=$(load_chamber "$chamber_a")
|
|
61
|
+
manifest_b=$(load_chamber "$chamber_b")
|
|
62
|
+
|
|
63
|
+
# Extract key fields for comparison
|
|
64
|
+
result=$(jq -n \
|
|
65
|
+
--arg a_name "$chamber_a" \
|
|
66
|
+
--arg b_name "$chamber_b" \
|
|
67
|
+
--argjson a "$manifest_a" \
|
|
68
|
+
--argjson b "$manifest_b" \
|
|
69
|
+
'{
|
|
70
|
+
chamber_a: {
|
|
71
|
+
name: $a_name,
|
|
72
|
+
goal: $a.goal,
|
|
73
|
+
milestone: $a.milestone,
|
|
74
|
+
version: $a.version,
|
|
75
|
+
phases_completed: $a.phases_completed,
|
|
76
|
+
total_phases: $a.total_phases,
|
|
77
|
+
entombed_at: $a.entombed_at,
|
|
78
|
+
decisions_count: ($a.decisions | length),
|
|
79
|
+
learnings_count: ($a.learnings | length)
|
|
80
|
+
},
|
|
81
|
+
chamber_b: {
|
|
82
|
+
name: $b_name,
|
|
83
|
+
goal: $b.goal,
|
|
84
|
+
milestone: $b.milestone,
|
|
85
|
+
version: $b.version,
|
|
86
|
+
phases_completed: $b.phases_completed,
|
|
87
|
+
total_phases: $b.total_phases,
|
|
88
|
+
entombed_at: $b.entombed_at,
|
|
89
|
+
decisions_count: ($b.decisions | length),
|
|
90
|
+
learnings_count: ($b.learnings | length)
|
|
91
|
+
},
|
|
92
|
+
comparison: {
|
|
93
|
+
phases_diff: ($b.phases_completed - $a.phases_completed),
|
|
94
|
+
decisions_diff: (($b.decisions | length) - ($a.decisions | length)),
|
|
95
|
+
learnings_diff: (($b.learnings | length) - ($a.learnings | length)),
|
|
96
|
+
same_milestone: ($a.milestone == $b.milestone),
|
|
97
|
+
time_between: (
|
|
98
|
+
(($b.entombed_at | fromdateiso8601) - ($a.entombed_at | fromdateiso8601)) / 86400 | floor
|
|
99
|
+
)
|
|
100
|
+
}
|
|
101
|
+
}')
|
|
102
|
+
|
|
103
|
+
json_ok "$result"
|
|
104
|
+
;;
|
|
105
|
+
|
|
106
|
+
diff)
|
|
107
|
+
chamber_a="${1:-}"
|
|
108
|
+
chamber_b="${2:-}"
|
|
109
|
+
[[ -z "$chamber_a" || -z "$chamber_b" ]] && json_err "$E_VALIDATION_FAILED" "Missing arguments. Try: diff <chamber_a> <chamber_b>."
|
|
110
|
+
|
|
111
|
+
manifest_a=$(load_chamber "$chamber_a")
|
|
112
|
+
manifest_b=$(load_chamber "$chamber_b")
|
|
113
|
+
|
|
114
|
+
# Find decisions in B but not in A (new decisions)
|
|
115
|
+
# Find learnings in B but not in A (new learnings)
|
|
116
|
+
result=$(jq -n \
|
|
117
|
+
--arg a_name "$chamber_a" \
|
|
118
|
+
--arg b_name "$chamber_b" \
|
|
119
|
+
--argjson a "$manifest_a" \
|
|
120
|
+
--argjson b "$manifest_b" \
|
|
121
|
+
'{
|
|
122
|
+
new_decisions: [
|
|
123
|
+
$b.decisions[] | select(
|
|
124
|
+
.content as $content |
|
|
125
|
+
$a.decisions | map(.content) | contains([$content]) | not
|
|
126
|
+
)
|
|
127
|
+
],
|
|
128
|
+
new_learnings: [
|
|
129
|
+
$b.learnings[] | select(
|
|
130
|
+
.content as $content |
|
|
131
|
+
$a.learnings | map(.content) | contains([$content]) | not
|
|
132
|
+
)
|
|
133
|
+
],
|
|
134
|
+
preserved_decisions: [
|
|
135
|
+
$a.decisions[] | select(
|
|
136
|
+
.content as $content |
|
|
137
|
+
$b.decisions | map(.content) | contains([$content])
|
|
138
|
+
)
|
|
139
|
+
],
|
|
140
|
+
preserved_learnings: [
|
|
141
|
+
$a.learnings[] | select(
|
|
142
|
+
.content as $content |
|
|
143
|
+
$b.learnings | map(.content) | contains([$content])
|
|
144
|
+
)
|
|
145
|
+
]
|
|
146
|
+
}')
|
|
147
|
+
|
|
148
|
+
json_ok "$result"
|
|
149
|
+
;;
|
|
150
|
+
|
|
151
|
+
stats)
|
|
152
|
+
chamber_a="${1:-}"
|
|
153
|
+
chamber_b="${2:-}"
|
|
154
|
+
[[ -z "$chamber_a" || -z "$chamber_b" ]] && json_err "$E_VALIDATION_FAILED" "Missing arguments. Try: stats <chamber_a> <chamber_b>."
|
|
155
|
+
|
|
156
|
+
manifest_a=$(load_chamber "$chamber_a")
|
|
157
|
+
manifest_b=$(load_chamber "$chamber_b")
|
|
158
|
+
|
|
159
|
+
# Calculate detailed statistics
|
|
160
|
+
result=$(jq -n \
|
|
161
|
+
--arg a_name "$chamber_a" \
|
|
162
|
+
--arg b_name "$chamber_b" \
|
|
163
|
+
--argjson a "$manifest_a" \
|
|
164
|
+
--argjson b "$manifest_b" \
|
|
165
|
+
'{
|
|
166
|
+
summary: {
|
|
167
|
+
a_phases: $a.phases_completed,
|
|
168
|
+
b_phases: $b.phases_completed,
|
|
169
|
+
growth: "\($b.phases_completed - $a.phases_completed) phases",
|
|
170
|
+
a_duration_days: null,
|
|
171
|
+
b_duration_days: null
|
|
172
|
+
},
|
|
173
|
+
knowledge_transfer: {
|
|
174
|
+
decisions_preserved: ($a.decisions | map(.content) | intersection($b.decisions | map(.content)) | length),
|
|
175
|
+
decisions_new: ($b.decisions | map(.content) - ($a.decisions | map(.content)) | length),
|
|
176
|
+
learnings_preserved: ($a.learnings | map(.content) | intersection($b.learnings | map(.content)) | length),
|
|
177
|
+
learnings_new: ($b.learnings | map(.content) - ($a.learnings | map(.content)) | length)
|
|
178
|
+
},
|
|
179
|
+
evolution: {
|
|
180
|
+
milestone_changed: ($a.milestone != $b.milestone),
|
|
181
|
+
from_milestone: $a.milestone,
|
|
182
|
+
to_milestone: $b.milestone,
|
|
183
|
+
version_delta: "\($a.version) → \($b.version)"
|
|
184
|
+
}
|
|
185
|
+
}')
|
|
186
|
+
|
|
187
|
+
json_ok "$result"
|
|
188
|
+
;;
|
|
189
|
+
|
|
190
|
+
*)
|
|
191
|
+
json_err "$E_VALIDATION_FAILED" "Unknown command: $cmd. Try: compare, diff, or stats."
|
|
192
|
+
;;
|
|
193
|
+
esac
|