@songsid/agend 2.3.4-beta.1 → 2.3.4-beta.2
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/channel/adapters/discord.js +13 -0
- package/dist/channel/adapters/discord.js.map +1 -1
- package/dist/chat-log-ids.d.ts +48 -0
- package/dist/chat-log-ids.js +182 -0
- package/dist/chat-log-ids.js.map +1 -0
- package/dist/classic-channel-manager.d.ts +8 -1
- package/dist/classic-channel-manager.js +24 -2
- package/dist/classic-channel-manager.js.map +1 -1
- package/dist/fleet-manager.d.ts +17 -0
- package/dist/fleet-manager.js +56 -2
- package/dist/fleet-manager.js.map +1 -1
- package/dist/ui/chat-strings.js +2 -2
- package/dist/ui/chat-thread.js +52 -10
- package/dist/ui/shared/app.css +14 -2
- package/package.json +1 -1
package/dist/ui/chat-strings.js
CHANGED
|
@@ -110,7 +110,7 @@ register("chat", {
|
|
|
110
110
|
pvServer_notListening: "Previews are not available on this fleet right now.",
|
|
111
111
|
previews: "Allow HTML previews",
|
|
112
112
|
clicked: "Clicked:", clickShow: "Show the message these buttons were on",
|
|
113
|
-
copy: "Copy", copyMessage: "Copy this reply", copied: "Copied", copyFailed: "Copy failed", wrap: "Wrap", showAll: "Show all {0} lines", showMore: "Show more", showLess: "Show less", jumpLatest: "Latest", newBelow: "{0} new",
|
|
113
|
+
copy: "Copy", copyMessage: "Copy this reply", copied: "Copied", copyFailed: "Copy failed", wrap: "Wrap", showAll: "Show all {0} lines", showMore: "Show more", showLess: "Show less", showAllShort: "All {0} lines", showMoreShort: "More", jumpLatest: "Latest", newBelow: "{0} new",
|
|
114
114
|
disconnected: "disconnected", tick_queued: "Waiting behind another message", tick_processing: "Handed to the agent", tick_delivered: "The agent has it", tick_failed: "Not delivered", tick_cancelled: "Dropped by Stop", reactedBy: "{0} reacted",
|
|
115
115
|
promptAnswering: "Answering…", promptGone: "This prompt is no longer open", promptTextPlaceholder: "Your answer", promptTextSend: "Send answer", promptFor: "{0}: {1}",
|
|
116
116
|
working: "{0} is working…", stuck: "{0} looks stuck", stopReply: "Stop reply", stopReplyTitle: "Stop the current reply (like Esc) and drop the messages still waiting. The instance keeps running.", stopSent: "Stopped",
|
|
@@ -249,7 +249,7 @@ register("chat", {
|
|
|
249
249
|
pvServer_notListening: "這個 fleet 目前無法預覽。",
|
|
250
250
|
previews: "允許預覽 HTML",
|
|
251
251
|
clicked: "點選了:", clickShow: "顯示這些按鈕所在的訊息",
|
|
252
|
-
copy: "複製", copyMessage: "複製這則回覆", copied: "已複製", copyFailed: "複製失敗", wrap: "換行", showAll: "展開全部 {0} 行", showMore: "顯示更多", showLess: "收合", jumpLatest: "最新", newBelow: "{0} 則新訊息",
|
|
252
|
+
copy: "複製", copyMessage: "複製這則回覆", copied: "已複製", copyFailed: "複製失敗", wrap: "換行", showAll: "展開全部 {0} 行", showMore: "顯示更多", showLess: "收合", showAllShort: "全部 {0} 行", showMoreShort: "更多", jumpLatest: "最新", newBelow: "{0} 則新訊息",
|
|
253
253
|
disconnected: "已斷線", tick_queued: "排在前一則訊息之後", tick_processing: "已交給 agent", tick_delivered: "agent 已收到", tick_failed: "未送達", tick_cancelled: "已被中止取消", reactedBy: "{0} 的回應",
|
|
254
254
|
promptAnswering: "回覆中…", promptGone: "這個提示已經結束", promptTextPlaceholder: "你的回答", promptTextSend: "送出回答", promptFor: "{0}:{1}",
|
|
255
255
|
working: "{0} 處理中…", stuck: "{0} 似乎卡住了", stopReply: "中止回覆", stopReplyTitle: "中止目前的回覆(同 Esc),並取消還在排隊的訊息。instance 會繼續運行。", stopSent: "已中止",
|
package/dist/ui/chat-thread.js
CHANGED
|
@@ -31,8 +31,14 @@ export const TEXT_PREVIEW_COLUMNS = 50;
|
|
|
31
31
|
export const TEXT_CARD_MAX = 1024 * 1024;
|
|
32
32
|
const P = () => globalThis.AgendPreview;
|
|
33
33
|
/** #1672: a status line longer than this (lines, or characters) is folded until it is opened. */
|
|
34
|
-
|
|
35
|
-
|
|
34
|
+
/**
|
|
35
|
+
* #1672 / the user (hmsg-d6ac6dfb): a status line shows two lines — its header ("A → B:") and the first line of the
|
|
36
|
+
* message, each one row (clipped with an ellipsis). Its "open" control shows when that hides something: more lines than
|
|
37
|
+
* two, or a row clipped at the width it is drawn at (measured after each draw and resize: fitStatus). Where nothing is
|
|
38
|
+
* measured (no layout), a line longer than STATUS_LINE_CHARS stands for "clipped".
|
|
39
|
+
*/
|
|
40
|
+
export const STATUS_FOLD_LINES = 2;
|
|
41
|
+
export const STATUS_LINE_CHARS = 100;
|
|
36
42
|
const REPLY = '<svg class="icon" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M9 14 4 9l5-5"/><path d="M4 9h10.5a5.5 5.5 0 0 1 0 11H11"/></svg>';
|
|
37
43
|
const COPY = '<svg class="icon" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="9" y="9" width="13" height="13" rx="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg>';
|
|
38
44
|
|
|
@@ -224,15 +230,19 @@ export function createThread(list, scroller, opts) {
|
|
|
224
230
|
*/
|
|
225
231
|
function statusHtml(x, time) {
|
|
226
232
|
const text = String(x.text == null ? "" : x.text);
|
|
227
|
-
|
|
233
|
+
// Rows split on any line break (a CRLF is one break, never a row and a stray CR); the text itself is not changed.
|
|
234
|
+
const lines = R().lineCount(text.replace(/\r\n?/g, "\n"));
|
|
228
235
|
const manyLines = lines > STATUS_FOLD_LINES;
|
|
229
|
-
const
|
|
230
|
-
|
|
231
|
-
|
|
236
|
+
const overflows = manyLines || text.split(/\r\n?|\n/).some(l => l.length > STATUS_LINE_CHARS);
|
|
237
|
+
// Its control: a short label at the end of line 2; its full name (and whether it is open) for a screen reader. Shown
|
|
238
|
+
// only while the line overflows (class `overflows`, kept by fitStatus at the width it is drawn at).
|
|
239
|
+
const more = `<button data-trust="thread-control" type="button" class="st-more" data-act="toggleFold" aria-expanded="false"${manyLines ? ` data-lines="${escAttr(lines)}"` : ""} aria-label="${escAttr(manyLines ? trf("chat.showAll", lines) : tr("chat.showMore"))}">${escAttr(manyLines ? trf("chat.showAllShort", lines) : tr("chat.showMoreShort"))}</button>`;
|
|
232
240
|
const tools = `<div data-trust="thread-control" class="msg-tools"><button type="button" class="chip-btn icon-only" data-act="copyMsg" data-arg="${escAttr(msgKey(x))}" title="${escAttr(tr("chat.copyMessage"))}" aria-label="${escAttr(tr("chat.copyMessage"))}">${COPY}</button></div>`;
|
|
233
241
|
// #1990: the other instance's name opens its chat (an in-app link the router takes: no target).
|
|
234
|
-
|
|
235
|
-
|
|
242
|
+
// Each line its own row (folded: the first two, each clipped to one row); the line breaks stay in the text.
|
|
243
|
+
const body = textLinkSegments(text, x.links).map(sg => sg.href ? `<a data-trust="link" class="st-link" href="${escAttr(sg.href)}">${escAttr(sg.text)}</a>` : escAttr(sg.text)).join("")
|
|
244
|
+
.split(/\r\n?|\n/).map(l => `<span class="st-ln">${l}</span>`).join("\n");
|
|
245
|
+
return `<div class="msg status-line folded${overflows ? " overflows" : ""}"><div class="meta">${time}</div><div class="body"><div class="st-text">${body}</div>${more}</div>${tools}</div>`;
|
|
236
246
|
}
|
|
237
247
|
/**
|
|
238
248
|
* #1266: an agent reply's buttons. Labels are text (escaped, never Markdown); the click names the set and the index,
|
|
@@ -610,7 +620,25 @@ export function createThread(list, scroller, opts) {
|
|
|
610
620
|
}
|
|
611
621
|
// Sizes change without a scroll event (layout after the render, the dock under the thread): while pinned, the view
|
|
612
622
|
// stays flush with the bottom; a reader who scrolled up is never moved.
|
|
613
|
-
const resized = () => { if (pinned && !atBottom()) toBottom(); reportJump(); };
|
|
623
|
+
const resized = () => { fitStatus(); if (pinned && !atBottom()) toBottom(); reportJump(); };
|
|
624
|
+
/**
|
|
625
|
+
* The user (hmsg-d6ac6dfb): a folded status line whose first two rows fit is plain two lines, no control; one with a
|
|
626
|
+
* row clipped at the width it is drawn at gets its "open" control (`overflows`). Measured after each draw and resize;
|
|
627
|
+
* a line with more than two rows always overflows (data-lines). Nothing laid out (no width): the guess it was drawn with.
|
|
628
|
+
*/
|
|
629
|
+
function fitStatus() {
|
|
630
|
+
for (const m of list.querySelectorAll(".msg.status-line.folded")) {
|
|
631
|
+
const btn = m.querySelector(".st-more");
|
|
632
|
+
if (!btn || btn.dataset.lines) continue;
|
|
633
|
+
let measured = false, over = false;
|
|
634
|
+
for (const row of [...m.querySelectorAll(".st-ln")].slice(0, STATUS_FOLD_LINES)) {
|
|
635
|
+
if (!row.clientWidth) continue;
|
|
636
|
+
measured = true;
|
|
637
|
+
if (row.scrollWidth > row.clientWidth + 1) over = true;
|
|
638
|
+
}
|
|
639
|
+
if (measured && m.classList.contains("overflows") !== over) m.classList.toggle("overflows", over);
|
|
640
|
+
}
|
|
641
|
+
}
|
|
614
642
|
let ro = typeof ResizeObserver === "function" ? new ResizeObserver(resized) : null;
|
|
615
643
|
if (ro) { ro.observe(list); ro.observe(scroller); }
|
|
616
644
|
// #2158: the reader's own hand on the thread — a wheel, a touch, the scrollbar (a pointer held), a scrolling key
|
|
@@ -725,6 +753,7 @@ export function createThread(list, scroller, opts) {
|
|
|
725
753
|
armPolls();
|
|
726
754
|
rove();
|
|
727
755
|
progress();
|
|
756
|
+
fitStatus();
|
|
728
757
|
return added;
|
|
729
758
|
}
|
|
730
759
|
/**
|
|
@@ -802,13 +831,26 @@ export function createThread(list, scroller, opts) {
|
|
|
802
831
|
function onClick(e) {
|
|
803
832
|
if (onImageClick(e)) return;
|
|
804
833
|
const el = e.target && e.target.closest ? e.target.closest("[data-act]") : null;
|
|
805
|
-
if (!el || !list.contains(el))
|
|
834
|
+
if (!el || !list.contains(el)) {
|
|
835
|
+
// A folded status line opens by a click on its text too (not on a link in it); its button is the keyboard's way.
|
|
836
|
+
const text = e.target && e.target.closest ? e.target.closest(".msg.status-line.folded.overflows .st-text") : null;
|
|
837
|
+
const btn = text && !e.target.closest("a") ? text.parentNode.querySelector(".st-more") : null;
|
|
838
|
+
if (btn && list.contains(btn)) onClick({ target: btn });
|
|
839
|
+
return;
|
|
840
|
+
}
|
|
806
841
|
const act = el.dataset.act;
|
|
807
842
|
if (act === "copyMsg") { const x = msgs.find(y => msgKey(y) === el.dataset.arg); if (x) copyFrom(el, x.text); }
|
|
808
843
|
else if (act === "copyCode") { const pre = el.closest(".codeblock")?.querySelector("pre"); if (pre) copyFrom(el, pre.textContent); }
|
|
809
844
|
else if (act === "toggleFold") {
|
|
810
845
|
const box = el.closest(".codeblock, .msg.status-line"); if (!box) return;
|
|
811
846
|
const folded = box.classList.toggle("folded");
|
|
847
|
+
if (box.classList.contains("status-line")) {
|
|
848
|
+
// A status line's own label: short at the end of line 2 while folded, its full name for a screen reader.
|
|
849
|
+
el.setAttribute("aria-expanded", folded ? "false" : "true");
|
|
850
|
+
el.setAttribute("aria-label", !folded ? tr("chat.showLess") : el.dataset.lines ? trf("chat.showAll", el.dataset.lines) : tr("chat.showMore"));
|
|
851
|
+
el.textContent = !folded ? tr("chat.showLess") : el.dataset.lines ? trf("chat.showAllShort", el.dataset.lines) : tr("chat.showMoreShort");
|
|
852
|
+
return;
|
|
853
|
+
}
|
|
812
854
|
el.textContent = !folded ? tr("chat.showLess") : el.dataset.lines ? trf("chat.showAll", el.dataset.lines) : tr("chat.showMore");
|
|
813
855
|
} else if (act === "toggleWrap") opts.toggleWrap();
|
|
814
856
|
else if (act === "replyButton") {
|
package/dist/ui/shared/app.css
CHANGED
|
@@ -623,9 +623,21 @@ html:has(.shell), html:has(.shell) body { overflow: hidden; }
|
|
|
623
623
|
Its class is `status-line`, never `status`: that is the header's inline-flex badge class, and on a message it turned
|
|
624
624
|
the meta, body and tools into one flex row. */
|
|
625
625
|
.msg.status-line { align-self: stretch; font-size: var(--fs-sm); color: var(--text-3); }
|
|
626
|
-
|
|
627
|
-
.msg.status-line
|
|
626
|
+
/* Each line is a row (.st-ln); the line breaks between rows are text for copying, not extra rows. */
|
|
627
|
+
.msg.status-line .st-text { border-left: 2px solid var(--border); padding-left: var(--s-3); }
|
|
628
|
+
.msg.status-line .st-ln { display: block; white-space: pre-wrap; overflow-wrap: anywhere; }
|
|
629
|
+
.msg.status-line .st-ln:empty::after { content: " "; }
|
|
630
|
+
/* Folded (the user, hmsg-d6ac6dfb): two lines — the header and the first line — each one row with an ellipsis; the
|
|
631
|
+
button sits at the end of line 2. The text opens it too. */
|
|
632
|
+
.msg.status-line.folded .body { display: flex; align-items: flex-end; gap: var(--s-2); }
|
|
633
|
+
.msg.status-line.folded .st-text { flex: 1 1 auto; min-width: 0; }
|
|
634
|
+
.msg.status-line.folded.overflows .st-text { cursor: pointer; }
|
|
635
|
+
/* Its control only while something is hidden (two short rows that fit: plain, no control). */
|
|
636
|
+
.msg.status-line.folded:not(.overflows) .st-more { display: none; }
|
|
637
|
+
.msg.status-line.folded .st-ln { white-space: pre; overflow: hidden; text-overflow: ellipsis; }
|
|
638
|
+
.msg.status-line.folded .st-ln:nth-child(n+3) { display: none; }
|
|
628
639
|
.msg.status-line .st-more { border: 0; background: none; color: var(--text-2); cursor: pointer; font-size: var(--fs-xs); padding: var(--s-1) 0 0 var(--s-3); }
|
|
640
|
+
.msg.status-line.folded .st-more { flex: none; padding: 0 var(--s-2) 0 0; white-space: nowrap; }
|
|
629
641
|
.msg.status-line .st-more:hover { color: var(--text); }
|
|
630
642
|
.msg-tools { display: flex; gap: var(--s-1); margin-top: var(--s-1); opacity: 0; transition: opacity var(--t-fast); }
|
|
631
643
|
/* #2147: bounded stock toolbar paint, including fixed descendants. Padding preserves focus outlines. */
|