@integrity-labs/agt-cli 0.28.80 → 0.28.82
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/bin/agt.js +3 -3
- package/dist/{chunk-JIJ5BGO5.js → chunk-WSRT4VSX.js} +2 -2
- package/dist/lib/manager-worker.js +2 -2
- package/dist/mcp/slack-channel.js +5 -11
- package/dist/mcp/telegram-channel.js +253 -11
- package/package.json +1 -1
- /package/dist/{chunk-JIJ5BGO5.js.map → chunk-WSRT4VSX.js.map} +0 -0
package/dist/bin/agt.js
CHANGED
|
@@ -37,7 +37,7 @@ import {
|
|
|
37
37
|
success,
|
|
38
38
|
table,
|
|
39
39
|
warn
|
|
40
|
-
} from "../chunk-
|
|
40
|
+
} from "../chunk-WSRT4VSX.js";
|
|
41
41
|
import {
|
|
42
42
|
CHANNEL_REGISTRY,
|
|
43
43
|
DEPLOYMENT_TEMPLATES,
|
|
@@ -4777,7 +4777,7 @@ import { execFileSync, execSync } from "child_process";
|
|
|
4777
4777
|
import { existsSync as existsSync10, realpathSync as realpathSync2 } from "fs";
|
|
4778
4778
|
import chalk18 from "chalk";
|
|
4779
4779
|
import ora16 from "ora";
|
|
4780
|
-
var cliVersion = true ? "0.28.
|
|
4780
|
+
var cliVersion = true ? "0.28.82" : "dev";
|
|
4781
4781
|
async function fetchLatestVersion() {
|
|
4782
4782
|
const host2 = getHost();
|
|
4783
4783
|
if (!host2) return null;
|
|
@@ -5791,7 +5791,7 @@ function handleError(err) {
|
|
|
5791
5791
|
}
|
|
5792
5792
|
|
|
5793
5793
|
// src/bin/agt.ts
|
|
5794
|
-
var cliVersion2 = true ? "0.28.
|
|
5794
|
+
var cliVersion2 = true ? "0.28.82" : "dev";
|
|
5795
5795
|
var program = new Command();
|
|
5796
5796
|
program.name("agt").description("Augmented CLI \u2014 agent provisioning and management").version(cliVersion2).option("--json", "Emit machine-readable JSON output (suppress spinners and colors)").option("--skip-update-check", "Skip the automatic update check on startup");
|
|
5797
5797
|
program.hook("preAction", async (thisCommand, actionCommand) => {
|
|
@@ -7516,7 +7516,7 @@ function requireHost() {
|
|
|
7516
7516
|
}
|
|
7517
7517
|
|
|
7518
7518
|
// src/lib/api-client.ts
|
|
7519
|
-
var agtCliVersion = true ? "0.28.
|
|
7519
|
+
var agtCliVersion = true ? "0.28.82" : "dev";
|
|
7520
7520
|
var lastConfigHash = null;
|
|
7521
7521
|
function setConfigHash(hash) {
|
|
7522
7522
|
lastConfigHash = hash && hash.length > 0 ? hash : null;
|
|
@@ -8813,4 +8813,4 @@ export {
|
|
|
8813
8813
|
managerInstallSystemUnitCommand,
|
|
8814
8814
|
managerUninstallSystemUnitCommand
|
|
8815
8815
|
};
|
|
8816
|
-
//# sourceMappingURL=chunk-
|
|
8816
|
+
//# sourceMappingURL=chunk-WSRT4VSX.js.map
|
|
@@ -28,7 +28,7 @@ import {
|
|
|
28
28
|
requireHost,
|
|
29
29
|
safeWriteJsonAtomic,
|
|
30
30
|
setConfigHash
|
|
31
|
-
} from "../chunk-
|
|
31
|
+
} from "../chunk-WSRT4VSX.js";
|
|
32
32
|
import {
|
|
33
33
|
getProjectDir as getProjectDir2,
|
|
34
34
|
getReadyTasks,
|
|
@@ -6803,7 +6803,7 @@ var cachedMaintenanceWindow = null;
|
|
|
6803
6803
|
var lastVersionCheckAt = 0;
|
|
6804
6804
|
var VERSION_CHECK_INTERVAL_MS = 5 * 60 * 1e3;
|
|
6805
6805
|
var lastResponsivenessProbeAt = 0;
|
|
6806
|
-
var agtCliVersion = true ? "0.28.
|
|
6806
|
+
var agtCliVersion = true ? "0.28.82" : "dev";
|
|
6807
6807
|
function resolveBrewPath(execFileSync4) {
|
|
6808
6808
|
try {
|
|
6809
6809
|
const out = execFileSync4("which", ["brew"], { timeout: 5e3 }).toString().trim();
|
|
@@ -18073,15 +18073,6 @@ async function postEphemeralViaResponseUrl(responseUrl, text, logTag) {
|
|
|
18073
18073
|
}
|
|
18074
18074
|
async function forwardOnboardingSlashCommand(opts) {
|
|
18075
18075
|
const { verb, path, userId, responseUrl, codeName } = opts;
|
|
18076
|
-
const allowed = getEffectiveAllowedUsers();
|
|
18077
|
-
if (allowed.size > 0 && (!userId || !allowed.has(userId))) {
|
|
18078
|
-
await postEphemeralViaResponseUrl(
|
|
18079
|
-
responseUrl,
|
|
18080
|
-
`\u{1F6AB} \`${verb}\` denied \u2014 your Slack user is not in the allowlist for \`${codeName}\`.`,
|
|
18081
|
-
codeName
|
|
18082
|
-
);
|
|
18083
|
-
return;
|
|
18084
|
-
}
|
|
18085
18076
|
if (!AGT_HOST || !AGT_API_KEY || !AGT_AGENT_ID) {
|
|
18086
18077
|
await postEphemeralViaResponseUrl(
|
|
18087
18078
|
responseUrl,
|
|
@@ -18097,9 +18088,12 @@ async function forwardOnboardingSlashCommand(opts) {
|
|
|
18097
18088
|
apiKey: AGT_API_KEY,
|
|
18098
18089
|
agentId: AGT_AGENT_ID
|
|
18099
18090
|
};
|
|
18100
|
-
const res = await apiCall2(cfg, "POST", `/host${path}`, {
|
|
18091
|
+
const res = await apiCall2(cfg, "POST", `/host${path}`, {
|
|
18092
|
+
agent_id: AGT_AGENT_ID,
|
|
18093
|
+
initiator: { channel: "slack", user_id: userId }
|
|
18094
|
+
});
|
|
18101
18095
|
const data = await res.json();
|
|
18102
|
-
const text = data.ok ? `\u{1F504} ${data.message ?? "Onboarding updated."}` : `:x: \`${verb}\` failed${data.error ? `: ${data.error}` : "."}`;
|
|
18096
|
+
const text = data.ok ? `\u{1F504} ${data.message ?? "Onboarding updated."}` : data.message ?? `:x: \`${verb}\` failed${data.error ? `: ${data.error}` : "."}`;
|
|
18103
18097
|
await postEphemeralViaResponseUrl(responseUrl, text, codeName);
|
|
18104
18098
|
} catch (err) {
|
|
18105
18099
|
process.stderr.write(
|
|
@@ -16232,6 +16232,12 @@ function markerArrivalMs(fullPath) {
|
|
|
16232
16232
|
}
|
|
16233
16233
|
}
|
|
16234
16234
|
function clearAllTelegramPendingMarkersForChat(pendingDir, chatId, clearMarkerFile, cutoffMs = Number.POSITIVE_INFINITY) {
|
|
16235
|
+
return applyToChatMarkers(pendingDir, chatId, clearMarkerFile, cutoffMs);
|
|
16236
|
+
}
|
|
16237
|
+
function markSeenAllTelegramPendingMarkersForChat(pendingDir, chatId, markSeen, cutoffMs = Number.POSITIVE_INFINITY) {
|
|
16238
|
+
return applyToChatMarkers(pendingDir, chatId, markSeen, cutoffMs);
|
|
16239
|
+
}
|
|
16240
|
+
function applyToChatMarkers(pendingDir, chatId, op, cutoffMs) {
|
|
16235
16241
|
const prefix = `${chatId.replace(/[^A-Za-z0-9_-]/g, "_")}__`;
|
|
16236
16242
|
const bounded = Number.isFinite(cutoffMs);
|
|
16237
16243
|
let filenames;
|
|
@@ -16240,16 +16246,69 @@ function clearAllTelegramPendingMarkersForChat(pendingDir, chatId, clearMarkerFi
|
|
|
16240
16246
|
} catch {
|
|
16241
16247
|
return 0;
|
|
16242
16248
|
}
|
|
16243
|
-
let
|
|
16249
|
+
let applied = 0;
|
|
16244
16250
|
for (const filename of filenames) {
|
|
16245
16251
|
if (!filename.startsWith(prefix)) continue;
|
|
16246
16252
|
if (!filename.endsWith(".json")) continue;
|
|
16247
16253
|
const fullPath = join4(pendingDir, filename);
|
|
16248
16254
|
if (bounded && markerArrivalMs(fullPath) > cutoffMs) continue;
|
|
16249
|
-
|
|
16250
|
-
|
|
16255
|
+
op(fullPath);
|
|
16256
|
+
applied++;
|
|
16257
|
+
}
|
|
16258
|
+
return applied;
|
|
16259
|
+
}
|
|
16260
|
+
|
|
16261
|
+
// src/channel-progress.ts
|
|
16262
|
+
function channelLiveProgressEnabled() {
|
|
16263
|
+
return resolveHostBooleanFlag({
|
|
16264
|
+
key: "channel-live-progress",
|
|
16265
|
+
envVar: "AGT_CHANNEL_PROGRESS_ENABLED",
|
|
16266
|
+
defaultValue: false
|
|
16267
|
+
});
|
|
16268
|
+
}
|
|
16269
|
+
function decideProgressAction(input) {
|
|
16270
|
+
const { now, heartbeat, target, tracked, freshnessMs, minPendingMs } = input;
|
|
16271
|
+
const fresh = heartbeat != null && now - heartbeat.updatedAtMs <= freshnessMs;
|
|
16272
|
+
const active = target != null && fresh;
|
|
16273
|
+
if (!active) {
|
|
16274
|
+
if (tracked) {
|
|
16275
|
+
return { type: "delete", channel: tracked.channel, threadTs: tracked.threadTs, ts: tracked.ts };
|
|
16276
|
+
}
|
|
16277
|
+
return { type: "none" };
|
|
16278
|
+
}
|
|
16279
|
+
const t = target;
|
|
16280
|
+
const hb = heartbeat;
|
|
16281
|
+
if (tracked && (tracked.threadTs !== t.threadTs || tracked.channel !== t.channel)) {
|
|
16282
|
+
return { type: "delete", channel: tracked.channel, threadTs: tracked.threadTs, ts: tracked.ts };
|
|
16283
|
+
}
|
|
16284
|
+
if (!tracked) {
|
|
16285
|
+
if (now - t.receivedAtMs < minPendingMs) return { type: "none" };
|
|
16286
|
+
return { type: "post", channel: t.channel, threadTs: t.threadTs, step: hb.step };
|
|
16287
|
+
}
|
|
16288
|
+
if (hb.step !== tracked.lastStep) {
|
|
16289
|
+
return { type: "update", channel: t.channel, threadTs: t.threadTs, ts: tracked.ts, step: hb.step };
|
|
16290
|
+
}
|
|
16291
|
+
return { type: "none" };
|
|
16292
|
+
}
|
|
16293
|
+
function progressHeartbeatFreshMs() {
|
|
16294
|
+
const raw = parseInt(process.env.AGT_CHANNEL_PROGRESS_FRESH_MS ?? "", 10);
|
|
16295
|
+
return Number.isFinite(raw) && raw > 0 ? raw : 45e3;
|
|
16296
|
+
}
|
|
16297
|
+
function progressMinPendingMs() {
|
|
16298
|
+
const raw = parseInt(process.env.AGT_CHANNEL_PROGRESS_MIN_PENDING_MS ?? "", 10);
|
|
16299
|
+
return Number.isFinite(raw) && raw > 0 ? raw : 12e3;
|
|
16300
|
+
}
|
|
16301
|
+
function parseProgressHeartbeat(raw) {
|
|
16302
|
+
if (!raw) return null;
|
|
16303
|
+
try {
|
|
16304
|
+
const obj = JSON.parse(raw);
|
|
16305
|
+
const step = typeof obj.step === "string" ? obj.step.trim() : "";
|
|
16306
|
+
const updatedAtMs = typeof obj.updated_at_ms === "number" ? obj.updated_at_ms : NaN;
|
|
16307
|
+
if (!step || !Number.isFinite(updatedAtMs)) return null;
|
|
16308
|
+
return { step, updatedAtMs };
|
|
16309
|
+
} catch {
|
|
16310
|
+
return null;
|
|
16251
16311
|
}
|
|
16252
|
-
return cleared;
|
|
16253
16312
|
}
|
|
16254
16313
|
|
|
16255
16314
|
// src/mcp-spawn-lock.ts
|
|
@@ -17131,7 +17190,8 @@ async function handleOnboardingCommand(opts) {
|
|
|
17131
17190
|
agentId: AGT_AGENT_ID
|
|
17132
17191
|
};
|
|
17133
17192
|
const res = await apiCall2(cfg, "POST", `/host/onboarding/${opts.mode}`, {
|
|
17134
|
-
agent_id: AGT_AGENT_ID
|
|
17193
|
+
agent_id: AGT_AGENT_ID,
|
|
17194
|
+
initiator: { channel: "telegram", user_id: opts.senderId }
|
|
17135
17195
|
});
|
|
17136
17196
|
const data = await res.json();
|
|
17137
17197
|
process.stderr.write(
|
|
@@ -17139,7 +17199,7 @@ async function handleOnboardingCommand(opts) {
|
|
|
17139
17199
|
`
|
|
17140
17200
|
);
|
|
17141
17201
|
await reply(
|
|
17142
|
-
data.ok ? `\u{1F504} ${data.message ?? "Onboarding updated."}` : `\u274C ${verb} failed${data.error ? `: ${data.error}` : "."}`
|
|
17202
|
+
data.ok ? `\u{1F504} ${data.message ?? "Onboarding updated."}` : data.message ?? `\u274C ${verb} failed${data.error ? `: ${data.error}` : "."}`
|
|
17143
17203
|
);
|
|
17144
17204
|
} catch (err) {
|
|
17145
17205
|
process.stderr.write(
|
|
@@ -17666,6 +17726,33 @@ function clearTelegramMarkerFileWithHeal(fullPath) {
|
|
|
17666
17726
|
} catch {
|
|
17667
17727
|
}
|
|
17668
17728
|
}
|
|
17729
|
+
function markTelegramMarkerSeenInPlace(fullPath) {
|
|
17730
|
+
let marker;
|
|
17731
|
+
try {
|
|
17732
|
+
marker = JSON.parse(readFileSync8(fullPath, "utf-8"));
|
|
17733
|
+
} catch {
|
|
17734
|
+
return;
|
|
17735
|
+
}
|
|
17736
|
+
if (marker.seen_at) return;
|
|
17737
|
+
marker.seen_at = (/* @__PURE__ */ new Date()).toISOString();
|
|
17738
|
+
if (marker.undeliverable) delete marker.undeliverable;
|
|
17739
|
+
rewriteTelegramMarkerInPlace(fullPath, marker);
|
|
17740
|
+
}
|
|
17741
|
+
function markTelegramMarkerSeenWithHeal(fullPath) {
|
|
17742
|
+
let marker = null;
|
|
17743
|
+
try {
|
|
17744
|
+
marker = JSON.parse(readFileSync8(fullPath, "utf-8"));
|
|
17745
|
+
} catch {
|
|
17746
|
+
return;
|
|
17747
|
+
}
|
|
17748
|
+
if (decideRecoveryHeal({
|
|
17749
|
+
wasUndeliverable: marker.undeliverable === true,
|
|
17750
|
+
hasTarget: Boolean(marker.chat_id)
|
|
17751
|
+
}) === "heal") {
|
|
17752
|
+
notifyBackOnline(marker.chat_id);
|
|
17753
|
+
}
|
|
17754
|
+
markTelegramMarkerSeenInPlace(fullPath);
|
|
17755
|
+
}
|
|
17669
17756
|
function readPendingInboundMarker(chatId, messageId) {
|
|
17670
17757
|
const path = pendingInboundPath(chatId, messageId);
|
|
17671
17758
|
if (!path || !existsSync5(path)) return null;
|
|
@@ -17911,6 +17998,143 @@ var orphanSweepTimer = setInterval(() => {
|
|
|
17911
17998
|
checkWatchdogGiveUpNotice();
|
|
17912
17999
|
}, orphanSweepIntervalMs());
|
|
17913
18000
|
orphanSweepTimer.unref?.();
|
|
18001
|
+
var TELEGRAM_PROGRESS_HEARTBEAT_PATH = AGENT_DIR ? join7(AGENT_DIR, "channel-progress-heartbeat.json") : null;
|
|
18002
|
+
var telegramTrackedProgress = null;
|
|
18003
|
+
var telegramProgressTickRunning = false;
|
|
18004
|
+
function readTelegramProgressHeartbeat() {
|
|
18005
|
+
if (!TELEGRAM_PROGRESS_HEARTBEAT_PATH || !existsSync5(TELEGRAM_PROGRESS_HEARTBEAT_PATH)) return null;
|
|
18006
|
+
try {
|
|
18007
|
+
return parseProgressHeartbeat(readFileSync8(TELEGRAM_PROGRESS_HEARTBEAT_PATH, "utf-8"));
|
|
18008
|
+
} catch {
|
|
18009
|
+
return null;
|
|
18010
|
+
}
|
|
18011
|
+
}
|
|
18012
|
+
function findTelegramProgressTarget() {
|
|
18013
|
+
if (!PENDING_INBOUND_DIR || !existsSync5(PENDING_INBOUND_DIR)) return null;
|
|
18014
|
+
let best = null;
|
|
18015
|
+
let bestMs = Infinity;
|
|
18016
|
+
try {
|
|
18017
|
+
for (const name of readdirSync3(PENDING_INBOUND_DIR)) {
|
|
18018
|
+
if (!name.endsWith(".json")) continue;
|
|
18019
|
+
let m;
|
|
18020
|
+
try {
|
|
18021
|
+
m = JSON.parse(readFileSync8(join7(PENDING_INBOUND_DIR, name), "utf-8"));
|
|
18022
|
+
} catch {
|
|
18023
|
+
continue;
|
|
18024
|
+
}
|
|
18025
|
+
if (!m.chat_id) continue;
|
|
18026
|
+
if (m.undeliverable === true) continue;
|
|
18027
|
+
const ms = Date.parse(m.received_at ?? "");
|
|
18028
|
+
if (!Number.isFinite(ms)) continue;
|
|
18029
|
+
if (ms < bestMs) {
|
|
18030
|
+
bestMs = ms;
|
|
18031
|
+
best = { channel: m.chat_id, threadTs: m.chat_id, receivedAtMs: ms };
|
|
18032
|
+
}
|
|
18033
|
+
}
|
|
18034
|
+
} catch {
|
|
18035
|
+
return null;
|
|
18036
|
+
}
|
|
18037
|
+
return best;
|
|
18038
|
+
}
|
|
18039
|
+
var TELEGRAM_PROGRESS_PREFIX = "\u23F3";
|
|
18040
|
+
function telegramProgressText(step) {
|
|
18041
|
+
return `${TELEGRAM_PROGRESS_PREFIX} Working\u2026 \xB7 ${step}`;
|
|
18042
|
+
}
|
|
18043
|
+
async function postTelegramProgress(chatId, step) {
|
|
18044
|
+
if (!BOT_TOKEN) return null;
|
|
18045
|
+
try {
|
|
18046
|
+
const data = await telegramApiCall(
|
|
18047
|
+
"sendMessage",
|
|
18048
|
+
{ chat_id: chatId, text: telegramProgressText(step), disable_notification: true },
|
|
18049
|
+
8e3
|
|
18050
|
+
);
|
|
18051
|
+
return data.ok && data.result?.message_id != null ? String(data.result.message_id) : null;
|
|
18052
|
+
} catch {
|
|
18053
|
+
return null;
|
|
18054
|
+
}
|
|
18055
|
+
}
|
|
18056
|
+
async function updateTelegramProgress(chatId, messageId, step) {
|
|
18057
|
+
if (!BOT_TOKEN) return false;
|
|
18058
|
+
try {
|
|
18059
|
+
const data = await telegramApiCall(
|
|
18060
|
+
"editMessageText",
|
|
18061
|
+
{ chat_id: chatId, message_id: Number(messageId), text: telegramProgressText(step) },
|
|
18062
|
+
8e3
|
|
18063
|
+
);
|
|
18064
|
+
return data.ok === true || /not modified/i.test(data.description ?? "");
|
|
18065
|
+
} catch {
|
|
18066
|
+
return false;
|
|
18067
|
+
}
|
|
18068
|
+
}
|
|
18069
|
+
async function deleteTelegramProgress(chatId, messageId) {
|
|
18070
|
+
if (!BOT_TOKEN) return false;
|
|
18071
|
+
try {
|
|
18072
|
+
const data = await telegramApiCall(
|
|
18073
|
+
"deleteMessage",
|
|
18074
|
+
{ chat_id: chatId, message_id: Number(messageId) },
|
|
18075
|
+
8e3
|
|
18076
|
+
);
|
|
18077
|
+
return data.ok === true || /message to delete not found|message can't be deleted/i.test(data.description ?? "");
|
|
18078
|
+
} catch {
|
|
18079
|
+
return false;
|
|
18080
|
+
}
|
|
18081
|
+
}
|
|
18082
|
+
async function telegramProgressTick() {
|
|
18083
|
+
if (telegramProgressTickRunning) return;
|
|
18084
|
+
telegramProgressTickRunning = true;
|
|
18085
|
+
try {
|
|
18086
|
+
if (!channelLiveProgressEnabled()) {
|
|
18087
|
+
if (telegramTrackedProgress) {
|
|
18088
|
+
if (await deleteTelegramProgress(telegramTrackedProgress.channel, telegramTrackedProgress.ts)) {
|
|
18089
|
+
telegramTrackedProgress = null;
|
|
18090
|
+
}
|
|
18091
|
+
}
|
|
18092
|
+
return;
|
|
18093
|
+
}
|
|
18094
|
+
const action = decideProgressAction({
|
|
18095
|
+
now: Date.now(),
|
|
18096
|
+
heartbeat: readTelegramProgressHeartbeat(),
|
|
18097
|
+
target: findTelegramProgressTarget(),
|
|
18098
|
+
tracked: telegramTrackedProgress,
|
|
18099
|
+
freshnessMs: progressHeartbeatFreshMs(),
|
|
18100
|
+
minPendingMs: progressMinPendingMs()
|
|
18101
|
+
});
|
|
18102
|
+
switch (action.type) {
|
|
18103
|
+
case "post": {
|
|
18104
|
+
const id = await postTelegramProgress(action.channel, action.step);
|
|
18105
|
+
if (id) telegramTrackedProgress = { channel: action.channel, threadTs: action.threadTs, ts: id, lastStep: action.step };
|
|
18106
|
+
break;
|
|
18107
|
+
}
|
|
18108
|
+
case "update": {
|
|
18109
|
+
if (await updateTelegramProgress(action.channel, action.ts, action.step)) {
|
|
18110
|
+
if (telegramTrackedProgress) telegramTrackedProgress.lastStep = action.step;
|
|
18111
|
+
}
|
|
18112
|
+
break;
|
|
18113
|
+
}
|
|
18114
|
+
case "delete": {
|
|
18115
|
+
if (await deleteTelegramProgress(action.channel, action.ts)) {
|
|
18116
|
+
telegramTrackedProgress = null;
|
|
18117
|
+
}
|
|
18118
|
+
break;
|
|
18119
|
+
}
|
|
18120
|
+
case "none":
|
|
18121
|
+
break;
|
|
18122
|
+
}
|
|
18123
|
+
} catch {
|
|
18124
|
+
} finally {
|
|
18125
|
+
telegramProgressTickRunning = false;
|
|
18126
|
+
}
|
|
18127
|
+
}
|
|
18128
|
+
function telegramProgressPollMs() {
|
|
18129
|
+
const raw = parseInt(process.env.AGT_CHANNEL_PROGRESS_POLL_MS ?? "", 10);
|
|
18130
|
+
return Number.isFinite(raw) && raw >= 2e3 ? raw : 8e3;
|
|
18131
|
+
}
|
|
18132
|
+
if (BOT_TOKEN && PENDING_INBOUND_DIR) {
|
|
18133
|
+
const telegramProgressTimer = setInterval(() => {
|
|
18134
|
+
void telegramProgressTick();
|
|
18135
|
+
}, telegramProgressPollMs());
|
|
18136
|
+
telegramProgressTimer.unref?.();
|
|
18137
|
+
}
|
|
17914
18138
|
var lastGiveUpHandledAtMs = null;
|
|
17915
18139
|
function listPendingInboundChatIds() {
|
|
17916
18140
|
if (!PENDING_INBOUND_DIR || !existsSync5(PENDING_INBOUND_DIR)) return [];
|
|
@@ -17922,6 +18146,7 @@ function listPendingInboundChatIds() {
|
|
|
17922
18146
|
const marker = JSON.parse(
|
|
17923
18147
|
readFileSync8(join7(PENDING_INBOUND_DIR, name), "utf8")
|
|
17924
18148
|
);
|
|
18149
|
+
if (typeof marker.seen_at === "string" && marker.seen_at) continue;
|
|
17925
18150
|
if (typeof marker.chat_id === "string" && marker.chat_id) chats.add(marker.chat_id);
|
|
17926
18151
|
} catch {
|
|
17927
18152
|
}
|
|
@@ -18044,9 +18269,18 @@ function clearPendingMessage(chatId, cutoffMs = Number.POSITIVE_INFINITY) {
|
|
|
18044
18269
|
cutoffMs
|
|
18045
18270
|
);
|
|
18046
18271
|
}
|
|
18272
|
+
function markSeenPendingMessage(chatId, cutoffMs = Number.POSITIVE_INFINITY) {
|
|
18273
|
+
if (!PENDING_INBOUND_DIR || !existsSync5(PENDING_INBOUND_DIR)) return;
|
|
18274
|
+
markSeenAllTelegramPendingMarkersForChat(
|
|
18275
|
+
PENDING_INBOUND_DIR,
|
|
18276
|
+
chatId,
|
|
18277
|
+
markTelegramMarkerSeenWithHeal,
|
|
18278
|
+
cutoffMs
|
|
18279
|
+
);
|
|
18280
|
+
}
|
|
18047
18281
|
function noteThreadActivity(chatId, cutoffMs = Number.POSITIVE_INFINITY) {
|
|
18048
18282
|
if (!chatId) return;
|
|
18049
|
-
|
|
18283
|
+
markSeenPendingMessage(chatId, cutoffMs);
|
|
18050
18284
|
}
|
|
18051
18285
|
var SKIP_REACTION_ON = channelSkipReactionEnabled() && TELEGRAM_SKIP_REACTION.length > 0;
|
|
18052
18286
|
var mcp = new Server(
|
|
@@ -18062,7 +18296,7 @@ var mcp = new Server(
|
|
|
18062
18296
|
instructions: [
|
|
18063
18297
|
// Highest-priority lines first — Claude Code truncates this string at
|
|
18064
18298
|
// 2048 chars, so anything appended late silently disappears.
|
|
18065
|
-
"CRITICAL: every response to a Telegram <channel> tag MUST go through telegram.reply with the chat_id from the tag.
|
|
18299
|
+
"CRITICAL: every response to a Telegram <channel> tag MUST go through telegram.reply with the chat_id from the tag \u2014 typed text never reaches the user. Slow work: interim ack (telegram.reply interim:true), then your FINAL answer as a separate telegram.reply (interim omitted). An ack is not the answer.",
|
|
18066
18300
|
'Messages from Telegram arrive as <channel source="telegram" chat_id="..." user="..." user_name="..." message_id="...">. Pass reply_to_message_id from the tag so the response lands as a quote-reply in busy chats.',
|
|
18067
18301
|
"Inbound attachments: <channel> `files` is a JSON-serialised array \u2014 JSON.parse it. If an entry has `path`, the image is already downloaded \u2014 Read it directly, do NOT call telegram.download_attachment. Use that tool only for entries with `file_id` but NO `path` (PDF, docx, voice, audio, video, animations): pass file_id + chat_id verbatim, then Read the returned path. Single-image messages also get a top-level `image_path`. Caption arrives as channel content. Don't surface internal file-handling errors that don't affect the answer.",
|
|
18068
18302
|
'For work >30s follow CLAUDE.md kanban flow: kanban_add \u2192 reply "On it \u2014 tracking here: <kanban URL>" \u2192 move to in_progress \u2192 do the work \u2192 reply with the result. Simple lookups skip kanban but still reply.',
|
|
@@ -18125,6 +18359,10 @@ mcp.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
|
18125
18359
|
reply_to_message_id: {
|
|
18126
18360
|
type: "string",
|
|
18127
18361
|
description: "Optional Telegram message_id to quote-reply to"
|
|
18362
|
+
},
|
|
18363
|
+
interim: {
|
|
18364
|
+
type: "boolean",
|
|
18365
|
+
description: 'Set true ONLY when this is an interim acknowledgement (e.g. "On it \u2014 checking now\u2026") and the real answer is still coming. The system keeps tracking this chat as awaiting your final reply. Your eventual substantive answer MUST be a separate telegram.reply with interim omitted/false \u2014 that is what marks the request complete. Omit (default false) for any reply that fully answers the user.'
|
|
18128
18366
|
}
|
|
18129
18367
|
},
|
|
18130
18368
|
required: ["chat_id", "text"]
|
|
@@ -18196,7 +18434,7 @@ mcp.setRequestHandler(CallToolRequestSchema, async (req) => {
|
|
|
18196
18434
|
return handleChannelRequestInput(args ?? {});
|
|
18197
18435
|
}
|
|
18198
18436
|
if (name === "telegram.reply" || name === "telegram.send_message") {
|
|
18199
|
-
const { chat_id, text, reply_to_message_id } = args;
|
|
18437
|
+
const { chat_id, text, reply_to_message_id, interim } = args;
|
|
18200
18438
|
if (ALLOWED_CHATS.size > 0 && !ALLOWED_CHATS.has(chat_id)) {
|
|
18201
18439
|
return {
|
|
18202
18440
|
content: [{ type: "text", text: `Chat ${chat_id} is not in TELEGRAM_ALLOWED_CHATS` }],
|
|
@@ -18322,7 +18560,8 @@ mcp.setRequestHandler(CallToolRequestSchema, async (req) => {
|
|
|
18322
18560
|
}
|
|
18323
18561
|
recordReply(chat_id, "", tgThrottleNow, tgThrottleCfg);
|
|
18324
18562
|
if (name === "telegram.reply") {
|
|
18325
|
-
|
|
18563
|
+
if (interim) markSeenPendingMessage(chat_id, drainCutoffMs);
|
|
18564
|
+
else clearPendingMessage(chat_id, drainCutoffMs);
|
|
18326
18565
|
}
|
|
18327
18566
|
return { content: [{ type: "text", text: "sent" }] };
|
|
18328
18567
|
} catch (err) {
|
|
@@ -18972,7 +19211,10 @@ async function pollLoop() {
|
|
|
18972
19211
|
await handleOnboardingCommand({
|
|
18973
19212
|
chatId,
|
|
18974
19213
|
messageId: String(msg.message_id),
|
|
18975
|
-
mode: access.command === "onboard" ? "reset" : "resume"
|
|
19214
|
+
mode: access.command === "onboard" ? "reset" : "resume",
|
|
19215
|
+
// ENG-6578: the manager gate compares the SENDER's user-id (not the
|
|
19216
|
+
// chat id — they differ in groups) to the resolved manager principal.
|
|
19217
|
+
senderId: msg.from?.id != null ? String(msg.from.id) : void 0
|
|
18976
19218
|
});
|
|
18977
19219
|
}
|
|
18978
19220
|
continue;
|
package/package.json
CHANGED
|
File without changes
|