Skip to content

feat(panel): optional localized labels for buildStatusPanel - #255

Open
ranxianglei wants to merge 3 commits into
masterfrom
2026-09-12_panel-labels
Open

ranxianglei wants to merge 3 commits into
masterfrom
2026-09-12_panel-labels

Conversation

@ranxianglei

Copy link
Copy Markdown
Owner

Problem

buildStatusPanel hardcodes every user-facing label in English. Adapters that want a localized /acp dashboard (ranxianglei/billion-context-pi#153) cannot translate the panel without patching kernel internals.

Change

  • StatusPanelInput gains optional labels?: Partial<PanelLabels> — 19 section-header keys (title, context, growth, sent, sentOfLimit, sessionOnly, breakdown, 5 category names, promptCache, nudgeActive/nudgeTierInfo/nudgeIdle, blocksHeader/blocksNone, tagVisibility), each substituting {placeholder} params.
  • Per-key fallback: omit any key and it renders the English default (DEFAULT_PANEL_LABELS, exported). Omit labels entirely and output is byte-identical to before — verified by a dedicated test.
  • Display-only: per-block lines and the compressible-ranges section stay structural (block/message IDs are never translated). Model-facing text is untouched.
  • New exports from acp-kernel/panel: DEFAULT_PANEL_LABELS, PanelLabels, fill, displayWidth, padLabel, renderTitleBox.
  • Title box is width-aware: CJK titles pad correctly (display-width based); non-default titles get a computed box; the exact default title reuses the frozen legacy box so existing dashboards do not shift.
  • fill() leaves unknown {placeholders} intact instead of crashing (typo in a pack stays visible).

Verification

  • npm run typecheck clean; npm test 678/678 pass (13 new tests: byte-identical default, legacy box verbatim, CJK box geometry, long-title widening, per-key fallback, full marker pack, idle nudge, sentOfLimit omission at limit=0, zero-active/none block branches, fill/pad/displayWidth units, key-list integrity); npm run build OK.

Release note

Additive only — safe for v0.0.65. Hosts not passing labels see zero behavior change (omp included). billion-context-pi P-B (language packs + config + detection chain) lands after this ships on npm.

@github-actions

github-actions Bot commented Sep 12, 2026

Copy link
Copy Markdown

📦 Built Package Artifact

Branch: 2026-09-12_panel-labels (998f889)

Option A — Install from npm PR tag (recommended)

In your adapter project:

npm install acp-kernel@pr-255

Each push to this PR publishes a new version under the pr-255 npm tag.

Option B — Download artifact

  1. Download the artifact from the Actions run
  2. Extract the tarball and install:
tar xzf acp-kernel-pr255.tgz
npm install ./package

This comment is automatically updated on each push.

@ranxianglei

Copy link
Copy Markdown
Owner Author

🤖 Powered by ework · qwen3.8-27b

[bot] 🏷 Review started for PR #255 (2026-09-12_panel-labels, single commit on top of master @ v0.0.64; 4 files: src/panel/labels.ts new, src/panel/panel.ts, src/panel/index.ts, tests/panel-labels.test.ts). Diff is clean — no unrelated churn, no version/lockfile changes. Running typecheck/tests/build plus an independent byte-identity cross-check of panel output vs master before I give a verdict.

@ranxianglei

Copy link
Copy Markdown
Owner Author

🤖 Powered by ework · qwen3.8-27b

[bot] 🏷 Review complete — verdict: mergeable (merge itself is human-only per repo rules).

What I verified independently (not just taken from the PR description)

  • Diff cleanliness: exactly 4 files (src/panel/labels.ts new, src/panel/panel.ts, src/panel/index.ts, tests/panel-labels.test.ts new) — every line in scope, no version/lockfile/unrelated churn. No packaging change needed: package.json exports ./panel and the tsup entry already exist on master.
  • Pre-flight: npm run typecheck clean · npm test 680/680 (your 678 + 2 regression tests I added below) · npm run build OK.
  • Byte-identity claim — proven by execution, not inspection: rendered 4 fixtures covering every panel branch (rich tier-2 active / idle-no-limit-zero-active / bare no-nudge / partial-cats-negative-session-only) against master@6cf0957 and the PR branch — output byte-identical whenever labels is omitted. An independent second-agent review went further with an 18-scenario differential harness (all conditionals × cache/blocks/nudge variants), including a reason string full of $&/$$/$1 — safe because fill() uses a function replacer, where String.replace does no $-substitution. All 18 scenarios byte-identical.
  • Display-only claim holds: nudge.reason passes verbatim into display templates only; per-block lines ([bN] T{tier} …) and the compressible-ranges section are untouched structural text; render-refs/nudge-text not modified.
  • 19-key contract: TS enforces DEFAULT_PANEL_LABELS: PanelLabels completeness and the sorted key-list test matches reality; all 19 keys used in panel.ts.

Bug found & fixed directly on the PR branch (2 commits, pushed)

Reproduced first: buildStatusPanel({ ..., labels: { title: undefined } })TypeError: s is not iterable (in displayWidth). Root cause: { ...DEFAULT_PANEL_LABELS, ...input.labels } lets one explicit-undefined key blank out its default. This is realistic for billion-context-pi P-B: packs built by Object.assign/conditional spreads from config can carry explicit undefined keys, and Partial<PanelLabels> accepts them at compile time.

  • 17977b2 — new exported resolvePanelLabels() (from acp-kernel/panel) copies only string entries over the defaults; panel.ts uses it. 2 regression tests added.
  • f10f976 — follow-up from the second review: unknown/typo'd pack keys are now ignored too (resolved object stays exactly the 19 known keys instead of leaking stray properties); test pins number/String-object/null/unknown-key behavior.

Byte-identity re-verified after both commits. Both reviewers (me + independent agent, satisfying the 2-agent rule) verdict: mergeable, zero blockers/majors.

Report-only findings (not blocking)

  1. Pre-existing, repo-wide: npm run format:check is red at master tip already — there is no Prettier config anywhere, so the script checks everything against printWidth-80 defaults while the established style is ~140 cols (99 files failing before this PR; CI does not gate on it). Formatting this PR's files to width 80 would make them inconsistent with the rest of src/. Suggest a separate housekeeping issue: add a .prettierrc matching the de-facto width, or drop the script. (I don't have an issue-creation tool from here, so flagging for you.)
  2. Nits, intentionally left: displayWidth counts emoji/ambiguous-width chars as 1 column (fine for a CJK-focused feature); fill()'s k in params walks the prototype chain (theoretical only — templates are internal constants).

