@integrity-labs/agt-cli 0.19.14 → 0.19.15

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.
@@ -14,7 +14,7 @@ import {
14
14
  stopAllSessionsAndWait,
15
15
  stopPersistentSession,
16
16
  writePersistentClaudeWrapper
17
- } from "./chunk-HA4IUBVC.js";
17
+ } from "./chunk-3K3RO5NS.js";
18
18
  export {
19
19
  _internals,
20
20
  collectDiagnostics,
@@ -32,4 +32,4 @@ export {
32
32
  stopPersistentSession,
33
33
  writePersistentClaudeWrapper
34
34
  };
35
- //# sourceMappingURL=persistent-session-CFDGW7QE.js.map
35
+ //# sourceMappingURL=persistent-session-M2GVL6Z6.js.map
@@ -14695,6 +14695,45 @@ function buildListChannelsResult(acc, limit, hadMore) {
14695
14695
  return { channels: capped, truncated };
14696
14696
  }
14697
14697
 
14698
+ // src/slack-channel-info.ts
14699
+ function buildChannelInfoResult(args) {
14700
+ const { infoRes, botUserHandle } = args;
14701
+ if (!infoRes) {
14702
+ return { ok: false, reason: "unknown", bot_user_handle: botUserHandle, raw_error: "no_response" };
14703
+ }
14704
+ if (infoRes.ok === false) {
14705
+ const err = infoRes.error ?? "unknown";
14706
+ if (err === "channel_not_found") {
14707
+ return { ok: false, reason: "channel_not_found", bot_user_handle: botUserHandle };
14708
+ }
14709
+ if (err === "not_in_channel") {
14710
+ return { ok: false, reason: "not_in_channel", bot_user_handle: botUserHandle };
14711
+ }
14712
+ if (err === "invalid_auth" || err === "token_expired" || err === "token_revoked" || err === "account_inactive") {
14713
+ return { ok: false, reason: "auth_failed", bot_user_handle: botUserHandle, raw_error: err };
14714
+ }
14715
+ return { ok: false, reason: "unknown", bot_user_handle: botUserHandle, raw_error: err };
14716
+ }
14717
+ const ch = infoRes.channel;
14718
+ if (!ch || !ch.id || !ch.name) {
14719
+ return { ok: false, reason: "unknown", bot_user_handle: botUserHandle, raw_error: "malformed_response" };
14720
+ }
14721
+ const channel = {
14722
+ id: ch.id,
14723
+ name: ch.name,
14724
+ is_private: ch.is_private === true,
14725
+ is_archived: ch.is_archived === true,
14726
+ is_member: ch.is_member === true
14727
+ };
14728
+ if (channel.is_archived) {
14729
+ return { ok: false, channel, bot_user_handle: botUserHandle, reason: "archived" };
14730
+ }
14731
+ if (!channel.is_member) {
14732
+ return { ok: false, channel, bot_user_handle: botUserHandle, reason: "not_in_channel" };
14733
+ }
14734
+ return { ok: true, channel, bot_user_handle: botUserHandle };
14735
+ }
14736
+
14698
14737
  // src/slack-channel.ts
14699
14738
  var BOT_TOKEN = process.env.SLACK_BOT_TOKEN;
14700
14739
  var APP_TOKEN = process.env.SLACK_APP_TOKEN;
@@ -15585,6 +15624,20 @@ mcp.setRequestHandler(ListToolsRequestSchema, async () => ({
15585
15624
  required: ["path", "channel"]
15586
15625
  }
15587
15626
  },
15627
+ {
15628
+ name: "slack.channel_info",
15629
+ 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).',
15630
+ inputSchema: {
15631
+ type: "object",
15632
+ properties: {
15633
+ channel_id: {
15634
+ type: "string",
15635
+ description: "Slack channel ID (C0..., G0... for legacy private). Required."
15636
+ }
15637
+ },
15638
+ required: ["channel_id"]
15639
+ }
15640
+ },
15588
15641
  {
15589
15642
  name: "slack.list_channels",
15590
15643
  description: 'Look up Slack channel IDs by name. Use when a user references a channel by its human name (e.g. "the Customer Success channel") and you need the underlying C0... channel ID \u2014 most commonly to set `delivery_to` on a scheduled-task update via mcp__augmented__update_scheduled_task. Returns the bot\'s accessible public channels (non-archived). Pass `query` to filter by case-insensitive substring match against the channel name; without a query, the first page is returned. If `truncated` is true, the workspace has more matches \u2014 ask the user to be more specific.',
@@ -15971,6 +16024,9 @@ ${formatted}` : "Thread is empty or not found."
15971
16024
  if (name === "slack.list_channels") {
15972
16025
  return await handleListChannels(args);
15973
16026
  }
16027
+ if (name === "slack.channel_info") {
16028
+ return await handleChannelInfo(args);
16029
+ }
15974
16030
  throw new Error(`Unknown tool: ${name}`);
15975
16031
  });
15976
16032
  var LIST_CHANNELS_DEFAULT_LIMIT = 50;
@@ -16027,6 +16083,61 @@ async function handleListChannels(args) {
16027
16083
  content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
16028
16084
  };
16029
16085
  }
16086
+ async function handleChannelInfo(args) {
16087
+ const channelId = typeof args["channel_id"] === "string" ? args["channel_id"].trim() : "";
16088
+ if (!channelId) {
16089
+ return {
16090
+ content: [{ type: "text", text: "channel_id is required" }],
16091
+ isError: true
16092
+ };
16093
+ }
16094
+ let infoData = null;
16095
+ let authData = null;
16096
+ const [infoSettled, authSettled] = await Promise.allSettled([
16097
+ fetch(
16098
+ `https://slack.com/api/conversations.info?channel=${encodeURIComponent(channelId)}&include_locale=false`,
16099
+ { headers: { Authorization: `Bearer ${BOT_TOKEN}` } }
16100
+ ),
16101
+ fetch("https://slack.com/api/auth.test", {
16102
+ method: "POST",
16103
+ headers: { Authorization: `Bearer ${BOT_TOKEN}` }
16104
+ })
16105
+ ]);
16106
+ let transportError;
16107
+ if (infoSettled.status === "fulfilled") {
16108
+ try {
16109
+ infoData = await infoSettled.value.json();
16110
+ } catch (parseErr) {
16111
+ transportError = `info_parse_failed: ${parseErr.message}`;
16112
+ }
16113
+ } else {
16114
+ transportError = `info_transport_failed: ${infoSettled.reason?.message ?? "unknown"}`;
16115
+ }
16116
+ if (authSettled.status === "fulfilled") {
16117
+ try {
16118
+ authData = await authSettled.value.json();
16119
+ } catch {
16120
+ }
16121
+ }
16122
+ if (infoData === null && transportError) {
16123
+ const fallback = {
16124
+ ok: false,
16125
+ reason: "unknown",
16126
+ raw_error: transportError
16127
+ };
16128
+ return {
16129
+ content: [{ type: "text", text: JSON.stringify(fallback, null, 2) }]
16130
+ };
16131
+ }
16132
+ const botUserHandle = authData?.ok && typeof authData.user === "string" && authData.user.length > 0 ? authData.user : void 0;
16133
+ const result = buildChannelInfoResult({
16134
+ infoRes: infoData,
16135
+ botUserHandle
16136
+ });
16137
+ return {
16138
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
16139
+ };
16140
+ }
16030
16141
  function blockKitToolsAvailable() {
16031
16142
  return BLOCK_KIT_ENABLED && !BLOCK_KIT_DISABLED;
16032
16143
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@integrity-labs/agt-cli",
3
- "version": "0.19.14",
3
+ "version": "0.19.15",
4
4
  "description": "Augmented Team CLI — agent provisioning and management",
5
5
  "type": "module",
6
6
  "engines": {