@integrity-labs/agt-cli 0.26.2-eng5706.1 → 0.27.0-test.4

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.
@@ -13982,6 +13982,75 @@ function createDirectChatProgressFlush(opts) {
13982
13982
  };
13983
13983
  }
13984
13984
 
13985
+ // src/inbound-context-client.ts
13986
+ var REQUEST_TIMEOUT_MS = 1e4;
13987
+ function createInboundContextClient(args) {
13988
+ if (!args.agtHost || !args.agtApiKey || !args.agentId) return null;
13989
+ const fetchImpl = args.fetchImpl ?? fetch;
13990
+ const log = args.log ?? (() => {
13991
+ });
13992
+ const base = args.agtHost.replace(/\/+$/, "");
13993
+ const agentId = args.agentId;
13994
+ const apiKey = args.agtApiKey;
13995
+ let cachedToken = null;
13996
+ let cachedTokenExpiresAt = 0;
13997
+ async function getToken() {
13998
+ if (cachedToken && Date.now() < cachedTokenExpiresAt) return cachedToken;
13999
+ const resp = await fetchImpl(`${base}/host/exchange`, {
14000
+ method: "POST",
14001
+ headers: { "Content-Type": "application/json" },
14002
+ body: JSON.stringify({ host_key: apiKey }),
14003
+ signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS)
14004
+ });
14005
+ if (!resp.ok) {
14006
+ const body = await resp.text().catch(() => "");
14007
+ throw new Error(`/host/exchange failed (${resp.status}): ${body.slice(0, 200)}`);
14008
+ }
14009
+ const data = await resp.json();
14010
+ cachedToken = data.token;
14011
+ cachedTokenExpiresAt = data.expires_at ? new Date(data.expires_at).getTime() - 12e4 : Date.now() + 55 * 6e4;
14012
+ return cachedToken;
14013
+ }
14014
+ async function postOnce(body) {
14015
+ const token = await getToken();
14016
+ return fetchImpl(`${base}/host/inbound-context`, {
14017
+ method: "POST",
14018
+ headers: { Authorization: `Bearer ${token}`, "Content-Type": "application/json" },
14019
+ body: JSON.stringify(body),
14020
+ signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS)
14021
+ });
14022
+ }
14023
+ async function emit(args2) {
14024
+ const body = {
14025
+ agent_id: agentId,
14026
+ source_integration: args2.sourceIntegration,
14027
+ source_external_id: args2.sourceExternalId,
14028
+ ...args2.sourceUrl ? { source_url: args2.sourceUrl } : {}
14029
+ };
14030
+ try {
14031
+ let resp = await postOnce(body);
14032
+ if (resp.status === 401) {
14033
+ cachedToken = null;
14034
+ cachedTokenExpiresAt = 0;
14035
+ resp = await postOnce(body);
14036
+ }
14037
+ if (!resp.ok) {
14038
+ const text = await resp.text().catch(() => "");
14039
+ log(
14040
+ `inbound-context: POST failed (${resp.status}) integration=${args2.sourceIntegration}: ${text.slice(0, 200)}`
14041
+ );
14042
+ }
14043
+ } catch (err) {
14044
+ log(`inbound-context: emit threw integration=${args2.sourceIntegration}: ${err.message}`);
14045
+ }
14046
+ }
14047
+ return {
14048
+ recordInbound(args2) {
14049
+ void emit(args2);
14050
+ }
14051
+ };
14052
+ }
14053
+
13985
14054
  // src/progress-tools.ts
13986
14055
  import { randomUUID } from "crypto";
13987
14056
 
@@ -14299,10 +14368,89 @@ function isMode(value) {
14299
14368
  return value === "thinking" || value === "working" || value === "waiting";
14300
14369
  }
14301
14370
 
