@integrity-labs/agt-cli 0.27.125 → 0.27.127

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.
@@ -14974,6 +14974,47 @@ function clearOldestSlackPendingMarkerInChannel(dir, channel, clear = defaultCle
14974
14974
  }
14975
14975
  }
14976
14976
 
14977
+ // src/restart-confirm.ts
14978
+ import { existsSync as existsSync2, mkdirSync, readFileSync as readFileSync2, renameSync, unlinkSync as unlinkSync2, writeFileSync } from "fs";
14979
+ import { dirname } from "path";
14980
+ import { randomUUID } from "crypto";
14981
+ var RESTART_CONFIRM_MAX_AGE_MS = 10 * 60 * 1e3;
14982
+ function shouldPostRestartConfirm(marker, processBootMs, nowMs) {
14983
+ if (!marker) return false;
14984
+ const requestedAt = marker.requested_at;
14985
+ if (typeof requestedAt !== "number" || !Number.isFinite(requestedAt)) return false;
14986
+ if (requestedAt >= processBootMs) return false;
14987
+ if (nowMs - requestedAt > RESTART_CONFIRM_MAX_AGE_MS) return false;
14988
+ return true;
14989
+ }
14990
+ function buildBackOnlineText(name) {
14991
+ const trimmed = typeof name === "string" ? name.trim() : "";
14992
+ return trimmed ? `Hey ${trimmed}, I'm back online after my restart. \u{1F7E2}` : `I'm back online after my restart. \u{1F7E2}`;
14993
+ }
14994
+ function writeRestartConfirmMarker(filePath, marker) {
14995
+ const dir = dirname(filePath);
14996
+ if (!existsSync2(dir)) mkdirSync(dir, { recursive: true, mode: 448 });
14997
+ const tmpPath = `${filePath}.${process.pid}.${randomUUID()}.tmp`;
14998
+ writeFileSync(tmpPath, JSON.stringify(marker) + "\n", { encoding: "utf8", mode: 384 });
14999
+ renameSync(tmpPath, filePath);
15000
+ }
15001
+ function readRestartConfirmMarker(filePath) {
15002
+ try {
15003
+ if (!existsSync2(filePath)) return null;
15004
+ const parsed = JSON.parse(readFileSync2(filePath, "utf8"));
15005
+ if (!parsed || typeof parsed !== "object") return null;
15006
+ return parsed;
15007
+ } catch {
15008
+ return null;
15009
+ }
15010
+ }
15011
+ function clearRestartConfirmMarker(filePath) {
15012
+ try {
15013
+ if (existsSync2(filePath)) unlinkSync2(filePath);
15014
+ } catch {
15015
+ }
15016
+ }
15017
+
14977
15018
  // ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.27.1_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/server/stdio.js
14978
15019
  import process2 from "process";
14979
15020
 
