Commit Graph

677 Commits

Author SHA1 Message Date
Peter Steinberger
4b751ce48a feat(tooling): complete packages/* noUncheckedIndexedAccess adoption (phase 2) (#104626)
* feat(tooling): extend strict-ratchet lane to all remaining leaf packages

* fix(packages): burn down indexed-access debt in ai and agent-core

All 196 noUncheckedIndexedAccess errors fixed behavior-identically
(iteration, .at()/slices, DataView byte math, guarded queue peeks) plus
cleanup finds: a sparse-tool diagnostic bug, deduplicated Responses
call/item ID parsing with an honest string|undefined splitter, and a
clearer local failure for redacted-thinking blocks missing signatures.
Removes all 17 remaining non-null assertions across ai, gateway-client,
and llm-core so the assertion ban aligns 1:1 with the ratchet lane.
speech-core joins memory-host-sdk as structurally deferred (imports
src/** via plugin-sdk path mappings).
2026-07-11 11:54:06 -07:00
Peter Steinberger
e9b7a9a912 fix(memory): search by filenames and paths (#104449)
Co-authored-by: Pick-cat <huang.ting3@xydigit.com>
2026-07-11 10:54:34 -07:00
Peter Steinberger
e686693732 feat(tooling): adopt noUncheckedIndexedAccess via a strict-ratchet lane (phase 1) (#104577)
* feat(tooling): add noUncheckedIndexedAccess strict-ratchet lane

* fix(packages): make indexed access explicit across ratchet packages

Burns down all 65 noUncheckedIndexedAccess errors in the seven ratchet
packages with behavior-identical restructuring (iteration, charAt/slice,
regex-group guards, validated hextet tuple). net-policy invariant
violations now throw instead of failing open. Adds
@openclaw/normalization-core/expect (expectDefined/first/last) with
subpath export and tests. memory-host-sdk fixes kept but the package
stays out of the lane: it re-exports core src/** so the flag would apply
transitively to all of core.

* fix(lint): keep .oxlintrc.json strict-JSON parseable for extension lint wrappers
2026-07-11 10:26:12 -07:00
Peter Steinberger
96f0983a85 fix(onboarding): skip setup for configured gateways and require inference first (#102883)
* fix(crestodian): keep onboarding RPCs restart-safe

* fix(profiles): isolate approval state migrations

* fix(crestodian): bypass configured gateway setup

* test(crestodian): type onboarding mocks

* fix(onboarding): require inference before Crestodian

* fix(onboarding): enforce verified inference handoff

* fix(macos): reset setup on gateway endpoint edits

* chore(i18n): refresh native source inventory

* fix(gateway): keep socket on request cancellation

* test(packaging): require workspace templates

* fix(onboarding): bind setup to verified inference

* fix(onboarding): align inference gate contracts

* fix(crestodian): classify concurrent policy rejection

* test(crestodian): expect registry restoration

* fix(onboarding): bind setup to configured gateways

* fix(codex): preserve startup phase deadlines

* test(crestodian): match fail-closed policy ordering

* test(onboarding): assert bound gateway handoff

* fix(codex): bind runtime resolution to spawn cwd

* test(crestodian): assert policy rejection order

* fix(cli): preserve gateway routing across restarts

* fix(macos): fail closed during gateway edits

* test(macos): cover gateway route generation races

* chore: keep release notes out of onboarding PR

* fix(ci): refresh onboarding generated checks

* style(swift): align gateway channel formatting

* fix(ci): refresh plugin SDK surface budgets

* fix(ci): resync native string inventory

* refactor(swift): split gateway channel support

* test(doctor): isolate plugin compatibility registry

* test(macos): isolate gateway onboarding fixtures

* test(macos): assert gateway lease health ordering

* fix(codex): reconcile computer-use startup changes
2026-07-11 10:25:14 -07:00
Peter Steinberger
49b5b862ac feat: node-hosted plugins — dynamic tools, MCP servers, and skills (#90431)
* feat: node-hosted plugins — dynamic tools, MCP servers, and skills

Nodes become declarative plugin hosts:
- node.pluginTools.update: node hosts publish plugin-registered agent tool
  descriptors; gateway materializes them as agent tools executing via
  node.invoke under the node command allowlist, with tools.effective
  invalidation and node online/offline removal.
- Trusted paired-node descriptors: no gateway-side plugin registration
  required; gateway.nodes.pluginTools.enabled off-switch (default on);
  description/count caps; deterministic node-prefixed collision names.
- Declarative node-hosted MCP: nodeHost.mcp.servers (McpServerConfig shape)
  starts MCP clients on the node host, publishes tools as pluginId node-mcp,
  executes via built-in mcp.tools.call.v1 with per-layer timeouts, failure
  isolation, and orphan-safe shutdown. No re-pairing when servers change.
- Node-hosted skills: node.skills.update publishes ~/.openclaw/skills
  content (64 skills/64KB/512KB caps both sides); gateway merges them into
  the skills snapshot while connected and exec host=node is available, with
  node:// locators, node-prefixed collisions, disabled command dispatch,
  and gateway.nodes.skills.enabled + nodeHost.skills.enabled switches.
- Security: node-supplied pluginIds cannot satisfy pluginId-scoped tool
  allowlists unless gateway-registered; reserved node-mcp id requires the
  core MCP descriptor shape; protocol registry kept out of public
  plugin-sdk dts.
- E2E: pond harness proves publication, MCP round-trip, skills locator, and
  disconnect/reconnect for all three surfaces.

* style: format node-plugin-tools test

* fix(skills): keep status loader unfiltered when eligibility is passed

skills.status started passing eligibility for the node-skill merge, which
flipped loadWorkspaceSkillEntries into filtered mode and dropped disabled
skills from status reports (QA plugin-lifecycle-hot-reload timeout). Status
now merges node skills explicitly around an unfiltered load. Also: regen
docs_map for new node docs sections; add the intentional node-host MCP
onclose suppression to the lint-suppression allowlist.
2026-07-11 10:16:34 -07:00
Peter Steinberger
57af2bbff0 fix: clear remaining release validation blockers (#104555)
* test: align provider tool call lifecycles

* test: isolate plugin install repair migrations

* fix: accept catalog temperature compatibility

* fix: disable GPT-5.6 tool reasoning on completions

* style: avoid shadowed stream model
2026-07-11 09:32:16 -07:00
Peter Steinberger
5ca46a6554 feat(cloud-workers): pinned SSH tunnel runtime and provider-owned key resolution (#104553)
* feat(cloud-workers): add pinned SSH tunnel runtime

* feat(crabbox): resolve cloud worker SSH identities

* docs(cloud-workers): document SSH tunnel contracts
2026-07-11 09:26:08 -07:00
Peter Steinberger
03cab29505 feat(cloud-workers): worker bundle production, pinned SSH bootstrap, and admission handshake (#104532)
* feat(gateway-protocol): add worker admission handshake

* feat(cloud-workers): build and bootstrap worker bundles

* feat(cloud-workers): wire bootstrap lifecycle

* fix(cloud-workers): state host-key TOFU fallback without warning-comment suppression

* test(cloud-workers): assemble host-key fixture to satisfy review secret scanner

* test(cloud-workers): assemble redaction fixture to satisfy review secret scanner

* fix(cloud-workers): require pinned SSH host keys

* fix(state): add ssh_host_key to additive worker_environments migration
2026-07-11 08:14:30 -07:00
haruai
597de699d0 fix: route node policy plugin approvals (#98561)
* fix: route node policy plugin approvals

* refactor(gateway): simplify node approval routing

* fix(gateway): preserve node approval routes

* chore(protocol): refresh node invoke model

---------

Co-authored-by: haruaiclone-droid <281899875+haruaiclone-droid@users.noreply.github.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-11 05:37:45 -07:00
Peter Steinberger
90e465833b feat(gateway): durable cloud worker environments, provider SDK contract, and lifecycle RPCs (#104401)
* docs(plan): add cloud workers design plan

* feat(plugin-sdk): add cloud worker provider foundations

* feat(protocol): add worker environment lifecycle shapes

* feat(gateway): persist worker environment lifecycles

* test(gateway): pin environment inventory assertion for damaged worker store

* style(cloud-workers): satisfy lint and docs formatting

* fix(gateway): narrow worker environment type boundaries

* chore(plugin-sdk): account for WorkerProvider surface growth

* docs: regenerate docs map
2026-07-11 04:54:27 -07:00
Vincent Koc
c79bac4018 test(memory): clean up llama worker fixtures 2026-07-11 16:40:14 +08:00
Vincent Koc
d8993d979d test(memory): describe requested llama context 2026-07-11 16:40:14 +08:00
Vincent Koc
9e39e9a862 fix(memory): complete llama runtime diagnostics 2026-07-11 16:40:14 +08:00
Vincent Koc
4b0e5f5461 feat(memory): capture llama.cpp runtime facts 2026-07-11 16:40:14 +08:00
Peter Steinberger
7bf80dc2c6 chore(tooling): enforce formatting and refresh TypeScript checks (#104239)
* chore(tooling): enforce current formatter and refresh checks

* chore(tooling): keep release changelog formatter-owned

* chore(tooling): retain compatible Node type surface

* ci: enforce formatting for docs-only changes

* ci: isolate docs formatter check

* chore(tooling): apply updated lint and format rules

* chore(tooling): satisfy updated switch lint

* style(ui): apply Linux formatter layout

* test(doctor): match quiet local audio contribution

* test(doctor): assert quiet output only

* test(doctor): follow restored information contract
2026-07-11 01:09:51 -07:00
Alix-007
5219c9353d fix(tts): bound voice-list requests (#102865)
* fix(microsoft): add timeout to voices list request

* fix(tts): bound voice-list requests

Co-authored-by: llagy009 <0668001470@xydigit.com>

---------

Co-authored-by: llagy009 <0668001470@xydigit.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-11 00:55:06 -07:00
NianJiu
54eda58447 fix(gateway-client): stop unbounded requests masking stalled transports (#103407)
* fix(gateway-client): keep watchdog active for unbounded requests

* test(gateway-client): prove watchdog recovery lifecycle

* style(gateway-client): satisfy watchdog test lint

---------

Co-authored-by: NianJiuZst <180004567+NianJiuZst@users.noreply.github.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-11 00:27:34 -07:00
Peter Steinberger
f94a7dc183 feat(codex): supervise native Codex sessions (#104045)
* feat(codex): add native session supervision

* fix(codex): harden supervision integration

* fix(codex): preserve locked harness ownership

* fix(codex): fence native session archive

* fix(codex): revalidate archive binding ownership

* feat(codex): integrate supervision runtime

* feat(sessions): preserve harness-owned execution

* feat(sessions): persist harness ownership invariants

* feat(gateway): enforce harness-owned sessions

* feat(setup): enable detected Codex supervision

* feat(mac): expose supervised Codex sessions

* feat(ui): make Codex sessions actionable

* docs(codex): document session supervision

* test(codex): cover integration ownership

* chore(i18n): refresh supervision inventories

* fix(setup): finalize Codex activation atomically

* test(codex): narrow binding store update

* fix(sessions): preserve legacy model locks

* test(macos): serialize Codex catalog fixtures

* fix(sessions): preserve legacy lock admission

* chore(i18n): reconcile supervision metadata

* test(sessions): mark legacy lock fixture

* fix(macos): drain final Codex catalog frame

* docs: leave supervision note to release

* style(macos): satisfy Codex catalog type length

* chore: record session accessor seam owners

* fix(macos): honor configured Codex supervision

* fix(codex): preserve harness-owned model locks

* fix(codex): satisfy supervision lint gates

* chore(i18n): refresh native supervision inventory

* fix(codex): align supervision validation contracts

* fix(codex): close supervision boundary gaps

* fix(codex): preserve supervision activation contracts

* fix(codex): dispose standalone supervision runtime

* fix(codex): pin supervised source connection

* fix(plugins): bind delegated runs to exact session target

* fix(codex): scope supervised sessions to configured agents

* fix(codex): fingerprint effective supervision home

* fix(codex): normalize supervision plugin policy

* fix(codex): keep supervised bindings stable across upgrades

* fix(codex): guard all supervised binding connections

* fix(codex): preserve catalog filters and pending CAS identity

* fix(codex): preserve supervision identity for diagnostics

* fix(codex): bind uncertain commits to supervision connection

* fix(codex): satisfy supervision type boundaries

* fix(macos): reconcile current main validation

* fix(codex): handle absent runtime config in supervision

* fix(doctor): own local audio acceleration check

* fix(codex): satisfy integration lint gates

* fix(codex): satisfy lifecycle safety guards
2026-07-11 00:12:08 -07:00
Peter Steinberger
ae2c6117d3 feat(ui): full-page New session screen with gateway folder browser (#104238)
* feat(gateway): add admin-only fs.listDir host directory listing

* feat(ui): replace new-session dialog with full-page /new screen and folder browser

* fix(ui): drop unnecessary template literal in new-session page

* refactor(ui): rename request token locals for review-bundle hygiene

* fix(ui): preserve typed draft on agent hydration and clear stale folder listings

* fix(ui): gate new-session submit on agent hydration and keep live folder edits

* test(ui): use exact textbox selector in new-session e2e

* test(ui): deep-link new-session e2e so agents.list override supplies workspace

* chore(i18n): translate new-session strings and refresh native inventory

* chore(i18n): reconcile locale metadata after rebase
2026-07-11 00:10:48 -07:00
Peter Steinberger
1d72c0f423 feat(ui): session diff panel showing a session checkout's changes in chat (#104184)
Adds a git-backed session diff panel to the Control UI, complementing the existing PR status chips.

New sessions.diff gateway method (operator.read): resolves the session checkout and returns structured per-file diffs (status, renames, +/- counts, capped unified patch) of branch + uncommitted + untracked work against the default-branch merge base. Hardened against git textconv execution and hardlinked out-of-tree content leaks; handles repos before their first commit via the empty-tree base.

Control UI renders a "Changes" panel in the chat detail sidebar with collapsible per-file diffs, hunk-gap markers, stat chips, and untracked/binary badges, gated on gateway method advertisement. Schemas additive (Swift models regenerated), 20 locales translated.

Closes #104182
2026-07-10 23:57:55 -07:00
Peter Steinberger
02cd9bf648 fix: suspension and restart wait for background execs (#104172)
* fix: block restart and suspension on background execs

* test: cover background exec suspension inspector
2026-07-10 22:56:17 -07:00
Josh Avant
fbd330b7aa fix(channels): honor configured read target policies (#99905)
* fix(channels): enforce configured read targets

* test(channels): align policy checks with boundaries

* fix: bind channel reads to trusted turn context

* test: satisfy gateway lint

* fix: narrow message action channel imports

* fix(feishu): authorize message reads before provider access

* fix(slack): await reaction clear authorization

* fix(channels): align provider action contracts

* fix(matrix): read direct-room account data before sync

* fix(channels): reject unsupported attachment actions early

* fix: restore trusted operator conversation reads

* fix(matrix): authorize pin actions before provider reads

* fix: preserve trusted channel read workflows

* fix(discord): resolve current channel ids consistently

* fix(agents): preserve message action turn capability

* fix(plugins): enforce host-owned read provenance

* fix(channels): harden Teams and Discord read policy

* fix(channels): preserve exact-current action compatibility

* fix(imessage): authorize trusted current chat aliases

* fix(channels): preserve normalized current aliases

* fix(channels): preserve external current target aliases

* fix: reconcile channel policy with current main

* fix(discord): isolate DM read policy

* fix(channels): enforce provider read gates

* fix(gateway): await serialized message action identity tokens

* fix(ci): refresh channel protocol contracts
2026-07-10 22:29:37 -05:00
Peter Steinberger
dba64d574f chore(release): set version to 2026.7.2 2026-07-11 04:00:49 +01:00
Peter Steinberger
05ebaf41f6 fix(tool-call-repair): bound serialized stream normalization (#104100)
* fix(tool-call-repair): bound serialized stream normalization

Co-authored-by: wuqingxuan <wu.qingxuan@xydigit.com>
Co-authored-by: 徐闻涵0668001344 <xu.wenhan1@xydigit.com>
Co-authored-by: qingminlong <qing.minlong@xydigit.com>
Co-authored-by: WangYan <wang.yan29@xydigit.com>

* fix(tool-call-repair): preserve strict scan narrowing

* fix(tool-call-repair): lint serialized name validation

* fix(tool-call-repair): replay split suffix whitespace

* fix(tool-call-repair): cap complete-call whitespace

* test(tool-call-repair): assert bounded whitespace replay

---------

Co-authored-by: wuqingxuan <wu.qingxuan@xydigit.com>
Co-authored-by: 徐闻涵0668001344 <xu.wenhan1@xydigit.com>
Co-authored-by: qingminlong <qing.minlong@xydigit.com>
Co-authored-by: WangYan <wang.yan29@xydigit.com>
2026-07-10 20:00:11 -07:00
Peter Steinberger
7b5854bee8 feat(webui): reintroduce opt-in AI purpose titles for tool calls (#103989)
* feat(webui): reintroduce opt-in AI purpose titles for tool calls

Restores the chat.toolTitles path removed in #103821, gated behind the new
gateway.controlUi.toolTitles opt-in (default false) so tool rendering stays
fully deterministic with no background model calls unless an operator enables
it. Disabled gateways answer { titles: {}, disabled: true } without loading
the completion runtime, and clients stop asking for the session.

When enabled, titles use canonical utility-model routing: an explicit
utilityModel (operator-chosen provider, like every utility task), else the
session provider's declared small-model default, honoring per-session model
overrides and auth profiles; utilityModel "" disables titles and malformed
refs fail closed — never the primary model. Tool inputs are redacted with the
tools-mode redactor before cache keys or prompts, caller ids are bounded and
never reach the model, and results cache in the per-agent SQLite
cache_entries so repeat views never re-bill.

Also completes two crestodian model-input mock factories that leaked into
sibling tests under shared-registry CI shards.

Fixes #103987

* fix(webui): redact tool-title inputs before truncation
2026-07-10 19:18:02 -07:00
qingminlong
6e0d590bd8 fix(agent-core): avoid a crash when empty output has a negative line limit (#103425)
* fix(agent-core): avoid empty truncation crash

* refactor(agent-core): simplify empty truncation handling

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
Co-authored-by: Peter Steinberger <peter@steipete.me>
2026-07-11 01:41:00 +01:00
Peter Steinberger
3ec2a50d6c fix(exec): prevent revoked policy from authorizing delayed node runs (#103950)
* fix(cli): fail closed on exec policy rollback races

* refactor(cli): reuse canonical exec policy ordering

* fix(exec): bind delayed approvals to prepared policy

* fix(macos): revalidate delayed exec approvals

* fix(exec): align approval snapshot validation gates
2026-07-11 01:37:37 +01:00
Peter Steinberger
a0354e5243 fix(onboarding): make fresh AI setup reliable and transparent (#103962)
* fix(onboarding): harden inference setup

* fix(mac): preserve setup request cancellation

* test(crestodian): align setup audit expectation

* test(crestodian): cover approval persistence warning

* fix(crestodian): preserve setup credentials and success

* chore(pr): leave changelog to release flow

* fix(onboarding): repair native CI gates
2026-07-10 23:44:53 +01:00
Peter Steinberger
d92d5774f5 fix(node): report Mac exec policy defaults (#103945) 2026-07-10 22:07:44 +01:00
Peter Steinberger
1bcc4c5e70 feat(gateway): add cooperative host suspension (#103618)
* feat(gateway): add cooperative suspension preparation

* style: satisfy suspension lint checks

* test(gateway): reset work admission between shared suites

* fix(gateway): reject upgrades during suspension

* fix(gateway): preserve admitted work during suspension

* test(gateway): isolate suspension and restart state

* fix(gateway): close suspension false-ready gaps

* refactor(protocol): slim suspension declaration graph

* refactor(plugin-sdk): sever protocol registry edges

* fix(gateway): preserve admitted restart follow-ups

* fix(gateway): make suspension recovery fail closed

* fix(protocol): keep validation formatter re-export only

* test(gateway): simplify deferred fixture type

* style(gateway): clarify suspension entry name

* fix(gateway): retain detached work admission
2026-07-10 20:24:53 +01:00
pick-cat
fd5b121510 fix(terminal): strip no-argument C1 CSI sequences in sanitization (#103707)
* fix(terminal): strip no-argument C1 CSI sequences in sanitization

* test(agents): align shell-utils incomplete ANSI assertion with C1 CSI sanitization

* fix(terminal): parse CSI sequences without leaking output

* fix(terminal): preserve stripAnsi callback contract

* fix(terminal): sanitize Codex approval previews

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-10 19:57:14 +01:00
Peter Steinberger
5aea34ad8c fix(webui): keep tool activity paired without model calls (#103821)
* fix(webui): make tool activity rendering deterministic

* fix(protocol): remove stale tool-title models

* fix(i18n): translate tool activity labels

* fix(i18n): translate tool activity labels
2026-07-10 18:21:08 +01:00
Peter Steinberger
c8ebfd8a3a fix(security): preserve UTF-16 token mask boundaries (#103843) 2026-07-10 18:20:05 +01:00
qingminlong
3a64889d83 fix(agent-core): report correct JSONL entry line after blank rows (#103645)
* fix(agent-core): report jsonl entry physical line numbers

* fix(agent-core): preserve physical JSONL line numbers

* test(agent-core): keep JSONL cleanup lint-safe

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-10 18:12:56 +01:00
Peter Steinberger
e484bdd993 fix(memory-host): keep redacted token hints UTF-16 safe (#103813)
Completes the sibling memory-host masker missed by #103341.

Co-authored-by: 张贵萍0668001030 <zhang.guiping@xydigit.com>
2026-07-10 17:43:37 +01:00
Peter Steinberger
97bbbc2271 feat(agents): derive a provider-declared default utility model when unset (#103769)
* feat(agents): derive a provider-declared default utility model when unset

When agents.defaults.utilityModel is not set, utility tasks (titles, progress
narration) now use the primary provider's declared small model
(modelCatalog.providers.<id>.defaultUtilityModel: OpenAI -> gpt-5.6-luna,
Anthropic -> claude-haiku-4-5). Auth is inherent because derivation follows
the agent's primary provider. Setting utilityModel to an empty string
disables utility routing entirely; narration turns on automatically when a
default resolves and stays off otherwise.

Formatting/lint/tests verified on Testbox (oxfmt, oxlint, plugins:inventory,
docs:map, import-cycles, check:test-types, 4 test files).

* fix(ai): drop the temperature parameter for models that reject it

The GPT-5.6 family 400s on temperature via the Responses API (live-verified:
gpt-5.6-luna/-terra reject it; gpt-5.5 and gpt-5.4-mini/nano accept it).
supportsOpenAITemperature gates all three OpenAI payload builders, with a
catalog compat override (compat.supportsTemperature) declared for the 5.6
family in the openai manifest. Without this, utility tasks (titles,
narration) would fail once gpt-5.6-luna becomes the derived default.

Gates on Testbox: oxfmt, oxlint, plugins:inventory, import-cycles,
check:test-types, 6 test files. Live proof on Testbox: gpt-5.6-luna and
claude-haiku-4-5 one-shot completions succeed with temperature requested.

* fix(agents): carry the primary model's auth profile onto the derived utility default

A primary like openai/gpt-5.5@work previously reached utility tasks via the
profiled fallback; the derived default shares the provider, so its trailing
auth profile carries over instead of silently switching to default
credentials (Codex review). Gates on Testbox: oxfmt, check:test-types, tests.

* docs: realign the manifest provider-fields table after adding defaultUtilityModel
2026-07-10 17:40:11 +01:00
Peter Steinberger
fc2afc83da feat(webui): redesign tool-call rendering with inline diffs, group summaries, and cheap-model purpose titles (#103748)
Kind-aware tool rows (terminal-style commands with wrapper stripping and
display highlighting, file edits with inline numbered diffs and diffstat,
write previews, key-value args), aggregate group summaries with live run
status, and a new batched chat.toolTitles gateway RPC that titles complex
calls via the configured utilityModel or the OpenAI Luna default (gated to
OpenAI-primary agents, cached in the per-agent SQLite cache_entries).

Also fixes two transcript pairing bugs: result blocks now inherit call
id/name/details at merge time, and results pair with any open call in the
current tool run so parallel calls render as single rows.

Fixes #103554
2026-07-10 17:26:22 +01:00
Peter Steinberger
48b0f4edf5 feat(gateway): session worktree targeting, branch listing, and server-side session groups (#103432)
* feat(gateway): session worktree targeting, branch listing, and group catalog

- sessions.create accepts worktreeBaseRef/worktreeName (write scope) and
  execNode (admin); worktree binding persists on the session entry as
  worktree { id, branch, repoRoot } and projects onto session rows with
  execNode so UIs can show checkout/branch/node state
- new worktrees.branches RPC lists local/remote branches (no fetch) for
  base-ref pickers; worktrees.remove now reports snapshotError
- sessions.delete reports preserved dirty checkouts as worktreePreserved
- gateway-owned session group catalog in the shared state DB with
  sessions.groups.list/put/rename/delete; rename/delete update member
  categories server-side without bumping recency; sessions.patch absorbs
  ad-hoc categories into the catalog
- group session display names prefer the human chat title (subject or
  space #channel) over stored compact tokens

Part of #103431

* fix(gateway): route group category updates through the session accessor and regen protocol models

- bulk member-category rename/clear uses applySessionEntryReplacements
  instead of legacy updateSessionStore call sites (session accessor
  boundary guard)
- regenerate Swift GatewayModels for the worktrees.branches schemas,
  snapshotError, and new sessions.create params

Part of #103431

* fix(gateway): resolvable remote branch refs and workspace-scoped branch listing

- worktrees.branches returns remote-only branches remote-qualified
  (origin/feature-a) so every advertised name works as a worktree base ref
- write-scoped worktrees.branches callers are limited to configured agent
  workspaces; other host paths require operator.admin, matching the
  sessions.create cwd bar

Part of #103431

* fix(gateway): guard worktree name reuse by owner and env-scope group transactions

- managedWorktrees.create rejects a caller-chosen name whose live or
  restorable record belongs to a different owner, so write-scoped
  sessions.create cannot bind a session into another session's or a
  manual checkout
- session group catalog writes run their SQLite transaction on the same
  env-scoped handle as their statements, keeping OPENCLAW_STATE_DIR
  overrides atomic and away from the default state DB

Part of #103431
2026-07-10 15:51:35 +01:00
JC
59e95fe3fd feat: support GPT-5.6 Ultra across OpenClaw and Codex runtimes (#98021)
* feat: support GPT-5.6 Ultra across agent runtimes

Co-authored-by: J Cai <anyech@gmail.com>

* fix: keep harness projections discovery-free

* fix(codex): mirror V2 native subagent tasks

* chore: refresh plugin SDK surface budgets

* test: expose Ultra wire effort proof

* test(cron): avoid hoisted mock initialization race

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-10 15:23:24 +01:00
Yuval Dinodia
b7ab62c2cf fix(mattermost): preserve text-block boundaries in draft preview (#87322) (#87449)
* fix(mattermost): preserve text-block boundaries in draft preview (#87322)

* fix(mattermost): preserve block preview boundaries

* fix(mattermost): reset progress at tool boundaries

* docs(plugin-sdk): refresh API baseline

* fix(mattermost): group parallel tool previews

* fix(mattermost): stage tool previews before awaits

* fix(mattermost): satisfy tool boundary return contract

* fix(mattermost): serialize preview block generations

Co-authored-by: Yuval Dinodia <yetvald@gmail.com>

* fix(mattermost): preserve complete block previews

* test(agents): align streaming assertions

* test(telegram): align reply pipeline mock

* fix(plugin-sdk): keep reply prefix options compatible

* test(mattermost): exercise threaded final participation

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-10 14:32:11 +01:00
Peter Steinberger
a13d2c4c93 fix(terminal): strip C1 OSC payloads from output (#103672) 2026-07-10 13:02:21 +01:00
Peter Steinberger
401f278f11 feat: add Control UI plugin management (#103176)
* feat(ui): add plugin catalog management

* feat(gateway): add plugins.uninstall and richer plugin catalog metadata

Adds a plugins.uninstall gateway method (operator.admin, control-plane write)
backed by a lock-guarded uninstallManagedPlugin that mirrors the CLI flow:
config cleanup, install-record removal, managed file deletion, and registry
refresh. Bundled plugins stay disable-only. Catalog entries now carry a
manifest-derived category and a removable flag; ClawHub search results expose
download counts and verification tiers.

* feat(ui): redesign plugins page with inventory, store shelves, and cover art

Rebuilds /settings/plugins around three tabs: Installed (category-grouped
inventory with overview stats, state filters, uninstall for external plugins,
and inline MCP server management through the shared config seam), Discover
(featured/official shelves plus one-click MCP connectors and curated ClawHub
searches), and ClawHub (search with download counts and verification badges).
Every catalog entry renders bundled cover art or a deterministic gradient
monogram tile - no more empty boxes. Artwork generated with Codex CLI, shipped
as 512px WebP under ui/public/plugin-art.

* chore(ui): regenerate locale bundles for plugins manager strings

* docs: describe plugins manager tabs, uninstall, and MCP connectors

* fix(plugins): human catalog labels and un-pinned hosted fallback ids

listManagedPlugins now prefers manifest names over registry package-name
backfill, falls back to channel catalog labels and blurbs, and stops pinning
expectedPluginId when a hosted feed entry only exposes its package name
(which rejected every legitimate install of that package). Found via live
gateway testing against ClawHub.

* fix(ui): send minimal RFC 7396 merge patches for MCP server edits

config.patch merges rather than replaces, so key removal needs an explicit
null; sending the full config back made MCP server removal a no-op. Found
via live gateway testing.

* fix(ui): write explicit MCP transports for URL servers

The MCP runtime defaults URL-only servers to SSE, so streamable HTTP
endpoints saved by the add form or connector templates would fail at
connect time. Connector templates now declare their transport and the
add form infers streamable-http unless the URL follows the /sse
convention. Flagged by autoreview against the transport resolver.

* test(ui): wait for deferred plugin requests before resolving in e2e

* feat(ui): plugins detail view, action menus, and unified ClawHub search

Reworks the plugins page from PR #103176 feedback: merges the ClawHub tab into
Discover (typing searches ClawHub inline and appends a quiet From ClawHub
section, with Browse ClawHub demoted to a header text link), makes every row and
store card open a plugin detail overlay (hero art, primary enable/install
action, metadata table), and replaces enable/disable switches with a state chip
plus an overflow menu (Enable/Disable, Remove for external plugins, View
details) matching the ChatGPT-store install+menu pattern. MCP rows use the same
menu; refresh is now icon-only.

* chore(ui): regenerate locale bundles for plugins UI iteration

* feat(ui): vetted, grouped connector catalog for the plugins store

Expands Connect your world to 28 connectors organized into use-case shelves
(Work & productivity, Coding & infrastructure, Home & media, Everyday life).
Every entry passed a three-stage subagent review: official-docs verification
plus live endpoint probes for MCP servers, ClawHub result-quality and
malware/typosquat screening for curated searches, and an adversarial pass
that dynamically registered OAuth clients to prove one-click viability.

That review removed Figma (registration allowlisted, 403) and Atlassian
(OAuth issuer-mismatch bug upstream), downgraded GitHub to PAT-based setup
(no dynamic client registration upstream), fixed Linear (/sse retired) and
Home Assistant (/api/mcp, streamable HTTP) endpoints, retargeted poisoned or
dead searches (youtube, finance, hue dropped; calendar -> google calendar;
stocks replaces finance), and added Todoist, Airtable, Canva, Stripe,
Context7, DeepWiki, Hugging Face one-click MCP servers plus Jira, PDF,
transcription, Kubernetes, Reddit, maps, translation, and notes searches.
Keyless servers get a ready-to-use success message; new cover art included.

* chore(ui): regenerate locale bundles for connector groups

* fix(plugins): suppress hosted catalog rows once their package is installed

Hosted feed entries without a declared runtime id fall back to their package
name as catalog id, which never matches the installed runtime id, so the
Discover shelf kept offering an already-installed package. Installed package
names now also suppress official rows. Flagged by autoreview.

* fix(plugins): pin declared runtime ids and surface connector errors in place

The runtime-id pin now keys off explicitly declared catalog ids (plugin,
channel, or provider) instead of string-comparing against the package name,
so declared ids that equal their package name stay enforced while entry-id
fallbacks stay unpinned. Connector add failures on Discover now render on the
triggering card instead of the Installed tab's MCP section. Both flagged by
autoreview; regression tests included.

* feat(ui): full inventory artwork, pulse header, and two-column plugin list

Every bundled plugin now ships distinctive cover art (113 new Codex CLI
illustrations; 172 total, ~2.1MB WebP), so inventory rows and detail views
never fall back to monogram tiles. The four stat cards give way to a compact
inventory pulse: a segmented enabled/disabled/issues meter whose legend and
counts live inside the filter chips. Inventory, MCP, and search rows flow
into two columns when the panel is wide enough.

* chore(ui): regenerate locale bundles for pulse header

* fix(ui): omit stdio args from the MCP server row target

Stdio MCP args routinely carry tokens, and the inventory is visible to
read-only operators; mirror the config page and show only the command.
Flagged by autoreview; regression test included.

* fix(merge): point crestodian setup at relocated plugin commit/refresh modules

* fix(merge): add bootstrapToken to plugins page test gateway harness

* fix(plugins): name catalog install-action branches so Swift emits the union

* fix(ui): satisfy strict lint on plugins page form parsing and mocks

* chore(build): regen docs map, raise plugin-sdk declaration budget for new protocol surface

* fix(ui): type the plugins page patch mock with its real call signature
2026-07-10 11:56:44 +01:00
heichl_xydigit
7eacd78c01 feat(devices): rename command for durable human-friendly device names (#94517)
Paired devices can now carry a durable operator-assigned label: device.pair.rename { deviceId, label } (schema-bounded, admin/ownership-gated) stores an operatorLabel that persists in the shared SQLite state DB, survives device repair and re-approval, and takes display precedence over the client-reported name in CLI devices list and the Control UI inventory (operatorLabel, then displayName, then clientId, then deviceId). The label was previously dropped on write because the pairing store had no column for it. CLI: openclaw devices rename --device <id> --name <label>. Docs cover the command and precedence.

Fixes #13870

Thanks to @bladin for the contribution.

Co-authored-by: heichl_xydigit <1740879+bladin@users.noreply.github.com>
Co-authored-by: Ayaan Zaidi <hi@obviy.us>
2026-07-10 15:05:41 +05:30
Peter Steinberger
ab5d143d59 feat(openai): default new setups to GPT-5.6 (#103581)
* feat(openai): default fresh setup to GPT-5.6

* test(crestodian): expect GPT-5.6 Codex defaults

* test(crestodian): expect GPT-5.6 bootstrap default
2026-07-10 10:22:58 +01:00
Peter Steinberger
2c909212f1 fix(tool-call-repair): preserve stream content order after repair (#103585)
Keep byte-over-cap visible suffixes at their streamed content indexes when terminal message snapshots are normalized.

Co-authored-by: ZOOWH <ZOOWH@users.noreply.github.com>
2026-07-10 10:16:09 +01:00
Peter Steinberger
b07ebe3ff3 feat: correlate managed agent requests (#103476) 2026-07-10 08:42:55 +01:00
wuqxuan
9e74dabad2 fix: parse zero-argument XML tool calls (#103220)
* fix: parse zero-argument XML tool calls

* fix(tool-call-repair): handle empty XML calls safely

---------

Co-authored-by: Peter Steinberger <peter@steipete.me>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-10 07:39:23 +01:00
Peter Steinberger
120385a88a fix(media-core): detect encoded URL extensions (#103410)
Co-authored-by: VectorPeak <73048950+VectorPeak@users.noreply.github.com>
2026-07-10 06:50:01 +01:00
Peter Steinberger
461772868d fix(computer): prevent stale, replayed, and post-cancel desktop actions (#103422)
* fix(ai): preserve streamed tool-call identity

* fix(computer): bind actions to current tool authority

* fix(macos): serialize computer control lifecycle

* docs(computer): document hardened control contract

* chore: follow release-owned changelog policy

* test(agents): cover node list cancellation
2026-07-10 06:47:56 +01:00
LZY3538
939d0ef45d fix(ai): cache and case-insensitively match Azure deployment map (#103005)
* fix(ai): cache and case-insensitively match Azure deployment map

resolveAzureDeploymentNameFromMap re-parsed the deployment-map string into
a new Map on every call (a hot path: streams and lifecycle hooks) and
looked model ids up case-sensitively. A request for `GPT-4o` against a
`gpt-4o=deployment-gpt-4o` map therefore fell back to the raw model id and
404'd on Azure ("deployment not found").

Cache the parsed lookup map keyed by the raw deployment-map string (bounded
so memory stays flat) and normalize keys to lowercase so lookups are
case-insensitive. Deployment names (the values) stay verbatim because Azure
requires the exact deployment name, and the fallback still returns the
original-cased model id.

Fixes #102936

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(ai): prefer exact-case match, case-insensitive only as fallback

Addresses review: lowercasing every key regressed configs whose deployment
map distinguishes keys by case (e.g. `GPT-4o=prod-a,gpt-4o=prod-b`), where an
exact `GPT-4o` request previously resolved to `prod-a` but would now collapse
to the last lowercased entry.

Cache an exact-case lookup alongside the lowercased one and resolve exact
first, using the case-insensitive map only as a fallback. Every previously
working exact mapping is preserved; the case-insensitive path only rescues
ids that would otherwise 404. Adds a regression test for exact-case
precedence.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* test(ai): prove Azure deployment map resolves on the real provider path

Adds an integration test that drives the real streamSimpleAzureOpenAIResponses
path against a loopback server (via the AI transport host fetch) and asserts the
deployment name resolved from AZURE_OPENAI_DEPLOYMENT_NAME_MAP is what lands in
the outgoing request `model` field — the value Azure routes on, and the source
of the reported 404 when it fell back to a mixed-case model id.

Covers the mixed-case fix (GPT-4o -> deployment-gpt-4o on the wire) and the
exact-case no-regression case (GPT-4o -> prod-a).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* test(ai): use block-body promise executors to satisfy oxlint

no-promise-executor-return flagged the arrow executors around server
listen/close; use statement bodies so nothing is returned from the executor.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* refactor(ai): simplify Azure deployment lookup

* refactor(ai): simplify Azure deployment lookup

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Peter Steinberger <peter@steipete.me>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-10 06:38:39 +01:00