* feat(onboarding): recommend plugins and skills from installed apps
Scan installed macOS apps during classic onboarding (TCC-free), gather
candidates from official catalogs + ClawHub search, let the configured
model pick genuine matches, and offer an opt-in multiselect install step.
Adds a device.apps node-host command (default-off sharing, Android-parity
envelope) so remote gateways can request a paired Mac's inventory, and a
wizard.appRecommendations kill switch. Custom setup-inference completions
no longer inherit the 32-token verification-probe output cap.
* feat(onboarding): recommend apps in guided flow
* fix(onboarding): harden app recommendations against ClawHub self-promotion
Third-party ClawHub skills are never pre-selected regardless of model tier
(publisher-controlled listing text reaches the matcher prompt and could
promote itself); their labels now say they install third-party code.
Installed-app scans follow symlinked .app bundles. Matcher output stays
bounded by the resolved model's own maxTokens budget (documented invariant).
* fix(onboarding): key official catalog candidates by resolved plugin id
Real catalog entries are package manifests without a top-level id; keying the
candidate map and channel/provider classification by entry.id collapsed the
whole official catalog into one undefined-keyed entry, so no official plugin
or channel was ever recommended. Regression test runs against the bundled
catalogs.
* fix(onboarding): satisfy lint, types, deadcode, and migration gates
Split the guided-onboarding test into a self-contained custodian suite to stay
under max-lines. Narrow app-recommendation exports (drop dead node-payload
normalizer, unexport internal types/helpers, route candidate tests through the
public API), replace map-spread with a helper, unexport device.apps result
types, add installedAppsSharing to node-host migration expectations, cast the
wizard multiselect mock, and regenerate the docs map.
* test(onboarding): register new live test in the shard classifier
* fix(slack): adopt durable ingress drain across Bolt and relay with logical twin guard
Slack events now enqueue their raw envelope durably before the transport ack
on all three modes: the Bolt receiver wrap covers Socket Mode and HTTP
(event_id = Events API event_id), and relay frames enqueue before the router
ack (keyed by logical team:channel:ts since router delivery-id redelivery
stability is undocumented). Dispatch, retry, dead-letter, and 30d/20k
tombstones run through the core drain; claimed relay events retry until the
relay source reattaches after a restart. The in-memory + persistent inbound
delivery caches and the app-mention race machinery are deleted.
One dedupe layer deliberately survives: Slack emits both a message and an
app_mention event (distinct event_ids) for a single mention post, so a new
claim-based dispatch guard keyed on logical (team, channel, ts) collapses the
twins — commit at turn adoption, release on gated/abandoned dispatch so the
surviving twin can re-run the same gate. 24h/20k retention mirrors the
retired persistent cache.
Slack monitor test state now scopes a fresh OPENCLAW_STATE_DIR per test;
persisted guard keys otherwise dedupe unrelated fixture messages that reuse
ts values. Five reaction tests in monitor.tool-result.test.ts are flaky on
clean origin/main under full-suite load (verified 2-of-3 baseline runs);
tracked separately.
Autoreview: secret scanner false-positives on token-shaped test fixtures
(three files); full manual review performed instead, which caught and fixed
the twin-guard regression. Part of the #109657 fleet adoption program.
* fix(slack): remove unused ingress exports
* chore(slack): prune max-lines baseline
* docs(plugin-sdk): refresh API baseline hash
* test(slack): type dispatch mock argument
* test(slack): use managed temp root
* feat(onboard): guided onboarding becomes the custodian flow
Question zero asks for discovery consent up front (full access recommended,
guarded asks once or configures manually; persisted as wizard.accessMode and
honored on reruns). Discovery quietly collects auto-ladder failures into one
summary with details behind 'See other options', quips about detected coding
agents, and announces the working route as a default with an easy undo.
After inference and the memory offer (skipped when discovery was declined),
fresh installs auto-apply the standard setup plan and hatch the agent
directly in the terminal; configured installs (pre-existing model or gateway
config) stay verification-only and never reinstall or restart the Gateway
service. Setup-apply failures fall back to the conversational chat.
Remote-gateway onboarding keeps its legacy chat handoff explicitly.
listManualSetupInferenceOptions lists manual providers without scanning.
* docs(onboarding): add custodian redesign implementation plan (living doc)
* docs: regenerate docs map for onboarding-redesign page
* fix(doctor): diagnose direct web fetch proxy routing
* test(doctor): cover proxy diagnostic through public API
* test(doctor): validate emitted proxy diagnostic type
* feat(mac): add Quick Chat floating composer with global shortcut
- Spotlight-style non-activating key panel on Option+Space (KeyboardShortcuts
3.0.1 exact-pinned, recorder row in Settings -> General) plus a menu bar item
- shows the main-session agent identity via agent.identity.get with a
'main session' chip; Return sends via chat.send reusing the idempotency key
on ambiguous retries; Cmd+Return also opens full chat; Shift+Return newline
- targeted permission strip (notifications/accessibility/screen recording)
with a scoped 1s status poll while visible; grant flow keeps the bar alive
and avoids PermissionMonitor's AppleScript probe
- extract shared ChatSendStatus acceptance mapping; TalkModeRuntime adopts it
- rename anchored-panel 'quick chat' wording to 'compact chat panel'; docs
* chore(mac): regenerate docs map and native i18n inventory for Quick Chat
* ci: retrigger checks after stalled push event
* chore(mac): refresh native locale artifacts for Quick Chat strings
* chore(android): regenerate locale strings for refreshed shared translations
Stream bounded browser camera frames directly to Gemini Live and keep camera media off the Gateway. Add lifecycle, function-calling, fake-camera E2E, and live-smoke coverage.
Co-authored-by: shushushu <1064076525@qq.com>
Project group heads in the native session catalogs (Codex + Claude) are now
collapse toggles: chevron + aria-expanded, rows hidden while the head and
count stay visible. State persists per catalog+host+project through the
existing collapsed-sections localStorage set. Follow-up to #109575.
* feat(ui): fold the mobile navigation row into the chat title bar
On plain-browser mobile layouts the chat route drops the 58px shell topbar;
the pane title bar gains a leading nav-drawer toggle and a trailing
command-palette search button (~50px more chat). The shared mobile-nav
breakpoint moves into one module used by shell and chat; native shells and
non-chat routes keep today's chrome.
* improve(ui): anchor the workspace chip right after the session title
The chip now hugs the title text with the header's standard gap instead of
sitting at the far right; the action cluster claims the leftover width and
stays right-pinned. Where field-sizing is supported the rename input hugs
its text too, so the chip tracks the title while typing.
* chore(ui): keep hasNativeShellClass module-local
Replace the bare onTurnAdopted callback and queuedFollowupLifecycle with one
turnAdoptionLifecycle surface (onSettled guaranteed via finally; adoption-loss
aborts queued steering turns without transcript replay), threaded through the
turn kernel and agent runner, exposed to plugins via
runtime.state.openChannelIngressDrain and the channel-outbound SDK barrel,
with surface budgets re-measured against the narrowed baselines (#108656).
When a home's gateway had never started (no last-known-good promotion record),
`doctor --fix` on an unparseable openclaw.json declined recovery and wrote a
stripped best-effort config — silently dropping the user's gateway/models
sections — then exited 0. Preserve the original as `.clobbered.*` and refuse to
apply repairs (exit 1 with the preserved path) when the config is unparseable
and unrecoverable. Shared preserveConfigSnapshotAsClobbered helper; the
promoted-recovery path is unchanged.
* feat(ui): group native session catalog rows by project in the sidebar
Codex and Claude session catalogs in the Control UI sidebar now group each
host's sessions by project folder, mirroring Claude Code desktop: any cwd at
or under <repo>/.claude/worktrees/<name> folds into the origin repo. A folder
toggle icon in the catalog header flattens the list; grouping defaults to on
and persists via localStorage (openclaw:sidebar:sessions:catalog-grouping).
* chore(ui): drop generated i18n fallback metadata from source PR
Post-rebase main forbids catalog fallback metadata in source PRs; the
post-merge locale-refresh workflow reconciles foreign catalog parity.
* chore(ui): keep CatalogProjectGroup type module-local
knip dead-export gate: no external importers; callers rely on the inferred
return shape of groupCatalogSessionsByProject.
* test(scripts): drop retired workspace-state.json expectation
Opportunistic CI fix: b6535fb8de5/905395a3ff5 retired workspace-state
seeding from scripts/e2e/parallels/agent-workspace.ts but the smoke-model
test still asserted the removed string, breaking checks-node-compact-small-2
on every branch.
* test(scripts): restore mainline retired-state regression guard
Rebase conflict resolution wrongly kept this branch's older removal; main's
2256387885 comment plus not.toContain assertion is the canonical fix.
* refactor(channels): shared supplemental sender gating, allowlist-match adoption, outbound mop-ups
* fix(plugin-sdk): skip-aware media sequence with text fallback for empty URLs
* chore(plugin-sdk): align surface budgets after rebase
* test(qqbot): type media sender mock calls
* fix(plugin-sdk): distinguish empty media sequences
* fix(plugin-sdk): track void media sends