@ainova-systems/intelligence 0.11.7 → 0.11.8

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.
@@ -2,8 +2,8 @@
2
2
  # Internal locked-store restore operation.
3
3
  #
4
4
  # Restore .intelligence/ from intelligence.lock — the fresh-clone command.
5
- # --frozen additionally refuses any manifest/lock divergence (CI mode) and
6
- # fails on a sha mismatch instead of re-resolving.
5
+ # --frozen additionally refuses manifest/lock divergence (CI mode).
6
+ # Locked packages always restore their recorded commit, never the ref's new HEAD.
7
7
  set -euo pipefail
8
8
  source "$CLI_DIR/lib/cli-common.sh"
9
9
 
@@ -50,6 +50,20 @@ if [ "$frozen" -eq 1 ]; then
50
50
  done < <(qmap_keys "$lock" "packages")
51
51
  fi
52
52
 
53
+ # Check every required commit identity before restoring any package. Only the
54
+ # matching bundled content may carry the historical empty development-build SHA.
55
+ while IFS="$LOCK_SEP" read -r name _requested url path resolved sha; do
56
+ [ -n "$name" ] || continue
57
+ assert_valid_pkg_name "$name"
58
+ assert_safe_source_url "$url"
59
+ assert_safe_ref "$resolved"
60
+ if [ -z "$sha" ] && is_bundle_source "$url" "$resolved" "$path"; then
61
+ continue
62
+ fi
63
+ [[ "$sha" =~ ^[0-9a-f]{40}$ || "$sha" =~ ^[0-9a-f]{64}$ ]] \
64
+ || die "locked restore: $name has a missing or invalid commit SHA — restore a valid intelligence.lock"
65
+ done < <(lock_to_tsv "$lock")
66
+
53
67
  # Manifest packages missing from the lock: resolve them now (npm install
54
68
  # semantics). Under --frozen the drift gate above has already refused.
55
69
  missing=""
@@ -89,7 +103,7 @@ fi
89
103
 
90
104
  # Restore every locked package that is not already in the store.
91
105
  if [ -f "$lock" ]; then
92
- while IFS="$LOCK_SEP" read -r name requested url path resolved sha; do
106
+ while IFS="$LOCK_SEP" read -r name _requested url path resolved sha; do
93
107
  [ -n "$name" ] || continue
94
108
  # The lock arrives with a cloned repo — its keys are untrusted input
95
109
  # on their way into rm -rf paths, and its urls into git argv.
@@ -106,17 +120,7 @@ if [ -f "$lock" ]; then
106
120
  # re-run (whose dir-exists check skips verification) would sync it.
107
121
  staging="$IP_ROOT/.intelligence/.staging-$$"
108
122
  rm -rf "$staging"
109
- got="$(fetch_package "$url" "$resolved" "$path" "$staging")"
110
- # An empty sha (bundle-seeded content on a dev build) means unknown,
111
- # not moved — only two known-and-different shas are a finding.
112
- if [ -n "$sha" ] && [ -n "$got" ] && [ "$got" != "$sha" ]; then
113
- if [ "$frozen" -eq 1 ]; then
114
- rm -rf "$staging"
115
- die "$name: fetched $got but the lock pins $sha — the ref moved; refusing under --frozen"
116
- fi
117
- echo " WARN: $name resolved to $got, lock had $sha — updating the lock" >&2
118
- lock_upsert "$lock" "$name" "$requested" "$url" "$path" "$resolved" "$got"
119
- fi
123
+ fetch_package "$url" "$resolved" "$path" "$staging" "$sha" >/dev/null
120
124
  rm -rf "${IP_ROOT:?}/$rel"
121
125
  mkdir -p "$(dirname "$IP_ROOT/$rel")"
122
126
  mv "$staging" "$IP_ROOT/$rel"
@@ -106,13 +106,20 @@ suggest_similar() {
106
106
  fi
107
107
  }
108
108
 
109
- # fetch_package <url> <ref> <subpath> <dest-dir>
109
+ # is_bundle_source <url> <ref> <subpath>
110
+ is_bundle_source() {
111
+ [ "$1" = "$SYNC_PKG_URL" ] && [ "$3" = "$SYNC_PKG_PATH" ] \
112
+ && [ "${2#v}" = "$(bundled_engine_version)" ]
113
+ }
114
+
115
+ # fetch_package <url> <ref> <subpath> <dest-dir> [locked-sha]
110
116
  # Shallow-clones url@ref (tag, branch, or SHA fallback), copies <subpath>
