@integrity-labs/agt-cli 0.27.115 → 0.27.116

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.
@@ -15047,15 +15047,15 @@ var StdioServerTransport = class {
15047
15047
  import {
15048
15048
  chmodSync,
15049
15049
  createWriteStream,
15050
- existsSync as existsSync3,
15051
- mkdirSync as mkdirSync3,
15052
- readFileSync as readFileSync4,
15050
+ existsSync as existsSync4,
15051
+ mkdirSync as mkdirSync4,
15052
+ readFileSync as readFileSync5,
15053
15053
  readdirSync as readdirSync3,
15054
15054
  renameSync as renameSync2,
15055
15055
  statSync as statSync2,
15056
15056
  unlinkSync as unlinkSync3,
15057
15057
  watch,
15058
- writeFileSync as writeFileSync3
15058
+ writeFileSync as writeFileSync4
15059
15059
  } from "fs";
15060
15060
  import { basename, join as join5, resolve as resolve2 } from "path";
15061
15061
  import { homedir as homedir2 } from "os";
@@ -15186,6 +15186,72 @@ async function runOrRetry(fn, opts) {
15186
15186
  }
15187
15187
  }
15188
15188
 
15189
+ // src/slack-bot-photo.ts
15190
+ import { existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "fs";
15191
+ import { dirname as dirname2 } from "path";
15192
+ async function applyBotPhoto(opts) {
15193
+ const fetchImpl = opts.fetchImpl ?? fetch;
15194
+ const log = opts.log ?? ((m) => {
15195
+ process.stderr.write(m);
15196
+ });
15197
+ const { token, avatarUrl, markerPath } = opts;
15198
+ if (markerPath && existsSync2(markerPath)) {
15199
+ try {
15200
+ if (readFileSync3(markerPath, "utf-8").trim() === avatarUrl) {
15201
+ return { status: "skipped-unchanged" };
15202
+ }
15203
+ } catch {
15204
+ }
15205
+ }
15206
+ try {
15207
+ const imgRes = await fetchImpl(avatarUrl, { signal: AbortSignal.timeout(1e4) });
15208
+ if (!imgRes.ok) {
15209
+ log(`slack-channel: avatar download failed (HTTP ${imgRes.status}) \u2014 skipping bot photo
15210
+ `);
15211
+ return { status: "download-failed", httpStatus: imgRes.status };
15212
+ }
15213
+ const bytes = new Uint8Array(await imgRes.arrayBuffer());
15214
+ const form = new FormData();
15215
+ form.append("image", new Blob([bytes], { type: "image/jpeg" }), "avatar.jpg");
15216
+ const res = await fetchImpl("https://slack.com/api/users.setPhoto", {
15217
+ method: "POST",
15218
+ headers: { Authorization: `Bearer ${token}` },
15219
+ body: form,
15220
+ signal: AbortSignal.timeout(15e3)
15221
+ });
15222
+ const data = await res.json();
15223
+ if (!data.ok) {
15224
+ const code = data.error ?? "unknown";
15225
+ if (code === "missing_scope") {
15226
+ if (!opts.warned || !opts.warned.has(code)) {
15227
+ opts.warned?.add(code);
15228
+ log(
15229
+ `slack-channel: users.setPhoto failed (missing_scope) \u2014 bot avatar disabled until users.profile:write is granted (re-OAuth required)
15230
+ `
15231
+ );
15232
+ }
15233
+ } else {
15234
+ log(`slack-channel: users.setPhoto failed (${code}) \u2014 bot avatar not updated
15235
+ `);
15236
+ }
15237
+ return { status: "slack-error", error: code };
15238
+ }
15239
+ if (markerPath) {
15240
+ try {
15241
+ mkdirSync2(dirname2(markerPath), { recursive: true, mode: 448 });
15242
+ writeFileSync2(markerPath, avatarUrl, { mode: 384 });
15243
+ } catch {
15244
+ }
15245
+ }
15246
+ log("slack-channel: bot profile photo updated from agent avatar\n");
15247
+ return { status: "applied" };
15248
+ } catch (err) {
15249
+ log(`slack-channel: applyBotPhotoOnFirstConnect threw: ${err.message}
15250
+ `);
15251
+ return { status: "threw", message: err.message };
15252
+ }
15253
+ }
15254
+
15189
15255
  // src/slack-inbound-files.ts
15190
15256
  function classifySlackFile(file) {
15191
15257
  if (!file || typeof file.id !== "string" || !file.id) return null;
@@ -15752,12 +15818,12 @@ function createSlackBotUserIdClient(args) {
15752
15818
 
15753
15819
  // src/mcp-spawn-lock.ts
15754
15820
  import {
15755
- existsSync as existsSync2,
15756
- mkdirSync as mkdirSync2,
15757
- readFileSync as readFileSync3,
15821
+ existsSync as existsSync3,
15822
+ mkdirSync as mkdirSync3,
15823
+ readFileSync as readFileSync4,
15758
15824
  renameSync,
15759
15825
  unlinkSync as unlinkSync2,
15760
- writeFileSync as writeFileSync2
15826
+ writeFileSync as writeFileSync3
15761
15827
  } from "fs";
15762
15828
  import { join as join4 } from "path";
15763
15829
  function defaultIsPidAlive(pid) {
@@ -15787,10 +15853,10 @@ function acquireMcpSpawnLock(args) {
15787
15853
  return { kind: "blocked", path, holder: existing };
15788
15854
  }
15789
15855
  }
15790
- mkdirSync2(agentDir, { recursive: true, mode: 448 });
15856
+ mkdirSync3(agentDir, { recursive: true, mode: 448 });
15791
15857
  const tmpPath = `${path}.${selfPid}.tmp`;
15792
15858
  const payload = { pid: selfPid, started_at: now() };
15793
- writeFileSync2(tmpPath, JSON.stringify(payload), { mode: 384 });
15859
+ writeFileSync3(tmpPath, JSON.stringify(payload), { mode: 384 });
15794
15860
  renameSync(tmpPath, path);
15795
15861
  return { kind: "acquired", path };
15796
15862
  }
@@ -15806,9 +15872,9 @@ function releaseMcpSpawnLock(lockPath, opts = {}) {
15806
15872
  }
15807
15873
  }
15808
15874
  function readLockHolder(path) {
15809
- if (!existsSync2(path)) return null;
15875
+ if (!existsSync3(path)) return null;
15810
15876
  try {
15811
- const raw = readFileSync3(path, "utf8");
15877
+ const raw = readFileSync4(path, "utf8");
15812
15878
  const parsed = JSON.parse(raw);
15813
15879
  const pid = typeof parsed.pid === "number" ? parsed.pid : Number(parsed.pid);
15814
15880
  if (!Number.isFinite(pid) || pid <= 0) return null;
@@ -15823,6 +15889,7 @@ function readLockHolder(path) {
15823
15889
  var BOT_TOKEN = process.env.SLACK_BOT_TOKEN;
15824
15890
  var APP_TOKEN = process.env.SLACK_APP_TOKEN;
15825
15891
  var AGENT_CODE_NAME = process.env.AGT_AGENT_CODE_NAME ?? null;
15892
+ var AGENT_AVATAR_URL = process.env.SLACK_AGENT_AVATAR_URL?.trim() || null;
15826
15893
  var SLACK_COMMAND_MAX_LENGTH = 32;
15827
15894
  function agentSlashCommand(base) {
15828
15895
  const codeName = AGENT_CODE_NAME?.trim().toLowerCase();
@@ -15989,6 +16056,7 @@ var SLACK_AGENT_DIR = AGENT_CODE_NAME ? join5(homedir2(), ".augmented", AGENT_CO
15989
16056
  var SLACK_PENDING_INBOUND_DIR = SLACK_AGENT_DIR ? join5(SLACK_AGENT_DIR, "slack-pending-inbound") : null;
15990
16057
  var SLACK_RECOVERY_OUTBOX_DIR = SLACK_AGENT_DIR ? join5(SLACK_AGENT_DIR, "slack-recovery-outbox") : null;
15991
16058
  var SLACK_MAX_RECOVERY_ATTEMPTS = 3;
16059
+ var SLACK_AVATAR_MARKER_PATH = SLACK_AGENT_DIR ? join5(SLACK_AGENT_DIR, "slack-avatar-applied") : null;
15992
16060
  function redactSlackId(id) {
15993
16061
  if (!id) return "<none>";
15994
16062
  return createHash("sha256").update(id).digest("hex").slice(0, 8);
@@ -16013,8 +16081,8 @@ function writeSlackPendingInboundMarker(channel, threadTs, messageTs, undelivera
16013
16081
  ...undeliverable ? { undeliverable: true } : {}
16014
16082
  };
16015
16083
  try {
16016
- mkdirSync3(SLACK_PENDING_INBOUND_DIR, { recursive: true, mode: 448 });
16017
- writeFileSync3(path, JSON.stringify(marker), { mode: 384 });
16084
+ mkdirSync4(SLACK_PENDING_INBOUND_DIR, { recursive: true, mode: 448 });
16085
+ writeFileSync4(path, JSON.stringify(marker), { mode: 384 });
16018
16086
  } catch (err) {
16019
16087
  process.stderr.write(
16020
16088
  `slack-channel(${AGENT_CODE_NAME}): pending-inbound marker write failed: ${err.message}
@@ -16075,7 +16143,7 @@ function __resetSlackUndeliverableNoticeThrottle() {
16075
16143
  function clearSlackMarkerFileWithHeal(fullPath) {
16076
16144
  let marker = null;
16077
16145
  try {
16078
- marker = JSON.parse(readFileSync4(fullPath, "utf-8"));
16146
+ marker = JSON.parse(readFileSync5(fullPath, "utf-8"));
16079
16147
  } catch {
16080
16148
  }
16081
16149
  if (marker && decideRecoveryHeal({
@@ -16085,7 +16153,7 @@ function clearSlackMarkerFileWithHeal(fullPath) {
16085
16153
  healSlackUndeliverable(marker.channel, marker.message_ts);
16086
16154
  }
16087
16155
  try {
16088
- if (existsSync3(fullPath)) unlinkSync3(fullPath);
16156
+ if (existsSync4(fullPath)) unlinkSync3(fullPath);
16089
16157
  } catch {
16090
16158
  }
16091
16159
  }
@@ -16129,7 +16197,7 @@ async function processSlackRecoveryOutboxFile(filename) {
16129
16197
  const fullPath = join5(SLACK_RECOVERY_OUTBOX_DIR, filename);
16130
16198
  let payload;
16131
16199
  try {
16132
- payload = JSON.parse(readFileSync4(fullPath, "utf-8"));
16200
+ payload = JSON.parse(readFileSync5(fullPath, "utf-8"));
16133
16201
  } catch (err) {
16134
16202
  process.stderr.write(
16135
16203
  `slack-channel(${AGENT_CODE_NAME}): recovery outbox parse failed (${filename}): ${err.message}
@@ -16254,7 +16322,7 @@ function scanSlackRecoveryRetries() {
16254
16322
  function startSlackRecoveryOutboxWatcher() {
16255
16323
  if (!SLACK_RECOVERY_OUTBOX_DIR) return;
16256
16324
  try {
16257
- mkdirSync3(SLACK_RECOVERY_OUTBOX_DIR, { recursive: true, mode: 448 });
16325
+ mkdirSync4(SLACK_RECOVERY_OUTBOX_DIR, { recursive: true, mode: 448 });
16258
16326
  } catch (err) {
16259
16327
  process.stderr.write(
16260
16328
  `slack-channel(${AGENT_CODE_NAME}): recovery outbox mkdir failed: ${err.message}
@@ -16272,7 +16340,7 @@ function startSlackRecoveryOutboxWatcher() {
16272
16340
  const watcher = watch(SLACK_RECOVERY_OUTBOX_DIR, (event, filename) => {
16273
16341
  if (event !== "rename" || !filename) return;
16274
16342
  if (!isFirstAttemptSlackOutboxFile(filename)) return;
16275
- if (existsSync3(join5(SLACK_RECOVERY_OUTBOX_DIR, filename))) {
16343
+ if (existsSync4(join5(SLACK_RECOVERY_OUTBOX_DIR, filename))) {
16276
16344
  void processSlackRecoveryOutboxFile(filename);
16277
16345
  }
16278
16346
  });
@@ -16293,7 +16361,7 @@ function trackPendingMessage(channel, threadTs, messageTs, undeliverable = false
16293
16361
  }
16294
16362
  function sweepSlackStaleMarkers(thresholdMs) {
16295
16363
  if (!SLACK_PENDING_INBOUND_DIR) return;
16296
- if (!existsSync3(SLACK_PENDING_INBOUND_DIR)) return;
16364
+ if (!existsSync4(SLACK_PENDING_INBOUND_DIR)) return;
16297
16365
  let filenames;
16298
16366
  try {
16299
16367
  filenames = readdirSync3(SLACK_PENDING_INBOUND_DIR);
@@ -16312,7 +16380,7 @@ function sweepSlackStaleMarkers(thresholdMs) {
16312
16380
  const fullPath = join5(SLACK_PENDING_INBOUND_DIR, filename);
16313
16381
  let marker;
16314
16382
  try {
16315
- marker = JSON.parse(readFileSync4(fullPath, "utf-8"));
16383
+ marker = JSON.parse(readFileSync5(fullPath, "utf-8"));
16316
16384
  } catch (err) {
16317
16385
  process.stderr.write(
16318
16386
  `slack-channel(${AGENT_CODE_NAME}): stale-marker parse failed for ${redactSlackId(filename)}: ${err.message}
@@ -16351,14 +16419,14 @@ var slackOrphanSweepTimer = setInterval(() => {
16351
16419
  slackOrphanSweepTimer.unref?.();
16352
16420
  var lastSlackGiveUpHandledAtMs = null;
16353
16421
  function listPendingSlackConversations() {
16354
- if (!SLACK_PENDING_INBOUND_DIR || !existsSync3(SLACK_PENDING_INBOUND_DIR)) return [];
16422
+ if (!SLACK_PENDING_INBOUND_DIR || !existsSync4(SLACK_PENDING_INBOUND_DIR)) return [];
16355
16423
  const byKey = /* @__PURE__ */ new Map();
16356
16424
  try {
16357
16425
  for (const name of readdirSync3(SLACK_PENDING_INBOUND_DIR)) {
16358
16426
  if (!name.endsWith(".json")) continue;
16359
16427
  try {
16360
16428
  const marker = JSON.parse(
16361
- readFileSync4(join5(SLACK_PENDING_INBOUND_DIR, name), "utf8")
16429
+ readFileSync5(join5(SLACK_PENDING_INBOUND_DIR, name), "utf8")
16362
16430
  );
16363
16431
  if (typeof marker.channel !== "string" || !marker.channel) continue;
16364
16432
  if (typeof marker.thread_ts !== "string" || !marker.thread_ts) continue;
@@ -16435,7 +16503,7 @@ async function notifyStrandedInboundsOnFirstConnect() {
16435
16503
  strandedInboundNoticeInFlight = true;
16436
16504
  let hadFailure = false;
16437
16505
  try {
16438
- if (!SLACK_PENDING_INBOUND_DIR || !existsSync3(SLACK_PENDING_INBOUND_DIR)) return;
16506
+ if (!SLACK_PENDING_INBOUND_DIR || !existsSync4(SLACK_PENDING_INBOUND_DIR)) return;
16439
16507
  let filenames;
16440
16508
  try {
16441
16509
  filenames = readdirSync3(SLACK_PENDING_INBOUND_DIR);
@@ -16451,7 +16519,7 @@ async function notifyStrandedInboundsOnFirstConnect() {
16451
16519
  const fullPath = join5(SLACK_PENDING_INBOUND_DIR, filename);
16452
16520
  let marker;
16453
16521
  try {
16454
- marker = JSON.parse(readFileSync4(fullPath, "utf-8"));
16522
+ marker = JSON.parse(readFileSync5(fullPath, "utf-8"));
16455
16523
  } catch {
16456
16524
  continue;
16457
16525
  }
@@ -16511,7 +16579,7 @@ function noteThreadActivityByMessageTs(channel, messageTs) {
16511
16579
  if (!channel || !messageTs) return;
16512
16580
  clearPendingMessage(channel, messageTs);
16513
16581
  if (!SLACK_PENDING_INBOUND_DIR) return;
16514
- if (!existsSync3(SLACK_PENDING_INBOUND_DIR)) return;
16582
+ if (!existsSync4(SLACK_PENDING_INBOUND_DIR)) return;
16515
16583
  let filenames;
16516
16584
  try {
16517
16585
  filenames = readdirSync3(SLACK_PENDING_INBOUND_DIR);
@@ -16642,6 +16710,19 @@ function clearBotStatusBestEffort() {
16642
16710
  }).catch(() => {
16643
16711
  });
16644
16712
  }
16713
+ var botPhotoApplyFired = false;
16714
+ var setBotPhotoWarnedErrors = /* @__PURE__ */ new Set();
16715
+ async function applyBotPhotoOnFirstConnect() {
16716
+ if (botPhotoApplyFired) return;
16717
+ if (!BOT_TOKEN || !AGENT_AVATAR_URL) return;
16718
+ botPhotoApplyFired = true;
16719
+ await applyBotPhoto({
16720
+ token: BOT_TOKEN,
16721
+ avatarUrl: AGENT_AVATAR_URL,
16722
+ markerPath: SLACK_AVATAR_MARKER_PATH,
16723
+ warned: setBotPhotoWarnedErrors
16724
+ });
16725
+ }
16645
16726
  function formatLastActivity() {
16646
16727
  if (lastActivityAt == null || lastActivityKind == null) return "no activity yet";
16647
16728
  const seconds = Math.max(0, Math.floor((Date.now() - lastActivityAt) / 1e3));
@@ -16898,8 +16979,8 @@ async function handleSlashCommandEnvelope(payload) {
16898
16979
  return;
16899
16980
  }
16900
16981
  try {
16901
- if (!existsSync3(RESTART_FLAGS_DIR)) {
16902
- mkdirSync3(RESTART_FLAGS_DIR, { recursive: true });
16982
+ if (!existsSync4(RESTART_FLAGS_DIR)) {
16983
+ mkdirSync4(RESTART_FLAGS_DIR, { recursive: true });
16903
16984
  }
16904
16985
  const flagPath = join5(RESTART_FLAGS_DIR, `${codeName}.flag`);
16905
16986
  const flag = {
@@ -16912,7 +16993,7 @@ async function handleSlashCommandEnvelope(payload) {
16912
16993
  }
16913
16994
  };
16914
16995
  const tmpPath = `${flagPath}.${process.pid}.${randomUUID()}.tmp`;
16915
- writeFileSync3(tmpPath, JSON.stringify(flag) + "\n", "utf8");
16996
+ writeFileSync4(tmpPath, JSON.stringify(flag) + "\n", "utf8");
16916
16997
  renameSync2(tmpPath, flagPath);
16917
16998
  process.stderr.write(
16918
16999
  `slack-channel(${codeName}): /restart slash-command queued from channel ${hashChannelId(payload.channel_id)}
@@ -17009,8 +17090,8 @@ async function handleHelpCommand(opts) {
17009
17090
  async function handleRestartCommand(opts) {
17010
17091
  const codeName = AGENT_CODE_NAME ?? "unknown";
17011
17092
  try {
17012
- if (!existsSync3(RESTART_FLAGS_DIR)) {
17013
- mkdirSync3(RESTART_FLAGS_DIR, { recursive: true });
17093
+ if (!existsSync4(RESTART_FLAGS_DIR)) {
17094
+ mkdirSync4(RESTART_FLAGS_DIR, { recursive: true });
17014
17095
  }
17015
17096
  const flagPath = join5(RESTART_FLAGS_DIR, `${codeName}.flag`);
17016
17097
  const flag = {
@@ -17024,7 +17105,7 @@ async function handleRestartCommand(opts) {
17024
17105
  }
17025
17106
  };
17026
17107
  const tmpPath = `${flagPath}.${process.pid}.${randomUUID()}.tmp`;
17027
- writeFileSync3(tmpPath, JSON.stringify(flag) + "\n", "utf8");
17108
+ writeFileSync4(tmpPath, JSON.stringify(flag) + "\n", "utf8");
17028
17109
  renameSync2(tmpPath, flagPath);
17029
17110
  process.stderr.write(
17030
17111
  `slack-channel(${codeName}): /restart queued from channel ${hashChannelId(opts.channel)}
@@ -17107,7 +17188,7 @@ var slackStderrLogStream = null;
17107
17188
  if (AGENT_CODE_NAME) {
17108
17189
  try {
17109
17190
  const logDir = join5(homedir2(), ".augmented", AGENT_CODE_NAME);
17110
- mkdirSync3(logDir, { recursive: true });
17191
+ mkdirSync4(logDir, { recursive: true });
17111
17192
  slackStderrLogStream = createWriteStream(join5(logDir, "slack-channel-stderr.log"), {
17112
17193
  flags: "a",
17113
17194
  mode: 384
@@ -17682,7 +17763,7 @@ ${result.formatted}` : "Thread is empty or not found."
17682
17763
  };
17683
17764
  }
17684
17765
  size = stat2.size;
17685
- bytes = readFileSync4(resolvedPath);
17766
+ bytes = readFileSync5(resolvedPath);
17686
17767
  } catch (err) {
17687
17768
  return {
17688
17769
  content: [{ type: "text", text: `Failed to read file: ${err.message}` }],
@@ -18320,8 +18401,8 @@ async function downloadSlackFile(fileId, codeName) {
18320
18401
  if (!isPathInside(savedPath, dir)) {
18321
18402
  throw new Error(`refusing to write ${savedPath} outside ${dir}`);
18322
18403
  }
18323
- mkdirSync3(dir, { recursive: true });
18324
- writeFileSync3(savedPath, bytes, { mode: 384 });
18404
+ mkdirSync4(dir, { recursive: true });
18405
+ writeFileSync4(savedPath, bytes, { mode: 384 });
18325
18406
  try {
18326
18407
  chmodSync(savedPath, 384);
18327
18408
  } catch {
@@ -18433,6 +18514,7 @@ async function connectSocketMode() {
18433
18514
  recordActivity("connect");
18434
18515
  void setBotStatus(":large_green_circle:", "Active");
18435
18516
  void notifyStrandedInboundsOnFirstConnect();
18517
+ void applyBotPhotoOnFirstConnect();
18436
18518
  };
18437
18519
  ws.onmessage = async (event) => {
18438
18520
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@integrity-labs/agt-cli",
3
- "version": "0.27.115",
3
+ "version": "0.27.116",
4
4
  "description": "Augmented Team CLI — agent provisioning and management",
5
5
  "type": "module",
6
6
  "engines": {