@ainova-systems/intelligence 0.14.0 → 0.16.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.
Files changed (35) hide show
  1. package/cli/commands/source.sh +177 -0
  2. package/cli/intelligence +5 -0
  3. package/cli/internal/check.sh +7 -0
  4. package/cli/lib/cli-common.sh +85 -0
  5. package/cli/lib/manifest.sh +97 -26
  6. package/engine/ENGINE_SHA +1 -1
  7. package/engine/VERSION +1 -1
  8. package/engine/lib/common.sh +9 -1
  9. package/engine/lib/contract.sh +1 -1
  10. package/package.json +1 -1
  11. package/packages/sync/agents/intelligence-architect.md +8 -14
  12. package/packages/sync/agents/intelligence-operator.md +3 -4
  13. package/packages/sync/references/conventions.md +3 -1
  14. package/packages/sync/rules/intelligence-authoring.md +1 -1
  15. package/packages/sync/skills/intelligence-learn-from-repository/SKILL.md +6 -7
  16. package/packages/sync/skills/intelligence-learn-from-session/SKILL.md +50 -0
  17. package/packages/sync/skills/intelligence-manage-adapters/SKILL.md +45 -0
  18. package/packages/sync/skills/intelligence-review-context/SKILL.md +54 -0
  19. package/packages/sync/skills/intelligence-review-context/references/audit-checks.md +56 -0
  20. package/packages/sync/skills/intelligence-review-context/references/compaction.md +57 -0
  21. package/packages/sync/skills/intelligence-update-context/SKILL.md +74 -0
  22. package/packages/sync/skills/intelligence-update-context/references/agents.md +31 -0
  23. package/packages/sync/skills/intelligence-update-context/references/rules.md +31 -0
  24. package/packages/sync/skills/intelligence-update-context/references/skills.md +34 -0
  25. package/packages/sync/skills/{intelligence-update → intelligence-upgrade}/SKILL.md +3 -3
  26. package/packages/sync/skills/intelligence-add-agent/SKILL.md +0 -62
  27. package/packages/sync/skills/intelligence-add-rule/SKILL.md +0 -54
  28. package/packages/sync/skills/intelligence-add-skill/SKILL.md +0 -53
  29. package/packages/sync/skills/intelligence-compact-context/SKILL.md +0 -118
  30. package/packages/sync/skills/intelligence-extract-skill/SKILL.md +0 -47
  31. package/packages/sync/skills/intelligence-install-adapter/SKILL.md +0 -45
  32. package/packages/sync/skills/intelligence-learn-from-context/SKILL.md +0 -88
  33. package/packages/sync/skills/intelligence-review-skills/SKILL.md +0 -101
  34. package/packages/sync/skills/intelligence-uninstall-adapter/SKILL.md +0 -24
  35. /package/packages/sync/skills/{intelligence-compact-context → intelligence-review-context}/references/principles.md +0 -0
