Commit Graph

931 Commits

Author SHA1 Message Date
Peter Steinberger
b2701ac9cf fix(mac): prevent app auth from blocking node-host startup (#115533)
* fix(mac): move device auth tokens to shared SQLite state

* fix(mac): fail identity migration when source auth vanishes mid-read

Missing-file tolerance now applies only to the first observation; a disappearance after the auth file was observed fails the migration so the claimed identity survives for retry instead of committing without its credentials.

* fix(ios): validate auth scope UTF-8 encoding

* fix(ios): isolate SQLite auth profiles

* chore(ios): refresh native source inventory

* fix(mac): keep device auth in the shared token table

* test(mac): pin shared-key token cache semantics
2026-07-29 02:33:03 -04:00
Peter Steinberger
df9a940872 feat(chat): show live run telemetry across clients (#113084)
* feat(chat): show live run telemetry across clients

* fix(chat): satisfy native validation gates

* fix(chat): settle advertised terminal runs

* fix(android): clear stale run usage on gaps

* chore(i18n): align native source inventory

* fix(chat): reconcile telemetry with current projections

* refactor(chat): keep run state in owner extensions

* chore(i18n): refresh native source inventory

* test(ui): expect persistent working telemetry through streaming
2026-07-29 01:27:58 -04:00
Peter Steinberger
1d57a4989b fix(mac): stop repeated exec approvals migration retries (#115502)
* fix(mac): classify exec-approvals migration errors and stop retry storm

* fix(mac): refresh native i18n inventory
2026-07-29 01:09:22 -04:00
Peter Steinberger
65f99734b2 fix(mac): recover interrupted device identity import after source recreation (#115494)
* fix(mac): drop stale native identity claim when key material matches

* fix(mac): acquire stale identity claim before deletion

* fix(mac): park stale identity claim instead of deleting it

Rescue path now contains no destructive unlink: the acquired claim is parked as .stale-<uuid> and validated before any continue path, closing both replacement races review found.

* fix(mac): restore parked claim when the rescue source vanishes

Review round 4: accepted the vanished-source regression (restore before continue so claim-without-source stays importable); rejected serializing the source acquisition - rescue imports nothing and post-rescue source writes follow the standard atomic claim-then-import path (invariant documented inline).

* style(apple): satisfy device identity SwiftFormat
2026-07-29 00:59:54 -04:00
yuvraj thakur
efec26b2df fix(ios): Apple Watch chat inherits thinking defaults (#111301)
* fix(thinking): fall back instead of erroring on unsupported adaptive level (#109351)

The adaptive level is the auto sentinel (normalizeThinkLevel maps auto ->
adaptive) meaning 'pick an appropriate level', not 'force this exact level'.
Some clients (e.g. the Apple Watch client) send it as a transport default
while the iOS app sends none, so hard-erroring on an unsupported adaptive
override rejected otherwise-valid turns from those clients. Now the auto
sentinel always falls back to a supported level; explicit concrete levels
(e.g. an explicit /think xhigh) still hard-error as before.

Closes #109351

* docs(proof): add real-behavior-proof screenshot + run log for #111301

Captured run of the real get-reply-run.media-only test (101 passed)
showing the adaptive-thinking fallback fix verified.

Co-Authored-By: yuvrajlaptop2008-byte <284412773+yuvrajlaptop2008-byte@users.noreply.github.com>

* fix(ios): inherit Watch chat thinking defaults

Co-authored-by: yuvraj thakur <284412773+yuvrajlaptop2008-byte@users.noreply.github.com>

* chore(ios): sync native i18n inventory

---------

Co-authored-by: yuvrajlaptop2008-byte <284412773+yuvrajlaptop2008-byte@users.noreply.github.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-28 23:24:22 -04:00
Peter Steinberger
49f4942760 fix(chat): preserve literal Markdown image examples (#113904) 2026-07-28 16:12:08 -04:00
Peter Steinberger
773d60dfb9 fix(macos): bound websocket ping so a dropped pong cannot orphan its continuation (#115362)
* fix(macos): bound websocket ping so a dropped pong cannot orphan its continuation

URLSession drops the pong handler entirely when a web socket task is cancelled or
closed mid-flight. The existing gate guarded a double resume but nothing guarded
zero resumes, so the checked continuation leaked, Swift logged CONTINUATION
MISUSE, and keepaliveLoop's await never returned - wedging the keepalive for the
lifetime of the process.

Race the ping against a deadline and reuse the gate so exactly one resume wins.
Cancellation of the deadline returns without resuming, otherwise a delivered pong
would race the gate and surface as a spurious timeout.

* fix(macos): reuse URLError(.timedOut) instead of a new public ping error

Periphery flags a public enum referenced only inside its own module as dead
code in the shared OpenClawKit intersection scan. URLError keeps the timeout
indistinguishable from a transport timeout for callers, which already handle
URLSession errors from every other path, and adds no public surface.
2026-07-28 14:58:16 -04:00
Yue Fei
1b4a465ea1 feat(gateway): accept WebSocket request trace context (#113189)
* feat(gateway): accept WebSocket request trace context

* test(gateway): prove WebSocket trace isolation

* test(gateway): simplify traced response match

* ci: allow iOS screenshot validation to finish

* fix(gateway): keep traced request failures scoped

* test(ci): align iOS screenshot timeout contract

* test(ui): reset config route location

* ci: scope iOS screenshots to native changes

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-28 13:15:05 -04:00
Peter Steinberger
40fb1ca27e fix: schema-version refusal blames a downgrade that never happened and cannot identify the stale install (#115232)
* fix(state): name the refusing install in schema and exec-approval refusals

The newer-schema refusal told operators not to downgrade and to upgrade
OpenClaw, neither of which is actionable when two builds share one release
version string. It now names the install root that refused, both schema
versions, and warns that a linked source checkout reports its git HEAD even
when its built dist is older.

The exec-approvals gate told operators to run `openclaw doctor --fix` without
naming the state directory, so a bare invocation repaired the default root
while the scoped install stayed blocked. Both the TypeScript gate and its
Swift sibling now scope the command to the blocked state directory.

Refs #115008

* fix(gateway): name the refusing install in the startup schema refusal

* fix(mac): keep the exec-approvals gate message buildable on iOS

* fix(exec-approvals): shell-quote the state directory in the repair command

* fix(exec-approvals): state the repair directory in prose so every shell can follow it
2026-07-28 12:21:43 -04:00
Vincent Koc
289c8ff992 fix(apple): localize gateway discovery status 2026-07-28 23:48:57 +08:00
Peter Steinberger
2025c3d1b8 feat(system-agent): give Ask OpenClaw ambient page context (#114943)
* feat(ui): add custodian page context

* fix(system-agent): keep planner input free of the pending-proposal marker

* fix(system-agent): preserve context-free call shape

* refactor(system-agent): isolate page context boundaries

* fix(gateway): canonicalize UI context

* fix(gateway): enforce ASCII page context
2026-07-28 05:30:44 -04:00
Peter Steinberger
4b05d83035 fix: generated images do not appear in native chat (#115042)
* fix(chat): render managed images in native clients

Co-authored-by: Francesco Giannicola <francescogiannicola1@gmail.com>

* chore: keep release changelog owned

* refactor(macos): split managed image loading

* test(apple): prove managed image header policy

* test(native): stabilize managed image proof

* test(apple): satisfy strict concurrency checks

---------

Co-authored-by: Francesco Giannicola <francescogiannicola1@gmail.com>
2026-07-28 04:39:53 -04:00
Vincent Koc
7838c6a6fd fix(apps): fence stale mobile delivery state 2026-07-28 08:15:52 +02:00
Peter Steinberger
a4d60af42b fix: sharpen working-claw silhouette into a toothed pincer (#114939) 2026-07-28 01:18:36 -04:00
Peter Steinberger
1e3a4a69b5 fix: preserve native trace heading typography (#103436)
* fix(ios): preserve native trace heading typography

* test(ios): attach trace heading visual proof

* test(ios): import shared chat UI for visual proof
2026-07-28 00:01:44 -04:00
Peter Steinberger
313daad549 perf(gateway): warm handler families and cache identity avatars (#114754)
* perf(gateway): warm handler families and cache identity avatars

* chore: drop changelog edit (release-generation-owned)

* fix(ci): regenerate protocol models, satisfy knip, absorb sidecar drift

- commit regenerated Swift GatewayModels for the additive cron.list param
- split the avatar data-url cache into assistant-avatar-cache.ts so its
  factory has a production consumer (knip production scan)
- de-export prewarm family names/type; test now drives fake families only
- postReadySidecarCount 2 -> 3: main added a post-ready sidecar in parallel
2026-07-27 19:37:13 -04:00
Peter Steinberger
f85a458a45 refactor(mobile): consolidate native gateway and voice lifecycles (#114671)
* refactor(mobile): consolidate native lifecycle ownership

* fix(ci): cover Codex prewarm and chat lifecycle proof
2026-07-27 14:52:02 -04:00
Peter Steinberger
14d8c2439f feat(ui): offer normally-absent core files instead of flagging them missing (#114559)
* feat(ui): offer normally-absent core files instead of flagging them missing

The Agents core-files editor rendered every unwritten workspace file as a
permanently-badged MISSING tab, so an ordinary workspace looked broken. Absence
is only a fault for required files; SOUL.md, USER.md, and MEMORY.md are normal
to be absent until written.

agents.files.list now marks those entries expectedAbsent, and the editor keeps
them out of the tab strip behind an add picker that creates the file on save.
A missing AGENTS.md still shows as a fault.

* chore(protocol): regenerate Swift gateway models for expectedAbsent

* fix(gateway): carry expectedAbsent through agents.files.get

Clients merge the get response over the listed entry, so a missing-file get
that dropped the flag made a file picked from the add picker re-render as a
MISSING fault. Caught by live Control UI proof, not by the unit tests.
2026-07-27 09:16:10 -04:00
Peter Steinberger
4aa96a118d fix(sessions): prevent stale and cross-agent observer status after reconnect (#114548)
* fix(sessions): prevent stale and cross-agent observer status

* fix(sessions): sync native observer source inventory

* fix(android): satisfy observer ownership formatting gate
2026-07-27 08:39:29 -04:00
Peter Steinberger
91f04499f5 fix(sessions): defer agent self-archive until run completion (#114522) 2026-07-27 07:46:22 -04:00
Peter Steinberger
c56689416e fix(ui): scope global route resolution by agent 2026-07-27 05:43:19 -04:00
Peter Steinberger
64bf485ba2 fix(sessions): scope observer state by agent 2026-07-27 05:43:19 -04:00
Peter Steinberger
51f228f6fe fix(ui): preserve agent-owned session navigation
Add agent ownership to observer digests, scope global observer delivery and reconciliation, and centralize application session selection across navigation and reconnects.

Co-authored-by: xbrxr03 <abrarhabib03@gmail.com>
2026-07-27 05:43:19 -04:00
Peter Steinberger
5a8db91459 fix(macos): keep polling gateway-executed wizard steps (#114383)
* fix(macos): keep polling gateway-executed wizard steps

* docs(ui): note the prebuilt control-UI bundle in live verification

* test(macos): fail fast when gateway progress polling stalls

* chore(i18n): refresh native source inventory anchors
2026-07-27 04:33:09 -04:00
Peter Lee
0406e66369 fix(ui): keep stable chat rows in insertion order and only sort live tool/stream items by timestamp (#113266)
* fix(ui): keep stable chat rows in insertion order and only sort live tool/stream items by timestamp

* fix(ui): keep live rows within current turn

* fix(ui): keep current work above queued turns

* fix(ui): keep streamed replies above queued turns

* fix(ui): preserve reconnecting run order

* fix(ui): preserve causal terminal ordering

* fix(ui): bound replay rows to owning turns

* fix(ui): keep question summaries in owning turns

* fix(ui): scope question run ownership to session

* fix(ui): restore reconnecting chat run identity

* fix(ui): remove unused chatItemTimestamp import in chat-thread-build.ts

* fix(ui): correlate question summaries with agent runs

Co-authored-by: Peter Lee <li.xialong@xydigit.com>

* chore(i18n): refresh native source baseline

Co-authored-by: Peter Lee <li.xialong@xydigit.com>

* fix(ui): remove unused chatItemTimestamp export and split tool-stream test file

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-27 02:08:22 -04:00
Peter Steinberger
8b66fc103d feat(ui): durable session board face and dashboards index (#114262)
* feat(ui): durable session board face and dashboards index

Board face lived only in client-side boardSessionViews, capped at 50 entries,
so the preference never followed the user to another device, evicted as
sessions accumulated, and could not be seen as a set.

Persist it as SessionEntry.boardFace, which rides the existing entry_json blob
and so needs no SQLite schema change or version bump. Expose it on the session
list row and add it to the sessions.patch write-scope allowlist alongside label,
pinned, and archived: setting your own view preference is user-level chat
organization, not policy. Unknown patch fields still fail closed to
operator.admin.

Generic navigation now reads the stored face, so the sidebar and session list
open a thread on the face you left it on. boardSessionViews keeps only
activeTabId and reopenDockByTab, which are genuinely per-device.

Add /dashboards listing threads whose preferred face is dashboard. Filtering
runs server-side in filterSessionEntries before pagination, because the client
holds only a capped page and a client-side filter would silently omit
dashboards.

* test(protocol): assert the pre-rename face param is rejected

The gateway-protocol validator test still passed the pre-rename 'face' key,
which the closed schema rejects. Use boardFace, and pin the old name as a
negative case so it cannot silently return.

* chore(protocol): regenerate Swift bindings and docs map for boardFace

Adding boardFace to the sessions schema changes two committed generated
artifacts: the Swift gateway models (pnpm protocol:gen:swift) and the docs map
(pnpm docs:map:gen), which now lists the dashboards index section.
2026-07-27 00:35:34 -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
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
adfb59c19b feat(mac): dashboard gateway picker with in-place switching (#113965)
* feat(mac): add dashboard gateway switching

* feat(ui): add dashboard gateway picker

* docs(mac): document dashboard gateway picker

* fix(mac): harden gateway switching after review

* fix(ui): refresh gateway picker snapshots

* fix(mac): carry TLS pins through promotion and serialize gateway switches

* style(ui): satisfy lint rules in gateway picker files

* fix(ui): tolerate absent context in gateway picker pane props

* chore(ci): refresh generated inventories

* style(mac): satisfy Swift CI checks

* refactor(mac): drop dead GatewayEndpointStore.requireConfig

* perf(ui): own gateway capability in the chat chunk

* chore(ui): keep gateway capability factory module-private
2026-07-25 20:57:28 -07:00
Peter Steinberger
852a686a1b feat(chat): restore prompt image attachments on rewind/fork (#113945)
* feat(chat): restore prompt image attachments on rewind/fork

* chore(i18n): refresh native source inventory anchors

* fix(gateway): restore media-store images on rewind/fork

* fix(gateway): bound and dedupe rewind media reads

* fix(sessions): bound inline editor attachments in message cut

* fix(ui): align restored attachment cap with gateway 5 MiB limit

* fix(gateway): dedupe rewind media refs by resolved id

* fix(sessions): lint-safe __openclaw access in message cut
2026-07-25 20:32:16 -07:00
Colin Johnson
de9ed64c29 feat(talk): enable GPT Live with Codex OAuth (#113354) 2026-07-25 20:41:27 -04:00
Peter Steinberger
9defe24ec2 fix(chat): restore canonical native session ordering and search (#113886) 2026-07-25 16:42:33 -07:00
Peter Steinberger
af44cb1a72 feat(native): show Swarm progress in chat (#113850)
* feat(native): show swarm progress

* fix(native): align swarm progress lifecycle

* chore(native): shorten swarm progress source name

* style(macos): pad swarm progress surfaces

* chore(native): use compact swarm source name

* fix(native): harden swarm route ownership

* fix(native): preserve swarm render ownership

* chore(i18n): refresh native swarm inventory

* fix(native): bound swarm refresh ownership

* fix(native): remove unused swarm capability initializer
2026-07-25 15:11:19 -07:00
Peter Steinberger
ce5ab8adb8 refactor(gateway): remove dead sessions.observer.ask rpc (#113791)
* refactor(gateway): remove dead sessions.observer.ask rpc

* docs: record btw and companion contract split

* fix(gateway): unexport observer model sanitizer after ask removal
2026-07-25 14:44:02 -07:00
Peter Steinberger
fca18dddc7 fix(native): preserve active chat when another run ends (#113786)
Co-authored-by: Peter Steinberger <steipete@golden-gate.local>
2026-07-25 11:04:35 -07:00
Peter Steinberger
a1d666fdc3 fix(native): keep images and voice notes visible in chat and exports (#113764)
* fix(native): preserve image and audio in chat transcripts

* fix(native): refresh extracted media localization source lines

---------

Co-authored-by: Peter Steinberger <steipete@golden-gate.local>
2026-07-25 10:49:56 -07:00
Peter Steinberger
a95486cefc feat: session rail with read-only session companion in Control UI chat (#113698)
* feat(protocol): add session companion schemas

* feat(gateway): add session companion service

* feat(gateway): expose session companion rpc

* fix(gateway): harden companion runtime limits

* test(gateway): fix companion type assertions

* test(gateway): align companion test target

* feat(ui): replace observer HUD and side chat with session rail

* docs: session rail companion for control ui

* test(ui): align session rail client mock

* fix(ui): drop stale chat search import

* fix: satisfy session companion lint contracts

* refactor(gateway): isolate companion state contract

* fix(ui): keep session rail reachable while idle

* fix(agents): clamp derived openai prompt cache keys at boundary

* fix(ai): clamp chatgpt responses session_id affinity header

* fix(ci): align session companion branch gates

* fix(ui): require run id for sessionless terminal chat events

* fix(agents): scope internal run events to transcript

* chore: revert changelog edit (release generation owns changelog)
2026-07-25 08:14:32 -07:00
Peter Steinberger
7e80f36723 fix(apps): restore live session updates after native reconnects (#113634)
* fix(apps): replay session visibility across native reconnects

* fix(apps): refresh shifted native i18n source lines

---------

Co-authored-by: Peter Steinberger <steipete@golden-gate.local>
2026-07-25 04:58:41 -07:00
Vincent Koc
509a5f0373 fix(sqlite): reject schema data loss during upgrades (#113473)
* fix(sqlite): reject schema data loss during upgrades

* test(macos): align native state schema boundary
2026-07-25 12:22:02 +08:00
scotthuang
2900026b33 fix: stop selected channel sessions from WebChat (#111108)
* fix: stop selected channel sessions from WebChat

* fix: clear channel working state after stop

* fix: cancel queued turns before session abort

* fix: replay pending stops after reconnect

* fix: align stop lifecycle test fixtures

* fix(ui): bind pending aborts to gateway client

* test(ui): keep chat pane specs within line limit

* chore(ios): refresh native i18n inventory

* chore: retrigger PR checks

* fix(system-agent): avoid blocking TUI catalog discovery

* fix: preserve session abort ownership

* test: align abort coverage with current main

* test: assert scoped session abort broadcast

* fix(agent-runs): expose SDK runtime abort state

* fix(ui): clear queued main-session stops by scope

* fix(ui): replay only exact run aborts

* fix(gateway): protect session abort cleanup

* fix(ui): narrow session abort intent

* test(ui): avoid unbound request assertions

---------

Co-authored-by: scotthuang <scotthuang@tencent.com>
Co-authored-by: Patrick Erichsen <patrick.a.erichsen@gmail.com>
2026-07-24 14:36:18 -05:00
Vincent Koc
a3911fe9ff fix(apple): localize TLS connection problems 2026-07-24 15:26:58 +08:00
joshavant
96539d1c3c test(cron): align generated and compatibility gates 2026-07-24 01:24:03 -05:00
Peter Steinberger
90aee82793 feat(sessions): suggestion queue + typing indicator (#113173)
* feat(protocol): add session collaboration contracts

* feat(gateway): add session suggestion queue and typing

* feat(ui): add session suggestion controls

* fix(collaboration): restrict suggestion resolution

* fix(collaboration): dedupe suggestion dispatch modes

* fix(collaboration): preserve resolver identity

* fix(collaboration): reconcile suggestion state

* fix(collaboration): filter identityless suggestion events

* fix(ui): expose full suggestion text

* fix(collaboration): durably claim suggestion dispatch

* fix(collaboration): harden suggestion events and typing

* fix(collaboration): reconcile suggestion races

* fix(ui): reconcile suggestion capabilities

* fix(collaboration): close suggestion privacy races

* test(ui): satisfy suggestion lifecycle lint

* fix(collaboration): fence resolved suggestion events

* test(collaboration): type deferred audit result

* fix(collaboration): fence delayed typing events

* fix(ui): coalesce suggestion refreshes

* fix(ui): preserve resolved self suggestions

* fix(collaboration): enforce draft suggestion visibility

* fix(collaboration): fence post-dispatch finalization

* fix(ui): retain suggestions across visibility changes

* fix(collaboration): fence suggestion context and archives

* fix(collaboration): fence suggestion resolve lifecycle

* fix(collaboration): map suggestion replacement races

* refactor(gateway): extract session typing state

* fix(collaboration): integrate suggestion storage with session nodes

* refactor(gateway): extract session sharing snapshot cache

* fix(collaboration): satisfy protocol and deadcode gates

* fix(ci): register iOS release script entrypoints

* fix(collaboration): fence typing by session instance

* fix(collaboration): enforce incognito suggestion privacy

* docs(ui): clarify solo suggestion dormancy

* test(gateway): preserve incognito literal type

* test(gateway): split session typing coverage

* test(gateway): register collaboration method expectations
2026-07-23 18:59:58 -07:00
Peter Steinberger
cbf94c0d8b feat(sessions): drafts UX — create-as-draft, promote, admin ghost treatment (#113127)
* feat(protocol): support draft session creation

* feat(ui): add draft session workflows

* docs: explain multi-user drafts

* test(ui): tighten draft ownership fixture

* test(ui): satisfy draft E2E lint

* test(ui): keep draft fixtures strictly typed

* docs: add drafts implementation report

* docs: clarify implementation LOC summary

* test: strengthen draft compatibility coverage

* docs: correct drafts cleanup report

* fix: harden draft availability policy

* docs: update draft policy review notes

* test(ui): type draft policy mock control

* fix: preserve keyed draft creation retries

* fix: keep disabled draft retries idempotent

* docs: finalize drafts cleanup report

* fix(ui): keep draft ownership helper internal

* docs: refresh drafts docs map
2026-07-23 13:06:35 -07:00
Peter Steinberger
c519e01a24 feat(gateway): chat.send expectedLeafEntryId precondition keeps stale panes off switched branches (#113073) 2026-07-23 12:33:31 -07:00
Peter Steinberger
013b24dd6d feat(sessions): archive attribution (archivedBy) (#113116)
* feat(sessions): attribute archive transitions

* docs: add archive attribution report

* fix(sessions): restore alias layout after archive audit failure

* docs: update archive attribution report

* fix(sessions): isolate archive audit rollback

* docs: record final archive rollback design

* fix(sessions): make archive audit note best-effort

* docs: record best-effort archive audit policy

* chore: refresh native i18n baseline
2026-07-23 11:23:30 -07:00
Jason (Json)
2f5e7cfc5d fix(ui): prevent duplicate image prompt and flicker (#113113)
* fix(ui): stabilize initial image prompt handoff

* chore(protocol): refresh sessions create model

* chore(i18n): refresh native source inventory
2026-07-23 12:11:52 -06: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
78b987aa2e fix: keep model catalog coherent across config reloads (#112331)
* fix(gateway): keep model catalog reads generation-safe

* fix(gateway): type owner-aware catalog snapshots

* fix(sessions): break lifecycle accessor import cycle

* fix(gateway): preserve requested catalog owner

* fix(gateway): keep catalog owner identity explicit

* fix(gateway): isolate catalog snapshot types

* fix(gateway): respect published catalog owner

* fix(gateway): reject mismatched catalog owners

* test(apple): gate unread patch timing explicitly

* fix(gateway): keep startup metadata bounded

* fix(gateway): forbid startup catalog fallback

* test(apple): wait for terminal outbox flush

* fix(cron): follow published model catalog owner

* test(cron): align catalog runtime mocks

* test(system-agent): isolate TUI catalog metadata

* test(gateway): refresh deletion session snapshot

* fix(gateway): preserve authoritative catalog owners

* fix(gateway): retain equivalent catalog preload

* fix(gateway): reject ownerless catalog projections

* fix(gateway): scope catalog loads to resolved agent

* fix(gateway): restore canonical catalog owner identity

* fix(cron): preserve published catalog owner

* test(cron): align owner snapshot mocks

* fix(cron): preserve replacement owner workspace

* fix(runtime): reject explicit catalog owner mismatch

* fix(runtime): preserve implicit owner fallback

* test(cron): resolve implicit owner fixtures
2026-07-23 10:54:27 -07:00