@integrity-labs/agt-cli 0.28.545 → 0.28.547

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.
package/dist/bin/agt.js CHANGED
@@ -40,7 +40,7 @@ import {
40
40
  success,
41
41
  table,
42
42
  warn
43
- } from "../chunk-6CHFBMJM.js";
43
+ } from "../chunk-SYHPBJK7.js";
44
44
  import {
45
45
  AnchorSessionClient,
46
46
  CHANNEL_REGISTRY,
@@ -71,7 +71,7 @@ import {
71
71
  requiredMcpWildcard,
72
72
  resolveChannels,
73
73
  serializeManifestForSlackCli
74
- } from "../chunk-QPSEQLSI.js";
74
+ } from "../chunk-ST4PZ6RF.js";
75
75
  import "../chunk-XWVM4KPK.js";
76
76
 
77
77
  // src/bin/agt.ts
@@ -4834,7 +4834,7 @@ import { execFileSync, execSync } from "child_process";
4834
4834
  import { existsSync as existsSync10, realpathSync as realpathSync2 } from "fs";
4835
4835
  import chalk18 from "chalk";
4836
4836
  import ora16 from "ora";
4837
- var cliVersion = true ? "0.28.545" : "dev";
4837
+ var cliVersion = true ? "0.28.547" : "dev";
4838
4838
  async function fetchLatestVersion() {
4839
4839
  const host2 = getHost();
4840
4840
  if (!host2) return null;
@@ -6006,7 +6006,7 @@ function handleError(err) {
6006
6006
  }
6007
6007
 
6008
6008
  // src/bin/agt.ts
6009
- var cliVersion2 = true ? "0.28.545" : "dev";
6009
+ var cliVersion2 = true ? "0.28.547" : "dev";
6010
6010
  var program = new Command();
6011
6011
  program.name("agt").description("Augmented CLI \u2014 agent provisioning and management").version(cliVersion2).option("--json", "Emit machine-readable JSON output (suppress spinners and colors)").option("--skip-update-check", "Skip the automatic update check on startup");
6012
6012
  program.hook("preAction", async (thisCommand, actionCommand) => {
@@ -15694,4 +15694,4 @@ export {
15694
15694
  stopAllSessionsAndWait,
15695
15695
  getProjectDir
15696
15696
  };
15697
- //# sourceMappingURL=chunk-QPSEQLSI.js.map
15697
+ //# sourceMappingURL=chunk-ST4PZ6RF.js.map
@@ -42,7 +42,7 @@ import {
42
42
  resolveConnectivityProbe,
43
43
  worseConnectivityOutcome,
44
44
  wrapScheduledTaskPrompt
45
- } from "./chunk-QPSEQLSI.js";
45
+ } from "./chunk-ST4PZ6RF.js";
46
46
  import {
47
47
  parsePsRows
48
48
  } from "./chunk-XWVM4KPK.js";
@@ -5549,7 +5549,7 @@ function exchangeFailureKind(err) {
5549
5549
  }
5550
5550
 
5551
5551
  // src/lib/api-client.ts
5552
- var agtCliVersion = true ? "0.28.545" : "dev";
5552
+ var agtCliVersion = true ? "0.28.547" : "dev";
5553
5553
  var lastConfigHash = null;
5554
5554
  function setConfigHash(hash) {
5555
5555
  lastConfigHash = hash && hash.length > 0 ? hash : null;
@@ -8861,4 +8861,4 @@ export {
8861
8861
  managerInstallSystemUnitCommand,
8862
8862
  managerUninstallSystemUnitCommand
8863
8863
  };
8864
- //# sourceMappingURL=chunk-6CHFBMJM.js.map
8864
+ //# sourceMappingURL=chunk-SYHPBJK7.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-FM5746XM.js");
103
+ const { resolveClaudeBinary } = await import("./persistent-session-KVONGDAL.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-R3R5OWDM.js.map
376
+ //# sourceMappingURL=claude-pair-runtime-TZKJGXZU.js.map
@@ -53,7 +53,7 @@ import {
53
53
  safeWriteJsonAtomic,
54
54
  setConfigHash,
55
55
  tripClass
56
- } from "../chunk-6CHFBMJM.js";
56
+ } from "../chunk-SYHPBJK7.js";
57
57
  import {
58
58
  getProjectDir as getProjectDir2,
59
59
  getReadyTasks,
@@ -181,7 +181,7 @@ import {
181
181
  toOpencodeModel,
182
182
  transcriptActivityAgeSeconds,
183
183
  writeEgressAllowlist
184
- } from "../chunk-QPSEQLSI.js";
184
+ } from "../chunk-ST4PZ6RF.js";
185
185
  import {
186
186
  reapOrphanChannelMcps
187
187
  } from "../chunk-XWVM4KPK.js";
@@ -10455,7 +10455,7 @@ var agentRestartTimezoneInputs = /* @__PURE__ */ new Map();
10455
10455
  var lastVersionCheckAt = 0;
10456
10456
  var VERSION_CHECK_INTERVAL_MS = 5 * 60 * 1e3;
10457
10457
  var lastResponsivenessProbeAt = 0;
10458
- var agtCliVersion = true ? "0.28.545" : "dev";
10458
+ var agtCliVersion = true ? "0.28.547" : "dev";
10459
10459
  function resolveBrewPath(execFileSync2) {
10460
10460
  try {
10461
10461
  const out = execFileSync2("which", ["brew"], { timeout: 5e3 }).toString().trim();
@@ -11759,7 +11759,7 @@ function flushRestartedAgentDiagnostics(hostId, codeNames) {
11759
11759
  if (codeNames.length === 0) return;
11760
11760
  void (async () => {
11761
11761
  try {
11762
- const { collectDiagnostics } = await import("../persistent-session-FM5746XM.js");
11762
+ const { collectDiagnostics } = await import("../persistent-session-KVONGDAL.js");
11763
11763
  await api.post("/host/heartbeat", {
11764
11764
  host_id: hostId,
11765
11765
  agent_diagnostics: collectDiagnostics(codeNames, quarantineEntriesFor, claudeMdSizeFor)
@@ -11867,7 +11867,7 @@ async function pollCycle() {
11867
11867
  }
11868
11868
  try {
11869
11869
  const { detectHostSecurity } = await import("../host-security-6PDFG7F5.js");
11870
- const { collectDiagnostics } = await import("../persistent-session-FM5746XM.js");
11870
+ const { collectDiagnostics } = await import("../persistent-session-KVONGDAL.js");
11871
11871
  const diagCodeNames = [...agentState.persistentSessionAgents];
11872
11872
  const agentDiagnostics = diagCodeNames.length > 0 ? collectDiagnostics(diagCodeNames, quarantineEntriesFor, claudeMdSizeFor) : void 0;
11873
11873
  let tailscaleHostname;
@@ -11990,7 +11990,7 @@ async function pollCycle() {
11990
11990
  collectPanelessActivityProbes,
11991
11991
  getResponsivenessIntervalMs,
11992
11992
  occupancyQualificationClassifications
11993
- } = await import("../responsiveness-probe-WZMDBY3T.js");
11993
+ } = await import("../responsiveness-probe-OUHRYJYH.js");
11994
11994
  const probeIntervalMs = getResponsivenessIntervalMs();
11995
11995
  if (now - lastResponsivenessProbeAt > probeIntervalMs) {
11996
11996
  const probeCodeNames = [...agentState.persistentSessionAgents];
@@ -12081,7 +12081,7 @@ async function pollCycle() {
12081
12081
  collectResponsivenessProbes,
12082
12082
  livePendingInboundOldestAgeSeconds,
12083
12083
  parkPendingInbound
12084
- } = await import("../responsiveness-probe-WZMDBY3T.js");
12084
+ } = await import("../responsiveness-probe-OUHRYJYH.js");
12085
12085
  const { getProjectDir: wedgeProjectDir } = await import("../scheduler-engine-NDP36U7O.js");
12086
12086
  const wedgeNow = /* @__PURE__ */ new Date();
12087
12087
  const liveAgents = agentState.persistentSessionAgents;
@@ -15611,7 +15611,7 @@ async function handleRestartDoorbell(agentId, requestedAt, restartReason) {
15611
15611
  void api.post("/host/restart-ack", { host_id: hostId, agent_id: agentId, restart_requested_at: requestedAt }).catch((err) => log(`[restart-lane] ack failed for '${codeName}': ${err.message}`));
15612
15612
  void (async () => {
15613
15613
  try {
15614
- const { collectDiagnostics } = await import("../persistent-session-FM5746XM.js");
15614
+ const { collectDiagnostics } = await import("../persistent-session-KVONGDAL.js");
15615
15615
  await api.post("/host/heartbeat", {
15616
15616
  host_id: hostId,
15617
15617
  agent_diagnostics: collectDiagnostics([codeName], quarantineEntriesFor, claudeMdSizeFor)
@@ -15661,7 +15661,7 @@ async function respawnAgentAfterMcpStop(codeName, reason) {
15661
15661
  }
15662
15662
  try {
15663
15663
  const hostId = await getHostId();
15664
- const { collectDiagnostics } = await import("../persistent-session-FM5746XM.js");
15664
+ const { collectDiagnostics } = await import("../persistent-session-KVONGDAL.js");
15665
15665
  await api.post("/host/heartbeat", {
15666
15666
  host_id: hostId,
15667
15667
  agent_diagnostics: collectDiagnostics([codeName], quarantineEntriesFor, claudeMdSizeFor)
@@ -16185,7 +16185,7 @@ async function processClaudePairSessions(agents) {
16185
16185
  killPairSession,
16186
16186
  pairTmuxSession,
16187
16187
  finalizeClaudePairOnboarding
16188
- } = await import("../claude-pair-runtime-R3R5OWDM.js");
16188
+ } = await import("../claude-pair-runtime-TZKJGXZU.js");
16189
16189
  for (const pairId of pendingResp.cancelled_pair_ids ?? []) {
16190
16190
  log(`[claude-pair] sweeping orphan tmux session for pair ${pairId.slice(0, 8)}`);
16191
16191
  const killed = await killPairSession(pairTmuxSession(pairId));
@@ -1094,11 +1094,11 @@ var require_util = __commonJS({
1094
1094
  return false;
1095
1095
  }
1096
1096
  exports.schemaHasRules = schemaHasRules;
1097
- function schemaHasRulesButRef(schema, RULES) {
1097
+ function schemaHasRulesButRef(schema, RULES2) {
1098
1098
  if (typeof schema == "boolean")
1099
1099
  return !schema;
1100
1100
  for (const key in schema)
1101
- if (key !== "$ref" && RULES.all[key])
1101
+ if (key !== "$ref" && RULES2.all[key])
1102
1102
  return true;
1103
1103
  return false;
1104
1104
  }
@@ -2492,17 +2492,17 @@ var require_validate = __commonJS({
2492
2492
  }
2493
2493
  function schemaKeywords(it, types, typeErrors, errsCount) {
2494
2494
  const { gen, schema, data, allErrors, opts, self } = it;
2495
- const { RULES } = self;
2496
- if (schema.$ref && (opts.ignoreKeywordsWithRef || !(0, util_1.schemaHasRulesButRef)(schema, RULES))) {
2497
- gen.block(() => keywordCode(it, "$ref", RULES.all.$ref.definition));
2495
+ const { RULES: RULES2 } = self;
2496
+ if (schema.$ref && (opts.ignoreKeywordsWithRef || !(0, util_1.schemaHasRulesButRef)(schema, RULES2))) {
2497
+ gen.block(() => keywordCode(it, "$ref", RULES2.all.$ref.definition));
2498
2498
  return;
2499
2499
  }
2500
2500
  if (!opts.jtd)
2501
2501
  checkStrictTypes(it, types);
2502
2502
  gen.block(() => {
2503
- for (const group of RULES.rules)
2503
+ for (const group of RULES2.rules)
2504
2504
  groupKeywords(group);
2505
- groupKeywords(RULES.post);
2505
+ groupKeywords(RULES2.post);
2506
2506
  });
2507
2507
  function groupKeywords(group) {
2508
2508
  if (!(0, applicability_1.shouldUseGroup)(schema, group))
@@ -4204,10 +4204,10 @@ var require_core = __commonJS({
4204
4204
  }
4205
4205
  // Remove keyword
4206
4206
  removeKeyword(keyword) {
4207
- const { RULES } = this;
4208
- delete RULES.keywords[keyword];
4209
- delete RULES.all[keyword];
4210
- for (const group of RULES.rules) {
4207
+ const { RULES: RULES2 } = this;
4208
+ delete RULES2.keywords[keyword];
4209
+ delete RULES2.all[keyword];
4210
+ for (const group of RULES2.rules) {
4211
4211
  const i = group.rules.findIndex((rule) => rule.keyword === keyword);
4212
4212
  if (i >= 0)
4213
4213
  group.rules.splice(i, 1);
@@ -4375,9 +4375,9 @@ var require_core = __commonJS({
4375
4375
  }
4376
4376
  var KEYWORD_NAME = /^[a-z_$][a-z0-9_$:-]*$/i;
4377
4377
  function checkKeyword(keyword, def) {
4378
- const { RULES } = this;
4378
+ const { RULES: RULES2 } = this;
4379
4379
  (0, util_1.eachItem)(keyword, (kwd) => {
4380
- if (RULES.keywords[kwd])
4380
+ if (RULES2.keywords[kwd])
4381
4381
  throw new Error(`Keyword ${kwd} is already defined`);
4382
4382
  if (!KEYWORD_NAME.test(kwd))
4383
4383
  throw new Error(`Keyword ${kwd} has invalid name`);
@@ -4393,13 +4393,13 @@ var require_core = __commonJS({
4393
4393
  const post = definition === null || definition === void 0 ? void 0 : definition.post;
4394
4394
  if (dataType && post)
4395
4395
  throw new Error('keyword with "post" flag cannot have "type"');
4396
- const { RULES } = this;
4397
- let ruleGroup = post ? RULES.post : RULES.rules.find(({ type: t }) => t === dataType);
4396
+ const { RULES: RULES2 } = this;
4397
+ let ruleGroup = post ? RULES2.post : RULES2.rules.find(({ type: t }) => t === dataType);
4398
4398
  if (!ruleGroup) {
4399
4399
  ruleGroup = { type: dataType, rules: [] };
4400
- RULES.rules.push(ruleGroup);
4400
+ RULES2.rules.push(ruleGroup);
4401
4401
  }
4402
- RULES.keywords[keyword] = true;
4402
+ RULES2.keywords[keyword] = true;
4403
4403
  if (!definition)
4404
4404
  return;
4405
4405
  const rule = {
@@ -4414,7 +4414,7 @@ var require_core = __commonJS({
4414
4414
  addBeforeRule.call(this, ruleGroup, rule, definition.before);
4415
4415
  else
4416
4416
  ruleGroup.rules.push(rule);
4417
- RULES.all[keyword] = rule;
4417
+ RULES2.all[keyword] = rule;
4418
4418
  (_a = definition.implements) === null || _a === void 0 ? void 0 : _a.forEach((kwd) => this.addKeyword(kwd));
4419
4419
  }
4420
4420
  function addBeforeRule(ruleGroup, rule, before) {
@@ -20985,7 +20985,63 @@ var StdioServerTransport = class {
20985
20985
  }
20986
20986
  };
20987
20987
 
20988
+ // src/redact.ts
20989
+ var REDACTED = "[redacted]";
20990
+ var MAX_RELAYED_MESSAGE_CHARS = 600;
20991
+ function truncationMarker(dropped) {
20992
+ return `\u2026 [truncated, ${dropped} chars]`;
20993
+ }
20994
+ function truncateWithMarker(text, max) {
20995
+ if (text.length <= max) return text;
20996
+ let keep = max;
20997
+ for (let i = 0; i < 8; i++) {
20998
+ const candidate = Math.max(0, max - truncationMarker(text.length - keep).length);
20999
+ if (candidate === keep) break;
21000
+ keep = candidate;
21001
+ }
21002
+ return text.slice(0, keep) + truncationMarker(text.length - keep);
21003
+ }
21004
+ var RULES = [
21005
+ // Authorization headers, with or without a scheme.
21006
+ { name: "authorization-header", pattern: /\b(authorization\s*[:=]\s*)(?:bearer\s+|basic\s+)?\S+/gi, replace: `$1${REDACTED}` },
21007
+ { name: "bearer", pattern: /\bbearer\s+[A-Za-z0-9._~+/-]{8,}=*/gi, replace: `Bearer ${REDACTED}` },
21008
+ // Cookies.
21009
+ { name: "cookie-header", pattern: /\b(set-cookie|cookie)\s*[:=]\s*\S+/gi, replace: `$1: ${REDACTED}` },
21010
+ // JWTs — three base64url segments. Caught before generic blobs.
21011
+ { name: "jwt", pattern: /\beyJ[A-Za-z0-9_-]{5,}\.[A-Za-z0-9_-]{5,}\.[A-Za-z0-9_-]{5,}/g, replace: REDACTED },
21012
+ // Platform + vendor key prefixes. `tlk_` is ours (host API keys).
21013
+ { name: "prefixed-key", pattern: /\b(?:tlk|sk|pk|rk|gho|ghp|ghu|ghs|ghr|github_pat|xoxb|xoxp|xoxa|xapp|lin_api|shpat|shpss)[_-][A-Za-z0-9_-]{8,}/gi, replace: REDACTED },
21014
+ // AWS access key ids.
21015
+ { name: "aws-access-key-id", pattern: /\b(?:AKIA|ASIA|ABIA|ACCA)[0-9A-Z]{12,}\b/g, replace: REDACTED },
21016
+ // Presigned-URL signature params and their friends.
21017
+ { name: "signature-param", pattern: /\b(X-Amz-Signature|X-Amz-Security-Token|X-Amz-Credential|Signature|sig)=[^&\s"']+/gi, replace: `$1=${REDACTED}` },
21018
+ // Generic secret-bearing key=value / key: value pairs.
21019
+ { name: "secret-kv", pattern: /\b(password|passwd|pwd|secret|token|api[-_]?key|access[-_]?key|private[-_]?key|client[-_]?secret|refresh[-_]?token|session[-_]?token|credential)s?\s*[:=]\s*(?:"[^"]*"|'[^']*'|\S+)/gi, replace: `$1=${REDACTED}` },
21020
+ // PEM blocks.
21021
+ { name: "pem", pattern: /-----BEGIN[^-]{0,64}-----[\s\S]*?-----END[^-]{0,64}-----/g, replace: REDACTED }
21022
+ ];
21023
+ function redactSensitive(message) {
21024
+ let out = message;
21025
+ for (const rule of RULES) {
21026
+ out = out.replace(rule.pattern, rule.replace);
21027
+ }
21028
+ out = out.replace(/\s+/g, " ").trim();
21029
+ return truncateWithMarker(out, MAX_RELAYED_MESSAGE_CHARS);
21030
+ }
21031
+
20988
21032
  // src/broker-client.ts
21033
+ var REDACTED_ONLY = REDACTED;
21034
+ function serverMessageFrom(payload) {
21035
+ if (!payload || typeof payload !== "object") return null;
21036
+ for (const key of ["error", "reason"]) {
21037
+ const v = payload[key];
21038
+ if (typeof v === "string" && v.trim() !== "") {
21039
+ const safe = redactSensitive(v);
21040
+ return safe.trim() === "" || safe.trim() === REDACTED_ONLY ? null : safe;
21041
+ }
21042
+ }
21043
+ return null;
21044
+ }
20989
21045
  function makeError(status, message, detail) {
20990
21046
  const err = new Error(message);
20991
21047
  err.status = status;
@@ -21070,7 +21126,7 @@ var AdminDebugClient = class _AdminDebugClient {
21070
21126
  parseFailed = true;
21071
21127
  }
21072
21128
  if (!res.ok) {
21073
- const message = payload && typeof payload === "object" && "error" in payload && typeof payload.error === "string" ? payload.error : `admin-debug request failed: ${res.status}`;
21129
+ const message = serverMessageFrom(payload) ?? `admin-debug request failed: ${res.status}`;
21074
21130
  throw makeError(res.status, message, payload);
21075
21131
  }
21076
21132
  if (parseFailed) {
@@ -21195,7 +21251,7 @@ var AdminDebugClient = class _AdminDebugClient {
21195
21251
  parseFailed = true;
21196
21252
  }
21197
21253
  if (!res.ok) {
21198
- const message = payload && typeof payload === "object" && "error" in payload && typeof payload.error === "string" ? payload.error : `admin-debug request failed: ${res.status}`;
21254
+ const message = serverMessageFrom(payload) ?? `admin-debug request failed: ${res.status}`;
21199
21255
  throw makeError(res.status, message, payload);
21200
21256
  }
21201
21257
  if (parseFailed) {
@@ -22868,6 +22868,411 @@ var init_slack_block_kit_runtime = __esm({
22868
22868
  }
22869
22869
  });
22870
22870
 
22871
+ // src/slack-message-text.ts
22872
+ function asRecord(v) {
22873
+ return typeof v === "object" && v !== null ? v : void 0;
22874
+ }
22875
+ function asArray(v) {
22876
+ return Array.isArray(v) ? v : [];
22877
+ }
22878
+ function textNode(v) {
22879
+ if (typeof v === "string") return v.trim();
22880
+ const rec = asRecord(v);
22881
+ if (!rec) return "";
22882
+ const t = rec["text"];
22883
+ return typeof t === "string" ? t.trim() : "";
22884
+ }
22885
+ var RICH_TEXT_MAX_DEPTH = 64;
22886
+ function richTextToString(node, depth = 0) {
22887
+ if (depth >= RICH_TEXT_MAX_DEPTH) return "[nested rich text truncated]";
22888
+ const rec = asRecord(node);
22889
+ if (!rec) return "";
22890
+ const parts = [];
22891
+ const t = rec["text"];
22892
+ if (typeof t === "string") parts.push(t);
22893
+ const url = rec["url"];
22894
+ if (typeof url === "string" && !t) parts.push(url);
22895
+ const userId = rec["user_id"];
22896
+ if (typeof userId === "string") parts.push(`<@${userId}>`);
22897
+ const channelId = rec["channel_id"];
22898
+ if (typeof channelId === "string") parts.push(`<#${channelId}>`);
22899
+ const type = typeof rec["type"] === "string" ? rec["type"] : "";
22900
+ const children = asArray(rec["elements"]).map((c) => richTextToString(c, depth + 1)).filter(Boolean);
22901
+ if (children.length > 0) {
22902
+ if (type === "rich_text_table") parts.push(children.join("\n"));
22903
+ else if (type === "rich_text_table_row") parts.push(children.join(" | "));
22904
+ else if (type === "rich_text_list") {
22905
+ parts.push(children.map((c) => `- ${c}`).join("\n"));
22906
+ } else if (type === "rich_text_quote" || type === "rich_text_preformatted") {
22907
+ parts.push(children.join("\n"));
22908
+ } else parts.push(children.join(""));
22909
+ }
22910
+ return parts.join("").trim();
22911
+ }
22912
+ function blockToString(block) {
22913
+ const b = asRecord(block);
22914
+ if (!b) return "";
22915
+ const type = typeof b["type"] === "string" ? b["type"] : "";
22916
+ if (type === "divider") return "";
22917
+ const lines = [];
22918
+ const main = textNode(b["text"]);
22919
+ if (main) lines.push(main);
22920
+ for (const f of asArray(b["fields"])) {
22921
+ const s = textNode(f);
22922
+ if (s) lines.push(s);
22923
+ }
22924
+ for (const el of asArray(b["elements"])) {
22925
+ const e = asRecord(el);
22926
+ if (!e) continue;
22927
+ if (e["type"] === "rich_text_section" || Array.isArray(e["elements"])) {
22928
+ const rich = richTextToString(e);
22929
+ if (rich) lines.push(rich);
22930
+ continue;
22931
+ }
22932
+ const s = textNode(e["text"]) || textNode(e);
22933
+ if (s) lines.push(s);
22934
+ }
22935
+ if (type === "image") {
22936
+ const alt = b["alt_text"];
22937
+ if (typeof alt === "string" && alt.trim()) lines.push(`[image: ${alt.trim()}]`);
22938
+ }
22939
+ return lines.join("\n").trim();
22940
+ }
22941
+ function attachmentToString(att) {
22942
+ const a = asRecord(att);
22943
+ if (!a) return "";
22944
+ const lines = [];
22945
+ for (const key2 of ["pretext", "title", "text"]) {
22946
+ const v = a[key2];
22947
+ if (typeof v === "string" && v.trim()) lines.push(v.trim());
22948
+ }
22949
+ for (const f of asArray(a["fields"])) {
22950
+ const fr = asRecord(f);
22951
+ if (!fr) continue;
22952
+ const title = typeof fr["title"] === "string" ? fr["title"].trim() : "";
22953
+ const value = typeof fr["value"] === "string" ? fr["value"].trim() : "";
22954
+ if (title && value) lines.push(`${title}: ${value}`);
22955
+ else if (title || value) lines.push(title || value);
22956
+ }
22957
+ for (const b of asArray(a["blocks"])) {
22958
+ const s = blockToString(b);
22959
+ if (s) lines.push(s);
22960
+ }
22961
+ if (lines.length === 0) {
22962
+ const fb = a["fallback"];
22963
+ if (typeof fb === "string" && fb.trim()) lines.push(fb.trim());
22964
+ }
22965
+ return lines.join("\n").trim();
22966
+ }
22967
+ var SLACK_MESSAGE_TEXT_MAX_CHARS = 4e3;
22968
+ function truncateMessageText(s, maxChars = SLACK_MESSAGE_TEXT_MAX_CHARS) {
22969
+ if (s.length <= maxChars) return s;
22970
+ const SHORT_MARKER = "\u2026";
22971
+ if (maxChars <= SHORT_MARKER.length) return SHORT_MARKER.slice(0, maxChars);
22972
+ const omittedFrom = (n) => `
22973
+ [\u2026 truncated, ${s.length - n} more characters]`;
22974
+ let keep = Math.max(0, maxChars - omittedFrom(maxChars).length);
22975
+ keep = Math.max(0, maxChars - omittedFrom(keep).length);
22976
+ if (keep <= 0) return s.slice(0, maxChars - SHORT_MARKER.length) + SHORT_MARKER;
22977
+ return s.slice(0, keep) + omittedFrom(keep);
22978
+ }
22979
+ function describeEmptyMessage(msg) {
22980
+ const blocks = asArray(msg.blocks);
22981
+ const attachments = asArray(msg.attachments);
22982
+ if (blocks.length === 0 && attachments.length === 0) return "";
22983
+ const types = blocks.map((b) => {
22984
+ const r = asRecord(b);
22985
+ return r && typeof r["type"] === "string" ? r["type"] : "unknown";
22986
+ }).filter(Boolean);
22987
+ const unique = [...new Set(types)];
22988
+ const parts = [];
22989
+ if (blocks.length > 0) {
22990
+ parts.push(`${blocks.length} block${blocks.length === 1 ? "" : "s"}`);
22991
+ if (unique.length > 0) parts.push(`of type ${unique.join(", ")}`);
22992
+ }
22993
+ if (attachments.length > 0) {
22994
+ parts.push(`${attachments.length} attachment${attachments.length === 1 ? "" : "s"}`);
22995
+ }
22996
+ return `[no readable text content - ${parts.join(" ")}]`;
22997
+ }
22998
+ function slackMessageBody(msg) {
22999
+ if (!msg) return "";
23000
+ const top = typeof msg.text === "string" ? msg.text.trim() : "";
23001
+ const blockText = asArray(msg.blocks).map(blockToString).filter(Boolean).join("\n");
23002
+ const attachmentText = asArray(msg.attachments).map(attachmentToString).filter(Boolean).join("\n");
23003
+ const rich = [blockText, attachmentText].filter(Boolean).join("\n");
23004
+ if (!rich) return top;
23005
+ if (!top) return rich;
23006
+ if (rich.startsWith(top)) return rich;
23007
+ return `${top}
23008
+ ${rich}`;
23009
+ }
23010
+
23011
+ // ../core/dist/channels/slack-rich-text.js
23012
+ var MAX_DEPTH = 12;
23013
+ function isRecord(v) {
23014
+ return typeof v === "object" && v !== null && !Array.isArray(v);
23015
+ }
23016
+ function asString(v) {
23017
+ return typeof v === "string" ? v : "";
23018
+ }
23019
+ function asArray2(v) {
23020
+ return Array.isArray(v) ? v : [];
23021
+ }
23022
+ function isTableElement(el) {
23023
+ return isRecord(el) && asString(el.type).includes("table");
23024
+ }
23025
+ function renderEmoji(el) {
23026
+ const unicode = asString(el.unicode);
23027
+ if (unicode) {
23028
+ try {
23029
+ const cps = unicode.split("-").map((h) => parseInt(h, 16));
23030
+ if (cps.every((n) => Number.isFinite(n) && n >= 0 && n <= 1114111)) {
23031
+ return String.fromCodePoint(...cps);
23032
+ }
23033
+ } catch {
23034
+ }
23035
+ }
23036
+ const name = asString(el.name);
23037
+ return name ? `:${name}:` : "";
23038
+ }
23039
+ function renderLeaf(el) {
23040
+ if (!isRecord(el))
23041
+ return "";
23042
+ switch (asString(el.type)) {
23043
+ case "text":
23044
+ return asString(el.text);
23045
+ case "link": {
23046
+ const label = asString(el.text);
23047
+ const url = asString(el.url);
23048
+ if (label && url && label !== url)
23049
+ return `${label} (${url})`;
23050
+ return label || url;
23051
+ }
23052
+ case "emoji":
23053
+ return renderEmoji(el);
23054
+ case "user":
23055
+ return `<@${asString(el.user_id)}>`;
23056
+ case "usergroup":
23057
+ return `<!subteam^${asString(el.usergroup_id)}>`;
23058
+ case "channel":
23059
+ return `<#${asString(el.channel_id)}>`;
23060
+ case "broadcast":
23061
+ return `@${asString(el.range) || "channel"}`;
23062
+ case "date":
23063
+ return asString(el.fallback) || asString(el.timestamp);
23064
+ default:
23065
+ if (Array.isArray(el.elements))
23066
+ return renderInline(el.elements);
23067
+ return asString(el.text);
23068
+ }
23069
+ }
23070
+ function renderInline(elements) {
23071
+ return elements.map(renderLeaf).join("");
23072
+ }
23073
+ function deepText(node, depth) {
23074
+ if (depth > MAX_DEPTH)
23075
+ return "";
23076
+ if (typeof node === "string")
23077
+ return node;
23078
+ if (Array.isArray(node))
23079
+ return node.map((n) => deepText(n, depth + 1)).join("");
23080
+ if (!isRecord(node))
23081
+ return "";
23082
+ const type = asString(node.type);
23083
+ if (type && type !== "rich_text" && !type.startsWith("rich_text_") && !type.includes("table")) {
23084
+ return renderLeaf(node);
23085
+ }
23086
+ if (Array.isArray(node.elements))
23087
+ return node.elements.map((n) => deepText(n, depth + 1)).join("");
23088
+ if (Array.isArray(node.rows))
23089
+ return node.rows.map((n) => deepText(n, depth + 1)).join(" ");
23090
+ return asString(node.text);
23091
+ }
23092
+ function renderCell(cell) {
23093
+ if (!isRecord(cell))
23094
+ return deepText(cell, 0).replace(/\s*\n\s*/g, " ").trim();
23095
+ const inner = Array.isArray(cell.elements) ? renderSection(cell, 0) : deepText(cell, 0);
23096
+ return inner.replace(/\s*\n\s*/g, " ").trim();
23097
+ }
23098
+ function renderTable(el) {
23099
+ const rawRows = asArray2(el.elements).length ? asArray2(el.elements) : asArray2(el.rows);
23100
+ const rows = [];
23101
+ for (const row of rawRows) {
23102
+ if (!isRecord(row) && !Array.isArray(row))
23103
+ continue;
23104
+ const rawCells = Array.isArray(row) ? row : asArray2(row.elements).length ? asArray2(row.elements) : asArray2(row.cells);
23105
+ if (rawCells.length === 0)
23106
+ continue;
23107
+ rows.push(rawCells.map(renderCell));
23108
+ }
23109
+ if (rows.length === 0) {
23110
+ const fallback = deepText(el, 0).replace(/[ \t]+\n/g, "\n").trim();
23111
+ return fallback;
23112
+ }
23113
+ const colCount = rows.reduce((max, r) => Math.max(max, r.length), 0);
23114
+ const pad = (r) => {
23115
+ const cells = r.slice();
23116
+ while (cells.length < colCount)
23117
+ cells.push("");
23118
+ return cells.map((c) => c.replace(/\|/g, "\\|"));
23119
+ };
23120
+ const lines = [];
23121
+ const header = rows[0] ?? [];
23122
+ const body = rows.slice(1);
23123
+ lines.push(`| ${pad(header).join(" | ")} |`);
23124
+ lines.push(`| ${Array.from({ length: colCount }, () => "---").join(" | ")} |`);
23125
+ for (const r of body)
23126
+ lines.push(`| ${pad(r).join(" | ")} |`);
23127
+ return lines.join("\n");
23128
+ }
23129
+ function renderSection(section, depth) {
23130
+ if (depth > MAX_DEPTH || !isRecord(section))
23131
+ return "";
23132
+ const type = asString(section.type);
23133
+ if (isTableElement(section))
23134
+ return renderTable(section);
23135
+ switch (type) {
23136
+ case "rich_text_section":
23137
+ return renderInline(asArray2(section.elements));
23138
+ case "rich_text_preformatted": {
23139
+ const code = renderInline(asArray2(section.elements));
23140
+ return code ? `\`\`\`
23141
+ ${code}
23142
+ \`\`\`` : "";
23143
+ }
23144
+ case "rich_text_quote": {
23145
+ const quoted = renderInline(asArray2(section.elements));
23146
+ return quoted ? quoted.split("\n").map((l) => `> ${l}`).join("\n") : "";
23147
+ }
23148
+ case "rich_text_list": {
23149
+ const ordered = asString(section.style) === "ordered";
23150
+ const items = asArray2(section.elements).map((item, i) => {
23151
+ const body = renderSection(item, depth + 1) || renderInline(asArray2(item?.elements));
23152
+ const marker = ordered ? `${i + 1}.` : "-";
23153
+ return `${marker} ${body}`.trimEnd();
23154
+ });
23155
+ return items.join("\n");
23156
+ }
23157
+ default:
23158
+ if (Array.isArray(section.elements))
23159
+ return renderInline(asArray2(section.elements));
23160
+ return deepText(section, depth + 1);
23161
+ }
23162
+ }
23163
+ function renderSlackBlocks(blocks) {
23164
+ let hadTable = false;
23165
+ const out = [];
23166
+ try {
23167
+ for (const block of asArray2(blocks)) {
23168
+ if (!isRecord(block))
23169
+ continue;
23170
+ if (isTableElement(block)) {
23171
+ hadTable = true;
23172
+ const rendered = renderTable(block);
23173
+ if (rendered.trim().length > 0)
23174
+ out.push(rendered);
23175
+ continue;
23176
+ }
23177
+ if (asString(block.type) !== "rich_text")
23178
+ continue;
23179
+ for (const section of asArray2(block.elements)) {
23180
+ if (isTableElement(section))
23181
+ hadTable = true;
23182
+ const rendered = renderSection(section, 0);
23183
+ if (rendered.trim().length > 0)
23184
+ out.push(rendered);
23185
+ }
23186
+ }
23187
+ } catch {
23188
+ }
23189
+ const text = out.join("\n\n").replace(/[ \t]+$/gm, "").replace(/\n{3,}/g, "\n\n").trim();
23190
+ return { text, hadTable };
23191
+ }
23192
+ function mergeInboundText(text, blocks) {
23193
+ const { text: rendered, hadTable } = renderSlackBlocks(blocks);
23194
+ if (!hadTable)
23195
+ return { content: text, recoveredTable: false };
23196
+ const content = rendered.length > 0 ? rendered : text;
23197
+ return { content, recoveredTable: rendered.length > 0 && content !== text };
23198
+ }
23199
+
23200
+ // ../core/dist/channels/governance/slack-forwarded.js
23201
+ function asTrimmed(v) {
23202
+ return typeof v === "string" ? v.trim() : "";
23203
+ }
23204
+ function extractForwardedContent(attachments) {
23205
+ if (!Array.isArray(attachments))
23206
+ return { text: "", files: [] };
23207
+ const parts = [];
23208
+ const files = [];
23209
+ for (const raw of attachments) {
23210
+ if (!raw || typeof raw !== "object")
23211
+ continue;
23212
+ const att = raw;
23213
+ const textBody = asTrimmed(att.text);
23214
+ let body = textBody || asTrimmed(att.fallback);
23215
+ const blockSources = [];
23216
+ if (Array.isArray(att.blocks))
23217
+ blockSources.push(att.blocks);
23218
+ if (Array.isArray(att.message_blocks)) {
23219
+ for (const mb of att.message_blocks)
23220
+ blockSources.push(mb?.message?.blocks);
23221
+ }
23222
+ for (const source of blockSources) {
23223
+ const rendered = renderSlackBlocks(source);
23224
+ const renderedText = rendered.text.trim();
23225
+ if (renderedText && (!textBody || rendered.hadTable)) {
23226
+ body = renderedText;
23227
+ break;
23228
+ }
23229
+ }
23230
+ const title = asTrimmed(att.title);
23231
+ const link = asTrimmed(att.title_link) || asTrimmed(att.from_url);
23232
+ const imageUrl = asTrimmed(att.image_url) || asTrimmed(att.thumb_url);
23233
+ const lines = [];
23234
+ if (body)
23235
+ lines.push(body);
23236
+ if (title && title !== body)
23237
+ lines.push(title);
23238
+ if (link)
23239
+ lines.push(link);
23240
+ if (imageUrl)
23241
+ lines.push(`[image] ${imageUrl}`);
23242
+ if (lines.length)
23243
+ parts.push(lines.join("\n"));
23244
+ if (Array.isArray(att.files))
23245
+ files.push(...att.files);
23246
+ }
23247
+ return { text: parts.join("\n\n"), files };
23248
+ }
23249
+ function hasForwardedContent(attachments) {
23250
+ const { text, files } = extractForwardedContent(attachments);
23251
+ return text.length > 0 || files.length > 0;
23252
+ }
23253
+
23254
+ // src/slack-inbound-text.ts
23255
+ function composeInboundText(evt, maxChars = SLACK_MESSAGE_TEXT_MAX_CHARS) {
23256
+ if (!evt) return { content: "", gateText: "", recoveredTable: false, recoveredForwarded: false, files: [] };
23257
+ const gateText = slackMessageBody({ text: evt.text, blocks: evt.blocks });
23258
+ const { content: merged, recoveredTable } = mergeInboundText(gateText, evt.blocks);
23259
+ const forwarded = extractForwardedContent(evt.attachments);
23260
+ let content = merged;
23261
+ if (forwarded.text) {
23262
+ content = merged.trim().length > 0 ? `${merged}
23263
+
23264
+ ${forwarded.text}` : forwarded.text;
23265
+ }
23266
+ if (!content.trim()) content = describeEmptyMessage(evt);
23267
+ return {
23268
+ content: truncateMessageText(content, maxChars),
23269
+ gateText,
23270
+ recoveredTable,
23271
+ recoveredForwarded: forwarded.text.length > 0,
23272
+ files: forwarded.files
23273
+ };
23274
+ }
23275
+
22871
23276
  // ../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v4/core/core.js
22872
23277
  var NEVER = Object.freeze({
22873
23278
  status: "aborted"
@@ -29839,249 +30244,6 @@ var Server = class extends Protocol {
29839
30244
  }
29840
30245
  };
29841
30246
 
29842
- // ../core/dist/channels/slack-rich-text.js
29843
- var MAX_DEPTH = 12;
29844
- function isRecord(v) {
29845
- return typeof v === "object" && v !== null && !Array.isArray(v);
29846
- }
29847
- function asString(v) {
29848
- return typeof v === "string" ? v : "";
29849
- }
29850
- function asArray(v) {
29851
- return Array.isArray(v) ? v : [];
29852
- }
29853
- function isTableElement(el) {
29854
- return isRecord(el) && asString(el.type).includes("table");
29855
- }
29856
- function renderEmoji(el) {
29857
- const unicode = asString(el.unicode);
29858
- if (unicode) {
29859
- try {
29860
- const cps = unicode.split("-").map((h) => parseInt(h, 16));
29861
- if (cps.every((n) => Number.isFinite(n) && n >= 0 && n <= 1114111)) {
29862
- return String.fromCodePoint(...cps);
29863
- }
29864
- } catch {
29865
- }
29866
- }
29867
- const name = asString(el.name);
29868
- return name ? `:${name}:` : "";
29869
- }
29870
- function renderLeaf(el) {
29871
- if (!isRecord(el))
29872
- return "";
29873
- switch (asString(el.type)) {
29874
- case "text":
29875
- return asString(el.text);
29876
- case "link": {
29877
- const label = asString(el.text);
29878
- const url = asString(el.url);
29879
- if (label && url && label !== url)
29880
- return `${label} (${url})`;
29881
- return label || url;
29882
- }
29883
- case "emoji":
29884
- return renderEmoji(el);
29885
- case "user":
29886
- return `<@${asString(el.user_id)}>`;
29887
- case "usergroup":
29888
- return `<!subteam^${asString(el.usergroup_id)}>`;
29889
- case "channel":
29890
- return `<#${asString(el.channel_id)}>`;
29891
- case "broadcast":
29892
- return `@${asString(el.range) || "channel"}`;
29893
- case "date":
29894
- return asString(el.fallback) || asString(el.timestamp);
29895
- default:
29896
- if (Array.isArray(el.elements))
29897
- return renderInline(el.elements);
29898
- return asString(el.text);
29899
- }
29900
- }
29901
- function renderInline(elements) {
29902
- return elements.map(renderLeaf).join("");
29903
- }
29904
- function deepText(node, depth) {
29905
- if (depth > MAX_DEPTH)
29906
- return "";
29907
- if (typeof node === "string")
29908
- return node;
29909
- if (Array.isArray(node))
29910
- return node.map((n) => deepText(n, depth + 1)).join("");
29911
- if (!isRecord(node))
29912
- return "";
29913
- const type = asString(node.type);
29914
- if (type && type !== "rich_text" && !type.startsWith("rich_text_") && !type.includes("table")) {
29915
- return renderLeaf(node);
29916
- }
29917
- if (Array.isArray(node.elements))
29918
- return node.elements.map((n) => deepText(n, depth + 1)).join("");
29919
- if (Array.isArray(node.rows))
29920
- return node.rows.map((n) => deepText(n, depth + 1)).join(" ");
29921
- return asString(node.text);
29922
- }
29923
- function renderCell(cell) {
29924
- if (!isRecord(cell))
29925
- return deepText(cell, 0).replace(/\s*\n\s*/g, " ").trim();
29926
- const inner = Array.isArray(cell.elements) ? renderSection(cell, 0) : deepText(cell, 0);
29927
- return inner.replace(/\s*\n\s*/g, " ").trim();
29928
- }
29929
- function renderTable(el) {
29930
- const rawRows = asArray(el.elements).length ? asArray(el.elements) : asArray(el.rows);
29931
- const rows = [];
29932
- for (const row of rawRows) {
29933
- if (!isRecord(row) && !Array.isArray(row))
29934
- continue;
29935
- const rawCells = Array.isArray(row) ? row : asArray(row.elements).length ? asArray(row.elements) : asArray(row.cells);
29936
- if (rawCells.length === 0)
29937
- continue;
29938
- rows.push(rawCells.map(renderCell));
29939
- }
29940
- if (rows.length === 0) {
29941
- const fallback = deepText(el, 0).replace(/[ \t]+\n/g, "\n").trim();
29942
- return fallback;
29943
- }
29944
- const colCount = rows.reduce((max, r) => Math.max(max, r.length), 0);
29945
- const pad = (r) => {
29946
- const cells = r.slice();
29947
- while (cells.length < colCount)
29948
- cells.push("");
29949
- return cells.map((c) => c.replace(/\|/g, "\\|"));
29950
- };
29951
- const lines = [];
29952
- const header = rows[0] ?? [];
29953
- const body = rows.slice(1);
29954
- lines.push(`| ${pad(header).join(" | ")} |`);
29955
- lines.push(`| ${Array.from({ length: colCount }, () => "---").join(" | ")} |`);
29956
- for (const r of body)
29957
- lines.push(`| ${pad(r).join(" | ")} |`);
29958
- return lines.join("\n");
29959
- }
29960
- function renderSection(section, depth) {
29961
- if (depth > MAX_DEPTH || !isRecord(section))
29962
- return "";
29963
- const type = asString(section.type);
29964
- if (isTableElement(section))
29965
- return renderTable(section);
29966
- switch (type) {
29967
- case "rich_text_section":
29968
- return renderInline(asArray(section.elements));
29969
- case "rich_text_preformatted": {
29970
- const code = renderInline(asArray(section.elements));
29971
- return code ? `\`\`\`
29972
- ${code}
29973
- \`\`\`` : "";
29974
- }
29975
- case "rich_text_quote": {
29976
- const quoted = renderInline(asArray(section.elements));
29977
- return quoted ? quoted.split("\n").map((l) => `> ${l}`).join("\n") : "";
29978
- }
29979
- case "rich_text_list": {
29980
- const ordered = asString(section.style) === "ordered";
29981
- const items = asArray(section.elements).map((item, i) => {
29982
- const body = renderSection(item, depth + 1) || renderInline(asArray(item?.elements));
29983
- const marker = ordered ? `${i + 1}.` : "-";
29984
- return `${marker} ${body}`.trimEnd();
29985
- });
29986
- return items.join("\n");
29987
- }
29988
- default:
29989
- if (Array.isArray(section.elements))
29990
- return renderInline(asArray(section.elements));
29991
- return deepText(section, depth + 1);
29992
- }
29993
- }
29994
- function renderSlackBlocks(blocks) {
29995
- let hadTable = false;
29996
- const out = [];
29997
- try {
29998
- for (const block of asArray(blocks)) {
29999
- if (!isRecord(block))
30000
- continue;
30001
- if (isTableElement(block)) {
30002
- hadTable = true;
30003
- const rendered = renderTable(block);
30004
- if (rendered.trim().length > 0)
30005
- out.push(rendered);
30006
- continue;
30007
- }
30008
- if (asString(block.type) !== "rich_text")
30009
- continue;
30010
- for (const section of asArray(block.elements)) {
30011
- if (isTableElement(section))
30012
- hadTable = true;
30013
- const rendered = renderSection(section, 0);
30014
- if (rendered.trim().length > 0)
30015
- out.push(rendered);
30016
- }
30017
- }
30018
- } catch {
30019
- }
30020
- const text = out.join("\n\n").replace(/[ \t]+$/gm, "").replace(/\n{3,}/g, "\n\n").trim();
30021
- return { text, hadTable };
30022
- }
30023
- function mergeInboundText(text, blocks) {
30024
- const { text: rendered, hadTable } = renderSlackBlocks(blocks);
30025
- if (!hadTable)
30026
- return { content: text, recoveredTable: false };
30027
- const content = rendered.length > 0 ? rendered : text;
30028
- return { content, recoveredTable: rendered.length > 0 && content !== text };
30029
- }
30030
-
30031
- // ../core/dist/channels/governance/slack-forwarded.js
30032
- function asTrimmed(v) {
30033
- return typeof v === "string" ? v.trim() : "";
30034
- }
30035
- function extractForwardedContent(attachments) {
30036
- if (!Array.isArray(attachments))
30037
- return { text: "", files: [] };
30038
- const parts = [];
30039
- const files = [];
30040
- for (const raw of attachments) {
30041
- if (!raw || typeof raw !== "object")
30042
- continue;
30043
- const att = raw;
30044
- const textBody = asTrimmed(att.text);
30045
- let body = textBody || asTrimmed(att.fallback);
30046
- const blockSources = [];
30047
- if (Array.isArray(att.blocks))
30048
- blockSources.push(att.blocks);
30049
- if (Array.isArray(att.message_blocks)) {
30050
- for (const mb of att.message_blocks)
30051
- blockSources.push(mb?.message?.blocks);
30052
- }
30053
- for (const source of blockSources) {
30054
- const rendered = renderSlackBlocks(source);
30055
- const renderedText = rendered.text.trim();
30056
- if (renderedText && (!textBody || rendered.hadTable)) {
30057
- body = renderedText;
30058
- break;
30059
- }
30060
- }
30061
- const title = asTrimmed(att.title);
30062
- const link = asTrimmed(att.title_link) || asTrimmed(att.from_url);
30063
- const imageUrl = asTrimmed(att.image_url) || asTrimmed(att.thumb_url);
30064
- const lines = [];
30065
- if (body)
30066
- lines.push(body);
30067
- if (title && title !== body)
30068
- lines.push(title);
30069
- if (link)
30070
- lines.push(link);
30071
- if (imageUrl)
30072
- lines.push(`[image] ${imageUrl}`);
30073
- if (lines.length)
30074
- parts.push(lines.join("\n"));
30075
- if (Array.isArray(att.files))
30076
- files.push(...att.files);
30077
- }
30078
- return { text: parts.join("\n\n"), files };
30079
- }
30080
- function hasForwardedContent(attachments) {
30081
- const { text, files } = extractForwardedContent(attachments);
30082
- return text.length > 0 || files.length > 0;
30083
- }
30084
-
30085
30247
  // ../core/dist/channels/governance/slack-inbound-filter.js
30086
30248
  var ALLOWED_MESSAGE_SUBTYPES = /* @__PURE__ */ new Set([
30087
30249
  void 0,
@@ -37152,7 +37314,14 @@ async function fetchThreadTranscript(channel, threadTs, limit, deps) {
37152
37314
  for (const msg of data.messages ?? []) {
37153
37315
  allMessages.push({
37154
37316
  user: msg.user ?? msg.bot_id ?? "unknown",
37155
- text: msg.text ?? "",
37317
+ // ENG-8635: blocks/attachments are how bots post. `msg.text` alone
37318
+ // rendered every Amazon Q / CloudWatch / GitHub alert as an empty line.
37319
+ // Composed through the same single owner as the live inbound path, so a
37320
+ // forwarded message reads identically whether the agent sees it arrive
37321
+ // or reads it back out of the thread - including the nested
37322
+ // `message_blocks` and unfurl metadata the generic flattener misses.
37323
+ // (CodeRabbit, PR #4263.)
37324
+ text: composeInboundText(msg).content,
37156
37325
  ts: msg.ts ?? ""
37157
37326
  });
37158
37327
  }
@@ -37198,7 +37367,15 @@ async function fetchChannelHistory(channel, limit, deps, options = {}) {
37198
37367
  for (const msg of data.messages ?? []) {
37199
37368
  allMessages.push({
37200
37369
  user: msg.user ?? msg.bot_id ?? "unknown",
37201
- text: msg.text ?? "",
37370
+ // ENG-8635: flatten blocks/attachments, and route through the SAME
37371
+ // single-owner composition the live inbound path uses. Calling
37372
+ // `slackMessageText` directly here read attachments with the generic
37373
+ // flattener, which does not see a forwarded message's nested
37374
+ // `message_blocks` or its unfurl link/image metadata - so history
37375
+ // silently showed less of a shared message than the inbound tag did for
37376
+ // the identical event. Two readers of one source will always drift;
37377
+ // there is now one. (CodeRabbit, PR #4263.)
37378
+ text: composeInboundText(msg).content,
37202
37379
  ts: msg.ts ?? ""
37203
37380
  });
37204
37381
  }
@@ -45510,7 +45687,8 @@ async function connectSocketMode() {
45510
45687
  return;
45511
45688
  }
45512
45689
  }
45513
- const text = evt.text ?? "";
45690
+ const composed = composeInboundText(evt);
45691
+ const text = composed.gateText;
45514
45692
  const channel = evt.channel ?? "";
45515
45693
  const ts = evt.ts ?? "";
45516
45694
  const threadTs = evt.thread_ts ?? ts;
@@ -45598,9 +45776,8 @@ async function connectSocketMode() {
45598
45776
  }
45599
45777
  }
45600
45778
  const userName = await resolveUserName(user);
45601
- const forwarded = extractForwardedContent(evt.attachments);
45602
45779
  const fileMeta = await buildInboundFileMeta(
45603
- [...evt.files ?? [], ...forwarded.files],
45780
+ [...evt.files ?? [], ...composed.files],
45604
45781
  AGENT_CODE_NAME,
45605
45782
  channel
45606
45783
  );
@@ -45631,18 +45808,14 @@ async function connectSocketMode() {
45631
45808
  );
45632
45809
  }
45633
45810
  }
45634
- const { content: mergedText, recoveredTable } = mergeInboundText(text, evt.blocks);
45635
- if (recoveredTable) {
45811
+ const inboundContent = composed.content;
45812
+ if (composed.recoveredTable) {
45636
45813
  process.stderr.write(
45637
45814
  `slack-channel(${AGENT_CODE_NAME}): recovered rich_text table from blocks (channel=${redactSlackId(channel)} ts=${redactSlackId(ts)})
45638
45815
  `
45639
45816
  );
45640
45817
  }
45641
- let inboundContent = mergedText;
45642
- if (forwarded.text) {
45643
- inboundContent = mergedText.trim().length > 0 ? `${mergedText}
45644
-
45645
- ${forwarded.text}` : forwarded.text;
45818
+ if (composed.recoveredForwarded) {
45646
45819
  process.stderr.write(
45647
45820
  `slack-channel(${AGENT_CODE_NAME}): recovered forwarded message content (channel=${redactSlackId(channel)} ts=${redactSlackId(ts)})
45648
45821
  `
@@ -41,7 +41,7 @@ import {
41
41
  writeDirectChatSessionState,
42
42
  writeEgressAllowlist,
43
43
  writePersistentClaudeWrapper
44
- } from "./chunk-QPSEQLSI.js";
44
+ } from "./chunk-ST4PZ6RF.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-FM5746XM.js.map
90
+ //# sourceMappingURL=persistent-session-KVONGDAL.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  paneLogPath
3
- } from "./chunk-QPSEQLSI.js";
3
+ } from "./chunk-ST4PZ6RF.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-WZMDBY3T.js.map
692
+ //# sourceMappingURL=responsiveness-probe-OUHRYJYH.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@integrity-labs/agt-cli",
3
- "version": "0.28.545",
3
+ "version": "0.28.547",
4
4
  "description": "Augmented Team CLI — agent provisioning and management",
5
5
  "type": "module",
6
6
  "engines": {