@songsid/agend 2.2.0-beta.6 → 2.2.0-beta.7
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-instructions.md +6 -2
- package/dist/agent-cli.js +9 -5
- package/dist/agent-cli.js.map +1 -1
- package/dist/backend/muse.d.ts +26 -0
- package/dist/backend/muse.js +131 -0
- package/dist/backend/muse.js.map +1 -1
- package/dist/channel/adapters/discord.js +12 -1
- package/dist/channel/adapters/discord.js.map +1 -1
- package/dist/channel/adapters/telegram.js +6 -0
- package/dist/channel/adapters/telegram.js.map +1 -1
- package/dist/channel/mcp-tools.js +3 -3
- package/dist/channel/mcp-tools.js.map +1 -1
- package/dist/channel/types.d.ts +3 -0
- package/dist/cross-instance-envelope.js +2 -0
- package/dist/cross-instance-envelope.js.map +1 -1
- package/dist/daemon.d.ts +6 -0
- package/dist/daemon.js +124 -54
- package/dist/daemon.js.map +1 -1
- package/dist/delivery-outbox.d.ts +27 -0
- package/dist/delivery-outbox.js +175 -6
- package/dist/delivery-outbox.js.map +1 -1
- package/dist/fleet-manager.d.ts +28 -1
- package/dist/fleet-manager.js +203 -40
- package/dist/fleet-manager.js.map +1 -1
- package/dist/general-knowledge/skills/cross-instance-messaging/SKILL.md +14 -1
- package/dist/general-knowledge/skills/worker-collaboration/SKILL.md +4 -0
- package/dist/human-delivery-receipts.d.ts +83 -0
- package/dist/human-delivery-receipts.js +194 -0
- package/dist/human-delivery-receipts.js.map +1 -0
- package/dist/instructions.d.ts +1 -1
- package/dist/instructions.js +1 -1
- package/dist/instructions.js.map +1 -1
- package/dist/locale.js +8 -0
- package/dist/locale.js.map +1 -1
- package/dist/outbound-handlers.d.ts +3 -0
- package/dist/outbound-handlers.js +20 -4
- package/dist/outbound-handlers.js.map +1 -1
- package/dist/outbound-schemas.d.ts +15 -13
- package/dist/outbound-schemas.js +5 -0
- package/dist/outbound-schemas.js.map +1 -1
- package/dist/public-link-progress.d.ts +1 -1
- package/dist/public-link-progress.js +8 -2
- package/dist/public-link-progress.js.map +1 -1
- package/dist/public-preview.d.ts +2 -1
- package/dist/public-preview.js +8 -5
- package/dist/public-preview.js.map +1 -1
- package/dist/public-web-link.d.ts +4 -1
- package/dist/public-web-link.js +27 -10
- package/dist/public-web-link.js.map +1 -1
- package/dist/reply-buttons-controller.d.ts +3 -0
- package/dist/reply-buttons-controller.js +3 -2
- package/dist/reply-buttons-controller.js.map +1 -1
- package/dist/topic-commands.d.ts +3 -2
- package/dist/topic-commands.js +14 -4
- package/dist/topic-commands.js.map +1 -1
- package/dist/tunnel/cloudflared.d.ts +7 -15
- package/dist/tunnel/cloudflared.js +36 -1
- package/dist/tunnel/cloudflared.js.map +1 -1
- package/dist/tunnel/types.d.ts +5 -1
- package/dist/tunnel/types.js.map +1 -1
- package/dist/ui/chat-strings.js +8 -2
- package/dist/ui/chat-thread.js +24 -4
- package/dist/ui/chat-time.js +80 -0
- package/dist/ui/preview-panel.js +7 -1
- package/dist/ui/preview.js +5 -1
- package/dist/ui/shared/app.css +4 -1
- package/dist/web-api.d.ts +2 -0
- package/dist/web-api.js +8 -1
- package/dist/web-api.js.map +1 -1
- package/dist/web-commands.d.ts +2 -2
- package/dist/web-commands.js +3 -2
- package/dist/web-commands.js.map +1 -1
- package/dist/web-reply-files.d.ts +45 -0
- package/dist/web-reply-files.js +223 -0
- package/dist/web-reply-files.js.map +1 -0
- package/dist/web-upload.d.ts +17 -4
- package/dist/web-upload.js +64 -13
- package/dist/web-upload.js.map +1 -1
- package/package.json +1 -1
package/dist/ui/chat-thread.js
CHANGED
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
import "./chat-render.js";
|
|
10
10
|
import "./preview.js";
|
|
11
11
|
import { loadHtmlAttachment } from "./html-attachment.js";
|
|
12
|
+
import { chatTime, chatTimeFull, onDayChange } from "./chat-time.js";
|
|
12
13
|
|
|
13
14
|
const R = () => globalThis.AgendChatRender;
|
|
14
15
|
/** #1589: the public link shows attachments as downloads only (its page says so: <body data-public-link="1">). */
|
|
@@ -49,18 +50,33 @@ export function createThread(list, scroller, opts) {
|
|
|
49
50
|
const cardRefresh = new WeakMap(); // card node → re-read availability (weak: a card that left takes its source with it)
|
|
50
51
|
const tr = opts.t, trf = opts.tf;
|
|
51
52
|
const stopIn = (node) => (P() ? P().stopIn(node) : []);
|
|
53
|
+
/** #1770: write a message node's time label for now; unchanged text is not touched. */
|
|
54
|
+
function timeLabel(node) {
|
|
55
|
+
const el = node.querySelector(".meta .time[data-ts]");
|
|
56
|
+
if (!el) return;
|
|
57
|
+
const v = chatTime(el.dataset.ts, { yesterday: (hm) => trf("chat.yesterdayAt", hm) });
|
|
58
|
+
if (el.textContent !== v) el.textContent = v;
|
|
59
|
+
}
|
|
60
|
+
// #1770: "today" ends at the fleet's midnight; the labels are rewritten then (and on every render), while there are any.
|
|
61
|
+
let offDay = null;
|
|
62
|
+
function armDay() {
|
|
63
|
+
if (nodes.size && !offDay) offDay = onDayChange(() => { for (const v of nodes.values()) timeLabel(v.node); });
|
|
64
|
+
else if (!nodes.size && offDay) { offDay(); offDay = null; }
|
|
65
|
+
}
|
|
52
66
|
|
|
53
67
|
const TICKS = () => ({ queued: tr("chat.tick_queued"), processing: tr("chat.tick_processing"), delivered: tr("chat.tick_delivered"), failed: tr("chat.tick_failed"), cancelled: tr("chat.tick_cancelled") });
|
|
54
68
|
|
|
55
69
|
function msgHtml(x) {
|
|
56
|
-
|
|
70
|
+
// #1770: the label ("17:38", "Yesterday 17:38", "10/11 17:38") depends on today, so it is not part of the html a node
|
|
71
|
+
// is kept by: it is written into the node (timeLabels) — crossing midnight relabels in place and reloads no preview.
|
|
72
|
+
const time = x.ts ? `<span class="time" data-ts="${escAttr(x.ts)}" title="${escAttr(chatTimeFull(x.ts))}"></span>` : `<span class="time"></span>`;
|
|
57
73
|
if (x.role === "status") return statusHtml(x, time);
|
|
58
74
|
const u = opts.isUser(x);
|
|
59
75
|
// renderMarkdown escapes the whole text before it adds any tag of its own (chat-render.js).
|
|
60
76
|
const ticks = u && x.delivery ? R().deliveryHtml(x.delivery, TICKS()) : "";
|
|
61
77
|
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
78
|
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
|
|
79
|
+
return `<div class="msg ${u ? "user" : "agent"}"><div class="meta"><span class="sender">${escAttr(x.sender)}</span>${time}${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
80
|
}
|
|
65
81
|
/**
|
|
66
82
|
* #1672: a status line (another instance's message, a daemon notice) is muted, read-only plain text — never Markdown,
|
|
@@ -75,7 +91,7 @@ export function createThread(list, scroller, opts) {
|
|
|
75
91
|
? `<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
92
|
: "";
|
|
77
93
|
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-line${more ? " folded" : ""}"><div class="meta"
|
|
94
|
+
return `<div class="msg status-line${more ? " folded" : ""}"><div class="meta">${time}</div><div class="body"><div class="st-text">${escAttr(text)}</div>${more}</div>${tools}</div>`;
|
|
79
95
|
}
|
|
80
96
|
/**
|
|
81
97
|
* #1266: an agent reply's buttons. Labels are text (escaped, never Markdown); the click names the set and the index,
|
|
@@ -97,6 +113,7 @@ export function createThread(list, scroller, opts) {
|
|
|
97
113
|
tpl.innerHTML = html;
|
|
98
114
|
const node = tpl.content.firstElementChild;
|
|
99
115
|
decorateCode(node);
|
|
116
|
+
timeLabel(node);
|
|
100
117
|
if (x) decorateHtmlCards(node, x, stoppedKeys || []);
|
|
101
118
|
if (x) decorateTextCards(node, x);
|
|
102
119
|
return node;
|
|
@@ -378,6 +395,7 @@ export function createThread(list, scroller, opts) {
|
|
|
378
395
|
if (!msgs.length) {
|
|
379
396
|
for (const v of nodes.values()) stopIn(v.node);
|
|
380
397
|
nodes.clear();
|
|
398
|
+
armDay();
|
|
381
399
|
list.textContent = "";
|
|
382
400
|
opts.onEmpty(true);
|
|
383
401
|
return;
|
|
@@ -394,12 +412,13 @@ export function createThread(list, scroller, opts) {
|
|
|
394
412
|
const node = msgNode(html, x, stopped);
|
|
395
413
|
if (have) have.node.replaceWith(node); else added++;
|
|
396
414
|
have = { html, node }; nodes.set(key, have);
|
|
397
|
-
}
|
|
415
|
+
} else timeLabel(have.node);
|
|
398
416
|
const want = prev ? prev.nextSibling : list.firstChild;
|
|
399
417
|
// A node already in the list is being moved: its preview stops first. A new node (still in its template) has none.
|
|
400
418
|
if (have.node !== want) { if (have.node.parentNode === list) stopIn(have.node); list.insertBefore(have.node, want); }
|
|
401
419
|
prev = have.node;
|
|
402
420
|
}
|
|
421
|
+
armDay();
|
|
403
422
|
if ("restore" in renderOpts) {
|
|
404
423
|
unseen = 0;
|
|
405
424
|
if (renderOpts.restore == null) toBottom();
|
|
@@ -478,6 +497,7 @@ export function createThread(list, scroller, opts) {
|
|
|
478
497
|
if (ro) ro.disconnect();
|
|
479
498
|
if (P()) P().stopAll("leave");
|
|
480
499
|
nodes.clear();
|
|
500
|
+
armDay();
|
|
481
501
|
}
|
|
482
502
|
|
|
483
503
|
return { render, onScroll, onClick, jumpLatest, reveal, refreshCards, dispose, nodes, get unseen() { return unseen; } };
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
// #1770: the time a chat line shows, read in the fleet's zone (the one chat-logs, fleet.log and the #1586 DMs use) —
|
|
2
|
+
// "17:38" today, "Yesterday 17:38", "10/11 17:38" earlier this year, "2025/10/11 17:38" before. The hour and minute keep
|
|
3
|
+
// the browser's own format (12- or 24-hour), as they always had. No imports: the thread, the preview panel and the
|
|
4
|
+
// tests read it as it is.
|
|
5
|
+
|
|
6
|
+
const cache = new Map();
|
|
7
|
+
/** One formatter per (kind, zone, locale): a thread may label 500 lines on every render. */
|
|
8
|
+
function fmt(kind, tz, locale) {
|
|
9
|
+
const key = `${kind}|${tz || ""}|${locale || ""}`;
|
|
10
|
+
let f = cache.get(key);
|
|
11
|
+
if (!f) {
|
|
12
|
+
const o = kind === "hm" ? { hour: "2-digit", minute: "2-digit" }
|
|
13
|
+
: kind === "ymd" ? { year: "numeric", month: "numeric", day: "numeric", hour: "numeric", minute: "numeric", second: "numeric", hourCycle: "h23" }
|
|
14
|
+
: { year: "numeric", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", timeZoneName: "short" };
|
|
15
|
+
f = new Intl.DateTimeFormat(kind === "ymd" ? "en-US" : (locale || []), { ...o, timeZone: tz || undefined });
|
|
16
|
+
cache.set(key, f);
|
|
17
|
+
}
|
|
18
|
+
return f;
|
|
19
|
+
}
|
|
20
|
+
/** `tz` when this browser knows it, else undefined (the browser's own zone): a label must still be drawn. */
|
|
21
|
+
function known(tz) {
|
|
22
|
+
if (!tz) return undefined;
|
|
23
|
+
try { fmt("ymd", tz); return tz; } catch { return undefined; }
|
|
24
|
+
}
|
|
25
|
+
/** The fleet's zone, as the page was served it (<body data-fleet-tz>); undefined when absent or unknown here. */
|
|
26
|
+
export function fleetTz() { return known(globalThis.document?.body?.dataset?.fleetTz); }
|
|
27
|
+
|
|
28
|
+
const toMs = (ts) => (typeof ts === "number" ? ts : Date.parse(String(ts || "")));
|
|
29
|
+
function wall(ms, tz) {
|
|
30
|
+
const p = {};
|
|
31
|
+
for (const x of fmt("ymd", tz).formatToParts(ms)) p[x.type] = Number(x.value);
|
|
32
|
+
return p;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* The label for `ts` (ISO string or epoch ms), "" when it cannot be read. opts: tz (default the fleet's), now (epoch ms),
|
|
37
|
+
* yesterday(hm) → the word for "yesterday" around hm (default: hm alone), locale (tests).
|
|
38
|
+
*/
|
|
39
|
+
export function chatTime(ts, opts = {}) {
|
|
40
|
+
const ms = toMs(ts);
|
|
41
|
+
if (!Number.isFinite(ms)) return "";
|
|
42
|
+
const tz = "tz" in opts ? known(opts.tz) : fleetTz();
|
|
43
|
+
const hm = fmt("hm", tz, opts.locale).format(ms);
|
|
44
|
+
const d = wall(ms, tz), today = wall(opts.now ?? Date.now(), tz);
|
|
45
|
+
if (d.year === today.year && d.month === today.month && d.day === today.day) return hm;
|
|
46
|
+
const y = new Date(Date.UTC(today.year, today.month - 1, today.day - 1));
|
|
47
|
+
if (d.year === y.getUTCFullYear() && d.month === y.getUTCMonth() + 1 && d.day === y.getUTCDate()) return opts.yesterday ? opts.yesterday(hm) : hm;
|
|
48
|
+
return d.year === today.year ? `${d.month}/${d.day} ${hm}` : `${d.year}/${d.month}/${d.day} ${hm}`;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** The full date, time and zone of `ts`, for a tooltip; "" when it cannot be read. */
|
|
52
|
+
export function chatTimeFull(ts, opts = {}) {
|
|
53
|
+
const ms = toMs(ts);
|
|
54
|
+
if (!Number.isFinite(ms)) return "";
|
|
55
|
+
return fmt("full", "tz" in opts ? known(opts.tz) : fleetTz(), opts.locale).format(ms);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/** Milliseconds until the fleet's next midnight (when "today" labels change), at most an hour (a DST day self-corrects). */
|
|
59
|
+
export function msToNextDay(now = Date.now(), tz = fleetTz()) {
|
|
60
|
+
const w = wall(now, known(tz));
|
|
61
|
+
const into = ((w.hour * 60 + w.minute) * 60 + w.second) * 1000 + (now % 1000);
|
|
62
|
+
return Math.max(1000, Math.min(3_600_000, 86_400_000 - into + 1000));
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Call `fn` when the fleet's day may have changed — at its next midnight, then again for each one after (an hour at
|
|
67
|
+
* most between looks, so a DST day or a late timer corrects itself). Each subscriber holds its own timer, and no
|
|
68
|
+
* module-wide state: the unsubscribe it returns leaves nothing armed.
|
|
69
|
+
*/
|
|
70
|
+
export function onDayChange(fn) {
|
|
71
|
+
let timer = null, live = true;
|
|
72
|
+
const arm = () => {
|
|
73
|
+
timer = setTimeout(() => {
|
|
74
|
+
timer = null;
|
|
75
|
+
try { fn(); } finally { if (live) arm(); }
|
|
76
|
+
}, msToNextDay());
|
|
77
|
+
};
|
|
78
|
+
arm();
|
|
79
|
+
return () => { live = false; if (timer !== null) { clearTimeout(timer); timer = null; } };
|
|
80
|
+
}
|
package/dist/ui/preview-panel.js
CHANGED
|
@@ -16,6 +16,7 @@ import { Icon } from "/assets/ui-icons.js";
|
|
|
16
16
|
import "./chat-render.js";
|
|
17
17
|
import "./preview.js";
|
|
18
18
|
import { loadHtmlAttachment } from "./html-attachment.js";
|
|
19
|
+
import { chatTime, onDayChange } from "./chat-time.js";
|
|
19
20
|
|
|
20
21
|
const R = () => globalThis.AgendChatRender;
|
|
21
22
|
const P = () => globalThis.AgendPreview;
|
|
@@ -112,7 +113,8 @@ export function clampWidth(w, total) {
|
|
|
112
113
|
return Math.round(Math.min(max, Math.max(MIN_PANEL, w)));
|
|
113
114
|
}
|
|
114
115
|
|
|
115
|
-
|
|
116
|
+
/** #1770: as the thread shows it — the fleet's zone, with the day when it is not today. */
|
|
117
|
+
const timeOf = (ts) => (ts ? chatTime(ts, { yesterday: (hm) => t("chat.yesterdayAt", hm) }) : "");
|
|
116
118
|
|
|
117
119
|
/**
|
|
118
120
|
* The panel, inside the chat's split (`split`: that element — the divider sets its width there, through CSSOM).
|
|
@@ -140,6 +142,10 @@ export function PreviewPanel({ name, split, msgs, subscribe, keyOf, reveal, down
|
|
|
140
142
|
useEffect(() => (P() ? P().onChange(() => { if (pending.current && ownAllow.current !== pending.current) pending.current = 0; choice(n => n + 1); }) : undefined), []);
|
|
141
143
|
// Leaving the chat (another instance, another panel) closes the panel: its frame stops with the thread's.
|
|
142
144
|
useEffect(() => () => closePanel(), []);
|
|
145
|
+
// #1770: the source and newer-version labels say the day as the thread does — drawn again when the fleet's day
|
|
146
|
+
// changes, while a block is open. A render: the frame and the run are left as they are.
|
|
147
|
+
const [, dayTick] = useState(0);
|
|
148
|
+
useEffect(() => (open ? onDayChange(() => dayTick(n => n + 1)) : undefined), [!!open]);
|
|
143
149
|
|
|
144
150
|
const ui = { state: (s, reason) => setRun({ state: s === "starting" || s === "running" ? s : "idle", reason: reason || "" }) };
|
|
145
151
|
const start = () => {
|
package/dist/ui/preview.js
CHANGED
|
@@ -31,7 +31,11 @@
|
|
|
31
31
|
var cfg = { dashboardOrigin: "", previewOrigin: "", boot: "", reason: "", reasonCode: "", detail: "" };
|
|
32
32
|
// Why it failed, in English when the app's dictionary has no word for it (chat-strings.js pvFail_*).
|
|
33
33
|
var FAIL_EN = { exited: "its address closed unexpectedly", "spawn-failed": "cloudflared could not start for it", "no-address": "no address was given for it",
|
|
34
|
-
unreachable: "its address could not be reached", "lease-held": "an earlier preview tunnel is still being cleaned up", "gateway-failed": "its local listener could not start"
|
|
34
|
+
unreachable: "its address could not be reached", "lease-held": "an earlier preview tunnel is still being cleaned up", "gateway-failed": "its local listener could not start",
|
|
35
|
+
// #1767: what cloudflared's exit before an address really was.
|
|
36
|
+
"rate-limited": "Cloudflare is limiting new temporary links from this machine — try again in a while",
|
|
37
|
+
"provisioning-failed": "Cloudflare refused to create its address right now", "process-exited": "cloudflared stopped before it gave an address",
|
|
38
|
+
"bad-address": "Cloudflare gave an address that could not be used" };
|
|
35
39
|
// #1554: the page's words. `say(key, english, …values)` asks the app's dictionary (init's opts.text) and keeps the
|
|
36
40
|
// English here when it has none — so this file still works, and reads the same, without the app.
|
|
37
41
|
var text = null;
|
package/dist/ui/shared/app.css
CHANGED
|
@@ -336,7 +336,10 @@ html:has(.shell), html:has(.shell) body { overflow: hidden; }
|
|
|
336
336
|
.msg .time { font-family: var(--font-mono); white-space: nowrap; flex: none; }
|
|
337
337
|
.msg.user { align-self: flex-end; max-width: min(80%, 620px); }
|
|
338
338
|
.msg.user .meta { justify-content: flex-end; }
|
|
339
|
-
|
|
339
|
+
/* #1773: the bubble hugs its text. The message is as wide as its widest child — usually the meta row (sender, a time
|
|
340
|
+
such as 「昨天 下午03:58」, ticks) — and a block body would stretch to it; fit-content keeps a short message short, on
|
|
341
|
+
the right under its meta, and a long one still wraps at the message's max-width. */
|
|
342
|
+
.msg.user .body { background: var(--user-bubble); border-radius: var(--r-xl); padding: 10px var(--s-4); width: fit-content; max-width: 100%; margin-left: auto; }
|
|
340
343
|
.msg.agent { align-self: stretch; }
|
|
341
344
|
/* #1672: a status line (another instance's message, a daemon notice): muted plain text, no bubble; a long one folds.
|
|
342
345
|
Its class is `status-line`, never `status`: that is the header's inline-flex badge class, and on a message it turned
|
package/dist/web-api.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type HumanOrigin } from "./human-delivery-receipts.js";
|
|
1
2
|
import type { CachedImage } from "./web-images.js";
|
|
2
3
|
import type { SettingsExecution } from "./settings-transaction.js";
|
|
3
4
|
import type { PaneContextSource } from "./pane-context-cache.js";
|
|
@@ -106,6 +107,7 @@ export interface WebApiContext {
|
|
|
106
107
|
sendClassicWebEcho?(instance: string, text: string): Promise<number>;
|
|
107
108
|
/** false: definitely not delivered (the instance's IPC is gone, or it was restarted meanwhile). */
|
|
108
109
|
deliverToInstance(instanceName: string, payload: Record<string, unknown>): Promise<boolean | void>;
|
|
110
|
+
deliverHumanToInstance?(instanceName: string, payload: Record<string, unknown>, origin: HumanOrigin, originalBody: string): Promise<boolean | void>;
|
|
109
111
|
getUiStatus(): unknown;
|
|
110
112
|
/** Current owned pane reader shared with status; absent means context is unavailable. */
|
|
111
113
|
getPaneContextSource?(name: string): PaneContextSource | null;
|
package/dist/web-api.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { webHumanOrigin } from "./human-delivery-receipts.js";
|
|
1
2
|
import { withSpawnHoldReply } from "./spawn-hold-reply.js";
|
|
2
3
|
import { binaryProbe } from "./binary-probe.js";
|
|
3
4
|
import { settingsRequestExecution, settingsWrite, isSettingsReplay } from "./settings-request-capability.js";
|
|
@@ -32,6 +33,7 @@ import { commitTeamCreate, commitTeamUpdate } from "./outbound-handlers.js";
|
|
|
32
33
|
import { parseMentionQuery } from "./web-mentions.js";
|
|
33
34
|
import { authorizeExplicitInstanceRemoval } from "./instance-removal.js";
|
|
34
35
|
import { measureSyncWork } from "./sync-work-attribution.js";
|
|
36
|
+
import { resolveTz } from "./tz-utils.js";
|
|
35
37
|
// ── Strict public-facing schemas ────────────────────────────────────────────
|
|
36
38
|
// web-api endpoints must reject unknown fields so the dashboard cannot inject
|
|
37
39
|
// internal-only flags that would reach handleCreate/scheduler/config writers.
|
|
@@ -1403,7 +1405,10 @@ function handleSendMessage(req, res, ctx) {
|
|
|
1403
1405
|
}) : undefined;
|
|
1404
1406
|
let delivered;
|
|
1405
1407
|
try {
|
|
1406
|
-
|
|
1408
|
+
const deliver = (name, payload) => ctx.deliverHumanToInstance
|
|
1409
|
+
? ctx.deliverHumanToInstance(name, payload, webHumanOrigin(), typed)
|
|
1410
|
+
: ctx.deliverToInstance(name, payload);
|
|
1411
|
+
delivered = await deliver(instance, {
|
|
1407
1412
|
type: "fleet_inbound",
|
|
1408
1413
|
content: delivery.text,
|
|
1409
1414
|
targetSession: instance,
|
|
@@ -1607,6 +1612,8 @@ function shellBodyTag(req, ctx, mode) {
|
|
|
1607
1612
|
+ `${p?.detail ? ` data-preview-detail="${attr(p.detail)}"` : ""}`
|
|
1608
1613
|
// #1523 N3: whether the fleet serves /api/ai-usage (web.usage_panel), for every page's ◔.
|
|
1609
1614
|
+ ` data-usage-panel="${ctx.fleetConfig?.web?.usage_panel === false ? "0" : "1"}"`
|
|
1615
|
+
// #1770: the fleet's zone (chat-logs' and fleet.log's), in which the chat reads its message times and days.
|
|
1616
|
+
+ ` data-fleet-tz="${attr(resolveTz())}"`
|
|
1610
1617
|
// #1589: the public link shows attachments as downloads only (no inline text or media): its scope is unchanged.
|
|
1611
1618
|
+ `${gatewayRequestContext(req) ? ' data-public-link="1"' : ""}>`;
|
|
1612
1619
|
}
|