@integrity-labs/agt-cli 0.28.570 → 0.28.572

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.
@@ -35721,9 +35721,9 @@ var FLAG_REGISTRY = [
35721
35721
  },
35722
35722
  {
35723
35723
  key: "notify-dispatch",
35724
- description: "Membership-based channel-notify dispatch (ENG-7682 / notify Slice 1). off = today's behaviour: a non-@mention top-level channel message is dropped by the mention_only engagement gate (SLACK_CHANNEL_RESPONSE_MODE). membership = the agent's Slack MCP ADMITS non-@mention channel messages in channels its bot is a member of (the Socket Mode websocket already receives them), waking the agent in-thread via the SAME existing wake path used for @mentions/DMs. Only the mention_only engagement gate is relaxed - the echo/dedup, bot_id/self, and peer-classifier safety leaves still apply, so this never opens a bot-to-bot wake loop. The channel server can't evaluate flags, so the manager materializes the resolved value into the AGT_NOTIFY_DISPATCH spawn env (operator/canary override, ADR-0022). filter = like membership (opt-out) but honours a per-channel mute list: a member-channel message wakes the agent UNLESS the user muted that channel via the /notify slash command. The manager materializes the muted set into AGT_NOTIFY_MUTED_CHANNELS from agent_notify_channel_prefs (ENG-7682 Slice 2). Ships dark (default off).",
35724
+ description: `Membership-based channel-notify dispatch (ENG-7682 / notify Slice 1). off = today's behaviour: a non-@mention top-level channel message is dropped by the mention_only engagement gate (SLACK_CHANNEL_RESPONSE_MODE). membership = the agent's Slack MCP ADMITS non-@mention channel messages in channels its bot is a member of (the Socket Mode websocket already receives them), waking the agent in-thread via the SAME existing wake path used for @mentions/DMs. Only the mention_only engagement gate is relaxed - the echo/dedup, bot_id/self, and peer-classifier safety leaves still apply, so this never opens a bot-to-bot wake loop. The channel server can't evaluate flags, so the manager materializes the resolved value into the AGT_NOTIFY_DISPATCH spawn env (operator/canary override, ADR-0022). filter = like membership (opt-out) but honours a per-channel mute list: a member-channel message wakes the agent UNLESS the user muted that channel via the /notify slash command. The manager materializes the muted set into AGT_NOTIFY_MUTED_CHANNELS from agent_notify_channel_prefs (ENG-7682 Slice 2). addressed = like filter (same per-channel mute, checked FIRST so a mute outranks being named), but a member-channel message additionally has to address THIS agent to wake it: a real Slack mention of its bot user id, \`@<code_name>\` typed verbatim, or the code name used as a vocative at the start of the message ("koda:", "hey koda"). @team / @everyone still wake everyone. This is the fix for one named agent waking every agent in a shared channel (ENG-8657); matching is deliberately conservative, so a name mentioned mid-sentence does NOT wake, and an agent whose identity is unknown to the channel server stays asleep rather than waking on everything. Ships dark (default off).`,
35725
35725
  flagType: "enum",
35726
- allowedValues: ["off", "membership", "filter"],
35726
+ allowedValues: ["off", "membership", "filter", "addressed"],
35727
35727
  // Declared safe value is `off`: the mention_only gate stays in force, byte-
35728
35728
  // identical to today. membership is the deliberate, per-agent flip that
35729
35729
  // widens what wakes the agent.
@@ -41612,9 +41612,9 @@ var FLAG_REGISTRY = [
41612
41612
  },
41613
41613
  {
41614
41614
  key: "notify-dispatch",
41615
- description: "Membership-based channel-notify dispatch (ENG-7682 / notify Slice 1). off = today's behaviour: a non-@mention top-level channel message is dropped by the mention_only engagement gate (SLACK_CHANNEL_RESPONSE_MODE). membership = the agent's Slack MCP ADMITS non-@mention channel messages in channels its bot is a member of (the Socket Mode websocket already receives them), waking the agent in-thread via the SAME existing wake path used for @mentions/DMs. Only the mention_only engagement gate is relaxed - the echo/dedup, bot_id/self, and peer-classifier safety leaves still apply, so this never opens a bot-to-bot wake loop. The channel server can't evaluate flags, so the manager materializes the resolved value into the AGT_NOTIFY_DISPATCH spawn env (operator/canary override, ADR-0022). filter = like membership (opt-out) but honours a per-channel mute list: a member-channel message wakes the agent UNLESS the user muted that channel via the /notify slash command. The manager materializes the muted set into AGT_NOTIFY_MUTED_CHANNELS from agent_notify_channel_prefs (ENG-7682 Slice 2). Ships dark (default off).",
41615
+ description: `Membership-based channel-notify dispatch (ENG-7682 / notify Slice 1). off = today's behaviour: a non-@mention top-level channel message is dropped by the mention_only engagement gate (SLACK_CHANNEL_RESPONSE_MODE). membership = the agent's Slack MCP ADMITS non-@mention channel messages in channels its bot is a member of (the Socket Mode websocket already receives them), waking the agent in-thread via the SAME existing wake path used for @mentions/DMs. Only the mention_only engagement gate is relaxed - the echo/dedup, bot_id/self, and peer-classifier safety leaves still apply, so this never opens a bot-to-bot wake loop. The channel server can't evaluate flags, so the manager materializes the resolved value into the AGT_NOTIFY_DISPATCH spawn env (operator/canary override, ADR-0022). filter = like membership (opt-out) but honours a per-channel mute list: a member-channel message wakes the agent UNLESS the user muted that channel via the /notify slash command. The manager materializes the muted set into AGT_NOTIFY_MUTED_CHANNELS from agent_notify_channel_prefs (ENG-7682 Slice 2). addressed = like filter (same per-channel mute, checked FIRST so a mute outranks being named), but a member-channel message additionally has to address THIS agent to wake it: a real Slack mention of its bot user id, \`@<code_name>\` typed verbatim, or the code name used as a vocative at the start of the message ("koda:", "hey koda"). @team / @everyone still wake everyone. This is the fix for one named agent waking every agent in a shared channel (ENG-8657); matching is deliberately conservative, so a name mentioned mid-sentence does NOT wake, and an agent whose identity is unknown to the channel server stays asleep rather than waking on everything. Ships dark (default off).`,
41616
41616
  flagType: "enum",
41617
- allowedValues: ["off", "membership", "filter"],
41617
+ allowedValues: ["off", "membership", "filter", "addressed"],
41618
41618
  // Declared safe value is `off`: the mention_only gate stays in force, byte-
41619
41619
  // identical to today. membership is the deliberate, per-agent flip that
41620
41620
  // widens what wakes the agent.
@@ -14991,7 +14991,7 @@ var require_lib = __commonJS({
14991
14991
  ">": "&gt;",
14992
14992
  "\\": "&#92;"
14993
14993
  };
14994
- var escapeRegex2 = /[&"'<>\\]/g;
14994
+ var escapeRegex3 = /[&"'<>\\]/g;
14995
14995
  var _exports = module.exports = {};
14996
14996
  function hasOwnProp(obj, k) {
14997
14997
  return ObjProto.hasOwnProperty.call(obj, k);
@@ -15095,7 +15095,7 @@ var require_lib = __commonJS({
15095
15095
  }
15096
15096
  _exports.TemplateError = TemplateError2;
15097
15097
  function escape2(val) {
15098
- return val.replace(escapeRegex2, lookupEscape);
15098
+ return val.replace(escapeRegex3, lookupEscape);
15099
15099
  }
15100
15100
  _exports.escape = escape2;
15101
15101
  function isFunction(obj) {
@@ -36057,9 +36057,9 @@ var FLAG_REGISTRY = [
36057
36057
  },
36058
36058
  {
36059
36059
  key: "notify-dispatch",
36060
- description: "Membership-based channel-notify dispatch (ENG-7682 / notify Slice 1). off = today's behaviour: a non-@mention top-level channel message is dropped by the mention_only engagement gate (SLACK_CHANNEL_RESPONSE_MODE). membership = the agent's Slack MCP ADMITS non-@mention channel messages in channels its bot is a member of (the Socket Mode websocket already receives them), waking the agent in-thread via the SAME existing wake path used for @mentions/DMs. Only the mention_only engagement gate is relaxed - the echo/dedup, bot_id/self, and peer-classifier safety leaves still apply, so this never opens a bot-to-bot wake loop. The channel server can't evaluate flags, so the manager materializes the resolved value into the AGT_NOTIFY_DISPATCH spawn env (operator/canary override, ADR-0022). filter = like membership (opt-out) but honours a per-channel mute list: a member-channel message wakes the agent UNLESS the user muted that channel via the /notify slash command. The manager materializes the muted set into AGT_NOTIFY_MUTED_CHANNELS from agent_notify_channel_prefs (ENG-7682 Slice 2). Ships dark (default off).",
36060
+ description: `Membership-based channel-notify dispatch (ENG-7682 / notify Slice 1). off = today's behaviour: a non-@mention top-level channel message is dropped by the mention_only engagement gate (SLACK_CHANNEL_RESPONSE_MODE). membership = the agent's Slack MCP ADMITS non-@mention channel messages in channels its bot is a member of (the Socket Mode websocket already receives them), waking the agent in-thread via the SAME existing wake path used for @mentions/DMs. Only the mention_only engagement gate is relaxed - the echo/dedup, bot_id/self, and peer-classifier safety leaves still apply, so this never opens a bot-to-bot wake loop. The channel server can't evaluate flags, so the manager materializes the resolved value into the AGT_NOTIFY_DISPATCH spawn env (operator/canary override, ADR-0022). filter = like membership (opt-out) but honours a per-channel mute list: a member-channel message wakes the agent UNLESS the user muted that channel via the /notify slash command. The manager materializes the muted set into AGT_NOTIFY_MUTED_CHANNELS from agent_notify_channel_prefs (ENG-7682 Slice 2). addressed = like filter (same per-channel mute, checked FIRST so a mute outranks being named), but a member-channel message additionally has to address THIS agent to wake it: a real Slack mention of its bot user id, \`@<code_name>\` typed verbatim, or the code name used as a vocative at the start of the message ("koda:", "hey koda"). @team / @everyone still wake everyone. This is the fix for one named agent waking every agent in a shared channel (ENG-8657); matching is deliberately conservative, so a name mentioned mid-sentence does NOT wake, and an agent whose identity is unknown to the channel server stays asleep rather than waking on everything. Ships dark (default off).`,
36061
36061
  flagType: "enum",
36062
- allowedValues: ["off", "membership", "filter"],
36062
+ allowedValues: ["off", "membership", "filter", "addressed"],
36063
36063
  // Declared safe value is `off`: the mention_only gate stays in force, byte-
36064
36064
  // identical to today. membership is the deliberate, per-agent flip that
36065
36065
  // widens what wakes the agent.
@@ -39908,6 +39908,26 @@ function matchesAddressedTeam(text) {
39908
39908
  if (/^(everyone|all)\s*[:,—-]/i.test(t)) return true;
39909
39909
  return false;
39910
39910
  }
39911
+ function matchesAddressedAgent(text, agent) {
39912
+ const t = text.trim();
39913
+ if (t.length === 0) return false;
39914
+ const botUserId2 = agent.botUserId?.trim();
39915
+ if (botUserId2 && new RegExp(`<@${escapeRegex2(botUserId2)}(?:\\|[^>]*)?>`).test(t)) return true;
39916
+ const codeName = agent.codeName?.trim();
39917
+ if (!codeName) return false;
39918
+ const name = escapeRegex2(codeName);
39919
+ if (new RegExp(`(?:^|\\s)@${name}(?=$|[\\s.,!?;:])`, "i").test(t)) return true;
39920
+ if (new RegExp(`^${name}\\s*[:,\u2014-]`, "i").test(t)) return true;
39921
+ if (new RegExp(
39922
+ `^(hey|hi|hello|howdy|good (morning|afternoon|evening)|morning|afternoon)\\s+${name}(?=$|[\\s,.!?:])`,
39923
+ "i"
39924
+ ).test(t))
39925
+ return true;
39926
+ return false;
39927
+ }
39928
+ function escapeRegex2(value) {
39929
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
39930
+ }
39911
39931
  function channelMessageShouldRespond(text, mode) {
39912
39932
  if (mode === "all") return true;
39913
39933
  if (mode === "mention_only") return false;
@@ -39920,6 +39940,7 @@ function parseNotifyDispatchMode(raw) {
39920
39940
  const v = raw.trim().toLowerCase();
39921
39941
  if (v === "membership") return "membership";
39922
39942
  if (v === "filter") return "filter";
39943
+ if (v === "addressed") return "addressed";
39923
39944
  return "off";
39924
39945
  }
39925
39946
  function parseMutedChannels(raw) {
@@ -39928,12 +39949,17 @@ function parseMutedChannels(raw) {
39928
39949
  raw.split(",").map((s) => s.trim()).filter(Boolean)
39929
39950
  );
39930
39951
  }
39931
- function channelMessageShouldWake(text, responseMode, notifyMode, channelId, mutedChannels) {
39952
+ function channelMessageShouldWake(text, responseMode, notifyMode, channelId, mutedChannels, agent) {
39932
39953
  if (notifyMode === "membership") return true;
39933
39954
  if (notifyMode === "filter") {
39934
39955
  if (channelId && mutedChannels && mutedChannels.has(channelId)) return false;
39935
39956
  return true;
39936
39957
  }
39958
+ if (notifyMode === "addressed") {
39959
+ if (channelId && mutedChannels && mutedChannels.has(channelId)) return false;
39960
+ if (!agent) return false;
39961
+ return matchesAddressedAgent(text, agent);
39962
+ }
39937
39963
  return channelMessageShouldRespond(text, responseMode);
39938
39964
  }
39939
39965
  function parseNotifyCommand(text, currentChannelId) {
@@ -39943,6 +39969,15 @@ function parseNotifyCommand(text, currentChannelId) {
39943
39969
  if (arg === "" || arg === "status") return { action: "status", channelId: currentChannelId };
39944
39970
  return { action: "help", channelId: currentChannelId };
39945
39971
  }
39972
+ function notifyStatusMessage(muted, mode) {
39973
+ if (mode === "filter") {
39974
+ return muted ? ":mute: This channel is *muted* \u2014 I won\u2019t wake on its messages (an @-mention still reaches me). `/notify on` to resume." : ":bell: This channel is *active* \u2014 I wake on its messages. `/notify off` to mute.";
39975
+ }
39976
+ if (mode === "addressed") {
39977
+ return muted ? ":mute: This channel is *muted* \u2014 I won\u2019t wake on its messages, including ones that name me (a direct @-mention still reaches me). `/notify on` to resume." : ":bell: This channel is *active* \u2014 I wake on messages that address me by name, not on every message here (an @-mention always reaches me). `/notify off` to mute.";
39978
+ }
39979
+ return muted ? ":grey_question: Your *mute* for this channel is *saved but not in effect* \u2014 I\u2019m not in a per-channel dispatch mode right now, so it isn\u2019t changing what wakes me. It applies as soon as an operator enables one." : ":grey_question: *No mute saved* for this channel \u2014 though it wouldn\u2019t apply yet either way: I\u2019m not in a per-channel dispatch mode right now. `/notify off` saves one for when an operator enables it.";
39980
+ }
39946
39981
 
39947
39982
  // src/slack-list-channels.ts
39948
39983
  function normaliseForMatch(s) {
@@ -42887,7 +42922,8 @@ async function handleNotifyCommand(payload, codeName) {
42887
42922
  );
42888
42923
  return;
42889
42924
  }
42890
- const inactiveNote = NOTIFY_DISPATCH_MODE === "filter" ? "" : " _(note: I\u2019m not in per-channel filter mode right now, so this is saved but won\u2019t take effect until an operator enables it.)_";
42925
+ const muteIsLive = NOTIFY_DISPATCH_MODE === "filter" || NOTIFY_DISPATCH_MODE === "addressed";
42926
+ const inactiveNote = muteIsLive ? "" : " _(note: I\u2019m not in a per-channel dispatch mode right now, so this is saved but won\u2019t take effect until an operator enables it.)_";
42891
42927
  const { action } = parseNotifyCommand(payload.text, channelId);
42892
42928
  if (action === "help") {
42893
42929
  await postEphemeralViaResponseUrl(
@@ -42901,7 +42937,9 @@ async function handleNotifyCommand(payload, codeName) {
42901
42937
  const muted = MUTED_CHANNELS.has(channelId);
42902
42938
  await postEphemeralViaResponseUrl(
42903
42939
  responseUrl,
42904
- (muted ? ":mute: This channel is *muted* \u2014 I won\u2019t wake on its messages (an @-mention still reaches me). `/notify on` to resume." : ":bell: This channel is *active* \u2014 I wake on its messages. `/notify off` to mute.") + inactiveNote,
42940
+ // Pass the MODE, not muteIsLive: `filter` and `addressed` both honour the
42941
+ // mute but do not wake alike, and the status line has to say which.
42942
+ notifyStatusMessage(muted, NOTIFY_DISPATCH_MODE),
42905
42943
  codeName
42906
42944
  );
42907
42945
  return;
@@ -45422,7 +45460,20 @@ async function seedMutedChannelsFromApi() {
45422
45460
  }
45423
45461
  }
45424
45462
  function connectSocketModeSafely() {
45425
- if (NOTIFY_DISPATCH_MODE === "filter") void seedMutedChannelsFromApi();
45463
+ void startSocketModeAfterSeedingMutes();
45464
+ }
45465
+ async function startSocketModeAfterSeedingMutes() {
45466
+ if (NOTIFY_DISPATCH_MODE === "filter" || NOTIFY_DISPATCH_MODE === "addressed") {
45467
+ try {
45468
+ await seedMutedChannelsFromApi();
45469
+ } catch (err) {
45470
+ process.stderr.write(
45471
+ `slack-channel: notify-prefs seed threw, connecting anyway: ${err.message}
45472
+ `
45473
+ );
45474
+ }
45475
+ }
45476
+ if (isShuttingDown) return;
45426
45477
  void runOrRetry(connectSocketMode, {
45427
45478
  retryDelayMs: 1e4,
45428
45479
  onError: (err) => process.stderr.write(
@@ -45848,7 +45899,10 @@ async function connectSocketMode() {
45848
45899
  CHANNEL_RESPONSE_MODE,
45849
45900
  NOTIFY_DISPATCH_MODE,
45850
45901
  evt.channel,
45851
- MUTED_CHANNELS
45902
+ MUTED_CHANNELS,
45903
+ // ENG-8657: who this agent is, so `addressed` can tell a message
45904
+ // naming IT from one naming a different agent in the same channel.
45905
+ { botUserId, codeName: AGENT_CODE_NAME }
45852
45906
  ))
45853
45907
  return;
45854
45908
  }
@@ -36216,9 +36216,9 @@ var FLAG_REGISTRY = [
36216
36216
  },
36217
36217
  {
36218
36218
  key: "notify-dispatch",
36219
- description: "Membership-based channel-notify dispatch (ENG-7682 / notify Slice 1). off = today's behaviour: a non-@mention top-level channel message is dropped by the mention_only engagement gate (SLACK_CHANNEL_RESPONSE_MODE). membership = the agent's Slack MCP ADMITS non-@mention channel messages in channels its bot is a member of (the Socket Mode websocket already receives them), waking the agent in-thread via the SAME existing wake path used for @mentions/DMs. Only the mention_only engagement gate is relaxed - the echo/dedup, bot_id/self, and peer-classifier safety leaves still apply, so this never opens a bot-to-bot wake loop. The channel server can't evaluate flags, so the manager materializes the resolved value into the AGT_NOTIFY_DISPATCH spawn env (operator/canary override, ADR-0022). filter = like membership (opt-out) but honours a per-channel mute list: a member-channel message wakes the agent UNLESS the user muted that channel via the /notify slash command. The manager materializes the muted set into AGT_NOTIFY_MUTED_CHANNELS from agent_notify_channel_prefs (ENG-7682 Slice 2). Ships dark (default off).",
36219
+ description: `Membership-based channel-notify dispatch (ENG-7682 / notify Slice 1). off = today's behaviour: a non-@mention top-level channel message is dropped by the mention_only engagement gate (SLACK_CHANNEL_RESPONSE_MODE). membership = the agent's Slack MCP ADMITS non-@mention channel messages in channels its bot is a member of (the Socket Mode websocket already receives them), waking the agent in-thread via the SAME existing wake path used for @mentions/DMs. Only the mention_only engagement gate is relaxed - the echo/dedup, bot_id/self, and peer-classifier safety leaves still apply, so this never opens a bot-to-bot wake loop. The channel server can't evaluate flags, so the manager materializes the resolved value into the AGT_NOTIFY_DISPATCH spawn env (operator/canary override, ADR-0022). filter = like membership (opt-out) but honours a per-channel mute list: a member-channel message wakes the agent UNLESS the user muted that channel via the /notify slash command. The manager materializes the muted set into AGT_NOTIFY_MUTED_CHANNELS from agent_notify_channel_prefs (ENG-7682 Slice 2). addressed = like filter (same per-channel mute, checked FIRST so a mute outranks being named), but a member-channel message additionally has to address THIS agent to wake it: a real Slack mention of its bot user id, \`@<code_name>\` typed verbatim, or the code name used as a vocative at the start of the message ("koda:", "hey koda"). @team / @everyone still wake everyone. This is the fix for one named agent waking every agent in a shared channel (ENG-8657); matching is deliberately conservative, so a name mentioned mid-sentence does NOT wake, and an agent whose identity is unknown to the channel server stays asleep rather than waking on everything. Ships dark (default off).`,
36220
36220
  flagType: "enum",
36221
- allowedValues: ["off", "membership", "filter"],
36221
+ allowedValues: ["off", "membership", "filter", "addressed"],
36222
36222
  // Declared safe value is `off`: the mention_only gate stays in force, byte-
36223
36223
  // identical to today. membership is the deliberate, per-agent flip that
36224
36224
  // widens what wakes the agent.
@@ -41,7 +41,7 @@ import {
41
41
  writeDirectChatSessionState,
42
42
  writeEgressAllowlist,
43
43
  writePersistentClaudeWrapper
44
- } from "./chunk-6XCGZUSS.js";
44
+ } from "./chunk-72K46XUZ.js";
45
45
  import "./chunk-XWVM4KPK.js";
46
46
  export {
47
47
  EGRESS_BASELINE_DOMAINS,
@@ -87,4 +87,4 @@ export {
87
87
  writeEgressAllowlist,
88
88
  writePersistentClaudeWrapper
89
89
  };
90
- //# sourceMappingURL=persistent-session-HY6GUPBQ.js.map
90
+ //# sourceMappingURL=persistent-session-74MH2XTM.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  paneLogPath
3
- } from "./chunk-6XCGZUSS.js";
3
+ } from "./chunk-72K46XUZ.js";
4
4
  import "./chunk-XWVM4KPK.js";
5
5
 
6
6
  // src/lib/responsiveness-probe.ts
@@ -689,4 +689,4 @@ export {
689
689
  readAndResetSlackReplyBindingClassifications,
690
690
  readAndResetSlackReplyTargetClassifications
691
691
  };
692
- //# sourceMappingURL=responsiveness-probe-6EEZKJVV.js.map
692
+ //# sourceMappingURL=responsiveness-probe-5VNQQZNJ.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@integrity-labs/agt-cli",
3
- "version": "0.28.570",
3
+ "version": "0.28.572",
4
4
  "description": "Augmented Team CLI — agent provisioning and management",
5
5
  "type": "module",
6
6
  "engines": {