@triclaps/cli 0.0.7 → 0.0.9
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.
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
|
|
3
|
+
# Centralized source-build knobs for the minimal Hermes cloud runner.
|
|
4
|
+
# Build args can still override any of these values.
|
|
5
|
+
|
|
6
|
+
: "${HERMES_GIT_OWNER:=NousResearch}"
|
|
7
|
+
: "${HERMES_GIT_REPO:=Hermes-Agent}"
|
|
8
|
+
: "${HERMES_GIT_REF:=main}"
|
|
9
|
+
: "${HERMES_SOURCE_ARCHIVE_URL:=}"
|
|
10
|
+
|
|
11
|
+
# Minimal extras needed by the CLAPS Hermes runner.
|
|
12
|
+
# - modal/daytona: preserve runtime delegation backends expected by Hermes
|
|
13
|
+
# - messaging: enable outbound messaging tools and gateway-backed integrations
|
|
14
|
+
# - pty: keep terminal tool behavior aligned with the upstream Linux runtime
|
|
15
|
+
: "${HERMES_PYTHON_EXTRAS:=modal,daytona,messaging,pty}"
|
|
16
|
+
|
|
17
|
+
# Extra wheels not covered by Hermes core deps but required by our default toolsets.
|
|
18
|
+
# - Pillow: vision tool auto-resize / image re-encoding path
|
|
19
|
+
: "${HERMES_PYPI_EXTRA_PACKAGES:=Pillow}"
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
|
|
3
|
+
set -euo pipefail
|
|
4
|
+
|
|
5
|
+
config_file="${1:-/opt/claps/hermes-source.env}"
|
|
6
|
+
install_root="${2:-/opt/hermes}"
|
|
7
|
+
|
|
8
|
+
if [[ ! -f "${config_file}" ]]; then
|
|
9
|
+
echo "[hermes-source] Missing config file: ${config_file}" >&2
|
|
10
|
+
exit 1
|
|
11
|
+
fi
|
|
12
|
+
|
|
13
|
+
# shellcheck disable=SC1090
|
|
14
|
+
source "${config_file}"
|
|
15
|
+
|
|
16
|
+
trim_csv_entry() {
|
|
17
|
+
local value="${1:-}"
|
|
18
|
+
value="${value#"${value%%[![:space:]]*}"}"
|
|
19
|
+
value="${value%"${value##*[![:space:]]}"}"
|
|
20
|
+
printf '%s' "${value}"
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
archive_url="${HERMES_SOURCE_ARCHIVE_URL:-}"
|
|
24
|
+
if [[ -z "${archive_url}" ]]; then
|
|
25
|
+
archive_url="https://github.com/${HERMES_GIT_OWNER}/${HERMES_GIT_REPO}/archive/${HERMES_GIT_REF}.tar.gz"
|
|
26
|
+
fi
|
|
27
|
+
|
|
28
|
+
workdir="$(mktemp -d)"
|
|
29
|
+
trap 'rm -rf "${workdir}"' EXIT
|
|
30
|
+
|
|
31
|
+
echo "[hermes-source] Fetching ${archive_url}" >&2
|
|
32
|
+
curl -fsSL "${archive_url}" | tar -xz --strip-components=1 -C "${workdir}"
|
|
33
|
+
|
|
34
|
+
mkdir -p "${install_root}"
|
|
35
|
+
cp -a "${workdir}/." "${install_root}/"
|
|
36
|
+
|
|
37
|
+
python_bin="$(command -v python3)"
|
|
38
|
+
|
|
39
|
+
ensure_uv_available() {
|
|
40
|
+
if command -v uv >/dev/null 2>&1; then
|
|
41
|
+
return 0
|
|
42
|
+
fi
|
|
43
|
+
|
|
44
|
+
if [[ "${CLAPS_HERMES_INSTALLER_AUTO_BOOTSTRAP_UV:-0}" != "1" ]]; then
|
|
45
|
+
return 1
|
|
46
|
+
fi
|
|
47
|
+
|
|
48
|
+
echo "[hermes-source] Bootstrapping uv via pip (CLAPS_HERMES_INSTALLER_AUTO_BOOTSTRAP_UV=1)" >&2
|
|
49
|
+
"${python_bin}" -m pip install --no-cache-dir "uv>=0.7,<1"
|
|
50
|
+
|
|
51
|
+
if command -v uv >/dev/null 2>&1; then
|
|
52
|
+
return 0
|
|
53
|
+
fi
|
|
54
|
+
|
|
55
|
+
local user_bin
|
|
56
|
+
user_bin="$("${python_bin}" -m site --user-base 2>/dev/null)/bin"
|
|
57
|
+
if [[ -x "${user_bin}/uv" ]]; then
|
|
58
|
+
export PATH="${user_bin}:${PATH}"
|
|
59
|
+
return 0
|
|
60
|
+
fi
|
|
61
|
+
|
|
62
|
+
return 1
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if ensure_uv_available; then
|
|
66
|
+
installer_backend="uv"
|
|
67
|
+
else
|
|
68
|
+
installer_backend="pip"
|
|
69
|
+
echo "[hermes-source] uv not available; falling back to python -m venv + pip (slower)." >&2
|
|
70
|
+
fi
|
|
71
|
+
|
|
72
|
+
# Hermes requires Python >=3.11. Detect current python3 and decide how to build the venv.
|
|
73
|
+
HERMES_MIN_PYTHON_VERSION="${HERMES_MIN_PYTHON_VERSION:-3.11}"
|
|
74
|
+
|
|
75
|
+
python_version="$("${python_bin}" -c 'import sys; print(f"{sys.version_info.major}.{sys.version_info.minor}")' 2>/dev/null || echo "0.0")"
|
|
76
|
+
python_too_old=0
|
|
77
|
+
if ! "${python_bin}" -c "import sys; req=tuple(int(x) for x in '${HERMES_MIN_PYTHON_VERSION}'.split('.')); sys.exit(0 if sys.version_info[:2] >= req else 1)" 2>/dev/null; then
|
|
78
|
+
python_too_old=1
|
|
79
|
+
fi
|
|
80
|
+
|
|
81
|
+
if [[ "${python_too_old}" == "1" ]]; then
|
|
82
|
+
if [[ "${installer_backend}" == "uv" ]]; then
|
|
83
|
+
echo "[hermes-source] python3 on PATH is ${python_version} (< ${HERMES_MIN_PYTHON_VERSION}); asking uv to auto-resolve a compatible interpreter." >&2
|
|
84
|
+
venv_python_arg="${HERMES_MIN_PYTHON_VERSION}"
|
|
85
|
+
# Force uv to use its python-build-standalone distribution rather than any
|
|
86
|
+
# too-old system interpreter it might still see; this also gives consistent
|
|
87
|
+
# ABI tags so prebuilt wheels (cbor2, pydantic-core, etc.) match.
|
|
88
|
+
uv_python_pref="--python-preference=only-managed"
|
|
89
|
+
else
|
|
90
|
+
echo "[hermes-source] ERROR: python3 on PATH is ${python_version} but Hermes requires >=${HERMES_MIN_PYTHON_VERSION}." >&2
|
|
91
|
+
echo "[hermes-source] Install Python ${HERMES_MIN_PYTHON_VERSION}+ (e.g. via brew/conda) or install uv (https://docs.astral.sh/uv/) so the installer can auto-provision a compatible interpreter." >&2
|
|
92
|
+
exit 1
|
|
93
|
+
fi
|
|
94
|
+
else
|
|
95
|
+
venv_python_arg="${python_bin}"
|
|
96
|
+
uv_python_pref=""
|
|
97
|
+
fi
|
|
98
|
+
|
|
99
|
+
if [[ "${installer_backend}" == "uv" ]]; then
|
|
100
|
+
if [[ -n "${uv_python_pref}" ]]; then
|
|
101
|
+
uv venv "${install_root}/.venv" --python "${venv_python_arg}" "${uv_python_pref}"
|
|
102
|
+
else
|
|
103
|
+
uv venv "${install_root}/.venv" --python "${venv_python_arg}"
|
|
104
|
+
fi
|
|
105
|
+
else
|
|
106
|
+
"${python_bin}" -m venv "${install_root}/.venv"
|
|
107
|
+
"${install_root}/.venv/bin/pip" install --no-cache-dir --upgrade pip
|
|
108
|
+
fi
|
|
109
|
+
|
|
110
|
+
extras_spec=""
|
|
111
|
+
IFS=',' read -r -a hermes_extras <<<"${HERMES_PYTHON_EXTRAS:-}"
|
|
112
|
+
normalized_extras=()
|
|
113
|
+
for extra in "${hermes_extras[@]}"; do
|
|
114
|
+
trimmed_extra="$(trim_csv_entry "${extra}")"
|
|
115
|
+
if [[ -n "${trimmed_extra}" ]]; then
|
|
116
|
+
normalized_extras+=("${trimmed_extra}")
|
|
117
|
+
fi
|
|
118
|
+
done
|
|
119
|
+
|
|
120
|
+
if [[ ${#normalized_extras[@]} -gt 0 ]]; then
|
|
121
|
+
extras_spec="["
|
|
122
|
+
for extra in "${normalized_extras[@]}"; do
|
|
123
|
+
if [[ "${extras_spec}" != "[" ]]; then
|
|
124
|
+
extras_spec+=","
|
|
125
|
+
fi
|
|
126
|
+
extras_spec+="${extra}"
|
|
127
|
+
done
|
|
128
|
+
extras_spec+="]"
|
|
129
|
+
fi
|
|
130
|
+
|
|
131
|
+
if [[ "${installer_backend}" == "uv" ]]; then
|
|
132
|
+
uv pip install --python "${install_root}/.venv/bin/python" "${install_root}${extras_spec}"
|
|
133
|
+
else
|
|
134
|
+
"${install_root}/.venv/bin/pip" install --no-cache-dir "${install_root}${extras_spec}"
|
|
135
|
+
fi
|
|
136
|
+
|
|
137
|
+
extra_packages=()
|
|
138
|
+
IFS=',' read -r -a pypi_packages <<<"${HERMES_PYPI_EXTRA_PACKAGES:-}"
|
|
139
|
+
for package in "${pypi_packages[@]}"; do
|
|
140
|
+
trimmed_package="$(trim_csv_entry "${package}")"
|
|
141
|
+
if [[ -n "${trimmed_package}" ]]; then
|
|
142
|
+
extra_packages+=("${trimmed_package}")
|
|
143
|
+
fi
|
|
144
|
+
done
|
|
145
|
+
|
|
146
|
+
if [[ ${#extra_packages[@]} -gt 0 ]]; then
|
|
147
|
+
if [[ "${installer_backend}" == "uv" ]]; then
|
|
148
|
+
uv pip install --python "${install_root}/.venv/bin/python" "${extra_packages[@]}"
|
|
149
|
+
else
|
|
150
|
+
"${install_root}/.venv/bin/pip" install --no-cache-dir "${extra_packages[@]}"
|
|
151
|
+
fi
|
|
152
|
+
fi
|
|
153
|
+
|
|
154
|
+
# Optional: install Hermes' npm-side deps (agent-browser, camofox-browser).
|
|
155
|
+
# These power the browser tool. Cloud images skip this stage to keep size down.
|
|
156
|
+
node_install_mode="none"
|
|
157
|
+
if [[ -f "${install_root}/package.json" && "${CLAPS_HERMES_INSTALLER_SKIP_NODE:-0}" != "1" ]]; then
|
|
158
|
+
if command -v pnpm >/dev/null 2>&1; then
|
|
159
|
+
echo "[hermes-source] Installing Hermes npm deps via pnpm" >&2
|
|
160
|
+
(cd "${install_root}" && pnpm install --prod --silent --no-frozen-lockfile)
|
|
161
|
+
node_install_mode="pnpm"
|
|
162
|
+
elif command -v npm >/dev/null 2>&1; then
|
|
163
|
+
echo "[hermes-source] Installing Hermes npm deps via npm" >&2
|
|
164
|
+
(cd "${install_root}" && npm install --omit=dev --silent --no-audit --no-fund)
|
|
165
|
+
node_install_mode="npm"
|
|
166
|
+
else
|
|
167
|
+
echo "[hermes-source] No pnpm/npm on PATH; skipping browser tool install. Install pnpm/npm and re-run with --repair to enable browser tools." >&2
|
|
168
|
+
fi
|
|
169
|
+
fi
|
|
170
|
+
|
|
171
|
+
# Cleanup directories that are not used at runtime. Preserve node_modules
|
|
172
|
+
# only when we just installed it; otherwise wipe whatever shipped in the tarball.
|
|
173
|
+
keep_node_modules=0
|
|
174
|
+
if [[ "${node_install_mode}" != "none" ]]; then
|
|
175
|
+
keep_node_modules=1
|
|
176
|
+
fi
|
|
177
|
+
|
|
178
|
+
cleanup_targets=(
|
|
179
|
+
"${install_root}/.playwright"
|
|
180
|
+
"${install_root}/optional-skills"
|
|
181
|
+
"${install_root}/tests"
|
|
182
|
+
"${install_root}/tui_gateway"
|
|
183
|
+
"${install_root}/ui-tui"
|
|
184
|
+
"${install_root}/web"
|
|
185
|
+
"${install_root}/website"
|
|
186
|
+
)
|
|
187
|
+
if [[ "${keep_node_modules}" -eq 0 ]]; then
|
|
188
|
+
cleanup_targets+=("${install_root}/node_modules")
|
|
189
|
+
fi
|
|
190
|
+
rm -rf "${cleanup_targets[@]}"
|
|
191
|
+
|
|
192
|
+
# Marker for the TS layer to know what we installed.
|
|
193
|
+
cat >"${install_root}/.install-state.json" <<JSON
|
|
194
|
+
{
|
|
195
|
+
"pythonBackend": "${installer_backend}",
|
|
196
|
+
"nodeInstallMode": "${node_install_mode}"
|
|
197
|
+
}
|
|
198
|
+
JSON
|
package/index.js
CHANGED
|
@@ -282,6 +282,12 @@ function resolveAdapterPath(env = process.env) {
|
|
|
282
282
|
if (override) {
|
|
283
283
|
return path4.resolve(override);
|
|
284
284
|
}
|
|
285
|
+
const inPackage = fileURLToPath2(
|
|
286
|
+
new URL("./adapters/hermes_claps_adapter.py", import.meta.url)
|
|
287
|
+
);
|
|
288
|
+
if (existsSync2(inPackage)) {
|
|
289
|
+
return inPackage;
|
|
290
|
+
}
|
|
285
291
|
return fileURLToPath2(
|
|
286
292
|
new URL("../../adapters/hermes_claps_adapter.py", import.meta.url)
|
|
287
293
|
);
|
|
@@ -10441,8 +10447,14 @@ var moduleDir = path9.dirname(fileURLToPath4(import.meta.url));
|
|
|
10441
10447
|
var repoRootCandidate = path9.resolve(moduleDir, "..", "..", "..", "..");
|
|
10442
10448
|
function resolveRepoAsset(assetRelPath, env) {
|
|
10443
10449
|
const override = env.CLAPS_HERMES_REPO_ROOT?.trim();
|
|
10444
|
-
|
|
10445
|
-
|
|
10450
|
+
if (override) {
|
|
10451
|
+
return path9.join(path9.resolve(override), assetRelPath);
|
|
10452
|
+
}
|
|
10453
|
+
const inPackage = path9.join(moduleDir, assetRelPath);
|
|
10454
|
+
if (existsSync5(inPackage)) {
|
|
10455
|
+
return inPackage;
|
|
10456
|
+
}
|
|
10457
|
+
return path9.join(repoRootCandidate, assetRelPath);
|
|
10446
10458
|
}
|
|
10447
10459
|
async function readInstallMode(versionDir) {
|
|
10448
10460
|
try {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@triclaps/cli",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.9",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"bin": {
|
|
6
6
|
"claps-cli": "index.js",
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
"index.js",
|
|
15
15
|
"neo-cli.js",
|
|
16
16
|
"adapters",
|
|
17
|
+
"docker",
|
|
17
18
|
"README.md"
|
|
18
19
|
],
|
|
19
20
|
"dependencies": {
|