Commit Graph

70518 Commits

Author SHA1 Message Date
Peter Steinberger
68ec50d643 fix(android): show conversation in screenshot fixture (#111000)
* fix(android): seed screenshot chat history

* fix(android): update screenshot chat readiness

* fix(android): use visible screenshot chat marker

* style(android): format screenshot script test

* fix(android): pin screenshot timezone

* fix(android): restore screenshot timezone
2026-07-18 17:02:29 -07:00
zengLingbiao
a68fdad8f5 fix(usage-bar): clear dead watcher reference after transient error (#109462)
* fix(usage-bar): clear dead watcher reference after transient error

When a usage bar template file watcher hits a transient error, the error
handler closes the FSWatcher but leaves entry.watcher pointing to the
closed instance.  loadUsageBarTemplate treats a truthy cached.watcher
as "still watching" and never re-reads the file, so a template that
became invalid stays stuck at the default forever.

Clear entry.watcher after closing so the next access that needs a
re-read can create a fresh watcher.

This matches the pattern from #109682 (config hot-reload watcher
recovery).

* fix(usage-bar): invalidate cached template on watcher error

Clear both entry.watcher and entry.template when the FSWatcher errors
so the next loadUsageBarTemplate call re-reads from disk and creates a
fresh watcher.  Previously only the watcher reference was cleared,
leaving a valid cached template that never observed future file edits.

This addresses the remaining valid-cache recovery gap from #109682.

* fix(usage-bar): fix no-promise-executor-return lint in test
2026-07-18 17:02:20 -07:00
zengLingbiao
0c221d2b4f fix(config): bound state-directory .env file reads with size limit (#109487)
* fix(config): bound state-directory .env file reads with size limit

Replace unbounded fs.readFileSync with readRegularFileSync capped at
1 MiB (MAX_STATE_DIR_DOTENV_BYTES) so an oversized .env file is
rejected before loading the entire file into memory.

Resolve symlinks via fs.realpathSync before the bounded read so
symlinked .env files keep working — matching the marketplace.ts
pattern for bounded manifest reads.

* fix(config): add diagnostic when oversized state .env is skipped

Log a warning when the state-directory .env file exceeds the 1 MiB
limit so operators know a configured file was skipped — matching the
pattern from #108200 (plugin catalog bounded read diagnostic).

* fix(config): bound global runtime dotenv file reads with size limit

Replace unbounded fs.readFileSync in readDotEnvFile with readRegularFileSync
capped at 1 MiB so CLI/Gateway startup dotenv loading also gets the bounded
read protection — not just the state-dir service-env path.

This addresses the P1 review finding that the original fix only capped the
helper-level reader while the shared readDotEnvFile used by
loadGlobalRuntimeDotEnvFiles was still unbounded.
2026-07-18 17:02:11 -07:00
NIO
86b5e279fb fix(voice-call): clamp continue poll RPCs to remaining deadline (#109053)
* fix(voice-call): clamp continue poll RPCs to remaining deadline

* test(voice-call): prove continue deadline bound

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-18 17:01:59 -07:00
zengLingbiao
c28284cb31 fix(config): bound external catalog file reads with size limit (#108200)
* fix(config): bound external catalog file reads with size limit

Replace unbounded fs.readFileSync with readRegularFileSync capped at
16 MiB (MAX_EXTERNAL_CATALOG_BYTES) to prevent memory exhaustion from
oversized or malicious plugin catalog files.

Resolve symlinks via fs.realpathSync before the bounded read so
symlinked catalog files keep working — matching the marketplace.ts
pattern for bounded manifest reads.

* fix(config): add diagnostic when oversized catalog is skipped

Log a warning when an external catalog file exceeds the 16 MiB limit
so operators know a configured file was skipped. Add regression test
verifying the oversized catalog is skipped and selection continues.

* fix(config): fix false-positive oversized catalog test

Replace the broken spy-on-object-literal mock with a real sparse file
that genuinely triggers readRegularFileSync rejection via stat.size.
The previous vi.spyOn({ readRegularFileSync }, ...) intercepted a
throwaway object, never the actual module import, so the test passed
regardless of whether the fix was applied or not.

Also fix the no-unused-expressions lint error on the env-primary
assertion that used a discarded ternary (? undefined : undefined)
instead of a proper expect assertion.
2026-07-18 17:01:54 -07:00
Peter Steinberger
a040f10e85 fix(gateway): reconcile config after watcher recovery (#111049)
Reload the current on-disk config once replacement native or polling watchers finish their initial scan, so edits made during recovery backoff are not lost.
2026-07-18 17:00:40 -07:00
Peter Steinberger
4b7d6fa3bf docs: align interactive client behavior (#111047) 2026-07-18 17:00:14 -07:00
Ted Li
10f5a7ac58 fix(groq): keep default Llama agent turns within TPM limit (#104904)
* fix(groq): recover oversized requests safely

* fix(groq): clear parallel tool aliases on fallback

* fix(groq): require provenance-aware host

* fix(groq): preserve configured request budgets

---------
authored-by: @MonkeyLeeT
Co-authored-by: Colin <colin@solvely.net>
2026-07-18 20:00:12 -04:00
Peter Steinberger
9a94beace7 fix(process): preserve descendant output under event-loop stalls (#111040)
* fix(process): drain buffered descendant output after exit

* test(process): cover deferred output release phase
2026-07-18 17:00:08 -07:00
Peter Steinberger
8853217ec7 fix(gateway): cancel run-bound approvals on abort and expose approval-park lifecycle (#110993)
* fix: harden approval abort lifecycle

* fix(gateway): recheck abort before committing detached exec authorization

* fix(gateway): recheck abort after inline exec authorization commit

* fix(gateway): propagate run-abort cancellation on the inline approval path

* fix(ci): refresh approval protocol bindings
2026-07-19 00:52:21 +01:00
lsr911
3d03b60da9 fix(litellm): guard loopback hostname auto-allow with isIP to prevent DNS SSRF bypass (#110693)
* fix(litellm): guard loopback hostname auto-allow with isIP to prevent DNS bypass

The isAutoAllowedLitellmHostname helper auto-enables private-network access
for loopback-style hosts. Before this fix, lowered.startsWith("127.")
matched DNS hostnames like 127.evil.com, letting remote endpoints bypass
the explicit allowPrivateNetwork opt-in — a SSRF risk.

Add isIP(host)===4 guard so only literal IPv4 loopback addresses qualify.
Same canonical pattern as extensions/slack/src/monitor/relay-source.ts:271
and the codex loopback fix.

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

* test(litellm): cover loopback endpoint policy

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-19 00:51:50 +01:00
cxbAsDev
8899940d5a fix(cron): support current and session: targets in initial delivery resolution (#99115)
* fix(cron): support current and session: targets in initial delivery resolution

resolveInitialCronDelivery only checked sessionTarget === 'isolated' for
default announce delivery. All other cron paths (delivery-plan.ts:106-114,
normalize.ts:680-684, jobs.ts:288-298) already treat 'isolated', 'current',
and 'session:' as equivalent. This gap meant cron jobs created with
--session-target current or --session-target session:... would not get
default announce delivery at creation time.

Real behavior proof:
  Input:  sessionTarget='current', payload.kind='agentTurn'
  OLD:    undefined  <- missing default announce delivery
  NEW:    {mode:'announce'}  <- consistent with other cron code paths

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

* test(cron): add typed initial delivery resolution tests for all session targets

* test(cron): document direct-service delivery contract and cover service callers

* refactor(cron): centralize detached-delivery-target predicate into shared helper

Extract isDetachedDeliveryTarget(sessionTarget, payloadKind) in normalize.ts
and use it from all three callers:

- normalizeCronJobInput (write-time default, normalize.ts)
- resolveCronDeliveryPlan (read-time default, delivery-plan.ts)
- resolveInitialCronDelivery (service-bypass default, initial-delivery.ts)

This removes the third manually synchronized copy that the original PR
added, addressing ClawSweeper P1 finding.

* fix(cron): align initial delivery targets

Co-authored-by: 陈宪彪0668000387 <chen.xianbiao@xydigit.com>

* test(cron): consolidate initial delivery coverage

Co-authored-by: 陈宪彪0668000387 <chen.xianbiao@xydigit.com>

* test(cron): keep delivery matrix type-safe

Co-authored-by: 陈宪彪0668000387 <chen.xianbiao@xydigit.com>

* chore: keep release note in PR metadata

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-19 00:51:05 +01:00
Jason (Json)
7c070d6df6 feat: allow standalone MCP Apps to use bound tools and resources (#110515)
* Gateway: enable ticketed MCP App bridge

* Gateway: make MCP App operation switch exhaustive

* refactor(gateway): drop no-op MCP App route change

* fix(gateway): enforce standalone MCP App tool authority

* docs(gateway): clarify standalone MCP App ticket authority

* fix(gateway): require standalone MCP App initialization

* refactor(gateway): keep standalone route load explicit
2026-07-18 17:50:37 -06:00
Omar Shahine
8b720729d2 fix(imessage): keep fast progress out of chat (#110052)
* fix(imessage): keep fast progress out of chat

* test(imessage): require fast progress callback

---------

Co-authored-by: Omar Shahine <10343873+omarshahine@users.noreply.github.com>
2026-07-18 16:45:10 -07:00
Peter Steinberger
56eef79989 fix(channels): recover dead-lettered inbound events (#111029)
* feat(channels): add ingress dead-letter recovery

* fix(channels): preserve dead-letter compatibility

* docs: refresh CLI map for channel dead letters
2026-07-19 00:44:23 +01:00
Peter Steinberger
65915bcd26 fix(ui): openknot/dash dark theme AA contrast for text-bearing fills (#111003) 2026-07-19 00:42:37 +01:00
Peter Steinberger
7562b79465 refactor(channels): share durable ingress monitor (#111017)
* refactor(channels): share durable ingress monitor

* fix(channels): harden ingress monitor shutdown

* docs: refresh SDK documentation map
2026-07-19 00:42:08 +01:00
Alexzhu
e5e93e8169 fix(whatsapp): evaluate mention patterns when other members are @-mentioned (#110412)
* fix(whatsapp): evaluate mention patterns when other members are @-mentioned

isBotMentionedFromTargets returned false as soon as a group message
carried native @-mentions that did not include the bot, so the
configured mentionPatterns were never evaluated and a message like
'marlow, look at @SomeoneElse's message' was silently dropped by the
requireMention gate (#109488).

Fall through to the configured text mentionPatterns when the native
@-mention JIDs do not include the bot. The loose self-number digit
fallback stays suppressed in that shape: an @-tag of another member
injects that member's number into the body, so substring digit
matching is unreliable there.

Fixes #109488

* refactor(whatsapp): unify mention pattern gating

---------

Co-authored-by: Marcus Castro <mcaxtr@openclaw.ai>
2026-07-18 20:40:34 -03:00
Peter Steinberger
c1e714e3df refactor(agents): shared spawn orchestration pipeline behind backend adapters (#111007)
* refactor(agents): share spawn orchestration pipeline

* fix(agents): preserve ACP spawn failure contract

* fix(agents): progress hooks keep per-backend session-key semantics

* fix(agents): ACP registration keeps the resolved requester agent id

* chore(agents): drop orphaned exports surfaced by the spawn dedup
2026-07-19 00:40:22 +01:00
Peter Steinberger
ec998a0f3f feat(canvas): export widgets as PNG — copy or download from the card menu (#110992)
* feat(canvas): export widgets as PNG — copy to clipboard or download from the card menu

* fix(ui): widget-export lint, knip, and lines-budget cleanup
2026-07-19 00:39:59 +01:00
Peter Steinberger
941ed4fd4a fix(memory-wiki): preserve unavailable source pages (#111034)
Preserve imported unsafe-local wiki pages and human annotations while configured source scopes are temporarily unreadable.
2026-07-19 00:39:23 +01:00
mushuiyu886
d411559dfb fix(acp): reject malformed session list cursors (#107895)
* fix(acp): reject malformed session list cursors

* fix(session-catalog): validate pagination cursors exactly

Co-authored-by: 杨浩宇0668001029 <yang.haoyu@xydigit.com>

* refactor(session-catalog): align search normalization owner

* refactor(session-catalog): keep parsing helpers private

Co-authored-by: 杨浩宇0668001029 <yang.haoyu@xydigit.com>

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-19 00:38:02 +01:00
tzy-17
828bcd8231 fix(scripts): bound GHSA patch GitHub lookups (#110756)
* fix(scripts): bound GHSA patch subprocesses

Co-authored-by: 唐梓夷0668001293 <tang.ziyi@xydigit.com>

* fix(scripts): satisfy GHSA runner control-flow lint

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-19 00:37:06 +01:00
Peter Steinberger
ed458f14dc test(scripts): wait for Knip pid file content (#111001) 2026-07-19 00:36:15 +01:00
Peter Steinberger
9275837f41 docs: explain managed Gateway heap sizing (#111027) 2026-07-19 00:36:03 +01:00
Peter Steinberger
f7024690ac refactor(gateway): split chat handlers by workflow (#111022) 2026-07-19 00:35:42 +01:00
Peter Steinberger
4362e1a4fe fix(agents): recognize nested message delivery receipts (#111012) 2026-07-19 00:33:33 +01:00
Peter Steinberger
dc8f90197e fix(tui): guarantee exit after drained teardown (#111015) 2026-07-19 00:33:16 +01:00
Jason (Json)
0483001ef6 fix(scripts): dedupe release checklist declaration (#111024) 2026-07-18 17:21:15 -06:00
Peter Steinberger
5590d7c280 docs: align SecretRef degradation semantics (#111021) 2026-07-19 00:18:01 +01:00
mushuiyu886
2dce9d3012 fix(scripts): retry auth alerts after ntfy rejects delivery (#110760)
* fix(scripts): retry auth alerts after delivery failure

* test(scripts): cover mixed auth notification outcomes

Co-authored-by: 杨浩宇0668001029 <yang.haoyu@xydigit.com>

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-19 00:10:32 +01:00
Peter Steinberger
14a714901b docs(imessage): align recovery with durable ingress (#111002) 2026-07-19 00:09:44 +01:00
zengLingbiao
b1c49677ec fix(agents): use fatal UTF-8 decoding for provider JSON responses (#108849)
* fix(agents): use fatal UTF-8 decoding in provider response readers

* fix(agents): use fatal UTF-8 decoding only for JSON responses, preserve compatibility for text
2026-07-18 16:08:30 -07:00
Alex Knight
66aa22e4e8 fix(ui): keep session rosters consistent (#108249)
Co-authored-by: Alex Knight <15041791+amknight@users.noreply.github.com>
2026-07-19 09:06:32 +10:00
Peter Steinberger
ea1887667e fix(scripts): declare validateTrustedToolingPin in the release-candidate contract (#111011) 2026-07-19 00:04:17 +01:00
tzy-17
e33257de11 fix(scripts): bound duplicate PR closure GitHub lookups (#110750)
* fix(scripts): bound duplicate PR closure GitHub lookups

The duplicate PR closure helper performs multiple sequential gh API
reads and writes after a merge. Each call used execFileSync without a
timeout, so one stalled GitHub request could block the surrounding
workflow job until it expires.

Add a 60-second timeout and SIGKILL to the default gh runner, applied
to both read-only lookups and pr edit writes that forward stdin.

* test(scripts): add real behavior proof for duplicate PR closure timeout

Add two live subprocess tests using the real spawnSync (not mocked) to
prove the timeout + SIGKILL surface works against actual child
processes:

- A 1 ms timeout against a long-running node subprocess proves
  SIGKILL is delivered and the timeout triggers correctly.
- A fast node -e 0 subprocess with the production 60-second bound
  proves the timeout does not false-positive on healthy completions.

Switch the vi.mock to a partial mock using importOriginal so
spawnSync remains the real implementation for live tests while
execFileSync stays mocked for the DI-based option assertions.

* refactor(scripts): inject duplicate closure GitHub runner

* fix(scripts): declare trusted tooling pin validator

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-19 00:01:23 +01:00
Miorbnli
9d0836ee25 fix(thread-ownership): bound 409 response read and preserve cancel semantics (#98941)
* fix(thread-ownership): bound 409 response read and preserve cancel semantics

The thread-ownership 409 conflict path still used unbounded resp.json(),
inconsistent with the bounded readers shipped across the other channel/provider
success paths. A compromised or buggy forwarder returning a multi-GB 409 body
would buffer the entire body before JSON.parse, OOMing the agent.

Bound the 409 body via readResponseTextLimited (8 KiB cap; a 409 owner field is
~30 bytes). Wrap the parse in try/catch so a truncated or malformed 409 body
still cancels the send (owner logged as "unknown") — the 409 status itself
means another agent owns this thread, independent of body parseability.

The discord webhook and huggingface /v1/models success reads from the original
PR were superseded upstream by #98098 and #101079 (readProviderJsonResponse),
so this branch now carries only the thread-ownership fix.

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

* fix(thread-ownership): bound forwarder conflict handling

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-07-19 00:01:09 +01:00
Peter Steinberger
077869c032 fix(release): declare validateTrustedToolingPin in the checklist contract (#111009) 2026-07-18 15:57:58 -07:00
WhatsSkiLL
19184a9fc6 improve(android): move Wear agent, session, and model pickers to Home (#110661)
* improve(android): move Wear agent, session, and model pickers to Home

* fix(android): harden Wear home context controls

Co-authored-by: JARVIS-Glasses <whatsskilll@gmail.com>

* fix(android): preserve Wear session model in capped lists

Co-authored-by: JARVIS-Glasses <whatsskilll@gmail.com>

* fix(android): scope Wear model catalogs to sessions

Co-authored-by: JARVIS-Glasses <whatsskilll@gmail.com>

* fix(android): harden Wear context request ordering

Co-authored-by: JARVIS-Glasses <whatsskilll@gmail.com>

* fix(android): scope Wear model responses to event cursors

Co-authored-by: JARVIS-Glasses <whatsskilll@gmail.com>

* fix(android): reload Wear catalog after model selection

Co-authored-by: JARVIS-Glasses <whatsskilll@gmail.com>

* fix(android): keep bounded Wear models navigable

Co-authored-by: JARVIS-Glasses <whatsskilll@gmail.com>

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-18 23:57:25 +01:00
Peter Steinberger
556a2ee276 feat(cron): add per-job dynamic cadence (#110978)
Add optional per-job pacing bounds across the cron API, CLI, tool schema, public output, and SQLite job envelope, requiring at least one bound. Allow only the currently running paced job to record a one-shot next_check proposal and carry it through isolated-run completion.

After successful runs, clamp the proposal to the job bounds and persist an exact one-shot slot marker so maintenance preserves only that timestamp. Clear the marker on runs, edits, and schedule normalization; preserve existing no-proposal, skip, timeout, and error scheduling behavior.
2026-07-18 23:43:39 +01:00
Peter Steinberger
5114b45927 chore(canvas): compact show_widget tool description with pattern anchor (-40% tokens) (#110999) 2026-07-18 23:41:29 +01:00
Peter Steinberger
d343216510 fix(ios): keep unified voice controls recoverable (#110906)
* docs(ios): align unified chat voice copy

* fix(ios): keep active dictation control available

* fix(ios): keep active talk control available

* fix(ios): restore unified voice recovery

* fix(ios): keep pending dictation cancel visible

* chore(ios): refresh native i18n inventory

* chore(ios): sync unified voice locale memory

* fix(ios): return unified mic label view

* test(ios): lock dictation cancellation ordering
2026-07-18 23:41:00 +01:00
Peter Steinberger
333a3297af refactor(plugin-sdk): consolidate persistent dedupe claim loop (#110984) 2026-07-18 23:36:59 +01:00
Peter Steinberger
26e7575780 fix(release): pin trusted candidate tooling across main advances 2026-07-18 23:33:42 +01:00
Dallin Romney
56915896bc fix(qa): bound Matrix E2EE sends (#110968) 2026-07-18 15:32:44 -07:00
tzy-17
9918dd77c4 fix(scripts): bound release CI summary GitHub lookups (#110747)
* fix(scripts): bound release CI summary GitHub lookups

The release CI summary helper performs multiple sequential gh API reads
during full release validation. Each read used execFileSync without a
timeout, so one stalled GitHub request could block the surrounding
workflow job until it expires.

Route the default gh runner through a caller-owned execFileSync with a
60-second timeout and SIGKILL, and apply the same bound to artifact zip
downloads. The runner accepts an execFileSyncImpl injection so the
timeout contract can be tested without a slow timer-based test.

* test(scripts): add real behavior proof for release CI summary timeout

Add two live subprocess tests alongside the existing mocked tests:

- A 1 ms timeout against a real gh subprocess proves the SIGKILL +
  timeout surface works on actual child processes (not only mocks).
- A fast node -e 0 subprocess with the production 60-second bound
  proves the timeout does not false-positive on healthy completions.

The runReleaseCiGh runner now accepts an optional timeoutMs parameter
so tests can exercise a shorter timeout without changing the production
default.

* refactor(scripts): share bounded release GitHub runner

* test(scripts): keep release runner assertions type-safe

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-18 23:29:19 +01:00
Peter Steinberger
7fbfc2e8ad fix(plugins): allow intentional uninstall size drops (#110991) 2026-07-18 23:28:18 +01:00
cxbAsDev
2295fae731 fix: bound miscellaneous unbounded file reads across 5 modules (#110516)
* fix: bound misc unbounded fs.readFile calls; remove unused fs import

* fix: decode buffer to string before passing to string consumers

readRegularFile and readRegularFileSync return { buffer, stat },
not a string. All 4 new call sites passed the raw object to functions
expecting a string (JSON.parse, RegExp.test, template literals, etc.),
causing TS2345 type errors and runtime failures.

Fix each call by extracting .buffer and calling .toString('utf8')
before passing the result to string consumers.

* style: fix oxfmt formatting in config-set-input.ts

* fix: bound config and trajectory metadata reads

Co-authored-by: 陈宪彪0668000387 <chen.xianbiao@xydigit.com>

* refactor: isolate bounded read ownership

Co-authored-by: 陈宪彪0668000387 <chen.xianbiao@xydigit.com>

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-18 23:27:26 +01:00
Peter Steinberger
a5ec26fa3c fix: prevent LINE channel reloads from hanging on stalled deliveries (#110971)
* fix(channels): bound ingress shutdown and document retention

* docs(channels): note ingress shutdown behavior

* chore: keep release notes in pull request

* docs: refresh documentation map

* fix(line): preserve deferred claims during shutdown

* fix(line): handle late abandonment failures
2026-07-18 23:25:33 +01:00
Peter Steinberger
7a7d6bb51f fix: cloud-worker results are lost when the box dies before reconciliation (#110952)
* fix(cloud-workers): stage worker results durably before reconciliation

* fix(cloud-workers): model result staging test seam

* fix(cloud-workers): disable staging git hooks safely

* chore: defer cloud worker release note

* fix(cloud-workers): harden staged result recovery
2026-07-18 23:24:50 +01:00