@integrity-labs/agt-cli 0.28.294 → 0.28.296

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.
@@ -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-7Z33SV2X.js");
103
+ const { resolveClaudeBinary } = await import("./persistent-session-A5N7BYS3.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-EWJQ5QXS.js.map
376
+ //# sourceMappingURL=claude-pair-runtime-BIBIVB7I.js.map
@@ -39,7 +39,7 @@ import {
39
39
  requireHost,
40
40
  safeWriteJsonAtomic,
41
41
  setConfigHash
42
- } from "../chunk-5F23HET3.js";
42
+ } from "../chunk-DZLBOAQ2.js";
43
43
  import {
44
44
  getProjectDir as getProjectDir2,
45
45
  getReadyTasks,
@@ -126,7 +126,7 @@ import {
126
126
  takeZombieDetection,
127
127
  transcriptActivityAgeSeconds,
128
128
  writeEgressAllowlist
129
- } from "../chunk-IGADZDYT.js";
129
+ } from "../chunk-QXU5FMXN.js";
130
130
  import {
131
131
  reapOrphanChannelMcps
132
132
  } from "../chunk-XWVM4KPK.js";
@@ -3442,6 +3442,63 @@ function killAgentChannelProcesses(codeName, opts) {
3442
3442
  return pids;
3443
3443
  }
3444
3444
 
3445
+ // src/lib/delivery-schedule-link.ts
3446
+ function envSuffixFor(codeName) {
3447
+ return codeName.replace(/[^A-Za-z0-9]+/g, "_").toUpperCase();
3448
+ }
3449
+ function scheduleLinkFooterEnabled(codeName, env = process.env) {
3450
+ if (codeName) {
3451
+ const perAgent = env[`AGT_SCHEDULE_LINK_FOOTER_DISABLED__${envSuffixFor(codeName)}`];
3452
+ if (perAgent === "1") return false;
3453
+ }
3454
+ if (env["AGT_SCHEDULE_LINK_FOOTER_DISABLED"] === "1") return false;
3455
+ return true;
3456
+ }
3457
+ function getConsoleUrl(env = process.env) {
3458
+ const canonical = env["AGT_CONSOLE_URL"]?.trim();
3459
+ if (canonical) return canonical.replace(/\/+$/, "");
3460
+ const fallback = env["NEXT_PUBLIC_APP_URL"]?.trim();
3461
+ if (fallback) return fallback.replace(/\/+$/, "");
3462
+ return null;
3463
+ }
3464
+ function buildScheduleEditLink(consoleUrl, agentId, taskId) {
3465
+ const base = consoleUrl.replace(/\/+$/, "");
3466
+ return `${base}/agents/${encodeURIComponent(agentId)}/schedules/${encodeURIComponent(taskId)}`;
3467
+ }
3468
+ function formatScheduleLinkFooter(url, medium) {
3469
+ if (medium === "slack") return `<${url}|Edit schedule>`;
3470
+ if (medium === "telegram") return `Edit schedule: ${url}`;
3471
+ return url;
3472
+ }
3473
+ function appendScheduleLinkFooter(body, url, medium) {
3474
+ const footer = formatScheduleLinkFooter(url, medium);
3475
+ const trimmed = body.replace(/\s+$/, "");
3476
+ if (trimmed.endsWith(footer)) return trimmed;
3477
+ return `${trimmed}
3478
+
3479
+ ${footer}`;
3480
+ }
3481
+ var warnedNullConsoleUrl = false;
3482
+ function withScheduleLinkFooter(opts) {
3483
+ if (!opts.taskId) return opts.body;
3484
+ if (!scheduleLinkFooterEnabled(opts.codeName, opts.env)) return opts.body;
3485
+ const consoleUrl = getConsoleUrl(opts.env);
3486
+ if (!consoleUrl) {
3487
+ if (!warnedNullConsoleUrl && opts.log) {
3488
+ warnedNullConsoleUrl = true;
3489
+ try {
3490
+ opts.log(
3491
+ "[schedule-link] AGT_CONSOLE_URL unset and NEXT_PUBLIC_APP_URL unset \u2014 schedule-edit deep-link footer disabled. Run `agt setup` again or export AGT_CONSOLE_URL (e.g. https://app.augmented.team) to restore it."
3492
+ );
3493
+ } catch {
3494
+ }
3495
+ }
3496
+ return opts.body;
3497
+ }
3498
+ const url = buildScheduleEditLink(consoleUrl, opts.agentId, opts.taskId);
3499
+ return appendScheduleLinkFooter(opts.body, url, opts.medium);
3500
+ }
3501
+
3445
3502
  // src/lib/manager/agent-state.ts
