feat(core,tooling): Windows support — shell selection, install.ps1, win-x64 release package, Windows CI (#79)

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Yaowei Zheng
2026-07-27 22:17:35 +08:00
committed by GitHub
parent c23f0bc2f0
commit c369e089a7
46 changed files with 1315 additions and 217 deletions
+6
View File
@@ -18,6 +18,12 @@ export const DOCS_URL = `${import.meta.env.BASE_URL}docs/`;
*/
export const INSTALL_CMD = "curl -fsSL https://penguin.ooo/install.sh | sh";
/**
* One-line installer for Windows (PowerShell 5.1+, x64, bundled Node runtime).
* penguin.ooo/install.ps1 is public/install.ps1 — the same thin-forwarder design.
*/
export const INSTALL_CMD_WINDOWS = "irm https://penguin.ooo/install.ps1 | iex";
/**
* Demo videos live in the sibling `penguin-harness-community` repo rather than in this
* one: they are ~9 MB each, and this repo's whole history is ~17 MB, so committing them
+6 -2
View File
@@ -59,7 +59,9 @@ export const en: Strings = {
ctaPrimary: "Get started",
ctaGithub: "GitHub",
installHint:
"One-line install (Linux / macOS, x64 / arm64, bundled Node runtime — unpack and run)",
"One-line install (Linux / macOS / Windows, bundled Node runtime — unpack and run)",
installLabelPosix: "Linux / macOS",
installLabelWindows: "Windows",
stats: [
{ value: "1000+", label: "supported models" },
{ value: "1×CPU", label: "minimum footprint" },
@@ -155,7 +157,9 @@ export const en: Strings = {
"Install with one command and let the Agent work from a desktop-grade interface — all data stays in your local ~/.penguin/data directory.",
step1: "Install",
step1Desc:
"Linux / macOS (x64 / arm64) with a bundled Node runtime — unpack and run; upgrades never touch your data.",
"Linux / macOS / Windows with a bundled Node runtime — unpack and run; upgrades never touch your data.",
installLabelPosix: "Linux / macOS",
installLabelWindows: "Windows (PowerShell)",
tabWeb: "Web UI",
tabCli: "CLI",
webStep2: "Open the web interface",
+6 -3
View File
@@ -63,7 +63,9 @@ export const zh = {
keywords: ["轻量", "高效", "开源"],
ctaPrimary: "快速开始",
ctaGithub: "GitHub",
installHint: "一行命令安装(Linux / macOS,x64 / arm64,内嵌 Node 运行时,解压即用)",
installHint: "一行命令安装(Linux / macOS / Windows,内嵌 Node 运行时,解压即用)",
installLabelPosix: "Linux / macOS",
installLabelWindows: "Windows",
stats: [
{ value: "1000+", label: "支持模型数量" },
{ value: "1×CPU", label: "最低运行配置" },
@@ -156,8 +158,9 @@ export const zh = {
subtitle:
"一行命令安装,打开桌面级界面即可让 Agent 开始工作;数据全部保存在本地 ~/.penguin/data 目录。",
step1: "安装",
step1Desc:
"Linux / macOS(x64 / arm64),产物内嵌 Node 运行时,解压即用;升级与重装不触碰数据。",
step1Desc: "Linux / macOS / Windows,产物内嵌 Node 运行时,解压即用;升级与重装不触碰数据。",
installLabelPosix: "Linux / macOS",
installLabelWindows: "Windows(PowerShell)",
tabWeb: "Web 界面",
tabCli: "命令行",
webStep2: "启动 Web 界面",
+23 -7
View File
@@ -7,7 +7,7 @@
import { Fragment, useEffect, useState } from "react";
import { Link } from "react-router";
import { S } from "../lib/strings";
import { INSTALL_CMD, REPO_URL } from "../lib/links";
import { INSTALL_CMD, INSTALL_CMD_WINDOWS, REPO_URL } from "../lib/links";
import { CopyButton } from "../components/copy-button";
import { ArrowRightIcon, GitHubIcon } from "../components/icons";
@@ -115,12 +115,28 @@ export function Hero() {
className="anim-rise mx-auto mt-10 w-fit max-w-full"
style={{ animationDelay: "240ms" }}
>
<div className="flex items-center gap-3 overflow-hidden rounded-xl border border-gray-200 bg-gray-50 py-2.5 pr-2.5 pl-4 text-left dark:border-gray-800 dark:bg-gray-900">
<code className="min-w-0 flex-1 overflow-x-auto font-mono text-[13px] whitespace-nowrap text-gray-800 dark:text-gray-200">
<span className="mr-2 text-gray-400 select-none dark:text-gray-500">$</span>
{INSTALL_CMD}
</code>
<CopyButton text={INSTALL_CMD} className="shrink-0" />
{/* One install row per OS (labels are language-neutral; prompt chars $ vs > match the shells). */}
<div className="overflow-hidden rounded-xl border border-gray-200 bg-gray-50 text-left dark:border-gray-800 dark:bg-gray-900">
<div className="flex items-center gap-3 py-2.5 pr-2.5 pl-4">
<span className="w-24 shrink-0 text-[11px] font-medium text-gray-400 dark:text-gray-500">
{S.hero.installLabelPosix}
</span>
<code className="min-w-0 flex-1 overflow-x-auto font-mono text-[13px] whitespace-nowrap text-gray-800 dark:text-gray-200">
<span className="mr-2 text-gray-400 select-none dark:text-gray-500">$</span>
{INSTALL_CMD}
</code>
<CopyButton text={INSTALL_CMD} className="shrink-0" />
</div>
<div className="flex items-center gap-3 border-t border-gray-200 py-2.5 pr-2.5 pl-4 dark:border-gray-800">
<span className="w-24 shrink-0 text-[11px] font-medium text-gray-400 dark:text-gray-500">
{S.hero.installLabelWindows}
</span>
<code className="min-w-0 flex-1 overflow-x-auto font-mono text-[13px] whitespace-nowrap text-gray-800 dark:text-gray-200">
<span className="mr-2 text-gray-400 select-none dark:text-gray-500">&gt;</span>
{INSTALL_CMD_WINDOWS}
</code>
<CopyButton text={INSTALL_CMD_WINDOWS} className="shrink-0" />
</div>
</div>
<p className="mt-2 text-xs text-gray-500 dark:text-gray-400">{S.hero.installHint}</p>
</div>
+12 -2
View File
@@ -7,7 +7,12 @@
import { useState } from "react";
import type { ReactNode } from "react";
import { S } from "../lib/strings";
import { DEEPSEEK_KEYS_URL, INSTALL_CMD, OPENROUTER_KEYS_URL } from "../lib/links";
import {
DEEPSEEK_KEYS_URL,
INSTALL_CMD,
INSTALL_CMD_WINDOWS,
OPENROUTER_KEYS_URL,
} from "../lib/links";
import { Section } from "../components/section";
import { CodeCard } from "../components/code-card";
import {
@@ -125,7 +130,12 @@ export function Quickstart() {
title={S.quickstart.step1}
desc={S.quickstart.step1Desc}
>
<CodeCard code={INSTALL_CMD} label="install" />
<CodeCard code={INSTALL_CMD} label={S.quickstart.installLabelPosix} />
<CodeCard
code={INSTALL_CMD_WINDOWS}
label={S.quickstart.installLabelWindows}
className="mt-2"
/>
</Step>
{mode === "web" ? (