* fix(sessions): bound trajectory snapshot and pointer reads
* test(sessions): align oversized snapshot assertion with bounded reader error message
* fix(sessions): cap follow-mode trajectory deltas
ClawSweeper review noted that the trajectory snapshot read was bounded
but the follow-mode delta read (Buffer.alloc(fileState.size - offset))
was not. A runaway trajectory append could still OOM the tail loop.
Reject deltas above TRAJECTORY_RUNTIME_FILE_MAX_BYTES and add regression
coverage for the oversized-delta path.
* test(sessions): exercise trajectory limits through command path
---------
Co-authored-by: Vincent Koc <25068+vincentkoc@users.noreply.github.com>
* fix(http-error-body): keep emoji / surrogate pairs intact during error body truncation
Replace .slice(0, limits.maxChars) with truncateUtf16Safe() so that
emoji straddling the maxChars boundary don't produce lone surrogates
that render as � in error diagnostics. Matches the sibling http-body.ts
which already uses truncateUtf16Safe.
Co-Authored-By: Claude <noreply@anthropic.com>
* test: cover UTF-16 HTTP body branches
---------
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
* fix(gateway): support native Windows exec approvals
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
* chore: defer changelog entry to release
* test: use tracked approvals temp directories
---------
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
* fix(tasks): keep emoji / surrogate pairs intact during terminal output truncation
.slice() counts UTF-16 code units; use Array.from() to count full
code points instead, preventing lone surrogates in task list output.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* fix(tasks): preserve terminal column width
---------
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
* fix(control-ui-assets): keep emoji / surrogate pairs intact during last-line truncation
.slice(0, 239) counts UTF-16 code units; an emoji straddling the
cut point produces a lone surrogate rendering as in WebUI assets.
Use [...last] spread to count full code points instead.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* fix(control-ui-assets): preserve diagnostic length cap
---------
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
* fix(auto-reply): keep suppressed reply text preview truncation UTF-16 safe
String.prototype.slice at offset 160 can split surrogate pairs in
reply text previews logged for suppressed auto-replies. Replace raw
slice(0, 160) with truncateUtf16Safe — already imported in this file.
* test(auto-reply): exercise suppressed preview logging
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
* fix(acp): use truncateUtf16Safe for event mapper error text truncation
.slice(0, 100) on ACP event argument values can split surrogate
pairs from emoji or CJK text, producing U+FFFD in error/warning
notices shown to operators.
Co-Authored-By: Claude <noreply@anthropic.com>
* test(acp): cover UTF-16-safe tool titles
* refactor(acp): keep event mapper import leaf-only
---------
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
* fix(gateway): keep plugin approval title and description truncation UTF-16 safe
Node.js String.prototype.slice cuts at UTF-16 code unit boundaries,
which can split surrogate pairs (emoji, CJK supplementary characters)
into lone surrogates that render as U+FFFD in approval UI payloads.
Use truncateUtf16Safe for both title and description fields in
createPluginApprovalsAttachment so approval requests never deliver
broken characters to the gateway approval UI.
Fixes #???
* test(gateway): exercise UTF-16 approval payloads
---------
Co-authored-by: wm0018 <wu.min5@xydigit.com>
* fix(session-cost-usage): keep emoji / surrogate pairs intact during content truncation
.slice(0, maxLen) counts UTF-16 code units, so an emoji straddling
the cut point produces a lone surrogate that renders as � in
usage cost CLI output. Use [...str] to count full code points instead.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* test(usage): cover UTF-16-safe log truncation
---------
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
* fix(status): keep issue message truncation UTF-16 safe
String.prototype.slice at offset 90 can split surrogate pairs in issue
titles displayed by `openclaw status --all`, rendering broken U+FFFD in
the channel issues column.
Replace raw slice(0, 90) with truncateUtf16Safe to match the existing
UTF-16-safe truncation hardening pattern.
Fixes #???
* test(status): cover UTF-16-safe issue rendering
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
sessions.delete gains an explicit archivedOnly param (additive protocol
schema change, Swift models regenerated): with archivedOnly=true, the
dispatcher grants operator.write and the handler requires the target to
already be archived (archive-then-delete keeps destructive intent a
two-step action). Without the flag nothing changes: deletes require
operator.admin, so internal fallback/synthetic dispatch, subagent cleanup,
and CLI minting keep their admin contracts, and the session-kill HTTP
endpoint pins admin explicitly since it terminates live runs.
Android sends archivedOnly and offers Delete only on archived rows, where
its bounded (non-admin) operator session is now authorized; active rows
archive first. iOS/web connect with admin and keep unrestricted deletes.
Refs #100712
* fix(backup): close archive stream before retry cleanup
Own the tar source and file writer with stream.pipeline so live-file EOF failures close the partial archive before Windows cleanup. Keep one native Windows handle-release regression and focused CI coverage.
Fixes#101382
Co-authored-by: 徐闻涵0668001344 <xu.wenhan1@xydigit.com>
* test(backup): track archive retry temp directory
* test(backup): model tar archive streams
* test(backup): model retry cleanup streams
---------
Co-authored-by: 徐闻涵0668001344 <xu.wenhan1@xydigit.com>
- Raise typing-breaker default from 2 to 5 consecutive failures via a
named constant, keeping explicit overrides intact.
- Extend rich-plain-fallback trigger map to classify
RICH_MESSAGE_CONTENT_REQUIRED alongside existing invalid-entity
errors so both durable and streaming send funnels benefit.
- Add empty rendered-rich-HTML guards before sendRichMessage in both
the durable chunk loop (send.ts) and the streaming delivery funnel
(delivery.send.ts), preventing doomed Bot API calls and preserving
later valid chunks.
- Add regression tests for the default typing breaker, delivery-side
and durable-side RICH_MESSAGE_CONTENT_REQUIRED fallback behavior.