@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.
Files changed (174) hide show
  1. package/dist/agent-cli.js +5 -5
  2. package/dist/agent-cli.js.map +1 -1
  3. package/dist/agent-file-read.d.ts +11 -6
  4. package/dist/agent-file-read.js +32 -17
  5. package/dist/agent-file-read.js.map +1 -1
  6. package/dist/agent-whats-new.js +10 -13
  7. package/dist/agent-whats-new.js.map +1 -1
  8. package/dist/auth-api.js +10 -5
  9. package/dist/auth-api.js.map +1 -1
  10. package/dist/backend/claude-code.d.ts +2 -2
  11. package/dist/backend/claude-code.js +10 -5
  12. package/dist/backend/claude-code.js.map +1 -1
  13. package/dist/backend/types.d.ts +13 -0
  14. package/dist/backend/types.js +10 -0
  15. package/dist/backend/types.js.map +1 -1
  16. package/dist/cache-analysis.d.ts +47 -1
  17. package/dist/cache-analysis.js +68 -8
  18. package/dist/cache-analysis.js.map +1 -1
  19. package/dist/cache-report-tool.d.ts +17 -0
  20. package/dist/cache-report-tool.js +40 -0
  21. package/dist/cache-report-tool.js.map +1 -0
  22. package/dist/cache-service.d.ts +15 -0
  23. package/dist/cache-service.js +26 -1
  24. package/dist/cache-service.js.map +1 -1
  25. package/dist/channel/mcp-tools.js +9 -3
  26. package/dist/channel/mcp-tools.js.map +1 -1
  27. package/dist/classic-channel-manager.d.ts +8 -3
  28. package/dist/classic-channel-manager.js +10 -3
  29. package/dist/classic-channel-manager.js.map +1 -1
  30. package/dist/cli.js +7 -3
  31. package/dist/cli.js.map +1 -1
  32. package/dist/config-validator.js +5 -1
  33. package/dist/config-validator.js.map +1 -1
  34. package/dist/daemon.js +5 -5
  35. package/dist/daemon.js.map +1 -1
  36. package/dist/delivery-outbox.js +5 -0
  37. package/dist/delivery-outbox.js.map +1 -1
  38. package/dist/fleet-manager.d.ts +71 -3
  39. package/dist/fleet-manager.js +256 -45
  40. package/dist/fleet-manager.js.map +1 -1
  41. package/dist/fleet-traffic.d.ts +38 -0
  42. package/dist/fleet-traffic.js +96 -0
  43. package/dist/fleet-traffic.js.map +1 -0
  44. package/dist/general-knowledge/skills/credential-profiles/SKILL.md +20 -5
  45. package/dist/general-knowledge/skills/multi-channel/SKILL.md +1 -1
  46. package/dist/general-knowledge/skills/web-appearance/SKILL.md +149 -5
  47. package/dist/general-knowledge/skills/web-dashboard/SKILL.md +398 -0
  48. package/dist/locale.js +6 -4
  49. package/dist/locale.js.map +1 -1
  50. package/dist/memory-hogs.d.ts +27 -0
  51. package/dist/memory-hogs.js +124 -0
  52. package/dist/memory-hogs.js.map +1 -0
  53. package/dist/outbound-handlers.d.ts +4 -0
  54. package/dist/outbound-handlers.js +74 -1
  55. package/dist/outbound-handlers.js.map +1 -1
  56. package/dist/outbound-schemas.d.ts +98 -0
  57. package/dist/outbound-schemas.js +56 -0
  58. package/dist/outbound-schemas.js.map +1 -1
  59. package/dist/public-web-gateway.js +1 -1
  60. package/dist/public-web-gateway.js.map +1 -1
  61. package/dist/scheduler/scheduler.d.ts +12 -0
  62. package/dist/scheduler/scheduler.js +83 -10
  63. package/dist/scheduler/scheduler.js.map +1 -1
  64. package/dist/service-installer.d.ts +2 -1
  65. package/dist/service-installer.js +18 -3
  66. package/dist/service-installer.js.map +1 -1
  67. package/dist/tmux-manager.d.ts +5 -0
  68. package/dist/tmux-manager.js +16 -0
  69. package/dist/tmux-manager.js.map +1 -1
  70. package/dist/tool-permissions.d.ts +5 -0
  71. package/dist/tool-permissions.js +15 -2
  72. package/dist/tool-permissions.js.map +1 -1
  73. package/dist/types.d.ts +1 -1
  74. package/dist/ui/app-effects.js +33 -9
  75. package/dist/ui/chat-effects.js +62 -4
  76. package/dist/ui/chat-strings.js +40 -4
  77. package/dist/ui/chat-thread.js +13 -5
  78. package/dist/ui/effect-trial-panel.js +19 -16
  79. package/dist/ui/fleet-cache.js +23 -1
  80. package/dist/ui/fleet-canvas-layout.js +111 -0
  81. package/dist/ui/fleet-canvas.js +489 -0
  82. package/dist/ui/fleet-org.js +27 -12
  83. package/dist/ui/fleet-traffic.js +224 -0
  84. package/dist/ui/panel-chat.js +8 -2
  85. package/dist/ui/panel-details.js +2 -1
  86. package/dist/ui/panel-fleet.js +17 -5
  87. package/dist/ui/panel-settings.js +3 -2
  88. package/dist/ui/preview.js +3 -2
  89. package/dist/ui/settings-appearance.js +34 -18
  90. package/dist/ui/settings-dialogs.js +3 -6
  91. package/dist/ui/settings-effects.js +4 -3
  92. package/dist/ui/settings-learn.js +25 -0
  93. package/dist/ui/settings-model.js +6 -2
  94. package/dist/ui/settings-mods.js +4 -3
  95. package/dist/ui/settings-owner-effects.js +8 -8
  96. package/dist/ui/settings-strings.js +34 -38
  97. package/dist/ui/shared/app-i18n.js +2 -2
  98. package/dist/ui/shared/app-prefs.js +1 -1
  99. package/dist/ui/shared/app-shell.js +23 -1
  100. package/dist/ui/shared/app-store.js +12 -1
  101. package/dist/ui/shared/app-stream.js +2 -1
  102. package/dist/ui/shared/app.css +163 -12
  103. package/dist/ui/shared/effect-app-runtime.js +1 -1
  104. package/dist/ui/shared/effect-frame.js +10 -5
  105. package/dist/ui/shared/effect-geometry.js +24 -9
  106. package/dist/ui/shared/effect-policy.js +2 -1
  107. package/dist/ui/shared/effect-registry.js +71 -17
  108. package/dist/ui/shared/effect-trial-shadow.js +62 -0
  109. package/dist/ui/shared/effect-trial-stage.js +15 -9
  110. package/dist/ui/shared/effect-trial.css +40 -0
  111. package/dist/ui/shared/identity-card.js +5 -2
  112. package/dist/ui/shared/identity-color.js +3 -3
  113. package/dist/ui/shared/instance-nav.js +35 -9
  114. package/dist/ui/shared/panel-view.js +2 -2
  115. package/dist/ui/shared/usage-dialog.js +14 -2
  116. package/dist/ui/shared/view-strings.js +22 -2
  117. package/dist/ui/signin.html +1 -1
  118. package/dist/usage/providers.d.ts +3 -0
  119. package/dist/usage/providers.js +4 -3
  120. package/dist/usage/providers.js.map +1 -1
  121. package/dist/view-api.d.ts +21 -0
  122. package/dist/view-api.js +28 -0
  123. package/dist/view-api.js.map +1 -1
  124. package/dist/web-api.d.ts +5 -6
  125. package/dist/web-api.js +60 -11
  126. package/dist/web-api.js.map +1 -1
  127. package/dist/web-appearance-view.d.ts +10 -0
  128. package/dist/web-appearance-view.js +77 -8
  129. package/dist/web-appearance-view.js.map +1 -1
  130. package/dist/web-asset-parts.d.ts +3 -8
  131. package/dist/web-asset-parts.js.map +1 -1
  132. package/dist/web-auth.js +1 -1
  133. package/dist/web-auth.js.map +1 -1
  134. package/dist/web-effect-service.js +3 -1
  135. package/dist/web-effect-service.js.map +1 -1
  136. package/dist/web-effect-tools.js +4 -1
  137. package/dist/web-effect-tools.js.map +1 -1
  138. package/dist/web-effect-trials.d.ts +4 -4
  139. package/dist/web-effect-trials.js +6 -6
  140. package/dist/web-effect-trials.js.map +1 -1
  141. package/dist/web-effect-upload.d.ts +2 -4
  142. package/dist/web-effect-upload.js +3 -8
  143. package/dist/web-effect-upload.js.map +1 -1
  144. package/dist/web-effect.d.ts +14 -0
  145. package/dist/web-effect.js +21 -0
  146. package/dist/web-effect.js.map +1 -1
  147. package/dist/web-guest-access.d.ts +67 -0
  148. package/dist/web-guest-access.js +126 -0
  149. package/dist/web-guest-access.js.map +1 -0
  150. package/dist/web-identity-palette.d.ts +1 -1
  151. package/dist/web-identity-palette.js +2 -2
  152. package/dist/web-identity-palette.js.map +1 -1
  153. package/dist/web-mod-agent.js +5 -3
  154. package/dist/web-mod-agent.js.map +1 -1
  155. package/dist/web-mod-bundle.d.ts +5 -0
  156. package/dist/web-mod-bundle.js +6 -0
  157. package/dist/web-mod-bundle.js.map +1 -1
  158. package/dist/web-mod-store.d.ts +5 -0
  159. package/dist/web-mod-store.js +8 -1
  160. package/dist/web-mod-store.js.map +1 -1
  161. package/dist/web-prefs.d.ts +8 -0
  162. package/dist/web-prefs.js +9 -0
  163. package/dist/web-prefs.js.map +1 -1
  164. package/dist/web-preview.d.ts +6 -2
  165. package/dist/web-preview.js +4 -2
  166. package/dist/web-preview.js.map +1 -1
  167. package/dist/web-session.d.ts +15 -7
  168. package/dist/web-session.js +25 -8
  169. package/dist/web-session.js.map +1 -1
  170. package/dist/web-settings-tools.d.ts +69 -0
  171. package/dist/web-settings-tools.js +247 -0
  172. package/dist/web-settings-tools.js.map +1 -0
  173. package/package.json +1 -1
  174. 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 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.
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
- const effects = rec.placements.effects.flatMap(p => { const e = ctx.modPlacedEffect?.(person, p.id); if (!e) {
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
- 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()}`);
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
- 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())) {
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", () => `event: status\ndata: ${JSON.stringify(ctx.getUiStatus())}\n\n`) + sseClock());
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, per-entry
2391
- // 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.
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);