@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.
package/engine/ENGINE_SHA CHANGED
@@ -1 +1 @@
1
- 0230d83b42848492194f593ebdd387714371b682
1
+ a8e3accf49ce60d8e0b04f04bc68ef6f813f2a2e
package/engine/VERSION CHANGED
@@ -1 +1 @@
1
- 0.11.2
1
+ 0.11.4
@@ -10,6 +10,9 @@
10
10
  # Unlike other adapters, the output is a single committed markdown file
11
11
  # meant to be read by both humans and LLMs. It must never be hand-edited —
12
12
  # every sync regenerates it from scratch.
13
+ #
14
+ # Every per-file loop batches its work into one awk process (see the batched
15
+ # helpers in lib/common.sh): process spawns dominate sync time on Windows.
13
16
 
14
17
  source "$(dirname "${BASH_SOURCE[0]}")/../lib/common.sh"
15
18
 
@@ -55,30 +58,37 @@ agents_md_append_agents_table() {
55
58
  local rows=""
56
59
  local count=0
57
60
 
61
+ local src f
62
+ local -a files=()
63
+ load_yaml_list "$config_file" "agents"
64
+ local list="$IS_YAML_LIST"
58
65
  while IFS= read -r src; do
59
66
  [ -z "$src" ] && continue
60
- local dir
61
- dir="$(resolve_source_dir "$repo_root" "$src")"
67
+ local dir="$repo_root/$src"
62
68
  [ -d "$dir" ] || continue
63
69
  # Byte-order (LC_ALL=C) sort so generated output is identical across
64
70
  # platforms — bash glob order follows LC_COLLATE, which differs between
65
71
  # Linux CI (UTF-8, ignores `-`) and Git Bash (C, byte order).
66
72
  while IFS= read -r f; do
67
73
  [ -f "$f" ] || continue
68
- local name rel tier access desc
69
- name="$(basename "$f" .md)"
70
- rel="$(repo_rel_link "$repo_root" "$f")"
71
- tier=$(get_frontmatter_value "tier" "$f")
72
- access=$(get_frontmatter_value "access" "$f")
73
- desc=$(get_frontmatter_value "description" "$f")
74
- if [ -n "$rel" ]; then
75
- rows+="| [$name]($rel) | ${tier:--} | ${access:--} | ${desc:--} |"$'\n'
74
+ files+=("$f")
75
+ done < <(find "$dir" -maxdepth 1 -type f -name '*.md' -print | LC_ALL=C sort)
76
+ done <<< "$list"
77
+
78
+ if [ "${#files[@]}" -gt 0 ]; then
79
+ local path tier access desc name
80
+ while IFS=$'\x1f' read -r path tier access desc; do
81
+ [ -n "$path" ] || continue
82
+ name="${path##*/}"; name="${name%.md}"
83
+ repo_rel_link_var "$repo_root" "$path"
84
+ if [ -n "$IS_REPO_REL" ]; then
85
+ rows+="| [$name]($IS_REPO_REL) | ${tier:--} | ${access:--} | ${desc:--} |"$'\n'
76
86
  else
77
87
  rows+="| $name | ${tier:--} | ${access:--} | ${desc:--} |"$'\n'
78
88
  fi
79
89
  count=$((count + 1))
80
- done < <(find "$dir" -maxdepth 1 -type f -name '*.md' -print | LC_ALL=C sort)
81
- done < <(read_yaml_list "$config_file" "agents")
90
+ done < <(frontmatter_index "tier,access,description" "${files[@]}")
91
+ fi
82
92
 
83
93
  [ "$count" -eq 0 ] && return 0
84
94
 
@@ -102,31 +112,39 @@ agents_md_append_skills_table() {
102
112
  local rows=""
103
113
  local count=0
104
114
 
115
+ local src skill_dir dirname
116
+ local -a skill_files=()
117
+ load_yaml_list "$config_file" "skills"
118
+ local list="$IS_YAML_LIST"
105
119
  while IFS= read -r src; do
106
120
  [ -z "$src" ] && continue
107
- local dir
108
- dir="$(resolve_source_dir "$repo_root" "$src")"
121
+ local dir="$repo_root/$src"
109
122
  [ -d "$dir" ] || continue
110
123
  # Byte-order (LC_ALL=C) sort so generated output is identical across
111
124
  # platforms — see the note in agents_md_append_agents_table.
112
125
  while IFS= read -r skill_dir; do
113
126
  [ -d "$skill_dir" ] || continue
114
- local dirname
115
- dirname="$(basename "$skill_dir")"
127
+ dirname="${skill_dir##*/}"
116
128
  case "$dirname" in _*) continue ;; esac
117
- local skill_file="${skill_dir%/}/SKILL.md"
118
- [ -f "$skill_file" ] || continue
119
- local rel desc
120
- rel="$(repo_rel_link "$repo_root" "$skill_file")"
121
- desc=$(get_frontmatter_value "description" "$skill_file")
122
- if [ -n "$rel" ]; then
123
- rows+="| [$dirname]($rel) | ${desc:--} |"$'\n'
129
+ [ -f "${skill_dir%/}/SKILL.md" ] || continue
130
+ skill_files+=("${skill_dir%/}/SKILL.md")
131
+ done < <(find "$dir" -mindepth 1 -maxdepth 1 -type d -print | LC_ALL=C sort)
132
+ done <<< "$list"
133
+
134
+ if [ "${#skill_files[@]}" -gt 0 ]; then
135
+ local path desc
136
+ while IFS=$'\x1f' read -r path desc; do
137
+ [ -n "$path" ] || continue
138
+ dirname="${path%/SKILL.md}"; dirname="${dirname##*/}"
139
+ repo_rel_link_var "$repo_root" "$path"
140
+ if [ -n "$IS_REPO_REL" ]; then
141
+ rows+="| [$dirname]($IS_REPO_REL) | ${desc:--} |"$'\n'
124
142
  else
125
143
  rows+="| $dirname | ${desc:--} |"$'\n'
126
144
  fi
127
145
  count=$((count + 1))
128
- done < <(find "$dir" -mindepth 1 -maxdepth 1 -type d -print | LC_ALL=C sort)
129
- done < <(read_yaml_list "$config_file" "skills")
146
+ done < <(frontmatter_index "description" "${skill_files[@]}")
147
+ fi
130
148
 
131
149
  [ "$count" -eq 0 ] && return 0
132
150
 
@@ -151,33 +169,43 @@ agents_md_append_rules_list() {
151
169
  local count=0
152
170
  local global_rule_files=()
153
171
 
172
+ local src f
173
+ local -a files=()
174
+ load_yaml_list "$config_file" "rules"
175
+ local list="$IS_YAML_LIST"
154
176
  while IFS= read -r src; do
155
177
  [ -z "$src" ] && continue
156
- local dir
157
- dir="$(resolve_source_dir "$repo_root" "$src")"
178
+ local dir="$repo_root/$src"
158
179
  [ -d "$dir" ] || continue
159
180
  # Byte-order (LC_ALL=C) sort so generated output — and the inline order
160
181
  # of always-on rules below — is identical across platforms. See the
161
182
  # note in agents_md_append_agents_table.
162
183
  while IFS= read -r f; do
163
184
  [ -f "$f" ] || continue
164
- local name rel scope
165
- name="$(basename "$f" .md)"
166
- rel="$(repo_rel_link "$repo_root" "$f")"
185
+ files+=("$f")
186
+ done < <(find "$dir" -maxdepth 1 -type f -name '*.md' -print | LC_ALL=C sort)
187
+ done <<< "$list"
188
+
189
+ if [ "${#files[@]}" -gt 0 ]; then
190
+ local path hp name scope
191
+ while IFS=$'\x1f' read -r path hp; do
192
+ [ -n "$path" ] || continue
193
+ name="${path##*/}"; name="${name%.md}"
167
194
  scope="global"
168
- if [ "$(has_paths "$f")" != "0" ]; then
195
+ if [ "$hp" != "0" ]; then
169
196
  scope="scoped"
170
197
  else
171
- global_rule_files+=("$f")
198
+ global_rule_files+=("$path")
172
199
  fi
173
- if [ -n "$rel" ]; then
174
- lines+="- [$name]($rel) ($scope)"$'\n'
200
+ repo_rel_link_var "$repo_root" "$path"
201
+ if [ -n "$IS_REPO_REL" ]; then
202
+ lines+="- [$name]($IS_REPO_REL) ($scope)"$'\n'
175
203
  else
176
204
  lines+="- $name ($scope)"$'\n'
177
205
  fi
178
206
  count=$((count + 1))
179
- done < <(find "$dir" -maxdepth 1 -type f -name '*.md' -print | LC_ALL=C sort)
180
- done < <(read_yaml_list "$config_file" "rules")
207
+ done < <(frontmatter_index "paths#" "${files[@]}")
208
+ fi
181
209
 
182
210
  [ "$count" -eq 0 ] && return 0
183
211
 
@@ -206,18 +234,17 @@ agents_md_append_rules_list() {
206
234
  echo "<!-- Inlined from always-on rules in $content_rel/rules/ -->"
207
235
  echo ""
208
236
  } >> "$output"
209
- local rf
210
- for rf in "${global_rule_files[@]}"; do
211
- awk '
212
- BEGIN { in_fm=0; past_fm=0 }
213
- { sub(/\r$/, "") }
214
- /^---$/ {
215
- if (!past_fm) { in_fm = !in_fm; if (!in_fm) { past_fm=1 }; next }
216
- }
217
- past_fm || !in_fm { print }
218
- ' "$rf" >> "$output"
219
- echo "" >> "$output"
220
- done
237
+ # One awk inlines every global rule body, with a blank line after
238
+ # each — the same output the per-file passes produced.
239
+ awk '
240
+ FNR == 1 { if (NR != 1) print ""; in_fm = 0; past_fm = 0 }
241
+ { sub(/\r$/, "") }
242
+ /^---$/ {
243
+ if (!past_fm) { in_fm = !in_fm; if (!in_fm) { past_fm = 1 }; next }
244
+ }
245
+ past_fm || !in_fm { print }
246
+ END { print "" }
247
+ ' "${global_rule_files[@]}" >> "$output"
221
248
  echo " rules: ${#global_rule_files[@]} global rule(s) inlined"
222
249
  fi
223
250
  }
@@ -5,6 +5,9 @@
5
5
  # Rules: copy as-is (paths: frontmatter preserved)
6
6
  # Skills: copy skill directories in full (SKILL.md + bundled resources)
7
7
  # Agents: tier -> model, access -> tools/disallowedTools
8
+ #
9
+ # Every per-file loop batches its work into one awk process (see the batched
10
+ # helpers in lib/common.sh): process spawns dominate sync time on Windows.
8
11
 
9
12
  source "$(dirname "${BASH_SOURCE[0]}")/../lib/common.sh"
10
13
 
@@ -29,18 +32,24 @@ sync_claude_rules() {
29
32
  local config_file="$2"
30
33
  local output_dir="$3"
31
34
 
35
+ local src f
36
+ local -a files=()
37
+ load_yaml_list "$config_file" "rules"
38
+ local list="$IS_YAML_LIST"
32
39
  while IFS= read -r src; do
33
40
  [ -z "$src" ] && continue
34
- local dir
35
- dir="$(resolve_source_dir "$repo_root" "$src")"
41
+ local dir="$repo_root/$src"
36
42
  [ -d "$dir" ] || continue
37
43
  for f in "$dir"/*.md; do
38
44
  [ -f "$f" ] || continue
39
- cp "$f" "$output_dir/rules/"
40
- finalize_output_file "$output_dir/rules/$(basename "$f")"
41
- echo " rule: $(basename "$f")"
45
+ files+=("$f")
42
46
  done
43
- done < <(read_yaml_list "$config_file" "rules")
47
+ done <<< "$list"
48
+ [ "${#files[@]}" -gt 0 ] || return 0
49
+ finalize_copy_files "$output_dir/rules" "${files[@]}"
50
+ for f in "${files[@]}"; do
51
+ echo " rule: ${f##*/}"
52
+ done
44
53
  }
