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.
Files changed (378) hide show
  1. package/.aether/aether-utils.sh +5354 -0
  2. package/.aether/agents-claude/aether-ambassador.md +265 -0
  3. package/.aether/agents-claude/aether-archaeologist.md +327 -0
  4. package/.aether/agents-claude/aether-architect.md +236 -0
  5. package/.aether/agents-claude/aether-auditor.md +271 -0
  6. package/.aether/agents-claude/aether-builder.md +224 -0
  7. package/.aether/agents-claude/aether-chaos.md +269 -0
  8. package/.aether/agents-claude/aether-chronicler.md +305 -0
  9. package/.aether/agents-claude/aether-gatekeeper.md +330 -0
  10. package/.aether/agents-claude/aether-includer.md +374 -0
  11. package/.aether/agents-claude/aether-keeper.md +272 -0
  12. package/.aether/agents-claude/aether-measurer.md +322 -0
  13. package/.aether/agents-claude/aether-oracle.md +237 -0
  14. package/.aether/agents-claude/aether-probe.md +211 -0
  15. package/.aether/agents-claude/aether-queen.md +330 -0
  16. package/.aether/agents-claude/aether-route-setter.md +178 -0
  17. package/.aether/agents-claude/aether-sage.md +418 -0
  18. package/.aether/agents-claude/aether-scout.md +179 -0
  19. package/.aether/agents-claude/aether-surveyor-disciplines.md +417 -0
  20. package/.aether/agents-claude/aether-surveyor-nest.md +355 -0
  21. package/.aether/agents-claude/aether-surveyor-pathogens.md +289 -0
  22. package/.aether/agents-claude/aether-surveyor-provisions.md +360 -0
  23. package/.aether/agents-claude/aether-tracker.md +270 -0
  24. package/.aether/agents-claude/aether-watcher.md +280 -0
  25. package/.aether/agents-claude/aether-weaver.md +248 -0
  26. package/.aether/commands/archaeology.yaml +653 -0
  27. package/.aether/commands/build.yaml +1221 -0
  28. package/.aether/commands/chaos.yaml +653 -0
  29. package/.aether/commands/colonize.yaml +438 -0
  30. package/.aether/commands/continue.yaml +1484 -0
  31. package/.aether/commands/council.yaml +304 -0
  32. package/.aether/commands/data-clean.yaml +80 -0
  33. package/.aether/commands/dream.yaml +275 -0
  34. package/.aether/commands/entomb.yaml +863 -0
  35. package/.aether/commands/export-signals.yaml +64 -0
  36. package/.aether/commands/feedback.yaml +158 -0
  37. package/.aether/commands/flag.yaml +160 -0
  38. package/.aether/commands/flags.yaml +177 -0
  39. package/.aether/commands/focus.yaml +112 -0
  40. package/.aether/commands/help.yaml +167 -0
  41. package/.aether/commands/history.yaml +137 -0
  42. package/.aether/commands/import-signals.yaml +79 -0
  43. package/.aether/commands/init.yaml +469 -0
  44. package/.aether/commands/insert-phase.yaml +98 -0
  45. package/.aether/commands/interpret.yaml +285 -0
  46. package/.aether/commands/lay-eggs.yaml +224 -0
  47. package/.aether/commands/maturity.yaml +122 -0
  48. package/.aether/commands/memory-details.yaml +74 -0
  49. package/.aether/commands/migrate-state.yaml +174 -0
  50. package/.aether/commands/oracle.yaml +1224 -0
  51. package/.aether/commands/organize.yaml +446 -0
  52. package/.aether/commands/patrol.yaml +621 -0
  53. package/.aether/commands/pause-colony.yaml +424 -0
  54. package/.aether/commands/phase.yaml +124 -0
  55. package/.aether/commands/pheromones.yaml +153 -0
  56. package/.aether/commands/plan.yaml +1313 -0
  57. package/.aether/commands/preferences.yaml +63 -0
  58. package/.aether/commands/redirect.yaml +123 -0
  59. package/.aether/commands/resume-colony.yaml +373 -0
  60. package/.aether/commands/resume.yaml +398 -0
  61. package/.aether/commands/run.yaml +193 -0
  62. package/.aether/commands/seal.yaml +1205 -0
  63. package/.aether/commands/skill-create.yaml +337 -0
  64. package/.aether/commands/status.yaml +364 -0
  65. package/.aether/commands/swarm.yaml +352 -0
  66. package/.aether/commands/tunnels.yaml +814 -0
  67. package/.aether/commands/update.yaml +131 -0
  68. package/.aether/commands/verify-castes.yaml +159 -0
  69. package/.aether/commands/watch.yaml +454 -0
  70. package/.aether/docs/INCIDENT_TEMPLATE.md +32 -0
  71. package/.aether/docs/QUEEN-SYSTEM.md +211 -0
  72. package/.aether/docs/README.md +98 -0
  73. package/.aether/docs/caste-system.md +48 -0
  74. package/.aether/docs/command-playbooks/README.md +23 -0
  75. package/.aether/docs/command-playbooks/build-complete.md +349 -0
  76. package/.aether/docs/command-playbooks/build-context.md +282 -0
  77. package/.aether/docs/command-playbooks/build-full.md +1682 -0
  78. package/.aether/docs/command-playbooks/build-prep.md +283 -0
  79. package/.aether/docs/command-playbooks/build-verify.md +405 -0
  80. package/.aether/docs/command-playbooks/build-wave.md +749 -0
  81. package/.aether/docs/command-playbooks/continue-advance.md +524 -0
  82. package/.aether/docs/command-playbooks/continue-finalize.md +447 -0
  83. package/.aether/docs/command-playbooks/continue-full.md +1724 -0
  84. package/.aether/docs/command-playbooks/continue-gates.md +686 -0
  85. package/.aether/docs/command-playbooks/continue-verify.md +406 -0
  86. package/.aether/docs/context-continuity.md +84 -0
  87. package/{runtime → .aether/docs/disciplines}/DISCIPLINES.md +13 -11
  88. package/.aether/docs/error-codes.md +268 -0
  89. package/.aether/docs/known-issues.md +94 -0
  90. package/{runtime → .aether}/docs/pheromones.md +86 -6
  91. package/.aether/docs/plans/pheromone-display-plan.md +257 -0
  92. package/.aether/docs/queen-commands.md +98 -0
  93. package/.aether/docs/source-of-truth-map.md +132 -0
  94. package/.aether/docs/xml-utilities.md +47 -0
  95. package/{runtime → .aether}/exchange/pheromone-xml.sh +2 -1
  96. package/{runtime → .aether}/exchange/registry-xml.sh +7 -3
  97. package/{runtime → .aether}/exchange/wisdom-xml.sh +11 -4
  98. package/.aether/rules/aether-colony.md +144 -0
  99. package/.aether/schemas/example-prompt-builder.xml +234 -0
  100. package/.aether/scripts/incident-test-add.sh +47 -0
  101. package/.aether/scripts/weekly-audit.sh +79 -0
  102. package/.aether/skills/.index.json +649 -0
  103. package/.aether/skills/colony/.manifest.json +16 -0
  104. package/.aether/skills/colony/build-discipline/SKILL.md +78 -0
  105. package/.aether/skills/colony/colony-interaction/SKILL.md +56 -0
  106. package/.aether/skills/colony/colony-lifecycle/SKILL.md +77 -0
  107. package/.aether/skills/colony/colony-visuals/SKILL.md +112 -0
  108. package/.aether/skills/colony/context-management/SKILL.md +80 -0
  109. package/.aether/skills/colony/error-presentation/SKILL.md +99 -0
  110. package/.aether/skills/colony/pheromone-protocol/SKILL.md +79 -0
  111. package/.aether/skills/colony/pheromone-visibility/SKILL.md +81 -0
  112. package/.aether/skills/colony/state-safety/SKILL.md +84 -0
  113. package/.aether/skills/colony/worker-priming/SKILL.md +82 -0
  114. package/.aether/skills/domain/.manifest.json +24 -0
  115. package/.aether/skills/domain/README.md +33 -0
  116. package/.aether/skills/domain/django/SKILL.md +49 -0
  117. package/.aether/skills/domain/docker/SKILL.md +52 -0
  118. package/.aether/skills/domain/golang/SKILL.md +52 -0
  119. package/.aether/skills/domain/graphql/SKILL.md +51 -0
  120. package/.aether/skills/domain/html-css/SKILL.md +48 -0
  121. package/.aether/skills/domain/nextjs/SKILL.md +45 -0
  122. package/.aether/skills/domain/nodejs/SKILL.md +53 -0
  123. package/.aether/skills/domain/postgresql/SKILL.md +53 -0
  124. package/.aether/skills/domain/prisma/SKILL.md +59 -0
  125. package/.aether/skills/domain/python/SKILL.md +50 -0
  126. package/.aether/skills/domain/rails/SKILL.md +52 -0
  127. package/.aether/skills/domain/react/SKILL.md +45 -0
  128. package/.aether/skills/domain/rest-api/SKILL.md +58 -0
  129. package/.aether/skills/domain/svelte/SKILL.md +47 -0
  130. package/.aether/skills/domain/tailwind/SKILL.md +45 -0
  131. package/.aether/skills/domain/testing/SKILL.md +53 -0
  132. package/.aether/skills/domain/typescript/SKILL.md +58 -0
  133. package/.aether/skills/domain/vue/SKILL.md +49 -0
  134. package/.aether/templates/QUEEN.md.template +61 -0
  135. package/.aether/templates/colony-state-reset.jq.template +23 -0
  136. package/.aether/templates/colony-state.template.json +39 -0
  137. package/.aether/templates/constraints.template.json +9 -0
  138. package/.aether/templates/crowned-anthill.template.md +36 -0
  139. package/.aether/templates/handoff-build-error.template.md +30 -0
  140. package/.aether/templates/handoff-build-success.template.md +39 -0
  141. package/.aether/templates/handoff.template.md +40 -0
  142. package/.aether/templates/learning-observations.template.json +6 -0
  143. package/.aether/templates/midden.template.json +13 -0
  144. package/.aether/templates/pheromones.template.json +6 -0
  145. package/.aether/templates/session.template.json +9 -0
  146. package/{runtime → .aether}/utils/atomic-write.sh +68 -22
  147. package/{runtime → .aether}/utils/chamber-compare.sh +23 -10
  148. package/.aether/utils/chamber-utils.sh +440 -0
  149. package/.aether/utils/emoji-audit.sh +166 -0
  150. package/{runtime → .aether}/utils/error-handler.sh +34 -8
  151. package/.aether/utils/file-lock.sh +313 -0
  152. package/.aether/utils/flag.sh +267 -0
  153. package/.aether/utils/hive.sh +572 -0
  154. package/.aether/utils/learning.sh +1928 -0
  155. package/.aether/utils/midden.sh +342 -0
  156. package/.aether/utils/oracle/oracle.md +168 -0
  157. package/.aether/utils/oracle/oracle.sh +1023 -0
  158. package/.aether/utils/pheromone.sh +2029 -0
  159. package/.aether/utils/queen.sh +1698 -0
  160. package/.aether/utils/scan.sh +860 -0
  161. package/.aether/utils/semantic-cli.sh +415 -0
  162. package/.aether/utils/session.sh +552 -0
  163. package/.aether/utils/skills.sh +509 -0
  164. package/.aether/utils/spawn-tree.sh +260 -0
  165. package/.aether/utils/spawn.sh +260 -0
  166. package/.aether/utils/state-api.sh +199 -0
  167. package/{runtime → .aether}/utils/state-loader.sh +8 -6
  168. package/.aether/utils/suggest.sh +611 -0
  169. package/{runtime → .aether}/utils/swarm-display.sh +10 -1
  170. package/.aether/utils/swarm.sh +1004 -0
  171. package/{runtime → .aether}/utils/watch-spawn-tree.sh +11 -2
  172. package/{runtime → .aether}/utils/xml-compose.sh +9 -3
  173. package/.aether/utils/xml-convert.sh +277 -0
  174. package/{runtime → .aether}/utils/xml-core.sh +5 -9
  175. package/.aether/utils/xml-query.sh +201 -0
  176. package/.aether/utils/xml-utils.sh +110 -0
  177. package/{runtime → .aether}/workers.md +97 -81
  178. package/.claude/agents/ant/aether-ambassador.md +265 -0
  179. package/.claude/agents/ant/aether-archaeologist.md +327 -0
  180. package/.claude/agents/ant/aether-architect.md +236 -0
  181. package/.claude/agents/ant/aether-auditor.md +271 -0
  182. package/.claude/agents/ant/aether-builder.md +224 -0
  183. package/.claude/agents/ant/aether-chaos.md +269 -0
  184. package/.claude/agents/ant/aether-chronicler.md +305 -0
  185. package/.claude/agents/ant/aether-gatekeeper.md +330 -0
  186. package/.claude/agents/ant/aether-includer.md +374 -0
  187. package/.claude/agents/ant/aether-keeper.md +272 -0
  188. package/.claude/agents/ant/aether-measurer.md +322 -0
  189. package/.claude/agents/ant/aether-oracle.md +237 -0
  190. package/.claude/agents/ant/aether-probe.md +211 -0
  191. package/.claude/agents/ant/aether-queen.md +330 -0
  192. package/.claude/agents/ant/aether-route-setter.md +178 -0
  193. package/.claude/agents/ant/aether-sage.md +418 -0
  194. package/.claude/agents/ant/aether-scout.md +179 -0
  195. package/.claude/agents/ant/aether-surveyor-disciplines.md +417 -0
  196. package/.claude/agents/ant/aether-surveyor-nest.md +355 -0
  197. package/.claude/agents/ant/aether-surveyor-pathogens.md +289 -0
  198. package/.claude/agents/ant/aether-surveyor-provisions.md +360 -0
  199. package/.claude/agents/ant/aether-tracker.md +270 -0
  200. package/.claude/agents/ant/aether-watcher.md +280 -0
  201. package/.claude/agents/ant/aether-weaver.md +248 -0
  202. package/.claude/commands/ant/archaeology.md +16 -14
  203. package/.claude/commands/ant/build.md +43 -1028
  204. package/.claude/commands/ant/chaos.md +19 -23
  205. package/.claude/commands/ant/colonize.md +52 -31
  206. package/.claude/commands/ant/continue.md +40 -1016
  207. package/.claude/commands/ant/council.md +21 -18
  208. package/.claude/commands/ant/data-clean.md +81 -0
  209. package/.claude/commands/ant/dream.md +27 -15
  210. package/.claude/commands/ant/entomb.md +317 -225
  211. package/.claude/commands/ant/export-signals.md +57 -0
  212. package/.claude/commands/ant/feedback.md +48 -26
  213. package/.claude/commands/ant/flag.md +30 -10
  214. package/.claude/commands/ant/flags.md +34 -12
  215. package/.claude/commands/ant/focus.md +45 -19
  216. package/.claude/commands/ant/help.md +50 -8
  217. package/.claude/commands/ant/history.md +13 -0
  218. package/.claude/commands/ant/import-signals.md +71 -0
  219. package/.claude/commands/ant/init.md +345 -194
  220. package/.claude/commands/ant/insert-phase.md +101 -0
  221. package/.claude/commands/ant/interpret.md +26 -4
  222. package/.claude/commands/ant/lay-eggs.md +184 -127
  223. package/.claude/commands/ant/maturity.md +32 -11
  224. package/.claude/commands/ant/memory-details.md +77 -0
  225. package/.claude/commands/ant/migrate-state.md +20 -2
  226. package/.claude/commands/ant/oracle.md +337 -74
  227. package/.claude/commands/ant/organize.md +39 -25
  228. package/.claude/commands/ant/patrol.md +620 -0
  229. package/.claude/commands/ant/pause-colony.md +23 -27
  230. package/.claude/commands/ant/phase.md +40 -42
  231. package/.claude/commands/ant/pheromones.md +156 -0
  232. package/.claude/commands/ant/plan.md +185 -51
  233. package/.claude/commands/ant/preferences.md +65 -0
  234. package/.claude/commands/ant/redirect.md +45 -30
  235. package/.claude/commands/ant/resume-colony.md +51 -27
  236. package/.claude/commands/ant/resume.md +314 -94
  237. package/.claude/commands/ant/run.md +195 -0
  238. package/.claude/commands/ant/seal.md +650 -221
  239. package/.claude/commands/ant/skill-create.md +286 -0
  240. package/.claude/commands/ant/status.md +196 -31
  241. package/.claude/commands/ant/swarm.md +16 -46
  242. package/.claude/commands/ant/tunnels.md +280 -105
  243. package/.claude/commands/ant/update.md +73 -89
  244. package/.claude/commands/ant/verify-castes.md +100 -42
  245. package/.claude/commands/ant/watch.md +14 -12
  246. package/.opencode/agents/aether-ambassador.md +63 -20
  247. package/.opencode/agents/aether-archaeologist.md +29 -12
  248. package/.opencode/agents/aether-architect.md +103 -36
  249. package/.opencode/agents/aether-auditor.md +51 -18
  250. package/.opencode/agents/aether-builder.md +70 -20
  251. package/.opencode/agents/aether-chaos.md +29 -12
  252. package/.opencode/agents/aether-chronicler.md +60 -18
  253. package/.opencode/agents/aether-gatekeeper.md +27 -18
  254. package/.opencode/agents/aether-includer.md +27 -18
  255. package/.opencode/agents/aether-keeper.md +89 -18
  256. package/.opencode/agents/aether-measurer.md +27 -18
  257. package/.opencode/agents/aether-oracle.md +137 -0
  258. package/.opencode/agents/aether-probe.md +60 -18
  259. package/.opencode/agents/aether-queen.md +172 -24
  260. package/.opencode/agents/aether-route-setter.md +57 -12
  261. package/.opencode/agents/aether-sage.md +26 -18
  262. package/.opencode/agents/aether-scout.md +28 -20
  263. package/.opencode/agents/aether-surveyor-disciplines.md +59 -2
  264. package/.opencode/agents/aether-surveyor-nest.md +59 -2
  265. package/.opencode/agents/aether-surveyor-pathogens.md +57 -2
  266. package/.opencode/agents/aether-surveyor-provisions.md +59 -2
  267. package/.opencode/agents/aether-tracker.md +64 -18
  268. package/.opencode/agents/aether-watcher.md +66 -19
  269. package/.opencode/agents/aether-weaver.md +61 -18
  270. package/.opencode/commands/ant/archaeology.md +7 -14
  271. package/.opencode/commands/ant/build.md +437 -257
  272. package/.opencode/commands/ant/chaos.md +7 -24
  273. package/.opencode/commands/ant/colonize.md +8 -17
  274. package/.opencode/commands/ant/continue.md +661 -142
  275. package/.opencode/commands/ant/council.md +11 -22
  276. package/.opencode/commands/ant/data-clean.md +77 -0
  277. package/.opencode/commands/ant/dream.md +15 -17
  278. package/.opencode/commands/ant/entomb.md +133 -62
  279. package/.opencode/commands/ant/export-signals.md +54 -0
  280. package/.opencode/commands/ant/feedback.md +24 -5
  281. package/.opencode/commands/ant/flag.md +16 -4
  282. package/.opencode/commands/ant/flags.md +24 -10
  283. package/.opencode/commands/ant/focus.md +22 -5
  284. package/.opencode/commands/ant/help.md +41 -8
  285. package/.opencode/commands/ant/history.md +9 -0
  286. package/.opencode/commands/ant/import-signals.md +68 -0
  287. package/.opencode/commands/ant/init.md +374 -167
  288. package/.opencode/commands/ant/insert-phase.md +107 -0
  289. package/.opencode/commands/ant/interpret.md +16 -0
  290. package/.opencode/commands/ant/lay-eggs.md +184 -112
  291. package/.opencode/commands/ant/maturity.md +18 -2
  292. package/.opencode/commands/ant/memory-details.md +83 -0
  293. package/.opencode/commands/ant/migrate-state.md +12 -0
  294. package/.opencode/commands/ant/oracle.md +322 -67
  295. package/.opencode/commands/ant/organize.md +18 -16
  296. package/.opencode/commands/ant/patrol.md +626 -0
  297. package/.opencode/commands/ant/pause-colony.md +12 -29
  298. package/.opencode/commands/ant/phase.md +30 -40
  299. package/.opencode/commands/ant/pheromones.md +162 -0
  300. package/.opencode/commands/ant/plan.md +184 -56
  301. package/.opencode/commands/ant/preferences.md +71 -0
  302. package/.opencode/commands/ant/redirect.md +22 -5
  303. package/.opencode/commands/ant/resume-colony.md +38 -27
  304. package/.opencode/commands/ant/resume.md +385 -0
  305. package/.opencode/commands/ant/run.md +201 -0
  306. package/.opencode/commands/ant/seal.md +259 -45
  307. package/.opencode/commands/ant/skill-create.md +63 -0
  308. package/.opencode/commands/ant/status.md +135 -31
  309. package/.opencode/commands/ant/swarm.md +3 -345
  310. package/.opencode/commands/ant/tunnels.md +152 -9
  311. package/.opencode/commands/ant/update.md +70 -91
  312. package/.opencode/commands/ant/verify-castes.md +96 -42
  313. package/.opencode/commands/ant/watch.md +7 -0
  314. package/CHANGELOG.md +356 -0
  315. package/README.md +203 -573
  316. package/bin/cli.js +455 -527
  317. package/bin/generate-commands.js +186 -0
  318. package/bin/generate-commands.sh +127 -88
  319. package/bin/lib/init.js +13 -3
  320. package/bin/lib/spawn-logger.js +0 -15
  321. package/bin/lib/update-transaction.js +392 -140
  322. package/bin/npx-install.js +178 -0
  323. package/bin/sync-to-runtime.sh +5 -137
  324. package/bin/validate-package.sh +166 -0
  325. package/package.json +14 -7
  326. package/.opencode/agents/aether-guardian.md +0 -107
  327. package/.opencode/agents/workers.md +0 -1034
  328. package/bin/lib/model-profiles.js +0 -445
  329. package/bin/lib/model-verify.js +0 -288
  330. package/bin/lib/proxy-health.js +0 -253
  331. package/bin/lib/telemetry.js +0 -441
  332. package/runtime/CONTEXT.md +0 -160
  333. package/runtime/QUEEN_ANT_ARCHITECTURE.md +0 -402
  334. package/runtime/aether-utils.sh +0 -3879
  335. package/runtime/data/signatures.json +0 -41
  336. package/runtime/docs/AETHER-2.0-IMPLEMENTATION-PLAN.md +0 -1343
  337. package/runtime/docs/AETHER-PHEROMONE-SYSTEM-MASTER-SPEC.md +0 -2642
  338. package/runtime/docs/PHEROMONE-INJECTION.md +0 -240
  339. package/runtime/docs/PHEROMONE-INTEGRATION.md +0 -192
  340. package/runtime/docs/PHEROMONE-SYSTEM-DESIGN.md +0 -426
  341. package/runtime/docs/README.md +0 -94
  342. package/runtime/docs/VISUAL-OUTPUT-SPEC.md +0 -219
  343. package/runtime/docs/biological-reference.md +0 -272
  344. package/runtime/docs/codebase-review.md +0 -399
  345. package/runtime/docs/command-sync.md +0 -164
  346. package/runtime/docs/constraints.md +0 -116
  347. package/runtime/docs/implementation-learnings.md +0 -89
  348. package/runtime/docs/known-issues.md +0 -217
  349. package/runtime/docs/namespace.md +0 -148
  350. package/runtime/docs/pathogen-schema-example.json +0 -36
  351. package/runtime/docs/pathogen-schema.md +0 -111
  352. package/runtime/docs/planning-discipline.md +0 -159
  353. package/runtime/docs/progressive-disclosure.md +0 -184
  354. package/runtime/lib/queen-utils.sh +0 -729
  355. package/runtime/model-profiles.yaml +0 -100
  356. package/runtime/planning.md +0 -159
  357. package/runtime/recover.sh +0 -136
  358. package/runtime/templates/QUEEN.md.template +0 -79
  359. package/runtime/utils/chamber-utils.sh +0 -285
  360. package/runtime/utils/file-lock.sh +0 -122
  361. package/runtime/utils/spawn-tree.sh +0 -428
  362. package/runtime/utils/spawn-with-model.sh +0 -56
  363. package/runtime/utils/xml-utils.sh +0 -2196
  364. package/runtime/workers-new-castes.md +0 -516
  365. /package/{runtime → .aether/docs/disciplines}/coding-standards.md +0 -0
  366. /package/{runtime → .aether/docs/disciplines}/debugging.md +0 -0
  367. /package/{runtime → .aether/docs/disciplines}/learning.md +0 -0
  368. /package/{runtime → .aether/docs/disciplines}/tdd.md +0 -0
  369. /package/{runtime → .aether/docs/disciplines}/verification-loop.md +0 -0
  370. /package/{runtime → .aether/docs/disciplines}/verification.md +0 -0
  371. /package/{runtime → .aether}/schemas/aether-types.xsd +0 -0
  372. /package/{runtime → .aether}/schemas/colony-registry.xsd +0 -0
  373. /package/{runtime → .aether}/schemas/pheromone.xsd +0 -0
  374. /package/{runtime → .aether}/schemas/prompt.xsd +0 -0
  375. /package/{runtime → .aether}/schemas/queen-wisdom.xsd +0 -0
  376. /package/{runtime → .aether}/schemas/worker-priming.xsd +0 -0
  377. /package/{runtime → .aether}/utils/colorize-log.sh +0 -0
  378. /package/{runtime → .aether}/utils/queen-to-md.xsl +0 -0