Ready for your merge when convenient: #255


中文摘要:修复了 labels 包中显式 undefined/null/未知键会冲掉英文默认值并导致渲染崩溃的问题(新增 resolvePanelLabels 归一化合并并补了回归测试),其余功能经双 agent 独立审查与逐字节差分验证均通过,可以合并。

ework-agent added 3 commits September 21, 2026 23:14
Adds labels?: Partial<PanelLabels> to StatusPanelInput (per-key fallback to English defaults, display-only) plus exported helpers fill/displayWidth/padLabel/renderTitleBox. Default output stays byte-identical (verified by test). Prerequisite for ranxianglei/billion-context-pi#153.
A plain spread merge let an explicit undefined/null pack entry (e.g. from a
config-driven language pack) blank out its English default and crash the
display-width renderers with a TypeError. resolvePanelLabels() now copies
only string entries over DEFAULT_PANEL_LABELS; exported from acp-kernel/panel.
resolvePanelLabels now ignores pack entries whose key is not part of
PanelLabels (typo'd overrides from a runtime pack stay inert instead of
leaking as stray properties on the resolved object), and the regression
test pins number/String-object values and unknown keys to defaults.
@ranxianglei
ranxianglei force-pushed the 2026-09-12_panel-labels branch from f10f976 to 998f889 Compare September 21, 2026 15:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant