@integrity-labs/agt-cli 0.28.96 → 0.28.97

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
@@ -37,7 +37,7 @@ import {
37
37
  success,
38
38
  table,
39
39
  warn
40
- } from "../chunk-LFTKXQEA.js";
40
+ } from "../chunk-EN7ZKY4A.js";
41
41
  import {
42
42
  CHANNEL_REGISTRY,
43
43
  DEPLOYMENT_TEMPLATES,
@@ -4777,7 +4777,7 @@ import { execFileSync, execSync } from "child_process";
4777
4777
  import { existsSync as existsSync10, realpathSync as realpathSync2 } from "fs";
4778
4778
  import chalk18 from "chalk";
4779
4779
  import ora16 from "ora";
4780
- var cliVersion = true ? "0.28.96" : "dev";
4780
+ var cliVersion = true ? "0.28.97" : "dev";
4781
4781
  async function fetchLatestVersion() {
4782
4782
  const host2 = getHost();
4783
4783
  if (!host2) return null;
@@ -5791,7 +5791,7 @@ function handleError(err) {
5791
5791
  }
5792
5792
 
5793
5793
  // src/bin/agt.ts
5794
- var cliVersion2 = true ? "0.28.96" : "dev";
5794
+ var cliVersion2 = true ? "0.28.97" : "dev";
5795
5795
  var program = new Command();
5796
5796
  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");
5797
5797
  program.hook("preAction", async (thisCommand, actionCommand) => {
@@ -7541,7 +7541,7 @@ function requireHost() {
7541
7541
  }
7542
7542
 
7543
7543
  // src/lib/api-client.ts
7544
- var agtCliVersion = true ? "0.28.96" : "dev";
7544
+ var agtCliVersion = true ? "0.28.97" : "dev";
7545
7545
  var lastConfigHash = null;
7546
7546
  function setConfigHash(hash) {
7547
7547
  lastConfigHash = hash && hash.length > 0 ? hash : null;
@@ -8838,4 +8838,4 @@ export {
8838
8838
  managerInstallSystemUnitCommand,
8839
8839
  managerUninstallSystemUnitCommand
8840
8840
  };
8841
- //# sourceMappingURL=chunk-LFTKXQEA.js.map
8841
+ //# sourceMappingURL=chunk-EN7ZKY4A.js.map
@@ -28,7 +28,7 @@ import {
28
28
  requireHost,
29
29
  safeWriteJsonAtomic,
30
30
  setConfigHash
31
- } from "../chunk-LFTKXQEA.js";
31
+ } from "../chunk-EN7ZKY4A.js";
32
32
  import {
33
33
  getProjectDir as getProjectDir2,
34
34
  getReadyTasks,
@@ -6953,7 +6953,7 @@ var cachedMaintenanceWindow = null;
6953
6953
  var lastVersionCheckAt = 0;
6954
6954
  var VERSION_CHECK_INTERVAL_MS = 5 * 60 * 1e3;
6955
6955
  var lastResponsivenessProbeAt = 0;
6956
- var agtCliVersion = true ? "0.28.96" : "dev";
6956
+ var agtCliVersion = true ? "0.28.97" : "dev";
6957
6957
  function resolveBrewPath(execFileSync4) {
6958
6958
  try {
6959
6959
  const out = execFileSync4("which", ["brew"], { timeout: 5e3 }).toString().trim();
@@ -15327,6 +15327,12 @@ function decideProgressAction(input) {
15327
15327
  const { now, heartbeat, target, tracked, freshnessMs, minPendingMs } = input;
15328
15328
  const fresh = heartbeat != null && now - heartbeat.updatedAtMs <= freshnessMs;
15329
15329
  const active = target != null && fresh;
15330
+ if (active && input.targetHasCard === true) {
15331
+ if (tracked) {
15332
+ return { type: "delete", channel: tracked.channel, threadTs: tracked.threadTs, ts: tracked.ts };
15333
+ }
15334
+ return { type: "none" };
15335
+ }
15330
15336
  if (!active) {
15331
15337
  if (tracked) {
15332
15338
  return { type: "delete", channel: tracked.channel, threadTs: tracked.threadTs, ts: tracked.ts };
@@ -15355,6 +15361,12 @@ function progressMinPendingMs() {
15355
15361
  const raw = parseInt(process.env.AGT_CHANNEL_PROGRESS_MIN_PENDING_MS ?? "", 10);
15356
15362
  return Number.isFinite(raw) && raw > 0 ? raw : 12e3;
15357
15363
  }
15364
+ function composeProgressBody(step) {
15365
+ const s = (step ?? "").trim();
15366
+ if (!s) return "Working\u2026";
15367
+ if (/^working/i.test(s)) return s;
15368
+ return `Working\u2026 \xB7 ${s}`;
15369
+ }
15358
15370
  function parseProgressHeartbeat(raw) {
15359
15371
  if (!raw) return null;
15360
15372
  try {
@@ -15368,6 +15380,83 @@ function parseProgressHeartbeat(raw) {
15368
15380
  }
15369
15381
  }
15370
15382
 
15383
+ // src/kanban-card-active-client.ts
15384
+ var REQUEST_TIMEOUT_MS = 8e3;
15385
+ var POSITIVE_TTL_MS = 10 * 6e4;
15386
+ var NEGATIVE_TTL_MS = 15e3;
15387
+ function createKanbanCardActiveClient(args) {
15388
+ if (!args.agtHost || !args.agtApiKey || !args.agentId) return null;
15389
+ const fetchImpl = args.fetchImpl ?? fetch;
15390
+ const now = args.now ?? (() => Date.now());
15391
+ const positiveTtlMs = args.positiveTtlMs ?? POSITIVE_TTL_MS;
15392
+ const negativeTtlMs = args.negativeTtlMs ?? NEGATIVE_TTL_MS;
15393
+ const log = args.log ?? (() => {
15394
+ });
15395
+ const base = args.agtHost.replace(/\/+$/, "");
15396
+ const agentId = args.agentId;
15397
+ const apiKey = args.agtApiKey;
15398
+ const cache2 = /* @__PURE__ */ new Map();
15399
+ let cachedToken = null;
15400
+ let cachedTokenExpiresAt = 0;
15401
+ async function getToken() {
15402
+ if (cachedToken && now() < cachedTokenExpiresAt) return cachedToken;
15403
+ const resp = await fetchImpl(`${base}/host/exchange`, {
15404
+ method: "POST",
15405
+ headers: { "Content-Type": "application/json" },
15406
+ body: JSON.stringify({ host_key: apiKey }),
15407
+ signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS)
15408
+ });
15409
+ if (!resp.ok) {
15410
+ const body = await resp.text().catch(() => "");
15411
+ throw new Error(`/host/exchange failed (${resp.status}): ${body.slice(0, 200)}`);
15412
+ }
15413
+ const data = await resp.json();
15414
+ cachedToken = data.token;
15415
+ cachedTokenExpiresAt = data.expires_at ? new Date(data.expires_at).getTime() - 12e4 : now() + 55 * 6e4;
15416
+ return cachedToken;
15417
+ }
15418
+ async function queryOnce(sourceIntegration, sourceExternalId) {
15419
+ const token = await getToken();
15420
+ const qs = new URLSearchParams({
15421
+ agent_id: agentId,
15422
+ source_integration: sourceIntegration,
15423
+ source_external_id: sourceExternalId
15424
+ });
15425
+ return fetchImpl(`${base}/host/kanban/progress-card-active?${qs.toString()}`, {
15426
+ method: "GET",
15427
+ headers: { Authorization: `Bearer ${token}` },
15428
+ signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS)
15429
+ });
15430
+ }
15431
+ async function query(sourceIntegration, sourceExternalId) {
15432
+ let resp = await queryOnce(sourceIntegration, sourceExternalId);
15433
+ if (resp.status === 401) {
15434
+ cachedToken = null;
15435
+ cachedTokenExpiresAt = 0;
15436
+ resp = await queryOnce(sourceIntegration, sourceExternalId);
15437
+ }
15438
+ if (!resp.ok) return false;
15439
+ const data = await resp.json();
15440
+ return data.active === true;
15441
+ }
15442
+ return {
15443
+ async isCardActive(sourceIntegration, sourceExternalId) {
15444
+ const key2 = `${sourceIntegration}:${sourceExternalId}`;
15445
+ const t = now();
15446
+ const hit = cache2.get(key2);
15447
+ if (hit && t < hit.expiresAt) return hit.active;
15448
+ try {
15449
+ const active = await query(sourceIntegration, sourceExternalId);
15450
+ cache2.set(key2, { active, expiresAt: t + (active ? positiveTtlMs : negativeTtlMs) });
15451
+ return active;
15452
+ } catch (err) {
15453
+ log(`kanban-card-active: query threw key=${key2}: ${err.message}`);
15454
+ return false;
15455
+ }
15456
+ }
15457
+ };
15458
+ }
15459
+
15371
15460
  // src/slack-reply-threading.ts
15372
15461
  function isSlackDmChannel(channel) {
15373
15462
  return typeof channel === "string" && channel.startsWith("D");
@@ -16343,7 +16432,7 @@ function parsePeerAgentModeEnv(raw) {
16343
16432
  }
16344
16433
 
16345
16434
  // src/cross-team-peer-audit-client.ts
16346
- var REQUEST_TIMEOUT_MS = 1e4;
16435
+ var REQUEST_TIMEOUT_MS2 = 1e4;
16347
16436
  function createCrossTeamPeerAuditClient(args) {
16348
16437
  if (!args.agtHost || !args.agtApiKey || !args.agentId) return null;
16349
16438
  const fetchImpl = args.fetchImpl ?? fetch;
@@ -16360,7 +16449,7 @@ function createCrossTeamPeerAuditClient(args) {
16360
16449
  method: "POST",
16361
16450
  headers: { "Content-Type": "application/json" },
16362
16451
  body: JSON.stringify({ host_key: apiKey }),
16363
- signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS)
16452
+ signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS2)
16364
16453
  });
16365
16454
  if (!resp.ok) {
16366
16455
  const body = await resp.text().catch(() => "");
@@ -16380,7 +16469,7 @@ function createCrossTeamPeerAuditClient(args) {
16380
16469
  "Content-Type": "application/json"
16381
16470
  },
16382
16471
  body: JSON.stringify({ agent_id: agentId, ...event }),
16383
- signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS)
16472
+ signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS2)
16384
16473
  });
16385
16474
  }
16386
16475
  async function emitAsync(event) {
@@ -16409,7 +16498,7 @@ function createCrossTeamPeerAuditClient(args) {
16409
16498
  }
16410
16499
 
16411
16500
  // src/conversation-ingest-client.ts
16412
- var REQUEST_TIMEOUT_MS2 = 1e4;
16501
+ var REQUEST_TIMEOUT_MS3 = 1e4;
16413
16502
  function createConversationIngestClient(args) {
16414
16503
  if (!args.agtHost || !args.agtApiKey || !args.agentId) return null;
16415
16504
  const fetchImpl = args.fetchImpl ?? fetch;
@@ -16426,7 +16515,7 @@ function createConversationIngestClient(args) {
16426
16515
  method: "POST",
16427
16516
  headers: { "Content-Type": "application/json" },
16428
16517
  body: JSON.stringify({ host_key: apiKey }),
16429
- signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS2)
16518
+ signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS3)
16430
16519
  });
16431
16520
  if (!resp.ok) {
16432
16521
  const body = await resp.text().catch(() => "");
@@ -16449,7 +16538,7 @@ function createConversationIngestClient(args) {
16449
16538
  method: "POST",
16450
16539
  headers: { Authorization: `Bearer ${token}`, "Content-Type": "application/json" },
16451
16540
  body: JSON.stringify({ agent_id: agentId, ...payload }),
16452
- signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS2)
16541
+ signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS3)
16453
16542
  });
16454
16543
  }
