@integrity-labs/agt-cli 0.24.7 → 0.24.9

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.
@@ -1,4 +1,5 @@
1
1
  import {
2
+ ApiError,
2
3
  SUPERVISOR_RESTART_EXIT_CODE,
3
4
  api,
4
5
  estimateActiveTasksTokens,
@@ -12,7 +13,7 @@ import {
12
13
  provisionOrientHook,
13
14
  provisionStopHook,
14
15
  requireHost
15
- } from "../chunk-FK6BJWEC.js";
16
+ } from "../chunk-67PAZ3I4.js";
16
17
  import {
17
18
  findTaskByTemplate,
18
19
  getProjectDir as getProjectDir2,
@@ -20,7 +21,7 @@ import {
20
21
  loadSchedulerState,
21
22
  markTaskFired,
22
23
  syncTasksToScheduler
23
- } from "../chunk-TS7W4YNI.js";
24
+ } from "../chunk-HR5T2RQF.js";
24
25
  import {
25
26
  buildAllowedTools,
26
27
  ensureKanbanLoopArmed,
@@ -28,6 +29,7 @@ import {
28
29
  getProjectDir,
29
30
  getSessionState,
30
31
  injectMessage,
32
+ injectMessageWithStatus,
31
33
  isAgentIdle,
32
34
  isAgentPromptReady,
33
35
  isKanbanLoopArmedForCurrentSession,
@@ -48,11 +50,12 @@ import {
48
50
  stopAllSessionsAndWait,
49
51
  stopPersistentSession,
50
52
  takeZombieDetection
51
- } from "../chunk-3A2PMQM4.js";
53
+ } from "../chunk-S262PDVS.js";
52
54
  import {
53
55
  KANBAN_CHECK_COMMAND,
54
56
  appendDmFooter,
55
57
  attributeTranscriptUsageByRun,
58
+ classifyActor,
56
59
  classifyOutput,
57
60
  extractFrontmatter,
58
61
  formatActorId,
@@ -68,7 +71,7 @@ import {
68
71
  resolveChannels,
69
72
  resolveDmTarget,
70
73
  wrapScheduledTaskPrompt
71
- } from "../chunk-53TCAGCM.js";
74
+ } from "../chunk-354Z63L7.js";
72
75
 
73
76
  // src/lib/manager-worker.ts
74
77
  import { createHash as createHash3 } from "crypto";
@@ -2695,6 +2698,7 @@ function stopPersistentSessionAndForgetMcpBaseline(codeName, breakerReason) {
2695
2698
  runningMcpHashes.delete(codeName);
2696
2699
  runningMcpServerKeys.delete(codeName);
2697
2700
  closeInjectedRunIfOpen(codeName, "cancelled", `session stopped (${breakerReason ?? "deprovision"})`);
2701
+ closeScheduledRunsForCode(codeName, "cancelled", `session stopped (${breakerReason ?? "deprovision"})`);
2698
2702
  if (breakerReason) {
2699
2703
  recordRestartForBreaker(codeName, breakerReason);
2700
2704
  }
@@ -2838,7 +2842,7 @@ var cachedFrameworkVersion = null;
2838
2842
  var lastVersionCheckAt = 0;
2839
2843
  var VERSION_CHECK_INTERVAL_MS = 5 * 60 * 1e3;
2840
2844
  var lastResponsivenessProbeAt = 0;
2841
- var agtCliVersion = true ? "0.24.7" : "dev";
2845
+ var agtCliVersion = true ? "0.24.9" : "dev";
2842
2846
  function resolveBrewPath(execFileSync4) {
2843
2847
  try {
2844
2848
  const out = execFileSync4("which", ["brew"], { timeout: 5e3 }).toString().trim();
@@ -3797,7 +3801,7 @@ async function pollCycle() {
3797
3801
  }
3798
3802
  try {
3799
3803
  const { detectHostSecurity } = await import("../host-security-6PDFG7F5.js");
3800
- const { collectDiagnostics } = await import("../persistent-session-XJYOPFIP.js");
3804
+ const { collectDiagnostics } = await import("../persistent-session-OYO4DTPL.js");
3801
3805
  const diagCodeNames = [...persistentSessionAgents];
3802
3806
  const agentDiagnostics = diagCodeNames.length > 0 ? collectDiagnostics(diagCodeNames) : void 0;
3803
3807
  let tailscaleHostname;
@@ -3848,7 +3852,7 @@ async function pollCycle() {
3848
3852
  const {
3849
3853
  collectResponsivenessProbes,
3850
3854
  getResponsivenessIntervalMs
3851
- } = await import("../responsiveness-probe-EWZNGMTX.js");
3855
+ } = await import("../responsiveness-probe-SSFKGL7Q.js");
3852
3856
  const probeIntervalMs = getResponsivenessIntervalMs();
3853
3857
  if (now - lastResponsivenessProbeAt > probeIntervalMs) {
3854
3858
  const probeCodeNames = [...persistentSessionAgents];
@@ -5106,7 +5110,9 @@ async function processAgent(agent, agentStates) {
5106
5110
  }
5107
5111
  const agentFw = agentFrameworkCache.get(agent.code_name) ?? "openclaw";
5108
5112
  const sessionMode = refreshData.agent.session_mode ?? "oneshot";
5109
- if (isKanbanHybridEnabled() && agentFw === "claude-code" && sessionMode === "persistent") {
5113
+ const wantsHybridInject = isKanbanHybridEnabled();
5114
+ const wantsScheduledReconcile = isScheduledViaKanbanEnabled();
5115
+ if ((wantsHybridInject || wantsScheduledReconcile) && agentFw === "claude-code" && sessionMode === "persistent") {
5110
5116
  let hybridBoard = hasBoardTemplates ? boardItems : void 0;
5111
5117
  if (!hybridBoard) {
5112
5118
  try {
@@ -5120,13 +5126,14 @@ async function processAgent(agent, agentStates) {
5120
5126
  hybridBoard = kanbanBoardCache.get(agent.code_name) ?? [];
5121
5127
  }
5122
5128
  }
5123
- if (hasHybridActionableItems(hybridBoard)) {
5124
- const actionableCount = hybridBoard.filter(
5125
- (i) => HYBRID_ACTIONABLE_STATUSES.has(i.status)
5126
- ).length;
5127
- void maybeInjectKanbanCheck(agent.code_name, agent.agent_id, actionableCount);
5128
- } else {
5129
- closeInjectedRunIfOpen(agent.code_name, "completed", "kanban board drained");
5129
+ void reconcileScheduledRuns(agent.code_name, agent.agent_id, hybridBoard);
5130
+ if (wantsHybridInject) {
5131
+ if (hasHybridActionableItems(hybridBoard)) {
5132
+ const actionableCount = hybridBoard.filter(isHybridActionable).length;
5133
+ void maybeInjectKanbanCheck(agent.code_name, agent.agent_id, actionableCount);
5134
+ } else {
5135
+ closeInjectedRunIfOpen(agent.code_name, "completed", "kanban board drained");
5136
+ }
5130
5137
  }
5131
5138
  }
5132
5139
  if (agentFw === "claude-code" && sessionMode === "persistent") {
@@ -5757,6 +5764,157 @@ async function fetchPriorScheduledRuns(agentId, taskId) {
5757
5764
  return [];
5758
5765
  }
5759
5766
  }
5767
+ function isScheduledViaKanbanEnabled() {
5768
+ const v = process.env["AGT_SCHEDULED_VIA_KANBAN"];
5769
+ return v === "1" || v?.toLowerCase() === "true";
5770
+ }
5771
+ var scheduledRunsByCode = /* @__PURE__ */ new Map();
5772
+ var claimedScheduledCards = /* @__PURE__ */ new Set();
5773
+ var completedScheduledCards = /* @__PURE__ */ new Set();
5774
+ function claimScheduledCardDelivery(cardId) {
5775
+ if (claimedScheduledCards.has(cardId)) return false;
5776
+ claimedScheduledCards.add(cardId);
5777
+ return true;
5778
+ }
5779
+ function releaseScheduledCardDelivery(cardId) {
5780
+ claimedScheduledCards.delete(cardId);
5781
+ }
5782
+ function markScheduledCardDeliveryComplete(cardId) {
5783
+ completedScheduledCards.add(cardId);
5784
+ }
5785
+ function __resetScheduledDeliveryDedupeForTest() {
5786
+ claimedScheduledCards.clear();
5787
+ completedScheduledCards.clear();
5788
+ }
5789
+ function trackScheduledRun(codeName, cardId, runId) {
5790
+ let m = scheduledRunsByCode.get(codeName);
5791
+ if (!m) {
5792
+ m = /* @__PURE__ */ new Map();
5793
+ scheduledRunsByCode.set(codeName, m);
5794
+ }
5795
+ m.set(cardId, runId);
5796
+ }
5797
+ function isScheduledCardTracked(cardId) {
5798
+ for (const m of scheduledRunsByCode.values()) {
5799
+ if (m.has(cardId)) return true;
5800
+ }
5801
+ return false;
5802
+ }
5803
+ function closeScheduledRunsForCode(codeName, outcome, reason) {
5804
+ const m = scheduledRunsByCode.get(codeName);
5805
+ if (!m || m.size === 0) return;
5806
+ scheduledRunsByCode.delete(codeName);
5807
+ for (const runId of m.values()) {
5808
+ void finishRun(runId, outcome, { outcomeMessage: reason });
5809
+ }
5810
+ }
5811
+ async function deliverScheduledCardResult(codeName, agentId, cardId) {
5812
+ if (!claimScheduledCardDelivery(cardId)) {
5813
+ return completedScheduledCards.has(cardId) ? "terminal" : "in_flight";
5814
+ }
5815
+ let card;
5816
+ try {
5817
+ const resp = await api.post("/host/kanban-item", {
5818
+ agent_id: agentId,
5819
+ item_id: cardId
5820
+ });
5821
+ card = resp.item;
5822
+ } catch (err) {
5823
+ if (err instanceof ApiError && err.status >= 400 && err.status < 500) {
5824
+ log(`[scheduled-kanban] delivery: card ${cardId} on '${codeName}' fetch returned ${err.status} (${err.message}) \u2014 treating as terminal, not retrying`);
5825
+ markScheduledCardDeliveryComplete(cardId);
5826
+ return "terminal";
5827
+ }
5828
+ releaseScheduledCardDelivery(cardId);
5829
+ log(`[scheduled-kanban] delivery fetch failed for card ${cardId} on '${codeName}': ${err.message} \u2014 will retry`);
5830
+ return "retry";
5831
+ }
5832
+ if (!card || card.status !== "done" || card.source_type !== "scheduled_task" || !card.source_ref) {
5833
+ markScheduledCardDeliveryComplete(cardId);
5834
+ return "terminal";
5835
+ }
5836
+ const state5 = claudeSchedulerStates.get(codeName) ?? loadSchedulerState(codeName);
5837
+ const task = state5.tasks[card.source_ref];
5838
+ if (!task) {
5839
+ log(`[scheduled-kanban] delivery: no scheduler task for source_ref=${card.source_ref} on '${codeName}' \u2014 skipping`);
5840
+ markScheduledCardDeliveryComplete(cardId);
5841
+ return "terminal";
5842
+ }
5843
+ if (!isPlainScheduledTemplate(task.templateId)) {
5844
+ log(`[scheduled-kanban] delivery: card ${cardId} template '${task.templateId}' on '${codeName}' is not a plain scheduled template \u2014 skipping manager delivery`);
5845
+ markScheduledCardDeliveryComplete(cardId);
5846
+ return "terminal";
5847
+ }
5848
+ await processClaudeTaskResult(codeName, agentId, task.templateId, card.result ?? "", {
5849
+ mode: task.deliveryMode,
5850
+ channel: task.deliveryChannel,
5851
+ to: task.deliveryTo,
5852
+ taskId: task.taskId
5853
+ });
5854
+ markScheduledCardDeliveryComplete(cardId);
5855
+ log(`[scheduled-kanban] Delivered result from card ${cardId} (task '${task.name}') for '${codeName}'`);
5856
+ return "delivered";
5857
+ }
5858
+ async function reconcileScheduledRuns(codeName, agentId, board) {
5859
+ const m = scheduledRunsByCode.get(codeName);
5860
+ if (!m || m.size === 0) return;
5861
+ const byId = new Map(board.map((i) => [i.id, i]));
5862
+ for (const [cardId, runId] of [...m.entries()]) {
5863
+ const card = byId.get(cardId);
5864
+ if (!card) continue;
5865
+ if (card.status === "done") {
5866
+ const result = await deliverScheduledCardResult(codeName, agentId, cardId);
5867
+ if (result === "retry" || result === "in_flight") continue;
5868
+ m.delete(cardId);
5869
+ void finishRun(runId, "completed", { outcomeMessage: "scheduled-task card done" });
5870
+ } else if (card.status === "failed") {
5871
+ m.delete(cardId);
5872
+ void finishRun(runId, "failed", { outcomeMessage: "scheduled-task card failed" });
5873
+ }
5874
+ }
5875
+ if (m.size === 0) scheduledRunsByCode.delete(codeName);
5876
+ }
5877
+ async function routeScheduledTaskViaKanban(codeName, agentId, task, prompt) {
5878
+ const { run_id, kanban_item_id } = await startRun({
5879
+ agent_id: agentId,
5880
+ source_type: "scheduled_task",
5881
+ source_ref: task.taskId,
5882
+ metadata: { template_id: task.templateId, name: task.name, via: "kanban-inject" },
5883
+ materialize_kanban: {
5884
+ title: task.name,
5885
+ description: prompt,
5886
+ priority: 2,
5887
+ initial_status: "todo"
5888
+ }
5889
+ });
5890
+ if (!run_id || !kanban_item_id) {
5891
+ log(`[scheduled-kanban] materialise incomplete for task '${task.name}' on '${codeName}' (run_id=${run_id ? "ok" : "null"}, card=${kanban_item_id ? "ok" : "null"}) \u2014 falling back to claude -p`);
5892
+ if (run_id) void finishRun(run_id, "failed", { outcomeMessage: "kanban materialise incomplete", completeKanbanItemId: kanban_item_id });
5893
+ return false;
5894
+ }
5895
+ const nudge = `You have a new scheduled task on your kanban board: id=${kanban_item_id} title=${JSON.stringify(task.name)}. Call kanban_move("${kanban_item_id}", "in_progress"), do the work described on the card, then write the finished result onto the card and mark it done. Do NOT send, post, or message the result to anyone yourself \u2014 recording it on the card is enough; delivery to the recipient is handled for you.
5896
+ ` + formatRunMarker(run_id);
5897
+ let injectStatus;
5898
+ try {
5899
+ injectStatus = await injectMessageWithStatus(codeName, "task", nudge, { task_name: "scheduled-task" }, log);
5900
+ } catch (err) {
5901
+ log(`[scheduled-kanban] nudge injection threw for task '${task.name}' on '${codeName}': ${err.message} \u2014 closing card + falling back to claude -p`);
5902
+ void finishRun(run_id, "failed", { outcomeMessage: "scheduled-task nudge delivery threw", completeKanbanItemId: kanban_item_id });
5903
+ return false;
5904
+ }
5905
+ const { delivered, fallbackUsed } = injectStatus;
5906
+ if (!delivered && !fallbackUsed) {
5907
+ log(`[scheduled-kanban] nudge delivery failed for task '${task.name}' on '${codeName}' \u2014 closing card + falling back to claude -p`);
5908
+ void finishRun(run_id, "failed", { outcomeMessage: "scheduled-task nudge delivery failed", completeKanbanItemId: kanban_item_id });
5909
+ return false;
5910
+ }
5911
+ if (!delivered && fallbackUsed) {
5912
+ log(`[scheduled-kanban] nudge sent via send-keys (unverified) for task '${task.name}' on '${codeName}' \u2014 proceeding without oneshot fallback`);
5913
+ }
5914
+ trackScheduledRun(codeName, kanban_item_id, run_id);
5915
+ log(`[scheduled-kanban] Routed task '${task.name}' for '${codeName}' via todo card ${kanban_item_id} run_id=${run_id}`);
5916
+ return true;
5917
+ }
5760
5918
  async function executeAndProcessClaudeTask(codeName, agentId, task, prompt) {
5761
5919
  const projectDir = getProjectDir2(codeName);
5762
5920
  const mcpConfigPath = join6(projectDir, ".mcp.json");
@@ -6264,6 +6422,31 @@ ${truncateForLog(ctx.tail)}` : `; pane_tail_hash=sha256:${createHash3("sha256").
6264
6422
  }
6265
6423
  inFlightClaudeTasks.add(task.taskId);
6266
6424
  claudeTaskConcurrency.set(codeName, (claudeTaskConcurrency.get(codeName) ?? 0) + 1);
6425
+ if (isScheduledViaKanbanEnabled() && isPlainScheduledTemplate(task.templateId)) {
6426
+ let routed = false;
6427
+ try {
6428
+ routed = await routeScheduledTaskViaKanban(codeName, agent.agent_id, task, prompt);
6429
+ } catch (err) {
6430
+ log(`[scheduled-kanban] route threw for '${task.name}' on '${codeName}': ${err.message}`);
6431
+ routed = false;
6432
+ }
6433
+ if (routed) {
6434
+ try {
6435
+ const updated = markTaskFired(codeName, task.taskId, "ok");
6436
+ claudeSchedulerStates.set(codeName, updated);
6437
+ } catch (err) {
6438
+ log(`[scheduled-kanban] markTaskFired failed for '${task.name}' on '${codeName}': ${err.message}`);
6439
+ }
6440
+ if (task.scheduleKind === "at") {
6441
+ api.post("/host/schedules/disable", { agent_id: agent.agent_id, task_id: task.taskId }).catch(
6442
+ (err) => log(`[scheduled-kanban] Failed to disable one-off task '${task.name}': ${err.message}`)
6443
+ );
6444
+ }
6445
+ inFlightClaudeTasks.delete(task.taskId);
6446
+ claudeTaskConcurrency.set(codeName, Math.max(0, (claudeTaskConcurrency.get(codeName) ?? 1) - 1));
6447
+ break;
6448
+ }
6449
+ }
6267
6450
  log(`[persistent-session] Firing task '${task.name}' for '${codeName}' via claude -p`);
6268
6451
  executeAndProcessClaudeTask(codeName, agent.agent_id, task, prompt).catch(() => {
6269
6452
  }).finally(() => {
@@ -6447,6 +6630,7 @@ function ensureRealtimeKanbanStarted(agentStates) {
6447
6630
  token: exchange.token,
6448
6631
  agentIds: activeAgentIds,
6449
6632
  onTodayItem: (item) => {
6633
+ if (item.source_type === "scheduled_task") return;
6450
6634
  const agent = agentStates.find((a) => a.agentId === item.agent_id);
6451
6635
  if (!agent) return;
6452
6636
  const agentFw = agentFrameworkCache.get(agent.codeName) ?? "openclaw";
@@ -6474,6 +6658,9 @@ function ensureRealtimeKanbanStarted(agentStates) {
6474
6658
  log(
6475
6659
  `[realtime] Kanban completion forwarded for '${codeName}': item=${event.item_id} status=${event.status} actor=${event.last_actor_id ?? "unknown"}`
6476
6660
  );
6661
+ if (event.status === "done" && (isScheduledViaKanbanEnabled() || isKanbanHybridEnabled()) && classifyActor(event.last_actor_id, event.agent_id) === "user" && isScheduledCardTracked(event.item_id)) {
6662
+ void deliverScheduledCardResult(codeName, event.agent_id, event.item_id);
6663
+ }
6477
6664
  },
6478
6665
  log
6479
6666
  });
@@ -6598,7 +6785,7 @@ ${escapeXml(msg.content)}
6598
6785
  try {
6599
6786
  let reply;
6600
6787
  if (fw === "claude-code") {
6601
- const { getProjectDir: ccProjectDir } = await import("../claude-scheduler-XHJS2MZV.js");
6788
+ const { getProjectDir: ccProjectDir } = await import("../claude-scheduler-EM24LTGV.js");
6602
6789
  const projDir = ccProjectDir(agent.codeName);
6603
6790
  const mcpConfigPath = join6(projDir, ".mcp.json");
6604
6791
  const serverNames = [];
@@ -6692,6 +6879,9 @@ var STANDUP_TEMPLATES = /* @__PURE__ */ new Set(["daily-standup", "end-of-day-su
6692
6879
  var TASK_UPDATE_TEMPLATES = /* @__PURE__ */ new Set(["hourly-status", "task-update"]);
6693
6880
  var PLAN_TEMPLATES = /* @__PURE__ */ new Set(["morning-plan"]);
6694
6881
  var KANBAN_WORK_TEMPLATES = /* @__PURE__ */ new Set(["kanban-work"]);
6882
+ function isPlainScheduledTemplate(templateId) {
6883
+ return !STANDUP_TEMPLATES.has(templateId) && !TASK_UPDATE_TEMPLATES.has(templateId) && !PLAN_TEMPLATES.has(templateId) && !KANBAN_WORK_TEMPLATES.has(templateId);
6884
+ }
6695
6885
  function isKanbanWorkCronDisabled() {
6696
6886
  const v = process.env["AGT_DISABLE_KANBAN_WORK_CRON"];
6697
6887
  return v === "1" || v?.toLowerCase() === "true";
@@ -6705,8 +6895,11 @@ function isKanbanHybridDryRun() {
6705
6895
  return v === "1" || v?.toLowerCase() === "true";
6706
6896
  }
6707
6897
  var HYBRID_ACTIONABLE_STATUSES = /* @__PURE__ */ new Set(["todo", "in_progress"]);
6898
+ function isHybridActionable(item) {
6899
+ return HYBRID_ACTIONABLE_STATUSES.has(item.status) && item.source_type !== "scheduled_task";
6900
+ }
6708
6901
  function hasHybridActionableItems(items) {
6709
- return items.some((item) => HYBRID_ACTIONABLE_STATUSES.has(item.status));
6902
+ return items.some(isHybridActionable);
6710
6903
  }
6711
6904
  var lastKanbanInjectAt = /* @__PURE__ */ new Map();
6712
6905
  var openInjectedRunByCode = /* @__PURE__ */ new Map();
@@ -6782,7 +6975,7 @@ function warnOnConflictingKanbanModes() {
6782
6975
  }
6783
6976
  }
6784
6977
  var BOARD_INJECT_TEMPLATES = /* @__PURE__ */ new Set(["morning-plan", "task-update", "hourly-status", "end-of-day-summary", "kanban-work"]);
6785
- var ACTIONABLE_STATUSES = /* @__PURE__ */ new Set(["backlog", "todo", "in_progress"]);
6978
+ var ACTIONABLE_STATUSES = /* @__PURE__ */ new Set(["todo", "in_progress"]);
6786
6979
  function hasActionableItems(items) {
6787
6980
  return items.some((item) => ACTIONABLE_STATUSES.has(item.status));
6788
6981
  }
@@ -7619,7 +7812,7 @@ async function processClaudePairSessions(agents) {
7619
7812
  killPairSession,
7620
7813
  pairTmuxSession,
7621
7814
  finalizeClaudePairOnboarding
7622
- } = await import("../claude-pair-runtime-4F53C7RB.js");
7815
+ } = await import("../claude-pair-runtime-6IB35CES.js");
7623
7816
  for (const pairId of pendingResp.cancelled_pair_ids ?? []) {
7624
7817
  log(`[claude-pair] sweeping orphan tmux session for pair ${pairId.slice(0, 8)}`);
7625
7818
  const killed = await killPairSession(pairTmuxSession(pairId));
@@ -8188,6 +8381,9 @@ async function stopPolling(opts = {}) {
8188
8381
  stopCaffeinate();
8189
8382
  stopRealtimeChat();
8190
8383
  stopGatewayPool();
8384
+ for (const codeName of [...scheduledRunsByCode.keys()]) {
8385
+ closeScheduledRunsForCode(codeName, "cancelled", "manager shutdown");
8386
+ }
8191
8387
  log("Killing tmux sessions...");
8192
8388
  await killAllAgtTmuxSessions();
8193
8389
  log("Stopping persistent sessions...");
@@ -8385,19 +8581,28 @@ process.on("disconnect", () => {
8385
8581
  });
8386
8582
  export {
8387
8583
  ChildProcessError,
8584
+ __resetScheduledDeliveryDedupeForTest,
8388
8585
  applyRestartAcks,
8389
8586
  claudeCodeUpgradeMarkerPath,
8390
8587
  claudeCodeUpgradeThrottled,
8588
+ deliverScheduledCardResult,
8391
8589
  extractCharterSlackPeers,
8392
8590
  extractCharterTelegramPeers,
8591
+ hasActionableItems,
8393
8592
  hasHybridActionableItems,
8394
8593
  hasRevokedResiduals,
8594
+ isHybridActionable,
8395
8595
  isKanbanHybridDryRun,
8396
8596
  isKanbanHybridEnabled,
8397
8597
  isKanbanWorkCronDisabled,
8598
+ isPlainScheduledTemplate,
8599
+ isScheduledCardTracked,
8600
+ isScheduledViaKanbanEnabled,
8398
8601
  markAgentForFreshMemorySync,
8399
8602
  maybeInjectKanbanCheck,
8400
8603
  maybeUpgradeClaudeCode,
8604
+ reconcileScheduledRuns,
8605
+ routeScheduledTaskViaKanban,
8401
8606
  shouldSkipRevokedCleanup,
8402
8607
  stampClaudeCodeUpgradeMarker,
8403
8608
  startManager,