@songsid/agend 2.3.0-beta.2 → 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.
Files changed (122) hide show
  1. package/dist/agent-whats-new.js +2 -0
  2. package/dist/agent-whats-new.js.map +1 -1
  3. package/dist/auth-api.js +10 -5
  4. package/dist/auth-api.js.map +1 -1
  5. package/dist/backend/claude-code.d.ts +2 -2
  6. package/dist/backend/claude-code.js +5 -4
  7. package/dist/backend/claude-code.js.map +1 -1
  8. package/dist/backend/types.d.ts +5 -0
  9. package/dist/backend/types.js.map +1 -1
  10. package/dist/channel/mcp-tools.js +4 -0
  11. package/dist/channel/mcp-tools.js.map +1 -1
  12. package/dist/classic-channel-manager.d.ts +8 -3
  13. package/dist/classic-channel-manager.js +10 -3
  14. package/dist/classic-channel-manager.js.map +1 -1
  15. package/dist/delivery-outbox.js +5 -0
  16. package/dist/delivery-outbox.js.map +1 -1
  17. package/dist/fleet-manager.d.ts +68 -3
  18. package/dist/fleet-manager.js +247 -41
  19. package/dist/fleet-manager.js.map +1 -1
  20. package/dist/fleet-traffic.d.ts +38 -0
  21. package/dist/fleet-traffic.js +96 -0
  22. package/dist/fleet-traffic.js.map +1 -0
  23. package/dist/general-knowledge/skills/credential-profiles/SKILL.md +13 -5
  24. package/dist/general-knowledge/skills/multi-channel/SKILL.md +1 -1
  25. package/dist/general-knowledge/skills/web-appearance/SKILL.md +39 -4
  26. package/dist/general-knowledge/skills/web-dashboard/SKILL.md +398 -0
  27. package/dist/locale.js +6 -4
  28. package/dist/locale.js.map +1 -1
  29. package/dist/memory-hogs.d.ts +27 -0
  30. package/dist/memory-hogs.js +124 -0
  31. package/dist/memory-hogs.js.map +1 -0
  32. package/dist/outbound-handlers.d.ts +2 -0
  33. package/dist/outbound-handlers.js +40 -1
  34. package/dist/outbound-handlers.js.map +1 -1
  35. package/dist/outbound-schemas.d.ts +88 -0
  36. package/dist/outbound-schemas.js +50 -0
  37. package/dist/outbound-schemas.js.map +1 -1
  38. package/dist/public-web-gateway.js +1 -1
  39. package/dist/public-web-gateway.js.map +1 -1
  40. package/dist/tmux-manager.d.ts +5 -0
  41. package/dist/tmux-manager.js +16 -0
  42. package/dist/tmux-manager.js.map +1 -1
  43. package/dist/tool-permissions.js +4 -0
  44. package/dist/tool-permissions.js.map +1 -1
  45. package/dist/types.d.ts +1 -1
  46. package/dist/ui/app-effects.js +33 -9
  47. package/dist/ui/chat-effects.js +62 -4
  48. package/dist/ui/chat-strings.js +40 -4
  49. package/dist/ui/chat-thread.js +13 -5
  50. package/dist/ui/effect-trial-panel.js +19 -16
  51. package/dist/ui/fleet-canvas-layout.js +111 -0
  52. package/dist/ui/fleet-canvas.js +489 -0
  53. package/dist/ui/fleet-org.js +27 -12
  54. package/dist/ui/fleet-traffic.js +224 -0
  55. package/dist/ui/panel-chat.js +8 -2
  56. package/dist/ui/panel-details.js +2 -1
  57. package/dist/ui/panel-fleet.js +17 -5
  58. package/dist/ui/panel-settings.js +3 -2
  59. package/dist/ui/preview.js +3 -2
  60. package/dist/ui/settings-appearance.js +34 -18
  61. package/dist/ui/settings-dialogs.js +3 -6
  62. package/dist/ui/settings-effects.js +4 -3
  63. package/dist/ui/settings-learn.js +25 -0
  64. package/dist/ui/settings-model.js +6 -2
  65. package/dist/ui/settings-mods.js +4 -3
  66. package/dist/ui/settings-owner-effects.js +8 -8
  67. package/dist/ui/settings-strings.js +34 -38
  68. package/dist/ui/shared/app-i18n.js +2 -2
  69. package/dist/ui/shared/app-prefs.js +1 -1
  70. package/dist/ui/shared/app-shell.js +23 -1
  71. package/dist/ui/shared/app-store.js +12 -1
  72. package/dist/ui/shared/app-stream.js +2 -1
  73. package/dist/ui/shared/app.css +152 -10
  74. package/dist/ui/shared/effect-app-runtime.js +1 -1
  75. package/dist/ui/shared/effect-frame.js +10 -5
  76. package/dist/ui/shared/effect-geometry.js +24 -9
  77. package/dist/ui/shared/effect-policy.js +2 -1
  78. package/dist/ui/shared/effect-registry.js +71 -17
  79. package/dist/ui/shared/effect-trial-shadow.js +62 -0
  80. package/dist/ui/shared/effect-trial-stage.js +15 -9
  81. package/dist/ui/shared/effect-trial.css +40 -0
  82. package/dist/ui/shared/identity-card.js +5 -2
  83. package/dist/ui/shared/identity-color.js +3 -3
  84. package/dist/ui/shared/instance-nav.js +20 -4
  85. package/dist/ui/shared/panel-view.js +2 -2
  86. package/dist/ui/shared/view-strings.js +16 -0
  87. package/dist/view-api.d.ts +21 -0
  88. package/dist/view-api.js +28 -0
  89. package/dist/view-api.js.map +1 -1
  90. package/dist/web-api.d.ts +5 -6
  91. package/dist/web-api.js +57 -10
  92. package/dist/web-api.js.map +1 -1
  93. package/dist/web-appearance-view.d.ts +10 -0
  94. package/dist/web-appearance-view.js +77 -8
  95. package/dist/web-appearance-view.js.map +1 -1
  96. package/dist/web-auth.js +1 -1
  97. package/dist/web-auth.js.map +1 -1
  98. package/dist/web-effect-trials.d.ts +2 -2
  99. package/dist/web-effect-trials.js +3 -3
  100. package/dist/web-effect-trials.js.map +1 -1
  101. package/dist/web-guest-access.d.ts +67 -0
  102. package/dist/web-guest-access.js +126 -0
  103. package/dist/web-guest-access.js.map +1 -0
  104. package/dist/web-identity-palette.d.ts +1 -1
  105. package/dist/web-identity-palette.js +2 -2
  106. package/dist/web-identity-palette.js.map +1 -1
  107. package/dist/web-mod-store.d.ts +5 -0
  108. package/dist/web-mod-store.js +6 -0
  109. package/dist/web-mod-store.js.map +1 -1
  110. package/dist/web-prefs.d.ts +8 -0
  111. package/dist/web-prefs.js +9 -0
  112. package/dist/web-prefs.js.map +1 -1
  113. package/dist/web-preview.d.ts +6 -2
  114. package/dist/web-preview.js +4 -2
  115. package/dist/web-preview.js.map +1 -1
  116. package/dist/web-session.d.ts +15 -7
  117. package/dist/web-session.js +25 -8
  118. package/dist/web-session.js.map +1 -1
  119. package/dist/web-settings-tools.d.ts +69 -0
  120. package/dist/web-settings-tools.js +247 -0
  121. package/dist/web-settings-tools.js.map +1 -0
  122. package/package.json +1 -1
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";
@@ -97,11 +98,27 @@ const safeInstanceSegment = (name) => /^[^\\/\x00]+$/.test(name) && name !== "."
97
98
  * the eviction the dead entry leaks forever, and without the try/catch a
