release: 0.2.1 (#204)

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Yaowei Zheng
2026-08-05 00:30:55 +08:00
committed by GitHub
parent 1cf0e4d9bc
commit 88916880eb
19 changed files with 94 additions and 4 deletions
+1
View File
@@ -2,6 +2,7 @@
One brief line per release. Per-release detail lives in [`changelog/<version>/`](changelog/).
- **0.2.1** — 2026-08-04. The desktop app: an Electron shell over the unchanged server and Web App (signed-in on open, shared data root, per-root single-instance lock, three-platform installers mirrored to OSS), a landing download page with mirror-aware static links, download source selection for standalone installers and `penguin update`, compaction that survives malformed summaries with retries and costs finally visible, a random seeded admin password with login throttling, skills manageable from agent settings, per-Project new-chat defaults, a Traces page scaled onto a SQLite trace index, and the server's last IO hotspots closed. ([details](changelog/0.2.1/README.md))
- **0.2.0** — 2026-08-03. One sealed installer bundle per target serving online and offline installs alike — now mirrored to Alibaba Cloud OSS with automatic fallback — truncated tool output recovered from the Session scratchpad, chat navigation for long conversations (shell-style ↑ input recall, stacked sticky run headers, a minimap tick rail with hover previews), steering that survives reloads and carries file attachments, a DB-served session list with paged sidebar groups, and the refreshed qianwenai / OpenRouter model catalog defaulting to deepseek-v4-flash. ([details](changelog/0.2.0/README.md))
- **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,0 +1,5 @@
# Compaction extraction tolerance, retry parity, and failure observability
Fixes #170, where deepseek-v4-flash sessions became unusable: the model wrote `[summary][/summary]` as a title with the body after the closing tag, extraction took the empty pair, and every retry re-showed the model its own committed bad output — which it copied verbatim, forever. `extractSummary` now applies a tolerance ladder (first non-empty tag pair → whatever remains after stripping empty summary blocks → tagless output verbatim), preserving byte-identical re-extraction of healthy historical Traces.
A committed-but-unusable compaction response now counts as one more failed attempt on the standard `compactionMaxReconnects` budget and exponential backoff ladder — only `auth` stops without retrying — with the tool_use pairing repaired and a corrective note prepended before the re-sent prompt (append-only, prompt-cache-safe). The burned cost becomes visible: `compaction_end` gains `attempts`, every attempt's `token_usage` is surfaced between the compaction event pair, and a failed compaction lands as one cost-center error row. Retry state moves to one shared `RetryDetail` shape (`error_message` / `attempt` / `retry_in_ms`) across `request_end` and `compaction_end`, read directly by the CLI and Web retry displays instead of client-side counting. New agents get a shorter compaction prompt that shows the format as a concrete example; existing agents keep their stored prompt and are covered by the extraction rescue and retry guidance.
@@ -0,0 +1,3 @@
# data-analysis skill v2 and a leaner multi-run evaluation flow
The `data-analysis` library skill moves to v2, tightening its constraints on data granularity and semantics, native artifact handling, complete delivery, and risk-proportional verification. The benchmark flow stops re-running what it already measured: the design stage pins every Case at one run and reuses the selected Pilot results verbatim as the Formal Baseline, the Optimization stage takes a user-specified per-Candidate `runs` count dispatched Case × Runs in parallel and compares the recorded averages directly, and the Evaluator treats `run` as an upstream-assigned label instead of rejecting runs beyond the config's total. Docs (zh/en), the frontend example prompts and the contract tests are updated in sync.
@@ -25,3 +25,5 @@ electron-builder produces macOS dmg + zip (arm64/x64), Windows NSIS and Linux Ap
## Fixes
Both Workspace HTML preview entry points were dead in the desktop app and now work. The preview redirect resolved to port `0` — preview URLs are built from the server's own bind port (deliberately, since dev serves the SPA on a different port) while the shell starts the server with `PORT=0` — producing a `http://127.0.0.1:0/…` address browsers reject as an unsafe port; the actual bound port is now written back once listening, and an unknown port degrades to the sandboxed same-origin preview instead of an unloadable URL. "Open in a new tab" silently did nothing, because the link is app-origin and the shell denied every popup while only forwarding external URLs to the system browser — where the cookie-gated redirect would 401 anyway; app-origin popups now open a Node-free child window that follows the redirect and may navigate this instance's loopback surface, with anything else still going outward. Separately, the desktop shell's process credentials (`PENGUIN_DESKTOP_TOKEN`, `PENGUIN_PORT_FILE`) and the pinned seed password no longer leak into Agent command environments.
The app also stopped forgetting UI preferences (language, theme) between launches: the renderer persists them in `localStorage`, which the browser scopes to the window origin, and a fresh `PORT=0` every launch changed that origin every time. The shell now remembers the port the server actually bound (`userData/preferred-port`) and requests it again when it is still free on both loopback stacks, falling back to `PORT=0` whenever it is taken — the OS allocator remains the only source of port numbers, and a lost port costs exactly one preference reset.
@@ -0,0 +1,9 @@
# Desktop installers on the OSS mirror, and a landing download page
## Distribution
Desktop installers move to version-less artifact names following the CLI bundle convention — `penguin-desktop-darwin-{arm64,x64}.dmg` / `.zip`, `penguin-desktop-win32-x64.exe`, `penguin-desktop-linux-x64.AppImage` / `.deb` — with the version carried by the Release tag and `SHA256SUMS.desktop`. The OSS mirror job now mirrors all seven installers plus `SHA256SUMS.desktop` into the immutable per-tag prefix, verified as a set through `SHA256SUMS.desktop`; the CLI bundles' canonical manifest is unchanged.
## Landing site
New `/download` page in the classic software-download shape: one card per platform with the visitor's OS badged, click-to-download buttons that start on GitHub's static `releases/latest/download/<name>` links and swap to the OSS mirror's per-tag URLs once the bucket's `latest.json` pointer resolves client-side (validated exactly like the installer forwarders validate it — a failed fetch, e.g. missing CORS, silently keeps the GitHub links), a manual GitHub/OSS source toggle, checksum and all-releases links, and the unsigned-build first-launch notes. The nav (landing and its docs parity copy), footer, quick-start hint, sitemap and Pages route shells are wired accordingly, and the README (en/zh) gains a desktop app install section pointing at the page.
@@ -0,0 +1,5 @@
# Download source selection for standalone installers and `penguin update`
Standalone `install.sh` / `install.ps1` files gain the same OSS-first source selection the `penguin.ooo` forwarding layer got in 0.2.0 (`PENGUIN_DOWNLOAD_SOURCE=auto|oss|github`). Newly published installers are stamped with their immutable Release tag, so a versioned installer downloads exactly its matching package instead of silently following a future latest Release — `auto` tries that tag on OSS first and falls back to the same tag on GitHub, explicit `PENGUIN_DOWNLOAD_BASE_URL` / fallback overrides keep top priority, and offline installation plus unconditional checksum enforcement are unchanged. An unstamped source-tree installer locks a tag through the OSS `latest.json` pointer before downloading anything, and a one-sided stamping state fails the release rather than shipping mismatched POSIX and Windows installers.
`penguin update` now follows the same contract instead of requiring GitHub at the start of every upgrade: release discovery prefers the validated OSS `latest.json` and its immutable release in `auto` (same-tag GitHub fallback; forced `oss` and `github` modes stay strict), the selected payload base and same-tag fallback are handed to the child installer with a stale inherited fallback explicitly cleared, explicit HTTPS mirrors keep precedence, and source-selection failures are reported localized.
@@ -1,4 +1,4 @@
# Web App: outline windowing, a cost stat that stays put, quieter failure and update chrome
# Web App: outline windowing, a cost stat that stays put, attachments as user content, quieter failure and update chrome
## Conversation outline
@@ -8,6 +8,10 @@ The tick-rail minimap over the stream's left gutter now appears only once a conv
The toolbar cost chip could vanish mid-run: goal rounds reset the live task buckets while the running state blocked the session-total refetch, a page opened during an active run never fetched the accrued total at all, and the idle blip between queued follow-ups could clobber a known total with an empty response. The displayed figure is now sticky and monotone while a session runs — the last fetched total plus each finished Task's settled increment plus the open Task's live estimate, reconciled verbatim once the session is idle. The usage fetch fires on session open regardless of run state, and an empty response can no longer erase a known value.
## Attachments as user content
Uploaded file attachments belong to the user's message and now render like it: below the user text in the same right-aligned container and hover-timestamp footer as uploaded images, instead of a left-aligned system-notice banner above the bubble (`AttachedFilesBanner` becomes presentation-only; its caller owns alignment, animation and the timestamp). A files-only steering message also shows its attached-files banner inside the steering chip — previously the filenames were dropped entirely and the chip rendered empty.
## Quieter chrome
Tool rows no longer print stop-reason markers at all — `[failed]`, `[aborted]`, `[timeout]`, `[malformed]` and `[auth]` are gone; the status icon is the single carrier of the outcome, with the raw reason still in its tooltip and aria-label, and the Trace viewer keeping the literal per-event values. The home page's "new version" hint sheds its accent pill for plain superscript text set in the version line's own type; only the link affordance remains.
@@ -1,10 +1,20 @@
# Unreleased
# Version 0.2.1
Released on 2026-08-04.
- [2026-08-04] Desktop app distribution: installers move to version-less names (`penguin-desktop-<os>-<arch>.<ext>`), are mirrored to the OSS bucket's immutable per-tag prefix alongside `SHA256SUMS.desktop`, and get a landing `/download` page — per-platform cards with the visitor's OS badged, static GitHub latest links that swap to the OSS mirror once its `latest.json` resolves client-side, a source toggle, and checksum links; nav/footer/README wired. ([details](2026-08-04-desktop-distribution-and-download-page.md))
- [2026-08-04] Tooling & CLI: standalone `install.sh` / `install.ps1` gain the forwarder's OSS-first download source selection with immutable Release-tag stamping, and `penguin update` adopts the same contract — OSS `latest.json` discovery with same-tag GitHub fallback in `auto`, strict forced modes, mirror overrides, localized failures. ([details](2026-08-04-download-source-selection.md))
- [2026-08-04] Core: compaction survives malformed summaries (fixes #170) — tolerant extraction, unusable responses retried on the standard backoff budget with a corrective note, burned attempts and tokens surfaced in stats, and one shared `RetryDetail` shape (`error_message`/`attempt`/`retry_in_ms`) across `request_end` and `compaction_end` read by both frontends. ([details](2026-08-04-compaction-retry-observability.md))
- [2026-08-04] Skills: `data-analysis` v2 — tighter data-semantics/delivery/verification constraints, and a leaner multi-run evaluation flow (Pilot results reused as the Formal Baseline, per-Candidate `runs` dispatched Case × Runs, Evaluator accepts `run` as a label). ([details](2026-08-04-data-analysis-skill-v2.md))
- [2026-08-04] Server: the last two IO hotspots closed — the 30-second scheduler tick and the schedules routes now serve from mtime-gated caches (zero steady-state file reads, hand edits still picked up; `.project_config.toml` parsed once per on-disk version across scheduler, routes and usage pricing), and `GET /messages` gains cursor pagination with tail-first web loading, Task-boundary windows, provable-continuity resync splicing and globally correct outline numbering — the no-params response stays byte-identical. ([details](2026-08-04-io-hotspots-scheduler-messages.md))
- [2026-08-04] Dependencies: `hono` bumped to ≥ 4.12.34, resolving the open Dependabot alert (GHSA-8j4g-w8fx-2239, CORS preflight ReDoS); lockfile change confined to the hono chain. ([details](2026-08-04-deps-hono-redos.md))
- [2026-08-04] Desktop app: new `packages/desktop` — an Electron shell that runs the existing server as a utilityProcess on the shared data root and its window on `http://localhost` with token-based no-login sign-in, graceful shutdown, and crash restart; desktop mode on the server (one-shot login, shutdown endpoint, unprinted random seed, `desktopMode`/`sessionVia` on /api/me), a new per-root `server.lock` single-instance guard the CLI and shell both honor, desktop-aware Web App chrome, and three-platform packaging (electron-builder over a pnpm-deploy staging tree, built by a reusable CI matrix ahead of Release creation; unsigned until the signing milestone). ([details](2026-08-04-desktop-app.md))
- [2026-08-04] Desktop app: new `packages/desktop` — an Electron shell that runs the existing server as a utilityProcess on the shared data root and its window on `http://localhost` with token-based no-login sign-in, graceful shutdown, and crash restart; desktop mode on the server (one-shot login, shutdown endpoint, unprinted random seed, `desktopMode`/`sessionVia` on /api/me), a new per-root `server.lock` single-instance guard the CLI and shell both honor, desktop-aware Web App chrome, and three-platform packaging (electron-builder over a pnpm-deploy staging tree, built by a reusable CI matrix ahead of Release creation; unsigned until the signing milestone). UI preferences (language, theme) now survive restarts: the shell reuses last launch's port when still free so the window origin — and its origin-scoped localStorage — stays stable, with `PORT=0` remaining the sole allocator. ([details](2026-08-04-desktop-app.md))
- [2026-08-04] Web App: the public fixed admin password `penguin-2026` is replaced by a random `penguin-<4 digits>` seed printed once at first start (`PENGUIN_SEED_ADMIN_PASSWORD` pins it for tests, policy-checked), and the login endpoint gains per-username exponential throttling (5 free failures, 1s doubling to 60s, `429 too_many_attempts`, reset on success, identical for unknown usernames) so the 4-digit space cannot be enumerated. ([details](2026-08-04-web-app.md))
@@ -18,7 +28,7 @@
- [2026-08-04] Web App: the Traces page becomes a second surface of the session sidebar — shared group/folder/mode-toggle components (the sidebar refactored onto them), workspace and agent grouping on the sidebar's own persisted preference, lazy subagent/schedule/archived folders, server-side session paging — and trace discovery plus the agents-list activity sparkline move off per-request filesystem walks onto a SQLite-derived, mtime-reconciled trace index (rebuildable cache; disk stays the source of truth). CLI sessions now follow the show-CLI-sessions preference (default hidden), titles fall back to the first user prompt, and raw session ids are gone from the page. ([details](2026-08-04-traces-page-scaling.md))
- [2026-08-04] Web App: chat refinements — the conversation outline rail appears from 5 exchanges and windows to ±20 turns around the active one (fixing its overlap onto the composer and, under browser font scaling, onto the prose column), the toolbar cost stat no longer blinks out mid-run, tool rows drop the stop-reason text markers entirely in favor of the status icon, and the home update hint sheds its pill for plain superscript text. ([details](2026-08-04-web-chat-refinements.md))
- [2026-08-04] Web App: chat refinements — the conversation outline rail appears from 5 exchanges and windows to ±20 turns around the active one (fixing its overlap onto the composer and, under browser font scaling, onto the prose column), the toolbar cost stat no longer blinks out mid-run, uploaded file attachments render as user content (right-aligned below the text like uploaded images, and inside the steering chip instead of vanishing from files-only steering), tool rows drop the stop-reason text markers entirely in favor of the status icon, and the home update hint sheds its pill for plain superscript text. ([details](2026-08-04-web-chat-refinements.md))
- [2026-08-04] Fix: ANSI color codes no longer leak into tool output — the CLI gates color on TTY/`NO_COLOR`/`TERM` with `FORCE_COLOR` override semantics matching Node, the command tool strips inherited `FORCE_COLOR`/`CLICOLOR_FORCE` from child environments so its `NO_COLOR=1` hardening wins, and the Web renders tool output through a defensive ANSI stripper covering historical Traces. ([details](2026-08-04-ansi-tool-output.md))
+51
View File
@@ -0,0 +1,51 @@
PenguinHarness 0.2.1 — the desktop app arrives: the full Web experience as a double-click application for macOS, Windows and Linux, opening already signed in, with installers on the new download page and the OSS mirror.
## Install
**Desktop app** (new): grab your platform's installer from [penguin.ooo/download](https://penguin.ooo/download) — served from the OSS mirror when it is reachable, GitHub otherwise. Current builds are unsigned: on first launch use right-click → Open on macOS, and "More info → Run anyway" past Windows SmartScreen.
CLI / server (Linux, macOS; bundled Node runtime):
```sh
curl -fsSL https://penguin.ooo/install.sh | sh
penguin web
```
Windows (PowerShell):
```powershell
irm https://penguin.ooo/install.ps1 | iex
penguin web
```
Or via npm (needs Node >= 24):
```sh
npm install -g @prismshadow/penguin-cli
```
## Highlights
**The desktop app.** A thin Electron shell over the unchanged server and Web App: it forks the server on the shared `~/.penguin/data` root, opens its window already signed in — no terminal, no login page, no initial password — and everything still flows through the same HTTP API (no preload, no node integration). A per-root single-instance lock keeps the schedule scheduler and `web.db` single-writer safe across the shell and CLI alike; if a CLI-started server is already up, the app attaches to it. UI preferences survive restarts via a stable window origin (the shell reuses last launch's port when still free). Installers: macOS dmg (Apple silicon / Intel), Windows NSIS, Linux AppImage / deb.
**A download page with mirror-aware links.** [penguin.ooo/download](https://penguin.ooo/download) shows one card per platform with your OS badged. Buttons start on GitHub's static `releases/latest/download` links — installers now carry version-less names, which is what makes those links possible — and swap to the OSS mirror's immutable per-tag URLs once the bucket's `latest.json` resolves in the browser, with a manual source toggle and checksum links. Desktop installers are mirrored to OSS alongside the CLI bundles.
**Download source selection everywhere.** Standalone `install.sh` / `install.ps1` gain the forwarder's OSS-first selection (`PENGUIN_DOWNLOAD_SOURCE=auto|oss|github`) with immutable Release-tag stamping, so a saved versioned installer downloads exactly its matching package forever. `penguin update` adopts the same contract: OSS `latest.json` discovery with a same-tag GitHub fallback in `auto`, strict forced modes, explicit HTTPS mirror precedence, and localized failure messages.
**Compaction failures fixed — and visible.** Models that mangle the `[summary]` format no longer trap a session in a failing-compaction loop (#170): extraction applies a tolerance ladder, an unusable response retries on the standard backoff budget with a corrective note, and the burned attempts and tokens finally show up in stats and the cost center, with one shared retry-detail shape across the CLI and Web.
## Notable in this release
- **Login hardened.** The fixed `penguin-2026` seed admin password is replaced by a random one printed once at first start, and the login endpoint gains per-username exponential throttling.
- **Skills manageable in the app.** Agent settings gains a Skills tab (list from disk, uninstall, zip import/export, chat-driven install), agent-list icons deep-link to settings tabs, and the new `skill-porting` library skill brings skills in from other ecosystems; `data-analysis` moves to v2 with a leaner multi-run evaluation flow.
- **New chat defaults per Project.** Default agent, working directory, approval mode, thinking level and model, seeded into new drafts.
- **A Traces page that scales.** Shared sidebar grouping components, workspace/agent grouping, server-side session paging, and a SQLite-derived mtime-reconciled trace index replacing per-request filesystem walks.
- **Chat refinements.** The conversation outline rail windows to ±20 turns and stops overlapping the composer, the cost stat stays put across task boundaries, uploaded file attachments render as user content (and inside steering chips), tool rows drop `[failed]`-style text markers, and ANSI color no longer leaks into tool output.
- **Server IO hotspots closed.** The scheduler tick and schedules routes serve from mtime-gated caches, and `GET /messages` gains cursor pagination with tail-first web loading.
- **Dependencies.** `hono` bumped past the CORS-preflight ReDoS advisory (GHSA-8j4g-w8fx-2239); OpenRouter catalog gains `qwen/qwen3.8-max`.
## Requirements
Linux or macOS (x64 / arm64), or Windows 10+ (x64). The desktop app and the CLI installers bundle their own runtime; installing from npm needs Node >= 24. All data stays under `~/.penguin/data`.
Full detail: [changelog/0.2.1/](https://github.com/Prism-Shadow/penguin-harness/tree/main/changelog/0.2.1).