Show each pairing's thread-message permission and let it be revoked alone
Nobody has claimed this yet.
Assessment
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Newbie friendliness
- 35/100
- Issue type
- Feature
- Clarity
- Clearly specified
- Activity status
- Active
- Tech stack
- react, typescript
Research direction
Depends on #16, which moves the outbound rows first. Read RemoteConnectionsSection.tsx, the thread-bridge.ts API shapes, and the HTTP transport; start with lib/threadBridges.ts and its direction-helper tests. Then build ThreadMessagesPanel.tsx, wire row facts and actions, add English and Chinese strings, and run the named tests and visual-proof script; done means permission details and single-entry actions work, with the required desktop and touch-context phone screenshots.
Written by the indexing model from the issue text.
Description
What feature would you like to see?
Pairing two spaces usually also sets up thread messages between them, so agents in one space can read, send to and wait on threads in the other. The GUI never shows this: a pairing row carries a "Thread messages" tag at most, with no direction, no scope, no operations and no expiry, and the only way to withdraw the thread-message permission without removing the whole pairing is the kiki bridges command. People cannot see, from the place where they manage pairings, what they have allowed.
Decided
- "Thread messages" is a permission on a pairing, not a separate object; the word "bridge" does not appear in the GUI.
- Every paired space's row on the Spaces page states, as read facts, whether it can be opened and which way thread messages flow.
- The row menu gets "Thread messages…", which shows the scope and operations and can revoke the thread-message permission alone.
- When the permission cannot be read, the row says so; it never shows "none" in its place.
- This is the GUI's first use of the existing thread-bridge API; no protocol change.
Design
Row facts. Each row for a space on another computer (Settings → Spaces, section "Spaces on other computers", moved there by the settings-merge issue) gets a third line:
◍ Workstation B
b.example.test · Connected · 1 minute ago
Can be opened · Thread messages: both ways · 3 working · 2 waiting on you [Switch] ⋯
◍ Writer space link
writer.example.test · Offline
Can't be opened · Thread messages: outgoing only ⋯
- Openable: "可打开 / Can be opened" when the record's
purposesincludesguiand the record is enabled; otherwise "不可打开 / Can't be opened". - Thread messages: "线程消息:双向 / 仅发出 / 仅接收 / 无" (en: "Thread messages: both ways / outgoing only / incoming only / none"); when the status call fails, "线程消息:读不到" (en: "Thread messages: can't read").
- Direction is computed from
GET /api/thread-bridges(klientrest.threadBridges.status()), which returns{ identity, inboundEnabled, inbound: BridgeGrant[], outbound: BridgeLink[] }:- outgoing: an
outboundlink withconnectionId === record.id, not revoked and enabled; - incoming: an
inboundgrant whosesourceidentity (homeId,hostId) equalsrecord.target, not revoked and enabled; - both → both ways; one → that one; neither → none.
- outgoing: an
"Thread messages…" panel (row menu item; desktop side panel, phone full-height sheet). One entry per thread-message permission of this pairing, each showing:
- direction (this space → that space, or the reverse);
- scope: which workspace (and, if set, which session) on each side; show this space's workspaces by name; for the other side show what the record says without raw identifiers;
- operations in words: read 读取, send 发送, wait 等待, wake 唤醒 (starts a turn on the receiving side). A permission without wake leaves sent messages pending instead of starting a turn; say that in the panel when wake is absent;
- expiry date, and whether it is on;
- actions: "停用 / 启用" (Turn off / Turn on,
setEnabled(direction, bridgeId, enabled)) and "撤销… / Revoke…" (revoke(direction, bridgeId)), each affecting only that entry. Revoking a thread-message permission does not remove the pairing; the row keeps "Can be opened".
Data access goes through a new apps/kiki-gui/src/lib/threadBridges.ts (query keys, a useThreadBridges(client) hook against this window's own home, and the direction helper), and the panel is its own component, apps/kiki-gui/src/components/settings/remote/ThreadMessagesPanel.tsx; the pairing-sheet issue reuses both for the Access page's incoming list. Read from this device's own home (the same control client the pairing list uses), never from the space on another computer.
Strings: add keys to both packages/session-core/src/i18n/en.ts and zh.ts. The zh copy above is fixed by the design; en copy follows its meaning.
Where
- API:
packages/klient/src/core/facade/thread-bridges.ts:4-12(status,setEnabled,revoke,receipts,retry), HTTP transportpackages/klient/src/transports/http/thread-bridges.ts, exposed asrest.threadBridges(packages/klient/src/transports/http/rest.ts:98). - Shapes:
packages/protocol/src/rest/thread-bridge.ts(bridgePolicySchemawithsourceScope,targetScope,operations,expiresAt;bridgeGrantSchemaaddsid,enabled,revoked;BridgeLink { connectionId, grant, enabled };BridgeStatus). - Rows today:
apps/kiki-gui/src/components/settings/RemoteConnectionsSection.tsx(RemoteConnectionRowand its menu at:151; list at:116-121). - Server behaviour to reflect: pairing issues
read,send,waitby default (packages/kap-server/src/services/connections/admission.ts:7;packages/kap-server/src/services/threadBridge/bridge.ts:94-110); withoutwakea bridged message stays pending (bridge.ts:309); a reverse bridge can be set up for a paired connection (bridge.ts:111ensureReversePeerBridge). - No GUI file uses
threadBridgestoday (checked withrg threadBridges apps/kiki-gui/src).
Done when
- The direction shown on each row matches the inbound and outbound entries the status call returns (unit test for the direction helper covering both ways, outgoing only, incoming only, none, revoked and disabled entries).
- When the status call fails, every row shows "Thread messages: can't read" and no row shows "none" (test).
- Revoking one thread-message permission calls
revokewith that entry's direction and id only, the row's direction updates, and the pairing stays (test). - "Can't be opened" appears for a bridge-only record (
purposes: ['bridge']) and that row has no "Switch" button. - Screenshots at desktop and phone width, light and dark, en and zh, with
node apps/kiki-gui/scripts/visual-proof.mjs: the Spaces page with rows in each direction state and the "Thread messages…" panel. UI work is accepted only with these screenshots. - Phone-width screenshots are taken in a touch context (
isMobile: true, hasTouch: true, asapps/kiki-gui/scripts/visual-proof-mobile-reading.mjs:294-300does). Phone mode is(pointer: coarse) and (max-width: 639px)(apps/kiki-gui/src/lib/layoutHooks.ts:57), so a width-only--viewport narrowrun ofvisual-proof.mjsshows the desktop layout squeezed, not the phone layout.
Additional information
Already in the tree: phase 1 corrected the Access page note to say that pairing with a code also allows thread messages (read, send, wait) when both sides have a workspace, and that the list does not show them yet (st.inbound.bridgeNote). Once this issue and the pairing-sheet issue land, that note is replaced by the facts on each row.
The GUI has never rendered real BridgeStatus data; look at the scope fields of a real pairing before fixing how the other side's workspace is worded.
Depends on the settings-merge issue, which moves the outbound rows to the Spaces page; both edit RemoteConnectionsSection.tsx, and the merge goes first. The pairing-sheet issue edits the Access page's incoming list and reuses lib/threadBridges.ts and ThreadMessagesPanel.tsx from this issue, so it goes after this one.
Order and scope. Paths and line numbers refer to the code after the pending GUI interaction and mobile pull request is merged into kiki.
Depends on: #16.
Main files: apps/kiki-gui/src/lib/threadBridges.ts (new), apps/kiki-gui/src/lib/threadBridges.test.ts (new), apps/kiki-gui/src/components/settings/remote/ThreadMessagesPanel.tsx (new), apps/kiki-gui/src/components/settings/RemoteConnectionsSection.tsx, apps/kiki-gui/src/components/settings/SpacesSection.test.tsx, packages/session-core/src/i18n/en.ts, packages/session-core/src/i18n/zh.ts.
- Dominant language
- TypeScript
- Stars
- 54
- Forks
- 5
- Avg merge
- 2h 54m
- Merged PRs (30d)
- 2
Getting set up
- No Dockerfile or Docker Compose file
- Has a pull request template
- Read the contributing guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from X-T-E-R/kiki
-
Document PowerShell shell semantics and read-only Bash deduplication in Built-in Tools referenceOpendocumentation
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
-
bug documentation
Difficulty 2/5 1-3 hours Newbie friendliness 74/100
-
bug
Difficulty 4/5 3-5 days Newbie friendliness 54/100
-
enhancement
Difficulty 5/5 Over a week Newbie friendliness 1/100
-
documentation
Difficulty 5/5 Over a week Newbie friendliness 25/100
Similar issues
-
area: cli priority: P3 type: bug
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
appandflow/stim#5640 · 1 comment ·
Maintainers usually reply within 1 day
-
Claude Code: hook systemMessage lines never reach the chatPossibly taken @chphch claimed this today. Open
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
slopus/happy-agent#139 ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
NangoHQ/nango#8285 · 1 comment ·
Maintainers usually reply within 1 day
-
community first-timers-only good first issue hacktoberfest help wanted low hanging fruit up-for-grabs
Difficulty 1/5 Under an hour Newbie friendliness 85/100
lingdojo/kana-dojo#34009 · 1 comment · 5 reactions ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 73/100
paperclipai/paperclip#21197 ·
Maintainers usually reply within 1 day