@ainova-systems/intelligence 0.11.0-rc.1 → 0.11.0-rc.3
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/registry.sh +13 -0
- package/cli/commands/search.sh +84 -0
- package/cli/intelligence +1 -0
- package/cli/lib/cli-common.sh +5 -1
- package/cli/lib/manifest.sh +10 -3
- package/cli/lib/semver.sh +5 -2
- package/engine/INIT.md +2 -0
- package/engine/docs/ADAPTERS.md +3 -2
- package/engine/docs/CONVENTIONS.md +16 -2
- package/package.json +1 -1
- package/registry/index.yaml +7 -0
package/cli/commands/registry.sh
CHANGED
|
@@ -35,6 +35,19 @@ case "$sub" in
|
|
|
35
35
|
{ [ -n "$scope" ] && [ -n "$url" ]; } || die "usage: intelligence registry add @scope <registry-repo-url>"
|
|
36
36
|
case "$scope" in @*/*) die "bind a scope (@acme), not a package name" ;; @*) ;; *) die "scope must start with @" ;; esac
|
|
37
37
|
require_v2
|
|
38
|
+
# Validate at bind time, not at the first `add`: a registry is a git
|
|
39
|
+
# repo holding index.yaml, and a URL pointing at anything else (a pack
|
|
40
|
+
# repo, a typo) is a mistake worth hearing about now. The binding is
|
|
41
|
+
# still written — the registry may simply not be reachable yet.
|
|
42
|
+
index="$(_fetch_index "${url#git+}")"
|
|
43
|
+
if [ -n "$index" ]; then
|
|
44
|
+
n="$(qmap_keys "$index" "packages" | grep -c . || true)"
|
|
45
|
+
echo " index.yaml reachable — $n package(s) offered"
|
|
46
|
+
else
|
|
47
|
+
echo " WARN: no index.yaml found at $url — 'intelligence add $scope/<name>' will fail until it has one." >&2
|
|
48
|
+
echo " A registry is a git repo with index.yaml at its root (see the README of" >&2
|
|
49
|
+
echo " https://github.com/ainova-systems/intelligence-registry for the format)." >&2
|
|
50
|
+
fi
|
|
38
51
|
qmap_set_value "$IP_ROOT/intelligence.yaml" "registries" "$scope" "$url"
|
|
39
52
|
echo "$scope -> $url"
|
|
40
53
|
;;
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# intelligence search [term] — what the registries offer, and what this project
|
|
3
|
+
# already has. The catalogue view `list` deliberately is not: `list` answers
|
|
4
|
+
# "what does this project depend on", `search` answers "what could it".
|
|
5
|
+
#
|
|
6
|
+
# Sources, in resolution order (a name found earlier wins, exactly as `add`
|
|
7
|
+
# resolves it): every scope bound in the manifest, then the bundled index.
|
|
8
|
+
set -euo pipefail
|
|
9
|
+
source "$CLI_DIR/lib/cli-common.sh"
|
|
10
|
+
|
|
11
|
+
term="${1:-}"
|
|
12
|
+
|
|
13
|
+
detect_project
|
|
14
|
+
manifest=""
|
|
15
|
+
[ "$IP_MODE" = "v2" ] && manifest="$IP_ROOT/intelligence.yaml"
|
|
16
|
+
|
|
17
|
+
# State of one package name in this project: installed / declared / available.
|
|
18
|
+
pkg_state() {
|
|
19
|
+
local name="$1"
|
|
20
|
+
[ -n "$manifest" ] || { printf 'available'; return 0; }
|
|
21
|
+
local declared=0 k
|
|
22
|
+
while IFS= read -r k; do
|
|
23
|
+
[ "$k" = "$name" ] && declared=1
|
|
24
|
+
done < <(qmap_keys "$manifest" "packages")
|
|
25
|
+
if [ "$declared" -eq 0 ]; then
|
|
26
|
+
printf 'available'
|
|
27
|
+
elif [ -d "$IP_ROOT/.intelligence/packages/$name" ]; then
|
|
28
|
+
printf 'installed %s' "$(qmap_field "$IP_ROOT/intelligence.lock" "packages" "$name" "resolved")"
|
|
29
|
+
else
|
|
30
|
+
printf 'declared (run install)'
|
|
31
|
+
fi
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
seen=" "
|
|
35
|
+
rows=0
|
|
36
|
+
emit_index() {
|
|
37
|
+
local index="$1" origin="$2" name desc state
|
|
38
|
+
[ -n "$index" ] && [ -f "$index" ] || return 0
|
|
39
|
+
while IFS= read -r name; do
|
|
40
|
+
[ -n "$name" ] || continue
|
|
41
|
+
case "$seen" in *" $name "*) continue ;; esac
|
|
42
|
+
if [ -n "$term" ]; then
|
|
43
|
+
desc="$(qmap_field "$index" "packages" "$name" "description")"
|
|
44
|
+
case "$name$desc" in
|
|
45
|
+
*"$term"*) ;;
|
|
46
|
+
*) continue ;;
|
|
47
|
+
esac
|
|
48
|
+
fi
|
|
49
|
+
seen="$seen$name "
|
|
50
|
+
desc="$(qmap_field "$index" "packages" "$name" "description")"
|
|
51
|
+
state="$(pkg_state "$name")"
|
|
52
|
+
printf '%-34s %-22s %s\n' "$name" "$state" "${desc:-$(qmap_field "$index" "packages" "$name" "url")}"
|
|
53
|
+
[ "$origin" = "bundled" ] || printf '%-34s %s\n' "" " via $origin"
|
|
54
|
+
rows=$((rows + 1))
|
|
55
|
+
done < <(qmap_keys "$index" "packages")
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if [ -n "$manifest" ]; then
|
|
59
|
+
while IFS= read -r scope; do
|
|
60
|
+
[ -n "$scope" ] || continue
|
|
61
|
+
url="$(qmap_value "$manifest" "registries" "$scope")"
|
|
62
|
+
[ -n "$url" ] || continue
|
|
63
|
+
index="$(_fetch_index "${url#git+}")"
|
|
64
|
+
if [ -z "$index" ]; then
|
|
65
|
+
echo " WARN: registry for $scope is unreachable or has no index.yaml: $url" >&2
|
|
66
|
+
continue
|
|
67
|
+
fi
|
|
68
|
+
emit_index "$index" "$scope -> $url"
|
|
69
|
+
done < <(qmap_keys "$manifest" "registries")
|
|
70
|
+
fi
|
|
71
|
+
emit_index "$(default_index_file)" "bundled"
|
|
72
|
+
|
|
73
|
+
if [ "$rows" -eq 0 ]; then
|
|
74
|
+
if [ -n "$term" ]; then
|
|
75
|
+
echo "Nothing matching '$term' in the configured registries."
|
|
76
|
+
else
|
|
77
|
+
echo "No registries hold any packages."
|
|
78
|
+
fi
|
|
79
|
+
echo "Any git repo with rules/, agents/ or skills/ is a package: intelligence add @org/repo"
|
|
80
|
+
exit 0
|
|
81
|
+
fi
|
|
82
|
+
|
|
83
|
+
echo ""
|
|
84
|
+
echo "add one: intelligence add <name> | private registry: intelligence registry add @scope <repo-url>"
|
package/cli/intelligence
CHANGED
|
@@ -46,6 +46,7 @@ Usage: intelligence <command> [args]
|
|
|
46
46
|
update [name] Re-resolve version ranges and rewrite the lockfile
|
|
47
47
|
upgrade Upgrade the project to this CLI's engine (restage + restamp)
|
|
48
48
|
list Installed packages with requested/locked versions
|
|
49
|
+
search [term] What the registries offer, and what this project has
|
|
49
50
|
sync [target] Render intelligence to every enabled tool (.claude, AGENTS.md, ...)
|
|
50
51
|
registry <list|add|remove> Bind a scope to a registry index
|
|
51
52
|
migrate [--dry-run] Convert a vendored (v1) setup to the CLI setup
|
package/cli/lib/cli-common.sh
CHANGED
|
@@ -102,7 +102,11 @@ stage_engine_content() {
|
|
|
102
102
|
rm -rf "$store"
|
|
103
103
|
mkdir -p "$store"
|
|
104
104
|
local d s name skip
|
|
105
|
-
|
|
105
|
+
# `scripts` travels too: engine-shipped skills reference `<module>/scripts/…`
|
|
106
|
+
# (adapters, docs) and `<module>` resolves here, so the paths they hand an
|
|
107
|
+
# agent must exist. Running that sync.sh directly is harmless — outside CLI
|
|
108
|
+
# mode it fails closed rather than generating against the wrong layout.
|
|
109
|
+
for d in rules agents docs scripts; do
|
|
106
110
|
[ -d "$IS_ENGINE_DIR/$d" ] && cp -R "$IS_ENGINE_DIR/$d" "$store/$d"
|
|
107
111
|
done
|
|
108
112
|
if [ -d "$IS_ENGINE_DIR/skills" ]; then
|
package/cli/lib/manifest.sh
CHANGED
|
@@ -134,10 +134,13 @@ qmap_set() {
|
|
|
134
134
|
if (c > 0 && substr(line, 1, c - 1) == field) { print fieldline(); done = 1; next }
|
|
135
135
|
print; next
|
|
136
136
|
}
|
|
137
|
-
{ print }
|
|
137
|
+
{ last = $0; print }
|
|
138
138
|
END {
|
|
139
139
|
flush_key(); flush_block()
|
|
140
140
|
if (!blockseen) {
|
|
141
|
+
# A block appended to a file that does not end blank would
|
|
142
|
+
# otherwise glue itself onto the previous section.
|
|
143
|
+
if (last != "") print ""
|
|
141
144
|
print block ":"
|
|
142
145
|
print keyline()
|
|
143
146
|
print fieldline()
|
|
@@ -159,10 +162,14 @@ qmap_set_value() {
|
|
|
159
162
|
s = substr($0, 4); q = index(s, "\"")
|
|
160
163
|
if (q > 0 && substr(s, 1, q - 1) == key) { print entry(); done = 1; next }
|
|
161
164
|
}
|
|
162
|
-
{ print }
|
|
165
|
+
{ last = $0; print }
|
|
163
166
|
END {
|
|
164
167
|
if (inb && !done) { print entry(); done = 1 }
|
|
165
|
-
if (!blockseen) {
|
|
168
|
+
if (!blockseen) {
|
|
169
|
+
if (last != "") print ""
|
|
170
|
+
print block ":"
|
|
171
|
+
print entry()
|
|
172
|
+
}
|
|
166
173
|
}
|
|
167
174
|
'
|
|
168
175
|
}
|
package/cli/lib/semver.sh
CHANGED
|
@@ -39,9 +39,12 @@ semver_match() {
|
|
|
39
39
|
""|"*"|latest) return 0 ;;
|
|
40
40
|
esac
|
|
41
41
|
local op="" base="$range"
|
|
42
|
+
# Both strip patterns are quoted: an unquoted `~` in ${range#~} is a tilde
|
|
43
|
+
# EXPANSION (it becomes $HOME), so the prefix never strips and every
|
|
44
|
+
# `~x.y.z` range silently matches nothing.
|
|
42
45
|
case "$range" in
|
|
43
|
-
"^"*) op="^"; base="${range
|
|
44
|
-
"~"*) op="~"; base="${range
|
|
46
|
+
"^"*) op="^"; base="${range#'^'}" ;;
|
|
47
|
+
"~"*) op="~"; base="${range#'~'}" ;;
|
|
45
48
|
esac
|
|
46
49
|
base="${base#v}"
|
|
47
50
|
semver_is_stable "$base" || return 1
|
package/engine/INIT.md
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
The sync engine is already installed in this directory's `scripts/` subfolder. Your job: analyze this codebase, ask the user targeted questions, and generate the project-specific configuration and content.
|
|
4
4
|
|
|
5
|
+
> **The intelligence CLI is the recommended setup for new projects.** If `intelligence --version` works on this machine (or `npm i -g @ainova-systems/intelligence` is acceptable), prefer `intelligence init` + `intelligence add <package>` over this document — it automates what this bootstrap does by hand and adds versioned packages with a lockfile (see `docs/CLI.md`). This document remains the authoritative bootstrap for the **vendored** setup, which stays fully supported; a vendored project can convert later with `intelligence migrate`.
|
|
6
|
+
|
|
5
7
|
**Execute phases sequentially. Do not skip or combine phases. Each phase has a gate — wait for it before proceeding.**
|
|
6
8
|
|
|
7
9
|
## Bootstrap: install the engine if it isn't here yet
|
package/engine/docs/ADAPTERS.md
CHANGED
|
@@ -110,9 +110,10 @@ The engine ships artifacts of its own — the `intelligence-authoring` rule and
|
|
|
110
110
|
| Token | Expands to |
|
|
111
111
|
|---|---|
|
|
112
112
|
| `<umbrella>` | repo-relative umbrella dir (e.g. `Intelligence`) |
|
|
113
|
-
| `<module>` | repo-relative engine module (e.g. `Intelligence/sync`) |
|
|
113
|
+
| `<module>` | repo-relative engine module (e.g. `Intelligence/sync`; CLI setup: `.intelligence/engine`) |
|
|
114
|
+
| `<sync-cmd>` | the sync invocation — vendored: `bash <module>/scripts/sync.sh`, CLI setup: `intelligence sync` (`IS_SYNC_CMD`) |
|
|
114
115
|
|
|
115
|
-
Values are exported by `sync.sh` (`IS_UMBRELLA_REL`, `IS_MODULE_REL`), derived from the detected layout. Expansion covers frontmatter and body, so `paths: ["<umbrella>/**"]` reaches Claude's `paths:`, Cursor's `globs:` and Copilot's `applyTo:` carrying the project's real folder name. A file written without `finalize_output_file` ships a literal `<umbrella>` into an IDE — CI fails the build if any generated output still contains a token.
|
|
116
|
+
Values are exported by `sync.sh` (`IS_UMBRELLA_REL`, `IS_MODULE_REL`; `IS_SYNC_CMD` comes from the CLI in CLI mode), derived from the detected layout. Expansion covers frontmatter and body, so `paths: ["<umbrella>/**"]` reaches Claude's `paths:`, Cursor's `globs:` and Copilot's `applyTo:` carrying the project's real folder name. A file written without `finalize_output_file` ships a literal `<umbrella>` into an IDE — CI fails the build if any generated output still contains a token.
|
|
116
117
|
|
|
117
118
|
### Cleanup Contract
|
|
118
119
|
|
|
@@ -56,9 +56,10 @@ An artifact shipped *by the engine* cannot write the umbrella's name down — th
|
|
|
56
56
|
| Token | Expands to | Example |
|
|
57
57
|
|---|---|---|
|
|
58
58
|
| `<umbrella>` | repo-relative umbrella dir | `Intelligence` |
|
|
59
|
-
| `<module>` | repo-relative engine module | `Intelligence/sync` |
|
|
59
|
+
| `<module>` | repo-relative engine module | `Intelligence/sync` (CLI setup: `.intelligence/engine`) |
|
|
60
|
+
| `<sync-cmd>` | how a reader re-runs the sync | vendored: `bash Intelligence/sync/scripts/sync.sh`; CLI setup: `intelligence sync` |
|
|
60
61
|
|
|
61
|
-
Expansion covers frontmatter and body alike, so `paths: ["<umbrella>/**"]` reaches Claude's `paths:`, Cursor's `globs:` and Copilot's `applyTo:` already carrying the project's real folder name. Project-authored artifacts may use the tokens too, but they have no reason to — they can simply name their own folders.
|
|
62
|
+
Expansion covers frontmatter and body alike, so `paths: ["<umbrella>/**"]` reaches Claude's `paths:`, Cursor's `globs:` and Copilot's `applyTo:` already carrying the project's real folder name. Project-authored artifacts may use the tokens too, but they have no reason to — they can simply name their own folders. `<sync-cmd>` exists because "run a sync" is spelled differently per setup: engine content says the token, and `IS_SYNC_CMD` (set by the CLI) picks the spelling; unset, it reproduces the vendored command string exactly.
|
|
62
63
|
|
|
63
64
|
A custom adapter belongs in the umbrella's `adapters/`, never in the module's `sync/scripts/adapters/` — the module is replaced wholesale on every update, so an adapter written there disappears at the next one. See `docs/ADAPTERS.md`.
|
|
64
65
|
|
|
@@ -401,6 +402,19 @@ Bash emits `IS_STATUS=<code> [IS_DETAIL=...]` on stdout and exits with the match
|
|
|
401
402
|
|
|
402
403
|
**Module model.** The engine self-locates by its own path; it does not assume a folder name (`sync/` by convention). Each `<umbrella>/<module>/` is self-contained: its own `scripts/`(+`VERSION`), `skills/`, `INIT.md`, `docs/`. Modules update independently and never touch sibling modules or project content (`rules/`, `agents/`, non-meta `skills/`) nor `config.yaml` beyond the idempotent additive `sources.skills` line and the `sync_version` key.
|
|
403
404
|
|
|
405
|
+
**CLI mode (0.11.0+).** The `intelligence` CLI drives the same engine from outside the repo (the npm install dir); the project arrives through an env contract honored only when `IS_CLI=1` — with every variable unset the engine behaves byte-identically to the vendored flow (CI's `legacy-golden` job asserts that):
|
|
406
|
+
|
|
407
|
+
| Variable | CLI-mode value |
|
|
408
|
+
|---|---|
|
|
409
|
+
| `CONFIG_FILE` | `<root>/intelligence.yaml` (the root manifest) |
|
|
410
|
+
| `REPO_ROOT` | project root |
|
|
411
|
+
| `IS_UMBRELLA_REL` / `IS_MODULE_REL` | content dir (default `intelligence`) / `.intelligence/engine` |
|
|
412
|
+
| `IS_SYNC_CMD` | `intelligence sync` (feeds the `<sync-cmd>` token) |
|
|
413
|
+
| `IS_PROTECTED_DIRS` | colon-separated dirs `validate_output_path` must refuse — restores the source-tree protection a root manifest would otherwise disable |
|
|
414
|
+
| `IS_SUPPRESS_CLI_NOTE` | silences the vendored-flow recommendation NOTE (stderr-only either way) |
|
|
415
|
+
|
|
416
|
+
In CLI projects the `intelligence-sync` and `intelligence-update` meta-skills are not installed — `intelligence sync` / `intelligence update` replace them; the other meta-skills ship unchanged and reach outputs from `.intelligence/engine/skills`. `sync.sh` in CLI mode still never migrates: an outdated stamp exits `needs-update` and the CLI's own `upgrade` closes the gap. See `docs/CLI.md` for the full CLI surface.
|
|
417
|
+
|
|
404
418
|
## .gitignore Pattern
|
|
405
419
|
|
|
406
420
|
```
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ainova-systems/intelligence",
|
|
3
|
-
"version": "0.11.0-rc.
|
|
3
|
+
"version": "0.11.0-rc.3",
|
|
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"
|
package/registry/index.yaml
CHANGED
|
@@ -6,10 +6,17 @@
|
|
|
6
6
|
# @org/name -> https://github.com/org/name.git, content at the repo root.
|
|
7
7
|
# Organizations override or extend this per scope with `intelligence registry
|
|
8
8
|
# add @scope <registry-repo-url>`.
|
|
9
|
+
#
|
|
10
|
+
# This copy travels inside the CLI package. The same index lives at
|
|
11
|
+
# https://github.com/ainova-systems/intelligence-registry and can be bound
|
|
12
|
+
# explicitly (`intelligence registry add @ainova-systems <url>`) to read the
|
|
13
|
+
# newest entries without waiting for a CLI release.
|
|
9
14
|
packages:
|
|
10
15
|
"@ainova-systems/core":
|
|
11
16
|
url: "https://github.com/ainova-systems/intelligence-dev-packs.git"
|
|
12
17
|
path: "packs/core"
|
|
18
|
+
description: "Engineering discipline for AI-first development: context engineering, artifact-derived status, review and diagnosis loops."
|
|
13
19
|
"@ainova-systems/spec":
|
|
14
20
|
url: "https://github.com/ainova-systems/intelligence-dev-packs.git"
|
|
15
21
|
path: "packs/spec"
|
|
22
|
+
description: "Spec-driven delivery: specifications, decision records, sliced execution."
|