@integrity-labs/agt-cli 0.28.325 → 0.28.327

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.
@@ -14693,6 +14693,7 @@ function createKanbanCardActiveClient(args) {
14693
14693
  const agentId = args.agentId;
14694
14694
  const apiKey = args.agtApiKey;
14695
14695
  const cache = /* @__PURE__ */ new Map();
14696
+ const threadCache = /* @__PURE__ */ new Map();
14696
14697
  let cachedToken = null;
14697
14698
  let cachedTokenExpiresAt = 0;
14698
14699
  async function getToken() {
@@ -14737,6 +14738,26 @@ function createKanbanCardActiveClient(args) {
14737
14738
  const data = await resp.json();
14738
14739
  return data.active === true;
14739
14740
  }
14741
+ async function queryThreadOnce(sourceIntegration, channel) {
14742
+ const token = await getToken();
14743
+ const qs = new URLSearchParams({ agent_id: agentId, source_integration: sourceIntegration, channel });
14744
+ return fetchImpl(`${base}/host/kanban/active-source-thread?${qs.toString()}`, {
14745
+ method: "GET",
14746
+ headers: { Authorization: `Bearer ${token}` },
14747
+ signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS2)
14748
+ });
14749
+ }
14750
+ async function queryThread(sourceIntegration, channel) {
14751
+ let resp = await queryThreadOnce(sourceIntegration, channel);
14752
+ if (resp.status === 401) {
14753
+ cachedToken = null;
14754
+ cachedTokenExpiresAt = 0;
14755
+ resp = await queryThreadOnce(sourceIntegration, channel);
14756
+ }
14757
+ if (!resp.ok) return void 0;
14758
+ const data = await resp.json();
14759
+ return data.thread_ts ?? void 0;
14760
+ }
14740
14761
  return {
14741
14762
  async isCardActive(sourceIntegration, sourceExternalId) {
14742
14763
  const key = `${sourceIntegration}:${sourceExternalId}`;
@@ -14751,6 +14772,20 @@ function createKanbanCardActiveClient(args) {
14751
14772
  log(`kanban-card-active: query threw key=${key}: ${err.message}`);
14752
14773
  return false;
14753
14774
  }
14775
+ },
14776
+ async getActiveCardSourceThread(sourceIntegration, channel) {
14777
+ const key = `thread:${sourceIntegration}:${channel}`;
14778
+ const t = now();
14779
+ const hit = threadCache.get(key);
14780
+ if (hit && t < hit.expiresAt) return hit.threadTs;
14781
+ try {
14782
+ const threadTs = await queryThread(sourceIntegration, channel);
14783
+ threadCache.set(key, { threadTs, expiresAt: t + (threadTs ? positiveTtlMs : negativeTtlMs) });
14784
+ return threadTs;
14785
+ } catch (err) {
14786
+ log(`kanban-card-active: thread query threw key=${key}: ${err.message}`);
14787
+ return void 0;
14788
+ }
14754
14789
  }
14755
14790
  };
14756
14791
  }
