From c6fb255a3ba8c61736e756b09cfedf807ab0973a Mon Sep 17 00:00:00 2001 From: Yaowei Zheng Date: Wed, 5 Aug 2026 12:05:39 +0800 Subject: [PATCH] docs(readme,landing): clearer install guidance with first-launch unsigned-build FAQ (#212) Co-authored-by: Claude Fable 5 --- README.md | 62 +++++++++++++++++--- README.zh.md | 62 +++++++++++++++++--- packages/landing/src/lib/links.ts | 21 +++++-- packages/landing/src/lib/strings-en.ts | 27 ++++++++- packages/landing/src/lib/strings.ts | 26 ++++++++- packages/landing/src/pages/download.tsx | 75 +++++++++++++++++++++++-- 6 files changed, 243 insertions(+), 30 deletions(-) diff --git a/README.md b/README.md index f038a04..47ddfe3 100644 --- a/README.md +++ b/README.md @@ -112,16 +112,64 @@ Each family's latest generation only — the app's **Models** page lists every b ## Installation -Every route installs the same `penguin` command: `penguin web` launches the full Web experience (multi-session chat, agent/skill/model management, usage stats, Trace observability, evaluation center; first login is `admin` with the initial password printed on the server's first start, of the form `penguin-1234` — change it right after), and models are configured on the in-app Models page. The online installers bundle their own Node runtime — unpack and run; upgrades and reinstalls never touch your data. +Two ways in — both work on the same `~/.penguin/data` root, so a desktop install and a CLI install can be mixed freely: -### 🐧 Linux (online install) +- **🖥️ Desktop app** — a double-click install: it embeds the server and opens already signed in, no terminal involved. +- **⌨️ CLI** — a one-line installer (or npm / offline package) puts the `penguin` command on the machine; `penguin web` then serves the full Web experience in your browser at `http://127.0.0.1:7364` (multi-session chat, agent / skill / model management, usage stats, Trace observability, evaluation center). The online installers bundle their own Node runtime — unpack and run; upgrades and reinstalls never touch your data. + +> [!NOTE] +> On a CLI install, the first Web login is `admin`, with the initial password printed on the server's first start (of the form `penguin-1234`) — change it right after. Models are configured on the in-app **Models** page. + +### 🖥️ Desktop app + +The full Web experience as a standalone application: it embeds the server and opens already signed in — no terminal, no login page, no initial password to copy. It works on the same `~/.penguin/data` root as a CLI install, so the two can be used interchangeably (a data root only ever runs one server; if a CLI-started instance is already up, the app attaches to it). + +**[⬇️ Get it from the download page](https://penguin.ooo/download)** — the page serves the OSS-accelerated mirror when it is reachable, and every installer is also attached to each [GitHub Release](https://github.com/Prism-Shadow/penguin-harness/releases). + +| Platform | Installers | +| ----------- | --------------------------- | +| macOS 11+ | dmg (Apple Silicon / Intel) | +| Windows 10+ | installer (.exe, x64) | +| Linux (x64) | AppImage / deb | + +Current builds are unsigned, so the system may block the very first launch. Expand your platform for the one-time fix: + +
+🍎 macOS says “PenguinHarness” is damaged and can’t be opened + +macOS quarantines files downloaded from the internet, and the missing signature makes that flag surface as a false “damaged” alert. Deleting the flag clears it: + +1. Open the downloaded dmg and drag `PenguinHarness.app` into the **Applications** folder. +2. Open **Terminal** (Launchpad → Other → Terminal). +3. Paste this command into Terminal and press Enter, then type your login password (nothing shows while you type; press Enter when done): + + ```bash + sudo xattr -rd com.apple.quarantine /Applications/PenguinHarness.app + ``` + +4. Once it finishes, double-click the app — it now opens normally. + +
+ +
+🪟 Windows SmartScreen says “Windows protected your PC” + +The installer is not signed yet, so SmartScreen holds the first run: click **More info**, then **Run anyway** to continue installing — first run only. + +
+ +
+🐧 Linux: double-clicking the AppImage does nothing + +Browsers download AppImages without the execute permission. Grant it once and the app starts normally from then on (the deb package installs through the package manager and is not affected): ```bash -curl -fsSL https://penguin.ooo/install.sh | sh -penguin web # start the service and open http://127.0.0.1:7364 +chmod +x penguin-desktop-linux-x86_64.AppImage ``` -### 🍎 macOS (online install) +
+ +### 🐧🍎 Linux / macOS (online install) ```bash curl -fsSL https://penguin.ooo/install.sh | sh @@ -142,10 +190,6 @@ npm install -g @prismshadow/penguin-cli penguin web # start the service and open http://127.0.0.1:7364 ``` -### 🖥️ Desktop app - -The full Web experience as a standalone application: it embeds the server and opens already signed in — no terminal, no login page, no initial password to copy — and it works on the same `~/.penguin/data` root as a CLI install, so the two can be used interchangeably (a data root only ever runs one server; if a CLI-started instance is already up, the app attaches to it). Installers for macOS (dmg, Apple silicon / Intel), Windows and Linux (AppImage / deb) live on the [download page](https://penguin.ooo/download) — which serves the OSS-accelerated mirror when it is reachable — and are attached to each [GitHub Release](https://github.com/Prism-Shadow/penguin-harness/releases). Current builds are unsigned: on first launch use right-click → Open on macOS, and "More info → Run anyway" past Windows SmartScreen. -
📴 Offline install (air-gapped machines) diff --git a/README.zh.md b/README.zh.md index 60d3543..97d11f1 100644 --- a/README.zh.md +++ b/README.zh.md @@ -112,16 +112,64 @@ https://github.com/user-attachments/assets/aec49ae9-b743-467b-b247-37bedfeaa36e ## 安装 -每种方式装出的都是同一个 `penguin` 命令:`penguin web` 启动完整 Web 体验(多会话对话、Agent / 技能 / 模型管理、用量统计、轨迹观测、评估中心;首次登录使用 `admin`,初始密码在服务端首次启动时打印,形如 `penguin-1234`,登录后请尽快修改密码),在应用内模型页配置模型后即可对话。在线安装器自带 Node 运行时,解压即用,升级与重装不触碰数据。 +两条路线——数据同在 `~/.penguin/data` 目录,桌面端与命令行安装可自由混用: -### 🐧 Linux(在线安装) +- **🖥️ 桌面端应用**——双击安装:内嵌服务端,打开即已登录,全程无需终端。 +- **⌨️ 命令行**——一行命令(或 npm / 离线包)装出 `penguin` 命令,`penguin web` 即在浏览器打开完整 Web 体验 `http://127.0.0.1:7364`(多会话对话、Agent / 技能 / 模型管理、用量统计、轨迹观测、评估中心)。在线安装器自带 Node 运行时,解压即用;升级与重装不触碰数据。 + +> [!NOTE] +> 命令行安装后,Web 首次登录用户名为 `admin`,初始密码在服务端首次启动时打印(形如 `penguin-1234`),登录后请尽快修改;模型在应用内「模型」页配置。 + +### 🖥️ 桌面端应用 + +完整的 Web 体验打包为独立应用:内嵌服务端,打开即已登录——无需终端、无登录页、也不用抄初始密码——并与 CLI 安装共用同一个 `~/.penguin/data` 数据目录,两者可以混用(一个数据目录同一时刻只运行一个服务端;CLI 已启动实例时,应用会直接接入它)。 + +**[⬇️ 前往下载页获取](https://penguin.ooo/download)**——国内自动走 OSS 镜像加速,安装包也附于每个 [GitHub Release](https://github.com/Prism-Shadow/penguin-harness/releases)。 + +| 平台 | 安装包 | +| ------------- | ---------------------------- | +| macOS 11+ | dmg(Apple 芯片 / Intel) | +| Windows 10+ | 安装程序(.exe,x64) | +| Linux(x64) | AppImage / deb | + +当前构建暂未签名,系统可能拦截首次启动。展开对应系统的步骤,操作一次即可解除: + +
+🍎 macOS 提示「PenguinHarness」已损坏,无法打开? + +macOS 会给从网络下载的文件加上隔离标记,应用未签名时会因此被误报「已损坏」。删除该标记即可解除: + +1. 打开下载的 dmg,把 `PenguinHarness.app` 拖入「应用程序(Applications)」文件夹。 +2. 打开终端:「启动台 → 其他 → 终端」。 +3. 在终端粘贴这条命令并回车,然后输入开机密码(输入时屏幕不显示字符,输完回车即可): + + ```bash + sudo xattr -rd com.apple.quarantine /Applications/PenguinHarness.app + ``` + +4. 执行完成后,双击即可正常打开应用。 + +
+ +
+🪟 Windows SmartScreen 提示「Windows 已保护你的电脑」? + +安装程序暂未签名,SmartScreen 会拦截首次运行:点「更多信息」,再点「仍要运行」即可继续安装,仅首次运行需要。 + +
+ +
+🐧 Linux 双击 AppImage 没有反应? + +浏览器下载的 AppImage 默认没有执行权限,赋权一次后即可正常启动(deb 包经包管理器安装,无此问题): ```bash -curl -fsSL https://penguin.ooo/install.sh | sh -penguin web # 启动服务并打开 http://127.0.0.1:7364 +chmod +x penguin-desktop-linux-x86_64.AppImage ``` -### 🍎 macOS(在线安装) +
+ +### 🐧🍎 Linux / macOS(在线安装) ```bash curl -fsSL https://penguin.ooo/install.sh | sh @@ -142,10 +190,6 @@ npm install -g @prismshadow/penguin-cli penguin web # 启动服务并打开 http://127.0.0.1:7364 ``` -### 🖥️ 桌面端应用 - -完整的 Web 体验打包为独立应用:内嵌服务端,打开即已登录——无需终端、无登录页、也不用抄初始密码——并与 CLI 安装共用同一个 `~/.penguin/data` 数据目录,两者可以混用(一个数据目录同一时刻只运行一个服务端;CLI 已启动实例时,应用会直接接入它)。macOS(dmg,Apple 芯片 / Intel)、Windows 与 Linux(AppImage / deb)的安装包可在[下载页](https://penguin.ooo/download)获取——国内自动走 OSS 镜像加速——也附于每个 [GitHub Release](https://github.com/Prism-Shadow/penguin-harness/releases)。当前构建暂未签名:macOS 首次启动请右键 →「打开」,Windows 在 SmartScreen 提示中选「仍要运行」。 -
📴 离线安装(无网环境) diff --git a/packages/landing/src/lib/links.ts b/packages/landing/src/lib/links.ts index 99d5546..19e8482 100644 --- a/packages/landing/src/lib/links.ts +++ b/packages/landing/src/lib/links.ts @@ -102,6 +102,12 @@ export interface DesktopInstaller { variant: string; } +/** Named separately: the first-launch FAQ's chmod command quotes this exact file name. */ +const LINUX_APPIMAGE: DesktopInstaller = { + file: "penguin-desktop-linux-x86_64.AppImage", + variant: "AppImage", +}; + /** Installers per platform card, in display order. */ export const DESKTOP_INSTALLERS: Record<"mac" | "windows" | "linux", DesktopInstaller[]> = { mac: [ @@ -109,11 +115,18 @@ export const DESKTOP_INSTALLERS: Record<"mac" | "windows" | "linux", DesktopInst { file: "penguin-desktop-darwin-x64.dmg", variant: "Intel" }, ], windows: [{ file: "penguin-desktop-win32-x64.exe", variant: "x64" }], - linux: [ - { file: "penguin-desktop-linux-x86_64.AppImage", variant: "AppImage" }, - { file: "penguin-desktop-linux-amd64.deb", variant: "deb" }, - ], + linux: [LINUX_APPIMAGE, { file: "penguin-desktop-linux-amd64.deb", variant: "deb" }], }; /** Checksum list covering every desktop installer of a release. */ export const DESKTOP_SHA256SUMS = "SHA256SUMS.desktop"; + +/** + * First-launch fixes for the unsigned desktop builds (the download page FAQ). + * Language-neutral, like the install commands above. The macOS one deletes the + * quarantine flag that makes Gatekeeper report the app as "damaged"; the Linux + * one restores the execute bit browsers strip from a downloaded AppImage. + */ +export const MAC_UNQUARANTINE_CMD = + "sudo xattr -rd com.apple.quarantine /Applications/PenguinHarness.app"; +export const LINUX_APPIMAGE_CHMOD_CMD = `chmod +x ${LINUX_APPIMAGE.file}`; diff --git a/packages/landing/src/lib/strings-en.ts b/packages/landing/src/lib/strings-en.ts index 7d45895..a30fadd 100644 --- a/packages/landing/src/lib/strings-en.ts +++ b/packages/landing/src/lib/strings-en.ts @@ -105,8 +105,31 @@ export const en: Strings = { altOss: "Use the OSS mirror instead", checksums: "Checksums (SHA256SUMS.desktop)", allReleases: "All releases", - unsignedNote: - 'Current builds are unsigned: on first launch use right-click → Open on macOS, and "More info → Run anyway" past Windows SmartScreen.', + /** First-launch FAQ: one collapsible item per platform, the visitor's own pre-expanded. */ + faq: { + title: "First-launch FAQ", + intro: + "Current builds are not signed yet, so the system may block the very first launch — the fix for your platform below is needed only once.", + mac: { + question: "macOS says “PenguinHarness” is damaged and can’t be opened?", + why: "macOS quarantines files downloaded from the internet, and the missing signature makes that flag surface as a false “damaged” alert. Deleting the flag clears it:", + stepDrag: "Open the downloaded dmg and drag PenguinHarness into the Applications folder.", + stepTerminal: "Open Terminal (Launchpad → Other → Terminal).", + stepPaste: + "Paste this command into Terminal and press Enter, then type your login password (nothing shows while you type; press Enter when done):", + stepOpen: "Once it finishes, double-click the app — it now opens normally.", + }, + windows: { + question: "Windows SmartScreen says “Windows protected your PC”?", + answer: + "The installer is not signed yet, so SmartScreen holds the first run: click “More info”, then “Run anyway” to continue installing — first run only.", + }, + linux: { + question: "Nothing happens when double-clicking the AppImage on Linux?", + answer: + "Browsers download AppImages without the execute permission. Grant it once and the app starts normally from then on (the deb package installs through the package manager and is not affected):", + }, + }, cliHint: "Just need the CLI, or the Web UI in a browser?", cliHintLink: "See the quick start", }, diff --git a/packages/landing/src/lib/strings.ts b/packages/landing/src/lib/strings.ts index 4c99af9..07fc4ce 100644 --- a/packages/landing/src/lib/strings.ts +++ b/packages/landing/src/lib/strings.ts @@ -107,8 +107,30 @@ export const zh = { altOss: "改用 OSS 镜像下载", checksums: "校验和(SHA256SUMS.desktop)", allReleases: "全部版本", - unsignedNote: - "当前构建暂未签名:macOS 首次启动请右键 →「打开」;Windows 在 SmartScreen 提示中选「更多信息 → 仍要运行」。", + /** First-launch FAQ: one collapsible item per platform, the visitor's own pre-expanded. */ + faq: { + title: "首次启动常见问题", + intro: "当前构建暂未签名,系统可能拦截首次启动——按对应系统的步骤解除即可,只需操作一次。", + mac: { + question: "macOS 提示「PenguinHarness」已损坏,无法打开?", + why: "macOS 会给从网络下载的文件加上隔离标记,应用未签名时会因此被误报「已损坏」。删除该标记即可解除:", + stepDrag: "打开下载的 dmg,把 PenguinHarness 拖入「应用程序(Applications)」文件夹。", + stepTerminal: "打开终端:「启动台 → 其他 → 终端」。", + stepPaste: + "在终端粘贴这条命令并回车,然后输入开机密码(输入时屏幕不显示字符,输完回车即可):", + stepOpen: "执行完成后,双击即可正常打开应用。", + }, + windows: { + question: "Windows SmartScreen 提示「Windows 已保护你的电脑」?", + answer: + "安装程序暂未签名,SmartScreen 会拦截首次运行:点「更多信息」,再点「仍要运行」即可继续安装,仅首次运行需要。", + }, + linux: { + question: "Linux 双击 AppImage 没有反应?", + answer: + "浏览器下载的 AppImage 默认没有执行权限,赋权一次后即可正常启动(deb 包经包管理器安装,无此问题):", + }, + }, cliHint: "只需要命令行或浏览器里的 Web 界面?", cliHintLink: "参见快速开始", }, diff --git a/packages/landing/src/pages/download.tsx b/packages/landing/src/pages/download.tsx index 4375bc8..1ec67cd 100644 --- a/packages/landing/src/pages/download.tsx +++ b/packages/landing/src/pages/download.tsx @@ -5,20 +5,27 @@ * resolves (validated the same way the installers validate it; any failure, e.g. CORS * not configured on the bucket or the mirror unreachable, silently keeps the GitHub * links). Plain-anchor downloads are never CORS-gated — only this version lookup is. + * Below the cards, a first-launch FAQ covers the unsigned builds — one collapsible item + * per platform (macOS quarantine removal, SmartScreen, AppImage execute bit), with the + * visitor's own platform pre-expanded. */ import { useEffect, useState } from "react"; import { Link } from "react-router"; +import type { ReactNode } from "react"; import { S } from "../lib/strings"; import { DESKTOP_INSTALLERS, DESKTOP_SHA256SUMS, GITHUB_LATEST_DOWNLOAD, + LINUX_APPIMAGE_CHMOD_CMD, + MAC_UNQUARANTINE_CMD, OSS_LATEST_JSON_URL, OSS_ORIGIN, RELEASES_URL, } from "../lib/links"; import { Section } from "../components/section"; -import { DownloadIcon, ExternalLinkIcon } from "../components/icons"; +import { CodeCard } from "../components/code-card"; +import { ChevronDownIcon, DownloadIcon, ExternalLinkIcon } from "../components/icons"; type Platform = "mac" | "windows" | "linux"; const PLATFORMS: Platform[] = ["mac", "windows", "linux"]; @@ -37,6 +44,36 @@ interface Mirror { base: string; } +/** + * One collapsible item of the first-launch FAQ. `defaultOpen` pre-expands the visitor's + * own platform on mount; after that the element owns its open state (React only writes + * the `open` property again if the rendered value changes, which it never does here). + */ +function FaqItem({ + question, + defaultOpen, + children, +}: { + question: string; + defaultOpen: boolean; + children: ReactNode; +}) { + return ( +
+ + {question} + + +
+ {children} +
+
+ ); +} + /** latest.json validated like the installer forwarders validate it: schema 1, safe v-tag, fixed bucket base. */ function parseMirror(value: unknown): Mirror | null { if (typeof value !== "object" || value === null) return null; @@ -135,10 +172,40 @@ export function DownloadPage() {

-

- {S.download.unsignedNote} + + +

+

+ {S.download.faq.title} +

+

+ {S.download.faq.intro}

-

+

+ +

{S.download.faq.mac.why}

+
    +
  1. {S.download.faq.mac.stepDrag}
  2. +
  3. {S.download.faq.mac.stepTerminal}
  4. +
  5. + {S.download.faq.mac.stepPaste} + +
  6. +
  7. {S.download.faq.mac.stepOpen}
  8. +
+
+ +

{S.download.faq.windows.answer}

+
+ +

{S.download.faq.linux.answer}

+ +
+
+
+ +
+

{S.download.cliHint}{" "} {S.download.cliHintLink}