Repository navigation
Conversation
The fixed delay raced the summary's state write under parallel test load (Node 22 on CI).
Fields per plugin, a bot.send middleware chain (allow/deny/hold, approvals), transports, remote targets and remote chat members, tool registration with visibleTo, UI endpoints and frontend slots, TypeScript types, and tests.
Bots attach files (message_friend_bot files) and the owner attaches them in the remote member composer; held sends list names and sizes, and bytes are uploaded (hash re-checked) only after approval. Incoming files render as chips in the remote bubble; get_friend_file saves a hash-verified copy and hands text content over as untrusted. bot.send carries attachment metadata; types updated.
…fuses a bare set)
… names; mount them as DSH bundles The DSH client module loader looks bundles up by package name, so @flybot/social and @flybot/tree (registered as flybot-social / flybot-tree) failed to load in the browser. Both packages now also declare dsh.bundle so 'dsh plugin add' mounts them, and tree's peer dependency is ds-bot (there is no @flybot/core).
… service flybot.sidebar.section is a FlyBot registry slot, not a DSH shell slot, so ctx.slots.register failed and the web boot reported '@flybot/tree: failed'. Adds a test that boots the social and tree web entries under real Cordis 4.
…ld change); idea from recursive-bot 7a3071e
When the plugin manager reloads ds-bot in a running DSH, the new instance can apply
before the old one is disposed. DSH's connection refuses a second owner of an exact
Fetch path ('already registered'), which failed the new apply; once the old instance
went away nothing served /api/bot, so every browser call (Friends' Bots 'Create invite
link' included) got HTTP 404 until a restart. The route now retries a taken path until
the previous owner lets go.
ds-bot sidebar tokens (--bt-*) like the tree section; collapsible header with a Bot count and '+ Add'; friends grouped by home with avatar, name, handle and a remote tag; empty states; invite link in a read-only field with a Copy button; inline paste+Join row; readable request and pending lists; no horizontal overflow. Errors are worded in English from their code (the host's localized 'HTTP 404' text was Chinese in a zh UI).
…7a3071e, 2aab086) Integrates recursive-bot's sidebar redesign (collapsible header with count, empty state, indented tree with guide lines, one-line role, click opens the Bot's chat) and the ensureRoot fix (root created at startup with a concurrency guard; autoRoot: false turns it off) on top of 090c5c5 (inject ['flybot'], section via ctx.flybot.slots) and 25e1c93 (10 s refresh).
…om recursive-bot 4699878) ds-bot's Main Bot (isMain / state.mainBotIds, preferring 'Chief'; config.rootBotId overrides) is adopted as the root with treeRole 'root'. A Root auto-created by earlier versions hands its children to Chief and loses its tree fields and tree prompt block; the bot itself is not deleted. The tree text lives in a marked block of systemPrompt so Chief's own text is never overwritten. Keeps inject ['flybot'] and the 10 s refresh.
…n the clipboard 'Join my FlyBot home <home>. In FlyBot: open Friends' Bots, click + Add, paste this link and click Join. Using a Grok bot? ... Link: <url> (single use, expires <date>)'. The field still shows the URL; 'Copy link only' copies the bare URL.
…ure)
A plugin can give the Bots a structure through the FlyBot registry slot
'flybot.sidebar.structure' ({ parentOf(botId) }). The Bot list then renders as one tree:
the Main Bot on top as the root (a row, not the tile), children indented with expand/
collapse, each with ds-bot's usual avatar, preview, unread mark and click-to-open. Bots
with no known parent (or a cycle) go under the Main Bot. Rooms and Agents follow as before.
There is no whole-home invite any more. social/create-invite (alias social.createInvite)
needs { botId }, registers that Bot's member identity and invites to it; it returns
{ botId, botName, handle, home, link, url, code, expiresAt, status, text } where text is
the copy message naming the Bot. The panel picks the Bot (default Chief); each Bot's
settings has 'Invite to this Bot'. ctx.flybot.social.canInvite(botId) is synchronous
(social/status cached) so the tree can show per-node invite buttons.
…ire the old Root (from recursive-bot 52d349e) Integrates recursive-bot's 52d349e: the separate Tree section is off by default (sidebarSection: true), local Bots outside the tree attach under Chief at startup and on bot.created, the old auto-created Root is retired (retired: true, not deleted), and a synchronous ctx.flybot.tree.forest(bots) helper. On top: the client registers flybot.sidebar.structure from forestOf, so ds-bot renders its own Bot list as one tree.
…eActions (from recursive-bot 3ee50ae)
recursive-bot's 3ee50ae: flybot.sidebar.structure entries may carry nodeActions({ bot }),
which ds-bot draws after each tree row; the tree uses it for a hover-only 'Copy invite link'
shown when social.canInvite(botId) is true (stopPropagation, copies createInvite's text).
Review changes: ds-bot wraps nodeActions in a real error boundary (a try/catch around
createElement never sees render errors); social exposes social.onChange(fn) and refreshes
its status every 30 s, so the tree re-renders on status changes instead of every node
polling every 3 s (the poll stays as a fallback for an older social).
ConnectPlugins drew a warning badge and the tooltip 'Plugin compatibility is not fully verified.' unconditionally; nothing checked anything. DSH's real compatibility check (dsh-app-boot evaluatePluginCompatibility) blocks incompatible plugins at install, so the badge only alarmed. Removes the badge, tooltip, its i18n string and styles. Rebuilt client.js.
…ms); Friends' Bots panel keeps only friends, requests and Join
FlyBot plugin layer (ctx.flybot) with social and tree plugins
…e; clipboard write starts inside the click (ClipboardItem), no bare-link fallback
…essage_bot reach friends' Bots
…ialized creates (Fixes #15) Patch by recursive-bot (Birfy/recursive-bot flybot-tree 7a64def).
…ny not delivered; legacy conversation kept (Fixes #8)
…ys hold a Bot's files, show full path, async single read, clean staging (Fixes #10)
ThinkFlowLab#87 registers only published Bots, so joining a face room with an unpublished Bot failed with "has no Bot Social identity yet". Register it on join with the same add_home_member path, keep it room-only (unpublished, not polled, not listed for friends), and revoke that identity when the Bot leaves its last face room. Co-authored-by: Danyang Chen <birfychen@gmail.com>
…egister-cf0e fix(social): register a Bot with Bot Social at face-to-face join if it has no identity (ThinkFlowLab#83)
There is no global published flag and no "publish all my Bots" concept. Every access is one of my Bots granted to one person (optionally scoped to a group). Default deny, Chief included. Accepting Invite to this Bot creates the grant; Manage access lists who has it, in which groups, and Revoke. Friends' Bots lists only Bots granted to me. Face-to-face join by 6-digit number stays a room-only implicit grant. Upgrading means no Bot is shared until it is granted. Core reach() is grant-based. @flybot/social isolates grant and invite server calls in src/mcp-client.js. Hide-a-friend's-Bot and in-chat approval prompts are unchanged. Co-authored-by: Danyang Chen <birfychen@gmail.com>
…t-inchat-approval-2176 Per-Bot grants instead of publish, remove a friend's Bot, in-chat approvals (ThinkFlowLab#90)
hideRemote waited for room leave and a fresh roster fetch, so the click felt stuck. Persist the hide and return the locally filtered list; leave rooms in parallel and refresh in the background. Friends' Bots tracked one hiding handle, so a second Remove re-enabled the first. Track a set per handle. Replace the large button with a hover/focus × that stays on the keyboard tab order and the context menu. Co-authored-by: Danyang Chen <birfychen@gmail.com>
…h-2176 Remove this Bot: fast optimistic hide, per-row pending state, compact control
## What - **AGENTS.md** rewritten toward a short pointer style: - Pipeline contract: issue -> branch -> PR (`Fixes #N`) -> CI `tests-ok` -> auto-merge (squash only), with the existing rules kept (review PASS on the tip; maintainer delegates the merge; stop conditions). - Conflict recipe for generated files: take main's `patches/ds-bot`, rebuild `client.js`, `node scripts/ds-bot-patches.mjs generate` + `check`. - Node 22+ requirement stated up front (Node 20 fails with "Could not find test/*.test.js"). - Removed the nonexistent `app/` references (two places). - **`npm run verify`** (new repo-root `package.json`, private, no dependencies, `engines.node >=22`): core lint (oxlint + arch-docs), plugin lint, `build-client.mjs --check`, `ds-bot-patches.mjs check`, core suite, `plugins/social` and `plugins/tree` suites. Same order as CI's `flybot-tests` action plus the patches check from the `package` job. It does not run pack check, typecheck, actionlint or smoke tests. Why a root `package.json` instead of `core/package.json`: `core/` is generated from `ds-bot/` + patches, so editing `core/package.json` means regenerating patch 0007 (a conflict hotspot). The root file touches no shipped package, no lockfile, and dependabot only watches `/core`. ## Verified Node 24.21: `npm run verify` exits 0 (core 674/674, social 68/68, tree 54/54, 0 skipped; lint, `--check`, patches check, arch-docs OK). Docs-only change plus one helper file; no `core/` or `patches/` change, so no patch regeneration and no subsystem doc needed (arch-docs OK). Co-authored-by: Danyang Chen <15378933+Birfy@users.noreply.github.com>
… chat (ThinkFlowLab#92) (ThinkFlowLab#96) Closes ThinkFlowLab#92. - Face-to-face join moves from the Friends' Bots panel into **+ Add** and opens its own screen. - Multi-select the Bots to bring, enter the 6-digit number (joins directly, one join per Bot with the same code), live waiting room with Bot + owner and a countdown, **Enter chat** starts the chat and opens the group; the screen follows when someone else starts it. - The old inline "Join with a number" block is removed. English only, no mention of "published". - Tests, bundle check, CHANGELOG and docs updated. Co-authored-by: Cursor Agent <cursoragent@cursor.com>
…' Bots panel (ThinkFlowLab#92) (ThinkFlowLab#100) Follow-up to ThinkFlowLab#96 / ThinkFlowLab#93 / ThinkFlowLab#91. - **Face-to-face group** is now an entry in the global sidebar **+** (new-chat picker), right after New group chat, via a new `flybot.new-chat.action` slot (patch layer). It also stays in Friends' Bots + Add and works while the roster is loading. - **Removed Bots stay gone:** a hide is forgotten only after two consecutive successful non-legacy roster fetches without that handle (or an explicit revoke); hidden handles are kept out of `flybot.remote.publish`, so persisted remote chats do not return in the sidebar, the send-to picker or mentions. Home-level rows are filtered the same way. - **Performance:** parallel mount, stale-while-revalidate roster (Refreshing\u2026 instead of blocking Loading\u2026), keep-alive HTTP, non-blocking grant listing, slower/paused polling. - Tests, bundle check, patches check, CHANGELOG updated. --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com>
…ort-only risk tier (ThinkFlowLab#102) Phase 0 of the autonomous-dev plan: report only. Nothing here blocks, labels, comments on or merges anything. ## What changed - `docs/autonomous-dev.md`: the design adapted to no GitHub App and no Cursor cloud agent (controller on `GITHUB_TOKEN` in Actions, LLM agents outside Actions, agents act only on `agent-ready`), the limits of `GITHUB_TOKEN` and workarounds, and the next phases. - Agent-task issue form (applies `agent-task`, never `agent-ready`), PR template, label definitions plus `sync-labels.mjs` (dry run by default; nothing runs it). - Risk tier: `risk-rules.json`, `risk-gate.mjs` with tests, and `risk-tier.yml` (`pull_request`, read-only, `continue-on-error`, not required, job summary only). - CODEOWNERS skipped on purpose: it would request both maintainers on most PRs and enforce nothing. - `npm run verify` and the CI `package` job run the new script tests. ## Verification at the tip Tip SHA: see the head of this PR. Ran: `npm run verify` (exit 0, 17 new tests), actionlint 1.7.7, replay over the last 30 merged PRs: T0 1, T1 2, T2 2, T3 25. Not run: the risk-tier workflow on GitHub before this PR (its first run falls back to the PR's own copy of the script, as the base has none), label script against the live repo. --------- Co-authored-by: Danyang Chen <15378933+Birfy@users.noreply.github.com>
…1, PR A) (ThinkFlowLab#103) Phase 1, PR A of 3 (conflict-proofing, from the measured hotspots in the speed-up plan). No behavior change to FlyBot itself; three commits, one per hotspot. ## What changed 1. **Patches no longer conflict on generated headers.** `generate` writes edits to upstream files without `index <hash>` lines and with each hunk's new-side start set to its old-side start (git's position hint; the old side is fixed by the pristine upstream, the true new side moves with every hunk above). Files upstream does not have go whole into `patches/ds-bot/files/` instead of one `@@ -0,0 +1,N @@` hunk whose N changes with every edit; they need no `topics.json` entry. `generate` applies each file's diff alone and compares it with `core/` before writing; `check` also compares the executable bit. 29 files moved; 4 patches that only added files are gone. 2. **CHANGELOG: one fragment per change.** `changelog.d/<name>.<kind>.md`; `.github/scripts/changelog.mjs check|preview|release <version>` (no network, no shell). CI `package` job runs `check`. Existing `[Unreleased]` entries stay and are folded in at release. `changelog.d/**` is T1 in `risk-rules.json`. 3. **Docs hotspot.** `ds-bot-core.md` split into `core-host`, `core-client` and a small pin/patch page; generated `patches/ds-bot/*.patch|files|topics.json` are no longer owned (so a core change does not force a doc edit for them). Invariants sit under headings so PRs append in different places. ## Evidence (replays in /workspace on the box; scripts: conflict-replay.sh, docs-hotspot-replay.mjs) - Two branches edit the same three core files (hooks.js new file, index.js, store.js), X near the top, Y near the bottom, each regenerates patches, then merge: - before (main): CONFLICT in `patches/ds-bot/0002-flybot-api-host.patch`, 4 regions: three `index <hash>` lines, the new-file `@@ -0,0 +1,802 @@` vs `+1,803`, and a shifted hunk header `+539,7` vs `+540,6`. - after: merge CLEAN; `ds-bot-patches.mjs check` passes on the merged tree **without regenerating**; both edits present. - Last 30 merges on main, pages each would have been forced to edit: `ds-bot-core.md` 16 → 3; new `core-host` 10, `core-client` 7. ## Verification at the tip Tip SHA: 3896928 (CI green: test, plugins x2, package, tests-ok) Ran: `npm run verify` (Node 24), actionlint, `check-pack.mjs`, new tests (`ds-bot-patches.test.mjs`, `changelog.test.mjs`) Not run (and why): smoke test (no host code changed); typecheck step (types untouched) ## Not done / follow-ups - `core/client.js` and `0008-client-bundle.patch` still conflict whenever two PRs change the client (generated bundle; build it instead of patching it). Out of scope. - Still conflicts, on purpose: two edits within ~6 lines of each other, or the same lines. - Hunk-start hint: if a repeated context ever made it misapply, `generate` falls back to exact numbers for that file (never hit on current patches). - After this merges, open PRs need one rebase: take main's `patches/ds-bot`, run `generate` (AGENTS.md recipe).
… (Phase 1, PR B) (ThinkFlowLab#104) Phase 1, PR B of 3 (merge plumbing). **Enables nothing**: without a merge queue the new trigger never fires. No repo setting, ruleset or branch protection is touched. ## What changed - `test.yml`: `merge_group:` trigger (no filters). `test`, `plugins`, `package` and `tests-ok` need no other change: nothing keys on the `pull_request` event, `tests-ok` keeps `if: always()` and needs all three. - `.github/scripts/test-workflow.test.mjs`: checks that shape (it fails on main's `test.yml`, passes here). - `docs/autonomous-dev.md`: what was verified and what was not about merge queue availability and `GITHUB_TOKEN` auto-merge. ## Verified / not - Verified (read-only `gh api`): repo is public and org-owned; docs say queues are available for that. Live protection already requires `test` and `tests-ok`; squash only; auto-merge allowed; no repo rulesets. - Verified locally: the `arch-docs` fetch step works on a one-commit shallow checkout of a merge-queue-shaped commit (it deepens until `merge-base` resolves). - Not verified: org plan (`plan` is null without `admin:org`), a real `merge_group` run (needs a queue), and whether an auto-merge by `GITHUB_TOKEN` starts the `main` push workflows. Documented rule and public reports say it does not, so the controller never enables auto-merge and agents use their own credential. Fallback: `gh workflow run Test --ref main`. ## Verification at the tip Tip SHA: a705fac (CI green: test, plugins x2, package, tests-ok) Ran: `npm run verify`, actionlint, new workflow-shape test (red without the trigger) Not run (and why): a real merge queue (would change repo settings)
…kFlowLab#105) Phase 1, PR C of 3: the label-only controller. **Dry run by default; this PR sets no repository variable and creates no label.** ## What changed - `.github/workflows/controller.yml` (schedule every 30 min + `workflow_dispatch`, `GITHUB_TOKEN` only, no secrets, `permissions: {}` at top). Job `plan`: read-only token, writes the proposed label changes to the job summary. Job `apply`: the only one with write (`issues`, `pull-requests`), runs only when the plan has operations **and** repo variable `CONTROLLER_LIVE` is exactly `true`. `AGENT_PAUSE=true` stops everything. - `.github/scripts/controller.mjs` + `controller.test.mjs` (19 tests) + `.github/agent/controller.json` (maintainers, TTL, caps). - It only manages labels: `risk:T0..T3` (risk-gate tier) and `agent-pr` on PRs; removes `agent-ready` (and `agent-working`) when a non-maintainer labeled the issue or edited it after approval; removes `agent-working` from claims past the TTL (6 h) with no recent push on a linked PR. Missing labels are skipped, never created. `hold` = hands off. - It never merges, approves, comments on, edits or closes anything, never checks out or runs PR/issue content; `validatePlan` refuses any op outside the label contract (it can never add `agent-ready`); tests scan the source and the workflow for this. - `labels.json`: + `risk:T0..T3` (they do not exist live until a maintainer runs `sync-labels --apply`). Docs: `docs/controller.md`. ## Evidence - Read-only dry run against the live repo (GET and a GraphQL query only): 5 open PRs, all T3, `risk:T3 label-missing` skipped, 0 changes, nothing written. - GraphQL shapes (edits by editor, rename and label events) checked against real issues. ## Verification at the tip Tip SHA: 13eab55 (CI green: test, plugins x2, package, tests-ok) Ran: `npm run verify`, actionlint + shellcheck, controller tests, live read-only `plan` Not run (and why): live `apply` (would write labels on the real repo); whether `issues: write` alone suffices to label a PR is untested (documented in docs/controller.md) ## To go live (maintainer) `node .github/scripts/sync-labels.mjs --repo ThinkFlowLab/FlyBot --apply`, read a few dry-run summaries, then set variable `CONTROLLER_LIVE=true`. Pause: `AGENT_PAUSE=true`.
…Lab#107) Follow-up to ThinkFlowLab#100 (owner feedback). - Each Bot shows its own distinct avatar in the Face-to-face Bot picker and in the waiting room. - The waiting room is a wrapping tile grid (avatar on top, name below), no owner subtitle or heavy badge. - Leave and Enter chat share one footer row. - Tests updated; local verify passed. --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com>
…opups) (ThinkFlowLab#108) The web UI chrome still said DS Bot. This changes user-visible branding to FlyBot (en + zh) via the patch layer (0014-flybot-branding), uses docs/images/logo.svg for the header mark, and labels updates as FlyBot core {version}. ds-bot/ is untouched; package names, the update check and upstream links are unchanged. Local verify passed (arch-docs, bundle check, patches check, core/social/tree tests). Co-authored-by: Cursor Agent <cursoragent@cursor.com>
…owLab#109) Fixes two bugs seen in a Face-to-face room. - The Auto-send my Bot's room messages setting called REST /v1/me with the connector token, which Bot Social rejects (connector_token_rest_forbidden). It now reads and changes the setting through the allowed /mcp path; the owner's click is the consent. - Friend Bots now show their own avatar (member list, message author, waiting grid), with a stable generated fallback from the handle. Tests added; see commit for details. Co-authored-by: Cursor Agent <cursoragent@cursor.com>
…human (ThinkFlowLab#52) (ThinkFlowLab#94) ## Why A held send was decidable by anyone who could reach the decide endpoint. The record carried no owner, no binding to the request content, and no origin, so on a host with member sessions one member could decide another's queued send, and a claim inside the message ("my owner approved this") was indistinguishable from authority. \ThinkFlowLab#52's acceptance calls for exactly this binding; it is also the held-send half of team-gate 3 (docs/subsystems/team.md). ## What - **Provenance stamped at hold (server-derived, `src/host/hooks.js`)**: `requestId` (the send's exchangeId), sha256 `version` over the request content (from/to/text/role/attachment names), `origin` (`via`, `hop`, room audience when known), and `ownerId` — the sender Bot's owner, resolved from team state. Claims in `meta` or the text are data on the record, never authority. - **Owner-bound decisions**: `flybot/decide` now passes authz for any signed-in member (carved out of `bot/blocked-shared` in `src/host/authz.js`), and hooks.js binds the decision to the sender Bot's owner's session — `bot/forbidden` for anyone else, `bot/unauthorized` without a session, a body `actorId` grants nothing (`src/host/channel.js` threads the actor into `flybotEndpoint`). - **Revalidation at approve/execute**: `release()` re-checks the record before dispatch; a changed request, a deleted sender or target Bot, a Bot that changed owners, or a demoted Chief marks the record `stale` — never dispatched. `deleteBot` and Chief replacement (`setMain`) invalidate affected pending holds eagerly. Deciding a non-pending record answers `bot/stale` (same code as `answerApproval`). - **Per-actor visibility**: under enforcement the pending list shows a member only their own holds; stale records whose sender Bot and owner are both gone keep their attribution in state but appear in no list (audit surface is ThinkFlowLab#57). - **Approval card context** (`src/client/flybot-slots.js`): the card shows the sending Bot and a "delegated" marker when the request was relayed (hop > 0); EN + ZH strings. - **Legacy holds** (pre-version-stamp) keep working: they skip only the tamper check; their owner is derived at decide time. Not in this PR: `social/decide-approval` stays a deployment-wide plugin write (blocked-shared while more than one member exists) — that follows the ThinkFlowLab#90/ThinkFlowLab#91 per-Bot-grant server work, and in-chat approval cards are ThinkFlowLab#90's scope. Team mode stays disabled. Fixes ThinkFlowLab#52 ## Verification Tips reviewed: `fe8eef2` (initial, Verifier FAIL — see review round 1) → **`f87ed85` (current)**. Ran at `f87ed85` (worktree `/tmp/flybot-52`, harness via symlinked `dev/harness/node_modules`): - `npm test` — **684/684 pass**, including new `core/test/approval-binding.test.js` (10 tests) and the updated `authz.test.js` flybot-endpoint rules. - Fail-without-change: `approval-binding.test.js` written first; at base `811df19` **9 of 10 fail** for the right reasons (missing provenance stamp, `blocked-shared` instead of owner-bound decide, list leak, no stale invalidation). The 10th ("deciding needs a member session") passes at base via the existing anonymous-call deny and is kept as a regression guard. - `node scripts/build-client.mjs --check` — pass (client.js rebuilt and committed). - `npm run lint` — oxlint 0 errors, 27 warnings (identical to base, compared by stashing the diff); `arch-docs` **OK at this tip** (21 changed files, `plugin-runtime.md` updated in f87ed85). - `node scripts/ds-bot-patches.mjs generate && check` — pass at this tip (`core/ == ds-bot/ + patches`; the fe8eef2 commit shipped a stale 0002 patch — regenerated in f87ed85). - Smoke (`src/host/` changed): `dev/bench.sh smoke 3096 8796 reset` + `node dev/smoke.mjs smoke 3096` at `fe8eef2` — **all 40 steps passed**; the f87ed85 delta touches the same approval paths (invalidation scope, staleReason wording, test hygiene) and is unit-covered; smoke not re-run at `f87ed85`. - CI at `f87ed85`: `package` pass; `ubuntu-latest` / plugin jobs pending at time of writing. Not run: DSH Desktop check, real-model steward eval, Windows locally, smoke at `f87ed85`. ## Reviewer notes - The worktree needs the harness symlink or `DSH_HARNESS` for tests (fresh worktrees have no `dev/harness/node_modules`). - To re-verify red-at-base mechanically: worktree at `811df19`, copy only `core/test/approval-binding.test.js` in, run it — expect the 9 failures listed above. - The authz.test.js change replaces ThinkFlowLab#91's "decide is blocked-shared with two members" assertion: deciding is now per-owner enforced in hooks (that test now also asserts a *different* plugin write, `flybot/social/decide-approval`, still gets `bot/blocked-shared`). - macOS bench gotchas: banner flush may hang `bench.sh reset` even though the web server is up — check `web.log` for the token and `lsof -iTCP:3096`; `stop` may leave listeners, kill the process groups. Co-authored-by: hsliu_ustc <hsliu_ustc@noreply.gitcode.com>
…lowLab#53) (ThinkFlowLab#101) ## Why On a host with member sessions, private context leaked across owners through four seams: a member Bot's group Session began with its owner's own-chat brief whoever else sat in the room; the memory review read every attributed human as a peer and could publish **team** memory out of another owner's room (any room admin could, and still can on single-owner rooms); `list_bots` disclosed other owners' `workDir` and instructions; and a `dsh-session:` reference chip copied any Session's snapshot to every recipient of the message. ThinkFlowLab#53's acceptance: markers in each owner's private context are unreachable from another owner's requests and shared-room context without an explicit authorized share. **Stacked on ThinkFlowLab#94** (`fix-52-approval-binding`, f87ed85) — this branch bases on it; retarget to `main` after ThinkFlowLab#94 merges. Host mechanism only: the share has no room-UI toggle yet (documented), and previously received messages are not retroactively unseen (the issue says to document exactly that). ## What - **Brief gate** (`src/host/groups.js`): the own-chat brief enters a group Session only for a single-owner room, or where the Bot's owner shared it — `share-brief` endpoint → `rt.setBriefShare` (`src/host/room-membership.js`), a `briefShared` flag **on the room participant** (leaving drops it; owner-checked, not admin-checked). Enforcement off = shipped single-human behavior. - **Memory review** (`src/host/memory.js`): `isUserLine` reads the member Bot's owner as "the user" (retention + read-back anchor) and another owner's human as a named peer; `teamAllowedFrom` refuses team-scope writes out of a room with more than one owner — entries land in the Bot's own memory. - **Roster** (`src/host/tools.js`): `list_bots` shows another owner's Bot by name, role, model; its folder and instructions stay private. - **References** (`src/host/channel.js`): `dsh-session:` chips in `send` and `room-post` must resolve through `sessionOwnedBy` for the author (`bot/forbidden` otherwise); authz allows the new `share-brief` for any signed-in actor (the owner check is on the record). Fixes ThinkFlowLab#53 ## Verification (updated: rebase + review round 1) Tips: `58fdae3` (initial, Verifier FAIL on packaging + narrative) → **`775bae1`** (current; branch rewritten as ONE commit `Share private context across owners only by an explicit share (ThinkFlowLab#53)` directly on the rebased ThinkFlowLab#94 tip `985c82e`, which sits on origin/main `1736161`). Ran at `775bae1`: - \`npm run verify\` (pipeline gate) — **exit 0**. - Red-at-base at \`985c82e\` + only the two test files: context-sharing **5 fail / 1 pass** — the 5 feature tests fail for the right reasons (brief present cross-owner; `bot/not-found: Unknown endpoint share-brief` on the owner-share and foreign-share tests — so the round-1 "2 passing guards" claim was wrong: the foreign-share guard fails at base too, via `bot/not-found` rather than `bot/forbidden`); memory **2 fail** — the classification test fails on the batch text, and the team-gate test fails with **nothing written at all** (base never writes b3's MEMORY.md from this fixture), not a cross-owner team write. - \`node --test\` on the two files at the tip: **66/66 across both files** (8 new). - Smoke: ports 3094/8794 — **all 40 steps passed**; bench stopped, data removed. ## Round-1 findings → fixes 1. **Patches block** — fixed: `context-sharing.test.js` joined topic 0002, patches regenerated in-commit. 2. **Narrative** — corrected above (5/1, and the memory base failure mode stated exactly). 3. **Remote owners** — fixed: a granted remote Bot's handle now counts as another owner in both `briefAllowed` (groups.js) and `teamAllowedFrom` (memory.js); a remote participant in an otherwise single-owner room suppresses the brief (new test). 4. **Chip gates beyond send/room-post** — follow-up filed as ThinkFlowLab#106; noted in team.md as not-done-here. Fixes ThinkFlowLab#53 Docs-not-needed: ThinkFlowLab#53 context-sharing narrative lives in docs/subsystems/team.md (Context sharing foundation) with core-host.md cross-ref; merge-queue squash must retain this trailer. Co-authored-by: hsliu_ustc <hsliu_ustc@noreply.gitcode.com>
…nd-share) (ThinkFlowLab#112) Bug: after creating a group and adding another person's Bot, that Bot's owner never saw the group. Cause: (a) FlyBot never told the other side a room existed (New group passed the remote chat session as a local member, and add/create did not notify Bot Social); (b) Bot Social only has 1:1 conversations, so an empty room is invisible; (c) the inbound-share projection (ThinkFlowLab#50) was never wired in production. Fix (FlyBot only): a FLYBOT-ROOM-SHARE envelope over 1:1 send_as_member carries join/leave and chat lines. The owner's pollOnce applies it before 1:1 delivery and creates an inbound-share room (Shared room from <inviter>); leave, hide or grant revoke marks it left. New group splits remote vs local members. The owner's Bot replies still go through in-chat approvals. Local verify passed. Co-authored-by: Cursor Agent <cursoragent@cursor.com>
The Bot tree's collapse/expand chevron was a 10px glyph in a 16x36 strip. It is now a 16px glyph on a 28x28 hit target, vertically centered, with a hover background and a :focus-visible ring. Rotation, aria-expanded/labels, indent and row height are unchanged. The optional Tree plugin section gets the same treatment. Local verify passed; not clicked in a live window. Co-authored-by: Cursor Agent <cursoragent@cursor.com>
…Add friend moved into the + menu (ThinkFlowLab#116) ## Why Approving a Bot Social hold meant leaving the conversation for a bloated sidebar card, and the Friends' Bots panel (approvals, Auto-send, Face-to-face rooms, "+ Add") had grown heavy. Creation actions belong in the single top-level "+" menu. ## What - **Inline approvals (ThinkFlowLab#114):** the open chat shows the held draft with Approve / Reject for the owner ("Waiting for the owner's approval" for everyone else), Approve all when several are held, and a wait badge on the chat row. - **Compact panels (ThinkFlowLab#115):** Friends' Bots is a one-line jump list; Auto-send is one compact toggle; Face-to-face rooms are one row each, with closed/left rooms under "Past rooms". - **"+ Add" merged into the global "+":** Add friend and Friend requests are rows next to Face-to-face group. The Friends' Bots header is just title, count and the "N to approve" chip. Each action opens the same flow as before. Fixes ThinkFlowLab#114 Fixes ThinkFlowLab#115 ## Verification - `ARCH_DOCS_BASE=upstream/main npm run verify` exit 0 at 906205b; patches generate/check and changelog check pass. - Not run: smoke, live click-through. --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com>
ThinkFlowLab#119) Fixes #16 Owner decision: **Option B**. Tree Bots (not only Main/root) may call `create_child_bot` to create children under themselves. AGENTS.md and the related docs are updated to match how the tree plugin already behaved (`visibleTo: inTree`, parent = caller). Guardrails unchanged: `maxChildren` and depth limits. A newly created child starts with **no person-grant**, even if the parent is already granted. Sharing still requires an independent per-Bot grant (default deny). No publish mechanism. Tests assert Option B creation for a non-Main tree Bot, that limits still apply, and that the child has no auto-grant. `ARCH_DOCS_BASE=upstream/main npm run verify` passes. Tree plugin + docs only; no core/patch regeneration. Co-authored-by: Cursor Agent <cursoragent@cursor.com>
ThinkFlowLab#118) Fixes ThinkFlowLab#117 Fixes found while running two real FlyBot instances side by side on the Face-to-face flow: - Waiting card no longer clipped or stale; it compacts after the first message. - Tiles show the owner's name, and each Bot keeps its own avatar. - The second instance now sees the join and receives messages, including lines the owner types (a `FLYBOT-FACE-HUMAN` envelope; typing is consent, applied as human on the other side). Checks: `ARCH_DOCS_BASE=upstream/main npm run verify` passes. Tests added in core, social and remote-room suites; changelog fragment and subsystem docs updated. No change to the pinned `ds-bot/`; generated patches regenerated. Not covered: Bot replies (needs a model key). Co-authored-by: Cursor Agent <cursoragent@cursor.com>
…nkFlowLab#98) (ThinkFlowLab#120) Fixes ThinkFlowLab#98 Rebase of [@hsliuustc0106](https://github.com/hsliuustc0106)'s [ThinkFlowLab#99](ThinkFlowLab#99) onto current `main`, with the design-review fixes applied. **Supersedes ThinkFlowLab#99.** - Fence by origin (remote participant, local `bot.remote` record, non-team botId, or `line.remote`), not only face rooms. - Skip a complete existing wrap so fanout does not nest; still fence a substring mention of the marker. - Room `RemoteMessage` unwraps with `remoteMessageText()` like the 1:1 path. - Inbound-share / face human lines are treated as remote-origin and fenced. Deferred: forgeable `FLYBOT-FACE-HUMAN` `who` lives in `plugins/social` (follow-up). `ARCH_DOCS_BASE=upstream/main npm run verify` passes. Please close ThinkFlowLab#99 once this is preferred. Co-authored-by: Cursor Agent <cursoragent@cursor.com>
ThinkFlowLab#121) Fixes ThinkFlowLab#54 Rebase of [@hsliuustc0106](https://github.com/hsliuustc0106)'s [ThinkFlowLab#110](ThinkFlowLab#110) onto current `main`, with grant-model review fixes. **Supersedes ThinkFlowLab#110.** - Task lifecycle: open → claimed → working → blocked ⇄ working → result-ready → accepted (wrong-owner moves refused; failed/cancelled cannot display as accepted). - Create does **not** require owning the Bot: matching grant or shared room is enough for a granted child to hand off; outgoing holds stay the owner's. - `list_bots` restricted to own Bots + granted-to-same-owner + current-room; granted children are scoped to their `createdBy` subtree. - Memory review labels another human as `peer`, not `bot`. - Changelog fragments only (`CHANGELOG.md` untouched); patches regenerated. Remaining related work (not this PR): in-chat task cards (ThinkFlowLab#57); ThinkFlowLab#111 follow-ups; grant-tied `briefAllowed` share (deferred, noted in `docs/subsystems/team.md`). `ARCH_DOCS_BASE=upstream/main npm run verify` passes (core 721). Please close ThinkFlowLab#110 once this is preferred. --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com>
…hinkFlowLab#124 ThinkFlowLab#125 ThinkFlowLab#126) (ThinkFlowLab#127) Fixes ThinkFlowLab#124 Fixes ThinkFlowLab#125 Fixes ThinkFlowLab#126 Found in a two-instance cloud UI self-test on `87c6940`. **ThinkFlowLab#124** Face-room human messages now go through the room post path (implicit owner when not signed in) with a quiet local notice, and skip the local Bot turn unless a local Bot is @mentioned. The other instance receives it via `FLYBOT-FACE-HUMAN`. **ThinkFlowLab#125** The waiting screen is a tile grid (avatar above name, with owner), Leave and Enter chat on one row, live member count, and owner + Bot name in join lines. Leaving after the matching window ended moves the room to Past rooms. Past rows are unique with a single Open; live rows are click-to-open with Leave. **ThinkFlowLab#126** The sidebar `+` is a short action menu. Add friend has one-click **Copy invite link**. Hold approvals show as `Chief → the room` instead of raw ids, and the Friends' Bots column no longer stacks jump lists. Softened "matching window" and "Add Agent" wording in the social `+`. Deferred: grant-tied `briefAllowed`; envelope `who` is still taken from JSON rather than the sending member record; DSH core still says "Add DSH Agent" outside the social `+`. `ARCH_DOCS_BASE=upstream/main npm run verify` passes. Smoke bench not run (no Harness checkout). Co-authored-by: Cursor Agent <cursoragent@cursor.com>
…ThinkFlowLab#122 ThinkFlowLab#123) (ThinkFlowLab#128) Fixes ThinkFlowLab#122 Fixes ThinkFlowLab#123 **ThinkFlowLab#122** Empty or `@` handles stay empty (`norm`, REST `get`, hide-handle). A stored `asBot: "@"` is healed, and the poll only sends `as` when it is a real handle. Rooms discovered through `list` are seeded from `my_bots`. A `face_room_not_found` on a room that is still listed repairs the meta and retries once. **ThinkFlowLab#123** Approval waiting notices no longer call `deliver` with a home-level handle. They open or resolve a listed friend Bot's 1:1 chat so the line lands in the chat. If there is none, they skip with `approval chat note skipped: no 1:1 chat for …` instead of throwing. `ARCH_DOCS_BASE=upstream/main npm run verify` passes; `ds-bot/` untouched, no patch regeneration. Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Unwrap stored untrusted-message wraps in room previews and bubbles, resolve User to the signed-in display name, and show a short friendly line instead of raw model/API-key errors. The sidebar + menu keeps plugin actions and toasts a returned string, without listing every Bot (Chief clutter). Co-authored-by: Danyang Chen <birfychen@gmail.com>
Expired matching and a peer leaving move rooms to Past rooms without a stale Leave. Titles include people or the code/time. The + menu holds Add friend, Accept invite, one-click Copy invite link, and Face-to-face group. Auto-send is the one hold label; the header shows either the Bot count or N to approve. Inbox and face poll drop to about 4s while a room is live. Co-authored-by: Danyang Chen <birfychen@gmail.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes ThinkFlowLab#129, ThinkFlowLab#130, ThinkFlowLab#131, ThinkFlowLab#132, ThinkFlowLab#133
What changed
Expired matching and a peer leaving the last remote seat move Face-to-face rooms into Past rooms (Open only, no stale Leave). Chat and sidebar previews show the inner words of a remote line, not
<untrusted-message>, and use the person's real name instead of User. Missing API key / model failures show a short friendly line; the raw error stays in diagnostics. The sidebar + menu is Face-to-face group, Add friend, Accept invite, and one-click Copy invite link (Friend requests is gone; individual Bots stay behind New chat). Hold labels use the real Bot name (Chief → the room); room titles include people or the code/time; Auto-send is the one hold label; Friends' Bots shows either the Bot count or N to approve. Live face rooms poll about every 4s (about 3s in the open room), then 15s when idle.Verification at the tip
Tip SHA: af5af0d
Ran:
ARCH_DOCS_BASE=upstream/main npm run verify(lint, patch check, core tests, social tests, tree tests, changelog check)Not run (and why): smoke test (
dev/bench.sh) — no harness checkout at../deepseek-harness; unit tests cover host poll, past-room move, + slots, unwrap, and titles.