@integrity-labs/agt-cli 0.27.13 → 0.27.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.
@@ -3933,4 +3933,4 @@ export {
3933
3933
  attributeTranscriptUsageByRun,
3934
3934
  KANBAN_CHECK_COMMAND
3935
3935
  };
3936
- //# sourceMappingURL=chunk-YSBGIXJG.js.map
3936
+ //# sourceMappingURL=chunk-HT6EETEL.js.map
@@ -100,7 +100,7 @@ async function spawnPairSession(session) {
100
100
  return { ok: true };
101
101
  } catch {
102
102
  }
103
- const { resolveClaudeBinary } = await import("./persistent-session-ICYFLUAM.js");
103
+ const { resolveClaudeBinary } = await import("./persistent-session-N6SYAERB.js");
104
104
  const claudeBin = resolveClaudeBinary();
105
105
  const pairEnv = {
106
106
  ...process.env,
@@ -373,4 +373,4 @@ export {
373
373
  startClaudePair,
374
374
  submitClaudePairCode
375
375
  };
376
- //# sourceMappingURL=claude-pair-runtime-ZBQKBBMT.js.map
376
+ //# sourceMappingURL=claude-pair-runtime-ISBA6RDU.js.map
@@ -15,7 +15,7 @@ import {
15
15
  provisionOrientHook,
16
16
  provisionStopHook,
17
17
  requireHost
18
- } from "../chunk-Q4MWFZ5Y.js";
18
+ } from "../chunk-HKZFMGYE.js";
19
19
  import {
20
20
  getProjectDir as getProjectDir2,
21
21
  getReadyTasks,
@@ -46,7 +46,7 @@ import {
46
46
  stopAllSessionsAndWait,
47
47
  stopPersistentSession,
48
48
  takeZombieDetection
49
- } from "../chunk-GN4XPQWJ.js";
49
+ } from "../chunk-5ZUNHYKV.js";
50
50
  import {
51
51
  KANBAN_CHECK_COMMAND,
52
52
  appendDmFooter,
@@ -69,7 +69,7 @@ import {
69
69
  resolveConnectivityProbe,
70
70
  resolveDmTarget,
71
71
  wrapScheduledTaskPrompt
72
- } from "../chunk-YSBGIXJG.js";
72
+ } from "../chunk-HT6EETEL.js";
73
73
  import {
74
74
  parsePsRows,
75
75
  reapOrphanChannelMcps
@@ -3166,7 +3166,7 @@ var cachedFrameworkVersion = null;
3166
3166
  var lastVersionCheckAt = 0;
3167
3167
  var VERSION_CHECK_INTERVAL_MS = 5 * 60 * 1e3;
3168
3168
  var lastResponsivenessProbeAt = 0;
3169
- var agtCliVersion = true ? "0.27.13" : "dev";
3169
+ var agtCliVersion = true ? "0.27.14" : "dev";
3170
3170
  function resolveBrewPath(execFileSync4) {
3171
3171
  try {
3172
3172
  const out = execFileSync4("which", ["brew"], { timeout: 5e3 }).toString().trim();
@@ -4180,7 +4180,7 @@ async function pollCycle() {
4180
4180
  }
4181
4181
  try {
4182
4182
  const { detectHostSecurity } = await import("../host-security-6PDFG7F5.js");
4183
- const { collectDiagnostics } = await import("../persistent-session-ICYFLUAM.js");
4183
+ const { collectDiagnostics } = await import("../persistent-session-N6SYAERB.js");
4184
4184
  const diagCodeNames = [...agentState.persistentSessionAgents];
4185
4185
  const agentDiagnostics = diagCodeNames.length > 0 ? collectDiagnostics(diagCodeNames) : void 0;
4186
4186
  let tailscaleHostname;
@@ -4248,7 +4248,7 @@ async function pollCycle() {
4248
4248
  const {
4249
4249
  collectResponsivenessProbes,
4250
4250
  getResponsivenessIntervalMs
4251
- } = await import("../responsiveness-probe-WZNQ2762.js");
4251
+ } = await import("../responsiveness-probe-GPRQBBZG.js");
4252
4252
  const probeIntervalMs = getResponsivenessIntervalMs();
4253
4253
  if (now - lastResponsivenessProbeAt > probeIntervalMs) {
4254
4254
  const probeCodeNames = [...agentState.persistentSessionAgents];
@@ -8196,7 +8196,7 @@ async function processClaudePairSessions(agents) {
8196
8196
  killPairSession,
8197
8197
  pairTmuxSession,
8198
8198
  finalizeClaudePairOnboarding
8199
- } = await import("../claude-pair-runtime-ZBQKBBMT.js");
8199
+ } = await import("../claude-pair-runtime-ISBA6RDU.js");
8200
8200
  for (const pairId of pendingResp.cancelled_pair_ids ?? []) {
8201
8201
  log(`[claude-pair] sweeping orphan tmux session for pair ${pairId.slice(0, 8)}`);
8202
8202
  const killed = await killPairSession(pairTmuxSession(pairId));
@@ -14813,6 +14813,64 @@ function isMode(value) {
14813
14813
  return value === "thinking" || value === "working" || value === "waiting";
14814
14814
  }
14815
14815
 
14816
+ // src/slack-thread-context.ts
14817
+ var SLACK_AUTOLOAD_THREAD_LIMIT = 30;
14818
+ var SLACK_AUTOLOAD_THREAD_MAX_CHARS = 4e3;
14819
+ function formatThreadMessages(messages, nameById) {
14820
+ return messages.map((m) => `[${m.ts}] ${nameById.get(m.user) ?? m.user} (<@${m.user}>): ${m.text}`).join("\n");
14821
+ }
14822
+ function capThreadContext(formatted, maxChars) {
14823
+ if (formatted.length <= maxChars) return formatted;
14824
+ const marker = "[\u2026earlier thread messages omitted \u2014 slack.read_thread for full history\u2026]\n";
14825
+ if (maxChars <= marker.length) return marker.slice(0, maxChars);
14826
+ const tailBudget = maxChars - marker.length;
14827
+ const tail = formatted.slice(formatted.length - tailBudget);
14828
+ const firstNewline = tail.indexOf("\n");
14829
+ const clean = firstNewline >= 0 ? tail.slice(firstNewline + 1) : tail;
14830
+ return `${marker}${clean}`;
14831
+ }
14832
+ async function fetchThreadTranscript(channel, threadTs, limit, deps) {
14833
+ const { botToken, resolveUserName: resolveUserName2, fetchImpl = fetch } = deps;
14834
+ const cappedLimit = Math.min(Math.max(limit, 1), 200);
14835
+ const allMessages = [];
14836
+ let cursor;
14837
+ do {
14838
+ const remaining = cappedLimit - allMessages.length;
14839
+ if (remaining <= 0) break;
14840
+ const params = new URLSearchParams({
14841
+ channel,
14842
+ ts: threadTs,
14843
+ limit: String(Math.min(remaining, 100)),
14844
+ ...cursor ? { cursor } : {}
14845
+ });
14846
+ let data;
14847
+ try {
14848
+ const res = await fetchImpl(`https://slack.com/api/conversations.replies?${params}`, {
14849
+ headers: { Authorization: `Bearer ${botToken}` }
14850
+ });
14851
+ if (!res.ok) return { ok: false, error: `http_${res.status}` };
14852
+ data = await res.json();
14853
+ } catch (err) {
14854
+ return { ok: false, error: err instanceof Error ? err.message : "fetch_failed" };
14855
+ }
14856
+ if (!data.ok) return { ok: false, error: data.error ?? "unknown" };
14857
+ for (const msg of data.messages ?? []) {
14858
+ allMessages.push({
14859
+ user: msg.user ?? msg.bot_id ?? "unknown",
14860
+ text: msg.text ?? "",
14861
+ ts: msg.ts ?? ""
14862
+ });
14863
+ }
14864
+ cursor = data.response_metadata?.next_cursor || void 0;
14865
+ } while (cursor && allMessages.length < cappedLimit);
14866
+ const uniqueUserIds = [...new Set(allMessages.map((m) => m.user))];
14867
+ const resolved = await Promise.all(
14868
+ uniqueUserIds.map(async (id) => [id, await resolveUserName2(id)])
14869
+ );
14870
+ const nameById = new Map(resolved);
14871
+ return { ok: true, count: allMessages.length, formatted: formatThreadMessages(allMessages, nameById) };
14872
+ }
14873
+
14816
14874
  // src/impersonation.ts
14817
14875
  var ENV_VAR = "AGT_ACT_AS_AGENT_ID";
14818
14876
  var OVERRIDE_ENV_VAR = "ENABLE_IMPERSONATION_CHANNELS";
@@ -16657,7 +16715,6 @@ void resolveBotUserIdOrThrow().then((id) => {
16657
16715
  );
16658
16716
  if (authFailed) slackBotUserIdClient?.reportAuthHealth(false);
16659
16717
  });
16660
- var selfIdentityInstruction = `Mentions of your own Slack bot user are directed at you, even inside auto_followed threads.`;
16661
16718
  var mcp = new Server(
16662
16719
  { name: "slack", version: "0.1.0" },
16663
16720
  {
@@ -16672,12 +16729,11 @@ var mcp = new Server(
16672
16729
  // Highest-priority lines first — Claude Code truncates this string at
16673
16730
  // 2048 chars, so anything appended late silently disappears.
16674
16731
  "CRITICAL: every response to a Slack <channel> tag MUST go through slack.reply. Text in your session WITHOUT a slack.reply call never reaches the user \u2014 the message dies inside the agent process.",
16675
- 'Messages from Slack arrive as <channel source="slack" user="<slack-id>" user_name="<display-name>" channel="..." thread_ts="...">. Pass channel + thread_ts from the tag to slack.reply; always include thread_ts on threaded replies.',
16732
+ `Inbound: <channel ... thread_ts="..." [thread_context="..."]>. Pass channel + thread_ts to slack.reply on threads. thread_context = thread pre-loaded; ground replies ONLY in it, never another channel's.`,
16676
16733
  "Long task (3+ tool calls or >5s)? slack_progress_start (channel + thread_ts), slack_progress_update between steps, slack_progress_complete/_fail to close. One anchor edits in place; avoids thread spam. Not for one-shots.",
16677
- selfIdentityInstruction,
16678
16734
  "Inbound attachments: <channel> `files` is a JSON-serialised array \u2014 JSON.parse it. If an entry has `path`, the image is already downloaded \u2014 Read it directly, do NOT call slack.download_attachment. Use that tool only for entries with `file_id` but NO `path` (PDF, docx, csv): pass file_id + channel verbatim, then Read the returned path. Single-image messages also get a top-level `image_path`. Don't surface internal file-handling errors that don't affect the answer.",
16679
16735
  "Address users by user_name, never by raw user ID. In multi-participant threads the CURRENT speaker is the one on the latest <channel> tag.",
16680
- 'Mentioned in a channel \u2192 respond in that thread. DM \u2192 respond directly. auto_followed="true" \u2192 only reply if you have something useful to add.',
16736
+ 'Mentioned in a channel \u2192 respond in that thread. DM \u2192 respond directly. auto_followed="true" \u2192 only reply if useful, OR if your own bot user is @-mentioned (counts even in auto_followed).',
16681
16737
  "Reaction taxonomy (use slack.react sparingly \u2014 prefer a reply): \u{1F440} = ack (already auto-added on inbound, do not duplicate); \u2705 = success. NEVER react to signal failure \u2014 users can't tell why something failed from an emoji. On failure, slack.reply with one sentence explaining what went wrong (no stack traces, no secrets).",
16682
16738
  `When a thread message is NOT addressed to you (different @-mention, side conversation, auto_followed catch-up): SILENTLY SKIP \u2014 no reaction, no reply, no "this wasn't for me" message.`,
16683
16739
  "To deliver a file: save under your project dir, call slack.upload_file with path + channel + thread_ts."
@@ -16743,7 +16799,7 @@ mcp.setRequestHandler(ListToolsRequestSchema, async () => ({
16743
16799
  },
16744
16800
  {
16745
16801
  name: "slack.read_thread",
16746
- description: "Read the full message history of a Slack thread. Use this to catch up on thread context before replying, especially for auto-followed threads.",
16802
+ description: "Read the full message history of a Slack thread. Inbound thread replies already carry the surrounding thread inline as the <channel> tag's thread_context attribute \u2014 ground your reply in that first, and only call this tool when you need MORE history than thread_context shows (it is capped to recent messages) or to catch up on an auto-followed thread.",
16747
16803
  inputSchema: {
16748
16804
  type: "object",
16749
16805
  properties: {
@@ -17117,46 +17173,22 @@ mcp.setRequestHandler(CallToolRequestSchema, async (req) => {
17117
17173
  const limit = Math.min(Math.max(rawLimit ?? 50, 1), 200);
17118
17174
  noteThreadActivity(channel, thread_ts);
17119
17175
  try {
17120
- const allMessages = [];
17121
- let cursor;
17122
- do {
17123
- const remaining = limit - allMessages.length;
17124
- if (remaining <= 0) break;
17125
- const params = new URLSearchParams({
17126
- channel,
17127
- ts: thread_ts,
17128
- limit: String(Math.min(remaining, 100)),
17129
- ...cursor ? { cursor } : {}
17130
- });
17131
- const res = await fetch(`https://slack.com/api/conversations.replies?${params}`, {
17132
- headers: { Authorization: `Bearer ${BOT_TOKEN}` }
17133
- });
17134
- const data = await res.json();
17135
- if (!data.ok) {
17136
- return {
17137
- content: [{ type: "text", text: `Slack error: ${data.error}` }],
17138
- isError: true
17139
- };
17140
- }
17141
- for (const msg of data.messages ?? []) {
17142
- allMessages.push({
17143
- user: msg.user ?? msg.bot_id ?? "unknown",
17144
- text: msg.text ?? "",
17145
- ts: msg.ts ?? ""
17146
- });
17147
- }
17148
- cursor = data.response_metadata?.next_cursor || void 0;
17149
- } while (cursor && allMessages.length < limit);
17150
- const uniqueUserIds = [...new Set(allMessages.map((m) => m.user))];
17151
- const resolved = await Promise.all(uniqueUserIds.map(async (id) => [id, await resolveUserName(id)]));
17152
- const nameById = new Map(resolved);
17153
- const formatted = allMessages.map((m) => `[${m.ts}] ${nameById.get(m.user) ?? m.user} (<@${m.user}>): ${m.text}`).join("\n");
17176
+ const result = await fetchThreadTranscript(channel, thread_ts, limit, {
17177
+ botToken: BOT_TOKEN,
17178
+ resolveUserName
17179
+ });
17180
+ if (!result.ok) {
17181
+ return {
17182
+ content: [{ type: "text", text: `Slack error: ${result.error}` }],
17183
+ isError: true
17184
+ };
17185
+ }
17154
17186
  return {
17155
17187
  content: [{
17156
17188
  type: "text",
17157
- text: allMessages.length > 0 ? `Thread (${allMessages.length} messages):
17189
+ text: result.count > 0 ? `Thread (${result.count} messages):
17158
17190
 
17159
- ${formatted}` : "Thread is empty or not found."
17191
+ ${result.formatted}` : "Thread is empty or not found."
17160
17192
  }]
17161
17193
  };
17162
17194
  } catch (err) {
@@ -18246,6 +18278,29 @@ async function connectSocketMode() {
18246
18278
  (f) => f.kind === "image" && typeof f.path === "string"
18247
18279
  );
18248
18280
  const imagePath = downloadedImages.length === 1 ? downloadedImages[0].path : void 0;
18281
+ let threadContext;
18282
+ if (isThreadReply && channel && threadTs) {
18283
+ try {
18284
+ const transcript = await fetchThreadTranscript(
18285
+ channel,
18286
+ threadTs,
18287
+ SLACK_AUTOLOAD_THREAD_LIMIT,
18288
+ { botToken: BOT_TOKEN, resolveUserName }
18289
+ );
18290
+ if (transcript.ok && transcript.count >= 2) {
18291
+ threadContext = capThreadContext(
18292
+ transcript.formatted,
18293
+ SLACK_AUTOLOAD_THREAD_MAX_CHARS
18294
+ );
18295
+ }
18296
+ } catch (err) {
18297
+ const msg2 = err instanceof Error ? err.message : String(err);
18298
+ process.stderr.write(
18299
+ `slack-channel(${AGENT_CODE_NAME}): thread_context fetch failed (channel=${redactSlackId(channel)} thread=${redactSlackId(threadTs)}): ${msg2}
18300
+ `
18301
+ );
18302
+ }
18303
+ }
18249
18304
  await mcp.notification({
18250
18305
  method: "notifications/claude/channel",
18251
18306
  params: {
@@ -18260,7 +18315,9 @@ async function connectSocketMode() {
18260
18315
  // Only set these when we actually have attachments to avoid
18261
18316
  // bloating every notification with empty metadata.
18262
18317
  ...fileMeta.length > 0 ? { files: JSON.stringify(fileMeta) } : {},
18263
- ...imagePath ? { image_path: imagePath } : {}
18318
+ ...imagePath ? { image_path: imagePath } : {},
18319
+ // ENG-5830: the pre-loaded surrounding thread (thread replies only).
18320
+ ...threadContext ? { thread_context: threadContext } : {}
18264
18321
  }
18265
18322
  }
18266
18323
  });
@@ -21,8 +21,8 @@ import {
21
21
  stopPersistentSession,
22
22
  takeZombieDetection,
23
23
  writePersistentClaudeWrapper
24
- } from "./chunk-GN4XPQWJ.js";
25
- import "./chunk-YSBGIXJG.js";
24
+ } from "./chunk-5ZUNHYKV.js";
25
+ import "./chunk-HT6EETEL.js";
26
26
  import "./chunk-XWVM4KPK.js";
27
27
  export {
28
28
  SEND_KEYS_ENTER_DELAY_MS,
@@ -48,4 +48,4 @@ export {
48
48
  takeZombieDetection,
49
49
  writePersistentClaudeWrapper
50
50
  };
51
- //# sourceMappingURL=persistent-session-ICYFLUAM.js.map
51
+ //# sourceMappingURL=persistent-session-N6SYAERB.js.map
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  paneLogPath
3
- } from "./chunk-GN4XPQWJ.js";
4
- import "./chunk-YSBGIXJG.js";
3
+ } from "./chunk-5ZUNHYKV.js";
4
+ import "./chunk-HT6EETEL.js";
5
5
  import "./chunk-XWVM4KPK.js";
6
6
 
7
7
  // src/lib/responsiveness-probe.ts
@@ -30,4 +30,4 @@ export {
30
30
  collectResponsivenessProbes,
31
31
  getResponsivenessIntervalMs
32
32
  };
33
- //# sourceMappingURL=responsiveness-probe-WZNQ2762.js.map
33
+ //# sourceMappingURL=responsiveness-probe-GPRQBBZG.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@integrity-labs/agt-cli",
3
- "version": "0.27.13",
3
+ "version": "0.27.14",
4
4
  "description": "Augmented Team CLI — agent provisioning and management",
5
5
  "type": "module",
6
6
  "engines": {