Commit Graph

1214 Commits

Author SHA1 Message Date
Peter Steinberger
08b1ff73e2 refactor(channels): fix account resolution and setup isolation (#114395)
* refactor(channels): fix account resolution and setup isolation

* fix(channels): keep account resolvers safely destructurable
2026-07-27 03:49:37 -04:00
Jesse Merhi
d7627d6f4c refactor(prompt): use plain inbound context labels and drop system-tag sanitizer (#112000)
* refactor(prompt): plain inbound context labels with a provenance marker

Replaces trust-worded inbound context labels ("(untrusted metadata)",
"(untrusted, for context)") with plain labels plus a fixed provenance
marker suffix appended to every OpenClaw-injected context header.

Detection keys on the marker, not label text, so strippers stay correct
across UI, TUI, replay, /trace segmentation, memory recall, and the Swift
chat preprocessor. Drops sanitizeInboundSystemTags in favor of the marker
boundary plus trusted system-prompt narration.

Renames the untrusted-named plugin SDK context identifiers to
channel-provenance names, keeping deprecated aliases registered for
removal after 2026-09-08.

Adds `openclaw doctor --fix` migrations that rewrite legacy inbound
labels in stored SQLite transcripts and purge legacy envelope-
contaminated LanceDB recall rows.

* fix(ci): resolve gate failures for plain inbound context labels

- doctor sqlite readers: open read-only connections via openNodeSqliteDatabase
  so the Kysely connection-boundary guardrail holds; unexport the now-internal
  transcript snapshot type (Knip unused-export gate).
- compat registry: split the record table into registry-records.ts and
  plugin-sdk-subpath-records.ts. The new compat record pushed registry.ts past
  the 700-line oxlint cap; suppressions are disallowed, so follow the existing
  sibling record-module pattern. Public exports and PluginCompatCode literals
  unchanged.
- acp-runtime test: assert current finalization behavior (newline normalization
  only). The bracket de-fang and System: rewrite it expected were removed with
  sanitizeInboundSystemTags; forged system lines are neutralized at the
  system-event queue, the single chokepoint feeding the System:-per-line render.
- regenerate docs_map and the plugin SDK API baseline manifest.

* fix(prompt): harden inbound context label migration and drop in-band sanitizer

Review follow-ups on the plain-label + provenance-marker change:

- Remove src/security/system-tags.ts. Rewriting inbound text to neutralize
  look-alike `System:`/`[System]` markers corrupted legitimate user text and is
  not a real injection boundary; role separation plus external-content wrapping
  is. Explicit product decision, recorded at the system-event queue.
- Narrow the LanceDB legacy-row purge so it cannot delete benign memories. It
  now requires a complete known legacy sentinel line, a legacy label followed by
  a fenced JSON body, or the complete legacy external-content header. The prior
  predicates matched ordinary prose such as `Notes (untrusted metadata):`, and
  deletion is irreversible.
- Make explicit-empty canonical ChannelStructuredContext win over the deprecated
  alias via a present/absent result instead of collapsing `[]` to undefined.
- Keep `\r?` in the active-memory doctor rule. It is the only rule spanning the
  header's line break, migrated assistant rows skip newline normalization, and
  without it the marked-header replace wins and the body strips to empty. Added
  a CRLF regression test.
- Fix stale comments that described removed behavior, and cover the Swift
  prose-block strip path.

Claude-Session: https://claude.ai/code/session_01WNzsPddQmxy9Y7jKD4wAxH
2026-07-27 11:27:53 +10:00
Peter Steinberger
9eae43bd37 refactor(infra): move exec approvals into the shared SQLite state DB (#114063)
* refactor(infra): move exec approvals into the shared SQLite state DB

Delete the file-runtime exec-approvals store (exec-approvals.json + .lock
sidecar machinery) on both runtimes and make the reserved
exec_approvals_config singleton row canonical. Doctor owns the one-time
import with claim/verify/receipt discipline; runtime fails closed with a
doctor instruction while un-migrated legacy state exists. The wire CAS
contract, socket semantics, and gateway auth-token derivations are
unchanged. Kills the #113929 lock-contention bug class structurally and
nets around -2.9k lines.

* fix(infra): green CI gates and retire file-era exec approvals tests

Break the migration-type import cycle with a leaf contract, regenerate the
plugin-SDK API and native i18n baselines for the intentional surface change,
drop unused exports, and replace the macOS file-era approvals test suite with
SQLite-backed behavior coverage per the obsolete-internals test policy.

* chore: green max-lines ratchet, native i18n baseline, and unused-export scan
2026-07-26 06:39:23 -04:00
Peter Steinberger
5347285d6b improve(models): source pricing from hosted catalog (#114060)
* feat(model-catalog): serve hosted fallback pricing

* refactor(config): retire client pricing bootstrap settings

* refactor(gateway): delete client pricing refresh runtime

* docs(models): explain hosted catalog pricing

* fix(model-catalog): preserve pricing privacy and aliases

* fix(model-catalog): fingerprint pricing eligibility

* fix(model-catalog): harden pricing endpoint checks

* fix(model-catalog): materialize source-safe pricing aliases

* fix(model-catalog): keep unknown pricing fallbacks safe

* fix(model-catalog): reject zero-only hosted prices

* fix(model-catalog): fail closed without pricing policy metadata

* refactor(utils): extract usage pricing normalization

* fix(model-catalog): rebuild policy-owned pricing namespaces

* test(model-catalog): type publisher cost fixtures

* chore(config): regenerate schema baselines

* fix(utils): keep raw pricing tiers private
2026-07-26 03:48:25 -04:00
Peter Steinberger
2de58d408a Control UI: gateway-owned sidebar section order (#113930)
* feat(ui): gateway-owned sidebar section order with hover-only drag grips

* fix(ui): repair sidebar section order CI gates

* fix(protocol): keep sectionOrder optional for older gateways

Native Swift clients ship separately from gateways, so new clients must decode older gateway responses that omit sectionOrder.

* fix(ui): reconcile gateway section ordering with main

* fix(state): allow lazy tables in v5 maintenance

* refactor(ui): retire prefs session section order in favor of gateway-owned order

Supersedes #113948 by deleting the unreleased ui.prefs.sessionSectionOrder key and its browser plumbing. Gateway SQLite sidebar_sections remains the single canonical store.
2026-07-26 01:15:19 -04:00
Peter Steinberger
f90cef67c8 feat(ui): drag custom sidebar groups between built-in session zones (#113948)
* feat(ui): drag custom sidebar groups between built-in session zones

* test(ui): remove stale split ratio fixture

* perf(ui): raise startup budget baseline for session-section ordering pref
2026-07-25 19:11:25 -07:00
Peter Steinberger
d7ef7fc5a6 refactor(config): promote planTool to canonical tools.updatePlan (#113958)
The update_plan checklist tool has been default-on with no model gating for a
while, so keeping it under tools.experimental misrepresented it and kept a
container key alive for a single boolean. Rename it to a plain boolean
tools.updatePlan (camel-cased tool id, matching tools.agentToAgent and
tools.toolSearch), keeping the !== false default-on semantics.

The strict schema rejects the retired key, so openclaw doctor --fix now lifts
tools.experimental.planTool to tools.updatePlan and deletes the emptied
container. Registration also drops five parameters that were never read
(agentSessionKey, agentId, modelProvider, modelId, pluginToolAllowlist).

Docs: config-tools.md dropped a stale claim that the tool defaults off behind a
strict-agentic GPT-5 rule that no longer exists, experimental-features.md no
longer lists the tool and now cites the real Codex app-server floor (0.143.0,
per MIN_CODEX_APP_SERVER_VERSION).

Config baseline core count drops 2307 -> 2306.
2026-07-25 18:31:23 -07:00
Peter Steinberger
ddd3d4fdb3 refactor(agents): split before-tool-call policy pipeline (#113885)
* refactor(agents): split before-tool-call pipeline

* refactor(agents): isolate before-tool call types

* fix(agents): restore approval resolution type import
2026-07-25 15:59:30 -07:00
Peter Steinberger
bde7033ac4 feat(models): dynamic model catalogs via hosted refresh overlay (#113660)
* feat(models): add remote catalog core

* feat(config): add model catalog refresh settings

* feat(models): wire remote catalog refresh

* ci(models): publish hosted catalog

* docs(models): document catalog refresh

* test(models): allow catalog count growth

* refactor(models): preserve safe catalog merge

* ci(models): publish catalog through GitHub

* docs(models): link public catalog history

* fix(model-catalog): enforce Kysely store access

* fix(model-catalog): trim unused catalog exports

* docs(models): refresh generated docs map
2026-07-25 12:15:05 -07:00
Peter Steinberger
481d826ff4 fix(vault): prevent insecure secrets plan writes (#113707)
* fix(vault): harden secrets plan writes

* fix(secrets): avoid env marker collision

* style(secrets): type plan write rejection

* refactor(onepassword): remove obsolete path resolver

* fix(secrets): preserve Windows plan path trust

* refactor(secrets): compact ACL token policy

* fix(secrets): route permission checks through facade
2026-07-25 08:27:33 -07:00
Peter Steinberger
4bfb26415a feat(agents): explicit per-surface agent targets + default-role materialization (#113637)
* refactor(agents): add explicit ambient target seams

* fix(doctor): materialize ambient default-agent roles

* fix(agents): satisfy dependency and docs checks

* chore: leave agent release note to release process

* test(agents): prove shared heartbeat fan-out survives doctor
2026-07-25 05:37:41 -07:00
Peter Steinberger
b06f40a821 refactor(plugin-sdk): share ingress lifecycle fan-in (#113648)
* refactor(channels): share ingress lifecycle fan-in

* chore(plugin-sdk): refresh ingress API baseline
2026-07-25 05:34:35 -07:00
joshavant
f153858045 fix(onepassword): make SecretRef setup production-safe 2026-07-25 06:03:30 -05:00
Peter Steinberger
902cc53279 refactor: batch of independent dedup wins (#113535)
* refactor(config): reuse session parent fork types

* refactor(channels): reuse setup adapter type

* refactor(discord): share model preference primitives

* refactor(whatsapp): share reaction eligibility

* test(auto-reply): deduplicate dispatch scenarios

* test(scripts): share scenario fixtures

* test: share process and registry fixtures

* test: satisfy dedup fixture lint

* fix(plugin-sdk): keep setup adapter contract acyclic
2026-07-25 02:56:05 -07:00
Vincent Koc
3af03aee6c refactor(approvals): share native target resolvers (#113568) 2026-07-25 16:23:14 +08:00
Peter Steinberger
d2b6573690 refactor(channels): remove v2026.7.2-gated compat (flat streaming keys, group intro hint) (#113533)
* refactor(channels): remove flat streaming compat

maintainer-approved early removal of v2026.7.2-gated compat

* refactor(channels): remove group intro hint adapter

maintainer-approved early removal of v2026.7.2-gated compat

Plugin SDK surface baseline update is maintainer-approved for this intentional removal.
2026-07-25 01:09:25 -07:00
Peter Steinberger
a5d758e74b refactor(plugin-sdk): share channel DM policy setup (#113537) 2026-07-25 01:00:53 -07:00
Peter Steinberger
e069b9dbdd fix(ui): repair settings titles, scope form-unsafe banner, consolidate advanced settings (#113160)
* feat(ui): repair settings titles, scope form-unsafe banner, consolidate advanced tier

- Advanced/Notifications settings headers rendered raw i18n keys
  (tabs.advanced/tabs.notifications); configPageTitle now resolves through
  the nav registry titleForRoute, deleting the drifting key map.
- Form-unsafe banner is value-aware (only when the user's config has a value
  at a form-unsupported path in the active scope), names the paths, offers an
  Open Raw editor action, and sits in the content column instead of full-bleed.
- Advanced tier collapses to one synced toggle: hidden advanced fields render
  a ghost row that enables the toggle; the Advanced page always reveals and
  hides the toggle; per-section details state and the controlled-open dance
  are deleted; toggle visibility mirrors the renderer's tier split.
- schema.tags no longer tags facet-less paths as "advanced" (common fields
  like update.channel wore a lying chip); the chip is no longer rendered in
  form rows while tag:advanced search keeps working.

* fix(config): dev bootstrap writes canonical agents.entries; finish stale agents.list sweep

- openclaw gateway run --dev failed on a fresh state dir: the bootstrap wrote
  the retired agents.list array and validation rejected its own config
  (Unrecognized key: list). It now writes the keyed agents.entries record;
  new dev.test.ts validates the written shape against the zod schema.
- Revive the dead gateway hot-reload rule: prefix agents.list never matched
  canonical config diffs, so per-agent heartbeat edits fell through to the
  agents:none tail rule; the rule now matches agents.entries.
- config set replacement protection moves from the dead agents.list array
  to the agents.entries map (joins plugins.entries/auth.profiles family).
- Sweep remaining stale agents.list config-path strings in hints, fix-it
  messages, elevated gates, doctor hints, audit text, and type docs to
  agents.entries.*; RPC ids, the internal list projection, and doctor
  legacy-migration references intentionally keep the old name.

* test(ui): derive nav i18n audit from route registry; fix stale bootstrap hint assertion

- Knip flagged navigationCopyEntries (test-only export); the audit now walks
  ALL_ROUTES through prod titleForRoute/subtitleForRoute and rejects raw
  dotted-key output, so no export exists solely for the test.
- commands-context-report expected the retired agents.list[] hint wording.

* fix(config): align rebase resolution with main's roster-aware diagnostic

- tool-policy-diagnostic: keep main's test expectations (dotted
  agents.entries.<id> paths from the roster-aware implementation); our
  pre-rebase bracket-style assertions no longer match any code.
- Reapply the placeholder sweep the conflict resolution dropped:
  generic agents.list[] fallbacks in tool-policy-diagnostic and the audit
  sandbox-mode hint now say agents.entries.*.
2026-07-25 00:51:57 -07:00
Peter Steinberger
82d1a03f25 refactor(agents): move implicit-main fallback into load-time roster injection (#112678)
* refactor(agents): require explicit roster defaults

* feat(onboard): create named first roster agent

* refactor(agents): remove runtime main fallbacks

* style(agents): apply roster refactor formatting

* refactor(agents): finish roster-only runtime sweep

* fix(doctor): migrate legacy main session sqlite

* fix(doctor): harden roster session migrations

* fix(onboard): commit first agent atomically

* fix(config): support empty-roster analysis

* fix(agents): preserve legacy main state during creation

* fix(setup): materialize baseline agent roster

* fix(agents): harden legacy default transfer recovery

* fix(agents): simplify roster-only legacy compatibility

* fix(agents): preserve staged first-agent entries

* fix(config): migrate persisted implicit-main rosters

* fix(config): preserve staged empty rosters

* fix(agents): finalize roster-only upgrade paths

* fix(sessions): close legacy main migration outcomes

* fix(config): migrate legacy roster markers at load

* fix(sessions): preserve roster upgrade history

* refactor(sessions): restore lean legacy main compatibility

* fix(setup): prepare first-agent credentials before publish

* fix(config): stabilize roster snapshot migration

* refactor(sessions): shrink legacy main compatibility

* fix(agents): restore roster compatibility fidelity

* fix(sessions): preserve divergent legacy history

* refactor(agents): narrow roster-only scope

* fix(config): isolate roster migration

* test(agents): align roster-only fixtures

* fix(agents): keep main agent undeletable

* fix(agents): harden roster migration invariants

* fix(agents): close setup and audit scope gaps

* fix(cron): scope session reaper throttles by agent

* fix(agents): preserve scoped owner precedence

* fix(config): preserve authored config ownership

* fix(setup): keep default workspace and roster in sync

* fix(setup): preserve default entry workspace on bare runs

* fix(agents): adapt roster rebase to keyed entries

* fix(agents): honor both roster representations

* fix(agents): route roster reads through shared helpers

* fix(config): preserve canonical roster writes

* fix(cron): resolve dynamic default for session reaper

* fix(agents): close dynamic default migration gaps

* fix(agents): align scoped session ownership

* fix(sessions): preserve legacy main directory casing

* fix(agents): align cron and legacy auth ownership

* fix(setup): provision the committed default workspace

* fix(cron): align scoped ownership and reaping

* fix(cron): treat blank agent ids as absent

* fix(cron): retain configured session-store owners

* fix(agents): repair roster-aware CI boundaries

* fix(cron): preserve scoped ownership resolution

* fix(agents): preserve rosterless maintenance paths

* fix(agents): propagate roster ownership through runtime boundaries

* fix(agents): preserve roster ownership across runtime paths

* fix(agents): harden roster diagnostics and legacy routing

* fix(agents): remove redundant diagnostic import

* test(agents): type CLI policy fixture explicitly

* fix(config): preserve canonical roster mutation identity

* fix(doctor): read canonical agent rosters consistently

* fix(config): resolve compound roster unsets safely

* fix(config): finalize main-session reconciliation

* fix(doctor): read canonical session state safely

* fix(sessions): preserve current visibility alias

* fix(config): track roster include provenance

* test(config): type roster provenance cases

* fix(config): refine roster include ownership

* fix(agents): preserve staged roster invariants

* test(config): align fixtures with explicit roster ownership

* test(node-host): preserve optional plan typing

* fix(config): preserve authored roster projections

* test(config): keep raw roster fixtures explicit

* test(config): normalize rosters at runtime fixtures

* fix(config): protect authored roster ownership

* fix(agents): require explicit session ownership

* fix(agents): enforce scoped roster ownership

* fix(sessions): merge fixed-store agent partitions

* fix(agents): harden roster ownership boundaries

* fix(config): reject ambiguous roster projections

* fix(sessions): preserve persisted store ownership

* fix(sessions): keep collision diagnostics additive

* fix(security): scan malformed roster workspaces

* test(config): align snapshot fixtures after rebase

* test(agents): use explicit roster fixtures

* fix(config): harden roster diagnostic boundaries

* fix(sessions): isolate fixed-store agent databases

* test(agents): type malformed default markers

* refactor(sessions): extract store collision resolution

* test(system-agent): split oversized setup coverage

* style(system-agent): format split setup suite

* fix(sessions): preserve promoted store ownership

* fix(sessions): derive scoped owner before target

* fix(sessions): preserve explicit sqlite ownership

* fix(agents): restore roster compatibility across CI

* fix(agents): enforce roster-owned runtime boundaries

* fix(agents): satisfy default lookup lint

* test(sessions): split known-owner coverage

* fix(state): satisfy path identity lint

* fix(agents): preserve malformed roster safety boundaries

* fix(agents): restore roster compatibility at runtime boundaries

* fix(config): satisfy roster boundary type checks

* fix(agents): preserve roster ownership across runtime probes

Setup inference probes now execute as the configured roster owner. Malformed agent-prefixed session rows are intentionally omitted by the fail-closed visibility contract rather than normalized by tests.

* fix(agents): satisfy session list owner lint

* fix(agents): preserve roster-owned runtime boundaries

Restore shared logical rows for exact SQLite session locators while keeping their physical database owner separate. The ownership regression test now constructs an explicit sole-owner database directly instead of relying on first-touch capture, matching the intentional shared-store contract.

* fix(sessions): preserve multiply owned exact stores

* fix(sessions): restore runtime owner boundaries

Keep incognito sentinels agent-owned, fold default-agent approvals into the global snapshot, and preserve the configless legacy-main CLI policy fallback. Also repair the existing CLI watchdog test lifecycle so the compact shard observes its timeout without an unawaited assertion or async timer stall; product behavior is unchanged by that test-only fix.

* test(ci): align owner-scoped fixtures

These assertions are unchanged. The fixtures now declare the intended non-default runner, expose the session-key constant imported by production status code, and select the main approvals bucket explicitly on Windows.

* fix(agents): close final roster ownership gaps
2026-07-24 22:38:09 -07:00
joshavant
66a75bb9e5 fix(channels): unify routed outbound hook ownership 2026-07-24 20:05:30 -05:00
Jason (Json)
ee606def49 fix(codex): stop Computer Use readiness stalls across fallbacks (#113393)
* fix(codex): bound computer use readiness preflight

* chore(codex): keep service status internal
2026-07-24 14:27:53 -06:00
Peter Steinberger
1e9d918037 feat(sdk): always persist media facts and ship facts-first replacements for legacy Media* surfaces (#113355)
* feat(sdk): always persist media facts and ship facts-first replacements for legacy Media* surfaces

PR 1 of the media legacy retirement program (audit-frozen, 4 PRs).

- Every media-bearing user turn now persists normalized __openclaw.media
  facts unconditionally while continuing to emit the legacy top-level
  Media* projection byte-identically (dual-write bridge; the conditional
  shouldPersistStructuredMediaEntries gate now always includes media).
- New replacement APIs, shipped before any removal: typed hook media
  facts (media[], originalMedia[], mediaStagingPending) on message
  events; {{AttachmentPath}}/{{AttachmentUrl}}/{{AttachmentContentType}}/
  {{AttachmentDir}}/{{AttachmentIndex}} template variables; focused
  openclaw/plugin-sdk/media-local-roots subpath split out of the
  deprecated agent-media-payload facade.
- Every legacy surface carries @deprecated naming its replacement, under
  one named compatibility record media-legacy-projection with the
  operator-approved removeAfter 2026-10-01 (two release trains; deletion
  additionally gates on a clean published-plugin artifact sweep).
- Generic transcript append invariant documented; SDK migration, hooks,
  and configuration docs updated to the facts-first path.

Writer golden matrix proves legacy bytes and model prompt bytes are
unchanged while nested facts become unconditional. 2,189 broad media
tests green; SDK api-baseline regenerated on fresh-env Testbox.

* feat(sdk): register media-local-roots subpath exports and deprecation metadata

Completes PR 1: package export map for openclaw/plugin-sdk/media-local-roots
plus the deprecated-subpath inventory and doc metadata entries for the
media-legacy-projection record.

* chore(sdk): track media-local-roots entrypoint and deprecated-export budgets

* fix(sdk): keep deprecated MSTeams buildMediaPayload re-export through the compat window

Deleting shipped runtime-api re-exports belongs to retirement PR 4 after
the media-legacy-projection window; PR 1 only deprecates. Also formats
the migration-guide schedule table.

* docs: regenerate docs map for media migration additions
2026-07-24 10:42:17 -07:00
Peter Steinberger
73bba03e4c refactor: canonicalize session delivery state (#113225)
* refactor: canonicalize session delivery state

* test: canonicalize reply persistence fixtures

* test: canonicalize talk delivery fixtures

* test: canonicalize voice session routes

* test: canonicalize attachment delivery fixtures

* test: migrate gateway delivery fixtures

* fix: skip invalid session delivery rows

* test: align delivery SDK surface gates

* fix: preserve legacy delivery precedence

* test: canonicalize heartbeat delivery fixtures

* fix: preserve delivery route prompt identity

* test: canonicalize session delivery fixtures

* fix: preserve recoverable legacy delivery routes

* fix: canonicalize remaining session state

* fix: preserve canonical session classification

* style: format delivery state changes

* test: refresh plugin SDK delivery baseline

* test: avoid mutating session fixture input

* style: simplify delivery identity check

* style: simplify delivery origin spread

* fix: preserve fresh delivery route metadata

* test: assert canonical surface route switch

* fix: canonicalize doctor file-store imports

* fix: preserve transitional delivery migration state

* fix: satisfy canonical delivery CI gates

* ci: scope GitHub App token permissions

* test: infer canonical delivery projections

* test: canonicalize ACP requester delivery fixtures

* test: canonicalize harness rollback fixture

* style: apply pinned formatter
2026-07-24 01:01:19 -07:00
Jason (Json)
aee46707ba feat(plugins): support manifest-declared MCP Apps in native plugins (#113224)
* feat(plugins): load native manifest MCP servers

* fix(gateway): advertise proxied plugin surface ports

* fix(codex): retain MCP App transcript previews

* fix(codex): render native MCP apps inline

* fix(mcp-apps): resolve harness-native views by session

* fix(codex): normalize null MCP result metadata

* fix(ui): give inline MCP apps full message width

* test(codex): use generic native MCP App fixtures

* chore(plugin-sdk): refresh harness runtime baseline

* refactor(codex): isolate native MCP App contracts

* fix(codex): satisfy native app CI contracts

* fix(ci): scope automation app tokens

* chore(ci): defer token scopes to current main
2026-07-24 01:43:48 -06:00
Vincent Koc
5ff16901ef refactor(browser): reuse shared error coercion (#113229) 2026-07-24 13:58:29 +08:00
Peter Steinberger
61f036f748 refactor(agents): close embedded attempt terminal outcomes (#113201)
* refactor(agents): close embedded attempt outcomes

* test(agents): align trajectory terminal fixture

* refactor(codex): share attempt failure type

* fix(codex): retain projector result contract

* test(agents): keep terminal projections test-only

* chore(plugin-sdk): refresh attempt terminal baseline
2026-07-23 19:56:03 -07:00
joshavant
6885d5b943 docs(plugins): refresh SDK API baseline 2026-07-23 20:34:39 -05:00
Peter Steinberger
bb657eec93 refactor(config): retire redundant settings (#113174)
* refactor(config): retire redundant settings

* style: apply current formatter

* chore: update plugin sdk baseline

* fix: keep Codex tool caps context-aware

* chore: remove stale imports

* test: align WhatsApp QA debounce config

* fix(config): clean up retired config checks

* fix(ci): align config cleanup checks
2026-07-23 17:45:02 -07:00
Peter Steinberger
0dd9dcda2f refactor(auto-reply): normalize inbound text once (#113179)
* refactor(auto-reply): canonicalize inbound text once

* chore(plugin-sdk): refresh API baseline

* refactor(auto-reply): narrow finalized template context

* test(auto-reply): keep runner fixtures structurally compatible

* fix(auto-reply): guard optional post-command agent text

* fix(auto-reply): finalize intercepted gateway context

* fix(ci): register iOS release planner entries
2026-07-23 17:39:01 -07:00
Peter Steinberger
b23c7bd0f8 feat(cron): convert heartbeat tasks: entries into independent cron jobs (#113165)
Each legacy heartbeat tasks: entry becomes an editable system-created cron
job (declaration key heartbeat-task:<agentId>:<hash>, per-occurrence
identity for duplicate names) that fires a guarded heartbeat wake carrying
the task prompt plus current monitor scratch context. Task cadence is now
independent of the base heartbeat interval; active-hours, busy-retry,
min-spacing, and flood guards are preserved, deferred payload-carrying
wakes are retained and retried after the spacing floor, and colliding
task/event wakes cannot starve each other.

openclaw doctor --fix migrates existing blocks: async parse/plan, then one
synchronous SQLite transaction that rereads the pinned scratch revision,
upserts job rows, and strips the tasks: block atomically — concurrent
doctors serialize on the database and a losing run aborts untouched.
Orphan fields, invalid intervals, and incomplete entries block migration
of their block with a clear finding instead of silent text loss. The
runtime tasks: parser is deleted; leftover text is ordinary scratch prose.

Nine Codex gpt-5.6-sol xhigh autoreview cycles; final verdict clean.
2026-07-23 16:13:08 -07:00
Peter Steinberger
95b86a3b2b refactor(heartbeat): make cron monitor rows own heartbeat cadence (#113135)
* refactor(heartbeat): make cron monitor rows own heartbeat cadence

agents.*.heartbeat.every stays the documented desired-state input; gateway
reconciliation and openclaw doctor --fix write it through into durable
system-owned cron monitor rows, and a scheduled monitor tick carries its
persisted everyMs/anchorMs as the authoritative cadence, which the runner
adopts for subsequent event cooldowns. Doctor gains a read-only cadence
preview (resolves the scheduler seed without creating device identity) and
an idempotent fix path that converges monitor rows per agent.

The cron-disabled fallback timer is deleted per its named removal plan
(#110950): gateways with cron.enabled=false or OPENCLAW_SKIP_CRON=1 log a
startup warning and get no scheduled heartbeats; manual and event-driven
wakes remain.

* fix(ci): drop unused requestHeartbeat import and refresh plugin SDK baseline
2026-07-23 12:56:54 -07:00
Peter Steinberger
73d279c232 fix(plugins): preserve shipped SDK and lifecycle state (#113101)
* fix(plugins): restore shipped channel compatibility

* docs(plugins): record shipped channel compatibility

* test(plugin-sdk): budget shipped channel compatibility

* docs(plugin-sdk): track shipped channel compat window

* test(plugins): align shipped compat guardrails
2026-07-23 12:30:54 -07:00
Peter Steinberger
913a6a83c5 fix(config): refresh docs baseline after help-text change 2026-07-23 11:58:42 -07:00
Peter Steinberger
129f86bbf5 feat: auto-collect durable meeting transcripts (#113122)
* feat(meetings): auto-collect durable transcripts

* chore(plugin-sdk): refresh meeting transcript API baseline

* fix(plugin-sdk): keep meeting transcript options implicit

* fix(meetings): satisfy transcript bridge typecheck

* fix(google-meet): preserve optional caption policy context

* fix(google-meet): retain caption mode callback type

* refactor(meetings): split transcript lifecycle helpers

* chore(plugin-sdk): refresh split meeting runtime baseline

* refactor(google-meet): split session helpers

* fix(meetings): decouple transcript retries from leave

* fix(meetings): isolate provider subscribers

* fix(meetings): harden capture lifecycle

* fix(meetings): preserve capture during storage outages

* fix(meetings): preserve pending transcript ordering

* fix(meetings): retry capture initialization

* test(agents): reflect default transcript registration
2026-07-23 11:41:08 -07:00
Peter Steinberger
3e2b3ea4d5 feat(cron): database-backed heartbeat monitor scratch replaces HEARTBEAT.md (#112967)
* feat(cron): move heartbeat context into database-backed per-job cron scratch

- new additive cron_job_scratch SQLite table (revision tombstones keep
  compare-and-swap monotonic across unset/recreate; 256KiB cap)
- heartbeat runner reads monitor scratch instead of workspace HEARTBEAT.md;
  heartbeat_respond gains a private scratch replacement parameter
- openclaw doctor --fix migrates HEARTBEAT.md into scratch (hash-verified,
  archived under state backups, idempotent, symlink-contained)
- gateway cron.scratch.get/set admin RPCs + openclaw cron scratch CLI
- workspace bootstrap no longer seeds HEARTBEAT.md; Codex heartbeat file
  guidance removed; docs and prompt snapshots updated

* fix(cron): review round 2 — shared-workspace heartbeat migration and non-default agent monitors

- doctor migration groups agents by heartbeat source file and imports into
  every monitor before archiving/removing the shared file once
- exempt heartbeat payloads from the main-session default-agent restriction:
  monitors only poke the wake bus, so non-default agents converge again
- document why disabled monitors retain their last cadence (config default
  already resolves before the fallback)

* fix(cron): honor configured cron store, legacy heartbeat fallback, and safer doctor claim

* fix(cron): claim HEARTBEAT.md before committing scratch and restore without clobbering

* fix(cron): pin migration CAS to precondition revision, re-verify claim on release, archive first, report scratch as pending

* docs(heartbeat): remove retired config options

* fix(cron): crash-recoverable migration claims, partial-import rollback, latest-response scratch pairing

* test(heartbeat): keep latest scratch proposal paired

* fix(cron): roll back committed scratch on changed-claim release and restore no-row state

* fix(cron): revision-guarded rollback delete and recreated-file detection on claim release

* fix(cron): treat every failed claim re-verification as a migration conflict

* test(heartbeat): rename ack test after ackMaxChars retirement

* fix(heartbeat): keep monitor scratch out of bypass-scope runs

* fix(cron): resolve claimed symlinks on release and gate legacy fallback on proven scratch state

* fix(cron): strict claim-name recovery and per-entry migration grouping

* fix(ci): heartbeat scratch gate repairs — lint causes, dead exports, since-train, inventory path, prompt snapshot, regenerated docs map, SDK baseline, protocol bindings

* fix(cron): live-owner claim guard and canonical entry-key migration grouping

* fix(cron): archive claimed inode on release and flag orphan claims beside recreated files

* docs(cron): document process-global state-db invariant for scratch service ops

* chore(i18n): refresh native inventory line numbers after protocol binding regen
2026-07-23 11:10:49 -07:00
Peter Steinberger
c5a2220d37 refactor(sessions): restructure per-agent SQLite schema (#113071)
* refactor(sessions): restructure agent session schema

* fix(sessions): preserve sharing across node ownership

* refactor: split session node artifact helpers

* test: track session cleanup temp directories

* fix(sessions): preserve fresher alias artifacts

* fix(sessions): reject placeholder membership writes

* test(sessions): align schema ownership fixtures

* fix(sessions): align incognito and heartbeat ownership

* test(sessions): preserve retained window rehoming coverage
2026-07-23 10:21:05 -07:00
Peter Steinberger
6f6c2acec3 refactor(infra): split outbound delivery services (#113099)
* refactor(infra): split outbound delivery services

* fix(infra): preserve outbound compatibility surface
2026-07-23 10:01:28 -07:00
Peter Steinberger
09672312c4 feat(gateway): incognito sessions for the web Control UI (#113006)
* feat(gateway): add web-only incognito sessions held in process memory

* feat(ui): add incognito toggle and badges to the web new-session flow

* fix(sessions): classify incognito by key shape, fail closed on stale keys, and gate memory writes

* fix(codex): start harness threads ephemeral for incognito sessions

* fix(sessions): reshape internal-effects incognito keys and add doctor repair for reserved key collisions

* refactor(plugin-sdk): export canonical incognito key classifier and guard the sentinel path

* fix(state): classify incognito DB handles from the recorded open-time set

* fix(gateway): isolate incognito sessions from durable lineage and allocation on read-only misses

* docs(sessions): pin the reserved incognito namespace ownership decision

* feat(gateway): admin-scope incognito visibility and incognito-blind cross-session surfaces

* fix(ci): repair kysely guardrails, dead export, docs map, protocol bindings, and ACP reset rotation

* fix(gateway): remove non-admin observability side channels for incognito sessions

* fix(gateway): enforce admin-scope incognito access and cover all parent-reference creation paths
2026-07-23 09:04:36 -07:00
Peter Steinberger
585eba56e3 refactor(infra): split exec approval services (#113050)
* refactor(infra): split exec approval services

* refactor(infra): keep approval token policy local

* fix(infra): preserve approval split bindings

* refactor(infra): clarify approval decision exports

* chore(plugin-sdk): refresh approval source links

* style(infra): mark approval type import

* refactor(infra): remove approval module cycles

* refactor(infra): keep socket normalization internal

* style(infra): remove stale approval type import

* refactor(infra): isolate approval type contracts
2026-07-23 08:51:19 -07:00
Peter Steinberger
3023d69fd8 feat(gateway): carry reviewer-only detail on plugin approvals (#113027)
* feat(gateway): carry reviewer-only detail on plugin approvals

* chore(protocol): regenerate projections for plugin approval detail

* chore(plugin-sdk): budget reviewer-detail surface additions
2026-07-23 06:28:23 -07:00
Peter Steinberger
6251343384 feat(sessions): visibility states, membership, and server-enforced participation (#112787)
* feat(sessions): enforce visibility and membership

* feat(ui): add session sharing controls

* docs: add session sharing implementation report

* refactor(sessions): use canonical creator identity

* fix(sessions): adopt creator ownership contract

* docs: refresh session sharing rebase report

* docs: record final creator integration proof

* docs: record final main rebase

* chore: drop worktree report artifact

* fix(sessions): keep drafts owner-only

* fix(ui): preserve redacted session restrictions

* fix(sessions): preserve scoped sharing authorization

* fix(sessions): re-verify session instance inside sharing mutation queue

* test(sessions): cover stale sharing mutation

* fix(sessions): bind membership to session instance, gate absence blocking on sharing

* fix(sessions): preserve entry normalization on rebase

* fix(sessions): atomic visibility instance guard, reset visibility on recreate

* docs(ui): name the absence-heuristic tradeoff and link follow-up

* feat(protocol): expose session sharing row state

* docs: note generated creator identity type

* fix(sessions): bind member writes and visibility rollback to session instance

* fix(ui): discard stale-connection sharing loads; drop worktree scratch files

* fix(ui): block composer only on observed sharing state, never on list absence

* fix(gateway): authorize agent runs against the resolved session (close keyless bypass)

* chore(protocol): allowlist Control UI-only session.sharing event for mobile

* test(config): record session.sharing keys in common-tier snapshot

* refactor(sessions): unexport internal sharing helpers

* test(gateway): update sessions changed routing assertions

* fix(sessions): align sharing identity with created actor

* fix(sessions): align membership identities and storage keys

* fix(gateway): re-filter drafts against fresh sharing state in sessions.list

* fix(gateway): drafts stay owner+admin only in the sessions.list fresh filter

* fix(ui): re-export sharing protocol types for the Control UI

* fix(ui): keep SessionSharingRole internal to satisfy deadcode gate

* fix(gateway): read runtime config lazily in session-mutation authorization

authorizeSessionMutation ran on every gateway request but eagerly called
context.getRuntimeConfig() — a non-trivial config resolve — for methods that
are never session mutations. Read config only once a real session-mutation
target is resolved. Also register the four session sharing methods in the
2026.7 release-train inventory test.

* fix(gateway): share one config snapshot across session-mutation authorization

Group rename/delete discovery and the authorization loop were each resolving
runtime config separately after the lazy-read change. Memoize the resolve so
non-session requests still pay nothing, while any session mutation resolves
config at most once and both discovery and authorization use that single
snapshot (no double reload, no mid-request config-change split).

* fix(gateway): resolve session-sharing CI gates

- isGatewayAdmin: null-safe connect access so internal/plugin-runtime runs
  (which reach authorization with a connect-less client) do not crash.
- emitSessionsChanged: scope only to a concrete session key; a [undefined]
  sessionKeys scope filters nothing correctly and would strip draft gating.
- session stores: mark the sync TOCTOU re-read and the sqlite_master
  existence probe as narrowly-justified raw SQLite primitives.
- tests: provide getRuntimeConfig to the session-action contract context,
  drop a shadowed 'call' binding, use structuredClone, and assert the
  agent-scoped sessions.changed broadcast shape.

* docs(gateway): note best-effort participation gate + refresh native i18n baseline

Session ownership/visibility are usability features, not a security boundary
(docs/concepts/multi-user.md, SECURITY.md); document that the pre-dispatch
authorization is intentionally not commit-bound to the resolved instance.
Also refresh apps/.i18n/native-source.json after the session-sharing protocol
codegen shifted line numbers of existing native strings (position-only).

* test(gateway): reset session sharing snapshots

* style(gateway): format sharing reset import
2026-07-23 08:53:57 -04:00
Peter Steinberger
852548ce05 feat(onboard): stage migration imports before promotion (#112798)
* feat(onboard): stage migration imports before promotion

* fix(onboard): harden migration recovery

* fix(onboard): commit promoted config with CAS

* fix(onboard): resume setup after migration recovery

* test(onboard): split noninteractive migration coverage

* refactor(onboard): split migration promotion helpers

* fix(onboard): normalize migration preparation cleanup

* fix(onboard): preserve recovered inference ownership

* fix(codex): complete empty deferred plugin config

* fix(codex): reconcile deferred plugin config retries

* fix(onboard): resolve verification target after rebase

* refactor(onboard): trim retired migration exports

* test(onboard): assert read-only auth prompt store
2026-07-23 07:06:01 -04:00
Peter Steinberger
b5232bc4dd refactor(markdown): add capability-driven fallbacks (#112985)
* refactor(markdown): add capability-driven fallbacks

* fix(markdown): type task-list core rule state

* style(markdown): make list-prefix return explicit

* fix(markdown): honor label-only plain links

* fix(markdown): retain clipped list provenance
2026-07-23 05:47:48 -04:00
Peter Steinberger
6522ce37d9 fix(release): unblock Telegram QA and Copilot media proof (#112972)
* fix(release): build Telegram candidate with private QA

* fix(copilot): preserve offloaded prompt images
2026-07-23 04:43:53 -04:00
Peter Steinberger
6bfdc9e474 refactor(meetings): share Teams and Zoom Chrome transport (#112931)
* refactor(meetings): share Chrome transport

* refactor(meetings): split platform adapter contract

* refactor(meetings): remove stale contract re-exports

* test(meetings): import adapter contract types
2026-07-23 04:27:48 -04:00
Jason (Json)
307b3060a9 fix: hide memory maintenance turns from chat (#112942)
* fix: hide memory maintenance turns from chat

* chore: update plugin SDK API baseline

* chore: account for harness visibility export
2026-07-23 01:02:27 -06:00
Peter Steinberger
cca67fc842 fix(meetings): verify talk-back loopback signal (#112939)
* fix(meetings): verify talk-back loopback signal

* refactor(meetings): keep verification helper private

* fix(meetings): type loopback buffers generically

* fix(meetings): bound loopback reference buffers

* fix(meetings): align loopback proof with playback

* chore(meetings): defer release note ownership

* fix(meetings): keep loopback health type private
2026-07-23 02:32:24 -04:00
Peter Steinberger
9735945083 refactor(markdown): share attributed range rendering (#112907) 2026-07-23 01:41:56 -04:00
Peter Steinberger
a542f01f49 refactor: remove dead tooling and deprecated exports (#112915) 2026-07-23 01:28:11 -04:00
Peter Steinberger
ebec398543 refactor: move Telegram and iMessage config schemas to plugins (#112850)
* refactor: move telegram and imessage schemas to plugins

* test: allow bundled schema facade regression coverage

* refactor: remove orphaned command config helper
2026-07-22 23:01:47 -04:00