e9dd0bf5d5
Follow-up on @fortun8te's user-made roster sections: - Sections start empty: no seeded General/Workforce/Clients. With no sections created the roster renders exactly as before. - New section and Rename go through one Dialog + Input + Cancel/Save (the app's session-rename shape) instead of an inline caret; the row menu's "New section…" files the bot as it creates. - Delete needs no confirmation: bots return to Unassigned and the toast offers Undo (restores the section in its slot and refiles its bots). - Drag: single-row drag under a private MIME type, every valid target shows a faint outline while a drag is live, the hovered target lights up, the source section refuses the drop, Escape cancels, and the moved row no longer stays faded after it remounts under its new section. - Multi-select (cmd/shift-click, querySelectorAll shift-range) dropped: the roster has no selection model. Per-bot saveBotMeta writes run in sequence, one per profile (membership IS a field on each profile). - Section heading reuses RosterSectionHeader (gains `action` / `onDoubleClick`), so user sections fold and look like the gateway headings; ⋯ menu and right-click drive the same Rename / Move up / Move down / Delete. Empty sections show a dashed "Drag bots here" slot. - Composes with gateway buckets: sections nest INSIDE each connection bucket, indented under a hairline rail (membership lives in the bot's profile on that gateway); empty sections repeat there only mid-drag. - Full i18n parity (en / ja / zh / zh-hant) for every new string; icon toggle and the storage-async plumbing removed. - Tests trimmed to the three invariants (membership persists through saveBotMeta + reload, remainder = Unassigned, delete returns bots + undo) plus a live Electron e2e covering the whole flow. - Docs: "Organize bots into sections" in user-guide/bot-mode.md.
Contributor email → GitHub login mappings
This directory replaces appending entries to AUTHOR_MAP in
scripts/release.py. The old dict caused constant merge conflicts when
several salvage PRs landed at once — every PR edited the same lines of the
same file. Here, each mapping is its own file, and file additions never
conflict.
Adding a mapping
One file per commit-author email, under emails/:
python3 scripts/add_contributor.py <email> <github-login>
# or by hand:
echo "<github-login>" > contributors/emails/<email>
- File name = the exact commit-author email (as shown by
git log --format='%ae'). - File content = the GitHub login on the first non-comment line.
Lines starting with
#are comments (use them for the PR reference).
Example — contributors/emails/jane.doe@example.com:
janedoe
# PR #12345 salvage (gateway: fix session key routing)
Rules
- Do NOT add new entries to
AUTHOR_MAPinscripts/release.py. That dict is frozen legacy data; the release tooling merges it with this directory (directory entries win on duplicates). - GitHub noreply emails (
<id>+<login>@users.noreply.github.comand<login>@users.noreply.github.com) auto-resolve — no file needed. - The
Contributor Attribution CheckCI job fails a PR whose commits carry an unmapped email; the failure message prints the exact command to run.