@craftsamo/telegram-tools 0.1.0 → 0.3.0

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.
package/dist/cli.js CHANGED
@@ -27,6 +27,21 @@ var PROJECT = {
27
27
  toolsets: ["account", "chats", "sync", "files", "sends", "actions"],
28
28
  /** The toolsets on when a setting names none. */
29
29
  defaultToolsets: ["account", "chats", "sync", "sends"],
30
+ /** The package's own settings, which the tools themselves read: each snake_case name and its type, with bounds when it needs them. */
31
+ options: {
32
+ /** Where every account's state lives. */
33
+ state_dir: "path",
34
+ /** Where received files are saved. */
35
+ download_dir: "path",
36
+ /** The largest received file a call may download, in megabytes. */
37
+ download_max_mb: { type: "number", integer: true, min: 1, max: 2e3 },
38
+ /** The directories files may be sent from, besides the working directory. */
39
+ send_dirs: "paths",
40
+ /** Whether messages that disappear are kept; read by the sync service's commands. */
41
+ keep_disappearing: "boolean",
42
+ /** Whether channels are listed and their messages received; read by the sync service's commands. */
43
+ channels: "boolean"
44
+ },
30
45
  /** The environment variables the tools read besides the settings, which Codex forwards to the server after them. */
31
46
  toolVariables: []
32
47
  };
@@ -5101,7 +5116,7 @@ var recursive = /* @__PURE__ */ new WeakMap();
5101
5116
  var NONE = 0;
5102
5117
  var ASSUMED = 1;
5103
5118
  var PROVEN = 2;
5104
- function isRecursive(inst, stack, resolve8) {
5119
+ function isRecursive(inst, stack, resolve6) {
5105
5120
  const cached2 = recursive.get(inst);
5106
5121
  if (cached2 !== void 0)
5107
5122
  return cached2 ? PROVEN : NONE;
@@ -5111,7 +5126,7 @@ function isRecursive(inst, stack, resolve8) {
5111
5126
  let result = NONE;
5112
5127
  const check2 = (child) => {
5113
5128
  if (result !== PROVEN && child?._zod) {
5114
- const answer = isRecursive(child, stack, resolve8);
5129
+ const answer = isRecursive(child, stack, resolve6);
5115
5130
  if (answer > result)
5116
5131
  result = answer;
5117
5132
  }
@@ -5122,7 +5137,7 @@ function isRecursive(inst, stack, resolve8) {
5122
5137
  const desc = Object.getOwnPropertyDescriptor(sh, key);
5123
5138
  if (spread && !desc.enumerable)
5124
5139
  continue;
5125
- const child = desc.get ? ASSUMED : desc.value?._zod ? isRecursive(desc.value, stack, resolve8) : NONE;
5140
+ const child = desc.get ? ASSUMED : desc.value?._zod ? isRecursive(desc.value, stack, resolve6) : NONE;
5126
5141
  if (child > answer)
5127
5142
  answer = child;
5128
5143
  }
@@ -5186,7 +5201,7 @@ function isRecursive(inst, stack, resolve8) {
5186
5201
  break;
5187
5202
  // `$ZodLazy` caches its inner on the def, so a resolved edge is followed exactly
5188
5203
  case "lazy": {
5189
- const inner = def._cachedInner ?? (resolve8 ? inst._zod.innerType : void 0);
5204
+ const inner = def._cachedInner ?? (resolve6 ? inst._zod.innerType : void 0);
5190
5205
  merge2(inner ? isRecursive(inner, stack, false) : ASSUMED);
5191
5206
  break;
5192
5207
  }
@@ -9384,8 +9399,8 @@ function ko_default() {
9384
9399
  }
9385
9400
 
9386
9401
  // node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/locales/lt.js
9387
- var capitalizeFirstCharacter = (text) => {
9388
- return text.charAt(0).toUpperCase() + text.slice(1);
9402
+ var capitalizeFirstCharacter = (text2) => {
9403
+ return text2.charAt(0).toUpperCase() + text2.slice(1);
9389
9404
  };
9390
9405
  function getUnitTypeFromNumber(number4) {
9391
9406
  const abs2 = Math.abs(number4);
@@ -19792,8 +19807,8 @@ function quoteBadLabel(value) {
19792
19807
  const truncated = value.length > MAX_BAD_LABEL_PREVIEW ? `${value.slice(0, MAX_BAD_LABEL_PREVIEW)}\u2026` : value;
19793
19808
  return JSON.stringify(truncated);
19794
19809
  }
19795
- function isLabel(text) {
19796
- return typeof text === "string" && LABEL_PATTERN.test(text);
19810
+ function isLabel(text2) {
19811
+ return typeof text2 === "string" && LABEL_PATTERN.test(text2);
19797
19812
  }
19798
19813
  function checkLabel(label) {
19799
19814
  if (!isLabel(label)) {
@@ -20229,6 +20244,7 @@ function acquireSyncLock(path) {
20229
20244
  }
20230
20245
 
20231
20246
  // src/core/time.ts
20247
+ var MS_PER_S = 1e3;
20232
20248
  var MS_PER_MINUTE = 6e4;
20233
20249
  var MINUTES_PER_HOUR = 60;
20234
20250
  var localOffsetMinutes = (ms) => -new Date(ms).getTimezoneOffset();
@@ -20248,10 +20264,10 @@ var MILLISECOND_DIGITS = 3;
20248
20264
  var MIN_YEAR = 1e3;
20249
20265
  var MAX_HOUR = 23;
20250
20266
  var MAX_MINUTE = 59;
20251
- function badTime(text, name) {
20267
+ function badTime(text2, name) {
20252
20268
  return new ToolError(
20253
20269
  "invalid_argument",
20254
- `${name} is not a time: ${JSON.stringify(text)}. Use RFC 3339 with an offset (2026-11-07T14:03:12+09:00), or a date or time without one (2026-11-07, 2026-11-07T14:03), which reads as local time.`
20270
+ `${name} is not a time: ${JSON.stringify(text2)}. Use RFC 3339 with an offset (2026-11-07T14:03:12+09:00), or a date or time without one (2026-11-07, 2026-11-07T14:03), which reads as local time.`
20255
20271
  );
20256
20272
  }
20257
20273
  function isCalendarDay(year, month, day) {
@@ -20259,21 +20275,21 @@ function isCalendarDay(year, month, day) {
20259
20275
  date5.setUTCFullYear(year, month - 1, day);
20260
20276
  return date5.getUTCFullYear() === year && date5.getUTCMonth() === month - 1 && date5.getUTCDate() === day;
20261
20277
  }
20262
- function parseTimeArgument(text, name) {
20263
- const match = TIME_PATTERN.exec(text.trim());
20264
- if (!match) throw badTime(text, name);
20278
+ function parseTimeArgument(text2, name) {
20279
+ const match = TIME_PATTERN.exec(text2.trim());
20280
+ if (!match) throw badTime(text2, name);
20265
20281
  const [, year, month, day, hour = "0", minute = "0", second = "0", fraction = "", zulu, sign, offsetHour, offsetMin] = match;
20266
20282
  const [y, mon, d, h2, mi, s] = [year, month, day, hour, minute, second].map(Number);
20267
20283
  const ms = Number(fraction.padEnd(MILLISECOND_DIGITS, "0").slice(0, MILLISECOND_DIGITS));
20268
20284
  if (y < MIN_YEAR || !isCalendarDay(y, mon, d) || h2 > MAX_HOUR || mi > MAX_MINUTE || s > MAX_MINUTE) {
20269
- throw badTime(text, name);
20285
+ throw badTime(text2, name);
20270
20286
  }
20271
20287
  if (sign === void 0 && zulu === void 0) return new Date(y, mon - 1, d, h2, mi, s, ms).getTime();
20272
20288
  const wall = Date.UTC(y, mon - 1, d, h2, mi, s, ms);
20273
20289
  if (zulu) return wall;
20274
20290
  const offsetH = Number(offsetHour);
20275
20291
  const offsetM = Number(offsetMin);
20276
- if (offsetH > MAX_HOUR || offsetM > MAX_MINUTE) throw badTime(text, name);
20292
+ if (offsetH > MAX_HOUR || offsetM > MAX_MINUTE) throw badTime(text2, name);
20277
20293
  const offset = (offsetH * MINUTES_PER_HOUR + offsetM) * MS_PER_MINUTE;
20278
20294
  return sign === "-" ? wall + offset : wall - offset;
20279
20295
  }
@@ -20622,23 +20638,23 @@ function encodeCursor(value) {
20622
20638
  function notACursor(name) {
20623
20639
  return new ToolError("invalid_argument", `${name} is not a cursor this tool returned.`);
20624
20640
  }
20625
- function decodeCursor(text, name) {
20626
- const bytes2 = Buffer3.from(text, "base64url");
20627
- if (bytes2.toString("base64url") !== text) throw notACursor(name);
20641
+ function decodeCursor(text2, name) {
20642
+ const bytes2 = Buffer3.from(text2, "base64url");
20643
+ if (bytes2.toString("base64url") !== text2) throw notACursor(name);
20628
20644
  try {
20629
20645
  return JSON.parse(bytes2.toString("utf8"));
20630
20646
  } catch {
20631
20647
  throw notACursor(name);
20632
20648
  }
20633
20649
  }
20634
- function readCursor(text, name, schema) {
20635
- const parsed = schema.safeParse(decodeCursor(text, name));
20650
+ function readCursor(text2, name, schema) {
20651
+ const parsed = schema.safeParse(decodeCursor(text2, name));
20636
20652
  if (!parsed.success) throw notACursor(name);
20637
20653
  return parsed.data;
20638
20654
  }
20639
20655
  var HIGH_SURROGATE = /[\uD800-\uDBFF]$/;
20640
- function cutText(text, keep) {
20641
- return text.length <= keep ? text : text.slice(0, keep).replace(HIGH_SURROGATE, "");
20656
+ function cutText(text2, keep) {
20657
+ return text2.length <= keep ? text2 : text2.slice(0, keep).replace(HIGH_SURROGATE, "");
20642
20658
  }
20643
20659
  function jsonLength(value) {
20644
20660
  return JSON.stringify(value).length;
@@ -20788,15 +20804,15 @@ var ERROR_CODES = {
20788
20804
  function isErrorCode(value) {
20789
20805
  return typeof value === "string" && Object.hasOwn(ERROR_CODES, value);
20790
20806
  }
20791
- function maskPhoneNumbers(text) {
20792
- return text.replace(PHONE_NUMBER, "[number]");
20807
+ function maskPhoneNumbers(text2) {
20808
+ return text2.replace(PHONE_NUMBER, "[number]");
20793
20809
  }
20794
20810
  function cut(message2) {
20795
20811
  return maskPhoneNumbers(message2).trim().slice(0, MAX_DETAIL_LENGTH);
20796
20812
  }
20797
20813
  function detail(message2) {
20798
- const text = cut(message2);
20799
- return text ? `: ${text}` : "";
20814
+ const text2 = cut(message2);
20815
+ return text2 ? `: ${text2}` : "";
20800
20816
  }
20801
20817
  function afterWriteError(method, effect, reason) {
20802
20818
  return effect === "write" ? new ToolError("uncertain", `${method} may have taken effect (${reason}). ${UNCERTAIN_ADVICE}`) : new ToolError("upstream_error", `${method} failed (${reason}).`);
@@ -20917,7 +20933,7 @@ function abortError(signal) {
20917
20933
  }
20918
20934
  function exec(argv, options) {
20919
20935
  const { signal } = options;
20920
- return new Promise((resolve8, reject) => {
20936
+ return new Promise((resolve6, reject) => {
20921
20937
  if (signal?.aborted) {
20922
20938
  reject(abortError(signal));
20923
20939
  return;
@@ -20976,7 +20992,7 @@ function exec(argv, options) {
20976
20992
  }
20977
20993
  const finish2 = () => settle3(() => {
20978
20994
  const { code, killedBy } = exitedWith ?? { code: null, killedBy: null };
20979
- resolve8({
20995
+ resolve6({
20980
20996
  code: code ?? -1,
20981
20997
  stdout,
20982
20998
  stderr,
@@ -21070,19 +21086,19 @@ var ServiceConnection = class _ServiceConnection {
21070
21086
  socket.on("error", (error62) => {
21071
21087
  this.endReason ??= `the connection to the service broke${error62.code ? ` (${error62.code})` : ""}`;
21072
21088
  });
21073
- this.closed = new Promise((resolve8) => {
21089
+ this.closed = new Promise((resolve6) => {
21074
21090
  socket.once("close", () => {
21075
21091
  this.endReason ??= "the service closed the connection";
21076
21092
  const lost = { lost: this.endReason };
21077
21093
  for (const settle3 of [...this.pending.values()]) settle3(lost);
21078
- resolve8();
21094
+ resolve6();
21079
21095
  });
21080
21096
  });
21081
21097
  }
21082
21098
  /** Connects to the service's socket; rejects as `upstream_error` when nothing is listening there. */
21083
21099
  static connect(socketPath, options = {}) {
21084
21100
  const { timeoutMs = DEFAULT_CONNECT_TIMEOUT_MS, signal, maxLineLength = DEFAULT_MAX_LINE_LENGTH } = options;
21085
- return new Promise((resolve8, reject) => {
21101
+ return new Promise((resolve6, reject) => {
21086
21102
  if (signal?.aborted) {
21087
21103
  reject(abortError(signal));
21088
21104
  return;
@@ -21104,7 +21120,7 @@ var ServiceConnection = class _ServiceConnection {
21104
21120
  };
21105
21121
  const onConnect = () => {
21106
21122
  detach();
21107
- resolve8(new _ServiceConnection(socket, maxLineLength));
21123
+ resolve6(new _ServiceConnection(socket, maxLineLength));
21108
21124
  };
21109
21125
  const onFailure = () => stop(new ToolError("upstream_error", NOT_RUNNING_MESSAGE));
21110
21126
  const onAbort2 = () => stop(abortError(signal));
@@ -21127,7 +21143,7 @@ var ServiceConnection = class _ServiceConnection {
21127
21143
  */
21128
21144
  call(method, params, options) {
21129
21145
  const { effect, timeoutMs = DEFAULT_CALL_TIMEOUT_MS, signal } = options;
21130
- return new Promise((resolve8, reject) => {
21146
+ return new Promise((resolve6, reject) => {
21131
21147
  if (signal?.aborted) {
21132
21148
  reject(abortError(signal));
21133
21149
  return;
@@ -21156,7 +21172,7 @@ var ServiceConnection = class _ServiceConnection {
21156
21172
  clearTimeout(timer);
21157
21173
  signal?.removeEventListener("abort", onAbort2);
21158
21174
  try {
21159
- resolve8(produce());
21175
+ resolve6(produce());
21160
21176
  } catch (error62) {
21161
21177
  reject(error62);
21162
21178
  }
@@ -21229,7 +21245,6 @@ async function callService(socketPath, method, params, options) {
21229
21245
  // src/core/chat/live.ts
21230
21246
  var REFRESH_TIMEOUT_MS = 12e4;
21231
21247
  var FETCH_TIMEOUT_MS = 18e4;
21232
- var MS_PER_S = 1e3;
21233
21248
  function requestHistory(socket, params, signal) {
21234
21249
  return callService(socket, SERVICE_REQUESTS.history, params, { effect: "read", signal });
21235
21250
  }
@@ -21357,113 +21372,6 @@ var messageEntry = external_exports.object({
21357
21372
  private_note: external_exports.string().optional()
21358
21373
  });
21359
21374
 
21360
- // src/core/chat/schema.ts
21361
- var METHODS = ["list", "view", "topics", "search", "around", "fetch"];
21362
- var GENERAL_TOPIC2 = 1;
21363
- var LIMITS = {
21364
- list: { default: 30, max: 200 },
21365
- view: { default: 50, max: 300 },
21366
- topics: { default: 30, max: TOPICS_LIMIT },
21367
- search: { default: 30, max: 200 }
21368
- };
21369
- var AROUND_COUNT = { default: 5, max: AROUND_LIMIT };
21370
- var FETCH_PAGES = { default: 1, max: FETCH_PAGE_LIMIT };
21371
- var accountArgument = external_exports.string().optional().describe("The account label; may be left out when only one account is logged in.");
21372
- var input3 = external_exports.object({
21373
- method: external_exports.enum(METHODS).describe(
21374
- "`list` finds chats; `view` reads the newest messages of one chat between two times, oldest first; `topics` lists the topics of a forum chat; `search` finds messages in the mirror by words; `around` reads the messages around one; `fetch` adds older history of a mirrored chat to the mirror."
21375
- ),
21376
- account: accountArgument,
21377
- query: external_exports.string().optional().describe(
21378
- "list: only chats whose name or username holds this text; a leading @ is ignored. search (required): the words to look for, all of which a message must hold in its text, caption or file name, in any order. Both ignore case and letter width."
21379
- ),
21380
- unread: external_exports.boolean().optional().describe("list: only chats with unread messages."),
21381
- last: external_exports.boolean().optional().describe("list: add each chat's newest mirrored message as `last_message`."),
21382
- refresh: external_exports.boolean().optional().describe(
21383
- "list: first take the chat list from Telegram (needs the sync service), then read it, and report when in `refreshed_at`."
21384
- ),
21385
- chat: external_exports.string().optional().describe(
21386
- "view, topics, around, fetch (required) and search (optional, to search one chat): the chat id, from `list`, such as 123456789 or -1001234567890. A name, username or phone number is not a chat."
21387
- ),
21388
- topic: external_exports.number().int().positive().optional().describe(
21389
- `view, around: only messages of this topic of a forum chat (ids from \`topics\`); the General topic is ${GENERAL_TOPIC2}. Refused for a chat without topics.`
21390
- ),
21391
- after: external_exports.string().optional().describe(
21392
- "view, search: only messages after this time (exclusive): RFC 3339 with an offset, or a date or time without one, read as local time, such as 2026-11-07 or 2026-11-07T14:03."
21393
- ),
21394
- before: external_exports.string().optional().describe("view, search: only messages before this time (exclusive); the same forms as `after`."),
21395
- limit: external_exports.number().int().optional().describe(
21396
- `How many to return. list: default ${LIMITS.list.default}, at most ${LIMITS.list.max}. view: default ${LIMITS.view.default}, at most ${LIMITS.view.max} (${HISTORY_LIMIT} for a chat read live). topics: default ${LIMITS.topics.default}, at most ${LIMITS.topics.max}. search: default ${LIMITS.search.default}, at most ${LIMITS.search.max}. A larger value is lowered to the most; a result may hold fewer to stay a size a model can read.`
21397
- ),
21398
- cursor: external_exports.string().optional().describe("The `next` of the previous result, to continue where it stopped."),
21399
- id: external_exports.number().int().positive().optional().describe("around (required): the id of the message to read around."),
21400
- before_count: external_exports.number().int().optional().describe(
21401
- `around: how many older messages to return, default ${AROUND_COUNT.default}, at most ${AROUND_COUNT.max}; 0 asks for none.`
21402
- ),
21403
- after_count: external_exports.number().int().optional().describe(
21404
- `around: how many newer messages to return, default ${AROUND_COUNT.default}, at most ${AROUND_COUNT.max}; 0 asks for none.`
21405
- ),
21406
- pages: external_exports.number().int().optional().describe(
21407
- `fetch: how many pages of ${FETCH_PAGE_SIZE} older messages to add, default ${FETCH_PAGES.default}, at most ${FETCH_PAGES.max}.`
21408
- )
21409
- });
21410
- var nameCut = external_exports.literal(true).optional().describe("Set when the name was longer than the most a result carries and was cut.");
21411
- var chatEntry2 = external_exports.object({
21412
- id: external_exports.string().describe("The chat id: Telegram's signed id as text, such as `123456789` or `-1001234567890`."),
21413
- kind: external_exports.enum(CHAT_KINDS).describe("`self` is Saved Messages."),
21414
- name: external_exports.string().nullable().describe("The person's or chat's name; null when none is known."),
21415
- name_cut: nameCut,
21416
- username: external_exports.string().optional(),
21417
- mirrored: external_exports.boolean().describe("Whether the mirror keeps this chat's messages."),
21418
- unread: external_exports.number().int().describe("Incoming messages not read yet."),
21419
- last_activity_at: localTimeSchema.nullable().describe("The latest message's time, in local time with offset; null when none is known."),
21420
- forum: external_exports.literal(true).optional().describe("Set for a supergroup with topics."),
21421
- archived: external_exports.literal(true).optional(),
21422
- left: external_exports.literal(true).optional().describe("Set for a group or channel the user has left or been removed from."),
21423
- can_send: external_exports.literal(false).optional().describe("Set when the user is known not to be able to write here."),
21424
- auto_delete_seconds: external_exports.number().int().optional().describe("The chat's auto-delete period, when on."),
21425
- last_message: messageEntry.nullable().optional().describe("With `last`: the newest mirrored message of the chat, or null when none is mirrored.")
21426
- });
21427
- var topicEntry = external_exports.object({
21428
- id: external_exports.number().int().describe(`The topic id, to pass as \`topic\` to \`view\`; ${GENERAL_TOPIC2} is the General topic.`),
21429
- title: external_exports.string().nullable().describe("The topic's title; null when none is known."),
21430
- closed: external_exports.literal(true).optional().describe("Set for a topic that is closed."),
21431
- pinned: external_exports.literal(true).optional().describe("Set for a topic that is pinned."),
21432
- unread: external_exports.number().int().describe("Messages in it not read yet."),
21433
- last_activity_at: localTimeSchema.nullable().describe("The newest message's time, in local time with offset; null when none is known.")
21434
- });
21435
- var output3 = external_exports.object({
21436
- chats: external_exports.array(chatEntry2).optional().describe("list: the chats, newest activity first."),
21437
- refreshed_at: localTimeSchema.optional().describe("list with `refresh`: when the chat list was taken from Telegram, in local time with offset."),
21438
- chat: chatEntry2.optional().describe("view, topics, around, fetch: the chat read."),
21439
- messages: external_exports.array(messageEntry).optional().describe("view, around: the messages, oldest first. search: the hits, newest first."),
21440
- live: external_exports.literal(true).optional().describe(
21441
- "view, around: set when the chat is not mirrored, so the messages were read from Telegram and stored nowhere."
21442
- ),
21443
- topics: external_exports.array(topicEntry).optional().describe("topics: the topics, most recently active first."),
21444
- anchor: external_exports.number().int().optional().describe("around: the id of the message read around, among `messages`."),
21445
- trimmed_before: external_exports.number().int().optional().describe(
21446
- "around: how many older messages were left out, farthest first, to keep the result a size that can be read."
21447
- ),
21448
- trimmed_after: external_exports.number().int().optional().describe(
21449
- "around: how many newer messages were left out, farthest first, to keep the result a size that can be read."
21450
- ),
21451
- scanned_to: localTimeSchema.optional().describe(
21452
- "search: set when the search stopped before the end of the history it covers: the time of the oldest message looked at, in local time with offset. `next` continues from there."
21453
- ),
21454
- scope: external_exports.string().optional().describe("search: what the search covers and what it does not."),
21455
- fetched: external_exports.object({
21456
- added: external_exports.number().int().describe("How many messages the mirror gained."),
21457
- pages: external_exports.number().int().describe("How many pages were read."),
21458
- complete: external_exports.boolean().describe("Whether Telegram has nothing older for this chat."),
21459
- oldest_at: localTimeSchema.nullable().describe(
21460
- "The time of the oldest message the mirror now holds of this chat, in local time with offset; null when none."
21461
- )
21462
- }).optional().describe("fetch: what the history fetch stored."),
21463
- next: external_exports.string().optional().describe("Pass back as `cursor` to continue; absent when there is no more."),
21464
- note: external_exports.string().describe("Says that what the result carries is data written by other people.")
21465
- });
21466
-
21467
21375
  // src/core/chat/message-rows.ts
21468
21376
  var MESSAGE_COLUMNS = "chat, id, topic, ts, from_me, sender, sender_name, kind, body, entities, media, action, reply, forward, grouped, reactions, edited, expires, view_once, self_destruct";
21469
21377
  function liveMessages(now) {
@@ -21471,7 +21379,7 @@ function liveMessages(now) {
21471
21379
  }
21472
21380
  function inTopic(topic) {
21473
21381
  return {
21474
- condition: topic === GENERAL_TOPIC2 ? "(topic IS NULL OR topic = ?)" : "topic = ?",
21382
+ condition: topic === GENERAL_TOPIC ? "(topic IS NULL OR topic = ?)" : "topic = ?",
21475
21383
  params: [topic]
21476
21384
  };
21477
21385
  }
@@ -21584,10 +21492,10 @@ function replyTo(parsed, related) {
21584
21492
  if (reply.chat !== void 0) entry2.chat = reply.chat;
21585
21493
  if (reply.topic !== void 0) entry2.topic = reply.topic;
21586
21494
  if (reply.quote !== void 0) entry2.quote = reply.quote;
21587
- const text = repliedText(parsed, related)?.text;
21588
- if (text !== void 0) {
21589
- entry2.text = cutText(text, REPLY_TEXT_LENGTH);
21590
- if (entry2.text.length < text.length) entry2.text_cut = true;
21495
+ const text2 = repliedText(parsed, related)?.text;
21496
+ if (text2 !== void 0) {
21497
+ entry2.text = cutText(text2, REPLY_TEXT_LENGTH);
21498
+ if (entry2.text.length < text2.length) entry2.text_cut = true;
21591
21499
  }
21592
21500
  return entry2;
21593
21501
  }
@@ -21656,25 +21564,25 @@ function texts(entry2) {
21656
21564
  ];
21657
21565
  }
21658
21566
  function messageTextLength(entry2) {
21659
- return texts(entry2).reduce((total, text) => total + text.length, 0);
21567
+ return texts(entry2).reduce((total, text2) => total + text2.length, 0);
21660
21568
  }
21661
21569
  function cutMessage(entry2, keep) {
21662
21570
  let room = keep;
21663
21571
  let cut3 = false;
21664
- const take = (text) => {
21665
- const kept = cutText(text, room);
21666
- room = Math.max(0, room - text.length);
21667
- if (kept.length < text.length) cut3 = true;
21572
+ const take = (text2) => {
21573
+ const kept = cutText(text2, room);
21574
+ room = Math.max(0, room - text2.length);
21575
+ if (kept.length < text2.length) cut3 = true;
21668
21576
  return kept;
21669
21577
  };
21670
21578
  const cutEntry = { ...entry2 };
21671
21579
  if (entry2.text !== void 0) cutEntry.text = take(entry2.text);
21672
21580
  if (entry2.reply_to) {
21673
- const { quote, text } = entry2.reply_to;
21581
+ const { quote, text: text2 } = entry2.reply_to;
21674
21582
  cutEntry.reply_to = {
21675
21583
  ...entry2.reply_to,
21676
21584
  ...quote === void 0 ? {} : { quote: take(quote) },
21677
- ...text === void 0 ? {} : { text: take(text) }
21585
+ ...text2 === void 0 ? {} : { text: take(text2) }
21678
21586
  };
21679
21587
  }
21680
21588
  if (entry2.earlier_versions)
@@ -21696,6 +21604,112 @@ var cuttableMessage = {
21696
21604
  drop: dropMetadata
21697
21605
  };
21698
21606
 
21607
+ // src/core/chat/schema.ts
21608
+ var METHODS = ["list", "view", "topics", "search", "around", "fetch"];
21609
+ var LIMITS = {
21610
+ list: { default: 30, max: 200 },
21611
+ view: { default: 50, max: 300 },
21612
+ topics: { default: 30, max: TOPICS_LIMIT },
21613
+ search: { default: 30, max: 200 }
21614
+ };
21615
+ var AROUND_COUNT = { default: 5, max: AROUND_LIMIT };
21616
+ var FETCH_PAGES = { default: 1, max: FETCH_PAGE_LIMIT };
21617
+ var accountArgument = external_exports.string().optional().describe("The account label; may be left out when only one account is logged in.");
21618
+ var input3 = external_exports.object({
21619
+ method: external_exports.enum(METHODS).describe(
21620
+ "`list` finds chats; `view` reads the newest messages of one chat between two times, oldest first; `topics` lists the topics of a forum chat; `search` finds messages in the mirror by words; `around` reads the messages around one; `fetch` adds older history of a mirrored chat to the mirror."
21621
+ ),
21622
+ account: accountArgument,
21623
+ query: external_exports.string().optional().describe(
21624
+ "list: only chats whose name or username holds this text; a leading @ is ignored. search (required): the words to look for, all of which a message must hold in its text, caption or file name, in any order. Both ignore case and letter width."
21625
+ ),
21626
+ unread: external_exports.boolean().optional().describe("list: only chats with unread messages."),
21627
+ last: external_exports.boolean().optional().describe("list: add each chat's newest mirrored message as `last_message`."),
21628
+ refresh: external_exports.boolean().optional().describe(
21629
+ "list: first take the chat list from Telegram (needs the sync service), then read it, and report when in `refreshed_at`."
21630
+ ),
21631
+ chat: external_exports.string().optional().describe(
21632
+ "view, topics, around, fetch (required) and search (optional, to search one chat): the chat id, from `list`, such as 123456789 or -1001234567890. A name, username or phone number is not a chat."
21633
+ ),
21634
+ topic: external_exports.number().int().positive().optional().describe(
21635
+ `view, around: only messages of this topic of a forum chat (ids from \`topics\`); the General topic is ${GENERAL_TOPIC}. Refused for a chat without topics.`
21636
+ ),
21637
+ after: external_exports.string().optional().describe(
21638
+ "view, search: only messages after this time (exclusive): RFC 3339 with an offset, or a date or time without one, read as local time, such as 2026-11-07 or 2026-11-07T14:03."
21639
+ ),
21640
+ before: external_exports.string().optional().describe("view, search: only messages before this time (exclusive); the same forms as `after`."),
21641
+ limit: external_exports.number().int().optional().describe(
21642
+ `How many to return. list: default ${LIMITS.list.default}, at most ${LIMITS.list.max}. view: default ${LIMITS.view.default}, at most ${LIMITS.view.max} (${HISTORY_LIMIT} for a chat read live). topics: default ${LIMITS.topics.default}, at most ${LIMITS.topics.max}. search: default ${LIMITS.search.default}, at most ${LIMITS.search.max}. A larger value is lowered to the most; a result may hold fewer to stay a size a model can read.`
21643
+ ),
21644
+ cursor: external_exports.string().optional().describe("The `next` of the previous result, to continue where it stopped."),
21645
+ id: external_exports.number().int().positive().optional().describe("around (required): the id of the message to read around."),
21646
+ before_count: external_exports.number().int().optional().describe(
21647
+ `around: how many older messages to return, default ${AROUND_COUNT.default}, at most ${AROUND_COUNT.max}; 0 asks for none.`
21648
+ ),
21649
+ after_count: external_exports.number().int().optional().describe(
21650
+ `around: how many newer messages to return, default ${AROUND_COUNT.default}, at most ${AROUND_COUNT.max}; 0 asks for none.`
21651
+ ),
21652
+ pages: external_exports.number().int().optional().describe(
21653
+ `fetch: how many pages of ${FETCH_PAGE_SIZE} older messages to add, default ${FETCH_PAGES.default}, at most ${FETCH_PAGES.max}.`
21654
+ )
21655
+ });
21656
+ var nameCut = external_exports.literal(true).optional().describe("Set when the name was longer than the most a result carries and was cut.");
21657
+ var chatEntry2 = external_exports.object({
21658
+ id: external_exports.string().describe("The chat id: Telegram's signed id as text, such as `123456789` or `-1001234567890`."),
21659
+ kind: external_exports.enum(CHAT_KINDS).describe("`self` is Saved Messages."),
21660
+ name: external_exports.string().nullable().describe("The person's or chat's name; null when none is known."),
21661
+ name_cut: nameCut,
21662
+ username: external_exports.string().optional(),
21663
+ mirrored: external_exports.boolean().describe("Whether the mirror keeps this chat's messages."),
21664
+ unread: external_exports.number().int().describe("Incoming messages not read yet."),
21665
+ last_activity_at: localTimeSchema.nullable().describe("The latest message's time, in local time with offset; null when none is known."),
21666
+ forum: external_exports.literal(true).optional().describe("Set for a supergroup with topics."),
21667
+ archived: external_exports.literal(true).optional(),
21668
+ left: external_exports.literal(true).optional().describe("Set for a group or channel the user has left or been removed from."),
21669
+ can_send: external_exports.literal(false).optional().describe("Set when the user is known not to be able to write here."),
21670
+ auto_delete_seconds: external_exports.number().int().optional().describe("The chat's auto-delete period, when on."),
21671
+ last_message: messageEntry.nullable().optional().describe("With `last`: the newest mirrored message of the chat, or null when none is mirrored.")
21672
+ });
21673
+ var topicEntry = external_exports.object({
21674
+ id: external_exports.number().int().describe(`The topic id, to pass as \`topic\` to \`view\`; ${GENERAL_TOPIC} is the General topic.`),
21675
+ title: external_exports.string().nullable().describe("The topic's title; null when none is known."),
21676
+ closed: external_exports.literal(true).optional().describe("Set for a topic that is closed."),
21677
+ pinned: external_exports.literal(true).optional().describe("Set for a topic that is pinned."),
21678
+ unread: external_exports.number().int().describe("Messages in it not read yet."),
21679
+ last_activity_at: localTimeSchema.nullable().describe("The newest message's time, in local time with offset; null when none is known.")
21680
+ });
21681
+ var output3 = external_exports.object({
21682
+ chats: external_exports.array(chatEntry2).optional().describe("list: the chats, newest activity first."),
21683
+ refreshed_at: localTimeSchema.optional().describe("list with `refresh`: when the chat list was taken from Telegram, in local time with offset."),
21684
+ chat: chatEntry2.optional().describe("view, topics, around, fetch: the chat read."),
21685
+ messages: external_exports.array(messageEntry).optional().describe("view, around: the messages, oldest first. search: the hits, newest first."),
21686
+ live: external_exports.literal(true).optional().describe(
21687
+ "view, around: set when the chat is not mirrored, so the messages were read from Telegram and stored nowhere."
21688
+ ),
21689
+ topics: external_exports.array(topicEntry).optional().describe("topics: the topics, most recently active first."),
21690
+ anchor: external_exports.number().int().optional().describe("around: the id of the message read around, among `messages`."),
21691
+ trimmed_before: external_exports.number().int().optional().describe(
21692
+ "around: how many older messages were left out, farthest first, to keep the result a size that can be read."
21693
+ ),
21694
+ trimmed_after: external_exports.number().int().optional().describe(
21695
+ "around: how many newer messages were left out, farthest first, to keep the result a size that can be read."
21696
+ ),
21697
+ scanned_to: localTimeSchema.optional().describe(
21698
+ "search: set when the search stopped before the end of the history it covers: the time of the oldest message looked at, in local time with offset. `next` continues from there."
21699
+ ),
21700
+ scope: external_exports.string().optional().describe("search: what the search covers and what it does not."),
21701
+ fetched: external_exports.object({
21702
+ added: external_exports.number().int().describe("How many messages the mirror gained."),
21703
+ pages: external_exports.number().int().describe("How many pages were read."),
21704
+ complete: external_exports.boolean().describe("Whether Telegram has nothing older for this chat."),
21705
+ oldest_at: localTimeSchema.nullable().describe(
21706
+ "The time of the oldest message the mirror now holds of this chat, in local time with offset; null when none."
21707
+ )
21708
+ }).optional().describe("fetch: what the history fetch stored."),
21709
+ next: external_exports.string().optional().describe("Pass back as `cursor` to continue; absent when there is no more."),
21710
+ note: external_exports.string().describe("Says that what the result carries is data written by other people.")
21711
+ });
21712
+
21699
21713
  // src/core/chat/around.ts
21700
21714
  var TRIMMED_RESERVE = 100;
21701
21715
  var NO_MESSAGE = "No message with this id in this chat.";
@@ -21817,8 +21831,8 @@ function fetchResult(read, stored) {
21817
21831
  }
21818
21832
 
21819
21833
  // src/core/fold.ts
21820
- function foldCase(text) {
21821
- return text.normalize("NFKC").toUpperCase().toLowerCase().replace(/ς/g, "\u03C3");
21834
+ function foldCase(text2) {
21835
+ return text2.normalize("NFKC").toUpperCase().toLowerCase().replace(/ς/g, "\u03C3");
21822
21836
  }
21823
21837
 
21824
21838
  // src/core/chat/filter.ts
@@ -21898,7 +21912,7 @@ function listChats(mirror, args, now) {
21898
21912
  return result;
21899
21913
  }
21900
21914
 
21901
- // src/core/chat/open.ts
21915
+ // src/core/open.ts
21902
21916
  async function pickPaths(ctx, account2) {
21903
21917
  if (!ctx.stateDir) throw new ToolError("internal_error", "The entry point did not supply a state directory.");
21904
21918
  return pickLabel(ctx.stateDir, account2);
@@ -21957,8 +21971,8 @@ function foldedFileName(media) {
21957
21971
  return isRecord(info) && typeof info.name === "string" ? foldCase(info.name) : void 0;
21958
21972
  }
21959
21973
  function matchesAllWords(row, words2) {
21960
- const text = foldCase(row.body ?? "");
21961
- const unmatched = words2.filter((word) => !text.includes(word));
21974
+ const text2 = foldCase(row.body ?? "");
21975
+ const unmatched = words2.filter((word) => !text2.includes(word));
21962
21976
  if (unmatched.length === 0) return true;
21963
21977
  const name = row.media === null ? void 0 : foldedFileName(row.media);
21964
21978
  return name !== void 0 && unmatched.every((word) => name.includes(word));
@@ -22318,6 +22332,56 @@ var CHAT_FACT_TRANSLATIONS = {
22318
22332
  }
22319
22333
  };
22320
22334
 
22335
+ // src/core/chat/media-facts.ts
22336
+ var MEDIA_KIND_WORDS = {
22337
+ photo: "Photo",
22338
+ document: "Document",
22339
+ audio: "Audio",
22340
+ voice: "Voice message",
22341
+ video: "Video",
22342
+ sticker: "Sticker",
22343
+ dice: "Dice",
22344
+ contact: "Contact",
22345
+ venue: "Venue",
22346
+ geo: "Location",
22347
+ geo_live: "Live location",
22348
+ game: "Game",
22349
+ invoice: "Invoice",
22350
+ webpage: "Link preview",
22351
+ poll: "Poll",
22352
+ todo: "Checklist",
22353
+ story: "Story",
22354
+ paid: "Paid media",
22355
+ unsupported: "Unsupported media"
22356
+ };
22357
+ function mediaKindValue(type3) {
22358
+ return Object.hasOwn(MEDIA_KIND_WORDS, type3) ? { text: MEDIA_KIND_WORDS[type3] } : type3;
22359
+ }
22360
+ var MEDIA_FACT_TRANSLATIONS = {
22361
+ ja: {
22362
+ Media: "\u30E1\u30C7\u30A3\u30A2",
22363
+ Photo: "\u5199\u771F",
22364
+ Document: "\u30C9\u30AD\u30E5\u30E1\u30F3\u30C8",
22365
+ Audio: "\u97F3\u58F0",
22366
+ "Voice message": "\u30DC\u30A4\u30B9\u30E1\u30C3\u30BB\u30FC\u30B8",
22367
+ Video: "\u52D5\u753B",
22368
+ Sticker: "\u30B9\u30BF\u30F3\u30D7",
22369
+ Dice: "\u30B5\u30A4\u30B3\u30ED",
22370
+ Contact: "\u9023\u7D61\u5148",
22371
+ Venue: "\u5834\u6240",
22372
+ Location: "\u4F4D\u7F6E\u60C5\u5831",
22373
+ "Live location": "\u30E9\u30A4\u30D6\u4F4D\u7F6E\u60C5\u5831",
22374
+ Game: "\u30B2\u30FC\u30E0",
22375
+ Invoice: "\u8ACB\u6C42\u66F8",
22376
+ "Link preview": "\u30EA\u30F3\u30AF\u306E\u30D7\u30EC\u30D3\u30E5\u30FC",
22377
+ Poll: "\u6295\u7968",
22378
+ Checklist: "\u30C1\u30A7\u30C3\u30AF\u30EA\u30B9\u30C8",
22379
+ Story: "\u30B9\u30C8\u30FC\u30EA\u30FC",
22380
+ "Paid media": "\u6709\u6599\u30E1\u30C7\u30A3\u30A2",
22381
+ "Unsupported media": "\u672A\u5BFE\u5FDC\u306E\u30E1\u30C7\u30A3\u30A2"
22382
+ }
22383
+ };
22384
+
22321
22385
  // src/core/facts.ts
22322
22386
  function sizeFact(bytes2) {
22323
22387
  return { label: "Size", value: { text: bytes2 === 1 ? "{bytes} byte" : "{bytes} bytes", values: { bytes: bytes2 } } };
@@ -22552,11 +22616,11 @@ var ANIMATED_STICKER = "an animated sticker (.tgs), which cannot be inspected";
22552
22616
  function unreadableArchive(label) {
22553
22617
  return `an archive that cannot be inspected (${label})`;
22554
22618
  }
22555
- function words(text) {
22556
- return text.split(/\s+/).filter((word) => word !== "");
22619
+ function words(text2) {
22620
+ return text2.split(/\s+/).filter((word) => word !== "");
22557
22621
  }
22558
- function ascii(text) {
22559
- return Array.from(text, (character) => character.charCodeAt(0));
22622
+ function ascii(text2) {
22623
+ return Array.from(text2, (character) => character.charCodeAt(0));
22560
22624
  }
22561
22625
  function at(offset, bytes2) {
22562
22626
  return { offset, bytes: bytes2 };
@@ -22814,9 +22878,9 @@ function parseHeader(block) {
22814
22878
  }
22815
22879
  return { path, size: parseNumber(block.subarray(SIZE_START, SIZE_END)), type: block[TYPE_OFFSET] };
22816
22880
  }
22817
- function parseDecimal(text) {
22818
- if (!/^[0-9]{1,15}$/.test(text)) return void 0;
22819
- return Number(text);
22881
+ function parseDecimal(text2) {
22882
+ if (!/^[0-9]{1,15}$/.test(text2)) return void 0;
22883
+ return Number(text2);
22820
22884
  }
22821
22885
  function parsePaxRecords(data, maxRecords = Infinity) {
22822
22886
  const records = [];
@@ -23006,8 +23070,8 @@ var EXTENSIONS = {
23006
23070
  };
23007
23071
  var KIND_PATTERN = /^[a-z]{1,16}$/;
23008
23072
  var UNKNOWN_KIND = "file";
23009
- function byteLength(text) {
23010
- return Buffer5.byteLength(text);
23073
+ function byteLength(text2) {
23074
+ return Buffer5.byteLength(text2);
23011
23075
  }
23012
23076
  function extensionOf2(type3) {
23013
23077
  return type3 == null ? "" : EXTENSIONS[type3.split(";")[0].trim().toLowerCase()] ?? "";
@@ -23323,8 +23387,8 @@ function fitListings(result) {
23323
23387
  var MAX_NAME_CHARACTERS = 255;
23324
23388
  var CUT_MARK = "\u2026";
23325
23389
  var HIDDEN_CHARACTERS = /[\u0000-\u001F\u007F-\u009F\u00AD\u034F\u061C\u115F\u1160\u17B4\u17B5\u180B-\u180F\u200B-\u200F\u2028-\u202E\u2060-\u206F\u3164\uFE00-\uFE0D\uFEFF\uFFA0\uFFF9-\uFFFC\u{1D173}-\u{1D17A}\u{E0000}-\u{E007F}]/gu;
23326
- function cleanName(text) {
23327
- const cleaned = text.normalize("NFC").replace(HIDDEN_CHARACTERS, "?");
23390
+ function cleanName(text2) {
23391
+ const cleaned = text2.normalize("NFC").replace(HIDDEN_CHARACTERS, "?");
23328
23392
  const characters = Array.from(cleaned);
23329
23393
  if (characters.length <= MAX_NAME_CHARACTERS) return cleaned;
23330
23394
  return characters.slice(0, MAX_NAME_CHARACTERS - CUT_MARK.length).join("") + CUT_MARK;
@@ -23497,9 +23561,9 @@ function decodeUtf8Lossy(bytes2) {
23497
23561
  return LOSSY_UTF8.decode(bytes2);
23498
23562
  }
23499
23563
  function decodeCp437(bytes2) {
23500
- let text = "";
23501
- for (const byte of bytes2) text += byte < ASCII_END ? String.fromCharCode(byte) : CP437_HIGH[byte - ASCII_END];
23502
- return text;
23564
+ let text2 = "";
23565
+ for (const byte of bytes2) text2 += byte < ASCII_END ? String.fromCharCode(byte) : CP437_HIGH[byte - ASCII_END];
23566
+ return text2;
23503
23567
  }
23504
23568
 
23505
23569
  // src/core/archive/tar.ts
@@ -24319,14 +24383,6 @@ function namesOf(file2, id) {
24319
24383
  const name = safeFileName(file2.name, { kind: file2.kind, id, type: file2.type });
24320
24384
  return { name, shown: file2.name === null ? file2.kind : name };
24321
24385
  }
24322
- var FILE_KIND_WORDS = {
24323
- photo: "Photo",
24324
- document: "Document",
24325
- audio: "Audio",
24326
- voice: "Voice message",
24327
- video: "Video",
24328
- sticker: "Sticker"
24329
- };
24330
24386
  function saveHeadline(file2, chat) {
24331
24387
  if (file2 !== void 0 && chat !== null) return { text: "About to save {file} from {chat}", values: { file: file2, chat } };
24332
24388
  if (chat !== null) return { text: "About to save a file from {chat}", values: { chat } };
@@ -24334,9 +24390,8 @@ function saveHeadline(file2, chat) {
24334
24390
  return void 0;
24335
24391
  }
24336
24392
  function fileFacts(media, unpack) {
24337
- const kind = media && Object.hasOwn(FILE_KIND_WORDS, media.type) ? FILE_KIND_WORDS[media.type] : void 0;
24338
24393
  return [
24339
- ...media ? [{ label: "File", value: kind ? { text: kind } : media.type }] : [],
24394
+ ...media ? [{ label: "File", value: mediaKindValue(media.type) }] : [],
24340
24395
  ...unpack ? [{ label: "Unpack", value: { text: "Yes" } }] : [],
24341
24396
  ...media?.size !== void 0 && Number.isSafeInteger(media.size) && media.size > 0 ? [sizeFact(media.size)] : []
24342
24397
  ];
@@ -24567,14 +24622,14 @@ function storedReactions(json2) {
24567
24622
  function ownReaction(reactions) {
24568
24623
  return reactions.find((reaction2) => reaction2.mine)?.emoji;
24569
24624
  }
24570
- function checkEditable({ kind, body, captioned }, text) {
24625
+ function checkEditable({ kind, body, captioned }, text2) {
24571
24626
  if (kind === "service" || body === null && !captioned) {
24572
24627
  throw new ToolError("invalid_argument", "This message has no text or caption to edit; nothing was edited.");
24573
24628
  }
24574
- if (body === text) {
24629
+ if (body === text2) {
24575
24630
  throw new ToolError("invalid_argument", "The text is the same as the message's; nothing to edit.");
24576
24631
  }
24577
- if (captioned && text.length > CAPTION_MAX_UNITS) {
24632
+ if (captioned && text2.length > CAPTION_MAX_UNITS) {
24578
24633
  throw new ToolError(
24579
24634
  "invalid_argument",
24580
24635
  `A caption must be at most ${CAPTION_MAX_UNITS} characters; nothing was edited.`
@@ -24583,8 +24638,8 @@ function checkEditable({ kind, body, captioned }, text) {
24583
24638
  }
24584
24639
 
24585
24640
  // src/core/message/arguments.ts
24586
- function checkedText(text) {
24587
- const trimmed = text.trim();
24641
+ function checkedText(text2) {
24642
+ const trimmed = text2.trim();
24588
24643
  if (trimmed === "") throw new ToolError("invalid_argument", "text is blank; give the text to send.");
24589
24644
  if (trimmed.length > TEXT_MAX_UNITS) {
24590
24645
  throw new ToolError(
@@ -24642,8 +24697,8 @@ var Window = class {
24642
24697
  get tail() {
24643
24698
  return this.#tail;
24644
24699
  }
24645
- sees(text) {
24646
- const all = this.#tail + text;
24700
+ sees(text2) {
24701
+ const all = this.#tail + text2;
24647
24702
  this.#tail = all.slice(-TAIL_LENGTH);
24648
24703
  return MARKER.test(all);
24649
24704
  }
@@ -24653,13 +24708,13 @@ var PrivateKeyScan = class {
24653
24708
  #withoutNuls;
24654
24709
  /** Feeds the next chunk; whether a marker starts anywhere in the bytes so far. */
24655
24710
  sees(chunk) {
24656
- const text = Buffer.from(chunk.buffer, chunk.byteOffset, chunk.byteLength).toString("latin1");
24711
+ const text2 = Buffer.from(chunk.buffer, chunk.byteOffset, chunk.byteLength).toString("latin1");
24657
24712
  const before = this.#plain.tail;
24658
- const plain2 = this.#plain.sees(text);
24659
- if (this.#withoutNuls === void 0 && text.includes(NUL)) {
24713
+ const plain2 = this.#plain.sees(text2);
24714
+ if (this.#withoutNuls === void 0 && text2.includes(NUL)) {
24660
24715
  this.#withoutNuls = new Window(before);
24661
24716
  }
24662
- const stripped = this.#withoutNuls?.sees(text.replaceAll(NUL, "")) ?? false;
24717
+ const stripped = this.#withoutNuls?.sees(text2.replaceAll(NUL, "")) ?? false;
24663
24718
  return plain2 || stripped;
24664
24719
  }
24665
24720
  };
@@ -24851,9 +24906,8 @@ async function checkArchive(path, format2, limits, signal) {
24851
24906
  }
24852
24907
 
24853
24908
  // src/core/outgoing/limits.ts
24854
- var BYTES_PER_MB2 = 1024 * 1024;
24855
24909
  var MAX_FILES = 10;
24856
- var MAX_TOTAL_BYTES = 100 * BYTES_PER_MB2;
24910
+ var MAX_TOTAL_BYTES = 100 * BYTES_PER_MB;
24857
24911
 
24858
24912
  // src/core/file/send/constants.ts
24859
24913
  var SEND_FILES_TIMEOUT_MS = 30 * 60 * 1e3;
@@ -25286,12 +25340,12 @@ var DUPLICATE_NOTE = "An earlier delivery of this same call had already gone out
25286
25340
  var DUPLICATE_UNKNOWN_ID_NOTE = `${DUPLICATE_NOTE} Its id is not known yet; \`telegram_chat_read\` shows it once the service receives it.`;
25287
25341
 
25288
25342
  // src/core/message/uncertain.ts
25289
- function sentLike(paths, chat, text, startedAt) {
25343
+ function sentLike(paths, chat, text2, startedAt) {
25290
25344
  const rows = readMirror(
25291
25345
  paths,
25292
25346
  (mirror) => mirror.prepare(
25293
25347
  "SELECT id, ts FROM messages WHERE chat = ? AND from_me = 1 AND body = ? AND ts >= ? ORDER BY ts DESC, id DESC LIMIT ?"
25294
- ).all(chat, text, startedAt - SENT_LOOKBACK_MS, MAX_SENT_LIKE)
25348
+ ).all(chat, text2, startedAt - SENT_LOOKBACK_MS, MAX_SENT_LIKE)
25295
25349
  );
25296
25350
  return rows.map(({ id, ts }) => ({ id, time: formatLocalTime(ts) }));
25297
25351
  }
@@ -25311,8 +25365,8 @@ function withFound(error62, find, describe3) {
25311
25365
  details: { ...error62.details, sent_like_this: found }
25312
25366
  });
25313
25367
  }
25314
- function withSentLike(error62, paths, chat, text, startedAt) {
25315
- return withFound(error62, () => sentLike(paths, chat, text, startedAt), sentence);
25368
+ function withSentLike(error62, paths, chat, text2, startedAt) {
25369
+ return withFound(error62, () => sentLike(paths, chat, text2, startedAt), sentence);
25316
25370
  }
25317
25371
 
25318
25372
  // src/core/file/send/uncertain.ts
@@ -25449,17 +25503,17 @@ var MAX_HEADLINE_VALUES = 8;
25449
25503
  var MAX_HEADLINE_VALUE_LENGTH = 80;
25450
25504
  var MAX_PINS = 16;
25451
25505
  var HEADLINE_PLACEHOLDER = /\{([A-Za-z_][A-Za-z0-9_]*)\}/;
25452
- function cut2(text, limit) {
25453
- const points = Array.from(text);
25454
- return points.length > limit ? `${points.slice(0, limit - 1).join("")}\u2026` : text;
25506
+ function cut2(text2, limit) {
25507
+ const points = Array.from(text2);
25508
+ return points.length > limit ? `${points.slice(0, limit - 1).join("")}\u2026` : text2;
25455
25509
  }
25456
- function omittedBy(text, limit) {
25457
- const length = Array.from(text).length;
25510
+ function omittedBy(text2, limit) {
25511
+ const length = Array.from(text2).length;
25458
25512
  return length > limit ? length - (limit - 1) : 0;
25459
25513
  }
25460
- function templatePlaceholders(text) {
25514
+ function templatePlaceholders(text2) {
25461
25515
  const names = /* @__PURE__ */ new Set();
25462
- const parts = text.split(HEADLINE_PLACEHOLDER);
25516
+ const parts = text2.split(HEADLINE_PLACEHOLDER);
25463
25517
  for (const [index, part] of parts.entries()) {
25464
25518
  if (index % 2 === 1) names.add(part);
25465
25519
  else if (/[{}]/.test(part)) return void 0;
@@ -25477,10 +25531,10 @@ function valueEntries(values) {
25477
25531
  const entries = Object.entries(values);
25478
25532
  return entries.length > MAX_HEADLINE_VALUES ? void 0 : entries;
25479
25533
  }
25480
- function isTemplate(text, limit, entries) {
25481
- if (text.trim() === "" || Array.from(text).length > limit) return false;
25534
+ function isTemplate(text2, limit, entries) {
25535
+ if (text2.trim() === "" || Array.from(text2).length > limit) return false;
25482
25536
  const given = new Set(entries.map(([name]) => name));
25483
- const placeholders2 = templatePlaceholders(text);
25537
+ const placeholders2 = templatePlaceholders(text2);
25484
25538
  return placeholders2 !== void 0 && [...placeholders2].every((name) => given.has(name));
25485
25539
  }
25486
25540
  function isTemplateValue(value) {
@@ -25496,15 +25550,15 @@ function isFact(fact) {
25496
25550
  }
25497
25551
  function cutValue(value) {
25498
25552
  if (typeof value === "string") return cut2(value, MAX_VALUE_LENGTH);
25499
- const { text, values } = value;
25500
- if (values === void 0) return { text };
25553
+ const { text: text2, values } = value;
25554
+ if (values === void 0) return { text: text2 };
25501
25555
  const cutValues = Object.entries(values).map(
25502
25556
  ([name, entry2]) => [name, typeof entry2 === "string" ? cut2(entry2, MAX_VALUE_LENGTH) : entry2]
25503
25557
  );
25504
- return { text, values: Object.fromEntries(cutValues) };
25558
+ return { text: text2, values: Object.fromEntries(cutValues) };
25505
25559
  }
25506
- function isText2(text) {
25507
- return isRecord2(text) && typeof text.label === "string" && text.label.trim() !== "" && typeof text.body === "string";
25560
+ function isText2(text2) {
25561
+ return isRecord2(text2) && typeof text2.label === "string" && text2.label.trim() !== "" && typeof text2.body === "string";
25508
25562
  }
25509
25563
  function pinsOf(pins) {
25510
25564
  if (pins === void 0) return {};
@@ -25518,32 +25572,32 @@ function pinsOf(pins) {
25518
25572
  }
25519
25573
  function copyValue(value) {
25520
25574
  if (typeof value === "string") return value;
25521
- const { text, values } = value;
25522
- return values === void 0 ? { text } : { text, values: { ...values } };
25575
+ const { text: text2, values } = value;
25576
+ return values === void 0 ? { text: text2 } : { text: text2, values: { ...values } };
25523
25577
  }
25524
25578
  function headlineOf(headline) {
25525
25579
  if (!isRecord2(headline) || typeof headline.text !== "string") return void 0;
25526
- const { text, values } = headline;
25580
+ const { text: text2, values } = headline;
25527
25581
  const entries = valueEntries(values);
25528
- if (entries === void 0 || !isTemplate(text, MAX_HEADLINE_LENGTH, entries)) return void 0;
25582
+ if (entries === void 0 || !isTemplate(text2, MAX_HEADLINE_LENGTH, entries)) return void 0;
25529
25583
  if (!entries.every((entry2) => typeof entry2[1] === "string")) return void 0;
25530
- return values === void 0 ? { text } : { text, values: Object.fromEntries(entries) };
25584
+ return values === void 0 ? { text: text2 } : { text: text2, values: Object.fromEntries(entries) };
25531
25585
  }
25532
- function cutHeadline({ text, values }) {
25533
- if (values === void 0) return { text };
25586
+ function cutHeadline({ text: text2, values }) {
25587
+ if (values === void 0) return { text: text2 };
25534
25588
  const cutValues = Object.entries(values).map(
25535
25589
  ([name, value]) => [name, cut2(value, MAX_HEADLINE_VALUE_LENGTH)]
25536
25590
  );
25537
- return { text, values: Object.fromEntries(cutValues) };
25591
+ return { text: text2, values: Object.fromEntries(cutValues) };
25538
25592
  }
25539
- function cutDescription({ headline, facts, text, pins }) {
25593
+ function cutDescription({ headline, facts, text: text2, pins }) {
25540
25594
  return {
25541
25595
  ...headline && { headline: cutHeadline(headline) },
25542
25596
  facts: facts.slice(0, MAX_FACTS).map(({ label, value }) => ({
25543
25597
  label: cut2(label, MAX_LABEL_LENGTH),
25544
25598
  value: cutValue(value)
25545
25599
  })),
25546
- ...text && { text: { label: cut2(text.label, MAX_TEXT_LABEL_LENGTH), body: cut2(text.body, MAX_TEXT_LENGTH) } },
25600
+ ...text2 && { text: { label: cut2(text2.label, MAX_TEXT_LABEL_LENGTH), body: cut2(text2.body, MAX_TEXT_LENGTH) } },
25547
25601
  ...pins && { pins }
25548
25602
  };
25549
25603
  }
@@ -25567,47 +25621,54 @@ async function wholeCallDescription(spec, args, ctx) {
25567
25621
  if (kept === void 0) return void 0;
25568
25622
  const facts = entries.map(({ label, value }) => ({ label, value: copyValue(value) }));
25569
25623
  const headline = answer.headline === void 0 ? void 0 : headlineOf(answer.headline);
25570
- const text = answer.text === void 0 || answer.text.body === "" ? void 0 : { label: answer.text.label, body: answer.text.body };
25571
- if (headline === void 0 && facts.length === 0 && text === void 0) return void 0;
25572
- return { ...headline && { headline }, facts, ...text && { text }, ...kept };
25624
+ const text2 = answer.text === void 0 || answer.text.body === "" ? void 0 : { label: answer.text.label, body: answer.text.body };
25625
+ if (headline === void 0 && facts.length === 0 && text2 === void 0) return void 0;
25626
+ return { ...headline && { headline }, facts, ...text2 && { text: text2 }, ...kept };
25573
25627
  }
25574
25628
 
25575
25629
  // src/core/message/action-describe.ts
25576
25630
  var EDIT_HEADLINES = {
25577
25631
  named: "About to edit message {id} in {chat}",
25578
- saved: "About to edit message {id} in Saved Messages"
25632
+ saved: "About to edit message {id} in Saved Messages",
25633
+ bare: "About to edit message {id}"
25579
25634
  };
25580
25635
  var DELETE_HEADLINES = {
25581
- named: "About to delete message {id} from {chat}",
25582
- saved: "About to delete message {id} from Saved Messages"
25636
+ named: "About to delete message {id} from {chat} for everyone",
25637
+ saved: "About to delete message {id} from Saved Messages",
25638
+ bare: "About to delete message {id} for everyone"
25583
25639
  };
25584
25640
  var REACT_HEADLINES = {
25585
25641
  named: "About to react {emoji} to message {id} in {chat}",
25586
- saved: "About to react {emoji} to message {id} in Saved Messages"
25642
+ saved: "About to react {emoji} to message {id} in Saved Messages",
25643
+ bare: "About to react {emoji} to message {id}"
25587
25644
  };
25588
25645
  var UNREACT_HEADLINES = {
25589
25646
  named: "About to remove your reaction from message {id} in {chat}",
25590
- saved: "About to remove your reaction from message {id} in Saved Messages"
25647
+ saved: "About to remove your reaction from message {id} in Saved Messages",
25648
+ bare: "About to remove your reaction from message {id}"
25591
25649
  };
25592
25650
  var PIN_HEADLINES = {
25593
25651
  named: "About to pin message {id} in {chat}",
25594
- saved: "About to pin message {id} in Saved Messages"
25652
+ saved: "About to pin message {id} in Saved Messages",
25653
+ bare: "About to pin message {id}"
25595
25654
  };
25596
25655
  var UNPIN_HEADLINES = {
25597
25656
  named: "About to unpin message {id} in {chat}",
25598
- saved: "About to unpin message {id} in Saved Messages"
25657
+ saved: "About to unpin message {id} in Saved Messages",
25658
+ bare: "About to unpin message {id}"
25599
25659
  };
25600
25660
  var MARK_READ_HEADLINES = {
25601
25661
  named: "About to mark {chat} read up to message {id}",
25602
- saved: "About to mark Saved Messages read up to message {id}"
25662
+ saved: "About to mark Saved Messages read up to message {id}",
25663
+ bare: "About to mark messages read up to message {id}"
25603
25664
  };
25604
25665
  function actionHeadline(headlines, { kind, name }, id, values) {
25605
25666
  if (kind === "self") return { text: headlines.saved, values: { id: String(id), ...values } };
25606
- return name === null ? void 0 : { text: headlines.named, values: { id: String(id), chat: name, ...values } };
25667
+ return name === null ? { text: headlines.bare, values: { id: String(id), ...values } } : { text: headlines.named, values: { id: String(id), chat: name, ...values } };
25607
25668
  }
25608
25669
  function currentFacts({ body, media }) {
25609
- const shown = body || media?.type;
25610
- return shown ? [{ label: "Current", value: cut2(shown, MAX_VALUE_LENGTH) }] : [];
25670
+ if (body) return [{ label: "Current", value: cut2(body, MAX_VALUE_LENGTH) }];
25671
+ return media ? [{ label: "Media", value: mediaKindValue(media.type) }] : [];
25611
25672
  }
25612
25673
  function describeAction(headlines, chat, id, message2, extras = {}) {
25613
25674
  const headline = actionHeadline(headlines, chat, id, extras.values ?? {});
@@ -25843,7 +25904,7 @@ var telegramMessageDelete = defineTool({
25843
25904
  "A result means Telegram deleted the message for everyone. `already` means it was gone before this call.",
25844
25905
  "A failure `uncertain` means the delete may have gone through: check the chat in Telegram and never ask for it again without the user checking."
25845
25906
  ].join(" "),
25846
- intent: "About to delete a message",
25907
+ intent: "About to delete a message for everyone",
25847
25908
  toolset: "actions",
25848
25909
  class: "administrative",
25849
25910
  input: deleteInput,
@@ -25875,10 +25936,10 @@ var telegramMessageDelete = defineTool({
25875
25936
  });
25876
25937
 
25877
25938
  // src/core/message/edit-prepare.ts
25878
- function prepareEdit(mirror, chatId, id, text) {
25939
+ function prepareEdit(mirror, chatId, id, text2) {
25879
25940
  const { chat, message: message2 } = findOwnMessage(mirror, chatId, id, "edit");
25880
25941
  if (!message2) throw deletedMessage();
25881
- checkEditable({ ...message2, captioned: message2.media !== null && takesCaption(message2.media.type) }, text);
25942
+ checkEditable({ ...message2, captioned: message2.media !== null && takesCaption(message2.media.type) }, text2);
25882
25943
  return { chat, message: message2 };
25883
25944
  }
25884
25945
 
@@ -25901,22 +25962,22 @@ var telegramMessageEdit = defineTool({
25901
25962
  input: editInput,
25902
25963
  output: editOutput,
25903
25964
  async describe(args, ctx) {
25904
- const text = checkedText(args.text);
25965
+ const text2 = checkedText(args.text);
25905
25966
  const chat = requireChatId(args.chat, MESSAGE_EDIT_TOOL_ID);
25906
25967
  const paths = await pickPaths(ctx, args.account);
25907
- const target = readMirror(paths, (mirror) => prepareEdit(mirror, chat, args.id, text));
25968
+ const target = readMirror(paths, (mirror) => prepareEdit(mirror, chat, args.id, text2));
25908
25969
  return {
25909
25970
  ...describeAction(EDIT_HEADLINES, target.chat, args.id, target.message),
25910
- text: { label: "New text", body: text }
25971
+ text: { label: "New text", body: text2 }
25911
25972
  };
25912
25973
  },
25913
25974
  targets: (args, ctx) => actionTargets(MESSAGE_EDIT_TOOL_ID, args, ctx),
25914
25975
  async execute(args, ctx) {
25915
25976
  const chat = requireChatId(args.chat, MESSAGE_EDIT_TOOL_ID);
25916
- const text = checkedText(args.text);
25977
+ const text2 = checkedText(args.text);
25917
25978
  const paths = await pickPaths(ctx, args.account);
25918
- readMirror(paths, (mirror) => prepareEdit(mirror, chat, args.id, text));
25919
- const params = { chat, id: args.id, text };
25979
+ readMirror(paths, (mirror) => prepareEdit(mirror, chat, args.id, text2));
25980
+ const params = { chat, id: args.id, text: text2 };
25920
25981
  const edited = await callService(paths.socket, SERVICE_REQUESTS.edit, params, {
25921
25982
  effect: "write",
25922
25983
  signal: ctx.signal,
@@ -26112,7 +26173,7 @@ var telegramMessageSend = defineTool({
26112
26173
  input: input5,
26113
26174
  output: output5,
26114
26175
  async describe(args, ctx) {
26115
- const text = checkedText(args.text);
26176
+ const text2 = checkedText(args.text);
26116
26177
  const chat = requireChatId(args.chat, MESSAGE_SEND_TOOL_ID);
26117
26178
  const paths = await pickPaths(ctx, args.account);
26118
26179
  const { row, title } = readMirror(paths, (mirror) => {
@@ -26124,17 +26185,17 @@ var telegramMessageSend = defineTool({
26124
26185
  headline: { text: "About to send a message to {chat}", values: { chat: row.name } }
26125
26186
  },
26126
26187
  facts: [chatFact(row.kind), ...topicFacts(args.topic, title), ...replyFacts(args.reply_to)],
26127
- text: { label: "Message text", body: text }
26188
+ text: { label: "Message text", body: text2 }
26128
26189
  };
26129
26190
  },
26130
26191
  targets: (args, ctx) => chatTargets(MESSAGE_SEND_TOOL_ID, args, ctx),
26131
26192
  async execute(args, ctx) {
26132
26193
  const chat = requireChatId(args.chat, MESSAGE_SEND_TOOL_ID);
26133
- const text = checkedText(args.text);
26194
+ const text2 = checkedText(args.text);
26134
26195
  const paths = await pickPaths(ctx, args.account);
26135
26196
  const params = {
26136
26197
  chat,
26137
- text,
26198
+ text: text2,
26138
26199
  ...args.topic !== void 0 && { topic: args.topic },
26139
26200
  ...args.reply_to !== void 0 && { reply_to: args.reply_to }
26140
26201
  };
@@ -26147,7 +26208,7 @@ var telegramMessageSend = defineTool({
26147
26208
  });
26148
26209
  return sendResult(chat, sent);
26149
26210
  } catch (error62) {
26150
- throw isToolError(error62) && error62.code === "uncertain" ? withSentLike(error62, paths, chat, text, startedAt) : error62;
26211
+ throw isToolError(error62) && error62.code === "uncertain" ? withSentLike(error62, paths, chat, text2, startedAt) : error62;
26151
26212
  }
26152
26213
  }
26153
26214
  });
@@ -26449,12 +26510,6 @@ var FILE_TRANSLATIONS = {
26449
26510
  "About to save a file from {chat}": "{chat} \u306E\u30D5\u30A1\u30A4\u30EB\u3092\u4FDD\u5B58\u3057\u3088\u3046\u3068\u3057\u3066\u3044\u307E\u3059",
26450
26511
  "About to save {file}": "{file} \u3092\u4FDD\u5B58\u3057\u3088\u3046\u3068\u3057\u3066\u3044\u307E\u3059",
26451
26512
  File: "\u30D5\u30A1\u30A4\u30EB",
26452
- Photo: "\u5199\u771F",
26453
- Document: "\u30C9\u30AD\u30E5\u30E1\u30F3\u30C8",
26454
- Audio: "\u97F3\u58F0",
26455
- "Voice message": "\u30DC\u30A4\u30B9\u30E1\u30C3\u30BB\u30FC\u30B8",
26456
- Video: "\u52D5\u753B",
26457
- Sticker: "\u30B9\u30BF\u30F3\u30D7",
26458
26513
  Unpack: "\u5C55\u958B",
26459
26514
  Yes: "\u3059\u308B"
26460
26515
  }
@@ -26469,24 +26524,31 @@ var ACTION_TRANSLATIONS = {
26469
26524
  "Pin or unpin a message": "\u30E1\u30C3\u30BB\u30FC\u30B8\u3092\u30D4\u30F3\u7559\u3081\u3059\u308B\u30FB\u89E3\u9664\u3059\u308B",
26470
26525
  "Mark a chat read": "\u30C1\u30E3\u30C3\u30C8\u3092\u65E2\u8AAD\u306B\u3059\u308B",
26471
26526
  "About to edit a message": "\u30E1\u30C3\u30BB\u30FC\u30B8\u3092\u7DE8\u96C6\u3057\u3088\u3046\u3068\u3057\u3066\u3044\u307E\u3059",
26472
- "About to delete a message": "\u30E1\u30C3\u30BB\u30FC\u30B8\u3092\u524A\u9664\u3057\u3088\u3046\u3068\u3057\u3066\u3044\u307E\u3059",
26527
+ "About to delete a message for everyone": "\u30E1\u30C3\u30BB\u30FC\u30B8\u3092\u5168\u54E1\u5206\u524A\u9664\u3057\u3088\u3046\u3068\u3057\u3066\u3044\u307E\u3059",
26473
26528
  "About to change a reaction": "\u30EA\u30A2\u30AF\u30B7\u30E7\u30F3\u3092\u5909\u66F4\u3057\u3088\u3046\u3068\u3057\u3066\u3044\u307E\u3059",
26474
26529
  "About to pin or unpin a message": "\u30E1\u30C3\u30BB\u30FC\u30B8\u306E\u30D4\u30F3\u7559\u3081\u3092\u5909\u66F4\u3057\u3088\u3046\u3068\u3057\u3066\u3044\u307E\u3059",
26475
26530
  "About to mark messages read": "\u30E1\u30C3\u30BB\u30FC\u30B8\u3092\u65E2\u8AAD\u306B\u3057\u3088\u3046\u3068\u3057\u3066\u3044\u307E\u3059",
26476
26531
  "About to edit message {id} in {chat}": "{chat} \u306E\u30E1\u30C3\u30BB\u30FC\u30B8 {id} \u3092\u7DE8\u96C6\u3057\u3088\u3046\u3068\u3057\u3066\u3044\u307E\u3059",
26477
- "About to edit message {id} in Saved Messages": "\u4FDD\u5B58\u6E08\u307F\u30E1\u30C3\u30BB\u30FC\u30B8\u306E\u30E1\u30C3\u30BB\u30FC\u30B8 {id} \u3092\u7DE8\u96C6\u3057\u3088\u3046\u3068\u3057\u3066\u3044\u307E\u3059",
26478
- "About to delete message {id} from {chat}": "{chat} \u306E\u30E1\u30C3\u30BB\u30FC\u30B8 {id} \u3092\u524A\u9664\u3057\u3088\u3046\u3068\u3057\u3066\u3044\u307E\u3059",
26479
- "About to delete message {id} from Saved Messages": "\u4FDD\u5B58\u6E08\u307F\u30E1\u30C3\u30BB\u30FC\u30B8\u306E\u30E1\u30C3\u30BB\u30FC\u30B8 {id} \u3092\u524A\u9664\u3057\u3088\u3046\u3068\u3057\u3066\u3044\u307E\u3059",
26532
+ "About to edit message {id} in Saved Messages": "\u4FDD\u5B58\u6E08\u307F\u30E1\u30C3\u30BB\u30FC\u30B8\u306B\u3042\u308B\u30E1\u30C3\u30BB\u30FC\u30B8 {id} \u3092\u7DE8\u96C6\u3057\u3088\u3046\u3068\u3057\u3066\u3044\u307E\u3059",
26533
+ "About to edit message {id}": "\u30E1\u30C3\u30BB\u30FC\u30B8 {id} \u3092\u7DE8\u96C6\u3057\u3088\u3046\u3068\u3057\u3066\u3044\u307E\u3059",
26534
+ "About to delete message {id} from {chat} for everyone": "{chat} \u306E\u30E1\u30C3\u30BB\u30FC\u30B8 {id} \u3092\u5168\u54E1\u5206\u524A\u9664\u3057\u3088\u3046\u3068\u3057\u3066\u3044\u307E\u3059",
26535
+ "About to delete message {id} from Saved Messages": "\u4FDD\u5B58\u6E08\u307F\u30E1\u30C3\u30BB\u30FC\u30B8\u306B\u3042\u308B\u30E1\u30C3\u30BB\u30FC\u30B8 {id} \u3092\u524A\u9664\u3057\u3088\u3046\u3068\u3057\u3066\u3044\u307E\u3059",
26536
+ "About to delete message {id} for everyone": "\u30E1\u30C3\u30BB\u30FC\u30B8 {id} \u3092\u5168\u54E1\u5206\u524A\u9664\u3057\u3088\u3046\u3068\u3057\u3066\u3044\u307E\u3059",
26480
26537
  "About to react {emoji} to message {id} in {chat}": "{chat} \u306E\u30E1\u30C3\u30BB\u30FC\u30B8 {id} \u306B {emoji} \u306E\u30EA\u30A2\u30AF\u30B7\u30E7\u30F3\u3092\u4ED8\u3051\u3088\u3046\u3068\u3057\u3066\u3044\u307E\u3059",
26481
- "About to react {emoji} to message {id} in Saved Messages": "\u4FDD\u5B58\u6E08\u307F\u30E1\u30C3\u30BB\u30FC\u30B8\u306E\u30E1\u30C3\u30BB\u30FC\u30B8 {id} \u306B {emoji} \u306E\u30EA\u30A2\u30AF\u30B7\u30E7\u30F3\u3092\u4ED8\u3051\u3088\u3046\u3068\u3057\u3066\u3044\u307E\u3059",
26538
+ "About to react {emoji} to message {id} in Saved Messages": "\u4FDD\u5B58\u6E08\u307F\u30E1\u30C3\u30BB\u30FC\u30B8\u306B\u3042\u308B\u30E1\u30C3\u30BB\u30FC\u30B8 {id} \u306B {emoji} \u306E\u30EA\u30A2\u30AF\u30B7\u30E7\u30F3\u3092\u4ED8\u3051\u3088\u3046\u3068\u3057\u3066\u3044\u307E\u3059",
26539
+ "About to react {emoji} to message {id}": "\u30E1\u30C3\u30BB\u30FC\u30B8 {id} \u306B {emoji} \u306E\u30EA\u30A2\u30AF\u30B7\u30E7\u30F3\u3092\u4ED8\u3051\u3088\u3046\u3068\u3057\u3066\u3044\u307E\u3059",
26482
26540
  "About to remove your reaction from message {id} in {chat}": "{chat} \u306E\u30E1\u30C3\u30BB\u30FC\u30B8 {id} \u304B\u3089\u81EA\u5206\u306E\u30EA\u30A2\u30AF\u30B7\u30E7\u30F3\u3092\u5916\u305D\u3046\u3068\u3057\u3066\u3044\u307E\u3059",
26483
- "About to remove your reaction from message {id} in Saved Messages": "\u4FDD\u5B58\u6E08\u307F\u30E1\u30C3\u30BB\u30FC\u30B8\u306E\u30E1\u30C3\u30BB\u30FC\u30B8 {id} \u304B\u3089\u81EA\u5206\u306E\u30EA\u30A2\u30AF\u30B7\u30E7\u30F3\u3092\u5916\u305D\u3046\u3068\u3057\u3066\u3044\u307E\u3059",
26541
+ "About to remove your reaction from message {id} in Saved Messages": "\u4FDD\u5B58\u6E08\u307F\u30E1\u30C3\u30BB\u30FC\u30B8\u306B\u3042\u308B\u30E1\u30C3\u30BB\u30FC\u30B8 {id} \u304B\u3089\u81EA\u5206\u306E\u30EA\u30A2\u30AF\u30B7\u30E7\u30F3\u3092\u5916\u305D\u3046\u3068\u3057\u3066\u3044\u307E\u3059",
26542
+ "About to remove your reaction from message {id}": "\u30E1\u30C3\u30BB\u30FC\u30B8 {id} \u304B\u3089\u81EA\u5206\u306E\u30EA\u30A2\u30AF\u30B7\u30E7\u30F3\u3092\u5916\u305D\u3046\u3068\u3057\u3066\u3044\u307E\u3059",
26484
26543
  "About to pin message {id} in {chat}": "{chat} \u306E\u30E1\u30C3\u30BB\u30FC\u30B8 {id} \u3092\u30D4\u30F3\u7559\u3081\u3057\u3088\u3046\u3068\u3057\u3066\u3044\u307E\u3059",
26485
- "About to pin message {id} in Saved Messages": "\u4FDD\u5B58\u6E08\u307F\u30E1\u30C3\u30BB\u30FC\u30B8\u306E\u30E1\u30C3\u30BB\u30FC\u30B8 {id} \u3092\u30D4\u30F3\u7559\u3081\u3057\u3088\u3046\u3068\u3057\u3066\u3044\u307E\u3059",
26544
+ "About to pin message {id} in Saved Messages": "\u4FDD\u5B58\u6E08\u307F\u30E1\u30C3\u30BB\u30FC\u30B8\u306B\u3042\u308B\u30E1\u30C3\u30BB\u30FC\u30B8 {id} \u3092\u30D4\u30F3\u7559\u3081\u3057\u3088\u3046\u3068\u3057\u3066\u3044\u307E\u3059",
26545
+ "About to pin message {id}": "\u30E1\u30C3\u30BB\u30FC\u30B8 {id} \u3092\u30D4\u30F3\u7559\u3081\u3057\u3088\u3046\u3068\u3057\u3066\u3044\u307E\u3059",
26486
26546
  "About to unpin message {id} in {chat}": "{chat} \u306E\u30E1\u30C3\u30BB\u30FC\u30B8 {id} \u306E\u30D4\u30F3\u7559\u3081\u3092\u89E3\u9664\u3057\u3088\u3046\u3068\u3057\u3066\u3044\u307E\u3059",
26487
- "About to unpin message {id} in Saved Messages": "\u4FDD\u5B58\u6E08\u307F\u30E1\u30C3\u30BB\u30FC\u30B8\u306E\u30E1\u30C3\u30BB\u30FC\u30B8 {id} \u306E\u30D4\u30F3\u7559\u3081\u3092\u89E3\u9664\u3057\u3088\u3046\u3068\u3057\u3066\u3044\u307E\u3059",
26547
+ "About to unpin message {id} in Saved Messages": "\u4FDD\u5B58\u6E08\u307F\u30E1\u30C3\u30BB\u30FC\u30B8\u306B\u3042\u308B\u30E1\u30C3\u30BB\u30FC\u30B8 {id} \u306E\u30D4\u30F3\u7559\u3081\u3092\u89E3\u9664\u3057\u3088\u3046\u3068\u3057\u3066\u3044\u307E\u3059",
26548
+ "About to unpin message {id}": "\u30E1\u30C3\u30BB\u30FC\u30B8 {id} \u306E\u30D4\u30F3\u7559\u3081\u3092\u89E3\u9664\u3057\u3088\u3046\u3068\u3057\u3066\u3044\u307E\u3059",
26488
26549
  "About to mark {chat} read up to message {id}": "{chat} \u3092\u30E1\u30C3\u30BB\u30FC\u30B8 {id} \u307E\u3067\u65E2\u8AAD\u306B\u3057\u3088\u3046\u3068\u3057\u3066\u3044\u307E\u3059",
26489
26550
  "About to mark Saved Messages read up to message {id}": "\u4FDD\u5B58\u6E08\u307F\u30E1\u30C3\u30BB\u30FC\u30B8\u3092\u30E1\u30C3\u30BB\u30FC\u30B8 {id} \u307E\u3067\u65E2\u8AAD\u306B\u3057\u3088\u3046\u3068\u3057\u3066\u3044\u307E\u3059",
26551
+ "About to mark messages read up to message {id}": "\u30E1\u30C3\u30BB\u30FC\u30B8 {id} \u307E\u3067\u65E2\u8AAD\u306B\u3057\u3088\u3046\u3068\u3057\u3066\u3044\u307E\u3059",
26490
26552
  Message: "\u30E1\u30C3\u30BB\u30FC\u30B8",
26491
26553
  Current: "\u73FE\u5728\u306E\u5185\u5BB9",
26492
26554
  Replaces: "\u7F6E\u304D\u63DB\u3048\u308B\u30EA\u30A2\u30AF\u30B7\u30E7\u30F3",
@@ -26530,6 +26592,7 @@ var SYNC_TRANSLATIONS = {
26530
26592
  var ALL_TRANSLATIONS = mergeTranslations(
26531
26593
  FACT_TRANSLATIONS,
26532
26594
  CHAT_FACT_TRANSLATIONS,
26595
+ MEDIA_FACT_TRANSLATIONS,
26533
26596
  MESSAGE_TRANSLATIONS,
26534
26597
  ACTION_TRANSLATIONS,
26535
26598
  FILE_TRANSLATIONS,
@@ -26537,6 +26600,35 @@ var ALL_TRANSLATIONS = mergeTranslations(
26537
26600
  SYNC_TRANSLATIONS
26538
26601
  );
26539
26602
 
26603
+ // src/entry/directory.ts
26604
+ import { homedir as homedir3 } from "node:os";
26605
+ import { isAbsolute as isAbsolute5, resolve as resolve4 } from "node:path";
26606
+ var DOWNLOADS_DIR = "Downloads";
26607
+ var DEFAULT_DOWNLOAD_MAX_MB = 100;
26608
+ function homeDir(env) {
26609
+ const envHome = env.HOME;
26610
+ if (envHome && isAbsolute5(envHome)) return envHome;
26611
+ return homedir3();
26612
+ }
26613
+ function defaultStateDir(name, env, home) {
26614
+ const xdg = env.XDG_STATE_HOME;
26615
+ return xdg && isAbsolute5(xdg) ? resolve4(xdg, name) : resolve4(home, ".local", "state", name);
26616
+ }
26617
+ function text(value) {
26618
+ return typeof value === "string" ? value : void 0;
26619
+ }
26620
+ function resolveDirectorySettings(options, env, profile) {
26621
+ const home = homeDir(env);
26622
+ const maxMb = options.download_max_mb;
26623
+ const sendDirs = options.send_dirs;
26624
+ return {
26625
+ state_dir: text(options.state_dir) ?? defaultStateDir(profile.name, env, home),
26626
+ download_dir: text(options.download_dir) ?? resolve4(home, DOWNLOADS_DIR, profile.name),
26627
+ download_max_mb: typeof maxMb === "number" ? maxMb : DEFAULT_DOWNLOAD_MAX_MB,
26628
+ send_dirs: Array.isArray(sendDirs) ? [...sendDirs] : []
26629
+ };
26630
+ }
26631
+
26540
26632
  // src/entry/errors.ts
26541
26633
  function errorBody(code, message2, details) {
26542
26634
  return { code, message: message2, ...details !== void 0 && { details } };
@@ -26556,9 +26648,9 @@ function mark(character) {
26556
26648
  const hex3 = character.codePointAt(0).toString(16).toUpperCase();
26557
26649
  return `<U+${hex3.padStart(MARK_DIGITS, "0")}>`;
26558
26650
  }
26559
- function visible(text, options = {}) {
26560
- if (options.keepNewlines) return text.replace(/\r\n/g, "\n").replace(HIDDEN_EXCEPT_NEWLINE, mark);
26561
- return text.replace(HIDDEN_ALL, mark);
26651
+ function visible(text2, options = {}) {
26652
+ if (options.keepNewlines) return text2.replace(/\r\n/g, "\n").replace(HIDDEN_EXCEPT_NEWLINE, mark);
26653
+ return text2.replace(HIDDEN_ALL, mark);
26562
26654
  }
26563
26655
 
26564
26656
  // src/entry/words.ts
@@ -26597,12 +26689,12 @@ var omittedOf = (count) => count > 0 ? { omitted: count } : {};
26597
26689
  function quoted(value) {
26598
26690
  return `"${visible(value).replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
26599
26691
  }
26600
- function filled(text, literal2, slot) {
26601
- return text.split(HEADLINE_PLACEHOLDER).map((part, index) => index % 2 === 0 ? literal2(part) : slot(part)).join("");
26692
+ function filled(text2, literal2, slot) {
26693
+ return text2.split(HEADLINE_PLACEHOLDER).map((part, index) => index % 2 === 0 ? literal2(part) : slot(part)).join("");
26602
26694
  }
26603
- function renderedHeadline({ text, values = {} }) {
26695
+ function renderedHeadline({ text: text2, values = {} }) {
26604
26696
  return filled(
26605
- text,
26697
+ text2,
26606
26698
  (part) => visible(part),
26607
26699
  (name) => quoted(values[name] ?? "")
26608
26700
  );
@@ -26616,7 +26708,7 @@ function renderedValue(value, t) {
26616
26708
  return { value: visible(cut2(whole, MAX_VALUE_LENGTH)), ...omittedOf(omittedBy(whole, MAX_VALUE_LENGTH)) };
26617
26709
  }
26618
26710
  function shownDescription(description, t) {
26619
- const { headline, facts, text } = cutDescription(description);
26711
+ const { headline, facts, text: text2 } = cutDescription(description);
26620
26712
  const wholeBody = description.text?.body ?? "";
26621
26713
  const dropped = description.facts.length - facts.length;
26622
26714
  return {
@@ -26626,9 +26718,9 @@ function shownDescription(description, t) {
26626
26718
  ...renderedValue(description.facts[index].value, t)
26627
26719
  })),
26628
26720
  ...dropped > 0 && { dropped },
26629
- ...text && {
26721
+ ...text2 && {
26630
26722
  text: {
26631
- label: visible(t.word(text.label, MAX_TEXT_LABEL_LENGTH)),
26723
+ label: visible(t.word(text2.label, MAX_TEXT_LABEL_LENGTH)),
26632
26724
  body: visible(cut2(wholeBody, MAX_TEXT_LENGTH), { keepNewlines: true }),
26633
26725
  ...omittedOf(omittedBy(wholeBody, MAX_TEXT_LENGTH))
26634
26726
  }
@@ -26642,9 +26734,9 @@ async function timedCallDescription(spec, args, ctx, timeoutMs = DESCRIBE_TIMEOU
26642
26734
  let timer;
26643
26735
  let onAbort2;
26644
26736
  try {
26645
- const timedOut = new Promise((resolve8) => {
26737
+ const timedOut = new Promise((resolve6) => {
26646
26738
  timer = setTimeout(() => {
26647
- resolve8(void 0);
26739
+ resolve6(void 0);
26648
26740
  controller.abort();
26649
26741
  }, timeoutMs);
26650
26742
  });
@@ -26694,81 +26786,44 @@ async function checkPin(spec, args, ctx, pin, timeoutMs = DESCRIBE_TIMEOUT_MS) {
26694
26786
  var PROJECT_PROFILE = {
26695
26787
  name: PROJECT.name,
26696
26788
  envPrefix: PROJECT.envPrefix,
26697
- toolsets: { names: PROJECT.toolsets, defaults: PROJECT.defaultToolsets }
26789
+ toolsets: { names: PROJECT.toolsets, defaults: PROJECT.defaultToolsets },
26790
+ options: PROJECT.options
26698
26791
  };
26699
26792
 
26700
- // src/entry/download-dir.ts
26701
- import { resolve as resolve5 } from "node:path";
26702
-
26703
- // src/entry/directory.ts
26704
- import { homedir as homedir3 } from "node:os";
26705
- import { isAbsolute as isAbsolute5, join as join11, resolve as resolve4, sep as sep4 } from "node:path";
26706
- function homeDir(env) {
26707
- const envHome = env.HOME;
26708
- if (envHome && isAbsolute5(envHome)) return envHome;
26709
- return homedir3();
26710
- }
26711
- function resolveGivenDirectory(given, home) {
26712
- const text = given.text.trim();
26713
- const expanded = text === "~" ? home : text.startsWith("~/") || text.startsWith(`~${sep4}`) ? join11(home, text.slice(2)) : text;
26714
- if (!text || !isAbsolute5(expanded)) {
26715
- throw new ToolError("invalid_argument", `${given.source} must be an absolute path.`);
26716
- }
26717
- return resolve4(expanded);
26718
- }
26719
-
26720
- // src/entry/download-dir.ts
26721
- var DOWNLOADS_DIR = "Downloads";
26722
- function resolveDownloadDir(given, env, profile) {
26723
- const home = homeDir(env);
26724
- return given !== void 0 ? resolveGivenDirectory(given, home) : resolve5(home, DOWNLOADS_DIR, profile.name);
26725
- }
26726
-
26727
- // src/entry/send-dirs.ts
26728
- function resolveSendDirs(given, env) {
26729
- const home = homeDir(env);
26730
- return given.map((directory) => resolveGivenDirectory(directory, home));
26731
- }
26732
-
26733
- // src/entry/state-dir.ts
26734
- import { isAbsolute as isAbsolute6, resolve as resolve6 } from "node:path";
26735
- function resolveStateDir(given, env, profile) {
26736
- const home = homeDir(env);
26737
- if (given !== void 0) return resolveGivenDirectory(given, home);
26738
- const xdg = env.XDG_STATE_HOME;
26739
- if (xdg && isAbsolute6(xdg)) {
26740
- return resolve6(xdg, profile.name);
26741
- }
26742
- return resolve6(home, ".local", "state", profile.name);
26743
- }
26744
-
26745
26793
  // src/entry/settings.ts
26794
+ import { homedir as homedir4 } from "node:os";
26795
+ import { isAbsolute as isAbsolute6, join as join11, resolve as resolvePath, sep as sep4 } from "node:path";
26746
26796
  var CONFIRM_MODES = ["harness", "elicitation"];
26747
26797
  var ALL_TOOLSETS = "all";
26748
26798
  var TRUE_VALUES = ["1", "true"];
26749
26799
  var FALSE_VALUES = ["0", "false"];
26750
- var DEFAULT_DOWNLOAD_MAX_MB = 100;
26751
- var MAX_DOWNLOAD_MB = 2e3;
26752
26800
  var OPTIONS = {
26753
26801
  toolsets: { flag: "--toolsets", envSuffix: "TOOLSETS" },
26754
26802
  read_only: { flag: "--read-only", envSuffix: "READ_ONLY", boolean: true },
26755
26803
  tools: { flag: "--tools", envSuffix: "TOOLS" },
26756
26804
  exclude_tools: { flag: "--exclude-tools", envSuffix: "EXCLUDE_TOOLS" },
26757
- confirm: { flag: "--confirm", envSuffix: "CONFIRM" },
26758
- state_dir: { flag: "--state-dir", envSuffix: "STATE_DIR" },
26759
- download_dir: { flag: "--download-dir", envSuffix: "DOWNLOAD_DIR" },
26760
- download_max_mb: { flag: "--download-max-mb", envSuffix: "DOWNLOAD_MAX_MB" },
26761
- send_dirs: { flag: "--send-dirs", envSuffix: "SEND_DIRS" },
26762
- keep_disappearing: { flag: "--keep-disappearing", envSuffix: "KEEP_DISAPPEARING", boolean: true },
26763
- channels: { flag: "--channels", envSuffix: "CHANNELS", boolean: true }
26764
- };
26765
- var SERVICE_OPTION_NAMES = ["keep_disappearing", "channels"];
26805
+ confirm: { flag: "--confirm", envSuffix: "CONFIRM" }
26806
+ };
26807
+ function profileOptions(profile) {
26808
+ return profile.options ?? {};
26809
+ }
26810
+ function settingOptions(profile) {
26811
+ const toolOptions = Object.entries(profileOptions(profile)).map(([name, spec]) => [
26812
+ name,
26813
+ {
26814
+ flag: `--${name.replace(/_/g, "-")}`,
26815
+ envSuffix: name.toUpperCase(),
26816
+ ...optionType(spec) === "boolean" && { boolean: true }
26817
+ }
26818
+ ]);
26819
+ return { ...OPTIONS, ...Object.fromEntries(toolOptions) };
26820
+ }
26766
26821
  function envName(name, profile) {
26767
- return `${profile.envPrefix}_${OPTIONS[name].envSuffix}`;
26822
+ return `${profile.envPrefix}_${settingOptions(profile)[name].envSuffix}`;
26768
26823
  }
26769
- function readFlags(argv) {
26824
+ function readFlags(argv, profile) {
26770
26825
  const byFlag = new Map(
26771
- Object.keys(OPTIONS).map((name) => [OPTIONS[name].flag, { name, ...OPTIONS[name] }])
26826
+ Object.entries(settingOptions(profile)).map(([name, option]) => [option.flag, { name, ...option }])
26772
26827
  );
26773
26828
  const given = {};
26774
26829
  for (let i = 0; i < argv.length; i++) {
@@ -26803,9 +26858,9 @@ function checkToolsets(names, source, toolsets) {
26803
26858
  return names.length ? names : void 0;
26804
26859
  }
26805
26860
  function parseBoolean(value, source) {
26806
- const text = value.trim().toLowerCase();
26807
- if (TRUE_VALUES.includes(text)) return true;
26808
- if (FALSE_VALUES.includes(text)) return false;
26861
+ const text2 = value.trim().toLowerCase();
26862
+ if (TRUE_VALUES.includes(text2)) return true;
26863
+ if (FALSE_VALUES.includes(text2)) return false;
26809
26864
  throw new ToolError(
26810
26865
  "invalid_argument",
26811
26866
  `Unknown value "${value}" in ${source}; use one of ${[...TRUE_VALUES, ...FALSE_VALUES].join(", ")}.`
@@ -26821,44 +26876,115 @@ function parseConfirm(value, source) {
26821
26876
  }
26822
26877
  return mode;
26823
26878
  }
26824
- function listedDirectories(given) {
26825
- return given === void 0 ? [] : splitList(given.text).map((text) => ({ text, source: given.source }));
26826
- }
26827
- function downloadMaxMb(value, source) {
26828
- if (typeof value !== "number" || !Number.isInteger(value) || value < 1 || value > MAX_DOWNLOAD_MB) {
26829
- throw new ToolError("invalid_argument", `${source} must be an integer from 1 to ${MAX_DOWNLOAD_MB}.`);
26879
+ function parseNumber2(value, source) {
26880
+ const trimmed = value.trim();
26881
+ const parsed = trimmed === "" ? Number.NaN : Number(trimmed);
26882
+ if (!Number.isFinite(parsed)) {
26883
+ throw new ToolError("invalid_argument", `Unknown number "${value}" in ${source}; use a finite number.`);
26830
26884
  }
26831
- return value;
26885
+ return parsed;
26832
26886
  }
26833
- function downloadMaxMbText({ text, source }) {
26834
- const trimmed = text.trim();
26835
- return downloadMaxMb(/^\d+$/.test(trimmed) ? Number(trimmed) : Number.NaN, source);
26887
+ function absolutePath(text2, source, env) {
26888
+ const home = env.HOME !== void 0 && isAbsolute6(env.HOME) ? env.HOME : homedir4();
26889
+ const expanded = text2 === "~" || text2.startsWith("~/") || text2.startsWith(`~${sep4}`) ? join11(home, text2.slice(1)) : text2;
26890
+ if (!isAbsolute6(expanded)) throw new ToolError("invalid_argument", `${source} must be an absolute path.`);
26891
+ return resolvePath(expanded);
26836
26892
  }
26837
- function downloadSettings(given, env, profile) {
26838
- const value = given ?? ((name) => envText(name, env, profile));
26839
- const max3 = value("download_max_mb");
26840
- return {
26841
- download_dir: resolveDownloadDir(value("download_dir"), env, profile),
26842
- download_max_mb: max3 === void 0 ? DEFAULT_DOWNLOAD_MAX_MB : downloadMaxMbText(max3)
26843
- };
26893
+ function absolutePaths(items, source, env) {
26894
+ return items.length > 0 ? items.map((item) => absolutePath(item, source, env)) : void 0;
26844
26895
  }
26845
26896
  function envText(name, env, profile) {
26846
26897
  const variable = envName(name, profile);
26847
- const text = env[variable];
26848
- return text === void 0 || text.trim() === "" ? void 0 : { text, source: variable };
26898
+ const text2 = env[variable];
26899
+ return text2 === void 0 || text2.trim() === "" ? void 0 : { text: text2, source: variable };
26849
26900
  }
26850
26901
  function flagOrEnvText(flags, name, env, profile) {
26851
26902
  const flagged = flags[name];
26852
26903
  return flagged !== void 0 ? { text: flagged, source: OPTIONS[name].flag } : envText(name, env, profile);
26853
26904
  }
26905
+ function optionType(spec) {
26906
+ return typeof spec === "string" ? spec : spec.type;
26907
+ }
26908
+ function itemCount(count) {
26909
+ return count === 1 ? "1 item" : `${count} items`;
26910
+ }
26911
+ function numberBoundsError({ integer: integer2, min: min3, max: max3 }, source) {
26912
+ const range = min3 !== void 0 && max3 !== void 0 ? ` from ${min3} to ${max3}` : min3 !== void 0 ? ` of at least ${min3}` : max3 !== void 0 ? ` of at most ${max3}` : "";
26913
+ return new ToolError("invalid_argument", `${source} must be ${integer2 ? "a whole number" : "a number"}${range}.`);
26914
+ }
26915
+ function countBoundsError({ min: min3, max: max3 }, source) {
26916
+ const range = min3 !== void 0 && max3 !== void 0 ? `from ${min3} to ${max3} items` : min3 !== void 0 ? `at least ${itemCount(min3)}` : `at most ${itemCount(max3)}`;
26917
+ return new ToolError("invalid_argument", `${source} must list ${range}.`);
26918
+ }
26919
+ function withinBounds(spec, value, source) {
26920
+ if (value === void 0 || typeof spec === "string") return value;
26921
+ const bounds = spec;
26922
+ const { integer: integer2, min: min3, max: max3 } = bounds;
26923
+ if (typeof value === "number") {
26924
+ if (integer2 && !Number.isInteger(value) || min3 !== void 0 && value < min3 || max3 !== void 0 && value > max3) {
26925
+ throw numberBoundsError(bounds, source);
26926
+ }
26927
+ } else if (typeof value === "object" && (min3 !== void 0 && value.length < min3 || max3 !== void 0 && value.length > max3)) {
26928
+ throw countBoundsError(bounds, source);
26929
+ }
26930
+ return value;
26931
+ }
26932
+ function parseOptionText(spec, given, env) {
26933
+ return withinBounds(spec, parseTypedText(optionType(spec), given, env), given.source);
26934
+ }
26935
+ function parseTypedText(kind, given, env) {
26936
+ switch (kind) {
26937
+ case "text":
26938
+ return nonBlank(given.text);
26939
+ case "boolean":
26940
+ return parseBoolean(given.text, given.source);
26941
+ case "number":
26942
+ return parseNumber2(given.text, given.source);
26943
+ case "list": {
26944
+ const items = splitList(given.text);
26945
+ return items.length > 0 ? items : void 0;
26946
+ }
26947
+ case "path": {
26948
+ const text2 = nonBlank(given.text);
26949
+ return text2 === void 0 ? void 0 : absolutePath(text2, given.source, env);
26950
+ }
26951
+ case "paths":
26952
+ return absolutePaths(splitList(given.text), given.source, env);
26953
+ }
26954
+ }
26955
+ function optionsFrom(flags, env, profile) {
26956
+ const options = {};
26957
+ for (const [name, spec] of Object.entries(profileOptions(profile))) {
26958
+ if (flags[name] !== void 0) {
26959
+ const parsed = parseOptionText(spec, { text: flags[name], source: settingOptions(profile)[name].flag }, env);
26960
+ if (parsed !== void 0) options[name] = parsed;
26961
+ continue;
26962
+ }
26963
+ const fromEnv = envText(name, env, profile);
26964
+ if (fromEnv !== void 0) {
26965
+ const parsed = parseOptionText(spec, fromEnv, env);
26966
+ if (parsed !== void 0) options[name] = parsed;
26967
+ }
26968
+ }
26969
+ return options;
26970
+ }
26971
+ function parseToolOptions(argv, env, profile = PROJECT_PROFILE) {
26972
+ const flags = readFlags(argv, profile);
26973
+ const known = profileOptions(profile);
26974
+ const other = Object.keys(flags).find((name) => !(name in known));
26975
+ if (other !== void 0) {
26976
+ throw new ToolError("invalid_argument", `Unknown option "${settingOptions(profile)[other].flag}".`);
26977
+ }
26978
+ return optionsFrom(flags, env, profile);
26979
+ }
26854
26980
  function parseSettings(argv, env, profile = PROJECT_PROFILE) {
26855
- const flags = readFlags(argv);
26981
+ const flags = readFlags(argv, profile);
26856
26982
  const value = (name) => flagOrEnvText(flags, name, env, profile);
26983
+ const options = optionsFrom(flags, env, profile);
26857
26984
  const settings = {
26858
26985
  confirm: "harness",
26859
- state_dir: resolveStateDir(value("state_dir"), env, profile),
26860
- ...downloadSettings(value, env, profile),
26861
- send_dirs: resolveSendDirs(listedDirectories(value("send_dirs")), env)
26986
+ options,
26987
+ ...resolveDirectorySettings(options, env, profile)
26862
26988
  };
26863
26989
  const toolsets = value("toolsets");
26864
26990
  if (toolsets) settings.toolsets = checkToolsets(splitList(toolsets.text), toolsets.source, profile.toolsets);
@@ -26870,10 +26996,6 @@ function parseSettings(argv, env, profile = PROJECT_PROFILE) {
26870
26996
  if (excluded) settings.exclude_tools = splitList(excluded.text);
26871
26997
  const confirm = value("confirm");
26872
26998
  if (confirm) settings.confirm = parseConfirm(confirm.text.trim(), confirm.source);
26873
- for (const name of SERVICE_OPTION_NAMES) {
26874
- const given = value(name);
26875
- if (given) settings[name] = parseBoolean(given.text, given.source);
26876
- }
26877
26999
  return settings;
26878
27000
  }
26879
27001
  function parseToolSettings(argv, env, profile = PROJECT_PROFILE) {
@@ -26888,48 +27010,11 @@ function parseToolSettings(argv, env, profile = PROJECT_PROFILE) {
26888
27010
  );
26889
27011
  return settings;
26890
27012
  }
26891
- function parseStateDir(argv, env, profile = PROJECT_PROFILE) {
26892
- const flags = readFlags(argv);
26893
- const other = Object.keys(flags).find((name) => name !== "state_dir");
26894
- if (other !== void 0)
26895
- throw new ToolError("invalid_argument", `Option ${OPTIONS[other].flag} is not available here.`);
26896
- return resolveStateDir(flagOrEnvText(flags, "state_dir", env, profile), env, profile);
26897
- }
26898
- function parseServiceSettings(argv, env, profile = PROJECT_PROFILE) {
26899
- const flags = readFlags(argv);
26900
- const allowed = ["state_dir", ...SERVICE_OPTION_NAMES];
26901
- const other = Object.keys(flags).find((name) => !allowed.includes(name));
26902
- if (other !== void 0)
26903
- throw new ToolError("invalid_argument", `Option ${OPTIONS[other].flag} is not available here.`);
26904
- const value = (name) => flagOrEnvText(flags, name, env, profile);
26905
- const on = (name) => {
26906
- const given = value(name);
26907
- return given !== void 0 && parseBoolean(given.text, given.source);
26908
- };
26909
- return {
26910
- state_dir: resolveStateDir(value("state_dir"), env, profile),
26911
- keep_disappearing: on("keep_disappearing"),
26912
- channels: on("channels")
26913
- };
26914
- }
26915
- var TOOL_OPTION_NAMES = [
26916
- "toolsets",
26917
- "read_only",
26918
- "tools",
26919
- "exclude_tools",
26920
- "state_dir",
26921
- "download_dir",
26922
- "download_max_mb",
26923
- "send_dirs",
26924
- ...SERVICE_OPTION_NAMES
26925
- ];
26926
- var LANGUAGE_OPTION = "language";
26927
- var PLUGIN_OPTION_NAMES = [...TOOL_OPTION_NAMES, LANGUAGE_OPTION];
26928
27013
  function languageVariable(profile = PROJECT_PROFILE) {
26929
27014
  return `${profile.envPrefix}_LANGUAGE`;
26930
27015
  }
26931
- function nonBlank(text) {
26932
- const trimmed = text?.trim();
27016
+ function nonBlank(text2) {
27017
+ const trimmed = text2?.trim();
26933
27018
  return trimmed === "" ? void 0 : trimmed;
26934
27019
  }
26935
27020
  function promptLanguage(flag2, env, harness, profile = PROJECT_PROFILE) {
@@ -26983,20 +27068,20 @@ function checkApiId(apiId) {
26983
27068
  if (!Number.isSafeInteger(apiId) || apiId <= 0) throw new ToolError("invalid_argument", INVALID_API_ID);
26984
27069
  return apiId;
26985
27070
  }
26986
- function parseApiId(text) {
26987
- const trimmed = text.trim();
27071
+ function parseApiId(text2) {
27072
+ const trimmed = text2.trim();
26988
27073
  if (!API_ID_PATTERN.test(trimmed)) throw new ToolError("invalid_argument", INVALID_API_ID);
26989
27074
  return checkApiId(Number(trimmed));
26990
27075
  }
26991
- function parseApiHash(text) {
26992
- const hash2 = text.trim().toLowerCase();
27076
+ function parseApiHash(text2) {
27077
+ const hash2 = text2.trim().toLowerCase();
26993
27078
  if (!API_HASH_PATTERN.test(hash2)) throw new ToolError("invalid_argument", INVALID_API_HASH);
26994
27079
  return hash2;
26995
27080
  }
26996
27081
  function readApp(path) {
26997
- let text;
27082
+ let text2;
26998
27083
  try {
26999
- text = readFileSync3(path, "utf8");
27084
+ text2 = readFileSync3(path, "utf8");
27000
27085
  } catch (error62) {
27001
27086
  if (error62.code === "ENOENT") {
27002
27087
  throw new ToolError("not_found", "This account has no app credentials yet; log in first.");
@@ -27004,7 +27089,7 @@ function readApp(path) {
27004
27089
  throw new ToolError("upstream_error", UNREADABLE_APP);
27005
27090
  }
27006
27091
  try {
27007
- const parsed = JSON.parse(text);
27092
+ const parsed = JSON.parse(text2);
27008
27093
  if (typeof parsed.api_id !== "number" || typeof parsed.api_hash !== "string") throw new Error("malformed");
27009
27094
  return { apiId: checkApiId(parsed.api_id), apiHash: parseApiHash(parsed.api_hash) };
27010
27095
  } catch {
@@ -28792,16 +28877,16 @@ function _isAny2() {
28792
28877
  }
28793
28878
  var LAYER = 232;
28794
28879
  var RpcError = class _RpcError extends Error {
28795
- constructor(code, text) {
28796
- super("Telegram API error " + code + ": " + text);
28880
+ constructor(code, text2) {
28881
+ super("Telegram API error " + code + ": " + text2);
28797
28882
  this.code = code;
28798
- this.text = text;
28883
+ this.text = text2;
28799
28884
  }
28800
- static is(err, text) {
28801
- return err != null && err.constructor === _RpcError && (!text || err.text === text);
28885
+ static is(err, text2) {
28886
+ return err != null && err.constructor === _RpcError && (!text2 || err.text === text2);
28802
28887
  }
28803
- is(text) {
28804
- return this.text === text;
28888
+ is(text2) {
28889
+ return this.text === text2;
28805
28890
  }
28806
28891
  };
28807
28892
  RpcError.fromTl = function(obj) {
@@ -30268,8 +30353,8 @@ var AsyncLock = class {
30268
30353
  this._locked = true;
30269
30354
  return new AsyncLockGuard(this._release);
30270
30355
  }
30271
- return new Promise((resolve8) => {
30272
- this._waiters.pushBack(resolve8);
30356
+ return new Promise((resolve6) => {
30357
+ this._waiters.pushBack(resolve6);
30273
30358
  });
30274
30359
  }
30275
30360
  async with(func) {
@@ -30479,8 +30564,8 @@ var ConditionVariable = class {
30479
30564
  if (this.#promise) {
30480
30565
  return this.#promise;
30481
30566
  }
30482
- return this.#promise = new Promise((resolve8) => {
30483
- this.#notify = resolve8;
30567
+ return this.#promise = new Promise((resolve6) => {
30568
+ this.#notify = resolve6;
30484
30569
  });
30485
30570
  }
30486
30571
  notify() {
@@ -32111,7 +32196,7 @@ function makeInspectable(obj, props, hide2) {
32111
32196
 
32112
32197
  // node_modules/.pnpm/@mtcute+core@0.32.7/node_modules/@mtcute/core/utils/misc-utils.js
32113
32198
  function sleepWithAbort(ms, signal) {
32114
- return new Promise((resolve8, reject) => {
32199
+ return new Promise((resolve6, reject) => {
32115
32200
  let timeout;
32116
32201
  const onAbort2 = () => {
32117
32202
  timers_exports.clearTimeout(timeout);
@@ -32120,7 +32205,7 @@ function sleepWithAbort(ms, signal) {
32120
32205
  signal.addEventListener("abort", onAbort2);
32121
32206
  timeout = timers_exports.setTimeout(() => {
32122
32207
  signal.removeEventListener("abort", onAbort2);
32123
- resolve8();
32208
+ resolve6();
32124
32209
  }, ms);
32125
32210
  });
32126
32211
  }
@@ -34113,19 +34198,19 @@ var User = class _User {
34113
34198
  * msg.replyText(html`Hello, ${msg.sender.mention()`)
34114
34199
  * ```
34115
34200
  */
34116
- mention(text) {
34117
- if (text === void 0 && this.username) {
34201
+ mention(text2) {
34202
+ if (text2 === void 0 && this.username) {
34118
34203
  return `@${this.username}`;
34119
34204
  }
34120
- if (!text) text = this.displayName;
34205
+ if (!text2) text2 = this.displayName;
34121
34206
  return new MessageEntity$2(
34122
34207
  {
34123
34208
  _: "messageEntityMentionName",
34124
34209
  offset: 0,
34125
- length: text.length,
34210
+ length: text2.length,
34126
34211
  userId: this.raw.id
34127
34212
  },
34128
- text
34213
+ text2
34129
34214
  );
34130
34215
  }
34131
34216
  /**
@@ -34165,19 +34250,19 @@ var User = class _User {
34165
34250
  *
34166
34251
  * @param text Mention text
34167
34252
  */
34168
- permanentMention(text) {
34253
+ permanentMention(text2) {
34169
34254
  if (!this.raw.accessHash) {
34170
34255
  throw new MtArgumentError("User's access hash is not available!");
34171
34256
  }
34172
- if (!text) text = this.displayName;
34257
+ if (!text2) text2 = this.displayName;
34173
34258
  return new MessageEntity$2(
34174
34259
  {
34175
34260
  _: "messageEntityTextUrl",
34176
34261
  offset: 0,
34177
- length: text.length,
34262
+ length: text2.length,
34178
34263
  url: `tg://user?id=${this.id}&hash=${this.raw.accessHash.toString(16)}`
34179
34264
  },
34180
- text
34265
+ text2
34181
34266
  );
34182
34267
  }
34183
34268
  };
@@ -34238,10 +34323,10 @@ var GameHighScore$1 = /* @__PURE__ */ memoizeGetters(GameHighScore, ["user"]);
34238
34323
  var GameHighScore$2 = /* @__PURE__ */ makeInspectable(GameHighScore$1);
34239
34324
 
34240
34325
  // node_modules/.pnpm/@mtcute+core@0.32.7/node_modules/@mtcute/core/highlevel/utils/walk-page-blocks.js
34241
- function walkRichText(text, visitor) {
34242
- if (!text) return;
34243
- visitor.richText?.(text);
34244
- switch (text._) {
34326
+ function walkRichText(text2, visitor) {
34327
+ if (!text2) return;
34328
+ visitor.richText?.(text2);
34329
+ switch (text2._) {
34245
34330
  case "textEmpty":
34246
34331
  case "textPlain":
34247
34332
  case "textEmail":
@@ -34273,14 +34358,14 @@ function walkRichText(text, visitor) {
34273
34358
  case "textDate":
34274
34359
  case "textMentionName":
34275
34360
  case "textButton":
34276
- walkRichText(text.text, visitor);
34361
+ walkRichText(text2.text, visitor);
34277
34362
  break;
34278
34363
  case "textConcat":
34279
- for (const child of text.texts) walkRichText(child, visitor);
34364
+ for (const child of text2.texts) walkRichText(child, visitor);
34280
34365
  break;
34281
34366
  case "textDiff":
34282
- walkRichText(text.text, visitor);
34283
- walkRichText(text.oldText, visitor);
34367
+ walkRichText(text2.text, visitor);
34368
+ walkRichText(text2.oldText, visitor);
34284
34369
  break;
34285
34370
  default:
34286
34371
  assertNever2();
@@ -34410,11 +34495,11 @@ function isUploadedFile(obj) {
34410
34495
  }
34411
34496
 
34412
34497
  // node_modules/.pnpm/@mtcute+core@0.32.7/node_modules/@mtcute/core/highlevel/types/misc/entities.js
34413
- function inputTextToTl(text) {
34498
+ function inputTextToTl(text2) {
34414
34499
  return {
34415
34500
  _: "textWithEntities",
34416
- text: typeof text === "string" ? text : text.text,
34417
- entities: typeof text === "string" ? [] : text.entities ?? []
34501
+ text: typeof text2 === "string" ? text2 : text2.text,
34502
+ entities: typeof text2 === "string" ? [] : text2.entities ?? []
34418
34503
  };
34419
34504
  }
34420
34505
 
@@ -34708,8 +34793,8 @@ function batchedQuery(params) {
34708
34793
  arr = [];
34709
34794
  waiters.set(key, arr);
34710
34795
  }
34711
- return new Promise((resolve8, reject) => {
34712
- arr.push([item, resolve8, reject]);
34796
+ return new Promise((resolve6, reject) => {
34797
+ arr.push([item, resolve6, reject]);
34713
34798
  });
34714
34799
  }
34715
34800
  function popWaiters(waiters, key) {
@@ -35131,9 +35216,9 @@ async function _normalizeInputText(client, input8) {
35131
35216
  if (typeof input8 === "string") {
35132
35217
  return [input8, void 0];
35133
35218
  }
35134
- let text = input8.text;
35219
+ let text2 = input8.text;
35135
35220
  const entities = input8.entities;
35136
- if (!entities) return [text, void 0];
35221
+ if (!entities) return [text2, void 0];
35137
35222
  let canTrimStart = true;
35138
35223
  for (const ent of entities) {
35139
35224
  if (ent._ === "messageEntityMentionName") {
@@ -35151,17 +35236,17 @@ async function _normalizeInputText(client, input8) {
35151
35236
  }
35152
35237
  }
35153
35238
  if (canTrimStart) {
35154
- const resultTrimmed = text.trimStart();
35155
- const numCharsTrimmed = text.length - resultTrimmed.length;
35156
- text = resultTrimmed;
35239
+ const resultTrimmed = text2.trimStart();
35240
+ const numCharsTrimmed = text2.length - resultTrimmed.length;
35241
+ text2 = resultTrimmed;
35157
35242
  adjustOffsets(entities, 0, -numCharsTrimmed);
35158
35243
  }
35159
- text = text.trimEnd();
35244
+ text2 = text2.trimEnd();
35160
35245
  for (const ent of entities) {
35161
35246
  const end = ent.offset + ent.length;
35162
- if (end > text.length) ent.length = text.length - ent.offset;
35247
+ if (end > text2.length) ent.length = text2.length - ent.offset;
35163
35248
  }
35164
- return [text, entities];
35249
+ return [text2, entities];
35165
35250
  }
35166
35251
 
35167
35252
  // node_modules/.pnpm/@fuman+io@0.0.23/node_modules/@fuman/io/read/index.js
@@ -37094,8 +37179,8 @@ async function _normalizeInputRichMessage(client, peer, input8, params) {
37094
37179
  const blocks = input8.blocks.map(processBlock);
37095
37180
  const mentionIds = /* @__PURE__ */ new Set();
37096
37181
  walkPageBlocks(blocks, {
37097
- richText: (text) => {
37098
- if (text._ === "textMentionName") mentionIds.add(text.userId);
37182
+ richText: (text2) => {
37183
+ if (text2._ === "textMentionName") mentionIds.add(text2.userId);
37099
37184
  }
37100
37185
  });
37101
37186
  const users = mentionIds.size ? await resolvePeerMany(client, [...mentionIds], toInputUser) : void 0;
@@ -38366,20 +38451,20 @@ var Chat = class {
38366
38451
  * msg.replyText(html`Hello, ${msg.chat.mention()`)
38367
38452
  * ```
38368
38453
  */
38369
- mention(text) {
38370
- if (text === void 0 && this.username) {
38454
+ mention(text2) {
38455
+ if (text2 === void 0 && this.username) {
38371
38456
  return `@${this.username}`;
38372
38457
  }
38373
- if (!text) text = this.displayName;
38374
- if (!this.username) return text;
38458
+ if (!text2) text2 = this.displayName;
38459
+ if (!this.username) return text2;
38375
38460
  return new MessageEntity$2(
38376
38461
  {
38377
38462
  _: "messageEntityTextUrl",
38378
38463
  offset: 0,
38379
- length: text.length,
38464
+ length: text2.length,
38380
38465
  url: `https://t.me/${this.username}`
38381
38466
  },
38382
- text
38467
+ text2
38383
38468
  );
38384
38469
  }
38385
38470
  };
@@ -44034,9 +44119,9 @@ function _inputReplyToToHeader(replyTo2, peer) {
44034
44119
  ];
44035
44120
  }
44036
44121
  }
44037
- async function sendText(client, chatId, text, params) {
44122
+ async function sendText(client, chatId, text2, params) {
44038
44123
  if (!params) params = {};
44039
- const [message2, entities] = await _normalizeInputText(client, text);
44124
+ const [message2, entities] = await _normalizeInputText(client, text2);
44040
44125
  const replyMarkup = _convertToTl(params.replyMarkup);
44041
44126
  const { peer, replyTo: replyTo2, scheduleDate, chainId, quickReplyShortcut } = await _processCommonSendParameters(
44042
44127
  client,
@@ -49520,8 +49605,8 @@ var UPDATES_TOO_LONG = { _: "updatesTooLong" };
49520
49605
  function collectRichMessagePeerIds(richMessage, peers) {
49521
49606
  if (!richMessage) return;
49522
49607
  walkPageBlocks(richMessage.blocks, {
49523
- richText: (text) => {
49524
- if (text._ === "textMentionName") peers.add(text.userId);
49608
+ richText: (text2) => {
49609
+ if (text2._ === "textMentionName") peers.add(text2.userId);
49525
49610
  }
49526
49611
  });
49527
49612
  }
@@ -79932,10 +80017,10 @@ var ConnectionFloodController = class {
79932
80017
  const delay = wakeup - now;
79933
80018
  this._log?.debug("connect throttled (waiting %dms)", Math.round(delay));
79934
80019
  waited = true;
79935
- await new Promise((resolve8, reject) => {
80020
+ await new Promise((resolve6, reject) => {
79936
80021
  const handle = timers_exports.setTimeout(() => {
79937
80022
  signal?.removeEventListener("abort", onAbort2);
79938
- resolve8();
80023
+ resolve6();
79939
80024
  }, delay);
79940
80025
  const onAbort2 = () => {
79941
80026
  timers_exports.clearTimeout(handle);
@@ -83913,8 +83998,8 @@ function rpcTextOf(error62) {
83913
83998
  return inner_tl_exports.RpcError.is(error62) ? String(error62.text) : void 0;
83914
83999
  }
83915
84000
  function isSessionEnded(error62) {
83916
- const text = rpcTextOf(error62);
83917
- return text !== void 0 && SESSION_ENDED_ERRORS.includes(text);
84001
+ const text2 = rpcTextOf(error62);
84002
+ return text2 !== void 0 && SESSION_ENDED_ERRORS.includes(text2);
83918
84003
  }
83919
84004
  function floodWaitSecondsOf(error62) {
83920
84005
  if (!inner_tl_exports.RpcError.is(error62)) return void 0;
@@ -83938,18 +84023,18 @@ var PHONE_REASONS = {
83938
84023
  function loginError(error62) {
83939
84024
  if (error62 instanceof ToolError || isAbortError(error62)) return error62;
83940
84025
  if (!inner_tl_exports.RpcError.is(error62)) return error62;
83941
- const text = String(error62.text);
84026
+ const text2 = String(error62.text);
83942
84027
  const seconds = floodWaitSecondsOf(error62);
83943
84028
  if (seconds !== void 0 || error62.code === inner_tl_exports.RpcError.FLOOD) {
83944
84029
  const wait = seconds === void 0 ? "a while" : `${seconds} seconds`;
83945
84030
  return new ToolError("rate_limited", `Telegram asks to wait ${wait} before logging in again.`);
83946
84031
  }
83947
- if (text === "PHONE_CODE_EXPIRED") {
84032
+ if (text2 === "PHONE_CODE_EXPIRED") {
83948
84033
  return new ToolError("invalid_argument", "The code expired; log in again.");
83949
84034
  }
83950
- const reason = PHONE_REASONS[text];
84035
+ const reason = PHONE_REASONS[text2];
83951
84036
  if (reason) return new ToolError("invalid_argument", reason);
83952
- return new ToolError("upstream_error", `Telegram refused the login (${text}).`);
84037
+ return new ToolError("upstream_error", `Telegram refused the login (${text2}).`);
83953
84038
  }
83954
84039
  async function guarded(run) {
83955
84040
  try {
@@ -83966,8 +84051,8 @@ async function isLoggedIn(client) {
83966
84051
  await client.getMe();
83967
84052
  return true;
83968
84053
  } catch (error62) {
83969
- const text = rpcTextOf(error62);
83970
- if (text === "AUTH_KEY_UNREGISTERED" || text === "SESSION_PASSWORD_NEEDED") return false;
84054
+ const text2 = rpcTextOf(error62);
84055
+ if (text2 === "AUTH_KEY_UNREGISTERED" || text2 === "SESSION_PASSWORD_NEEDED") return false;
83971
84056
  throw loginError(error62);
83972
84057
  }
83973
84058
  }
@@ -84007,9 +84092,9 @@ async function signInWithCode(client, io, phone, phoneCodeHash) {
84007
84092
  try {
84008
84093
  return await client.signIn({ phone, phoneCodeHash, phoneCode, abortSignal: io.signal });
84009
84094
  } catch (error62) {
84010
- const text = rpcTextOf(error62);
84011
- if (text === "SESSION_PASSWORD_NEEDED") return checkTwoStepPassword(client, io);
84012
- if (text !== "PHONE_CODE_INVALID") throw error62;
84095
+ const text2 = rpcTextOf(error62);
84096
+ if (text2 === "SESSION_PASSWORD_NEEDED") return checkTwoStepPassword(client, io);
84097
+ if (text2 !== "PHONE_CODE_INVALID") throw error62;
84013
84098
  io.say("That code is not right.");
84014
84099
  }
84015
84100
  }
@@ -84081,6 +84166,26 @@ async function logoutLabel(options) {
84081
84166
  }
84082
84167
  }
84083
84168
 
84169
+ // src/entry/command-settings.ts
84170
+ var SERVICE_BOOLEANS = ["keep_disappearing", "channels"];
84171
+ var STATE_DIR = "state_dir";
84172
+ function onlyOptions(profile, names) {
84173
+ const declared = Object.entries(profile.options ?? {}).filter(([name]) => names.includes(name));
84174
+ return { ...profile, options: Object.fromEntries(declared) };
84175
+ }
84176
+ function parseStateDir(argv, env, profile = PROJECT_PROFILE) {
84177
+ const options = parseToolOptions(argv, env, onlyOptions(profile, [STATE_DIR]));
84178
+ return resolveDirectorySettings(options, env, profile).state_dir;
84179
+ }
84180
+ function parseServiceSettings(argv, env, profile = PROJECT_PROFILE) {
84181
+ const options = parseToolOptions(argv, env, onlyOptions(profile, [STATE_DIR, ...SERVICE_BOOLEANS]));
84182
+ return {
84183
+ state_dir: resolveDirectorySettings(options, env, profile).state_dir,
84184
+ keep_disappearing: options.keep_disappearing === true,
84185
+ channels: options.channels === true
84186
+ };
84187
+ }
84188
+
84084
84189
  // src/cli/command-args.ts
84085
84190
  function usageError(message2) {
84086
84191
  return new ToolError("invalid_argument", message2);
@@ -84606,35 +84711,35 @@ function makeNumeric(digits) {
84606
84711
  }
84607
84712
  return new QrSegment(MODE_NUMERIC, digits.length, bb);
84608
84713
  }
84609
- function makeAlphanumeric(text) {
84610
- if (!isAlphanumeric(text))
84714
+ function makeAlphanumeric(text2) {
84715
+ if (!isAlphanumeric(text2))
84611
84716
  throw new RangeError("String contains unencodable characters in alphanumeric mode");
84612
84717
  const bb = [];
84613
84718
  let i;
84614
- for (i = 0; i + 2 <= text.length; i += 2) {
84615
- let temp = ALPHANUMERIC_CHARSET.indexOf(text.charAt(i)) * 45;
84616
- temp += ALPHANUMERIC_CHARSET.indexOf(text.charAt(i + 1));
84719
+ for (i = 0; i + 2 <= text2.length; i += 2) {
84720
+ let temp = ALPHANUMERIC_CHARSET.indexOf(text2.charAt(i)) * 45;
84721
+ temp += ALPHANUMERIC_CHARSET.indexOf(text2.charAt(i + 1));
84617
84722
  appendBits(temp, 11, bb);
84618
84723
  }
84619
- if (i < text.length)
84620
- appendBits(ALPHANUMERIC_CHARSET.indexOf(text.charAt(i)), 6, bb);
84621
- return new QrSegment(MODE_ALPHANUMERIC, text.length, bb);
84724
+ if (i < text2.length)
84725
+ appendBits(ALPHANUMERIC_CHARSET.indexOf(text2.charAt(i)), 6, bb);
84726
+ return new QrSegment(MODE_ALPHANUMERIC, text2.length, bb);
84622
84727
  }
84623
- function makeSegments(text) {
84624
- if (text === "")
84728
+ function makeSegments(text2) {
84729
+ if (text2 === "")
84625
84730
  return [];
84626
- else if (isNumeric(text))
84627
- return [makeNumeric(text)];
84628
- else if (isAlphanumeric(text))
84629
- return [makeAlphanumeric(text)];
84731
+ else if (isNumeric(text2))
84732
+ return [makeNumeric(text2)];
84733
+ else if (isAlphanumeric(text2))
84734
+ return [makeAlphanumeric(text2)];
84630
84735
  else
84631
- return [makeBytes(toUtf8ByteArray(text))];
84736
+ return [makeBytes(toUtf8ByteArray(text2))];
84632
84737
  }
84633
- function isNumeric(text) {
84634
- return NUMERIC_REGEX.test(text);
84738
+ function isNumeric(text2) {
84739
+ return NUMERIC_REGEX.test(text2);
84635
84740
  }
84636
- function isAlphanumeric(text) {
84637
- return ALPHANUMERIC_REGEX.test(text);
84741
+ function isAlphanumeric(text2) {
84742
+ return ALPHANUMERIC_REGEX.test(text2);
84638
84743
  }
84639
84744
  function getTotalBits(segs, version3) {
84640
84745
  let result = 0;
@@ -84820,8 +84925,8 @@ function cell(top, bottom) {
84820
84925
  const background = bottom === true ? DARK : LIGHT;
84821
84926
  return `\x1B[38;5;${foreground}m\x1B[48;5;${background}m${HALF_BLOCK}`;
84822
84927
  }
84823
- function drawQr(text) {
84824
- const modules = encode5(text, { border: QR_QUIET_ZONE }).data;
84928
+ function drawQr(text2) {
84929
+ const modules = encode5(text2, { border: QR_QUIET_ZONE }).data;
84825
84930
  const lines = [];
84826
84931
  for (let row = 0; row < modules.length; row += 2) {
84827
84932
  const upper = modules[row] ?? [];
@@ -85707,13 +85812,13 @@ async function answerBotGuestChatQuery(client, queryId, result) {
85707
85812
 
85708
85813
  // node_modules/.pnpm/@mtcute+core@0.32.7/node_modules/@mtcute/core/highlevel/methods/bots/answer-callback-query.js
85709
85814
  async function answerCallbackQuery(client, queryId, params) {
85710
- const { cacheTime = 0, text, alert, url: url2 } = params ?? {};
85815
+ const { cacheTime = 0, text: text2, alert, url: url2 } = params ?? {};
85711
85816
  const r = await client.call({
85712
85817
  _: "messages.setBotCallbackAnswer",
85713
85818
  queryId: long_default.isLong(queryId) ? queryId : queryId.id,
85714
85819
  cacheTime,
85715
85820
  alert,
85716
- message: text,
85821
+ message: text2,
85717
85822
  url: url2
85718
85823
  });
85719
85824
  assertTrue("messages.setBotCallbackAnswer", r);
@@ -88171,11 +88276,11 @@ function _findEphemeralMessageInUpdate(client, res, isEdit = false, noDispatch =
88171
88276
 
88172
88277
  // node_modules/.pnpm/@mtcute+core@0.32.7/node_modules/@mtcute/core/highlevel/methods/ephemeral/edit-ephemeral-message.js
88173
88278
  async function editEphemeralMessage(client, params) {
88174
- const { chatId, receiverId, messageId, text, media, richMessage, replyMarkup, shouldDispatch, uploadCache } = params;
88279
+ const { chatId, receiverId, messageId, text: text2, media, richMessage, replyMarkup, shouldDispatch, uploadCache } = params;
88175
88280
  let message2;
88176
88281
  let entities;
88177
- if (text !== void 0) {
88178
- [message2, entities] = await _normalizeInputText(client, text);
88282
+ if (text2 !== void 0) {
88283
+ [message2, entities] = await _normalizeInputText(client, text2);
88179
88284
  }
88180
88285
  const peer = chatId !== null ? await resolvePeer(client, chatId) : void 0;
88181
88286
  if (richMessage && !peer) {
@@ -88239,9 +88344,9 @@ async function getWelcomeMessages(client, chatId) {
88239
88344
  }
88240
88345
 
88241
88346
  // node_modules/.pnpm/@mtcute+core@0.32.7/node_modules/@mtcute/core/highlevel/methods/ephemeral/send-ephemeral-message.js
88242
- async function sendEphemeralMessage(client, chatId, receiverId, text, params) {
88347
+ async function sendEphemeralMessage(client, chatId, receiverId, text2, params) {
88243
88348
  const { media, richMessage, replyTo: replyTo2, replyToEphemeral, queryId, shouldDispatch, uploadCache } = params ?? {};
88244
- const [message2, entities] = await _normalizeInputText(client, text);
88349
+ const [message2, entities] = await _normalizeInputText(client, text2);
88245
88350
  const peer = chatId !== null ? await resolvePeer(client, chatId) : void 0;
88246
88351
  if (richMessage && !peer) {
88247
88352
  throw new MtArgumentError("richMessage requires chatId to be passed");
@@ -88287,8 +88392,8 @@ var DownloadDelayGate = class {
88287
88392
  const ms = at2 - now;
88288
88393
  if (ms <= 0) return Promise.resolve();
88289
88394
  if (signal) return sleepWithAbort(ms, signal);
88290
- return new Promise((resolve8) => {
88291
- timers_exports.setTimeout(resolve8, ms);
88395
+ return new Promise((resolve6) => {
88396
+ timers_exports.setTimeout(resolve6, ms);
88292
88397
  });
88293
88398
  }
88294
88399
  };
@@ -89740,16 +89845,16 @@ async function createStreamingDraft(client, chatId, params) {
89740
89845
  const peer = await resolvePeer(client, chatId);
89741
89846
  const stopListener = canStop ? _listenForDraftStop(client, randomId) : void 0;
89742
89847
  let previousText;
89743
- const sendDraft = async (text) => {
89848
+ const sendDraft = async (text2) => {
89744
89849
  if (stopListener?.signal.aborted) return;
89745
- if (typeof text === "string") {
89746
- text = { text };
89850
+ if (typeof text2 === "string") {
89851
+ text2 = { text: text2 };
89747
89852
  }
89748
89853
  if (mode === "append" && previousText) {
89749
- text = joinTextWithEntities([previousText, text]);
89854
+ text2 = joinTextWithEntities([previousText, text2]);
89750
89855
  }
89751
- previousText = text;
89752
- const [_text, entities = []] = await _normalizeInputText(client, text);
89856
+ previousText = text2;
89857
+ const [_text, entities = []] = await _normalizeInputText(client, text2);
89753
89858
  if (stopListener?.signal.aborted) return;
89754
89859
  const r = await client.call({
89755
89860
  _: "messages.setTyping",
@@ -90378,8 +90483,8 @@ async function getUnreadPollVotes(client, chatId, params) {
90378
90483
  }
90379
90484
 
90380
90485
  // node_modules/.pnpm/@mtcute+core@0.32.7/node_modules/@mtcute/core/highlevel/methods/messages/get-web-page-preview.js
90381
- async function getWebPagePreview(client, text) {
90382
- const [message2, entities] = await _normalizeInputText(client, text);
90486
+ async function getWebPagePreview(client, text2) {
90487
+ const [message2, entities] = await _normalizeInputText(client, text2);
90383
90488
  const res = await client.call({
90384
90489
  _: "messages.getWebPagePreview",
90385
90490
  message: message2,
@@ -90766,9 +90871,9 @@ function answerText(client, message2, ...params) {
90766
90871
  if (!message2.isTopicMessage || !message2.replyToMessage?.threadId) {
90767
90872
  return sendText(client, message2.chat.inputPeer, ...params);
90768
90873
  }
90769
- const [text, params_ = {}] = params;
90874
+ const [text2, params_ = {}] = params;
90770
90875
  params_.replyTo = message2.replyToMessage.threadId;
90771
- return sendText(client, message2.chat.inputPeer, text, params_);
90876
+ return sendText(client, message2.chat.inputPeer, text2, params_);
90772
90877
  }
90773
90878
  function answerMedia(client, message2, ...params) {
90774
90879
  if (!message2.isTopicMessage || !message2.replyToMessage?.threadId) {
@@ -90789,11 +90894,11 @@ function answerMediaGroup(client, message2, ...params) {
90789
90894
 
90790
90895
  // node_modules/.pnpm/@mtcute+core@0.32.7/node_modules/@mtcute/core/highlevel/methods/messages/send-reply.js
90791
90896
  function replyText(client, message2, ...params) {
90792
- const [text, params_ = {}] = params;
90897
+ const [text2, params_ = {}] = params;
90793
90898
  params_.replyTo = message2.id;
90794
90899
  const threadId = message2.replyToMessage?.threadId;
90795
90900
  if (threadId) params_.threadId = threadId;
90796
- return sendText(client, message2.chat.inputPeer, text, params_);
90901
+ return sendText(client, message2.chat.inputPeer, text2, params_);
90797
90902
  }
90798
90903
  function replyMedia(client, message2, ...params) {
90799
90904
  const [media, params_ = {}] = params;
@@ -90818,9 +90923,9 @@ function commentText(client, message2, ...params) {
90818
90923
  if (!message2.replies || !message2.replies.hasComments) {
90819
90924
  throw new MtArgumentError("This message does not have comments section");
90820
90925
  }
90821
- const [text, params_ = {}] = params;
90926
+ const [text2, params_ = {}] = params;
90822
90927
  params_.commentTo = message2.id;
90823
- return sendText(client, message2.chat.inputPeer, text, params_);
90928
+ return sendText(client, message2.chat.inputPeer, text2, params_);
90824
90929
  }
90825
90930
  function commentMedia(client, message2, ...params) {
90826
90931
  if (message2.chat.type !== "chat" || message2.chat.chatType !== "channel") {
@@ -90960,11 +91065,11 @@ function extractQuote(message2, from, to) {
90960
91065
  const { raw } = message2;
90961
91066
  if (raw._ === "messageService") throw new MtArgumentError("Cannot quote service message");
90962
91067
  if (!raw.message) throw new MtArgumentError("Cannot quote empty message");
90963
- const text = raw.message;
91068
+ const text2 = raw.message;
90964
91069
  if (from < 0) from = 0;
90965
- if (to > text.length) to = text.length;
91070
+ if (to > text2.length) to = text2.length;
90966
91071
  if (from >= to) throw new MtArgumentError("Invalid quote range");
90967
- if (!raw.entities) return { text: text.slice(from, to), entities: void 0 };
91072
+ if (!raw.entities) return { text: text2.slice(from, to), entities: void 0 };
90968
91073
  const entities = [];
90969
91074
  for (const ent of raw.entities) {
90970
91075
  const start3 = ent.offset;
@@ -90975,15 +91080,15 @@ function extractQuote(message2, from, to) {
90975
91080
  const newEnt = { ...ent, offset: newStart, length: newEnd - newStart };
90976
91081
  entities.push(newEnt);
90977
91082
  }
90978
- return { text: text.slice(from, to), entities };
91083
+ return { text: text2.slice(from, to), entities };
90979
91084
  }
90980
91085
  function quoteWithText(client, message2, params) {
90981
- const { toChatId = message2.chat, start: start3, end, text, ...params__ } = params;
91086
+ const { toChatId = message2.chat, start: start3, end, text: text2, ...params__ } = params;
90982
91087
  const params_ = params__;
90983
91088
  params_.replyTo = message2;
90984
91089
  params_.quote = extractQuote(message2, params.start, params.end);
90985
91090
  params_.quoteOffset = params.start;
90986
- return sendText(client, toChatId, text, params_);
91091
+ return sendText(client, toChatId, text2, params_);
90987
91092
  }
90988
91093
  function quoteWithMedia(client, message2, params) {
90989
91094
  const { toChatId = message2.chat, start: start3, end, media, ...params__ } = params;
@@ -91176,8 +91281,8 @@ async function translateMessage(client, params) {
91176
91281
  }
91177
91282
 
91178
91283
  // node_modules/.pnpm/@mtcute+core@0.32.7/node_modules/@mtcute/core/highlevel/methods/messages/translate-text.js
91179
- async function translateText(client, text, toLanguage, params) {
91180
- const [message2, entities] = await _normalizeInputText(client, text);
91284
+ async function translateText(client, text2, toLanguage, params) {
91285
+ const [message2, entities] = await _normalizeInputText(client, text2);
91181
91286
  const res = await client.call({
91182
91287
  _: "messages.translateText",
91183
91288
  text: [
@@ -91431,8 +91536,8 @@ async function canApplyBoost(client) {
91431
91536
  }
91432
91537
 
91433
91538
  // node_modules/.pnpm/@mtcute+core@0.32.7/node_modules/@mtcute/core/highlevel/methods/premium/create-business-chat-link.js
91434
- async function createBusinessChatLink(client, text, params) {
91435
- const [message2, entities] = await _normalizeInputText(client, text);
91539
+ async function createBusinessChatLink(client, text2, params) {
91540
+ const [message2, entities] = await _normalizeInputText(client, text2);
91436
91541
  const res = await client.call({
91437
91542
  _: "account.createBusinessChatLink",
91438
91543
  link: {
@@ -94089,10 +94194,10 @@ var NodeSocketConnection = class {
94089
94194
  }
94090
94195
  async write(bytes2) {
94091
94196
  if (this.#error) throw this.#error;
94092
- return new Promise((resolve8, reject) => {
94197
+ return new Promise((resolve6, reject) => {
94093
94198
  this.socket.write(bytes2, (error62) => {
94094
94199
  if (error62) reject(error62);
94095
- else resolve8();
94200
+ else resolve6();
94096
94201
  });
94097
94202
  });
94098
94203
  }
@@ -94121,14 +94226,14 @@ var TcpConnection = class extends NodeSocketConnection {
94121
94226
  // node_modules/.pnpm/@fuman+node@0.0.23/node_modules/@fuman/node/net/functions.js
94122
94227
  import { Socket as Socket2, Server } from "node:net";
94123
94228
  function awaitConnect(socket, signal) {
94124
- return new Promise((resolve8, reject) => {
94229
+ return new Promise((resolve6, reject) => {
94125
94230
  function onError(error62) {
94126
94231
  cleanup();
94127
94232
  reject(error62);
94128
94233
  }
94129
94234
  function onConnect() {
94130
94235
  cleanup();
94131
- resolve8();
94236
+ resolve6();
94132
94237
  }
94133
94238
  function onAbort2() {
94134
94239
  cleanup();
@@ -94281,7 +94386,7 @@ var NodeCryptoProvider = class extends BaseCryptoProvider {
94281
94386
  }
94282
94387
  pbkdf2(password, salt, iterations, keylen = 64, algo = "sha512") {
94283
94388
  return new Promise(
94284
- (resolve8, reject) => pbkdf2(password, salt, iterations, keylen, algo, (err, buf) => err !== null ? reject(err) : resolve8(buf))
94389
+ (resolve6, reject) => pbkdf2(password, salt, iterations, keylen, algo, (err, buf) => err !== null ? reject(err) : resolve6(buf))
94285
94390
  );
94286
94391
  }
94287
94392
  sha1(data) {
@@ -94531,7 +94636,7 @@ function createTelegramClient(settings) {
94531
94636
  function deviceInfo() {
94532
94637
  return {
94533
94638
  model: `${PROJECT.name} (unofficial)`,
94534
- appVersion: true ? "0.1.0" : DEV_VERSION,
94639
+ appVersion: true ? "0.3.0" : DEV_VERSION,
94535
94640
  systemVersion: `${type2()} ${release()}`
94536
94641
  };
94537
94642
  }
@@ -94591,9 +94696,9 @@ async function appCredentials(paths, io) {
94591
94696
  return app;
94592
94697
  }
94593
94698
  async function telethonSession(io) {
94594
- const text = isTerminal(io) ? await askHidden(io, TELETHON_PROMPT) : await io.readStdin?.() ?? "";
94595
- if (text.trim() === "") throw usageError("No Telethon string session was given.");
94596
- return text;
94699
+ const text2 = isTerminal(io) ? await askHidden(io, TELETHON_PROMPT) : await io.readStdin?.() ?? "";
94700
+ if (text2.trim() === "") throw usageError("No Telethon string session was given.");
94701
+ return text2;
94597
94702
  }
94598
94703
  function qrPrinter(io) {
94599
94704
  const inPlace = io.isTTY ?? Boolean(process.stdout.isTTY);
@@ -94721,7 +94826,7 @@ async function removeLabel(options) {
94721
94826
  if (Date.now() - start3 >= timeoutMs) {
94722
94827
  throw new ToolError("invalid_argument", "The sync service for this label is still running; stop it first.");
94723
94828
  }
94724
- await new Promise((resolve8) => setTimeout(resolve8, Math.min(intervalMs, timeoutMs - (Date.now() - start3))));
94829
+ await new Promise((resolve6) => setTimeout(resolve6, Math.min(intervalMs, timeoutMs - (Date.now() - start3))));
94725
94830
  }
94726
94831
  const finalStat = await lstat8(paths.dir).catch(() => void 0);
94727
94832
  if (!finalStat || finalStat.isSymbolicLink() || !finalStat.isDirectory()) {
@@ -94746,8 +94851,8 @@ import { chmod as chmod3, lstat as lstat9, mkdir as mkdir5, rename as rename3, r
94746
94851
  import { basename as basename3, dirname as dirname6, join as join13 } from "node:path";
94747
94852
  import { setTimeout as setTimeout3 } from "node:timers/promises";
94748
94853
  var LAUNCHER_SCRIPT = '#!/bin/sh\nexec "$@"\n';
94749
- function xmlEscape(text) {
94750
- return text.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&apos;");
94854
+ function xmlEscape(text2) {
94855
+ return text2.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&apos;");
94751
94856
  }
94752
94857
  function buildLaunchdPlist(spec, logPath, launcherPath) {
94753
94858
  checkServiceSpecControlChars(spec);
@@ -94803,8 +94908,8 @@ function launcherPaths(id, label, launcher, home) {
94803
94908
  }
94804
94909
  function isLaunchdNotLoaded(result) {
94805
94910
  if (result.code === 0) return true;
94806
- const text = `${result.stderr} ${result.stdout}`.toLowerCase();
94807
- return text.includes("not loaded") || text.includes("no such process") || text.includes("input/output error") || text.includes("could not find") || result.code === 3 || result.code === 5;
94911
+ const text2 = `${result.stderr} ${result.stdout}`.toLowerCase();
94912
+ return text2.includes("not loaded") || text2.includes("no such process") || text2.includes("input/output error") || text2.includes("could not find") || result.code === 3 || result.code === 5;
94808
94913
  }
94809
94914
  var STOP_POLL_INTERVAL_MS = 200;
94810
94915
  var STOP_TIMEOUT_MS = 3e4;
@@ -94947,8 +95052,8 @@ function systemdPaths(id, label, host) {
94947
95052
  }
94948
95053
  function isSystemdNotLoaded(result) {
94949
95054
  if (result.code === 0) return true;
94950
- const text = `${result.stderr} ${result.stdout}`.toLowerCase();
94951
- return text.includes("not loaded") || text.includes("does not exist") || text.includes("not found") || text.includes("no such") || text.includes("not active");
95055
+ const text2 = `${result.stderr} ${result.stdout}`.toLowerCase();
95056
+ return text2.includes("not loaded") || text2.includes("does not exist") || text2.includes("not found") || text2.includes("no such") || text2.includes("not active");
94952
95057
  }
94953
95058
  async function isSystemdActive(unitName, host) {
94954
95059
  const result = await host.run(["systemctl", "--user", "is-active", unitName]);
@@ -95080,7 +95185,7 @@ import { existsSync as existsSync3, realpathSync } from "node:fs";
95080
95185
 
95081
95186
  // src/cli/service-program.ts
95082
95187
  import { access as access2, constants as constants4, realpath as realpath7, stat as stat3 } from "node:fs/promises";
95083
- import { isAbsolute as isAbsolute7, join as join15, resolve as resolve7, sep as sep5 } from "node:path";
95188
+ import { isAbsolute as isAbsolute7, join as join15, resolve as resolve5, sep as sep5 } from "node:path";
95084
95189
  var PROBE_TIMEOUT_MS = 1e4;
95085
95190
  var PROGRAM_NAME = "node";
95086
95191
  var PROBE_ARGS = ["-p", "process.execPath"];
@@ -95113,7 +95218,7 @@ async function resolveRoots(roots) {
95113
95218
  const resolved = /* @__PURE__ */ new Set();
95114
95219
  for (const root of roots) {
95115
95220
  if (root === "" || !isAbsolute7(root)) continue;
95116
- resolved.add(resolve7(root));
95221
+ resolved.add(resolve5(root));
95117
95222
  try {
95118
95223
  resolved.add(await realpath7(root));
95119
95224
  } catch {
@@ -95144,7 +95249,7 @@ async function pickStableProgram(options) {
95144
95249
  if (dir !== "" && isAbsolute7(dir)) candidates.add(join15(dir, PROGRAM_NAME));
95145
95250
  }
95146
95251
  for (const candidate of candidates) {
95147
- if (pathHoldsVersion(candidate, version3) || isUnder(resolve7(candidate), volatileRoots)) continue;
95252
+ if (pathHoldsVersion(candidate, version3) || isUnder(resolve5(candidate), volatileRoots)) continue;
95148
95253
  if (!await isExecutableFile(candidate)) continue;
95149
95254
  let started;
95150
95255
  try {
@@ -95479,12 +95584,12 @@ function parseRequest(message2) {
95479
95584
  return { id: message2.id, method: message2.method, params };
95480
95585
  }
95481
95586
  function probe(socketPath) {
95482
- return new Promise((resolve8) => {
95587
+ return new Promise((resolve6) => {
95483
95588
  const socket = new Socket3();
95484
95589
  const settle3 = (outcome) => {
95485
95590
  clearTimeout(timer);
95486
95591
  socket.destroy();
95487
- resolve8(outcome);
95592
+ resolve6(outcome);
95488
95593
  };
95489
95594
  const timer = setTimeout(() => settle3("unknown"), PROBE_TIMEOUT_MS2);
95490
95595
  socket.once("connect", () => settle3("answering"));
@@ -95505,16 +95610,16 @@ async function claimSocketPath(socketPath) {
95505
95610
  if (outcome === "stale") await rm5(socketPath, { force: true });
95506
95611
  }
95507
95612
  function listen(server, socketPath) {
95508
- return new Promise((resolve8, reject) => {
95613
+ return new Promise((resolve6, reject) => {
95509
95614
  server.once("error", reject);
95510
95615
  server.listen(socketPath, () => {
95511
95616
  server.off("error", reject);
95512
- resolve8();
95617
+ resolve6();
95513
95618
  });
95514
95619
  });
95515
95620
  }
95516
95621
  function closeServer(server) {
95517
- return new Promise((resolve8) => server.close(() => resolve8()));
95622
+ return new Promise((resolve6) => server.close(() => resolve6()));
95518
95623
  }
95519
95624
  function frame(reply) {
95520
95625
  return `${JSON.stringify({ jsonrpc: "2.0", ...reply })}
@@ -95582,14 +95687,14 @@ var Connection = class {
95582
95687
  signal: this.calls.signal,
95583
95688
  afterAnswered: (effect) => answered ? runEffect(effect) : void effects.push(effect)
95584
95689
  };
95585
- let text;
95690
+ let text2;
95586
95691
  try {
95587
95692
  const result = await handler(params, call);
95588
- text = frame({ id, result: result ?? null });
95693
+ text2 = frame({ id, result: result ?? null });
95589
95694
  } catch (error62) {
95590
- text = frame({ id, error: this.failure(error62, method) });
95695
+ text2 = frame({ id, error: this.failure(error62, method) });
95591
95696
  }
95592
- this.write(text, () => {
95697
+ this.write(text2, () => {
95593
95698
  answered = true;
95594
95699
  for (const effect of effects.splice(0)) runEffect(effect);
95595
95700
  });
@@ -95612,13 +95717,13 @@ var Connection = class {
95612
95717
  * way is the client's loss. `onWritten` runs once the line is flushed, or
95613
95718
  * when it cannot be.
95614
95719
  */
95615
- write(text, onWritten) {
95720
+ write(text2, onWritten) {
95616
95721
  if (!this.socket.writable) {
95617
95722
  onWritten?.();
95618
95723
  return;
95619
95724
  }
95620
95725
  try {
95621
- this.socket.write(text, onWritten);
95726
+ this.socket.write(text2, onWritten);
95622
95727
  } catch {
95623
95728
  this.socket.destroy();
95624
95729
  onWritten?.();
@@ -95654,7 +95759,7 @@ async function serveService(socketPath, handlers, options = {}) {
95654
95759
  });
95655
95760
  let closing;
95656
95761
  const shutDown2 = async () => {
95657
- const closed = [...connections].map((socket) => new Promise((resolve8) => socket.once("close", resolve8)));
95762
+ const closed = [...connections].map((socket) => new Promise((resolve6) => socket.once("close", resolve6)));
95658
95763
  for (const socket of connections) socket.destroy();
95659
95764
  await Promise.all(closed);
95660
95765
  await closeServer(server);
@@ -95676,8 +95781,8 @@ var STORAGE_FAILURE_REASON = "the mirror cannot be written; receiving stopped";
95676
95781
  var CONNECTION_LOST_REASON = "the connection to Telegram could not be kept";
95677
95782
  var OTHER_ACCOUNT_REASON = "this mirror belongs to another account";
95678
95783
  function errorLabel(error62) {
95679
- const text = rpcTextOf(error62);
95680
- if (text !== void 0) return text;
95784
+ const text2 = rpcTextOf(error62);
95785
+ if (text2 !== void 0) return text2;
95681
95786
  if (error62 instanceof ToolError) return error62.message;
95682
95787
  return error62 instanceof Error ? error62.name : "unexpected error";
95683
95788
  }
@@ -95753,7 +95858,7 @@ var Ending = class {
95753
95858
  };
95754
95859
  result;
95755
95860
  constructor() {
95756
- this.promise = new Promise((resolve8) => this.resolve = resolve8);
95861
+ this.promise = new Promise((resolve6) => this.resolve = resolve6);
95757
95862
  }
95758
95863
  /** Aborts once the run has ended, so everything waiting on it gives up. */
95759
95864
  get signal() {
@@ -95782,26 +95887,26 @@ function onAbort(signal, fn) {
95782
95887
  signal.addEventListener("abort", fn, { once: true });
95783
95888
  return () => signal.removeEventListener("abort", fn);
95784
95889
  }
95785
- var realPause = (ms, signal) => new Promise((resolve8) => {
95890
+ var realPause = (ms, signal) => new Promise((resolve6) => {
95786
95891
  let stopListening = () => {
95787
95892
  };
95788
95893
  const timer = setTimeout(() => {
95789
95894
  stopListening();
95790
- resolve8();
95895
+ resolve6();
95791
95896
  }, ms);
95792
95897
  stopListening = onAbort(signal, () => {
95793
95898
  clearTimeout(timer);
95794
- resolve8();
95899
+ resolve6();
95795
95900
  });
95796
95901
  });
95797
95902
  function waitThrough(pause, ms, signal) {
95798
95903
  if (signal.aborted) return Promise.resolve();
95799
- return new Promise((resolve8) => {
95800
- const stopListening = onAbort(signal, resolve8);
95904
+ return new Promise((resolve6) => {
95905
+ const stopListening = onAbort(signal, resolve6);
95801
95906
  pause(ms, signal).catch(() => {
95802
95907
  }).finally(() => {
95803
95908
  stopListening();
95804
- resolve8();
95909
+ resolve6();
95805
95910
  });
95806
95911
  });
95807
95912
  }
@@ -95826,9 +95931,9 @@ function cancelled() {
95826
95931
  return new ToolError("upstream_error", "The request was cancelled before Telegram answered.");
95827
95932
  }
95828
95933
  function abortable(promise2, signal) {
95829
- return new Promise((resolve8, reject) => {
95934
+ return new Promise((resolve6, reject) => {
95830
95935
  const stopListening = onAbort(signal, () => reject(cancelled()));
95831
- promise2.then(resolve8, reject).then(stopListening);
95936
+ promise2.then(resolve6, reject).then(stopListening);
95832
95937
  });
95833
95938
  }
95834
95939
  function requestFailure(error62, what, env) {
@@ -96219,9 +96324,8 @@ function applyRead(mirror, read) {
96219
96324
  }
96220
96325
 
96221
96326
  // src/core/telegram/ingest-messages.ts
96222
- var MS_PER_S2 = 1e3;
96223
96327
  function expiryOf(msg) {
96224
- return isCount(msg.ttl) && msg.ttl > 0 ? msg.ts + msg.ttl * MS_PER_S2 : null;
96328
+ return isCount(msg.ttl) && msg.ttl > 0 ? msg.ts + msg.ttl * MS_PER_S : null;
96225
96329
  }
96226
96330
  function findVersion(mirror, chat, id) {
96227
96331
  const row = mirror.prepare("SELECT ts, body, entities, media, edited, expires FROM messages WHERE chat = ? AND id = ?").get(chat, id);
@@ -96578,8 +96682,8 @@ var ChatListRefresh = class {
96578
96682
  }
96579
96683
  begin() {
96580
96684
  let listener;
96581
- const listed = new Promise((resolve8, reject) => {
96582
- listener = { listed: resolve8, failed: reject };
96685
+ const listed = new Promise((resolve6, reject) => {
96686
+ listener = { listed: resolve6, failed: reject };
96583
96687
  });
96584
96688
  listed.catch(() => {
96585
96689
  });
@@ -96759,7 +96863,6 @@ import { Buffer as Buffer8 } from "node:buffer";
96759
96863
  import { open as open6 } from "node:fs/promises";
96760
96864
 
96761
96865
  // src/core/telegram/sync-download-file.ts
96762
- var MS_PER_S3 = 1e3;
96763
96866
  var FILE_KINDS = ["photo", "document", "audio", "voice", "video", "sticker"];
96764
96867
  function isFileMedia(media) {
96765
96868
  return media !== null && FILE_KINDS.includes(media.type);
@@ -96773,7 +96876,7 @@ function messageFile(message2) {
96773
96876
  }
96774
96877
  function disappearsAtOf(message2) {
96775
96878
  const ttl = message2.ttlPeriod;
96776
- return ttl ? message2.date.getTime() + ttl * MS_PER_S3 : void 0;
96879
+ return ttl ? message2.date.getTime() + ttl * MS_PER_S : void 0;
96777
96880
  }
96778
96881
 
96779
96882
  // src/core/telegram/sync-download-refusal.ts
@@ -96801,11 +96904,10 @@ function tooLargeReason(size, maxBytes) {
96801
96904
  // src/core/telegram/sync-download-stream.ts
96802
96905
  import { open as open4 } from "node:fs/promises";
96803
96906
  var FILE_MODE3 = 384;
96804
- var MS_PER_S4 = 1e3;
96805
96907
  function stalled(stallMs) {
96806
96908
  return new ToolError(
96807
96909
  "upstream_error",
96808
- `The download received nothing for ${stallMs / MS_PER_S4} seconds; try again later.`
96910
+ `The download received nothing for ${stallMs / MS_PER_S} seconds; try again later.`
96809
96911
  );
96810
96912
  }
96811
96913
  async function writeAll2(handle, chunk) {
@@ -96814,7 +96916,7 @@ async function writeAll2(handle, chunk) {
96814
96916
  }
96815
96917
  async function writeDownload(ctx, signal, media, file2, max3) {
96816
96918
  const env = { endSession: ctx.endSession, log: ctx.settings.log };
96817
- const stallMs = ctx.settings.downloadStallMs;
96919
+ const stallMs = ctx.settings.transferStallMs;
96818
96920
  const failure2 = (error62) => {
96819
96921
  if (signal.aborted) return cancelled();
96820
96922
  if (error62 instanceof MtTimeoutError && error62.timeout === stallMs) return stalled(stallMs);
@@ -97144,6 +97246,202 @@ var FileKeeper = class {
97144
97246
  }
97145
97247
  };
97146
97248
 
97249
+ // src/core/telegram/sync-options.ts
97250
+ var SECOND_MS2 = 1e3;
97251
+ var MINUTE_MS = 60 * SECOND_MS2;
97252
+ var HOUR_MS = 60 * MINUTE_MS;
97253
+ var DAY_MS = 24 * HOUR_MS;
97254
+ var TRANSFER_STALL_MS = 6e4;
97255
+ var DEFAULT_HEARTBEAT_EVERY_MS = 5 * SECOND_MS2;
97256
+ var DEFAULT_GAP_AFTER_MS = 30 * SECOND_MS2;
97257
+ var DEFAULT_OFFLINE_LIMIT_MS = 10 * MINUTE_MS;
97258
+ var DEFAULT_PURGE_EVERY_MS = HOUR_MS;
97259
+ var DEFAULT_REFRESH_EVERY_MS = 30 * MINUTE_MS;
97260
+ var DEFAULT_REFRESH_RETRY_MS = MINUTE_MS;
97261
+ var DEFAULT_ROUND_EVERY_MS = 5 * SECOND_MS2;
97262
+ var DEFAULT_STOP_WAIT_MS = 10 * SECOND_MS2;
97263
+ var DEFAULT_SEED_WITHIN_MS = 30 * DAY_MS;
97264
+ var DEFAULT_SEED_COUNT = 50;
97265
+ var DEFAULT_SEED_CHATS_PER_ROUND = 20;
97266
+ var DEFAULT_SEED_ATTEMPTS = 3;
97267
+ var DEFAULT_FILL_LIMIT = 200;
97268
+ var DEFAULT_PACE_MS = [500, 1500];
97269
+ function resolveOptions(options) {
97270
+ return {
97271
+ ...options,
97272
+ now: options.now ?? Date.now,
97273
+ pause: options.pause ?? realPause,
97274
+ heartbeatEveryMs: options.heartbeatEveryMs ?? DEFAULT_HEARTBEAT_EVERY_MS,
97275
+ gapAfterMs: options.gapAfterMs ?? DEFAULT_GAP_AFTER_MS,
97276
+ offlineLimitMs: options.offlineLimitMs ?? DEFAULT_OFFLINE_LIMIT_MS,
97277
+ purgeEveryMs: options.purgeEveryMs ?? DEFAULT_PURGE_EVERY_MS,
97278
+ refreshEveryMs: options.refreshEveryMs ?? DEFAULT_REFRESH_EVERY_MS,
97279
+ refreshRetryMs: options.refreshRetryMs ?? DEFAULT_REFRESH_RETRY_MS,
97280
+ roundEveryMs: options.roundEveryMs ?? DEFAULT_ROUND_EVERY_MS,
97281
+ stopWaitMs: options.stopWaitMs ?? DEFAULT_STOP_WAIT_MS,
97282
+ seedWithinMs: options.seedWithinMs ?? DEFAULT_SEED_WITHIN_MS,
97283
+ seedCount: options.seedCount ?? DEFAULT_SEED_COUNT,
97284
+ seedChatsPerRound: options.seedChatsPerRound ?? DEFAULT_SEED_CHATS_PER_ROUND,
97285
+ seedAttempts: options.seedAttempts ?? DEFAULT_SEED_ATTEMPTS,
97286
+ fillLimit: options.fillLimit ?? DEFAULT_FILL_LIMIT,
97287
+ paceMs: options.paceMs ?? DEFAULT_PACE_MS,
97288
+ transferStallMs: options.transferStallMs ?? TRANSFER_STALL_MS
97289
+ };
97290
+ }
97291
+
97292
+ // src/core/telegram/sync-message.ts
97293
+ function readMessage(message2, channels) {
97294
+ const input8 = messageInputOf(message2);
97295
+ if (!input8) return null;
97296
+ const peer = readOrNull(() => message2.chat);
97297
+ const chat = peer ? chatInputOf(peer) : null;
97298
+ if (chat && !keepsKind(chat.kind, channels)) return null;
97299
+ return { chat, message: input8, topic: topicInputOfAction(message2) };
97300
+ }
97301
+ function writeMessage(mirror, ctx, read, channels) {
97302
+ if (read.chat) rememberChats(mirror, [read.chat], ctx.now, channels);
97303
+ if (read.topic) upsertTopics(mirror, [read.topic], ctx.now);
97304
+ return storeMessage(mirror, ctx, read.message);
97305
+ }
97306
+
97307
+ // src/core/telegram/sync-receive.ts
97308
+ var SKIPPED = "skipped";
97309
+ function countsOf(outcomes) {
97310
+ const counts = /* @__PURE__ */ new Map();
97311
+ for (const outcome of outcomes) counts.set(outcome, (counts.get(outcome) ?? 0) + 1);
97312
+ return [...counts].map(([outcome, count]) => `${outcome}=${count}`).join(" ") || "none";
97313
+ }
97314
+ var Receiver = class {
97315
+ deps;
97316
+ keeper;
97317
+ halted = false;
97318
+ constructor(deps) {
97319
+ this.deps = deps;
97320
+ }
97321
+ /**
97322
+ * Registers the handlers on the client's emitters; call it before the client
97323
+ * connects. `keeper` keeps the files of the disappearing messages that
97324
+ * arrive, when `keepDisappearing` is on.
97325
+ */
97326
+ attach(client, keeper) {
97327
+ this.keeper = keeper;
97328
+ client.onNewMessage.add((message2) => this.onMessage("message", message2));
97329
+ client.onEditMessage.add((message2) => this.onMessage("edit", message2));
97330
+ client.onDeleteMessage.add((update) => this.onDelete(update));
97331
+ client.onHistoryRead.add((update) => this.onRead(update));
97332
+ }
97333
+ /** Stops storing: whatever arrives from here on is ignored. */
97334
+ halt() {
97335
+ this.halted = true;
97336
+ }
97337
+ onMessage(label, message2) {
97338
+ const { channels, keepDisappearing } = this.deps;
97339
+ const done = this.process(
97340
+ label,
97341
+ () => readMessage(message2, channels),
97342
+ (read, ctx) => writeMessage(this.deps.mirror, ctx, read, channels)
97343
+ );
97344
+ if (keepDisappearing && label === "message" && done?.outcome === "stored") {
97345
+ this.keeper?.keep(message2, done.prepared.message);
97346
+ }
97347
+ }
97348
+ onDelete(update) {
97349
+ const { mirror, coverage, keepDisappearing } = this.deps;
97350
+ const done = this.process(
97351
+ "delete",
97352
+ () => deleteInputOf(update),
97353
+ (input8, ctx) => {
97354
+ if (input8.chat !== null && !findChat(mirror, input8.chat)?.followed) return SKIPPED;
97355
+ coverage.note(ctx.now);
97356
+ return countsOf(deleteMessages2(mirror, ctx, input8));
97357
+ }
97358
+ );
97359
+ if (keepDisappearing && done && done.outcome !== SKIPPED) {
97360
+ this.keeper?.forgetMessages(done.prepared.chat, done.prepared.ids);
97361
+ }
97362
+ }
97363
+ onRead(update) {
97364
+ this.process(
97365
+ "read",
97366
+ () => readInputOf(update),
97367
+ (input8) => {
97368
+ applyRead(this.deps.mirror, input8);
97369
+ return "applied";
97370
+ }
97371
+ );
97372
+ }
97373
+ /**
97374
+ * Turns the update into `prepared` outside the transaction, so that what
97375
+ * fails there is only mtcute's data, then writes it. `store` names the
97376
+ * outcome for the log. Resolves with `prepared` and the outcome once it is
97377
+ * written, and with null when the update was not (unreadable, not for the
97378
+ * mirror, or a storage failure).
97379
+ */
97380
+ process(label, prepare2, store) {
97381
+ if (this.halted) return null;
97382
+ const { mirror, now, keepDisappearing, log } = this.deps;
97383
+ let prepared;
97384
+ try {
97385
+ prepared = prepare2();
97386
+ } catch (error62) {
97387
+ log(`event: ${label} unreadable (${errorLabel(error62)})`);
97388
+ return null;
97389
+ }
97390
+ if (prepared === null) {
97391
+ log(`event: ${label} ${SKIPPED}`);
97392
+ return null;
97393
+ }
97394
+ let outcome;
97395
+ try {
97396
+ const received = now();
97397
+ outcome = inTransaction(mirror, () => {
97398
+ const result = store(prepared, { now: received, keepDisappearing });
97399
+ if (result !== SKIPPED) setMeta(mirror, { [META.lastReceivedAt]: received });
97400
+ return result;
97401
+ });
97402
+ } catch {
97403
+ this.failStorage();
97404
+ return null;
97405
+ }
97406
+ log(`event: ${label} ${outcome}`);
97407
+ return { prepared, outcome };
97408
+ }
97409
+ failStorage() {
97410
+ if (this.halted) return;
97411
+ this.halted = true;
97412
+ this.deps.onStorageFailure();
97413
+ this.deps.log(STORAGE_FAILURE_REASON);
97414
+ }
97415
+ };
97416
+
97417
+ // src/core/telegram/sync-request-queue.ts
97418
+ var RequestQueue = class {
97419
+ /** Settles when the last job in line is done. It never rejects. */
97420
+ tail = Promise.resolve();
97421
+ /**
97422
+ * Runs `work` once the jobs ahead are done. Rejects as `cancelled()`, without
97423
+ * running `work`, when `signal` aborts first; the jobs behind it then wait
97424
+ * for the ones ahead of it, as they would have.
97425
+ */
97426
+ async run(signal, work) {
97427
+ const ahead = this.tail;
97428
+ let done = () => {
97429
+ };
97430
+ this.tail = new Promise((resolve6) => done = resolve6);
97431
+ try {
97432
+ await abortable(ahead, signal);
97433
+ } catch (error62) {
97434
+ void ahead.then(done);
97435
+ throw error62;
97436
+ }
97437
+ try {
97438
+ return await work();
97439
+ } finally {
97440
+ done();
97441
+ }
97442
+ }
97443
+ };
97444
+
97147
97445
  // src/core/telegram/sync-request-calls.ts
97148
97446
  async function viaTelegram(ctx, call, what, work) {
97149
97447
  const signal = AbortSignal.any([call.signal, ctx.signal]);
@@ -97276,12 +97574,12 @@ function parseDownloadParams(params) {
97276
97574
  };
97277
97575
  }
97278
97576
  function sendTextAt(fields) {
97279
- const { text } = fields;
97280
- if (typeof text !== "string") throw invalid("text must be a string.");
97281
- if (text.trim() === "") throw invalid("text must not be blank.");
97282
- if (text !== text.trim()) throw invalid("text must not start or end with blank space.");
97283
- if (text.length > TEXT_MAX_UNITS) throw invalid(`text must be at most ${TEXT_MAX_UNITS} characters.`);
97284
- return text;
97577
+ const { text: text2 } = fields;
97578
+ if (typeof text2 !== "string") throw invalid("text must be a string.");
97579
+ if (text2.trim() === "") throw invalid("text must not be blank.");
97580
+ if (text2 !== text2.trim()) throw invalid("text must not start or end with blank space.");
97581
+ if (text2.length > TEXT_MAX_UNITS) throw invalid(`text must be at most ${TEXT_MAX_UNITS} characters.`);
97582
+ return text2;
97285
97583
  }
97286
97584
  function parseSendParams(params) {
97287
97585
  const fields = recordOf(params, SEND_KEYS, "The send parameters");
@@ -97404,7 +97702,6 @@ function expectNoParams(params, what) {
97404
97702
  }
97405
97703
 
97406
97704
  // src/core/telegram/sync-download.ts
97407
- var DOWNLOAD_STALL_MS = 6e4;
97408
97705
  function fileOf(message2, id) {
97409
97706
  const file2 = messageFile(message2);
97410
97707
  if (!file2) {
@@ -97478,201 +97775,6 @@ function downloadRequest(ctx, queue, raw, call) {
97478
97775
  return keptCopy(ctx, params).then((kept) => kept ?? queue.run(signal, () => downloadFile(ctx, call, signal, params)));
97479
97776
  }
97480
97777
 
97481
- // src/core/telegram/sync-options.ts
97482
- var SECOND_MS2 = 1e3;
97483
- var MINUTE_MS = 60 * SECOND_MS2;
97484
- var HOUR_MS = 60 * MINUTE_MS;
97485
- var DAY_MS = 24 * HOUR_MS;
97486
- var DEFAULT_HEARTBEAT_EVERY_MS = 5 * SECOND_MS2;
97487
- var DEFAULT_GAP_AFTER_MS = 30 * SECOND_MS2;
97488
- var DEFAULT_OFFLINE_LIMIT_MS = 10 * MINUTE_MS;
97489
- var DEFAULT_PURGE_EVERY_MS = HOUR_MS;
97490
- var DEFAULT_REFRESH_EVERY_MS = 30 * MINUTE_MS;
97491
- var DEFAULT_REFRESH_RETRY_MS = MINUTE_MS;
97492
- var DEFAULT_ROUND_EVERY_MS = 5 * SECOND_MS2;
97493
- var DEFAULT_STOP_WAIT_MS = 10 * SECOND_MS2;
97494
- var DEFAULT_SEED_WITHIN_MS = 30 * DAY_MS;
97495
- var DEFAULT_SEED_COUNT = 50;
97496
- var DEFAULT_SEED_CHATS_PER_ROUND = 20;
97497
- var DEFAULT_SEED_ATTEMPTS = 3;
97498
- var DEFAULT_FILL_LIMIT = 200;
97499
- var DEFAULT_PACE_MS = [500, 1500];
97500
- function resolveOptions(options) {
97501
- return {
97502
- ...options,
97503
- now: options.now ?? Date.now,
97504
- pause: options.pause ?? realPause,
97505
- heartbeatEveryMs: options.heartbeatEveryMs ?? DEFAULT_HEARTBEAT_EVERY_MS,
97506
- gapAfterMs: options.gapAfterMs ?? DEFAULT_GAP_AFTER_MS,
97507
- offlineLimitMs: options.offlineLimitMs ?? DEFAULT_OFFLINE_LIMIT_MS,
97508
- purgeEveryMs: options.purgeEveryMs ?? DEFAULT_PURGE_EVERY_MS,
97509
- refreshEveryMs: options.refreshEveryMs ?? DEFAULT_REFRESH_EVERY_MS,
97510
- refreshRetryMs: options.refreshRetryMs ?? DEFAULT_REFRESH_RETRY_MS,
97511
- roundEveryMs: options.roundEveryMs ?? DEFAULT_ROUND_EVERY_MS,
97512
- stopWaitMs: options.stopWaitMs ?? DEFAULT_STOP_WAIT_MS,
97513
- seedWithinMs: options.seedWithinMs ?? DEFAULT_SEED_WITHIN_MS,
97514
- seedCount: options.seedCount ?? DEFAULT_SEED_COUNT,
97515
- seedChatsPerRound: options.seedChatsPerRound ?? DEFAULT_SEED_CHATS_PER_ROUND,
97516
- seedAttempts: options.seedAttempts ?? DEFAULT_SEED_ATTEMPTS,
97517
- fillLimit: options.fillLimit ?? DEFAULT_FILL_LIMIT,
97518
- paceMs: options.paceMs ?? DEFAULT_PACE_MS,
97519
- downloadStallMs: options.downloadStallMs ?? DOWNLOAD_STALL_MS
97520
- };
97521
- }
97522
-
97523
- // src/core/telegram/sync-message.ts
97524
- function readMessage(message2, channels) {
97525
- const input8 = messageInputOf(message2);
97526
- if (!input8) return null;
97527
- const peer = readOrNull(() => message2.chat);
97528
- const chat = peer ? chatInputOf(peer) : null;
97529
- if (chat && !keepsKind(chat.kind, channels)) return null;
97530
- return { chat, message: input8, topic: topicInputOfAction(message2) };
97531
- }
97532
- function writeMessage(mirror, ctx, read, channels) {
97533
- if (read.chat) rememberChats(mirror, [read.chat], ctx.now, channels);
97534
- if (read.topic) upsertTopics(mirror, [read.topic], ctx.now);
97535
- return storeMessage(mirror, ctx, read.message);
97536
- }
97537
-
97538
- // src/core/telegram/sync-receive.ts
97539
- var SKIPPED = "skipped";
97540
- function countsOf(outcomes) {
97541
- const counts = /* @__PURE__ */ new Map();
97542
- for (const outcome of outcomes) counts.set(outcome, (counts.get(outcome) ?? 0) + 1);
97543
- return [...counts].map(([outcome, count]) => `${outcome}=${count}`).join(" ") || "none";
97544
- }
97545
- var Receiver = class {
97546
- deps;
97547
- keeper;
97548
- halted = false;
97549
- constructor(deps) {
97550
- this.deps = deps;
97551
- }
97552
- /**
97553
- * Registers the handlers on the client's emitters; call it before the client
97554
- * connects. `keeper` keeps the files of the disappearing messages that
97555
- * arrive, when `keepDisappearing` is on.
97556
- */
97557
- attach(client, keeper) {
97558
- this.keeper = keeper;
97559
- client.onNewMessage.add((message2) => this.onMessage("message", message2));
97560
- client.onEditMessage.add((message2) => this.onMessage("edit", message2));
97561
- client.onDeleteMessage.add((update) => this.onDelete(update));
97562
- client.onHistoryRead.add((update) => this.onRead(update));
97563
- }
97564
- /** Stops storing: whatever arrives from here on is ignored. */
97565
- halt() {
97566
- this.halted = true;
97567
- }
97568
- onMessage(label, message2) {
97569
- const { channels, keepDisappearing } = this.deps;
97570
- const done = this.process(
97571
- label,
97572
- () => readMessage(message2, channels),
97573
- (read, ctx) => writeMessage(this.deps.mirror, ctx, read, channels)
97574
- );
97575
- if (keepDisappearing && label === "message" && done?.outcome === "stored") {
97576
- this.keeper?.keep(message2, done.prepared.message);
97577
- }
97578
- }
97579
- onDelete(update) {
97580
- const { mirror, coverage, keepDisappearing } = this.deps;
97581
- const done = this.process(
97582
- "delete",
97583
- () => deleteInputOf(update),
97584
- (input8, ctx) => {
97585
- if (input8.chat !== null && !findChat(mirror, input8.chat)?.followed) return SKIPPED;
97586
- coverage.note(ctx.now);
97587
- return countsOf(deleteMessages2(mirror, ctx, input8));
97588
- }
97589
- );
97590
- if (keepDisappearing && done && done.outcome !== SKIPPED) {
97591
- this.keeper?.forgetMessages(done.prepared.chat, done.prepared.ids);
97592
- }
97593
- }
97594
- onRead(update) {
97595
- this.process(
97596
- "read",
97597
- () => readInputOf(update),
97598
- (input8) => {
97599
- applyRead(this.deps.mirror, input8);
97600
- return "applied";
97601
- }
97602
- );
97603
- }
97604
- /**
97605
- * Turns the update into `prepared` outside the transaction, so that what
97606
- * fails there is only mtcute's data, then writes it. `store` names the
97607
- * outcome for the log. Resolves with `prepared` and the outcome once it is
97608
- * written, and with null when the update was not (unreadable, not for the
97609
- * mirror, or a storage failure).
97610
- */
97611
- process(label, prepare2, store) {
97612
- if (this.halted) return null;
97613
- const { mirror, now, keepDisappearing, log } = this.deps;
97614
- let prepared;
97615
- try {
97616
- prepared = prepare2();
97617
- } catch (error62) {
97618
- log(`event: ${label} unreadable (${errorLabel(error62)})`);
97619
- return null;
97620
- }
97621
- if (prepared === null) {
97622
- log(`event: ${label} ${SKIPPED}`);
97623
- return null;
97624
- }
97625
- let outcome;
97626
- try {
97627
- const received = now();
97628
- outcome = inTransaction(mirror, () => {
97629
- const result = store(prepared, { now: received, keepDisappearing });
97630
- if (result !== SKIPPED) setMeta(mirror, { [META.lastReceivedAt]: received });
97631
- return result;
97632
- });
97633
- } catch {
97634
- this.failStorage();
97635
- return null;
97636
- }
97637
- log(`event: ${label} ${outcome}`);
97638
- return { prepared, outcome };
97639
- }
97640
- failStorage() {
97641
- if (this.halted) return;
97642
- this.halted = true;
97643
- this.deps.onStorageFailure();
97644
- this.deps.log(STORAGE_FAILURE_REASON);
97645
- }
97646
- };
97647
-
97648
- // src/core/telegram/sync-request-queue.ts
97649
- var RequestQueue = class {
97650
- /** Settles when the last job in line is done. It never rejects. */
97651
- tail = Promise.resolve();
97652
- /**
97653
- * Runs `work` once the jobs ahead are done. Rejects as `cancelled()`, without
97654
- * running `work`, when `signal` aborts first; the jobs behind it then wait
97655
- * for the ones ahead of it, as they would have.
97656
- */
97657
- async run(signal, work) {
97658
- const ahead = this.tail;
97659
- let done = () => {
97660
- };
97661
- this.tail = new Promise((resolve8) => done = resolve8);
97662
- try {
97663
- await abortable(ahead, signal);
97664
- } catch (error62) {
97665
- void ahead.then(done);
97666
- throw error62;
97667
- }
97668
- try {
97669
- return await work();
97670
- } finally {
97671
- done();
97672
- }
97673
- }
97674
- };
97675
-
97676
97778
  // src/core/telegram/sync-list-requests.ts
97677
97779
  function expectListable({ mirror, settings }, chats) {
97678
97780
  for (const id of chats) {
@@ -97724,7 +97826,6 @@ async function syncRemove(ctx, raw) {
97724
97826
  }
97725
97827
 
97726
97828
  // src/core/telegram/sync-send-outcome.ts
97727
- var MS_PER_S5 = 1e3;
97728
97829
  var RANDOM_ID_DUPLICATE = "RANDOM_ID_DUPLICATE";
97729
97830
  var CALL_TIMEOUT = "TIMEOUT";
97730
97831
  var REFUSAL_CODES = [400, 403, 406];
@@ -97764,9 +97865,9 @@ function refusedSend(code, what, name) {
97764
97865
  return new ToolError(code, `${what} (${name}); nothing was sent.`);
97765
97866
  }
97766
97867
  function rateLimitSecondsOf(error62) {
97767
- const text = String(error62.text);
97768
- if (!RATE_LIMIT_ERRORS.includes(text.replace(/\d+$/, "%d"))) return void 0;
97769
- const digits = /\d+$/.exec(text);
97868
+ const text2 = String(error62.text);
97869
+ if (!RATE_LIMIT_ERRORS.includes(text2.replace(/\d+$/, "%d"))) return void 0;
97870
+ const digits = /\d+$/.exec(text2);
97770
97871
  return floodWaitSecondsOf(error62) ?? (digits ? Number(digits[0]) : void 0);
97771
97872
  }
97772
97873
  function refusalOf(error62) {
@@ -97807,7 +97908,7 @@ function sentMessageOf(response, randomId) {
97807
97908
  return {
97808
97909
  form: "short",
97809
97910
  id: response.id,
97810
- date: response.date * MS_PER_S5,
97911
+ date: response.date * MS_PER_S,
97811
97912
  ttl: response.ttlPeriod ?? null,
97812
97913
  entities: response.entities ?? []
97813
97914
  };
@@ -97898,8 +97999,8 @@ function checkSendable(mirror, { chat, topic, reply_to }) {
97898
97999
  throw new ToolError("not_found", `No message ${reply_to} in this chat to reply to; nothing was sent.`);
97899
98000
  }
97900
98001
  }
97901
- function deliveredId(mirror, chat, text, startedAt) {
97902
- const rows = mirror.prepare("SELECT id FROM messages WHERE chat = ? AND from_me = 1 AND body = ? AND ts >= ? LIMIT 2").all(chat, text, startedAt - DUPLICATE_LOOKBACK_MS);
98002
+ function deliveredId(mirror, chat, text2, startedAt) {
98003
+ const rows = mirror.prepare("SELECT id FROM messages WHERE chat = ? AND from_me = 1 AND body = ? AND ts >= ? LIMIT 2").all(chat, text2, startedAt - DUPLICATE_LOOKBACK_MS);
97903
98004
  return rows.length === 1 ? rows[0].id : void 0;
97904
98005
  }
97905
98006
  function deliveredFileIds(mirror, chat, files, startedAt) {
@@ -97973,9 +98074,9 @@ function replyToOf({
97973
98074
  return { _: "inputReplyToMessage", replyToMsgId, ...inTopic2 === void 0 ? {} : { topMsgId: inTopic2 } };
97974
98075
  }
97975
98076
  function untilAborted(promise2, signal) {
97976
- return new Promise((resolve8, reject) => {
98077
+ return new Promise((resolve6, reject) => {
97977
98078
  const stopListening = onAbort(signal, () => reject(signal.reason));
97978
- promise2.then(resolve8, reject).then(stopListening);
98079
+ promise2.then(resolve6, reject).then(stopListening);
97979
98080
  });
97980
98081
  }
97981
98082
  async function callOnce(ctx, signal, what, call, settle3) {
@@ -98075,12 +98176,27 @@ function sendRequest(ctx, queue, raw, call) {
98075
98176
  }
98076
98177
 
98077
98178
  // src/core/telegram/sync-action.ts
98078
- function performAction(ctx, signal, refusals, call) {
98179
+ function runAction(ctx, queue, raw, call, parse6, act) {
98180
+ const params = parse6(raw);
98181
+ const signal = AbortSignal.any([call.signal, ctx.signal]);
98182
+ return queue.run(signal, () => act(params, signal));
98183
+ }
98184
+ async function resolveChatPeer(ctx, call, signal, what, chat) {
98185
+ const peer = await viaTelegram(ctx, call, what, () => ctx.client.resolvePeer(Number(chat)));
98186
+ if (signal.aborted) throw cancelled();
98187
+ return peer;
98188
+ }
98189
+ function inputChannelOf(peer) {
98190
+ if (peer._ !== "inputPeerChannel") return void 0;
98191
+ const { channelId, accessHash } = peer;
98192
+ return { _: "inputChannel", channelId, accessHash };
98193
+ }
98194
+ function performAction(ctx, signal, refusals, request) {
98079
98195
  return callOnce(
98080
98196
  ctx,
98081
98197
  signal,
98082
98198
  refusals.words.name,
98083
- call,
98199
+ (options) => ctx.client.call(request, options),
98084
98200
  (error62, trouble) => actionFailureOf(error62, trouble, refusals)
98085
98201
  );
98086
98202
  }
@@ -98161,10 +98277,9 @@ var DELETE_REFUSALS = {
98161
98277
  }
98162
98278
  ]
98163
98279
  };
98164
- function requestOf(peer, id) {
98165
- if (peer._ !== "inputPeerChannel") return { _: "messages.deleteMessages", revoke: true, id: [id] };
98166
- const { channelId, accessHash } = peer;
98167
- return { _: "channels.deleteMessages", channel: { _: "inputChannel", channelId, accessHash }, id: [id] };
98280
+ function requestOf(channel, id) {
98281
+ if (!channel) return { _: "messages.deleteMessages", revoke: true, id: [id] };
98282
+ return { _: "channels.deleteMessages", channel, id: [id] };
98168
98283
  }
98169
98284
  function recordDelete(ctx, { id: chat, kind }, id) {
98170
98285
  recordAction(ctx, "delete", () => {
@@ -98180,22 +98295,17 @@ function recordDelete(ctx, { id: chat, kind }, id) {
98180
98295
  async function deleteOwn(ctx, call, signal, params) {
98181
98296
  const { chat, message: message2 } = targetOf(ctx.mirror, params.chat, params.id, DELETE_WORDS);
98182
98297
  if (!message2) return { id: params.id, deleted: true, already: true };
98183
- const peer = await viaTelegram(ctx, call, "delete", () => ctx.client.resolvePeer(Number(params.chat)));
98184
- if (signal.aborted) throw cancelled();
98185
- const request = requestOf(peer, params.id);
98186
- const affected = await performAction(ctx, signal, DELETE_REFUSALS, (options) => ctx.client.call(request, options));
98187
- if (affected) handOverAffected(ctx, "delete", affected, peer._ === "inputPeerChannel" ? peer.channelId : void 0);
98298
+ const channel = inputChannelOf(await resolveChatPeer(ctx, call, signal, "delete", params.chat));
98299
+ const affected = await performAction(ctx, signal, DELETE_REFUSALS, requestOf(channel, params.id));
98300
+ if (affected) handOverAffected(ctx, "delete", affected, channel?.channelId);
98188
98301
  recordDelete(ctx, chat, params.id);
98189
98302
  return { id: params.id, deleted: true, ...!affected || affected.ptsCount === 0 ? { already: true } : {} };
98190
98303
  }
98191
98304
  function deleteRequest(ctx, queue, raw, call) {
98192
- const params = parseDeleteParams(raw);
98193
- const signal = AbortSignal.any([call.signal, ctx.signal]);
98194
- return queue.run(signal, () => deleteOwn(ctx, call, signal, params));
98305
+ return runAction(ctx, queue, raw, call, parseDeleteParams, (params, signal) => deleteOwn(ctx, call, signal, params));
98195
98306
  }
98196
98307
 
98197
98308
  // src/core/telegram/sync-edit.ts
98198
- var MS_PER_S6 = 1e3;
98199
98309
  var EDIT_WORDS = {
98200
98310
  name: "edit",
98201
98311
  gerund: "editing",
@@ -98218,10 +98328,10 @@ var EDIT_REFUSALS = {
98218
98328
  { names: ["MEDIA_CAPTION_TOO_LONG"], code: "invalid_argument", what: "Telegram refused the caption" }
98219
98329
  ]
98220
98330
  };
98221
- function refuseUneditable({ message: message2 }, text) {
98331
+ function refuseUneditable({ message: message2 }, text2) {
98222
98332
  if (!message2) throw deletedMessage();
98223
98333
  const captioned = message2.media !== null && takesCaption(JSON.parse(message2.media).type);
98224
- checkEditable({ ...message2, captioned }, text);
98334
+ checkEditable({ ...message2, captioned }, text2);
98225
98335
  }
98226
98336
  function editedOf(group, id) {
98227
98337
  for (const update of group.updates) {
@@ -98238,10 +98348,10 @@ function recordEdit(ctx, { chat }, raw, group) {
98238
98348
  recordSent(ctx.mirror, { now: now(), keepDisappearing }, read, channels);
98239
98349
  });
98240
98350
  }
98241
- function alreadyResult(ctx, { chat, id, text }) {
98351
+ function alreadyResult(ctx, { chat, id, text: text2 }) {
98242
98352
  try {
98243
98353
  const stored = storedMessageOf(ctx.mirror, chat, id);
98244
- if (stored?.body === text && stored.edited !== null) return { id, edited: stored.edited, already: true };
98354
+ if (stored?.body === text2 && stored.edited !== null) return { id, edited: stored.edited, already: true };
98245
98355
  } catch (error62) {
98246
98356
  ctx.settings.log(`edit: the mirror could not be read (${errorLabel(error62)})`);
98247
98357
  }
@@ -98255,25 +98365,22 @@ function acceptedResult2(ctx, params, response) {
98255
98365
  throw uncertainAction(EDIT_WORDS, "Telegram's answer did not name the edited message");
98256
98366
  }
98257
98367
  recordEdit(ctx, params, raw, group);
98258
- return { id: params.id, edited: raw.editDate * MS_PER_S6 };
98368
+ return { id: params.id, edited: raw.editDate * MS_PER_S };
98259
98369
  }
98260
98370
  async function editText(ctx, call, signal, params) {
98261
98371
  refuseUneditable(targetOf(ctx.mirror, params.chat, params.id, EDIT_WORDS), params.text);
98262
- const peer = await viaTelegram(ctx, call, "edit", () => ctx.client.resolvePeer(Number(params.chat)));
98263
- if (signal.aborted) throw cancelled();
98372
+ const peer = await resolveChatPeer(ctx, call, signal, "edit", params.chat);
98264
98373
  const request = {
98265
98374
  _: "messages.editMessage",
98266
98375
  peer,
98267
98376
  id: params.id,
98268
98377
  message: params.text
98269
98378
  };
98270
- const response = await performAction(ctx, signal, EDIT_REFUSALS, (options) => ctx.client.call(request, options));
98379
+ const response = await performAction(ctx, signal, EDIT_REFUSALS, request);
98271
98380
  return response === void 0 ? alreadyResult(ctx, params) : acceptedResult2(ctx, params, response);
98272
98381
  }
98273
98382
  function editRequest(ctx, queue, raw, call) {
98274
- const params = parseEditParams(raw);
98275
- const signal = AbortSignal.any([call.signal, ctx.signal]);
98276
- return queue.run(signal, () => editText(ctx, call, signal, params));
98383
+ return runAction(ctx, queue, raw, call, parseEditParams, (params, signal) => editText(ctx, call, signal, params));
98277
98384
  }
98278
98385
 
98279
98386
  // src/core/telegram/sync-mark-read.ts
@@ -98290,9 +98397,9 @@ var MARK_READ_REFUSALS = {
98290
98397
  };
98291
98398
  function requestOf2(peer, { up_to, topic }) {
98292
98399
  if (topic !== void 0) return { _: "messages.readDiscussion", peer, msgId: topic, readMaxId: up_to };
98293
- if (peer._ !== "inputPeerChannel") return { _: "messages.readHistory", peer, maxId: up_to };
98294
- const { channelId, accessHash } = peer;
98295
- return { _: "channels.readHistory", channel: { _: "inputChannel", channelId, accessHash }, maxId: up_to };
98400
+ const channel = inputChannelOf(peer);
98401
+ if (!channel) return { _: "messages.readHistory", peer, maxId: up_to };
98402
+ return { _: "channels.readHistory", channel, maxId: up_to };
98296
98403
  }
98297
98404
  function unreadPast(mirror, chat, readMax) {
98298
98405
  const row = mirror.prepare("SELECT COUNT(*) AS unread FROM messages WHERE chat = ? AND from_me = 0 AND id > ?").get(chat, readMax);
@@ -98318,23 +98425,19 @@ async function markRead(ctx, call, signal, params) {
98318
98425
  checkInTopic(message2.topic, topic, MARK_READ_WORDS.past);
98319
98426
  const done = { chat, up_to, ...topic === void 0 ? {} : { topic } };
98320
98427
  if (topic === void 0 && row.read_max !== null && row.read_max >= up_to) return { ...done, already: true };
98321
- const peer = await viaTelegram(ctx, call, "mark read", () => ctx.client.resolvePeer(Number(chat)));
98322
- if (signal.aborted) throw cancelled();
98323
- const request = requestOf2(peer, params);
98428
+ const peer = await resolveChatPeer(ctx, call, signal, "mark read", chat);
98324
98429
  const answer = await performAction(
98325
98430
  ctx,
98326
98431
  signal,
98327
98432
  MARK_READ_REFUSALS,
98328
- (options) => ctx.client.call(request, options)
98433
+ requestOf2(peer, params)
98329
98434
  );
98330
98435
  if (typeof answer === "object") handOverAffected(ctx, "mark read", answer);
98331
98436
  if (topic === void 0) recordRead(ctx, params);
98332
98437
  return done;
98333
98438
  }
98334
98439
  function markReadRequest(ctx, queue, raw, call) {
98335
- const params = parseMarkReadParams(raw);
98336
- const signal = AbortSignal.any([call.signal, ctx.signal]);
98337
- return queue.run(signal, () => markRead(ctx, call, signal, params));
98440
+ return runAction(ctx, queue, raw, call, parseMarkReadParams, (params, signal) => markRead(ctx, call, signal, params));
98338
98441
  }
98339
98442
 
98340
98443
  // src/core/telegram/sync-pin.ts
@@ -98384,8 +98487,7 @@ async function pinMessage2(ctx, call, signal, params) {
98384
98487
  const unpin = params.unpin === true;
98385
98488
  const { chat } = anyMessageOf(ctx.mirror, params.chat, params.id, unpin ? UNPIN_WORDS : PIN_WORDS);
98386
98489
  checkBothSides(chat.kind, params.both_sides);
98387
- const peer = await viaTelegram(ctx, call, "pin", () => ctx.client.resolvePeer(Number(params.chat)));
98388
- if (signal.aborted) throw cancelled();
98490
+ const peer = await resolveChatPeer(ctx, call, signal, "pin", params.chat);
98389
98491
  const request = {
98390
98492
  _: "messages.updatePinnedMessage",
98391
98493
  peer,
@@ -98394,21 +98496,14 @@ async function pinMessage2(ctx, call, signal, params) {
98394
98496
  ...unpin ? { unpin } : {},
98395
98497
  ...isPrivateChat(chat.kind) && !params.both_sides ? { pmOneside: true } : {}
98396
98498
  };
98397
- const response = await performAction(
98398
- ctx,
98399
- signal,
98400
- unpin ? UNPIN_REFUSALS : PIN_REFUSALS,
98401
- (options) => ctx.client.call(request, options)
98402
- );
98499
+ const response = await performAction(ctx, signal, unpin ? UNPIN_REFUSALS : PIN_REFUSALS, request);
98403
98500
  if (response === void 0) return { id: params.id, pinned: !unpin, already: true };
98404
98501
  handOver(ctx, response, "pin");
98405
98502
  recordServiceMessages(ctx, params.chat, response);
98406
98503
  return { id: params.id, pinned: !unpin };
98407
98504
  }
98408
98505
  function pinRequest(ctx, queue, raw, call) {
98409
- const params = parsePinParams(raw);
98410
- const signal = AbortSignal.any([call.signal, ctx.signal]);
98411
- return queue.run(signal, () => pinMessage2(ctx, call, signal, params));
98506
+ return runAction(ctx, queue, raw, call, parsePinParams, (params, signal) => pinMessage2(ctx, call, signal, params));
98412
98507
  }
98413
98508
 
98414
98509
  // src/core/telegram/sync-react.ts
@@ -98474,24 +98569,21 @@ async function reactTo(ctx, call, signal, params) {
98474
98569
  if (params.emoji !== void 0 && ownReaction(storedReactions(message2.reactions)) === params.emoji) {
98475
98570
  return { ...doneOf(params), already: true };
98476
98571
  }
98477
- const peer = await viaTelegram(ctx, call, "react", () => ctx.client.resolvePeer(Number(params.chat)));
98478
- if (signal.aborted) throw cancelled();
98572
+ const peer = await resolveChatPeer(ctx, call, signal, "react", params.chat);
98479
98573
  const request = {
98480
98574
  _: "messages.sendReaction",
98481
98575
  peer,
98482
98576
  msgId: params.id,
98483
98577
  reaction: params.emoji === void 0 ? [] : [{ _: "reactionEmoji", emoticon: params.emoji }]
98484
98578
  };
98485
- const response = await performAction(ctx, signal, REACT_REFUSALS, (options) => ctx.client.call(request, options));
98579
+ const response = await performAction(ctx, signal, REACT_REFUSALS, request);
98486
98580
  if (response === void 0) return { ...doneOf(params), already: true };
98487
98581
  handOver(ctx, response, "react");
98488
98582
  recordReaction(ctx, params, response);
98489
98583
  return doneOf(params);
98490
98584
  }
98491
98585
  function reactRequest(ctx, queue, raw, call) {
98492
- const params = parseReactParams(raw);
98493
- const signal = AbortSignal.any([call.signal, ctx.signal]);
98494
- return queue.run(signal, () => reactTo(ctx, call, signal, params));
98586
+ return runAction(ctx, queue, raw, call, parseReactParams, (params, signal) => reactTo(ctx, call, signal, params));
98495
98587
  }
98496
98588
 
98497
98589
  // src/core/telegram/sync-send-outbox.ts
@@ -98567,7 +98659,7 @@ function uploadFailure(ctx, signal, error62, name) {
98567
98659
  return refusal ?? new ToolError("upstream_error", `The upload of ${name} failed (${errorLabel(error62)}); nothing was sent.`);
98568
98660
  }
98569
98661
  async function uploadOne(ctx, signal, file2) {
98570
- const stallMs = ctx.settings.downloadStallMs;
98662
+ const stallMs = ctx.settings.transferStallMs;
98571
98663
  const stall = new AbortController();
98572
98664
  const uploadSignal = AbortSignal.any([signal, stall.signal]);
98573
98665
  let stalled2 = false;
@@ -99158,6 +99250,7 @@ function toolContext(command, io) {
99158
99250
  downloadMaxMb: command.downloadMaxMb,
99159
99251
  sendDirs: command.sendDirs,
99160
99252
  programName: PROJECT.name,
99253
+ options: command.options,
99161
99254
  signal: io.signal
99162
99255
  };
99163
99256
  }
@@ -99199,16 +99292,18 @@ function parseCommand(argv, io) {
99199
99292
  if (cwd === void 0) throw usageError2(`Command ${name} needs ${CWD_FLAG} <dir>.`);
99200
99293
  if (name === "target") {
99201
99294
  const { value: language, rest: afterLanguage } = takeFlag(rest, LANGUAGE_FLAG);
99202
- const { value: harnessLanguage, rest: settingFlags2 } = takeFlag(afterLanguage, HARNESS_LANGUAGE_FLAG);
99203
- const settings2 = parseToolSettings(settingFlags2, io.env, profile);
99295
+ const { value: harnessLanguage, rest: optionFlags } = takeFlag(afterLanguage, HARNESS_LANGUAGE_FLAG);
99296
+ const parsedOptions = parseToolOptions(optionFlags, io.env, profile);
99297
+ const directories = resolveDirectorySettings(parsedOptions, io.env, profile);
99204
99298
  return {
99205
99299
  name,
99206
99300
  toolId,
99207
99301
  cwd,
99208
- stateDir: settings2.state_dir,
99209
- downloadDir: settings2.download_dir,
99210
- downloadMaxMb: settings2.download_max_mb,
99211
- sendDirs: settings2.send_dirs,
99302
+ stateDir: directories.state_dir,
99303
+ downloadDir: directories.download_dir,
99304
+ downloadMaxMb: directories.download_max_mb,
99305
+ sendDirs: directories.send_dirs,
99306
+ options: parsedOptions,
99212
99307
  language: promptLanguage(language, io.env, harnessLanguage, profile)
99213
99308
  };
99214
99309
  }
@@ -99226,7 +99321,8 @@ function parseCommand(argv, io) {
99226
99321
  stateDir: settings.state_dir,
99227
99322
  downloadDir: settings.download_dir,
99228
99323
  downloadMaxMb: settings.download_max_mb,
99229
- sendDirs: settings.send_dirs
99324
+ sendDirs: settings.send_dirs,
99325
+ options: settings.options
99230
99326
  };
99231
99327
  }
99232
99328
  function describeSpec(spec) {
@@ -99251,10 +99347,10 @@ function writeError(io, code, message2, details) {
99251
99347
  return EXIT_FAILED;
99252
99348
  }
99253
99349
  async function readArguments(io) {
99254
- const text = await io.readStdin();
99255
- if (text.trim() === "") return {};
99350
+ const text2 = await io.readStdin();
99351
+ if (text2.trim() === "") return {};
99256
99352
  try {
99257
- return JSON.parse(text);
99353
+ return JSON.parse(text2);
99258
99354
  } catch (error62) {
99259
99355
  throw new ToolError("invalid_argument", "The arguments on standard input are not valid JSON.", { cause: error62 });
99260
99356
  }
@@ -99354,8 +99450,8 @@ async function main() {
99354
99450
  env: process.env,
99355
99451
  ownDir: packageRoot(import.meta.url),
99356
99452
  readStdin,
99357
- stdout: (text) => process.stdout.write(text),
99358
- stderr: (text) => process.stderr.write(text),
99453
+ stdout: (text2) => process.stdout.write(text2),
99454
+ stderr: (text2) => process.stderr.write(text2),
99359
99455
  signal: controller.signal
99360
99456
  });
99361
99457
  if (argv[0] === "target") process.stdout.write("", () => process.stderr.write("", () => process.exit()));