Commit Graph

10061 Commits

Author SHA1 Message Date
Peter Steinberger
abfe7c64a7 docs(install): recommend Node 26 as the OpenClaw runtime (#114399)
* docs(install): recommend Node 26; CI/installer stay on Node 24 for now

* feat(cli): point unsupported-runtime nvm hint at Node 26

* feat(install): provision Node 26 by default (brew mainline node formula, NodeSource 26.x, portable win zip)

* test(install): align installer tests with Node 26 provisioning defaults

* docs(install): state per-platform Node provisioning accurately
2026-07-27 04:32:21 -04:00
Peter Steinberger
af552d4bc6 feat(ui): resolve session URLs through the gateway with best-effort slug matching (#114422)
* feat(ui): resolve session URLs through the gateway with best-effort slug matching

Session URLs now resolve a stored board face and a display-name slug through
the gateway instead of guessing from the browser's cached session page.

- An uncached open marks only the in-app navigation, never the shareable href,
  so the chat loader can re-derive the face and replace the URL.
- A cached row settles the lookup locally, keeping navigation off the wire.
- A one-segment reference resolves short id, then literal key, then display-name
  slug; ties reuse the existing disambiguation view.

* refactor(ui): keep slug ties on short disambiguation prefixes

Slug candidates reused the full uuid, which produced 32-character links in the
disambiguation view. uniqueShortIdPrefix already falls back to the full id when
the bounded search was truncated, so reuse it and drop the flag.

* fix(ui): navigate worktree owner links in-app so the face marker survives

The Worktrees owner link was a bare anchor consuming only the shareable href,
so preferenceDerivedFace was a no-op there and an uncached owner always opened
on chat. Match the other session surfaces: keep the clean href and navigate
with the options on plain clicks.

* fix(ui): search the first uuid block so long session references resolve

The gateway matches sessions.list search as a plain substring and stored keys
hold a hyphenated uuid, so any hyphen-stripped reference past the first block
matched nothing and 404'd. This hit disambiguation links, which offer prefixes
longer than eight characters. Send the first block and keep applying the full
prefix per row.

A resolved slug now canonicalizes to that same short reference instead of a
full uuid, so /chat/main/deploy-monitor settles on -6db92d48.

* docs(ui): record why the face marker stays out of shareable hrefs
2026-07-27 04:31:33 -04:00
Peter Steinberger
669db2968f refactor(agents): retire TOOLS.md into an AGENTS.md section with a doctor migration (#113966)
* fix(agents): stop retired attestation hashes from faking a vanished workspace

* feat(agents): migrate TOOLS.md content into the AGENTS.md tools section

* refactor(agents): drop TOOLS.md from the workspace bootstrap set

* refactor(policy): read tool policy entries from AGENTS.md

* docs: describe local tool notes as an AGENTS.md section

* test(codex): drop TOOLS.md developer-instruction coverage with the removed path

* test(agents): cover the TOOLS.md doctor migration behaviors

* refactor(doctor): satisfy TOOLS.md migration lint

* test(agents): split workspace attestation survival coverage

* refactor(codex): simplify workspace context basenames

* refactor(doctor): keep TOOLS.md migration helpers module-local

* docs: regenerate docs map

* fix(doctor): keep migration claims fresh

* fix(doctor): preserve nested tool notes

* refactor(doctor): split tools migration helpers

* refactor(doctor): limit TOOLS.md migration to workspace root

* style(doctor): keep migration under line limit

* fix(doctor): recover interrupted AGENTS publish

* docs(hooks): describe root-only TOOLS.md migration accurately

* fix(doctor): preserve migrated tool guidance visibility

* test(agents): regenerate prompt snapshots after rebase

* fix(policy): block evaluation while TOOLS.md is unmigrated

* fix(doctor): check merged bootstrap budget per agent

* fix(doctor): keep budget helper internal

* refactor(doctor): keep migration budget helpers to their consumers
2026-07-27 03:56:30 -04:00
Santhi Prakash
445774d85e [AI-assisted] docs(senseaudio): fix broken Docs URL to docs.senseaudio.cn (#114021)
The SenseAudio provider guide linked its Docs row to
https://senseaudio.cn/docs, which returns 404. The SenseAudio platform
homepage itself links to https://docs.senseaudio.cn (200), so point the
Docs row there instead.
2026-07-27 03:56:03 -04:00
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
Peter Steinberger
e9990b818a feat(cli): add models auth logout (#114407) 2026-07-27 03:48:27 -04:00
Peter Steinberger
65cce37480 fix(codex): keep user-home app-servers on native Codex auth (#114397)
A prepared OpenClaw auth handoff was still resolved for connections that
target the operator's native Codex home, so every turn failed with
"Prepared Codex auth requires an isolated app-server home." once a stored
OpenAI profile produced a prepared model route. User-home mode now keeps
its native account for both subscription and Platform routes, matching the
documented contract; the shared-client guard stays as the backstop.
2026-07-27 03:19:06 -04:00
Peter Steinberger
3a4f337802 fix(gateway): connect first-boot loopback agents after readiness (#114380)
* fix(gateway): pair local CLI before runtime-token readiness

* docs(gateway): explain first-boot loopback CLI auth

* fix(gateway): keep startup pairing result internal

* chore(gateway): leave release note to release process
2026-07-27 03:15:12 -04:00
Pavan Kumar Gondhi
33f44caa5d fix: restrict QQBot quoted context [AI] (#114136)
* fix: restrict qqbot quoted context

* fix: narrow qqbot bot quote exemption

* test: use valid qqbot ingress reasons

* fix: honor narrowed qqbot open dm quotes

* fix: honor narrowed qqbot open group quotes

* test: use valid qqbot blocked ingress decisions

* fix: honor qqbot quote visibility mode

* docs: mention qqbot context visibility

* fix: validate qqbot context visibility config

* fix: hide denied qqbot quote sender

* test: avoid unbound qqbot access mock

* test: allow auth migration isolation to finish

* Revert "test: allow auth migration isolation to finish"

This reverts commit f2b9a4f5e9.
2026-07-27 12:23:21 +05:30
Peter Steinberger
054495d16d fix(ci): verify stale bugs before closure (#114365) 2026-07-27 02:25:15 -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
Dallin Romney
9310586b09 fix(qa-lab): unify runner control plane (#112838) 2026-07-27 14:05:14 +08:00
Peter Steinberger
b5137604ef feat(cron): default agent turns to the current conversation, add /loop, tighten cron tool surface (#114328)
* feat(cron): bind agent turns to current sessions

* feat(commands): add loop chat command

* test(cron): cover session defaults and loop commands

* docs(cron): document current defaults and loops

* fix(commands): scope /loop status and stop by conversation name tag

* fix(commands): widen /loop conversation tag to 48 bits

* fix(commands): include disabled jobs in /loop status and stop

* docs(cron): regenerate docs map

* test(cron): split session-target default tests to satisfy max-lines
2026-07-27 01:44:38 -04:00
Peter Steinberger
fa28e9be8d fix(plugins): find installed external web-search providers on fresh installs (#114327)
* fix(plugins): stop treating a partial active registry as authoritative for web providers

An active plugin registry with some web providers used to win even when a
manifest-declared candidate (e.g. an npm-installed Brave plugin with
BRAVE_API_KEY set) was absent from it, so env-var auto-detect could never see
installed external search providers. Delegate to the coverage-checked
resolvePluginWebProviders path, which reuses the active registry only when it
covers every declared candidate.

* feat(agents): require explicit overwrite before replacing pre-existing files in the write tool

Blind writes to an existing path silently destroyed user content (observed as
WildClawBench safety-task data loss with weaker models). The write tool now
refuses to replace an existing differing file unless the call passes
overwrite:true or this tool instance already wrote that path, keeping
iterate-loops friction-free while making destructive replacement an explicit
model decision.

* docs(templates): make a concrete first-message task outrank the BOOTSTRAP.md birth sequence

A fresh workspace's birth ritual hijacked substantive first messages: agents
introduced themselves and asked for a name instead of doing the requested
work (worst with weaker models, which follow the ritual literally). State
task precedence explicitly at the top of the template.

* fix(agents): lead the write overwrite guard error with the safe protocol

Weak models retried immediately with overwrite:true when the flag came first
in the message. Order the guidance read -> rename -> overwrite-as-last-resort
so the destructive path requires an explicit judgment call.

* refactor(agents): replace the write overwrite flag with a confirm-by-resend gate

The overwrite:true escape hatch let weak models bulldoze reflexively and grew
the tool schema. The first write to a differing pre-existing file now returns
that file's content (head-clipped) and a resend of the identical write, issued
after the warning, against byte-identical existing content confirms the
replacement. Fingerprints hash raw bytes; oversized files fall back to
size+mtime (named tradeoff); missing metadata fails closed.

* revert(agents): restore plain overwrite semantics in the write tool

The overwrite gate (flag, then confirm-by-resend) was overfit to one
WildClawBench safety rubric: the guarded model still chose to overwrite and
still scored zero, while every real overwrite in normal sessions paid a
round-trip. Write means write; peers (Pi, Hermes) agree.

* test(agents): drop the stale overwrite arg from the write output-contract test
2026-07-27 01:32:04 -04:00
Peter Steinberger
d413fbd8ec fix: Tool Search finds tools by how agents actually phrase requests (#114285)
* feat(agents): rank Tool Search with BM25 over names, descriptions, and parameters

Ranking was case-insensitive substring matching with hand-tuned weights, which
failed in ways that made tools unreachable rather than merely mis-ordered:

- "scheduling" found nothing against a tool described "Schedule a recurring
  task" — no stemming.
- "read" ranked spreadsheet_open, because "sp-read-sheet" contains it.
- A non-English query tokenized to zero terms, and the scorer returned 1 for
  every entry, so the model received an arbitrary alphabetical slice of the
  catalog presented as a ranked result.

Replace it with Okapi BM25 over a tokenizer that splits on Unicode word
boundaries, drops stopwords, and collapses light English inflection. Index
parameter names and descriptions too, which Codex (bm25 crate) and the Claude
API tool-search tools both do; a query like "repository" now reaches a tool
whose description never says it. Underscore-joined names index as both the whole
name and its parts.

A small query-expansion table bridges intent to description vocabulary ("look up
the price" -> search/web), which pure lexical overlap cannot do. It holds only
generic capability words, never plugin or vendor names.

Empty queries now score nothing instead of everything, and both `tool_search`
and the code-mode bridge tell the model to query in English, so the degenerate
case is steered away from rather than silently mishandled.

Untrusted schemas are still never traversed: parameters are indexed only for
`openclaw` entries, matching the boundary compactToolSearchCatalogEntry already
enforces by reporting MCP and client inputs as "unknown".

* fix(agents): undouble inflected consonants and state the real English contract

Autoreview caught two defects in the new stemmer and its documentation.

"running" stripped to "runn", which can never meet "run", so a tool named
task_runner described "Running tasks" became unreachable for the query "run" —
a regression the substring scorer did not have. English doubles the final
consonant before -ing/-ed/-er, so undo that, while keeping doubles that belong
to the root (call, process, off, buzz).

The English-only claim was also stronger than the code: the tokenizer keeps
Unicode letters, so a non-English query yields terms and can match. Rejecting
them would make a catalog that legitimately names a tool in another script
permanently unreachable, so the behavior stays and the wording now matches it —
catalogs are written in English, so other languages usually match nothing, and
the model is asked to query in English for that reason rather than because the
input is filtered. The previous test only proved an unrelated document scored
zero, so it is replaced by one that asserts each half directly.

* fix(agents): split camelCase, discount expansions, and stop trigger collisions

Three defects in the new tokenizer, all found by autoreview and all reproduced
before fixing.

`splitWords` lowercased before looking for boundaries, so `readFile` produced
only `readfil` and the natural query `read file` could not meet it. MCP catalogs
commonly use camelCase, and the old substring scorer matched those. Split case
transitions before lowercasing.

Expansion terms carried the same BM25 weight as words the caller typed, so
`weather` — which expands to search/web — could rank a general web tool above
the exact weather tool by matching two terms instead of one. Expansions are a
guess about how the catalog words a capability, so they now score at 0.35, and a
term the caller actually wrote keeps full weight even when an expansion repeats
it.

Trigger matching ran the document stemmer, which collapsed unrelated vocabulary:
`news` became `new`, so "open a new issue" silently acquired a web-search intent.
Triggers now normalize by singularization only, which leaves `news` intact, and
the table lists `reminder` explicitly rather than relying on the stemmer to
reach it.

* fix(agents): normalize -ies plurals and tier literal matches above expansions

`repositories` stemmed to `repositori` while `repository` stayed put, so the two
never met; `-ies` now normalizes back to `-y` in both the document stemmer and
the expansion triggers, which also lets `directories` and `memories` reach their
intended groups instead of stalling at `directorie`.

The 0.35 expansion discount is not sufficient on its own to keep a literal match
ranked first: BM25 sums per term, so a common literal like `weather` carries
little IDF while a short document collecting two rare expansions can outscore
it, and a small result limit then drops every tool matching the typed word.
Literal overlap is now reported per hit and ranked as a tier ahead of score, so
the discount orders within a tier rather than trying to carry the invariant.

Verified by running the ranker over the failing inputs rather than reasoning
about them; the first attempt at the trigger fix silently did not apply because
the formatter had reflowed the function, which the matrix run caught.

* fix(agents): keep non-plural -s words out of the plural stem rule

"news" stemmed to "new", which literal-matched every "Create a new ..." tool;
because literal overlap now outranks expansion-only hits, a search for news
returned creation tools instead of the web tool the query meant.

The collision is not unique to news — "status", "canvas", and "alias" are all
ordinary tool vocabulary here and all lose their meaning under the same rule, so
the exemption covers that class rather than the single reported word.

* fix(agents): restore the exact-name tier and keep `get` searchable

Two signals the old substring scorer had and BM25 alone does not.

It gave an exact name/id match +20, which flattening everything into one
document removed: querying a known tool name could rank a shorter entry that
merely mentions the word above the tool itself, and the result limit would then
drop the tool asked for. Exact name/id is now a sort tier ahead of literal
overlap.

`get` was in the stopword list, but it names real operations in a tool catalog.
Discarding it made `search("get")` empty and reduced "get issue" to "issue",
where a shorter delete_issue or update_issue entry can win on length
normalization. Capability verbs stay indexed.

* fix(agents): keep acronyms whole, both -ies readings, and stopword-named tools

* refactor(agents): keep the ranking types and entry-text helper module-local

Knip's hard-zero unused-export gate flagged WeightedTerm, RankedDocument,
LexicalIndex, and toolSearchEntryText: nothing outside their own modules
imported them. Narrowing the surface is what the repo asks for anyway.

The untrusted-schema test now drives ToolSearchRuntime.search instead of
calling toolSearchEntryText directly, which proves the boundary through the
real entry point. Verified it still bites: removing the source gate makes it
fail with "client properties must remain deferred".
2026-07-27 01:10:53 -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
joshavant
44378dd24a fix(channels): harden record session override 2026-07-26 23:15:06 -05:00
joshavant
d8de71258a refactor(channels): route bundled command replies 2026-07-26 23:15:06 -05:00
Peter Steinberger
a05cfd4756 feat(runtime): run OpenClaw under Bun runtimes that provide node:sqlite (#114256)
* feat(runtime): allow Bun runtimes that provide node:sqlite

* fix(process): drop execa buffer encoding under Bun spawn (Bun rejects non-spawn options)

* chore(process): cite oven-sh/bun#36049 in bun spawn workaround

* docs(install): bun with node:sqlite can run openclaw; bun install workspace caveat

* fix(process): clear execa buffer encoding under Bun without mutating read-only options
2026-07-26 23:44:09 -04:00
Peter Steinberger
e717d24c2e refactor(meetings): close manual action state (#114247) 2026-07-26 23:25:19 -04:00
Peter Steinberger
e71e4ac83e docs: explain why steering waits for the current tool-call batch (#114249)
* docs: explain why steering waits for the current tool-call batch

* docs: regenerate docs map for steering batch section
2026-07-26 23:10:24 -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
Jesse Merhi
6bbf1dd917 fix: open selected channel setup immediately (#113197)
* CLI: enter selected channel setup directly

* fix: keep channel direct entry resolution scoped

* fix: keep exact channel ids ahead of aliases

* test: clarify channel-only guided routing

* fix: align channel direct entry with current main
2026-07-27 03:30:15 +10:00
Peter Steinberger
cca5b14785 feat(ui): path-based session and dashboard URLs (#113883)
* feat(ui): path-based session and dashboard URLs

* docs(ui): document control UI URLs

* fix(ui): finalize session path routing

* feat(ui): anchor session URLs on stable keys

* docs(ui): clarify stable session URL identity

* fix(ui): resolve session prefixes with full prefix and pagination

Query sessions.list with the full supplied prefix instead of an eight-char
truncation, and paginate up to a bounded page count so longer disambiguation
links resolve instead of being reported ambiguous. Zero strict-prefix matches
now fall through to literal-key resolution rather than rendering an empty
ambiguity view.

Also document the ~dot/~dotdot segment escape: peer ids reach session keys
trimmed and lowercased only (src/routing/session-key.ts), so a literal '.' or
'..' segment is reachable and browsers would normalize it away.

* fix(ui): synchronize committed session routes

* test(ui): split native shell host coverage

* fix(ui): thread configured mainKey through session URL builders

Reserved-set disambiguation needs the operator-configured mainKey at runtime, so
thread it from agentsList through every session path builder and the ClickClack
control URL. Unambiguous non-hex single-segment rests now resolve literally while
short-id-shaped rests still fail closed, which restores ClickClack channel
compatibility detection and control-link reconciliation.

Also bound prefix-resolution retries, preserve catalog thread identity, and keep
draft state on ambiguous candidate links.

* fix(ui): repair session URL CI integration

* perf(ui): lazy-load session route resolution

* perf(ui): isolate session prefix resolution

* perf(ui): defer session path parsing

* perf(ui): defer session navigation startup

* fix(ui): preserve first-run and literal session navigation

* fix(ui): satisfy session routing type and export gates

* fix(clickclack): preserve unscoped control link agent

* style(ui): satisfy chat page line limit

* refactor(ui): move chat page helpers to owning modules

* fix(ui): preserve destination session route identity

* fix(ui): preserve agent identity in session routes

* fix(ui): escape dots in literal session path segments

encodeURIComponent leaves periods intact, so a literal key segment like
channel:release.js produced /chat/main/channel/release.js. In-app navigation is
intercepted by the SPA, but a refresh, an external link, or a ClickClack link
would be served as a static asset request and never reach the app.

pathForWorkboardBoard already escapes dots for this reason; mirror it in both the
session URL contract and the ClickClack encoder, route the agent id through the
same segment encoder, and pin the case in both shared vector tables.

* fix(ui): stop bootstrap after teardown race

* refactor(ui): centralize session navigation targets

* fix(ui): consume bootstrap teardown abort

* fix(ui): canonicalize configured main session routes

* fix(ui): preserve distinct session references

* fix(ui): redirect released session query links

* fix(ui): make bootstrap teardown abort-safe
2026-07-26 12:46:04 -04:00
Peter Steinberger
01f8bd9d12 fix(agents): resume interrupted turns without a recognized abort string (#114121) 2026-07-26 11:10:21 -04:00
Shakker
04cafe601b fix: make Buzz rooms usable by default (#113419) 2026-07-26 14:09:23 +01:00
Shakker
ffb00ca624 fix: register Buzz agent identities 2026-07-26 14:09:23 +01:00
Shakker
3e858a2a6f fix: streamline Buzz guided setup 2026-07-26 14:09:23 +01:00
Shakker
2478134fa6 fix: publish Buzz bot presence 2026-07-26 14:09:23 +01:00
Shakker
08eac200b3 fix: publish Buzz bot profile names 2026-07-26 14:09:23 +01:00
Shakker
0e0698b6bc fix: correct Buzz room authorization guidance 2026-07-26 14:09:23 +01:00
Shakker
2746e35f69 fix: complete Buzz channel contracts 2026-07-26 14:09:23 +01:00
Shakker
b6cb3b6d7d fix: verify Buzz room access during setup 2026-07-26 14:09:23 +01:00
Patrick Erichsen
aa0d3192d2 feat(channels): add Buzz channel plugin 2026-07-26 14:09:23 +01:00
Peter Steinberger
19a98c873c refactor(auth): finish SQLite-only auth profile cutover (#114033)
* refactor(auth): finish SQLite-only profile cutover

* test(auth): isolate SQLite shadow fixtures

* test(auth): satisfy OAuth refresh lint

* test(auth): infer legacy sidecar fixtures

* fix(auth): fail closed on unreadable stores

* fix(auth): recheck migration readiness on lookup

* fix(auth): preserve compatibility owner checks

* fix(auth): align SQLite cutover proof

* style(qa): format SQLite auth helpers

* fix(auth): recover interrupted SQLite migrations

* fix(auth): bind materialized SQLite refs

* style(auth): clarify receipt hash value

* fix(auth): preserve state-only OAuth routing

* fix(auth): snapshot receipted migration sources

* fix(auth): fail closed across recovery races

* fix(auth): close legacy recovery gaps

* fix(auth): serialize SQLite refresh recovery
2026-07-26 07:27:54 -04: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
27293aa273 feat(ui): gateway subtitle in the sidebar footer identity card (#114059)
* feat(ui): show gateway subtitle in sidebar footer

* chore: keep CHANGELOG release-only

* test(ui): fix indexed-access type in sidebar gateway case

* perf(ui): trim footer subtitle startup bytes

* perf(ui): trim gateway footer strings

* perf(ui): re-record startup baseline for gateway footer

* perf(ui): re-record startup baseline from Linux build
2026-07-26 05:23:42 -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
417bd3c88a feat(agents): derive default run concurrency from CPU count (#114047)
* feat(agents): derive default run concurrency from CPU count

* test(agents): pin lane-resume concurrency in suspension persistence case
2026-07-26 03:02:34 -04:00
Peter Steinberger
f0b7542a22 feat(mac): gateway menu-bar surfaces and Gateways main menu (#114038)
* feat(mac): add gateway menu surfaces

* docs(mac): document gateway menu surfaces

* test(mac): make dashboard frame assertions display-independent
2026-07-26 02:13:13 -04:00
Peter Steinberger
9dfb2a1318 fix: show native history in adopted Pi and OpenCode sessions (#114040)
* fix(plugins): import adopted catalog history into the OpenClaw transcript

Import native Pi and OpenCode history when a catalog session is adopted so the OpenClaw transcript reflects the full conversation immediately.

Mark imported user rows with mirrorOrigin because they are transcript mirrors, not new external turns. This preserves watcher deduplication and prevents adopted history from being reported as fresh upstream input.

* refactor(plugins): split catalog history importer

Keep the session catalog contract module leaf-like by moving transcript mutation into a dedicated runtime module. This breaks the registry-to-transcript import cycle while preserving the Plugin SDK entrypoint and importer behavior.
2026-07-26 02:09:48 -04:00
Peter Steinberger
f6131a4fbf build(deps): remove npm shrinkwrap; mirror pnpm lock into transient package locks (#114006)
* build(deps): remove npm shrinkwrap; mirror pnpm lock into transient package locks

npm 12 removed shrinkwrap (command + tarball/root loading). Delete all 82
committed npm-shrinkwrap.json files and stop publishing lockfiles; keep
pnpm-lock.yaml as the single reviewed dependency boundary. The generator
becomes scripts/generate-npm-package-lock.mjs and feeds plugin bundling via
a transient package-lock.json + npm ci (works on npm 11 and 12). Tarball
validation treats the published 2026.7.2 beta train as a shrinkwrap
transition; self-update npm detection now uses install topology instead of
the shipped shrinkwrap.

* fix(deps): repair lint, deadcode, and test-type lanes for the npm 12 migration

- sort integrity comparisons with an explicit comparator (oxlint)
- keep resolveBunGlobalNodeModules module-local (knip unused-export gate)
- model npm pack --json as npm<=11 array / npm 12 name-keyed object
- default calver destructuring in the tarball test fixture
2026-07-26 01:29:55 -04:00
Peter Steinberger
e935a008f8 docs(cli): cross-link agent exec from automation and policy pages (#114034) 2026-07-26 01:19:11 -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
5c7f7d198e fix(cerebras): prefer current Gemma 4 onboarding default (#114015)
* fix(cerebras): default onboarding to Gemma 4

* fix(cerebras): preserve existing primary on setup
2026-07-25 21:44:59 -07:00
Peter Steinberger
fc3476b116 fix(policy): drop retired config coverage entry (#114014) 2026-07-25 21:29:50 -07:00
Peter Steinberger
b2f6ecc2a9 chore(compat): date the annotated deprecation families and expose removal-pending debt (#114002)
* chore(compat): date the annotated deprecation families and expose removal-pending debt

Adds 10 dated compat-registry records for shipped deprecated surfaces that
previously had @deprecated annotations only (removeAfter 2026-10-01 per the
approved 60-day window), extends the beta5 session-store record with the
package-root aliases, surfaces removal-pending records with due dates,
blockers, and readers in the plugin boundary report, and converts undated
cleanup obligations (CI timing job, zizmor excessive-permissions, staged
Codex CI auth, memory-host legacy state dir, agent-DB schema-ladder floors)
into dated markers visible to the weekly dated-TODO sweep. Metadata,
diagnostics, and docs only - no runtime behavior change.

* fix(compat): keep extension src test paths out of core string literals

The core import guardrail forbids extensions/*/src/ path shapes in core
production string literals; cite the package-root google-meet test and the
registry test for official-plugin-export-aliases instead.
2026-07-25 21:01:20 -07:00
Peter Steinberger
69399b1cc3 feat(cli): add openclaw agent exec headless one-shot runner (#113988)
* feat(cli): add agent exec headless runner

* test(cli): align agent parent startup paths

* fix(cli): scope agent exec environment explicitly
2026-07-25 20:59:20 -07: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
48addb3d57 fix(kimi): refresh K3 catalog and add 256K variant (#113918)
* fix(kimi): retire k3[1m], add k3-256k, k3 now 1M

* fix(kimi): integrate K3 256K catalog split

* docs(kimi): correct K3 thinking-level ladder in thinking.md
2026-07-25 20:57:26 -07:00