@ainova-systems/intelligence 0.23.0 → 0.24.0

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
- 79201cedae74ec96e67c3aa94e267f6b1e226c23
1
+ 6878d4ce559755d55f90ae23296678333e95f775
package/engine/VERSION CHANGED
@@ -1 +1 @@
1
- 0.23.0
1
+ 0.24.0
@@ -3,8 +3,7 @@
3
3
  # Transforms source prompts to Codex format.
4
4
  #
5
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.
6
+ # inlines shared always-on rules into AGENTS.md.
8
7
  #
9
8
  # Rules: an always-on rule AGENTS.md does not carry — a local one, or one whose
10
9
  # targets leave `agents` out — goes into AGENTS.override.md beside it
@@ -12,6 +11,8 @@
12
11
  # directory, so it holds the whole AGENTS.md plus those rules. The contract
13
12
  # ignores it, and it exists only while such a rule does; one Intelligence did
14
13
  # not generate is never touched, and refuses a render that needs the path.
14
+ # Scoped rules get compact pattern-to-source links in that same override.
15
+ # This is on-demand reading guidance, not a native glob-triggered loader.
15
16
  #
16
17
  # Skills: copy skill directories in full to .agents/skills/{name}/ (Codex
17
18
  # reads from $REPO_ROOT/.agents/skills exclusively per official docs)
