Skip to content

Releases

FlyBot v0.2.29

Choose a tag to compare

@github-actions github-actions released this 11 Nov 00:38
75781c1

Fixed

  • A Bot turn now carries its own outcome to the sender instead of leaving it in the wording: an answer says failure: false, a turn stopped before it answered says failure: true with the stop notice as its reason, and a failed one keeps its failure notice — so a workflow step classifies the step by that marker, a stop notice can no longer advance a run, and an answer that happens to quote a failure sentence can no longer fail one (#2742).
  • A Workflow run whose host call never answered no longer stays running for ever: a step whose deadline passes is ended as failed even while a dispatch, a release or a Bot start is still waiting, with its Bots released. A start whose Bots the host does not create within 60 seconds is refused, and a queued card a drain had already taken out of the queue goes back to it instead of disappearing. A lane also keeps its concurrency limit while a start is still waiting on the host: two steps ending in the same turn no longer start one card too many. (#2748)
  • A Workflow run whose Stop cannot release a Bot no longer retries for ever: after two deadline retries it ends failed as release-failed, with the ids the host would not remove and the attempt count on the run, so its lane slot comes back and the cards queued behind it start (#2750).
  • A tree reorganization no longer waits for ever on a host call that never answers: after 10 minutes the job is abandoned with its id in the log (flybot-tree: reorganization job <id> was abandoned after …), later placements, repairs and the daily tidy still run, and settled() still resolves. An abandoned exclusive() job reports abandoned: true with its job id instead of hanging. See #2751.
  • A card queued behind a run that ended failed now starts on its own: the load-time reap that ends a run a dead host left running drains the lane's queue the way any other terminal transition does, instead of leaving the card parked with a free slot until the next assign. See #2752.
  • A room whose stored join floor sits above its own room.seq no longer shows an empty history: the read path clamps that floor to room.seq, so the guest sees the line it joined at and every line after it, warns once per room, and leaves the stored state untouched (#2754).
  • A state.json whose saved room or Bot record is null no longer hides the whole team: the file as it was is kept as a state.json.broken-<stamp> copy, one warning names state.json, the room is folded to an empty member list (an unusable Bot record is dropped), and the repaired team loads and saves. A version-1 file still keeps its .v1 backup, and a read-only window records the evidence but never writes state.json. See #2755.
  • A track_tasks batch whose store write was refused no longer leaves the cards it committed in memory: the board is restored before the error, so a ghost card cannot ride the next save onto disk (#2761).
  • workflows/<id>.json — the file a saved workflow definition lives in — was written with writeFileSync, which opens the target at zero bytes and then writes, so a second window reading inside that window parsed half a definition (or nothing), list() skipped it as unparsable and open() answered workflow/not-found for a definition that was not lost. Saving now stages a private temp name in the same folder and renames it over the target, for both save() and the project.json pointer setDefault() writes, so every read sees the previous complete definition or the new one, and a crash inside the write leaves the old bytes whole. A temp name a crashed write left behind is swept by the next write, a failed write removes its own temp name, and a link planted at the temp name is refused before the first byte. See #2762.
  • A refused state save no longer leaves an unaccepted Always allow live in memory: the grant is rolled back and the refusal is reported, so the next matching card still asks instead of being answered on the owner's behalf; a refused Remove likewise keeps the grant it could not delete (#2764).
  • Reading a long room that was saved before rooms carried a seq counter no longer walks its log once per line: the read works out the join floor once and filters with that number, so a 20,000-line history reads in linear instead of quadratic time, with the same visible lines and the same one-time warning (#2766).
  • bot_schedules no longer prints next <a time that has already passed> for a task whose status is not active: such a row reads no next run (the same sentence paused rows already used) and keeps its status word, while an active row is unchanged. The settings page already said Finished for the same row, so the tool and the page now agree. See #2767.
  • ask_user now enforces the two-to-four answers its own card promises: a question with one option, or with more than four, is refused with Give two to four answers. and no card is stored, instead of accepting a single "choice" or silently dropping a seventh option (labels dropped as empty are not counted, so five given with two blanks is a three-button card and passes). Two to four options produce the same card and the same answer string as before. See #2771.
  • read_own_chat({ part: N }) no longer calls the current part "in your context" after a checkpoint condensed it. When the part carries a [Checkpoint N], the answer names the checkpoint, shows the newest messages that are still in context, and points at the words search for the rest; without a checkpoint, and for an ended or missing part, the answer is unchanged. See #2774.
  • update_bot now refuses a colour the host does not know, instead of answering Updated <name>. while the Bot keeps the colour it had; the refusal names the accepted colours (#2775).
  • core/dev/token-report.mjs with no --db now reads the ledger where the host writes it, $DSH_HOME/bot/usage.sqlite, instead of one directory above it, so the command runs on an ordinary install instead of exiting with "no ledger at" (#2778).
  • read_group_chat now says how many room lines its 30-line cap left out — Latest in "<room>" (newest 30 of 45, oldest first): — instead of printing a cut log as the whole log; an uncut read is byte-identical (#2780).
  • Two "Always allow" answers on the same Bot could lose one of the grants. A refused save put the whole list back the way it was found, and the second answer had already added its own grant to that list in memory, so the rollback dropped it — and a save queued behind the refused one could write a grant whose own save had been refused. Answers on one record now run one after another, so each rollback touches only its own grant.
  • boundedSpawn released the Bots a late spawn created only when the host’s late answer succeeded: a late failure carried the ids it had already made on error.spawned and the deadline branch only warned, so those hidden run Bots lived until the process exited. The deadline now releases that list too, while a refusal and a release that itself fails still warn (#2785).
  • A card queued behind a run ended by the reap a window runs when it takes the store over now starts on its own: the takeover reap drains the lane's queue like the load-time reap, instead of leaving the card parked with a free slot until some unrelated assign or ingest. See #2787.
  • read_group_chat resolved its floor from the Bot's own participant record and filtered the room log on the raw joinedSeq, so it never ran the #2754 clamp: a stored floor above the room's own room.seq — the shape a host counter left on a participant record before #2612/#2613 stopped the write — hid every line from that reader and answered "<room>" has no messages yet in a room the pane and every other reader still showed. The read now asks the membership window for its seat floor (rt.seatFloor), which applies the same clamp, memo and one-time warning as the human reads, and it keeps answering from room.seq when the room was saved before seq existed (#2790).
  • A room a friend publishes once per member is one chat again: the friends' list keys a remote chat by the room — the same published name at the same home — instead of by the member handle it arrived on, so one group no longer fills the sidebar with a row per member and keeps its history when that handle changes (#2797).
  • Feishu's app mode drew the App Secret as a bare .bt-secret-input — the masked field the Secrets page only ever places inside a bordered .bt-q-field wrapper — so it showed as a grey Paste or type the key line under the App ID box with no box and no label, and the form read as if only the App ID could be filled in. The connector form now gives every masked credential that same wrapper, so app mode shows an App Secret box beside the App ID box and the webhook field gets the border it was missing too (#2799).
  • The tree plugin's jobTimeoutMs config key now bounds a queu...
Read more

FlyBot v0.2.28

Choose a tag to compare

@github-actions github-actions released this 10 Nov 04:59
4c8ec30

Fixed

  • A window that takes over a workflow store after the other window closes no longer writes the copy it loaded while the other one was still running: the first read or write after it becomes the writer re-reads workflows.json, and it reaps the run the closed window left behind instead of leaving the lane blocked. A card that was only queued is kept and starts normally. See #2704.
  • inflight.json — the record that lets an interrupted turn resume — is now staged in a temp file and renamed over the old one, so a crash in the middle of the write leaves the previous complete notes instead of an empty or half-written file. Every turn and queued message the crash cut off is still picked up at the next start, where an empty file used to drop them all silently. A file that still cannot be parsed (a hand-edit, a disk error) is now reported once with its path and the reason instead of passing for "nothing was in flight", and a temp name a crashed write left behind is swept by the next host that writes. See #2705.
  • A timeline window that opens while another window is writing the trace no longer loses every span for the rest of its life: it asks for the writer lock again when it has something to write, begins persisting as soon as the other window closes, and keeps the segments already on disk. Until the lock is free a flush that wrote nothing answers false and names the reason once, instead of reporting success for a dropped span. See #2706.
  • Every message read_own_chat shows now names its part in the anchor, part N #<seq>, from the first message of a chat onward, so an anchor a Bot saved before the conversation moved to a second part still opens that same message afterwards. A bare #<seq> in an anchor written earlier keeps working and reads the part that is current now, but the answer says the part was guessed instead of reporting an exact hit — previously it silently returned a different message from another part and said exact: true. Anchors written the old way remain valid; nothing needs re-reading. See #2710.
  • read_own_chat no longer shows every message twice when a second window or a plugin activation indexes the same chat: the part's mark is read inside the transaction that writes the rows (so the second writer sees the first one's commit), and the index's lines table now refuses a second row for the same event. An index an older build already duplicated is rebuilt once from the Session logs on the next start, and the log says how many duplicated lines it found. A window another dsh keeps read-only now reads the existing chat-index.sqlite without creating, repairing or writing it, instead of writing the index behind the other window's back. See #2711.
  • A saved team whose group-chat record carries no members list (a hand edit, a restore from another machine, or a version-1 home from before the field) no longer makes FlyBot fail to start: the record's list is repaired to empty when the team is loaded, the room itself is kept, and the repaired team is saved, instead of every later load rejecting with no warning and no way to repair it from the UI. See #2714.
  • A saved team file whose fields that hold tables arrive as null — or as something else that is not a list or a record — no longer loads as a writable team that then fails every write. exchanges is repaired to an empty list and exchangeTurns, questions, rooms, bots, prefs and agents to an empty record when the team is loaded, and the repaired team is saved, so creating a Bot, renaming a room, posting in a group, a memory write and a delivery all work again instead of each throwing a stack trace that never named the team file as the problem. See #2715.
  • A team file that is empty or half written is now described as what it is instead of telling the person to update FlyBot. state.json holding {}, null, [] or an empty string parses but carries no version, and the read-only sentence used to read saved by a newer FlyBot; update FlyBot — a repair that cannot help an install already on the current version. It now reads the team file has no version — it is incomplete (an empty or half-written file), so the first thing a broken install shows points at the file to move aside. The newer-version sentence is kept for a file whose version is above this build's, the file is still never changed, and a zero-byte or truncated file keeps its existing backup-and-load-fresh path. See #2716.
  • A Bot Social settings or identity file that exists but cannot be read or parsed is no longer treated as "nothing was ever saved". A torn flybot-social-bots.<tag>.json used to make a server switch silently restart the Bot as a stranger — no member identity, no grants — and the next switch rewrote the only copy; the switch now refuses before anything moves, names the file and leaves its bytes alone. A torn flybot-social-server.json refuses at start instead of quietly connecting to the default server as if no server had been chosen, and a damaged credentials file of another server is warned about and left out of the known-server list. A file that is absent still means a first run. See #2717.
  • The decision log no longer shares one temp file between writers: the trim stages the retained log at decisions.jsonl.<pid>.<uuid>.tmp and renames it over the log, so two hosts of one team folder cannot take each other's temp away and report a write that never landed — the a decision was not written: … ENOENT … warning, and the trim that was lost with it, are gone (#2724). A read-only window, the second host of one team folder, now writes nothing at all: record_decision there appends no line, trims nothing, fires no decision event, and answers Not recorded: this window is read-only, … instead of claiming a record that is not on disk.
  • Pausing or resuming a workflow run while one of its steps was still dispatching no longer loses the control: both now land on the run record the lane holds, so a run paused during a dispatch stays paused when that dispatch returns and a run resumed during one stays resumed — the stage no longer reads 已暂停 while the run is running with its step deadline re-armed and no Resume pressed (#2734).
  • A card parked behind the concurrency limit is no longer dropped when the host refuses to start a Bot for it once: the parked row goes back to the head of the queue and starts on the next drain, instead of leaving the queue while the stored claim still answered already: true — which left the card in nobody's hands, with no run naming it, until a human used rematch (#2735).
  • A workflow store that parses but holds an entry that is not a workflow now answers store-unreadable instead of throwing out of every read of workflow/state: the panel gets the repair hint, and the damaged bytes are kept as workflows.json.broken-<stamp> before the next write, instead of a raw TypeError escaping each render (#2736).
  • A memory review answer that named a topic memory cannot use no longer throws the whole answer away: only that change is left out, the valid add, edit or remove beside it lands and the cursor moves past the lines that were read, and one warning per answer — not one per process — says how many this answer lost and why the first one was, so a later answer in the same Session still warns again while a secret keeps its silence and is not counted (#2739).
  • The /api/health route, the one answer given without a session, now uses the connection's fence verdict as it comes instead of comparing it to 403: a refusal with any other status (a newer code, or the 400 a connection answers for a request it cannot read) is written with that code and no health body leaves, and an answer that is not a status reaches the web server's 400 arm instead of being read as "not refused" (#2740).
  • A Workflow step whose Bot turn the host stopped before it answered is now reported as failed, with the stop notice as its reason, instead of finishing as done and handing that notice downstream as its output. A step's ordinary answer that merely mentions "model call failed" is no longer read as a failure. (#2741)

FlyBot v0.2.27

Choose a tag to compare

@github-actions github-actions released this 08 Nov 18:11
af9a30b

Fixed

  • A trace rotation whose flush is refused no longer prunes the oldest segment, so the last durable trace file stays on disk instead of being deleted while the newer records exist only in memory (#2624).
  • A timeline trace whose open is refused — a directory that cannot be listed, one removed underneath, or an I/O error — now gives its writer lock back instead of keeping it for the life of the process, so the next open in the same process and every later process succeeds once the problem is gone, and one transient read failure no longer leaves the on-disk trace switched off until a restart (#2629).
  • A Bot Social credentials, backup or settings file that exists but no longer parses is now refused with a message naming it instead of being read as "not configured", so a torn file no longer makes a restart register a new home identity and overwrite the old one. Writes land through a temp file and a rename, so a failed write leaves the previous file whole (#2631).
  • A grant or profile change that falls back to Bot Social's REST routes now gives up at the client's deadline instead of waiting forever, so a Bot Social server that accepts the connection and never answers shows a timeout error rather than a hung action (#2633).
  • An external participant whose room turn times out is now stopped instead of being left running, so a late answer to the timed-out turn can no longer become the next turn's answer — a slow process no longer replies one turn behind (#2634).
  • The group board (track_tasks) now matches a Bot name and a group name the way every other door does — trimmed, case-insensitive, a leading @ dropped from a Bot name and surrounding quotes from a group name — so assignee: "dev" and group: "delivery group" resolve the Bot and the room they name instead of being refused while the same state resolves them everywhere else. A name that matches no member or more than one still gets the same refusal (#2637).
  • A Project name, repository, default branch, owner id, working folder or status that ends in an emoji at its length bound is now cut on a character boundary, so state.json stores a whole character instead of half a surrogate pair that every UTF-8 write showed as a replacement character (#2638).
  • A person's own line in a face-to-face room is now capped at 18 000 code points instead of UTF-16 units, so an emoji at the bound is kept whole rather than stored as half a surrogate pair that every later UTF-8 write shows as a replacement character (#2641).
  • The social, timeline and workflow plugins now resolve $DSH_HOME the way the core does — a blank or whitespace value counts as unset, ~ expands, and the root is always absolute — so bot/flybot-social.json, bot/flybot-timeline and bot/flybot-workflow no longer move with the process's working directory (#2643).
  • A copied line no longer loses the front of a word that only starts with a Bot's name: Development plan is ready, Devices are offline, Released v0.2.26, Reviewers disagree and Chief concern about the tip copy exactly as the preview reads them, while a real Dev → Reviewer delegation trace is still removed (#2645).
  • A friend's Bot can no longer put its own CSS on your page: the image URL in its published look is checked where it enters and again in the page-wide mention stylesheet, so a value carrying a quote, a parenthesis, a backslash or a control character is dropped and the Bot is drawn with its colour and mask instead of its photo (#2646).
  • A Bot's stored GIF avatar now reaches friends as the picture itself instead of a generated shape, and a look Bot Social refuses is no longer recorded as synced: saving the same picture again retries it instead of being silently skipped (#2649).
  • The Project board reads every page of its GitHub pull-request and issue lists instead of the first hundred rows, so its seven-day merge and close medians and its day counts now cover the whole window rather than roughly the newest three days (#2650).
  • A define_workflow call that replaces a saved graph now stores its stepTimeoutMinutes instead of returning success while keeping the old value, and refuses a value outside 1..120 the way the create branch does; the workflow/graph save applies the same rule, while a save that omits the field still keeps what is stored (#2654).
  • The Inbox lists failed workflow runs again: the shell now reads the workflow pack through the plugin's flybot/workflow/state endpoint instead of the bare workflow/state the host refuses, so a failed run reaches the Needs list and its badge (#2656).
  • An issue fast-line run no longer ends failed after its pull request was already opened: a Triage step that prints its delivery as its own OUTPUT pr: 2657 (verified) — or as OUTPUT merged: <40-character sha> — now counts as work done, so the run continues to gate/enqueue/attest and its record keeps the pull request number instead of dying on a missing state line (#2658).
  • Two run_workflow calls that land in the same millisecond now start two runs instead of sharing a generated task id, so the second call is no longer silently dropped and no longer overwrites the first run's brief; a repeated dispatch that passes the same task explicitly is still de-duplicated (#2662).
  • Adding three or more Bots to one Parallel step in the New workflow dialog no longer gives two of them the same node id, so Create succeeds instead of failing with Node n2 is listed twice (#2663).
  • A card that has already finished — accepted, cancelled or failed — now refuses a late handoff with A finished task cannot be handed on instead of reopening itself as open, not-started and 0% under the next role, so a card that shows 100% can no longer slide back to the start of the board; the refusal is written the way the same card's "waiting on a question" write already is, and the refused write lands nothing at all, with claimedBy and the card's terminal state kept. A result-ready card still hands on, because that column is allowed to go back to working (#2667).
  • A workflow node is now told which OUTPUT lines it owes from its own declared outputs and from the outputs its outgoing edges read, with the accepted values spelled out (OUTPUT state: <one of: ready, blocked>), so a node that declares no outputs no longer runs every step into Missing OUTPUT state and fails (#2669).
  • A second, read-only DSH window on the same home no longer reaps or disposes the writer's live workflow: loading the plugin and closing that window both leave the run, its step Bots and the stored progress alone, and the writing host's own load-time reap decides (#2673).
  • A second, read-only DSH window on the same home no longer onboards a Bot Social home or writes the shared credentials file: it starts the social layer from the credentials the writable window already saved, so friends and messages stay visible, while the window that holds the team is the only one that can create a home or change that file (#2675).
  • A workflow step no longer fails because its own answer quotes could not answer your message while auditing that sentence: the host marks its real failure notice structurally, and an old host without the marker is read only from the notice shape at the start of the reply (#2677).
  • A turn that DSH ended at the model's output limit is no longer reported as a normal finish or as a member that chose silence: the activity feed marks turn.end with limited: true, the ended-turn view keeps the turn (with silent and the streak when it wrote nothing, and its own sentence in the chat instead of "could not run"), and a group member cut off before it answered is recorded as "no answer" instead of a pass (#2679).
  • A workflow file written by a newer FlyBot is no longer rewritten by an older one: the workspace store refuses to save over a definition whose version is higher than the one it writes and leaves it byte-identical, and lists it as a newer file instead of showing a definition that has lost fields it could not read. The workflow plugin does the same for workflows.json — workflow/state now answers store-newer-version with the version that wrote it, and every write is refused, so the owner's workflows, runs, claims and seq can no longer be replaced by the factory fixture (#2681).
  • A declared pr/pull OUTPUT now counts as delivery evidence only when its value is the pull number itself — a positive integer, an optional leading #, an optional trailing parenthetical such as 2657 (verified) — so a step that says it has no pull request is no longer read as one, and a l...
Read more

FlyBot v0.2.26

Choose a tag to compare

@github-actions github-actions released this 07 Nov 18:10
73edc8f

Added

  • FlyBot has a community WeChat group; the README now carries its QR code, with a note that the code expires and how to ask for a fresh one (#775).

Changed

  • A team can now cap its model turns per team-local day (prefs.turnBudget, 200 for a fresh team, 0 turns the budget off). At or over the cap only a turn the user starts themselves is still dispatched; scheduled reports, tidy passes and rounds a Bot starts are refused before a model call, with one line in the host log (#645).

Fixed

  • Face-to-face room names, role labels, platform lines and surface Bot Social's own failure text now cap on character boundaries instead of UTF-16 units, so an emoji at the cut is no longer split into a half character and shown as a replacement character (#2438).
  • The timeline's on-demand OTLP export no longer fails as a whole when the trace holds an old or hand-edited record without a usable time: a turn or tool call whose timestamps cannot be read is skipped, and the complete spans in the same trace are still exported (#2442).
  • Workflow failure text, task cues, co-seat room shares, workflow avatars and role lines, and timeline labels now cut on character boundaries instead of UTF-16 units, so an emoji is never split into a half character and rendered as a replacement character (#2581).
  • A workflow step that ends without the OUTPUT state: line its gate reads no longer kills the run when it has already done the work: a Triage node that opened a pull request or claimed the issue keeps its done status, the run continues, and run.outputMissing / run.producedPull record the slip and the pull request (#2583).
  • The Diagnostics report and its downloaded log survive a corrupt line in logs/diagnostics.jsonl: a line with no level or source, or a timestamp JSON parses as Infinity, is shown with that part defaulted instead of throwing the whole report away (#2591).
  • The meeting list — and every write that echoes a record back — keeps a stored meeting whose level is not one of ordinary, major or severe instead of throwing the whole list away; a write still refuses an unknown level (#2592).
  • A task update refused for an invalid priority, progress or column no longer leaves the card partly changed: task-update reads and validates the whole request before it writes, so a refused call leaves every task record exactly as it was (#2596).
  • A track_tasks batch that is refused no longer leaves the cards it had already created on the board: the whole list is validated on a staged copy of the board and only committed once every item passed, so a refused batch leaves state.tasks exactly as it was and posts no claim line for a card that never landed (#2597).
  • A workflow save that the store refused no longer leaves a half-created workflow in memory: the refusal is returned and the graph, its creation line and the sequence number are dropped, so the next successful save cannot persist a workflow the caller was told was not created; a refused rename keeps the name it could not save (#2598).
  • A workflow store that cannot be read is no longer answered as a clean list: workflow/state now reports store-unreadable with the file and the reason instead of the factory fixture, so the Workflows page says the store is unreadable instead of showing workflows that are not yours, and the first save keeps the unreadable bytes in workflows.json.broken-<stamp> before it writes a fresh store (#2603).
  • The Diagnostics report and its downloaded log now say when logs/diagnostics.jsonl could not be read at start-up, instead of reporting No host errors recorded. for a log that exists and holds errors: the report names the reason (not read (EACCES)), says that the errors the log holds are not shown, and the entry list and the download carry that reason rather than an empty answer, while the errors this host recorded since start-up stay listed (#2604).
  • Deleting a Bot now ends its seat in every group chat in the same save: the group's member list and a shared room's guest roster stop naming it, and the next membership change can no longer write the deleted id back into the room, also after a reload (#2607).
  • Opening, previewing or reading the bytes of a workflow whose id is not a plain file name no longer reaches a JSON file outside the workspace's workflows/ folder: the read path now accepts only the same ids the save path always did, so an id such as ../outside/stolen — or a stored default naming one — answers workflow/not-found instead of returning that file's definition (#2609).
  • A group shared with a friend's Bot now shows the room's recent messages right after the share, and every message that arrives afterwards, instead of an empty room that stayed empty until the host's message count reached the number the share carried: the guest numbers its mirrored copy of the room locally, so it no longer takes the host's line counter as the point where its own history starts, and a malformed counter in a share can no longer be stored or blank the room (#2612).
  • A workspace's workflows/ folder that is there but cannot be listed no longer answers "no workflows": the host now says workflow/unreadable and names the folder, a save that landed still reports wrote: true, and opening a workflow by name keeps working (#2614).
  • Removing the DSH Agent no longer drops a Session added while its earlier Sessions are still being archived: the removal applies its own archives to the live record, keeps any Session that arrived meanwhile, and asks you to remove the Agent again instead of leaving that Session orphaned (#2616).
  • The Project digest header now names the same Asia/Shanghai calendar day the digest is filed under, so a digest built between 00:00 and 08:00 no longer prints yesterday's date — including one held by quiet hours and replayed later (#2618).
  • The timeline panel's Copy report now prints the window's hours in your own time zone, the same hours the header above the button shows, instead of the Bot host's: the panel sends its browser zone with the request and the host formats the report in it, including the (+1 day) suffix on a window that crosses your midnight. A zone the host cannot use falls back to its own clock, as before (#2619).
  • Renaming a Bot now moves the DSH Session title before the stored record, so a refused title write leaves the Bot, its group chats and state.json under the old name instead of showing the new one until a restart silently reverts it (#2622).
  • Deleting a Workflow whose store write is refused now puts the workflow and its lane, run, log, route, claim and brief records back before the refusal reaches the page, so the list and workflows.json cannot disagree and the delete can be retried instead of answering No such workflow until a restart (#2623).

FlyBot v0.2.25

Choose a tag to compare

@github-actions github-actions released this 06 Nov 18:11
d5620ee

Added

  • The instance now answers GET /api/health without a session: a JSON object holding exactly ok, version, commit and startedAt, so a person or a monitor can ask which build is running instead of counting startup banners. It is served ahead of the sign-in wall as an exact route, keeps the wall's Host/Origin fence (loopback or a trusted authority only), answers GET only, and reports commit: null when the install has no git checkout of its own (#2128).
  • Settings → Plugins can turn the Bot Social, Tree, Timeline and Workflow plugins off and back on (#2564). The switch is kept in FlyBot's own state.json and applies at the next start: a plugin that is off registers no tools, panels or endpoints, and the packages stay installed so nothing has to be reinstalled.
  • A keyless browser suite now runs in CI: the scripted mock drives the same bench and web adapter as the real-model suite, so the web UI's message-and-reply path is measured on every pull request that touches core/ or plugins/ instead of only existing as a nightly that skips without a secret. The job reads no secret, its step summary names each check it ran, and the real-model live job is unchanged. (#2565)

Fixed

  • A long message the context steward reads now spends its 1,500-character budget in characters at both ends: the start keeps 1,000 characters and the end keeps 500, so a message dense in emoji shows the whole budget instead of only its first 1,000 characters, and the marker reports the 100 characters really left out instead of counting the surplus UTF-16 units a second time. (#2552)
  • The memory review's two-ended cut of the user's own line now spends its 3,000-character budget in characters at both ends: a line of 3,500 emoji keeps 3,000 characters (2,000 head, 1,000 tail) instead of 1,503, so the review no longer drops half of a long message written with characters outside the BMP. (#2553)
  • A memory review line that carried an unpaired surrogate now reaches the prompt as one whole character instead of half a pair: both of the review's render paths flatten the text first (#2556).
  • The memory review now leaves out only the one entry it cannot keep and lands the rest of the answer: an over-long entry beside a valid remove or edit used to discard the whole answer and read the same lines again next turn, without a bound on the repeats. The review warns once about what it left out, applies the changes it can, and moves its cursor past those lines. (#2558)
  • The memory review no longer asks the model over and over for the same lines it cannot change. Two failures at one cursor stop the retries with a single warning instead of one per turn, and the review resumes once a review succeeds or the user writes again, so a Session whose review keeps failing stops rereading the same messages forever. (#2561)

FlyBot v0.2.24

Choose a tag to compare

@github-actions github-actions released this 06 Nov 00:12
39bd520

Added

  • The diagnostics report now lists the backups the store leaves beside the team file — state.json.v1 and the state.json.broken-<stamp> copies — with their size and age, newest three broken copies plus a count of the rest, or state backups: none; a backup this host cannot read is named with its reason, and no backup is ever opened (#2434).
  • A workflow assignment resolves its brief from the task card, so re-dispatching the same card to another lane keeps the same facts and records one handoff line.
  • The Settings header, the details drawer, the Inbox and the Memory panel now draw a Reload beside the host's read-only sentence, so a window that was told to reload can do it where it stands instead of closing the panel and reaching for the sidebar (#2502).
  • A scheduled task can be run once from its own row even when its last run went fine: Run now joins Retry, a run in flight or a paused task offers neither, and running a task now leaves its next DSH run where it was (#2507).

Fixed

  • An open face-to-face room a home is a member of no longer disappears from that home's sidebar row list: a stored hidden flag is cleared by the room's open snapshot, and the sidebar's past-room and hidden-row filters never drop an open face room.
  • A workflow card re-matched into another workflow now leaves one Task re-matched · <task> → <destination> line on the source graph's own log, so the graph that lost the card says where it went instead of the card silently vanishing (#1668).
  • A read-only window's Settings → Projects page now draws no write the host would refuse: no name field, no New Project, no Bind to {name} choice on a Project row and no Unbind on a Project or on a binding, because project-create and project-bind are writes a reading window is refused. Open board, the Project rows with their names, working folders and members stay readable, and a writable window draws exactly the tree it drew before. (#2305)
  • A read-only window's Project board now draws no settings write the host would refuse: opening Project settings shows the host's own read-only sentence and Back to board instead of Bind, Unbind, the digest Save and Save memory, because project-bind, project-assistant-owner and project-memory-write are writes a reading window is refused. The board, its rows, the Members panel and the record stay readable, and a writable window draws the panel exactly as before. (#2306)
  • In a read-only window the New-Bot form now draws the host's own read-only sentence where Create was, instead of a form whose only answer from the host was bot/read-only; a writable window is unchanged (#2307).
  • A held message now says why it is waiting: the host's reason is drawn under the sender line on the session dock's approval card and on a held reply's own bubble in a chat, instead of living only in a hover title on the card and nowhere at all on the bubble. The visible line stops at 200 code points with an ellipsis and the whole sentence stays in the title, so a long reason is readable without hiding its end, and a reason that is empty or only whitespace draws no line at all (#2422).
  • The diagnostics report's state line no longer promises a read it could not make: a state.json that is a link to a plain file this host cannot read now keeps the same sentence as a link to a folder (not a plain file (nothing is read or written)), instead of saying the store reads the team file through the link directly above a Read-only row that reports that read failing with EACCES. The target's read permission is asked with access(), which opens nothing and reads no byte (#2428).
  • The tree model now treats a Bot retired with archive_bot as out of the tree everywhere: it no longer occupies its parent's maxChildren slot, and its children move up to its own parent instead of being stranded under a Bot that cannot be messaged (#2430).
  • A workflow's read-only run flowchart now names each wire for a reader and gives every route a 10px hit target of its own: pointing at one wire marks it and dims the rest, and the plane still writes nothing (#2431).
  • A Bot's Sharing card in a read-only window keeps People with access (who has this Bot, and its Auto-send state) and drops only its writes — no Revoke, no invite, no Share with a friend (#2446).
  • Fixed a room-share envelope being dropped when a chat line's own text carried one unbalanced brace, which lost the sent line and the join history copied into a join envelope (#2447).
  • A Bot retired with archive_bot now appears in the sidebar's Archived section at once, instead of up to one 10 s roster poll later (#2450).
  • A Workflow run frozen by a Stop whose Bot could not be released no longer holds its lane slot forever: the step deadline it was already counting now retries the release and ends the run as paused-expired, freeing the slot, and re-arms itself while the Bot still will not go. Before this, the deadline was consumed by the paused run and nothing ran again, so the workflow stayed at its maxConcurrent limit until the owner pressed Stop a second time (#2428).
  • project_state no longer reports a Project State file it cannot read as if the folder held none: a PROJECT.md that is a folder, or a file the process may not read, now answers unreadable: PROJECT.md (<reason>) beside the rows that could be read instead of the listing answering no Project State files in this folder, which said there was nothing to read while something was (#2461).
  • A read-only window no longer draws the write controls on the seven Settings pages that still had them: General (theme, accent and the notification switches), Bots (both Main Bot choices and the animation picker), a Bot's own settings, a group chat's settings, Connectors, Capabilities and Secrets. Each page now states its facts as plain text — the theme and accent in use, who holds the Main Bot role, the animation setting, a Bot's role, model, folder and instructions, a group's members and notice, each connector's state, each capability and each stored key with who may use it — because the host refuses every one of those writes with bot/read-only. New Bot stays as an entry, since the form behind it already explains the lock, and a writable window is unchanged. (#2474)
  • A workflow assignment's brief is now the caller's to clear. An explicit brief replaces the facts cached on the lane, and brief: '' clears them instead of falling back to the old text; deleting a workflow drops the facts it cached, so a later assignment carries nothing from it and records no handoff naming a lane that no longer exists (#2475).
  • A workflow card handed to a Bot now leaves the same Task re-matched · <task> → <destination> line on the source graph's own log that a hand-over to another workflow already wrote, and a hand-over into a workflow that is already running the card writes it too — the graph that lost the card says where it went instead of the card silently vanishing (#2480).
  • A face-to-face room's Hide from sidebar switch now holds: the hide a person chose survives the poll that re-reads the room every few seconds (and turning it back off survives too), while a hidden an older state left behind is still cleared by the room's open snapshot, as #1605 asked (#2482).
  • A workflow card a lane is holding can now be handed straight to a Bot from the panel, and the lane that lost it writes the same Task re-matched · <task> → <destination> line a hand-over to another lane already wrote — the source graph no longer drops the card silently when the destination is a Bot (#2485).
  • A workflow card whose facts were cleared no longer brings them back when it is re-matched into another lane: the re-match path now passes the card's current brief — its text when it holds facts, an explicit empty one when it does not — so the lane cache can no longer resurrect instructions the author removed (#2486).
  • In a window that holds the team read-only, Settings → Projects no longer tells the reader to create a Project: with no Project the empty state reads No Project yet. instead of No Project yet — create one., which pointed at the New Project section the same page had already hidden (#2489). A writable window and the Project board's own empty state keep the shared sentence.
  • In a read-only window a face-to-face group's Settings page names each person's Bots under them, and states who answers and the room's working folder, instead of drawing every person as Human while its own header counted the Bots.
  • Handing a card to a Workflow from the panel now carries the card's own facts into the run instead of droppin...
Read more

FlyBot v0.2.23

Choose a tag to compare

@github-actions github-actions released this 04 Nov 18:17
334960b

Added

  • A scheduled task's row now says which connectors its unattended run will carry, in the words of the Bot's own switches at the moment it fires: turning Composio on for that Bot changes what a task written weeks ago uses, and the row names it instead of the owner learning after the fact (#2323).

Changed

  • Settings → Feedback's Clear now says what it actually did: the same sentence when the log is gone, one that names the leftover logs/diagnostics.jsonl.1 when the rotated copy could not be removed, and one that does not claim a cleared log when the file is a link or a shared name (#2360).

Fixed

  • Settings → Feedback no longer offers Clear in a read-only window: Clear truncates the shared logs/diagnostics.jsonl on the host, so a window that only reads now leaves that file alone and keeps Download, Show, Copy and Report on GitHub. The host refuses diagnostics-clear from a reading window with bot/read-only instead of erasing the log a bug report is supposed to carry (#2302).
  • A window that holds the team read-only no longer draws Retry, Reject or Approve on an approval card or on a held reply's bubble in a chat: none of them can succeed there, because the host refuses the decision, so each card keeps the message, who it is for, and says why in the host's own sentence (#2310). A plugin's own approval card is told the window is read-only too, so it can hide its buttons the same way.
  • A refused action away from any form now names the host's own error code in its toast, so a second-holder refusal reads bot/read-only instead of leaving the reader to guess what failed. When the code is bot/read-only the toast also carries Reload in place: it asks for the client's full-state read, so the window becomes writable once the other holder let go, without a page reload that would drop what is in the composer. Every other failure keeps the sentence and Details it had. (#2312)
  • gate-ruleset now finds main's ruleset by the ref it governs instead of by its display name, so the live main merge queue reads as gated rather than as "main is unprotected": --check names the live id and reports drift in both directions (a context the file wants and the ruleset lacks, and a context the ruleset requires and the file does not carry), --apply updates that ruleset instead of creating a second one and refuses a body that would drop a live-required context or the merge_queue rule before it sends the request, and --rollback deletes the same rows it matched. policy-sign also names the comments that can sign the tip when it refuses for a missing or stale signature (#2314).
  • An image in a chat bubble shows its picture again instead of only the alt text: the bubble's Markdown is no longer wrapped in a delegate of its own, so the host's image resolver and file opener reach it again and a local [x](path#L12) link keeps its chip. A link is still taken by FlyBot's own browser panel, now from a capture-phase click on the bubble or on the person's own line, while a mention, a file link and a modified or middle click are left to the host (#2319).
  • The host judged a text bound in UTF-16 units while it cut in code points, so a character outside the BMP spent two of a limit's budget: a 300-character message was cut by a 400-character limit and came back short through read_own_chat and search rows. Bounds now judge with fits() in core/src/shared/text-boundary.js, clip and excerpt use it, and the third copy of clip in the memory review is the shared one (#2321).
  • the changelog's version headings link to their release comparisons again, and [Unreleased] compares from the newest release.
  • The memory-review user line and the room/board one-line fields still judged their limit in UTF-16 units while they cut in code points, so a line of characters outside the BMP was cut while it was already under its own limit: a 1,497-character user line reached the review as 1,497 emoji under a 3,000-character bound and lost about 1,400 of them, and a 40-character holder name or an 80-character card title came back at 19 and 39. Both bounds now judge with fits() in core/src/shared/text-boundary.js, with the maxima and the cuts unchanged (#2339).
  • Settings → Feedback's Clear now removes the rotated logs/diagnostics.jsonl.1 too: past 1 MB the log moves aside, and the truncate alone left every rotated line on disk after the page said the error log was cleared. The removal runs in the same write chain and behind the same leaf guard as the truncate, so a log that is a link is still left untouched (#2345).
  • read_browser no longer splits a long page between the two halves of a character: a part used to end on a UTF-16 unit, so a cut that landed inside an emoji handed the model two parts that each carried U+FFFD and printed a continuation point inside the character as well. The hard cut and the plain-text part now end on a code-point boundary and a from that lands inside a pair moves back to that character's first half, so the two reads join back into the original page and no character is dropped between them (#2349).
  • A window that opens the host state read-only no longer creates or rewrites the state journal: opening the writer is itself a write, so it now happens on the first save that got past the write lock instead of at host start, while rt.journal.status() and the diagnostics line answer as before on a host that may write (#2351).
  • A schedule row no longer names a connector whose connection failed, or one still connecting, as carried by its unattended run: the host unmounts a failed connection before it writes error and a connecting one has no tools yet, so only a ready connector appears in the row's Runs with … sentence, while the Connectors page keeps the switch that reconnects it (#2354).
  • Settings → Feedback's Clear now truncates the log even when the rotated copy cannot be removed: that removal reports itself in one line on stderr instead of stopping the truncate, so "Cleared the error log." matches the file on disk again (#2358).
  • Settings → Feedback's Clear now says so when the log file cannot be truncated (a read-only logs/diagnostics.jsonl, e.g. after one sudo run): it prints one [ds-bot] diagnostics log not truncated: <code> line on stderr instead of leaving the window reading as cleared while every line stays on disk. A Clear that does not empty the leaf has no side effect at all: the truncate runs before the rotated copy is removed, so logs/diagnostics.jsonl.1 keeps the only copy left of those lines, and the recent errors and the Download still list what is still on disk instead of reading "0 recent errors" next to "not cleared" (#2364).
  • The diagnostics report no longer says the state journal is recording before this host has saved the team: a journal whose writer has not opened yet now reads state journal: not started (opens with the first save), so a window that never saves stops promising lines it never asked the file for (#2373).
  • Settings → Feedback's Clear no longer writes [ds-bot] diagnostics log not truncated: ENOENT when there is no log file on disk yet: a home whose logs/ folder does not exist has nothing to empty, so the Clear stays silent on stderr and the window's Cleared the error log. is what happened. A leaf that is there and refuses the truncate (0444, EACCES) still names the code on exactly one line, and the answer for it is still leaf: 'kept' (#2379).
  • A window that holds the team read-only no longer draws Approve or Reject on a shared room's "Waiting for your approval" card in the details drawer: a decision is a write, so the host refuses it there and the two buttons could only produce a refusal after the click. The card keeps its headline, its count and each request's own text, and says why in the host's own sentence. A decision the host still refuses — in a writable window, or in a room with several members — now writes that reason on the card in one alert line instead of disappearing (#2381).
  • The diagnostics report behind Settings → Feedback's Report on GitHub now says whether FlyBot's own error log is being written: diagnostics log: recording while appends land, not written (EACCES) (or the code the disk gave) after an append it refused, and not written (not a plain file of its own) when logs/diagnostics.jsonl is a link or another file's second name. A support bundle therefore no longer lists recent errors whose file is missing or short without saying why; a host with the log turned off adds no line (#2383).
  • A write the host refuses in the details drawer's own Settings view now says so above the page instead of at the top of the scrolling box: pressing Pin, Hide, Make admin or Remove at the bottom of a group's page wrote bot/read-only above the viewport, where the card and its switches never changed and the press looked ignored ([#2385](https://github.com/ThinkFlo...
Read more

FlyBot v0.2.22

Choose a tag to compare

@github-actions github-actions released this 04 Nov 00:12
e40cecf

Added

  • Hand a task to a Workflow now names each lane's Project on its target row, so two Workflows that share a name but belong to different Projects are told apart before a card is handed over; a lane with no Project draws no badge (#2241).

Changed

  • The gate signature now covers the queue gates it enforces: a pull request that changes .github/scripts/enqueue-guard.mjs or .github/scripts/enqueue-rules.mjs must carry a Policy-sign: line naming a comment by someone other than its author, and that comment must name the head, exactly as a change to merge-gate.mjs already did — a pull request can no longer loosen what may enter the merge queue without a second person's signature (#2093).
  • A Live E2E run no longer publishes a key the suite itself refuses: the preflight that decides whether any step runs, the bench starter and the run guard now read DEEPSEEK_API_KEY through one module, so the mock's key or one under 16 characters is skipped with its own warning — saying plainly that nothing ran — instead of reaching a bench that refuses it and failing the night for a reason the skip exists to avoid. A key long enough but not real is not detected here; only the endpoint can judge that (#2214).
  • Hand a task to a Workflow now names the picked target on its confirm button — Assign to <lane> · <Project>, or the Bot when the card goes to one Bot — so two lanes that share a name are told apart at the click; the confirm body is unchanged. (#2254)
  • Hand a task to a Workflow keeps the picked card in the twelve it draws after the card list is folded again: a card picked past the twelfth is drawn first, so the rows never hide the card its confirm button is about to send. The count row and the assignment it sends are unchanged. (#2257)
  • The gate list is derived from docs/testing-layers.json now instead of being retyped: a workflow the manifest marks gate: true is a Policy-sign: gate file by construction, so merge-gate.yml, enqueue-guard.yml and the container-image build docker.yml joined the list, together with gate-check.mjs, the script that writes the enqueue-guard check run — policy/gates.test.mjs pins each gate workflow to the scripts it runs in both directions, so a pull request can no longer weaken a gate's switch or move a rule under another workflow without a second person's signature (#2303).

Fixed

  • The gate-change signature is now judged by the copy of the checker in the pull request's base commit instead of the copy in its own tree, so a pull request can no longer weaken or delete policy-sign.mjs and pass the check it just edited — the Gate change signature step still runs before the suite, and a signature is still a comment by someone other than the author that names the head (#2099).
  • A review asking for changes stopped nothing: the state was dropped on the way in and an empty body matched no stop, so both the enqueue guard and the queue entry answered ok. The review's state is now read — CHANGES_REQUESTED refuses with or without a body, names the review, and a later approval or a dismissal clears it. The written request and the review's request are read apart, so approving the review answers the review and leaves a hold written in a comment standing.
  • The gate-change signature is a job of its own (policy-sign) instead of a step inside the Test suite, and main's ruleset file names it next to tests-ok and enqueue-guard: required contexts are job names, so deleting the step used to leave the suite green, while the suite now needs the signature job and cannot run without it — a pull request that removes it loses a required context instead of passing. The live ruleset still has to be given the same context, which is the owner's edit: until then the job reports without being required (#2124).
  • A card in the Project board's Done group keeps its title, its priority and the board it opens: the done column no longer draws #<task-id> with no priority, and clicking the card opens the Bot or group the work lives on (#2198).
  • A link picked in a chat message now opens in FlyBot's own browser panel: the host used to open it in its right sidebar, a tab this panel's fixed layer covers, so the content area looked blank with no error to explain it. The bubble's Markdown is delegated to FlyBot's panel now, and a window without the Desktop bridge opens the page itself.
  • A refused Rename, Delete or Create in the Workflows panel is announced once now: the dialog that holds the host's sentence is the only role="alert" for that refusal, and the section no longer draws a second copy behind the mask that a screen reader read out as well. A refusal with no dialog open is still reported once on the page. In the same family, a read-only window no longer prints the host's read-only sentence twice on Settings → Workflow graphs: the Settings header draws it once for every page, so the workflow page drops its own copy (#2202).
  • The main view no longer hands the shell a conversation its session list does not know, so loading a Bot stops throwing the two uncaught sessions.retain: unknown session errors from the landing timer: a part the list has not listed yet falls back to the chat it replaced, and when the list knows none of them the view simply stays where it is (#2206, reported in #1306).
  • A read-only window no longer offers the Stage write controls that core refuses: Hand a task to a Workflow, Re-match, Pause/Resume/Stop, Edit and the drag palette, plus Reset, are gone from the Stage a workflow row opens, and the Stage prints the host's own read-only sentence instead (#2213).
  • A read-only FlyBot window no longer offers Bot Social's write entries: it keeps the section, its share requests, accept notices and past rooms as reads, and no longer draws Dismiss, Ask them to share a Bot, Leave, Approve, Reject or Auto-send from now on, offers no Bot Social row in the sidebar + menu, and opening a past room whose local mirror is gone returns the stored room instead of creating one (#2219).
  • The reorganization notice in the sidebar no longer offers Undo and Dismiss in a read-only window: the card still shows what the last run changed and what an undo kept, but the two buttons are writes the host refuses, so they are not drawn while roster.readOnly is set (#2220).
  • A workflow row with live runs now says how many: the number sits beside the dot and is part of the row's accessible name, so a reader who cannot see the colour can tell one running run from five; an idle row draws no dot, no count and no digit. Opening the list in a read-only window no longer sends workflow/ingest for every open card — the Project filter still fills, and a writable window still ingests every open card (#2222).
  • A read-only FlyBot window no longer draws the Bot Social room overview's Leave, Auto-send switch or invite: the room view keeps its status chip (and a waiting room keeps its wait code and roster) and offers no write control, while a writable window keeps the same controls and the two-tap Leave (#2228).
  • A Workflow row with live runs no longer replaces its accessible name with {name} · {count} running. The count rides in a visually hidden span beside the aria-hidden dot instead, so a reader gets everything the row's content gives — the lane's name, the Workflow badge, its Project and its preview — plus how many runs are live. Two lanes that share a name are distinguishable again, and a read-only window still hears the count (#2230).
  • A read-only FlyBot window no longer rewrites flybot-social-settings.json from its read endpoints: social/remote-bots and social/friends still derive the inbound backfill, the hidden-remote aging and the accept-notice cleanup in memory, but they write nothing, so opening a second window cannot create that file, age a hidden friend on it, or put an older copy back over what the writable window saved (#2231).
  • A read-only FlyBot window no longer draws the scheduled-task writes the host would refuse — the Quiet hours toggle and window fields, New task, Edit, Copy, Pause/Resume, Delete and Retry — and a refused Pause, Resume, Delete or Retry now says the host's own sentence on that row instead of nothing, announced to a screen reader (#2232).
  • A refused Hand a task to a Workflow now says so inside the dialog that stays open: the host's sentence is the only role="alert" for that refusal, the page draws no second copy behind the mask, and re-opening the dialog starts clean instead of inheriting the previous attempt's sentence (#2237).
  • A Bot's right-click menu in a read-only window no longer offers Copy invite link: the entry needs social.createInvite, which the host refuses there, so it is hidden instead of painting a failure. Writable windows keep the entry unchanged (#2238).
  • Hand a task to a Workflow no longer cuts its card and Bot lists at twelve without saying so: each list draws twelve and a row says how many are left, and expanding it offers every card and every local Bot (#2244).
  • **Hand a task to a Work...
Read more

FlyBot v0.2.21

Choose a tag to compare

@github-actions github-actions released this 02 Nov 18:17
75e3c18

Added

  • A pull request that edits an acceptance gate (policy/gates.json) must carry Policy-sign: naming a comment by someone other than its author that also names the tip it signs, so a signature cannot be carried over to a later push, and Test fails the pull request otherwise — a pull request can no longer change what "pass" means on its own (#2054).
  • A task card in the Done column now says when it finished — a relative time (2 h, Sep 22) beside the assignee, on a Bot's board and a group's alike (#2066). The moment is the first terminal entry in the card's history (accepted, cancelled or failed), so editing a finished task no longer moves the time; a card recorded before that history existed falls back to its last update, and one with no usable stamp shows no time at all.
  • With stateJournal on, the diagnostics report now says whether the state journal is recording or why it stopped, and journal.status() answers the same question to a host (#2134).
  • A wire on the Settings → Workflows flowchart now says which two cards it joins and can be pointed at: two wires that end at the same port used to be one stroke to the eye and the wire layer was invisible to a pointer and to a screen reader, so a narration that named a hand-off left no way to find that wire on the picture. Each route now carries a 10px transparent hit path of its own, names both ends (Reviewer → Deployer — a hover tooltip and an aria-label inside a named Connections group), and while the pointer is on it that wire is drawn in the accent colour with the others dimmed. Read-only, this only points at a wire; it commits nothing (#2142).
  • A window that holds the Bot team read-only now says so in the Settings header, in the host's own sentence, above every page that still offers its write controls: General, Bots, Groups, Secrets, Connectors, Capabilities, Scheduled tasks and Projects. Pressing a control there is refused by the host, and until now nothing on the panel explained why nothing moved. The standing sentence sits above the line that reports one refused write, and a blank or missing sentence draws nothing (#2199).
  • The messages a Bot's chat loads above the current part are now messages you can act on: the reaction and reply buttons on a bubble from an earlier part used to do nothing, because the bubble was drawn without the identity a reaction is stored under and without a session to quote into. A reaction picked on such a bubble now sticks to that message and stays there when another page is loaded above it, and Reply quotes the line into the open chat instead of into the part it was said in. (#2136).

Fixed

  • A room board opened from a Bot board now counts each active card once in its rail: the bot board's read stayed in the rail's own list after the switch, so a room that draws two cards read 1/3 instead of 1/2 (#2069).
  • The state journal now asks what its folder and its file are when it writes, not only when the host starts: a home/journal folder swapped for a link is refused with one warning and recording stops, and a state.jsonl swapped for a link is never written through, instead of silently appending a snapshot into a folder or a file outside the home. The append path refuses the write; the prune path replaces the link with a fresh file in the verified folder, so nothing is written through it (#2074).
  • memory/journal.jsonl, a workspace workflows/<id>.json and workflows/project.json are asked as files before a write, the way their folders already were: a missing file is created, a plain file is written, and a link or a directory is not written through (#2079). A linked journal file drops that one record with a warning and the memory write still lands; a linked workflow file refuses the save with workflow/not-a-file and one warning.
  • The decision log and the diagnostics log now ask what their file is before they write, the way the state journal does: a decisions.jsonl or logs/diagnostics.jsonl swapped for a link is refused instead of appending the line into whatever the link points at. A refused decision is dropped with one warning and the tool answers Not recorded: the decision log is not a plain file.; the diagnostics log drops the line with one line on stderr, keeps it readable in memory, and clear no longer truncates a file behind such a link.
  • A memory write and a frozen prompt snapshot are no longer written through a link left at their temporary name: MEMORY.md.<pid>.tmp and <session>.md.tmp are asked as files before the write, so a link there refuses the save (one warning, the memory file keeps what it had) instead of landing the bytes outside the home and replacing the file with the link (#2097). A window between the check and the write remains, as with every lstat-then-write guard.
  • The memory panel can now tell a folder it could not read from a Bot that has never saved anything: memory-view carries a blocked entry (scope and the folder that failed) for each memory scope the host refused, and the panel prints one line naming that folder above its empty title instead of telling the user to save something that cannot be written. A folder that is merely empty, or not created yet, still renders exactly the copy it rendered before.
  • The decision log's housekeeping no longer writes through a link left at its temporary name: it lands through <home>/decisions.jsonl.tmp and renames it over the log, and that name is now asked as a file before the write. A link there refuses the trim — one warning, the new entry is still appended and the retained log simply grows past its bound — instead of writing the whole retained log outside the home and replacing the log itself with the link; the tool then answers Written: … — the log was not trimmed rather than Recorded: (#2103). A window between the check and the write remains, as with every lstat-then-write guard.
  • The memory panel now names a refused memory folder even when the other memory scope has entries: entries is own and team merged, so the line added for the empty state disappeared as soon as either scope held a single entry. A second pure helper answers the same sentence from the view's blocked scopes alone, and the panel draws it above the summary and above the entries list; the empty state keeps its own copy and a view with nothing refused renders exactly what it rendered before.
  • A link left at the temporary name a write lands through no longer takes the write: the team state, the OCR cache, the Automation-tasks defaults, the Bot Social server choice and the workflow store ask <file>.<pid>.tmp as a file before writing, so a link (or a folder) there refuses the save, with the temp name in the message, instead of putting the bytes outside the folder and renaming the link into place. A window between the check and the write remains, as with every lstat-then-write guard. (#2109).
  • The timeline trace now asks its temporary name before a segment write lands through it: a symbolic or hard link left at trace-000001.json.tmp, or a directory, refuses the write with one warning, so a preset name can no longer take the bytes outside the trace folder or put a link where the segment belongs. The segment is neither created nor replaced on a refusal; a missing temp name stays the writer's to create and the plain leftover of a crashed writer is still overwritten.
  • The Bot Social credentials file, its per-server backup and the settings file are written only after the path is asked what it is: a symbolic or hard link left there was followed, so an onboarding token, the owner id and the display name could land in a file outside the Bot's home. The write now refuses before the first byte, the file behind a link keeps its bytes, and the start fails with one line naming the path rather than running on a link.
  • The run flowchart in Settings → Workflows now routes every wire on its own lane: a fork and a join no longer collapse onto one stroke, a wire leaves the card at its real bottom edge and never cuts through the card below it, and a back edge loops outside the cards as a visible return path instead of a stub. The dashed parallel frame is drawn from the measured card boxes with an equal margin on all four sides (#2122).
  • A message with no text painted a row of its own: a turn that ended in tool calls only left the Bot avatar and a bubble holding nothing under the trace row. An empty or whitespace-only text is now no row at all, in a Bot's own chat, a group chat, a friend's line and the exchange sheet; a line that carries files keeps them and loses only the empty bubble.
  • The state journal now refuses a journal/state.jsonl that is a hard link: its bytes are also a name outside this home, so the start-up read and the append both require the file to carry only this one name (nlink === 1). A shared inode is refused exactly like a symbolic link — one warning, nothing read, chmod-ed or appended — while a journal with one name records as before.
  • A loop wire in the workflow flowchart turns in the gap above or below its row, so it no longer runs behind the card beside it (#2138).
  • A start that moves to another server now asks the backup name before it asks the server for a home: the .bak copy (`flybot-social.j...
Read more

FlyBot v0.2.20

Choose a tag to compare

@github-actions github-actions released this 02 Nov 00:02
8540c35

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) — 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): 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).

Fixed

  • Renaming a group chat now reaches the guests already seated in it (#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): 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).
  • 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).
  • 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).
  • 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).
  • A text bound no longer keeps an unpaired surrogate the caller handed in (#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): 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): 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): 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). 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): 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): 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).
  • 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).
  • The last five text bounds in core/src/host/ no longer cut on UTF-16 units (#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 (...
Read more