aether-colony 5.0.0 → 5.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.aether/aether-utils.sh +3226 -3345
- package/.aether/agents-claude/aether-ambassador.md +265 -0
- package/.aether/agents-claude/aether-archaeologist.md +327 -0
- package/.aether/agents-claude/aether-architect.md +236 -0
- package/.aether/agents-claude/aether-auditor.md +271 -0
- package/.aether/agents-claude/aether-builder.md +224 -0
- package/.aether/agents-claude/aether-chaos.md +269 -0
- package/.aether/agents-claude/aether-chronicler.md +305 -0
- package/.aether/agents-claude/aether-gatekeeper.md +330 -0
- package/.aether/agents-claude/aether-includer.md +374 -0
- package/.aether/agents-claude/aether-keeper.md +272 -0
- package/.aether/agents-claude/aether-measurer.md +322 -0
- package/.aether/agents-claude/aether-oracle.md +237 -0
- package/.aether/agents-claude/aether-probe.md +211 -0
- package/.aether/agents-claude/aether-queen.md +330 -0
- package/.aether/agents-claude/aether-route-setter.md +178 -0
- package/.aether/agents-claude/aether-sage.md +418 -0
- package/.aether/agents-claude/aether-scout.md +179 -0
- package/.aether/agents-claude/aether-surveyor-disciplines.md +417 -0
- package/.aether/agents-claude/aether-surveyor-nest.md +355 -0
- package/.aether/agents-claude/aether-surveyor-pathogens.md +289 -0
- package/.aether/agents-claude/aether-surveyor-provisions.md +360 -0
- package/.aether/agents-claude/aether-tracker.md +270 -0
- package/.aether/agents-claude/aether-watcher.md +280 -0
- package/.aether/agents-claude/aether-weaver.md +248 -0
- package/.aether/commands/archaeology.yaml +653 -0
- package/.aether/commands/build.yaml +1221 -0
- package/.aether/commands/chaos.yaml +653 -0
- package/.aether/commands/colonize.yaml +442 -0
- package/.aether/commands/continue.yaml +1484 -0
- package/.aether/commands/council.yaml +509 -0
- package/.aether/commands/data-clean.yaml +80 -0
- package/.aether/commands/dream.yaml +275 -0
- package/.aether/commands/entomb.yaml +863 -0
- package/.aether/commands/export-signals.yaml +64 -0
- package/.aether/commands/feedback.yaml +158 -0
- package/.aether/commands/flag.yaml +160 -0
- package/.aether/commands/flags.yaml +177 -0
- package/.aether/commands/focus.yaml +112 -0
- package/.aether/commands/help.yaml +167 -0
- package/.aether/commands/history.yaml +137 -0
- package/.aether/commands/import-signals.yaml +79 -0
- package/.aether/commands/init.yaml +502 -0
- package/.aether/commands/insert-phase.yaml +102 -0
- package/.aether/commands/interpret.yaml +285 -0
- package/.aether/commands/lay-eggs.yaml +224 -0
- package/.aether/commands/maturity.yaml +122 -0
- package/.aether/commands/memory-details.yaml +74 -0
- package/.aether/commands/migrate-state.yaml +174 -0
- package/.aether/commands/oracle.yaml +1224 -0
- package/.aether/commands/organize.yaml +446 -0
- package/.aether/commands/patrol.yaml +621 -0
- package/.aether/commands/pause-colony.yaml +424 -0
- package/.aether/commands/phase.yaml +124 -0
- package/.aether/commands/pheromones.yaml +153 -0
- package/.aether/commands/plan.yaml +1364 -0
- package/.aether/commands/preferences.yaml +63 -0
- package/.aether/commands/quick.yaml +104 -0
- package/.aether/commands/redirect.yaml +123 -0
- package/.aether/commands/resume-colony.yaml +375 -0
- package/.aether/commands/resume.yaml +407 -0
- package/.aether/commands/run.yaml +229 -0
- package/.aether/commands/seal.yaml +1214 -0
- package/.aether/commands/skill-create.yaml +337 -0
- package/.aether/commands/status.yaml +408 -0
- package/.aether/commands/swarm.yaml +352 -0
- package/.aether/commands/tunnels.yaml +814 -0
- package/.aether/commands/update.yaml +131 -0
- package/.aether/commands/verify-castes.yaml +159 -0
- package/.aether/commands/watch.yaml +454 -0
- package/.aether/docs/INCIDENT_TEMPLATE.md +32 -0
- package/.aether/docs/QUEEN-SYSTEM.md +11 -11
- package/.aether/docs/README.md +32 -2
- package/.aether/docs/command-playbooks/README.md +23 -0
- package/.aether/docs/command-playbooks/build-complete.md +349 -0
- package/.aether/docs/command-playbooks/build-context.md +282 -0
- package/.aether/docs/command-playbooks/build-full.md +1683 -0
- package/.aether/docs/command-playbooks/build-prep.md +284 -0
- package/.aether/docs/command-playbooks/build-verify.md +405 -0
- package/.aether/docs/command-playbooks/build-wave.md +749 -0
- package/.aether/docs/command-playbooks/continue-advance.md +524 -0
- package/.aether/docs/command-playbooks/continue-finalize.md +447 -0
- package/.aether/docs/command-playbooks/continue-full.md +1725 -0
- package/.aether/docs/command-playbooks/continue-gates.md +686 -0
- package/.aether/docs/command-playbooks/continue-verify.md +407 -0
- package/.aether/docs/context-continuity.md +84 -0
- package/.aether/docs/disciplines/DISCIPLINES.md +9 -7
- package/.aether/docs/error-codes.md +1 -1
- package/.aether/docs/known-issues.md +34 -173
- package/.aether/docs/pheromones.md +86 -6
- package/.aether/docs/plans/pheromone-display-plan.md +257 -0
- package/.aether/docs/queen-commands.md +10 -9
- package/.aether/docs/source-of-truth-map.md +132 -0
- package/.aether/docs/xml-utilities.md +47 -0
- package/.aether/rules/aether-colony.md +23 -13
- package/.aether/scripts/incident-test-add.sh +47 -0
- package/.aether/scripts/weekly-audit.sh +79 -0
- package/.aether/skills/.index.json +649 -0
- package/.aether/skills/colony/.manifest.json +16 -0
- package/.aether/skills/colony/build-discipline/SKILL.md +78 -0
- package/.aether/skills/colony/colony-interaction/SKILL.md +56 -0
- package/.aether/skills/colony/colony-lifecycle/SKILL.md +77 -0
- package/.aether/skills/colony/colony-visuals/SKILL.md +112 -0
- package/.aether/skills/colony/context-management/SKILL.md +80 -0
- package/.aether/skills/colony/error-presentation/SKILL.md +99 -0
- package/.aether/skills/colony/pheromone-protocol/SKILL.md +79 -0
- package/.aether/skills/colony/pheromone-visibility/SKILL.md +81 -0
- package/.aether/skills/colony/state-safety/SKILL.md +84 -0
- package/.aether/skills/colony/worker-priming/SKILL.md +82 -0
- package/.aether/skills/domain/.manifest.json +24 -0
- package/.aether/skills/domain/README.md +33 -0
- package/.aether/skills/domain/django/SKILL.md +49 -0
- package/.aether/skills/domain/docker/SKILL.md +52 -0
- package/.aether/skills/domain/golang/SKILL.md +52 -0
- package/.aether/skills/domain/graphql/SKILL.md +51 -0
- package/.aether/skills/domain/html-css/SKILL.md +48 -0
- package/.aether/skills/domain/nextjs/SKILL.md +45 -0
- package/.aether/skills/domain/nodejs/SKILL.md +53 -0
- package/.aether/skills/domain/postgresql/SKILL.md +53 -0
- package/.aether/skills/domain/prisma/SKILL.md +59 -0
- package/.aether/skills/domain/python/SKILL.md +50 -0
- package/.aether/skills/domain/rails/SKILL.md +52 -0
- package/.aether/skills/domain/react/SKILL.md +45 -0
- package/.aether/skills/domain/rest-api/SKILL.md +58 -0
- package/.aether/skills/domain/svelte/SKILL.md +47 -0
- package/.aether/skills/domain/tailwind/SKILL.md +45 -0
- package/.aether/skills/domain/testing/SKILL.md +53 -0
- package/.aether/skills/domain/typescript/SKILL.md +58 -0
- package/.aether/skills/domain/vue/SKILL.md +49 -0
- package/.aether/templates/QUEEN.md.template +23 -41
- package/.aether/templates/colony-state-reset.jq.template +1 -0
- package/.aether/templates/colony-state.template.json +4 -0
- package/.aether/templates/learning-observations.template.json +6 -0
- package/.aether/templates/midden.template.json +13 -0
- package/.aether/templates/pheromones.template.json +6 -0
- package/.aether/templates/session.template.json +9 -0
- package/.aether/utils/atomic-write.sh +63 -17
- package/.aether/utils/chamber-utils.sh +145 -2
- package/.aether/utils/council.sh +425 -0
- package/.aether/utils/emoji-audit.sh +166 -0
- package/.aether/utils/error-handler.sh +21 -7
- package/.aether/utils/file-lock.sh +182 -27
- package/.aether/utils/flag.sh +278 -0
- package/.aether/utils/hive.sh +572 -0
- package/.aether/utils/immune.sh +508 -0
- package/.aether/utils/learning.sh +1928 -0
- package/.aether/utils/midden.sh +520 -0
- package/.aether/utils/oracle/oracle.md +168 -0
- package/.aether/utils/oracle/oracle.sh +1023 -0
- package/.aether/utils/pheromone.sh +2029 -0
- package/.aether/utils/queen.sh +1710 -0
- package/.aether/utils/scan.sh +860 -0
- package/.aether/utils/semantic-cli.sh +10 -8
- package/.aether/utils/session.sh +816 -0
- package/.aether/utils/skills.sh +509 -0
- package/.aether/utils/spawn-tree.sh +103 -271
- package/.aether/utils/spawn.sh +260 -0
- package/.aether/utils/state-api.sh +389 -0
- package/.aether/utils/state-loader.sh +8 -6
- package/.aether/utils/suggest.sh +611 -0
- package/.aether/utils/swarm-display.sh +10 -1
- package/.aether/utils/swarm.sh +1004 -0
- package/.aether/utils/watch-spawn-tree.sh +11 -2
- package/.aether/utils/xml-compose.sh +2 -2
- package/.aether/utils/xml-convert.sh +9 -5
- package/.aether/utils/xml-core.sh +5 -9
- package/.aether/utils/xml-query.sh +4 -4
- package/.aether/workers.md +86 -67
- package/.claude/agents/ant/aether-ambassador.md +2 -1
- package/.claude/agents/ant/aether-archaeologist.md +6 -1
- package/.claude/agents/ant/aether-architect.md +236 -0
- package/.claude/agents/ant/aether-auditor.md +6 -1
- package/.claude/agents/ant/aether-builder.md +38 -1
- package/.claude/agents/ant/aether-chaos.md +2 -1
- package/.claude/agents/ant/aether-chronicler.md +1 -0
- package/.claude/agents/ant/aether-gatekeeper.md +6 -1
- package/.claude/agents/ant/aether-includer.md +1 -0
- package/.claude/agents/ant/aether-keeper.md +1 -0
- package/.claude/agents/ant/aether-measurer.md +6 -1
- package/.claude/agents/ant/aether-oracle.md +237 -0
- package/.claude/agents/ant/aether-probe.md +2 -1
- package/.claude/agents/ant/aether-queen.md +6 -1
- package/.claude/agents/ant/aether-route-setter.md +6 -1
- package/.claude/agents/ant/aether-sage.md +68 -3
- package/.claude/agents/ant/aether-scout.md +38 -1
- package/.claude/agents/ant/aether-surveyor-disciplines.md +2 -1
- package/.claude/agents/ant/aether-surveyor-nest.md +2 -1
- package/.claude/agents/ant/aether-surveyor-pathogens.md +2 -1
- package/.claude/agents/ant/aether-surveyor-provisions.md +2 -1
- package/.claude/agents/ant/aether-tracker.md +6 -1
- package/.claude/agents/ant/aether-watcher.md +37 -1
- package/.claude/agents/ant/aether-weaver.md +2 -1
- package/.claude/commands/ant/archaeology.md +1 -8
- package/.claude/commands/ant/build.md +43 -1159
- package/.claude/commands/ant/chaos.md +1 -14
- package/.claude/commands/ant/colonize.md +3 -14
- package/.claude/commands/ant/continue.md +40 -1026
- package/.claude/commands/ant/council.md +213 -15
- package/.claude/commands/ant/data-clean.md +81 -0
- package/.claude/commands/ant/dream.md +12 -9
- package/.claude/commands/ant/entomb.md +62 -87
- package/.claude/commands/ant/export-signals.md +57 -0
- package/.claude/commands/ant/feedback.md +18 -0
- package/.claude/commands/ant/flag.md +12 -0
- package/.claude/commands/ant/flags.md +22 -8
- package/.claude/commands/ant/focus.md +18 -0
- package/.claude/commands/ant/help.md +40 -8
- package/.claude/commands/ant/history.md +3 -0
- package/.claude/commands/ant/import-signals.md +71 -0
- package/.claude/commands/ant/init.md +349 -191
- package/.claude/commands/ant/insert-phase.md +105 -0
- package/.claude/commands/ant/interpret.md +11 -0
- package/.claude/commands/ant/lay-eggs.md +167 -158
- package/.claude/commands/ant/maturity.md +22 -11
- package/.claude/commands/ant/memory-details.md +77 -0
- package/.claude/commands/ant/migrate-state.md +6 -0
- package/.claude/commands/ant/oracle.md +317 -62
- package/.claude/commands/ant/organize.md +10 -5
- package/.claude/commands/ant/patrol.md +620 -0
- package/.claude/commands/ant/pause-colony.md +8 -22
- package/.claude/commands/ant/phase.md +26 -37
- package/.claude/commands/ant/pheromones.md +156 -0
- package/.claude/commands/ant/plan.md +199 -50
- package/.claude/commands/ant/preferences.md +65 -0
- package/.claude/commands/ant/quick.md +100 -0
- package/.claude/commands/ant/redirect.md +18 -0
- package/.claude/commands/ant/resume-colony.md +37 -22
- package/.claude/commands/ant/resume.md +60 -7
- package/.claude/commands/ant/run.md +231 -0
- package/.claude/commands/ant/seal.md +506 -78
- package/.claude/commands/ant/skill-create.md +286 -0
- package/.claude/commands/ant/status.md +171 -1
- package/.claude/commands/ant/swarm.md +11 -23
- package/.claude/commands/ant/tunnels.md +1 -0
- package/.claude/commands/ant/update.md +58 -135
- package/.claude/commands/ant/verify-castes.md +90 -42
- package/.claude/commands/ant/watch.md +1 -0
- package/.opencode/agents/aether-ambassador.md +1 -1
- package/.opencode/agents/aether-architect.md +133 -0
- package/.opencode/agents/aether-builder.md +3 -3
- package/.opencode/agents/aether-oracle.md +137 -0
- package/.opencode/agents/aether-queen.md +1 -1
- package/.opencode/agents/aether-route-setter.md +1 -1
- package/.opencode/agents/aether-scout.md +1 -1
- package/.opencode/agents/aether-surveyor-disciplines.md +6 -1
- package/.opencode/agents/aether-surveyor-nest.md +6 -1
- package/.opencode/agents/aether-surveyor-pathogens.md +6 -1
- package/.opencode/agents/aether-surveyor-provisions.md +6 -1
- package/.opencode/agents/aether-tracker.md +1 -1
- package/.opencode/agents/aether-watcher.md +1 -1
- package/.opencode/agents/aether-weaver.md +1 -1
- package/.opencode/commands/ant/archaeology.md +7 -14
- package/.opencode/commands/ant/build.md +54 -88
- package/.opencode/commands/ant/chaos.md +7 -24
- package/.opencode/commands/ant/colonize.md +10 -17
- package/.opencode/commands/ant/continue.md +595 -66
- package/.opencode/commands/ant/council.md +150 -18
- package/.opencode/commands/ant/data-clean.md +77 -0
- package/.opencode/commands/ant/dream.md +15 -17
- package/.opencode/commands/ant/entomb.md +28 -18
- package/.opencode/commands/ant/export-signals.md +54 -0
- package/.opencode/commands/ant/feedback.md +24 -5
- package/.opencode/commands/ant/flag.md +16 -4
- package/.opencode/commands/ant/flags.md +24 -10
- package/.opencode/commands/ant/focus.md +22 -5
- package/.opencode/commands/ant/help.md +41 -8
- package/.opencode/commands/ant/history.md +9 -0
- package/.opencode/commands/ant/import-signals.md +68 -0
- package/.opencode/commands/ant/init.md +396 -154
- package/.opencode/commands/ant/insert-phase.md +111 -0
- package/.opencode/commands/ant/interpret.md +16 -0
- package/.opencode/commands/ant/lay-eggs.md +184 -112
- package/.opencode/commands/ant/maturity.md +18 -2
- package/.opencode/commands/ant/memory-details.md +83 -0
- package/.opencode/commands/ant/migrate-state.md +12 -0
- package/.opencode/commands/ant/oracle.md +322 -67
- package/.opencode/commands/ant/organize.md +14 -12
- package/.opencode/commands/ant/patrol.md +626 -0
- package/.opencode/commands/ant/pause-colony.md +12 -29
- package/.opencode/commands/ant/phase.md +30 -40
- package/.opencode/commands/ant/pheromones.md +162 -0
- package/.opencode/commands/ant/plan.md +210 -57
- package/.opencode/commands/ant/preferences.md +71 -0
- package/.opencode/commands/ant/quick.md +91 -0
- package/.opencode/commands/ant/redirect.md +22 -5
- package/.opencode/commands/ant/resume-colony.md +41 -29
- package/.opencode/commands/ant/resume.md +80 -20
- package/.opencode/commands/ant/run.md +237 -0
- package/.opencode/commands/ant/seal.md +230 -25
- package/.opencode/commands/ant/skill-create.md +63 -0
- package/.opencode/commands/ant/status.md +125 -30
- package/.opencode/commands/ant/swarm.md +3 -345
- package/.opencode/commands/ant/tunnels.md +3 -9
- package/.opencode/commands/ant/update.md +63 -127
- package/.opencode/commands/ant/verify-castes.md +96 -42
- package/.opencode/commands/ant/watch.md +7 -0
- package/CHANGELOG.md +368 -1
- package/README.md +195 -324
- package/bin/cli.js +236 -429
- package/bin/generate-commands.js +186 -0
- package/bin/generate-commands.sh +128 -89
- package/bin/lib/spawn-logger.js +0 -15
- package/bin/lib/update-transaction.js +285 -35
- package/bin/npx-install.js +178 -0
- package/bin/validate-package.sh +85 -3
- package/package.json +16 -4
- package/.aether/CONTEXT.md +0 -160
- package/.aether/docs/QUEEN.md +0 -84
- package/.aether/exchange/colony-registry.xml +0 -11
- package/.aether/exchange/pheromones.xml +0 -87
- package/.aether/exchange/queen-wisdom.xml +0 -14
- package/.aether/model-profiles.yaml +0 -100
- package/.aether/utils/spawn-with-model.sh +0 -56
- package/bin/lib/model-profiles.js +0 -445
- package/bin/lib/model-verify.js +0 -288
- package/bin/lib/proxy-health.js +0 -253
- package/bin/lib/telemetry.js +0 -441
|
@@ -0,0 +1,425 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Council deliberation module — Advocate/Challenger/Sage model with spawn budget guards
|
|
3
|
+
# Provides: _council_deliberate, _council_advocate, _council_challenger, _council_sage,
|
|
4
|
+
# _council_history, _council_budget_check
|
|
5
|
+
#
|
|
6
|
+
# These functions are sourced by aether-utils.sh at startup.
|
|
7
|
+
# All shared infrastructure (json_ok, json_err, atomic_write, acquire_lock,
|
|
8
|
+
# release_lock, LOCK_DIR, COLONY_DATA_DIR, error constants) is available.
|
|
9
|
+
# _spawn_can_spawn is available from spawn.sh (sourced before this module).
|
|
10
|
+
|
|
11
|
+
# ---------------------------------------------------------------------------
|
|
12
|
+
# Internal helpers
|
|
13
|
+
# ---------------------------------------------------------------------------
|
|
14
|
+
|
|
15
|
+
_council_data_dir() {
|
|
16
|
+
echo "$COLONY_DATA_DIR/council"
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
_council_deliberations_file() {
|
|
20
|
+
echo "$COLONY_DATA_DIR/council/deliberations.json"
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
_council_ensure_file() {
|
|
24
|
+
local cf
|
|
25
|
+
cf="$(_council_deliberations_file)"
|
|
26
|
+
mkdir -p "$(_council_data_dir)"
|
|
27
|
+
if [[ ! -f "$cf" ]]; then
|
|
28
|
+
printf '%s\n' '{"version":"1.0","deliberations":[]}' > "$cf"
|
|
29
|
+
fi
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
# ---------------------------------------------------------------------------
|
|
33
|
+
# _council_deliberate
|
|
34
|
+
# Usage: council-deliberate --proposal <text> [--budget N] [--depth light|standard|deep]
|
|
35
|
+
# ---------------------------------------------------------------------------
|
|
36
|
+
_council_deliberate() {
|
|
37
|
+
local cd_proposal=""
|
|
38
|
+
local cd_budget="3"
|
|
39
|
+
local cd_depth="standard"
|
|
40
|
+
|
|
41
|
+
while [[ $# -gt 0 ]]; do
|
|
42
|
+
case "$1" in
|
|
43
|
+
--proposal) cd_proposal="${2:-}"; shift 2 ;;
|
|
44
|
+
--budget) cd_budget="${2:-3}"; shift 2 ;;
|
|
45
|
+
--depth) cd_depth="${2:-standard}"; shift 2 ;;
|
|
46
|
+
*) shift ;;
|
|
47
|
+
esac
|
|
48
|
+
done
|
|
49
|
+
|
|
50
|
+
if [[ -z "$cd_proposal" ]]; then
|
|
51
|
+
json_err "$E_VALIDATION_FAILED" "council-deliberate requires --proposal"
|
|
52
|
+
return
|
|
53
|
+
fi
|
|
54
|
+
|
|
55
|
+
if ! [[ "$cd_budget" =~ ^[0-9]+$ ]]; then
|
|
56
|
+
json_err "$E_VALIDATION_FAILED" "council-deliberate --budget must be a positive integer"
|
|
57
|
+
return
|
|
58
|
+
fi
|
|
59
|
+
|
|
60
|
+
local cd_ts
|
|
61
|
+
cd_ts=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
|
|
62
|
+
local cd_unix
|
|
63
|
+
cd_unix=$(date -u +%s)
|
|
64
|
+
local cd_id="delib_${cd_unix}"
|
|
65
|
+
|
|
66
|
+
_council_ensure_file
|
|
67
|
+
|
|
68
|
+
local cd_file
|
|
69
|
+
cd_file="$(_council_deliberations_file)"
|
|
70
|
+
|
|
71
|
+
acquire_lock "$cd_file" 2>/dev/null || true
|
|
72
|
+
# shellcheck disable=SC2064
|
|
73
|
+
trap "release_lock '$cd_file' 2>/dev/null || true" EXIT
|
|
74
|
+
|
|
75
|
+
local cd_updated
|
|
76
|
+
cd_updated=$(jq \
|
|
77
|
+
--arg id "$cd_id" \
|
|
78
|
+
--arg proposal "$cd_proposal" \
|
|
79
|
+
--arg ts "$cd_ts" \
|
|
80
|
+
--argjson budget "$cd_budget" \
|
|
81
|
+
--arg depth "$cd_depth" \
|
|
82
|
+
'.deliberations += [{
|
|
83
|
+
"id": $id,
|
|
84
|
+
"proposal": $proposal,
|
|
85
|
+
"advocate": null,
|
|
86
|
+
"challenger": null,
|
|
87
|
+
"sage": null,
|
|
88
|
+
"budget": $budget,
|
|
89
|
+
"depth": $depth,
|
|
90
|
+
"created_at": $ts,
|
|
91
|
+
"status": "pending"
|
|
92
|
+
}]' "$cd_file") || {
|
|
93
|
+
release_lock "$cd_file" 2>/dev/null || true
|
|
94
|
+
trap - EXIT
|
|
95
|
+
json_err "$E_UNKNOWN" "Failed to write deliberation"
|
|
96
|
+
return
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
atomic_write "$cd_file" "$cd_updated" || {
|
|
100
|
+
release_lock "$cd_file" 2>/dev/null || true
|
|
101
|
+
trap - EXIT
|
|
102
|
+
json_err "$E_UNKNOWN" "Failed to persist deliberation"
|
|
103
|
+
return
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
release_lock "$cd_file" 2>/dev/null || true
|
|
107
|
+
trap - EXIT
|
|
108
|
+
|
|
109
|
+
json_ok "$(jq -n \
|
|
110
|
+
--arg id "$cd_id" \
|
|
111
|
+
--arg proposal "$cd_proposal" \
|
|
112
|
+
--argjson budget "$cd_budget" \
|
|
113
|
+
'{"id":$id,"proposal":$proposal,"status":"pending","budget":$budget}')"
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
# ---------------------------------------------------------------------------
|
|
117
|
+
# _council_advocate
|
|
118
|
+
# Usage: council-advocate --deliberation-id <id> --argument <text>
|
|
119
|
+
# ---------------------------------------------------------------------------
|
|
120
|
+
_council_advocate() {
|
|
121
|
+
local ca_id=""
|
|
122
|
+
local ca_argument=""
|
|
123
|
+
|
|
124
|
+
while [[ $# -gt 0 ]]; do
|
|
125
|
+
case "$1" in
|
|
126
|
+
--deliberation-id) ca_id="${2:-}"; shift 2 ;;
|
|
127
|
+
--argument) ca_argument="${2:-}"; shift 2 ;;
|
|
128
|
+
*) shift ;;
|
|
129
|
+
esac
|
|
130
|
+
done
|
|
131
|
+
|
|
132
|
+
if [[ -z "$ca_id" ]]; then
|
|
133
|
+
json_err "$E_VALIDATION_FAILED" "council-advocate requires --deliberation-id"
|
|
134
|
+
return
|
|
135
|
+
fi
|
|
136
|
+
|
|
137
|
+
if [[ -z "$ca_argument" ]]; then
|
|
138
|
+
json_err "$E_VALIDATION_FAILED" "council-advocate requires --argument"
|
|
139
|
+
return
|
|
140
|
+
fi
|
|
141
|
+
|
|
142
|
+
local ca_file
|
|
143
|
+
ca_file="$(_council_deliberations_file)"
|
|
144
|
+
|
|
145
|
+
if [[ ! -f "$ca_file" ]]; then
|
|
146
|
+
json_err "$E_VALIDATION_FAILED" "No deliberations found; run council-deliberate first"
|
|
147
|
+
return
|
|
148
|
+
fi
|
|
149
|
+
|
|
150
|
+
local ca_exists
|
|
151
|
+
ca_exists=$(jq -r --arg id "$ca_id" '.deliberations[] | select(.id == $id) | .id' "$ca_file" 2>/dev/null || echo "")
|
|
152
|
+
if [[ -z "$ca_exists" ]]; then
|
|
153
|
+
json_err "$E_VALIDATION_FAILED" "Deliberation not found: $ca_id"
|
|
154
|
+
return
|
|
155
|
+
fi
|
|
156
|
+
|
|
157
|
+
acquire_lock "$ca_file" 2>/dev/null || true
|
|
158
|
+
# shellcheck disable=SC2064
|
|
159
|
+
trap "release_lock '$ca_file' 2>/dev/null || true" EXIT
|
|
160
|
+
|
|
161
|
+
local ca_updated
|
|
162
|
+
ca_updated=$(jq \
|
|
163
|
+
--arg id "$ca_id" \
|
|
164
|
+
--arg arg "$ca_argument" \
|
|
165
|
+
'(.deliberations[] | select(.id == $id)).advocate = $arg
|
|
166
|
+
| (.deliberations[] | select(.id == $id)).status = "in_progress"' \
|
|
167
|
+
"$ca_file") || {
|
|
168
|
+
release_lock "$ca_file" 2>/dev/null || true
|
|
169
|
+
trap - EXIT
|
|
170
|
+
json_err "$E_UNKNOWN" "Failed to record advocate argument"
|
|
171
|
+
return
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
atomic_write "$ca_file" "$ca_updated" || {
|
|
175
|
+
release_lock "$ca_file" 2>/dev/null || true
|
|
176
|
+
trap - EXIT
|
|
177
|
+
json_err "$E_UNKNOWN" "Failed to persist advocate argument"
|
|
178
|
+
return
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
release_lock "$ca_file" 2>/dev/null || true
|
|
182
|
+
trap - EXIT
|
|
183
|
+
|
|
184
|
+
json_ok '{"role":"advocate","recorded":true}'
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
# ---------------------------------------------------------------------------
|
|
188
|
+
# _council_challenger
|
|
189
|
+
# Usage: council-challenger --deliberation-id <id> --argument <text>
|
|
190
|
+
# ---------------------------------------------------------------------------
|
|
191
|
+
_council_challenger() {
|
|
192
|
+
local cc_id=""
|
|
193
|
+
local cc_argument=""
|
|
194
|
+
|
|
195
|
+
while [[ $# -gt 0 ]]; do
|
|
196
|
+
case "$1" in
|
|
197
|
+
--deliberation-id) cc_id="${2:-}"; shift 2 ;;
|
|
198
|
+
--argument) cc_argument="${2:-}"; shift 2 ;;
|
|
199
|
+
*) shift ;;
|
|
200
|
+
esac
|
|
201
|
+
done
|
|
202
|
+
|
|
203
|
+
if [[ -z "$cc_id" ]]; then
|
|
204
|
+
json_err "$E_VALIDATION_FAILED" "council-challenger requires --deliberation-id"
|
|
205
|
+
return
|
|
206
|
+
fi
|
|
207
|
+
|
|
208
|
+
if [[ -z "$cc_argument" ]]; then
|
|
209
|
+
json_err "$E_VALIDATION_FAILED" "council-challenger requires --argument"
|
|
210
|
+
return
|
|
211
|
+
fi
|
|
212
|
+
|
|
213
|
+
local cc_file
|
|
214
|
+
cc_file="$(_council_deliberations_file)"
|
|
215
|
+
|
|
216
|
+
if [[ ! -f "$cc_file" ]]; then
|
|
217
|
+
json_err "$E_VALIDATION_FAILED" "No deliberations found; run council-deliberate first"
|
|
218
|
+
return
|
|
219
|
+
fi
|
|
220
|
+
|
|
221
|
+
local cc_exists
|
|
222
|
+
cc_exists=$(jq -r --arg id "$cc_id" '.deliberations[] | select(.id == $id) | .id' "$cc_file" 2>/dev/null || echo "")
|
|
223
|
+
if [[ -z "$cc_exists" ]]; then
|
|
224
|
+
json_err "$E_VALIDATION_FAILED" "Deliberation not found: $cc_id"
|
|
225
|
+
return
|
|
226
|
+
fi
|
|
227
|
+
|
|
228
|
+
acquire_lock "$cc_file" 2>/dev/null || true
|
|
229
|
+
# shellcheck disable=SC2064
|
|
230
|
+
trap "release_lock '$cc_file' 2>/dev/null || true" EXIT
|
|
231
|
+
|
|
232
|
+
local cc_updated
|
|
233
|
+
cc_updated=$(jq \
|
|
234
|
+
--arg id "$cc_id" \
|
|
235
|
+
--arg arg "$cc_argument" \
|
|
236
|
+
'(.deliberations[] | select(.id == $id)).challenger = $arg
|
|
237
|
+
| (.deliberations[] | select(.id == $id)).status = "in_progress"' \
|
|
238
|
+
"$cc_file") || {
|
|
239
|
+
release_lock "$cc_file" 2>/dev/null || true
|
|
240
|
+
trap - EXIT
|
|
241
|
+
json_err "$E_UNKNOWN" "Failed to record challenger argument"
|
|
242
|
+
return
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
atomic_write "$cc_file" "$cc_updated" || {
|
|
246
|
+
release_lock "$cc_file" 2>/dev/null || true
|
|
247
|
+
trap - EXIT
|
|
248
|
+
json_err "$E_UNKNOWN" "Failed to persist challenger argument"
|
|
249
|
+
return
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
release_lock "$cc_file" 2>/dev/null || true
|
|
253
|
+
trap - EXIT
|
|
254
|
+
|
|
255
|
+
json_ok '{"role":"challenger","recorded":true}'
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
# ---------------------------------------------------------------------------
|
|
259
|
+
# _council_sage
|
|
260
|
+
# Usage: council-sage --deliberation-id <id> --synthesis <text> --recommendation <text>
|
|
261
|
+
# ---------------------------------------------------------------------------
|
|
262
|
+
_council_sage() {
|
|
263
|
+
local cs_id=""
|
|
264
|
+
local cs_synthesis=""
|
|
265
|
+
local cs_recommendation=""
|
|
266
|
+
|
|
267
|
+
while [[ $# -gt 0 ]]; do
|
|
268
|
+
case "$1" in
|
|
269
|
+
--deliberation-id) cs_id="${2:-}"; shift 2 ;;
|
|
270
|
+
--synthesis) cs_synthesis="${2:-}"; shift 2 ;;
|
|
271
|
+
--recommendation) cs_recommendation="${2:-}"; shift 2 ;;
|
|
272
|
+
*) shift ;;
|
|
273
|
+
esac
|
|
274
|
+
done
|
|
275
|
+
|
|
276
|
+
if [[ -z "$cs_id" ]]; then
|
|
277
|
+
json_err "$E_VALIDATION_FAILED" "council-sage requires --deliberation-id"
|
|
278
|
+
return
|
|
279
|
+
fi
|
|
280
|
+
|
|
281
|
+
if [[ -z "$cs_synthesis" ]]; then
|
|
282
|
+
json_err "$E_VALIDATION_FAILED" "council-sage requires --synthesis"
|
|
283
|
+
return
|
|
284
|
+
fi
|
|
285
|
+
|
|
286
|
+
if [[ -z "$cs_recommendation" ]]; then
|
|
287
|
+
json_err "$E_VALIDATION_FAILED" "council-sage requires --recommendation"
|
|
288
|
+
return
|
|
289
|
+
fi
|
|
290
|
+
|
|
291
|
+
local cs_file
|
|
292
|
+
cs_file="$(_council_deliberations_file)"
|
|
293
|
+
|
|
294
|
+
if [[ ! -f "$cs_file" ]]; then
|
|
295
|
+
json_err "$E_VALIDATION_FAILED" "No deliberations found; run council-deliberate first"
|
|
296
|
+
return
|
|
297
|
+
fi
|
|
298
|
+
|
|
299
|
+
local cs_exists
|
|
300
|
+
cs_exists=$(jq -r --arg id "$cs_id" '.deliberations[] | select(.id == $id) | .id' "$cs_file" 2>/dev/null || echo "")
|
|
301
|
+
if [[ -z "$cs_exists" ]]; then
|
|
302
|
+
json_err "$E_VALIDATION_FAILED" "Deliberation not found: $cs_id"
|
|
303
|
+
return
|
|
304
|
+
fi
|
|
305
|
+
|
|
306
|
+
acquire_lock "$cs_file" 2>/dev/null || true
|
|
307
|
+
# shellcheck disable=SC2064
|
|
308
|
+
trap "release_lock '$cs_file' 2>/dev/null || true" EXIT
|
|
309
|
+
|
|
310
|
+
local cs_updated
|
|
311
|
+
cs_updated=$(jq \
|
|
312
|
+
--arg id "$cs_id" \
|
|
313
|
+
--arg synthesis "$cs_synthesis" \
|
|
314
|
+
--arg rec "$cs_recommendation" \
|
|
315
|
+
'(.deliberations[] | select(.id == $id)).sage = {"synthesis": $synthesis, "recommendation": $rec}
|
|
316
|
+
| (.deliberations[] | select(.id == $id)).status = "complete"' \
|
|
317
|
+
"$cs_file") || {
|
|
318
|
+
release_lock "$cs_file" 2>/dev/null || true
|
|
319
|
+
trap - EXIT
|
|
320
|
+
json_err "$E_UNKNOWN" "Failed to record sage synthesis"
|
|
321
|
+
return
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
atomic_write "$cs_file" "$cs_updated" || {
|
|
325
|
+
release_lock "$cs_file" 2>/dev/null || true
|
|
326
|
+
trap - EXIT
|
|
327
|
+
json_err "$E_UNKNOWN" "Failed to persist sage synthesis"
|
|
328
|
+
return
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
release_lock "$cs_file" 2>/dev/null || true
|
|
332
|
+
trap - EXIT
|
|
333
|
+
|
|
334
|
+
json_ok "$(jq -n \
|
|
335
|
+
--arg rec "$cs_recommendation" \
|
|
336
|
+
'{"role":"sage","recommendation":$rec,"deliberation_complete":true}')"
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
# ---------------------------------------------------------------------------
|
|
340
|
+
# _council_history
|
|
341
|
+
# Usage: council-history [--limit N]
|
|
342
|
+
# ---------------------------------------------------------------------------
|
|
343
|
+
_council_history() {
|
|
344
|
+
local ch_limit=""
|
|
345
|
+
|
|
346
|
+
while [[ $# -gt 0 ]]; do
|
|
347
|
+
case "$1" in
|
|
348
|
+
--limit) ch_limit="${2:-}"; shift 2 ;;
|
|
349
|
+
*) shift ;;
|
|
350
|
+
esac
|
|
351
|
+
done
|
|
352
|
+
|
|
353
|
+
local ch_file
|
|
354
|
+
ch_file="$(_council_deliberations_file)"
|
|
355
|
+
|
|
356
|
+
if [[ ! -f "$ch_file" ]]; then
|
|
357
|
+
json_ok '{"total":0,"deliberations":[]}'
|
|
358
|
+
return
|
|
359
|
+
fi
|
|
360
|
+
|
|
361
|
+
local ch_total
|
|
362
|
+
ch_total=$(jq '.deliberations | length' "$ch_file" 2>/dev/null || echo 0)
|
|
363
|
+
|
|
364
|
+
if [[ -n "$ch_limit" ]] && [[ "$ch_limit" =~ ^[0-9]+$ ]]; then
|
|
365
|
+
local ch_result
|
|
366
|
+
ch_result=$(jq \
|
|
367
|
+
--argjson limit "$ch_limit" \
|
|
368
|
+
--argjson total "$ch_total" \
|
|
369
|
+
'{"total":$total,"deliberations":(.deliberations | .[-($limit):])}' \
|
|
370
|
+
"$ch_file" 2>/dev/null) || ch_result='{"total":0,"deliberations":[]}'
|
|
371
|
+
json_ok "$ch_result"
|
|
372
|
+
else
|
|
373
|
+
local ch_result
|
|
374
|
+
ch_result=$(jq \
|
|
375
|
+
--argjson total "$ch_total" \
|
|
376
|
+
'{"total":$total,"deliberations":.deliberations}' \
|
|
377
|
+
"$ch_file" 2>/dev/null) || ch_result='{"total":0,"deliberations":[]}'
|
|
378
|
+
json_ok "$ch_result"
|
|
379
|
+
fi
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
# ---------------------------------------------------------------------------
|
|
383
|
+
# _council_budget_check
|
|
384
|
+
# Usage: council-budget-check [--budget N]
|
|
385
|
+
# ---------------------------------------------------------------------------
|
|
386
|
+
_council_budget_check() {
|
|
387
|
+
local cb_budget="3"
|
|
388
|
+
|
|
389
|
+
while [[ $# -gt 0 ]]; do
|
|
390
|
+
case "$1" in
|
|
391
|
+
--budget) cb_budget="${2:-3}"; shift 2 ;;
|
|
392
|
+
*) shift ;;
|
|
393
|
+
esac
|
|
394
|
+
done
|
|
395
|
+
|
|
396
|
+
if ! [[ "$cb_budget" =~ ^[0-9]+$ ]]; then
|
|
397
|
+
json_err "$E_VALIDATION_FAILED" "council-budget-check --budget must be a positive integer"
|
|
398
|
+
return
|
|
399
|
+
fi
|
|
400
|
+
|
|
401
|
+
# Delegate to spawn-can-spawn at depth 1
|
|
402
|
+
local cb_spawn_result
|
|
403
|
+
cb_spawn_result=$(_spawn_can_spawn 1 2>/dev/null || echo '{"can_spawn":false,"current_total":0,"global_cap":10}')
|
|
404
|
+
|
|
405
|
+
local cb_can
|
|
406
|
+
cb_can=$(echo "$cb_spawn_result" | jq -r '.result.can_spawn // .can_spawn // false' 2>/dev/null || echo "false")
|
|
407
|
+
local cb_current
|
|
408
|
+
cb_current=$(echo "$cb_spawn_result" | jq -r '.result.current_total // .current_total // 0' 2>/dev/null || echo 0)
|
|
409
|
+
local cb_cap
|
|
410
|
+
cb_cap=$(echo "$cb_spawn_result" | jq -r '.result.global_cap // .global_cap // 10' 2>/dev/null || echo 10)
|
|
411
|
+
local cb_remaining=$(( cb_cap - cb_current ))
|
|
412
|
+
[[ $cb_remaining -lt 0 ]] && cb_remaining=0
|
|
413
|
+
|
|
414
|
+
# allowed is true only if spawn is allowed AND remaining >= requested budget
|
|
415
|
+
local cb_allowed="false"
|
|
416
|
+
if [[ "$cb_can" == "true" ]] && [[ $cb_remaining -ge $cb_budget ]]; then
|
|
417
|
+
cb_allowed="true"
|
|
418
|
+
fi
|
|
419
|
+
|
|
420
|
+
json_ok "$(jq -n \
|
|
421
|
+
--argjson allowed "$cb_allowed" \
|
|
422
|
+
--argjson remaining "$cb_remaining" \
|
|
423
|
+
--argjson budget "$cb_budget" \
|
|
424
|
+
'{"allowed":$allowed,"remaining":$remaining,"budget":$budget}')"
|
|
425
|
+
}
|
|
@@ -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
|
|
@@ -87,8 +87,8 @@ json_err() {
|
|
|
87
87
|
"$code" "$escaped_message" "$details_json" "$recovery" "$timestamp" >&2
|
|
88
88
|
|
|
89
89
|
# Log to activity.log (best effort)
|
|
90
|
-
if [[ -n "${
|
|
91
|
-
echo "[$timestamp] ERROR $code: $escaped_message" >> "$
|
|
90
|
+
if [[ -n "${COLONY_DATA_DIR:-}" ]] && [[ "${AETHER_TESTING:-}" != "1" ]]; then
|
|
91
|
+
echo "[$timestamp] ERROR $code: $escaped_message" >> "$COLONY_DATA_DIR/activity.log" 2>/dev/null || true
|
|
92
92
|
fi
|
|
93
93
|
|
|
94
94
|
exit 1
|
|
@@ -111,8 +111,22 @@ json_warn() {
|
|
|
111
111
|
"$code" "$escaped_message" "$timestamp"
|
|
112
112
|
|
|
113
113
|
# Log to activity.log (best effort)
|
|
114
|
-
if [[ -n "${
|
|
115
|
-
echo "[$timestamp] WARN $code: $escaped_message" >> "$
|
|
114
|
+
if [[ -n "${COLONY_DATA_DIR:-}" ]] && [[ "${AETHER_TESTING:-}" != "1" ]]; then
|
|
115
|
+
echo "[$timestamp] WARN $code: $escaped_message" >> "$COLONY_DATA_DIR/activity.log" 2>/dev/null || true
|
|
116
|
+
fi
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
# --- _aether_log_error function for surfaced errors ---
|
|
120
|
+
# Dual output: [error] prefix to stderr (screen) + timestamped entry to errors.log (file)
|
|
121
|
+
# Distinct from: json_err (structured JSON), json_warn (non-fatal JSON), ⚠ (recovery), [trimmed] (budget)
|
|
122
|
+
_aether_log_error() {
|
|
123
|
+
local message="$1"
|
|
124
|
+
local timestamp
|
|
125
|
+
timestamp=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
|
|
126
|
+
echo "[error] $message" >&2
|
|
127
|
+
if [[ -n "${COLONY_DATA_DIR:-}" ]]; then
|
|
128
|
+
mkdir -p "$DATA_DIR" 2>/dev/null # SUPPRESS:OK -- idempotent: ensure dir exists
|
|
129
|
+
echo "[$timestamp] $message" >> "$COLONY_DATA_DIR/errors.log" 2>/dev/null # SUPPRESS:OK -- cleanup: log write is best-effort
|
|
116
130
|
fi
|
|
117
131
|
}
|
|
118
132
|
|
|
@@ -139,8 +153,8 @@ error_handler() {
|
|
|
139
153
|
"$E_BASH_ERROR" "$details" "$(_recovery_default)" "$timestamp" >&2
|
|
140
154
|
|
|
141
155
|
# Log to activity.log (best effort)
|
|
142
|
-
if [[ -n "${
|
|
143
|
-
echo "[$timestamp] ERROR $E_BASH_ERROR: Command failed at line $line_num (exit $exit_code)" >> "$
|
|
156
|
+
if [[ -n "${COLONY_DATA_DIR:-}" ]] && [[ "${AETHER_TESTING:-}" != "1" ]]; then
|
|
157
|
+
echo "[$timestamp] ERROR $E_BASH_ERROR: Command failed at line $line_num (exit $exit_code)" >> "$COLONY_DATA_DIR/activity.log" 2>/dev/null || true
|
|
144
158
|
fi
|
|
145
159
|
|
|
146
160
|
exit 1
|
|
@@ -198,7 +212,7 @@ feature_log_degradation() {
|
|
|
198
212
|
}
|
|
199
213
|
|
|
200
214
|
# --- Export all functions and variables ---
|
|
201
|
-
export -f json_err json_warn error_handler
|
|
215
|
+
export -f json_err json_warn _aether_log_error error_handler
|
|
202
216
|
export -f feature_enable feature_disable feature_enabled feature_log_degradation
|
|
203
217
|
export -f _get_recovery _recovery_hub_not_found _recovery_repo_not_init
|
|
204
218
|
export -f _recovery_file_not_found _recovery_json_invalid _recovery_lock_failed
|