@@ -43,32 +44,50 @@ adapter_contract_codex() {
43
44
  CODEX_OVERRIDE_MARKER="<!-- Generated by intelligence-sync. Do not edit manually. -->"
44
45
 
45
46
  # sync_codex_override <repo_root> <config_file> — write AGENTS.override.md
46
- # while an always-on rule AGENTS.md does not carry is for Codex, and remove a
47
- # generated one otherwise.
47
+ # while Codex needs extra always-on rules or scoped-rule routing, and remove
48
+ # a generated one otherwise.
48
49
  sync_codex_override() {
49
50
  local repo_root="$1" config_file="$2" override="$1/AGENTS.override.md" first="" agents_file i
50
- local -a files=() names=()
51
+ local -a files=() names=() scoped=() scoped_names=()
51
52
  source_artifacts_var "$repo_root" "$config_file" rules codex "AGENTS.override.md"
52
53
  for ((i = 0; i < ${#IS_SOURCE_FILES[@]}; i++)); do
53
- [ "${IS_SOURCE_SCOPED[i]}" = 0 ] && [ "${IS_SOURCE_IN_AGENTS[i]}" = 0 ] || continue
54
- files+=("${IS_SOURCE_FILES[i]}")
54
+ if [ "${IS_SOURCE_SCOPED[i]}" = 1 ]; then
55
+ scoped+=("${IS_SOURCE_FILES[i]}")
56
+ scoped_names+=("${IS_SOURCE_NAMES[i]}")
57
+ elif [ "${IS_SOURCE_IN_AGENTS[i]}" = 0 ]; then
58
+ files+=("${IS_SOURCE_FILES[i]}")
59
+ else
60
+ continue
61
+ fi
55
62
  names+=("${IS_SOURCE_NAMES[i]}")
56
63
  done
57
64
  if [ -f "$override" ]; then
58
65
  IFS= read -r first < "$override" || true
59
66
  if [ "${first%$'\r'}" != "$CODEX_OVERRIDE_MARKER" ]; then
60
- [ "${#files[@]}" -gt 0 ] || return 0
61
- echo "ERROR: AGENTS.override.md was not generated by intelligence-sync, but ${names[*]} need it: always-on rules for Codex that AGENTS.md does not carry go there. Move its guidance into a rule, remove it, then sync." >&2
67
+ [ "${#names[@]}" -gt 0 ] || return 0
68
+ echo "ERROR: AGENTS.override.md was not generated by intelligence-sync, but ${names[*]} need it: additional Codex rules and scoped-rule routing go there. Move its guidance into a rule, remove it, then sync." >&2
62
69
  return 1
63
70
  fi
64
71
  fi
65
- if [ "${#files[@]}" -eq 0 ]; then
72
+ if [ "${#names[@]}" -eq 0 ]; then
66
73
  rm -f "$override"
67
74
  return 0
68
75
  fi
69
76
  target_output_var "$config_file" "agents"
70
77
  agents_output_path_var "${IS_TGT_OUTPUT:-.agents}"
71
78
  agents_file="$repo_root/$IS_AGENTS_OUTPUT_PATH"
79
+ local routes="" rows path patterns link
80
+ if [ "${#scoped[@]}" -gt 0 ]; then
81
+ rows="$(frontmatter_index 'paths[]' "${scoped[@]}")" || return 1
82
+ i=0
83
+ while IFS=$'\x1f' read -r path patterns; do
84
+ repo_rel_link_var "$repo_root" "$path"
85
+ # The override is ignored: external sources may use their real path.
86
+ link="${IS_REPO_REL:-$path}"
87
+ routes+="- \`${patterns:-[]}\` → [${scoped_names[i]}](<$link>)"$'\n'
88
+ i=$((i + 1))
89
+ done <<< "$rows"
90
+ fi
72
91
  {
73
92
  if [ -f "$agents_file" ]; then
74
93
  cat "$agents_file"
@@ -79,13 +98,18 @@ sync_codex_override() {
79
98
  echo ""
80
99
  echo "## Codex Project Context"
81
100
  echo ""
82
- echo "<!-- Always-on rules AGENTS.md does not carry. Codex reads this file instead of AGENTS.md. -->"
101
+ echo "<!-- Codex reads this file instead of AGENTS.md. -->"
83
102
  echo ""
84
- emit_rule_bodies "${files[@]}"
103
+ if [ -n "$routes" ]; then
104
+ echo "Before working on files matching these repo-relative patterns, read and follow the linked rules. Apply each only within its scope."
105
+ echo ""
106
+ printf '%s\n' "$routes"
107
+ fi
108
+ [ "${#files[@]}" -eq 0 ] || emit_rule_bodies "${files[@]}"
85
109
  } > "$override"
86
110
  finalize_output_file "$override"
87
111
  for ((i = 0; i < ${#names[@]}; i++)); do
88
- echo " rule: ${names[i]} (always-on, AGENTS.override.md)"
112
+ echo " rule: ${names[i]} (AGENTS.override.md)"
89
113
  done
90
114
  echo " -> AGENTS.override.md"
91
115
  }
@@ -217,7 +217,9 @@ source_name_map_var() {
217
217
  # unit separator — never present in frontmatter values). Value semantics are
218
218
  # get_frontmatter_value's exactly: first frontmatter block only, first key
219
219
  # occurrence wins, first-colon split, symmetric quote strip. The special key
220
- # `paths#` yields the has_paths count instead of a value. A file without
220
+ # `paths#` yields the has_paths count; `paths[]` folds the first paths list
221
+ # into one display value, preserving YAML quotes and inline list syntax.
222
+ # A file without
221
223
  # frontmatter (or an empty file) still gets a row, with empty values.
222
224
  frontmatter_index() {
223
225
  local keys="$1"
@@ -235,7 +237,7 @@ frontmatter_index() {
235
237
  store()
236
238
  cur = FILENAME
237
239
  for (ri = 1; ri <= nk; ri++) { V[ri] = (K[ri] == "paths#") ? 0 : ""; delete SEEN[ri] }
238
- in_fm = 0; fm_done = 0
240
+ in_fm = 0; fm_done = 0; paths_list = 0
239
241
  }
240
242
  { sub(/\r$/, "") }
241
243
  FNR == 1 && $0 == "---" { in_fm = 1; next }
@@ -243,12 +245,29 @@ frontmatter_index() {
243
245
  in_fm && !fm_done && $0 == "---" { fm_done = 1; next }
244
246
  fm_done || !in_fm { next }
245
247
  {
248
+ if (paths_list && /^[[:space:]]*#/) next
249
+ if (paths_list && (/^[[:space:]]+/ || /^-[[:space:]]+/ || /^\]/)) {
250
+ item = $0
251
+ sub(/^[[:space:]]*/, "", item)
252
+ sub(/^-[[:space:]]+/, "", item)
253
+ if (item != "" && item !~ /^#/) {
254
+ for (ki = 1; ki <= nk; ki++)
255
+ if (K[ki] == "paths[]") V[ki] = V[ki] (V[ki] == "" ? "" : " ") item
256
+ }
257
+ next
258
+ }
259
+ if ($0 !~ /^[[:space:]]*$/) paths_list = 0
246
260
  idx = index($0, ":")
247
261
  if (idx == 0) next
248
262
  k = substr($0, 1, idx - 1)
249
263
  for (ki = 1; ki <= nk; ki++) {
250
264
  if (K[ki] == "paths#") {
251
265
  if (k == "paths") V[ki]++
266
+ } else if (K[ki] == "paths[]" && k == "paths" && !(ki in SEEN)) {
267
+ SEEN[ki] = 1
268
+ V[ki] = substr($0, idx + 1)
269
+ sub(/^[[:space:]]+/, "", V[ki])
270
+ paths_list = 1
252
271
  } else if (k == K[ki] && !(ki in SEEN)) {
253
272
  SEEN[ki] = 1
254
273
  V[ki] = fm_value_strip(substr($0, idx + 1))
@@ -2767,7 +2786,7 @@ source_catalog_check_local() {
2767
2786
  # A project adapter's channels are its own business: it has one.
2768
2787
  builtin_has_channel() {
2769
2788
  case "$1:$2" in
2770
- opencode:always|opencode:scoped|codex:scoped) return 1 ;;
2789
+ opencode:always|opencode:scoped) return 1 ;;
2771
2790
  esac
2772
2791
  return 0
2773
2792
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ainova-systems/intelligence",
3
- "version": "0.23.0",
3
+ "version": "0.24.0",
4
4
  "description": "Build, version and distribute AI agent intelligence across your organization — one CLI, versioned Intelligence Packages, and a sync engine for Claude Code, Cursor, Copilot, Codex, Pi and OpenCode.",
5
5
  "bin": {
6
6
  "intelligence": "bin/intelligence.js"
@@ -187,7 +187,7 @@ Use the engine library instead of copying parsers or file-handling logic.
187
187
  | `read_yaml_list(config, section)` | Stream entries from `sources.<section>`, package references as their store paths. |
188
188
  | `load_yaml_list(config, section)` | Same list into `IS_YAML_LIST`, cached — no subprocess on repeat reads. |
189
189
  | `get_frontmatter_value(key, file)` | Read a scalar from the first frontmatter block. |
190
- | `frontmatter_index(keys, file...)` | Read several frontmatter scalars for many files in one pass (`\x1f`-separated rows; special key `paths#` counts `paths:` lines). |
190
+ | `frontmatter_index(keys, file...)` | Read several frontmatter scalars for many files in one pass (`\x1f`-separated rows; `paths#` counts `paths:` lines, `paths[]` folds a paths list for display). |
191
191
  | `has_frontmatter(file)` / `has_paths(file)` | Inspect source shape. |
192
192
  | `strip_frontmatter(file)` | Emit the body without its first frontmatter block. |
193
193
  | `get_model(config, tool, tier)` | Resolve a `frontier`, `heavy`, `standard` or `light` model, including manifest overrides. |
@@ -223,11 +223,13 @@ Intelligence routes always-on rules once through `AGENTS.md` for tools that cons
223
223
  | `claude` | Copy | Copy | Copy with `paths:` preserved |
224
224
  | `cursor` | Omit; reads `AGENTS.md` | `.mdc` with `alwaysApply: true` | `.mdc` with `globs:` |
225
225
  | `copilot` | Omit; reads `AGENTS.md` | `.instructions.md` with `applyTo: "**"` | `.instructions.md` with `applyTo:` |
226
- | `codex` | Omit; reads `AGENTS.md` | `AGENTS.override.md`: all of `AGENTS.md` plus these rules | No native channel |
226
+ | `codex` | Omit; reads `AGENTS.md` | `AGENTS.override.md`: all of `AGENTS.md` plus these rules | Compact patterns and source links in `AGENTS.override.md`; read on demand |
227
227
  | `pi` | Omit; reads `AGENTS.md` | Added to the system prompt by the generated extension | Generated on-demand files and extension |
228
228
  | `opencode` | Omit; reads `AGENTS.md` | No channel; sync warns | No native channel |
229
229
 
230
- Codex reads `AGENTS.override.md` instead of `AGENTS.md` in the same directory, so the Codex adapter writes it — the whole rendered `AGENTS.md`, then the rules only Codex receives — while such a rule exists, and removes it when none does. Its contract manages and ignores the path; a file there that Intelligence did not generate is never touched, and a render that needs the path refuses until it is moved.
230
+ Codex reads `AGENTS.override.md` instead of `AGENTS.md` in the same directory, so the Codex adapter writes the whole rendered `AGENTS.md`, a compact scoped-rule index, and any additional always-on rules into that override. It exists while either kind needs it. Its contract manages and ignores the path; a file there that Intelligence did not generate is never touched, and a render that needs the path refuses until it is moved.
231
+
232
+ The scoped index pairs source `paths:` patterns with source links and asks Codex to read matching rules before working on files. Local and targeted rules follow the same source filtering as other output. This is model-followed guidance, not a native glob matcher; it creates no nested `AGENTS.md` files and leaves other tools' instruction channels unchanged. Checked 2026-10-23 against OpenAI's [instruction discovery documentation](https://learn.chatgpt.com/docs/agent-configuration/agents-md): startup discovery walks from the project root to the working directory, and an override replaces the base file in the same directory. Restart Codex after syncing updated instructions.
231
233
 
232
234
  If a new adapter relies on `AGENTS.md` for always-on rules, its target must require `agents`. Add that invariant to `engine/sync.sh` when contributing the adapter upstream.
233
235
 
@@ -279,13 +279,13 @@ Rule content in Markdown.
279
279
 
280
280
  | Source rule | Claude | Cursor | Antigravity | Copilot | Codex / Pi / OpenCode / `AGENTS.md` |
281
281
  |---|---|---|---|---|---|
282
- | Scoped | copied with `paths:` | `.mdc` with `globs:` | `.md` with `trigger: glob` and `globs:` | `.instructions.md` with `applyTo:` | listed in `AGENTS.md`; Pi also gets on-demand files and an extension |
282
+ | Scoped | copied with `paths:` | `.mdc` with `globs:` | `.md` with `trigger: glob` and `globs:` | `.instructions.md` with `applyTo:` | listed in `AGENTS.md`; Codex gets routing in its override; Pi gets on-demand files and an extension |
283
283
  | Always-on | copied | omitted | omitted | omitted | inlined once into `AGENTS.md` |
284
284
  | Always-on, not in `AGENTS.md` | copied | `.mdc` with `alwaysApply: true` | `.md` with `trigger: always_on` | `.instructions.md` with `applyTo: "**"` | Codex: `AGENTS.override.md`; Pi: added to the system prompt by its extension; OpenCode: none |
285
285
 
286
- Cursor, Copilot, Codex, Pi, OpenCode and Antigravity consume `AGENTS.md`, so always-on rules are not duplicated in their tool-specific channels. Claude does not consume `AGENTS.md`, so it receives the full rule set. OpenCode and Codex have no generated path-scoped rule channel; OpenCode users may configure `instructions:` globs themselves.
286
+ Cursor, Copilot, Codex, Pi, OpenCode and Antigravity consume `AGENTS.md`, so always-on rules are not duplicated in their tool-specific channels. Claude does not consume `AGENTS.md`, so it receives the full rule set. Codex's override lists scoped patterns and source links with an instruction to read matching rules on demand; this depends on the model following the instruction, not native glob-triggered loading. OpenCode users may configure `instructions:` globs themselves. See [adapter routing](adapters.md#rules) for delivery details.
287
287
 
288
- An always-on rule `AGENTS.md` does not carry — a local one, or one whose set leaves `agents` out (see [Selecting adapters](#selecting-adapters)) — reaches each tool in its set through that tool's own channel instead, the last row. Codex reads `AGENTS.override.md` instead of `AGENTS.md` in the same directory, so the file holds the whole `AGENTS.md` plus the rules only Codex receives; it is ignored, exists only while such a rule does, and one Intelligence did not generate is never touched. Antigravity's `trigger: always_on` belongs to the same undocumented key family as its `trigger: glob`. OpenCode reads instructions only from `AGENTS.md` or its committed `opencode.json`, so it can receive neither a local nor a tool-targeted always-on rule.
288
+ An always-on rule `AGENTS.md` does not carry — a local one, or one whose set leaves `agents` out (see [Selecting adapters](#selecting-adapters)) — reaches each tool in its set through that tool's own channel instead, the last row. Codex reads `AGENTS.override.md` instead of `AGENTS.md` in the same directory, so the file holds the whole `AGENTS.md` plus scoped routing and additional always-on rules; it is ignored, exists while either needs it, and one Intelligence did not generate is never touched. Antigravity's `trigger: always_on` belongs to the same undocumented key family as its `trigger: glob`. OpenCode reads instructions only from `AGENTS.md` or its committed `opencode.json`, so it can receive neither a local nor a tool-targeted always-on rule.
289
289
 
290
290
  Keep always-on rules small. Put narrow framework or component guidance behind `paths:` so unrelated tasks do not pay its context cost.
291
291