16455
16544
  function refKey(payload) {
@@ -16481,7 +16570,7 @@ function createConversationIngestClient(args) {
16481
16570
  }
16482
16571
 
16483
16572
  // src/inbound-context-client.ts
16484
- var REQUEST_TIMEOUT_MS3 = 1e4;
16573
+ var REQUEST_TIMEOUT_MS4 = 1e4;
16485
16574
  function createInboundContextClient(args) {
16486
16575
  if (!args.agtHost || !args.agtApiKey || !args.agentId) return null;
16487
16576
  const fetchImpl = args.fetchImpl ?? fetch;
@@ -16498,7 +16587,7 @@ function createInboundContextClient(args) {
16498
16587
  method: "POST",
16499
16588
  headers: { "Content-Type": "application/json" },
16500
16589
  body: JSON.stringify({ host_key: apiKey }),
16501
- signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS3)
16590
+ signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS4)
16502
16591
  });
16503
16592
  if (!resp.ok) {
16504
16593
  const body = await resp.text().catch(() => "");
@@ -16515,7 +16604,7 @@ function createInboundContextClient(args) {
16515
16604
  method: "POST",
16516
16605
  headers: { Authorization: `Bearer ${token}`, "Content-Type": "application/json" },
16517
16606
  body: JSON.stringify(body),
16518
- signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS3)
16607
+ signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS4)
16519
16608
  });
