@integrity-labs/agt-cli 0.19.12 → 0.19.14

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-QFWR2NV5.js";
17
+ } from "./chunk-HA4IUBVC.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-XBRQN7XE.js.map
35
+ //# sourceMappingURL=persistent-session-CFDGW7QE.js.map
package/mcp/index.js CHANGED
@@ -21731,7 +21731,7 @@ server.tool(
21731
21731
  "schedule.update",
21732
21732
  // Lead with user phrasings the agent should match against, then explain
21733
21733
  // the two modes. Order matters for tool selection.
21734
- 'Update an existing scheduled task. USE THIS TOOL when the user says: "change the schedule for X", "run the daily report at 10am instead of 9am", "pause the standup schedule", "move the weekly digest to Mondays", "make this report more concise", "add a section about X to the daily summary", "tell the Y schedule to also cover Z". Two modes: (1) DIRECT FIELD UPDATES \u2014 set cron_expression/interval/timezone/channel/enabled/name/prompt to change those values directly. (2) LLM DESCRIPTION REWRITE \u2014 pass description_feedback to have the platform rewrite the task prompt based on natural-language feedback (e.g. "make this more concise" or "add a section about the team backlog"). Default for LLM rewrites is preview-then-apply: call once to get the proposed rewrite, show the diff to the user, call again with auto_apply=true on confirmation. Direct field updates apply immediately. The two modes are mutually exclusive \u2014 one request is EITHER a field update OR a description rewrite.',
21734
+ 'Update an existing scheduled task. USE THIS TOOL when the user says: "change the schedule for X", "run the daily report at 10am instead of 9am", "pause the standup schedule", "move the weekly digest to Mondays", "make this report more concise", "add a section about X to the daily summary", "tell the Y schedule to also cover Z", "post these to the Customer Success channel from now on". Two modes: (1) DIRECT FIELD UPDATES \u2014 set cron_expression/interval/timezone/delivery_channel/delivery_to/enabled/name/prompt to change those values directly. (2) LLM DESCRIPTION REWRITE \u2014 pass description_feedback to have the platform rewrite the task prompt based on natural-language feedback (e.g. "make this more concise" or "add a section about the team backlog"). Default for LLM rewrites is preview-then-apply: call once to get the proposed rewrite, show the diff to the user, call again with auto_apply=true on confirmation. Direct field updates apply immediately. The two modes are mutually exclusive \u2014 one request is EITHER a field update OR a description rewrite.\n\nIMPORTANT \u2014 `delivery_to` requires a Slack channel ID (e.g. `C0123ABC456`), NOT a human channel name. If the user references a channel by its name ("the Customer Success channel"), call `mcp__slack__slack.list_channels` first with `query: "customer success"` to get the matching `id`, then pass that id as `delivery_to` here. Do not guess channel ids.',
21735
21735
  {
21736
21736
  task_id: external_exports.string().describe("The task ID to update (from schedule.list)"),
21737
21737
  // Direct-field mode
@@ -14196,6 +14196,9 @@ function decideSlackEngagement(input) {
14196
14196
  const isExplicitMention = input.type === "app_mention" || input.botUserId.length > 0 && input.text.includes(`<@${input.botUserId}>`);
14197
14197
  return !(input.isAutoFollowed && !isExplicitMention);
14198
14198
  }
14199
+ function decideSlackAckReaction(input) {
14200
+ return Boolean(input.channel && input.ts);
14201
+ }
14199
14202
 
14200
14203
  // src/slack-loop-throttle.ts
14201
14204
  var DEFAULT_THROTTLE = {
@@ -14665,6 +14668,33 @@ function channelMessageShouldRespond(text, mode) {
14665
14668
  return false;
14666
14669
  }
14667
14670
 
14671
+ // src/slack-list-channels.ts
14672
+ function normaliseForMatch(s) {
14673
+ return s.toLowerCase().replace(/[-_\s]+/g, "");
14674
+ }
14675
+ function filterChannelsPage(rows, query) {
14676
+ const trimmed = query?.trim();
14677
+ const normQuery = trimmed ? normaliseForMatch(trimmed) : "";
14678
+ const result = [];
14679
+ for (const row of rows) {
14680
+ if (row.is_archived) continue;
14681
+ if (!row.id || !row.name) continue;
14682
+ if (normQuery && !normaliseForMatch(row.name).includes(normQuery)) continue;
14683
+ result.push({
14684
+ id: row.id,
14685
+ name: row.name,
14686
+ is_member: row.is_member === true,
14687
+ num_members: typeof row.num_members === "number" ? row.num_members : 0
14688
+ });
14689
+ }
14690
+ return result;
14691
+ }
14692
+ function buildListChannelsResult(acc, limit, hadMore) {
14693
+ const capped = acc.slice(0, limit);
14694
+ const truncated = capped.length < acc.length || hadMore;
14695
+ return { channels: capped, truncated };
14696
+ }
14697
+
14668
14698
  // src/slack-channel.ts
14669
14699
  var BOT_TOKEN = process.env.SLACK_BOT_TOKEN;
14670
14700
  var APP_TOKEN = process.env.SLACK_APP_TOKEN;
@@ -15554,6 +15584,23 @@ mcp.setRequestHandler(ListToolsRequestSchema, async () => ({
15554
15584
  },
15555
15585
  required: ["path", "channel"]
15556
15586
  }
15587
+ },
15588
+ {
15589
+ name: "slack.list_channels",
15590
+ 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.',
15591
+ inputSchema: {
15592
+ type: "object",
15593
+ properties: {
15594
+ query: {
15595
+ type: "string",
15596
+ description: 'Optional case-insensitive substring filter on the channel name. "customer success" matches "customer-success", "customer-success-team", etc.'
15597
+ },
15598
+ limit: {
15599
+ type: "number",
15600
+ description: "Max channels to return after filtering (default 50, capped at 200). If the cap is hit, `truncated` is true and the agent should narrow the query."
15601
+ }
15602
+ }
15603
+ }
15557
15604
  }
15558
15605
  ]
15559
15606
  }));
