@songsid/agend 2.2.0-beta.10 → 2.2.0-beta.12

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 (105) hide show
  1. package/dist/agent-endpoint.js +3 -0
  2. package/dist/agent-endpoint.js.map +1 -1
  3. package/dist/agent-whats-new.js +4 -0
  4. package/dist/agent-whats-new.js.map +1 -1
  5. package/dist/auth-api.d.ts +3 -1
  6. package/dist/auth-api.js +15 -1
  7. package/dist/auth-api.js.map +1 -1
  8. package/dist/backend/antigravity.d.ts +5 -0
  9. package/dist/backend/antigravity.js +27 -13
  10. package/dist/backend/antigravity.js.map +1 -1
  11. package/dist/backend/effort-metadata.d.ts +36 -0
  12. package/dist/backend/effort-metadata.js +83 -13
  13. package/dist/backend/effort-metadata.js.map +1 -1
  14. package/dist/backend/launch-effort.d.ts +29 -1
  15. package/dist/backend/launch-effort.js +53 -6
  16. package/dist/backend/launch-effort.js.map +1 -1
  17. package/dist/backend/types.d.ts +14 -0
  18. package/dist/backend/types.js +10 -0
  19. package/dist/backend/types.js.map +1 -1
  20. package/dist/channel/adapters/discord.d.ts +12 -0
  21. package/dist/channel/adapters/discord.js +39 -2
  22. package/dist/channel/adapters/discord.js.map +1 -1
  23. package/dist/channel/adapters/telegram.d.ts +18 -0
  24. package/dist/channel/adapters/telegram.js +24 -3
  25. package/dist/channel/adapters/telegram.js.map +1 -1
  26. package/dist/channel/mcp-tools.js +2 -0
  27. package/dist/channel/mcp-tools.js.map +1 -1
  28. package/dist/channel/tool-router.d.ts +2 -0
  29. package/dist/channel/tool-router.js +1 -1
  30. package/dist/channel/tool-router.js.map +1 -1
  31. package/dist/channel/types.d.ts +16 -0
  32. package/dist/cli.js +34 -11
  33. package/dist/cli.js.map +1 -1
  34. package/dist/daemon.js +9 -0
  35. package/dist/daemon.js.map +1 -1
  36. package/dist/delivery-outbox.d.ts +8 -1
  37. package/dist/delivery-outbox.js +6 -2
  38. package/dist/delivery-outbox.js.map +1 -1
  39. package/dist/fleet-manager.d.ts +59 -3
  40. package/dist/fleet-manager.js +157 -22
  41. package/dist/fleet-manager.js.map +1 -1
  42. package/dist/general-knowledge/skills/model-discovery/SKILL.md +4 -1
  43. package/dist/instructions.js +2 -2
  44. package/dist/instructions.js.map +1 -1
  45. package/dist/locale.js +26 -0
  46. package/dist/locale.js.map +1 -1
  47. package/dist/outbound-handlers.js +21 -1
  48. package/dist/outbound-handlers.js.map +1 -1
  49. package/dist/outbound-schemas.d.ts +12 -0
  50. package/dist/outbound-schemas.js +12 -1
  51. package/dist/outbound-schemas.js.map +1 -1
  52. package/dist/public-web-gateway.js +3 -0
  53. package/dist/public-web-gateway.js.map +1 -1
  54. package/dist/reply-buttons-controller.d.ts +86 -5
  55. package/dist/reply-buttons-controller.js +271 -7
  56. package/dist/reply-buttons-controller.js.map +1 -1
  57. package/dist/reply-buttons.d.ts +48 -3
  58. package/dist/reply-buttons.js +105 -10
  59. package/dist/reply-buttons.js.map +1 -1
  60. package/dist/reply-polls.d.ts +85 -0
  61. package/dist/reply-polls.js +154 -0
  62. package/dist/reply-polls.js.map +1 -0
  63. package/dist/tool-permissions.js +3 -3
  64. package/dist/tool-permissions.js.map +1 -1
  65. package/dist/topic-commands.js +9 -4
  66. package/dist/topic-commands.js.map +1 -1
  67. package/dist/ui/chat-render.js +19 -2
  68. package/dist/ui/chat-store.js +35 -1
  69. package/dist/ui/chat-strings.js +2 -0
  70. package/dist/ui/chat-thread.js +42 -0
  71. package/dist/ui/panel-chat.js +2 -0
  72. package/dist/ui/panel-log.js +2 -2
  73. package/dist/ui/panel-settings.js +48 -1
  74. package/dist/ui/settings-strings.js +10 -0
  75. package/dist/ui/shared/app-i18n.js +1 -1
  76. package/dist/ui/shared/app-stream.js +4 -1
  77. package/dist/ui/shared/app.css +28 -5
  78. package/dist/ui/shared/header-tools.js +12 -4
  79. package/dist/ui/shared/instance-switch.js +5 -2
  80. package/dist/ui/shared/view-strings.js +2 -2
  81. package/dist/update-check.d.ts +31 -0
  82. package/dist/update-check.js +47 -0
  83. package/dist/update-check.js.map +1 -1
  84. package/dist/update-launch.d.ts +46 -1
  85. package/dist/update-launch.js +146 -3
  86. package/dist/update-launch.js.map +1 -1
  87. package/dist/web-api.d.ts +40 -2
  88. package/dist/web-api.js +130 -14
  89. package/dist/web-api.js.map +1 -1
  90. package/dist/web-chat-history.d.ts +12 -1
  91. package/dist/web-chat-history.js +29 -7
  92. package/dist/web-chat-history.js.map +1 -1
  93. package/dist/web-login.d.ts +14 -0
  94. package/dist/web-login.js +4 -2
  95. package/dist/web-login.js.map +1 -1
  96. package/dist/web-prefs.d.ts +18 -0
  97. package/dist/web-prefs.js +36 -4
  98. package/dist/web-prefs.js.map +1 -1
  99. package/dist/web-profile.d.ts +32 -0
  100. package/dist/web-profile.js +132 -0
  101. package/dist/web-profile.js.map +1 -0
  102. package/dist/web-session.d.ts +14 -0
  103. package/dist/web-session.js +10 -0
  104. package/dist/web-session.js.map +1 -1
  105. package/package.json +1 -1