14371
+ // src/mcp-spawn-lock.ts
14372
+ import {
14373
+ existsSync,
14374
+ mkdirSync,
14375
+ readFileSync,
14376
+ renameSync,
14377
+ unlinkSync,
14378
+ writeFileSync
14379
+ } from "fs";
14380
+ import { join } from "path";
14381
+ function defaultIsPidAlive(pid) {
14382
+ if (!Number.isFinite(pid) || pid <= 0) return false;
14383
+ try {
14384
+ process.kill(pid, 0);
14385
+ return true;
14386
+ } catch (err) {
14387
+ const code = err.code;
14388
+ if (code === "ESRCH") return false;
14389
+ return true;
14390
+ }
14391
+ }
14392
+ function acquireMcpSpawnLock(args) {
14393
+ const { agentDir, basename, options = {} } = args;
14394
+ if (!agentDir) return { kind: "no-agent-dir" };
14395
+ const isPidAlive = options.isPidAlive ?? defaultIsPidAlive;
14396
+ const selfPid = options.selfPid ?? process.pid;
14397
+ const now = options.now ?? (() => (/* @__PURE__ */ new Date()).toISOString());
14398
+ const path = join(agentDir, basename);
14399
+ const existing = readLockHolder(path);
14400
+ if (existing) {
14401
+ if (existing.pid === selfPid) {
14402
+ return { kind: "acquired", path };
14403
+ }
14404
+ if (isPidAlive(existing.pid)) {
14405
+ return { kind: "blocked", path, holder: existing };
14406
+ }
14407
+ }
14408
+ mkdirSync(agentDir, { recursive: true, mode: 448 });
14409
+ const tmpPath = `${path}.${selfPid}.tmp`;
14410
+ const payload = { pid: selfPid, started_at: now() };
14411
+ writeFileSync(tmpPath, JSON.stringify(payload), { mode: 384 });
14412
+ renameSync(tmpPath, path);
14413
+ return { kind: "acquired", path };
14414
+ }
14415
+ function releaseMcpSpawnLock(lockPath, opts = {}) {
14416
+ if (!lockPath) return;
14417
+ const selfPid = opts.selfPid ?? process.pid;
14418
+ const existing = readLockHolder(lockPath);
14419
+ if (!existing) return;
14420
+ if (existing.pid !== selfPid) return;
14421
+ try {
14422
+ unlinkSync(lockPath);
14423
+ } catch {
14424
+ }
14425
+ }
14426
+ function readLockHolder(path) {
14427
+ if (!existsSync(path)) return null;
14428
+ try {
14429
+ const raw = readFileSync(path, "utf8");
14430
+ const parsed = JSON.parse(raw);
14431
+ const pid = typeof parsed.pid === "number" ? parsed.pid : Number(parsed.pid);
14432
+ if (!Number.isFinite(pid) || pid <= 0) return null;
14433
+ const startedAt = typeof parsed.started_at === "string" ? parsed.started_at : "";
14434
+ return { pid, started_at: startedAt };
14435
+ } catch {
14436
+ return null;
14437
+ }
14438
+ }
14439
+
14302
14440
  // src/direct-chat-channel.ts
14441
+ import { homedir } from "os";
14442
+ import { join as join2 } from "path";
14303
14443
  var AGT_HOST = process.env.AGT_HOST;
14304
14444
  var AGT_API_KEY = process.env.AGT_API_KEY;
14305
14445
  var AGT_AGENT_ID = process.env.AGT_AGENT_ID;
