@integrity-labs/agt-cli 0.25.1 → 0.26.0
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/{chunk-4FSQVXWB.js → chunk-LULDCIUS.js} +5 -66
- package/dist/chunk-LULDCIUS.js.map +1 -0
- package/dist/{chunk-AAK2IU2Z.js → chunk-XG4X7BNT.js} +3 -125
- package/dist/chunk-XG4X7BNT.js.map +1 -0
- package/dist/{chunk-4K3ERUGE.js → chunk-YMIDZT5T.js} +335 -5
- package/dist/chunk-YMIDZT5T.js.map +1 -0
- package/dist/{claude-pair-runtime-ZWE5572F.js → claude-pair-runtime-7PHOEAUN.js} +2 -2
- package/dist/lib/manager-worker.js +299 -106
- package/dist/lib/manager-worker.js.map +1 -1
- package/dist/{persistent-session-3FQVLVJM.js → persistent-session-3ITHPO4P.js} +3 -9
- package/dist/{responsiveness-probe-M7PUFD5V.js → responsiveness-probe-7XWORQLO.js} +3 -3
- package/package.json +1 -1
- package/dist/chunk-4FSQVXWB.js.map +0 -1
- package/dist/chunk-4K3ERUGE.js.map +0 -1
- package/dist/chunk-AAK2IU2Z.js.map +0 -1
- /package/dist/{claude-pair-runtime-ZWE5572F.js.map → claude-pair-runtime-7PHOEAUN.js.map} +0 -0
- /package/dist/{persistent-session-3FQVLVJM.js.map → persistent-session-3ITHPO4P.js.map} +0 -0
- /package/dist/{responsiveness-probe-M7PUFD5V.js.map → responsiveness-probe-7XWORQLO.js.map} +0 -0
|
@@ -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-
|
|
103
|
+
const { resolveClaudeBinary } = await import("./persistent-session-3ITHPO4P.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-
|
|
376
|
+
//# sourceMappingURL=claude-pair-runtime-7PHOEAUN.js.map
|
|
@@ -13,9 +13,8 @@ import {
|
|
|
13
13
|
provisionOrientHook,
|
|
14
14
|
provisionStopHook,
|
|
15
15
|
requireHost
|
|
16
|
-
} from "../chunk-
|
|
16
|
+
} from "../chunk-XG4X7BNT.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-
|
|
49
|
+
} from "../chunk-LULDCIUS.js";
|
|
54
50
|
import {
|
|
55
51
|
KANBAN_CHECK_COMMAND,
|
|
56
52
|
appendDmFooter,
|
|
@@ -68,10 +64,12 @@ import {
|
|
|
68
64
|
parseDeliveryTarget,
|
|
69
65
|
parseTranscriptUsage,
|
|
70
66
|
parseUsageBanner,
|
|
67
|
+
probeHttpProvider,
|
|
71
68
|
resolveChannels,
|
|
69
|
+
resolveConnectivityProbe,
|
|
72
70
|
resolveDmTarget,
|
|
73
71
|
wrapScheduledTaskPrompt
|
|
74
|
-
} from "../chunk-
|
|
72
|
+
} from "../chunk-YMIDZT5T.js";
|
|
75
73
|
|
|
76
74
|
// src/lib/manager-worker.ts
|
|
77
75
|
import { createHash as createHash3 } from "crypto";
|
|
@@ -691,6 +689,223 @@ function shouldRespawnForModelChange(input) {
|
|
|
691
689
|
return previousModel !== primaryModel;
|
|
692
690
|
}
|
|
693
691
|
|
|
692
|
+
// src/lib/connectivity-probe-executor.ts
|
|
693
|
+
async function executeConnectivityProbe(target, deps = {}) {
|
|
694
|
+
const descriptor = resolveConnectivityProbe({
|
|
695
|
+
definitionId: target.definitionId,
|
|
696
|
+
sourceType: target.sourceType,
|
|
697
|
+
authType: target.authType
|
|
698
|
+
});
|
|
699
|
+
if (!descriptor.readOnly) {
|
|
700
|
+
throw new Error(`Refusing non-read-only probe for ${target.definitionId}`);
|
|
701
|
+
}
|
|
702
|
+
switch (descriptor.kind) {
|
|
703
|
+
case "http_provider":
|
|
704
|
+
return probeHttpProvider(target.definitionId, target.credentials, deps.fetchImpl ?? fetch);
|
|
705
|
+
case "composio_account":
|
|
706
|
+
if (!deps.composioProbe) return null;
|
|
707
|
+
return deps.composioProbe(target.definitionId, target.credentials);
|
|
708
|
+
case "mcp_tools_list":
|
|
709
|
+
if (!deps.mcpProbe) return null;
|
|
710
|
+
return deps.mcpProbe({
|
|
711
|
+
serverKey: target.mcpServerKey ?? target.definitionId,
|
|
712
|
+
definitionId: target.definitionId
|
|
713
|
+
});
|
|
714
|
+
case "cli_command":
|
|
715
|
+
if (!deps.runCli) return null;
|
|
716
|
+
return deps.runCli(target.cliBinary ?? target.definitionId, descriptor.cliArgs ?? ["--version"]);
|
|
717
|
+
case "builtin":
|
|
718
|
+
return { status: "ok", message: `${target.definitionId}: built-in` };
|
|
719
|
+
case "unsupported":
|
|
720
|
+
default:
|
|
721
|
+
return null;
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
// src/lib/connectivity-probe-runner.ts
|
|
726
|
+
var DEFAULT_INTERVAL_MS = 60 * 60 * 1e3;
|
|
727
|
+
var DEFAULT_MAX_PER_RUN = 25;
|
|
728
|
+
function isDue(lastCheck, now, intervalMs) {
|
|
729
|
+
if (!lastCheck) return true;
|
|
730
|
+
const t = Date.parse(lastCheck);
|
|
731
|
+
if (Number.isNaN(t)) return true;
|
|
732
|
+
return now - t >= intervalMs;
|
|
733
|
+
}
|
|
734
|
+
async function runConnectivityProbes(integrations, options = {}) {
|
|
735
|
+
const now = (options.now?.() ?? /* @__PURE__ */ new Date()).getTime();
|
|
736
|
+
const intervalMs = options.intervalMs ?? DEFAULT_INTERVAL_MS;
|
|
737
|
+
const maxPerRun = options.maxPerRun ?? DEFAULT_MAX_PER_RUN;
|
|
738
|
+
const probeDeps = options.probeDeps ?? {};
|
|
739
|
+
const execute = options.executeProbe ?? executeConnectivityProbe;
|
|
740
|
+
const due = integrations.filter((i) => isDue(i.last_connectivity_check_at, now, intervalMs)).sort((a, b) => {
|
|
741
|
+
const ta = a.last_connectivity_check_at ? Date.parse(a.last_connectivity_check_at) : 0;
|
|
742
|
+
const tb = b.last_connectivity_check_at ? Date.parse(b.last_connectivity_check_at) : 0;
|
|
743
|
+
return ta - tb;
|
|
744
|
+
});
|
|
745
|
+
const batch = due.slice(0, maxPerRun);
|
|
746
|
+
const reports = [];
|
|
747
|
+
let skipped = 0;
|
|
748
|
+
for (const integ of batch) {
|
|
749
|
+
const target = {
|
|
750
|
+
definitionId: integ.definition_id,
|
|
751
|
+
sourceType: integ.source_type ?? null,
|
|
752
|
+
authType: integ.auth_type ?? null,
|
|
753
|
+
credentials: integ.credentials ?? {},
|
|
754
|
+
cliBinary: integ.cli_binary,
|
|
755
|
+
mcpServerKey: integ.mcp_server_key
|
|
756
|
+
};
|
|
757
|
+
let outcome;
|
|
758
|
+
try {
|
|
759
|
+
outcome = await execute(target, probeDeps);
|
|
760
|
+
} catch (err) {
|
|
761
|
+
console.warn(`[connectivity-probe] ${integ.definition_id} threw: ${err.message}`);
|
|
762
|
+
outcome = null;
|
|
763
|
+
}
|
|
764
|
+
if (!outcome) {
|
|
765
|
+
skipped += 1;
|
|
766
|
+
continue;
|
|
767
|
+
}
|
|
768
|
+
reports.push({
|
|
769
|
+
integration_id: integ.id,
|
|
770
|
+
scope: integ.scope,
|
|
771
|
+
status: outcome.status,
|
|
772
|
+
...outcome.message ? { message: outcome.message } : {}
|
|
773
|
+
});
|
|
774
|
+
}
|
|
775
|
+
return { reports, due: due.length, probed: batch.length, skipped };
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
// src/lib/mcp-probe-client.ts
|
|
779
|
+
var MCP_ACCEPT = "application/json, text/event-stream";
|
|
780
|
+
var DEFAULT_TIMEOUT_MS = 1e4;
|
|
781
|
+
async function parseRpc(res, expectedId) {
|
|
782
|
+
const ct = res.headers.get("content-type") ?? "";
|
|
783
|
+
if (ct.includes("text/event-stream")) {
|
|
784
|
+
const text = await res.text();
|
|
785
|
+
let dataLines = [];
|
|
786
|
+
for (const rawLine of text.split(/\r?\n/)) {
|
|
787
|
+
if (rawLine.startsWith("data:")) {
|
|
788
|
+
dataLines.push(rawLine.slice(5).trimStart());
|
|
789
|
+
continue;
|
|
790
|
+
}
|
|
791
|
+
if (rawLine === "" && dataLines.length > 0) {
|
|
792
|
+
try {
|
|
793
|
+
const msg2 = JSON.parse(dataLines.join("\n"));
|
|
794
|
+
if (("result" in msg2 || "error" in msg2) && msg2["id"] === expectedId) return msg2;
|
|
795
|
+
} catch {
|
|
796
|
+
}
|
|
797
|
+
dataLines = [];
|
|
798
|
+
}
|
|
799
|
+
}
|
|
800
|
+
return null;
|
|
801
|
+
}
|
|
802
|
+
const msg = await res.json().catch(() => null);
|
|
803
|
+
if (msg && ("result" in msg || "error" in msg) && msg["id"] === expectedId) return msg;
|
|
804
|
+
return msg;
|
|
805
|
+
}
|
|
806
|
+
function httpStatusOutcome(status, step) {
|
|
807
|
+
if (status === 401 || status === 403) {
|
|
808
|
+
return { status: "down", message: `MCP ${step} unauthorized (${status}) \u2014 reconnect required` };
|
|
809
|
+
}
|
|
810
|
+
if (status >= 500) {
|
|
811
|
+
return { status: "transient_error", message: `MCP ${step} returned ${status}` };
|
|
812
|
+
}
|
|
813
|
+
return { status: "down", message: `MCP ${step} returned ${status}` };
|
|
814
|
+
}
|
|
815
|
+
async function probeMcpHttp(config2, fetchImpl = fetch) {
|
|
816
|
+
const timeoutMs = config2.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
817
|
+
const baseHeaders = {
|
|
818
|
+
...config2.headers ?? {},
|
|
819
|
+
"Content-Type": "application/json",
|
|
820
|
+
Accept: MCP_ACCEPT
|
|
821
|
+
};
|
|
822
|
+
try {
|
|
823
|
+
const initRes = await fetchImpl(config2.url, {
|
|
824
|
+
method: "POST",
|
|
825
|
+
headers: baseHeaders,
|
|
826
|
+
body: JSON.stringify({
|
|
827
|
+
jsonrpc: "2.0",
|
|
828
|
+
id: 1,
|
|
829
|
+
method: "initialize",
|
|
830
|
+
params: {
|
|
831
|
+
protocolVersion: "2025-03-26",
|
|
832
|
+
capabilities: {},
|
|
833
|
+
clientInfo: { name: "augmented-connectivity-probe", version: "1.0.0" }
|
|
834
|
+
}
|
|
835
|
+
}),
|
|
836
|
+
signal: AbortSignal.timeout(timeoutMs)
|
|
837
|
+
});
|
|
838
|
+
if (!initRes.ok) return httpStatusOutcome(initRes.status, "initialize");
|
|
839
|
+
const sessionId = initRes.headers.get("mcp-session-id");
|
|
840
|
+
await parseRpc(initRes, 1);
|
|
841
|
+
const sessionHeaders = { ...baseHeaders, ...sessionId ? { "Mcp-Session-Id": sessionId } : {} };
|
|
842
|
+
const initializedRes = await fetchImpl(config2.url, {
|
|
843
|
+
method: "POST",
|
|
844
|
+
headers: sessionHeaders,
|
|
845
|
+
body: JSON.stringify({ jsonrpc: "2.0", method: "notifications/initialized" }),
|
|
846
|
+
signal: AbortSignal.timeout(5e3)
|
|
847
|
+
});
|
|
848
|
+
if (!initializedRes.ok) return httpStatusOutcome(initializedRes.status, "initialized");
|
|
849
|
+
await initializedRes.text().catch(() => "");
|
|
850
|
+
const listRes = await fetchImpl(config2.url, {
|
|
851
|
+
method: "POST",
|
|
852
|
+
headers: sessionHeaders,
|
|
853
|
+
body: JSON.stringify({ jsonrpc: "2.0", id: 2, method: "tools/list" }),
|
|
854
|
+
signal: AbortSignal.timeout(timeoutMs)
|
|
855
|
+
});
|
|
856
|
+
if (!listRes.ok) return httpStatusOutcome(listRes.status, "tools/list");
|
|
857
|
+
const rpc = await parseRpc(listRes, 2);
|
|
858
|
+
if (rpc && "error" in rpc) {
|
|
859
|
+
const err = rpc["error"];
|
|
860
|
+
return { status: "down", message: `MCP tools/list error: ${err?.message ?? "unknown"}` };
|
|
861
|
+
}
|
|
862
|
+
const result = rpc?.["result"];
|
|
863
|
+
const toolCount = Array.isArray(result?.tools) ? result.tools.length : void 0;
|
|
864
|
+
return {
|
|
865
|
+
status: "ok",
|
|
866
|
+
message: toolCount !== void 0 ? `${toolCount} tools` : "reachable",
|
|
867
|
+
...toolCount !== void 0 ? { details: { toolCount } } : {}
|
|
868
|
+
};
|
|
869
|
+
} catch (err) {
|
|
870
|
+
const isAbort = err?.name === "TimeoutError" || err?.name === "AbortError";
|
|
871
|
+
return {
|
|
872
|
+
status: "transient_error",
|
|
873
|
+
message: isAbort ? `MCP handshake timed out after ${timeoutMs / 1e3}s` : `MCP handshake failed: ${err.message}`
|
|
874
|
+
};
|
|
875
|
+
}
|
|
876
|
+
}
|
|
877
|
+
|
|
878
|
+
// src/lib/cli-probe.ts
|
|
879
|
+
import { execFile } from "child_process";
|
|
880
|
+
var DEFAULT_TIMEOUT_MS2 = 8e3;
|
|
881
|
+
function runCliProbe(binary, args, opts = {}) {
|
|
882
|
+
const timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS2;
|
|
883
|
+
return new Promise((resolve) => {
|
|
884
|
+
execFile(
|
|
885
|
+
binary,
|
|
886
|
+
args,
|
|
887
|
+
{ timeout: timeoutMs, env: opts.env ?? process.env, windowsHide: true },
|
|
888
|
+
(err, stdout) => {
|
|
889
|
+
if (!err) {
|
|
890
|
+
const firstLine = String(stdout).split(/\r?\n/, 1)[0]?.trim();
|
|
891
|
+
resolve({ status: "ok", message: firstLine ? `${binary}: ${firstLine}` : `${binary}: ok` });
|
|
892
|
+
return;
|
|
893
|
+
}
|
|
894
|
+
const e = err;
|
|
895
|
+
if (e.code === "ENOENT") {
|
|
896
|
+
resolve({ status: "down", message: `${binary} not found on PATH (not installed)` });
|
|
897
|
+
return;
|
|
898
|
+
}
|
|
899
|
+
if (e.killed || e.signal === "SIGTERM") {
|
|
900
|
+
resolve({ status: "transient_error", message: `${binary} probe timed out after ${timeoutMs / 1e3}s` });
|
|
901
|
+
return;
|
|
902
|
+
}
|
|
903
|
+
resolve({ status: "down", message: `${binary} exited non-zero: ${e.message}` });
|
|
904
|
+
}
|
|
905
|
+
);
|
|
906
|
+
});
|
|
907
|
+
}
|
|
908
|
+
|
|
694
909
|
// src/lib/usage-banner-monitor.ts
|
|
695
910
|
var MIN_CHECK_INTERVAL_MS = 6e4;
|
|
696
911
|
var PANE_TAIL_LINES_FOR_BANNER = 200;
|
|
@@ -1377,9 +1592,9 @@ var GatewayClientPool = class extends EventEmitter {
|
|
|
1377
1592
|
import { readFile, readdir } from "fs/promises";
|
|
1378
1593
|
import { homedir as homedir2, platform } from "os";
|
|
1379
1594
|
import { join as join3 } from "path";
|
|
1380
|
-
import { execFile } from "child_process";
|
|
1595
|
+
import { execFile as execFile2 } from "child_process";
|
|
1381
1596
|
import { promisify } from "util";
|
|
1382
|
-
var execFileAsync = promisify(
|
|
1597
|
+
var execFileAsync = promisify(execFile2);
|
|
1383
1598
|
var EXPIRING_SOON_MS = 48 * 60 * 60 * 1e3;
|
|
1384
1599
|
async function detectClaudeAuth() {
|
|
1385
1600
|
if (process.env["ANTHROPIC_API_KEY"] || process.env["ANTHROPIC_AUTH_TOKEN"]) {
|
|
@@ -2712,6 +2927,55 @@ function projectMcpKeys(_codeName, projectDir) {
|
|
|
2712
2927
|
return null;
|
|
2713
2928
|
}
|
|
2714
2929
|
}
|
|
2930
|
+
function readMcpHttpServerConfig(projectDir, serverKey) {
|
|
2931
|
+
try {
|
|
2932
|
+
const raw = readFileSync5(join6(projectDir, ".mcp.json"), "utf-8");
|
|
2933
|
+
const servers = JSON.parse(raw).mcpServers ?? {};
|
|
2934
|
+
const entry = servers[serverKey];
|
|
2935
|
+
if (entry && typeof entry.url === "string" && (entry.type === "http" || entry.type === void 0)) {
|
|
2936
|
+
return { url: entry.url, ...entry.headers ? { headers: entry.headers } : {} };
|
|
2937
|
+
}
|
|
2938
|
+
return null;
|
|
2939
|
+
} catch {
|
|
2940
|
+
return null;
|
|
2941
|
+
}
|
|
2942
|
+
}
|
|
2943
|
+
async function runAgentConnectivityProbes(agent, integrations, projectDir) {
|
|
2944
|
+
if (integrations.length === 0) return;
|
|
2945
|
+
const probeDeps = {
|
|
2946
|
+
fetchImpl: fetch,
|
|
2947
|
+
runCli: (binary, args) => runCliProbe(binary, args),
|
|
2948
|
+
mcpProbe: async (target) => {
|
|
2949
|
+
const cfg = readMcpHttpServerConfig(projectDir, target.serverKey);
|
|
2950
|
+
if (!cfg) {
|
|
2951
|
+
return { status: "transient_error", message: `MCP server '${target.serverKey}' not resolvable from .mcp.json` };
|
|
2952
|
+
}
|
|
2953
|
+
return probeMcpHttp(cfg);
|
|
2954
|
+
}
|
|
2955
|
+
};
|
|
2956
|
+
const intervalSec = Number(process.env.AGT_CONNECTIVITY_PROBE_INTERVAL_SECONDS) || 3600;
|
|
2957
|
+
const result = await runConnectivityProbes(
|
|
2958
|
+
integrations.map((i) => ({
|
|
2959
|
+
id: i.id,
|
|
2960
|
+
definition_id: i.definition_id,
|
|
2961
|
+
scope: i.scope,
|
|
2962
|
+
auth_type: i.auth_type,
|
|
2963
|
+
source_type: i.source_type ?? null,
|
|
2964
|
+
credentials: i.credentials,
|
|
2965
|
+
last_connectivity_check_at: i.last_connectivity_check_at ?? null
|
|
2966
|
+
})),
|
|
2967
|
+
{ probeDeps, intervalMs: intervalSec * 1e3 }
|
|
2968
|
+
);
|
|
2969
|
+
if (result.reports.length > 0) {
|
|
2970
|
+
await api.post("/host/integration-connectivity", {
|
|
2971
|
+
agent_id: agent.agent_id,
|
|
2972
|
+
results: result.reports
|
|
2973
|
+
});
|
|
2974
|
+
log(
|
|
2975
|
+
`Connectivity probe for '${agent.code_name}': probed=${result.probed} reported=${result.reports.length} due=${result.due}`
|
|
2976
|
+
);
|
|
2977
|
+
}
|
|
2978
|
+
}
|
|
2715
2979
|
function stopPersistentSessionAndForgetMcpBaseline(codeName, breakerReason) {
|
|
2716
2980
|
cancelPendingSessionRestart(codeName);
|
|
2717
2981
|
stopPersistentSession(codeName, log);
|
|
@@ -2862,7 +3126,7 @@ var cachedFrameworkVersion = null;
|
|
|
2862
3126
|
var lastVersionCheckAt = 0;
|
|
2863
3127
|
var VERSION_CHECK_INTERVAL_MS = 5 * 60 * 1e3;
|
|
2864
3128
|
var lastResponsivenessProbeAt = 0;
|
|
2865
|
-
var agtCliVersion = true ? "0.
|
|
3129
|
+
var agtCliVersion = true ? "0.26.0" : "dev";
|
|
2866
3130
|
function resolveBrewPath(execFileSync4) {
|
|
2867
3131
|
try {
|
|
2868
3132
|
const out = execFileSync4("which", ["brew"], { timeout: 5e3 }).toString().trim();
|
|
@@ -3821,7 +4085,7 @@ async function pollCycle() {
|
|
|
3821
4085
|
}
|
|
3822
4086
|
try {
|
|
3823
4087
|
const { detectHostSecurity } = await import("../host-security-6PDFG7F5.js");
|
|
3824
|
-
const { collectDiagnostics } = await import("../persistent-session-
|
|
4088
|
+
const { collectDiagnostics } = await import("../persistent-session-3ITHPO4P.js");
|
|
3825
4089
|
const diagCodeNames = [...persistentSessionAgents];
|
|
3826
4090
|
const agentDiagnostics = diagCodeNames.length > 0 ? collectDiagnostics(diagCodeNames) : void 0;
|
|
3827
4091
|
let tailscaleHostname;
|
|
@@ -3879,7 +4143,7 @@ async function pollCycle() {
|
|
|
3879
4143
|
const {
|
|
3880
4144
|
collectResponsivenessProbes,
|
|
3881
4145
|
getResponsivenessIntervalMs
|
|
3882
|
-
} = await import("../responsiveness-probe-
|
|
4146
|
+
} = await import("../responsiveness-probe-7XWORQLO.js");
|
|
3883
4147
|
const probeIntervalMs = getResponsivenessIntervalMs();
|
|
3884
4148
|
if (now - lastResponsivenessProbeAt > probeIntervalMs) {
|
|
3885
4149
|
const probeCodeNames = [...persistentSessionAgents];
|
|
@@ -4789,6 +5053,14 @@ async function processAgent(agent, agentStates) {
|
|
|
4789
5053
|
log(`OAuth token refresh failed for '${agent.code_name}/${integration.definition_id}': ${err.message}`);
|
|
4790
5054
|
}
|
|
4791
5055
|
}
|
|
5056
|
+
if (process.env.AGT_CONNECTIVITY_PROBE_ENABLED === "true") {
|
|
5057
|
+
try {
|
|
5058
|
+
const probeProjectDir = join6(homedir4(), ".augmented", agent.code_name, "project");
|
|
5059
|
+
await runAgentConnectivityProbes(agent, integrations, probeProjectDir);
|
|
5060
|
+
} catch (err) {
|
|
5061
|
+
log(`Connectivity probe failed for '${agent.code_name}': ${err.message}`);
|
|
5062
|
+
}
|
|
5063
|
+
}
|
|
4792
5064
|
if (integrations.length > 0) {
|
|
4793
5065
|
const intHash = computeIntegrationsHash(integrations);
|
|
4794
5066
|
const prevIntHash = knownIntegrationHashes.get(agent.agent_id);
|
|
@@ -4945,12 +5217,15 @@ async function processAgent(agent, agentStates) {
|
|
|
4945
5217
|
}
|
|
4946
5218
|
let tasks = refreshData.scheduled_tasks ?? [];
|
|
4947
5219
|
const existingTemplateIds = new Set(tasks.map((t) => t.template_id));
|
|
5220
|
+
const kanbanWorkRetired = (agentFrameworkCache.get(agent.code_name) ?? "openclaw") === "claude-code" && agentSessionMode === "persistent";
|
|
4948
5221
|
try {
|
|
4949
5222
|
const defaultsData = await api.post("/host/resolve-default-schedules", { agent_id: agent.agent_id });
|
|
4950
|
-
const
|
|
5223
|
+
const allSchedules = (defaultsData.schedules ?? []).filter(
|
|
5224
|
+
(s) => !(kanbanWorkRetired && s.template_id === "kanban-work")
|
|
5225
|
+
);
|
|
5226
|
+
const missing = allSchedules.filter(
|
|
4951
5227
|
(s) => !existingTemplateIds.has(s.template_id)
|
|
4952
5228
|
);
|
|
4953
|
-
const allSchedules = defaultsData.schedules ?? [];
|
|
4954
5229
|
if (allSchedules.length > 0) {
|
|
4955
5230
|
await api.post("/host/ensure-default-schedules", {
|
|
4956
5231
|
agent_id: agent.agent_id,
|
|
@@ -4967,6 +5242,9 @@ async function processAgent(agent, agentStates) {
|
|
|
4967
5242
|
} catch (err) {
|
|
4968
5243
|
log(`Default schedule provisioning failed for '${agent.code_name}': ${err.message}`);
|
|
4969
5244
|
}
|
|
5245
|
+
if (kanbanWorkRetired) {
|
|
5246
|
+
tasks = tasks.filter((t) => t.template_id !== "kanban-work");
|
|
5247
|
+
}
|
|
4970
5248
|
if (agent.status === "active") {
|
|
4971
5249
|
if (frameworkAdapter.installPlugin) {
|
|
4972
5250
|
try {
|
|
@@ -5210,10 +5488,6 @@ async function processAgent(agent, agentStates) {
|
|
|
5210
5488
|
sessionHealthy: psResult.sessionHealthyAfter,
|
|
5211
5489
|
spawnAttempted: psResult.spawnAttempted
|
|
5212
5490
|
});
|
|
5213
|
-
if (psResult.sessionHealthyAfter) {
|
|
5214
|
-
ensureKanbanLoopArmed(agent.code_name, log).catch(() => {
|
|
5215
|
-
});
|
|
5216
|
-
}
|
|
5217
5491
|
if (stuck.shouldWarn) {
|
|
5218
5492
|
log(
|
|
5219
5493
|
`[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)`
|
|
@@ -5412,8 +5686,6 @@ async function processAgent(agent, agentStates) {
|
|
|
5412
5686
|
} else {
|
|
5413
5687
|
log(`[persistent-session] Work trigger skipped for '${agent.code_name}' \u2014 session not yet healthy`);
|
|
5414
5688
|
}
|
|
5415
|
-
} else {
|
|
5416
|
-
fireClaudeWorkTrigger(agent.code_name, agent.agent_id, boardItems);
|
|
5417
5689
|
}
|
|
5418
5690
|
}
|
|
5419
5691
|
}
|
|
@@ -5730,8 +6002,7 @@ async function syncAndCheckClaudeScheduler(agent, tasks, boardItems, refreshData
|
|
|
5730
6002
|
if (ready.length === 0) return;
|
|
5731
6003
|
for (const task of ready) {
|
|
5732
6004
|
if ((claudeTaskConcurrency.get(codeName) ?? 0) >= MAX_CLAUDE_CONCURRENCY) break;
|
|
5733
|
-
if (KANBAN_WORK_TEMPLATES.has(task.templateId)
|
|
5734
|
-
log(`[claude-scheduler] Skipping '${task.name}' for '${codeName}' \u2014 board is empty`);
|
|
6005
|
+
if (KANBAN_WORK_TEMPLATES.has(task.templateId)) {
|
|
5735
6006
|
const updated = markTaskFired(codeName, task.taskId, "ok");
|
|
5736
6007
|
claudeSchedulerStates.set(codeName, updated);
|
|
5737
6008
|
continue;
|
|
@@ -5742,20 +6013,6 @@ async function syncAndCheckClaudeScheduler(agent, tasks, boardItems, refreshData
|
|
|
5742
6013
|
const boardPrefix = formatBoardForPrompt(boardItems, template);
|
|
5743
6014
|
prompt = boardPrefix + prompt;
|
|
5744
6015
|
}
|
|
5745
|
-
if (KANBAN_WORK_TEMPLATES.has(task.templateId)) {
|
|
5746
|
-
const todayItem = boardItems.find((b) => b.status === "todo");
|
|
5747
|
-
if (todayItem) {
|
|
5748
|
-
try {
|
|
5749
|
-
await api.post("/host/kanban", {
|
|
5750
|
-
agent_id: agent.agent_id,
|
|
5751
|
-
update: [{ id: todayItem.id, title: todayItem.title, status: "in_progress" }]
|
|
5752
|
-
});
|
|
5753
|
-
log(`[claude-scheduler] Moved '${todayItem.title}' to in_progress for '${codeName}'`);
|
|
5754
|
-
} catch (err) {
|
|
5755
|
-
log(`[claude-scheduler] Failed to move item to in_progress: ${err.message}`);
|
|
5756
|
-
}
|
|
5757
|
-
}
|
|
5758
|
-
}
|
|
5759
6016
|
inFlightClaudeTasks.add(task.taskId);
|
|
5760
6017
|
claudeTaskConcurrency.set(codeName, (claudeTaskConcurrency.get(codeName) ?? 0) + 1);
|
|
5761
6018
|
log(`[claude-scheduler] Firing '${task.name}' for '${codeName}'`);
|
|
@@ -6157,30 +6414,6 @@ async function processClaudeTaskResult(codeName, agentId, templateId, rawOutput,
|
|
|
6157
6414
|
log(`[claude-scheduler] Failed to post result for '${codeName}': ${err.message}`);
|
|
6158
6415
|
}
|
|
6159
6416
|
}
|
|
6160
|
-
function fireClaudeWorkTrigger(codeName, agentId, boardItems) {
|
|
6161
|
-
const state5 = claudeSchedulerStates.get(codeName) ?? loadSchedulerState(codeName);
|
|
6162
|
-
const kanbanTask = findTaskByTemplate(state5, "kanban-work");
|
|
6163
|
-
if (!kanbanTask) {
|
|
6164
|
-
log(`[claude-scheduler] Work trigger: no kanban-work task found for '${codeName}'`);
|
|
6165
|
-
return;
|
|
6166
|
-
}
|
|
6167
|
-
if (inFlightClaudeTasks.has(kanbanTask.taskId)) {
|
|
6168
|
-
log(`[claude-scheduler] Work trigger: kanban-work already in-flight for '${codeName}'`);
|
|
6169
|
-
return;
|
|
6170
|
-
}
|
|
6171
|
-
let prompt = kanbanTask.prompt;
|
|
6172
|
-
if (boardItems.length > 0) {
|
|
6173
|
-
const boardPrefix = formatBoardForPrompt(boardItems, "follow-up");
|
|
6174
|
-
prompt = boardPrefix + prompt;
|
|
6175
|
-
}
|
|
6176
|
-
inFlightClaudeTasks.add(kanbanTask.taskId);
|
|
6177
|
-
claudeTaskConcurrency.set(codeName, (claudeTaskConcurrency.get(codeName) ?? 0) + 1);
|
|
6178
|
-
log(`[claude-scheduler] Work trigger: firing kanban-work for '${codeName}'`);
|
|
6179
|
-
executeAndProcessClaudeTask(codeName, agentId, kanbanTask, prompt).finally(() => {
|
|
6180
|
-
inFlightClaudeTasks.delete(kanbanTask.taskId);
|
|
6181
|
-
claudeTaskConcurrency.set(codeName, Math.max(0, (claudeTaskConcurrency.get(codeName) ?? 1) - 1));
|
|
6182
|
-
});
|
|
6183
|
-
}
|
|
6184
6417
|
var persistentSessionAgents = /* @__PURE__ */ new Set();
|
|
6185
6418
|
var lastMcpFailedBannerCount = /* @__PURE__ */ new Map();
|
|
6186
6419
|
var persistentSessionStuckTracker = new PersistentSessionStuckTracker();
|
|
@@ -6435,13 +6668,7 @@ ${truncateForLog(ctx.tail)}` : `; pane_tail_hash=sha256:${createHash3("sha256").
|
|
|
6435
6668
|
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(", ")}`);
|
|
6436
6669
|
}
|
|
6437
6670
|
for (const task of ready) {
|
|
6438
|
-
if (KANBAN_WORK_TEMPLATES.has(task.templateId)
|
|
6439
|
-
const updated = markTaskFired(codeName, task.taskId, "ok");
|
|
6440
|
-
claudeSchedulerStates.set(codeName, updated);
|
|
6441
|
-
continue;
|
|
6442
|
-
}
|
|
6443
|
-
if (KANBAN_WORK_TEMPLATES.has(task.templateId) && !hasActionableItems(boardItems)) {
|
|
6444
|
-
log(`[persistent-session] Skipping '${task.name}' for '${codeName}' \u2014 board is empty`);
|
|
6671
|
+
if (KANBAN_WORK_TEMPLATES.has(task.templateId)) {
|
|
6445
6672
|
const updated = markTaskFired(codeName, task.taskId, "ok");
|
|
6446
6673
|
claudeSchedulerStates.set(codeName, updated);
|
|
6447
6674
|
continue;
|
|
@@ -6452,19 +6679,6 @@ ${truncateForLog(ctx.tail)}` : `; pane_tail_hash=sha256:${createHash3("sha256").
|
|
|
6452
6679
|
const boardPrefix = formatBoardForPrompt(boardItems, template);
|
|
6453
6680
|
prompt = boardPrefix + prompt;
|
|
6454
6681
|
}
|
|
6455
|
-
if (KANBAN_WORK_TEMPLATES.has(task.templateId)) {
|
|
6456
|
-
const todayItem = boardItems.find((b) => b.status === "todo");
|
|
6457
|
-
if (todayItem) {
|
|
6458
|
-
try {
|
|
6459
|
-
await api.post("/host/kanban", {
|
|
6460
|
-
agent_id: agent.agent_id,
|
|
6461
|
-
update: [{ id: todayItem.id, title: todayItem.title, status: "in_progress" }]
|
|
6462
|
-
});
|
|
6463
|
-
log(`[persistent-session] Moved '${todayItem.title}' to in_progress for '${codeName}'`);
|
|
6464
|
-
} catch {
|
|
6465
|
-
}
|
|
6466
|
-
}
|
|
6467
|
-
}
|
|
6468
6682
|
if (inFlightClaudeTasks.has(task.taskId)) {
|
|
6469
6683
|
continue;
|
|
6470
6684
|
}
|
|
@@ -6698,15 +6912,13 @@ function ensureRealtimeKanbanStarted(agentStates) {
|
|
|
6698
6912
|
if (!agent) return;
|
|
6699
6913
|
const agentFw = agentFrameworkCache.get(agent.codeName) ?? "openclaw";
|
|
6700
6914
|
if (agentFw === "claude-code") {
|
|
6701
|
-
const boardItems = kanbanBoardCache.get(agent.codeName) ?? [];
|
|
6702
6915
|
if (isSessionHealthy(agent.codeName)) {
|
|
6703
6916
|
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.`, {
|
|
6704
6917
|
task_name: "kanban-work-trigger"
|
|
6705
6918
|
}, log);
|
|
6706
6919
|
log(`[realtime] Injected kanban-work trigger for '${agent.codeName}': "${item.title}"`);
|
|
6707
6920
|
} else {
|
|
6708
|
-
|
|
6709
|
-
log(`[realtime] Fired kanban-work for '${agent.codeName}': "${item.title}"`);
|
|
6921
|
+
log(`[realtime] Work trigger skipped for '${agent.codeName}' \u2014 session not yet healthy; hybrid will pick up "${item.title}"`);
|
|
6710
6922
|
}
|
|
6711
6923
|
}
|
|
6712
6924
|
},
|
|
@@ -6945,13 +7157,8 @@ var KANBAN_WORK_TEMPLATES = /* @__PURE__ */ new Set(["kanban-work"]);
|
|
|
6945
7157
|
function isPlainScheduledTemplate(templateId) {
|
|
6946
7158
|
return !STANDUP_TEMPLATES.has(templateId) && !TASK_UPDATE_TEMPLATES.has(templateId) && !PLAN_TEMPLATES.has(templateId) && !KANBAN_WORK_TEMPLATES.has(templateId);
|
|
6947
7159
|
}
|
|
6948
|
-
function isKanbanWorkCronDisabled() {
|
|
6949
|
-
const v = process.env["AGT_DISABLE_KANBAN_WORK_CRON"];
|
|
6950
|
-
return v === "1" || v?.toLowerCase() === "true";
|
|
6951
|
-
}
|
|
6952
7160
|
function isKanbanHybridEnabled() {
|
|
6953
|
-
|
|
6954
|
-
return v === "1" || v?.toLowerCase() === "true";
|
|
7161
|
+
return true;
|
|
6955
7162
|
}
|
|
6956
7163
|
function isKanbanHybridDryRun() {
|
|
6957
7164
|
const v = process.env["AGT_KANBAN_HYBRID_DRY_RUN"];
|
|
@@ -7026,18 +7233,7 @@ ${formatRunMarker(run_id)}` : KANBAN_CHECK_COMMAND;
|
|
|
7026
7233
|
log(`[manager-worker] kanban inject failed for '${codeName}'`);
|
|
7027
7234
|
}
|
|
7028
7235
|
}
|
|
7029
|
-
|
|
7030
|
-
if (!isKanbanHybridEnabled()) return;
|
|
7031
|
-
const cronOff = isKanbanWorkCronDisabled();
|
|
7032
|
-
const loopOff = isKanbanLoopDisabled();
|
|
7033
|
-
if (!cronOff || !loopOff) {
|
|
7034
|
-
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";
|
|
7035
|
-
log(
|
|
7036
|
-
`[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.`
|
|
7037
|
-
);
|
|
7038
|
-
}
|
|
7039
|
-
}
|
|
7040
|
-
var BOARD_INJECT_TEMPLATES = /* @__PURE__ */ new Set(["morning-plan", "task-update", "hourly-status", "end-of-day-summary", "kanban-work"]);
|
|
7236
|
+
var BOARD_INJECT_TEMPLATES = /* @__PURE__ */ new Set(["morning-plan", "task-update", "hourly-status", "end-of-day-summary"]);
|
|
7041
7237
|
var ACTIONABLE_STATUSES = /* @__PURE__ */ new Set(["todo", "in_progress"]);
|
|
7042
7238
|
function hasActionableItems(items) {
|
|
7043
7239
|
return items.some((item) => ACTIONABLE_STATUSES.has(item.status));
|
|
@@ -7875,7 +8071,7 @@ async function processClaudePairSessions(agents) {
|
|
|
7875
8071
|
killPairSession,
|
|
7876
8072
|
pairTmuxSession,
|
|
7877
8073
|
finalizeClaudePairOnboarding
|
|
7878
|
-
} = await import("../claude-pair-runtime-
|
|
8074
|
+
} = await import("../claude-pair-runtime-7PHOEAUN.js");
|
|
7879
8075
|
for (const pairId of pendingResp.cancelled_pair_ids ?? []) {
|
|
7880
8076
|
log(`[claude-pair] sweeping orphan tmux session for pair ${pairId.slice(0, 8)}`);
|
|
7881
8077
|
const killed = await killPairSession(pairTmuxSession(pairId));
|
|
@@ -8478,7 +8674,6 @@ function startManager(opts) {
|
|
|
8478
8674
|
log(
|
|
8479
8675
|
`[startup] worker pid=${process.pid} ppid=${process.ppid} node=${process.version} log=${join6(homedir4(), ".augmented", "manager.log")}`
|
|
8480
8676
|
);
|
|
8481
|
-
warnOnConflictingKanbanModes();
|
|
8482
8677
|
deployMcpAssets();
|
|
8483
8678
|
reapOrphanChannelMcps({ log });
|
|
8484
8679
|
void ensureHostFrameworkBinaries();
|
|
@@ -8657,7 +8852,6 @@ export {
|
|
|
8657
8852
|
isHybridActionable,
|
|
8658
8853
|
isKanbanHybridDryRun,
|
|
8659
8854
|
isKanbanHybridEnabled,
|
|
8660
|
-
isKanbanWorkCronDisabled,
|
|
8661
8855
|
isPlainScheduledTemplate,
|
|
8662
8856
|
isScheduledCardTracked,
|
|
8663
8857
|
isScheduledViaKanbanEnabled,
|
|
@@ -8669,7 +8863,6 @@ export {
|
|
|
8669
8863
|
shouldSkipRevokedCleanup,
|
|
8670
8864
|
stampClaudeCodeUpgradeMarker,
|
|
8671
8865
|
startManager,
|
|
8672
|
-
stopManager
|
|
8673
|
-
warnOnConflictingKanbanModes
|
|
8866
|
+
stopManager
|
|
8674
8867
|
};
|
|
8675
8868
|
//# sourceMappingURL=manager-worker.js.map
|