@songsid/agend 2.2.0-alpha.5 → 2.2.0-alpha.6

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 (43) hide show
  1. package/dist/auth-api.d.ts +22 -0
  2. package/dist/auth-api.js +65 -1
  3. package/dist/auth-api.js.map +1 -1
  4. package/dist/channel/adapters/discord.js +9 -0
  5. package/dist/channel/adapters/discord.js.map +1 -1
  6. package/dist/command-table.d.ts +8 -1
  7. package/dist/command-table.js +13 -4
  8. package/dist/command-table.js.map +1 -1
  9. package/dist/fleet-manager.d.ts +38 -0
  10. package/dist/fleet-manager.js +128 -5
  11. package/dist/fleet-manager.js.map +1 -1
  12. package/dist/locale.js +10 -0
  13. package/dist/locale.js.map +1 -1
  14. package/dist/public-web-gateway.js +2 -2
  15. package/dist/public-web-gateway.js.map +1 -1
  16. package/dist/topic-commands.js +3 -2
  17. package/dist/topic-commands.js.map +1 -1
  18. package/dist/ui/chat-render.js +6 -0
  19. package/dist/ui/chat-strings.js +4 -0
  20. package/dist/ui/chat-thread.js +7 -3
  21. package/dist/ui/panel-chat.js +7 -0
  22. package/dist/ui/preview-panel.js +2 -1
  23. package/dist/ui/preview.js +49 -0
  24. package/dist/ui/shared/agend-auth.js +15 -7
  25. package/dist/ui/shared/app.css +8 -1
  26. package/dist/ui/shared/signin.js +38 -1
  27. package/dist/ui/signin.html +3 -0
  28. package/dist/web-chat-history.d.ts +97 -6
  29. package/dist/web-chat-history.js +189 -12
  30. package/dist/web-chat-history.js.map +1 -1
  31. package/dist/web-chat-store.d.ts +45 -0
  32. package/dist/web-chat-store.js +192 -0
  33. package/dist/web-chat-store.js.map +1 -0
  34. package/dist/web-login.d.ts +2 -0
  35. package/dist/web-login.js +4 -0
  36. package/dist/web-login.js.map +1 -1
  37. package/dist/web-returning-device.d.ts +84 -0
  38. package/dist/web-returning-device.js +204 -0
  39. package/dist/web-returning-device.js.map +1 -0
  40. package/dist/web-upload.d.ts +21 -0
  41. package/dist/web-upload.js +50 -1
  42. package/dist/web-upload.js.map +1 -1
  43. package/package.json +1 -1
@@ -3,7 +3,9 @@
3
3
  // Two jobs: (1) when the page is what a gated URL answered with because the browser sent no cookie
4
4
  // (a SameSite=Strict cookie is not sent on a navigation that came from a chat app), probe the session
5
5
  // from *here* — a same-site request does carry the cookie — and carry on to the page that was asked
6
- // for; (2) otherwise take the one-time code and exchange it.
6
+ // for; (2) otherwise take the one-time code and exchange it. A browser that signed in before with a code from
7
+ // /dashboard (a returning device, #1570) is also offered "Send me a new code": the server sends it privately to the
8
+ // person who received that earlier code — the page never learns who that is.
7
9
  (() => {
8
10
  "use strict";
9
11
  const $ = (id) => document.getElementById(id);
@@ -15,6 +17,9 @@
15
17
  refused: "That code did not work — it may be wrong, expired or already used. Ask for a new one with /dashboard.",
16
18
  paused: "Too many wrong codes — sign-in is paused for a few minutes.",
17
19
  network: "Could not reach AgEnD. Check the connection and try again.",
20
+ resend: "Send me a new code", resent: "A new code was sent to you privately in chat. Enter it above.",
21
+ resend_wait: "A code was asked for a moment ago — wait a little and try again.",
22
+ resend_refused: "A new code could not be sent. Ask for one with /dashboard.",
18
23
  },
19
24
  "zh-TW": {
20
25
  checking: "正在確認登入狀態…", title: "登入 AgEnD", lead: "請輸入聊天頻道給你的一次性登入碼。",
@@ -23,6 +28,9 @@
23
28
  refused: "登入碼無效:可能輸入錯誤、已過期或已使用。請用 /dashboard 再要一個。",
24
29
  paused: "錯誤次數過多,登入暫停幾分鐘。",
25
30
  network: "連不上 AgEnD,請檢查連線後再試。",
31
+ resend: "傳一組新的登入碼給我", resent: "新的登入碼已私訊給你,請在上方輸入。",
32
+ resend_wait: "剛剛才要過登入碼,請稍候再試。",
33
+ resend_refused: "無法傳送新的登入碼。請用 /dashboard 再要一個。",
26
34
  },
27
35
  };
