@integrity-labs/agt-cli 0.28.448 → 0.28.450

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.
@@ -18870,7 +18870,7 @@ var require_filters = __commonJS({
18870
18870
  return r.copySafeness(str, res);
18871
18871
  }
18872
18872
  _exports.indent = indent;
18873
- function join19(arr, del, attr) {
18873
+ function join21(arr, del, attr) {
18874
18874
  del = del || "";
18875
18875
  if (attr) {
18876
18876
  arr = lib.map(arr, function(v) {
@@ -18879,7 +18879,7 @@ var require_filters = __commonJS({
18879
18879
  }
18880
18880
  return arr.join(del);
18881
18881
  }
18882
- _exports.join = join19;
18882
+ _exports.join = join21;
18883
18883
  function last(arr) {
18884
18884
  return arr[arr.length - 1];
18885
18885
  }
@@ -22480,11 +22480,11 @@ async function waitForResolution(cfg, callbackId, opts) {
22480
22480
  }
22481
22481
  } catch {
22482
22482
  }
22483
- await sleep(interval);
22483
+ await sleep2(interval);
22484
22484
  }
22485
22485
  return { kind: "timeout" };
22486
22486
  }
22487
- function sleep(ms) {
22487
+ function sleep2(ms) {
22488
22488
  return new Promise((r) => setTimeout(r, ms));
22489
22489
  }
22490
22490
  function generateOptionToken() {
@@ -30393,6 +30393,40 @@ function resolveSlackScheduledChannelGuardMode(opts) {
30393
30393
  if (cached2 !== void 0) return clampScheduledChannelGuardMode(cached2);
30394
30394
  return "shadow";
30395
30395
  }
30396
+ var USAGE_LIMIT_REACTIVE_FLAG_KEY = "usage-limit-reactive-notice";
30397
+ function parseUsageLimitReactiveMode(raw) {
30398
+ if (raw === void 0) return void 0;
30399
+ const v = raw.trim().toLowerCase();
30400
+ if (v === "") return void 0;
30401
+ if (v === "off" || v === "shadow" || v === "enforce") return v;
30402
+ const b = envBoolean(raw);
30403
+ if (b === true) return "enforce";
30404
+ if (b === false) return "off";
30405
+ return void 0;
30406
+ }
30407
+ function cachedUsageLimitReactiveMode(path) {
30408
+ try {
30409
+ if (!existsSync(path)) return void 0;
30410
+ const parsed = JSON.parse(readFileSync(path, "utf8"));
30411
+ if (!parsed || typeof parsed !== "object") return void 0;
30412
+ const flags = parsed.flags;
30413
+ if (!flags || typeof flags !== "object") return void 0;
30414
+ const value = flags[USAGE_LIMIT_REACTIVE_FLAG_KEY];
30415
+ if (typeof value === "string") return parseUsageLimitReactiveMode(value);
30416
+ if (typeof value === "boolean") return value ? "enforce" : "off";
30417
+ return void 0;
30418
+ } catch {
30419
+ return void 0;
30420
+ }
30421
+ }
30422
+ function resolveUsageLimitReactiveMode(opts) {
30423
+ const env2 = opts?.env ?? process.env;
30424
+ const modeOverride = parseUsageLimitReactiveMode(env2["AGT_USAGE_LIMIT_REACTIVE_MODE"]);
30425
+ if (modeOverride !== void 0) return modeOverride;
30426
+ const cached2 = cachedUsageLimitReactiveMode(opts?.cachePath ?? defaultFlagsCachePath());
30427
+ if (cached2 !== void 0) return cached2;
30428
+ return "off";
30429
+ }
30396
30430
 
30397
30431
  // src/maintenance-mode.ts
30398
30432
  var FLAG_KEY = "platform-maintenance-mode";
@@ -33734,7 +33768,113 @@ var BANNER_PATTERNS = [
33734
33768
  // pct=100.
33735
33769
  new RegExp(`${SUBJECT}hit\\s+your\\s+(?:[a-z0-9-]+\\s+)?limit${SEP}resets\\s+(${RESET_DATE})`, "i")
33736
33770
  ];
33771
+ function parseUsageBanner(text, now = /* @__PURE__ */ new Date()) {
33772
+ let bestIndex = -1;
33773
+ let best = null;
33774
+ for (let i = 0; i < BANNER_PATTERNS.length; i++) {
33775
+ const pattern = new RegExp(BANNER_PATTERNS[i].source, "gi");
33776
+ let match;
33777
+ while ((match = pattern.exec(text)) !== null) {
33778
+ if (match.index === pattern.lastIndex)
33779
+ pattern.lastIndex++;
33780
+ let pct;
33781
+ let resetStr;
33782
+ if (i === 0) {
33783
+ pct = Number.parseInt(match[1], 10);
33784
+ resetStr = match[2];
33785
+ } else {
33786
+ pct = 100;
33787
+ resetStr = match[1];
33788
+ }
33789
+ if (!Number.isFinite(pct) || pct < 0 || pct > 100)
33790
+ continue;
33791
+ const nextChar = text[match.index + match[0].length];
33792
+ if (nextChar !== void 0 && /[A-Za-z0-9]/.test(nextChar))
33793
+ continue;
33794
+ const weekResetsAt = parseResetDateTime(resetStr, now);
33795
+ if (!weekResetsAt)
33796
+ continue;
33797
+ if (match.index >= bestIndex) {
33798
+ bestIndex = match.index;
33799
+ best = { pct, weekResetsAt };
33800
+ }
33801
+ }
33802
+ }
33803
+ return best;
33804
+ }
33805
+ var MONTHS = [
33806
+ "jan",
33807
+ "feb",
33808
+ "mar",
33809
+ "apr",
33810
+ "may",
33811
+ "jun",
33812
+ "jul",
33813
+ "aug",
33814
+ "sep",
33815
+ "oct",
33816
+ "nov",
33817
+ "dec"
33818
+ ];
33819
+ var TIME_TAIL = /,\s*(\d{1,2})(?::(\d{2}))?\s*(am|pm)(?:\s*\(?UTC\)?)?\s*$/i;
33820
+ var TIME_ONLY = /^(\d{1,2})(?::(\d{2}))?\s*(am|pm)(?:\s*\(?UTC\)?)?$/i;
33737
33821
  var MS_PER_DAY = 24 * 60 * 60 * 1e3;
33822
+ function parseAmPm(hourStr, minStr, ampm) {
33823
+ const rawHour = Number.parseInt(hourStr, 10);
33824
+ if (!Number.isFinite(rawHour) || rawHour < 1 || rawHour > 12)
33825
+ return null;
33826
+ let minute = 0;
33827
+ if (minStr) {
33828
+ minute = Number.parseInt(minStr, 10);
33829
+ if (!Number.isFinite(minute) || minute < 0 || minute > 59)
33830
+ return null;
33831
+ }
33832
+ const isPm = ampm.toLowerCase() === "pm";
33833
+ return { hour: rawHour % 12 + (isPm ? 12 : 0), minute };
33834
+ }
33835
+ function parseResetDateTime(humanDate, now) {
33836
+ const trimmed = humanDate.trim();
33837
+ const timeOnly = trimmed.match(TIME_ONLY);
33838
+ if (timeOnly) {
33839
+ const hm = parseAmPm(timeOnly[1], timeOnly[2], timeOnly[3]);
33840
+ if (!hm)
33841
+ return null;
33842
+ const todayAt = Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate(), hm.hour, hm.minute);
33843
+ return new Date(todayAt <= now.getTime() ? todayAt + MS_PER_DAY : todayAt);
33844
+ }
33845
+ const timeMatch = trimmed.match(TIME_TAIL);
33846
+ const dateOnly = timeMatch ? trimmed.slice(0, timeMatch.index).trim() : trimmed;
33847
+ const parts = dateOnly.split(/\s+/);
33848
+ if (parts.length !== 2)
33849
+ return null;
33850
+ const month = MONTHS.indexOf(parts[0].slice(0, 3).toLowerCase());
33851
+ if (month < 0)
33852
+ return null;
33853
+ const day = Number.parseInt(parts[1], 10);
33854
+ if (!Number.isFinite(day) || day < 1 || day > 31)
33855
+ return null;
33856
+ let hour = 0;
33857
+ let minute = 0;
33858
+ if (timeMatch) {
33859
+ const hm = parseAmPm(timeMatch[1], timeMatch[2], timeMatch[3]);
33860
+ if (!hm)
33861
+ return null;
33862
+ hour = hm.hour;
33863
+ minute = hm.minute;
33864
+ }
33865
+ const baseYear = now.getUTCFullYear();
33866
+ let resolved = null;
33867
+ let bestDelta = Number.POSITIVE_INFINITY;
33868
+ for (const y of [baseYear - 1, baseYear, baseYear + 1]) {
33869
+ const candidate = new Date(Date.UTC(y, month, day, hour, minute));
33870
+ const delta = Math.abs(candidate.getTime() - now.getTime());
33871
+ if (delta < bestDelta) {
33872
+ bestDelta = delta;
33873
+ resolved = candidate;
33874
+ }
33875
+ }
33876
+ return resolved;
33877
+ }
33738
33878
 
33739
33879
  // ../core/dist/claude-code-usage/usage-limit-marker.js
33740
33880
  var USAGE_LIMIT_MARKER_FILENAME = "claude-usage-limit.json";
@@ -33779,6 +33919,101 @@ var UNKNOWN_RATE_LIMIT = Object.freeze({
33779
33919
  resetsAt: null,
33780
33920
  text: null
33781
33921
  });
33922
+ function contentText(record2) {
33923
+ const candidates = [record2.content];
33924
+ const message = record2.message;
33925
+ if (typeof message === "object" && message !== null) {
33926
+ candidates.push(message.content);
33927
+ }
33928
+ const parts = [];
33929
+ for (const candidate of candidates) {
33930
+ if (typeof candidate === "string") {
33931
+ if (candidate)
33932
+ parts.push(candidate);
33933
+ continue;
33934
+ }
33935
+ if (!Array.isArray(candidate))
33936
+ continue;
33937
+ for (const block of candidate) {
33938
+ if (typeof block === "string") {
33939
+ if (block)
33940
+ parts.push(block);
33941
+ continue;
33942
+ }
33943
+ if (typeof block !== "object" || block === null)
33944
+ continue;
33945
+ const text = block.text;
33946
+ if (typeof text === "string" && text)
33947
+ parts.push(text);
33948
+ }
33949
+ }
33950
+ const joined = parts.join("\n").trim();
33951
+ return joined ? joined : null;
33952
+ }
33953
+ function classifyTranscriptLine(line, startMs, endMs, now) {
33954
+ const trimmed = line.trim();
33955
+ if (!trimmed)
33956
+ return null;
33957
+ let obj;
33958
+ try {
33959
+ obj = JSON.parse(trimmed);
33960
+ } catch {
33961
+ return null;
33962
+ }
33963
+ if (typeof obj !== "object" || obj === null)
33964
+ return null;
33965
+ const record2 = obj;
33966
+ if (record2.type !== "assistant")
33967
+ return null;
33968
+ const ts = record2.timestamp;
33969
+ if (typeof ts !== "string" || !ts)
33970
+ return null;
33971
+ const tsMs = new Date(ts).getTime();
33972
+ if (!Number.isFinite(tsMs) || tsMs < startMs || tsMs > endMs)
33973
+ return null;
33974
+ if (record2.error === "rate_limit" || record2.apiErrorStatus === 429) {
33975
+ const text = contentText(record2);
33976
+ const observation = text ? parseUsageBanner(text, now ?? new Date(endMs)) : null;
33977
+ return { verdict: "capped", atMs: tsMs, resetsAt: observation?.weekResetsAt ?? null, text };
33978
+ }
33979
+ if (record2.isApiErrorMessage === true)
33980
+ return null;
33981
+ const message = record2.message;
33982
+ if (typeof message !== "object" || message === null)
33983
+ return null;
33984
+ const msg = message;
33985
+ if (msg.model === "<synthetic>")
33986
+ return null;
33987
+ const usage = msg.usage;
33988
+ if (typeof usage !== "object" || usage === null)
33989
+ return null;
33990
+ const u = usage;
33991
+ const spent = Number(u.input_tokens ?? 0) + Number(u.output_tokens ?? 0) + Number(u.cache_creation_input_tokens ?? 0) + Number(u.cache_read_input_tokens ?? 0);
33992
+ if (!Number.isFinite(spent) || spent <= 0)
33993
+ return null;
33994
+ return { verdict: "serving", atMs: tsMs, resetsAt: null, text: null };
33995
+ }
33996
+ function pickNewerClassification(current, next) {
33997
+ if (next.verdict === "unknown")
33998
+ return current;
33999
+ if (current.verdict === "unknown")
34000
+ return next;
34001
+ return next.atMs >= current.atMs ? next : current;
34002
+ }
34003
+ function classifyTranscriptRateLimit(jsonl, startMs, endMs, now) {
34004
+ let newest = UNKNOWN_RATE_LIMIT;
34005
+ for (const line of jsonl.split("\n")) {
34006
+ const classified = classifyTranscriptLine(line, startMs, endMs, now);
34007
+ if (classified)
34008
+ newest = pickNewerClassification(newest, classified);
34009
+ }
34010
+ return newest;
34011
+ }
34012
+
34013
+ // ../core/dist/claude-code-usage/transcript-location.js
34014
+ function encodeClaudeProjectPath(projectDir) {
34015
+ return "-" + projectDir.replace(/^\//, "").replace(/[/.]/g, "-");
34016
+ }
33782
34017
 
33783
34018
  // ../core/dist/account-enforcement/marker.js
33784
34019
  var ACCOUNT_ENFORCEMENT_MARKER_FILENAME = "account-enforcement.json";
@@ -36309,11 +36544,102 @@ function emitToolCallMarkupRedactionTelemetry(channel) {
36309
36544
  }
36310
36545
  }
36311
36546
 
36547
+ // src/rate-limit-watch.ts
36548
+ import { readFileSync as readFileSync6, readdirSync as readdirSync2, statSync } from "fs";
36549
+ import { homedir as homedir5 } from "os";
36550
+ import { join as join7 } from "path";
36551
+ var DEFAULT_WATCH_MS = 5e3;
36552
+ var DEFAULT_POLL_MS = 400;
36553
+ function agentTranscriptDir(opts) {
36554
+ const cwd = opts?.cwd ?? process.cwd();
36555
+ const home = opts?.home ?? homedir5();
36556
+ return join7(home, ".claude", "projects", encodeClaudeProjectPath(cwd));
36557
+ }
36558
+ function classifyTranscriptSince(opts) {
36559
+ const dir = opts.transcriptDir ?? agentTranscriptDir({ cwd: opts.cwd, home: opts.home });
36560
+ let entries;
36561
+ try {
36562
+ entries = readdirSync2(dir);
36563
+ } catch {
36564
+ return UNKNOWN_RATE_LIMIT;
36565
+ }
36566
+ let newest = UNKNOWN_RATE_LIMIT;
36567
+ for (const name of entries) {
36568
+ if (!name.endsWith(".jsonl")) continue;
36569
+ const path = join7(dir, name);
36570
+ try {
36571
+ const st = statSync(path);
36572
+ if (!st.isFile() || st.mtimeMs < opts.sinceMs) continue;
36573
+ } catch {
36574
+ continue;
36575
+ }
36576
+ let content;
36577
+ try {
36578
+ content = readFileSync6(path, "utf-8");
36579
+ } catch {
36580
+ continue;
36581
+ }
36582
+ newest = pickNewerClassification(
36583
+ newest,
36584
+ classifyTranscriptRateLimit(content, opts.sinceMs, opts.nowMs, new Date(opts.nowMs))
36585
+ );
36586
+ }
36587
+ return newest;
36588
+ }
36589
+ var sleep = (ms) => new Promise((resolve3) => setTimeout(resolve3, ms));
36590
+ async function watchForRateLimitRefusal(opts) {
36591
+ const now = opts.now ?? (() => Date.now());
36592
+ const wait = opts.wait ?? sleep;
36593
+ const timeoutMs = opts.timeoutMs ?? DEFAULT_WATCH_MS;
36594
+ const pollMs = opts.pollMs ?? DEFAULT_POLL_MS;
36595
+ const deadline = now() + timeoutMs;
36596
+ for (; ; ) {
36597
+ let result;
36598
+ try {
36599
+ result = classifyTranscriptSince({
36600
+ sinceMs: opts.sinceMs,
36601
+ nowMs: now(),
36602
+ transcriptDir: opts.transcriptDir,
36603
+ cwd: opts.cwd,
36604
+ home: opts.home
36605
+ });
36606
+ } catch {
36607
+ return null;
36608
+ }
36609
+ if (result.verdict === "capped") return result;
36610
+ if (result.verdict === "serving") return null;
36611
+ if (now() >= deadline) return null;
36612
+ await wait(pollMs);
36613
+ }
36614
+ }
36615
+
36616
+ // src/usage-limit-reactive-decision.ts
36617
+ import { createHash } from "crypto";
36618
+ function shouldReadPredictiveMarker(mode) {
36619
+ return mode !== "enforce";
36620
+ }
36621
+ function armedWatchMode(opts) {
36622
+ if (opts.mode === "off") return null;
36623
+ if (opts.isBot || !opts.replyOwed) return null;
36624
+ return opts.mode;
36625
+ }
36626
+ function decideRefusalAction(opts) {
36627
+ const { refusal } = opts;
36628
+ if (!refusal || refusal.verdict !== "capped") return "none";
36629
+ if (!refusal.resetsAt) return "missing-reset";
36630
+ return opts.mode === "shadow" ? "shadow-log" : "notify";
36631
+ }
36632
+ function describeUnparsedRefusal(text) {
36633
+ if (!text) return "refusal=absent";
36634
+ const hash = createHash("sha256").update(text).digest("hex").slice(0, 12);
36635
+ return `refusal_hash=${hash} refusal_len=${text.length}`;
36636
+ }
36637
+
36312
36638
  // src/reply-intent-runtime.ts
36313
36639
  import { execFile as execFile2 } from "child_process";
36314
36640
  import { existsSync as existsSync3, mkdirSync, writeFileSync as writeFileSync2 } from "fs";
36315
- import { homedir as homedir5 } from "os";
36316
- import { join as join7 } from "path";
36641
+ import { homedir as homedir6 } from "os";
36642
+ import { join as join8 } from "path";
36317
36643
  var DEFAULT_CLAUDE_EVAL_MODEL = "claude-haiku-4-5-20251001";
36318
36644
  var DEFAULT_ANTHROPIC_MESSAGES_URL = "https://api.anthropic.com/v1/messages";
36319
36645
  var ANTHROPIC_API_VERSION = "2023-06-01";
@@ -36412,12 +36738,12 @@ async function runAnthropicMessages(prompt, opts) {
36412
36738
  var emptyMcpConfigPath = null;
36413
36739
  function ensureEmptyMcpConfig() {
36414
36740
  if (emptyMcpConfigPath && existsSync3(emptyMcpConfigPath)) return emptyMcpConfigPath;
36415
- const dir = join7(homedir5(), ".augmented");
36741
+ const dir = join8(homedir6(), ".augmented");
36416
36742
  try {
36417
36743
  mkdirSync(dir, { recursive: true });
36418
36744
  } catch {
36419
36745
  }
36420
- const p2 = join7(dir, ".reply-intent-empty-mcp.json");
36746
+ const p2 = join8(dir, ".reply-intent-empty-mcp.json");
36421
36747
  writeFileSync2(p2, JSON.stringify({ mcpServers: {} }));
36422
36748
  emptyMcpConfigPath = p2;
36423
36749
  return p2;
@@ -36442,7 +36768,7 @@ function runClaudeP(prompt, model) {
36442
36768
  execFile2(
36443
36769
  "claude",
36444
36770
  args,
36445
- { cwd: homedir5(), timeout: CLASSIFY_TIMEOUT_MS, maxBuffer: 1 << 20 },
36771
+ { cwd: homedir6(), timeout: CLASSIFY_TIMEOUT_MS, maxBuffer: 1 << 20 },
36446
36772
  (err, stdout) => {
36447
36773
  if (err) {
36448
36774
  reject(err);
@@ -36564,8 +36890,8 @@ function emitTransientApiErrorTelemetry(channel, match, original) {
36564
36890
  }
36565
36891
 
36566
36892
  // src/slack-pending-inbound-cleanup.ts
36567
- import { existsSync as existsSync4, readdirSync as readdirSync2, statSync, unlinkSync } from "fs";
36568
- import { join as join8 } from "path";
36893
+ import { existsSync as existsSync4, readdirSync as readdirSync3, statSync as statSync2, unlinkSync } from "fs";
36894
+ import { join as join9 } from "path";
36569
36895
  function sanitizeMarkerSegment(value) {
36570
36896
  return value.replace(/[^A-Za-z0-9_-]/g, "_");
36571
36897
  }
@@ -36579,9 +36905,9 @@ function applyToMatchingMarkers(dir, prefix, suffix, op) {
36579
36905
  if (!dir) return 0;
36580
36906
  let applied = 0;
36581
36907
  try {
36582
- for (const f of readdirSync2(dir)) {
36908
+ for (const f of readdirSync3(dir)) {
36583
36909
  if (!f.startsWith(prefix) || !f.endsWith(suffix)) continue;
36584
- op(join8(dir, f));
36910
+ op(join9(dir, f));
36585
36911
  applied += 1;
36586
36912
  }
36587
36913
  } catch {
@@ -36610,11 +36936,11 @@ function clearOldestSlackPendingMarkerInChannel(dir, channel, clear = defaultCle
36610
36936
  if (!dir) return null;
36611
36937
  const channelPrefix = `${sanitizeMarkerSegment(channel)}__`;
36612
36938
  try {
36613
- const entries = readdirSync2(dir).filter((f) => f.startsWith(channelPrefix) && f.endsWith(".json")).map((f) => {
36614
- const full = join8(dir, f);
36939
+ const entries = readdirSync3(dir).filter((f) => f.startsWith(channelPrefix) && f.endsWith(".json")).map((f) => {
36940
+ const full = join9(dir, f);
36615
36941
  let mtime = 0;
36616
36942
  try {
36617
- mtime = statSync(full).mtimeMs;
36943
+ mtime = statSync2(full).mtimeMs;
36618
36944
  } catch {
36619
36945
  }
36620
36946
  return { name: f, full, mtime };
@@ -36630,12 +36956,12 @@ function clearOldestSlackPendingMarkerInChannel(dir, channel, clear = defaultCle
36630
36956
 
36631
36957
  // src/recovery-ledger.ts
36632
36958
  import { existsSync as existsSync5, unlinkSync as unlinkSync2 } from "fs";
36633
- import { join as join9 } from "path";
36959
+ import { join as join10 } from "path";
36634
36960
  function recoveryLedgerEntryExists(ledgerDir, markerName, exists = (p2) => existsSync5(p2)) {
36635
36961
  if (!ledgerDir || !markerName) return false;
36636
36962
  if (markerName.includes("/") || markerName.includes("\\") || markerName.includes("..")) return false;
36637
36963
  try {
36638
- return exists(join9(ledgerDir, markerName));
36964
+ return exists(join10(ledgerDir, markerName));
36639
36965
  } catch {
36640
36966
  return false;
36641
36967
  }
@@ -36646,7 +36972,7 @@ function removeRecoveryLedgerEntry(ledgerDir, markerName, unlink = (p2) => {
36646
36972
  if (!ledgerDir || !markerName) return;
36647
36973
  if (markerName.includes("/") || markerName.includes("\\") || markerName.includes("..")) return;
36648
36974
  try {
36649
- unlink(join9(ledgerDir, markerName));
36975
+ unlink(join10(ledgerDir, markerName));
36650
36976
  } catch {
36651
36977
  }
36652
36978
  }
@@ -36882,8 +37208,36 @@ function applyHotThreadGuard(input) {
36882
37208
  return { threadTs: void 0, guard: "root_no_hot_thread" };
36883
37209
  }
36884
37210
 
37211
+ // src/slack-hot-thread-telemetry.ts
37212
+ import { readFileSync as readFileSync7, writeFileSync as writeFileSync3 } from "fs";
37213
+ import { join as join11 } from "path";
37214
+ var HOT_THREAD_CLASSIFICATION_COUNTER_SUFFIX = "-hot-thread-classifications.json";
37215
+ function hotThreadKey(mode, outcome, proactive) {
37216
+ return `${mode}|${outcome}|${proactive ? "true" : "false"}`;
37217
+ }
37218
+ function recordHotThreadClassification(agentDir, channel, classification) {
37219
+ if (!agentDir || !channel) return;
37220
+ const path = join11(agentDir, `${channel}${HOT_THREAD_CLASSIFICATION_COUNTER_SUFFIX}`);
37221
+ let counts = {};
37222
+ try {
37223
+ const parsed = JSON.parse(readFileSync7(path, "utf-8"));
37224
+ if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
37225
+ for (const [k, v] of Object.entries(parsed)) {
37226
+ if (typeof v === "number" && Number.isInteger(v) && v >= 0) counts[k] = v;
37227
+ }
37228
+ }
37229
+ } catch {
37230
+ }
37231
+ const key2 = hotThreadKey(classification.mode, classification.outcome, classification.proactive);
37232
+ counts[key2] = (counts[key2] ?? 0) + 1;
37233
+ try {
37234
+ writeFileSync3(path, JSON.stringify(counts), { mode: 384 });
37235
+ } catch {
37236
+ }
37237
+ }
37238
+
36885
37239
  // src/restart-confirm.ts
36886
- import { existsSync as existsSync6, mkdirSync as mkdirSync2, readFileSync as readFileSync6, renameSync, unlinkSync as unlinkSync3, writeFileSync as writeFileSync3 } from "fs";
37240
+ import { existsSync as existsSync6, mkdirSync as mkdirSync2, readFileSync as readFileSync8, renameSync, unlinkSync as unlinkSync3, writeFileSync as writeFileSync4 } from "fs";
36887
37241
  import { dirname } from "path";
36888
37242
  import { randomUUID } from "crypto";
36889
37243
  var RESTART_CONFIRM_MAX_AGE_MS = 10 * 60 * 1e3;
@@ -36903,13 +37257,13 @@ function writeRestartConfirmMarker(filePath, marker) {
36903
37257
  const dir = dirname(filePath);
36904
37258
  if (!existsSync6(dir)) mkdirSync2(dir, { recursive: true, mode: 448 });
36905
37259
  const tmpPath = `${filePath}.${process.pid}.${randomUUID()}.tmp`;
36906
- writeFileSync3(tmpPath, JSON.stringify(marker) + "\n", { encoding: "utf8", mode: 384 });
37260
+ writeFileSync4(tmpPath, JSON.stringify(marker) + "\n", { encoding: "utf8", mode: 384 });
36907
37261
  renameSync(tmpPath, filePath);
36908
37262
  }
36909
37263
  function readRestartConfirmMarker(filePath) {
36910
37264
  try {
36911
37265
  if (!existsSync6(filePath)) return null;
36912
- const parsed = JSON.parse(readFileSync6(filePath, "utf8"));
37266
+ const parsed = JSON.parse(readFileSync8(filePath, "utf8"));
36913
37267
  if (!parsed || typeof parsed !== "object") return null;
36914
37268
  return parsed;
36915
37269
  } catch {
@@ -37054,21 +37408,21 @@ import {
37054
37408
  ftruncateSync,
37055
37409
  mkdirSync as mkdirSync9,
37056
37410
  openSync,
37057
- readFileSync as readFileSync18,
37058
- readdirSync as readdirSync5,
37411
+ readFileSync as readFileSync20,
37412
+ readdirSync as readdirSync6,
37059
37413
  renameSync as renameSync5,
37060
- statSync as statSync3,
37414
+ statSync as statSync4,
37061
37415
  unlinkSync as unlinkSync7,
37062
37416
  watch,
37063
- writeFileSync as writeFileSync13,
37417
+ writeFileSync as writeFileSync14,
37064
37418
  writeSync
37065
37419
  } from "fs";
37066
- import { basename, join as join18, resolve as resolve2 } from "path";
37067
- import { homedir as homedir6 } from "os";
37068
- import { createHash as createHash2, randomUUID as randomUUID2 } from "crypto";
37420
+ import { basename, join as join20, resolve as resolve2 } from "path";
37421
+ import { homedir as homedir7 } from "os";
37422
+ import { createHash as createHash3, randomUUID as randomUUID2 } from "crypto";
37069
37423
 
37070
37424
  // src/slack-thread-store.ts
37071
- import { mkdirSync as mkdirSync3, readFileSync as readFileSync7, writeFileSync as writeFileSync4 } from "fs";
37425
+ import { mkdirSync as mkdirSync3, readFileSync as readFileSync9, writeFileSync as writeFileSync5 } from "fs";
37072
37426
  import { dirname as dirname2 } from "path";
37073
37427
  function isParticipatingThread(entry) {
37074
37428
  if (!entry) return false;
@@ -37083,7 +37437,7 @@ function loadThreadStore(filePath, opts = {}) {
37083
37437
  const ttlMs = ttlDays * 24 * 60 * 60 * 1e3;
37084
37438
  let raw;
37085
37439
  try {
37086
- raw = readFileSync7(filePath, "utf-8");
37440
+ raw = readFileSync9(filePath, "utf-8");
37087
37441
  } catch {
37088
37442
  return { threads: /* @__PURE__ */ new Map(), pruned: 0 };
37089
37443
  }
@@ -37132,7 +37486,7 @@ function createThreadPersister(opts) {
37132
37486
  const writeNow = (snap) => {
37133
37487
  try {
37134
37488
  mkdirSync3(dirname2(opts.filePath), { recursive: true });
37135
- writeFileSync4(opts.filePath, serializeThreadStore(snap), "utf-8");
37489
+ writeFileSync5(opts.filePath, serializeThreadStore(snap), "utf-8");
37136
37490
  lastWriteAt = Date.now();
37137
37491
  } catch (err) {
37138
37492
  opts.onError?.(
@@ -37184,7 +37538,7 @@ function isThreadEntry(value) {
37184
37538
  }
37185
37539
 
37186
37540
  // src/dm-restart-notice.ts
37187
- import { mkdirSync as mkdirSync4, readFileSync as readFileSync8, unlinkSync as unlinkSync4, writeFileSync as writeFileSync5 } from "fs";
37541
+ import { mkdirSync as mkdirSync4, readFileSync as readFileSync10, unlinkSync as unlinkSync4, writeFileSync as writeFileSync6 } from "fs";
37188
37542
  import { dirname as dirname3 } from "path";
37189
37543
  var RECENT_DM_VERSION = 1;
37190
37544
  var DEFAULT_RECENT_DM_TTL_MS = 30 * 60 * 1e3;
@@ -37208,7 +37562,7 @@ function loadRecentDms(filePath, opts = {}) {
37208
37562
  const ttlMs = opts.ttlMs ?? DEFAULT_RECENT_DM_TTL_MS;
37209
37563
  let raw;
37210
37564
  try {
37211
- raw = readFileSync8(filePath, "utf-8");
37565
+ raw = readFileSync10(filePath, "utf-8");
37212
37566
  } catch (err) {
37213
37567
  const code = err.code;
37214
37568
  if (code !== "ENOENT") {
@@ -37248,7 +37602,7 @@ function createRecentDmPersister(opts) {
37248
37602
  const writeNow = (snap) => {
37249
37603
  try {
37250
37604
  mkdirSync4(dirname3(opts.filePath), { recursive: true });
37251
- writeFileSync5(opts.filePath, serializeRecentDms(snap), "utf-8");
37605
+ writeFileSync6(opts.filePath, serializeRecentDms(snap), "utf-8");
37252
37606
  lastWriteAt = Date.now();
37253
37607
  } catch (err) {
37254
37608
  opts.onError?.(`dm-restart-notice: failed to persist recent-DMs: ${err.message}`);
@@ -37293,7 +37647,7 @@ var CHANNEL_ADD_RESTART_MAX_AGE_MS = 15 * 60 * 1e3;
37293
37647
  function readChannelAddRestartMarker(filePath) {
37294
37648
  let raw;
37295
37649
  try {
37296
- raw = readFileSync8(filePath, "utf-8");
37650
+ raw = readFileSync10(filePath, "utf-8");
37297
37651
  } catch {
37298
37652
  return null;
37299
37653
  }
@@ -37351,13 +37705,13 @@ async function runOrRetry(fn, opts) {
37351
37705
  }
37352
37706
 
37353
37707
  // src/turn-initiator-marker.ts
37354
- import { writeFileSync as writeFileSync6, readFileSync as readFileSync9, mkdirSync as mkdirSync5, renameSync as renameSync2 } from "fs";
37355
- import { dirname as dirname4, join as join10 } from "path";
37708
+ import { writeFileSync as writeFileSync7, readFileSync as readFileSync11, mkdirSync as mkdirSync5, renameSync as renameSync2 } from "fs";
37709
+ import { dirname as dirname4, join as join12 } from "path";
37356
37710
  var TURN_INITIATOR_MAX_AGE_MS = 5 * 60 * 1e3;
37357
37711
  var TURN_INITIATOR_LEDGER_MAX_ENTRIES = 20;
37358
37712
  var TURN_INITIATOR_LEDGER_FILENAME = ".turn-initiator-ledger.json";
37359
37713
  function turnInitiatorLedgerPath(singleSlotFile) {
37360
- return join10(dirname4(singleSlotFile), TURN_INITIATOR_LEDGER_FILENAME);
37714
+ return join12(dirname4(singleSlotFile), TURN_INITIATOR_LEDGER_FILENAME);
37361
37715
  }
37362
37716
  function foldTurnInitiatorLedger(existing, marker, maxAgeMs = TURN_INITIATOR_MAX_AGE_MS, maxEntries = TURN_INITIATOR_LEDGER_MAX_ENTRIES) {
37363
37717
  const now = marker.ts;
@@ -37382,13 +37736,13 @@ function updateTurnInitiatorLedger(singleSlotFile, marker) {
37382
37736
  const ledgerFile = turnInitiatorLedgerPath(singleSlotFile);
37383
37737
  let existing = null;
37384
37738
  try {
37385
- const parsed = JSON.parse(readFileSync9(ledgerFile, "utf8"));
37739
+ const parsed = JSON.parse(readFileSync11(ledgerFile, "utf8"));
37386
37740
  if (parsed && parsed.v === 1 && Array.isArray(parsed.entries)) existing = parsed;
37387
37741
  } catch {
37388
37742
  }
37389
37743
  const next = foldTurnInitiatorLedger(existing, marker);
37390
37744
  const tmp = `${ledgerFile}.tmp`;
37391
- writeFileSync6(tmp, JSON.stringify(next), "utf8");
37745
+ writeFileSync7(tmp, JSON.stringify(next), "utf8");
37392
37746
  renameSync2(tmp, ledgerFile);
37393
37747
  }
37394
37748
  function writeTurnInitiatorMarker(input) {
@@ -37398,7 +37752,7 @@ function writeTurnInitiatorMarker(input) {
37398
37752
  mkdirSync5(dirname4(file), { recursive: true });
37399
37753
  const marker = { ...input, ts: Date.now() };
37400
37754
  const tmp = `${file}.tmp`;
37401
- writeFileSync6(tmp, JSON.stringify(marker), "utf8");
37755
+ writeFileSync7(tmp, JSON.stringify(marker), "utf8");
37402
37756
  renameSync2(tmp, file);
37403
37757
  try {
37404
37758
  updateTurnInitiatorLedger(file, marker);
@@ -37409,7 +37763,7 @@ function writeTurnInitiatorMarker(input) {
37409
37763
  }
37410
37764
 
37411
37765
  // src/slack-bot-photo.ts
37412
- import { existsSync as existsSync7, mkdirSync as mkdirSync6, readFileSync as readFileSync10, writeFileSync as writeFileSync7 } from "fs";
37766
+ import { existsSync as existsSync7, mkdirSync as mkdirSync6, readFileSync as readFileSync12, writeFileSync as writeFileSync8 } from "fs";
37413
37767
  import { dirname as dirname5 } from "path";
37414
37768
  async function applyBotPhoto(opts) {
37415
37769
  const fetchImpl = opts.fetchImpl ?? fetch;
@@ -37419,7 +37773,7 @@ async function applyBotPhoto(opts) {
37419
37773
  const { token, avatarUrl, markerPath } = opts;
37420
37774
  if (markerPath && existsSync7(markerPath)) {
37421
37775
  try {
37422
- if (readFileSync10(markerPath, "utf-8").trim() === avatarUrl) {
37776
+ if (readFileSync12(markerPath, "utf-8").trim() === avatarUrl) {
37423
37777
  return { status: "skipped-unchanged" };
37424
37778
  }
37425
37779
  } catch {
@@ -37461,7 +37815,7 @@ async function applyBotPhoto(opts) {
37461
37815
  if (markerPath) {
37462
37816
  try {
37463
37817
  mkdirSync6(dirname5(markerPath), { recursive: true, mode: 448 });
37464
- writeFileSync7(markerPath, avatarUrl, { mode: 384 });
37818
+ writeFileSync8(markerPath, avatarUrl, { mode: 384 });
37465
37819
  } catch {
37466
37820
  }
37467
37821
  }
@@ -37544,8 +37898,8 @@ function conversationalLaneMeta(expectsReply = true) {
37544
37898
  }
37545
37899
 
37546
37900
  // src/inbound-lane-telemetry.ts
37547
- import { readFileSync as readFileSync11, writeFileSync as writeFileSync8 } from "fs";
37548
- import { join as join11 } from "path";
37901
+ import { readFileSync as readFileSync13, writeFileSync as writeFileSync9 } from "fs";
37902
+ import { join as join13 } from "path";
37549
37903
  var LANE_CLASSIFICATION_COUNTER_SUFFIX = "-lane-classifications.json";
37550
37904
  var SUSPECTED_MISCLASSIFICATION_KEY = "suspected_misclassification";
37551
37905
  var HUMAN_CHANNEL_SOURCES = /* @__PURE__ */ new Set([
@@ -37562,10 +37916,10 @@ function isSuspectedMisclassification(lane, source) {
37562
37916
  }
37563
37917
  function recordLaneClassification(agentDir, channel, classification) {
37564
37918
  if (!agentDir) return;
37565
- const path = join11(agentDir, `${channel}${LANE_CLASSIFICATION_COUNTER_SUFFIX}`);
37919
+ const path = join13(agentDir, `${channel}${LANE_CLASSIFICATION_COUNTER_SUFFIX}`);
37566
37920
  let counts = {};
37567
37921
  try {
37568
- const parsed = JSON.parse(readFileSync11(path, "utf-8"));
37922
+ const parsed = JSON.parse(readFileSync13(path, "utf-8"));
37569
37923
  if (parsed && typeof parsed === "object") counts = parsed;
37570
37924
  } catch {
37571
37925
  }
@@ -37575,14 +37929,14 @@ function recordLaneClassification(agentDir, channel, classification) {
37575
37929
  counts[SUSPECTED_MISCLASSIFICATION_KEY] = (counts[SUSPECTED_MISCLASSIFICATION_KEY] ?? 0) + 1;
37576
37930
  }
37577
37931
  try {
37578
- writeFileSync8(path, JSON.stringify(counts), { mode: 384 });
37932
+ writeFileSync9(path, JSON.stringify(counts), { mode: 384 });
37579
37933
  } catch {
37580
37934
  }
37581
37935
  }
37582
37936
 
37583
37937
  // src/slack-inbound-registry.ts
37584
- import { readdirSync as readdirSync3, readFileSync as readFileSync12 } from "fs";
37585
- import { join as join12 } from "path";
37938
+ import { readdirSync as readdirSync4, readFileSync as readFileSync14 } from "fs";
37939
+ import { join as join14 } from "path";
37586
37940
  var DEFAULT_MAX_ENTRIES = 500;
37587
37941
  var DEFAULT_CLEARED_TTL_MS = 6 * 60 * 60 * 1e3;
37588
37942
  function entryKey(channel, messageTs) {
@@ -37694,7 +38048,7 @@ function createInboundRegistry(opts = {}) {
37694
38048
  function seedFromMarkerDir(dir) {
37695
38049
  let names;
37696
38050
  try {
37697
- names = readdirSync3(dir);
38051
+ names = readdirSync4(dir);
37698
38052
  } catch {
37699
38053
  return;
37700
38054
  }
@@ -37703,7 +38057,7 @@ function createInboundRegistry(opts = {}) {
37703
38057
  if (name.includes(".retry-") || name.includes(".poison")) continue;
37704
38058
  let marker;
37705
38059
  try {
37706
- marker = JSON.parse(readFileSync12(join12(dir, name), "utf-8"));
38060
+ marker = JSON.parse(readFileSync14(join14(dir, name), "utf-8"));
37707
38061
  } catch {
37708
38062
  continue;
37709
38063
  }
@@ -37740,25 +38094,25 @@ function createInboundRegistry(opts = {}) {
37740
38094
  }
37741
38095
 
37742
38096
  // src/slack-inbound-id.ts
37743
- import { createHash } from "crypto";
38097
+ import { createHash as createHash2 } from "crypto";
37744
38098
  var INBOUND_ID_HEX_LEN = 12;
37745
38099
  function slackInboundId(channel, threadTs, messageTs) {
37746
- const digest = createHash("sha256").update(`${channel}|${threadTs}|${messageTs}`).digest("hex").slice(0, INBOUND_ID_HEX_LEN);
38100
+ const digest = createHash2("sha256").update(`${channel}|${threadTs}|${messageTs}`).digest("hex").slice(0, INBOUND_ID_HEX_LEN);
37747
38101
  return `ib_${digest}`;
37748
38102
  }
37749
38103
 
37750
38104
  // src/inbound-delivery-ledger.ts
37751
- import { existsSync as existsSync8, mkdirSync as mkdirSync7, readdirSync as readdirSync4, readFileSync as readFileSync13, renameSync as renameSync3, writeFileSync as writeFileSync9 } from "fs";
37752
- import { join as join13 } from "path";
38105
+ import { existsSync as existsSync8, mkdirSync as mkdirSync7, readdirSync as readdirSync5, readFileSync as readFileSync15, renameSync as renameSync3, writeFileSync as writeFileSync10 } from "fs";
38106
+ import { join as join15 } from "path";
37753
38107
  function safeInboundId(inboundId) {
37754
38108
  return inboundId.replace(/[^A-Za-z0-9_-]/g, "_");
37755
38109
  }
37756
38110
  var defaultDeps = {
37757
38111
  mkdir: (dir) => mkdirSync7(dir, { recursive: true }),
37758
- writeFile: (path, data) => writeFileSync9(path, data, "utf8"),
38112
+ writeFile: (path, data) => writeFileSync10(path, data, "utf8"),
37759
38113
  rename: (from, to) => renameSync3(from, to),
37760
- readdir: (dir) => readdirSync4(dir),
37761
- readFile: (path) => readFileSync13(path, "utf8"),
38114
+ readdir: (dir) => readdirSync5(dir),
38115
+ readFile: (path) => readFileSync15(path, "utf8"),
37762
38116
  exists: (path) => existsSync8(path)
37763
38117
  };
37764
38118
  function writeInboundDeliveryLedgerEntry(dir, record2, deps = defaultDeps) {
@@ -37767,7 +38121,7 @@ function writeInboundDeliveryLedgerEntry(dir, record2, deps = defaultDeps) {
37767
38121
  if (!safe || safe.includes("/") || safe.includes("\\") || safe.includes("..")) return;
37768
38122
  try {
37769
38123
  deps.mkdir(dir);
37770
- const final = join13(dir, `${safe}.json`);
38124
+ const final = join15(dir, `${safe}.json`);
37771
38125
  const tmp = `${final}.tmp`;
37772
38126
  deps.writeFile(tmp, JSON.stringify(record2));
37773
38127
  deps.rename(tmp, final);
@@ -37923,8 +38277,8 @@ function describeChannelRedirect(input) {
37923
38277
  }
37924
38278
 
37925
38279
  // src/slack-reply-binding-telemetry.ts
37926
- import { readFileSync as readFileSync14, writeFileSync as writeFileSync10 } from "fs";
37927
- import { join as join14 } from "path";
38280
+ import { readFileSync as readFileSync16, writeFileSync as writeFileSync11 } from "fs";
38281
+ import { join as join16 } from "path";
37928
38282
  var REPLY_BINDING_CLASSIFICATION_COUNTER_SUFFIX = "-reply-binding-classifications.json";
37929
38283
  var UNKNOWN_INBOUND_ID_KEY = "unknown_inbound_id";
37930
38284
  var CHANNEL_MISTARGET_CORRECTED_KEY = "channel_mistarget_corrected";
@@ -37939,10 +38293,10 @@ function slackReplyBindingMode() {
37939
38293
  }
37940
38294
  function recordReplyBindingClassification(agentDir, channel, input) {
37941
38295
  if (!agentDir) return;
37942
- const path = join14(agentDir, `${channel}${REPLY_BINDING_CLASSIFICATION_COUNTER_SUFFIX}`);
38296
+ const path = join16(agentDir, `${channel}${REPLY_BINDING_CLASSIFICATION_COUNTER_SUFFIX}`);
37943
38297
  let counts = {};
37944
38298
  try {
37945
- const parsed = JSON.parse(readFileSync14(path, "utf-8"));
38299
+ const parsed = JSON.parse(readFileSync16(path, "utf-8"));
37946
38300
  if (parsed && typeof parsed === "object") counts = parsed;
37947
38301
  } catch {
37948
38302
  }
@@ -37951,32 +38305,32 @@ function recordReplyBindingClassification(agentDir, channel, input) {
37951
38305
  counts[UNKNOWN_INBOUND_ID_KEY] = (counts[UNKNOWN_INBOUND_ID_KEY] ?? 0) + 1;
37952
38306
  }
37953
38307
  try {
37954
- writeFileSync10(path, JSON.stringify(counts), { mode: 384 });
38308
+ writeFileSync11(path, JSON.stringify(counts), { mode: 384 });
37955
38309
  } catch {
37956
38310
  }
37957
38311
  }
37958
38312
  function recordScheduledChannelOverride(agentDir, channel, input) {
37959
38313
  if (!agentDir) return;
37960
- const path = join14(agentDir, `${channel}${REPLY_BINDING_CLASSIFICATION_COUNTER_SUFFIX}`);
38314
+ const path = join16(agentDir, `${channel}${REPLY_BINDING_CLASSIFICATION_COUNTER_SUFFIX}`);
37961
38315
  let counts = {};
37962
38316
  try {
37963
- const parsed = JSON.parse(readFileSync14(path, "utf-8"));
38317
+ const parsed = JSON.parse(readFileSync16(path, "utf-8"));
37964
38318
  if (parsed && typeof parsed === "object") counts = parsed;
37965
38319
  } catch {
37966
38320
  }
37967
38321
  const key2 = input.enforced ? SCHEDULED_CHANNEL_OVERRIDE_BLOCKED_KEY : SCHEDULED_CHANNEL_OVERRIDE_SHADOW_KEY;
37968
38322
  counts[key2] = (counts[key2] ?? 0) + 1;
37969
38323
  try {
37970
- writeFileSync10(path, JSON.stringify(counts), { mode: 384 });
38324
+ writeFileSync11(path, JSON.stringify(counts), { mode: 384 });
37971
38325
  } catch {
37972
38326
  }
37973
38327
  }
37974
38328
  function recordChannelMistarget(agentDir, channel, input) {
37975
38329
  if (!agentDir) return;
37976
- const path = join14(agentDir, `${channel}${REPLY_BINDING_CLASSIFICATION_COUNTER_SUFFIX}`);
38330
+ const path = join16(agentDir, `${channel}${REPLY_BINDING_CLASSIFICATION_COUNTER_SUFFIX}`);
37977
38331
  let counts = {};
37978
38332
  try {
37979
- const parsed = JSON.parse(readFileSync14(path, "utf-8"));
38333
+ const parsed = JSON.parse(readFileSync16(path, "utf-8"));
37980
38334
  if (parsed && typeof parsed === "object") counts = parsed;
37981
38335
  } catch {
37982
38336
  }
@@ -37985,14 +38339,14 @@ function recordChannelMistarget(agentDir, channel, input) {
37985
38339
  counts[DM_CHANNEL_MISTARGET_KEY] = (counts[DM_CHANNEL_MISTARGET_KEY] ?? 0) + 1;
37986
38340
  }
37987
38341
  try {
37988
- writeFileSync10(path, JSON.stringify(counts), { mode: 384 });
38342
+ writeFileSync11(path, JSON.stringify(counts), { mode: 384 });
37989
38343
  } catch {
37990
38344
  }
37991
38345
  }
37992
38346
 
37993
38347
  // src/slack-reply-target-telemetry.ts
37994
- import { readFileSync as readFileSync15, writeFileSync as writeFileSync11 } from "fs";
37995
- import { join as join15 } from "path";
38348
+ import { readFileSync as readFileSync17, writeFileSync as writeFileSync12 } from "fs";
38349
+ import { join as join17 } from "path";
37996
38350
  var REPLY_TARGET_CLASSIFICATION_COUNTER_SUFFIX = "-reply-target-classifications.json";
37997
38351
  function pendingThreadsBucket(n) {
37998
38352
  if (n <= 0) return "0";
@@ -38025,10 +38379,10 @@ function classifyReplyTarget(input) {
38025
38379
  }
38026
38380
  function recordReplyTargetClassification(agentDir, channel, classification) {
38027
38381
  if (!agentDir) return;
38028
- const path = join15(agentDir, `${channel}${REPLY_TARGET_CLASSIFICATION_COUNTER_SUFFIX}`);
38382
+ const path = join17(agentDir, `${channel}${REPLY_TARGET_CLASSIFICATION_COUNTER_SUFFIX}`);
38029
38383
  let counts = {};
38030
38384
  try {
38031
- const parsed = JSON.parse(readFileSync15(path, "utf-8"));
38385
+ const parsed = JSON.parse(readFileSync17(path, "utf-8"));
38032
38386
  if (parsed && typeof parsed === "object") counts = parsed;
38033
38387
  } catch {
38034
38388
  }
@@ -38038,14 +38392,14 @@ function recordReplyTargetClassification(agentDir, channel, classification) {
38038
38392
  );
38039
38393
  counts[key2] = (counts[key2] ?? 0) + 1;
38040
38394
  try {
38041
- writeFileSync11(path, JSON.stringify(counts), { mode: 384 });
38395
+ writeFileSync12(path, JSON.stringify(counts), { mode: 384 });
38042
38396
  } catch {
38043
38397
  }
38044
38398
  }
38045
38399
 
38046
38400
  // src/scheduled-turn-marker.ts
38047
- import { readFileSync as readFileSync16, unlinkSync as unlinkSync5 } from "fs";
38048
- import { join as join16 } from "path";
38401
+ import { readFileSync as readFileSync18, unlinkSync as unlinkSync5 } from "fs";
38402
+ import { join as join18 } from "path";
38049
38403
  var SCHEDULED_TURN_MARKER_FILENAME2 = ".current-scheduled-turn.json";
38050
38404
  var SCHEDULED_TURN_MAX_AGE_MS = 15 * 60 * 1e3;
38051
38405
  function validateScheduledTurnMarker(raw, now, maxAgeMs = SCHEDULED_TURN_MAX_AGE_MS) {
@@ -38083,7 +38437,7 @@ function readScheduledTurnMarker(agentDir, now = Date.now()) {
38083
38437
  if (!agentDir) return null;
38084
38438
  try {
38085
38439
  const raw = JSON.parse(
38086
- readFileSync16(join16(agentDir, SCHEDULED_TURN_MARKER_FILENAME2), "utf8")
38440
+ readFileSync18(join18(agentDir, SCHEDULED_TURN_MARKER_FILENAME2), "utf8")
38087
38441
  );
38088
38442
  return validateScheduledTurnMarker(raw, now);
38089
38443
  } catch {
@@ -38093,7 +38447,7 @@ function readScheduledTurnMarker(agentDir, now = Date.now()) {
38093
38447
  function clearScheduledTurnMarker(agentDir) {
38094
38448
  if (!agentDir) return;
38095
38449
  try {
38096
- unlinkSync5(join16(agentDir, SCHEDULED_TURN_MARKER_FILENAME2));
38450
+ unlinkSync5(join18(agentDir, SCHEDULED_TURN_MARKER_FILENAME2));
38097
38451
  } catch {
38098
38452
  }
38099
38453
  }
@@ -38891,14 +39245,14 @@ async function actuateHostRestart(opts) {
38891
39245
  import {
38892
39246
  existsSync as existsSync9,
38893
39247
  mkdirSync as mkdirSync8,
38894
- readFileSync as readFileSync17,
39248
+ readFileSync as readFileSync19,
38895
39249
  renameSync as renameSync4,
38896
- statSync as statSync2,
39250
+ statSync as statSync3,
38897
39251
  unlinkSync as unlinkSync6,
38898
39252
  utimesSync,
38899
- writeFileSync as writeFileSync12
39253
+ writeFileSync as writeFileSync13
38900
39254
  } from "fs";
38901
- import { join as join17 } from "path";
39255
+ import { join as join19 } from "path";
38902
39256
  var STALE_LOCK_MS = 9e4;
38903
39257
  var HEARTBEAT_INTERVAL_MS = 3e4;
38904
39258
  function defaultIsPidAlive(pid) {
@@ -38921,7 +39275,7 @@ function acquireMcpSpawnLock(args) {
38921
39275
  const nowMs = options.nowMs ?? (() => Date.now());
38922
39276
  const lockMtimeMs = options.lockMtimeMs ?? defaultLockMtimeMs;
38923
39277
  const staleMs = options.staleMs ?? STALE_LOCK_MS;
38924
- const path = join17(agentDir, basename2);
39278
+ const path = join19(agentDir, basename2);
38925
39279
  const existing = readLockHolder(path);
38926
39280
  if (existing) {
38927
39281
  if (existing.pid === selfPid) {
@@ -38938,7 +39292,7 @@ function acquireMcpSpawnLock(args) {
38938
39292
  mkdirSync8(agentDir, { recursive: true, mode: 448 });
38939
39293
  const tmpPath = `${path}.${selfPid}.tmp`;
38940
39294
  const payload = { pid: selfPid, started_at: now() };
38941
- writeFileSync12(tmpPath, JSON.stringify(payload), { mode: 384 });
39295
+ writeFileSync13(tmpPath, JSON.stringify(payload), { mode: 384 });
38942
39296
  renameSync4(tmpPath, path);
38943
39297
  return { kind: "acquired", path };
38944
39298
  }
@@ -38980,7 +39334,7 @@ function startMcpSpawnLockHeartbeat(lockPath, opts = {}) {
38980
39334
  }
38981
39335
  function defaultLockMtimeMs(path) {
38982
39336
  try {
38983
- return statSync2(path).mtimeMs;
39337
+ return statSync3(path).mtimeMs;
38984
39338
  } catch {
38985
39339
  return null;
38986
39340
  }
@@ -38988,7 +39342,7 @@ function defaultLockMtimeMs(path) {
38988
39342
  function readLockHolder(path) {
38989
39343
  if (!existsSync9(path)) return null;
38990
39344
  try {
38991
- const raw = readFileSync17(path, "utf8");
39345
+ const raw = readFileSync19(path, "utf8");
38992
39346
  const parsed = JSON.parse(raw);
38993
39347
  const pid = typeof parsed.pid === "number" ? parsed.pid : Number(parsed.pid);
38994
39348
  if (!Number.isFinite(pid) || pid <= 0) return null;
@@ -39219,6 +39573,49 @@ async function maybeSendUsageLimitNotice(args) {
39219
39573
  clearTimeout(timeoutId);
39220
39574
  }
39221
39575
  }
39576
+ function armSlackUsageLimitWatch(args) {
39577
+ void (async () => {
39578
+ try {
39579
+ const refusal = await watchForRateLimitRefusal({ sinceMs: args.sinceMs });
39580
+ const action = decideRefusalAction({ mode: args.mode, refusal });
39581
+ if (action === "none") return;
39582
+ if (action === "missing-reset") {
39583
+ process.stderr.write(
39584
+ `slack-channel(${AGENT_CODE_NAME}): [usage-limit-reactive] mode=${args.mode} refusal detected for channel=${redactSlackId(args.channel)} but no reset time in it (${describeUnparsedRefusal(refusal?.text)}) - no notice
39585
+ `
39586
+ );
39587
+ return;
39588
+ }
39589
+ const resetsAt = refusal?.resetsAt;
39590
+ if (!resetsAt) return;
39591
+ if (action === "shadow-log") {
39592
+ process.stderr.write(
39593
+ `slack-channel(${AGENT_CODE_NAME}): [usage-limit-reactive] mode=shadow WOULD notify channel=${redactSlackId(args.channel)} ts=${redactSlackId(args.messageTs)} resets=${resetsAt.toISOString()}
39594
+ `
39595
+ );
39596
+ return;
39597
+ }
39598
+ await maybeSendUsageLimitNotice({
39599
+ channel: args.channel,
39600
+ senderId: args.senderId,
39601
+ threadTs: args.threadTs,
39602
+ limitedUntil: resetsAt
39603
+ });
39604
+ if (args.channel && args.messageTs) {
39605
+ clearSlackPendingMarkerByMessageTs2(args.channel, args.messageTs);
39606
+ }
39607
+ process.stderr.write(
39608
+ `slack-channel(${AGENT_CODE_NAME}): [usage-limit-reactive] reported refusal for channel=${redactSlackId(args.channel)} ts=${redactSlackId(args.messageTs)} resets=${resetsAt.toISOString()}
39609
+ `
39610
+ );
39611
+ } catch (err) {
39612
+ process.stderr.write(
39613
+ `slack-channel(${AGENT_CODE_NAME}): [usage-limit-reactive] watch failed for channel=${redactSlackId(args.channel)}: ${err.message}
39614
+ `
39615
+ );
39616
+ }
39617
+ })();
39618
+ }
39222
39619
  var SLACK_ACCOUNT_MUTE_NOTICE_CACHE = /* @__PURE__ */ new Map();
39223
39620
  async function maybeSendAccountMuteNotice(args) {
39224
39621
  if (!BOT_TOKEN) return;
@@ -39394,18 +39791,18 @@ var SLACK_TEAM_PEER_USER_IDS = parseTeamPeerUserIdsEnv(
39394
39791
  process.env.SLACK_TEAM_PEER_USER_IDS
39395
39792
  );
39396
39793
  var PEER_HINT_SEEN = /* @__PURE__ */ new Set();
39397
- var SLACK_AGENT_DIR = AGENT_CODE_NAME ? join18(homedir6(), ".augmented", AGENT_CODE_NAME) : null;
39398
- var SLACK_MCP_CONFIG_PATH = SLACK_AGENT_DIR ? join18(SLACK_AGENT_DIR, "project", ".mcp.json") : null;
39794
+ var SLACK_AGENT_DIR = AGENT_CODE_NAME ? join20(homedir7(), ".augmented", AGENT_CODE_NAME) : null;
39795
+ var SLACK_MCP_CONFIG_PATH = SLACK_AGENT_DIR ? join20(SLACK_AGENT_DIR, "project", ".mcp.json") : null;
39399
39796
  var liveAllowedUsersCache = null;
39400
39797
  function readLiveAllowedUsers() {
39401
39798
  if (!SLACK_MCP_CONFIG_PATH) return null;
39402
39799
  try {
39403
- const mtimeMs = statSync3(SLACK_MCP_CONFIG_PATH).mtimeMs;
39800
+ const mtimeMs = statSync4(SLACK_MCP_CONFIG_PATH).mtimeMs;
39404
39801
  if (liveAllowedUsersCache && liveAllowedUsersCache.mtimeMs === mtimeMs) {
39405
39802
  return liveAllowedUsersCache.value;
39406
39803
  }
39407
39804
  const value = extractAllowedUsersFromMcpJson(
39408
- readFileSync18(SLACK_MCP_CONFIG_PATH, "utf-8")
39805
+ readFileSync20(SLACK_MCP_CONFIG_PATH, "utf-8")
39409
39806
  );
39410
39807
  if (value === null) return null;
39411
39808
  liveAllowedUsersCache = { mtimeMs, value };
@@ -39421,12 +39818,12 @@ var livePingAllowedUsersCache = null;
39421
39818
  function readLivePingAllowedUsers() {
39422
39819
  if (!SLACK_MCP_CONFIG_PATH) return null;
39423
39820
  try {
39424
- const mtimeMs = statSync3(SLACK_MCP_CONFIG_PATH).mtimeMs;
39821
+ const mtimeMs = statSync4(SLACK_MCP_CONFIG_PATH).mtimeMs;
39425
39822
  if (livePingAllowedUsersCache && livePingAllowedUsersCache.mtimeMs === mtimeMs) {
39426
39823
  return livePingAllowedUsersCache.value;
39427
39824
  }
39428
39825
  const value = extractPingAllowedUsersFromMcpJson(
39429
- readFileSync18(SLACK_MCP_CONFIG_PATH, "utf-8")
39826
+ readFileSync20(SLACK_MCP_CONFIG_PATH, "utf-8")
39430
39827
  );
39431
39828
  if (value === null) return null;
39432
39829
  livePingAllowedUsersCache = { mtimeMs, value };
@@ -39438,20 +39835,20 @@ function readLivePingAllowedUsers() {
39438
39835
  function getEffectivePingAllowedUsers() {
39439
39836
  return readLivePingAllowedUsers() ?? PING_ALLOWED_USERS;
39440
39837
  }
39441
- var SLACK_PENDING_INBOUND_DIR = SLACK_AGENT_DIR ? join18(SLACK_AGENT_DIR, "slack-pending-inbound") : null;
39442
- var SLACK_RESTART_CONTEXT_DIR = SLACK_AGENT_DIR ? join18(SLACK_AGENT_DIR, "slack-restart-context") : null;
39443
- var SLACK_RECOVERY_OUTBOX_DIR = SLACK_AGENT_DIR ? join18(SLACK_AGENT_DIR, "slack-recovery-outbox") : null;
39444
- var SLACK_RECOVERY_LEDGER_DIR = SLACK_AGENT_DIR ? join18(SLACK_AGENT_DIR, ".agt-slack-recovery-ledger") : null;
39445
- var SLACK_DELIVERY_LEDGER_DIR = SLACK_AGENT_DIR ? join18(SLACK_AGENT_DIR, ".agt-inbound-delivery-ledger") : null;
39838
+ var SLACK_PENDING_INBOUND_DIR = SLACK_AGENT_DIR ? join20(SLACK_AGENT_DIR, "slack-pending-inbound") : null;
39839
+ var SLACK_RESTART_CONTEXT_DIR = SLACK_AGENT_DIR ? join20(SLACK_AGENT_DIR, "slack-restart-context") : null;
39840
+ var SLACK_RECOVERY_OUTBOX_DIR = SLACK_AGENT_DIR ? join20(SLACK_AGENT_DIR, "slack-recovery-outbox") : null;
39841
+ var SLACK_RECOVERY_LEDGER_DIR = SLACK_AGENT_DIR ? join20(SLACK_AGENT_DIR, ".agt-slack-recovery-ledger") : null;
39842
+ var SLACK_DELIVERY_LEDGER_DIR = SLACK_AGENT_DIR ? join20(SLACK_AGENT_DIR, ".agt-inbound-delivery-ledger") : null;
39446
39843
  var slackInboundRegistry = createInboundRegistry();
39447
- var SLACK_RESTART_CONFIRM_FILE = SLACK_AGENT_DIR ? join18(SLACK_AGENT_DIR, "slack-restart-confirm.json") : null;
39448
- var SLACK_RECENT_DMS_FILE = SLACK_AGENT_DIR ? join18(SLACK_AGENT_DIR, "slack-recent-dms.json") : null;
39449
- var SLACK_CHANNEL_ADD_RESTART_FILE = SLACK_AGENT_DIR ? join18(SLACK_AGENT_DIR, "slack-channel-add-restart.json") : null;
39844
+ var SLACK_RESTART_CONFIRM_FILE = SLACK_AGENT_DIR ? join20(SLACK_AGENT_DIR, "slack-restart-confirm.json") : null;
39845
+ var SLACK_RECENT_DMS_FILE = SLACK_AGENT_DIR ? join20(SLACK_AGENT_DIR, "slack-recent-dms.json") : null;
39846
+ var SLACK_CHANNEL_ADD_RESTART_FILE = SLACK_AGENT_DIR ? join20(SLACK_AGENT_DIR, "slack-channel-add-restart.json") : null;
39450
39847
  var SLACK_MAX_RECOVERY_ATTEMPTS = 3;
39451
- var SLACK_AVATAR_MARKER_PATH = SLACK_AGENT_DIR ? join18(SLACK_AGENT_DIR, "slack-avatar-applied") : null;
39848
+ var SLACK_AVATAR_MARKER_PATH = SLACK_AGENT_DIR ? join20(SLACK_AGENT_DIR, "slack-avatar-applied") : null;
39452
39849
  function redactSlackId(id) {
39453
39850
  if (!id) return "<none>";
39454
- return createHash2("sha256").update(id).digest("hex").slice(0, 8);
39851
+ return createHash3("sha256").update(id).digest("hex").slice(0, 8);
39455
39852
  }
39456
39853
  function safeSlackMarkerName(channel, threadTs, messageTs) {
39457
39854
  const safe = (s) => s.replace(/[^A-Za-z0-9_-]/g, "_");
@@ -39459,7 +39856,7 @@ function safeSlackMarkerName(channel, threadTs, messageTs) {
39459
39856
  }
39460
39857
  function slackPendingInboundPath(channel, threadTs, messageTs) {
39461
39858
  if (!SLACK_PENDING_INBOUND_DIR) return null;
39462
- return join18(SLACK_PENDING_INBOUND_DIR, safeSlackMarkerName(channel, threadTs, messageTs));
39859
+ return join20(SLACK_PENDING_INBOUND_DIR, safeSlackMarkerName(channel, threadTs, messageTs));
39463
39860
  }
39464
39861
  function writeSlackPendingInboundMarker(channel, threadTs, messageTs, undeliverable = false, discretionary = false, payload) {
39465
39862
  const path = slackPendingInboundPath(channel, threadTs, messageTs);
@@ -39482,7 +39879,7 @@ function writeSlackPendingInboundMarker(channel, threadTs, messageTs, undelivera
39482
39879
  };
39483
39880
  try {
39484
39881
  mkdirSync9(SLACK_PENDING_INBOUND_DIR, { recursive: true, mode: 448 });
39485
- writeFileSync13(path, JSON.stringify(marker), { mode: 384 });
39882
+ writeFileSync14(path, JSON.stringify(marker), { mode: 384 });
39486
39883
  } catch (err) {
39487
39884
  process.stderr.write(
39488
39885
  `slack-channel(${AGENT_CODE_NAME}): pending-inbound marker write failed: ${err.message}
@@ -39510,7 +39907,7 @@ function rewriteSlackMarkerInPlace(path, marker) {
39510
39907
  function markSlackMarkerSeenInPlace(fullPath) {
39511
39908
  let marker;
39512
39909
  try {
39513
- marker = JSON.parse(readFileSync18(fullPath, "utf-8"));
39910
+ marker = JSON.parse(readFileSync20(fullPath, "utf-8"));
39514
39911
  } catch {
39515
39912
  return;
39516
39913
  }
@@ -39524,7 +39921,7 @@ function attachSlackReplayPayload(channel, threadTs, messageTs, payload) {
39524
39921
  if (!path) return;
39525
39922
  let marker;
39526
39923
  try {
39527
- marker = JSON.parse(readFileSync18(path, "utf-8"));
39924
+ marker = JSON.parse(readFileSync20(path, "utf-8"));
39528
39925
  } catch {
39529
39926
  return;
39530
39927
  }
@@ -39535,7 +39932,7 @@ function readSlackPendingInboundMarker(channel, threadTs, messageTs) {
39535
39932
  const path = slackPendingInboundPath(channel, threadTs, messageTs);
39536
39933
  if (!path || !existsSync10(path)) return null;
39537
39934
  try {
39538
- return JSON.parse(readFileSync18(path, "utf-8"));
39935
+ return JSON.parse(readFileSync20(path, "utf-8"));
39539
39936
  } catch {
39540
39937
  return null;
39541
39938
  }
@@ -39651,7 +40048,7 @@ function scheduleBusyAck(channel, threadTs, messageTs, isThreadReply, arrivedWhi
39651
40048
  let paneLogFreshAgeMs = null;
39652
40049
  if (SLACK_AGENT_DIR) {
39653
40050
  try {
39654
- const paneMtimeMs = statSync3(join18(SLACK_AGENT_DIR, "pane.log")).mtimeMs;
40051
+ const paneMtimeMs = statSync4(join20(SLACK_AGENT_DIR, "pane.log")).mtimeMs;
39655
40052
  paneLogFreshAgeMs = Math.max(0, Date.now() - paneMtimeMs);
39656
40053
  } catch {
39657
40054
  }
@@ -39684,7 +40081,7 @@ function __resetSlackBusyAckNoticeThrottle() {
39684
40081
  function clearSlackMarkerFileWithHeal(fullPath) {
39685
40082
  let marker = null;
39686
40083
  try {
39687
- marker = JSON.parse(readFileSync18(fullPath, "utf-8"));
40084
+ marker = JSON.parse(readFileSync20(fullPath, "utf-8"));
39688
40085
  } catch {
39689
40086
  }
39690
40087
  if (marker && decideRecoveryHeal({
@@ -39702,7 +40099,7 @@ function clearSlackMarkerFileWithHeal(fullPath) {
39702
40099
  function markSlackMarkerSeenWithHeal(fullPath) {
39703
40100
  let marker = null;
39704
40101
  try {
39705
- marker = JSON.parse(readFileSync18(fullPath, "utf-8"));
40102
+ marker = JSON.parse(readFileSync20(fullPath, "utf-8"));
39706
40103
  } catch {
39707
40104
  return;
39708
40105
  }
@@ -39771,10 +40168,10 @@ function slackNextRetryName(filename) {
39771
40168
  async function processSlackRecoveryOutboxFile(filename) {
39772
40169
  if (!SLACK_RECOVERY_OUTBOX_DIR) return;
39773
40170
  if (filename.endsWith(".poison.json") || filename.endsWith(".tmp")) return;
39774
- const fullPath = join18(SLACK_RECOVERY_OUTBOX_DIR, filename);
40171
+ const fullPath = join20(SLACK_RECOVERY_OUTBOX_DIR, filename);
39775
40172
  let payload;
39776
40173
  try {
39777
- payload = JSON.parse(readFileSync18(fullPath, "utf-8"));
40174
+ payload = JSON.parse(readFileSync20(fullPath, "utf-8"));
39778
40175
  } catch (err) {
39779
40176
  process.stderr.write(
39780
40177
  `slack-channel(${AGENT_CODE_NAME}): recovery outbox parse failed (${filename}): ${err.message}
@@ -39878,7 +40275,7 @@ async function processSlackRecoveryOutboxFile(filename) {
39878
40275
  const next = slackNextRetryName(filename);
39879
40276
  if (next) {
39880
40277
  try {
39881
- renameSync5(fullPath, join18(SLACK_RECOVERY_OUTBOX_DIR, next.next));
40278
+ renameSync5(fullPath, join20(SLACK_RECOVERY_OUTBOX_DIR, next.next));
39882
40279
  if (next.attempt >= SLACK_MAX_RECOVERY_ATTEMPTS) {
39883
40280
  process.stderr.write(
39884
40281
  `slack-channel(${AGENT_CODE_NAME}): ghost-reply recovery exhausted retries \u2014 moved to ${next.next}
@@ -39909,7 +40306,7 @@ function scanSlackRecoveryRetries() {
39909
40306
  if (!SLACK_RECOVERY_OUTBOX_DIR) return;
39910
40307
  let entries;
39911
40308
  try {
39912
- entries = readdirSync5(SLACK_RECOVERY_OUTBOX_DIR);
40309
+ entries = readdirSync6(SLACK_RECOVERY_OUTBOX_DIR);
39913
40310
  } catch {
39914
40311
  return;
39915
40312
  }
@@ -39918,7 +40315,7 @@ function scanSlackRecoveryRetries() {
39918
40315
  if (!f.includes(".retry-") || f.endsWith(".poison.json")) continue;
39919
40316
  let mtimeMs;
39920
40317
  try {
39921
- mtimeMs = statSync3(join18(SLACK_RECOVERY_OUTBOX_DIR, f)).mtimeMs;
40318
+ mtimeMs = statSync4(join20(SLACK_RECOVERY_OUTBOX_DIR, f)).mtimeMs;
39922
40319
  } catch {
39923
40320
  continue;
39924
40321
  }
@@ -39939,7 +40336,7 @@ function startSlackRecoveryOutboxWatcher() {
39939
40336
  return;
39940
40337
  }
39941
40338
  try {
39942
- for (const f of readdirSync5(SLACK_RECOVERY_OUTBOX_DIR)) {
40339
+ for (const f of readdirSync6(SLACK_RECOVERY_OUTBOX_DIR)) {
39943
40340
  if (isFirstAttemptSlackOutboxFile(f)) void processSlackRecoveryOutboxFile(f);
39944
40341
  }
39945
40342
  } catch {
@@ -39948,7 +40345,7 @@ function startSlackRecoveryOutboxWatcher() {
39948
40345
  const watcher = watch(SLACK_RECOVERY_OUTBOX_DIR, (event, filename) => {
39949
40346
  if (event !== "rename" || !filename) return;
39950
40347
  if (!isFirstAttemptSlackOutboxFile(filename)) return;
39951
- if (existsSync10(join18(SLACK_RECOVERY_OUTBOX_DIR, filename))) {
40348
+ if (existsSync10(join20(SLACK_RECOVERY_OUTBOX_DIR, filename))) {
39952
40349
  void processSlackRecoveryOutboxFile(filename);
39953
40350
  }
39954
40351
  });
@@ -39963,7 +40360,7 @@ function startSlackRecoveryOutboxWatcher() {
39963
40360
  retryTimer.unref?.();
39964
40361
  }
39965
40362
  startSlackRecoveryOutboxWatcher();
39966
- var SLACK_NOTICE_OUTBOX_DIR = SLACK_AGENT_DIR ? join18(SLACK_AGENT_DIR, "slack-notice-outbox") : null;
40363
+ var SLACK_NOTICE_OUTBOX_DIR = SLACK_AGENT_DIR ? join20(SLACK_AGENT_DIR, "slack-notice-outbox") : null;
39967
40364
  var SLACK_NOTICE_MAX_AGE_MS = 9e4;
39968
40365
  var SLACK_NOTICE_INFLIGHT = /* @__PURE__ */ new Set();
39969
40366
  async function processSlackNoticeOutboxFile(filename) {
@@ -39971,11 +40368,11 @@ async function processSlackNoticeOutboxFile(filename) {
39971
40368
  if (filename.startsWith(".") || filename.endsWith(".tmp") || !filename.endsWith(".json")) return;
39972
40369
  if (SLACK_NOTICE_INFLIGHT.has(filename)) return;
39973
40370
  SLACK_NOTICE_INFLIGHT.add(filename);
39974
- const fullPath = join18(SLACK_NOTICE_OUTBOX_DIR, filename);
40371
+ const fullPath = join20(SLACK_NOTICE_OUTBOX_DIR, filename);
39975
40372
  try {
39976
40373
  let mtimeMs;
39977
40374
  try {
39978
- mtimeMs = statSync3(fullPath).mtimeMs;
40375
+ mtimeMs = statSync4(fullPath).mtimeMs;
39979
40376
  } catch {
39980
40377
  return;
39981
40378
  }
@@ -39988,7 +40385,7 @@ async function processSlackNoticeOutboxFile(filename) {
39988
40385
  }
39989
40386
  let payload;
39990
40387
  try {
39991
- const parsed = JSON.parse(readFileSync18(fullPath, "utf-8"));
40388
+ const parsed = JSON.parse(readFileSync20(fullPath, "utf-8"));
39992
40389
  if (!parsed || typeof parsed !== "object") throw new Error("not an object");
39993
40390
  payload = parsed;
39994
40391
  } catch {
@@ -40071,13 +40468,13 @@ function startSlackNoticeOutboxWatcher() {
40071
40468
  return;
40072
40469
  }
40073
40470
  try {
40074
- for (const f of readdirSync5(SLACK_NOTICE_OUTBOX_DIR)) void processSlackNoticeOutboxFile(f);
40471
+ for (const f of readdirSync6(SLACK_NOTICE_OUTBOX_DIR)) void processSlackNoticeOutboxFile(f);
40075
40472
  } catch {
40076
40473
  }
40077
40474
  try {
40078
40475
  const watcher = watch(SLACK_NOTICE_OUTBOX_DIR, (event, filename) => {
40079
40476
  if (event !== "rename" || !filename) return;
40080
- if (existsSync10(join18(SLACK_NOTICE_OUTBOX_DIR, filename))) {
40477
+ if (existsSync10(join20(SLACK_NOTICE_OUTBOX_DIR, filename))) {
40081
40478
  void processSlackNoticeOutboxFile(filename);
40082
40479
  }
40083
40480
  });
@@ -40100,7 +40497,7 @@ function sweepSlackStaleMarkers(thresholdMs) {
40100
40497
  if (!existsSync10(SLACK_PENDING_INBOUND_DIR)) return;
40101
40498
  let filenames;
40102
40499
  try {
40103
- filenames = readdirSync5(SLACK_PENDING_INBOUND_DIR);
40500
+ filenames = readdirSync6(SLACK_PENDING_INBOUND_DIR);
40104
40501
  } catch (err) {
40105
40502
  process.stderr.write(
40106
40503
  `slack-channel(${AGENT_CODE_NAME}): stale-marker readdir failed: ${err.message}
@@ -40114,10 +40511,10 @@ function sweepSlackStaleMarkers(thresholdMs) {
40114
40511
  for (const filename of filenames) {
40115
40512
  if (!filename.endsWith(".json")) continue;
40116
40513
  if (filename.endsWith(".tmp")) continue;
40117
- const fullPath = join18(SLACK_PENDING_INBOUND_DIR, filename);
40514
+ const fullPath = join20(SLACK_PENDING_INBOUND_DIR, filename);
40118
40515
  let marker;
40119
40516
  try {
40120
- marker = JSON.parse(readFileSync18(fullPath, "utf-8"));
40517
+ marker = JSON.parse(readFileSync20(fullPath, "utf-8"));
40121
40518
  } catch (err) {
40122
40519
  process.stderr.write(
40123
40520
  `slack-channel(${AGENT_CODE_NAME}): stale-marker parse failed for ${redactSlackId(filename)}: ${err.message}
@@ -40175,13 +40572,13 @@ var slackOrphanSweepTimer = setInterval(() => {
40175
40572
  checkSlackWatchdogGiveUpNotice();
40176
40573
  }, orphanSweepIntervalMs());
40177
40574
  slackOrphanSweepTimer.unref?.();
40178
- var SLACK_PROGRESS_HEARTBEAT_PATH = SLACK_AGENT_DIR ? join18(SLACK_AGENT_DIR, "channel-progress-heartbeat.json") : null;
40575
+ var SLACK_PROGRESS_HEARTBEAT_PATH = SLACK_AGENT_DIR ? join20(SLACK_AGENT_DIR, "channel-progress-heartbeat.json") : null;
40179
40576
  var slackTrackedProgress = null;
40180
40577
  var slackProgressTickRunning = false;
40181
40578
  function readSlackProgressHeartbeat() {
40182
40579
  if (!SLACK_PROGRESS_HEARTBEAT_PATH || !existsSync10(SLACK_PROGRESS_HEARTBEAT_PATH)) return null;
40183
40580
  try {
40184
- return parseProgressHeartbeat(readFileSync18(SLACK_PROGRESS_HEARTBEAT_PATH, "utf-8"));
40581
+ return parseProgressHeartbeat(readFileSync20(SLACK_PROGRESS_HEARTBEAT_PATH, "utf-8"));
40185
40582
  } catch {
40186
40583
  return null;
40187
40584
  }
@@ -40190,7 +40587,7 @@ function seedSlackProgressHeartbeat() {
40190
40587
  if (!SLACK_PROGRESS_HEARTBEAT_PATH) return;
40191
40588
  const tmp = `${SLACK_PROGRESS_HEARTBEAT_PATH}.${process.pid}.tmp`;
40192
40589
  try {
40193
- writeFileSync13(tmp, serializeProgressHeartbeat(SEED_PROGRESS_STEP, Date.now()), { mode: 384 });
40590
+ writeFileSync14(tmp, serializeProgressHeartbeat(SEED_PROGRESS_STEP, Date.now()), { mode: 384 });
40194
40591
  renameSync5(tmp, SLACK_PROGRESS_HEARTBEAT_PATH);
40195
40592
  } catch {
40196
40593
  try {
@@ -40204,11 +40601,11 @@ function findSlackProgressTarget() {
40204
40601
  let best = null;
40205
40602
  let bestMs = Infinity;
40206
40603
  try {
40207
- for (const name of readdirSync5(SLACK_PENDING_INBOUND_DIR)) {
40604
+ for (const name of readdirSync6(SLACK_PENDING_INBOUND_DIR)) {
40208
40605
  if (!name.endsWith(".json")) continue;
40209
40606
  let m;
40210
40607
  try {
40211
- m = JSON.parse(readFileSync18(join18(SLACK_PENDING_INBOUND_DIR, name), "utf-8"));
40608
+ m = JSON.parse(readFileSync20(join20(SLACK_PENDING_INBOUND_DIR, name), "utf-8"));
40212
40609
  } catch {
40213
40610
  continue;
40214
40611
  }
@@ -40355,11 +40752,11 @@ function listPendingSlackConversations() {
40355
40752
  if (!SLACK_PENDING_INBOUND_DIR || !existsSync10(SLACK_PENDING_INBOUND_DIR)) return [];
40356
40753
  const byKey = /* @__PURE__ */ new Map();
40357
40754
  try {
40358
- for (const name of readdirSync5(SLACK_PENDING_INBOUND_DIR)) {
40755
+ for (const name of readdirSync6(SLACK_PENDING_INBOUND_DIR)) {
40359
40756
  if (!name.endsWith(".json")) continue;
40360
40757
  try {
40361
40758
  const marker = JSON.parse(
40362
- readFileSync18(join18(SLACK_PENDING_INBOUND_DIR, name), "utf8")
40759
+ readFileSync20(join20(SLACK_PENDING_INBOUND_DIR, name), "utf8")
40363
40760
  );
40364
40761
  if (typeof marker.channel !== "string" || !marker.channel) continue;
40365
40762
  if (typeof marker.thread_ts !== "string" || !marker.thread_ts) continue;
@@ -40411,7 +40808,7 @@ function postSlackWatchdogGiveUpNotice(channel, threadTs, isThreadReply, reason)
40411
40808
  }
40412
40809
  function checkSlackWatchdogGiveUpNotice() {
40413
40810
  if (!SLACK_AGENT_DIR) return;
40414
- const signal = readGiveUpSignal(join18(SLACK_AGENT_DIR, GIVE_UP_SIGNAL_FILENAME));
40811
+ const signal = readGiveUpSignal(join20(SLACK_AGENT_DIR, GIVE_UP_SIGNAL_FILENAME));
40415
40812
  const signalAtMs = signal?.atMs ?? null;
40416
40813
  const act = decideGiveUpNotice({
40417
40814
  signalAtMs,
@@ -40443,7 +40840,7 @@ function readRestartTopicForMarker(filename, channel, threadTs) {
40443
40840
  if (!SLACK_RESTART_CONTEXT_DIR) return null;
40444
40841
  let raw;
40445
40842
  try {
40446
- raw = readFileSync18(join18(SLACK_RESTART_CONTEXT_DIR, filename), "utf-8");
40843
+ raw = readFileSync20(join20(SLACK_RESTART_CONTEXT_DIR, filename), "utf-8");
40447
40844
  } catch {
40448
40845
  return null;
40449
40846
  }
@@ -40452,7 +40849,7 @@ function readRestartTopicForMarker(filename, channel, threadTs) {
40452
40849
  function removeRestartContextHint(filename) {
40453
40850
  if (!SLACK_RESTART_CONTEXT_DIR) return;
40454
40851
  try {
40455
- unlinkSync7(join18(SLACK_RESTART_CONTEXT_DIR, filename));
40852
+ unlinkSync7(join20(SLACK_RESTART_CONTEXT_DIR, filename));
40456
40853
  } catch {
40457
40854
  }
40458
40855
  }
@@ -40460,14 +40857,14 @@ function clearAllRestartContextHints() {
40460
40857
  if (!SLACK_RESTART_CONTEXT_DIR) return;
40461
40858
  let names;
40462
40859
  try {
40463
- names = readdirSync5(SLACK_RESTART_CONTEXT_DIR);
40860
+ names = readdirSync6(SLACK_RESTART_CONTEXT_DIR);
40464
40861
  } catch {
40465
40862
  return;
40466
40863
  }
40467
40864
  for (const name of names) {
40468
40865
  if (!name.endsWith(".json")) continue;
40469
40866
  try {
40470
- unlinkSync7(join18(SLACK_RESTART_CONTEXT_DIR, name));
40867
+ unlinkSync7(join20(SLACK_RESTART_CONTEXT_DIR, name));
40471
40868
  } catch {
40472
40869
  }
40473
40870
  }
@@ -40484,7 +40881,7 @@ async function notifyStrandedInboundsOnFirstConnect() {
40484
40881
  if (!SLACK_PENDING_INBOUND_DIR || !existsSync10(SLACK_PENDING_INBOUND_DIR)) return;
40485
40882
  let filenames;
40486
40883
  try {
40487
- filenames = readdirSync5(SLACK_PENDING_INBOUND_DIR);
40884
+ filenames = readdirSync6(SLACK_PENDING_INBOUND_DIR);
40488
40885
  } catch {
40489
40886
  hadFailure = true;
40490
40887
  return;
@@ -40494,10 +40891,10 @@ async function notifyStrandedInboundsOnFirstConnect() {
40494
40891
  let notified = 0;
40495
40892
  for (const filename of filenames) {
40496
40893
  if (!filename.endsWith(".json")) continue;
40497
- const fullPath = join18(SLACK_PENDING_INBOUND_DIR, filename);
40894
+ const fullPath = join20(SLACK_PENDING_INBOUND_DIR, filename);
40498
40895
  let marker;
40499
40896
  try {
40500
- marker = JSON.parse(readFileSync18(fullPath, "utf-8"));
40897
+ marker = JSON.parse(readFileSync20(fullPath, "utf-8"));
40501
40898
  } catch {
40502
40899
  continue;
40503
40900
  }
@@ -40671,7 +41068,7 @@ function noteThreadActivityByMessageTs(channel, messageTs) {
40671
41068
  markSeenAllSlackPendingMarkersForThread2(channel, messageTs);
40672
41069
  markSeenSlackPendingMarkerByMessageTs2(channel, messageTs);
40673
41070
  }
40674
- var RESTART_FLAGS_DIR = join18(homedir6(), ".augmented", "restart-flags");
41071
+ var RESTART_FLAGS_DIR = join20(homedir7(), ".augmented", "restart-flags");
40675
41072
  function actuateHostRestartSlack() {
40676
41073
  return actuateHostRestart({
40677
41074
  agtHost: AGT_HOST,
@@ -40692,10 +41089,10 @@ function buildAugmentedSlackMetadata() {
40692
41089
  };
40693
41090
  }
40694
41091
  function hashChannelId(id) {
40695
- return createHash2("sha256").update(id).digest("hex").slice(0, 8);
41092
+ return createHash3("sha256").update(id).digest("hex").slice(0, 8);
40696
41093
  }
40697
41094
  function hashId(id) {
40698
- return createHash2("sha256").update(id).digest("hex").slice(0, 8);
41095
+ return createHash3("sha256").update(id).digest("hex").slice(0, 8);
40699
41096
  }
40700
41097
  async function postSlackMessage(body) {
40701
41098
  const augmentedMeta = buildAugmentedSlackMetadata();
@@ -41276,7 +41673,7 @@ async function handleSlashCommandEnvelope(payload) {
41276
41673
  if (!existsSync10(RESTART_FLAGS_DIR)) {
41277
41674
  mkdirSync9(RESTART_FLAGS_DIR, { recursive: true });
41278
41675
  }
41279
- const flagPath = join18(RESTART_FLAGS_DIR, `${codeName}.flag`);
41676
+ const flagPath = join20(RESTART_FLAGS_DIR, `${codeName}.flag`);
41280
41677
  const flag = {
41281
41678
  codeName,
41282
41679
  source: "slack",
@@ -41284,7 +41681,7 @@ async function handleSlashCommandEnvelope(payload) {
41284
41681
  reply: confirmReply
41285
41682
  };
41286
41683
  const tmpPath = `${flagPath}.${process.pid}.${randomUUID2()}.tmp`;
41287
- writeFileSync13(tmpPath, JSON.stringify(flag) + "\n", "utf8");
41684
+ writeFileSync14(tmpPath, JSON.stringify(flag) + "\n", "utf8");
41288
41685
  renameSync5(tmpPath, flagPath);
41289
41686
  }
41290
41687
  process.stderr.write(
@@ -41419,7 +41816,7 @@ async function handleRestartCommand(opts) {
41419
41816
  if (!existsSync10(RESTART_FLAGS_DIR)) {
41420
41817
  mkdirSync9(RESTART_FLAGS_DIR, { recursive: true });
41421
41818
  }
41422
- const flagPath = join18(RESTART_FLAGS_DIR, `${codeName}.flag`);
41819
+ const flagPath = join20(RESTART_FLAGS_DIR, `${codeName}.flag`);
41423
41820
  const flag = {
41424
41821
  codeName,
41425
41822
  source: "slack",
@@ -41427,7 +41824,7 @@ async function handleRestartCommand(opts) {
41427
41824
  reply: { ...confirmReply, message_ts: opts.ts }
41428
41825
  };
41429
41826
  const tmpPath = `${flagPath}.${process.pid}.${randomUUID2()}.tmp`;
41430
- writeFileSync13(tmpPath, JSON.stringify(flag) + "\n", "utf8");
41827
+ writeFileSync14(tmpPath, JSON.stringify(flag) + "\n", "utf8");
41431
41828
  renameSync5(tmpPath, flagPath);
41432
41829
  }
41433
41830
  process.stderr.write(
@@ -41541,7 +41938,7 @@ var SLACK_HOT_THREAD_WINDOW_MS = parseHotThreadWindowMs(
41541
41938
  );
41542
41939
  function resolveThreadStorePath() {
41543
41940
  if (!AGENT_CODE_NAME) return null;
41544
- return join18(homedir6(), ".augmented", AGENT_CODE_NAME, "slack-tracked-threads.json");
41941
+ return join20(homedir7(), ".augmented", AGENT_CODE_NAME, "slack-tracked-threads.json");
41545
41942
  }
41546
41943
  function parseTtlDays(raw) {
41547
41944
  if (!raw) return void 0;
@@ -41580,9 +41977,9 @@ if (!BOT_TOKEN || !APP_TOKEN) {
41580
41977
  var slackStderrLogStream = null;
41581
41978
  if (AGENT_CODE_NAME) {
41582
41979
  try {
41583
- const logDir = join18(homedir6(), ".augmented", AGENT_CODE_NAME);
41980
+ const logDir = join20(homedir7(), ".augmented", AGENT_CODE_NAME);
41584
41981
  mkdirSync9(logDir, { recursive: true });
41585
- slackStderrLogStream = createWriteStream(join18(logDir, "slack-channel-stderr.log"), {
41982
+ slackStderrLogStream = createWriteStream(join20(logDir, "slack-channel-stderr.log"), {
41586
41983
  flags: "a",
41587
41984
  mode: 384
41588
41985
  });
@@ -42118,6 +42515,11 @@ mcp.setRequestHandler(CallToolRequestSchema, async (req) => {
42118
42515
  windowMs: SLACK_HOT_THREAD_WINDOW_MS
42119
42516
  });
42120
42517
  hotGuard = applyHotThreadGuard({ baseThreadTs, forcedRoot, hotThread });
42518
+ recordHotThreadClassification(SLACK_AGENT_DIR, channel, {
42519
+ mode: hotThreadMode,
42520
+ outcome: hotGuard.guard,
42521
+ proactive: proactive === true
42522
+ });
42121
42523
  if (hotGuard.guard === "redirected_to_hot_thread") {
42122
42524
  process.stderr.write(
42123
42525
  `slack-channel(${AGENT_CODE_NAME}): hot_thread_guard mode=${hotThreadMode} applied=${hotThreadMode === "enforce"} channel=${redactSlackId(channel)} hot_thread=${redactSlackId(hotGuard.threadTs)} proactive=${proactive === true} age_ms=${hotThread?.ageMs ?? ""}
@@ -42453,7 +42855,7 @@ ${result.formatted}` : "No messages in range, or the bot is not a member of this
42453
42855
  isError: true
42454
42856
  };
42455
42857
  }
42456
- const allowedRoot = resolve2(homedir6(), ".augmented", AGENT_CODE_NAME, "project") + "/";
42858
+ const allowedRoot = resolve2(homedir7(), ".augmented", AGENT_CODE_NAME, "project") + "/";
42457
42859
  const resolvedPath = resolve2(path);
42458
42860
  if (!resolvedPath.startsWith(allowedRoot)) {
42459
42861
  return {
@@ -42467,7 +42869,7 @@ ${result.formatted}` : "No messages in range, or the bot is not a member of this
42467
42869
  let bytes;
42468
42870
  let size;
42469
42871
  try {
42470
- const stat2 = statSync3(resolvedPath);
42872
+ const stat2 = statSync4(resolvedPath);
42471
42873
  if (!stat2.isFile()) {
42472
42874
  return {
42473
42875
  content: [{ type: "text", text: `Upload refused: ${resolvedPath} is not a regular file.` }],
@@ -42475,7 +42877,7 @@ ${result.formatted}` : "No messages in range, or the bot is not a member of this
42475
42877
  };
42476
42878
  }
42477
42879
  size = stat2.size;
42478
- bytes = readFileSync18(resolvedPath);
42880
+ bytes = readFileSync20(resolvedPath);
42479
42881
  } catch (err) {
42480
42882
  return {
42481
42883
  content: [{ type: "text", text: `Failed to read file: ${err.message}` }],
@@ -43130,7 +43532,7 @@ function isDownloadableFileId(fileId, channel) {
43130
43532
  }
43131
43533
  function redactAugmentedPaths2(msg) {
43132
43534
  return msg.replaceAll(
43133
- new RegExp(`${homedir6().replace(/[.*+?^${}()|[\\]\\\\]/g, "\\\\$&")}/\\.augmented/[^\\s'"\`]*`, "g"),
43535
+ new RegExp(`${homedir7().replace(/[.*+?^${}()|[\\]\\\\]/g, "\\\\$&")}/\\.augmented/[^\\s'"\`]*`, "g"),
43134
43536
  "<augmented-path>"
43135
43537
  );
43136
43538
  }
@@ -43189,7 +43591,7 @@ async function downloadSlackFile(fileId, codeName) {
43189
43591
  throw new Error(`refusing to write ${savedPath} outside ${dir}`);
43190
43592
  }
43191
43593
  mkdirSync9(dir, { recursive: true });
43192
- writeFileSync13(savedPath, bytes, { mode: 384 });
43594
+ writeFileSync14(savedPath, bytes, { mode: 384 });
43193
43595
  try {
43194
43596
  chmodSync(savedPath, 384);
43195
43597
  } catch {
@@ -43250,7 +43652,7 @@ async function replayPendingSlackMarkers() {
43250
43652
  if (!sessionAlive) return;
43251
43653
  let filenames;
43252
43654
  try {
43253
- filenames = readdirSync5(SLACK_PENDING_INBOUND_DIR);
43655
+ filenames = readdirSync6(SLACK_PENDING_INBOUND_DIR);
43254
43656
  } catch {
43255
43657
  return;
43256
43658
  }
@@ -43258,7 +43660,7 @@ async function replayPendingSlackMarkers() {
43258
43660
  let paneFreshAgeMs = null;
43259
43661
  if (SLACK_AGENT_DIR) {
43260
43662
  try {
43261
- paneFreshAgeMs = Math.max(0, now - statSync3(join18(SLACK_AGENT_DIR, "pane.log")).mtimeMs);
43663
+ paneFreshAgeMs = Math.max(0, now - statSync4(join20(SLACK_AGENT_DIR, "pane.log")).mtimeMs);
43262
43664
  } catch {
43263
43665
  }
43264
43666
  }
@@ -43266,10 +43668,10 @@ async function replayPendingSlackMarkers() {
43266
43668
  const entries = [];
43267
43669
  for (const name of filenames) {
43268
43670
  if (!name.endsWith(".json") || name.endsWith(".tmp")) continue;
43269
- const fullPath = join18(SLACK_PENDING_INBOUND_DIR, name);
43671
+ const fullPath = join20(SLACK_PENDING_INBOUND_DIR, name);
43270
43672
  let marker;
43271
43673
  try {
43272
- marker = JSON.parse(readFileSync18(fullPath, "utf-8"));
43674
+ marker = JSON.parse(readFileSync20(fullPath, "utf-8"));
43273
43675
  } catch {
43274
43676
  continue;
43275
43677
  }
@@ -43616,7 +44018,7 @@ async function connectSocketMode() {
43616
44018
  const passedIdentity = access.kind !== "drop" || access.reason.startsWith("peer:");
43617
44019
  if (passedIdentity) recordActivity("inbound");
43618
44020
  if (access.kind === "drop") {
43619
- const channelHash = createHash2("sha256").update(evt.channel ?? "").digest("hex").slice(0, 8);
44021
+ const channelHash = createHash3("sha256").update(evt.channel ?? "").digest("hex").slice(0, 8);
43620
44022
  const subtypeSuffix = access.reason === "content:subtype" ? ` subtype=${evt.subtype ?? "none"}` : "";
43621
44023
  process.stderr.write(
43622
44024
  `slack-channel: inbound drop reason=${access.reason}${subtypeSuffix} channel=${channelHash} ts=${redactSlackId(evt.ts)}
@@ -43741,7 +44143,8 @@ async function connectSocketMode() {
43741
44143
  });
43742
44144
  return;
43743
44145
  }
43744
- const usageLimitUntil = !isBot ? readUsageLimitUntil({ codeName: AGENT_CODE_NAME }) : null;
44146
+ const reactiveMode = resolveUsageLimitReactiveMode();
44147
+ const usageLimitUntil = !isBot && shouldReadPredictiveMarker(reactiveMode) ? readUsageLimitUntil({ codeName: AGENT_CODE_NAME }) : null;
43745
44148
  if (usageLimitUntil) {
43746
44149
  process.stderr.write(
43747
44150
  `slack-channel(${AGENT_CODE_NAME}): usage-limit active until ${usageLimitUntil.toISOString()} \u2014 notice, no dispatch (channel=${redactSlackId(evt.channel)})
@@ -43800,7 +44203,7 @@ async function connectSocketMode() {
43800
44203
  if (evt.type === "message" && evt.channel && !isDirectMessage) {
43801
44204
  if (isThreadReply) {
43802
44205
  const logThreadDrop = (reason) => {
43803
- const channelHash = createHash2("sha256").update(evt.channel ?? "").digest("hex").slice(0, 8);
44206
+ const channelHash = createHash3("sha256").update(evt.channel ?? "").digest("hex").slice(0, 8);
43804
44207
  process.stderr.write(
43805
44208
  `slack-channel(${AGENT_CODE_NAME}): thread-reply drop reason=${reason} auto_follow=${THREAD_AUTO_FOLLOW} channel=${channelHash} ts=${redactSlackId(evt.ts)}
43806
44209
  `
@@ -43866,7 +44269,7 @@ async function connectSocketMode() {
43866
44269
  let paneLogFreshAgeMs = null;
43867
44270
  if (SLACK_AGENT_DIR) {
43868
44271
  try {
43869
- const paneMtimeMs = statSync3(join18(SLACK_AGENT_DIR, "pane.log")).mtimeMs;
44272
+ const paneMtimeMs = statSync4(join20(SLACK_AGENT_DIR, "pane.log")).mtimeMs;
43870
44273
  paneLogFreshAgeMs = Math.max(0, Date.now() - paneMtimeMs);
43871
44274
  } catch {
43872
44275
  }
@@ -44032,10 +44435,26 @@ ${forwarded.text}` : forwarded.text;
44032
44435
  });
44033
44436
  clearScheduledTurnMarker(SLACK_AGENT_DIR);
44034
44437
  }
44438
+ const dispatchedAtMs = Date.now();
44035
44439
  await mcp.notification({
44036
44440
  method: "notifications/claude/channel",
44037
44441
  params: replayPayload
44038
44442
  });
44443
+ const watchMode = armedWatchMode({
44444
+ mode: reactiveMode,
44445
+ isBot: isFromBot,
44446
+ replyOwed: shouldEngage
44447
+ });
44448
+ if (watchMode) {
44449
+ armSlackUsageLimitWatch({
44450
+ mode: watchMode,
44451
+ channel,
44452
+ senderId: evt.user,
44453
+ threadTs,
44454
+ messageTs: ts,
44455
+ sinceMs: dispatchedAtMs
44456
+ });
44457
+ }
44039
44458
  if (shouldEngage) seedSlackProgressHeartbeat();
44040
44459
  if (channel) {
44041
44460
  conversationIngestClient?.ingest({