98
99
  * single dead client breaks delivery to every client iterated after it.
99
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();
100
103
  export function broadcastSseEvent(clients, event, data, onError, id) {
101
104
  const payload = sseFrame(event, data, id);
102
105
  const dead = [];
103
106
  for (const client of clients) {
104
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
+ }
105
122
  client.write(payload);
106
123
  }
107
124
  catch (err) {
@@ -382,7 +399,7 @@ function handleEffectTrials(req, res, url, ctx, path, method) {
382
399
  css = value;
383
400
  }
384
401
  catch { /* unavailable is never off */ }
385
- // CSS remains a checked runtime value. The authority refuses anything except off on start/read.
402
+ // CSS is diagnostic for Try; its host-owned shadow shell isolates controls and local paint.
386
403
  const actor = Object.freeze({ via: "session", surface: "local", tier: "admin", sessionHash: v.session.idHash, epoch: v.session.handle, person, ownerCss: css });
387
404
  return { actor, record: v.session, sessions };
388
405
  };
@@ -978,6 +995,12 @@ export function handleWebRequest(req, res, url, ctx) {
978
995
  // that arrived while the stream was silent is not skipped by the cursor this answer hands out (#1251
979
996
  // review). The page keeps one entry per boot+id, so what it already loaded from /ui/history is not doubled.
980
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
+ }
981
1004
  const history = ctx.webChatHistory;
982
1005
  const after = url.searchParams.get("after");
983
1006
  const fresh = after === null || after === ""; // a cursor that is not ours in shape still gets nothing
@@ -1013,9 +1036,15 @@ export function handleWebRequest(req, res, url, ctx) {
1013
1036
  });
1014
1037
  // #1823 (#1830 review): with the status, the server's clock — now and with every heartbeat — that the page counts a
1015
1038
  // poll down by (one write: the frames a connect sends are unchanged in number).
