@integrity-labs/agt-cli 0.25.2 → 0.26.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.
@@ -13,9 +13,8 @@ import {
13
13
  provisionOrientHook,
14
14
  provisionStopHook,
15
15
  requireHost
16
- } from "../chunk-U4DAVDAZ.js";
16
+ } from "../chunk-UTPOHAX7.js";
17
17
  import {
18
- findTaskByTemplate,
19
18
  getProjectDir as getProjectDir2,
20
19
  getReadyTasks,
21
20
  loadSchedulerState,
@@ -24,7 +23,6 @@ import {
24
23
  } from "../chunk-HR5T2RQF.js";
25
24
  import {
26
25
  buildAllowedTools,
27
- ensureKanbanLoopArmed,
28
26
  getLastFailureContext,
29
27
  getProjectDir,
30
28
  getSessionState,
@@ -32,8 +30,6 @@ import {
32
30
  injectMessageWithStatus,
33
31
  isAgentIdle,
34
32
  isAgentPromptReady,
35
- isKanbanLoopArmedForCurrentSession,
36
- isKanbanLoopDisabled,
37
33
  isSessionHealthy,
38
34
  isStaleForToday,
39
35
  parsePsRows,
@@ -50,7 +46,7 @@ import {
50
46
  stopAllSessionsAndWait,
51
47
  stopPersistentSession,
52
48
  takeZombieDetection
53
- } from "../chunk-M2RBM3M5.js";
49
+ } from "../chunk-QJJAGFJJ.js";
54
50
  import {
55
51
  KANBAN_CHECK_COMMAND,
56
52
  appendDmFooter,
@@ -73,7 +69,7 @@ import {
73
69
  resolveConnectivityProbe,
74
70
  resolveDmTarget,
75
71
  wrapScheduledTaskPrompt
76
- } from "../chunk-VWOXS4YP.js";
72
+ } from "../chunk-7NDNTSHD.js";
77
73
 
78
74
  // src/lib/manager-worker.ts
79
75
  import { createHash as createHash3 } from "crypto";
@@ -2966,7 +2962,14 @@ async function runAgentConnectivityProbes(agent, integrations, projectDir) {
2966
2962
  auth_type: i.auth_type,
2967
2963
  source_type: i.source_type ?? null,
2968
2964
  credentials: i.credentials,
2969
- last_connectivity_check_at: i.last_connectivity_check_at ?? null
2965
+ last_connectivity_check_at: i.last_connectivity_check_at ?? null,
2966
+ // ENG-5665: for managed (Composio) + mcp_server toolkits the connectivity
2967
+ // probe is an MCP `tools/list` against the agent's wired server. Derive the
2968
+ // .mcp.json server key the same way the managed-toolkit writer does
2969
+ // (definition_id === toolkit_id, sanitised: non-alnum → '_', lowercased —
2970
+ // e.g. 'composio_outlook'). The executor looks this up in .mcp.json; an
2971
+ // unresolvable key degrades to transient_error, never a false 'down'.
2972
+ mcp_server_key: i.source_type === "managed" || i.source_type === "mcp_server" ? i.definition_id.replace(/[^a-z0-9]/gi, "_").toLowerCase() : void 0
2970
2973
  })),
2971
2974
  { probeDeps, intervalMs: intervalSec * 1e3 }
2972
2975
  );
@@ -3130,7 +3133,7 @@ var cachedFrameworkVersion = null;
3130
3133
  var lastVersionCheckAt = 0;
3131
3134
  var VERSION_CHECK_INTERVAL_MS = 5 * 60 * 1e3;
3132
3135
  var lastResponsivenessProbeAt = 0;
