@songsid/agend 2.3.0-beta.16 → 2.3.0-beta.18

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/README.md +1 -1
  2. package/README.zh-TW.md +1 -1
  3. package/dist/backend/claude-code.js +13 -4
  4. package/dist/backend/claude-code.js.map +1 -1
  5. package/dist/backend/codex.js +15 -2
  6. package/dist/backend/codex.js.map +1 -1
  7. package/dist/backend-command.d.ts +2 -0
  8. package/dist/backend-command.js +3 -1
  9. package/dist/backend-command.js.map +1 -1
  10. package/dist/bug-report-cli.d.ts +30 -0
  11. package/dist/bug-report-cli.js +138 -0
  12. package/dist/bug-report-cli.js.map +1 -0
  13. package/dist/bug-report.d.ts +47 -0
  14. package/dist/bug-report.js +136 -0
  15. package/dist/bug-report.js.map +1 -0
  16. package/dist/channel/mcp-tools.js +1 -1
  17. package/dist/channel/mcp-tools.js.map +1 -1
  18. package/dist/cli.js +93 -8
  19. package/dist/cli.js.map +1 -1
  20. package/dist/config-validator.d.ts +6 -0
  21. package/dist/config-validator.js +13 -0
  22. package/dist/config-validator.js.map +1 -1
  23. package/dist/daemon.d.ts +14 -1
  24. package/dist/daemon.js +59 -3
  25. package/dist/daemon.js.map +1 -1
  26. package/dist/diagnostic-redaction.d.ts +10 -0
  27. package/dist/diagnostic-redaction.js +167 -0
  28. package/dist/diagnostic-redaction.js.map +1 -0
  29. package/dist/fleet-manager.d.ts +18 -0
  30. package/dist/fleet-manager.js +109 -8
  31. package/dist/fleet-manager.js.map +1 -1
  32. package/dist/general-knowledge/skills/bug-report/SKILL.md +31 -0
  33. package/dist/general-knowledge/skills/web-dashboard/SKILL.md +22 -1
  34. package/dist/instance-lifecycle.d.ts +8 -1
  35. package/dist/instance-lifecycle.js +68 -12
  36. package/dist/instance-lifecycle.js.map +1 -1
  37. package/dist/locale.js +55 -2
  38. package/dist/locale.js.map +1 -1
  39. package/dist/login-controller.d.ts +45 -0
  40. package/dist/login-controller.js +66 -3
  41. package/dist/login-controller.js.map +1 -1
  42. package/dist/ls-attach-resolve.d.ts +3 -2
  43. package/dist/ls-attach-resolve.js +10 -4
  44. package/dist/ls-attach-resolve.js.map +1 -1
  45. package/dist/ls-rows.d.ts +12 -0
  46. package/dist/ls-rows.js +82 -3
  47. package/dist/ls-rows.js.map +1 -1
  48. package/dist/needs-you.d.ts +10 -0
  49. package/dist/needs-you.js +2 -1
  50. package/dist/needs-you.js.map +1 -1
  51. package/dist/outbound-handlers.js +31 -5
  52. package/dist/outbound-handlers.js.map +1 -1
  53. package/dist/quickstart-api.d.ts +9 -0
  54. package/dist/quickstart-api.js +82 -0
  55. package/dist/quickstart-api.js.map +1 -1
  56. package/dist/service-installer.js +12 -0
  57. package/dist/service-installer.js.map +1 -1
  58. package/dist/settings-effect.js +15 -1
  59. package/dist/settings-effect.js.map +1 -1
  60. package/dist/setup-form.d.ts +1 -1
  61. package/dist/setup-form.js +23 -7
  62. package/dist/setup-form.js.map +1 -1
  63. package/dist/ui/backend-signin.js +297 -0
  64. package/dist/ui/chat-msg-actions.js +176 -0
  65. package/dist/ui/chat-store.js +33 -3
  66. package/dist/ui/chat-strings.js +8 -2
  67. package/dist/ui/chat-thread.js +44 -2
  68. package/dist/ui/panel-chat.js +37 -0
  69. package/dist/ui/panel-needs.js +4 -2
  70. package/dist/ui/panel-settings.js +6 -3
  71. package/dist/ui/shared/app-shell.js +2 -1
  72. package/dist/ui/shared/app-stream.js +2 -1
  73. package/dist/ui/shared/app.css +42 -0
  74. package/dist/ui/shared/app.js +2 -0
  75. package/dist/ui/shared/usage-dialog.js +26 -3
  76. package/dist/ui/shared/view-strings.js +10 -0
  77. package/dist/ui/web-terminal/terminal.html +1 -1
  78. package/dist/update-launch.d.ts +9 -0
  79. package/dist/update-launch.js +38 -12
  80. package/dist/update-launch.js.map +1 -1
  81. package/dist/usage/format-rich.js +6 -3
  82. package/dist/usage/format-rich.js.map +1 -1
  83. package/dist/usage/i18n-keys.d.ts +1 -1
  84. package/dist/usage/i18n-keys.js +2 -1
  85. package/dist/usage/i18n-keys.js.map +1 -1
  86. package/dist/usage/i18n.d.ts +13 -1
  87. package/dist/usage/i18n.js +29 -0
  88. package/dist/usage/i18n.js.map +1 -1
  89. package/dist/usage/providers.d.ts +43 -8
  90. package/dist/usage/providers.js +58 -20
  91. package/dist/usage/providers.js.map +1 -1
  92. package/dist/usage/usage-api.d.ts +2 -0
  93. package/dist/usage/usage-api.js +180 -55
  94. package/dist/usage/usage-api.js.map +1 -1
  95. package/dist/user-systemd.d.ts +24 -0
  96. package/dist/user-systemd.js +75 -0
  97. package/dist/user-systemd.js.map +1 -0
  98. package/dist/web-api.d.ts +10 -1
  99. package/dist/web-api.js +134 -5
  100. package/dist/web-api.js.map +1 -1
  101. package/dist/web-backend-login.d.ts +130 -0
  102. package/dist/web-backend-login.js +225 -0
  103. package/dist/web-backend-login.js.map +1 -0
  104. package/dist/web-chat-history.d.ts +31 -0
  105. package/dist/web-chat-history.js +49 -1
  106. package/dist/web-chat-history.js.map +1 -1
  107. package/dist/web-commands.d.ts +5 -1
  108. package/dist/web-commands.js +1 -1
  109. package/dist/web-commands.js.map +1 -1
  110. package/dist/web-guest-access.d.ts +3 -2
  111. package/dist/web-guest-access.js +10 -6
  112. package/dist/web-guest-access.js.map +1 -1
  113. package/dist/windows-shortcuts.d.ts +78 -0
  114. package/dist/windows-shortcuts.js +203 -0
  115. package/dist/windows-shortcuts.js.map +1 -0
  116. package/launcher/agend-install.cjs +548 -0
  117. package/launcher/install-admission.cjs +4 -39
  118. package/launcher/postinstall.cjs +14 -12
  119. package/package.json +3 -2
  120. package/scripts/preinstall-guard.cjs +2 -5
  121. package/templates/windows-shortcuts.ps1 +181 -0
  122. package/launcher/old-updater-note.cjs +0 -48