28
36
  const lang = /^zh/i.test(navigator.language || "") ? "zh-TW" : "en";
@@ -97,8 +105,36 @@
97
105
  if (note) { sessionStorage.removeItem("agend_signout_note"); $("msg").textContent = note; }
98
106
  } catch { /* private mode */ }
99
107
  $("code").focus();
108
+ offerResend();
100
109
  }
101
110
 
111
+ // Only a returning device gets the button; the answer is a boolean and asking has no side effect.
112
+ async function offerResend() {
113
+ try {
114
+ const r = await fetch("/auth/device", { credentials: "same-origin", cache: "no-store" });
115
+ if (r.ok && (await r.json()).returning === true) $("resend").hidden = false;
116
+ } catch { /* no button */ }
117
+ }
118
+
119
+ $("resend").addEventListener("click", async () => {
120
+ const button = $("resend");
121
+ const msg = $("msg");
122
+ msg.textContent = "";
123
+ msg.classList?.remove("ok");
124
+ button.disabled = true;
125
+ try {
126
+ const r = await fetch("/auth/request-code", {
127
+ method: "POST", credentials: "same-origin", headers: { "Content-Type": "application/json" }, body: "{}",
128
+ });
129
+ if (r.status === 202) { msg.classList?.add("ok"); msg.textContent = t("resent"); $("code").focus(); }
130
+ else if (r.status === 429) msg.textContent = t("resend_wait");
131
+ else { msg.textContent = t("resend_refused"); if (r.status === 401) button.hidden = true; }
132
+ } catch {
133
+ msg.textContent = t("network");
134
+ }
135
+ button.disabled = false;
136
+ });
137
+
102
138
  async function probe() {
103
139
  // A second bounce inside ten seconds means the cookie is valid but not being sent on the
104
140
  // navigation; going round again would loop, so stop and let the person type a code.
@@ -116,6 +152,7 @@
116
152
  const button = $("go");
117
153
  const msg = $("msg");
118
154
  msg.textContent = "";
155
+ msg.classList?.remove("ok");
119
156
  button.disabled = true;
120
157
  button.textContent = t("working");
121
158
  try {
@@ -28,7 +28,9 @@
28
28
  border: 0; border-radius: var(--r-full); cursor: pointer; }
29
29
  button:hover:not(:disabled) { opacity: .88; }
30
30
  button:disabled { opacity: .6; cursor: default; }
31
+ button.secondary { margin-top: 10px; color: var(--text); background: transparent; border: 1px solid var(--border-strong); }
31
32
  #msg { min-height: 1.5em; margin-top: 14px; font-size: var(--fs-sm); color: var(--danger); }
33
+ #msg.ok { color: var(--text-2); }
32
34
  .hint { margin-top: 18px; font-size: var(--fs-xs); color: var(--text-3); }
33
35
  .hint code { white-space: nowrap; font-family: var(--font-mono); }
34
36
  [hidden] { display: none !important; }
@@ -45,6 +47,7 @@
45
47
  <input id="code" name="code" inputmode="text" autocomplete="one-time-code" autocapitalize="characters"
46
48
  autocorrect="off" spellcheck="false" maxlength="12" placeholder="XXXX-XXXX" required>
47
49
  <button id="go" type="submit" data-i18n="submit">Sign in</button>
50
+ <button id="resend" type="button" class="secondary" hidden data-i18n="resend">Send me a new code</button>
48
51
  <div id="msg" role="alert" aria-live="polite"></div>
49
52
  <div class="hint" data-i18n="hint">Send /dashboard to your AgEnD bot, or run “<code>agend web --code</code>” on the host. A code works once and expires in 5 minutes.</div>
50
53
  </form>
@@ -6,6 +6,17 @@ export interface WebChatAttachment {
6
6
  size: number;
7
7
  mime: string;
8
8
  }
9
+ /**
10
+ * #1565: a file shown with a message from before the fleet restarted that could not be served again (missing, moved,
11
+ * or failing one of the ledger's checks): no id — the page shows the name as unavailable, and nothing can be fetched.
12
+ */
13
+ export interface WebChatGoneAttachment {
14
+ gone: true;
15
+ kind: "photo" | "document";
16
+ name: string;
17
+ size: number;
18
+ mime: string;
19
+ }
9
20
  /**
10
21
  * How far a message the web user sent has got (web track C3) — the ticks under it. The same lifecycle a
11
22
  * Telegram message shows as reactions: waiting behind another message, handed to the agent, taken up by it,
@@ -24,8 +35,8 @@ export interface WebChatButtons {
24
35
  by?: string;
25
36
  }
26
37
  export interface WebChatMessage {
27
- /** Files shown with the message (absent when none). */
28
- attachments?: WebChatAttachment[];
38
+ /** Files shown with the message (absent when none); a restored one that cannot be served again is `gone` (#1565). */
39
+ attachments?: Array<WebChatAttachment | WebChatGoneAttachment>;
29
40
  /** #1266: an agent reply's buttons (agent messages only). */
30
41
  buttons?: WebChatButtons;
31
42
  /** The fleet process generation the id belongs to. */
@@ -55,6 +66,53 @@ export interface WebChatHistoryOptions {
55
66
  replayMax?: number;
56
67
  /** The generation id (tests); random otherwise. */
57
68
  boot?: string;
69
+ /** #1565: where the history is kept between fleet processes (web-chat-store.ts); none: memory only. */
70
+ store?: WebChatPersistence | null;
71
+ /** #1565: the file ledger, so a kept message's files are served again after a restart; none: they are not. */
72
+ files?: WebChatFiles | null;
73
+ }
74
+ /** #1565: a message as it is kept on disk — what was said, never the interactive state; files with their paths. */
75
+ export interface StoredWebChatMessage {
76
+ boot: string;
77
+ id: number;
78
+ instance: string;
79
+ role: WebChatRole;
80
+ sender: string;
81
+ text: string;
82
+ ts: string;
83
+ attachments?: Array<{
84
+ id?: string;
85
+ path?: string;
86
+ kind: "photo" | "document";
87
+ name: string;
88
+ size: number;
89
+ mime: string;
90
+ }>;
91
+ }
92
+ /** #1565: what the history needs of the file ledger (web-upload.ts). */
93
+ export interface WebChatFiles {
94
+ /** The path to keep with a file id (null: not served, or an upload no message took — never kept). */
95
+ storablePath(id: string): string | null;
96
+ /** Serve a kept file again under its id if it passes every check; null: it does not (shown as unavailable). */
97
+ restore(entry: {
98
+ id: string;
99
+ path: string;
100
+ name: string;
101
+ mime: string;
102
+ kind: string;
103
+ }, instance: string): {
104
+ id: string;
105
+ kind: "photo" | "document";
106
+ size: number;
107
+ mime: string;
108
+ } | null;
109
+ /** These ids are no longer shown: nothing is served under them. */
110
+ drop(ids: string[]): void;
111
+ }
112
+ /** #1565: what the history needs of its disk store. */
113
+ export interface WebChatPersistence {
114
+ schedule(instance: string, snapshot: () => StoredWebChatMessage[]): void;
115
+ remove(instance: string): Promise<void>;
58
116
  }
59
117
  export declare const WEB_CHAT_TEXT_MAX = 16000;
60
118
  /**
@@ -72,7 +130,36 @@ export declare class WebChatHistory {
72
130
  private readonly perInstance;
73
131
  private readonly perInstanceChars;
74
132
  private readonly replayMax;
133
+ private store;
134
+ private files;
135
+ /** #1565: the boots of restored messages, by the time of their first message — older processes, in order. */
136
+ private readonly restoredBoots;
75
137
  constructor(opts?: WebChatHistoryOptions);
138
+ /** #1565: keep this history on disk from now on (the fleet sets it at start, once its home is known). */
139
+ setStore(store: WebChatPersistence | null): void;
140
+ /** #1565: the file ledger (set at fleet start, before restore()). */
141
+ setFiles(files: WebChatFiles | null): void;
142
+ private persist;
143
+ /** #1565: a message as kept on disk: no buttons, no delivery, no message id; a file with the path it is served from. */
144
+ private stored;
145
+ /** #1565: the file ids these messages show that no message still kept for the instance shows: no longer served. */
146
+ private dropFiles;
147
+ /**
148
+ * The order of the boots this history holds: older processes first (by their first restored message), this process
149
+ * last. rank(boot) is its place, or -1 for a boot this history does not hold.
150
+ */
151
+ private bootRanks;
152
+ /**
153
+ * #1565: the messages this instance had in an earlier fleet process, as stored (web-chat-store.ts) — validated
154
+ * here, never trusted: a row that is not ours in shape is dropped; text is cut; the role is kept as stored and is
155
+ * never made `agent` (anything else is a person's message); nothing interactive comes back (no buttons, no ticks).
156
+ * Bounds as for record(). Then each kept message's files are served again under their ids, by the file ledger's
157
+ * checks; a file that fails one — or is missing — is `gone` (its name shown as unavailable). Returns how many
158
+ * messages it restored. Only for an instance with nothing recorded yet in this process.
159
+ */
160
+ restore(instance: string, rows: unknown[] | null): number;
161
+ /** #1565: a restored row's files served again (only the rows kept: an older one's file is never registered). */
162
+ private restoreFiles;
76
163
  /** The id the next message will get minus one: the newest id handed out so far (0 when none). */
77
164
  get lastId(): number;
78
165
  /** Record one message; returns it with its id. Text beyond WEB_CHAT_TEXT_MAX is cut. */
@@ -103,6 +190,8 @@ export declare class WebChatHistory {
103
190
  * Ids are this boot's: a cursor from another boot goes through replayFor(), never straight here.
104
191
  */
105
192
  after(lastId: number): WebChatMessage[];
193
+ /** The retained messages that pass `keep`, across instances, in boot order then id order, at most replayMax (newest). */
194
+ private collect;
106
195
  /**
107
196
  * A delivery report for one of this instance's messages. Returns the message when its state changed (so the
108
197
  * caller tells the pages), null when there is no such message or the report would move it back.
@@ -125,14 +214,16 @@ export declare class WebChatHistory {
125
214
  delivery: WebDeliveryState;
126
215
  }>;
127
216
  cancelPending(instance: string): WebChatMessage[];
128
- /** Forget an instance (deleted). */
217
+ /** Forget an instance (deleted) — and its file (#1565): a later instance of the same name starts empty. */
129
218
  forget(instance: string): void;
130
219
  /** The SSE cursor for one message: `<boot>-<id>`. */
131
220
  cursorOf(m: WebChatMessage): string;
132
221
  /**
133
- * What a reconnecting stream with this `Last-Event-ID` should be sent. A cursor of this boot replays what
134
- * came after it; a cursor of another boot (the fleet restarted) gets this boot's whole retained backlog,
135
- * since none of it can have been seen; no cursor, or one that is not ours in shape, gets nothing.
222
+ * What a reconnecting stream with this `Last-Event-ID` should be sent. A cursor of this boot replays what came
223
+ * after it. #1565: a cursor of a restored boot (a page that stayed open across the restart) gets what came after
224
+ * it in that boot and everything of the later boots — never a message it already has. A cursor of a boot this
225
+ * process does not hold gets everything retained (the page keeps one entry per boot+id, so nothing doubles). No
226
+ * cursor, or one that is not ours in shape, gets nothing.
136
227
  */
137
228
  replayFor(cursor: {
138
229
  boot: string;
@@ -7,11 +7,16 @@
7
7
  * of one instance, and an EventSource that reconnects with `Last-Event-ID` is sent what it missed.
8
8
  *
9
9
  * Bounded by count AND by bytes per instance, so a chatty agent cannot grow the fleet process without limit.
10
- * In memory only: it survives a page reload, not a fleet restart (persisting chat text is a separate decision).
10
+ * #1565: it also survives a fleet restart — the same bounded history is kept on the local disk (web-chat-store.ts)
11
+ * and restored at fleet start, every message with the boot and id it had. What is kept is what was said: the text,
12
+ * who said it, and its files (served again under their ids when they still pass the ledger's checks) — never the
13
+ * interactive state (buttons, delivery ticks), which belonged to the process that ended.
11
14
  *
12
15
  * Ids count from 1 in every fleet process, so an id alone is not an identity across a restart: each history
13
- * has a random `boot` generation, every message carries it, and the SSE cursor is `<boot>-<id>`. A cursor
14
- * from another boot is not compared with this boot's ids at all — that client gets this boot's backlog.
16
+ * has a random `boot` generation, every message carries it, and the SSE cursor is `<boot>-<id>`. Restored messages
17
+ * keep their boot and id, so a page that stayed open across the restart already holds them (it keeps one entry per
18
+ * boot+id); the server knows the order of the boots it holds, and a cursor of a restored boot is sent only what came
19
+ * after it.
15
20
  */
16
21
  import { randomBytes } from "node:crypto";
17
22
  /**
@@ -63,11 +68,121 @@ export class WebChatHistory {
63
68
  perInstance;
64
69
  perInstanceChars;
65
70
  replayMax;
71
+ store;
72
+ files;
73
+ /** #1565: the boots of restored messages, by the time of their first message — older processes, in order. */
74
+ restoredBoots = new Map();
66
75
  constructor(opts = {}) {
67
76
  this.perInstance = opts.perInstance ?? 500;
68
77
  this.perInstanceChars = opts.perInstanceChars ?? 1_000_000;
69
78
  this.replayMax = opts.replayMax ?? 500;
70
79
  this.boot = opts.boot ?? randomBytes(6).toString("hex");
80
+ this.store = opts.store ?? null;
81
+ this.files = opts.files ?? null;
82
+ }
83
+ /** #1565: keep this history on disk from now on (the fleet sets it at start, once its home is known). */
84
+ setStore(store) { this.store = store; }
85
+ /** #1565: the file ledger (set at fleet start, before restore()). */
86
+ setFiles(files) { this.files = files; }
87
+ persist(instance) {
88
+ if (!this.store)
89
+ return;
90
+ this.store.schedule(instance, () => (this.byInstance.get(instance)?.messages ?? []).map((m) => this.stored(m)));
91
+ }
92
+ /** #1565: a message as kept on disk: no buttons, no delivery, no message id; a file with the path it is served from. */
93
+ stored(m) {
94
+ const row = { boot: m.boot, id: m.id, instance: m.instance, role: m.role, sender: m.sender, text: m.text, ts: m.ts };
95
+ if (m.attachments?.length) {
96
+ row.attachments = m.attachments.map((a) => {
97
+ const base = { kind: a.kind, name: a.name, size: a.size, mime: a.mime };
98
+ const path = "id" in a && this.files ? this.files.storablePath(a.id) : null;
99
+ return path && "id" in a ? { id: a.id, path, ...base } : base;
100
+ });
101
+ }
102
+ return row;
103
+ }
104
+ /** #1565: the file ids these messages show that no message still kept for the instance shows: no longer served. */
105
+ dropFiles(instance, gone) {
106
+ if (!this.files)
107
+ return;
108
+ const ids = new Set();
109
+ for (const m of gone)
110
+ for (const a of m.attachments ?? [])
111
+ if ("id" in a)
112
+ ids.add(a.id);
113
+ if (!ids.size)
114
+ return;
115
+ for (const m of this.byInstance.get(instance)?.messages ?? [])
116
+ for (const a of m.attachments ?? [])
117
+ if ("id" in a)
118
+ ids.delete(a.id);
119
+ if (ids.size)
120
+ this.files.drop([...ids]);
121
+ }
122
+ /**
123
+ * The order of the boots this history holds: older processes first (by their first restored message), this process
124
+ * last. rank(boot) is its place, or -1 for a boot this history does not hold.
125
+ */
126
+ bootRanks() {
127
+ const order = [...this.restoredBoots.entries()].sort((a, b) => (a[1] < b[1] ? -1 : a[1] > b[1] ? 1 : a[0] < b[0] ? -1 : 1)).map(([b]) => b);
128
+ const at = new Map(order.map((b, i) => [b, i]));
129
+ return (boot) => (boot === this.boot ? Number.MAX_SAFE_INTEGER : at.get(boot) ?? -1);
130
+ }
131
+ /**
132
+ * #1565: the messages this instance had in an earlier fleet process, as stored (web-chat-store.ts) — validated
133
+ * here, never trusted: a row that is not ours in shape is dropped; text is cut; the role is kept as stored and is
134
+ * never made `agent` (anything else is a person's message); nothing interactive comes back (no buttons, no ticks).
135
+ * Bounds as for record(). Then each kept message's files are served again under their ids, by the file ledger's
136
+ * checks; a file that fails one — or is missing — is `gone` (its name shown as unavailable). Returns how many
137
+ * messages it restored. Only for an instance with nothing recorded yet in this process.
138
+ */
139
+ restore(instance, rows) {
140
+ if (!Array.isArray(rows) || this.byInstance.has(instance))
141
+ return 0;
142
+ const seen = new Set();
143
+ const out = [];
144
+ for (const raw of rows) {
145
+ const r = restoredRow(raw, instance, this.boot);
146
+ if (!r)
147
+ continue;
148
+ const key = `${r.message.boot}:${r.message.id}`;
149
+ if (seen.has(key))
150
+ continue;
151
+ seen.add(key);
152
+ out.push(r);
153
+ }
154
+ // The newest within the bounds, in their order.
155
+ let chars = 0, from = out.length;
156
+ while (from > 0 && out.length - from < this.perInstance && chars + out[from - 1].message.text.length <= this.perInstanceChars)
157
+ chars += out[--from].message.text.length;
158
+ const kept = out.slice(from).map((r) => this.restoreFiles(r, instance));
159
+ if (!kept.length)
160
+ return 0;
161
+ this.byInstance.set(instance, { messages: kept, chars });
162
+ for (const m of kept) {
163
+ const first = this.restoredBoots.get(m.boot);
164
+ if (first === undefined || m.ts < first)
165
+ this.restoredBoots.set(m.boot, m.ts);
166
+ }
167
+ return kept.length;
168
+ }
169
+ /** #1565: a restored row's files served again (only the rows kept: an older one's file is never registered). */
170
+ restoreFiles(r, instance) {
171
+ if (!r.files.length)
172
+ return r.message;
173
+ const seen = new Set();
174
+ r.message.attachments = r.files.map((f) => {
175
+ const gone = { gone: true, kind: f.kind, name: f.name, size: f.size, mime: f.mime };
176
+ // One id, one file: a second row naming an id again is shown as unavailable rather than served twice.
177
+ if (!f.id || !f.path || !this.files || seen.has(f.id))
178
+ return gone;
179
+ const served = this.files.restore({ id: f.id, path: f.path, name: f.name, mime: f.mime, kind: f.kind }, instance);
180
+ if (!served || served.id !== f.id)
181
+ return gone;
182
+ seen.add(f.id);
183
+ return { id: served.id, kind: served.kind, name: f.name, size: served.size, mime: served.mime };
184
+ });
185
+ return r.message;
71
186
  }
72
187
  /** The id the next message will get minus one: the newest id handed out so far (0 when none). */
73
188
  get lastId() { return this.nextId - 1; }
@@ -95,9 +210,16 @@ export class WebChatHistory {
95
210
  }
96
211
  slot.messages.push(entry);
97
212
  slot.chars += entry.text.length;
213
+ const evicted = [];
98
214
  while (slot.messages.length > 1 && (slot.messages.length > this.perInstance || slot.chars > this.perInstanceChars)) {
99
- slot.chars -= slot.messages.shift().text.length;
215
+ const old = slot.messages.shift();
216
+ slot.chars -= old.text.length;
217
+ evicted.push(old);
100
218
  }
219
+ // #1565: a file leaves with its message — nothing is served under its id any more.
220
+ if (evicted.length)
221
+ this.dropFiles(entry.instance, evicted);
222
+ this.persist(entry.instance);
101
223
  return entry;
102
224
  }
103
225
  /**
@@ -113,6 +235,7 @@ export class WebChatHistory {
113
235
  const m = slot.messages[i];
114
236
  if (m.buttons?.id === next.id) {
115
237
  m.buttons = next;
238
+ this.persist(instance);
116
239
  return m;
117
240
  }
118
241
  }
@@ -143,13 +266,19 @@ export class WebChatHistory {
143
266
  after(lastId) {
144
267
  if (!Number.isFinite(lastId) || lastId < 0)
145
268
  return [];
269
+ // #1565: only this boot's ids compare with `lastId`; 0 (no cursor yet) is everything retained, restored too.
270
+ return this.collect((m) => (m.boot === this.boot ? m.id > lastId : lastId === 0));
271
+ }
272
+ /** The retained messages that pass `keep`, across instances, in boot order then id order, at most replayMax (newest). */
273
+ collect(keep) {
146
274
  const out = [];
147
275
  for (const slot of this.byInstance.values()) {
148
276
  for (const m of slot.messages)
149
- if (m.id > lastId)
277
+ if (keep(m))
150
278
  out.push(m);
151
279
  }
152
- out.sort((a, b) => a.id - b.id);
280
+ const r = this.bootRanks();
281
+ out.sort((a, b) => (r(a.boot) - r(b.boot)) || (a.id - b.id));
153
282
  return out.length > this.replayMax ? out.slice(-this.replayMax) : out;
154
283
  }
155
284
  /**
@@ -168,6 +297,7 @@ export class WebChatHistory {
168
297
  if (next === m.delivery)
169
298
  return null;
170
299
  m.delivery = next;
300
+ this.persist(instance);
171
301
  return m;
172
302
  }
173
303
  /**
@@ -202,23 +332,70 @@ export class WebChatHistory {
202
332
  m.delivery = "cancelled";
203
333
  changed.push(m);
204
334
  }
335
+ if (changed.length)
336
+ this.persist(instance);
205
337
  return changed.reverse();
206
338
  }
207
- /** Forget an instance (deleted). */
208
- forget(instance) { this.byInstance.delete(instance); }
339
+ /** Forget an instance (deleted) — and its file (#1565): a later instance of the same name starts empty. */
340
+ forget(instance) {
341
+ const messages = this.byInstance.get(instance)?.messages ?? [];
342
+ this.byInstance.delete(instance);
343
+ this.dropFiles(instance, messages);
344
+ if (this.store)
345
+ void this.store.remove(instance);
346
+ }
209
347
  /** The SSE cursor for one message: `<boot>-<id>`. */
210
348
  cursorOf(m) { return `${m.boot}-${m.id}`; }
211
349
  /**
212
- * What a reconnecting stream with this `Last-Event-ID` should be sent. A cursor of this boot replays what
213
- * came after it; a cursor of another boot (the fleet restarted) gets this boot's whole retained backlog,
214
- * since none of it can have been seen; no cursor, or one that is not ours in shape, gets nothing.
350
+ * What a reconnecting stream with this `Last-Event-ID` should be sent. A cursor of this boot replays what came
351
+ * after it. #1565: a cursor of a restored boot (a page that stayed open across the restart) gets what came after
352
+ * it in that boot and everything of the later boots — never a message it already has. A cursor of a boot this
353
+ * process does not hold gets everything retained (the page keeps one entry per boot+id, so nothing doubles). No
354
+ * cursor, or one that is not ours in shape, gets nothing.
215
355
  */
216
356
  replayFor(cursor) {
217
357
  if (!cursor)
218
358
  return [];
219
- return cursor.boot === this.boot ? this.after(cursor.id) : this.after(0);
359
+ if (cursor.boot === this.boot)
360
+ return this.after(cursor.id);
361
+ const rank = this.bootRanks();
362
+ const at = rank(cursor.boot);
363
+ if (at < 0)
364
+ return this.collect(() => true);
365
+ return this.collect((m) => { const r = rank(m.boot); return r > at || (r === at && m.id > cursor.id); });
220
366
  }
221
367
  }
368
+ /**
369
+ * #1565: one stored row as a restored message (and its files, to serve again), or null when it is not ours in shape.
370
+ * Only what was said comes back: no buttons, no delivery tick, no message id — whatever a row carries of those.
371
+ */
372
+ function restoredRow(raw, instance, thisBoot) {
373
+ if (!raw || typeof raw !== "object" || Array.isArray(raw))
374
+ return null;
375
+ const r = raw;
376
+ if (typeof r.boot !== "string" || !/^[0-9a-f]{1,32}$/.test(r.boot) || r.boot === thisBoot)
377
+ return null;
378
+ if (typeof r.id !== "number" || !Number.isSafeInteger(r.id) || r.id < 1)
379
+ return null;
380
+ if (r.instance !== instance || typeof r.sender !== "string" || typeof r.text !== "string" || typeof r.ts !== "string")
381
+ return null;
382
+ // The role as stored — a person's message unless it is one of the three; never upgraded to `agent`.
383
+ const role = typeof r.role === "string" && ROLES.has(r.role) ? r.role : "user";
384
+ const message = { boot: r.boot, id: r.id, instance, role, sender: r.sender.slice(0, 256), text: r.text.slice(0, WEB_CHAT_TEXT_MAX), ts: r.ts.slice(0, 64) };
385
+ const files = !Array.isArray(r.attachments) ? [] : r.attachments.slice(0, 20).flatMap((a) => {
386
+ if (!a || typeof a !== "object" || Array.isArray(a))
387
+ return [];
388
+ const f = a;
389
+ if (typeof f.name !== "string")
390
+ return [];
391
+ return [{
392
+ ...(typeof f.id === "string" ? { id: f.id } : {}), ...(typeof f.path === "string" ? { path: f.path } : {}),
393
+ kind: f.kind === "photo" ? "photo" : "document", name: f.name.slice(0, 255),
394
+ size: typeof f.size === "number" && Number.isSafeInteger(f.size) && f.size >= 0 ? f.size : 0, mime: typeof f.mime === "string" ? f.mime.slice(0, 128) : "",
395
+ }];
396
+ });
397
+ return { message, files };
398
+ }
222
399
  /** `Last-Event-ID` as `<boot>-<id>`, or null when absent or not that shape. */
223
400
  export function parseLastEventId(header) {
224
401
  const raw = (Array.isArray(header) ? header[0] : header)?.trim();
@@ -1 +1 @@
1
- {"version":3,"file":"web-chat-history.js","sourceRoot":"","sources":["../src/web-chat-history.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"web-chat-history.js","sourceRoot":"","sources":["../src/web-chat-history.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,45 @@
1
+ import type { StoredWebChatMessage } from "./web-chat-history.js";
2
+ export declare const WEB_CHAT_FILE = "web-chat.json";
3
+ /** A file larger than this is not read (the bounds keep a real one far smaller). */
4
+ export declare const WEB_CHAT_FILE_MAX_BYTES: number;
5
+ export interface WebChatStoreLogger {
6
+ warn(obj: unknown, msg?: string): void;
7
+ debug?(obj: unknown, msg?: string): void;
8
+ }
9
+ /** The rule instance paths are held to: no separator, no control character, no traversal. */
10
+ export declare function isSafeInstanceDirName(name: string): boolean;
11
+ export declare class WebChatDiskStore {
12
+ private readonly home;
13
+ private readonly logger;
14
+ private readonly debounceMs;
15
+ /**
16
+ * Who the instance is now: a fleet agent's working directory, a ClassicBot room's channel. Written with the file
17
+ * and required to match when it is read, so a later instance that only shares the name (deleted while the fleet was
18
+ * down, then created again elsewhere) never gets another one's history. Null: not configured — not written.
19
+ */
20
+ private readonly ownerOf;
21
+ /** instance → its pending write (a timer) and whether one is in flight. */
22
+ private readonly pending;
23
+ /** Instances forgotten: a write already under way must not bring the file back. */
24
+ private readonly gone;
25
+ constructor(opts: {
26
+ home: string;
27
+ logger: WebChatStoreLogger;
28
+ debounceMs?: number;
29
+ ownerOf: (instance: string) => string | null;
30
+ });
31
+ pathOf(instance: string): string | null;
32
+ /**
33
+ * The stored messages of one instance, as written (validated later by the history), or null: no file, or one that
34
+ * is skipped (too large, unreadable, not JSON, not ours, another instance's) — said once in the log.
35
+ */
36
+ load(instance: string): unknown[] | null;
37
+ /** The instance's history changed: write it soon (debounced; one write in flight; the latest snapshot wins). */
38
+ schedule(instance: string, snapshot: () => StoredWebChatMessage[]): void;
39
+ private write;
40
+ private writeFile;
41
+ /** Every pending write done (tests; a clean shutdown). */
42
+ flush(): Promise<void>;
43
+ /** The instance is gone: no further write, and the file (and any temporary one of ours) is deleted. */
44
+ remove(instance: string): Promise<void>;
45
+ }