@integrity-labs/agt-cli 0.28.329 → 0.28.331
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-AOSBSVNB.js → chunk-4Y3UPOR2.js} +83 -17
- package/dist/chunk-4Y3UPOR2.js.map +1 -0
- package/dist/lib/manager-worker.js +2 -2
- package/dist/mcp/slack-channel.js +115 -86
- package/dist/mcp/teams-channel.js +62 -41
- package/dist/mcp/telegram-channel.js +90 -61
- package/dist/mcp/xero.js +61 -18
- package/package.json +1 -1
- package/dist/chunk-AOSBSVNB.js.map +0 -1
|
@@ -14522,7 +14522,7 @@ import { createHash, randomUUID as randomUUID3 } from "crypto";
|
|
|
14522
14522
|
import {
|
|
14523
14523
|
closeSync,
|
|
14524
14524
|
createWriteStream,
|
|
14525
|
-
existsSync as
|
|
14525
|
+
existsSync as existsSync8,
|
|
14526
14526
|
ftruncateSync,
|
|
14527
14527
|
mkdirSync as mkdirSync8,
|
|
14528
14528
|
openSync,
|
|
@@ -14531,13 +14531,13 @@ import {
|
|
|
14531
14531
|
realpathSync,
|
|
14532
14532
|
renameSync as renameSync6,
|
|
14533
14533
|
statSync as statSync2,
|
|
14534
|
-
unlinkSync as
|
|
14534
|
+
unlinkSync as unlinkSync7,
|
|
14535
14535
|
watch,
|
|
14536
14536
|
writeFileSync as writeFileSync10,
|
|
14537
14537
|
writeSync
|
|
14538
14538
|
} from "fs";
|
|
14539
14539
|
import { homedir as homedir4 } from "os";
|
|
14540
|
-
import { basename, extname, join as
|
|
14540
|
+
import { basename, extname, join as join11, resolve as resolve2 } from "path";
|
|
14541
14541
|
|
|
14542
14542
|
// src/channel-attachments.ts
|
|
14543
14543
|
import { homedir } from "os";
|
|
@@ -17024,6 +17024,29 @@ function applyToChatMarkers(pendingDir, chatId, op, cutoffMs) {
|
|
|
17024
17024
|
return applied;
|
|
17025
17025
|
}
|
|
17026
17026
|
|
|
17027
|
+
// src/recovery-ledger.ts
|
|
17028
|
+
import { existsSync as existsSync6, unlinkSync as unlinkSync5 } from "fs";
|
|
17029
|
+
import { join as join8 } from "path";
|
|
17030
|
+
function recoveryLedgerEntryExists(ledgerDir, markerName, exists = (p) => existsSync6(p)) {
|
|
17031
|
+
if (!ledgerDir || !markerName) return false;
|
|
17032
|
+
if (markerName.includes("/") || markerName.includes("\\") || markerName.includes("..")) return false;
|
|
17033
|
+
try {
|
|
17034
|
+
return exists(join8(ledgerDir, markerName));
|
|
17035
|
+
} catch {
|
|
17036
|
+
return false;
|
|
17037
|
+
}
|
|
17038
|
+
}
|
|
17039
|
+
function removeRecoveryLedgerEntry(ledgerDir, markerName, unlink = (p) => {
|
|
17040
|
+
if (existsSync6(p)) unlinkSync5(p);
|
|
17041
|
+
}) {
|
|
17042
|
+
if (!ledgerDir || !markerName) return;
|
|
17043
|
+
if (markerName.includes("/") || markerName.includes("\\") || markerName.includes("..")) return;
|
|
17044
|
+
try {
|
|
17045
|
+
unlink(join8(ledgerDir, markerName));
|
|
17046
|
+
} catch {
|
|
17047
|
+
}
|
|
17048
|
+
}
|
|
17049
|
+
|
|
17027
17050
|
// src/channel-progress.ts
|
|
17028
17051
|
function channelLiveProgressEnabled() {
|
|
17029
17052
|
return resolveHostBooleanFlag({
|
|
@@ -17208,14 +17231,14 @@ function createKanbanCardActiveClient(args) {
|
|
|
17208
17231
|
|
|
17209
17232
|
// src/mcp-spawn-lock.ts
|
|
17210
17233
|
import {
|
|
17211
|
-
existsSync as
|
|
17234
|
+
existsSync as existsSync7,
|
|
17212
17235
|
mkdirSync as mkdirSync7,
|
|
17213
17236
|
readFileSync as readFileSync9,
|
|
17214
17237
|
renameSync as renameSync5,
|
|
17215
|
-
unlinkSync as
|
|
17238
|
+
unlinkSync as unlinkSync6,
|
|
17216
17239
|
writeFileSync as writeFileSync8
|
|
17217
17240
|
} from "fs";
|
|
17218
|
-
import { join as
|
|
17241
|
+
import { join as join9 } from "path";
|
|
17219
17242
|
function defaultIsPidAlive(pid) {
|
|
17220
17243
|
if (!Number.isFinite(pid) || pid <= 0) return false;
|
|
17221
17244
|
try {
|
|
@@ -17233,7 +17256,7 @@ function acquireMcpSpawnLock(args) {
|
|
|
17233
17256
|
const isPidAlive = options.isPidAlive ?? defaultIsPidAlive;
|
|
17234
17257
|
const selfPid = options.selfPid ?? process.pid;
|
|
17235
17258
|
const now = options.now ?? (() => (/* @__PURE__ */ new Date()).toISOString());
|
|
17236
|
-
const path =
|
|
17259
|
+
const path = join9(agentDir, basename2);
|
|
17237
17260
|
const existing = readLockHolder(path);
|
|
17238
17261
|
if (existing) {
|
|
17239
17262
|
if (existing.pid === selfPid) {
|
|
@@ -17257,12 +17280,12 @@ function releaseMcpSpawnLock(lockPath, opts = {}) {
|
|
|
17257
17280
|
if (!existing) return;
|
|
17258
17281
|
if (existing.pid !== selfPid) return;
|
|
17259
17282
|
try {
|
|
17260
|
-
|
|
17283
|
+
unlinkSync6(lockPath);
|
|
17261
17284
|
} catch {
|
|
17262
17285
|
}
|
|
17263
17286
|
}
|
|
17264
17287
|
function readLockHolder(path) {
|
|
17265
|
-
if (!
|
|
17288
|
+
if (!existsSync7(path)) return null;
|
|
17266
17289
|
try {
|
|
17267
17290
|
const raw = readFileSync9(path, "utf8");
|
|
17268
17291
|
const parsed = JSON.parse(raw);
|
|
@@ -17277,7 +17300,7 @@ function readLockHolder(path) {
|
|
|
17277
17300
|
|
|
17278
17301
|
// src/ack-reaction.ts
|
|
17279
17302
|
import { readdirSync as readdirSync2, readFileSync as readFileSync10, writeFileSync as writeFileSync9 } from "fs";
|
|
17280
|
-
import { join as
|
|
17303
|
+
import { join as join10 } from "path";
|
|
17281
17304
|
var REPLY_WEDGED_THRESHOLD_MS = 5 * 60 * 1e3;
|
|
17282
17305
|
var ACK_STARTUP_GRACE_MS = 6e4;
|
|
17283
17306
|
var ACK_PANE_FRESH_THRESHOLD_MS = 6e4;
|
|
@@ -17385,7 +17408,7 @@ function oldestPendingMarkerAgeMs(dir, now = Date.now(), opts) {
|
|
|
17385
17408
|
if (!name.endsWith(".json")) continue;
|
|
17386
17409
|
let receivedAt;
|
|
17387
17410
|
try {
|
|
17388
|
-
const raw = JSON.parse(readFileSync10(
|
|
17411
|
+
const raw = JSON.parse(readFileSync10(join10(dir, name), "utf-8"));
|
|
17389
17412
|
if (raw.discretionary === true) continue;
|
|
17390
17413
|
if (!opts?.includeSeen && typeof raw.seen_at === "string" && raw.seen_at) continue;
|
|
17391
17414
|
receivedAt = raw.received_at;
|
|
@@ -17453,7 +17476,7 @@ function isMarkerGenuinelyAged(receivedAt, nowMs, thresholdMs) {
|
|
|
17453
17476
|
}
|
|
17454
17477
|
var DEFLECTION_COUNTER_SUFFIX = "-deflections.json";
|
|
17455
17478
|
function deflectionCounterPath(agentDir, channel) {
|
|
17456
|
-
return
|
|
17479
|
+
return join10(agentDir, `${channel}${DEFLECTION_COUNTER_SUFFIX}`);
|
|
17457
17480
|
}
|
|
17458
17481
|
function recordChannelDeflection(agentDir, channel, cause) {
|
|
17459
17482
|
if (!agentDir) return;
|
|
@@ -17541,7 +17564,7 @@ function redactId(id) {
|
|
|
17541
17564
|
}
|
|
17542
17565
|
var BOT_TOKEN = process.env.TELEGRAM_BOT_TOKEN;
|
|
17543
17566
|
var AGENT_CODE_NAME = process.env.AGT_AGENT_CODE_NAME ?? "unknown";
|
|
17544
|
-
var TELEGRAM_AGENT_DIR = AGENT_CODE_NAME && AGENT_CODE_NAME !== "unknown" ?
|
|
17567
|
+
var TELEGRAM_AGENT_DIR = AGENT_CODE_NAME && AGENT_CODE_NAME !== "unknown" ? join11(homedir4(), ".augmented", AGENT_CODE_NAME) : null;
|
|
17545
17568
|
var AGT_HOST = process.env.AGT_HOST ?? null;
|
|
17546
17569
|
var AGT_API_KEY = process.env.AGT_API_KEY ?? null;
|
|
17547
17570
|
var AGT_AGENT_ID = process.env.AGT_AGENT_ID ?? null;
|
|
@@ -17645,9 +17668,9 @@ if (!BOT_TOKEN) {
|
|
|
17645
17668
|
var stderrLogStream = null;
|
|
17646
17669
|
if (AGENT_CODE_NAME && AGENT_CODE_NAME !== "unknown") {
|
|
17647
17670
|
try {
|
|
17648
|
-
const logDir =
|
|
17671
|
+
const logDir = join11(homedir4(), ".augmented", AGENT_CODE_NAME);
|
|
17649
17672
|
mkdirSync8(logDir, { recursive: true });
|
|
17650
|
-
stderrLogStream = createWriteStream(
|
|
17673
|
+
stderrLogStream = createWriteStream(join11(logDir, "telegram-channel-stderr.log"), {
|
|
17651
17674
|
flags: "a",
|
|
17652
17675
|
mode: 384
|
|
17653
17676
|
});
|
|
@@ -17926,7 +17949,7 @@ function scheduleBusyAck(chatId, messageId, arrivedWhileBusy) {
|
|
|
17926
17949
|
let paneLogFreshAgeMs = null;
|
|
17927
17950
|
if (AGENT_DIR) {
|
|
17928
17951
|
try {
|
|
17929
|
-
const paneMtimeMs = statSync2(
|
|
17952
|
+
const paneMtimeMs = statSync2(join11(AGENT_DIR, "pane.log")).mtimeMs;
|
|
17930
17953
|
paneLogFreshAgeMs = Math.max(0, Date.now() - paneMtimeMs);
|
|
17931
17954
|
} catch {
|
|
17932
17955
|
}
|
|
@@ -17956,7 +17979,7 @@ function scheduleBusyAck(chatId, messageId, arrivedWhileBusy) {
|
|
|
17956
17979
|
function __resetBusyAckNoticeThrottle() {
|
|
17957
17980
|
lastBusyAckNoticeAt.clear();
|
|
17958
17981
|
}
|
|
17959
|
-
var RESTART_FLAGS_DIR =
|
|
17982
|
+
var RESTART_FLAGS_DIR = join11(homedir4(), ".augmented", "restart-flags");
|
|
17960
17983
|
function actuateHostRestartTelegram() {
|
|
17961
17984
|
return actuateHostRestart({
|
|
17962
17985
|
agtHost: AGT_HOST,
|
|
@@ -18338,10 +18361,10 @@ async function handleRestartCommand(opts) {
|
|
|
18338
18361
|
writeTelegramRestartConfirm({ chat_id: opts.chatId, message_id: opts.messageId }, opts.requesterName);
|
|
18339
18362
|
} else {
|
|
18340
18363
|
writeTelegramRestartConfirm({ chat_id: opts.chatId, message_id: opts.messageId }, opts.requesterName);
|
|
18341
|
-
if (!
|
|
18364
|
+
if (!existsSync8(RESTART_FLAGS_DIR)) {
|
|
18342
18365
|
mkdirSync8(RESTART_FLAGS_DIR, { recursive: true });
|
|
18343
18366
|
}
|
|
18344
|
-
const flagPath =
|
|
18367
|
+
const flagPath = join11(RESTART_FLAGS_DIR, `${AGENT_CODE_NAME}.flag`);
|
|
18345
18368
|
const flag = {
|
|
18346
18369
|
codeName: AGENT_CODE_NAME,
|
|
18347
18370
|
source: "telegram",
|
|
@@ -18747,14 +18770,15 @@ async function classifyRestartCommand(text) {
|
|
|
18747
18770
|
if (!ours) return "verification_failed";
|
|
18748
18771
|
return target === ours ? "act" : "ignore";
|
|
18749
18772
|
}
|
|
18750
|
-
var AGENT_DIR = AGENT_CODE_NAME && AGENT_CODE_NAME !== "unknown" ?
|
|
18751
|
-
var PENDING_INBOUND_DIR = AGENT_DIR ?
|
|
18752
|
-
var RECOVERY_OUTBOX_DIR = AGENT_DIR ?
|
|
18753
|
-
var
|
|
18773
|
+
var AGENT_DIR = AGENT_CODE_NAME && AGENT_CODE_NAME !== "unknown" ? join11(homedir4(), ".augmented", AGENT_CODE_NAME) : null;
|
|
18774
|
+
var PENDING_INBOUND_DIR = AGENT_DIR ? join11(AGENT_DIR, "telegram-pending-inbound") : null;
|
|
18775
|
+
var RECOVERY_OUTBOX_DIR = AGENT_DIR ? join11(AGENT_DIR, "telegram-recovery-outbox") : null;
|
|
18776
|
+
var RECOVERY_LEDGER_DIR = AGENT_DIR ? join11(AGENT_DIR, ".agt-telegram-recovery-ledger") : null;
|
|
18777
|
+
var RESTART_CONFIRM_FILE = AGENT_DIR ? join11(AGENT_DIR, "telegram-restart-confirm.json") : null;
|
|
18754
18778
|
var TELEGRAM_PROCESS_BOOT_MS = Date.now();
|
|
18755
|
-
var TELEGRAM_RECENT_DMS_FILE = AGENT_DIR ?
|
|
18756
|
-
var TELEGRAM_CHANNEL_ADD_RESTART_FILE = AGENT_DIR ?
|
|
18757
|
-
var TELEGRAM_OFFSET_FILE = AGENT_DIR ?
|
|
18779
|
+
var TELEGRAM_RECENT_DMS_FILE = AGENT_DIR ? join11(AGENT_DIR, "telegram-recent-dms.json") : null;
|
|
18780
|
+
var TELEGRAM_CHANNEL_ADD_RESTART_FILE = AGENT_DIR ? join11(AGENT_DIR, "telegram-channel-add-restart.json") : null;
|
|
18781
|
+
var TELEGRAM_OFFSET_FILE = AGENT_DIR ? join11(AGENT_DIR, "telegram-getupdates-offset.json") : null;
|
|
18758
18782
|
var recentDms = /* @__PURE__ */ new Map();
|
|
18759
18783
|
var recentDmPersister = TELEGRAM_RECENT_DMS_FILE ? createRecentDmPersister({
|
|
18760
18784
|
filePath: TELEGRAM_RECENT_DMS_FILE,
|
|
@@ -18809,7 +18833,7 @@ function safeMarkerName(chatId, messageId) {
|
|
|
18809
18833
|
}
|
|
18810
18834
|
function pendingInboundPath(chatId, messageId) {
|
|
18811
18835
|
if (!PENDING_INBOUND_DIR) return null;
|
|
18812
|
-
return
|
|
18836
|
+
return join11(PENDING_INBOUND_DIR, safeMarkerName(chatId, messageId));
|
|
18813
18837
|
}
|
|
18814
18838
|
function writePendingInboundMarker(chatId, messageId, chatType, undeliverable = false, payload) {
|
|
18815
18839
|
const path = pendingInboundPath(chatId, messageId);
|
|
@@ -18865,7 +18889,7 @@ function clearTelegramMarkerFileWithHeal(fullPath) {
|
|
|
18865
18889
|
notifyBackOnline(marker.chat_id);
|
|
18866
18890
|
}
|
|
18867
18891
|
try {
|
|
18868
|
-
if (
|
|
18892
|
+
if (existsSync8(fullPath)) unlinkSync7(fullPath);
|
|
18869
18893
|
} catch {
|
|
18870
18894
|
}
|
|
18871
18895
|
}
|
|
@@ -18898,7 +18922,7 @@ function markTelegramMarkerSeenWithHeal(fullPath) {
|
|
|
18898
18922
|
}
|
|
18899
18923
|
function readPendingInboundMarker(chatId, messageId) {
|
|
18900
18924
|
const path = pendingInboundPath(chatId, messageId);
|
|
18901
|
-
if (!path || !
|
|
18925
|
+
if (!path || !existsSync8(path)) return null;
|
|
18902
18926
|
try {
|
|
18903
18927
|
return JSON.parse(readFileSync11(path, "utf-8"));
|
|
18904
18928
|
} catch {
|
|
@@ -18920,7 +18944,7 @@ function nextRetryName(filename) {
|
|
|
18920
18944
|
async function processRecoveryOutboxFile(filename) {
|
|
18921
18945
|
if (!RECOVERY_OUTBOX_DIR) return;
|
|
18922
18946
|
if (filename.endsWith(".poison.json") || filename.endsWith(".tmp")) return;
|
|
18923
|
-
const fullPath =
|
|
18947
|
+
const fullPath = join11(RECOVERY_OUTBOX_DIR, filename);
|
|
18924
18948
|
let payload;
|
|
18925
18949
|
try {
|
|
18926
18950
|
const raw = readFileSync11(fullPath, "utf-8");
|
|
@@ -18941,6 +18965,7 @@ async function processRecoveryOutboxFile(filename) {
|
|
|
18941
18965
|
`telegram-channel(${AGENT_CODE_NAME}): recovery outbox malformed (${filename}): missing chat_id or text
|
|
18942
18966
|
`
|
|
18943
18967
|
);
|
|
18968
|
+
removeRecoveryLedgerEntry(RECOVERY_LEDGER_DIR, payload.marker_name);
|
|
18944
18969
|
try {
|
|
18945
18970
|
renameSync6(fullPath, `${fullPath}.malformed.poison`);
|
|
18946
18971
|
} catch {
|
|
@@ -18969,8 +18994,9 @@ async function processRecoveryOutboxFile(filename) {
|
|
|
18969
18994
|
);
|
|
18970
18995
|
if (decision.action === "suppress") {
|
|
18971
18996
|
clearPendingMessage(payload.chat_id, recoveryDrainCutoffMs);
|
|
18997
|
+
removeRecoveryLedgerEntry(RECOVERY_LEDGER_DIR, payload.marker_name);
|
|
18972
18998
|
try {
|
|
18973
|
-
|
|
18999
|
+
unlinkSync7(fullPath);
|
|
18974
19000
|
} catch {
|
|
18975
19001
|
}
|
|
18976
19002
|
return;
|
|
@@ -19005,8 +19031,9 @@ async function processRecoveryOutboxFile(filename) {
|
|
|
19005
19031
|
);
|
|
19006
19032
|
}
|
|
19007
19033
|
if (sendSucceeded) {
|
|
19034
|
+
removeRecoveryLedgerEntry(RECOVERY_LEDGER_DIR, payload.marker_name);
|
|
19008
19035
|
try {
|
|
19009
|
-
|
|
19036
|
+
unlinkSync7(fullPath);
|
|
19010
19037
|
} catch {
|
|
19011
19038
|
}
|
|
19012
19039
|
return;
|
|
@@ -19014,12 +19041,13 @@ async function processRecoveryOutboxFile(filename) {
|
|
|
19014
19041
|
const next = nextRetryName(filename);
|
|
19015
19042
|
if (next) {
|
|
19016
19043
|
try {
|
|
19017
|
-
renameSync6(fullPath,
|
|
19044
|
+
renameSync6(fullPath, join11(RECOVERY_OUTBOX_DIR, next.next));
|
|
19018
19045
|
if (next.attempt >= MAX_RECOVERY_ATTEMPTS) {
|
|
19019
19046
|
process.stderr.write(
|
|
19020
19047
|
`telegram-channel(${AGENT_CODE_NAME}): ghost-reply recovery exhausted retries \u2014 moved to ${next.next}
|
|
19021
19048
|
`
|
|
19022
19049
|
);
|
|
19050
|
+
removeRecoveryLedgerEntry(RECOVERY_LEDGER_DIR, payload.marker_name);
|
|
19023
19051
|
}
|
|
19024
19052
|
} catch {
|
|
19025
19053
|
}
|
|
@@ -19054,7 +19082,7 @@ function scanRecoveryRetries() {
|
|
|
19054
19082
|
if (!f.includes(".retry-") || f.endsWith(".poison.json")) continue;
|
|
19055
19083
|
let mtimeMs;
|
|
19056
19084
|
try {
|
|
19057
|
-
mtimeMs = statSync2(
|
|
19085
|
+
mtimeMs = statSync2(join11(RECOVERY_OUTBOX_DIR, f)).mtimeMs;
|
|
19058
19086
|
} catch {
|
|
19059
19087
|
continue;
|
|
19060
19088
|
}
|
|
@@ -19084,7 +19112,7 @@ function startRecoveryOutboxWatcher() {
|
|
|
19084
19112
|
const watcher = watch(RECOVERY_OUTBOX_DIR, (event, filename) => {
|
|
19085
19113
|
if (event !== "rename" || !filename) return;
|
|
19086
19114
|
if (!isFirstAttemptOutboxFile(filename)) return;
|
|
19087
|
-
if (
|
|
19115
|
+
if (existsSync8(join11(RECOVERY_OUTBOX_DIR, filename))) {
|
|
19088
19116
|
void processRecoveryOutboxFile(filename);
|
|
19089
19117
|
}
|
|
19090
19118
|
});
|
|
@@ -19099,7 +19127,7 @@ function startRecoveryOutboxWatcher() {
|
|
|
19099
19127
|
retryTimer.unref?.();
|
|
19100
19128
|
}
|
|
19101
19129
|
startRecoveryOutboxWatcher();
|
|
19102
|
-
var NOTICE_OUTBOX_DIR = AGENT_DIR ?
|
|
19130
|
+
var NOTICE_OUTBOX_DIR = AGENT_DIR ? join11(AGENT_DIR, "telegram-notice-outbox") : null;
|
|
19103
19131
|
var NOTICE_MAX_AGE_MS = 9e4;
|
|
19104
19132
|
var NOTICE_INFLIGHT = /* @__PURE__ */ new Set();
|
|
19105
19133
|
async function processNoticeOutboxFile(filename) {
|
|
@@ -19107,7 +19135,7 @@ async function processNoticeOutboxFile(filename) {
|
|
|
19107
19135
|
if (filename.startsWith(".") || filename.endsWith(".tmp") || !filename.endsWith(".json")) return;
|
|
19108
19136
|
if (NOTICE_INFLIGHT.has(filename)) return;
|
|
19109
19137
|
NOTICE_INFLIGHT.add(filename);
|
|
19110
|
-
const fullPath =
|
|
19138
|
+
const fullPath = join11(NOTICE_OUTBOX_DIR, filename);
|
|
19111
19139
|
try {
|
|
19112
19140
|
let mtimeMs;
|
|
19113
19141
|
try {
|
|
@@ -19117,7 +19145,7 @@ async function processNoticeOutboxFile(filename) {
|
|
|
19117
19145
|
}
|
|
19118
19146
|
if (Date.now() - mtimeMs > NOTICE_MAX_AGE_MS) {
|
|
19119
19147
|
try {
|
|
19120
|
-
|
|
19148
|
+
unlinkSync7(fullPath);
|
|
19121
19149
|
} catch {
|
|
19122
19150
|
}
|
|
19123
19151
|
return;
|
|
@@ -19129,14 +19157,14 @@ async function processNoticeOutboxFile(filename) {
|
|
|
19129
19157
|
payload = parsed;
|
|
19130
19158
|
} catch {
|
|
19131
19159
|
try {
|
|
19132
|
-
|
|
19160
|
+
unlinkSync7(fullPath);
|
|
19133
19161
|
} catch {
|
|
19134
19162
|
}
|
|
19135
19163
|
return;
|
|
19136
19164
|
}
|
|
19137
19165
|
if (!payload.chat_id || !payload.text) {
|
|
19138
19166
|
try {
|
|
19139
|
-
|
|
19167
|
+
unlinkSync7(fullPath);
|
|
19140
19168
|
} catch {
|
|
19141
19169
|
}
|
|
19142
19170
|
return;
|
|
@@ -19147,7 +19175,7 @@ async function processNoticeOutboxFile(filename) {
|
|
|
19147
19175
|
defaultValue: false
|
|
19148
19176
|
})) {
|
|
19149
19177
|
try {
|
|
19150
|
-
|
|
19178
|
+
unlinkSync7(fullPath);
|
|
19151
19179
|
} catch {
|
|
19152
19180
|
}
|
|
19153
19181
|
return;
|
|
@@ -19176,7 +19204,7 @@ async function processNoticeOutboxFile(filename) {
|
|
|
19176
19204
|
);
|
|
19177
19205
|
}
|
|
19178
19206
|
try {
|
|
19179
|
-
|
|
19207
|
+
unlinkSync7(fullPath);
|
|
19180
19208
|
} catch {
|
|
19181
19209
|
}
|
|
19182
19210
|
} finally {
|
|
@@ -19201,7 +19229,7 @@ function startNoticeOutboxWatcher() {
|
|
|
19201
19229
|
try {
|
|
19202
19230
|
const watcher = watch(NOTICE_OUTBOX_DIR, (event, filename) => {
|
|
19203
19231
|
if (event !== "rename" || !filename) return;
|
|
19204
|
-
if (
|
|
19232
|
+
if (existsSync8(join11(NOTICE_OUTBOX_DIR, filename))) void processNoticeOutboxFile(filename);
|
|
19205
19233
|
});
|
|
19206
19234
|
watcher.unref?.();
|
|
19207
19235
|
} catch (err) {
|
|
@@ -19218,7 +19246,7 @@ function trackPendingMessage(chatId, messageId, chatType, undeliverable = false,
|
|
|
19218
19246
|
}
|
|
19219
19247
|
function sweepTelegramStaleMarkers(thresholdMs) {
|
|
19220
19248
|
if (!PENDING_INBOUND_DIR) return;
|
|
19221
|
-
if (!
|
|
19249
|
+
if (!existsSync8(PENDING_INBOUND_DIR)) return;
|
|
19222
19250
|
let filenames;
|
|
19223
19251
|
try {
|
|
19224
19252
|
filenames = readdirSync3(PENDING_INBOUND_DIR);
|
|
@@ -19234,7 +19262,7 @@ function sweepTelegramStaleMarkers(thresholdMs) {
|
|
|
19234
19262
|
for (const filename of filenames) {
|
|
19235
19263
|
if (!filename.endsWith(".json")) continue;
|
|
19236
19264
|
if (filename.endsWith(".tmp")) continue;
|
|
19237
|
-
const fullPath =
|
|
19265
|
+
const fullPath = join11(PENDING_INBOUND_DIR, filename);
|
|
19238
19266
|
let marker;
|
|
19239
19267
|
try {
|
|
19240
19268
|
marker = JSON.parse(readFileSync11(fullPath, "utf-8"));
|
|
@@ -19244,7 +19272,7 @@ function sweepTelegramStaleMarkers(thresholdMs) {
|
|
|
19244
19272
|
`
|
|
19245
19273
|
);
|
|
19246
19274
|
try {
|
|
19247
|
-
|
|
19275
|
+
unlinkSync7(fullPath);
|
|
19248
19276
|
} catch {
|
|
19249
19277
|
}
|
|
19250
19278
|
cleared++;
|
|
@@ -19262,7 +19290,7 @@ function sweepTelegramStaleMarkers(thresholdMs) {
|
|
|
19262
19290
|
);
|
|
19263
19291
|
}
|
|
19264
19292
|
try {
|
|
19265
|
-
|
|
19293
|
+
unlinkSync7(fullPath);
|
|
19266
19294
|
} catch {
|
|
19267
19295
|
}
|
|
19268
19296
|
cleared++;
|
|
@@ -19283,11 +19311,11 @@ var orphanSweepTimer = setInterval(() => {
|
|
|
19283
19311
|
checkWatchdogGiveUpNotice();
|
|
19284
19312
|
}, orphanSweepIntervalMs());
|
|
19285
19313
|
orphanSweepTimer.unref?.();
|
|
19286
|
-
var TELEGRAM_PROGRESS_HEARTBEAT_PATH = AGENT_DIR ?
|
|
19314
|
+
var TELEGRAM_PROGRESS_HEARTBEAT_PATH = AGENT_DIR ? join11(AGENT_DIR, "channel-progress-heartbeat.json") : null;
|
|
19287
19315
|
var telegramTrackedProgress = null;
|
|
19288
19316
|
var telegramProgressTickRunning = false;
|
|
19289
19317
|
function readTelegramProgressHeartbeat() {
|
|
19290
|
-
if (!TELEGRAM_PROGRESS_HEARTBEAT_PATH || !
|
|
19318
|
+
if (!TELEGRAM_PROGRESS_HEARTBEAT_PATH || !existsSync8(TELEGRAM_PROGRESS_HEARTBEAT_PATH)) return null;
|
|
19291
19319
|
try {
|
|
19292
19320
|
return parseProgressHeartbeat(readFileSync11(TELEGRAM_PROGRESS_HEARTBEAT_PATH, "utf-8"));
|
|
19293
19321
|
} catch {
|
|
@@ -19302,13 +19330,13 @@ function seedTelegramProgressHeartbeat() {
|
|
|
19302
19330
|
renameSync6(tmp, TELEGRAM_PROGRESS_HEARTBEAT_PATH);
|
|
19303
19331
|
} catch {
|
|
19304
19332
|
try {
|
|
19305
|
-
|
|
19333
|
+
unlinkSync7(tmp);
|
|
19306
19334
|
} catch {
|
|
19307
19335
|
}
|
|
19308
19336
|
}
|
|
19309
19337
|
}
|
|
19310
19338
|
function findTelegramProgressTarget() {
|
|
19311
|
-
if (!PENDING_INBOUND_DIR || !
|
|
19339
|
+
if (!PENDING_INBOUND_DIR || !existsSync8(PENDING_INBOUND_DIR)) return null;
|
|
19312
19340
|
let best = null;
|
|
19313
19341
|
let bestMs = Infinity;
|
|
19314
19342
|
try {
|
|
@@ -19316,7 +19344,7 @@ function findTelegramProgressTarget() {
|
|
|
19316
19344
|
if (!name.endsWith(".json")) continue;
|
|
19317
19345
|
let m;
|
|
19318
19346
|
try {
|
|
19319
|
-
m = JSON.parse(readFileSync11(
|
|
19347
|
+
m = JSON.parse(readFileSync11(join11(PENDING_INBOUND_DIR, name), "utf-8"));
|
|
19320
19348
|
} catch {
|
|
19321
19349
|
continue;
|
|
19322
19350
|
}
|
|
@@ -19440,14 +19468,14 @@ if (BOT_TOKEN && PENDING_INBOUND_DIR) {
|
|
|
19440
19468
|
}
|
|
19441
19469
|
var lastGiveUpHandledAtMs = null;
|
|
19442
19470
|
function listPendingInboundChatIds() {
|
|
19443
|
-
if (!PENDING_INBOUND_DIR || !
|
|
19471
|
+
if (!PENDING_INBOUND_DIR || !existsSync8(PENDING_INBOUND_DIR)) return [];
|
|
19444
19472
|
const chats = /* @__PURE__ */ new Set();
|
|
19445
19473
|
try {
|
|
19446
19474
|
for (const name of readdirSync3(PENDING_INBOUND_DIR)) {
|
|
19447
19475
|
if (!name.endsWith(".json")) continue;
|
|
19448
19476
|
try {
|
|
19449
19477
|
const marker = JSON.parse(
|
|
19450
|
-
readFileSync11(
|
|
19478
|
+
readFileSync11(join11(PENDING_INBOUND_DIR, name), "utf8")
|
|
19451
19479
|
);
|
|
19452
19480
|
if (typeof marker.seen_at === "string" && marker.seen_at) continue;
|
|
19453
19481
|
if (typeof marker.chat_id === "string" && marker.chat_id) chats.add(marker.chat_id);
|
|
@@ -19489,7 +19517,7 @@ async function notifyWatchdogGiveUp(chatId, reason) {
|
|
|
19489
19517
|
}
|
|
19490
19518
|
function checkWatchdogGiveUpNotice() {
|
|
19491
19519
|
if (!AGENT_DIR) return;
|
|
19492
|
-
const signal = readGiveUpSignal(
|
|
19520
|
+
const signal = readGiveUpSignal(join11(AGENT_DIR, GIVE_UP_SIGNAL_FILENAME));
|
|
19493
19521
|
const signalAtMs = signal?.atMs ?? null;
|
|
19494
19522
|
const act = decideGiveUpNotice({
|
|
19495
19523
|
signalAtMs,
|
|
@@ -19551,7 +19579,7 @@ async function deliverQueuedReply(p) {
|
|
|
19551
19579
|
}
|
|
19552
19580
|
}
|
|
19553
19581
|
function clearPendingMessage(chatId, cutoffMs = Number.POSITIVE_INFINITY) {
|
|
19554
|
-
if (!PENDING_INBOUND_DIR || !
|
|
19582
|
+
if (!PENDING_INBOUND_DIR || !existsSync8(PENDING_INBOUND_DIR)) return;
|
|
19555
19583
|
clearAllTelegramPendingMarkersForChat(
|
|
19556
19584
|
PENDING_INBOUND_DIR,
|
|
19557
19585
|
chatId,
|
|
@@ -19560,7 +19588,7 @@ function clearPendingMessage(chatId, cutoffMs = Number.POSITIVE_INFINITY) {
|
|
|
19560
19588
|
);
|
|
19561
19589
|
}
|
|
19562
19590
|
function markSeenPendingMessage(chatId, cutoffMs = Number.POSITIVE_INFINITY) {
|
|
19563
|
-
if (!PENDING_INBOUND_DIR || !
|
|
19591
|
+
if (!PENDING_INBOUND_DIR || !existsSync8(PENDING_INBOUND_DIR)) return;
|
|
19564
19592
|
markSeenAllTelegramPendingMarkersForChat(
|
|
19565
19593
|
PENDING_INBOUND_DIR,
|
|
19566
19594
|
chatId,
|
|
@@ -20386,7 +20414,7 @@ await mcp.connect(new StdioServerTransport());
|
|
|
20386
20414
|
var REPLAY_SCAN_INTERVAL_MS = 6e4;
|
|
20387
20415
|
async function replayPendingTelegramMarkers() {
|
|
20388
20416
|
if (!channelReplayEnabled()) return;
|
|
20389
|
-
if (!PENDING_INBOUND_DIR || !
|
|
20417
|
+
if (!PENDING_INBOUND_DIR || !existsSync8(PENDING_INBOUND_DIR)) return;
|
|
20390
20418
|
const probe = process.env.TMUX && AGENT_CODE_NAME && AGENT_CODE_NAME !== "unknown" ? probeAgentSessionCached(AGENT_CODE_NAME) : { tmux: "unknown", claude: "unknown" };
|
|
20391
20419
|
const sessionAlive = probe.tmux === "alive" && probe.claude === "alive";
|
|
20392
20420
|
if (!sessionAlive) return;
|
|
@@ -20400,7 +20428,7 @@ async function replayPendingTelegramMarkers() {
|
|
|
20400
20428
|
let paneFreshAgeMs = null;
|
|
20401
20429
|
if (AGENT_DIR) {
|
|
20402
20430
|
try {
|
|
20403
|
-
paneFreshAgeMs = Math.max(0, now - statSync2(
|
|
20431
|
+
paneFreshAgeMs = Math.max(0, now - statSync2(join11(AGENT_DIR, "pane.log")).mtimeMs);
|
|
20404
20432
|
} catch {
|
|
20405
20433
|
}
|
|
20406
20434
|
}
|
|
@@ -20408,7 +20436,7 @@ async function replayPendingTelegramMarkers() {
|
|
|
20408
20436
|
const entries = [];
|
|
20409
20437
|
for (const name of filenames) {
|
|
20410
20438
|
if (!name.endsWith(".json") || name.endsWith(".tmp")) continue;
|
|
20411
|
-
const fullPath =
|
|
20439
|
+
const fullPath = join11(PENDING_INBOUND_DIR, name);
|
|
20412
20440
|
let marker;
|
|
20413
20441
|
try {
|
|
20414
20442
|
marker = JSON.parse(readFileSync11(fullPath, "utf-8"));
|
|
@@ -20421,6 +20449,7 @@ async function replayPendingTelegramMarkers() {
|
|
|
20421
20449
|
}
|
|
20422
20450
|
entries.sort((a, b) => b.ageMs - a.ageMs);
|
|
20423
20451
|
for (const { path, marker, ageMs } of entries) {
|
|
20452
|
+
if (recoveryLedgerEntryExists(RECOVERY_LEDGER_DIR, basename(path))) continue;
|
|
20424
20453
|
if (!shouldReplayMarker({
|
|
20425
20454
|
enabled: true,
|
|
20426
20455
|
hasPayload: Boolean(marker.payload),
|
|
@@ -20930,7 +20959,7 @@ async function pollLoop() {
|
|
|
20930
20959
|
let paneLogFreshAgeMs = null;
|
|
20931
20960
|
if (AGENT_DIR) {
|
|
20932
20961
|
try {
|
|
20933
|
-
const paneMtimeMs = statSync2(
|
|
20962
|
+
const paneMtimeMs = statSync2(join11(AGENT_DIR, "pane.log")).mtimeMs;
|
|
20934
20963
|
paneLogFreshAgeMs = Math.max(0, Date.now() - paneMtimeMs);
|
|
20935
20964
|
} catch {
|
|
20936
20965
|
}
|
package/dist/mcp/xero.js
CHANGED
|
@@ -114409,7 +114409,8 @@ var BrokerCredentialClient = class {
|
|
|
114409
114409
|
accessToken: res.data.access_token,
|
|
114410
114410
|
tenantId: res.data.tenant_id ?? null,
|
|
114411
114411
|
expiresAt: res.data.expires_at ?? null,
|
|
114412
|
-
grantedScopes: res.data.granted_scopes ?? null
|
|
114412
|
+
grantedScopes: res.data.granted_scopes ?? null,
|
|
114413
|
+
effectiveScopes: res.data.effective_scopes ?? null
|
|
114413
114414
|
};
|
|
114414
114415
|
} catch (err) {
|
|
114415
114416
|
if (err.status !== void 0) throw err;
|
|
@@ -120511,38 +120512,80 @@ function writesGoViaBroker() {
|
|
|
120511
120512
|
const raw = (process.env.XERO_WRITES_VIA_BROKER ?? "").trim().toLowerCase();
|
|
120512
120513
|
return raw === "true" || raw === "1" || raw === "yes";
|
|
120513
120514
|
}
|
|
120514
|
-
|
|
120515
|
+
var SCOPE_GATES = [
|
|
120516
|
+
{ family: /payroll/i, requiresScope: "payroll" }
|
|
120517
|
+
];
|
|
120518
|
+
function makeToolGate(effectiveScopes) {
|
|
120519
|
+
if (effectiveScopes == null) return () => true;
|
|
120520
|
+
const scopes = effectiveScopes.toLowerCase();
|
|
120521
|
+
return (toolName) => {
|
|
120522
|
+
for (const gate of SCOPE_GATES) {
|
|
120523
|
+
if (gate.family.test(toolName) && !scopes.includes(gate.requiresScope)) {
|
|
120524
|
+
return false;
|
|
120525
|
+
}
|
|
120526
|
+
}
|
|
120527
|
+
return true;
|
|
120528
|
+
};
|
|
120529
|
+
}
|
|
120530
|
+
function ToolFactory(server, effectiveScopes = null) {
|
|
120515
120531
|
const readOnly = writesGoViaBroker();
|
|
120532
|
+
const allow = makeToolGate(effectiveScopes);
|
|
120516
120533
|
if (readOnly) {
|
|
120517
120534
|
console.error(
|
|
120518
120535
|
"xero-mcp-server: XERO_WRITES_VIA_BROKER is set \u2014 registering read-only tools only (Get/List). Create/Update/Delete are gated through the Augmented xero-broker (HITL)."
|
|
120519
120536
|
);
|
|
120520
120537
|
}
|
|
120521
|
-
|
|
120522
|
-
|
|
120523
|
-
|
|
120524
|
-
|
|
120525
|
-
|
|
120526
|
-
);
|
|
120538
|
+
if (effectiveScopes != null && !effectiveScopes.toLowerCase().includes("payroll")) {
|
|
120539
|
+
console.error(
|
|
120540
|
+
"xero-mcp-server: agent policy excludes payroll scopes \u2014 payroll tools not registered (ENG-7824)."
|
|
120541
|
+
);
|
|
120542
|
+
}
|
|
120543
|
+
GetTools.map((tool) => tool()).filter((tool) => allow(tool.name)).forEach((tool) => server.tool(tool.name, tool.description, tool.schema, tool.handler));
|
|
120544
|
+
ListTools.map((tool) => tool()).filter((tool) => allow(tool.name)).forEach((tool) => server.tool(tool.name, tool.description, tool.schema, tool.handler));
|
|
120527
120545
|
AttachmentTools.map((tool) => tool()).forEach(
|
|
120528
120546
|
(tool) => server.tool(tool.name, tool.description, tool.schema, tool.handler)
|
|
120529
120547
|
);
|
|
120530
120548
|
if (readOnly) return;
|
|
120531
|
-
DeleteTools.map((tool) => tool()).forEach(
|
|
120532
|
-
|
|
120533
|
-
);
|
|
120534
|
-
CreateTools.map((tool) => tool()).forEach(
|
|
120535
|
-
(tool) => server.tool(tool.name, tool.description, tool.schema, tool.handler)
|
|
120536
|
-
);
|
|
120537
|
-
UpdateTools.map((tool) => tool()).forEach(
|
|
120538
|
-
(tool) => server.tool(tool.name, tool.description, tool.schema, tool.handler)
|
|
120539
|
-
);
|
|
120549
|
+
DeleteTools.map((tool) => tool()).filter((tool) => allow(tool.name)).forEach((tool) => server.tool(tool.name, tool.description, tool.schema, tool.handler));
|
|
120550
|
+
CreateTools.map((tool) => tool()).filter((tool) => allow(tool.name)).forEach((tool) => server.tool(tool.name, tool.description, tool.schema, tool.handler));
|
|
120551
|
+
UpdateTools.map((tool) => tool()).filter((tool) => allow(tool.name)).forEach((tool) => server.tool(tool.name, tool.description, tool.schema, tool.handler));
|
|
120540
120552
|
}
|
|
120541
120553
|
|
|
120542
120554
|
// src/index.ts
|
|
120555
|
+
async function resolveEffectiveScopes() {
|
|
120556
|
+
const host = process.env.AGT_HOST;
|
|
120557
|
+
const agentId = process.env.AGT_AGENT_ID;
|
|
120558
|
+
const integrationId = process.env.AGT_INTEGRATION_ID;
|
|
120559
|
+
const initialToken = process.env.AGT_TOKEN;
|
|
120560
|
+
const apiKey = process.env.AGT_API_KEY;
|
|
120561
|
+
const brokerMode = Boolean(host && agentId && integrationId && (initialToken || apiKey));
|
|
120562
|
+
if (!brokerMode) return null;
|
|
120563
|
+
try {
|
|
120564
|
+
const client = new BrokerCredentialClient({
|
|
120565
|
+
host,
|
|
120566
|
+
initialToken,
|
|
120567
|
+
apiKey,
|
|
120568
|
+
agentId,
|
|
120569
|
+
integrationId
|
|
120570
|
+
});
|
|
120571
|
+
const cred = await Promise.race([
|
|
120572
|
+
client.fetchCredential(),
|
|
120573
|
+
new Promise(
|
|
120574
|
+
(_, reject) => setTimeout(() => reject(new Error("effective-scope resolution timed out")), 8e3)
|
|
120575
|
+
)
|
|
120576
|
+
]);
|
|
120577
|
+
return cred.effectiveScopes;
|
|
120578
|
+
} catch (err) {
|
|
120579
|
+
console.error(
|
|
120580
|
+
`xero-mcp-server: effective-scope resolution failed, registering all tools (fail-open): ${err.message}`
|
|
120581
|
+
);
|
|
120582
|
+
return null;
|
|
120583
|
+
}
|
|
120584
|
+
}
|
|
120543
120585
|
var main = async () => {
|
|
120544
120586
|
const server = XeroMcpServer.GetServer();
|
|
120545
|
-
|
|
120587
|
+
const effectiveScopes = await resolveEffectiveScopes();
|
|
120588
|
+
ToolFactory(server, effectiveScopes);
|
|
120546
120589
|
const transport = new StdioServerTransport();
|
|
120547
120590
|
await server.connect(transport);
|
|
120548
120591
|
};
|