From c2b213c365b56c904665a113aef5ad614eeacf5c Mon Sep 17 00:00:00 2001 From: Danyang Chen Date: Mon, 2 Nov 2026 02:39:29 +0800 Subject: [PATCH] Release v0.2.20 Changelog fragments consumed (48): - changelog.d/1949-rename-push.fixed.md - changelog.d/1954-arch-docs-no-shell.fixed.md - changelog.d/1956-task-card-text-code-point-bound.fixed.md - changelog.d/1958-oneline-code-point-bound.fixed.md - changelog.d/1960-room-context-code-point-bound.fixed.md - changelog.d/1962-room-settings-line.fixed.md - changelog.d/1963-cut-wellformed.fixed.md - changelog.d/1967-settings-line-attribution.fixed.md - changelog.d/1968-rename-push-auto.fixed.md - changelog.d/1973-arch-docs-win-guard.fixed.md - changelog.d/1976-store-auto-name.fixed.md - changelog.d/1979-external-text-bounds.fixed.md - changelog.d/1984-turns-code-point-bounds.fixed.md - changelog.d/1990-p321-remote-chat-name-bound.fixed.md - changelog.d/1992-approval-command-cut.fixed.md - changelog.d/1993-p2-c5-remaining.fixed.md - changelog.d/1995-unnamed-title-follows-seats.fixed.md - changelog.d/2001-recall-remaining.fixed.md - changelog.d/2002-connector-error-cut.fixed.md - changelog.d/2004-seat-rename-broadcast.fixed.md - changelog.d/2005-project-panel-code-points.fixed.md - changelog.d/2006-memory-bounds-code-points.fixed.md - changelog.d/2009-human-seat-rename-broadcast.fixed.md - changelog.d/2010-startup-rename-notify.fixed.md - changelog.d/2016-connector-error-bound.fixed.md - changelog.d/2017-workflow-avatar-code-point.fixed.md - changelog.d/2021-project-board-decision-total.fixed.md - changelog.d/2024-schedules-drawer-paused-next.fixed.md - changelog.d/2027-connector-error-copy.fixed.md - changelog.d/2029-blocked-card-age.changed.md - changelog.d/2030-schedules-summary-more.changed.md - changelog.d/2033-decision-path-cap.fixed.md - changelog.d/2035-schedules-unknown-guard.fixed.md - changelog.d/2037-decision-name-guard.fixed.md - changelog.d/2039-room-schedules.fixed.md - changelog.d/2041-decision-open.added.md - changelog.d/2042-inbox-done-total.fixed.md - changelog.d/2043-dock-more-rooms.fixed.md - changelog.d/2045-board-archive-counts.fixed.md - changelog.d/2048-room-rail-bound.fixed.md - changelog.d/2050-inbox-show-all.fixed.md - changelog.d/2052-decisiondir-card-binding.fixed.md - changelog.d/2055-decisions-dir-symlink.fixed.md - changelog.d/2056-journal-folder-symlink.fixed.md - changelog.d/2057-memory-workflows-dir-symlink.fixed.md - changelog.d/2061-unreadable-archive-cards.fixed.md - changelog.d/2063-room-rail-active-cards.fixed.md - changelog.d/2070-kanban-rail-switch.fixed.md --- CHANGELOG.md | 59 +++++++++++++++++++ changelog.d/1949-rename-push.fixed.md | 1 - changelog.d/1954-arch-docs-no-shell.fixed.md | 1 - ...6-task-card-text-code-point-bound.fixed.md | 1 - .../1958-oneline-code-point-bound.fixed.md | 1 - ...960-room-context-code-point-bound.fixed.md | 1 - changelog.d/1962-room-settings-line.fixed.md | 1 - changelog.d/1963-cut-wellformed.fixed.md | 1 - .../1967-settings-line-attribution.fixed.md | 1 - changelog.d/1968-rename-push-auto.fixed.md | 1 - changelog.d/1973-arch-docs-win-guard.fixed.md | 1 - changelog.d/1976-store-auto-name.fixed.md | 1 - .../1979-external-text-bounds.fixed.md | 1 - .../1984-turns-code-point-bounds.fixed.md | 1 - .../1990-p321-remote-chat-name-bound.fixed.md | 1 - .../1992-approval-command-cut.fixed.md | 1 - changelog.d/1993-p2-c5-remaining.fixed.md | 1 - .../1995-unnamed-title-follows-seats.fixed.md | 1 - changelog.d/2001-recall-remaining.fixed.md | 1 - changelog.d/2002-connector-error-cut.fixed.md | 1 - .../2004-seat-rename-broadcast.fixed.md | 1 - .../2005-project-panel-code-points.fixed.md | 1 - .../2006-memory-bounds-code-points.fixed.md | 1 - .../2009-human-seat-rename-broadcast.fixed.md | 1 - .../2010-startup-rename-notify.fixed.md | 1 - .../2016-connector-error-bound.fixed.md | 1 - .../2017-workflow-avatar-code-point.fixed.md | 1 - ...2021-project-board-decision-total.fixed.md | 1 - ...2024-schedules-drawer-paused-next.fixed.md | 1 - .../2027-connector-error-copy.fixed.md | 1 - changelog.d/2029-blocked-card-age.changed.md | 1 - .../2030-schedules-summary-more.changed.md | 1 - changelog.d/2033-decision-path-cap.fixed.md | 1 - .../2035-schedules-unknown-guard.fixed.md | 1 - changelog.d/2037-decision-name-guard.fixed.md | 1 - changelog.d/2039-room-schedules.fixed.md | 1 - changelog.d/2041-decision-open.added.md | 1 - changelog.d/2042-inbox-done-total.fixed.md | 1 - changelog.d/2043-dock-more-rooms.fixed.md | 1 - .../2045-board-archive-counts.fixed.md | 1 - changelog.d/2048-room-rail-bound.fixed.md | 1 - changelog.d/2050-inbox-show-all.fixed.md | 1 - .../2052-decisiondir-card-binding.fixed.md | 1 - .../2055-decisions-dir-symlink.fixed.md | 1 - .../2056-journal-folder-symlink.fixed.md | 1 - ...2057-memory-workflows-dir-symlink.fixed.md | 1 - .../2061-unreadable-archive-cards.fixed.md | 1 - .../2063-room-rail-active-cards.fixed.md | 1 - changelog.d/2070-kanban-rail-switch.fixed.md | 1 - core/package-lock.json | 4 +- core/package.json | 2 +- patches/ds-bot/0007-version-and-tooling.patch | 6 +- 52 files changed, 65 insertions(+), 54 deletions(-) delete mode 100644 changelog.d/1949-rename-push.fixed.md delete mode 100644 changelog.d/1954-arch-docs-no-shell.fixed.md delete mode 100644 changelog.d/1956-task-card-text-code-point-bound.fixed.md delete mode 100644 changelog.d/1958-oneline-code-point-bound.fixed.md delete mode 100644 changelog.d/1960-room-context-code-point-bound.fixed.md delete mode 100644 changelog.d/1962-room-settings-line.fixed.md delete mode 100644 changelog.d/1963-cut-wellformed.fixed.md delete mode 100644 changelog.d/1967-settings-line-attribution.fixed.md delete mode 100644 changelog.d/1968-rename-push-auto.fixed.md delete mode 100644 changelog.d/1973-arch-docs-win-guard.fixed.md delete mode 100644 changelog.d/1976-store-auto-name.fixed.md delete mode 100644 changelog.d/1979-external-text-bounds.fixed.md delete mode 100644 changelog.d/1984-turns-code-point-bounds.fixed.md delete mode 100644 changelog.d/1990-p321-remote-chat-name-bound.fixed.md delete mode 100644 changelog.d/1992-approval-command-cut.fixed.md delete mode 100644 changelog.d/1993-p2-c5-remaining.fixed.md delete mode 100644 changelog.d/1995-unnamed-title-follows-seats.fixed.md delete mode 100644 changelog.d/2001-recall-remaining.fixed.md delete mode 100644 changelog.d/2002-connector-error-cut.fixed.md delete mode 100644 changelog.d/2004-seat-rename-broadcast.fixed.md delete mode 100644 changelog.d/2005-project-panel-code-points.fixed.md delete mode 100644 changelog.d/2006-memory-bounds-code-points.fixed.md delete mode 100644 changelog.d/2009-human-seat-rename-broadcast.fixed.md delete mode 100644 changelog.d/2010-startup-rename-notify.fixed.md delete mode 100644 changelog.d/2016-connector-error-bound.fixed.md delete mode 100644 changelog.d/2017-workflow-avatar-code-point.fixed.md delete mode 100644 changelog.d/2021-project-board-decision-total.fixed.md delete mode 100644 changelog.d/2024-schedules-drawer-paused-next.fixed.md delete mode 100644 changelog.d/2027-connector-error-copy.fixed.md delete mode 100644 changelog.d/2029-blocked-card-age.changed.md delete mode 100644 changelog.d/2030-schedules-summary-more.changed.md delete mode 100644 changelog.d/2033-decision-path-cap.fixed.md delete mode 100644 changelog.d/2035-schedules-unknown-guard.fixed.md delete mode 100644 changelog.d/2037-decision-name-guard.fixed.md delete mode 100644 changelog.d/2039-room-schedules.fixed.md delete mode 100644 changelog.d/2041-decision-open.added.md delete mode 100644 changelog.d/2042-inbox-done-total.fixed.md delete mode 100644 changelog.d/2043-dock-more-rooms.fixed.md delete mode 100644 changelog.d/2045-board-archive-counts.fixed.md delete mode 100644 changelog.d/2048-room-rail-bound.fixed.md delete mode 100644 changelog.d/2050-inbox-show-all.fixed.md delete mode 100644 changelog.d/2052-decisiondir-card-binding.fixed.md delete mode 100644 changelog.d/2055-decisions-dir-symlink.fixed.md delete mode 100644 changelog.d/2056-journal-folder-symlink.fixed.md delete mode 100644 changelog.d/2057-memory-workflows-dir-symlink.fixed.md delete mode 100644 changelog.d/2061-unreadable-archive-cards.fixed.md delete mode 100644 changelog.d/2063-room-rail-active-cards.fixed.md delete mode 100644 changelog.d/2070-kanban-rail-switch.fixed.md diff --git a/CHANGELOG.md b/CHANGELOG.md index 7e945be69..c5f5a1fb4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,65 @@ New entries are written as one fragment file per change in [changelog.d/](change ## [Unreleased] +## [0.2.20] - 2026-11-02 + +### Added + +- A decision row on the Project board now opens: activating a `decisions/*.md` row (by mouse or keyboard) shows that file's text under the row, and activating it again closes it ([#2041](https://github.com/ThinkFlowLab/FlyBot/issues/2041)) — before this, the board could list 200 decision files and open none of them. The text comes from a new host read that accepts only a name the board's own listing produced, including one past the 200-row cut, so a name like `decisions/../outside.md`, an absolute path, a name one level down or a symlink answers `not listed` without touching the disk; a file over 200,000 bytes answers `too large` rather than being cut, and a row whose file was deleted answers `absent` and stays a row. + +### Changed + +- A Project board's Blocked group now says how long a card has been stuck, and lists the card stuck longest first ([#2029](https://github.com/ThinkFlowLab/FlyBot/issues/2029)): the row kept the card's own reason and read the same whether the card had been blocked for three days or three minutes, and the group was unsorted. The host now answers `since` / `waitedMs` from the question's own `requestedAt` stamp — a card whose ask wrote no stamp shows no duration rather than an invented one — and the board draws `reason · 2d`, ordering the group oldest first the way Waiting already is. +- A Bot's Scheduled tasks line in its details panel says how many tasks the Bot has and, past the three rows it draws, one **2 more not shown** row opens the full list ([#2030](https://github.com/ThinkFlowLab/FlyBot/issues/2030)). + +### Fixed + +- Renaming a group chat now reaches the guests already seated in it ([#1949](https://github.com/ThinkFlowLab/FlyBot/issues/1949)): the host pushed a membership envelope only when the notice changed, so a shared room kept its old title on the other homes until the next chat line, and a quiet room kept it indefinitely. A rename rides the same one `join` the notice edit already used — the envelope carries the name field it always carried — and a settings save that changes both the name and the notice still sends a single envelope, while a save that writes back the values the room already holds sends nothing. +- The architecture-docs gate no longer starts git through a shell ([#1954](https://github.com/ThinkFlowLab/FlyBot/issues/1954)): on Windows the gate handed `git rev-parse --verify origin/main^{commit}` to cmd.exe, `^` is cmd's escape character, so the `^{commit}` never reached git and every scheduled Windows row reported `arch-docs: FAIL — cannot diff against origin/main` on a checkout where `origin/main` existed. git now runs with its arguments as a list, the ref verbatim, and the fail-closed behaviour on a genuinely missing base ref is unchanged. +- The task card's three 2,000-unit text bounds now cut on a code point boundary: the result summary a Done move copies from the card's note, the criteria stored at create, and the summary a return writes drop a surrogate pair whole instead of storing a lone surrogate that the card shows as U+FFFD ([#1956](https://github.com/ThinkFlowLab/FlyBot/issues/1956)). +- The task card's title and note and a dispatched card's title and note are cut at 300 characters on a code point boundary, so a bound that lands inside an emoji or other astral character keeps whole characters instead of storing a lone surrogate the card shows as U+FFFD ([#1958](https://github.com/ThinkFlowLab/FlyBot/issues/1958)). +- A room turn and the stored `room.log` no longer split a surrogate pair at a character bound: the status stub's hundred units, the transcript clip, and the card, board and presence fields now cut on a code point boundary, so a title or a Bot essay that ends on an emoji keeps the whole emoji instead of an unpaired half the encoder turns into U+FFFD ([#1960](https://github.com/ThinkFlowLab/FlyBot/issues/1960)). +- A group settings change now leaves one line in the room: renaming the room, editing or clearing the notice, switching the reply mode, or naming a new admin or task lead posts a single quiet event that says what changed and who changed it, opens no Bot turn, and stays quiet when a patch writes back the values the room already holds or when an unnamed room's title follows its members ([#1962](https://github.com/ThinkFlowLab/FlyBot/issues/1962)). +- A text bound no longer keeps an unpaired surrogate the caller handed in ([#1963](https://github.com/ThinkFlowLab/FlyBot/issues/1963)): every character bound in the host goes through the shared `cut`, and that helper moved its cut point off a pair it was about to split but copied a string that already carried a lone surrogate straight through, so a card title, a note or a name that arrived broken was written to `state.json` as the same broken value — read back as U+FFFD by any encoder. `cut` now flattens its input with `toWellFormed()` before it bounds, so the stored text is well formed; U+FFFD is one UTF-16 unit for the one it replaces, so a well-formed input keeps its exact prefix and its "was cut" flag. +- The one line a group-settings save leaves in the room now names the person who saved it on the default single-user setup ([#1967](https://github.com/ThinkFlowLab/FlyBot/issues/1967)): the web UI has no member session, so the save reached the host with no name and every rename, notice, mode or admin change read "Someone updated the group notice". The line now takes the room's implicit owner — the local person whose Bots sit in it — while a signed-in member and a Bot saving through its own tool still win, and only a room with no owner at all falls back to "the user". +- Renaming a Bot now reaches the guests already seated in every unnamed group it sits in ([#1968](https://github.com/ThinkFlowLab/FlyBot/issues/1968)): the host recomputed the room's title from its members and retitled the room locally, but pushed nothing, so a shared group kept its old title on the other homes until the next chat line and a quiet group kept it indefinitely. The automatic rename now rides the same one `join` an explicit rename already used (#1949) and carries the new name, while a rename that leaves the computed title alone — a Bot outside the group, a group with a chosen name, a group with no remote guest — still sends nothing. +- The Windows Compatibility job no longer fails on a test case that can only run on POSIX ([#1973](https://github.com/ThinkFlowLab/FlyBot/issues/1973)): the case proving the arch-docs gate never hands git's arguments to a shell observes that by running a fake `git`, which has to be an executable script with an interpreter line — Windows cannot launch one and would fail the job with `ENOENT`. The case is now marked skipped on Windows rather than quietly passing, and the same job's Lint step still runs the real gate there, so the platform stays covered. +- A restart no longer renames an unnamed group to `You, …` or drops its remote guests ([#1976](https://github.com/ThinkFlowLab/FlyBot/issues/1976)). On load the host compared the stored title with the name computed from the room's people and guests, then wrote a title computed from the member Bots alone: the owner became `You`, every remote guest fell out of the name, and because that name could never match again the file and the group's Session title were rewritten on every boot. Both the comparison and the write now use the one name that sees the room, so a restart migrates an old title once and then leaves it alone. +- Six bounds on text another home or another person supplied no longer cut on UTF-16 units ([#1979](https://github.com/ThinkFlowLab/FlyBot/issues/1979)): a connector item name (80), a role label another home set on a face-room seat (80), a cross-home group name (200), a capability description from a peer server (2,000), a remote home's own error text (157) and an abbreviated remote reply (80) used a bare `slice`, so a bound that landed between the halves of a surrogate pair produced a lone high surrogate — read as U+FFFD by any encoder and shown to the owner that way. Each now goes through the shared `cut`, which keeps the longest prefix that stops before a split pair within the same budget; the error preview's `…` and the reply's trailing-period strip still apply to the cut value. +- The host's turn lines no longer split a surrogate pair at their character bounds ([#1984](https://github.com/ThinkFlowLab/FlyBot/issues/1984)): a failed turn's 500-unit message, the 200-unit message of its one-line reason, the 79-unit step a running call shows, an approval card's 300-unit description and 400-unit command, and the 160-unit reason a failed turn leaves for the inbox now cut on a code point boundary, so a line that ends on an emoji keeps the whole emoji instead of an unpaired half the encoder turns into U+FFFD. +- The name a friend's Bot keeps is cut on code points at both places the chat stores it: creating the chat (40) and refreshing its name (40) used a bare `slice`, so a name whose bound fell between the halves of a surrogate pair became a lone high surrogate — shown as U+FFFD once `roster.createBot` bounded it again. Both now go through the shared `cut`, so the longest whole-code-point prefix within the same 40-unit budget is kept, and a short name is stored word for word ([#1990](https://github.com/ThinkFlowLab/FlyBot/issues/1990)). +- An approval card now stores the command "Allow once" runs instead of clipping it at 400 units: the description and command bounds are 2,000 and 4,000, a value that still has to be cut ends with an ellipsis inside that bound, and the card wraps and scrolls a long command rather than drawing it as one clipped line ([#1992](https://github.com/ThinkFlowLab/FlyBot/issues/1992)). +- The last five text bounds in `core/src/host/` no longer cut on UTF-16 units ([#1993](https://github.com/ThinkFlowLab/FlyBot/issues/1993)): the quoted first line of a checkpoint's kept tail (80), an approval record's reason (500), a mention receipt's reason line (240), the title given to a DSH Agent's Session (80) and a schedule run's failure reason (200) used a bare `slice`, so a bound that landed between the halves of a surrogate pair stored a lone high surrogate — read as U+FFFD by any encoder. Each now goes through the shared `cut`, which keeps within the same budget the longest prefix that stops before a split pair; none of the five maxima changes. +- The title of a group without a chosen name follows its seats now ([#1995](https://github.com/ThinkFlowLab/FlyBot/issues/1995)): a friend's Bot invited to such a group appears in its name and in the group's Session title the moment the seat exists, and a seat that leaves drops out of both instead of staying in `state.json` until a restart. Before this, only a settings save or a renamed Bot recomputed that name, so inviting or removing a guest left the title reading the old set of people while the roster had already changed. A group created together with a guest was opened under the narrow name — `You, Chief A, Chief B`, with the guest missing — and was corrected in `state.json` without ever reaching the Session the user reads. A group with a chosen name keeps it. +- `recall` now says when it cut its hit list ([#2001](https://github.com/ThinkFlowLab/FlyBot/issues/2001)): a keyword search with more than 30 matches ends with `N more entries match; narrow the query or read a topic` and the exact count (`1 more entry matches; …` when exactly one is left out), and a `semantic: "true"` search asks the index for one entry past the cap and ends with `more entries match this meaning than are shown; narrow the query or read a topic`. Before this, a Bot with 35 matching entries was shown 30 and told nothing, so entry 31 read as not existing. The cap stays 30 and a reply that shows every match adds no line. +- A connector or MCP server's error no longer reaches the owner's card as U+FFFD ([#2002](https://github.com/ThinkFlowLab/FlyBot/issues/2002)): the 300-unit `reason` in `core/src/host/connectors.js` used a bare `slice`, so a message whose 300th UTF-16 unit landed inside a surrogate pair was stored with a lone high surrogate. It now goes through the shared `cut`, which keeps within the same 300 the longest prefix that stops before a split pair; a message under the bound is stored word for word. +- A guest already seated in a group without a chosen name learns the new name as soon as another seat joins or leaves ([#2004](https://github.com/ThinkFlowLab/FlyBot/issues/2004)): before this the host moved its own name and Session title while the other homes kept the copy they arrived with, and only a guest arriving after the change was told, so the drawer and the group settings could still read a set of seats that had already changed. The seat that changed keeps its one targeted join; the guests already in the room get one more carrying the same text the host holds. A group with a chosen name, a mirror of another home's room and a face-to-face room still send nothing for a seat change. +- Five Project-panel bounds now cut on a code point boundary, so a dossier or a board card no longer carries half an emoji: the assistant digest's 77-unit card title, the board's 200-unit one-line reason and decision title, and the dossier's capped name, role, persona, model and color, plus its 4,000-unit memory head — that last one is bounded where the memory is read, so the character is dropped whole instead of reaching the panel as U+FFFD ([#2005](https://github.com/ThinkFlowLab/FlyBot/issues/2005)). +- Four memory bounds now cut on a code-point boundary, so the news line, a `recall` query, the saved summary and the memory panel's ask prompt can no longer keep half an emoji, which every encoder shows as U+FFFD ([#2006](https://github.com/ThinkFlowLab/FlyBot/issues/2006)). Each bound still holds its 160, 120, 8,000 or 2,000 units and the character that would not fit is dropped whole. +- Adding or removing a person in a group without a chosen name now tells the guests already seated the new name ([#2009](https://github.com/ThinkFlowLab/FlyBot/issues/2009)): before this a human seat moved the host's own name and Session title while the other homes kept the copy they arrived with, because only a Bot's seat change sent the one `join` a guest holds. A group with a chosen name, a mirror of another home's room and a face-to-face room still send nothing for a seat change. +- A group without a chosen name that is renamed when FlyBot starts now tells the guests already seated the name it settled on ([#2010](https://github.com/ThinkFlowLab/FlyBot/issues/2010)): before this the load rewrote the name and the group Session title while every other home kept the copy it arrived with, so the two sides disagreed until that guest happened to join again. A group with no remote guest, a mirror of another home's room and a face-to-face room still send nothing. +- A connector's failure text no longer stops at 300 units without saying so ([#2016](https://github.com/ThinkFlowLab/FlyBot/issues/2016)): the `reason` stored on the owner's connector card now holds up to 2,000 — the bound another server's own description already uses — and a message that still has to be cut ends with `…` inside that bound, so the card says what it abridged instead of showing a sentence that stops mid-word as the server's whole answer. A message at or under 2,000 is stored word for word. +- A Workflow node's avatar now shows the first character of its name ([#2017](https://github.com/ThinkFlowLab/FlyBot/issues/2017)): the circle took the name's first UTF-16 unit, so a node called `🚀 Deployer` showed half an emoji on the flowchart and in the run view. It takes the first code point instead, and a node with no name still shows `?`. +- The Project board now keeps the newest 200 decisions and says how many it found ([#2021](https://github.com/ThinkFlowLab/FlyBot/issues/2021)): the read sorted the decision paths ascending and took the first 200, so a Project past the cap dropped the files it had just written, and a full list and a truncated one both read as the same number. The cut takes the tail now — the order on screen is still oldest first — the decisions read answers `total`, taken after the one-row-per-path dedup and before the cut, the meetings read answers `decidedTotal` / `pendingTotal` per list, and the board draws one `N more not shown` / 还有 N 条未显示 line under each list it shortened, with `data-decisions-total` beside the rows-drawn count. A list at or under its cap answers the same rows as before, plus the count. +- A Bot's Scheduled tasks block in its details panel now lists the Bot's paused and finished tasks instead of claiming the Bot has none, and each row says when it runs next — `Next: …`, `Paused` or `Finished` — rather than only the repeat rule ([#2024](https://github.com/ThinkFlowLab/FlyBot/issues/2024)). +- A failed connector's error text is now copyable in one click ([#2027](https://github.com/ThinkFlowLab/FlyBot/issues/2027)): since [#2022](https://github.com/ThinkFlowLab/FlyBot/issues/2022) a row in the `error` state can carry up to 2,000 characters of the host's own failure text, but its only actions were `Try again` and `Disconnect`, so passing that sentence on meant selecting it by hand — close to impossible on a phone. The row now offers `Copy error` next to `Try again`, which puts the exact stored text on the clipboard through the shared helper and reads `Copied` when it landed and `Could not copy the error` when the page has no clipboard or the write was refused, never a quiet success ([#1347](https://github.com/ThinkFlowLab/FlyBot/issues/1347)). `ready` and `off` rows are unchanged. +- A decided meeting's row on a Project board no longer reports `decision file gone` for a file that is still there ([#2033](https://github.com/ThinkFlowLab/FlyBot/issues/2033)): the board lists only the newest 200 decision files ([#2021](https://github.com/ThinkFlowLab/FlyBot/issues/2021)), and the lookup behind a meeting's own file name was built from that cut list, so every decided meeting whose file fell off the oldest end claimed its file had been deleted — while the same read reported the full count. The lookup now falls back to the names this read actually saw in the folder, so a file past the cut is named and only a name the folder no longer holds reads as gone; the fallback takes names from that read, never from the filesystem, so `../outside.md` still yields no path. +- A Bot's details panel no longer says "No scheduled tasks yet. Add one" before it has read the Bot's scheduled tasks: the line kept the shared view's `null` (nothing read yet) and treated it as an empty list, so the first frame — and every frame after a first read that failed, since the error was swallowed and the shared view stayed `null` — offered the new-task form on a Bot that may well have tasks. It now draws nothing until a read answers, the way the settings card beside it already did, and the empty state is kept for a read that answers zero ([#2035](https://github.com/ThinkFlowLab/FlyBot/issues/2035)). +- A decision file name can no longer reach outside the project, and a symlinked Project State file is no longer read ([#2037](https://github.com/ThinkFlowLab/FlyBot/issues/2037)): the board accepted any name that started with `decisions/` and ended in `.md`, so a hand-edited `decisionFile` or a crafted folder name such as `decisions/zz/../../../outside.md` put a file outside the folder in a row — with its `path` and its first line as `title` — and the same name could come back through the `known` fallback past the 200-row cut. One rule now decides a decision name at the point the listing is produced: exactly one segment under `decisions/`, ending in `.md`, used by the listing, the reader and the fallback alike; a symlink is refused too, and `project_state` answers `absent` for a symlinked file instead of handing over the text it points at. +- A group chat's details panel now lists the scheduled tasks that room owns. Before, a task could target a group chat — the new-task form offered `Group chats`, and Settings grouped tasks by room — but the room itself showed nothing, so "is the 9am task on this room still there?" meant leaving the room for Settings. The panel draws the three newest of the room's tasks, a title carrying the real count and `N more not shown` past three, and only tasks that carry this room's `roomId` and no `botId`: a Bot's task and another room's task stay out. Rows open the settings list, a room with no tasks draws nothing at all, and a face-to-face room gets no such section ([#2039](https://github.com/ThinkFlowLab/FlyBot/issues/2039)). +- The Inbox's Done group draws at most 20 rows, and it no longer hides the rest silently: when the model had more finished cards than it drew, one **5 more not shown** line under the Done rows says how many were left out, in the same words the Project board uses for its own capped list. A Done group of 20 or fewer, and the empty group, read exactly as before ([#2042](https://github.com/ThinkFlowLab/FlyBot/issues/2042)). +- The Bot's own-chat dock no longer drops rooms past the fourth silently: when it is at work in more than four, it draws four rows and then `1 more room` / `N more rooms` ([#2043](https://github.com/ThinkFlowLab/FlyBot/issues/2043)). +- The task board's Done column is one archive page of 20 cards, and until now it presented that page as the whole story: a Bot with 45 finished tasks read **Done 20**, and its rail row read **20/22** as if 22 were everything. When the archive page is full the column heading now reads **20 newest** and the rail row reads **20+ done** — what was drawn, and that there is more; a page under the limit, and the empty board, read exactly as before ([#2045](https://github.com/ThinkFlowLab/FlyBot/issues/2045)). +- The task board's group rail reads a Bot's own slice of the room's cut archive page as `done/total`, so a Bot with 18 of the newest 20 finished cards says `18/18` while the room holds 45. A full page is now a lower bound for every Bot on it (`18+ done`), and a page under the limit still reads its exact counts ([#2048](https://github.com/ThinkFlowLab/FlyBot/issues/2048)). +- The Inbox counted the finished tasks its Done group left out but gave no way to see them: with 29 finished tasks the group drew 20, said `9 more not shown`, and those nine were unreachable anywhere in the UI. The model now keeps every finished row and the Done group has a **Show all** / **Show fewer** control that draws the rest in place; collapsed, and at or under the cap, the group reads exactly as before. +- A decided meeting that saved no folder keeps the cards it decided, so its decision text is open to the same readers as one that saved a folder ([#2052](https://github.com/ThinkFlowLab/FlyBot/issues/2052)): before this a record written with an empty `decisionDir` was listed from the Project's own `decisions/` folder with no cards behind it, and a member of the same Project who could not see the meeting's card could still read the text, while the same file saved into a folder was refused as `not listed`. A record that decided no card still answers through the role list, and a name the folder did not list still opens nothing. +- A Project folder's `decisions/` must itself be a real directory: a link to another folder, a link to a path that does not exist and a plain file all read as no decisions at all, so `project_state`, the Project digest and the board's decision rows never list, hash or open another folder's files ([#2055](https://github.com/ThinkFlowLab/FlyBot/issues/2055)). +- A journal folder that is a symlink now records nothing, instead of letting the host change the permissions of the folder it points at and write the team's state journal there ([#2056](https://github.com/ThinkFlowLab/FlyBot/issues/2056)): the folder that holds `/journal/state.jsonl` must be a real directory, checked before anything is created, permissions changed or written, so a link to a folder outside the home stops recording with one warning the same way any other journal problem does. A real journal folder records exactly as before. +- A memory or workflows folder is now read as empty, and refused as a write target, when it is a symlink ([#2057](https://github.com/ThinkFlowLab/FlyBot/issues/2057), [#2068](https://github.com/ThinkFlowLab/FlyBot/issues/2068)): one resolver walks every segment of `/memory` — the root, `memory/bots`, the Bot's or team's own folder — and the same rule covers `snapshots`, `summaries`, `archive`, `reviewed.json` and `journal.jsonl`, plus a workspace's `workflows/`. Readers take only a real directory, so a link to a folder outside the home no longer feeds another folder's `MEMORY.md`, topics, prompt snapshot, summary or workflow definitions into a prompt, a listing or a page; a host write or delete still creates a folder that is not there yet, as before, and refuses a linked one instead of writing or deleting through it, and the entry writers behind `remember`, `edit` and `forget` refuse it the same way. A linked folder is named once per folder and process in one warning, because "nothing saved" and "nothing readable" look alike otherwise. A single `*.md`/`*.json` file that is a link is still read (unchanged), and a local process that can write inside the home can still win a redirect race. +- A decided meeting whose archived file cannot be read no longer takes the cards of the Project folder's same-named row ([#2061](https://github.com/ThinkFlowLab/FlyBot/issues/2061)): `archivedOf` now answers three mutually exclusive states (`none`, `unreadable`, `read`), so only a record that named no folder at all reaches the legacy card backfill while a record that named a folder keeps its cards off a row of a different folder — the answer no longer depends on the order the meetings happen to be stored in. +- A room board's rail counted only the newest page of the room's finished cards, so a Bot whose four cards were all still open read `0/1` on a board that also held one finished card, and the numbers disagreed with the cards drawn in the column beside them. The rail now counts the room's active cards as well, so the same Bot reads `1/4` and every Bot on the page reads the same total ([#2063](https://github.com/ThinkFlowLab/FlyBot/issues/2063)). +- The task board's Done column now follows the rail: switching from one Bot to another re-reads that Bot's archive page instead of keeping the one the board loaded for the previous Bot, which had left the newly selected Bot's Done column empty until the dialog was reopened ([#2070](https://github.com/ThinkFlowLab/FlyBot/issues/2070)). + ## [0.2.19] - 2026-11-01 ### Changed diff --git a/changelog.d/1949-rename-push.fixed.md b/changelog.d/1949-rename-push.fixed.md deleted file mode 100644 index 0ee9c386a..000000000 --- a/changelog.d/1949-rename-push.fixed.md +++ /dev/null @@ -1 +0,0 @@ -Renaming a group chat now reaches the guests already seated in it ([#1949](https://github.com/ThinkFlowLab/FlyBot/issues/1949)): the host pushed a membership envelope only when the notice changed, so a shared room kept its old title on the other homes until the next chat line, and a quiet room kept it indefinitely. A rename rides the same one `join` the notice edit already used — the envelope carries the name field it always carried — and a settings save that changes both the name and the notice still sends a single envelope, while a save that writes back the values the room already holds sends nothing. diff --git a/changelog.d/1954-arch-docs-no-shell.fixed.md b/changelog.d/1954-arch-docs-no-shell.fixed.md deleted file mode 100644 index facd11bab..000000000 --- a/changelog.d/1954-arch-docs-no-shell.fixed.md +++ /dev/null @@ -1 +0,0 @@ -The architecture-docs gate no longer starts git through a shell ([#1954](https://github.com/ThinkFlowLab/FlyBot/issues/1954)): on Windows the gate handed `git rev-parse --verify origin/main^{commit}` to cmd.exe, `^` is cmd's escape character, so the `^{commit}` never reached git and every scheduled Windows row reported `arch-docs: FAIL — cannot diff against origin/main` on a checkout where `origin/main` existed. git now runs with its arguments as a list, the ref verbatim, and the fail-closed behaviour on a genuinely missing base ref is unchanged. diff --git a/changelog.d/1956-task-card-text-code-point-bound.fixed.md b/changelog.d/1956-task-card-text-code-point-bound.fixed.md deleted file mode 100644 index 6d5c39090..000000000 --- a/changelog.d/1956-task-card-text-code-point-bound.fixed.md +++ /dev/null @@ -1 +0,0 @@ -The task card's three 2,000-unit text bounds now cut on a code point boundary: the result summary a Done move copies from the card's note, the criteria stored at create, and the summary a return writes drop a surrogate pair whole instead of storing a lone surrogate that the card shows as U+FFFD ([#1956](https://github.com/ThinkFlowLab/FlyBot/issues/1956)). diff --git a/changelog.d/1958-oneline-code-point-bound.fixed.md b/changelog.d/1958-oneline-code-point-bound.fixed.md deleted file mode 100644 index 9c36e3b04..000000000 --- a/changelog.d/1958-oneline-code-point-bound.fixed.md +++ /dev/null @@ -1 +0,0 @@ -The task card's title and note and a dispatched card's title and note are cut at 300 characters on a code point boundary, so a bound that lands inside an emoji or other astral character keeps whole characters instead of storing a lone surrogate the card shows as U+FFFD ([#1958](https://github.com/ThinkFlowLab/FlyBot/issues/1958)). diff --git a/changelog.d/1960-room-context-code-point-bound.fixed.md b/changelog.d/1960-room-context-code-point-bound.fixed.md deleted file mode 100644 index 182ffb274..000000000 --- a/changelog.d/1960-room-context-code-point-bound.fixed.md +++ /dev/null @@ -1 +0,0 @@ -A room turn and the stored `room.log` no longer split a surrogate pair at a character bound: the status stub's hundred units, the transcript clip, and the card, board and presence fields now cut on a code point boundary, so a title or a Bot essay that ends on an emoji keeps the whole emoji instead of an unpaired half the encoder turns into U+FFFD ([#1960](https://github.com/ThinkFlowLab/FlyBot/issues/1960)). diff --git a/changelog.d/1962-room-settings-line.fixed.md b/changelog.d/1962-room-settings-line.fixed.md deleted file mode 100644 index 55bc71703..000000000 --- a/changelog.d/1962-room-settings-line.fixed.md +++ /dev/null @@ -1 +0,0 @@ -A group settings change now leaves one line in the room: renaming the room, editing or clearing the notice, switching the reply mode, or naming a new admin or task lead posts a single quiet event that says what changed and who changed it, opens no Bot turn, and stays quiet when a patch writes back the values the room already holds or when an unnamed room's title follows its members ([#1962](https://github.com/ThinkFlowLab/FlyBot/issues/1962)). diff --git a/changelog.d/1963-cut-wellformed.fixed.md b/changelog.d/1963-cut-wellformed.fixed.md deleted file mode 100644 index 05ecacd95..000000000 --- a/changelog.d/1963-cut-wellformed.fixed.md +++ /dev/null @@ -1 +0,0 @@ -A text bound no longer keeps an unpaired surrogate the caller handed in ([#1963](https://github.com/ThinkFlowLab/FlyBot/issues/1963)): every character bound in the host goes through the shared `cut`, and that helper moved its cut point off a pair it was about to split but copied a string that already carried a lone surrogate straight through, so a card title, a note or a name that arrived broken was written to `state.json` as the same broken value — read back as U+FFFD by any encoder. `cut` now flattens its input with `toWellFormed()` before it bounds, so the stored text is well formed; U+FFFD is one UTF-16 unit for the one it replaces, so a well-formed input keeps its exact prefix and its "was cut" flag. diff --git a/changelog.d/1967-settings-line-attribution.fixed.md b/changelog.d/1967-settings-line-attribution.fixed.md deleted file mode 100644 index 028147636..000000000 --- a/changelog.d/1967-settings-line-attribution.fixed.md +++ /dev/null @@ -1 +0,0 @@ -The one line a group-settings save leaves in the room now names the person who saved it on the default single-user setup ([#1967](https://github.com/ThinkFlowLab/FlyBot/issues/1967)): the web UI has no member session, so the save reached the host with no name and every rename, notice, mode or admin change read "Someone updated the group notice". The line now takes the room's implicit owner — the local person whose Bots sit in it — while a signed-in member and a Bot saving through its own tool still win, and only a room with no owner at all falls back to "the user". diff --git a/changelog.d/1968-rename-push-auto.fixed.md b/changelog.d/1968-rename-push-auto.fixed.md deleted file mode 100644 index 4cc4c2ea7..000000000 --- a/changelog.d/1968-rename-push-auto.fixed.md +++ /dev/null @@ -1 +0,0 @@ -Renaming a Bot now reaches the guests already seated in every unnamed group it sits in ([#1968](https://github.com/ThinkFlowLab/FlyBot/issues/1968)): the host recomputed the room's title from its members and retitled the room locally, but pushed nothing, so a shared group kept its old title on the other homes until the next chat line and a quiet group kept it indefinitely. The automatic rename now rides the same one `join` an explicit rename already used (#1949) and carries the new name, while a rename that leaves the computed title alone — a Bot outside the group, a group with a chosen name, a group with no remote guest — still sends nothing. diff --git a/changelog.d/1973-arch-docs-win-guard.fixed.md b/changelog.d/1973-arch-docs-win-guard.fixed.md deleted file mode 100644 index 4a664aa7f..000000000 --- a/changelog.d/1973-arch-docs-win-guard.fixed.md +++ /dev/null @@ -1 +0,0 @@ -The Windows Compatibility job no longer fails on a test case that can only run on POSIX ([#1973](https://github.com/ThinkFlowLab/FlyBot/issues/1973)): the case proving the arch-docs gate never hands git's arguments to a shell observes that by running a fake `git`, which has to be an executable script with an interpreter line — Windows cannot launch one and would fail the job with `ENOENT`. The case is now marked skipped on Windows rather than quietly passing, and the same job's Lint step still runs the real gate there, so the platform stays covered. diff --git a/changelog.d/1976-store-auto-name.fixed.md b/changelog.d/1976-store-auto-name.fixed.md deleted file mode 100644 index 86ed94e73..000000000 --- a/changelog.d/1976-store-auto-name.fixed.md +++ /dev/null @@ -1 +0,0 @@ -A restart no longer renames an unnamed group to `You, …` or drops its remote guests ([#1976](https://github.com/ThinkFlowLab/FlyBot/issues/1976)). On load the host compared the stored title with the name computed from the room's people and guests, then wrote a title computed from the member Bots alone: the owner became `You`, every remote guest fell out of the name, and because that name could never match again the file and the group's Session title were rewritten on every boot. Both the comparison and the write now use the one name that sees the room, so a restart migrates an old title once and then leaves it alone. diff --git a/changelog.d/1979-external-text-bounds.fixed.md b/changelog.d/1979-external-text-bounds.fixed.md deleted file mode 100644 index 26774306a..000000000 --- a/changelog.d/1979-external-text-bounds.fixed.md +++ /dev/null @@ -1 +0,0 @@ -Six bounds on text another home or another person supplied no longer cut on UTF-16 units ([#1979](https://github.com/ThinkFlowLab/FlyBot/issues/1979)): a connector item name (80), a role label another home set on a face-room seat (80), a cross-home group name (200), a capability description from a peer server (2,000), a remote home's own error text (157) and an abbreviated remote reply (80) used a bare `slice`, so a bound that landed between the halves of a surrogate pair produced a lone high surrogate — read as U+FFFD by any encoder and shown to the owner that way. Each now goes through the shared `cut`, which keeps the longest prefix that stops before a split pair within the same budget; the error preview's `…` and the reply's trailing-period strip still apply to the cut value. diff --git a/changelog.d/1984-turns-code-point-bounds.fixed.md b/changelog.d/1984-turns-code-point-bounds.fixed.md deleted file mode 100644 index 037c0dd07..000000000 --- a/changelog.d/1984-turns-code-point-bounds.fixed.md +++ /dev/null @@ -1 +0,0 @@ -The host's turn lines no longer split a surrogate pair at their character bounds ([#1984](https://github.com/ThinkFlowLab/FlyBot/issues/1984)): a failed turn's 500-unit message, the 200-unit message of its one-line reason, the 79-unit step a running call shows, an approval card's 300-unit description and 400-unit command, and the 160-unit reason a failed turn leaves for the inbox now cut on a code point boundary, so a line that ends on an emoji keeps the whole emoji instead of an unpaired half the encoder turns into U+FFFD. diff --git a/changelog.d/1990-p321-remote-chat-name-bound.fixed.md b/changelog.d/1990-p321-remote-chat-name-bound.fixed.md deleted file mode 100644 index 731e76b09..000000000 --- a/changelog.d/1990-p321-remote-chat-name-bound.fixed.md +++ /dev/null @@ -1 +0,0 @@ -The name a friend's Bot keeps is cut on code points at both places the chat stores it: creating the chat (40) and refreshing its name (40) used a bare `slice`, so a name whose bound fell between the halves of a surrogate pair became a lone high surrogate — shown as U+FFFD once `roster.createBot` bounded it again. Both now go through the shared `cut`, so the longest whole-code-point prefix within the same 40-unit budget is kept, and a short name is stored word for word ([#1990](https://github.com/ThinkFlowLab/FlyBot/issues/1990)). diff --git a/changelog.d/1992-approval-command-cut.fixed.md b/changelog.d/1992-approval-command-cut.fixed.md deleted file mode 100644 index a165fb07e..000000000 --- a/changelog.d/1992-approval-command-cut.fixed.md +++ /dev/null @@ -1 +0,0 @@ -An approval card now stores the command "Allow once" runs instead of clipping it at 400 units: the description and command bounds are 2,000 and 4,000, a value that still has to be cut ends with an ellipsis inside that bound, and the card wraps and scrolls a long command rather than drawing it as one clipped line ([#1992](https://github.com/ThinkFlowLab/FlyBot/issues/1992)). diff --git a/changelog.d/1993-p2-c5-remaining.fixed.md b/changelog.d/1993-p2-c5-remaining.fixed.md deleted file mode 100644 index f6f29d65d..000000000 --- a/changelog.d/1993-p2-c5-remaining.fixed.md +++ /dev/null @@ -1 +0,0 @@ -The last five text bounds in `core/src/host/` no longer cut on UTF-16 units ([#1993](https://github.com/ThinkFlowLab/FlyBot/issues/1993)): the quoted first line of a checkpoint's kept tail (80), an approval record's reason (500), a mention receipt's reason line (240), the title given to a DSH Agent's Session (80) and a schedule run's failure reason (200) used a bare `slice`, so a bound that landed between the halves of a surrogate pair stored a lone high surrogate — read as U+FFFD by any encoder. Each now goes through the shared `cut`, which keeps within the same budget the longest prefix that stops before a split pair; none of the five maxima changes. diff --git a/changelog.d/1995-unnamed-title-follows-seats.fixed.md b/changelog.d/1995-unnamed-title-follows-seats.fixed.md deleted file mode 100644 index 88cd81458..000000000 --- a/changelog.d/1995-unnamed-title-follows-seats.fixed.md +++ /dev/null @@ -1 +0,0 @@ -The title of a group without a chosen name follows its seats now ([#1995](https://github.com/ThinkFlowLab/FlyBot/issues/1995)): a friend's Bot invited to such a group appears in its name and in the group's Session title the moment the seat exists, and a seat that leaves drops out of both instead of staying in `state.json` until a restart. Before this, only a settings save or a renamed Bot recomputed that name, so inviting or removing a guest left the title reading the old set of people while the roster had already changed. A group created together with a guest was opened under the narrow name — `You, Chief A, Chief B`, with the guest missing — and was corrected in `state.json` without ever reaching the Session the user reads. A group with a chosen name keeps it. diff --git a/changelog.d/2001-recall-remaining.fixed.md b/changelog.d/2001-recall-remaining.fixed.md deleted file mode 100644 index 616d3202c..000000000 --- a/changelog.d/2001-recall-remaining.fixed.md +++ /dev/null @@ -1 +0,0 @@ -`recall` now says when it cut its hit list ([#2001](https://github.com/ThinkFlowLab/FlyBot/issues/2001)): a keyword search with more than 30 matches ends with `N more entries match; narrow the query or read a topic` and the exact count (`1 more entry matches; …` when exactly one is left out), and a `semantic: "true"` search asks the index for one entry past the cap and ends with `more entries match this meaning than are shown; narrow the query or read a topic`. Before this, a Bot with 35 matching entries was shown 30 and told nothing, so entry 31 read as not existing. The cap stays 30 and a reply that shows every match adds no line. diff --git a/changelog.d/2002-connector-error-cut.fixed.md b/changelog.d/2002-connector-error-cut.fixed.md deleted file mode 100644 index c9fac6072..000000000 --- a/changelog.d/2002-connector-error-cut.fixed.md +++ /dev/null @@ -1 +0,0 @@ -A connector or MCP server's error no longer reaches the owner's card as U+FFFD ([#2002](https://github.com/ThinkFlowLab/FlyBot/issues/2002)): the 300-unit `reason` in `core/src/host/connectors.js` used a bare `slice`, so a message whose 300th UTF-16 unit landed inside a surrogate pair was stored with a lone high surrogate. It now goes through the shared `cut`, which keeps within the same 300 the longest prefix that stops before a split pair; a message under the bound is stored word for word. diff --git a/changelog.d/2004-seat-rename-broadcast.fixed.md b/changelog.d/2004-seat-rename-broadcast.fixed.md deleted file mode 100644 index 87256e7d6..000000000 --- a/changelog.d/2004-seat-rename-broadcast.fixed.md +++ /dev/null @@ -1 +0,0 @@ -A guest already seated in a group without a chosen name learns the new name as soon as another seat joins or leaves ([#2004](https://github.com/ThinkFlowLab/FlyBot/issues/2004)): before this the host moved its own name and Session title while the other homes kept the copy they arrived with, and only a guest arriving after the change was told, so the drawer and the group settings could still read a set of seats that had already changed. The seat that changed keeps its one targeted join; the guests already in the room get one more carrying the same text the host holds. A group with a chosen name, a mirror of another home's room and a face-to-face room still send nothing for a seat change. diff --git a/changelog.d/2005-project-panel-code-points.fixed.md b/changelog.d/2005-project-panel-code-points.fixed.md deleted file mode 100644 index c267178ac..000000000 --- a/changelog.d/2005-project-panel-code-points.fixed.md +++ /dev/null @@ -1 +0,0 @@ -Five Project-panel bounds now cut on a code point boundary, so a dossier or a board card no longer carries half an emoji: the assistant digest's 77-unit card title, the board's 200-unit one-line reason and decision title, and the dossier's capped name, role, persona, model and color, plus its 4,000-unit memory head — that last one is bounded where the memory is read, so the character is dropped whole instead of reaching the panel as U+FFFD ([#2005](https://github.com/ThinkFlowLab/FlyBot/issues/2005)). diff --git a/changelog.d/2006-memory-bounds-code-points.fixed.md b/changelog.d/2006-memory-bounds-code-points.fixed.md deleted file mode 100644 index c01b61334..000000000 --- a/changelog.d/2006-memory-bounds-code-points.fixed.md +++ /dev/null @@ -1 +0,0 @@ -Four memory bounds now cut on a code-point boundary, so the news line, a `recall` query, the saved summary and the memory panel's ask prompt can no longer keep half an emoji, which every encoder shows as U+FFFD ([#2006](https://github.com/ThinkFlowLab/FlyBot/issues/2006)). Each bound still holds its 160, 120, 8,000 or 2,000 units and the character that would not fit is dropped whole. diff --git a/changelog.d/2009-human-seat-rename-broadcast.fixed.md b/changelog.d/2009-human-seat-rename-broadcast.fixed.md deleted file mode 100644 index e3727c7d8..000000000 --- a/changelog.d/2009-human-seat-rename-broadcast.fixed.md +++ /dev/null @@ -1 +0,0 @@ -Adding or removing a person in a group without a chosen name now tells the guests already seated the new name ([#2009](https://github.com/ThinkFlowLab/FlyBot/issues/2009)): before this a human seat moved the host's own name and Session title while the other homes kept the copy they arrived with, because only a Bot's seat change sent the one `join` a guest holds. A group with a chosen name, a mirror of another home's room and a face-to-face room still send nothing for a seat change. diff --git a/changelog.d/2010-startup-rename-notify.fixed.md b/changelog.d/2010-startup-rename-notify.fixed.md deleted file mode 100644 index 734eca3e1..000000000 --- a/changelog.d/2010-startup-rename-notify.fixed.md +++ /dev/null @@ -1 +0,0 @@ -A group without a chosen name that is renamed when FlyBot starts now tells the guests already seated the name it settled on ([#2010](https://github.com/ThinkFlowLab/FlyBot/issues/2010)): before this the load rewrote the name and the group Session title while every other home kept the copy it arrived with, so the two sides disagreed until that guest happened to join again. A group with no remote guest, a mirror of another home's room and a face-to-face room still send nothing. diff --git a/changelog.d/2016-connector-error-bound.fixed.md b/changelog.d/2016-connector-error-bound.fixed.md deleted file mode 100644 index f26c9f923..000000000 --- a/changelog.d/2016-connector-error-bound.fixed.md +++ /dev/null @@ -1 +0,0 @@ -A connector's failure text no longer stops at 300 units without saying so ([#2016](https://github.com/ThinkFlowLab/FlyBot/issues/2016)): the `reason` stored on the owner's connector card now holds up to 2,000 — the bound another server's own description already uses — and a message that still has to be cut ends with `…` inside that bound, so the card says what it abridged instead of showing a sentence that stops mid-word as the server's whole answer. A message at or under 2,000 is stored word for word. diff --git a/changelog.d/2017-workflow-avatar-code-point.fixed.md b/changelog.d/2017-workflow-avatar-code-point.fixed.md deleted file mode 100644 index fb9060125..000000000 --- a/changelog.d/2017-workflow-avatar-code-point.fixed.md +++ /dev/null @@ -1 +0,0 @@ -A Workflow node's avatar now shows the first character of its name ([#2017](https://github.com/ThinkFlowLab/FlyBot/issues/2017)): the circle took the name's first UTF-16 unit, so a node called `🚀 Deployer` showed half an emoji on the flowchart and in the run view. It takes the first code point instead, and a node with no name still shows `?`. diff --git a/changelog.d/2021-project-board-decision-total.fixed.md b/changelog.d/2021-project-board-decision-total.fixed.md deleted file mode 100644 index 0c271d9b4..000000000 --- a/changelog.d/2021-project-board-decision-total.fixed.md +++ /dev/null @@ -1 +0,0 @@ -The Project board now keeps the newest 200 decisions and says how many it found ([#2021](https://github.com/ThinkFlowLab/FlyBot/issues/2021)): the read sorted the decision paths ascending and took the first 200, so a Project past the cap dropped the files it had just written, and a full list and a truncated one both read as the same number. The cut takes the tail now — the order on screen is still oldest first — the decisions read answers `total`, taken after the one-row-per-path dedup and before the cut, the meetings read answers `decidedTotal` / `pendingTotal` per list, and the board draws one `N more not shown` / 还有 N 条未显示 line under each list it shortened, with `data-decisions-total` beside the rows-drawn count. A list at or under its cap answers the same rows as before, plus the count. diff --git a/changelog.d/2024-schedules-drawer-paused-next.fixed.md b/changelog.d/2024-schedules-drawer-paused-next.fixed.md deleted file mode 100644 index 60a0c5e7b..000000000 --- a/changelog.d/2024-schedules-drawer-paused-next.fixed.md +++ /dev/null @@ -1 +0,0 @@ -A Bot's Scheduled tasks block in its details panel now lists the Bot's paused and finished tasks instead of claiming the Bot has none, and each row says when it runs next — `Next: …`, `Paused` or `Finished` — rather than only the repeat rule ([#2024](https://github.com/ThinkFlowLab/FlyBot/issues/2024)). diff --git a/changelog.d/2027-connector-error-copy.fixed.md b/changelog.d/2027-connector-error-copy.fixed.md deleted file mode 100644 index 7d69e193e..000000000 --- a/changelog.d/2027-connector-error-copy.fixed.md +++ /dev/null @@ -1 +0,0 @@ -A failed connector's error text is now copyable in one click ([#2027](https://github.com/ThinkFlowLab/FlyBot/issues/2027)): since [#2022](https://github.com/ThinkFlowLab/FlyBot/issues/2022) a row in the `error` state can carry up to 2,000 characters of the host's own failure text, but its only actions were `Try again` and `Disconnect`, so passing that sentence on meant selecting it by hand — close to impossible on a phone. The row now offers `Copy error` next to `Try again`, which puts the exact stored text on the clipboard through the shared helper and reads `Copied` when it landed and `Could not copy the error` when the page has no clipboard or the write was refused, never a quiet success ([#1347](https://github.com/ThinkFlowLab/FlyBot/issues/1347)). `ready` and `off` rows are unchanged. diff --git a/changelog.d/2029-blocked-card-age.changed.md b/changelog.d/2029-blocked-card-age.changed.md deleted file mode 100644 index 010f48189..000000000 --- a/changelog.d/2029-blocked-card-age.changed.md +++ /dev/null @@ -1 +0,0 @@ -A Project board's Blocked group now says how long a card has been stuck, and lists the card stuck longest first ([#2029](https://github.com/ThinkFlowLab/FlyBot/issues/2029)): the row kept the card's own reason and read the same whether the card had been blocked for three days or three minutes, and the group was unsorted. The host now answers `since` / `waitedMs` from the question's own `requestedAt` stamp — a card whose ask wrote no stamp shows no duration rather than an invented one — and the board draws `reason · 2d`, ordering the group oldest first the way Waiting already is. diff --git a/changelog.d/2030-schedules-summary-more.changed.md b/changelog.d/2030-schedules-summary-more.changed.md deleted file mode 100644 index a45b111c8..000000000 --- a/changelog.d/2030-schedules-summary-more.changed.md +++ /dev/null @@ -1 +0,0 @@ -A Bot's Scheduled tasks line in its details panel says how many tasks the Bot has and, past the three rows it draws, one **2 more not shown** row opens the full list ([#2030](https://github.com/ThinkFlowLab/FlyBot/issues/2030)). diff --git a/changelog.d/2033-decision-path-cap.fixed.md b/changelog.d/2033-decision-path-cap.fixed.md deleted file mode 100644 index 8f79b1b8c..000000000 --- a/changelog.d/2033-decision-path-cap.fixed.md +++ /dev/null @@ -1 +0,0 @@ -A decided meeting's row on a Project board no longer reports `decision file gone` for a file that is still there ([#2033](https://github.com/ThinkFlowLab/FlyBot/issues/2033)): the board lists only the newest 200 decision files ([#2021](https://github.com/ThinkFlowLab/FlyBot/issues/2021)), and the lookup behind a meeting's own file name was built from that cut list, so every decided meeting whose file fell off the oldest end claimed its file had been deleted — while the same read reported the full count. The lookup now falls back to the names this read actually saw in the folder, so a file past the cut is named and only a name the folder no longer holds reads as gone; the fallback takes names from that read, never from the filesystem, so `../outside.md` still yields no path. diff --git a/changelog.d/2035-schedules-unknown-guard.fixed.md b/changelog.d/2035-schedules-unknown-guard.fixed.md deleted file mode 100644 index 6b0118c84..000000000 --- a/changelog.d/2035-schedules-unknown-guard.fixed.md +++ /dev/null @@ -1 +0,0 @@ -A Bot's details panel no longer says "No scheduled tasks yet. Add one" before it has read the Bot's scheduled tasks: the line kept the shared view's `null` (nothing read yet) and treated it as an empty list, so the first frame — and every frame after a first read that failed, since the error was swallowed and the shared view stayed `null` — offered the new-task form on a Bot that may well have tasks. It now draws nothing until a read answers, the way the settings card beside it already did, and the empty state is kept for a read that answers zero ([#2035](https://github.com/ThinkFlowLab/FlyBot/issues/2035)). diff --git a/changelog.d/2037-decision-name-guard.fixed.md b/changelog.d/2037-decision-name-guard.fixed.md deleted file mode 100644 index e2e66f0f5..000000000 --- a/changelog.d/2037-decision-name-guard.fixed.md +++ /dev/null @@ -1 +0,0 @@ -A decision file name can no longer reach outside the project, and a symlinked Project State file is no longer read ([#2037](https://github.com/ThinkFlowLab/FlyBot/issues/2037)): the board accepted any name that started with `decisions/` and ended in `.md`, so a hand-edited `decisionFile` or a crafted folder name such as `decisions/zz/../../../outside.md` put a file outside the folder in a row — with its `path` and its first line as `title` — and the same name could come back through the `known` fallback past the 200-row cut. One rule now decides a decision name at the point the listing is produced: exactly one segment under `decisions/`, ending in `.md`, used by the listing, the reader and the fallback alike; a symlink is refused too, and `project_state` answers `absent` for a symlinked file instead of handing over the text it points at. diff --git a/changelog.d/2039-room-schedules.fixed.md b/changelog.d/2039-room-schedules.fixed.md deleted file mode 100644 index 038d84663..000000000 --- a/changelog.d/2039-room-schedules.fixed.md +++ /dev/null @@ -1 +0,0 @@ -A group chat's details panel now lists the scheduled tasks that room owns. Before, a task could target a group chat — the new-task form offered `Group chats`, and Settings grouped tasks by room — but the room itself showed nothing, so "is the 9am task on this room still there?" meant leaving the room for Settings. The panel draws the three newest of the room's tasks, a title carrying the real count and `N more not shown` past three, and only tasks that carry this room's `roomId` and no `botId`: a Bot's task and another room's task stay out. Rows open the settings list, a room with no tasks draws nothing at all, and a face-to-face room gets no such section ([#2039](https://github.com/ThinkFlowLab/FlyBot/issues/2039)). diff --git a/changelog.d/2041-decision-open.added.md b/changelog.d/2041-decision-open.added.md deleted file mode 100644 index d2b565a03..000000000 --- a/changelog.d/2041-decision-open.added.md +++ /dev/null @@ -1 +0,0 @@ -A decision row on the Project board now opens: activating a `decisions/*.md` row (by mouse or keyboard) shows that file's text under the row, and activating it again closes it ([#2041](https://github.com/ThinkFlowLab/FlyBot/issues/2041)) — before this, the board could list 200 decision files and open none of them. The text comes from a new host read that accepts only a name the board's own listing produced, including one past the 200-row cut, so a name like `decisions/../outside.md`, an absolute path, a name one level down or a symlink answers `not listed` without touching the disk; a file over 200,000 bytes answers `too large` rather than being cut, and a row whose file was deleted answers `absent` and stays a row. diff --git a/changelog.d/2042-inbox-done-total.fixed.md b/changelog.d/2042-inbox-done-total.fixed.md deleted file mode 100644 index e5de079c8..000000000 --- a/changelog.d/2042-inbox-done-total.fixed.md +++ /dev/null @@ -1 +0,0 @@ -The Inbox's Done group draws at most 20 rows, and it no longer hides the rest silently: when the model had more finished cards than it drew, one **5 more not shown** line under the Done rows says how many were left out, in the same words the Project board uses for its own capped list. A Done group of 20 or fewer, and the empty group, read exactly as before ([#2042](https://github.com/ThinkFlowLab/FlyBot/issues/2042)). diff --git a/changelog.d/2043-dock-more-rooms.fixed.md b/changelog.d/2043-dock-more-rooms.fixed.md deleted file mode 100644 index eb39a62d1..000000000 --- a/changelog.d/2043-dock-more-rooms.fixed.md +++ /dev/null @@ -1 +0,0 @@ -The Bot's own-chat dock no longer drops rooms past the fourth silently: when it is at work in more than four, it draws four rows and then `1 more room` / `N more rooms` ([#2043](https://github.com/ThinkFlowLab/FlyBot/issues/2043)). diff --git a/changelog.d/2045-board-archive-counts.fixed.md b/changelog.d/2045-board-archive-counts.fixed.md deleted file mode 100644 index 7b0e4e0e6..000000000 --- a/changelog.d/2045-board-archive-counts.fixed.md +++ /dev/null @@ -1 +0,0 @@ -The task board's Done column is one archive page of 20 cards, and until now it presented that page as the whole story: a Bot with 45 finished tasks read **Done 20**, and its rail row read **20/22** as if 22 were everything. When the archive page is full the column heading now reads **20 newest** and the rail row reads **20+ done** — what was drawn, and that there is more; a page under the limit, and the empty board, read exactly as before ([#2045](https://github.com/ThinkFlowLab/FlyBot/issues/2045)). diff --git a/changelog.d/2048-room-rail-bound.fixed.md b/changelog.d/2048-room-rail-bound.fixed.md deleted file mode 100644 index a92d5325d..000000000 --- a/changelog.d/2048-room-rail-bound.fixed.md +++ /dev/null @@ -1 +0,0 @@ -The task board's group rail reads a Bot's own slice of the room's cut archive page as `done/total`, so a Bot with 18 of the newest 20 finished cards says `18/18` while the room holds 45. A full page is now a lower bound for every Bot on it (`18+ done`), and a page under the limit still reads its exact counts ([#2048](https://github.com/ThinkFlowLab/FlyBot/issues/2048)). diff --git a/changelog.d/2050-inbox-show-all.fixed.md b/changelog.d/2050-inbox-show-all.fixed.md deleted file mode 100644 index 60051a390..000000000 --- a/changelog.d/2050-inbox-show-all.fixed.md +++ /dev/null @@ -1 +0,0 @@ -The Inbox counted the finished tasks its Done group left out but gave no way to see them: with 29 finished tasks the group drew 20, said `9 more not shown`, and those nine were unreachable anywhere in the UI. The model now keeps every finished row and the Done group has a **Show all** / **Show fewer** control that draws the rest in place; collapsed, and at or under the cap, the group reads exactly as before. diff --git a/changelog.d/2052-decisiondir-card-binding.fixed.md b/changelog.d/2052-decisiondir-card-binding.fixed.md deleted file mode 100644 index f113c768b..000000000 --- a/changelog.d/2052-decisiondir-card-binding.fixed.md +++ /dev/null @@ -1 +0,0 @@ -A decided meeting that saved no folder keeps the cards it decided, so its decision text is open to the same readers as one that saved a folder ([#2052](https://github.com/ThinkFlowLab/FlyBot/issues/2052)): before this a record written with an empty `decisionDir` was listed from the Project's own `decisions/` folder with no cards behind it, and a member of the same Project who could not see the meeting's card could still read the text, while the same file saved into a folder was refused as `not listed`. A record that decided no card still answers through the role list, and a name the folder did not list still opens nothing. diff --git a/changelog.d/2055-decisions-dir-symlink.fixed.md b/changelog.d/2055-decisions-dir-symlink.fixed.md deleted file mode 100644 index 8c6b864fc..000000000 --- a/changelog.d/2055-decisions-dir-symlink.fixed.md +++ /dev/null @@ -1 +0,0 @@ -A Project folder's `decisions/` must itself be a real directory: a link to another folder, a link to a path that does not exist and a plain file all read as no decisions at all, so `project_state`, the Project digest and the board's decision rows never list, hash or open another folder's files ([#2055](https://github.com/ThinkFlowLab/FlyBot/issues/2055)). diff --git a/changelog.d/2056-journal-folder-symlink.fixed.md b/changelog.d/2056-journal-folder-symlink.fixed.md deleted file mode 100644 index 413dd9209..000000000 --- a/changelog.d/2056-journal-folder-symlink.fixed.md +++ /dev/null @@ -1 +0,0 @@ -A journal folder that is a symlink now records nothing, instead of letting the host change the permissions of the folder it points at and write the team's state journal there ([#2056](https://github.com/ThinkFlowLab/FlyBot/issues/2056)): the folder that holds `/journal/state.jsonl` must be a real directory, checked before anything is created, permissions changed or written, so a link to a folder outside the home stops recording with one warning the same way any other journal problem does. A real journal folder records exactly as before. diff --git a/changelog.d/2057-memory-workflows-dir-symlink.fixed.md b/changelog.d/2057-memory-workflows-dir-symlink.fixed.md deleted file mode 100644 index 343bde5a5..000000000 --- a/changelog.d/2057-memory-workflows-dir-symlink.fixed.md +++ /dev/null @@ -1 +0,0 @@ -A memory or workflows folder is now read as empty, and refused as a write target, when it is a symlink ([#2057](https://github.com/ThinkFlowLab/FlyBot/issues/2057), [#2068](https://github.com/ThinkFlowLab/FlyBot/issues/2068)): one resolver walks every segment of `/memory` — the root, `memory/bots`, the Bot's or team's own folder — and the same rule covers `snapshots`, `summaries`, `archive`, `reviewed.json` and `journal.jsonl`, plus a workspace's `workflows/`. Readers take only a real directory, so a link to a folder outside the home no longer feeds another folder's `MEMORY.md`, topics, prompt snapshot, summary or workflow definitions into a prompt, a listing or a page; a host write or delete still creates a folder that is not there yet, as before, and refuses a linked one instead of writing or deleting through it, and the entry writers behind `remember`, `edit` and `forget` refuse it the same way. A linked folder is named once per folder and process in one warning, because "nothing saved" and "nothing readable" look alike otherwise. A single `*.md`/`*.json` file that is a link is still read (unchanged), and a local process that can write inside the home can still win a redirect race. diff --git a/changelog.d/2061-unreadable-archive-cards.fixed.md b/changelog.d/2061-unreadable-archive-cards.fixed.md deleted file mode 100644 index 0141a6ffb..000000000 --- a/changelog.d/2061-unreadable-archive-cards.fixed.md +++ /dev/null @@ -1 +0,0 @@ -A decided meeting whose archived file cannot be read no longer takes the cards of the Project folder's same-named row ([#2061](https://github.com/ThinkFlowLab/FlyBot/issues/2061)): `archivedOf` now answers three mutually exclusive states (`none`, `unreadable`, `read`), so only a record that named no folder at all reaches the legacy card backfill while a record that named a folder keeps its cards off a row of a different folder — the answer no longer depends on the order the meetings happen to be stored in. diff --git a/changelog.d/2063-room-rail-active-cards.fixed.md b/changelog.d/2063-room-rail-active-cards.fixed.md deleted file mode 100644 index eab3470ed..000000000 --- a/changelog.d/2063-room-rail-active-cards.fixed.md +++ /dev/null @@ -1 +0,0 @@ -A room board's rail counted only the newest page of the room's finished cards, so a Bot whose four cards were all still open read `0/1` on a board that also held one finished card, and the numbers disagreed with the cards drawn in the column beside them. The rail now counts the room's active cards as well, so the same Bot reads `1/4` and every Bot on the page reads the same total ([#2063](https://github.com/ThinkFlowLab/FlyBot/issues/2063)). diff --git a/changelog.d/2070-kanban-rail-switch.fixed.md b/changelog.d/2070-kanban-rail-switch.fixed.md deleted file mode 100644 index d55acac98..000000000 --- a/changelog.d/2070-kanban-rail-switch.fixed.md +++ /dev/null @@ -1 +0,0 @@ -The task board's Done column now follows the rail: switching from one Bot to another re-reads that Bot's archive page instead of keeping the one the board loaded for the previous Bot, which had left the newly selected Bot's Done column empty until the dialog was reopened ([#2070](https://github.com/ThinkFlowLab/FlyBot/issues/2070)). diff --git a/core/package-lock.json b/core/package-lock.json index 64ad6259f..cdd29bec6 100644 --- a/core/package-lock.json +++ b/core/package-lock.json @@ -1,12 +1,12 @@ { "name": "ds-bot", - "version": "0.2.19", + "version": "0.2.20", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "ds-bot", - "version": "0.2.19", + "version": "0.2.20", "license": "Apache-2.0", "dependencies": { "@larksuiteoapi/node-sdk": "1.76.0" diff --git a/core/package.json b/core/package.json index 4b7be1ea1..a225b31cf 100644 --- a/core/package.json +++ b/core/package.json @@ -1,6 +1,6 @@ { "name": "ds-bot", - "version": "0.2.19", + "version": "0.2.20", "description": "DS Bot: a team of long-lived Bots for DeepSeek Harness, with Main Bots, Bot-to-Bot messages and group chats", "keywords": [ "dsh-plugin", diff --git a/patches/ds-bot/0007-version-and-tooling.patch b/patches/ds-bot/0007-version-and-tooling.patch index d5be01961..c96f194bf 100644 --- a/patches/ds-bot/0007-version-and-tooling.patch +++ b/patches/ds-bot/0007-version-and-tooling.patch @@ -68,14 +68,14 @@ diff --git a/package-lock.json b/package-lock.json { "name": "ds-bot", - "version": "0.1.5", -+ "version": "0.2.19", ++ "version": "0.2.20", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "ds-bot", - "version": "0.1.5", -+ "version": "0.2.19", ++ "version": "0.2.20", "license": "Apache-2.0", + "dependencies": { + "@larksuiteoapi/node-sdk": "1.76.0" @@ -706,7 +706,7 @@ diff --git a/package.json b/package.json { "name": "ds-bot", - "version": "0.1.5", -+ "version": "0.2.19", ++ "version": "0.2.20", "description": "DS Bot: a team of long-lived Bots for DeepSeek Harness, with Main Bots, Bot-to-Bot messages and group chats", "keywords": [ "dsh-plugin",