* feat(ios): refine control and talk visual hierarchy
* feat(ios): refine control and talk visual hierarchy
* feat(ios): refine control and talk visual hierarchy
* fix(cli): explain how to recover from device approve deadlock
`openclaw devices approve` could fail two ways with no path forward:
- When the calling device can't approve its own scope upgrade (it lacks
operator.approvals) and no loopback local fallback is available (e.g. a
remote --url gateway), the raw "scope upgrade pending approval" error
propagated with no guidance.
- When the request id wasn't found in pending state (already approved,
expired, or superseded), it printed only "unknown requestId".
Surface actionable guidance instead:
- On an authorization failure, explain that the device can't approve its
own upgrade and point to `--token`/`--password` (gateway owner creds) or
approving from a device that already holds operator.approvals.
- On a missing request, point to `openclaw devices list` and
`openclaw devices approve --latest`.
AI-assisted (Claude Code).
* fix(cli): clarify device approval recovery
* fix(cli): avoid unusable approval credential advice
Summary:
- The branch adds bundled skill-creator guidance to route durable OpenClaw skill work through Skill Workshop proposals and removes the direct `init_skill.py` scaffold helper plus its test.
- PR surface: Docs +6, Other -429. Total -423 across 3 files.
- Reproducibility: yes. source-level: current main has `init_skill.py` writing a live `SKILL.md` directly, whi ... `. I did not run the direct helper as a repro because this review was read-only and that path writes files.
Automerge notes:
- No ClawSweeper repair was needed after automerge opt-in.
Validation:
- ClawSweeper review passed for head 8eca165447.
- Required merge gates passed before the squash merge.
Prepared head SHA: 8eca165447
Review: https://github.com/openclaw/openclaw/pull/98346#issuecomment-4849855806
Co-authored-by: momothemage <niuzhengnan@163.com>
Approved-by: momothemage
The in-loop context-overflow guard (installToolResultContextGuard) sizes
transcript messages via estimateMessageChars, which only handled user,
assistant, and toolResult roles. Harness roles (bashExecution,
compactionSummary, branchSummary, custom) fell through to a flat 256-char
return, causing the guard to undercount summary- and bash-dominated
context by orders of magnitude.
This is the sibling defect of the just-merged #97861 which fixed the same
class in estimateMessageTokenPressure (the pre-prompt precheck). This
commit applies the identical pattern to the live in-loop guard estimator.
Fixes#97927
matchLevelDirective consumed the token after a level directive
(/think, /verbose, /trace, /fast, /reasoning, /elevated) as the level
argument unconditionally, and extractLevelDirective stripped it from the
body whether or not it was a valid level. So a message like
"/verbose explain quantum computing" reached the agent as
"quantum computing", silently dropping the user's first word, and the
whitespace scan crossed newlines so "/verbose\nSummarize this" lost
"Summarize".
Treat the trailing token as the directive argument only when it
normalizes to a valid level or is the sole remaining token (preserving
the unrecognized-level hint and the default/inherit clear sentinels).
When two or more words follow, the directive acts argument-less and the
message text is preserved intact, matching the exec and queue parsers
that stop at an unrecognized token.
The gateway agent.run freshness decision called evaluateSessionFreshness
directly at both of its decision sites with no provider-owned guard, so a
provider-owned CLI session (claude-cli, codex, gemini-cli) under the default
reset config was rotated after the daily boundary when a turn ran through the
gateway path (webchat, openclaw agent, ACP, control UI, cron, heartbeat). The
rotation cleared the CLI session binding and split the transcript, violating
the documented exemption that the inbound auto-reply path and the canonical
session helper already honor.
Route both gateway freshness decisions through the same
resetPolicy.configured !== true && hasProviderOwnedSession(entry) skip the
inbound path uses, and export hasProviderOwnedSession so the predicate has one
shared definition instead of a third copy. Explicit session.reset and /reset
still cut these sessions.
Summary:
- Merged fix: show in-progress status for channel runs after ClawSweeper review.
Automerge notes:
- No ClawSweeper repair was needed after automerge opt-in.
Validation:
- ClawSweeper review passed for head 08eec41769.
- Required merge gates passed before the squash merge.
Prepared head SHA: 08eec41769
Review: https://github.com/openclaw/openclaw/pull/98257#issuecomment-4849525931
Co-authored-by: scotthuang <scotthuang@tencent.com>
Approved-by: takhoffman
* fix(agents): keep merged delivery routes account-bound
mergeDeliveryContext gated route-field crossing on channel only, so a
completion origin that knew its account but not a concrete target
inherited a different account's to/threadId on the same channel. A
subagent, cron, or media completion for bot-a could be addressed to
bot-b's chat but sent through bot-a (cross-account misroute) or dropped.
This restores the account-bound guard added in 1ed8592467 and removed as
collateral by 025db6cf9e (PR #89949); same-account and missing-account
merges still backfill so the media route-pin path is preserved. Restores
the deleted regression test.
* fix(agents): centralize account-bound completion routes
---------
Co-authored-by: Peter Steinberger <steipete@golden-gate.local>
* 'main' of https://github.com/openclaw/openclaw: (29 commits)
refactor(gateway): trim attach grant implementation
feat(gateway): scoped attach grants for external MCP loopback clients
fix(gateway): iOS Talk treats SecretRef-backed API keys as missing (#98210)
test(infra): add unit tests for SQLite number normalization (#98009)
test(config): add unit tests for resolveExecCommandHighlighting (#98087)
test(utils): add unit tests for chunkItems (#98219)
fix(core): propagate caller env PATHEXT through isExecutableFile on Windows (#98093)
fix(matrix): guard JSON.parse against malformed homeserver response bodies (#97973)
fix(sms): guard Twilio JSON.parse against malformed API response bodies (#97999)
Add Swedish mobile app localization (#98043)
fix(anthropic): surface Discord pre-tool commentary
fix(tui): correct disconnect copy for device scope upgrades (#98144)
chore(ui): refresh fa control ui locale
chore(ui): refresh nl control ui locale
chore(ui): refresh vi control ui locale
chore(ui): refresh th control ui locale
chore(ui): refresh pl control ui locale
chore(ui): refresh uk control ui locale
chore(ui): refresh id control ui locale
chore(ui): refresh tr control ui locale
...
Per-session, TTL-bounded, revocable bearer grants (mcp-grant-store) let an external/interactive
harness reach the gateway's scoped MCP loopback tools without the cli-backend's process-global
token. A grant is a lower-trust boundary: it binds the session server-side AND fail-closes on every
caller-supplied context header (x-session-key plus message-channel/account/current-channel/thread/
source-reply/event-kind), so a grant holder can neither scope-shop the session nor spoof
delivery/action context into scoped tools or the message tool. New attach.grant/attach.revoke
operator methods mint/revoke grants and return the loopback MCP config. Owner/non-owner cli-backend
path unchanged.
* fix(core): propagate caller env PATHEXT through isExecutableFile on Windows
isExecutableFile hardcoded undefined when calling resolveWindowsExecutableExtSet,
ignoring any caller-provided custom env.PATHEXT. This meant resolveExecutablePath
and resolveExecutableFromPathEnv would fall back to process.env.PATHEXT even when
the caller supplied a different env with an extended PATHEXT (e.g. .PS1).
- Add optional options.env parameter to isExecutableFile
- resolveWindowsExecutableExtSet now reads from options?.env
- All 3 callers pass their available env through
Affects Windows deployments using sandbox/container environments where
PATHEXT differs from process.env (Docker Windows containers, CI runners, tests).
Fully backward compatible: undefined env falls back to process.env.PATHEXT.
* fix(core): also propagate caller env PATHEXT in node-host invoke resolver
- Fix sibling system.which resolver in src/node-host/invoke.ts:378
to use caller env PATHEXT instead of process.env only
- Add comprehensive Windows-mocked tests for caller env PATHEXT
propagation through isExecutableFile, resolveExecutableFromPathEnv,
and resolveExecutablePath
- Tests cover: custom env accepted, fallback to process.env,
path-separator and PATH-based resolution paths
* fix(core): also propagate caller env PATHEXT through node-host invoke resolver
- Add env?.PathExt and process.env.PathExt casing to both
resolveWindowsExecutableExtSet and resolveWindowsExecutableExtensions
for compatibility with callers using PascalCase env keys
- Isolate positive PATHEXT tests from process.env.PATHEXT by
explicitly setting it to .TXT before each test, ensuring they
prove caller env propagation rather than host env leak
* fix(core): add env?.PathExt casing to node-host system.which resolver
---------
Co-authored-by: wendy-chsy <wan.wenyan@xydigit.com>
Wrap JSON.parse(text) in MatrixAuthedHttpClient.requestJson with try/catch to prevent a malformed Matrix homeserver response from throwing an unhandled SyntaxError.
On parse failure, throw an Error with statusCode attached (matching the buildHttpError convention) so callers can handle it like any other Matrix API error.
Signed-off-by: lsr911 <liao.shirong@xydigit.com>
Co-authored-by: Claude <noreply@anthropic.com>
Wrap JSON.parse in parseTwilioListPayload and retrieveTwilioMessagingService with try/catch to prevent a malformed Twilio API response from throwing an unhandled SyntaxError.
- parseTwilioListPayload: return [] on parse failure (fail-safe for phone number listing)
- retrieveTwilioMessagingService: throw descriptive Error on parse failure
Note: parseTwilioApiError and parseTwilioSuccessPayload already had try/catch guards (lines 85-97, 104-121).
Signed-off-by: lsr911 <liao.shirong@xydigit.com>
Co-authored-by: Claude <noreply@anthropic.com>
* fix(tui): correct disconnect copy for device scope upgrades
On disconnect, the TUI told users "Pairing required. Run `openclaw devices
list`, approve your request ID, then reconnect." This is misleading: the
gateway is asking for a device *scope upgrade* (the device is already
paired), and "pairing" points users at `openclaw pairing`, which only
handles chat DM pairing — a different subsystem.
- Reword the hint to name the scope upgrade and the actual recovery command
(`openclaw devices approve --latest`), including the `--token`/`--password`
escape hatch for when the device can't approve its own upgrade.
- Also match the gateway's "scope upgrade" disconnect reason, not just
"pairing required".
AI-assisted (Claude Code).
* fix(tui): clarify device approval preview hint