@hienlh/ppm 0.8.38 → 0.8.39
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 +6 -0
- package/README.md +7 -1
- package/package.json +1 -1
- package/scripts/install.ps1 +116 -0
- package/scripts/install.sh +8 -15
- package/scripts/release.sh +34 -7
- package/src/server/routes/static.ts +7 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.8.39] - 2026-03-24
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
- **Binary frontend missing**: Compiled binary now ships with `web/` assets in archive (`.tar.gz`/`.zip`). Server looks for `web/` next to binary when running in compiled mode.
|
|
7
|
+
- **Windows install**: Fix TLS 1.2, SSL revocation, and download hang issues in PowerShell installer
|
|
8
|
+
|
|
3
9
|
## [0.8.38] - 2026-03-24
|
|
4
10
|
|
|
5
11
|
### Fixed
|
package/README.md
CHANGED
|
@@ -12,11 +12,17 @@ A mobile-first web IDE with AI chat, terminal, git, database tools, and file exp
|
|
|
12
12
|
|
|
13
13
|
### Binary (no dependencies)
|
|
14
14
|
|
|
15
|
+
**macOS / Linux:**
|
|
15
16
|
```bash
|
|
16
17
|
curl -fsSL https://raw.githubusercontent.com/hienlh/ppm/main/scripts/install.sh | sh
|
|
17
18
|
```
|
|
18
19
|
|
|
19
|
-
|
|
20
|
+
**Windows (PowerShell):**
|
|
21
|
+
```powershell
|
|
22
|
+
irm https://raw.githubusercontent.com/hienlh/ppm/main/scripts/install.ps1 | iex
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Downloads the latest binary, adds to PATH, and shows next steps. To upgrade, run the same command again.
|
|
20
26
|
|
|
21
27
|
### Via Bun
|
|
22
28
|
|
package/package.json
CHANGED
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
$ErrorActionPreference = "Stop"
|
|
2
|
+
$ProgressPreference = "SilentlyContinue"
|
|
3
|
+
# PowerShell 5.1 defaults to TLS 1.0 — GitHub requires TLS 1.2
|
|
4
|
+
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
|
|
5
|
+
|
|
6
|
+
$Repo = "hienlh/ppm"
|
|
7
|
+
$InstallDir = if ($env:PPM_INSTALL_DIR) { $env:PPM_INSTALL_DIR } else { "$env:USERPROFILE\.ppm\bin" }
|
|
8
|
+
$Artifact = "ppm-windows-x64.exe"
|
|
9
|
+
|
|
10
|
+
Write-Host "Detected: windows/x64"
|
|
11
|
+
|
|
12
|
+
# Check current version
|
|
13
|
+
$Current = ""
|
|
14
|
+
if (Test-Path "$InstallDir\ppm.exe") {
|
|
15
|
+
try { $Current = & "$InstallDir\ppm.exe" --version 2>$null } catch {}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
# Get latest release
|
|
19
|
+
Write-Host "Fetching latest release..."
|
|
20
|
+
$Release = Invoke-RestMethod "https://api.github.com/repos/$Repo/releases/latest"
|
|
21
|
+
$Tag = $Release.tag_name
|
|
22
|
+
if (-not $Tag) { Write-Host "Failed to fetch latest release"; exit 1 }
|
|
23
|
+
$Latest = $Tag -replace "^v", ""
|
|
24
|
+
|
|
25
|
+
# Check if upgrade needed
|
|
26
|
+
if ($Current -eq $Latest) {
|
|
27
|
+
Write-Host "Already up to date: v$Current"
|
|
28
|
+
exit 0
|
|
29
|
+
}
|
|
30
|
+
if ($Current) {
|
|
31
|
+
Write-Host "Upgrading: v$Current -> v$Latest"
|
|
32
|
+
} else {
|
|
33
|
+
Write-Host "Installing: v$Latest"
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
# Download and extract archive
|
|
37
|
+
$Archive = "ppm-windows-x64"
|
|
38
|
+
$Url = "https://github.com/$Repo/releases/download/$Tag/${Archive}.zip"
|
|
39
|
+
Write-Host "Downloading ${Archive}.zip..."
|
|
40
|
+
New-Item -ItemType Directory -Force -Path $InstallDir | Out-Null
|
|
41
|
+
$TmpZip = "$env:TEMP\ppm-install.zip"
|
|
42
|
+
& curl.exe -fSL# --ssl-no-revoke -o $TmpZip $Url
|
|
43
|
+
if ($LASTEXITCODE -ne 0) {
|
|
44
|
+
Write-Host "Download failed. Binary may not be available for this version."
|
|
45
|
+
Write-Host "Try installing via: bunx @hienlh/ppm start"
|
|
46
|
+
exit 1
|
|
47
|
+
}
|
|
48
|
+
# Extract ppm.exe + web/ into install dir
|
|
49
|
+
$TmpDir = "$env:TEMP\ppm-extract"
|
|
50
|
+
Remove-Item $TmpDir -Recurse -ErrorAction SilentlyContinue
|
|
51
|
+
Expand-Archive -Path $TmpZip -DestinationPath $TmpDir -Force
|
|
52
|
+
# Move contents from nested folder to install dir
|
|
53
|
+
$Nested = Get-ChildItem $TmpDir | Select-Object -First 1
|
|
54
|
+
Copy-Item "$($Nested.FullName)\*" -Destination $InstallDir -Recurse -Force
|
|
55
|
+
Remove-Item $TmpZip, $TmpDir -Recurse -ErrorAction SilentlyContinue
|
|
56
|
+
|
|
57
|
+
# Show changelog
|
|
58
|
+
Write-Host ""
|
|
59
|
+
Write-Host "========== Changelog =========="
|
|
60
|
+
try {
|
|
61
|
+
$Changelog = Invoke-RestMethod "https://raw.githubusercontent.com/$Repo/$Tag/CHANGELOG.md" -ErrorAction Stop
|
|
62
|
+
if ($Current) {
|
|
63
|
+
$Print = $false
|
|
64
|
+
foreach ($Line in $Changelog -split "`n") {
|
|
65
|
+
if ($Line -match "^## \[(.+?)\]") {
|
|
66
|
+
if ($Matches[1] -eq $Current) { break }
|
|
67
|
+
$Print = $true
|
|
68
|
+
}
|
|
69
|
+
if ($Print) { Write-Host $Line }
|
|
70
|
+
}
|
|
71
|
+
} else {
|
|
72
|
+
$Count = 0
|
|
73
|
+
foreach ($Line in $Changelog -split "`n") {
|
|
74
|
+
if ($Line -match "^## \[") { $Count++ }
|
|
75
|
+
if ($Count -gt 1) { break }
|
|
76
|
+
if ($Count -eq 1) { Write-Host $Line }
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
} catch {
|
|
80
|
+
Write-Host "(changelog unavailable)"
|
|
81
|
+
}
|
|
82
|
+
Write-Host "================================"
|
|
83
|
+
|
|
84
|
+
Write-Host ""
|
|
85
|
+
if ($Current) {
|
|
86
|
+
Write-Host "Upgraded ppm v$Current -> v$Latest"
|
|
87
|
+
} else {
|
|
88
|
+
Write-Host "Installed ppm v$Latest to $InstallDir\ppm.exe"
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
# Add to PATH
|
|
92
|
+
$UserPath = [Environment]::GetEnvironmentVariable("Path", "User")
|
|
93
|
+
if ($UserPath -notlike "*$InstallDir*") {
|
|
94
|
+
[Environment]::SetEnvironmentVariable("Path", "$InstallDir;$UserPath", "User")
|
|
95
|
+
$env:Path = "$InstallDir;$env:Path"
|
|
96
|
+
Write-Host "Added to PATH. Restart your terminal to use ppm."
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
# Getting started (fresh install)
|
|
100
|
+
if (-not $Current) {
|
|
101
|
+
Write-Host ""
|
|
102
|
+
Write-Host "========== Getting Started =========="
|
|
103
|
+
Write-Host "1. Restart your terminal"
|
|
104
|
+
Write-Host "2. Run the setup wizard:"
|
|
105
|
+
Write-Host " ppm init"
|
|
106
|
+
Write-Host "3. Start the server:"
|
|
107
|
+
Write-Host " ppm start"
|
|
108
|
+
Write-Host "4. Open in browser:"
|
|
109
|
+
Write-Host " ppm open"
|
|
110
|
+
Write-Host ""
|
|
111
|
+
Write-Host "For remote access (public URL via Cloudflare tunnel):"
|
|
112
|
+
Write-Host " ppm start --share"
|
|
113
|
+
Write-Host ""
|
|
114
|
+
Write-Host "Docs: https://github.com/$Repo#readme"
|
|
115
|
+
Write-Host "====================================="
|
|
116
|
+
}
|
package/scripts/install.sh
CHANGED
|
@@ -49,19 +49,15 @@ else
|
|
|
49
49
|
echo "Installing: v${LATEST}"
|
|
50
50
|
fi
|
|
51
51
|
|
|
52
|
-
#
|
|
53
|
-
URL="https://github.com/${REPO}/releases/download/${TAG}/${ARTIFACT}"
|
|
54
|
-
|
|
55
|
-
if [ "$HTTP_CODE" != "200" ] && [ "$HTTP_CODE" != "302" ]; then
|
|
56
|
-
echo "Binary not available for ${os}/${arch} in ${TAG} (HTTP ${HTTP_CODE})"
|
|
57
|
-
echo "Try installing via: bunx @hienlh/ppm start"
|
|
58
|
-
exit 1
|
|
59
|
-
fi
|
|
60
|
-
|
|
61
|
-
# Download binary
|
|
62
|
-
echo "Downloading ${ARTIFACT}..."
|
|
52
|
+
# Download and extract archive
|
|
53
|
+
URL="https://github.com/${REPO}/releases/download/${TAG}/${ARTIFACT}.tar.gz"
|
|
54
|
+
echo "Downloading ${ARTIFACT}.tar.gz..."
|
|
63
55
|
mkdir -p "$INSTALL_DIR"
|
|
64
|
-
|
|
56
|
+
TMPFILE=$(mktemp)
|
|
57
|
+
curl -fSL# -o "$TMPFILE" "$URL"
|
|
58
|
+
# Extract binary + web/ into install dir
|
|
59
|
+
tar -xzf "$TMPFILE" -C "$INSTALL_DIR"
|
|
60
|
+
rm -f "$TMPFILE"
|
|
65
61
|
chmod +x "${INSTALL_DIR}/ppm"
|
|
66
62
|
|
|
67
63
|
# Show changelog
|
|
@@ -71,7 +67,6 @@ CHANGELOG_URL="https://raw.githubusercontent.com/${REPO}/${TAG}/CHANGELOG.md"
|
|
|
71
67
|
CHANGELOG=$(curl -fsSL "$CHANGELOG_URL" 2>/dev/null || true)
|
|
72
68
|
if [ -n "$CHANGELOG" ]; then
|
|
73
69
|
if [ -n "$CURRENT" ]; then
|
|
74
|
-
# Upgrade: show entries between current and latest
|
|
75
70
|
echo "$CHANGELOG" | awk -v cur="$CURRENT" '
|
|
76
71
|
/^## \[/ {
|
|
77
72
|
ver = $0; gsub(/.*\[/, "", ver); gsub(/\].*/, "", ver)
|
|
@@ -81,7 +76,6 @@ if [ -n "$CHANGELOG" ]; then
|
|
|
81
76
|
printing { print }
|
|
82
77
|
'
|
|
83
78
|
else
|
|
84
|
-
# Fresh install: show latest entry only
|
|
85
79
|
echo "$CHANGELOG" | awk '
|
|
86
80
|
/^## \[/ { count++; if (count > 1) exit }
|
|
87
81
|
count == 1 { print }
|
|
@@ -104,7 +98,6 @@ PATH_LINE="export PATH=\"${INSTALL_DIR}:\$PATH\""
|
|
|
104
98
|
case ":$PATH:" in
|
|
105
99
|
*":${INSTALL_DIR}:"*) ;;
|
|
106
100
|
*)
|
|
107
|
-
# Detect shell profile
|
|
108
101
|
PROFILE=""
|
|
109
102
|
if [ -n "$ZSH_VERSION" ] || [ "$(basename "$SHELL")" = "zsh" ]; then
|
|
110
103
|
PROFILE="$HOME/.zshrc"
|
package/scripts/release.sh
CHANGED
|
@@ -36,21 +36,48 @@ for entry in "${TARGETS[@]}"; do
|
|
|
36
36
|
bun build src/index.ts --compile --target="$target" --outfile="dist/$artifact"
|
|
37
37
|
done
|
|
38
38
|
|
|
39
|
-
# 3.
|
|
39
|
+
# 3. Package binaries with web assets
|
|
40
|
+
echo "[3/5] Packaging..."
|
|
41
|
+
rm -f dist/ppm-*.tar.gz dist/ppm-*.zip
|
|
42
|
+
|
|
43
|
+
for entry in "${TARGETS[@]}"; do
|
|
44
|
+
artifact="${entry##*:}"
|
|
45
|
+
if [[ "$artifact" == *.exe ]]; then
|
|
46
|
+
# Windows: zip
|
|
47
|
+
name="${artifact%.exe}"
|
|
48
|
+
mkdir -p "dist/$name"
|
|
49
|
+
cp "dist/$artifact" "dist/$name/ppm.exe"
|
|
50
|
+
cp -r dist/web "dist/$name/web"
|
|
51
|
+
(cd dist && zip -qr "${name}.zip" "$name")
|
|
52
|
+
rm -rf "dist/$name"
|
|
53
|
+
echo " -> ${name}.zip"
|
|
54
|
+
else
|
|
55
|
+
# Unix: tar.gz
|
|
56
|
+
mkdir -p "dist/$artifact-pkg"
|
|
57
|
+
cp "dist/$artifact" "dist/$artifact-pkg/ppm"
|
|
58
|
+
cp -r dist/web "dist/$artifact-pkg/web"
|
|
59
|
+
tar -czf "dist/${artifact}.tar.gz" -C "dist/$artifact-pkg" .
|
|
60
|
+
rm -rf "dist/$artifact-pkg"
|
|
61
|
+
echo " -> ${artifact}.tar.gz"
|
|
62
|
+
fi
|
|
63
|
+
done
|
|
64
|
+
|
|
65
|
+
# 4. Create tag if not exists
|
|
40
66
|
if git rev-parse "$TAG" >/dev/null 2>&1; then
|
|
41
|
-
echo "[
|
|
67
|
+
echo "[4/5] Tag $TAG already exists, skipping"
|
|
42
68
|
else
|
|
43
|
-
echo "[
|
|
69
|
+
echo "[4/5] Creating tag $TAG..."
|
|
44
70
|
git tag "$TAG"
|
|
45
71
|
git push origin "$TAG"
|
|
46
72
|
fi
|
|
47
73
|
|
|
48
|
-
#
|
|
49
|
-
echo "[
|
|
74
|
+
# 5. Create or update release
|
|
75
|
+
echo "[5/5] Uploading to GitHub release..."
|
|
76
|
+
ARCHIVES=(dist/ppm-*.tar.gz dist/ppm-*.zip)
|
|
50
77
|
if gh release view "$TAG" >/dev/null 2>&1; then
|
|
51
|
-
gh release upload "$TAG"
|
|
78
|
+
gh release upload "$TAG" ${ARCHIVES[@]} --clobber
|
|
52
79
|
else
|
|
53
|
-
gh release create "$TAG"
|
|
80
|
+
gh release create "$TAG" ${ARCHIVES[@]} --title "$TAG" --generate-notes
|
|
54
81
|
fi
|
|
55
82
|
|
|
56
83
|
echo "=== Done: https://github.com/$(gh repo view --json nameWithOwner -q .nameWithOwner)/releases/tag/$TAG ==="
|
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
import { Hono } from "hono";
|
|
2
2
|
import { existsSync } from "node:fs";
|
|
3
|
-
import { resolve, join, extname } from "node:path";
|
|
3
|
+
import { resolve, join, extname, dirname } from "node:path";
|
|
4
|
+
import { isCompiledBinary } from "../../services/autostart-generator.ts";
|
|
4
5
|
|
|
5
6
|
export const staticRoutes = new Hono();
|
|
6
7
|
|
|
7
|
-
|
|
8
|
+
// Compiled binary: look for web/ next to the binary itself
|
|
9
|
+
// Dev mode: resolve relative to source file
|
|
10
|
+
const DIST_DIR = isCompiledBinary()
|
|
11
|
+
? resolve(dirname(process.execPath), "web")
|
|
12
|
+
: resolve(import.meta.dir, "../../../dist/web");
|
|
8
13
|
|
|
9
14
|
/** MIME types for common static assets */
|
|
10
15
|
const MIME_TYPES: Record<string, string> = {
|