@@ -15921,8 +15968,65 @@ ${formatted}` : "Thread is empty or not found."
15921
15968
  if (name === "slack.ask_user") {
15922
15969
  return await handleAskUser(args);
15923
15970
  }
15971
+ if (name === "slack.list_channels") {
15972
+ return await handleListChannels(args);
15973
+ }
15924
15974
  throw new Error(`Unknown tool: ${name}`);
15925
15975
  });
15976
+ var LIST_CHANNELS_DEFAULT_LIMIT = 50;
15977
+ var LIST_CHANNELS_MAX_LIMIT = 200;
15978
+ var LIST_CHANNELS_PAGE_SIZE = 200;
15979
+ var LIST_CHANNELS_MAX_PAGES = 20;
15980
+ async function handleListChannels(args) {
15981
+ const rawQuery = typeof args["query"] === "string" ? args["query"] : void 0;
15982
+ const requestedLimitRaw = typeof args["limit"] === "number" ? args["limit"] : LIST_CHANNELS_DEFAULT_LIMIT;
15983
+ const limit = Math.max(1, Math.min(LIST_CHANNELS_MAX_LIMIT, Math.floor(requestedLimitRaw)));
15984
+ const accumulated = [];
15985
+ let cursor;
15986
+ let pageCount = 0;
15987
+ let hadMore = false;
15988
+ try {
15989
+ while (pageCount < LIST_CHANNELS_MAX_PAGES) {
15990
+ pageCount++;
15991
+ const params = new URLSearchParams({
15992
+ types: "public_channel",
15993
+ exclude_archived: "true",
15994
+ limit: String(LIST_CHANNELS_PAGE_SIZE)
15995
+ });
15996
+ if (cursor) params.set("cursor", cursor);
15997
+ const res = await fetch(`https://slack.com/api/conversations.list?${params}`, {
15998
+ headers: { Authorization: `Bearer ${BOT_TOKEN}` }
15999
+ });
16000
+ const data = await res.json();
16001
+ if (!data.ok) {
16002
+ return {
16003
+ content: [{ type: "text", text: `Slack error: ${data.error ?? "conversations.list failed"}` }],
16004
+ isError: true
16005
+ };
16006
+ }
16007
+ const filtered = filterChannelsPage(data.channels ?? [], rawQuery);
16008
+ accumulated.push(...filtered);
16009
+ cursor = data.response_metadata?.next_cursor || void 0;
16010
+ if (!cursor) break;
16011
+ if (accumulated.length >= limit) {
16012
+ hadMore = true;
16013
+ break;
16014
+ }
16015
+ }
16016
+ if (pageCount >= LIST_CHANNELS_MAX_PAGES && cursor) {
16017
+ hadMore = true;
16018
+ }
16019
+ } catch (err) {
16020
+ return {
16021
+ content: [{ type: "text", text: `Slack error: ${err.message}` }],
16022
+ isError: true
16023
+ };
16024
+ }
16025
+ const result = buildListChannelsResult(accumulated, limit, hadMore);
16026
+ return {
16027
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
16028
+ };
16029
+ }
15926
16030
  function blockKitToolsAvailable() {
15927
16031
  return BLOCK_KIT_ENABLED && !BLOCK_KIT_DISABLED;
15928
16032
  }
@@ -16529,7 +16633,7 @@ async function connectSocketMode() {
16529
16633
  isAutoFollowed,
16530
16634
  botUserId
16531
16635
  });
16532
- if (channel && ts && shouldEngage) {
16636
+ if (decideSlackAckReaction({ channel, ts })) {
16533
16637
  fetch("https://slack.com/api/reactions.add", {
16534
16638
  method: "POST",
16535
16639
  headers: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@integrity-labs/agt-cli",
3
- "version": "0.19.12",
3
+ "version": "0.19.14",
4
4
  "description": "Augmented Team CLI — agent provisioning and management",
5
5
  "type": "module",
6
6
  "engines": {