@integrity-labs/agt-cli 0.13.0 → 0.14.1

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.
@@ -9,6 +9,7 @@ import {
9
9
  getIntegration,
10
10
  isParseError,
11
11
  isResolveError,
12
+ isSuppressOutput,
12
13
  parseDeliveryTarget,
13
14
  provision,
14
15
  provisionIsolationHook,
@@ -17,7 +18,7 @@ import {
17
18
  resolveChannels,
18
19
  resolveDmTarget,
19
20
  wrapScheduledTaskPrompt
20
- } from "../chunk-WNYQKTBP.js";
21
+ } from "../chunk-HGPRV76J.js";
21
22
  import {
22
23
  findTaskByTemplate,
23
24
  getProjectDir,
@@ -637,6 +638,51 @@ function pickHintVariant(rng = Math.random) {
637
638
  return HINT_VARIANTS[idx];
638
639
  }
639
640
 
641
+ // src/lib/delivery-schedule-link.ts
642
+ function envSuffixFor2(codeName) {
643
+ return codeName.replace(/[^A-Za-z0-9]+/g, "_").toUpperCase();
644
+ }
645
+ function scheduleLinkFooterEnabled(codeName, env = process.env) {
646
+ if (codeName) {
647
+ const perAgent = env[`AGT_SCHEDULE_LINK_FOOTER_DISABLED__${envSuffixFor2(codeName)}`];
648
+ if (perAgent === "1") return false;
649
+ }
650
+ if (env["AGT_SCHEDULE_LINK_FOOTER_DISABLED"] === "1") return false;
651
+ return true;
652
+ }
653
+ function getConsoleUrl(env = process.env) {
654
+ const canonical = env["AGT_CONSOLE_URL"]?.trim();
655
+ if (canonical) return canonical.replace(/\/+$/, "");
656
+ const fallback = env["NEXT_PUBLIC_APP_URL"]?.trim();
657
+ if (fallback) return fallback.replace(/\/+$/, "");
658
+ return null;
659
+ }
660
+ function buildScheduleEditLink(consoleUrl, agentId, taskId) {
661
+ const base = consoleUrl.replace(/\/+$/, "");
662
+ return `${base}/agents/${encodeURIComponent(agentId)}/schedules/${encodeURIComponent(taskId)}`;
663
+ }
664
+ function formatScheduleLinkFooter(url, medium) {
665
+ if (medium === "slack") return `<${url}|Edit schedule>`;
666
+ if (medium === "telegram") return `Edit schedule: ${url}`;
667
+ return url;
668
+ }
669
+ function appendScheduleLinkFooter(body, url, medium) {
670
+ const footer = formatScheduleLinkFooter(url, medium);
671
+ const trimmed = body.replace(/\s+$/, "");
672
+ if (trimmed.endsWith(footer)) return trimmed;
673
+ return `${trimmed}
674
+
675
+ ${footer}`;
676
+ }
677
+ function withScheduleLinkFooter(opts) {
678
+ if (!opts.taskId) return opts.body;
679
+ if (!scheduleLinkFooterEnabled(opts.codeName, opts.env)) return opts.body;
680
+ const consoleUrl = getConsoleUrl(opts.env);
681
+ if (!consoleUrl) return opts.body;
682
+ const url = buildScheduleEditLink(consoleUrl, opts.agentId, opts.taskId);
683
+ return appendScheduleLinkFooter(opts.body, url, opts.medium);
684
+ }
685
+
640
686
  // src/lib/realtime-chat.ts
641
687
  import { createClient } from "@supabase/supabase-js";
642
688
  var client = null;
@@ -3162,6 +3208,18 @@ async function executeAndProcessClaudeTask(codeName, agentId, task, prompt) {
3162
3208
  }
3163
3209
  async function processClaudeTaskResult(codeName, agentId, templateId, output, delivery) {
3164
3210
  try {
3211
+ if (isSuppressOutput(output)) {
3212
+ const trimmed = (output ?? "").trim();
3213
+ const outputSummary = trimmed.length === 0 ? "<empty>" : trimmed.length > 80 ? `${trimmed.slice(0, 77)}...` : trimmed;
3214
+ log(`[claude-scheduler] Suppressing delivery for '${codeName}' (template=${templateId}, task=${delivery?.taskId ?? "n/a"}) \u2014 output was: ${outputSummary}`);
3215
+ if (delivery?.mode === "announce" && delivery.to) {
3216
+ await reportDeliveryStatus(agentId, delivery.taskId, {
3217
+ status: "skipped",
3218
+ error_code: "NO_CONTENT"
3219
+ });
3220
+ }
3221
+ return;
3222
+ }
3165
3223
  if (STANDUP_TEMPLATES.has(templateId)) {
3166
3224
  const standup = parseStandupSummary(output);
3167
3225
  await api.post("/host/agent-status", {
@@ -3195,7 +3253,7 @@ async function processClaudeTaskResult(codeName, agentId, templateId, output, de
3195
3253
  log(`[claude-scheduler] Kanban updates posted for '${codeName}' (${kanbanUpdates.length} updates)`);
3196
3254
  }
3197
3255
  }
3198
- if (delivery?.mode === "announce" && delivery.to && output) {
3256
+ if (delivery?.mode === "announce" && delivery.to) {
3199
3257
  await deliverScheduledTaskOutput(
3200
3258
  codeName,
3201
3259
  agentId,
@@ -4367,9 +4425,10 @@ ${a.detail}`;
4367
4425
  ${blocks.join("\n\n")}`);
4368
4426
  }
4369
4427
  async function deliverScheduledTaskOutput(agentCodeName, agentId, rawTarget, body, taskId) {
4428
+ const withLink = (b, medium) => withScheduleLinkFooter({ body: b, medium, codeName: agentCodeName, agentId, taskId });
4370
4429
  if (typeof rawTarget === "string") {
4371
4430
  if (rawTarget.startsWith("channel:")) {
4372
- const result = await sendTaskNotification(agentCodeName, "slack", rawTarget, body);
4431
+ const result = await sendTaskNotification(agentCodeName, "slack", rawTarget, withLink(body, "slack"));
4373
4432
  await reportDeliveryStatus(agentId, taskId, {
4374
4433
  status: result.ok ? "ok" : "failed",
4375
4434
  medium: "slack",
@@ -4378,7 +4437,7 @@ async function deliverScheduledTaskOutput(agentCodeName, agentId, rawTarget, bod
4378
4437
  return;
4379
4438
  }
4380
4439
  if (rawTarget.startsWith("chat:")) {
4381
- const result = await sendTaskNotification(agentCodeName, "telegram", rawTarget, body);
4440
+ const result = await sendTaskNotification(agentCodeName, "telegram", rawTarget, withLink(body, "telegram"));
4382
4441
  await reportDeliveryStatus(agentId, taskId, {
4383
4442
  status: result.ok ? "ok" : "failed",
4384
4443
  medium: "telegram",
@@ -4399,7 +4458,7 @@ async function deliverScheduledTaskOutput(agentCodeName, agentId, rawTarget, bod
4399
4458
  if (parsed.kind === "channel") {
4400
4459
  if (parsed.provider === "slack") {
4401
4460
  const channelId = parsed.channel_id ?? "";
4402
- const sent = await postSlackChannelMessage(agentCodeName, channelId, body);
4461
+ const sent = await postSlackChannelMessage(agentCodeName, channelId, withLink(body, "slack"));
4403
4462
  await reportDeliveryStatus(agentId, taskId, {
4404
4463
  status: sent.ok ? "ok" : "failed",
4405
4464
  medium: "slack",
@@ -4410,7 +4469,7 @@ async function deliverScheduledTaskOutput(agentCodeName, agentId, rawTarget, bod
4410
4469
  }
4411
4470
  const chatId = parsed.chat_id ?? "";
4412
4471
  const toStr = `chat:${chatId}`;
4413
- const result = await sendTaskNotification(agentCodeName, "telegram", toStr, body);
4472
+ const result = await sendTaskNotification(agentCodeName, "telegram", toStr, withLink(body, "telegram"));
4414
4473
  await reportDeliveryStatus(agentId, taskId, {
4415
4474
  status: result.ok ? "ok" : "failed",
4416
4475
  medium: "telegram",
@@ -4434,11 +4493,12 @@ async function deliverScheduledTaskOutput(agentCodeName, agentId, rawTarget, bod
4434
4493
  await reportDeliveryStatus(agentId, taskId, { status: "failed", error_code: resolved.code });
4435
4494
  return;
4436
4495
  }
4437
- const footeredBody = appendDmFooter(
4496
+ const attributionBody = appendDmFooter(
4438
4497
  body,
4439
4498
  agentRow.ownerTeamName,
4440
4499
  agentRow.agentDisplayName
4441
4500
  );
4501
+ const footeredBody = resolved.kind === "dm" ? withLink(attributionBody, resolved.medium === "slack" ? "slack" : "telegram") : attributionBody;
4442
4502
  if (resolved.kind === "dm" && resolved.medium === "slack") {
4443
4503
  const tokens = agentChannelTokens.get(agentCodeName);
4444
4504
  const botToken = tokens?.slack;