* fix(nextcloud-talk): dispose webhook auth rate limiter on monitor stop
The monitor created its webhook auth rate limiter with a prune interval
but never called dispose(), leaking one interval plus entry maps per
stop/start cycle (boot, config hot reload, health-monitor restart).
dispose() is idempotent and callers own the timer lifecycle, matching
how core gateway callers release their limiters on shutdown.
* fix(nextcloud-talk): release webhook limiter in all lifecycle owners
Preserve the contributor stop-time limiter disposal while routing the shared webhook harness and both direct-listener fixtures through the same canonical stop owner, including failure cleanup.
Co-authored-by: wangmiao0668000666 <wang.miao86@xydigit.com>
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Route Claude Agent SDK AskUserQuestion through OpenClaw's shared structured-input flow across the Control UI and existing channel fallback surfaces.
Fixes#81099.
Preserve the contributor fix from #127288 and its original Git author. Thanks @cantoblanco for the original issue and pull request.
Co-authored-by: Alex <alex@example.com>
* feat(geolocation): resolve client addresses to a coarse city via a bundled plugin
The Activity identity card could show a client's IP address but not where it
was, so an operator still had to look the address up by hand.
Add a bundled `geolocation` plugin that owns address-to-place resolution behind
one authenticated route, `GET /plugins/geolocation/lookup?ip=`. It downloads a
MaxMind-format database on first lookup into the state directory, answers from
that local copy, and refreshes it monthly, so a lookup never sends an address
to a third party. The Control UI renders the resolved city on the device row
next to the address and the client-reported time zone.
The default source is DB-IP City Lite under CC BY 4.0. That license requires
attribution, so every response carries the credit and the UI renders it next to
the value; the database is downloaded at runtime and never redistributed.
Plugin code and the `maxmind` reader are MIT. No free city-level IP database is
MIT-licensed, so the obligation lives with the data rather than the code, and
`databaseUrl` plus the attribution fields make the source swappable.
No new core provider kind: with one implementation the plugin owns everything
through the existing HTTP-route seam, keeping core plugin-agnostic. A second
provider is what would justify promoting this to a registry contract.
Availability and lookup failure stay distinguishable: a missing or still
downloading database answers 503, never `found: false`. A failed refresh serves
the cached copy, and a body that does not parse as an MMDB is discarded without
replacing a working database.
* fix(docs): correct geolocation config examples and add zh-CN glossary entries
The config examples used `plugins.<id>` instead of the real
`plugins.entries.<id>.config` shape, which the docs config-example
validator and src/config/docs-config-examples.test.ts both reject.
New doc labels also need zh-CN glossary entries.
* chore(labeler): cover the geolocation extension directory
AGENTS.md requires a labeler entry plus a GitHub label for every new
plugin surface; test/scripts/labeler-extension-coverage.test.ts enforces
the labeler half.
* fix(geolocation): address review findings on caching, download bounds, and scope
Cold-start lookups were permanently suppressed. The loader cached one promise
per address including failures, so the 15s browser deadline expiring against a
first download that takes ~46s cached a blank forever, and a mounted row only
looks up again when its IP changes. Lookups now return a discriminated
located/absent/unavailable result: only definitive answers are cached, and the
element retries an unavailable one on a widening 5s/15s/45s schedule.
Download limits ran after allocation. The size check happened only after
`response.arrayBuffer()` had buffered the whole body, and gunzip had no output
ceiling, so a replaced source or a compression bomb could exhaust Gateway memory
before rejection. The body now streams against a compressed ceiling enforced
per chunk, and inflation uses zlib's maxOutputLength.
Cached placements were not scoped to the Gateway. The cache keyed only by
address while endpoint and credentials come from the shared Gateway context, so
a switch could render the previous Gateway's answer. The shared reset hook now
supports multiple subscribers - a single slot silently dropped whichever
registered first - and the geolocation cache subscribes.
Unresolvable ranges no longer trigger a download. Only loopback suppresses `ip`
at connect, so Tailscale carrier-grade-NAT and LAN addresses are recorded and
displayed. No geolocation database contains them, so a tailnet-only or LAN-only
Gateway was downloading 125 MB to answer nothing. The route now answers those
ranges without loading the database, using the already-public
`isPrivateOrLoopbackHost` seam so the SDK surface budget is unchanged.
The quickstart queried a reserved documentation range while showing a located
response, which cannot happen; it now uses a routable address and documents the
not-found case.
* fix(deps): resync the lockfile after dropping the net-policy dependency
The geolocation plugin briefly depended on @openclaw/net-policy before
switching to the already-public isPrivateOrLoopbackHost SDK seam. The
package.json entry was removed without regenerating the lockfile, so the
frozen-lockfile install failed and every downstream CI job failed with it.
* fix(memory-wiki): persist ChatGPT import run record before compiling the vault
The import wrote and overwrote wiki pages, then compiled the whole vault, and
only persisted the rollback run record after a successful compile. When the
compile failed, for example on an unrelated report page with malformed
frontmatter, the pages were already changed but no run record existed, so the
run was invisible to listing and rollback could not restore the overwritten
pages. The record is now persisted right after the page writes and before the
compile, keeping every page-mutating run rollbackable.
* fix(memory-wiki): expose failed import rollback id
---------
Co-authored-by: Ayaan Zaidi <hi@obviy.us>
* refactor(anthropic): explore official Claude Agent SDK runtime
* refactor(anthropic): replace handwritten Claude sessions with SDK
* refactor(anthropic): collapse SDK live-session ownership
* refactor(anthropic): simplify SDK ownership and preserve live skills
* fix(anthropic): fence cancelled SDK runs before process startup
* fix(anthropic): harden SDK approvals, lifecycle, and packaging
* refactor(anthropic): own SDK process trees and streamline runtime
* fix(anthropic): repair rebased packaging and legacy test fixtures
* fix(diffs-language-pack): send Content-Length on viewer HEAD responses
* test(diffs-language-pack): await route handler result and build generated viewer runtime fixture
* test(diffs-language-pack): reuse canonical viewer build and HTTP server
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
* fix(llm-task): trust explicit provider for slash-containing model ids
Model ids like openai/gpt-oss-20b contain a slash that resolveModelRefFromString
misreads as a provider separator, overriding an explicit provider=groq and
resolving to provider=openai. When the caller supplies an explicit provider,
trust it and only strip a duplicate provider prefix instead of re-parsing the
model string.
* fix(llm-task): preserve aliases with explicit providers
* fix(llm-task): preserve selected providers for nested model ids
Co-authored-by: Chris Cantwell <ChrisCantwell@protonmail.com>
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
* fix(msteams): use one Teams API runtime entrypoint
* test(msteams): exercise packaged CJS loader
* test(msteams): run packaged build through CLI
* chore(msteams): document SDK assertion safety
Failed channel turns could leave caller-owned pending group history in the next prompt. Finalize it on every terminal path, and filter Telegram rolling context while preserving explicit reply ancestry.
Co-authored-by: SunnyShu0925 <shu.zongyu@xydigit.com>
Co-authored-by: Ayaan Zaidi <hi@obviy.us>