### What this PR does
> **Stacked PR.** Base is `jd/resource-list-config`, not `main` — this
builds on the old-view resource-list rails from that branch. It should
merge after its base.
Before this PR:
- The old-view assistant rail showed a flat assistant list with no way
to group it.
- A resource (assistant) could carry multiple tags, and the
resource-card tag picker rendered each tag with a multi-select checkbox.
After this PR:
- The old-view assistant rail has a right-click / "more" menu toggle
that groups the non-pinned assistants into collapsible per-tag sections
(the "已固定" pinned section stays on top). The state reuses the existing
`assistant.tab.sort_type` preference (`list` | `tags`). Drag-reorder is
disabled while grouping. Untagged assistants collapse under the existing
"未分组" section. Agents and the topic list are untouched.
- A resource now carries a single tag. The resource-card tag picker
drops the checkbox and shows a single trailing check on the selected tag
(`menuitemradio`), matching the single-select tag combobox in the edit
dialog.
Fixes #
### Why we need it and why it was done in this way
The following tradeoffs were made:
- Tag grouping reuses the existing collapsible `SectionHeader` primitive
instead of adding a new visual, so it only allows expand/collapse and
matches the current rail look.
- Grouping reuses the v1 `assistant.tab.sort_type` preference
(cross-window, persisted) rather than introducing a new cache key.
- The single-tag model keeps the backend tag relation many-to-many and
only sends a 0/1-element array at the UI boundary.
The following alternatives were considered:
- A new `GroupHeader` (with chevron/actions) for tags — rejected to keep
"expand/collapse only" and reuse the existing section visual.
- Storing the grouping toggle in the Cache layer — rejected in favor of
the existing Preference, which is the idiomatic home for a synced UI
setting.
Links to places where the discussion took place: N/A
### Breaking changes
Collapsing assistant tags from many to one is a behavior change, but no
multi-tag assistant data exists at this pre-release stage, so there is
no user-visible data impact.
### Special notes for your reviewer
- Intentionally stacked on `jd/resource-list-config`; the diff is the
three commits on top of that branch (single-tag collapse, tag grouping,
single-select tag picker visual). Opened as **draft** since it cannot
merge before its base.
### Checklist
This checklist is not enforcing, but it's a reminder of items that could
be relevant to every PR.
Approvers are expected to review this list.
- [x] Branch: This PR targets the correct branch — stacked on
`jd/resource-list-config` (its base feature branch), not `main`
- [x] PR: The PR description is expressive enough and will help future
contributors
- [x] Code: [Write code that humans can
understand](https://en.wikiquote.org/wiki/Martin_Fowler#code-for-humans)
and [Keep it simple](https://en.wikipedia.org/wiki/KISS_principle)
- [x] Refactor: You have [left the code cleaner than you found it (Boy
Scout
Rule)](https://learning.oreilly.com/library/view/97-things-every/9780596809515/ch08.html)
- [x] Upgrade: Impact of this change on upgrade flows was considered and
addressed if required
- [ ] Documentation: A [user-guide update](https://docs.cherry-ai.com)
was considered and is present (link) or not required. Check this only
when the PR introduces or changes a user-facing feature or behavior.
- [x] Self-review: I have reviewed my own code (e.g., via
[`/gh-pr-review`](/.claude/skills/gh-pr-review/SKILL.md), `gh pr diff`,
or GitHub UI) before requesting review from others
### Release note
```release-note
Group assistants by tag in the chat sidebar (old view) via the assistant right-click menu, and use a single tag per assistant with a single-select tag picker.
```
---------
Signed-off-by: jd <59188306+zhangjiadi225@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The resources/database/drizzle SQL files and meta snapshots are v1-era CherryClaw agents-db migrations with no runtime consumer — the active v2 migrations live in migrations/sqlite-drizzle and are loaded from app.database.migrations. Delete the directory and clean up the now-dangling references: three source comments in AgentsDbMappings.ts that cited the deleted SQL files as the v1 column-type source (the epoch-ms notes are kept inline), and a stale doc row in cherryclaw/scheduler.md pointing to a migration file that no longer exists.
The setter updater contract previously said "must be pure" only in the sense of "don't mutate prev / return a new value" (the isEqual short-circuit footgun); it did not cover side effects inside the updater.
Document that updaters must also be side-effect-free: don't smuggle a derived value out (e.g. into an enclosing-scope variable) to drive post-write work, and don't rely on how often or when the updater runs. To react to what changed, derive it from the value transition in a useEffect that watches the value.
Deliberately does not promise single synchronous invocation, to keep the setter free to batch/retry/defer later. Updates the CacheSetStateAction type doc, the useCache @remarks (canonical reference for all three hooks), and cache-usage.md.
Now that the renderer cache hooks resolve functional updaters against the latest stored value, replace the hand-rolled ref + `typeof === 'function'` wrappers (TabsProvider, TranslatePage, GlobalSearchPanel) and the snapshot-based read-modify-write call sites (recent-items in AppShell/HomePage/AgentPage, emoji recents, message selection, recall-test history) with `setX(prev => ...)`. Each updater derives from `prev`, and the callbacks drop the cache value from their dependency arrays.
The mini-app keep-alive sites (hide / cleanup / sync) close the read-modify-write race where an app opened concurrently during a status mutation's await was clobbered by a stale snapshot. Fixes#16460.
Update the two local cache mocks (GlobalSearchPanel / RecallTestPanel tests) to resolve functional updaters like the real hook.