@@ -1,9 +1,141 @@
1
1
  /** Chat updates must survive the fleet's service cgroup being stopped (#1490 row 37). */
2
2
  import { execFile } from "node:child_process";
3
3
  import { randomBytes } from "node:crypto";
4
+ import { appendFileSync, existsSync, fchmodSync, openSync, readFileSync, statSync, writeFileSync } from "node:fs";
4
5
  import { readFile } from "node:fs/promises";
6
+ import { basename, dirname, isAbsolute, join } from "node:path";
5
7
  import { promisify } from "node:util";
6
8
  import { updateCommand } from "./update-dispatch.js";
9
+ import { maskSecrets } from "./log-steps.js";
10
+ /** How many bytes to read from the tail of the log when extracting a cause after the updater exits. */
11
+ const CAUSE_TAIL_BYTES = 8 * 1024;
12
+ /** How many bytes to cap the update.log file at (across all runs). */
13
+ export const UPDATE_LOG_FILE_CAP = 400 * 1024;
14
+ /**
15
+ * Path of the update log file (mode 0600; raw updater output is written directly — secrets are
16
+ * masked only when extracting the short cause shown in chat; the file itself is owner-readable only).
17
+ */
18
+ export function updateLogPath(dataDir) {
19
+ return join(dataDir, "update.log");
20
+ }
21
+ /**
22
+ * Extract a short human-readable cause from raw updater output.
23
+ * Prefers the last `npm ERR!`/`npm error` summary line or the last `✗` line.
24
+ * Falls back to the last non-blank line. Masks secrets and caps at ~300 chars.
25
+ */
26
+ export function extractUpdateCause(output) {
27
+ // Lines starting with --- are log headers, not updater output.
28
+ const lines = output.split("\n").map(l => l.trimEnd()).filter(l => Boolean(l) && !l.startsWith("---"));
29
+ if (!lines.length)
30
+ return null;
31
+ // npm ERR! ends with !, a non-word char: \b does not anchor here. Use (?:\s|$) instead.
32
+ const npmErrRe = /^npm (ERR!|error)(?:\s|$)/i;
33
+ const npmLines = lines.filter(l => npmErrRe.test(l));
34
+ if (npmLines.length) {
35
+ // npm 10 always ends with "A complete log of this run can be found in: …". Skip that footer.
36
+ // Prefer the first `npm error code` line plus the next for context.
37
+ const codeIdx = npmLines.findIndex(l => /^npm (ERR!|error) code\s/i.test(l));
38
+ if (codeIdx >= 0) {
39
+ const summary = [npmLines[codeIdx], npmLines[codeIdx + 1]].filter(Boolean).join(" — ");
40
+ return maskSecrets(summary).slice(0, 300);
41
+ }
42
+ const meaningful = npmLines.filter(l => !/A complete log of this run can be found in/i.test(l));
43
+ const pick = meaningful.length ? meaningful[meaningful.length - 1] : npmLines[npmLines.length - 1];
44
+ return maskSecrets(pick).slice(0, 300);
45
+ }
46
+ const cross = lines.filter(l => /^\s*[✗✕×✘]/.test(l));
47
+ if (cross.length)
48
+ return maskSecrets(cross[cross.length - 1]).slice(0, 300);
49
+ return maskSecrets(lines[lines.length - 1]).slice(0, 300);
50
+ }
51
+ /** A version or dist-tag as the updater printed it, safe to put in a suggested command; else a placeholder. */
52
+ function updateTarget(output) {
53
+ const to = /Updating AgEnD v\S+ → v(\S+?)\.\.\./.exec(output)?.[1] ?? /Updating AgEnD to (\S+?)\.\.\./.exec(output)?.[1];
54
+ return to && /^[0-9A-Za-z][0-9A-Za-z.+-]*$/.test(to) ? to : "<version>";
55
+ }
56
+ /**
57
+ * #1829: the one-line fix for a failure AgEnD knows, from this run's output (a small lookup; anything else: null).
58
+ * - `agendGone`: the launched `agend` is no longer there (an install that removed it and did not put it back).
59
+ * - npm `ENOTEMPTY` on its rename: a staging directory left by an interrupted install. npm names the same one on every
60
+ * retry, so the retry fails the same way until it is removed — only that exact directory, and only when it is one of
61
+ * AgEnD's own (`@songsid/.agend…`), never a pattern.
62
+ * - "systemd does not know …": the activation proof could not read the user manager (#1804): the one-time manual hop.
63
+ */
64
+ export function updateFixHint(output, opts = {}) {
65
+ const target = updateTarget(output);
66
+ if (opts.agendGone)
67
+ return `\`npm install -g @songsid/agend@${target}\``;
68
+ if (/^npm (?:ERR!|error) code ENOTEMPTY\b/im.test(output)) {
69
+ const named = /^npm (?:ERR!|error) dest (.+)$/im.exec(output)?.[1] ?? /ENOTEMPTY[^\n]*rename '[^'\n]+' -> '([^'\n]+)'/.exec(output)?.[1];
70
+ const ours = named && isAbsolute(named) && !/['"\s\\`$]/.test(named)
71
+ && basename(dirname(named)) === "@songsid" && /^\.agend[A-Za-z0-9._-]*$/.test(basename(named));
72
+ if (ours)
73
+ return `remove the directory an interrupted install left, then update again: \`rm -rf '${named}' && agend update\``;
74
+ return null;
75
+ }
76
+ if (/systemd does not know /.test(output))
77
+ return `\`npm i -g @songsid/agend@${target} && agend restart\``;
78
+ return null;
79
+ }
80
+ /**
81
+ * Rotate the log file if needed, write a run header, and return an open file descriptor
82
+ * for the child process to write to directly — not a pipe.
83
+ *
84
+ * Using an fd instead of a pipe means the updater can keep writing after the fleet process
85
+ * that spawned it has been stopped: there is no read end to close, so no EPIPE.
86
+ * The caller must closeSync(fd) after spawn so the parent's copy of the fd is released.
87
+ *
88
+ * Returns `null` when the log file cannot be opened (dataDir unwritable, disk full, etc.).
89
+ * In that case the caller should fall back to `stdio: "ignore"` and omit the log note.
90
+ */
91
+ export function openUpdateLog(logPath, header) {
92
+ // Rotate BEFORE opening the fd the child will use (never write to the same inode concurrently).
93
+ try {
94
+ if (existsSync(logPath) && statSync(logPath).size > UPDATE_LOG_FILE_CAP / 2) {
95
+ const old = readFileSync(logPath);
96
+ writeFileSync(logPath, old.subarray(Math.max(0, old.length - UPDATE_LOG_FILE_CAP / 2)));
97
+ }
98
+ }
99
+ catch { /* best-effort */ }
100
+ try {
101
+ appendFileSync(logPath, `${header}\n`, { mode: 0o600 });
102
+ }
103
+ catch { /* best-effort */ }
104
+ let fd;
105
+ try {
106
+ fd = openSync(logPath, "a", 0o600);
107
+ }
108
+ catch {
109
+ return null; // caller falls back to stdio: "ignore" and no log note
110
+ }
111
+ // fchmod: mode param of openSync only applies to new files; existing files keep their mode.
112
+ try {
113
+ fchmodSync(fd, 0o600);
114
+ }
115
+ catch { /* best-effort */ }
116
+ // Record the offset so readRunCause only reads this run's output, not previous runs.
117
+ const offset = (() => { try {
118
+ return statSync(logPath).size;
119
+ }
120
+ catch {
121
+ return 0;
122
+ } })();
123
+ return { fd, offset };
124
+ }
125
+ /**
126
+ * Read only this run's output from the log (from `offset`): its tail, for the cause and the fix.
127
+ * Prevents a run with no output from picking up the previous run's error as the cause.
128
+ */
129
+ function readRunTail(logPath, offset) {
130
+ try {
131
+ const buf = readFileSync(logPath);
132
+ const runBytes = buf.subarray(offset);
133
+ return runBytes.subarray(Math.max(0, runBytes.length - CAUSE_TAIL_BYTES)).toString("utf8");
134
+ }
135
+ catch {
136
+ return null;
137
+ }
138
+ }
7
139
  export const defaultUpdateLaunchDeps = {
8
140
  platform: process.platform,
9
141
  cgroup: async () => {
@@ -89,18 +221,29 @@ export async function resolveUpdateLaunch(agend, deps = defaultUpdateLaunchDeps)
89
221
  ] };
90
222
  }
91
223
  /** Spawn/manager refusal and nonzero updater exit are visible; exit 75 is the existing pending hand-off. */
92
- export function watchUpdateLaunch(child, fail) {
224
+ export function watchUpdateLaunch(child, fail, logPath,
225
+ /** Byte offset into the log file at which this run's output begins. */
226
+ logOffset,
227
+ /** The `agend` the updater runs: there at launch and gone after a failure → reinstalling is the fix (#1829). */
228
+ agendPath) {
93
229
  let reported = false;
230
+ const agendAtLaunch = agendPath !== undefined && existsSync(agendPath);
94
231
  const report = (reason) => {
95
232
  if (reported)
96
233
  return;
97
234
  reported = true;
98
- fail(`/update could not complete (${reason}). Run \`agend update\` from a host shell.`);
235
+ const tail = logPath != null && logOffset != null ? readRunTail(logPath, logOffset) : null;
236
+ const cause = tail === null ? null : extractUpdateCause(tail);
237
+ const logNote = logPath ? ` Full log: ${logPath}.` : "";
238
+ const detail = cause ? ` Cause: ${cause}.${logNote}` : logNote;
239
+ const fix = updateFixHint(tail ?? "", { agendGone: agendAtLaunch && !existsSync(agendPath) });
240
+ fail(`/update could not complete (${reason}).${detail} ${fix ? `Fix: ${fix}` : "Run `agend update` from a host shell."}`);
99
241
  };
100
242
  child.once("error", () => report("updater launch failed"));
101
243
  child.once("exit", (code, signal) => {
102
- if (signal || (code !== 0 && code !== 75))
244
+ if (signal || (code !== 0 && code !== 75)) {
103
245
  report(signal ? "updater was interrupted" : `updater exited ${code ?? "without a status"}`);
246
+ }
104
247
  });
105
248
  }
106
249
  //# sourceMappingURL=update-launch.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"update-launch.js","sourceRoot":"","sources":["../src/update-launch.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"update-launch.js","sourceRoot":"","sources":["../src/update-launch.ts"],"names":[],"mappings":"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"}
package/dist/web-api.d.ts CHANGED
@@ -10,6 +10,7 @@ import { type WebChatHistory } from "./web-chat-history.js";
10
10
  import { type WebFileLedger } from "./web-upload.js";
11
11
  import type { WebSessionStore } from "./web-session.js";
12
12
  import { type WebPrefsStore } from "./web-prefs.js";
13
+ import { type WebAccount } from "./web-profile.js";
13
14
  import { type MentionNames, type MentionQuery } from "./web-mentions.js";
14
15
  import type { ExplicitInstanceRemoval } from "./instance-removal.js";
15
16
  /**
@@ -104,7 +105,7 @@ export interface WebApiContext {
104
105
  * (#1320 part B). Resolves the entries and adapters itself; returns how
105
106
  * many channels were posted to. Never rejects the web send on failure.
106
107
  */
107
- sendClassicWebEcho?(instance: string, text: string): Promise<number>;
108
+ sendClassicWebEcho?(instance: string, text: string, sender?: string): Promise<number>;
108
109
  /** false: definitely not delivered (the instance's IPC is gone, or it was restarted meanwhile). */
109
110
  deliverToInstance(instanceName: string, payload: Record<string, unknown>): Promise<boolean | void>;
110
111
  deliverHumanToInstance?(instanceName: string, payload: Record<string, unknown>, origin: HumanOrigin, originalBody: string): Promise<boolean | void>;
@@ -160,10 +161,25 @@ export interface WebApiContext {
160
161
  confirm?: string;
161
162
  }, opts: {
162
163
  publicLink: boolean;
164
+ person?: WebPerson;
163
165
  }): Promise<{
164
166
  status: number;
165
167
  body: unknown;
166
168
  }>;
169
+ /**
170
+ * #1827: a web person — for the account a session is bound to (none: the operator) — as agents and chats see them.
171
+ * Absent: everyone is "web-user", as before.
172
+ */
173
+ webPerson?(owner?: WebAccount): WebPerson;
174
+ /** #1827: set (or, with null, clear) a person's own name; refused with a reason. */
175
+ setWebPersonName?(owner: WebAccount | undefined, raw: unknown): {
176
+ ok: true;
177
+ person: WebPerson;
178
+ } | {
179
+ ok: false;
180
+ status: number;
181
+ error: string;
182
+ };
167
183
  /** #1386: the web's Acknowledge of a delivery item; `principal` is "web:<session handle>" or "cli". */
168
184
  acknowledgeNeedsItem?(id: string, principal: string): {
169
185
  status: number;
@@ -175,9 +191,14 @@ export interface WebApiContext {
175
191
  error?: string;
176
192
  }>;
177
193
  /** #1266: a click on an agent reply's button. */
178
- clickWebReplyButton?(instance: string, id: string, index: number): Promise<{
194
+ clickWebReplyButton?(instance: string, id: string, index: number, voter?: {
195
+ key: string;
196
+ userId: string;
197
+ name: string;
198
+ }): Promise<{
179
199
  status: number;
180
200
  error?: string;
201
+ options?: number[];
181
202
  }>;
182
203
  /** Interrupt the current reply and drop what was queued for it; false when the instance is not running. */
183
204
  cancelInstance?(name: string): boolean;
@@ -232,6 +253,23 @@ export interface WebApiContext {
232
253
  delete(id: string): void;
233
254
  } | null;
234
255
  }
256
+ /** #1827: a web person as the web chat shows them to agents and chats. */
257
+ export interface WebPerson {
258
+ /** Their key in the web preferences (web-profile.ts webPersonKey): never shown. */
259
+ readonly key: string;
260
+ /** Signed in as an account (a sign-in code DMed to it), or the operator. */
261
+ readonly bound: boolean;
262
+ /** What agents see as the id: the bound account's user id on its platform (still `via web`), or "web-user". */
263
+ readonly userId: string;
264
+ /** Their poll ballot's key: the account's `<connection>:<user id>` (as on the platform), or the operator's. */
265
+ readonly voterKey: string;
266
+ /** The name in use: the one they chose, else their account's name at sign-in, else "web-user". */
267
+ readonly name: string;
268
+ /** Whether the name in use is one they chose. */
269
+ readonly set: boolean;
270
+ /** Their account's name at sign-in, made safe (bound only). */
271
+ readonly platformName?: string;
272
+ }
235
273
  /**
236
274
  * Handle a Web UI request. Returns true if handled, false to pass through.
237
275
  */
package/dist/web-api.js CHANGED
@@ -29,6 +29,7 @@ import { newWebMessageId, parseLastEventId } from "./web-chat-history.js";
29
29
  import { attachmentDelivery, displayName, INLINE_MIME, isFileId, MEDIA_RANGE_MAX, publicAttachment, sniffUpload, UPLOAD_LIMITS, wellFormed } from "./web-upload.js";
30
30
  import { getAgendHome } from "./paths.js";
31
31
  import { OPERATOR } from "./web-prefs.js";
32
+ import { WEB_NAME_FALLBACK } from "./web-profile.js";
32
33
  import { commitTeamCreate, commitTeamUpdate } from "./outbound-handlers.js";
33
34
  import { parseMentionQuery } from "./web-mentions.js";
34
35
  import { authorizeExplicitInstanceRemoval } from "./instance-removal.js";
@@ -149,6 +150,37 @@ function stillAuthorized(req, res, url, ctx) {
149
150
  json(res, 401, { error: WEB_TOKEN_INVALID_MESSAGE });
150
151
  return false;
151
152
  }
153
+ /**
154
+ * #1827: whose a request is, asked NOW (after its body arrived: a session revoked, expired or rotated away meanwhile is
155
+ * no one — `null`, never the operator). An authorized session is the account it was signed in as, or (an `agend web`
156
+ * session, the CLI's header token) none: the operator. For recognition only; nothing here authorizes anything.
157
+ */
158
+ function webAccountOf(req, url, ctx) {
159
+ const verdict = evaluateWebRequest(req, url, ctx.webToken ?? null, ctx.webSessions, { touch: false });
160
+ if (verdict.kind !== "allow")
161
+ return null;
162
+ return verdict.via === "session" && verdict.session?.owner ? { owner: verdict.session.owner } : {};
163
+ }
164
+ function webPersonOf(req, url, ctx) {
165
+ // No people kept here: everyone is "web-user", as before, and there is no identity to protect.
166
+ if (!ctx.webPerson)
167
+ return { key: OPERATOR, bound: false, userId: WEB_NAME_FALLBACK, voterKey: "web:operator", name: WEB_NAME_FALLBACK, set: false };
168
+ const who = webAccountOf(req, url, ctx);
169
+ return who ? ctx.webPerson(who.owner) : null;
170
+ }
171
+ /** #1827: the person, or the request is answered 401 here (it is no longer authorized) and null is returned. */
172
+ function webPersonOr401(req, res, url, ctx) {
173
+ const p = webPersonOf(req, url, ctx);
174
+ if (!p)
175
+ json(res, 401, { error: WEB_TOKEN_INVALID_MESSAGE });
176
+ return p;
177
+ }
178
+ /** #1827: what the page's profile card reads — the name they chose (or null), the one in use, and how agents know them. */
179
+ function profileBody(p) {
180
+ return { name: p.set ? p.name : null, shown: p.name, id: p.userId, bound: p.bound, ...(p.platformName !== undefined ? { platform_name: p.platformName } : {}) };
181
+ }
182
+ /** #1823: an SSE frame with the server's clock (no id: it is not a message, and a reconnect gets a fresh one). */
183
+ function sseClock() { return `event: clock\ndata: ${JSON.stringify({ now: Date.now() })}\n\n`; }
152
184
  /**
153
185
  * Handle a Web UI request. Returns true if handled, false to pass through.
154
186
  */
@@ -261,6 +293,8 @@ export function handleWebRequest(req, res, url, ctx) {
261
293
  // #1577: the newest message this answer accounts for — after a restart, the last restored one until this process
262
294
  // records its own (`<boot>-0` would be after(0): the whole restored history again on every poll).
263
295
  cursor: history ? history.pollCursor() : null,
296
+ // #1823 (#1830 review): the server's clock now, for the page's poll countdown (a poll's deadline is the server's).
297
+ now: Date.now(),
264
298
  });
265
299
  return true;
266
300
  }