111
117
  # (or the repo root) into <dest-dir>, prints the resolved commit sha.
118
+ # A locked SHA selects and verifies the commit independently of the ref name.
112
119
  # The clone pins autocrlf/eol/symlinks exactly like the engine does, so the
113
120
  # store holds the bytes the package published.
114
121
  fetch_package() {
115
- local url="$1" ref="$2" subpath="$3" dest="$4"
122
+ local url="$1" ref="$2" subpath="$3" dest="$4" locked_sha="${5:-}" bundle_sha=""
116
123
  assert_safe_source_url "$url"
117
124
  assert_safe_ref "$ref"
118
125
  # Bundle seed: the engine-content package at the CLI's own version copies
@@ -120,34 +127,63 @@ fetch_package() {
120
127
  # archived-project conversion offline. Keyed on the
121
128
  # full (url, path, ref) triple; any other version or source falls through
122
129
  # to the normal clone.
123
- if [ "$url" = "$SYNC_PKG_URL" ] && [ "$subpath" = "$SYNC_PKG_PATH" ] \
124
- && [ "${ref#v}" = "$(bundled_engine_version)" ]; then
130
+ if is_bundle_source "$url" "$ref" "$subpath"; then
131
+ if [ -f "$IS_ENGINE_DIR/ENGINE_SHA" ]; then
132
+ bundle_sha="$(tr -d ' \t\r\n' < "$IS_ENGINE_DIR/ENGINE_SHA")"
133
+ fi
134
+ fi
135
+ if is_bundle_source "$url" "$ref" "$subpath" \
136
+ && { [ -z "$locked_sha" ] || [ -z "$bundle_sha" ] || [ "$locked_sha" = "$bundle_sha" ]; }; then
125
137
  [ -n "${IS_BUNDLED_PKG_DIR:-}" ] && [ -d "$IS_BUNDLED_PKG_DIR" ] \
126
138
  || die "bundled engine content not found next to the CLI — reinstall @ainova-systems/intelligence"
127
139
  rm -rf "$dest"
128
140
  mkdir -p "$dest"
129
141
  cp -R "$IS_BUNDLED_PKG_DIR/." "$dest/"
130
142
  rm -rf "$dest/.git"
131
- if [ -f "$IS_ENGINE_DIR/ENGINE_SHA" ]; then
132
- tr -d ' \t\r\n' < "$IS_ENGINE_DIR/ENGINE_SHA"
143
+ if [ "$#" -ge 5 ] && { [ -z "$locked_sha" ] || [ -z "$bundle_sha" ]; }; then
144
+ echo "WARNING: bundled sync content restored without commit verification (development bundle or lock has no SHA)" >&2
133
145
  fi
146
+ printf '%s' "$bundle_sha"
134
147
  return 0
135
148
  fi
136
149
  local tmp sha src
137
150
  local -a branch_arg=()
138
151
  [ -n "$ref" ] && branch_arg=(--branch "$ref")
139
152
  tmp="$(mktemp -d -t intelligence-pkg-XXXXXX 2>/dev/null || mktemp -d)"
140
- if ! GIT_TERMINAL_PROMPT=0 git -c core.symlinks=false -c core.autocrlf=false -c core.eol=lf \
153
+ if [ -n "$locked_sha" ]; then
154
+ local -a format_arg=()
155
+ [ "${#locked_sha}" -ne 64 ] || format_arg=(--object-format=sha256)
156
+ git init --quiet "${format_arg[@]+"${format_arg[@]}"}" "$tmp/clone" \
157
+ || { rm -rf "$tmp"; die "cannot stage locked commit $locked_sha"; }
158
+ # Request the object directly, including retained commits no longer named
159
+ # by a branch/tag. Servers that forbid SHA wants may still advertise a
160
+ # descendant; fetch their history before declaring the commit unavailable.
161
+ if ! GIT_TERMINAL_PROMPT=0 git -C "$tmp/clone" fetch --quiet --no-tags --depth 1 -- "$url" "$locked_sha" 2>/dev/null; then
162
+ GIT_TERMINAL_PROMPT=0 git -C "$tmp/clone" fetch --quiet --tags -- "$url" \
163
+ '+refs/heads/*:refs/remotes/locked/*' 2>/dev/null \
164
+ || { rm -rf "$tmp"; die "cannot fetch locked commit $locked_sha from $url — check source access and commit availability"; }
165
+ fi
166
+ [ "$(git -C "$tmp/clone" cat-file -t "$locked_sha" 2>/dev/null || true)" = commit ] \
167
+ || { rm -rf "$tmp"; die "locked commit $locked_sha unavailable from $url — refusing to substitute '$ref' or HEAD"; }
168
+ git -c core.symlinks=false -c core.autocrlf=false -c core.eol=lf \
169
+ -C "$tmp/clone" checkout --quiet --detach "$locked_sha" -- \
170
+ || { rm -rf "$tmp"; die "cannot check out locked commit $locked_sha from $url"; }
171
+ elif ! GIT_TERMINAL_PROMPT=0 git -c core.symlinks=false -c core.autocrlf=false -c core.eol=lf \
141
172
  clone --depth 1 "${branch_arg[@]+"${branch_arg[@]}"}" --quiet -- "$url" "$tmp/clone" 2>/dev/null; then
142
173
  # A SHA is not clonable with --branch — fall back to a full clone + checkout.
143
174
  rm -rf "$tmp/clone"
144
175
  GIT_TERMINAL_PROMPT=0 git -c core.symlinks=false -c core.autocrlf=false -c core.eol=lf \
145
176
  clone --quiet -- "$url" "$tmp/clone" 2>/dev/null \
146
177
  || { rm -rf "$tmp"; die "cannot clone $url"; }
147
- [ -z "$ref" ] || git -C "$tmp/clone" checkout --quiet "$ref" -- \
178
+ [ -z "$ref" ] || git -c core.symlinks=false -c core.autocrlf=false -c core.eol=lf \
179
+ -C "$tmp/clone" checkout --quiet "$ref" -- \
148
180
  || { rm -rf "$tmp"; die "ref '$ref' not found in $url"; }
149
181
  fi
150
182
  sha="$(git -C "$tmp/clone" rev-parse HEAD)"
183
+ if [ -n "$locked_sha" ] && [ "$sha" != "$locked_sha" ]; then
184
+ rm -rf "$tmp"
185
+ die "fetched $sha but the lock pins $locked_sha — refusing package replacement"
186
+ fi
151
187
  src="$tmp/clone"
152
188
  if [ -n "$subpath" ]; then
153
189
  case "$subpath" in
package/engine/ENGINE_SHA CHANGED
@@ -1 +1 @@
1
- 00308bfbdcd92ebf37924bb1083cee142e655fd7
1
+ 3413f7d6f9ef181368b16b90e36d77360cb5f479
package/engine/VERSION CHANGED
@@ -1 +1 @@
1
- 0.11.7
1
+ 0.11.8
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ainova-systems/intelligence",
3
- "version": "0.11.7",
3
+ "version": "0.11.8",
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"
@@ -11,12 +11,12 @@ context: fork
11
11
  was requested). For Intelligence projects, this command first aligns project schema/content
12
12
  with the installed CLI and restores a missing package store strictly from
13
13
  `intelligence.lock`.
14
- 2. Require final `IS_STATUS=ok`; relay per-adapter counts and any model-drift
15
- or unsynced-source warnings.
14
+ 2. Require final `IS_STATUS=ok`; relay per-adapter counts and any integrity,
15
+ model-drift or unsynced-source warnings.
16
16
  3. In CI, a required tracked project upgrade is intentionally refused. Report
17
17
  the instruction to run `intelligence init --apply` locally, review and
18
18
  commit its diff; never bypass the gate. A frozen restore refusal means the
19
- manifest and lock disagree or a pinned ref moved—report it without
19
+ manifest and lock disagree or the locked commit cannot be verified/restored—report it without
20
20
  hand-copying package content.
21
21
  4. On a probable Intelligence defect, first ask whether to collect a sanitized
22
22
  issue draft; collect nothing before approval and never use telemetry. Include