@@ -0,0 +1,130 @@
1
+ import type { LoginChat, LoginStartOptions, WebLoginSink } from "./login-controller.js";
2
+ import type { AvailabilityState } from "./backend-availability.js";
3
+ /** How long the dialog's "go ahead" stays valid after the pre-check (chat's buttons expire as stale too). */
4
+ export declare const WEB_LOGIN_CONFIRM_TTL_MS: number;
5
+ /** How long an ended sign-in is still shown (its outcome), then it is gone. */
6
+ export declare const WEB_LOGIN_KEEP_ENDED_MS: number;
7
+ /** How often a running sign-in checks that the session which started it is still a local admin. */
8
+ export declare const WEB_LOGIN_WATCH_MS = 5000;
9
+ /**
10
+ * The provider hosts a sign-in link may point at to be offered as a link; any other URL is shown as text only. The
11
+ * CLI's own output is what is matched, and a page that turns whatever it printed into a link is a phishing aid.
12
+ */
13
+ export declare const LOGIN_LINK_HOSTS: Readonly<Record<string, readonly string[]>>;
14
+ /** An https URL on one of the backend's own hosts (or a subdomain of one). */
15
+ export declare function linkableLoginUrl(backend: string, url: string): boolean;
16
+ /** Whether the dashboard can run this sign-in (the same rule as chat's /login: a reviewed flow, profiles where chat signs them in). */
17
+ export declare function dashboardSignInSupported(backend: string, profile?: string | null): boolean;
18
+ /** One row of Settings → Agents' sign-in list: a backend's default login, or a credential profile one of the agents uses. */
19
+ export interface SignInTarget {
20
+ backend: string;
21
+ profile?: string;
22
+ state: AvailabilityState;
23
+ /** The dashboard can sign it in (else: `hostCommand`, run on the machine, or nothing to sign in). */
24
+ signIn: boolean;
25
+ hostCommand?: string;
26
+ /** Not installed: the command that installs it. */
27
+ install?: string;
28
+ /** Too old: the command that installs the current version over it. */
29
+ update?: string;
30
+ }
31
+ export interface WebLoginRequester {
32
+ /** The session's handle (web-session.ts): what the sign-in is bound to. */
33
+ handle: string;
34
+ /** Its device label, for the other sessions and the notice. */
35
+ label: string;
36
+ }
37
+ export interface WebBackendLoginDeps {
38
+ /** Is the session with this handle live, admin and local right now? */
39
+ isLocalAdmin(handle: string): boolean;
40
+ /** LoginController.start for a dashboard requester (FleetManager refuses a CLI that is not installed first). */
41
+ start(backend: string, chat: LoginChat, opts: LoginStartOptions): Promise<string | null>;
42
+ accessToken(sink: WebLoginSink): string | null;
43
+ isActiveFor(sink: WebLoginSink): boolean;
44
+ /** End the sign-in this sink started (pending or running) and nothing else; true when there was one. */
45
+ cancelFor(sink: WebLoginSink): Promise<boolean>;
46
+ /** `/login cancel`: whatever sign-in or install is running. */
47
+ cancel(): Promise<string>;
48
+ /** A sign-in started from the dashboard: said where a chat login would be seen (General, or the Log). */
49
+ notice(info: {
50
+ shown: string;
51
+ label: string;
52
+ handle: string;
53
+ }): void;
54
+ /** The current sign-in started, changed phase or went: the pages are told to read it again (no details in the event). */
55
+ changed?(): void;
56
+ now?(): number;
57
+ }
58
+ export interface WebLoginConfirm {
59
+ id: string;
60
+ backend: string;
61
+ profile?: string;
62
+ tokenPresent: boolean;
63
+ logoutFirst: string | null;
64
+ publicLink: boolean;
65
+ deviceAuth: boolean;
66
+ expiresAt: number;
67
+ }
68
+ /** What one session sees of the current sign-in. The parts after `mine` are present only for the session that started it. */
69
+ export interface WebLoginView {
70
+ id: string;
71
+ backend: string;
72
+ profile?: string;
73
+ phase: "running" | "ended";
74
+ ok: boolean | null;
75
+ startedOn: string;
76
+ startedAt: number;
77
+ endedAt: number | null;
78
+ mine: boolean;
79
+ lines?: string[];
80
+ hint?: {
81
+ url: string;
82
+ code: string | null;
83
+ linkable: boolean;
84
+ } | null;
85
+ terminal?: {
86
+ url: string;
87
+ ttlMinutes: number;
88
+ command: string;
89
+ loopback: boolean;
90
+ public: boolean;
91
+ } | null;
92
+ /** The browser terminal's one-time access code, while it is unredeemed. */
93
+ accessCode?: string | null;
94
+ }
95
+ export declare class WebBackendLogins {
96
+ private readonly deps;
97
+ private readonly pending;
98
+ private run;
99
+ /** Every admitted sign-in not yet ended — starting (its listener, tunnel or cloudflared still coming) or running. */
100
+ private readonly live;
101
+ private seq;
102
+ private watch;
103
+ constructor(deps: WebBackendLoginDeps);
104
+ private now;
105
+ /** The pre-check: the dialog's question, or the controller's answer (a refusal, "busy", "unsupported"…). */
106
+ check(who: WebLoginRequester, backendArg: string, profile?: string): Promise<{
107
+ confirm: WebLoginConfirm;
108
+ } | {
109
+ message: string;
110
+ }>;
111
+ /** The go-ahead for a pre-check this session was given; `tunnel` only where it offered a public link. */
112
+ begin(who: WebLoginRequester, confirmId: string, tunnel: boolean): Promise<{
113
+ login: WebLoginView;
114
+ } | {
115
+ message: string;
116
+ } | {
117
+ error: "confirm_expired" | "tunnel_not_offered";
118
+ }>;
119
+ /** The current sign-in as this session may see it, or null. */
120
+ view(viewerHandle: string): WebLoginView | null;
121
+ /** Any local admin may stop it (it only takes something away); a chat-started sign-in or install included. */
122
+ cancel(): Promise<string>;
123
+ dispose(): void;
124
+ private viewOf;
125
+ private changed;
126
+ private chatFor;
127
+ private sweep;
128
+ private startWatch;
129
+ private stopWatch;
130
+ }
@@ -0,0 +1,225 @@
1
+ /**
2
+ * #2233: signing a backend in from the web dashboard — the dashboard side of LoginController's `web` requester.
3
+ *
4
+ * - Who: a signed-in admin session on the local surface (the route checks it; the controller asks again through the
5
+ * sink, and the watchdog below keeps asking while the sign-in runs). Never a guest, a read session or the public link.
6
+ * - Two steps, as in chat: `check` runs the controller's pre-check and keeps its answer here, server-side, under a
7
+ * random id bound to the session that asked (chat keeps it in a nonce button); `begin` with that id starts the
8
+ * sign-in through every check again. The client never says whether a token was present.
9
+ * - What chat sends as a link, a DM or a device code goes to the one session that started it, read back with `view`:
10
+ * the browser terminal's URL, the provider's URL and code, and the access token while it is unredeemed. Other admin
11
+ * sessions see that a sign-in is running (backend, device, phase) and may cancel it; nothing more.
12
+ * - A sign-in whose session signs out, expires or is revoked is cancelled (WEB_LOGIN_WATCH_MS).
13
+ */
14
+ import { randomBytes } from "node:crypto";
15
+ import { LOGIN_BACKEND_ALIASES, LOGIN_FLOWS } from "./login-flows.js";
16
+ import { CHAT_PROFILE_LOGIN_BACKENDS } from "./backend/credential-profile.js";
17
+ /** How long the dialog's "go ahead" stays valid after the pre-check (chat's buttons expire as stale too). */
18
+ export const WEB_LOGIN_CONFIRM_TTL_MS = 5 * 60_000;
19
+ /** How long an ended sign-in is still shown (its outcome), then it is gone. */
20
+ export const WEB_LOGIN_KEEP_ENDED_MS = 10 * 60_000;
21
+ /** How often a running sign-in checks that the session which started it is still a local admin. */
22
+ export const WEB_LOGIN_WATCH_MS = 5_000;
23
+ const MAX_LINES = 20;
24
+ const MAX_LINE_CHARS = 2000;
25
+ /**
26
+ * The provider hosts a sign-in link may point at to be offered as a link; any other URL is shown as text only. The
27
+ * CLI's own output is what is matched, and a page that turns whatever it printed into a link is a phishing aid.
28
+ */
29
+ export const LOGIN_LINK_HOSTS = {
30
+ "codex": ["openai.com"],
31
+ "grok": ["x.ai"],
32
+ "kiro-cli": ["amazonaws.com", "awsapps.com", "aws.amazon.com", "kiro.dev"],
33
+ "claude-code": ["anthropic.com", "claude.ai", "claude.com"],
34
+ };
35
+ /** An https URL on one of the backend's own hosts (or a subdomain of one). */
36
+ export function linkableLoginUrl(backend, url) {
37
+ let parsed;
38
+ try {
39
+ parsed = new URL(url);
40
+ }
41
+ catch {
42
+ return false;
43
+ }
44
+ if (parsed.protocol !== "https:" || parsed.username || parsed.password)
45
+ return false;
46
+ const host = parsed.hostname.toLowerCase();
47
+ return (LOGIN_LINK_HOSTS[backend] ?? []).some(domain => host === domain || host.endsWith(`.${domain}`));
48
+ }
49
+ /** Whether the dashboard can run this sign-in (the same rule as chat's /login: a reviewed flow, profiles where chat signs them in). */
50
+ export function dashboardSignInSupported(backend, profile) {
51
+ const flow = LOGIN_FLOWS[backend];
52
+ if (!flow || flow.remoteLogin === "unsupported" || flow.noShellEscape !== true)
53
+ return false;
54
+ return !profile || CHAT_PROFILE_LOGIN_BACKENDS.has(backend);
55
+ }
56
+ export class WebBackendLogins {
57
+ deps;
58
+ pending = new Map();
59
+ run = null;
60
+ /** Every admitted sign-in not yet ended — starting (its listener, tunnel or cloudflared still coming) or running. */
61
+ live = new Set();
62
+ seq = 0;
63
+ watch = null;
64
+ constructor(deps) {
65
+ this.deps = deps;
66
+ }
67
+ now() { return (this.deps.now ?? Date.now)(); }
68
+ /** The pre-check: the dialog's question, or the controller's answer (a refusal, "busy", "unsupported"…). */
69
+ async check(who, backendArg, profile) {
70
+ const backend = LOGIN_BACKEND_ALIASES[backendArg.toLowerCase()] ?? backendArg.toLowerCase();
71
+ const asked = { info: null };
72
+ const sink = {
73
+ isAdmin: () => this.deps.isLocalAdmin(who.handle),
74
+ confirm: info => { asked.info = info; },
75
+ hint: () => { }, terminal: () => { }, ended: () => { },
76
+ };
77
+ const lines = [];
78
+ const message = await this.deps.start(backend, this.chatFor(who, sink, lines), profile !== undefined ? { profile } : {});
79
+ if (!asked.info)
80
+ return { message: message ?? lines.join("\n") };
81
+ this.sweep();
82
+ for (const [id, p] of this.pending)
83
+ if (p.handle === who.handle)
84
+ this.pending.delete(id); // one question per session
85
+ const id = randomBytes(16).toString("hex");
86
+ const entry = { id, backend, ...(profile !== undefined ? { profile } : {}), handle: who.handle, ...asked.info, expiresAt: this.now() + WEB_LOGIN_CONFIRM_TTL_MS };
87
+ this.pending.set(id, entry);
88
+ const { handle: _handle, ...confirm } = entry;
89
+ return { confirm };
90
+ }
91
+ /** The go-ahead for a pre-check this session was given; `tunnel` only where it offered a public link. */
92
+ async begin(who, confirmId, tunnel) {
93
+ this.sweep();
94
+ const asked = this.pending.get(confirmId);
95
+ if (!asked || asked.handle !== who.handle)
96
+ return { error: "confirm_expired" };
97
+ if (tunnel && !asked.publicLink)
98
+ return { error: "tunnel_not_offered" };
99
+ this.pending.delete(confirmId);
100
+ const run = {
101
+ id: randomBytes(16).toString("hex"), seq: ++this.seq, backend: asked.backend, ...(asked.profile !== undefined ? { profile: asked.profile } : {}),
102
+ handle: who.handle, label: who.label, startedAt: this.now(), phase: "running", ok: null, endedAt: null,
103
+ hint: null, terminal: null, lines: [], sink: null,
104
+ };
105
+ run.sink = {
106
+ isAdmin: () => this.deps.isLocalAdmin(who.handle),
107
+ confirm: () => { },
108
+ hint: (url, code) => { run.hint = { url, code, linkable: linkableLoginUrl(run.backend, url) }; },
109
+ terminal: info => { run.terminal = { ...info }; },
110
+ ended: result => {
111
+ run.phase = "ended";
112
+ run.ok = result.ok;
113
+ run.endedAt = this.now();
114
+ this.live.delete(run);
115
+ if (!this.live.size)
116
+ this.stopWatch();
117
+ if (this.run === run)
118
+ this.changed();
119
+ },
120
+ };
121
+ // Watched from admission, not from publication: a session revoked while its listener, tunnel or cloudflared is
122
+ // still coming up ends its own attempt (cancelFor) — never one that replaced it.
123
+ this.live.add(run);
124
+ this.startWatch();
125
+ const message = await this.deps.start(asked.backend, this.chatFor(who, run.sink, run.lines), {
126
+ skipAuthCheck: true, tokenPresent: asked.tokenPresent, ...(tunnel ? { tunnel: true } : {}),
127
+ ...(asked.profile !== undefined ? { profile: asked.profile } : {}),
128
+ });
129
+ const running = run.phase === "running" && this.deps.isActiveFor(run.sink);
130
+ if (!running && run.phase !== "ended") { // refused: nothing ran
131
+ this.live.delete(run);
132
+ if (!this.live.size)
133
+ this.stopWatch();
134
+ return { message: message ?? "" };
135
+ }
136
+ if (message && !running)
137
+ pushLine(run.lines, message); // ended while starting: why
138
+ // A start that took longer than a later one (its listener held, then cancelled) never replaces what that one shows.
139
+ if (this.run && this.run.seq > run.seq)
140
+ return running ? { login: this.viewOf(run, who.handle) } : { message: message ?? run.lines.join("\n") };
141
+ this.run = run;
142
+ this.changed();
143
+ if (running) {
144
+ try {
145
+ this.deps.notice({ shown: asked.profile ? `${asked.backend} (${asked.profile})` : asked.backend, label: who.label, handle: who.handle });
146
+ }
147
+ catch { /* a notice never stops a sign-in */ }
148
+ }
149
+ return { login: this.viewOf(run, who.handle) };
150
+ }
151
+ /** The current sign-in as this session may see it, or null. */
152
+ view(viewerHandle) {
153
+ const run = this.run;
154
+ if (!run)
155
+ return null;
156
+ if (run.phase === "ended" && run.endedAt !== null && this.now() - run.endedAt > WEB_LOGIN_KEEP_ENDED_MS) {
157
+ this.run = null;
158
+ return null;
159
+ }
160
+ return this.viewOf(run, viewerHandle);
161
+ }
162
+ /** Any local admin may stop it (it only takes something away); a chat-started sign-in or install included. */
163
+ cancel() { return this.deps.cancel(); }
164
+ dispose() { this.stopWatch(); this.pending.clear(); this.live.clear(); }
165
+ viewOf(run, viewerHandle) {
166
+ const mine = run.handle === viewerHandle && this.deps.isLocalAdmin(viewerHandle);
167
+ const base = {
168
+ id: run.id, backend: run.backend, ...(run.profile !== undefined ? { profile: run.profile } : {}), phase: run.phase, ok: run.ok,
169
+ startedOn: run.label, startedAt: run.startedAt, endedAt: run.endedAt, mine,
170
+ };
171
+ if (!mine)
172
+ return base;
173
+ const running = run.phase === "running" && this.deps.isActiveFor(run.sink);
174
+ return {
175
+ ...base, lines: [...run.lines], hint: running ? run.hint : null, terminal: running ? run.terminal : null,
176
+ accessCode: running && run.terminal ? this.deps.accessToken(run.sink) : null,
177
+ };
178
+ }
179
+ changed() { try {
180
+ this.deps.changed?.();
181
+ }
182
+ catch { /* the pages read it on their own next time */ } }
183
+ chatFor(who, sink, lines) {
184
+ // The status lines chat would post (done, recovery, a download notice) — this sign-in's own, shown to its session.
185
+ const adapter = {
186
+ type: "web", id: "web",
187
+ sendText: async (_chatId, text) => { pushLine(lines, text); return { chatId: "web", messageId: randomBytes(6).toString("hex") }; },
188
+ };
189
+ return { adapter, adapterId: "web", chatId: "web", userId: `web:${who.handle}`, web: sink };
190
+ }
191
+ sweep() {
192
+ const now = this.now();
193
+ for (const [id, p] of this.pending)
194
+ if (p.expiresAt <= now)
195
+ this.pending.delete(id);
196
+ }
197
+ startWatch() {
198
+ if (this.watch)
199
+ return;
200
+ this.watch = setInterval(() => {
201
+ for (const run of [...this.live]) {
202
+ if (this.deps.isLocalAdmin(run.handle))
203
+ continue;
204
+ // The session that holds the code is gone (signed out, expired, revoked): its own sign-in goes with it.
205
+ this.live.delete(run);
206
+ void this.deps.cancelFor(run.sink).catch(() => false);
207
+ }
208
+ if (!this.live.size)
209
+ this.stopWatch();
210
+ }, WEB_LOGIN_WATCH_MS);
211
+ this.watch.unref?.();
212
+ }
213
+ stopWatch() {
214
+ if (this.watch) {
215
+ clearInterval(this.watch);
216
+ this.watch = null;
217
+ }
218
+ }
219
+ }
220
+ function pushLine(lines, text) {
221
+ lines.push(text.length > MAX_LINE_CHARS ? `${text.slice(0, MAX_LINE_CHARS - 1)}…` : text);
222
+ if (lines.length > MAX_LINES)
223
+ lines.splice(0, lines.length - MAX_LINES);
224
+ }
225
+ //# sourceMappingURL=web-backend-login.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"web-backend-login.js","sourceRoot":"","sources":["../src/web-backend-login.ts"],"names":[],"mappings":"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"}
@@ -95,7 +95,33 @@ export interface WebChatMessage {
95
95
  * across a restart is still sent it.
96
96
  */
97
97
  seenSeq?: number;
98
+ /**
99
+ * #2272: the message a person's message replies to — its row (`boot`, `id`) and what the bubble quotes: who wrote it
100
+ * and its first words, taken by the server from that row when the reply was sent (never from the page). `media`: a
101
+ * row with files and no text. A person's messages only.
102
+ */
103
+ replyTo?: WebChatReplyRef;
98
104
  }