@@ -16284,6 +16284,7 @@ function createKanbanCardActiveClient(args) {
16284
16284
  const agentId = args.agentId;
16285
16285
  const apiKey = args.agtApiKey;
16286
16286
  const cache = /* @__PURE__ */ new Map();
16287
+ const threadCache = /* @__PURE__ */ new Map();
16287
16288
  let cachedToken = null;
16288
16289
  let cachedTokenExpiresAt = 0;
16289
16290
  async function getToken() {
@@ -16328,6 +16329,26 @@ function createKanbanCardActiveClient(args) {
16328
16329
  const data = await resp.json();
16329
16330
  return data.active === true;
16330
16331
  }
16332
+ async function queryThreadOnce(sourceIntegration, channel) {
16333
+ const token = await getToken();
16334
+ const qs = new URLSearchParams({ agent_id: agentId, source_integration: sourceIntegration, channel });
16335
+ return fetchImpl(`${base}/host/kanban/active-source-thread?${qs.toString()}`, {
16336
+ method: "GET",
16337
+ headers: { Authorization: `Bearer ${token}` },
16338
+ signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS)
16339
+ });
16340
+ }
16341
+ async function queryThread(sourceIntegration, channel) {
16342
+ let resp = await queryThreadOnce(sourceIntegration, channel);
16343
+ if (resp.status === 401) {
16344
+ cachedToken = null;
16345
+ cachedTokenExpiresAt = 0;
16346
+ resp = await queryThreadOnce(sourceIntegration, channel);
16347
+ }
16348
+ if (!resp.ok) return void 0;
16349
+ const data = await resp.json();
16350
+ return data.thread_ts ?? void 0;
16351
+ }
16331
16352
  return {
16332
16353
  async isCardActive(sourceIntegration, sourceExternalId) {
16333
16354
  const key2 = `${sourceIntegration}:${sourceExternalId}`;
@@ -16342,6 +16363,20 @@ function createKanbanCardActiveClient(args) {
16342
16363
  log(`kanban-card-active: query threw key=${key2}: ${err.message}`);
16343
16364
  return false;
16344
16365
  }
16366
+ },
16367
+ async getActiveCardSourceThread(sourceIntegration, channel) {
16368
+ const key2 = `thread:${sourceIntegration}:${channel}`;
16369
+ const t = now();
16370
+ const hit = threadCache.get(key2);
16371
+ if (hit && t < hit.expiresAt) return hit.threadTs;
16372
+ try {
16373
+ const threadTs = await queryThread(sourceIntegration, channel);
16374
+ threadCache.set(key2, { threadTs, expiresAt: t + (threadTs ? positiveTtlMs : negativeTtlMs) });
16375
+ return threadTs;
16376
+ } catch (err) {
16377
+ log(`kanban-card-active: thread query threw key=${key2}: ${err.message}`);
16378
+ return void 0;
16379
+ }
16345
16380
  }
16346
16381
  };
16347
16382
  }
