@integrity-labs/agt-cli 0.28.151 → 0.28.153

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.
@@ -16399,7 +16399,26 @@ function buildChannelInfoResult(args) {
16399
16399
  return { ok: false, reason: "unknown", bot_user_handle: botUserHandle, raw_error: err };
16400
16400
  }
16401
16401
  const ch = infoRes.channel;
16402
- if (!ch || !ch.id || !ch.name) {
16402
+ if (!ch || !ch.id) {
16403
+ return { ok: false, reason: "unknown", bot_user_handle: botUserHandle, raw_error: "malformed_response" };
16404
+ }
16405
+ const isDm = ch.is_im === true || typeof ch.user === "string" && ch.user.length > 0;
16406
+ if (isDm) {
16407
+ const dmChannel = {
16408
+ id: ch.id,
16409
+ name: ch.user ?? ch.id,
16410
+ is_private: true,
16411
+ is_archived: ch.is_archived === true,
16412
+ is_member: true,
16413
+ kind: "dm",
16414
+ user: ch.user
16415
+ };
16416
+ if (dmChannel.is_archived) {
16417
+ return { ok: false, channel: dmChannel, bot_user_handle: botUserHandle, reason: "archived" };
16418
+ }
16419
+ return { ok: true, channel: dmChannel, bot_user_handle: botUserHandle };
16420
+ }
16421
+ if (!ch.name) {
16403
16422
  return { ok: false, reason: "unknown", bot_user_handle: botUserHandle, raw_error: "malformed_response" };
16404
16423
  }
16405
16424
  const channel = {
@@ -16417,6 +16436,17 @@ function buildChannelInfoResult(args) {
16417
16436
  }
16418
16437
  return { ok: true, channel, bot_user_handle: botUserHandle };
16419
16438
  }
16439
+ function buildDmUserInfo(usersInfoRes) {
16440
+ if (!usersInfoRes || usersInfoRes.ok === false || !usersInfoRes.user) return {};
16441
+ const u = usersInfoRes.user;
16442
+ const nonEmpty = (s) => typeof s === "string" && s.trim().length > 0 ? s : void 0;
16443
+ const user_name = nonEmpty(u.profile?.display_name) ?? nonEmpty(u.profile?.real_name) ?? nonEmpty(u.real_name);
16444
+ const user_handle = nonEmpty(u.name);
16445
+ const out = {};
16446
+ if (user_handle) out.user_handle = user_handle;
16447
+ if (user_name) out.user_name = user_name;
16448
+ return out;
16449
+ }
16420
16450
 
16421
16451
  // src/slack-peer-classifier.ts
16422
16452
  var CODE_NAME_RE = /^[a-z0-9]+(-[a-z0-9]+)*$/;
@@ -19208,13 +19238,13 @@ mcp.setRequestHandler(ListToolsRequestSchema, async () => ({
19208
19238
  },
19209
19239
  {
19210
19240
  name: "slack.channel_info",
19211
- description: 'Verify the bot can post to a specific Slack channel. Use this before relying on a channel ID for delivery (e.g. before submitting an AWS access request that will notify an approval channel) to avoid silent posting failures. Works for both public AND private channels \u2014 unlike slack.list_channels which is public-only. Returns `{ ok, channel: { id, name, is_private, is_archived, is_member }, bot_user_handle, reason? }`. When `ok=false`, branch on `reason`: "channel_not_found" or "not_in_channel" \u2192 tell the user to run `/invite @<bot_user_handle>` in that channel (the configured ID exists but your bot isn\'t a member, or the ID is from a workspace the bot isn\'t installed in); "archived" \u2192 the channel exists but is archived, ask an admin to point the integration at a non-archived channel; "auth_failed" \u2192 bot token is invalid, escalate to an operator (do not surface to the end user). Pass the raw C0... channel ID, not a human name (use slack.list_channels for name \u2192 ID).',
19241
+ description: 'Verify the bot can post to a specific Slack channel, OR resolve who is on the other side of a DM. Use this before relying on a channel ID for delivery (e.g. before submitting an AWS access request that will notify an approval channel) to avoid silent posting failures, and to confirm the human behind a DM channel id before claiming a message reached a named person. Works for public AND private channels (unlike slack.list_channels, which is public-only) and for DM (`D0...`) channels. Returns `{ ok, channel: { id, name, is_private, is_archived, is_member, kind }, bot_user_handle, reason? }`. For a DM, `kind` is "dm" and the result also carries `channel.user` (the partner\'s Slack user id) plus best-effort `channel.user_handle` and `channel.user_name` (the human\'s handle and display name); use these to VERIFY a DM\'s recipient rather than assuming whose DM it is. When `ok=false`, branch on `reason`: "channel_not_found" or "not_in_channel" \u2192 tell the user to run `/invite @<bot_user_handle>` in that channel (the configured ID exists but your bot isn\'t a member, or the ID is from a workspace the bot isn\'t installed in); "archived" \u2192 the channel exists but is archived, ask an admin to point the integration at a non-archived channel; "auth_failed" \u2192 bot token is invalid, escalate to an operator (do not surface to the end user). Pass the raw C0.../G0.../D0... channel ID, not a human name (use slack.list_channels for name \u2192 ID).',
19212
19242
  inputSchema: {
19213
19243
  type: "object",
19214
19244
  properties: {
19215
19245
  channel_id: {
19216
19246
  type: "string",
19217
- description: "Slack channel ID (C0..., G0... for legacy private). Required."
19247
+ description: "Slack channel ID: C0... (public), G0... (legacy private), or D0... (DM). Required."
19218
19248
  }
19219
19249
  },
19220
19250
  required: ["channel_id"]
@@ -19736,6 +19766,25 @@ async function handleChannelInfo(args) {
19736
19766
  infoRes: infoData,
19737
19767
  botUserHandle
19738
19768
  });
19769
+ if (result.channel?.kind === "dm" && result.channel.user) {
19770
+ const controller = new AbortController();
19771
+ const timeout = setTimeout(() => controller.abort(), 3e3);
19772
+ try {
19773
+ const usersRes = await fetch(
19774
+ `https://slack.com/api/users.info?user=${encodeURIComponent(result.channel.user)}`,
19775
+ { headers: { Authorization: `Bearer ${BOT_TOKEN}` }, signal: controller.signal }
19776
+ );
19777
+ const usersData = await usersRes.json();
19778
+ const { user_handle, user_name } = buildDmUserInfo(usersData);
19779
+ if (user_handle) result.channel.user_handle = user_handle;
19780
+ if (user_name) result.channel.user_name = user_name;
19781
+ if (user_name) result.channel.name = user_name;
19782
+ else if (user_handle) result.channel.name = user_handle;
19783
+ } catch {
19784
+ } finally {
19785
+ clearTimeout(timeout);
19786
+ }
19787
+ }
19739
19788
  return {
19740
19789
  content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
19741
19790
  };
@@ -34,7 +34,7 @@ import {
34
34
  writeDirectChatSessionState,
35
35
  writeEgressAllowlist,
36
36
  writePersistentClaudeWrapper
37
- } from "./chunk-HYW5ZAGY.js";
37
+ } from "./chunk-AYN7K3DY.js";
38
38
  import "./chunk-SKANUWSB.js";
39
39
  import "./chunk-XWVM4KPK.js";
40
40
  export {
@@ -74,4 +74,4 @@ export {
74
74
  writeEgressAllowlist,
75
75
  writePersistentClaudeWrapper
76
76
  };
77
- //# sourceMappingURL=persistent-session-S2674LBO.js.map
77
+ //# sourceMappingURL=persistent-session-42JGH4TP.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  paneLogPath
3
- } from "./chunk-HYW5ZAGY.js";
3
+ } from "./chunk-AYN7K3DY.js";
4
4
  import "./chunk-SKANUWSB.js";
5
5
  import "./chunk-XWVM4KPK.js";
6
6
 
@@ -304,4 +304,4 @@ export {
304
304
  readAndResetChannelDeflections,
305
305
  readAndResetChannelLaneClassifications
306
306
  };
307
- //# sourceMappingURL=responsiveness-probe-NHQYDMHJ.js.map
307
+ //# sourceMappingURL=responsiveness-probe-P3H7BWPZ.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@integrity-labs/agt-cli",
3
- "version": "0.28.151",
3
+ "version": "0.28.153",
4
4
  "description": "Augmented Team CLI — agent provisioning and management",
5
5
  "type": "module",
6
6
  "engines": {