Commit Graph

71385 Commits

Author SHA1 Message Date
Peter Steinberger e13bc7c63e refactor(agents): remove unused JSONL session paths (#112775)
* refactor(agents): remove legacy session file discovery

* refactor(agents): remove dead sessions directory helper
2026-07-22 19:22:26 -04:00
Peter Steinberger cdb8d32bcc refactor(agents): consolidate model normalization (#112772)
* refactor(agents): consolidate model normalization

* docs(agents): clarify normalization boundary
2026-07-22 19:19:41 -04:00
Peter Steinberger dbd6662976 refactor(cloud-workers): audit staged finalize fences (#112739) 2026-07-22 19:18:44 -04:00
Peter Steinberger 637afd0114 refactor(config): move Slack and Signal schemas to plugins (#112792)
* refactor(config): move Slack and Signal schemas to plugins

* build(signal): declare schema runtime dependency

* build(signal): refresh plugin shrinkwrap
2026-07-22 19:14:56 -04:00
Peter Steinberger 9b1e9a5e66 test: trim update CLI boilerplate (#112793) 2026-07-22 19:10:02 -04:00
Peter Steinberger f5562748de fix(logging): give non-default profiles their own gateway log file (#112777)
* fix(logging): give non-default profiles their own gateway log file

* chore: defer profile log release note
2026-07-22 19:08:41 -04:00
Peter Steinberger bf922f59fe fix(onboard): keep setup effects on the default agent (#112738)
* fix(onboard): align default agent setup ownership

* chore(onboard): remove stale target assignments

* fix(onboard): preserve workspace provisioning boundary
2026-07-22 19:05:21 -04:00
Peter Steinberger 0724dfda21 refactor(channels): share retry and text break helpers (#112786)
* refactor(channels): share retry and text break helpers

* fix(sdk): keep helper internals private
2026-07-22 19:05:00 -04:00
Peter Steinberger 939ecb5ef8 refactor(meeting-bot): hoist meeting adapter runtime glue (#112785)
* refactor(meeting-bot): hoist adapter runtime glue

* refactor(meeting-bot): specialize runtime adapters

* refactor(google-meet): reuse runtime adapter alias

* refactor(meeting-bot): privatize consult internals

* refactor(plugin-sdk): ratchet meeting runtime surface
2026-07-22 18:52:17 -04:00
Peter Steinberger 30c651d5bf docs(control-ui): clarify loopback gateway auth (#112746)
* docs(control-ui): clarify loopback gateway auth

* fix(gateway): preserve control ui settings auth hint
2026-07-22 18:45:56 -04:00
Peter Steinberger 62c148d7d0 refactor(e2e): remove stale proof scripts (#112776) 2026-07-22 15:31:36 -07:00
Peter Steinberger c4bd3f5b2e refactor: consolidate CLI runner test fixtures (#112779)
* test: consolidate cli runner fixtures

* test: satisfy CLI fixture guards
2026-07-22 15:28:48 -07:00
Peter Steinberger 3525e06587 test(ui): collapse chat-send request mock boilerplate (#112783)
* test(ui): collapse chat send request mocks

* test(ui): satisfy chat mock lint
2026-07-22 15:23:28 -07:00
Peter Steinberger f4e465d295 refactor(ui): sidebar cleanups — shared tooltips, one idle-import helper, cross-tab outbox bridge (#112780)
* refactor(ui): sidebar cleanups — shared tooltips, one idle-import helper, cross-tab outbox bridge

Three bounded cleanups following the offline-state work:

- Tooltip unification: every sidebar-family tooltip (session-row badges,
  offline status, agent card, attention actions, brand icons) now uses
  the shared <openclaw-tooltip> component instead of raw title attrs,
  completing the direction #112639 started. Aria labels unchanged.
- One idle-import helper (ui/src/lib/idle-import.ts): the duplicated
  idle-load/retry logic from app-sidebar chrome and app-host's outbox
  loader collapses into createIdleImport (cached promise clears on
  failure, one idle retry while online, online re-arm, dispose). The
  helper migration is net negative at its call sites.
- Cross-tab outbox bridge: subscribeStoredChatOutboxChanges now also
  notifies on storage events for the composer outbox keys, installed on
  first subscribe and removed with the last subscriber, so a message
  queued in another tab refreshes badges here.

* fix(ui): keep idle-import scheduling statement-form for narrow-safe types and consistent-return

* fix(ui): give idle-import a strictly void schedule and promise-only load
2026-07-22 15:21:33 -07:00
Yuval Dinodia 0f3855aa81 fix(memory-core): keep live reindex of reset/deleted session archives (#96132)
* fix(memory-core): keep live reindex of reset/deleted session archives

The session transcript listener dropped every archive artifact before
scheduling, so .jsonl.reset and .jsonl.deleted archives written by /reset
and session delete were no longer indexed on the live path and only
surfaced in memory search after the next gateway restart. Remove the
archive guard so in-agent archives fall through to scheduleSessionDirty,
which reaches the usage-counted-archive branch in processSessionDeltaBatch.

Regression from #89912; restores the incremental archive indexing added in

* fix(memory-core): constrain live archive indexing

* test(memory-core): align migrated search fixtures

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-22 15:13:47 -07:00
Peter Steinberger 85e2a43229 refactor: share subagent test fixtures (#112778)
* test(agents): share subagent fixtures

* test(agents): keep gateway mock private
2026-07-22 15:04:02 -07:00
mushuiyu886 e8f0d3198d fix(nostr): normal shutdown no longer reports relay errors (#111905) 2026-07-22 14:59:12 -07:00
Peter Steinberger 1650faf6a1 refactor(plugin-sdk): remove unread setup helpers (#112767)
* refactor(plugin-sdk): remove unread setup helpers

* refactor(plugin-sdk): privatize removed setup edges

* test(channels): remove stale proxy mock import
2026-07-22 14:57:32 -07:00
LZY3538 954a5089b3 fix(browser): detect Windows browsers when install roots are blank (#111256)
* fix(browser): ignore blank Windows install roots

* fix(browser): complete Windows install root fallbacks

Co-authored-by: LZY3538 <liu.zhenye@xydigit.com>

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-22 14:54:50 -07:00
Jason (Json) dc5f14f442 fix(onboarding): reuse active Codex API-key authentication (#112770)
* fix(onboarding): import Codex API key auth

* fix(onboarding): honor active Codex API-key auth

* fix(onboarding): remove unused Codex auth export
2026-07-22 15:52:27 -06:00
wahaha1223 2287d65cda fix(infra): preserve git metadata across short reads (#109419)
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Co-authored-by: ZengWen-DT <ceng.wen@xydigit.com>
2026-07-22 14:49:53 -07:00
Peter Steinberger 4501da6123 refactor(speech-core): split TTS runtime (#112768)
* refactor(speech-core): split TTS runtime

* refactor(speech-core): keep helper types private
2026-07-22 14:48:00 -07:00
Peter Steinberger 18f70922de fix(cron): harden live automation lifecycle (#112766) 2026-07-22 14:47:58 -07:00
Dallin Romney 635d396755 refactor(talk): run the Gateway realtime relay through the shared session harness (#112590)
* refactor(talk): adopt session harness in gateway relay

* fix(talk): preserve relay harness behavior

* style(talk): format relay barge-in call

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-22 14:40:32 -07:00
Peter Steinberger e194979830 test: table-drive policy guard cases (#112759) 2026-07-22 14:38:26 -07:00
clawsweeper[bot] 2329e07243 fix(voice-call): reject malformed media base64 (#106859)
* fix(voice-call): reject malformed media base64

Co-authored-by: sunlit-deng <253064511+sunlit-deng@users.noreply.github.com>

* refactor(voice-call): centralize malformed media rejection

Reuse the public media canonicalizer at both raw ingress boundaries and preserve the contributor WebSocket regression proof.

Co-authored-by: 潘晓波0668000512 <pan.xiaobo@xydigit.com>

* fix(voice-call): preserve base64url media frames

* docs(voice-call): clarify base64url padding contract

* test(voice-call): isolate base64 WebSocket regression

---------

Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: sunlit-deng <253064511+sunlit-deng@users.noreply.github.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Co-authored-by: 潘晓波0668000512 <pan.xiaobo@xydigit.com>
2026-07-22 14:28:06 -07:00
sunlit-deng 74c5415e2e fix(google-meet): reject malformed audio base64 (#106474)
* fix(google-meet): reject malformed audio base64

* refactor(meeting-bot): validate node audio centrally

Make the shared meeting-bot owner reject malformed push and pull audio for Google Meet, Teams, and Zoom without plugin-specific callbacks or permissive fallbacks.

Co-authored-by: sunlit-deng <yang.jiajun1@xydigit.com>

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-22 14:25:42 -07:00
Peter Steinberger a220cc00bd test: table-drive database-first guard cases (#112757) 2026-07-22 14:23:51 -07:00
Md Abrar Ibn Habib d2d3171bb7 fix(agents): strip current exec failure traces (#111877)
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Co-authored-by: xbrxr03 <abrarhabib03@gmail.com>
2026-07-22 14:19:59 -07:00
Peter Steinberger ef872829c3 perf(models): scope provider-filtered catalog discovery (#112752)
* perf(models): scope provider-filtered catalog discovery

* fix(models): gate scoped discovery on catalog ownership

* test(models): type catalog ownership fixtures
2026-07-22 14:17:47 -07:00
Gwydion Nanashi Ferrinas Solidor 4e6a6bdbcc fix: message sends fail when optional location is blank (#112013)
* fix(outbound): ignore blank shared-schema send location

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: b529c5fd-6822-4c0d-ab8d-9906bd7dc8d9

* fix(outbound): normalize blank send locations

Co-authored-by: ronan-dandelion-cult <ronan.dandelion.cult@hotmail.com>

---------

Co-authored-by: ronan-dandelion-cult <ronan.dandelion.cult@hotmail.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-22 14:16:18 -07:00
Peter Steinberger 267d9f89ef fix(compaction): preserve summary conversation anchors (#112755)
Co-authored-by: rune-dandelion-cult <rune.dandelion.cult@hotmail.com>
2026-07-22 14:15:32 -07:00
Masato Hoshino fd461d423c fix(agents): give bash stdout and stderr independent decode lanes (#112325)
* fix(agents): give bash stdout and stderr independent decode lanes

stdout and stderr are independent pipes, but the local bash execution path
fed both into one onData callback sharing a single TextDecoder and one
streaming ANSI/OSC sanitizer. A multibyte UTF-8 character split across a
stdout read boundary was corrupted when stderr wrote between its bytes, and
an unterminated OSC on stdout swallowed subsequent stderr output. This
contradicts the documented invariant in shell-utils.ts ('Keep one ANSI
parser per process stream so control sequences can span callbacks').

Tag onData with an optional stream identifier and give each lane its own
TextDecoder and text-transform state; finish() flushes every lane. Untagged
callers keep the single shared lane for backward compatibility.

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

* fix(agents): harden bash stream isolation

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-22 14:14:14 -07:00
ooiuuii 6c0bda782c fix(discord): accept raw mentions when hydration fails (#111860)
* fix(discord): fall back to raw bot mentions

* fix(discord): gate raw mention fallback on hydration failure

* fix(discord): reject non-pinging raw mentions

* fix(discord): model mention hydration authority

Co-authored-by: luyifan <al3060388206@gmail.com>

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-22 14:11:35 -07:00
LZY3538 d94a192143 fix(path): follow mise data directory precedence (#111258)
* fix(path): follow mise data directory precedence

* test(path): tighten mise precedence coverage

Co-authored-by: LZY3538 <liu.zhenye@xydigit.com>

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-22 14:10:19 -07:00
juyaohuidt 38d1a727f4 fix(discord): keep voice participant labels UTF-16 safe at truncation boundary (#108278)
normalizeLabel truncated external member display names (nick / global_name /
username) with a raw .slice(0, 100). When the cut landed on a UTF-16 surrogate
pair, the label kept a lone high surrogate that corrupted the JSON-quoted
roster line fed into the agent's voice-roster prompt. Use truncateUtf16Safe
so the boundary backs off the split pair, matching the same surrogate-safe
truncation already applied to other discord truncation sites.

Co-authored-by: ben.li <li.yang6@xydigit.com>
Co-authored-by: 刘伟勤0668000710 <liu.weiqin@xydigit.com>
2026-07-22 14:07:43 -07:00
Peter Steinberger 4e9ae9fbff feat(cron): system-owned heartbeat monitor jobs replace the dedicated interval scheduler (#112585)
* feat(cron): system-owned heartbeat monitor jobs replace the interval scheduler

- new internal cron payload kind {kind:"heartbeat"}: execution pokes
  requestHeartbeat({source:"interval"}); reported in the protocol job
  schema, not accepted from client create/patch
- gateway converges one declaration-keyed monitor job per heartbeat-enabled
  agent (schedule every+deterministic phase anchor) at startup and on
  config reload; removes monitors for unconfigured agents
- heartbeat runner loses its interval setTimeout machinery; nextDueMs
  stays as the cooldown gate, event wakes unchanged

* test(cron): heartbeat monitor regressions; docs for cron-owned cadence

- converge/prune/failure-containment tests for heartbeat monitor jobs
- heartbeat payload run fires an interval wake, no system event
- scheduler tests converted from timer self-fire to wake-queue pokes;
  timer-mechanics-only tests deleted with the timer
- persisted-shape accepts the heartbeat payload kind
- docs: heartbeat cadence ownership + system payload kind

* fix(cron): heartbeat monitor review round 1

- targeted cron-monitor interval ticks use the full per-agent path so
  due-commitment sessions still deliver
- cron-disabled gateways keep a local fallback interval timer (shipped
  cron.enabled=false contract; removed when heartbeat config folds into
  cron in #110950)
- heartbeat job reconciliations serialize with latest-wins epochs and a
  bounded 30s retry after a failed convergence pass

* fix(cron): chain clamped fallback heartbeat timers past the setTimeout cap

* fix(cron): heartbeat monitor review round 3

- targeted monitor redirect skips wakes carrying heartbeat overrides and
  surfaces the per-agent terminal skip reason instead of not-due
- cron-disabled fallback timer re-arms with a 1s floor after each firing
  so a dropped wake cannot end the chain
- heartbeat payloads are system-owned at the service boundary: add requires
  the gateway opt-in, patches to the kind are rejected

* fix(cron): heartbeat monitor review round 4 — full ownership enforcement

- prune only jobs proven to be monitors (prefix AND heartbeat payload)
- existing monitors reject every update patch; declarative upserts on the
  monitor key require the gateway opt-in even with a different payload

* fix(cron): complete heartbeat monitor ownership boundary

- converge scopes declarative matching to real monitors so a colliding
  user job with the same key is never adopted or overwritten
- monitor removal requires the gateway systemOwned opt-in; ad-hoc
  API/CLI deletion is rejected, reconciliation cleanup still prunes

* docs(cron): record intentional enrollment-snapshot semantics for monitor ticks

* fix(cron): repair heartbeat monitor CI gates
2026-07-22 14:03:29 -07:00
Po-Han Shih 7cf6bd5e4b fix: treat EPERM as alive in isPidAlive (#110235)
* fix(pid): treat EPERM as alive in isPidAlive

Match isPidDefinitelyDead: process.kill(pid, 0) throwing EPERM means the
PID exists but cannot be signaled, so it should not look dead.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(pid): check Linux zombies after EPERM existence probe

EPERM means the PID exists but cannot be signaled; still run the zombie check so Linux zombies are not reported as alive.

Co-authored-by: Cursor <cursoragent@cursor.com>

* test(pid): isolate EPERM liveness probe

Co-authored-by: stantheman0128 <stanshih888@gmail.com>

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-22 13:56:09 -07:00
Peter Steinberger 9e8bcd1134 chore(claude): auto-install deps on new Claude Code worktree startup
Claude Code worktrees under .claude/worktrees/ are created without their
own node_modules (git worktrees don't materialize gitignored dirs), so
tooling silently resolves up to the parent checkout's node_modules. That
breaks when the parent sits on a divergent branch missing a newer
dependency (observed: tsgo failing on libphonenumber-js in a fresh
worktree).

Track a minimal .claude/settings.json with a SessionStart(startup) hook
that runs an idempotent `pnpm install --frozen-lockfile --ignore-scripts`
in the worktree root on first entry, so each worktree is self-contained.

Hardening:
- resolves the worktree root via `git rev-parse --show-toplevel` (not cwd),
  so it works when Claude launches from a subdirectory;
- --ignore-scripts: a branch-controlled package lifecycle script cannot gain
  code execution merely because Claude starts a session in that worktree;
- --frozen-lockfile: no lockfile mutation; skips cleanly when pnpm or the
  lockfile is absent; warns instead of blocking the session on failure.

Only .claude/settings.json is un-ignored; .claude/worktrees, skills, and
settings.local.json stay ignored. Claude Code only — CI and Codex worktrees
do not read this file.
2026-07-22 13:47:40 -07:00
Gio Della-Libera f004d76a0e Plan grouped Claw agent updates (#102959)
* Plan grouped Claw agent updates

* test(claws): cover update planning

* docs(claws): document update preview

* fix(claws): bind update capability effects

* fix(claws): redact update capability effects

* fix(claws): bind capability previews to exact changes

---------

Co-authored-by: Patrick Erichsen <patrick.a.erichsen@gmail.com>
2026-07-22 13:44:09 -07:00
Peter Steinberger 6bf03cd674 fix(ui): keep composer sends on one stable bubble through the history handoff and add a subtle entry animation (#112567)
* fix(ui): keep composer sends on one stable bubble through the history handoff and add a subtle entry animation

* fix(ui): keep userTurnSendIdentity module-local
2026-07-22 13:02:49 -07:00
Peter Steinberger 988e640c7a test: finish stateless isolation cleanup (#112704) 2026-07-22 12:21:53 -07:00
Gio Della-Libera 31ff00fe82 Add experimental Claw lifecycle diagnostics (#102427)
* Add experimental Claw lifecycle diagnostics

* test(claws): cover lifecycle diagnostics

* docs(claws): document doctor diagnostics

* test(claws): derive future state schema version

* test(claws): clean doctor restack fixture

* test(claws): align doctor drift fixture with agent entries

---------

Co-authored-by: Patrick Erichsen <patrick.a.erichsen@gmail.com>
2026-07-22 11:55:47 -07:00
Yuval Dinodia 5419a94587 fix(doctor): merge legacy flat auth repair into existing SQLite store (#98245)
maybeRepairLegacyFlatAuthProfileStores rewrote the per-agent SQLite auth
profile store with a store built solely from the legacy flat
auth-profiles.json, and backed up only that flat JSON. Any credential
present in SQLite but absent from the flat file (for example an OAuth
refresh token from a login after the SQLite migration) was destroyed and
was not in the backup, so a routine openclaw doctor caused unrecoverable
credential loss.

Load the existing SQLite store and merge the legacy flat profiles into
it, preserving credentials already present, then verify the imported
profiles persisted before removing the flat file, mirroring the SQLite
migration path.
2026-07-22 11:37:26 -07:00
Peter Steinberger df551c10a1 ci: update Kova release fixture pin (#112715) 2026-07-22 11:27:00 -07:00
Peter Steinberger 2b405755b1 fix(plugins): refresh prepared provider metadata (#112699)
* fix(plugins): refresh prepared provider metadata

* test(agents): tolerate minimal metadata snapshots

* test(agents): cover snapshot endpoint precedence
2026-07-22 11:07:35 -07:00
Peter Steinberger 32d4323049 docs(plugins): link setup-input deprecations to the migration pattern and document reader sweeps (#112692)
* docs(plugins): link setup-input deprecations to the migration pattern and document reader sweeps

* ci: retrigger queued run

* docs: regenerate docs map
2026-07-22 11:04:19 -07:00
openclaw-mantis[bot] e92e338e9c chore(ui): refresh control ui locales (#112673)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-07-22 11:03:28 -07:00
Peter Steinberger 85fda04df7 feat(ui): surface queued-outbox counts in composer hint, session rows, and offline footer (#112649)
* feat(ui): surface queued-outbox counts in composer hint, session rows, and offline footer

Follow-up to the offline-state unification: queued sends were mechanically
safe (durable outbox with reconnect replay) but only visible inside the
open session's thread.

- Composer offline hint now includes the visible session's queued count.
- Session rows show a clock badge with the per-scope outbox count,
  independent of connection state (covers waiting-idle and failed too),
  with alias-safe scope resolution so agent-main never double-counts.
- The offline footer button appends the aggregate ("· N queued"); the
  connected state stays completely silent.
- One narrow subscription seam (subscribeStoredChatOutboxChanges) added
  in composer-persistence; no send/drain logic touched.

* perf(ui): keep the startup bundle under budget with a lean outbox read module

The queued-count feature statically imported composer-persistence from
startup modules, hoisting the chat page's persistence machinery into the
startup chunk and breaking the Control UI startup JS gzip budget
(319.6 KiB > 314.0 KiB limit).

Split ownership instead of gaming the budget: a lean read/subscribe
module (ui/src/lib/chat/outbox-store.ts + codec/draft-state) serves
startup consumers (app-host, sidebar), while writes, migrations, and
drain stay in the lazy chat chunk (composer-outbox-store/composer-storage);
composer-persistence keeps its export surface for chat callers. Startup
is back to 313.8 KiB gzip at 12 requests with no chunking-config changes.

Also fixes an autoreview finding in the new summary: legacy bare-main
outbox rows now resolve through session defaults (online) or the
persisted mainAlias (offline reload) instead of trusting the row's stale
embedded agent id, so badge counts key to the same scope the sidebar
resolves. The shared footer status renderer is deduplicated into
session-row-badges.

* fix(ui): correct type-only import and const tuple in outbox split

* perf(ui): idle-load the outbox summary so startup carries no outbox code

The lean outbox read module still cost ~2.8 KiB of startup gzip against
1.5 KiB of budget headroom. Follow the sidebar chrome pattern
(lobster-pet/facepile): app-host idle-loads outbox-store, subscribes on
arrival, and passes the sidebar a resolver callback instead of letting
startup modules import scope resolution. Badges and counts hydrate
moments after load; before that the summary is empty by design.

Failed chunk loads recover on browser online events and, because chunks
are usually served by the gateway itself, on gateway reconnect — the
exact moment the offline badges become relevant again.

Raise the initial-graph packing ceiling 448->512 KiB: the grown core
graph split at the old boundary into an extra chunk, costing ~1.9 KiB of
startup gzip to compression-context resets (same documented tradeoff as
the earlier 400->448 bump). Startup lands at 313.5 KiB gzip / 9 requests,
matching the origin/main baseline, limit 315.0.
2026-07-22 10:53:22 -07:00
openclaw-mantis[bot] a3a08a6db0 chore(i18n): refresh native locales (#112662)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-07-22 09:38:17 -07:00