Files
penguin-harness/changelog/0.1.0/2026-07-20-tooling.md
T
2026-07-21 18:00:11 +08:00

9.6 KiB

Tooling, language, and infrastructure

Repository language, dev commands, the changelog layout itself, and dependency upgrades.

Make English the repository working language

Translated all residual non-i18n Chinese (comments, error/log messages, test titles and fixtures, package metadata, e2e mock content) to English; Chinese remains only in i18n catalogs, zh documents, and CJK-purpose test fixtures.

Details

  • Package metadata: package.json descriptions (root/server/web/landing) and the link:cli fallback echo.
  • Source comments: all remaining Chinese comments, including the SQL comment set in packages/server/src/db/schema.ts.
  • Hardcoded non-i18n user-facing strings (user-visible language change; error codes, placeholders, and limits untouched): server HTTP/validation/409 messages, schedule TOML validation errors, server logs, core SDK errors, CLI fallback errors, web provider invariants.
  • Tests: all Chinese describe/it titles and language-irrelevant fixtures translated; assertions realigned to the new English source strings.
  • e2e: mock LLM conversation content and cross-file branch markers translated consistently (the substring relationships the mock's includes() dispatch relies on are preserved); zh-locale UI assertions kept; e2e/README.md translated.
  • Kept as required Chinese: zh i18n catalogs and fields (strings.ts dictionaries, CLI i18n.ts, titleZh, short_description_zh, the zh language-name label, *.zh.md docs) and test literals that assert zh i18n output or exercise CJK-specific behavior (display width, CJK id validation, title-language consistency, zh-CN e2e UI assertions).
  • Known gap: web formatTaskStats still hardcodes zh stat-line fragments; the proper fix is routing them through the locale catalogs.

PR: #5 (merged 2026-07-20)

Reorganize the changelog by release version

The top level now holds only version folders; each version's README carries the one-line-per-change index, and detail files live inside the folder (mirrors agenthub PR #162).

Details

  • changelog/<version>/README.md is the release summary: one line per change with its title and one-sentence summary, linking the detail file relatively; 0.1.0/README.md absorbs the section previously kept in the top-level index.
  • changelog/README.md now documents only the layout and the entry conventions (no per-file listing).
  • The working rules (AGENTS.md, CONTRIBUTING.md) point index updates at the version folder's README instead of the top-level file.

Serialize the dev prebuild to fix concurrent dev:server / dev:web clobbering

dev:server and dev:web now share a lock-serialized, deduplicated prebuild of skills and core, so launching both at the same time no longer corrupts dist/ (previously two tsup builds with clean:true raced in the same output directories).

Details

  • New scripts/dev-prebuild.mjs: takes an exclusive on-disk lock (atomic mkdir under node_modules/) around pnpm --filter skills --filter core build; concurrent invocations wait instead of clobbering. Locks left by crashed runs are stolen when the holder PID is dead or the lock is older than 10 minutes.
  • A 5-second success stamp collapses duplicate builds: starting dev:server and dev:web simultaneously builds once (the waiter skips), and dev:server's inner re-invocation is a no-op. The window is deliberately tiny so an edit-then-restart cycle always rebuilds — the "never start on stale deps" behavior is unchanged.
  • Root dev:server now just delegates to the server package's dev script (which prebuilds via the shared script), removing the historical double build of core; dev:web prebuilds via the script and then starts Vite.
  • pnpm dev run standalone from packages/server now also builds skills (it previously built only core, even though the server imports skills at runtime).
  • Verified: concurrent invocations wait/skip correctly and release the lock; a simultaneous dev:server + dev:web start performs a single build with both servers coming up cleanly.

Add a combined pnpm dev and a dev:landing shortcut

pnpm dev now starts the backend and the web app together with prefixed logs (workspace deps built once via the shared prebuild lock), and pnpm dev:landing serves the landing page dev server from the repo root.

Details

  • pnpm dev runs concurrently -n server,web "pnpm dev:server" "pnpm dev:web". Merging the two was previously unsafe: each command prebuilt skills/core with tsup clean: true into the same dist/ directories and the parallel builds clobbered each other. The lock-serialized prebuild (see the serialize-dev-prebuild entry) removed that race, and its success stamp collapses the two prebuilds into a single build on a combined start.
  • pnpm dev:landing delegates to the landing package's Vite dev server (port 7366, completing the 7364/7365/7367 dev-port family). The landing package has no workspace deps, so no prebuild is involved.
  • concurrently added as a root devDependency; the dev-command lists in README.md and README.zh.md now cover dev and dev:landing.
  • Verified: a combined start performs exactly one skills+core build (the other prebuild waits and skips), with the server on 127.0.0.1:7364 and Vite on localhost:7365; the landing dev server responds on localhost:7366. Note Vite binds localhost (IPv6 ::1) — use localhost, not 127.0.0.1, when probing the Vite ports with curl.

Dev commands keep pnpm install current automatically

Forgetting pnpm install before a dev command no longer breaks the start: every dev command's prestep checks install freshness (lockfile-hash stamp) and runs pnpm install itself when node_modules is missing or the lockfile changed.

Details

  • scripts/dev-prebuild.mjs gains an install-freshness step inside its existing lock: the pnpm-lock.yaml content hash is stamped after a successful install, so the usual dev start pays nothing; a fresh clone or a pulled lockfile change triggers pnpm install automatically (concurrent dev commands still install/build exactly once).
  • The lock and stamps move from node_modules/ to the OS temp directory keyed by the repo path — they must exist before the first install does (the old location crashed on a fresh clone), and per-checkout isolation comes from the key.
  • dev:docs / dev:landing have no workspace deps to build but still need current installs: they now run the prestep with --install-only.

Upgrade AgentHub to 0.4.0 and adopt the opaque fidelity payload

@prismshadow/agenthub 0.3.3 -> 0.4.0 (agenthub PR #159): content items replace the item-level signature/phase fields with one opaque fidelity object, and OmniMessage now carries it verbatim end to end — Trace, replay, and resume included; the agenthub-dev skill joins the built-in library.

Details

  • OmniMessage complete payloads (text, thinking, inline_data, inline_thinking, tool_call) replace signature?: string / phase?: string | null with fidelity?: Record<string, unknown> — an opaque wire-fidelity payload written to the Trace as-is and passed back verbatim on replay (Claude thinking signatures, GPT-5 encrypted reasoning {id, encrypted_content} and {phase} markers, the OpenAI-compatible {reasoning_field} name). Builders take the object directly; an empty object is treated as absent.
  • GenerativeModel's streaming translator mirrors AgentHub baseClient aggregation: a thinking block is closed by its fidelity payload and a run of equal fidelity is one block (the OpenAI-compatible clients stamp every thinking delta with the same {reasoning_field}, which must not split blocks — this carries agenthub's reasoning-field replay fix through PenguinHarness so multi-turn conversations against strict OpenAI-compatible upstreams survive); a text segment splits on a differing fidelity.phase and closes on fidelity.signature, merging fidelity keys. Text-phase stickiness across segments is gone (mirrors baseClient).
  • The agenthub-dev skill (AgentHub's own model-support development workflow) is installed into the built-in library under the Penguin Development group, completed to the library contract (version/updated frontmatter, short descriptions, a "Before you start" section, and a custom icon).
  • Malformed-classification fix for 0.4.x: agenthub now surfaces truncated streamed tool-call arguments as its own ToolCallArgumentParseError (previously a raw SyntaxError) and thinking-only completions as EmptyResponseError; isMalformedJsonParseError recognizes both (instanceof + name fallback + cause chain), so these still end as malformed and the engine reconnects and retries instead of failing the turn (caught by the malformed e2e).
  • Docs (omni-message, interfaces, sessions-and-traces; en + zh) and the design specs updated to the fidelity semantics.
  • Traces written before this change carried signature/phase on payloads; per the pre-release no-migration policy they are not converted (old fields are ignored on replay — resume of such Sessions loses provider fidelity; delete and recreate if needed).

One file per change had grown to 35 fragment files for this release alone; related changes are now merged into six date-slug entry files (models-and-catalog, web-app, landing-site, blog-and-docs, readme, tooling), each keeping the standard entry shape — H1 title, one-sentence summary, then per-change details — with the version README listing one line per entry file. The layout convention itself is unchanged; the branch was also rebased onto main to linearize away the merge commit with the final tree kept byte-identical.