@omg-dev/protocol 0.6.136 → 0.6.138
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/session-mention-token.d.ts +73 -0
- package/dist/session-mention-token.d.ts.map +1 -1
- package/dist/session-mention-token.js +161 -0
- package/dist/session-mention-token.js.map +1 -1
- package/dist/threads.d.ts +146 -0
- package/dist/threads.d.ts.map +1 -0
- package/dist/threads.js +172 -0
- package/dist/threads.js.map +1 -0
- package/package.json +1 -1
|
@@ -36,4 +36,77 @@ export declare function formatSessionMentionToken(sessionId: string, title: stri
|
|
|
36
36
|
export declare function sessionRefFromHref(href: string): string | null;
|
|
37
37
|
/** Every reference in `text`, first-appearance order, one entry per session. */
|
|
38
38
|
export declare function parseSessionMentions(text: string): ParsedSessionMention[];
|
|
39
|
+
/**
|
|
40
|
+
* Agents quote a session as a bare short id in inline code (`228efabd`),
|
|
41
|
+
* because that is the form every omg.dev tool returns. The `omg:session_`
|
|
42
|
+
* href for such a span, or null when the text is not a session id. Only the
|
|
43
|
+
* exact 8-hex short form or a full UUID qualifies: anything looser would
|
|
44
|
+
* turn ordinary code into links. A span that looks right but names no
|
|
45
|
+
* session (an 8-char git sha) resolves to nothing, so the tap does nothing.
|
|
46
|
+
*/
|
|
47
|
+
export declare function sessionHrefFromCodespan(text: string): string | null;
|
|
48
|
+
export type SessionIds = {
|
|
49
|
+
sessionId?: string | null;
|
|
50
|
+
nativeSessionId?: string | null;
|
|
51
|
+
/** Shown in place of a bare id when a reference is rendered. */
|
|
52
|
+
title?: string | null;
|
|
53
|
+
/** Agent kind, for the icon on a rendered reference. */
|
|
54
|
+
agent?: string | null;
|
|
55
|
+
/** Project name, shown as a badge on a rendered reference. */
|
|
56
|
+
project?: string | null;
|
|
57
|
+
};
|
|
58
|
+
/** What a rendered reference shows. Stable per ref, so React can compare it. */
|
|
59
|
+
export type SessionRefLabel = {
|
|
60
|
+
title: string | null;
|
|
61
|
+
agent: string | null;
|
|
62
|
+
project: string | null;
|
|
63
|
+
};
|
|
64
|
+
/** The subset of OmgClient a reference lookup needs, so tests can fake it. */
|
|
65
|
+
export type SessionRefClient = {
|
|
66
|
+
peekSessions(): SessionIds[] | null;
|
|
67
|
+
listSessions(): Promise<SessionIds[]>;
|
|
68
|
+
transport: {
|
|
69
|
+
request<T>(path: string, init?: RequestInit): Promise<T>;
|
|
70
|
+
};
|
|
71
|
+
};
|
|
72
|
+
/**
|
|
73
|
+
* The one session in `list` that `ref` names. Null when nothing or more than
|
|
74
|
+
* one session matches: a guess would open the wrong transcript.
|
|
75
|
+
*/
|
|
76
|
+
export declare function findSessionRef(ref: string, list: SessionIds[] | null): SessionIds | null;
|
|
77
|
+
/** Full id for a short ref within `list`, or null (see `findSessionRef`). */
|
|
78
|
+
export declare function resolveSessionRef(ref: string, list: SessionIds[] | null): string | null;
|
|
79
|
+
/**
|
|
80
|
+
* The same ladder omg.dev's MCP layer climbs for an agent-facing short id:
|
|
81
|
+
* the sessions already in hand, then the live list, then the durable
|
|
82
|
+
* catalog. Each rung is skipped once a rung below has answered.
|
|
83
|
+
*/
|
|
84
|
+
export declare function lookupSessionRefWith(client: SessionRefClient, ref: string): Promise<SessionIds | null>;
|
|
85
|
+
export declare function resolveSessionRefWith(client: SessionRefClient, ref: string): Promise<string | null>;
|
|
86
|
+
/**
|
|
87
|
+
* The tap handler for a rendered reference, with the router injected.
|
|
88
|
+
*
|
|
89
|
+
* The lookup is asynchronous and the app can switch machine or sign out
|
|
90
|
+
* while it runs. An answer is only acted on when the client it came from is
|
|
91
|
+
* still the registered one: a session id from the previous box must never
|
|
92
|
+
* be pushed onto the new one. Every failure is swallowed here, because a
|
|
93
|
+
* markdown tap has nowhere to report and an unhandled rejection is worse
|
|
94
|
+
* than a tap that does nothing.
|
|
95
|
+
*/
|
|
96
|
+
export declare function createSessionRefOpener(deps: {
|
|
97
|
+
navigate: (sessionId: string) => void;
|
|
98
|
+
resolve?: (client: SessionRefClient, ref: string) => Promise<string | null>;
|
|
99
|
+
lookup?: (client: SessionRefClient, ref: string) => Promise<SessionIds | null>;
|
|
100
|
+
}): {
|
|
101
|
+
register(client: SessionRefClient | null): void;
|
|
102
|
+
/** True when `href` was a session reference and has been taken over. */
|
|
103
|
+
open(href: string): boolean;
|
|
104
|
+
/**
|
|
105
|
+
* Title and agent for `ref`, or null while unknown. The first call for a
|
|
106
|
+
* ref starts one lookup; `subscribe` fires when it lands. A ref that names
|
|
107
|
+
* no session stays null so the caller keeps showing the id.
|
|
108
|
+
*/
|
|
109
|
+
label(ref: string): SessionRefLabel | null;
|
|
110
|
+
subscribe(listener: () => void): () => void;
|
|
111
|
+
};
|
|
39
112
|
//# sourceMappingURL=session-mention-token.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session-mention-token.d.ts","sourceRoot":"","sources":["../src/session-mention-token.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAMH,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAEzD;AAED,+EAA+E;AAC/E,wBAAgB,qBAAqB,IAAI,MAAM,CAE9C;AAED,MAAM,MAAM,oBAAoB,GAAG;IACjC,yEAAyE;IACzE,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,mEAAmE;AACnE,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAE1D;AAED,wBAAgB,yBAAyB,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAIlF;AAED,+EAA+E;AAC/E,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAG9D;AAED,gFAAgF;AAChF,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,oBAAoB,EAAE,CAWzE"}
|
|
1
|
+
{"version":3,"file":"session-mention-token.d.ts","sourceRoot":"","sources":["../src/session-mention-token.ts"],"names":[],"mappings":"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"}
|
|
@@ -60,4 +60,165 @@ export function parseSessionMentions(text) {
|
|
|
60
60
|
}
|
|
61
61
|
return out;
|
|
62
62
|
}
|
|
63
|
+
/**
|
|
64
|
+
* Agents quote a session as a bare short id in inline code (`228efabd`),
|
|
65
|
+
* because that is the form every omg.dev tool returns. The `omg:session_`
|
|
66
|
+
* href for such a span, or null when the text is not a session id. Only the
|
|
67
|
+
* exact 8-hex short form or a full UUID qualifies: anything looser would
|
|
68
|
+
* turn ordinary code into links. A span that looks right but names no
|
|
69
|
+
* session (an 8-char git sha) resolves to nothing, so the tap does nothing.
|
|
70
|
+
*/
|
|
71
|
+
export function sessionHrefFromCodespan(text) {
|
|
72
|
+
const t = text.trim();
|
|
73
|
+
if (/^[0-9a-f]{8}$/i.test(t))
|
|
74
|
+
return `omg:session_${t}`;
|
|
75
|
+
if (/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(t)) {
|
|
76
|
+
return `omg:session_${t}`;
|
|
77
|
+
}
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* The one session in `list` that `ref` names. Null when nothing or more than
|
|
82
|
+
* one session matches: a guess would open the wrong transcript.
|
|
83
|
+
*/
|
|
84
|
+
export function findSessionRef(ref, list) {
|
|
85
|
+
const lower = ref.toLowerCase();
|
|
86
|
+
const matches = new Map();
|
|
87
|
+
for (const session of list ?? []) {
|
|
88
|
+
for (const candidate of [session.sessionId, session.nativeSessionId]) {
|
|
89
|
+
if (candidate && candidate.toLowerCase().startsWith(lower)) {
|
|
90
|
+
matches.set(session.sessionId ?? candidate, session);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
if (matches.size !== 1)
|
|
95
|
+
return null;
|
|
96
|
+
const [[id, session]] = [...matches];
|
|
97
|
+
return { ...session, sessionId: id };
|
|
98
|
+
}
|
|
99
|
+
/** Full id for a short ref within `list`, or null (see `findSessionRef`). */
|
|
100
|
+
export function resolveSessionRef(ref, list) {
|
|
101
|
+
return findSessionRef(ref, list)?.sessionId ?? null;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* The same ladder omg.dev's MCP layer climbs for an agent-facing short id:
|
|
105
|
+
* the sessions already in hand, then the live list, then the durable
|
|
106
|
+
* catalog. Each rung is skipped once a rung below has answered.
|
|
107
|
+
*/
|
|
108
|
+
export async function lookupSessionRefWith(client, ref) {
|
|
109
|
+
const peeked = findSessionRef(ref, client.peekSessions());
|
|
110
|
+
if (peeked)
|
|
111
|
+
return peeked;
|
|
112
|
+
const listed = await client.listSessions().catch(() => null);
|
|
113
|
+
const live = findSessionRef(ref, listed);
|
|
114
|
+
if (live)
|
|
115
|
+
return live;
|
|
116
|
+
const found = await client.transport
|
|
117
|
+
.request("/api/sessions/find", {
|
|
118
|
+
method: "POST",
|
|
119
|
+
headers: { "Content-Type": "application/json" },
|
|
120
|
+
body: JSON.stringify({ sessionId: ref, limit: 5 }),
|
|
121
|
+
})
|
|
122
|
+
.catch(() => null);
|
|
123
|
+
return findSessionRef(ref, found?.sessions ?? null);
|
|
124
|
+
}
|
|
125
|
+
export async function resolveSessionRefWith(client, ref) {
|
|
126
|
+
return (await lookupSessionRefWith(client, ref))?.sessionId ?? null;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* The tap handler for a rendered reference, with the router injected.
|
|
130
|
+
*
|
|
131
|
+
* The lookup is asynchronous and the app can switch machine or sign out
|
|
132
|
+
* while it runs. An answer is only acted on when the client it came from is
|
|
133
|
+
* still the registered one: a session id from the previous box must never
|
|
134
|
+
* be pushed onto the new one. Every failure is swallowed here, because a
|
|
135
|
+
* markdown tap has nowhere to report and an unhandled rejection is worse
|
|
136
|
+
* than a tap that does nothing.
|
|
137
|
+
*/
|
|
138
|
+
export function createSessionRefOpener(deps) {
|
|
139
|
+
const resolve = deps.resolve ?? resolveSessionRefWith;
|
|
140
|
+
const lookup = deps.lookup ?? lookupSessionRefWith;
|
|
141
|
+
let current = null;
|
|
142
|
+
let generation = 0;
|
|
143
|
+
// Titles belong to the registered client: a switch clears them.
|
|
144
|
+
let labels = new Map();
|
|
145
|
+
const toLabel = (session) => session
|
|
146
|
+
? {
|
|
147
|
+
title: session.title?.trim() || null,
|
|
148
|
+
agent: session.agent?.trim() || null,
|
|
149
|
+
project: session.project?.trim() || null,
|
|
150
|
+
}
|
|
151
|
+
: null;
|
|
152
|
+
const pending = new Set();
|
|
153
|
+
const listeners = new Set();
|
|
154
|
+
const notify = () => {
|
|
155
|
+
for (const listener of listeners)
|
|
156
|
+
listener();
|
|
157
|
+
};
|
|
158
|
+
return {
|
|
159
|
+
register(client) {
|
|
160
|
+
generation += 1;
|
|
161
|
+
current = client;
|
|
162
|
+
const hadLabels = labels.size > 0;
|
|
163
|
+
labels = new Map();
|
|
164
|
+
pending.clear();
|
|
165
|
+
// A reader can trigger registration from inside a render. Tell
|
|
166
|
+
// subscribers later, and only when titles were actually dropped.
|
|
167
|
+
if (hadLabels)
|
|
168
|
+
queueMicrotask(notify);
|
|
169
|
+
},
|
|
170
|
+
label(ref) {
|
|
171
|
+
const key = ref.toLowerCase();
|
|
172
|
+
if (labels.has(key))
|
|
173
|
+
return labels.get(key) ?? null;
|
|
174
|
+
const client = current;
|
|
175
|
+
if (!client)
|
|
176
|
+
return null;
|
|
177
|
+
const known = findSessionRef(ref, client.peekSessions());
|
|
178
|
+
if (known) {
|
|
179
|
+
const found = toLabel(known);
|
|
180
|
+
labels.set(key, found);
|
|
181
|
+
return found;
|
|
182
|
+
}
|
|
183
|
+
if (pending.has(key))
|
|
184
|
+
return null;
|
|
185
|
+
pending.add(key);
|
|
186
|
+
const startedAt = generation;
|
|
187
|
+
Promise.resolve()
|
|
188
|
+
.then(() => lookup(client, ref))
|
|
189
|
+
.catch(() => null)
|
|
190
|
+
.then((session) => {
|
|
191
|
+
if (current !== client || generation !== startedAt)
|
|
192
|
+
return;
|
|
193
|
+
pending.delete(key);
|
|
194
|
+
labels.set(key, toLabel(session));
|
|
195
|
+
notify();
|
|
196
|
+
});
|
|
197
|
+
return null;
|
|
198
|
+
},
|
|
199
|
+
subscribe(listener) {
|
|
200
|
+
listeners.add(listener);
|
|
201
|
+
return () => {
|
|
202
|
+
listeners.delete(listener);
|
|
203
|
+
};
|
|
204
|
+
},
|
|
205
|
+
open(href) {
|
|
206
|
+
const ref = sessionRefFromHref(href);
|
|
207
|
+
if (!ref)
|
|
208
|
+
return false;
|
|
209
|
+
const client = current;
|
|
210
|
+
if (!client)
|
|
211
|
+
return true;
|
|
212
|
+
const startedAt = generation;
|
|
213
|
+
Promise.resolve()
|
|
214
|
+
.then(() => resolve(client, ref))
|
|
215
|
+
.then((full) => {
|
|
216
|
+
if (full && current === client && generation === startedAt)
|
|
217
|
+
deps.navigate(full);
|
|
218
|
+
})
|
|
219
|
+
.catch(() => { });
|
|
220
|
+
return true;
|
|
221
|
+
},
|
|
222
|
+
};
|
|
223
|
+
}
|
|
63
224
|
//# sourceMappingURL=session-mention-token.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session-mention-token.js","sourceRoot":"","sources":["../src/session-mention-token.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,MAAM,SAAS,GAAG,CAAC,CAAC;AACpB,MAAM,SAAS,GAAG,+EAA+E,CAAC;AAClG,MAAM,WAAW,GAAG,sBAAsB,CAAC;AAE3C,MAAM,UAAU,eAAe,CAAC,SAAiB;IAC/C,OAAO,SAAS,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AAC/E,CAAC;AAED,+EAA+E;AAC/E,MAAM,UAAU,qBAAqB;IACnC,OAAO,IAAI,MAAM,CAAC,4CAA4C,WAAW,MAAM,EAAE,GAAG,CAAC,CAAC;AACxF,CAAC;AAQD,mEAAmE;AACnE,MAAM,UAAU,oBAAoB,CAAC,KAAa;IAChD,OAAO,KAAK,CAAC,OAAO,CAAC,cAAc,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;AACxE,CAAC;AAED,MAAM,UAAU,yBAAyB,CAAC,SAAiB,EAAE,KAAa;IACxE,MAAM,GAAG,GAAG,eAAe,CAAC,SAAS,CAAC,CAAC;IACvC,MAAM,KAAK,GAAG,oBAAoB,CAAC,KAAK,CAAC,IAAI,GAAG,CAAC;IACjD,OAAO,KAAK,KAAK,iBAAiB,GAAG,GAAG,CAAC;AAC3C,CAAC;AAED,+EAA+E;AAC/E,MAAM,UAAU,kBAAkB,CAAC,IAAY;IAC7C,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,MAAM,CAAC,iBAAiB,WAAW,IAAI,CAAC,CAAC,CAAC;IACvE,OAAO,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AACjC,CAAC;AAED,gFAAgF;AAChF,MAAM,UAAU,oBAAoB,CAAC,IAAY;IAC/C,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,gBAAgB,CAAC;QAAE,OAAO,EAAE,CAAC;IACzD,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,MAAM,GAAG,GAA2B,EAAE,CAAC;IACvC,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,QAAQ,CAAC,qBAAqB,EAAE,CAAC,EAAE,CAAC;QAC3D,MAAM,UAAU,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QAC5B,IAAI,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC;YAAE,SAAS;QACnC,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QACrB,GAAG,CAAC,IAAI,CAAC,EAAE,UAAU,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IAC5C,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}
|
|
1
|
+
{"version":3,"file":"session-mention-token.js","sourceRoot":"","sources":["../src/session-mention-token.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Threads on the wire, and the rules every client draws them with.
|
|
3
|
+
*
|
|
4
|
+
* One owner for the server (src/threads.ts), iOS and the web app. A thread is
|
|
5
|
+
* people-first chat with no agent behind it; omg joins only on `@omg`, and a
|
|
6
|
+
* task it starts is drawn as a card whose state is decided by
|
|
7
|
+
* `taskCardState` below. Keeping that rule here is what stops the phone and
|
|
8
|
+
* the web from disagreeing about whether a task "needs you".
|
|
9
|
+
*/
|
|
10
|
+
export type ThreadAuthor = {
|
|
11
|
+
kind: "human";
|
|
12
|
+
participantId: string;
|
|
13
|
+
name: string;
|
|
14
|
+
} | {
|
|
15
|
+
kind: "omg";
|
|
16
|
+
};
|
|
17
|
+
export type ThreadTaskEvent = "started" | "finished" | "blocked" | "failed";
|
|
18
|
+
export type ThreadMessage = {
|
|
19
|
+
id: string;
|
|
20
|
+
threadId: string;
|
|
21
|
+
ts: number;
|
|
22
|
+
author: ThreadAuthor;
|
|
23
|
+
text: string;
|
|
24
|
+
/** Present on omg's task messages: which task, and what happened to it. */
|
|
25
|
+
task?: {
|
|
26
|
+
sessionId: string;
|
|
27
|
+
event: ThreadTaskEvent;
|
|
28
|
+
title?: string | null;
|
|
29
|
+
project?: string | null;
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* The top-level message this is a reply to, as in Slack. omg always answers
|
|
33
|
+
* in the replies of the message that mentioned it, and a task's updates go
|
|
34
|
+
* to the same replies. Absent: a top-level message.
|
|
35
|
+
*/
|
|
36
|
+
replyTo?: string | null;
|
|
37
|
+
/** Client only: sent, not yet stored. */
|
|
38
|
+
pending?: boolean;
|
|
39
|
+
};
|
|
40
|
+
export type ThreadProject = {
|
|
41
|
+
cwd: string;
|
|
42
|
+
name: string;
|
|
43
|
+
};
|
|
44
|
+
export type ThreadSummary = {
|
|
45
|
+
id: string;
|
|
46
|
+
title: string;
|
|
47
|
+
createdAt: number;
|
|
48
|
+
updatedAt: number;
|
|
49
|
+
project: ThreadProject | null;
|
|
50
|
+
lastMessage: Pick<ThreadMessage, "author" | "text" | "ts"> | null;
|
|
51
|
+
};
|
|
52
|
+
export type ThreadTaskRow = {
|
|
53
|
+
sessionId: string;
|
|
54
|
+
title: string | null;
|
|
55
|
+
project: string | null;
|
|
56
|
+
busy: boolean;
|
|
57
|
+
status: string | null;
|
|
58
|
+
/** Not in the live session list any more. */
|
|
59
|
+
ended: boolean;
|
|
60
|
+
};
|
|
61
|
+
export type ThreadParticipant = {
|
|
62
|
+
id: string;
|
|
63
|
+
kind: string;
|
|
64
|
+
role?: string;
|
|
65
|
+
display: {
|
|
66
|
+
name?: string | null;
|
|
67
|
+
fallback: string;
|
|
68
|
+
};
|
|
69
|
+
};
|
|
70
|
+
export type ThreadDetail = {
|
|
71
|
+
/** The caller's participant id, so a client can put their own bubbles on the right. */
|
|
72
|
+
me: string;
|
|
73
|
+
thread: ThreadSummary;
|
|
74
|
+
participants: ThreadParticipant[];
|
|
75
|
+
messages: ThreadMessage[];
|
|
76
|
+
tasks: ThreadTaskRow[];
|
|
77
|
+
};
|
|
78
|
+
export type TaskCardState = "working" | "needs-you" | "done" | "failed" | "ended";
|
|
79
|
+
export declare const TASK_STATE_LABEL: Record<TaskCardState, string>;
|
|
80
|
+
/** Only an explicit mention wakes omg. An address like x@omg.dev does not. */
|
|
81
|
+
export declare const OMG_MENTION: RegExp;
|
|
82
|
+
export declare function mentionsOmg(text: string): boolean;
|
|
83
|
+
/** The same id in either form: a full uuid or a short prefix. */
|
|
84
|
+
export declare function sameSession(a: string | null | undefined, b: string | null | undefined): boolean;
|
|
85
|
+
/** The newest event omg posted for a task. */
|
|
86
|
+
export declare function latestTaskEvent(messages: readonly ThreadMessage[], sessionId: string): ThreadTaskEvent | null;
|
|
87
|
+
/**
|
|
88
|
+
* A question waiting on the person wins over everything but a running turn.
|
|
89
|
+
* Then the live row: busy is working. An idle task is done once it has
|
|
90
|
+
* reported and working until then; a task gone from the list is its last
|
|
91
|
+
* report, or "ended".
|
|
92
|
+
*/
|
|
93
|
+
export declare function taskCardState(input: {
|
|
94
|
+
event: ThreadTaskEvent | null;
|
|
95
|
+
row: ThreadTaskRow | null | undefined;
|
|
96
|
+
openAsk: boolean;
|
|
97
|
+
}): TaskCardState;
|
|
98
|
+
/**
|
|
99
|
+
* Which messages draw a card. Each task is drawn once, at the message that
|
|
100
|
+
* started it; later messages about the same task are plain omg messages,
|
|
101
|
+
* because the card above already shows the live state.
|
|
102
|
+
*/
|
|
103
|
+
export declare function cardMessageIds(messages: readonly ThreadMessage[]): Set<string>;
|
|
104
|
+
/** One line for a thread row: who spoke last, and what they said. */
|
|
105
|
+
export declare function threadPreview(thread: Pick<ThreadSummary, "lastMessage">): string;
|
|
106
|
+
/** The task a message is about, as the card needs it. Pure, for both clients. */
|
|
107
|
+
export declare function taskCardFor(message: ThreadMessage, detail: Pick<ThreadDetail, "tasks">, messages: readonly ThreadMessage[], openAskSessionIds: readonly (string | null | undefined)[]): {
|
|
108
|
+
sessionId: string;
|
|
109
|
+
title: string;
|
|
110
|
+
project: string | null;
|
|
111
|
+
state: TaskCardState;
|
|
112
|
+
} | null;
|
|
113
|
+
/** Slack's rule: a message joins the one above when the same author wrote it within this long. */
|
|
114
|
+
export declare const THREAD_GROUP_MS: number;
|
|
115
|
+
/**
|
|
116
|
+
* Whether a message starts a new group: its own avatar, name and time. The
|
|
117
|
+
* rest of a group is just text under the first message.
|
|
118
|
+
*/
|
|
119
|
+
export declare function startsMessageGroup(previous: ThreadMessage | undefined, message: ThreadMessage): boolean;
|
|
120
|
+
/** A stable avatar colour for a person, from their participant id. */
|
|
121
|
+
export declare function authorHue(author: ThreadAuthor): number;
|
|
122
|
+
export declare function authorName(author: ThreadAuthor): string;
|
|
123
|
+
/** Top-level messages: what the main list shows. */
|
|
124
|
+
export declare function topLevelMessages(messages: readonly ThreadMessage[]): ThreadMessage[];
|
|
125
|
+
/** The replies to one top-level message, oldest first. */
|
|
126
|
+
export declare function repliesTo(messages: readonly ThreadMessage[], rootId: string): ThreadMessage[];
|
|
127
|
+
export type ReplySummary = {
|
|
128
|
+
count: number;
|
|
129
|
+
lastTs: number;
|
|
130
|
+
/** Who replied, first reply first, each once. */
|
|
131
|
+
authors: ThreadAuthor[];
|
|
132
|
+
/** The task started in these replies, if any, for a state chip on the root. */
|
|
133
|
+
taskSessionId: string | null;
|
|
134
|
+
};
|
|
135
|
+
/** The "N replies" line under a top-level message, or null when it has none. */
|
|
136
|
+
export declare function replySummary(messages: readonly ThreadMessage[], rootId: string): ReplySummary | null;
|
|
137
|
+
/**
|
|
138
|
+
* Pull Home's list down past the refresh to start a thread. Distances in
|
|
139
|
+
* points (iOS) or CSS pixels (web). A normal refresh fires well before the
|
|
140
|
+
* first; the second arms the thread, and releasing then opens it.
|
|
141
|
+
*/
|
|
142
|
+
export declare const THREAD_PULL_HINT = 90;
|
|
143
|
+
export declare const THREAD_PULL_ARM = 150;
|
|
144
|
+
/** 0: nothing. 1: show "keep pulling". 2: armed, release starts a thread. */
|
|
145
|
+
export declare function threadPullStage(pull: number): 0 | 1 | 2;
|
|
146
|
+
//# sourceMappingURL=threads.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"threads.d.ts","sourceRoot":"","sources":["../src/threads.ts"],"names":[],"mappings":"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"}
|
package/dist/threads.js
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Threads on the wire, and the rules every client draws them with.
|
|
3
|
+
*
|
|
4
|
+
* One owner for the server (src/threads.ts), iOS and the web app. A thread is
|
|
5
|
+
* people-first chat with no agent behind it; omg joins only on `@omg`, and a
|
|
6
|
+
* task it starts is drawn as a card whose state is decided by
|
|
7
|
+
* `taskCardState` below. Keeping that rule here is what stops the phone and
|
|
8
|
+
* the web from disagreeing about whether a task "needs you".
|
|
9
|
+
*/
|
|
10
|
+
export const TASK_STATE_LABEL = {
|
|
11
|
+
working: "Working",
|
|
12
|
+
"needs-you": "Needs you",
|
|
13
|
+
done: "Done",
|
|
14
|
+
failed: "Failed",
|
|
15
|
+
ended: "Ended",
|
|
16
|
+
};
|
|
17
|
+
/** Only an explicit mention wakes omg. An address like x@omg.dev does not. */
|
|
18
|
+
export const OMG_MENTION = /(^|[^\w@])@omg\b/i;
|
|
19
|
+
export function mentionsOmg(text) {
|
|
20
|
+
return OMG_MENTION.test(text);
|
|
21
|
+
}
|
|
22
|
+
/** The same id in either form: a full uuid or a short prefix. */
|
|
23
|
+
export function sameSession(a, b) {
|
|
24
|
+
if (!a || !b)
|
|
25
|
+
return false;
|
|
26
|
+
const x = a.toLowerCase();
|
|
27
|
+
const y = b.toLowerCase();
|
|
28
|
+
return x === y || (x.length >= 8 && y.startsWith(x)) || (y.length >= 8 && x.startsWith(y));
|
|
29
|
+
}
|
|
30
|
+
/** The newest event omg posted for a task. */
|
|
31
|
+
export function latestTaskEvent(messages, sessionId) {
|
|
32
|
+
for (let i = messages.length - 1; i >= 0; i -= 1) {
|
|
33
|
+
const task = messages[i].task;
|
|
34
|
+
if (task && sameSession(task.sessionId, sessionId))
|
|
35
|
+
return task.event;
|
|
36
|
+
}
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* A question waiting on the person wins over everything but a running turn.
|
|
41
|
+
* Then the live row: busy is working. An idle task is done once it has
|
|
42
|
+
* reported and working until then; a task gone from the list is its last
|
|
43
|
+
* report, or "ended".
|
|
44
|
+
*/
|
|
45
|
+
export function taskCardState(input) {
|
|
46
|
+
const waiting = input.openAsk || input.row?.status === "blocked" || input.event === "blocked";
|
|
47
|
+
if (waiting && !input.row?.busy)
|
|
48
|
+
return "needs-you";
|
|
49
|
+
if (input.row?.busy)
|
|
50
|
+
return "working";
|
|
51
|
+
if (input.event === "failed")
|
|
52
|
+
return "failed";
|
|
53
|
+
if (input.event === "finished")
|
|
54
|
+
return "done";
|
|
55
|
+
if (input.row && !input.row.ended)
|
|
56
|
+
return "working";
|
|
57
|
+
return "ended";
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Which messages draw a card. Each task is drawn once, at the message that
|
|
61
|
+
* started it; later messages about the same task are plain omg messages,
|
|
62
|
+
* because the card above already shows the live state.
|
|
63
|
+
*/
|
|
64
|
+
export function cardMessageIds(messages) {
|
|
65
|
+
const seen = new Set();
|
|
66
|
+
const ids = new Set();
|
|
67
|
+
for (const message of messages) {
|
|
68
|
+
const task = message.task;
|
|
69
|
+
if (!task)
|
|
70
|
+
continue;
|
|
71
|
+
const key = task.sessionId.toLowerCase();
|
|
72
|
+
if (seen.has(key))
|
|
73
|
+
continue;
|
|
74
|
+
seen.add(key);
|
|
75
|
+
ids.add(message.id);
|
|
76
|
+
}
|
|
77
|
+
return ids;
|
|
78
|
+
}
|
|
79
|
+
/** One line for a thread row: who spoke last, and what they said. */
|
|
80
|
+
export function threadPreview(thread) {
|
|
81
|
+
const last = thread.lastMessage;
|
|
82
|
+
if (!last)
|
|
83
|
+
return "No messages yet";
|
|
84
|
+
const who = last.author.kind === "omg" ? "omg" : last.author.name;
|
|
85
|
+
return `${who}: ${last.text.replace(/\s+/g, " ").trim()}`;
|
|
86
|
+
}
|
|
87
|
+
/** The task a message is about, as the card needs it. Pure, for both clients. */
|
|
88
|
+
export function taskCardFor(message, detail, messages, openAskSessionIds) {
|
|
89
|
+
const task = message.task;
|
|
90
|
+
if (!task)
|
|
91
|
+
return null;
|
|
92
|
+
const row = detail.tasks.find((t) => sameSession(t.sessionId, task.sessionId));
|
|
93
|
+
return {
|
|
94
|
+
sessionId: task.sessionId,
|
|
95
|
+
title: row?.title || task.title || "Task",
|
|
96
|
+
project: row?.project || task.project || null,
|
|
97
|
+
state: taskCardState({
|
|
98
|
+
event: latestTaskEvent(messages, task.sessionId),
|
|
99
|
+
row,
|
|
100
|
+
openAsk: openAskSessionIds.some((id) => sameSession(task.sessionId, id)),
|
|
101
|
+
}),
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
/** Slack's rule: a message joins the one above when the same author wrote it within this long. */
|
|
105
|
+
export const THREAD_GROUP_MS = 5 * 60_000;
|
|
106
|
+
/**
|
|
107
|
+
* Whether a message starts a new group: its own avatar, name and time. The
|
|
108
|
+
* rest of a group is just text under the first message.
|
|
109
|
+
*/
|
|
110
|
+
export function startsMessageGroup(previous, message) {
|
|
111
|
+
if (!previous)
|
|
112
|
+
return true;
|
|
113
|
+
if (message.ts - previous.ts > THREAD_GROUP_MS)
|
|
114
|
+
return true;
|
|
115
|
+
if (previous.author.kind !== message.author.kind)
|
|
116
|
+
return true;
|
|
117
|
+
if (message.author.kind === "human" && previous.author.kind === "human") {
|
|
118
|
+
return previous.author.participantId !== message.author.participantId;
|
|
119
|
+
}
|
|
120
|
+
return false;
|
|
121
|
+
}
|
|
122
|
+
/** A stable avatar colour for a person, from their participant id. */
|
|
123
|
+
export function authorHue(author) {
|
|
124
|
+
if (author.kind === "omg")
|
|
125
|
+
return 11;
|
|
126
|
+
let hash = 0;
|
|
127
|
+
for (const char of author.participantId)
|
|
128
|
+
hash = (hash * 31 + char.charCodeAt(0)) >>> 0;
|
|
129
|
+
return hash % 360;
|
|
130
|
+
}
|
|
131
|
+
export function authorName(author) {
|
|
132
|
+
return author.kind === "omg" ? "omg" : author.name;
|
|
133
|
+
}
|
|
134
|
+
/** Top-level messages: what the main list shows. */
|
|
135
|
+
export function topLevelMessages(messages) {
|
|
136
|
+
return messages.filter((message) => !message.replyTo);
|
|
137
|
+
}
|
|
138
|
+
/** The replies to one top-level message, oldest first. */
|
|
139
|
+
export function repliesTo(messages, rootId) {
|
|
140
|
+
return messages.filter((message) => message.replyTo === rootId);
|
|
141
|
+
}
|
|
142
|
+
/** The "N replies" line under a top-level message, or null when it has none. */
|
|
143
|
+
export function replySummary(messages, rootId) {
|
|
144
|
+
const replies = repliesTo(messages, rootId);
|
|
145
|
+
if (!replies.length)
|
|
146
|
+
return null;
|
|
147
|
+
const authors = [];
|
|
148
|
+
for (const reply of replies) {
|
|
149
|
+
const same = authors.some((a) => a.kind === reply.author.kind &&
|
|
150
|
+
(a.kind === "omg" || (reply.author.kind === "human" && a.participantId === reply.author.participantId)));
|
|
151
|
+
if (!same)
|
|
152
|
+
authors.push(reply.author);
|
|
153
|
+
}
|
|
154
|
+
const task = [...replies].reverse().find((reply) => reply.task)?.task ?? null;
|
|
155
|
+
return { count: replies.length, lastTs: replies[replies.length - 1].ts, authors, taskSessionId: task?.sessionId ?? null };
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Pull Home's list down past the refresh to start a thread. Distances in
|
|
159
|
+
* points (iOS) or CSS pixels (web). A normal refresh fires well before the
|
|
160
|
+
* first; the second arms the thread, and releasing then opens it.
|
|
161
|
+
*/
|
|
162
|
+
export const THREAD_PULL_HINT = 90;
|
|
163
|
+
export const THREAD_PULL_ARM = 150;
|
|
164
|
+
/** 0: nothing. 1: show "keep pulling". 2: armed, release starts a thread. */
|
|
165
|
+
export function threadPullStage(pull) {
|
|
166
|
+
if (pull >= THREAD_PULL_ARM)
|
|
167
|
+
return 2;
|
|
168
|
+
if (pull >= THREAD_PULL_HINT)
|
|
169
|
+
return 1;
|
|
170
|
+
return 0;
|
|
171
|
+
}
|
|
172
|
+
//# sourceMappingURL=threads.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"threads.js","sourceRoot":"","sources":["../src/threads.ts"],"names":[],"mappings":"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"}
|