@osfactory/har 0.49.2 → 0.50.0
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/dist/index.js +82 -46
- package/dist/templates/adaptation-prompt-init.md +5 -0
- package/dist/templates/adaptation-prompt-maintain.md +1 -1
- package/dist/templates/har-boilerplate/agent-cli.sh +7 -6
- package/dist/templates/har-boilerplate/agent-slot.sh +1 -1
- package/dist/templates/har-boilerplate/harness.env +117 -0
- package/dist/templates/har-boilerplate/launch.sh +3 -3
- package/dist/templates/har-boilerplate/provision-toolchain.sh +136 -15
- package/dist/templates/har-boilerplate/setup-infra.sh +1 -1
- package/dist/templates/har-boilerplate/teardown.sh +1 -1
- package/dist/templates/har-boilerplate-cli/agent-slot.sh +1 -1
- package/dist/templates/har-boilerplate-cli/harness.env +117 -0
- package/dist/templates/har-boilerplate-cli/launch.sh +3 -2
- package/dist/templates/har-boilerplate-cli/provision-toolchain.sh +136 -15
- package/dist/templates/har-boilerplate-cli/setup-infra.sh +1 -1
- package/dist/templates/har-boilerplate-ios/harness.env +117 -0
- package/dist/templates/har-boilerplate-ios/provision-toolchain.sh +136 -15
- package/package.json +1 -1
|
@@ -27,6 +27,119 @@ pt_log() {
|
|
|
27
27
|
fi
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
+
# ── Node package manager helpers ──────────────────────────────────────────────
|
|
31
|
+
# Mirrored verbatim in harness.env and provision-toolchain.sh so a sourcing
|
|
32
|
+
# script and the provisioning subprocess resolve the same tool.
|
|
33
|
+
|
|
34
|
+
# Package managers HAR can drive, in fallback preference order.
|
|
35
|
+
HAR_NODE_PACKAGE_MANAGERS="npm bun pnpm yarn"
|
|
36
|
+
|
|
37
|
+
# Package manager the repo declares: an explicit HARNESS_NODE_PACKAGE_MANAGER
|
|
38
|
+
# wins, then package.json "packageManager", then the lockfile. Empty when the
|
|
39
|
+
# repo says nothing.
|
|
40
|
+
har_node_declared_package_manager() {
|
|
41
|
+
local dir="${1:-.}"
|
|
42
|
+
|
|
43
|
+
if [ -n "${HARNESS_NODE_PACKAGE_MANAGER:-}" ]; then
|
|
44
|
+
echo "$HARNESS_NODE_PACKAGE_MANAGER"
|
|
45
|
+
return
|
|
46
|
+
fi
|
|
47
|
+
if [ -f "$dir/package.json" ]; then
|
|
48
|
+
local field
|
|
49
|
+
field="$(sed -n 's/.*"packageManager"[[:space:]]*:[[:space:]]*"\([a-z]*\)@.*/\1/p' "$dir/package.json" | head -1)"
|
|
50
|
+
if [ -n "$field" ]; then
|
|
51
|
+
echo "$field"
|
|
52
|
+
return
|
|
53
|
+
fi
|
|
54
|
+
fi
|
|
55
|
+
if [ -f "$dir/bun.lock" ] || [ -f "$dir/bun.lockb" ]; then echo bun; return; fi
|
|
56
|
+
if [ -f "$dir/pnpm-lock.yaml" ]; then echo pnpm; return; fi
|
|
57
|
+
if [ -f "$dir/yarn.lock" ]; then echo yarn; return; fi
|
|
58
|
+
if [ -f "$dir/package-lock.json" ]; then echo npm; return; fi
|
|
59
|
+
echo ""
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
# Package manager to actually run. A manager the repo declares but this machine
|
|
63
|
+
# lacks falls back to one that is installed, so a repo pinned to npm still
|
|
64
|
+
# provisions on a bun-only machine (and the reverse).
|
|
65
|
+
har_node_package_manager() {
|
|
66
|
+
local dir="${1:-.}"
|
|
67
|
+
local declared
|
|
68
|
+
declared="$(har_node_declared_package_manager "$dir")"
|
|
69
|
+
|
|
70
|
+
if [ -n "$declared" ] && command -v "$declared" >/dev/null 2>&1; then
|
|
71
|
+
echo "$declared"
|
|
72
|
+
return
|
|
73
|
+
fi
|
|
74
|
+
|
|
75
|
+
local candidate
|
|
76
|
+
for candidate in $HAR_NODE_PACKAGE_MANAGERS; do
|
|
77
|
+
if command -v "$candidate" >/dev/null 2>&1; then
|
|
78
|
+
echo "$candidate"
|
|
79
|
+
return
|
|
80
|
+
fi
|
|
81
|
+
done
|
|
82
|
+
|
|
83
|
+
echo "${declared:-npm}"
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
# Lockfile a manager writes, so a substitute install can clean up after itself.
|
|
87
|
+
har_node_lockfile() {
|
|
88
|
+
case "$1" in
|
|
89
|
+
bun) echo "bun.lock" ;;
|
|
90
|
+
npm) echo "package-lock.json" ;;
|
|
91
|
+
pnpm) echo "pnpm-lock.yaml" ;;
|
|
92
|
+
yarn) echo "yarn.lock" ;;
|
|
93
|
+
*) echo "" ;;
|
|
94
|
+
esac
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
# Install dependencies in a directory. When a substitute manager stands in for
|
|
98
|
+
# the one the repo declares, any lockfile it creates is removed afterwards:
|
|
99
|
+
# provisioning must not migrate the repo to a different package manager.
|
|
100
|
+
# (bun writes bun.lock even under --no-save, so the flags alone are not enough.)
|
|
101
|
+
har_node_install() {
|
|
102
|
+
local dir="$1"
|
|
103
|
+
local manager="$2"
|
|
104
|
+
local declared="${3:-}"
|
|
105
|
+
local substituting=false
|
|
106
|
+
local lockfile=""
|
|
107
|
+
local had_lockfile=false
|
|
108
|
+
|
|
109
|
+
if [ -n "$declared" ] && [ "$declared" != "$manager" ]; then
|
|
110
|
+
substituting=true
|
|
111
|
+
lockfile="$(har_node_lockfile "$manager")"
|
|
112
|
+
if [ -n "$lockfile" ] && [ -e "$dir/$lockfile" ]; then
|
|
113
|
+
had_lockfile=true
|
|
114
|
+
fi
|
|
115
|
+
fi
|
|
116
|
+
|
|
117
|
+
local code=0
|
|
118
|
+
(cd "$dir" && "$manager" install --silent) || code=$?
|
|
119
|
+
|
|
120
|
+
if [ "$substituting" = true ] && [ "$had_lockfile" = false ] && [ -n "$lockfile" ]; then
|
|
121
|
+
rm -f "$dir/$lockfile"
|
|
122
|
+
[ "$manager" = "bun" ] && rm -f "$dir/bun.lockb"
|
|
123
|
+
fi
|
|
124
|
+
return $code
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
# Package runner (npx equivalent) for one-off CLIs such as pm2, including the
|
|
128
|
+
# flag that keeps it non-interactive. Takes a manager name, or none to resolve
|
|
129
|
+
# from the environment and PATH.
|
|
130
|
+
har_pkg_exec() {
|
|
131
|
+
case "${1:-${HARNESS_NODE_PACKAGE_MANAGER:-}}" in
|
|
132
|
+
bun) echo "bunx"; return ;;
|
|
133
|
+
pnpm) echo "pnpm dlx"; return ;;
|
|
134
|
+
yarn) echo "yarn dlx"; return ;;
|
|
135
|
+
npm) echo "npx --yes"; return ;;
|
|
136
|
+
esac
|
|
137
|
+
if command -v npx >/dev/null 2>&1; then echo "npx --yes"; return; fi
|
|
138
|
+
if command -v bunx >/dev/null 2>&1; then echo "bunx"; return; fi
|
|
139
|
+
if command -v pnpm >/dev/null 2>&1; then echo "pnpm dlx"; return; fi
|
|
140
|
+
echo "npx --yes"
|
|
141
|
+
}
|
|
142
|
+
|
|
30
143
|
append_env() {
|
|
31
144
|
local key="$1"
|
|
32
145
|
local value="$2"
|
|
@@ -81,32 +194,37 @@ run_install_cmd() {
|
|
|
81
194
|
|
|
82
195
|
provision_node() {
|
|
83
196
|
local dir="$1"
|
|
84
|
-
local npm_bin="npm"
|
|
85
197
|
local node_bin="node"
|
|
198
|
+
local pkg_manager declared_manager
|
|
199
|
+
declared_manager="$(har_node_declared_package_manager "$dir")"
|
|
200
|
+
pkg_manager="$(har_node_package_manager "$dir")"
|
|
201
|
+
|
|
202
|
+
if [ -n "$declared_manager" ] && [ "$declared_manager" != "$pkg_manager" ]; then
|
|
203
|
+
pt_log "Repo declares ${declared_manager}, which is not on PATH — installing with ${pkg_manager} and leaving the lockfile untouched."
|
|
204
|
+
fi
|
|
86
205
|
|
|
87
206
|
if ! run_install_cmd "$dir"; then
|
|
88
|
-
pt_log "Installing Node dependencies..."
|
|
89
|
-
|
|
90
|
-
(cd "$dir" && pnpm install --silent)
|
|
91
|
-
npm_bin="pnpm"
|
|
92
|
-
elif [ -f "$dir/yarn.lock" ] && command -v yarn >/dev/null 2>&1; then
|
|
93
|
-
(cd "$dir" && yarn install --silent)
|
|
94
|
-
npm_bin="yarn"
|
|
95
|
-
else
|
|
96
|
-
(cd "$dir" && npm install --silent)
|
|
97
|
-
fi
|
|
207
|
+
pt_log "Installing Node dependencies with ${pkg_manager}..."
|
|
208
|
+
har_node_install "$dir" "$pkg_manager" "$declared_manager"
|
|
98
209
|
fi
|
|
99
210
|
|
|
100
211
|
if command -v node >/dev/null 2>&1; then
|
|
101
212
|
node_bin="$(command -v node)"
|
|
213
|
+
elif [ "$pkg_manager" = "bun" ]; then
|
|
214
|
+
# bun-only machine: bun runs the `node -e` snippets verify.sh relies on.
|
|
215
|
+
node_bin="$(command -v bun)"
|
|
102
216
|
fi
|
|
103
|
-
|
|
104
|
-
|
|
217
|
+
|
|
218
|
+
local npm_bin="$pkg_manager"
|
|
219
|
+
if command -v "$pkg_manager" >/dev/null 2>&1; then
|
|
220
|
+
npm_bin="$(command -v "$pkg_manager")"
|
|
105
221
|
fi
|
|
106
222
|
|
|
107
223
|
append_env "HARNESS_ECOSYSTEM" "node"
|
|
108
224
|
append_env "NODE_BIN" "$node_bin"
|
|
109
225
|
append_env "NPM_BIN" "$npm_bin"
|
|
226
|
+
append_env "HARNESS_NODE_PACKAGE_MANAGER" "$pkg_manager"
|
|
227
|
+
append_env "HARNESS_PKG_EXEC" "$(har_pkg_exec "$pkg_manager")"
|
|
110
228
|
append_path_prefix "$dir/node_modules/.bin"
|
|
111
229
|
}
|
|
112
230
|
|
|
@@ -252,8 +370,11 @@ provision_monorepo_root() {
|
|
|
252
370
|
[ -n "$HAR_WORKTREE_DIR" ] || return 0
|
|
253
371
|
[ -f "$HAR_WORKTREE_DIR/package.json" ] || return 0
|
|
254
372
|
[ -d "$HAR_WORKTREE_DIR/node_modules" ] && return 0
|
|
255
|
-
|
|
256
|
-
(
|
|
373
|
+
local pkg_manager
|
|
374
|
+
pkg_manager="$(har_node_package_manager "$HAR_WORKTREE_DIR")"
|
|
375
|
+
pt_log "Installing monorepo root dependencies in $HAR_WORKTREE_DIR with ${pkg_manager}..."
|
|
376
|
+
har_node_install "$HAR_WORKTREE_DIR" "$pkg_manager" \
|
|
377
|
+
"$(har_node_declared_package_manager "$HAR_WORKTREE_DIR")"
|
|
257
378
|
}
|
|
258
379
|
|
|
259
380
|
provision_ecosystem() {
|
|
@@ -165,7 +165,7 @@ fi
|
|
|
165
165
|
SHARED_ECOSYSTEM="$SCRIPT_DIR/ecosystem.shared.config.cjs"
|
|
166
166
|
if [ -f "$SHARED_ECOSYSTEM" ]; then
|
|
167
167
|
log "Starting shared app services from ecosystem.shared.config.cjs..."
|
|
168
|
-
(cd "$REPO_ROOT" &&
|
|
168
|
+
(cd "$REPO_ROOT" && $(har_pkg_exec) pm2 startOrReload "$SHARED_ECOSYSTEM" >/dev/null)
|
|
169
169
|
log "Shared app services running (pm2 ls | grep har-${HARNESS_PROJECT_NAME}-shared-)."
|
|
170
170
|
fi
|
|
171
171
|
|
|
@@ -41,7 +41,7 @@ fi
|
|
|
41
41
|
[ -n "$WORKTREE_PATH" ] || WORKTREE_PATH="$HOME/worktrees/${HARNESS_PROJECT_NAME}-agent-${AGENT_ID}"
|
|
42
42
|
|
|
43
43
|
PM2_REGEX="$(har_pm2_delete_regex "$AGENT_ID")"
|
|
44
|
-
|
|
44
|
+
$(har_pkg_exec) pm2 delete "$PM2_REGEX" 2>/dev/null || true
|
|
45
45
|
echo "✓ Stopped PM2 processes"
|
|
46
46
|
|
|
47
47
|
if har_infra_enabled db; then
|
|
@@ -164,7 +164,7 @@ har_check_foreign_pm2() {
|
|
|
164
164
|
local agent_id="$1"
|
|
165
165
|
local pm2_raw
|
|
166
166
|
har_harness_uses_pm2 || return 0
|
|
167
|
-
pm2_raw="$(
|
|
167
|
+
pm2_raw="$($(har_pkg_exec) pm2 jlist 2>/dev/null || true)"
|
|
168
168
|
[ -n "$pm2_raw" ] || return 0
|
|
169
169
|
set +e
|
|
170
170
|
echo "$pm2_raw" | node -e "
|
|
@@ -23,6 +23,10 @@ export HARNESS_AGENT_SLOT_MAX=3
|
|
|
23
23
|
export HARNESS_ECOSYSTEM="auto"
|
|
24
24
|
# Optional install override (eval in work dir after env file is created)
|
|
25
25
|
# export HARNESS_INSTALL_CMD="make deps"
|
|
26
|
+
# Node package manager: auto-detected from package.json "packageManager" and the
|
|
27
|
+
# lockfile (bun.lock → bun, pnpm-lock.yaml → pnpm, yarn.lock → yarn, else npm),
|
|
28
|
+
# falling back to whichever is installed. Set to pin one: npm | bun | pnpm | yarn
|
|
29
|
+
# export HARNESS_NODE_PACKAGE_MANAGER="bun"
|
|
26
30
|
|
|
27
31
|
# Shared infrastructure — space-separated docker compose service names from
|
|
28
32
|
# docker-compose.agent.yml, started ONCE by setup-infra.sh and shared by all
|
|
@@ -38,6 +42,119 @@ har_infra_enabled() {
|
|
|
38
42
|
esac
|
|
39
43
|
}
|
|
40
44
|
|
|
45
|
+
# ── Node package manager helpers ──────────────────────────────────────────────
|
|
46
|
+
# Mirrored verbatim in harness.env and provision-toolchain.sh so a sourcing
|
|
47
|
+
# script and the provisioning subprocess resolve the same tool.
|
|
48
|
+
|
|
49
|
+
# Package managers HAR can drive, in fallback preference order.
|
|
50
|
+
HAR_NODE_PACKAGE_MANAGERS="npm bun pnpm yarn"
|
|
51
|
+
|
|
52
|
+
# Package manager the repo declares: an explicit HARNESS_NODE_PACKAGE_MANAGER
|
|
53
|
+
# wins, then package.json "packageManager", then the lockfile. Empty when the
|
|
54
|
+
# repo says nothing.
|
|
55
|
+
har_node_declared_package_manager() {
|
|
56
|
+
local dir="${1:-.}"
|
|
57
|
+
|
|
58
|
+
if [ -n "${HARNESS_NODE_PACKAGE_MANAGER:-}" ]; then
|
|
59
|
+
echo "$HARNESS_NODE_PACKAGE_MANAGER"
|
|
60
|
+
return
|
|
61
|
+
fi
|
|
62
|
+
if [ -f "$dir/package.json" ]; then
|
|
63
|
+
local field
|
|
64
|
+
field="$(sed -n 's/.*"packageManager"[[:space:]]*:[[:space:]]*"\([a-z]*\)@.*/\1/p' "$dir/package.json" | head -1)"
|
|
65
|
+
if [ -n "$field" ]; then
|
|
66
|
+
echo "$field"
|
|
67
|
+
return
|
|
68
|
+
fi
|
|
69
|
+
fi
|
|
70
|
+
if [ -f "$dir/bun.lock" ] || [ -f "$dir/bun.lockb" ]; then echo bun; return; fi
|
|
71
|
+
if [ -f "$dir/pnpm-lock.yaml" ]; then echo pnpm; return; fi
|
|
72
|
+
if [ -f "$dir/yarn.lock" ]; then echo yarn; return; fi
|
|
73
|
+
if [ -f "$dir/package-lock.json" ]; then echo npm; return; fi
|
|
74
|
+
echo ""
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
# Package manager to actually run. A manager the repo declares but this machine
|
|
78
|
+
# lacks falls back to one that is installed, so a repo pinned to npm still
|
|
79
|
+
# provisions on a bun-only machine (and the reverse).
|
|
80
|
+
har_node_package_manager() {
|
|
81
|
+
local dir="${1:-.}"
|
|
82
|
+
local declared
|
|
83
|
+
declared="$(har_node_declared_package_manager "$dir")"
|
|
84
|
+
|
|
85
|
+
if [ -n "$declared" ] && command -v "$declared" >/dev/null 2>&1; then
|
|
86
|
+
echo "$declared"
|
|
87
|
+
return
|
|
88
|
+
fi
|
|
89
|
+
|
|
90
|
+
local candidate
|
|
91
|
+
for candidate in $HAR_NODE_PACKAGE_MANAGERS; do
|
|
92
|
+
if command -v "$candidate" >/dev/null 2>&1; then
|
|
93
|
+
echo "$candidate"
|
|
94
|
+
return
|
|
95
|
+
fi
|
|
96
|
+
done
|
|
97
|
+
|
|
98
|
+
echo "${declared:-npm}"
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
# Lockfile a manager writes, so a substitute install can clean up after itself.
|
|
102
|
+
har_node_lockfile() {
|
|
103
|
+
case "$1" in
|
|
104
|
+
bun) echo "bun.lock" ;;
|
|
105
|
+
npm) echo "package-lock.json" ;;
|
|
106
|
+
pnpm) echo "pnpm-lock.yaml" ;;
|
|
107
|
+
yarn) echo "yarn.lock" ;;
|
|
108
|
+
*) echo "" ;;
|
|
109
|
+
esac
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
# Install dependencies in a directory. When a substitute manager stands in for
|
|
113
|
+
# the one the repo declares, any lockfile it creates is removed afterwards:
|
|
114
|
+
# provisioning must not migrate the repo to a different package manager.
|
|
115
|
+
# (bun writes bun.lock even under --no-save, so the flags alone are not enough.)
|
|
116
|
+
har_node_install() {
|
|
117
|
+
local dir="$1"
|
|
118
|
+
local manager="$2"
|
|
119
|
+
local declared="${3:-}"
|
|
120
|
+
local substituting=false
|
|
121
|
+
local lockfile=""
|
|
122
|
+
local had_lockfile=false
|
|
123
|
+
|
|
124
|
+
if [ -n "$declared" ] && [ "$declared" != "$manager" ]; then
|
|
125
|
+
substituting=true
|
|
126
|
+
lockfile="$(har_node_lockfile "$manager")"
|
|
127
|
+
if [ -n "$lockfile" ] && [ -e "$dir/$lockfile" ]; then
|
|
128
|
+
had_lockfile=true
|
|
129
|
+
fi
|
|
130
|
+
fi
|
|
131
|
+
|
|
132
|
+
local code=0
|
|
133
|
+
(cd "$dir" && "$manager" install --silent) || code=$?
|
|
134
|
+
|
|
135
|
+
if [ "$substituting" = true ] && [ "$had_lockfile" = false ] && [ -n "$lockfile" ]; then
|
|
136
|
+
rm -f "$dir/$lockfile"
|
|
137
|
+
[ "$manager" = "bun" ] && rm -f "$dir/bun.lockb"
|
|
138
|
+
fi
|
|
139
|
+
return $code
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
# Package runner (npx equivalent) for one-off CLIs such as pm2, including the
|
|
143
|
+
# flag that keeps it non-interactive. Takes a manager name, or none to resolve
|
|
144
|
+
# from the environment and PATH.
|
|
145
|
+
har_pkg_exec() {
|
|
146
|
+
case "${1:-${HARNESS_NODE_PACKAGE_MANAGER:-}}" in
|
|
147
|
+
bun) echo "bunx"; return ;;
|
|
148
|
+
pnpm) echo "pnpm dlx"; return ;;
|
|
149
|
+
yarn) echo "yarn dlx"; return ;;
|
|
150
|
+
npm) echo "npx --yes"; return ;;
|
|
151
|
+
esac
|
|
152
|
+
if command -v npx >/dev/null 2>&1; then echo "npx --yes"; return; fi
|
|
153
|
+
if command -v bunx >/dev/null 2>&1; then echo "bunx"; return; fi
|
|
154
|
+
if command -v pnpm >/dev/null 2>&1; then echo "pnpm dlx"; return; fi
|
|
155
|
+
echo "npx --yes"
|
|
156
|
+
}
|
|
157
|
+
|
|
41
158
|
# Postgres client — uses host tools when installed, otherwise docker exec into
|
|
42
159
|
# the shared db container. Usage: har_pg psql -d postgres -c "SELECT 1"
|
|
43
160
|
har_pg() {
|
|
@@ -187,8 +187,9 @@ elif [ -f "$SCRIPT_DIR/provision-toolchain.sh" ]; then
|
|
|
187
187
|
HAR_AGENT_ID="$AGENT_ID" \
|
|
188
188
|
"$SCRIPT_DIR/provision-toolchain.sh"
|
|
189
189
|
elif [ -f "$WORK_DIR/package.json" ] && [ ! -d "$WORK_DIR/node_modules" ]; then
|
|
190
|
-
|
|
191
|
-
|
|
190
|
+
PKG_MANAGER="$(har_node_package_manager "$WORK_DIR")"
|
|
191
|
+
log "Installing dependencies in $WORK_DIR with ${PKG_MANAGER}..."
|
|
192
|
+
har_node_install "$WORK_DIR" "$PKG_MANAGER" "$(har_node_declared_package_manager "$WORK_DIR")"
|
|
192
193
|
fi
|
|
193
194
|
|
|
194
195
|
SLOT_AGENT_ID="$AGENT_ID" \
|
|
@@ -27,6 +27,119 @@ pt_log() {
|
|
|
27
27
|
fi
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
+
# ── Node package manager helpers ──────────────────────────────────────────────
|
|
31
|
+
# Mirrored verbatim in harness.env and provision-toolchain.sh so a sourcing
|
|
32
|
+
# script and the provisioning subprocess resolve the same tool.
|
|
33
|
+
|
|
34
|
+
# Package managers HAR can drive, in fallback preference order.
|
|
35
|
+
HAR_NODE_PACKAGE_MANAGERS="npm bun pnpm yarn"
|
|
36
|
+
|
|
37
|
+
# Package manager the repo declares: an explicit HARNESS_NODE_PACKAGE_MANAGER
|
|
38
|
+
# wins, then package.json "packageManager", then the lockfile. Empty when the
|
|
39
|
+
# repo says nothing.
|
|
40
|
+
har_node_declared_package_manager() {
|
|
41
|
+
local dir="${1:-.}"
|
|
42
|
+
|
|
43
|
+
if [ -n "${HARNESS_NODE_PACKAGE_MANAGER:-}" ]; then
|
|
44
|
+
echo "$HARNESS_NODE_PACKAGE_MANAGER"
|
|
45
|
+
return
|
|
46
|
+
fi
|
|
47
|
+
if [ -f "$dir/package.json" ]; then
|
|
48
|
+
local field
|
|
49
|
+
field="$(sed -n 's/.*"packageManager"[[:space:]]*:[[:space:]]*"\([a-z]*\)@.*/\1/p' "$dir/package.json" | head -1)"
|
|
50
|
+
if [ -n "$field" ]; then
|
|
51
|
+
echo "$field"
|
|
52
|
+
return
|
|
53
|
+
fi
|
|
54
|
+
fi
|
|
55
|
+
if [ -f "$dir/bun.lock" ] || [ -f "$dir/bun.lockb" ]; then echo bun; return; fi
|
|
56
|
+
if [ -f "$dir/pnpm-lock.yaml" ]; then echo pnpm; return; fi
|
|
57
|
+
if [ -f "$dir/yarn.lock" ]; then echo yarn; return; fi
|
|
58
|
+
if [ -f "$dir/package-lock.json" ]; then echo npm; return; fi
|
|
59
|
+
echo ""
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
# Package manager to actually run. A manager the repo declares but this machine
|
|
63
|
+
# lacks falls back to one that is installed, so a repo pinned to npm still
|
|
64
|
+
# provisions on a bun-only machine (and the reverse).
|
|
65
|
+
har_node_package_manager() {
|
|
66
|
+
local dir="${1:-.}"
|
|
67
|
+
local declared
|
|
68
|
+
declared="$(har_node_declared_package_manager "$dir")"
|
|
69
|
+
|
|
70
|
+
if [ -n "$declared" ] && command -v "$declared" >/dev/null 2>&1; then
|
|
71
|
+
echo "$declared"
|
|
72
|
+
return
|
|
73
|
+
fi
|
|
74
|
+
|
|
75
|
+
local candidate
|
|
76
|
+
for candidate in $HAR_NODE_PACKAGE_MANAGERS; do
|
|
77
|
+
if command -v "$candidate" >/dev/null 2>&1; then
|
|
78
|
+
echo "$candidate"
|
|
79
|
+
return
|
|
80
|
+
fi
|
|
81
|
+
done
|
|
82
|
+
|
|
83
|
+
echo "${declared:-npm}"
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
# Lockfile a manager writes, so a substitute install can clean up after itself.
|
|
87
|
+
har_node_lockfile() {
|
|
88
|
+
case "$1" in
|
|
89
|
+
bun) echo "bun.lock" ;;
|
|
90
|
+
npm) echo "package-lock.json" ;;
|
|
91
|
+
pnpm) echo "pnpm-lock.yaml" ;;
|
|
92
|
+
yarn) echo "yarn.lock" ;;
|
|
93
|
+
*) echo "" ;;
|
|
94
|
+
esac
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
# Install dependencies in a directory. When a substitute manager stands in for
|
|
98
|
+
# the one the repo declares, any lockfile it creates is removed afterwards:
|
|
99
|
+
# provisioning must not migrate the repo to a different package manager.
|
|
100
|
+
# (bun writes bun.lock even under --no-save, so the flags alone are not enough.)
|
|
101
|
+
har_node_install() {
|
|
102
|
+
local dir="$1"
|
|
103
|
+
local manager="$2"
|
|
104
|
+
local declared="${3:-}"
|
|
105
|
+
local substituting=false
|
|
106
|
+
local lockfile=""
|
|
107
|
+
local had_lockfile=false
|
|
108
|
+
|
|
109
|
+
if [ -n "$declared" ] && [ "$declared" != "$manager" ]; then
|
|
110
|
+
substituting=true
|
|
111
|
+
lockfile="$(har_node_lockfile "$manager")"
|
|
112
|
+
if [ -n "$lockfile" ] && [ -e "$dir/$lockfile" ]; then
|
|
113
|
+
had_lockfile=true
|
|
114
|
+
fi
|
|
115
|
+
fi
|
|
116
|
+
|
|
117
|
+
local code=0
|
|
118
|
+
(cd "$dir" && "$manager" install --silent) || code=$?
|
|
119
|
+
|
|
120
|
+
if [ "$substituting" = true ] && [ "$had_lockfile" = false ] && [ -n "$lockfile" ]; then
|
|
121
|
+
rm -f "$dir/$lockfile"
|
|
122
|
+
[ "$manager" = "bun" ] && rm -f "$dir/bun.lockb"
|
|
123
|
+
fi
|
|
124
|
+
return $code
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
# Package runner (npx equivalent) for one-off CLIs such as pm2, including the
|
|
128
|
+
# flag that keeps it non-interactive. Takes a manager name, or none to resolve
|
|
129
|
+
# from the environment and PATH.
|
|
130
|
+
har_pkg_exec() {
|
|
131
|
+
case "${1:-${HARNESS_NODE_PACKAGE_MANAGER:-}}" in
|
|
132
|
+
bun) echo "bunx"; return ;;
|
|
133
|
+
pnpm) echo "pnpm dlx"; return ;;
|
|
134
|
+
yarn) echo "yarn dlx"; return ;;
|
|
135
|
+
npm) echo "npx --yes"; return ;;
|
|
136
|
+
esac
|
|
137
|
+
if command -v npx >/dev/null 2>&1; then echo "npx --yes"; return; fi
|
|
138
|
+
if command -v bunx >/dev/null 2>&1; then echo "bunx"; return; fi
|
|
139
|
+
if command -v pnpm >/dev/null 2>&1; then echo "pnpm dlx"; return; fi
|
|
140
|
+
echo "npx --yes"
|
|
141
|
+
}
|
|
142
|
+
|
|
30
143
|
append_env() {
|
|
31
144
|
local key="$1"
|
|
32
145
|
local value="$2"
|
|
@@ -81,32 +194,37 @@ run_install_cmd() {
|
|
|
81
194
|
|
|
82
195
|
provision_node() {
|
|
83
196
|
local dir="$1"
|
|
84
|
-
local npm_bin="npm"
|
|
85
197
|
local node_bin="node"
|
|
198
|
+
local pkg_manager declared_manager
|
|
199
|
+
declared_manager="$(har_node_declared_package_manager "$dir")"
|
|
200
|
+
pkg_manager="$(har_node_package_manager "$dir")"
|
|
201
|
+
|
|
202
|
+
if [ -n "$declared_manager" ] && [ "$declared_manager" != "$pkg_manager" ]; then
|
|
203
|
+
pt_log "Repo declares ${declared_manager}, which is not on PATH — installing with ${pkg_manager} and leaving the lockfile untouched."
|
|
204
|
+
fi
|
|
86
205
|
|
|
87
206
|
if ! run_install_cmd "$dir"; then
|
|
88
|
-
pt_log "Installing Node dependencies..."
|
|
89
|
-
|
|
90
|
-
(cd "$dir" && pnpm install --silent)
|
|
91
|
-
npm_bin="pnpm"
|
|
92
|
-
elif [ -f "$dir/yarn.lock" ] && command -v yarn >/dev/null 2>&1; then
|
|
93
|
-
(cd "$dir" && yarn install --silent)
|
|
94
|
-
npm_bin="yarn"
|
|
95
|
-
else
|
|
96
|
-
(cd "$dir" && npm install --silent)
|
|
97
|
-
fi
|
|
207
|
+
pt_log "Installing Node dependencies with ${pkg_manager}..."
|
|
208
|
+
har_node_install "$dir" "$pkg_manager" "$declared_manager"
|
|
98
209
|
fi
|
|
99
210
|
|
|
100
211
|
if command -v node >/dev/null 2>&1; then
|
|
101
212
|
node_bin="$(command -v node)"
|
|
213
|
+
elif [ "$pkg_manager" = "bun" ]; then
|
|
214
|
+
# bun-only machine: bun runs the `node -e` snippets verify.sh relies on.
|
|
215
|
+
node_bin="$(command -v bun)"
|
|
102
216
|
fi
|
|
103
|
-
|
|
104
|
-
|
|
217
|
+
|
|
218
|
+
local npm_bin="$pkg_manager"
|
|
219
|
+
if command -v "$pkg_manager" >/dev/null 2>&1; then
|
|
220
|
+
npm_bin="$(command -v "$pkg_manager")"
|
|
105
221
|
fi
|
|
106
222
|
|
|
107
223
|
append_env "HARNESS_ECOSYSTEM" "node"
|
|
108
224
|
append_env "NODE_BIN" "$node_bin"
|
|
109
225
|
append_env "NPM_BIN" "$npm_bin"
|
|
226
|
+
append_env "HARNESS_NODE_PACKAGE_MANAGER" "$pkg_manager"
|
|
227
|
+
append_env "HARNESS_PKG_EXEC" "$(har_pkg_exec "$pkg_manager")"
|
|
110
228
|
append_path_prefix "$dir/node_modules/.bin"
|
|
111
229
|
}
|
|
112
230
|
|
|
@@ -252,8 +370,11 @@ provision_monorepo_root() {
|
|
|
252
370
|
[ -n "$HAR_WORKTREE_DIR" ] || return 0
|
|
253
371
|
[ -f "$HAR_WORKTREE_DIR/package.json" ] || return 0
|
|
254
372
|
[ -d "$HAR_WORKTREE_DIR/node_modules" ] && return 0
|
|
255
|
-
|
|
256
|
-
(
|
|
373
|
+
local pkg_manager
|
|
374
|
+
pkg_manager="$(har_node_package_manager "$HAR_WORKTREE_DIR")"
|
|
375
|
+
pt_log "Installing monorepo root dependencies in $HAR_WORKTREE_DIR with ${pkg_manager}..."
|
|
376
|
+
har_node_install "$HAR_WORKTREE_DIR" "$pkg_manager" \
|
|
377
|
+
"$(har_node_declared_package_manager "$HAR_WORKTREE_DIR")"
|
|
257
378
|
}
|
|
258
379
|
|
|
259
380
|
provision_ecosystem() {
|
|
@@ -165,7 +165,7 @@ fi
|
|
|
165
165
|
SHARED_ECOSYSTEM="$SCRIPT_DIR/ecosystem.shared.config.cjs"
|
|
166
166
|
if [ -f "$SHARED_ECOSYSTEM" ]; then
|
|
167
167
|
log "Starting shared app services from ecosystem.shared.config.cjs..."
|
|
168
|
-
(cd "$REPO_ROOT" &&
|
|
168
|
+
(cd "$REPO_ROOT" && $(har_pkg_exec) pm2 startOrReload "$SHARED_ECOSYSTEM" >/dev/null)
|
|
169
169
|
log "Shared app services running (pm2 ls | grep har-${HARNESS_PROJECT_NAME}-shared-)."
|
|
170
170
|
fi
|
|
171
171
|
|
|
@@ -10,6 +10,10 @@ export HARNESS_AGENT_SLOT_MAX=3
|
|
|
10
10
|
# Toolchain provisioning — launch writes Xcode/simulator paths into .env.agent.<id>
|
|
11
11
|
export HARNESS_ECOSYSTEM="ios"
|
|
12
12
|
# export HARNESS_INSTALL_CMD="xcodebuild -resolvePackageDependencies ..."
|
|
13
|
+
# Node package manager: auto-detected from package.json "packageManager" and the
|
|
14
|
+
# lockfile (bun.lock → bun, pnpm-lock.yaml → pnpm, yarn.lock → yarn, else npm),
|
|
15
|
+
# falling back to whichever is installed. Set to pin one: npm | bun | pnpm | yarn
|
|
16
|
+
# export HARNESS_NODE_PACKAGE_MANAGER="bun"
|
|
13
17
|
|
|
14
18
|
# ── Xcode project ─────────────────────────────────────────────────────────────
|
|
15
19
|
# Set one of HARNESS_XCODE_WORKSPACE or HARNESS_XCODE_PROJECT (workspace wins).
|
|
@@ -70,6 +74,119 @@ har_infra_enabled() {
|
|
|
70
74
|
esac
|
|
71
75
|
}
|
|
72
76
|
|
|
77
|
+
# ── Node package manager helpers ──────────────────────────────────────────────
|
|
78
|
+
# Mirrored verbatim in harness.env and provision-toolchain.sh so a sourcing
|
|
79
|
+
# script and the provisioning subprocess resolve the same tool.
|
|
80
|
+
|
|
81
|
+
# Package managers HAR can drive, in fallback preference order.
|
|
82
|
+
HAR_NODE_PACKAGE_MANAGERS="npm bun pnpm yarn"
|
|
83
|
+
|
|
84
|
+
# Package manager the repo declares: an explicit HARNESS_NODE_PACKAGE_MANAGER
|
|
85
|
+
# wins, then package.json "packageManager", then the lockfile. Empty when the
|
|
86
|
+
# repo says nothing.
|
|
87
|
+
har_node_declared_package_manager() {
|
|
88
|
+
local dir="${1:-.}"
|
|
89
|
+
|
|
90
|
+
if [ -n "${HARNESS_NODE_PACKAGE_MANAGER:-}" ]; then
|
|
91
|
+
echo "$HARNESS_NODE_PACKAGE_MANAGER"
|
|
92
|
+
return
|
|
93
|
+
fi
|
|
94
|
+
if [ -f "$dir/package.json" ]; then
|
|
95
|
+
local field
|
|
96
|
+
field="$(sed -n 's/.*"packageManager"[[:space:]]*:[[:space:]]*"\([a-z]*\)@.*/\1/p' "$dir/package.json" | head -1)"
|
|
97
|
+
if [ -n "$field" ]; then
|
|
98
|
+
echo "$field"
|
|
99
|
+
return
|
|
100
|
+
fi
|
|
101
|
+
fi
|
|
102
|
+
if [ -f "$dir/bun.lock" ] || [ -f "$dir/bun.lockb" ]; then echo bun; return; fi
|
|
103
|
+
if [ -f "$dir/pnpm-lock.yaml" ]; then echo pnpm; return; fi
|
|
104
|
+
if [ -f "$dir/yarn.lock" ]; then echo yarn; return; fi
|
|
105
|
+
if [ -f "$dir/package-lock.json" ]; then echo npm; return; fi
|
|
106
|
+
echo ""
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
# Package manager to actually run. A manager the repo declares but this machine
|
|
110
|
+
# lacks falls back to one that is installed, so a repo pinned to npm still
|
|
111
|
+
# provisions on a bun-only machine (and the reverse).
|
|
112
|
+
har_node_package_manager() {
|
|
113
|
+
local dir="${1:-.}"
|
|
114
|
+
local declared
|
|
115
|
+
declared="$(har_node_declared_package_manager "$dir")"
|
|
116
|
+
|
|
117
|
+
if [ -n "$declared" ] && command -v "$declared" >/dev/null 2>&1; then
|
|
118
|
+
echo "$declared"
|
|
119
|
+
return
|
|
120
|
+
fi
|
|
121
|
+
|
|
122
|
+
local candidate
|
|
123
|
+
for candidate in $HAR_NODE_PACKAGE_MANAGERS; do
|
|
124
|
+
if command -v "$candidate" >/dev/null 2>&1; then
|
|
125
|
+
echo "$candidate"
|
|
126
|
+
return
|
|
127
|
+
fi
|
|
128
|
+
done
|
|
129
|
+
|
|
130
|
+
echo "${declared:-npm}"
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
# Lockfile a manager writes, so a substitute install can clean up after itself.
|
|
134
|
+
har_node_lockfile() {
|
|
135
|
+
case "$1" in
|
|
136
|
+
bun) echo "bun.lock" ;;
|
|
137
|
+
npm) echo "package-lock.json" ;;
|
|
138
|
+
pnpm) echo "pnpm-lock.yaml" ;;
|
|
139
|
+
yarn) echo "yarn.lock" ;;
|
|
140
|
+
*) echo "" ;;
|
|
141
|
+
esac
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
# Install dependencies in a directory. When a substitute manager stands in for
|
|
145
|
+
# the one the repo declares, any lockfile it creates is removed afterwards:
|
|
146
|
+
# provisioning must not migrate the repo to a different package manager.
|
|
147
|
+
# (bun writes bun.lock even under --no-save, so the flags alone are not enough.)
|
|
148
|
+
har_node_install() {
|
|
149
|
+
local dir="$1"
|
|
150
|
+
local manager="$2"
|
|
151
|
+
local declared="${3:-}"
|
|
152
|
+
local substituting=false
|
|
153
|
+
local lockfile=""
|
|
154
|
+
local had_lockfile=false
|
|
155
|
+
|
|
156
|
+
if [ -n "$declared" ] && [ "$declared" != "$manager" ]; then
|
|
157
|
+
substituting=true
|
|
158
|
+
lockfile="$(har_node_lockfile "$manager")"
|
|
159
|
+
if [ -n "$lockfile" ] && [ -e "$dir/$lockfile" ]; then
|
|
160
|
+
had_lockfile=true
|
|
161
|
+
fi
|
|
162
|
+
fi
|
|
163
|
+
|
|
164
|
+
local code=0
|
|
165
|
+
(cd "$dir" && "$manager" install --silent) || code=$?
|
|
166
|
+
|
|
167
|
+
if [ "$substituting" = true ] && [ "$had_lockfile" = false ] && [ -n "$lockfile" ]; then
|
|
168
|
+
rm -f "$dir/$lockfile"
|
|
169
|
+
[ "$manager" = "bun" ] && rm -f "$dir/bun.lockb"
|
|
170
|
+
fi
|
|
171
|
+
return $code
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
# Package runner (npx equivalent) for one-off CLIs such as pm2, including the
|
|
175
|
+
# flag that keeps it non-interactive. Takes a manager name, or none to resolve
|
|
176
|
+
# from the environment and PATH.
|
|
177
|
+
har_pkg_exec() {
|
|
178
|
+
case "${1:-${HARNESS_NODE_PACKAGE_MANAGER:-}}" in
|
|
179
|
+
bun) echo "bunx"; return ;;
|
|
180
|
+
pnpm) echo "pnpm dlx"; return ;;
|
|
181
|
+
yarn) echo "yarn dlx"; return ;;
|
|
182
|
+
npm) echo "npx --yes"; return ;;
|
|
183
|
+
esac
|
|
184
|
+
if command -v npx >/dev/null 2>&1; then echo "npx --yes"; return; fi
|
|
185
|
+
if command -v bunx >/dev/null 2>&1; then echo "bunx"; return; fi
|
|
186
|
+
if command -v pnpm >/dev/null 2>&1; then echo "pnpm dlx"; return; fi
|
|
187
|
+
echo "npx --yes"
|
|
188
|
+
}
|
|
189
|
+
|
|
73
190
|
# Optional "agent usable" smoke beyond build/test, such as a simulator flow or
|
|
74
191
|
# backend-auth check. Enable only when this project needs it.
|
|
75
192
|
# export HARNESS_READINESS_CMD="./.har/readiness.sh"
|