@@ -274,7 +308,9 @@ export function handleWebRequest(req, res, url, ctx) {
274
308
  "Cache-Control": "no-cache",
275
309
  Connection: "keep-alive",
276
310
  });
277
- res.write(`event: status\ndata: ${JSON.stringify(ctx.getUiStatus())}\n\n`);
311
+ // #1823 (#1830 review): with the status, the server's clock — now and with every heartbeat — that the page counts a
312
+ // poll down by (one write: the frames a connect sends are unchanged in number).
313
+ res.write(`event: status\ndata: ${JSON.stringify(ctx.getUiStatus())}\n\n${sseClock()}`);
278
314
  // An EventSource that reconnects says what it last saw: send what it missed, before anything new.
279
315
  const lastSeen = parseLastEventId(req.headers["last-event-id"]);
280
316
  if (lastSeen !== null && ctx.webChatHistory) {
@@ -310,7 +346,7 @@ export function handleWebRequest(req, res, url, ctx) {
310
346
  }
311
347
  try {
312
348
  // Every open dashboard tab, every 10 s: the status of every instance, serialized on the fleet's loop (#1235).
313
- res.write(measureSyncWork("web.sseStatus", () => `event: status\ndata: ${JSON.stringify(ctx.getUiStatus())}\n\n`));
349
+ res.write(measureSyncWork("web.sseStatus", () => `event: status\ndata: ${JSON.stringify(ctx.getUiStatus())}\n\n`) + sseClock());
314
350
  }
315
351
  catch {
316
352
  cleanup();
@@ -527,6 +563,63 @@ export function handleWebRequest(req, res, url, ctx) {
527
563
  });
528
564
  return true;
529
565
  }
