@ainova-systems/intelligence 0.11.3 → 0.11.5
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/cli/commands/sync.sh +5 -3
- package/cli/intelligence +1 -1
- package/engine/ENGINE_SHA +1 -1
- package/engine/VERSION +1 -1
- package/engine/adapters/agents.sh +68 -80
- package/engine/adapters/claude.sh +88 -58
- package/engine/adapters/codex.sh +79 -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 +854 -128
- package/engine/lib/contract.sh +2 -2
- package/engine/sync.sh +39 -14
- package/package.json +1 -1
- package/packages/sync/agents/intelligence-architect.md +2 -0
- package/packages/sync/references/adapters.md +13 -1
- package/packages/sync/references/conventions.md +1 -1
- package/packages/sync/rules/intelligence-authoring.md +1 -1
- package/packages/sync/skills/intelligence-compact-context/SKILL.md +118 -0
- package/packages/sync/skills/intelligence-compact-context/references/principles.md +58 -0
- package/packages/sync/skills/intelligence-review-skills/SKILL.md +18 -3
package/cli/commands/sync.sh
CHANGED
|
@@ -57,9 +57,10 @@ if [ "$compact" -eq 0 ]; then
|
|
|
57
57
|
exit $?
|
|
58
58
|
fi
|
|
59
59
|
|
|
60
|
-
# Compact mode
|
|
61
|
-
# combined stream means a failure still returns every diagnostic
|
|
62
|
-
# lifecycle preflight, locked restore or the engine, together with
|
|
60
|
+
# Compact mode keeps actionable one-line warnings on success. Buffering the
|
|
61
|
+
# complete combined stream means a failure still returns every diagnostic
|
|
62
|
+
# emitted by lifecycle preflight, locked restore or the engine, together with
|
|
63
|
+
# its real rc.
|
|
63
64
|
compact_output="$(mktemp -t intelligence-sync-XXXXXX)"
|
|
64
65
|
trap 'rm -f "$compact_output"' EXIT
|
|
65
66
|
rc=0
|
|
@@ -76,5 +77,6 @@ if [ -z "$status_line" ] || [ -z "$done_line" ]; then
|
|
|
76
77
|
echo "ERROR: sync succeeded without its final status contract" >&2
|
|
77
78
|
exit 1
|
|
78
79
|
fi
|
|
80
|
+
grep -E '^(WARNING:|CONTEXT:)' "$compact_output" || true
|
|
79
81
|
echo "$status_line"
|
|
80
82
|
echo "$done_line"
|
package/cli/intelligence
CHANGED
|
@@ -47,7 +47,7 @@ Usage: intelligence <command> [args]
|
|
|
47
47
|
--targets a,b --dir name --bare --no-sync New-project options
|
|
48
48
|
--force Accept a dirty worktree during legacy project conversion
|
|
49
49
|
sync [adapter] [--compact] Restore locked content, then render enabled adapters
|
|
50
|
-
--compact On success show
|
|
50
|
+
--compact On success show context, warnings and final status; on failure show diagnostics
|
|
51
51
|
update [@scope/name] Show an update plan; ask before applying it
|
|
52
52
|
--preview Show the plan without asking or writing
|
|
53
53
|
--apply Apply the plan without asking
|
package/engine/ENGINE_SHA
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
bd688bcdb5443d808a72ed4e63805a65255a7d02
|
package/engine/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
0.11.
|
|
1
|
+
0.11.5
|
|
@@ -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,26 @@ agents_md_append_agents_table() {
|
|
|
55
58
|
local rows=""
|
|
56
59
|
local count=0
|
|
57
60
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
while IFS
|
|
67
|
-
[ -
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
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'
|
|
61
|
+
local f
|
|
62
|
+
local -a files=()
|
|
63
|
+
while IFS= read -r f; do
|
|
64
|
+
[ -n "$f" ] && files+=("$f")
|
|
65
|
+
done < <(source_artifact_files "$repo_root" "$config_file" "agents")
|
|
66
|
+
|
|
67
|
+
if [ "${#files[@]}" -gt 0 ]; then
|
|
68
|
+
local path tier access desc name
|
|
69
|
+
while IFS=$'\x1f' read -r path tier access desc; do
|
|
70
|
+
[ -n "$path" ] || continue
|
|
71
|
+
name="${path##*/}"; name="${name%.md}"
|
|
72
|
+
repo_rel_link_var "$repo_root" "$path"
|
|
73
|
+
if [ -n "$IS_REPO_REL" ]; then
|
|
74
|
+
rows+="| [$name]($IS_REPO_REL) | ${tier:--} | ${access:--} | ${desc:--} |"$'\n'
|
|
76
75
|
else
|
|
77
76
|
rows+="| $name | ${tier:--} | ${access:--} | ${desc:--} |"$'\n'
|
|
78
77
|
fi
|
|
79
78
|
count=$((count + 1))
|
|
80
|
-
done < <(
|
|
81
|
-
|
|
79
|
+
done < <(frontmatter_index "tier,access,description" "${files[@]}")
|
|
80
|
+
fi
|
|
82
81
|
|
|
83
82
|
[ "$count" -eq 0 ] && return 0
|
|
84
83
|
|
|
@@ -102,31 +101,26 @@ agents_md_append_skills_table() {
|
|
|
102
101
|
local rows=""
|
|
103
102
|
local count=0
|
|
104
103
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
dirname="$
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
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'
|
|
104
|
+
local f dirname
|
|
105
|
+
local -a skill_files=()
|
|
106
|
+
while IFS= read -r f; do
|
|
107
|
+
[ -n "$f" ] && skill_files+=("$f")
|
|
108
|
+
done < <(source_artifact_files "$repo_root" "$config_file" "skills")
|
|
109
|
+
|
|
110
|
+
if [ "${#skill_files[@]}" -gt 0 ]; then
|
|
111
|
+
local path desc
|
|
112
|
+
while IFS=$'\x1f' read -r path desc; do
|
|
113
|
+
[ -n "$path" ] || continue
|
|
114
|
+
dirname="${path%/SKILL.md}"; dirname="${dirname##*/}"
|
|
115
|
+
repo_rel_link_var "$repo_root" "$path"
|
|
116
|
+
if [ -n "$IS_REPO_REL" ]; then
|
|
117
|
+
rows+="| [$dirname]($IS_REPO_REL) | ${desc:--} |"$'\n'
|
|
124
118
|
else
|
|
125
119
|
rows+="| $dirname | ${desc:--} |"$'\n'
|
|
126
120
|
fi
|
|
127
121
|
count=$((count + 1))
|
|
128
|
-
done < <(
|
|
129
|
-
|
|
122
|
+
done < <(frontmatter_index "description" "${skill_files[@]}")
|
|
123
|
+
fi
|
|
130
124
|
|
|
131
125
|
[ "$count" -eq 0 ] && return 0
|
|
132
126
|
|
|
@@ -151,33 +145,32 @@ agents_md_append_rules_list() {
|
|
|
151
145
|
local count=0
|
|
152
146
|
local global_rule_files=()
|
|
153
147
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
while IFS
|
|
163
|
-
[ -
|
|
164
|
-
|
|
165
|
-
name="$(basename "$f" .md)"
|
|
166
|
-
rel="$(repo_rel_link "$repo_root" "$f")"
|
|
148
|
+
local f
|
|
149
|
+
local -a files=()
|
|
150
|
+
while IFS= read -r f; do
|
|
151
|
+
[ -n "$f" ] && files+=("$f")
|
|
152
|
+
done < <(source_artifact_files "$repo_root" "$config_file" "rules")
|
|
153
|
+
|
|
154
|
+
if [ "${#files[@]}" -gt 0 ]; then
|
|
155
|
+
local path hp name scope
|
|
156
|
+
while IFS=$'\x1f' read -r path hp; do
|
|
157
|
+
[ -n "$path" ] || continue
|
|
158
|
+
name="${path##*/}"; name="${name%.md}"
|
|
167
159
|
scope="global"
|
|
168
|
-
if [ "$
|
|
160
|
+
if [ "$hp" != "0" ]; then
|
|
169
161
|
scope="scoped"
|
|
170
162
|
else
|
|
171
|
-
global_rule_files+=("$
|
|
163
|
+
global_rule_files+=("$path")
|
|
172
164
|
fi
|
|
173
|
-
|
|
174
|
-
|
|
165
|
+
repo_rel_link_var "$repo_root" "$path"
|
|
166
|
+
if [ -n "$IS_REPO_REL" ]; then
|
|
167
|
+
lines+="- [$name]($IS_REPO_REL) ($scope)"$'\n'
|
|
175
168
|
else
|
|
176
169
|
lines+="- $name ($scope)"$'\n'
|
|
177
170
|
fi
|
|
178
171
|
count=$((count + 1))
|
|
179
|
-
done < <(
|
|
180
|
-
|
|
172
|
+
done < <(frontmatter_index "paths#" "${files[@]}")
|
|
173
|
+
fi
|
|
181
174
|
|
|
182
175
|
[ "$count" -eq 0 ] && return 0
|
|
183
176
|
|
|
@@ -206,28 +199,25 @@ agents_md_append_rules_list() {
|
|
|
206
199
|
echo "<!-- Inlined from always-on rules in $content_rel/rules/ -->"
|
|
207
200
|
echo ""
|
|
208
201
|
} >> "$output"
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
done
|
|
202
|
+
# One awk inlines every global rule body, with a blank line after
|
|
203
|
+
# each — the same output the per-file passes produced.
|
|
204
|
+
awk '
|
|
205
|
+
FNR == 1 { if (NR != 1) print ""; in_fm = 0; past_fm = 0 }
|
|
206
|
+
{ sub(/\r$/, "") }
|
|
207
|
+
/^---$/ {
|
|
208
|
+
if (!past_fm) { in_fm = !in_fm; if (!in_fm) { past_fm = 1 }; next }
|
|
209
|
+
}
|
|
210
|
+
past_fm || !in_fm { print }
|
|
211
|
+
END { print "" }
|
|
212
|
+
' "${global_rule_files[@]}" >> "$output"
|
|
221
213
|
echo " rules: ${#global_rule_files[@]} global rule(s) inlined"
|
|
222
214
|
fi
|
|
223
215
|
}
|
|
224
216
|
|
|
225
217
|
# Main entry point for AGENTS.md adapter
|
|
226
218
|
adapter_contract_agents() {
|
|
227
|
-
local output
|
|
228
|
-
|
|
229
|
-
output="${output%/}/AGENTS.md"
|
|
230
|
-
fi
|
|
219
|
+
local output
|
|
220
|
+
output="$(agents_output_path "$1")"
|
|
231
221
|
adapter_contract_version 1
|
|
232
222
|
adapter_contract_owned "$output"
|
|
233
223
|
adapter_contract_legacy "AGENTS.md"
|
|
@@ -244,10 +234,8 @@ sync_to_agents() {
|
|
|
244
234
|
# If it looks like a directory lexically (trailing slash or no .md
|
|
245
235
|
# extension), append the default filename. The ownership contract uses the
|
|
246
236
|
# same rule, so filesystem state cannot make its write-set ambiguous.
|
|
247
|
-
local output_file
|
|
248
|
-
|
|
249
|
-
output_file="${output_file%/}/AGENTS.md"
|
|
250
|
-
fi
|
|
237
|
+
local output_file
|
|
238
|
+
output_file="$(agents_output_path "$output_dir")"
|
|
251
239
|
|
|
252
240
|
mkdir -p "$(dirname "$output_file")"
|
|
253
241
|
|
|
@@ -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
|
-
|
|
40
|
-
finalize_output_file "$output_dir/rules/$(basename "$f")"
|
|
41
|
-
echo " rule: $(basename "$f")"
|
|
45
|
+
files+=("$f")
|
|
42
46
|
done
|
|
43
|
-
done
|
|
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
|
-
|
|
63
|
-
echo " skill: $skill_name"
|
|
72
|
+
skill_dirs+=("$d")
|
|
64
73
|
done
|
|
65
|
-
done
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
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
|
-
|
|
100
|
+
files+=("$f")
|
|
119
101
|
done
|
|
120
|
-
done
|
|
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
|
|
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
|
|
package/engine/adapters/codex.sh
CHANGED
|
@@ -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
|
|
|
@@ -23,6 +26,44 @@ adapter_contract_codex() {
|
|
|
23
26
|
adapter_contract_ignore "$output/agents/"
|
|
24
27
|
}
|
|
25
28
|
|
|
29
|
+
# Codex-specific guard for its documented project-instruction byte budget.
|
|
30
|
+
# A personal/project Codex config may already raise the actual limit, so the
|
|
31
|
+
# manifest exposes one warning setting: false disables it, while a positive
|
|
32
|
+
# byte count matches an effective limit the adapter cannot discover itself.
|
|
33
|
+
codex_warn_project_doc_size() {
|
|
34
|
+
local repo_root="$1"
|
|
35
|
+
local config_file="$2"
|
|
36
|
+
local warning_setting warning_limit=32768
|
|
37
|
+
warning_setting="$(get_target_field "$config_file" "codex" "warn_project_doc_limit")"
|
|
38
|
+
case "$warning_setting" in
|
|
39
|
+
''|true) ;;
|
|
40
|
+
false) return 0 ;;
|
|
41
|
+
*[!0-9]*|0|0*)
|
|
42
|
+
echo "ERROR: targets.codex.warn_project_doc_limit must be true, false, or a positive byte count without leading zeros." >&2
|
|
43
|
+
return 1
|
|
44
|
+
;;
|
|
45
|
+
*) warning_limit="$warning_setting" ;;
|
|
46
|
+
esac
|
|
47
|
+
|
|
48
|
+
target_output_var "$config_file" "agents"
|
|
49
|
+
local output
|
|
50
|
+
output="$(agents_output_path "${IS_TGT_OUTPUT:-.agents}")"
|
|
51
|
+
|
|
52
|
+
local output_file="$repo_root/$output"
|
|
53
|
+
[ -f "$output_file" ] || return 0
|
|
54
|
+
|
|
55
|
+
local bytes
|
|
56
|
+
bytes="$(context_files_bytes "$output_file")"
|
|
57
|
+
[ "$bytes" -gt "$warning_limit" ] || return 0
|
|
58
|
+
|
|
59
|
+
local recommended="$warning_limit"
|
|
60
|
+
while [ "$recommended" -lt "$bytes" ]; do
|
|
61
|
+
recommended=$((recommended * 2))
|
|
62
|
+
done
|
|
63
|
+
|
|
64
|
+
echo "WARNING: Codex may truncate $output: $bytes bytes exceeds the $warning_limit-byte Intelligence warning threshold; set project_doc_max_bytes = $recommended in Codex config.toml and restart Codex, reduce/split the instructions, set targets.codex.warn_project_doc_limit to the effective byte limit, or set it to false to disable this warning."
|
|
65
|
+
}
|
|
66
|
+
|
|
26
67
|
# Sync skills to Codex format (.agents/skills/{name}/SKILL.md)
|
|
27
68
|
sync_codex_skills() {
|
|
28
69
|
local repo_root="$1"
|
|
@@ -38,24 +79,29 @@ sync_codex_agents() {
|
|
|
38
79
|
local config_file="$2"
|
|
39
80
|
local output_dir="$3"
|
|
40
81
|
|
|
41
|
-
local
|
|
82
|
+
local src f
|
|
83
|
+
local -a files=()
|
|
84
|
+
load_yaml_list "$config_file" "agents"
|
|
85
|
+
local list="$IS_YAML_LIST"
|
|
42
86
|
while IFS= read -r src; do
|
|
43
87
|
[ -z "$src" ] && continue
|
|
44
|
-
local dir
|
|
45
|
-
dir="$(resolve_source_dir "$repo_root" "$src")"
|
|
88
|
+
local dir="$repo_root/$src"
|
|
46
89
|
[ -d "$dir" ] || continue
|
|
47
90
|
for f in "$dir"/*.md; do
|
|
48
91
|
[ -f "$f" ] || continue
|
|
49
|
-
|
|
50
|
-
|
|
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")
|
|
92
|
+
files+=("$f")
|
|
93
|
+
done
|
|
94
|
+
done <<< "$list"
|
|
56
95
|
|
|
57
|
-
|
|
58
|
-
|
|
96
|
+
local count=0
|
|
97
|
+
if [ "${#files[@]}" -gt 0 ]; then
|
|
98
|
+
load_model_tiers "$config_file" "codex"
|
|
99
|
+
|
|
100
|
+
local path tier access description name effort sandbox spec="" report="" LS=$'\x1e'
|
|
101
|
+
while IFS=$'\x1f' read -r path tier access description; do
|
|
102
|
+
[ -n "$path" ] || continue
|
|
103
|
+
name="${path##*/}"; name="${name%.md}"
|
|
104
|
+
resolve_model_var "$tier"
|
|
59
105
|
case "$tier" in
|
|
60
106
|
heavy) effort="high" ;;
|
|
61
107
|
standard) effort="medium" ;;
|
|
@@ -66,43 +112,27 @@ sync_codex_agents() {
|
|
|
66
112
|
readonly) sandbox="read-only" ;;
|
|
67
113
|
*) sandbox="workspace-write" ;;
|
|
68
114
|
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
115
|
local name_escaped description_escaped
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
finalize_output_file "$output_dir/$name.toml"
|
|
116
|
+
toml_escape_var "$name"; name_escaped="$IS_TOML_ESCAPED"
|
|
117
|
+
toml_escape_var "$description"; description_escaped="$IS_TOML_ESCAPED"
|
|
118
|
+
|
|
119
|
+
local header
|
|
120
|
+
header="${LS}name = \"$name_escaped\""
|
|
121
|
+
header+="${LS}description = \"$description_escaped\""
|
|
122
|
+
header+="${LS}model = \"$IS_MODEL\""
|
|
123
|
+
header+="${LS}model_reasoning_effort = \"$effort\""
|
|
124
|
+
header+="${LS}sandbox_mode = \"$sandbox\""
|
|
125
|
+
header+="${LS}"
|
|
126
|
+
header+="${LS}developer_instructions = \"\"\""
|
|
127
|
+
|
|
128
|
+
spec+="$path"$'\x1f'"$output_dir/$name.toml"$'\x1f'"fence"$'\x1f'"1"$'\x1f'"toml"$'\x1f'"$header"$'\x1f'"${LS}\"\"\""$'\n'
|
|
129
|
+
report+=" agent: $name.toml"$'\n'
|
|
102
130
|
count=$((count + 1))
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
131
|
+
done < <(frontmatter_index "tier,access,description" "${files[@]}")
|
|
132
|
+
|
|
133
|
+
emit_wrapped_bodies "$spec"
|
|
134
|
+
printf '%s' "$report"
|
|
135
|
+
fi
|
|
106
136
|
|
|
107
137
|
echo " -> Agents: $count"
|
|
108
138
|
}
|
|
@@ -125,4 +155,6 @@ sync_to_codex() {
|
|
|
125
155
|
rm -rf "$agents_dir"
|
|
126
156
|
mkdir -p "$agents_dir"
|
|
127
157
|
sync_codex_agents "$repo_root" "$config_file" "$agents_dir"
|
|
158
|
+
|
|
159
|
+
codex_warn_project_doc_size "$repo_root" "$config_file"
|
|
128
160
|
}
|