Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog.d/3098-past-room-time-zh.fixed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
In a Chinese window a past face-to-face room now reads its time in Chinese: the row's hover says `已结束 10月19日 14:05` instead of `Ended Oct 19 14:05`, a room that never ended says `开始`, and the title rebuilt from the room's members reads `面对面 · Alice · 10月19日 14:05`. The stored room name and the rules that parse it are untouched, so an English window shows exactly what it showed before ([#3098](https://github.com/ThinkFlowLab/FlyBot/issues/3098)).
2 changes: 2 additions & 0 deletions core/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,8 @@ var ZH = {
"Copy a link a friend can paste in Add friend.": "复制链接,朋友在添加好友里粘贴即可。",
"Copy my handle": "复制我的 handle",
"Your Bot Social handle": "你的 Bot Social handle",
// #P769b: a Past room's hover names when the call started, then the day and the clock.
Started: "开始",
"Face-to-face": "面对面",
"This Bot has no model set up yet.": "这个 Bot 还没有配置模型。",
"This Bot could not answer right now.": "这个 Bot 现在没法回答。",
Expand Down
2 changes: 2 additions & 0 deletions core/src/client/i18n.js
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,8 @@ const ZH = {
'Copy a link a friend can paste in Add friend.': '复制链接,朋友在添加好友里粘贴即可。',
'Copy my handle': '复制我的 handle',
'Your Bot Social handle': '你的 Bot Social handle',
// #P769b: a Past room's hover names when the call started, then the day and the clock.
Started: '开始',
'Face-to-face': '面对面',
'This Bot has no model set up yet.': '这个 Bot 还没有配置模型。',
'This Bot could not answer right now.': '这个 Bot 现在没法回答。',
Expand Down
2 changes: 1 addition & 1 deletion docs/subsystems/core-client.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ The browser side of the patched `ds-bot` core (`core/`): sources in `core/src/cl
| `core/src/client/memory-empty.js` | The memory dialog's refused-folder line (#2101), decided by pure helpers because the suite has no renderer: `memoryEmptyNotice(view)` answers one line naming the folder when `entries` is empty and the host reported refused scopes in `view.blocked`, and `null` for the ordinary empty view, so `memory-panel.js` draws it above `{name} has not saved anything yet`; `memoryBlockedNotice(view)` answers that same line from `view.blocked` alone, whatever `entries` holds, and the panel draws it above the summary and above the entries list, because `entries` is own and team merged and one scope's entries would otherwise silence the other scope's refusal. A refused folder and a fresh Bot both answer `entries: []`; the host side of that field is in [core-host](core-host.md). Tests: `core/test/memory-empty.test.js`. |
| `core/src/client/memory-panel.js` | The memory dialog. `MemoryRow` is the Bot details pane's row — how much it keeps and the way into `MemoryDialog` — and `useMemoryCount` keeps that count from the same read the dialog does, so a read the host refuses answers `memoryCountText`'s sentence with the host's reason instead of `Loading…` for as long as the window stays open, while an empty memory and an arrived count keep their own wording; that sentence is drawn a second time below the row in a `role="status"` note, because the row's `aria-label` replaces the text inside the button whenever the accessible name is computed (#2402). The dialog has two pages: the summary the model writes from the entries (stale and failed states, **Try again**), and the entries themselves behind the ⋯ menu, grouped by scope and topic with a two-click **Remove**. The foot's **Ask or update** is one model call that answers from the entries or changes them, and lists each change as applied or refused. `useMemoryView` re-reads every `POLL_MS` while a summary is being written and only the latest answer counts. Since #2276 a read-only window (`roster.readOnly` a non-empty string) draws neither **Remove** nor the ask form — the host refuses `memory-forget` and `memory-ask` — and says why in the host's own sentence, while the entries and **Regenerate summary** (a read) still work. Tests: `core/test/memory-panel-readonly.test.js`, `core/test/memory.test.js`, `core/test/memory-empty.test.js`, `core/test/memory-search.test.js`. |
| `core/src/client/exchange.js` | The Bot-exchange sheet: `ExchangeDialog` polls the stored turns between two Bots and `ExchangeLine` draws one. A stored line is read once, by `exchangeText`: a leading `Chief → 助手` delegation trace and an `<untrusted-message …>` fence are routing, not words, so the bubble and the message tools' **Copy** receive the same cleaned string. Unlike a sidebar row it is not folded to one line — a reply's paragraph breaks are the writer's own and stay exactly as stored. Since #2841 the trace is read the way every other surface reads it: `stripTrace(text, names)` in `src/client/text.js` removes a leading trace only when every hop is a roster Bot name, the names reach `readableLine`/`collapsedLine` and the bubble call sites (`cells.js`, `exchange.js`) as `botNames(roster)`, and with no roster nothing that merely looks like routing is removed — a reply that opens `Settings → Models 页面` keeps that line, and a real `Chief → FlyBot Dev-1: 正文` still reads `正文`. Tests: `core/test/exchange-read.test.js`, `core/test/inbound-ui.test.js`. |
| `core/src/client/i18n.js` | The zh map the host `t()` reads. A plugin Settings page that calls `t('…')` adds the English key here (Settings → Bot Social friends and sharing, #1074); `npm run build` in `core/` copies the same map into `core/client.js`. The same map carries the words a plugin draws itself: the social plugin's face-room status chip calls `t()` for all five states — **Open** / **Closed** / **Left** / **Ended** / **Joining** (#3090) — so a missing key here leaves that chip in English. |
| `core/src/client/i18n.js` | The zh map the host `t()` reads. A plugin Settings page that calls `t('…')` adds the English key here (Settings → Bot Social friends and sharing, #1074); `npm run build` in `core/` copies the same map into `core/client.js`. The same map carries the words a plugin draws itself: the social plugin's face-room status chip calls `t()` for all five states — **Open** / **Closed** / **Left** / **Ended** / **Joining** (#3090), and the Past face-to-face row's hover words **Ended** / **Started** (#3097, #3098) — so a missing key here leaves that chip or that hover in English. |
| `core/src/client/new-chat.js` | Sidebar **+** picker. Plugin rows via `flybot.new-chat.action` (`newChatActionRows` in `flybot-registry.js`); social adds Face-to-face room and Add friend (copy actions live inside Add friend, #181). The DSH Agent row reads **Add coding agent** (hint "A plain DSH session, not a Bot") so it is not mistaken for **Create new Bot** (#181). The short + menu does not list individual Bots. A group the host refuses because one of my Bots is not shared with the friend whose Bot is in it (`error.details.reason === 'ungranted-local'`, put on the error by `client/api.js`) is drawn as a card, not a red line: it names the Bot(s) and friend(s), and offers **Copy invite link for {Bot}** (`__flybot__.social.createInvite`; shown only when social is loaded and can invite that Bot, nothing is granted by the click; it says *copied* only when `copiedToClipboard` in `shared/remote-label.js` reports the write took, else it shows the link in a read-only, select-on-focus field to copy by hand) and **Leave {Bot} out** (`ungrantedLocalFix`, `shared/remote-label.js`). |
| `core/src/client/stats-dock.js` | The shell's run-stats footer under the composer (`conversation.composer.dock`) re-registered one priority lower with the shell's own component, inject and `chat` locale, so the English counts read **1 turn** / **1 step** instead of `1 turns 1 steps` (`pluralStats` rewrites only the exact English template, #419). The shell ids differ by version — one `stats` footer in 0.2.0-rc.2, the counts split into an `activity` pill next to `usage` in 0.2.1-alpha.1 — so `statsDocks` registers one wrapper per id and the wrapper whose id the shell does not publish draws nothing (#659); `usage` stays hidden. Still hidden in a friend's Bot chat by CSS (#419). Tests: `core/test/stats-dock.test.js`. |
| `core/src/client/room-invite-preview.js` | The one room-invite preview card (#876). `invitePreviewOf` says only what a server reply can honestly say (a name cleaned at fixed point, the lead, `n / m in the room`, the deadline), `inviteCountdown` words the deadline, `RoomInvitePreview` draws the card from a caller-supplied `h`; `kind` renames the `data-flybot` hooks, so the face-room paste flow (`face-link-preview`) and the member-invite dialog (`room-invite-preview`) render the same tree instead of two copies of the markup. Registered on `__flybot__` in `flybot-slots.js`, because a classic-script plugin cannot import it. Tests: `core/test/room-invite-preview.test.js`. |
Expand Down
2 changes: 1 addition & 1 deletion docs/subsystems/social.md
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ Settings → **Bot Social** lists friends and shares once the server is connecte
### Past rooms, unique titles, poll, and + (#129–#133)

- Expired matching (`candidate` whose `expiresAt` has passed) and a peer leaving the last remote seat move the hosted room to **Past rooms** on the next poll (`rememberPastFace`, status `closed` / `left`). The local room stays so **Open** still works; **Leave** is not shown on those cards. Face-room names are `Face-to-face · Alice, Bob · 482913` (people plus the 6-digit code, or `Oct 16 21:40` when there is no code) so two rooms with the same people stay distinct. The literal `Face-to-face room` is not a fallback. The number printed there and on the waiting card is the six digits only (#1005): `faceWaitCode` and `shownFaceTitle` refuse a stored value that is not exactly six digits (`1234567` never reads as `123456`) and fall back to the code the owner typed, or to the creation time.
- Ended-room state and titles (#304): when every other home's Bots have left an open room, this home marks it **Closed** (it did not leave; `faceSnapshotPast` → `closed` with `peersGone`) and then leaves it on Bot Social itself (`leaveFaceRoom({ status: 'closed' })`), so it stops polling the room and the room-only identity is released (invariant 4). If that leave fails (timeout, 5xx), the next poll that still finds the room open on Bot Social tries it again. A room that drops off Bot Social's list without this home leaving is the same end (#1070): the hosted room is marked `closed` so the sidebar's active list drops it, and Past rooms keeps that one row (a `left` room stays Left). Its `endedAt` is the snapshot's `closed_at` when Bot Social sent one, so both homes show that time; otherwise the first time this home noticed. The owner who left keeps **Left**: `rememberPastFace` never turns a `left` row into `closed` when a later poll finds the room gone, and their room reads `You left this room.` while the others read `<Name> left the room. Room closed.` That status line is the one leave signal when the room closes (#1103): the shorter `<Name> left the room` is not also posted into the transcript. The number a room was joined by goes with every `upsertFace` (`joinCode`) and core keeps it on `room.face.joinCode`, so the title stays `Face-to-face · Alice, Bob · 482913` through polls, Leave and the end; Past rooms show that same title (people rebuilt from the row's members when it has them, the number or stored time kept; with neither, the creation time, never the joining deadline). A left or closed room's details are read-only: the status chip only, no Auto-send and no Leave. Past rows list everyone who was in the room (#304): `faceRoomTitle` takes the snapshot's members plus every participant the hosted room ever had (like the core title), and `viewHostedFace` for a closed or left room lists all participants, marking who had left `left: true` (Open on a dropped room seats only the others again); a row stored before this is refreshed from its hosted room. Each row shows its time (`data-flybot=face-time`): `endedAt`, set once by `rememberPastFace`, else the start (or creation) time; today reads `14:05`, an earlier day `Oct 19`, and the hover text has the full `Ended Oct 19 14:05`. The fold remembers whether it is open across a reload (`localStorage` `flybot.social.pastRoomsOpen`). A read-only window (the shell names it in `roster.readOnly`) keeps every read and drops every write (#2219): the section still polls `social/status` and still lists share requests, accept notices and past rooms, but draws no Dismiss, no Ask them to share a Bot, no Leave and no decision on a held send, offers none of the three Bot Social rows in the sidebar `+` menu, and `social/face-open` returns the stored past view (`readOnly: true`, name, status, members) instead of `upsertFace`-ing a local mirror, so reopening a past room creates no room; the room view's own head row draws the same chip-only head as a past room, with no Leave, no Auto-send switch and no invite (#2228), while a waiting room keeps its wait code and roster and drops its Leave and Enter chat; a local Bot's **Sharing** card draws the window's reason, no invite maker and no **Share with a friend**, and keeps **People with access** readable — the list of who has this Bot, and each person's Auto-send as a state line rather than a switch, with no Revoke — because `social/access` is a read the host allows (#2219, #2446), while a local group's **Members** card keeps no read of its own and draws only the reason with no **Create link** (#2418); a writable window behaves exactly as before.
- Ended-room state and titles (#304): when every other home's Bots have left an open room, this home marks it **Closed** (it did not leave; `faceSnapshotPast` → `closed` with `peersGone`) and then leaves it on Bot Social itself (`leaveFaceRoom({ status: 'closed' })`), so it stops polling the room and the room-only identity is released (invariant 4). If that leave fails (timeout, 5xx), the next poll that still finds the room open on Bot Social tries it again. A room that drops off Bot Social's list without this home leaving is the same end (#1070): the hosted room is marked `closed` so the sidebar's active list drops it, and Past rooms keeps that one row (a `left` room stays Left). Its `endedAt` is the snapshot's `closed_at` when Bot Social sent one, so both homes show that time; otherwise the first time this home noticed. The owner who left keeps **Left**: `rememberPastFace` never turns a `left` row into `closed` when a later poll finds the room gone, and their room reads `You left this room.` while the others read `<Name> left the room. Room closed.` That status line is the one leave signal when the room closes (#1103): the shorter `<Name> left the room` is not also posted into the transcript. The number a room was joined by goes with every `upsertFace` (`joinCode`) and core keeps it on `room.face.joinCode`, so the title stays `Face-to-face · Alice, Bob · 482913` through polls, Leave and the end; Past rooms show that same title (people rebuilt from the row's members when it has them, the number or stored time kept; with neither, the creation time, never the joining deadline). A left or closed room's details are read-only: the status chip only, no Auto-send and no Leave. Past rows list everyone who was in the room (#304): `faceRoomTitle` takes the snapshot's members plus every participant the hosted room ever had (like the core title), and `viewHostedFace` for a closed or left room lists all participants, marking who had left `left: true` (Open on a dropped room seats only the others again); a row stored before this is refreshed from its hosted room. Each row shows its time (`data-flybot=face-time`): `endedAt`, set once by `rememberPastFace`, else the start (or creation) time; today reads `14:05`, an earlier day `Oct 19`, and the hover text has the full `Ended Oct 19 14:05`. That day, that hover word and the first word of the title rebuilt from the row's members follow the interface language (#3098): a zh window draws `10月19日` and `已结束 10月19日 14:05` / `开始 …` / `面对面 · Alice · 10月19日 14:05` while an English window keeps the bytes it drew before. Only what the owner reads moves — the stored `room.name` (still `Face-to-face · Alice · Oct 19 14:05`) and every rule that parses it (`startsWith('Face-to-face · ')`, the two fallback matches, the six-digit code) stay English, because the next render parses that string again; a stored auto name's own English stamp is rewritten for display only, never saved back. Tests: `plugins/social/test/zh-face-time.test.js` (four zh cases, two English byte controls). The fold remembers whether it is open across a reload (`localStorage` `flybot.social.pastRoomsOpen`). A read-only window (the shell names it in `roster.readOnly`) keeps every read and drops every write (#2219): the section still polls `social/status` and still lists share requests, accept notices and past rooms, but draws no Dismiss, no Ask them to share a Bot, no Leave and no decision on a held send, offers none of the three Bot Social rows in the sidebar `+` menu, and `social/face-open` returns the stored past view (`readOnly: true`, name, status, members) instead of `upsertFace`-ing a local mirror, so reopening a past room creates no room; the room view's own head row draws the same chip-only head as a past room, with no Leave, no Auto-send switch and no invite (#2228), while a waiting room keeps its wait code and roster and drops its Leave and Enter chat; a local Bot's **Sharing** card draws the window's reason, no invite maker and no **Share with a friend**, and keeps **People with access** readable — the list of who has this Bot, and each person's Auto-send as a state line rather than a switch, with no Revoke — because `social/access` is a read the host allows (#2219, #2446), while a local group's **Members** card keeps no read of its own and draws only the reason with no **Create link** (#2418); a writable window behaves exactly as before.
- The face-to-face join field for the room number starts empty with a light `6 digits` hint (normal letter spacing, 13px), not a `000000` that looks pre-filled (#173). A number that is not empty and not exactly six digits keeps **Join** disabled and shows **Enter 6 digits** under the field (#1052). Six digits clear that line and enable Join once a Bot is picked; an empty field shows nothing.
- Round-3 polish (#173): **Accept invite** is no longer a separate **+** row; **Add friend** opens the single join panel for both a handle and an invite link or code. Escape closes the Add friend and Face-to-face panels, the `000000` code is a placeholder, Past rooms and friend rows use shorter copy, and Bot settings group invite and access under **Sharing** / **People with access**.
- **Open** on a Past room calls `social/face-open` (`plugins/social/src/social.js`): it returns the existing local hosted session or recreates one from the saved room, so a peer home can open a room that already left Bot Social (#171). Titles come from `plugins/social/src/face-title.js`, with participant owners in stable handle order, so both homes show the same name (#172).
Expand Down
4 changes: 3 additions & 1 deletion patches/ds-bot/0001-core-fixes.patch
Original file line number Diff line number Diff line change
Expand Up @@ -852,7 +852,7 @@ diff --git a/src/client/i18n.js b/src/client/i18n.js
Content: '内容',
'Referenced {labels}': '引用了 {labels}',
', ': '、',
@@ -41,22 +41,79 @@ const ZH = {
@@ -41,22 +41,81 @@ const ZH = {
' and ': '、',
and: '和',
'{count} members': '{count} 位成员',
Expand Down Expand Up @@ -886,6 +886,8 @@ diff --git a/src/client/i18n.js b/src/client/i18n.js
+ 'Copy a link a friend can paste in Add friend.': '复制链接,朋友在添加好友里粘贴即可。',
+ 'Copy my handle': '复制我的 handle',
+ 'Your Bot Social handle': '你的 Bot Social handle',
+ // #P769b: a Past room's hover names when the call started, then the day and the clock.
+ Started: '开始',
+ 'Face-to-face': '面对面',
+ 'This Bot has no model set up yet.': '这个 Bot 还没有配置模型。',
+ 'This Bot could not answer right now.': '这个 Bot 现在没法回答。',
Expand Down
Loading
Loading