@integrity-labs/agt-cli 0.20.9 → 0.21.1

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.
@@ -13871,12 +13871,18 @@ var TERMINAL_EMOJI = {
13871
13871
  completed: "\u2705",
13872
13872
  failed: "\u274C"
13873
13873
  };
13874
- function formatWallClock(ms) {
13875
- const d = new Date(ms);
13876
- const hh = String(d.getUTCHours()).padStart(2, "0");
13877
- const mm = String(d.getUTCMinutes()).padStart(2, "0");
13878
- const ss = String(d.getUTCSeconds()).padStart(2, "0");
13879
- return `${hh}:${mm}:${ss} UTC`;
13874
+ function formatWallClock(ms, timeZone) {
13875
+ const fmt = new Intl.DateTimeFormat("en-GB", {
13876
+ hour: "2-digit",
13877
+ minute: "2-digit",
13878
+ second: "2-digit",
13879
+ hour12: false,
13880
+ timeZone,
13881
+ timeZoneName: "short"
13882
+ });
13883
+ const parts = fmt.formatToParts(new Date(ms));
13884
+ const get = (t) => parts.find((p) => p.type === t)?.value ?? "";
13885
+ return `${get("hour")}:${get("minute")}:${get("second")} ${get("timeZoneName")}`;
13880
13886
  }
13881
13887
  function renderProgressMarkdown(state) {
13882
13888
  const lines = [];
@@ -14333,12 +14333,18 @@ var TERMINAL_EMOJI = {
14333
14333
  completed: "\u2705",
14334
14334
  failed: "\u274C"
14335
14335
  };
14336
- function formatWallClock(ms) {
14337
- const d = new Date(ms);
14338
- const hh = String(d.getUTCHours()).padStart(2, "0");
14339
- const mm = String(d.getUTCMinutes()).padStart(2, "0");
14340
- const ss = String(d.getUTCSeconds()).padStart(2, "0");
14341
- return `${hh}:${mm}:${ss} UTC`;
14336
+ function formatWallClock(ms, timeZone) {
14337
+ const fmt = new Intl.DateTimeFormat("en-GB", {
14338
+ hour: "2-digit",
14339
+ minute: "2-digit",
14340
+ second: "2-digit",
14341
+ hour12: false,
14342
+ timeZone,
14343
+ timeZoneName: "short"
14344
+ });
14345
+ const parts = fmt.formatToParts(new Date(ms));
14346
+ const get = (t) => parts.find((p) => p.type === t)?.value ?? "";
14347
+ return `${get("hour")}:${get("minute")}:${get("second")} ${get("timeZoneName")}`;
14342
14348
  }
14343
14349
  function renderHeaderLine(state) {
14344
14350
  if (state.terminal) {
@@ -13863,7 +13863,7 @@ var StdioServerTransport = class {
13863
13863
 
13864
13864
  // src/telegram-channel.ts
13865
13865
  import https from "https";
13866
- import { createHash, randomUUID } from "crypto";
13866
+ import { createHash, randomUUID as randomUUID2 } from "crypto";
13867
13867
  import {
13868
13868
  closeSync,
13869
13869
  createWriteStream,
@@ -14820,6 +14820,430 @@ function createObservedChatClient(args) {
14820
14820
  };
14821
14821
  }
14822
14822
 
14823
+ // src/progress-tools.ts
14824
+ import { randomUUID } from "crypto";
14825
+
14826
+ // src/progress-handle.ts
14827
+ async function startProgressHandle(opts) {
14828
+ const now = opts.now ?? (() => Date.now());
14829
+ const setTimer = opts.setTimer ?? ((cb, ms) => setTimeout(cb, ms));
14830
+ const clearTimer = opts.clearTimer ?? ((id) => clearTimeout(id));
14831
+ const debounceMs = opts.debounceMs ?? 1e3;
14832
+ const onPostTerminalUpdate = opts.onPostTerminalUpdate ?? defaultPostTerminalWarn;
14833
+ const state = {
14834
+ initialLabel: opts.initialLabel,
14835
+ mode: opts.initialMode ?? "working",
14836
+ lastChangeAt: now()
14837
+ };
14838
+ let lastFlushAt = 0;
14839
+ let pendingTimer = null;
14840
+ let inFlight = null;
14841
+ let terminal = false;
14842
+ async function doFlush() {
14843
+ while (inFlight) await inFlight;
14844
+ if (pendingTimer != null) {
14845
+ clearTimer(pendingTimer);
14846
+ pendingTimer = null;
14847
+ }
14848
+ lastFlushAt = now();
14849
+ const promise = opts.flush(snapshotState());
14850
+ inFlight = promise.then(
14851
+ () => {
14852
+ inFlight = null;
14853
+ },
14854
+ (err) => {
14855
+ inFlight = null;
14856
+ throw err;
14857
+ }
14858
+ );
14859
+ await inFlight;
14860
+ }
14861
+ function snapshotState() {
14862
+ return {
14863
+ initialLabel: state.initialLabel,
14864
+ mode: state.mode,
14865
+ stepLabel: state.stepLabel,
14866
+ stepNumber: state.stepNumber ? { ...state.stepNumber } : void 0,
14867
+ detail: state.detail,
14868
+ lastChangeAt: state.lastChangeAt,
14869
+ terminal: state.terminal ? { ...state.terminal } : void 0
14870
+ };
14871
+ }
14872
+ function applyUpdate(next) {
14873
+ if (next.mode !== void 0) state.mode = next.mode;
14874
+ if (next.stepLabel !== void 0) state.stepLabel = next.stepLabel;
14875
+ if (next.stepNumber !== void 0) state.stepNumber = { ...next.stepNumber };
14876
+ if (next.detail !== void 0) state.detail = next.detail;
14877
+ state.lastChangeAt = now();
14878
+ }
14879
+ async function scheduleOrFlush() {
14880
+ const elapsed = now() - lastFlushAt;
14881
+ if (elapsed >= debounceMs) {
14882
+ await doFlush();
14883
+ return;
14884
+ }
14885
+ if (pendingTimer != null) return;
14886
+ const remaining = debounceMs - elapsed;
14887
+ pendingTimer = setTimer(() => {
14888
+ pendingTimer = null;
14889
+ void doFlush().catch(() => {
14890
+ });
14891
+ }, remaining);
14892
+ }
14893
+ lastFlushAt = now();
14894
+ await opts.flush(snapshotState());
14895
+ return {
14896
+ snapshot: snapshotState,
14897
+ async update(next) {
14898
+ if (terminal) {
14899
+ const peeked = snapshotState();
14900
+ Object.assign(peeked, {
14901
+ mode: next.mode ?? peeked.mode,
14902
+ stepLabel: next.stepLabel ?? peeked.stepLabel,
14903
+ stepNumber: next.stepNumber ?? peeked.stepNumber,
14904
+ detail: next.detail ?? peeked.detail
14905
+ });
14906
+ try {
14907
+ onPostTerminalUpdate(peeked);
14908
+ } catch (err) {
14909
+ console.warn(
14910
+ "[progress-handle] onPostTerminalUpdate threw \u2014 swallowed to keep update() non-throwing:",
14911
+ err
14912
+ );
14913
+ }
14914
+ return;
14915
+ }
14916
+ applyUpdate(next);
14917
+ await scheduleOrFlush();
14918
+ },
14919
+ async complete(summary) {
14920
+ if (terminal) return;
14921
+ terminal = true;
14922
+ state.terminal = { kind: "completed", message: summary };
14923
+ state.lastChangeAt = now();
14924
+ await doFlush();
14925
+ },
14926
+ async fail(reason) {
14927
+ if (terminal) return;
14928
+ terminal = true;
14929
+ state.terminal = { kind: "failed", message: reason };
14930
+ state.lastChangeAt = now();
14931
+ await doFlush();
14932
+ },
14933
+ isTerminal: () => terminal
14934
+ };
14935
+ }
14936
+ function defaultPostTerminalWarn(state) {
14937
+ console.warn(
14938
+ `[progress-handle] update() called after terminal transition (${state.terminal?.kind}) \u2014 ignored.`
14939
+ );
14940
+ }
14941
+
14942
+ // src/progress-tools.ts
14943
+ var ProgressToolRegistry = class {
14944
+ constructor(opts) {
14945
+ this.opts = opts;
14946
+ this.toolNames = {
14947
+ start: `${opts.prefix}_progress_start`,
14948
+ update: `${opts.prefix}_progress_update`,
14949
+ complete: `${opts.prefix}_progress_complete`,
14950
+ fail: `${opts.prefix}_progress_fail`
14951
+ };
14952
+ }
14953
+ handles = /* @__PURE__ */ new Map();
14954
+ toolNames;
14955
+ /** Tool definitions to splice into the MCP ListToolsRequest response. */
14956
+ getDefinitions() {
14957
+ const { surfaceDescription, startArgsSchema } = this.opts;
14958
+ const debounceMs = this.opts.debounceMs ?? 1e3;
14959
+ const debounceText = debounceMs === 1e3 ? "per second" : `every ${debounceMs}ms`;
14960
+ return [
14961
+ {
14962
+ name: this.toolNames.start,
14963
+ description: `Post a "still working" anchor to ${surfaceDescription} and return a progress_id. The anchor message updates in place as you call ${this.toolNames.update} \u2014 operators see one message that ticks forward instead of a flood of new ones. Always end with ${this.toolNames.complete} or ${this.toolNames.fail}; otherwise the anchor lingers as "working" until the stale-state sweep flips it. Opt-in \u2014 only call this for tasks that will take more than a few seconds.`,
14964
+ inputSchema: {
14965
+ type: "object",
14966
+ properties: {
14967
+ label: {
14968
+ type: "string",
14969
+ description: 'Short top-line label for the task (e.g. "diagnose vigil"). Stays constant for the lifetime of this progress anchor.'
14970
+ },
14971
+ initial_mode: {
14972
+ type: "string",
14973
+ enum: ["thinking", "working", "waiting"],
14974
+ description: 'Initial mode emoji \u2014 defaults to "working".'
14975
+ },
14976
+ ...startArgsSchema.properties
14977
+ },
14978
+ required: ["label", ...startArgsSchema.required]
14979
+ }
14980
+ },
14981
+ {
14982
+ name: this.toolNames.update,
14983
+ description: `Update the progress anchor in place. The state machine debounces calls to one ${surfaceDescription} API call ${debounceText}, so spamming this every step is safe \u2014 only the latest pending state will paint. Any subset of fields can be passed; omitted ones retain their previous value.`,
14984
+ inputSchema: {
14985
+ type: "object",
14986
+ properties: {
14987
+ progress_id: { type: "string", description: "The progress_id returned from start." },
14988
+ step_label: { type: "string", description: 'Short label for the current step (e.g. "Querying CloudWatch logs").' },
14989
+ step_current: { type: "number", description: "1-based step counter \u2014 current." },
14990
+ step_total: { type: "number", description: "Total steps if known. Omit for open-ended progress." },
14991
+ mode: { type: "string", enum: ["thinking", "working", "waiting"] },
14992
+ detail: { type: "string", description: "Free-text detail line under the step label." }
14993
+ },
14994
+ required: ["progress_id"]
14995
+ }
14996
+ },
14997
+ {
14998
+ name: this.toolNames.complete,
14999
+ description: `Mark the progress anchor as \u2705 completed. Flushes any pending debounced state before painting the terminal banner \u2014 the operator never sees a stale "Step N" beside the \u2705. After this, the handle is dead; further updates are no-ops.`,
15000
+ inputSchema: {
15001
+ type: "object",
15002
+ properties: {
15003
+ progress_id: { type: "string" },
15004
+ summary: { type: "string", description: "Optional one-line summary of what was achieved." }
15005
+ },
15006
+ required: ["progress_id"]
15007
+ }
15008
+ },
15009
+ {
15010
+ name: this.toolNames.fail,
15011
+ description: `Mark the progress anchor as \u274C failed. Always include a one-sentence reason \u2014 the operator can't tell *why* from emoji alone. Same flush-then-paint behaviour as complete.`,
15012
+ inputSchema: {
15013
+ type: "object",
15014
+ properties: {
15015
+ progress_id: { type: "string" },
15016
+ reason: { type: "string", description: "One-sentence failure reason." }
15017
+ },
15018
+ required: ["progress_id", "reason"]
15019
+ }
15020
+ }
15021
+ ];
15022
+ }
15023
+ /**
15024
+ * Dispatch a CallToolRequest. Returns `undefined` if the tool name
15025
+ * isn't one of ours (so the caller can keep walking its dispatch
15026
+ * chain). Returns a tool result otherwise.
15027
+ */
15028
+ async handle(name, args) {
15029
+ if (name === this.toolNames.start) return this.handleStart(args);
15030
+ if (name === this.toolNames.update) return this.handleUpdate(args);
15031
+ if (name === this.toolNames.complete) return this.handleComplete(args);
15032
+ if (name === this.toolNames.fail) return this.handleFail(args);
15033
+ return void 0;
15034
+ }
15035
+ /** Live count of in-flight handles. Exposed for tests + diagnostics. */
15036
+ size() {
15037
+ return this.handles.size;
15038
+ }
15039
+ async handleStart(args) {
15040
+ const label = typeof args.label === "string" ? args.label : null;
15041
+ if (!label) return errResult(`${this.toolNames.start}: 'label' must be a non-empty string`);
15042
+ if ("initial_mode" in args && !isMode(args.initial_mode)) {
15043
+ return errResult(
15044
+ `${this.toolNames.start}: 'initial_mode' must be one of 'thinking', 'working', or 'waiting'`
15045
+ );
15046
+ }
15047
+ for (const k of this.opts.startArgsSchema.required) {
15048
+ if (typeof args[k] !== "string" || args[k].length === 0) {
15049
+ return errResult(`${this.toolNames.start}: '${k}' must be a non-empty string`);
15050
+ }
15051
+ }
15052
+ const initialMode = isMode(args.initial_mode) ? args.initial_mode : void 0;
15053
+ const progressId = randomUUID();
15054
+ try {
15055
+ const flush = this.opts.createFlush(args);
15056
+ const handle = await startProgressHandle({
15057
+ initialLabel: label,
15058
+ initialMode,
15059
+ flush,
15060
+ debounceMs: this.opts.debounceMs ?? 1e3
15061
+ });
15062
+ this.handles.set(progressId, handle);
15063
+ return okResult(JSON.stringify({ progress_id: progressId }));
15064
+ } catch (err) {
15065
+ return errResult(`${this.toolNames.start} failed: ${err.message ?? String(err)}`);
15066
+ }
15067
+ }
15068
+ async handleUpdate(args) {
15069
+ const id = typeof args.progress_id === "string" ? args.progress_id : null;
15070
+ if (!id) return errResult(`${this.toolNames.update}: 'progress_id' must be a string`);
15071
+ const handle = this.handles.get(id);
15072
+ if (!handle) return errResult(`${this.toolNames.update}: unknown progress_id (already terminated, or never started)`);
15073
+ if ("mode" in args && !isMode(args.mode)) {
15074
+ return errResult(
15075
+ `${this.toolNames.update}: 'mode' must be one of 'thinking', 'working', or 'waiting'`
15076
+ );
15077
+ }
15078
+ if (typeof args.step_total === "number" && typeof args.step_current !== "number") {
15079
+ return errResult(
15080
+ `${this.toolNames.update}: 'step_total' requires 'step_current'`
15081
+ );
15082
+ }
15083
+ const next = {};
15084
+ if (typeof args.step_label === "string") next.stepLabel = args.step_label;
15085
+ if (typeof args.step_current === "number") {
15086
+ next.stepNumber = {
15087
+ current: args.step_current,
15088
+ ...typeof args.step_total === "number" ? { total: args.step_total } : {}
15089
+ };
15090
+ }
15091
+ if (isMode(args.mode)) next.mode = args.mode;
15092
+ if (typeof args.detail === "string") next.detail = args.detail;
15093
+ try {
15094
+ await handle.update(next);
15095
+ return okResult("ok");
15096
+ } catch (err) {
15097
+ return errResult(`${this.toolNames.update} failed: ${err.message ?? String(err)}`);
15098
+ }
15099
+ }
15100
+ async handleComplete(args) {
15101
+ const id = typeof args.progress_id === "string" ? args.progress_id : null;
15102
+ if (!id) return errResult(`${this.toolNames.complete}: 'progress_id' must be a string`);
15103
+ const handle = this.handles.get(id);
15104
+ if (!handle) return errResult(`${this.toolNames.complete}: unknown progress_id`);
15105
+ const summary = typeof args.summary === "string" ? args.summary : void 0;
15106
+ try {
15107
+ await handle.complete(summary);
15108
+ this.handles.delete(id);
15109
+ return okResult("ok");
15110
+ } catch (err) {
15111
+ return errResult(`${this.toolNames.complete} failed: ${err.message ?? String(err)}`);
15112
+ }
15113
+ }
15114
+ async handleFail(args) {
15115
+ const id = typeof args.progress_id === "string" ? args.progress_id : null;
15116
+ if (!id) return errResult(`${this.toolNames.fail}: 'progress_id' must be a string`);
15117
+ const reason = typeof args.reason === "string" ? args.reason : null;
15118
+ if (!reason) return errResult(`${this.toolNames.fail}: 'reason' must be a non-empty string`);
15119
+ const handle = this.handles.get(id);
15120
+ if (!handle) return errResult(`${this.toolNames.fail}: unknown progress_id`);
15121
+ try {
15122
+ await handle.fail(reason);
15123
+ this.handles.delete(id);
15124
+ return okResult("ok");
15125
+ } catch (err) {
15126
+ return errResult(`${this.toolNames.fail} failed: ${err.message ?? String(err)}`);
15127
+ }
15128
+ }
15129
+ };
15130
+ function okResult(text) {
15131
+ return { content: [{ type: "text", text }] };
15132
+ }
15133
+ function errResult(text) {
15134
+ return { content: [{ type: "text", text }], isError: true };
15135
+ }
15136
+ function isMode(value) {
15137
+ return value === "thinking" || value === "working" || value === "waiting";
15138
+ }
15139
+
15140
+ // src/telegram-progress.ts
15141
+ var MODE_EMOJI = {
15142
+ thinking: "\u{1F4AD}",
15143
+ working: "\u{1F6E0}\uFE0F",
15144
+ waiting: "\u23F3"
15145
+ };
15146
+ var TERMINAL_EMOJI = {
15147
+ completed: "\u2705",
15148
+ failed: "\u274C"
15149
+ };
15150
+ function formatWallClock(ms, timeZone) {
15151
+ const fmt = new Intl.DateTimeFormat("en-GB", {
15152
+ hour: "2-digit",
15153
+ minute: "2-digit",
15154
+ second: "2-digit",
15155
+ hour12: false,
15156
+ timeZone,
15157
+ timeZoneName: "short"
15158
+ });
15159
+ const parts = fmt.formatToParts(new Date(ms));
15160
+ const get = (t) => parts.find((p) => p.type === t)?.value ?? "";
15161
+ return `${get("hour")}:${get("minute")}:${get("second")} ${get("timeZoneName")}`;
15162
+ }
15163
+ function escapeHtml(s) {
15164
+ return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
15165
+ }
15166
+ function renderProgressHtml(state) {
15167
+ const lines = [];
15168
+ if (state.terminal) {
15169
+ const banner = state.terminal.kind === "completed" ? "Done" : "Failed";
15170
+ lines.push(`${TERMINAL_EMOJI[state.terminal.kind]} <b>${banner}</b> \u2014 ${escapeHtml(state.initialLabel)}`);
15171
+ if (state.terminal.message) lines.push(escapeHtml(state.terminal.message));
15172
+ const verb = state.terminal.kind === "completed" ? "completed" : "failed";
15173
+ lines.push(`<i>${verb}: ${formatWallClock(state.lastChangeAt)}</i>`);
15174
+ return lines.join("\n");
15175
+ }
15176
+ lines.push(`${MODE_EMOJI[state.mode]} <b>Working on:</b> ${escapeHtml(state.initialLabel)}`);
15177
+ if (state.stepNumber || state.stepLabel) {
15178
+ const parts = [];
15179
+ if (state.stepNumber) {
15180
+ if (state.stepNumber.total != null) {
15181
+ parts.push(`<b>Step ${state.stepNumber.current} of ${state.stepNumber.total}</b>`);
15182
+ } else {
15183
+ parts.push(`<b>Step ${state.stepNumber.current}</b>`);
15184
+ }
15185
+ }
15186
+ if (state.stepLabel) parts.push(escapeHtml(state.stepLabel));
15187
+ lines.push(parts.join(": "));
15188
+ }
15189
+ if (state.detail) lines.push(`<i>${escapeHtml(state.detail)}</i>`);
15190
+ lines.push(`<i>last update: ${formatWallClock(state.lastChangeAt)}</i>`);
15191
+ return lines.join("\n");
15192
+ }
15193
+ var TelegramApiError = class extends Error {
15194
+ constructor(endpoint, apiError) {
15195
+ super(`Telegram ${endpoint} failed: ${apiError}`);
15196
+ this.endpoint = endpoint;
15197
+ this.apiError = apiError;
15198
+ this.name = "TelegramApiError";
15199
+ }
15200
+ };
15201
+ function isMessageNotModified(description) {
15202
+ if (!description) return false;
15203
+ return /message is not modified/i.test(description);
15204
+ }
15205
+ function createTelegramProgressFlush(opts) {
15206
+ let anchorMessageId = null;
15207
+ return async function flush(state) {
15208
+ const text = renderProgressHtml(state);
15209
+ if (anchorMessageId == null) {
15210
+ const body = {
15211
+ chat_id: opts.chatId,
15212
+ text,
15213
+ parse_mode: "HTML",
15214
+ disable_notification: true
15215
+ };
15216
+ if (opts.messageThreadId != null) body.message_thread_id = opts.messageThreadId;
15217
+ if (opts.replyToMessageId != null) body.reply_to_message_id = opts.replyToMessageId;
15218
+ const res = await opts.callImpl("sendMessage", body);
15219
+ if (!res.ok || !res.result?.message_id) {
15220
+ throw new TelegramApiError("sendMessage", res.description ?? "missing message_id");
15221
+ }
15222
+ anchorMessageId = res.result.message_id;
15223
+ opts.onAnchorPosted?.(res.result.message_id);
15224
+ return;
15225
+ }
15226
+ try {
15227
+ const res = await opts.callImpl("editMessageText", {
15228
+ chat_id: opts.chatId,
15229
+ message_id: anchorMessageId,
15230
+ text,
15231
+ parse_mode: "HTML"
15232
+ });
15233
+ if (!res.ok) {
15234
+ if (isMessageNotModified(res.description)) return;
15235
+ throw new TelegramApiError("editMessageText", res.description ?? "unknown");
15236
+ }
15237
+ } catch (err) {
15238
+ if (opts.onApiError && err instanceof TelegramApiError) {
15239
+ await opts.onApiError(err);
15240
+ return;
15241
+ }
15242
+ throw err;
15243
+ }
15244
+ };
15245
+ }
15246
+
14823
15247
  // src/pending-reminder-schedule.ts
14824
15248
  var REMINDER_SCHEDULE_MS = [5, 10, 20].map((m) => m * 6e4);
14825
15249
  var MAX_REMINDERS = REMINDER_SCHEDULE_MS.length;
@@ -15050,7 +15474,7 @@ async function handleRestartCommand(opts) {
15050
15474
  ts: Date.now(),
15051
15475
  reply: { chat_id: opts.chatId, message_id: opts.messageId }
15052
15476
  };
15053
- const tmpPath = `${flagPath}.${process.pid}.${randomUUID()}.tmp`;
15477
+ const tmpPath = `${flagPath}.${process.pid}.${randomUUID2()}.tmp`;
15054
15478
  writeFileSync2(tmpPath, JSON.stringify(flag) + "\n", "utf8");
15055
15479
  renameSync2(tmpPath, flagPath);
15056
15480
  process.stderr.write(
@@ -15619,8 +16043,42 @@ var mcp = new Server(
15619
16043
  ].join(" ")
15620
16044
  }
15621
16045
  );
16046
+ var TELEGRAM_PROGRESS_TIMEOUT_MS = 5e3;
16047
+ var progressRegistry = new ProgressToolRegistry({
16048
+ prefix: "telegram",
16049
+ surfaceDescription: "a Telegram chat",
16050
+ startArgsSchema: {
16051
+ properties: {
16052
+ chat_id: {
16053
+ type: "string",
16054
+ description: "Telegram chat id (from the `chat_id` attribute on the inbound <channel> tag). Numeric ids are passed as strings; the API accepts both."
16055
+ },
16056
+ message_thread_id: {
16057
+ type: "string",
16058
+ description: "Forum topic id (`message_thread_id`) \u2014 pass this if the inbound arrived in a forum topic so the anchor lands in the same topic. Omit for normal chats."
16059
+ },
16060
+ reply_to_message_id: {
16061
+ type: "string",
16062
+ description: "Optional message id to thread the anchor under (typically the inbound message_id from the <channel> tag)."
16063
+ }
16064
+ },
16065
+ required: ["chat_id"]
16066
+ },
16067
+ createFlush: (args) => {
16068
+ const chatId = args.chat_id;
16069
+ const threadId = typeof args.message_thread_id === "string" && args.message_thread_id.length > 0 ? Number(args.message_thread_id) : void 0;
16070
+ const replyTo = typeof args.reply_to_message_id === "string" && args.reply_to_message_id.length > 0 ? Number(args.reply_to_message_id) : void 0;
16071
+ return createTelegramProgressFlush({
16072
+ chatId,
16073
+ messageThreadId: Number.isFinite(threadId) ? threadId : void 0,
16074
+ replyToMessageId: Number.isFinite(replyTo) ? replyTo : void 0,
16075
+ callImpl: (method, body) => telegramApiCall(method, body, TELEGRAM_PROGRESS_TIMEOUT_MS)
16076
+ });
16077
+ }
16078
+ });
15622
16079
  mcp.setRequestHandler(ListToolsRequestSchema, async () => ({
15623
16080
  tools: [
16081
+ ...progressRegistry.getDefinitions(),
15624
16082
  {
15625
16083
  name: "telegram.reply",
15626
16084
  description: "Reply to a Telegram chat or specific message",
@@ -15699,6 +16157,8 @@ mcp.setRequestHandler(ListToolsRequestSchema, async () => ({
15699
16157
  }));
15700
16158
  mcp.setRequestHandler(CallToolRequestSchema, async (req) => {
15701
16159
  const { name, arguments: args } = req.params;
16160
+ const progressResult = await progressRegistry.handle(name, args ?? {});
16161
+ if (progressResult !== void 0) return progressResult;
15702
16162
  if (name === "telegram.reply" || name === "telegram.send_message") {
15703
16163
  const { chat_id, text, reply_to_message_id } = args;
15704
16164
  if (ALLOWED_CHATS.size > 0 && !ALLOWED_CHATS.has(chat_id)) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@integrity-labs/agt-cli",
3
- "version": "0.20.9",
3
+ "version": "0.21.1",
4
4
  "description": "Augmented Team CLI — agent provisioning and management",
5
5
  "type": "module",
6
6
  "engines": {