45
54
 
46
55
  # Sync skills to Claude format (copy skill directories in full)
@@ -49,75 +58,98 @@ sync_claude_skills() {
49
58
  local config_file="$2"
50
59
  local output_dir="$3"
51
60
 
61
+ local src d skill_name
62
+ local -a skill_dirs=()
63
+ load_yaml_list "$config_file" "skills"
64
+ local list="$IS_YAML_LIST"
52
65
  while IFS= read -r src; do
53
66
  [ -z "$src" ] && continue
54
- local dir
55
- dir="$(resolve_source_dir "$repo_root" "$src")"
67
+ local dir="$repo_root/$src"
56
68
  [ -d "$dir" ] || continue
57
69
  for d in "$dir"/*/; do
58
70
  [ -d "$d" ] || continue
59
- local skill_name
60
- skill_name="$(basename "$d")"
61
71
  [ -f "$d/SKILL.md" ] || continue
62
- copy_skill_bundle "$d" "$output_dir/skills/$skill_name"
63
- echo " skill: $skill_name"
72
+ skill_dirs+=("$d")
64
73
  done
65
- done < <(read_yaml_list "$config_file" "skills")
66
- }
67
-
68
- # Sync a single agent file to Claude format
69
- sync_claude_agent() {
70
- local src="$1"
71
- local config_file="$2"
72
- local output_dir="$3"
73
- local name
74
- name="$(basename "$src")"
75
-
76
- local tier access
77
- tier=$(get_frontmatter_value "tier" "$src")
78
- access=$(get_frontmatter_value "access" "$src")
79
-
80
- local model tools extra
81
- model=$(get_model "$config_file" "claude" "$tier")
82
- tools=$(map_access_to_claude_tools "$access")
83
- extra=$(map_access_to_claude_disallowed "$access")
84
-
85
- # Transform: remove tier/access, inject tools/model/disallowedTools before closing ---
86
- awk -v model="$model" -v tools="$tools" -v extra="$extra" '
87
- BEGIN { count=0 }
88
- /^tier:/ { next }
89
- /^access:/ { next }
90
- {
91
- sub(/\r$/, "")
92
- }
93
- /^---$/ { count++ }
94
- count==2 && /^---$/ {
95
- if (tools != "") print "tools: " tools
96
- if (extra != "") print "disallowedTools: " extra
97
- print "model: " model
98
- }
99
- { print }
100
- ' "$src" > "$output_dir/agents/$name"
101
- finalize_output_file "$output_dir/agents/$name"
102
- echo " agent: $name (tier=$tier -> model=$model, access=$access)"
74
+ done <<< "$list"
75
+ [ "${#skill_dirs[@]}" -gt 0 ] || return 0
76
+ copy_skill_bundle_dirs "$output_dir/skills" "${skill_dirs[@]}"
77
+ for d in "${skill_dirs[@]}"; do
78
+ skill_name="${d%/}"
79
+ echo " skill: ${skill_name##*/}"
80
+ done
103
81
  }