1016
- res.write(`event: status\ndata: ${JSON.stringify(ctx.getUiStatus())}\n\n${sseClock()}`);
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()}`);
1017
1046
  // An EventSource that reconnects says what it last saw: send what it missed, before anything new.
1018
- const lastSeen = parseLastEventId(req.headers["last-event-id"]);
1047
+ const lastSeen = guest ? null : parseLastEventId(req.headers["last-event-id"]);
1019
1048
  if (lastSeen !== null && ctx.webChatHistory) {
1020
1049
  const history = ctx.webChatHistory;
1021
1050
  for (const m of history.replayFor(lastSeen))
@@ -1023,20 +1052,22 @@ export function handleWebRequest(req, res, url, ctx) {
1023
1052
  }
1024
1053
  // Ticks change messages already sent and carry no cursor: every (re)connect gets where each one is now, so a
1025
1054
  // report that fell into a gap is not lost until a reload (#1253 review). No id: it is not a message.
1026
- if (ctx.webChatHistory)
1055
+ if (!guest && ctx.webChatHistory)
1027
1056
  res.write(`event: deliveries\ndata: ${JSON.stringify(ctx.webChatHistory.deliveries())}\n\n`);
1028
1057
  // The same for the fleet prompts (C4): one posted, answered or expired during a gap is caught up here.
1029
- if (ctx.listWebPrompts)
1058
+ if (!guest && ctx.listWebPrompts)
1030
1059
  res.write(`event: prompts\ndata: ${JSON.stringify(ctx.listWebPrompts())}\n\n`);
1031
1060
  // #1386: and "Needs you" as it is now; changes follow as `needs` events.
1032
- if (ctx.needsYouItems)
1061
+ if (!guest && ctx.needsYouItems)
1033
1062
  res.write(`event: needs\ndata: ${JSON.stringify({ items: ctx.needsYouItems() })}\n\n`);
1034
1063
  ctx.sseClients.add(res);
1035
1064
  const interval = setInterval(() => {
1036
1065
  // A stream authorized once must not outlive the authorization. Re-checked
1037
1066
  // without counting as activity, or an open tab would keep an idle session
1038
1067
  // alive forever; a revoked, expired or rotated-away session ends here.
1039
- if (!isWebRequestAuthorized(req, url, ctx.webToken, ctx.webSessions, { touch: false })) {
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())) {
1040
1071
  // Close the connection too, not just the response: an ended response leaves the socket idle in
1041
1072
  // keep-alive, still held open by whoever's session just ended.
1042
1073
  const socket = req.socket;
@@ -1049,7 +1080,7 @@ export function handleWebRequest(req, res, url, ctx) {
1049
1080
  }
1050
1081
  try {
1051
1082
  // Every open dashboard tab, every 10 s: the status of every instance, serialized on the fleet's loop (#1235).
1052
- res.write(measureSyncWork("web.sseStatus", () => `event: status\ndata: ${JSON.stringify(ctx.getUiStatus())}\n\n`) + sseClock());
1083
+ res.write(measureSyncWork("web.sseStatus", statusFrame) + sseClock());
1053
1084
  }
1054
1085
  catch {
1055
1086
  cleanup();
@@ -1138,6 +1169,16 @@ export function handleWebRequest(req, res, url, ctx) {
1138
1169
  const fileMatch = path.match(/^\/ui\/file\/([^/]+)$/);
1139
1170
  if (method === "GET" && fileMatch) {
1140
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
+ }
1141
1182
  // #1589: audio and video, played in the page — one byte range at a time (206), by id only, never a whole video in
1142
1183
  // memory. Every other type is answered exactly as before.
1143
1184
  const media = isFileId(id) ? ctx.webFiles?.mediaOf?.(id) ?? null : null;
@@ -2131,6 +2172,12 @@ export function handleWebRequest(req, res, url, ctx) {
2131
2172
  json(res, 200, ctx.orgChart?.() ?? { general: [], teams: [], instances: {} });
2132
2173
  return true;
2133
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
+ }
2134
2181
  if (method === "GET" && path === "/ui/teams") {
2135
2182
  const teams = ctx.fleetConfig?.teams ?? {};
2136
2183
  json(res, 200, { teams });
@@ -2389,8 +2436,8 @@ function handleSendMessage(req, res, ctx) {
2389
2436
  && !ctx.isClassicInstance?.(instance) && syncAdapter && groupId && topicId != null;
2390
2437
  // Add no runtime credentials or local attachment paths to the display copy.
2391
2438
  const preview = webEchoPreview(message, files.map(f => f.name));
2392
- // ClassicBot echo (#1320 part B): same ordering lane, per-entry
2393
- // opt-in resolved at send time inside sendClassicWebEcho.
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.
2394
2441
  const canClassicEcho = ctx.isClassicInstance?.(instance) === true && !!ctx.sendClassicWebEcho;
2395
2442
  const settleClassicEcho = canClassicEcho ? ctx.reserveWebChannelEcho?.(instance, async () => {
2396
2443
  await ctx.sendClassicWebEcho(instance, formatWebChannelEcho(person.name, preview, t("web.echo_full_text")), person.name);