@amsterdamdatalabs/adl-agent-control-linux-x64 0.1.5 → 0.1.7
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/bin/adl +1 -1
- package/bin/reconcile +290 -238
- package/bin/validate-manifest +17 -15
- package/package.json +1 -1
- package/packages/fleet/manifest.json +4 -4
- package/packages/fleet/manifest.schema.json +6 -5
- package/packages/repo-controls/src/gitignore-block.ts +17 -0
package/bin/adl
CHANGED
package/bin/reconcile
CHANGED
|
@@ -407,12 +407,14 @@ run_brew_upgrade_all() {
|
|
|
407
407
|
echo "brew upgrade: nothing outdated"
|
|
408
408
|
return 0
|
|
409
409
|
fi
|
|
410
|
-
local
|
|
410
|
+
local upgrade_status=0
|
|
411
411
|
# Routed through run_brew itself (same owner/cwd/stdin wiring as every
|
|
412
412
|
# other brew mutation in this file), bounded by run_with_timeout so a
|
|
413
413
|
# network-stalled `brew upgrade` cannot hang the rest of this run forever.
|
|
414
|
-
|
|
415
|
-
|
|
414
|
+
# brew's output streams live -- never captured and printed at the end,
|
|
415
|
+
# which left a long upgrade silent for minutes and looking stuck.
|
|
416
|
+
echo "brew upgrade: $formulae_count formulae, $casks_count casks outdated; upgrading (timeout ${BREW_UPGRADE_ALL_TIMEOUT_SECONDS}s)"
|
|
417
|
+
run_with_timeout "$BREW_UPGRADE_ALL_TIMEOUT_SECONDS" run_brew upgrade 2>&1 || upgrade_status=$?
|
|
416
418
|
if [[ "$upgrade_status" -eq 124 ]]; then
|
|
417
419
|
echo "brew upgrade timed out after ${BREW_UPGRADE_ALL_TIMEOUT_SECONDS}s" >&2
|
|
418
420
|
return 1
|
|
@@ -454,28 +456,15 @@ run_npm() {
|
|
|
454
456
|
fi
|
|
455
457
|
}
|
|
456
458
|
|
|
457
|
-
# Whether a read-only, owner-scoped query (brew_query, npm_installed_version)
|
|
458
|
-
# can run without asking for privilege reconcile does not already have. Apply
|
|
459
|
-
# mode always runs as real root (checked elsewhere), which can sudo -u any
|
|
460
|
-
# administrator with no password. A plan/audit preview run has no such
|
|
461
|
-
# guarantee -- $administrator on a Linux VPS device is "root", and previewing
|
|
462
|
-
# that device's plan from an unprivileged account must not demand a sudo
|
|
463
|
-
# password it may not have; it falls back to the pre-2026-09-28 unconditional
|
|
464
|
-
# message instead. Self-administered devices (m3: administrator=tarunrana)
|
|
465
|
-
# need no escalation at all, so their preview can query for real.
|
|
466
|
-
can_query_as_administrator() {
|
|
467
|
-
[[ "$(id -un)" == "$administrator" ]] || [[ "$(id -u)" -eq 0 ]]
|
|
468
|
-
}
|
|
469
|
-
|
|
470
459
|
# Read-only Homebrew query, run exactly like run_brew's real mutations (same
|
|
471
460
|
# owner, cwd, and stdin) but never a mutation itself. A named function so
|
|
472
461
|
# tests can stub just this, instead of having to fake sudo's own argument
|
|
473
462
|
# parsing the way a raw inline `sudo -u ... "$brew_bin" ...` would require.
|
|
474
|
-
# Apply-mode only
|
|
475
|
-
#
|
|
476
|
-
#
|
|
477
|
-
#
|
|
478
|
-
#
|
|
463
|
+
# Apply-mode only: `brew list`/`brew outdated` have been observed to take
|
|
464
|
+
# minutes under real load on a contended box (Homebrew's own auto-update
|
|
465
|
+
# against a large git checkout), so a plan preview never calls this -- it
|
|
466
|
+
# would turn a "quick look" into a slow, load-dependent one for every brew
|
|
467
|
+
# formula on the device.
|
|
479
468
|
brew_query() {
|
|
480
469
|
(cd /tmp && sudo -u "$brew_owner" -H "$brew_bin" "$@" </dev/null)
|
|
481
470
|
}
|
|
@@ -798,6 +787,27 @@ install_surface_policy_file() {
|
|
|
798
787
|
echo "installed required surface policy: $target"
|
|
799
788
|
}
|
|
800
789
|
|
|
790
|
+
# A resolved release version against the first line of a release-archive-
|
|
791
|
+
# latest tool's own `--version` output. Different tools format that line
|
|
792
|
+
# differently -- lean-ctx: "lean-ctx 3.10.5 (official, ...)" (version padded
|
|
793
|
+
# by spaces on both sides); agent-vault: "agent-vault version 0.39.3" (flush
|
|
794
|
+
# against the end of the line, no trailing space); a plain "vX.Y.Z" line
|
|
795
|
+
# with no separating space before the version at all -- so the LEFT boundary
|
|
796
|
+
# is a string start or a real space, with an OPTIONAL literal "v" directly
|
|
797
|
+
# after that boundary (never "v" floating anywhere: found in review,
|
|
798
|
+
# 2026-09-28, `(^|[ v])` treated a bare "v" as equivalent to a space no
|
|
799
|
+
# matter what preceded it, so "tool dev0.39.3"/"tool rev0.39.3" -- where the
|
|
800
|
+
# "v" belongs to "dev"/"rev", not a version prefix -- silently matched and
|
|
801
|
+
# would have skipped a real upgrade). The RIGHT boundary is a space or a
|
|
802
|
+
# string end and never accepts "v", or "0.39.3" would incorrectly match
|
|
803
|
+
# inside "0.39.30". Dots in the version are escaped so they match literally,
|
|
804
|
+
# not "any character," in the regex below.
|
|
805
|
+
release_archive_version_matches() {
|
|
806
|
+
local version_line="$1" version="$2" escaped
|
|
807
|
+
escaped="$(printf '%s' "$version" | sed 's/[.[\*^$()+?{}|]/\\&/g')"
|
|
808
|
+
grep -Eq "(^| )v?${escaped}( |\$)" <<<"$version_line"
|
|
809
|
+
}
|
|
810
|
+
|
|
801
811
|
# Resolves the release tag GitHub's own "latest" redirect currently points
|
|
802
812
|
# at, without touching the api.github.com REST API (unauthenticated calls
|
|
803
813
|
# there are rate-limited per source IP; this fleet's shared egress IP already
|
|
@@ -811,65 +821,33 @@ resolve_latest_release_tag() {
|
|
|
811
821
|
basename "$location"
|
|
812
822
|
}
|
|
813
823
|
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
local release_dir archive_file extract_dir actual_sha256
|
|
834
|
-
release_dir="$(mktemp -d)"
|
|
835
|
-
trap 'rm -rf "$release_dir"' EXIT
|
|
836
|
-
archive_file="$release_dir/release.tar.gz"
|
|
837
|
-
extract_dir="$release_dir/extract"
|
|
838
|
-
mkdir -p "$extract_dir"
|
|
839
|
-
curl --proto '=https' --proto-redir '=https' -fsSL --retry 3 -o "$archive_file" "$url"
|
|
840
|
-
case "$(uname -s)" in
|
|
841
|
-
Darwin) actual_sha256="$(shasum -a 256 "$archive_file" | awk '{print $1}')" ;;
|
|
842
|
-
Linux) actual_sha256="$(sha256sum "$archive_file" | awk '{print $1}')" ;;
|
|
843
|
-
*) echo "unsupported operating system for release archive" >&2; exit 1 ;;
|
|
844
|
-
esac
|
|
845
|
-
[[ "$actual_sha256" == "$expected_sha256" ]] || {
|
|
846
|
-
echo "checksum mismatch for $package $version" >&2
|
|
847
|
-
exit 1
|
|
848
|
-
}
|
|
849
|
-
tar -xzf "$archive_file" -C "$extract_dir" "$archive_executable"
|
|
850
|
-
[[ -f "$extract_dir/$archive_executable" ]] || {
|
|
851
|
-
echo "archive executable missing: $archive_executable" >&2
|
|
852
|
-
exit 1
|
|
853
|
-
}
|
|
854
|
-
atomic_install_executable "$extract_dir/$archive_executable" "$target"
|
|
855
|
-
)
|
|
856
|
-
}
|
|
857
|
-
|
|
858
|
-
# Like run_release_archive, but never pins a version or checksum in the
|
|
859
|
-
# manifest: it always installs whatever GitHub's own "latest" alias currently
|
|
860
|
-
# serves, verified against the checksums file published *in that same
|
|
861
|
-
# release* (never a value carried over from a previous run or hardcoded
|
|
862
|
-
# here) -- fails loud, installs nothing, if that checksums asset is missing
|
|
863
|
-
# or doesn't list our asset. `.../releases/latest/download/<name>` is GitHub's
|
|
864
|
-
# own stable alias for "the matching asset of whatever release is latest
|
|
865
|
-
# right now", so the download itself never needs the resolved tag.
|
|
824
|
+
# A GitHub release archive, installed under /usr/local/bin, verified against
|
|
825
|
+
# a checksum published *in that same release* (never a value carried over
|
|
826
|
+
# from a previous run or hardcoded here) -- fails loud, installs nothing, if
|
|
827
|
+
# the checksums asset is missing or doesn't list our asset. It always
|
|
828
|
+
# installs whatever GitHub's own "latest" release was when install_one_tool
|
|
829
|
+
# resolved $tag (resolve_latest_release_tag), fetched with $tag pinned into
|
|
830
|
+
# BOTH download URLs -- `.../releases/download/<tag>/<name>`, never through
|
|
831
|
+
# GitHub's separate "always whatever is latest right now" alias for the
|
|
832
|
+
# downloads themselves. Fixed 2026-09-29 (review): that alias re-resolves on
|
|
833
|
+
# every request, so a release published between the tag resolve and the
|
|
834
|
+
# archive download would otherwise serve the checksums file from one release
|
|
835
|
+
# and the archive from a newer one -- silently mixing versions past the
|
|
836
|
+
# checksum check (which would still "pass" against whichever checksums file
|
|
837
|
+
# actually got fetched). Pinning both fetches to the one $tag closes that
|
|
838
|
+
# window.
|
|
839
|
+
# Tarun, 2026-09-29 (hard rule): versions are never pinned in the manifest --
|
|
840
|
+
# this replaced the old pinned run_release_archive (fixed version + url +
|
|
841
|
+
# sha256), which validate-manifest no longer accepts on any manager; $tag
|
|
842
|
+
# here is resolved fresh every run, never carried over or hardcoded.
|
|
866
843
|
run_release_archive_latest() {
|
|
867
844
|
local package="$1"
|
|
868
845
|
local repo="$2"
|
|
869
|
-
local
|
|
870
|
-
local
|
|
871
|
-
local
|
|
872
|
-
local
|
|
846
|
+
local tag="$3"
|
|
847
|
+
local asset="$4"
|
|
848
|
+
local checksums_asset="$5"
|
|
849
|
+
local archive_executable="$6"
|
|
850
|
+
local target="$7"
|
|
873
851
|
[[ "$(id -u)" -eq 0 ]] || { echo "apply mode must run as root" >&2; exit 1; }
|
|
874
852
|
[[ "$target" == /usr/local/bin/* ]] || { echo "release archive target must be under /usr/local/bin: $target" >&2; exit 1; }
|
|
875
853
|
[[ "$archive_executable" != /* && "$archive_executable" != *..* ]] || {
|
|
@@ -886,13 +864,13 @@ run_release_archive_latest() {
|
|
|
886
864
|
extract_dir="$release_dir/extract"
|
|
887
865
|
mkdir -p "$extract_dir"
|
|
888
866
|
curl --proto '=https' --proto-redir '=https' -fsSL --retry 3 \
|
|
889
|
-
-o "$checksums_file" "https://github.com/$repo/releases/
|
|
867
|
+
-o "$checksums_file" "https://github.com/$repo/releases/download/$tag/$checksums_asset"
|
|
890
868
|
expected_sha256="$(awk -v want="$asset" '$2 == want { print $1; found = 1 } END { exit !found }' "$checksums_file")" || {
|
|
891
869
|
echo "no published checksum for $asset in $repo's $checksums_asset -- refusing to install unverified bytes" >&2
|
|
892
870
|
exit 1
|
|
893
871
|
}
|
|
894
872
|
curl --proto '=https' --proto-redir '=https' -fsSL --retry 3 \
|
|
895
|
-
-o "$archive_file" "https://github.com/$repo/releases/
|
|
873
|
+
-o "$archive_file" "https://github.com/$repo/releases/download/$tag/$asset"
|
|
896
874
|
case "$(uname -s)" in
|
|
897
875
|
Darwin) actual_sha256="$(shasum -a 256 "$archive_file" | awk '{print $1}')" ;;
|
|
898
876
|
Linux) actual_sha256="$(sha256sum "$archive_file" | awk '{print $1}')" ;;
|
|
@@ -942,7 +920,7 @@ resolve_surface_mode() {
|
|
|
942
920
|
# root") is a real environment fault, not a flaky install, and still
|
|
943
921
|
# aborts immediately -- `exit` is unconditional and is never caught here.
|
|
944
922
|
install_one_tool() {
|
|
945
|
-
local tool_id="$1" manager package executable previous_executable migrating_from_bun=0 rc=0
|
|
923
|
+
local tool_id="$1" manager package executable previous_executable migrating_from_bun=0 rc=0 npm_spec npm_allow_scripts npm_target_version npm_installed_ver brew_outdated_output brew_installed_version
|
|
946
924
|
manager="$(jq -r --arg id "$tool_id" '.[$id].manager' "$resolved_file")"
|
|
947
925
|
package="$(jq -r --arg id "$tool_id" '.[$id].package' "$resolved_file")"
|
|
948
926
|
executable="$(jq -r --arg id "$tool_id" '.[$id].executable' "$resolved_file")"
|
|
@@ -998,15 +976,14 @@ install_one_tool() {
|
|
|
998
976
|
run_apt install -y "$package" || rc=1
|
|
999
977
|
;;
|
|
1000
978
|
npm)
|
|
1001
|
-
#
|
|
1002
|
-
#
|
|
1003
|
-
#
|
|
979
|
+
# Tarun, 2026-09-29 (hard rule): versions are never pinned -- every
|
|
980
|
+
# fleet tool installs latest stable. npm entries never carry a
|
|
981
|
+
# .version (validate-manifest rejects one outright); $npm_spec stays a
|
|
982
|
+
# separate variable from $package only because the exact run_npm
|
|
983
|
+
# invocation below is asserted at the source level. Ownership
|
|
1004
984
|
# verification below still uses the bare package name: npm's global
|
|
1005
|
-
# tree and package.json are keyed by package, never by
|
|
1006
|
-
# version spec.
|
|
1007
|
-
npm_version="$(jq -r --arg id "$tool_id" '.[$id].version // empty' "$resolved_file")"
|
|
985
|
+
# tree and package.json are keyed by package, never by a version spec.
|
|
1008
986
|
npm_spec="$package"
|
|
1009
|
-
[[ -z "$npm_version" ]] || npm_spec="$package@$npm_version"
|
|
1010
987
|
# Only @amsterdamdatalabs/enact-docs-search's manifest entry carries
|
|
1011
988
|
# this (docs/operations/global-tools.md Topic 2, decided 2026-09-28):
|
|
1012
989
|
# its own dependencies' install scripts, explicitly reviewed and
|
|
@@ -1017,41 +994,20 @@ install_one_tool() {
|
|
|
1017
994
|
previous_executable="$(jq -r --arg id "$tool_id" '.[$id].executable' "$previous_resolved_file")"
|
|
1018
995
|
echo "would remove retired Bun compilation before npm install: $tool_id ($previous_executable and $(bun_source_hash_file "$tool_id"))"
|
|
1019
996
|
fi
|
|
1020
|
-
#
|
|
1021
|
-
#
|
|
1022
|
-
#
|
|
1023
|
-
#
|
|
1024
|
-
#
|
|
1025
|
-
|
|
1026
|
-
# conservative message instead of guessing. Either way, only query
|
|
1027
|
-
# when it needs no new sudo privilege (can_query_as_administrator) --
|
|
1028
|
-
# a preview run must not demand a password a different device's real
|
|
1029
|
-
# administrator would need.
|
|
1030
|
-
if [[ -n "$npm_version" ]] && can_query_as_administrator; then
|
|
1031
|
-
if npm_plan_installed="$(npm_installed_version "$package")"; then
|
|
1032
|
-
if [[ -n "$npm_plan_installed" && "$npm_plan_installed" == "$npm_version" ]]; then
|
|
1033
|
-
echo "already latest: $tool_id (npm:$package@$npm_plan_installed)"
|
|
1034
|
-
else
|
|
1035
|
-
echo "would install or upgrade npm package: $npm_spec"
|
|
1036
|
-
fi
|
|
1037
|
-
else
|
|
1038
|
-
echo "would install or upgrade npm package: $npm_spec (installed version not checked: npm ls -g failed)"
|
|
1039
|
-
fi
|
|
1040
|
-
else
|
|
1041
|
-
echo "would install or upgrade npm package: $npm_spec"
|
|
1042
|
-
fi
|
|
997
|
+
# "latest stable" is not knowable without a per-package registry
|
|
998
|
+
# round trip (npm_latest_version) -- doing that here would make a
|
|
999
|
+
# plan preview slow and network-bound for every npm tool on the
|
|
1000
|
+
# device, so plan mode always prints this unconditional message
|
|
1001
|
+
# instead of guessing.
|
|
1002
|
+
echo "would install or upgrade npm package: $npm_spec"
|
|
1043
1003
|
else
|
|
1044
1004
|
if is_in_place_bun_to_npm_migration "$tool_id"; then
|
|
1045
1005
|
migrating_from_bun=1
|
|
1046
1006
|
prepare_in_place_bun_to_npm_migration "$tool_id" || rc=1
|
|
1047
1007
|
fi
|
|
1048
|
-
if [[ "$rc" -eq 0 ]]; then
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
elif ! npm_target_version="$(npm_latest_version "$package")"; then
|
|
1052
|
-
echo "$tool_id: npm view could not resolve the latest version of $package" >&2
|
|
1053
|
-
rc=1
|
|
1054
|
-
fi
|
|
1008
|
+
if [[ "$rc" -eq 0 ]] && ! npm_target_version="$(npm_latest_version "$package")"; then
|
|
1009
|
+
echo "$tool_id: npm view could not resolve the latest version of $package" >&2
|
|
1010
|
+
rc=1
|
|
1055
1011
|
fi
|
|
1056
1012
|
if [[ "$rc" -eq 0 ]]; then
|
|
1057
1013
|
if ! npm_installed_ver="$(npm_installed_version "$package")"; then
|
|
@@ -1079,21 +1035,8 @@ install_one_tool() {
|
|
|
1079
1035
|
fi
|
|
1080
1036
|
[[ "$rc" -eq 0 ]] && { ensure_global_pip_executable "$executable" || rc=1; }
|
|
1081
1037
|
;;
|
|
1082
|
-
release-archive)
|
|
1083
|
-
local version url sha256 archive_executable
|
|
1084
|
-
version="$(jq -r --arg id "$tool_id" '.[$id].version' "$resolved_file")"
|
|
1085
|
-
url="$(jq -r --arg id "$tool_id" '.[$id].url' "$resolved_file")"
|
|
1086
|
-
sha256="$(jq -r --arg id "$tool_id" '.[$id].sha256' "$resolved_file")"
|
|
1087
|
-
archive_executable="$(jq -r --arg id "$tool_id" '.[$id].archive_executable' "$resolved_file")"
|
|
1088
|
-
if [[ "$mode" == apply && -x "$executable" ]] &&
|
|
1089
|
-
"$executable" version 2>/dev/null | head -n 1 | grep -Fq "v$version"; then
|
|
1090
|
-
echo "pinned release already installed: $package $version"
|
|
1091
|
-
else
|
|
1092
|
-
run_release_archive "$package" "$version" "$url" "$sha256" "$archive_executable" "$executable" || rc=1
|
|
1093
|
-
fi
|
|
1094
|
-
;;
|
|
1095
1038
|
release-archive-latest)
|
|
1096
|
-
local repo asset checksums_asset archive_executable latest_tag latest_version
|
|
1039
|
+
local repo asset checksums_asset archive_executable latest_tag latest_version resolved_asset resolved_checksums_asset
|
|
1097
1040
|
repo="$(jq -r --arg id "$tool_id" '.[$id].repo' "$resolved_file")"
|
|
1098
1041
|
asset="$(jq -r --arg id "$tool_id" '.[$id].asset' "$resolved_file")"
|
|
1099
1042
|
checksums_asset="$(jq -r --arg id "$tool_id" '.[$id].checksums_asset // "SHA256SUMS"' "$resolved_file")"
|
|
@@ -1104,10 +1047,17 @@ install_one_tool() {
|
|
|
1104
1047
|
latest_tag="$(resolve_latest_release_tag "$repo")" || { rc=1; latest_tag=""; }
|
|
1105
1048
|
if [[ "$rc" -eq 0 ]]; then
|
|
1106
1049
|
latest_version="${latest_tag#v}"
|
|
1107
|
-
|
|
1050
|
+
# A release whose asset filename bakes in the version (agent-vault:
|
|
1051
|
+
# agent-vault_<ver>_darwin_arm64.tar.gz) declares "{version}" in
|
|
1052
|
+
# .asset/.checksums_asset; lean-ctx's own asset names carry no
|
|
1053
|
+
# version at all, so this is a no-op substring replace for it.
|
|
1054
|
+
resolved_asset="${asset//\{version\}/$latest_version}"
|
|
1055
|
+
resolved_checksums_asset="${checksums_asset//\{version\}/$latest_version}"
|
|
1056
|
+
if [[ -x "$executable" ]] &&
|
|
1057
|
+
release_archive_version_matches "$("$executable" --version 2>/dev/null | head -n 1)" "$latest_version"; then
|
|
1108
1058
|
echo "latest release already installed: $package $latest_version"
|
|
1109
1059
|
else
|
|
1110
|
-
run_release_archive_latest "$package" "$repo" "$
|
|
1060
|
+
run_release_archive_latest "$package" "$repo" "$latest_tag" "$resolved_asset" "$resolved_checksums_asset" "$archive_executable" "$executable" || rc=1
|
|
1111
1061
|
fi
|
|
1112
1062
|
fi
|
|
1113
1063
|
fi
|
|
@@ -1652,6 +1602,212 @@ remove_one_repo_dir() {
|
|
|
1652
1602
|
rm -rf -- "$target"
|
|
1653
1603
|
}
|
|
1654
1604
|
|
|
1605
|
+
# Lexical-only path normalization: collapses repeated slashes ("//" ->
|
|
1606
|
+
# "/") and current-dir segments ("/./" -> "/"), and drops one trailing
|
|
1607
|
+
# slash. Never resolves ".." or symlinks, and never touches the filesystem
|
|
1608
|
+
# -- the target frequently doesn't exist yet when this runs. Second review
|
|
1609
|
+
# pass, 2026-09-29: without this, "/usr/local/bin//agent-vault" and
|
|
1610
|
+
# "/usr/local/bin/agent-vault" compare unequal even though they name the
|
|
1611
|
+
# same real file, silently defeating executable_claimed_by_current_manifest
|
|
1612
|
+
# below (the guard would say "not claimed" and let the old manager's `rm -f`
|
|
1613
|
+
# through) -- previous_resolved_file is never validated, so a malformed
|
|
1614
|
+
# path there is exactly the case this guard exists to protect against.
|
|
1615
|
+
normalize_manifest_path() {
|
|
1616
|
+
local path="$1"
|
|
1617
|
+
while [[ "$path" == *//* ]]; do path="${path//\/\//\/}"; done
|
|
1618
|
+
while [[ "$path" == */./* ]]; do path="${path//\/.\//\/}"; done
|
|
1619
|
+
path="${path%/}"
|
|
1620
|
+
printf '%s\n' "$path"
|
|
1621
|
+
}
|
|
1622
|
+
|
|
1623
|
+
# A previous entry's executable path can be EXACTLY the path a CURRENT
|
|
1624
|
+
# entry now owns -- e.g. agent-vault-cli migrating release-archive ->
|
|
1625
|
+
# release-archive-latest, both /usr/local/bin/agent-vault. Bug found in
|
|
1626
|
+
# review, 2026-09-29: the install loop runs BEFORE the removal loop below
|
|
1627
|
+
# and already wrote/verified that binary; "retain shared package after
|
|
1628
|
+
# entry deletion" only skips removal when manager+package are BOTH
|
|
1629
|
+
# unchanged, so a manager-only change (exactly this migration) still
|
|
1630
|
+
# selects the id for removal, and the OLD manager's case arm then does a
|
|
1631
|
+
# plain `rm -f` on the path the install pass upstream just installed.
|
|
1632
|
+
# Checked by executable path, not by tool_id/manager/package, because that
|
|
1633
|
+
# is the one thing the filesystem actually cares about -- both sides
|
|
1634
|
+
# normalized first (see normalize_manifest_path) so a malformed legacy path
|
|
1635
|
+
# in previous_resolved_file still compares equal to a clean one.
|
|
1636
|
+
#
|
|
1637
|
+
# Second review pass, 2026-09-29 (bare-name executables): most managers
|
|
1638
|
+
# store an ABSOLUTE path in .executable (release-archive-latest, shim,
|
|
1639
|
+
# bun-compile, repo-script all require the /usr/local/bin/ prefix), but pip,
|
|
1640
|
+
# npm, and brew store a bare command name instead -- pip's own
|
|
1641
|
+
# ensure_global_pip_executable/remove_global_pip_executable ALWAYS place (or
|
|
1642
|
+
# remove) that name as a fixed /usr/local/bin/<name> symlink regardless of
|
|
1643
|
+
# the pip package name, so a bare pip .executable maps there and IS
|
|
1644
|
+
# compared. npm and brew do not get the same treatment: their real install
|
|
1645
|
+
# location depends on the device's own npm global prefix / Homebrew prefix,
|
|
1646
|
+
# resolved only through a live `command -v` PATH search
|
|
1647
|
+
# (npm_global_executable_path) that varies by platform -- never a single
|
|
1648
|
+
# fixed path this function can compute without shelling out. A migration
|
|
1649
|
+
# INTO an npm or brew entry is not detected here and the old manager's real
|
|
1650
|
+
# removal proceeds exactly as before this fix. That gap is narrower than it
|
|
1651
|
+
# looks: npm and brew each remove through their OWN package manager (`npm
|
|
1652
|
+
# uninstall -g`, `brew uninstall`), never the raw `rm -f` this guard
|
|
1653
|
+
# protects, so nothing here relies on rm to leave an npm/brew-owned file
|
|
1654
|
+
# alone in the first place.
|
|
1655
|
+
executable_claimed_by_current_manifest() {
|
|
1656
|
+
local target="$1" normalized_target normalized_current current_manager current_executable
|
|
1657
|
+
normalized_target="$(normalize_manifest_path "$target")"
|
|
1658
|
+
while IFS=$'\t' read -r current_manager current_executable; do
|
|
1659
|
+
[[ -n "$current_executable" ]] || continue
|
|
1660
|
+
if [[ "$current_executable" == /* ]]; then
|
|
1661
|
+
normalized_current="$(normalize_manifest_path "$current_executable")"
|
|
1662
|
+
elif [[ "$current_manager" == pip ]]; then
|
|
1663
|
+
normalized_current="$(normalize_manifest_path "/usr/local/bin/$current_executable")"
|
|
1664
|
+
else
|
|
1665
|
+
continue
|
|
1666
|
+
fi
|
|
1667
|
+
[[ "$normalized_current" == "$normalized_target" ]] && return 0
|
|
1668
|
+
done < <(jq -r '.[] | [.manager, .executable] | @tsv' "$resolved_file")
|
|
1669
|
+
return 1
|
|
1670
|
+
}
|
|
1671
|
+
|
|
1672
|
+
# Uninstalls a single previously-applied tool the CURRENT manifest no longer
|
|
1673
|
+
# declares (or has migrated to a different manager/package) -- extracted
|
|
1674
|
+
# into its own function, like install_one_tool, so
|
|
1675
|
+
# packages/fleet/tests/test-manifest.sh can exercise it directly through the
|
|
1676
|
+
# RECONCILE_SOURCE_ONLY seam instead of only through a real apply run.
|
|
1677
|
+
remove_one_manifest_entry() {
|
|
1678
|
+
local tool_id="$1" manager package executable removed_repo_dir_target
|
|
1679
|
+
if jq -e --arg id "$tool_id" '.config.protected_tools | index($id)' "$manifest" >/dev/null; then
|
|
1680
|
+
echo "refusing to remove protected bootstrap tool: $tool_id" >&2
|
|
1681
|
+
exit 1
|
|
1682
|
+
fi
|
|
1683
|
+
manager="$(jq -r --arg id "$tool_id" '.[$id].manager' "$previous_resolved_file")"
|
|
1684
|
+
package="$(jq -r --arg id "$tool_id" '.[$id].package' "$previous_resolved_file")"
|
|
1685
|
+
executable="$(jq -r --arg id "$tool_id" '.[$id].executable' "$previous_resolved_file")"
|
|
1686
|
+
if is_in_place_bun_to_npm_migration "$tool_id"; then
|
|
1687
|
+
if [[ "$mode" == apply ]]; then
|
|
1688
|
+
echo "retired Bun compilation already removed for npm migration: $tool_id"
|
|
1689
|
+
fi
|
|
1690
|
+
return 0
|
|
1691
|
+
fi
|
|
1692
|
+
if jq -e --arg manager "$manager" --arg package "$package" 'to_entries | any(.value.manager == $manager and .value.package == $package)' "$resolved_file" >/dev/null; then
|
|
1693
|
+
echo "retain shared package after entry deletion: $manager:$package"
|
|
1694
|
+
return 0
|
|
1695
|
+
fi
|
|
1696
|
+
# Truthfulness fix (second review pass, 2026-09-29): for the managers that
|
|
1697
|
+
# remove via a raw filesystem `rm -f` on a fixed path (never their own
|
|
1698
|
+
# package manager's uninstall command), check executable_claimed_by_
|
|
1699
|
+
# current_manifest BEFORE claiming an "uninstall" happened at all. The
|
|
1700
|
+
# log line printed below this case is the only outcome a human or another
|
|
1701
|
+
# tool sees; printing "explicit manifest deletion: uninstall ..." and only
|
|
1702
|
+
# THEN discovering the file is retained (as this used to) makes the log
|
|
1703
|
+
# lie about what just happened, exactly backwards from "log the decision
|
|
1704
|
+
# as the outcome."
|
|
1705
|
+
case "$manager" in
|
|
1706
|
+
release-archive | release-archive-latest | shim | bun-compile)
|
|
1707
|
+
if executable_claimed_by_current_manifest "$executable"; then
|
|
1708
|
+
echo "retain $tool_id ($manager:$package): $executable is still declared by the current manifest"
|
|
1709
|
+
return 0
|
|
1710
|
+
fi
|
|
1711
|
+
;;
|
|
1712
|
+
esac
|
|
1713
|
+
echo "explicit manifest deletion: uninstall $tool_id ($manager:$package)"
|
|
1714
|
+
case "$manager" in
|
|
1715
|
+
brew) run_brew uninstall "$package" ;;
|
|
1716
|
+
apt) run_apt remove -y "$package" ;;
|
|
1717
|
+
npm) run_npm uninstall -g "$package" ;;
|
|
1718
|
+
pip)
|
|
1719
|
+
run_pip uninstall --break-system-packages -y "$package"
|
|
1720
|
+
remove_global_pip_executable "$executable"
|
|
1721
|
+
;;
|
|
1722
|
+
# "release-archive" (pinned version+url+sha256) is retired from
|
|
1723
|
+
# validate-manifest's accepted managers (Tarun, 2026-09-29: versions
|
|
1724
|
+
# are never pinned) -- no CURRENT manifest.json can declare one, so
|
|
1725
|
+
# install_one_tool no longer has a case for it. This removal arm stays
|
|
1726
|
+
# so a device whose applied-manifest.json still remembers an old
|
|
1727
|
+
# release-archive entry (agent-vault-cli, before this change) can
|
|
1728
|
+
# still cleanly uninstall it the next time it reconciles; previous
|
|
1729
|
+
# state is read straight from disk, never re-validated.
|
|
1730
|
+
release-archive)
|
|
1731
|
+
[[ "$executable" == /usr/local/bin/* ]] || {
|
|
1732
|
+
echo "refusing unsafe release archive removal target: $executable" >&2
|
|
1733
|
+
exit 1
|
|
1734
|
+
}
|
|
1735
|
+
if [[ "$mode" == apply ]]; then
|
|
1736
|
+
rm -f -- "$executable"
|
|
1737
|
+
else
|
|
1738
|
+
echo "would remove pinned release executable: $executable"
|
|
1739
|
+
fi
|
|
1740
|
+
;;
|
|
1741
|
+
release-archive-latest)
|
|
1742
|
+
[[ "$executable" == /usr/local/bin/* ]] || {
|
|
1743
|
+
echo "refusing unsafe release archive removal target: $executable" >&2
|
|
1744
|
+
exit 1
|
|
1745
|
+
}
|
|
1746
|
+
if [[ "$mode" == apply ]]; then
|
|
1747
|
+
rm -f -- "$executable"
|
|
1748
|
+
else
|
|
1749
|
+
echo "would remove latest release executable: $executable"
|
|
1750
|
+
fi
|
|
1751
|
+
;;
|
|
1752
|
+
shim)
|
|
1753
|
+
[[ "$executable" == /usr/local/bin/* ]] || {
|
|
1754
|
+
echo "refusing unsafe shim removal target: $executable" >&2
|
|
1755
|
+
exit 1
|
|
1756
|
+
}
|
|
1757
|
+
if [[ "$mode" == apply ]]; then
|
|
1758
|
+
rm -f -- "$executable"
|
|
1759
|
+
else
|
|
1760
|
+
echo "would remove shim: $executable"
|
|
1761
|
+
fi
|
|
1762
|
+
;;
|
|
1763
|
+
repo-script)
|
|
1764
|
+
if [[ "$mode" == apply ]]; then
|
|
1765
|
+
remove_one_repo_script "$executable"
|
|
1766
|
+
else
|
|
1767
|
+
[[ "$executable" =~ ^/usr/local/bin/[A-Za-z0-9][A-Za-z0-9._-]*$ ]] || {
|
|
1768
|
+
echo "refusing unsafe managed script removal target: $executable" >&2
|
|
1769
|
+
exit 1
|
|
1770
|
+
}
|
|
1771
|
+
echo "would remove managed repo script: $executable"
|
|
1772
|
+
fi
|
|
1773
|
+
;;
|
|
1774
|
+
repo-dir)
|
|
1775
|
+
removed_repo_dir_target="$(jq -r --arg id "$tool_id" '.[$id].target' "$previous_resolved_file")"
|
|
1776
|
+
if [[ "$mode" == apply ]]; then
|
|
1777
|
+
remove_one_repo_dir "$removed_repo_dir_target"
|
|
1778
|
+
else
|
|
1779
|
+
[[ "$removed_repo_dir_target" == "$repo_dir_libexec_root"/* ]] || {
|
|
1780
|
+
echo "refusing unsafe repo-dir removal target: $removed_repo_dir_target" >&2
|
|
1781
|
+
exit 1
|
|
1782
|
+
}
|
|
1783
|
+
echo "would remove repo dir: $removed_repo_dir_target"
|
|
1784
|
+
fi
|
|
1785
|
+
;;
|
|
1786
|
+
bun-compile)
|
|
1787
|
+
[[ "$executable" == /usr/local/bin/* ]] || {
|
|
1788
|
+
echo "refusing unsafe bun binary removal target: $executable" >&2
|
|
1789
|
+
exit 1
|
|
1790
|
+
}
|
|
1791
|
+
if [[ "$mode" == apply ]]; then
|
|
1792
|
+
rm -f -- "$executable"
|
|
1793
|
+
else
|
|
1794
|
+
echo "would remove bun binary: $executable"
|
|
1795
|
+
fi
|
|
1796
|
+
;;
|
|
1797
|
+
embedding-model)
|
|
1798
|
+
if [[ "$mode" == apply ]]; then
|
|
1799
|
+
[[ "$(id -u)" -eq 0 ]] || { echo "apply mode must run as root" >&2; exit 1; }
|
|
1800
|
+
command -v bun >/dev/null 2>&1 || { echo "embedding-model requires bun; ensure bun installs before this tool" >&2; exit 1; }
|
|
1801
|
+
(cd /tmp && sudo -u "$administrator" -H env PATH="${brew_bin%/*}:/usr/bin:/bin" \
|
|
1802
|
+
bun "$repo_root/packages/fleet/src/install-embedding-model.ts" uninstall </dev/null)
|
|
1803
|
+
else
|
|
1804
|
+
echo "would remove embedding model cache: ~/.cache/adl-embedding/model (as $administrator)"
|
|
1805
|
+
fi
|
|
1806
|
+
;;
|
|
1807
|
+
*) echo "unsupported manager in previous manifest: $manager" >&2; exit 1 ;;
|
|
1808
|
+
esac
|
|
1809
|
+
}
|
|
1810
|
+
|
|
1655
1811
|
# config.git_global_config: global git config for the administrator (the
|
|
1656
1812
|
# account whose HOME the per-user deployers below also write to). Apply runs git as
|
|
1657
1813
|
# that user (sudo -u -H) so ~/.gitconfig stays user-owned; plan/audit only
|
|
@@ -2194,111 +2350,7 @@ reconcile_surface_clis
|
|
|
2194
2350
|
if [[ "$have_previous" -eq 1 ]]; then
|
|
2195
2351
|
while IFS= read -r tool_id; do
|
|
2196
2352
|
[[ -n "$tool_id" ]] || continue
|
|
2197
|
-
|
|
2198
|
-
echo "refusing to remove protected bootstrap tool: $tool_id" >&2
|
|
2199
|
-
exit 1
|
|
2200
|
-
fi
|
|
2201
|
-
manager="$(jq -r --arg id "$tool_id" '.[$id].manager' "$previous_resolved_file")"
|
|
2202
|
-
package="$(jq -r --arg id "$tool_id" '.[$id].package' "$previous_resolved_file")"
|
|
2203
|
-
executable="$(jq -r --arg id "$tool_id" '.[$id].executable' "$previous_resolved_file")"
|
|
2204
|
-
if is_in_place_bun_to_npm_migration "$tool_id"; then
|
|
2205
|
-
if [[ "$mode" == apply ]]; then
|
|
2206
|
-
echo "retired Bun compilation already removed for npm migration: $tool_id"
|
|
2207
|
-
fi
|
|
2208
|
-
continue
|
|
2209
|
-
fi
|
|
2210
|
-
if jq -e --arg manager "$manager" --arg package "$package" 'to_entries | any(.value.manager == $manager and .value.package == $package)' "$resolved_file" >/dev/null; then
|
|
2211
|
-
echo "retain shared package after entry deletion: $manager:$package"
|
|
2212
|
-
continue
|
|
2213
|
-
fi
|
|
2214
|
-
echo "explicit manifest deletion: uninstall $tool_id ($manager:$package)"
|
|
2215
|
-
case "$manager" in
|
|
2216
|
-
brew) run_brew uninstall "$package" ;;
|
|
2217
|
-
apt) run_apt remove -y "$package" ;;
|
|
2218
|
-
npm) run_npm uninstall -g "$package" ;;
|
|
2219
|
-
pip)
|
|
2220
|
-
run_pip uninstall --break-system-packages -y "$package"
|
|
2221
|
-
remove_global_pip_executable "$executable"
|
|
2222
|
-
;;
|
|
2223
|
-
release-archive)
|
|
2224
|
-
[[ "$executable" == /usr/local/bin/* ]] || {
|
|
2225
|
-
echo "refusing unsafe release archive removal target: $executable" >&2
|
|
2226
|
-
exit 1
|
|
2227
|
-
}
|
|
2228
|
-
if [[ "$mode" == apply ]]; then
|
|
2229
|
-
rm -f -- "$executable"
|
|
2230
|
-
else
|
|
2231
|
-
echo "would remove pinned release executable: $executable"
|
|
2232
|
-
fi
|
|
2233
|
-
;;
|
|
2234
|
-
release-archive-latest)
|
|
2235
|
-
[[ "$executable" == /usr/local/bin/* ]] || {
|
|
2236
|
-
echo "refusing unsafe release archive removal target: $executable" >&2
|
|
2237
|
-
exit 1
|
|
2238
|
-
}
|
|
2239
|
-
if [[ "$mode" == apply ]]; then
|
|
2240
|
-
rm -f -- "$executable"
|
|
2241
|
-
else
|
|
2242
|
-
echo "would remove latest release executable: $executable"
|
|
2243
|
-
fi
|
|
2244
|
-
;;
|
|
2245
|
-
shim)
|
|
2246
|
-
[[ "$executable" == /usr/local/bin/* ]] || {
|
|
2247
|
-
echo "refusing unsafe shim removal target: $executable" >&2
|
|
2248
|
-
exit 1
|
|
2249
|
-
}
|
|
2250
|
-
if [[ "$mode" == apply ]]; then
|
|
2251
|
-
rm -f -- "$executable"
|
|
2252
|
-
else
|
|
2253
|
-
echo "would remove shim: $executable"
|
|
2254
|
-
fi
|
|
2255
|
-
;;
|
|
2256
|
-
repo-script)
|
|
2257
|
-
if [[ "$mode" == apply ]]; then
|
|
2258
|
-
remove_one_repo_script "$executable"
|
|
2259
|
-
else
|
|
2260
|
-
[[ "$executable" =~ ^/usr/local/bin/[A-Za-z0-9][A-Za-z0-9._-]*$ ]] || {
|
|
2261
|
-
echo "refusing unsafe managed script removal target: $executable" >&2
|
|
2262
|
-
exit 1
|
|
2263
|
-
}
|
|
2264
|
-
echo "would remove managed repo script: $executable"
|
|
2265
|
-
fi
|
|
2266
|
-
;;
|
|
2267
|
-
repo-dir)
|
|
2268
|
-
removed_repo_dir_target="$(jq -r --arg id "$tool_id" '.[$id].target' "$previous_resolved_file")"
|
|
2269
|
-
if [[ "$mode" == apply ]]; then
|
|
2270
|
-
remove_one_repo_dir "$removed_repo_dir_target"
|
|
2271
|
-
else
|
|
2272
|
-
[[ "$removed_repo_dir_target" == "$repo_dir_libexec_root"/* ]] || {
|
|
2273
|
-
echo "refusing unsafe repo-dir removal target: $removed_repo_dir_target" >&2
|
|
2274
|
-
exit 1
|
|
2275
|
-
}
|
|
2276
|
-
echo "would remove repo dir: $removed_repo_dir_target"
|
|
2277
|
-
fi
|
|
2278
|
-
;;
|
|
2279
|
-
bun-compile)
|
|
2280
|
-
[[ "$executable" == /usr/local/bin/* ]] || {
|
|
2281
|
-
echo "refusing unsafe bun binary removal target: $executable" >&2
|
|
2282
|
-
exit 1
|
|
2283
|
-
}
|
|
2284
|
-
if [[ "$mode" == apply ]]; then
|
|
2285
|
-
rm -f -- "$executable"
|
|
2286
|
-
else
|
|
2287
|
-
echo "would remove bun binary: $executable"
|
|
2288
|
-
fi
|
|
2289
|
-
;;
|
|
2290
|
-
embedding-model)
|
|
2291
|
-
if [[ "$mode" == apply ]]; then
|
|
2292
|
-
[[ "$(id -u)" -eq 0 ]] || { echo "apply mode must run as root" >&2; exit 1; }
|
|
2293
|
-
command -v bun >/dev/null 2>&1 || { echo "embedding-model requires bun; ensure bun installs before this tool" >&2; exit 1; }
|
|
2294
|
-
(cd /tmp && sudo -u "$administrator" -H env PATH="${brew_bin%/*}:/usr/bin:/bin" \
|
|
2295
|
-
bun "$repo_root/packages/fleet/src/install-embedding-model.ts" uninstall </dev/null)
|
|
2296
|
-
else
|
|
2297
|
-
echo "would remove embedding model cache: ~/.cache/adl-embedding/model (as $administrator)"
|
|
2298
|
-
fi
|
|
2299
|
-
;;
|
|
2300
|
-
*) echo "unsupported manager in previous manifest: $manager" >&2; exit 1 ;;
|
|
2301
|
-
esac
|
|
2353
|
+
remove_one_manifest_entry "$tool_id"
|
|
2302
2354
|
# Selects an id when it was deleted outright (absent from the current
|
|
2303
2355
|
# manifest) OR retained but migrated to a different manager/package (e.g.
|
|
2304
2356
|
# lean-ctx moving from npm:lean-ctx-bin to release-archive-latest:lean-ctx)
|
package/bin/validate-manifest
CHANGED
|
@@ -70,18 +70,19 @@ if ! jq -e '
|
|
|
70
70
|
(.mac.devices.m3.surface_clis // [] | any(.name == "codex" and .manager == "brew" and .command == "brew" and .update_args == ["upgrade", "--cask", "codex"] and (.report_only // false) == false)) and
|
|
71
71
|
(.mac.devices.m5.surface_clis // [] | any(.name == "codex" and .manager == "brew" and .command == "brew" and .update_args == ["upgrade", "--cask", "codex"] and (.report_only // false) == false)) and
|
|
72
72
|
([.mac.common.tools[], .linux.common.tools[], .mac.devices[].tools[], .linux.devices[].tools[]] |
|
|
73
|
-
all(.manager == "brew" or .manager == "apt" or .manager == "npm" or .manager == "pip" or .manager == "release-archive
|
|
73
|
+
all(.manager == "brew" or .manager == "apt" or .manager == "npm" or .manager == "pip" or .manager == "release-archive-latest" or .manager == "shim" or .manager == "repo-script" or .manager == "repo-dir" or .manager == "bun-compile" or .manager == "embedding-model") and
|
|
74
74
|
all((.package | type) == "string" and (.package | length) > 0) and
|
|
75
75
|
all((.executable | type) == "string" and (.executable | length) > 0) and
|
|
76
|
+
# Second review pass, 2026-09-29: the removal-path guard in bin/
|
|
77
|
+
# reconcile (executable_claimed_by_current_manifest) compares
|
|
78
|
+
# .executable paths lexically after normalizing a legacy, unvalidated
|
|
79
|
+
# previous-manifest path -- a CURRENT manifest must never need that
|
|
80
|
+
# normalization in the first place, so a "//" or "/./" segment is
|
|
81
|
+
# rejected here outright rather than silently accepted and normalized
|
|
82
|
+
# away later.
|
|
83
|
+
all((.executable | contains("//") | not) and (.executable | contains("/./") | not)) and
|
|
76
84
|
all((.reason // null) == null or (.reason | type == "string" and length > 0)) and
|
|
77
|
-
all(if .manager == "release-archive" then
|
|
78
|
-
((.version | type) == "string" and (.version | length) > 0) and
|
|
79
|
-
((.url | type) == "string" and (.url | startswith("https://"))) and
|
|
80
|
-
((.sha256 | type) == "string" and (.sha256 | test("^[0-9a-f]{64}$"))) and
|
|
81
|
-
((.archive_executable | type) == "string" and
|
|
82
|
-
(.archive_executable | test("^[^/]") and (contains("..") | not))) and
|
|
83
|
-
(.executable | startswith("/usr/local/bin/"))
|
|
84
|
-
elif .manager == "release-archive-latest" then
|
|
85
|
+
all(if .manager == "release-archive-latest" then
|
|
85
86
|
((.repo | type) == "string" and (.repo | test("^[^/[:space:]]+/[^/[:space:]]+$"))) and
|
|
86
87
|
((.asset | type) == "string" and
|
|
87
88
|
(.asset | test("^[^/]") and (contains("..") | not))) and
|
|
@@ -124,12 +125,13 @@ if ! jq -e '
|
|
|
124
125
|
((.dim | type) == "number") and
|
|
125
126
|
(has("revision") | not) and (has("source_files") | not) and (has("artifact_files") | not)
|
|
126
127
|
elif .manager == "npm" then
|
|
127
|
-
#
|
|
128
|
-
#
|
|
129
|
-
#
|
|
130
|
-
#
|
|
131
|
-
#
|
|
132
|
-
|
|
128
|
+
# Tarun, 2026-09-29 (hard rule): versions are never pinned -- every
|
|
129
|
+
# fleet tool installs latest stable. .version on npm used to be an
|
|
130
|
+
# optional pin (Handoff 5, 2026-09-26, H4); it is refused outright now,
|
|
131
|
+
# the same way release-archive-latest already refuses one, and the
|
|
132
|
+
# same day the release-archive manager (pinned version+url+sha256) was
|
|
133
|
+
# removed from the accepted managers above entirely.
|
|
134
|
+
(has("version") | not) and
|
|
133
135
|
# .allow_scripts (docs/operations/global-tools.md Topic 2, decided
|
|
134
136
|
# 2026-09-28): an explicit, per-entry allow-list of dependency package
|
|
135
137
|
# names whose install/postinstall scripts reconcile passes through as
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@amsterdamdatalabs/adl-agent-control-linux-x64",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.7",
|
|
4
4
|
"description": "adl CLI binary for linux/x64 (agent identity + Azure DevOps front door — see docs/architecture/cli-design.md)",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"os": [
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
"mac": {
|
|
45
45
|
"common": {
|
|
46
46
|
"tools": {
|
|
47
|
-
"agent-vault-cli": {"manager": "release-archive", "package": "agent-vault", "executable": "/usr/local/bin/agent-vault", "
|
|
47
|
+
"agent-vault-cli": {"manager": "release-archive-latest", "package": "agent-vault", "executable": "/usr/local/bin/agent-vault", "repo": "Infisical/agent-vault", "asset": "agent-vault_{version}_darwin_arm64.tar.gz", "checksums_asset": "checksums.txt", "archive_executable": "agent-vault"},
|
|
48
48
|
"ast-grep": {"manager": "brew", "package": "ast-grep", "executable": "ast-grep"},
|
|
49
49
|
"azure-cli": {"manager": "brew", "package": "azure-cli", "executable": "az"},
|
|
50
50
|
"bun": {"manager": "brew", "package": "bun", "executable": "bun"},
|
|
@@ -57,7 +57,7 @@
|
|
|
57
57
|
"docker-compose": {"manager": "brew", "package": "docker-compose", "executable": "docker-compose"},
|
|
58
58
|
"docs-search": {"manager": "npm", "package": "@amsterdamdatalabs/enact-docs-search", "executable": "enact-docs-search", "allow_scripts": ["hnswlib-node", "onnxruntime-node", "sharp", "protobufjs"], "reason": "Separate search product that provides the search tool."},
|
|
59
59
|
"adl": {"manager": "npm", "package": "@amsterdamdatalabs/adl-agent-control", "executable": "adl"},
|
|
60
|
-
"adl-agent-id": {"manager": "npm", "package": "@amsterdamdatalabs/adl-agent-id", "executable": "adl-agent-id", "
|
|
60
|
+
"adl-agent-id": {"manager": "npm", "package": "@amsterdamdatalabs/adl-agent-id", "executable": "adl-agent-id", "reason": "Separate Go binary with its own trust boundary."},
|
|
61
61
|
"fd": {"manager": "brew", "package": "fd", "executable": "fd"},
|
|
62
62
|
"git": {"manager": "brew", "package": "git", "executable": "git"},
|
|
63
63
|
"jq": {"manager": "brew", "package": "jq", "executable": "jq"},
|
|
@@ -134,7 +134,7 @@
|
|
|
134
134
|
"common": {
|
|
135
135
|
"os_upgrade": true,
|
|
136
136
|
"tools": {
|
|
137
|
-
"agent-vault-cli": {"manager": "release-archive", "package": "agent-vault", "executable": "/usr/local/bin/agent-vault", "
|
|
137
|
+
"agent-vault-cli": {"manager": "release-archive-latest", "package": "agent-vault", "executable": "/usr/local/bin/agent-vault", "repo": "Infisical/agent-vault", "asset": "agent-vault_{version}_linux_amd64.tar.gz", "checksums_asset": "checksums.txt", "archive_executable": "agent-vault"},
|
|
138
138
|
"ast-grep": {"manager": "brew", "package": "ast-grep", "executable": "ast-grep"},
|
|
139
139
|
"azure-cli": {"manager": "brew", "package": "azure-cli", "executable": "az"},
|
|
140
140
|
"bun": {"manager": "brew", "package": "bun", "executable": "bun"},
|
|
@@ -147,7 +147,7 @@
|
|
|
147
147
|
"docker-compose": {"manager": "brew", "package": "docker-compose", "executable": "docker-compose"},
|
|
148
148
|
"docs-search": {"manager": "npm", "package": "@amsterdamdatalabs/enact-docs-search", "executable": "enact-docs-search", "allow_scripts": ["hnswlib-node", "onnxruntime-node", "sharp", "protobufjs"], "reason": "Separate search product that provides the search tool."},
|
|
149
149
|
"adl": {"manager": "npm", "package": "@amsterdamdatalabs/adl-agent-control", "executable": "adl"},
|
|
150
|
-
"adl-agent-id": {"manager": "npm", "package": "@amsterdamdatalabs/adl-agent-id", "executable": "adl-agent-id", "
|
|
150
|
+
"adl-agent-id": {"manager": "npm", "package": "@amsterdamdatalabs/adl-agent-id", "executable": "adl-agent-id", "reason": "Separate Go binary with its own trust boundary."},
|
|
151
151
|
"fd": {"manager": "brew", "package": "fd", "executable": "fd"},
|
|
152
152
|
"git": {"manager": "brew", "package": "git", "executable": "git"},
|
|
153
153
|
"jq": {"manager": "brew", "package": "jq", "executable": "jq"},
|
|
@@ -93,7 +93,7 @@
|
|
|
93
93
|
"additionalProperties": false,
|
|
94
94
|
"required": ["manager", "package", "executable"],
|
|
95
95
|
"properties": {
|
|
96
|
-
"manager": {"enum": ["apt", "brew", "npm", "pip", "release-archive
|
|
96
|
+
"manager": {"enum": ["apt", "brew", "npm", "pip", "release-archive-latest", "shim", "repo-script", "bun-compile", "embedding-model"]},
|
|
97
97
|
"package": {"type": "string", "minLength": 1},
|
|
98
98
|
"executable": {"type": "string", "minLength": 1},
|
|
99
99
|
"version": {"type": "string", "minLength": 1},
|
|
@@ -110,17 +110,18 @@
|
|
|
110
110
|
"reason": {"type": "string", "minLength": 1}
|
|
111
111
|
},
|
|
112
112
|
"allOf": [
|
|
113
|
-
{
|
|
114
|
-
"if": {"properties": {"manager": {"const": "release-archive"}}},
|
|
115
|
-
"then": {"required": ["version", "url", "sha256", "archive_executable"]}
|
|
116
|
-
},
|
|
117
113
|
{
|
|
118
114
|
"if": {"properties": {"manager": {"const": "release-archive-latest"}}},
|
|
119
115
|
"then": {
|
|
120
116
|
"required": ["repo", "asset", "archive_executable"],
|
|
117
|
+
"not": {"anyOf": [{"required": ["version"]}, {"required": ["url"]}, {"required": ["sha256"]}]},
|
|
121
118
|
"properties": {"executable": {"pattern": "^/usr/local/bin/"}}
|
|
122
119
|
}
|
|
123
120
|
},
|
|
121
|
+
{
|
|
122
|
+
"if": {"properties": {"manager": {"const": "npm"}}},
|
|
123
|
+
"then": {"not": {"required": ["version"]}}
|
|
124
|
+
},
|
|
124
125
|
{
|
|
125
126
|
"if": {"properties": {"manager": {"const": "shim"}}},
|
|
126
127
|
"then": {"properties": {"executable": {"pattern": "^/usr/local/bin/"}}}
|
|
@@ -120,6 +120,23 @@ export const GITIGNORE_BLOCK_LINES: readonly string[] = [
|
|
|
120
120
|
'# adl process convention: scratch and throwaway work, never committed',
|
|
121
121
|
'/.scratchpad/',
|
|
122
122
|
'packages/*/.scratchpad/',
|
|
123
|
+
'',
|
|
124
|
+
'# fleet tools that write into every checkout: docs-search index, code-review-graph, compliance pytest',
|
|
125
|
+
'.cache/',
|
|
126
|
+
'.code-review-graph/',
|
|
127
|
+
'.codegraph/',
|
|
128
|
+
'.pytest_cache/',
|
|
129
|
+
'',
|
|
130
|
+
'# dependencies, OS and log noise',
|
|
131
|
+
'node_modules/',
|
|
132
|
+
'.DS_Store',
|
|
133
|
+
'*.log',
|
|
134
|
+
'',
|
|
135
|
+
'# local secrets and per-user agent settings, never committed',
|
|
136
|
+
'.env',
|
|
137
|
+
'.env.*',
|
|
138
|
+
'!.env.example',
|
|
139
|
+
'.claude/settings.local.json',
|
|
123
140
|
] as const
|
|
124
141
|
|
|
125
142
|
interface SplitText {
|