@integrity-labs/agt-cli 0.15.33 → 0.15.35

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.
@@ -22,7 +22,7 @@ import {
22
22
  resolveChannels,
23
23
  resolveDmTarget,
24
24
  wrapScheduledTaskPrompt
25
- } from "../chunk-6J5SG6JQ.js";
25
+ } from "../chunk-5IT25PYX.js";
26
26
  import {
27
27
  findTaskByTemplate,
28
28
  getProjectDir,
@@ -1435,7 +1435,7 @@ function clearAgentCaches(agentId, codeName) {
1435
1435
  var cachedFrameworkVersion = null;
1436
1436
  var lastVersionCheckAt = 0;
1437
1437
  var VERSION_CHECK_INTERVAL_MS = 5 * 60 * 1e3;
1438
- var agtCliVersion = true ? "0.15.33" : "dev";
1438
+ var agtCliVersion = true ? "0.15.35" : "dev";
1439
1439
  function resolveBrewPath(execFileSync2) {
1440
1440
  try {
1441
1441
  const out = execFileSync2("which", ["brew"], { timeout: 5e3 }).toString().trim();
@@ -14976,7 +14976,9 @@ async function postSlackMessage(body) {
14976
14976
  // used elsewhere in this file for chat.postMessage.
14977
14977
  signal: AbortSignal.timeout(SLACK_DOWNLOAD_TIMEOUT_MS)
14978
14978
  });
14979
- return await res.json();
14979
+ const data = await res.json();
14980
+ if (data.ok) recordActivity("reply");
14981
+ return data;
14980
14982
  } catch (err) {
14981
14983
  const isTimeout = err.name === "TimeoutError" || err.name === "AbortError";
14982
14984
  return { ok: false, error: isTimeout ? "timeout" : err.message };
@@ -14992,9 +14994,66 @@ function buildSlackHelpMessage(codeName) {
14992
14994
  "",
14993
14995
  "_Real Slack slash commands (also discoverable via `/`-autocomplete):_",
14994
14996
  "\u2022 `/kill` \u2014 silence all agents in this thread for 6h (use as a thread reply)",
14995
- "\u2022 `/unkill` \u2014 clear a kill (use as a thread reply)"
14997
+ "\u2022 `/unkill` \u2014 clear a kill (use as a thread reply)",
14998
+ "\u2022 `/agent-status` \u2014 report whether this agent is online + last activity"
14996
14999
  ].join("\n");
14997
15000
  }
15001
+ var lastActivityAt = null;
15002
+ var lastActivityKind = null;
15003
+ function recordActivity(kind) {
15004
+ lastActivityAt = Date.now();
15005
+ lastActivityKind = kind;
15006
+ }
15007
+ async function setBotStatus(status_emoji, status_text) {
15008
+ if (!BOT_TOKEN) return;
15009
+ try {
15010
+ const res = await fetch("https://slack.com/api/users.profile.set", {
15011
+ method: "POST",
15012
+ headers: {
15013
+ "Content-Type": "application/json; charset=utf-8",
15014
+ Authorization: `Bearer ${BOT_TOKEN}`
15015
+ },
15016
+ body: JSON.stringify({ profile: { status_emoji, status_text, status_expiration: 0 } })
15017
+ });
15018
+ const data = await res.json();
15019
+ if (!data.ok) {
15020
+ process.stderr.write(
15021
+ `slack-channel: users.profile.set failed (${data.error ?? "unknown"}) \u2014 bot presence indicator disabled
15022
+ `
15023
+ );
15024
+ }
15025
+ } catch (err) {
15026
+ process.stderr.write(
15027
+ `slack-channel: users.profile.set threw: ${err.message}
15028
+ `
15029
+ );
15030
+ }
15031
+ }
15032
+ function clearBotStatusBestEffort() {
15033
+ if (!BOT_TOKEN) return;
15034
+ fetch("https://slack.com/api/users.profile.set", {
15035
+ method: "POST",
15036
+ headers: {
15037
+ "Content-Type": "application/json; charset=utf-8",
15038
+ Authorization: `Bearer ${BOT_TOKEN}`
15039
+ },
15040
+ body: JSON.stringify({ profile: { status_emoji: "", status_text: "", status_expiration: 0 } })
15041
+ }).catch(() => {
15042
+ });
15043
+ }
15044
+ function formatLastActivity() {
15045
+ if (lastActivityAt == null || lastActivityKind == null) return "no activity yet";
15046
+ const seconds = Math.max(0, Math.floor((Date.now() - lastActivityAt) / 1e3));
15047
+ const ago = seconds < 5 ? "just now" : seconds < 60 ? `${seconds}s ago` : seconds < 3600 ? `${Math.floor(seconds / 60)}m ago` : `${Math.floor(seconds / 3600)}h ago`;
15048
+ const kindLabel = lastActivityKind === "inbound" ? "inbound message" : lastActivityKind === "reply" ? "reply sent" : "connected";
15049
+ return `${kindLabel} ${ago}`;
15050
+ }
15051
+ function buildAgentStatusReply(codeName) {
15052
+ const connected = currentWs != null && !isShuttingDown;
15053
+ const dot = connected ? "\u{1F7E2}" : "\u{1F534}";
15054
+ const state = connected ? "online" : "offline";
15055
+ return `${dot} \`${codeName}\` is *${state}* \u2014 Socket Mode ${connected ? "connected" : "disconnected"}. Last activity: ${formatLastActivity()}.`;
15056
+ }
14998
15057
  async function handleHelpCommand(opts) {
14999
15058
  const codeName = AGENT_CODE_NAME ?? "unknown";
15000
15059
  const replyThread = opts.threadTs ?? opts.ts;
@@ -16187,6 +16246,8 @@ async function connectSocketMode() {
16187
16246
  currentWs = ws;
16188
16247
  ws.onopen = () => {
16189
16248
  process.stderr.write("slack-channel: Socket Mode connected\n");
16249
+ recordActivity("connect");
16250
+ void setBotStatus(":large_green_circle:", "Active");
16190
16251
  };
16191
16252
  ws.onmessage = async (event) => {
16192
16253
  try {
@@ -16194,6 +16255,27 @@ async function connectSocketMode() {
16194
16255
  if (msg.envelope_id) {
16195
16256
  ws.send(JSON.stringify({ envelope_id: msg.envelope_id }));
16196
16257
  }
16258
+ if (msg.type === "slash_commands" && msg.payload?.command) {
16259
+ const command = msg.payload.command;
16260
+ const responseUrl = msg.payload.response_url;
16261
+ if (command === "/agent-status" && responseUrl) {
16262
+ const codeName = AGENT_CODE_NAME ?? "unknown";
16263
+ fetch(responseUrl, {
16264
+ method: "POST",
16265
+ headers: { "Content-Type": "application/json; charset=utf-8" },
16266
+ body: JSON.stringify({
16267
+ response_type: "ephemeral",
16268
+ text: buildAgentStatusReply(codeName)
16269
+ })
16270
+ }).catch((err) => {
16271
+ process.stderr.write(
16272
+ `slack-channel(${codeName}): /agent-status response_url POST failed: ${err.message}
16273
+ `
16274
+ );
16275
+ });
16276
+ }
16277
+ return;
16278
+ }
16197
16279
  if (msg.type === "interactive" && msg.payload?.type === "block_actions") {
16198
16280
  if (!interactiveHostAvailable()) {
16199
16281
  process.stderr.write(
@@ -16242,6 +16324,7 @@ async function connectSocketMode() {
16242
16324
  `);
16243
16325
  return;
16244
16326
  }
16327
+ recordActivity("inbound");
16245
16328
  const isDirectMessage = evt.channel?.startsWith("D");
16246
16329
  const isThreadReply = !!evt.thread_ts && evt.thread_ts !== evt.ts;
16247
16330
  const trackTs = evt.thread_ts ?? evt.ts ?? "";
@@ -16374,6 +16457,10 @@ function shutdown(reason, exitCode = 0) {
16374
16457
  }
16375
16458
  process.stderr.write(`slack-channel: ${reason} \u2014 closing Socket Mode and exiting
16376
16459
  `);
16460
+ try {
16461
+ clearBotStatusBestEffort();
16462
+ } catch {
16463
+ }
16377
16464
  try {
16378
16465
  currentWs?.close();
16379
16466
  } catch {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@integrity-labs/agt-cli",
3
- "version": "0.15.33",
3
+ "version": "0.15.35",
4
4
  "description": "Augmented Team CLI — agent provisioning and management",
5
5
  "type": "module",
6
6
  "engines": {