* perf(agents): skip per-turn context deep clone when no context handler is registered
* perf(agents): avoid duplicate context handler scan
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Persist qualified QQBot group and guild routes so session announcements return to the originating conversation without letting direct-message turns overwrite the shared route.
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Co-authored-by: lzyyzznl <lzyyzznl@users.noreply.github.com>
* fix(cron): hint after disable about list filtering disabled jobs by default
* fix(cron): use !params.enabled in disable-hint guard for oxlint compliance
* docs(cron): clarify disabled jobs in list output
* fix(cron): keep disable hint interactive
* test(cron): use exported store snapshot helper
* test(cron): create disable-list regression job via service
* docs(cron): defer list default contract wording
* test(cron): tighten disable list coverage
Co-authored-by: Kate Stahnke <35552+kate@users.noreply.github.com>
* docs(cron): document enabled-only list default
Co-authored-by: Kate Stahnke <35552+kate@users.noreply.github.com>
---------
Co-authored-by: Kate <35552+kate@users.noreply.github.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
* docs(skills): support CodexBar CLI on Linux
Enable the existing model-usage skill on Linux when the supported CodexBar CLI is present, and document the official Homebrew, AUR, and release-tarball install paths.
Co-authored-by: Santiago <shbernal.01@gmail.com>
* docs(skills): link CodexBar Linux packages
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Branch menu (list/switch) for macOS+iOS shared chat via sessions.branches.*;
rewind/fork/switch gated on run activity and pending outbox work through a
durable session-mutation lease; outbox rows carry branch-epoch ownership with
local-only flush checks, atomic confirm/park transitions, attempt-versioned
delivery callbacks, fresh retry identity for possibly-accepted rows, and
epoch-guarded branch evidence; 21-locale native translations for new strings.
* fix(browser): retire durable tab rows whose browser never returns
Durable cleanup defers whenever ownership cannot be proven, so a browser
that never comes back at the same cdpUrl leaves its rows behind forever:
each sweep re-claims them, fails the identity lookup, warns, and defers
again. Nothing in the subsystem removes a row by age.
The `browser.session-tabs` namespace is opened with a 5000-row cap and
`reject-new`, so once those rows accumulate to the cap, tracking a new tab
throws PLUGIN_STATE_LIMIT_EXCEEDED. That propagates into the compensation
path in browser-tool-session-tabs.ts, which closes the tab the user just
opened and rethrows -- every `browser open` on that profile then opens a
tab, closes it again, and errors, with no self-healing path.
Bound the retry: when a close attempt reports the target unavailable and
the tab has been unused for longer than the retire window, drop the row
instead of deferring again. A browser returning after that long almost
always carries a fresh instance fingerprint, which retires the row through
the ownership-mismatch path anyway.
closeTrackedBrowserTabsForSessions now accepts `now` like the sweep does,
so lifecycle cleanup can be exercised on a coherent clock.
* refactor(browser): split session tab cleanup claim and test harness
check-lint failed on max-lines: session-tab-registry.ts was at 699 of its
700-line budget and the durable registry test at 982 of 1000, so the retire
branch and its regression test pushed both over.
Extract the cleanup claim bookkeeping (claim, ownership match, delete) into
session-tab-cleanup-claim.ts, and the durable registry test shapes into
session-tab-registry.sqlite.test-helpers.ts, matching the existing
*.test-helpers.ts convention in this directory. No behavior change.
* test(browser): protect unreachable retirement races
Co-authored-by: Yigtwxx <yigiterdogan023@gmail.com>
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
GroupChatSchema used .positive() which rejects 0, while all other
historyLimit schemas use .min(0). This caused a silent config reload
failure when setting messages.groupChat.historyLimit to 0.
Change .positive() to .min(0) and add test coverage.
Fixes https://github.com/openclaw/openclaw/issues/65305
* fix(clawhub): use fatal UTF-8 decoding for all ClawHub HTTP responses
Replace forgiving TextDecoder() with TextDecoder(utf-8, { fatal: true })
in three functions that decode ClawHub HTTP response bodies:
- parseClawHubJsonBody (JSON API responses)
- fetchClawHubSkillCard (skill card markdown)
- fetchClawHubPromotionsFeed (promotions feed, etag-cached)
Invalid UTF-8 bytes now throw TypeError immediately instead of silently
substituting U+FFFD, preventing corrupted payloads from being parsed,
cached, or rendered.
* fix(clawhub): extract decodeClawHubResponseBody helper with fatal UTF-8 decoding
Replace three inline TextDecoder() calls with a single exported
decodeClawHubResponseBody helper that uses fatal: true, so malformed
UTF-8 bytes throw TypeError instead of silently substituting U+FFFD.
Add focused test coverage for the helper: valid UTF-8, ASCII,
empty buffer, and invalid 0xFF byte at start, middle, and end positions.
* fix(clawhub): remove unused export of decodeClawHubResponseBody
Make decodeClawHubResponseBody internal since it is only used within
clawhub.ts. Remove the standalone test for this thin TextDecoder wrapper;
its behavior is covered by consumers (parseClawHubJsonBody, etc.).
* fix(clawhub): reject malformed UTF-8 responses
Co-authored-by: chenyangjun-xy <chenyangjun@xydigit.com>
* test(clawhub): verify failed refresh cache persistence
Co-authored-by: chenyangjun-xy <chenyangjun@xydigit.com>
* test(clawhub): use typed malformed response buffer
Co-authored-by: chenyangjun-xy <chenyangjun@xydigit.com>
---------
Co-authored-by: chenyangjun-xy <chenyangjun@xydigit.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
* fix(qa-lab): reject hex/exponent Telegram SUT uid env values
* test(qa-lab): add direct unit tests for parseSutId strict int parsing
Export parseSutId and add 15 direct unit tests covering hex/exponent/fraction/
empty/whitespace/zero/negative rejection and valid decimal acceptance across
UID, GID, and CLEANUP_TIMEOUT_MS keys. The 3 existing integration tests
already prove the full CLI chain rejects malformed UIDs before gateway startup.
Mutation check: reverting to permissive Number() parsing causes 6 tests to
fail (4 unit + 2 integration).
Co-Authored-By: nebulacoder-v8.0 <noreply@zte.com.cn>
* test(qa-lab): cover GID and cleanup-timeout CLI reject-before-gateway
* fix(qa-lab): drop stale live-scenario mocks from SUT uid tests
* style(qa-lab): oxfmt import order in telegram cli.runtime
* test(qa-lab): streamline strict SUT integer coverage
---------
Co-authored-by: nebulacoder-v8.0 <noreply@zte.com.cn>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
* fix(config): reject gateway.port values outside the 1–65535 TCP range
Tighten the gateway.port schema to 1–65535 and add a Doctor
migration that removes out-of-range port values from existing
configs, so previously loadable configs with port 65536+ do not
fail startup after the schema change.
Fixes#109293
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(doctor): repair gateway port before origin seeding
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
* fix: tighten toolSearch limit from Type.Number to Type.Integer
toolSearch.limit uses Type.Number() but represents a result count which
is inherently an integer. Tighten to Type.Integer() to reject float values
at the schema level, preventing LLM intent mismatch.
Reference: qingminglong PR #102481 (same pattern)
* fix(agents): add minimum:1 constraint and regression tests for toolSearch limit
- Add minimum: 1 to limit schema (rejects zero/negative at schema layer)
- Add focused regression test: tool-search.limit-schema.test.ts
(7 cases: valid int, min boundary, large int, float rejection,
zero rejection, negative rejection, optional omission)
* fix(agents): update toolSearch limit test to validate production schema
- test now imports actual createToolSearchTools + TOOL_SEARCH_RAW_TOOL_NAME
- validates against the real tool_search parameters schema, not a standalone copy
- adds missing required query validation test case (8 total)
* fix(agents): remove unused variable in toolSearch limit-schema test
* fix(agents): add execution-boundary tests for toolSearch limit
Add runtime execution boundary coverage for the limit-schema tightening,
validating that readSearchArgs -> readLimit rejects float/zero/negative
values at the execution layer. This covers the provider-normalization
path where TypeBox schema constraints may be stripped.
* test(agents): streamline tool search limit coverage
* test(agents): avoid tool search fixture shadowing
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
* fix(transcript): keep pagination cursors out of secret masking on resume
Persisted transcripts masked any `*_token` tool-call argument to `***`
via the generic secret-key heuristic, including pagination cursors like
`page_token`/`next_page_token`. On resume the model replays the mask as a
real cursor and the platform silently pages from the start, returning
wrong data with no error (#104992). Exempt only unambiguous page cursors
in the transcript redaction path (the `page` marker rules out credentials);
value-pattern redaction still runs so an embedded real secret is masked,
and logs keep redacting these keys. Genuine credential args stay masked.
Refs #104992
* fix(transcript): keep cursor redaction tests type-safe
* refactor(transcript): trim cursor redaction path
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Preserve existing lower-level high effort while making xhigh/max available before runtime activation.
Co-authored-by: Peter Steinberger <steipete@gmail.com>