aether-colony 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (207) hide show
  1. package/.aether/CONTEXT.md +160 -0
  2. package/.aether/QUEEN.md +84 -0
  3. package/.aether/aether-utils.sh +7749 -0
  4. package/.aether/docs/QUEEN-SYSTEM.md +211 -0
  5. package/.aether/docs/README.md +68 -0
  6. package/.aether/docs/caste-system.md +48 -0
  7. package/.aether/docs/disciplines/DISCIPLINES.md +93 -0
  8. package/.aether/docs/disciplines/coding-standards.md +197 -0
  9. package/.aether/docs/disciplines/debugging.md +207 -0
  10. package/.aether/docs/disciplines/learning.md +254 -0
  11. package/.aether/docs/disciplines/tdd.md +257 -0
  12. package/.aether/docs/disciplines/verification-loop.md +167 -0
  13. package/.aether/docs/disciplines/verification.md +116 -0
  14. package/.aether/docs/error-codes.md +268 -0
  15. package/.aether/docs/known-issues.md +233 -0
  16. package/.aether/docs/pheromones.md +205 -0
  17. package/.aether/docs/queen-commands.md +97 -0
  18. package/.aether/exchange/colony-registry.xml +11 -0
  19. package/.aether/exchange/pheromone-xml.sh +575 -0
  20. package/.aether/exchange/pheromones.xml +87 -0
  21. package/.aether/exchange/queen-wisdom.xml +14 -0
  22. package/.aether/exchange/registry-xml.sh +273 -0
  23. package/.aether/exchange/wisdom-xml.sh +319 -0
  24. package/.aether/midden/approach-changes.md +5 -0
  25. package/.aether/midden/build-failures.md +5 -0
  26. package/.aether/midden/test-failures.md +5 -0
  27. package/.aether/model-profiles.yaml +100 -0
  28. package/.aether/rules/aether-colony.md +134 -0
  29. package/.aether/schemas/aether-types.xsd +255 -0
  30. package/.aether/schemas/colony-registry.xsd +309 -0
  31. package/.aether/schemas/example-prompt-builder.xml +234 -0
  32. package/.aether/schemas/pheromone.xsd +163 -0
  33. package/.aether/schemas/prompt.xsd +416 -0
  34. package/.aether/schemas/queen-wisdom.xsd +325 -0
  35. package/.aether/schemas/worker-priming.xsd +276 -0
  36. package/.aether/templates/QUEEN.md.template +79 -0
  37. package/.aether/templates/colony-state-reset.jq.template +22 -0
  38. package/.aether/templates/colony-state.template.json +35 -0
  39. package/.aether/templates/constraints.template.json +9 -0
  40. package/.aether/templates/crowned-anthill.template.md +36 -0
  41. package/.aether/templates/handoff-build-error.template.md +30 -0
  42. package/.aether/templates/handoff-build-success.template.md +39 -0
  43. package/.aether/templates/handoff.template.md +40 -0
  44. package/.aether/templates/learning-observations.template.json +6 -0
  45. package/.aether/templates/midden.template.json +7 -0
  46. package/.aether/templates/pheromones.template.json +6 -0
  47. package/.aether/templates/session.template.json +9 -0
  48. package/.aether/utils/atomic-write.sh +219 -0
  49. package/.aether/utils/chamber-compare.sh +193 -0
  50. package/.aether/utils/chamber-utils.sh +297 -0
  51. package/.aether/utils/colorize-log.sh +132 -0
  52. package/.aether/utils/error-handler.sh +212 -0
  53. package/.aether/utils/file-lock.sh +158 -0
  54. package/.aether/utils/queen-to-md.xsl +395 -0
  55. package/.aether/utils/semantic-cli.sh +413 -0
  56. package/.aether/utils/spawn-tree.sh +428 -0
  57. package/.aether/utils/spawn-with-model.sh +56 -0
  58. package/.aether/utils/state-loader.sh +215 -0
  59. package/.aether/utils/swarm-display.sh +268 -0
  60. package/.aether/utils/watch-spawn-tree.sh +253 -0
  61. package/.aether/utils/xml-compose.sh +253 -0
  62. package/.aether/utils/xml-convert.sh +273 -0
  63. package/.aether/utils/xml-core.sh +186 -0
  64. package/.aether/utils/xml-query.sh +201 -0
  65. package/.aether/utils/xml-utils.sh +110 -0
  66. package/.aether/workers.md +765 -0
  67. package/.claude/agents/ant/aether-ambassador.md +264 -0
  68. package/.claude/agents/ant/aether-archaeologist.md +322 -0
  69. package/.claude/agents/ant/aether-auditor.md +266 -0
  70. package/.claude/agents/ant/aether-builder.md +187 -0
  71. package/.claude/agents/ant/aether-chaos.md +268 -0
  72. package/.claude/agents/ant/aether-chronicler.md +304 -0
  73. package/.claude/agents/ant/aether-gatekeeper.md +325 -0
  74. package/.claude/agents/ant/aether-includer.md +373 -0
  75. package/.claude/agents/ant/aether-keeper.md +271 -0
  76. package/.claude/agents/ant/aether-measurer.md +317 -0
  77. package/.claude/agents/ant/aether-probe.md +210 -0
  78. package/.claude/agents/ant/aether-queen.md +325 -0
  79. package/.claude/agents/ant/aether-route-setter.md +173 -0
  80. package/.claude/agents/ant/aether-sage.md +353 -0
  81. package/.claude/agents/ant/aether-scout.md +142 -0
  82. package/.claude/agents/ant/aether-surveyor-disciplines.md +416 -0
  83. package/.claude/agents/ant/aether-surveyor-nest.md +354 -0
  84. package/.claude/agents/ant/aether-surveyor-pathogens.md +288 -0
  85. package/.claude/agents/ant/aether-surveyor-provisions.md +359 -0
  86. package/.claude/agents/ant/aether-tracker.md +265 -0
  87. package/.claude/agents/ant/aether-watcher.md +244 -0
  88. package/.claude/agents/ant/aether-weaver.md +247 -0
  89. package/.claude/commands/ant/archaeology.md +341 -0
  90. package/.claude/commands/ant/build.md +1160 -0
  91. package/.claude/commands/ant/chaos.md +349 -0
  92. package/.claude/commands/ant/colonize.md +270 -0
  93. package/.claude/commands/ant/continue.md +1070 -0
  94. package/.claude/commands/ant/council.md +309 -0
  95. package/.claude/commands/ant/dream.md +265 -0
  96. package/.claude/commands/ant/entomb.md +487 -0
  97. package/.claude/commands/ant/feedback.md +78 -0
  98. package/.claude/commands/ant/flag.md +139 -0
  99. package/.claude/commands/ant/flags.md +155 -0
  100. package/.claude/commands/ant/focus.md +58 -0
  101. package/.claude/commands/ant/help.md +122 -0
  102. package/.claude/commands/ant/history.md +137 -0
  103. package/.claude/commands/ant/init.md +409 -0
  104. package/.claude/commands/ant/interpret.md +267 -0
  105. package/.claude/commands/ant/lay-eggs.md +201 -0
  106. package/.claude/commands/ant/maturity.md +102 -0
  107. package/.claude/commands/ant/memory-details.md +77 -0
  108. package/.claude/commands/ant/migrate-state.md +165 -0
  109. package/.claude/commands/ant/oracle.md +387 -0
  110. package/.claude/commands/ant/organize.md +227 -0
  111. package/.claude/commands/ant/pause-colony.md +247 -0
  112. package/.claude/commands/ant/phase.md +126 -0
  113. package/.claude/commands/ant/plan.md +544 -0
  114. package/.claude/commands/ant/redirect.md +58 -0
  115. package/.claude/commands/ant/resume-colony.md +182 -0
  116. package/.claude/commands/ant/resume.md +363 -0
  117. package/.claude/commands/ant/seal.md +306 -0
  118. package/.claude/commands/ant/status.md +272 -0
  119. package/.claude/commands/ant/swarm.md +361 -0
  120. package/.claude/commands/ant/tunnels.md +425 -0
  121. package/.claude/commands/ant/update.md +209 -0
  122. package/.claude/commands/ant/verify-castes.md +95 -0
  123. package/.claude/commands/ant/watch.md +238 -0
  124. package/.opencode/agents/aether-ambassador.md +140 -0
  125. package/.opencode/agents/aether-archaeologist.md +108 -0
  126. package/.opencode/agents/aether-auditor.md +144 -0
  127. package/.opencode/agents/aether-builder.md +184 -0
  128. package/.opencode/agents/aether-chaos.md +115 -0
  129. package/.opencode/agents/aether-chronicler.md +122 -0
  130. package/.opencode/agents/aether-gatekeeper.md +116 -0
  131. package/.opencode/agents/aether-includer.md +117 -0
  132. package/.opencode/agents/aether-keeper.md +177 -0
  133. package/.opencode/agents/aether-measurer.md +128 -0
  134. package/.opencode/agents/aether-probe.md +133 -0
  135. package/.opencode/agents/aether-queen.md +286 -0
  136. package/.opencode/agents/aether-route-setter.md +130 -0
  137. package/.opencode/agents/aether-sage.md +106 -0
  138. package/.opencode/agents/aether-scout.md +101 -0
  139. package/.opencode/agents/aether-surveyor-disciplines.md +386 -0
  140. package/.opencode/agents/aether-surveyor-nest.md +324 -0
  141. package/.opencode/agents/aether-surveyor-pathogens.md +259 -0
  142. package/.opencode/agents/aether-surveyor-provisions.md +329 -0
  143. package/.opencode/agents/aether-tracker.md +137 -0
  144. package/.opencode/agents/aether-watcher.md +174 -0
  145. package/.opencode/agents/aether-weaver.md +130 -0
  146. package/.opencode/commands/ant/archaeology.md +338 -0
  147. package/.opencode/commands/ant/build.md +1200 -0
  148. package/.opencode/commands/ant/chaos.md +346 -0
  149. package/.opencode/commands/ant/colonize.md +202 -0
  150. package/.opencode/commands/ant/continue.md +938 -0
  151. package/.opencode/commands/ant/council.md +305 -0
  152. package/.opencode/commands/ant/dream.md +262 -0
  153. package/.opencode/commands/ant/entomb.md +367 -0
  154. package/.opencode/commands/ant/feedback.md +80 -0
  155. package/.opencode/commands/ant/flag.md +137 -0
  156. package/.opencode/commands/ant/flags.md +153 -0
  157. package/.opencode/commands/ant/focus.md +56 -0
  158. package/.opencode/commands/ant/help.md +124 -0
  159. package/.opencode/commands/ant/history.md +127 -0
  160. package/.opencode/commands/ant/init.md +337 -0
  161. package/.opencode/commands/ant/interpret.md +256 -0
  162. package/.opencode/commands/ant/lay-eggs.md +141 -0
  163. package/.opencode/commands/ant/maturity.md +92 -0
  164. package/.opencode/commands/ant/memory-details.md +77 -0
  165. package/.opencode/commands/ant/migrate-state.md +153 -0
  166. package/.opencode/commands/ant/oracle.md +338 -0
  167. package/.opencode/commands/ant/organize.md +224 -0
  168. package/.opencode/commands/ant/pause-colony.md +220 -0
  169. package/.opencode/commands/ant/phase.md +123 -0
  170. package/.opencode/commands/ant/plan.md +531 -0
  171. package/.opencode/commands/ant/redirect.md +67 -0
  172. package/.opencode/commands/ant/resume-colony.md +178 -0
  173. package/.opencode/commands/ant/resume.md +363 -0
  174. package/.opencode/commands/ant/seal.md +247 -0
  175. package/.opencode/commands/ant/status.md +272 -0
  176. package/.opencode/commands/ant/swarm.md +357 -0
  177. package/.opencode/commands/ant/tunnels.md +406 -0
  178. package/.opencode/commands/ant/update.md +191 -0
  179. package/.opencode/commands/ant/verify-castes.md +85 -0
  180. package/.opencode/commands/ant/watch.md +220 -0
  181. package/.opencode/opencode.json +3 -0
  182. package/CHANGELOG.md +325 -0
  183. package/DISCLAIMER.md +74 -0
  184. package/LICENSE +21 -0
  185. package/README.md +258 -0
  186. package/bin/cli.js +2436 -0
  187. package/bin/generate-commands.sh +291 -0
  188. package/bin/lib/caste-colors.js +57 -0
  189. package/bin/lib/colors.js +76 -0
  190. package/bin/lib/errors.js +255 -0
  191. package/bin/lib/event-types.js +190 -0
  192. package/bin/lib/file-lock.js +695 -0
  193. package/bin/lib/init.js +454 -0
  194. package/bin/lib/logger.js +242 -0
  195. package/bin/lib/model-profiles.js +445 -0
  196. package/bin/lib/model-verify.js +288 -0
  197. package/bin/lib/nestmate-loader.js +130 -0
  198. package/bin/lib/proxy-health.js +253 -0
  199. package/bin/lib/spawn-logger.js +266 -0
  200. package/bin/lib/state-guard.js +602 -0
  201. package/bin/lib/state-sync.js +516 -0
  202. package/bin/lib/telemetry.js +441 -0
  203. package/bin/lib/update-transaction.js +1454 -0
  204. package/bin/npx-install.js +178 -0
  205. package/bin/sync-to-runtime.sh +6 -0
  206. package/bin/validate-package.sh +88 -0
  207. package/package.json +70 -0
