* fix(matrix): truncate inbound preview on UTF-16 code-point boundary
The matrix inbound verbose preview used bodyText.slice(0, 200) before logging.
When a supplementary-plane character (emoji, extended CJK) straddles the 200th
code unit, the slice splits its surrogate pair and emits a lone surrogate into
the verbose log line. Lone surrogates corrupt JSON log serialization, break
terminal rendering, and crash UTF-8-validating log shippers.
Use the shared truncateUtf16Safe helper (already used by the mattermost sibling
monitor after #101630) to keep complete surrogate pairs intact. No behavior
change for ASCII input; the preview is still capped at 200 code units.
Co-Authored-By: Claude <noreply@anthropic.com>
* test(matrix): fix inbound-preview test for lint and lib target
- Avoid String.prototype.isWellFormed (ES2024 lib): use the encodeURIComponent
well-formedness probe instead, which works on the project's TS lib target.
- Replace literal string concatenation with template strings to satisfy the
no-useless-concat lint rule. No behavior change in the assertions.
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(channels): keep inbound log previews UTF-16 safe
* test(line): type verbose preview fixtures
---------
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
* fix(line): truncate outbound altText, location, menu, and code fields on code-point boundaries
* fix(line): use safe truncation for receipt card altText
* fix(line): count rich menu limits by grapheme
---------
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
The multi-account resolver had two bugs that prevented webhook routes
from registering:
1. `accounts.default` was ignored because `resolveLineAccount` short-
circuited the account lookup whenever `accountId` resolved to
`DEFAULT_ACCOUNT_ID`. Credentials placed under
`channels.line.accounts.default` therefore never reached the
gateway, and the default `/line/webhook` route never registered.
2. Named accounts defaulted to disabled when they did not explicitly
set `enabled: true`. A configured second account
(`channels.line.accounts.<name>`) was treated as disabled before
`startAccount` ran, so its webhook never registered either.
Both behaviours diverged from the Telegram plugin, which uses
`baseEnabled && accountEnabled` with each defaulting to
`enabled !== false`. Align the LINE resolver with that idiom and add
seven regression tests covering the credential lookup, the default-
enabled semantics, and channel-level disable propagation.
* fix(line): truncate template title/altText on grapheme boundaries, not raw UTF-16
createConfirmTemplate/createButtonTemplate/createTemplateCarousel/createCarouselColumn/
createImageCarousel truncated title and altText with a raw `.slice(0, N)`, so an
emoji straddling a LINE field limit (e.g. a 40-char button title) was cut in half,
leaving a lone high surrogate that LINE renders as the replacement char or rejects.
Route those fields through the file's existing grapheme-safe truncateTemplateText
(already used for the text body) via a small truncateOptionalTemplateText wrapper.
Byte-identical for all-BMP input; only straddling-emoji truncation changes.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* chore: retry OpenGrep scan (HTTP 502 infra flake)
* test(line): cover grapheme-safe template fields
---------
Co-authored-by: ly-wang19 <ly-wang19@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
Use surrogate-safe truncation for LINE action labels/data, including card-command, markdown link, quick-reply, and media-control action surfaces, with focused regression coverage.
* chore(release): close out 2026.6.10 on main
* chore(release): align native app metadata for 2026.6.10
* chore(release): sync Android 2026.6.10 notes
* docs(changelog): preserve 2026.6.9 history
* docs(changelog): preserve 2026.6.9 history
* fix(line): cap carousel column text at 60 chars with title or image
LINE limits a carousel column's text to 60 characters when the column has
a title or thumbnail image, and 120 characters otherwise. createCarouselColumn
always truncated to 120, so a column with a title/image and 61-120 char text
exceeded the limit and made LINE reject the entire carousel reply (HTTP 400).
Apply the conditional limit (mirroring the buttons template) and drop the now
redundant slice in createProductCarousel.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(line): apply conditional text limits across templates
* fix(line): truncate template text by code point
* fix(line): preserve grapheme clusters when truncating
* fix(line): apply compact limit for default actions
* fix(line): follow title and thumbnail text limits
* fix(line): truncate template text within UTF-16 limits
* fix(line): preserve required text within template limits
* fix(line): preserve carousel product prices
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Vincent Koc <25068+vincentkoc@users.noreply.github.com>
Bumps OpenClaw release metadata to 2026.5.31 across package manifests, app version files, plugin metadata, changelog headings, and generated shrinkwraps.
Verification:
- pnpm plugins:sync:check
- pnpm ios:version:check
- pnpm deps:shrinkwrap:check
- git diff --check
- stale 2026.5.30/build-code scan across changed files
- autoreview clean: no accepted/actionable findings
- PR CI green for real gates: Checks, security scans, dependency guard, app lanes, real behavior proof
Known non-code workflow issue:
- label workflow failed because this PR hits GitHub's 100-label issue cap before the size-label step.