@openmarket/rooms-client 0.3.0 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent/lane-prompts.js +1 -1
- package/dist/agent/room-context.d.ts +7 -0
- package/dist/agent/room-context.js +6 -2
- package/dist/client.d.ts +29 -4
- package/dist/client.js +55 -8
- package/dist/shared/rooms-protocol.d.ts +30 -0
- package/dist/shared/rooms-protocol.js +1 -0
- package/dist/social-client.d.ts +3 -2
- package/dist/social-types.d.ts +3 -0
- package/dist/types.d.ts +1 -1
- package/dist/version.d.ts +2 -2
- package/dist/version.js +2 -2
- package/package.json +1 -1
- package/src/agent/lane-prompts.ts +1 -1
- package/src/agent/room-context.ts +13 -2
- package/src/client.ts +81 -5
- package/src/shared/rooms-protocol.ts +36 -1
- package/src/social-client.ts +3 -2
- package/src/social-types.ts +3 -0
- package/src/types.ts +2 -0
- package/src/version.ts +2 -2
|
@@ -96,7 +96,7 @@ export function buildMergeProposalBootstrap(opts) {
|
|
|
96
96
|
/** The librarian bootstrap for `/brief refresh`: the agent rewrites the
|
|
97
97
|
* room's brief doc itself, in the canonical structure renderBrief pins. */
|
|
98
98
|
export function buildBriefRefreshBootstrap(opts) {
|
|
99
|
-
return lines(opts.personaLine, `You are the LIBRARIAN for ${opts.label}. Maintain its brief: a concise, current snapshot.`, "1. Read the recent conversation with room_history for this room.", `2. Read the existing brief if any: doc_read spaceId ${opts.spaceId}, path ${opts.path}.`, `3. List the docs in play with doc_list (spaceId ${opts.spaceId}).`, `4. Write the brief with doc_write (spaceId ${opts.spaceId}, path ${opts.path}, a note describing what changed), following EXACTLY this structure:`, "", `# Brief: ${opts.label}`, "", `> Auto-generated by the room agent, read-only. Updated ${opts.nowLabel}.`, "", "## Summary", "<one or two short paragraphs on what this room is about and where it stands>", "", "## Open
|
|
99
|
+
return lines(opts.personaLine, `You are the LIBRARIAN for ${opts.label}. Maintain its brief: a concise, current snapshot.`, "1. Read the recent conversation with room_history for this room.", `2. Read the existing brief if any: doc_read spaceId ${opts.spaceId}, path ${opts.path}.`, `3. List the docs in play with doc_list (spaceId ${opts.spaceId}).`, `4. Write the brief with doc_write (spaceId ${opts.spaceId}, path ${opts.path}, a note describing what changed), following EXACTLY this structure:`, "", `# Brief: ${opts.label}`, "", `> Auto-generated by the room agent, read-only. Updated ${opts.nowLabel}.`, "", "## Summary", "<one or two short paragraphs on what this room is about and where it stands>", "", "## Open questions", "- <unresolved questions, or `None.`>", "", "## Decisions", "- <decisions reached, or `None yet.`>", "", "## Docs in play", "- `path` (rN, when) for each referenced doc, or `None referenced.`", "", "Keep it tight and factual. Do NOT output a DRAFT line. After writing, reply with one line naming the revision you wrote.");
|
|
100
100
|
}
|
|
101
101
|
/** The scoped-summarize turn message. It runs on the DEFAULT lane bootstrap
|
|
102
102
|
* (context spine + citation teaching already present); the message carries
|
|
@@ -107,7 +107,14 @@ export interface BriefInput {
|
|
|
107
107
|
openThreads: string[];
|
|
108
108
|
decisions: string[];
|
|
109
109
|
docs: BriefDocRef[];
|
|
110
|
+
/** Highest message seq this brief has incorporated. Rendered into the
|
|
111
|
+
* banner as the librarian's shared cursor; co-librarians read it before
|
|
112
|
+
* spending anything. */
|
|
113
|
+
coveredSeq?: number;
|
|
110
114
|
}
|
|
115
|
+
/** The banner's machine-readable coverage claim. Parsers must only consult
|
|
116
|
+
* the banner blockquote line, never body prose. */
|
|
117
|
+
export declare const BRIEF_COVERED_RE: RegExp;
|
|
111
118
|
/** Render the canonical brief markdown. Deterministic shell; the LLM only
|
|
112
119
|
* supplies the summary/threads/decisions prose. */
|
|
113
120
|
export declare function renderBrief(input: BriefInput): string;
|
|
@@ -128,19 +128,23 @@ export function briefPath(roomName) {
|
|
|
128
128
|
.slice(0, 60) || "room";
|
|
129
129
|
return `briefs/${slug}.md`;
|
|
130
130
|
}
|
|
131
|
+
/** The banner's machine-readable coverage claim. Parsers must only consult
|
|
132
|
+
* the banner blockquote line, never body prose. */
|
|
133
|
+
export const BRIEF_COVERED_RE = /\bCovers through seq (\d+)\./;
|
|
131
134
|
/** Render the canonical brief markdown. Deterministic shell; the LLM only
|
|
132
135
|
* supplies the summary/threads/decisions prose. */
|
|
133
136
|
export function renderBrief(input) {
|
|
137
|
+
const covered = input.coveredSeq !== undefined ? ` Covers through seq ${input.coveredSeq}.` : "";
|
|
134
138
|
const lines = [];
|
|
135
139
|
lines.push(`# Brief: ${input.room}`);
|
|
136
140
|
lines.push("");
|
|
137
|
-
lines.push(`> Auto-generated by the room agent, read-only. Updated ${input.updatedAtLabel}
|
|
141
|
+
lines.push(`> Auto-generated by the room agent, read-only. Updated ${input.updatedAtLabel}.${covered}`);
|
|
138
142
|
lines.push("");
|
|
139
143
|
lines.push("## Summary");
|
|
140
144
|
lines.push("");
|
|
141
145
|
lines.push(input.summary.trim() || "_No summary yet._");
|
|
142
146
|
lines.push("");
|
|
143
|
-
lines.push("## Open
|
|
147
|
+
lines.push("## Open questions");
|
|
144
148
|
lines.push("");
|
|
145
149
|
if (input.openThreads.length === 0)
|
|
146
150
|
lines.push("_None._");
|
package/dist/client.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type RoomAccessMode, type RoomAttachmentInput, type RoomAuditLogPayload, type RoomAuthSuccessPayload, type RoomBackfillPayload, type RoomDmHistoryResultPayload, type RoomDmMessagePayload, type RoomDmOpenedPayload, type RoomFriendPresence, type RoomInvitedPayload, type RoomLedgerEntry, type RoomMemberRemovedPayload, type RoomMemberRoleChangedPayload, type RoomMeta, type RoomPinsPayload, type RoomPresencePayload, type RoomReactorsPayload, type RoomReadStatePayload, type RoomReportedPayload, type RoomRole, type RoomSearchResultsPayload, type RoomSearchScope, type RoomSpace, type RoomThreadPayload, type RoomTopic, type RoomTopicAttention, type RoomTopicResultPayload, type RoomTopicsResultPayload, type RoomUserStatus, type RoomWhoPayload } from "./types.js";
|
|
1
|
+
import { type RoomAccessMode, type RoomAttachmentInput, type RoomAuditLogPayload, type RoomAuthSuccessPayload, type RoomBackfillPayload, type RoomClientPlatform, type RoomDmHistoryResultPayload, type RoomDmInboxUpdatedPayload, type RoomDmMessagePayload, type RoomDmOpenedPayload, type RoomFriendPresence, type RoomInvitedPayload, type RoomLedgerEntry, type RoomMemberRemovedPayload, type RoomMemberRoleChangedPayload, type RoomMeta, type RoomPinsPayload, type RoomPresencePayload, type RoomReactorsPayload, type RoomReadStatePayload, type RoomReportedPayload, type RoomRole, type RoomSearchResultsPayload, type RoomSearchScope, type RoomSpace, type RoomThreadPayload, type RoomTopic, type RoomTopicAttention, type RoomTopicResultPayload, type RoomTopicsResultPayload, type RoomUserStatus, type RoomWhoPayload } from "./types.js";
|
|
2
2
|
import { type RoomWebSocketCtor, RoomWsClient } from "./ws-client.js";
|
|
3
3
|
export interface RoomClientConfig {
|
|
4
4
|
url: string;
|
|
@@ -213,6 +213,10 @@ export interface RoomDmSendRequest {
|
|
|
213
213
|
* Additive — omitted for text-only sends. */
|
|
214
214
|
imageUrl?: string;
|
|
215
215
|
}
|
|
216
|
+
export interface RoomDmReadRequest {
|
|
217
|
+
username?: string;
|
|
218
|
+
conversationId?: string;
|
|
219
|
+
}
|
|
216
220
|
export interface RoomThreadRequest {
|
|
217
221
|
room: string;
|
|
218
222
|
rootSeq: number;
|
|
@@ -254,6 +258,7 @@ export declare function whoamiRoom(config: RoomClientConfig): Promise<RoomAuthSu
|
|
|
254
258
|
export declare function requestRoomFriends(client: RoomWsClient): Promise<RoomFriendPresence[]>;
|
|
255
259
|
export declare function openRoomDmOnClient(client: RoomWsClient, request: RoomDmOpenRequest, timeoutMs?: number): Promise<RoomDmOpenedPayload>;
|
|
256
260
|
export declare function requestRoomDmHistoryOnClient(client: RoomWsClient, request: RoomDmHistoryRequest, timeoutMs?: number): Promise<RoomDmHistoryResultPayload>;
|
|
261
|
+
export declare function markRoomDmReadOnClient(client: RoomWsClient, request: RoomDmReadRequest, timeoutMs?: number): Promise<RoomDmInboxUpdatedPayload>;
|
|
257
262
|
export declare function sendRoomDmOnClient(client: RoomWsClient, request: RoomDmSendRequest, timeoutMs?: number): Promise<RoomDmMessagePayload>;
|
|
258
263
|
/** Edit one of my DM messages. Fire-and-forget over the WS; the relay fans out
|
|
259
264
|
* DM_MESSAGE_EDITED to both participants. */
|
|
@@ -283,9 +288,18 @@ export declare function joinRoom(config: RoomClientConfig, options: RoomJoinOpti
|
|
|
283
288
|
/** Re-join a room on an already-connected client (used after a reconnect). */
|
|
284
289
|
export declare function rejoinRoomOnClient(client: RoomWsClient, options: RoomJoinOptions): Promise<RoomBackfillPayload>;
|
|
285
290
|
export declare function attachRejoinOnReconnect(client: RoomWsClient, options: RoomJoinOptions, latestSeq: () => number | undefined, onRejoined?: (backfill: RoomBackfillPayload) => void, onError?: (err: unknown) => void): () => void;
|
|
286
|
-
|
|
291
|
+
/**
|
|
292
|
+
* Post into a joined room and return the frame's clientMsgId (what MESSAGE
|
|
293
|
+
* echoes carry back for optimistic-send reconciliation). `clientMsgId` is
|
|
294
|
+
* caller-suppliable so an offline send queue can retry one logical message
|
|
295
|
+
* under one stable id (same contract as sayRoom / sendRoomDmOnClient);
|
|
296
|
+
* omitted, it mints a UUID exactly as before. The relay validates the id
|
|
297
|
+
* (1..128 chars after trim); dedupe on (userId, clientMsgId) is server-side
|
|
298
|
+
* work and NOT implied here.
|
|
299
|
+
*/
|
|
300
|
+
export declare function postRoomMessage(client: RoomWsClient, room: string, text: string, inReplyTo?: number, attachments?: RoomAttachmentInput[], topicId?: string, clientMsgId?: string): string;
|
|
287
301
|
export declare function sendRoomTyping(client: RoomWsClient, room: string, state: "start" | "stop"): void;
|
|
288
|
-
export declare function sendRoomStatus(client: RoomWsClient, status: RoomUserStatus, statusText?: string | null): void;
|
|
302
|
+
export declare function sendRoomStatus(client: RoomWsClient, status: RoomUserStatus, statusText?: string | null, platform?: RoomClientPlatform): void;
|
|
289
303
|
/**
|
|
290
304
|
* Fetch a joined room's meta (title, access, postingRoles, viewerRole) over
|
|
291
305
|
* the live socket via a scoped SEARCH. Returns null on timeout/no match so
|
|
@@ -310,7 +324,18 @@ export declare function requestRoomReactors(client: RoomWsClient, request: {
|
|
|
310
324
|
* persists it durably; a one-shot socket has no joined rooms, so live
|
|
311
325
|
* rosters pick the change up from the store (the TUI/GUI send STATUS on
|
|
312
326
|
* their live connection instead, which also broadcasts PRESENCE_DELTA). */
|
|
313
|
-
export declare function setRoomStatusOnce(config: RoomClientConfig, status: RoomUserStatus, statusText?: string | null): Promise<void>;
|
|
327
|
+
export declare function setRoomStatusOnce(config: RoomClientConfig, status: RoomUserStatus, statusText?: string | null, platform?: RoomClientPlatform): Promise<void>;
|
|
328
|
+
/**
|
|
329
|
+
* Set the caller's room-level attention (notification posture) on a live
|
|
330
|
+
* client. The relay validates room participation, persists through the
|
|
331
|
+
* store, and acks with a READ_STATE frame scoped to this room whose
|
|
332
|
+
* attention map carries the persisted value (readState stays empty: cursors
|
|
333
|
+
* are untouched). Private per-user state; nothing broadcasts.
|
|
334
|
+
*/
|
|
335
|
+
export declare function setRoomAttentionOnClient(client: RoomWsClient, request: {
|
|
336
|
+
room: string;
|
|
337
|
+
attention: RoomTopicAttention;
|
|
338
|
+
}): Promise<RoomReadStatePayload>;
|
|
314
339
|
/** Add/remove one reaction (one-shot). Returns the updated entry. */
|
|
315
340
|
export declare function reactRoom(config: RoomClientConfig, options: {
|
|
316
341
|
room: string;
|
package/dist/client.js
CHANGED
|
@@ -454,6 +454,20 @@ export async function requestRoomDmHistoryOnClient(client, request, timeoutMs) {
|
|
|
454
454
|
const history = await client.waitFor(RoomServerMessageType.DM_HISTORY, (msg) => msg.payload.requestId === requestId, timeoutMs, requestId);
|
|
455
455
|
return history.payload;
|
|
456
456
|
}
|
|
457
|
+
export async function markRoomDmReadOnClient(client, request, timeoutMs) {
|
|
458
|
+
const requestId = randomUUID();
|
|
459
|
+
client.send({
|
|
460
|
+
type: RoomClientMessageType.DM_READ,
|
|
461
|
+
payload: {
|
|
462
|
+
requestId,
|
|
463
|
+
...(request.username ? { username: request.username } : {}),
|
|
464
|
+
...(request.conversationId ? { conversationId: request.conversationId } : {}),
|
|
465
|
+
},
|
|
466
|
+
timestamp: Date.now(),
|
|
467
|
+
});
|
|
468
|
+
const updated = await client.waitFor(RoomServerMessageType.DM_INBOX_UPDATED, (msg) => msg.payload.requestId === requestId, timeoutMs, requestId);
|
|
469
|
+
return updated.payload;
|
|
470
|
+
}
|
|
457
471
|
export async function sendRoomDmOnClient(client, request, timeoutMs) {
|
|
458
472
|
const requestId = randomUUID();
|
|
459
473
|
const clientMsgId = request.clientMsgId ?? randomUUID();
|
|
@@ -618,21 +632,30 @@ export function attachRejoinOnReconnect(client, options, latestSeq, onRejoined,
|
|
|
618
632
|
.catch((err) => onError?.(err));
|
|
619
633
|
});
|
|
620
634
|
}
|
|
621
|
-
|
|
622
|
-
|
|
635
|
+
/**
|
|
636
|
+
* Post into a joined room and return the frame's clientMsgId (what MESSAGE
|
|
637
|
+
* echoes carry back for optimistic-send reconciliation). `clientMsgId` is
|
|
638
|
+
* caller-suppliable so an offline send queue can retry one logical message
|
|
639
|
+
* under one stable id (same contract as sayRoom / sendRoomDmOnClient);
|
|
640
|
+
* omitted, it mints a UUID exactly as before. The relay validates the id
|
|
641
|
+
* (1..128 chars after trim); dedupe on (userId, clientMsgId) is server-side
|
|
642
|
+
* work and NOT implied here.
|
|
643
|
+
*/
|
|
644
|
+
export function postRoomMessage(client, room, text, inReplyTo, attachments, topicId, clientMsgId) {
|
|
645
|
+
const msgId = clientMsgId ?? randomUUID();
|
|
623
646
|
client.send({
|
|
624
647
|
type: RoomClientMessageType.POST,
|
|
625
648
|
payload: {
|
|
626
649
|
room,
|
|
627
650
|
...(text ? { text } : {}),
|
|
628
651
|
...(attachments?.length ? { attachments: toRoomAttachmentPayloads(attachments) } : {}),
|
|
629
|
-
clientMsgId,
|
|
652
|
+
clientMsgId: msgId,
|
|
630
653
|
...(inReplyTo !== undefined ? { inReplyTo } : {}),
|
|
631
654
|
...(topicId ? { topicId } : {}),
|
|
632
655
|
},
|
|
633
656
|
timestamp: Date.now(),
|
|
634
657
|
});
|
|
635
|
-
return
|
|
658
|
+
return msgId;
|
|
636
659
|
}
|
|
637
660
|
export function sendRoomTyping(client, room, state) {
|
|
638
661
|
if (client.isGuest())
|
|
@@ -643,10 +666,16 @@ export function sendRoomTyping(client, room, state) {
|
|
|
643
666
|
timestamp: Date.now(),
|
|
644
667
|
});
|
|
645
668
|
}
|
|
646
|
-
export function sendRoomStatus(client, status, statusText) {
|
|
669
|
+
export function sendRoomStatus(client, status, statusText, platform) {
|
|
647
670
|
client.send({
|
|
648
671
|
type: RoomClientMessageType.STATUS,
|
|
649
|
-
payload: {
|
|
672
|
+
payload: {
|
|
673
|
+
status,
|
|
674
|
+
...(statusText !== undefined ? { statusText } : {}),
|
|
675
|
+
// Session identity, declared once per connection (or on change): the
|
|
676
|
+
// relay carries it onto presence member entries.
|
|
677
|
+
...(platform ? { platform } : {}),
|
|
678
|
+
},
|
|
650
679
|
timestamp: Date.now(),
|
|
651
680
|
});
|
|
652
681
|
}
|
|
@@ -769,11 +798,11 @@ export async function requestRoomReactors(client, request) {
|
|
|
769
798
|
* persists it durably; a one-shot socket has no joined rooms, so live
|
|
770
799
|
* rosters pick the change up from the store (the TUI/GUI send STATUS on
|
|
771
800
|
* their live connection instead, which also broadcasts PRESENCE_DELTA). */
|
|
772
|
-
export async function setRoomStatusOnce(config, status, statusText) {
|
|
801
|
+
export async function setRoomStatusOnce(config, status, statusText, platform) {
|
|
773
802
|
const client = new RoomWsClient(config);
|
|
774
803
|
try {
|
|
775
804
|
await client.connect();
|
|
776
|
-
sendRoomStatus(client, status, statusText);
|
|
805
|
+
sendRoomStatus(client, status, statusText, platform);
|
|
777
806
|
// STATUS has no ack frame: give the socket a beat to flush before close.
|
|
778
807
|
await new Promise((resolve) => setTimeout(resolve, 200));
|
|
779
808
|
}
|
|
@@ -781,6 +810,24 @@ export async function setRoomStatusOnce(config, status, statusText) {
|
|
|
781
810
|
client.close();
|
|
782
811
|
}
|
|
783
812
|
}
|
|
813
|
+
/**
|
|
814
|
+
* Set the caller's room-level attention (notification posture) on a live
|
|
815
|
+
* client. The relay validates room participation, persists through the
|
|
816
|
+
* store, and acks with a READ_STATE frame scoped to this room whose
|
|
817
|
+
* attention map carries the persisted value (readState stays empty: cursors
|
|
818
|
+
* are untouched). Private per-user state; nothing broadcasts.
|
|
819
|
+
*/
|
|
820
|
+
export async function setRoomAttentionOnClient(client, request) {
|
|
821
|
+
const requestId = randomUUID();
|
|
822
|
+
const room = normalizeRoomName(request.room);
|
|
823
|
+
client.send({
|
|
824
|
+
type: RoomClientMessageType.ROOM_SET_ATTENTION,
|
|
825
|
+
payload: { requestId, room, attention: request.attention },
|
|
826
|
+
timestamp: Date.now(),
|
|
827
|
+
});
|
|
828
|
+
const result = await client.waitFor(RoomServerMessageType.READ_STATE, (msg) => msg.payload.requestId === requestId, undefined, requestId);
|
|
829
|
+
return result.payload;
|
|
830
|
+
}
|
|
784
831
|
/** One-shot session helper for the config-based mutation verbs below (the
|
|
785
832
|
* agent tools' transport: connect, join, act, wait for the echo, close). */
|
|
786
833
|
async function withRoomEcho(config, room, seq, send) {
|
|
@@ -48,6 +48,7 @@ export declare const RoomClientMessageType: {
|
|
|
48
48
|
readonly TOPIC_RESOLVE: "TOPIC_RESOLVE";
|
|
49
49
|
readonly TOPIC_SET_ATTENTION: "TOPIC_SET_ATTENTION";
|
|
50
50
|
readonly TOPIC_LIST: "TOPIC_LIST";
|
|
51
|
+
readonly ROOM_SET_ATTENTION: "ROOM_SET_ATTENTION";
|
|
51
52
|
};
|
|
52
53
|
export type RoomClientMessageType = (typeof RoomClientMessageType)[keyof typeof RoomClientMessageType];
|
|
53
54
|
export declare const RoomServerMessageType: {
|
|
@@ -127,6 +128,9 @@ export type RoomRole = "owner" | "admin" | "mod" | "member";
|
|
|
127
128
|
* semantics of an absent value). */
|
|
128
129
|
export type RoomTopicsPolicy = "off" | "allowed" | "required";
|
|
129
130
|
export type RoomTopicAttention = "follow" | "default" | "mute";
|
|
131
|
+
/** Self-declared client class on STATUS frames; presence member entries
|
|
132
|
+
* carry it through so rosters can render where someone is connected from. */
|
|
133
|
+
export type RoomClientPlatform = "web" | "desktop" | "mobile" | "tui";
|
|
130
134
|
export interface RoomMember {
|
|
131
135
|
userId: string;
|
|
132
136
|
username: string;
|
|
@@ -140,6 +144,8 @@ export interface RoomMember {
|
|
|
140
144
|
joinedAt: number;
|
|
141
145
|
avatarUrl?: string | null;
|
|
142
146
|
statusText?: string | null;
|
|
147
|
+
/** Present when the member's session declared one via STATUS. */
|
|
148
|
+
platform?: RoomClientPlatform | undefined;
|
|
143
149
|
}
|
|
144
150
|
export interface RoomMeta {
|
|
145
151
|
name: string;
|
|
@@ -164,6 +170,10 @@ export interface RoomMeta {
|
|
|
164
170
|
* 2026-07-12 dial-default flip (post-flip relays always advertise the
|
|
165
171
|
* stored value, "off" included); explicit "off" means topics are inert. */
|
|
166
172
|
topicsPolicy?: RoomTopicsPolicy | undefined;
|
|
173
|
+
/** The viewer's room attention (notification posture), a per-viewer field
|
|
174
|
+
* like viewerRole: surfaced on rooms listings for the caller. Absent
|
|
175
|
+
* reads as "default". */
|
|
176
|
+
attention?: RoomTopicAttention | undefined;
|
|
167
177
|
tags?: string[] | undefined;
|
|
168
178
|
entities?: string[] | undefined;
|
|
169
179
|
sourceRefs?: Array<Record<string, unknown>> | undefined;
|
|
@@ -295,7 +305,12 @@ export interface RoomPinsPayload {
|
|
|
295
305
|
requestId?: string | undefined;
|
|
296
306
|
}
|
|
297
307
|
export interface RoomReadStatePayload {
|
|
308
|
+
/** Partial map: rooms absent from a reply are unchanged. */
|
|
298
309
|
readState: Record<string, number>;
|
|
310
|
+
/** Per-room attention for the requesting user, keyed like readState.
|
|
311
|
+
* Present when the store surfaces it and on ROOM_SET_ATTENTION acks
|
|
312
|
+
* (which reply READ_STATE scoped to the one room, readState empty). */
|
|
313
|
+
attention?: Record<string, RoomTopicAttention> | undefined;
|
|
299
314
|
requestId?: string | undefined;
|
|
300
315
|
}
|
|
301
316
|
export interface RoomSearchResultsPayload {
|
|
@@ -560,6 +575,7 @@ export interface RoomDmMessagePayload {
|
|
|
560
575
|
clientMsgId?: string;
|
|
561
576
|
}
|
|
562
577
|
export interface RoomDmInboxUpdatedPayload {
|
|
578
|
+
requestId?: string;
|
|
563
579
|
conversationId: string;
|
|
564
580
|
participant: RoomDmParticipant;
|
|
565
581
|
unreadCount: number;
|
|
@@ -743,6 +759,15 @@ export interface RoomTopicSetAttentionPayload {
|
|
|
743
759
|
topicId: string;
|
|
744
760
|
attention: RoomTopicAttention;
|
|
745
761
|
}
|
|
762
|
+
/** Room-level attention (notification posture). Private per-user state on
|
|
763
|
+
* the caller's read row; topic attention wins for topic-scoped messages
|
|
764
|
+
* and room attention wins over space attention. The relay acks with a
|
|
765
|
+
* READ_STATE frame scoped to the room (see RoomReadStatePayload). */
|
|
766
|
+
export interface RoomSetAttentionPayload {
|
|
767
|
+
requestId?: string;
|
|
768
|
+
room: string;
|
|
769
|
+
attention: RoomTopicAttention;
|
|
770
|
+
}
|
|
746
771
|
export interface RoomTopicListPayload {
|
|
747
772
|
requestId?: string;
|
|
748
773
|
room: string;
|
|
@@ -1017,6 +1042,7 @@ export type RoomClientMessage = {
|
|
|
1017
1042
|
payload: {
|
|
1018
1043
|
status: RoomUserStatus;
|
|
1019
1044
|
statusText?: string | null;
|
|
1045
|
+
platform?: RoomClientPlatform;
|
|
1020
1046
|
};
|
|
1021
1047
|
timestamp?: number;
|
|
1022
1048
|
} | {
|
|
@@ -1092,6 +1118,10 @@ export type RoomClientMessage = {
|
|
|
1092
1118
|
type: typeof RoomClientMessageType.TOPIC_LIST;
|
|
1093
1119
|
payload: RoomTopicListPayload;
|
|
1094
1120
|
timestamp?: number;
|
|
1121
|
+
} | {
|
|
1122
|
+
type: typeof RoomClientMessageType.ROOM_SET_ATTENTION;
|
|
1123
|
+
payload: RoomSetAttentionPayload;
|
|
1124
|
+
timestamp?: number;
|
|
1095
1125
|
};
|
|
1096
1126
|
export type RoomServerMessage = {
|
|
1097
1127
|
type: typeof RoomServerMessageType.AUTH_SUCCESS;
|
|
@@ -48,6 +48,7 @@ export const RoomClientMessageType = {
|
|
|
48
48
|
TOPIC_RESOLVE: "TOPIC_RESOLVE",
|
|
49
49
|
TOPIC_SET_ATTENTION: "TOPIC_SET_ATTENTION",
|
|
50
50
|
TOPIC_LIST: "TOPIC_LIST",
|
|
51
|
+
ROOM_SET_ATTENTION: "ROOM_SET_ATTENTION",
|
|
51
52
|
};
|
|
52
53
|
export const RoomServerMessageType = {
|
|
53
54
|
AUTH_SUCCESS: "AUTH_SUCCESS",
|
package/dist/social-client.d.ts
CHANGED
|
@@ -174,7 +174,8 @@ export interface RoomSpaceSummary {
|
|
|
174
174
|
export declare function listRoomSpacesViaChat(config: RoomSocialConfig): Promise<RoomSpaceSummary[]>;
|
|
175
175
|
export interface RoomSpaceMember {
|
|
176
176
|
userId: string;
|
|
177
|
-
role
|
|
177
|
+
/** The ladder role. 'librarian' maintains the generated briefs/ docs. */
|
|
178
|
+
role: "owner" | "admin" | "librarian" | "member";
|
|
178
179
|
/** Named identity roles (RoomSpaceRole.roleId). */
|
|
179
180
|
roleIds?: string[];
|
|
180
181
|
joinedAt?: string;
|
|
@@ -329,7 +330,7 @@ export declare function listRoomChannelMembers(config: RoomSocialConfig, roomId:
|
|
|
329
330
|
export declare function removeSpaceMember(config: RoomSocialConfig, spaceId: string, targetUserId: string): Promise<{
|
|
330
331
|
removed?: boolean;
|
|
331
332
|
}>;
|
|
332
|
-
export declare function changeSpaceMemberRole(config: RoomSocialConfig, spaceId: string, targetUserId: string, role: "admin" | "member"): Promise<RoomSpaceMember>;
|
|
333
|
+
export declare function changeSpaceMemberRole(config: RoomSocialConfig, spaceId: string, targetUserId: string, role: "admin" | "librarian" | "member"): Promise<RoomSpaceMember>;
|
|
333
334
|
/** Set (string) or clear (null) a member's per-space nickname; the store validates and enforces uniqueness. */
|
|
334
335
|
export declare function setSpaceMemberNickname(config: RoomSocialConfig, spaceId: string, targetUserId: string, nickname: string | null): Promise<RoomSpaceMember>;
|
|
335
336
|
export declare function createRoomSpace(config: RoomSocialConfig, input: {
|
package/dist/social-types.d.ts
CHANGED
|
@@ -130,6 +130,9 @@ export interface RoomDmMessage {
|
|
|
130
130
|
emoji: string;
|
|
131
131
|
users: string[];
|
|
132
132
|
}>;
|
|
133
|
+
/** Client-minted idempotency tag echoed back on DM sends, so a sender's
|
|
134
|
+
* durable queue can settle its optimistic row. Additive (0.4.0). */
|
|
135
|
+
clientMsgId?: string;
|
|
133
136
|
}
|
|
134
137
|
export interface RoomDmHistory {
|
|
135
138
|
conversationId: string;
|
package/dist/types.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export type { RoomAccessMode, RoomAttachment, RoomAttachmentInput, RoomAuditEntry, RoomAuditLogPayload, RoomAuditLogRequestPayload, RoomAuthSuccessPayload, RoomBackfillPayload, RoomClientMessage, RoomCreatedPayload, RoomCreatePayload, RoomDmHistoryPayload, RoomDmHistoryResultPayload, RoomDmInboxUpdatedPayload, RoomDmMessage, RoomDmMessagePayload, RoomDmOpenedPayload, RoomDmOpenPayload, RoomDmParticipant, RoomDmReadPayload, RoomDmSendPayload, RoomEntryUpdatedPayload, RoomErrorPayload, RoomFriendPresence, RoomInvitedPayload, RoomInvitePayload, RoomLedgerEntry, RoomMember, RoomMemberRemovedPayload, RoomMemberRoleChangedPayload, RoomMemberTier, RoomMessagePayload, RoomMeta, RoomModerateMemberPayload, RoomMutedPayload, RoomPinsPayload, RoomPresenceDeltaPayload, RoomPresencePayload, RoomReactorsPayload, RoomReadStatePayload, RoomRemoveMemberPayload, RoomReportedPayload, RoomReportPayload, RoomResyncPayload, RoomRole, RoomRoleChangePayload, RoomSearchPayload, RoomSearchResultsPayload, RoomSearchScope, RoomServerMessage, RoomServerMessageOf, RoomSetReadOnlyPayload, RoomSpace, RoomSpaceJoinedPayload, RoomSpacesPayload, RoomThreadPayload, RoomTopic, RoomTopicAttention, RoomTopicBucketState, RoomTopicCreatePayload, RoomTopicListPayload, RoomTopicMergePayload, RoomTopicMovePayload, RoomTopicRenamePayload, RoomTopicResolvePayload, RoomTopicResultPayload, RoomTopicSetAttentionPayload, RoomTopicsPolicy, RoomTopicsResultPayload, RoomTopicUpdatedPayload, RoomTypingPayload, RoomUserStatus, RoomWhoPayload, } from "./shared/rooms-protocol.js";
|
|
1
|
+
export type { RoomAccessMode, RoomAttachment, RoomAttachmentInput, RoomAuditEntry, RoomAuditLogPayload, RoomAuditLogRequestPayload, RoomAuthSuccessPayload, RoomBackfillPayload, RoomClientMessage, RoomClientPlatform, RoomCreatedPayload, RoomCreatePayload, RoomDmHistoryPayload, RoomDmHistoryResultPayload, RoomDmInboxUpdatedPayload, RoomDmMessage, RoomDmMessagePayload, RoomDmOpenedPayload, RoomDmOpenPayload, RoomDmParticipant, RoomDmReadPayload, RoomDmSendPayload, RoomEntryUpdatedPayload, RoomErrorPayload, RoomFriendPresence, RoomInvitedPayload, RoomInvitePayload, RoomLedgerEntry, RoomMember, RoomMemberRemovedPayload, RoomMemberRoleChangedPayload, RoomMemberTier, RoomMessagePayload, RoomMeta, RoomModerateMemberPayload, RoomMutedPayload, RoomPinsPayload, RoomPresenceDeltaPayload, RoomPresencePayload, RoomReactorsPayload, RoomReadStatePayload, RoomRemoveMemberPayload, RoomReportedPayload, RoomReportPayload, RoomResyncPayload, RoomRole, RoomRoleChangePayload, RoomSearchPayload, RoomSearchResultsPayload, RoomSearchScope, RoomServerMessage, RoomServerMessageOf, RoomSetAttentionPayload, RoomSetReadOnlyPayload, RoomSpace, RoomSpaceJoinedPayload, RoomSpacesPayload, RoomThreadPayload, RoomTopic, RoomTopicAttention, RoomTopicBucketState, RoomTopicCreatePayload, RoomTopicListPayload, RoomTopicMergePayload, RoomTopicMovePayload, RoomTopicRenamePayload, RoomTopicResolvePayload, RoomTopicResultPayload, RoomTopicSetAttentionPayload, RoomTopicsPolicy, RoomTopicsResultPayload, RoomTopicUpdatedPayload, RoomTypingPayload, RoomUserStatus, RoomWhoPayload, } from "./shared/rooms-protocol.js";
|
|
2
2
|
export { applyRoomPresenceDelta, isSystemRoomLedgerEntryType, ROOM_PRESENCE_SAMPLE_LIMIT, RoomClientMessageType, RoomLedgerEntryType, RoomServerMessageType, SUPPORTED_ROOM_PROTOCOL_VERSION, } from "./shared/rooms-protocol.js";
|
package/dist/version.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const VERSION = "0.
|
|
2
|
-
export declare const RUNNER_VERSION = "0.
|
|
1
|
+
export declare const VERSION = "0.6.0";
|
|
2
|
+
export declare const RUNNER_VERSION = "0.6.0";
|
package/dist/version.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export const VERSION = "0.
|
|
2
|
-
export const RUNNER_VERSION = "0.
|
|
1
|
+
export const VERSION = "0.6.0";
|
|
2
|
+
export const RUNNER_VERSION = "0.6.0";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openmarket/rooms-client",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.1",
|
|
4
4
|
"description": "OM Rooms protocol client: wire types, WebSocket + REST clients, and chat view-models. Browser-safe (no node:/bun: imports).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -202,7 +202,7 @@ export function buildBriefRefreshBootstrap(opts: {
|
|
|
202
202
|
"## Summary",
|
|
203
203
|
"<one or two short paragraphs on what this room is about and where it stands>",
|
|
204
204
|
"",
|
|
205
|
-
"## Open
|
|
205
|
+
"## Open questions",
|
|
206
206
|
"- <unresolved questions, or `None.`>",
|
|
207
207
|
"",
|
|
208
208
|
"## Decisions",
|
|
@@ -202,21 +202,32 @@ export interface BriefInput {
|
|
|
202
202
|
openThreads: string[];
|
|
203
203
|
decisions: string[];
|
|
204
204
|
docs: BriefDocRef[];
|
|
205
|
+
/** Highest message seq this brief has incorporated. Rendered into the
|
|
206
|
+
* banner as the librarian's shared cursor; co-librarians read it before
|
|
207
|
+
* spending anything. */
|
|
208
|
+
coveredSeq?: number;
|
|
205
209
|
}
|
|
206
210
|
|
|
211
|
+
/** The banner's machine-readable coverage claim. Parsers must only consult
|
|
212
|
+
* the banner blockquote line, never body prose. */
|
|
213
|
+
export const BRIEF_COVERED_RE = /\bCovers through seq (\d+)\./;
|
|
214
|
+
|
|
207
215
|
/** Render the canonical brief markdown. Deterministic shell; the LLM only
|
|
208
216
|
* supplies the summary/threads/decisions prose. */
|
|
209
217
|
export function renderBrief(input: BriefInput): string {
|
|
218
|
+
const covered = input.coveredSeq !== undefined ? ` Covers through seq ${input.coveredSeq}.` : "";
|
|
210
219
|
const lines: string[] = [];
|
|
211
220
|
lines.push(`# Brief: ${input.room}`);
|
|
212
221
|
lines.push("");
|
|
213
|
-
lines.push(
|
|
222
|
+
lines.push(
|
|
223
|
+
`> Auto-generated by the room agent, read-only. Updated ${input.updatedAtLabel}.${covered}`,
|
|
224
|
+
);
|
|
214
225
|
lines.push("");
|
|
215
226
|
lines.push("## Summary");
|
|
216
227
|
lines.push("");
|
|
217
228
|
lines.push(input.summary.trim() || "_No summary yet._");
|
|
218
229
|
lines.push("");
|
|
219
|
-
lines.push("## Open
|
|
230
|
+
lines.push("## Open questions");
|
|
220
231
|
lines.push("");
|
|
221
232
|
if (input.openThreads.length === 0) lines.push("_None._");
|
|
222
233
|
else for (const t of input.openThreads) lines.push(`- ${t}`);
|
package/src/client.ts
CHANGED
|
@@ -13,7 +13,9 @@ import {
|
|
|
13
13
|
type RoomBackfillPayload,
|
|
14
14
|
type RoomClientMessage,
|
|
15
15
|
RoomClientMessageType,
|
|
16
|
+
type RoomClientPlatform,
|
|
16
17
|
type RoomDmHistoryResultPayload,
|
|
18
|
+
type RoomDmInboxUpdatedPayload,
|
|
17
19
|
type RoomDmMessagePayload,
|
|
18
20
|
type RoomDmOpenedPayload,
|
|
19
21
|
type RoomFriendPresence,
|
|
@@ -292,6 +294,11 @@ export interface RoomDmSendRequest {
|
|
|
292
294
|
imageUrl?: string;
|
|
293
295
|
}
|
|
294
296
|
|
|
297
|
+
export interface RoomDmReadRequest {
|
|
298
|
+
username?: string;
|
|
299
|
+
conversationId?: string;
|
|
300
|
+
}
|
|
301
|
+
|
|
295
302
|
export interface RoomThreadRequest {
|
|
296
303
|
room: string;
|
|
297
304
|
rootSeq: number;
|
|
@@ -922,6 +929,30 @@ export async function requestRoomDmHistoryOnClient(
|
|
|
922
929
|
return history.payload;
|
|
923
930
|
}
|
|
924
931
|
|
|
932
|
+
export async function markRoomDmReadOnClient(
|
|
933
|
+
client: RoomWsClient,
|
|
934
|
+
request: RoomDmReadRequest,
|
|
935
|
+
timeoutMs?: number,
|
|
936
|
+
): Promise<RoomDmInboxUpdatedPayload> {
|
|
937
|
+
const requestId = randomUUID();
|
|
938
|
+
client.send({
|
|
939
|
+
type: RoomClientMessageType.DM_READ,
|
|
940
|
+
payload: {
|
|
941
|
+
requestId,
|
|
942
|
+
...(request.username ? { username: request.username } : {}),
|
|
943
|
+
...(request.conversationId ? { conversationId: request.conversationId } : {}),
|
|
944
|
+
},
|
|
945
|
+
timestamp: Date.now(),
|
|
946
|
+
});
|
|
947
|
+
const updated = await client.waitFor(
|
|
948
|
+
RoomServerMessageType.DM_INBOX_UPDATED,
|
|
949
|
+
(msg) => msg.payload.requestId === requestId,
|
|
950
|
+
timeoutMs,
|
|
951
|
+
requestId,
|
|
952
|
+
);
|
|
953
|
+
return updated.payload;
|
|
954
|
+
}
|
|
955
|
+
|
|
925
956
|
export async function sendRoomDmOnClient(
|
|
926
957
|
client: RoomWsClient,
|
|
927
958
|
request: RoomDmSendRequest,
|
|
@@ -1147,6 +1178,15 @@ export function attachRejoinOnReconnect(
|
|
|
1147
1178
|
});
|
|
1148
1179
|
}
|
|
1149
1180
|
|
|
1181
|
+
/**
|
|
1182
|
+
* Post into a joined room and return the frame's clientMsgId (what MESSAGE
|
|
1183
|
+
* echoes carry back for optimistic-send reconciliation). `clientMsgId` is
|
|
1184
|
+
* caller-suppliable so an offline send queue can retry one logical message
|
|
1185
|
+
* under one stable id (same contract as sayRoom / sendRoomDmOnClient);
|
|
1186
|
+
* omitted, it mints a UUID exactly as before. The relay validates the id
|
|
1187
|
+
* (1..128 chars after trim); dedupe on (userId, clientMsgId) is server-side
|
|
1188
|
+
* work and NOT implied here.
|
|
1189
|
+
*/
|
|
1150
1190
|
export function postRoomMessage(
|
|
1151
1191
|
client: RoomWsClient,
|
|
1152
1192
|
room: string,
|
|
@@ -1154,21 +1194,22 @@ export function postRoomMessage(
|
|
|
1154
1194
|
inReplyTo?: number,
|
|
1155
1195
|
attachments?: RoomAttachmentInput[],
|
|
1156
1196
|
topicId?: string,
|
|
1197
|
+
clientMsgId?: string,
|
|
1157
1198
|
): string {
|
|
1158
|
-
const
|
|
1199
|
+
const msgId = clientMsgId ?? randomUUID();
|
|
1159
1200
|
client.send({
|
|
1160
1201
|
type: RoomClientMessageType.POST,
|
|
1161
1202
|
payload: {
|
|
1162
1203
|
room,
|
|
1163
1204
|
...(text ? { text } : {}),
|
|
1164
1205
|
...(attachments?.length ? { attachments: toRoomAttachmentPayloads(attachments) } : {}),
|
|
1165
|
-
clientMsgId,
|
|
1206
|
+
clientMsgId: msgId,
|
|
1166
1207
|
...(inReplyTo !== undefined ? { inReplyTo } : {}),
|
|
1167
1208
|
...(topicId ? { topicId } : {}),
|
|
1168
1209
|
},
|
|
1169
1210
|
timestamp: Date.now(),
|
|
1170
1211
|
});
|
|
1171
|
-
return
|
|
1212
|
+
return msgId;
|
|
1172
1213
|
}
|
|
1173
1214
|
|
|
1174
1215
|
export function sendRoomTyping(client: RoomWsClient, room: string, state: "start" | "stop"): void {
|
|
@@ -1184,10 +1225,17 @@ export function sendRoomStatus(
|
|
|
1184
1225
|
client: RoomWsClient,
|
|
1185
1226
|
status: RoomUserStatus,
|
|
1186
1227
|
statusText?: string | null,
|
|
1228
|
+
platform?: RoomClientPlatform,
|
|
1187
1229
|
): void {
|
|
1188
1230
|
client.send({
|
|
1189
1231
|
type: RoomClientMessageType.STATUS,
|
|
1190
|
-
payload: {
|
|
1232
|
+
payload: {
|
|
1233
|
+
status,
|
|
1234
|
+
...(statusText !== undefined ? { statusText } : {}),
|
|
1235
|
+
// Session identity, declared once per connection (or on change): the
|
|
1236
|
+
// relay carries it onto presence member entries.
|
|
1237
|
+
...(platform ? { platform } : {}),
|
|
1238
|
+
},
|
|
1191
1239
|
timestamp: Date.now(),
|
|
1192
1240
|
});
|
|
1193
1241
|
}
|
|
@@ -1393,11 +1441,12 @@ export async function setRoomStatusOnce(
|
|
|
1393
1441
|
config: RoomClientConfig,
|
|
1394
1442
|
status: RoomUserStatus,
|
|
1395
1443
|
statusText?: string | null,
|
|
1444
|
+
platform?: RoomClientPlatform,
|
|
1396
1445
|
): Promise<void> {
|
|
1397
1446
|
const client = new RoomWsClient(config);
|
|
1398
1447
|
try {
|
|
1399
1448
|
await client.connect();
|
|
1400
|
-
sendRoomStatus(client, status, statusText);
|
|
1449
|
+
sendRoomStatus(client, status, statusText, platform);
|
|
1401
1450
|
// STATUS has no ack frame: give the socket a beat to flush before close.
|
|
1402
1451
|
await new Promise((resolve) => setTimeout(resolve, 200));
|
|
1403
1452
|
} finally {
|
|
@@ -1405,6 +1454,33 @@ export async function setRoomStatusOnce(
|
|
|
1405
1454
|
}
|
|
1406
1455
|
}
|
|
1407
1456
|
|
|
1457
|
+
/**
|
|
1458
|
+
* Set the caller's room-level attention (notification posture) on a live
|
|
1459
|
+
* client. The relay validates room participation, persists through the
|
|
1460
|
+
* store, and acks with a READ_STATE frame scoped to this room whose
|
|
1461
|
+
* attention map carries the persisted value (readState stays empty: cursors
|
|
1462
|
+
* are untouched). Private per-user state; nothing broadcasts.
|
|
1463
|
+
*/
|
|
1464
|
+
export async function setRoomAttentionOnClient(
|
|
1465
|
+
client: RoomWsClient,
|
|
1466
|
+
request: { room: string; attention: RoomTopicAttention },
|
|
1467
|
+
): Promise<RoomReadStatePayload> {
|
|
1468
|
+
const requestId = randomUUID();
|
|
1469
|
+
const room = normalizeRoomName(request.room);
|
|
1470
|
+
client.send({
|
|
1471
|
+
type: RoomClientMessageType.ROOM_SET_ATTENTION,
|
|
1472
|
+
payload: { requestId, room, attention: request.attention },
|
|
1473
|
+
timestamp: Date.now(),
|
|
1474
|
+
});
|
|
1475
|
+
const result = await client.waitFor(
|
|
1476
|
+
RoomServerMessageType.READ_STATE,
|
|
1477
|
+
(msg) => msg.payload.requestId === requestId,
|
|
1478
|
+
undefined,
|
|
1479
|
+
requestId,
|
|
1480
|
+
);
|
|
1481
|
+
return result.payload;
|
|
1482
|
+
}
|
|
1483
|
+
|
|
1408
1484
|
/** One-shot session helper for the config-based mutation verbs below (the
|
|
1409
1485
|
* agent tools' transport: connect, join, act, wait for the echo, close). */
|
|
1410
1486
|
async function withRoomEcho(
|
|
@@ -48,6 +48,7 @@ export const RoomClientMessageType = {
|
|
|
48
48
|
TOPIC_RESOLVE: "TOPIC_RESOLVE",
|
|
49
49
|
TOPIC_SET_ATTENTION: "TOPIC_SET_ATTENTION",
|
|
50
50
|
TOPIC_LIST: "TOPIC_LIST",
|
|
51
|
+
ROOM_SET_ATTENTION: "ROOM_SET_ATTENTION",
|
|
51
52
|
} as const;
|
|
52
53
|
|
|
53
54
|
export type RoomClientMessageType =
|
|
@@ -152,6 +153,9 @@ export type RoomRole = "owner" | "admin" | "mod" | "member";
|
|
|
152
153
|
* semantics of an absent value). */
|
|
153
154
|
export type RoomTopicsPolicy = "off" | "allowed" | "required";
|
|
154
155
|
export type RoomTopicAttention = "follow" | "default" | "mute";
|
|
156
|
+
/** Self-declared client class on STATUS frames; presence member entries
|
|
157
|
+
* carry it through so rosters can render where someone is connected from. */
|
|
158
|
+
export type RoomClientPlatform = "web" | "desktop" | "mobile" | "tui";
|
|
155
159
|
|
|
156
160
|
export interface RoomMember {
|
|
157
161
|
userId: string;
|
|
@@ -166,6 +170,8 @@ export interface RoomMember {
|
|
|
166
170
|
joinedAt: number;
|
|
167
171
|
avatarUrl?: string | null;
|
|
168
172
|
statusText?: string | null;
|
|
173
|
+
/** Present when the member's session declared one via STATUS. */
|
|
174
|
+
platform?: RoomClientPlatform | undefined;
|
|
169
175
|
}
|
|
170
176
|
|
|
171
177
|
export interface RoomMeta {
|
|
@@ -191,6 +197,10 @@ export interface RoomMeta {
|
|
|
191
197
|
* 2026-07-12 dial-default flip (post-flip relays always advertise the
|
|
192
198
|
* stored value, "off" included); explicit "off" means topics are inert. */
|
|
193
199
|
topicsPolicy?: RoomTopicsPolicy | undefined;
|
|
200
|
+
/** The viewer's room attention (notification posture), a per-viewer field
|
|
201
|
+
* like viewerRole: surfaced on rooms listings for the caller. Absent
|
|
202
|
+
* reads as "default". */
|
|
203
|
+
attention?: RoomTopicAttention | undefined;
|
|
194
204
|
tags?: string[] | undefined;
|
|
195
205
|
entities?: string[] | undefined;
|
|
196
206
|
sourceRefs?: Array<Record<string, unknown>> | undefined;
|
|
@@ -331,7 +341,12 @@ export interface RoomPinsPayload {
|
|
|
331
341
|
}
|
|
332
342
|
|
|
333
343
|
export interface RoomReadStatePayload {
|
|
344
|
+
/** Partial map: rooms absent from a reply are unchanged. */
|
|
334
345
|
readState: Record<string, number>;
|
|
346
|
+
/** Per-room attention for the requesting user, keyed like readState.
|
|
347
|
+
* Present when the store surfaces it and on ROOM_SET_ATTENTION acks
|
|
348
|
+
* (which reply READ_STATE scoped to the one room, readState empty). */
|
|
349
|
+
attention?: Record<string, RoomTopicAttention> | undefined;
|
|
335
350
|
requestId?: string | undefined;
|
|
336
351
|
}
|
|
337
352
|
|
|
@@ -659,6 +674,7 @@ export interface RoomDmMessagePayload {
|
|
|
659
674
|
}
|
|
660
675
|
|
|
661
676
|
export interface RoomDmInboxUpdatedPayload {
|
|
677
|
+
requestId?: string;
|
|
662
678
|
conversationId: string;
|
|
663
679
|
participant: RoomDmParticipant;
|
|
664
680
|
unreadCount: number;
|
|
@@ -862,6 +878,16 @@ export interface RoomTopicSetAttentionPayload {
|
|
|
862
878
|
attention: RoomTopicAttention;
|
|
863
879
|
}
|
|
864
880
|
|
|
881
|
+
/** Room-level attention (notification posture). Private per-user state on
|
|
882
|
+
* the caller's read row; topic attention wins for topic-scoped messages
|
|
883
|
+
* and room attention wins over space attention. The relay acks with a
|
|
884
|
+
* READ_STATE frame scoped to the room (see RoomReadStatePayload). */
|
|
885
|
+
export interface RoomSetAttentionPayload {
|
|
886
|
+
requestId?: string;
|
|
887
|
+
room: string;
|
|
888
|
+
attention: RoomTopicAttention;
|
|
889
|
+
}
|
|
890
|
+
|
|
865
891
|
export interface RoomTopicListPayload {
|
|
866
892
|
requestId?: string;
|
|
867
893
|
room: string;
|
|
@@ -1129,7 +1155,11 @@ export type RoomClientMessage =
|
|
|
1129
1155
|
}
|
|
1130
1156
|
| {
|
|
1131
1157
|
type: typeof RoomClientMessageType.STATUS;
|
|
1132
|
-
payload: {
|
|
1158
|
+
payload: {
|
|
1159
|
+
status: RoomUserStatus;
|
|
1160
|
+
statusText?: string | null;
|
|
1161
|
+
platform?: RoomClientPlatform;
|
|
1162
|
+
};
|
|
1133
1163
|
timestamp?: number;
|
|
1134
1164
|
}
|
|
1135
1165
|
| {
|
|
@@ -1213,6 +1243,11 @@ export type RoomClientMessage =
|
|
|
1213
1243
|
type: typeof RoomClientMessageType.TOPIC_LIST;
|
|
1214
1244
|
payload: RoomTopicListPayload;
|
|
1215
1245
|
timestamp?: number;
|
|
1246
|
+
}
|
|
1247
|
+
| {
|
|
1248
|
+
type: typeof RoomClientMessageType.ROOM_SET_ATTENTION;
|
|
1249
|
+
payload: RoomSetAttentionPayload;
|
|
1250
|
+
timestamp?: number;
|
|
1216
1251
|
};
|
|
1217
1252
|
|
|
1218
1253
|
export type RoomServerMessage =
|
package/src/social-client.ts
CHANGED
|
@@ -657,7 +657,8 @@ export async function listRoomSpacesViaChat(config: RoomSocialConfig): Promise<R
|
|
|
657
657
|
|
|
658
658
|
export interface RoomSpaceMember {
|
|
659
659
|
userId: string;
|
|
660
|
-
role
|
|
660
|
+
/** The ladder role. 'librarian' maintains the generated briefs/ docs. */
|
|
661
|
+
role: "owner" | "admin" | "librarian" | "member";
|
|
661
662
|
/** Named identity roles (RoomSpaceRole.roleId). */
|
|
662
663
|
roleIds?: string[];
|
|
663
664
|
joinedAt?: string;
|
|
@@ -1047,7 +1048,7 @@ export async function changeSpaceMemberRole(
|
|
|
1047
1048
|
config: RoomSocialConfig,
|
|
1048
1049
|
spaceId: string,
|
|
1049
1050
|
targetUserId: string,
|
|
1050
|
-
role: "admin" | "member",
|
|
1051
|
+
role: "admin" | "librarian" | "member",
|
|
1051
1052
|
): Promise<RoomSpaceMember> {
|
|
1052
1053
|
const result = await socialRequest<{ member: RoomSpaceMember }>(
|
|
1053
1054
|
config,
|
package/src/social-types.ts
CHANGED
|
@@ -144,6 +144,9 @@ export interface RoomDmMessage {
|
|
|
144
144
|
imageUrl?: string | null;
|
|
145
145
|
/** Aggregated reactions (per-emoji userId lists). Additive. */
|
|
146
146
|
reactions?: Array<{ emoji: string; users: string[] }>;
|
|
147
|
+
/** Client-minted idempotency tag echoed back on DM sends, so a sender's
|
|
148
|
+
* durable queue can settle its optimistic row. Additive (0.4.0). */
|
|
149
|
+
clientMsgId?: string;
|
|
147
150
|
}
|
|
148
151
|
|
|
149
152
|
export interface RoomDmHistory {
|
package/src/types.ts
CHANGED
|
@@ -8,6 +8,7 @@ export type {
|
|
|
8
8
|
RoomAuthSuccessPayload,
|
|
9
9
|
RoomBackfillPayload,
|
|
10
10
|
RoomClientMessage,
|
|
11
|
+
RoomClientPlatform,
|
|
11
12
|
RoomCreatedPayload,
|
|
12
13
|
RoomCreatePayload,
|
|
13
14
|
RoomDmHistoryPayload,
|
|
@@ -50,6 +51,7 @@ export type {
|
|
|
50
51
|
RoomSearchScope,
|
|
51
52
|
RoomServerMessage,
|
|
52
53
|
RoomServerMessageOf,
|
|
54
|
+
RoomSetAttentionPayload,
|
|
53
55
|
RoomSetReadOnlyPayload,
|
|
54
56
|
RoomSpace,
|
|
55
57
|
RoomSpaceJoinedPayload,
|
package/src/version.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export const VERSION = "0.
|
|
2
|
-
export const RUNNER_VERSION = "0.
|
|
1
|
+
export const VERSION = "0.6.0";
|
|
2
|
+
export const RUNNER_VERSION = "0.6.0";
|