104
82
 
105
- # Sync all agents to Claude format
83
+ # Sync all agents to Claude format: one frontmatter pass resolves
84
+ # tier/access for every file, one transform pass writes every output.
106
85
  sync_claude_agents() {
107
86
  local repo_root="$1"
108
87
  local config_file="$2"
109
88
  local output_dir="$3"
110
89
 
90
+ local src f
91
+ local -a files=()
92
+ load_yaml_list "$config_file" "agents"
93
+ local list="$IS_YAML_LIST"
111
94
  while IFS= read -r src; do
112
95
  [ -z "$src" ] && continue
113
- local dir
114
- dir="$(resolve_source_dir "$repo_root" "$src")"
96
+ local dir="$repo_root/$src"
115
97
  [ -d "$dir" ] || continue
116
98
  for f in "$dir"/*.md; do
117
99
  [ -f "$f" ] || continue
118
- sync_claude_agent "$f" "$config_file" "$output_dir"
100
+ files+=("$f")
119
101
  done
120
- done < <(read_yaml_list "$config_file" "agents")
102
+ done <<< "$list"
103
+ [ "${#files[@]}" -gt 0 ] || return 0
104
+
105
+ load_model_tiers "$config_file" "claude"
106
+
107
+ local path tier access spec="" report=""
108
+ while IFS=$'\x1f' read -r path tier access; do
109
+ [ -n "$path" ] || continue
110
+ resolve_model_var "$tier"
111
+ map_access_to_claude_tools_var "$access"
112
+ map_access_to_claude_disallowed_var "$access"
113
+ spec+="$path"$'\x1f'"$IS_MODEL"$'\x1f'"$IS_CLAUDE_TOOLS"$'\x1f'"$IS_CLAUDE_DISALLOWED"$'\n'
114
+ report+=" agent: ${path##*/} (tier=$tier -> model=$IS_MODEL, access=$access)"$'\n'
115
+ done < <(frontmatter_index "tier,access" "${files[@]}")
116
+
117
+ # The transform used to run per file with the values injected via -v;
118
+ # the batched form carries them per file through the environment (awk -v
119
+ # would reprocess backslash escapes).
120
+ is_fin_awk_vars
121
+ IS_MAP_SPEC="$spec" awk "${IS_FIN_V[@]}" -v dst="$output_dir/agents" "$IS_AWK_LIB"'
122
+ BEGIN {
123
+ US = sprintf("%c", 31)
124
+ n = split(ENVIRON["IS_MAP_SPEC"], recs, "\n")
125
+ for (i = 1; i <= n; i++) {
126
+ if (recs[i] == "") continue
127
+ split(recs[i], f, US)
128
+ MODEL[f[1]] = f[2]; TOOLS[f[1]] = f[3]; EXTRA[f[1]] = f[4]
129
+ }
130
+ }
131
+ FNR == 1 {
132
+ if (out != "") close(out)
133
+ out = dst "/" base_name(FILENAME)
134
+ count = 0
135
+ }
136
+ /^tier:/ { next }
137
+ /^access:/ { next }
138
+ { sub(/\r$/, "") }
139
+ /^---$/ { count++ }
140
+ count == 2 && /^---$/ {
141
+ if (TOOLS[FILENAME] != "") print fin_line("tools: " TOOLS[FILENAME]) > out
142
+ if (EXTRA[FILENAME] != "") print fin_line("disallowedTools: " EXTRA[FILENAME]) > out
143
+ print fin_line("model: " MODEL[FILENAME]) > out
144
+ }
145
+ { print fin_line($0) > out }
146
+ ' "${files[@]}"
147
+ # awk never reads a record from an empty source; the old per-file shell
148
+ # redirect still created an empty output for it.
149
+ for f in "${files[@]}"; do
150
+ [ -s "$f" ] || : > "$output_dir/agents/${f##*/}"
151
+ done
152
+ printf '%s' "$report"
121
153
  }
