@integrity-labs/agt-cli 0.26.1 → 0.26.2-eng5706.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/mcp/index.js CHANGED
@@ -21057,10 +21057,12 @@ import { spawn } from "child_process";
21057
21057
  var DeliveryTargetSchema = external_exports.union([
21058
21058
  external_exports.object({
21059
21059
  kind: external_exports.literal("channel"),
21060
- provider: external_exports.enum(["slack", "telegram"]),
21060
+ provider: external_exports.enum(["slack", "telegram", "msteams"]),
21061
21061
  channel_id: external_exports.string().optional(),
21062
- chat_id: external_exports.string().optional()
21063
- }).describe("Post to a Slack channel or Telegram chat. Provide channel_id for Slack or chat_id for Telegram."),
21062
+ chat_id: external_exports.string().optional(),
21063
+ conversation_id: external_exports.string().optional(),
21064
+ service_url: external_exports.string().optional()
21065
+ }).describe("Post to a Slack channel, Telegram chat, or Microsoft Teams conversation. Provide channel_id for Slack, chat_id for Telegram, or conversation_id + service_url for Teams."),
21064
21066
  external_exports.object({
21065
21067
  kind: external_exports.literal("dm"),
21066
21068
  person_id: external_exports.string().uuid(),
@@ -14891,17 +14891,17 @@ var StdioServerTransport = class {
14891
14891
  import {
14892
14892
  chmodSync,
14893
14893
  createWriteStream,
14894
- existsSync,
14895
- mkdirSync as mkdirSync2,
14896
- readFileSync as readFileSync2,
14894
+ existsSync as existsSync2,
14895
+ mkdirSync as mkdirSync3,
14896
+ readFileSync as readFileSync3,
14897
14897
  readdirSync,
14898
- renameSync,
14898
+ renameSync as renameSync2,
14899
14899
  statSync,
14900
- unlinkSync,
14900
+ unlinkSync as unlinkSync2,
14901
14901
  watch,
14902
- writeFileSync as writeFileSync2
14902
+ writeFileSync as writeFileSync3
14903
14903
  } from "fs";
14904
- import { basename, join as join2, resolve as resolve2 } from "path";
14904
+ import { basename, join as join3, resolve as resolve2 } from "path";
14905
14905
  import { homedir as homedir2 } from "os";
14906
14906
  import { createHash, randomUUID as randomUUID2 } from "crypto";
14907
14907
 
@@ -15607,6 +15607,75 @@ function createSlackBotUserIdClient(args) {
15607
15607
  };
15608
15608
  }
15609
15609
 
15610
+ // src/slack-spawn-lock.ts
15611
+ import {
15612
+ existsSync,
15613
+ mkdirSync as mkdirSync2,
15614
+ readFileSync as readFileSync2,
15615
+ renameSync,
15616
+ unlinkSync,
15617
+ writeFileSync as writeFileSync2
15618
+ } from "fs";
15619
+ import { join as join2 } from "path";
15620
+ var DEFAULT_LOCK_BASENAME = "slack-channel.lock";
15621
+ function defaultIsPidAlive(pid) {
15622
+ if (!Number.isFinite(pid) || pid <= 0) return false;
15623
+ try {
15624
+ process.kill(pid, 0);
15625
+ return true;
15626
+ } catch (err) {
15627
+ const code = err.code;
15628
+ if (code === "ESRCH") return false;
15629
+ return true;
15630
+ }
15631
+ }
15632
+ function acquireSlackSpawnLock(slackAgentDir, opts = {}) {
15633
+ if (!slackAgentDir) return { kind: "no-agent-dir" };
15634
+ const isPidAlive = opts.isPidAlive ?? defaultIsPidAlive;
15635
+ const selfPid = opts.selfPid ?? process.pid;
15636
+ const now = opts.now ?? (() => (/* @__PURE__ */ new Date()).toISOString());
15637
+ const path = join2(slackAgentDir, DEFAULT_LOCK_BASENAME);
15638
+ const existing = readLockHolder(path);
15639
+ if (existing) {
15640
+ if (existing.pid === selfPid) {
15641
+ return { kind: "acquired", path };
15642
+ }
15643
+ if (isPidAlive(existing.pid)) {
15644
+ return { kind: "blocked", path, holder: existing };
15645
+ }
15646
+ }
15647
+ mkdirSync2(slackAgentDir, { recursive: true, mode: 448 });
15648
+ const tmpPath = `${path}.${selfPid}.tmp`;
15649
+ const payload = { pid: selfPid, started_at: now() };
15650
+ writeFileSync2(tmpPath, JSON.stringify(payload), { mode: 384 });
15651
+ renameSync(tmpPath, path);
15652
+ return { kind: "acquired", path };
15653
+ }
15654
+ function releaseSlackSpawnLock(lockPath, opts = {}) {
15655
+ if (!lockPath) return;
15656
+ const selfPid = opts.selfPid ?? process.pid;
15657
+ const existing = readLockHolder(lockPath);
15658
+ if (!existing) return;
15659
+ if (existing.pid !== selfPid) return;
15660
+ try {
15661
+ unlinkSync(lockPath);
15662
+ } catch {
15663
+ }
15664
+ }
15665
+ function readLockHolder(path) {
15666
+ if (!existsSync(path)) return null;
15667
+ try {
15668
+ const raw = readFileSync2(path, "utf8");
15669
+ const parsed = JSON.parse(raw);
15670
+ const pid = typeof parsed.pid === "number" ? parsed.pid : Number(parsed.pid);
15671
+ if (!Number.isFinite(pid) || pid <= 0) return null;
15672
+ const startedAt = typeof parsed.started_at === "string" ? parsed.started_at : "";
15673
+ return { pid, started_at: startedAt };
15674
+ } catch {
15675
+ return null;
15676
+ }
15677
+ }
15678
+
15610
15679
  // src/slack-channel.ts
15611
15680
  var BOT_TOKEN = process.env.SLACK_BOT_TOKEN;
15612
15681
  var APP_TOKEN = process.env.SLACK_APP_TOKEN;
@@ -15658,9 +15727,9 @@ var SLACK_PEER_CLASSIFIER_CONFIG = {
15658
15727
  peers: parsePeersEnv(process.env.SLACK_PEERS, process.env.SLACK_PEERS_GATE),
15659
15728
  peer_disabled_mode: SLACK_PEER_DISABLED_MODE
15660
15729
  };
15661
- var SLACK_AGENT_DIR = AGENT_CODE_NAME ? join2(homedir2(), ".augmented", AGENT_CODE_NAME) : null;
15662
- var SLACK_PENDING_INBOUND_DIR = SLACK_AGENT_DIR ? join2(SLACK_AGENT_DIR, "slack-pending-inbound") : null;
15663
- var SLACK_RECOVERY_OUTBOX_DIR = SLACK_AGENT_DIR ? join2(SLACK_AGENT_DIR, "slack-recovery-outbox") : null;
15730
+ var SLACK_AGENT_DIR = AGENT_CODE_NAME ? join3(homedir2(), ".augmented", AGENT_CODE_NAME) : null;
15731
+ var SLACK_PENDING_INBOUND_DIR = SLACK_AGENT_DIR ? join3(SLACK_AGENT_DIR, "slack-pending-inbound") : null;
15732
+ var SLACK_RECOVERY_OUTBOX_DIR = SLACK_AGENT_DIR ? join3(SLACK_AGENT_DIR, "slack-recovery-outbox") : null;
15664
15733
  var SLACK_MAX_RECOVERY_ATTEMPTS = 3;
15665
15734
  function redactSlackId(id) {
15666
15735
  if (!id) return "<none>";
@@ -15672,7 +15741,7 @@ function safeSlackMarkerName(channel, threadTs, messageTs) {
15672
15741
  }
15673
15742
  function slackPendingInboundPath(channel, threadTs, messageTs) {
15674
15743
  if (!SLACK_PENDING_INBOUND_DIR) return null;
15675
- return join2(SLACK_PENDING_INBOUND_DIR, safeSlackMarkerName(channel, threadTs, messageTs));
15744
+ return join3(SLACK_PENDING_INBOUND_DIR, safeSlackMarkerName(channel, threadTs, messageTs));
15676
15745
  }
15677
15746
  function writeSlackPendingInboundMarker(channel, threadTs, messageTs) {
15678
15747
  const path = slackPendingInboundPath(channel, threadTs, messageTs);
@@ -15684,8 +15753,8 @@ function writeSlackPendingInboundMarker(channel, threadTs, messageTs) {
15684
15753
  received_at: (/* @__PURE__ */ new Date()).toISOString()
15685
15754
  };
15686
15755
  try {
15687
- mkdirSync2(SLACK_PENDING_INBOUND_DIR, { recursive: true, mode: 448 });
15688
- writeFileSync2(path, JSON.stringify(marker), { mode: 384 });
15756
+ mkdirSync3(SLACK_PENDING_INBOUND_DIR, { recursive: true, mode: 448 });
15757
+ writeFileSync3(path, JSON.stringify(marker), { mode: 384 });
15689
15758
  } catch (err) {
15690
15759
  process.stderr.write(
15691
15760
  `slack-channel(${AGENT_CODE_NAME}): pending-inbound marker write failed: ${err.message}
@@ -15702,7 +15771,7 @@ function clearAllSlackPendingMarkersForThread(channel, threadTs) {
15702
15771
  for (const f of readdirSync(SLACK_PENDING_INBOUND_DIR)) {
15703
15772
  if (!f.startsWith(prefix) || !f.endsWith(".json")) continue;
15704
15773
  try {
15705
- unlinkSync(join2(SLACK_PENDING_INBOUND_DIR, f));
15774
+ unlinkSync2(join3(SLACK_PENDING_INBOUND_DIR, f));
15706
15775
  } catch {
15707
15776
  }
15708
15777
  }
@@ -15723,17 +15792,17 @@ function slackNextRetryName(filename) {
15723
15792
  async function processSlackRecoveryOutboxFile(filename) {
15724
15793
  if (!SLACK_RECOVERY_OUTBOX_DIR) return;
15725
15794
  if (filename.endsWith(".poison.json") || filename.endsWith(".tmp")) return;
15726
- const fullPath = join2(SLACK_RECOVERY_OUTBOX_DIR, filename);
15795
+ const fullPath = join3(SLACK_RECOVERY_OUTBOX_DIR, filename);
15727
15796
  let payload;
15728
15797
  try {
15729
- payload = JSON.parse(readFileSync2(fullPath, "utf-8"));
15798
+ payload = JSON.parse(readFileSync3(fullPath, "utf-8"));
15730
15799
  } catch (err) {
15731
15800
  process.stderr.write(
15732
15801
  `slack-channel(${AGENT_CODE_NAME}): recovery outbox parse failed (${filename}): ${err.message}
15733
15802
  `
15734
15803
  );
15735
15804
  try {
15736
- renameSync(fullPath, `${fullPath}.parse-error.poison`);
15805
+ renameSync2(fullPath, `${fullPath}.parse-error.poison`);
15737
15806
  } catch {
15738
15807
  }
15739
15808
  return;
@@ -15744,7 +15813,7 @@ async function processSlackRecoveryOutboxFile(filename) {
15744
15813
  `
15745
15814
  );
15746
15815
  try {
15747
- renameSync(fullPath, `${fullPath}.malformed.poison`);
15816
+ renameSync2(fullPath, `${fullPath}.malformed.poison`);
15748
15817
  } catch {
15749
15818
  }
15750
15819
  return;
@@ -15792,7 +15861,7 @@ async function processSlackRecoveryOutboxFile(filename) {
15792
15861
  }
15793
15862
  if (sendSucceeded) {
15794
15863
  try {
15795
- unlinkSync(fullPath);
15864
+ unlinkSync2(fullPath);
15796
15865
  } catch {
15797
15866
  }
15798
15867
  return;
@@ -15800,7 +15869,7 @@ async function processSlackRecoveryOutboxFile(filename) {
15800
15869
  const next = slackNextRetryName(filename);
15801
15870
  if (next) {
15802
15871
  try {
15803
- renameSync(fullPath, join2(SLACK_RECOVERY_OUTBOX_DIR, next.next));
15872
+ renameSync2(fullPath, join3(SLACK_RECOVERY_OUTBOX_DIR, next.next));
15804
15873
  if (next.attempt >= SLACK_MAX_RECOVERY_ATTEMPTS) {
15805
15874
  process.stderr.write(
15806
15875
  `slack-channel(${AGENT_CODE_NAME}): ghost-reply recovery exhausted retries \u2014 moved to ${next.next}
@@ -15839,7 +15908,7 @@ function scanSlackRecoveryRetries() {
15839
15908
  if (!f.includes(".retry-") || f.endsWith(".poison.json")) continue;
15840
15909
  let mtimeMs;
15841
15910
  try {
15842
- mtimeMs = statSync(join2(SLACK_RECOVERY_OUTBOX_DIR, f)).mtimeMs;
15911
+ mtimeMs = statSync(join3(SLACK_RECOVERY_OUTBOX_DIR, f)).mtimeMs;
15843
15912
  } catch {
15844
15913
  continue;
15845
15914
  }
@@ -15851,7 +15920,7 @@ function scanSlackRecoveryRetries() {
15851
15920
  function startSlackRecoveryOutboxWatcher() {
15852
15921
  if (!SLACK_RECOVERY_OUTBOX_DIR) return;
15853
15922
  try {
15854
- mkdirSync2(SLACK_RECOVERY_OUTBOX_DIR, { recursive: true, mode: 448 });
15923
+ mkdirSync3(SLACK_RECOVERY_OUTBOX_DIR, { recursive: true, mode: 448 });
15855
15924
  } catch (err) {
15856
15925
  process.stderr.write(
15857
15926
  `slack-channel(${AGENT_CODE_NAME}): recovery outbox mkdir failed: ${err.message}
@@ -15869,7 +15938,7 @@ function startSlackRecoveryOutboxWatcher() {
15869
15938
  const watcher = watch(SLACK_RECOVERY_OUTBOX_DIR, (event, filename) => {
15870
15939
  if (event !== "rename" || !filename) return;
15871
15940
  if (!isFirstAttemptSlackOutboxFile(filename)) return;
15872
- if (existsSync(join2(SLACK_RECOVERY_OUTBOX_DIR, filename))) {
15941
+ if (existsSync2(join3(SLACK_RECOVERY_OUTBOX_DIR, filename))) {
15873
15942
  void processSlackRecoveryOutboxFile(filename);
15874
15943
  }
15875
15944
  });
@@ -15890,7 +15959,7 @@ function trackPendingMessage(channel, threadTs, messageTs) {
15890
15959
  }
15891
15960
  function sweepSlackStaleMarkersOnBoot() {
15892
15961
  if (!SLACK_PENDING_INBOUND_DIR) return;
15893
- if (!existsSync(SLACK_PENDING_INBOUND_DIR)) return;
15962
+ if (!existsSync2(SLACK_PENDING_INBOUND_DIR)) return;
15894
15963
  let filenames;
15895
15964
  try {
15896
15965
  filenames = readdirSync(SLACK_PENDING_INBOUND_DIR);
@@ -15906,17 +15975,17 @@ function sweepSlackStaleMarkersOnBoot() {
15906
15975
  for (const filename of filenames) {
15907
15976
  if (!filename.endsWith(".json")) continue;
15908
15977
  if (filename.endsWith(".tmp")) continue;
15909
- const fullPath = join2(SLACK_PENDING_INBOUND_DIR, filename);
15978
+ const fullPath = join3(SLACK_PENDING_INBOUND_DIR, filename);
15910
15979
  let marker;
15911
15980
  try {
15912
- marker = JSON.parse(readFileSync2(fullPath, "utf-8"));
15981
+ marker = JSON.parse(readFileSync3(fullPath, "utf-8"));
15913
15982
  } catch (err) {
15914
15983
  process.stderr.write(
15915
15984
  `slack-channel(${AGENT_CODE_NAME}): stale-marker parse failed for ${redactSlackId(filename)}: ${err.message}
15916
15985
  `
15917
15986
  );
15918
15987
  try {
15919
- unlinkSync(fullPath);
15988
+ unlinkSync2(fullPath);
15920
15989
  } catch {
15921
15990
  }
15922
15991
  cleared++;
@@ -15925,7 +15994,7 @@ function sweepSlackStaleMarkersOnBoot() {
15925
15994
  const { channel, thread_ts, message_ts, received_at } = marker;
15926
15995
  if (!channel || !thread_ts || !message_ts || !received_at) {
15927
15996
  try {
15928
- unlinkSync(fullPath);
15997
+ unlinkSync2(fullPath);
15929
15998
  } catch {
15930
15999
  }
15931
16000
  cleared++;
@@ -15934,7 +16003,7 @@ function sweepSlackStaleMarkersOnBoot() {
15934
16003
  const receivedAtMs = Date.parse(received_at);
15935
16004
  if (!Number.isFinite(receivedAtMs) || receivedAtMs > now || now - receivedAtMs > STALE_MARKER_MS) {
15936
16005
  try {
15937
- unlinkSync(fullPath);
16006
+ unlinkSync2(fullPath);
15938
16007
  } catch {
15939
16008
  }
15940
16009
  cleared++;
@@ -15959,7 +16028,7 @@ function noteThreadActivityByMessageTs(channel, messageTs) {
15959
16028
  if (!channel || !messageTs) return;
15960
16029
  clearPendingMessage(channel, messageTs);
15961
16030
  if (!SLACK_PENDING_INBOUND_DIR) return;
15962
- if (!existsSync(SLACK_PENDING_INBOUND_DIR)) return;
16031
+ if (!existsSync2(SLACK_PENDING_INBOUND_DIR)) return;
15963
16032
  let filenames;
15964
16033
  try {
15965
16034
  filenames = readdirSync(SLACK_PENDING_INBOUND_DIR);
@@ -15974,12 +16043,12 @@ function noteThreadActivityByMessageTs(channel, messageTs) {
15974
16043
  if (!filename.startsWith(channelPrefix)) continue;
15975
16044
  if (!filename.endsWith(messageSuffix)) continue;
15976
16045
  try {
15977
- unlinkSync(join2(SLACK_PENDING_INBOUND_DIR, filename));
16046
+ unlinkSync2(join3(SLACK_PENDING_INBOUND_DIR, filename));
15978
16047
  } catch {
15979
16048
  }
15980
16049
  }
15981
16050
  }
15982
- var RESTART_FLAGS_DIR = join2(homedir2(), ".augmented", "restart-flags");
16051
+ var RESTART_FLAGS_DIR = join3(homedir2(), ".augmented", "restart-flags");
15983
16052
  function hashChannelId(id) {
15984
16053
  return createHash("sha256").update(id).digest("hex").slice(0, 8);
15985
16054
  }
@@ -16146,10 +16215,10 @@ async function handleSlashCommandEnvelope(payload) {
16146
16215
  return;
16147
16216
  }
16148
16217
  try {
16149
- if (!existsSync(RESTART_FLAGS_DIR)) {
16150
- mkdirSync2(RESTART_FLAGS_DIR, { recursive: true });
16218
+ if (!existsSync2(RESTART_FLAGS_DIR)) {
16219
+ mkdirSync3(RESTART_FLAGS_DIR, { recursive: true });
16151
16220
  }
16152
- const flagPath = join2(RESTART_FLAGS_DIR, `${codeName}.flag`);
16221
+ const flagPath = join3(RESTART_FLAGS_DIR, `${codeName}.flag`);
16153
16222
  const flag = {
16154
16223
  codeName,
16155
16224
  source: "slack",
@@ -16160,8 +16229,8 @@ async function handleSlashCommandEnvelope(payload) {
16160
16229
  }
16161
16230
  };
16162
16231
  const tmpPath = `${flagPath}.${process.pid}.${randomUUID2()}.tmp`;
16163
- writeFileSync2(tmpPath, JSON.stringify(flag) + "\n", "utf8");
16164
- renameSync(tmpPath, flagPath);
16232
+ writeFileSync3(tmpPath, JSON.stringify(flag) + "\n", "utf8");
16233
+ renameSync2(tmpPath, flagPath);
16165
16234
  process.stderr.write(
16166
16235
  `slack-channel(${codeName}): /restart slash-command queued from channel ${hashChannelId(payload.channel_id)}
16167
16236
  `
@@ -16253,10 +16322,10 @@ async function handleHelpCommand(opts) {
16253
16322
  async function handleRestartCommand(opts) {
16254
16323
  const codeName = AGENT_CODE_NAME ?? "unknown";
16255
16324
  try {
16256
- if (!existsSync(RESTART_FLAGS_DIR)) {
16257
- mkdirSync2(RESTART_FLAGS_DIR, { recursive: true });
16325
+ if (!existsSync2(RESTART_FLAGS_DIR)) {
16326
+ mkdirSync3(RESTART_FLAGS_DIR, { recursive: true });
16258
16327
  }
16259
- const flagPath = join2(RESTART_FLAGS_DIR, `${codeName}.flag`);
16328
+ const flagPath = join3(RESTART_FLAGS_DIR, `${codeName}.flag`);
16260
16329
  const flag = {
16261
16330
  codeName,
16262
16331
  source: "slack",
@@ -16268,8 +16337,8 @@ async function handleRestartCommand(opts) {
16268
16337
  }
16269
16338
  };
16270
16339
  const tmpPath = `${flagPath}.${process.pid}.${randomUUID2()}.tmp`;
16271
- writeFileSync2(tmpPath, JSON.stringify(flag) + "\n", "utf8");
16272
- renameSync(tmpPath, flagPath);
16340
+ writeFileSync3(tmpPath, JSON.stringify(flag) + "\n", "utf8");
16341
+ renameSync2(tmpPath, flagPath);
16273
16342
  process.stderr.write(
16274
16343
  `slack-channel(${codeName}): /restart queued from channel ${hashChannelId(opts.channel)}
16275
16344
  `
@@ -16315,7 +16384,7 @@ var THREAD_STORE_TTL_DAYS = parseTtlDays(process.env.SLACK_THREAD_FOLLOW_TTL_DAY
16315
16384
  var threadPersister = null;
16316
16385
  function resolveThreadStorePath() {
16317
16386
  if (!AGENT_CODE_NAME) return null;
16318
- return join2(homedir2(), ".augmented", AGENT_CODE_NAME, "slack-tracked-threads.json");
16387
+ return join3(homedir2(), ".augmented", AGENT_CODE_NAME, "slack-tracked-threads.json");
16319
16388
  }
16320
16389
  function parseTtlDays(raw) {
16321
16390
  if (!raw) return void 0;
@@ -16350,9 +16419,9 @@ if (!BOT_TOKEN || !APP_TOKEN) {
16350
16419
  var slackStderrLogStream = null;
16351
16420
  if (AGENT_CODE_NAME) {
16352
16421
  try {
16353
- const logDir = join2(homedir2(), ".augmented", AGENT_CODE_NAME);
16354
- mkdirSync2(logDir, { recursive: true });
16355
- slackStderrLogStream = createWriteStream(join2(logDir, "slack-channel-stderr.log"), {
16422
+ const logDir = join3(homedir2(), ".augmented", AGENT_CODE_NAME);
16423
+ mkdirSync3(logDir, { recursive: true });
16424
+ slackStderrLogStream = createWriteStream(join3(logDir, "slack-channel-stderr.log"), {
16356
16425
  flags: "a",
16357
16426
  mode: 384
16358
16427
  });
@@ -16965,7 +17034,7 @@ ${formatted}` : "Thread is empty or not found."
16965
17034
  };
16966
17035
  }
16967
17036
  size = stat.size;
16968
- bytes = readFileSync2(resolvedPath);
17037
+ bytes = readFileSync3(resolvedPath);
16969
17038
  } catch (err) {
16970
17039
  return {
16971
17040
  content: [{ type: "text", text: `Failed to read file: ${err.message}` }],
@@ -17683,8 +17752,8 @@ async function downloadSlackFile(fileId, codeName) {
17683
17752
  if (!isPathInside(savedPath, dir)) {
17684
17753
  throw new Error(`refusing to write ${savedPath} outside ${dir}`);
17685
17754
  }
17686
- mkdirSync2(dir, { recursive: true });
17687
- writeFileSync2(savedPath, bytes, { mode: 384 });
17755
+ mkdirSync3(dir, { recursive: true });
17756
+ writeFileSync3(savedPath, bytes, { mode: 384 });
17688
17757
  try {
17689
17758
  chmodSync(savedPath, 384);
17690
17759
  } catch {
@@ -17757,6 +17826,7 @@ async function resolveUserName(userId) {
17757
17826
  }
17758
17827
  var currentWs = null;
17759
17828
  var isShuttingDown = false;
17829
+ var acquiredLockPath = null;
17760
17830
  function connectSocketModeSafely() {
17761
17831
  void runOrRetry(connectSocketMode, {
17762
17832
  retryDelayMs: 1e4,
@@ -18062,6 +18132,10 @@ function shutdown(reason, exitCode = 0) {
18062
18132
  currentWs?.close();
18063
18133
  } catch {
18064
18134
  }
18135
+ try {
18136
+ releaseSlackSpawnLock(acquiredLockPath);
18137
+ } catch {
18138
+ }
18065
18139
  setTimeout(() => process.exit(exitCode), 500).unref();
18066
18140
  }
18067
18141
  process.stdin.on("close", () => shutdown("stdin closed"));
@@ -18074,6 +18148,18 @@ process.on("unhandledRejection", (reason) => {
18074
18148
  process.stderr.write(`slack-channel: unhandledRejection (continuing): ${msg}
18075
18149
  `);
18076
18150
  });
18151
+ {
18152
+ const lockResult = acquireSlackSpawnLock(SLACK_AGENT_DIR);
18153
+ if (lockResult.kind === "blocked") {
18154
+ process.stderr.write(
18155
+ `slack-channel: another instance pid=${lockResult.holder.pid} already running (since ${lockResult.holder.started_at}), exiting
18156
+ `
18157
+ );
18158
+ process.exit(0);
18159
+ } else if (lockResult.kind === "acquired") {
18160
+ acquiredLockPath = lockResult.path;
18161
+ }
18162
+ }
18077
18163
  if (THREAD_STORE_PATH) {
18078
18164
  const threadStoreLabel = "slack-tracked-threads.json";
18079
18165
  const redact = (msg) => msg.replaceAll(THREAD_STORE_PATH, threadStoreLabel);
@@ -20,8 +20,9 @@ import {
20
20
  stopPersistentSession,
21
21
  takeZombieDetection,
22
22
  writePersistentClaudeWrapper
23
- } from "./chunk-QJJAGFJJ.js";
24
- import "./chunk-7NDNTSHD.js";
23
+ } from "./chunk-QSDDP7JN.js";
24
+ import "./chunk-U3HCB23E.js";
25
+ import "./chunk-XWVM4KPK.js";
25
26
  export {
26
27
  _internals,
27
28
  collectDiagnostics,
@@ -45,4 +46,4 @@ export {
45
46
  takeZombieDetection,
46
47
  writePersistentClaudeWrapper
47
48
  };
48
- //# sourceMappingURL=persistent-session-E5EZ32CI.js.map
49
+ //# sourceMappingURL=persistent-session-K4X76LLB.js.map
@@ -1,7 +1,8 @@
1
1
  import {
2
2
  paneLogPath
3
- } from "./chunk-QJJAGFJJ.js";
4
- import "./chunk-7NDNTSHD.js";
3
+ } from "./chunk-QSDDP7JN.js";
4
+ import "./chunk-U3HCB23E.js";
5
+ import "./chunk-XWVM4KPK.js";
5
6
 
6
7
  // src/lib/responsiveness-probe.ts
7
8
  import { statSync } from "fs";
@@ -29,4 +30,4 @@ export {
29
30
  collectResponsivenessProbes,
30
31
  getResponsivenessIntervalMs
31
32
  };
32
- //# sourceMappingURL=responsiveness-probe-MLUVAXJH.js.map
33
+ //# sourceMappingURL=responsiveness-probe-QBV43SJ7.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/lib/responsiveness-probe.ts"],"sourcesContent":["/**\n * ENG-5399 — Tier 1 responsiveness probe (manager-side).\n *\n * Cheap, fast-cadence canary that catches \"agent went silent\" inside\n * minutes, well before the existing synthetic-probe cron's ~35 min\n * staleness window (`SyntheticReplyAgeSeconds`, ENG-5122).\n *\n * Mechanism: for each managed agent, read the mtime of the agent's\n * `pane.log` and report `now - mtime` as `PaneActivityAgeSeconds` via\n * a new `/host/responsiveness-probe` endpoint. `pane.log` is the\n * tmux pipe-pane sink set up by `setupPaneLog()` — any visible\n * activity (assistant turns, tool calls, in-place progress\n * heartbeats) bumps its mtime. A silent agent has a steadily\n * climbing age that lands in CloudWatch and trips a per-agent alarm.\n *\n * Run from `pollCycle()` in `manager-worker.ts` on a configurable\n * interval (default 5 min via `AUGMENTED_RESPONSIVENESS_INTERVAL_MS`).\n */\n\nimport { statSync } from 'node:fs';\nimport { paneLogPath } from './persistent-session.js';\n\nexport interface ResponsivenessProbeResult {\n code_name: string;\n pane_activity_age_seconds: number;\n}\n\nconst DEFAULT_INTERVAL_MS = 5 * 60 * 1000;\n\nexport function getResponsivenessIntervalMs(): number {\n const raw = process.env.AUGMENTED_RESPONSIVENESS_INTERVAL_MS;\n if (!raw) return DEFAULT_INTERVAL_MS;\n const parsed = Number.parseInt(raw, 10);\n return Number.isFinite(parsed) && parsed > 0 ? parsed : DEFAULT_INTERVAL_MS;\n}\n\n/**\n * Compute the pane.log age for each agent. Missing or unreadable\n * pane.log returns null — the caller should drop those entries\n * rather than fabricate a \"fresh\" or \"ancient\" value. A missing\n * file means the agent has never spawned in this manager generation,\n * which is a separate problem covered by SessionAliveAgeSeconds.\n */\nexport function collectResponsivenessProbes(\n codeNames: string[],\n now: Date = new Date(),\n): ResponsivenessProbeResult[] {\n const nowMs = now.getTime();\n const results: ResponsivenessProbeResult[] = [];\n for (const codeName of codeNames) {\n try {\n const mtimeMs = statSync(paneLogPath(codeName)).mtimeMs;\n const ageSeconds = Math.max(0, Math.floor((nowMs - mtimeMs) / 1000));\n results.push({ code_name: codeName, pane_activity_age_seconds: ageSeconds });\n } catch {\n // No pane.log yet (fresh agent, never spawned) — skip. The\n // session-alive monitor already covers the \"should be running\n // but isn't\" case.\n }\n }\n return results;\n}\n"],"mappings":";;;;;;AAmBA,SAAS,gBAAgB;AAQzB,IAAM,sBAAsB,IAAI,KAAK;AAE9B,SAAS,8BAAsC;AACpD,QAAM,MAAM,QAAQ,IAAI;AACxB,MAAI,CAAC,IAAK,QAAO;AACjB,QAAM,SAAS,OAAO,SAAS,KAAK,EAAE;AACtC,SAAO,OAAO,SAAS,MAAM,KAAK,SAAS,IAAI,SAAS;AAC1D;AASO,SAAS,4BACd,WACA,MAAY,oBAAI,KAAK,GACQ;AAC7B,QAAM,QAAQ,IAAI,QAAQ;AAC1B,QAAM,UAAuC,CAAC;AAC9C,aAAW,YAAY,WAAW;AAChC,QAAI;AACF,YAAM,UAAU,SAAS,YAAY,QAAQ,CAAC,EAAE;AAChD,YAAM,aAAa,KAAK,IAAI,GAAG,KAAK,OAAO,QAAQ,WAAW,GAAI,CAAC;AACnE,cAAQ,KAAK,EAAE,WAAW,UAAU,2BAA2B,WAAW,CAAC;AAAA,IAC7E,QAAQ;AAAA,IAIR;AAAA,EACF;AACA,SAAO;AACT;","names":[]}
1
+ {"version":3,"sources":["../src/lib/responsiveness-probe.ts"],"sourcesContent":["/**\n * ENG-5399 — Tier 1 responsiveness probe (manager-side).\n *\n * Cheap, fast-cadence canary that catches \"agent went silent\" inside\n * minutes, well before the existing synthetic-probe cron's ~35 min\n * staleness window (`SyntheticReplyAgeSeconds`, ENG-5122).\n *\n * Mechanism: for each managed agent, read the mtime of the agent's\n * `pane.log` and report `now - mtime` as `PaneActivityAgeSeconds` via\n * a new `/host/responsiveness-probe` endpoint. `pane.log` is the\n * tmux pipe-pane sink set up by `setupPaneLog()` — any visible\n * activity (assistant turns, tool calls, in-place progress\n * heartbeats) bumps its mtime. A silent agent has a steadily\n * climbing age that lands in CloudWatch and trips a per-agent alarm.\n *\n * Run from `pollCycle()` in `manager-worker.ts` on a configurable\n * interval (default 5 min via `AUGMENTED_RESPONSIVENESS_INTERVAL_MS`).\n */\n\nimport { statSync } from 'node:fs';\nimport { paneLogPath } from './persistent-session.js';\n\nexport interface ResponsivenessProbeResult {\n code_name: string;\n pane_activity_age_seconds: number;\n}\n\nconst DEFAULT_INTERVAL_MS = 5 * 60 * 1000;\n\nexport function getResponsivenessIntervalMs(): number {\n const raw = process.env.AUGMENTED_RESPONSIVENESS_INTERVAL_MS;\n if (!raw) return DEFAULT_INTERVAL_MS;\n const parsed = Number.parseInt(raw, 10);\n return Number.isFinite(parsed) && parsed > 0 ? parsed : DEFAULT_INTERVAL_MS;\n}\n\n/**\n * Compute the pane.log age for each agent. Missing or unreadable\n * pane.log returns null — the caller should drop those entries\n * rather than fabricate a \"fresh\" or \"ancient\" value. A missing\n * file means the agent has never spawned in this manager generation,\n * which is a separate problem covered by SessionAliveAgeSeconds.\n */\nexport function collectResponsivenessProbes(\n codeNames: string[],\n now: Date = new Date(),\n): ResponsivenessProbeResult[] {\n const nowMs = now.getTime();\n const results: ResponsivenessProbeResult[] = [];\n for (const codeName of codeNames) {\n try {\n const mtimeMs = statSync(paneLogPath(codeName)).mtimeMs;\n const ageSeconds = Math.max(0, Math.floor((nowMs - mtimeMs) / 1000));\n results.push({ code_name: codeName, pane_activity_age_seconds: ageSeconds });\n } catch {\n // No pane.log yet (fresh agent, never spawned) — skip. The\n // session-alive monitor already covers the \"should be running\n // but isn't\" case.\n }\n }\n return results;\n}\n"],"mappings":";;;;;;;AAmBA,SAAS,gBAAgB;AAQzB,IAAM,sBAAsB,IAAI,KAAK;AAE9B,SAAS,8BAAsC;AACpD,QAAM,MAAM,QAAQ,IAAI;AACxB,MAAI,CAAC,IAAK,QAAO;AACjB,QAAM,SAAS,OAAO,SAAS,KAAK,EAAE;AACtC,SAAO,OAAO,SAAS,MAAM,KAAK,SAAS,IAAI,SAAS;AAC1D;AASO,SAAS,4BACd,WACA,MAAY,oBAAI,KAAK,GACQ;AAC7B,QAAM,QAAQ,IAAI,QAAQ;AAC1B,QAAM,UAAuC,CAAC;AAC9C,aAAW,YAAY,WAAW;AAChC,QAAI;AACF,YAAM,UAAU,SAAS,YAAY,QAAQ,CAAC,EAAE;AAChD,YAAM,aAAa,KAAK,IAAI,GAAG,KAAK,OAAO,QAAQ,WAAW,GAAI,CAAC;AACnE,cAAQ,KAAK,EAAE,WAAW,UAAU,2BAA2B,WAAW,CAAC;AAAA,IAC7E,QAAQ;AAAA,IAIR;AAAA,EACF;AACA,SAAO;AACT;","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@integrity-labs/agt-cli",
3
- "version": "0.26.1",
3
+ "version": "0.26.2-eng5706.1",
4
4
  "description": "Augmented Team CLI — agent provisioning and management",
5
5
  "type": "module",
6
6
  "engines": {