Commit Graph

65714 Commits

Author SHA1 Message Date
ZOOWH
7809acfc24 perf(gateway): avoid per-character chat sanitizer rebuilds (#102971)
* perf(gateway): replace O(n^2) char loop with regex in stripDisallowedChatControlChars

Replace character-by-character iteration with a single regex replace to
avoid event-loop blocking on large messages (1MB+). The regex matches
only disallowed control characters (NUL-BS, VT, FF, SO-US, DEL) while
preserving tab, newline, CR, printable ASCII, and Unicode.

Closes #102915

* perf(gateway): use String.fromCodePoint for regex to avoid lint suppression

Replace the eslint-disable comment and hex-escape regex literal with
String.fromCodePoint() construction. This avoids adding a new entry to
the lint suppression baseline while keeping the same character set and
performance characteristics.

Ref: #102915

* refactor(gateway): consolidate chat sanitizer

---------

Co-authored-by: Peter Steinberger <peter@steipete.me>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-10 03:27:00 +01:00
Ayaan Zaidi
e6a9a5d182 docs(web): document Docker host-networking requirement for the Telegram Mini App 2026-07-10 07:53:37 +05:30
Ayaan Zaidi
6da0af1cd3 fix(ci): use public plugin-sdk test seams and refresh generated surfaces 2026-07-10 07:53:37 +05:30
Ayaan Zaidi
0521d848bb fix(telegram): fixed-length initData hash compare and base-path ws url 2026-07-10 07:53:37 +05:30
Ayaan Zaidi
04ff278a1d refactor(device-bootstrap): close bootstrap purpose type 2026-07-10 07:53:37 +05:30
Ayaan Zaidi
00aad83f43 fix(telegram): harden mini app URL and page serving 2026-07-10 07:53:37 +05:30
Ayaan Zaidi
b2ee68780c docs(web): document Telegram dashboard entry 2026-07-10 07:53:37 +05:30
Ayaan Zaidi
3c99adb9ca feat(telegram): add dashboard mini app command 2026-07-10 07:53:37 +05:30
Ayaan Zaidi
9cca9afa70 feat(ui): accept dashboard bootstrap tokens 2026-07-10 07:53:37 +05:30
Ayaan Zaidi
0c4188b3ec feat(gateway): approve control-ui bootstrap handoffs 2026-07-10 07:53:37 +05:30
Ayaan Zaidi
c64db7c9c7 feat(plugin-sdk): export dashboard bootstrap helpers 2026-07-10 07:53:37 +05:30
Ayaan Zaidi
b7fa44abd3 feat(device-bootstrap): add control-ui bootstrap purpose 2026-07-10 07:53:37 +05:30
Miorbnli
25337df1c8 fix(proxy-capture): truncate inline preview on UTF-8 character boundary (#102409)
* fix(proxy-capture): truncate inline preview on UTF-8 character boundary

persistEventPayload stores a small UTF-8 preview (dataText) inline for fast CLI
listings and query output, capped at previewLimit bytes (default 8192). It built
the preview with buffer.subarray(0, previewLimit).toString("utf8"), which slices
the buffer at an arbitrary byte offset. For any non-ASCII body (emoji/CJK/accented
text, common in model-provider HTTP traffic), the cut lands mid-multibyte-sequence
and Node emits a trailing U+FFFD replacement char into the stored preview column.

Decode the full buffer first, then truncate with the existing truncateUtf8Prefix
helper (src/utils/utf8-truncate.ts), which backtracks off UTF-8 continuation bytes
so the preview ends on a complete character while staying within the byte budget.
ASCII previews are byte-identical; only malformed trailing U+FFFD is removed.

Co-Authored-By: Claude <noreply@anthropic.com>

* test(proxy-capture): align stub store return type with SharedCaptureBlobRecord

The preview-boundary test stub returned a bare { blobId, sha256, byteLength },
which fails tsgo typecheck against persistPayload's declared
CaptureBlobRecord | SharedCaptureBlobRecord return. Return a complete
SharedCaptureBlobRecord instead. Also use template strings for the multibyte
fixtures to satisfy no-useless-concat. No assertion behavior change.

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(proxy-capture): byte-bounded UTF-8 preview, unify store and proxy paths

The prior fix decoded the whole payload with buffer.toString("utf8") before
truncating, an availability regression for large captured payloads, and it left
the proxy-server finishBodyPreviewCapture path on the same byte-subarray decode
that can split a trailing multibyte sequence into U+FFFD.

Add truncateUtf8PrefixFromBuffer: decodes only the byte-bounded prefix and walks
back to verify the trailing multibyte sequence is complete (handles both a hard
byte cap and a buffer already sliced mid-sequence upstream, e.g. a dangling lead
byte). Use it from persistEventPayload (no full-payload decode) and
finishBodyPreviewCapture (same boundary safety), so both preview paths share one
canonical helper.

Add completeUtf8PrefixLength coverage plus proxy-server body-preview regression
tests for dangling-lead, byte-cap, emoji, and oversized-body cases.

Co-Authored-By: Claude <noreply@anthropic.com>

* style(proxy-capture): fix no-useless-assignment and unnecessary template expr

- utf8-truncate.ts: expected is reassigned in every branch, so declare without
  the unused initial value (no-useless-assignment).
- proxy-server.body-preview.test.ts: drop the redundant template wrapper around
  a single expression (no-unnecessary-template-expression). No behavior change.

Co-Authored-By: Claude <noreply@anthropic.com>

* docs(utf8-truncate): clarify completeUtf8PrefixLength byte-budget contract

Document that maxBytes is a byte (not character) limit and that the returned
length is the largest offset that does not split a multibyte sequence.

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(proxy-capture): preserve UTF-8 preview boundaries

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-10 03:18:38 +01:00
ZOOWH
6b90610cdb fix(copilot): redact OAuth error response body in fetchJson error messages (#102953)
* fix(copilot): redact OAuth error response body in fetchJson error messages

Replace raw response body text with bounded, redacted structured error detail
extracted via extractProviderErrorDetail so OAuth error responses containing
tokens, device codes, or other sensitive fields are not leaked into Error
messages and downstream logs.

* test(copilot): add device-code and non-JSON error body redaction cases

Add regression tests covering the device code flow and non-JSON error
bodies alongside the existing token refresh coverage. Also include live
proof output showing real Response object redaction via
extractProviderErrorDetail.

Ref: #102953

* fix(copilot): normalize OAuth HTTP failures

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-10 03:15:29 +01:00
Peter Steinberger
67ff8dfc15 fix(ui): apply selected reasoning and speed before sending (#103253)
* fix(ui): gate sends on pending session settings

* chore(ui): keep changelog release-owned
2026-07-10 03:14:23 +01:00
Masato Hoshino
fbc73ca1b7 fix(outbound): publish conversation bindings after SQLite commit (#101023)
* fix(outbound): restore current-conversation binding map when persist fails

The generic current-conversation binding mutators (bind/touch/unbind/
prune-on-read) changed the process-wide in-memory map before calling
writePersistedBindings(), with no rollback. A throwing SQLite write left
the map ahead of disk; because bindingsLoaded is a one-time flag, the
diverged bindings were served until restart, routing inbound messages to
wrong or deleted session targets while the caller already saw the throw.

Add persistBindingsOrRestore(): snapshot the map before mutation and, on
write failure, restore it and rethrow. Covers all six write sites. Mirrors
the cron rollback precedent (#99960, src/cron/service/ops.ts persistOrRestore).

Fault-injection tests assert the map reverts for each path.

* fix(outbound): publish conversation bindings after SQLite commit

* chore(outbound): align binding files with current main

* fix(outbound): publish conversation bindings after SQLite commit

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
Co-authored-by: Peter Steinberger <peter@steipete.me>
2026-07-10 03:13:27 +01:00
wuqxuan
e99af07369 fix(cron): channel failure alerts drop when global webhook failure destination is set (#102445)
* fix(cron): keep channel-shaped failure destinations from inheriting webhook mode

* test(cron): prove channel failure destination announces under global webhook

* test(gateway): prove cron channel failure destination under global webhook

* fix(cron): harden failure destination mode inference

Tighten the resolver invariant, reuse focused test fixtures, and keep the Gateway proof at the real finished-event boundary.

Co-authored-by: wuqingxuan <wu.qingxuan@xydigit.com>

Co-authored-by: Hakan Baysal <hakan.baysal@trmix.com>

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
Co-authored-by: Hakan Baysal <hakan.baysal@trmix.com>
2026-07-10 03:13:18 +01:00
Darren2030
b8f365a82b fix(tasks): skip discarded registry sort (#102202)
Preserve the cloned task snapshot and deterministic activity ordering while avoiding the createdAt sort that tasks.list immediately replaces.

Closes #101716

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-10 03:12:35 +01:00
Peter Lee
cab8040b14 fix(cron): preserve cron context in session entry for async completion wakes (#101078)
* fix(cron): preserve cron context in session entry for async completion wakes (#99919)

Persist bootstrapContextRunKind on the session entry after cron agent
runs, and restore provider/model/thinking/runKind from the session
entry into directAgentParams when an async completion wake (e.g. media
generation) resumes a cron session.

Before this fix, async completion wakes lost the original cron run
context and fell back to account defaults, causing multi-step cron tasks
to silently dead-end after the first async media generation call.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(cron): authorize model override on trusted in-process dispatch for cron context restoration

* fix(cron): persist bootstrapContextRunKind on base session entry for async completion wakes

* fix(cron): route async completion wake to base cron session key instead of ephemeral run key

When the cron run-key fallback fires, record the base cron key as
effectiveSessionKey so deliverDirectSubagentAnnounce can route the
agent call to the persisted session row with its transcript and task
context instead of starting a fresh turn (#99919).

* fix(cron): add bootstrapContextRunKind to session entry slot keys and declare loadRequesterSessionEntry return type

* fix(cron): rebase onto upstream main, restore upstream agent-command behavior while keeping bootstrapContextRunKind persistence

* fix(cron): persist bootstrapContextRunKind from a pre-mutation snapshot to produce a real delta

* fix(cron): move pre-mutation snapshot inside guard so initialEntry is non-optional

* fix(cron): preserve async media continuation context

Co-authored-by: Peter Lee <li.xialong@xydigit.com>

* fix(cron): retain continuation after base cleanup

* test(gateway): complete agent scope mock

* test(gateway): preserve agent scope exports

* test(cron): persist mocked session mutations

* test(cron): model persisted session fixtures

* fix(agents): snapshot cron continuation retries

* fix(cron): harden async continuation settlement

* test(cron): control continuation recovery clock

* fix(gateway): narrow continuation model row

* chore(changelog): defer cron continuation note

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-10 03:07:30 +01:00
Peter Steinberger
73db6b2aca ci: pin docs i18n Go toolchain (#103244) 2026-07-10 03:02:52 +01:00
Peter Steinberger
25eaa53a8a fix(ci): verify performance report after push timeout (#103237) 2026-07-10 02:50:36 +01:00
Peter Steinberger
2c622e19de docs(web): the Lobster gets its own page (#103175)
A fun field guide for the Control UI lobster: what it is, when it
visits, how to interact (hover names, pokes, right-click shoo), the
Appearance toggle, the Lobsterdex, reduced-motion and privacy notes.
Deliberately teases rather than documents the rare variants, events,
and the anniversary. Registered in the Web interfaces nav group and the
generated docs map.
2026-07-10 02:48:21 +01:00
Peter Steinberger
25e93ef9f9 fix(opencode): list current Zen models in offline discovery (#103197)
* fix(opencode): refresh Zen model catalog

* fix(opencode): expose static catalog fallback
2026-07-10 02:44:56 +01:00
Peter Steinberger
10b50843e7 feat(webchat): the Lobsterdex - a quiet collection of every lobster that visited (#103172)
Arrivals (visits and offline summons) log their palette id into a
best-effort localStorage set. Settings -> Appearance gains a Lobsterdex
row: mini canonical lobsters for all twelve palettes, seen ones in
color (grails keep their glow/translucency via the palette classes),
unseen ones as dim silhouettes, with a seen/total count. Minis render
standalone (closed-lid layer inline-hidden) since they live outside the
pet's CSS context. New quickSettings.appearance strings synced across
locale bundles.
2026-07-10 02:44:24 +01:00
Vincent Koc
cbc087dcc5 fix(ci): pin Kova resource scope contract (#103217) 2026-07-09 18:40:25 -07:00
Peter Steinberger
66e4f4869c test(agents): stabilize MCP timeout retry coverage (#103223) 2026-07-10 02:35:45 +01:00
Peter Steinberger
f12a92d3ca fix(ui): settle canonical session refreshes in lifecycle E2Es (#103224)
* test(ui): settle canonical session refreshes

* test(ui): isolate stale session event assertions
2026-07-10 02:34:15 +01:00
colton-octaria
dc8c0aaaf2 fix(msteams): recover inbound channel and group-chat files safely (#90738)
* fix(msteams): read file attachments on Teams channel messages

Three bugs blocked reading files attached to channel messages:
- Graph /teams/{id} used channelData.team.id (the 19:..@thread.tacv2 thread id)
  instead of team.aadGroupId (the AAD group GUID) -> 400.
- The Graph fetch was gated on an <attachment id> HTML marker that channel
  @mention activities don't carry -> fetch skipped.
- A thread reply was fetched at /messages/{replyId} (404) then fell back to the
  bare thread root, returning the root's file for every reply. Replies live at
  /messages/{root}/replies/{replyId}.

Fixes #89594

* fix(msteams): gate Graph media fallback on text/html stub; run trigger tests in channel context

* fix(msteams): canonicalize Graph attachment recovery

Build one canonical Graph message URL per Teams activity, recover marker-free channel and group-chat file shares, and retain bounded current-main attachment handling.

Co-authored-by: Colton Williams <colton@coltons-apps.tech>

* fix(msteams): canonicalize Graph media recovery

Recover channel and group-chat files through one fail-closed Graph identity path, bound inbound enrichment, and remove invalid app-only Graph fallbacks.

Co-authored-by: Colton Williams <colton@coltons-apps.tech>
Co-authored-by: Joshua Packwood <joshua.packwood@gmail.com>

---------

Co-authored-by: Colton Williams <colton@coltons-apps.tech>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Co-authored-by: Joshua Packwood <joshua.packwood@gmail.com>
2026-07-10 02:34:12 +01:00
Peter Steinberger
c07fe5fe70 chore(deps): update docs-i18n x/net (#103225) 2026-07-10 02:34:00 +01:00
Peter Steinberger
31f76b9792 fix(release): validate GitHub notes before publish (#103222) 2026-07-10 02:33:23 +01:00
Peter Steinberger
0d2db46956 fix(gateway): clean up aborted queued turns (#103194)
Co-authored-by: Ted Li <tl2493@columbia.edu>
2026-07-10 02:27:27 +01:00
Peter Steinberger
28eb9e5d29 perf(test): reduce hotspot setup costs 2026-07-09 21:17:12 -04:00
Vincent Koc
968b89defe fix(ci): remove cross-os TypeScript loader bootstrap (#103195) 2026-07-09 18:15:12 -07:00
Peter Steinberger
874e4a2d40 feat(webchat): dreams scene sleeps your seeded lobster cameo (#103167)
The dreams page's generic sleeper is replaced by the agent's own seeded
lobster (same look system as the sidebar pet) rendered with a new
sleeping option: pupils hidden, closed-lid curves inline-visible so the
cameo needs no lobster-pet CSS context. Palette vars are supplied by
the cameo wrapper. Deletes the bespoke dreams svg.
2026-07-10 02:15:10 +01:00
Peter Steinberger
aef945f847 fix(browser): require exact Playwright target identity (#103177) 2026-07-10 02:12:53 +01:00
Peter Steinberger
a5d70e114c test(copilot): align replay metadata assertion (#103182) 2026-07-09 18:07:31 -07:00
qingminlong
3f68e1b5e3 fix(media): accept matching repeated content lengths (#102939)
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-10 02:03:30 +01:00
Peter Steinberger
9e6900fc9f feat(webchat): seasonal lobster pet wardrobe and anniversary dress code (#103158)
December visitors can roll a santa hat and Oct 20-31 a pumpkin (extra
weighted entries joining the accessory pool on the right dates; one
roll either way so seeds keep the rest of their look). On Nov 24 - the
repository's birthday (GitHub created_at 2025-11-24) - every visitor
dresses as the classic-logo retro with a party hat and confetti-colored
z's. Look generation takes an injectable date so seasonal behavior is
pure and testable; existing look tests pin a neutral date.
2026-07-10 02:01:01 +01:00
NianJiu
05d17289c9 fix(android): order disconnect after in-flight gateway work (#103068)
* fix(android): drain gateway events before disconnect callback

* chore(android): refresh native i18n inventory

* chore(android): refresh native i18n inventory

---------

Co-authored-by: NianJiuZst <180004567+NianJiuZst@users.noreply.github.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Co-authored-by: Peter Steinberger <peter@steipete.me>
2026-07-10 01:51:51 +01:00
Peter Steinberger
e6a8feb9c2 refactor(pairing): move device pairing store to shared SQLite state DB (#103160)
* refactor(pairing): move device pairing store to shared SQLite state DB

Device pairing, pending requests, and bootstrap tokens now live in the
device_pairing_* / device_bootstrap_tokens tables of state/openclaw.sqlite
instead of devices/{paired,pending,bootstrap}.json. Gateways import legacy
paired records once at startup (before the node-surface fold) and archive
the JSON files with a .migrated suffix; transient pending/bootstrap rows
are dropped. The unshipped node_pairing_* tables are removed from the
schema and dropped from existing DBs. Doctor now flags un-imported legacy
store files instead of corrupt-JSON reads.

* refactor(pairing): drop stale awaits now that store persistence is synchronous

* refactor(pairing): extract leaf record types to break store/domain module cycle
2026-07-10 01:46:56 +01:00
Peter Steinberger
b0e77bbe72 feat(webchat): rare lobster pet events - molting and twin visits (#103154)
~12% of loads plan a molt: during the first idle act the pet shivers,
squashes, and pops one size tier bigger, leaving its old shell behind
as a frozen, washed-out silhouette that fades over a minute. The shell
keeps the true pre-molt size, respects dismissal and the visits
setting, and its timer resets with the seed. ~4% of loads are twin
days: a mini copycat ('<name> Jr.') tags along on the parent's trailing
side and mirrors every act a beat later via an act-delay variable
threaded through the act animations. Rare-event plans are pure
per-seed functions so tests probe them directly.
2026-07-10 01:32:42 +01:00
Peter Steinberger
d8624a4e1b fix: fail release performance when reports do not publish (#103126)
* fix(ci): harden performance report publishing

* ci: use scoped app token for reports

* ci: pin Kova readiness probe fix

* ci: pin latest Kova readiness checks

* ci: pin Kova startup sequencing fix

* ci: pin calibrated Kova release policy
2026-07-10 01:27:26 +01:00
Peter Steinberger
e26a850fbd feat(webchat): lobster pet charm bundle - names, celebrations, poke moods, night owl (#103149)
Every pet gets a seeded name shown via native hover tooltip (rare
palettes carry signature names: Goldie, Boo, Picasso, Patches, Lantern,
Blueberry, OG). A busy->idle mode flip now earns a cheer act (double hop
with a mid-air twirl, claws up) instead of a startle, so the lobster
celebrates finished runs. Three fast pokes make it grumpy for a minute
(angry brows + frown overlay); ten pokes send it off in a huff until a
later scheduled visit (offline pets are on duty and never huff).
Visits between 22:00 and 06:00 local always act sleepy regardless of
personality.
2026-07-10 01:15:20 +01:00
Peter Steinberger
8b300e57f0 fix(browser): keep remote CDP credentials out of responses (#103139)
* fix(browser): contain remote CDP credentials

* fix(browser): probe authenticated discovery before attach

* chore: keep release note in PR metadata
2026-07-10 01:12:51 +01:00
ZOOWH
e327a3dca1 fix(telegram): deliver content instead of throwing when tag overhead fills chunk (#102999)
* fix(telegram): deliver content instead of throwing when tag overhead fills chunk

When HTML tag overhead (open + close tags) exceeds the chunk limit,
appendText threw an error causing complete message delivery failure.
Instead, force the text into the chunk so the message is still delivered
even if the chunk slightly exceeds the limit.

Closes #102910

* fix(telegram): strip rich formatting when tag overhead fills chunk

When HTML tag overhead fills an empty chunk with no room for text, strip
rich formatting and retry as plain text instead of delivering an oversized
chunk or throwing. Orphan close tags from the stripped formatting are
skipped to keep the output well-formed and within the chunk limit.

This preserves the existing plain-text fallback paths in send.ts and
rich-message.ts.

Closes #102910

* fix(telegram): preserve delivery when HTML tag overhead overflows

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-10 01:05:51 +01:00
maweibin
8dd45e864e fix(ui): preserve sidebar sessions through reconnect (#102424)
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-10 01:02:10 +01:00
SunnyShu
9526224f42 fix(gateway): guard thinkingLevel re-validation against only relevant patch fields (#102866)
* fix(gateway): guard thinkingLevel re-validation against only relevant patch fields

The second thinkingLevel validation block used `if (next.thinkingLevel)`,
which enters on ANY patch when the session already has a thinkingLevel
inherited from the existing entry. This caused unnecessary model catalog
loading and could silently delete or modify the existing value.

Fix: change guard to also check that the patch explicitly touches
thinkingLevel or changes the model (which may alter the effective
provider/model that thinkingLevel is validated against).

Ref: BUG-002 (local finding)
Co-Authored-By: Claude <claude@anthropic.com>

* test(gateway): prove session patch catalog isolation

---------

Co-authored-by: Claude <claude@anthropic.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-10 01:01:33 +01:00
Peter Steinberger
6fd9cc92b7 fix(meta): live validation targets deployed Muse Spark 1.1 (#103163)
* fix(meta): target Muse Spark 1.1 in live checks

* chore: follow release-owned changelog policy
2026-07-10 01:00:31 +01:00
Ayaan Zaidi
f351288a0d chore(repo): remove stale repository artifacts (#103152)
* docs: remove merged cron design document
* chore(repo): remove stale planning and proof artifacts

---------

Co-authored-by: Ayaan Zaidi <hi@obviy.us>
2026-07-10 05:28:12 +05:30
Peter Steinberger
dc3d06c5d6 fix(ci): calibrate hosted startup memory 2026-07-09 19:54:42 -04:00