122
154
 
123
155
  # Main entry point for Claude adapter
@@ -133,9 +165,7 @@ sync_to_claude() {
133
165
  # commands/, statusline.sh, etc.).
134
166
  rm -rf "$output_dir/rules" "$output_dir/agents"
135
167
  if [ -d "$output_dir/skills" ]; then
136
- find "$output_dir/skills" -mindepth 1 -maxdepth 1 -type d | while read -r d; do
137
- rm -rf "$d"
138
- done
168
+ find "$output_dir/skills" -mindepth 1 -maxdepth 1 -type d -exec rm -rf {} +
139
169
  fi
140
170
  mkdir -p "$output_dir/rules" "$output_dir/skills" "$output_dir/agents"
141
171
 
@@ -10,6 +10,9 @@
10
10
  # reads from $REPO_ROOT/.agents/skills exclusively per official docs)
11
11
  # Agents: -> .codex/agents/{name}.toml (name, description, model,
12
12
  # model_reasoning_effort, sandbox_mode, developer_instructions)
13
+ #
14
+ # Every per-file loop batches its work into one awk process (see the batched
15
+ # helpers in lib/common.sh): process spawns dominate sync time on Windows.
13
16
 
14
17
  source "$(dirname "${BASH_SOURCE[0]}")/../lib/common.sh"
15
18
 
@@ -38,24 +41,29 @@ sync_codex_agents() {
38
41
  local config_file="$2"
39
42
  local output_dir="$3"
40
43
 
41
- local count=0
44
+ local src f
45
+ local -a files=()
46
+ load_yaml_list "$config_file" "agents"
47
+ local list="$IS_YAML_LIST"
42
48
  while IFS= read -r src; do
43
49
  [ -z "$src" ] && continue
44
- local dir
45
- dir="$(resolve_source_dir "$repo_root" "$src")"
50
+ local dir="$repo_root/$src"
46
51
  [ -d "$dir" ] || continue
47
52
  for f in "$dir"/*.md; do
48
53
  [ -f "$f" ] || continue
49
- local name
50
- name="$(basename "$f" .md)"
51
-
52
- local tier access description
53
- tier=$(get_frontmatter_value "tier" "$f")
54
- access=$(get_frontmatter_value "access" "$f")
55
- description=$(get_frontmatter_value "description" "$f")
54
+ files+=("$f")
55
+ done
56
+ done <<< "$list"
56
57
 
57
- local model effort sandbox
58
- model=$(get_model "$config_file" "codex" "$tier")
58
+ local count=0
59
+ if [ "${#files[@]}" -gt 0 ]; then
60
+ load_model_tiers "$config_file" "codex"
61
+
62
+ local path tier access description name effort sandbox spec="" report="" LS=$'\x1e'
63
+ while IFS=$'\x1f' read -r path tier access description; do
64
+ [ -n "$path" ] || continue
65
+ name="${path##*/}"; name="${name%.md}"
66
+ resolve_model_var "$tier"
59
67
  case "$tier" in
60
68
  heavy) effort="high" ;;
