@amsterdamdatalabs/adl-agent-control-linux-x64 0.1.10 → 0.1.12
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 +2 -2
- package/bin/git +1 -1
- package/bin/git-ado +2 -2
- package/bin/lib/bun-compile-build.sh +1 -1
- package/bin/lib/fleet-host.sh +59 -0
- package/bin/lib/lean-ctx-observe-hooks.sh +9 -9
- package/bin/reconcile +222 -249
- package/bin/reconcile-host +111 -0
- package/bin/setup +216 -0
- package/bin/sync-and-reconcile +52 -39
- package/bin/validate-manifest +15 -44
- package/package.json +1 -3
- package/packages/agent-hooks/package.json +1 -2
- package/packages/agent-hooks/src/rules/impl/fs-trash.ts +2 -2
- package/packages/agent-settings/assets/GLOBAL-AGENTS.md +4 -2
- package/packages/agent-settings/src/global-surface-sweep.ts +5 -15
- package/packages/agent-skills/package.json +1 -1
- package/packages/azdo/package.json +1 -2
- package/packages/fleet/manifest.json +5 -24
- package/packages/fleet/manifest.schema.json +8 -58
- package/packages/fleet/src/install-embedding-model.ts +1 -1
- package/packages/fleet/src/repo-maintain.ts +403 -0
- package/packages/fleet/src/scratch-reap.ts +1 -1
- package/packages/repo-controls/package.json +0 -1
- package/packages/fleet/jobs/git-maintain/src/main.ts +0 -848
- package/packages/fleet/systemd/adl-azure-agent-update.service +0 -13
- package/packages/fleet/systemd/adl-azure-agent-update.timer +0 -10
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
# `sudo adl reconcile --host NAME [--mode plan|apply]` -- one full pass of what
|
|
5
|
+
# the 12-hourly job does (the job's program is `adl reconcile`, which runs this),
|
|
6
|
+
# also run on demand:
|
|
7
|
+
#
|
|
8
|
+
# 1. tools: this package's bin/sync-and-reconcile with
|
|
9
|
+
# `--source npm --device NAME --owner OWNER` (npm update, then tools
|
|
10
|
+
# reconcile). The owner is the device's `administrator` in this package's
|
|
11
|
+
# manifest (bin/lib/fleet-host.sh, the lookup bin/setup shares). --mode is
|
|
12
|
+
# forwarded only when given, so the default is apply.
|
|
13
|
+
# 2. repositories: `adl maintain --location <repo_location> --expect-user
|
|
14
|
+
# OWNER`, the package's own bin/adl, run AS THE ADMINISTRATOR -- never as
|
|
15
|
+
# root. sudo resets PATH to its secure_path, which has neither Homebrew nor
|
|
16
|
+
# /usr/local/bin, so PATH is always handed over explicitly with `env PATH=`
|
|
17
|
+
# (every sudo -u call that ends up running adl, git or bun must). --mode
|
|
18
|
+
# plan becomes --dry-run.
|
|
19
|
+
#
|
|
20
|
+
# Both steps always run (a failed tools step does not hide a repository problem,
|
|
21
|
+
# and vice versa); the exit code is the first failure's, and each failure is
|
|
22
|
+
# reported as an ERROR line. A host that declares no repo_location skips step 2
|
|
23
|
+
# with a log line.
|
|
24
|
+
#
|
|
25
|
+
# ADL_SETUP_TEST_ROOT is the same single test switch bin/setup has: unset in
|
|
26
|
+
# every real run; when set it only keeps the caller's PATH so `id`, `uname` and
|
|
27
|
+
# `sudo` can be stubbed (packages/fleet/tests/reconcile-host.test.ts).
|
|
28
|
+
|
|
29
|
+
if [[ -n "${ADL_SETUP_TEST_ROOT:-}" ]]; then
|
|
30
|
+
export PATH="${PATH:-/usr/bin:/bin}"
|
|
31
|
+
else
|
|
32
|
+
export PATH="/usr/local/bin:/opt/homebrew/bin:/home/linuxbrew/.linuxbrew/bin:/usr/bin:/bin:/usr/sbin:/sbin"
|
|
33
|
+
fi
|
|
34
|
+
|
|
35
|
+
host=""
|
|
36
|
+
mode=""
|
|
37
|
+
while [[ "$#" -gt 0 ]]; do
|
|
38
|
+
case "$1" in
|
|
39
|
+
--host) host="${2:-}"; shift 2 ;;
|
|
40
|
+
--mode) mode="${2:-}"; shift 2 ;;
|
|
41
|
+
*) echo "ERROR unknown argument: $1" >&2; exit 2 ;;
|
|
42
|
+
esac
|
|
43
|
+
done
|
|
44
|
+
[[ -n "$host" ]] || { echo "ERROR usage: sudo adl reconcile --host NAME [--mode plan|apply]" >&2; exit 2; }
|
|
45
|
+
if [[ -n "$mode" && "$mode" != plan && "$mode" != apply ]]; then
|
|
46
|
+
echo "ERROR unsupported mode: $mode (expected plan or apply)" >&2
|
|
47
|
+
exit 2
|
|
48
|
+
fi
|
|
49
|
+
[[ "$(id -u)" -eq 0 ]] || { echo "ERROR adl reconcile must run as root: sudo adl reconcile --host $host" >&2; exit 1; }
|
|
50
|
+
|
|
51
|
+
script_dir="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
|
|
52
|
+
package_dir="$(cd -- "$script_dir/.." && pwd)"
|
|
53
|
+
# shellcheck source=lib/fleet-host.sh
|
|
54
|
+
source "$script_dir/lib/fleet-host.sh"
|
|
55
|
+
fleet_host_resolve "adl reconcile" "$package_dir/packages/fleet/manifest.json" "$host" || exit $?
|
|
56
|
+
owner="$fleet_host_owner"
|
|
57
|
+
repo_location="$fleet_host_repo_location"
|
|
58
|
+
|
|
59
|
+
[[ -x "$script_dir/sync-and-reconcile" ]] || { echo "ERROR adl reconcile: package scheduler script is missing: $script_dir/sync-and-reconcile" >&2; exit 1; }
|
|
60
|
+
|
|
61
|
+
# One lock around both steps: an on-demand run overlapping the timer must not
|
|
62
|
+
# run a second repository pass after its tools step lost sync's own lock.
|
|
63
|
+
if [[ -n "${ADL_SETUP_TEST_ROOT:-}" ]]; then
|
|
64
|
+
lock_dir="${ADL_SETUP_TEST_ROOT%/}/adl-reconcile.lock"
|
|
65
|
+
else
|
|
66
|
+
lock_dir=/var/run/adl-reconcile.lock
|
|
67
|
+
fi
|
|
68
|
+
if ! mkdir "$lock_dir" 2>/dev/null; then
|
|
69
|
+
echo "ERROR adl reconcile: another reconcile is running (lock: $lock_dir)" >&2
|
|
70
|
+
exit 1
|
|
71
|
+
fi
|
|
72
|
+
trap 'rmdir -- "$lock_dir"' EXIT
|
|
73
|
+
|
|
74
|
+
# 1. tools
|
|
75
|
+
sync_args=(--source npm --device "$host" --owner "$owner")
|
|
76
|
+
if [[ -n "$mode" ]]; then sync_args+=(--mode "$mode"); fi
|
|
77
|
+
tools_rc=0
|
|
78
|
+
"$script_dir/sync-and-reconcile" "${sync_args[@]}" || tools_rc=$?
|
|
79
|
+
if [[ "$tools_rc" -ne 0 ]]; then
|
|
80
|
+
echo "ERROR global-tools: tools reconcile failed (exit $tools_rc)" >&2
|
|
81
|
+
fi
|
|
82
|
+
|
|
83
|
+
# 2. repositories
|
|
84
|
+
repos_rc=0
|
|
85
|
+
if [[ -z "$repo_location" ]]; then
|
|
86
|
+
echo "global-tools: repo maintenance skipped: $host declares no repo_location"
|
|
87
|
+
else
|
|
88
|
+
adl_bin="$package_dir/bin/adl"
|
|
89
|
+
if [[ ! -x "$adl_bin" ]]; then
|
|
90
|
+
echo "ERROR global-tools: package adl is missing or not executable: $adl_bin" >&2
|
|
91
|
+
repos_rc=1
|
|
92
|
+
else
|
|
93
|
+
if [[ "$fleet_host_platform" == mac ]]; then
|
|
94
|
+
brew_bin_dir=/opt/homebrew/bin
|
|
95
|
+
else
|
|
96
|
+
brew_bin_dir=/home/linuxbrew/.linuxbrew/bin
|
|
97
|
+
fi
|
|
98
|
+
maintain_args=(maintain --location "$repo_location" --expect-user "$owner")
|
|
99
|
+
if [[ "$mode" == plan ]]; then maintain_args+=(--dry-run); fi
|
|
100
|
+
# /usr/local/bin first: git must resolve to the managed controller, which
|
|
101
|
+
# routes Azure DevOps traffic through the agent identity; Homebrew's git
|
|
102
|
+
# would bypass it.
|
|
103
|
+
sudo -u "$owner" -H env PATH="/usr/local/bin:$brew_bin_dir:/usr/bin:/bin" "$adl_bin" "${maintain_args[@]}" || repos_rc=$?
|
|
104
|
+
if [[ "$repos_rc" -ne 0 ]]; then
|
|
105
|
+
echo "ERROR global-tools: repository maintenance failed (exit $repos_rc)" >&2
|
|
106
|
+
fi
|
|
107
|
+
fi
|
|
108
|
+
fi
|
|
109
|
+
|
|
110
|
+
if [[ "$tools_rc" -ne 0 ]]; then exit "$tools_rc"; fi
|
|
111
|
+
exit "$repos_rc"
|
package/bin/setup
ADDED
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
# `sudo adl setup --host NAME` -- the whole onboarding of a host after
|
|
5
|
+
# `npm install -g @amsterdamdatalabs/adl-agent-control`:
|
|
6
|
+
#
|
|
7
|
+
# 1. check this is THE package the job manages (the one in the owner's global
|
|
8
|
+
# npm root), and that its bin/adl is there
|
|
9
|
+
# 2. run the first reconcile: `<this package>/bin/adl reconcile --host NAME`
|
|
10
|
+
# 3. only if that succeeded, arm the job that re-runs the same command every
|
|
11
|
+
# 12 hours
|
|
12
|
+
#
|
|
13
|
+
# A host that cannot reconcile is never left with a timer that fails unseen.
|
|
14
|
+
# The job's program is the package's own bin/adl, not a shell script: on macOS
|
|
15
|
+
# the one-time Full Disk Access grant (needed to read the repositories under the
|
|
16
|
+
# host's repo_location) goes to that binary, and the launchd/systemd job and
|
|
17
|
+
# `sudo adl reconcile --host NAME` are then literally the same command.
|
|
18
|
+
#
|
|
19
|
+
# Everything comes from this package: it locates itself from its own path and
|
|
20
|
+
# reads packages/fleet/manifest.json beside it (no git checkout, no source
|
|
21
|
+
# flag -- npm is the only source). The account the job runs npm as is the
|
|
22
|
+
# device's `administrator` in that manifest; there is no owner flag.
|
|
23
|
+
#
|
|
24
|
+
# ADL_SETUP_TEST_ROOT is the one test switch (packages/fleet/tests/setup.test.ts):
|
|
25
|
+
# unset in every real run. When set it relocates the system paths under that
|
|
26
|
+
# directory and keeps the caller's PATH so the system commands can be stubbed.
|
|
27
|
+
|
|
28
|
+
if [[ -n "${ADL_SETUP_TEST_ROOT:-}" ]]; then
|
|
29
|
+
export PATH="${PATH:-/usr/bin:/bin}"
|
|
30
|
+
# The sourced sync-and-reconcile has its own test switch; one switch here
|
|
31
|
+
# drives both, so a test sets only ADL_SETUP_TEST_ROOT.
|
|
32
|
+
export SYNC_AND_RECONCILE_TEST_ROOT="$ADL_SETUP_TEST_ROOT"
|
|
33
|
+
else
|
|
34
|
+
export PATH="/usr/local/bin:/opt/homebrew/bin:/home/linuxbrew/.linuxbrew/bin:/usr/bin:/bin:/usr/sbin:/sbin"
|
|
35
|
+
fi
|
|
36
|
+
|
|
37
|
+
host=""
|
|
38
|
+
while [[ "$#" -gt 0 ]]; do
|
|
39
|
+
case "$1" in
|
|
40
|
+
--host) host="${2:-}"; shift 2 ;;
|
|
41
|
+
*) echo "ERROR unknown argument: $1" >&2; exit 2 ;;
|
|
42
|
+
esac
|
|
43
|
+
done
|
|
44
|
+
[[ -n "$host" ]] || { echo "ERROR usage: sudo adl setup --host NAME" >&2; exit 2; }
|
|
45
|
+
[[ "$(id -u)" -eq 0 ]] || { echo "ERROR adl setup must run as root: sudo adl setup --host $host" >&2; exit 1; }
|
|
46
|
+
|
|
47
|
+
script_dir="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
|
|
48
|
+
package_dir="$(cd -- "$script_dir/.." && pwd)"
|
|
49
|
+
package_dir_real="$(cd -P -- "$script_dir/.." && pwd -P)"
|
|
50
|
+
# shellcheck source=lib/fleet-host.sh
|
|
51
|
+
source "$script_dir/lib/fleet-host.sh"
|
|
52
|
+
fleet_host_resolve "adl setup" "$package_dir/packages/fleet/manifest.json" "$host" || exit $?
|
|
53
|
+
owner="$fleet_host_owner"
|
|
54
|
+
minute="$fleet_host_minute"
|
|
55
|
+
|
|
56
|
+
# The job keeps THE package installed in the owner's global npm root up to date
|
|
57
|
+
# and reconciles from it. This must be that package, or the host would be armed
|
|
58
|
+
# to manage a different copy than the one the operator just ran. Ask npm the same
|
|
59
|
+
# way the job does (the functions are the job's own, from the sibling
|
|
60
|
+
# sync-and-reconcile), and compare real paths.
|
|
61
|
+
[[ -f "$script_dir/sync-and-reconcile" ]] || { echo "ERROR adl setup: package scheduler script is missing: $script_dir/sync-and-reconcile" >&2; exit 1; }
|
|
62
|
+
# shellcheck source=sync-and-reconcile
|
|
63
|
+
SYNC_AND_RECONCILE_SOURCE_ONLY=1 source "$script_dir/sync-and-reconcile"
|
|
64
|
+
os_name="$(uname -s)"
|
|
65
|
+
npm_root="$(npm_global_root "$owner" "$os_name")" || {
|
|
66
|
+
echo "ERROR adl setup: cannot resolve the global npm root as $owner" >&2
|
|
67
|
+
exit 1
|
|
68
|
+
}
|
|
69
|
+
managed_dir="$(npm_platform_package_dir "$npm_root" "$os_name" "$(uname -m)")" || exit 1
|
|
70
|
+
managed_real="$(cd -P -- "$managed_dir" 2>/dev/null && pwd -P)" || managed_real=""
|
|
71
|
+
if [[ -z "$managed_real" || "$package_dir_real" != "$managed_real" ]]; then
|
|
72
|
+
{
|
|
73
|
+
echo "ERROR adl setup: this package ($package_dir_real) is not the package the scheduled job manages ($managed_dir)."
|
|
74
|
+
echo "ERROR adl setup: install it where the job looks, as $owner, then run setup again:"
|
|
75
|
+
echo "ERROR adl setup: Linux: npm install -g --prefix /usr/local @amsterdamdatalabs/adl-agent-control"
|
|
76
|
+
echo "ERROR adl setup: macOS: npm install -g @amsterdamdatalabs/adl-agent-control"
|
|
77
|
+
} >&2
|
|
78
|
+
exit 1
|
|
79
|
+
fi
|
|
80
|
+
|
|
81
|
+
adl_bin="$package_dir_real/bin/adl"
|
|
82
|
+
[[ -x "$adl_bin" ]] || { echo "ERROR adl setup: the package adl is missing or not executable: $package_dir/bin/adl" >&2; exit 1; }
|
|
83
|
+
|
|
84
|
+
if [[ -n "${ADL_SETUP_TEST_ROOT:-}" ]]; then
|
|
85
|
+
system_root="${ADL_SETUP_TEST_ROOT%/}"
|
|
86
|
+
else
|
|
87
|
+
system_root=""
|
|
88
|
+
fi
|
|
89
|
+
legacy_adl_sync="$system_root/usr/local/libexec/adl-sync"
|
|
90
|
+
launch_daemons_dir="$system_root/Library/LaunchDaemons"
|
|
91
|
+
systemd_dir="$system_root/etc/systemd/system"
|
|
92
|
+
brew_prefix="$system_root/home/linuxbrew/.linuxbrew"
|
|
93
|
+
|
|
94
|
+
# Preflight that must hold before the first reconcile: the Linux job runs
|
|
95
|
+
# Homebrew as a non-root owner, and that owner needs git's safe.directory for
|
|
96
|
+
# the brew repositories or every `brew update` inside the reconcile fails.
|
|
97
|
+
if [[ "$fleet_host_platform" == linux ]]; then
|
|
98
|
+
if [[ -d "$brew_prefix" ]]; then
|
|
99
|
+
brew_owner="$(stat -c '%U' "$brew_prefix")"
|
|
100
|
+
[[ "$brew_owner" != root ]] || {
|
|
101
|
+
echo "ERROR Homebrew prefix must be owned by a non-root account: /home/linuxbrew/.linuxbrew" >&2
|
|
102
|
+
exit 1
|
|
103
|
+
}
|
|
104
|
+
else
|
|
105
|
+
echo "ERROR Homebrew prefix missing: /home/linuxbrew/.linuxbrew" >&2
|
|
106
|
+
exit 1
|
|
107
|
+
fi
|
|
108
|
+
for brew_repo in \
|
|
109
|
+
"$brew_prefix/Homebrew" \
|
|
110
|
+
"$brew_prefix/Homebrew/Library/Taps/adl-tan-theta/homebrew-tap"; do
|
|
111
|
+
[[ -d "$brew_repo/.git" ]] || continue
|
|
112
|
+
if ! (cd /tmp && sudo -u "$brew_owner" -H git config --global --get-all safe.directory 2>/dev/null) | grep -Fxq "$brew_repo"; then
|
|
113
|
+
(cd /tmp && sudo -u "$brew_owner" -H git config --global --add safe.directory "$brew_repo")
|
|
114
|
+
fi
|
|
115
|
+
done
|
|
116
|
+
fi
|
|
117
|
+
|
|
118
|
+
mkdir -p "$system_root/var/lib/adl" "$system_root/var/log/adl"
|
|
119
|
+
|
|
120
|
+
echo "adl setup: first reconcile for $host (owner $owner)"
|
|
121
|
+
reconcile_rc=0
|
|
122
|
+
"$adl_bin" reconcile --host "$host" || reconcile_rc=$?
|
|
123
|
+
if [[ "$reconcile_rc" -ne 0 ]]; then
|
|
124
|
+
echo "ERROR adl setup: first reconcile failed (exit $reconcile_rc); scheduler NOT armed. Fix the failure and re-run: sudo adl setup --host $host" >&2
|
|
125
|
+
exit "$reconcile_rc"
|
|
126
|
+
fi
|
|
127
|
+
|
|
128
|
+
case "$fleet_host_platform" in
|
|
129
|
+
mac)
|
|
130
|
+
mkdir -p "$launch_daemons_dir"
|
|
131
|
+
plist="$launch_daemons_dir/com.adl.global-tools.plist"
|
|
132
|
+
{
|
|
133
|
+
printf '%s\n' '<?xml version="1.0" encoding="UTF-8"?>'
|
|
134
|
+
printf '%s\n' '<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">'
|
|
135
|
+
printf '%s\n' '<plist version="1.0"><dict>'
|
|
136
|
+
printf '%s\n' '<key>Label</key><string>com.adl.global-tools</string>'
|
|
137
|
+
printf '%s\n' '<key>ProgramArguments</key><array>'
|
|
138
|
+
printf '<string>%s</string>\n' "$adl_bin"
|
|
139
|
+
printf '%s\n' '<string>reconcile</string>'
|
|
140
|
+
printf '<string>--host</string><string>%s</string>\n' "$host"
|
|
141
|
+
printf '%s\n' '</array>'
|
|
142
|
+
printf '%s\n' '<key>StartCalendarInterval</key><array>'
|
|
143
|
+
for hour in 0 12; do printf '<dict><key>Hour</key><integer>%s</integer><key>Minute</key><integer>%s</integer></dict>\n' "$hour" "$minute"; done
|
|
144
|
+
printf '%s\n' '</array><key>ProcessType</key><string>Background</string>'
|
|
145
|
+
printf '%s\n' '<key>StandardOutPath</key><string>/var/log/adl/stdout.log</string>'
|
|
146
|
+
printf '%s\n' '<key>StandardErrorPath</key><string>/var/log/adl/stderr.log</string>'
|
|
147
|
+
printf '%s\n' '</dict></plist>'
|
|
148
|
+
} >"$plist"
|
|
149
|
+
chown root:wheel "$plist"
|
|
150
|
+
chmod 0644 "$plist"
|
|
151
|
+
plutil -lint "$plist"
|
|
152
|
+
# bootout fails when the job is not loaded, so ask first instead of
|
|
153
|
+
# swallowing the error: a bootout that fails on a loaded job must stop us.
|
|
154
|
+
if launchctl print system/com.adl.global-tools >/dev/null 2>&1; then
|
|
155
|
+
launchctl bootout system/com.adl.global-tools
|
|
156
|
+
# bootout returns before launchd has finished unloading, and a
|
|
157
|
+
# bootstrap in that window fails with an I/O error. Wait until the
|
|
158
|
+
# label is really gone, bounded, and fail loud if it is not.
|
|
159
|
+
unloaded=0
|
|
160
|
+
for _ in 1 2 3 4 5 6 7 8 9 10; do
|
|
161
|
+
if ! launchctl print system/com.adl.global-tools >/dev/null 2>&1; then unloaded=1; break; fi
|
|
162
|
+
sleep 0.5
|
|
163
|
+
done
|
|
164
|
+
[[ "$unloaded" -eq 1 ]] || {
|
|
165
|
+
echo "ERROR adl setup: com.adl.global-tools is still loaded after bootout (waited 5s); not bootstrapping. Run: sudo launchctl bootout system/com.adl.global-tools" >&2
|
|
166
|
+
exit 1
|
|
167
|
+
}
|
|
168
|
+
fi
|
|
169
|
+
launchctl bootstrap system "$plist"
|
|
170
|
+
;;
|
|
171
|
+
linux)
|
|
172
|
+
mkdir -p "$systemd_dir"
|
|
173
|
+
cat > "$systemd_dir/adl-global-tools.service" <<EOF
|
|
174
|
+
[Unit]
|
|
175
|
+
Description=Reconcile Adl global tools and repositories (adl reconcile)
|
|
176
|
+
After=network-online.target
|
|
177
|
+
Wants=network-online.target
|
|
178
|
+
|
|
179
|
+
[Service]
|
|
180
|
+
Type=oneshot
|
|
181
|
+
ExecStart=$adl_bin reconcile --host $host
|
|
182
|
+
StandardOutput=append:/var/log/adl/stdout.log
|
|
183
|
+
StandardError=append:/var/log/adl/stderr.log
|
|
184
|
+
Nice=10
|
|
185
|
+
IOSchedulingClass=best-effort
|
|
186
|
+
IOSchedulingPriority=7
|
|
187
|
+
TimeoutStartSec=3h
|
|
188
|
+
EOF
|
|
189
|
+
cat > "$systemd_dir/adl-global-tools.timer" <<EOF
|
|
190
|
+
[Unit]
|
|
191
|
+
Description=Run Adl global-tool reconciliation every 12 hours
|
|
192
|
+
|
|
193
|
+
[Timer]
|
|
194
|
+
OnCalendar=*-*-* 00,12:$minute:00
|
|
195
|
+
Persistent=true
|
|
196
|
+
Unit=adl-global-tools.service
|
|
197
|
+
|
|
198
|
+
[Install]
|
|
199
|
+
WantedBy=timers.target
|
|
200
|
+
EOF
|
|
201
|
+
systemctl daemon-reload
|
|
202
|
+
systemctl enable --now adl-global-tools.timer
|
|
203
|
+
# enable --now leaves an already-active timer on its old schedule.
|
|
204
|
+
systemctl restart adl-global-tools.timer
|
|
205
|
+
;;
|
|
206
|
+
esac
|
|
207
|
+
|
|
208
|
+
# The job used to run a copy of bin/sync-and-reconcile installed here. Its
|
|
209
|
+
# definition now points at the package's adl, so the copy is dead weight that
|
|
210
|
+
# would keep running stale update logic if anyone invoked it.
|
|
211
|
+
if [[ -e "$legacy_adl_sync" ]]; then
|
|
212
|
+
rm -f -- "$legacy_adl_sync"
|
|
213
|
+
echo "adl setup: removed the legacy scheduler copy $legacy_adl_sync"
|
|
214
|
+
fi
|
|
215
|
+
|
|
216
|
+
echo "adl setup: $host reconciled and armed (every 12 hours at minute $minute); run on demand with: sudo adl reconcile --host $host"
|
package/bin/sync-and-reconcile
CHANGED
|
@@ -13,14 +13,14 @@ sync_and_reconcile_platform() {
|
|
|
13
13
|
case "$(uname -s)" in
|
|
14
14
|
Darwin) printf '%s\n' mac ;;
|
|
15
15
|
Linux) printf '%s\n' linux ;;
|
|
16
|
-
*) echo "unsupported operating system for scheduled sync: $(uname -s)" >&2; return 1 ;;
|
|
16
|
+
*) echo "ERROR unsupported operating system for scheduled sync: $(uname -s)" >&2; return 1 ;;
|
|
17
17
|
esac
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
require_linux_automation_root() {
|
|
21
21
|
local platform="$1" owner="$2"
|
|
22
22
|
if [[ "$platform" == linux && "$owner" != root ]]; then
|
|
23
|
-
echo "global-tools: Linux scheduled sync must run as root; got --owner $owner" >&2
|
|
23
|
+
echo "ERROR global-tools: Linux scheduled sync must run as root; got --owner $owner" >&2
|
|
24
24
|
return 1
|
|
25
25
|
fi
|
|
26
26
|
}
|
|
@@ -35,7 +35,7 @@ parse_sync_source() {
|
|
|
35
35
|
done
|
|
36
36
|
case "$sync_source" in
|
|
37
37
|
npm|checkout) ;;
|
|
38
|
-
*) echo "unsupported source: $sync_source" >&2; return 2 ;;
|
|
38
|
+
*) echo "ERROR unsupported source: $sync_source" >&2; return 2 ;;
|
|
39
39
|
esac
|
|
40
40
|
}
|
|
41
41
|
|
|
@@ -45,12 +45,12 @@ npm_package_spec() {
|
|
|
45
45
|
latest-stable) printf '%s@latest\n' '@amsterdamdatalabs/adl-agent-control' ;;
|
|
46
46
|
pinned)
|
|
47
47
|
[[ "$version" =~ ^[0-9]+\.[0-9]+\.[0-9]+([-.][0-9A-Za-z.-]+)?$ ]] || {
|
|
48
|
-
echo "pinned update_policy requires a valid installed package version" >&2
|
|
48
|
+
echo "ERROR pinned update_policy requires a valid installed package version" >&2
|
|
49
49
|
return 1
|
|
50
50
|
}
|
|
51
51
|
printf '%s@%s\n' '@amsterdamdatalabs/adl-agent-control' "$version"
|
|
52
52
|
;;
|
|
53
|
-
*) echo "unsupported update_policy: $policy" >&2; return 1 ;;
|
|
53
|
+
*) echo "ERROR unsupported update_policy: $policy" >&2; return 1 ;;
|
|
54
54
|
esac
|
|
55
55
|
}
|
|
56
56
|
|
|
@@ -59,9 +59,33 @@ npm_platform_package_dir() {
|
|
|
59
59
|
case "$os:$arch" in
|
|
60
60
|
Darwin:arm64) platform=darwin-arm64 ;;
|
|
61
61
|
Linux:x86_64) platform=linux-x64 ;;
|
|
62
|
-
*) echo "unsupported platform for npm package: $os $arch" >&2; return 1 ;;
|
|
62
|
+
*) echo "ERROR unsupported platform for npm package: $os $arch" >&2; return 1 ;;
|
|
63
63
|
esac
|
|
64
|
-
|
|
64
|
+
# A global install nests optionalDependencies under the wrapper; npm never
|
|
65
|
+
# hoists them to the global root.
|
|
66
|
+
printf '%s/@amsterdamdatalabs/adl-agent-control/node_modules/@amsterdamdatalabs/adl-agent-control-%s\n' "${npm_root%/}" "$platform"
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
# Sets the `npm_env` array the owner's npm runs under: the same PATH and, on
|
|
70
|
+
# Linux, the same /usr/local prefix for every npm call this job makes. bin/setup
|
|
71
|
+
# sources this file and uses npm_global_root below, so it asks npm the very
|
|
72
|
+
# same question the scheduled job does.
|
|
73
|
+
resolve_npm_env() {
|
|
74
|
+
local os="$1" npm_path
|
|
75
|
+
case "$os" in
|
|
76
|
+
Darwin) npm_path=/opt/homebrew/bin:/usr/bin:/bin ;;
|
|
77
|
+
Linux) npm_path=/home/linuxbrew/.linuxbrew/bin:/usr/bin:/bin ;;
|
|
78
|
+
*) echo "ERROR unsupported operating system for npm package: $os" >&2; return 1 ;;
|
|
79
|
+
esac
|
|
80
|
+
npm_env=(PATH="$npm_path")
|
|
81
|
+
if [[ "$os" == Linux ]]; then npm_env=(npm_config_prefix=/usr/local PATH="$npm_path"); fi
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
# Prints OWNER's global npm root (`npm root -g` as that user, under npm_env).
|
|
85
|
+
npm_global_root() {
|
|
86
|
+
local owner="$1" os="$2"
|
|
87
|
+
resolve_npm_env "$os" || return 1
|
|
88
|
+
sudo -u "$owner" -H env "${npm_env[@]}" npm root -g
|
|
65
89
|
}
|
|
66
90
|
|
|
67
91
|
prepare_adl_npm_migration() {
|
|
@@ -72,7 +96,7 @@ prepare_adl_npm_migration() {
|
|
|
72
96
|
previous_executable="$(jq -r --arg platform "$platform" --arg device "$device" '(.[$platform].common.tools // {}) * (.[$platform].devices[$device].tools // {}) | .adl.executable // empty' "$applied_manifest")" || return 1
|
|
73
97
|
[[ "$previous_manager" == bun-compile && "$previous_executable" == /usr/local/bin/adl ]] || return 0
|
|
74
98
|
[[ -f "$legacy_adl" && ! -L "$legacy_adl" ]] || {
|
|
75
|
-
echo "prior manifest proves adl was a Bun binary, but the expected regular file is missing or is a symlink: $legacy_adl" >&2
|
|
99
|
+
echo "ERROR prior manifest proves adl was a Bun binary, but the expected regular file is missing or is a symlink: $legacy_adl" >&2
|
|
76
100
|
return 1
|
|
77
101
|
}
|
|
78
102
|
rm -f -- "$legacy_adl"
|
|
@@ -96,39 +120,37 @@ while [[ "$#" -gt 0 ]]; do
|
|
|
96
120
|
--repo) repo="${2:-}"; shift 2 ;;
|
|
97
121
|
--owner) owner="${2:-}"; shift 2 ;;
|
|
98
122
|
--mode) mode="${2:-}"; shift 2 ;;
|
|
99
|
-
*) echo "unknown argument: $1" >&2; exit 2 ;;
|
|
123
|
+
*) echo "ERROR unknown argument: $1" >&2; exit 2 ;;
|
|
100
124
|
esac
|
|
101
125
|
done
|
|
102
126
|
case "$sync_source" in
|
|
103
127
|
npm|checkout) ;;
|
|
104
|
-
*) echo "unsupported source: $sync_source" >&2; exit 2 ;;
|
|
128
|
+
*) echo "ERROR unsupported source: $sync_source" >&2; exit 2 ;;
|
|
105
129
|
esac
|
|
106
130
|
[[ -n "$device" && -n "$owner" ]] || {
|
|
107
|
-
echo "usage: sync-and-reconcile [--source npm|checkout] --device NAME --owner USER [--repo PATH] [--mode audit|plan|apply]" >&2
|
|
131
|
+
echo "ERROR usage: sync-and-reconcile [--source npm|checkout] --device NAME --owner USER [--repo PATH] [--mode audit|plan|apply]" >&2
|
|
108
132
|
exit 2
|
|
109
133
|
}
|
|
110
134
|
[[ "$mode" == audit || "$mode" == plan || "$mode" == apply ]] || {
|
|
111
|
-
echo "unsupported reconcile mode: $mode" >&2
|
|
135
|
+
echo "ERROR unsupported reconcile mode: $mode" >&2
|
|
112
136
|
exit 2
|
|
113
137
|
}
|
|
114
138
|
if [[ "$sync_source" == checkout && -z "$repo" ]]; then
|
|
115
|
-
echo "checkout source requires --repo PATH" >&2
|
|
139
|
+
echo "ERROR checkout source requires --repo PATH" >&2
|
|
116
140
|
exit 2
|
|
117
141
|
fi
|
|
118
142
|
if [[ "$sync_source" == npm && -n "$repo" ]]; then
|
|
119
|
-
echo "npm source does not accept --repo; use --source checkout for a checkout path" >&2
|
|
143
|
+
echo "ERROR npm source does not accept --repo; use --source checkout for a checkout path" >&2
|
|
120
144
|
exit 2
|
|
121
145
|
fi
|
|
122
146
|
|
|
123
147
|
if [[ -n "${SYNC_AND_RECONCILE_TEST_ROOT:-}" ]]; then
|
|
124
148
|
lock_dir="${SYNC_AND_RECONCILE_TEST_ROOT%/}/adl-sync.lock"
|
|
125
|
-
scheduler_path="${SYNC_AND_RECONCILE_TEST_ROOT%/}/scheduler"
|
|
126
149
|
else
|
|
127
150
|
lock_dir=/var/run/adl-sync.lock
|
|
128
|
-
scheduler_path=/usr/local/libexec/adl-sync
|
|
129
151
|
fi
|
|
130
152
|
if ! mkdir "$lock_dir" 2>/dev/null; then
|
|
131
|
-
echo "global-tools: another reconciliation is running (lock: $lock_dir)" >&2
|
|
153
|
+
echo "ERROR global-tools: another reconciliation is running (lock: $lock_dir)" >&2
|
|
132
154
|
exit 1
|
|
133
155
|
fi
|
|
134
156
|
trap 'rmdir "$lock_dir" 2>/dev/null || true' EXIT
|
|
@@ -137,28 +159,22 @@ host_platform="$(sync_and_reconcile_platform)"
|
|
|
137
159
|
require_linux_automation_root "$host_platform" "$owner" || exit 1
|
|
138
160
|
|
|
139
161
|
if [[ "$sync_source" == checkout ]]; then
|
|
140
|
-
[[ -e "$repo/.git" ]] || { echo "developer checkout missing: $repo" >&2; exit 1; }
|
|
162
|
+
[[ -e "$repo/.git" ]] || { echo "ERROR developer checkout missing: $repo" >&2; exit 1; }
|
|
141
163
|
manifest="$repo/packages/fleet/manifest.json"
|
|
142
|
-
[[ -f "$manifest" ]] || { echo "developer checkout manifest missing: $manifest" >&2; exit 1; }
|
|
143
|
-
[[ -x "$repo/bin/reconcile" ]] || { echo "developer checkout reconcile is missing: $repo/bin/reconcile" >&2; exit 1; }
|
|
164
|
+
[[ -f "$manifest" ]] || { echo "ERROR developer checkout manifest missing: $manifest" >&2; exit 1; }
|
|
165
|
+
[[ -x "$repo/bin/reconcile" ]] || { echo "ERROR developer checkout reconcile is missing: $repo/bin/reconcile" >&2; exit 1; }
|
|
144
166
|
echo "global-tools: source=checkout (developer mode)"
|
|
145
167
|
reconcile_dir="$repo/bin"
|
|
146
168
|
else
|
|
147
169
|
os="$(uname -s)"
|
|
148
170
|
arch="$(uname -m)"
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
*) echo "unsupported operating system for npm package: $os" >&2; exit 1 ;;
|
|
153
|
-
esac
|
|
154
|
-
npm_env=(PATH="$npm_path")
|
|
155
|
-
if [[ "$os" == Linux ]]; then npm_env=(npm_config_prefix=/usr/local PATH="$npm_path"); fi
|
|
156
|
-
npm_root="$(sudo -u "$owner" -H env "${npm_env[@]}" npm root -g)" || {
|
|
157
|
-
echo "cannot resolve the global npm root as $owner" >&2
|
|
171
|
+
resolve_npm_env "$os" || exit 1
|
|
172
|
+
npm_root="$(npm_global_root "$owner" "$os")" || {
|
|
173
|
+
echo "ERROR cannot resolve the global npm root as $owner" >&2
|
|
158
174
|
exit 1
|
|
159
175
|
}
|
|
160
176
|
[[ "$npm_root" == /*/lib/node_modules ]] || {
|
|
161
|
-
echo "global npm root has an unsupported path: $npm_root" >&2
|
|
177
|
+
echo "ERROR global npm root has an unsupported path: $npm_root" >&2
|
|
162
178
|
exit 1
|
|
163
179
|
}
|
|
164
180
|
npm_prefix="${npm_root%/lib/node_modules}"
|
|
@@ -167,14 +183,14 @@ else
|
|
|
167
183
|
package_spec=""
|
|
168
184
|
if [[ -f "$installed_manifest" ]]; then
|
|
169
185
|
update_policy="$(jq -er '.config.update_policy | select(type == "string")' "$installed_manifest")" || {
|
|
170
|
-
echo "installed adl package manifest has no config.update_policy: $installed_manifest" >&2
|
|
186
|
+
echo "ERROR installed adl package manifest has no config.update_policy: $installed_manifest" >&2
|
|
171
187
|
exit 1
|
|
172
188
|
}
|
|
173
189
|
case "$update_policy" in
|
|
174
190
|
latest-stable) package_spec="$(npm_package_spec latest-stable)" ;;
|
|
175
191
|
pinned)
|
|
176
192
|
pinned_version="$(jq -er --arg platform "$host_platform" '.[$platform].common.tools.adl.version | select(type == "string")' "$installed_manifest")" || {
|
|
177
|
-
echo "installed adl package manifest requires a version for pinned update_policy: $installed_manifest" >&2
|
|
193
|
+
echo "ERROR installed adl package manifest requires a version for pinned update_policy: $installed_manifest" >&2
|
|
178
194
|
exit 1
|
|
179
195
|
}
|
|
180
196
|
package_spec="$(npm_package_spec pinned "$pinned_version")" || exit 1
|
|
@@ -199,15 +215,12 @@ else
|
|
|
199
215
|
prepare_adl_npm_migration "$applied_manifest" "$device" "$host_platform" "$legacy_adl" "$legacy_hash"
|
|
200
216
|
|
|
201
217
|
sudo -u "$owner" -H env "${npm_env[@]}" npm install --global --prefix "$npm_prefix" --no-audit --no-fund "$package_spec"
|
|
202
|
-
[[ -d "$platform_dir" ]] || { echo "npm install did not create the platform package: $platform_dir" >&2; exit 1; }
|
|
218
|
+
[[ -d "$platform_dir" ]] || { echo "ERROR npm install did not create the platform package: $platform_dir" >&2; exit 1; }
|
|
203
219
|
installed_manifest="$platform_dir/packages/fleet/manifest.json"
|
|
204
|
-
[[ -f "$installed_manifest" ]] || { echo "installed adl package manifest missing: $installed_manifest" >&2; exit 1; }
|
|
205
|
-
[[ -x "$platform_dir/bin/reconcile" ]] || { echo "installed adl package reconcile is missing: $platform_dir/bin/reconcile" >&2; exit 1; }
|
|
206
|
-
[[ -x "$platform_dir/bin/
|
|
207
|
-
[[ -x "$platform_dir/bin/validate-manifest" ]] || { echo "installed adl package manifest validator is missing: $platform_dir/bin/validate-manifest" >&2; exit 1; }
|
|
220
|
+
[[ -f "$installed_manifest" ]] || { echo "ERROR installed adl package manifest missing: $installed_manifest" >&2; exit 1; }
|
|
221
|
+
[[ -x "$platform_dir/bin/reconcile" ]] || { echo "ERROR installed adl package reconcile is missing: $platform_dir/bin/reconcile" >&2; exit 1; }
|
|
222
|
+
[[ -x "$platform_dir/bin/validate-manifest" ]] || { echo "ERROR installed adl package manifest validator is missing: $platform_dir/bin/validate-manifest" >&2; exit 1; }
|
|
208
223
|
"$platform_dir/bin/validate-manifest" "$installed_manifest"
|
|
209
|
-
install -m 0755 "$platform_dir/bin/sync-and-reconcile" "$scheduler_path.new"
|
|
210
|
-
mv "$scheduler_path.new" "$scheduler_path"
|
|
211
224
|
reconcile_dir="$platform_dir/bin"
|
|
212
225
|
fi
|
|
213
226
|
|
package/bin/validate-manifest
CHANGED
|
@@ -15,7 +15,7 @@ if ! jq -e '
|
|
|
15
15
|
.config.schema == 1 and
|
|
16
16
|
(.config.repository | type == "string" and test("^https://dev\\.azure\\.com/[A-Za-z0-9._-]+/[A-Za-z0-9._-]+/_git/[A-Za-z0-9._-]+$")) and
|
|
17
17
|
.config.branch == "main" and
|
|
18
|
-
.config.interval_seconds ==
|
|
18
|
+
.config.interval_seconds == 43200 and
|
|
19
19
|
.config.update_policy == "latest-stable" and
|
|
20
20
|
.config.allow_major_updates == true and
|
|
21
21
|
.config.remove_deleted_entries == true and
|
|
@@ -43,28 +43,21 @@ if ! jq -e '
|
|
|
43
43
|
all(.minimum_free_gib >= 1) and
|
|
44
44
|
all((.home | type) == "string" and (.home | startswith("/"))) and
|
|
45
45
|
all((.default_agent | type) == "string" and (.default_agent | test("^agent-[a-z0-9-]+$"))) and
|
|
46
|
-
all((keys - ["administrator", "default_agent", "home", "
|
|
46
|
+
all((keys - ["administrator", "default_agent", "home", "minimum_free_gib", "schedule_minute", "scratch_repos", "brew_upgrade_all", "surface_clis", "repo_location", "tools"] | length) == 0) and
|
|
47
47
|
all((.scratch_repos // []) | type == "array" and (. | unique | length) == length and
|
|
48
48
|
all(type == "string" and startswith("/") and . != "/" and
|
|
49
49
|
(endswith("/") | not) and (contains("..") | not) and (test("\\s") | not))) and
|
|
50
|
-
#
|
|
51
|
-
# repositories
|
|
52
|
-
#
|
|
53
|
-
#
|
|
54
|
-
#
|
|
55
|
-
#
|
|
56
|
-
#
|
|
57
|
-
#
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
# point of actual use (jobs/git-maintain/src/main.ts,
|
|
62
|
-
# isForbiddenAzurePipelinesPath) -- this schema check alone only ever
|
|
63
|
-
# sees the manifest literal string, never what a symlink resolves to.
|
|
64
|
-
all((.git_maintain_repos // []) | type == "array" and (. | unique | length) == length and
|
|
65
|
-
all(type == "string" and startswith("/") and . != "/" and
|
|
66
|
-
(endswith("/") | not) and (contains("..") | not) and (test("\\s") | not) and
|
|
67
|
-
(ascii_downcase | contains("azagent") | not) and (ascii_downcase | contains("vsts.agent") | not))) and
|
|
50
|
+
# repo_location (2026-09-30): the ONE directory `adl reconcile` maintains
|
|
51
|
+
# repositories under (immediate children carrying adl-config.toml only). It
|
|
52
|
+
# is the whole scope of that step, so it must be an exact absolute directory
|
|
53
|
+
# path: never "/", no trailing slash, no "..", no whitespace. The
|
|
54
|
+
# azagent/vsts.agent substring bans keep it off Azure Pipelines agent
|
|
55
|
+
# installs (case-insensitively -- a value could be typed AzAgent2 as easily
|
|
56
|
+
# as azagent2); the maintenance step refuses the same names again, by
|
|
57
|
+
# realpath too, at the point of use.
|
|
58
|
+
all((.repo_location // "/ok") | type == "string" and startswith("/") and . != "/" and
|
|
59
|
+
(endswith("/") | not) and (contains("..") | not) and (test("\\s") | not) and
|
|
60
|
+
(ascii_downcase | contains("azagent") | not) and (ascii_downcase | contains("vsts.agent") | not)) and
|
|
68
61
|
all((.brew_upgrade_all // false) | type == "boolean") and
|
|
69
62
|
all(
|
|
70
63
|
(.surface_clis // []) as $surfaces |
|
|
@@ -159,30 +152,8 @@ if ! jq -e '
|
|
|
159
152
|
((.allow_scripts // []) | type == "array" and
|
|
160
153
|
all(type == "string" and test("^(@[a-z0-9][a-z0-9._-]*/)?[a-z0-9][a-z0-9._-]*$")))
|
|
161
154
|
else true end)) and
|
|
162
|
-
|
|
163
|
-
([.linux.
|
|
164
|
-
(.mac.common.launch_agents["git-maintain"] as $job |
|
|
165
|
-
($job | type == "object") and
|
|
166
|
-
($job.repo_scope | type == "object" and keys == ["glob", "recursive", "root"] and
|
|
167
|
-
(.root | relpath) and .glob == "*" and .recursive == true) and
|
|
168
|
-
($job.environment | has("GIT_MAINTAIN_ROOT") | not) and
|
|
169
|
-
($job.environment | has("GIT_MAINTAIN_GLOB") | not)) and
|
|
170
|
-
([.mac.common.launch_agents, .mac.devices[].launch_agents] | map(. // {}) |
|
|
171
|
-
all(type == "object") and
|
|
172
|
-
([.[] | to_entries[] | .value] |
|
|
173
|
-
all(
|
|
174
|
-
type == "object" and
|
|
175
|
-
(keys - ["label", "source", "entry", "start_interval_seconds", "run_at_load", "environment", "log", "replaces", "repo_scope"] | length == 0) and
|
|
176
|
-
((.label | type) == "string" and (.label | test("^[A-Za-z0-9][A-Za-z0-9._-]*$"))) and
|
|
177
|
-
(.source | relpath) and
|
|
178
|
-
(.entry | relpath) and
|
|
179
|
-
((.start_interval_seconds | type) == "number" and .start_interval_seconds >= 60 and (.start_interval_seconds | floor) == .start_interval_seconds) and
|
|
180
|
-
((.run_at_load | type) == "boolean") and
|
|
181
|
-
((.environment | type) == "object" and (.environment | to_entries | all((.key | test("^[A-Z_][A-Z0-9_]*$")) and (.value | type) == "string"))) and
|
|
182
|
-
(.log | relpath) and
|
|
183
|
-
((.replaces // []) | type == "array" and all(relpath))
|
|
184
|
-
) and
|
|
185
|
-
(map(.label) | length == (unique | length))))
|
|
155
|
+
# launch_agents are gone (2026-09-30): a stale declaration must fail loud.
|
|
156
|
+
([.mac.common, .linux.common] | all(keys - ["os_upgrade", "tools"] | length == 0))
|
|
186
157
|
' "$manifest" >/dev/null; then
|
|
187
158
|
echo "global-tools manifest: INVALID ($manifest does not satisfy bin/validate-manifest's schema)" >&2
|
|
188
159
|
exit 1
|
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.12",
|
|
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": [
|
|
@@ -14,8 +14,6 @@
|
|
|
14
14
|
"packages/fleet/manifest.json",
|
|
15
15
|
"packages/fleet/manifest.schema.json",
|
|
16
16
|
"packages/fleet/src",
|
|
17
|
-
"packages/fleet/jobs",
|
|
18
|
-
"packages/fleet/systemd",
|
|
19
17
|
"packages/agent-settings/surface-policy.json",
|
|
20
18
|
"packages/agent-settings/protected.json",
|
|
21
19
|
"packages/agent-settings/src",
|
|
@@ -8,8 +8,7 @@
|
|
|
8
8
|
"start": "bun src/main.ts",
|
|
9
9
|
"build": "bun ../../workflows/scripts/build/agent-hooks/build.ts",
|
|
10
10
|
"typecheck": "tsc --noEmit",
|
|
11
|
-
"test": "bun test --timeout 30000",
|
|
12
|
-
"test:coverage": "bun test --coverage --timeout 30000",
|
|
11
|
+
"test": "bun test --coverage --timeout 30000",
|
|
13
12
|
"check": "bun run typecheck && bun test --coverage"
|
|
14
13
|
},
|
|
15
14
|
"dependencies": {
|