@@ -0,0 +1,186 @@
1
+ #!/bin/bash
2
+ # XML Core Utilities
3
+ # Fundamental XML operations: validation, formatting, escaping
4
+ #
5
+ # Usage: source .aether/utils/xml-core.sh
6
+ # xml-validate <xml_file> <xsd_file>
7
+ # xml-well-formed <xml_file>
8
+ # xml-format <xml_file>
9
+ # xml-escape <text>
10
+ # xml-unescape <text>
11
+
12
+ # ============================================================================
13
+ # Feature Detection
14
+ # ============================================================================
15
+
16
+ # Check for required XML tools (only if not already set)
17
+ if [[ -z "${XMLLINT_AVAILABLE:-}" ]]; then
18
+ XMLLINT_AVAILABLE=false
19
+ if command -v xmllint >/dev/null 2>&1; then
20
+ XMLLINT_AVAILABLE=true
21
+ fi
22
+ fi
23
+
24
+ if [[ -z "${XMLSTARLET_AVAILABLE:-}" ]]; then
25
+ XMLSTARLET_AVAILABLE=false
26
+ if command -v xmlstarlet >/dev/null 2>&1; then
27
+ XMLSTARLET_AVAILABLE=true
28
+ fi
29
+ fi
30
+
31
+ if [[ -z "${XSLTPROC_AVAILABLE:-}" ]]; then
32
+ XSLTPROC_AVAILABLE=false
33
+ if command -v xsltproc >/dev/null 2>&1; then
34
+ XSLTPROC_AVAILABLE=true
35
+ fi
36
+ fi
37
+
38
+ # ============================================================================
39
+ # JSON Output Helpers
40
+ # ============================================================================
41
+
42
+ xml_json_ok() { printf '{"ok":true,"result":%s}\n' "$1"; }
43
+
44
+ xml_json_err() {
45
+ local code="${1:-UNKNOWN_ERROR}"
46
+ local message="${2:-$1}"
47
+ local details="${3:-}"
48
+ if [[ -n "$details" ]]; then
49
+ printf '{"ok":false,"error":"%s","code":"%s","details":"%s"}\n' "$message" "$code" "$details" >&2
50
+ else
51
+ printf '{"ok":false,"error":"%s","code":"%s"}\n' "$message" "$code" >&2
52
+ fi
53
+ return 1
54
+ }
55
+
56
+ # ============================================================================
57
+ # Core XML Functions
58
+ # ============================================================================
59
+
60
+ # xml-detect-tools: Detect available XML tools
61
+ # Usage: xml-detect-tools
62
+ # Returns: {"ok":true,"result":{"xmllint":true,"xmlstarlet":false,...}}
63
+ xml-detect-tools() {
64
+ xml_json_ok "{\"xmllint\":$XMLLINT_AVAILABLE,\"xmlstarlet\":$XMLSTARLET_AVAILABLE,\"xsltproc\":$XSLTPROC_AVAILABLE}"
65
+ }
66
+
67
+ # xml-validate: Validate XML against XSD schema using xmllint
68
+ # Usage: xml-validate <xml_file> <xsd_file>
69
+ # Returns: {"ok":true,"result":{"valid":true,"errors":[]}} or error
70
+ xml-validate() {
71
+ local xml_file="${1:-}"
72
+ local xsd_file="${2:-}"
73
+
74
+ # Validate arguments
75
+ [[ -z "$xml_file" ]] && { xml_json_err "MISSING_ARG" "Missing XML file argument"; return 1; }
76
+ [[ -z "$xsd_file" ]] && { xml_json_err "MISSING_ARG" "Missing XSD schema file argument"; return 1; }
77
+ [[ -f "$xml_file" ]] || { xml_json_err "FILE_NOT_FOUND" "XML file not found: $xml_file"; return 1; }
78
+ [[ -f "$xsd_file" ]] || { xml_json_err "FILE_NOT_FOUND" "XSD schema file not found: $xsd_file"; return 1; }
79
+
80
+ # Check for xmllint
81
+ if [[ "$XMLLINT_AVAILABLE" != "true" ]]; then
82
+ xml_json_err "TOOL_NOT_AVAILABLE" "xmllint not available. Install libxml2 utilities."
83
+ return 1
84
+ fi
85
+
86
+ # Validate XML against XSD (with XXE protection)
87
+ local errors
88
+ errors=$(xmllint --nonet --noent --noout --schema "$xsd_file" "$xml_file" 2>&1) && {
89
+ xml_json_ok '{"valid":true,"errors":[]}'
90
+ return 0
91
+ } || {
92
+ # Escape errors for JSON
93
+ local escaped_errors
94
+ escaped_errors=$(echo "$errors" | sed 's/\\/\\\\/g; s/"/\\"/g; s/\t/\\t/g' | tr '\n' ' ')
95
+ xml_json_ok "{\"valid\":false,\"errors\":[\"$escaped_errors\"]}"
96
+ return 0
97
+ }
98
+ }
99
+
100
+ # xml-well-formed: Check if XML is well-formed (no schema validation)
101
+ # Usage: xml-well-formed <xml_file>
102
+ # Returns: {"ok":true,"result":{"well_formed":true}} or error
103
+ xml-well-formed() {
104
+ local xml_file="${1:-}"
105
+
106
+ [[ -z "$xml_file" ]] && { xml_json_err "MISSING_ARG" "Missing XML file argument"; return 1; }
107
+ [[ -f "$xml_file" ]] || { xml_json_err "FILE_NOT_FOUND" "XML file not found: $xml_file"; return 1; }
108
+
109
+ if [[ "$XMLLINT_AVAILABLE" != "true" ]]; then
110
+ xml_json_err "TOOL_NOT_AVAILABLE" "xmllint not available. Install libxml2 utilities."
111
+ return 1
112
+ fi
113
+
114
+ # Check well-formedness with XXE protection
115
+ if xmllint --nonet --noent --noout "$xml_file" 2>/dev/null; then
116
+ xml_json_ok '{"well_formed":true}'
117
+ return 0
118
+ else
119
+ xml_json_ok '{"well_formed":false}'
120
+ return 0
121
+ fi
122
+ }
123
+
124
+ # xml-format: Pretty-print XML with proper indentation
125
+ # Usage: xml-format <xml_file> [output_file]
126
+ # Returns: {"ok":true,"result":{"formatted":true,"output":"..."}} or writes to file
127
+ xml-format() {
128
+ local xml_file="${1:-}"
129
+ local output_file="${2:-}"
130
+
131
+ [[ -z "$xml_file" ]] && { xml_json_err "MISSING_ARG" "Missing XML file argument"; return 1; }
132
+ [[ -f "$xml_file" ]] || { xml_json_err "FILE_NOT_FOUND" "XML file not found: $xml_file"; return 1; }
133
+
134
+ if [[ "$XMLLINT_AVAILABLE" != "true" ]]; then
135
+ xml_json_err "TOOL_NOT_AVAILABLE" "xmllint not available. Install libxml2 utilities."
136
+ return 1
137
+ fi
138
+
139
+ local formatted
140
+ formatted=$(xmllint --nonet --noent --format "$xml_file" 2>/dev/null) || {
141
+ xml_json_err "PARSE_ERROR" "Failed to parse XML file"
142
+ return 1
143
+ }
144
+
145
+ if [[ -n "$output_file" ]]; then
146
+ echo "$formatted" > "$output_file"
147
+ xml_json_ok "{\"formatted\":true,\"path\":\"$output_file\"}"
148
+ else
149
+ # Escape for JSON
150
+ local escaped
151
+ escaped=$(echo "$formatted" | sed 's/\\/\\\\/g; s/"/\\"/g' | tr '\n' ' ')
152
+ xml_json_ok "{\"formatted\":true,\"output\":\"$escaped\"}"
153
+ fi
154
+ }
155
+
156
+ # xml-escape: Escape special XML characters
157
+ # Usage: xml-escape <text>
158
+ # Returns: Escaped text (not JSON - direct output)
159
+ xml-escape() {
160
+ local text="${1:-}"
161
+ # Escape &, <, >, ", '
162
+ echo "$text" | sed 's/&/\&amp;/g; s/</\&lt;/g; s/>/\&gt;/g; s/"/\&quot;/g; s/'"'"'/\&apos;/g'
163
+ }
164
+
165
+ # xml-unescape: Unescape XML entities
166
+ # Usage: xml-unescape <text>
167
+ # Returns: Unescaped text (not JSON - direct output)
168
+ xml-unescape() {
169
+ local text="${1:-}"
170
+ # Unescape XML entities
171
+ echo "$text" | sed 's/&amp;/\&/g; s/&lt;/</g; s/&gt;/>/g; s/&quot;/"/g; s/&apos;/'"'"'/g'
172
+ }
173
+
174
+ # xml-escape-content: Escape content for XML CDATA or text nodes
175
+ # Internal helper for consistent escaping
176
+ _xml_escape_content() {
177
+ local content="${1:-}"
178
+ # Basic XML escaping for text content
179
+ echo "$content" | sed 's/&/\&amp;/g; s/</\&lt;/g; s/>/\&gt;/g'
180
+ }
181
+
182
+ # Export functions for use by other modules
183
+ export -f xml_json_ok xml_json_err
184
+ export -f xml-detect-tools xml-validate xml-well-formed xml-format
185
+ export -f xml-escape xml-unescape _xml_escape_content
186
+ export XMLLINT_AVAILABLE XMLSTARLET_AVAILABLE XSLTPROC_AVAILABLE
@@ -0,0 +1,201 @@
1
+ #!/bin/bash
2
+ # XML Query Utilities
3
+ # XPath queries with xmlstarlet and xmllint fallback
4
+ #
5
+ # Usage: source .aether/utils/xml-query.sh
6
+ # xml-query <xml_file> <xpath_expression>
7
+ # xml-query-attr <xml_file> <xpath_expression>
8
+ # xml-query-text <xml_file> <element_name>
9
+ # xml-query-count <xml_file> <xpath_expression>
10
+
11
+ set -euo pipefail
12
+
13
+ # Source xml-core.sh for JSON helpers and tool detection
14
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
15
+ source "$SCRIPT_DIR/xml-core.sh"
16
+
17
+ # ============================================================================
18
+ # XPath Query Functions
19
+ # ============================================================================
20
+
21
+ # xml-query: Execute XPath query against XML file
22
+ # Usage: xml-query <xml_file> <xpath_expression>
23
+ # Returns: {"ok":true,"result":{"matches":["value1","value2",...]}}
24
+ xml-query() {
25
+ local xml_file="${1:-}"
26
+ local xpath="${2:-}"
27
+
28
+ [[ -z "$xml_file" ]] && { xml_json_err "MISSING_ARG" "Missing XML file argument"; return 1; }
29
+ [[ -z "$xpath" ]] && { xml_json_err "MISSING_ARG" "Missing XPath expression"; return 1; }
30
+ [[ -f "$xml_file" ]] || { xml_json_err "FILE_NOT_FOUND" "XML file not found: $xml_file"; return 1; }
31
+
32
+ local results=""
33
+
34
+ # Prefer xmlstarlet for full XPath support
35
+ if [[ "$XMLSTARLET_AVAILABLE" == "true" ]]; then
36
+ results=$(xmlstarlet sel -t -v "$xpath" "$xml_file" 2>/dev/null | tr '\n' '|')
37
+ # Remove trailing pipe
38
+ results="${results%|}"
39
+ elif [[ "$XMLLINT_AVAILABLE" == "true" ]]; then
40
+ # xmllint has limited XPath but works for basic queries
41
+ # Note: xmllint --xpath returns the text content of matched nodes
42
+ results=$(xmllint --nonet --noent --xpath "$xpath" "$xml_file" 2>/dev/null | \
43
+ sed 's/<[^>]*>//g' | tr '\n' '|' | sed 's/|$//')
44
+ else
45
+ xml_json_err "TOOL_NOT_AVAILABLE" "No XPath-capable tool available (install xmlstarlet or libxml2)"
46
+ return 1
47
+ fi
48
+
49
+ # Build JSON array from pipe-separated results
50
+ if [[ -n "$results" ]]; then
51
+ local json_array="["
52
+ local first=true
53
+ IFS='|' read -ra matches <<< "$results"
54
+ for match in "${matches[@]}"; do
55
+ # Trim whitespace and escape for JSON
56
+ match=$(echo "$match" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
57
+ match=$(echo "$match" | sed 's/\\/\\\\/g; s/"/\\"/g')
58
+ if [[ "$first" == "true" ]]; then
59
+ first=false
60
+ json_array="$json_array\"$match\""
61
+ else
62
+ json_array="$json_array,\"$match\""
63
+ fi
64
+ done
65
+ json_array="$json_array]"
66
+ xml_json_ok "{\"matches\":$json_array}"
67
+ else
68
+ xml_json_ok '{"matches":[]}'
69
+ fi
70
+ }
71
+
72
+ # xml-query-attr: Extract attribute values using XPath
73
+ # Usage: xml-query-attr <xml_file> <element_xpath> <attribute_name>
74
+ # Returns: {"ok":true,"result":{"attribute":"name","values":["val1","val2"]}}
75
+ xml-query-attr() {
76
+ local xml_file="${1:-}"
77
+ local element_xpath="${2:-}"
78
+ local attr_name="${3:-}"
79
+
80
+ [[ -z "$xml_file" ]] && { xml_json_err "MISSING_ARG" "Missing XML file argument"; return 1; }
81
+ [[ -z "$element_xpath" ]] && { xml_json_err "MISSING_ARG" "Missing element XPath"; return 1; }
82
+ [[ -z "$attr_name" ]] && { xml_json_err "MISSING_ARG" "Missing attribute name"; return 1; }
83
+ [[ -f "$xml_file" ]] || { xml_json_err "FILE_NOT_FOUND" "XML file not found: $xml_file"; return 1; }
84
+
85
+ local full_xpath="${element_xpath}/@${attr_name}"
86
+ local results=""
87
+
88
+ if [[ "$XMLSTARLET_AVAILABLE" == "true" ]]; then
89
+ results=$(xmlstarlet sel -t -v "$full_xpath" "$xml_file" 2>/dev/null | tr '\n' '|')
90
+ results="${results%|}"
91
+ elif [[ "$XMLLINT_AVAILABLE" == "true" ]]; then
92
+ # xmllint can extract attributes with //@attrname syntax
93
+ results=$(xmllint --nonet --noent --xpath "$full_xpath" "$xml_file" 2>/dev/null | tr '\n' '|')
94
+ results="${results%|}"
95
+ else
96
+ xml_json_err "TOOL_NOT_AVAILABLE" "No XPath-capable tool available"
97
+ return 1
98
+ fi
99
+
100
+ # Build JSON array
101
+ if [[ -n "$results" ]]; then
102
+ local json_array="["
103
+ local first=true
104
+ IFS='|' read -ra values <<< "$results"
105
+ for val in "${values[@]}"; do
106
+ val=$(echo "$val" | sed 's/\\/\\\\/g; s/"/\\"/g')
107
+ if [[ "$first" == "true" ]]; then
108
+ first=false
109
+ json_array="$json_array\"$val\""
110
+ else
111
+ json_array="$json_array,\"$val\""
112
+ fi
113
+ done
114
+ json_array="$json_array]"
115
+ xml_json_ok "{\"attribute\":\"$attr_name\",\"values\":$json_array}"
116
+ else
117
+ xml_json_ok "{\"attribute\":\"$attr_name\",\"values\":[]}"
118
+ fi
119
+ }
120
+
121
+ # xml-query-text: Extract text content of elements
122
+ # Usage: xml-query-text <xml_file> <element_name>
123
+ # Returns: {"ok":true,"result":{"element":"name","text":["text1","text2"]}}
124
+ xml-query-text() {
125
+ local xml_file="${1:-}"
126
+ local element_name="${2:-}"
127
+
128
+ [[ -z "$xml_file" ]] && { xml_json_err "MISSING_ARG" "Missing XML file argument"; return 1; }
129
+ [[ -z "$element_name" ]] && { xml_json_err "MISSING_ARG" "Missing element name"; return 1; }
130
+ [[ -f "$xml_file" ]] || { xml_json_err "FILE_NOT_FOUND" "XML file not found: $xml_file"; return 1; }
131
+
132
+ local xpath="//$element_name"
133
+ local results=""
134
+
135
+ if [[ "$XMLSTARLET_AVAILABLE" == "true" ]]; then
136
+ # Use -m to match nodes and extract text
137
+ results=$(xmlstarlet sel -t -m "$xpath" -v "." -n "$xml_file" 2>/dev/null | tr '\n' '|')
138
+ results="${results%|}"
139
+ elif [[ "$XMLLINT_AVAILABLE" == "true" ]]; then
140
+ # xmllint --xpath returns text content directly for simple paths
141
+ results=$(xmllint --nonet --noent --xpath "$xpath" "$xml_file" 2>/dev/null | \
142
+ sed 's/<[^>]*>//g' | tr '\n' '|' | sed 's/|$//')
143
+ else
144
+ xml_json_err "TOOL_NOT_AVAILABLE" "No XPath-capable tool available"
145
+ return 1
146
+ fi
147
+
148
+ if [[ -n "$results" ]]; then
149
+ local json_array="["
150
+ local first=true
151
+ IFS='|' read -ra texts <<< "$results"
152
+ for text in "${texts[@]}"; do
153
+ text=$(echo "$text" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
154
+ text=$(echo "$text" | sed 's/\\/\\\\/g; s/"/\\"/g')
155
+ if [[ "$first" == "true" ]]; then
156
+ first=false
157
+ json_array="$json_array\"$text\""
158
+ else
159
+ json_array="$json_array,\"$text\""
160
+ fi
161
+ done
162
+ json_array="$json_array]"
163
+ xml_json_ok "{\"element\":\"$element_name\",\"text\":$json_array}"
164
+ else
165
+ xml_json_ok "{\"element\":\"$element_name\",\"text\":[]}"
166
+ fi
167
+ }
168
+
169
+ # xml-query-count: Count nodes matching XPath expression
170
+ # Usage: xml-query-count <xml_file> <xpath_expression>
171
+ # Returns: {"ok":true,"result":{"count":5}}
172
+ xml-query-count() {
173
+ local xml_file="${1:-}"
174
+ local xpath="${2:-}"
175
+
176
+ [[ -z "$xml_file" ]] && { xml_json_err "MISSING_ARG" "Missing XML file argument"; return 1; }
177
+ [[ -z "$xpath" ]] && { xml_json_err "MISSING_ARG" "Missing XPath expression"; return 1; }
178
+ [[ -f "$xml_file" ]] || { xml_json_err "FILE_NOT_FOUND" "XML file not found: $xml_file"; return 1; }
179
+
180
+ local count=0
181
+
182
+ if [[ "$XMLSTARLET_AVAILABLE" == "true" ]]; then
183
+ # Use count() XPath function
184
+ local count_result
185
+ count_result=$(xmlstarlet sel -t -v "count($xpath)" "$xml_file" 2>/dev/null)
186
+ count="${count_result:-0}"
187
+ elif [[ "$XMLLINT_AVAILABLE" == "true" ]]; then
188
+ # Count matching lines (approximate for simple cases)
189
+ local matches
190
+ matches=$(xmllint --nonet --noent --xpath "$xpath" "$xml_file" 2>/dev/null | grep -c '<' || true)
191
+ count="${matches:-0}"
192
+ else
193
+ xml_json_err "TOOL_NOT_AVAILABLE" "No XPath-capable tool available"
194
+ return 1
195
+ fi
196
+
197
+ xml_json_ok "{\"count\":$count}"
198
+ }
199
+
200
+ # Export functions
201
+ export -f xml-query xml-query-attr xml-query-text xml-query-count
@@ -0,0 +1,110 @@
1
+ #!/bin/bash
2
+ # XML Utilities Loader
3
+ # Sources all XML modules for backward compatibility
4
+ #
5
+ # IMPORTANT: This file is now a loader only. New code should source
6
+ # individual modules directly from .aether/utils/ or .aether/exchange/
7
+ #
8
+ # Usage: source .aether/utils/xml-utils.sh
9
+ #
10
+ # Modules loaded:
11
+ # - xml-core.sh : Core operations (validate, format, escape)
12
+ # - xml-query.sh : XPath queries
13
+ # - xml-convert.sh : JSON/XML conversion
14
+ # - xml-compose.sh : XInclude composition
15
+ # - pheromone-xml.sh : Pheromone exchange
16
+ # - wisdom-xml.sh : Queen wisdom exchange
17
+ # - registry-xml.sh : Colony registry exchange
18
+ #
19
+ # Deprecated functions (maintained for compatibility):
20
+ # - pheromone-to-xml() -> Use xml-pheromone-export()
21
+ # - pheromone-from-xml() -> Use xml-pheromone-import()
22
+ # - queen-wisdom-to-xml() -> Use xml-wisdom-export()
23
+ # - queen-wisdom-from-xml() -> Use xml-wisdom-import()
24
+
25
+ set -euo pipefail
26
+
27
+ # Determine script directory for relative sourcing
28
+ # Handle case when sourced interactively (BASH_SOURCE[0] may be empty)
29
+ if [[ -n "${BASH_SOURCE[0]:-}" ]]; then
30
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
31
+ else
32
+ # Fallback: derive from the sourced script's location
33
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]:-$0}")" && pwd)"
34
+ fi
35
+ EXCHANGE_DIR="$(cd "$SCRIPT_DIR/../exchange" && pwd)"
36
+
37
+ # ============================================================================
38
+ # Load Core Modules
39
+ # ============================================================================
40
+
41
+ # Core utilities (required by other modules)
42
+ source "$SCRIPT_DIR/xml-core.sh"
43
+
44
+ # Query functions
45
+ source "$SCRIPT_DIR/xml-query.sh"
46
+
47
+ # Conversion functions
48
+ source "$SCRIPT_DIR/xml-convert.sh"
49
+
50
+ # Composition functions
51
+ source "$SCRIPT_DIR/xml-compose.sh"
52
+
53
+ # ============================================================================
54
+ # Load Exchange Modules
55
+ # ============================================================================
56
+
57
+ # Pheromone exchange (export/import)
58
+ source "$EXCHANGE_DIR/pheromone-xml.sh"
59
+
60
+ # Queen wisdom exchange
61
+ source "$EXCHANGE_DIR/wisdom-xml.sh"
62
+
63
+ # Colony registry exchange
64
+ source "$EXCHANGE_DIR/registry-xml.sh"
65
+
66
+ # ============================================================================
67
+ # Backward Compatibility Aliases
68
+ # ============================================================================
69
+
70
+ # Map old function names to new ones for compatibility
71
+ pheromone-to-xml() { xml-pheromone-export "$@"; }
72
+ pheromone-from-xml() { xml-pheromone-import "$@"; }
73
+ queen-wisdom-to-xml() { xml-wisdom-export "$@"; }
74
+ queen-wisdom-from-xml() { xml-wisdom-import "$@"; }
75
+ registry-to-xml() { xml-registry-export "$@"; }
76
+ registry-from-xml() { xml-registry-import "$@"; }
77
+
78
+ # Export compatibility aliases
79
+ export -f pheromone-to-xml pheromone-from-xml
80
+ export -f queen-wisdom-to-xml queen-wisdom-from-xml
81
+ export -f registry-to-xml registry-from-xml
82
+
83
+ # ============================================================================
84
+ # Module Information
85
+ # ============================================================================
86
+
87
+ # xml-utils-info: Display module information
88
+ # Usage: xml-utils-info
89
+ xml-utils-info() {
90
+ xml_json_ok '{
91
+ "modules": [
92
+ "xml-core.sh",
93
+ "xml-query.sh",
94
+ "xml-convert.sh",
95
+ "xml-compose.sh",
96
+ "pheromone-xml.sh",
97
+ "wisdom-xml.sh",
98
+ "registry-xml.sh"
99
+ ],
100
+ "note": "This loader provides backward compatibility. New code should source individual modules.",
101
+ "tools": {
102
+ "xmllint": '"$XMLLINT_AVAILABLE"',
103
+ "xmlstarlet": '"$XMLSTARLET_AVAILABLE"',
104
+ "xsltproc": '"$XSLTPROC_AVAILABLE"'
105
+ }
106
+ }'
107
+ }
108
+
109
+ export -f xml-utils-info
110
+