16520
16609
  }
16521
16610
  async function emit(args2) {
@@ -16550,7 +16639,7 @@ function createInboundContextClient(args) {
16550
16639
  }
16551
16640
 
16552
16641
  // src/slack-bot-user-id-client.ts
16553
- var REQUEST_TIMEOUT_MS4 = 1e4;
16642
+ var REQUEST_TIMEOUT_MS5 = 1e4;
16554
16643
  function createSlackBotUserIdClient(args) {
16555
16644
  if (!args.agtHost || !args.agtApiKey || !args.agentId) return null;
16556
16645
  const fetchImpl = args.fetchImpl ?? fetch;
@@ -16568,7 +16657,7 @@ function createSlackBotUserIdClient(args) {
16568
16657
  method: "POST",
16569
16658
  headers: { "Content-Type": "application/json" },
16570
16659
  body: JSON.stringify({ host_key: apiKey }),
16571
- signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS4)
16660
+ signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS5)
16572
16661
  });
16573
16662
  if (!resp.ok) {
16574
16663
  const body = await resp.text().catch(() => "");
@@ -16585,7 +16674,7 @@ function createSlackBotUserIdClient(args) {
16585
16674
  method: "POST",
16586
16675
  headers: { Authorization: `Bearer ${token}`, "Content-Type": "application/json" },
16587
16676
  body: JSON.stringify({ agent_id: agentId, bot_user_id: botUserId2 }),
16588
- signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS4)
16677
+ signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS5)
16589
16678
  });
