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