release: 0.1.5 (#134)

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Yaowei ZhengandClaude Fable 5 authored and GitHub committed 2026-07-30 19:23:41 +08:00
1 parent ba0860f8d1
commit 6664edf890
44 files changed
+596 -151

No files matched your search

+1
View File
@@ -2,6 +2,7 @@
One brief line per release. Per-release detail lives in [`changelog/<version>/`](changelog/). One brief line per release. Per-release detail lives in [`changelog/<version>/`](changelog/).
- **0.1.5** — 2026-07-30. Self-contained offline installer bundles for all five platforms (with MinGit bundled on Windows), composer attachments of any file type with images reaching steering and goal objectives, in-run recovery for every LLM failure short of a rejected credential, a tenth-shorter default system prompt, the paper-editorial web-design theme with thinking/image guidance in the SDK skill, and a refreshed README/landing install story. ([details](changelog/0.1.5/README.md))
- **0.1.4** — 2026-07-27. Carries the whole 0.1.3 feature set to npm, which 0.1.3 itself never reached: its publish job failed on a version-endpoint test asserting a hard-coded build date, and only the release jobs stamp one. Plus blog images hosted in the sibling community repo rather than in this clone. ([details](changelog/0.1.4/README.md)) - **0.1.4** — 2026-07-27. Carries the whole 0.1.3 feature set to npm, which 0.1.3 itself never reached: its publish job failed on a version-endpoint test asserting a hard-coded build date, and only the release jobs stamp one. Plus blog images hosted in the sibling community repo rather than in this clone. ([details](changelog/0.1.4/README.md))
- **0.1.3** — 2026-07-27. Windows support (shell selection, `install.ps1`, a win-x64 package), goal mode looping Tasks until an objective completes, a docked subagents panel with a live call graph, LLM-error reconnects with a visible countdown, and in-app version display with update checks and admin self-update. ([details](changelog/0.1.3/README.md)) - **0.1.3** — 2026-07-27. Windows support (shell selection, `install.ps1`, a win-x64 package), goal mode looping Tasks until an objective completes, a docked subagents panel with a live call graph, LLM-error reconnects with a visible countdown, and in-app version display with update checks and admin self-update. ([details](changelog/0.1.3/README.md))
- **0.1.2** — 2026-07-26. Builtin file tools with git-style edit diffs, mid-run steering and queued follow-ups, handoff-style model switching with a per-request thinking level, free OpenRouter models, and isolated-origin Workspace HTML previews. ([details](changelog/0.1.2/README.md)) - **0.1.2** — 2026-07-26. Builtin file tools with git-style edit diffs, mid-run steering and queued follow-ups, handoff-style model switching with a per-request thinking level, free OpenRouter models, and isolated-origin Workspace HTML previews. ([details](changelog/0.1.2/README.md))
+54 -6
View File
@@ -4,7 +4,7 @@
<h1 align="center">PenguinHarness</h1> <h1 align="center">PenguinHarness</h1>
<p align="center"><b>Your automated agent builder lives on your desktop, connected to 1,000+ models.</b></p> <p align="center"><b>Your Automated Agent Builder, Right on Your Desktop / Server</b><br />Create Self-Evolving Agents in One Click</p>
<p align="center"> <p align="center">
<a href="https://www.producthunt.com/products/penguinharness?embed=true&amp;utm_source=badge-featured&amp;utm_medium=badge&amp;utm_campaign=badge-penguinharness" target="_blank" rel="noopener noreferrer"><img alt="PenguinHarness - Let Agents Autonomously Build Better Agents for $0.02 | Product Hunt" width="250" height="54" src="https://api.producthunt.com/widgets/embed-image/v1/featured.svg?post_id=1202577&amp;theme=light&amp;t=1784804711946" /></a> <a href="https://www.producthunt.com/products/penguinharness?embed=true&amp;utm_source=badge-featured&amp;utm_medium=badge&amp;utm_campaign=badge-penguinharness" target="_blank" rel="noopener noreferrer"><img alt="PenguinHarness - Let Agents Autonomously Build Better Agents for $0.02 | Product Hunt" width="250" height="54" src="https://api.producthunt.com/widgets/embed-image/v1/featured.svg?post_id=1202577&amp;theme=light&amp;t=1784804711946" /></a>
@@ -108,18 +108,66 @@ Each family's latest generation only — the app's **Models** page lists every b
## Installation ## Installation
### 🌐 Web App — for humans 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 admin / penguin-2026 — change the password 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.
🚀 Install and launch the full experience (multi-session chat, agent/skill/model management, usage stats, Trace observability, evaluation center): ### 🐧 Linux (online install)
```bash ```bash
curl -fsSL https://penguin.ooo/install.sh | sh curl -fsSL https://penguin.ooo/install.sh | sh
penguin web # start the service and open http://127.0.0.1:7364 (first login: admin / penguin-2026) penguin web # start the service and open http://127.0.0.1:7364
``` ```
🪟 On Windows (PowerShell): `irm https://penguin.ooo/install.ps1 | iex` ### 🍎 macOS (online install)
📦 Or via npm: `npm install -g @prismshadow/penguin-cli`. Configure models on the in-app Models page, then chat. ```bash
curl -fsSL https://penguin.ooo/install.sh | sh
penguin web # start the service and open http://127.0.0.1:7364
```
### 🪟 Windows (online install, PowerShell)
```powershell
irm https://penguin.ooo/install.ps1 | iex
penguin web # start the service and open http://127.0.0.1:7364
```
### 📦 npm (any platform, Node >= 24)
```bash
npm install -g @prismshadow/penguin-cli
penguin web # start the service and open http://127.0.0.1:7364
```
<details>
<summary><b>📴 Offline install packages (air-gapped machines)</b></summary>
Every <a href="https://github.com/Prism-Shadow/penguin-harness/releases">GitHub Release</a> attaches five self-contained offline bundles — Linux and macOS in x64 / arm64, Windows in x64. Each bundle carries the program archive, its SHA256 checksum and the platform's installer: download on a networked machine, copy to the target, and install with no network at all (offline installs verify the SHA256 unconditionally).
**Linux (on arm64, use `penguin-linux-arm64-offline.tar.gz`):**
```bash
mkdir penguin-offline
tar -xzf penguin-linux-x64-offline.tar.gz -C penguin-offline
./penguin-offline/install.sh
```
**macOS (Apple silicon shown; on Intel, use `penguin-darwin-x64-offline.tar.gz`):**
```bash
mkdir penguin-offline
tar -xzf penguin-darwin-arm64-offline.tar.gz -C penguin-offline
./penguin-offline/install.sh
```
**Windows (unzip, then double-click `install.cmd` — or run it in PowerShell):**
```powershell
Expand-Archive penguin-win32-x64-offline.zip -DestinationPath penguin-offline
cd penguin-offline
.\install.cmd
```
</details>
### 🤖 CLI & SDK — for agents ### 🤖 CLI & SDK — for agents
+54 -6
View File
@@ -4,7 +4,7 @@
<h1 align="center">PenguinHarness</h1> <h1 align="center">PenguinHarness</h1>
<p align="center"><b>全自动 Agent 构建器,住在你的桌面上,连接 1,000+ 模型。</b></p> <p align="center"><b>全自动 Agent 构建平台,运行在你的桌面 / 服务器上</b><br />一键创建自进化 Agent</p>
<p align="center"> <p align="center">
<a href="https://www.producthunt.com/products/penguinharness?embed=true&amp;utm_source=badge-featured&amp;utm_medium=badge&amp;utm_campaign=badge-penguinharness" target="_blank" rel="noopener noreferrer"><img alt="PenguinHarness - Let Agents Autonomously Build Better Agents for $0.02 | Product Hunt" width="250" height="54" src="https://api.producthunt.com/widgets/embed-image/v1/featured.svg?post_id=1202577&amp;theme=light&amp;t=1784804711946" /></a> <a href="https://www.producthunt.com/products/penguinharness?embed=true&amp;utm_source=badge-featured&amp;utm_medium=badge&amp;utm_campaign=badge-penguinharness" target="_blank" rel="noopener noreferrer"><img alt="PenguinHarness - Let Agents Autonomously Build Better Agents for $0.02 | Product Hunt" width="250" height="54" src="https://api.producthunt.com/widgets/embed-image/v1/featured.svg?post_id=1202577&amp;theme=light&amp;t=1784804711946" /></a>
@@ -108,18 +108,66 @@ https://github.com/user-attachments/assets/aec49ae9-b743-467b-b247-37bedfeaa36e
## 安装 ## 安装
### 🌐 Web 应用——面向人 每种方式装出的都是同一个 `penguin` 命令:`penguin web` 启动完整 Web 体验(多会话对话、Agent / 技能 / 模型管理、用量统计、轨迹观测、评估中心;首次登录 admin / penguin-2026,登录后请尽快修改密码),在应用内模型页配置模型后即可对话。在线安装器自带 Node 运行时,解压即用,升级与重装不触碰数据。
🚀 一行安装,启动完整体验(多会话对话、Agent / 技能 / 模型管理、用量统计、轨迹观测、评估中心): ### 🐧 Linux(在线安装)
```bash ```bash
curl -fsSL https://penguin.ooo/install.sh | sh curl -fsSL https://penguin.ooo/install.sh | sh
penguin web # 启动服务并打开 http://127.0.0.1:7364(首次登录:admin / penguin-2026) penguin web # 启动服务并打开 http://127.0.0.1:7364
``` ```
🪟 Windows(PowerShell):`irm https://penguin.ooo/install.ps1 | iex` ### 🍎 macOS(在线安装)
📦 或经 npm 安装:`npm install -g @prismshadow/penguin-cli`。在应用内模型页配置模型后即可对话。 ```bash
curl -fsSL https://penguin.ooo/install.sh | sh
penguin web # 启动服务并打开 http://127.0.0.1:7364
```
### 🪟 Windows(在线安装,PowerShell)
```powershell
irm https://penguin.ooo/install.ps1 | iex
penguin web # 启动服务并打开 http://127.0.0.1:7364
```
### 📦 npm(任意平台,需 Node >= 24)
```bash
npm install -g @prismshadow/penguin-cli
penguin web # 启动服务并打开 http://127.0.0.1:7364
```
<details>
<summary><b>📴 离线安装包(无网环境)</b></summary>
每个 <a href="https://github.com/Prism-Shadow/penguin-harness/releases">GitHub Release</a> 附带五个自包含的离线安装包——Linux 与 macOS 各有 x64 / arm64 两种架构,Windows 为 x64。包内自带程序压缩包、SHA256 校验文件与对应平台的安装器,在有网机器下载后拷贝到目标机器即可安装,全程无需联网(离线安装强制校验 SHA256)。
**Linux(arm64 机器换用 `penguin-linux-arm64-offline.tar.gz`):**
```bash
mkdir penguin-offline
tar -xzf penguin-linux-x64-offline.tar.gz -C penguin-offline
./penguin-offline/install.sh
```
**macOS(Apple 芯片用 arm64 包,Intel 芯片换用 `penguin-darwin-x64-offline.tar.gz`):**
```bash
mkdir penguin-offline
tar -xzf penguin-darwin-arm64-offline.tar.gz -C penguin-offline
./penguin-offline/install.sh
```
**Windows(解压后双击 `install.cmd`,或在 PowerShell 中运行):**
```powershell
Expand-Archive penguin-win32-x64-offline.zip -DestinationPath penguin-offline
cd penguin-offline
.\install.cmd
```
</details>
### 🤖 CLI 与 SDK——面向 Agent ### 🤖 CLI 与 SDK——面向 Agent
@@ -0,0 +1,17 @@
# Install documentation and landing refresh for 0.1.5
The 0.1.5 release repackages how the product introduces and installs itself, in both READMEs and on the landing site.
## One tagline pair everywhere
README and landing unify on the same two lines: **"Your Automated Agent Builder, Right on Your Desktop / Server"** (the landing hero keeps rotating the Desktop/Server word; the README writes the pair with a slash) and the subtitle **"Create Self-Evolving Agents in One Click"** — 中文为「全自动 Agent 构建平台,运行在你的桌面 / 服务器上」与「一键创建自进化 Agent」. The hero's "Agents building agents" badge is removed; the phrase moves to the LangChain comparison section, retitled **"Building Agents with Agents"** (用 Agent 构建 Agent).
## README: every install method spelled out
The Installation section now gives each method its own complete, copy-paste code block — Linux, macOS and Windows online one-liners, npm — each ending in `penguin web`, with the five offline bundles documented per-OS inside a collapsible `<details>` block (extract-and-run commands, architecture hints, the unconditional SHA256 note). The Web-App feature pitch folds into the section intro; the CLI & SDK section is unchanged.
## Landing: switch, don't list
- The hero's install box and the quick start's install step both switch by OS (Linux / macOS / Windows) instead of stacking every command; the quick start adds a second online/offline toggle, with the offline side carrying the bundle note, per-OS commands, architecture hints and a Releases link. Offline commands live beside the online one-liners in `lib/links.ts`.
- The announcement bar drops from four rotating items to two: Kimi K3 with the free models, and the AMD Developer Program credits.
- The 0.1.5 release post ships in both languages (`penguinharness-0-1-5`), covering offline installs, attachments and input images, in-run LLM recovery, and the skill-library upgrades.
@@ -0,0 +1,21 @@
# web-design and penguin-sdk skills: editorial theme, output contracts, thinking and images
Two of the built-in skills were reworked across three iterations (web-design v3 → v6, penguin-sdk v14 → v17), with the goal of getting better results from shorter user prompts.
## web-design
- A second complete visual language, the opt-in **paper editorial** theme: warm paper/ink/hairline tokens with one warm accent plus a status green, system-serif display headings over a sans body (CJK serif fallbacks, still no CDN fonts), uppercase mono micro-labels as the hierarchy tool, tighter radii with soft warm shadows, and signature shapes (asymmetric-corner brand mark, echoed user-bubble radius, orbit-medallion flourish). Light-only; the GitHub-style default remains, and the two never mix.
- Theme-agnostic chat/RAG upgrades: an optional knowledge side panel with index-status rows, a fuller empty-state composition (eyebrow → one-accent-word title → subtitle → pill chips or numbered example cards), a retrieval status line while answers stream, a sources accordion as an alternative citation surface, and composer refinements (kbd hints, disclaimer, gradient fade).
- A **ship-complete contract**: the one-line request is the whole spec — the skill never asks how a page should look, routes the recipe by request shape, and every delivery includes `lang`/viewport/title, persisted dark mode, designed loading/empty/error states, a working keyboard path, alt text and zero external requests.
- Chat recipes for the two message kinds modern models add: a collapsible reasoning block (auto-collapsed at the first answer delta, never restyled as answer prose) and composer image attachments (paperclip/paste/drag-drop, thumbnail queue, in-message previews).
## penguin-sdk
- A **Thinking and image messages** section, verified against core's OmniMessage protocol: stream `partial_thinking` into its own collapsed channel and ignore `fidelity` (core's replay bookkeeping); build image input with `imageUrlMessage` beside `userText`, with the config `vision` flag degrading gracefully (`[attached image: <path>]` folding read back through the project's `vision_model`); and a cheat sheet for the remaining app-relevant payloads (`request_end` error signals, `token_usage`, compaction events, tool activity).
- The streaming-loop guidance covers `opts.thinkingLevel` (`none…xhigh`, a per-turn override of `model.thinking_level`) and names Session lifetime as the app's memory model — one long-lived Session for stateful chat, one per request for stateless QA.
- An **output format and language** block in the RAG recipe: fix the format in the persona and per-request prompt (plain text, bare `[n]` citations — or a sanitized HTML whitelist when structure matters) instead of shipping a Markdown renderer, and bridge cross-language lexical retrieval with a small ingest-time bilingual keyword map expanded in `search()`.
- The overlapping "before you build" / "check the model first" sections merged into one keys-and-data-root section, each rule stated once.
## Web draft-page examples
With the knowledge moved into the skills, the draft page's example prompts shrink in both languages: the RAG example drops its BM25 cross-language lecture and empty-state instruction (keeping the bilingual self-test step), and the game-center / music-player examples drop the theme-persistence and responsive details the web-design skill now guarantees.
+39
View File
@@ -0,0 +1,39 @@
# Version 0.1.5
Released on 2026-07-30.
- [2026-07-30] Skills: web-design (v3 → v6) gains an opt-in paper editorial theme, a ship-complete delivery contract, and chat recipes for the thinking block and composer attachments; penguin-sdk (v14 → v17) documents the thinking and image message kinds, a plain-text output contract, cross-language BM25 retrieval, and a merged keys/data-root setup flow — with the Web draft page's example prompts shortened now that the skills carry the knowledge. ([details](2026-07-30-skills-web-design-and-penguin-sdk.md))
- [2026-07-30] Sites and docs: the README and landing page unify on the new tagline pair ("Your Automated Agent Builder, Right on Your Desktop / Server" · "Create Self-Evolving Agents in One Click"); the README spells out every install method as a complete per-OS code block with the offline bundles behind a collapsible; the landing install sections switch by OS and method instead of listing everything; the announcement bar drops to two items; the LangChain comparison is retitled "Building Agents with Agents"; and the 0.1.5 release post ships in both languages. ([details](2026-07-30-install-docs-and-landing.md))
- [2026-07-30] Backward compatibility: the batch's compat decisions in one place — the two per-panel localStorage width keys adopted into one shared key (widest wins, self-cleaning, with its removal release named), plus the changes checked and found to need no handling. ([details](2026-07-30-backward-compatibility.md))
- [2026-07-30] Web App: navigation entries settle on one name each across the sidebar, the collapsed rail and page titles; the user menu's three update rows collapse into one; the Workspace and Agents panels share a single (wider) width and a single open/closed lifetime, closing only on a new chat; the Agents panel says what each subagent was sent to do; Project display names become editable; and the draft page's examples become a fixed-height, always-one-open folder shelf with a multi-agent game-center example added. ([details](2026-07-30-web-app-refinements.md))
- [2026-07-30] CLI: pasting CJK or emoji into `penguin chat` no longer corrupts a character wherever the terminal split its stdin blocks — each chunk was decoded on its own, so a character torn across two reads became three replacement characters instead of one, and about 1400 Chinese characters was enough to trigger it. ([details](2026-07-30-paste-filter-utf8.md))
- [2026-07-30] Docs: three reference blocks catch up with the code they document — `run_subagent`'s argument block lists the `provider` that `model_id` must be paired with, the provider credential table covers the three gateway groups it had been missing, and the Project model entry table documents `max_tokens`. ([details](2026-07-30-docs-tools-and-configuration-reference.md))
- [2026-07-29] Core: every LLM failure except a rejected credential now retries inside the run — the classifier separating transient from permanent is an allowlist, so a gateway wording a transient fault its own way used to kill the turn — with the retry visible in both frontends, compaction on the same set under its own shorter budget, and a recovered failure no longer reported to the operator as an incident. Separately, pressing Stop mid-request can no longer leave a Session running forever when the provider's stream neither yields nor rejects after the abort. ([details](2026-07-29-llm-request-lifecycle.md))
- [2026-07-29] Cost center: the error table can page back through the whole history instead of showing only the newest 20, its source column reads `[env]` rather than `environment ·`, and an ordinary non-zero exit from a command tool is no longer recorded as an error — `grep` finding nothing had been crowding out the failures the table exists to show. ([details](2026-07-29-cost-center-errors.md))
- [2026-07-29] Core and tooling: `PORT` / `HOST` and the internal CLI plumbing no longer reach commands the Agent runs, so a dev server started by `exec_command` picks its own port instead of binding the harness's; and the development backend moves to 7368, so `pnpm dev` no longer collides with an installed `penguin web` — or, quieter and worse, proxies to it. ([details](2026-07-29-harness-env-and-dev-ports.md))
- [2026-07-29] Web App: the composer can attach files of any type — written to the Session scratchpad and handed to the model as `[attached file: <path>]` lines, keeping non-ASCII names — and the `@` mention becomes an `/agent` command; both switch commands are session-only and stage their pick as a chip, cached with the text, until Enter sends. ([details](2026-07-29-composer-attachments-and-switch-commands.md))
- [2026-07-29] Core: the default system prompt is about a tenth shorter (1087 → 969 words), with the trim concentrated in the sections re-read every turn. It now pins replies to the user's language, states the API-key stop rule once, points at parallel subagents for large tasks, and has tooling installed once into a shared per-Agent `shared_env/` directory while project dependencies stay in the project. The App Data Dir rule also stops forbidding deliverables in a tree that a temporary Workspace lives inside. Existing Agents keep their own prompt. ([details](2026-07-29-default-system-prompt.md))
- [2026-07-29] Web App: the chat header's elapsed chip no longer restarts from zero when a running Session is reloaded and now counts an event still in flight, and a round interrupted before its first Request settles to the same figure whether it was watched live or replayed — the running Task is anchored to the server's own clock instead of the browser's. ([details](2026-07-29-session-elapsed.md))
- [2026-07-28] Web App: model configuration stops inviting the browser's saved login — every form control opts out of autofill unless it declares a real credential role, and a secret field says `new-password`, the only value Chrome and Safari honor on a password box; a closed docked side panel no longer paints its 1px divider next to the open one, which read as a second, empty panel beside the Workspace files; a provider-signature message carrying no text stops drawing an empty reply bubble after a thinking segment; Benchmark costs now follow the display currency selected in settings; the tool card states a call's outcome once instead of twice; and no page can grow the document into a second scrollbar that drags the whole shell. ([details](2026-07-28-web-app.md))
- [2026-07-28] Web App and CLI: duration and byte abbreviations now carry into the next unit instead of printing `1m60s` or `1024KB` — both helpers rounded the value they displayed but chose the unit (or the minute/second split) from the raw input. ([details](2026-07-28-duration-and-byte-formatting.md))
- [2026-07-27] Input images: mid-run steering carries them (an uncaptioned image is a complete steering message), a goal objective accepts them as scratchpad paths on every model since it is re-injected as text each round, and the composer's mid-run action button can no longer sit disabled with Stop displaced. ([details](2026-07-27-input-images.md))
- [2026-07-27] Windows: the `win32-x64` package bundles MinGit under `git/`, so `exec_command` has a real bash even on a machine with no Git for Windows — the shell stops depending on what happens to be installed. A user's own Git for Windows still wins (its MSYS userland is the fuller one); the bundle is the floor, and PowerShell is now reached only by npm installs. GPLv2 obligations are recorded in a new root `THIRD-PARTY-NOTICES.md`. ([details](2026-07-27-windows-bundled-shell.md))
- [2026-07-27] Sites: the 0.1.4 release post in both languages, with a capture script for its screenshots. ([details](2026-07-27-sites-and-blog.md))
- [2026-07-25] Agent tuning: the Web App gains an end-to-end example for creating, benchmarking, and optimizing an Agent through isolated CLI Sessions, while the built-in tuning Skills tighten phase ownership, private evaluation boundaries, and Evaluator dispatch contracts. ([details](2026-07-25-agent-tuning-pipeline.md))
+50
View File
@@ -0,0 +1,50 @@
PenguinHarness 0.1.5 — offline installs for every platform, attachments and images in every input, and runs that recover instead of dying.
## Install
```sh
curl -fsSL https://penguin.ooo/install.sh | sh
penguin web
```
Windows (PowerShell):
```powershell
irm https://penguin.ooo/install.ps1 | iex
penguin web
```
Linux, macOS and Windows, with a bundled Node runtime. Or via npm (needs Node >= 24):
```sh
npm install -g @prismshadow/penguin-cli
```
**New: fully offline installs.** This release attaches five self-contained offline bundles — `penguin-linux-{x64,arm64}-offline.tar.gz`, `penguin-darwin-{x64,arm64}-offline.tar.gz`, `penguin-win32-x64-offline.zip` — each carrying the program archive, its SHA256 checksum and the platform's installer. Download on a networked machine, copy to the target, extract, and run `./install.sh` (POSIX) or double-click `install.cmd` (Windows); offline installs verify the checksum unconditionally.
## Highlights
**Offline install everywhere.** Every platform archive now ships wrapped as a self-contained offline bundle, `install.sh` / `install.ps1` accept a verified local archive (`--archive` / `PENGUIN_ARCHIVE`) while keeping their online behavior, POSIX bundles pass their payload explicitly so the online installer never trusts archives found beside a temporary script, and renamed archives still install thanks to an embedded target manifest. The Windows package also bundles MinGit, so `exec_command` has a real bash even on a machine with no Git for Windows — your own installation still wins when present, and GPLv2 obligations are recorded in `THIRD-PARTY-NOTICES.md`.
**Attachments and images reach every input.** The Web composer attaches files of any type — written to the Session scratchpad and handed to the model as `[attached file: <path>]` lines, non-ASCII names preserved. Images now ride mid-run steering (an uncaptioned image is a complete steering message) and goal objectives (as scratchpad paths, re-injected as text every round, so they work on every model). The `@` mention becomes an `/agent` command, and both switch commands stage their pick as a chip until Enter sends.
**LLM failures recover in-run.** The transient-vs-permanent classifier is inverted: every failure except a rejected credential now retries inside the run — visible in both frontends as a live countdown — with compaction retrying under its own shorter budget and recovered failures no longer reported as operator incidents. Pressing Stop mid-request can no longer strand a Session when a provider's stream neither yields nor rejects after the abort.
**A skill library that designs and builds better apps.** web-design gains an opt-in paper editorial theme and a ship-complete contract (a one-line request is the whole spec — dark mode, loading/empty/error states, keyboard path and zero external requests included unasked), plus recipes for collapsible thinking blocks and composer attachments; penguin-sdk documents the thinking and image message kinds, a plain-text output contract, and cross-language BM25 retrieval. The Web draft page adds an end-to-end agent tuning example.
## Notable in this release
- **A shorter default system prompt.** About a tenth smaller (1087 → 969 words), pinned to the user's language, with shared tooling installed once into a per-Agent `shared_env/` directory. Existing Agents keep their own prompt.
- **Web App refinements.** Navigation names unified; the Workspace and Agents panels share one width and lifetime; Project display names editable; the draft examples become a fixed-height folder shelf; the session elapsed chip survives reloads and counts in-flight events.
- **Cost center, honest errors.** The error table pages through the whole history, ordinary non-zero exits are no longer recorded as errors, and environment-sourced entries read `[env]`.
- **CLI paste fix.** CJK and emoji pasted into `penguin chat` no longer corrupt when the terminal splits stdin blocks mid-character.
- **Formatting carries.** Duration and byte abbreviations roll into the next unit instead of printing `1m60s` or `1024KB`.
- **Cleaner harness env.** `PORT` / `HOST` and internal CLI plumbing no longer reach commands the Agent runs, and the development backend moves to port 7368, out of an installed `penguin web`'s way.
- **Docs catch up.** `run_subagent`'s `provider` argument, the gateway credential groups, and the Project model entry's `max_tokens` are documented.
- **A refreshed front door.** README and landing unify on the new tagline pair, the README spells out every install method per-OS with offline bundles in a collapsible, and the landing page switches install methods by OS instead of listing them all.
## Requirements
Linux or macOS (x64 / arm64), or Windows 10+ (x64). The installers bundle their own Node runtime; installing from npm needs Node >= 24. All data stays under `~/.penguin/data`.
Full detail: [changelog/0.1.5/](https://github.com/Prism-Shadow/penguin-harness/tree/main/changelog/0.1.5).
+1 -33
View File
@@ -1,35 +1,3 @@
# Unreleased # Unreleased
Changes since v0.1.4. The version number is assigned at release, when this folder is renamed. Changes since v0.1.5. The version number is assigned at release, when this folder is renamed.
- [2026-07-30] Backward compatibility: the batch's compat decisions in one place — the two per-panel localStorage width keys adopted into one shared key (widest wins, self-cleaning, with its removal release named), plus the changes checked and found to need no handling. ([details](2026-07-30-backward-compatibility.md))
- [2026-07-30] Web App: navigation entries settle on one name each across the sidebar, the collapsed rail and page titles; the user menu's three update rows collapse into one; the Workspace and Agents panels share a single (wider) width and a single open/closed lifetime, closing only on a new chat; the Agents panel says what each subagent was sent to do; Project display names become editable; and the draft page's examples become a fixed-height, always-one-open folder shelf with a multi-agent game-center example added. ([details](2026-07-30-web-app-refinements.md))
- [2026-07-30] CLI: pasting CJK or emoji into `penguin chat` no longer corrupts a character wherever the terminal split its stdin blocks — each chunk was decoded on its own, so a character torn across two reads became three replacement characters instead of one, and about 1400 Chinese characters was enough to trigger it. ([details](2026-07-30-paste-filter-utf8.md))
- [2026-07-30] Docs: three reference blocks catch up with the code they document — `run_subagent`'s argument block lists the `provider` that `model_id` must be paired with, the provider credential table covers the three gateway groups it had been missing, and the Project model entry table documents `max_tokens`. ([details](2026-07-30-docs-tools-and-configuration-reference.md))
- [2026-07-29] Core: every LLM failure except a rejected credential now retries inside the run — the classifier separating transient from permanent is an allowlist, so a gateway wording a transient fault its own way used to kill the turn — with the retry visible in both frontends, compaction on the same set under its own shorter budget, and a recovered failure no longer reported to the operator as an incident. Separately, pressing Stop mid-request can no longer leave a Session running forever when the provider's stream neither yields nor rejects after the abort. ([details](2026-07-29-llm-request-lifecycle.md))
- [2026-07-29] Cost center: the error table can page back through the whole history instead of showing only the newest 20, its source column reads `[env]` rather than `environment ·`, and an ordinary non-zero exit from a command tool is no longer recorded as an error — `grep` finding nothing had been crowding out the failures the table exists to show. ([details](2026-07-29-cost-center-errors.md))
- [2026-07-29] Core and tooling: `PORT` / `HOST` and the internal CLI plumbing no longer reach commands the Agent runs, so a dev server started by `exec_command` picks its own port instead of binding the harness's; and the development backend moves to 7368, so `pnpm dev` no longer collides with an installed `penguin web` — or, quieter and worse, proxies to it. ([details](2026-07-29-harness-env-and-dev-ports.md))
- [2026-07-29] Web App: the composer can attach files of any type — written to the Session scratchpad and handed to the model as `[attached file: <path>]` lines, keeping non-ASCII names — and the `@` mention becomes an `/agent` command; both switch commands are session-only and stage their pick as a chip, cached with the text, until Enter sends. ([details](2026-07-29-composer-attachments-and-switch-commands.md))
- [2026-07-29] Core: the default system prompt is about a tenth shorter (1087 → 969 words), with the trim concentrated in the sections re-read every turn. It now pins replies to the user's language, states the API-key stop rule once, points at parallel subagents for large tasks, and has tooling installed once into a shared per-Agent `shared_env/` directory while project dependencies stay in the project. The App Data Dir rule also stops forbidding deliverables in a tree that a temporary Workspace lives inside. Existing Agents keep their own prompt. ([details](2026-07-29-default-system-prompt.md))
- [2026-07-29] Web App: the chat header's elapsed chip no longer restarts from zero when a running Session is reloaded and now counts an event still in flight, and a round interrupted before its first Request settles to the same figure whether it was watched live or replayed — the running Task is anchored to the server's own clock instead of the browser's. ([details](2026-07-29-session-elapsed.md))
- [2026-07-28] Web App: model configuration stops inviting the browser's saved login — every form control opts out of autofill unless it declares a real credential role, and a secret field says `new-password`, the only value Chrome and Safari honor on a password box; a closed docked side panel no longer paints its 1px divider next to the open one, which read as a second, empty panel beside the Workspace files; a provider-signature message carrying no text stops drawing an empty reply bubble after a thinking segment; Benchmark costs now follow the display currency selected in settings; the tool card states a call's outcome once instead of twice; and no page can grow the document into a second scrollbar that drags the whole shell. ([details](2026-07-28-web-app.md))
- [2026-07-28] Web App and CLI: duration and byte abbreviations now carry into the next unit instead of printing `1m60s` or `1024KB` — both helpers rounded the value they displayed but chose the unit (or the minute/second split) from the raw input. ([details](2026-07-28-duration-and-byte-formatting.md))
- [2026-07-27] Input images: mid-run steering carries them (an uncaptioned image is a complete steering message), a goal objective accepts them as scratchpad paths on every model since it is re-injected as text each round, and the composer's mid-run action button can no longer sit disabled with Stop displaced. ([details](2026-07-27-input-images.md))
- [2026-07-27] Windows: the `win32-x64` package bundles MinGit under `git/`, so `exec_command` has a real bash even on a machine with no Git for Windows — the shell stops depending on what happens to be installed. A user's own Git for Windows still wins (its MSYS userland is the fuller one); the bundle is the floor, and PowerShell is now reached only by npm installs. GPLv2 obligations are recorded in a new root `THIRD-PARTY-NOTICES.md`. ([details](2026-07-27-windows-bundled-shell.md))
- [2026-07-27] Sites: the 0.1.4 release post in both languages, with a capture script for its screenshots. ([details](2026-07-27-sites-and-blog.md))
- [2026-07-25] Agent tuning: the Web App gains an end-to-end example for creating, benchmarking, and optimizing an Agent through isolated CLI Sessions, while the built-in tuning Skills tighten phase ownership, private evaluation boundaries, and Evaluator dispatch contracts. ([details](2026-07-25-agent-tuning-pipeline.md))
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "penguin-harness", "name": "penguin-harness",
"version": "0.1.4", "version": "0.1.5",
"private": true, "private": true,
"type": "module", "type": "module",
"description": "PenguinHarness — TypeScript AI Agent (SDK + CLI).", "description": "PenguinHarness — TypeScript AI Agent (SDK + CLI).",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@prismshadow/penguin-cli", "name": "@prismshadow/penguin-cli",
"version": "0.1.4", "version": "0.1.5",
"type": "module", "type": "module",
"description": "PenguinHarness CLI: interactive REPL and single-task runner over @prismshadow/penguin-core.", "description": "PenguinHarness CLI: interactive REPL and single-task runner over @prismshadow/penguin-core.",
"license": "Apache-2.0", "license": "Apache-2.0",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@prismshadow/penguin-core", "name": "@prismshadow/penguin-core",
"version": "0.1.4", "version": "0.1.5",
"type": "module", "type": "module",
"description": "PenguinHarness core SDK: context_engine, OmniMessage protocol, LLM/Environment interfaces.", "description": "PenguinHarness core SDK: context_engine, OmniMessage protocol, LLM/Environment interfaces.",
"license": "Apache-2.0", "license": "Apache-2.0",
+1 -1
View File
@@ -56,7 +56,7 @@ export { Agent, createAgent } from "./agent.js";
export type { CreateAgentOptions, CreateSessionOptions, ResumeSessionOptions } from "./agent.js"; export type { CreateAgentOptions, CreateSessionOptions, ResumeSessionOptions } from "./agent.js";
/** SDK version number. */ /** SDK version number. */
export const VERSION = "0.1.4"; export const VERSION = "0.1.5";
/** Release build date (UTC yyyy-mm-dd), stamped by the release workflow next to VERSION; null in a dev/source build. */ /** Release build date (UTC yyyy-mm-dd), stamped by the release workflow next to VERSION; null in a dev/source build. */
export const BUILD_DATE: string | null = null; export const BUILD_DATE: string | null = null;
// Version-string helpers (shared by the CLI's `penguin update` and the server's update check). // Version-string helpers (shared by the CLI's `penguin update` and the server's update check).
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@prismshadow/penguin-docs", "name": "@prismshadow/penguin-docs",
"version": "0.1.4", "version": "0.1.5",
"private": true, "private": true,
"type": "module", "type": "module",
"description": "PenguinHarness documentation site (React + Vite + Tailwind CSS): bilingual zh/en Markdown pages with light/dark themes and per-page Copy Markdown, deployed to GitHub Pages under /docs/ next to the landing page.", "description": "PenguinHarness documentation site (React + Vite + Tailwind CSS): bilingual zh/en Markdown pages with light/dark themes and per-page Copy Markdown, deployed to GitHub Pages under /docs/ next to the landing page.",
@@ -0,0 +1,73 @@
---
title: "PenguinHarness 0.1.5: offline installs, richer input, and runs that recover"
date: 2026-07-30
category: news
excerpt: 0.1.5 widens where PenguinHarness runs and what it can take in. Five self-contained offline bundles install it on machines with no network at all; the composer attaches any file and images now reach steering and goal objectives; nearly every LLM failure recovers inside the run instead of killing the turn; and the built-in skills learned a second visual language plus the thinking and image message kinds. Here is what shipped.
---
PenguinHarness 0.1.5 is out. The release widens both ends of the pipe: where the harness can be installed — including machines that never touch the internet — and what you can hand it once it is running. In between, runs got sturdier: almost every LLM failure now recovers inside the run, and a mid-request Stop can no longer strand a Session. Feature by feature:
## Install with no network at all
Every GitHub Release now attaches **five self-contained offline bundles** — Linux and macOS in x64 and arm64, Windows in x64. Each bundle carries the program archive, its SHA256 checksum and the platform's own installer, so the whole flow is: download on any networked machine, copy to the target, run one command.
```bash
mkdir penguin-offline
tar -xzf penguin-linux-x64-offline.tar.gz -C penguin-offline
./penguin-offline/install.sh
```
On Windows, unzip `penguin-win32-x64-offline.zip` and double-click `install.cmd` — or run `.\install.ps1` in PowerShell. Offline installs verify the SHA256 unconditionally (there is no network to re-download from, so a corrupted archive must be caught, not tolerated), the POSIX bundles pass their payload to the installer explicitly rather than letting a script scan its directory, and a renamed archive still installs because platform packages now carry a target manifest inside.
The Windows package also grew a floor to stand on: it bundles MinGit under `git/`, so `exec_command` has a real bash even on a machine with no Git for Windows installed. Your own Git for Windows still wins when present — its MSYS userland is the fuller one — and the GPLv2 obligations are recorded in the new root `THIRD-PARTY-NOTICES.md`.
The install story around the bundles is redone to match: the README now spells out every method — Linux, macOS, Windows, npm, and the offline packages — each as a complete copy-paste block, and the landing page's install sections switch by OS and method instead of listing everything at once.
## Attach anything, steer with images
The Web composer can now attach **files of any type**, not just images. Attachments are written into the Session scratchpad and handed to the model as `[attached file: <path>]` lines — non-ASCII filenames preserved — so the model reads them with its normal file tools, and the same attachment flow works mid-run.
Images, meanwhile, now reach **every** input. Mid-run steering carries them (an image with no caption is a complete steering message by itself), and a goal objective accepts images as scratchpad paths — re-injected as text every round, they work on every model, vision or not.
The composer's `@` mention grew up into an `/agent` command, and both switch commands (`/agent`, `/model`) now stage their pick as a chip beside the text — cached with the draft, applied only when Enter sends, and session-only.
## Runs that recover instead of dying
The classifier separating transient from permanent LLM failures used to be an allowlist: a gateway that worded a transient fault its own way killed the turn. 0.1.5 inverts it — **every failure except a rejected credential now retries inside the run**, with the retry visible in both frontends as a live countdown, compaction retrying under its own shorter budget, and a recovered failure no longer reported to the operator as an incident.
Two companions to that: pressing Stop mid-request can no longer leave a Session running forever when a provider's stream neither yields nor rejects after the abort; and the Cost center's error table now pages back through the whole history, stops recording an ordinary non-zero exit (`grep` finding nothing) as an error, and labels environment-sourced entries `[env]`.
## Skills that design — and build — better apps
The built-in skill library took two big steps this release:
- **web-design** now carries a second complete visual language — an opt-in *paper editorial* theme with warm paper tones, system-serif display headings and mono micro-labels — next to the default GitHub-style simplicity, plus a "ship complete" contract: a one-line request is the whole spec, and every delivered page includes dark mode, loading/empty/error states, a working keyboard path and zero external requests, unasked. Chat interfaces gained recipes for a collapsible reasoning block and composer image attachments.
- **penguin-sdk** documents the message kinds modern models actually emit and accept: stream `partial_thinking` into its own collapsed channel, build image input with `imageUrlMessage` (with the config `vision` flag degrading gracefully through the project's `vision_model`), fix the output format in the persona instead of shipping a Markdown renderer, and bridge cross-language BM25 retrieval with an ingest-time bilingual keyword map.
On top of both, the Web App's draft page gained an end-to-end **agent tuning example** — create, benchmark and optimize an Agent through isolated CLI sessions — and its example prompts got shorter, because the skills now carry the knowledge the prompts used to spell out.
## Also in 0.1.5
- The default system prompt is about a tenth shorter (1087 → 969 words), pins replies to the user's language, and directs shared tooling into a per-Agent `shared_env/` directory. Existing Agents keep their own prompt.
- Navigation entries settle on one name each; the Workspace and Agents panels share one width and one open/closed lifetime; Project display names are editable; the draft page's examples became a fixed-height folder shelf.
- The chat header's elapsed chip survives reloads and counts in-flight events — anchored to the server's clock, so live and replayed views agree.
- Pasting CJK or emoji into `penguin chat` no longer corrupts characters torn across stdin chunks.
- Duration and byte formatting carry into the next unit instead of printing `1m60s` or `1024KB`.
- `PORT` / `HOST` no longer leak into commands the Agent runs, and the development backend moved to port 7368, out of the installed `penguin web`'s way.
- Docs catch up in three reference blocks: `run_subagent`'s `provider` argument, the gateway credential table, and the Project model entry's `max_tokens`.
## Install or upgrade
```bash
curl -fsSL https://penguin.ooo/install.sh | sh
penguin web
```
Windows (PowerShell):
```powershell
irm https://penguin.ooo/install.ps1 | iex
penguin web
```
Or `npm install -g @prismshadow/penguin-cli` with Node >= 24 — and from this release, fully offline from the [Release assets](https://github.com/Prism-Shadow/penguin-harness/releases). Full detail per change: [changelog/0.1.5](https://github.com/Prism-Shadow/penguin-harness/tree/main/changelog/0.1.5).
@@ -0,0 +1,73 @@
---
title: "PenguinHarness 0.1.5:离线安装、更丰富的输入与更稳的运行"
date: 2026-07-30
category: news
excerpt: 0.1.5 同时拓宽了 PenguinHarness 的两端:五个自包含离线安装包让它装进完全没有网络的机器;composer 可以附加任意类型的文件,图像也进入了中途引导与目标模式;几乎所有 LLM 故障都在运行内自动恢复而不再终止任务;内置技能学会了第二套视觉语言,并写清了 thinking 与图像这两类消息的用法。逐项说明如下。
---
PenguinHarness 0.1.5 发布了。这个版本把管道的两端同时拓宽:harness 能装在哪里——包括从不联网的机器;装好之后你能递给它什么。中间那段也更结实了:几乎所有 LLM 故障都在运行内自动恢复,请求中途按下 Stop 也不再可能让 Session 悬死。逐项来看:
## 完全离线也能安装
每个 GitHub Release 现在附带**五个自包含离线安装包**——Linux 与 macOS 各有 x64、arm64 两种架构,Windows 为 x64。包内自带程序压缩包、SHA256 校验文件与对应平台的安装器,完整流程就是:在任意有网机器下载、拷贝到目标机器、跑一条命令。
```bash
mkdir penguin-offline
tar -xzf penguin-linux-x64-offline.tar.gz -C penguin-offline
./penguin-offline/install.sh
```
Windows 上解压 `penguin-win32-x64-offline.zip` 后双击 `install.cmd` 即可——或在 PowerShell 里运行 `.\install.ps1`。离线安装无条件校验 SHA256(没有网络可以重新下载,损坏的包必须被拦下而不是被容忍);POSIX 离线包把安装载荷显式传给安装器,而不是让脚本扫描所在目录;平台包内置目标清单,改过名的压缩包也能正常安装。
Windows 安装包还多了一块「地板」:内置 MinGit(位于 `git/`),即使机器上没装 Git for Windows,`exec_command` 也有真正的 bash 可用。装了 Git for Windows 时仍然优先用你自己的——它的 MSYS 用户层更完整;GPLv2 义务记录在新增的根目录 `THIRD-PARTY-NOTICES.md` 中。
围绕离线包,安装文档也整体重做:README 把每种方式——Linux、macOS、Windows、npm、离线安装包——都写成可整段复制的完整代码块;官网落地页的安装区改为按系统与方式切换展示,不再全部平铺。
## 附加任意文件,用图像引导
Web composer 现在可以附加**任意类型的文件**,不再局限于图像。附件写入 Session 暂存目录,以 `[attached file: <path>]` 行交给模型——非 ASCII 文件名原样保留——模型用常规文件工具读取,运行中途同样可以附加。
图像则进入了**所有**输入通道:中途引导可以携带图像(不带文字说明的图像本身就是一条完整的引导消息);目标模式的 objective 以暂存目录路径的形式接受图像——每轮以文本重新注入,因此无论模型是否具备视觉能力都可用。
composer 的 `@` 提及升级为 `/agent` 命令,两个切换命令(`/agent`、`/model`)的选择都以纸片形式暂存在输入框旁——与草稿一同缓存,按下 Enter 发送时才生效,且仅作用于当前会话。
## 运行不再死于一次故障
区分暂时性与永久性 LLM 故障的分类器过去是一张允许名单:网关用自己的措辞描述一次暂时故障,任务就被判死。0.1.5 把它反了过来——**除凭证被拒外的所有故障都在运行内重试**,重试在两个前端都以倒计时可见,压缩请求在自己更短的预算内重试,恢复成功的故障也不再作为事故报给管理员。
两项配套:请求中途按 Stop,即使供应商的流在中止后既不产出也不报错,Session 也不再可能永远悬着;成本中心的错误表可以翻页回看全部历史,普通的非零退出(`grep` 没搜到)不再被记为错误,环境来源的条目标注为 `[env]`。
## 会设计、也会构建的技能库
内置技能库这个版本迈了两大步:
- **web-design** 在默认的 GitHub 风格简洁语言之外,新增第二套完整视觉语言——可选的「纸质编辑风」主题:暖纸色调、系统衬线大标题、等宽小标签;并立下「交付即成品」的约定:一句话请求就是完整规格,交付页面默认包含暗色模式、加载/空态/错误状态、完整键盘路径与零外部请求。聊天界面新增了可折叠思考块与 composer 图像附件的配方。
- **penguin-sdk** 写清了现代模型真正收发的消息类型:把 `partial_thinking` 流入独立的折叠通道,用 `imageUrlMessage` 构造图像输入(配置的 `vision` 标志经项目 `vision_model` 平滑降级),在 persona 里约定输出格式而不是在 UI 里搭 Markdown 渲染管线,并用 ingest 时生成的双语关键词映射弥合跨语言 BM25 检索。
在这之上,Web 应用的草稿页新增了端到端的 **Agent 调优示例**——通过相互隔离的 CLI 会话创建、评测并优化一个 Agent;示例提示词也变短了,因为过去要在提示词里写明的知识,现在由技能承载。
## 0.1.5 还有这些
- 默认系统提示词缩短约十分之一(1087 → 969 词),回复语言锁定用户语言,共享工具装入 Agent 级 `shared_env/` 目录。已有 Agent 保持自己的提示词不变。
- 导航条目名称统一;Workspace 与 Agents 面板共用宽度与开合状态;Project 显示名可编辑;草稿页示例改为定高折叠书架。
- 会话头部的耗时纸片在刷新后不再归零,并统计在途事件——锚定服务器时钟,直播与回放一致。
- 向 `penguin chat` 粘贴中文或 emoji 不再因 stdin 分块撕裂字符而出现乱码。
- 时长与字节的缩写会正确进位,不再出现 `1m60s` 或 `1024KB`。
- `PORT` / `HOST` 不再泄漏进 Agent 运行的命令;开发后端移至 7368 端口,与已安装的 `penguin web` 互不干扰。
- 文档补齐三处参考:`run_subagent` 的 `provider` 参数、网关凭证表、Project 模型条目的 `max_tokens`。
## 安装或升级
```bash
curl -fsSL https://penguin.ooo/install.sh | sh
penguin web
```
Windows(PowerShell):
```powershell
irm https://penguin.ooo/install.ps1 | iex
penguin web
```
也可以在 Node >= 24 环境 `npm install -g @prismshadow/penguin-cli`——从这个版本起,还可以用 [Release 附件](https://github.com/Prism-Shadow/penguin-harness/releases)完全离线安装。每项改动的完整细节见 [changelog/0.1.5](https://github.com/Prism-Shadow/penguin-harness/tree/main/changelog/0.1.5)。
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@prismshadow/penguin-landing", "name": "@prismshadow/penguin-landing",
"version": "0.1.4", "version": "0.1.5",
"private": true, "private": true,
"type": "module", "type": "module",
"description": "PenguinHarness landing page (React + Vite + Tailwind CSS): multilingual, light/dark themes, benchmark showcase, and a local Markdown blog, deployed to GitHub Pages via GitHub Actions.", "description": "PenguinHarness landing page (React + Vite + Tailwind CSS): multilingual, light/dark themes, benchmark showcase, and a local Markdown blog, deployed to GitHub Pages via GitHub Actions.",
@@ -20,9 +20,7 @@ const ROTATE_MS = 6000;
* freshest news goes at the front. * freshest news goes at the front.
*/ */
const ITEMS = [ const ITEMS = [
{ key: "freeModels", to: "/blog/free-models-in-penguin-harness" }, { key: "k3AndFree", to: "/blog/free-models-in-penguin-harness" },
{ key: "gemini", to: "/blog/gemini-3-6-in-penguinharness" },
{ key: "models", to: "/blog/introducing-penguinharness" },
{ key: "fireworks", to: "/blog/fireworks-credits-amd" }, { key: "fireworks", to: "/blog/fireworks-credits-amd" },
] as const; ] as const;
@@ -34,9 +32,7 @@ function prefersReducedMotion(): boolean {
export function AnnouncementBar() { export function AnnouncementBar() {
const texts: Record<(typeof ITEMS)[number]["key"], string> = { const texts: Record<(typeof ITEMS)[number]["key"], string> = {
freeModels: S.announcement.freeModels, k3AndFree: S.announcement.k3AndFree,
gemini: S.announcement.gemini,
models: S.announcement.models,
fireworks: S.announcement.fireworks, fireworks: S.announcement.fireworks,
}; };
// pos runs 0..ITEMS.length where ITEMS.length is the clone of slide 0. // pos runs 0..ITEMS.length where ITEMS.length is the clone of slide 0.
+18
View File
@@ -24,6 +24,24 @@ export const INSTALL_CMD = "curl -fsSL https://penguin.ooo/install.sh | sh";
*/ */
export const INSTALL_CMD_WINDOWS = "irm https://penguin.ooo/install.ps1 | iex"; export const INSTALL_CMD_WINDOWS = "irm https://penguin.ooo/install.ps1 | iex";
/**
* Offline-bundle install commands, per OS tab of the install switcher. Each Release
* attaches five self-contained bundles (see scripts/package-offline-bundles.sh); the
* commands show the most common architecture — the localized hint strings name the
* alternative archive. Language-neutral, like the one-liners above.
*/
export const OFFLINE_INSTALL_CMDS: Record<"linux" | "macos" | "windows", string> = {
linux: `mkdir penguin-offline
tar -xzf penguin-linux-x64-offline.tar.gz -C penguin-offline
./penguin-offline/install.sh`,
macos: `mkdir penguin-offline
tar -xzf penguin-darwin-arm64-offline.tar.gz -C penguin-offline
./penguin-offline/install.sh`,
windows: `Expand-Archive penguin-win32-x64-offline.zip -DestinationPath penguin-offline
cd penguin-offline
.\\install.cmd`,
};
/** /**
* Heavy marketing media lives in the sibling `penguin-harness-community` repo rather than * Heavy marketing media lives in the sibling `penguin-harness-community` repo rather than
* in this one, so that assets only the landing site ever renders stay out of the clone of * in this one, so that assets only the landing site ever renders stay out of the clone of
+25 -16
View File
@@ -12,9 +12,7 @@ export const en: Strings = {
label: "Announcements", label: "Announcements",
prev: "Previous announcement", prev: "Previous announcement",
next: "Next announcement", next: "Next announcement",
freeModels: "Free models Ling 3.0 Flash and the Free Models Router are now in PenguinHarness", k3AndFree: "Kimi K3 and free models like Ling 3.0 Flash are now available in PenguinHarness",
gemini: "Gemini 3.6 Flash is now available in PenguinHarness",
models: "Kimi K3 and Qwen 3.8 Max are now available in PenguinHarness",
fireworks: "Claim $50 in Fireworks API credits with the AMD Developer Program", fireworks: "Claim $50 in Fireworks API credits with the AMD Developer Program",
}, },
@@ -48,20 +46,16 @@ export const en: Strings = {
}, },
hero: { hero: {
badge: "Agents building agents",
// The trailing space lives in the PREFIX (a breakable space before the nowrap // The trailing space lives in the PREFIX (a breakable space before the nowrap
// span) — inside titleNoWrap it would glue "Builder" to the unbreakable chunk. // span) — inside titleNoWrap it would glue "Builder," to the unbreakable chunk.
titlePrefix: "Your Automated Agent Builder ", titlePrefix: "Your Automated Agent Builder, ",
titleNoWrap: "Lives on Your ", titleNoWrap: "Right on Your ",
titleWords: ["Desktop", "Server"], titleWords: ["Desktop", "Server"],
titleSuffix: "", titleSuffix: "",
keywords: ["Lightweight", "Efficient", "Open Source"], subtitle: "Create Self-Evolving Agents in One Click",
ctaPrimary: "Get started", ctaPrimary: "Get started",
ctaGithub: "GitHub", ctaGithub: "GitHub",
installHint: installHint: "One-line install (bundled Node runtime — unpack and run)",
"One-line install (Linux / macOS / Windows, bundled Node runtime — unpack and run)",
installLabelPosix: "Linux / macOS",
installLabelWindows: "Windows",
stats: [ stats: [
{ value: "1000+", label: "supported models" }, { value: "1000+", label: "supported models" },
{ value: "1×CPU", label: "minimum footprint" }, { value: "1×CPU", label: "minimum footprint" },
@@ -70,6 +64,23 @@ export const en: Strings = {
], ],
}, },
install: {
linux: "Linux",
macos: "macOS",
windows: "Windows",
online: "Online install",
offline: "Offline package",
offlineNote:
"Every GitHub Release attaches five self-contained offline bundles (Linux / macOS in x64 and arm64, Windows in x64), each carrying the program archive, its SHA256 checksum and the installer: download on a networked machine, copy to the target, and install with no network at all.",
offlineHints: {
linux: "On arm64 machines, use penguin-linux-arm64-offline.tar.gz.",
macos:
"Apple silicon uses the arm64 bundle; on Intel, use penguin-darwin-x64-offline.tar.gz.",
windows: "After unzipping you can also just double-click install.cmd.",
},
offlineRelease: "Download offline packages from GitHub Releases",
},
copy: { copy: {
copy: "Copy", copy: "Copy",
copied: "Copied", copied: "Copied",
@@ -105,7 +116,7 @@ export const en: Strings = {
compare: { compare: {
eyebrow: "vs. LangChain", eyebrow: "vs. LangChain",
title: "The gap between 1× and 100×", title: "Building Agents with Agents",
subtitle: [ subtitle: [
"With LangChain, you build agents by hand — at 1× speed.", "With LangChain, you build agents by hand — at 1× speed.",
"With PenguinHarness, agents build agents — at 100×.", "With PenguinHarness, agents build agents — at 100×.",
@@ -157,9 +168,7 @@ 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.", "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", step1: "Install",
step1Desc: step1Desc:
"Linux / macOS / Windows with a bundled Node runtime — unpack and run; upgrades never touch your data.", "Pick your OS and method — the online one-liner, or an offline package; the bundle carries its own Node runtime, and upgrades never touch your data.",
installLabelPosix: "Linux / macOS",
installLabelWindows: "Windows (PowerShell)",
tabWeb: "Web UI", tabWeb: "Web UI",
tabCli: "CLI", tabCli: "CLI",
webStep2: "Open the web interface", webStep2: "Open the web interface",
+28 -17
View File
@@ -13,9 +13,7 @@ export const zh = {
label: "公告", label: "公告",
prev: "上一条公告", prev: "上一条公告",
next: "下一条公告", next: "下一条公告",
freeModels: "Ling 3.0 Flash 与 Free Models Router 等免费模型现已在 PenguinHarness 可用", k3AndFree: "Kimi K3 与 Ling 3.0 Flash 等免费模型现已在 PenguinHarness 可用",
gemini: "Gemini 3.6 Flash 现已在 PenguinHarness 可用",
models: "Kimi K3 与 Qwen 3.8 Max 模型现已在 PenguinHarness 可用",
fireworks: "携手 AMD 开发者计划:$50 Fireworks API 额度免费领取中", fireworks: "携手 AMD 开发者计划:$50 Fireworks API 额度免费领取中",
}, },
@@ -49,23 +47,20 @@ export const zh = {
}, },
hero: { hero: {
badge: "让 Agent 为你构建 Agent",
/** /**
* Headline: {titlePrefix}<nowrap>{titleNoWrap}{word}{titleSuffix}</nowrap>, the word * Headline: {titlePrefix}<nowrap>{titleNoWrap}{word}{titleSuffix}</nowrap>, the word
* rotating through titleWords (桌面/服务器 — where the builder lives; the README * rotating through titleWords (桌面/服务器 — where the builder runs; the README
* states Desktop only). The nowrap span pins the wrap point in front of it, so a * writes the pair as "桌面 / 服务器"). The nowrap span pins the wrap point in front
* break never splits "Agent Builder" / "Lives on Your Desktop" mid-phrase. * of it, so a break never splits "Agent Builder" / "Right on Your Desktop" mid-phrase.
*/ */
titlePrefix: "全自动 Agent 构建器,", titlePrefix: "全自动 Agent 构建平台,",
titleNoWrap: "住在你的", titleNoWrap: "运行在你的",
titleWords: ["桌面", "服务器"], titleWords: ["桌面", "服务器"],
titleSuffix: "上", titleSuffix: "上",
keywords: ["轻量", "高效", "开源"], subtitle: "一键创建自进化 Agent",
ctaPrimary: "快速开始", ctaPrimary: "快速开始",
ctaGithub: "GitHub", ctaGithub: "GitHub",
installHint: "一行命令安装(Linux / macOS / Windows,内嵌 Node 运行时,解压即用)", installHint: "一行命令安装(内嵌 Node 运行时,解压即用)",
installLabelPosix: "Linux / macOS",
installLabelWindows: "Windows",
stats: [ stats: [
{ value: "1000+", label: "支持模型数量" }, { value: "1000+", label: "支持模型数量" },
{ value: "1×CPU", label: "最低运行配置" }, { value: "1×CPU", label: "最低运行配置" },
@@ -74,6 +69,23 @@ export const zh = {
], ],
}, },
/** Install-method switcher (hero + quick start): OS tabs, online/offline methods. */
install: {
linux: "Linux",
macos: "macOS",
windows: "Windows",
online: "在线安装",
offline: "离线安装包",
offlineNote:
"每个 GitHub Release 附带五个自包含离线安装包(Linux / macOS 各 x64 与 arm64,Windows 为 x64),内含程序包、SHA256 校验文件与安装器:在有网机器下载,拷贝到目标机器安装,全程无需联网。",
offlineHints: {
linux: "arm64 机器换用 penguin-linux-arm64-offline.tar.gz。",
macos: "Apple 芯片用 arm64 包,Intel 芯片换用 penguin-darwin-x64-offline.tar.gz。",
windows: "解压后也可直接双击 install.cmd 完成安装。",
},
offlineRelease: "前往 GitHub Releases 下载离线安装包",
},
copy: { copy: {
copy: "复制", copy: "复制",
copied: "已复制", copied: "已复制",
@@ -108,7 +120,7 @@ export const zh = {
compare: { compare: {
eyebrow: "对比 LangChain", eyebrow: "对比 LangChain",
title: "1× 与 100× 的差距", title: "用 Agent 构建 Agent",
subtitle: [ subtitle: [
"使用 LangChain,以 1 倍速度人工构建 Agent;", "使用 LangChain,以 1 倍速度人工构建 Agent;",
"使用 PenguinHarness,以 100 倍速度用 Agent 构建 Agent。", "使用 PenguinHarness,以 100 倍速度用 Agent 构建 Agent。",
@@ -158,9 +170,8 @@ export const zh = {
subtitle: subtitle:
"一行命令安装,打开桌面级界面即可让 Agent 开始工作;数据全部保存在本地 ~/.penguin/data 目录。", "一行命令安装,打开桌面级界面即可让 Agent 开始工作;数据全部保存在本地 ~/.penguin/data 目录。",
step1: "安装", step1: "安装",
step1Desc: "Linux / macOS / Windows,产物内嵌 Node 运行时,解压即用;升级与重装不触碰数据。", step1Desc:
installLabelPosix: "Linux / macOS", "选择你的系统与安装方式:在线一行命令,或离线安装包;产物内嵌 Node 运行时,解压即用,升级与重装不触碰数据。",
installLabelWindows: "Windows(PowerShell)",
tabWeb: "Web 界面", tabWeb: "Web 界面",
tabCli: "命令行", tabCli: "命令行",
webStep2: "启动 Web 界面", webStep2: "启动 Web 界面",
+59 -50
View File
@@ -1,10 +1,10 @@
/** /**
* Hero: enlarged logo + product name, the slogan inside the pill badge, then the * Hero: enlarged logo + product name, the one-line headline whose rotating word
* one-line headline whose rotating word crossfades through a gaussian blur * crossfades through a gaussian blur (Desktop <-> Server, localized per dictionary),
* (Desktop <-> Server, localized per dictionary), three keywords, the install one-liner * the one-sentence subtitle, the install one-liner behind an OS switcher, and stats.
* and stats. The rotating word is a stacked inline-grid so line width never jumps. * The rotating word is a stacked inline-grid so line width never jumps.
*/ */
import { Fragment, useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { Link } from "react-router"; import { Link } from "react-router";
import { S } from "../lib/strings"; import { S } from "../lib/strings";
import { INSTALL_CMD, INSTALL_CMD_WINDOWS, REPO_URL } from "../lib/links"; import { INSTALL_CMD, INSTALL_CMD_WINDOWS, REPO_URL } from "../lib/links";
@@ -13,6 +13,54 @@ import { ArrowRightIcon, GitHubIcon } from "../components/icons";
const ROTATE_MS = 2600; const ROTATE_MS = 2600;
type InstallOs = "linux" | "macos" | "windows";
/**
* Install one-liner behind an OS tab row: one command visible at a time (Linux and
* macOS share the POSIX one-liner; the tabs still name them apart so nobody has to
* know that). Prompt char follows the shell: $ for POSIX, > for PowerShell.
*/
function InstallBox() {
const [os, setOs] = useState<InstallOs>("linux");
const cmd = os === "windows" ? INSTALL_CMD_WINDOWS : INSTALL_CMD;
const osBtn = (active: boolean) =>
`rounded-md px-2.5 py-1 text-xs font-medium transition-colors ${
active
? "bg-white text-gray-900 shadow-sm dark:bg-gray-700 dark:text-gray-100"
: "text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200"
}`;
return (
<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-1 border-b border-gray-200 bg-gray-100/70 px-2 py-1.5 dark:border-gray-800 dark:bg-gray-800/40"
role="tablist"
>
{(["linux", "macos", "windows"] as const).map((key) => (
<button
key={key}
type="button"
role="tab"
aria-selected={os === key}
className={osBtn(os === key)}
onClick={() => setOs(key)}
>
{S.install[key]}
</button>
))}
</div>
<div className="flex items-center gap-3 py-2.5 pr-2.5 pl-4">
<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">
{os === "windows" ? ">" : "$"}
</span>
{cmd}
</code>
<CopyButton text={cmd} className="shrink-0" />
</div>
</div>
);
}
function RotatingWord({ words }: { words: string[] }) { function RotatingWord({ words }: { words: string[] }) {
const [active, setActive] = useState(0); const [active, setActive] = useState(0);
useEffect(() => { useEffect(() => {
@@ -50,16 +98,9 @@ export function Hero() {
/> />
<span className="text-3xl font-semibold tracking-tight sm:text-4xl">{S.siteName}</span> <span className="text-3xl font-semibold tracking-tight sm:text-4xl">{S.siteName}</span>
</div> </div>
<p
className="anim-rise mx-auto mt-6 inline-flex items-center gap-2 rounded-full border border-gray-200 bg-white px-3.5 py-1 text-[13px] text-gray-600 dark:border-gray-800 dark:bg-gray-900 dark:text-gray-400"
style={{ animationDelay: "40ms" }}
>
<span className="h-1.5 w-1.5 rounded-full bg-brand-500" aria-hidden="true" />
{S.hero.badge}
</p>
{/* No text-balance: balance may break inside the breakable prefix ("…Agent / {/* No text-balance: balance may break inside the breakable prefix ("…Agent /
Builder…"); greedy wrapping + the nowrap span pins the desktop break to Builder…"); greedy wrapping + the nowrap span pins the desktop break to
"Your Automated Agent Builder / Lives on Your Desktop". */} "Your Automated Agent Builder, / Right on Your Desktop". */}
<h1 <h1
className="anim-rise mx-auto mt-6 max-w-full text-3xl font-semibold tracking-tight sm:text-5xl" className="anim-rise mx-auto mt-6 max-w-full text-3xl font-semibold tracking-tight sm:text-5xl"
style={{ animationDelay: "80ms" }} style={{ animationDelay: "80ms" }}
@@ -72,22 +113,12 @@ export function Hero() {
</span> </span>
</h1> </h1>
<div <p
className="anim-rise mt-6 flex items-center justify-center gap-4 text-base font-medium text-gray-600 sm:text-lg dark:text-gray-300" className="anim-rise mt-6 text-base font-medium text-gray-600 sm:text-lg dark:text-gray-300"
style={{ animationDelay: "140ms" }} style={{ animationDelay: "140ms" }}
> >
{S.hero.keywords.map((keyword, i) => ( {S.hero.subtitle}
<Fragment key={keyword}> </p>
{i > 0 && (
<span
className="h-1 w-1 rounded-full bg-gray-300 dark:bg-gray-600"
aria-hidden="true"
/>
)}
<span>{keyword}</span>
</Fragment>
))}
</div>
<div <div
className="anim-rise mt-8 flex flex-wrap items-center justify-center gap-3" className="anim-rise mt-8 flex flex-wrap items-center justify-center gap-3"
@@ -115,29 +146,7 @@ export function Hero() {
className="anim-rise mx-auto mt-10 w-fit max-w-full" className="anim-rise mx-auto mt-10 w-fit max-w-full"
style={{ animationDelay: "240ms" }} style={{ animationDelay: "240ms" }}
> >
{/* One install row per OS (labels are language-neutral; prompt chars $ vs > match the shells). */} <InstallBox />
<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> <p className="mt-2 text-xs text-gray-500 dark:text-gray-400">{S.hero.installHint}</p>
</div> </div>
+69 -6
View File
@@ -11,7 +11,9 @@ import {
DEEPSEEK_KEYS_URL, DEEPSEEK_KEYS_URL,
INSTALL_CMD, INSTALL_CMD,
INSTALL_CMD_WINDOWS, INSTALL_CMD_WINDOWS,
OFFLINE_INSTALL_CMDS,
OPENROUTER_KEYS_URL, OPENROUTER_KEYS_URL,
RELEASES_URL,
} from "../lib/links"; } from "../lib/links";
import { Section } from "../components/section"; import { Section } from "../components/section";
import { CodeCard } from "../components/code-card"; import { CodeCard } from "../components/code-card";
@@ -75,6 +77,8 @@ function KeyLinks() {
export function Quickstart() { export function Quickstart() {
const [mode, setMode] = useState<"web" | "cli">("web"); const [mode, setMode] = useState<"web" | "cli">("web");
const [provider, setProvider] = useState<"deepseek" | "openrouter">("deepseek"); const [provider, setProvider] = useState<"deepseek" | "openrouter">("deepseek");
const [os, setOs] = useState<"linux" | "macos" | "windows">("linux");
const [method, setMethod] = useState<"online" | "offline">("online");
const modeBtn = (active: boolean) => const modeBtn = (active: boolean) =>
`inline-flex items-center gap-1.5 rounded-md px-3.5 py-1.5 text-sm font-medium transition-colors ${ `inline-flex items-center gap-1.5 rounded-md px-3.5 py-1.5 text-sm font-medium transition-colors ${
@@ -130,12 +134,71 @@ export function Quickstart() {
title={S.quickstart.step1} title={S.quickstart.step1}
desc={S.quickstart.step1Desc} desc={S.quickstart.step1Desc}
> >
<CodeCard code={INSTALL_CMD} label={S.quickstart.installLabelPosix} /> {/* Two switch rows — OS, then online/offline — so exactly one method shows at a time. */}
<CodeCard <div className="mb-2 flex flex-wrap gap-2">
code={INSTALL_CMD_WINDOWS} <div
label={S.quickstart.installLabelWindows} className="inline-flex gap-1 rounded-lg border border-gray-200 bg-white p-1 dark:border-gray-800 dark:bg-gray-900"
className="mt-2" role="tablist"
/> >
{(["linux", "macos", "windows"] as const).map((key) => (
<button
key={key}
type="button"
role="tab"
aria-selected={os === key}
className={providerBtn(os === key)}
onClick={() => setOs(key)}
>
{S.install[key]}
</button>
))}
</div>
<div
className="inline-flex gap-1 rounded-lg border border-gray-200 bg-white p-1 dark:border-gray-800 dark:bg-gray-900"
role="tablist"
>
{(["online", "offline"] as const).map((key) => (
<button
key={key}
type="button"
role="tab"
aria-selected={method === key}
className={providerBtn(method === key)}
onClick={() => setMethod(key)}
>
{S.install[key]}
</button>
))}
</div>
</div>
{method === "online" ? (
<CodeCard
code={os === "windows" ? INSTALL_CMD_WINDOWS : INSTALL_CMD}
label={os === "windows" ? "PowerShell" : "curl | sh"}
/>
) : (
<>
<p className="mb-2 text-xs leading-5 text-gray-500 dark:text-gray-400">
{S.install.offlineNote}
</p>
<CodeCard
code={OFFLINE_INSTALL_CMDS[os]}
label={os === "windows" ? "PowerShell" : "shell"}
/>
<p className="mt-2 text-xs leading-5 text-gray-500 dark:text-gray-400">
{S.install.offlineHints[os]}{" "}
<a
href={RELEASES_URL}
target="_blank"
rel="noreferrer"
className="inline-flex items-center gap-1 text-brand-700 underline decoration-brand-300 underline-offset-2 transition-colors hover:text-brand-600 dark:text-brand-300 dark:decoration-brand-700"
>
{S.install.offlineRelease}
<ExternalLinkIcon className="h-3 w-3" />
</a>
</p>
</>
)}
</Step> </Step>
{mode === "web" ? ( {mode === "web" ? (
+2 -1
View File
@@ -96,7 +96,7 @@ describe("frontmatter mapping (author / pinned / category)", () => {
it("reads the pinned flag and sorts the pinned post first", () => { it("reads the pinned flag and sorts the pinned post first", () => {
for (const locale of ["en", "zh"] as const) { for (const locale of ["en", "zh"] as const) {
const posts = postsFor(locale); const posts = postsFor(locale);
expect(posts.length).toBe(12); expect(posts.length).toBe(13);
// The launch post stays the single pinned post; newer posts sort under it by date. // The launch post stays the single pinned post; newer posts sort under it by date.
expect(posts.filter((p) => p.pinned).map((p) => p.slug)).toEqual([ expect(posts.filter((p) => p.pinned).map((p) => p.slug)).toEqual([
"introducing-penguinharness", "introducing-penguinharness",
@@ -120,6 +120,7 @@ describe("frontmatter mapping (author / pinned / category)", () => {
it("filters by the news category, newest first", () => { it("filters by the news category, newest first", () => {
expect(postsFor("en", "news").map((p) => p.slug)).toEqual([ expect(postsFor("en", "news").map((p) => p.slug)).toEqual([
"introducing-penguinharness", "introducing-penguinharness",
"penguinharness-0-1-5",
"penguinharness-0-1-4", "penguinharness-0-1-4",
"free-models-in-penguin-harness", "free-models-in-penguin-harness",
"gemini-3-6-in-penguinharness", "gemini-3-6-in-penguinharness",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@prismshadow/penguin-server", "name": "@prismshadow/penguin-server",
"version": "0.1.4", "version": "0.1.5",
"type": "module", "type": "module",
"description": "PenguinHarness web server: multi-user authentication and authorization, Session execution with SSE streaming, and usage accounting, built on @prismshadow/penguin-core.", "description": "PenguinHarness web server: multi-user authentication and authorization, Session execution with SSE streaming, and usage accounting, built on @prismshadow/penguin-core.",
"license": "Apache-2.0", "license": "Apache-2.0",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@prismshadow/penguin-skills", "name": "@prismshadow/penguin-skills",
"version": "0.1.4", "version": "0.1.5",
"type": "module", "type": "module",
"description": "PenguinHarness skill library: built-in SKILL.md documents and skill groups, decoupled from core.", "description": "PenguinHarness skill library: built-in SKILL.md documents and skill groups, decoupled from core.",
"license": "Apache-2.0", "license": "Apache-2.0",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@prismshadow/penguin-web", "name": "@prismshadow/penguin-web",
"version": "0.1.4", "version": "0.1.5",
"private": true, "private": true,
"type": "module", "type": "module",
"description": "PenguinHarness web frontend SPA: React + Vite + Tailwind CSS, rendering conversations streamed over the OmniMessage protocol, plus Agent configuration, model configuration, usage stats, and Traces.", "description": "PenguinHarness web frontend SPA: React + Vite + Tailwind CSS, rendering conversations streamed over the OmniMessage protocol, plus Agent configuration, model configuration, usage stats, and Traces.",
@@ -30,7 +30,7 @@ const WIDTH_STORAGE_KEY = "penguin.panelWidth";
* *
* REMOVAL: delete this constant and storedWidth()'s legacy branch in the release AFTER the one * REMOVAL: delete this constant and storedWidth()'s legacy branch in the release AFTER the one
* shipping this change, as part of preparing that release. Nothing else in the repo reads these * shipping this change, as part of preparing that release. Nothing else in the repo reads these
* keys, so it is a pure deletion. See changelog/unreleased/2026-07-30-backward-compatibility.md. * keys, so it is a pure deletion. See changelog/0.1.5/2026-07-30-backward-compatibility.md.
*/ */
const LEGACY_WIDTH_KEYS = ["penguin.filesPanelWidth", "penguin.subagentsPanelWidth"] as const; const LEGACY_WIDTH_KEYS = ["penguin.filesPanelWidth", "penguin.subagentsPanelWidth"] as const;