105
+ /** #2272: a reply's reference to an earlier message of the same chat (see WebChatMessage.replyTo). */
106
+ export interface WebChatReplyRef {
107
+ boot: string;
108
+ id: number;
109
+ sender: string;
110
+ text: string;
111
+ media?: "photo" | "document";
112
+ }
113
+ /** #2272: how much of the quoted message a reply keeps for its bubble (the agent's `reply_to` is longer). */
114
+ export declare const WEB_CHAT_REPLY_SNIPPET_MAX = 160;
115
+ /** #2272: the agent's `(reply_to: "…")` — at most this many characters of the quoted message. */
116
+ export declare const WEB_CHAT_REPLY_TEXT_MAX = 500;
117
+ /** #2272: what a reply quotes from a row: its sender, its first words on one line (a click's label), its files' kind. */
118
+ export declare function webChatReplyRef(row: WebChatMessage): WebChatReplyRef;
119
+ /**
120
+ * #2272: the quoted message as the agent gets it — `(reply_to: "…")`, like a Discord or Telegram reply: one line (a
121
+ * newline in it could start a line that reads as another header), its double quotes made typographic so the quote
122
+ * cannot end early, at most WEB_CHAT_REPLY_TEXT_MAX characters; a message of files only names them.
123
+ */
124
+ export declare function webChatReplyText(row: WebChatMessage): string;
99
125
  export declare function webChatFrom(adapterId: unknown, userId: unknown): string | undefined;