16590
16679
  }
16591
16680
  async function emitAsync(botUserId2) {
@@ -16617,7 +16706,7 @@ function createSlackBotUserIdClient(args) {
16617
16706
  method: "POST",
16618
16707
  headers: { Authorization: `Bearer ${token}`, "Content-Type": "application/json" },
16619
16708
  body: JSON.stringify({ agent_id: agentId, channel_id: "slack", healthy }),
16620
- signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS4)
16709
+ signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS5)
16621
16710
  });
16622
16711
  };
16623
16712
  try {
@@ -16935,6 +17024,13 @@ var inboundContextClient = createInboundContextClient({
16935
17024
  log: (line) => process.stderr.write(`slack-channel: ${line}
16936
17025
  `)
16937
17026
  });
17027
+ var kanbanCardActiveClient = createKanbanCardActiveClient({
17028
+ agtHost: AGT_HOST,
17029
+ agtApiKey: AGT_API_KEY,
17030
+ agentId: AGT_AGENT_ID,
17031
+ log: (line) => process.stderr.write(`slack-channel: ${line}
17032
+ `)
17033
+ });
16938
17034
  var SLACK_PEER_CLASSIFIER_CONFIG = {
16939
17035
  peer_agent_mode: parsePeerAgentModeEnv(process.env.SLACK_PEER_AGENT_MODE),
16940
17036
  peer_group_ids: parsePeerGroupIdsEnv(process.env.SLACK_PEER_GROUP_IDS),
@@ -17535,7 +17631,7 @@ function findSlackProgressTarget() {
17535
17631
  }
17536
17632
  var SLACK_PROGRESS_PREFIX = "\u23F3";
17537
17633
  function slackProgressBlocks(step) {
17538
- const text = `${SLACK_PROGRESS_PREFIX} _Working\u2026 \xB7 ${step}_`;
17634
+ const text = `${SLACK_PROGRESS_PREFIX} _${composeProgressBody(step)}_`;
17539
17635
  return [{ type: "context", elements: [{ type: "mrkdwn", text }] }];
17540
17636
  }
17541
17637
  async function postSlackProgress(channel, threadTs, step) {
@@ -17547,7 +17643,7 @@ async function postSlackProgress(channel, threadTs, step) {
17547
17643
  body: JSON.stringify({
17548
17644
  channel,
17549
17645
  thread_ts: threadTs,
17550
- text: `${SLACK_PROGRESS_PREFIX} Working\u2026 \xB7 ${step}`,
17646
+ text: `${SLACK_PROGRESS_PREFIX} ${composeProgressBody(step)}`,
17551
17647
  blocks: slackProgressBlocks(step)
17552
17648
  }),
17553
17649
  signal: AbortSignal.timeout(8e3)
@@ -17567,7 +17663,7 @@ async function updateSlackProgress(channel, ts, step) {
17567
17663
  body: JSON.stringify({
17568
17664
  channel,
17569
17665
  ts,
17570
- text: `${SLACK_PROGRESS_PREFIX} Working\u2026 \xB7 ${step}`,
17666
+ text: `${SLACK_PROGRESS_PREFIX} ${composeProgressBody(step)}`,
17571
17667
  blocks: slackProgressBlocks(step)
17572
17668
  }),
17573
17669
  signal: AbortSignal.timeout(8e3)
@@ -17605,14 +17701,22 @@ async function slackProgressTick() {
17605
17701
  }
17606
17702
  return;
17607
17703
  }
17608
- const action = decideProgressAction({
17704
+ const baseInput = {
17609
17705
  now: Date.now(),
17610
17706
  heartbeat: readSlackProgressHeartbeat(),
17611
17707
  target: findSlackProgressTarget(),
17612
17708
  tracked: slackTrackedProgress,
17613
17709
  freshnessMs: progressHeartbeatFreshMs(),
17614
17710
  minPendingMs: progressMinPendingMs()
17615
- });
17711
+ };
17712
+ let action = decideProgressAction(baseInput);
17713
+ if (kanbanCardActiveClient && baseInput.target && (action.type === "post" || action.type === "update" || action.type === "none" && slackTrackedProgress)) {
17714
+ const hasCard = await kanbanCardActiveClient.isCardActive(
17715
+ "slack",
17716
+ `${baseInput.target.channel}:${baseInput.target.threadTs}`
17717
+ );
17718
+ if (hasCard) action = decideProgressAction({ ...baseInput, targetHasCard: true });
17719
+ }
17616
17720
  switch (action.type) {
17617
17721
  case "post": {
17618
17722
  const ts = await postSlackProgress(action.channel, action.threadTs, action.step);
@@ -16334,6 +16334,12 @@ function decideProgressAction(input) {
16334
16334
  const { now, heartbeat, target, tracked, freshnessMs, minPendingMs } = input;
16335
16335
  const fresh = heartbeat != null && now - heartbeat.updatedAtMs <= freshnessMs;
16336
16336
  const active = target != null && fresh;
16337
+ if (active && input.targetHasCard === true) {
16338
+ if (tracked) {
16339
+ return { type: "delete", channel: tracked.channel, threadTs: tracked.threadTs, ts: tracked.ts };
16340
+ }
16341
+ return { type: "none" };
16342
+ }
16337
16343
  if (!active) {
16338
16344
  if (tracked) {
16339
16345
  return { type: "delete", channel: tracked.channel, threadTs: tracked.threadTs, ts: tracked.ts };
@@ -16362,6 +16368,12 @@ function progressMinPendingMs() {
16362
16368
  const raw = parseInt(process.env.AGT_CHANNEL_PROGRESS_MIN_PENDING_MS ?? "", 10);
16363
16369
  return Number.isFinite(raw) && raw > 0 ? raw : 12e3;
16364
16370
  }
16371
+ function composeProgressBody(step) {
16372
+ const s = (step ?? "").trim();
16373
+ if (!s) return "Working\u2026";
16374
+ if (/^working/i.test(s)) return s;
16375
+ return `Working\u2026 \xB7 ${s}`;
16376
+ }
16365
16377
  function parseProgressHeartbeat(raw) {
16366
16378
  if (!raw) return null;
16367
16379
  try {
@@ -16375,6 +16387,83 @@ function parseProgressHeartbeat(raw) {
16375
16387
  }
16376
16388
  }
16377
16389
 
16390
+ // src/kanban-card-active-client.ts
16391
+ var REQUEST_TIMEOUT_MS6 = 8e3;
16392
+ var POSITIVE_TTL_MS = 10 * 6e4;
16393
+ var NEGATIVE_TTL_MS = 15e3;
16394
+ function createKanbanCardActiveClient(args) {
16395
+ if (!args.agtHost || !args.agtApiKey || !args.agentId) return null;
16396
+ const fetchImpl = args.fetchImpl ?? fetch;
16397
+ const now = args.now ?? (() => Date.now());
16398
+ const positiveTtlMs = args.positiveTtlMs ?? POSITIVE_TTL_MS;
16399
+ const negativeTtlMs = args.negativeTtlMs ?? NEGATIVE_TTL_MS;
16400
+ const log = args.log ?? (() => {
16401
+ });
16402
+ const base = args.agtHost.replace(/\/+$/, "");
16403
+ const agentId = args.agentId;
16404
+ const apiKey = args.agtApiKey;
16405
+ const cache2 = /* @__PURE__ */ new Map();
16406
+ let cachedToken = null;
16407
+ let cachedTokenExpiresAt = 0;
16408
+ async function getToken() {
16409
+ if (cachedToken && now() < cachedTokenExpiresAt) return cachedToken;
16410
+ const resp = await fetchImpl(`${base}/host/exchange`, {
16411
+ method: "POST",
16412
+ headers: { "Content-Type": "application/json" },
16413
+ body: JSON.stringify({ host_key: apiKey }),
16414
+ signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS6)
16415
+ });
16416
+ if (!resp.ok) {
16417
+ const body = await resp.text().catch(() => "");
16418
+ throw new Error(`/host/exchange failed (${resp.status}): ${body.slice(0, 200)}`);
16419
+ }
16420
+ const data = await resp.json();
16421
+ cachedToken = data.token;
16422
+ cachedTokenExpiresAt = data.expires_at ? new Date(data.expires_at).getTime() - 12e4 : now() + 55 * 6e4;
16423
+ return cachedToken;
16424
+ }
16425
+ async function queryOnce(sourceIntegration, sourceExternalId) {
16426
+ const token = await getToken();
16427
+ const qs = new URLSearchParams({
16428
+ agent_id: agentId,
16429
+ source_integration: sourceIntegration,
16430
+ source_external_id: sourceExternalId
16431
+ });
16432
+ return fetchImpl(`${base}/host/kanban/progress-card-active?${qs.toString()}`, {
16433
+ method: "GET",
16434
+ headers: { Authorization: `Bearer ${token}` },
16435
+ signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS6)
16436
+ });
16437
+ }
16438
+ async function query(sourceIntegration, sourceExternalId) {
16439
+ let resp = await queryOnce(sourceIntegration, sourceExternalId);
16440
+ if (resp.status === 401) {
16441
+ cachedToken = null;
16442
+ cachedTokenExpiresAt = 0;
16443
+ resp = await queryOnce(sourceIntegration, sourceExternalId);
16444
+ }
16445
+ if (!resp.ok) return false;
16446
+ const data = await resp.json();
16447
+ return data.active === true;
16448
+ }
16449
+ return {
16450
+ async isCardActive(sourceIntegration, sourceExternalId) {
16451
+ const key2 = `${sourceIntegration}:${sourceExternalId}`;
16452
+ const t = now();
16453
+ const hit = cache2.get(key2);
16454
+ if (hit && t < hit.expiresAt) return hit.active;
16455
+ try {
16456
+ const active = await query(sourceIntegration, sourceExternalId);
16457
+ cache2.set(key2, { active, expiresAt: t + (active ? positiveTtlMs : negativeTtlMs) });
16458
+ return active;
16459
+ } catch (err) {
16460
+ log(`kanban-card-active: query threw key=${key2}: ${err.message}`);
16461
+ return false;
16462
+ }
16463
+ }
16464
+ };
16465
+ }
16466
+
16378
16467
  // src/mcp-spawn-lock.ts
16379
16468
  import {
16380
16469
  existsSync as existsSync5,
@@ -16734,6 +16823,13 @@ var inboundContextClient = createInboundContextClient({
16734
16823
  log: (line) => process.stderr.write(`telegram-channel(${AGENT_CODE_NAME}): ${line}
16735
16824
  `)
16736
16825
  });
16826
+ var kanbanCardActiveClient = createKanbanCardActiveClient({
16827
+ agtHost: AGT_HOST,
16828
+ agtApiKey: AGT_API_KEY,
16829
+ agentId: process.env.AGT_AGENT_ID ?? null,
16830
+ log: (line) => process.stderr.write(`telegram-channel(${AGENT_CODE_NAME}): ${line}
16831
+ `)
16832
+ });
16737
16833
  var peerRateApiClient = createDefaultPeerRateApiClient({
16738
16834
  agtHost: AGT_HOST,
16739
16835
  agtApiKey: AGT_API_KEY,
@@ -18105,7 +18201,7 @@ function findTelegramProgressTarget() {
18105
18201
  }
18106
18202
  var TELEGRAM_PROGRESS_PREFIX = "\u23F3";
18107
18203
  function telegramProgressText(step) {
18108
- return `${TELEGRAM_PROGRESS_PREFIX} Working\u2026 \xB7 ${step}`;
18204
+ return `${TELEGRAM_PROGRESS_PREFIX} ${composeProgressBody(step)}`;
18109
18205
  }
18110
18206
  async function postTelegramProgress(chatId, step) {
18111
18207
  if (!BOT_TOKEN) return null;
@@ -18158,14 +18254,19 @@ async function telegramProgressTick() {
18158
18254
  }
18159
18255
  return;
18160
18256
  }
18161
- const action = decideProgressAction({
18257
+ const baseInput = {
18162
18258
  now: Date.now(),
18163
18259
  heartbeat: readTelegramProgressHeartbeat(),
18164
18260
  target: findTelegramProgressTarget(),
18165
18261
  tracked: telegramTrackedProgress,
18166
18262
  freshnessMs: progressHeartbeatFreshMs(),
18167
18263
  minPendingMs: progressMinPendingMs()
18168
- });
18264
+ };
18265
+ let action = decideProgressAction(baseInput);
18266
+ if (kanbanCardActiveClient && baseInput.target && (action.type === "post" || action.type === "update" || action.type === "none" && telegramTrackedProgress)) {
18267
+ const hasCard = await kanbanCardActiveClient.isCardActive("telegram", baseInput.target.channel);
18268
+ if (hasCard) action = decideProgressAction({ ...baseInput, targetHasCard: true });
18269
+ }
18169
18270
  switch (action.type) {
18170
18271
  case "post": {
18171
18272
  const id = await postTelegramProgress(action.channel, action.step);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@integrity-labs/agt-cli",
3
- "version": "0.28.96",
3
+ "version": "0.28.97",
4
4
  "description": "Augmented Team CLI — agent provisioning and management",
5
5
  "type": "module",
6
6
  "engines": {