@songsid/agend 2.2.0-beta.3 → 2.2.0-beta.5
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-cli.js +6 -2
- package/dist/agent-cli.js.map +1 -1
- package/dist/backend/claude-code.d.ts +46 -2
- package/dist/backend/claude-code.js +125 -31
- package/dist/backend/claude-code.js.map +1 -1
- package/dist/backend/credential-profile.d.ts +33 -3
- package/dist/backend/credential-profile.js +107 -5
- package/dist/backend/credential-profile.js.map +1 -1
- package/dist/backend/types.d.ts +1 -1
- package/dist/cache-service.d.ts +2 -0
- package/dist/cache-service.js +2 -1
- package/dist/cache-service.js.map +1 -1
- package/dist/channel/adapters/discord.d.ts +13 -0
- package/dist/channel/adapters/discord.js +42 -0
- package/dist/channel/adapters/discord.js.map +1 -1
- package/dist/channel/adapters/telegram.d.ts +6 -1
- package/dist/channel/adapters/telegram.js +27 -2
- package/dist/channel/adapters/telegram.js.map +1 -1
- package/dist/channel/types.d.ts +22 -1
- package/dist/cli.js +35 -0
- package/dist/cli.js.map +1 -1
- package/dist/config-validator.js +7 -0
- package/dist/config-validator.js.map +1 -1
- package/dist/daemon.d.ts +96 -0
- package/dist/daemon.js +339 -16
- package/dist/daemon.js.map +1 -1
- package/dist/delivery-outbox.d.ts +18 -5
- package/dist/delivery-outbox.js +121 -14
- package/dist/delivery-outbox.js.map +1 -1
- package/dist/fleet-context.d.ts +1 -0
- package/dist/fleet-manager.d.ts +89 -3
- package/dist/fleet-manager.js +541 -86
- package/dist/fleet-manager.js.map +1 -1
- package/dist/general-knowledge/skills/credential-profiles/SKILL.md +43 -10
- package/dist/host-memory.d.ts +10 -0
- package/dist/host-memory.js +33 -1
- package/dist/host-memory.js.map +1 -1
- package/dist/instance-lifecycle.d.ts +25 -6
- package/dist/instance-lifecycle.js +73 -26
- package/dist/instance-lifecycle.js.map +1 -1
- package/dist/locale.js +48 -18
- package/dist/locale.js.map +1 -1
- package/dist/login-controller.d.ts +20 -3
- package/dist/login-controller.js +71 -19
- package/dist/login-controller.js.map +1 -1
- package/dist/login-flows.d.ts +5 -2
- package/dist/login-flows.js +5 -4
- package/dist/login-flows.js.map +1 -1
- package/dist/memory-pressure.d.ts +13 -1
- package/dist/memory-pressure.js +50 -10
- package/dist/memory-pressure.js.map +1 -1
- package/dist/outbound-handlers.d.ts +61 -0
- package/dist/outbound-handlers.js +100 -35
- package/dist/outbound-handlers.js.map +1 -1
- package/dist/outbound-schemas.d.ts +1 -0
- package/dist/outbound-schemas.js +2 -0
- package/dist/outbound-schemas.js.map +1 -1
- package/dist/public-preview.d.ts +100 -0
- package/dist/public-preview.js +233 -0
- package/dist/public-preview.js.map +1 -0
- package/dist/public-web-gateway.js +6 -4
- package/dist/public-web-gateway.js.map +1 -1
- package/dist/public-web-link.d.ts +20 -0
- package/dist/public-web-link.js +26 -1
- package/dist/public-web-link.js.map +1 -1
- package/dist/restart-progress.d.ts +29 -0
- package/dist/restart-progress.js +23 -0
- package/dist/restart-progress.js.map +1 -1
- package/dist/settings-api.js +10 -4
- package/dist/settings-api.js.map +1 -1
- package/dist/spawn-gate.js +5 -1
- package/dist/spawn-gate.js.map +1 -1
- package/dist/spawn-hold-reply.d.ts +12 -0
- package/dist/spawn-hold-reply.js +39 -0
- package/dist/spawn-hold-reply.js.map +1 -0
- package/dist/topic-commands.js +9 -2
- package/dist/topic-commands.js.map +1 -1
- package/dist/tunnel/purpose-lane.d.ts +5 -1
- package/dist/tunnel/purpose-lane.js +14 -7
- package/dist/tunnel/purpose-lane.js.map +1 -1
- package/dist/turn-resume.d.ts +2 -0
- package/dist/turn-resume.js +1 -1
- package/dist/turn-resume.js.map +1 -1
- package/dist/types.d.ts +8 -0
- package/dist/ui/chat-mentions.js +63 -0
- package/dist/ui/chat-render.js +25 -0
- package/dist/ui/chat-strings.js +14 -2
- package/dist/ui/chat-thread.js +28 -10
- package/dist/ui/panel-chat.js +26 -11
- package/dist/ui/panel-details.js +2 -0
- package/dist/ui/panel-fleet.js +199 -57
- package/dist/ui/panel-needs.js +4 -3
- package/dist/ui/panel-settings.js +4 -2
- package/dist/ui/preview-panel.js +48 -14
- package/dist/ui/preview-status.js +28 -0
- package/dist/ui/preview.js +40 -3
- package/dist/ui/settings-token.js +1 -1
- package/dist/ui/shared/app-i18n.js +4 -0
- package/dist/ui/shared/app-prefs.js +1 -0
- package/dist/ui/shared/app-shell.js +146 -2
- package/dist/ui/shared/app-store.js +3 -1
- package/dist/ui/shared/app.css +47 -20
- package/dist/ui/shared/instance-nav.js +79 -23
- package/dist/ui/shared/view-strings.js +10 -0
- package/dist/unrecognised-prompt.d.ts +23 -0
- package/dist/unrecognised-prompt.js +74 -0
- package/dist/unrecognised-prompt.js.map +1 -0
- package/dist/update-install.d.ts +8 -0
- package/dist/update-install.js +9 -3
- package/dist/update-install.js.map +1 -1
- package/dist/update-marker.d.ts +40 -0
- package/dist/update-marker.js +49 -0
- package/dist/update-marker.js.map +1 -1
- package/dist/usage/i18n-keys.d.ts +1 -1
- package/dist/usage/i18n-keys.js +1 -1
- package/dist/usage/i18n-keys.js.map +1 -1
- package/dist/usage/providers.d.ts +34 -5
- package/dist/usage/providers.js +160 -27
- package/dist/usage/providers.js.map +1 -1
- package/dist/usage/statusline-usage.d.ts +6 -2
- package/dist/usage/statusline-usage.js +10 -4
- package/dist/usage/statusline-usage.js.map +1 -1
- package/dist/web-api.d.ts +20 -0
- package/dist/web-api.js +216 -30
- package/dist/web-api.js.map +1 -1
- package/dist/web-auth.js +3 -2
- package/dist/web-auth.js.map +1 -1
- package/dist/web-mentions.d.ts +44 -0
- package/dist/web-mentions.js +75 -0
- package/dist/web-mentions.js.map +1 -0
- package/dist/web-prefs.js +2 -0
- package/dist/web-prefs.js.map +1 -1
- package/dist/web-preview.d.ts +14 -1
- package/dist/web-preview.js +35 -13
- package/dist/web-preview.js.map +1 -1
- package/dist/web-schedules.d.ts +12 -0
- package/dist/web-schedules.js +34 -0
- package/dist/web-schedules.js.map +1 -0
- package/package.json +1 -1
package/dist/ui/chat-thread.js
CHANGED
|
@@ -34,7 +34,7 @@ export const msgKey = (x) => `${x.boot}-${x.id}`;
|
|
|
34
34
|
/**
|
|
35
35
|
* Bind a renderer to `list` (the thread element) inside `scroller`. opts: { t, tf, isUser(x), onJump({show, unseen}),
|
|
36
36
|
* setPreviewOptIn(on), copyText(text) → Promise<boolean>, download(code), panel? }. panel (#1481): { shown() → the card
|
|
37
|
-
* key the side panel shows, or null; open(spec, { run }) } — without it a card has no "Open in panel".
|
|
37
|
+
* key the side panel shows, or null; open(spec, { run }); version(); claim(); claims() } — without it a card has no "Open in panel".
|
|
38
38
|
*/
|
|
39
39
|
export function createThread(list, scroller, opts) {
|
|
40
40
|
const nodes = new Map(); // key → { html, node }
|
|
@@ -60,7 +60,7 @@ export function createThread(list, scroller, opts) {
|
|
|
60
60
|
const ticks = u && x.delivery ? R().deliveryHtml(x.delivery, TICKS()) : "";
|
|
61
61
|
const tools = u ? "" : `<div 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>`;
|
|
62
62
|
const buttons = x.role === "agent" ? replyButtonsHtml(x.buttons) : "";
|
|
63
|
-
return `<div class="msg ${u ? "user" : "agent"}"><div class="meta"><span class="sender">${escAttr(x.sender)}</span><span class="time">${time}</span>${ticks}</div><div class="body"><div class="md">${R().renderMarkdown(x.text, { htmlCards: x.role === "agent", emojis: opts.emojis })}</div>${R().attachmentsHtml(x.attachments, { htmlCards: x.role === "agent", goneTitle: tr("chat.attGone"), goneLabel: tr("chat.attUnavailable"), inlinePreviews: !PUBLIC_LINK() })}${buttons}</div>${tools}</div>`;
|
|
63
|
+
return `<div class="msg ${u ? "user" : "agent"}"><div class="meta"><span class="sender">${escAttr(x.sender)}</span><span class="time">${time}</span>${ticks}</div><div class="body"><div class="md">${R().renderMarkdown(x.text, { htmlCards: x.role === "agent", emojis: opts.emojis, mentions: opts.mentions })}</div>${R().attachmentsHtml(x.attachments, { htmlCards: x.role === "agent", goneTitle: tr("chat.attGone"), goneLabel: tr("chat.attUnavailable"), inlinePreviews: !PUBLIC_LINK() })}${buttons}</div>${tools}</div>`;
|
|
64
64
|
}
|
|
65
65
|
/**
|
|
66
66
|
* #1672: a status line (another instance's message, a daemon notice) is muted, read-only plain text — never Markdown,
|
|
@@ -75,7 +75,7 @@ export function createThread(list, scroller, opts) {
|
|
|
75
75
|
? `<button type="button" class="st-more" data-act="toggleFold"${manyLines ? ` data-lines="${escAttr(lines)}"` : ""}>${escAttr(manyLines ? trf("chat.showAll", lines) : tr("chat.showMore"))}</button>`
|
|
76
76
|
: "";
|
|
77
77
|
const tools = `<div 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>`;
|
|
78
|
-
return `<div class="msg status${more ? " folded" : ""}"><div class="meta"><span class="time">${time}</span></div><div class="body"><div class="st-text">${escAttr(text)}</div>${more}</div>${tools}</div>`;
|
|
78
|
+
return `<div class="msg status-line${more ? " folded" : ""}"><div class="meta"><span class="time">${time}</span></div><div class="body"><div class="st-text">${escAttr(text)}</div>${more}</div>${tools}</div>`;
|
|
79
79
|
}
|
|
80
80
|
/**
|
|
81
81
|
* #1266: an agent reply's buttons. Labels are text (escaped, never Markdown); the click names the set and the index,
|
|
@@ -318,14 +318,32 @@ export function createThread(list, scroller, opts) {
|
|
|
318
318
|
};
|
|
319
319
|
const ui = { state: (name, reason) => { state = name === "starting" || name === "running" ? name : "idle"; refresh(reason || null); } };
|
|
320
320
|
// Nothing is read for Preview on a device that does not allow previews: the button is not even shown there.
|
|
321
|
-
|
|
321
|
+
// A Preview click is newer than any Open in panel still reading (#1704): it claims the panel's turn too — and, its
|
|
322
|
+
// own HTML read, starts only if no newer click claimed meanwhile and no preview was started since (the panel's own
|
|
323
|
+
// Preview): a late read never undoes a newer choice. A close is neither, so it does not drop this click.
|
|
324
|
+
run.onclick = () => {
|
|
325
|
+
if (!P().availability().ok || reading) return; // this card already reading: that click stays the one
|
|
326
|
+
const mine = panel ? (panel.claim(), panel.claims()) : 0, started = P().startCount();
|
|
327
|
+
withCode((c) => {
|
|
328
|
+
if ((panel && panel.claims() !== mine) || P().startCount() !== started) { refresh(); return; }
|
|
329
|
+
P().start(key, holder, c, ui);
|
|
330
|
+
});
|
|
331
|
+
};
|
|
322
332
|
stopB.onclick = () => { if (reading) { reading = 0; refresh(); } else P().stop(key, "stopped", ""); };
|
|
323
|
-
//
|
|
324
|
-
//
|
|
333
|
+
// #1704: this click runs it in the panel, as Preview there would — a running preview moves (it stops here and
|
|
334
|
+
// starts there), an idle one starts there. Whether it can run is the panel's to say: a device that has not allowed
|
|
335
|
+
// previews is offered Allow first (and allowing runs it); where previews are off, nothing runs.
|
|
336
|
+
// An attachment's HTML is read first. The click claims the panel at once, so a newer click (even one still reading)
|
|
337
|
+
// wins: if the panel changed (another click, block, close) or any preview started meanwhile, this one is dropped —
|
|
338
|
+
// a late read never undoes a newer click.
|
|
325
339
|
if (toPanel) toPanel.onclick = () => {
|
|
326
|
-
|
|
327
|
-
if (
|
|
328
|
-
|
|
340
|
+
if (reading) return; // this card already reading: that click stays the one
|
|
341
|
+
if (P().running(key)) P().stop(key, "stopped", "");
|
|
342
|
+
const at = panel.claim(), started = P().startCount();
|
|
343
|
+
withCode((c) => {
|
|
344
|
+
if (panel.version() !== at || P().startCount() !== started) { refresh(); return; }
|
|
345
|
+
panel.open({ key, instance: x.instance, msgKey: msgKey(x), ...(att ? { att } : { n: source.n }), code: c, sender: x.sender, ts: x.ts }, { run: true });
|
|
346
|
+
});
|
|
329
347
|
};
|
|
330
348
|
if (dl) dl.onclick = () => opts.download(code);
|
|
331
349
|
ack.onclick = () => P().ackBanner(); // every card and the panel hear it (onChange)
|
|
@@ -445,7 +463,7 @@ export function createThread(list, scroller, opts) {
|
|
|
445
463
|
if (act === "copyMsg") { const x = msgs.find(y => msgKey(y) === el.dataset.arg); if (x) copyFrom(el, x.text); }
|
|
446
464
|
else if (act === "copyCode") { const pre = el.closest(".codeblock")?.querySelector("pre"); if (pre) copyFrom(el, pre.textContent); }
|
|
447
465
|
else if (act === "toggleFold") {
|
|
448
|
-
const box = el.closest(".codeblock, .msg.status"); if (!box) return;
|
|
466
|
+
const box = el.closest(".codeblock, .msg.status-line"); if (!box) return;
|
|
449
467
|
const folded = box.classList.toggle("folded");
|
|
450
468
|
el.textContent = !folded ? tr("chat.showLess") : el.dataset.lines ? trf("chat.showAll", el.dataset.lines) : tr("chat.showMore");
|
|
451
469
|
} else if (act === "toggleWrap") opts.toggleWrap();
|
package/dist/ui/panel-chat.js
CHANGED
|
@@ -10,7 +10,7 @@ import { html, useEffect, useLayoutEffect, useRef, useState } from "/assets/app-
|
|
|
10
10
|
import { t } from "/assets/app-i18n.js";
|
|
11
11
|
import { appStore, useStore } from "/assets/app-store.js";
|
|
12
12
|
import { useLease } from "/assets/app-ctx.js";
|
|
13
|
-
import {
|
|
13
|
+
import { namesOf, namesStore } from "/assets/instance-nav.js";
|
|
14
14
|
import { PanelHeader, onPanelKey, setTitle, statusClass, statusLabel, openDrawer, requestNewInstance } from "/assets/app-shell.js";
|
|
15
15
|
import { detailsPath } from "/assets/app-route.js";
|
|
16
16
|
import { InstanceSwitch } from "/assets/instance-switch.js";
|
|
@@ -28,7 +28,9 @@ import { confirmedWrite } from "./settings-confirm.js";
|
|
|
28
28
|
import { createChatStore } from "./chat-store.js";
|
|
29
29
|
import { createThread, msgKey } from "./chat-thread.js";
|
|
30
30
|
import { createEmojiIndex } from "./chat-emojis.js";
|
|
31
|
-
import {
|
|
31
|
+
import { pollPublicPreview } from "./preview-status.js";
|
|
32
|
+
import { createMentionIndex } from "./chat-mentions.js";
|
|
33
|
+
import { PreviewPanel, claimPanel, openPanel, panelClaims, panelStore, panelVersion, shownKey } from "./preview-panel.js";
|
|
32
34
|
import { needsArgument, paletteFor, parseCommandLine } from "./chat-commands.js";
|
|
33
35
|
import { installTour, refreshTourSpot } from "./chat-tour.js";
|
|
34
36
|
import { FirstRunCard } from "./first-run.js";
|
|
@@ -45,6 +47,7 @@ export let store = null;
|
|
|
45
47
|
let announceTimer = null;
|
|
46
48
|
/** #1630: which Discord server emoji this page may draw (created with the store, in boot). */
|
|
47
49
|
let emojiIndex = null;
|
|
50
|
+
let mentionIndex = null; // #1682: the names of the mentions shown
|
|
48
51
|
function announce(text) {
|
|
49
52
|
let el = document.getElementById("announcer");
|
|
50
53
|
if (!el) { el = document.createElement("div"); el.id = "announcer"; el.className = "sr-only"; el.setAttribute("role", "status"); el.setAttribute("aria-live", "polite"); el.setAttribute("aria-atomic", "true"); document.body.appendChild(el); }
|
|
@@ -56,11 +59,12 @@ function announce(text) {
|
|
|
56
59
|
|
|
57
60
|
/**
|
|
58
61
|
* This device's preview opt-in: asks once (the app's dialog) and says what it means; turning it off stops every
|
|
59
|
-
* running preview. Resolves to the choice in force.
|
|
62
|
+
* running preview. Resolves to the choice in force. commit(apply): runs `apply` (the change itself) — the panel's Allow
|
|
63
|
+
* wraps it to know which change of the choice is its own (#1704).
|
|
60
64
|
*/
|
|
61
|
-
export async function setPreviewOptIn(on) {
|
|
65
|
+
export async function setPreviewOptIn(on, commit = (apply) => apply()) {
|
|
62
66
|
if (on && !P().optedIn() && !(await confirmDialog({ message: t("chat.pvConfirm"), confirmLabel: t("chat.pvAllowButton") }))) on = false;
|
|
63
|
-
P().setOptIn(on);
|
|
67
|
+
commit(() => P().setOptIn(on));
|
|
64
68
|
// #1665: kept on the host for every device (only a signed-in page writes it; never the public link).
|
|
65
69
|
savePref("preview.optIn", P().optedIn());
|
|
66
70
|
return P().optedIn();
|
|
@@ -73,11 +77,14 @@ export function boot({ stream, boot: bootData, deps = {} }) {
|
|
|
73
77
|
fetch: (...a) => fetch(...a), toast, announce, t, setTimeout: (fn, ms) => setTimeout(fn, ms), confirm: confirmDialog, ...deps,
|
|
74
78
|
});
|
|
75
79
|
emojiIndex = createEmojiIndex((url) => (deps.fetch || fetch)(url, { credentials: "same-origin" }));
|
|
80
|
+
mentionIndex = createMentionIndex((url) => (deps.fetch || fetch)(url, { credentials: "same-origin" }));
|
|
76
81
|
store.attach(stream);
|
|
77
82
|
// #1306: what the server said about previews for this load. The page-wide message and storage listeners this adds
|
|
78
83
|
// belong to the app, once (they are never per mount).
|
|
79
84
|
// #1554: its words in the page's language (chat.pv*); a key the dictionary does not have keeps preview.js's English.
|
|
80
85
|
if (P() && bootData) P().init(bootData, { text: (key, ...v) => { const k = `chat.${key}`, s = t(k, ...v); return s === k ? null : s; } });
|
|
86
|
+
// #1723: the public link's preview was still starting when this page loaded: ask until it is up (or failed).
|
|
87
|
+
if (P() && bootData) pollPublicPreview(P());
|
|
81
88
|
// #1568: the banner's "I understand" lasts until the next sign-in — preview.js is told which sign-in this page is
|
|
82
89
|
// (the session handle, from the one /auth/session read); none (no session, or no AgendAuth): this tab only.
|
|
83
90
|
if (P() && typeof P().setBannerScope === "function") {
|
|
@@ -127,6 +134,9 @@ function useChatTick(name, kinds) {
|
|
|
127
134
|
|
|
128
135
|
// ── The panel ──
|
|
129
136
|
|
|
137
|
+
/** #1722: the chat's title — the name that leads, the other on hover. */
|
|
138
|
+
const headerName = ({ primary, secondary }) => (secondary ? html`<span title=${secondary}>${primary}</span>` : primary);
|
|
139
|
+
|
|
130
140
|
export function ChatPanel({ route, navKey }) {
|
|
131
141
|
const lease = useLease(navKey);
|
|
132
142
|
const app = useStore(appStore);
|
|
@@ -162,6 +172,7 @@ function NotFound({ name }) {
|
|
|
162
172
|
}
|
|
163
173
|
|
|
164
174
|
function ChatView({ name, inst, lease, navKey, exec, awaiting }) {
|
|
175
|
+
const names = useStore(namesStore); // #1722: which name leads (the title)
|
|
165
176
|
const [dialog, setDialog] = useState(null); // "delete" | null
|
|
166
177
|
const [wrap, setWrap] = useState(codeWrap);
|
|
167
178
|
const view = useRef(null), split = useRef(null), thread = useRef(null);
|
|
@@ -197,6 +208,7 @@ function ChatView({ name, inst, lease, navKey, exec, awaiting }) {
|
|
|
197
208
|
try { const res = await fetch(`/ui/${verb}/${encodeURIComponent(name)}`, { method: "POST", headers: { "Content-Type": "application/json" } }); r = await res.json(); }
|
|
198
209
|
catch (err) { r = { error: err && err.message ? err.message : t("chat.disconnected") }; }
|
|
199
210
|
if (r && r.error) toast(r.error, false);
|
|
211
|
+
else if (r && r.held) toast(r.message);
|
|
200
212
|
else toast(t(verb === "start" ? "chat.started" : verb === "stop" ? "chat.stoppedInst" : "chat.restarted", name));
|
|
201
213
|
};
|
|
202
214
|
const items = [
|
|
@@ -214,14 +226,14 @@ function ChatView({ name, inst, lease, navKey, exec, awaiting }) {
|
|
|
214
226
|
${inst.model ? html`<button type="button" class="hd-chip" title=${t("chat.chipModel", inst.model)} aria-label=${t("chat.chipModel", inst.model)} onClick=${() => pick("model")}>${inst.model}</button>` : null}
|
|
215
227
|
${inst.effort ? html`<button type="button" class="hd-chip" title=${t("chat.chipEffort", inst.effort)} aria-label=${t("chat.chipEffort", inst.effort)} onClick=${() => pick("effort")}>${inst.effort}</button>` : null}`;
|
|
216
228
|
return html`<div class=${`panel p-chat${wrap ? " wrap-code" : ""}`} ref=${view}>
|
|
217
|
-
<${PanelHeader} title=${
|
|
229
|
+
<${PanelHeader} title=${headerName(namesOf(inst || { name }, names.primary))} sub=${sub} nav=${html`<${InstanceSwitch} name=${name} current="chat" />`}><${HeaderTools} navKey=${navKey} /><${Menu} items=${items} label=${t("app.more")} /></${PanelHeader}>
|
|
218
230
|
<div class="chat-split" ref=${split}>
|
|
219
231
|
<div class="chat-main">
|
|
220
232
|
<${Thread} name=${name} th=${thread} />
|
|
221
233
|
<${Dock} name=${name} inst=${inst} lease=${lease} exec=${exec} awaiting=${awaiting} />
|
|
222
234
|
</div>
|
|
223
235
|
<${PreviewPanel} name=${name} split=${split} msgs=${() => store.state.msgs[name] || []} subscribe=${(fn) => store.subscribe(fn)}
|
|
224
|
-
keyOf=${msgKey} reveal=${(k) => thread.current && thread.current.reveal(k)} download=${downloadHtml} allow=${() => setPreviewOptIn(true)} />
|
|
236
|
+
keyOf=${msgKey} reveal=${(k) => thread.current && thread.current.reveal(k)} download=${downloadHtml} allow=${(commit) => setPreviewOptIn(true, commit)} />
|
|
225
237
|
</div>
|
|
226
238
|
<${LightboxHost} />
|
|
227
239
|
<div class="drop-overlay" aria-hidden="true"><div class="drop-card"><${Icon} name="attach" size=${32} /><span>${t("chat.dropHere")}</span></div></div>
|
|
@@ -240,14 +252,17 @@ function Thread({ name, th }) {
|
|
|
240
252
|
setPreviewOptIn, copyText, download: downloadHtml, toggleWrap,
|
|
241
253
|
clickReplyButton: (id, index) => store.clickReplyButton(name, id, index), // #1266
|
|
242
254
|
replyButtonBusy: (id) => store.state.rbBusy.has(id),
|
|
243
|
-
panel: { shown: shownKey, open: (spec, o) => openPanel(spec, o) }, // #1481
|
|
255
|
+
panel: { shown: shownKey, open: (spec, o) => openPanel(spec, o), version: panelVersion, claim: claimPanel, claims: panelClaims }, // #1481, #1704
|
|
244
256
|
openImage: openLightbox, // an image, full size, in the page
|
|
245
257
|
emojis: (id) => !!emojiIndex && emojiIndex.known(id), // #1630: the fleet's server emoji
|
|
258
|
+
mentions: (kind, id) => (mentionIndex ? mentionIndex.name(kind, id) : null), // #1682: mention names
|
|
246
259
|
});
|
|
247
260
|
th.current = thread;
|
|
248
261
|
// #1630: the server-emoji list is read once a message shows a tag; when it arrives, those messages are drawn again.
|
|
249
|
-
|
|
262
|
+
// #1682: the same for mention names — asked for the ids the messages carry; when names arrive, drawn again.
|
|
263
|
+
const wantEmojis = (msgs) => { if (emojiIndex && emojiIndex.wants(msgs)) emojiIndex.ensure(); if (mentionIndex) mentionIndex.ensure(msgs); };
|
|
250
264
|
const offEmojis = emojiIndex ? emojiIndex.subscribe(() => thread.render(store.state.msgs[name] || [])) : () => {};
|
|
265
|
+
const offMentions = mentionIndex ? mentionIndex.subscribe(() => thread.render(store.state.msgs[name] || [])) : () => {};
|
|
251
266
|
thread.render(store.state.msgs[name] || [], { restore: store.state.scrollMemo[name] ?? null });
|
|
252
267
|
wantEmojis(store.state.msgs[name]);
|
|
253
268
|
const off = store.subscribe((instance, kind) => {
|
|
@@ -262,7 +277,7 @@ function Thread({ name, th }) {
|
|
|
262
277
|
sc.addEventListener("scroll", onScroll, { passive: true });
|
|
263
278
|
ls.addEventListener("click", thread.onClick);
|
|
264
279
|
return () => {
|
|
265
|
-
off(); offPv(); offPanel(); offEmojis();
|
|
280
|
+
off(); offPv(); offPanel(); offEmojis(); offMentions();
|
|
266
281
|
sc.removeEventListener("scroll", onScroll);
|
|
267
282
|
ls.removeEventListener("click", thread.onClick);
|
|
268
283
|
thread.dispose(); // the whole thread goes: every preview in it stops first
|
|
@@ -479,7 +494,7 @@ function DeleteDialog({ name, onClose }) {
|
|
|
479
494
|
<button type="button" class="btn btn-danger" disabled=${typed !== want || busy} onClick=${go}>${t("chat.deleteGo")}</button>`}>
|
|
480
495
|
<p>${t("chat.deleteHelp", name)}</p>
|
|
481
496
|
<label class="field"><span class="sr-only">${t("chat.deleteHelp", name)}</span>
|
|
482
|
-
<input type="text" value=${typed} autocomplete="off" spellcheck
|
|
497
|
+
<input type="text" value=${typed} autocomplete="off" spellcheck=${false} placeholder=${want} onInput=${(e) => setTyped(e.target.value)}
|
|
483
498
|
onKeyDown=${(e) => { if (e.key === "Enter") go(); }} /></label>
|
|
484
499
|
</${Dialog}>`;
|
|
485
500
|
}
|
package/dist/ui/panel-details.js
CHANGED
|
@@ -73,11 +73,13 @@ function DetailsView({ name, inst, navKey, exec, awaiting }) {
|
|
|
73
73
|
try { const res = await fetch(`/ui/${verb}/${encodeURIComponent(name)}`, { method: "POST", headers: { "Content-Type": "application/json" } }); r = await res.json(); }
|
|
74
74
|
catch (err) { r = { error: err && err.message ? err.message : t("chat.disconnected") }; }
|
|
75
75
|
if (r && r.error) toast(r.error, false);
|
|
76
|
+
else if (r && r.held) toast(r.message);
|
|
76
77
|
else toast(t(verb === "start" ? "chat.started" : verb === "stop" ? "chat.stoppedInst" : "chat.restarted", name));
|
|
77
78
|
});
|
|
78
79
|
const pauseWake = (verb) => act(verb, async () => {
|
|
79
80
|
const res = await api(`/api/settings/instances/${encodeURIComponent(name)}/${verb}`, { method: "POST" }).catch(() => ({ ok: false, body: {} }));
|
|
80
81
|
if (!res.ok) toast((res.body && res.body.error) || t("chat.dActionFailed"), false);
|
|
82
|
+
else if (res.body && res.body.held) toast(res.body.message);
|
|
81
83
|
else toast(t(verb === "pause" ? "chat.dPaused" : "chat.dWoken", name));
|
|
82
84
|
});
|
|
83
85
|
// A ClassicBot room (classicBot.yaml) keeps Classic's split: its own Settings dialog, and only the actions Settings'
|