Repository navigation
fix(social): granted friend Bot shows for the grantee (#178) #183
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| A Bot a friend shared with you shows in your list again: the talk-through grant on your own Bot no longer hides it (regression of the #161 fix), it no longer shows as you sharing that Bot, and the join message names the person ("SelfA shared Helper with you."). ([#178](https://github.com/ThinkFlowLab/FlyBot/issues/178)) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -81,9 +81,9 @@ | |
| const TEXTUAL = new Set(['text/plain', 'text/markdown', 'text/csv', 'text/tab-separated-values', 'application/json']) | ||
| const sizeLabel = n => (n < 1024 ? `${n} B` : n < 1048576 ? `${(n / 1024).toFixed(1)} KB` : `${(n / 1048576).toFixed(1)} MB`) | ||
| // Remote strings that reach model-visible text: one line, no brackets or markup, capped. | ||
| export const cleanText = (value, fallback = '') => String(value ?? '').replace(/[\u0000-\u001f\u007f-\u009f\u2028\u2029]/g, ' ').replace(/[[\]"<>`]/g, '').replace(/\s+/g, ' ').trim().slice(0, 60) || fallback | ||
| // Owner-only draft body: keep punctuation the friend will see; strip controls and cap. | ||
| export const draftText = (value) => String(value ?? '').replace(/[\u0000-\u001f\u007f-\u009f\u2028\u2029]/g, ' ').replace(/\s+/g, ' ').trim().slice(0, 800) | ||
| // Owner cards never show the FLYBOT-FACE-HUMAN wire envelope (#159). | ||
| export function approvalDraftText(value) { | ||
| const raw = draftText(value) | ||
|
|
@@ -136,7 +136,7 @@ | |
| } | ||
| const SEEN_KEPT = 1000 | ||
| const CREDENTIAL_NAME = /(^id_(rsa|dsa|ecdsa|ed25519)|\.(pem|key|p12|pfx|kdbx|keychain)$|credential|secret|token|password|passwd|^flybot-social.*\.json$|^\.?env$|^\.netrc$|^known_hosts$|^authorized_keys$)/i | ||
| const safeName = name => String(name ?? 'file').replace(/[\u0000-\u001f\u007f/\\:]/g, '_').replace(/^\.+/, '_').slice(0, 120) || 'file' | ||
| // The text Copy puts on the clipboard for a per-Bot invite: what to do with the link, for a | ||
| // person in FlyBot or for their Grok bot. | ||
| export function inviteText({ handle, name, home, url, expiresAt }) { | ||
|
|
@@ -575,7 +575,7 @@ | |
| if (result?.unavailable) return | ||
| } catch (error) { | ||
| if (/invalid_avatar|invalid_color|invalid_request/i.test(`${error?.code ?? ''} ${error?.message ?? ''}`)) { | ||
| settings.lookSynced = { ...(settings.lookSynced ?? {}), [bot.id]: fingerprint } | ||
| saveSettings() | ||
| return | ||
| } | ||
|
|
@@ -684,9 +684,12 @@ | |
| const key = norm(bot.handle) | ||
| if (!key) return false | ||
| if (declinedRemotes.has(key)) return false | ||
| // Outgoing grants win: the Bot that joined our invite is not granted back (#138 / #161). | ||
| // A Bot someone shared with us (we joined their invite) always shows, even though the | ||
| // talk-through grant on our own Bot names it as grantee (#178). | ||
| if (settings.inboundBots?.[key]) return true | ||
| // Otherwise outgoing grants win: the Bot that joined our invite is not granted back (#138 / #161). | ||
| if (outgoingPeerHandles().has(key)) return false | ||
| if (settings.inboundBots?.[key] || settings.inboundBots?.[bot.home]) return true | ||
| if (settings.inboundBots?.[bot.home]) return true | ||
| if (settings.roomBots?.[key]) return false | ||
| return true | ||
| } | ||
|
|
@@ -718,9 +721,19 @@ | |
| // The friendship covers only these local members (an invite made for one Bot, or joined | ||
| // as one Bot); empty when it covers this whole home. Only they can talk to this friend. | ||
| via: (entry.via ?? []).map(norm), | ||
| ...(entry.relationship_id ? { relationshipId: String(entry.relationship_id) } : {}), | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
AGENTS.md reference: AGENTS.md:L59-L59 Useful? React with 👍 / 👎. |
||
| } | ||
| }) | ||
| } | ||
| // The grant a joiner's own Bot carries for talking through to a shared Bot: same | ||
| // relationship, the Bot is one this friendship covers, and the grantee is a Bot the friend | ||
| // shared with us. It is not us sharing that Bot (#178). | ||
| function isTalkThroughGrant(member, grant) { | ||
| const rid = grant.relationshipId | ||
| const grantee = memberHandleOf(grant.grantee) | ||
| if (!rid || !grantee || !member?.handle || !settings.inboundBots?.[grantee]) return false | ||
| return remote.homes.some(entry => entry.relationshipId === rid && entry.via.includes(norm(member.handle))) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
AGENTS.md reference: AGENTS.md:L59-L59 Useful? React with 👍 / 👎. |
||
| } | ||
| function listedRemoteBots() { | ||
| return remote.homes.flatMap(entry => entry.bots.map(bot => ({ | ||
| handle: bot.handle, name: bot.name, home: entry.home, homeName: entry.name, owner: entry.owner, | ||
|
|
@@ -938,7 +951,7 @@ | |
| try { | ||
| const listed = await api.listGrants({ botId: member.bot_id }) | ||
| const roomScoped = (flybot.grants.of?.(bot.id) ?? []).filter(grant => grant.roomId) | ||
| const people = listed.filter(grant => !grant.roomId).map(grant => { | ||
| const people = listed.filter(grant => !grant.roomId && !isTalkThroughGrant(member, grant)).map(grant => { | ||
| const view = grantPersonView(grant) | ||
| // Core normGrantee cannot match decorated non-@ values; persist a canonical @handle. | ||
| const canonical = view.member || view.home || memberHandleOf(grant.grantee) | ||
|
|
@@ -1446,7 +1459,8 @@ | |
| } | ||
| if (offered?.handle) rememberInbound(offered.handle) | ||
| const inviterHome = joined.inviter?.handle ? homeOfPeer(joined.inviter.handle) : added[0]?.home | ||
| const inviterName = cleanText(joined.inviter?.display_name || joined.inviter?.owner_display_name || added[0]?.owner || added[0]?.homeName) | ||
| // Name the person, not the Bot they shared (#178: "SelfA1933 shared Helper with you"). | ||
| const inviterName = cleanText(joined.inviter?.owner_display_name || added[0]?.owner || added[0]?.homeName || joined.inviter?.display_name) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
This fallback-order change has no regression assertion that distinguishes a Bot name from its owner's name: the join mocks provide only AGENTS.md reference: AGENTS.md:L18-L18 Useful? React with 👍 / 👎. |
||
| const inviterBotName = cleanText(offered?.display_name || offered?.name || (added.length === 1 ? added[0].name : '')) | ||
| // A new friendship starts with Auto-send off; only push server auto-approve if the owner already opted in. | ||
| if (joined.relationship_id && autoAcceptOf(inviterHome)) await serverAutoApprove(joined.relationship_id, true) | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
inboundBotsis append-only and is not cleared when a received share is revoked or declined. If that same remote Bot later accepts one of this user's invites, this early return overrides the currentoutgoingPeerHandlesevidence and publishes the reverse roster row as though it were still granted to the user; with a matching relationship andvia,isTalkThroughGrantalso removes the legitimate outgoing core grant, preventing the invited Bot from reaching the local Bot. Base the precedence on a current inbound relationship or expire the marker when the share disappears.AGENTS.md reference: AGENTS.md:L59-L59
Useful? React with 👍 / 👎.