@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 +1 -1
- package/engine/VERSION +1 -1
- package/engine/adapters/agents.sh +75 -48
- package/engine/adapters/claude.sh +88 -58
- package/engine/adapters/codex.sh +39 -47
- package/engine/adapters/copilot.sh +120 -89
- package/engine/adapters/cursor.sh +110 -67
- package/engine/adapters/opencode.sh +77 -61
- package/engine/adapters/pi.sh +118 -80
- package/engine/lib/common.sh +746 -116
- package/engine/lib/contract.sh +2 -2
- package/engine/sync.sh +36 -14
- package/package.json +1 -1
- package/packages/sync/references/adapters.md +9 -1
|
@@ -11,6 +11,9 @@
|
|
|
11
11
|
# copilot-instructions.md is present.
|
|
12
12
|
# Skills: copy skill directories in full to .github/skills/{name}/
|
|
13
13
|
# Agents: -> .github/agents/{name}.agent.md (description, tools, model)
|
|
14
|
+
#
|
|
15
|
+
# Every per-file loop batches its work into one awk process (see the batched
|
|
16
|
+
# helpers in lib/common.sh): process spawns dominate sync time on Windows.
|
|
14
17
|
|
|
15
18
|
source "$(dirname "${BASH_SOURCE[0]}")/../lib/common.sh"
|
|
16
19
|
|
|
@@ -25,6 +28,38 @@ adapter_contract_copilot() {
|
|
|
25
28
|
adapter_contract_legacy "$output/copilot-instructions.md"
|
|
26
29
|
}
|
|
27
30
|
|
|
31
|
+
# copilot_paths_rows <file>... — batch form of the old per-file `paths:`
|
|
32
|
+
# joiner: one row per file in argument order, `path \x1f p1,p2,...`. Quotes
|
|
33
|
+
# are stripped anywhere in a pattern and the list is scanned from the first
|
|
34
|
+
# `paths:` line, exactly like the per-file reader did.
|
|
35
|
+
copilot_paths_rows() {
|
|
36
|
+
[ "$#" -gt 0 ] || return 0
|
|
37
|
+
awk '
|
|
38
|
+
BEGIN { US = sprintf("%c", 31) }
|
|
39
|
+
function store() { if (cur != "") R[cur] = row }
|
|
40
|
+
FNR == 1 { store(); cur = FILENAME; row = cur US; sep = ""; done_f = 0; in_paths = 0 }
|
|
41
|
+
{ sub(/\r$/, "") }
|
|
42
|
+
done_f { next }
|
|
43
|
+
/^paths:/ { in_paths = 1; next }
|
|
44
|
+
in_paths && /^ - / {
|
|
45
|
+
val = $0
|
|
46
|
+
sub(/^ - /, "", val)
|
|
47
|
+
gsub(/["\047]/, "", val)
|
|
48
|
+
row = row sep val
|
|
49
|
+
sep = ","
|
|
50
|
+
next
|
|
51
|
+
}
|
|
52
|
+
in_paths && !/^ - / && !/^$/ { done_f = 1 }
|
|
53
|
+
END {
|
|
54
|
+
store()
|
|
55
|
+
for (i = 1; i < ARGC; i++) {
|
|
56
|
+
if (ARGV[i] in R) print R[ARGV[i]]
|
|
57
|
+
else print ARGV[i] US
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
' "$@"
|
|
61
|
+
}
|
|
62
|
+
|
|
28
63
|
# Sync rules to Copilot format. Only path-scoped rules are emitted —
|
|
29
64
|
# always-on rules live in AGENTS.md (read by Copilot natively).
|
|
30
65
|
sync_copilot_rules() {
|
|
@@ -37,56 +72,50 @@ sync_copilot_rules() {
|
|
|
37
72
|
|
|
38
73
|
local scoped_count=0
|
|
39
74
|
|
|
75
|
+
local src f
|
|
76
|
+
local -a files=()
|
|
77
|
+
load_yaml_list "$config_file" "rules"
|
|
78
|
+
local list="$IS_YAML_LIST"
|
|
40
79
|
while IFS= read -r src; do
|
|
41
80
|
[ -z "$src" ] && continue
|
|
42
|
-
local dir
|
|
43
|
-
dir="$(resolve_source_dir "$repo_root" "$src")"
|
|
81
|
+
local dir="$repo_root/$src"
|
|
44
82
|
[ -d "$dir" ] || continue
|
|
45
83
|
for f in "$dir"/*.md; do
|
|
46
84
|
[ -f "$f" ] || continue
|
|
47
|
-
|
|
48
|
-
|
|
85
|
+
files+=("$f")
|
|
86
|
+
done
|
|
87
|
+
done <<< "$list"
|
|
49
88
|
|
|
50
|
-
|
|
89
|
+
local -a scoped=()
|
|
90
|
+
if [ "${#files[@]}" -gt 0 ]; then
|
|
91
|
+
local path hp
|
|
92
|
+
while IFS=$'\x1f' read -r path hp; do
|
|
93
|
+
[ -n "$path" ] || continue
|
|
51
94
|
[ "$hp" -eq 0 ] && continue
|
|
95
|
+
scoped+=("$path")
|
|
96
|
+
done < <(frontmatter_index "paths#" "${files[@]}")
|
|
97
|
+
fi
|
|
98
|
+
|
|
99
|
+
if [ "${#scoped[@]}" -gt 0 ]; then
|
|
100
|
+
local base paths_line spec="" report="" LS=$'\x1e'
|
|
101
|
+
while IFS=$'\x1f' read -r path paths_line; do
|
|
102
|
+
[ -n "$path" ] || continue
|
|
103
|
+
base="${path##*/}"; base="${base%.md}"
|
|
52
104
|
|
|
53
|
-
local
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
val = $0
|
|
62
|
-
sub(/^ - /, "", val)
|
|
63
|
-
gsub(/["\047]/, "", val)
|
|
64
|
-
printf "%s%s", sep, val
|
|
65
|
-
sep = ","
|
|
66
|
-
}
|
|
67
|
-
in_paths && !/^ - / && !/^$/ { exit }
|
|
68
|
-
END { print "" }
|
|
69
|
-
' "$f")
|
|
70
|
-
|
|
71
|
-
{
|
|
72
|
-
echo "---"
|
|
73
|
-
echo "applyTo: \"$paths_line\""
|
|
74
|
-
echo "---"
|
|
75
|
-
echo ""
|
|
76
|
-
awk '
|
|
77
|
-
BEGIN { in_fm=0; past_fm=0 }
|
|
78
|
-
{ sub(/\r$/, "") }
|
|
79
|
-
/^---$/ {
|
|
80
|
-
if (!past_fm) { in_fm = !in_fm; if (!in_fm) { past_fm=1 }; next }
|
|
81
|
-
}
|
|
82
|
-
past_fm || !in_fm { print }
|
|
83
|
-
' "$f"
|
|
84
|
-
} > "$instructions_dir/$base.instructions.md"
|
|
85
|
-
finalize_output_file "$instructions_dir/$base.instructions.md"
|
|
105
|
+
local header
|
|
106
|
+
header="${LS}---"
|
|
107
|
+
header+="${LS}applyTo: \"$paths_line\""
|
|
108
|
+
header+="${LS}---"
|
|
109
|
+
header+="${LS}"
|
|
110
|
+
|
|
111
|
+
spec+="$path"$'\x1f'"$instructions_dir/$base.instructions.md"$'\x1f'"fence_nofm"$'\x1f'"0"$'\x1f'"none"$'\x1f'"$header"$'\x1f\n'
|
|
112
|
+
report+=" rule: $base.instructions.md (scoped)"$'\n'
|
|
86
113
|
scoped_count=$((scoped_count + 1))
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
114
|
+
done < <(copilot_paths_rows "${scoped[@]}")
|
|
115
|
+
|
|
116
|
+
emit_wrapped_bodies "$spec"
|
|
117
|
+
printf '%s' "$report"
|
|
118
|
+
fi
|
|
90
119
|
|
|
91
120
|
echo " rules: $scoped_count scoped"
|
|
92
121
|
}
|
|
@@ -97,22 +126,30 @@ sync_copilot_skills() {
|
|
|
97
126
|
local config_file="$2"
|
|
98
127
|
local output_dir="$3"
|
|
99
128
|
|
|
100
|
-
local
|
|
129
|
+
local src d skill_name
|
|
130
|
+
local -a skill_dirs=()
|
|
131
|
+
load_yaml_list "$config_file" "skills"
|
|
132
|
+
local list="$IS_YAML_LIST"
|
|
101
133
|
while IFS= read -r src; do
|
|
102
134
|
[ -z "$src" ] && continue
|
|
103
|
-
local dir
|
|
104
|
-
dir="$(resolve_source_dir "$repo_root" "$src")"
|
|
135
|
+
local dir="$repo_root/$src"
|
|
105
136
|
[ -d "$dir" ] || continue
|
|
106
137
|
for d in "$dir"/*/; do
|
|
107
138
|
[ -d "$d" ] || continue
|
|
108
|
-
local skill_name
|
|
109
|
-
skill_name="$(basename "$d")"
|
|
110
139
|
[ -f "$d/SKILL.md" ] || continue
|
|
111
|
-
|
|
140
|
+
skill_dirs+=("$d")
|
|
141
|
+
done
|
|
142
|
+
done <<< "$list"
|
|
143
|
+
|
|
144
|
+
local count=0
|
|
145
|
+
if [ "${#skill_dirs[@]}" -gt 0 ]; then
|
|
146
|
+
copy_skill_bundle_dirs "$output_dir/skills" "${skill_dirs[@]}"
|
|
147
|
+
for d in "${skill_dirs[@]}"; do
|
|
148
|
+
skill_name="${d%/}"
|
|
112
149
|
count=$((count + 1))
|
|
113
|
-
echo " skill: $skill_name"
|
|
150
|
+
echo " skill: ${skill_name##*/}"
|
|
114
151
|
done
|
|
115
|
-
|
|
152
|
+
fi
|
|
116
153
|
|
|
117
154
|
echo " -> Skills: $count"
|
|
118
155
|
}
|
|
@@ -123,59 +160,55 @@ sync_copilot_agents() {
|
|
|
123
160
|
local config_file="$2"
|
|
124
161
|
local output_dir="$3"
|
|
125
162
|
|
|
126
|
-
local
|
|
163
|
+
local src f
|
|
164
|
+
local -a files=()
|
|
165
|
+
load_yaml_list "$config_file" "agents"
|
|
166
|
+
local list="$IS_YAML_LIST"
|
|
127
167
|
while IFS= read -r src; do
|
|
128
168
|
[ -z "$src" ] && continue
|
|
129
|
-
local dir
|
|
130
|
-
dir="$(resolve_source_dir "$repo_root" "$src")"
|
|
169
|
+
local dir="$repo_root/$src"
|
|
131
170
|
[ -d "$dir" ] || continue
|
|
132
171
|
for f in "$dir"/*.md; do
|
|
133
172
|
[ -f "$f" ] || continue
|
|
134
|
-
|
|
135
|
-
|
|
173
|
+
files+=("$f")
|
|
174
|
+
done
|
|
175
|
+
done <<< "$list"
|
|
136
176
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
description=$(get_frontmatter_value "description" "$f")
|
|
177
|
+
local count=0
|
|
178
|
+
if [ "${#files[@]}" -gt 0 ]; then
|
|
179
|
+
load_model_tiers "$config_file" "copilot"
|
|
141
180
|
|
|
142
|
-
|
|
143
|
-
|
|
181
|
+
local path tier access description name tools_line spec="" report="" LS=$'\x1e'
|
|
182
|
+
while IFS=$'\x1f' read -r path tier access description; do
|
|
183
|
+
[ -n "$path" ] || continue
|
|
184
|
+
name="${path##*/}"; name="${name%.md}"
|
|
185
|
+
resolve_model_var "$tier"
|
|
144
186
|
|
|
145
187
|
# Build tools list based on access. Tool aliases per Copilot custom-agent
|
|
146
188
|
# spec: `read`, `search`, `edit`, `execute`, `agent`, `web`, `todo`, `*`.
|
|
147
189
|
# Omitting `tools:` grants all; restrict to read/search for readonly access.
|
|
148
|
-
|
|
190
|
+
tools_line=""
|
|
149
191
|
if [ "$access" = "readonly" ]; then
|
|
150
192
|
tools_line="tools: [\"read\", \"search\"]"
|
|
151
193
|
fi
|
|
152
194
|
|
|
153
|
-
local
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
{
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
# Strip original frontmatter, keep body
|
|
165
|
-
awk '
|
|
166
|
-
BEGIN { in_fm=0; past_fm=0 }
|
|
167
|
-
{ sub(/\r$/, "") }
|
|
168
|
-
/^---$/ {
|
|
169
|
-
if (!past_fm) { in_fm = !in_fm; if (!in_fm) { past_fm=1 }; next }
|
|
170
|
-
}
|
|
171
|
-
past_fm { print }
|
|
172
|
-
' "$f"
|
|
173
|
-
} > "$output_dir/agents/$name.agent.md"
|
|
174
|
-
finalize_output_file "$output_dir/agents/$name.agent.md"
|
|
195
|
+
local header
|
|
196
|
+
yaml_dq_escape_var "$description"
|
|
197
|
+
header="${LS}---"
|
|
198
|
+
header+="${LS}description: \"$IS_YAML_ESCAPED\""
|
|
199
|
+
header+="${LS}model: $IS_MODEL"
|
|
200
|
+
[ -n "$tools_line" ] && header+="${LS}$tools_line"
|
|
201
|
+
header+="${LS}---"
|
|
202
|
+
header+="${LS}"
|
|
203
|
+
|
|
204
|
+
spec+="$path"$'\x1f'"$output_dir/agents/$name.agent.md"$'\x1f'"fence"$'\x1f'"0"$'\x1f'"none"$'\x1f'"$header"$'\x1f\n'
|
|
205
|
+
report+=" agent: $name.agent.md (tier=$tier -> model=$IS_MODEL)"$'\n'
|
|
175
206
|
count=$((count + 1))
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
207
|
+
done < <(frontmatter_index "tier,access,description" "${files[@]}")
|
|
208
|
+
|
|
209
|
+
emit_wrapped_bodies "$spec"
|
|
210
|
+
printf '%s' "$report"
|
|
211
|
+
fi
|
|
179
212
|
|
|
180
213
|
echo " -> Agents: $count"
|
|
181
214
|
}
|
|
@@ -191,9 +224,7 @@ sync_to_copilot() {
|
|
|
191
224
|
# Clean generated content (preserve workflows, etc.)
|
|
192
225
|
rm -rf "$output_dir/instructions" "$output_dir/prompts"
|
|
193
226
|
if [ -d "$output_dir/skills" ]; then
|
|
194
|
-
find "$output_dir/skills" -mindepth 1 -maxdepth 1 -type d
|
|
195
|
-
rm -rf "$d"
|
|
196
|
-
done
|
|
227
|
+
find "$output_dir/skills" -mindepth 1 -maxdepth 1 -type d -exec rm -rf {} +
|
|
197
228
|
fi
|
|
198
229
|
rm -rf "$output_dir/agents"
|
|
199
230
|
mkdir -p "$output_dir" "$output_dir/skills" "$output_dir/agents"
|
|
@@ -10,6 +10,9 @@
|
|
|
10
10
|
# same rules would cause double-loading and burn the context window.
|
|
11
11
|
# Skills: copy skill directories in full (SKILL.md + bundled resources)
|
|
12
12
|
# Agents: strip tier/access/tools/disallowedTools, add model + readonly:true
|
|
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
|
|
|
@@ -34,37 +37,51 @@ sync_cursor_rules() {
|
|
|
34
37
|
local config_file="$2"
|
|
35
38
|
local output_dir="$3"
|
|
36
39
|
|
|
40
|
+
local src f
|
|
41
|
+
local -a files=()
|
|
42
|
+
load_yaml_list "$config_file" "rules"
|
|
43
|
+
local list="$IS_YAML_LIST"
|
|
37
44
|
while IFS= read -r src; do
|
|
38
45
|
[ -z "$src" ] && continue
|
|
39
|
-
local dir
|
|
40
|
-
dir="$(resolve_source_dir "$repo_root" "$src")"
|
|
46
|
+
local dir="$repo_root/$src"
|
|
41
47
|
[ -d "$dir" ] || continue
|
|
42
48
|
for f in "$dir"/*.md; do
|
|
43
49
|
[ -f "$f" ] || continue
|
|
44
|
-
|
|
45
|
-
hp=$(has_paths "$f")
|
|
46
|
-
|
|
47
|
-
# Skip always-on rules: AGENTS.md (canonical) carries them.
|
|
48
|
-
if [ "$hp" -eq 0 ]; then
|
|
49
|
-
continue
|
|
50
|
-
fi
|
|
51
|
-
|
|
52
|
-
local base
|
|
53
|
-
base="$(basename "$f" .md)"
|
|
54
|
-
|
|
55
|
-
# Path-scoped rule -> Auto Attached (paths -> globs)
|
|
56
|
-
awk '
|
|
57
|
-
{
|
|
58
|
-
sub(/\r$/, "")
|
|
59
|
-
sub(/^paths:/, "globs:")
|
|
60
|
-
}
|
|
61
|
-
NR==1 { print; print "alwaysApply: false"; next }
|
|
62
|
-
{ print }
|
|
63
|
-
' "$f" > "$output_dir/rules/$base.mdc"
|
|
64
|
-
finalize_output_file "$output_dir/rules/$base.mdc"
|
|
65
|
-
echo " rule: $base.mdc (scoped)"
|
|
50
|
+
files+=("$f")
|
|
66
51
|
done
|
|
67
|
-
done
|
|
52
|
+
done <<< "$list"
|
|
53
|
+
[ "${#files[@]}" -gt 0 ] || return 0
|
|
54
|
+
|
|
55
|
+
# Skip always-on rules: AGENTS.md (canonical) carries them.
|
|
56
|
+
local path hp base
|
|
57
|
+
local -a scoped=()
|
|
58
|
+
while IFS=$'\x1f' read -r path hp; do
|
|
59
|
+
[ -n "$path" ] || continue
|
|
60
|
+
[ "$hp" -eq 0 ] && continue
|
|
61
|
+
scoped+=("$path")
|
|
62
|
+
done < <(frontmatter_index "paths#" "${files[@]}")
|
|
63
|
+
[ "${#scoped[@]}" -gt 0 ] || return 0
|
|
64
|
+
|
|
65
|
+
# Path-scoped rule -> Auto Attached (paths -> globs)
|
|
66
|
+
is_fin_awk_vars
|
|
67
|
+
awk "${IS_FIN_V[@]}" -v dst="$output_dir/rules" "$IS_AWK_LIB"'
|
|
68
|
+
FNR == 1 {
|
|
69
|
+
if (out != "") close(out)
|
|
70
|
+
nm = base_name(FILENAME)
|
|
71
|
+
sub(/\.md$/, ".mdc", nm)
|
|
72
|
+
out = dst "/" nm
|
|
73
|
+
}
|
|
74
|
+
{
|
|
75
|
+
sub(/\r$/, "")
|
|
76
|
+
sub(/^paths:/, "globs:")
|
|
77
|
+
}
|
|
78
|
+
FNR == 1 { print fin_line($0) > out; print fin_line("alwaysApply: false") > out; next }
|
|
79
|
+
{ print fin_line($0) > out }
|
|
80
|
+
' "${scoped[@]}"
|
|
81
|
+
for f in "${scoped[@]}"; do
|
|
82
|
+
base="${f##*/}"; base="${base%.md}"
|
|
83
|
+
echo " rule: $base.mdc (scoped)"
|
|
84
|
+
done
|
|
68
85
|
}
|
|
69
86
|
|
|
70
87
|
# Sync skills to Cursor format (copy as-is)
|
|
@@ -73,20 +90,26 @@ sync_cursor_skills() {
|
|
|
73
90
|
local config_file="$2"
|
|
74
91
|
local output_dir="$3"
|
|
75
92
|
|
|
93
|
+
local src d skill_name
|
|
94
|
+
local -a skill_dirs=()
|
|
95
|
+
load_yaml_list "$config_file" "skills"
|
|
96
|
+
local list="$IS_YAML_LIST"
|
|
76
97
|
while IFS= read -r src; do
|
|
77
98
|
[ -z "$src" ] && continue
|
|
78
|
-
local dir
|
|
79
|
-
dir="$(resolve_source_dir "$repo_root" "$src")"
|
|
99
|
+
local dir="$repo_root/$src"
|
|
80
100
|
[ -d "$dir" ] || continue
|
|
81
101
|
for d in "$dir"/*/; do
|
|
82
102
|
[ -d "$d" ] || continue
|
|
83
|
-
local skill_name
|
|
84
|
-
skill_name="$(basename "$d")"
|
|
85
103
|
[ -f "$d/SKILL.md" ] || continue
|
|
86
|
-
|
|
87
|
-
echo " skill: $skill_name"
|
|
104
|
+
skill_dirs+=("$d")
|
|
88
105
|
done
|
|
89
|
-
done
|
|
106
|
+
done <<< "$list"
|
|
107
|
+
[ "${#skill_dirs[@]}" -gt 0 ] || return 0
|
|
108
|
+
copy_skill_bundle_dirs "$output_dir/skills" "${skill_dirs[@]}"
|
|
109
|
+
for d in "${skill_dirs[@]}"; do
|
|
110
|
+
skill_name="${d%/}"
|
|
111
|
+
echo " skill: ${skill_name##*/}"
|
|
112
|
+
done
|
|
90
113
|
}
|
|
91
114
|
|
|
92
115
|
# Sync agents to Cursor format
|
|
@@ -95,47 +118,67 @@ sync_cursor_agents() {
|
|
|
95
118
|
local config_file="$2"
|
|
96
119
|
local output_dir="$3"
|
|
97
120
|
|
|
121
|
+
local src f
|
|
122
|
+
local -a files=()
|
|
123
|
+
load_yaml_list "$config_file" "agents"
|
|
124
|
+
local list="$IS_YAML_LIST"
|
|
98
125
|
while IFS= read -r src; do
|
|
99
126
|
[ -z "$src" ] && continue
|
|
100
|
-
local dir
|
|
101
|
-
dir="$(resolve_source_dir "$repo_root" "$src")"
|
|
127
|
+
local dir="$repo_root/$src"
|
|
102
128
|
[ -d "$dir" ] || continue
|
|
103
129
|
for f in "$dir"/*.md; do
|
|
104
130
|
[ -f "$f" ] || continue
|
|
105
|
-
|
|
106
|
-
name="$(basename "$f")"
|
|
107
|
-
|
|
108
|
-
local tier access
|
|
109
|
-
tier=$(get_frontmatter_value "tier" "$f")
|
|
110
|
-
access=$(get_frontmatter_value "access" "$f")
|
|
111
|
-
|
|
112
|
-
local cursor_model cursor_readonly
|
|
113
|
-
cursor_model=$(get_model "$config_file" "cursor" "$tier")
|
|
114
|
-
cursor_readonly=""
|
|
115
|
-
[ "$access" = "readonly" ] && cursor_readonly="readonly: true"
|
|
116
|
-
|
|
117
|
-
# Always emit model: line (even when value matches Cursor's default)
|
|
118
|
-
# so config is explicit and grep-able.
|
|
119
|
-
awk -v cm="$cursor_model" -v cr="$cursor_readonly" '
|
|
120
|
-
BEGIN { count=0 }
|
|
121
|
-
/^tier:/ { next }
|
|
122
|
-
/^access:/ { next }
|
|
123
|
-
/^tools:/ { next }
|
|
124
|
-
/^disallowedTools:/ { next }
|
|
125
|
-
{
|
|
126
|
-
sub(/\r$/, "")
|
|
127
|
-
}
|
|
128
|
-
/^---$/ { count++ }
|
|
129
|
-
count==2 && /^---$/ {
|
|
130
|
-
print "model: " cm
|
|
131
|
-
if (cr != "") print cr
|
|
132
|
-
}
|
|
133
|
-
{ print }
|
|
134
|
-
' "$f" > "$output_dir/agents/$name"
|
|
135
|
-
finalize_output_file "$output_dir/agents/$name"
|
|
136
|
-
echo " agent: $name (tier=$tier -> cursor)"
|
|
131
|
+
files+=("$f")
|
|
137
132
|
done
|
|
138
|
-
done
|
|
133
|
+
done <<< "$list"
|
|
134
|
+
[ "${#files[@]}" -gt 0 ] || return 0
|
|
135
|
+
|
|
136
|
+
load_model_tiers "$config_file" "cursor"
|
|
137
|
+
|
|
138
|
+
local path tier access spec="" report="" cursor_readonly
|
|
139
|
+
while IFS=$'\x1f' read -r path tier access; do
|
|
140
|
+
[ -n "$path" ] || continue
|
|
141
|
+
resolve_model_var "$tier"
|
|
142
|
+
cursor_readonly=""
|
|
143
|
+
[ "$access" = "readonly" ] && cursor_readonly="readonly: true"
|
|
144
|
+
spec+="$path"$'\x1f'"$IS_MODEL"$'\x1f'"$cursor_readonly"$'\n'
|
|
145
|
+
report+=" agent: ${path##*/} (tier=$tier -> cursor)"$'\n'
|
|
146
|
+
done < <(frontmatter_index "tier,access" "${files[@]}")
|
|
147
|
+
|
|
148
|
+
# Always emit model: line (even when value matches Cursor's default)
|
|
149
|
+
# so config is explicit and grep-able.
|
|
150
|
+
is_fin_awk_vars
|
|
151
|
+
IS_MAP_SPEC="$spec" awk "${IS_FIN_V[@]}" -v dst="$output_dir/agents" "$IS_AWK_LIB"'
|
|
152
|
+
BEGIN {
|
|
153
|
+
US = sprintf("%c", 31)
|
|
154
|
+
n = split(ENVIRON["IS_MAP_SPEC"], recs, "\n")
|
|
155
|
+
for (i = 1; i <= n; i++) {
|
|
156
|
+
if (recs[i] == "") continue
|
|
157
|
+
split(recs[i], f, US)
|
|
158
|
+
MODEL[f[1]] = f[2]; RO[f[1]] = f[3]
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
FNR == 1 {
|
|
162
|
+
if (out != "") close(out)
|
|
163
|
+
out = dst "/" base_name(FILENAME)
|
|
164
|
+
count = 0
|
|
165
|
+
}
|
|
166
|
+
/^tier:/ { next }
|
|
167
|
+
/^access:/ { next }
|
|
168
|
+
/^tools:/ { next }
|
|
169
|
+
/^disallowedTools:/ { next }
|
|
170
|
+
{ sub(/\r$/, "") }
|
|
171
|
+
/^---$/ { count++ }
|
|
172
|
+
count == 2 && /^---$/ {
|
|
173
|
+
print fin_line("model: " MODEL[FILENAME]) > out
|
|
174
|
+
if (RO[FILENAME] != "") print fin_line(RO[FILENAME]) > out
|
|
175
|
+
}
|
|
176
|
+
{ print fin_line($0) > out }
|
|
177
|
+
' "${files[@]}"
|
|
178
|
+
for f in "${files[@]}"; do
|
|
179
|
+
[ -s "$f" ] || : > "$output_dir/agents/${f##*/}"
|
|
180
|
+
done
|
|
181
|
+
printf '%s' "$report"
|
|
139
182
|
}
|
|
140
183
|
|
|
141
184
|
# Main entry point for Cursor adapter
|