100
126
  export interface WebChatClick {
101
127
  label: string;
@@ -143,6 +169,8 @@ export interface StoredWebChatMessage {
143
169
  from?: string;
144
170
  /** #1920: when, in its boot's id sequence, it became the channel's (see WebChatMessage). */
145
171
  seenSeq?: number;
172
+ /** #2272: what a person's reply quotes (see WebChatMessage). */
173
+ replyTo?: WebChatReplyRef;
146
174
  }
147
175
  /** #1565: what the history needs of the file ledger (web-upload.ts). */
148
176
  export interface WebChatFiles {
@@ -240,6 +268,7 @@ export declare class WebChatHistory {
240
268
  links?: unknown;
241
269
  channel?: unknown;
242
270
  from?: unknown;
271
+ replyTo?: unknown;
243
272
  }): WebChatMessage;
244
273
  /** Host-only producer seam. Generic records cannot promote sender/role strings into a Try action. */
245
274
  recordEffectTrial(instance: string, offer: unknown, ts: string): WebChatMessage | null;
@@ -263,6 +292,8 @@ export declare class WebChatHistory {
263
292
  id: number;
264
293
  } | null): WebChatMessage[];
265
294
  /** #1920: a kept message by the `message_id` the agent was given (a web message, a web click). */
295
+ /** #2272: one kept message of an instance's chat by its row (`boot`, `id`), or undefined (never sent, or no longer kept). */
296
+ find(instance: string, boot: string, id: number): WebChatMessage | undefined;
266
297
  findByMessageId(instance: string, messageId: string): WebChatMessage | undefined;