566
+ // #1827: the person's own name — the one agents and chats see for their web messages. Their own profile, so the public
567
+ // link may read and set it too (profile edits are allowed there); a read-only session may as well: it is about them.
568
+ if (path === "/ui/profile" && method === "GET") {
569
+ if (!ctx.webPerson) {
570
+ json(res, 404, { error: "Profiles are not kept on this fleet" });
571
+ return true;
572
+ }
573
+ const p = webPersonOr401(req, res, url, ctx);
574
+ if (p)
575
+ json(res, 200, profileBody(p));
576
+ return true;
577
+ }
578
+ if (path === "/ui/profile" && method === "POST") {
579
+ if (!ctx.setWebPersonName) {
580
+ json(res, 404, { error: "Profiles are not kept on this fleet" });
581
+ return true;
582
+ }
583
+ const set = ctx.setWebPersonName.bind(ctx);
584
+ (async () => {
585
+ let body;
586
+ try {
587
+ body = await parseBody(req);
588
+ }
589
+ catch {
590
+ json(res, 400, { error: "Invalid JSON" });
591
+ return;
592
+ }
593
+ if (!permitWebContinuation(req, res, ctx))
594
+ return;
595
+ if (!body || typeof body !== "object" || Array.isArray(body) || !Object.hasOwn(body, "name")) {
596
+ json(res, 400, { error: "name required (text, or null to clear)" });
597
+ return;
598
+ }
599
+ // Whose: asked once the body is in. A session revoked, expired or rotated away meanwhile writes nothing — it is
600
+ // not the operator (#1833 review).
601
+ const who = webAccountOf(req, url, ctx);
602
+ if (!who) {
603
+ json(res, 401, { error: WEB_TOKEN_INVALID_MESSAGE });
604
+ return;
605
+ }
606
+ const r = set(who.owner, body.name);
607
+ if (!r.ok) {
608
+ json(res, r.status, { error: r.error });
609
+ return;
610
+ }
611
+ // The person's other devices read it at their next status (the prefs rev moved).
612
+ ctx.emitSseEvent("status", ctx.getUiStatus());
613
+ json(res, 200, profileBody(r.person));
614
+ })().catch(err => {
615
+ ctx.logger.error({ err: err.message }, "Saving the web name failed");
616
+ try {
617
+ json(res, 500, { error: "Saving the name failed" });
618
+ }
619
+ catch { /* already answered */ }
620
+ });
621
+ return true;
622
+ }
530
623
  // #1266: a click on an agent reply's button. The set id travels in the body; the public link may click too (a click