61
69
  standard) effort="medium" ;;
@@ -66,43 +74,27 @@ sync_codex_agents() {
66
74
  readonly) sandbox="read-only" ;;
67
75
  *) sandbox="workspace-write" ;;
68
76
  esac
69
-
70
- local body
71
- body=$(awk '
72
- BEGIN { in_fm=0; past_fm=0 }
73
- { sub(/\r$/, "") }
74
- /^---$/ {
75
- if (!past_fm) { in_fm = !in_fm; if (!in_fm) { past_fm=1 }; next }
76
- }
77
- past_fm { print }
78
- ' "$f")
79
-
80
- # Escape backslashes used in Markdown paths, then neutralize any
81
- # closing TOML triple-quote sequence in the agent body.
82
- local body_safe
83
- body_safe="${body//\\/\\\\}"
84
- body_safe="${body_safe//\"\"\"/\"\"\\\"}"
85
-
86
77
  local name_escaped description_escaped
87
- name_escaped=$(toml_escape "$name")
88
- description_escaped=$(toml_escape "$description")
89
-
90
- {
91
- echo "name = \"$name_escaped\""
92
- echo "description = \"$description_escaped\""
93
- echo "model = \"$model\""
94
- echo "model_reasoning_effort = \"$effort\""
95
- echo "sandbox_mode = \"$sandbox\""
96
- echo ""
97
- echo "developer_instructions = \"\"\""
98
- echo "$body_safe"
99
- echo "\"\"\""
100
- } > "$output_dir/$name.toml"
101
- finalize_output_file "$output_dir/$name.toml"
78
+ toml_escape_var "$name"; name_escaped="$IS_TOML_ESCAPED"
79
+ toml_escape_var "$description"; description_escaped="$IS_TOML_ESCAPED"
80
+
81
+ local header
82
+ header="${LS}name = \"$name_escaped\""
83
+ header+="${LS}description = \"$description_escaped\""
84
+ header+="${LS}model = \"$IS_MODEL\""
85
+ header+="${LS}model_reasoning_effort = \"$effort\""
86
+ header+="${LS}sandbox_mode = \"$sandbox\""
87
+ header+="${LS}"
88
+ header+="${LS}developer_instructions = \"\"\""
89
+
90
+ spec+="$path"$'\x1f'"$output_dir/$name.toml"$'\x1f'"fence"$'\x1f'"1"$'\x1f'"toml"$'\x1f'"$header"$'\x1f'"${LS}\"\"\""$'\n'
91
+ report+=" agent: $name.toml"$'\n'
102
92
  count=$((count + 1))
103
- echo " agent: $name.toml"
104
- done
105
- done < <(read_yaml_list "$config_file" "agents")
93
+ done < <(frontmatter_index "tier,access,description" "${files[@]}")
94
+
95
+ emit_wrapped_bodies "$spec"
96
+ printf '%s' "$report"
97
+ fi
106
98
 
107
99
  echo " -> Agents: $count"
108
100
  }