267
298
  /** #1920: a kept reply by its buttons' set id. */
268
299
  findByButtons(instance: string, buttonsId: string): WebChatMessage | undefined;
@@ -67,6 +67,42 @@ function webChatButtons(raw) {
67
67
  ...(state === "chosen" && typeof b.by === "string" ? { by: b.by.slice(0, 64) } : {}),
68
68
  };
69
69
  }
70
+ /** #2272: how much of the quoted message a reply keeps for its bubble (the agent's `reply_to` is longer). */
71
+ export const WEB_CHAT_REPLY_SNIPPET_MAX = 160;
72
+ /** #2272: the agent's `(reply_to: "…")` — at most this many characters of the quoted message. */
73
+ export const WEB_CHAT_REPLY_TEXT_MAX = 500;
74
+ const BOOT_RE = /^[0-9a-f]{1,32}$/;
75
+ /** One line: runs of whitespace (newlines too) become one space. */
76
+ const oneLine = (s) => s.replace(/\s+/g, " ").trim();
77
+ const cut = (s, max) => (s.length > max ? `${s.slice(0, max - 1).trimEnd()}…` : s);
78
+ /** #2272: what a reply quotes from a row: its sender, its first words on one line (a click's label), its files' kind. */
79
+ export function webChatReplyRef(row) {
80
+ const words = oneLine(row.click?.label ?? row.text);
81
+ const media = !words && row.attachments?.length ? (row.attachments.some(a => a.kind === "photo") ? "photo" : "document") : undefined;
82
+ return { boot: row.boot, id: row.id, sender: row.sender.slice(0, 256), text: cut(words, WEB_CHAT_REPLY_SNIPPET_MAX), ...(media ? { media } : {}) };
83
+ }
84
+ /**
85
+ * #2272: the quoted message as the agent gets it — `(reply_to: "…")`, like a Discord or Telegram reply: one line (a
86
+ * newline in it could start a line that reads as another header), its double quotes made typographic so the quote
87
+ * cannot end early, at most WEB_CHAT_REPLY_TEXT_MAX characters; a message of files only names them.
88
+ */
89
+ export function webChatReplyText(row) {
90
+ const words = oneLine(row.click?.label ?? row.text);
91
+ const files = (row.attachments ?? []).map(a => `[${a.kind === "photo" ? "photo" : "file"}: ${oneLine(a.name)}]`).join(" ");
92
+ return cut((words || files).replace(/"/g, "\u201d"), WEB_CHAT_REPLY_TEXT_MAX);
93
+ }
94
+ /** A stored or sent reply reference, checked field by field (one that fails is dropped, never repaired). */
95
+ function webChatReplyRefOf(raw) {
96
+ if (!raw || typeof raw !== "object" || Array.isArray(raw))
97
+ return undefined;
98
+ const r = raw;
99
+ if (typeof r.boot !== "string" || !BOOT_RE.test(r.boot) || typeof r.id !== "number" || !Number.isSafeInteger(r.id) || r.id < 1)
100
+ return undefined;
101
+ if (typeof r.sender !== "string" || typeof r.text !== "string")
102
+ return undefined;
103
+ const media = r.media === "photo" || r.media === "document" ? r.media : undefined;
104
+ return { boot: r.boot, id: r.id, sender: r.sender.slice(0, 256), text: cut(oneLine(r.text), WEB_CHAT_REPLY_SNIPPET_MAX), ...(media ? { media } : {}) };
105
+ }
70
106
  /** #1920: an account as a row names it — the connection id and the user id, one line. */
71
107
  const FROM = /^[^\s:]{1,64}:[^\s:]{1,128}$/;
72
108
  export function webChatFrom(adapterId, userId) {
@@ -129,7 +165,8 @@ export class WebChatHistory {
129
165
  /** #1565: a message as kept on disk: no buttons, no delivery, no message id; a file with the path it is served from. */
130
166
  stored(m) {
131
167
  const row = { boot: m.boot, id: m.id, instance: m.instance, role: m.role, sender: m.sender, text: m.text, ts: m.ts, ...(m.click ? { click: { label: m.click.label } } : {}), ...(m.links ? { links: m.links } : {}),
132
- ...(m.channel ? { channel: true } : {}), ...(m.from ? { from: m.from } : {}), ...(m.channel && m.seenSeq !== undefined ? { seenSeq: m.seenSeq } : {}) };
168
+ ...(m.channel ? { channel: true } : {}), ...(m.from ? { from: m.from } : {}), ...(m.channel && m.seenSeq !== undefined ? { seenSeq: m.seenSeq } : {}),
169
+ ...(m.replyTo ? { replyTo: m.replyTo } : {}) };
133
170
  if (m.attachments?.length) {
134
171
  row.attachments = m.attachments.map((a) => {
135
172
  const base = { kind: a.kind, name: a.name, size: a.size, mime: a.mime };
@@ -279,6 +316,10 @@ export class WebChatHistory {
279
316
  entry.channel = true;
280
317
  if (entry.role === "user" && typeof msg.from === "string" && FROM.test(msg.from))
281
318
  entry.from = msg.from;
319
+ // #2272: only a person's message replies to another.
320
+ const replyTo = entry.role === "user" ? webChatReplyRefOf(msg.replyTo) : undefined;
321
+ if (replyTo)
322
+ entry.replyTo = replyTo;
282
323
  let slot = this.byInstance.get(entry.instance);
283
324
  if (!slot) {
284
325
  slot = { messages: [], chars: 0 };
@@ -346,6 +387,10 @@ export class WebChatHistory {
346
387
  return this.collect((m) => m.boot === cursor.boot && m.seenSeq !== undefined && m.seenSeq > cursor.id);
347
388
  }
348
389
  /** #1920: a kept message by the `message_id` the agent was given (a web message, a web click). */
390
+ /** #2272: one kept message of an instance's chat by its row (`boot`, `id`), or undefined (never sent, or no longer kept). */
391
+ find(instance, boot, id) {
392
+ return this.byInstance.get(instance)?.messages.find(m => m.boot === boot && m.id === id);
393
+ }
349
394
  findByMessageId(instance, messageId) {
350
395
  const messages = this.byInstance.get(instance)?.messages ?? [];
351
396
  for (let i = messages.length - 1; i >= 0; i--)
@@ -538,6 +583,9 @@ function restoredRow(raw, instance, thisBoot) {
538
583
  message.from = r.from;
539
584
  if (message.channel && typeof r.seenSeq === "number" && Number.isSafeInteger(r.seenSeq) && r.seenSeq > r.id)
540
585
  message.seenSeq = r.seenSeq;
586
+ const replyTo = role === "user" ? webChatReplyRefOf(r.replyTo) : undefined;
587
+ if (replyTo)
588
+ message.replyTo = replyTo;
541
589
  const files = !Array.isArray(r.attachments) ? [] : r.attachments.slice(0, 20).flatMap((a) => {
542
590
  if (!a || typeof a !== "object" || Array.isArray(a))
543
591
  return [];