@@ -0,0 +1,177 @@
1
+ #!/bin/bash
2
+ # intelligence source <add|remove|list> — the `sources:` block of the manifest.
3
+ #
4
+ # Sources are an ORDERED list of directories the engine renders, and the order
5
+ # is the override rule: adapters copy in order, the last write wins. So the
6
+ # command's real job is placement, and its default is the end of the section —
7
+ # the project's own territory, where a directory the project added wins over
8
+ # every installed package. `--before` / `--after` cover the other intent:
9
+ # content that should behave like a package (a pack developed in the repository
10
+ # that ships it) belongs after the store entries and before the project's.
11
+ #
12
+ # Installed package content is NOT managed here: `.intelligence/` entries are
13
+ # written by `package add` and removed by `package remove`, and a hand-placed
14
+ # entry under the store does not survive the next lifecycle alignment.
15
+ set -euo pipefail
16
+ source "$CLI_DIR/lib/cli-common.sh"
17
+
18
+ USAGE="usage: intelligence source <command>
19
+ add <rules|agents|skills> <dir> [--first|--last|--before <entry>|--after <entry>]
20
+ remove <rules|agents|skills> <dir>
21
+ list"
22
+
23
+ SECTIONS="rules agents skills"
24
+
25
+ assert_source_section() {
26
+ case "${1:-}" in
27
+ rules|agents|skills) ;;
28
+ "") die "$USAGE" ;;
29
+ *) die "unknown source kind '$1' — expected rules, agents or skills" ;;
30
+ esac
31
+ }
32
+
33
+ # `normalize_source_dir` reduces `./x/`, `x/.` and `x/./y` to the one spelling
34
+ # the manifest stores; it lives beside the classifier in cli-common so a typed
35
+ # path and a manifest entry are judged as the same thing. Nothing else is
36
+ # repaired — a source entry decides which artifact wins, so a path the user did
37
+ # not type is the wrong kind of help.
38
+
39
+ # assert_valid_source_dir <root> <dir> — refuse what the engine cannot report.
40
+ # The shape checks are `source_entry_problem`, shared with `status --check` so
41
+ # one definition covers both the entry about to be written and the one already
42
+ # in the manifest; the store rule is this command's alone, because a
43
+ # `.intelligence/` entry is legitimate when `package add` wrote it.
44
+ assert_valid_source_dir() {
45
+ local root="$1" dir="$2" problem
46
+ [ -n "$dir" ] || die "$USAGE"
47
+ case "$dir" in
48
+ *\\*) die "invalid source '$dir' — manifest paths use '/': ${dir//\\//}" ;;
49
+ .intelligence|.intelligence/*)
50
+ die "'$dir' is inside the CLI-managed package store — install content with 'intelligence package add', and it is wired into sources automatically"
51
+ ;;
52
+ esac
53
+ problem="$(source_entry_problem "$root" "$dir")"
54
+ [ -z "$problem" ] || die "invalid source '$dir': it $problem"
55
+ }
56
+
57
+ # Print one section with its override direction and the state of each entry.
58
+ # Position is the whole point of the block, so every mutation ends by showing
59
+ # the order it produced rather than only naming what it wrote.
60
+ print_section() {
61
+ local manifest="$1" root="$2" section="$3" entry n=0 note
62
+ echo "sources.$section (a later entry overrides an earlier one):"
63
+ while IFS= read -r entry; do
64
+ [ -n "$entry" ] || continue
65
+ n=$((n + 1))
66
+ note=""
67
+ case "$entry" in
68
+ .intelligence/*) note=" package" ;;
69
+ esac
70
+ [ -d "$root/$entry" ] || note="$note MISSING"
71
+ printf ' %d. %s%s\n' "$n" "$entry" "$note"
72
+ done < <(sources_list_entries "$manifest" "$section")
73
+ [ "$n" -eq 0 ] && echo " (none)"
74
+ return 0
75
+ }
76
+
77
+ action="${1:-}"
78
+ [ -n "$action" ] || die "$USAGE"
79
+ shift
80
+
81
+ case "$action" in
82
+ add)
83
+ section="${1:-}"
84
+ dir="${2:-}"
85
+ assert_source_section "$section"
86
+ [ -n "$dir" ] || die "$USAGE"
87
+ shift 2
88
+ pos="last"
89
+ anchor=""
90
+ pos_given=0
91
+ while [ $# -gt 0 ]; do
92
+ case "$1" in
93
+ --first|--last)
94
+ [ "$pos_given" -eq 0 ] || die "only one position may be given"
95
+ pos="${1#--}"; pos_given=1; shift
96
+ ;;
97
+ --before|--after)
98
+ [ "$pos_given" -eq 0 ] || die "only one position may be given"
99
+ [ -n "${2:-}" ] || die "$1 needs the entry to place this source next to"
100
+ pos="${1#--}"; anchor="$(normalize_source_dir "$2")"; pos_given=1; shift 2
101
+ ;;
102
+ *) die "$USAGE" ;;
103
+ esac
104
+ done
105
+
106
+ require_cli_project
107
+ dir="$(normalize_source_dir "$dir")"
108
+ assert_valid_source_dir "$IP_ROOT" "$dir"
109
+ [ "$anchor" != "$dir" ] || die "cannot place '$dir' relative to itself"
110
+ ensure_project_current "$IP_ROOT"
111
+ manifest="$IP_ROOT/intelligence.yaml"
112
+
113
+ if [ -n "$anchor" ] && ! sources_has_entry "$manifest" "$section" "$anchor"; then
114
+ echo "ERROR: sources.$section does not list '$anchor'." >&2
115
+ print_section "$manifest" "$IP_ROOT" "$section" >&2
116
+ exit 1
117
+ fi
118
+
119
+ if sources_has_entry "$manifest" "$section" "$dir"; then
120
+ if [ "$pos_given" -eq 0 ]; then
121
+ echo "already listed: sources.$section holds $dir"
122
+ print_section "$manifest" "$IP_ROOT" "$section"
123
+ exit 0
124
+ fi
125
+ sources_remove_entry "$manifest" "$section" "$dir"
126
+ sources_add_entry "$manifest" "$section" "$dir" "$pos" "$anchor"
127
+ echo "moved: $dir"
128
+ else
129
+ sources_add_entry "$manifest" "$section" "$dir" "$pos" "$anchor"
130
+ echo "added: $dir"
131
+ fi
132
+ if [ ! -d "$IP_ROOT/$dir" ]; then
133
+ echo " WARN: $dir does not exist yet — sync skips a missing source and renders it once the directory appears." >&2
134
+ fi
135
+ print_section "$manifest" "$IP_ROOT" "$section"
136
+ echo "Run 'intelligence sync' to render it."
137
+ ;;
138
+ remove)
139
+ section="${1:-}"
140
+ dir="${2:-}"
141
+ assert_source_section "$section"
142
+ [ -n "$dir" ] || die "$USAGE"
143
+ [ $# -le 2 ] || die "$USAGE"
144
+ dir="$(normalize_source_dir "$dir")"
145
+ case "$dir" in
146
+ .intelligence|.intelligence/*)
147
+ die "'$dir' is installed package content — remove the package instead: intelligence package remove <@scope/name>"
148
+ ;;
149
+ esac
150
+
151
+ require_cli_project
152
+ ensure_project_current "$IP_ROOT"
153
+ manifest="$IP_ROOT/intelligence.yaml"
154
+
155
+ if ! sources_has_entry "$manifest" "$section" "$dir"; then
156
+ echo "not listed: sources.$section does not hold $dir"
157
+ print_section "$manifest" "$IP_ROOT" "$section"
158
+ exit 0
159
+ fi
160
+ sources_remove_entry "$manifest" "$section" "$dir"
161
+ echo "removed: $dir"
162
+ echo " The directory is untouched; its artifacts leave the generated output at the next sync."
163
+ print_section "$manifest" "$IP_ROOT" "$section"
164
+ echo "Run 'intelligence sync' to rewrite the outputs."
165
+ ;;
166
+ list)
167
+ [ $# -eq 0 ] || die "$USAGE"
168
+ require_cli_project
169
+ manifest="$IP_ROOT/intelligence.yaml"
170
+ for section in $SECTIONS; do
171
+ print_section "$manifest" "$IP_ROOT" "$section"
172
+ done
173
+ ;;
174
+ *)
175
+ die "$USAGE"
176
+ ;;
177
+ esac
package/cli/intelligence CHANGED
@@ -55,6 +55,7 @@ Usage: intelligence <command> [args]
55
55
  upgrade [--next] [--preview|--apply] Replace the installed CLI with the newest npm version
56
56
  --next Follow the prerelease line instead of the stable one
57
57
  package <command> add | remove | list | search
58
+ source <command> add | remove | list — the sources: block (own directories)
58
59
  adapter <command> list | create | enable | disable | remove
59
60
  status [--check] Project state; --check runs deep consistency checks
60
61
  registry <list|add|remove> Manage the trusted registry list (add <repo-url>)
@@ -89,6 +90,10 @@ if [ ! -f "$cmd_file" ]; then
89
90
  echo "ERROR: unknown command 'packages'. Use the singular command: intelligence package list" >&2
90
91
  exit 1
91
92
  ;;
93
+ sources)
94
+ echo "ERROR: unknown command 'sources'. Use the singular command: intelligence source list" >&2
95
+ exit 1
96
+ ;;
92
97
  registries)
93
98
  echo "ERROR: unknown command 'registries'. Use the singular command: intelligence registry list" >&2
94
99
  exit 1
@@ -175,6 +175,13 @@ for section in rules agents skills; do
175
175
  case "$src" in
176
176
  git+*|@*) continue ;;
177
177
  esac
178
+ # A hand-edited entry the engine cannot render is worse than a missing
179
+ # one: it is skipped without a word and the sync still reports ok.
180
+ problem="$(source_entry_problem "$IP_ROOT" "$src")"
181
+ if [ -n "$problem" ]; then
182
+ warn "sources.$section '$src' $problem"
183
+ continue
184
+ fi
178
185
  if [ ! -d "$IP_ROOT/$src" ]; then
179
186
  case "$src" in
180
187
  # Store content is restorable state: absent means un-installed.
@@ -156,6 +156,91 @@ require_cli_project() {
156
156
 
157
157
  # --- Manifest basics (engine-readable shapes) ----------------------------
158
158
 
159
+ # normalize_source_dir_var <dir> — set IS_SOURCE_DIR to the spelling the
160
+ # manifest stores: `.` and empty segments dropped, no trailing slash. A path
161
+ # that reduces to nothing named the repository root, which is spelled `.` — so
162
+ # the caller judges one shape instead of several.
163
+ #
164
+ # Rebuilt segment by segment rather than with `${dir//\/.\//\/}`: bash 3.2, which
165
+ # is what macOS ships and CI runs, keeps the backslash of an escaped separator in
166
+ # the REPLACEMENT and produced `intelligence\/rules`, while bash 5 consumed it.
167
+ # shellcheck disable=SC2034
168
+ normalize_source_dir_var() {
169
+ local dir="$1" out="" seg rest lead=""
170
+ # A leading slash is meaning, not an empty segment: dropping it would turn
171
+ # an absolute path into a relative one and hide it from the classifier.
172
+ case "$dir" in /*) lead="/" ;; esac
173
+ rest="$dir"
174
+ while [ -n "$rest" ]; do
175
+ seg="${rest%%/*}"
176
+ if [ "$seg" = "$rest" ]; then rest=""; else rest="${rest#*/}"; fi
177
+ case "$seg" in ""|".") continue ;; esac
178
+ out="${out:+$out/}$seg"
179
+ done
180
+ if [ -n "$lead" ]; then
181
+ IS_SOURCE_DIR="$lead$out"
182
+ else
183
+ IS_SOURCE_DIR="${out:-.}"
184
+ fi
185
+ }
186
+
187
+ normalize_source_dir() {
188
+ normalize_source_dir_var "$1"
189
+ printf '%s' "$IS_SOURCE_DIR"
190
+ }
191
+
192
+ # source_entry_problem <root> <entry> — one line naming why the engine cannot
193
+ # render this `sources:` entry, or nothing when the entry is sound. Most cases
194
+ # here are invisible at sync time: the engine resolves an entry as
195
+ # `$REPO_ROOT/<entry>` and skips whatever is not a directory, so a bad entry is
196
+ # a silent omission from a run that still reports ok. `source add` refuses one
197
+ # before it is written; `status --check` reports one already in the manifest.
198
+ source_entry_problem() {
199
+ local root="$1" entry="$2" seg rest norm
200
+ case "$entry" in
201
+ "") printf 'is empty'; return 0 ;;
202
+ *\\*) printf 'uses backslashes — manifest paths use "/"'; return 0 ;;
203
+ /*|[A-Za-z]:/*)
204
+ printf 'is an absolute path — the engine resolves every entry as $REPO_ROOT/<entry>, so it renders nothing'
205
+ return 0
206
+ ;;
207
+ esac
208
+ # The root is the loud failure rather than the silent one: it IS a
209
+ # directory, so the engine reads every top-level *.md in it — README,
210
+ # CHANGELOG, docs — as an artifact of this section.
211
+ normalize_source_dir_var "$entry"
212
+ norm="$IS_SOURCE_DIR"
213
+ if [ "$norm" = "." ]; then
214
+ printf 'is the repository root — every top-level *.md there would be read as an artifact of this section'
215
+ return 0
216
+ fi
217
+ rest="$norm"
218
+ while [ -n "$rest" ]; do
219
+ seg="${rest%%/*}"
220
+ if [ "$seg" = ".." ]; then
221
+ printf 'leaves the repository — its artifacts render, but with bare names instead of links in AGENTS.md'
222
+ return 0
223
+ fi
224
+ [ "$seg" = "$rest" ] && break
225
+ rest="${rest#*/}"
226
+ done
227
+ # The entry is stored as a double-quoted YAML scalar and read back by a
228
+ # parser that strips quotes and a trailing ` # comment`.
229
+ case "$entry" in
230
+ *[\"\'\#\$\`]*|*:*)
231
+ printf 'holds a character the manifest cannot carry verbatim — allowed: letters, digits, . _ - / @'
232
+ return 0
233
+ ;;
234
+ esac
235
+ # A symlink leaves the repository without a '..' anywhere in the path.
236
+ # repo_rel_dir compares by device+inode, so it answers for the real target.
237
+ if [ -d "$root/$entry" ] && [ -z "$(repo_rel_dir "$root" "$root/$entry")" ]; then
238
+ printf 'resolves outside the repository root'
239
+ return 0
240
+ fi
241
+ return 0
242
+ }
243
+
159
244
  manifest_intelligence_dir() {
160
245
  local manifest="$1" v
161
246
  v="$(get_yaml_field "$manifest" "project" "intelligence_dir")"
@@ -184,11 +184,14 @@ qmap_field() { _qmap_read field "$1" "$2" "$3" "$4"; }
184
184
  qmap_value() { _qmap_read value "$1" "$2" "$3"; }
185
185
 
186
186
  # _qmap_stage <file> <awk-program> [awk args…] — run an editing pass, verify
187
- # it produced output, commit.
187
+ # it produced output, commit. An editor that cannot place its edit exits
188
+ # non-zero; the staged file is dropped so a refused edit never reaches the
189
+ # manifest half-applied.
188
190
  _qmap_stage() {
189
191
  local file="$1"; shift
190
- local tmp="$file.cli.tmp"
191
- awk "$@" "$file" > "$tmp"
192
+ local tmp="$file.cli.tmp" rc=0
193
+ awk "$@" "$file" > "$tmp" || rc=$?
194
+ [ "$rc" -eq 0 ] || { rm -f "$tmp"; die "internal: manifest edit refused (awk exit $rc) for $file"; }
192
195
  [ -s "$tmp" ] || { rm -f "$tmp"; die "internal: manifest edit produced an empty file for $file"; }
193
196
  mv "$tmp" "$file"
194
197
  }
@@ -399,44 +402,112 @@ registries_remove() {
399
402
  { print }
400
403
  '
401
404
  }
402
- # True (0) if <config> already lists <entry> under any sources section. Quoted
403
- # and bare spellings both count - a manifest may hold either.
404
- _mig_has_source() {
405
- local config="$1" entry="$2"
406
- [ -f "$config" ] || return 1
407
- grep -Fq -- "\"$entry\"" "$config" || grep -Fq -- "- $entry" "$config"
405
+ # --- sources: an ORDERED list of content directories ------------------------
406
+ # Adapters copy sources in order and the last write wins, so position carries
407
+ # meaning: a later entry overrides a same-named artifact from an earlier one.
408
+ # Reading goes through the engine's own list parser, so the CLI sees exactly
409
+ # what the engine will render instead of a second reading of the same file.
410
+
411
+ # sources_list_entries <file> <section> — entries of sources.<section>, one per
412
+ # line, in manifest order.
413
+ sources_list_entries() {
414
+ [ -f "$1" ] || return 0
415
+ read_yaml_list "$1" "$2"
408
416
  }
409
417
 
418
+ # sources_has_entry <file> <section> <entry> — true (0) when that section lists
419
+ # exactly this entry. Section-scoped and exact on purpose: one directory may
420
+ # legitimately appear under two sections, and a substring test over the whole
421
+ # file would silently refuse the second add — and would match a bare `- docs`
422
+ # against a neighbouring `- docs/api`.
423
+ sources_has_entry() {
424
+ local file="$1" section="$2" entry="$3" listed
425
+ [ -f "$file" ] || return 1
426
+ while IFS= read -r listed; do
427
+ [ "$listed" = "$entry" ] && return 0
428
+ done < <(sources_list_entries "$file" "$section")
429
+ return 1
430
+ }
410
431
 
411
- # sources_add_entry_first <file> <section> <entry> — idempotent insert at the
412
- # TOP of sources.<section> (creating sources:/section as needed). Package
413
- # entries go through this so project-owned entries stay later in the list —
414
- # adapters copy sources in order and the last write wins, which is exactly
415
- # the documented "your file overrides the package's" behavior.
416
- sources_add_entry_first() {
417
- local file="$1" section="$2" entry="$3"
418
- _mig_has_source "$file" "$entry" && return 0
419
- _qmap_stage "$file" -v section="$section" -v entry="$entry" '
432
+ # sources_add_entry <file> <section> <entry> [position] [anchor]
433
+ # Idempotent insert into sources.<section>, creating `sources:` and the section
434
+ # as needed. Position is `last` (default), `first`, `before` or `after`; the
435
+ # anchored forms take <anchor>, an entry the section already lists. The caller
436
+ # validates the anchor, and an edit that cannot be placed exits 3 rather than
437
+ # landing the entry somewhere else — a silently misplaced source changes which
438
+ # artifact wins.
439
+ sources_add_entry() {
440
+ local file="$1" section="$2" entry="$3" pos="${4:-last}" anchor="${5:-}"
441
+ sources_has_entry "$file" "$section" "$entry" && return 0
442
+ _qmap_stage "$file" -v section="$section" -v entry="$entry" -v pos="$pos" -v anchor="$anchor" '
420
443
  function line() { return " - \"" entry "\"" }
444
+ function place() { print line(); done = 1 }
445
+ # Blank lines inside sources: are held back so an insert lands next to
446
+ # the entries it belongs with, not after the blank line that separates
447
+ # one section from the next.
448
+ function flush_tail( i) { for (i = 1; i <= ntail; i++) print tail[i]; blanks = ntail; ntail = 0 }
449
+ function open_section() { flush_tail(); print " " section ":"; place(); if (blanks) print "" }
450
+ function value(s, v) {
451
+ v = s
452
+ sub(/^[ \t]*-[ \t]*/, "", v)
453
+ gsub(/["\x27]/, "", v)
454
+ sub(/[ \t]+#.*$/, "", v)
455
+ sub(/[ \t]+$/, "", v)
456
+ return v
457
+ }
458
+ BEGIN { anchored = (pos == "before" || pos == "after") }
421
459
  { sub(/\r$/, "") }
422
460
  /^sources:[ \t]*$/ { ins = 1; sourceseen = 1; print; next }
423
461
  ins && /^[^ #]/ {
424
- if (!secseen && !done) { print " " section ":"; print line(); done = 1 }
462
+ if (insec) { if (!done && pos == "last") place(); insec = 0 }
463
+ if (!secseen && !done && !anchored) { open_section(); secseen = 1 }
464
+ else flush_tail()
425
465
  ins = 0
426
466
  }
427
- ins && $0 ~ "^ " section ":[ \t]*$" { secseen = 1; print; print line(); done = 1; next }
428
- { print }
467
+ ins && !insec && $0 ~ "^ " section ":[ \t]*$" {
468
+ flush_tail(); secseen = 1; insec = 1; print
469
+ if (pos == "first") place()
470
+ next
471
+ }
472
+ ins && insec && /^ [A-Za-z_]/ {
473
+ if (!done && pos == "last") place()
474
+ insec = 0
475
+ flush_tail()
476
+ }
477
+ insec && /^[ \t]*-/ {
478
+ flush_tail()
479
+ v = value($0)
480
+ if (pos == "before" && v == anchor && !done) place()
481
+ print
482
+ if (pos == "after" && v == anchor && !done) place()
483
+ next
484
+ }
485
+ ins && /^[ \t]*$/ { tail[++ntail] = $0; next }
486
+ ins { flush_tail(); print; next }
487
+ { last = $0; print }
429
488
  END {
430
- if (ins && !secseen && !done) { print " " section ":"; print line(); done = 1 }
431
- if (!sourceseen) {
432
- print "sources:"
433
- print " " section ":"
434
- print line()
489
+ if (insec && !done && pos == "last") place()
490
+ flush_tail()
491
+ if (!done && !anchored) {
492
+ if (ins && !secseen) { print " " section ":"; place() }
493
+ else if (!sourceseen) {
494
+ if (last != "") print ""
495
+ print "sources:"; print " " section ":"; place()
496
+ }
435
497
  }
498
+ if (!done) exit 3
436
499
  }
437
500
  '
438
501
  }
439
502
 
503
+ # sources_add_entry_first <file> <section> <entry> — insert at the TOP of
504
+ # sources.<section>. Package wiring uses it so project-owned entries stay later
505
+ # in the list — adapters copy sources in order and the last write wins, which
506
+ # is exactly the documented "your file overrides the package's" behavior.
507
+ sources_add_entry_first() {
508
+ sources_add_entry "$1" "$2" "$3" first
509
+ }
510
+
440
511
  # sources_remove_entry <file> <section> <entry> — remove `- "entry"` from
441
512
  # sources.<section>.
442
513
  sources_remove_entry() {
package/engine/ENGINE_SHA CHANGED
@@ -1 +1 @@
1
- a9cf448bc3f2944c988ce57581822df081195ca2
1
+ 179b1e89ade2ac7d833750458de1babe0c7a6d90
package/engine/VERSION CHANGED
@@ -1 +1 @@
1
- 0.14.0
1
+ 0.16.0
@@ -1335,7 +1335,15 @@ warn_unsynced() {
1335
1335
  done < <(find "$repo_root" \( -name ".git" -o -name "node_modules" -o -name "vendor" -o -name "dist" -o -name ".claude" -o -name ".cursor" -o -name ".github" -o -name ".codex" -o -name ".agents" -o -name ".intelligence" \) -prune -o -type d \( -name "rules" -o -name "agents" -o -name "skills" -o -name "Rules" -o -name "Agents" -o -name "Skills" \) -print 2>/dev/null)
1336
1336
 
1337
1337
  if [ $warnings -gt 0 ]; then
1338
- echo " Add these paths to sources: in ${config_file##*/}"
1338
+ # Name the command that does it. A diagnostic that ends in "edit this
1339
+ # file yourself" is the one step nobody repeats the same way twice —
1340
+ # and hand-placing an entry in an ordered list decides which artifact
1341
+ # wins. The engine may also run without the CLI around it.
1342
+ if [ "${IS_CLI:-0}" = "1" ]; then
1343
+ echo " Wire one in: intelligence source add <rules|agents|skills> <path>"
1344
+ else
1345
+ echo " Add these paths to sources: in ${config_file##*/}"
1346
+ fi
1339
1347
  fi
1340
1348
  }
1341
1349
 
@@ -53,7 +53,7 @@ stamp_schema_version() {
53
53
  # --- bash ↔ skill status contract -------------------------------------------
54
54
  # Bash is the deterministic, fail-closed core: it never guesses. Any state it
55
55
  # cannot resolve safely is reported as a machine-readable status line on
56
- # stdout plus a stable exit code, and the intelligence-update SKILL (the
56
+ # stdout plus a stable exit code, and the intelligence-upgrade SKILL (the
57
57
  # intelligent layer) decides what to do. Codes are part of the public
58
58
  # contract — do not renumber.
59
59
  IS_RC_OK=0 # success (synced / migrated / nothing to do)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ainova-systems/intelligence",
3
- "version": "0.14.0",
3
+ "version": "0.16.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"
@@ -4,14 +4,10 @@ description: "Design and prune the intelligence layer - rule vs skill vs agent,
4
4
  tier: heavy
5
5
  access: full
6
6
  skills:
7
- - intelligence-add-rule
8
- - intelligence-add-agent
9
- - intelligence-add-skill
10
- - intelligence-extract-skill
11
- - intelligence-compact-context
12
- - intelligence-review-skills
7
+ - intelligence-update-context
8
+ - intelligence-review-context
13
9
  - intelligence-learn-from-repository
14
- - intelligence-learn-from-context
10
+ - intelligence-learn-from-session
15
11
  ---
16
12
 
17
13
  # Intelligence architect
@@ -44,14 +40,12 @@ The per-artifact checks are procedure, so they live in the meta-skills rather th
44
40
 
45
41
  | Skill | Use it to |
46
42
  |---|---|
47
- | `intelligence-add-rule` / `intelligence-add-agent` / `intelligence-add-skill` | author one artifact |
48
- | `intelligence-extract-skill` | turn an observed workflow into a skill |
49
- | `intelligence-compact-context` | reduce context without changing behavior or teaching terse output |
50
- | `intelligence-review-skills` | audit the layer for duplication, drift, size, hardcoded paths |
43
+ | `intelligence-update-context` | create, revise, or remove rules, agents, and skills |
44
+ | `intelligence-review-context` | audit the layer and propose reductions that preserve behavior |
51
45
  | `intelligence-learn-from-repository` | recover and complete first-time repository onboarding |
52
- | `intelligence-learn-from-context` | fold one later session lesson into an established layer |
46
+ | `intelligence-learn-from-session` | capture session lessons and observed workflows |
53
47
  | `intelligence-sync` | project the source to every tool channel |
54
- | `intelligence-update` | interpret and apply the CLI's unified update plan |
55
- | `intelligence-install-adapter` / `intelligence-uninstall-adapter` | research and manage a tool adapter |
48
+ | `intelligence-upgrade` | interpret and apply the CLI's unified update plan |
49
+ | `intelligence-manage-adapters` | enable, disable, remove, and assess output cleanup |
56
50
 
57
51
  A change is done when the sync is green and the skill you invoked reports clean. Size is a separate judgement: the caps are ceilings, not quotas, and a short artifact is not a defect.
@@ -5,9 +5,8 @@ tier: standard
5
5
  access: full
6
6
  skills:
7
7
  - intelligence-sync
8
- - intelligence-update
9
- - intelligence-install-adapter
10
- - intelligence-uninstall-adapter
8
+ - intelligence-upgrade
9
+ - intelligence-manage-adapters
11
10
  ---
12
11
 
13
12
  # Intelligence operator
@@ -27,7 +26,7 @@ the operation in prose.
27
26
  ## Boundaries
28
27
 
29
28
  - **Every flow goes through its skill.** The steps and their guards live in `intelligence-sync`,
30
- `intelligence-update`, `intelligence-install-adapter` and `intelligence-uninstall-adapter`;
29
+ `intelligence-upgrade` and `intelligence-manage-adapters`;
31
30
  improvising around them produces an unverified version of the same work.
32
31
  - **Operating is not authoring.** A change to what an artifact says - a rule body, an agent persona,
33
32
  a skill's steps - belongs to `intelligence-architect` and the authoring meta-skills. This agent
@@ -73,6 +73,8 @@ sources:
73
73
 
74
74
  Missing project-owned source directories are skipped, so a package-only project need not create empty `rules/`, `agents/` or `skills/` directories. Source order matters: later files with the same artifact name overwrite earlier ones. Package sources are wired before project sources so the project can override a package artifact deliberately.
75
75
 
76
+ Project-owned entries are managed with `intelligence source add|remove|list` rather than by hand — it validates the path against the way the engine resolves it and prints the resulting order. `add` appends by default; `--before <entry>` / `--after <entry>` place content that should behave like a package ahead of the project's own directories.
77
+
76
78
  The CLI owns package and registry blocks:
77
79
 
78
80
  ```yaml
@@ -422,7 +424,7 @@ The public lifecycle is deliberately compact:
422
424
 
423
425
  Implement Intelligence schema changes as idempotent structural checks. Stage and verify replacement state before deleting or replacing prior state. A stale engine refuses a manifest whose `schema_version` is a newer major; a newer minor or patch within the same major warns once and proceeds without restamping the project. Normal project entry points close a behind-project gap through lifecycle preflight.
424
426
 
425
- Breaking changelog entries use a `### Breaking` checklist of verifiable post-conditions. The update skill reads every release across the version gap, chooses the package/CLI/project command sequence and verifies those conditions after the deterministic command completes.
427
+ Breaking changelog entries use a `### Breaking` checklist of verifiable post-conditions. The `intelligence-upgrade` skill reads every release across the version gap, chooses the package/CLI/project command sequence and verifies those conditions after the deterministic command completes.
426
428
 
427
429
  ### Engine status contract
428
430
 
@@ -109,6 +109,6 @@ The goal is subtraction, above. These are only the line past which something is
109
109
 
110
110
  ## Verifying a change to this layer
111
111
 
112
- The per-artifact checks are a procedure, not a constraint to hold in mind while doing other work — so they live in the meta-skills, not here. Invoke the one that matches what you are doing: `intelligence-add-rule`, `intelligence-add-agent`, `intelligence-add-skill`, `intelligence-extract-skill`, `intelligence-review-skills`, `intelligence-learn-from-repository`, `intelligence-learn-from-context`, `intelligence-sync`, `intelligence-update`, `intelligence-install-adapter`, `intelligence-uninstall-adapter`.
112
+ The per-artifact authoring checks belong to `intelligence-update-context`. Session learning, repository onboarding, and accepted review findings use that same procedure. Invoke `intelligence-learn-from-session` to capture a lesson or workflow, `intelligence-learn-from-repository` for initial migration and recovery, and `intelligence-review-context` for audits and reductions. Operational work uses `intelligence-sync`, `intelligence-upgrade`, or `intelligence-manage-adapters`.
113
113
 
114
114
  A change to this layer is done when `<sync-cmd>` reports `IS_STATUS=ok` and the skill you invoked reports clean.
@@ -39,8 +39,7 @@ mechanics; this skill supplies repository judgement.
39
39
 
40
40
  5. Read `<manifest>` and resolve the configured source directories. Load
41
41
  `<module>/references/conventions.md` and the bundled
42
- `intelligence-add-rule`, `intelligence-add-skill`, and
43
- `intelligence-add-agent` skills before proposing authored content. When
42
+ `intelligence-update-context` skill before proposing authored content. When
44
43
  preserved or legacy instructions exist, also read
45
44
  `<module>/references/onboarding-migration.md` and use its inventory,
46
45
  reverse-mapping, packaging-safety, and stale-reference procedures.
@@ -87,10 +86,10 @@ explains itself well.
87
86
 
88
87
  ## Apply after approval
89
88
 
90
- 9. Apply only accepted proposals. Delegate new artifacts to
91
- `intelligence-add-rule`, `intelligence-add-skill`, or
92
- `intelligence-add-agent`; update an existing project-owned artifact directly
93
- when smaller, and edit an accepted manifest header directly. Never edit
89
+ 9. Apply only accepted proposals. Pass all artifact changes to
90
+ `intelligence-update-context`, retaining the migration evidence and acceptance
91
+ scope. Defer its batch sync to step 10 so the accepted manifest header and
92
+ content are verified together. Edit an accepted header directly. Never edit
94
93
  installed package content or generated tool output.
95
94
  10. Run `intelligence sync`, then `intelligence status --check`. Inspect the
96
95
  relevant generated `AGENTS.md`, Cursor rules, Claude rules, and any
@@ -106,6 +105,6 @@ explains itself well.
106
105
 
107
106
  ## Later learning
108
107
 
109
- After onboarding is complete, use `/intelligence-learn-from-context` to capture
108
+ After onboarding is complete, use `/intelligence-learn-from-session` to capture
110
109
  a durable lesson from a working session. It does not repeat repository
111
110
  onboarding.