@songsid/agend 2.3.0-beta.1 → 2.3.0-beta.3
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 +5 -5
- package/dist/agent-cli.js.map +1 -1
- package/dist/agent-file-read.d.ts +11 -6
- package/dist/agent-file-read.js +32 -17
- package/dist/agent-file-read.js.map +1 -1
- package/dist/agent-whats-new.js +10 -13
- package/dist/agent-whats-new.js.map +1 -1
- package/dist/auth-api.js +10 -5
- package/dist/auth-api.js.map +1 -1
- package/dist/backend/claude-code.d.ts +2 -2
- package/dist/backend/claude-code.js +10 -5
- package/dist/backend/claude-code.js.map +1 -1
- package/dist/backend/types.d.ts +13 -0
- package/dist/backend/types.js +10 -0
- package/dist/backend/types.js.map +1 -1
- package/dist/cache-analysis.d.ts +47 -1
- package/dist/cache-analysis.js +68 -8
- package/dist/cache-analysis.js.map +1 -1
- package/dist/cache-report-tool.d.ts +17 -0
- package/dist/cache-report-tool.js +40 -0
- package/dist/cache-report-tool.js.map +1 -0
- package/dist/cache-service.d.ts +15 -0
- package/dist/cache-service.js +26 -1
- package/dist/cache-service.js.map +1 -1
- package/dist/channel/mcp-tools.js +9 -3
- package/dist/channel/mcp-tools.js.map +1 -1
- package/dist/classic-channel-manager.d.ts +8 -3
- package/dist/classic-channel-manager.js +10 -3
- package/dist/classic-channel-manager.js.map +1 -1
- package/dist/cli.js +7 -3
- package/dist/cli.js.map +1 -1
- package/dist/config-validator.js +5 -1
- package/dist/config-validator.js.map +1 -1
- package/dist/daemon.js +5 -5
- package/dist/daemon.js.map +1 -1
- package/dist/delivery-outbox.js +5 -0
- package/dist/delivery-outbox.js.map +1 -1
- package/dist/fleet-manager.d.ts +71 -3
- package/dist/fleet-manager.js +256 -45
- package/dist/fleet-manager.js.map +1 -1
- package/dist/fleet-traffic.d.ts +38 -0
- package/dist/fleet-traffic.js +96 -0
- package/dist/fleet-traffic.js.map +1 -0
- package/dist/general-knowledge/skills/credential-profiles/SKILL.md +20 -5
- package/dist/general-knowledge/skills/multi-channel/SKILL.md +1 -1
- package/dist/general-knowledge/skills/web-appearance/SKILL.md +149 -5
- package/dist/general-knowledge/skills/web-dashboard/SKILL.md +398 -0
- package/dist/locale.js +6 -4
- package/dist/locale.js.map +1 -1
- package/dist/memory-hogs.d.ts +27 -0
- package/dist/memory-hogs.js +124 -0
- package/dist/memory-hogs.js.map +1 -0
- package/dist/outbound-handlers.d.ts +4 -0
- package/dist/outbound-handlers.js +74 -1
- package/dist/outbound-handlers.js.map +1 -1
- package/dist/outbound-schemas.d.ts +98 -0
- package/dist/outbound-schemas.js +56 -0
- package/dist/outbound-schemas.js.map +1 -1
- package/dist/public-web-gateway.js +1 -1
- package/dist/public-web-gateway.js.map +1 -1
- package/dist/scheduler/scheduler.d.ts +12 -0
- package/dist/scheduler/scheduler.js +83 -10
- package/dist/scheduler/scheduler.js.map +1 -1
- package/dist/service-installer.d.ts +2 -1
- package/dist/service-installer.js +18 -3
- package/dist/service-installer.js.map +1 -1
- package/dist/tmux-manager.d.ts +5 -0
- package/dist/tmux-manager.js +16 -0
- package/dist/tmux-manager.js.map +1 -1
- package/dist/tool-permissions.d.ts +5 -0
- package/dist/tool-permissions.js +15 -2
- package/dist/tool-permissions.js.map +1 -1
- package/dist/types.d.ts +1 -1
- package/dist/ui/app-effects.js +33 -9
- package/dist/ui/chat-effects.js +62 -4
- package/dist/ui/chat-strings.js +40 -4
- package/dist/ui/chat-thread.js +13 -5
- package/dist/ui/effect-trial-panel.js +19 -16
- package/dist/ui/fleet-cache.js +23 -1
- package/dist/ui/fleet-canvas-layout.js +111 -0
- package/dist/ui/fleet-canvas.js +489 -0
- package/dist/ui/fleet-org.js +27 -12
- package/dist/ui/fleet-traffic.js +224 -0
- package/dist/ui/panel-chat.js +8 -2
- package/dist/ui/panel-details.js +2 -1
- package/dist/ui/panel-fleet.js +17 -5
- package/dist/ui/panel-settings.js +3 -2
- package/dist/ui/preview.js +3 -2
- package/dist/ui/settings-appearance.js +34 -18
- package/dist/ui/settings-dialogs.js +3 -6
- package/dist/ui/settings-effects.js +4 -3
- package/dist/ui/settings-learn.js +25 -0
- package/dist/ui/settings-model.js +6 -2
- package/dist/ui/settings-mods.js +4 -3
- package/dist/ui/settings-owner-effects.js +8 -8
- package/dist/ui/settings-strings.js +34 -38
- package/dist/ui/shared/app-i18n.js +2 -2
- package/dist/ui/shared/app-prefs.js +1 -1
- package/dist/ui/shared/app-shell.js +23 -1
- package/dist/ui/shared/app-store.js +12 -1
- package/dist/ui/shared/app-stream.js +2 -1
- package/dist/ui/shared/app.css +163 -12
- package/dist/ui/shared/effect-app-runtime.js +1 -1
- package/dist/ui/shared/effect-frame.js +10 -5
- package/dist/ui/shared/effect-geometry.js +24 -9
- package/dist/ui/shared/effect-policy.js +2 -1
- package/dist/ui/shared/effect-registry.js +71 -17
- package/dist/ui/shared/effect-trial-shadow.js +62 -0
- package/dist/ui/shared/effect-trial-stage.js +15 -9
- package/dist/ui/shared/effect-trial.css +40 -0
- package/dist/ui/shared/identity-card.js +5 -2
- package/dist/ui/shared/identity-color.js +3 -3
- package/dist/ui/shared/instance-nav.js +35 -9
- package/dist/ui/shared/panel-view.js +2 -2
- package/dist/ui/shared/usage-dialog.js +14 -2
- package/dist/ui/shared/view-strings.js +22 -2
- package/dist/ui/signin.html +1 -1
- package/dist/usage/providers.d.ts +3 -0
- package/dist/usage/providers.js +4 -3
- package/dist/usage/providers.js.map +1 -1
- package/dist/view-api.d.ts +21 -0
- package/dist/view-api.js +28 -0
- package/dist/view-api.js.map +1 -1
- package/dist/web-api.d.ts +5 -6
- package/dist/web-api.js +60 -11
- package/dist/web-api.js.map +1 -1
- package/dist/web-appearance-view.d.ts +10 -0
- package/dist/web-appearance-view.js +77 -8
- package/dist/web-appearance-view.js.map +1 -1
- package/dist/web-asset-parts.d.ts +3 -8
- package/dist/web-asset-parts.js.map +1 -1
- package/dist/web-auth.js +1 -1
- package/dist/web-auth.js.map +1 -1
- package/dist/web-effect-service.js +3 -1
- package/dist/web-effect-service.js.map +1 -1
- package/dist/web-effect-tools.js +4 -1
- package/dist/web-effect-tools.js.map +1 -1
- package/dist/web-effect-trials.d.ts +4 -4
- package/dist/web-effect-trials.js +6 -6
- package/dist/web-effect-trials.js.map +1 -1
- package/dist/web-effect-upload.d.ts +2 -4
- package/dist/web-effect-upload.js +3 -8
- package/dist/web-effect-upload.js.map +1 -1
- package/dist/web-effect.d.ts +14 -0
- package/dist/web-effect.js +21 -0
- package/dist/web-effect.js.map +1 -1
- package/dist/web-guest-access.d.ts +67 -0
- package/dist/web-guest-access.js +126 -0
- package/dist/web-guest-access.js.map +1 -0
- package/dist/web-identity-palette.d.ts +1 -1
- package/dist/web-identity-palette.js +2 -2
- package/dist/web-identity-palette.js.map +1 -1
- package/dist/web-mod-agent.js +5 -3
- package/dist/web-mod-agent.js.map +1 -1
- package/dist/web-mod-bundle.d.ts +5 -0
- package/dist/web-mod-bundle.js +6 -0
- package/dist/web-mod-bundle.js.map +1 -1
- package/dist/web-mod-store.d.ts +5 -0
- package/dist/web-mod-store.js +8 -1
- package/dist/web-mod-store.js.map +1 -1
- package/dist/web-prefs.d.ts +8 -0
- package/dist/web-prefs.js +9 -0
- package/dist/web-prefs.js.map +1 -1
- package/dist/web-preview.d.ts +6 -2
- package/dist/web-preview.js +4 -2
- package/dist/web-preview.js.map +1 -1
- package/dist/web-session.d.ts +15 -7
- package/dist/web-session.js +25 -8
- package/dist/web-session.js.map +1 -1
- package/dist/web-settings-tools.d.ts +69 -0
- package/dist/web-settings-tools.js +247 -0
- package/dist/web-settings-tools.js.map +1 -0
- package/package.json +1 -1
- package/templates/systemd.service.ejs +8 -0
package/dist/web-api.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { webHumanOrigin } from "./human-delivery-receipts.js";
|
|
2
|
+
import { guestFrameData, guestPollBody, guestRequestOf, guestStatus } from "./web-guest-access.js";
|
|
2
3
|
import { withSpawnHoldReply } from "./spawn-hold-reply.js";
|
|
3
4
|
import { binaryProbe } from "./binary-probe.js";
|
|
4
5
|
import { settingsRequestExecution, settingsWrite, isSettingsReplay } from "./settings-request-capability.js";
|
|
@@ -41,6 +42,7 @@ import { parseMentionQuery } from "./web-mentions.js";
|
|
|
41
42
|
import { authorizeExplicitInstanceRemoval } from "./instance-removal.js";
|
|
42
43
|
import { measureSyncWork } from "./sync-work-attribution.js";
|
|
43
44
|
import { resolveTz } from "./tz-utils.js";
|
|
45
|
+
import { filesPlayInChat } from "./web-effect.js";
|
|
44
46
|
// ── Strict public-facing schemas ────────────────────────────────────────────
|
|
45
47
|
// web-api endpoints must reject unknown fields so the dashboard cannot inject
|
|
46
48
|
// internal-only flags that would reach handleCreate/scheduler/config writers.
|
|
@@ -96,11 +98,27 @@ const safeInstanceSegment = (name) => /^[^\\/\x00]+$/.test(name) && name !== "."
|
|
|
96
98
|
* the eviction the dead entry leaks forever, and without the try/catch a
|
|
97
99
|
* single dead client breaks delivery to every client iterated after it.
|
|
98
100
|
*/
|
|
101
|
+
/** #1920 phase 1b: the open streams that are a guest's, and whose — each event is projected for them (guestFrameData). */
|
|
102
|
+
const streamGuests = new WeakMap();
|
|
99
103
|
export function broadcastSseEvent(clients, event, data, onError, id) {
|
|
100
104
|
const payload = sseFrame(event, data, id);
|
|
101
105
|
const dead = [];
|
|
102
106
|
for (const client of clients) {
|
|
103
107
|
try {
|
|
108
|
+
// An admin's stream gets these bytes; a guest's, the event as projected for its scope now, or nothing (no id: it
|
|
109
|
+
// never replays chat, so a cursor of the admin's stream is not its to hold).
|
|
110
|
+
const guest = streamGuests.get(client);
|
|
111
|
+
if (guest) {
|
|
112
|
+
// The exact session that opened it ended (revoked, expired, rotated away): nothing more, and the stream goes.
|
|
113
|
+
if (!guest.current()) {
|
|
114
|
+
dead.push(client);
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
const shown = guestFrameData(event, data, guest.scope());
|
|
118
|
+
if (shown !== undefined)
|
|
119
|
+
client.write(sseFrame(event, shown));
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
104
122
|
client.write(payload);
|
|
105
123
|
}
|
|
106
124
|
catch (err) {
|
|
@@ -381,7 +399,7 @@ function handleEffectTrials(req, res, url, ctx, path, method) {
|
|
|
381
399
|
css = value;
|
|
382
400
|
}
|
|
383
401
|
catch { /* unavailable is never off */ }
|
|
384
|
-
// CSS
|
|
402
|
+
// CSS is diagnostic for Try; its host-owned shadow shell isolates controls and local paint.
|
|
385
403
|
const actor = Object.freeze({ via: "session", surface: "local", tier: "admin", sessionHash: v.session.idHash, epoch: v.session.handle, person, ownerCss: css });
|
|
386
404
|
return { actor, record: v.session, sessions };
|
|
387
405
|
};
|
|
@@ -817,7 +835,8 @@ export function exportMod(ctx, person, body) {
|
|
|
817
835
|
if (inc.theme === true) {
|
|
818
836
|
// The effects the theme places travel with it, as the library keeps them (a person may export what is placed).
|
|
819
837
|
// Only effects this person may carry away travel (Sol's ACL); the rest are counted, never packaged.
|
|
820
|
-
|
|
838
|
+
// #2017: an older placement of an effect that doesn't play in chat stays out (a mod can't place it): counted.
|
|
839
|
+
const effects = rec.placements.effects.flatMap(p => { const e = ctx.modPlacedEffect?.(person, p.id); if (!e || !filesPlayInChat(e.files)) {
|
|
821
840
|
omitted++;
|
|
822
841
|
return [];
|
|
823
842
|
} return [{ name: e.name, files: e.files, params: p.params ?? {} }]; });
|
|
@@ -976,6 +995,12 @@ export function handleWebRequest(req, res, url, ctx) {
|
|
|
976
995
|
// that arrived while the stream was silent is not skipped by the cursor this answer hands out (#1251
|
|
977
996
|
// review). The page keeps one entry per boot+id, so what it already loaded from /ui/history is not doubled.
|
|
978
997
|
if (method === "GET" && path === "/ui/poll") {
|
|
998
|
+
// #1920: a guest's poll is projected for its scope (web-guest-access.ts) — the same rule as its stream.
|
|
999
|
+
const guest = guestRequestOf(req);
|
|
1000
|
+
if (guest) {
|
|
1001
|
+
json(res, 200, guestPollBody(ctx.getUiStatus(), guest.scope(), Date.now()));
|
|
1002
|
+
return true;
|
|
1003
|
+
}
|
|
979
1004
|
const history = ctx.webChatHistory;
|
|
980
1005
|
const after = url.searchParams.get("after");
|
|
981
1006
|
const fresh = after === null || after === ""; // a cursor that is not ours in shape still gets nothing
|
|
@@ -1011,9 +1036,15 @@ export function handleWebRequest(req, res, url, ctx) {
|
|
|
1011
1036
|
});
|
|
1012
1037
|
// #1823 (#1830 review): with the status, the server's clock — now and with every heartbeat — that the page counts a
|
|
1013
1038
|
// poll down by (one write: the frames a connect sends are unchanged in number).
|
|
1014
|
-
|
|
1039
|
+
// #1920: a guest's stream: its projected status now and with each heartbeat, then only what guestFrameData lets
|
|
1040
|
+
// through — no replay, no ticks, prompts or Needs you.
|
|
1041
|
+
const guest = guestRequestOf(req);
|
|
1042
|
+
if (guest)
|
|
1043
|
+
streamGuests.set(res, guest);
|
|
1044
|
+
const statusFrame = () => `event: status\ndata: ${JSON.stringify(guest ? guestStatus(ctx.getUiStatus(), guest.scope()) : ctx.getUiStatus())}\n\n`;
|
|
1045
|
+
res.write(`${statusFrame()}${sseClock()}`);
|
|
1015
1046
|
// An EventSource that reconnects says what it last saw: send what it missed, before anything new.
|
|
1016
|
-
const lastSeen = parseLastEventId(req.headers["last-event-id"]);
|
|
1047
|
+
const lastSeen = guest ? null : parseLastEventId(req.headers["last-event-id"]);
|
|
1017
1048
|
if (lastSeen !== null && ctx.webChatHistory) {
|
|
1018
1049
|
const history = ctx.webChatHistory;
|
|
1019
1050
|
for (const m of history.replayFor(lastSeen))
|
|
@@ -1021,20 +1052,22 @@ export function handleWebRequest(req, res, url, ctx) {
|
|
|
1021
1052
|
}
|
|
1022
1053
|
// Ticks change messages already sent and carry no cursor: every (re)connect gets where each one is now, so a
|
|
1023
1054
|
// report that fell into a gap is not lost until a reload (#1253 review). No id: it is not a message.
|
|
1024
|
-
if (ctx.webChatHistory)
|
|
1055
|
+
if (!guest && ctx.webChatHistory)
|
|
1025
1056
|
res.write(`event: deliveries\ndata: ${JSON.stringify(ctx.webChatHistory.deliveries())}\n\n`);
|
|
1026
1057
|
// The same for the fleet prompts (C4): one posted, answered or expired during a gap is caught up here.
|
|
1027
|
-
if (ctx.listWebPrompts)
|
|
1058
|
+
if (!guest && ctx.listWebPrompts)
|
|
1028
1059
|
res.write(`event: prompts\ndata: ${JSON.stringify(ctx.listWebPrompts())}\n\n`);
|
|
1029
1060
|
// #1386: and "Needs you" as it is now; changes follow as `needs` events.
|
|
1030
|
-
if (ctx.needsYouItems)
|
|
1061
|
+
if (!guest && ctx.needsYouItems)
|
|
1031
1062
|
res.write(`event: needs\ndata: ${JSON.stringify({ items: ctx.needsYouItems() })}\n\n`);
|
|
1032
1063
|
ctx.sseClients.add(res);
|
|
1033
1064
|
const interval = setInterval(() => {
|
|
1034
1065
|
// A stream authorized once must not outlive the authorization. Re-checked
|
|
1035
1066
|
// without counting as activity, or an open tab would keep an idle session
|
|
1036
1067
|
// alive forever; a revoked, expired or rotated-away session ends here.
|
|
1037
|
-
|
|
1068
|
+
// #2049 review: a guest's stream also needs the exact session that opened it — another cookie on the same request
|
|
1069
|
+
// still authenticating does not keep a revoked device's stream (with its scope) alive.
|
|
1070
|
+
if (!isWebRequestAuthorized(req, url, ctx.webToken, ctx.webSessions, { touch: false }) || (guest && !guest.current())) {
|
|
1038
1071
|
// Close the connection too, not just the response: an ended response leaves the socket idle in
|
|
1039
1072
|
// keep-alive, still held open by whoever's session just ended.
|
|
1040
1073
|
const socket = req.socket;
|
|
@@ -1047,7 +1080,7 @@ export function handleWebRequest(req, res, url, ctx) {
|
|
|
1047
1080
|
}
|
|
1048
1081
|
try {
|
|
1049
1082
|
// Every open dashboard tab, every 10 s: the status of every instance, serialized on the fleet's loop (#1235).
|
|
1050
|
-
res.write(measureSyncWork("web.sseStatus",
|
|
1083
|
+
res.write(measureSyncWork("web.sseStatus", statusFrame) + sseClock());
|
|
1051
1084
|
}
|
|
1052
1085
|
catch {
|
|
1053
1086
|
cleanup();
|
|
@@ -1136,6 +1169,16 @@ export function handleWebRequest(req, res, url, ctx) {
|
|
|
1136
1169
|
const fileMatch = path.match(/^\/ui\/file\/([^/]+)$/);
|
|
1137
1170
|
if (method === "GET" && fileMatch) {
|
|
1138
1171
|
const id = fileMatch[1];
|
|
1172
|
+
// #1920: a guest gets a file only when its stored instance is in scope — "no such file" otherwise, like an unknown id
|
|
1173
|
+
// (an id from another instance's chat is useless).
|
|
1174
|
+
const guest = guestRequestOf(req);
|
|
1175
|
+
if (guest) {
|
|
1176
|
+
const served = isFileId(id) ? ctx.webFiles?.servedFile?.(id) ?? null : null;
|
|
1177
|
+
if (!served || !guest.scope().has(served.instance)) {
|
|
1178
|
+
json(res, 404, { error: "No such file" });
|
|
1179
|
+
return true;
|
|
1180
|
+
}
|
|
1181
|
+
}
|
|
1139
1182
|
// #1589: audio and video, played in the page — one byte range at a time (206), by id only, never a whole video in
|
|
1140
1183
|
// memory. Every other type is answered exactly as before.
|
|
1141
1184
|
const media = isFileId(id) ? ctx.webFiles?.mediaOf?.(id) ?? null : null;
|
|
@@ -2129,6 +2172,12 @@ export function handleWebRequest(req, res, url, ctx) {
|
|
|
2129
2172
|
json(res, 200, ctx.orgChart?.() ?? { general: [], teams: [], instances: {} });
|
|
2130
2173
|
return true;
|
|
2131
2174
|
}
|
|
2175
|
+
// #1918: the org canvas's traffic on opening, and the public link's (which has no stream) on its poll cadence. The
|
|
2176
|
+
// fleet works it out at most once every two seconds and caps it, whoever asks how often.
|
|
2177
|
+
if (method === "GET" && path === "/ui/traffic") {
|
|
2178
|
+
json(res, 200, ctx.trafficSnapshot?.() ?? { now: new Date().toISOString(), items: [] });
|
|
2179
|
+
return true;
|
|
2180
|
+
}
|
|
2132
2181
|
if (method === "GET" && path === "/ui/teams") {
|
|
2133
2182
|
const teams = ctx.fleetConfig?.teams ?? {};
|
|
2134
2183
|
json(res, 200, { teams });
|
|
@@ -2387,8 +2436,8 @@ function handleSendMessage(req, res, ctx) {
|
|
|
2387
2436
|
&& !ctx.isClassicInstance?.(instance) && syncAdapter && groupId && topicId != null;
|
|
2388
2437
|
// Add no runtime credentials or local attachment paths to the display copy.
|
|
2389
2438
|
const preview = webEchoPreview(message, files.map(f => f.name));
|
|
2390
|
-
// ClassicBot echo (#1320 part B): same ordering lane,
|
|
2391
|
-
//
|
|
2439
|
+
// ClassicBot echo (#1320 part B): same ordering lane, each room's setting (#2054: on unless it says false, or
|
|
2440
|
+
// the fleet-wide switch is off for a room that is unset) resolved at send time inside sendClassicWebEcho.
|
|
2392
2441
|
const canClassicEcho = ctx.isClassicInstance?.(instance) === true && !!ctx.sendClassicWebEcho;
|
|
2393
2442
|
const settleClassicEcho = canClassicEcho ? ctx.reserveWebChannelEcho?.(instance, async () => {
|
|
2394
2443
|
await ctx.sendClassicWebEcho(instance, formatWebChannelEcho(person.name, preview, t("web.echo_full_text")), person.name);
|