@ainova-systems/intelligence 0.11.0-rc.1
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/LICENSE +21 -0
- package/README.md +46 -0
- package/bin/intelligence.js +59 -0
- package/cli/commands/add.sh +133 -0
- package/cli/commands/doctor.sh +100 -0
- package/cli/commands/init.sh +96 -0
- package/cli/commands/install.sh +84 -0
- package/cli/commands/list.sh +28 -0
- package/cli/commands/migrate.sh +251 -0
- package/cli/commands/registry.sh +51 -0
- package/cli/commands/remove.sh +39 -0
- package/cli/commands/status.sh +34 -0
- package/cli/commands/sync.sh +22 -0
- package/cli/commands/update.sh +59 -0
- package/cli/commands/upgrade.sh +27 -0
- package/cli/intelligence +71 -0
- package/cli/lib/cli-common.sh +149 -0
- package/cli/lib/lockfile.sh +97 -0
- package/cli/lib/manifest.sh +211 -0
- package/cli/lib/registry.sh +141 -0
- package/cli/lib/semver.sh +127 -0
- package/engine/INIT.md +498 -0
- package/engine/agents/intelligence-architect.md +53 -0
- package/engine/agents/intelligence-operator.md +49 -0
- package/engine/docs/ADAPTERS.md +212 -0
- package/engine/docs/CLI.md +91 -0
- package/engine/docs/CONVENTIONS.md +440 -0
- package/engine/rules/intelligence-authoring.md +114 -0
- package/engine/scripts/VERSION +1 -0
- package/engine/scripts/adapters/_template.sh +86 -0
- package/engine/scripts/adapters/agents.sh +299 -0
- package/engine/scripts/adapters/claude.sh +136 -0
- package/engine/scripts/adapters/codex.sh +118 -0
- package/engine/scripts/adapters/copilot.sh +193 -0
- package/engine/scripts/adapters/cursor.sh +146 -0
- package/engine/scripts/adapters/opencode.sh +200 -0
- package/engine/scripts/adapters/pi.sh +256 -0
- package/engine/scripts/lib/common.sh +1602 -0
- package/engine/scripts/lib/layout.sh +51 -0
- package/engine/scripts/lib/migrations.sh +708 -0
- package/engine/scripts/sync.sh +311 -0
- package/engine/scripts/update.sh +237 -0
- package/engine/skills/intelligence-add-agent/SKILL.md +62 -0
- package/engine/skills/intelligence-add-rule/SKILL.md +54 -0
- package/engine/skills/intelligence-add-skill/SKILL.md +53 -0
- package/engine/skills/intelligence-extract-skill/SKILL.md +47 -0
- package/engine/skills/intelligence-install-adapter/SKILL.md +31 -0
- package/engine/skills/intelligence-learn-from-context/SKILL.md +69 -0
- package/engine/skills/intelligence-review-skills/SKILL.md +86 -0
- package/engine/skills/intelligence-sync/SKILL.md +18 -0
- package/engine/skills/intelligence-uninstall-adapter/SKILL.md +42 -0
- package/engine/skills/intelligence-update/SKILL.md +159 -0
- package/package.json +39 -0
- package/registry/index.yaml +15 -0
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# intelligence-sync: Adapter template
|
|
3
|
+
# Copy this file to create a new IDE adapter.
|
|
4
|
+
#
|
|
5
|
+
# This file is NOT executable as-is — `<name>` placeholders below would be
|
|
6
|
+
# parsed by bash as input redirection (`<` operator). Replace every
|
|
7
|
+
# occurrence with your adapter name before sourcing.
|
|
8
|
+
#
|
|
9
|
+
# Required:
|
|
10
|
+
# 1. Name the file: <ide-name>.sh (e.g., myide.sh)
|
|
11
|
+
# 2. Replace every `<name>` placeholder with your adapter name
|
|
12
|
+
# 3. Implement sync_to_<name>() function
|
|
13
|
+
# 4. Add target to config.yaml:
|
|
14
|
+
# targets:
|
|
15
|
+
# <name>: { enabled: true, output: ".<name>" }
|
|
16
|
+
#
|
|
17
|
+
# The sync_to_<name>() function receives:
|
|
18
|
+
# $1 = repo_root — absolute path to the project root
|
|
19
|
+
# $2 = config_file — absolute path to config.yaml
|
|
20
|
+
# $3 = output_dir — absolute path to the output directory (e.g., .myide/)
|
|
21
|
+
#
|
|
22
|
+
# Available library functions (from lib/common.sh):
|
|
23
|
+
# normalize_file_to_lf(file) — fix CRLF line endings
|
|
24
|
+
# lint_frontmatter(file) — warn about unquoted colons / leading tabs
|
|
25
|
+
# get_frontmatter_value(key, file) — extract YAML frontmatter value
|
|
26
|
+
# has_frontmatter(file) — check if file has --- header
|
|
27
|
+
# has_paths(file) — check if file has paths: field
|
|
28
|
+
# get_model(config, ide, tier) — resolve model from config or default
|
|
29
|
+
# get_model_default(ide, tier) — hardcoded default for ide:tier
|
|
30
|
+
# map_access_to_claude_tools(access) — full->"" (no tools list; inherits all), readonly->restricted
|
|
31
|
+
# map_access_to_claude_disallowed(access) — readonly->"Write, Edit", full->""
|
|
32
|
+
# read_yaml_list(config, section) — read list from config.yaml
|
|
33
|
+
# get_target_field(config, target, field) — read a target's config field
|
|
34
|
+
|
|
35
|
+
source "$(dirname "${BASH_SOURCE[0]}")/../lib/common.sh"
|
|
36
|
+
|
|
37
|
+
# Sync rules for <agent-name>
|
|
38
|
+
# Typical transformations:
|
|
39
|
+
# - Copy as-is (like Claude)
|
|
40
|
+
# - Convert paths: to globs: (like Cursor)
|
|
41
|
+
# - Merge into single file (like Copilot)
|
|
42
|
+
sync_<name>_rules() {
|
|
43
|
+
local repo_root="$1"
|
|
44
|
+
local config_file="$2"
|
|
45
|
+
local output_dir="$3"
|
|
46
|
+
|
|
47
|
+
# TODO: Implement rule sync logic
|
|
48
|
+
echo " rules: not implemented"
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
# Sync skills for <agent-name>
|
|
52
|
+
sync_<name>_skills() {
|
|
53
|
+
local repo_root="$1"
|
|
54
|
+
local config_file="$2"
|
|
55
|
+
local output_dir="$3"
|
|
56
|
+
|
|
57
|
+
# TODO: Implement skill sync logic
|
|
58
|
+
echo " skills: not implemented"
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
# Sync agents for <agent-name>
|
|
62
|
+
sync_<name>_agents() {
|
|
63
|
+
local repo_root="$1"
|
|
64
|
+
local config_file="$2"
|
|
65
|
+
local output_dir="$3"
|
|
66
|
+
|
|
67
|
+
# TODO: Implement agent sync logic
|
|
68
|
+
echo " agents: not implemented"
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
# Main entry point
|
|
72
|
+
sync_to_<name>() {
|
|
73
|
+
local repo_root="$1"
|
|
74
|
+
local config_file="$2"
|
|
75
|
+
local output_dir="$3"
|
|
76
|
+
|
|
77
|
+
echo "=== <Agent Name> ==="
|
|
78
|
+
|
|
79
|
+
# Clean and create output directories
|
|
80
|
+
rm -rf "$output_dir/rules" "$output_dir/agents" "$output_dir/skills"
|
|
81
|
+
mkdir -p "$output_dir/rules" "$output_dir/skills" "$output_dir/agents"
|
|
82
|
+
|
|
83
|
+
sync_<name>_rules "$repo_root" "$config_file" "$output_dir"
|
|
84
|
+
sync_<name>_skills "$repo_root" "$config_file" "$output_dir"
|
|
85
|
+
sync_<name>_agents "$repo_root" "$config_file" "$output_dir"
|
|
86
|
+
}
|
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# intelligence-sync: AGENTS.md adapter
|
|
3
|
+
# Generates a committed project-index document that lists all agents, skills,
|
|
4
|
+
# and rules discovered from intelligence/ sources.
|
|
5
|
+
#
|
|
6
|
+
# Output: AGENTS.md at repo root (or wherever targets.agents.output points)
|
|
7
|
+
# Header: static text from config.yaml targets.agents.header (block scalar)
|
|
8
|
+
# Body: auto-built tables/lists from frontmatter of rules/agents/skills
|
|
9
|
+
#
|
|
10
|
+
# Unlike other adapters, the output is a single committed markdown file
|
|
11
|
+
# meant to be read by both humans and LLMs. It must never be hand-edited —
|
|
12
|
+
# every sync regenerates it from scratch.
|
|
13
|
+
|
|
14
|
+
source "$(dirname "${BASH_SOURCE[0]}")/../lib/common.sh"
|
|
15
|
+
|
|
16
|
+
# Repo-relative paths to the umbrella folder and the engine module, DERIVED —
|
|
17
|
+
# never hardcoded. The umbrella is named by the project (`intelligence/`,
|
|
18
|
+
# `Intelligence/`, a codename) and the engine lives in a module inside it;
|
|
19
|
+
# detect_layout resolved both before any adapter ran. A literal path here would
|
|
20
|
+
# print a sync command that does not exist, and would be wrong outright on a
|
|
21
|
+
# case-sensitive filesystem — in the one document Cursor, Copilot and Codex all
|
|
22
|
+
# read as canonical.
|
|
23
|
+
# sync.sh exports both as layout tokens; recompute only when an adapter is
|
|
24
|
+
# driven directly (tests), never assume a folder name.
|
|
25
|
+
agents_md_umbrella_rel() {
|
|
26
|
+
local repo_root="$1" rel="${IS_UMBRELLA_REL:-}"
|
|
27
|
+
[ -n "$rel" ] || rel="$(repo_rel_dir "$repo_root" "${LS_UMBRELLA_DIR:-$repo_root/intelligence}")"
|
|
28
|
+
printf '%s' "${rel:-intelligence}"
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
agents_md_module_rel() {
|
|
32
|
+
local repo_root="$1" rel="${IS_MODULE_REL:-}"
|
|
33
|
+
[ -n "$rel" ] || rel="$(repo_rel_dir "$repo_root" "${LS_MODULE_DIR:-$repo_root/intelligence/sync}")"
|
|
34
|
+
printf '%s' "${rel:-intelligence/sync}"
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
# Append the static header block from config.yaml (or a fallback).
|
|
38
|
+
agents_md_append_header() {
|
|
39
|
+
local output="$1"
|
|
40
|
+
local config_file="$2"
|
|
41
|
+
|
|
42
|
+
local header
|
|
43
|
+
header=$(get_target_block "$config_file" "agents" "header")
|
|
44
|
+
|
|
45
|
+
if [ -n "$header" ]; then
|
|
46
|
+
printf '%s\n' "$header" >> "$output"
|
|
47
|
+
else
|
|
48
|
+
local project_name
|
|
49
|
+
project_name=$(get_project_name "$config_file")
|
|
50
|
+
echo "# ${project_name:-Project}" >> "$output"
|
|
51
|
+
fi
|
|
52
|
+
echo "" >> "$output"
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
agents_md_append_agents_table() {
|
|
56
|
+
local repo_root="$1"
|
|
57
|
+
local config_file="$2"
|
|
58
|
+
local output="$3"
|
|
59
|
+
|
|
60
|
+
local rows=""
|
|
61
|
+
local count=0
|
|
62
|
+
|
|
63
|
+
while IFS= read -r src; do
|
|
64
|
+
[ -z "$src" ] && continue
|
|
65
|
+
local dir
|
|
66
|
+
dir="$(resolve_source_dir "$repo_root" "$src")"
|
|
67
|
+
[ -d "$dir" ] || continue
|
|
68
|
+
# Byte-order (LC_ALL=C) sort so generated output is identical across
|
|
69
|
+
# platforms — bash glob order follows LC_COLLATE, which differs between
|
|
70
|
+
# Linux CI (UTF-8, ignores `-`) and Git Bash (C, byte order).
|
|
71
|
+
while IFS= read -r f; do
|
|
72
|
+
[ -f "$f" ] || continue
|
|
73
|
+
local name rel tier access desc
|
|
74
|
+
name="$(basename "$f" .md)"
|
|
75
|
+
rel="$(repo_rel_link "$repo_root" "$f")"
|
|
76
|
+
tier=$(get_frontmatter_value "tier" "$f")
|
|
77
|
+
access=$(get_frontmatter_value "access" "$f")
|
|
78
|
+
desc=$(get_frontmatter_value "description" "$f")
|
|
79
|
+
if [ -n "$rel" ]; then
|
|
80
|
+
rows+="| [$name]($rel) | ${tier:--} | ${access:--} | ${desc:--} |"$'\n'
|
|
81
|
+
else
|
|
82
|
+
rows+="| $name | ${tier:--} | ${access:--} | ${desc:--} |"$'\n'
|
|
83
|
+
fi
|
|
84
|
+
count=$((count + 1))
|
|
85
|
+
done < <(find "$dir" -maxdepth 1 -type f -name '*.md' -print | LC_ALL=C sort)
|
|
86
|
+
done < <(read_yaml_list "$config_file" "agents")
|
|
87
|
+
|
|
88
|
+
[ "$count" -eq 0 ] && return 0
|
|
89
|
+
|
|
90
|
+
{
|
|
91
|
+
echo "### Agents"
|
|
92
|
+
echo ""
|
|
93
|
+
echo "| Agent | Tier | Access | Description |"
|
|
94
|
+
echo "|-------|------|--------|-------------|"
|
|
95
|
+
printf '%s' "$rows"
|
|
96
|
+
echo ""
|
|
97
|
+
} >> "$output"
|
|
98
|
+
|
|
99
|
+
echo " agents: $count listed"
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
agents_md_append_skills_table() {
|
|
103
|
+
local repo_root="$1"
|
|
104
|
+
local config_file="$2"
|
|
105
|
+
local output="$3"
|
|
106
|
+
|
|
107
|
+
local rows=""
|
|
108
|
+
local count=0
|
|
109
|
+
|
|
110
|
+
while IFS= read -r src; do
|
|
111
|
+
[ -z "$src" ] && continue
|
|
112
|
+
local dir
|
|
113
|
+
dir="$(resolve_source_dir "$repo_root" "$src")"
|
|
114
|
+
[ -d "$dir" ] || continue
|
|
115
|
+
# Byte-order (LC_ALL=C) sort so generated output is identical across
|
|
116
|
+
# platforms — see the note in agents_md_append_agents_table.
|
|
117
|
+
while IFS= read -r skill_dir; do
|
|
118
|
+
[ -d "$skill_dir" ] || continue
|
|
119
|
+
local dirname
|
|
120
|
+
dirname="$(basename "$skill_dir")"
|
|
121
|
+
case "$dirname" in _*) continue ;; esac
|
|
122
|
+
local skill_file="${skill_dir%/}/SKILL.md"
|
|
123
|
+
[ -f "$skill_file" ] || continue
|
|
124
|
+
local rel desc
|
|
125
|
+
rel="$(repo_rel_link "$repo_root" "$skill_file")"
|
|
126
|
+
desc=$(get_frontmatter_value "description" "$skill_file")
|
|
127
|
+
if [ -n "$rel" ]; then
|
|
128
|
+
rows+="| [$dirname]($rel) | ${desc:--} |"$'\n'
|
|
129
|
+
else
|
|
130
|
+
rows+="| $dirname | ${desc:--} |"$'\n'
|
|
131
|
+
fi
|
|
132
|
+
count=$((count + 1))
|
|
133
|
+
done < <(find "$dir" -mindepth 1 -maxdepth 1 -type d -print | LC_ALL=C sort)
|
|
134
|
+
done < <(read_yaml_list "$config_file" "skills")
|
|
135
|
+
|
|
136
|
+
[ "$count" -eq 0 ] && return 0
|
|
137
|
+
|
|
138
|
+
{
|
|
139
|
+
echo "### Skills"
|
|
140
|
+
echo ""
|
|
141
|
+
echo "| Skill | Description |"
|
|
142
|
+
echo "|-------|-------------|"
|
|
143
|
+
printf '%s' "$rows"
|
|
144
|
+
echo ""
|
|
145
|
+
} >> "$output"
|
|
146
|
+
|
|
147
|
+
echo " skills: $count listed"
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
agents_md_append_rules_list() {
|
|
151
|
+
local repo_root="$1"
|
|
152
|
+
local config_file="$2"
|
|
153
|
+
local output="$3"
|
|
154
|
+
|
|
155
|
+
local lines=""
|
|
156
|
+
local count=0
|
|
157
|
+
local global_rule_files=()
|
|
158
|
+
|
|
159
|
+
while IFS= read -r src; do
|
|
160
|
+
[ -z "$src" ] && continue
|
|
161
|
+
local dir
|
|
162
|
+
dir="$(resolve_source_dir "$repo_root" "$src")"
|
|
163
|
+
[ -d "$dir" ] || continue
|
|
164
|
+
# Byte-order (LC_ALL=C) sort so generated output — and the inline order
|
|
165
|
+
# of always-on rules below — is identical across platforms. See the
|
|
166
|
+
# note in agents_md_append_agents_table.
|
|
167
|
+
while IFS= read -r f; do
|
|
168
|
+
[ -f "$f" ] || continue
|
|
169
|
+
local name rel scope
|
|
170
|
+
name="$(basename "$f" .md)"
|
|
171
|
+
rel="$(repo_rel_link "$repo_root" "$f")"
|
|
172
|
+
scope="global"
|
|
173
|
+
if [ "$(has_paths "$f")" != "0" ]; then
|
|
174
|
+
scope="scoped"
|
|
175
|
+
else
|
|
176
|
+
global_rule_files+=("$f")
|
|
177
|
+
fi
|
|
178
|
+
if [ -n "$rel" ]; then
|
|
179
|
+
lines+="- [$name]($rel) ($scope)"$'\n'
|
|
180
|
+
else
|
|
181
|
+
lines+="- $name ($scope)"$'\n'
|
|
182
|
+
fi
|
|
183
|
+
count=$((count + 1))
|
|
184
|
+
done < <(find "$dir" -maxdepth 1 -type f -name '*.md' -print | LC_ALL=C sort)
|
|
185
|
+
done < <(read_yaml_list "$config_file" "rules")
|
|
186
|
+
|
|
187
|
+
[ "$count" -eq 0 ] && return 0
|
|
188
|
+
|
|
189
|
+
{
|
|
190
|
+
echo "### Rules"
|
|
191
|
+
echo ""
|
|
192
|
+
printf '%s' "$lines"
|
|
193
|
+
echo ""
|
|
194
|
+
} >> "$output"
|
|
195
|
+
|
|
196
|
+
echo " rules: $count listed"
|
|
197
|
+
|
|
198
|
+
# Always-on rules (no `paths:`) are inlined into AGENTS.md as canonical
|
|
199
|
+
# project context. Codex (only reads AGENTS.md) and Cursor/Copilot
|
|
200
|
+
# (read AGENTS.md natively) all pick up rule content from here.
|
|
201
|
+
# Path-scoped rules stay in tool-specific channels (.cursor/rules/,
|
|
202
|
+
# .github/instructions/) so monorepo scoping is preserved.
|
|
203
|
+
if [ "${#global_rule_files[@]}" -gt 0 ]; then
|
|
204
|
+
local umbrella_rel
|
|
205
|
+
umbrella_rel="$(agents_md_umbrella_rel "$repo_root")"
|
|
206
|
+
{
|
|
207
|
+
echo "---"
|
|
208
|
+
echo ""
|
|
209
|
+
echo "## Project Context"
|
|
210
|
+
echo ""
|
|
211
|
+
echo "<!-- Inlined from always-on rules in $umbrella_rel/rules/ -->"
|
|
212
|
+
echo ""
|
|
213
|
+
} >> "$output"
|
|
214
|
+
local rf
|
|
215
|
+
for rf in "${global_rule_files[@]}"; do
|
|
216
|
+
awk '
|
|
217
|
+
BEGIN { in_fm=0; past_fm=0 }
|
|
218
|
+
{ sub(/\r$/, "") }
|
|
219
|
+
/^---$/ {
|
|
220
|
+
if (!past_fm) { in_fm = !in_fm; if (!in_fm) { past_fm=1 }; next }
|
|
221
|
+
}
|
|
222
|
+
past_fm || !in_fm { print }
|
|
223
|
+
' "$rf" >> "$output"
|
|
224
|
+
echo "" >> "$output"
|
|
225
|
+
done
|
|
226
|
+
echo " rules: ${#global_rule_files[@]} global rule(s) inlined"
|
|
227
|
+
fi
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
# Main entry point for AGENTS.md adapter
|
|
231
|
+
sync_to_agents() {
|
|
232
|
+
local repo_root="$1"
|
|
233
|
+
local config_file="$2"
|
|
234
|
+
local output_dir="$3"
|
|
235
|
+
|
|
236
|
+
echo "=== AGENTS.md ==="
|
|
237
|
+
|
|
238
|
+
# output_dir points at the target file path (e.g., /repo/AGENTS.md).
|
|
239
|
+
# If it looks like a directory (trailing slash, existing dir, or no .md
|
|
240
|
+
# extension), append default filename.
|
|
241
|
+
local output_file="$output_dir"
|
|
242
|
+
if [ -d "$output_file" ] || [[ "$output_file" == */ ]] || [[ "$output_file" != *.md ]]; then
|
|
243
|
+
output_file="${output_file%/}/AGENTS.md"
|
|
244
|
+
fi
|
|
245
|
+
|
|
246
|
+
mkdir -p "$(dirname "$output_file")"
|
|
247
|
+
|
|
248
|
+
local umbrella_rel module_rel
|
|
249
|
+
umbrella_rel="$(agents_md_umbrella_rel "$repo_root")"
|
|
250
|
+
module_rel="$(agents_md_module_rel "$repo_root")"
|
|
251
|
+
|
|
252
|
+
# These two strings are written into a COMMITTED file. An absolute path here
|
|
253
|
+
# means the derivation failed, and a machine-specific path in AGENTS.md is
|
|
254
|
+
# worse than a failed sync — fail loudly instead.
|
|
255
|
+
case "$umbrella_rel$module_rel" in
|
|
256
|
+
/*|*:[\\/]*)
|
|
257
|
+
echo " ERROR: AGENTS.md paths did not resolve relative to the repo root:" >&2
|
|
258
|
+
echo " umbrella='$umbrella_rel' module='$module_rel' repo_root='$repo_root'" >&2
|
|
259
|
+
return 1
|
|
260
|
+
;;
|
|
261
|
+
esac
|
|
262
|
+
|
|
263
|
+
# How a reader re-runs the sync: the CLI names its own command (IS_SYNC_CMD),
|
|
264
|
+
# a vendored setup gets the script invocation.
|
|
265
|
+
local sync_cmd="${IS_SYNC_CMD:-bash $module_rel/scripts/sync.sh}"
|
|
266
|
+
|
|
267
|
+
{
|
|
268
|
+
echo "<!-- Generated by intelligence-sync. Do not edit manually. -->"
|
|
269
|
+
echo "<!-- Source: $umbrella_rel/ | Sync: $sync_cmd -->"
|
|
270
|
+
echo ""
|
|
271
|
+
} > "$output_file"
|
|
272
|
+
|
|
273
|
+
agents_md_append_header "$output_file" "$config_file"
|
|
274
|
+
|
|
275
|
+
{
|
|
276
|
+
echo "## Intelligence"
|
|
277
|
+
echo ""
|
|
278
|
+
echo "Source of truth: \`$umbrella_rel/\` | Sync: \`$sync_cmd\`"
|
|
279
|
+
echo ""
|
|
280
|
+
} >> "$output_file"
|
|
281
|
+
|
|
282
|
+
agents_md_append_agents_table "$repo_root" "$config_file" "$output_file"
|
|
283
|
+
agents_md_append_skills_table "$repo_root" "$config_file" "$output_file"
|
|
284
|
+
agents_md_append_rules_list "$repo_root" "$config_file" "$output_file"
|
|
285
|
+
|
|
286
|
+
finalize_output_file "$output_file"
|
|
287
|
+
|
|
288
|
+
# Safety net: AGENTS.md is committed, so it must never carry an absolute or
|
|
289
|
+
# transient link target (remote-pack content lives under the run cache). If
|
|
290
|
+
# relativization ever fails, fail the sync loudly rather than write a
|
|
291
|
+
# machine-specific path into version control.
|
|
292
|
+
if grep -nE '\]\((/|[A-Za-z]:[\\/])' "$output_file" >/dev/null 2>&1; then
|
|
293
|
+
echo " ERROR: AGENTS.md has an absolute link target — relativization failed:" >&2
|
|
294
|
+
grep -nE '\]\((/|[A-Za-z]:[\\/])' "$output_file" >&2
|
|
295
|
+
return 1
|
|
296
|
+
fi
|
|
297
|
+
|
|
298
|
+
echo " -> ${output_file#$repo_root/}"
|
|
299
|
+
}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# intelligence-sync: Claude Code adapter
|
|
3
|
+
# Transforms source prompts to .claude/ format
|
|
4
|
+
#
|
|
5
|
+
# Rules: copy as-is (paths: frontmatter preserved)
|
|
6
|
+
# Skills: copy skill directories in full (SKILL.md + bundled resources)
|
|
7
|
+
# Agents: tier -> model, access -> tools/disallowedTools
|
|
8
|
+
|
|
9
|
+
source "$(dirname "${BASH_SOURCE[0]}")/../lib/common.sh"
|
|
10
|
+
|
|
11
|
+
# Sync rules to Claude format (copy as-is, normalize LF)
|
|
12
|
+
sync_claude_rules() {
|
|
13
|
+
local repo_root="$1"
|
|
14
|
+
local config_file="$2"
|
|
15
|
+
local output_dir="$3"
|
|
16
|
+
|
|
17
|
+
while IFS= read -r src; do
|
|
18
|
+
[ -z "$src" ] && continue
|
|
19
|
+
local dir
|
|
20
|
+
dir="$(resolve_source_dir "$repo_root" "$src")"
|
|
21
|
+
[ -d "$dir" ] || continue
|
|
22
|
+
for f in "$dir"/*.md; do
|
|
23
|
+
[ -f "$f" ] || continue
|
|
24
|
+
cp "$f" "$output_dir/rules/"
|
|
25
|
+
finalize_output_file "$output_dir/rules/$(basename "$f")"
|
|
26
|
+
echo " rule: $(basename "$f")"
|
|
27
|
+
done
|
|
28
|
+
done < <(read_yaml_list "$config_file" "rules")
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
# Sync skills to Claude format (copy skill directories in full)
|
|
32
|
+
sync_claude_skills() {
|
|
33
|
+
local repo_root="$1"
|
|
34
|
+
local config_file="$2"
|
|
35
|
+
local output_dir="$3"
|
|
36
|
+
|
|
37
|
+
while IFS= read -r src; do
|
|
38
|
+
[ -z "$src" ] && continue
|
|
39
|
+
local dir
|
|
40
|
+
dir="$(resolve_source_dir "$repo_root" "$src")"
|
|
41
|
+
[ -d "$dir" ] || continue
|
|
42
|
+
for d in "$dir"/*/; do
|
|
43
|
+
[ -d "$d" ] || continue
|
|
44
|
+
local skill_name
|
|
45
|
+
skill_name="$(basename "$d")"
|
|
46
|
+
[ -f "$d/SKILL.md" ] || continue
|
|
47
|
+
copy_skill_bundle "$d" "$output_dir/skills/$skill_name"
|
|
48
|
+
echo " skill: $skill_name"
|
|
49
|
+
done
|
|
50
|
+
done < <(read_yaml_list "$config_file" "skills")
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
# Sync a single agent file to Claude format
|
|
54
|
+
sync_claude_agent() {
|
|
55
|
+
local src="$1"
|
|
56
|
+
local config_file="$2"
|
|
57
|
+
local output_dir="$3"
|
|
58
|
+
local name
|
|
59
|
+
name="$(basename "$src")"
|
|
60
|
+
|
|
61
|
+
local tier access
|
|
62
|
+
tier=$(get_frontmatter_value "tier" "$src")
|
|
63
|
+
access=$(get_frontmatter_value "access" "$src")
|
|
64
|
+
|
|
65
|
+
local model tools extra
|
|
66
|
+
model=$(get_model "$config_file" "claude" "$tier")
|
|
67
|
+
tools=$(map_access_to_claude_tools "$access")
|
|
68
|
+
extra=$(map_access_to_claude_disallowed "$access")
|
|
69
|
+
|
|
70
|
+
# Transform: remove tier/access, inject tools/model/disallowedTools before closing ---
|
|
71
|
+
awk -v model="$model" -v tools="$tools" -v extra="$extra" '
|
|
72
|
+
BEGIN { count=0 }
|
|
73
|
+
/^tier:/ { next }
|
|
74
|
+
/^access:/ { next }
|
|
75
|
+
{
|
|
76
|
+
sub(/\r$/, "")
|
|
77
|
+
}
|
|
78
|
+
/^---$/ { count++ }
|
|
79
|
+
count==2 && /^---$/ {
|
|
80
|
+
if (tools != "") print "tools: " tools
|
|
81
|
+
if (extra != "") print "disallowedTools: " extra
|
|
82
|
+
print "model: " model
|
|
83
|
+
}
|
|
84
|
+
{ print }
|
|
85
|
+
' "$src" > "$output_dir/agents/$name"
|
|
86
|
+
finalize_output_file "$output_dir/agents/$name"
|
|
87
|
+
echo " agent: $name (tier=$tier -> model=$model, access=$access)"
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
# Sync all agents to Claude format
|
|
91
|
+
sync_claude_agents() {
|
|
92
|
+
local repo_root="$1"
|
|
93
|
+
local config_file="$2"
|
|
94
|
+
local output_dir="$3"
|
|
95
|
+
|
|
96
|
+
while IFS= read -r src; do
|
|
97
|
+
[ -z "$src" ] && continue
|
|
98
|
+
local dir
|
|
99
|
+
dir="$(resolve_source_dir "$repo_root" "$src")"
|
|
100
|
+
[ -d "$dir" ] || continue
|
|
101
|
+
for f in "$dir"/*.md; do
|
|
102
|
+
[ -f "$f" ] || continue
|
|
103
|
+
sync_claude_agent "$f" "$config_file" "$output_dir"
|
|
104
|
+
done
|
|
105
|
+
done < <(read_yaml_list "$config_file" "agents")
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
# Main entry point for Claude adapter
|
|
109
|
+
sync_to_claude() {
|
|
110
|
+
local repo_root="$1"
|
|
111
|
+
local config_file="$2"
|
|
112
|
+
local output_dir="$3"
|
|
113
|
+
|
|
114
|
+
echo "=== Claude Code ==="
|
|
115
|
+
|
|
116
|
+
# Clean generated content only — preserve any project-level files
|
|
117
|
+
# the user manages directly (settings.json, settings.local.json,
|
|
118
|
+
# commands/, statusline.sh, etc.).
|
|
119
|
+
rm -rf "$output_dir/rules" "$output_dir/agents"
|
|
120
|
+
if [ -d "$output_dir/skills" ]; then
|
|
121
|
+
find "$output_dir/skills" -mindepth 1 -maxdepth 1 -type d | while read -r d; do
|
|
122
|
+
rm -rf "$d"
|
|
123
|
+
done
|
|
124
|
+
fi
|
|
125
|
+
mkdir -p "$output_dir/rules" "$output_dir/skills" "$output_dir/agents"
|
|
126
|
+
|
|
127
|
+
sync_claude_rules "$repo_root" "$config_file" "$output_dir"
|
|
128
|
+
sync_claude_skills "$repo_root" "$config_file" "$output_dir"
|
|
129
|
+
sync_claude_agents "$repo_root" "$config_file" "$output_dir"
|
|
130
|
+
|
|
131
|
+
local rules_count skills_count agents_count
|
|
132
|
+
rules_count=$(find "$output_dir/rules" -name "*.md" 2>/dev/null | wc -l)
|
|
133
|
+
skills_count=$(find "$output_dir/skills" -name "SKILL.md" 2>/dev/null | wc -l)
|
|
134
|
+
agents_count=$(find "$output_dir/agents" -name "*.md" 2>/dev/null | wc -l)
|
|
135
|
+
echo " -> Rules: $rules_count, Skills: $skills_count, Agents: $agents_count"
|
|
136
|
+
}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# intelligence-sync: OpenAI Codex CLI adapter
|
|
3
|
+
# Transforms source prompts to Codex format.
|
|
4
|
+
#
|
|
5
|
+
# Codex reads AGENTS.md natively for project context — the `agents` adapter
|
|
6
|
+
# inlines always-on rules into AGENTS.md, so this adapter only emits skills
|
|
7
|
+
# and subagent definitions.
|
|
8
|
+
#
|
|
9
|
+
# Skills: copy skill directories in full to .agents/skills/{name}/ (Codex
|
|
10
|
+
# reads from $REPO_ROOT/.agents/skills exclusively per official docs)
|
|
11
|
+
# Agents: -> .codex/agents/{name}.toml (name, description, model,
|
|
12
|
+
# model_reasoning_effort, sandbox_mode, developer_instructions)
|
|
13
|
+
|
|
14
|
+
source "$(dirname "${BASH_SOURCE[0]}")/../lib/common.sh"
|
|
15
|
+
|
|
16
|
+
# Sync skills to Codex format (.agents/skills/{name}/SKILL.md)
|
|
17
|
+
sync_codex_skills() {
|
|
18
|
+
local repo_root="$1"
|
|
19
|
+
local config_file="$2"
|
|
20
|
+
local output_dir="$3"
|
|
21
|
+
|
|
22
|
+
sync_open_skill_dirs "$repo_root" "$config_file" "$output_dir"
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
# Sync agents to Codex format (.codex/agents/{name}.toml)
|
|
26
|
+
sync_codex_agents() {
|
|
27
|
+
local repo_root="$1"
|
|
28
|
+
local config_file="$2"
|
|
29
|
+
local output_dir="$3"
|
|
30
|
+
|
|
31
|
+
local count=0
|
|
32
|
+
while IFS= read -r src; do
|
|
33
|
+
[ -z "$src" ] && continue
|
|
34
|
+
local dir
|
|
35
|
+
dir="$(resolve_source_dir "$repo_root" "$src")"
|
|
36
|
+
[ -d "$dir" ] || continue
|
|
37
|
+
for f in "$dir"/*.md; do
|
|
38
|
+
[ -f "$f" ] || continue
|
|
39
|
+
local name
|
|
40
|
+
name="$(basename "$f" .md)"
|
|
41
|
+
|
|
42
|
+
local tier access description
|
|
43
|
+
tier=$(get_frontmatter_value "tier" "$f")
|
|
44
|
+
access=$(get_frontmatter_value "access" "$f")
|
|
45
|
+
description=$(get_frontmatter_value "description" "$f")
|
|
46
|
+
|
|
47
|
+
local model effort sandbox
|
|
48
|
+
model=$(get_model "$config_file" "codex" "$tier")
|
|
49
|
+
case "$tier" in
|
|
50
|
+
heavy) effort="high" ;;
|
|
51
|
+
standard) effort="medium" ;;
|
|
52
|
+
light) effort="low" ;;
|
|
53
|
+
*) effort="medium" ;;
|
|
54
|
+
esac
|
|
55
|
+
case "$access" in
|
|
56
|
+
readonly) sandbox="read-only" ;;
|
|
57
|
+
*) sandbox="workspace-write" ;;
|
|
58
|
+
esac
|
|
59
|
+
|
|
60
|
+
local body
|
|
61
|
+
body=$(awk '
|
|
62
|
+
BEGIN { in_fm=0; past_fm=0 }
|
|
63
|
+
{ sub(/\r$/, "") }
|
|
64
|
+
/^---$/ {
|
|
65
|
+
if (!past_fm) { in_fm = !in_fm; if (!in_fm) { past_fm=1 }; next }
|
|
66
|
+
}
|
|
67
|
+
past_fm { print }
|
|
68
|
+
' "$f")
|
|
69
|
+
|
|
70
|
+
# Escape backslashes used in Markdown paths, then neutralize any
|
|
71
|
+
# closing TOML triple-quote sequence in the agent body.
|
|
72
|
+
local body_safe
|
|
73
|
+
body_safe="${body//\\/\\\\}"
|
|
74
|
+
body_safe="${body_safe//\"\"\"/\"\"\\\"}"
|
|
75
|
+
|
|
76
|
+
local name_escaped description_escaped
|
|
77
|
+
name_escaped=$(toml_escape "$name")
|
|
78
|
+
description_escaped=$(toml_escape "$description")
|
|
79
|
+
|
|
80
|
+
{
|
|
81
|
+
echo "name = \"$name_escaped\""
|
|
82
|
+
echo "description = \"$description_escaped\""
|
|
83
|
+
echo "model = \"$model\""
|
|
84
|
+
echo "model_reasoning_effort = \"$effort\""
|
|
85
|
+
echo "sandbox_mode = \"$sandbox\""
|
|
86
|
+
echo ""
|
|
87
|
+
echo "developer_instructions = \"\"\""
|
|
88
|
+
echo "$body_safe"
|
|
89
|
+
echo "\"\"\""
|
|
90
|
+
} > "$output_dir/$name.toml"
|
|
91
|
+
finalize_output_file "$output_dir/$name.toml"
|
|
92
|
+
count=$((count + 1))
|
|
93
|
+
echo " agent: $name.toml"
|
|
94
|
+
done
|
|
95
|
+
done < <(read_yaml_list "$config_file" "agents")
|
|
96
|
+
|
|
97
|
+
echo " -> Agents: $count"
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
# Main entry point for Codex adapter
|
|
101
|
+
sync_to_codex() {
|
|
102
|
+
local repo_root="$1"
|
|
103
|
+
local config_file="$2"
|
|
104
|
+
local output_dir="$3"
|
|
105
|
+
|
|
106
|
+
echo "=== OpenAI Codex ==="
|
|
107
|
+
|
|
108
|
+
# Skills -> .agents/skills/ (Codex reads from this fixed path).
|
|
109
|
+
# `sync_open_skill_dirs` owns clean + populate of this shared dir.
|
|
110
|
+
local skills_dir="$repo_root/.agents/skills"
|
|
111
|
+
sync_codex_skills "$repo_root" "$config_file" "$skills_dir"
|
|
112
|
+
|
|
113
|
+
# Agents -> .codex/agents/
|
|
114
|
+
local agents_dir="$repo_root/.codex/agents"
|
|
115
|
+
rm -rf "$agents_dir"
|
|
116
|
+
mkdir -p "$agents_dir"
|
|
117
|
+
sync_codex_agents "$repo_root" "$config_file" "$agents_dir"
|
|
118
|
+
}
|