@integrity-labs/agt-cli 0.28.77 → 0.28.79
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 +4 -4
- package/dist/{chunk-XHKMS4UY.js → chunk-3KLQA3SC.js} +8 -1
- package/dist/chunk-3KLQA3SC.js.map +1 -0
- package/dist/{chunk-EHSKP4FA.js → chunk-N7FYQX2R.js} +128 -8
- package/dist/chunk-N7FYQX2R.js.map +1 -0
- package/dist/{chunk-PEVDRQJA.js → chunk-XDZFMTY5.js} +2 -2
- package/dist/{claude-pair-runtime-IGVIKCHS.js → claude-pair-runtime-6XYMSC6B.js} +2 -2
- package/dist/lib/manager-worker.js +14 -9
- package/dist/lib/manager-worker.js.map +1 -1
- package/dist/mcp/slack-channel.js +298 -46
- package/dist/mcp/telegram-channel.js +1 -0
- package/dist/{persistent-session-Z3RHQRVC.js → persistent-session-U6P5I6TT.js} +3 -3
- package/dist/{responsiveness-probe-QWO75M34.js → responsiveness-probe-VKIJY4IC.js} +3 -3
- package/package.json +1 -1
- package/dist/chunk-EHSKP4FA.js.map +0 -1
- package/dist/chunk-XHKMS4UY.js.map +0 -1
- /package/dist/{chunk-PEVDRQJA.js.map → chunk-XDZFMTY5.js.map} +0 -0
- /package/dist/{claude-pair-runtime-IGVIKCHS.js.map → claude-pair-runtime-6XYMSC6B.js.map} +0 -0
- /package/dist/{persistent-session-Z3RHQRVC.js.map → persistent-session-U6P5I6TT.js.map} +0 -0
- /package/dist/{responsiveness-probe-QWO75M34.js.map → responsiveness-probe-VKIJY4IC.js.map} +0 -0
|
@@ -14618,6 +14618,7 @@ function oldestPendingMarkerAgeMs(dir, now = Date.now()) {
|
|
|
14618
14618
|
try {
|
|
14619
14619
|
const raw = JSON.parse(readFileSync2(join2(dir, name), "utf-8"));
|
|
14620
14620
|
if (raw.discretionary === true) continue;
|
|
14621
|
+
if (typeof raw.seen_at === "string" && raw.seen_at) continue;
|
|
14621
14622
|
receivedAt = raw.received_at;
|
|
14622
14623
|
} catch {
|
|
14623
14624
|
continue;
|
|
@@ -15261,34 +15262,36 @@ var defaultClearMarkerFile = (fullPath) => {
|
|
|
15261
15262
|
} catch {
|
|
15262
15263
|
}
|
|
15263
15264
|
};
|
|
15264
|
-
function
|
|
15265
|
+
function applyToMatchingMarkers(dir, prefix, suffix, op) {
|
|
15265
15266
|
if (!dir) return 0;
|
|
15266
|
-
|
|
15267
|
-
let cleared = 0;
|
|
15267
|
+
let applied = 0;
|
|
15268
15268
|
try {
|
|
15269
15269
|
for (const f of readdirSync2(dir)) {
|
|
15270
|
-
if (!f.startsWith(prefix) || !f.endsWith(
|
|
15271
|
-
|
|
15272
|
-
|
|
15270
|
+
if (!f.startsWith(prefix) || !f.endsWith(suffix)) continue;
|
|
15271
|
+
op(join5(dir, f));
|
|
15272
|
+
applied += 1;
|
|
15273
15273
|
}
|
|
15274
15274
|
} catch {
|
|
15275
15275
|
}
|
|
15276
|
-
return
|
|
15276
|
+
return applied;
|
|
15277
|
+
}
|
|
15278
|
+
function clearAllSlackPendingMarkersForThread(dir, channel, threadTs, clear = defaultClearMarkerFile) {
|
|
15279
|
+
const prefix = `${sanitizeMarkerSegment(channel)}__${sanitizeMarkerSegment(threadTs)}__`;
|
|
15280
|
+
return applyToMatchingMarkers(dir, prefix, ".json", clear);
|
|
15281
|
+
}
|
|
15282
|
+
function markSeenAllSlackPendingMarkersForThread(dir, channel, threadTs, markSeen) {
|
|
15283
|
+
const prefix = `${sanitizeMarkerSegment(channel)}__${sanitizeMarkerSegment(threadTs)}__`;
|
|
15284
|
+
return applyToMatchingMarkers(dir, prefix, ".json", markSeen);
|
|
15277
15285
|
}
|
|
15278
15286
|
function clearSlackPendingMarkerByMessageTs(dir, channel, messageTs, clear = defaultClearMarkerFile) {
|
|
15279
|
-
if (!dir) return 0;
|
|
15280
15287
|
const channelPrefix = `${sanitizeMarkerSegment(channel)}__`;
|
|
15281
15288
|
const messageSuffix = `__${sanitizeMarkerSegment(messageTs)}.json`;
|
|
15282
|
-
|
|
15283
|
-
|
|
15284
|
-
|
|
15285
|
-
|
|
15286
|
-
|
|
15287
|
-
|
|
15288
|
-
}
|
|
15289
|
-
} catch {
|
|
15290
|
-
}
|
|
15291
|
-
return cleared;
|
|
15289
|
+
return applyToMatchingMarkers(dir, channelPrefix, messageSuffix, clear);
|
|
15290
|
+
}
|
|
15291
|
+
function markSeenSlackPendingMarkerByMessageTs(dir, channel, messageTs, markSeen) {
|
|
15292
|
+
const channelPrefix = `${sanitizeMarkerSegment(channel)}__`;
|
|
15293
|
+
const messageSuffix = `__${sanitizeMarkerSegment(messageTs)}.json`;
|
|
15294
|
+
return applyToMatchingMarkers(dir, channelPrefix, messageSuffix, markSeen);
|
|
15292
15295
|
}
|
|
15293
15296
|
function clearOldestSlackPendingMarkerInChannel(dir, channel, clear = defaultClearMarkerFile) {
|
|
15294
15297
|
if (!dir) return null;
|
|
@@ -15312,6 +15315,59 @@ function clearOldestSlackPendingMarkerInChannel(dir, channel, clear = defaultCle
|
|
|
15312
15315
|
}
|
|
15313
15316
|
}
|
|
15314
15317
|
|
|
15318
|
+
// src/channel-progress.ts
|
|
15319
|
+
function channelLiveProgressEnabled() {
|
|
15320
|
+
return resolveHostBooleanFlag({
|
|
15321
|
+
key: "channel-live-progress",
|
|
15322
|
+
envVar: "AGT_CHANNEL_PROGRESS_ENABLED",
|
|
15323
|
+
defaultValue: false
|
|
15324
|
+
});
|
|
15325
|
+
}
|
|
15326
|
+
function decideProgressAction(input) {
|
|
15327
|
+
const { now, heartbeat, target, tracked, freshnessMs, minPendingMs } = input;
|
|
15328
|
+
const fresh = heartbeat != null && now - heartbeat.updatedAtMs <= freshnessMs;
|
|
15329
|
+
const active = target != null && fresh;
|
|
15330
|
+
if (!active) {
|
|
15331
|
+
if (tracked) {
|
|
15332
|
+
return { type: "delete", channel: tracked.channel, threadTs: tracked.threadTs, ts: tracked.ts };
|
|
15333
|
+
}
|
|
15334
|
+
return { type: "none" };
|
|
15335
|
+
}
|
|
15336
|
+
const t = target;
|
|
15337
|
+
const hb = heartbeat;
|
|
15338
|
+
if (tracked && (tracked.threadTs !== t.threadTs || tracked.channel !== t.channel)) {
|
|
15339
|
+
return { type: "delete", channel: tracked.channel, threadTs: tracked.threadTs, ts: tracked.ts };
|
|
15340
|
+
}
|
|
15341
|
+
if (!tracked) {
|
|
15342
|
+
if (now - t.receivedAtMs < minPendingMs) return { type: "none" };
|
|
15343
|
+
return { type: "post", channel: t.channel, threadTs: t.threadTs, step: hb.step };
|
|
15344
|
+
}
|
|
15345
|
+
if (hb.step !== tracked.lastStep) {
|
|
15346
|
+
return { type: "update", channel: t.channel, threadTs: t.threadTs, ts: tracked.ts, step: hb.step };
|
|
15347
|
+
}
|
|
15348
|
+
return { type: "none" };
|
|
15349
|
+
}
|
|
15350
|
+
function progressHeartbeatFreshMs() {
|
|
15351
|
+
const raw = parseInt(process.env.AGT_CHANNEL_PROGRESS_FRESH_MS ?? "", 10);
|
|
15352
|
+
return Number.isFinite(raw) && raw > 0 ? raw : 45e3;
|
|
15353
|
+
}
|
|
15354
|
+
function progressMinPendingMs() {
|
|
15355
|
+
const raw = parseInt(process.env.AGT_CHANNEL_PROGRESS_MIN_PENDING_MS ?? "", 10);
|
|
15356
|
+
return Number.isFinite(raw) && raw > 0 ? raw : 12e3;
|
|
15357
|
+
}
|
|
15358
|
+
function parseProgressHeartbeat(raw) {
|
|
15359
|
+
if (!raw) return null;
|
|
15360
|
+
try {
|
|
15361
|
+
const obj = JSON.parse(raw);
|
|
15362
|
+
const step = typeof obj.step === "string" ? obj.step.trim() : "";
|
|
15363
|
+
const updatedAtMs = typeof obj.updated_at_ms === "number" ? obj.updated_at_ms : NaN;
|
|
15364
|
+
if (!step || !Number.isFinite(updatedAtMs)) return null;
|
|
15365
|
+
return { step, updatedAtMs };
|
|
15366
|
+
} catch {
|
|
15367
|
+
return null;
|
|
15368
|
+
}
|
|
15369
|
+
}
|
|
15370
|
+
|
|
15315
15371
|
// src/slack-reply-threading.ts
|
|
15316
15372
|
function isSlackDmChannel(channel) {
|
|
15317
15373
|
return typeof channel === "string" && channel.startsWith("D");
|
|
@@ -16953,6 +17009,18 @@ function rewriteSlackMarkerInPlace(path, marker) {
|
|
|
16953
17009
|
}
|
|
16954
17010
|
}
|
|
16955
17011
|
}
|
|
17012
|
+
function markSlackMarkerSeenInPlace(fullPath) {
|
|
17013
|
+
let marker;
|
|
17014
|
+
try {
|
|
17015
|
+
marker = JSON.parse(readFileSync9(fullPath, "utf-8"));
|
|
17016
|
+
} catch {
|
|
17017
|
+
return;
|
|
17018
|
+
}
|
|
17019
|
+
if (marker.seen_at) return;
|
|
17020
|
+
marker.seen_at = (/* @__PURE__ */ new Date()).toISOString();
|
|
17021
|
+
if (marker.undeliverable) delete marker.undeliverable;
|
|
17022
|
+
rewriteSlackMarkerInPlace(fullPath, marker);
|
|
17023
|
+
}
|
|
16956
17024
|
function attachSlackReplayPayload(channel, threadTs, messageTs, payload) {
|
|
16957
17025
|
const path = slackPendingInboundPath(channel, threadTs, messageTs);
|
|
16958
17026
|
if (!path) return;
|
|
@@ -17111,6 +17179,21 @@ function clearSlackMarkerFileWithHeal(fullPath) {
|
|
|
17111
17179
|
} catch {
|
|
17112
17180
|
}
|
|
17113
17181
|
}
|
|
17182
|
+
function markSlackMarkerSeenWithHeal(fullPath) {
|
|
17183
|
+
let marker = null;
|
|
17184
|
+
try {
|
|
17185
|
+
marker = JSON.parse(readFileSync9(fullPath, "utf-8"));
|
|
17186
|
+
} catch {
|
|
17187
|
+
return;
|
|
17188
|
+
}
|
|
17189
|
+
if (decideRecoveryHeal({
|
|
17190
|
+
wasUndeliverable: marker.undeliverable === true,
|
|
17191
|
+
hasTarget: Boolean(marker.channel && marker.message_ts)
|
|
17192
|
+
}) === "heal") {
|
|
17193
|
+
healSlackUndeliverable(marker.channel, marker.message_ts);
|
|
17194
|
+
}
|
|
17195
|
+
markSlackMarkerSeenInPlace(fullPath);
|
|
17196
|
+
}
|
|
17114
17197
|
function clearAllSlackPendingMarkersForThread2(channel, threadTs) {
|
|
17115
17198
|
clearAllSlackPendingMarkersForThread(
|
|
17116
17199
|
SLACK_PENDING_INBOUND_DIR,
|
|
@@ -17134,6 +17217,22 @@ function clearOldestSlackPendingMarkerInChannel2(channel) {
|
|
|
17134
17217
|
clearSlackMarkerFileWithHeal
|
|
17135
17218
|
);
|
|
17136
17219
|
}
|
|
17220
|
+
function markSeenAllSlackPendingMarkersForThread2(channel, threadTs) {
|
|
17221
|
+
markSeenAllSlackPendingMarkersForThread(
|
|
17222
|
+
SLACK_PENDING_INBOUND_DIR,
|
|
17223
|
+
channel,
|
|
17224
|
+
threadTs,
|
|
17225
|
+
markSlackMarkerSeenWithHeal
|
|
17226
|
+
);
|
|
17227
|
+
}
|
|
17228
|
+
function markSeenSlackPendingMarkerByMessageTs2(channel, messageTs) {
|
|
17229
|
+
markSeenSlackPendingMarkerByMessageTs(
|
|
17230
|
+
SLACK_PENDING_INBOUND_DIR,
|
|
17231
|
+
channel,
|
|
17232
|
+
messageTs,
|
|
17233
|
+
markSlackMarkerSeenWithHeal
|
|
17234
|
+
);
|
|
17235
|
+
}
|
|
17137
17236
|
function slackNextRetryName(filename) {
|
|
17138
17237
|
const match = filename.match(/^(.*?)(?:\.retry-(\d+))?\.json$/);
|
|
17139
17238
|
if (!match) return null;
|
|
@@ -17380,6 +17479,160 @@ var slackOrphanSweepTimer = setInterval(() => {
|
|
|
17380
17479
|
checkSlackWatchdogGiveUpNotice();
|
|
17381
17480
|
}, orphanSweepIntervalMs());
|
|
17382
17481
|
slackOrphanSweepTimer.unref?.();
|
|
17482
|
+
var SLACK_PROGRESS_HEARTBEAT_PATH = SLACK_AGENT_DIR ? join7(SLACK_AGENT_DIR, "channel-progress-heartbeat.json") : null;
|
|
17483
|
+
var slackTrackedProgress = null;
|
|
17484
|
+
var slackProgressTickRunning = false;
|
|
17485
|
+
function readSlackProgressHeartbeat() {
|
|
17486
|
+
if (!SLACK_PROGRESS_HEARTBEAT_PATH || !existsSync7(SLACK_PROGRESS_HEARTBEAT_PATH)) return null;
|
|
17487
|
+
try {
|
|
17488
|
+
return parseProgressHeartbeat(readFileSync9(SLACK_PROGRESS_HEARTBEAT_PATH, "utf-8"));
|
|
17489
|
+
} catch {
|
|
17490
|
+
return null;
|
|
17491
|
+
}
|
|
17492
|
+
}
|
|
17493
|
+
function findSlackProgressTarget() {
|
|
17494
|
+
if (!SLACK_PENDING_INBOUND_DIR || !existsSync7(SLACK_PENDING_INBOUND_DIR)) return null;
|
|
17495
|
+
let best = null;
|
|
17496
|
+
let bestMs = Infinity;
|
|
17497
|
+
try {
|
|
17498
|
+
for (const name of readdirSync3(SLACK_PENDING_INBOUND_DIR)) {
|
|
17499
|
+
if (!name.endsWith(".json")) continue;
|
|
17500
|
+
let m;
|
|
17501
|
+
try {
|
|
17502
|
+
m = JSON.parse(readFileSync9(join7(SLACK_PENDING_INBOUND_DIR, name), "utf-8"));
|
|
17503
|
+
} catch {
|
|
17504
|
+
continue;
|
|
17505
|
+
}
|
|
17506
|
+
if (!m.channel || !m.thread_ts) continue;
|
|
17507
|
+
if (m.discretionary === true || m.undeliverable === true) continue;
|
|
17508
|
+
const ms = Date.parse(m.received_at ?? "");
|
|
17509
|
+
if (!Number.isFinite(ms)) continue;
|
|
17510
|
+
if (ms < bestMs) {
|
|
17511
|
+
bestMs = ms;
|
|
17512
|
+
best = { channel: m.channel, threadTs: m.thread_ts, receivedAtMs: ms };
|
|
17513
|
+
}
|
|
17514
|
+
}
|
|
17515
|
+
} catch {
|
|
17516
|
+
return null;
|
|
17517
|
+
}
|
|
17518
|
+
return best;
|
|
17519
|
+
}
|
|
17520
|
+
var SLACK_PROGRESS_PREFIX = "\u23F3";
|
|
17521
|
+
function slackProgressBlocks(step) {
|
|
17522
|
+
const text = `${SLACK_PROGRESS_PREFIX} _Working\u2026 \xB7 ${step}_`;
|
|
17523
|
+
return [{ type: "context", elements: [{ type: "mrkdwn", text }] }];
|
|
17524
|
+
}
|
|
17525
|
+
async function postSlackProgress(channel, threadTs, step) {
|
|
17526
|
+
if (!BOT_TOKEN) return null;
|
|
17527
|
+
try {
|
|
17528
|
+
const res = await fetch("https://slack.com/api/chat.postMessage", {
|
|
17529
|
+
method: "POST",
|
|
17530
|
+
headers: { "Content-Type": "application/json; charset=utf-8", Authorization: `Bearer ${BOT_TOKEN}` },
|
|
17531
|
+
body: JSON.stringify({
|
|
17532
|
+
channel,
|
|
17533
|
+
thread_ts: threadTs,
|
|
17534
|
+
text: `${SLACK_PROGRESS_PREFIX} Working\u2026 \xB7 ${step}`,
|
|
17535
|
+
blocks: slackProgressBlocks(step)
|
|
17536
|
+
}),
|
|
17537
|
+
signal: AbortSignal.timeout(8e3)
|
|
17538
|
+
});
|
|
17539
|
+
const data = await res.json();
|
|
17540
|
+
return data.ok && data.ts ? data.ts : null;
|
|
17541
|
+
} catch {
|
|
17542
|
+
return null;
|
|
17543
|
+
}
|
|
17544
|
+
}
|
|
17545
|
+
async function updateSlackProgress(channel, ts, step) {
|
|
17546
|
+
if (!BOT_TOKEN) return false;
|
|
17547
|
+
try {
|
|
17548
|
+
const res = await fetch("https://slack.com/api/chat.update", {
|
|
17549
|
+
method: "POST",
|
|
17550
|
+
headers: { "Content-Type": "application/json; charset=utf-8", Authorization: `Bearer ${BOT_TOKEN}` },
|
|
17551
|
+
body: JSON.stringify({
|
|
17552
|
+
channel,
|
|
17553
|
+
ts,
|
|
17554
|
+
text: `${SLACK_PROGRESS_PREFIX} Working\u2026 \xB7 ${step}`,
|
|
17555
|
+
blocks: slackProgressBlocks(step)
|
|
17556
|
+
}),
|
|
17557
|
+
signal: AbortSignal.timeout(8e3)
|
|
17558
|
+
});
|
|
17559
|
+
const data = await res.json();
|
|
17560
|
+
return data.ok === true;
|
|
17561
|
+
} catch {
|
|
17562
|
+
return false;
|
|
17563
|
+
}
|
|
17564
|
+
}
|
|
17565
|
+
async function deleteSlackProgress(channel, ts) {
|
|
17566
|
+
if (!BOT_TOKEN) return false;
|
|
17567
|
+
try {
|
|
17568
|
+
const res = await fetch("https://slack.com/api/chat.delete", {
|
|
17569
|
+
method: "POST",
|
|
17570
|
+
headers: { "Content-Type": "application/json; charset=utf-8", Authorization: `Bearer ${BOT_TOKEN}` },
|
|
17571
|
+
body: JSON.stringify({ channel, ts }),
|
|
17572
|
+
signal: AbortSignal.timeout(8e3)
|
|
17573
|
+
});
|
|
17574
|
+
const data = await res.json();
|
|
17575
|
+
return data.ok === true || data.error === "message_not_found";
|
|
17576
|
+
} catch {
|
|
17577
|
+
return false;
|
|
17578
|
+
}
|
|
17579
|
+
}
|
|
17580
|
+
async function slackProgressTick() {
|
|
17581
|
+
if (slackProgressTickRunning) return;
|
|
17582
|
+
slackProgressTickRunning = true;
|
|
17583
|
+
try {
|
|
17584
|
+
if (!channelLiveProgressEnabled()) {
|
|
17585
|
+
if (slackTrackedProgress) {
|
|
17586
|
+
if (await deleteSlackProgress(slackTrackedProgress.channel, slackTrackedProgress.ts)) {
|
|
17587
|
+
slackTrackedProgress = null;
|
|
17588
|
+
}
|
|
17589
|
+
}
|
|
17590
|
+
return;
|
|
17591
|
+
}
|
|
17592
|
+
const action = decideProgressAction({
|
|
17593
|
+
now: Date.now(),
|
|
17594
|
+
heartbeat: readSlackProgressHeartbeat(),
|
|
17595
|
+
target: findSlackProgressTarget(),
|
|
17596
|
+
tracked: slackTrackedProgress,
|
|
17597
|
+
freshnessMs: progressHeartbeatFreshMs(),
|
|
17598
|
+
minPendingMs: progressMinPendingMs()
|
|
17599
|
+
});
|
|
17600
|
+
switch (action.type) {
|
|
17601
|
+
case "post": {
|
|
17602
|
+
const ts = await postSlackProgress(action.channel, action.threadTs, action.step);
|
|
17603
|
+
if (ts) slackTrackedProgress = { channel: action.channel, threadTs: action.threadTs, ts, lastStep: action.step };
|
|
17604
|
+
break;
|
|
17605
|
+
}
|
|
17606
|
+
case "update": {
|
|
17607
|
+
if (await updateSlackProgress(action.channel, action.ts, action.step)) {
|
|
17608
|
+
if (slackTrackedProgress) slackTrackedProgress.lastStep = action.step;
|
|
17609
|
+
}
|
|
17610
|
+
break;
|
|
17611
|
+
}
|
|
17612
|
+
case "delete": {
|
|
17613
|
+
if (await deleteSlackProgress(action.channel, action.ts)) {
|
|
17614
|
+
slackTrackedProgress = null;
|
|
17615
|
+
}
|
|
17616
|
+
break;
|
|
17617
|
+
}
|
|
17618
|
+
case "none":
|
|
17619
|
+
break;
|
|
17620
|
+
}
|
|
17621
|
+
} catch {
|
|
17622
|
+
} finally {
|
|
17623
|
+
slackProgressTickRunning = false;
|
|
17624
|
+
}
|
|
17625
|
+
}
|
|
17626
|
+
function slackProgressPollMs() {
|
|
17627
|
+
const raw = parseInt(process.env.AGT_CHANNEL_PROGRESS_POLL_MS ?? "", 10);
|
|
17628
|
+
return Number.isFinite(raw) && raw >= 2e3 ? raw : 8e3;
|
|
17629
|
+
}
|
|
17630
|
+
if (BOT_TOKEN && SLACK_PENDING_INBOUND_DIR) {
|
|
17631
|
+
const slackProgressTimer = setInterval(() => {
|
|
17632
|
+
void slackProgressTick();
|
|
17633
|
+
}, slackProgressPollMs());
|
|
17634
|
+
slackProgressTimer.unref?.();
|
|
17635
|
+
}
|
|
17383
17636
|
var lastSlackGiveUpHandledAtMs = null;
|
|
17384
17637
|
function listPendingSlackConversations() {
|
|
17385
17638
|
if (!SLACK_PENDING_INBOUND_DIR || !existsSync7(SLACK_PENDING_INBOUND_DIR)) return [];
|
|
@@ -17394,6 +17647,7 @@ function listPendingSlackConversations() {
|
|
|
17394
17647
|
if (typeof marker.channel !== "string" || !marker.channel) continue;
|
|
17395
17648
|
if (typeof marker.thread_ts !== "string" || !marker.thread_ts) continue;
|
|
17396
17649
|
if (marker.discretionary === true) continue;
|
|
17650
|
+
if (typeof marker.seen_at === "string" && marker.seen_at) continue;
|
|
17397
17651
|
const isThreadReply = typeof marker.message_ts === "string" && marker.message_ts !== marker.thread_ts;
|
|
17398
17652
|
const key2 = isThreadReply ? `${marker.channel}:${marker.thread_ts}` : marker.channel;
|
|
17399
17653
|
if (!byKey.has(key2)) {
|
|
@@ -17647,28 +17901,12 @@ function clearPendingMessage(channel, threadTs) {
|
|
|
17647
17901
|
}
|
|
17648
17902
|
function noteThreadActivity(channel, threadTs) {
|
|
17649
17903
|
if (!channel || !threadTs) return;
|
|
17650
|
-
|
|
17904
|
+
markSeenAllSlackPendingMarkersForThread2(channel, threadTs);
|
|
17651
17905
|
}
|
|
17652
17906
|
function noteThreadActivityByMessageTs(channel, messageTs) {
|
|
17653
17907
|
if (!channel || !messageTs) return;
|
|
17654
|
-
|
|
17655
|
-
|
|
17656
|
-
if (!existsSync7(SLACK_PENDING_INBOUND_DIR)) return;
|
|
17657
|
-
let filenames;
|
|
17658
|
-
try {
|
|
17659
|
-
filenames = readdirSync3(SLACK_PENDING_INBOUND_DIR);
|
|
17660
|
-
} catch {
|
|
17661
|
-
return;
|
|
17662
|
-
}
|
|
17663
|
-
const safeChannel = channel.replace(/[^A-Za-z0-9_-]/g, "_");
|
|
17664
|
-
const safeMessageTs = messageTs.replace(/[^A-Za-z0-9_-]/g, "_");
|
|
17665
|
-
const channelPrefix = `${safeChannel}__`;
|
|
17666
|
-
const messageSuffix = `__${safeMessageTs}.json`;
|
|
17667
|
-
for (const filename of filenames) {
|
|
17668
|
-
if (!filename.startsWith(channelPrefix)) continue;
|
|
17669
|
-
if (!filename.endsWith(messageSuffix)) continue;
|
|
17670
|
-
clearSlackMarkerFileWithHeal(join7(SLACK_PENDING_INBOUND_DIR, filename));
|
|
17671
|
-
}
|
|
17908
|
+
markSeenAllSlackPendingMarkersForThread2(channel, messageTs);
|
|
17909
|
+
markSeenSlackPendingMarkerByMessageTs2(channel, messageTs);
|
|
17672
17910
|
}
|
|
17673
17911
|
var RESTART_FLAGS_DIR = join7(homedir3(), ".augmented", "restart-flags");
|
|
17674
17912
|
function buildAugmentedSlackMetadata() {
|
|
@@ -18490,7 +18728,7 @@ var mcp = new Server(
|
|
|
18490
18728
|
instructions: [
|
|
18491
18729
|
// Highest-priority lines first — Claude Code truncates this string at
|
|
18492
18730
|
// 2048 chars, so anything appended late silently disappears.
|
|
18493
|
-
"CRITICAL: every response to a Slack <channel> tag MUST go through slack.reply
|
|
18731
|
+
"CRITICAL: every response to a Slack <channel> tag MUST go through slack.reply \u2014 typed text never reaches the user. Slow work: interim ack (slack.reply interim:true), then your FINAL answer as a separate slack.reply (interim omitted). An ack is not the answer.",
|
|
18494
18732
|
`Inbound: <channel ... thread_ts="..." message_ts="..." [thread_context="..."]>. Pass channel + message_ts to slack.reply (and thread_ts on threads). thread_context = thread pre-loaded; ground replies ONLY in it, never another channel's.`,
|
|
18495
18733
|
"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 slack.download_attachment. Use that tool only for entries with `file_id` but NO `path` (PDF, docx, csv): pass file_id + channel verbatim, then Read the returned path. Single-image messages also get a top-level `image_path`. Don't surface internal file-handling errors that don't affect the answer.",
|
|
18496
18734
|
"Address users by user_name, never by raw user ID. In multi-participant threads the CURRENT speaker is the one on the latest <channel> tag.",
|
|
@@ -18528,6 +18766,12 @@ mcp.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
|
18528
18766
|
message_ts: {
|
|
18529
18767
|
type: "string",
|
|
18530
18768
|
description: "The message_ts of the specific inbound this reply addresses (from the message_ts attribute on the <channel> tag). Used by the pending-inbound cleanup gate so the marker is reliably cleared even for top-level DMs that have no thread_ts."
|
|
18769
|
+
},
|
|
18770
|
+
// ENG-6567: explicit interim/final distinction so the system knows
|
|
18771
|
+
// whether the agent still owes a substantive answer.
|
|
18772
|
+
interim: {
|
|
18773
|
+
type: "boolean",
|
|
18774
|
+
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 conversation as awaiting your final reply. Your eventual substantive answer MUST be a separate slack.reply with interim omitted/false \u2014 that is what marks the request complete. Omit (default false) for any reply that fully answers the user.'
|
|
18531
18775
|
}
|
|
18532
18776
|
},
|
|
18533
18777
|
required: ["channel", "text"]
|
|
@@ -18754,7 +18998,7 @@ mcp.setRequestHandler(CallToolRequestSchema, async (req) => {
|
|
|
18754
18998
|
return buildImpersonationRefusal(name);
|
|
18755
18999
|
}
|
|
18756
19000
|
if (name === "slack.reply") {
|
|
18757
|
-
const { channel, text, thread_ts, message_ts } = args;
|
|
19001
|
+
const { channel, text, thread_ts, message_ts, interim } = args;
|
|
18758
19002
|
const effectiveThreadTs = resolveReplyThreadTs({
|
|
18759
19003
|
channel,
|
|
18760
19004
|
threadTs: thread_ts,
|
|
@@ -18818,16 +19062,23 @@ mcp.setRequestHandler(CallToolRequestSchema, async (req) => {
|
|
|
18818
19062
|
isError: true
|
|
18819
19063
|
};
|
|
18820
19064
|
}
|
|
18821
|
-
|
|
19065
|
+
const settlePendingMarker = () => {
|
|
19066
|
+
if (!channel) return;
|
|
18822
19067
|
if (message_ts) {
|
|
18823
|
-
|
|
18824
|
-
|
|
19068
|
+
if (interim) {
|
|
19069
|
+
markSeenSlackPendingMarkerByMessageTs2(channel, message_ts);
|
|
19070
|
+
if (thread_ts) markSeenAllSlackPendingMarkersForThread2(channel, thread_ts);
|
|
19071
|
+
} else {
|
|
19072
|
+
clearSlackPendingMarkerByMessageTs2(channel, message_ts);
|
|
19073
|
+
if (thread_ts) clearPendingMessage(channel, thread_ts);
|
|
19074
|
+
}
|
|
18825
19075
|
} else if (thread_ts) {
|
|
18826
|
-
|
|
18827
|
-
|
|
19076
|
+
if (interim) markSeenAllSlackPendingMarkersForThread2(channel, thread_ts);
|
|
19077
|
+
else clearPendingMessage(channel, thread_ts);
|
|
19078
|
+
} else if (!interim) {
|
|
18828
19079
|
clearOldestSlackPendingMarkerInChannel2(channel);
|
|
18829
19080
|
}
|
|
18830
|
-
}
|
|
19081
|
+
};
|
|
18831
19082
|
try {
|
|
18832
19083
|
const res = await fetch("https://slack.com/api/chat.postMessage", {
|
|
18833
19084
|
method: "POST",
|
|
@@ -18851,6 +19102,7 @@ mcp.setRequestHandler(CallToolRequestSchema, async (req) => {
|
|
|
18851
19102
|
isError: true
|
|
18852
19103
|
};
|
|
18853
19104
|
}
|
|
19105
|
+
settlePendingMarker();
|
|
18854
19106
|
recordReply(channel, throttleKey, throttleNow, throttleCfg);
|
|
18855
19107
|
recordActivity("reply");
|
|
18856
19108
|
if (THREAD_AUTO_FOLLOW !== "off") {
|
|
@@ -19290,7 +19542,6 @@ async function handleSendStructured(args) {
|
|
|
19290
19542
|
if (typeof text !== "string" || !text) {
|
|
19291
19543
|
return errResult("text is required (used as fallback for push notifications and unfurls)");
|
|
19292
19544
|
}
|
|
19293
|
-
noteThreadActivity(channel, thread_ts);
|
|
19294
19545
|
const validation = validateSlackBlocks2(blocks);
|
|
19295
19546
|
if (!validation.ok) {
|
|
19296
19547
|
return errResult(`Invalid blocks: ${validation.errors.map((e) => `${e.path}: ${e.message}`).join("; ")}`);
|
|
@@ -19304,6 +19555,7 @@ async function handleSendStructured(args) {
|
|
|
19304
19555
|
if (!result.ok || !result.ts) {
|
|
19305
19556
|
return errResult(`Slack chat.postMessage failed: ${result.error ?? "unknown"}`);
|
|
19306
19557
|
}
|
|
19558
|
+
if (thread_ts) clearPendingMessage(channel, thread_ts);
|
|
19307
19559
|
if (interactiveHostAvailable()) {
|
|
19308
19560
|
const cfg = {
|
|
19309
19561
|
apiHost: AGT_HOST,
|
|
@@ -16430,6 +16430,7 @@ function oldestPendingMarkerAgeMs(dir, now = Date.now()) {
|
|
|
16430
16430
|
try {
|
|
16431
16431
|
const raw = JSON.parse(readFileSync7(join6(dir, name), "utf-8"));
|
|
16432
16432
|
if (raw.discretionary === true) continue;
|
|
16433
|
+
if (typeof raw.seen_at === "string" && raw.seen_at) continue;
|
|
16433
16434
|
receivedAt = raw.received_at;
|
|
16434
16435
|
} catch {
|
|
16435
16436
|
continue;
|
|
@@ -25,8 +25,8 @@ import {
|
|
|
25
25
|
takeZombieDetection,
|
|
26
26
|
writeDirectChatSessionState,
|
|
27
27
|
writePersistentClaudeWrapper
|
|
28
|
-
} from "./chunk-
|
|
29
|
-
import "./chunk-
|
|
28
|
+
} from "./chunk-XDZFMTY5.js";
|
|
29
|
+
import "./chunk-3KLQA3SC.js";
|
|
30
30
|
import "./chunk-XWVM4KPK.js";
|
|
31
31
|
export {
|
|
32
32
|
SEND_KEYS_ENTER_DELAY_MS,
|
|
@@ -56,4 +56,4 @@ export {
|
|
|
56
56
|
writeDirectChatSessionState,
|
|
57
57
|
writePersistentClaudeWrapper
|
|
58
58
|
};
|
|
59
|
-
//# sourceMappingURL=persistent-session-
|
|
59
|
+
//# sourceMappingURL=persistent-session-U6P5I6TT.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
paneLogPath
|
|
3
|
-
} from "./chunk-
|
|
4
|
-
import "./chunk-
|
|
3
|
+
} from "./chunk-XDZFMTY5.js";
|
|
4
|
+
import "./chunk-3KLQA3SC.js";
|
|
5
5
|
import "./chunk-XWVM4KPK.js";
|
|
6
6
|
|
|
7
7
|
// src/lib/responsiveness-probe.ts
|
|
@@ -250,4 +250,4 @@ export {
|
|
|
250
250
|
parkPendingInbound,
|
|
251
251
|
readAndResetChannelDeflections
|
|
252
252
|
};
|
|
253
|
-
//# sourceMappingURL=responsiveness-probe-
|
|
253
|
+
//# sourceMappingURL=responsiveness-probe-VKIJY4IC.js.map
|