Commit Graph

1035 Commits

Author SHA1 Message Date
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
Peter Steinberger fd1b965f2b refactor(plugins): remove orphan test API barrels (#121761)
* test(plugins): remove orphan test API barrels

* refactor(plugins): remove orphan test-only exports

* refactor(imessage): remove orphan test plugin

* test(plugins): remove stale package guard timeout
2026-08-10 16:42:34 -07:00
Ayaan Zaidi 4c951398ef fix(messages): keep runtime details out of chat alerts (#121600)
Keep raw commands, paths, and provider errors out of ordinary chat while preserving explicit raw diagnostics and structured admin history.

Default command progress is status-only; `/verbose full` and `commandText: "raw"` retain diagnostic detail.

Co-authored-by: Ayaan Zaidi <hi@obviy.us>
2026-08-10 21:37:48 +05:30
Pavan Kumar Gondhi d85f5c1176 fix(msteams): fail closed on denied group access (#121086) 2026-08-10 10:39:22 +05:30
Peter Steinberger 3bdfd60caa fix(media): accept mixed-case local file URLs (#121226) 2026-08-09 16:40:55 -07:00
Peter Steinberger c2e7c819f5 perf(doctor): slim remaining heavy doctor contract closures (#120811)
* perf(doctor): slim remaining heavy doctor contract closures

Follow-up to #120698: several doctor closures still cold-loaded multi-second
kysely-bearing graphs through other broad barrels (session-store-runtime,
realtime-voice, channel-outbound, logging-core, memory-host-core/-events,
sqlite-runtime, persistent-dedupe, and plugin-local barrels).

- lazy-import heavy helpers inside async migration bodies (codex, msteams,
  zalouser, workboard, matrix inbound-dedupe, memory-core migrations)
- bypass plugin-local barrels to defining modules (reef protocol,
  memory-core short-term-promotion)
- move to lighter existing subpaths (slack -> channel-streaming, matrix
  logger -> security-runtime, memory-wiki -> agent-scope-runtime, which now
  also exports resolveSessionAgentId)
- add narrow openclaw/plugin-sdk/realtime-voice-activation for discord's
  sync wake-name doctor rules
- split src/infra/kysely-sync-cache-state.ts so sqlite-transaction clears
  Kysely caches without value-loading kysely; split the memory-host-sdk
  kysely bridge off the schema/transaction bridge
- guard: forbid the heavy barrels in doctor closures with per-kind scoping

Cold enumeration per plugin: discord 52.6s->0.3s, msteams 30.9s->0.5s,
codex 29.6s->2.6s, zalouser 28.8s->2.3s, matrix 27.2s->3.2s,
slack 17.5s->1.5s, reef 9.9s->0.7s, memory-core 6.4s->3.6s,
workboard 3.4s->0.25s; all kysely-free except llm-task (named follow-up).

* fix(plugins): route slack streaming compat through a focused streaming-config subpath

The channel-streaming compat barrel is deprecated for extension production
code (deprecated-api-usage guard + SDK package contract). Add the narrow
non-deprecated openclaw/plugin-sdk/channel-streaming-config subpath for the
pure streaming config readers, and drop the now consumer-less
short-term-promotion barrel re-exports knip flagged.

* test(plugins): register memory-host-sdk kysely bridge in package boundary inventory

* fix(plugins): classify realtime-voice-activation as private-local

ClawSweeper P2: the subpath exports only a default target, which is the
private-local shape; register it in plugin-sdk-private-local-only-subpaths,
the package-boundary d.ts alias maps, and correct the public surface budgets
(realtime-voice-activation no longer counts as public).

* fix(release): exclude realtime-voice-activation declarations from the published package

Private-local subpaths ship without d.ts; register the files negation the
release pack-path check requires.
2026-08-08 20:28:58 -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
Peter Steinberger 10e60fa0ce refactor(plugins): shared legacy-state doctor migration and simple secret contracts (#120346)
* refactor(plugins): share legacy JSON doctor migration

* refactor(discord): share account token inspection cascade

* refactor(plugins): share simple channel secret contracts

* refactor(discord): keep token inspector private
2026-08-07 13:55:31 -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
Vincent Koc 5f585a57bd test(msteams): cover occupied webhook port (#120158)
Punchcard-Session: silver-willow-harbor-px
2026-08-07 13:46:41 +08:00
Peter Steinberger 9aa24e8f2e refactor(test): replace logic-bearing vi.mock factories with boundary fakes, batch 2 (#120117)
* refactor(test): exercise real Teams monitor lifecycle

* refactor(test): use real gateway lifecycle state

* refactor(test): use real restart delivery queue

* test: type Teams SDK boundary fixture
2026-08-06 22:02:50 -07:00
Peter Steinberger c663c39763 refactor(test): table-drive exact-duplicate test blocks, batch 2 (#120071)
* refactor(test): table-drive tooling test cases

* refactor(test): table-drive agent test cases

* refactor(test): table-drive core test cases

* refactor(test): table-drive plugin test cases

* refactor(test): table-drive package test cases

* chore(test): prune max-lines baseline

* fix(test): preserve table row literal types
2026-08-06 17:00:28 -07:00
Alix-007 819f92bba5 fix(msteams): reject malformed OAuth token envelopes [AI-assisted] (#111638)
* fix(msteams): reject malformed OAuth token envelopes

* refactor(msteams): reuse canonical record guard
2026-08-06 03:57:33 +00:00
Peter Steinberger 1f0269eda5 refactor(msteams): consolidate channel action target resolution (#119632)
* refactor(msteams): consolidate channel action target resolution

* fix(msteams): honor configured group read policy

* fix(msteams): explain delegated channel access recovery
2026-08-05 10:52:13 -07:00
Peter Steinberger 2d1242556e test(msteams): serve JWKS from in-process server in auth coverage (#119354)
* test(msteams): serve JWKS from in-process server in auth coverage

The Entra/service-token validator tests spied JwksClient.prototype on the
jwks-rsa copy the test file imports, but the SDK's internal
require("jwks-rsa") resolves a different physical copy and vitest cannot
intercept a CommonJS require inside node_modules — so the spy missed and
the tests hit the real login.botframework.com / login.microsoftonline.com
JWKS endpoints (JwksError: Bad Request, SigningKeyNotFoundError).

Replace the mock with a real JWKS document served from an in-process
node:http server, pointed at via the SDK's own endpoint overrides
(openIdMetadataUrl cloud override for the service validator, loginEndpoint
for the Entra factory). The v2-issuer acceptance test drives the underlying
JwtValidator with a decoupled jwksUriOptions {type:'uri'} so issuer
validation uses the real login host while keys come from the local server.
Deterministic, no external network, and exercises the real fetch + RS256
verify path.

* test(msteams): fix cloud-environment import and drop unused jwks-rsa

The extensions test-types gate resolves @microsoft/teams.api's dual
.d.ts/.d.mts types strictly and does not see the root re-export of
withOverrides/PUBLIC (TS2305), so import them from the canonical
auth/cloud-environment subpath the SDK itself uses. The JWKS-server rework
also removed the last direct jwks-rsa import, so drop the now-unused
devDependency and refresh the lockfile (knip deadcode).

---------

Co-authored-by: Peter Steinberger <steipete@mac-studio-sf2.local>
2026-08-04 15:34:38 -07:00
Peter Steinberger 467492b125 fix(msteams): enforce documented AAD owner approval principals (#118967) 2026-08-03 14:24:30 -07:00
Peter Steinberger be9a34a79d fix(msteams): enable channels for federated environment credentials (#118931) 2026-08-03 13:57:08 -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 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 15560382a2 test(msteams): consolidate Graph upload fixtures (#118268) 2026-08-02 16:15:17 -07:00
Peter Steinberger 6c29fc154f test(msteams): avoid hanging response clones (#118096)
Co-authored-by: Peter Steinberger <steipete@mac-studio-sf2.local>
2026-08-02 11:04:38 -07:00
Peter Steinberger a154b4faea refactor: consolidate Teams and error helpers (#117907) 2026-08-02 02:02:17 -07:00
zengLingbiao 83c6a51b0e fix(msteams): cancel unread Graph error response bodies (#117664)
* fix(msteams): cancel unread Graph error response bodies

* fix(msteams): release every guarded Graph response safely

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-08-02 17:01:30 +08:00
Peter Steinberger ac28f4d558 fix: release channel delivery resources reliably (#117855)
* fix(channels): consolidate delivery lifecycle ownership

* test(msteams): match release mock contract

* test(plugin-sdk): satisfy promise executor lint

* chore(plugin-sdk): regenerate API baseline for delivery-correlation + fetch-runtime exports
2026-08-02 00:24:47 -07:00
Peter Steinberger 996b1e1e86 refactor(plugins): remove oauth pass-through wrappers (#117867) 2026-08-01 23:28:59 -07:00
Jiatai Wang bacc5071db fix(msteams): rename SharePoint uploads on name conflict (#113560)
Bot-generated files reuse names (openclaw runtime emits image-1.png every
generation), so Graph's default conflictBehavior=replace overwrote the prior
same-named driveItem in place. Because Teams caches file cards by driveItem
URL, channels kept showing the stale file and earlier content was lost from
OpenClawShared.

Force @microsoft.graph.conflictBehavior=rename on the simple upload so
SharePoint mints a uniquely-named driveItem (fresh name/eTag/URL) on
collision. The existing getDriveItemProperties re-read by item id already
surfaces the new name/URL to the Teams file card, so no downstream change is
needed.

Closes #112368

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Peter Steinberger <steipete@macos.shared>
2026-08-01 22:59:44 -07:00
Peter Steinberger d6e537a859 refactor(channels): share persistent state error reporting (#117813) 2026-08-01 22:06:25 -07:00
Peter Steinberger e98fdeefdf refactor(errors): consolidate message formatting (#117818) 2026-08-01 22:05:49 -07:00
Peter Steinberger a084763814 fix(msteams): deliver approved workspace attachments across send paths (#117776) 2026-08-01 21:07:52 -07:00
Peter Steinberger 17625e5cd2 fix(msteams): preserve thread targets for structured sends (#117516) 2026-08-01 10:07:22 -07:00
Peter Steinberger 568ea29d2e refactor(plugins): inherit shared package boundary settings (#117474) 2026-08-01 09:11:09 -07:00
Ahmed Tarek 730cf56915 fix(msteams): prevent duplicate final replies (#116398)
* fix(msteams): preserve message-tool thread routing

Co-authored-by: Vincent Koc <vincentkoc@ieee.org>

* test(msteams): prove thread-aware final dedupe

* fix(agents): suppress duplicate source previews

* fix(agents): dedupe current-source reply previews

---------

Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
2026-08-01 15:32:56 +08:00
Vincent Koc 6922ddd936 fix(qa): isolate runner discovery facades (#117203) 2026-08-01 13:40:11 +08: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
Vincent Koc a3220af4aa chore(msteams): add private Gateway QA adapter
Add the reusable private-build Microsoft Teams Gateway QA adapter with loopback-only ingress, exact-origin connector routing, and packaged runtime coverage. Exact-head CI, Testbox changed gate, real Gateway channel canary, autoreview, and ClawSweeper disposition are complete.
2026-08-01 06:14:50 +08:00
Peter Steinberger c572982556 fix(channels): preserve actionable presentation fallbacks (#116990)
* fix(channels): preserve actionable presentation fallbacks

* test(interactive): isolate presentation fallback regression coverage

---------

Co-authored-by: Peter Steinberger <steipete@macos.shared>
2026-07-31 12:37:30 -07:00
joshavant 12b9e7c683 test(msteams): satisfy async lint 2026-07-30 14:20:11 -05:00
joshavant 834559d043 fix(msteams): settle stopped stream replacements 2026-07-30 14:20:11 -05:00
joshavant c659c21672 fix(msteams): preserve acknowledged stream settlement 2026-07-30 14:20:11 -05:00
pash-openai e52354ea13 fix(build): pin typebox to a published release (#116333) 2026-07-30 09:58:51 +00:00
Ayaan Zaidi c63241d3ce fix(channels): resolve tool progress against the caller's stream mode
resolveChannelStreamingPreviewToolProgress guessed a mode when streaming.mode
was unset, so it could never be right for every channel: guessing "partial"
dropped Discord and Telegram's explicit progress.toolProgress opt-out, and my
earlier switch to "progress" broke it the other way for Slack, Mattermost, and
Teams, whose real default is partial. With both keys configured and disagreeing,
the wrong one won.

The helper has no channel identity, so it stops guessing and takes the mode the
caller already resolved. All nine call sites pass theirs. Omitting it keeps the
previous configured-mode reading, so untouched callers behave exactly as before.

Reported by ClawSweeper on #116143.
2026-07-30 13:36:21 +09:00
Vincent Koc 18e107f494 fix(plugins): report request timeouts for stalled response bodies (#116166)
* fix(openai): preserve device-code request timeouts

* fix(msteams): preserve SharePoint upload timeouts

* fix(qqbot): preserve channel API request timeouts
2026-07-30 10:03:39 +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
Peter Steinberger 5bfc65d7f4 refactor: remove 3,543 lines of redundant runtime and tests (#115961)
* refactor: remove 3,543 lines of redundant runtime and tests

* refactor: ratchet production environment variable budget
2026-07-29 11:43:41 -04:00