@@ -16349,7 +16384,9 @@ function createKanbanCardActiveClient(args) {
16349
16384
  // src/slack-reply-threading.ts
16350
16385
  function resolveReplyThreadTs(input) {
16351
16386
  if (input.threadTs) return input.threadTs;
16352
- return input.messageTs || void 0;
16387
+ if (input.messageTs) return input.messageTs;
16388
+ if (input.threadTs === null) return void 0;
16389
+ return input.activeCardThreadTs || void 0;
16353
16390
  }
16354
16391
 
16355
16392
  // src/restart-confirm.ts
@@ -18351,14 +18388,17 @@ var SLACK_SENDER_POLICY = (() => {
18351
18388
  );
18352
18389
  }
18353
18390
  const internalOnlyFields = internalOnly ? { internalOnly: true, homeTeamId } : {};
18391
+ const registeredAgentSlackUserIds = /* @__PURE__ */ new Set();
18354
18392
  const slackPeersRaw = process.env.SLACK_PEERS;
18355
- const registryFields = slackPeersRaw && slackPeersRaw.trim().length > 0 ? {
18356
- registeredAgentSlackUserIds: new Set(
18357
- parsePeersEnv(slackPeersRaw, process.env.SLACK_PEERS_GATE).map(
18358
- (p) => p.bot_user_id
18359
- )
18360
- )
18361
- } : {};
18393
+ if (slackPeersRaw && slackPeersRaw.trim().length > 0) {
18394
+ for (const p of parsePeersEnv(slackPeersRaw, process.env.SLACK_PEERS_GATE)) {
18395
+ registeredAgentSlackUserIds.add(p.bot_user_id);
18396
+ }
18397
+ }
18398
+ for (const id of parseTeamPeerUserIdsEnv(process.env.SLACK_TEAM_PEER_USER_IDS)) {
18399
+ registeredAgentSlackUserIds.add(id);
18400
+ }
18401
+ const registryFields = registeredAgentSlackUserIds.size > 0 ? { registeredAgentSlackUserIds } : {};
18362
18402
  if (raw === "all") return { mode: "all", ...internalOnlyFields, ...registryFields };
18363
18403
  if (raw === "agents_only") return { mode: "agents_only", ...internalOnlyFields, ...registryFields };
18364
18404
  if (raw === "team_agents_only") {
@@ -21162,10 +21202,12 @@ mcp.setRequestHandler(CallToolRequestSchema, async (req) => {
21162
21202
  };
21163
21203
  }
21164
21204
  const bindingFeedback = bindingMode === "warn" ? binding.agentFeedback : void 0;
21205
+ const activeCardThreadTs = !scheduledDest && !enforceBound && !channelGuard.corrected && !thread_ts && !message_ts && kanbanCardActiveClient && typeof channel === "string" && channel ? await kanbanCardActiveClient.getActiveCardSourceThread("slack", channel) : void 0;
21165
21206
  const effectiveThreadTs = scheduledDest ? scheduledDest.thread_ts : enforceBound ? binding.threadTs : channelGuard.corrected ? channelGuard.threadTs : resolveReplyThreadTs({
21166
21207
  channel,
21167
21208
  threadTs: thread_ts,
21168
- messageTs: message_ts
21209
+ messageTs: message_ts,
21210
+ activeCardThreadTs
21169
21211
  });
21170
21212
  if (effectiveChannel) {
21171
21213
  recordReplyTargetClassification(
@@ -21843,10 +21885,12 @@ async function handleSendStructured(args) {
21843
21885
  if (typeof text !== "string" || !text) {
21844
21886
  return errResult("text is required (used as fallback for push notifications and unfurls)");
21845
21887
  }
21888
+ const activeCardThreadTs = !thread_ts && !message_ts && kanbanCardActiveClient ? await kanbanCardActiveClient.getActiveCardSourceThread("slack", channel) : void 0;
21846
21889
  const effectiveThreadTs = resolveReplyThreadTs({
21847
21890
  channel,
21848
21891
  threadTs: thread_ts,
21849
- messageTs: message_ts
21892
+ messageTs: message_ts,
21893
+ activeCardThreadTs
21850
21894
  });
21851
21895
  recordReplyTargetClassification(
21852
21896
  SLACK_AGENT_DIR,
@@ -17109,6 +17109,7 @@ function createKanbanCardActiveClient(args) {
17109
17109
  const agentId = args.agentId;
17110
17110
  const apiKey = args.agtApiKey;
17111
17111
  const cache = /* @__PURE__ */ new Map();
17112
+ const threadCache = /* @__PURE__ */ new Map();
17112
17113
  let cachedToken = null;
17113
17114
  let cachedTokenExpiresAt = 0;
17114
17115
  async function getToken() {
@@ -17153,6 +17154,26 @@ function createKanbanCardActiveClient(args) {
17153
17154
  const data = await resp.json();
17154
17155
  return data.active === true;
17155
17156
  }
17157
+ async function queryThreadOnce(sourceIntegration, channel) {
17158
+ const token = await getToken();
17159
+ const qs = new URLSearchParams({ agent_id: agentId, source_integration: sourceIntegration, channel });
17160
+ return fetchImpl(`${base}/host/kanban/active-source-thread?${qs.toString()}`, {
17161
+ method: "GET",
17162
+ headers: { Authorization: `Bearer ${token}` },
17163
+ signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS6)
17164
+ });
17165
+ }
17166
+ async function queryThread(sourceIntegration, channel) {
17167
+ let resp = await queryThreadOnce(sourceIntegration, channel);
17168
+ if (resp.status === 401) {
17169
+ cachedToken = null;
17170
+ cachedTokenExpiresAt = 0;
17171
+ resp = await queryThreadOnce(sourceIntegration, channel);
17172
+ }
17173
+ if (!resp.ok) return void 0;
17174
+ const data = await resp.json();
17175
+ return data.thread_ts ?? void 0;
17176
+ }
17156
17177
  return {
17157
17178
  async isCardActive(sourceIntegration, sourceExternalId) {
17158
17179
  const key2 = `${sourceIntegration}:${sourceExternalId}`;
@@ -17167,6 +17188,20 @@ function createKanbanCardActiveClient(args) {
17167
17188
  log(`kanban-card-active: query threw key=${key2}: ${err.message}`);
17168
17189
  return false;
17169
17190
  }
17191
+ },
17192
+ async getActiveCardSourceThread(sourceIntegration, channel) {
17193
+ const key2 = `thread:${sourceIntegration}:${channel}`;
17194
+ const t = now();
17195
+ const hit = threadCache.get(key2);
17196
+ if (hit && t < hit.expiresAt) return hit.threadTs;
17197
+ try {
17198
+ const threadTs = await queryThread(sourceIntegration, channel);
17199
+ threadCache.set(key2, { threadTs, expiresAt: t + (threadTs ? positiveTtlMs : negativeTtlMs) });
17200
+ return threadTs;
17201
+ } catch (err) {
17202
+ log(`kanban-card-active: thread query threw key=${key2}: ${err.message}`);
17203
+ return void 0;
17204
+ }
17170
17205
  }
17171
17206
  };
17172
17207
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@integrity-labs/agt-cli",
3
- "version": "0.28.325",
3
+ "version": "0.28.327",
4
4
  "description": "Augmented Team CLI — agent provisioning and management",
5
5
  "type": "module",
6
6
  "engines": {