14446
+ var DIRECT_CHAT_AGENT_DIR = AGT_AGENT_ID ? join2(homedir(), ".augmented", AGT_AGENT_ID) : null;
14447
+ var inboundContextClient = createInboundContextClient({
14448
+ agtHost: AGT_HOST ?? null,
14449
+ agtApiKey: AGT_API_KEY ?? null,
14450
+ agentId: AGT_AGENT_ID ?? null,
14451
+ log: (line) => process.stderr.write(`direct-chat-channel: ${line}
14452
+ `)
14453
+ });
14306
14454
  if (!AGT_HOST || !AGT_API_KEY || !AGT_AGENT_ID) {
14307
14455
  process.stderr.write(
14308
14456
  "direct-chat-channel: Missing AGT_HOST, AGT_API_KEY, or AGT_AGENT_ID. Cannot start.\n"
@@ -14488,6 +14636,22 @@ mcp.setRequestHandler(CallToolRequestSchema, async (req) => {
14488
14636
  throw new Error(`Unknown tool: ${name}`);
14489
14637
  });
14490
14638
  await mcp.connect(new StdioServerTransport());
14639
+ var acquiredLockPath = null;
14640
+ {
14641
+ const lockResult = acquireMcpSpawnLock({
14642
+ agentDir: DIRECT_CHAT_AGENT_DIR,
14643
+ basename: "direct-chat-channel.lock"
14644
+ });
14645
+ if (lockResult.kind === "blocked") {
14646
+ process.stderr.write(
14647
+ `direct-chat-channel: another instance pid=${lockResult.holder.pid} already running (since ${lockResult.holder.started_at}), exiting
14648
+ `
14649
+ );
14650
+ process.exit(0);
14651
+ } else if (lockResult.kind === "acquired") {
14652
+ acquiredLockPath = lockResult.path;
14653
+ }
14654
+ }
14491
14655
  process.stderr.write(
14492
14656
  `direct-chat-channel: Started (agent=${AGT_AGENT_ID}, polling=disabled \u2014 using Realtime)
14493
14657
  `
@@ -14498,6 +14662,10 @@ function shutdown(reason) {
14498
14662
  isShuttingDown = true;
14499
14663
  process.stderr.write(`direct-chat-channel: ${reason} \u2014 exiting
14500
14664
  `);
14665
+ try {
14666
+ releaseMcpSpawnLock(acquiredLockPath);
14667
+ } catch {
14668
+ }
14501
14669
  setTimeout(() => process.exit(0), 100).unref();
14502
14670
  }
14503
14671
  process.stdin.on("close", () => shutdown("stdin closed"));
@@ -14230,6 +14230,24 @@ function decideSlackEngagement(input) {
14230
14230
  function decideSlackAckReaction(input) {
14231
14231
  return Boolean(input.channel && input.ts);
14232
14232
  }
14233
+ function extractAugmentedSlackLabel(evt) {
14234
+ if (evt.metadata?.event_type !== "augmented_agent_message") return null;
14235
+ return {
14236
+ teamId: evt.metadata.event_payload?.["augmented_team_id"],
14237
+ agentId: evt.metadata.event_payload?.["augmented_agent_id"]
14238
+ };
14239
+ }
14240
+ function decideSenderPolicyForward(evt, policy) {
14241
+ if (policy.mode === "all") return { forward: true };
14242
+ const label = extractAugmentedSlackLabel(evt);
14243
+ if (!label) return { forward: false, reason: "sender_policy" };
14244
+ if (policy.mode === "team_agents_only") {
14245
+ if (!policy.teamId || label.teamId !== policy.teamId) {
14246
+ return { forward: false, reason: "sender_policy" };
14247
+ }
14248
+ }
14249
+ return { forward: true };
14250
+ }
14233
14251
 
14234
14252
  // src/slack-loop-throttle.ts
14235
14253
  var DEFAULT_THROTTLE = {
@@ -15495,8 +15513,77 @@ function createConversationIngestClient(args) {
15495
15513
  };
15496
15514
  }
15497
15515
 
15498
- // src/slack-bot-user-id-client.ts
15516
+ // src/inbound-context-client.ts
15499
15517
  var REQUEST_TIMEOUT_MS3 = 1e4;
15518
+ function createInboundContextClient(args) {
15519
+ if (!args.agtHost || !args.agtApiKey || !args.agentId) return null;
15520
+ const fetchImpl = args.fetchImpl ?? fetch;
15521
+ const log = args.log ?? (() => {
15522
+ });
15523
+ const base = args.agtHost.replace(/\/+$/, "");
15524
+ const agentId = args.agentId;
15525
+ const apiKey = args.agtApiKey;
15526
+ let cachedToken = null;
15527
+ let cachedTokenExpiresAt = 0;
15528
+ async function getToken() {
15529
+ if (cachedToken && Date.now() < cachedTokenExpiresAt) return cachedToken;
15530
+ const resp = await fetchImpl(`${base}/host/exchange`, {
15531
+ method: "POST",
15532
+ headers: { "Content-Type": "application/json" },
15533
+ body: JSON.stringify({ host_key: apiKey }),
15534
+ signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS3)
15535
+ });
15536
+ if (!resp.ok) {
15537
+ const body = await resp.text().catch(() => "");
15538
+ throw new Error(`/host/exchange failed (${resp.status}): ${body.slice(0, 200)}`);
15539
+ }
15540
+ const data = await resp.json();
15541
+ cachedToken = data.token;
15542
+ cachedTokenExpiresAt = data.expires_at ? new Date(data.expires_at).getTime() - 12e4 : Date.now() + 55 * 6e4;
15543
+ return cachedToken;
15544
+ }
15545
+ async function postOnce(body) {
15546
+ const token = await getToken();
15547
+ return fetchImpl(`${base}/host/inbound-context`, {
15548
+ method: "POST",
15549
+ headers: { Authorization: `Bearer ${token}`, "Content-Type": "application/json" },
15550
+ body: JSON.stringify(body),
15551
+ signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS3)
15552
+ });
15553
+ }
15554
+ async function emit(args2) {
15555
+ const body = {
15556
+ agent_id: agentId,
15557
+ source_integration: args2.sourceIntegration,
15558
+ source_external_id: args2.sourceExternalId,
15559
+ ...args2.sourceUrl ? { source_url: args2.sourceUrl } : {}
15560
+ };
15561
+ try {
15562
+ let resp = await postOnce(body);
15563
+ if (resp.status === 401) {
15564
+ cachedToken = null;
15565
+ cachedTokenExpiresAt = 0;
15566
+ resp = await postOnce(body);
15567
+ }
15568
+ if (!resp.ok) {
15569
+ const text = await resp.text().catch(() => "");
15570
+ log(
15571
+ `inbound-context: POST failed (${resp.status}) integration=${args2.sourceIntegration}: ${text.slice(0, 200)}`
15572
+ );
15573
+ }
15574
+ } catch (err) {
15575
+ log(`inbound-context: emit threw integration=${args2.sourceIntegration}: ${err.message}`);
15576
+ }
15577
+ }
15578
+ return {
15579
+ recordInbound(args2) {
15580
+ void emit(args2);
15581
+ }
15582
+ };
15583
+ }
15584
+
15585
+ // src/slack-bot-user-id-client.ts
15586
+ var REQUEST_TIMEOUT_MS4 = 1e4;
15500
15587
  function createSlackBotUserIdClient(args) {
15501
15588
  if (!args.agtHost || !args.agtApiKey || !args.agentId) return null;
15502
15589
  const fetchImpl = args.fetchImpl ?? fetch;
@@ -15514,7 +15601,7 @@ function createSlackBotUserIdClient(args) {
15514
15601
  method: "POST",
15515
15602
  headers: { "Content-Type": "application/json" },
15516
15603
  body: JSON.stringify({ host_key: apiKey }),
15517
- signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS3)
15604
+ signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS4)
15518
15605
  });
