@guiho/runx 0.2.6 → 0.4.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/CHANGELOG.md +44 -0
- package/DOCS.md +128 -109
- package/README.md +58 -58
- package/devops/build-binaries.ts +44 -62
- package/devops/devops.xdocs.md +8 -5
- package/devops/install.ps1 +182 -152
- package/devops/install.sh +197 -262
- package/devops/installers.spec.ts +31 -0
- package/devops/verify-release-assets.ts +17 -0
- package/docs/decisions/decisions.xdocs.md +4 -0
- package/docs/decisions/interactive-init-manifest.md +187 -0
- package/docs/docs.xdocs.md +3 -1
- package/docs/plans/interactive-init-manifest.md +177 -0
- package/docs/plans/plans.xdocs.md +11 -0
- package/docs/plans/rfc-0034-cli-compliance-migration.md +586 -0
- package/docs/plans/upgrade-reliability-implementation.md +95 -0
- package/docs/reviews/implementation/implementation.xdocs.md +6 -0
- package/docs/reviews/implementation/interactive-init-manifest-review.md +69 -0
- package/docs/reviews/implementation/rfc-0034-cli-compliance-migration-review.md +59 -0
- package/docs/reviews/plans/interactive-init-manifest-review.md +82 -0
- package/docs/reviews/plans/plans.xdocs.md +10 -0
- package/docs/reviews/plans/rfc-0034-cli-compliance-migration-review.md +80 -0
- package/docs/reviews/plans/upgrade-reliability-implementation-review.md +65 -0
- package/docs/superpowers/specs/2026-07-15-upgrade-reliability-design.md +662 -0
- package/docs/superpowers/specs/specs.xdocs.md +24 -0
- package/docs/superpowers/superpowers.xdocs.md +21 -0
- package/docs/todo/rfc-0034-cli-compliance-migration-implementation.md +58 -0
- package/docs/todo/rfc-0034-cli-compliance-migration.md +151 -0
- package/docs/todo/todo.xdocs.md +6 -2
- package/docs/validation/interactive-init-manifest.md +79 -0
- package/docs/validation/rfc-0034-cli-compliance-migration.md +67 -0
- package/docs/validation/upgrade-reliability.md +124 -0
- package/docs/validation/validation.xdocs.md +9 -0
- package/library/agents.d.ts +28 -4
- package/library/agents.d.ts.map +1 -1
- package/library/agents.js +143 -41
- package/library/cli.d.ts.map +1 -1
- package/library/cli.js +297 -317
- package/library/configuration.d.ts +57 -0
- package/library/configuration.d.ts.map +1 -0
- package/library/configuration.js +111 -0
- package/library/embedded-resources.d.ts +6 -1
- package/library/embedded-resources.d.ts.map +1 -1
- package/library/embedded-resources.js +10 -4
- package/library/executor.d.ts +5 -1
- package/library/executor.d.ts.map +1 -1
- package/library/executor.js +10 -10
- package/library/help.d.ts +8 -4
- package/library/help.d.ts.map +1 -1
- package/library/help.js +70 -42
- package/library/init.d.ts +18 -0
- package/library/init.d.ts.map +1 -0
- package/library/init.js +43 -0
- package/library/manifest.d.ts +4 -40
- package/library/manifest.d.ts.map +1 -1
- package/library/manifest.js +4 -112
- package/library/path-utils.d.ts +13 -0
- package/library/path-utils.d.ts.map +1 -0
- package/library/path-utils.js +82 -0
- package/library/recovery.d.ts +7 -0
- package/library/recovery.d.ts.map +1 -0
- package/library/recovery.js +23 -0
- package/library/release-catalog.d.ts +32 -0
- package/library/release-catalog.d.ts.map +1 -0
- package/library/release-catalog.js +124 -0
- package/library/self-management.d.ts +24 -4
- package/library/self-management.d.ts.map +1 -1
- package/library/self-management.js +279 -99
- package/library/storage.d.ts +13 -0
- package/library/storage.d.ts.map +1 -0
- package/library/storage.js +38 -0
- package/library/types.d.ts +11 -16
- package/library/types.d.ts.map +1 -1
- package/library/types.js +3 -0
- package/library/update-cache.d.ts +21 -0
- package/library/update-cache.d.ts.map +1 -0
- package/library/update-cache.js +68 -0
- package/library/upgrade-reporting.d.ts +11 -0
- package/library/upgrade-reporting.d.ts.map +1 -0
- package/library/upgrade-reporting.js +67 -0
- package/library/upgrade-types.d.ts +72 -0
- package/library/upgrade-types.d.ts.map +1 -0
- package/library/upgrade-types.js +3 -0
- package/package.json +6 -3
- package/scripts/runx-bin.mjs +49 -0
- package/scripts/runx-bin.spec.ts +62 -0
- package/scripts/scripts.xdocs.md +3 -3
- package/skills/guiho-s-runx/SKILL.md +64 -59
- package/skills/guiho-s-runx/guiho-s-runx.xdocs.md +7 -4
- package/skills/skills.xdocs.md +1 -1
- package/docs/todo/implement-runx-alpha.md +0 -36
- package/scripts/runx-bin.ts +0 -24
package/devops/install.sh
CHANGED
|
@@ -1,324 +1,259 @@
|
|
|
1
|
-
#!/usr/bin/env
|
|
2
|
-
|
|
3
|
-
# Install GUIHO RunX as a native CLI binary from GitHub Releases.
|
|
4
|
-
#
|
|
5
|
-
set -Eeuo pipefail
|
|
1
|
+
#!/usr/bin/env sh
|
|
2
|
+
set -eu
|
|
6
3
|
|
|
7
4
|
REPO="${RUNX_REPO:-CGuiho/runx}"
|
|
8
5
|
VERSION="${RUNX_VERSION:-latest}"
|
|
9
6
|
INSTALL_DIR="${RUNX_INSTALL_DIR:-$HOME/.local/bin}"
|
|
7
|
+
DOWNLOAD_BASE_URL="${RUNX_DOWNLOAD_BASE_URL:-}"
|
|
10
8
|
ARCH_OVERRIDE=""
|
|
11
9
|
VARIANT_OVERRIDE=""
|
|
12
10
|
OS=""
|
|
13
11
|
ARCH=""
|
|
14
|
-
|
|
12
|
+
TARGET_VERSION=""
|
|
15
13
|
TMP=""
|
|
16
14
|
|
|
17
|
-
cleanup() {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
trap cleanup EXIT
|
|
15
|
+
cleanup() { [ -z "$TMP" ] || rm -rf -- "$TMP"; }
|
|
16
|
+
trap cleanup EXIT HUP INT TERM
|
|
17
|
+
fail() { printf 'error: %s\n' "$*" >&2; exit 1; }
|
|
18
|
+
require_command() { command -v "$1" >/dev/null 2>&1 || fail "required command not found: $1"; }
|
|
19
|
+
require_value() { [ -n "${2:-}" ] || fail "$1 requires a value"; }
|
|
24
20
|
|
|
25
21
|
usage() {
|
|
26
22
|
cat <<EOF
|
|
27
|
-
Install GUIHO RunX as a native CLI binary from GitHub Releases.
|
|
23
|
+
Install GUIHO RunX as a verified native CLI binary from GitHub Releases.
|
|
28
24
|
|
|
29
|
-
Usage: install.sh [
|
|
25
|
+
Usage: install.sh [--version VERSION] [--arch x64|arm64] [--variant baseline|default|modern] [--install-dir DIR]
|
|
30
26
|
|
|
31
|
-
|
|
32
|
-
-v, --version VERSION Version to install (default: latest).
|
|
33
|
-
Examples: latest, 0.1.1, @guiho/runx@0.1.1
|
|
34
|
-
--arch ARCH Force architecture: x64 | arm64 (default: auto-detect)
|
|
35
|
-
--variant VARIANT Force x64 variant: baseline | default | modern (default: baseline)
|
|
36
|
-
--install-dir DIR Install directory (default: \$HOME/.local/bin)
|
|
37
|
-
-h, --help Show this help
|
|
38
|
-
|
|
39
|
-
Environment variables:
|
|
40
|
-
RUNX_VERSION Same as --version
|
|
41
|
-
RUNX_REPO GitHub repo (default: CGuiho/runx)
|
|
42
|
-
RUNX_INSTALL_DIR Same as --install-dir
|
|
27
|
+
VERSION may be an exact stable or prerelease version. The default is latest stable.
|
|
43
28
|
EOF
|
|
44
29
|
}
|
|
45
30
|
|
|
46
|
-
fail() {
|
|
47
|
-
printf 'error: %s\n' "$*" >&2
|
|
48
|
-
exit 1
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
require_command() {
|
|
52
|
-
command -v "$1" >/dev/null 2>&1 || fail "required command not found: $1"
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
require_value() {
|
|
56
|
-
local option="$1"
|
|
57
|
-
local value="${2:-}"
|
|
58
|
-
|
|
59
|
-
[[ -n "$value" ]] || fail "$option requires a value"
|
|
60
|
-
}
|
|
61
|
-
|
|
62
31
|
parse_args() {
|
|
63
|
-
while [
|
|
32
|
+
while [ "$#" -gt 0 ]; do
|
|
64
33
|
case "$1" in
|
|
65
|
-
-v
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
--
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
require_value "$1" "${2:-}"
|
|
76
|
-
ARCH_OVERRIDE="$2"
|
|
77
|
-
shift 2
|
|
78
|
-
;;
|
|
79
|
-
--arch=*)
|
|
80
|
-
ARCH_OVERRIDE="${1#*=}"
|
|
81
|
-
shift
|
|
82
|
-
;;
|
|
83
|
-
--variant)
|
|
84
|
-
require_value "$1" "${2:-}"
|
|
85
|
-
VARIANT_OVERRIDE="$2"
|
|
86
|
-
shift 2
|
|
87
|
-
;;
|
|
88
|
-
--variant=*)
|
|
89
|
-
VARIANT_OVERRIDE="${1#*=}"
|
|
90
|
-
shift
|
|
91
|
-
;;
|
|
92
|
-
--install-dir)
|
|
93
|
-
require_value "$1" "${2:-}"
|
|
94
|
-
INSTALL_DIR="$2"
|
|
95
|
-
shift 2
|
|
96
|
-
;;
|
|
97
|
-
--install-dir=*)
|
|
98
|
-
INSTALL_DIR="${1#*=}"
|
|
99
|
-
shift
|
|
100
|
-
;;
|
|
101
|
-
-h | --help)
|
|
102
|
-
usage
|
|
103
|
-
exit 0
|
|
104
|
-
;;
|
|
105
|
-
*)
|
|
106
|
-
fail "unknown flag: $1. Run with --help for usage."
|
|
107
|
-
;;
|
|
34
|
+
-v|--version) require_value "$1" "${2:-}"; VERSION="$2"; shift 2 ;;
|
|
35
|
+
--version=*) VERSION=${1#*=}; shift ;;
|
|
36
|
+
--arch) require_value "$1" "${2:-}"; ARCH_OVERRIDE="$2"; shift 2 ;;
|
|
37
|
+
--arch=*) ARCH_OVERRIDE=${1#*=}; shift ;;
|
|
38
|
+
--variant) require_value "$1" "${2:-}"; VARIANT_OVERRIDE="$2"; shift 2 ;;
|
|
39
|
+
--variant=*) VARIANT_OVERRIDE=${1#*=}; shift ;;
|
|
40
|
+
--install-dir) require_value "$1" "${2:-}"; INSTALL_DIR="$2"; shift 2 ;;
|
|
41
|
+
--install-dir=*) INSTALL_DIR=${1#*=}; shift ;;
|
|
42
|
+
-h|--help) usage; exit 0 ;;
|
|
43
|
+
*) fail "unknown flag: $1" ;;
|
|
108
44
|
esac
|
|
109
45
|
done
|
|
110
46
|
}
|
|
111
47
|
|
|
112
|
-
detect_os() {
|
|
113
|
-
case "$(uname -s)" in
|
|
114
|
-
Linux) printf 'linux\n' ;;
|
|
115
|
-
Darwin) printf 'macos\n' ;;
|
|
116
|
-
*) fail "unsupported OS: $(uname -s)" ;;
|
|
117
|
-
esac
|
|
118
|
-
}
|
|
119
|
-
|
|
48
|
+
detect_os() { case "$(uname -s)" in Linux) printf 'linux\n' ;; Darwin) printf 'darwin\n' ;; *) fail "unsupported OS: $(uname -s)" ;; esac; }
|
|
120
49
|
detect_arch() {
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
x64 | arm64) printf '%s\n' "$ARCH_OVERRIDE" ;;
|
|
124
|
-
*) fail "invalid --arch '$ARCH_OVERRIDE'. Must be x64 or arm64." ;;
|
|
125
|
-
esac
|
|
126
|
-
return
|
|
127
|
-
fi
|
|
128
|
-
|
|
129
|
-
case "$(uname -m)" in
|
|
130
|
-
x86_64 | amd64) printf 'x64\n' ;;
|
|
131
|
-
arm64 | aarch64) printf 'arm64\n' ;;
|
|
132
|
-
*) fail "unsupported architecture: $(uname -m)" ;;
|
|
133
|
-
esac
|
|
50
|
+
detected=${ARCH_OVERRIDE:-$(uname -m)}
|
|
51
|
+
case "$detected" in x64|x86_64|amd64) printf 'x64\n' ;; arm64|aarch64) printf 'arm64\n' ;; *) fail "unsupported architecture: $detected" ;; esac
|
|
134
52
|
}
|
|
135
53
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
;;
|
|
155
|
-
*)
|
|
156
|
-
fail "invalid --variant '$variant'. Must be baseline, default, or modern."
|
|
54
|
+
normalize_version() {
|
|
55
|
+
value=$1
|
|
56
|
+
value=${value#@guiho/runx@}
|
|
57
|
+
value=${value#v}
|
|
58
|
+
printf '%s\n' "$value" | grep -Eq '^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)(-[0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*)?(\+[0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*)?$' || fail "invalid RunX version: $1"
|
|
59
|
+
case "$value" in
|
|
60
|
+
*-*)
|
|
61
|
+
prerelease=${value#*-}
|
|
62
|
+
prerelease=${prerelease%%+*}
|
|
63
|
+
old_ifs=$IFS
|
|
64
|
+
IFS=.
|
|
65
|
+
set -- $prerelease
|
|
66
|
+
IFS=$old_ifs
|
|
67
|
+
for identifier do
|
|
68
|
+
if printf '%s\n' "$identifier" | grep -Eq '^[0-9]+$'; then
|
|
69
|
+
case "$identifier" in 0|[1-9]*) ;; 0*) fail "invalid RunX version: $value" ;; esac
|
|
70
|
+
fi
|
|
71
|
+
done
|
|
157
72
|
;;
|
|
158
73
|
esac
|
|
74
|
+
printf '%s\n' "$value"
|
|
159
75
|
}
|
|
160
76
|
|
|
161
|
-
|
|
162
|
-
|
|
77
|
+
resolve_target_version() {
|
|
78
|
+
if [ "$VERSION" != latest ]; then normalize_version "$VERSION"; return; fi
|
|
79
|
+
printf 'Resolving latest stable RunX release...\n' >&2
|
|
80
|
+
effective=$(curl --fail --location --silent --show-error --proto '=https' --tlsv1.2 --output /dev/null --write-out '%{url_effective}' "https://github.com/${REPO}/releases/latest")
|
|
81
|
+
tag=${effective##*/}
|
|
82
|
+
tag=$(printf '%s' "$tag" | sed 's/%40/@/g; s/%2[Ff]/\//g')
|
|
83
|
+
normalize_version "$tag"
|
|
84
|
+
}
|
|
163
85
|
|
|
164
|
-
|
|
165
|
-
|
|
86
|
+
build_candidates() {
|
|
87
|
+
variant=${VARIANT_OVERRIDE:-baseline}
|
|
88
|
+
if [ "$ARCH" = arm64 ]; then
|
|
89
|
+
[ -z "$VARIANT_OVERRIDE" ] || fail '--variant is only valid for x64 installs'
|
|
90
|
+
printf 'runx-%s-arm64\n' "$OS"
|
|
166
91
|
return
|
|
167
92
|
fi
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
*) tag="@guiho/runx@${VERSION}" ;;
|
|
93
|
+
case "$variant" in
|
|
94
|
+
baseline) printf 'runx-%s-x64-baseline\nrunx-%s-x64\nrunx-%s-x64-modern\n' "$OS" "$OS" "$OS" ;;
|
|
95
|
+
default) printf 'runx-%s-x64\nrunx-%s-x64-baseline\nrunx-%s-x64-modern\n' "$OS" "$OS" "$OS" ;;
|
|
96
|
+
modern) printf 'runx-%s-x64-modern\nrunx-%s-x64\nrunx-%s-x64-baseline\n' "$OS" "$OS" "$OS" ;;
|
|
97
|
+
*) fail "invalid variant: $variant" ;;
|
|
174
98
|
esac
|
|
175
|
-
|
|
176
|
-
local encoded_tag="${tag//@/%40}"
|
|
177
|
-
encoded_tag="${encoded_tag//\//%2F}"
|
|
178
|
-
printf 'https://github.com/%s/releases/download/%s/%s\n' "$REPO" "$encoded_tag" "$asset"
|
|
179
99
|
}
|
|
180
100
|
|
|
181
101
|
verify_native_binary() {
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
magic2="$(LC_ALL=C head -c 2 "$path" 2>/dev/null || true)"
|
|
187
|
-
magic4="$(LC_ALL=C head -c 4 "$path" 2>/dev/null || true)"
|
|
188
|
-
|
|
189
|
-
case "$magic4" in
|
|
190
|
-
$'\177ELF' | $'\xcf\xfa\xed\xfe' | $'\xce\xfa\xed\xfe' | $'\xca\xfe\xba\xbe') return 0 ;;
|
|
191
|
-
'<!DO' | '<htm') return 1 ;;
|
|
192
|
-
esac
|
|
193
|
-
|
|
194
|
-
case "$magic2" in
|
|
195
|
-
MZ) return 0 ;;
|
|
196
|
-
'#!') return 1 ;;
|
|
197
|
-
esac
|
|
198
|
-
|
|
199
|
-
return 2
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
shell_profile_path() {
|
|
203
|
-
local shell_name="${SHELL##*/}"
|
|
204
|
-
|
|
205
|
-
case "$shell_name" in
|
|
206
|
-
fish) printf '%s/.config/fish/config.fish\n' "$HOME" ;;
|
|
207
|
-
zsh) printf '%s/.zshrc\n' "$HOME" ;;
|
|
208
|
-
bash)
|
|
209
|
-
if [[ "$OS" == "macos" && -f "$HOME/.bash_profile" ]]; then
|
|
210
|
-
printf '%s/.bash_profile\n' "$HOME"
|
|
211
|
-
else
|
|
212
|
-
printf '%s/.bashrc\n' "$HOME"
|
|
213
|
-
fi
|
|
214
|
-
;;
|
|
215
|
-
*) printf '%s/.profile\n' "$HOME" ;;
|
|
216
|
-
esac
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
path_contains_install_dir() {
|
|
220
|
-
case ":$PATH:" in
|
|
221
|
-
*:"$INSTALL_DIR":*) return 0 ;;
|
|
102
|
+
magic=$(od -An -tx1 -N4 "$1" 2>/dev/null | tr -d ' \n')
|
|
103
|
+
case "$OS:$magic" in
|
|
104
|
+
linux:7f454c46|darwin:cffaedfe|darwin:cefaedfe|darwin:cafebabe|darwin:feedfacf|darwin:feedface) return 0 ;;
|
|
222
105
|
*) return 1 ;;
|
|
223
106
|
esac
|
|
224
107
|
}
|
|
225
108
|
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
if [
|
|
233
|
-
|
|
109
|
+
verify_installed_version() {
|
|
110
|
+
verify_output=$(mktemp "${TMPDIR:-/tmp}/runx-version.XXXXXX") || return 1
|
|
111
|
+
"$1" --version >"$verify_output" 2>&1 &
|
|
112
|
+
verify_pid=$!
|
|
113
|
+
verify_waited=0
|
|
114
|
+
while kill -0 "$verify_pid" 2>/dev/null; do
|
|
115
|
+
if [ "$verify_waited" -ge 10 ]; then
|
|
116
|
+
kill "$verify_pid" 2>/dev/null || true
|
|
117
|
+
wait "$verify_pid" 2>/dev/null || true
|
|
118
|
+
rm -f -- "$verify_output"
|
|
119
|
+
printf 'error: installed RunX version check timed out after 10 seconds\n' >&2
|
|
120
|
+
return 1
|
|
234
121
|
fi
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
122
|
+
sleep 1
|
|
123
|
+
verify_waited=$((verify_waited + 1))
|
|
124
|
+
done
|
|
125
|
+
if ! wait "$verify_pid"; then
|
|
126
|
+
cat "$verify_output" >&2
|
|
127
|
+
rm -f -- "$verify_output"
|
|
128
|
+
return 1
|
|
241
129
|
fi
|
|
242
|
-
|
|
243
|
-
|
|
130
|
+
actual=$(cat "$verify_output")
|
|
131
|
+
rm -f -- "$verify_output"
|
|
132
|
+
[ "$actual" = "$TARGET_VERSION" ] || { printf 'error: installed RunX reported %s; expected %s\n' "${actual:-<empty>}" "$TARGET_VERSION" >&2; return 1; }
|
|
244
133
|
}
|
|
245
134
|
|
|
246
135
|
ensure_path() {
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
136
|
+
PATH="$INSTALL_DIR:$PATH"; export PATH
|
|
137
|
+
profile="$HOME/.profile"
|
|
138
|
+
case "${SHELL##*/}" in zsh) profile="$HOME/.zshrc" ;; bash) profile="$HOME/.bashrc" ;; fish) profile="$HOME/.config/fish/config.fish" ;; esac
|
|
139
|
+
mkdir -p -- "$(dirname "$profile")"
|
|
140
|
+
if ! grep -Fq "$INSTALL_DIR" "$profile" 2>/dev/null; then
|
|
141
|
+
if [ "${SHELL##*/}" = fish ]; then printf '\n# Added by runx installer\nfish_add_path %s\n' "$INSTALL_DIR" >>"$profile"
|
|
142
|
+
else printf '\n# Added by runx installer\nexport PATH=%s:$PATH\n' "$INSTALL_DIR" >>"$profile"; fi
|
|
251
143
|
fi
|
|
252
|
-
|
|
253
|
-
local profile
|
|
254
|
-
profile="$(shell_profile_path)"
|
|
255
|
-
append_path_to_profile "$profile"
|
|
256
|
-
|
|
257
|
-
printf 'runx: ensured %s is added to PATH in %s\n' "$INSTALL_DIR" "$profile"
|
|
258
|
-
printf 'runx: restart your terminal, or run this for the current shell:\n'
|
|
259
|
-
printf ' export PATH=%q:\$PATH\n' "$INSTALL_DIR"
|
|
260
144
|
}
|
|
261
145
|
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
146
|
+
download_asset() {
|
|
147
|
+
url=$1
|
|
148
|
+
output=$2
|
|
149
|
+
set +e
|
|
150
|
+
if [ -n "$DOWNLOAD_BASE_URL" ]; then
|
|
151
|
+
http_code=$(curl --location --progress-bar --show-error --output "$output" --write-out '%{http_code}' "$url")
|
|
152
|
+
else
|
|
153
|
+
http_code=$(curl --location --progress-bar --show-error --proto '=https' --tlsv1.2 --output "$output" --write-out '%{http_code}' "$url")
|
|
154
|
+
fi
|
|
155
|
+
curl_exit=$?
|
|
156
|
+
set -e
|
|
157
|
+
[ "$curl_exit" -eq 0 ] || fail "download failed for $url (curl exit $curl_exit)"
|
|
158
|
+
case "$http_code" in
|
|
159
|
+
404) return 44 ;;
|
|
160
|
+
2??) return 0 ;;
|
|
161
|
+
*) fail "download failed for $url (HTTP $http_code)" ;;
|
|
162
|
+
esac
|
|
274
163
|
}
|
|
275
164
|
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
165
|
+
install_transactional() {
|
|
166
|
+
source_path=$1
|
|
167
|
+
destination=$2
|
|
168
|
+
backup="${destination}.old.$$.$(date +%s)"
|
|
169
|
+
original_moved=false
|
|
170
|
+
if [ -e "$destination" ]; then mv -- "$destination" "$backup" || fail "could not back up existing RunX at $destination"; original_moved=true; fi
|
|
171
|
+
if ! install -m 0755 "$source_path" "$destination"; then
|
|
172
|
+
[ "$original_moved" = false ] || mv -- "$backup" "$destination" || fail "installation and automatic rollback both failed; backup remains at $backup"
|
|
173
|
+
fail 'installation failed; the previous executable was restored'
|
|
174
|
+
fi
|
|
175
|
+
printf 'Verifying...\n'
|
|
176
|
+
if ! verify_installed_version "$destination"; then
|
|
177
|
+
rm -f -- "$destination"
|
|
178
|
+
[ "$original_moved" = false ] || mv -- "$backup" "$destination" || fail "verification and automatic rollback both failed; backup remains at $backup"
|
|
179
|
+
fail 'installation verification failed; the previous executable was restored'
|
|
180
|
+
fi
|
|
181
|
+
[ "$original_moved" = false ] || rm -f -- "$backup"
|
|
182
|
+
}
|
|
289
183
|
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
184
|
+
install_agent_assets() {
|
|
185
|
+
tag_base=${DOWNLOAD_BASE_URL:-"https://github.com/${REPO}/releases/download"}
|
|
186
|
+
skill_url="${tag_base%/}/${encoded_tag}/guiho-s-runx"
|
|
187
|
+
prompt_url="${tag_base%/}/${encoded_tag}/guiho-i-runx"
|
|
188
|
+
printf 'Downloading skill asset: %s\n' "$skill_url"
|
|
189
|
+
download_asset "$skill_url" "$TMP/guiho-s-runx" || fail 'could not download guiho-s-runx'
|
|
190
|
+
printf 'Downloading instruction asset: %s\n' "$prompt_url"
|
|
191
|
+
download_asset "$prompt_url" "$TMP/guiho-i-runx" || fail 'could not download guiho-i-runx'
|
|
192
|
+
for skill_root in "$HOME/.agents/skills/guiho-s-runx" "$HOME/.claude/skills/guiho-s-runx"; do
|
|
193
|
+
mkdir -p -- "$skill_root"
|
|
194
|
+
install -m 0644 "$TMP/guiho-s-runx" "$skill_root/SKILL.md"
|
|
195
|
+
printf 'Installed skill: %s\n' "$skill_root/SKILL.md"
|
|
196
|
+
done
|
|
197
|
+
targets=""
|
|
198
|
+
[ ! -f AGENTS.md ] || targets="AGENTS.md"
|
|
199
|
+
[ ! -f CLAUDE.md ] || targets="${targets}${targets:+ }CLAUDE.md"
|
|
200
|
+
[ -n "$targets" ] || targets="AGENTS.md"
|
|
201
|
+
for instruction_file in $targets; do
|
|
202
|
+
printf 'Reconciling instruction file: %s\n' "$instruction_file"
|
|
203
|
+
clean_file="$TMP/instruction-clean"
|
|
204
|
+
if [ -f "$instruction_file" ]; then
|
|
205
|
+
awk '
|
|
206
|
+
$0 == "<!-- BEGIN RUNX — DO NOT EDIT THIS SECTION -->" { managed=1; next }
|
|
207
|
+
$0 == "<!-- END RUNX -->" { managed=0; next }
|
|
208
|
+
!managed { print }
|
|
209
|
+
' "$instruction_file" >"$clean_file"
|
|
210
|
+
else
|
|
211
|
+
: >"$clean_file"
|
|
297
212
|
fi
|
|
298
|
-
|
|
299
|
-
|
|
213
|
+
{
|
|
214
|
+
cat "$clean_file"
|
|
215
|
+
[ ! -s "$clean_file" ] || printf '\n'
|
|
216
|
+
printf '<!-- BEGIN RUNX — DO NOT EDIT THIS SECTION -->\n'
|
|
217
|
+
cat "$TMP/guiho-i-runx"
|
|
218
|
+
printf '\n<!-- END RUNX -->\n'
|
|
219
|
+
} >"$instruction_file"
|
|
300
220
|
done
|
|
301
|
-
|
|
302
|
-
fail "no compatible runx binary found. Check available assets at: https://github.com/${REPO}/releases"
|
|
303
221
|
}
|
|
304
222
|
|
|
305
223
|
main() {
|
|
306
224
|
parse_args "$@"
|
|
307
|
-
require_command
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
225
|
+
for command in awk cat curl date dirname grep head install mktemp mv od rm sed tr uname; do require_command "$command"; done
|
|
226
|
+
OS=$(detect_os); ARCH=$(detect_arch); TARGET_VERSION=$(resolve_target_version)
|
|
227
|
+
TMP=$(mktemp -d "${TMPDIR:-/tmp}/runx-install.XXXXXX")
|
|
228
|
+
mkdir -p -- "$INSTALL_DIR"
|
|
229
|
+
destination="$INSTALL_DIR/runx"
|
|
230
|
+
encoded_tag="%40guiho%2Frunx%40${TARGET_VERSION}"
|
|
231
|
+
downloaded=""
|
|
232
|
+
first_asset=$(build_candidates | head -n 1)
|
|
233
|
+
source_url="${DOWNLOAD_BASE_URL:-https://github.com/${REPO}/releases/download}/${encoded_tag}/${first_asset}"
|
|
234
|
+
printf 'Initiating GUIHO CLI Upgrade / Installation Sequence...\n'
|
|
235
|
+
printf 'Target Version: v%s\nArchitecture: %s\nVariant: %s\nSource URL: %s\n' "$TARGET_VERSION" "$ARCH" "${VARIANT_OVERRIDE:-baseline}" "$source_url"
|
|
236
|
+
build_candidates | while IFS= read -r asset; do printf '%s\n' "$asset"; done >"$TMP/candidates"
|
|
237
|
+
while IFS= read -r asset; do
|
|
238
|
+
if [ -n "$DOWNLOAD_BASE_URL" ]; then url="${DOWNLOAD_BASE_URL%/}/${encoded_tag}/${asset}"; else url="https://github.com/${REPO}/releases/download/${encoded_tag}/${asset}"; fi
|
|
239
|
+
candidate="$TMP/$asset"
|
|
240
|
+
printf 'Downloading %s\n' "$url"
|
|
241
|
+
if download_asset "$url" "$candidate"; then :; else
|
|
242
|
+
status=$?
|
|
243
|
+
if [ "$status" -eq 44 ]; then printf ' %s is not available; trying the next compatible candidate.\n' "$asset"; continue; fi
|
|
244
|
+
exit "$status"
|
|
245
|
+
fi
|
|
246
|
+
verify_native_binary "$candidate" || fail "downloaded asset $asset is not a native $OS executable"
|
|
247
|
+
downloaded=$candidate
|
|
248
|
+
break
|
|
249
|
+
done <"$TMP/candidates"
|
|
250
|
+
[ -n "$downloaded" ] || fail "no compatible RunX $TARGET_VERSION binary found at https://github.com/${REPO}/releases"
|
|
251
|
+
printf 'Replacing...\n'
|
|
252
|
+
install_transactional "$downloaded" "$destination"
|
|
253
|
+
install_agent_assets
|
|
254
|
+
[ "${RUNX_SKIP_PATH_UPDATE:-0}" = 1 ] || ensure_path
|
|
255
|
+
printf 'Final verification: %s --version\n' "$destination"
|
|
256
|
+
printf 'Installed and verified RunX %s at %s\n' "$TARGET_VERSION" "$destination"
|
|
322
257
|
}
|
|
323
258
|
|
|
324
259
|
main "$@"
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @copyright Copyright © 2026 GUIHO Technologies as represented by Cristóvão GUIHO. All Rights Reserved.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { describe, expect, test } from 'bun:test'
|
|
6
|
+
|
|
7
|
+
describe('RunX direct installers', () => {
|
|
8
|
+
test('PowerShell installer exposes the complete RFC sequence', async () => {
|
|
9
|
+
const script = await Bun.file(new URL('./install.ps1', import.meta.url)).text()
|
|
10
|
+
expect(script).toContain('Initiating GUIHO CLI Upgrade / Installation Sequence...')
|
|
11
|
+
expect(script).toContain('guiho-s-runx')
|
|
12
|
+
expect(script).toContain('guiho-i-runx')
|
|
13
|
+
expect(script).toContain('.agents\\skills\\guiho-s-runx')
|
|
14
|
+
expect(script).toContain('.claude\\skills\\guiho-s-runx')
|
|
15
|
+
expect(script).toContain('BEGIN RUNX — DO NOT EDIT THIS SECTION')
|
|
16
|
+
expect(script).toContain('Test-NativeBinary')
|
|
17
|
+
expect(script).toContain('Install-Transactional')
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
test('POSIX installer selects Darwin assets and has no Bun dependency', async () => {
|
|
21
|
+
const script = await Bun.file(new URL('./install.sh', import.meta.url)).text()
|
|
22
|
+
expect(script).toContain("Darwin) printf 'darwin")
|
|
23
|
+
expect(script).toContain('--progress-bar')
|
|
24
|
+
expect(script).toContain('guiho-s-runx')
|
|
25
|
+
expect(script).toContain('guiho-i-runx')
|
|
26
|
+
expect(script).toContain('.agents/skills/guiho-s-runx')
|
|
27
|
+
expect(script).toContain('.claude/skills/guiho-s-runx')
|
|
28
|
+
expect(script).toContain('BEGIN RUNX — DO NOT EDIT THIS SECTION')
|
|
29
|
+
expect(script).not.toContain(' bun ')
|
|
30
|
+
})
|
|
31
|
+
})
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @copyright Copyright © 2026 GUIHO Technologies as represented by Cristóvão GUIHO. All Rights Reserved.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { expectedReleaseAssetNames } from './build-binaries.js'
|
|
6
|
+
import { joinPath } from '../source/path-utils.js'
|
|
7
|
+
|
|
8
|
+
const root = Bun.fileURLToPath(new URL('..', import.meta.url))
|
|
9
|
+
const bin = joinPath(root, 'bin')
|
|
10
|
+
const observed = [...new Bun.Glob('*').scanSync({ cwd: bin, onlyFiles: true })].sort()
|
|
11
|
+
const expected = [...expectedReleaseAssetNames].sort()
|
|
12
|
+
|
|
13
|
+
if (JSON.stringify(observed) !== JSON.stringify(expected)) {
|
|
14
|
+
throw new Error(`Expected exactly ${expected.length} release assets.\nExpected: ${expected.join(', ')}\nObserved: ${observed.join(', ')}`)
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
process.stdout.write(`${JSON.stringify({ count: observed.length, assets: observed }, null, 2)}\n`)
|
|
@@ -6,12 +6,14 @@ children: []
|
|
|
6
6
|
files:
|
|
7
7
|
alpha-boundaries.md: Captures accepted alpha scope, safety, distribution, and compatibility decisions.
|
|
8
8
|
citty-cli-migration.md: Defines the accepted full migration from handwritten parsing and routing to Citty.
|
|
9
|
+
interactive-init-manifest.md: Defines interactive initialization, Semantic Versioning, the public group, and the scripts directory contract.
|
|
9
10
|
mirror-automatic-push.md: Defines automatic Mirror release pushes with a synchronized protected-main gate.
|
|
10
11
|
npm-trusted-publishing.md: Defines the accepted npm OIDC publishing workflow and protected-branch patch-release trial.
|
|
11
12
|
windows-self-upgrade.md: Defines synchronous Windows executable replacement, verification, rollback, and cleanup.
|
|
12
13
|
documents:
|
|
13
14
|
alpha-boundaries.md: Decision record for RunX alpha boundaries.
|
|
14
15
|
citty-cli-migration.md: Decision record for the complete Citty CLI parser and router migration.
|
|
16
|
+
interactive-init-manifest.md: Accepted manifest and interactive initialization decision for runx init.
|
|
15
17
|
mirror-automatic-push.md: Accepted release-policy decision for Mirror push=true and protected delivery ordering.
|
|
16
18
|
npm-trusted-publishing.md: Decision record for GitHub Actions npm trusted publishing and the first automated patch release.
|
|
17
19
|
windows-self-upgrade.md: Accepted design for synchronous and recoverable Windows native self-upgrade.
|
|
@@ -20,6 +22,8 @@ tags:
|
|
|
20
22
|
keywords:
|
|
21
23
|
- runx
|
|
22
24
|
- decisions
|
|
25
|
+
- runx init
|
|
26
|
+
- scripts directory
|
|
23
27
|
- mirror push
|
|
24
28
|
- windows self-upgrade
|
|
25
29
|
flags: []
|