@ainova-systems/intelligence 0.11.5 → 0.11.6
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/internal/check.sh +1 -1
- package/cli/internal/package-list.sh +2 -1
- package/cli/internal/package-update.sh +58 -6
- package/cli/lib/cli-common.sh +21 -0
- package/cli/lib/semver.sh +33 -0
- package/engine/ENGINE_SHA +1 -1
- package/engine/VERSION +1 -1
- package/package.json +1 -1
package/cli/internal/check.sh
CHANGED
|
@@ -82,7 +82,7 @@ while IFS= read -r name; do
|
|
|
82
82
|
warn "$name is locked but not installed — run 'intelligence sync'"
|
|
83
83
|
continue
|
|
84
84
|
fi
|
|
85
|
-
ok "$name @ $(qmap_field "$lock" "packages" "$name" "
|
|
85
|
+
ok "$name @ $(pin_label "$m_ref" "$l_res" "$(qmap_field "$lock" "packages" "$name" "sha")")"
|
|
86
86
|
fi
|
|
87
87
|
done < <(qmap_keys "$manifest" "packages")
|
|
88
88
|
|
|
@@ -14,6 +14,7 @@ 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
|
+
sha="$(qmap_field "$lock" "packages" "$name" "sha")"
|
|
17
18
|
if [ ! -f "$lock" ]; then
|
|
18
19
|
state="lock missing — restore committed intelligence.lock"
|
|
19
20
|
elif [ -d "$IP_ROOT/.intelligence/packages/$name" ]; then
|
|
@@ -24,7 +25,7 @@ while IFS= read -r name; do
|
|
|
24
25
|
printf '%s %s locked:%s %s\n' \
|
|
25
26
|
"$name" \
|
|
26
27
|
"${ref:+ref:$ref}${ref:-${range:-*}}" \
|
|
27
|
-
"$
|
|
28
|
+
"$(pin_label "$ref" "$resolved" "$sha")" \
|
|
28
29
|
"$state"
|
|
29
30
|
done < <(qmap_keys "$manifest" "packages")
|
|
30
31
|
|
|
@@ -22,6 +22,20 @@ require_cli_project
|
|
|
22
22
|
manifest="$IP_ROOT/intelligence.yaml"
|
|
23
23
|
lock="$IP_ROOT/intelligence.lock"
|
|
24
24
|
|
|
25
|
+
# move_label <ref-or-empty> <from-resolved> <to-resolved> <from-sha> <to-sha>
|
|
26
|
+
# A version pin moves between tags, a ref pin between commits under one name —
|
|
27
|
+
# printing "main -> main" would report the move by hiding what moved.
|
|
28
|
+
move_label() {
|
|
29
|
+
local ref="$1" from="$2" to="$3" from_sha="$4" to_sha="$5"
|
|
30
|
+
if [ -z "$ref" ]; then
|
|
31
|
+
printf '%s -> %s' "${from:-<none>}" "$to"
|
|
32
|
+
elif [ -n "$from" ] && [ "$from" != "$ref" ]; then
|
|
33
|
+
printf '%s -> %s@%s' "$from" "$ref" "$(short_sha "$to_sha")"
|
|
34
|
+
else
|
|
35
|
+
printf '%s %s -> %s' "$ref" "$(short_sha "$from_sha")" "$(short_sha "$to_sha")"
|
|
36
|
+
fi
|
|
37
|
+
}
|
|
38
|
+
|
|
25
39
|
moved=0 found=0
|
|
26
40
|
while IFS= read -r name; do
|
|
27
41
|
[ -n "$name" ] || continue
|
|
@@ -37,6 +51,7 @@ while IFS= read -r name; do
|
|
|
37
51
|
fi
|
|
38
52
|
current="$(qmap_field "$lock" "packages" "$name" "resolved")"
|
|
39
53
|
locked_requested="$(qmap_field "$lock" "packages" "$name" "requested")"
|
|
54
|
+
locked_sha="$(qmap_field "$lock" "packages" "$name" "sha")"
|
|
40
55
|
url="$(qmap_field "$lock" "packages" "$name" "url")"
|
|
41
56
|
path="$(qmap_field "$lock" "packages" "$name" "path")"
|
|
42
57
|
[ -n "$url" ] || die "$name has no source in intelligence.lock — restore the committed lock or re-add the package"
|
|
@@ -44,32 +59,69 @@ while IFS= read -r name; do
|
|
|
44
59
|
range="$(qmap_field "$manifest" "packages" "$name" "version")"
|
|
45
60
|
[ -n "$ref" ] || [ -n "$range" ] || die "$name has neither version nor ref in the manifest"
|
|
46
61
|
|
|
62
|
+
ref_moved=0 remote_sha=""
|
|
47
63
|
if [ -n "$ref" ]; then
|
|
48
64
|
tag="$ref"
|
|
49
65
|
requested=""
|
|
66
|
+
# A ref is requested INTENT, and the lock's `resolved` column holds
|
|
67
|
+
# that same ref name — comparing the two asks a question no branch can
|
|
68
|
+
# ever answer differently. The sha column is the only record of where
|
|
69
|
+
# the ref actually pointed, so a ref pin is compared commit to commit:
|
|
70
|
+
# a moved branch, a re-cut tag and a `HEAD` pin all become visible,
|
|
71
|
+
# while a pin that IS a commit stays immutable by construction.
|
|
72
|
+
probe_rc=0
|
|
73
|
+
remote_sha="$(remote_sha_for_ref "$url" "$ref")" || probe_rc=$?
|
|
74
|
+
if [ "$probe_rc" -ne 0 ]; then
|
|
75
|
+
# No answer is not "no change": reporting up to date here would
|
|
76
|
+
# freeze the pin exactly as the ref-name comparison used to.
|
|
77
|
+
echo " WARN: $name: cannot reach $url — ref '$ref' was not checked" >&2
|
|
78
|
+
echo " $name: $ref (not checked — remote unreachable)"
|
|
79
|
+
continue
|
|
80
|
+
fi
|
|
81
|
+
# ls-remote advertises refs, not arbitrary objects, so a commit pin
|
|
82
|
+
# legitimately matches nothing — and cannot move. This verdict applies
|
|
83
|
+
# only once the lock already resolved to this ref; a manifest that now
|
|
84
|
+
# names a ref the lock never resolved is an ordinary move, and falls
|
|
85
|
+
# through to the fetch below.
|
|
86
|
+
if [ -z "$remote_sha" ] && [ "$ref" = "$current" ]; then
|
|
87
|
+
# The lock records the commit this ref resolved to, so a ref that
|
|
88
|
+
# prefixes it IS that commit. Asking the lock beats guessing from
|
|
89
|
+
# the ref's shape: a deleted branch named like a hex string would
|
|
90
|
+
# otherwise pass for a pin and swallow its own disappearance.
|
|
91
|
+
case "$locked_sha" in
|
|
92
|
+
"$ref"*)
|
|
93
|
+
echo " $name: $(short_sha "$ref") (pinned commit)"
|
|
94
|
+
;;
|
|
95
|
+
*)
|
|
96
|
+
echo " WARN: $name pins ref '$ref', which $url no longer advertises" >&2
|
|
97
|
+
echo " $name: $ref (unresolvable — gone upstream)"
|
|
98
|
+
;;
|
|
99
|
+
esac
|
|
100
|
+
continue
|
|
101
|
+
fi
|
|
102
|
+
[ -z "$remote_sha" ] || [ "$remote_sha" = "$locked_sha" ] || ref_moved=1
|
|
50
103
|
else
|
|
51
104
|
picked="$(list_remote_versions "$url" | semver_pick_highest "$range")"
|
|
52
105
|
[ -n "$picked" ] || { echo " $name: nothing satisfies '$range' at $url" >&2; continue; }
|
|
53
106
|
read -r tag _ <<< "$(remote_tag_for_version "$url" "$picked")"
|
|
54
107
|
requested="$range"
|
|
55
108
|
fi
|
|
56
|
-
if [ "$tag" = "$current" ] && [ "$requested" != "$locked_requested" ]; then
|
|
109
|
+
if [ "$ref_moved" -eq 0 ] && [ "$tag" = "$current" ] && [ "$requested" != "$locked_requested" ]; then
|
|
57
110
|
if [ "$preview" -eq 1 ]; then
|
|
58
111
|
echo " $name: request ${locked_requested:-<none>} -> ${requested:-<ref>} (keeps $current)"
|
|
59
112
|
else
|
|
60
|
-
locked_sha="$(qmap_field "$lock" "packages" "$name" "sha")"
|
|
61
113
|
lock_upsert "$lock" "$name" "$requested" "$url" "$path" "$current" "$locked_sha"
|
|
62
114
|
echo " $name: request ${locked_requested:-<none>} -> ${requested:-<ref>} (kept $current)"
|
|
63
115
|
fi
|
|
64
116
|
moved=$((moved + 1))
|
|
65
117
|
continue
|
|
66
118
|
fi
|
|
67
|
-
if [ "$tag" = "$current" ]; then
|
|
68
|
-
echo " $name: $
|
|
119
|
+
if [ "$ref_moved" -eq 0 ] && [ "$tag" = "$current" ]; then
|
|
120
|
+
echo " $name: $(pin_label "$ref" "$current" "$locked_sha") (up to date)"
|
|
69
121
|
continue
|
|
70
122
|
fi
|
|
71
123
|
if [ "$preview" -eq 1 ]; then
|
|
72
|
-
echo " $name: $
|
|
124
|
+
echo " $name: $(move_label "$ref" "$current" "$tag" "$locked_sha" "$remote_sha")"
|
|
73
125
|
moved=$((moved + 1))
|
|
74
126
|
continue
|
|
75
127
|
fi
|
|
@@ -87,7 +139,7 @@ while IFS= read -r name; do
|
|
|
87
139
|
mv "$staging" "$IP_ROOT/$rel"
|
|
88
140
|
wire_package_sources "$manifest" "$name" "$rel" "$IP_ROOT"
|
|
89
141
|
lock_upsert "$lock" "$name" "$requested" "$url" "$path" "$tag" "$sha"
|
|
90
|
-
echo " $name: $
|
|
142
|
+
echo " $name: $(move_label "$ref" "$current" "$tag" "$locked_sha" "$sha")"
|
|
91
143
|
moved=$((moved + 1))
|
|
92
144
|
done < <(qmap_keys "$manifest" "packages")
|
|
93
145
|
|
package/cli/lib/cli-common.sh
CHANGED
|
@@ -47,6 +47,27 @@ assert_safe_ref() {
|
|
|
47
47
|
esac
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
+
# --- Resolved-pin display ------------------------------------------------
|
|
51
|
+
# A `ref:` pin's resolved column holds the ref NAME, which never changes: the
|
|
52
|
+
# sha is the only field that says which commit is installed. Every surface
|
|
53
|
+
# reporting such a pin prints both, so a branch that stopped moving is visible
|
|
54
|
+
# without asking the remote.
|
|
55
|
+
|
|
56
|
+
short_sha() {
|
|
57
|
+
[ -n "$1" ] || { printf '<none>'; return 0; }
|
|
58
|
+
printf '%s' "${1:0:7}"
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
# pin_label <ref-or-empty> <resolved> <sha>
|
|
62
|
+
pin_label() {
|
|
63
|
+
local ref="$1" resolved="$2" sha="$3"
|
|
64
|
+
if [ -n "$ref" ]; then
|
|
65
|
+
printf '%s@%s' "${resolved:-$ref}" "$(short_sha "$sha")"
|
|
66
|
+
else
|
|
67
|
+
printf '%s' "${resolved:-<none>}"
|
|
68
|
+
fi
|
|
69
|
+
}
|
|
70
|
+
|
|
50
71
|
source "$CLI_DIR/lib/manifest.sh"
|
|
51
72
|
source "$CLI_DIR/lib/semver.sh"
|
|
52
73
|
source "$CLI_DIR/lib/registry.sh"
|
package/cli/lib/semver.sh
CHANGED
|
@@ -120,6 +120,39 @@ remote_tag_for_version() {
|
|
|
120
120
|
}'
|
|
121
121
|
}
|
|
122
122
|
|
|
123
|
+
# remote_sha_for_ref <git-url> <ref> — the commit a branch/tag/HEAD pin points
|
|
124
|
+
# at on the remote right now; empty when the remote advertises no such ref
|
|
125
|
+
# (a pin that IS a commit, or a ref deleted upstream). Exit 2 means the remote
|
|
126
|
+
# could not be asked at all: a check that produced no answer must never be
|
|
127
|
+
# read by the caller as "nothing changed".
|
|
128
|
+
#
|
|
129
|
+
# Three git behaviours this mirrors deliberately, because a sha that is not the
|
|
130
|
+
# one `fetch_package` would land on is worse than no answer:
|
|
131
|
+
# - `git ls-remote <url> main` also matches `refs/heads/feature/main`
|
|
132
|
+
# (patterns match at slash boundaries), so candidates are selected by full
|
|
133
|
+
# ref name, never by the pattern that fetched them;
|
|
134
|
+
# - an annotated tag advertises the tag OBJECT on `refs/tags/<t>` and the
|
|
135
|
+
# commit on the peeled `refs/tags/<t>^{}`, while the lock records the
|
|
136
|
+
# commit — so peeled wins, and the peel line only appears when its own
|
|
137
|
+
# pattern is asked for;
|
|
138
|
+
# - on a name shared by a branch and a tag, `git clone --branch <ref>` takes
|
|
139
|
+
# the branch, so `refs/heads` outranks `refs/tags` here too.
|
|
140
|
+
remote_sha_for_ref() {
|
|
141
|
+
local url="$1" ref="$2" out
|
|
142
|
+
assert_safe_source_url "$url"
|
|
143
|
+
assert_safe_ref "$ref"
|
|
144
|
+
[ -n "$ref" ] || return 0
|
|
145
|
+
out="$(GIT_TERMINAL_PROMPT=0 git ls-remote -- "$url" \
|
|
146
|
+
"$ref" "$ref^{}" "refs/heads/$ref" "refs/tags/$ref" "refs/tags/$ref^{}" 2>/dev/null)" \
|
|
147
|
+
|| return 2
|
|
148
|
+
printf '%s\n' "$out" | awk -v ref="$ref" '
|
|
149
|
+
{ sub(/\r$/, ""); if ($2 != "") seen[$2] = $1 }
|
|
150
|
+
END {
|
|
151
|
+
split("refs/heads/" ref "\037refs/tags/" ref "^{}\037refs/tags/" ref "\037" ref "^{}\037" ref, C, "\037")
|
|
152
|
+
for (i = 1; i <= 5; i++) if (C[i] in seen) { print seen[C[i]]; exit }
|
|
153
|
+
}'
|
|
154
|
+
}
|
|
155
|
+
|
|
123
156
|
# semver_pick_highest <range> — reads versions on stdin, prints the highest
|
|
124
157
|
# one matching the range (empty output when nothing matches).
|
|
125
158
|
semver_pick_highest() {
|
package/engine/ENGINE_SHA
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
512d06382f43fa910c32ccc275a5fc286500d4e2
|
package/engine/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
0.11.
|
|
1
|
+
0.11.6
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ainova-systems/intelligence",
|
|
3
|
-
"version": "0.11.
|
|
3
|
+
"version": "0.11.6",
|
|
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"
|