531
624
  // is a message, and the public link may send messages).
532
625
  if (method === "POST" && path === "/ui/reply-button") {
@@ -551,8 +644,14 @@ export function handleWebRequest(req, res, url, ctx) {
551
644
  json(res, 400, { error: "instance, id and index required" });
552
645
  return;
553
646
  }
554
- const r = await click(instance, id, index);
555
- json(res, r.status, r.status === 200 ? { answered: true } : { error: r.error ?? "Refused", ...(r.status === 409 ? { gone: true } : {}) });
647
+ // #1823/#1827: the click is this page's person's — on a poll their vote (one per person, on every device of
648
+ // theirs), on one-click buttons their choice — under their web id and name. A request that no longer passes the
649
+ // gate (a session revoked meanwhile) clicks nothing as anyone.
650
+ const person = webPersonOr401(req, res, url, ctx);
651
+ if (!person)
652
+ return;
653
+ const r = await click(instance, id, index, { key: person.voterKey, userId: person.userId, name: person.name });
654
+ json(res, r.status, r.status === 200 ? { answered: true, ...(r.options ? { options: r.options } : {}) } : { error: r.error ?? "Refused", ...(r.status === 409 ? { gone: true } : {}) });
556
655
  })().catch(err => {
557
656
  ctx.logger.error({ err: err.message }, "Web reply-button click failed");
558
657
  try {
@@ -728,7 +827,10 @@ export function handleWebRequest(req, res, url, ctx) {
728
827
  json(res, 400, { error: "invalid confirmation" });
729
828
  return;
730
829
  }
731
- const r = await run({ instance, command, args: str(body.args, MAX_COMMAND_ARGS), confirm: body.confirm }, { publicLink: !!gatewayRequestContext(req) });
830
+ const person = webPersonOr401(req, res, url, ctx); // #1827: asked again, now the body is in
831
+ if (!person)
832
+ return;
833
+ const r = await run({ instance, command, args: str(body.args, MAX_COMMAND_ARGS), confirm: body.confirm }, { publicLink: !!gatewayRequestContext(req), person });
732
834
  json(res, r.status, r.body);
733
835
  })().catch(err => {
734
836
  ctx.logger.error({ err: err.message }, "Web command failed");
@@ -762,7 +864,7 @@ export function handleWebRequest(req, res, url, ctx) {
762
864
  json(res, 409, { error: `${name} is not running` });
763
865
  return true;
764
866
  }
765
- ctx.eventLog?.logActivity("cancel", "web-user", "stop the current reply", name);
867
+ ctx.eventLog?.logActivity("cancel", webPersonOf(req, url, ctx)?.name ?? WEB_NAME_FALLBACK, "stop the current reply", name);
766
868
  json(res, 200, { cancelled: name });
767
869
  return true;
768
870
  }
@@ -993,12 +1095,15 @@ export function handleWebRequest(req, res, url, ctx) {
993
1095
  const parsed = parseOrReject(TaskCreateSchema, body, res);
994
1096
  if (!parsed)
995
1097
  return;
1098
+ const person = webPersonOr401(req, res, url, ctx); // #1827: asked again, now the body is in
1099
+ if (!person)
1100
+ return;
996
1101
  const task = ctx.scheduler.db.createTask({
997
1102
  title: parsed.title,
998
1103
  description: parsed.description,
999
1104
  priority: parsed.priority,
1000
1105
  assignee: parsed.assignee,
1001
- created_by: "web-user",
1106
+ created_by: person.name, // #1827
1002
1107
  });
1003
1108
  json(res, 200, task);
1004
1109
  }
@@ -1025,7 +1130,10 @@ export function handleWebRequest(req, res, url, ctx) {
1025
1130
  return;
1026
1131
  let result;
1027
1132
  if (parsed.action === "claim") {
1028
- result = ctx.scheduler.db.claimTask(id, parsed.assignee || "web-user");
1133
+ const person = parsed.assignee ? null : webPersonOr401(req, res, url, ctx); // #1827: the default is the person
1134
+ if (!parsed.assignee && !person)
1135
+ return;
1136
+ result = ctx.scheduler.db.claimTask(id, parsed.assignee || person.name);
1029
1137
  }
1030
1138
  else if (parsed.action === "complete") {
1031
1139
  result = ctx.scheduler.db.completeTask(id, parsed.result);
@@ -1414,6 +1522,14 @@ function handleSendMessage(req, res, ctx) {
1414
1522
  return;
1415
1523
  }
1416
1524
  const message = typed;
1525
+ // #1827: who is writing — the name agents and chats see, and the id they tell people apart by. Asked now that the
1526
+ // body is in: a session revoked meanwhile sends nothing (not as the operator).
1527
+ const person = webPersonOf(req, new URL(req.url ?? "/", "http://localhost"), ctx);
1528
+ if (!person) {
1529
+ ctx.webFiles?.release(files);
1530
+ json(res, 401, { error: WEB_TOKEN_INVALID_MESSAGE });
1531
+ return;
1532
+ }
1417
1533
  const ts = new Date().toISOString();
1418
1534
  // The id the agent is given, and the one its delivery reports come back under: the page's ticks.
1419
1535
  const messageId = newWebMessageId();
@@ -1432,7 +1548,7 @@ function handleSendMessage(req, res, ctx) {
1432
1548
  // opt-in resolved at send time inside sendClassicWebEcho.
1433
1549
  const canClassicEcho = ctx.isClassicInstance?.(instance) === true && !!ctx.sendClassicWebEcho;
1434
1550
  const settleClassicEcho = canClassicEcho ? ctx.reserveWebChannelEcho?.(instance, async () => {
1435
- await ctx.sendClassicWebEcho(instance, formatWebChannelEcho("web-user", preview, t("web.echo_full_text")));
1551
+ await ctx.sendClassicWebEcho(instance, formatWebChannelEcho(person.name, preview, t("web.echo_full_text")), person.name);
1436
1552
  }) : undefined;
1437
1553
  const settleEcho = canEcho ? ctx.reserveWebChannelEcho?.(instance, async () => {
1438
1554
  // A replacement adapter or edited binding is not the route we reserved.
@@ -1440,7 +1556,7 @@ function handleSendMessage(req, res, ctx) {
1440
1556
  || (ctx.getGroupIdForInstance?.(instance) ?? String(ctx.fleetConfig?.channel?.group_id ?? "")) !== groupId
1441
1557
  || ctx.fleetConfig?.instances[instance]?.topic_id !== topicId)
1442
1558
  return;
1443
- return syncAdapter.sendText(String(groupId), formatWebChannelEcho("web-user", preview, t("web.echo_full_text")), { threadId: String(topicId), format: "text", allowedMentions: { parse: [] } });
1559
+ return syncAdapter.sendText(String(groupId), formatWebChannelEcho(person.name, preview, t("web.echo_full_text")), { threadId: String(topicId), format: "text", allowedMentions: { parse: [] } });
1444
1560
  }) : undefined;
1445
1561
  let delivered;
1446
1562
  try {
@@ -1454,7 +1570,7 @@ function handleSendMessage(req, res, ctx) {
1454
1570
  meta: {
1455
1571
  chat_id: groupId ? String(groupId) : "",
1456
1572
  message_id: messageId,
1457
- user: "web-user", user_id: "web-user",
1573
+ user: person.name, user_id: person.userId,
1458
1574
  ts,
1459
1575
  thread_id: topicId != null ? String(topicId) : "",
1460
1576
  source: "web",
@@ -1492,9 +1608,9 @@ function handleSendMessage(req, res, ctx) {
1492
1608
  ctx.reserveWebChannelEcho?.(instance, () => startProgress(instance), { copy: false })(true);
1493
1609
  }
1494
1610
  ctx.webFiles?.commit(files);
1495
- ctx.lastInboundUser.set(instance, "web-user");
1496
- ctx.eventLog?.logActivity("message", "web-user", (message || `[${files.length} file(s)]`).slice(0, 200), instance);
1497
- ctx.emitSseEvent("message", { instance, sender: "web-user", role: "user", text: message, ts, attachments: files.map(publicAttachment), messageId });
1611
+ ctx.lastInboundUser.set(instance, person.name);
1612
+ ctx.eventLog?.logActivity("message", person.name, (message || `[${files.length} file(s)]`).slice(0, 200), instance);
1613
+ ctx.emitSseEvent("message", { instance, sender: person.name, role: "user", text: message, ts, attachments: files.map(publicAttachment), messageId });
1498
1614
  json(res, 200, { sent: true, messageId });
1499
1615
  }
1500
1616
  catch {