aether-colony 3.1.17 → 5.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/aether-utils.sh +5354 -0
- package/.aether/agents-claude/aether-ambassador.md +265 -0
- package/.aether/agents-claude/aether-archaeologist.md +327 -0
- package/.aether/agents-claude/aether-architect.md +236 -0
- package/.aether/agents-claude/aether-auditor.md +271 -0
- package/.aether/agents-claude/aether-builder.md +224 -0
- package/.aether/agents-claude/aether-chaos.md +269 -0
- package/.aether/agents-claude/aether-chronicler.md +305 -0
- package/.aether/agents-claude/aether-gatekeeper.md +330 -0
- package/.aether/agents-claude/aether-includer.md +374 -0
- package/.aether/agents-claude/aether-keeper.md +272 -0
- package/.aether/agents-claude/aether-measurer.md +322 -0
- package/.aether/agents-claude/aether-oracle.md +237 -0
- package/.aether/agents-claude/aether-probe.md +211 -0
- package/.aether/agents-claude/aether-queen.md +330 -0
- package/.aether/agents-claude/aether-route-setter.md +178 -0
- package/.aether/agents-claude/aether-sage.md +418 -0
- package/.aether/agents-claude/aether-scout.md +179 -0
- package/.aether/agents-claude/aether-surveyor-disciplines.md +417 -0
- package/.aether/agents-claude/aether-surveyor-nest.md +355 -0
- package/.aether/agents-claude/aether-surveyor-pathogens.md +289 -0
- package/.aether/agents-claude/aether-surveyor-provisions.md +360 -0
- package/.aether/agents-claude/aether-tracker.md +270 -0
- package/.aether/agents-claude/aether-watcher.md +280 -0
- package/.aether/agents-claude/aether-weaver.md +248 -0
- package/.aether/commands/archaeology.yaml +653 -0
- package/.aether/commands/build.yaml +1221 -0
- package/.aether/commands/chaos.yaml +653 -0
- package/.aether/commands/colonize.yaml +438 -0
- package/.aether/commands/continue.yaml +1484 -0
- package/.aether/commands/council.yaml +304 -0
- package/.aether/commands/data-clean.yaml +80 -0
- package/.aether/commands/dream.yaml +275 -0
- package/.aether/commands/entomb.yaml +863 -0
- package/.aether/commands/export-signals.yaml +64 -0
- package/.aether/commands/feedback.yaml +158 -0
- package/.aether/commands/flag.yaml +160 -0
- package/.aether/commands/flags.yaml +177 -0
- package/.aether/commands/focus.yaml +112 -0
- package/.aether/commands/help.yaml +167 -0
- package/.aether/commands/history.yaml +137 -0
- package/.aether/commands/import-signals.yaml +79 -0
- package/.aether/commands/init.yaml +469 -0
- package/.aether/commands/insert-phase.yaml +98 -0
- package/.aether/commands/interpret.yaml +285 -0
- package/.aether/commands/lay-eggs.yaml +224 -0
- package/.aether/commands/maturity.yaml +122 -0
- package/.aether/commands/memory-details.yaml +74 -0
- package/.aether/commands/migrate-state.yaml +174 -0
- package/.aether/commands/oracle.yaml +1224 -0
- package/.aether/commands/organize.yaml +446 -0
- package/.aether/commands/patrol.yaml +621 -0
- package/.aether/commands/pause-colony.yaml +424 -0
- package/.aether/commands/phase.yaml +124 -0
- package/.aether/commands/pheromones.yaml +153 -0
- package/.aether/commands/plan.yaml +1313 -0
- package/.aether/commands/preferences.yaml +63 -0
- package/.aether/commands/redirect.yaml +123 -0
- package/.aether/commands/resume-colony.yaml +373 -0
- package/.aether/commands/resume.yaml +398 -0
- package/.aether/commands/run.yaml +193 -0
- package/.aether/commands/seal.yaml +1205 -0
- package/.aether/commands/skill-create.yaml +337 -0
- package/.aether/commands/status.yaml +364 -0
- package/.aether/commands/swarm.yaml +352 -0
- package/.aether/commands/tunnels.yaml +814 -0
- package/.aether/commands/update.yaml +131 -0
- package/.aether/commands/verify-castes.yaml +159 -0
- package/.aether/commands/watch.yaml +454 -0
- package/.aether/docs/INCIDENT_TEMPLATE.md +32 -0
- package/.aether/docs/QUEEN-SYSTEM.md +211 -0
- package/.aether/docs/README.md +98 -0
- package/.aether/docs/caste-system.md +48 -0
- package/.aether/docs/command-playbooks/README.md +23 -0
- package/.aether/docs/command-playbooks/build-complete.md +349 -0
- package/.aether/docs/command-playbooks/build-context.md +282 -0
- package/.aether/docs/command-playbooks/build-full.md +1682 -0
- package/.aether/docs/command-playbooks/build-prep.md +283 -0
- package/.aether/docs/command-playbooks/build-verify.md +405 -0
- package/.aether/docs/command-playbooks/build-wave.md +749 -0
- package/.aether/docs/command-playbooks/continue-advance.md +524 -0
- package/.aether/docs/command-playbooks/continue-finalize.md +447 -0
- package/.aether/docs/command-playbooks/continue-full.md +1724 -0
- package/.aether/docs/command-playbooks/continue-gates.md +686 -0
- package/.aether/docs/command-playbooks/continue-verify.md +406 -0
- package/.aether/docs/context-continuity.md +84 -0
- package/{runtime → .aether/docs/disciplines}/DISCIPLINES.md +13 -11
- package/.aether/docs/error-codes.md +268 -0
- package/.aether/docs/known-issues.md +94 -0
- package/{runtime → .aether}/docs/pheromones.md +86 -6
- package/.aether/docs/plans/pheromone-display-plan.md +257 -0
- package/.aether/docs/queen-commands.md +98 -0
- package/.aether/docs/source-of-truth-map.md +132 -0
- package/.aether/docs/xml-utilities.md +47 -0
- package/{runtime → .aether}/exchange/pheromone-xml.sh +2 -1
- package/{runtime → .aether}/exchange/registry-xml.sh +7 -3
- package/{runtime → .aether}/exchange/wisdom-xml.sh +11 -4
- package/.aether/rules/aether-colony.md +144 -0
- package/.aether/schemas/example-prompt-builder.xml +234 -0
- package/.aether/scripts/incident-test-add.sh +47 -0
- package/.aether/scripts/weekly-audit.sh +79 -0
- package/.aether/skills/.index.json +649 -0
- package/.aether/skills/colony/.manifest.json +16 -0
- package/.aether/skills/colony/build-discipline/SKILL.md +78 -0
- package/.aether/skills/colony/colony-interaction/SKILL.md +56 -0
- package/.aether/skills/colony/colony-lifecycle/SKILL.md +77 -0
- package/.aether/skills/colony/colony-visuals/SKILL.md +112 -0
- package/.aether/skills/colony/context-management/SKILL.md +80 -0
- package/.aether/skills/colony/error-presentation/SKILL.md +99 -0
- package/.aether/skills/colony/pheromone-protocol/SKILL.md +79 -0
- package/.aether/skills/colony/pheromone-visibility/SKILL.md +81 -0
- package/.aether/skills/colony/state-safety/SKILL.md +84 -0
- package/.aether/skills/colony/worker-priming/SKILL.md +82 -0
- package/.aether/skills/domain/.manifest.json +24 -0
- package/.aether/skills/domain/README.md +33 -0
- package/.aether/skills/domain/django/SKILL.md +49 -0
- package/.aether/skills/domain/docker/SKILL.md +52 -0
- package/.aether/skills/domain/golang/SKILL.md +52 -0
- package/.aether/skills/domain/graphql/SKILL.md +51 -0
- package/.aether/skills/domain/html-css/SKILL.md +48 -0
- package/.aether/skills/domain/nextjs/SKILL.md +45 -0
- package/.aether/skills/domain/nodejs/SKILL.md +53 -0
- package/.aether/skills/domain/postgresql/SKILL.md +53 -0
- package/.aether/skills/domain/prisma/SKILL.md +59 -0
- package/.aether/skills/domain/python/SKILL.md +50 -0
- package/.aether/skills/domain/rails/SKILL.md +52 -0
- package/.aether/skills/domain/react/SKILL.md +45 -0
- package/.aether/skills/domain/rest-api/SKILL.md +58 -0
- package/.aether/skills/domain/svelte/SKILL.md +47 -0
- package/.aether/skills/domain/tailwind/SKILL.md +45 -0
- package/.aether/skills/domain/testing/SKILL.md +53 -0
- package/.aether/skills/domain/typescript/SKILL.md +58 -0
- package/.aether/skills/domain/vue/SKILL.md +49 -0
- package/.aether/templates/QUEEN.md.template +61 -0
- package/.aether/templates/colony-state-reset.jq.template +23 -0
- package/.aether/templates/colony-state.template.json +39 -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 +13 -0
- package/.aether/templates/pheromones.template.json +6 -0
- package/.aether/templates/session.template.json +9 -0
- package/{runtime → .aether}/utils/atomic-write.sh +68 -22
- package/{runtime → .aether}/utils/chamber-compare.sh +23 -10
- package/.aether/utils/chamber-utils.sh +440 -0
- package/.aether/utils/emoji-audit.sh +166 -0
- package/{runtime → .aether}/utils/error-handler.sh +34 -8
- package/.aether/utils/file-lock.sh +313 -0
- package/.aether/utils/flag.sh +267 -0
- package/.aether/utils/hive.sh +572 -0
- package/.aether/utils/learning.sh +1928 -0
- package/.aether/utils/midden.sh +342 -0
- package/.aether/utils/oracle/oracle.md +168 -0
- package/.aether/utils/oracle/oracle.sh +1023 -0
- package/.aether/utils/pheromone.sh +2029 -0
- package/.aether/utils/queen.sh +1698 -0
- package/.aether/utils/scan.sh +860 -0
- package/.aether/utils/semantic-cli.sh +415 -0
- package/.aether/utils/session.sh +552 -0
- package/.aether/utils/skills.sh +509 -0
- package/.aether/utils/spawn-tree.sh +260 -0
- package/.aether/utils/spawn.sh +260 -0
- package/.aether/utils/state-api.sh +199 -0
- package/{runtime → .aether}/utils/state-loader.sh +8 -6
- package/.aether/utils/suggest.sh +611 -0
- package/{runtime → .aether}/utils/swarm-display.sh +10 -1
- package/.aether/utils/swarm.sh +1004 -0
- package/{runtime → .aether}/utils/watch-spawn-tree.sh +11 -2
- package/{runtime → .aether}/utils/xml-compose.sh +9 -3
- package/.aether/utils/xml-convert.sh +277 -0
- package/{runtime → .aether}/utils/xml-core.sh +5 -9
- package/.aether/utils/xml-query.sh +201 -0
- package/.aether/utils/xml-utils.sh +110 -0
- package/{runtime → .aether}/workers.md +97 -81
- package/.claude/agents/ant/aether-ambassador.md +265 -0
- package/.claude/agents/ant/aether-archaeologist.md +327 -0
- package/.claude/agents/ant/aether-architect.md +236 -0
- package/.claude/agents/ant/aether-auditor.md +271 -0
- package/.claude/agents/ant/aether-builder.md +224 -0
- package/.claude/agents/ant/aether-chaos.md +269 -0
- package/.claude/agents/ant/aether-chronicler.md +305 -0
- package/.claude/agents/ant/aether-gatekeeper.md +330 -0
- package/.claude/agents/ant/aether-includer.md +374 -0
- package/.claude/agents/ant/aether-keeper.md +272 -0
- package/.claude/agents/ant/aether-measurer.md +322 -0
- package/.claude/agents/ant/aether-oracle.md +237 -0
- package/.claude/agents/ant/aether-probe.md +211 -0
- package/.claude/agents/ant/aether-queen.md +330 -0
- package/.claude/agents/ant/aether-route-setter.md +178 -0
- package/.claude/agents/ant/aether-sage.md +418 -0
- package/.claude/agents/ant/aether-scout.md +179 -0
- package/.claude/agents/ant/aether-surveyor-disciplines.md +417 -0
- package/.claude/agents/ant/aether-surveyor-nest.md +355 -0
- package/.claude/agents/ant/aether-surveyor-pathogens.md +289 -0
- package/.claude/agents/ant/aether-surveyor-provisions.md +360 -0
- package/.claude/agents/ant/aether-tracker.md +270 -0
- package/.claude/agents/ant/aether-watcher.md +280 -0
- package/.claude/agents/ant/aether-weaver.md +248 -0
- package/.claude/commands/ant/archaeology.md +16 -14
- package/.claude/commands/ant/build.md +43 -1028
- package/.claude/commands/ant/chaos.md +19 -23
- package/.claude/commands/ant/colonize.md +52 -31
- package/.claude/commands/ant/continue.md +40 -1016
- package/.claude/commands/ant/council.md +21 -18
- package/.claude/commands/ant/data-clean.md +81 -0
- package/.claude/commands/ant/dream.md +27 -15
- package/.claude/commands/ant/entomb.md +317 -225
- package/.claude/commands/ant/export-signals.md +57 -0
- package/.claude/commands/ant/feedback.md +48 -26
- package/.claude/commands/ant/flag.md +30 -10
- package/.claude/commands/ant/flags.md +34 -12
- package/.claude/commands/ant/focus.md +45 -19
- package/.claude/commands/ant/help.md +50 -8
- package/.claude/commands/ant/history.md +13 -0
- package/.claude/commands/ant/import-signals.md +71 -0
- package/.claude/commands/ant/init.md +345 -194
- package/.claude/commands/ant/insert-phase.md +101 -0
- package/.claude/commands/ant/interpret.md +26 -4
- package/.claude/commands/ant/lay-eggs.md +184 -127
- package/.claude/commands/ant/maturity.md +32 -11
- package/.claude/commands/ant/memory-details.md +77 -0
- package/.claude/commands/ant/migrate-state.md +20 -2
- package/.claude/commands/ant/oracle.md +337 -74
- package/.claude/commands/ant/organize.md +39 -25
- package/.claude/commands/ant/patrol.md +620 -0
- package/.claude/commands/ant/pause-colony.md +23 -27
- package/.claude/commands/ant/phase.md +40 -42
- package/.claude/commands/ant/pheromones.md +156 -0
- package/.claude/commands/ant/plan.md +185 -51
- package/.claude/commands/ant/preferences.md +65 -0
- package/.claude/commands/ant/redirect.md +45 -30
- package/.claude/commands/ant/resume-colony.md +51 -27
- package/.claude/commands/ant/resume.md +314 -94
- package/.claude/commands/ant/run.md +195 -0
- package/.claude/commands/ant/seal.md +650 -221
- package/.claude/commands/ant/skill-create.md +286 -0
- package/.claude/commands/ant/status.md +196 -31
- package/.claude/commands/ant/swarm.md +16 -46
- package/.claude/commands/ant/tunnels.md +280 -105
- package/.claude/commands/ant/update.md +73 -89
- package/.claude/commands/ant/verify-castes.md +100 -42
- package/.claude/commands/ant/watch.md +14 -12
- package/.opencode/agents/aether-ambassador.md +63 -20
- package/.opencode/agents/aether-archaeologist.md +29 -12
- package/.opencode/agents/aether-architect.md +103 -36
- package/.opencode/agents/aether-auditor.md +51 -18
- package/.opencode/agents/aether-builder.md +70 -20
- package/.opencode/agents/aether-chaos.md +29 -12
- package/.opencode/agents/aether-chronicler.md +60 -18
- package/.opencode/agents/aether-gatekeeper.md +27 -18
- package/.opencode/agents/aether-includer.md +27 -18
- package/.opencode/agents/aether-keeper.md +89 -18
- package/.opencode/agents/aether-measurer.md +27 -18
- package/.opencode/agents/aether-oracle.md +137 -0
- package/.opencode/agents/aether-probe.md +60 -18
- package/.opencode/agents/aether-queen.md +172 -24
- package/.opencode/agents/aether-route-setter.md +57 -12
- package/.opencode/agents/aether-sage.md +26 -18
- package/.opencode/agents/aether-scout.md +28 -20
- package/.opencode/agents/aether-surveyor-disciplines.md +59 -2
- package/.opencode/agents/aether-surveyor-nest.md +59 -2
- package/.opencode/agents/aether-surveyor-pathogens.md +57 -2
- package/.opencode/agents/aether-surveyor-provisions.md +59 -2
- package/.opencode/agents/aether-tracker.md +64 -18
- package/.opencode/agents/aether-watcher.md +66 -19
- package/.opencode/agents/aether-weaver.md +61 -18
- package/.opencode/commands/ant/archaeology.md +7 -14
- package/.opencode/commands/ant/build.md +437 -257
- package/.opencode/commands/ant/chaos.md +7 -24
- package/.opencode/commands/ant/colonize.md +8 -17
- package/.opencode/commands/ant/continue.md +661 -142
- package/.opencode/commands/ant/council.md +11 -22
- package/.opencode/commands/ant/data-clean.md +77 -0
- package/.opencode/commands/ant/dream.md +15 -17
- package/.opencode/commands/ant/entomb.md +133 -62
- package/.opencode/commands/ant/export-signals.md +54 -0
- package/.opencode/commands/ant/feedback.md +24 -5
- package/.opencode/commands/ant/flag.md +16 -4
- package/.opencode/commands/ant/flags.md +24 -10
- package/.opencode/commands/ant/focus.md +22 -5
- package/.opencode/commands/ant/help.md +41 -8
- package/.opencode/commands/ant/history.md +9 -0
- package/.opencode/commands/ant/import-signals.md +68 -0
- package/.opencode/commands/ant/init.md +374 -167
- package/.opencode/commands/ant/insert-phase.md +107 -0
- package/.opencode/commands/ant/interpret.md +16 -0
- package/.opencode/commands/ant/lay-eggs.md +184 -112
- package/.opencode/commands/ant/maturity.md +18 -2
- package/.opencode/commands/ant/memory-details.md +83 -0
- package/.opencode/commands/ant/migrate-state.md +12 -0
- package/.opencode/commands/ant/oracle.md +322 -67
- package/.opencode/commands/ant/organize.md +18 -16
- package/.opencode/commands/ant/patrol.md +626 -0
- package/.opencode/commands/ant/pause-colony.md +12 -29
- package/.opencode/commands/ant/phase.md +30 -40
- package/.opencode/commands/ant/pheromones.md +162 -0
- package/.opencode/commands/ant/plan.md +184 -56
- package/.opencode/commands/ant/preferences.md +71 -0
- package/.opencode/commands/ant/redirect.md +22 -5
- package/.opencode/commands/ant/resume-colony.md +38 -27
- package/.opencode/commands/ant/resume.md +385 -0
- package/.opencode/commands/ant/run.md +201 -0
- package/.opencode/commands/ant/seal.md +259 -45
- package/.opencode/commands/ant/skill-create.md +63 -0
- package/.opencode/commands/ant/status.md +135 -31
- package/.opencode/commands/ant/swarm.md +3 -345
- package/.opencode/commands/ant/tunnels.md +152 -9
- package/.opencode/commands/ant/update.md +70 -91
- package/.opencode/commands/ant/verify-castes.md +96 -42
- package/.opencode/commands/ant/watch.md +7 -0
- package/CHANGELOG.md +356 -0
- package/README.md +203 -573
- package/bin/cli.js +455 -527
- package/bin/generate-commands.js +186 -0
- package/bin/generate-commands.sh +127 -88
- package/bin/lib/init.js +13 -3
- package/bin/lib/spawn-logger.js +0 -15
- package/bin/lib/update-transaction.js +392 -140
- package/bin/npx-install.js +178 -0
- package/bin/sync-to-runtime.sh +5 -137
- package/bin/validate-package.sh +166 -0
- package/package.json +14 -7
- package/.opencode/agents/aether-guardian.md +0 -107
- package/.opencode/agents/workers.md +0 -1034
- package/bin/lib/model-profiles.js +0 -445
- package/bin/lib/model-verify.js +0 -288
- package/bin/lib/proxy-health.js +0 -253
- package/bin/lib/telemetry.js +0 -441
- package/runtime/CONTEXT.md +0 -160
- package/runtime/QUEEN_ANT_ARCHITECTURE.md +0 -402
- package/runtime/aether-utils.sh +0 -3879
- package/runtime/data/signatures.json +0 -41
- package/runtime/docs/AETHER-2.0-IMPLEMENTATION-PLAN.md +0 -1343
- package/runtime/docs/AETHER-PHEROMONE-SYSTEM-MASTER-SPEC.md +0 -2642
- package/runtime/docs/PHEROMONE-INJECTION.md +0 -240
- package/runtime/docs/PHEROMONE-INTEGRATION.md +0 -192
- package/runtime/docs/PHEROMONE-SYSTEM-DESIGN.md +0 -426
- package/runtime/docs/README.md +0 -94
- package/runtime/docs/VISUAL-OUTPUT-SPEC.md +0 -219
- package/runtime/docs/biological-reference.md +0 -272
- package/runtime/docs/codebase-review.md +0 -399
- package/runtime/docs/command-sync.md +0 -164
- package/runtime/docs/constraints.md +0 -116
- package/runtime/docs/implementation-learnings.md +0 -89
- package/runtime/docs/known-issues.md +0 -217
- package/runtime/docs/namespace.md +0 -148
- package/runtime/docs/pathogen-schema-example.json +0 -36
- package/runtime/docs/pathogen-schema.md +0 -111
- package/runtime/docs/planning-discipline.md +0 -159
- package/runtime/docs/progressive-disclosure.md +0 -184
- package/runtime/lib/queen-utils.sh +0 -729
- package/runtime/model-profiles.yaml +0 -100
- package/runtime/planning.md +0 -159
- package/runtime/recover.sh +0 -136
- package/runtime/templates/QUEEN.md.template +0 -79
- package/runtime/utils/chamber-utils.sh +0 -285
- package/runtime/utils/file-lock.sh +0 -122
- package/runtime/utils/spawn-tree.sh +0 -428
- package/runtime/utils/spawn-with-model.sh +0 -56
- package/runtime/utils/xml-utils.sh +0 -2196
- package/runtime/workers-new-castes.md +0 -516
- /package/{runtime → .aether/docs/disciplines}/coding-standards.md +0 -0
- /package/{runtime → .aether/docs/disciplines}/debugging.md +0 -0
- /package/{runtime → .aether/docs/disciplines}/learning.md +0 -0
- /package/{runtime → .aether/docs/disciplines}/tdd.md +0 -0
- /package/{runtime → .aether/docs/disciplines}/verification-loop.md +0 -0
- /package/{runtime → .aether/docs/disciplines}/verification.md +0 -0
- /package/{runtime → .aether}/schemas/aether-types.xsd +0 -0
- /package/{runtime → .aether}/schemas/colony-registry.xsd +0 -0
- /package/{runtime → .aether}/schemas/pheromone.xsd +0 -0
- /package/{runtime → .aether}/schemas/prompt.xsd +0 -0
- /package/{runtime → .aether}/schemas/queen-wisdom.xsd +0 -0
- /package/{runtime → .aether}/schemas/worker-priming.xsd +0 -0
- /package/{runtime → .aether}/utils/colorize-log.sh +0 -0
- /package/{runtime → .aether}/utils/queen-to-md.xsl +0 -0
package/bin/cli.js
CHANGED
|
@@ -22,31 +22,8 @@ const { logError, logActivity } = require('./lib/logger');
|
|
|
22
22
|
const { UpdateTransaction, UpdateError, UpdateErrorCodes } = require('./lib/update-transaction');
|
|
23
23
|
const { initializeRepo, isInitialized } = require('./lib/init');
|
|
24
24
|
const { syncStateFromPlanning, reconcileStates } = require('./lib/state-sync');
|
|
25
|
-
const { createVerificationReport } = require('./lib/model-verify');
|
|
26
|
-
const {
|
|
27
|
-
loadModelProfiles,
|
|
28
|
-
getAllAssignments,
|
|
29
|
-
getProviderForModel,
|
|
30
|
-
validateCaste,
|
|
31
|
-
validateModel,
|
|
32
|
-
setModelOverride,
|
|
33
|
-
resetModelOverride,
|
|
34
|
-
getEffectiveModel,
|
|
35
|
-
getUserOverrides,
|
|
36
|
-
getModelMetadata,
|
|
37
|
-
getProxyConfig,
|
|
38
|
-
} = require('./lib/model-profiles');
|
|
39
|
-
const {
|
|
40
|
-
checkProxyHealth,
|
|
41
|
-
verifyModelRouting,
|
|
42
|
-
formatProxyStatusColored,
|
|
43
|
-
} = require('./lib/proxy-health');
|
|
44
25
|
const { findNestmates, formatNestmates, loadNestmateTodos } = require('./lib/nestmate-loader');
|
|
45
26
|
const { logSpawn, formatSpawnTree } = require('./lib/spawn-logger');
|
|
46
|
-
const {
|
|
47
|
-
getTelemetrySummary,
|
|
48
|
-
getModelPerformance,
|
|
49
|
-
} = require('./lib/telemetry');
|
|
50
27
|
|
|
51
28
|
// Color palette
|
|
52
29
|
const c = require('./lib/colors');
|
|
@@ -65,14 +42,22 @@ if (!HOME) {
|
|
|
65
42
|
}
|
|
66
43
|
|
|
67
44
|
// Claude Code paths (global)
|
|
68
|
-
const COMMANDS_SRC = path.join(PACKAGE_DIR, 'commands', 'ant');
|
|
45
|
+
const COMMANDS_SRC = path.join(PACKAGE_DIR, '.claude', 'commands', 'ant');
|
|
69
46
|
const COMMANDS_DEST = path.join(HOME, '.claude', 'commands', 'ant');
|
|
47
|
+
const AGENTS_DEST = path.join(HOME, '.claude', 'agents', 'ant');
|
|
48
|
+
|
|
49
|
+
// OpenCode paths (global)
|
|
50
|
+
const OPENCODE_COMMANDS_DEST = path.join(HOME, '.opencode', 'command');
|
|
51
|
+
const OPENCODE_AGENTS_DEST = path.join(HOME, '.opencode', 'agent');
|
|
70
52
|
|
|
71
53
|
// Hub paths
|
|
72
54
|
const HUB_DIR = path.join(HOME, '.aether');
|
|
73
|
-
const
|
|
74
|
-
const
|
|
75
|
-
const
|
|
55
|
+
const HUB_SYSTEM_DIR = path.join(HUB_DIR, 'system');
|
|
56
|
+
const HUB_COMMANDS_CLAUDE = path.join(HUB_SYSTEM_DIR, 'commands', 'claude');
|
|
57
|
+
const HUB_COMMANDS_OPENCODE = path.join(HUB_SYSTEM_DIR, 'commands', 'opencode');
|
|
58
|
+
const HUB_AGENTS = path.join(HUB_SYSTEM_DIR, 'agents');
|
|
59
|
+
const HUB_AGENTS_CLAUDE = path.join(HUB_SYSTEM_DIR, 'agents-claude');
|
|
60
|
+
const HUB_RULES = path.join(HUB_SYSTEM_DIR, 'rules');
|
|
76
61
|
const HUB_REGISTRY = path.join(HUB_DIR, 'registry.json');
|
|
77
62
|
const HUB_VERSION = path.join(HUB_DIR, 'version.json');
|
|
78
63
|
|
|
@@ -374,41 +359,15 @@ function removeDirSync(dir) {
|
|
|
374
359
|
return count;
|
|
375
360
|
}
|
|
376
361
|
|
|
377
|
-
//
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
'coding-standards.md',
|
|
381
|
-
'debugging.md',
|
|
382
|
-
'DISCIPLINES.md',
|
|
383
|
-
'learning.md',
|
|
384
|
-
'planning.md',
|
|
385
|
-
'QUEEN_ANT_ARCHITECTURE.md',
|
|
386
|
-
'tdd.md',
|
|
387
|
-
'verification-loop.md',
|
|
388
|
-
'verification.md',
|
|
389
|
-
'workers.md',
|
|
390
|
-
'docs/constraints.md',
|
|
391
|
-
'docs/pathogen-schema-example.json',
|
|
392
|
-
'docs/pathogen-schema.md',
|
|
393
|
-
'docs/pheromones.md',
|
|
394
|
-
'docs/progressive-disclosure.md',
|
|
395
|
-
'utils/atomic-write.sh',
|
|
396
|
-
'utils/colorize-log.sh',
|
|
397
|
-
'utils/file-lock.sh',
|
|
398
|
-
'utils/watch-spawn-tree.sh',
|
|
399
|
-
];
|
|
400
|
-
|
|
401
|
-
function copySystemFiles(srcDir, destDir) {
|
|
362
|
+
// Remove only files from dest that exist in source (safe for shared directories)
|
|
363
|
+
function removeFilesFromSource(sourceDir, destDir) {
|
|
364
|
+
if (!fs.existsSync(sourceDir) || !fs.existsSync(destDir)) return 0;
|
|
402
365
|
let count = 0;
|
|
403
|
-
|
|
404
|
-
|
|
366
|
+
const sourceFiles = fs.readdirSync(sourceDir).filter(f => f.endsWith('.md'));
|
|
367
|
+
for (const file of sourceFiles) {
|
|
405
368
|
const destPath = path.join(destDir, file);
|
|
406
|
-
if (fs.existsSync(
|
|
407
|
-
fs.
|
|
408
|
-
fs.copyFileSync(srcPath, destPath);
|
|
409
|
-
if (file.endsWith('.sh')) {
|
|
410
|
-
fs.chmodSync(destPath, 0o755);
|
|
411
|
-
}
|
|
369
|
+
if (fs.existsSync(destPath)) {
|
|
370
|
+
fs.unlinkSync(destPath);
|
|
412
371
|
count++;
|
|
413
372
|
}
|
|
414
373
|
}
|
|
@@ -585,65 +544,15 @@ function computeFileHash(filePath) {
|
|
|
585
544
|
}
|
|
586
545
|
}
|
|
587
546
|
|
|
588
|
-
function syncSystemFilesWithCleanup(srcDir, destDir, opts) {
|
|
589
|
-
opts = opts || {};
|
|
590
|
-
const dryRun = opts.dryRun || false;
|
|
591
|
-
|
|
592
|
-
let copied = 0;
|
|
593
|
-
let skipped = 0;
|
|
594
|
-
for (const file of SYSTEM_FILES) {
|
|
595
|
-
const srcPath = path.join(srcDir, file);
|
|
596
|
-
const destPath = path.join(destDir, file);
|
|
597
|
-
if (fs.existsSync(srcPath)) {
|
|
598
|
-
if (!dryRun) {
|
|
599
|
-
// Compute hashes to determine if copy is needed
|
|
600
|
-
const srcHash = computeFileHash(srcPath);
|
|
601
|
-
const destHash = fs.existsSync(destPath) ? computeFileHash(destPath) : null;
|
|
602
|
-
|
|
603
|
-
if (srcHash === destHash) {
|
|
604
|
-
// Files are identical, skip copying
|
|
605
|
-
skipped++;
|
|
606
|
-
continue;
|
|
607
|
-
}
|
|
608
|
-
|
|
609
|
-
fs.mkdirSync(path.dirname(destPath), { recursive: true });
|
|
610
|
-
fs.copyFileSync(srcPath, destPath);
|
|
611
|
-
if (file.endsWith('.sh')) {
|
|
612
|
-
fs.chmodSync(destPath, 0o755);
|
|
613
|
-
}
|
|
614
|
-
}
|
|
615
|
-
copied++;
|
|
616
|
-
}
|
|
617
|
-
}
|
|
618
|
-
|
|
619
|
-
// Remove allowlisted files that no longer exist in src
|
|
620
|
-
const removed = [];
|
|
621
|
-
for (const file of SYSTEM_FILES) {
|
|
622
|
-
const srcPath = path.join(srcDir, file);
|
|
623
|
-
const destPath = path.join(destDir, file);
|
|
624
|
-
if (!fs.existsSync(srcPath) && fs.existsSync(destPath)) {
|
|
625
|
-
removed.push(file);
|
|
626
|
-
if (!dryRun) {
|
|
627
|
-
fs.unlinkSync(destPath);
|
|
628
|
-
}
|
|
629
|
-
}
|
|
630
|
-
}
|
|
631
|
-
|
|
632
|
-
if (!dryRun && removed.length > 0) {
|
|
633
|
-
cleanEmptyDirs(destDir);
|
|
634
|
-
}
|
|
635
|
-
|
|
636
|
-
return { copied, removed, skipped };
|
|
637
|
-
}
|
|
638
|
-
|
|
639
547
|
// Checkpoint allowlist - only these files are captured in checkpoints
|
|
640
548
|
// NEVER include: data/, dreams/, oracle/, TO-DOs.md (user data)
|
|
549
|
+
// Note: runtime/ was removed in v4.0 — .aether/ is published directly
|
|
641
550
|
const CHECKPOINT_ALLOWLIST = [
|
|
642
551
|
'.aether/*.md', // All .md files directly in .aether/
|
|
643
552
|
'.claude/commands/ant/**', // All files in .claude/commands/ant/ recursively
|
|
553
|
+
'.claude/agents/ant/**', // All files in .claude/agents/ant/ recursively
|
|
644
554
|
'.opencode/commands/ant/**', // All files in .opencode/commands/ant/ recursively
|
|
645
555
|
'.opencode/agents/**', // All files in .opencode/agents/ recursively
|
|
646
|
-
'runtime/**', // All files in runtime/ recursively
|
|
647
556
|
'bin/cli.js', // Specific file: bin/cli.js
|
|
648
557
|
];
|
|
649
558
|
|
|
@@ -805,6 +714,64 @@ function isGitRepo(repoPath) {
|
|
|
805
714
|
}
|
|
806
715
|
}
|
|
807
716
|
|
|
717
|
+
// Paths that updates should preserve (never overwrite/stash as "managed")
|
|
718
|
+
const UPDATE_PROTECTED_AETHER_DIRS = new Set([
|
|
719
|
+
'data',
|
|
720
|
+
'dreams',
|
|
721
|
+
'oracle',
|
|
722
|
+
'midden',
|
|
723
|
+
'checkpoints',
|
|
724
|
+
'locks',
|
|
725
|
+
'temp',
|
|
726
|
+
'archive',
|
|
727
|
+
'chambers',
|
|
728
|
+
'exchange',
|
|
729
|
+
]);
|
|
730
|
+
|
|
731
|
+
const UPDATE_MANAGED_PREFIXES = [
|
|
732
|
+
'.claude/commands/ant',
|
|
733
|
+
'.claude/agents/ant',
|
|
734
|
+
'.claude/rules',
|
|
735
|
+
'.opencode/commands/ant',
|
|
736
|
+
'.opencode/agents',
|
|
737
|
+
];
|
|
738
|
+
|
|
739
|
+
function normalizePorcelainPath(filePath) {
|
|
740
|
+
let normalized = filePath;
|
|
741
|
+
|
|
742
|
+
// For rename entries, keep only destination path: "old -> new"
|
|
743
|
+
if (normalized.includes(' -> ')) {
|
|
744
|
+
normalized = normalized.split(' -> ').pop();
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
// Handle quoted porcelain paths (spaces, escaped chars)
|
|
748
|
+
if (normalized.startsWith('"') && normalized.endsWith('"')) {
|
|
749
|
+
normalized = normalized
|
|
750
|
+
.slice(1, -1)
|
|
751
|
+
.replace(/\\"/g, '"')
|
|
752
|
+
.replace(/\\\\/g, '\\');
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
return normalized;
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
function isManagedUpdatePath(filePath) {
|
|
759
|
+
const normalized = normalizePorcelainPath(filePath);
|
|
760
|
+
|
|
761
|
+
if (normalized === '.aether' || normalized.startsWith('.aether/')) {
|
|
762
|
+
const rel = normalized === '.aether' ? '' : normalized.slice('.aether/'.length);
|
|
763
|
+
if (!rel) return true;
|
|
764
|
+
|
|
765
|
+
const first = rel.split('/')[0];
|
|
766
|
+
if (!first || first.startsWith('.')) return false;
|
|
767
|
+
if (UPDATE_PROTECTED_AETHER_DIRS.has(first)) return false;
|
|
768
|
+
if (rel === 'QUEEN.md') return false;
|
|
769
|
+
return true;
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
return UPDATE_MANAGED_PREFIXES.some(prefix => normalized === prefix || normalized.startsWith(`${prefix}/`));
|
|
773
|
+
}
|
|
774
|
+
|
|
808
775
|
function getGitDirtyFiles(repoPath, targetDirs) {
|
|
809
776
|
try {
|
|
810
777
|
const args = targetDirs.filter(d => fs.existsSync(path.join(repoPath, d)));
|
|
@@ -814,7 +781,14 @@ function getGitDirtyFiles(repoPath, targetDirs) {
|
|
|
814
781
|
stdio: 'pipe',
|
|
815
782
|
encoding: 'utf8',
|
|
816
783
|
});
|
|
817
|
-
|
|
784
|
+
const files = [];
|
|
785
|
+
for (const line of result.split('\n')) {
|
|
786
|
+
if (!line || line.length < 4) continue;
|
|
787
|
+
const filePath = line.slice(3);
|
|
788
|
+
if (!isManagedUpdatePath(filePath)) continue;
|
|
789
|
+
files.push(normalizePorcelainPath(filePath));
|
|
790
|
+
}
|
|
791
|
+
return [...new Set(files)];
|
|
818
792
|
} catch {
|
|
819
793
|
return [];
|
|
820
794
|
}
|
|
@@ -835,7 +809,13 @@ function gitStashFiles(repoPath, files) {
|
|
|
835
809
|
}
|
|
836
810
|
|
|
837
811
|
// Directories to exclude from hub sync (user data, local state)
|
|
838
|
-
|
|
812
|
+
// 'rules' is excluded here because it is synced via a dedicated step (rulesSrc below)
|
|
813
|
+
const HUB_EXCLUDE_DIRS = ['data', 'dreams', 'checkpoints', 'locks', 'temp', 'rules'];
|
|
814
|
+
// Directories excluded only when they are the FIRST path segment under .aether/
|
|
815
|
+
// (e.g., .aether/oracle/ is excluded but .aether/utils/oracle/ is NOT)
|
|
816
|
+
const HUB_EXCLUDE_FIRST_SEGMENT = ['oracle'];
|
|
817
|
+
// Files to exclude from hub sync (repo-local state, not distributable)
|
|
818
|
+
const HUB_EXCLUDE_FILES = ['CONTEXT.md', 'HANDOFF.md'];
|
|
839
819
|
|
|
840
820
|
/**
|
|
841
821
|
* Check if a path should be excluded from hub sync
|
|
@@ -844,8 +824,13 @@ const HUB_EXCLUDE_DIRS = ['data', 'dreams', 'checkpoints', 'locks', 'temp'];
|
|
|
844
824
|
*/
|
|
845
825
|
function shouldExcludeFromHub(relPath) {
|
|
846
826
|
const parts = relPath.split(path.sep);
|
|
827
|
+
const basename = path.basename(relPath);
|
|
847
828
|
// Exclude if any part of the path is in the exclude list
|
|
848
|
-
|
|
829
|
+
if (parts.some(part => HUB_EXCLUDE_DIRS.includes(part))) return true;
|
|
830
|
+
// Exclude if first segment matches first-segment-only list (position-aware)
|
|
831
|
+
if (parts.length > 0 && HUB_EXCLUDE_FIRST_SEGMENT.includes(parts[0])) return true;
|
|
832
|
+
if (HUB_EXCLUDE_FILES.includes(basename)) return true;
|
|
833
|
+
return false;
|
|
849
834
|
}
|
|
850
835
|
|
|
851
836
|
/**
|
|
@@ -870,6 +855,7 @@ function syncAetherToHub(srcDir, destDir) {
|
|
|
870
855
|
const fullPath = path.join(dir, entry.name);
|
|
871
856
|
const relPath = path.relative(base, fullPath);
|
|
872
857
|
|
|
858
|
+
// Exclude non-distributable paths from source collection.
|
|
873
859
|
if (shouldExcludeFromHub(relPath)) continue;
|
|
874
860
|
|
|
875
861
|
if (entry.isDirectory()) {
|
|
@@ -920,7 +906,10 @@ function syncAetherToHub(srcDir, destDir) {
|
|
|
920
906
|
const fullPath = path.join(dir, entry.name);
|
|
921
907
|
const relPath = path.relative(base, fullPath);
|
|
922
908
|
|
|
923
|
-
|
|
909
|
+
// Skip protected directories during cleanup, but allow excluded files
|
|
910
|
+
// (e.g. CONTEXT.md/HANDOFF.md) to be removed from the hub if stale.
|
|
911
|
+
const parts = relPath.split(path.sep);
|
|
912
|
+
if (parts.some(part => HUB_EXCLUDE_DIRS.includes(part))) continue;
|
|
924
913
|
|
|
925
914
|
if (entry.isDirectory()) {
|
|
926
915
|
collectDestFiles(fullPath, base);
|
|
@@ -950,11 +939,116 @@ function syncAetherToHub(srcDir, destDir) {
|
|
|
950
939
|
return { copied, removed, skipped };
|
|
951
940
|
}
|
|
952
941
|
|
|
942
|
+
/**
|
|
943
|
+
* Sync skills from source to hub using manifest-aware strategy.
|
|
944
|
+
* Only syncs skills listed in .manifest.json (Aether-managed).
|
|
945
|
+
* User-created skills (not in manifest) are never modified or deleted.
|
|
946
|
+
*
|
|
947
|
+
* @param {string} skillsSrc - Source skills directory (e.g., .aether/skills)
|
|
948
|
+
* @param {string} hubSkillsDir - Hub skills directory (e.g., ~/.aether/skills)
|
|
949
|
+
* @returns {{ synced: string[], skipped: string[], notices: string[] }}
|
|
950
|
+
*/
|
|
951
|
+
function syncSkillsToHub(skillsSrc, hubSkillsDir) {
|
|
952
|
+
const result = { synced: [], skipped: [], notices: [] };
|
|
953
|
+
|
|
954
|
+
if (!fs.existsSync(skillsSrc)) {
|
|
955
|
+
return result;
|
|
956
|
+
}
|
|
957
|
+
|
|
958
|
+
for (const category of ['colony', 'domain']) {
|
|
959
|
+
const srcCat = path.join(skillsSrc, category);
|
|
960
|
+
const hubCat = path.join(hubSkillsDir, category);
|
|
961
|
+
|
|
962
|
+
if (!fs.existsSync(srcCat)) continue;
|
|
963
|
+
fs.mkdirSync(hubCat, { recursive: true });
|
|
964
|
+
|
|
965
|
+
// Copy manifest
|
|
966
|
+
const manifestSrc = path.join(srcCat, '.manifest.json');
|
|
967
|
+
if (fs.existsSync(manifestSrc)) {
|
|
968
|
+
fs.copyFileSync(manifestSrc, path.join(hubCat, '.manifest.json'));
|
|
969
|
+
}
|
|
970
|
+
|
|
971
|
+
// Read manifest for owned skills list
|
|
972
|
+
let manifest = { skills: [] };
|
|
973
|
+
try {
|
|
974
|
+
manifest = JSON.parse(fs.readFileSync(manifestSrc, 'utf8'));
|
|
975
|
+
} catch (e) { /* no manifest = no managed skills */ }
|
|
976
|
+
|
|
977
|
+
// Sync only managed skills (skip user-created)
|
|
978
|
+
const srcDirs = fs.readdirSync(srcCat, { withFileTypes: true })
|
|
979
|
+
.filter(d => d.isDirectory());
|
|
980
|
+
|
|
981
|
+
for (const dir of srcDirs) {
|
|
982
|
+
if (manifest.skills.includes(dir.name)) {
|
|
983
|
+
// Managed skill — overwrite via syncDirWithCleanup
|
|
984
|
+
const srcSkill = path.join(srcCat, dir.name);
|
|
985
|
+
const hubSkill = path.join(hubCat, dir.name);
|
|
986
|
+
syncDirWithCleanup(srcSkill, hubSkill);
|
|
987
|
+
result.synced.push(`${category}/${dir.name}`);
|
|
988
|
+
} else if (fs.existsSync(path.join(hubCat, dir.name))) {
|
|
989
|
+
// User-created skill exists with same name — skip and log notice
|
|
990
|
+
const notice = `Skipped skill '${dir.name}' — user version exists. Run 'aether skill-diff ${dir.name}' to compare.`;
|
|
991
|
+
result.notices.push(notice);
|
|
992
|
+
result.skipped.push(`${category}/${dir.name}`);
|
|
993
|
+
}
|
|
994
|
+
}
|
|
995
|
+
|
|
996
|
+
// Copy README if present
|
|
997
|
+
const readmeSrc = path.join(srcCat, 'README.md');
|
|
998
|
+
if (fs.existsSync(readmeSrc)) {
|
|
999
|
+
fs.copyFileSync(readmeSrc, path.join(hubCat, 'README.md'));
|
|
1000
|
+
}
|
|
1001
|
+
}
|
|
1002
|
+
|
|
1003
|
+
return result;
|
|
1004
|
+
}
|
|
1005
|
+
|
|
953
1006
|
function setupHub() {
|
|
954
1007
|
// Create ~/.aether/ directory structure and populate from package
|
|
955
1008
|
try {
|
|
956
1009
|
fs.mkdirSync(HUB_DIR, { recursive: true });
|
|
957
1010
|
|
|
1011
|
+
// MIGRATION: Check for old structure and migrate to system/
|
|
1012
|
+
const oldStructureFiles = [
|
|
1013
|
+
path.join(HUB_DIR, 'aether-utils.sh'),
|
|
1014
|
+
path.join(HUB_DIR, 'workers.md'),
|
|
1015
|
+
];
|
|
1016
|
+
const hasOldStructure = oldStructureFiles.some(f => fs.existsSync(f));
|
|
1017
|
+
const hasNewStructure = fs.existsSync(HUB_SYSTEM_DIR);
|
|
1018
|
+
|
|
1019
|
+
if (hasOldStructure && !hasNewStructure) {
|
|
1020
|
+
log(' Migrating hub to new structure...');
|
|
1021
|
+
fs.mkdirSync(HUB_SYSTEM_DIR, { recursive: true });
|
|
1022
|
+
|
|
1023
|
+
// Move system files to system/
|
|
1024
|
+
const systemFiles = ['aether-utils.sh', 'workers.md'];
|
|
1025
|
+
const systemDirs = ['docs', 'utils', 'commands', 'agents', 'schemas', 'exchange', 'templates', 'lib'];
|
|
1026
|
+
|
|
1027
|
+
for (const file of systemFiles) {
|
|
1028
|
+
const oldPath = path.join(HUB_DIR, file);
|
|
1029
|
+
if (fs.existsSync(oldPath)) {
|
|
1030
|
+
fs.renameSync(oldPath, path.join(HUB_SYSTEM_DIR, file));
|
|
1031
|
+
}
|
|
1032
|
+
}
|
|
1033
|
+
|
|
1034
|
+
for (const dir of systemDirs) {
|
|
1035
|
+
const oldPath = path.join(HUB_DIR, dir);
|
|
1036
|
+
if (fs.existsSync(oldPath)) {
|
|
1037
|
+
fs.renameSync(oldPath, path.join(HUB_SYSTEM_DIR, dir));
|
|
1038
|
+
}
|
|
1039
|
+
}
|
|
1040
|
+
|
|
1041
|
+
log(' Migration complete: system files moved to ~/.aether/system/');
|
|
1042
|
+
}
|
|
1043
|
+
|
|
1044
|
+
// Create system/ directory structure
|
|
1045
|
+
fs.mkdirSync(HUB_SYSTEM_DIR, { recursive: true });
|
|
1046
|
+
fs.mkdirSync(path.join(HUB_SYSTEM_DIR, 'commands', 'claude'), { recursive: true });
|
|
1047
|
+
fs.mkdirSync(path.join(HUB_SYSTEM_DIR, 'commands', 'opencode'), { recursive: true });
|
|
1048
|
+
fs.mkdirSync(path.join(HUB_SYSTEM_DIR, 'agents'), { recursive: true });
|
|
1049
|
+
fs.mkdirSync(path.join(HUB_SYSTEM_DIR, 'agents-claude'), { recursive: true });
|
|
1050
|
+
fs.mkdirSync(path.join(HUB_SYSTEM_DIR, 'rules'), { recursive: true });
|
|
1051
|
+
|
|
958
1052
|
// Read previous manifest for delta reporting
|
|
959
1053
|
const prevManifestRaw = readJsonSafe(path.join(HUB_DIR, 'manifest.json'));
|
|
960
1054
|
const prevManifest = prevManifestRaw && validateManifest(prevManifestRaw).valid ? prevManifestRaw : null;
|
|
@@ -962,21 +1056,32 @@ function setupHub() {
|
|
|
962
1056
|
log(` Warning: previous manifest is invalid, regenerating`);
|
|
963
1057
|
}
|
|
964
1058
|
|
|
965
|
-
// Sync
|
|
966
|
-
//
|
|
967
|
-
const
|
|
968
|
-
if (fs.existsSync(
|
|
969
|
-
const result = syncAetherToHub(
|
|
970
|
-
log(` Hub system: ${result.copied} files, ${result.skipped} unchanged -> ${
|
|
1059
|
+
// Sync .aether/ -> ~/.aether/system/ (direct packaging, no staging)
|
|
1060
|
+
// v4.0: .aether/ is published directly — runtime/ staging removed
|
|
1061
|
+
const aetherSrc = path.join(PACKAGE_DIR, '.aether');
|
|
1062
|
+
if (fs.existsSync(aetherSrc)) {
|
|
1063
|
+
const result = syncAetherToHub(aetherSrc, HUB_SYSTEM_DIR);
|
|
1064
|
+
log(` Hub system: ${result.copied} files, ${result.skipped} unchanged -> ${HUB_SYSTEM_DIR}`);
|
|
971
1065
|
if (result.removed.length > 0) {
|
|
972
1066
|
log(` Hub system: removed ${result.removed.length} stale files`);
|
|
973
1067
|
for (const f of result.removed) log(` - ${f}`);
|
|
974
1068
|
}
|
|
975
1069
|
}
|
|
976
1070
|
|
|
977
|
-
//
|
|
1071
|
+
// Migration message for users upgrading from pre-4.0 (runtime/ era)
|
|
1072
|
+
const prevManifestForMigration = readJsonSafe(path.join(HUB_DIR, 'manifest.json'));
|
|
1073
|
+
if (prevManifestForMigration && prevManifestForMigration.version && prevManifestForMigration.version.startsWith('3.')) {
|
|
1074
|
+
log('');
|
|
1075
|
+
log(' Distribution pipeline simplified (v4.0 change):');
|
|
1076
|
+
log(' - runtime/ staging directory has been removed');
|
|
1077
|
+
log(' - .aether/ is now published directly (private dirs excluded)');
|
|
1078
|
+
log(' - Your colony state and data are unaffected');
|
|
1079
|
+
log(' - See CHANGELOG.md for details');
|
|
1080
|
+
log('');
|
|
1081
|
+
}
|
|
1082
|
+
|
|
1083
|
+
// Clean up legacy directories from very old hub structure (pre-system/)
|
|
978
1084
|
const legacyDirs = [
|
|
979
|
-
path.join(HUB_DIR, 'system'),
|
|
980
1085
|
path.join(HUB_DIR, '.aether'),
|
|
981
1086
|
path.join(HUB_DIR, 'visualizations'),
|
|
982
1087
|
];
|
|
@@ -991,7 +1096,7 @@ function setupHub() {
|
|
|
991
1096
|
}
|
|
992
1097
|
}
|
|
993
1098
|
|
|
994
|
-
// Sync .claude/commands/ant/ -> ~/.aether/commands/claude/
|
|
1099
|
+
// Sync .claude/commands/ant/ -> ~/.aether/system/commands/claude/
|
|
995
1100
|
const claudeCmdSrc = fs.existsSync(COMMANDS_SRC)
|
|
996
1101
|
? COMMANDS_SRC
|
|
997
1102
|
: path.join(PACKAGE_DIR, '.claude', 'commands', 'ant');
|
|
@@ -1004,7 +1109,7 @@ function setupHub() {
|
|
|
1004
1109
|
}
|
|
1005
1110
|
}
|
|
1006
1111
|
|
|
1007
|
-
// Sync .opencode/commands/ant/ -> ~/.aether/commands/opencode/
|
|
1112
|
+
// Sync .opencode/commands/ant/ -> ~/.aether/system/commands/opencode/
|
|
1008
1113
|
const opencodeCmdSrc = path.join(PACKAGE_DIR, '.opencode', 'commands', 'ant');
|
|
1009
1114
|
if (fs.existsSync(opencodeCmdSrc)) {
|
|
1010
1115
|
const result = syncDirWithCleanup(opencodeCmdSrc, HUB_COMMANDS_OPENCODE);
|
|
@@ -1015,7 +1120,7 @@ function setupHub() {
|
|
|
1015
1120
|
}
|
|
1016
1121
|
}
|
|
1017
1122
|
|
|
1018
|
-
// Sync .opencode/agents/ -> ~/.aether/agents/
|
|
1123
|
+
// Sync .opencode/agents/ -> ~/.aether/system/agents/
|
|
1019
1124
|
const agentsSrc = path.join(PACKAGE_DIR, '.opencode', 'agents');
|
|
1020
1125
|
if (fs.existsSync(agentsSrc)) {
|
|
1021
1126
|
const result = syncDirWithCleanup(agentsSrc, HUB_AGENTS);
|
|
@@ -1026,7 +1131,44 @@ function setupHub() {
|
|
|
1026
1131
|
}
|
|
1027
1132
|
}
|
|
1028
1133
|
|
|
1029
|
-
//
|
|
1134
|
+
// Sync .claude/agents/ant/ -> ~/.aether/system/agents-claude/
|
|
1135
|
+
const claudeAgentsSrc = path.join(PACKAGE_DIR, '.claude', 'agents', 'ant');
|
|
1136
|
+
if (fs.existsSync(claudeAgentsSrc)) {
|
|
1137
|
+
const result = syncDirWithCleanup(claudeAgentsSrc, HUB_AGENTS_CLAUDE);
|
|
1138
|
+
log(` Hub agents (claude): ${result.copied} files, ${result.skipped} unchanged -> ${HUB_AGENTS_CLAUDE}`);
|
|
1139
|
+
if (result.removed.length > 0) {
|
|
1140
|
+
log(` Hub agents (claude): removed ${result.removed.length} stale files`);
|
|
1141
|
+
for (const f of result.removed) log(` - ${f}`);
|
|
1142
|
+
}
|
|
1143
|
+
}
|
|
1144
|
+
|
|
1145
|
+
// Sync rules/ from .aether/ -> ~/.aether/system/rules/
|
|
1146
|
+
// v4.0: source is .aether/rules/ directly (no runtime/ staging)
|
|
1147
|
+
const rulesSrc = path.join(PACKAGE_DIR, '.aether', 'rules');
|
|
1148
|
+
if (fs.existsSync(rulesSrc)) {
|
|
1149
|
+
const result = syncDirWithCleanup(rulesSrc, HUB_RULES);
|
|
1150
|
+
log(` Hub rules: ${result.copied} files -> ${HUB_RULES}`);
|
|
1151
|
+
if (result.removed.length > 0) {
|
|
1152
|
+
log(` Hub rules: removed ${result.removed.length} stale files`);
|
|
1153
|
+
for (const f of result.removed) log(` - ${f}`);
|
|
1154
|
+
}
|
|
1155
|
+
}
|
|
1156
|
+
|
|
1157
|
+
// Sync skills to hub (~/.aether/skills/)
|
|
1158
|
+
// Skills install at hub root (NOT in system/) so users can find and create their own
|
|
1159
|
+
const skillsSrc = path.join(aetherSrc, 'skills');
|
|
1160
|
+
const HUB_SKILLS_DIR = path.join(HUB_DIR, 'skills');
|
|
1161
|
+
if (fs.existsSync(skillsSrc)) {
|
|
1162
|
+
const skillsResult = syncSkillsToHub(skillsSrc, HUB_SKILLS_DIR);
|
|
1163
|
+
if (skillsResult.synced.length > 0) {
|
|
1164
|
+
log(` Hub skills: ${skillsResult.synced.length} managed skills synced -> ${HUB_SKILLS_DIR}`);
|
|
1165
|
+
}
|
|
1166
|
+
for (const notice of skillsResult.notices) {
|
|
1167
|
+
log(` ${notice}`);
|
|
1168
|
+
}
|
|
1169
|
+
}
|
|
1170
|
+
|
|
1171
|
+
// Create/preserve registry.json (at root, not in system/)
|
|
1030
1172
|
if (!fs.existsSync(HUB_REGISTRY)) {
|
|
1031
1173
|
writeJsonSync(HUB_REGISTRY, { schema_version: 1, repos: [] });
|
|
1032
1174
|
log(` Registry: initialized ${HUB_REGISTRY}`);
|
|
@@ -1034,7 +1176,7 @@ function setupHub() {
|
|
|
1034
1176
|
log(` Registry: preserved existing ${HUB_REGISTRY}`);
|
|
1035
1177
|
}
|
|
1036
1178
|
|
|
1037
|
-
// Generate and write manifest
|
|
1179
|
+
// Generate and write manifest (at root, tracks everything)
|
|
1038
1180
|
const manifest = generateManifest(HUB_DIR);
|
|
1039
1181
|
const manifestPath = path.join(HUB_DIR, 'manifest.json');
|
|
1040
1182
|
writeJsonSync(manifestPath, manifest);
|
|
@@ -1053,7 +1195,7 @@ function setupHub() {
|
|
|
1053
1195
|
}
|
|
1054
1196
|
}
|
|
1055
1197
|
|
|
1056
|
-
// Write version.json
|
|
1198
|
+
// Write version.json (at root)
|
|
1057
1199
|
writeJsonSync(HUB_VERSION, { version: VERSION, updated_at: new Date().toISOString() });
|
|
1058
1200
|
log(` Hub version: ${VERSION}`);
|
|
1059
1201
|
} catch (err) {
|
|
@@ -1079,21 +1221,23 @@ async function updateRepo(repoPath, sourceVersion, opts) {
|
|
|
1079
1221
|
const currentVer = currentVersion ? currentVersion.version : 'unknown';
|
|
1080
1222
|
|
|
1081
1223
|
// Target directories for git safety checks
|
|
1082
|
-
const targetDirs = ['.aether', '.claude/commands/ant', '.opencode/commands/ant', '.opencode/agents'];
|
|
1224
|
+
const targetDirs = ['.aether', '.claude/commands/ant', '.claude/agents/ant', '.claude/rules', '.opencode/commands/ant', '.opencode/agents'];
|
|
1083
1225
|
|
|
1084
|
-
//
|
|
1226
|
+
// Use UpdateTransaction for two-phase commit with automatic rollback
|
|
1227
|
+
const transaction = new UpdateTransaction(repoPath, { sourceVersion, quiet, force });
|
|
1228
|
+
|
|
1229
|
+
// Git safety: only warn about dirty files the update would actually overwrite
|
|
1085
1230
|
let dirtyFiles = [];
|
|
1086
|
-
if (isGitRepo(repoPath)) {
|
|
1087
|
-
|
|
1088
|
-
|
|
1231
|
+
if (isGitRepo(repoPath) && !force) {
|
|
1232
|
+
const wouldOverwrite = new Set(transaction.getConflictingFiles());
|
|
1233
|
+
const allDirty = getGitDirtyFiles(repoPath, targetDirs);
|
|
1234
|
+
dirtyFiles = allDirty.filter(f => wouldOverwrite.has(f));
|
|
1235
|
+
if (dirtyFiles.length > 0) {
|
|
1089
1236
|
return { status: 'dirty', files: dirtyFiles };
|
|
1090
1237
|
}
|
|
1091
1238
|
// Note: --force handling is now done via checkpoint stash in UpdateTransaction
|
|
1092
1239
|
}
|
|
1093
1240
|
|
|
1094
|
-
// Use UpdateTransaction for two-phase commit with automatic rollback
|
|
1095
|
-
const transaction = new UpdateTransaction(repoPath, { sourceVersion, quiet, force });
|
|
1096
|
-
|
|
1097
1241
|
try {
|
|
1098
1242
|
const result = await transaction.execute(sourceVersion, { dryRun });
|
|
1099
1243
|
|
|
@@ -1101,17 +1245,25 @@ async function updateRepo(repoPath, sourceVersion, opts) {
|
|
|
1101
1245
|
const systemCopied = result.sync_result?.system?.copied || 0;
|
|
1102
1246
|
const commandsCopied = (result.sync_result?.commands?.copied || 0);
|
|
1103
1247
|
const agentsCopied = result.sync_result?.agents?.copied || 0;
|
|
1248
|
+
const rulesCopied = result.sync_result?.rules?.copied || 0;
|
|
1249
|
+
const agentsClaudeCopied = result.sync_result?.agents_claude?.copied || 0;
|
|
1104
1250
|
|
|
1105
1251
|
const systemRemoved = result.sync_result?.system?.removed?.length || 0;
|
|
1106
1252
|
const commandsRemoved = result.sync_result?.commands?.removed?.length || 0;
|
|
1107
1253
|
const agentsRemoved = result.sync_result?.agents?.removed?.length || 0;
|
|
1254
|
+
const rulesRemoved = result.sync_result?.rules?.removed?.length || 0;
|
|
1255
|
+
const agentsClaudeRemoved = result.sync_result?.agents_claude?.removed?.length || 0;
|
|
1108
1256
|
|
|
1109
1257
|
const allRemovedFiles = [
|
|
1110
1258
|
...(result.sync_result?.system?.removed || []),
|
|
1111
1259
|
...(result.sync_result?.commands?.removed || []).map(f => `.claude/commands/ant/${f}`),
|
|
1112
1260
|
...(result.sync_result?.agents?.removed || []).map(f => `.opencode/agents/${f}`),
|
|
1261
|
+
...(result.sync_result?.rules?.removed || []).map(f => `.claude/rules/${f}`),
|
|
1262
|
+
...(result.sync_result?.agents_claude?.removed || []).map(f => `.claude/agents/ant/${f}`),
|
|
1113
1263
|
];
|
|
1114
1264
|
|
|
1265
|
+
const cleanupResult = result.cleanup_result || { cleaned: [], failed: [] };
|
|
1266
|
+
|
|
1115
1267
|
return {
|
|
1116
1268
|
status: result.status,
|
|
1117
1269
|
from: currentVer,
|
|
@@ -1119,10 +1271,13 @@ async function updateRepo(repoPath, sourceVersion, opts) {
|
|
|
1119
1271
|
system: systemCopied,
|
|
1120
1272
|
commands: commandsCopied,
|
|
1121
1273
|
agents: agentsCopied,
|
|
1122
|
-
|
|
1274
|
+
rules: rulesCopied,
|
|
1275
|
+
agentsClaude: agentsClaudeCopied,
|
|
1276
|
+
removed: systemRemoved + commandsRemoved + agentsRemoved + rulesRemoved + agentsClaudeRemoved,
|
|
1123
1277
|
removedFiles: allRemovedFiles,
|
|
1124
1278
|
stashCreated: !!transaction.checkpoint?.stashRef,
|
|
1125
1279
|
checkpoint_id: result.checkpoint_id,
|
|
1280
|
+
cleanup: cleanupResult,
|
|
1126
1281
|
};
|
|
1127
1282
|
} catch (error) {
|
|
1128
1283
|
// Handle UpdateError with recovery commands
|
|
@@ -1161,7 +1316,7 @@ program.on('option:quiet', () => {
|
|
|
1161
1316
|
// Install command
|
|
1162
1317
|
program
|
|
1163
1318
|
.command('install')
|
|
1164
|
-
.description('Install
|
|
1319
|
+
.description('Install commands and agents to ~/.claude/ and set up distribution hub')
|
|
1165
1320
|
.action(wrapCommand(async () => {
|
|
1166
1321
|
log(c.header(`aether-colony v${VERSION} — installing...`));
|
|
1167
1322
|
|
|
@@ -1188,6 +1343,39 @@ program
|
|
|
1188
1343
|
}
|
|
1189
1344
|
}
|
|
1190
1345
|
|
|
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}`);
|
|
1354
|
+
}
|
|
1355
|
+
}
|
|
1356
|
+
|
|
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}`);
|
|
1365
|
+
}
|
|
1366
|
+
}
|
|
1367
|
+
|
|
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}`);
|
|
1376
|
+
}
|
|
1377
|
+
}
|
|
1378
|
+
|
|
1191
1379
|
// Set up distribution hub at ~/.aether/
|
|
1192
1380
|
log('');
|
|
1193
1381
|
log(c.colony('Setting up distribution hub...'));
|
|
@@ -1196,6 +1384,7 @@ program
|
|
|
1196
1384
|
log('');
|
|
1197
1385
|
log(c.success('Install complete.'));
|
|
1198
1386
|
log(` ${c.queen('Claude Code:')} run /ant to get started`);
|
|
1387
|
+
log(` ${c.colony('OpenCode:')} run /ant to get started`);
|
|
1199
1388
|
log(` ${c.colony('Hub:')} ${c.dim('~/.aether/')} (for coordinated updates across repos)`);
|
|
1200
1389
|
}));
|
|
1201
1390
|
|
|
@@ -1288,19 +1477,31 @@ program
|
|
|
1288
1477
|
console.error(` Skipping. Use --force to stash and update.`);
|
|
1289
1478
|
dirty++;
|
|
1290
1479
|
} else if (result.status === 'dry-run') {
|
|
1291
|
-
log(` Would update: ${repo.path} (${result.from} -> ${result.to}) [${result.system} system, ${result.commands} commands, ${result.agents} agents]`);
|
|
1480
|
+
log(` Would update: ${repo.path} (${result.from} -> ${result.to}) [${result.system} system, ${result.commands} commands, ${result.agents} agents, ${result.agentsClaude} claude agents]`);
|
|
1292
1481
|
if (result.removed > 0) {
|
|
1293
1482
|
log(` Would remove ${result.removed} stale files:`);
|
|
1294
1483
|
for (const f of result.removedFiles) log(` - ${f}`);
|
|
1295
1484
|
}
|
|
1296
1485
|
updated++;
|
|
1297
1486
|
} else if (result.status === 'updated') {
|
|
1298
|
-
log(` ${c.success('Updated:')} ${repo.path} (${result.from} -> ${result.to}) [${result.system} system, ${result.commands} commands, ${result.agents} agents]`);
|
|
1487
|
+
log(` ${c.success('Updated:')} ${repo.path} (${result.from} -> ${result.to}) [${result.system} system, ${result.commands} commands, ${result.agents} agents, ${result.agentsClaude} claude agents]`);
|
|
1299
1488
|
if (result.removed > 0) {
|
|
1300
1489
|
log(` Removed ${result.removed} stale files:`);
|
|
1301
1490
|
for (const f of result.removedFiles) log(` - ${f}`);
|
|
1302
1491
|
totalRemoved += result.removed;
|
|
1303
1492
|
}
|
|
1493
|
+
// Distribution chain cleanup reporting
|
|
1494
|
+
if (result.cleanup && result.cleanup.cleaned.length > 0) {
|
|
1495
|
+
for (const label of result.cleanup.cleaned) {
|
|
1496
|
+
log(` ${c.success('\u2713')} Removed ${label}`);
|
|
1497
|
+
}
|
|
1498
|
+
}
|
|
1499
|
+
for (const failure of (result.cleanup?.failed || [])) {
|
|
1500
|
+
log(` ${c.error('\u2717')} Failed to remove ${failure.label}: ${failure.error}`);
|
|
1501
|
+
}
|
|
1502
|
+
if (result.cleanup && result.cleanup.cleaned.length === 0 && result.cleanup.failed.length === 0) {
|
|
1503
|
+
log(` Distribution chain: ${c.success('\u2713')} clean`);
|
|
1504
|
+
}
|
|
1304
1505
|
if (result.stashCreated) {
|
|
1305
1506
|
log(` Stash created. Recover with: cd ${repo.path} && git stash pop`);
|
|
1306
1507
|
}
|
|
@@ -1324,7 +1525,7 @@ program
|
|
|
1324
1525
|
}
|
|
1325
1526
|
|
|
1326
1527
|
const label = dryRun ? 'would update' : 'updated';
|
|
1327
|
-
let summary = `\nSummary: ${updated} ${label}, ${upToDate} up
|
|
1528
|
+
let summary = `\nSummary: ${updated} ${label}, ${upToDate} up to date, ${pruned} pruned`;
|
|
1328
1529
|
if (dirty > 0) summary += `, ${dirty} dirty (skipped)`;
|
|
1329
1530
|
if (totalRemoved > 0) summary += `, ${totalRemoved} stale files removed`;
|
|
1330
1531
|
console.log(summary);
|
|
@@ -1343,11 +1544,19 @@ program
|
|
|
1343
1544
|
process.exit(getExitCode(error.code));
|
|
1344
1545
|
}
|
|
1345
1546
|
|
|
1547
|
+
const pendingPath = path.join(repoAether, '.update-pending');
|
|
1548
|
+
const hasPending = fs.existsSync(pendingPath);
|
|
1549
|
+
|
|
1550
|
+
if (hasPending) {
|
|
1551
|
+
console.log('Detected incomplete update, re-syncing...');
|
|
1552
|
+
try { fs.unlinkSync(pendingPath); } catch { /* ignore */ }
|
|
1553
|
+
}
|
|
1554
|
+
|
|
1346
1555
|
const currentVersion = readJsonSafe(path.join(repoAether, 'version.json'));
|
|
1347
1556
|
const currentVer = currentVersion ? currentVersion.version : 'unknown';
|
|
1348
1557
|
|
|
1349
|
-
if (!forceFlag && !dryRun && currentVer === sourceVersion) {
|
|
1350
|
-
console.log(c.info(`Already up
|
|
1558
|
+
if (!hasPending && !forceFlag && !dryRun && currentVer === sourceVersion) {
|
|
1559
|
+
console.log(c.info(`Already up to date (v${sourceVersion}).`));
|
|
1351
1560
|
return;
|
|
1352
1561
|
}
|
|
1353
1562
|
|
|
@@ -1371,7 +1580,7 @@ program
|
|
|
1371
1580
|
|
|
1372
1581
|
if (result.status === 'dry-run') {
|
|
1373
1582
|
console.log(`Would update: ${result.from} -> ${result.to}`);
|
|
1374
|
-
console.log(` ${result.system} system files, ${result.commands} command files, ${result.agents} agent files`);
|
|
1583
|
+
console.log(` ${result.system} system files, ${result.commands} command files, ${result.agents} agent files, ${result.agentsClaude} claude agent files`);
|
|
1375
1584
|
if (result.removed > 0) {
|
|
1376
1585
|
console.log(` Would remove ${result.removed} stale files:`);
|
|
1377
1586
|
for (const f of result.removedFiles) console.log(` - ${f}`);
|
|
@@ -1381,11 +1590,23 @@ program
|
|
|
1381
1590
|
}
|
|
1382
1591
|
|
|
1383
1592
|
console.log(c.success(`Updated: ${result.from} -> ${result.to}`));
|
|
1384
|
-
console.log(` ${result.system} system files, ${result.commands} command files, ${result.agents} agent files, ${result.
|
|
1593
|
+
console.log(` ${result.system} system files, ${result.commands} command files, ${result.agents} agent files, ${result.agentsClaude} claude agent files`);
|
|
1385
1594
|
if (result.removed > 0) {
|
|
1386
1595
|
console.log(` Removed ${result.removed} stale files:`);
|
|
1387
1596
|
for (const f of result.removedFiles) console.log(` - ${f}`);
|
|
1388
1597
|
}
|
|
1598
|
+
// Distribution chain cleanup reporting
|
|
1599
|
+
if (result.cleanup && result.cleanup.cleaned.length > 0) {
|
|
1600
|
+
for (const label of result.cleanup.cleaned) {
|
|
1601
|
+
console.log(` ${c.success('\u2713')} Removed ${label}`);
|
|
1602
|
+
}
|
|
1603
|
+
}
|
|
1604
|
+
for (const failure of (result.cleanup?.failed || [])) {
|
|
1605
|
+
console.log(` ${c.error('\u2717')} Failed to remove ${failure.label}: ${failure.error}`);
|
|
1606
|
+
}
|
|
1607
|
+
if (result.cleanup && result.cleanup.cleaned.length === 0 && result.cleanup.failed.length === 0) {
|
|
1608
|
+
console.log(` Distribution chain: ${c.success('\u2713')} clean`);
|
|
1609
|
+
}
|
|
1389
1610
|
if (result.stashCreated) {
|
|
1390
1611
|
console.log(' Git stash created. Recover with: git stash pop');
|
|
1391
1612
|
}
|
|
@@ -1432,7 +1653,7 @@ program
|
|
|
1432
1653
|
// Uninstall command
|
|
1433
1654
|
program
|
|
1434
1655
|
.command('uninstall')
|
|
1435
|
-
.description('Remove slash-commands from ~/.claude/commands/ant/ (preserves project state and hub)')
|
|
1656
|
+
.description('Remove slash-commands from ~/.claude/commands/ant/ and ~/.opencode/ (preserves project state and hub)')
|
|
1436
1657
|
.action(wrapCommand(async () => {
|
|
1437
1658
|
log(c.header(`aether-colony v${VERSION} — uninstalling...`));
|
|
1438
1659
|
|
|
@@ -1444,6 +1665,26 @@ program
|
|
|
1444
1665
|
log(' Claude Code commands already removed.');
|
|
1445
1666
|
}
|
|
1446
1667
|
|
|
1668
|
+
// Remove Claude Code agents
|
|
1669
|
+
if (fs.existsSync(AGENTS_DEST)) {
|
|
1670
|
+
const n = removeDirSync(AGENTS_DEST);
|
|
1671
|
+
log(` Removed: ${n} agent files from ${AGENTS_DEST}`);
|
|
1672
|
+
}
|
|
1673
|
+
|
|
1674
|
+
// Remove OpenCode commands (only our files, preserve others)
|
|
1675
|
+
const opencodeCmdsSrc = path.join(PACKAGE_DIR, '.opencode', 'commands', 'ant');
|
|
1676
|
+
if (fs.existsSync(OPENCODE_COMMANDS_DEST) && fs.existsSync(opencodeCmdsSrc)) {
|
|
1677
|
+
const n = removeFilesFromSource(opencodeCmdsSrc, OPENCODE_COMMANDS_DEST);
|
|
1678
|
+
log(` Removed: ${n} command files from ${OPENCODE_COMMANDS_DEST}`);
|
|
1679
|
+
}
|
|
1680
|
+
|
|
1681
|
+
// Remove OpenCode agents (only our files, preserve others)
|
|
1682
|
+
const opencodeAgentsSrc = path.join(PACKAGE_DIR, '.opencode', 'agents');
|
|
1683
|
+
if (fs.existsSync(OPENCODE_AGENTS_DEST) && fs.existsSync(opencodeAgentsSrc)) {
|
|
1684
|
+
const n = removeFilesFromSource(opencodeAgentsSrc, OPENCODE_AGENTS_DEST);
|
|
1685
|
+
log(` Removed: ${n} agent files from ${OPENCODE_AGENTS_DEST}`);
|
|
1686
|
+
}
|
|
1687
|
+
|
|
1447
1688
|
log('');
|
|
1448
1689
|
log(c.success('Uninstall complete. Per-project .aether/data/ directories are untouched.'));
|
|
1449
1690
|
log(` ${c.colony('Hub:')} ${c.dim('~/.aether/')} preserved (remove manually if desired).`);
|
|
@@ -1681,261 +1922,6 @@ program
|
|
|
1681
1922
|
}
|
|
1682
1923
|
}));
|
|
1683
1924
|
|
|
1684
|
-
// Caste emoji mapping for display
|
|
1685
|
-
const CASTE_EMOJIS = {
|
|
1686
|
-
builder: '🔨',
|
|
1687
|
-
watcher: '👁️',
|
|
1688
|
-
scout: '🔍',
|
|
1689
|
-
chaos: '🎲',
|
|
1690
|
-
oracle: '🔮',
|
|
1691
|
-
architect: '🏗️',
|
|
1692
|
-
prime: '🏛️',
|
|
1693
|
-
colonizer: '🌱',
|
|
1694
|
-
route_setter: '🧭',
|
|
1695
|
-
archaeologist: '📜',
|
|
1696
|
-
};
|
|
1697
|
-
|
|
1698
|
-
/**
|
|
1699
|
-
* Format context window for display
|
|
1700
|
-
* @param {number} contextWindow - Context window size
|
|
1701
|
-
* @returns {string} Formatted string (e.g., "256K")
|
|
1702
|
-
*/
|
|
1703
|
-
function formatContextWindow(contextWindow) {
|
|
1704
|
-
if (!contextWindow) return '-';
|
|
1705
|
-
if (contextWindow >= 1000) {
|
|
1706
|
-
return `${Math.round(contextWindow / 1000)}K`;
|
|
1707
|
-
}
|
|
1708
|
-
return String(contextWindow);
|
|
1709
|
-
}
|
|
1710
|
-
|
|
1711
|
-
// Caste-models command - Manage caste-to-model assignments
|
|
1712
|
-
const casteModelsCmd = program
|
|
1713
|
-
.command('caste-models')
|
|
1714
|
-
.description('Manage caste-to-model assignments');
|
|
1715
|
-
|
|
1716
|
-
// list subcommand
|
|
1717
|
-
casteModelsCmd
|
|
1718
|
-
.command('list')
|
|
1719
|
-
.description('List current model assignments per caste')
|
|
1720
|
-
.option('--verify', 'Verify model availability on proxy')
|
|
1721
|
-
.action(wrapCommand(async (options) => {
|
|
1722
|
-
const repoPath = process.cwd();
|
|
1723
|
-
const profiles = loadModelProfiles(repoPath);
|
|
1724
|
-
const overrides = getUserOverrides(profiles);
|
|
1725
|
-
const proxyConfig = getProxyConfig(profiles);
|
|
1726
|
-
|
|
1727
|
-
// Check proxy health
|
|
1728
|
-
let proxyHealth = null;
|
|
1729
|
-
let proxyModels = null;
|
|
1730
|
-
if (proxyConfig?.endpoint) {
|
|
1731
|
-
proxyHealth = await checkProxyHealth(proxyConfig.endpoint);
|
|
1732
|
-
if (proxyHealth.healthy && proxyHealth.models) {
|
|
1733
|
-
proxyModels = proxyHealth.models;
|
|
1734
|
-
}
|
|
1735
|
-
}
|
|
1736
|
-
|
|
1737
|
-
console.log(c.header('Caste Model Assignments\n'));
|
|
1738
|
-
|
|
1739
|
-
// Display proxy status
|
|
1740
|
-
if (proxyConfig?.endpoint) {
|
|
1741
|
-
const proxyStatus = formatProxyStatusColored(proxyHealth, c) + c.dim(` @ ${proxyConfig.endpoint}`);
|
|
1742
|
-
console.log(`Proxy: ${proxyStatus}`);
|
|
1743
|
-
if (!proxyHealth?.healthy) {
|
|
1744
|
-
console.log(c.warning('Warning: Using default model (kimi-k2.5) for all castes'));
|
|
1745
|
-
}
|
|
1746
|
-
console.log('');
|
|
1747
|
-
}
|
|
1748
|
-
|
|
1749
|
-
// Table header - add Verify column if --verify flag
|
|
1750
|
-
const verifyFlag = options.verify;
|
|
1751
|
-
const header = verifyFlag
|
|
1752
|
-
? `${'Caste'.padEnd(14)} ${'Model'.padEnd(14)} ${'Provider'.padEnd(10)} ${'Context'.padEnd(8)} Verify Status`
|
|
1753
|
-
: `${'Caste'.padEnd(14)} ${'Model'.padEnd(14)} ${'Provider'.padEnd(10)} ${'Context'.padEnd(8)} Status`;
|
|
1754
|
-
console.log(header);
|
|
1755
|
-
console.log(verifyFlag ? '─'.repeat(70) : '─'.repeat(60));
|
|
1756
|
-
|
|
1757
|
-
// Get all assignments
|
|
1758
|
-
const assignments = getAllAssignments(profiles);
|
|
1759
|
-
|
|
1760
|
-
for (const assignment of assignments) {
|
|
1761
|
-
const emoji = CASTE_EMOJIS[assignment.caste] || '•';
|
|
1762
|
-
const casteName = assignment.caste.charAt(0).toUpperCase() + assignment.caste.slice(1);
|
|
1763
|
-
const casteDisplay = `${emoji} ${casteName}`;
|
|
1764
|
-
|
|
1765
|
-
// Check for override
|
|
1766
|
-
const hasOverride = overrides[assignment.caste] !== undefined;
|
|
1767
|
-
const effectiveModel = getEffectiveModel(profiles, assignment.caste);
|
|
1768
|
-
const modelDisplay = effectiveModel.model + (hasOverride ? ' (override)' : '');
|
|
1769
|
-
|
|
1770
|
-
// Get model metadata
|
|
1771
|
-
const metadata = getModelMetadata(profiles, effectiveModel.model);
|
|
1772
|
-
const provider = metadata?.provider || assignment.provider || '-';
|
|
1773
|
-
const contextWindow = formatContextWindow(metadata?.context_window);
|
|
1774
|
-
|
|
1775
|
-
// Status indicator based on proxy health
|
|
1776
|
-
const status = proxyHealth?.healthy ? '✓' : '⚠';
|
|
1777
|
-
|
|
1778
|
-
// Verify flag - check if model is available on proxy
|
|
1779
|
-
let verifyStatus = '';
|
|
1780
|
-
if (verifyFlag) {
|
|
1781
|
-
if (proxyModels) {
|
|
1782
|
-
const isAvailable = proxyModels.includes(effectiveModel.model);
|
|
1783
|
-
verifyStatus = isAvailable ? '✓' : '✗';
|
|
1784
|
-
} else {
|
|
1785
|
-
verifyStatus = '?';
|
|
1786
|
-
}
|
|
1787
|
-
console.log(
|
|
1788
|
-
`${casteDisplay.padEnd(14)} ${modelDisplay.padEnd(14)} ${provider.padEnd(10)} ${contextWindow.padEnd(8)} ${verifyStatus.padEnd(7)} ${status}`
|
|
1789
|
-
);
|
|
1790
|
-
} else {
|
|
1791
|
-
console.log(
|
|
1792
|
-
`${casteDisplay.padEnd(14)} ${modelDisplay.padEnd(14)} ${provider.padEnd(10)} ${contextWindow.padEnd(8)} ${status}`
|
|
1793
|
-
);
|
|
1794
|
-
}
|
|
1795
|
-
}
|
|
1796
|
-
|
|
1797
|
-
// Show overrides summary if any exist
|
|
1798
|
-
const overrideCount = Object.keys(overrides).length;
|
|
1799
|
-
if (overrideCount > 0) {
|
|
1800
|
-
console.log('');
|
|
1801
|
-
console.log(c.info(`Active overrides: ${overrideCount}`));
|
|
1802
|
-
for (const [caste, model] of Object.entries(overrides)) {
|
|
1803
|
-
console.log(` ${caste}: ${model}`);
|
|
1804
|
-
}
|
|
1805
|
-
}
|
|
1806
|
-
}));
|
|
1807
|
-
|
|
1808
|
-
// set subcommand
|
|
1809
|
-
casteModelsCmd
|
|
1810
|
-
.command('set')
|
|
1811
|
-
.description('Set model override for a caste')
|
|
1812
|
-
.argument('<assignment>', 'caste=model (e.g., builder=glm-5)')
|
|
1813
|
-
.action(wrapCommand(async (assignment) => {
|
|
1814
|
-
// Parse caste=model format
|
|
1815
|
-
const match = assignment.match(/^([^=]+)=(.+)$/);
|
|
1816
|
-
if (!match) {
|
|
1817
|
-
const error = new ValidationError(
|
|
1818
|
-
`Invalid assignment format: '${assignment}'`,
|
|
1819
|
-
{ received: assignment },
|
|
1820
|
-
'Use format: caste=model (e.g., builder=glm-5)'
|
|
1821
|
-
);
|
|
1822
|
-
throw error;
|
|
1823
|
-
}
|
|
1824
|
-
|
|
1825
|
-
const [, caste, model] = match;
|
|
1826
|
-
|
|
1827
|
-
const repoPath = process.cwd();
|
|
1828
|
-
|
|
1829
|
-
// Validate and set
|
|
1830
|
-
try {
|
|
1831
|
-
const result = setModelOverride(repoPath, caste, model);
|
|
1832
|
-
|
|
1833
|
-
if (result.previous) {
|
|
1834
|
-
console.log(c.success(`Updated ${caste}: ${result.previous} → ${model}`));
|
|
1835
|
-
} else {
|
|
1836
|
-
console.log(c.success(`Set ${caste} to ${model}`));
|
|
1837
|
-
}
|
|
1838
|
-
} catch (error) {
|
|
1839
|
-
if (error.name === 'ValidationError') {
|
|
1840
|
-
// Add helpful suggestions
|
|
1841
|
-
if (error.details?.validCastes) {
|
|
1842
|
-
console.error(c.error(`Error: ${error.message}`));
|
|
1843
|
-
console.error('\nValid castes:');
|
|
1844
|
-
for (const casteName of error.details.validCastes) {
|
|
1845
|
-
const emoji = CASTE_EMOJIS[casteName] || '•';
|
|
1846
|
-
console.error(` ${emoji} ${casteName}`);
|
|
1847
|
-
}
|
|
1848
|
-
} else if (error.details?.validModels) {
|
|
1849
|
-
console.error(c.error(`Error: ${error.message}`));
|
|
1850
|
-
console.error('\nValid models:');
|
|
1851
|
-
for (const modelName of error.details.validModels) {
|
|
1852
|
-
console.error(` • ${modelName}`);
|
|
1853
|
-
}
|
|
1854
|
-
}
|
|
1855
|
-
process.exit(1);
|
|
1856
|
-
}
|
|
1857
|
-
throw error;
|
|
1858
|
-
}
|
|
1859
|
-
}));
|
|
1860
|
-
|
|
1861
|
-
// reset subcommand
|
|
1862
|
-
casteModelsCmd
|
|
1863
|
-
.command('reset')
|
|
1864
|
-
.description('Reset caste to default model (remove override)')
|
|
1865
|
-
.argument('<caste>', 'caste name (e.g., builder)')
|
|
1866
|
-
.action(wrapCommand(async (caste) => {
|
|
1867
|
-
const repoPath = process.cwd();
|
|
1868
|
-
|
|
1869
|
-
try {
|
|
1870
|
-
const result = resetModelOverride(repoPath, caste);
|
|
1871
|
-
|
|
1872
|
-
if (result.hadOverride) {
|
|
1873
|
-
console.log(c.success(`Reset ${caste} to default model`));
|
|
1874
|
-
} else {
|
|
1875
|
-
console.log(c.info(`${caste} was already using default model`));
|
|
1876
|
-
}
|
|
1877
|
-
} catch (error) {
|
|
1878
|
-
if (error.name === 'ValidationError' && error.details?.validCastes) {
|
|
1879
|
-
console.error(c.error(`Error: ${error.message}`));
|
|
1880
|
-
console.error('\nValid castes:');
|
|
1881
|
-
for (const casteName of error.details.validCastes) {
|
|
1882
|
-
const emoji = CASTE_EMOJIS[casteName] || '•';
|
|
1883
|
-
console.error(` ${emoji} ${casteName}`);
|
|
1884
|
-
}
|
|
1885
|
-
process.exit(1);
|
|
1886
|
-
}
|
|
1887
|
-
throw error;
|
|
1888
|
-
}
|
|
1889
|
-
}));
|
|
1890
|
-
|
|
1891
|
-
// Verify-models command - Verify model routing configuration
|
|
1892
|
-
program
|
|
1893
|
-
.command('verify-models')
|
|
1894
|
-
.description('Verify model routing configuration is active')
|
|
1895
|
-
.action(wrapCommand(async () => {
|
|
1896
|
-
const repoPath = process.cwd();
|
|
1897
|
-
const report = await createVerificationReport(repoPath);
|
|
1898
|
-
|
|
1899
|
-
console.log('=== Model Routing Verification ===\n');
|
|
1900
|
-
|
|
1901
|
-
// Proxy status
|
|
1902
|
-
console.log(`LiteLLM Proxy: ${report.proxy.running ? '✓ Running' : '✗ Not running'}`);
|
|
1903
|
-
if (report.proxy.running) {
|
|
1904
|
-
console.log(` Latency: ${report.proxy.latency}ms`);
|
|
1905
|
-
}
|
|
1906
|
-
|
|
1907
|
-
// Environment
|
|
1908
|
-
console.log(`\nEnvironment:`);
|
|
1909
|
-
console.log(` ANTHROPIC_MODEL: ${report.env.model || '(not set)'}`);
|
|
1910
|
-
console.log(` ANTHROPIC_BASE_URL: ${report.env.baseUrl || '(not set)'}`);
|
|
1911
|
-
|
|
1912
|
-
// Caste assignments
|
|
1913
|
-
console.log(`\nCaste Model Assignments:`);
|
|
1914
|
-
for (const [caste, info] of Object.entries(report.castes)) {
|
|
1915
|
-
const status = info.assigned ? '✓' : '✗';
|
|
1916
|
-
console.log(` ${status} ${caste}: ${info.model || 'default'}`);
|
|
1917
|
-
}
|
|
1918
|
-
|
|
1919
|
-
// Model profiles file
|
|
1920
|
-
console.log(`\nModel Profiles File:`);
|
|
1921
|
-
if (report.profilesFile.exists) {
|
|
1922
|
-
console.log(` ✓ Found: ${report.profilesFile.path}`);
|
|
1923
|
-
const profileCount = Object.keys(report.profilesFile.profiles).length;
|
|
1924
|
-
console.log(` Profiles: ${profileCount} castes configured`);
|
|
1925
|
-
} else {
|
|
1926
|
-
console.log(` ✗ Not found: ${report.profilesFile.path}`);
|
|
1927
|
-
}
|
|
1928
|
-
|
|
1929
|
-
// Issues
|
|
1930
|
-
if (report.issues.length > 0) {
|
|
1931
|
-
console.log(`\nIssues Found:`);
|
|
1932
|
-
report.issues.forEach(issue => console.log(` ⚠ ${issue}`));
|
|
1933
|
-
}
|
|
1934
|
-
|
|
1935
|
-
// Recommendation
|
|
1936
|
-
console.log(`\n${report.recommendation}`);
|
|
1937
|
-
}));
|
|
1938
|
-
|
|
1939
1925
|
// Spawn-log command - Log a worker spawn event
|
|
1940
1926
|
program
|
|
1941
1927
|
.command('spawn-log')
|
|
@@ -1969,156 +1955,100 @@ program
|
|
|
1969
1955
|
console.log(tree);
|
|
1970
1956
|
}));
|
|
1971
1957
|
|
|
1972
|
-
//
|
|
1958
|
+
// Status command - Show colony status
|
|
1973
1959
|
program
|
|
1974
|
-
.command('
|
|
1975
|
-
.description('
|
|
1976
|
-
.
|
|
1960
|
+
.command('status')
|
|
1961
|
+
.description('Show colony status')
|
|
1962
|
+
.option('-j, --json', 'Output as JSON')
|
|
1963
|
+
.action(wrapCommand(async (options) => {
|
|
1977
1964
|
const repoPath = process.cwd();
|
|
1978
|
-
const
|
|
1965
|
+
const colonyStatePath = path.join(repoPath, '.aether', 'data', 'COLONY_STATE.json');
|
|
1979
1966
|
|
|
1980
|
-
|
|
1981
|
-
|
|
1967
|
+
// Check if colony exists
|
|
1968
|
+
if (!fs.existsSync(colonyStatePath)) {
|
|
1969
|
+
console.log(c.warning('No colony found in current directory.'));
|
|
1970
|
+
console.log(c.dim('Run /ant:init to create a new colony, or cd to a project with an existing colony.'));
|
|
1982
1971
|
return;
|
|
1983
1972
|
}
|
|
1984
1973
|
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
.action(wrapCommand(async () => {
|
|
1994
|
-
// Default action: show summary
|
|
1995
|
-
const repoPath = process.cwd();
|
|
1996
|
-
const summary = getTelemetrySummary(repoPath);
|
|
1997
|
-
|
|
1998
|
-
console.log(c.header('Model Performance Telemetry\n'));
|
|
1999
|
-
console.log(`Total Spawns: ${summary.total_spawns}`);
|
|
2000
|
-
console.log(`Models Used: ${summary.total_models}\n`);
|
|
2001
|
-
|
|
2002
|
-
if (summary.total_spawns === 0) {
|
|
2003
|
-
console.log(c.info('No telemetry data yet. Run some builds to collect data.'));
|
|
1974
|
+
// Load colony state
|
|
1975
|
+
let state;
|
|
1976
|
+
try {
|
|
1977
|
+
state = JSON.parse(fs.readFileSync(colonyStatePath, 'utf8'));
|
|
1978
|
+
} catch (err) {
|
|
1979
|
+
console.log(c.error('Could not read colony state.'));
|
|
1980
|
+
console.log(c.dim(`Error: ${err.message}`));
|
|
1981
|
+
console.log(c.dim('The colony state file may be corrupted. Consider running /ant:init to reinitialize.'));
|
|
2004
1982
|
return;
|
|
2005
1983
|
}
|
|
2006
1984
|
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
const rateColor = stats.success_rate >= 0.9 ? c.success :
|
|
2012
|
-
stats.success_rate >= 0.7 ? c.warning : c.error;
|
|
2013
|
-
console.log(` ${model.padEnd(15)} ${String(stats.total_spawns).padStart(4)} spawns ${rateColor(rate + '%')} success`);
|
|
2014
|
-
}
|
|
2015
|
-
|
|
2016
|
-
if (summary.recent_decisions.length > 0) {
|
|
2017
|
-
console.log('\nRecent Routing Decisions:');
|
|
2018
|
-
console.log('─'.repeat(60));
|
|
2019
|
-
for (const decision of summary.recent_decisions.slice(-5)) {
|
|
2020
|
-
console.log(` ${decision.caste.padEnd(10)} → ${decision.selected_model.padEnd(12)} (${decision.source})`);
|
|
2021
|
-
}
|
|
1985
|
+
// JSON output
|
|
1986
|
+
if (options.json) {
|
|
1987
|
+
console.log(JSON.stringify(state, null, 2));
|
|
1988
|
+
return;
|
|
2022
1989
|
}
|
|
2023
|
-
}));
|
|
2024
1990
|
|
|
2025
|
-
//
|
|
2026
|
-
|
|
2027
|
-
.command('summary')
|
|
2028
|
-
.description('Show overall telemetry summary')
|
|
2029
|
-
.action(wrapCommand(async () => {
|
|
2030
|
-
const repoPath = process.cwd();
|
|
2031
|
-
const summary = getTelemetrySummary(repoPath);
|
|
1991
|
+
// Dashboard output
|
|
1992
|
+
console.log(c.header('Colony Status\n'));
|
|
2032
1993
|
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
if (summary.total_spawns === 0) {
|
|
2038
|
-
console.log(c.info('No telemetry data yet. Run some builds to collect data.'));
|
|
2039
|
-
return;
|
|
1994
|
+
// Goal
|
|
1995
|
+
if (state.goal) {
|
|
1996
|
+
console.log(`${c.queen('Goal:')} ${state.goal}`);
|
|
2040
1997
|
}
|
|
2041
1998
|
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
console.log(
|
|
1999
|
+
// State
|
|
2000
|
+
if (state.state) {
|
|
2001
|
+
const stateDisplay = state.state === 'BUILDING' ? c.success(state.state) :
|
|
2002
|
+
state.state === 'PLANNING' ? c.warning(state.state) :
|
|
2003
|
+
state.state === 'COMPLETED' ? c.success(state.state) :
|
|
2004
|
+
state.state;
|
|
2005
|
+
console.log(`${c.colony('State:')} ${stateDisplay}`);
|
|
2049
2006
|
}
|
|
2050
2007
|
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
console.log('
|
|
2054
|
-
for (const decision of summary.recent_decisions.slice(-5)) {
|
|
2055
|
-
console.log(` ${decision.caste.padEnd(10)} → ${decision.selected_model.padEnd(12)} (${decision.source})`);
|
|
2056
|
-
}
|
|
2008
|
+
// Phase
|
|
2009
|
+
if (state.current_phase !== undefined) {
|
|
2010
|
+
console.log(`${c.info('Phase:')} ${state.current_phase}`);
|
|
2057
2011
|
}
|
|
2058
|
-
}));
|
|
2059
2012
|
|
|
2060
|
-
//
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
.description('Show detailed performance for a specific model')
|
|
2064
|
-
.action(wrapCommand(async (modelName) => {
|
|
2065
|
-
const repoPath = process.cwd();
|
|
2066
|
-
const performance = getModelPerformance(repoPath, modelName);
|
|
2067
|
-
|
|
2068
|
-
if (!performance) {
|
|
2069
|
-
console.log(c.warning(`No data for model: ${modelName}`));
|
|
2070
|
-
return;
|
|
2013
|
+
// Version
|
|
2014
|
+
if (state.version) {
|
|
2015
|
+
console.log(`${c.dim('Version:')} ${state.version}`);
|
|
2071
2016
|
}
|
|
2072
2017
|
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2018
|
+
// Last updated
|
|
2019
|
+
if (state.last_updated) {
|
|
2020
|
+
const lastUpdated = new Date(state.last_updated);
|
|
2021
|
+
const now = new Date();
|
|
2022
|
+
const hoursAgo = Math.round((now - lastUpdated) / (1000 * 60 * 60));
|
|
2023
|
+
const timeDisplay = hoursAgo < 1 ? 'just now' :
|
|
2024
|
+
hoursAgo < 24 ? `${hoursAgo} hours ago` :
|
|
2025
|
+
`${Math.round(hoursAgo / 24)} days ago`;
|
|
2026
|
+
console.log(`${c.dim('Last updated:')} ${timeDisplay}`);
|
|
2027
|
+
}
|
|
2079
2028
|
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
console.log('
|
|
2083
|
-
for (const [caste, stats] of Object.entries(performance.by_caste)) {
|
|
2084
|
-
const casteRate = stats.spawns > 0 ? (stats.success / stats.spawns * 100).toFixed(1) : '0.0';
|
|
2085
|
-
console.log(` ${caste.padEnd(12)} ${String(stats.spawns).padStart(4)} spawns ${casteRate}% success`);
|
|
2086
|
-
}
|
|
2029
|
+
// Event count
|
|
2030
|
+
if (state.events && state.events.length > 0) {
|
|
2031
|
+
console.log(`${c.dim('Events:')} ${state.events.length}`);
|
|
2087
2032
|
}
|
|
2033
|
+
|
|
2034
|
+
console.log('');
|
|
2088
2035
|
}));
|
|
2089
2036
|
|
|
2090
|
-
//
|
|
2091
|
-
|
|
2092
|
-
.command('
|
|
2093
|
-
.description('
|
|
2037
|
+
// Nestmates command - List sibling colonies
|
|
2038
|
+
program
|
|
2039
|
+
.command('nestmates')
|
|
2040
|
+
.description('List sibling colonies (nestmates)')
|
|
2094
2041
|
.action(wrapCommand(async () => {
|
|
2095
2042
|
const repoPath = process.cwd();
|
|
2096
|
-
const
|
|
2097
|
-
|
|
2098
|
-
console.log(c.header('Model Performance Ranking\n'));
|
|
2043
|
+
const nestmates = findNestmates(repoPath);
|
|
2099
2044
|
|
|
2100
|
-
if (
|
|
2101
|
-
console.log(
|
|
2045
|
+
if (nestmates.length === 0) {
|
|
2046
|
+
console.log('No nestmates found (sibling directories with .aether/).');
|
|
2102
2047
|
return;
|
|
2103
2048
|
}
|
|
2104
2049
|
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
.map(([model, stats]) => ({ model, ...stats }))
|
|
2108
|
-
.sort((a, b) => b.success_rate - a.success_rate);
|
|
2109
|
-
|
|
2110
|
-
console.log(`${'Rank'.padEnd(6)} ${'Model'.padEnd(15)} ${'Spawns'.padStart(6)} ${'Success'.padStart(8)} ${'Rate'.padStart(6)}`);
|
|
2111
|
-
console.log('─'.repeat(60));
|
|
2112
|
-
|
|
2113
|
-
ranked.forEach((m, i) => {
|
|
2114
|
-
const rank = `${i + 1}.`.padEnd(6);
|
|
2115
|
-
const rate = (m.success_rate * 100).toFixed(1);
|
|
2116
|
-
const rateColor = m.success_rate >= 0.9 ? c.success :
|
|
2117
|
-
m.success_rate >= 0.7 ? c.warning : c.error;
|
|
2118
|
-
console.log(`${rank} ${m.model.padEnd(15)} ${String(m.total_spawns).padStart(6)} ${String(m.successful_completions || 0).padStart(8)} ${rateColor(rate.padStart(5) + '%')}`);
|
|
2119
|
-
});
|
|
2120
|
-
|
|
2121
|
-
console.log('\n' + c.dim('Tip: Use "aether telemetry model <name>" for detailed stats'));
|
|
2050
|
+
console.log(`Found ${nestmates.length} nestmate(s):\n`);
|
|
2051
|
+
console.log(formatNestmates(nestmates));
|
|
2122
2052
|
}));
|
|
2123
2053
|
|
|
2124
2054
|
// Context command - Show auto-loaded context
|
|
@@ -2191,8 +2121,7 @@ program
|
|
|
2191
2121
|
console.log('Next steps:');
|
|
2192
2122
|
console.log(' 1. Define your colony goal in .aether/data/COLONY_STATE.json');
|
|
2193
2123
|
console.log(' 2. Run: aether sync-state');
|
|
2194
|
-
console.log(' 3.
|
|
2195
|
-
console.log(' 4. Start building: /ant:init');
|
|
2124
|
+
console.log(' 3. Start building: /ant:init');
|
|
2196
2125
|
}
|
|
2197
2126
|
}));
|
|
2198
2127
|
|
|
@@ -2204,7 +2133,6 @@ program.on('--help', () => {
|
|
|
2204
2133
|
console.log(' install Install slash-commands and set up distribution hub');
|
|
2205
2134
|
console.log(' update Update current repo from hub');
|
|
2206
2135
|
console.log(' sync-state Synchronize COLONY_STATE.json with .planning/STATE.md');
|
|
2207
|
-
console.log(' verify-models Verify model routing configuration');
|
|
2208
2136
|
console.log(' version Show installed version');
|
|
2209
2137
|
console.log(' uninstall Remove slash-commands (preserves project state and hub)');
|
|
2210
2138
|
console.log('');
|
|
@@ -2242,7 +2170,7 @@ module.exports = {
|
|
|
2242
2170
|
saveCheckpointMetadata,
|
|
2243
2171
|
isUserData,
|
|
2244
2172
|
syncDirWithCleanup,
|
|
2245
|
-
|
|
2173
|
+
syncSkillsToHub,
|
|
2246
2174
|
listFilesRecursive,
|
|
2247
2175
|
cleanEmptyDirs
|
|
2248
2176
|
};
|