@alashi/cli 0.8.1 → 0.9.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/assets/v1/chat.js +42 -2
- package/assets/v1/system.css +16 -18
- package/package.json +1 -1
- package/templates/basic-app/AGENTS.md +6 -1
package/assets/v1/chat.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/* alashi chat
|
|
1
|
+
/* alashi chat + markdown components v1
|
|
2
2
|
*
|
|
3
3
|
* The system chat UI, served by the host. Apps drop in:
|
|
4
4
|
*
|
|
@@ -9,6 +9,10 @@
|
|
|
9
9
|
* and cost display. Renders into light DOM using system.css classes, so it
|
|
10
10
|
* inherits the app's theme tokens.
|
|
11
11
|
*
|
|
12
|
+
* The same script also registers <alashi-markdown>, the markdown renderer on
|
|
13
|
+
* its own for apps that display prose outside a conversation (see the bottom
|
|
14
|
+
* of this file). One renderer, one place formatting bugs get fixed.
|
|
15
|
+
*
|
|
12
16
|
* Attributes:
|
|
13
17
|
* app app name (default: derived from /app/<name>/ in the URL)
|
|
14
18
|
* placeholder input placeholder text
|
|
@@ -31,7 +35,8 @@
|
|
|
31
35
|
* Breaking changes ship as /assets/v2/chat.js. */
|
|
32
36
|
|
|
33
37
|
(() => {
|
|
34
|
-
|
|
38
|
+
// Loading the script twice is a no-op for every element it defines.
|
|
39
|
+
if (customElements.get('alashi-chat') || customElements.get('alashi-markdown')) return;
|
|
35
40
|
|
|
36
41
|
const escapeHtml = (s) =>
|
|
37
42
|
s
|
|
@@ -357,5 +362,40 @@
|
|
|
357
362
|
}
|
|
358
363
|
}
|
|
359
364
|
|
|
365
|
+
/* <alashi-markdown> — the same renderMarkdown() as chat bubbles, as a
|
|
366
|
+
* standalone display primitive. No fetching, no SSE, no conversations.
|
|
367
|
+
*
|
|
368
|
+
* <alashi-markdown text="**hi**"></alashi-markdown> // static markup
|
|
369
|
+
* node.text = card.description; // re-renders
|
|
370
|
+
*
|
|
371
|
+
* The `text` property is the primary path: apps pass model-derived,
|
|
372
|
+
* multi-line strings that do not belong in an attribute. Renders into light
|
|
373
|
+
* DOM (like _setMsgText) so it inherits the app's theme tokens, and carries
|
|
374
|
+
* the `markdown` class so system.css can style its children. */
|
|
375
|
+
class AlashiMarkdown extends HTMLElement {
|
|
376
|
+
connectedCallback() {
|
|
377
|
+
this.classList.add('markdown');
|
|
378
|
+
// A property set before connect wins; the attribute is the static path.
|
|
379
|
+
if (this._text === undefined) this._text = this.getAttribute('text') ?? '';
|
|
380
|
+
this._render();
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
get text() {
|
|
384
|
+
return this._text ?? '';
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
set text(value) {
|
|
388
|
+
this._text = String(value ?? '');
|
|
389
|
+
this._render();
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
_render() {
|
|
393
|
+
// Escape-first pipeline: renderMarkdown escapes before rebuilding a
|
|
394
|
+
// known-safe subset of tags, so untrusted markdown stays inert.
|
|
395
|
+
this.innerHTML = renderMarkdown(String(this._text ?? ''));
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
|
|
360
399
|
customElements.define('alashi-chat', AlashiChat);
|
|
400
|
+
customElements.define('alashi-markdown', AlashiMarkdown);
|
|
361
401
|
})();
|
package/assets/v1/system.css
CHANGED
|
@@ -578,41 +578,39 @@ input[type="checkbox"] {
|
|
|
578
578
|
/* assistant bubbles hold rendered markdown (chat.js), not preformatted text */
|
|
579
579
|
white-space: normal;
|
|
580
580
|
}
|
|
581
|
-
.
|
|
582
|
-
.
|
|
583
|
-
|
|
584
|
-
.
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
581
|
+
/* Rendered-markdown prose. Shared by assistant chat bubbles and the
|
|
582
|
+
* <alashi-markdown> element (or any `.markdown` container) — chat.js renders
|
|
583
|
+
* both with the same renderMarkdown(), so the styling lives in one place too.
|
|
584
|
+
* Headings stay h3..h6 because that is what renderMarkdown emits. */
|
|
585
|
+
alashi-markdown {
|
|
586
|
+
/* unknown element to CSS, same as <alashi-chat> in consumer apps */
|
|
587
|
+
display: block;
|
|
588
|
+
}
|
|
589
|
+
:is(.msg.assistant, alashi-markdown, .markdown) :is(p, ul, ol, pre, h3, h4, h5, h6) {
|
|
589
590
|
margin: 0 0 0.6rem;
|
|
590
591
|
}
|
|
591
|
-
.msg.assistant > :last-child {
|
|
592
|
+
:is(.msg.assistant, alashi-markdown, .markdown) > :last-child {
|
|
592
593
|
margin-bottom: 0;
|
|
593
594
|
}
|
|
594
|
-
.msg.assistant ul,
|
|
595
|
-
.msg.assistant ol {
|
|
595
|
+
:is(.msg.assistant, alashi-markdown, .markdown) :is(ul, ol) {
|
|
596
596
|
padding-left: 1.3rem;
|
|
597
597
|
}
|
|
598
|
-
.msg.assistant li {
|
|
598
|
+
:is(.msg.assistant, alashi-markdown, .markdown) li {
|
|
599
599
|
margin: 0.15rem 0;
|
|
600
600
|
}
|
|
601
|
-
.msg.assistant img {
|
|
601
|
+
:is(.msg.assistant, alashi-markdown, .markdown) img {
|
|
602
602
|
max-width: 100%;
|
|
603
603
|
border-radius: var(--radius-sm);
|
|
604
604
|
border: 1px solid var(--border);
|
|
605
605
|
}
|
|
606
|
-
.msg.assistant pre {
|
|
606
|
+
:is(.msg.assistant, alashi-markdown, .markdown) pre {
|
|
607
607
|
background: var(--panel);
|
|
608
608
|
padding: 0.6rem 0.75rem;
|
|
609
609
|
}
|
|
610
|
-
.msg.assistant h3 {
|
|
610
|
+
:is(.msg.assistant, alashi-markdown, .markdown) h3 {
|
|
611
611
|
font-size: 1rem;
|
|
612
612
|
}
|
|
613
|
-
.msg.assistant h4,
|
|
614
|
-
.msg.assistant h5,
|
|
615
|
-
.msg.assistant h6 {
|
|
613
|
+
:is(.msg.assistant, alashi-markdown, .markdown) :is(h4, h5, h6) {
|
|
616
614
|
font-size: 0.92rem;
|
|
617
615
|
}
|
|
618
616
|
.msg.assistant.pending {
|
package/package.json
CHANGED
|
@@ -73,6 +73,10 @@ the connection before calling `runMigrations`.
|
|
|
73
73
|
with `openConversation`/`adoptSession`). Methods: `adoptSession(sessionId, title?)`,
|
|
74
74
|
`openConversation(id)`, `newChat()`. Bubbling events: `alashi-chat:turn`
|
|
75
75
|
(`{ok, costUsd, error, conversationId}`), `alashi-chat:conversation`.
|
|
76
|
+
The same script also registers `<alashi-markdown>` — the host's markdown
|
|
77
|
+
renderer as a standalone display primitive, for prose outside a conversation
|
|
78
|
+
(`node.text = card.description` re-renders on assignment; `text="**hi**"` is
|
|
79
|
+
honoured on connect for static markup). No fetching, no conversation logic.
|
|
76
80
|
Never vendor or fork system UI; breaking changes ship as `/assets/v2/`.
|
|
77
81
|
|
|
78
82
|
## App routes
|
|
@@ -84,7 +88,8 @@ the connection before calling `runMigrations`.
|
|
|
84
88
|
|
|
85
89
|
- Never `innerHTML` external or model-derived data in the UI — build DOM via
|
|
86
90
|
the `el()` helper / `textContent`. Markdown rendering belongs to
|
|
87
|
-
`<alashi-chat>`,
|
|
91
|
+
`<alashi-chat>` / `<alashi-markdown>`, the sanctioned exception because the
|
|
92
|
+
host's renderer is escape-first. Never bundle a markdown library.
|
|
88
93
|
- Validate at boundaries (webhooks, user input): JSON only, cap body sizes,
|
|
89
94
|
4xx on garbage. Model output is a boundary too — parse defensively.
|
|
90
95
|
- Secrets come from declared `config` keys (`secret: true`), referenced as
|