@ainova-systems/intelligence 0.11.0-rc.3 → 0.11.0-rc.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cli/commands/add.sh +17 -0
- package/cli/commands/doctor.sh +28 -7
- package/cli/commands/init.sh +51 -20
- package/cli/commands/install.sh +9 -3
- package/cli/commands/migrate.sh +11 -2
- package/cli/commands/registry.sh +53 -26
- package/cli/commands/remove.sh +13 -1
- package/cli/commands/search.sh +8 -7
- package/cli/commands/status.sh +5 -4
- package/cli/commands/sync.sh +19 -1
- package/cli/commands/update.sh +4 -0
- package/cli/commands/upgrade.sh +50 -9
- package/cli/lib/cli-common.sh +28 -47
- package/cli/lib/manifest.sh +79 -0
- package/cli/lib/registry.sh +77 -14
- package/cli/lib/semver.sh +5 -2
- package/engine/agents/intelligence-operator.md +4 -4
- package/engine/docs/ADAPTERS.md +2 -1
- package/engine/docs/CLI.md +14 -11
- package/engine/docs/CONVENTIONS.md +5 -3
- package/engine/rules/intelligence-authoring.md +4 -4
- package/engine/scripts/ENGINE_SHA +1 -0
- package/engine/scripts/lib/common.sh +6 -2
- package/engine/skills/intelligence-add-agent/SKILL.md +7 -7
- package/engine/skills/intelligence-add-rule/SKILL.md +5 -5
- package/engine/skills/intelligence-add-skill/SKILL.md +5 -5
- package/engine/skills/intelligence-extract-skill/SKILL.md +2 -2
- package/engine/skills/intelligence-install-adapter/SKILL.md +6 -6
- package/engine/skills/intelligence-learn-from-context/SKILL.md +1 -1
- package/engine/skills/intelligence-review-skills/SKILL.md +5 -5
- package/engine/skills/intelligence-sync/SKILL.md +5 -7
- package/engine/skills/intelligence-uninstall-adapter/SKILL.md +2 -2
- package/engine/skills/intelligence-update/SKILL.md +6 -0
- package/package.json +1 -1
- package/registry/index.yaml +4 -0
package/cli/commands/add.sh
CHANGED
|
@@ -81,6 +81,23 @@ if [ "$mode" = "registry" ]; then
|
|
|
81
81
|
echo " resolving $name via $RES_VIA -> $url${path:+ ($path)}"
|
|
82
82
|
fi
|
|
83
83
|
|
|
84
|
+
# The source must exist before anything else is attempted — a name that fell
|
|
85
|
+
# through to the convention is often just a typo, and that must say so, not
|
|
86
|
+
# die mid-pipeline with no message.
|
|
87
|
+
if ! GIT_TERMINAL_PROMPT=0 git ls-remote "$url" >/dev/null 2>&1; then
|
|
88
|
+
echo "ERROR: no reachable repository at $url" >&2
|
|
89
|
+
if [ "${RES_VIA:-}" = "convention" ]; then
|
|
90
|
+
echo " No registry declares '$name', so it resolved by convention to github.com/${name#@}." >&2
|
|
91
|
+
echo " Either the name is misspelled ('intelligence search' lists what registries offer)," >&2
|
|
92
|
+
echo " the repo is private (check your git credentials), or its registry is not added yet:" >&2
|
|
93
|
+
echo " intelligence registry add <registry-repo-url>" >&2
|
|
94
|
+
suggest_similar "$manifest" "$name"
|
|
95
|
+
else
|
|
96
|
+
echo " Declared by ${RES_VIA:-the manifest} — check the URL and your git access." >&2
|
|
97
|
+
fi
|
|
98
|
+
exit 1
|
|
99
|
+
fi
|
|
100
|
+
|
|
84
101
|
# Pick the version: an explicit ref pins; otherwise the highest stable tag
|
|
85
102
|
# matching the range (npm's behaviour, `^highest` becoming the requested range
|
|
86
103
|
# when none was given).
|
package/cli/commands/doctor.sh
CHANGED
|
@@ -43,14 +43,23 @@ else
|
|
|
43
43
|
ok "sync_version $stamp matches the engine"
|
|
44
44
|
fi
|
|
45
45
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
46
|
+
# The engine-content package must sit at the bundled engine version — the
|
|
47
|
+
# content documents exactly the scripts the CLI executes.
|
|
48
|
+
sync_locked="$(qmap_field "$lock" "packages" "$SYNC_PKG_NAME" "resolved")"
|
|
49
|
+
if [ -n "$sync_locked" ]; then
|
|
50
|
+
if [ "${sync_locked#v}" = "$eng" ]; then
|
|
51
|
+
ok "$SYNC_PKG_NAME at $sync_locked (matches the engine)"
|
|
52
|
+
else
|
|
53
|
+
warn "$SYNC_PKG_NAME locked at $sync_locked but the engine is $eng — run 'intelligence upgrade'"
|
|
54
|
+
fi
|
|
55
|
+
fi
|
|
56
|
+
if [ -d "$IP_ROOT/.intelligence/engine" ]; then
|
|
57
|
+
warn "stale .intelligence/engine directory (pre-package layout) — run 'intelligence upgrade'"
|
|
51
58
|
fi
|
|
52
59
|
|
|
53
|
-
# Manifest packages: names valid, locked, installed
|
|
60
|
+
# Manifest packages: names valid, locked, installed — and the lock's source
|
|
61
|
+
# still the one resolution would pick today (a registry silently re-pointing
|
|
62
|
+
# an installed name is the dependency-confusion tail this check cuts off).
|
|
54
63
|
while IFS= read -r name; do
|
|
55
64
|
[ -n "$name" ] || continue
|
|
56
65
|
assert_valid_pkg_name "$name"
|
|
@@ -60,6 +69,13 @@ while IFS= read -r name; do
|
|
|
60
69
|
warn "$name is locked but not installed — run 'intelligence install'"
|
|
61
70
|
else
|
|
62
71
|
ok "$name @ $(qmap_field "$lock" "packages" "$name" "resolved")"
|
|
72
|
+
if [ -z "$(qmap_field "$manifest" "packages" "$name" "url")" ]; then
|
|
73
|
+
locked_url="$(qmap_field "$lock" "packages" "$name" "url")"
|
|
74
|
+
resolve_package_source "$manifest" "$name" 2>/dev/null || true
|
|
75
|
+
if [ -n "${RES_URL:-}" ] && [ -n "$locked_url" ] && [ "$RES_URL" != "$locked_url" ]; then
|
|
76
|
+
warn "$name now resolves to $RES_URL but the lock pins $locked_url — a registry re-pointed the name; verify before 'intelligence update'"
|
|
77
|
+
fi
|
|
78
|
+
fi
|
|
63
79
|
fi
|
|
64
80
|
done < <(qmap_keys "$manifest" "packages")
|
|
65
81
|
|
|
@@ -85,8 +101,13 @@ for section in rules agents skills; do
|
|
|
85
101
|
esac
|
|
86
102
|
if [ ! -d "$IP_ROOT/$src" ]; then
|
|
87
103
|
case "$src" in
|
|
104
|
+
# Store content is restorable state: absent means un-installed.
|
|
88
105
|
.intelligence/*) warn "sources.$section '$src' missing — run 'intelligence install'" ;;
|
|
89
|
-
|
|
106
|
+
# A project-owned dir that does not exist yet is a legitimate
|
|
107
|
+
# state — a project consuming only packages authors nothing of
|
|
108
|
+
# its own — and the engine simply skips it. Declared up front so
|
|
109
|
+
# authoring later needs no config edit.
|
|
110
|
+
*) ok "sources.$section '$src' — not created yet (optional)" ;;
|
|
90
111
|
esac
|
|
91
112
|
fi
|
|
92
113
|
done < <(read_yaml_list "$manifest" "$section")
|
package/cli/commands/init.sh
CHANGED
|
@@ -8,15 +8,21 @@
|
|
|
8
8
|
set -euo pipefail
|
|
9
9
|
source "$CLI_DIR/lib/cli-common.sh"
|
|
10
10
|
|
|
11
|
-
targets_arg="" no_sync=0
|
|
11
|
+
targets_arg="" no_sync=0 content_dir="intelligence" bare=0
|
|
12
12
|
while [ $# -gt 0 ]; do
|
|
13
13
|
case "$1" in
|
|
14
14
|
--targets) shift; targets_arg="${1:-}" ;;
|
|
15
|
+
--dir) shift; content_dir="${1:-}" ;;
|
|
15
16
|
--no-sync) no_sync=1 ;;
|
|
17
|
+
--bare) bare=1 ;;
|
|
16
18
|
*) die "unknown option '$1'" ;;
|
|
17
19
|
esac
|
|
18
20
|
shift || true
|
|
19
21
|
done
|
|
22
|
+
[ -n "$content_dir" ] || die "--dir needs a directory name"
|
|
23
|
+
case "$content_dir" in
|
|
24
|
+
/*|*..*|.intelligence|.intelligence/*) die "--dir must be a plain directory inside the repo, and not the package store" ;;
|
|
25
|
+
esac
|
|
20
26
|
|
|
21
27
|
detect_project
|
|
22
28
|
case "$IP_MODE" in
|
|
@@ -41,23 +47,32 @@ fi
|
|
|
41
47
|
manifest="$root/intelligence.yaml"
|
|
42
48
|
{
|
|
43
49
|
echo "# Intelligence manifest — what this project's AI tooling knows and where it goes."
|
|
44
|
-
echo "# Managed by the intelligence CLI
|
|
50
|
+
echo "# Managed by the intelligence CLI. Reference: https://github.com/ainova-systems/intelligence-sync"
|
|
45
51
|
echo "project:"
|
|
46
52
|
echo " name: \"$(basename "$root")\""
|
|
53
|
+
[ "$content_dir" = "intelligence" ] || echo " intelligence_dir: \"$content_dir\""
|
|
47
54
|
echo ""
|
|
55
|
+
echo "# Schema version of this manifest. The CLI keeps it in step with its engine."
|
|
48
56
|
echo "sync_version: \"$(bundled_engine_version)\""
|
|
49
57
|
echo ""
|
|
58
|
+
echo "# Where content comes from. Nothing here has to exist: a directory that is"
|
|
59
|
+
echo "# absent is skipped, so a project consuming only packages authors nothing of"
|
|
60
|
+
echo "# its own. To write your own, create the directory and sync — no config edit:"
|
|
61
|
+
echo "# $content_dir/rules/context.md an always-on rule; describe the project,"
|
|
62
|
+
echo "# its stack, and the constraints to respect"
|
|
63
|
+
echo "# $content_dir/agents/<name>.md a persona (frontmatter: name, description,"
|
|
64
|
+
echo "# tier: heavy|standard|light, access: full|readonly)"
|
|
65
|
+
echo "# $content_dir/skills/<name>/SKILL.md a procedure invoked as /<name>"
|
|
66
|
+
echo "# '.intelligence/' is CLI-managed (packages + engine content) — never edit it."
|
|
50
67
|
echo "sources:"
|
|
51
68
|
echo " rules:"
|
|
52
|
-
echo " - \"
|
|
53
|
-
echo " - \".intelligence/engine/rules\""
|
|
69
|
+
echo " - \"$content_dir/rules\""
|
|
54
70
|
echo " agents:"
|
|
55
|
-
echo " - \"
|
|
56
|
-
echo " - \".intelligence/engine/agents\""
|
|
71
|
+
echo " - \"$content_dir/agents\""
|
|
57
72
|
echo " skills:"
|
|
58
|
-
echo " - \"
|
|
59
|
-
echo " - \".intelligence/engine/skills\""
|
|
73
|
+
echo " - \"$content_dir/skills\""
|
|
60
74
|
echo ""
|
|
75
|
+
echo "# Generated output, one entry per tool. Add or drop tools freely."
|
|
61
76
|
echo "targets:"
|
|
62
77
|
for t in $targets; do
|
|
63
78
|
case "$t" in
|
|
@@ -65,18 +80,24 @@ manifest="$root/intelligence.yaml"
|
|
|
65
80
|
*) echo " $t: { enabled: true, output: \".$t\" }" ;;
|
|
66
81
|
esac
|
|
67
82
|
done
|
|
83
|
+
echo ""
|
|
84
|
+
echo "# Packages are managed with 'intelligence add' / 'search' / 'list':"
|
|
85
|
+
echo "# intelligence add @ainova-systems/core from the registry"
|
|
86
|
+
echo "# intelligence add github:org/repo any repo with rules|agents|skills"
|
|
87
|
+
echo "# packages:"
|
|
88
|
+
echo "# \"@ainova-systems/core\":"
|
|
89
|
+
echo "# version: \"^0.3.0\""
|
|
90
|
+
echo ""
|
|
91
|
+
echo "# Registries are a TRUST LIST: git repos holding an index.yaml, consulted"
|
|
92
|
+
echo "# in order — the first to declare a name wins, then the CLI's bundled index,"
|
|
93
|
+
echo "# then the @org/name -> github.com/org/name convention. Adding one is a"
|
|
94
|
+
echo "# committed, reviewable act of trust in the names it declares; sources are"
|
|
95
|
+
echo "# pinned by url+sha in intelligence.lock, and overriding a bundled name"
|
|
96
|
+
echo "# warns loudly. Managed with 'intelligence registry add|remove'."
|
|
97
|
+
echo "# registries:"
|
|
98
|
+
echo "# - \"https://github.com/acme/intelligence-registry.git\""
|
|
68
99
|
} > "$manifest"
|
|
69
100
|
|
|
70
|
-
mkdir -p "$root/intelligence/rules" "$root/intelligence/agents" "$root/intelligence/skills"
|
|
71
|
-
if [ ! -f "$root/intelligence/rules/context.md" ]; then
|
|
72
|
-
cat > "$root/intelligence/rules/context.md" <<EOF
|
|
73
|
-
# Project Context
|
|
74
|
-
|
|
75
|
-
<!-- Always-on context every AI tool receives. Describe what this project is,
|
|
76
|
-
its stack, and the constraints an agent must respect. -->
|
|
77
|
-
EOF
|
|
78
|
-
fi
|
|
79
|
-
|
|
80
101
|
# The package store is restorable state, never committed — the npm model.
|
|
81
102
|
if [ ! -f "$root/.gitignore" ] || ! grep -q '^\.intelligence/' "$root/.gitignore"; then
|
|
82
103
|
{
|
|
@@ -86,9 +107,19 @@ if [ ! -f "$root/.gitignore" ] || ! grep -q '^\.intelligence/' "$root/.gitignore
|
|
|
86
107
|
} >> "$root/.gitignore"
|
|
87
108
|
fi
|
|
88
109
|
|
|
89
|
-
|
|
110
|
+
# The engine's own content (meta-skills, authoring rule, engine agents) is an
|
|
111
|
+
# ordinary package: auto-selected, opted out with --bare, removable later with
|
|
112
|
+
# 'intelligence remove @ainova-systems/sync --force'.
|
|
113
|
+
if [ "$bare" -eq 0 ]; then
|
|
114
|
+
sync_pkg_entry "$manifest"
|
|
115
|
+
sync_pkg_install "$root"
|
|
116
|
+
fi
|
|
117
|
+
|
|
90
118
|
echo "initialized: intelligence.yaml (targets:$(printf ' %s' $targets))"
|
|
91
|
-
echo "
|
|
119
|
+
[ "$bare" -eq 1 ] && echo " bare setup: no packages — engine meta-skills not installed"
|
|
120
|
+
echo " add packages: intelligence add @ainova-systems/core (browse: intelligence search)"
|
|
121
|
+
echo " write your own: create $content_dir/rules/context.md, then intelligence sync"
|
|
122
|
+
echo " docs: https://github.com/ainova-systems/intelligence-sync#readme"
|
|
92
123
|
|
|
93
124
|
if [ "$no_sync" -eq 0 ]; then
|
|
94
125
|
cd "$root"
|
package/cli/commands/install.sh
CHANGED
|
@@ -22,8 +22,6 @@ require_v2
|
|
|
22
22
|
manifest="$IP_ROOT/intelligence.yaml"
|
|
23
23
|
lock="$IP_ROOT/intelligence.lock"
|
|
24
24
|
|
|
25
|
-
ensure_engine_staged "$IP_ROOT"
|
|
26
|
-
|
|
27
25
|
# Manifest packages missing from the lock: resolve them now (npm install
|
|
28
26
|
# semantics). Under --frozen that is an error instead.
|
|
29
27
|
missing=""
|
|
@@ -36,6 +34,12 @@ done < <(qmap_keys "$manifest" "packages")
|
|
|
36
34
|
if [ -n "$missing" ]; then
|
|
37
35
|
[ "$frozen" -eq 1 ] && die "lockfile is missing packages:$missing — run 'intelligence install' without --frozen"
|
|
38
36
|
for name in $missing; do
|
|
37
|
+
# The engine-content package needs no remote resolution: its pin IS
|
|
38
|
+
# the bundled engine version and it seeds from the bundle, offline.
|
|
39
|
+
if [ "$name" = "$SYNC_PKG_NAME" ]; then
|
|
40
|
+
sync_pkg_install "$IP_ROOT"
|
|
41
|
+
continue
|
|
42
|
+
fi
|
|
39
43
|
url="$(qmap_field "$manifest" "packages" "$name" "url")"
|
|
40
44
|
path="$(qmap_field "$manifest" "packages" "$name" "path")"
|
|
41
45
|
ref="$(qmap_field "$manifest" "packages" "$name" "ref")"
|
|
@@ -67,7 +71,9 @@ if [ -f "$lock" ]; then
|
|
|
67
71
|
continue
|
|
68
72
|
fi
|
|
69
73
|
got="$(fetch_package "$url" "$resolved" "$path" "$IP_ROOT/$rel")"
|
|
70
|
-
|
|
74
|
+
# An empty sha (bundle-seeded content on a dev build) means unknown,
|
|
75
|
+
# not moved — only two known-and-different shas are a finding.
|
|
76
|
+
if [ -n "$sha" ] && [ -n "$got" ] && [ "$got" != "$sha" ]; then
|
|
71
77
|
if [ "$frozen" -eq 1 ]; then
|
|
72
78
|
die "$name: fetched $got but the lock pins $sha — the ref moved; refusing under --frozen"
|
|
73
79
|
fi
|
package/cli/commands/migrate.sh
CHANGED
|
@@ -59,7 +59,9 @@ trap cleanup_stage EXIT INT TERM
|
|
|
59
59
|
mkdir -p "$stage/.intelligence/packages"
|
|
60
60
|
|
|
61
61
|
echo "== staging =="
|
|
62
|
-
|
|
62
|
+
# Engine content arrives as the @ainova-systems/sync package, seeded from the
|
|
63
|
+
# bundle (fetch_package's guard — no network).
|
|
64
|
+
sync_pkg_sha="$(fetch_package "$SYNC_PKG_URL" "v$eng" "$SYNC_PKG_PATH" "$stage/$SYNC_PKG_STORE")"
|
|
63
65
|
|
|
64
66
|
# Legacy pack name -> v2 package name (@org/repo derived from the url), plus
|
|
65
67
|
# per-pack source facts. Recorded as rows for the config rewrite and the lock.
|
|
@@ -117,7 +119,7 @@ rewrite_source_value() {
|
|
|
117
119
|
local v="$1" pack name rest
|
|
118
120
|
case "$v" in
|
|
119
121
|
"$module_rel"/rules|"$module_rel"/agents|"$module_rel"/skills)
|
|
120
|
-
printf '
|
|
122
|
+
printf '%s/%s' "$SYNC_PKG_STORE" "${v##*/}"
|
|
121
123
|
return 0 ;;
|
|
122
124
|
@*)
|
|
123
125
|
rest="${v#@}"
|
|
@@ -168,6 +170,13 @@ while IFS="$LOCK_SEP" read -r pack name url ref mirror; do
|
|
|
168
170
|
[ -n "$ref" ] && qmap_set "$manifest_stage" "packages" "$name" "ref" "$ref"
|
|
169
171
|
done < "$pack_rows"
|
|
170
172
|
|
|
173
|
+
# The engine's own content rides along as a package, pinned to the engine.
|
|
174
|
+
qmap_set "$manifest_stage" "packages" "$SYNC_PKG_NAME" "version" "$eng"
|
|
175
|
+
qmap_set "$manifest_stage" "packages" "$SYNC_PKG_NAME" "url" "$SYNC_PKG_URL"
|
|
176
|
+
qmap_set "$manifest_stage" "packages" "$SYNC_PKG_NAME" "path" "$SYNC_PKG_PATH"
|
|
177
|
+
printf '%s\037%s\037%s\037%s\037%s\037%s\n' \
|
|
178
|
+
"$SYNC_PKG_NAME" "$eng" "$SYNC_PKG_URL" "$SYNC_PKG_PATH" "v$eng" "$sync_pkg_sha" >> "$lock_rows"
|
|
179
|
+
|
|
171
180
|
# ---- Verify ---------------------------------------------------------------
|
|
172
181
|
echo "== verifying staged state =="
|
|
173
182
|
fail=0
|
package/cli/commands/registry.sh
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
#!/bin/bash
|
|
2
|
-
# intelligence registry <list | add
|
|
2
|
+
# intelligence registry <list | add <registry-repo-url> [--force] | remove <url>>
|
|
3
3
|
#
|
|
4
|
-
#
|
|
5
|
-
#
|
|
4
|
+
# The registries block is a TRUST LIST: git repos holding an index.yaml, in
|
|
5
|
+
# trust order. Adding one is a committed, reviewable act — after it, every
|
|
6
|
+
# name that registry declares installs like a bundled one. No scope labels:
|
|
7
|
+
# names carry their own scope, and the first registry to declare a name wins.
|
|
6
8
|
set -euo pipefail
|
|
7
9
|
source "$CLI_DIR/lib/cli-common.sh"
|
|
8
10
|
|
|
@@ -11,13 +13,19 @@ case "$sub" in
|
|
|
11
13
|
list)
|
|
12
14
|
detect_project
|
|
13
15
|
if [ "$IP_MODE" = "v2" ] && [ -f "$IP_ROOT/intelligence.yaml" ]; then
|
|
14
|
-
echo "Project
|
|
16
|
+
echo "Project registries (intelligence.yaml, trust order):"
|
|
15
17
|
found=0
|
|
16
|
-
while IFS= read -r
|
|
17
|
-
[ -n "$
|
|
18
|
+
while IFS= read -r url; do
|
|
19
|
+
[ -n "$url" ] || continue
|
|
18
20
|
found=1
|
|
19
|
-
|
|
20
|
-
|
|
21
|
+
index="$(_fetch_index "${url#git+}")"
|
|
22
|
+
if [ -n "$index" ]; then
|
|
23
|
+
n="$(qmap_keys "$index" "packages" | grep -c . || true)"
|
|
24
|
+
echo " $url — $n package(s)"
|
|
25
|
+
else
|
|
26
|
+
echo " $url — UNREACHABLE or no index.yaml"
|
|
27
|
+
fi
|
|
28
|
+
done < <(registries_list "$IP_ROOT/intelligence.yaml")
|
|
21
29
|
[ "$found" -eq 0 ] && echo " (none)"
|
|
22
30
|
fi
|
|
23
31
|
bundled="$(default_index_file)"
|
|
@@ -31,34 +39,53 @@ case "$sub" in
|
|
|
31
39
|
echo "Fallback: @org/name -> https://github.com/org/name.git"
|
|
32
40
|
;;
|
|
33
41
|
add)
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
42
|
+
url="${2:-}"
|
|
43
|
+
force=0
|
|
44
|
+
[ "${3:-}" = "--force" ] && force=1
|
|
45
|
+
[ -n "$url" ] || die "usage: intelligence registry add <registry-repo-url> [--force]"
|
|
46
|
+
case "$url" in
|
|
47
|
+
@*) die "registries are added by URL — names carry their own scope. To install a package: intelligence add $url/<name>" ;;
|
|
48
|
+
esac
|
|
37
49
|
require_v2
|
|
38
|
-
#
|
|
39
|
-
#
|
|
40
|
-
#
|
|
41
|
-
#
|
|
50
|
+
# Fail closed: a URL that cannot produce an index is not a registry,
|
|
51
|
+
# and recording it would turn a typo here into a confusing failure at
|
|
52
|
+
# the first add. --force covers the one honest case: the registry is
|
|
53
|
+
# not published (or reachable) yet.
|
|
42
54
|
index="$(_fetch_index "${url#git+}")"
|
|
43
55
|
if [ -n "$index" ]; then
|
|
44
56
|
n="$(qmap_keys "$index" "packages" | grep -c . || true)"
|
|
45
|
-
echo " index.yaml reachable — $n package(s)
|
|
57
|
+
echo " index.yaml reachable — $n package(s):"
|
|
58
|
+
qmap_keys "$index" "packages" | sed 's/^/ /'
|
|
59
|
+
elif [ "$force" -eq 1 ]; then
|
|
60
|
+
echo " WARN: no index.yaml at $url — recording anyway (--force)." >&2
|
|
46
61
|
else
|
|
47
|
-
echo "
|
|
48
|
-
echo "
|
|
49
|
-
echo "
|
|
62
|
+
echo "ERROR: no index.yaml found at $url — not adding it." >&2
|
|
63
|
+
echo " A registry is a git repo with index.yaml at its root, mapping names to sources:" >&2
|
|
64
|
+
echo " packages:" >&2
|
|
65
|
+
echo " \"@acme/backend\":" >&2
|
|
66
|
+
echo " url: \"https://github.com/acme/intelligence.git\"" >&2
|
|
67
|
+
echo " path: \"packs/backend\" # omit when the repo IS the package" >&2
|
|
68
|
+
echo " Format and an example: https://github.com/ainova-systems/intelligence-registry" >&2
|
|
69
|
+
echo " A single repository needs no registry at all: intelligence add github:org/repo" >&2
|
|
70
|
+
echo " Recording it ahead of a registry that does not exist yet: --force" >&2
|
|
71
|
+
exit 1
|
|
50
72
|
fi
|
|
51
|
-
|
|
52
|
-
echo "
|
|
73
|
+
registries_add "$IP_ROOT/intelligence.yaml" "$url"
|
|
74
|
+
echo "added: $url"
|
|
53
75
|
;;
|
|
54
76
|
remove)
|
|
55
|
-
|
|
56
|
-
[ -n "$
|
|
77
|
+
url="${2:-}"
|
|
78
|
+
[ -n "$url" ] || die "usage: intelligence registry remove <url>"
|
|
57
79
|
require_v2
|
|
58
|
-
|
|
59
|
-
|
|
80
|
+
registries_remove "$IP_ROOT/intelligence.yaml" "$url"
|
|
81
|
+
# The retired flat-map form also stored scope keys — drop one if the
|
|
82
|
+
# argument names it, so old manifests clean up with the old command.
|
|
83
|
+
case "$url" in
|
|
84
|
+
@*) qmap_delete_key "$IP_ROOT/intelligence.yaml" "registries" "$url" ;;
|
|
85
|
+
esac
|
|
86
|
+
echo "removed: $url"
|
|
60
87
|
;;
|
|
61
88
|
*)
|
|
62
|
-
die "usage: intelligence registry <list | add
|
|
89
|
+
die "usage: intelligence registry <list | add <url> [--force] | remove <url>>"
|
|
63
90
|
;;
|
|
64
91
|
esac
|
package/cli/commands/remove.sh
CHANGED
|
@@ -6,15 +6,27 @@ source "$CLI_DIR/lib/cli-common.sh"
|
|
|
6
6
|
name="${1:-}"
|
|
7
7
|
[ -n "$name" ] || die "usage: intelligence remove <@scope/name>"
|
|
8
8
|
shift || true
|
|
9
|
-
no_sync=0
|
|
9
|
+
no_sync=0 force=0
|
|
10
10
|
for a in "$@"; do
|
|
11
11
|
case "$a" in
|
|
12
12
|
--no-sync) no_sync=1 ;;
|
|
13
|
+
--force) force=1 ;;
|
|
13
14
|
*) die "unknown option '$a'" ;;
|
|
14
15
|
esac
|
|
15
16
|
done
|
|
16
17
|
|
|
17
18
|
require_v2
|
|
19
|
+
|
|
20
|
+
# Removing the engine-content package guts the outputs (meta-skills, the
|
|
21
|
+
# authoring rule, both engine agents disappear) while everything still
|
|
22
|
+
# reports ok — legal, but never by accident.
|
|
23
|
+
if [ "$name" = "$SYNC_PKG_NAME" ] && [ "$force" -eq 0 ]; then
|
|
24
|
+
echo "ERROR: $SYNC_PKG_NAME is the engine's own content — removing it drops every" >&2
|
|
25
|
+
echo " intelligence-* meta-skill, the authoring rule and the engine agents from" >&2
|
|
26
|
+
echo " the outputs. The sync engine itself keeps working (it ships with the CLI)." >&2
|
|
27
|
+
echo " If that is what you want: intelligence remove $SYNC_PKG_NAME --force" >&2
|
|
28
|
+
exit 1
|
|
29
|
+
fi
|
|
18
30
|
assert_valid_pkg_name "$name"
|
|
19
31
|
manifest="$IP_ROOT/intelligence.yaml"
|
|
20
32
|
lock="$IP_ROOT/intelligence.lock"
|
package/cli/commands/search.sh
CHANGED
|
@@ -33,6 +33,9 @@ pkg_state() {
|
|
|
33
33
|
|
|
34
34
|
seen=" "
|
|
35
35
|
rows=0
|
|
36
|
+
# emit_index <index-file> <origin-label>
|
|
37
|
+
# Registries are consulted in trust order; the first to declare a name wins,
|
|
38
|
+
# so a name already seen is not repeated (that IS the resolution order).
|
|
36
39
|
emit_index() {
|
|
37
40
|
local index="$1" origin="$2" name desc state
|
|
38
41
|
[ -n "$index" ] && [ -f "$index" ] || return 0
|
|
@@ -56,17 +59,15 @@ emit_index() {
|
|
|
56
59
|
}
|
|
57
60
|
|
|
58
61
|
if [ -n "$manifest" ]; then
|
|
59
|
-
while IFS= read -r
|
|
60
|
-
[ -n "$scope" ] || continue
|
|
61
|
-
url="$(qmap_value "$manifest" "registries" "$scope")"
|
|
62
|
+
while IFS= read -r url; do
|
|
62
63
|
[ -n "$url" ] || continue
|
|
63
64
|
index="$(_fetch_index "${url#git+}")"
|
|
64
65
|
if [ -z "$index" ]; then
|
|
65
|
-
echo " WARN: registry
|
|
66
|
+
echo " WARN: registry unreachable or missing index.yaml: $url" >&2
|
|
66
67
|
continue
|
|
67
68
|
fi
|
|
68
|
-
emit_index "$index" "$
|
|
69
|
-
done < <(
|
|
69
|
+
emit_index "$index" "$url"
|
|
70
|
+
done < <(registries_list "$manifest")
|
|
70
71
|
fi
|
|
71
72
|
emit_index "$(default_index_file)" "bundled"
|
|
72
73
|
|
|
@@ -81,4 +82,4 @@ if [ "$rows" -eq 0 ]; then
|
|
|
81
82
|
fi
|
|
82
83
|
|
|
83
84
|
echo ""
|
|
84
|
-
echo "add one: intelligence add <name> | private registry: intelligence registry add
|
|
85
|
+
echo "add one: intelligence add <name> | private registry: intelligence registry add <repo-url>"
|
package/cli/commands/status.sh
CHANGED
|
@@ -13,12 +13,13 @@ case "$IP_MODE" in
|
|
|
13
13
|
else
|
|
14
14
|
echo "Lockfile: none (no packages added yet)"
|
|
15
15
|
fi
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
sync_locked="$(qmap_field "$IP_ROOT/intelligence.lock" "packages" "$SYNC_PKG_NAME" "resolved")"
|
|
17
|
+
if [ -n "$sync_locked" ]; then
|
|
18
|
+
echo "Content: $SYNC_PKG_NAME at $sync_locked"
|
|
18
19
|
else
|
|
19
|
-
echo "
|
|
20
|
+
echo "Content: no $SYNC_PKG_NAME (bare setup)"
|
|
20
21
|
fi
|
|
21
|
-
echo "Engine: $(bundled_engine_version) (bundled)"
|
|
22
|
+
echo "Engine: $(bundled_engine_version) (bundled with the CLI)"
|
|
22
23
|
;;
|
|
23
24
|
legacy)
|
|
24
25
|
echo "Project: $IP_ROOT (vendored v1 setup)"
|
package/cli/commands/sync.sh
CHANGED
|
@@ -6,7 +6,25 @@ source "$CLI_DIR/lib/cli-common.sh"
|
|
|
6
6
|
detect_project
|
|
7
7
|
case "$IP_MODE" in
|
|
8
8
|
v2)
|
|
9
|
-
|
|
9
|
+
# Fail closed, never skip silently: a store-backed source that is not
|
|
10
|
+
# on disk means the project is not installed (or predates the package
|
|
11
|
+
# model) — syncing would quietly drop whole rule sets.
|
|
12
|
+
missing="" stale=0
|
|
13
|
+
for section in rules agents skills; do
|
|
14
|
+
while IFS= read -r src; do
|
|
15
|
+
[ -n "$src" ] || continue
|
|
16
|
+
case "$src" in
|
|
17
|
+
.intelligence/engine/*) stale=1 ;;
|
|
18
|
+
.intelligence/*) [ -d "$IP_ROOT/$src" ] || missing="$missing $src" ;;
|
|
19
|
+
esac
|
|
20
|
+
done < <(read_yaml_list "$IP_ROOT/intelligence.yaml" "$section")
|
|
21
|
+
done
|
|
22
|
+
if [ "$stale" -eq 1 ]; then
|
|
23
|
+
die "this manifest predates the engine-content package (.intelligence/engine sources) — run 'intelligence upgrade'"
|
|
24
|
+
fi
|
|
25
|
+
if [ -n "$missing" ]; then
|
|
26
|
+
die "installed content missing on disk:$missing — run 'intelligence install'"
|
|
27
|
+
fi
|
|
10
28
|
export_engine_env "$IP_ROOT"
|
|
11
29
|
exec bash "$IS_ENGINE_DIR/scripts/sync.sh" "$@"
|
|
12
30
|
;;
|
package/cli/commands/update.sh
CHANGED
|
@@ -25,6 +25,10 @@ moved=0 checked=0
|
|
|
25
25
|
while IFS= read -r name; do
|
|
26
26
|
[ -n "$name" ] || continue
|
|
27
27
|
[ -n "$only" ] && [ "$name" != "$only" ] && continue
|
|
28
|
+
if [ "$name" = "$SYNC_PKG_NAME" ]; then
|
|
29
|
+
echo " $name: engine content moves with the engine — 'intelligence upgrade' owns it"
|
|
30
|
+
continue
|
|
31
|
+
fi
|
|
28
32
|
ref="$(qmap_field "$manifest" "packages" "$name" "ref")"
|
|
29
33
|
[ -n "$ref" ] && { echo " $name: pinned to ref '$ref' — skipped"; continue; }
|
|
30
34
|
range="$(qmap_field "$manifest" "packages" "$name" "version")"
|
package/cli/commands/upgrade.sh
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/bin/bash
|
|
2
|
-
# intelligence upgrade — bring the project to this CLI's engine:
|
|
3
|
-
#
|
|
4
|
-
#
|
|
2
|
+
# intelligence upgrade — bring the project to this CLI's engine: apply v2
|
|
3
|
+
# schema migrations, align the engine-content package to the bundled version,
|
|
4
|
+
# restamp sync_version, sync.
|
|
5
5
|
set -euo pipefail
|
|
6
6
|
source "$CLI_DIR/lib/cli-common.sh"
|
|
7
7
|
|
|
@@ -14,13 +14,54 @@ if [ -n "$stamp" ] && _ver_gt "$stamp" "$eng"; then
|
|
|
14
14
|
die "manifest schema $stamp is newer than this CLI's engine $eng — update the CLI first: npm i -g @ainova-systems/intelligence@latest"
|
|
15
15
|
fi
|
|
16
16
|
|
|
17
|
-
# v2 schema migrations
|
|
18
|
-
# vendored layouts
|
|
19
|
-
#
|
|
20
|
-
#
|
|
17
|
+
# --- v2 schema migrations -------------------------------------------------
|
|
18
|
+
# The engine's own chain owns vendored layouts; this one owns the manifest.
|
|
19
|
+
# Same discipline: ascending, append-only, each migration self-detects and
|
|
20
|
+
# no-ops when already applied.
|
|
21
|
+
|
|
22
|
+
# v2 migration 1: staged engine content -> the @ainova-systems/sync package.
|
|
23
|
+
# Pre-package manifests listed `.intelligence/engine/{rules,agents,skills}`
|
|
24
|
+
# as sources fed by a CLI-staged copy; that copy is now an ordinary package
|
|
25
|
+
# entry seeded from the bundle. Post-condition: no `.intelligence/engine`
|
|
26
|
+
# source entries, the package present in manifest+lock+store, stale dir gone.
|
|
27
|
+
migrated=0
|
|
28
|
+
for section in rules agents skills; do
|
|
29
|
+
while IFS= read -r src; do
|
|
30
|
+
case "$src" in
|
|
31
|
+
.intelligence/engine/*)
|
|
32
|
+
sources_remove_entry "$manifest" "$section" "$src"
|
|
33
|
+
migrated=1
|
|
34
|
+
;;
|
|
35
|
+
esac
|
|
36
|
+
done < <(read_yaml_list "$manifest" "$section")
|
|
37
|
+
done
|
|
38
|
+
if [ "$migrated" -eq 1 ]; then
|
|
39
|
+
echo " migrating: staged engine content -> $SYNC_PKG_NAME package"
|
|
40
|
+
rm -rf "$IP_ROOT/.intelligence/engine"
|
|
41
|
+
sync_pkg_entry "$manifest"
|
|
42
|
+
sync_pkg_install "$IP_ROOT"
|
|
43
|
+
fi
|
|
44
|
+
|
|
45
|
+
# --- steady state ---------------------------------------------------------
|
|
46
|
+
# Align the engine-content package with the bundled engine. Only a manifest
|
|
47
|
+
# that HAS the entry is touched — a --bare project opted out, and upgrade
|
|
48
|
+
# respects that.
|
|
49
|
+
have_pkg=0
|
|
50
|
+
while IFS= read -r name; do
|
|
51
|
+
[ "$name" = "$SYNC_PKG_NAME" ] && have_pkg=1
|
|
52
|
+
done < <(qmap_keys "$manifest" "packages")
|
|
53
|
+
if [ "$have_pkg" -eq 1 ] && [ "$migrated" -eq 0 ]; then
|
|
54
|
+
pinned="$(qmap_field "$manifest" "packages" "$SYNC_PKG_NAME" "version")"
|
|
55
|
+
if [ "$pinned" != "$eng" ]; then
|
|
56
|
+
echo " $SYNC_PKG_NAME: $pinned -> $eng"
|
|
57
|
+
fi
|
|
58
|
+
sync_pkg_entry "$manifest"
|
|
59
|
+
sync_pkg_install "$IP_ROOT"
|
|
60
|
+
fi
|
|
61
|
+
if [ "$have_pkg" -eq 0 ] && [ "$migrated" -eq 0 ]; then
|
|
62
|
+
echo " NOTE: $SYNC_PKG_NAME is not in this manifest (bare setup) — engine meta-skills stay uninstalled; 'intelligence add $SYNC_PKG_NAME' opts back in." >&2
|
|
63
|
+
fi
|
|
21
64
|
|
|
22
|
-
stage_engine_content "$IP_ROOT/.intelligence/engine"
|
|
23
|
-
echo " engine content restaged ($eng)"
|
|
24
65
|
stamp_version "$manifest" "$eng"
|
|
25
66
|
echo " sync_version -> $eng"
|
|
26
67
|
|