@integrity-labs/agt-cli 0.28.57 → 0.28.59
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-SJRG5VUF.js → chunk-OEZEWEEG.js} +8 -1
- package/dist/chunk-OEZEWEEG.js.map +1 -0
- package/dist/{chunk-MKKTPM6J.js → chunk-UA3LEZL4.js} +2 -2
- package/dist/{chunk-F45T5XPH.js → chunk-ZNOAT5RQ.js} +3 -3
- package/dist/{claude-pair-runtime-RAAIXOKO.js → claude-pair-runtime-VSXYDPST.js} +2 -2
- package/dist/lib/manager-worker.js +61 -16
- package/dist/lib/manager-worker.js.map +1 -1
- package/dist/mcp/slack-channel.js +280 -46
- package/dist/mcp/telegram-channel.js +262 -45
- package/dist/{persistent-session-INTCKEG6.js → persistent-session-42V6NGMR.js} +3 -3
- package/dist/{responsiveness-probe-XAYQAVLV.js → responsiveness-probe-YSSYWWTG.js} +3 -3
- package/package.json +1 -1
- package/dist/chunk-SJRG5VUF.js.map +0 -1
- /package/dist/{chunk-MKKTPM6J.js.map → chunk-UA3LEZL4.js.map} +0 -0
- /package/dist/{chunk-F45T5XPH.js.map → chunk-ZNOAT5RQ.js.map} +0 -0
- /package/dist/{claude-pair-runtime-RAAIXOKO.js.map → claude-pair-runtime-VSXYDPST.js.map} +0 -0
- /package/dist/{persistent-session-INTCKEG6.js.map → persistent-session-42V6NGMR.js.map} +0 -0
- /package/dist/{responsiveness-probe-XAYQAVLV.js.map → responsiveness-probe-YSSYWWTG.js.map} +0 -0
|
@@ -14637,8 +14637,11 @@ function orphanSweepIntervalMs() {
|
|
|
14637
14637
|
}
|
|
14638
14638
|
var MAX_MARKER_REPLAYS = 3;
|
|
14639
14639
|
function channelReplayEnabled() {
|
|
14640
|
-
|
|
14641
|
-
|
|
14640
|
+
return resolveHostBooleanFlag({
|
|
14641
|
+
key: "channel-replay",
|
|
14642
|
+
envVar: "AGT_CHANNEL_REPLAY_ENABLED",
|
|
14643
|
+
defaultValue: false
|
|
14644
|
+
});
|
|
14642
14645
|
}
|
|
14643
14646
|
function shouldReplayMarker(i) {
|
|
14644
14647
|
if (!i.enabled) return false;
|
|
@@ -15448,15 +15451,15 @@ import {
|
|
|
15448
15451
|
createWriteStream,
|
|
15449
15452
|
existsSync as existsSync7,
|
|
15450
15453
|
ftruncateSync,
|
|
15451
|
-
mkdirSync as
|
|
15454
|
+
mkdirSync as mkdirSync6,
|
|
15452
15455
|
openSync,
|
|
15453
|
-
readFileSync as
|
|
15456
|
+
readFileSync as readFileSync9,
|
|
15454
15457
|
readdirSync as readdirSync3,
|
|
15455
15458
|
renameSync as renameSync3,
|
|
15456
15459
|
statSync as statSync2,
|
|
15457
|
-
unlinkSync as
|
|
15460
|
+
unlinkSync as unlinkSync5,
|
|
15458
15461
|
watch,
|
|
15459
|
-
writeFileSync as
|
|
15462
|
+
writeFileSync as writeFileSync7,
|
|
15460
15463
|
writeSync
|
|
15461
15464
|
} from "fs";
|
|
15462
15465
|
import { basename, join as join7, resolve as resolve2 } from "path";
|
|
@@ -15575,6 +15578,156 @@ function isThreadEntry(value) {
|
|
|
15575
15578
|
return (v.involvement === "started" || v.involvement === "mentioned") && typeof v.last_seen_at === "string";
|
|
15576
15579
|
}
|
|
15577
15580
|
|
|
15581
|
+
// src/dm-restart-notice.ts
|
|
15582
|
+
import { mkdirSync as mkdirSync3, readFileSync as readFileSync6, unlinkSync as unlinkSync3, writeFileSync as writeFileSync4 } from "fs";
|
|
15583
|
+
import { dirname as dirname3 } from "path";
|
|
15584
|
+
var RECENT_DM_VERSION = 1;
|
|
15585
|
+
var DEFAULT_RECENT_DM_TTL_MS = 30 * 60 * 1e3;
|
|
15586
|
+
var DEFAULT_DM_NOTICE_WINDOW_MS = 5 * 60 * 1e3;
|
|
15587
|
+
var DEFAULT_MIN_INTERVAL_MS2 = 1e3;
|
|
15588
|
+
function recordDmActivity(map, dmKey, now = /* @__PURE__ */ new Date()) {
|
|
15589
|
+
if (!dmKey) return;
|
|
15590
|
+
map.set(dmKey, { last_activity_at: now.toISOString() });
|
|
15591
|
+
}
|
|
15592
|
+
function recentlyActiveDmKeys(map, now = /* @__PURE__ */ new Date(), windowMs = DEFAULT_DM_NOTICE_WINDOW_MS) {
|
|
15593
|
+
const cutoff = now.getTime() - windowMs;
|
|
15594
|
+
return [...map.entries()].map(([key2, e]) => ({ key: key2, ts: Date.parse(e.last_activity_at) })).filter(({ ts }) => Number.isFinite(ts) && ts >= cutoff).sort((a, b) => b.ts - a.ts).map(({ key: key2 }) => key2);
|
|
15595
|
+
}
|
|
15596
|
+
function serializeRecentDms(map) {
|
|
15597
|
+
const out = { version: RECENT_DM_VERSION, dms: {} };
|
|
15598
|
+
for (const [key2, e] of map) out.dms[key2] = e;
|
|
15599
|
+
return JSON.stringify(out, null, 2);
|
|
15600
|
+
}
|
|
15601
|
+
function loadRecentDms(filePath, opts = {}) {
|
|
15602
|
+
const now = opts.now ?? /* @__PURE__ */ new Date();
|
|
15603
|
+
const ttlMs = opts.ttlMs ?? DEFAULT_RECENT_DM_TTL_MS;
|
|
15604
|
+
let raw;
|
|
15605
|
+
try {
|
|
15606
|
+
raw = readFileSync6(filePath, "utf-8");
|
|
15607
|
+
} catch (err) {
|
|
15608
|
+
const code = err.code;
|
|
15609
|
+
if (code !== "ENOENT") {
|
|
15610
|
+
opts.onError?.(`dm-restart-notice: failed to read recent-DM file: ${err.message}`);
|
|
15611
|
+
}
|
|
15612
|
+
return /* @__PURE__ */ new Map();
|
|
15613
|
+
}
|
|
15614
|
+
let parsed;
|
|
15615
|
+
try {
|
|
15616
|
+
parsed = JSON.parse(raw);
|
|
15617
|
+
} catch (err) {
|
|
15618
|
+
opts.onError?.(`dm-restart-notice: malformed recent-DM JSON (${err.message}) \u2014 ignoring`);
|
|
15619
|
+
return /* @__PURE__ */ new Map();
|
|
15620
|
+
}
|
|
15621
|
+
if (typeof parsed !== "object" || parsed === null || // CodeRabbit: reject unknown versions so a future/legacy on-disk format can't
|
|
15622
|
+
// be read with this version's (possibly incompatible) semantics.
|
|
15623
|
+
parsed.version !== RECENT_DM_VERSION || typeof parsed.dms !== "object" || parsed.dms === null) {
|
|
15624
|
+
opts.onError?.("dm-restart-notice: unexpected recent-DM shape/version \u2014 ignoring");
|
|
15625
|
+
return /* @__PURE__ */ new Map();
|
|
15626
|
+
}
|
|
15627
|
+
const map = /* @__PURE__ */ new Map();
|
|
15628
|
+
const cutoff = now.getTime() - ttlMs;
|
|
15629
|
+
for (const [key2, val] of Object.entries(parsed.dms)) {
|
|
15630
|
+
const at = val?.last_activity_at;
|
|
15631
|
+
if (typeof at !== "string") continue;
|
|
15632
|
+
const ts = Date.parse(at);
|
|
15633
|
+
if (!Number.isFinite(ts) || ts < cutoff) continue;
|
|
15634
|
+
map.set(key2, { last_activity_at: at });
|
|
15635
|
+
}
|
|
15636
|
+
return map;
|
|
15637
|
+
}
|
|
15638
|
+
function createRecentDmPersister(opts) {
|
|
15639
|
+
const interval = opts.minIntervalMs ?? DEFAULT_MIN_INTERVAL_MS2;
|
|
15640
|
+
let lastWriteAt = 0;
|
|
15641
|
+
let pendingTimer = null;
|
|
15642
|
+
let pendingSnapshot = null;
|
|
15643
|
+
const writeNow = (snap) => {
|
|
15644
|
+
try {
|
|
15645
|
+
mkdirSync3(dirname3(opts.filePath), { recursive: true });
|
|
15646
|
+
writeFileSync4(opts.filePath, serializeRecentDms(snap), "utf-8");
|
|
15647
|
+
lastWriteAt = Date.now();
|
|
15648
|
+
} catch (err) {
|
|
15649
|
+
opts.onError?.(`dm-restart-notice: failed to persist recent-DMs: ${err.message}`);
|
|
15650
|
+
}
|
|
15651
|
+
};
|
|
15652
|
+
return {
|
|
15653
|
+
schedule(map) {
|
|
15654
|
+
pendingSnapshot = new Map(map);
|
|
15655
|
+
const sinceLast = Date.now() - lastWriteAt;
|
|
15656
|
+
if (sinceLast >= interval) {
|
|
15657
|
+
const snap = pendingSnapshot;
|
|
15658
|
+
pendingSnapshot = null;
|
|
15659
|
+
writeNow(snap);
|
|
15660
|
+
return;
|
|
15661
|
+
}
|
|
15662
|
+
if (pendingTimer) return;
|
|
15663
|
+
pendingTimer = setTimeout(() => {
|
|
15664
|
+
pendingTimer = null;
|
|
15665
|
+
const snap = pendingSnapshot;
|
|
15666
|
+
pendingSnapshot = null;
|
|
15667
|
+
if (snap) writeNow(snap);
|
|
15668
|
+
}, interval - sinceLast);
|
|
15669
|
+
pendingTimer.unref?.();
|
|
15670
|
+
},
|
|
15671
|
+
flush(map) {
|
|
15672
|
+
if (pendingTimer) {
|
|
15673
|
+
clearTimeout(pendingTimer);
|
|
15674
|
+
pendingTimer = null;
|
|
15675
|
+
pendingSnapshot = null;
|
|
15676
|
+
}
|
|
15677
|
+
writeNow(new Map(map));
|
|
15678
|
+
},
|
|
15679
|
+
dispose() {
|
|
15680
|
+
if (pendingTimer) clearTimeout(pendingTimer);
|
|
15681
|
+
pendingTimer = null;
|
|
15682
|
+
pendingSnapshot = null;
|
|
15683
|
+
}
|
|
15684
|
+
};
|
|
15685
|
+
}
|
|
15686
|
+
var CHANNEL_ADD_RESTART_VERSION = 1;
|
|
15687
|
+
var CHANNEL_ADD_RESTART_MAX_AGE_MS = 15 * 60 * 1e3;
|
|
15688
|
+
function readChannelAddRestartMarker(filePath) {
|
|
15689
|
+
let raw;
|
|
15690
|
+
try {
|
|
15691
|
+
raw = readFileSync6(filePath, "utf-8");
|
|
15692
|
+
} catch {
|
|
15693
|
+
return null;
|
|
15694
|
+
}
|
|
15695
|
+
try {
|
|
15696
|
+
const parsed = JSON.parse(raw);
|
|
15697
|
+
if (typeof parsed !== "object" || parsed === null || parsed.version !== CHANNEL_ADD_RESTART_VERSION || typeof parsed.at !== "string") {
|
|
15698
|
+
return null;
|
|
15699
|
+
}
|
|
15700
|
+
const rawAdded = parsed.added;
|
|
15701
|
+
const added = Array.isArray(rawAdded) ? rawAdded.filter((x) => typeof x === "string") : [];
|
|
15702
|
+
return { version: CHANNEL_ADD_RESTART_VERSION, at: parsed.at, added };
|
|
15703
|
+
} catch {
|
|
15704
|
+
return null;
|
|
15705
|
+
}
|
|
15706
|
+
}
|
|
15707
|
+
function shouldPostChannelAddNotice(marker, bootMs, maxAgeMs = CHANNEL_ADD_RESTART_MAX_AGE_MS) {
|
|
15708
|
+
if (!marker) return false;
|
|
15709
|
+
const at = Date.parse(marker.at);
|
|
15710
|
+
if (!Number.isFinite(at)) return false;
|
|
15711
|
+
const age = bootMs - at;
|
|
15712
|
+
return age <= maxAgeMs && age >= -6e4;
|
|
15713
|
+
}
|
|
15714
|
+
function clearChannelAddRestartMarker(filePath) {
|
|
15715
|
+
try {
|
|
15716
|
+
unlinkSync3(filePath);
|
|
15717
|
+
} catch {
|
|
15718
|
+
}
|
|
15719
|
+
}
|
|
15720
|
+
function buildChannelAddNoticeText(added) {
|
|
15721
|
+
const list = added.filter(Boolean);
|
|
15722
|
+
if (list.length === 1) {
|
|
15723
|
+
return `Quick heads-up \u2014 I briefly restarted to bring a new channel (${list[0]}) online. I'm back now; please re-send anything I might have missed.`;
|
|
15724
|
+
}
|
|
15725
|
+
if (list.length > 1) {
|
|
15726
|
+
return `Quick heads-up \u2014 I briefly restarted to bring new channels (${list.join(", ")}) online. I'm back now; please re-send anything I might have missed.`;
|
|
15727
|
+
}
|
|
15728
|
+
return `Quick heads-up \u2014 I briefly restarted to update my configuration. I'm back now; please re-send anything I might have missed.`;
|
|
15729
|
+
}
|
|
15730
|
+
|
|
15578
15731
|
// src/safe-async.ts
|
|
15579
15732
|
async function runOrRetry(fn, opts) {
|
|
15580
15733
|
try {
|
|
@@ -15593,8 +15746,8 @@ async function runOrRetry(fn, opts) {
|
|
|
15593
15746
|
}
|
|
15594
15747
|
|
|
15595
15748
|
// src/slack-bot-photo.ts
|
|
15596
|
-
import { existsSync as existsSync5, mkdirSync as
|
|
15597
|
-
import { dirname as
|
|
15749
|
+
import { existsSync as existsSync5, mkdirSync as mkdirSync4, readFileSync as readFileSync7, writeFileSync as writeFileSync5 } from "fs";
|
|
15750
|
+
import { dirname as dirname4 } from "path";
|
|
15598
15751
|
async function applyBotPhoto(opts) {
|
|
15599
15752
|
const fetchImpl = opts.fetchImpl ?? fetch;
|
|
15600
15753
|
const log = opts.log ?? ((m) => {
|
|
@@ -15603,7 +15756,7 @@ async function applyBotPhoto(opts) {
|
|
|
15603
15756
|
const { token, avatarUrl, markerPath } = opts;
|
|
15604
15757
|
if (markerPath && existsSync5(markerPath)) {
|
|
15605
15758
|
try {
|
|
15606
|
-
if (
|
|
15759
|
+
if (readFileSync7(markerPath, "utf-8").trim() === avatarUrl) {
|
|
15607
15760
|
return { status: "skipped-unchanged" };
|
|
15608
15761
|
}
|
|
15609
15762
|
} catch {
|
|
@@ -15644,8 +15797,8 @@ async function applyBotPhoto(opts) {
|
|
|
15644
15797
|
}
|
|
15645
15798
|
if (markerPath) {
|
|
15646
15799
|
try {
|
|
15647
|
-
|
|
15648
|
-
|
|
15800
|
+
mkdirSync4(dirname4(markerPath), { recursive: true, mode: 448 });
|
|
15801
|
+
writeFileSync5(markerPath, avatarUrl, { mode: 384 });
|
|
15649
15802
|
} catch {
|
|
15650
15803
|
}
|
|
15651
15804
|
}
|
|
@@ -16428,11 +16581,11 @@ function createSlackBotUserIdClient(args) {
|
|
|
16428
16581
|
// src/mcp-spawn-lock.ts
|
|
16429
16582
|
import {
|
|
16430
16583
|
existsSync as existsSync6,
|
|
16431
|
-
mkdirSync as
|
|
16432
|
-
readFileSync as
|
|
16584
|
+
mkdirSync as mkdirSync5,
|
|
16585
|
+
readFileSync as readFileSync8,
|
|
16433
16586
|
renameSync as renameSync2,
|
|
16434
|
-
unlinkSync as
|
|
16435
|
-
writeFileSync as
|
|
16587
|
+
unlinkSync as unlinkSync4,
|
|
16588
|
+
writeFileSync as writeFileSync6
|
|
16436
16589
|
} from "fs";
|
|
16437
16590
|
import { join as join6 } from "path";
|
|
16438
16591
|
function defaultIsPidAlive(pid) {
|
|
@@ -16462,10 +16615,10 @@ function acquireMcpSpawnLock(args) {
|
|
|
16462
16615
|
return { kind: "blocked", path, holder: existing };
|
|
16463
16616
|
}
|
|
16464
16617
|
}
|
|
16465
|
-
|
|
16618
|
+
mkdirSync5(agentDir, { recursive: true, mode: 448 });
|
|
16466
16619
|
const tmpPath = `${path}.${selfPid}.tmp`;
|
|
16467
16620
|
const payload = { pid: selfPid, started_at: now() };
|
|
16468
|
-
|
|
16621
|
+
writeFileSync6(tmpPath, JSON.stringify(payload), { mode: 384 });
|
|
16469
16622
|
renameSync2(tmpPath, path);
|
|
16470
16623
|
return { kind: "acquired", path };
|
|
16471
16624
|
}
|
|
@@ -16476,14 +16629,14 @@ function releaseMcpSpawnLock(lockPath, opts = {}) {
|
|
|
16476
16629
|
if (!existing) return;
|
|
16477
16630
|
if (existing.pid !== selfPid) return;
|
|
16478
16631
|
try {
|
|
16479
|
-
|
|
16632
|
+
unlinkSync4(lockPath);
|
|
16480
16633
|
} catch {
|
|
16481
16634
|
}
|
|
16482
16635
|
}
|
|
16483
16636
|
function readLockHolder(path) {
|
|
16484
16637
|
if (!existsSync6(path)) return null;
|
|
16485
16638
|
try {
|
|
16486
|
-
const raw =
|
|
16639
|
+
const raw = readFileSync8(path, "utf8");
|
|
16487
16640
|
const parsed = JSON.parse(raw);
|
|
16488
16641
|
const pid = typeof parsed.pid === "number" ? parsed.pid : Number(parsed.pid);
|
|
16489
16642
|
if (!Number.isFinite(pid) || pid <= 0) return null;
|
|
@@ -16672,7 +16825,7 @@ function readLiveAllowedUsers() {
|
|
|
16672
16825
|
return liveAllowedUsersCache.value;
|
|
16673
16826
|
}
|
|
16674
16827
|
const value = extractAllowedUsersFromMcpJson(
|
|
16675
|
-
|
|
16828
|
+
readFileSync9(SLACK_MCP_CONFIG_PATH, "utf-8")
|
|
16676
16829
|
);
|
|
16677
16830
|
if (value === null) return null;
|
|
16678
16831
|
liveAllowedUsersCache = { mtimeMs, value };
|
|
@@ -16687,6 +16840,8 @@ function getEffectiveAllowedUsers() {
|
|
|
16687
16840
|
var SLACK_PENDING_INBOUND_DIR = SLACK_AGENT_DIR ? join7(SLACK_AGENT_DIR, "slack-pending-inbound") : null;
|
|
16688
16841
|
var SLACK_RECOVERY_OUTBOX_DIR = SLACK_AGENT_DIR ? join7(SLACK_AGENT_DIR, "slack-recovery-outbox") : null;
|
|
16689
16842
|
var SLACK_RESTART_CONFIRM_FILE = SLACK_AGENT_DIR ? join7(SLACK_AGENT_DIR, "slack-restart-confirm.json") : null;
|
|
16843
|
+
var SLACK_RECENT_DMS_FILE = SLACK_AGENT_DIR ? join7(SLACK_AGENT_DIR, "slack-recent-dms.json") : null;
|
|
16844
|
+
var SLACK_CHANNEL_ADD_RESTART_FILE = SLACK_AGENT_DIR ? join7(SLACK_AGENT_DIR, "slack-channel-add-restart.json") : null;
|
|
16690
16845
|
var SLACK_MAX_RECOVERY_ATTEMPTS = 3;
|
|
16691
16846
|
var SLACK_AVATAR_MARKER_PATH = SLACK_AGENT_DIR ? join7(SLACK_AGENT_DIR, "slack-avatar-applied") : null;
|
|
16692
16847
|
function redactSlackId(id) {
|
|
@@ -16717,8 +16872,8 @@ function writeSlackPendingInboundMarker(channel, threadTs, messageTs, undelivera
|
|
|
16717
16872
|
...payload ? { payload } : {}
|
|
16718
16873
|
};
|
|
16719
16874
|
try {
|
|
16720
|
-
|
|
16721
|
-
|
|
16875
|
+
mkdirSync6(SLACK_PENDING_INBOUND_DIR, { recursive: true, mode: 448 });
|
|
16876
|
+
writeFileSync7(path, JSON.stringify(marker), { mode: 384 });
|
|
16722
16877
|
} catch (err) {
|
|
16723
16878
|
process.stderr.write(
|
|
16724
16879
|
`slack-channel(${AGENT_CODE_NAME}): pending-inbound marker write failed: ${err.message}
|
|
@@ -16748,7 +16903,7 @@ function attachSlackReplayPayload(channel, threadTs, messageTs, payload) {
|
|
|
16748
16903
|
if (!path) return;
|
|
16749
16904
|
let marker;
|
|
16750
16905
|
try {
|
|
16751
|
-
marker = JSON.parse(
|
|
16906
|
+
marker = JSON.parse(readFileSync9(path, "utf-8"));
|
|
16752
16907
|
} catch {
|
|
16753
16908
|
return;
|
|
16754
16909
|
}
|
|
@@ -16759,7 +16914,7 @@ function readSlackPendingInboundMarker(channel, threadTs, messageTs) {
|
|
|
16759
16914
|
const path = slackPendingInboundPath(channel, threadTs, messageTs);
|
|
16760
16915
|
if (!path || !existsSync7(path)) return null;
|
|
16761
16916
|
try {
|
|
16762
|
-
return JSON.parse(
|
|
16917
|
+
return JSON.parse(readFileSync9(path, "utf-8"));
|
|
16763
16918
|
} catch {
|
|
16764
16919
|
return null;
|
|
16765
16920
|
}
|
|
@@ -16887,7 +17042,7 @@ function __resetSlackBusyAckNoticeThrottle() {
|
|
|
16887
17042
|
function clearSlackMarkerFileWithHeal(fullPath) {
|
|
16888
17043
|
let marker = null;
|
|
16889
17044
|
try {
|
|
16890
|
-
marker = JSON.parse(
|
|
17045
|
+
marker = JSON.parse(readFileSync9(fullPath, "utf-8"));
|
|
16891
17046
|
} catch {
|
|
16892
17047
|
}
|
|
16893
17048
|
if (marker && decideRecoveryHeal({
|
|
@@ -16897,7 +17052,7 @@ function clearSlackMarkerFileWithHeal(fullPath) {
|
|
|
16897
17052
|
healSlackUndeliverable(marker.channel, marker.message_ts);
|
|
16898
17053
|
}
|
|
16899
17054
|
try {
|
|
16900
|
-
if (existsSync7(fullPath))
|
|
17055
|
+
if (existsSync7(fullPath)) unlinkSync5(fullPath);
|
|
16901
17056
|
} catch {
|
|
16902
17057
|
}
|
|
16903
17058
|
}
|
|
@@ -16941,7 +17096,7 @@ async function processSlackRecoveryOutboxFile(filename) {
|
|
|
16941
17096
|
const fullPath = join7(SLACK_RECOVERY_OUTBOX_DIR, filename);
|
|
16942
17097
|
let payload;
|
|
16943
17098
|
try {
|
|
16944
|
-
payload = JSON.parse(
|
|
17099
|
+
payload = JSON.parse(readFileSync9(fullPath, "utf-8"));
|
|
16945
17100
|
} catch (err) {
|
|
16946
17101
|
process.stderr.write(
|
|
16947
17102
|
`slack-channel(${AGENT_CODE_NAME}): recovery outbox parse failed (${filename}): ${err.message}
|
|
@@ -17009,7 +17164,7 @@ ${payload.text}`;
|
|
|
17009
17164
|
}
|
|
17010
17165
|
if (sendSucceeded) {
|
|
17011
17166
|
try {
|
|
17012
|
-
|
|
17167
|
+
unlinkSync5(fullPath);
|
|
17013
17168
|
} catch {
|
|
17014
17169
|
}
|
|
17015
17170
|
return;
|
|
@@ -17068,7 +17223,7 @@ function scanSlackRecoveryRetries() {
|
|
|
17068
17223
|
function startSlackRecoveryOutboxWatcher() {
|
|
17069
17224
|
if (!SLACK_RECOVERY_OUTBOX_DIR) return;
|
|
17070
17225
|
try {
|
|
17071
|
-
|
|
17226
|
+
mkdirSync6(SLACK_RECOVERY_OUTBOX_DIR, { recursive: true, mode: 448 });
|
|
17072
17227
|
} catch (err) {
|
|
17073
17228
|
process.stderr.write(
|
|
17074
17229
|
`slack-channel(${AGENT_CODE_NAME}): recovery outbox mkdir failed: ${err.message}
|
|
@@ -17127,14 +17282,14 @@ function sweepSlackStaleMarkers(thresholdMs) {
|
|
|
17127
17282
|
const fullPath = join7(SLACK_PENDING_INBOUND_DIR, filename);
|
|
17128
17283
|
let marker;
|
|
17129
17284
|
try {
|
|
17130
|
-
marker = JSON.parse(
|
|
17285
|
+
marker = JSON.parse(readFileSync9(fullPath, "utf-8"));
|
|
17131
17286
|
} catch (err) {
|
|
17132
17287
|
process.stderr.write(
|
|
17133
17288
|
`slack-channel(${AGENT_CODE_NAME}): stale-marker parse failed for ${redactSlackId(filename)}: ${err.message}
|
|
17134
17289
|
`
|
|
17135
17290
|
);
|
|
17136
17291
|
try {
|
|
17137
|
-
|
|
17292
|
+
unlinkSync5(fullPath);
|
|
17138
17293
|
} catch {
|
|
17139
17294
|
}
|
|
17140
17295
|
cleared++;
|
|
@@ -17149,7 +17304,7 @@ function sweepSlackStaleMarkers(thresholdMs) {
|
|
|
17149
17304
|
recordChannelDeflection(SLACK_AGENT_DIR, "slack", "replay_orphaned");
|
|
17150
17305
|
}
|
|
17151
17306
|
try {
|
|
17152
|
-
|
|
17307
|
+
unlinkSync5(fullPath);
|
|
17153
17308
|
} catch {
|
|
17154
17309
|
}
|
|
17155
17310
|
cleared++;
|
|
@@ -17179,7 +17334,7 @@ function listPendingSlackConversations() {
|
|
|
17179
17334
|
if (!name.endsWith(".json")) continue;
|
|
17180
17335
|
try {
|
|
17181
17336
|
const marker = JSON.parse(
|
|
17182
|
-
|
|
17337
|
+
readFileSync9(join7(SLACK_PENDING_INBOUND_DIR, name), "utf8")
|
|
17183
17338
|
);
|
|
17184
17339
|
if (typeof marker.channel !== "string" || !marker.channel) continue;
|
|
17185
17340
|
if (typeof marker.thread_ts !== "string" || !marker.thread_ts) continue;
|
|
@@ -17273,7 +17428,7 @@ async function notifyStrandedInboundsOnFirstConnect() {
|
|
|
17273
17428
|
const fullPath = join7(SLACK_PENDING_INBOUND_DIR, filename);
|
|
17274
17429
|
let marker;
|
|
17275
17430
|
try {
|
|
17276
|
-
marker = JSON.parse(
|
|
17431
|
+
marker = JSON.parse(readFileSync9(fullPath, "utf-8"));
|
|
17277
17432
|
} catch {
|
|
17278
17433
|
continue;
|
|
17279
17434
|
}
|
|
@@ -17286,7 +17441,7 @@ async function notifyStrandedInboundsOnFirstConnect() {
|
|
|
17286
17441
|
const key2 = `${channel}__${thread_ts}`;
|
|
17287
17442
|
if (seen.has(key2)) {
|
|
17288
17443
|
try {
|
|
17289
|
-
|
|
17444
|
+
unlinkSync5(fullPath);
|
|
17290
17445
|
} catch {
|
|
17291
17446
|
}
|
|
17292
17447
|
continue;
|
|
@@ -17300,7 +17455,7 @@ async function notifyStrandedInboundsOnFirstConnect() {
|
|
|
17300
17455
|
if (res.ok) {
|
|
17301
17456
|
notified += 1;
|
|
17302
17457
|
try {
|
|
17303
|
-
|
|
17458
|
+
unlinkSync5(fullPath);
|
|
17304
17459
|
} catch {
|
|
17305
17460
|
}
|
|
17306
17461
|
} else {
|
|
@@ -17372,6 +17527,49 @@ async function notifyRestartCompleteOnFirstConnect() {
|
|
|
17372
17527
|
restartConfirmNoticeInFlight = false;
|
|
17373
17528
|
}
|
|
17374
17529
|
}
|
|
17530
|
+
var dmChannelAddNoticeFired = false;
|
|
17531
|
+
var dmChannelAddNoticeInFlight = false;
|
|
17532
|
+
async function notifyDmUsersOnChannelAddRestart() {
|
|
17533
|
+
if (dmChannelAddNoticeFired || dmChannelAddNoticeInFlight) return;
|
|
17534
|
+
if (!SLACK_CHANNEL_ADD_RESTART_FILE) return;
|
|
17535
|
+
dmChannelAddNoticeInFlight = true;
|
|
17536
|
+
try {
|
|
17537
|
+
const marker = readChannelAddRestartMarker(SLACK_CHANNEL_ADD_RESTART_FILE);
|
|
17538
|
+
if (!shouldPostChannelAddNotice(marker, SLACK_PROCESS_BOOT_MS)) {
|
|
17539
|
+
if (marker) clearChannelAddRestartMarker(SLACK_CHANNEL_ADD_RESTART_FILE);
|
|
17540
|
+
return;
|
|
17541
|
+
}
|
|
17542
|
+
const dmChannels = recentlyActiveDmKeys(recentDms);
|
|
17543
|
+
const text = buildChannelAddNoticeText(marker.added);
|
|
17544
|
+
let notified = 0;
|
|
17545
|
+
for (const channel of dmChannels) {
|
|
17546
|
+
const res = await postSlackMessage({ channel, text });
|
|
17547
|
+
if (res.ok) {
|
|
17548
|
+
notified += 1;
|
|
17549
|
+
} else {
|
|
17550
|
+
process.stderr.write(
|
|
17551
|
+
`slack-channel(${AGENT_CODE_NAME}): channel-add DM notice failed channel=${redactSlackId(channel)} error=${res.error}
|
|
17552
|
+
`
|
|
17553
|
+
);
|
|
17554
|
+
}
|
|
17555
|
+
}
|
|
17556
|
+
clearChannelAddRestartMarker(SLACK_CHANNEL_ADD_RESTART_FILE);
|
|
17557
|
+
if (notified > 0) {
|
|
17558
|
+
process.stderr.write(
|
|
17559
|
+
`slack-channel(${AGENT_CODE_NAME}): notified ${notified} recently-active DM(s) after channel-add restart
|
|
17560
|
+
`
|
|
17561
|
+
);
|
|
17562
|
+
}
|
|
17563
|
+
} catch (err) {
|
|
17564
|
+
process.stderr.write(
|
|
17565
|
+
`slack-channel(${AGENT_CODE_NAME}): channel-add DM notice threw: ${redactAugmentedPaths2(err.message)}
|
|
17566
|
+
`
|
|
17567
|
+
);
|
|
17568
|
+
} finally {
|
|
17569
|
+
dmChannelAddNoticeFired = true;
|
|
17570
|
+
dmChannelAddNoticeInFlight = false;
|
|
17571
|
+
}
|
|
17572
|
+
}
|
|
17375
17573
|
function writeSlackRestartConfirm(reply, requesterName) {
|
|
17376
17574
|
if (!SLACK_RESTART_CONFIRM_FILE) return;
|
|
17377
17575
|
const marker = {
|
|
@@ -17806,7 +18004,7 @@ async function handleSlashCommandEnvelope(payload) {
|
|
|
17806
18004
|
}
|
|
17807
18005
|
try {
|
|
17808
18006
|
if (!existsSync7(RESTART_FLAGS_DIR)) {
|
|
17809
|
-
|
|
18007
|
+
mkdirSync6(RESTART_FLAGS_DIR, { recursive: true });
|
|
17810
18008
|
}
|
|
17811
18009
|
const flagPath = join7(RESTART_FLAGS_DIR, `${codeName}.flag`);
|
|
17812
18010
|
writeSlackRestartConfirm(
|
|
@@ -17826,7 +18024,7 @@ async function handleSlashCommandEnvelope(payload) {
|
|
|
17826
18024
|
}
|
|
17827
18025
|
};
|
|
17828
18026
|
const tmpPath = `${flagPath}.${process.pid}.${randomUUID2()}.tmp`;
|
|
17829
|
-
|
|
18027
|
+
writeFileSync7(tmpPath, JSON.stringify(flag) + "\n", "utf8");
|
|
17830
18028
|
renameSync3(tmpPath, flagPath);
|
|
17831
18029
|
process.stderr.write(
|
|
17832
18030
|
`slack-channel(${codeName}): /restart slash-command queued from channel ${hashChannelId(payload.channel_id)}
|
|
@@ -17968,7 +18166,7 @@ async function handleRestartCommand(opts) {
|
|
|
17968
18166
|
const codeName = AGENT_CODE_NAME ?? "unknown";
|
|
17969
18167
|
try {
|
|
17970
18168
|
if (!existsSync7(RESTART_FLAGS_DIR)) {
|
|
17971
|
-
|
|
18169
|
+
mkdirSync6(RESTART_FLAGS_DIR, { recursive: true });
|
|
17972
18170
|
}
|
|
17973
18171
|
const flagPath = join7(RESTART_FLAGS_DIR, `${codeName}.flag`);
|
|
17974
18172
|
writeSlackRestartConfirm(
|
|
@@ -17989,7 +18187,7 @@ async function handleRestartCommand(opts) {
|
|
|
17989
18187
|
}
|
|
17990
18188
|
};
|
|
17991
18189
|
const tmpPath = `${flagPath}.${process.pid}.${randomUUID2()}.tmp`;
|
|
17992
|
-
|
|
18190
|
+
writeFileSync7(tmpPath, JSON.stringify(flag) + "\n", "utf8");
|
|
17993
18191
|
renameSync3(tmpPath, flagPath);
|
|
17994
18192
|
process.stderr.write(
|
|
17995
18193
|
`slack-channel(${codeName}): /restart queued from channel ${hashChannelId(opts.channel)}
|
|
@@ -18085,6 +18283,8 @@ async function denyUnauthorizedWatch(opts) {
|
|
|
18085
18283
|
...opts.threadTs ? { thread_ts: opts.threadTs } : {}
|
|
18086
18284
|
});
|
|
18087
18285
|
}
|
|
18286
|
+
var recentDms = /* @__PURE__ */ new Map();
|
|
18287
|
+
var recentDmPersister = null;
|
|
18088
18288
|
var trackedThreads = /* @__PURE__ */ new Map();
|
|
18089
18289
|
var THREAD_STORE_PATH = resolveThreadStorePath();
|
|
18090
18290
|
var THREAD_STORE_TTL_DAYS = parseTtlDays(process.env.SLACK_THREAD_FOLLOW_TTL_DAYS);
|
|
@@ -18131,7 +18331,7 @@ var slackStderrLogStream = null;
|
|
|
18131
18331
|
if (AGENT_CODE_NAME) {
|
|
18132
18332
|
try {
|
|
18133
18333
|
const logDir = join7(homedir3(), ".augmented", AGENT_CODE_NAME);
|
|
18134
|
-
|
|
18334
|
+
mkdirSync6(logDir, { recursive: true });
|
|
18135
18335
|
slackStderrLogStream = createWriteStream(join7(logDir, "slack-channel-stderr.log"), {
|
|
18136
18336
|
flags: "a",
|
|
18137
18337
|
mode: 384
|
|
@@ -18712,7 +18912,7 @@ ${result.formatted}` : "Thread is empty or not found."
|
|
|
18712
18912
|
};
|
|
18713
18913
|
}
|
|
18714
18914
|
size = stat2.size;
|
|
18715
|
-
bytes =
|
|
18915
|
+
bytes = readFileSync9(resolvedPath);
|
|
18716
18916
|
} catch (err) {
|
|
18717
18917
|
return {
|
|
18718
18918
|
content: [{ type: "text", text: `Failed to read file: ${err.message}` }],
|
|
@@ -19350,8 +19550,8 @@ async function downloadSlackFile(fileId, codeName) {
|
|
|
19350
19550
|
if (!isPathInside(savedPath, dir)) {
|
|
19351
19551
|
throw new Error(`refusing to write ${savedPath} outside ${dir}`);
|
|
19352
19552
|
}
|
|
19353
|
-
|
|
19354
|
-
|
|
19553
|
+
mkdirSync6(dir, { recursive: true });
|
|
19554
|
+
writeFileSync7(savedPath, bytes, { mode: 384 });
|
|
19355
19555
|
try {
|
|
19356
19556
|
chmodSync(savedPath, 384);
|
|
19357
19557
|
} catch {
|
|
@@ -19430,7 +19630,7 @@ async function replayPendingSlackMarkers() {
|
|
|
19430
19630
|
const fullPath = join7(SLACK_PENDING_INBOUND_DIR, name);
|
|
19431
19631
|
let marker;
|
|
19432
19632
|
try {
|
|
19433
|
-
marker = JSON.parse(
|
|
19633
|
+
marker = JSON.parse(readFileSync9(fullPath, "utf-8"));
|
|
19434
19634
|
} catch {
|
|
19435
19635
|
continue;
|
|
19436
19636
|
}
|
|
@@ -19557,6 +19757,7 @@ async function connectSocketMode() {
|
|
|
19557
19757
|
void notifyStrandedInboundsOnFirstConnect();
|
|
19558
19758
|
}
|
|
19559
19759
|
void notifyRestartCompleteOnFirstConnect();
|
|
19760
|
+
void notifyDmUsersOnChannelAddRestart();
|
|
19560
19761
|
void applyBotPhotoOnFirstConnect();
|
|
19561
19762
|
};
|
|
19562
19763
|
ws.onmessage = async (event) => {
|
|
@@ -19754,6 +19955,14 @@ async function connectSocketMode() {
|
|
|
19754
19955
|
const isThreadReply = !!evt.thread_ts && evt.thread_ts !== evt.ts;
|
|
19755
19956
|
const trackTs = evt.thread_ts ?? evt.ts ?? "";
|
|
19756
19957
|
const threadKey = buildThreadKey(evt.channel, trackTs);
|
|
19958
|
+
if (isDirectMessage && !isBot && evt.channel && evt.user && evt.user !== botUserId) {
|
|
19959
|
+
recordDmActivity(recentDms, evt.channel);
|
|
19960
|
+
if (isShuttingDown) {
|
|
19961
|
+
recentDmPersister?.flush(recentDms);
|
|
19962
|
+
} else {
|
|
19963
|
+
recentDmPersister?.schedule(recentDms);
|
|
19964
|
+
}
|
|
19965
|
+
}
|
|
19757
19966
|
if (isBot && peerClassification?.kind === "peer-ingress") {
|
|
19758
19967
|
const peerGate = peerClassification.peer.gate_path;
|
|
19759
19968
|
if (peerGate === "intra_org_unrestricted") {
|
|
@@ -19989,6 +20198,14 @@ function shutdown(reason, exitCode = 0) {
|
|
|
19989
20198
|
threadPersister?.dispose();
|
|
19990
20199
|
} catch {
|
|
19991
20200
|
}
|
|
20201
|
+
try {
|
|
20202
|
+
recentDmPersister?.flush(recentDms);
|
|
20203
|
+
} catch {
|
|
20204
|
+
}
|
|
20205
|
+
try {
|
|
20206
|
+
recentDmPersister?.dispose();
|
|
20207
|
+
} catch {
|
|
20208
|
+
}
|
|
19992
20209
|
process.stderr.write(`slack-channel: ${reason} \u2014 closing Socket Mode and exiting
|
|
19993
20210
|
`);
|
|
19994
20211
|
try {
|
|
@@ -20032,7 +20249,12 @@ process.on("unhandledRejection", (reason) => {
|
|
|
20032
20249
|
}
|
|
20033
20250
|
if (THREAD_STORE_PATH) {
|
|
20034
20251
|
const threadStoreLabel = "slack-tracked-threads.json";
|
|
20035
|
-
const
|
|
20252
|
+
const recentDmsLabel = "slack-recent-dms.json";
|
|
20253
|
+
const redact = (msg) => {
|
|
20254
|
+
let out = msg.replaceAll(THREAD_STORE_PATH, threadStoreLabel);
|
|
20255
|
+
if (SLACK_RECENT_DMS_FILE) out = out.replaceAll(SLACK_RECENT_DMS_FILE, recentDmsLabel);
|
|
20256
|
+
return out;
|
|
20257
|
+
};
|
|
20036
20258
|
const { threads, pruned } = loadThreadStore(THREAD_STORE_PATH, {
|
|
20037
20259
|
ttlDays: THREAD_STORE_TTL_DAYS,
|
|
20038
20260
|
onError: (msg) => process.stderr.write(`${redact(msg)}
|
|
@@ -20048,6 +20270,18 @@ if (THREAD_STORE_PATH) {
|
|
|
20048
20270
|
`slack-channel: hydrated ${trackedThreads.size} tracked thread(s)${pruned > 0 ? ` (pruned ${pruned} stale)` : ""} from ${threadStoreLabel}
|
|
20049
20271
|
`
|
|
20050
20272
|
);
|
|
20273
|
+
if (SLACK_RECENT_DMS_FILE) {
|
|
20274
|
+
const loadedDms = loadRecentDms(SLACK_RECENT_DMS_FILE, {
|
|
20275
|
+
onError: (msg) => process.stderr.write(`${redact(msg)}
|
|
20276
|
+
`)
|
|
20277
|
+
});
|
|
20278
|
+
for (const [key2, entry] of loadedDms) recentDms.set(key2, entry);
|
|
20279
|
+
recentDmPersister = createRecentDmPersister({
|
|
20280
|
+
filePath: SLACK_RECENT_DMS_FILE,
|
|
20281
|
+
onError: (msg) => process.stderr.write(`${redact(msg)}
|
|
20282
|
+
`)
|
|
20283
|
+
});
|
|
20284
|
+
}
|
|
20051
20285
|
} else {
|
|
20052
20286
|
process.stderr.write(
|
|
20053
20287
|
"slack-channel: AGT_AGENT_CODE_NAME not set \u2014 running without thread-follow persistence\n"
|