* fix(whatsapp): thread authDir through command authorization and owner bypass for LID JID resolution
WhatsApp group commands (/new, /stop) can be ignored when Baileys reports the sender as a LID JID (@lid) instead of a phone JID (@s.whatsapp.net). The resolveWhatsAppCommandAuthorized() and isOwnerSender() functions called getSelfIdentity/getSenderIdentity without passing authDir, so the LID-to-phone reverse mapping could not happen.
Fix: thread account.authDir through both command authorization and group owner-bypass identity resolution paths so that LID JIDs are properly resolved to phone E.164 identities before owner/allowlist checks.
* fix(whatsapp): replace deprecated top-level fields with admission overrides in LID JID test
* fix(feishu): send blocks as independent messages when blockStreaming is enabled
* fix(feishu): preserve mention targets on first independently sent block
* fix(feishu): route independent block sends through chunked text delivery
Route the independent block-send path through sendChunkedTextReply
instead of calling sendMessageFeishu directly, so the configured
Feishu textChunkLimit is honored for completed blocks. Preserve
mention targets only on the first emitted block chunk and keep
sentBlockText based on the original block text for duplicate-final
suppression.
Add regression test with a small textChunkLimit that verifies a
long block is split into chunked messages and mentions only appear
on the first chunk.
* fix(feishu): preserve block delivery target
---------
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
Claude Code >= 2.1.156 tightened its PermissionResult schema so an
approved can_use_tool control_response allow branch must carry an
updatedInput record. The Claude live-session bridge answered with the
deprecated { behavior: "allow" } shape and no updatedInput, so the CLI
rejected every approval-gated native tool call (Bash, WebFetch, and
AskUserQuestion among them) with a ZodError before the tool ran.
Echo the tool input back unchanged as updatedInput on the allow branch,
matching the shape the Claude Code 2.1 binary expects. The deny branch
and all other behavior are unchanged.
Fixes#95171.
hasProviderAuthForTool/hasAuthForProvider now thread cfg and workspaceDir into resolveEnvApiKey, so provider plugins that authenticate via environment variables and are only discoverable with config are detected during image/video model auto-selection instead of being dropped as unconfigured.
* fix(cron): persist startup catch-up deferral ids in service state to prevent read-RPC clobber
The startup overflow catch-up deferral (#93810) set deferred job
nextRunAtMs to a staggered slot, but the exemption was stored as a
local skipFutureRepairJobIds set threaded only into start()'s
maintenance recompute pass. Every other caller of
recomputeNextRunsForMaintenance — ensureLoadedForRead (list/status),
finalizeCompletedResults, empty-due tick, manual run preflight, and
releaseUnclaimedDueJobReservations — called maintenance recompute
without the skip set, causing shouldRepairFutureCronNextRunAtMs to
advance the deferred staggered slot to the job's natural next run,
dropping the missed run for a full period.
Fix: Move the exemption into CronServiceState as
pendingCatchupDeferralJobIds, populated by applyStartupCatchupOutcomes
where deferrals are assigned. recomputeNextRunsForMaintenance now
always checks this state-level set instead of a local parameter, and
clears each id once its staggered slot is reached (now >= nextRunAtMs).
This gives one canonical exemption path that covers all recompute
callers.
The now-redundant skipFutureRepairJobIds parameter is removed.
Fixes#93935
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(clownfish): address review for repair-94022-fresh-plan-20260618 (1)
* fix(cron): preserve agentTurn exempt + add stale-deferral cleanup + runtime proof
Address ClawSweeper review by:
1. Keeping the existing agentTurn deferred-slot exemption unchanged
(shouldRepairFutureCronNextRunAtMs still returns false for agentTurn
jobs with nextRunAtMs before the natural schedule).
2. Adding cleanup of stale pendingCatchupDeferralJobIds markers for
jobs that no longer exist or are disabled.
3. Adding regression tests for pending startup catch-up deferral
preservation and stale marker cleanup.
4. Adding standalone CLI runtime proof script demonstrating the fix.
Co-Authored-By: Claude <noreply@anthropic.com>
* fix: add pendingCatchupDeferralJobIds to test-harness + remove unused import
- Add pendingCatchupDeferralJobIds to createMockCronStateForJobs to fix TS2741.
- Remove unused loadCronStore import from runtime proof script.
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(cron): tighten startup catch-up deferral handling
---------
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: openclaw-clownfish[bot] <280122609+openclaw-clownfish[bot]@users.noreply.github.com>
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
* fix(gateway): cap agentRunCache to prevent unbounded growth under run fan-out
Time-based prune only reclaims entries past the 10-minute TTL window; a burst
of run fan-out can add far more entries than the window reclaims, so the cache
could grow without bound between prunes. Add a FIFO entry cap (5000) enforced
on insert, mirroring the existing Discord REST entity-cache bound.
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* test(gateway): preserve waited run snapshots under cache cap
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
* fix(tlon): bound error response body reads to prevent OOM
Replace bare response.text() on non-ok paths with readResponseTextLimited
capped at 16 KiB so a hostile or misconfigured Urbit ship cannot force the
gateway to buffer an arbitrary-size error body into process memory.
Affected paths:
- pokeUrbitChannel (channel-ops.ts)
- channel.runtime.ts poke path
- sendSubscription (sse-client.ts)
* fix(tlon): fix lint issues in error-body-boundary test
- Remove unused beforeEach import
- Wrap if/else bodies in braces (curly)
- Use block body for Promise executors (no-promise-executor-return)
* fix(types): resolve pre-existing TS test type errors
- Fix TS2493 tuple type errors in server-cron-notifications and
server-cron tests by adding explicit type annotations on mock.calls
- Fix TS2322 in anthropic.test.ts by adding as const to resource
content block type
* chore: trigger CI
* fix(update-check): bound npm registry JSON response read to prevent OOM
- Replace unbounded res.json() with readProviderJsonResponse capped at 16 MiB
- Update test mock to use real Response instead of bare object
- Verified against live npm registry: openclaw update status --json returns latestVersion: 2026.6.11
* fix(update-check): add 4 boundary tests for bounded npm registry read
- Tests: oversized response >16 MiB, near-boundary success
- Tests: malformed JSON, non-200 status code
- All pass with the readProviderJsonResponse bounded reader
* chore: add real behavior proof script for bounded JSON reader
Adds a standalone proof script that starts a local HTTP server and
drives the bounded reader against it with real HTTP requests, showing:
- Normal responses (~1 MB) parse correctly
- Oversized responses (>20 MB) are rejected with a descriptive error
- Malformed JSON is caught
- RSS does not spike on oversized responses
Ref. https://github.com/openclaw/openclaw/pull/98508
* chore: remove PR-specific proof script before merge
The proof script was accepted by ClawSweeper (proof: sufficient,
rating: diamond lobster), but it duplicates repository logic and
fails the scripts lint lane. Removing it per review feedback.
The real behavior proof remains in the PR body.
Ref. https://github.com/openclaw/openclaw/pull/98508
* fix(cli): retry logs.tail after journal fallback in logs follow
Rebase #88159 onto current main and keep systemd journal fallback temporary in follow mode. Preserve the journal cursor across repeated fallback outages, but retry logs.tail on the next loop so recovered Gateway RPC returns to normal log output.
This refresh also replaces the stale red checks-node-core-fast result from the old head with a current-head CI run.
* Keep log source metadata explicit
* ci: retrigger checks for PR #88159
* docs: clarify logs follow JSON source transitions
* fix(cli): keep journal logs responsive during recovery
---------
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
* fix(status): bound systemd service probes so status cannot hang on a wedged systemctl (#84698)
* test(daemon): assert readRuntime receives the threaded status timeout opts (#84698)
---------
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(cron): preserve provider/model on isolated-run timeout row
* fix(cron): carry provider/model/session into timer-built timeout rows
The reporter's blank cron_run_logs row (cron: job execution timed out
(last phase: ...)) comes from the wall-clock/cancel outcome built in
executeJobCoreWithTimeout, not the inner run catch the prior commit
patched (that catch result loses the Promise.race). Carry the
already-resolved attribution from watchdog-visible execution state into
the timer-built timeout and post-runner cancel outcomes so the persisted
row keeps provider/model/session. Pre-runner setup timeouts stay blank.
Refs #95873
* fix(cron): attribute timeout-disabled isolated-run operator-cancel rows
The timeoutSeconds:0 branch in executeJobCoreWithTimeout has no watchdog,
so it returned createOperatorCancellationOutcome() with no execution data
and never wired the execution callbacks. An operator-cancelled isolated run
with timeouts disabled still wrote a blank provider/model/session row.
Track the resolved identity locally from the same onExecutionStarted/
onExecutionPhase callbacks and carry it into the cancel outcome, matching
the timed branch. Adds a focused regression with negative control (#95873).
---------
Co-authored-by: Cursor <cursoragent@cursor.com>
Summary:
- The PR adds `cursor-agent` as an opt-in autoreview engine, updates the helper docs, runner dispatch, stream filtering, report parsing, and harness allowlists.
- PR surface: Docs +1, Other +99. Total +100 across 4 files.
- Reproducibility: not applicable. this is a feature PR, not a reported bug. The relevant check is source review plus maintainer validation of the external engine path.
Automerge notes:
- No ClawSweeper repair was needed after automerge opt-in.
Validation:
- ClawSweeper review passed for head 807659492b.
- Required merge gates passed before the squash merge.
Prepared head SHA: 807659492b
Review: https://github.com/openclaw/openclaw/pull/97348#issuecomment-4824183439
Co-authored-by: Mason Huang <masonxhuang@tencent.com>
Approved-by: hxy91819
* fix(cli): show exit code when npm install returns empty output
installPackageDir previously produced 'npm install failed:' with an empty
suffix when npm exited non-zero without writing to stdout or stderr. Users
running 'openclaw plugins install @openclaw/acpx' saw only that empty line
followed by the misleading hook-pack fallback error, leaving nothing
actionable in the output.
Add a small helper that keeps npm's own output when it exists but falls
back to reporting the exit code, signal, and termination reason when both
streams are empty. Regression tests cover the empty-output exit case and
the signal-terminated case; the existing stderr surfacing test still
passes unchanged.
Refs #98484
* fix(cli): narrow npm install failure diagnostics
---------
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>