@songsid/agend 2.1.5 → 2.1.6-beta.2

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 (102) hide show
  1. package/dist/apply-job.d.ts +114 -0
  2. package/dist/apply-job.js +214 -0
  3. package/dist/apply-job.js.map +1 -0
  4. package/dist/backend/codex.d.ts +16 -0
  5. package/dist/backend/codex.js +50 -0
  6. package/dist/backend/codex.js.map +1 -1
  7. package/dist/backend/credential-profile.d.ts +114 -0
  8. package/dist/backend/credential-profile.js +242 -0
  9. package/dist/backend/credential-profile.js.map +1 -0
  10. package/dist/backend/kiro-auth-store.d.ts +25 -0
  11. package/dist/backend/kiro-auth-store.js +61 -0
  12. package/dist/backend/kiro-auth-store.js.map +1 -0
  13. package/dist/backend/kiro.d.ts +8 -0
  14. package/dist/backend/kiro.js +31 -2
  15. package/dist/backend/kiro.js.map +1 -1
  16. package/dist/backend/types.d.ts +13 -0
  17. package/dist/backend/types.js.map +1 -1
  18. package/dist/cli.js +113 -0
  19. package/dist/cli.js.map +1 -1
  20. package/dist/config-validator.js +21 -0
  21. package/dist/config-validator.js.map +1 -1
  22. package/dist/daemon.d.ts +25 -0
  23. package/dist/daemon.js +157 -16
  24. package/dist/daemon.js.map +1 -1
  25. package/dist/fleet-level-config.d.ts +42 -0
  26. package/dist/fleet-level-config.js +78 -0
  27. package/dist/fleet-level-config.js.map +1 -0
  28. package/dist/fleet-lock.d.ts +21 -0
  29. package/dist/fleet-lock.js +42 -8
  30. package/dist/fleet-lock.js.map +1 -1
  31. package/dist/fleet-manager.d.ts +130 -1
  32. package/dist/fleet-manager.js +611 -83
  33. package/dist/fleet-manager.js.map +1 -1
  34. package/dist/general-knowledge/skills/credential-profiles/SKILL.md +121 -0
  35. package/dist/instance-config-impact.d.ts +55 -0
  36. package/dist/instance-config-impact.js +152 -0
  37. package/dist/instance-config-impact.js.map +1 -0
  38. package/dist/locale.js +2 -0
  39. package/dist/locale.js.map +1 -1
  40. package/dist/outbound-handlers.d.ts +5 -1
  41. package/dist/outbound-handlers.js +179 -1
  42. package/dist/outbound-handlers.js.map +1 -1
  43. package/dist/outbound-schemas.d.ts +6 -5
  44. package/dist/outbound-schemas.js +1 -0
  45. package/dist/outbound-schemas.js.map +1 -1
  46. package/dist/provider-probe.d.ts +45 -0
  47. package/dist/provider-probe.js +111 -0
  48. package/dist/provider-probe.js.map +1 -0
  49. package/dist/quickstart-api.d.ts +161 -0
  50. package/dist/quickstart-api.js +340 -0
  51. package/dist/quickstart-api.js.map +1 -0
  52. package/dist/quickstart.js +23 -50
  53. package/dist/quickstart.js.map +1 -1
  54. package/dist/self-restart-limit.d.ts +21 -0
  55. package/dist/self-restart-limit.js +129 -0
  56. package/dist/self-restart-limit.js.map +1 -0
  57. package/dist/settings-api.d.ts +15 -0
  58. package/dist/settings-api.js +126 -1
  59. package/dist/settings-api.js.map +1 -1
  60. package/dist/setup-auth.d.ts +113 -0
  61. package/dist/setup-auth.js +181 -0
  62. package/dist/setup-auth.js.map +1 -0
  63. package/dist/setup-form.d.ts +18 -0
  64. package/dist/setup-form.js +315 -0
  65. package/dist/setup-form.js.map +1 -0
  66. package/dist/setup-host.d.ts +162 -0
  67. package/dist/setup-host.js +496 -0
  68. package/dist/setup-host.js.map +1 -0
  69. package/dist/setup-marker.d.ts +8 -0
  70. package/dist/setup-marker.js +39 -0
  71. package/dist/setup-marker.js.map +1 -0
  72. package/dist/setup-tunnel-consent.d.ts +53 -0
  73. package/dist/setup-tunnel-consent.js +82 -0
  74. package/dist/setup-tunnel-consent.js.map +1 -0
  75. package/dist/tips.js +1 -1
  76. package/dist/tips.js.map +1 -1
  77. package/dist/transcript-sources.d.ts +12 -1
  78. package/dist/transcript-sources.js +19 -3
  79. package/dist/transcript-sources.js.map +1 -1
  80. package/dist/tunnel/cloudflared.d.ts +71 -0
  81. package/dist/tunnel/cloudflared.js +447 -0
  82. package/dist/tunnel/cloudflared.js.map +1 -0
  83. package/dist/tunnel/lease.d.ts +75 -0
  84. package/dist/tunnel/lease.js +209 -0
  85. package/dist/tunnel/lease.js.map +1 -0
  86. package/dist/tunnel/manager.d.ts +56 -0
  87. package/dist/tunnel/manager.js +167 -0
  88. package/dist/tunnel/manager.js.map +1 -0
  89. package/dist/tunnel/types.d.ts +119 -0
  90. package/dist/tunnel/types.js +33 -0
  91. package/dist/tunnel/types.js.map +1 -0
  92. package/dist/ui/dashboard.html +4 -3
  93. package/dist/ui/settings.html +640 -153
  94. package/dist/usage/providers.d.ts +16 -13
  95. package/dist/usage/providers.js +79 -53
  96. package/dist/usage/providers.js.map +1 -1
  97. package/dist/web-api.js +6 -4
  98. package/dist/web-api.js.map +1 -1
  99. package/dist/web-auth.d.ts +75 -0
  100. package/dist/web-auth.js +208 -2
  101. package/dist/web-auth.js.map +1 -1
  102. package/package.json +1 -1
