@ainova-systems/intelligence 0.11.2 → 0.11.4

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.
@@ -92,8 +92,8 @@ _ver_gt() {
92
92
  IFS=. read -r -a A <<< "$a"
93
93
  IFS=. read -r -a B <<< "$b"
94
94
  for i in 0 1 2; do
95
- ai=$(printf '%s' "${A[$i]:-0}" | tr -cd '0-9'); ai=${ai:-0}
96
- bi=$(printf '%s' "${B[$i]:-0}" | tr -cd '0-9'); bi=${bi:-0}
95
+ ai="${A[$i]:-0}"; ai="${ai//[!0-9]/}"; ai=${ai:-0}
96
+ bi="${B[$i]:-0}"; bi="${bi//[!0-9]/}"; bi=${bi:-0}
97
97
  if [ "$((10#$ai))" -gt "$((10#$bi))" ]; then return 0; fi
98
98
  if [ "$((10#$ai))" -lt "$((10#$bi))" ]; then return 1; fi
99
99
  done
package/engine/sync.sh CHANGED
@@ -86,24 +86,38 @@ echo " Config: $CONFIG_FILE"
86
86
  echo " Root: $REPO_ROOT"
87
87
  echo ""
88
88
 
89
+ # The engine never mutates the manifest, so parse its hot sections exactly
90
+ # once: every later read_yaml_list / target lookup — in this process and in
91
+ # adapter process substitutions — hits the in-memory copy instead of
92
+ # spawning awk.
93
+ load_targets_cache "$CONFIG_FILE"
94
+ for section in rules agents skills ignore submodules; do
95
+ load_yaml_list "$CONFIG_FILE" "$section"
96
+ done
97
+
89
98
  # Lint frontmatter across all source files (rules, agents, skills).
90
99
  # Catches issues like unquoted colons that strict YAML consumers reject.
100
+ LINT_FILES=()
91
101
  for section in rules agents skills; do
102
+ load_yaml_list "$CONFIG_FILE" "$section"
92
103
  while IFS= read -r src; do
93
104
  [ -z "$src" ] && continue
94
- src_dir="$(resolve_source_dir "$REPO_ROOT" "$src")"
105
+ src_dir="$REPO_ROOT/$src"
95
106
  [ -d "$src_dir" ] || continue
96
107
  if [ "$section" = "skills" ]; then
97
108
  while IFS= read -r f; do
98
- [ -n "$f" ] && lint_frontmatter "$f"
109
+ [ -n "$f" ] && LINT_FILES+=("$f")
99
110
  done < <(find "$src_dir" -mindepth 2 -maxdepth 2 -name 'SKILL.md' 2>/dev/null)
100
111
  else
101
112
  for f in "$src_dir"/*.md; do
102
- [ -f "$f" ] && lint_frontmatter "$f"
113
+ [ -f "$f" ] && LINT_FILES+=("$f")
103
114
  done
104
115
  fi
105
- done < <(read_yaml_list "$CONFIG_FILE" "$section")
116
+ done <<< "$IS_YAML_LIST"
106
117
  done
118
+ if [ "${#LINT_FILES[@]}" -gt 0 ]; then
119
+ lint_frontmatter_files "${LINT_FILES[@]}"
120
+ fi
107
121
 
108
122
  # Adapters come from two places, discovered by filename (minus `.sh`,
109
123
  # `_template` excluded):
@@ -149,24 +163,27 @@ done
149
163
  # point of view.
150
164
  SYNC_TX_DIR="$(mktemp -d -t intelligence-sync-XXXXXX)"
151
165
  SYNC_TX_INDEX="$SYNC_TX_DIR/paths.tsv"
152
- SYNC_TX_SEEN="$SYNC_TX_DIR/seen"
153
166
  mkdir -p "$SYNC_TX_DIR/data"
154
167
  : > "$SYNC_TX_INDEX"
155
- : > "$SYNC_TX_SEEN"
156
168
  SYNC_TX_ACTIVE=0
169
+ SYNC_TX_SEEN_LIST=$'\n'
170
+ SYNC_TX_COUNT=0
157
171
 
158
172
  snapshot_sync_path() {
159
173
  local adapter_name="$1" rel="$2" src index present=0
160
- grep -Fqx -- "$rel" "$SYNC_TX_SEEN" && return 0
161
- printf '%s\n' "$rel" >> "$SYNC_TX_SEEN"
174
+ case "$SYNC_TX_SEEN_LIST" in
175
+ *$'\n'"$rel"$'\n'*) return 0 ;;
176
+ esac
177
+ SYNC_TX_SEEN_LIST="$SYNC_TX_SEEN_LIST$rel"$'\n'
162
178
  validate_output_path "$REPO_ROOT" "$CONFIG_FILE" "$adapter_name" "$REPO_ROOT/$rel"
163
- index="$(wc -l < "$SYNC_TX_INDEX" | tr -d ' ')"
179
+ index="$SYNC_TX_COUNT"
164
180
  src="$REPO_ROOT/$rel"
165
181
  if [ -e "$src" ] || [ -L "$src" ]; then
166
182
  cp -a "$src" "$SYNC_TX_DIR/data/$index"
167
183
  present=1
168
184
  fi
169
185
  printf '%s\t%s\t%s\n' "$index" "$rel" "$present" >> "$SYNC_TX_INDEX"
186
+ SYNC_TX_COUNT=$((SYNC_TX_COUNT + 1))
170
187
  }
171
188
 
172
189
  restore_sync_snapshot() {
@@ -204,14 +221,17 @@ while [ "$preflight_idx" -lt "${#ADAPTERS[@]}" ]; do
204
221
  if [ -n "$TARGET_FILTER" ] && [ "$adapter" != "$TARGET_FILTER" ]; then
205
222
  continue
206
223
  fi
207
- [ "$(is_target_enabled "$CONFIG_FILE" "$adapter")" = "1" ] || continue
208
- output="$(get_target_output "$CONFIG_FILE" "$adapter")"
224
+ target_enabled_var "$CONFIG_FILE" "$adapter"
225
+ [ "$IS_TGT_ENABLED" = "1" ] || continue
226
+ target_output_var "$CONFIG_FILE" "$adapter"
227
+ output="$IS_TGT_OUTPUT"
209
228
  [ -n "$output" ] || output=".$adapter"
210
229
  validate_output_path "$REPO_ROOT" "$CONFIG_FILE" "$adapter" "$REPO_ROOT/$output"
211
230
  records="$(adapter_contract_records "$adapter" "$adapter_file" "$output")" || exit 1
212
231
  while IFS=$'\t' read -r kind value; do
213
232
  [ "$kind" = "requires" ] || continue
214
- if [ "$(is_target_enabled "$CONFIG_FILE" "$value")" != "1" ]; then
233
+ target_enabled_var "$CONFIG_FILE" "$value"
234
+ if [ "$IS_TGT_ENABLED" != "1" ]; then
215
235
  echo "ERROR: targets.$adapter requires enabled target '$value'." >&2
216
236
  echo " Enable it first: intelligence adapter enable $value" >&2
217
237
  exit 1
@@ -240,7 +260,8 @@ while [ "$adapter_idx" -lt "$adapter_count" ]; do
240
260
  fi
241
261
 
242
262
  # Check if target is enabled in config
243
- enabled=$(is_target_enabled "$CONFIG_FILE" "$adapter")
263
+ target_enabled_var "$CONFIG_FILE" "$adapter"
264
+ enabled="$IS_TGT_ENABLED"
244
265
  if [ "$enabled" != "1" ]; then
245
266
  if [ -n "$TARGET_FILTER" ]; then
246
267
  echo "ERROR: Adapter '$TARGET_FILTER' is disabled in $CONFIG_FILE." >&2
@@ -251,7 +272,8 @@ while [ "$adapter_idx" -lt "$adapter_count" ]; do
251
272
  fi
252
273
 
253
274
  # Get output directory
254
- output=$(get_target_output "$CONFIG_FILE" "$adapter")
275
+ target_output_var "$CONFIG_FILE" "$adapter"
276
+ output="$IS_TGT_OUTPUT"
255
277
  if [ -z "$output" ]; then
256
278
  output=".$adapter"
257
279
  fi
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ainova-systems/intelligence",
3
- "version": "0.11.2",
3
+ "version": "0.11.4",
4
4
  "description": "Build, version and distribute AI agent intelligence across your organization — one CLI, versioned Intelligence Packages, and a sync engine for Claude Code, Cursor, Copilot, Codex, Pi and OpenCode.",
5
5
  "bin": {
6
6
  "intelligence": "bin/intelligence.js"
@@ -131,18 +131,26 @@ Use the engine library instead of copying parsers or file-handling logic.
131
131
  |---|---|
132
132
  | `resolve_source_dir(repo_root, source)` | Resolve a manifest source to its local directory. |
133
133
  | `read_yaml_list(config, section)` | Stream entries from `sources.<section>`. |
134
+ | `load_yaml_list(config, section)` | Same list into `IS_YAML_LIST`, cached — no subprocess on repeat reads. |
134
135
  | `get_frontmatter_value(key, file)` | Read a scalar from the first frontmatter block. |
136
+ | `frontmatter_index(keys, file...)` | Read several frontmatter scalars for many files in one pass (`\x1f`-separated rows; special key `paths#` counts `paths:` lines). |
135
137
  | `has_frontmatter(file)` / `has_paths(file)` | Inspect source shape. |
136
138
  | `strip_frontmatter(file)` | Emit the body without its first frontmatter block. |
137
139
  | `get_model(config, tool, tier)` | Resolve a `heavy`, `standard` or `light` model, including manifest overrides. |
138
140
  | `get_model_default(tool, tier)` | Read the built-in model default. |
141
+ | `load_model_tiers(config, tool)` / `resolve_model_var(tier)` | Resolve the three standard tiers once, then map per file without subprocesses. |
139
142
  | `copy_skill_bundle(src, dest)` | Copy `SKILL.md` and all resources safely, normalize Markdown and quote free-text frontmatter. |
143
+ | `copy_skill_bundle_dirs(dest_root, src...)` | Batch form: copy every skill directory into `dest_root/<name>` with one copy and one finalize pass. |
140
144
  | `sync_open_skill_dirs(root, config, dest)` | Own and populate a shared Agent Skills directory such as `.agents/skills/`. |
141
145
  | `finalize_output_file(file)` | Expand layout tokens and normalize line endings; required for every emitted text file. |
146
+ | `finalize_output_files(file...)` / `finalize_copy_files(dest, src...)` | Batch forms: finalize in place, or copy-and-finalize into a directory, in one process. |
147
+ | `emit_wrapped_bodies(spec)` | Emit many header + source-body + tail outputs in one process (see `engine/lib/common.sh` for the spec format). |
142
148
  | `get_target_field(config, target, field)` | Read another field from the target configuration. |
143
149
  | `repo_rel_link(root, path)` | Produce a stable repo-relative link for a committed output. |
144
150
 
145
- `lint_frontmatter` is run across all inputs by the engine before adapters execute. It warns about common YAML hazards; adapters should not duplicate that pass.
151
+ `lint_frontmatter` is run across all inputs by the engine before adapters execute (batched as `lint_frontmatter_files`). It warns about common YAML hazards; adapters should not duplicate that pass.
152
+
153
+ Prefer the batched forms inside per-file loops: a process spawn costs tens of milliseconds on Git Bash for Windows, so one-awk-per-file adapters turn large projects into minutes of process creation. The built-in adapters are the reference for the pattern.
146
154
 
147
155
  ## Rules, skills and agents
148
156