@herbertgao/pi-impeccable 0.0.0-stage → 0.0.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/LICENSE +191 -0
- package/NOTICE.md +11 -0
- package/README.md +33 -2
- package/package.json +51 -4
- package/skills/impeccable/SKILL.md +89 -0
- package/skills/impeccable/reference/adapt.md +318 -0
- package/skills/impeccable/reference/adapt.native.md +58 -0
- package/skills/impeccable/reference/android.md +46 -0
- package/skills/impeccable/reference/animate.md +89 -0
- package/skills/impeccable/reference/audit.md +139 -0
- package/skills/impeccable/reference/audit.native.md +139 -0
- package/skills/impeccable/reference/bolder.md +33 -0
- package/skills/impeccable/reference/clarify.md +94 -0
- package/skills/impeccable/reference/colorize.md +86 -0
- package/skills/impeccable/reference/component-review.md +63 -0
- package/skills/impeccable/reference/craft-floor.md +44 -0
- package/skills/impeccable/reference/craft.md +5 -0
- package/skills/impeccable/reference/critique.md +819 -0
- package/skills/impeccable/reference/degraded/asset-producer.md +42 -0
- package/skills/impeccable/reference/degraded/documenter.md +24 -0
- package/skills/impeccable/reference/degraded/finish-reviewer.md +38 -0
- package/skills/impeccable/reference/degraded/manual-edit-applier.md +92 -0
- package/skills/impeccable/reference/delight.md +70 -0
- package/skills/impeccable/reference/distill.md +111 -0
- package/skills/impeccable/reference/doctor.md +54 -0
- package/skills/impeccable/reference/document.md +416 -0
- package/skills/impeccable/reference/extract.md +69 -0
- package/skills/impeccable/reference/generate.md +101 -0
- package/skills/impeccable/reference/harden.md +362 -0
- package/skills/impeccable/reference/hooks.md +114 -0
- package/skills/impeccable/reference/init.md +131 -0
- package/skills/impeccable/reference/ios.md +51 -0
- package/skills/impeccable/reference/layout.md +84 -0
- package/skills/impeccable/reference/live-setup.md +104 -0
- package/skills/impeccable/reference/live.md +325 -0
- package/skills/impeccable/reference/mode-operate.md +21 -0
- package/skills/impeccable/reference/mode-persuade.md +19 -0
- package/skills/impeccable/reference/mode-read.md +21 -0
- package/skills/impeccable/reference/new-work.md +152 -0
- package/skills/impeccable/reference/onboard.md +234 -0
- package/skills/impeccable/reference/operate.md +61 -0
- package/skills/impeccable/reference/optimize.md +257 -0
- package/skills/impeccable/reference/overdrive.md +127 -0
- package/skills/impeccable/reference/polish.md +105 -0
- package/skills/impeccable/reference/quieter.md +99 -0
- package/skills/impeccable/reference/region-map.md +26 -0
- package/skills/impeccable/reference/routing.md +24 -0
- package/skills/impeccable/reference/shape.md +59 -0
- package/skills/impeccable/reference/typeset.md +90 -0
- package/skills/impeccable/reference/visualize.md +47 -0
- package/skills/impeccable/scripts/VERSION +1 -0
- package/skills/impeccable/scripts/command-metadata.json +98 -0
- package/skills/impeccable/scripts/data/font-index-failures.json +121 -0
- package/skills/impeccable/scripts/data/font-index.json +1 -0
- package/skills/impeccable/scripts/engine-checksums.txt +9 -0
- package/skills/impeccable/scripts/impeccable +249 -0
- package/skills/impeccable/scripts/impeccable.cmd +278 -0
- package/skills/impeccable/scripts/live-browser-dom.js +320 -0
- package/skills/impeccable/scripts/live-browser-ignores.js +246 -0
- package/skills/impeccable/scripts/live-browser-session.js +183 -0
- package/skills/impeccable/scripts/live-browser.js +13645 -0
- package/skills/impeccable/scripts/modern-screenshot.umd.js +14 -0
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# Engine binary digests for the pinned ENGINE_VERSION: <engine-version> <asset> <sha256>.
|
|
2
|
+
# The launchers, the npm shim, `impeccable install` and scripts/fetch-engine.mjs verify
|
|
3
|
+
# every engine download against this file. Written by
|
|
4
|
+
# `node scripts/check-engine-release.mjs --record` after each engine release.
|
|
5
|
+
0.1.18 impeccable-darwin-arm64 543ee2f72036ad185dc9991ac3ba86b74d91f988f3d497776a088b8b65c8a9e1
|
|
6
|
+
0.1.18 impeccable-darwin-x64 1f1eee78c142f7e40e16f481aeeeb1fad1d8515d8a1ef033d7c6d133e52232b3
|
|
7
|
+
0.1.18 impeccable-linux-x64 736ed785e74ae2344d3036127f614ddde5ab520a527d8bc82a891612ef71f648
|
|
8
|
+
0.1.18 impeccable-linux-arm64 317cb18d64b0f7715681dd6e574ad64b2adb5a6caf8e7a1b3b57965f805404be
|
|
9
|
+
0.1.18 impeccable-windows-x64.exe 8f61e96b0c97001546a824d79b44f46b423b560f3eb1a0cc44a8695a1b395d9f
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
# Impeccable launcher. Runs the platform binary shipped next to this script:
|
|
3
|
+
# <this dir>/bin/<os>-<arch>/impeccable
|
|
4
|
+
# Order: $IMPECCABLE_BIN, the sibling binary, ~/.impeccable/bin/impeccable,
|
|
5
|
+
# the version-pinned cache, then `impeccable` on PATH. Never needs Node.
|
|
6
|
+
# The unversioned home binary and the PATH candidate are validated with the
|
|
7
|
+
# engine-probe handshake first: the retired 3.x npm CLI also installed a bin
|
|
8
|
+
# named `impeccable`, and exec'ing it would fail every verb with
|
|
9
|
+
# "Unknown command". Trusted candidates (IMPECCABLE_BIN, the sibling binary,
|
|
10
|
+
# the version-pinned cache) are exec'd without a probe: hooks run them on
|
|
11
|
+
# every edit and must stay fast. The version-pinned cache and the download are
|
|
12
|
+
# verified against engine-checksums.txt (next to this script), never against
|
|
13
|
+
# anything published beside the binary; a <binary>.verified stamp records that
|
|
14
|
+
# a cached binary passed, so only the first run hashes it.
|
|
15
|
+
set -eu
|
|
16
|
+
|
|
17
|
+
# True when the candidate answers the engine handshake (prints
|
|
18
|
+
# "impeccable-engine <version>", exit 0). Quiet and fast (<100ms).
|
|
19
|
+
# IMPECCABLE_LAUNCHER_PROBE marks the child as a probe: a copy of this
|
|
20
|
+
# launcher reached recursively (e.g. symlinked onto PATH as `impeccable`)
|
|
21
|
+
# then skips its own probes and refuses to download, so probing stays cheap
|
|
22
|
+
# and can never loop.
|
|
23
|
+
probe_ok() {
|
|
24
|
+
probe_out=$(IMPECCABLE_LAUNCHER_PROBE=1 "$1" engine-probe 2>/dev/null) || return 1
|
|
25
|
+
case "$probe_out" in
|
|
26
|
+
impeccable-engine*) return 0 ;;
|
|
27
|
+
esac
|
|
28
|
+
return 1
|
|
29
|
+
}
|
|
30
|
+
probing=${IMPECCABLE_LAUNCHER_PROBE:-}
|
|
31
|
+
|
|
32
|
+
# Prints the digest engine-checksums.txt records for engine version $1 and
|
|
33
|
+
# asset $2 (lines are "<version> <asset> <sha256>"), nothing when there is none.
|
|
34
|
+
# A CR is a separator too (CRLF checkouts), and a last line with no newline
|
|
35
|
+
# still counts.
|
|
36
|
+
manifest_digest() {
|
|
37
|
+
[ -f "$manifest" ] || return 0
|
|
38
|
+
while IFS="$(printf ' \t\r')" read -r m_version m_asset m_sum _ || [ -n "$m_version" ]; do
|
|
39
|
+
case "$m_version" in ''|'#'*) continue ;; esac
|
|
40
|
+
if [ "$m_version" = "$1" ] && [ "$m_asset" = "$2" ]; then
|
|
41
|
+
printf '%s' "$m_sum"
|
|
42
|
+
return 0
|
|
43
|
+
fi
|
|
44
|
+
done < "$manifest"
|
|
45
|
+
return 0
|
|
46
|
+
}
|
|
47
|
+
# Sets $expected (and, on Windows on ARM, which runs x64 binaries,
|
|
48
|
+
# $expected_x64) from engine-checksums.txt. Only called off the stamped fast
|
|
49
|
+
# path: hooks run this launcher on every edit.
|
|
50
|
+
read_expected() {
|
|
51
|
+
expected=$(manifest_digest "$version" "$asset")
|
|
52
|
+
expected_x64=""
|
|
53
|
+
if [ "$os" = windows ] && [ "$arch" = arm64 ]; then
|
|
54
|
+
expected_x64=$(manifest_digest "$version" impeccable-windows-x64.exe)
|
|
55
|
+
fi
|
|
56
|
+
}
|
|
57
|
+
# Sets $actual to the sha256 of $1, empty when no hash tool works.
|
|
58
|
+
hash_file() {
|
|
59
|
+
actual=""
|
|
60
|
+
if command -v shasum >/dev/null 2>&1; then
|
|
61
|
+
if digest=$(shasum -a 256 "$1" 2>/dev/null); then actual=${digest%% *}; fi
|
|
62
|
+
elif command -v sha256sum >/dev/null 2>&1; then
|
|
63
|
+
if digest=$(sha256sum "$1" 2>/dev/null); then actual=${digest%% *}; fi
|
|
64
|
+
fi
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
dir=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
|
|
68
|
+
manifest="$dir/engine-checksums.txt"
|
|
69
|
+
|
|
70
|
+
# What the binary needs to know about its home: the skill directory (for
|
|
71
|
+
# reference/*.md and command-metadata.json) and how to name itself in the
|
|
72
|
+
# commands it prints. Exported BEFORE any exec below, including the
|
|
73
|
+
# IMPECCABLE_BIN override: an engine binary reached with no IMPECCABLE_SKILL_DIR
|
|
74
|
+
# cannot find reference/*.md (so native platform refs never inline) or read its
|
|
75
|
+
# own version (so UPDATE_AVAILABLE never fires). Setting it here covers every
|
|
76
|
+
# candidate the launcher can exec.
|
|
77
|
+
: "${IMPECCABLE_SKILL_DIR:=$(CDPATH= cd -- "$dir/.." && pwd)}"
|
|
78
|
+
: "${IMPECCABLE_SELF:=$0}"
|
|
79
|
+
export IMPECCABLE_SKILL_DIR IMPECCABLE_SELF
|
|
80
|
+
|
|
81
|
+
if [ -n "${IMPECCABLE_BIN:-}" ] && [ -x "${IMPECCABLE_BIN}" ]; then
|
|
82
|
+
exec "${IMPECCABLE_BIN}" "$@"
|
|
83
|
+
fi
|
|
84
|
+
|
|
85
|
+
case "$(uname -s 2>/dev/null || echo unknown)" in
|
|
86
|
+
Darwin) os=darwin ;;
|
|
87
|
+
Linux) os=linux ;;
|
|
88
|
+
MINGW*|MSYS*|CYGWIN*|Windows_NT) os=windows ;;
|
|
89
|
+
*) os=unknown ;;
|
|
90
|
+
esac
|
|
91
|
+
case "$(uname -m 2>/dev/null || echo unknown)" in
|
|
92
|
+
arm64|aarch64) arch=arm64 ;;
|
|
93
|
+
x86_64|amd64) arch=x64 ;;
|
|
94
|
+
*) arch=unknown ;;
|
|
95
|
+
esac
|
|
96
|
+
|
|
97
|
+
bin="$dir/bin/$os-$arch/impeccable"
|
|
98
|
+
[ "$os" = windows ] && bin="$bin.exe"
|
|
99
|
+
|
|
100
|
+
if [ -x "$bin" ]; then
|
|
101
|
+
exec "$bin" "$@"
|
|
102
|
+
fi
|
|
103
|
+
if [ -f "$bin" ]; then
|
|
104
|
+
# Lost the executable bit in transit (zip extraction, some copiers).
|
|
105
|
+
chmod +x "$bin" 2>/dev/null && exec "$bin" "$@"
|
|
106
|
+
fi
|
|
107
|
+
# On Windows (an MSYS/Git Bash shell) the cached names carry .exe so this
|
|
108
|
+
# launcher and impeccable.cmd share one cache.
|
|
109
|
+
exe=""
|
|
110
|
+
[ "$os" = windows ] && exe=".exe"
|
|
111
|
+
home_bin="${HOME:-/nonexistent}/.impeccable/bin/impeccable$exe"
|
|
112
|
+
if [ -z "$probing" ] && [ -x "$home_bin" ] && probe_ok "$home_bin"; then
|
|
113
|
+
exec "$home_bin" "$@"
|
|
114
|
+
fi
|
|
115
|
+
# Version-pinned user cache, filled by the download below or by `impeccable update`.
|
|
116
|
+
version=""
|
|
117
|
+
[ -f "$dir/VERSION" ] && version=$(tr -d '[:space:]' < "$dir/VERSION")
|
|
118
|
+
cache_root="${IMPECCABLE_HOME:-${HOME:-/nonexistent}/.impeccable}"
|
|
119
|
+
cached="$cache_root/bin/$version/impeccable$exe"
|
|
120
|
+
asset="impeccable-$os-$arch"
|
|
121
|
+
[ "$os" = windows ] && asset="$asset.exe"
|
|
122
|
+
if [ -n "$version" ] && [ -x "$cached" ]; then
|
|
123
|
+
if [ -f "$cached.verified" ]; then
|
|
124
|
+
exec "$cached" "$@"
|
|
125
|
+
fi
|
|
126
|
+
read_expected
|
|
127
|
+
hash_file "$cached"
|
|
128
|
+
if [ -n "$actual" ] && { [ "$actual" = "$expected" ] || [ "$actual" = "$expected_x64" ]; }; then
|
|
129
|
+
{ echo "$actual" > "$cached.verified"; } 2>/dev/null || :
|
|
130
|
+
exec "$cached" "$@"
|
|
131
|
+
fi
|
|
132
|
+
echo "impeccable: cannot verify the cached engine $cached against $manifest; not using it" >&2
|
|
133
|
+
fi
|
|
134
|
+
if [ -z "$probing" ] && command -v impeccable >/dev/null 2>&1 && probe_ok impeccable; then
|
|
135
|
+
exec impeccable "$@"
|
|
136
|
+
fi
|
|
137
|
+
|
|
138
|
+
# Last resort: fetch this version's binary for the current platform from the
|
|
139
|
+
# public release channel into the user cache. Needs network; sandboxes without
|
|
140
|
+
# egress preinstall the binary on PATH instead.
|
|
141
|
+
setup_help() {
|
|
142
|
+
echo "Engine $version setup needs network access and write permission to $cache_root/bin/$version." >&2
|
|
143
|
+
echo "Run this launcher ($0) with engine-probe in a terminal that has those permissions, then retry the original command." >&2
|
|
144
|
+
echo "Alternatively, set IMPECCABLE_HOME to a writable cache location, or IMPECCABLE_BIN to a preinstalled engine binary." >&2
|
|
145
|
+
}
|
|
146
|
+
fetch_url() {
|
|
147
|
+
if command -v curl >/dev/null 2>&1; then
|
|
148
|
+
curl -fsSL --retry 2 -o "$tmp" "$1" 2>/dev/null
|
|
149
|
+
elif command -v wget >/dev/null 2>&1; then
|
|
150
|
+
wget -q -O "$tmp" "$1" 2>/dev/null
|
|
151
|
+
else
|
|
152
|
+
return 1
|
|
153
|
+
fi
|
|
154
|
+
}
|
|
155
|
+
check_download() {
|
|
156
|
+
download_file=${1:-$tmp}
|
|
157
|
+
if [ ! -f "$download_file" ]; then
|
|
158
|
+
echo "impeccable: download completed but the file was removed before execution: $url; check your antivirus quarantine or logs. Refusing to continue; do not disable protection." >&2
|
|
159
|
+
exit 127
|
|
160
|
+
fi
|
|
161
|
+
if [ ! -s "$download_file" ]; then
|
|
162
|
+
rm -f "$download_file"
|
|
163
|
+
echo "impeccable: downloaded file is empty: $url; refusing the unverified download" >&2
|
|
164
|
+
exit 127
|
|
165
|
+
fi
|
|
166
|
+
}
|
|
167
|
+
if [ -n "$probing" ]; then
|
|
168
|
+
# Inside another launcher's probe: no download, fail fast and quiet.
|
|
169
|
+
exit 127
|
|
170
|
+
fi
|
|
171
|
+
if [ -n "$version" ] && [ "$os" != unknown ] && [ "$arch" != unknown ]; then
|
|
172
|
+
base="${IMPECCABLE_DOWNLOAD_BASE:-https://github.com/pbakaus/impeccable/releases/download}"
|
|
173
|
+
url="$base/engine-v$version/$asset"
|
|
174
|
+
read_expected
|
|
175
|
+
# Fail closed before any network traffic or cache write.
|
|
176
|
+
if [ -z "$expected" ] && [ -z "$expected_x64" ]; then
|
|
177
|
+
echo "impeccable: no checksum for engine $version ($asset) in $manifest; refusing the unverified download" >&2
|
|
178
|
+
exit 127
|
|
179
|
+
fi
|
|
180
|
+
tmp="$cache_root/bin/$version/.impeccable.part.$$"
|
|
181
|
+
# An interrupted download (Ctrl-C, a hook timeout) would otherwise leave the
|
|
182
|
+
# PID-named staging file behind for good. The handlers must exit explicitly.
|
|
183
|
+
cleanup() { rm -f "$tmp" 2>/dev/null || :; }
|
|
184
|
+
trap 'cleanup; exit 129' HUP
|
|
185
|
+
trap 'cleanup; exit 130' INT
|
|
186
|
+
trap 'cleanup; exit 143' TERM
|
|
187
|
+
if ! mkdir -p "$cache_root/bin/$version" 2>/dev/null; then
|
|
188
|
+
echo "impeccable: engine $version is not installed; cannot create cache directory: $cache_root/bin/$version" >&2
|
|
189
|
+
setup_help
|
|
190
|
+
exit 127
|
|
191
|
+
fi
|
|
192
|
+
# Check the actual staging file, not just directory existence: a cache from
|
|
193
|
+
# an earlier run can be readable but no longer writable inside a sandbox.
|
|
194
|
+
if ! (umask 077; : > "$tmp") 2>/dev/null; then
|
|
195
|
+
echo "impeccable: engine $version is not installed; cannot write to cache directory: $cache_root/bin/$version" >&2
|
|
196
|
+
setup_help
|
|
197
|
+
exit 127
|
|
198
|
+
fi
|
|
199
|
+
fetched=0
|
|
200
|
+
if [ -n "$expected" ] && fetch_url "$url"; then
|
|
201
|
+
fetched=1
|
|
202
|
+
elif [ -n "$expected_x64" ]; then
|
|
203
|
+
# Windows on ARM runs x64 binaries; fall back when no arm64 asset exists.
|
|
204
|
+
url="$base/engine-v$version/impeccable-windows-x64.exe"
|
|
205
|
+
expected=$expected_x64
|
|
206
|
+
fetch_url "$url" && fetched=1
|
|
207
|
+
fi
|
|
208
|
+
if [ "$fetched" = 1 ]; then
|
|
209
|
+
check_download
|
|
210
|
+
# No sha256 tool refuses the download too.
|
|
211
|
+
hash_file "$tmp"
|
|
212
|
+
check_download
|
|
213
|
+
if [ -z "$actual" ]; then
|
|
214
|
+
rm -f "$tmp"
|
|
215
|
+
echo "impeccable: cannot verify $url (no sha256 tool, or hashing failed); refusing the unverified download" >&2
|
|
216
|
+
exit 127
|
|
217
|
+
fi
|
|
218
|
+
if [ "$actual" != "$expected" ]; then
|
|
219
|
+
rm -f "$tmp"
|
|
220
|
+
echo "impeccable: checksum mismatch downloading $url" >&2
|
|
221
|
+
exit 127
|
|
222
|
+
fi
|
|
223
|
+
check_download
|
|
224
|
+
if ! chmod +x "$tmp" 2>/dev/null; then
|
|
225
|
+
check_download
|
|
226
|
+
rm -f "$tmp"
|
|
227
|
+
echo "impeccable: could not make the verified download executable: $url" >&2
|
|
228
|
+
exit 127
|
|
229
|
+
fi
|
|
230
|
+
check_download
|
|
231
|
+
if ! mv -f "$tmp" "$cached" 2>/dev/null; then
|
|
232
|
+
check_download
|
|
233
|
+
rm -f "$tmp"
|
|
234
|
+
echo "impeccable: could not cache the verified download: $url" >&2
|
|
235
|
+
exit 127
|
|
236
|
+
fi
|
|
237
|
+
check_download "$cached"
|
|
238
|
+
{ echo "$actual" > "$cached.verified"; } 2>/dev/null || :
|
|
239
|
+
exec "$cached" "$@"
|
|
240
|
+
fi
|
|
241
|
+
rm -f "$tmp" 2>/dev/null
|
|
242
|
+
echo "impeccable: could not download engine $version from $url; check network access, the release URL, and curl or wget availability." >&2
|
|
243
|
+
setup_help
|
|
244
|
+
exit 127
|
|
245
|
+
fi
|
|
246
|
+
|
|
247
|
+
echo "impeccable: no engine binary for $os-$arch found (looked in $bin, $cached, PATH)." >&2
|
|
248
|
+
echo "Download impeccable-$os-$arch from https://github.com/pbakaus/impeccable/releases (tag engine-v$version) into $cache_root/bin/$version/impeccable$exe (then chmod +x), or set IMPECCABLE_BIN to a preinstalled engine binary. Docs: https://impeccable.style" >&2
|
|
249
|
+
exit 127
|
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
@echo off
|
|
2
|
+
setlocal
|
|
3
|
+
rem Impeccable launcher (Windows). Runs bin\windows-<arch>\impeccable.exe next
|
|
4
|
+
rem to this file, else a cached or freshly downloaded engine binary.
|
|
5
|
+
rem
|
|
6
|
+
rem Structure notes (this file is exercised by dry parsing and string-level
|
|
7
|
+
rem tests, not yet on a real Windows machine):
|
|
8
|
+
rem - No multi-line parenthesized blocks: cmd expands %var% at block parse
|
|
9
|
+
rem time, which made the old download path read back empty %url%/%cached%.
|
|
10
|
+
rem Linear goto flow keeps every expansion on its own line, and avoids
|
|
11
|
+
rem delayed expansion eating ! characters in user arguments.
|
|
12
|
+
rem - The unversioned user binary and the PATH candidate are validated with
|
|
13
|
+
rem the engine-probe handshake (see :probe) so the retired 3.x npm CLI,
|
|
14
|
+
rem whose bin is also named impeccable, is never exec'd. IMPECCABLE_BIN,
|
|
15
|
+
rem the sibling binary, and the version-pinned cache stay trusted.
|
|
16
|
+
rem - Downloads and the version-pinned cache are verified via certutil
|
|
17
|
+
rem against engine-checksums.txt next to this file, and fail closed; a
|
|
18
|
+
rem .verified stamp lets later runs skip hashing the cache. On ARM64 the
|
|
19
|
+
rem arm64 asset is tried first and the x64 asset is the fallback (Windows on
|
|
20
|
+
rem ARM runs x64 binaries), each only when the manifest has a line for it.
|
|
21
|
+
if not defined IMPECCABLE_SKILL_DIR set "IMPECCABLE_SKILL_DIR=%~dp0.."
|
|
22
|
+
if not defined IMPECCABLE_SELF set "IMPECCABLE_SELF=%~f0"
|
|
23
|
+
set "arch=x64"
|
|
24
|
+
if /I "%PROCESSOR_ARCHITECTURE%"=="ARM64" set "arch=arm64"
|
|
25
|
+
|
|
26
|
+
if not defined IMPECCABLE_BIN goto no_env_bin
|
|
27
|
+
if not exist "%IMPECCABLE_BIN%" goto no_env_bin
|
|
28
|
+
set "run=%IMPECCABLE_BIN%"
|
|
29
|
+
goto run
|
|
30
|
+
:no_env_bin
|
|
31
|
+
|
|
32
|
+
set "bin=%~dp0bin\windows-%arch%\impeccable.exe"
|
|
33
|
+
if not exist "%bin%" goto no_sibling
|
|
34
|
+
set "run=%bin%"
|
|
35
|
+
goto run
|
|
36
|
+
:no_sibling
|
|
37
|
+
|
|
38
|
+
set "home_bin=%USERPROFILE%\.impeccable\bin\impeccable.exe"
|
|
39
|
+
if not exist "%home_bin%" goto no_home_bin
|
|
40
|
+
if defined IMPECCABLE_LAUNCHER_PROBE goto no_home_bin
|
|
41
|
+
call :probe "%home_bin%"
|
|
42
|
+
if not "%probe_ok%"=="1" goto no_home_bin
|
|
43
|
+
set "run=%home_bin%"
|
|
44
|
+
goto run
|
|
45
|
+
:no_home_bin
|
|
46
|
+
|
|
47
|
+
set "version="
|
|
48
|
+
if exist "%~dp0VERSION" set /p version=<"%~dp0VERSION"
|
|
49
|
+
if not defined IMPECCABLE_HOME set "IMPECCABLE_HOME=%USERPROFILE%\.impeccable"
|
|
50
|
+
set "cached=%IMPECCABLE_HOME%\bin\%version%\impeccable.exe"
|
|
51
|
+
set "asset=impeccable-windows-%arch%.exe"
|
|
52
|
+
set "manifest=%~dp0engine-checksums.txt"
|
|
53
|
+
if not defined version goto no_cache
|
|
54
|
+
if not exist "%cached%" goto no_cache
|
|
55
|
+
if exist "%cached%.verified" goto cache_trusted
|
|
56
|
+
call :read_expected
|
|
57
|
+
call :sha256 "%cached%" "%TEMP%\impeccable-hash-%RANDOM%%RANDOM%.txt"
|
|
58
|
+
if not defined actual goto cache_unverified
|
|
59
|
+
if /I "%actual%"=="%expected%" goto cache_verified
|
|
60
|
+
if /I "%actual%"=="%expected_x64%" goto cache_verified
|
|
61
|
+
:cache_unverified
|
|
62
|
+
echo impeccable: cannot verify the cached engine "%cached%" against "%manifest%"; not using it 1>&2
|
|
63
|
+
goto no_cache
|
|
64
|
+
:cache_verified
|
|
65
|
+
(>"%cached%.verified" echo %actual%) 2>nul
|
|
66
|
+
:cache_trusted
|
|
67
|
+
set "run=%cached%"
|
|
68
|
+
goto run
|
|
69
|
+
:no_cache
|
|
70
|
+
|
|
71
|
+
if defined IMPECCABLE_LAUNCHER_PROBE goto download
|
|
72
|
+
where impeccable >nul 2>nul
|
|
73
|
+
if errorlevel 1 goto download
|
|
74
|
+
call :probe impeccable
|
|
75
|
+
if not "%probe_ok%"=="1" goto download
|
|
76
|
+
impeccable %*
|
|
77
|
+
exit /b %errorlevel%
|
|
78
|
+
|
|
79
|
+
:download
|
|
80
|
+
rem Last resort: fetch this version's binary from the release channel into
|
|
81
|
+
rem the version-pinned user cache, verify it, then run it. Never inside
|
|
82
|
+
rem another launcher's probe: fail fast and quiet instead.
|
|
83
|
+
if defined IMPECCABLE_LAUNCHER_PROBE exit /b 127
|
|
84
|
+
if not defined version goto fail
|
|
85
|
+
call :read_expected
|
|
86
|
+
if not defined expected if not defined expected_x64 goto no_checksum
|
|
87
|
+
where curl.exe >nul 2>nul
|
|
88
|
+
if errorlevel 1 goto curl_missing
|
|
89
|
+
if not defined IMPECCABLE_DOWNLOAD_BASE set "IMPECCABLE_DOWNLOAD_BASE=https://github.com/pbakaus/impeccable/releases/download"
|
|
90
|
+
if exist "%IMPECCABLE_HOME%\bin\%version%\" goto cache_ready
|
|
91
|
+
mkdir "%IMPECCABLE_HOME%\bin\%version%" >nul 2>nul
|
|
92
|
+
if errorlevel 1 goto cache_directory_failed
|
|
93
|
+
:cache_ready
|
|
94
|
+
rem Stage the download in a directory only this run owns, as the sh launcher
|
|
95
|
+
rem does with .impeccable.part.$$: concurrent first runs (parallel hooks, two
|
|
96
|
+
rem agents) must never write, hash or move each other's files. mkdir fails
|
|
97
|
+
rem when the name exists, so it claims the name atomically. RANDOM alone is
|
|
98
|
+
rem not enough because cmd seeds it from the clock in whole seconds; the
|
|
99
|
+
rem timestamp and the retry on collision keep same-second runs apart. A cache
|
|
100
|
+
rem directory that refuses every mkdir is reported as unwritable.
|
|
101
|
+
set "attempt=0"
|
|
102
|
+
:claim_staging
|
|
103
|
+
set /a attempt+=1
|
|
104
|
+
if %attempt% GTR 20 goto cache_write_failed
|
|
105
|
+
set "stamp=%TIME: =0%"
|
|
106
|
+
set "stamp=%stamp::=%"
|
|
107
|
+
set "stamp=%stamp:.=%"
|
|
108
|
+
set "stamp=%stamp:,=%"
|
|
109
|
+
set "staging=%IMPECCABLE_HOME%\bin\%version%\.impeccable.part.%stamp%-%RANDOM%%RANDOM%"
|
|
110
|
+
mkdir "%staging%" >nul 2>nul
|
|
111
|
+
if errorlevel 1 goto claim_staging
|
|
112
|
+
set "part=%staging%\impeccable.exe"
|
|
113
|
+
rem Redirection failures do not reliably update ERRORLEVEL in cmd.exe;
|
|
114
|
+
rem branch on the command's failure directly.
|
|
115
|
+
(type nul >"%part%") 2>nul || goto staging_write_failed
|
|
116
|
+
set "url=%IMPECCABLE_DOWNLOAD_BASE%/engine-v%version%/%asset%"
|
|
117
|
+
if not defined expected goto fetch_x64
|
|
118
|
+
curl.exe -fsSL -o "%part%" "%url%" >nul 2>nul
|
|
119
|
+
if not errorlevel 1 goto verify
|
|
120
|
+
:fetch_x64
|
|
121
|
+
if not defined expected_x64 goto download_failed
|
|
122
|
+
set "asset=impeccable-windows-x64.exe"
|
|
123
|
+
set "expected=%expected_x64%"
|
|
124
|
+
set "url=%IMPECCABLE_DOWNLOAD_BASE%/engine-v%version%/%asset%"
|
|
125
|
+
curl.exe -fsSL -o "%part%" "%url%" >nul 2>nul
|
|
126
|
+
if errorlevel 1 goto download_failed
|
|
127
|
+
|
|
128
|
+
:verify
|
|
129
|
+
call :check_download
|
|
130
|
+
if errorlevel 1 exit /b 127
|
|
131
|
+
rem Mirrors the sh launcher and fails closed: a freshly downloaded binary
|
|
132
|
+
rem runs only after its hash matches the digest read from engine-checksums.txt.
|
|
133
|
+
rem An empty certutil result refuses the download instead of running an
|
|
134
|
+
rem unverified binary.
|
|
135
|
+
call :sha256 "%part%" "%staging%\hash.txt"
|
|
136
|
+
call :check_download
|
|
137
|
+
if errorlevel 1 exit /b 127
|
|
138
|
+
if not defined actual goto verify_refuse
|
|
139
|
+
if /I "%actual%"=="%expected%" goto place
|
|
140
|
+
call :discard_staging
|
|
141
|
+
echo impeccable: checksum mismatch downloading %url% 1>&2
|
|
142
|
+
exit /b 127
|
|
143
|
+
|
|
144
|
+
:verify_refuse
|
|
145
|
+
call :check_download
|
|
146
|
+
if errorlevel 1 exit /b 127
|
|
147
|
+
call :discard_staging
|
|
148
|
+
echo impeccable: cannot verify %url% (certutil could not hash it); refusing the unverified download 1>&2
|
|
149
|
+
exit /b 127
|
|
150
|
+
|
|
151
|
+
:read_expected
|
|
152
|
+
rem Sets expected (and, on ARM64, expected_x64: Windows on ARM runs x64
|
|
153
|
+
rem binaries) from engine-checksums.txt. Only called off the stamped path:
|
|
154
|
+
rem hooks run this launcher on every edit.
|
|
155
|
+
call :manifest_digest "%asset%" expected
|
|
156
|
+
set "expected_x64="
|
|
157
|
+
if "%arch%"=="arm64" call :manifest_digest impeccable-windows-x64.exe expected_x64
|
|
158
|
+
exit /b 0
|
|
159
|
+
|
|
160
|
+
:manifest_digest
|
|
161
|
+
rem Sets the variable named %2 to the digest the first engine-checksums.txt
|
|
162
|
+
rem line for this version and asset %1 records, empty when there is none.
|
|
163
|
+
set "%~2="
|
|
164
|
+
if not exist "%manifest%" exit /b 0
|
|
165
|
+
for /f "usebackq tokens=1-3" %%a in ("%manifest%") do if "%%a"=="%version%" if /I "%%b"=="%~1" if not defined %~2 set "%~2=%%c"
|
|
166
|
+
exit /b 0
|
|
167
|
+
|
|
168
|
+
:sha256
|
|
169
|
+
rem Sets actual to the sha256 of %~1, empty when certutil fails. %~2 is the
|
|
170
|
+
rem scratch file for its output. Check certutil's status before parsing: its
|
|
171
|
+
rem error text on stdout is not a digest.
|
|
172
|
+
set "actual="
|
|
173
|
+
certutil -hashfile "%~1" SHA256 >"%~2" 2>nul
|
|
174
|
+
if errorlevel 1 goto sha256_done
|
|
175
|
+
for /f "usebackq skip=1 delims=" %%h in ("%~2") do if not defined actual set "actual=%%h"
|
|
176
|
+
if not defined actual goto sha256_done
|
|
177
|
+
set "actual=%actual: =%"
|
|
178
|
+
:sha256_done
|
|
179
|
+
del "%~2" >nul 2>nul
|
|
180
|
+
exit /b 0
|
|
181
|
+
|
|
182
|
+
:check_download
|
|
183
|
+
set "download_file=%~1"
|
|
184
|
+
if not defined download_file set "download_file=%part%"
|
|
185
|
+
if not exist "%download_file%" goto download_missing
|
|
186
|
+
for %%f in ("%download_file%") do if %%~zf==0 goto download_empty
|
|
187
|
+
exit /b 0
|
|
188
|
+
|
|
189
|
+
:download_missing
|
|
190
|
+
call :discard_staging
|
|
191
|
+
echo impeccable: download completed but the file was removed before execution: %url%; check your antivirus quarantine or logs. Refusing to continue; do not disable protection. 1>&2
|
|
192
|
+
exit /b 127
|
|
193
|
+
|
|
194
|
+
:download_empty
|
|
195
|
+
del "%download_file%" >nul 2>nul
|
|
196
|
+
call :discard_staging
|
|
197
|
+
echo impeccable: downloaded file is empty: %url%; refusing the unverified download 1>&2
|
|
198
|
+
exit /b 127
|
|
199
|
+
|
|
200
|
+
:discard_staging
|
|
201
|
+
rem Removes this run's staging directory and whatever is left in it. Never
|
|
202
|
+
rem touches another run's staging directory or the cached binary.
|
|
203
|
+
if defined staging rd /s /q "%staging%" >nul 2>nul
|
|
204
|
+
exit /b 0
|
|
205
|
+
|
|
206
|
+
:place
|
|
207
|
+
call :check_download
|
|
208
|
+
if errorlevel 1 exit /b 127
|
|
209
|
+
move /y "%part%" "%cached%" >nul 2>nul
|
|
210
|
+
if errorlevel 1 goto place_failed
|
|
211
|
+
call :discard_staging
|
|
212
|
+
call :check_download "%cached%"
|
|
213
|
+
if errorlevel 1 exit /b 127
|
|
214
|
+
(>"%cached%.verified" echo %actual%) 2>nul
|
|
215
|
+
set "run=%cached%"
|
|
216
|
+
goto run
|
|
217
|
+
|
|
218
|
+
:place_failed
|
|
219
|
+
call :check_download
|
|
220
|
+
if errorlevel 1 exit /b 127
|
|
221
|
+
call :discard_staging
|
|
222
|
+
echo impeccable: could not cache the verified download: %url% 1>&2
|
|
223
|
+
exit /b 127
|
|
224
|
+
|
|
225
|
+
:run
|
|
226
|
+
"%run%" %*
|
|
227
|
+
exit /b %errorlevel%
|
|
228
|
+
|
|
229
|
+
:probe
|
|
230
|
+
rem Sets probe_ok=1 when %1 answers the engine handshake: prints
|
|
231
|
+
rem "impeccable-engine <version>" and exits 0. The 3.x npm CLI answers any
|
|
232
|
+
rem unknown verb with "Unknown command", exit 1, so it never passes.
|
|
233
|
+
set "probe_ok="
|
|
234
|
+
set "probe_tmp=%TEMP%\impeccable-probe-%RANDOM%%RANDOM%.txt"
|
|
235
|
+
set "IMPECCABLE_LAUNCHER_PROBE=1"
|
|
236
|
+
"%~1" engine-probe >"%probe_tmp%" 2>nul
|
|
237
|
+
set "probe_err=%ERRORLEVEL%"
|
|
238
|
+
set "IMPECCABLE_LAUNCHER_PROBE="
|
|
239
|
+
if not "%probe_err%"=="0" goto probe_done
|
|
240
|
+
findstr /b /c:"impeccable-engine" "%probe_tmp%" >nul 2>nul
|
|
241
|
+
if not errorlevel 1 set "probe_ok=1"
|
|
242
|
+
:probe_done
|
|
243
|
+
del "%probe_tmp%" >nul 2>nul
|
|
244
|
+
exit /b 0
|
|
245
|
+
|
|
246
|
+
:no_checksum
|
|
247
|
+
echo impeccable: no checksum for engine %version% (%asset%) in "%manifest%"; refusing the unverified download 1>&2
|
|
248
|
+
exit /b 127
|
|
249
|
+
|
|
250
|
+
:cache_directory_failed
|
|
251
|
+
echo impeccable: engine %version% is not installed; cannot create cache directory: "%IMPECCABLE_HOME%\bin\%version%" 1>&2
|
|
252
|
+
goto setup_failed
|
|
253
|
+
|
|
254
|
+
:staging_write_failed
|
|
255
|
+
call :discard_staging
|
|
256
|
+
|
|
257
|
+
:cache_write_failed
|
|
258
|
+
echo impeccable: engine %version% is not installed; cannot write to cache directory: "%IMPECCABLE_HOME%\bin\%version%" 1>&2
|
|
259
|
+
goto setup_failed
|
|
260
|
+
|
|
261
|
+
:curl_missing
|
|
262
|
+
echo impeccable: cannot download engine %version%; curl.exe is unavailable. 1>&2
|
|
263
|
+
goto setup_failed
|
|
264
|
+
|
|
265
|
+
:download_failed
|
|
266
|
+
call :discard_staging
|
|
267
|
+
echo impeccable: could not download engine %version% from %url%; check network access and the release URL. 1>&2
|
|
268
|
+
|
|
269
|
+
:setup_failed
|
|
270
|
+
echo Engine %version% setup needs network access and write permission to "%IMPECCABLE_HOME%\bin\%version%". 1>&2
|
|
271
|
+
echo Run this launcher ("%~f0") with engine-probe in a terminal that has those permissions, then retry the original command. 1>&2
|
|
272
|
+
echo Alternatively, set IMPECCABLE_HOME to a writable cache location, or IMPECCABLE_BIN to a preinstalled engine binary. 1>&2
|
|
273
|
+
exit /b 127
|
|
274
|
+
|
|
275
|
+
:fail
|
|
276
|
+
echo impeccable: no engine binary found (looked in %bin%, %cached%, PATH). 1>&2
|
|
277
|
+
echo Download impeccable-windows-%arch%.exe from https://github.com/pbakaus/impeccable/releases (tag engine-v%version%) and save it as %cached%, or set IMPECCABLE_BIN to a preinstalled engine binary. Docs: https://impeccable.style 1>&2
|
|
278
|
+
exit /b 127
|