3133
- var agtCliVersion = true ? "0.25.2" : "dev";
3136
+ var agtCliVersion = true ? "0.26.1" : "dev";
3134
3137
  function resolveBrewPath(execFileSync4) {
3135
3138
  try {
3136
3139
  const out = execFileSync4("which", ["brew"], { timeout: 5e3 }).toString().trim();
@@ -4089,7 +4092,7 @@ async function pollCycle() {
4089
4092
  }
4090
4093
  try {
4091
4094
  const { detectHostSecurity } = await import("../host-security-6PDFG7F5.js");
4092
- const { collectDiagnostics } = await import("../persistent-session-MUJA45LT.js");
4095
+ const { collectDiagnostics } = await import("../persistent-session-E5EZ32CI.js");
4093
4096
  const diagCodeNames = [...persistentSessionAgents];
4094
4097
  const agentDiagnostics = diagCodeNames.length > 0 ? collectDiagnostics(diagCodeNames) : void 0;
4095
4098
  let tailscaleHostname;
@@ -4147,7 +4150,7 @@ async function pollCycle() {
4147
4150
  const {
4148
4151
  collectResponsivenessProbes,
4149
4152
  getResponsivenessIntervalMs
4150
- } = await import("../responsiveness-probe-2TBRHC5T.js");
4153
+ } = await import("../responsiveness-probe-MLUVAXJH.js");
4151
4154
  const probeIntervalMs = getResponsivenessIntervalMs();
4152
4155
  if (now - lastResponsivenessProbeAt > probeIntervalMs) {
4153
4156
  const probeCodeNames = [...persistentSessionAgents];
@@ -5221,12 +5224,15 @@ async function processAgent(agent, agentStates) {
5221
5224
  }
5222
5225
  let tasks = refreshData.scheduled_tasks ?? [];
5223
5226
  const existingTemplateIds = new Set(tasks.map((t) => t.template_id));
5227
+ const kanbanWorkRetired = (agentFrameworkCache.get(agent.code_name) ?? "openclaw") === "claude-code" && agentSessionMode === "persistent";
5224
5228
  try {
5225
5229
  const defaultsData = await api.post("/host/resolve-default-schedules", { agent_id: agent.agent_id });
5226
- const missing = (defaultsData.schedules ?? []).filter(
5230
+ const allSchedules = (defaultsData.schedules ?? []).filter(
5231
+ (s) => !(kanbanWorkRetired && s.template_id === "kanban-work")
5232
+ );
5233
+ const missing = allSchedules.filter(
5227
5234
  (s) => !existingTemplateIds.has(s.template_id)
5228
5235
  );
5229
- const allSchedules = defaultsData.schedules ?? [];
5230
5236
  if (allSchedules.length > 0) {
5231
5237
  await api.post("/host/ensure-default-schedules", {
5232
5238
  agent_id: agent.agent_id,
@@ -5243,6 +5249,9 @@ async function processAgent(agent, agentStates) {
5243
5249
  } catch (err) {
5244
5250
  log(`Default schedule provisioning failed for '${agent.code_name}': ${err.message}`);
5245
5251
  }
5252
+ if (kanbanWorkRetired) {
5253
+ tasks = tasks.filter((t) => t.template_id !== "kanban-work");
5254
+ }
5246
5255
  if (agent.status === "active") {
5247
5256
  if (frameworkAdapter.installPlugin) {
5248
5257
  try {
@@ -5486,10 +5495,6 @@ async function processAgent(agent, agentStates) {
5486
5495
  sessionHealthy: psResult.sessionHealthyAfter,
5487
5496
  spawnAttempted: psResult.spawnAttempted
5488
5497
  });
5489
- if (psResult.sessionHealthyAfter) {
5490
- ensureKanbanLoopArmed(agent.code_name, log).catch(() => {
5491
- });
5492
- }
5493
5498
  if (stuck.shouldWarn) {
5494
5499
  log(
5495
5500
  `[persistent-session-stuck] WARN: agent=${agent.code_name} unhealthy with no spawn attempt for ${stuck.consecutiveTicks} consecutive ticks (last_decision=${psResult.decision}) \u2014 manager-worker may need restart, or upstream guard is mis-firing (see ENG-5116)`
@@ -5688,8 +5693,6 @@ async function processAgent(agent, agentStates) {
5688
5693
  } else {
5689
5694
  log(`[persistent-session] Work trigger skipped for '${agent.code_name}' \u2014 session not yet healthy`);
5690
5695
  }
5691
- } else {
5692
- fireClaudeWorkTrigger(agent.code_name, agent.agent_id, boardItems);
5693
5696
  }
5694
5697
  }
5695
5698
  }
@@ -5719,12 +5722,7 @@ async function processAgent(agent, agentStates) {
5719
5722
  for (const item of newlyDone) {
5720
5723
  log(`Newly done: '${item.title}' notify_channel=${item.notify_channel ?? "none"} notify_to=${item.notify_to ?? "none"}`);
5721
5724
  if (item.notify_channel && item.notify_to) {
5722
- const isFailed = item.status === "failed";
5723
- const resultLine = item.result ? `
5724
- ${isFailed ? "Reason" : "Result"}: ${item.result}` : "";
5725
- const emoji = isFailed ? "\u274C" : "\u2705";
5726
- const message = `${emoji} ${isFailed ? "Task Failed" : "Task Complete"} \u2014 ${displayName}
5727
- ${item.title}${resultLine}`;
5725
+ const message = await buildDoneCardNotification(agentId, agent.code_name, displayName, item);
5728
5726
  sendTaskNotification(agent.code_name, item.notify_channel, item.notify_to, message).catch((err) => {
5729
5727
  log(`sendTaskNotification failed for '${agent.code_name}': ${err.message}`);
5730
5728
  });
@@ -6006,8 +6004,7 @@ async function syncAndCheckClaudeScheduler(agent, tasks, boardItems, refreshData
6006
6004
  if (ready.length === 0) return;
6007
6005
  for (const task of ready) {
6008
6006
  if ((claudeTaskConcurrency.get(codeName) ?? 0) >= MAX_CLAUDE_CONCURRENCY) break;
6009
- if (KANBAN_WORK_TEMPLATES.has(task.templateId) && !hasActionableItems(boardItems)) {
6010
- log(`[claude-scheduler] Skipping '${task.name}' for '${codeName}' \u2014 board is empty`);
6007
+ if (KANBAN_WORK_TEMPLATES.has(task.templateId)) {
6011
6008
  const updated = markTaskFired(codeName, task.taskId, "ok");
6012
6009
  claudeSchedulerStates.set(codeName, updated);
6013
6010
  continue;
@@ -6018,20 +6015,6 @@ async function syncAndCheckClaudeScheduler(agent, tasks, boardItems, refreshData
6018
6015
  const boardPrefix = formatBoardForPrompt(boardItems, template);
6019
6016
  prompt = boardPrefix + prompt;
6020
6017
  }
6021
- if (KANBAN_WORK_TEMPLATES.has(task.templateId)) {
6022
- const todayItem = boardItems.find((b) => b.status === "todo");
6023
- if (todayItem) {
6024
- try {
6025
- await api.post("/host/kanban", {
6026
- agent_id: agent.agent_id,
6027
- update: [{ id: todayItem.id, title: todayItem.title, status: "in_progress" }]
6028
- });
6029
- log(`[claude-scheduler] Moved '${todayItem.title}' to in_progress for '${codeName}'`);
6030
- } catch (err) {
6031
- log(`[claude-scheduler] Failed to move item to in_progress: ${err.message}`);
6032
- }
6033
- }
6034
- }
6035
6018
  inFlightClaudeTasks.add(task.taskId);
6036
6019
  claudeTaskConcurrency.set(codeName, (claudeTaskConcurrency.get(codeName) ?? 0) + 1);
6037
6020
  log(`[claude-scheduler] Firing '${task.name}' for '${codeName}'`);
@@ -6433,30 +6416,6 @@ async function processClaudeTaskResult(codeName, agentId, templateId, rawOutput,
6433
6416
  log(`[claude-scheduler] Failed to post result for '${codeName}': ${err.message}`);
6434
6417
  }
6435
6418
  }
6436
- function fireClaudeWorkTrigger(codeName, agentId, boardItems) {
6437
- const state5 = claudeSchedulerStates.get(codeName) ?? loadSchedulerState(codeName);
6438
- const kanbanTask = findTaskByTemplate(state5, "kanban-work");
6439
- if (!kanbanTask) {
6440
- log(`[claude-scheduler] Work trigger: no kanban-work task found for '${codeName}'`);
6441
- return;
6442
- }
6443
- if (inFlightClaudeTasks.has(kanbanTask.taskId)) {
6444
- log(`[claude-scheduler] Work trigger: kanban-work already in-flight for '${codeName}'`);
6445
- return;
6446
- }
6447
- let prompt = kanbanTask.prompt;
6448
- if (boardItems.length > 0) {
6449
- const boardPrefix = formatBoardForPrompt(boardItems, "follow-up");
6450
- prompt = boardPrefix + prompt;
6451
- }
6452
- inFlightClaudeTasks.add(kanbanTask.taskId);
6453
- claudeTaskConcurrency.set(codeName, (claudeTaskConcurrency.get(codeName) ?? 0) + 1);
6454
- log(`[claude-scheduler] Work trigger: firing kanban-work for '${codeName}'`);
6455
- executeAndProcessClaudeTask(codeName, agentId, kanbanTask, prompt).finally(() => {
6456
- inFlightClaudeTasks.delete(kanbanTask.taskId);
6457
- claudeTaskConcurrency.set(codeName, Math.max(0, (claudeTaskConcurrency.get(codeName) ?? 1) - 1));
6458
- });
6459
- }
6460
6419
  var persistentSessionAgents = /* @__PURE__ */ new Set();
6461
6420
  var lastMcpFailedBannerCount = /* @__PURE__ */ new Map();
6462
6421
  var persistentSessionStuckTracker = new PersistentSessionStuckTracker();
@@ -6711,13 +6670,7 @@ ${truncateForLog(ctx.tail)}` : `; pane_tail_hash=sha256:${createHash3("sha256").
6711
6670
  log(`[persistent-session] ${ready.length} ready task(s) for '${codeName}': ${ready.map((t) => `${t.name}(next=${t.nextFireAt ? new Date(t.nextFireAt).toISOString() : "null"})`).join(", ")}`);
6712
6671
  }
6713
6672
  for (const task of ready) {
6714
- if (KANBAN_WORK_TEMPLATES.has(task.templateId) && isKanbanWorkCronDisabled() && isKanbanLoopArmedForCurrentSession(codeName)) {
6715
- const updated = markTaskFired(codeName, task.taskId, "ok");
6716
- claudeSchedulerStates.set(codeName, updated);
6717
- continue;
6718
- }
6719
- if (KANBAN_WORK_TEMPLATES.has(task.templateId) && !hasActionableItems(boardItems)) {
6720
- log(`[persistent-session] Skipping '${task.name}' for '${codeName}' \u2014 board is empty`);
6673
+ if (KANBAN_WORK_TEMPLATES.has(task.templateId)) {
6721
6674
  const updated = markTaskFired(codeName, task.taskId, "ok");
6722
6675
  claudeSchedulerStates.set(codeName, updated);
6723
6676
  continue;
@@ -6728,19 +6681,6 @@ ${truncateForLog(ctx.tail)}` : `; pane_tail_hash=sha256:${createHash3("sha256").
6728
6681
  const boardPrefix = formatBoardForPrompt(boardItems, template);
6729
6682
  prompt = boardPrefix + prompt;
6730
6683
  }
6731
- if (KANBAN_WORK_TEMPLATES.has(task.templateId)) {
6732
- const todayItem = boardItems.find((b) => b.status === "todo");
6733
- if (todayItem) {
6734
- try {
6735
- await api.post("/host/kanban", {
6736
- agent_id: agent.agent_id,
6737
- update: [{ id: todayItem.id, title: todayItem.title, status: "in_progress" }]
6738
- });
6739
- log(`[persistent-session] Moved '${todayItem.title}' to in_progress for '${codeName}'`);
6740
- } catch {
6741
- }
6742
- }
6743
- }
6744
6684
  if (inFlightClaudeTasks.has(task.taskId)) {
6745
6685
  continue;
6746
6686
  }
@@ -6974,15 +6914,13 @@ function ensureRealtimeKanbanStarted(agentStates) {
6974
6914
  if (!agent) return;
6975
6915
  const agentFw = agentFrameworkCache.get(agent.codeName) ?? "openclaw";
6976
6916
  if (agentFw === "claude-code") {
6977
- const boardItems = kanbanBoardCache.get(agent.codeName) ?? [];
6978
6917
  if (isSessionHealthy(agent.codeName)) {
6979
6918
  injectMessage(agent.codeName, "task", `New task added to your board: id=${item.id} title=${JSON.stringify(item.title)} priority=${item.priority}. Call kanban_move("${item.id}", "in_progress") and start working.`, {
6980
6919
  task_name: "kanban-work-trigger"
6981
6920
  }, log);
6982
6921
  log(`[realtime] Injected kanban-work trigger for '${agent.codeName}': "${item.title}"`);
6983
6922
  } else {
6984
- fireClaudeWorkTrigger(agent.codeName, agent.agentId, boardItems);
6985
- log(`[realtime] Fired kanban-work for '${agent.codeName}': "${item.title}"`);
6923
+ log(`[realtime] Work trigger skipped for '${agent.codeName}' \u2014 session not yet healthy; hybrid will pick up "${item.title}"`);
6986
6924
  }
6987
6925
  }
6988
6926
  },
@@ -7221,13 +7159,8 @@ var KANBAN_WORK_TEMPLATES = /* @__PURE__ */ new Set(["kanban-work"]);
7221
7159
  function isPlainScheduledTemplate(templateId) {
7222
7160
  return !STANDUP_TEMPLATES.has(templateId) && !TASK_UPDATE_TEMPLATES.has(templateId) && !PLAN_TEMPLATES.has(templateId) && !KANBAN_WORK_TEMPLATES.has(templateId);
7223
7161
  }
7224
- function isKanbanWorkCronDisabled() {
7225
- const v = process.env["AGT_DISABLE_KANBAN_WORK_CRON"];
7226
- return v === "1" || v?.toLowerCase() === "true";
7227
- }
7228
7162
  function isKanbanHybridEnabled() {
7229
- const v = process.env["AGT_KANBAN_HYBRID"];
7230
- return v === "1" || v?.toLowerCase() === "true";
7163
+ return true;
7231
7164
  }
7232
7165
  function isKanbanHybridDryRun() {
7233
7166
  const v = process.env["AGT_KANBAN_HYBRID_DRY_RUN"];
@@ -7302,18 +7235,7 @@ ${formatRunMarker(run_id)}` : KANBAN_CHECK_COMMAND;
7302
7235
  log(`[manager-worker] kanban inject failed for '${codeName}'`);
7303
7236
  }
7304
7237
  }
7305
- function warnOnConflictingKanbanModes() {
7306
- if (!isKanbanHybridEnabled()) return;
7307
- const cronOff = isKanbanWorkCronDisabled();
7308
- const loopOff = isKanbanLoopDisabled();
7309
- if (!cronOff || !loopOff) {
7310
- const stillOn = !cronOff && !loopOff ? "AGT_DISABLE_KANBAN_WORK_CRON and AGT_DISABLE_KANBAN_LOOP are" : !cronOff ? "AGT_DISABLE_KANBAN_WORK_CRON is" : "AGT_DISABLE_KANBAN_LOOP is";
7311
- log(
7312
- `[manager-worker] WARN AGT_KANBAN_HYBRID=1 but ${stillOn} not set \u2014 kanban-work will fire from MULTIPLE sources (doubles token spend). Set both predecessors to 1 for clean hybrid mode.`
7313
- );
7314
- }
7315
- }
7316
- var BOARD_INJECT_TEMPLATES = /* @__PURE__ */ new Set(["morning-plan", "task-update", "hourly-status", "end-of-day-summary", "kanban-work"]);
7238
+ var BOARD_INJECT_TEMPLATES = /* @__PURE__ */ new Set(["morning-plan", "task-update", "hourly-status", "end-of-day-summary"]);
7317
7239
  var ACTIONABLE_STATUSES = /* @__PURE__ */ new Set(["todo", "in_progress"]);
7318
7240
  function hasActionableItems(items) {
7319
7241
  return items.some((item) => ACTIONABLE_STATUSES.has(item.status));
@@ -7322,6 +7244,7 @@ var lastHarvestAt = /* @__PURE__ */ new Map();
7322
7244
  var HARVEST_INTERVAL_MS = 3 * 60 * 1e3;
7323
7245
  var kanbanBoardCache = /* @__PURE__ */ new Map();
7324
7246
  var notifyBoardCache = /* @__PURE__ */ new Map();
7247
+ var NOTIFY_RESULT_MAX_CHARS = 3500;
7325
7248
  async function harvestCronResults(codeName, tasks, gatewayPort) {
7326
7249
  const token = readGatewayToken(codeName);
7327
7250
  const gwArgs = ["--url", `ws://127.0.0.1:${gatewayPort}`, ...token ? ["--token", token] : []];
@@ -8151,7 +8074,7 @@ async function processClaudePairSessions(agents) {
8151
8074
  killPairSession,
8152
8075
  pairTmuxSession,
8153
8076
  finalizeClaudePairOnboarding
8154
- } = await import("../claude-pair-runtime-Q5CZLM2R.js");
8077
+ } = await import("../claude-pair-runtime-A35NZYDN.js");
8155
8078
  for (const pairId of pendingResp.cancelled_pair_ids ?? []) {
8156
8079
  log(`[claude-pair] sweeping orphan tmux session for pair ${pairId.slice(0, 8)}`);
8157
8080
  const killed = await killPairSession(pairTmuxSession(pairId));
@@ -8270,6 +8193,24 @@ async function maybePostScheduledTaskRatingPrompt(agentId, taskId, channelId, me
8270
8193
  log(`[rating-prompt] Failed to post rating prompt for ${agentId}/${taskId}: ${err.message}`);
8271
8194
  }
8272
8195
  }
8196
+ async function buildDoneCardNotification(agentId, codeName, displayName, item) {
8197
+ const isFailed = item.status === "failed";
8198
+ let resultBody = item.result ?? "";
8199
+ try {
8200
+ const full = await api.post("/host/kanban-item", {
8201
+ agent_id: agentId,
8202
+ item_id: item.id
8203
+ });
8204
+ if (full.item?.result) resultBody = full.item.result;
8205
+ } catch (err) {
8206
+ log(`[notify] full-result fetch failed for card ${item.id} on '${codeName}': ${err.message} \u2014 using truncated board result`);
8207
+ }
8208
+ const resultLine = resultBody ? `
8209
+ ${isFailed ? "Reason" : "Result"}: ${resultBody.slice(0, NOTIFY_RESULT_MAX_CHARS)}` : "";
8210
+ const emoji = isFailed ? "\u274C" : "\u2705";
8211
+ return `${emoji} ${isFailed ? "Task Failed" : "Task Complete"} \u2014 ${displayName}
8212
+ ${item.title}${resultLine}`;
8213
+ }
8273
8214
  async function sendTaskNotification(agentCodeName, channel, to, text) {
8274
8215
  const tokens = agentChannelTokens.get(agentCodeName);
8275
8216
  if (channel === "slack") {
@@ -8754,7 +8695,6 @@ function startManager(opts) {
8754
8695
  log(
8755
8696
  `[startup] worker pid=${process.pid} ppid=${process.ppid} node=${process.version} log=${join6(homedir4(), ".augmented", "manager.log")}`
8756
8697
  );
8757
- warnOnConflictingKanbanModes();
8758
8698
  deployMcpAssets();
8759
8699
  reapOrphanChannelMcps({ log });
8760
8700
  void ensureHostFrameworkBinaries();
@@ -8922,6 +8862,7 @@ export {
8922
8862
  ChildProcessError,
8923
8863
  __resetScheduledDeliveryDedupeForTest,
8924
8864
  applyRestartAcks,
8865
+ buildDoneCardNotification,
8925
8866
  claudeCodeUpgradeMarkerPath,
8926
8867
  claudeCodeUpgradeThrottled,
8927
8868
  deliverScheduledCardResult,
@@ -8933,7 +8874,6 @@ export {
8933
8874
  isHybridActionable,
8934
8875
  isKanbanHybridDryRun,
8935
8876
  isKanbanHybridEnabled,
8936
- isKanbanWorkCronDisabled,
8937
8877
  isPlainScheduledTemplate,
8938
8878
  isScheduledCardTracked,
8939
8879
  isScheduledViaKanbanEnabled,
@@ -8945,7 +8885,6 @@ export {
8945
8885
  shouldSkipRevokedCleanup,
8946
8886
  stampClaudeCodeUpgradeMarker,
8947
8887
  startManager,
8948
- stopManager,
8949
- warnOnConflictingKanbanModes
8888
+ stopManager
8950
8889
  };
8951
8890
  //# sourceMappingURL=manager-worker.js.map