@@ -0,0 +1,340 @@
1
+ import { existsSync, readFileSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { writeSecretFile } from "./secret-file.js";
4
+ import { KNOWN_BACKENDS, validateFleetConfig } from "./config-validator.js";
5
+ import { awaitTelegramGroupStart, detectInstalledBackends, listDiscordGuilds, TelegramPollConflictError, verifyDiscordToken, verifyTelegramToken, } from "./provider-probe.js";
6
+ /** One slice of Telegram long polling, so the browser gets an answer. */
7
+ export const TELEGRAM_WAIT_SLICE_MS = 25_000;
8
+ export const WIZARD_BACKENDS = [
9
+ { name: "claude-code", binary: "claude" },
10
+ { name: "codex", binary: "codex" },
11
+ { name: "opencode", binary: "opencode" },
12
+ { name: "kiro-cli", binary: "kiro-cli" },
13
+ { name: "antigravity", binary: "agy" },
14
+ { name: "grok", binary: "grok" },
15
+ ];
16
+ /**
17
+ * A channel id that is free, or the id of the connection being replaced.
18
+ *
19
+ * The platform name is the obvious id and the first bot gets it. A second bot on
20
+ * the same platform cannot have it — `duplicate channel id` — so it is
21
+ * qualified by the variable that holds its token. Without this the wizard can
22
+ * never add a second Telegram bot at all.
23
+ */
24
+ export function nextChannelId(platform, tokenEnv, existing) {
25
+ const owner = existing.find(channel => channel.token_env === tokenEnv);
26
+ if (owner)
27
+ return owner.id;
28
+ const taken = new Set(existing.map(channel => channel.id));
29
+ if (!taken.has(platform))
30
+ return platform;
31
+ const qualified = `${platform}-${tokenEnv.toLowerCase()}`;
32
+ if (!taken.has(qualified))
33
+ return qualified;
34
+ for (let n = 2;; n++) {
35
+ const candidate = `${qualified}-${n}`;
36
+ if (!taken.has(candidate))
37
+ return candidate;
38
+ }
39
+ }
40
+ export function planQuickstart(input, env) {
41
+ const warnings = [];
42
+ const channel = {
43
+ type: input.platform,
44
+ bot_token_env: input.token_env,
45
+ mode: "topic",
46
+ access: { mode: "locked", allowed_users: input.admin_user_id ? [input.admin_user_id] : [] },
47
+ };
48
+ // Only the id that platform has — Discord has a guild, Telegram a group.
49
+ if (input.platform === "discord") {
50
+ if (input.guild_id)
51
+ channel.group_id = input.guild_id;
52
+ if (input.general_channel_id)
53
+ channel.general_channel_id = input.general_channel_id;
54
+ }
55
+ else if (input.group_id) {
56
+ channel.group_id = input.group_id;
57
+ }
58
+ if (!input.admin_user_id) {
59
+ warnings.push("No admin user id: access stays locked with an empty allow list, so nobody can drive the bot until you add one.");
60
+ }
61
+ const clash = env.channels.find(existing => existing.token_env === input.token_env);
62
+ if (clash) {
63
+ warnings.push(`${input.token_env} is already used by the "${clash.id}" connection — its token will be overwritten.`);
64
+ // Re-running the wizard rewrites that connection's access block, so anyone
65
+ // else on its allow list stops being able to drive the bot. That is a
66
+ // lockout, and it must not happen without the user reading it first.
67
+ const previous = clash.allowed_users ?? [];
68
+ const dropped = previous.filter(user => user !== input.admin_user_id);
69
+ if (dropped.length) {
70
+ warnings.push(`Its allow list is replaced: ${dropped.join(", ")} will no longer be able to use the bot.`);
71
+ }
72
+ }
73
+ if (!env.backends.includes(input.backend)) {
74
+ warnings.push(`${input.backend} was not found on this host; the agent will fail to start until it is installed.`);
75
+ }
76
+ return {
77
+ channel,
78
+ instance: { name: input.instance_name, working_directory: input.working_directory, backend: input.backend },
79
+ env_keys: [input.token_env],
80
+ warnings,
81
+ };
82
+ }
83
+ /** Upsert one `KEY=value` line, preserving everything else in the file. */
84
+ export function upsertEnvLine(existing, key, value) {
85
+ const lines = existing.split("\n").filter(line => line !== "");
86
+ const index = lines.findIndex(line => line.startsWith(`${key}=`));
87
+ if (index >= 0)
88
+ lines[index] = `${key}=${value}`;
89
+ else
90
+ lines.push(`${key}=${value}`);
91
+ return lines.join("\n") + "\n";
92
+ }
93
+ export function writeQuickstartSecret(dataDir, key, value) {
94
+ const path = join(dataDir, ".env");
95
+ const existing = existsSync(path) ? readFileSync(path, "utf-8") : "";
96
+ return writeSecretFile(path, upsertEnvLine(existing, key, value));
97
+ }
98
+ /**
99
+ * Run one probe.
100
+ *
101
+ * `isTokenInUse` exists for the Telegram wait: `getUpdates` has exactly one
102
+ * consumer, so polling a token the running fleet already polls makes the two
103
+ * take turns and both miss messages. Refusing is the only honest answer — the
104
+ * alternative silently breaks the live bot while the wizard waits.
105
+ */
106
+ export async function runProviderProbe(request, opts = {}) {
107
+ if (request.action === "verify") {
108
+ const identity = request.platform === "discord"
109
+ ? await verifyDiscordToken(request.token)
110
+ : await verifyTelegramToken(request.token);
111
+ return { ok: true, identity };
112
+ }
113
+ if (request.action === "guilds") {
114
+ return { ok: true, guilds: await listDiscordGuilds(request.token) };
115
+ }
116
+ if (opts.isTokenInUse?.(request.token)) {
117
+ return {
118
+ ok: false,
119
+ conflict: true,
120
+ error: "This bot token is already being polled by the running fleet. Enter the group id by hand, or stop AgEnD first.",
121
+ };
122
+ }
123
+ try {
124
+ const slice = await awaitTelegramGroupStart(request.token, {
125
+ deadlineMs: opts.deadlineMs ?? TELEGRAM_WAIT_SLICE_MS,
126
+ offset: request.offset ?? 0,
127
+ });
128
+ return { ok: true, found: slice.found, offset: slice.offset };
129
+ }
130
+ catch (err) {
131
+ if (err instanceof TelegramPollConflictError) {
132
+ return { ok: false, conflict: true, error: "Another process is already reading this bot's updates. Stop it, or enter the group id by hand." };
133
+ }
134
+ return { ok: false, error: err.message };
135
+ }
136
+ }
137
+ export function detectWizardBackends() {
138
+ return detectInstalledBackends(WIZARD_BACKENDS);
139
+ }
140
+ function json(res, status, data) {
141
+ res.setHeader("Content-Type", "application/json");
142
+ res.writeHead(status);
143
+ res.end(JSON.stringify(data));
144
+ }
145
+ function readBody(req, maxBytes) {
146
+ return new Promise((resolve, reject) => {
147
+ const chunks = [];
148
+ let size = 0;
149
+ req.on("data", (chunk) => {
150
+ size += chunk.length;
151
+ if (size > maxBytes) {
152
+ reject(new Error("body too large"));
153
+ req.destroy();
154
+ return;
155
+ }
156
+ chunks.push(chunk);
157
+ });
158
+ req.on("end", () => resolve(Buffer.concat(chunks)));
159
+ req.on("error", reject);
160
+ });
161
+ }
162
+ /** The channels as the wizard sees them, from either config shape. */
163
+ export function wizardChannels(cfg) {
164
+ const channels = (cfg?.channels ?? (cfg?.channel ? [cfg.channel] : []));
165
+ return channels.map((channel, index) => ({
166
+ id: String(channel.id ?? channel.type ?? `channel-${index}`),
167
+ type: String(channel.type ?? ""),
168
+ token_env: channel.bot_token_env ? String(channel.bot_token_env) : null,
169
+ group_id: channel.group_id != null ? String(channel.group_id) : null,
170
+ allowed_users: (channel.access?.allowed_users ?? []).map(String),
171
+ }));
172
+ }
173
+ /** Reject anything that would land in fleet.yaml or a shell env file unchecked. */
174
+ export function validateWizardInput(input) {
175
+ if (input.platform !== "telegram" && input.platform !== "discord")
176
+ return "platform must be telegram or discord";
177
+ if (!input.token_env || !/^[A-Z][A-Z0-9_]{2,63}$/.test(input.token_env))
178
+ return "token_env must be an UPPER_SNAKE env var name";
179
+ if (!input.backend || !KNOWN_BACKENDS.includes(input.backend))
180
+ return "backend must be a known backend";
181
+ if (!input.working_directory || !input.working_directory.startsWith("/"))
182
+ return "working_directory must be an absolute path";
183
+ if (!input.instance_name || !/^[A-Za-z0-9._-]{1,128}$/.test(input.instance_name))
184
+ return "instance_name must be [A-Za-z0-9._-]";
185
+ for (const [field, value] of Object.entries({
186
+ group_id: input.group_id, guild_id: input.guild_id,
187
+ general_channel_id: input.general_channel_id, admin_user_id: input.admin_user_id,
188
+ })) {
189
+ if (value !== undefined && value !== "" && !/^-?\d{1,20}$/.test(String(value)))
190
+ return `${field} must be numeric`;
191
+ }
192
+ return null;
193
+ }
194
+ /** Handle one wizard route. Returns false when the path is not one of ours. */
195
+ export function handleQuickstartRequest(req, res, url, ctx) {
196
+ const path = url.pathname;
197
+ const method = req.method ?? "GET";
198
+ const cfg = ctx.fleetConfig;
199
+ if (!path.startsWith("/api/settings/quickstart/"))
200
+ return false;
201
+ if (method === "GET" && path === "/api/settings/quickstart/environment") {
202
+ json(res, 200, {
203
+ backends: detectWizardBackends(),
204
+ has_fleet: !!cfg && Object.keys(cfg.instances ?? {}).length > 0,
205
+ channels: wizardChannels(cfg),
206
+ });
207
+ return true;
208
+ }
209
+ if (method === "POST" && path === "/api/settings/quickstart/probe") {
210
+ readBody(req, 16 * 1024).then(async (buf) => {
211
+ let body;
212
+ try {
213
+ body = JSON.parse(buf.toString("utf-8") || "{}");
214
+ }
215
+ catch {
216
+ return json(res, 400, { error: "invalid JSON" });
217
+ }
218
+ const token = typeof body.token === "string" ? body.token : "";
219
+ if (!token)
220
+ return json(res, 400, { error: "token required" });
221
+ const action = String(body.action ?? "");
222
+ if (action !== "verify" && action !== "guilds" && action !== "await-telegram-start") {
223
+ return json(res, 400, { error: "unknown probe" });
224
+ }
225
+ const platform = body.platform === "discord" ? "discord" : "telegram";
226
+ // The token is read, used for one outbound call, and dropped. It is never
227
+ // logged and never echoed back in the response.
228
+ ctx.logger.info({ action, platform }, "settings: quickstart probe");
229
+ const result = await runProviderProbe({ action, platform, token, offset: typeof body.offset === "number" ? body.offset : 0 }, { isTokenInUse: candidate => ctx.isBotTokenInUse?.(candidate) ?? false });
230
+ json(res, result.ok ? 200 : 409, result);
231
+ }).catch(() => json(res, 400, { error: "bad request" }));
232
+ return true;
233
+ }
234
+ if (method === "POST" && path === "/api/settings/quickstart/plan") {
235
+ if (!cfg) {
236
+ json(res, 503, { error: "fleet not loaded" });
237
+ return true;
238
+ }
239
+ readBody(req, 16 * 1024).then(buf => {
240
+ let body;
241
+ try {
242
+ body = JSON.parse(buf.toString("utf-8") || "{}");
243
+ }
244
+ catch {
245
+ return json(res, 400, { error: "invalid JSON" });
246
+ }
247
+ const invalid = validateWizardInput(body);
248
+ if (invalid)
249
+ return json(res, 400, { error: invalid });
250
+ json(res, 200, planQuickstart(body, {
251
+ backends: detectWizardBackends(),
252
+ has_fleet: Object.keys(cfg.instances ?? {}).length > 0,
253
+ channels: wizardChannels(cfg),
254
+ }));
255
+ }).catch(() => json(res, 400, { error: "bad request" }));
256
+ return true;
257
+ }
258
+ if (method === "POST" && path === "/api/settings/quickstart/commit") {
259
+ if (!cfg) {
260
+ json(res, 503, { error: "fleet not loaded" });
261
+ return true;
262
+ }
263
+ readBody(req, 16 * 1024).then(buf => {
264
+ let body;
265
+ try {
266
+ body = JSON.parse(buf.toString("utf-8") || "{}");
267
+ }
268
+ catch {
269
+ return json(res, 400, { error: "invalid JSON" });
270
+ }
271
+ const invalid = validateWizardInput(body);
272
+ if (invalid)
273
+ return json(res, 400, { error: invalid });
274
+ if (!body.token)
275
+ return json(res, 400, { error: "token required" });
276
+ const summary = wizardChannels(cfg);
277
+ const plan = planQuickstart(body, {
278
+ backends: detectWizardBackends(),
279
+ has_fleet: Object.keys(cfg.instances ?? {}).length > 0,
280
+ channels: summary,
281
+ });
282
+ // Everything is assembled and validated on a copy. Nothing on disk and
283
+ // nothing in memory moves until the whole result is known to be valid —
284
+ // the previous order wrote the token first and left the running config
285
+ // rewritten when validation then failed.
286
+ const draft = structuredClone(cfg);
287
+ const channels = (draft.channels ?? (draft.channel ? [draft.channel] : []));
288
+ const existingIndex = channels.findIndex(channel => channel.bot_token_env === body.token_env);
289
+ const entry = { id: nextChannelId(body.platform, body.token_env, summary), ...plan.channel };
290
+ if (existingIndex >= 0)
291
+ channels[existingIndex] = { ...channels[existingIndex], ...entry };
292
+ else
293
+ channels.push(entry);
294
+ draft.channels = channels;
295
+ delete draft.channel;
296
+ draft.instances[body.instance_name] = {
297
+ ...(draft.instances[body.instance_name] ?? {}),
298
+ working_directory: body.working_directory,
299
+ backend: body.backend,
300
+ };
301
+ const validation = validateFleetConfig(draft);
302
+ if (!validation.valid) {
303
+ return json(res, 400, { error: validation.errors.map(e => `${e.path}: ${e.message}`).join("; ") });
304
+ }
305
+ const secret = writeQuickstartSecret(ctx.dataDir, body.token_env, body.token);
306
+ const before = {
307
+ channels: cfg.channels,
308
+ channel: cfg.channel,
309
+ instance: cfg.instances[body.instance_name],
310
+ hadInstance: Object.prototype.hasOwnProperty.call(cfg.instances, body.instance_name),
311
+ };
312
+ cfg.channels = draft.channels;
313
+ delete cfg.channel;
314
+ cfg.instances[body.instance_name] = draft.instances[body.instance_name];
315
+ try {
316
+ ctx.saveFleetConfig();
317
+ }
318
+ catch (err) {
319
+ // The file is the authority. If it did not take the change, the running
320
+ // config must not keep it either.
321
+ cfg.channels = before.channels;
322
+ if (before.channel !== undefined)
323
+ cfg.channel = before.channel;
324
+ if (before.hadInstance)
325
+ cfg.instances[body.instance_name] = before.instance;
326
+ else
327
+ delete cfg.instances[body.instance_name];
328
+ return json(res, 500, { error: err.message });
329
+ }
330
+ ctx.logger.info({ instance: body.instance_name, platform: body.platform }, "settings: quickstart committed");
331
+ // No apply here: the page starts the ordinary job so the wizard's last
332
+ // step has the same progress, deadline and restart recovery as everything
333
+ // else the panel applies.
334
+ json(res, 200, { ok: true, plan, secret_mode_ok: secret.ok, warnings: plan.warnings });
335
+ }).catch(() => json(res, 400, { error: "bad request" }));
336
+ return true;
337
+ }
338
+ return false;
339
+ }
340
+ //# sourceMappingURL=quickstart-api.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"quickstart-api.js","sourceRoot":"","sources":["../src/quickstart-api.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,8 @@
1
1
  import { createInterface } from "node:readline/promises";
2
2
  import { writeFileSync, readFileSync, mkdirSync, existsSync, readdirSync, statSync } from "node:fs";
3
3
  import { writeSecretFile } from "./secret-file.js";
4
+ // The same probes the Settings wizard makes — one copy, one behaviour.
5
+ import { awaitTelegramGroupStart, listDiscordGuilds, TelegramPollConflictError, verifyDiscordToken } from "./provider-probe.js";
4
6
  import { join, resolve } from "node:path";
5
7
  import { homedir, platform } from "node:os";
6
8
  import { stdin, stdout } from "node:process";
@@ -42,61 +44,18 @@ function detectBackends() {
42
44
  }
43
45
  // ── Group + User ID auto-detect via Telegram polling ─────
44
46
  // ── Discord bot verification ─────────────────────────────
45
- async function verifyDiscordToken(token) {
46
- try {
47
- const res = await fetch("https://discord.com/api/v10/users/@me", {
48
- headers: { Authorization: `Bot ${token}` },
49
- });
50
- if (!res.ok)
51
- return { valid: false, username: null, id: null };
52
- // For a bot user, the account id is also its application (client) id.
53
- const data = (await res.json());
54
- return { valid: true, username: data.username ?? null, id: data.id ?? null };
55
- }
56
- catch {
57
- return { valid: false, username: null, id: null };
58
- }
59
- }
60
- async function listDiscordGuilds(token) {
61
- try {
62
- const res = await fetch("https://discord.com/api/v10/users/@me/guilds", {
63
- headers: { Authorization: `Bot ${token}` },
64
- });
65
- if (!res.ok)
66
- return [];
67
- return (await res.json());
68
- }
69
- catch {
70
- return [];
71
- }
72
- }
73
47
  // ── Telegram group + user detection ──────────────────────
74
48
  const DETECT_TIMEOUT = 3 * 60_000;
75
49
  async function detectGroupAndUser(token) {
76
- const api = `https://api.telegram.org/bot${token}`;
77
- let offset = 0;
78
50
  const start = Date.now();
79
- // Consume stale updates first
80
- try {
81
- const stale = await fetch(`${api}/getUpdates?offset=-1&timeout=0`);
82
- const data = (await stale.json());
83
- if (data.result?.length)
84
- offset = data.result[data.result.length - 1].update_id + 1;
85
- }
86
- catch { /* ignore */ }
51
+ let offset = 0;
87
52
  while (Date.now() - start < DETECT_TIMEOUT) {
88
53
  process.stdout.write(` Waiting for message... ${dim("(Ctrl+C to cancel)")}\r`);
89
- const res = await fetch(`${api}/getUpdates?offset=${offset}&timeout=30`);
90
- const data = (await res.json());
91
- for (const update of data.result ?? []) {
92
- offset = update.update_id + 1;
93
- const msg = update.message;
94
- if (msg?.chat?.type === "supergroup" || msg?.chat?.type === "group") {
95
- if (msg.from?.id) {
96
- process.stdout.write("\x1b[2K"); // clear line
97
- return { groupId: msg.chat.id, userId: msg.from.id };
98
- }
99
- }
54
+ const slice = await awaitTelegramGroupStart(token, { deadlineMs: 30_000, offset });
55
+ offset = slice.offset;
56
+ if (slice.found) {
57
+ process.stdout.write("\x1b[2K"); // clear line
58
+ return slice.found;
100
59
  }
101
60
  }
102
61
  throw new Error("Timed out (3 min). Please run `agend quickstart` again.");
@@ -257,7 +216,21 @@ async function runTelegramFlow(rl) {
257
216
  break;
258
217
  }
259
218
  console.log(` Add @${botUsername} to a Telegram group, then send /start in the group.\n`);
260
- const detected = await detectGroupAndUser(token);
219
+ let detected;
220
+ try {
221
+ detected = await detectGroupAndUser(token);
222
+ }
223
+ catch (err) {
224
+ if (err instanceof TelegramPollConflictError) {
225
+ // getUpdates has one consumer. Before the shared probe reported this, the
226
+ // CLI polled against the other reader and timed out after three silent
227
+ // minutes; now it says what is wrong and how to get past it.
228
+ console.log(`\n ${yellow("!")} Another process is already reading this bot's updates.`);
229
+ console.log(` A running AgEnD, or a second quickstart, is polling the same token.`);
230
+ console.log(` Stop it (${dim("agend stop")}) and try again, or enter the group id by hand in Settings.\n`);
231
+ }
232
+ throw err;
233
+ }
261
234
  const groupId = String(detected.groupId);
262
235
  const userId = String(detected.userId);
263
236
  console.log(` ${green("✓")} Group: ${groupId} | User: ${userId}\n`);