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
@@ -0,0 +1,440 @@
1
+ #!/bin/bash
2
+ # Aether Chamber Utilities
3
+ # Manages entombed colonies — directory management, manifest generation, integrity verification
4
+ #
5
+ # Usage:
6
+ # source .aether/utils/chamber-utils.sh
7
+ # chamber_create <chamber_dir> <state_file> <goal> <phases_completed> <total_phases> <milestone> <version> <decisions_json> <learnings_json>
8
+ # chamber_verify <chamber_dir>
9
+ # chamber_list <chambers_root>
10
+ # chamber_sanitize_goal <goal>
11
+
12
+ set -euo pipefail
13
+
14
+ # Initialize lock state before sourcing (file-lock.sh trap needs these)
15
+ LOCK_ACQUIRED=${LOCK_ACQUIRED:-false}
16
+ CURRENT_LOCK=${CURRENT_LOCK:-""}
17
+
18
+ # Get script directory for sourcing (preserve parent SCRIPT_DIR if set)
19
+ __chamber_utils_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
20
+ # Respect existing AETHER_ROOT if already set
21
+ if [[ -z "${AETHER_ROOT:-}" ]]; then
22
+ AETHER_ROOT="$(cd "$__chamber_utils_dir/../.." && pwd 2>/dev/null || echo "$__chamber_utils_dir/../..")"
23
+ fi
24
+
25
+ # Use parent SCRIPT_DIR if available, otherwise use local
26
+ SCRIPT_DIR="${SCRIPT_DIR:-$__chamber_utils_dir}"
27
+
28
+ # Source atomic-write for safe file operations
29
+ [[ -f "$SCRIPT_DIR/atomic-write.sh" ]] && source "$SCRIPT_DIR/atomic-write.sh"
30
+
31
+ # --- JSON output helpers ---
32
+ json_ok() { printf '{"ok":true,"result":%s}\n' "$1"; }
33
+
34
+ # Guard: yield to error-handler.sh's enhanced json_err when already loaded
35
+ if ! type json_err &>/dev/null; then
36
+ json_err() {
37
+ local code="${1:-E_UNKNOWN}"
38
+ local message="${2:-An unknown error occurred}"
39
+ printf '{"ok":false,"error":{"code":"%s","message":"%s"}}\n' "$code" "$message" >&2
40
+ exit 1
41
+ }
42
+ fi
43
+
44
+ # Fallback E_* constants (no-ops when error-handler.sh is already loaded)
45
+ : "${E_UNKNOWN:=E_UNKNOWN}"
46
+ : "${E_VALIDATION_FAILED:=E_VALIDATION_FAILED}"
47
+ : "${E_FILE_NOT_FOUND:=E_FILE_NOT_FOUND}"
48
+ : "${E_BASH_ERROR:=E_BASH_ERROR}"
49
+ : "${E_JSON_INVALID:=E_JSON_INVALID}"
50
+ : "${E_FEATURE_UNAVAILABLE:=E_FEATURE_UNAVAILABLE}"
51
+
52
+ # --- Chamber Functions ---
53
+
54
+ # Sanitize goal string for use in directory names
55
+ # Converts to lowercase, replaces spaces/special chars with hyphens, removes non-alphanumeric
56
+ chamber_sanitize_goal() {
57
+ local goal="$1"
58
+ # Convert to lowercase, replace spaces and special chars with hyphens
59
+ local sanitized=$(echo "$goal" | tr '[:upper:]' '[:lower:]' | tr -cs '[:alnum:]' '-')
60
+ # Remove leading/trailing hyphens
61
+ sanitized=$(echo "$sanitized" | sed 's/^-//;s/-$//')
62
+ # Limit length to avoid overly long directory names
63
+ if [[ ${#sanitized} -gt 50 ]]; then
64
+ sanitized="${sanitized:0:50}"
65
+ fi
66
+ echo "$sanitized"
67
+ }
68
+
69
+ # Compute SHA256 hash of a file
70
+ # Returns hash string or empty on error
71
+ chamber_compute_hash() {
72
+ local file_path="$1"
73
+ if [[ ! -f "$file_path" ]]; then
74
+ echo ""
75
+ return 1
76
+ fi
77
+
78
+ # Try sha256sum first (Linux), then shasum -a 256 (macOS)
79
+ if command -v sha256sum >/dev/null 2>&1; then
80
+ sha256sum "$file_path" | cut -d' ' -f1
81
+ elif command -v shasum >/dev/null 2>&1; then
82
+ shasum -a 256 "$file_path" | cut -d' ' -f1
83
+ else
84
+ echo ""
85
+ return 1
86
+ fi
87
+ }
88
+
89
+ # Create a new chamber (entomb a colony)
90
+ # Arguments:
91
+ # chamber_dir: Directory to create for this chamber
92
+ # state_file: Path to COLONY_STATE.json to archive
93
+ # goal: Colony goal string
94
+ # phases_completed: Number of completed phases
95
+ # total_phases: Total number of phases
96
+ # milestone: Milestone name
97
+ # version: Version string
98
+ # decisions_json: JSON array of decisions
99
+ # learnings_json: JSON array of learnings
100
+ chamber_create() {
101
+ local chamber_dir="$1"
102
+ local state_file="$2"
103
+ local goal="$3"
104
+ local phases_completed="$4"
105
+ local total_phases="$5"
106
+ local milestone="$6"
107
+ local version="$7"
108
+ local decisions_json="$8"
109
+ local learnings_json="$9"
110
+
111
+ # Validate inputs
112
+ [[ -z "$chamber_dir" ]] && json_err "$E_VALIDATION_FAILED" "chamber_dir argument is required. Try: pass the chamber directory path."
113
+ [[ -z "$state_file" ]] && json_err "$E_VALIDATION_FAILED" "state_file argument is required. Try: pass the state file path."
114
+ [[ ! -f "$state_file" ]] && json_err "$E_FILE_NOT_FOUND" "State file not found: $state_file. Try: check the file path."
115
+
116
+ # Create chamber directory
117
+ mkdir -p "$chamber_dir" || json_err "$E_BASH_ERROR" "Couldn't create chamber directory: $chamber_dir. Try: check disk space and permissions."
118
+
119
+ # Copy state file to chamber
120
+ local target_state="$chamber_dir/COLONY_STATE.json"
121
+ cp "$state_file" "$target_state" || json_err "$E_BASH_ERROR" "Couldn't copy the state file. Try: check disk space and permissions."
122
+
123
+ # Compute hash of the copied state file
124
+ local state_hash=$(chamber_compute_hash "$target_state")
125
+ [[ -z "$state_hash" ]] && json_err "$E_BASH_ERROR" "Couldn't compute state file hash. Try: check that shasum is available."
126
+
127
+ # Generate timestamp
128
+ local entombed_at=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
129
+
130
+ # Create manifest.json
131
+ local manifest_file="$chamber_dir/manifest.json"
132
+ local manifest_content=$(cat <<EOF
133
+ {
134
+ "entombed_at": "$entombed_at",
135
+ "goal": $(echo "$goal" | jq -Rs '.[:-1]'),
136
+ "phases_completed": $phases_completed,
137
+ "total_phases": $total_phases,
138
+ "milestone": $(echo "$milestone" | jq -Rs '.[:-1]'),
139
+ "version": $(echo "$version" | jq -Rs '.[:-1]'),
140
+ "decisions": $decisions_json,
141
+ "learnings": $learnings_json,
142
+ "files": {
143
+ "COLONY_STATE.json": "$state_hash"
144
+ }
145
+ }
146
+ EOF
147
+ )
148
+
149
+ # Write manifest atomically if atomic_write is available, otherwise direct
150
+ if type atomic_write &>/dev/null; then
151
+ atomic_write "$manifest_file" "$manifest_content" || json_err "$E_BASH_ERROR" "Couldn't write chamber manifest. Try: check disk space."
152
+ else
153
+ echo "$manifest_content" > "$manifest_file" || json_err "$E_BASH_ERROR" "Couldn't write chamber manifest. Try: check disk space."
154
+ fi
155
+
156
+ # Verify the manifest was written correctly
157
+ if [[ ! -f "$manifest_file" ]]; then
158
+ json_err "$E_FILE_NOT_FOUND" "Chamber manifest wasn't created. Try: check disk space and permissions."
159
+ fi
160
+
161
+ # Return success with chamber info
162
+ local result=$(cat <<EOF
163
+ {
164
+ "chamber_dir": "$chamber_dir",
165
+ "manifest": {
166
+ "entombed_at": "$entombed_at",
167
+ "goal": $(echo "$goal" | jq -Rs '.[:-1]'),
168
+ "phases_completed": $phases_completed,
169
+ "total_phases": $total_phases,
170
+ "milestone": $(echo "$milestone" | jq -Rs '.[:-1]'),
171
+ "version": $(echo "$version" | jq -Rs '.[:-1]')
172
+ }
173
+ }
174
+ EOF
175
+ )
176
+
177
+ json_ok "$result"
178
+ }
179
+
180
+ # Verify chamber integrity
181
+ # Arguments:
182
+ # chamber_dir: Directory containing the chamber
183
+ chamber_verify() {
184
+ local chamber_dir="$1"
185
+
186
+ # Validate inputs
187
+ [[ -z "$chamber_dir" ]] && json_err "$E_VALIDATION_FAILED" "chamber_dir argument is required. Try: pass the chamber directory path."
188
+ [[ ! -d "$chamber_dir" ]] && json_err "$E_FILE_NOT_FOUND" "Chamber directory not found: $chamber_dir. Try: check the path."
189
+
190
+ local manifest_file="$chamber_dir/manifest.json"
191
+ local state_file="$chamber_dir/COLONY_STATE.json"
192
+
193
+ # Check required files exist
194
+ [[ ! -f "$manifest_file" ]] && json_err "$E_FILE_NOT_FOUND" "Manifest not found in chamber. Try: verify the chamber was created correctly."
195
+ [[ ! -f "$state_file" ]] && json_err "$E_FILE_NOT_FOUND" "COLONY_STATE.json not found in chamber. Try: re-entomb the colony."
196
+
197
+ # Read stored hash from manifest
198
+ local stored_hash=$(jq -r '.files["COLONY_STATE.json"] // empty' "$manifest_file" 2>/dev/null)
199
+ [[ -z "$stored_hash" ]] && json_err "$E_JSON_INVALID" "No hash found in manifest. Try: re-entomb the colony."
200
+
201
+ # Compute current hash
202
+ local current_hash=$(chamber_compute_hash "$state_file")
203
+ [[ -z "$current_hash" ]] && json_err "$E_BASH_ERROR" "Couldn't compute state file hash. Try: check that shasum is available."
204
+
205
+ # Compare hashes
206
+ if [[ "$stored_hash" != "$current_hash" ]]; then
207
+ local result=$(cat <<EOF
208
+ {
209
+ "verified": false,
210
+ "chamber_dir": "$chamber_dir",
211
+ "error": "hash mismatch",
212
+ "stored_hash": "$stored_hash",
213
+ "current_hash": "$current_hash"
214
+ }
215
+ EOF
216
+ )
217
+ json_ok "$result"
218
+ return 0
219
+ fi
220
+
221
+ # Verification passed
222
+ local result=$(cat <<EOF
223
+ {
224
+ "verified": true,
225
+ "chamber_dir": "$chamber_dir",
226
+ "hash": "$current_hash"
227
+ }
228
+ EOF
229
+ )
230
+
231
+ json_ok "$result"
232
+ }
233
+
234
+ # List all chambers
235
+ # Arguments:
236
+ # chambers_root: Root directory containing chambers (default: .aether/chambers/)
237
+ chamber_list() {
238
+ local chambers_root="${1:-$AETHER_ROOT/.aether/chambers}"
239
+
240
+ # Default to current directory's chambers if AETHER_ROOT not set
241
+ if [[ -z "$chambers_root" || "$chambers_root" == "/.aether/chambers" ]]; then
242
+ chambers_root="$(pwd)/.aether/chambers"
243
+ fi
244
+
245
+ # Check if chambers directory exists
246
+ if [[ ! -d "$chambers_root" ]]; then
247
+ json_ok "[]"
248
+ return 0
249
+ fi
250
+
251
+ # Build array of chamber summaries
252
+ local chambers="["
253
+ local first=true
254
+
255
+ # Find all directories in chambers_root
256
+ while IFS= read -r -d '' chamber_dir; do
257
+ local chamber_name=$(basename "$chamber_dir")
258
+ local manifest_file="$chamber_dir/manifest.json"
259
+
260
+ # Skip if no manifest
261
+ [[ ! -f "$manifest_file" ]] && continue
262
+
263
+ # Read manifest fields
264
+ local goal=$(jq -r '.goal // "unknown"' "$manifest_file" 2>/dev/null)
265
+ local milestone=$(jq -r '.milestone // "unknown"' "$manifest_file" 2>/dev/null)
266
+ local phases_completed=$(jq -r '.phases_completed // 0' "$manifest_file" 2>/dev/null)
267
+ local entombed_at=$(jq -r '.entombed_at // ""' "$manifest_file" 2>/dev/null)
268
+
269
+ # Escape for JSON
270
+ goal=$(echo "$goal" | jq -Rs '.[:-1]')
271
+ milestone=$(echo "$milestone" | jq -Rs '.[:-1]')
272
+
273
+ # Add comma if not first
274
+ if [[ "$first" == "true" ]]; then
275
+ first=false
276
+ else
277
+ chambers+=","
278
+ fi
279
+
280
+ chambers+=$(cat <<EOF
281
+ {
282
+ "name": $(echo "$chamber_name" | jq -Rs '.[:-1]'),
283
+ "goal": $goal,
284
+ "milestone": $milestone,
285
+ "phases_completed": $phases_completed,
286
+ "entombed_at": $(echo "$entombed_at" | jq -Rs '.[:-1]')
287
+ }
288
+ EOF
289
+ )
290
+ done < <(find "$chambers_root" -mindepth 1 -maxdepth 1 -type d -print0 2>/dev/null || true)
291
+
292
+ chambers+="]"
293
+
294
+ # Sort by entombed_at descending using jq
295
+ local sorted=$(echo "$chambers" | jq 'sort_by(.entombed_at) | reverse')
296
+
297
+ json_ok "$sorted"
298
+ }
299
+
300
+ # --- Colony Archive XML ---
301
+
302
+ # Export combined colony archive XML containing pheromones, wisdom, and registry
303
+ # Usage: _colony_archive_xml [output_file]
304
+ # Default output: .aether/exchange/colony-archive.xml
305
+ # Always filters to active-only pheromone signals
306
+ _colony_archive_xml() {
307
+ # Graceful degradation: check for xmllint
308
+ if ! command -v xmllint >/dev/null 2>&1; then
309
+ json_err "$E_FEATURE_UNAVAILABLE" "xmllint is not installed. Try: xcode-select --install on macOS."
310
+ fi
311
+
312
+ cax_output="${1:-$SCRIPT_DIR/exchange/colony-archive.xml}"
313
+ mkdir -p "$(dirname "$cax_output")"
314
+
315
+ # Step 1: Filter active-only pheromone signals to a temp file
316
+ cax_tmp_pheromones=$(mktemp)
317
+ if [[ -f "$COLONY_DATA_DIR/pheromones.json" ]]; then
318
+ jq '{
319
+ version: .version,
320
+ colony_id: .colony_id,
321
+ generated_at: .generated_at,
322
+ signals: [.signals[] | select(.active == true)]
323
+ }' "$COLONY_DATA_DIR/pheromones.json" > "$cax_tmp_pheromones" 2>/dev/null # SUPPRESS:OK -- read-default: file may not exist yet
324
+ else
325
+ printf '%s\n' '{"version":"1.0","colony_id":"unknown","generated_at":"","signals":[]}' > "$cax_tmp_pheromones"
326
+ fi
327
+
328
+ # Step 2: Export each section to temp XML files
329
+ cax_tmp_dir=$(mktemp -d)
330
+
331
+ # Pheromone section (using filtered active-only)
332
+ source "$SCRIPT_DIR/exchange/pheromone-xml.sh"
333
+ xml-pheromone-export "$cax_tmp_pheromones" "$cax_tmp_dir/pheromones.xml" 2>/dev/null || _aether_log_error "Could not export pheromones to XML"
334
+
335
+ # Wisdom section — reuse wisdom-export-xml fallback logic
336
+ source "$SCRIPT_DIR/exchange/wisdom-xml.sh"
337
+ cax_wisdom_input="$DATA_DIR/queen-wisdom.json"
338
+ if [[ ! -f "$cax_wisdom_input" ]]; then
339
+ # MIGRATE: direct COLONY_STATE.json access -- use _state_read_field instead
340
+ # Try extracting from COLONY_STATE.json memory field
341
+ if [[ -f "$DATA_DIR/COLONY_STATE.json" ]]; then
342
+ cax_wex_memory=$(jq '.memory // {}' "$DATA_DIR/COLONY_STATE.json" 2>/dev/null || echo '{}') # SUPPRESS:OK -- read-default: returns fallback if missing
343
+ if [[ "$cax_wex_memory" != "{}" && "$cax_wex_memory" != "null" ]]; then
344
+ cax_wex_created_at=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
345
+ cax_wisdom_input="$cax_tmp_dir/wisdom-input.json"
346
+ printf '%s\n' "{
347
+ \"version\": \"1.0.0\",
348
+ # SUPPRESS:OK -- read-default: query may return empty
349
+ \"metadata\": {\"created\": \"$cax_wex_created_at\", \"colony_id\": \"$(jq -r '.goal // \"unknown\"' "$DATA_DIR/COLONY_STATE.json" 2>/dev/null)\"},
350
+ \"philosophies\": [],
351
+ # SUPPRESS:OK -- read-default: query may return empty
352
+ \"patterns\": $(echo "$cax_wex_memory" | jq '[.instincts // [] | .[] | {"id": (. | @base64), "content": ., "confidence": 0.7, "domain": "general", "source": "colony_memory"}]' 2>/dev/null || echo '[]')
353
+ }" > "$cax_wisdom_input"
354
+ fi
355
+ fi
356
+ fi
357
+ if [[ -f "$cax_wisdom_input" ]]; then
358
+ xml-wisdom-export "$cax_wisdom_input" "$cax_tmp_dir/wisdom.xml" 2>/dev/null || _aether_log_error "Could not export wisdom to XML"
359
+ fi
360
+
361
+ # Registry section — reuse registry-export-xml on-demand generation logic
362
+ source "$SCRIPT_DIR/exchange/registry-xml.sh"
363
+ cax_registry_input="$DATA_DIR/colony-registry.json"
364
+ if [[ ! -f "$cax_registry_input" ]]; then
365
+ cax_rex_chambers_dir="$AETHER_ROOT/.aether/chambers"
366
+ cax_rex_generated_at=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
367
+ cax_rex_colonies="[]"
368
+ if [[ -d "$cax_rex_chambers_dir" ]]; then
369
+ cax_rex_colonies=$(
370
+ for manifest in "$cax_rex_chambers_dir"/*/manifest.json; do
371
+ [[ -f "$manifest" ]] || continue
372
+ jq -c '{
373
+ id: (.colony_id // .goal // "unknown"),
374
+ name: (.goal // "Unnamed Colony"),
375
+ created_at: (.created_at // "unknown"),
376
+ sealed_at: (.sealed_at // null),
377
+ status: (if .sealed_at then "sealed" else "active" end),
378
+ chamber: input_filename
379
+ }' "$manifest" 2>/dev/null || true # SUPPRESS:OK -- cleanup: operation is best-effort
380
+ done | jq -s '.' 2>/dev/null || echo '[]' # SUPPRESS:OK -- read-default: returns fallback if missing
381
+ )
382
+ fi
383
+ cax_registry_input="$cax_tmp_dir/registry-input.json"
384
+ printf '%s\n' "{
385
+ \"version\": \"1.0.0\",
386
+ \"generated_at\": \"$cax_rex_generated_at\",
387
+ \"colonies\": $cax_rex_colonies
388
+ }" > "$cax_registry_input"
389
+ fi
390
+ xml-registry-export "$cax_registry_input" "$cax_tmp_dir/registry.xml" 2>/dev/null || _aether_log_error "Could not export registry to XML"
391
+
392
+ # Step 3: Build combined XML
393
+ # SUPPRESS:OK -- read-default: query may return empty
394
+ cax_colony_id=$(jq -r '.goal // "unknown"' "$DATA_DIR/COLONY_STATE.json" 2>/dev/null | tr '[:upper:]' '[:lower:]' | tr -cs '[:alnum:]' '-' | sed 's/^-//;s/-$//')
395
+ [[ -z "$cax_colony_id" || "$cax_colony_id" == "unknown" ]] && cax_colony_id="unknown"
396
+ cax_sealed_at=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
397
+ cax_pheromone_count=$(jq '.signals | length' "$cax_tmp_pheromones" 2>/dev/null || echo 0) # SUPPRESS:OK -- read-default: file may not exist yet
398
+
399
+ {
400
+ printf '<?xml version="1.0" encoding="UTF-8"?>\n'
401
+ printf '<colony-archive\n'
402
+ printf ' xmlns="http://aether.colony/schemas/archive/1.0"\n'
403
+ printf ' colony_id="%s"\n' "$cax_colony_id"
404
+ printf ' sealed_at="%s"\n' "$cax_sealed_at"
405
+ printf ' version="1.0.0"\n'
406
+ printf ' pheromone_count="%s">\n' "$cax_pheromone_count"
407
+
408
+ # Append pheromone section (strip XML declaration)
409
+ if [[ -f "$cax_tmp_dir/pheromones.xml" ]]; then
410
+ sed '1{/^<?xml/d;}' "$cax_tmp_dir/pheromones.xml"
411
+ fi
412
+
413
+ # Append wisdom section (strip XML declaration)
414
+ if [[ -f "$cax_tmp_dir/wisdom.xml" ]]; then
415
+ sed '1{/^<?xml/d;}' "$cax_tmp_dir/wisdom.xml"
416
+ fi
417
+
418
+ # Append registry section (strip XML declaration)
419
+ if [[ -f "$cax_tmp_dir/registry.xml" ]]; then
420
+ sed '1{/^<?xml/d;}' "$cax_tmp_dir/registry.xml"
421
+ fi
422
+
423
+ printf '</colony-archive>\n'
424
+ } > "$cax_output"
425
+
426
+ # Step 4: Validate well-formedness
427
+ if xmllint --noout "$cax_output" 2>/dev/null; then # SUPPRESS:OK -- validation: testing XML validity
428
+ cax_valid=true
429
+ else
430
+ cax_valid=false
431
+ fi
432
+
433
+ # Step 5: Cleanup temp files
434
+ rm -rf "$cax_tmp_dir" "$cax_tmp_pheromones"
435
+
436
+ json_ok "$(jq -n --arg path "$cax_output" --argjson valid "$cax_valid" --arg colony_id "$cax_colony_id" --argjson pheromone_count "$cax_pheromone_count" '{path: $path, valid: $valid, colony_id: $colony_id, pheromone_count: $pheromone_count}')"
437
+ }
438
+
439
+ # Export functions for use in other scripts
440
+ export -f chamber_sanitize_goal chamber_compute_hash chamber_create chamber_verify chamber_list _colony_archive_xml
@@ -0,0 +1,166 @@
1
+ #!/usr/bin/env bash
2
+ # emoji-audit.sh — Audit emoji usage across Aether command files
3
+ # Checks command files against the canonical emoji reference map defined in
4
+ # .aether/skills/colony/colony-visuals/SKILL.md
5
+ #
6
+ # Usage: bash emoji-audit.sh [repo_root]
7
+ #
8
+ # Output: JSON compatible with aether-utils.sh subcommand pattern:
9
+ # {"ok": true, "result": {"files_scanned": N, "total_emojis": N,
10
+ # "unmapped": [...], "unused": [...], "usage": {...}}}
11
+ #
12
+ # Compatible with bash 3.x (macOS system bash).
13
+ # Can be sourced by aether-utils.sh or run standalone.
14
+
15
+ # ---------------------------------------------------------------------------
16
+ # _emoji_audit_main — perform the audit and print JSON result
17
+ # Uses Python3 for emoji extraction and map logic (handles multi-codepoint sequences)
18
+ # ---------------------------------------------------------------------------
19
+ _emoji_audit_main() {
20
+ local repo_root="${1:-.}"
21
+
22
+ if ! command -v python3 >/dev/null 2>&1; then
23
+ printf '{"ok":false,"error":"python3 is required but not found"}\n'
24
+ return 1
25
+ fi
26
+
27
+ python3 - "$repo_root" <<'PYEOF'
28
+ import sys
29
+ import os
30
+ import re
31
+ import json
32
+ import glob
33
+
34
+ repo_root = sys.argv[1] if len(sys.argv) > 1 else "."
35
+
36
+ # ---------------------------------------------------------------------------
37
+ # Canonical emoji reference map — must match colony-visuals SKILL.md
38
+ # ---------------------------------------------------------------------------
39
+ EMOJI_REF_MAP = {
40
+ "\U0001f528": "Builder ant", # 🔨
41
+ "\U0001f441\ufe0f": "Watcher ant", # 👁️
42
+ "\U0001f3b2": "Chaos ant", # 🎲
43
+ "\U0001f50d": "Scout ant", # 🔍
44
+ "\U0001f3fa": "Archaeologist / Seal", # 🏺
45
+ "\U0001f52e": "Oracle ant", # 🔮
46
+ "\U0001f3db\ufe0f": "Architect ant", # 🏛️
47
+ "\U0001f50c": "Ambassador ant", # 🔌
48
+ "\U0001f4ca": "Measurer ant / Status", # 📊
49
+ "\U0001f9ea": "Probe / Tests", # 🧪
50
+ "\U0001f504": "Weaver / Refresh", # 🔄
51
+ "\U0001f4e6": "Gatekeeper / Package", # 📦
52
+ "\U0001f465": "Auditor", # 👥
53
+ "\U0001f6a9": "Flag / Blocker", # 🚩
54
+ "\U0001f4ad": "Dream", # 💭
55
+ "\U0001f95a": "Queen / Init", # 🥚
56
+ "\U0001f4cb": "Plan / List", # 📋
57
+ "\u2705": "Pass / Success", # ✅
58
+ "\u274c": "Fail / Error", # ❌
59
+ "\u26a0\ufe0f": "Warning", # ⚠️
60
+ "\u26d4": "Hard block", # ⛔
61
+ "\U0001f4be": "Save / Persist", # 💾
62
+ "\U0001f3af": "Focus signal", # 🎯
63
+ "\U0001f6ab": "Redirect signal", # 🚫
64
+ "\U0001f4ac": "Feedback signal", # 💬
65
+ }
66
+
67
+ # ---------------------------------------------------------------------------
68
+ # Scan command files
69
+ # ---------------------------------------------------------------------------
70
+ scan_dirs = [
71
+ os.path.join(repo_root, ".claude", "commands", "ant"),
72
+ os.path.join(repo_root, ".opencode", "commands", "ant"),
73
+ ]
74
+
75
+ scan_files = []
76
+ for d in scan_dirs:
77
+ if os.path.isdir(d):
78
+ scan_files.extend(glob.glob(os.path.join(d, "*.md")))
79
+
80
+ files_scanned = len(scan_files)
81
+
82
+ # ---------------------------------------------------------------------------
83
+ # Extract emoji sequences from combined content
84
+ # Matches base emoji + optional variation selectors, ZWJ sequences
85
+ # ---------------------------------------------------------------------------
86
+ EMOJI_PATTERN = re.compile(
87
+ r'[\U0001F300-\U0001F9FF\U00002600-\U000027BF\U00002702-\U000027B0'
88
+ r'\U0001FA00-\U0001FA9F\U0001FAA0-\U0001FAFF\U00002300-\U000023FF'
89
+ r'\U00002B00-\U00002BFF\U00003000-\U0000303F'
90
+ r'\U0001F600-\U0001F64F\U0001F680-\U0001F6FF'
91
+ r'\u2300-\u27BF\u2B00-\u2BFF\u2600-\u27FF'
92
+ r'\u2702-\u27B0\u2194-\u21AA\u231A-\u231B\u23E9-\u23F3\u23F8-\u23FA'
93
+ r'\u25AA-\u25FE\u2614-\u2615\u2648-\u2653\u267F\u2693\u26A0-\u26A1'
94
+ r'\u26AA-\u26AB\u26BD-\u26BE\u26C4-\u26C5\u26CE\u26D4\u26EA'
95
+ r'\u26F2-\u26F3\u26F5\u26FA\u26FD\u2702\u2705\u2708-\u270D'
96
+ r'\u270F\u2712\u2714\u2716\u271D\u2721\u2728\u2733-\u2734\u2744'
97
+ r'\u2747\u274C\u274E\u2753-\u2755\u2757\u2763-\u2764\u2795-\u2797'
98
+ r'\u27A1\u27B0\u27BF\u2934-\u2935\u2B05-\u2B07\u2B1B-\u2B1C\u2B50'
99
+ r'\u2B55\u3030\u303D\u3297\u3299]'
100
+ r'[\uFE0E\uFE0F\u20D0-\u20FF\u200D\U0001F3FB-\U0001F3FF]*'
101
+ r'(?:\u200D[\U0001F300-\U0001FFFF\u2600-\u27BF][\uFE0E\uFE0F\u20D0-\u20FF]*)*',
102
+ re.UNICODE
103
+ )
104
+
105
+ found_emojis = set()
106
+ for filepath in scan_files:
107
+ try:
108
+ with open(filepath, "r", encoding="utf-8", errors="replace") as fh:
109
+ content = fh.read()
110
+ for m in EMOJI_PATTERN.finditer(content):
111
+ e = m.group(0)
112
+ if e.strip():
113
+ found_emojis.add(e)
114
+ except OSError:
115
+ pass
116
+
117
+ total_emojis = len(found_emojis)
118
+
119
+ # ---------------------------------------------------------------------------
120
+ # Compute results
121
+ # ---------------------------------------------------------------------------
122
+ # Normalize ref map keys for lookup (strip variation selectors for comparison)
123
+ def normalize(s):
124
+ return s.replace("\ufe0f", "").replace("\ufe0e", "")
125
+
126
+ ref_normalized = {normalize(k): (k, v) for k, v in EMOJI_REF_MAP.items()}
127
+ found_normalized = {normalize(e): e for e in found_emojis}
128
+
129
+ # unmapped: found in files but not in reference map (by normalized form)
130
+ unmapped = sorted([
131
+ raw for norm, raw in found_normalized.items()
132
+ if norm not in ref_normalized
133
+ ])
134
+
135
+ # unused: in reference map but not found in files (by normalized form)
136
+ unused = sorted([
137
+ canonical for norm, (canonical, concept) in ref_normalized.items()
138
+ if norm not in found_normalized
139
+ ])
140
+
141
+ # usage: reference map entries found in files -> concept
142
+ usage = {}
143
+ for norm, (canonical, concept) in ref_normalized.items():
144
+ if norm in found_normalized:
145
+ usage[canonical] = concept
146
+
147
+ output = {
148
+ "ok": True,
149
+ "result": {
150
+ "files_scanned": files_scanned,
151
+ "total_emojis": total_emojis,
152
+ "unmapped": unmapped,
153
+ "unused": unused,
154
+ "usage": usage,
155
+ }
156
+ }
157
+ print(json.dumps(output))
158
+ PYEOF
159
+ }
160
+
161
+ # ---------------------------------------------------------------------------
162
+ # Entry point when run as a standalone script
163
+ # ---------------------------------------------------------------------------
164
+ if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
165
+ _emoji_audit_main "${1:-$(pwd)}"
166
+ fi