3446
3503
  var agentState = {
3447
3504
  // ---------------------------------------------------------------------------
@@ -4164,11 +4221,11 @@ function setAlertSlackWebhook(value) {
4164
4221
 
4165
4222
  // src/lib/delivery-hint.ts
4166
4223
  var DEFAULT_PROBABILITY = 0.1;
4167
- function envSuffixFor(codeName) {
4224
+ function envSuffixFor2(codeName) {
4168
4225
  return codeName.replace(/[^A-Za-z0-9]+/g, "_").toUpperCase();
4169
4226
  }
4170
4227
  function hintProbability(codeName, env = process.env) {
4171
- const suffix = codeName ? `__${envSuffixFor(codeName)}` : "";
4228
+ const suffix = codeName ? `__${envSuffixFor2(codeName)}` : "";
4172
4229
  if (suffix && env[`AGT_DELIVERY_HINT_DISABLED${suffix}`] === "1") return 0;
4173
4230
  const perAgent = suffix ? env[`AGT_DELIVERY_HINT_PROBABILITY${suffix}`] : void 0;
4174
4231
  if (perAgent != null) return clampProbability(perAgent);
@@ -4436,6 +4493,29 @@ ${isFailed ? "Reason" : "Result"}: ${resultBody.slice(0, NOTIFY_RESULT_MAX_CHARS
4436
4493
  return `${emoji} ${isFailed ? "Task Failed" : "Task Complete"} \u2014 ${displayName}
4437
4494
  ${item.title}${resultLine}`;
4438
4495
  }
4496
+ function resolveRequesterDmTarget(requester) {
4497
+ if (requester.channel === "slack" && requester.sender_id) {
4498
+ return { channel: "slack", to: requester.sender_id };
4499
+ }
4500
+ if (requester.channel === "telegram" && requester.external_id) {
4501
+ return { channel: "telegram", to: requester.external_id };
4502
+ }
4503
+ return null;
4504
+ }
4505
+ function buildWaitingHumanNotification(args) {
4506
+ const esc = (s) => args.medium === "slack" ? s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;") : s;
4507
+ const lines = [`\u{1F514} ${esc(args.displayName)} needs your input on "${esc(args.title)}".`];
4508
+ const ask = args.waitingOn?.trim();
4509
+ if (ask) lines.push(esc(ask));
4510
+ const choiceLabels = (args.choices ?? []).map((c) => c.label?.trim()).filter((l) => !!l).map(esc);
4511
+ if (choiceLabels.length > 0) lines.push(`Options: ${choiceLabels.join(" \xB7 ")}`);
4512
+ if (args.consoleUrl) {
4513
+ const base = args.consoleUrl.replace(/\/+$/, "");
4514
+ const url = `${base}/agents/${encodeURIComponent(args.agentId)}?item=${encodeURIComponent(args.itemId)}`;
4515
+ lines.push(args.medium === "slack" ? `<${url}|Respond>` : `Respond: ${url}`);
4516
+ }
4517
+ return lines.join("\n");
4518
+ }
4439
4519
  async function sendTaskNotification(agentCodeName, channel, to, text) {
4440
4520
  const tokens = agentChannelTokens.get(agentCodeName);
4441
4521
  if (channel === "slack") {
@@ -4613,63 +4693,6 @@ function closeScheduledRunsForCode(codeName, outcome, reason) {
4613
4693
  // src/lib/manager/scheduler/kanban-route.ts
4614
4694
  import { createHash as createHash9 } from "crypto";
4615
4695
 
4616
- // src/lib/delivery-schedule-link.ts
4617
- function envSuffixFor2(codeName) {
4618
- return codeName.replace(/[^A-Za-z0-9]+/g, "_").toUpperCase();
4619
- }
4620
- function scheduleLinkFooterEnabled(codeName, env = process.env) {
4621
- if (codeName) {
4622
- const perAgent = env[`AGT_SCHEDULE_LINK_FOOTER_DISABLED__${envSuffixFor2(codeName)}`];
4623
- if (perAgent === "1") return false;
4624
- }
4625
- if (env["AGT_SCHEDULE_LINK_FOOTER_DISABLED"] === "1") return false;
4626
- return true;
4627
- }
4628
- function getConsoleUrl(env = process.env) {
4629
- const canonical = env["AGT_CONSOLE_URL"]?.trim();
4630
- if (canonical) return canonical.replace(/\/+$/, "");
4631
- const fallback = env["NEXT_PUBLIC_APP_URL"]?.trim();
4632
- if (fallback) return fallback.replace(/\/+$/, "");
4633
- return null;
4634
- }
4635
- function buildScheduleEditLink(consoleUrl, agentId, taskId) {
4636
- const base = consoleUrl.replace(/\/+$/, "");
4637
- return `${base}/agents/${encodeURIComponent(agentId)}/schedules/${encodeURIComponent(taskId)}`;
4638
- }
4639
- function formatScheduleLinkFooter(url, medium) {
4640
- if (medium === "slack") return `<${url}|Edit schedule>`;
4641
- if (medium === "telegram") return `Edit schedule: ${url}`;
4642
- return url;
4643
- }
4644
- function appendScheduleLinkFooter(body, url, medium) {
4645
- const footer = formatScheduleLinkFooter(url, medium);
4646
- const trimmed = body.replace(/\s+$/, "");
4647
- if (trimmed.endsWith(footer)) return trimmed;
4648
- return `${trimmed}
4649
-
4650
- ${footer}`;
4651
- }
4652
- var warnedNullConsoleUrl = false;
4653
- function withScheduleLinkFooter(opts) {
4654
- if (!opts.taskId) return opts.body;
4655
- if (!scheduleLinkFooterEnabled(opts.codeName, opts.env)) return opts.body;
4656
- const consoleUrl = getConsoleUrl(opts.env);
4657
- if (!consoleUrl) {
4658
- if (!warnedNullConsoleUrl && opts.log) {
4659
- warnedNullConsoleUrl = true;
4660
- try {
4661
- opts.log(
4662
- "[schedule-link] AGT_CONSOLE_URL unset and NEXT_PUBLIC_APP_URL unset \u2014 schedule-edit deep-link footer disabled. Run `agt setup` again or export AGT_CONSOLE_URL (e.g. https://app.augmented.team) to restore it."
4663
- );
4664
- } catch {
4665
- }
4666
- }
4667
- return opts.body;
4668
- }
4669
- const url = buildScheduleEditLink(consoleUrl, opts.agentId, opts.taskId);
4670
- return appendScheduleLinkFooter(opts.body, url, opts.medium);
4671
- }
4672
-
4673
4696
  // src/lib/manager/delivery/scheduled-output.ts
4674
4697
  async function deliverScheduledTaskOutput(agentCodeName, agentId, rawTarget, body, taskId) {
4675
4698
  const withLink = (b, medium) => withScheduleLinkFooter({ body: b, medium, codeName: agentCodeName, agentId, taskId, log });
@@ -6901,6 +6924,8 @@ function clearAgentCaches(agentId, codeName) {
6901
6924
  agentChannelTokens.delete(codeName);
6902
6925
  agentFrameworkCache.delete(codeName);
6903
6926
  kanbanBoardCache.delete(codeName);
6927
+ notifyBoardCache.delete(codeName);
6928
+ notifiedWaitingHumanIds.delete(codeName);
6904
6929
  lastHarvestAt.delete(codeName);
6905
6930
  claudeSchedulerStates.delete(codeName);
6906
6931
  claudeTaskConcurrency.delete(codeName);
@@ -6922,7 +6947,7 @@ var agentRestartTimezoneInputs = /* @__PURE__ */ new Map();
6922
6947
  var lastVersionCheckAt = 0;
6923
6948
  var VERSION_CHECK_INTERVAL_MS = 5 * 60 * 1e3;
6924
6949
  var lastResponsivenessProbeAt = 0;
6925
- var agtCliVersion = true ? "0.28.294" : "dev";
6950
+ var agtCliVersion = true ? "0.28.296" : "dev";
6926
6951
  function resolveBrewPath(execFileSync2) {
6927
6952
  try {
6928
6953
  const out = execFileSync2("which", ["brew"], { timeout: 5e3 }).toString().trim();
@@ -7775,7 +7800,7 @@ function flushRestartedAgentDiagnostics(hostId, codeNames) {
7775
7800
  if (codeNames.length === 0) return;
7776
7801
  void (async () => {
7777
7802
  try {
7778
- const { collectDiagnostics } = await import("../persistent-session-7Z33SV2X.js");
7803
+ const { collectDiagnostics } = await import("../persistent-session-A5N7BYS3.js");
7779
7804
  await api.post("/host/heartbeat", {
7780
7805
  host_id: hostId,
7781
7806
  agent_diagnostics: collectDiagnostics(codeNames)
@@ -7873,7 +7898,7 @@ async function pollCycle() {
7873
7898
  }
7874
7899
  try {
7875
7900
  const { detectHostSecurity } = await import("../host-security-6PDFG7F5.js");
7876
- const { collectDiagnostics } = await import("../persistent-session-7Z33SV2X.js");
7901
+ const { collectDiagnostics } = await import("../persistent-session-A5N7BYS3.js");
7877
7902
  const diagCodeNames = [...agentState.persistentSessionAgents];
7878
7903
  const agentDiagnostics = diagCodeNames.length > 0 ? collectDiagnostics(diagCodeNames) : void 0;
7879
7904
  let tailscaleHostname;
@@ -8021,7 +8046,7 @@ async function pollCycle() {
8021
8046
  const {
8022
8047
  collectResponsivenessProbes,
8023
8048
  getResponsivenessIntervalMs
8024
- } = await import("../responsiveness-probe-RPX63Y5S.js");
8049
+ } = await import("../responsiveness-probe-OZP2HO2F.js");
8025
8050
  const probeIntervalMs = getResponsivenessIntervalMs();
8026
8051
  if (now - lastResponsivenessProbeAt > probeIntervalMs) {
8027
8052
  const probeCodeNames = [...agentState.persistentSessionAgents];
@@ -8053,7 +8078,7 @@ async function pollCycle() {
8053
8078
  collectResponsivenessProbes,
8054
8079
  livePendingInboundOldestAgeSeconds,
8055
8080
  parkPendingInbound
8056
- } = await import("../responsiveness-probe-RPX63Y5S.js");
8081
+ } = await import("../responsiveness-probe-OZP2HO2F.js");
8057
8082
  const { getProjectDir: wedgeProjectDir } = await import("../claude-scheduler-FATCLHDM.js");
8058
8083
  const wedgeNow = /* @__PURE__ */ new Date();
8059
8084
  const liveAgents = agentState.persistentSessionAgents;
@@ -10299,6 +10324,49 @@ async function processAgent(agent, agentStates) {
10299
10324
  }
10300
10325
  }
10301
10326
  }
10327
+ {
10328
+ const freshWaitingHumanIds = new Set(
10329
+ freshBoard.filter((b) => b.status === "waiting" && b.waiting_kind === "human" && b.metadata?.requester).map((b) => b.id)
10330
+ );
10331
+ const prevWaitingHumanIds = notifiedWaitingHumanIds.get(agent.code_name);
10332
+ notifiedWaitingHumanIds.set(agent.code_name, freshWaitingHumanIds);
10333
+ if (prevWaitingHumanIds) {
10334
+ const newlyWaiting = freshBoard.filter(
10335
+ (b) => b.status === "waiting" && b.waiting_kind === "human" && !prevWaitingHumanIds.has(b.id) && b.metadata?.requester && // ENG-7643 (P5b-2): the API posts inline Slack buttons for a Slack
10336
+ // requester WITH choices; suppress the text DM for that exact case
10337
+ // so the requester isn't pinged twice. Non-Slack or no-choices
10338
+ // still gets the manager text DM.
10339
+ !(b.metadata.requester.channel === "slack" && (b.waiting_context?.choices?.length ?? 0) > 0)
10340
+ );
10341
+ if (newlyWaiting.length > 0) {
10342
+ const waitingDisplayName = agentState.agentDisplayNames.get(agent.code_name) ?? agent.code_name;
10343
+ const consoleUrl = getConsoleUrl();
10344
+ for (const item of newlyWaiting) {
10345
+ const requester = item.metadata.requester;
10346
+ const target = resolveRequesterDmTarget(requester);
10347
+ if (!target) {
10348
+ log(
10349
+ `[${agent.code_name}] waiting-human notify skipped for '${item.id}': no DM target for channel=${requester.channel}`
10350
+ );
10351
+ continue;
10352
+ }
10353
+ const message = buildWaitingHumanNotification({
10354
+ displayName: waitingDisplayName,
10355
+ agentId,
10356
+ itemId: item.id,
10357
+ title: item.title,
10358
+ waitingOn: item.waiting_on,
10359
+ choices: item.waiting_context?.choices,
10360
+ medium: target.channel,
10361
+ consoleUrl
10362
+ });
10363
+ sendTaskNotification(agent.code_name, target.channel, target.to, message).catch((err) => {
10364
+ log(`waiting-human notify failed for '${agent.code_name}': ${err.message}`);
10365
+ });
10366
+ }
10367
+ }
10368
+ }
10369
+ }
10302
10370
  const staleItems = freshBoard.filter((b) => {
10303
10371
  if (b.status !== "in_progress" || !b.updated_at) return false;
10304
10372
  const age = Date.now() - new Date(b.updated_at).getTime();
@@ -10981,7 +11049,7 @@ async function handleRestartDoorbell(agentId, requestedAt, restartReason) {
10981
11049
  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}`));
10982
11050
  void (async () => {
10983
11051
  try {
10984
- const { collectDiagnostics } = await import("../persistent-session-7Z33SV2X.js");
11052
+ const { collectDiagnostics } = await import("../persistent-session-A5N7BYS3.js");
10985
11053
  await api.post("/host/heartbeat", {
10986
11054
  host_id: hostId,
10987
11055
  agent_diagnostics: collectDiagnostics([codeName])
@@ -11031,7 +11099,7 @@ async function respawnAgentAfterMcpStop(codeName, reason) {
11031
11099
  }
11032
11100
  try {
11033
11101
  const hostId = await getHostId();
11034
- const { collectDiagnostics } = await import("../persistent-session-7Z33SV2X.js");
11102
+ const { collectDiagnostics } = await import("../persistent-session-A5N7BYS3.js");
11035
11103
  await api.post("/host/heartbeat", {
11036
11104
  host_id: hostId,
11037
11105
  agent_diagnostics: collectDiagnostics([codeName])
@@ -11419,6 +11487,7 @@ var lastHarvestAt = /* @__PURE__ */ new Map();
11419
11487
  var HARVEST_INTERVAL_MS = 3 * 60 * 1e3;
11420
11488
  var kanbanBoardCache = /* @__PURE__ */ new Map();
11421
11489
  var notifyBoardCache = /* @__PURE__ */ new Map();
11490
+ var notifiedWaitingHumanIds = /* @__PURE__ */ new Map();
11422
11491
  var spawnedPairIds = /* @__PURE__ */ new Set();
11423
11492
  async function processClaudePairSessions(agents) {
11424
11493
  if (agents.length === 0 && spawnedPairIds.size === 0) return;
@@ -11435,7 +11504,7 @@ async function processClaudePairSessions(agents) {
11435
11504
  killPairSession,
11436
11505
  pairTmuxSession,
11437
11506
  finalizeClaudePairOnboarding
11438
- } = await import("../claude-pair-runtime-EWJQ5QXS.js");
11507
+ } = await import("../claude-pair-runtime-BIBIVB7I.js");
11439
11508
  for (const pairId of pendingResp.cancelled_pair_ids ?? []) {
11440
11509
  log(`[claude-pair] sweeping orphan tmux session for pair ${pairId.slice(0, 8)}`);
11441
11510
  const killed = await killPairSession(pairTmuxSession(pairId));