Commit Graph

1294 Commits

Author SHA1 Message Date
Peter Steinberger 40cb6f0e3b feat(ui): keep Where picker destinations live (#122531)
* feat(gateway): enrich environment summaries

* chore(sdk): refresh plugin API surface

surface drift approved: additive EnvironmentSummary enrichment (runners plan rev 2, milestone 4)

* feat(ui): keep where picker destinations live

* docs: link picker liveness milestone PR

* fix(ui): deduplicate picker locale keys

* test(ui): update picker section expectations

* fix(ssrf): narrow lookup resolver contract

* fix(gateway): publish authoritative environment facts
2026-08-12 05:11:46 -07:00
Peter Steinberger 08142099da refactor(plugins): remove test-only facades and adapter (#122532)
* refactor(plugins): trim test-only facades

* refactor(whatsapp): remove legacy outbound adapter
2026-08-12 01:20:09 -07:00
Peter Steinberger b080dd1e76 refactor: consolidate coercion contracts (#122458)
* refactor: consolidate coercion contracts

Centralize exact string, record, numeric, date, Boolean, argument, and structured-error coercions while preserving call-site semantics.

Migrate canonical-name collisions and deprecated internal SDK bypasses, deleting 55 net production/tooling lines. Expand declaration ownership enforcement to 101 allowed helpers and add a narrow export-completeness audit.

* fix: preserve standalone script coercions

Keep copied Control UI tooling self-contained and retain the trusted release harness module-relative source seam when the harness runs against an old target cwd.
2026-08-11 23:26:37 -07:00
Peter Steinberger 964c8c84c1 refactor: consolidate coercion ownership (#122299)
* refactor: consolidate coercion ownership

Centralize four canonical coercion helpers, migrate exact core and plugin duplicates through narrow Plugin SDK facades, and enforce declaration and plugin-normalization ownership boundaries.

The sweep adds eight focused SDK exports while deleting more production and tooling code than it adds. User-visible behavior is unchanged except for safer equivalent object and UI parsing at existing boundaries.

* fix: guard integer option ownership

Register resolveIntegerOption with the canonical function owner and extend the declaration-guard fixture so future local duplicates fail validation.

* fix: keep integer helpers on numeric facade

Remove the unshipped duplicate string-coerce exports and route every affected plugin consumer through the existing number-runtime contract.

* fix: point numeric coercion to number runtime

Make boundary and declaration diagnostics recommend the canonical numeric facade, with failing-before coverage for both guidance paths.
2026-08-11 17:14:53 -07:00
Peter Steinberger cad77fb39c refactor: consolidate remaining coercion helpers (#122020) 2026-08-11 10:22:01 -07:00
Ayaan Zaidi 2c8ed54ddb feat(heartbeat): default delivery to the configured owner, never groups (#121988)
Unset heartbeat.target now resolves "owner": elected heartbeat notifications deliver to the operator's DM resolved from commands.ownerAllowFrom or the channel allowFrom (first concrete entry; wildcards and channel-scoped wildcards excluded; configured owners exhausted across channels before any channel-local fallback). Delivery requires the channel's own classifier to positively prove a direct destination — every bundled messaging plugin now ships an inferTargetChatType contract — and unproven or group-shaped destinations fail closed to the visible no-route state. The first implicitly-routed delivery carries a one-line self-explanation naming the target: "none" opt-out. Explicit target "last" remains as the follow-the-conversation opt-in. Refines the unreleased #121892 default before it ships; refs #121880.

Co-authored-by: Ayaan Zaidi <hi@obviy.us>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-08-11 13:18:22 +00:00
Ayaan Zaidi 77fc82c9d3 test(feishu): opt into raw commandText in raw-detail card test
The raw-command-detail streaming card test shipped in #121826 asserting
raw exec text under the default commandText mode, but the same commit
made "status" (tool label only) the documented default with raw as an
explicit opt-in. The test has failed since introduction; change-classified
CI never selected the feishu lane on main pushes. Opt the test into
streaming.progress.commandText: "raw" so it proves the documented path.
2026-08-11 09:30:23 +02:00
Peter Steinberger fa03d9b913 refactor: consolidate coercion helpers (#121366)
* refactor: consolidate coercion helpers

* fix: remove duplicate coercion imports

* fix: preserve serialized coercion guard

* chore: ratchet coercion helper carve-outs

* fix(test): keep gauntlet subprocess startup lean

* fix: preserve imported session timestamp semantics

* fix: preserve catalog timestamp string semantics

* chore: align plugin SDK surface ratchet

* fix: preserve trajectory and SDK string contracts

* fix(test): preserve QA record assertion semantics

* fix: complete standalone record guard rename

* refactor(cron): use canonical string coercion

* fix(acpx): preserve Pi timestamp parsing

* test(channels): adapt custody test harnesses

* test(telegram): classify media harness as test support

* test(acpx): split timestamp contract coverage

* test(channels): support generated custody contracts

* chore: ban the full coercion helper name set

Extends the declaration guard to all eleven consolidated helper names and
renames the cron schedule-identity readNumber wrapper to readScheduleInteger
so the banned generic name cannot regrow.

* fix(scripts): repair release-validation guard drift and lint cause

Restores the renamed isJsonRecord guard in assertTrustedWorkflowHarness after
main added isRecord call sites in parallel, and attaches the caught YAML error
as the thrown error cause (preserve-caught-error was red on main).

* fix: preserve Claude timestamp string semantics

* fix: preserve persisted timestamp string semantics

* fix: preserve date-first timestamp contracts

* fix(openai): harden delegation failure formatting

* chore: close coercion helper guard gaps

* test(openai): model non-error delegation rejection

* chore: refresh plugin SDK API contract

* fix(tasks): use canonical string field reader

* fix(ai): use canonical provider error field coercion

* fix(browser): migrate native bootstrap coercion

* docs(plugin-sdk): clarify text record export compatibility

* fix(gateway): normalize approval execution identity

* test(outbound): isolate message action poll harness
2026-08-11 00:02:18 -07:00
Peter Steinberger f4bac99a81 feat(secrets): add SQLite-backed secret store (#121559) 2026-08-10 07:08:40 -07:00
Peter Steinberger f805ad0354 refactor(extensions): remove unused compatibility exports (#121338) 2026-08-09 19:01:38 -07:00
Peter Steinberger 2e6c2bba19 fix(feishu): restore forwarded interactive card content (#115136) 2026-08-09 07:07:03 -07:00
Peter Steinberger 8616c0c374 refactor: finish shared test helper migrations (#120996)
* test: finish shared helper migrations

* test: fix helper migration CI

* style: fix test import ordering

* test(acpx): restore deferred void types

* test: fix helper migrations after rebase
2026-08-09 06:00:06 -07:00
Peter Steinberger 75dbe52e3e refactor: one code path behind doctor legacy-state migrations (#120716)
* refactor(doctor): prefer manifest route-state owners

* refactor(doctor): unify config repair declarations

* refactor(doctor): unify legacy state migrations

* fix(doctor): satisfy migration pipeline guards

* fix(plugin-sdk): keep doctor adapter inside boundary
2026-08-08 18:23:15 -07:00
Peter Steinberger 8cb53c7b55 perf(doctor): keep bundled doctor contract closures dependency-light (#120698)
* perf(doctor): keep bundled doctor contract closures dependency-light

Doctor contract enumeration cold-loads each plugin's doctor-contract-api
closure via jiti, so a static value import of openclaw/plugin-sdk/runtime-doctor
pulled the state-db/kysely graph (~4.3s per closure) into
listPluginDoctorLegacyConfigRules / listPluginDoctorStateMigrationEntries.

- migrate all light doctor-contract closures (66 files) to the
  dependency-light openclaw/plugin-sdk/runtime-doctor-migrations subpath
- voice-call: load detect/repairOpenClawStateDatabaseSchema* lazily inside
  the migration bodies; keep only a type-only static runtime-doctor import
- matrix: split pure credential record shapes/normalizers into
  credentials-state.ts so the doctor closure no longer imports the sync
  plugin-state store through credentials-read
- guard: doctor-contract-closure-guard.test.ts now forbids static value
  imports of runtime-doctor in closures alongside agent-runtime

* fix(matrix): keep credential revocation record type module-local

Knip production scan flags the export as consumer-less; the type is only
referenced by the exported union and revocation guard signature.
2026-08-08 17:51:31 -07:00
Peter Steinberger da4a656cdb improve: doctor migration checks no longer load every bundled plugin runtime (#120678)
* perf(plugins): declare doctor contract surfaces

* perf(doctor): slim migration import closures

* perf(plugins): narrow doctor declaration record surface and wire owner-test lane

Registry records carry only the doctorContract declaration instead of the whole
parsed manifest, and check:changed now selects the src/plugins-owned declaration
honesty and closure-guard tests for extension module/manifest changes so
cross-lane drift cannot pass PR classification.

* fix(doctor): keep control-plane dist imports require-safe

Keep doctor and channel control-plane chunks off exec-class dependencies, and enforce native require(esm) loading during postbuild.

* chore(plugin-sdk): regenerate API baseline

* chore(plugin-sdk): sync export ordering

* fix(plugins): satisfy doctor contract CI boundaries

* perf(doctor): make qqbot doctor closure dependency-light

qqbot was the last plugin above 5s in doctor state-migration enumeration
(~8s under tsx/jiti). The cost was not the state-key builder (already a
leaf): its doctor closure value-imported the runtime-doctor SDK barrel,
whose plugin-state-store/state-db re-exports pull kysely (~330 modules),
plus security-runtime for one fileExists (~200 modules), all resolved
per-module by jiti during enumeration.

Split the migration-define helpers and light re-exports into a new
private-local plugin-sdk/runtime-doctor-migrations subpath; runtime-doctor
re-exports it so its public surface is byte-identical (API baseline hash
unchanged). qqbot's doctor-contract and state-migrations now import only
the light subpath, swapping fileExists for the equivalent async
legacyStateFileExists already in the closure.

qqbot enumeration: ~8.0s/531 modules -> ~0.25s/18 modules.

* chore(plugin-sdk): drop private-local subpath from API baseline

runtime-doctor-migrations is private-local-only; the baseline tracks public
modules, and the earlier line was generated before the classification.

* fix(plugins): register runtime-doctor-migrations boundary paths

The private-local subpath list feeds the extension package boundary map;
the shared paths config and xai's derived overrides must carry the same
entry or the boundary contract test fails.
2026-08-08 13:29:18 -07:00
Peter Steinberger 48639663b0 chore(release): prepare 2026.8.1 (#120375) 2026-08-07 18:44:12 -07:00
Josh Avant c691f2e41c fix(progress): preserve callback acceptance results (#120171)
* fix(progress): preserve callback acceptance results

* fix(progress): require transport acknowledgements

* fix(progress): preserve direct acceptance outcomes
2026-08-07 14:40:33 -05:00
Peter Steinberger b4a26783f7 refactor(test): consolidate duplicated requireRecord and provider HTTP mock helpers (#119982)
* refactor(test): consolidate duplicated test helpers

* test: remove stale record guard import

* fix(test): remove orphaned record guards

* refactor(test): keep record requirement messages exhaustively typed

* fix(test): keep packages/ai record guard package-local
2026-08-06 14:48:01 -07:00
Pavan Kumar Gondhi 528c5e0817 fix(feishu): honor cross-context limits for message mutations [AI] (#119845)
* fix(feishu): guard native mutation targets

* fix(outbound): preserve direct resource actions
2026-08-06 14:38:24 +05:30
Jason (Json) ab7b3ffd1f fix: retry delivery when outbound adapter is unavailable (#119371)
* fix(outbound): preserve pre-dispatch retryability

* test(outbound): assert lazy runtime sender

* fix(feishu): preflight direct message runtime

* test(gateway): preserve scoped registry fixture
2026-08-04 21:22:07 -06:00
zhangLei99586 e79f358b02 fix(feishu): report bot identity retry failures (#102185)
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
Co-authored-by: zhangLei99586 <294081397+zhangLei99586@users.noreply.github.com>
2026-08-04 22:45:28 +08:00
Patrick Erichsen 1aea2df935 fix(plugins): refresh bundled channel skills (#119020) 2026-08-03 17:31:00 -07:00
Peter Steinberger 14fe739ee9 fix(feishu): enforce exact signed webhook request boundaries (#118758)
* fix(feishu): enforce exact signed webhook request targets

* fix(feishu): preserve explicitly configured signed webhook query targets

* fix(feishu): preserve shipped relative webhook paths

* fix(feishu): normalize and migrate legacy webhook callback paths

* fix(feishu): preserve transformed webhook schema defaults

* fix(feishu): require canonical webhook paths before runtime startup

* docs(feishu): document canonical webhook routes and doctor recovery
2026-08-03 14:52:58 -07:00
Peter Steinberger f9d9d1225a refactor(channels): own the lifecycle status contract in SDK patch factories (#118795)
* refactor(sdk): add channel lifecycle patch factories

* refactor(channels): adopt lifecycle patches in a-m

* refactor(channels): adopt lifecycle patches in n-z

* refactor(runtime): lifecycle-own ambient registries

* test(slack): assert lifecycle factory fields

* fix(sdk): preserve lifecycle patch extras types

* test(zalouser): widen lifecycle status sink

* test(irc): avoid shadowed status patch

* fix(zalo): reuse account-agnostic media route

* fix(gateway): accept explicit channel ready recovery

* test(qa): assert terminal Slack block fact

* test(qa): restore Slack blocked lifecycle scenario

* test(gateway): lock explicit lifecycle recovery contract
2026-08-03 12:39:48 -07:00
Peter Steinberger c1686c9a84 fix(feishu): fence external collaboration tool results (#118877)
* fix(feishu): fence external collaboration tool results

* test(feishu): narrow bitable result content safely
2026-08-03 12:36:39 -07:00
Peter Steinberger 4c66ed5615 feat(channels): lifecycle wave 2 — fifteen more channels publish recorded lifecycle (#118298)
* feat(channels): publish lifecycle from existing status sinks

* feat(channels): thread lifecycle through provider monitors

* fix(mattermost): keep lifecycle status helper private

* fix(matrix): preserve terminal lifecycle during startup cleanup

* fix(matrix): reject invalid tokens during startup

* test(mattermost): drop unused vi import
2026-08-02 17:30:56 -07:00
Peter Steinberger dd97722e3e test(feishu): consolidate monitor lifecycle fixtures (#118273) 2026-08-02 16:13:45 -07:00
Peter Steinberger 8e7a24adb8 refactor(feishu): consolidate chat tool fixtures (#118234) 2026-08-02 16:04:17 -07:00
Peter Steinberger 1786a011df refactor(feishu): consolidate doctor state fixtures (#118238) 2026-08-02 16:02:06 -07:00
Peter Steinberger e7ce514f4e fix(feishu): deliver approved workspace attachments through plugin owners (#117778) 2026-08-01 21:24:04 -07:00
Peter Steinberger ccee629359 refactor(plugins): delete registry compat scaffolding (#117749)
* refactor(plugins): delete registry compat scaffolding

* test(plugins): update CLI registry handle mock

* fix(plugins): preserve explicitly initialized hook registries

* test(plugins): update registry ownership fixtures

* fix(channels): restore registry snapshot memo
2026-08-01 21:18:47 -07:00
Peter Steinberger 6c41f37417 fix(feishu): avoid 400s on topic reaction hydration (#117685)
* fix(feishu): hydrate reaction topics with real ids

Fixes #34528

* fix(feishu): scope topic hydration id for errors
2026-08-01 16:49:42 -07:00
Peter Steinberger 0e45b46889 refactor(feishu): deduplicate drive test fixtures (#117659) 2026-08-01 15:27:07 -07:00
zengLingbiao 1a0d3b5c40 fix(feishu): cancel unread streaming-card error bodies before release (#117312) 2026-08-01 12:26:27 -07:00
Peter Steinberger 568ea29d2e refactor(plugins): inherit shared package boundary settings (#117474) 2026-08-01 09:11:09 -07:00
Peter Steinberger a1f2fb45bc fix(feishu): restore custom HTTPS API domains (#117278)
Co-authored-by: Peter Steinberger <steipete@macos.shared>
2026-08-01 01:00:09 -07:00
Vincent Koc f5a8cb02ea test(release): repair full validation regressions (#116931)
* test(discord): mock thread delete listener

* test(qa): expect blocked update evidence

* test(telegram): preserve recovered context body

* fix(test): configure kitchen-sink personality

* test(browser): expect canonical staged upload paths

* test(browser): canonicalize macOS download roots

* test(feishu): seed legacy session rows offline

* test(telegram): isolate message context session stores

* test(qqbot): expect canonical media paths

* test(anthropic): match canonical transcript paths

* test(qa): expect canonical session store keys

* test(gateway): isolate rewind media reads

* test(release): review plugin child spawns

* test(plugins): expect process-stable manifest metadata

* test(google): retire usage telemetry contracts
2026-08-01 15:42:50 +08:00
Peter Steinberger ad3e36ef33 fix(feishu): unify outbound delivery lifecycle (#117223)
Co-authored-by: Peter Steinberger <steipete@macos.shared>
2026-07-31 23:16:04 -07:00
Peter Steinberger b521ce626b fix(feishu): consume implicit reply targets across media delivery (#117196)
Co-authored-by: Peter Steinberger <steipete@macos.shared>
2026-07-31 21:01:45 -07:00
Peter Steinberger 9e4381eb1c refactor(channels): unify bundled channel setup contracts (#117106)
* refactor(channels): canonicalize bundled setup contracts

* test(matrix): use scoped environment fixtures
2026-07-31 16:57:29 -07:00
Peter Steinberger 24a0401c3d fix(feishu): unify truthful delivery and media ownership (#117023)
* fix(feishu): preserve thread history and delivery contracts

* fix(feishu): route native images by verified content signatures

* fix(feishu): require authentic HEIC image signatures

* fix(feishu): retain accepted delivery when provider omits message ids

* fix(feishu): preserve accepted visibility across all delivery owners

* fix(feishu): recognize supported HEIC and TIFF local image paths

* test(feishu): prevent accepted-reply fixture state leaking between cases

* fix(feishu): preserve typed delivery contracts in CI

---------

Co-authored-by: Peter Steinberger <steipete@macos.shared>
2026-07-31 14:26:41 -07:00
Peter Steinberger 47a7798789 fix(feishu): preserve paginated reaction actors and topic ownership (#116918)
* fix(feishu): drain all message reaction pages

* fix(feishu): preserve reaction actor and topic ownership

* fix(feishu): support all valid reaction pages

---------

Co-authored-by: Peter Steinberger <steipete@macos.shared>
2026-07-31 08:49:34 -07:00
pash-openai e52354ea13 fix(build): pin typebox to a published release (#116333) 2026-07-30 09:58:51 +00:00
Vincent Koc 636d7705c4 fix(feishu): preserve source time in message envelopes (#116156) 2026-07-30 09:27:01 +08:00
metaforismo c868c81e91 fix(feishu): preserve card actions through mention gating (#116105)
* fix(feishu): preserve card actions through mention gating

* test(feishu): use structured card action fixtures
2026-07-29 17:07:42 -07:00
Peter Steinberger 11de91ad03 fix(qa): forward-port beta 6 validation fixes (#116065)
* test(macos): avoid busy-spin timeout fixtures

* fix(qa): forward-port beta 6 validation fixes

* test(qa): complete Telegram run options fixture
2026-07-29 16:21:04 -04:00
heichl_xydigit c40a9b15b0 fix(feishu): guard Object.assign against prototype pollution in webhook payload merge (#111729)
* fix(feishu): guard Object.assign against prototype pollution in webhook payload merge

Object.assign merges JSON.parse webhook payload into an Object.create target
without filtering `__proto__`, `constructor`, or `prototype` keys. A
crafted webhook body like `{"__proto__": {"polluted": true}}` would set
the `__proto__` property on the envelope object, enabling prototype
pollution on the target.

Replace Object.assign with explicit iteration that skips blocked keys, and
use Object.create(null) so the envelope itself has no prototype to pollute.
Matches the isBlockedObjectKey pattern used in core config paths.

* fix(feishu): preserve webhook envelope when filtering payloads

* fix(feishu): preserve webhook envelope when filtering payloads

---------

Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
2026-07-30 01:27:55 +08:00
Eden 601a405430 fix(channels): mark durable webhook acceptance on Zalo, Google Chat, SMS, Feishu, Nextcloud Talk, and Synology Chat (#115586)
* fix(channels): extend the durable-acceptance marker to zalo, googlechat, and sms

* fix(feishu): mark durable webhook acceptance

* fix(channels): extend the durable-acceptance marker to nextcloud-talk and synology-chat

* fix(channels): extend the durable-acceptance marker to zalo, googlechat, and sms

* fix(feishu): mark durable webhook acceptance

* fix(channels): extend the durable-acceptance marker to nextcloud-talk and synology-chat

* fix(channels): carry durable webhook admission results

* docs(changelog): note durable webhook acceptance

* test(channels): tighten webhook admission types

* chore: leave release changelog to release prep

---------

Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
2026-07-30 01:07:08 +08:00
Peter Steinberger d16e33e08e fix: restore trustworthy end-to-end QA and cross-channel delivery (#115404)
* fix(qa): repair verified end-to-end and channel regressions

* fix(gateway): make interrupted restart recovery lifecycle-safe

* test(heartbeat): target the canonical recovery session store

* fix(gateway): prioritize durable restart recovery before heartbeat

* fix(qa): preserve safe restart recovery and channel expiry

* fix(qa): fail closed and fence restart recovery

* test(agents): isolate restart recovery timing

* test(agents): prove actual restart retry timing

* fix(qa): report incompatible profile scenarios

* fix(scripts): resolve symlinked docker scheduler entrypoints

* fix(qa): require fresh native test evidence

* fix(heartbeat): fence active restart recovery delivery

* fix(gateway): consume untargeted restart acknowledgements

* fix(qa): satisfy exhaustive hosted validation gates

* fix(agents): fence stopped restart recovery dispatch

* style(agents): format restart recovery lifecycle regression

* test(gateway): isolate context prewarm sidecar lifecycle

* test(qa): make scenario process timeout cleanup deterministic

* fix(qa): stamp synthetic gateway configs with current version

* fix(openai): preserve vision capabilities in stale model catalogs

* test(qa): align profile channel rejection with current main

* fix(openai): forward supported moderation for image edits

* fix: restore latest-main CI and image edit documentation

* fix(qa): retain relocated code-mode evidence validation

* fix(openai): expose GPT-5.4 vision in static catalog

* fix(pricing): honor explicit model cost overrides

* test(pricing): keep isolated provider regressions deterministic

* fix(openai): inherit transport for discovered static models

* fix(gateway): honor agent-owned static image capabilities

* test(gateway): preserve prepared-snapshot attachment races

* test(gateway): isolate subagent persistence failure injection

* test(gateway): exercise concurrent voice replay admission

* fix(gateway): restore stale model image capabilities

* fix(agents): publish configured model vision capabilities

* fix(agents): isolate detached media transcript ownership

* test(agents): preserve generic transcript lock regression

* fix(gateway): require proven static model route identity

* fix(qa): accept bounded full-size generated image attachments

* fix(qa): require fresh script producer evidence

* test(qa): prove native E2E scenario execution
2026-07-29 12:45:27 -04:00
zw-xysk ebf9fcc02c fix(feishu): log message content JSON parse failures instead of silently swallowing (#107947)
* fix(feishu): log message content JSON parse failures instead of silently swallowing

Replace formatErrorMessage(err) with safe metadata-only logging in
parseFeishuMessageContent to prevent potential message content leaks
through V8 JSON.parse error messages.

Changes:
- Remove formatErrorMessage import (security: V8 JSON.parse errors can
  include input content in the message)
- Log only msgType and optional messageId (safe metadata) when parse
  fails, never the exception message or raw content
- Add assertion that raw content is NOT present in the log output
- Pass messageId through to enable richer diagnostics

The raw content is still preserved as the function return value (existing
fallback behavior).

* fix(feishu): move parse-failure test into getMessageFeishu suite

The test 'logs a safe diagnostic (not raw content) when message content
is not valid JSON' was declared after the closing brace of
describe('getMessageFeishu'), so it did not inherit that suite's fixture
setup and reset hooks (beforeEach/afterAll). Move it inside the suite
so it benefits from the shared mock reset and cleanup.

Fixes ClawSweeper P2: 'Keep the parse-failure test inside the fetch suite'

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-29 07:16:24 -04:00