15519
15606
  if (!resp.ok) {
15520
15607
  const body = await resp.text().catch(() => "");
@@ -15531,7 +15618,7 @@ function createSlackBotUserIdClient(args) {
15531
15618
  method: "POST",
15532
15619
  headers: { Authorization: `Bearer ${token}`, "Content-Type": "application/json" },
15533
15620
  body: JSON.stringify({ agent_id: agentId, bot_user_id: botUserId2 }),
15534
- signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS3)
15621
+ signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS4)
15535
15622
  });
15536
15623
  }
15537
15624
  async function emitAsync(botUserId2) {
@@ -15563,7 +15650,7 @@ function createSlackBotUserIdClient(args) {
15563
15650
  method: "POST",
15564
15651
  headers: { Authorization: `Bearer ${token}`, "Content-Type": "application/json" },
15565
15652
  body: JSON.stringify({ agent_id: agentId, channel_id: "slack", healthy }),
15566
- signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS3)
15653
+ signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS4)
15567
15654
  });
15568
15655
  };
15569
15656
  try {
@@ -15607,7 +15694,7 @@ function createSlackBotUserIdClient(args) {
15607
15694
  };
15608
15695
  }
15609
15696
 
15610
- // src/slack-spawn-lock.ts
15697
+ // src/mcp-spawn-lock.ts
15611
15698
  import {
15612
15699
  existsSync,
15613
15700
  mkdirSync as mkdirSync2,
@@ -15617,7 +15704,6 @@ import {
15617
15704
  writeFileSync as writeFileSync2
15618
15705
  } from "fs";
15619
15706
  import { join as join2 } from "path";
15620
- var DEFAULT_LOCK_BASENAME = "slack-channel.lock";
15621
15707
  function defaultIsPidAlive(pid) {
15622
15708
  if (!Number.isFinite(pid) || pid <= 0) return false;
15623
15709
  try {
@@ -15629,12 +15715,13 @@ function defaultIsPidAlive(pid) {
15629
15715
  return true;
15630
15716
  }
15631
15717
  }
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);
15718
+ function acquireMcpSpawnLock(args) {
15719
+ const { agentDir, basename: basename2, options = {} } = args;
15720
+ if (!agentDir) return { kind: "no-agent-dir" };
15721
+ const isPidAlive = options.isPidAlive ?? defaultIsPidAlive;
15722
+ const selfPid = options.selfPid ?? process.pid;
15723
+ const now = options.now ?? (() => (/* @__PURE__ */ new Date()).toISOString());
15724
+ const path = join2(agentDir, basename2);
15638
15725
  const existing = readLockHolder(path);
15639
15726
  if (existing) {
15640
15727
  if (existing.pid === selfPid) {
@@ -15644,14 +15731,14 @@ function acquireSlackSpawnLock(slackAgentDir, opts = {}) {
15644
15731
  return { kind: "blocked", path, holder: existing };
15645
15732
  }
15646
15733
  }
15647
- mkdirSync2(slackAgentDir, { recursive: true, mode: 448 });
15734
+ mkdirSync2(agentDir, { recursive: true, mode: 448 });
15648
15735
  const tmpPath = `${path}.${selfPid}.tmp`;
15649
15736
  const payload = { pid: selfPid, started_at: now() };
15650
15737
  writeFileSync2(tmpPath, JSON.stringify(payload), { mode: 384 });
15651
15738
  renameSync(tmpPath, path);
15652
15739
  return { kind: "acquired", path };
15653
15740
  }
15654
- function releaseSlackSpawnLock(lockPath, opts = {}) {
15741
+ function releaseMcpSpawnLock(lockPath, opts = {}) {
15655
15742
  if (!lockPath) return;
15656
15743
  const selfPid = opts.selfPid ?? process.pid;
15657
15744
  const existing = readLockHolder(lockPath);
@@ -15683,6 +15770,19 @@ var AGENT_CODE_NAME = process.env.AGT_AGENT_CODE_NAME ?? null;
15683
15770
  var AGT_HOST = process.env.AGT_HOST ?? null;
15684
15771
  var AGT_API_KEY = process.env.AGT_API_KEY ?? null;
15685
15772
  var AGT_AGENT_ID = process.env.AGT_AGENT_ID ?? null;
15773
+ var AGT_TEAM_ID = process.env.AGT_TEAM_ID ?? null;
15774
+ var SLACK_SENDER_POLICY = (() => {
15775
+ const raw = (process.env.SLACK_SENDER_POLICY ?? "all").trim().toLowerCase();
15776
+ if (raw === "all") return { mode: "all" };
15777
+ if (raw === "agents_only") return { mode: "agents_only" };
15778
+ if (raw === "team_agents_only") {
15779
+ if (!AGT_TEAM_ID) {
15780
+ throw new Error("SLACK_SENDER_POLICY=team_agents_only requires AGT_TEAM_ID");
15781
+ }
15782
+ return { mode: "team_agents_only", teamId: AGT_TEAM_ID };
15783
+ }
15784
+ throw new Error(`Invalid SLACK_SENDER_POLICY=${JSON.stringify(process.env.SLACK_SENDER_POLICY)}`);
15785
+ })();
15686
15786
  var BLOCK_KIT_ENABLED = process.env.SLACK_BLOCK_KIT_ENABLED === "true";
15687
15787
  var BLOCK_KIT_ASK_USER_ENABLED = process.env.SLACK_BLOCK_KIT_ASK_USER_ENABLED === "true";
15688
15788
  var BLOCK_KIT_DISABLED = process.env.SLACK_BLOCK_KIT_DISABLED === "true";
@@ -15721,6 +15821,13 @@ var conversationIngestClient = createConversationIngestClient({
15721
15821
  log: (line) => process.stderr.write(`slack-channel: ${line}
15722
15822
  `)
15723
15823
  });
15824
+ var inboundContextClient = createInboundContextClient({
15825
+ agtHost: AGT_HOST,
15826
+ agtApiKey: AGT_API_KEY,
15827
+ agentId: AGT_AGENT_ID,
15828
+ log: (line) => process.stderr.write(`slack-channel: ${line}
15829
+ `)
15830
+ });
15724
15831
  var SLACK_PEER_CLASSIFIER_CONFIG = {
15725
15832
  peer_agent_mode: parsePeerAgentModeEnv(process.env.SLACK_PEER_AGENT_MODE),
15726
15833
  peer_group_ids: parsePeerGroupIdsEnv(process.env.SLACK_PEER_GROUP_IDS),
@@ -16049,6 +16156,16 @@ function noteThreadActivityByMessageTs(channel, messageTs) {
16049
16156
  }
16050
16157
  }
16051
16158
  var RESTART_FLAGS_DIR = join3(homedir2(), ".augmented", "restart-flags");
16159
+ function buildAugmentedSlackMetadata() {
16160
+ if (!AGT_TEAM_ID) return void 0;
16161
+ return {
16162
+ event_type: "augmented_agent_message",
16163
+ event_payload: {
16164
+ augmented_team_id: AGT_TEAM_ID,
16165
+ ...AGT_AGENT_ID ? { augmented_agent_id: AGT_AGENT_ID } : {}
16166
+ }
16167
+ };
16168
+ }
16052
16169
  function hashChannelId(id) {
16053
16170
  return createHash("sha256").update(id).digest("hex").slice(0, 8);
16054
16171
  }
@@ -16056,6 +16173,8 @@ function hashId(id) {
16056
16173
  return createHash("sha256").update(id).digest("hex").slice(0, 8);
16057
16174
  }
16058
16175
  async function postSlackMessage(body) {
16176
+ const augmentedMeta = buildAugmentedSlackMetadata();
16177
+ const bodyWithLabel = augmentedMeta ? { ...body, metadata: augmentedMeta } : body;
16059
16178
  try {
16060
16179
  const res = await fetch("https://slack.com/api/chat.postMessage", {
16061
16180
  method: "POST",
@@ -16063,7 +16182,7 @@ async function postSlackMessage(body) {
16063
16182
  "Content-Type": "application/json; charset=utf-8",
16064
16183
  Authorization: `Bearer ${BOT_TOKEN}`
16065
16184
  },
16066
- body: JSON.stringify(body),
16185
+ body: JSON.stringify(bodyWithLabel),
16067
16186
  // Hard deadline so a hung Slack API can't stall the live Socket Mode
16068
16187
  // event loop or the manager's restart ack path. Matches the timeout
16069
16188
  // used elsewhere in this file for chat.postMessage.
@@ -16865,7 +16984,10 @@ mcp.setRequestHandler(CallToolRequestSchema, async (req) => {
16865
16984
  body: JSON.stringify({
16866
16985
  channel,
16867
16986
  text,
16868
- ...thread_ts ? { thread_ts } : {}
16987
+ ...thread_ts ? { thread_ts } : {},
16988
+ ...buildAugmentedSlackMetadata() ? { metadata: buildAugmentedSlackMetadata() } : {}
16989
+ // ↑ Labels this message as Augmented-agent-originated so peer agents
16990
+ // enforcing sender_policy=team_agents_only can verify the sender.
16869
16991
  })
16870
16992
  });
16871
16993
  const data = await res.json();
@@ -17289,6 +17411,8 @@ function forwardingHostAvailable() {
17289
17411
  return Boolean(AGT_HOST && AGT_API_KEY && AGT_AGENT_ID);
17290
17412
  }
17291
17413
  async function postSlackMessageWithTs(payload) {
17414
+ const augmentedMeta = buildAugmentedSlackMetadata();
17415
+ const payloadWithLabel = augmentedMeta ? { ...payload, metadata: augmentedMeta } : payload;
17292
17416
  try {
17293
17417
  const res = await fetch("https://slack.com/api/chat.postMessage", {
17294
17418
  method: "POST",
@@ -17296,7 +17420,7 @@ async function postSlackMessageWithTs(payload) {
17296
17420
  "Content-Type": "application/json; charset=utf-8",
17297
17421
  Authorization: `Bearer ${BOT_TOKEN}`
17298
17422
  },
17299
- body: JSON.stringify(payload),
17423
+ body: JSON.stringify(payloadWithLabel),
17300
17424
  signal: AbortSignal.timeout(SLACK_DOWNLOAD_TIMEOUT_MS)
17301
17425
  });
17302
17426
  const data = await res.json();
@@ -17920,6 +18044,12 @@ async function connectSocketMode() {
17920
18044
  const filterDecision = decideSlackMessageForward(evt);
17921
18045
  if (!filterDecision.forward) {
17922
18046
  process.stderr.write(`slack-channel: dropped message event (reason=${filterDecision.reason}, subtype=${evt.subtype ?? "none"}, ts=${evt.ts ?? "n/a"})
18047
+ `);
18048
+ return;
18049
+ }
18050
+ const senderPolicyDecision = decideSenderPolicyForward(evt, SLACK_SENDER_POLICY);
18051
+ if (!senderPolicyDecision.forward) {
18052
+ process.stderr.write(`slack-channel: dropped message event (reason=sender_policy, mode=${SLACK_SENDER_POLICY.mode}, ts=${evt.ts ?? "n/a"})
17923
18053
  `);
17924
18054
  return;
17925
18055
  }
@@ -18094,6 +18224,12 @@ async function connectSocketMode() {
18094
18224
  is_bot: isFromBot,
18095
18225
  bot_id: evt.bot_id ?? null
18096
18226
  });
18227
+ if (!isFromBot && threadTs) {
18228
+ inboundContextClient?.recordInbound({
18229
+ sourceIntegration: "slack",
18230
+ sourceExternalId: `${channel}:${threadTs}`
18231
+ });
18232
+ }
18097
18233
  }
18098
18234
  } catch (err) {
18099
18235
  process.stderr.write(`slack-channel: Event error: ${err.message}
@@ -18133,7 +18269,7 @@ function shutdown(reason, exitCode = 0) {
18133
18269
  } catch {
18134
18270
  }
18135
18271
  try {
18136
- releaseSlackSpawnLock(acquiredLockPath);
18272
+ releaseMcpSpawnLock(acquiredLockPath);
18137
18273
  } catch {
18138
18274
  }
18139
18275
  setTimeout(() => process.exit(exitCode), 500).unref();
@@ -18149,7 +18285,10 @@ process.on("unhandledRejection", (reason) => {
18149
18285
  `);
18150
18286
  });
18151
18287
  {
18152
- const lockResult = acquireSlackSpawnLock(SLACK_AGENT_DIR);
18288
+ const lockResult = acquireMcpSpawnLock({
18289
+ agentDir: SLACK_AGENT_DIR,
18290
+ basename: "slack-channel.lock"
18291
+ });
18153
18292
  if (lockResult.kind === "blocked") {
18154
18293
  process.stderr.write(
18155
18294
  `slack-channel: another instance pid=${lockResult.holder.pid} already running (since ${lockResult.holder.started_at}), exiting