@@ -161,61 +161,45 @@ class UpdateTransaction {
161
161
  // Hub paths (from cli.js)
162
162
  this.HOME = process.env.HOME || process.env.USERPROFILE;
163
163
  this.HUB_DIR = path.join(this.HOME, '.aether');
164
- this.HUB_COMMANDS_CLAUDE = path.join(this.HUB_DIR, 'commands', 'claude');
165
- this.HUB_COMMANDS_OPENCODE = path.join(this.HUB_DIR, 'commands', 'opencode');
166
- this.HUB_AGENTS = path.join(this.HUB_DIR, 'agents');
164
+ this.HUB_SYSTEM_DIR = path.join(this.HUB_DIR, 'system');
165
+ this.HUB_COMMANDS_CLAUDE = path.join(this.HUB_SYSTEM_DIR, 'commands', 'claude');
166
+ this.HUB_COMMANDS_OPENCODE = path.join(this.HUB_SYSTEM_DIR, 'commands', 'opencode');
167
+ this.HUB_AGENTS = path.join(this.HUB_SYSTEM_DIR, 'agents');
168
+ this.HUB_AGENTS_CLAUDE = path.join(this.HUB_SYSTEM_DIR, 'agents-claude');
169
+ this.HUB_RULES = path.join(this.HUB_SYSTEM_DIR, 'rules');
167
170
  this.HUB_VERSION = path.join(this.HUB_DIR, 'version.json');
168
171
  this.HUB_REGISTRY = path.join(this.HUB_DIR, 'registry.json');
169
172
 
170
- // Directories to exclude from sync (user data, local state)
171
- this.EXCLUDE_DIRS = ['data', 'dreams', 'checkpoints', 'locks', 'temp'];
173
+ // Directories to exclude from sync (user data, local state, and separately-synced dirs)
174
+ // v4.0: archive and chambers added these are private and must not sync to target repos
175
+ // v6.0: oracle, midden, exchange added for complete user data protection
176
+ this.EXCLUDE_DIRS = ['data', 'dreams', 'oracle', 'midden', 'checkpoints', 'locks', 'temp', 'agents', 'commands', 'rules', 'archive', 'chambers', 'exchange'];
177
+
178
+ // Files to exclude from sync (user wisdom, protected files)
179
+ this.EXCLUDE_FILES = ['QUEEN.md'];
172
180
 
173
181
  // Target directories for git safety checks
174
- this.targetDirs = ['.aether', '.claude/commands/ant', '.opencode/commands/ant', '.opencode/agents'];
175
-
176
- // System files allowlist (from cli.js)
177
- this.SYSTEM_FILES = [
178
- 'aether-utils.sh',
179
- 'coding-standards.md',
180
- 'debugging.md',
181
- 'DISCIPLINES.md',
182
- 'learning.md',
183
- 'planning.md',
184
- 'QUEEN_ANT_ARCHITECTURE.md',
185
- 'tdd.md',
186
- 'verification-loop.md',
187
- 'verification.md',
188
- 'workers.md',
189
- 'workers-new-castes.md',
190
- 'docs/biological-reference.md',
191
- 'docs/command-sync.md',
192
- 'docs/constraints.md',
193
- 'docs/namespace.md',
194
- 'docs/pathogen-schema-example.json',
195
- 'docs/pathogen-schema.md',
196
- 'docs/PHEROMONE-INJECTION.md',
197
- 'docs/PHEROMONE-INTEGRATION.md',
198
- 'docs/PHEROMONE-SYSTEM-DESIGN.md',
199
- 'docs/pheromones.md',
200
- 'docs/progressive-disclosure.md',
201
- 'docs/README.md',
202
- 'docs/VISUAL-OUTPUT-SPEC.md',
203
- 'docs/known-issues.md',
204
- 'docs/implementation-learnings.md',
205
- 'docs/codebase-review.md',
206
- 'docs/planning-discipline.md',
207
- 'utils/atomic-write.sh',
208
- 'utils/chamber-compare.sh',
209
- 'utils/chamber-utils.sh',
210
- 'utils/colorize-log.sh',
211
- 'utils/error-handler.sh',
212
- 'utils/file-lock.sh',
213
- 'utils/spawn-tree.sh',
214
- 'utils/spawn-with-model.sh',
215
- 'utils/state-loader.sh',
216
- 'utils/swarm-display.sh',
217
- 'utils/watch-spawn-tree.sh',
218
- 'templates/QUEEN.md.template',
182
+ this.targetDirs = ['.aether', '.claude/commands/ant', '.claude/agents/ant', '.claude/rules', '.opencode/commands/ant', '.opencode/agents'];
183
+
184
+ // Managed paths for update safety checks (must align with files update can actually modify)
185
+ this.protectedAetherDirs = new Set([
186
+ 'data',
187
+ 'dreams',
188
+ 'oracle',
189
+ 'midden',
190
+ 'checkpoints',
191
+ 'locks',
192
+ 'temp',
193
+ 'archive',
194
+ 'chambers',
195
+ 'exchange',
196
+ ]);
197
+ this.managedPrefixes = [
198
+ '.claude/commands/ant',
199
+ '.claude/agents/ant',
200
+ '.claude/rules',
201
+ '.opencode/commands/ant',
202
+ '.opencode/agents',
219
203
  ];
220
204
  }
221
205
 
@@ -251,7 +235,22 @@ class UpdateTransaction {
251
235
  */
252
236
  writeJsonSync(filePath, data) {
253
237
  fs.mkdirSync(path.dirname(filePath), { recursive: true });
254
- fs.writeFileSync(filePath, JSON.stringify(data, null, 2) + '\n');
238
+ const content = JSON.stringify(data, null, 2) + '\n';
239
+ const tmpPath = filePath + '.tmp';
240
+ try {
241
+ fs.writeFileSync(tmpPath, content);
242
+ fs.renameSync(tmpPath, filePath);
243
+ } catch (err) {
244
+ // Clean up temp file on failure
245
+ try {
246
+ if (fs.existsSync(tmpPath)) {
247
+ fs.unlinkSync(tmpPath);
248
+ }
249
+ } catch {
250
+ // Ignore cleanup errors
251
+ }
252
+ throw err;
253
+ }
255
254
  }
256
255
 
257
256
  /**
@@ -269,6 +268,40 @@ class UpdateTransaction {
269
268
  }
270
269
  }
271
270
 
271
+ /**
272
+ * Copy file atomically using temp file + rename pattern
273
+ * Prevents partial file corruption on process interruption
274
+ * @param {string} srcPath - Source file path
275
+ * @param {string} destPath - Destination file path
276
+ * @private
277
+ */
278
+ copyFileAtomic(srcPath, destPath) {
279
+ const tempPath = `${destPath}.tmp.${process.pid}.${Date.now()}`;
280
+
281
+ try {
282
+ // Copy to temp file first
283
+ fs.copyFileSync(srcPath, tempPath);
284
+
285
+ // Atomic rename (POSIX guarantees atomicity)
286
+ fs.renameSync(tempPath, destPath);
287
+
288
+ // Set executable permission for shell scripts
289
+ if (destPath.endsWith('.sh')) {
290
+ fs.chmodSync(destPath, 0o755);
291
+ }
292
+ } catch (err) {
293
+ // Clean up temp file on failure
294
+ try {
295
+ if (fs.existsSync(tempPath)) {
296
+ fs.unlinkSync(tempPath);
297
+ }
298
+ } catch {
299
+ // Ignore cleanup errors
300
+ }
301
+ throw err;
302
+ }
303
+ }
304
+
272
305
  /**
273
306
  * Check if path is a git repository
274
307
  * @returns {boolean} True if git repo
@@ -283,6 +316,54 @@ class UpdateTransaction {
283
316
  }
284
317
  }
285
318
 
319
+ /**
320
+ * Normalize git porcelain path output.
321
+ * Handles rename syntax and quoted/escaped paths.
322
+ * @param {string} filePath - Raw path fragment from git porcelain
323
+ * @returns {string} Normalized path
324
+ * @private
325
+ */
326
+ normalizePorcelainPath(filePath) {
327
+ let normalized = filePath;
328
+
329
+ if (normalized.includes(' -> ')) {
330
+ normalized = normalized.split(' -> ').pop();
331
+ }
332
+
333
+ if (normalized.startsWith('"') && normalized.endsWith('"')) {
334
+ normalized = normalized
335
+ .slice(1, -1)
336
+ .replace(/\\"/g, '"')
337
+ .replace(/\\\\/g, '\\');
338
+ }
339
+
340
+ return normalized;
341
+ }
342
+
343
+ /**
344
+ * True when a path is managed by update and may be overwritten by sync.
345
+ * Paths under .aether/data and other protected runtime dirs are intentionally excluded.
346
+ * @param {string} filePath - Normalized or raw path
347
+ * @returns {boolean} Whether update should treat this path as managed
348
+ * @private
349
+ */
350
+ isManagedUpdatePath(filePath) {
351
+ const p = this.normalizePorcelainPath(filePath);
352
+
353
+ if (p === '.aether' || p.startsWith('.aether/')) {
354
+ const rel = p === '.aether' ? '' : p.slice('.aether/'.length);
355
+ if (!rel) return true;
356
+
357
+ const first = rel.split('/')[0];
358
+ if (!first || first.startsWith('.')) return false;
359
+ if (this.protectedAetherDirs.has(first)) return false;
360
+ if (rel === 'QUEEN.md') return false;
361
+ return true;
362
+ }
363
+
364
+ return this.managedPrefixes.some(prefix => p === prefix || p.startsWith(`${prefix}/`));
365
+ }
366
+
286
367
  /**
287
368
  * Detect dirty repository state with detailed categorization
288
369
  * @returns {object} Dirty state info: { isDirty, tracked, untracked, staged }
@@ -298,14 +379,25 @@ class UpdateTransaction {
298
379
  encoding: 'utf8',
299
380
  });
300
381
 
301
- const lines = result.trim().split('\n').filter(Boolean);
382
+ // Preserve the two-column porcelain status prefix on each line.
383
+ // Using `trim()` on the whole output would strip leading spaces from
384
+ // the first line and can misclassify unstaged vs staged changes.
385
+ const lines = result.split('\n').filter(line => line.trim().length > 0);
302
386
  const tracked = [];
303
387
  const untracked = [];
304
388
  const staged = [];
389
+ let managedCount = 0;
305
390
 
306
391
  for (const line of lines) {
307
392
  const status = line.slice(0, 2);
308
- const filePath = line.slice(3);
393
+ const rawPath = line.slice(3);
394
+ const filePath = this.normalizePorcelainPath(rawPath);
395
+
396
+ if (!this.isManagedUpdatePath(filePath)) {
397
+ continue;
398
+ }
399
+
400
+ managedCount++;
309
401
 
310
402
  // Staged changes (in index)
311
403
  if (status[0] !== ' ' && status[0] !== '?') {
@@ -322,7 +414,7 @@ class UpdateTransaction {
322
414
  }
323
415
 
324
416
  return {
325
- isDirty: lines.length > 0,
417
+ isDirty: managedCount > 0,
326
418
  tracked,
327
419
  untracked,
328
420
  staged,
@@ -621,10 +713,7 @@ class UpdateTransaction {
621
713
  }
622
714
 
623
715
  if (shouldCopy) {
624
- fs.copyFileSync(srcPath, destPath);
625
- if (relPath.endsWith('.sh')) {
626
- fs.chmodSync(destPath, 0o755);
627
- }
716
+ this.copyFileAtomic(srcPath, destPath);
628
717
  copied++;
629
718
  }
630
719
  } catch (err) {
@@ -687,74 +776,59 @@ class UpdateTransaction {
687
776
  }
688
777
 
689
778
  /**
690
- * Sync system files from hub
691
- * @param {string} srcDir - Source directory
692
- * @param {string} destDir - Destination directory
693
- * @param {object} opts - Options
694
- * @returns {object} Sync result: { copied, removed, skipped }
779
+ * Check if a path should be excluded from sync
780
+ * @param {string} relPath - Relative path
781
+ * @returns {boolean} True if should be excluded
695
782
  * @private
696
783
  */
697
- syncSystemFilesWithCleanup(srcDir, destDir, opts) {
698
- opts = opts || {};
699
- const dryRun = opts.dryRun || false;
700
-
701
- let copied = 0;
702
- let skipped = 0;
703
-
704
- for (const file of this.SYSTEM_FILES) {
705
- const srcPath = path.join(srcDir, file);
706
- const destPath = path.join(destDir, file);
707
- if (fs.existsSync(srcPath)) {
708
- if (!dryRun) {
709
- // Compute hashes to determine if copy is needed
710
- const srcHash = this.hashFileSync(srcPath);
711
- const destHash = fs.existsSync(destPath) ? this.hashFileSync(destPath) : null;
712
-
713
- if (srcHash === destHash) {
714
- // Files are identical, skip copying
715
- skipped++;
716
- continue;
717
- }
718
-
719
- fs.mkdirSync(path.dirname(destPath), { recursive: true });
720
- fs.copyFileSync(srcPath, destPath);
721
- if (file.endsWith('.sh')) {
722
- fs.chmodSync(destPath, 0o755);
723
- }
724
- }
725
- copied++;
726
- }
727
- }
728
-
729
- // Remove allowlisted files that no longer exist in src
730
- const removed = [];
731
- for (const file of this.SYSTEM_FILES) {
732
- const srcPath = path.join(srcDir, file);
733
- const destPath = path.join(destDir, file);
734
- if (!fs.existsSync(srcPath) && fs.existsSync(destPath)) {
735
- removed.push(file);
736
- if (!dryRun) {
737
- fs.unlinkSync(destPath);
738
- }
739
- }
784
+ shouldExclude(relPath) {
785
+ const parts = relPath.split(path.sep);
786
+ // Check for excluded directories
787
+ if (parts.some(part => this.EXCLUDE_DIRS.includes(part))) {
788
+ return true;
740
789
  }
741
-
742
- if (!dryRun && removed.length > 0) {
743
- this.cleanEmptyDirs(destDir);
790
+ // Check for excluded files (QUEEN.md protection)
791
+ const basename = path.basename(relPath);
792
+ if (this.EXCLUDE_FILES.includes(basename)) {
793
+ return true;
744
794
  }
745
-
746
- return { copied, removed, skipped };
795
+ return false;
747
796
  }
748
797
 
749
798
  /**
750
- * Check if a path should be excluded from sync
751
- * @param {string} relPath - Relative path
752
- * @returns {boolean} True if should be excluded
753
- * @private
799
+ * Get files that the update would actually overwrite (hub version differs from repo version).
800
+ * Used by the dirty-file check to only warn about files that matter.
801
+ * @returns {string[]} Repo-relative paths of files that would be overwritten
754
802
  */
755
- shouldExclude(relPath) {
756
- const parts = relPath.split(path.sep);
757
- return parts.some(part => this.EXCLUDE_DIRS.includes(part));
803
+ getConflictingFiles() {
804
+ const conflicts = [];
805
+
806
+ // Helper: check a hub->repo dir pair for differing files
807
+ const checkDir = (hubDir, repoDir, prefix) => {
808
+ if (!fs.existsSync(hubDir)) return;
809
+ const srcFiles = this.listFilesRecursive(hubDir);
810
+ for (const relPath of srcFiles) {
811
+ if (this.shouldExclude(relPath)) continue;
812
+ const destPath = path.join(repoDir, relPath);
813
+ if (fs.existsSync(destPath)) {
814
+ const srcHash = this.hashFileSync(path.join(hubDir, relPath));
815
+ const destHash = this.hashFileSync(destPath);
816
+ if (srcHash !== destHash) {
817
+ conflicts.push(`${prefix}${relPath}`);
818
+ }
819
+ }
820
+ }
821
+ };
822
+
823
+ const repoAether = path.join(this.repoPath, '.aether');
824
+ checkDir(this.HUB_SYSTEM_DIR, repoAether, '.aether/');
825
+ checkDir(this.HUB_COMMANDS_CLAUDE, path.join(this.repoPath, '.claude', 'commands', 'ant'), '.claude/commands/ant/');
826
+ checkDir(this.HUB_COMMANDS_OPENCODE, path.join(this.repoPath, '.opencode', 'commands', 'ant'), '.opencode/commands/ant/');
827
+ checkDir(this.HUB_AGENTS, path.join(this.repoPath, '.opencode', 'agents'), '.opencode/agents/');
828
+ checkDir(this.HUB_AGENTS_CLAUDE, path.join(this.repoPath, '.claude', 'agents', 'ant'), '.claude/agents/ant/');
829
+ checkDir(this.HUB_RULES, path.join(this.repoPath, '.claude', 'rules'), '.claude/rules/');
830
+
831
+ return conflicts;
758
832
  }
759
833
 
760
834
  /**
@@ -800,28 +874,30 @@ class UpdateTransaction {
800
874
  const srcPath = path.join(srcDir, relPath);
801
875
  const destPath = path.join(destDir, relPath);
802
876
 
877
+ // Hash comparison: determine if copy is needed (runs for both dry-run and actual)
878
+ let shouldCopy = true;
879
+ if (fs.existsSync(destPath)) {
880
+ const srcHash = this.hashFileSync(srcPath);
881
+ const destHash = this.hashFileSync(destPath);
882
+ if (srcHash === destHash) {
883
+ shouldCopy = false;
884
+ skipped++;
885
+ }
886
+ }
887
+
803
888
  if (!dryRun) {
804
889
  fs.mkdirSync(path.dirname(destPath), { recursive: true });
805
890
 
806
- // Hash comparison
807
- let shouldCopy = true;
808
- if (fs.existsSync(destPath)) {
809
- const srcHash = this.hashFileSync(srcPath);
810
- const destHash = this.hashFileSync(destPath);
811
- if (srcHash === destHash) {
812
- shouldCopy = false;
813
- skipped++;
814
- }
891
+ if (shouldCopy) {
892
+ this.copyFileAtomic(srcPath, destPath);
893
+ copied++; // FIX: Only increment when actually copied
815
894
  }
816
-
895
+ } else {
896
+ // dry-run: count files that WOULD be copied
817
897
  if (shouldCopy) {
818
- fs.copyFileSync(srcPath, destPath);
819
- if (relPath.endsWith('.sh')) {
820
- fs.chmodSync(destPath, 0o755);
821
- }
898
+ copied++; // Count only files that would actually be copied
822
899
  }
823
900
  }
824
- copied++;
825
901
  }
826
902
 
827
903
  // Cleanup: remove files in dest that aren't in source
@@ -867,6 +943,116 @@ class UpdateTransaction {
867
943
  return { copied, removed, skipped };
868
944
  }
869
945
 
946
+ /**
947
+ * Move a file or directory to trash instead of deleting
948
+ * @param {string} itemPath - Path to file or directory
949
+ * @param {string} repoPath - Repository root for trash location
950
+ * @returns {boolean} True if moved to trash successfully
951
+ * @private
952
+ */
953
+ moveToTrash(itemPath, repoPath) {
954
+ const timestamp = new Date().toISOString().replace(/[:.]/g, '-').slice(0, 19);
955
+ const trashDir = path.join(repoPath, '.aether', '.trash', timestamp);
956
+ const basename = path.basename(itemPath);
957
+ const trashPath = path.join(trashDir, basename);
958
+
959
+ try {
960
+ fs.mkdirSync(trashDir, { recursive: true });
961
+ fs.renameSync(itemPath, trashPath);
962
+ return true;
963
+ } catch (err) {
964
+ // If rename fails (cross-device), fall back to copy + delete
965
+ try {
966
+ fs.mkdirSync(trashDir, { recursive: true });
967
+ if (fs.statSync(itemPath).isDirectory()) {
968
+ fs.cpSync(itemPath, path.join(trashDir, basename), { recursive: true });
969
+ fs.rmSync(itemPath, { recursive: true, force: true });
970
+ } else {
971
+ fs.copyFileSync(itemPath, path.join(trashDir, basename));
972
+ fs.unlinkSync(itemPath);
973
+ }
974
+ return true;
975
+ } catch (fallbackErr) {
976
+ return false;
977
+ }
978
+ }
979
+ }
980
+
981
+ /**
982
+ * Remove known stale directories and files left behind by pre-3.0.0 versions.
983
+ *
984
+ * IMPORTANT: Removed items are moved to .aether/.trash/ NOT deleted.
985
+ * Users can inspect and manually clean trash when ready.
986
+ * Trash folders are timestamped for easy identification.
987
+ *
988
+ * Protected paths (never cleaned):
989
+ * - .aether/data/ - Colony state
990
+ * - .aether/dreams/ - Session notes
991
+ * - .aether/oracle/ - Research progress
992
+ * - .aether/midden/ - Failure tracking
993
+ * - .aether/QUEEN.md - User's wisdom file
994
+ *
995
+ * Idempotent: safe to call when items do not exist.
996
+ *
997
+ * @param {string} repoPath - Absolute path to the target repository root
998
+ * @returns {{ cleaned: string[], failed: Array<{label: string, error: string}>, trashDir: string }}
999
+ */
1000
+ cleanupStaleAetherDirs(repoPath) {
1001
+ // Safety check: never clean protected directories
1002
+ const protectedDirs = ['data', 'dreams', 'oracle', 'midden'];
1003
+ const protectedFiles = ['QUEEN.md'];
1004
+
1005
+ // Verify none of our stale items are in protected paths
1006
+ const aetherDir = path.join(repoPath, '.aether');
1007
+ for (const dir of protectedDirs) {
1008
+ const protectedPath = path.join(aetherDir, dir);
1009
+ if (fs.existsSync(protectedPath)) {
1010
+ // Log that protected dir exists and will be preserved
1011
+ this.log?.(` Preserving protected directory: .aether/${dir}/`);
1012
+ }
1013
+ }
1014
+
1015
+ const staleItems = [
1016
+ {
1017
+ path: path.join(repoPath, '.aether', 'agents'),
1018
+ label: '.aether/agents/ (stale duplicate)',
1019
+ type: 'dir',
1020
+ },
1021
+ {
1022
+ path: path.join(repoPath, '.aether', 'commands'),
1023
+ label: '.aether/commands/ (stale duplicate)',
1024
+ type: 'dir',
1025
+ },
1026
+ {
1027
+ path: path.join(repoPath, '.aether', 'planning.md'),
1028
+ label: '.aether/planning.md (phantom file)',
1029
+ type: 'file',
1030
+ },
1031
+ ];
1032
+
1033
+ const cleaned = [];
1034
+ const failed = [];
1035
+
1036
+ for (const item of staleItems) {
1037
+ if (!fs.existsSync(item.path)) {
1038
+ // Already clean — idempotent skip
1039
+ continue;
1040
+ }
1041
+
1042
+ try {
1043
+ if (this.moveToTrash(item.path, repoPath)) {
1044
+ cleaned.push(item.label);
1045
+ } else {
1046
+ failed.push({ label: item.label, error: 'Failed to move to trash' });
1047
+ }
1048
+ } catch (err) {
1049
+ failed.push({ label: item.label, error: err.message });
1050
+ }
1051
+ }
1052
+
1053
+ return { cleaned, failed, trashDir: path.join(repoPath, '.aether', '.trash') };
1054
+ }
1055
+
870
1056
  /**
871
1057
  * Sync files from hub to repo
872
1058
  * @param {string} sourceVersion - Version to sync from
@@ -880,14 +1066,16 @@ class UpdateTransaction {
880
1066
  system: { copied: 0, removed: 0, skipped: 0 },
881
1067
  commands: { copied: 0, removed: 0, skipped: 0 },
882
1068
  agents: { copied: 0, removed: 0, skipped: 0 },
1069
+ agents_claude: { copied: 0, removed: [], skipped: 0 },
1070
+ rules: { copied: 0, removed: 0, skipped: 0 },
883
1071
  errors: [],
884
1072
  };
885
1073
 
886
1074
  const repoAether = path.join(this.repoPath, '.aether');
887
1075
 
888
1076
  // Sync .aether/ from hub to repo (excluding user data directories)
889
- if (fs.existsSync(this.HUB_DIR)) {
890
- results.system = this.syncAetherToRepo(this.HUB_DIR, repoAether, { dryRun });
1077
+ if (fs.existsSync(this.HUB_SYSTEM_DIR)) {
1078
+ results.system = this.syncAetherToRepo(this.HUB_SYSTEM_DIR, repoAether, { dryRun });
891
1079
  }
892
1080
 
893
1081
  // Sync commands from hub
@@ -911,6 +1099,18 @@ class UpdateTransaction {
911
1099
  results.agents = this.syncDirWithCleanup(this.HUB_AGENTS, repoAgents, { dryRun });
912
1100
  }
913
1101
 
1102
+ // Sync claude agents from hub to .claude/agents/ant/
1103
+ const repoClaudeAgents = path.join(this.repoPath, '.claude', 'agents', 'ant');
1104
+ if (fs.existsSync(this.HUB_AGENTS_CLAUDE)) {
1105
+ results.agents_claude = this.syncDirWithCleanup(this.HUB_AGENTS_CLAUDE, repoClaudeAgents, { dryRun });
1106
+ }
1107
+
1108
+ // Sync rules from hub to .claude/rules/
1109
+ const repoRules = path.join(this.repoPath, '.claude', 'rules');
1110
+ if (fs.existsSync(this.HUB_RULES)) {
1111
+ results.rules = this.syncDirWithCleanup(this.HUB_RULES, repoRules, { dryRun });
1112
+ }
1113
+
914
1114
  this.syncResult = results;
915
1115
  return results;
916
1116
  }
@@ -953,10 +1153,12 @@ class UpdateTransaction {
953
1153
  };
954
1154
 
955
1155
  const repoAether = path.join(this.repoPath, '.aether');
956
- verifyDir(this.HUB_DIR, repoAether);
1156
+ verifyDir(this.HUB_SYSTEM_DIR, repoAether);
957
1157
  verifyDir(this.HUB_COMMANDS_CLAUDE, path.join(this.repoPath, '.claude', 'commands', 'ant'));
958
1158
  verifyDir(this.HUB_COMMANDS_OPENCODE, path.join(this.repoPath, '.opencode', 'commands', 'ant'));
959
1159
  verifyDir(this.HUB_AGENTS, path.join(this.repoPath, '.opencode', 'agents'));
1160
+ verifyDir(this.HUB_AGENTS_CLAUDE, path.join(this.repoPath, '.claude', 'agents', 'ant'));
1161
+ verifyDir(this.HUB_RULES, path.join(this.repoPath, '.claude', 'rules'));
960
1162
 
961
1163
  return {
962
1164
  valid: errors.length === 0,
@@ -1002,6 +1204,8 @@ class UpdateTransaction {
1002
1204
  checkDir(this.HUB_COMMANDS_CLAUDE, 'commands/claude');
1003
1205
  checkDir(this.HUB_COMMANDS_OPENCODE, 'commands/opencode');
1004
1206
  checkDir(this.HUB_AGENTS, 'agents');
1207
+ checkDir(this.HUB_AGENTS_CLAUDE, 'agents-claude');
1208
+ checkDir(this.HUB_RULES, 'rules');
1005
1209
  checkDir(this.HUB_VERSION, 'version');
1006
1210
 
1007
1211
  // Check if source files exist
@@ -1098,10 +1302,11 @@ class UpdateTransaction {
1098
1302
  };
1099
1303
 
1100
1304
  const repoAether = path.join(this.repoPath, '.aether');
1101
- checkDir(this.HUB_DIR, repoAether);
1305
+ checkDir(this.HUB_SYSTEM_DIR, repoAether);
1102
1306
  checkDir(this.HUB_COMMANDS_CLAUDE, path.join(this.repoPath, '.claude', 'commands', 'ant'));
1103
1307
  checkDir(this.HUB_COMMANDS_OPENCODE, path.join(this.repoPath, '.opencode', 'commands', 'ant'));
1104
1308
  checkDir(this.HUB_AGENTS, path.join(this.repoPath, '.opencode', 'agents'));
1309
+ checkDir(this.HUB_RULES, path.join(this.repoPath, '.claude', 'rules'));
1105
1310
 
1106
1311
  return {
1107
1312
  isPartial: missing.length > 0 || corrupted.length > 0,
@@ -1260,6 +1465,14 @@ class UpdateTransaction {
1260
1465
  * @returns {Promise<boolean>} True if rollback succeeded
1261
1466
  */
1262
1467
  async rollback() {
1468
+ // Clear pending sentinel on rollback — we've cleanly returned to prior state
1469
+ const pendingPath = path.join(this.repoPath, '.aether', '.update-pending');
1470
+ try {
1471
+ if (fs.existsSync(pendingPath)) {
1472
+ fs.unlinkSync(pendingPath);
1473
+ }
1474
+ } catch { /* ignore — rollback cleanup is best-effort */ }
1475
+
1263
1476
  this.state = TransactionStates.ROLLING_BACK;
1264
1477
  this.log(' Rolling back to checkpoint...');
1265
1478
 
@@ -1270,6 +1483,23 @@ class UpdateTransaction {
1270
1483
  return false;
1271
1484
  }
1272
1485
 
1486
+ // Restore backed-up managed files before stash pop
1487
+ // Stash only contains the user's local modifications; managed files
1488
+ // overwritten by syncFiles must be restored from the checkpoint backup.
1489
+ if (this.checkpoint.backedUpFiles && this.checkpoint.backedUpFiles.length > 0) {
1490
+ for (const entry of this.checkpoint.backedUpFiles) {
1491
+ try {
1492
+ if (fs.existsSync(entry.backupPath)) {
1493
+ fs.mkdirSync(path.dirname(path.join(this.repoPath, entry.relPath)), { recursive: true });
1494
+ fs.copyFileSync(entry.backupPath, path.join(this.repoPath, entry.relPath));
1495
+ this.log(` Restored managed file: ${entry.relPath}`);
1496
+ }
1497
+ } catch (err) {
1498
+ this.log(` Warning: could not restore ${entry.relPath}: ${err.message}`);
1499
+ }
1500
+ }
1501
+ }
1502
+
1273
1503
  // Restore from stash if available
1274
1504
  if (this.checkpoint.stashRef) {
1275
1505
  try {
@@ -1342,6 +1572,13 @@ class UpdateTransaction {
1342
1572
  async execute(sourceVersion, options = {}) {
1343
1573
  const dryRun = options.dryRun || false;
1344
1574
 
1575
+ // Write pending sentinel BEFORE any work — marks update as in-flight
1576
+ const pendingPath = path.join(this.repoPath, '.aether', '.update-pending');
1577
+ this.writeJsonSync(pendingPath, {
1578
+ target_version: sourceVersion,
1579
+ started_at: new Date().toISOString(),
1580
+ });
1581
+
1345
1582
  try {
1346
1583
  // Phase 0: Validate repo state (before any modifications)
1347
1584
  // Check for dirty repo and provide clear recovery instructions
@@ -1368,6 +1605,9 @@ class UpdateTransaction {
1368
1605
 
1369
1606
  await this.createCheckpoint();
1370
1607
 
1608
+ // Clean up known stale directories/files from previous versions
1609
+ this.cleanupResult = this.cleanupStaleAetherDirs(this.repoPath);
1610
+
1371
1611
  // Phase 2: Sync (with network error handling)
1372
1612
  this.state = TransactionStates.SYNCING;
1373
1613
  try {
@@ -1403,15 +1643,26 @@ class UpdateTransaction {
1403
1643
  this.state = TransactionStates.COMMITTING;
1404
1644
  this.updateVersion(sourceVersion);
1405
1645
  this.state = TransactionStates.COMMITTED;
1646
+
1647
+ // Delete pending sentinel — update is now complete
1648
+ try {
1649
+ if (fs.existsSync(pendingPath)) {
1650
+ fs.unlinkSync(pendingPath);
1651
+ }
1652
+ } catch (err) {
1653
+ this.log(` Warning: could not clear update sentinel: ${err.message}`);
1654
+ }
1406
1655
  }
1407
1656
 
1408
1657
  // Calculate totals
1409
1658
  const filesSynced = (this.syncResult?.system?.copied || 0) +
1410
1659
  (this.syncResult?.commands?.copied || 0) +
1411
- (this.syncResult?.agents?.copied || 0);
1660
+ (this.syncResult?.agents?.copied || 0) +
1661
+ (this.syncResult?.rules?.copied || 0);
1412
1662
  const filesRemoved = (this.syncResult?.system?.removed?.length || 0) +
1413
1663
  (this.syncResult?.commands?.removed?.length || 0) +
1414
- (this.syncResult?.agents?.removed?.length || 0);
1664
+ (this.syncResult?.agents?.removed?.length || 0) +
1665
+ (this.syncResult?.rules?.removed?.length || 0);
1415
1666
 
1416
1667
  return {
1417
1668
  success: true,
@@ -1420,6 +1671,7 @@ class UpdateTransaction {
1420
1671
  files_synced: filesSynced,
1421
1672
  files_removed: filesRemoved,
1422
1673
  sync_result: this.syncResult,
1674
+ cleanup_result: this.cleanupResult || { cleaned: [], failed: [] },
1423
1675
  };
1424
1676
 
1425
1677
  } catch (error) {
@@ -1449,4 +1701,4 @@ module.exports = {
1449
1701
  UpdateError,
1450
1702
  UpdateErrorCodes,
1451
1703
  TransactionStates,
1452
- };
1704
+ };