@qpfai/pf-gate-cli 1.0.64 → 1.0.65-darwin-x64
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/README.md +11 -77
- package/package.json +8 -19
- package/vendor/x86_64-apple-darwin/pf-gate/pf-gate +165 -0
- package/vendor/x86_64-apple-darwin/python/persons_field-1.0.0-py3-none-any.whl +0 -0
- package/bin/pf.mjs +0 -10
- package/lib/main.mjs +0 -648
- /package/vendor/{.keep → x86_64-apple-darwin/path/.keep} +0 -0
package/README.md
CHANGED
|
@@ -1,81 +1,15 @@
|
|
|
1
|
-
# @qpfai/pf-gate-cli
|
|
1
|
+
# @qpfai/pf-gate-cli (darwin-x64)
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Platform runtime payload for PF Gate CLI.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
The bundled launcher at `vendor/<target-triple>/pf-gate/` runs PF Gate through Python.
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
```
|
|
7
|
+
Default install source:
|
|
8
|
+
- bundled wheel: `vendor/<target-triple>/python/persons_field-1.0.0-py3-none-any.whl`
|
|
10
9
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
```
|
|
18
|
-
|
|
19
|
-
`pf gate` checks npm for a newer `@qpfai/pf-gate-cli` release on startup and
|
|
20
|
-
auto-installs updates before launching UX.
|
|
21
|
-
To disable this behavior, set `PF_GATE_DISABLE_AUTO_UPDATE=1`.
|
|
22
|
-
|
|
23
|
-
Run direct CLI commands:
|
|
24
|
-
|
|
25
|
-
```bash
|
|
26
|
-
pf --version
|
|
27
|
-
pf gate --selftest
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
The launcher resolves a platform package at install time and executes a bundled runtime binary at run time.
|
|
31
|
-
On first run, it bootstraps a per-user runtime environment under `~/.pf-gate/runtime/.venv`.
|
|
32
|
-
|
|
33
|
-
## Maintainer release flow
|
|
34
|
-
|
|
35
|
-
Set the release version for all npm package manifests:
|
|
36
|
-
|
|
37
|
-
```bash
|
|
38
|
-
node npm/tools/set-version.mjs 1.0.0
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
Validate release topology without publishing:
|
|
42
|
-
|
|
43
|
-
```bash
|
|
44
|
-
node npm/tools/publish-all.mjs --dry-run
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
`publish-all.mjs` rebuilds `persons_field-1.0.0-py3-none-any.whl` from current source
|
|
48
|
-
and syncs it into every platform package before validation/publish.
|
|
49
|
-
|
|
50
|
-
The dry run warns on placeholder runtime payloads by default.
|
|
51
|
-
To fail dry run on placeholders, use:
|
|
52
|
-
|
|
53
|
-
```bash
|
|
54
|
-
node npm/tools/publish-all.mjs --dry-run --strict-placeholder-check
|
|
55
|
-
```
|
|
56
|
-
|
|
57
|
-
Publish all platform variants, then the meta package:
|
|
58
|
-
|
|
59
|
-
```bash
|
|
60
|
-
node npm/tools/publish-all.mjs --registry=https://registry.npmjs.org/
|
|
61
|
-
```
|
|
62
|
-
|
|
63
|
-
Release tags used by default:
|
|
64
|
-
- platform payload packages: `platform`
|
|
65
|
-
- meta package: `latest`
|
|
66
|
-
|
|
67
|
-
With npm passkey/WebAuthn 2FA:
|
|
68
|
-
|
|
69
|
-
```bash
|
|
70
|
-
cd "/Users/nicholashuunguyen/Documents/PF Gate/PF Gate V7"
|
|
71
|
-
node npm/tools/publish-all.mjs --registry=https://registry.npmjs.org/
|
|
72
|
-
npm view @qpfai/pf-gate-cli version --registry=https://registry.npmjs.org/
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
If npm prompts with `Authenticate your account at ... Press ENTER to open in the browser...`,
|
|
76
|
-
press Enter and approve with your passkey in the browser.
|
|
77
|
-
|
|
78
|
-
Each platform package must contain:
|
|
79
|
-
|
|
80
|
-
- `vendor/<target-triple>/pf-gate/<binary>`
|
|
81
|
-
- optional helper tools in `vendor/<target-triple>/path/`
|
|
10
|
+
Runtime behavior:
|
|
11
|
+
- Uses `PF_GATE_PYTHON` when set.
|
|
12
|
+
- Otherwise creates/uses a per-user runtime venv at `~/.pf-gate/runtime/.venv` (or `PF_GATE_RUNTIME_HOME/.venv`).
|
|
13
|
+
- Installs from bundled wheel by default.
|
|
14
|
+
- Optional override: set `PF_GATE_PIP_SPEC` to force a different install source.
|
|
15
|
+
- Starts `persons_field.terminal.launcher` with forwarded arguments.
|
package/package.json
CHANGED
|
@@ -1,33 +1,22 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@qpfai/pf-gate-cli",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"description": "PF Gate
|
|
3
|
+
"version": "1.0.65-darwin-x64",
|
|
4
|
+
"description": "PF Gate runtime payload for darwin x64.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
7
|
-
"
|
|
8
|
-
"
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
"os": [
|
|
8
|
+
"darwin"
|
|
9
|
+
],
|
|
10
|
+
"cpu": [
|
|
11
|
+
"x64"
|
|
12
|
+
],
|
|
11
13
|
"files": [
|
|
12
|
-
"bin",
|
|
13
|
-
"lib",
|
|
14
14
|
"vendor",
|
|
15
15
|
"README.md"
|
|
16
16
|
],
|
|
17
|
-
"scripts": {
|
|
18
|
-
"test": "node --test tests/*.test.mjs"
|
|
19
|
-
},
|
|
20
17
|
"engines": {
|
|
21
18
|
"node": ">=18"
|
|
22
19
|
},
|
|
23
|
-
"optionalDependencies": {
|
|
24
|
-
"@qpfai/pf-gate-cli-linux-x64": "npm:@qpfai/pf-gate-cli@1.0.64-linux-x64",
|
|
25
|
-
"@qpfai/pf-gate-cli-linux-arm64": "npm:@qpfai/pf-gate-cli@1.0.64-linux-arm64",
|
|
26
|
-
"@qpfai/pf-gate-cli-darwin-x64": "npm:@qpfai/pf-gate-cli@1.0.64-darwin-x64",
|
|
27
|
-
"@qpfai/pf-gate-cli-darwin-arm64": "npm:@qpfai/pf-gate-cli@1.0.64-darwin-arm64",
|
|
28
|
-
"@qpfai/pf-gate-cli-win32-x64": "npm:@qpfai/pf-gate-cli@1.0.64-win32-x64",
|
|
29
|
-
"@qpfai/pf-gate-cli-win32-arm64": "npm:@qpfai/pf-gate-cli@1.0.64-win32-arm64"
|
|
30
|
-
},
|
|
31
20
|
"publishConfig": {
|
|
32
21
|
"access": "public"
|
|
33
22
|
}
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
#!/usr/bin/env sh
|
|
2
|
+
set -eu
|
|
3
|
+
|
|
4
|
+
SCRIPT_DIR="$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)"
|
|
5
|
+
BUNDLED_WHEEL="$SCRIPT_DIR/../python/persons_field-1.0.0-py3-none-any.whl"
|
|
6
|
+
USER_HOME="${HOME:-}"
|
|
7
|
+
RUNTIME_HOME="${PF_GATE_RUNTIME_HOME:-}"
|
|
8
|
+
if [ -z "$RUNTIME_HOME" ] && [ -n "$USER_HOME" ]; then
|
|
9
|
+
RUNTIME_HOME="$USER_HOME/.pf-gate/runtime"
|
|
10
|
+
fi
|
|
11
|
+
WHEEL_STAMP_FILE=""
|
|
12
|
+
if [ -n "$RUNTIME_HOME" ]; then
|
|
13
|
+
WHEEL_STAMP_FILE="$RUNTIME_HOME/.bundled-wheel.sha256"
|
|
14
|
+
fi
|
|
15
|
+
SYSTEM_PYTHON=""
|
|
16
|
+
VENV_DIR=""
|
|
17
|
+
IS_MANAGED_VENV=0
|
|
18
|
+
|
|
19
|
+
resolve_system_python() {
|
|
20
|
+
if command -v python3 >/dev/null 2>&1; then
|
|
21
|
+
printf '%s' "python3"
|
|
22
|
+
return 0
|
|
23
|
+
fi
|
|
24
|
+
if command -v python >/dev/null 2>&1; then
|
|
25
|
+
printf '%s' "python"
|
|
26
|
+
return 0
|
|
27
|
+
fi
|
|
28
|
+
return 1
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
sha256_file() {
|
|
32
|
+
file_path="$1"
|
|
33
|
+
if command -v shasum >/dev/null 2>&1; then
|
|
34
|
+
shasum -a 256 "$file_path" | awk '{print $1}'
|
|
35
|
+
return 0
|
|
36
|
+
fi
|
|
37
|
+
if command -v sha256sum >/dev/null 2>&1; then
|
|
38
|
+
sha256sum "$file_path" | awk '{print $1}'
|
|
39
|
+
return 0
|
|
40
|
+
fi
|
|
41
|
+
if command -v openssl >/dev/null 2>&1; then
|
|
42
|
+
openssl dgst -sha256 "$file_path" | awk '{print $NF}'
|
|
43
|
+
return 0
|
|
44
|
+
fi
|
|
45
|
+
return 1
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
read_wheel_stamp() {
|
|
49
|
+
if [ -z "$WHEEL_STAMP_FILE" ] || [ ! -f "$WHEEL_STAMP_FILE" ]; then
|
|
50
|
+
return 0
|
|
51
|
+
fi
|
|
52
|
+
head -n 1 "$WHEEL_STAMP_FILE" 2>/dev/null || true
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
write_wheel_stamp() {
|
|
56
|
+
wheel_hash="$1"
|
|
57
|
+
if [ -z "$WHEEL_STAMP_FILE" ] || [ -z "$wheel_hash" ]; then
|
|
58
|
+
return 0
|
|
59
|
+
fi
|
|
60
|
+
mkdir -p "$(dirname "$WHEEL_STAMP_FILE")"
|
|
61
|
+
printf '%s\n' "$wheel_hash" >"$WHEEL_STAMP_FILE" || true
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
PYTHON_BIN="${PF_GATE_PYTHON:-}"
|
|
65
|
+
if [ -z "$PYTHON_BIN" ]; then
|
|
66
|
+
SYSTEM_PYTHON="$(resolve_system_python || true)"
|
|
67
|
+
if [ -z "$SYSTEM_PYTHON" ]; then
|
|
68
|
+
echo "PF Gate runtime error: Python 3.13+ not found. Install Python or set PF_GATE_PYTHON." >&2
|
|
69
|
+
exit 1
|
|
70
|
+
fi
|
|
71
|
+
|
|
72
|
+
if [ -z "$USER_HOME" ] && [ -z "${PF_GATE_RUNTIME_HOME:-}" ]; then
|
|
73
|
+
echo "PF Gate runtime error: HOME is not set. Set PF_GATE_RUNTIME_HOME or PF_GATE_PYTHON." >&2
|
|
74
|
+
exit 1
|
|
75
|
+
fi
|
|
76
|
+
|
|
77
|
+
if [ -z "$RUNTIME_HOME" ]; then
|
|
78
|
+
RUNTIME_HOME="$USER_HOME/.pf-gate/runtime"
|
|
79
|
+
fi
|
|
80
|
+
VENV_DIR="$RUNTIME_HOME/.venv"
|
|
81
|
+
IS_MANAGED_VENV=1
|
|
82
|
+
PYTHON_BIN="$VENV_DIR/bin/python"
|
|
83
|
+
|
|
84
|
+
if [ ! -x "$PYTHON_BIN" ]; then
|
|
85
|
+
echo "PF Gate runtime: creating runtime environment at $VENV_DIR" >&2
|
|
86
|
+
mkdir -p "$RUNTIME_HOME"
|
|
87
|
+
if ! "$SYSTEM_PYTHON" -m venv "$VENV_DIR"; then
|
|
88
|
+
echo "PF Gate runtime error: failed to create runtime environment at $VENV_DIR" >&2
|
|
89
|
+
exit 1
|
|
90
|
+
fi
|
|
91
|
+
fi
|
|
92
|
+
fi
|
|
93
|
+
|
|
94
|
+
PIP_TARGET="${PF_GATE_PIP_SPEC:-$BUNDLED_WHEEL}"
|
|
95
|
+
if [ -z "${PF_GATE_PIP_SPEC:-}" ] && [ ! -f "$BUNDLED_WHEEL" ]; then
|
|
96
|
+
echo "PF Gate runtime error: missing bundled wheel at $BUNDLED_WHEEL" >&2
|
|
97
|
+
exit 1
|
|
98
|
+
fi
|
|
99
|
+
|
|
100
|
+
BUNDLED_HASH=""
|
|
101
|
+
if [ -z "${PF_GATE_PIP_SPEC:-}" ] && [ -f "$BUNDLED_WHEEL" ]; then
|
|
102
|
+
BUNDLED_HASH="$(sha256_file "$BUNDLED_WHEEL" 2>/dev/null || true)"
|
|
103
|
+
fi
|
|
104
|
+
|
|
105
|
+
NEEDS_INSTALL=0
|
|
106
|
+
FORCE_REINSTALL=0
|
|
107
|
+
INSTALL_REASON="persons_field is missing"
|
|
108
|
+
if ! "$PYTHON_BIN" -c "import persons_field.terminal.launcher" >/dev/null 2>&1; then
|
|
109
|
+
NEEDS_INSTALL=1
|
|
110
|
+
elif [ -z "${PF_GATE_PIP_SPEC:-}" ] && [ -n "$BUNDLED_HASH" ]; then
|
|
111
|
+
STORED_HASH="$(read_wheel_stamp)"
|
|
112
|
+
if [ "$STORED_HASH" != "$BUNDLED_HASH" ]; then
|
|
113
|
+
NEEDS_INSTALL=1
|
|
114
|
+
FORCE_REINSTALL=1
|
|
115
|
+
INSTALL_REASON="bundled runtime payload changed"
|
|
116
|
+
fi
|
|
117
|
+
fi
|
|
118
|
+
|
|
119
|
+
if [ "$NEEDS_INSTALL" -eq 1 ]; then
|
|
120
|
+
echo "PF Gate runtime: ${INSTALL_REASON}; installing ${PIP_TARGET}..." >&2
|
|
121
|
+
FORCE_PIP_REINSTALL="$FORCE_REINSTALL"
|
|
122
|
+
if [ "$FORCE_REINSTALL" -eq 1 ] && [ "$IS_MANAGED_VENV" -eq 1 ] && [ -n "$SYSTEM_PYTHON" ] && [ -n "$VENV_DIR" ]; then
|
|
123
|
+
echo "PF Gate runtime: refreshing runtime environment at $VENV_DIR" >&2
|
|
124
|
+
rm -rf "$VENV_DIR"
|
|
125
|
+
mkdir -p "$RUNTIME_HOME"
|
|
126
|
+
if ! "$SYSTEM_PYTHON" -m venv "$VENV_DIR"; then
|
|
127
|
+
echo "PF Gate runtime error: failed to refresh runtime environment at $VENV_DIR" >&2
|
|
128
|
+
exit 1
|
|
129
|
+
fi
|
|
130
|
+
PYTHON_BIN="$VENV_DIR/bin/python"
|
|
131
|
+
FORCE_PIP_REINSTALL=0
|
|
132
|
+
fi
|
|
133
|
+
if ! "$PYTHON_BIN" -m pip --version >/dev/null 2>&1; then
|
|
134
|
+
"$PYTHON_BIN" -m ensurepip --upgrade >/dev/null 2>&1 || true
|
|
135
|
+
fi
|
|
136
|
+
if [ "$FORCE_PIP_REINSTALL" -eq 1 ]; then
|
|
137
|
+
if ! "$PYTHON_BIN" -m pip install --upgrade --force-reinstall --disable-pip-version-check "$PIP_TARGET"; then
|
|
138
|
+
if [ "$IS_MANAGED_VENV" -eq 1 ]; then
|
|
139
|
+
echo "PF Gate runtime error: failed to install ${PIP_TARGET}. Set PF_GATE_PYTHON and PF_GATE_PIP_SPEC, then retry." >&2
|
|
140
|
+
exit 1
|
|
141
|
+
fi
|
|
142
|
+
if ! "$PYTHON_BIN" -m pip install --user --upgrade --force-reinstall --disable-pip-version-check "$PIP_TARGET"; then
|
|
143
|
+
echo "PF Gate runtime error: failed to install ${PIP_TARGET}. Set PF_GATE_PYTHON and PF_GATE_PIP_SPEC, then retry." >&2
|
|
144
|
+
exit 1
|
|
145
|
+
fi
|
|
146
|
+
fi
|
|
147
|
+
else
|
|
148
|
+
if ! "$PYTHON_BIN" -m pip install --upgrade --disable-pip-version-check "$PIP_TARGET"; then
|
|
149
|
+
if [ "$IS_MANAGED_VENV" -eq 1 ]; then
|
|
150
|
+
echo "PF Gate runtime error: failed to install ${PIP_TARGET}. Set PF_GATE_PYTHON and PF_GATE_PIP_SPEC, then retry." >&2
|
|
151
|
+
exit 1
|
|
152
|
+
fi
|
|
153
|
+
if ! "$PYTHON_BIN" -m pip install --user --upgrade --disable-pip-version-check "$PIP_TARGET"; then
|
|
154
|
+
echo "PF Gate runtime error: failed to install ${PIP_TARGET}. Set PF_GATE_PYTHON and PF_GATE_PIP_SPEC, then retry." >&2
|
|
155
|
+
exit 1
|
|
156
|
+
fi
|
|
157
|
+
fi
|
|
158
|
+
fi
|
|
159
|
+
fi
|
|
160
|
+
|
|
161
|
+
if [ -z "${PF_GATE_PIP_SPEC:-}" ] && [ -n "$BUNDLED_HASH" ]; then
|
|
162
|
+
write_wheel_stamp "$BUNDLED_HASH"
|
|
163
|
+
fi
|
|
164
|
+
|
|
165
|
+
exec "$PYTHON_BIN" -m persons_field.terminal.launcher "$@"
|
package/bin/pf.mjs
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
import { runCli } from "../lib/main.mjs";
|
|
4
|
-
|
|
5
|
-
runCli(process.argv.slice(2)).catch((error) => {
|
|
6
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
7
|
-
console.error(`PF Gate launcher error: ${message}`);
|
|
8
|
-
process.exit(1);
|
|
9
|
-
});
|
|
10
|
-
|
package/lib/main.mjs
DELETED
|
@@ -1,648 +0,0 @@
|
|
|
1
|
-
import { spawn, spawnSync } from "node:child_process";
|
|
2
|
-
import { existsSync } from "node:fs";
|
|
3
|
-
import path from "node:path";
|
|
4
|
-
import process from "node:process";
|
|
5
|
-
import { createInterface } from "node:readline";
|
|
6
|
-
import { createRequire } from "node:module";
|
|
7
|
-
import { fileURLToPath } from "node:url";
|
|
8
|
-
|
|
9
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
10
|
-
const __dirname = path.dirname(__filename);
|
|
11
|
-
const PACKAGE_ROOT = path.resolve(__dirname, "..");
|
|
12
|
-
const require = createRequire(import.meta.url);
|
|
13
|
-
const NPM_REGISTRY = "https://registry.npmjs.org/";
|
|
14
|
-
const CLI_PACKAGE_NAME = "@qpfai/pf-gate-cli";
|
|
15
|
-
const CLI_PACKAGE_VERSION = (() => {
|
|
16
|
-
try {
|
|
17
|
-
const packageJson = require(path.join(PACKAGE_ROOT, "package.json"));
|
|
18
|
-
return String(packageJson?.version || "").trim();
|
|
19
|
-
} catch {
|
|
20
|
-
return "";
|
|
21
|
-
}
|
|
22
|
-
})();
|
|
23
|
-
|
|
24
|
-
export function resolveCliPackageVersion() {
|
|
25
|
-
return CLI_PACKAGE_VERSION;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
function envFlagEnabled(value) {
|
|
29
|
-
return /^(1|true|yes|on)$/i.test(String(value || "").trim());
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
function parseVersion(rawVersion) {
|
|
33
|
-
const normalized = String(rawVersion || "")
|
|
34
|
-
.trim()
|
|
35
|
-
.replace(/^v/i, "");
|
|
36
|
-
const [coreRaw, prereleaseRaw = ""] = normalized.split("-", 2);
|
|
37
|
-
const core = coreRaw
|
|
38
|
-
.split(".")
|
|
39
|
-
.map((segment) => Number.parseInt(segment, 10))
|
|
40
|
-
.map((value) => (Number.isFinite(value) ? value : 0))
|
|
41
|
-
.slice(0, 3);
|
|
42
|
-
while (core.length < 3) {
|
|
43
|
-
core.push(0);
|
|
44
|
-
}
|
|
45
|
-
return {
|
|
46
|
-
core,
|
|
47
|
-
prerelease: prereleaseRaw.trim(),
|
|
48
|
-
};
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
export function compareCliVersions(left, right) {
|
|
52
|
-
const a = parseVersion(left);
|
|
53
|
-
const b = parseVersion(right);
|
|
54
|
-
for (let index = 0; index < 3; index += 1) {
|
|
55
|
-
if (a.core[index] > b.core[index]) {
|
|
56
|
-
return 1;
|
|
57
|
-
}
|
|
58
|
-
if (a.core[index] < b.core[index]) {
|
|
59
|
-
return -1;
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
if (!a.prerelease && !b.prerelease) {
|
|
63
|
-
return 0;
|
|
64
|
-
}
|
|
65
|
-
if (!a.prerelease) {
|
|
66
|
-
return 1;
|
|
67
|
-
}
|
|
68
|
-
if (!b.prerelease) {
|
|
69
|
-
return -1;
|
|
70
|
-
}
|
|
71
|
-
return a.prerelease.localeCompare(b.prerelease, undefined, {
|
|
72
|
-
numeric: true,
|
|
73
|
-
sensitivity: "base",
|
|
74
|
-
});
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
function normalizeVersionValue(raw) {
|
|
78
|
-
if (typeof raw === "string") {
|
|
79
|
-
return raw.trim();
|
|
80
|
-
}
|
|
81
|
-
if (Array.isArray(raw) && raw.length > 0 && typeof raw[0] === "string") {
|
|
82
|
-
return raw[0].trim();
|
|
83
|
-
}
|
|
84
|
-
return "";
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
function normalizeDistTagsValue(raw) {
|
|
88
|
-
if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
|
|
89
|
-
return {};
|
|
90
|
-
}
|
|
91
|
-
const parsed = {};
|
|
92
|
-
for (const [key, value] of Object.entries(raw)) {
|
|
93
|
-
const tag = String(key || "").trim();
|
|
94
|
-
const version = String(value || "").trim();
|
|
95
|
-
if (!tag || !version) {
|
|
96
|
-
continue;
|
|
97
|
-
}
|
|
98
|
-
parsed[tag] = version;
|
|
99
|
-
}
|
|
100
|
-
return parsed;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
export function resolveLatestPublishedVersion(options = {}) {
|
|
104
|
-
const packageManager = options.packageManager || "npm";
|
|
105
|
-
if (packageManager !== "npm") {
|
|
106
|
-
return "";
|
|
107
|
-
}
|
|
108
|
-
const env = options.env || process.env;
|
|
109
|
-
const runSync = options.runSync || spawnSync;
|
|
110
|
-
const timeoutMs = Number(options.timeoutMs || 5000);
|
|
111
|
-
const requestedTag = String(options.tag || "latest").trim() || "latest";
|
|
112
|
-
const packageSpecifier =
|
|
113
|
-
requestedTag === "latest" ? CLI_PACKAGE_NAME : `${CLI_PACKAGE_NAME}@${requestedTag}`;
|
|
114
|
-
const result = runSync(
|
|
115
|
-
"npm",
|
|
116
|
-
["view", packageSpecifier, "version", "--json", "--registry", NPM_REGISTRY],
|
|
117
|
-
{
|
|
118
|
-
env,
|
|
119
|
-
encoding: "utf-8",
|
|
120
|
-
timeout: timeoutMs,
|
|
121
|
-
},
|
|
122
|
-
);
|
|
123
|
-
if (result.error || (result.status ?? 1) !== 0) {
|
|
124
|
-
return "";
|
|
125
|
-
}
|
|
126
|
-
const stdout = String(result.stdout || "").trim();
|
|
127
|
-
if (!stdout) {
|
|
128
|
-
return "";
|
|
129
|
-
}
|
|
130
|
-
try {
|
|
131
|
-
return normalizeVersionValue(JSON.parse(stdout));
|
|
132
|
-
} catch {
|
|
133
|
-
return normalizeVersionValue(stdout.replace(/^"+|"+$/g, ""));
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
export function resolvePublishedDistTags(options = {}) {
|
|
138
|
-
const packageManager = options.packageManager || "npm";
|
|
139
|
-
if (packageManager !== "npm") {
|
|
140
|
-
return {};
|
|
141
|
-
}
|
|
142
|
-
const env = options.env || process.env;
|
|
143
|
-
const runSync = options.runSync || spawnSync;
|
|
144
|
-
const timeoutMs = Number(options.timeoutMs || 5000);
|
|
145
|
-
const result = runSync(
|
|
146
|
-
"npm",
|
|
147
|
-
["view", CLI_PACKAGE_NAME, "dist-tags", "--json", "--registry", NPM_REGISTRY],
|
|
148
|
-
{
|
|
149
|
-
env,
|
|
150
|
-
encoding: "utf-8",
|
|
151
|
-
timeout: timeoutMs,
|
|
152
|
-
},
|
|
153
|
-
);
|
|
154
|
-
if (result.error || (result.status ?? 1) !== 0) {
|
|
155
|
-
return {};
|
|
156
|
-
}
|
|
157
|
-
const stdout = String(result.stdout || "").trim();
|
|
158
|
-
if (!stdout) {
|
|
159
|
-
return {};
|
|
160
|
-
}
|
|
161
|
-
try {
|
|
162
|
-
return normalizeDistTagsValue(JSON.parse(stdout));
|
|
163
|
-
} catch {
|
|
164
|
-
return {};
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
export function resolveAutoUpdateTag(options = {}) {
|
|
169
|
-
const env = options.env || process.env;
|
|
170
|
-
const forcedTag = String(options.updateTag || env.PF_GATE_UPDATE_TAG || "").trim();
|
|
171
|
-
if (forcedTag) {
|
|
172
|
-
return forcedTag;
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
const distTags = normalizeDistTagsValue(options.distTags || {});
|
|
176
|
-
const currentVersion = String(options.currentVersion || "").trim();
|
|
177
|
-
if (!currentVersion || !distTags.latest) {
|
|
178
|
-
return "latest";
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
for (const [tag, version] of Object.entries(distTags)) {
|
|
182
|
-
if (version === currentVersion) {
|
|
183
|
-
return tag;
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
if (compareCliVersions(currentVersion, distTags.latest) <= 0) {
|
|
188
|
-
return "latest";
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
let selectedTag = "latest";
|
|
192
|
-
let selectedVersion = "";
|
|
193
|
-
for (const [tag, version] of Object.entries(distTags)) {
|
|
194
|
-
if (tag === "latest") {
|
|
195
|
-
continue;
|
|
196
|
-
}
|
|
197
|
-
if (compareCliVersions(version, currentVersion) <= 0) {
|
|
198
|
-
continue;
|
|
199
|
-
}
|
|
200
|
-
if (!selectedVersion || compareCliVersions(version, selectedVersion) < 0) {
|
|
201
|
-
selectedTag = tag;
|
|
202
|
-
selectedVersion = version;
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
return selectedTag;
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
export function maybeAutoUpdateCli(options = {}) {
|
|
209
|
-
const env = options.env || process.env;
|
|
210
|
-
const log =
|
|
211
|
-
typeof options.log === "function"
|
|
212
|
-
? options.log
|
|
213
|
-
: (message) => process.stderr.write(String(message));
|
|
214
|
-
if (envFlagEnabled(env.PF_GATE_DISABLE_AUTO_UPDATE)) {
|
|
215
|
-
return { updated: false, latestVersion: "" };
|
|
216
|
-
}
|
|
217
|
-
if (envFlagEnabled(env.PF_GATE_AUTO_UPDATE_APPLIED)) {
|
|
218
|
-
return { updated: false, latestVersion: "" };
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
const packageManager = options.packageManager || detectPackageManager(env) || "npm";
|
|
222
|
-
if (packageManager !== "npm") {
|
|
223
|
-
return { updated: false, latestVersion: "" };
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
const currentVersion = String(options.currentVersion || CLI_PACKAGE_VERSION).trim();
|
|
227
|
-
if (!currentVersion) {
|
|
228
|
-
return { updated: false, latestVersion: "" };
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
const runSync = options.runSync || spawnSync;
|
|
232
|
-
const latestVersionOverride = String(options.latestVersionOverride || "").trim();
|
|
233
|
-
const latestVersion =
|
|
234
|
-
latestVersionOverride ||
|
|
235
|
-
resolveLatestPublishedVersion({
|
|
236
|
-
packageManager,
|
|
237
|
-
env,
|
|
238
|
-
runSync,
|
|
239
|
-
timeoutMs: options.timeoutMs,
|
|
240
|
-
tag: options.updateTag,
|
|
241
|
-
});
|
|
242
|
-
if (!latestVersion) {
|
|
243
|
-
return { updated: false, latestVersion: "" };
|
|
244
|
-
}
|
|
245
|
-
if (compareCliVersions(latestVersion, currentVersion) <= 0) {
|
|
246
|
-
return { updated: false, latestVersion };
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
if (typeof options.shouldInstall === "function") {
|
|
250
|
-
const shouldInstall = Boolean(
|
|
251
|
-
options.shouldInstall({
|
|
252
|
-
currentVersion,
|
|
253
|
-
latestVersion,
|
|
254
|
-
packageName: CLI_PACKAGE_NAME,
|
|
255
|
-
}),
|
|
256
|
-
);
|
|
257
|
-
if (!shouldInstall) {
|
|
258
|
-
return { updated: false, latestVersion };
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
const installTarget =
|
|
263
|
-
String(options.installTarget || "").trim() || CLI_PACKAGE_NAME;
|
|
264
|
-
log(`PF Gate launcher: updating ${CLI_PACKAGE_NAME} ${currentVersion} -> ${latestVersion}...\n`);
|
|
265
|
-
const installResult = runSync(
|
|
266
|
-
"npm",
|
|
267
|
-
["install", "-g", installTarget, "--registry", NPM_REGISTRY],
|
|
268
|
-
{
|
|
269
|
-
env,
|
|
270
|
-
stdio: "inherit",
|
|
271
|
-
},
|
|
272
|
-
);
|
|
273
|
-
if (installResult.error || (installResult.status ?? 1) !== 0) {
|
|
274
|
-
log("PF Gate launcher warning: auto-update failed; continuing with installed version.\n");
|
|
275
|
-
return { updated: false, latestVersion };
|
|
276
|
-
}
|
|
277
|
-
return { updated: true, latestVersion };
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
export function resolveEffectiveCliVersion(options = {}) {
|
|
281
|
-
const env = options.env || process.env;
|
|
282
|
-
const currentVersion = String(options.currentVersion || CLI_PACKAGE_VERSION).trim();
|
|
283
|
-
const existingVersion = String(env.PF_GATE_CLI_VERSION || "").trim();
|
|
284
|
-
if (existingVersion) {
|
|
285
|
-
return existingVersion;
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
const updateResult = options.updateResult || {};
|
|
289
|
-
const updated = Boolean(updateResult.updated);
|
|
290
|
-
const latestVersion = String(updateResult.latestVersion || "").trim();
|
|
291
|
-
if (updated && latestVersion) {
|
|
292
|
-
return latestVersion;
|
|
293
|
-
}
|
|
294
|
-
return currentVersion;
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
export function promptOutputStream(primaryOut = process.stderr, secondaryOut = process.stdout) {
|
|
298
|
-
if (primaryOut?.isTTY) {
|
|
299
|
-
return primaryOut;
|
|
300
|
-
}
|
|
301
|
-
if (secondaryOut?.isTTY) {
|
|
302
|
-
return secondaryOut;
|
|
303
|
-
}
|
|
304
|
-
return primaryOut || secondaryOut;
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
export function isInteractivePrompt(
|
|
308
|
-
streamIn = process.stdin,
|
|
309
|
-
primaryOut = process.stderr,
|
|
310
|
-
secondaryOut = process.stdout,
|
|
311
|
-
) {
|
|
312
|
-
const output = promptOutputStream(primaryOut, secondaryOut);
|
|
313
|
-
return Boolean(streamIn?.isTTY && output?.isTTY);
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
async function promptYesNo(
|
|
317
|
-
message,
|
|
318
|
-
{ streamIn = process.stdin, streamOut = process.stderr, fallbackOut = process.stdout } = {},
|
|
319
|
-
) {
|
|
320
|
-
const output = promptOutputStream(streamOut, fallbackOut);
|
|
321
|
-
if (!isInteractivePrompt(streamIn, output)) {
|
|
322
|
-
return false;
|
|
323
|
-
}
|
|
324
|
-
return await new Promise((resolve) => {
|
|
325
|
-
const rl = createInterface({
|
|
326
|
-
input: streamIn,
|
|
327
|
-
output,
|
|
328
|
-
});
|
|
329
|
-
|
|
330
|
-
const ask = () => {
|
|
331
|
-
rl.question(`${message} [Y/N]: `, (rawAnswer) => {
|
|
332
|
-
const answer = String(rawAnswer || "").trim().toLowerCase();
|
|
333
|
-
if (answer === "y" || answer === "yes") {
|
|
334
|
-
rl.close();
|
|
335
|
-
resolve(true);
|
|
336
|
-
return;
|
|
337
|
-
}
|
|
338
|
-
if (answer === "n" || answer === "no") {
|
|
339
|
-
rl.close();
|
|
340
|
-
resolve(false);
|
|
341
|
-
return;
|
|
342
|
-
}
|
|
343
|
-
output.write("Please enter Y or N.\n");
|
|
344
|
-
ask();
|
|
345
|
-
});
|
|
346
|
-
};
|
|
347
|
-
|
|
348
|
-
ask();
|
|
349
|
-
});
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
function shouldAutoUpdateForArgs(args) {
|
|
353
|
-
if (!Array.isArray(args) || args.length === 0) {
|
|
354
|
-
return true;
|
|
355
|
-
}
|
|
356
|
-
const command = String(args[0] || "")
|
|
357
|
-
.trim()
|
|
358
|
-
.toLowerCase();
|
|
359
|
-
return command === "gate" || command === "ux" || command === "shell";
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
const PLATFORM_PACKAGE_BY_TARGET = Object.freeze({
|
|
363
|
-
"x86_64-unknown-linux-musl": "@qpfai/pf-gate-cli-linux-x64",
|
|
364
|
-
"aarch64-unknown-linux-musl": "@qpfai/pf-gate-cli-linux-arm64",
|
|
365
|
-
"x86_64-apple-darwin": "@qpfai/pf-gate-cli-darwin-x64",
|
|
366
|
-
"aarch64-apple-darwin": "@qpfai/pf-gate-cli-darwin-arm64",
|
|
367
|
-
"x86_64-pc-windows-msvc": "@qpfai/pf-gate-cli-win32-x64",
|
|
368
|
-
"aarch64-pc-windows-msvc": "@qpfai/pf-gate-cli-win32-arm64",
|
|
369
|
-
});
|
|
370
|
-
|
|
371
|
-
function commandForPackageManager(packageManager) {
|
|
372
|
-
if (packageManager === "bun") {
|
|
373
|
-
return "bun install -g @qpfai/pf-gate-cli";
|
|
374
|
-
}
|
|
375
|
-
return "npm install -g @qpfai/pf-gate-cli";
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
function firstExisting(paths, existsSyncFn) {
|
|
379
|
-
for (const candidate of paths) {
|
|
380
|
-
if (existsSyncFn(candidate)) {
|
|
381
|
-
return candidate;
|
|
382
|
-
}
|
|
383
|
-
}
|
|
384
|
-
return null;
|
|
385
|
-
}
|
|
386
|
-
|
|
387
|
-
export function resolveTargetTriple(platform = process.platform, arch = process.arch) {
|
|
388
|
-
switch (platform) {
|
|
389
|
-
case "linux":
|
|
390
|
-
case "android":
|
|
391
|
-
if (arch === "x64") {
|
|
392
|
-
return "x86_64-unknown-linux-musl";
|
|
393
|
-
}
|
|
394
|
-
if (arch === "arm64") {
|
|
395
|
-
return "aarch64-unknown-linux-musl";
|
|
396
|
-
}
|
|
397
|
-
return null;
|
|
398
|
-
case "darwin":
|
|
399
|
-
if (arch === "x64") {
|
|
400
|
-
return "x86_64-apple-darwin";
|
|
401
|
-
}
|
|
402
|
-
if (arch === "arm64") {
|
|
403
|
-
return "aarch64-apple-darwin";
|
|
404
|
-
}
|
|
405
|
-
return null;
|
|
406
|
-
case "win32":
|
|
407
|
-
if (arch === "x64") {
|
|
408
|
-
return "x86_64-pc-windows-msvc";
|
|
409
|
-
}
|
|
410
|
-
if (arch === "arm64") {
|
|
411
|
-
return "aarch64-pc-windows-msvc";
|
|
412
|
-
}
|
|
413
|
-
return null;
|
|
414
|
-
default:
|
|
415
|
-
return null;
|
|
416
|
-
}
|
|
417
|
-
}
|
|
418
|
-
|
|
419
|
-
export function packageAliasForTarget(targetTriple) {
|
|
420
|
-
return PLATFORM_PACKAGE_BY_TARGET[targetTriple] || null;
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
export function binaryNameCandidates(platform = process.platform) {
|
|
424
|
-
if (platform === "win32") {
|
|
425
|
-
return ["pf-gate.exe", "pf-gate.cmd", "pf-gate.bat"];
|
|
426
|
-
}
|
|
427
|
-
return ["pf-gate"];
|
|
428
|
-
}
|
|
429
|
-
|
|
430
|
-
export function prependPath(existingPath, newDirs, platform = process.platform) {
|
|
431
|
-
const separator = platform === "win32" ? ";" : ":";
|
|
432
|
-
const current = String(existingPath || "")
|
|
433
|
-
.split(separator)
|
|
434
|
-
.filter(Boolean);
|
|
435
|
-
return [...newDirs, ...current].join(separator);
|
|
436
|
-
}
|
|
437
|
-
|
|
438
|
-
export function detectPackageManager(env = process.env, dirnameHint = __dirname) {
|
|
439
|
-
const userAgent = String(env.npm_config_user_agent || "");
|
|
440
|
-
if (/\bbun\//.test(userAgent)) {
|
|
441
|
-
return "bun";
|
|
442
|
-
}
|
|
443
|
-
const execPath = String(env.npm_execpath || "");
|
|
444
|
-
if (execPath.includes("bun")) {
|
|
445
|
-
return "bun";
|
|
446
|
-
}
|
|
447
|
-
if (
|
|
448
|
-
dirnameHint.includes(".bun/install/global") ||
|
|
449
|
-
dirnameHint.includes(".bun\\install\\global")
|
|
450
|
-
) {
|
|
451
|
-
return "bun";
|
|
452
|
-
}
|
|
453
|
-
if (userAgent) {
|
|
454
|
-
return "npm";
|
|
455
|
-
}
|
|
456
|
-
return null;
|
|
457
|
-
}
|
|
458
|
-
|
|
459
|
-
export function shouldUseShellForBinary(binaryPath, platform = process.platform) {
|
|
460
|
-
if (platform !== "win32") {
|
|
461
|
-
return false;
|
|
462
|
-
}
|
|
463
|
-
return /\.(cmd|bat)$/i.test(binaryPath);
|
|
464
|
-
}
|
|
465
|
-
|
|
466
|
-
export function resolveRuntimeBinary(options = {}) {
|
|
467
|
-
const platform = options.platform || process.platform;
|
|
468
|
-
const arch = options.arch || process.arch;
|
|
469
|
-
const packageRoot = options.packageRoot || PACKAGE_ROOT;
|
|
470
|
-
const existsSyncFn = options.existsSync || existsSync;
|
|
471
|
-
const requireResolve = options.requireResolve || ((specifier) => require.resolve(specifier));
|
|
472
|
-
|
|
473
|
-
const targetTriple = resolveTargetTriple(platform, arch);
|
|
474
|
-
if (!targetTriple) {
|
|
475
|
-
throw new Error(`Unsupported platform: ${platform} (${arch})`);
|
|
476
|
-
}
|
|
477
|
-
|
|
478
|
-
const packageAlias = packageAliasForTarget(targetTriple);
|
|
479
|
-
if (!packageAlias) {
|
|
480
|
-
throw new Error(`Unsupported target triple: ${targetTriple}`);
|
|
481
|
-
}
|
|
482
|
-
|
|
483
|
-
const names = binaryNameCandidates(platform);
|
|
484
|
-
const localVendorRoot = path.join(packageRoot, "vendor");
|
|
485
|
-
const localBinaryCandidates = names.map((name) =>
|
|
486
|
-
path.join(localVendorRoot, targetTriple, "pf-gate", name),
|
|
487
|
-
);
|
|
488
|
-
|
|
489
|
-
let vendorRoot = null;
|
|
490
|
-
try {
|
|
491
|
-
const packageJsonPath = requireResolve(`${packageAlias}/package.json`);
|
|
492
|
-
vendorRoot = path.join(path.dirname(packageJsonPath), "vendor");
|
|
493
|
-
} catch {
|
|
494
|
-
const localBinary = firstExisting(localBinaryCandidates, existsSyncFn);
|
|
495
|
-
if (localBinary) {
|
|
496
|
-
vendorRoot = localVendorRoot;
|
|
497
|
-
}
|
|
498
|
-
}
|
|
499
|
-
|
|
500
|
-
if (!vendorRoot) {
|
|
501
|
-
const packageManager = detectPackageManager();
|
|
502
|
-
const reinstallCommand = commandForPackageManager(packageManager);
|
|
503
|
-
throw new Error(
|
|
504
|
-
`Missing optional dependency ${packageAlias}. Reinstall PF Gate CLI: ${reinstallCommand}`,
|
|
505
|
-
);
|
|
506
|
-
}
|
|
507
|
-
|
|
508
|
-
const binaryCandidates = names.map((name) => path.join(vendorRoot, targetTriple, "pf-gate", name));
|
|
509
|
-
const binaryPath = firstExisting(binaryCandidates, existsSyncFn);
|
|
510
|
-
if (!binaryPath) {
|
|
511
|
-
throw new Error(
|
|
512
|
-
`PF Gate binary missing for ${targetTriple}. Expected one of: ${binaryCandidates.join(", ")}`,
|
|
513
|
-
);
|
|
514
|
-
}
|
|
515
|
-
|
|
516
|
-
const pathDir = path.join(vendorRoot, targetTriple, "path");
|
|
517
|
-
const additionalPathDirs = existsSyncFn(pathDir) ? [pathDir] : [];
|
|
518
|
-
return {
|
|
519
|
-
targetTriple,
|
|
520
|
-
packageAlias,
|
|
521
|
-
vendorRoot,
|
|
522
|
-
binaryPath,
|
|
523
|
-
additionalPathDirs,
|
|
524
|
-
};
|
|
525
|
-
}
|
|
526
|
-
|
|
527
|
-
function forwardSignal(child, signal) {
|
|
528
|
-
if (child.killed) {
|
|
529
|
-
return;
|
|
530
|
-
}
|
|
531
|
-
try {
|
|
532
|
-
child.kill(signal);
|
|
533
|
-
} catch {
|
|
534
|
-
// Ignore child process signaling failures.
|
|
535
|
-
}
|
|
536
|
-
}
|
|
537
|
-
|
|
538
|
-
export async function runCli(args) {
|
|
539
|
-
const env = { ...process.env };
|
|
540
|
-
const packageManager = detectPackageManager(env);
|
|
541
|
-
const effectivePackageManager = packageManager || "npm";
|
|
542
|
-
const shouldAutoUpdate = shouldAutoUpdateForArgs(args);
|
|
543
|
-
const currentVersion = String(CLI_PACKAGE_VERSION || "").trim();
|
|
544
|
-
let updateTag = "latest";
|
|
545
|
-
|
|
546
|
-
let approvedUpdate = true;
|
|
547
|
-
let latestVersionHint = "";
|
|
548
|
-
if (
|
|
549
|
-
shouldAutoUpdate &&
|
|
550
|
-
effectivePackageManager === "npm" &&
|
|
551
|
-
currentVersion &&
|
|
552
|
-
!envFlagEnabled(env.PF_GATE_DISABLE_AUTO_UPDATE) &&
|
|
553
|
-
!envFlagEnabled(env.PF_GATE_AUTO_UPDATE_APPLIED)
|
|
554
|
-
) {
|
|
555
|
-
const distTags = resolvePublishedDistTags({
|
|
556
|
-
packageManager: effectivePackageManager,
|
|
557
|
-
env,
|
|
558
|
-
runSync: spawnSync,
|
|
559
|
-
});
|
|
560
|
-
updateTag = resolveAutoUpdateTag({
|
|
561
|
-
currentVersion,
|
|
562
|
-
distTags,
|
|
563
|
-
env,
|
|
564
|
-
});
|
|
565
|
-
latestVersionHint = resolveLatestPublishedVersion({
|
|
566
|
-
packageManager: effectivePackageManager,
|
|
567
|
-
env,
|
|
568
|
-
runSync: spawnSync,
|
|
569
|
-
tag: updateTag,
|
|
570
|
-
});
|
|
571
|
-
if (!latestVersionHint && updateTag !== "latest") {
|
|
572
|
-
updateTag = "latest";
|
|
573
|
-
latestVersionHint = resolveLatestPublishedVersion({
|
|
574
|
-
packageManager: effectivePackageManager,
|
|
575
|
-
env,
|
|
576
|
-
runSync: spawnSync,
|
|
577
|
-
tag: updateTag,
|
|
578
|
-
});
|
|
579
|
-
}
|
|
580
|
-
if (latestVersionHint && compareCliVersions(latestVersionHint, currentVersion) > 0) {
|
|
581
|
-
const tagHint = updateTag === "latest" ? "" : ` [channel: ${updateTag}]`;
|
|
582
|
-
approvedUpdate = await promptYesNo(
|
|
583
|
-
`PF Gate launcher: update available ${CLI_PACKAGE_NAME} ${currentVersion} -> ${latestVersionHint}${tagHint}. Update now?`,
|
|
584
|
-
);
|
|
585
|
-
}
|
|
586
|
-
}
|
|
587
|
-
|
|
588
|
-
const installTarget =
|
|
589
|
-
updateTag === "latest" ? CLI_PACKAGE_NAME : `${CLI_PACKAGE_NAME}@${updateTag}`;
|
|
590
|
-
const updateResult = shouldAutoUpdate
|
|
591
|
-
? maybeAutoUpdateCli({
|
|
592
|
-
currentVersion: CLI_PACKAGE_VERSION,
|
|
593
|
-
packageManager: effectivePackageManager,
|
|
594
|
-
env,
|
|
595
|
-
latestVersionOverride: latestVersionHint,
|
|
596
|
-
updateTag,
|
|
597
|
-
installTarget,
|
|
598
|
-
shouldInstall: () => approvedUpdate,
|
|
599
|
-
})
|
|
600
|
-
: { updated: false, latestVersion: "" };
|
|
601
|
-
|
|
602
|
-
if (updateResult.updated) {
|
|
603
|
-
env.PF_GATE_AUTO_UPDATE_APPLIED = "1";
|
|
604
|
-
}
|
|
605
|
-
env.PF_GATE_CLI_VERSION = resolveEffectiveCliVersion({
|
|
606
|
-
env,
|
|
607
|
-
currentVersion: CLI_PACKAGE_VERSION,
|
|
608
|
-
updateResult,
|
|
609
|
-
});
|
|
610
|
-
|
|
611
|
-
const runtime = resolveRuntimeBinary();
|
|
612
|
-
if (runtime.additionalPathDirs.length > 0) {
|
|
613
|
-
env.PATH = prependPath(env.PATH, runtime.additionalPathDirs);
|
|
614
|
-
}
|
|
615
|
-
const managedByVar = packageManager === "bun" ? "PF_GATE_MANAGED_BY_BUN" : "PF_GATE_MANAGED_BY_NPM";
|
|
616
|
-
env[managedByVar] = "1";
|
|
617
|
-
|
|
618
|
-
const child = spawn(runtime.binaryPath, args, {
|
|
619
|
-
stdio: "inherit",
|
|
620
|
-
env,
|
|
621
|
-
shell: shouldUseShellForBinary(runtime.binaryPath),
|
|
622
|
-
});
|
|
623
|
-
|
|
624
|
-
child.on("error", (error) => {
|
|
625
|
-
console.error(error);
|
|
626
|
-
process.exit(1);
|
|
627
|
-
});
|
|
628
|
-
|
|
629
|
-
for (const signal of ["SIGINT", "SIGTERM", "SIGHUP"]) {
|
|
630
|
-
process.on(signal, () => forwardSignal(child, signal));
|
|
631
|
-
}
|
|
632
|
-
|
|
633
|
-
const childResult = await new Promise((resolve) => {
|
|
634
|
-
child.on("exit", (code, signal) => {
|
|
635
|
-
if (signal) {
|
|
636
|
-
resolve({ type: "signal", signal });
|
|
637
|
-
return;
|
|
638
|
-
}
|
|
639
|
-
resolve({ type: "code", exitCode: code ?? 1 });
|
|
640
|
-
});
|
|
641
|
-
});
|
|
642
|
-
|
|
643
|
-
if (childResult.type === "signal") {
|
|
644
|
-
process.kill(process.pid, childResult.signal);
|
|
645
|
-
return;
|
|
646
|
-
}
|
|
647
|
-
process.exit(childResult.exitCode);
|
|
648
|
-
}
|
|
File without changes
|