@@ -15070,23 +15111,23 @@ var StdioServerTransport = class {
15070
15111
  import {
15071
15112
  chmodSync,
15072
15113
  createWriteStream,
15073
- existsSync as existsSync4,
15074
- mkdirSync as mkdirSync4,
15075
- readFileSync as readFileSync5,
15114
+ existsSync as existsSync5,
15115
+ mkdirSync as mkdirSync5,
15116
+ readFileSync as readFileSync6,
15076
15117
  readdirSync as readdirSync3,
15077
- renameSync as renameSync2,
15118
+ renameSync as renameSync3,
15078
15119
  statSync as statSync2,
15079
- unlinkSync as unlinkSync3,
15120
+ unlinkSync as unlinkSync4,
15080
15121
  watch,
15081
- writeFileSync as writeFileSync4
15122
+ writeFileSync as writeFileSync5
15082
15123
  } from "fs";
15083
15124
  import { basename, join as join5, resolve as resolve2 } from "path";
15084
15125
  import { homedir as homedir2 } from "os";
15085
- import { createHash, randomUUID } from "crypto";
15126
+ import { createHash, randomUUID as randomUUID2 } from "crypto";
15086
15127
 
15087
15128
  // src/slack-thread-store.ts
15088
- import { mkdirSync, readFileSync as readFileSync2, writeFileSync } from "fs";
15089
- import { dirname } from "path";
15129
+ import { mkdirSync as mkdirSync2, readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "fs";
15130
+ import { dirname as dirname2 } from "path";
15090
15131
  var FILE_VERSION = 1;
15091
15132
  var DEFAULT_TTL_DAYS = 30;
15092
15133
  var DEFAULT_MIN_INTERVAL_MS = 1e3;
@@ -15096,7 +15137,7 @@ function loadThreadStore(filePath, opts = {}) {
15096
15137
  const ttlMs = ttlDays * 24 * 60 * 60 * 1e3;
15097
15138
  let raw;
15098
15139
  try {
15099
- raw = readFileSync2(filePath, "utf-8");
15140
+ raw = readFileSync3(filePath, "utf-8");
15100
15141
  } catch {
15101
15142
  return { threads: /* @__PURE__ */ new Map(), pruned: 0 };
15102
15143
  }
@@ -15140,8 +15181,8 @@ function createThreadPersister(opts) {
15140
15181
  let pendingSnapshot = null;
15141
15182
  const writeNow = (snap) => {
15142
15183
  try {
15143
- mkdirSync(dirname(opts.filePath), { recursive: true });
15144
- writeFileSync(opts.filePath, serializeThreadStore(snap), "utf-8");
15184
+ mkdirSync2(dirname2(opts.filePath), { recursive: true });
15185
+ writeFileSync2(opts.filePath, serializeThreadStore(snap), "utf-8");
15145
15186
  lastWriteAt = Date.now();
15146
15187
  } catch (err) {
15147
15188
  opts.onError?.(
@@ -15210,17 +15251,17 @@ async function runOrRetry(fn, opts) {
15210
15251
  }
15211
15252
 
15212
15253
  // src/slack-bot-photo.ts
15213
- import { existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "fs";
15214
- import { dirname as dirname2 } from "path";
15254
+ import { existsSync as existsSync3, mkdirSync as mkdirSync3, readFileSync as readFileSync4, writeFileSync as writeFileSync3 } from "fs";
15255
+ import { dirname as dirname3 } from "path";
15215
15256
  async function applyBotPhoto(opts) {
15216
15257
  const fetchImpl = opts.fetchImpl ?? fetch;
15217
15258
  const log = opts.log ?? ((m) => {
15218
15259
  process.stderr.write(m);
15219
15260
  });
15220
15261
  const { token, avatarUrl, markerPath } = opts;
15221
- if (markerPath && existsSync2(markerPath)) {
15262
+ if (markerPath && existsSync3(markerPath)) {
15222
15263
  try {
15223
- if (readFileSync3(markerPath, "utf-8").trim() === avatarUrl) {
15264
+ if (readFileSync4(markerPath, "utf-8").trim() === avatarUrl) {
15224
15265
  return { status: "skipped-unchanged" };
15225
15266
  }
15226
15267
  } catch {
@@ -15261,8 +15302,8 @@ async function applyBotPhoto(opts) {
15261
15302
  }
15262
15303
  if (markerPath) {
15263
15304
  try {
15264
- mkdirSync2(dirname2(markerPath), { recursive: true, mode: 448 });
15265
- writeFileSync2(markerPath, avatarUrl, { mode: 384 });
15305
+ mkdirSync3(dirname3(markerPath), { recursive: true, mode: 448 });
15306
+ writeFileSync3(markerPath, avatarUrl, { mode: 384 });
15266
15307
  } catch {
15267
15308
  }
15268
15309
  }
@@ -16000,12 +16041,12 @@ function createSlackBotUserIdClient(args) {
16000
16041
 
16001
16042
  // src/mcp-spawn-lock.ts
16002
16043
  import {
16003
- existsSync as existsSync3,
16004
- mkdirSync as mkdirSync3,
16005
- readFileSync as readFileSync4,
16006
- renameSync,
16007
- unlinkSync as unlinkSync2,
16008
- writeFileSync as writeFileSync3
16044
+ existsSync as existsSync4,
16045
+ mkdirSync as mkdirSync4,
16046
+ readFileSync as readFileSync5,
16047
+ renameSync as renameSync2,
16048
+ unlinkSync as unlinkSync3,
16049
+ writeFileSync as writeFileSync4
16009
16050
  } from "fs";
16010
16051
  import { join as join4 } from "path";
16011
16052
  function defaultIsPidAlive(pid) {
@@ -16035,11 +16076,11 @@ function acquireMcpSpawnLock(args) {
16035
16076
  return { kind: "blocked", path, holder: existing };
16036
16077
  }
16037
16078
  }
16038
- mkdirSync3(agentDir, { recursive: true, mode: 448 });
16079
+ mkdirSync4(agentDir, { recursive: true, mode: 448 });
16039
16080
  const tmpPath = `${path}.${selfPid}.tmp`;
16040
16081
  const payload = { pid: selfPid, started_at: now() };
16041
- writeFileSync3(tmpPath, JSON.stringify(payload), { mode: 384 });
16042
- renameSync(tmpPath, path);
16082
+ writeFileSync4(tmpPath, JSON.stringify(payload), { mode: 384 });
16083
+ renameSync2(tmpPath, path);
16043
16084
  return { kind: "acquired", path };
16044
16085
  }
16045
16086
  function releaseMcpSpawnLock(lockPath, opts = {}) {
@@ -16049,14 +16090,14 @@ function releaseMcpSpawnLock(lockPath, opts = {}) {
16049
16090
  if (!existing) return;
16050
16091
  if (existing.pid !== selfPid) return;
16051
16092
  try {
16052
- unlinkSync2(lockPath);
16093
+ unlinkSync3(lockPath);
16053
16094
  } catch {
16054
16095
  }
16055
16096
  }
16056
16097
  function readLockHolder(path) {
16057
- if (!existsSync3(path)) return null;
16098
+ if (!existsSync4(path)) return null;
16058
16099
  try {
16059
- const raw = readFileSync4(path, "utf8");
16100
+ const raw = readFileSync5(path, "utf8");
16060
16101
  const parsed = JSON.parse(raw);
16061
16102
  const pid = typeof parsed.pid === "number" ? parsed.pid : Number(parsed.pid);
16062
16103
  if (!Number.isFinite(pid) || pid <= 0) return null;
@@ -16237,6 +16278,7 @@ var SLACK_PEER_CLASSIFIER_CONFIG = {
16237
16278
  var SLACK_AGENT_DIR = AGENT_CODE_NAME ? join5(homedir2(), ".augmented", AGENT_CODE_NAME) : null;
16238
16279
  var SLACK_PENDING_INBOUND_DIR = SLACK_AGENT_DIR ? join5(SLACK_AGENT_DIR, "slack-pending-inbound") : null;
16239
16280
  var SLACK_RECOVERY_OUTBOX_DIR = SLACK_AGENT_DIR ? join5(SLACK_AGENT_DIR, "slack-recovery-outbox") : null;
16281
+ var SLACK_RESTART_CONFIRM_FILE = SLACK_AGENT_DIR ? join5(SLACK_AGENT_DIR, "slack-restart-confirm.json") : null;
16240
16282
  var SLACK_MAX_RECOVERY_ATTEMPTS = 3;
16241
16283
  var SLACK_AVATAR_MARKER_PATH = SLACK_AGENT_DIR ? join5(SLACK_AGENT_DIR, "slack-avatar-applied") : null;
16242
16284
  function redactSlackId(id) {
@@ -16263,8 +16305,8 @@ function writeSlackPendingInboundMarker(channel, threadTs, messageTs, undelivera
16263
16305
  ...undeliverable ? { undeliverable: true } : {}
16264
16306
  };
16265
16307
  try {
16266
- mkdirSync4(SLACK_PENDING_INBOUND_DIR, { recursive: true, mode: 448 });
16267
- writeFileSync4(path, JSON.stringify(marker), { mode: 384 });
16308
+ mkdirSync5(SLACK_PENDING_INBOUND_DIR, { recursive: true, mode: 448 });
16309
+ writeFileSync5(path, JSON.stringify(marker), { mode: 384 });
16268
16310
  } catch (err) {
16269
16311
  process.stderr.write(
16270
16312
  `slack-channel(${AGENT_CODE_NAME}): pending-inbound marker write failed: ${err.message}
@@ -16274,9 +16316,9 @@ function writeSlackPendingInboundMarker(channel, threadTs, messageTs, undelivera
16274
16316
  }
16275
16317
  function readSlackPendingInboundMarker(channel, threadTs, messageTs) {
16276
16318
  const path = slackPendingInboundPath(channel, threadTs, messageTs);
16277
- if (!path || !existsSync4(path)) return null;
16319
+ if (!path || !existsSync5(path)) return null;
16278
16320
  try {
16279
- return JSON.parse(readFileSync5(path, "utf-8"));
16321
+ return JSON.parse(readFileSync6(path, "utf-8"));
16280
16322
  } catch {
16281
16323
  return null;
16282
16324
  }
@@ -16395,7 +16437,7 @@ function __resetSlackBusyAckNoticeThrottle() {
16395
16437
  function clearSlackMarkerFileWithHeal(fullPath) {
16396
16438
  let marker = null;
16397
16439
  try {
16398
- marker = JSON.parse(readFileSync5(fullPath, "utf-8"));
16440
+ marker = JSON.parse(readFileSync6(fullPath, "utf-8"));
16399
16441
  } catch {
16400
16442
  }
16401
16443
  if (marker && decideRecoveryHeal({
@@ -16405,7 +16447,7 @@ function clearSlackMarkerFileWithHeal(fullPath) {
16405
16447
  healSlackUndeliverable(marker.channel, marker.message_ts);
16406
16448
  }
16407
16449
  try {
16408
- if (existsSync4(fullPath)) unlinkSync3(fullPath);
16450
+ if (existsSync5(fullPath)) unlinkSync4(fullPath);
16409
16451
  } catch {
16410
16452
  }
16411
16453
  }
@@ -16449,14 +16491,14 @@ async function processSlackRecoveryOutboxFile(filename) {
16449
16491
  const fullPath = join5(SLACK_RECOVERY_OUTBOX_DIR, filename);
16450
16492
  let payload;
16451
16493
  try {
16452
- payload = JSON.parse(readFileSync5(fullPath, "utf-8"));
16494
+ payload = JSON.parse(readFileSync6(fullPath, "utf-8"));
16453
16495
  } catch (err) {
16454
16496
  process.stderr.write(
16455
16497
  `slack-channel(${AGENT_CODE_NAME}): recovery outbox parse failed (${filename}): ${err.message}
16456
16498
  `
16457
16499
  );
16458
16500
  try {
16459
- renameSync2(fullPath, `${fullPath}.parse-error.poison`);
16501
+ renameSync3(fullPath, `${fullPath}.parse-error.poison`);
16460
16502
  } catch {
16461
16503
  }
16462
16504
  return;
@@ -16467,7 +16509,7 @@ async function processSlackRecoveryOutboxFile(filename) {
16467
16509
  `
16468
16510
  );
16469
16511
  try {
16470
- renameSync2(fullPath, `${fullPath}.malformed.poison`);
16512
+ renameSync3(fullPath, `${fullPath}.malformed.poison`);
16471
16513
  } catch {
16472
16514
  }
16473
16515
  return;
@@ -16515,7 +16557,7 @@ async function processSlackRecoveryOutboxFile(filename) {
16515
16557
  }
16516
16558
  if (sendSucceeded) {
16517
16559
  try {
16518
- unlinkSync3(fullPath);
16560
+ unlinkSync4(fullPath);
16519
16561
  } catch {
16520
16562
  }
16521
16563
  return;
@@ -16523,7 +16565,7 @@ async function processSlackRecoveryOutboxFile(filename) {
16523
16565
  const next = slackNextRetryName(filename);
16524
16566
  if (next) {
16525
16567
  try {
16526
- renameSync2(fullPath, join5(SLACK_RECOVERY_OUTBOX_DIR, next.next));
16568
+ renameSync3(fullPath, join5(SLACK_RECOVERY_OUTBOX_DIR, next.next));
16527
16569
  if (next.attempt >= SLACK_MAX_RECOVERY_ATTEMPTS) {
16528
16570
  process.stderr.write(
16529
16571
  `slack-channel(${AGENT_CODE_NAME}): ghost-reply recovery exhausted retries \u2014 moved to ${next.next}
@@ -16574,7 +16616,7 @@ function scanSlackRecoveryRetries() {
16574
16616
  function startSlackRecoveryOutboxWatcher() {
16575
16617
  if (!SLACK_RECOVERY_OUTBOX_DIR) return;
16576
16618
  try {
16577
- mkdirSync4(SLACK_RECOVERY_OUTBOX_DIR, { recursive: true, mode: 448 });
16619
+ mkdirSync5(SLACK_RECOVERY_OUTBOX_DIR, { recursive: true, mode: 448 });
16578
16620
  } catch (err) {
16579
16621
  process.stderr.write(
16580
16622
  `slack-channel(${AGENT_CODE_NAME}): recovery outbox mkdir failed: ${err.message}
@@ -16592,7 +16634,7 @@ function startSlackRecoveryOutboxWatcher() {
16592
16634
  const watcher = watch(SLACK_RECOVERY_OUTBOX_DIR, (event, filename) => {
16593
16635
  if (event !== "rename" || !filename) return;
16594
16636
  if (!isFirstAttemptSlackOutboxFile(filename)) return;
16595
- if (existsSync4(join5(SLACK_RECOVERY_OUTBOX_DIR, filename))) {
16637
+ if (existsSync5(join5(SLACK_RECOVERY_OUTBOX_DIR, filename))) {
16596
16638
  void processSlackRecoveryOutboxFile(filename);
16597
16639
  }
16598
16640
  });
@@ -16613,7 +16655,7 @@ function trackPendingMessage(channel, threadTs, messageTs, undeliverable = false
16613
16655
  }
16614
16656
  function sweepSlackStaleMarkers(thresholdMs) {
16615
16657
  if (!SLACK_PENDING_INBOUND_DIR) return;
16616
- if (!existsSync4(SLACK_PENDING_INBOUND_DIR)) return;
16658
+ if (!existsSync5(SLACK_PENDING_INBOUND_DIR)) return;
16617
16659
  let filenames;
16618
16660
  try {
16619
16661
  filenames = readdirSync3(SLACK_PENDING_INBOUND_DIR);
@@ -16632,14 +16674,14 @@ function sweepSlackStaleMarkers(thresholdMs) {
16632
16674
  const fullPath = join5(SLACK_PENDING_INBOUND_DIR, filename);
16633
16675
  let marker;
16634
16676
  try {
16635
- marker = JSON.parse(readFileSync5(fullPath, "utf-8"));
16677
+ marker = JSON.parse(readFileSync6(fullPath, "utf-8"));
16636
16678
  } catch (err) {
16637
16679
  process.stderr.write(
16638
16680
  `slack-channel(${AGENT_CODE_NAME}): stale-marker parse failed for ${redactSlackId(filename)}: ${err.message}
16639
16681
  `
16640
16682
  );
16641
16683
  try {
16642
- unlinkSync3(fullPath);
16684
+ unlinkSync4(fullPath);
16643
16685
  } catch {
16644
16686
  }
16645
16687
  cleared++;
@@ -16648,7 +16690,7 @@ function sweepSlackStaleMarkers(thresholdMs) {
16648
16690
  const { channel, thread_ts, message_ts, received_at } = marker;
16649
16691
  if (!channel || !thread_ts || !message_ts || isPendingMarkerStale(received_at, now, thresholdMs)) {
16650
16692
  try {
16651
- unlinkSync3(fullPath);
16693
+ unlinkSync4(fullPath);
16652
16694
  } catch {
16653
16695
  }
16654
16696
  cleared++;
@@ -16671,14 +16713,14 @@ var slackOrphanSweepTimer = setInterval(() => {
16671
16713
  slackOrphanSweepTimer.unref?.();
16672
16714
  var lastSlackGiveUpHandledAtMs = null;
16673
16715
  function listPendingSlackConversations() {
16674
- if (!SLACK_PENDING_INBOUND_DIR || !existsSync4(SLACK_PENDING_INBOUND_DIR)) return [];
16716
+ if (!SLACK_PENDING_INBOUND_DIR || !existsSync5(SLACK_PENDING_INBOUND_DIR)) return [];
16675
16717
  const byKey = /* @__PURE__ */ new Map();
16676
16718
  try {
16677
16719
  for (const name of readdirSync3(SLACK_PENDING_INBOUND_DIR)) {
16678
16720
  if (!name.endsWith(".json")) continue;
16679
16721
  try {
16680
16722
  const marker = JSON.parse(
16681
- readFileSync5(join5(SLACK_PENDING_INBOUND_DIR, name), "utf8")
16723
+ readFileSync6(join5(SLACK_PENDING_INBOUND_DIR, name), "utf8")
16682
16724
  );
16683
16725
  if (typeof marker.channel !== "string" || !marker.channel) continue;
16684
16726
  if (typeof marker.thread_ts !== "string" || !marker.thread_ts) continue;
@@ -16755,7 +16797,7 @@ async function notifyStrandedInboundsOnFirstConnect() {
16755
16797
  strandedInboundNoticeInFlight = true;
16756
16798
  let hadFailure = false;
16757
16799
  try {
16758
- if (!SLACK_PENDING_INBOUND_DIR || !existsSync4(SLACK_PENDING_INBOUND_DIR)) return;
16800
+ if (!SLACK_PENDING_INBOUND_DIR || !existsSync5(SLACK_PENDING_INBOUND_DIR)) return;
16759
16801
  let filenames;
16760
16802
  try {
16761
16803
  filenames = readdirSync3(SLACK_PENDING_INBOUND_DIR);
@@ -16771,7 +16813,7 @@ async function notifyStrandedInboundsOnFirstConnect() {
16771
16813
  const fullPath = join5(SLACK_PENDING_INBOUND_DIR, filename);
16772
16814
  let marker;
16773
16815
  try {
16774
- marker = JSON.parse(readFileSync5(fullPath, "utf-8"));
16816
+ marker = JSON.parse(readFileSync6(fullPath, "utf-8"));
16775
16817
  } catch {
16776
16818
  continue;
16777
16819
  }
@@ -16784,7 +16826,7 @@ async function notifyStrandedInboundsOnFirstConnect() {
16784
16826
  const key2 = `${channel}__${thread_ts}`;
16785
16827
  if (seen.has(key2)) {
16786
16828
  try {
16787
- unlinkSync3(fullPath);
16829
+ unlinkSync4(fullPath);
16788
16830
  } catch {
16789
16831
  }
16790
16832
  continue;
@@ -16798,7 +16840,7 @@ async function notifyStrandedInboundsOnFirstConnect() {
16798
16840
  if (res.ok) {
16799
16841
  notified += 1;
16800
16842
  try {
16801
- unlinkSync3(fullPath);
16843
+ unlinkSync4(fullPath);
16802
16844
  } catch {
16803
16845
  }
16804
16846
  } else {
@@ -16820,6 +16862,73 @@ async function notifyStrandedInboundsOnFirstConnect() {
16820
16862
  strandedInboundNoticeInFlight = false;
16821
16863
  }
16822
16864
  }
16865
+ var restartConfirmNoticeFired = false;
16866
+ var restartConfirmNoticeInFlight = false;
16867
+ var firstConnectNoticesGated = false;
16868
+ var suppressStrandedForBoot = false;
16869
+ async function notifyRestartCompleteOnFirstConnect() {
16870
+ if (restartConfirmNoticeFired || restartConfirmNoticeInFlight) return;
16871
+ if (!SLACK_RESTART_CONFIRM_FILE) return;
16872
+ restartConfirmNoticeInFlight = true;
16873
+ let hadFailure = false;
16874
+ try {
16875
+ const marker = readRestartConfirmMarker(SLACK_RESTART_CONFIRM_FILE);
16876
+ if (!shouldPostRestartConfirm(marker, SLACK_PROCESS_BOOT_MS, Date.now())) {
16877
+ if (marker) clearRestartConfirmMarker(SLACK_RESTART_CONFIRM_FILE);
16878
+ return;
16879
+ }
16880
+ const channel = marker.reply["channel"];
16881
+ if (channel == null) {
16882
+ clearRestartConfirmMarker(SLACK_RESTART_CONFIRM_FILE);
16883
+ return;
16884
+ }
16885
+ const threadTs = marker.reply["thread_ts"];
16886
+ const res = await postSlackMessage({
16887
+ channel: String(channel),
16888
+ ...threadTs != null ? { thread_ts: String(threadTs) } : {},
16889
+ text: buildBackOnlineText(marker.requester_name)
16890
+ });
16891
+ if (res.ok) {
16892
+ clearRestartConfirmMarker(SLACK_RESTART_CONFIRM_FILE);
16893
+ process.stderr.write(
16894
+ `slack-channel(${AGENT_CODE_NAME}): posted back-online confirmation after restart
16895
+ `
16896
+ );
16897
+ } else {
16898
+ hadFailure = true;
16899
+ process.stderr.write(
16900
+ `slack-channel(${AGENT_CODE_NAME}): back-online confirmation failed: ${res.error}
16901
+ `
16902
+ );
16903
+ }
16904
+ } catch (err) {
16905
+ hadFailure = true;
16906
+ process.stderr.write(
16907
+ `slack-channel(${AGENT_CODE_NAME}): back-online confirmation threw: ${redactAugmentedPaths2(err.message)}
16908
+ `
16909
+ );
16910
+ } finally {
16911
+ if (!hadFailure) restartConfirmNoticeFired = true;
16912
+ restartConfirmNoticeInFlight = false;
16913
+ }
16914
+ }
16915
+ function writeSlackRestartConfirm(reply, requesterName) {
16916
+ if (!SLACK_RESTART_CONFIRM_FILE) return;
16917
+ const marker = {
16918
+ source: "slack",
16919
+ requested_at: Date.now(),
16920
+ ...requesterName ? { requester_name: requesterName } : {},
16921
+ reply
16922
+ };
16923
+ try {
16924
+ writeRestartConfirmMarker(SLACK_RESTART_CONFIRM_FILE, marker);
16925
+ } catch (err) {
16926
+ process.stderr.write(
16927
+ `slack-channel(${AGENT_CODE_NAME}): restart-confirm marker write failed: ${redactAugmentedPaths2(err.message)}
16928
+ `
16929
+ );
16930
+ }
16931
+ }
16823
16932
  function clearPendingMessage(channel, threadTs) {
16824
16933
  clearAllSlackPendingMarkersForThread2(channel, threadTs);
16825
16934
  }
@@ -16831,7 +16940,7 @@ function noteThreadActivityByMessageTs(channel, messageTs) {
16831
16940
  if (!channel || !messageTs) return;
16832
16941
  clearPendingMessage(channel, messageTs);
16833
16942
  if (!SLACK_PENDING_INBOUND_DIR) return;
16834
- if (!existsSync4(SLACK_PENDING_INBOUND_DIR)) return;
16943
+ if (!existsSync5(SLACK_PENDING_INBOUND_DIR)) return;
16835
16944
  let filenames;
16836
16945
  try {
16837
16946
  filenames = readdirSync3(SLACK_PENDING_INBOUND_DIR);
@@ -17231,10 +17340,17 @@ async function handleSlashCommandEnvelope(payload) {
17231
17340
  return;
17232
17341
  }
17233
17342
  try {
17234
- if (!existsSync4(RESTART_FLAGS_DIR)) {
17235
- mkdirSync4(RESTART_FLAGS_DIR, { recursive: true });
17343
+ if (!existsSync5(RESTART_FLAGS_DIR)) {
17344
+ mkdirSync5(RESTART_FLAGS_DIR, { recursive: true });
17236
17345
  }
17237
17346
  const flagPath = join5(RESTART_FLAGS_DIR, `${codeName}.flag`);
17347
+ writeSlackRestartConfirm(
17348
+ {
17349
+ channel: payload.channel_id,
17350
+ ...payload.thread_ts ? { thread_ts: payload.thread_ts } : {}
17351
+ },
17352
+ payload.user_name
17353
+ );
17238
17354
  const flag = {
17239
17355
  codeName,
17240
17356
  source: "slack",
@@ -17244,9 +17360,9 @@ async function handleSlashCommandEnvelope(payload) {
17244
17360
  ...payload.thread_ts ? { thread_ts: payload.thread_ts } : {}
17245
17361
  }
17246
17362
  };
17247
- const tmpPath = `${flagPath}.${process.pid}.${randomUUID()}.tmp`;
17248
- writeFileSync4(tmpPath, JSON.stringify(flag) + "\n", "utf8");
17249
- renameSync2(tmpPath, flagPath);
17363
+ const tmpPath = `${flagPath}.${process.pid}.${randomUUID2()}.tmp`;
17364
+ writeFileSync5(tmpPath, JSON.stringify(flag) + "\n", "utf8");
17365
+ renameSync3(tmpPath, flagPath);
17250
17366
  process.stderr.write(
17251
17367
  `slack-channel(${codeName}): /restart slash-command queued from channel ${hashChannelId(payload.channel_id)}
17252
17368
  `
@@ -17342,10 +17458,17 @@ async function handleHelpCommand(opts) {
17342
17458
  async function handleRestartCommand(opts) {
17343
17459
  const codeName = AGENT_CODE_NAME ?? "unknown";
17344
17460
  try {
17345
- if (!existsSync4(RESTART_FLAGS_DIR)) {
17346
- mkdirSync4(RESTART_FLAGS_DIR, { recursive: true });
17461
+ if (!existsSync5(RESTART_FLAGS_DIR)) {
17462
+ mkdirSync5(RESTART_FLAGS_DIR, { recursive: true });
17347
17463
  }
17348
17464
  const flagPath = join5(RESTART_FLAGS_DIR, `${codeName}.flag`);
17465
+ writeSlackRestartConfirm(
17466
+ {
17467
+ channel: opts.channel,
17468
+ ...opts.threadTs ? { thread_ts: opts.threadTs } : {}
17469
+ },
17470
+ opts.requesterName
17471
+ );
17349
17472
  const flag = {
17350
17473
  codeName,
17351
17474
  source: "slack",
@@ -17356,9 +17479,9 @@ async function handleRestartCommand(opts) {
17356
17479
  message_ts: opts.ts
17357
17480
  }
17358
17481
  };
17359
- const tmpPath = `${flagPath}.${process.pid}.${randomUUID()}.tmp`;
17360
- writeFileSync4(tmpPath, JSON.stringify(flag) + "\n", "utf8");
17361
- renameSync2(tmpPath, flagPath);
17482
+ const tmpPath = `${flagPath}.${process.pid}.${randomUUID2()}.tmp`;
17483
+ writeFileSync5(tmpPath, JSON.stringify(flag) + "\n", "utf8");
17484
+ renameSync3(tmpPath, flagPath);
17362
17485
  process.stderr.write(
17363
17486
  `slack-channel(${codeName}): /restart queued from channel ${hashChannelId(opts.channel)}
17364
17487
  `
@@ -17440,7 +17563,7 @@ var slackStderrLogStream = null;
17440
17563
  if (AGENT_CODE_NAME) {
17441
17564
  try {
17442
17565
  const logDir = join5(homedir2(), ".augmented", AGENT_CODE_NAME);
17443
- mkdirSync4(logDir, { recursive: true });
17566
+ mkdirSync5(logDir, { recursive: true });
17444
17567
  slackStderrLogStream = createWriteStream(join5(logDir, "slack-channel-stderr.log"), {
17445
17568
  flags: "a",
17446
17569
  mode: 384
@@ -18015,7 +18138,7 @@ ${result.formatted}` : "Thread is empty or not found."
18015
18138
  };
18016
18139
  }
18017
18140
  size = stat2.size;
18018
- bytes = readFileSync5(resolvedPath);
18141
+ bytes = readFileSync6(resolvedPath);
18019
18142
  } catch (err) {
18020
18143
  return {
18021
18144
  content: [{ type: "text", text: `Failed to read file: ${err.message}` }],
@@ -18653,8 +18776,8 @@ async function downloadSlackFile(fileId, codeName) {
18653
18776
  if (!isPathInside(savedPath, dir)) {
18654
18777
  throw new Error(`refusing to write ${savedPath} outside ${dir}`);
18655
18778
  }
18656
- mkdirSync4(dir, { recursive: true });
18657
- writeFileSync4(savedPath, bytes, { mode: 384 });
18779
+ mkdirSync5(dir, { recursive: true });
18780
+ writeFileSync5(savedPath, bytes, { mode: 384 });
18658
18781
  try {
18659
18782
  chmodSync(savedPath, 384);
18660
18783
  } catch {
@@ -18765,7 +18888,18 @@ async function connectSocketMode() {
18765
18888
  process.stderr.write("slack-channel: Socket Mode connected\n");
18766
18889
  recordActivity("connect");
18767
18890
  void setBotStatus(":large_green_circle:", "Active");
18768
- void notifyStrandedInboundsOnFirstConnect();
18891
+ if (!firstConnectNoticesGated) {
18892
+ firstConnectNoticesGated = true;
18893
+ suppressStrandedForBoot = SLACK_RESTART_CONFIRM_FILE != null && shouldPostRestartConfirm(
18894
+ readRestartConfirmMarker(SLACK_RESTART_CONFIRM_FILE),
18895
+ SLACK_PROCESS_BOOT_MS,
18896
+ Date.now()
18897
+ );
18898
+ }
18899
+ if (!suppressStrandedForBoot) {
18900
+ void notifyStrandedInboundsOnFirstConnect();
18901
+ }
18902
+ void notifyRestartCompleteOnFirstConnect();
18769
18903
  void applyBotPhotoOnFirstConnect();
18770
18904
  };
18771
18905
  ws.onmessage = async (event) => {
@@ -18878,13 +19012,16 @@ async function connectSocketMode() {
18878
19012
  });
18879
19013
  return;
18880
19014
  }
19015
+ const resolvedName = await resolveUserName(evt.user);
19016
+ const requesterName = resolvedName && resolvedName !== evt.user ? resolvedName : void 0;
18881
19017
  await handleRestartCommand({
18882
19018
  channel: evt.channel ?? "",
18883
19019
  // Only carry thread_ts when the originating message was already
18884
19020
  // threaded; a top-level command acks in-channel rather than
18885
19021
  // synthesising a brand-new thread (CodeRabbit feedback).
18886
19022
  threadTs: evt.thread_ts,
18887
- ts: evt.ts ?? ""
19023
+ ts: evt.ts ?? "",
19024
+ requesterName
18888
19025
  });
18889
19026
  return;
18890
19027
  }