@integrity-labs/agt-cli 0.24.8 → 0.24.10
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 +4 -4
- package/dist/bin/agt.js.map +1 -1
- package/dist/{chunk-53TCAGCM.js → chunk-7DRLULIO.js} +38 -26
- package/dist/{chunk-53TCAGCM.js.map → chunk-7DRLULIO.js.map} +1 -1
- package/dist/{chunk-TS7W4YNI.js → chunk-HR5T2RQF.js} +8 -2
- package/dist/{chunk-TS7W4YNI.js.map → chunk-HR5T2RQF.js.map} +1 -1
- package/dist/{chunk-3A2PMQM4.js → chunk-IEVHEZV4.js} +11 -7
- package/dist/chunk-IEVHEZV4.js.map +1 -0
- package/dist/{chunk-XW27YIEU.js → chunk-Z25YM6B4.js} +2 -2
- package/dist/{claude-pair-runtime-4F53C7RB.js → claude-pair-runtime-SENCKRI4.js} +2 -2
- package/dist/{claude-scheduler-XHJS2MZV.js → claude-scheduler-EM24LTGV.js} +2 -2
- package/dist/lib/manager-worker.js +255 -20
- package/dist/lib/manager-worker.js.map +1 -1
- package/dist/mcp/slack-channel.js +94 -4
- package/dist/mcp/telegram-channel.js +88 -0
- package/dist/{persistent-session-XJYOPFIP.js → persistent-session-3SNFKR2Q.js} +5 -3
- package/dist/{responsiveness-probe-EWZNGMTX.js → responsiveness-probe-UBNJFMAU.js} +3 -3
- package/package.json +1 -1
- package/dist/chunk-3A2PMQM4.js.map +0 -1
- /package/dist/{chunk-XW27YIEU.js.map → chunk-Z25YM6B4.js.map} +0 -0
- /package/dist/{claude-pair-runtime-4F53C7RB.js.map → claude-pair-runtime-SENCKRI4.js.map} +0 -0
- /package/dist/{claude-scheduler-XHJS2MZV.js.map → claude-scheduler-EM24LTGV.js.map} +0 -0
- /package/dist/{persistent-session-XJYOPFIP.js.map → persistent-session-3SNFKR2Q.js.map} +0 -0
- /package/dist/{responsiveness-probe-EWZNGMTX.js.map → responsiveness-probe-UBNJFMAU.js.map} +0 -0
|
@@ -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-
|
|
16
|
+
} from "../chunk-Z25YM6B4.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-
|
|
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-
|
|
53
|
+
} from "../chunk-IEVHEZV4.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-
|
|
74
|
+
} from "../chunk-7DRLULIO.js";
|
|
72
75
|
|
|
73
76
|
// src/lib/manager-worker.ts
|
|
74
77
|
import { createHash as createHash3 } from "crypto";
|
|
@@ -2411,6 +2414,16 @@ function stopRealtimeIntegrationContext() {
|
|
|
2411
2414
|
function isRealtimeConnected() {
|
|
2412
2415
|
return connected;
|
|
2413
2416
|
}
|
|
2417
|
+
function isRealtimeSocketConnected() {
|
|
2418
|
+
try {
|
|
2419
|
+
return client?.realtime?.isConnected() ?? false;
|
|
2420
|
+
} catch {
|
|
2421
|
+
return false;
|
|
2422
|
+
}
|
|
2423
|
+
}
|
|
2424
|
+
function shouldForcePollFallback(channelConnected, socketConnected) {
|
|
2425
|
+
return channelConnected && !socketConnected;
|
|
2426
|
+
}
|
|
2414
2427
|
function stopRealtimeChat() {
|
|
2415
2428
|
if (tearingDown) return;
|
|
2416
2429
|
tearingDown = true;
|
|
@@ -2695,6 +2708,7 @@ function stopPersistentSessionAndForgetMcpBaseline(codeName, breakerReason) {
|
|
|
2695
2708
|
runningMcpHashes.delete(codeName);
|
|
2696
2709
|
runningMcpServerKeys.delete(codeName);
|
|
2697
2710
|
closeInjectedRunIfOpen(codeName, "cancelled", `session stopped (${breakerReason ?? "deprovision"})`);
|
|
2711
|
+
closeScheduledRunsForCode(codeName, "cancelled", `session stopped (${breakerReason ?? "deprovision"})`);
|
|
2698
2712
|
if (breakerReason) {
|
|
2699
2713
|
recordRestartForBreaker(codeName, breakerReason);
|
|
2700
2714
|
}
|
|
@@ -2838,7 +2852,7 @@ var cachedFrameworkVersion = null;
|
|
|
2838
2852
|
var lastVersionCheckAt = 0;
|
|
2839
2853
|
var VERSION_CHECK_INTERVAL_MS = 5 * 60 * 1e3;
|
|
2840
2854
|
var lastResponsivenessProbeAt = 0;
|
|
2841
|
-
var agtCliVersion = true ? "0.24.
|
|
2855
|
+
var agtCliVersion = true ? "0.24.10" : "dev";
|
|
2842
2856
|
function resolveBrewPath(execFileSync4) {
|
|
2843
2857
|
try {
|
|
2844
2858
|
const out = execFileSync4("which", ["brew"], { timeout: 5e3 }).toString().trim();
|
|
@@ -3797,7 +3811,7 @@ async function pollCycle() {
|
|
|
3797
3811
|
}
|
|
3798
3812
|
try {
|
|
3799
3813
|
const { detectHostSecurity } = await import("../host-security-6PDFG7F5.js");
|
|
3800
|
-
const { collectDiagnostics } = await import("../persistent-session-
|
|
3814
|
+
const { collectDiagnostics } = await import("../persistent-session-3SNFKR2Q.js");
|
|
3801
3815
|
const diagCodeNames = [...persistentSessionAgents];
|
|
3802
3816
|
const agentDiagnostics = diagCodeNames.length > 0 ? collectDiagnostics(diagCodeNames) : void 0;
|
|
3803
3817
|
let tailscaleHostname;
|
|
@@ -3839,7 +3853,14 @@ async function pollCycle() {
|
|
|
3839
3853
|
agent_diagnostics: agentDiagnostics,
|
|
3840
3854
|
hostname: tailscaleHostname,
|
|
3841
3855
|
os_username: osUsername,
|
|
3842
|
-
claude_auth: claudeAuth ?? void 0
|
|
3856
|
+
claude_auth: claudeAuth ?? void 0,
|
|
3857
|
+
// ENG-5614: inbound-loop liveness. The actual phoenix socket state
|
|
3858
|
+
// behind the direct-chat Realtime subscription. When this is false
|
|
3859
|
+
// but the manager keeps heartbeating, inbound is being served by the
|
|
3860
|
+
// polling fallback (healRealtimeSocketDivergence forces it). Surfaced
|
|
3861
|
+
// so a sustained socket-down window is observable rather than hidden
|
|
3862
|
+
// behind a fresh heartbeat.
|
|
3863
|
+
realtime_socket_connected: isRealtimeSocketConnected()
|
|
3843
3864
|
});
|
|
3844
3865
|
} catch (err) {
|
|
3845
3866
|
log(`Heartbeat failed: ${err.message}`);
|
|
@@ -3848,7 +3869,7 @@ async function pollCycle() {
|
|
|
3848
3869
|
const {
|
|
3849
3870
|
collectResponsivenessProbes,
|
|
3850
3871
|
getResponsivenessIntervalMs
|
|
3851
|
-
} = await import("../responsiveness-probe-
|
|
3872
|
+
} = await import("../responsiveness-probe-UBNJFMAU.js");
|
|
3852
3873
|
const probeIntervalMs = getResponsivenessIntervalMs();
|
|
3853
3874
|
if (now - lastResponsivenessProbeAt > probeIntervalMs) {
|
|
3854
3875
|
const probeCodeNames = [...persistentSessionAgents];
|
|
@@ -4062,6 +4083,7 @@ async function pollCycle() {
|
|
|
4062
4083
|
log(`Cron health monitor error: ${err.message}`);
|
|
4063
4084
|
});
|
|
4064
4085
|
}
|
|
4086
|
+
healRealtimeSocketDivergence();
|
|
4065
4087
|
if (!isRealtimeConnected()) {
|
|
4066
4088
|
pollDirectChatMessages(agentStates).catch((err) => {
|
|
4067
4089
|
log(`Direct chat poll error: ${err.message}`);
|
|
@@ -5106,7 +5128,9 @@ async function processAgent(agent, agentStates) {
|
|
|
5106
5128
|
}
|
|
5107
5129
|
const agentFw = agentFrameworkCache.get(agent.code_name) ?? "openclaw";
|
|
5108
5130
|
const sessionMode = refreshData.agent.session_mode ?? "oneshot";
|
|
5109
|
-
|
|
5131
|
+
const wantsHybridInject = isKanbanHybridEnabled();
|
|
5132
|
+
const wantsScheduledReconcile = isScheduledViaKanbanEnabled();
|
|
5133
|
+
if ((wantsHybridInject || wantsScheduledReconcile) && agentFw === "claude-code" && sessionMode === "persistent") {
|
|
5110
5134
|
let hybridBoard = hasBoardTemplates ? boardItems : void 0;
|
|
5111
5135
|
if (!hybridBoard) {
|
|
5112
5136
|
try {
|
|
@@ -5120,13 +5144,14 @@ async function processAgent(agent, agentStates) {
|
|
|
5120
5144
|
hybridBoard = kanbanBoardCache.get(agent.code_name) ?? [];
|
|
5121
5145
|
}
|
|
5122
5146
|
}
|
|
5123
|
-
|
|
5124
|
-
|
|
5125
|
-
|
|
5126
|
-
|
|
5127
|
-
|
|
5128
|
-
|
|
5129
|
-
|
|
5147
|
+
void reconcileScheduledRuns(agent.code_name, agent.agent_id, hybridBoard);
|
|
5148
|
+
if (wantsHybridInject) {
|
|
5149
|
+
if (hasHybridActionableItems(hybridBoard)) {
|
|
5150
|
+
const actionableCount = hybridBoard.filter(isHybridActionable).length;
|
|
5151
|
+
void maybeInjectKanbanCheck(agent.code_name, agent.agent_id, actionableCount);
|
|
5152
|
+
} else {
|
|
5153
|
+
closeInjectedRunIfOpen(agent.code_name, "completed", "kanban board drained");
|
|
5154
|
+
}
|
|
5130
5155
|
}
|
|
5131
5156
|
}
|
|
5132
5157
|
if (agentFw === "claude-code" && sessionMode === "persistent") {
|
|
@@ -5757,6 +5782,157 @@ async function fetchPriorScheduledRuns(agentId, taskId) {
|
|
|
5757
5782
|
return [];
|
|
5758
5783
|
}
|
|
5759
5784
|
}
|
|
5785
|
+
function isScheduledViaKanbanEnabled() {
|
|
5786
|
+
const v = process.env["AGT_SCHEDULED_VIA_KANBAN"];
|
|
5787
|
+
return v === "1" || v?.toLowerCase() === "true";
|
|
5788
|
+
}
|
|
5789
|
+
var scheduledRunsByCode = /* @__PURE__ */ new Map();
|
|
5790
|
+
var claimedScheduledCards = /* @__PURE__ */ new Set();
|
|
5791
|
+
var completedScheduledCards = /* @__PURE__ */ new Set();
|
|
5792
|
+
function claimScheduledCardDelivery(cardId) {
|
|
5793
|
+
if (claimedScheduledCards.has(cardId)) return false;
|
|
5794
|
+
claimedScheduledCards.add(cardId);
|
|
5795
|
+
return true;
|
|
5796
|
+
}
|
|
5797
|
+
function releaseScheduledCardDelivery(cardId) {
|
|
5798
|
+
claimedScheduledCards.delete(cardId);
|
|
5799
|
+
}
|
|
5800
|
+
function markScheduledCardDeliveryComplete(cardId) {
|
|
5801
|
+
completedScheduledCards.add(cardId);
|
|
5802
|
+
}
|
|
5803
|
+
function __resetScheduledDeliveryDedupeForTest() {
|
|
5804
|
+
claimedScheduledCards.clear();
|
|
5805
|
+
completedScheduledCards.clear();
|
|
5806
|
+
}
|
|
5807
|
+
function trackScheduledRun(codeName, cardId, runId) {
|
|
5808
|
+
let m = scheduledRunsByCode.get(codeName);
|
|
5809
|
+
if (!m) {
|
|
5810
|
+
m = /* @__PURE__ */ new Map();
|
|
5811
|
+
scheduledRunsByCode.set(codeName, m);
|
|
5812
|
+
}
|
|
5813
|
+
m.set(cardId, runId);
|
|
5814
|
+
}
|
|
5815
|
+
function isScheduledCardTracked(cardId) {
|
|
5816
|
+
for (const m of scheduledRunsByCode.values()) {
|
|
5817
|
+
if (m.has(cardId)) return true;
|
|
5818
|
+
}
|
|
5819
|
+
return false;
|
|
5820
|
+
}
|
|
5821
|
+
function closeScheduledRunsForCode(codeName, outcome, reason) {
|
|
5822
|
+
const m = scheduledRunsByCode.get(codeName);
|
|
5823
|
+
if (!m || m.size === 0) return;
|
|
5824
|
+
scheduledRunsByCode.delete(codeName);
|
|
5825
|
+
for (const runId of m.values()) {
|
|
5826
|
+
void finishRun(runId, outcome, { outcomeMessage: reason });
|
|
5827
|
+
}
|
|
5828
|
+
}
|
|
5829
|
+
async function deliverScheduledCardResult(codeName, agentId, cardId) {
|
|
5830
|
+
if (!claimScheduledCardDelivery(cardId)) {
|
|
5831
|
+
return completedScheduledCards.has(cardId) ? "terminal" : "in_flight";
|
|
5832
|
+
}
|
|
5833
|
+
let card;
|
|
5834
|
+
try {
|
|
5835
|
+
const resp = await api.post("/host/kanban-item", {
|
|
5836
|
+
agent_id: agentId,
|
|
5837
|
+
item_id: cardId
|
|
5838
|
+
});
|
|
5839
|
+
card = resp.item;
|
|
5840
|
+
} catch (err) {
|
|
5841
|
+
if (err instanceof ApiError && err.status >= 400 && err.status < 500) {
|
|
5842
|
+
log(`[scheduled-kanban] delivery: card ${cardId} on '${codeName}' fetch returned ${err.status} (${err.message}) \u2014 treating as terminal, not retrying`);
|
|
5843
|
+
markScheduledCardDeliveryComplete(cardId);
|
|
5844
|
+
return "terminal";
|
|
5845
|
+
}
|
|
5846
|
+
releaseScheduledCardDelivery(cardId);
|
|
5847
|
+
log(`[scheduled-kanban] delivery fetch failed for card ${cardId} on '${codeName}': ${err.message} \u2014 will retry`);
|
|
5848
|
+
return "retry";
|
|
5849
|
+
}
|
|
5850
|
+
if (!card || card.status !== "done" || card.source_type !== "scheduled_task" || !card.source_ref) {
|
|
5851
|
+
markScheduledCardDeliveryComplete(cardId);
|
|
5852
|
+
return "terminal";
|
|
5853
|
+
}
|
|
5854
|
+
const state5 = claudeSchedulerStates.get(codeName) ?? loadSchedulerState(codeName);
|
|
5855
|
+
const task = state5.tasks[card.source_ref];
|
|
5856
|
+
if (!task) {
|
|
5857
|
+
log(`[scheduled-kanban] delivery: no scheduler task for source_ref=${card.source_ref} on '${codeName}' \u2014 skipping`);
|
|
5858
|
+
markScheduledCardDeliveryComplete(cardId);
|
|
5859
|
+
return "terminal";
|
|
5860
|
+
}
|
|
5861
|
+
if (!isPlainScheduledTemplate(task.templateId)) {
|
|
5862
|
+
log(`[scheduled-kanban] delivery: card ${cardId} template '${task.templateId}' on '${codeName}' is not a plain scheduled template \u2014 skipping manager delivery`);
|
|
5863
|
+
markScheduledCardDeliveryComplete(cardId);
|
|
5864
|
+
return "terminal";
|
|
5865
|
+
}
|
|
5866
|
+
await processClaudeTaskResult(codeName, agentId, task.templateId, card.result ?? "", {
|
|
5867
|
+
mode: task.deliveryMode,
|
|
5868
|
+
channel: task.deliveryChannel,
|
|
5869
|
+
to: task.deliveryTo,
|
|
5870
|
+
taskId: task.taskId
|
|
5871
|
+
});
|
|
5872
|
+
markScheduledCardDeliveryComplete(cardId);
|
|
5873
|
+
log(`[scheduled-kanban] Delivered result from card ${cardId} (task '${task.name}') for '${codeName}'`);
|
|
5874
|
+
return "delivered";
|
|
5875
|
+
}
|
|
5876
|
+
async function reconcileScheduledRuns(codeName, agentId, board) {
|
|
5877
|
+
const m = scheduledRunsByCode.get(codeName);
|
|
5878
|
+
if (!m || m.size === 0) return;
|
|
5879
|
+
const byId = new Map(board.map((i) => [i.id, i]));
|
|
5880
|
+
for (const [cardId, runId] of [...m.entries()]) {
|
|
5881
|
+
const card = byId.get(cardId);
|
|
5882
|
+
if (!card) continue;
|
|
5883
|
+
if (card.status === "done") {
|
|
5884
|
+
const result = await deliverScheduledCardResult(codeName, agentId, cardId);
|
|
5885
|
+
if (result === "retry" || result === "in_flight") continue;
|
|
5886
|
+
m.delete(cardId);
|
|
5887
|
+
void finishRun(runId, "completed", { outcomeMessage: "scheduled-task card done" });
|
|
5888
|
+
} else if (card.status === "failed") {
|
|
5889
|
+
m.delete(cardId);
|
|
5890
|
+
void finishRun(runId, "failed", { outcomeMessage: "scheduled-task card failed" });
|
|
5891
|
+
}
|
|
5892
|
+
}
|
|
5893
|
+
if (m.size === 0) scheduledRunsByCode.delete(codeName);
|
|
5894
|
+
}
|
|
5895
|
+
async function routeScheduledTaskViaKanban(codeName, agentId, task, prompt) {
|
|
5896
|
+
const { run_id, kanban_item_id } = await startRun({
|
|
5897
|
+
agent_id: agentId,
|
|
5898
|
+
source_type: "scheduled_task",
|
|
5899
|
+
source_ref: task.taskId,
|
|
5900
|
+
metadata: { template_id: task.templateId, name: task.name, via: "kanban-inject" },
|
|
5901
|
+
materialize_kanban: {
|
|
5902
|
+
title: task.name,
|
|
5903
|
+
description: prompt,
|
|
5904
|
+
priority: 2,
|
|
5905
|
+
initial_status: "todo"
|
|
5906
|
+
}
|
|
5907
|
+
});
|
|
5908
|
+
if (!run_id || !kanban_item_id) {
|
|
5909
|
+
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`);
|
|
5910
|
+
if (run_id) void finishRun(run_id, "failed", { outcomeMessage: "kanban materialise incomplete", completeKanbanItemId: kanban_item_id });
|
|
5911
|
+
return false;
|
|
5912
|
+
}
|
|
5913
|
+
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.
|
|
5914
|
+
` + formatRunMarker(run_id);
|
|
5915
|
+
let injectStatus;
|
|
5916
|
+
try {
|
|
5917
|
+
injectStatus = await injectMessageWithStatus(codeName, "task", nudge, { task_name: "scheduled-task" }, log);
|
|
5918
|
+
} catch (err) {
|
|
5919
|
+
log(`[scheduled-kanban] nudge injection threw for task '${task.name}' on '${codeName}': ${err.message} \u2014 closing card + falling back to claude -p`);
|
|
5920
|
+
void finishRun(run_id, "failed", { outcomeMessage: "scheduled-task nudge delivery threw", completeKanbanItemId: kanban_item_id });
|
|
5921
|
+
return false;
|
|
5922
|
+
}
|
|
5923
|
+
const { delivered, fallbackUsed } = injectStatus;
|
|
5924
|
+
if (!delivered && !fallbackUsed) {
|
|
5925
|
+
log(`[scheduled-kanban] nudge delivery failed for task '${task.name}' on '${codeName}' \u2014 closing card + falling back to claude -p`);
|
|
5926
|
+
void finishRun(run_id, "failed", { outcomeMessage: "scheduled-task nudge delivery failed", completeKanbanItemId: kanban_item_id });
|
|
5927
|
+
return false;
|
|
5928
|
+
}
|
|
5929
|
+
if (!delivered && fallbackUsed) {
|
|
5930
|
+
log(`[scheduled-kanban] nudge sent via send-keys (unverified) for task '${task.name}' on '${codeName}' \u2014 proceeding without oneshot fallback`);
|
|
5931
|
+
}
|
|
5932
|
+
trackScheduledRun(codeName, kanban_item_id, run_id);
|
|
5933
|
+
log(`[scheduled-kanban] Routed task '${task.name}' for '${codeName}' via todo card ${kanban_item_id} run_id=${run_id}`);
|
|
5934
|
+
return true;
|
|
5935
|
+
}
|
|
5760
5936
|
async function executeAndProcessClaudeTask(codeName, agentId, task, prompt) {
|
|
5761
5937
|
const projectDir = getProjectDir2(codeName);
|
|
5762
5938
|
const mcpConfigPath = join6(projectDir, ".mcp.json");
|
|
@@ -6264,6 +6440,31 @@ ${truncateForLog(ctx.tail)}` : `; pane_tail_hash=sha256:${createHash3("sha256").
|
|
|
6264
6440
|
}
|
|
6265
6441
|
inFlightClaudeTasks.add(task.taskId);
|
|
6266
6442
|
claudeTaskConcurrency.set(codeName, (claudeTaskConcurrency.get(codeName) ?? 0) + 1);
|
|
6443
|
+
if (isScheduledViaKanbanEnabled() && isPlainScheduledTemplate(task.templateId)) {
|
|
6444
|
+
let routed = false;
|
|
6445
|
+
try {
|
|
6446
|
+
routed = await routeScheduledTaskViaKanban(codeName, agent.agent_id, task, prompt);
|
|
6447
|
+
} catch (err) {
|
|
6448
|
+
log(`[scheduled-kanban] route threw for '${task.name}' on '${codeName}': ${err.message}`);
|
|
6449
|
+
routed = false;
|
|
6450
|
+
}
|
|
6451
|
+
if (routed) {
|
|
6452
|
+
try {
|
|
6453
|
+
const updated = markTaskFired(codeName, task.taskId, "ok");
|
|
6454
|
+
claudeSchedulerStates.set(codeName, updated);
|
|
6455
|
+
} catch (err) {
|
|
6456
|
+
log(`[scheduled-kanban] markTaskFired failed for '${task.name}' on '${codeName}': ${err.message}`);
|
|
6457
|
+
}
|
|
6458
|
+
if (task.scheduleKind === "at") {
|
|
6459
|
+
api.post("/host/schedules/disable", { agent_id: agent.agent_id, task_id: task.taskId }).catch(
|
|
6460
|
+
(err) => log(`[scheduled-kanban] Failed to disable one-off task '${task.name}': ${err.message}`)
|
|
6461
|
+
);
|
|
6462
|
+
}
|
|
6463
|
+
inFlightClaudeTasks.delete(task.taskId);
|
|
6464
|
+
claudeTaskConcurrency.set(codeName, Math.max(0, (claudeTaskConcurrency.get(codeName) ?? 1) - 1));
|
|
6465
|
+
break;
|
|
6466
|
+
}
|
|
6467
|
+
}
|
|
6267
6468
|
log(`[persistent-session] Firing task '${task.name}' for '${codeName}' via claude -p`);
|
|
6268
6469
|
executeAndProcessClaudeTask(codeName, agent.agent_id, task, prompt).catch(() => {
|
|
6269
6470
|
}).finally(() => {
|
|
@@ -6287,6 +6488,18 @@ var subscribedIntegrationContextAgentIds = /* @__PURE__ */ new Set();
|
|
|
6287
6488
|
var realtimeAssignStarted = false;
|
|
6288
6489
|
var realtimeConfigStarted = false;
|
|
6289
6490
|
var realtimeSubscribedAgentIds = /* @__PURE__ */ new Set();
|
|
6491
|
+
function healRealtimeSocketDivergence() {
|
|
6492
|
+
if (!shouldForcePollFallback(isRealtimeConnected(), isRealtimeSocketConnected())) return false;
|
|
6493
|
+
log("[realtime] Socket divergence \u2014 channel flag connected but socket dead; forcing poll fallback + reconnect");
|
|
6494
|
+
stopRealtimeChat();
|
|
6495
|
+
realtimeStarted = false;
|
|
6496
|
+
realtimeDriftStarted = false;
|
|
6497
|
+
realtimeAssignStarted = false;
|
|
6498
|
+
realtimeConfigStarted = false;
|
|
6499
|
+
realtimeKanbanStarted = false;
|
|
6500
|
+
subscribedIntegrationContextAgentIds = /* @__PURE__ */ new Set();
|
|
6501
|
+
return true;
|
|
6502
|
+
}
|
|
6290
6503
|
function ensureRealtimeStarted(agentStates) {
|
|
6291
6504
|
const currentActiveIds = new Set(
|
|
6292
6505
|
agentStates.filter((a) => a.status === "active").map((a) => a.agentId)
|
|
@@ -6447,6 +6660,7 @@ function ensureRealtimeKanbanStarted(agentStates) {
|
|
|
6447
6660
|
token: exchange.token,
|
|
6448
6661
|
agentIds: activeAgentIds,
|
|
6449
6662
|
onTodayItem: (item) => {
|
|
6663
|
+
if (item.source_type === "scheduled_task") return;
|
|
6450
6664
|
const agent = agentStates.find((a) => a.agentId === item.agent_id);
|
|
6451
6665
|
if (!agent) return;
|
|
6452
6666
|
const agentFw = agentFrameworkCache.get(agent.codeName) ?? "openclaw";
|
|
@@ -6474,6 +6688,9 @@ function ensureRealtimeKanbanStarted(agentStates) {
|
|
|
6474
6688
|
log(
|
|
6475
6689
|
`[realtime] Kanban completion forwarded for '${codeName}': item=${event.item_id} status=${event.status} actor=${event.last_actor_id ?? "unknown"}`
|
|
6476
6690
|
);
|
|
6691
|
+
if (event.status === "done" && (isScheduledViaKanbanEnabled() || isKanbanHybridEnabled()) && classifyActor(event.last_actor_id, event.agent_id) === "user" && isScheduledCardTracked(event.item_id)) {
|
|
6692
|
+
void deliverScheduledCardResult(codeName, event.agent_id, event.item_id);
|
|
6693
|
+
}
|
|
6477
6694
|
},
|
|
6478
6695
|
log
|
|
6479
6696
|
});
|
|
@@ -6598,7 +6815,7 @@ ${escapeXml(msg.content)}
|
|
|
6598
6815
|
try {
|
|
6599
6816
|
let reply;
|
|
6600
6817
|
if (fw === "claude-code") {
|
|
6601
|
-
const { getProjectDir: ccProjectDir } = await import("../claude-scheduler-
|
|
6818
|
+
const { getProjectDir: ccProjectDir } = await import("../claude-scheduler-EM24LTGV.js");
|
|
6602
6819
|
const projDir = ccProjectDir(agent.codeName);
|
|
6603
6820
|
const mcpConfigPath = join6(projDir, ".mcp.json");
|
|
6604
6821
|
const serverNames = [];
|
|
@@ -6692,6 +6909,9 @@ var STANDUP_TEMPLATES = /* @__PURE__ */ new Set(["daily-standup", "end-of-day-su
|
|
|
6692
6909
|
var TASK_UPDATE_TEMPLATES = /* @__PURE__ */ new Set(["hourly-status", "task-update"]);
|
|
6693
6910
|
var PLAN_TEMPLATES = /* @__PURE__ */ new Set(["morning-plan"]);
|
|
6694
6911
|
var KANBAN_WORK_TEMPLATES = /* @__PURE__ */ new Set(["kanban-work"]);
|
|
6912
|
+
function isPlainScheduledTemplate(templateId) {
|
|
6913
|
+
return !STANDUP_TEMPLATES.has(templateId) && !TASK_UPDATE_TEMPLATES.has(templateId) && !PLAN_TEMPLATES.has(templateId) && !KANBAN_WORK_TEMPLATES.has(templateId);
|
|
6914
|
+
}
|
|
6695
6915
|
function isKanbanWorkCronDisabled() {
|
|
6696
6916
|
const v = process.env["AGT_DISABLE_KANBAN_WORK_CRON"];
|
|
6697
6917
|
return v === "1" || v?.toLowerCase() === "true";
|
|
@@ -6705,8 +6925,11 @@ function isKanbanHybridDryRun() {
|
|
|
6705
6925
|
return v === "1" || v?.toLowerCase() === "true";
|
|
6706
6926
|
}
|
|
6707
6927
|
var HYBRID_ACTIONABLE_STATUSES = /* @__PURE__ */ new Set(["todo", "in_progress"]);
|
|
6928
|
+
function isHybridActionable(item) {
|
|
6929
|
+
return HYBRID_ACTIONABLE_STATUSES.has(item.status) && item.source_type !== "scheduled_task";
|
|
6930
|
+
}
|
|
6708
6931
|
function hasHybridActionableItems(items) {
|
|
6709
|
-
return items.some(
|
|
6932
|
+
return items.some(isHybridActionable);
|
|
6710
6933
|
}
|
|
6711
6934
|
var lastKanbanInjectAt = /* @__PURE__ */ new Map();
|
|
6712
6935
|
var openInjectedRunByCode = /* @__PURE__ */ new Map();
|
|
@@ -6782,7 +7005,7 @@ function warnOnConflictingKanbanModes() {
|
|
|
6782
7005
|
}
|
|
6783
7006
|
}
|
|
6784
7007
|
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(["
|
|
7008
|
+
var ACTIONABLE_STATUSES = /* @__PURE__ */ new Set(["todo", "in_progress"]);
|
|
6786
7009
|
function hasActionableItems(items) {
|
|
6787
7010
|
return items.some((item) => ACTIONABLE_STATUSES.has(item.status));
|
|
6788
7011
|
}
|
|
@@ -7619,7 +7842,7 @@ async function processClaudePairSessions(agents) {
|
|
|
7619
7842
|
killPairSession,
|
|
7620
7843
|
pairTmuxSession,
|
|
7621
7844
|
finalizeClaudePairOnboarding
|
|
7622
|
-
} = await import("../claude-pair-runtime-
|
|
7845
|
+
} = await import("../claude-pair-runtime-SENCKRI4.js");
|
|
7623
7846
|
for (const pairId of pendingResp.cancelled_pair_ids ?? []) {
|
|
7624
7847
|
log(`[claude-pair] sweeping orphan tmux session for pair ${pairId.slice(0, 8)}`);
|
|
7625
7848
|
const killed = await killPairSession(pairTmuxSession(pairId));
|
|
@@ -8188,6 +8411,9 @@ async function stopPolling(opts = {}) {
|
|
|
8188
8411
|
stopCaffeinate();
|
|
8189
8412
|
stopRealtimeChat();
|
|
8190
8413
|
stopGatewayPool();
|
|
8414
|
+
for (const codeName of [...scheduledRunsByCode.keys()]) {
|
|
8415
|
+
closeScheduledRunsForCode(codeName, "cancelled", "manager shutdown");
|
|
8416
|
+
}
|
|
8191
8417
|
log("Killing tmux sessions...");
|
|
8192
8418
|
await killAllAgtTmuxSessions();
|
|
8193
8419
|
log("Stopping persistent sessions...");
|
|
@@ -8385,19 +8611,28 @@ process.on("disconnect", () => {
|
|
|
8385
8611
|
});
|
|
8386
8612
|
export {
|
|
8387
8613
|
ChildProcessError,
|
|
8614
|
+
__resetScheduledDeliveryDedupeForTest,
|
|
8388
8615
|
applyRestartAcks,
|
|
8389
8616
|
claudeCodeUpgradeMarkerPath,
|
|
8390
8617
|
claudeCodeUpgradeThrottled,
|
|
8618
|
+
deliverScheduledCardResult,
|
|
8391
8619
|
extractCharterSlackPeers,
|
|
8392
8620
|
extractCharterTelegramPeers,
|
|
8621
|
+
hasActionableItems,
|
|
8393
8622
|
hasHybridActionableItems,
|
|
8394
8623
|
hasRevokedResiduals,
|
|
8624
|
+
isHybridActionable,
|
|
8395
8625
|
isKanbanHybridDryRun,
|
|
8396
8626
|
isKanbanHybridEnabled,
|
|
8397
8627
|
isKanbanWorkCronDisabled,
|
|
8628
|
+
isPlainScheduledTemplate,
|
|
8629
|
+
isScheduledCardTracked,
|
|
8630
|
+
isScheduledViaKanbanEnabled,
|
|
8398
8631
|
markAgentForFreshMemorySync,
|
|
8399
8632
|
maybeInjectKanbanCheck,
|
|
8400
8633
|
maybeUpgradeClaudeCode,
|
|
8634
|
+
reconcileScheduledRuns,
|
|
8635
|
+
routeScheduledTaskViaKanban,
|
|
8401
8636
|
shouldSkipRevokedCleanup,
|
|
8402
8637
|
stampClaudeCodeUpgradeMarker,
|
|
8403
8638
|
startManager,
|