@ai-matrx/messaging 0.2.0 → 0.4.0
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/CHANGELOG.md +68 -0
- package/README.md +26 -0
- package/dist/index.cjs +16 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +14 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.js +16 -5
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +104 -29
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +91 -9
- package/dist/react.d.ts +91 -9
- package/dist/react.js +104 -29
- package/dist/react.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,73 @@
|
|
|
1
1
|
# Changelog — `@ai-matrx/messaging`
|
|
2
2
|
|
|
3
|
+
## 0.4.0 — 2026-09-07
|
|
4
|
+
|
|
5
|
+
**A ```matrx fence written in the PLATFORM's dialect was being deleted on render.** Found the
|
|
6
|
+
moment the first consumer's real messages went through this package's bubble. Third and last
|
|
7
|
+
release of the adoption session.
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
|
|
11
|
+
- **A fence this package cannot parse is never dropped.** `splitText` advanced past an
|
|
12
|
+
unrecognized fence and emitted nothing for it, so a message that named a note or a task lost
|
|
13
|
+
that paragraph between the sender and the reader — silently, with the surrounding prose intact
|
|
14
|
+
so nothing looked wrong. This package understands exactly one fence dialect (its own array of
|
|
15
|
+
`{entityType, entityId}`); Matrx's real fences are two-key `__kind` directive shells whose
|
|
16
|
+
items are typed per noun and resolvable only by the app's kind registry, i.e. every real
|
|
17
|
+
reference on the platform hit this path.
|
|
18
|
+
- **The regression test that should have caught it was hollow** — it asserted
|
|
19
|
+
`segments.every(s => s.type === "text")` on what was, after the drop, an EMPTY array. Replaced
|
|
20
|
+
with one that asserts the fence survives, and one for the platform's own dialect.
|
|
21
|
+
- **An unreadable fence collapses to the label `Reference` in previews and notifications**, never
|
|
22
|
+
to nothing. Collapsing to nothing is how a reference-only message becomes an inbox row reading
|
|
23
|
+
"No messages yet".
|
|
24
|
+
|
|
25
|
+
### Added
|
|
26
|
+
|
|
27
|
+
- **`renderFence`** — the host draws ```matrx fences with its own renderer, every fence, parsed
|
|
28
|
+
or not. A platform's fence dialect is the platform's business.
|
|
29
|
+
- `TextSegment` gains `{ type: "fence", body }`. With no host renderer the bubble draws an inert
|
|
30
|
+
card labeled "Reference" whose title says what is missing and how to wire it — drawn, never
|
|
31
|
+
deleted, never a code block of JSON.
|
|
32
|
+
|
|
33
|
+
### Consumer action (C28)
|
|
34
|
+
|
|
35
|
+
- **A host on the Matrx reference-fence protocol MUST pass `renderFence`** or its references
|
|
36
|
+
render as the generic inert card. matrx-frontend passes `MatrxEnvelopeBlock`.
|
|
37
|
+
- Code that switches on `TextSegment.type` gains a third case. TypeScript will point at it.
|
|
38
|
+
|
|
39
|
+
## 0.3.0 — 2026-09-07
|
|
40
|
+
|
|
41
|
+
**Three more seams the first adoption needed** — each one a case where the host
|
|
42
|
+
would otherwise have kept a piece of its own messaging UI beside this package's,
|
|
43
|
+
which is the failure this package exists to prevent. Same session as 0.2.0.
|
|
44
|
+
|
|
45
|
+
### Added
|
|
46
|
+
|
|
47
|
+
- **`wrapMessage` / `wrapConversationRow` — app chrome around a bubble and a row.**
|
|
48
|
+
The reason is the right-click menu: a platform whose every surface answers a right-click with
|
|
49
|
+
copy / export / attach / hand-to-an-agent cannot have messaging be the one surface that does
|
|
50
|
+
not, and that menu needs the app's surface name, entity tokens and clipboard primitive — none
|
|
51
|
+
of which a package can own. The wrapper WRAPS the package's bubble; it cannot replace it.
|
|
52
|
+
- **`renderReference` — the host's own reference renderer.** References are the one part of a
|
|
53
|
+
bubble an app is most likely to already render everywhere else (this platform resolves a
|
|
54
|
+
```matrx fence through a kind registry into a live chip). Two treatments of one fence in one
|
|
55
|
+
app is the second-renderer defect. Omit it and the package's card is used, unchanged.
|
|
56
|
+
- **`onIncomingMessage` now receives an `IncomingMessageContext`** —
|
|
57
|
+
`{ isActiveConversation, conversation }`. "Do not interrupt someone for the conversation they
|
|
58
|
+
are looking at" is the rule every chat app needs and only this package can answer, and a
|
|
59
|
+
desktop notification names the SENDER, whose display name lives on a conversation the host
|
|
60
|
+
cannot see from above the provider. (The origin surface had `sender_id.substring(0, 8)` and a
|
|
61
|
+
`// Placeholder` comment where the name belonged.)
|
|
62
|
+
|
|
63
|
+
### Consumer action (C28)
|
|
64
|
+
|
|
65
|
+
- `onIncomingMessage` gains a SECOND argument. Existing one-argument callbacks keep compiling and
|
|
66
|
+
keep working — but if you were suppressing notifications for the open conversation by reading
|
|
67
|
+
your own state, delete that and read `context.isActiveConversation`.
|
|
68
|
+
- Hosts with their own reference chips or per-row context menus: pass `renderReference` /
|
|
69
|
+
`wrapMessage` / `wrapConversationRow` and DELETE the host-side message list.
|
|
70
|
+
|
|
3
71
|
## 0.2.0 — 2026-09-07
|
|
4
72
|
|
|
5
73
|
**Both fixes came from the first real adoption** (matrx-frontend, the C9 full-elimination swap).
|
package/README.md
CHANGED
|
@@ -241,6 +241,32 @@ rule that matters: an unknown kind — or a known kind at a version this build d
|
|
|
241
241
|
renders NOTHING. Use `actions` for decisions, `actionRenderers` for surfaces; a kind may have
|
|
242
242
|
both a handler (for `summarize`, used by previews) and a renderer.
|
|
243
243
|
|
|
244
|
+
### Your app's chrome around our bubbles
|
|
245
|
+
|
|
246
|
+
A platform whose surfaces all answer a right-click, or that already renders references through
|
|
247
|
+
its own registry, hands those in rather than rebuilding the thread:
|
|
248
|
+
|
|
249
|
+
```tsx
|
|
250
|
+
<MessagingProvider …
|
|
251
|
+
wrapMessage={({ message, children }) => (
|
|
252
|
+
<MessageContextMenu message={message}>{children}</MessageContextMenu>
|
|
253
|
+
)}
|
|
254
|
+
wrapConversationRow={({ conversation, children }) => (
|
|
255
|
+
<ConversationContextMenu conversation={conversation}>{children}</ConversationContextMenu>
|
|
256
|
+
)}
|
|
257
|
+
renderReference={({ reference }) => <AppReferenceChip reference={reference} />}
|
|
258
|
+
/>
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
`wrapMessage` and `wrapConversationRow` WRAP; they never replace. `renderReference` replaces the
|
|
262
|
+
package's card — deliberately, because an app that draws references everywhere else must not
|
|
263
|
+
draw them two ways.
|
|
264
|
+
|
|
265
|
+
**If your platform has its own ```matrx fence dialect, pass `renderFence` too.** This package
|
|
266
|
+
parses one shape (an array of `{entityType, entityId}`); anything else reaches your renderer
|
|
267
|
+
verbatim as the fence body. Without it those fences draw an honest inert "Reference" card — they
|
|
268
|
+
are never deleted, and never shown to a reader as JSON.
|
|
269
|
+
|
|
244
270
|
### Theming
|
|
245
271
|
|
|
246
272
|
Structural CSS ships in the package; the token **contract** is enforced; token **values** are
|
package/dist/index.cjs
CHANGED
|
@@ -319,21 +319,32 @@ function splitText(content) {
|
|
|
319
319
|
if (start > cursor) {
|
|
320
320
|
segments.push({ type: "text", value: content.slice(cursor, start) });
|
|
321
321
|
}
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
322
|
+
const body = match[1] ?? "";
|
|
323
|
+
const references = parseFenceBody(body);
|
|
324
|
+
if (references.length === 0) {
|
|
325
|
+
segments.push({ type: "fence", body });
|
|
326
|
+
} else {
|
|
327
|
+
references.forEach((reference) => {
|
|
328
|
+
segments.push({ type: "reference", reference });
|
|
329
|
+
});
|
|
330
|
+
}
|
|
325
331
|
cursor = start + match[0].length;
|
|
326
332
|
}
|
|
327
333
|
if (cursor < content.length) {
|
|
328
334
|
segments.push({ type: "text", value: content.slice(cursor) });
|
|
329
335
|
}
|
|
330
336
|
return segments.filter(
|
|
331
|
-
(segment) => segment.type
|
|
337
|
+
(segment) => segment.type !== "text" || segment.value.trim().length > 0
|
|
332
338
|
);
|
|
333
339
|
}
|
|
334
340
|
function summarizeText(content, maxLength = 140) {
|
|
335
341
|
const parts = splitText(content).map(
|
|
336
|
-
(segment) => segment.type === "text" ? segment.value : segment.reference.label
|
|
342
|
+
(segment) => segment.type === "text" ? segment.value : segment.type === "reference" ? segment.reference.label : (
|
|
343
|
+
// A fence we cannot read still SAYS something. Collapsing it to
|
|
344
|
+
// nothing is how a reference-only message becomes an inbox row that
|
|
345
|
+
// reads "No messages yet" — a screen telling a lie.
|
|
346
|
+
"Reference"
|
|
347
|
+
)
|
|
337
348
|
);
|
|
338
349
|
const flattened = parts.join(" ").replace(/\s+/g, " ").trim();
|
|
339
350
|
if (flattened.length <= maxLength) return flattened;
|