@ainova-systems/intelligence 0.11.0-rc.7 → 0.11.0-rc.9
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/README.md +19 -16
- package/cli/commands/adapter.sh +153 -0
- package/cli/commands/init.sh +113 -22
- package/cli/commands/package.sh +30 -0
- package/cli/commands/registry.sh +4 -2
- package/cli/commands/status.sh +12 -4
- package/cli/commands/sync.sh +7 -20
- package/cli/commands/update.sh +76 -70
- package/cli/engine-package.yaml +2 -2
- package/cli/intelligence +10 -12
- package/cli/{commands/doctor.sh → internal/check.sh} +30 -23
- package/cli/{commands/migrate.sh → internal/migrate-v1.sh} +117 -30
- package/cli/{commands/add.sh → internal/package-add.sh} +11 -16
- package/cli/{commands/list.sh → internal/package-list.sh} +9 -4
- package/cli/{commands/remove.sh → internal/package-remove.sh} +3 -3
- package/cli/{commands/search.sh → internal/package-search.sh} +4 -4
- package/cli/internal/package-update.sh +103 -0
- package/cli/{commands/install.sh → internal/restore.sh} +7 -18
- package/cli/internal/target-state.sh +57 -0
- package/cli/internal/upgrade-v2.sh +133 -0
- package/cli/lib/cli-common.sh +142 -12
- package/cli/lib/lockfile.sh +1 -1
- package/cli/lib/manifest.sh +109 -0
- package/cli/lib/registry.sh +4 -4
- package/engine/ENGINE_SHA +1 -1
- package/engine/adapters/_template.sh +10 -9
- package/engine/adapters/agents.sh +11 -11
- package/engine/adapters/opencode.sh +1 -1
- package/engine/lib/common.sh +14 -22
- package/engine/lib/contract.sh +14 -14
- package/engine/sync.sh +25 -20
- package/package.json +1 -1
- package/packages/sync/agents/intelligence-architect.md +5 -3
- package/packages/sync/agents/intelligence-operator.md +10 -13
- package/packages/sync/references/adapters.md +252 -0
- package/packages/sync/references/conventions.md +385 -0
- package/packages/sync/rules/intelligence-authoring.md +6 -6
- package/packages/sync/skills/intelligence-add-agent/SKILL.md +5 -5
- package/packages/sync/skills/intelligence-add-rule/SKILL.md +3 -3
- package/packages/sync/skills/intelligence-add-skill/SKILL.md +3 -3
- package/packages/sync/skills/intelligence-extract-skill/SKILL.md +2 -2
- package/packages/sync/skills/intelligence-install-adapter/SKILL.md +29 -22
- package/packages/sync/skills/intelligence-learn-from-context/SKILL.md +3 -3
- package/packages/sync/skills/intelligence-learn-from-repository/SKILL.md +55 -0
- package/packages/sync/skills/intelligence-review-skills/SKILL.md +6 -6
- package/packages/sync/skills/intelligence-sync/SKILL.md +13 -9
- package/packages/sync/skills/intelligence-uninstall-adapter/SKILL.md +19 -37
- package/packages/sync/skills/intelligence-update/SKILL.md +34 -156
- package/cli/commands/upgrade.sh +0 -68
- package/packages/sync/docs/ADAPTERS.md +0 -214
- package/packages/sync/docs/CONVENTIONS.md +0 -456
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/bin/bash
|
|
2
|
-
#
|
|
2
|
+
# Internal package add operation.
|
|
3
3
|
#
|
|
4
4
|
# Specs:
|
|
5
5
|
# @scope/name[@range] resolved ONLY through the manifest's trusted registries
|
|
@@ -9,7 +9,7 @@ set -euo pipefail
|
|
|
9
9
|
source "$CLI_DIR/lib/cli-common.sh"
|
|
10
10
|
|
|
11
11
|
spec="${1:-}"
|
|
12
|
-
[ -n "$spec" ] || die "usage: intelligence add <@scope/name[@range] | github:org/repo[#path] | git+<url>[@ref][#path]>"
|
|
12
|
+
[ -n "$spec" ] || die "usage: intelligence package add <@scope/name[@range] | github:org/repo[#path] | git+<url>[@ref][#path]>"
|
|
13
13
|
shift || true
|
|
14
14
|
|
|
15
15
|
no_sync=0
|
|
@@ -85,7 +85,7 @@ if [ "$mode" = "registry" ]; then
|
|
|
85
85
|
echo " ('intelligence registry list' shows them). Either add its registry:" >&2
|
|
86
86
|
echo " intelligence registry add <registry-repo-url>" >&2
|
|
87
87
|
echo " or install from an explicit source you name yourself:" >&2
|
|
88
|
-
echo " intelligence add github:org/repo | intelligence add git+<url>[@ref][#path]" >&2
|
|
88
|
+
echo " intelligence package add github:org/repo | intelligence package add git+<url>[@ref][#path]" >&2
|
|
89
89
|
suggest_similar "$manifest" "$name"
|
|
90
90
|
exit 1
|
|
91
91
|
fi
|
|
@@ -117,6 +117,7 @@ if [ -z "$ref" ]; then
|
|
|
117
117
|
die "'$name' has no stable version tags at $url — a registry package must be versioned; use github:/git+ with @<ref> to pin a branch or commit"
|
|
118
118
|
fi
|
|
119
119
|
echo " NOTE: no version tags at $url — pinning the default branch head" >&2
|
|
120
|
+
ref="HEAD"
|
|
120
121
|
fi
|
|
121
122
|
fi
|
|
122
123
|
|
|
@@ -125,22 +126,16 @@ sha="$(fetch_package "$url" "${ref:-$resolved_tag}" "$path" "$IP_ROOT/$rel")"
|
|
|
125
126
|
|
|
126
127
|
wire_package_sources "$manifest" "$name" "$rel" "$IP_ROOT"
|
|
127
128
|
|
|
128
|
-
#
|
|
129
|
-
#
|
|
130
|
-
#
|
|
131
|
-
# fields behind (a stale ref: would freeze update, a stale url: would pin the
|
|
132
|
-
# old source).
|
|
129
|
+
# The manifest records requested intent only. The resolved source URL/path,
|
|
130
|
+
# tag/ref and SHA live in the required lock. Re-adding a package is the
|
|
131
|
+
# explicit operation for changing its trusted source.
|
|
133
132
|
qmap_delete_key "$manifest" "packages" "$name"
|
|
134
|
-
if [ "$
|
|
133
|
+
if [ -n "$ref" ]; then
|
|
134
|
+
qmap_set "$manifest" "packages" "$name" "ref" "$ref"
|
|
135
|
+
elif [ -n "$requested" ]; then
|
|
135
136
|
qmap_set "$manifest" "packages" "$name" "version" "$requested"
|
|
136
137
|
else
|
|
137
|
-
|
|
138
|
-
[ -n "$path" ] && qmap_set "$manifest" "packages" "$name" "path" "$path"
|
|
139
|
-
if [ -n "$ref" ]; then
|
|
140
|
-
qmap_set "$manifest" "packages" "$name" "ref" "$ref"
|
|
141
|
-
elif [ -n "$requested" ]; then
|
|
142
|
-
qmap_set "$manifest" "packages" "$name" "version" "$requested"
|
|
143
|
-
fi
|
|
138
|
+
die "internal: package '$name' has neither a requested version nor ref"
|
|
144
139
|
fi
|
|
145
140
|
|
|
146
141
|
lock_upsert "$lock" "$name" "$requested" "$url" "$path" "${ref:-$resolved_tag}" "$sha"
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/bin/bash
|
|
2
|
-
#
|
|
2
|
+
# Internal package list operation.
|
|
3
3
|
set -euo pipefail
|
|
4
4
|
source "$CLI_DIR/lib/cli-common.sh"
|
|
5
5
|
|
|
@@ -14,8 +14,13 @@ while IFS= read -r name; do
|
|
|
14
14
|
range="$(qmap_field "$manifest" "packages" "$name" "version")"
|
|
15
15
|
ref="$(qmap_field "$manifest" "packages" "$name" "ref")"
|
|
16
16
|
resolved="$(qmap_field "$lock" "packages" "$name" "resolved")"
|
|
17
|
-
|
|
18
|
-
|
|
17
|
+
if [ ! -f "$lock" ]; then
|
|
18
|
+
state="lock missing — restore committed intelligence.lock"
|
|
19
|
+
elif [ -d "$IP_ROOT/.intelligence/packages/$name" ]; then
|
|
20
|
+
state="installed"
|
|
21
|
+
else
|
|
22
|
+
state="store missing — run 'intelligence sync'"
|
|
23
|
+
fi
|
|
19
24
|
printf '%s %s locked:%s %s\n' \
|
|
20
25
|
"$name" \
|
|
21
26
|
"${ref:+ref:$ref}${ref:-${range:-*}}" \
|
|
@@ -24,5 +29,5 @@ while IFS= read -r name; do
|
|
|
24
29
|
done < <(qmap_keys "$manifest" "packages")
|
|
25
30
|
|
|
26
31
|
if [ "$count" -eq 0 ]; then
|
|
27
|
-
echo "No packages. Add one: intelligence add @ainova-systems/core"
|
|
32
|
+
echo "No packages. Add one: intelligence package add @ainova-systems/core"
|
|
28
33
|
fi
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
#!/bin/bash
|
|
2
|
-
#
|
|
2
|
+
# Internal package remove operation.
|
|
3
3
|
set -euo pipefail
|
|
4
4
|
source "$CLI_DIR/lib/cli-common.sh"
|
|
5
5
|
|
|
6
6
|
name="${1:-}"
|
|
7
|
-
[ -n "$name" ] || die "usage: intelligence remove <@scope/name>"
|
|
7
|
+
[ -n "$name" ] || die "usage: intelligence package remove <@scope/name>"
|
|
8
8
|
shift || true
|
|
9
9
|
no_sync=0 force=0
|
|
10
10
|
for a in "$@"; do
|
|
@@ -24,7 +24,7 @@ if [ "$name" = "$SYNC_PKG_NAME" ] && [ "$force" -eq 0 ]; then
|
|
|
24
24
|
echo "ERROR: $SYNC_PKG_NAME is the engine's own content — removing it drops every" >&2
|
|
25
25
|
echo " intelligence-* meta-skill, the authoring rule and the engine agents from" >&2
|
|
26
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
|
|
27
|
+
echo " If that is what you want: intelligence package remove $SYNC_PKG_NAME --force" >&2
|
|
28
28
|
exit 1
|
|
29
29
|
fi
|
|
30
30
|
assert_valid_pkg_name "$name"
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/bin/bash
|
|
2
|
-
#
|
|
2
|
+
# Internal package search operation: what the registries offer and what this project
|
|
3
3
|
# already has. The catalogue view `list` deliberately is not: `list` answers
|
|
4
4
|
# "what does this project depend on", `search` answers "what could it".
|
|
5
5
|
#
|
|
@@ -27,7 +27,7 @@ pkg_state() {
|
|
|
27
27
|
elif [ -d "$IP_ROOT/.intelligence/packages/$name" ]; then
|
|
28
28
|
printf 'installed %s' "$(qmap_field "$IP_ROOT/intelligence.lock" "packages" "$name" "resolved")"
|
|
29
29
|
else
|
|
30
|
-
printf 'declared (run
|
|
30
|
+
printf 'declared (run sync)'
|
|
31
31
|
fi
|
|
32
32
|
}
|
|
33
33
|
|
|
@@ -75,9 +75,9 @@ if [ "$rows" -eq 0 ]; then
|
|
|
75
75
|
else
|
|
76
76
|
echo "No trusted registries (or they offer nothing) — intelligence registry add <repo-url>."
|
|
77
77
|
fi
|
|
78
|
-
echo "Explicit installs need no registry: intelligence add github:org/repo"
|
|
78
|
+
echo "Explicit installs need no registry: intelligence package add github:org/repo"
|
|
79
79
|
exit 0
|
|
80
80
|
fi
|
|
81
81
|
|
|
82
82
|
echo ""
|
|
83
|
-
echo "add one: intelligence add <name> | private registry: intelligence registry add <repo-url>"
|
|
83
|
+
echo "add one: intelligence package add <name> | private registry: intelligence registry add <repo-url>"
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Internal package range update operation.
|
|
3
|
+
#
|
|
4
|
+
# Resolve requested versions/refs against each package's locked source and
|
|
5
|
+
# rewrite the lock. `update <name>` limits the pass to one package; re-adding
|
|
6
|
+
# is the explicit operation for changing a source URL/path.
|
|
7
|
+
set -euo pipefail
|
|
8
|
+
source "$CLI_DIR/lib/cli-common.sh"
|
|
9
|
+
|
|
10
|
+
only="" no_sync=0 preview=0
|
|
11
|
+
while [ $# -gt 0 ]; do
|
|
12
|
+
case "$1" in
|
|
13
|
+
--no-sync) no_sync=1 ;;
|
|
14
|
+
--preview) preview=1 ;;
|
|
15
|
+
@*) only="$1" ;;
|
|
16
|
+
*) die "unknown argument '$1'" ;;
|
|
17
|
+
esac
|
|
18
|
+
shift || true
|
|
19
|
+
done
|
|
20
|
+
|
|
21
|
+
require_v2
|
|
22
|
+
manifest="$IP_ROOT/intelligence.yaml"
|
|
23
|
+
lock="$IP_ROOT/intelligence.lock"
|
|
24
|
+
|
|
25
|
+
moved=0 found=0
|
|
26
|
+
while IFS= read -r name; do
|
|
27
|
+
[ -n "$name" ] || continue
|
|
28
|
+
# Manifest keys are untrusted input on their way into store paths.
|
|
29
|
+
assert_valid_pkg_name "$name"
|
|
30
|
+
[ -n "$only" ] && [ "$name" != "$only" ] && continue
|
|
31
|
+
# A named package that exists is "found" whatever happens next — a skip
|
|
32
|
+
# message followed by "not in the manifest" would contradict itself.
|
|
33
|
+
found=1
|
|
34
|
+
if [ "$name" = "$SYNC_PKG_NAME" ]; then
|
|
35
|
+
echo " $name: engine content follows the installed CLI — skipped"
|
|
36
|
+
continue
|
|
37
|
+
fi
|
|
38
|
+
current="$(qmap_field "$lock" "packages" "$name" "resolved")"
|
|
39
|
+
locked_requested="$(qmap_field "$lock" "packages" "$name" "requested")"
|
|
40
|
+
url="$(qmap_field "$lock" "packages" "$name" "url")"
|
|
41
|
+
path="$(qmap_field "$lock" "packages" "$name" "path")"
|
|
42
|
+
[ -n "$url" ] || die "$name has no source in intelligence.lock — restore the committed lock or re-add the package"
|
|
43
|
+
ref="$(qmap_field "$manifest" "packages" "$name" "ref")"
|
|
44
|
+
range="$(qmap_field "$manifest" "packages" "$name" "version")"
|
|
45
|
+
[ -n "$ref" ] || [ -n "$range" ] || die "$name has neither version nor ref in the manifest"
|
|
46
|
+
|
|
47
|
+
if [ -n "$ref" ]; then
|
|
48
|
+
tag="$ref"
|
|
49
|
+
requested=""
|
|
50
|
+
else
|
|
51
|
+
picked="$(list_remote_versions "$url" | semver_pick_highest "$range")"
|
|
52
|
+
[ -n "$picked" ] || { echo " $name: nothing satisfies '$range' at $url" >&2; continue; }
|
|
53
|
+
read -r tag _ <<< "$(remote_tag_for_version "$url" "$picked")"
|
|
54
|
+
requested="$range"
|
|
55
|
+
fi
|
|
56
|
+
if [ "$tag" = "$current" ] && [ "$requested" != "$locked_requested" ]; then
|
|
57
|
+
if [ "$preview" -eq 1 ]; then
|
|
58
|
+
echo " $name: request ${locked_requested:-<none>} -> ${requested:-<ref>} (keeps $current)"
|
|
59
|
+
else
|
|
60
|
+
locked_sha="$(qmap_field "$lock" "packages" "$name" "sha")"
|
|
61
|
+
lock_upsert "$lock" "$name" "$requested" "$url" "$path" "$current" "$locked_sha"
|
|
62
|
+
echo " $name: request ${locked_requested:-<none>} -> ${requested:-<ref>} (kept $current)"
|
|
63
|
+
fi
|
|
64
|
+
moved=$((moved + 1))
|
|
65
|
+
continue
|
|
66
|
+
fi
|
|
67
|
+
if [ "$tag" = "$current" ]; then
|
|
68
|
+
echo " $name: ${current:-<none>} (up to date)"
|
|
69
|
+
continue
|
|
70
|
+
fi
|
|
71
|
+
if [ "$preview" -eq 1 ]; then
|
|
72
|
+
echo " $name: ${current:-<none>} -> $tag"
|
|
73
|
+
moved=$((moved + 1))
|
|
74
|
+
continue
|
|
75
|
+
fi
|
|
76
|
+
rel=".intelligence/packages/$name"
|
|
77
|
+
# Fetch into staging FIRST: a failed clone must leave the current install
|
|
78
|
+
# fully wired and intact. Only after success is the old shape unwired
|
|
79
|
+
# (the new version may have dropped a section dir), the store swapped,
|
|
80
|
+
# and the new shape wired.
|
|
81
|
+
staging="$IP_ROOT/.intelligence/.staging-$$"
|
|
82
|
+
rm -rf "$staging"
|
|
83
|
+
sha="$(fetch_package "$url" "$tag" "$path" "$staging")"
|
|
84
|
+
unwire_package_sources "$manifest" "$rel"
|
|
85
|
+
rm -rf "${IP_ROOT:?}/$rel"
|
|
86
|
+
mkdir -p "$(dirname "$IP_ROOT/$rel")"
|
|
87
|
+
mv "$staging" "$IP_ROOT/$rel"
|
|
88
|
+
wire_package_sources "$manifest" "$name" "$rel" "$IP_ROOT"
|
|
89
|
+
lock_upsert "$lock" "$name" "$requested" "$url" "$path" "$tag" "$sha"
|
|
90
|
+
echo " $name: ${current:-<none>} -> $tag"
|
|
91
|
+
moved=$((moved + 1))
|
|
92
|
+
done < <(qmap_keys "$manifest" "packages")
|
|
93
|
+
|
|
94
|
+
[ -n "$only" ] && [ "$found" -eq 0 ] && die "package '$only' is not in the manifest"
|
|
95
|
+
if [ "$preview" -eq 1 ]; then
|
|
96
|
+
echo "updates available: $moved package(s)"
|
|
97
|
+
else
|
|
98
|
+
echo "updated: $moved package(s)"
|
|
99
|
+
fi
|
|
100
|
+
|
|
101
|
+
if [ "$preview" -eq 0 ] && [ "$moved" -gt 0 ] && [ "$no_sync" -eq 0 ]; then
|
|
102
|
+
exec bash "$CLI_DIR/commands/sync.sh"
|
|
103
|
+
fi
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/bin/bash
|
|
2
|
-
#
|
|
2
|
+
# Internal locked-store restore operation.
|
|
3
3
|
#
|
|
4
4
|
# Restore .intelligence/ from intelligence.lock — the fresh-clone command.
|
|
5
5
|
# --frozen additionally refuses any manifest/lock divergence (CI mode) and
|
|
@@ -23,30 +23,22 @@ manifest="$IP_ROOT/intelligence.yaml"
|
|
|
23
23
|
lock="$IP_ROOT/intelligence.lock"
|
|
24
24
|
|
|
25
25
|
# --frozen is the reproducibility contract: the lock must agree with the
|
|
26
|
-
# manifest on the package SET and on every requested-
|
|
26
|
+
# manifest on the package SET and on every requested-intent field before a
|
|
27
27
|
# single byte is restored. Anything less lets a manifest edit ride on a stale
|
|
28
28
|
# lock — the exact drift the flag exists to refuse.
|
|
29
29
|
if [ "$frozen" -eq 1 ]; then
|
|
30
30
|
while IFS= read -r name; do
|
|
31
31
|
[ -n "$name" ] || continue
|
|
32
32
|
[ -n "$(qmap_field "$lock" "packages" "$name" "url")" ] \
|
|
33
|
-
|| die "
|
|
33
|
+
|| die "locked restore: $name is in the manifest but not in intelligence.lock"
|
|
34
34
|
m_ver="$(qmap_field "$manifest" "packages" "$name" "version")"
|
|
35
35
|
m_ref="$(qmap_field "$manifest" "packages" "$name" "ref")"
|
|
36
|
-
m_url="$(qmap_field "$manifest" "packages" "$name" "url")"
|
|
37
|
-
m_path="$(qmap_field "$manifest" "packages" "$name" "path")"
|
|
38
36
|
l_req="$(qmap_field "$lock" "packages" "$name" "requested")"
|
|
39
37
|
l_res="$(qmap_field "$lock" "packages" "$name" "resolved")"
|
|
40
|
-
l_url="$(qmap_field "$lock" "packages" "$name" "url")"
|
|
41
|
-
l_path="$(qmap_field "$lock" "packages" "$name" "path")"
|
|
42
38
|
[ -z "$m_ver" ] || [ "$m_ver" = "$l_req" ] \
|
|
43
|
-
|| die "
|
|
39
|
+
|| die "locked restore: $name requests '$m_ver' but the lock recorded '$l_req' — reconcile the manifest and lock"
|
|
44
40
|
[ -z "$m_ref" ] || [ "$m_ref" = "$l_res" ] \
|
|
45
41
|
|| die "--frozen: $name pins ref '$m_ref' but the lock resolved '$l_res'"
|
|
46
|
-
[ -z "$m_url" ] || [ "$m_url" = "$l_url" ] \
|
|
47
|
-
|| die "--frozen: $name declares url '$m_url' but the lock recorded '$l_url'"
|
|
48
|
-
[ -z "$m_path" ] || [ "$m_path" = "$l_path" ] \
|
|
49
|
-
|| die "--frozen: $name declares path '$m_path' but the lock recorded '$l_path'"
|
|
50
42
|
done < <(qmap_keys "$manifest" "packages")
|
|
51
43
|
while IFS= read -r name; do
|
|
52
44
|
[ -n "$name" ] || continue
|
|
@@ -76,14 +68,11 @@ if [ -n "$missing" ]; then
|
|
|
76
68
|
sync_pkg_install "$IP_ROOT"
|
|
77
69
|
continue
|
|
78
70
|
fi
|
|
79
|
-
url="$(qmap_field "$manifest" "packages" "$name" "url")"
|
|
80
|
-
path="$(qmap_field "$manifest" "packages" "$name" "path")"
|
|
81
71
|
ref="$(qmap_field "$manifest" "packages" "$name" "ref")"
|
|
82
72
|
range="$(qmap_field "$manifest" "packages" "$name" "version")"
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
fi
|
|
73
|
+
resolve_package_source "$manifest" "$name"
|
|
74
|
+
url="$RES_URL"; path="$RES_PATH"
|
|
75
|
+
[ -n "$url" ] || die "no trusted registry declares '$name' and it is absent from intelligence.lock"
|
|
87
76
|
resolved_tag=""
|
|
88
77
|
if [ -z "$ref" ]; then
|
|
89
78
|
picked="$(list_remote_versions "$url" | semver_pick_highest "$range")"
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Internal adapter target-state operation.
|
|
3
|
+
#
|
|
4
|
+
# Change only the manifest. Syncing and deleting generated output are separate
|
|
5
|
+
# explicit actions: a generic target command cannot infer a custom adapter's
|
|
6
|
+
# ownership safely.
|
|
7
|
+
set -euo pipefail
|
|
8
|
+
source "$CLI_DIR/lib/cli-common.sh"
|
|
9
|
+
|
|
10
|
+
action="${1:-}"
|
|
11
|
+
name="${2:-}"
|
|
12
|
+
[ $# -le 2 ] || die "internal target state: expected <enable|disable> <name>"
|
|
13
|
+
case "$action" in enable|disable) ;; *) die "internal target state: expected <enable|disable> <name>" ;; esac
|
|
14
|
+
[ -n "$name" ] || die "internal target state: missing adapter name"
|
|
15
|
+
assert_valid_target_name "$name"
|
|
16
|
+
|
|
17
|
+
require_v2
|
|
18
|
+
manifest="$IP_ROOT/intelligence.yaml"
|
|
19
|
+
content_dir="$(manifest_intelligence_dir "$manifest")"
|
|
20
|
+
|
|
21
|
+
if [ "$action" = "enable" ]; then
|
|
22
|
+
project_adapter="$IP_ROOT/$content_dir/adapters/$name.sh"
|
|
23
|
+
bundled_adapter="$IS_ENGINE_DIR/adapters/$name.sh"
|
|
24
|
+
if [ ! -f "$project_adapter" ] && [ ! -f "$bundled_adapter" ]; then
|
|
25
|
+
die "adapter '$name' not found — create it first: intelligence adapter create $name"
|
|
26
|
+
fi
|
|
27
|
+
|
|
28
|
+
# These adapters intentionally omit always-on rules because their tools
|
|
29
|
+
# read AGENTS.md. Do not create a manifest that full sync must refuse.
|
|
30
|
+
case "$name" in
|
|
31
|
+
cursor|copilot|codex|pi|opencode)
|
|
32
|
+
if [ "$(is_target_enabled "$manifest" "agents")" != "1" ]; then
|
|
33
|
+
die "target '$name' requires target 'agents' — enable it first"
|
|
34
|
+
fi
|
|
35
|
+
;;
|
|
36
|
+
esac
|
|
37
|
+
|
|
38
|
+
output="$(get_target_output "$manifest" "$name")"
|
|
39
|
+
[ -n "$output" ] || output="$(default_target_output "$name")"
|
|
40
|
+
target_set_enabled "$manifest" "$name" true "$output"
|
|
41
|
+
echo "enabled: $name (output: $output)"
|
|
42
|
+
exit 0
|
|
43
|
+
fi
|
|
44
|
+
|
|
45
|
+
target_exists "$manifest" "$name" || die "target '$name' is not in the manifest"
|
|
46
|
+
if [ "$name" = "agents" ]; then
|
|
47
|
+
for dependent in cursor copilot codex pi opencode; do
|
|
48
|
+
if [ "$(is_target_enabled "$manifest" "$dependent")" = "1" ]; then
|
|
49
|
+
die "target 'agents' is required by enabled target '$dependent' — disable '$dependent' first"
|
|
50
|
+
fi
|
|
51
|
+
done
|
|
52
|
+
fi
|
|
53
|
+
output="$(get_target_output "$manifest" "$name")"
|
|
54
|
+
[ -n "$output" ] || output="$(default_target_output "$name")"
|
|
55
|
+
target_set_enabled "$manifest" "$name" false "$output"
|
|
56
|
+
echo "disabled: $name"
|
|
57
|
+
echo " generated output was kept; remove only paths owned by this adapter"
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Internal: bring the project to this CLI's engine: apply v2
|
|
3
|
+
# schema migrations, align the engine-content package to the bundled version,
|
|
4
|
+
# restamp schema_version, sync.
|
|
5
|
+
set -euo pipefail
|
|
6
|
+
source "$CLI_DIR/lib/cli-common.sh"
|
|
7
|
+
|
|
8
|
+
no_sync=0
|
|
9
|
+
while [ $# -gt 0 ]; do
|
|
10
|
+
case "$1" in
|
|
11
|
+
--no-sync) no_sync=1 ;;
|
|
12
|
+
*) die "internal upgrade: unknown option '$1'" ;;
|
|
13
|
+
esac
|
|
14
|
+
shift
|
|
15
|
+
done
|
|
16
|
+
|
|
17
|
+
require_v2
|
|
18
|
+
manifest="$IP_ROOT/intelligence.yaml"
|
|
19
|
+
|
|
20
|
+
stamp="$(read_schema_version "$manifest")"
|
|
21
|
+
legacy_stamp="$(top_scalar "$manifest" "sync_version")"
|
|
22
|
+
schema_key_count="$(awk '/^schema_version:[[:space:]]*/ { n++ } END { print n + 0 }' "$manifest")"
|
|
23
|
+
legacy_key_count="$(awk '/^sync_version:[[:space:]]*/ { n++ } END { print n + 0 }' "$manifest")"
|
|
24
|
+
eng="$(bundled_engine_version)"
|
|
25
|
+
[ "$schema_key_count" -le 1 ] || die "manifest has duplicate schema_version keys"
|
|
26
|
+
[ "$legacy_key_count" -le 1 ] || die "manifest has duplicate sync_version keys"
|
|
27
|
+
if [ -n "$stamp" ] && _ver_gt "$stamp" "$eng"; then
|
|
28
|
+
die "manifest schema $stamp is newer than this CLI's engine $eng — update the global CLI first"
|
|
29
|
+
fi
|
|
30
|
+
if [ -n "$legacy_stamp" ] && _ver_gt "$legacy_stamp" "$eng"; then
|
|
31
|
+
die "manifest schema $legacy_stamp is newer than this CLI's engine $eng — update the global CLI first"
|
|
32
|
+
fi
|
|
33
|
+
|
|
34
|
+
# --- v2 schema migrations -------------------------------------------------
|
|
35
|
+
# The engine's own chain owns vendored layouts; this one owns the manifest.
|
|
36
|
+
# Same discipline: ascending, append-only, each migration self-detects and
|
|
37
|
+
# no-ops when already applied.
|
|
38
|
+
|
|
39
|
+
# v2 migration 0: the original RC manifest called the permanent schema key
|
|
40
|
+
# `sync_version`. Rename it without changing its value; the final stamp below
|
|
41
|
+
# then aligns it with this engine. The archived v1 reader remains separate.
|
|
42
|
+
if [ -n "$legacy_stamp" ]; then
|
|
43
|
+
if [ -n "$stamp" ]; then
|
|
44
|
+
[ "$stamp" = "$legacy_stamp" ] || die "manifest has conflicting schema_version '$stamp' and sync_version '$legacy_stamp'"
|
|
45
|
+
_qmap_stage "$manifest" '$0 !~ /^sync_version:[[:space:]]*/'
|
|
46
|
+
else
|
|
47
|
+
_qmap_stage "$manifest" '{ sub(/^sync_version:/, "schema_version:"); print }'
|
|
48
|
+
fi
|
|
49
|
+
echo " migrating: sync_version -> schema_version"
|
|
50
|
+
fi
|
|
51
|
+
|
|
52
|
+
# v2 migration 1: package entries contain requested intent only. Early RCs
|
|
53
|
+
# also copied resolved url/path into the manifest. Preserve the existing lock
|
|
54
|
+
# as the trusted source and remove that duplicate representation. A direct
|
|
55
|
+
# unversioned package becomes an explicit HEAD pin so its manifest entry stays
|
|
56
|
+
# meaningful after the source fields are removed.
|
|
57
|
+
source_fields_migrated=0
|
|
58
|
+
while IFS= read -r name; do
|
|
59
|
+
[ -n "$name" ] || continue
|
|
60
|
+
m_url="$(qmap_field "$manifest" "packages" "$name" "url")"
|
|
61
|
+
m_path="$(qmap_field "$manifest" "packages" "$name" "path")"
|
|
62
|
+
[ -n "$m_url" ] || [ -n "$m_path" ] || continue
|
|
63
|
+
m_ver="$(qmap_field "$manifest" "packages" "$name" "version")"
|
|
64
|
+
m_ref="$(qmap_field "$manifest" "packages" "$name" "ref")"
|
|
65
|
+
if [ -z "$m_ver" ] && [ -z "$m_ref" ]; then
|
|
66
|
+
locked_ref="$(qmap_field "$IP_ROOT/intelligence.lock" "packages" "$name" "resolved")"
|
|
67
|
+
qmap_set "$manifest" "packages" "$name" "ref" "${locked_ref:-HEAD}"
|
|
68
|
+
fi
|
|
69
|
+
qmap_delete_field "$manifest" "packages" "$name" "url"
|
|
70
|
+
qmap_delete_field "$manifest" "packages" "$name" "path"
|
|
71
|
+
source_fields_migrated=1
|
|
72
|
+
done < <(qmap_keys "$manifest" "packages")
|
|
73
|
+
if [ "$source_fields_migrated" -eq 1 ]; then
|
|
74
|
+
echo " migrating: package url/path -> intelligence.lock"
|
|
75
|
+
fi
|
|
76
|
+
|
|
77
|
+
# v2 migration 2: staged engine content -> the @ainova-systems/sync package.
|
|
78
|
+
# Pre-package manifests listed `.intelligence/engine/{rules,agents,skills}`
|
|
79
|
+
# as sources fed by a CLI-staged copy; that copy is now an ordinary package
|
|
80
|
+
# entry seeded from the bundle. Post-condition: no `.intelligence/engine`
|
|
81
|
+
# source entries, the package present in manifest+lock+store, stale dir gone.
|
|
82
|
+
migrated=0
|
|
83
|
+
for section in rules agents skills; do
|
|
84
|
+
while IFS= read -r src; do
|
|
85
|
+
case "$src" in
|
|
86
|
+
.intelligence/engine/*)
|
|
87
|
+
sources_remove_entry "$manifest" "$section" "$src"
|
|
88
|
+
migrated=1
|
|
89
|
+
;;
|
|
90
|
+
esac
|
|
91
|
+
done < <(read_yaml_list "$manifest" "$section")
|
|
92
|
+
done
|
|
93
|
+
if [ "$migrated" -eq 1 ]; then
|
|
94
|
+
echo " migrating: staged engine content -> $SYNC_PKG_NAME package"
|
|
95
|
+
rm -rf "$IP_ROOT/.intelligence/engine"
|
|
96
|
+
sync_pkg_entry "$manifest"
|
|
97
|
+
sync_pkg_install "$IP_ROOT"
|
|
98
|
+
fi
|
|
99
|
+
|
|
100
|
+
# --- steady state ---------------------------------------------------------
|
|
101
|
+
# Align the engine-content package with the bundled engine. Only a manifest
|
|
102
|
+
# that HAS the entry is touched — a --bare project opted out, and upgrade
|
|
103
|
+
# respects that.
|
|
104
|
+
have_pkg=0
|
|
105
|
+
while IFS= read -r name; do
|
|
106
|
+
[ "$name" = "$SYNC_PKG_NAME" ] && have_pkg=1
|
|
107
|
+
done < <(qmap_keys "$manifest" "packages")
|
|
108
|
+
if [ "$have_pkg" -eq 1 ] && [ "$migrated" -eq 0 ]; then
|
|
109
|
+
pinned="$(qmap_field "$manifest" "packages" "$SYNC_PKG_NAME" "version")"
|
|
110
|
+
if [ "$pinned" != "$eng" ]; then
|
|
111
|
+
echo " $SYNC_PKG_NAME: $pinned -> $eng"
|
|
112
|
+
fi
|
|
113
|
+
sync_pkg_entry "$manifest"
|
|
114
|
+
sync_pkg_install "$IP_ROOT"
|
|
115
|
+
fi
|
|
116
|
+
if [ "$have_pkg" -eq 0 ] && [ "$migrated" -eq 0 ]; then
|
|
117
|
+
echo " NOTE: $SYNC_PKG_NAME is not in this manifest (bare setup) — engine meta-skills stay uninstalled; 'intelligence package add $SYNC_PKG_NAME' opts back in." >&2
|
|
118
|
+
fi
|
|
119
|
+
|
|
120
|
+
# A previous RC could leave this managed directory even after its source
|
|
121
|
+
# entries were already removed. Its presence is itself an upgrade predicate,
|
|
122
|
+
# so always close that post-condition.
|
|
123
|
+
if [ -d "$IP_ROOT/.intelligence/engine" ]; then
|
|
124
|
+
rm -rf "$IP_ROOT/.intelligence/engine"
|
|
125
|
+
echo " removed stale .intelligence/engine"
|
|
126
|
+
fi
|
|
127
|
+
|
|
128
|
+
stamp_schema_version "$manifest" "$eng"
|
|
129
|
+
echo " schema_version -> $eng"
|
|
130
|
+
|
|
131
|
+
if [ "$no_sync" -eq 0 ]; then
|
|
132
|
+
exec bash "$CLI_DIR/commands/sync.sh"
|
|
133
|
+
fi
|