@integrity-labs/agt-cli 0.23.2 → 0.24.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 +3 -3
- package/dist/{chunk-WUYKMPYW.js → chunk-WZTRMJM4.js} +3 -3
- package/dist/{chunk-WUYKMPYW.js.map → chunk-WZTRMJM4.js.map} +1 -1
- package/dist/lib/manager-worker.js +354 -239
- package/dist/lib/manager-worker.js.map +1 -1
- package/dist/mcp/slack-channel.js +32 -246
- package/dist/mcp/telegram-channel.js +30 -232
- package/dist/pane-mcp-banner-scraper-JA437JIB.js +22 -0
- package/dist/pane-mcp-banner-scraper-JA437JIB.js.map +1 -0
- package/package.json +1 -1
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
provisionOrientHook,
|
|
13
13
|
provisionStopHook,
|
|
14
14
|
requireHost
|
|
15
|
-
} from "../chunk-
|
|
15
|
+
} from "../chunk-WZTRMJM4.js";
|
|
16
16
|
import {
|
|
17
17
|
findTaskByTemplate,
|
|
18
18
|
getProjectDir as getProjectDir2,
|
|
@@ -67,11 +67,11 @@ import {
|
|
|
67
67
|
|
|
68
68
|
// src/lib/manager-worker.ts
|
|
69
69
|
import { createHash as createHash2 } from "crypto";
|
|
70
|
-
import { readFileSync as
|
|
70
|
+
import { readFileSync as readFileSync4, writeFileSync as writeFileSync3, appendFileSync, mkdirSync as mkdirSync2, chmodSync, existsSync as existsSync4, rmSync as rmSync2, readdirSync as readdirSync2, statSync, unlinkSync, copyFileSync } from "fs";
|
|
71
71
|
import https from "https";
|
|
72
72
|
import { execFileSync as syncExecFile } from "child_process";
|
|
73
|
-
import { join as
|
|
74
|
-
import { homedir as
|
|
73
|
+
import { join as join5, dirname } from "path";
|
|
74
|
+
import { homedir as homedir4 } from "os";
|
|
75
75
|
import { fileURLToPath } from "url";
|
|
76
76
|
|
|
77
77
|
// src/lib/mcp-config-drift.ts
|
|
@@ -435,12 +435,12 @@ function reapMissingMcpSessions(args) {
|
|
|
435
435
|
if (!missingRaw.includes(key)) liveKeys.add(key);
|
|
436
436
|
}
|
|
437
437
|
for (const key of liveKeys) {
|
|
438
|
-
const
|
|
439
|
-
if (
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
438
|
+
const state4 = presenceReaperState.get(stateKey(codeName, key));
|
|
439
|
+
if (state4) {
|
|
440
|
+
state4.attempts = 0;
|
|
441
|
+
state4.lastSeenLiveAt = now();
|
|
442
|
+
state4.lastAttemptedSessionStartedAt = null;
|
|
443
|
+
state4.gaveUpLogged = false;
|
|
444
444
|
}
|
|
445
445
|
}
|
|
446
446
|
if (missing.length === 0) {
|
|
@@ -455,24 +455,24 @@ function reapMissingMcpSessions(args) {
|
|
|
455
455
|
const active = [];
|
|
456
456
|
for (const key of missing) {
|
|
457
457
|
const sk = stateKey(codeName, key);
|
|
458
|
-
const
|
|
458
|
+
const state4 = presenceReaperState.get(sk) ?? {
|
|
459
459
|
attempts: 0,
|
|
460
460
|
lastSeenLiveAt: null,
|
|
461
461
|
lastAttemptedSessionStartedAt: null,
|
|
462
462
|
gaveUpLogged: false
|
|
463
463
|
};
|
|
464
|
-
if (
|
|
465
|
-
|
|
466
|
-
|
|
464
|
+
if (state4.lastAttemptedSessionStartedAt !== sessionStartedAt) {
|
|
465
|
+
state4.attempts += 1;
|
|
466
|
+
state4.lastAttemptedSessionStartedAt = sessionStartedAt;
|
|
467
467
|
}
|
|
468
|
-
presenceReaperState.set(sk,
|
|
469
|
-
if (
|
|
468
|
+
presenceReaperState.set(sk, state4);
|
|
469
|
+
if (state4.attempts > MAX_PRESENCE_RESTART_ATTEMPTS) {
|
|
470
470
|
givenUp.push(key);
|
|
471
|
-
if (!
|
|
471
|
+
if (!state4.gaveUpLogged) {
|
|
472
472
|
log2(
|
|
473
473
|
`[mcp-presence-reaper] giving up on '${codeName}:${key}' after ${MAX_PRESENCE_RESTART_ATTEMPTS} consecutive failed restarts \u2014 declared but never recovers (likely orphaned config; see ENG-5279)`
|
|
474
474
|
);
|
|
475
|
-
|
|
475
|
+
state4.gaveUpLogged = true;
|
|
476
476
|
if (onGiveUp) {
|
|
477
477
|
try {
|
|
478
478
|
onGiveUp(codeName, key);
|
|
@@ -710,6 +710,79 @@ async function maybeReportUsageBanner(args) {
|
|
|
710
710
|
}
|
|
711
711
|
}
|
|
712
712
|
|
|
713
|
+
// src/lib/activity-cache-monitor.ts
|
|
714
|
+
import { existsSync, readFileSync } from "fs";
|
|
715
|
+
import { homedir } from "os";
|
|
716
|
+
import { join } from "path";
|
|
717
|
+
var MIN_CHECK_INTERVAL_MS2 = 6e4;
|
|
718
|
+
var STATS_CACHE_PATH = join(homedir(), ".claude", "stats-cache.json");
|
|
719
|
+
var ISO_DATE_RE = /^\d{4}-\d{2}-\d{2}$/;
|
|
720
|
+
var state2 = { lastObservedDate: null, lastCheckedAt: 0 };
|
|
721
|
+
function selectNewDailyRows(raw, lastObservedDate) {
|
|
722
|
+
let parsed;
|
|
723
|
+
try {
|
|
724
|
+
parsed = JSON.parse(raw);
|
|
725
|
+
} catch {
|
|
726
|
+
return [];
|
|
727
|
+
}
|
|
728
|
+
const days = Array.isArray(parsed.dailyActivity) ? parsed.dailyActivity : [];
|
|
729
|
+
const nonNegInt = (v) => {
|
|
730
|
+
if (typeof v !== "number" || !Number.isFinite(v)) return null;
|
|
731
|
+
const n = Math.trunc(v);
|
|
732
|
+
return n >= 0 ? n : null;
|
|
733
|
+
};
|
|
734
|
+
const result = [];
|
|
735
|
+
for (const d of days) {
|
|
736
|
+
if (typeof d.date !== "string" || !ISO_DATE_RE.test(d.date)) continue;
|
|
737
|
+
if (lastObservedDate !== null && d.date <= lastObservedDate) continue;
|
|
738
|
+
const m = nonNegInt(d.messageCount);
|
|
739
|
+
const s = nonNegInt(d.sessionCount);
|
|
740
|
+
const t = nonNegInt(d.toolCallCount);
|
|
741
|
+
if (m === null || s === null || t === null) continue;
|
|
742
|
+
const breakdownForDay = parsed.dailyModelTokens?.[d.date];
|
|
743
|
+
const model_breakdown = breakdownForDay && typeof breakdownForDay === "object" && !Array.isArray(breakdownForDay) ? breakdownForDay : null;
|
|
744
|
+
result.push({
|
|
745
|
+
date: d.date,
|
|
746
|
+
message_count: m,
|
|
747
|
+
session_count: s,
|
|
748
|
+
tool_call_count: t,
|
|
749
|
+
model_breakdown
|
|
750
|
+
});
|
|
751
|
+
}
|
|
752
|
+
result.sort((a, b) => a.date.localeCompare(b.date));
|
|
753
|
+
return result;
|
|
754
|
+
}
|
|
755
|
+
async function maybeReportActivityCache(args) {
|
|
756
|
+
const { api: api2, log: log2 } = args;
|
|
757
|
+
const now = args.now ?? /* @__PURE__ */ new Date();
|
|
758
|
+
const nowMs = now.getTime();
|
|
759
|
+
if (nowMs - state2.lastCheckedAt < MIN_CHECK_INTERVAL_MS2) return;
|
|
760
|
+
state2.lastCheckedAt = nowMs;
|
|
761
|
+
if (!existsSync(STATS_CACHE_PATH)) {
|
|
762
|
+
return;
|
|
763
|
+
}
|
|
764
|
+
let raw;
|
|
765
|
+
try {
|
|
766
|
+
raw = readFileSync(STATS_CACHE_PATH, "utf-8");
|
|
767
|
+
} catch (err) {
|
|
768
|
+
log2(`[activity-cache] readFileSync failed: ${err.message}`);
|
|
769
|
+
return;
|
|
770
|
+
}
|
|
771
|
+
const rows = selectNewDailyRows(raw, state2.lastObservedDate);
|
|
772
|
+
if (rows.length === 0) return;
|
|
773
|
+
for (const row of rows) {
|
|
774
|
+
try {
|
|
775
|
+
await api2.post("/host/activity-observations", row);
|
|
776
|
+
state2.lastObservedDate = row.date;
|
|
777
|
+
} catch (err) {
|
|
778
|
+
log2(
|
|
779
|
+
`[activity-cache] POST /host/activity-observations failed for date=${row.date}: ${err.message}`
|
|
780
|
+
);
|
|
781
|
+
return;
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
}
|
|
785
|
+
|
|
713
786
|
// src/lib/poll-backoff.ts
|
|
714
787
|
var POLL_BACKOFF_BASE_MS = 1e3;
|
|
715
788
|
var POLL_BACKOFF_MAX_MS = 6e4;
|
|
@@ -1139,8 +1212,8 @@ var GatewayClientPool = class extends EventEmitter {
|
|
|
1139
1212
|
|
|
1140
1213
|
// src/lib/claude-auth-detect.ts
|
|
1141
1214
|
import { readFile, readdir } from "fs/promises";
|
|
1142
|
-
import { homedir, platform } from "os";
|
|
1143
|
-
import { join } from "path";
|
|
1215
|
+
import { homedir as homedir2, platform } from "os";
|
|
1216
|
+
import { join as join2 } from "path";
|
|
1144
1217
|
import { execFile } from "child_process";
|
|
1145
1218
|
import { promisify } from "util";
|
|
1146
1219
|
var execFileAsync = promisify(execFile);
|
|
@@ -1155,8 +1228,8 @@ async function detectClaudeAuth() {
|
|
|
1155
1228
|
}
|
|
1156
1229
|
async function findClaudeCredentialsPaths() {
|
|
1157
1230
|
const candidates = [
|
|
1158
|
-
|
|
1159
|
-
|
|
1231
|
+
join2(homedir2(), ".claude", ".credentials.json"),
|
|
1232
|
+
join2(homedir2(), ".claude", "credentials.json")
|
|
1160
1233
|
];
|
|
1161
1234
|
const isLinuxRoot = platform() === "linux" && typeof process.getuid === "function" && process.getuid() === 0;
|
|
1162
1235
|
if (isLinuxRoot) {
|
|
@@ -1164,8 +1237,8 @@ async function findClaudeCredentialsPaths() {
|
|
|
1164
1237
|
const entries = await readdir("/home", { withFileTypes: true });
|
|
1165
1238
|
for (const entry of entries) {
|
|
1166
1239
|
if (!entry.isDirectory()) continue;
|
|
1167
|
-
candidates.push(
|
|
1168
|
-
candidates.push(
|
|
1240
|
+
candidates.push(join2("/home", entry.name, ".claude", ".credentials.json"));
|
|
1241
|
+
candidates.push(join2("/home", entry.name, ".claude", "credentials.json"));
|
|
1169
1242
|
}
|
|
1170
1243
|
} catch {
|
|
1171
1244
|
}
|
|
@@ -1257,18 +1330,18 @@ function normalize(value) {
|
|
|
1257
1330
|
}
|
|
1258
1331
|
|
|
1259
1332
|
// src/lib/channel-hash-cache.ts
|
|
1260
|
-
import { existsSync, readFileSync, writeFileSync } from "fs";
|
|
1261
|
-
import { join as
|
|
1333
|
+
import { existsSync as existsSync2, readFileSync as readFileSync2, writeFileSync } from "fs";
|
|
1334
|
+
import { join as join3 } from "path";
|
|
1262
1335
|
var CACHE_FILENAME = "channel-hash-cache.json";
|
|
1263
1336
|
function getChannelHashCacheFile(configDir) {
|
|
1264
|
-
return
|
|
1337
|
+
return join3(configDir, CACHE_FILENAME);
|
|
1265
1338
|
}
|
|
1266
1339
|
function loadChannelHashCache(target, configDir) {
|
|
1267
1340
|
const path = getChannelHashCacheFile(configDir);
|
|
1268
|
-
if (!
|
|
1341
|
+
if (!existsSync2(path)) return;
|
|
1269
1342
|
let parsed;
|
|
1270
1343
|
try {
|
|
1271
|
-
parsed = JSON.parse(
|
|
1344
|
+
parsed = JSON.parse(readFileSync2(path, "utf-8"));
|
|
1272
1345
|
} catch {
|
|
1273
1346
|
return;
|
|
1274
1347
|
}
|
|
@@ -1741,24 +1814,24 @@ function withScheduleLinkFooter(opts) {
|
|
|
1741
1814
|
}
|
|
1742
1815
|
|
|
1743
1816
|
// src/lib/restart-flags.ts
|
|
1744
|
-
import { existsSync as
|
|
1745
|
-
import { homedir as
|
|
1746
|
-
import { join as
|
|
1817
|
+
import { existsSync as existsSync3, mkdirSync, readdirSync, readFileSync as readFileSync3, renameSync, rmSync, writeFileSync as writeFileSync2 } from "fs";
|
|
1818
|
+
import { homedir as homedir3 } from "os";
|
|
1819
|
+
import { join as join4 } from "path";
|
|
1747
1820
|
import { randomUUID } from "crypto";
|
|
1748
1821
|
function restartFlagsDir() {
|
|
1749
|
-
return
|
|
1822
|
+
return join4(homedir3(), ".augmented", "restart-flags");
|
|
1750
1823
|
}
|
|
1751
1824
|
function flagPath(codeName) {
|
|
1752
|
-
return
|
|
1825
|
+
return join4(restartFlagsDir(), `${codeName}.flag`);
|
|
1753
1826
|
}
|
|
1754
1827
|
function readRestartFlags() {
|
|
1755
1828
|
const dir = restartFlagsDir();
|
|
1756
|
-
if (!
|
|
1829
|
+
if (!existsSync3(dir)) return [];
|
|
1757
1830
|
const out = [];
|
|
1758
1831
|
for (const entry of readdirSync(dir)) {
|
|
1759
1832
|
if (!entry.endsWith(".flag")) continue;
|
|
1760
1833
|
try {
|
|
1761
|
-
const raw =
|
|
1834
|
+
const raw = readFileSync3(join4(dir, entry), "utf8");
|
|
1762
1835
|
const parsed = JSON.parse(raw);
|
|
1763
1836
|
if (typeof parsed.codeName !== "string" || parsed.codeName.length === 0) {
|
|
1764
1837
|
parsed.codeName = entry.replace(/\.flag$/, "");
|
|
@@ -1776,7 +1849,7 @@ function readRestartFlags() {
|
|
|
1776
1849
|
}
|
|
1777
1850
|
function deleteRestartFlag(codeName) {
|
|
1778
1851
|
const path = flagPath(codeName);
|
|
1779
|
-
if (
|
|
1852
|
+
if (existsSync3(path)) {
|
|
1780
1853
|
rmSync(path, { force: true });
|
|
1781
1854
|
}
|
|
1782
1855
|
}
|
|
@@ -2274,8 +2347,8 @@ function applyRestartAcks(args) {
|
|
|
2274
2347
|
var GATEWAY_PORT_BASE = 18800;
|
|
2275
2348
|
var GATEWAY_PORT_STEP = 10;
|
|
2276
2349
|
var GATEWAY_PORT_MAX = 18899;
|
|
2277
|
-
var AUGMENTED_DIR =
|
|
2278
|
-
var GATEWAY_PORTS_FILE =
|
|
2350
|
+
var AUGMENTED_DIR = join5(process.env["HOME"] ?? "/tmp", ".augmented");
|
|
2351
|
+
var GATEWAY_PORTS_FILE = join5(AUGMENTED_DIR, "gateway-ports.json");
|
|
2279
2352
|
var CHANNEL_SWEEP_INTERVAL_MS = (() => {
|
|
2280
2353
|
const raw = parseInt(process.env["AGT_CHANNEL_SWEEP_INTERVAL_MS"] ?? "", 10);
|
|
2281
2354
|
if (!Number.isFinite(raw)) return 5 * 60 * 1e3;
|
|
@@ -2382,8 +2455,8 @@ var KNOWN_SAFE_TAIL_SIGNATURES = /* @__PURE__ */ new Set(["session_id_in_use"]);
|
|
|
2382
2455
|
function shouldSkipRevokedCleanup(previousKnownStatus) {
|
|
2383
2456
|
return previousKnownStatus === "revoked";
|
|
2384
2457
|
}
|
|
2385
|
-
function hasRevokedResiduals(
|
|
2386
|
-
return
|
|
2458
|
+
function hasRevokedResiduals(state4) {
|
|
2459
|
+
return state4.gatewayRunning || state4.portAllocated || state4.provisionDirExists;
|
|
2387
2460
|
}
|
|
2388
2461
|
var knownVersions = /* @__PURE__ */ new Map();
|
|
2389
2462
|
var knownStatuses = /* @__PURE__ */ new Map();
|
|
@@ -2449,7 +2522,7 @@ var runningMcpHashes = /* @__PURE__ */ new Map();
|
|
|
2449
2522
|
var runningMcpServerKeys = /* @__PURE__ */ new Map();
|
|
2450
2523
|
function projectMcpHash(_codeName, projectDir) {
|
|
2451
2524
|
try {
|
|
2452
|
-
const raw =
|
|
2525
|
+
const raw = readFileSync4(join5(projectDir, ".mcp.json"), "utf-8");
|
|
2453
2526
|
return createHash2("sha256").update(canonicalJson(JSON.parse(raw))).digest("hex");
|
|
2454
2527
|
} catch {
|
|
2455
2528
|
return null;
|
|
@@ -2457,7 +2530,7 @@ function projectMcpHash(_codeName, projectDir) {
|
|
|
2457
2530
|
}
|
|
2458
2531
|
function projectMcpKeys(_codeName, projectDir) {
|
|
2459
2532
|
try {
|
|
2460
|
-
const raw =
|
|
2533
|
+
const raw = readFileSync4(join5(projectDir, ".mcp.json"), "utf-8");
|
|
2461
2534
|
const parsed = JSON.parse(raw);
|
|
2462
2535
|
const servers = parsed.mcpServers;
|
|
2463
2536
|
if (!servers || typeof servers !== "object") return /* @__PURE__ */ new Set();
|
|
@@ -2554,7 +2627,7 @@ var codeNameToAgentId = /* @__PURE__ */ new Map();
|
|
|
2554
2627
|
var agentChannelTokens = /* @__PURE__ */ new Map();
|
|
2555
2628
|
var activeChannels = /* @__PURE__ */ new Map();
|
|
2556
2629
|
var gatewaysStartedThisCycle = /* @__PURE__ */ new Set();
|
|
2557
|
-
var
|
|
2630
|
+
var state3 = {
|
|
2558
2631
|
pid: process.pid,
|
|
2559
2632
|
startedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2560
2633
|
lastPollAt: null,
|
|
@@ -2588,6 +2661,7 @@ function clearAgentCaches(agentId, codeName) {
|
|
|
2588
2661
|
lastHarvestAt.delete(codeName);
|
|
2589
2662
|
claudeSchedulerStates.delete(codeName);
|
|
2590
2663
|
claudeTaskConcurrency.delete(codeName);
|
|
2664
|
+
lastMcpFailedBannerCount.delete(codeName);
|
|
2591
2665
|
memoryFileHashes.delete(agentId);
|
|
2592
2666
|
lastDownloadHash.delete(agentId);
|
|
2593
2667
|
lastLocalFileHash.delete(agentId);
|
|
@@ -2610,7 +2684,7 @@ var cachedFrameworkVersion = null;
|
|
|
2610
2684
|
var lastVersionCheckAt = 0;
|
|
2611
2685
|
var VERSION_CHECK_INTERVAL_MS = 5 * 60 * 1e3;
|
|
2612
2686
|
var lastResponsivenessProbeAt = 0;
|
|
2613
|
-
var agtCliVersion = true ? "0.
|
|
2687
|
+
var agtCliVersion = true ? "0.24.0" : "dev";
|
|
2614
2688
|
function resolveBrewPath(execFileSync4) {
|
|
2615
2689
|
try {
|
|
2616
2690
|
const out = execFileSync4("which", ["brew"], { timeout: 5e3 }).toString().trim();
|
|
@@ -2623,7 +2697,7 @@ function resolveBrewPath(execFileSync4) {
|
|
|
2623
2697
|
"/usr/local/bin/brew"
|
|
2624
2698
|
];
|
|
2625
2699
|
for (const path of fallbacks) {
|
|
2626
|
-
if (
|
|
2700
|
+
if (existsSync4(path)) return path;
|
|
2627
2701
|
}
|
|
2628
2702
|
return null;
|
|
2629
2703
|
}
|
|
@@ -2633,7 +2707,7 @@ function claudeBinaryInstalled(execFileSync4) {
|
|
|
2633
2707
|
"/opt/homebrew/bin/claude",
|
|
2634
2708
|
"/usr/local/bin/claude"
|
|
2635
2709
|
];
|
|
2636
|
-
if (canonical.some((path) =>
|
|
2710
|
+
if (canonical.some((path) => existsSync4(path))) return true;
|
|
2637
2711
|
try {
|
|
2638
2712
|
execFileSync4("which", ["claude"], { timeout: 5e3 });
|
|
2639
2713
|
return true;
|
|
@@ -2815,7 +2889,7 @@ async function ensureFrameworkBinary(frameworkId) {
|
|
|
2815
2889
|
if (!process.env.PATH?.split(":").includes(brewBinDir)) {
|
|
2816
2890
|
process.env.PATH = `${brewBinDir}:${process.env.PATH ?? ""}`;
|
|
2817
2891
|
}
|
|
2818
|
-
if (
|
|
2892
|
+
if (existsSync4("/home/linuxbrew/.linuxbrew/bin/claude")) {
|
|
2819
2893
|
log("Claude Code installed successfully");
|
|
2820
2894
|
} else {
|
|
2821
2895
|
log("Claude Code install completed but binary not found at expected path \u2014 check brew logs");
|
|
@@ -2827,7 +2901,7 @@ async function ensureFrameworkBinary(frameworkId) {
|
|
|
2827
2901
|
var CLAUDE_CODE_UPGRADE_CHECK_INTERVAL_MS = 24 * 60 * 60 * 1e3;
|
|
2828
2902
|
var claudeCodeUpgradeInFlight = false;
|
|
2829
2903
|
function claudeCodeUpgradeMarkerPath() {
|
|
2830
|
-
return
|
|
2904
|
+
return join5(homedir4(), ".augmented", ".last-claude-code-upgrade-check");
|
|
2831
2905
|
}
|
|
2832
2906
|
function stampClaudeCodeUpgradeMarker() {
|
|
2833
2907
|
try {
|
|
@@ -2837,7 +2911,7 @@ function stampClaudeCodeUpgradeMarker() {
|
|
|
2837
2911
|
}
|
|
2838
2912
|
function claudeCodeUpgradeThrottled() {
|
|
2839
2913
|
try {
|
|
2840
|
-
const lastCheck = parseInt(
|
|
2914
|
+
const lastCheck = parseInt(readFileSync4(claudeCodeUpgradeMarkerPath(), "utf-8").trim(), 10);
|
|
2841
2915
|
if (!Number.isFinite(lastCheck)) return false;
|
|
2842
2916
|
return Date.now() - lastCheck < CLAUDE_CODE_UPGRADE_CHECK_INTERVAL_MS;
|
|
2843
2917
|
} catch {
|
|
@@ -2907,7 +2981,7 @@ async function checkAndUpdateCli() {
|
|
|
2907
2981
|
const isNpmGlobal = !isBrewFormula && resolvedPath.includes("node_modules");
|
|
2908
2982
|
if (!isBrewFormula && !isNpmGlobal) return;
|
|
2909
2983
|
const { readFileSync: readF, writeFileSync: writeF } = await import("fs");
|
|
2910
|
-
const markerPath =
|
|
2984
|
+
const markerPath = join5(homedir4(), ".augmented", ".last-update-check");
|
|
2911
2985
|
try {
|
|
2912
2986
|
const lastCheck = parseInt(readF(markerPath, "utf-8").trim(), 10);
|
|
2913
2987
|
if (Date.now() - lastCheck < UPDATE_CHECK_INTERVAL_MS) return;
|
|
@@ -2972,17 +3046,18 @@ async function checkAndUpdateCliViaBrew() {
|
|
|
2972
3046
|
async function checkAndUpdateCliViaNpm() {
|
|
2973
3047
|
const { execFileSync: execFileSync4 } = await import("child_process");
|
|
2974
3048
|
if (agtCliVersion === "dev") return;
|
|
3049
|
+
const channel = process.env.AGT_CLI_RELEASE_CHANNEL || "latest";
|
|
2975
3050
|
let latest;
|
|
2976
3051
|
try {
|
|
2977
3052
|
const res = await fetch(
|
|
2978
|
-
|
|
3053
|
+
`https://registry.npmjs.org/@integrity-labs/agt-cli/${encodeURIComponent(channel)}`,
|
|
2979
3054
|
{
|
|
2980
3055
|
signal: AbortSignal.timeout(1e4),
|
|
2981
3056
|
headers: { Accept: "application/json" }
|
|
2982
3057
|
}
|
|
2983
3058
|
);
|
|
2984
3059
|
if (!res.ok) {
|
|
2985
|
-
log(`[self-update] npm registry returned ${res.status}`);
|
|
3060
|
+
log(`[self-update] npm registry returned ${res.status} (channel=${channel})`);
|
|
2986
3061
|
return;
|
|
2987
3062
|
}
|
|
2988
3063
|
const body = await res.json();
|
|
@@ -2995,14 +3070,15 @@ async function checkAndUpdateCliViaNpm() {
|
|
|
2995
3070
|
log(`[self-update] npm registry fetch failed: ${err.message}`);
|
|
2996
3071
|
return;
|
|
2997
3072
|
}
|
|
2998
|
-
|
|
3073
|
+
const shouldUpdate = channel === "latest" ? isNewerSemver(agtCliVersion, latest) : latest !== agtCliVersion;
|
|
3074
|
+
if (!shouldUpdate) {
|
|
2999
3075
|
if (!selfUpdateUpToDateLogged) {
|
|
3000
|
-
log(`[self-update] agt CLI is up to date (npm, ${agtCliVersion})`);
|
|
3076
|
+
log(`[self-update] agt CLI is up to date (npm, channel=${channel}, ${agtCliVersion})`);
|
|
3001
3077
|
selfUpdateUpToDateLogged = true;
|
|
3002
3078
|
}
|
|
3003
3079
|
return;
|
|
3004
3080
|
}
|
|
3005
|
-
log(`[self-update] agt CLI update available: ${agtCliVersion} \u2192 ${latest}. Upgrading via npm...`);
|
|
3081
|
+
log(`[self-update] agt CLI update available: ${agtCliVersion} \u2192 ${latest} (channel=${channel}). Upgrading via npm...`);
|
|
3006
3082
|
const isRoot = typeof process.getuid === "function" && process.getuid() === 0;
|
|
3007
3083
|
const cmd = isRoot ? "npm" : "sudo";
|
|
3008
3084
|
const args = isRoot ? [
|
|
@@ -3069,10 +3145,10 @@ async function applyClaudeAuthToEnv(childEnv, label) {
|
|
|
3069
3145
|
throw new Error("claude_auth_mode=api_key but /host/exchange returned no decrypted key");
|
|
3070
3146
|
}
|
|
3071
3147
|
childEnv.ANTHROPIC_API_KEY = exchange.anthropicApiKey;
|
|
3072
|
-
const claudeDir =
|
|
3148
|
+
const claudeDir = join5(homedir4(), ".claude");
|
|
3073
3149
|
for (const filename of [".credentials.json", "credentials.json"]) {
|
|
3074
|
-
const p =
|
|
3075
|
-
if (
|
|
3150
|
+
const p = join5(claudeDir, filename);
|
|
3151
|
+
if (existsSync4(p)) {
|
|
3076
3152
|
try {
|
|
3077
3153
|
rmSync2(p, { force: true });
|
|
3078
3154
|
log(`[${label}] Removed ${p} (api_key mode \u2014 preventing OAuth fallback)`);
|
|
@@ -3086,7 +3162,7 @@ async function applyClaudeAuthToEnv(childEnv, label) {
|
|
|
3086
3162
|
}
|
|
3087
3163
|
function loadGatewayPorts() {
|
|
3088
3164
|
try {
|
|
3089
|
-
return JSON.parse(
|
|
3165
|
+
return JSON.parse(readFileSync4(GATEWAY_PORTS_FILE, "utf-8"));
|
|
3090
3166
|
} catch {
|
|
3091
3167
|
return {};
|
|
3092
3168
|
}
|
|
@@ -3116,10 +3192,10 @@ function freePort(codeName) {
|
|
|
3116
3192
|
}
|
|
3117
3193
|
}
|
|
3118
3194
|
function getStateFile() {
|
|
3119
|
-
return
|
|
3195
|
+
return join5(config?.configDir ?? join5(process.env["HOME"] ?? "/tmp", ".augmented"), "manager-state.json");
|
|
3120
3196
|
}
|
|
3121
3197
|
function channelHashCacheDir() {
|
|
3122
|
-
return config?.configDir ??
|
|
3198
|
+
return config?.configDir ?? join5(process.env["HOME"] ?? "/tmp", ".augmented");
|
|
3123
3199
|
}
|
|
3124
3200
|
function loadChannelHashCache2() {
|
|
3125
3201
|
loadChannelHashCache(knownChannelConfigHashes, channelHashCacheDir());
|
|
@@ -3161,9 +3237,9 @@ function log(msg) {
|
|
|
3161
3237
|
`;
|
|
3162
3238
|
if (!managerLogPath) {
|
|
3163
3239
|
try {
|
|
3164
|
-
managerLogPath =
|
|
3240
|
+
managerLogPath = join5(homedir4(), ".augmented", "manager.log");
|
|
3165
3241
|
mkdirSync2(dirname(managerLogPath), { recursive: true });
|
|
3166
|
-
if (
|
|
3242
|
+
if (existsSync4(managerLogPath)) {
|
|
3167
3243
|
chmodSync(managerLogPath, 384);
|
|
3168
3244
|
}
|
|
3169
3245
|
} catch {
|
|
@@ -3191,7 +3267,7 @@ function sha256(content) {
|
|
|
3191
3267
|
}
|
|
3192
3268
|
function hashFile(filePath) {
|
|
3193
3269
|
try {
|
|
3194
|
-
const content =
|
|
3270
|
+
const content = readFileSync4(filePath, "utf-8");
|
|
3195
3271
|
return sha256(content);
|
|
3196
3272
|
} catch {
|
|
3197
3273
|
return null;
|
|
@@ -3216,12 +3292,12 @@ function parseSkillFrontmatter(content) {
|
|
|
3216
3292
|
}
|
|
3217
3293
|
async function refreshSkillsIndexInClaudeMd(configDir, codeName, log2) {
|
|
3218
3294
|
const { readdirSync: readdirSync3, readFileSync: rfs, existsSync: ex, writeFileSync: writeFileSync4 } = await import("fs");
|
|
3219
|
-
const skillsDir =
|
|
3220
|
-
const claudeMdPath =
|
|
3295
|
+
const skillsDir = join5(configDir, codeName, "project", ".claude", "skills");
|
|
3296
|
+
const claudeMdPath = join5(configDir, codeName, "project", "CLAUDE.md");
|
|
3221
3297
|
if (!ex(skillsDir) || !ex(claudeMdPath)) return;
|
|
3222
3298
|
const entries = [];
|
|
3223
3299
|
for (const dir of readdirSync3(skillsDir).sort()) {
|
|
3224
|
-
const skillFile =
|
|
3300
|
+
const skillFile = join5(skillsDir, dir, "SKILL.md");
|
|
3225
3301
|
if (!ex(skillFile)) continue;
|
|
3226
3302
|
try {
|
|
3227
3303
|
const { name, description } = parseSkillFrontmatter(rfs(skillFile, "utf-8"));
|
|
@@ -3269,10 +3345,10 @@ ${SKILLS_INDEX_END}`;
|
|
|
3269
3345
|
}
|
|
3270
3346
|
async function migrateToProfiles() {
|
|
3271
3347
|
const homeDir = process.env["HOME"] ?? "/tmp";
|
|
3272
|
-
const sharedConfigPath =
|
|
3348
|
+
const sharedConfigPath = join5(homeDir, ".openclaw", "openclaw.json");
|
|
3273
3349
|
let sharedConfig;
|
|
3274
3350
|
try {
|
|
3275
|
-
sharedConfig = JSON.parse(
|
|
3351
|
+
sharedConfig = JSON.parse(readFileSync4(sharedConfigPath, "utf-8"));
|
|
3276
3352
|
} catch {
|
|
3277
3353
|
return;
|
|
3278
3354
|
}
|
|
@@ -3285,19 +3361,19 @@ async function migrateToProfiles() {
|
|
|
3285
3361
|
const codeName = agentEntry["id"];
|
|
3286
3362
|
if (!codeName) continue;
|
|
3287
3363
|
if (codeName === "main") continue;
|
|
3288
|
-
const profileDir =
|
|
3289
|
-
if (
|
|
3364
|
+
const profileDir = join5(homeDir, `.openclaw-${codeName}`);
|
|
3365
|
+
if (existsSync4(join5(profileDir, "openclaw.json"))) continue;
|
|
3290
3366
|
log(`Migrating agent '${codeName}' to per-agent profile`);
|
|
3291
3367
|
if (adapter.seedProfileConfig) {
|
|
3292
3368
|
adapter.seedProfileConfig(codeName);
|
|
3293
3369
|
}
|
|
3294
|
-
const sharedAuthDir =
|
|
3295
|
-
const profileAuthDir =
|
|
3296
|
-
const authFile =
|
|
3297
|
-
if (
|
|
3370
|
+
const sharedAuthDir = join5(homeDir, ".openclaw", "agents", codeName, "agent");
|
|
3371
|
+
const profileAuthDir = join5(profileDir, "agents", codeName, "agent");
|
|
3372
|
+
const authFile = join5(sharedAuthDir, "auth-profiles.json");
|
|
3373
|
+
if (existsSync4(authFile)) {
|
|
3298
3374
|
mkdirSync2(profileAuthDir, { recursive: true });
|
|
3299
|
-
const authContent =
|
|
3300
|
-
writeFileSync3(
|
|
3375
|
+
const authContent = readFileSync4(authFile, "utf-8");
|
|
3376
|
+
writeFileSync3(join5(profileAuthDir, "auth-profiles.json"), authContent);
|
|
3301
3377
|
}
|
|
3302
3378
|
allocatePort(codeName);
|
|
3303
3379
|
migrated++;
|
|
@@ -3335,7 +3411,7 @@ function readGatewayToken(codeName) {
|
|
|
3335
3411
|
}
|
|
3336
3412
|
const homeDir = process.env["HOME"] ?? "/tmp";
|
|
3337
3413
|
try {
|
|
3338
|
-
const cfg = JSON.parse(
|
|
3414
|
+
const cfg = JSON.parse(readFileSync4(join5(homeDir, `.openclaw-${codeName}`, "openclaw.json"), "utf-8"));
|
|
3339
3415
|
return cfg?.gateway?.auth?.token;
|
|
3340
3416
|
} catch {
|
|
3341
3417
|
return void 0;
|
|
@@ -3344,18 +3420,18 @@ function readGatewayToken(codeName) {
|
|
|
3344
3420
|
var GATEWAY_HUNG_TIMEOUT_MS = 5 * 6e4;
|
|
3345
3421
|
function isGatewayHung(codeName) {
|
|
3346
3422
|
const homeDir = process.env["HOME"] ?? "/tmp";
|
|
3347
|
-
const jobsPath =
|
|
3348
|
-
if (!
|
|
3423
|
+
const jobsPath = join5(homeDir, `.openclaw-${codeName}`, "cron", "jobs.json");
|
|
3424
|
+
if (!existsSync4(jobsPath)) return false;
|
|
3349
3425
|
try {
|
|
3350
|
-
const data = JSON.parse(
|
|
3426
|
+
const data = JSON.parse(readFileSync4(jobsPath, "utf-8"));
|
|
3351
3427
|
const jobs = data.jobs ?? data;
|
|
3352
3428
|
if (!Array.isArray(jobs)) return false;
|
|
3353
3429
|
const now = Date.now();
|
|
3354
3430
|
for (const job of jobs) {
|
|
3355
|
-
const
|
|
3356
|
-
if (!
|
|
3357
|
-
const runStartedAt =
|
|
3358
|
-
const isRunning =
|
|
3431
|
+
const state4 = job.state;
|
|
3432
|
+
if (!state4) continue;
|
|
3433
|
+
const runStartedAt = state4.runStartedAtMs;
|
|
3434
|
+
const isRunning = state4.status === "running" || state4.running === true;
|
|
3359
3435
|
if (isRunning && runStartedAt && now - runStartedAt > GATEWAY_HUNG_TIMEOUT_MS) {
|
|
3360
3436
|
return true;
|
|
3361
3437
|
}
|
|
@@ -3380,15 +3456,15 @@ async function ensureGatewayRunning(codeName, adapter) {
|
|
|
3380
3456
|
}
|
|
3381
3457
|
await new Promise((r) => setTimeout(r, 2e3));
|
|
3382
3458
|
const homeDir = process.env["HOME"] ?? "/tmp";
|
|
3383
|
-
const cronJobsPath =
|
|
3459
|
+
const cronJobsPath = join5(homeDir, `.openclaw-${codeName}`, "cron", "jobs.json");
|
|
3384
3460
|
clearStaleCronRunState(cronJobsPath);
|
|
3385
3461
|
} else {
|
|
3386
3462
|
if (status.port) {
|
|
3387
3463
|
try {
|
|
3388
3464
|
const homeDir = process.env["HOME"] ?? "/tmp";
|
|
3389
|
-
const configPath =
|
|
3390
|
-
if (
|
|
3391
|
-
const cfg = JSON.parse(
|
|
3465
|
+
const configPath = join5(homeDir, `.openclaw-${codeName}`, "openclaw.json");
|
|
3466
|
+
if (existsSync4(configPath)) {
|
|
3467
|
+
const cfg = JSON.parse(readFileSync4(configPath, "utf-8"));
|
|
3392
3468
|
if (cfg.gateway?.port !== status.port) {
|
|
3393
3469
|
if (!cfg.gateway) cfg.gateway = {};
|
|
3394
3470
|
cfg.gateway.port = status.port;
|
|
@@ -3412,9 +3488,9 @@ async function ensureGatewayRunning(codeName, adapter) {
|
|
|
3412
3488
|
gatewaysStartedThisCycle.add(codeName);
|
|
3413
3489
|
try {
|
|
3414
3490
|
const homeDir = process.env["HOME"] ?? "/tmp";
|
|
3415
|
-
const configPath =
|
|
3416
|
-
if (
|
|
3417
|
-
const cfg = JSON.parse(
|
|
3491
|
+
const configPath = join5(homeDir, `.openclaw-${codeName}`, "openclaw.json");
|
|
3492
|
+
if (existsSync4(configPath)) {
|
|
3493
|
+
const cfg = JSON.parse(readFileSync4(configPath, "utf-8"));
|
|
3418
3494
|
if (!cfg.gateway) cfg.gateway = {};
|
|
3419
3495
|
cfg.gateway.port = port;
|
|
3420
3496
|
writeFileSync3(configPath, JSON.stringify(cfg, null, 2));
|
|
@@ -3556,7 +3632,7 @@ async function pollCycle() {
|
|
|
3556
3632
|
const now = Date.now();
|
|
3557
3633
|
if (now - lastVersionCheckAt > VERSION_CHECK_INTERVAL_MS) {
|
|
3558
3634
|
try {
|
|
3559
|
-
const firstAgent =
|
|
3635
|
+
const firstAgent = state3.agents[0];
|
|
3560
3636
|
const versionAdapter = firstAgent ? resolveAgentFramework(firstAgent.codeName) : getFramework("openclaw");
|
|
3561
3637
|
if (versionAdapter.getVersion) {
|
|
3562
3638
|
cachedFrameworkVersion = await versionAdapter.getVersion();
|
|
@@ -3635,13 +3711,50 @@ async function pollCycle() {
|
|
|
3635
3711
|
} catch (err) {
|
|
3636
3712
|
log(`[responsiveness-probe] collection failed: ${err.message}`);
|
|
3637
3713
|
}
|
|
3714
|
+
try {
|
|
3715
|
+
const { scrapeMcpFailedBannerCount } = await import("../pane-mcp-banner-scraper-JA437JIB.js");
|
|
3716
|
+
const observations = [];
|
|
3717
|
+
const pendingCacheCommits = [];
|
|
3718
|
+
for (const codeName of persistentSessionAgents) {
|
|
3719
|
+
const agentId = codeNameToAgentId.get(codeName);
|
|
3720
|
+
if (!agentId) continue;
|
|
3721
|
+
const tail = readPaneLogTail(codeName, 40);
|
|
3722
|
+
if (!tail) continue;
|
|
3723
|
+
const observed = scrapeMcpFailedBannerCount(tail);
|
|
3724
|
+
const count = observed ?? 0;
|
|
3725
|
+
const last = lastMcpFailedBannerCount.get(codeName);
|
|
3726
|
+
if (last === count) continue;
|
|
3727
|
+
observations.push({ agent_id: agentId, count });
|
|
3728
|
+
pendingCacheCommits.push({ codeName, count });
|
|
3729
|
+
}
|
|
3730
|
+
if (observations.length > 0) {
|
|
3731
|
+
void api.post(
|
|
3732
|
+
"/host/mcp-banner-observation",
|
|
3733
|
+
{ observations }
|
|
3734
|
+
).then((resp) => {
|
|
3735
|
+
const accepted = new Set(
|
|
3736
|
+
(resp?.results ?? []).filter((r) => r.ok).map((r) => r.agent_id)
|
|
3737
|
+
);
|
|
3738
|
+
for (const { codeName, count } of pendingCacheCommits) {
|
|
3739
|
+
const agentId = codeNameToAgentId.get(codeName);
|
|
3740
|
+
if (agentId && accepted.has(agentId)) {
|
|
3741
|
+
lastMcpFailedBannerCount.set(codeName, count);
|
|
3742
|
+
}
|
|
3743
|
+
}
|
|
3744
|
+
}).catch((err) => {
|
|
3745
|
+
log(`[mcp-banner] post failed: ${err.message}`);
|
|
3746
|
+
});
|
|
3747
|
+
}
|
|
3748
|
+
} catch (err) {
|
|
3749
|
+
log(`[mcp-banner] collection failed: ${err.message}`);
|
|
3750
|
+
}
|
|
3638
3751
|
const data = await api.post("/host/agents", { host_id: hostId });
|
|
3639
3752
|
const agents = data.agents ?? [];
|
|
3640
3753
|
const restartAcks = /* @__PURE__ */ new Map();
|
|
3641
3754
|
for (const agent of agents) {
|
|
3642
3755
|
const requested = agent.restart_requested_at ?? null;
|
|
3643
3756
|
if (!requested) continue;
|
|
3644
|
-
const prev =
|
|
3757
|
+
const prev = state3.agents.find((a) => a.agentId === agent.agent_id);
|
|
3645
3758
|
const lastProcessed = prev?.lastRestartProcessedAt ?? null;
|
|
3646
3759
|
if (lastProcessed && Date.parse(lastProcessed) >= Date.parse(requested)) continue;
|
|
3647
3760
|
log(`[restart] Dashboard requested restart for '${agent.code_name}' at ${requested}`);
|
|
@@ -3664,7 +3777,7 @@ async function pollCycle() {
|
|
|
3664
3777
|
await processAgent(agent, agentStates);
|
|
3665
3778
|
} catch (err) {
|
|
3666
3779
|
log(`Error processing agent '${agent.code_name}': ${err.message}`);
|
|
3667
|
-
const existing =
|
|
3780
|
+
const existing = state3.agents.find((a) => a.agentId === agent.agent_id);
|
|
3668
3781
|
if (existing) {
|
|
3669
3782
|
agentStates.push(existing);
|
|
3670
3783
|
} else {
|
|
@@ -3687,14 +3800,15 @@ async function pollCycle() {
|
|
|
3687
3800
|
}
|
|
3688
3801
|
}
|
|
3689
3802
|
}
|
|
3803
|
+
void maybeReportActivityCache({ api, log });
|
|
3690
3804
|
const restartAckStateChanged = applyRestartAcks({
|
|
3691
3805
|
agentStates,
|
|
3692
|
-
priorAgents:
|
|
3806
|
+
priorAgents: state3.agents,
|
|
3693
3807
|
restartAcks
|
|
3694
3808
|
});
|
|
3695
3809
|
if (restartAckStateChanged) {
|
|
3696
3810
|
try {
|
|
3697
|
-
const ackedState = { ...
|
|
3811
|
+
const ackedState = { ...state3, agents: agentStates };
|
|
3698
3812
|
writeFileSync3(getStateFile(), JSON.stringify(ackedState, null, 2));
|
|
3699
3813
|
} catch (err) {
|
|
3700
3814
|
log(`[restart] failed to persist ack immediately: ${err.message}`);
|
|
@@ -3712,7 +3826,7 @@ async function pollCycle() {
|
|
|
3712
3826
|
} catch {
|
|
3713
3827
|
}
|
|
3714
3828
|
const currentIds = new Set(agents.map((a) => a.agent_id));
|
|
3715
|
-
for (const prev of
|
|
3829
|
+
for (const prev of state3.agents) {
|
|
3716
3830
|
if (!currentIds.has(prev.agentId)) {
|
|
3717
3831
|
log(`Agent '${prev.codeName}' removed from host (deleted or unassigned)`);
|
|
3718
3832
|
const adapter = resolveAgentFramework(prev.codeName);
|
|
@@ -3725,7 +3839,7 @@ async function pollCycle() {
|
|
|
3725
3839
|
}
|
|
3726
3840
|
killAgentChannelProcesses(prev.codeName, { log });
|
|
3727
3841
|
freePort(prev.codeName);
|
|
3728
|
-
const agentDir =
|
|
3842
|
+
const agentDir = join5(adapter.getAgentDir(prev.codeName), "provision");
|
|
3729
3843
|
await cleanupAgentFiles(prev.codeName, agentDir);
|
|
3730
3844
|
clearAgentCaches(prev.agentId, prev.codeName);
|
|
3731
3845
|
}
|
|
@@ -3812,10 +3926,10 @@ async function pollCycle() {
|
|
|
3812
3926
|
}
|
|
3813
3927
|
} catch {
|
|
3814
3928
|
}
|
|
3815
|
-
|
|
3816
|
-
...
|
|
3929
|
+
state3 = {
|
|
3930
|
+
...state3,
|
|
3817
3931
|
lastPollAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3818
|
-
pollCount:
|
|
3932
|
+
pollCount: state3.pollCount + 1,
|
|
3819
3933
|
agents: agentStates,
|
|
3820
3934
|
// ENG-5441: serialise trip state on every poll so manager restarts
|
|
3821
3935
|
// never silently clear a tripped breaker. Cheap — only tripped
|
|
@@ -3826,9 +3940,9 @@ async function pollCycle() {
|
|
|
3826
3940
|
log(`[poll-backoff] recovered after ${consecutivePollFailures} failure(s), resuming normal interval`);
|
|
3827
3941
|
consecutivePollFailures = 0;
|
|
3828
3942
|
}
|
|
3829
|
-
send({ type: "state-update", state:
|
|
3943
|
+
send({ type: "state-update", state: state3 });
|
|
3830
3944
|
} catch (err) {
|
|
3831
|
-
|
|
3945
|
+
state3.errorCount++;
|
|
3832
3946
|
const message = err.message;
|
|
3833
3947
|
log(`Poll error: ${message}`);
|
|
3834
3948
|
send({ type: "error", message });
|
|
@@ -3869,7 +3983,7 @@ async function processAgent(agent, agentStates) {
|
|
|
3869
3983
|
}
|
|
3870
3984
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
3871
3985
|
const adapter = resolveAgentFramework(agent.code_name);
|
|
3872
|
-
let agentDir =
|
|
3986
|
+
let agentDir = join5(adapter.getAgentDir(agent.code_name), "provision");
|
|
3873
3987
|
if (agent.status === "draft" || agent.status === "paused") {
|
|
3874
3988
|
if (previousKnownStatus !== agent.status) {
|
|
3875
3989
|
log(`Agent '${agent.code_name}' is ${agent.status}, skipping provisioning`);
|
|
@@ -3908,7 +4022,7 @@ async function processAgent(agent, agentStates) {
|
|
|
3908
4022
|
const residuals = {
|
|
3909
4023
|
gatewayRunning: gatewayLiveness.running,
|
|
3910
4024
|
portAllocated: Object.prototype.hasOwnProperty.call(ports, agent.code_name),
|
|
3911
|
-
provisionDirExists:
|
|
4025
|
+
provisionDirExists: existsSync4(agentDir)
|
|
3912
4026
|
};
|
|
3913
4027
|
if (!hasRevokedResiduals(residuals)) {
|
|
3914
4028
|
agentStates.push({
|
|
@@ -3990,7 +4104,7 @@ async function processAgent(agent, agentStates) {
|
|
|
3990
4104
|
});
|
|
3991
4105
|
} catch (err) {
|
|
3992
4106
|
log(`Refresh failed for '${agent.code_name}': ${err.message}`);
|
|
3993
|
-
const existing =
|
|
4107
|
+
const existing = state3.agents.find((a) => a.agentId === agent.agent_id);
|
|
3994
4108
|
agentStates.push(existing ?? {
|
|
3995
4109
|
agentId: agent.agent_id,
|
|
3996
4110
|
codeName: agent.code_name,
|
|
@@ -4038,7 +4152,7 @@ async function processAgent(agent, agentStates) {
|
|
|
4038
4152
|
const frameworkId = refreshData.agent.framework ?? "openclaw";
|
|
4039
4153
|
agentFrameworkCache.set(agent.code_name, frameworkId);
|
|
4040
4154
|
const frameworkAdapter = getFramework(frameworkId);
|
|
4041
|
-
agentDir =
|
|
4155
|
+
agentDir = join5(frameworkAdapter.getAgentDir(agent.code_name), "provision");
|
|
4042
4156
|
cacheAgentDeliveryMetadata(agent.code_name, refreshData);
|
|
4043
4157
|
if (frameworkAdapter.seedProfileConfig) {
|
|
4044
4158
|
frameworkAdapter.seedProfileConfig(agent.code_name);
|
|
@@ -4046,7 +4160,7 @@ async function processAgent(agent, agentStates) {
|
|
|
4046
4160
|
const charterVersion = refreshData.charter.version;
|
|
4047
4161
|
const toolsVersion = refreshData.tools.version;
|
|
4048
4162
|
const known = knownVersions.get(agent.agent_id);
|
|
4049
|
-
let lastProvisionAt =
|
|
4163
|
+
let lastProvisionAt = state3.agents.find((a) => a.agentId === agent.agent_id)?.lastProvisionAt ?? null;
|
|
4050
4164
|
const currentChannelIds = launchableChannelIds(refreshData.channel_configs);
|
|
4051
4165
|
const previousChannelIds = knownChannels.get(agent.agent_id);
|
|
4052
4166
|
const channelsChanged = !previousChannelIds || currentChannelIds.size !== previousChannelIds.size || [...currentChannelIds].some((ch) => !previousChannelIds.has(ch)) || [...previousChannelIds].some((ch) => !currentChannelIds.has(ch));
|
|
@@ -4069,7 +4183,7 @@ async function processAgent(agent, agentStates) {
|
|
|
4069
4183
|
const changedFiles = [];
|
|
4070
4184
|
mkdirSync2(agentDir, { recursive: true });
|
|
4071
4185
|
for (const artifact of artifacts) {
|
|
4072
|
-
const filePath =
|
|
4186
|
+
const filePath = join5(agentDir, artifact.relativePath);
|
|
4073
4187
|
let existingHash;
|
|
4074
4188
|
let newHash;
|
|
4075
4189
|
let writeContent = artifact.content;
|
|
@@ -4081,8 +4195,8 @@ async function processAgent(agent, agentStates) {
|
|
|
4081
4195
|
};
|
|
4082
4196
|
newHash = sha256(stripDynamicSections(artifact.content));
|
|
4083
4197
|
try {
|
|
4084
|
-
const projectClaudeMd =
|
|
4085
|
-
const existing =
|
|
4198
|
+
const projectClaudeMd = join5(config.configDir, agent.code_name, "project", "CLAUDE.md");
|
|
4199
|
+
const existing = readFileSync4(projectClaudeMd, "utf-8");
|
|
4086
4200
|
existingHash = sha256(stripDynamicSections(existing));
|
|
4087
4201
|
} catch {
|
|
4088
4202
|
existingHash = null;
|
|
@@ -4100,7 +4214,7 @@ async function processAgent(agent, agentStates) {
|
|
|
4100
4214
|
const generatorKeys = Object.keys(generatorServers);
|
|
4101
4215
|
let existingRaw = "";
|
|
4102
4216
|
try {
|
|
4103
|
-
existingRaw =
|
|
4217
|
+
existingRaw = readFileSync4(filePath, "utf-8");
|
|
4104
4218
|
} catch {
|
|
4105
4219
|
}
|
|
4106
4220
|
const existingServers = parseMcp(existingRaw);
|
|
@@ -4122,22 +4236,22 @@ async function processAgent(agent, agentStates) {
|
|
|
4122
4236
|
}
|
|
4123
4237
|
}
|
|
4124
4238
|
if (changedFiles.length > 0) {
|
|
4125
|
-
const isFirst = !
|
|
4239
|
+
const isFirst = !existsSync4(join5(agentDir, "CHARTER.md"));
|
|
4126
4240
|
const verb = isFirst ? "Provisioning" : "Updating";
|
|
4127
4241
|
const fileNames = changedFiles.map((f) => f.relativePath).join(", ");
|
|
4128
4242
|
log(`${verb} '${agent.code_name}': ${fileNames}`);
|
|
4129
4243
|
for (const file of changedFiles) {
|
|
4130
|
-
const filePath =
|
|
4244
|
+
const filePath = join5(agentDir, file.relativePath);
|
|
4131
4245
|
mkdirSync2(dirname(filePath), { recursive: true });
|
|
4132
4246
|
writeFileSync3(filePath, file.content);
|
|
4133
4247
|
}
|
|
4134
4248
|
try {
|
|
4135
|
-
const provSkillsDir =
|
|
4136
|
-
if (
|
|
4249
|
+
const provSkillsDir = join5(agentDir, ".claude", "skills");
|
|
4250
|
+
if (existsSync4(provSkillsDir)) {
|
|
4137
4251
|
for (const folder of readdirSync2(provSkillsDir)) {
|
|
4138
4252
|
if (folder.startsWith("knowledge-")) {
|
|
4139
4253
|
try {
|
|
4140
|
-
rmSync2(
|
|
4254
|
+
rmSync2(join5(provSkillsDir, folder), { recursive: true });
|
|
4141
4255
|
} catch {
|
|
4142
4256
|
}
|
|
4143
4257
|
}
|
|
@@ -4150,7 +4264,7 @@ async function processAgent(agent, agentStates) {
|
|
|
4150
4264
|
const trackedFiles2 = frameworkAdapter.driftTrackedFiles();
|
|
4151
4265
|
const hashes = /* @__PURE__ */ new Map();
|
|
4152
4266
|
for (const file of trackedFiles2) {
|
|
4153
|
-
const h = hashFile(
|
|
4267
|
+
const h = hashFile(join5(agentDir, file));
|
|
4154
4268
|
if (h) hashes.set(file, h);
|
|
4155
4269
|
}
|
|
4156
4270
|
writtenHashes.set(agent.agent_id, hashes);
|
|
@@ -4194,10 +4308,10 @@ async function processAgent(agent, agentStates) {
|
|
|
4194
4308
|
}
|
|
4195
4309
|
let lastDriftCheckAt = now;
|
|
4196
4310
|
const written = writtenHashes.get(agent.agent_id);
|
|
4197
|
-
if (written &&
|
|
4311
|
+
if (written && existsSync4(agentDir)) {
|
|
4198
4312
|
const driftedFiles = [];
|
|
4199
4313
|
for (const [file, expectedHash] of written) {
|
|
4200
|
-
const localHash = hashFile(
|
|
4314
|
+
const localHash = hashFile(join5(agentDir, file));
|
|
4201
4315
|
if (localHash && localHash !== expectedHash) {
|
|
4202
4316
|
driftedFiles.push(file);
|
|
4203
4317
|
}
|
|
@@ -4208,7 +4322,7 @@ async function processAgent(agent, agentStates) {
|
|
|
4208
4322
|
try {
|
|
4209
4323
|
const localHashes = {};
|
|
4210
4324
|
for (const file of driftedFiles) {
|
|
4211
|
-
localHashes[file] = hashFile(
|
|
4325
|
+
localHashes[file] = hashFile(join5(agentDir, file));
|
|
4212
4326
|
}
|
|
4213
4327
|
await api.post("/host/drift", {
|
|
4214
4328
|
agent_id: agent.agent_id,
|
|
@@ -4366,24 +4480,24 @@ async function processAgent(agent, agentStates) {
|
|
|
4366
4480
|
if (agentSessionMode === "persistent" && (agentFrameworkCache.get(agent.code_name) ?? "openclaw") === "claude-code") {
|
|
4367
4481
|
try {
|
|
4368
4482
|
const agentProvisionDir = agentDir;
|
|
4369
|
-
const projectDir =
|
|
4483
|
+
const projectDir = join5(homedir4(), ".augmented", agent.code_name, "project");
|
|
4370
4484
|
mkdirSync2(agentProvisionDir, { recursive: true });
|
|
4371
4485
|
mkdirSync2(projectDir, { recursive: true });
|
|
4372
|
-
const provisionMcpPath =
|
|
4373
|
-
const projectMcpPath =
|
|
4486
|
+
const provisionMcpPath = join5(agentProvisionDir, ".mcp.json");
|
|
4487
|
+
const projectMcpPath = join5(projectDir, ".mcp.json");
|
|
4374
4488
|
let mcpConfig = { mcpServers: {} };
|
|
4375
4489
|
try {
|
|
4376
|
-
mcpConfig = JSON.parse(
|
|
4490
|
+
mcpConfig = JSON.parse(readFileSync4(provisionMcpPath, "utf-8"));
|
|
4377
4491
|
if (!mcpConfig.mcpServers) mcpConfig.mcpServers = {};
|
|
4378
4492
|
} catch {
|
|
4379
4493
|
}
|
|
4380
|
-
const localDirectChatChannel =
|
|
4494
|
+
const localDirectChatChannel = join5(homedir4(), ".augmented", "_mcp", "direct-chat-channel.js");
|
|
4381
4495
|
const directChatTeamSettings = refreshData.team?.settings;
|
|
4382
4496
|
const directChatTz = (() => {
|
|
4383
4497
|
const tz = directChatTeamSettings?.["timezone"];
|
|
4384
4498
|
return typeof tz === "string" && tz.trim() !== "" ? tz.trim() : void 0;
|
|
4385
4499
|
})();
|
|
4386
|
-
if (
|
|
4500
|
+
if (existsSync4(localDirectChatChannel) && !mcpConfig.mcpServers["direct-chat"]) {
|
|
4387
4501
|
mcpConfig.mcpServers["direct-chat"] = {
|
|
4388
4502
|
command: "node",
|
|
4389
4503
|
args: [localDirectChatChannel],
|
|
@@ -4399,8 +4513,8 @@ async function processAgent(agent, agentStates) {
|
|
|
4399
4513
|
writeFileSync3(projectMcpPath, serialized);
|
|
4400
4514
|
log(`Channel credentials written for '${agent.code_name}/direct-chat'`);
|
|
4401
4515
|
}
|
|
4402
|
-
const staleChannelsPath =
|
|
4403
|
-
if (
|
|
4516
|
+
const staleChannelsPath = join5(projectDir, ".mcp-channels.json");
|
|
4517
|
+
if (existsSync4(staleChannelsPath)) {
|
|
4404
4518
|
try {
|
|
4405
4519
|
rmSync2(staleChannelsPath, { force: true });
|
|
4406
4520
|
} catch {
|
|
@@ -4410,7 +4524,7 @@ async function processAgent(agent, agentStates) {
|
|
|
4410
4524
|
log(`Failed to provision direct-chat channel for '${agent.code_name}': ${err.message}`);
|
|
4411
4525
|
}
|
|
4412
4526
|
}
|
|
4413
|
-
let lastSecretsProvisionAt =
|
|
4527
|
+
let lastSecretsProvisionAt = state3.agents.find((a) => a.agentId === agent.agent_id)?.lastSecretsProvisionAt ?? null;
|
|
4414
4528
|
let secretsHash = knownSecretsHashes.get(agent.agent_id) ?? null;
|
|
4415
4529
|
try {
|
|
4416
4530
|
const secretsData = await api.post("/host/secrets", { agent_id: agent.agent_id });
|
|
@@ -4466,11 +4580,11 @@ async function processAgent(agent, agentStates) {
|
|
|
4466
4580
|
const intHash = computeIntegrationsHash(integrations);
|
|
4467
4581
|
const prevIntHash = knownIntegrationHashes.get(agent.agent_id);
|
|
4468
4582
|
if (intHash !== prevIntHash) {
|
|
4469
|
-
const projectDir =
|
|
4470
|
-
const envIntPath =
|
|
4583
|
+
const projectDir = join5(homedir4(), ".augmented", agent.code_name, "project");
|
|
4584
|
+
const envIntPath = join5(projectDir, ".env.integrations");
|
|
4471
4585
|
let preWriteEnv;
|
|
4472
4586
|
try {
|
|
4473
|
-
preWriteEnv =
|
|
4587
|
+
preWriteEnv = readFileSync4(envIntPath, "utf-8");
|
|
4474
4588
|
} catch {
|
|
4475
4589
|
preWriteEnv = void 0;
|
|
4476
4590
|
}
|
|
@@ -4482,9 +4596,9 @@ async function processAgent(agent, agentStates) {
|
|
|
4482
4596
|
let rotationHandled = true;
|
|
4483
4597
|
if (fw === "claude-code" && isSessionHealthy(agent.code_name)) {
|
|
4484
4598
|
try {
|
|
4485
|
-
const projectMcpPath =
|
|
4486
|
-
const postWriteEnv =
|
|
4487
|
-
const mcpContent =
|
|
4599
|
+
const projectMcpPath = join5(projectDir, ".mcp.json");
|
|
4600
|
+
const postWriteEnv = readFileSync4(envIntPath, "utf-8");
|
|
4601
|
+
const mcpContent = readFileSync4(projectMcpPath, "utf-8");
|
|
4488
4602
|
const changedVars = diffEnvIntegrations(preWriteEnv, postWriteEnv);
|
|
4489
4603
|
const mcpJsonForReap = JSON.parse(mcpContent);
|
|
4490
4604
|
const affectedServerKeys = findMcpServersUsingVars(mcpJsonForReap, changedVars);
|
|
@@ -4550,8 +4664,8 @@ async function processAgent(agent, agentStates) {
|
|
|
4550
4664
|
const mcpPath = frameworkAdapter.getMcpPath(agent.code_name);
|
|
4551
4665
|
if (mcpPath) {
|
|
4552
4666
|
try {
|
|
4553
|
-
const { readFileSync:
|
|
4554
|
-
const mcpConfig = JSON.parse(
|
|
4667
|
+
const { readFileSync: readFileSync5 } = await import("fs");
|
|
4668
|
+
const mcpConfig = JSON.parse(readFileSync5(mcpPath, "utf-8"));
|
|
4555
4669
|
if (mcpConfig.mcpServers) {
|
|
4556
4670
|
const managedPrefixes = [
|
|
4557
4671
|
"composio_",
|
|
@@ -4640,8 +4754,8 @@ async function processAgent(agent, agentStates) {
|
|
|
4640
4754
|
if (agent.status === "active") {
|
|
4641
4755
|
if (frameworkAdapter.installPlugin) {
|
|
4642
4756
|
try {
|
|
4643
|
-
const pluginPath =
|
|
4644
|
-
if (
|
|
4757
|
+
const pluginPath = join5(process.cwd(), "packages", "openclaw-plugin-augmented", "src", "index.ts");
|
|
4758
|
+
if (existsSync4(pluginPath)) {
|
|
4645
4759
|
frameworkAdapter.installPlugin(agent.code_name, "augmented", pluginPath, {
|
|
4646
4760
|
agtHost: requireHost(),
|
|
4647
4761
|
agtApiKey: getApiKey() ?? void 0,
|
|
@@ -4707,20 +4821,20 @@ async function processAgent(agent, agentStates) {
|
|
|
4707
4821
|
}
|
|
4708
4822
|
try {
|
|
4709
4823
|
const { readdirSync: readdirSync3, rmSync: rmSync3 } = await import("fs");
|
|
4710
|
-
const { homedir:
|
|
4824
|
+
const { homedir: homedir5 } = await import("os");
|
|
4711
4825
|
const frameworkId2 = frameworkAdapter.id;
|
|
4712
4826
|
const candidateSkillDirs = [
|
|
4713
4827
|
// Claude Code — framework runtime tree
|
|
4714
|
-
|
|
4828
|
+
join5(homedir5(), ".augmented", agent.code_name, "skills"),
|
|
4715
4829
|
// Claude Code — project tree
|
|
4716
|
-
|
|
4830
|
+
join5(homedir5(), ".augmented", agent.code_name, "project", ".claude", "skills"),
|
|
4717
4831
|
// OpenClaw — framework runtime tree
|
|
4718
|
-
|
|
4832
|
+
join5(homedir5(), `.openclaw-${agent.code_name}`, "skills"),
|
|
4719
4833
|
// Defensive: legacy provision-side path, not currently an
|
|
4720
4834
|
// install target but cheap to sweep.
|
|
4721
|
-
|
|
4835
|
+
join5(agentDir, ".claude", "skills")
|
|
4722
4836
|
];
|
|
4723
|
-
const existingDirs = candidateSkillDirs.filter((d) =>
|
|
4837
|
+
const existingDirs = candidateSkillDirs.filter((d) => existsSync4(d));
|
|
4724
4838
|
const discoveredEntries = /* @__PURE__ */ new Set();
|
|
4725
4839
|
for (const dir of existingDirs) {
|
|
4726
4840
|
try {
|
|
@@ -4734,8 +4848,8 @@ async function processAgent(agent, agentStates) {
|
|
|
4734
4848
|
}
|
|
4735
4849
|
const removeSkillFolder = (entry, reason) => {
|
|
4736
4850
|
for (const dir of existingDirs) {
|
|
4737
|
-
const p =
|
|
4738
|
-
if (
|
|
4851
|
+
const p = join5(dir, entry);
|
|
4852
|
+
if (existsSync4(p)) {
|
|
4739
4853
|
rmSync3(p, { recursive: true, force: true });
|
|
4740
4854
|
}
|
|
4741
4855
|
}
|
|
@@ -4895,8 +5009,8 @@ async function processAgent(agent, agentStates) {
|
|
|
4895
5009
|
const sess = getSessionState(agent.code_name);
|
|
4896
5010
|
let mcpJsonParsed = null;
|
|
4897
5011
|
try {
|
|
4898
|
-
const mcpPath =
|
|
4899
|
-
mcpJsonParsed = JSON.parse(
|
|
5012
|
+
const mcpPath = join5(getProjectDir(agent.code_name), ".mcp.json");
|
|
5013
|
+
mcpJsonParsed = JSON.parse(readFileSync4(mcpPath, "utf-8"));
|
|
4900
5014
|
} catch {
|
|
4901
5015
|
}
|
|
4902
5016
|
reapMissingMcpSessions({
|
|
@@ -5045,10 +5159,10 @@ async function processAgent(agent, agentStates) {
|
|
|
5045
5159
|
lastWorkTriggerAt.set(agent.code_name, triggerTs);
|
|
5046
5160
|
if (agentFw === "openclaw" && gatewayRunning && gatewayPort) {
|
|
5047
5161
|
const homeDir = process.env["HOME"] ?? "/tmp";
|
|
5048
|
-
const jobsPath =
|
|
5049
|
-
if (
|
|
5162
|
+
const jobsPath = join5(homeDir, `.openclaw-${agent.code_name}`, "cron", "jobs.json");
|
|
5163
|
+
if (existsSync4(jobsPath)) {
|
|
5050
5164
|
try {
|
|
5051
|
-
const jobsData = JSON.parse(
|
|
5165
|
+
const jobsData = JSON.parse(readFileSync4(jobsPath, "utf-8"));
|
|
5052
5166
|
const kanbanJob = (jobsData.jobs ?? []).find(
|
|
5053
5167
|
(j) => typeof j.name === "string" && j.name.includes("kanban-work")
|
|
5054
5168
|
);
|
|
@@ -5189,10 +5303,10 @@ In progress for ${age} minutes \u2014 auto-failed`).catch(() => {
|
|
|
5189
5303
|
}
|
|
5190
5304
|
}
|
|
5191
5305
|
const trackedFiles = frameworkAdapter.driftTrackedFiles();
|
|
5192
|
-
if (trackedFiles.length > 0 &&
|
|
5306
|
+
if (trackedFiles.length > 0 && existsSync4(agentDir)) {
|
|
5193
5307
|
const hashes = /* @__PURE__ */ new Map();
|
|
5194
5308
|
for (const file of trackedFiles) {
|
|
5195
|
-
const h = hashFile(
|
|
5309
|
+
const h = hashFile(join5(agentDir, file));
|
|
5196
5310
|
if (h) hashes.set(file, h);
|
|
5197
5311
|
}
|
|
5198
5312
|
writtenHashes.set(agent.agent_id, hashes);
|
|
@@ -5226,19 +5340,19 @@ function cleanupStaleSessions(codeName) {
|
|
|
5226
5340
|
lastCleanupAt.set(codeName, Date.now());
|
|
5227
5341
|
const homeDir = process.env["HOME"] ?? "/tmp";
|
|
5228
5342
|
for (const agentDir of ["main", codeName]) {
|
|
5229
|
-
const sessionsDir =
|
|
5343
|
+
const sessionsDir = join5(homeDir, `.openclaw-${codeName}`, "agents", agentDir, "sessions");
|
|
5230
5344
|
cleanupCronSessions(sessionsDir, CRON_SESSION_KEEP_COUNT);
|
|
5231
5345
|
}
|
|
5232
|
-
const cronRunsDir =
|
|
5346
|
+
const cronRunsDir = join5(homeDir, `.openclaw-${codeName}`, "cron", "runs");
|
|
5233
5347
|
cleanupOldFiles(cronRunsDir, CRON_RUN_RETENTION_DAYS, ".jsonl");
|
|
5234
|
-
const cronJobsPath =
|
|
5348
|
+
const cronJobsPath = join5(homeDir, `.openclaw-${codeName}`, "cron", "jobs.json");
|
|
5235
5349
|
clearStaleCronRunState(cronJobsPath);
|
|
5236
5350
|
}
|
|
5237
5351
|
function cleanupCronSessions(sessionsDir, keepCount) {
|
|
5238
|
-
const indexPath =
|
|
5239
|
-
if (!
|
|
5352
|
+
const indexPath = join5(sessionsDir, "sessions.json");
|
|
5353
|
+
if (!existsSync4(indexPath)) return;
|
|
5240
5354
|
try {
|
|
5241
|
-
const raw =
|
|
5355
|
+
const raw = readFileSync4(indexPath, "utf-8");
|
|
5242
5356
|
const index = JSON.parse(raw);
|
|
5243
5357
|
const cronRunKeys = Object.keys(index).filter((k) => k.includes(":cron:") && k.includes(":run:")).map((k) => ({
|
|
5244
5358
|
key: k,
|
|
@@ -5251,9 +5365,9 @@ function cleanupCronSessions(sessionsDir, keepCount) {
|
|
|
5251
5365
|
for (const entry of toDelete) {
|
|
5252
5366
|
delete index[entry.key];
|
|
5253
5367
|
if (entry.sessionId) {
|
|
5254
|
-
const sessionFile =
|
|
5368
|
+
const sessionFile = join5(sessionsDir, `${entry.sessionId}.jsonl`);
|
|
5255
5369
|
try {
|
|
5256
|
-
if (
|
|
5370
|
+
if (existsSync4(sessionFile)) {
|
|
5257
5371
|
unlinkSync(sessionFile);
|
|
5258
5372
|
deletedFiles++;
|
|
5259
5373
|
}
|
|
@@ -5273,8 +5387,8 @@ function cleanupCronSessions(sessionsDir, keepCount) {
|
|
|
5273
5387
|
delete index[parentKey];
|
|
5274
5388
|
if (parentSessionId) {
|
|
5275
5389
|
try {
|
|
5276
|
-
const f =
|
|
5277
|
-
if (
|
|
5390
|
+
const f = join5(sessionsDir, `${parentSessionId}.jsonl`);
|
|
5391
|
+
if (existsSync4(f)) {
|
|
5278
5392
|
unlinkSync(f);
|
|
5279
5393
|
deletedFiles++;
|
|
5280
5394
|
}
|
|
@@ -5292,28 +5406,28 @@ function cleanupCronSessions(sessionsDir, keepCount) {
|
|
|
5292
5406
|
}
|
|
5293
5407
|
var STALE_RUN_TIMEOUT_MS = 5 * 6e4;
|
|
5294
5408
|
function clearStaleCronRunState(jobsPath) {
|
|
5295
|
-
if (!
|
|
5409
|
+
if (!existsSync4(jobsPath)) return;
|
|
5296
5410
|
try {
|
|
5297
|
-
const raw =
|
|
5411
|
+
const raw = readFileSync4(jobsPath, "utf-8");
|
|
5298
5412
|
const data = JSON.parse(raw);
|
|
5299
5413
|
const jobs = data.jobs ?? data;
|
|
5300
5414
|
if (!Array.isArray(jobs)) return;
|
|
5301
5415
|
let changed = false;
|
|
5302
5416
|
const now = Date.now();
|
|
5303
5417
|
for (const job of jobs) {
|
|
5304
|
-
const
|
|
5305
|
-
if (!
|
|
5306
|
-
const runStartedAt =
|
|
5307
|
-
const isRunning =
|
|
5418
|
+
const state4 = job.state;
|
|
5419
|
+
if (!state4) continue;
|
|
5420
|
+
const runStartedAt = state4.runningAtMs ?? state4.runStartedAtMs;
|
|
5421
|
+
const isRunning = state4.running === true || state4.status === "running";
|
|
5308
5422
|
if (isRunning && runStartedAt && now - runStartedAt > STALE_RUN_TIMEOUT_MS) {
|
|
5309
|
-
|
|
5310
|
-
delete
|
|
5311
|
-
delete
|
|
5312
|
-
delete
|
|
5423
|
+
state4.running = false;
|
|
5424
|
+
delete state4.status;
|
|
5425
|
+
delete state4.runStartedAtMs;
|
|
5426
|
+
delete state4.currentRunId;
|
|
5313
5427
|
changed = true;
|
|
5314
5428
|
log(`Cleared stale running state for cron job '${job.name}' (stuck for ${Math.round((now - runStartedAt) / 6e4)}min)`);
|
|
5315
5429
|
} else if (isRunning && !runStartedAt) {
|
|
5316
|
-
|
|
5430
|
+
state4.running = false;
|
|
5317
5431
|
changed = true;
|
|
5318
5432
|
log(`Cleared stale running state for cron job '${job.name}' (no start timestamp)`);
|
|
5319
5433
|
}
|
|
@@ -5325,13 +5439,13 @@ function clearStaleCronRunState(jobsPath) {
|
|
|
5325
5439
|
}
|
|
5326
5440
|
}
|
|
5327
5441
|
function cleanupOldFiles(dir, maxAgeDays, ext) {
|
|
5328
|
-
if (!
|
|
5442
|
+
if (!existsSync4(dir)) return;
|
|
5329
5443
|
const cutoff = Date.now() - maxAgeDays * 24 * 60 * 60 * 1e3;
|
|
5330
5444
|
let removed = 0;
|
|
5331
5445
|
try {
|
|
5332
5446
|
for (const f of readdirSync2(dir)) {
|
|
5333
5447
|
if (!f.endsWith(ext)) continue;
|
|
5334
|
-
const fullPath =
|
|
5448
|
+
const fullPath = join5(dir, f);
|
|
5335
5449
|
try {
|
|
5336
5450
|
const st = statSync(fullPath);
|
|
5337
5451
|
if (st.mtimeMs < cutoff) {
|
|
@@ -5377,16 +5491,16 @@ async function syncAndCheckClaudeScheduler(agent, tasks, boardItems, refreshData
|
|
|
5377
5491
|
enabled: t.enabled ?? true,
|
|
5378
5492
|
triggered_at: t.triggered_at ?? null
|
|
5379
5493
|
}));
|
|
5380
|
-
const
|
|
5381
|
-
claudeSchedulerStates.set(codeName,
|
|
5494
|
+
const state5 = syncTasksToScheduler(codeName, agent.agent_id, taskInputs);
|
|
5495
|
+
claudeSchedulerStates.set(codeName, state5);
|
|
5382
5496
|
knownTasksHashes.set(agent.agent_id, combinedHash);
|
|
5383
5497
|
log(`[claude-scheduler] Tasks synced for '${codeName}' (${taskInputs.length} task(s))`);
|
|
5384
5498
|
}
|
|
5385
5499
|
if (!claudeSchedulerStates.has(codeName)) {
|
|
5386
5500
|
claudeSchedulerStates.set(codeName, loadSchedulerState(codeName));
|
|
5387
5501
|
}
|
|
5388
|
-
const
|
|
5389
|
-
const ready = getReadyTasks(
|
|
5502
|
+
const state4 = claudeSchedulerStates.get(codeName);
|
|
5503
|
+
const ready = getReadyTasks(state4, inFlightClaudeTasks);
|
|
5390
5504
|
if (ready.length === 0) return;
|
|
5391
5505
|
for (const task of ready) {
|
|
5392
5506
|
if ((claudeTaskConcurrency.get(codeName) ?? 0) >= MAX_CLAUDE_CONCURRENCY) break;
|
|
@@ -5475,7 +5589,7 @@ async function fetchPriorScheduledRuns(agentId, taskId) {
|
|
|
5475
5589
|
}
|
|
5476
5590
|
async function executeAndProcessClaudeTask(codeName, agentId, task, prompt) {
|
|
5477
5591
|
const projectDir = getProjectDir2(codeName);
|
|
5478
|
-
const mcpConfigPath =
|
|
5592
|
+
const mcpConfigPath = join5(projectDir, ".mcp.json");
|
|
5479
5593
|
let runId = null;
|
|
5480
5594
|
let kanbanItemId = null;
|
|
5481
5595
|
let taskResult;
|
|
@@ -5483,11 +5597,11 @@ async function executeAndProcessClaudeTask(codeName, agentId, task, prompt) {
|
|
|
5483
5597
|
const priorRuns = await fetchPriorScheduledRuns(agentId, task.taskId);
|
|
5484
5598
|
prompt = wrapScheduledTaskPrompt(prompt, { priorRuns });
|
|
5485
5599
|
try {
|
|
5486
|
-
const claudeMdPath =
|
|
5600
|
+
const claudeMdPath = join5(projectDir, "CLAUDE.md");
|
|
5487
5601
|
const serverNames = [];
|
|
5488
|
-
if (
|
|
5602
|
+
if (existsSync4(mcpConfigPath)) {
|
|
5489
5603
|
try {
|
|
5490
|
-
const d = JSON.parse(
|
|
5604
|
+
const d = JSON.parse(readFileSync4(mcpConfigPath, "utf-8"));
|
|
5491
5605
|
if (d.mcpServers) serverNames.push(...Object.keys(d.mcpServers));
|
|
5492
5606
|
} catch {
|
|
5493
5607
|
}
|
|
@@ -5506,14 +5620,14 @@ async function executeAndProcessClaudeTask(codeName, agentId, task, prompt) {
|
|
|
5506
5620
|
"--allowedTools",
|
|
5507
5621
|
allowedTools
|
|
5508
5622
|
];
|
|
5509
|
-
if (
|
|
5623
|
+
if (existsSync4(claudeMdPath)) {
|
|
5510
5624
|
claudeArgs.push("--system-prompt-file", claudeMdPath);
|
|
5511
5625
|
}
|
|
5512
5626
|
const childEnv = { ...process.env };
|
|
5513
|
-
const envIntPath =
|
|
5514
|
-
if (
|
|
5627
|
+
const envIntPath = join5(projectDir, ".env.integrations");
|
|
5628
|
+
if (existsSync4(envIntPath)) {
|
|
5515
5629
|
try {
|
|
5516
|
-
for (const line of
|
|
5630
|
+
for (const line of readFileSync4(envIntPath, "utf-8").split("\n")) {
|
|
5517
5631
|
if (!line || line.startsWith("#") || !line.includes("=")) continue;
|
|
5518
5632
|
const eqIdx = line.indexOf("=");
|
|
5519
5633
|
childEnv[line.slice(0, eqIdx)] = line.slice(eqIdx + 1);
|
|
@@ -5667,8 +5781,8 @@ async function processClaudeTaskResult(codeName, agentId, templateId, rawOutput,
|
|
|
5667
5781
|
}
|
|
5668
5782
|
}
|
|
5669
5783
|
function fireClaudeWorkTrigger(codeName, agentId, boardItems) {
|
|
5670
|
-
const
|
|
5671
|
-
const kanbanTask = findTaskByTemplate(
|
|
5784
|
+
const state4 = claudeSchedulerStates.get(codeName) ?? loadSchedulerState(codeName);
|
|
5785
|
+
const kanbanTask = findTaskByTemplate(state4, "kanban-work");
|
|
5672
5786
|
if (!kanbanTask) {
|
|
5673
5787
|
log(`[claude-scheduler] Work trigger: no kanban-work task found for '${codeName}'`);
|
|
5674
5788
|
return;
|
|
@@ -5691,13 +5805,14 @@ function fireClaudeWorkTrigger(codeName, agentId, boardItems) {
|
|
|
5691
5805
|
});
|
|
5692
5806
|
}
|
|
5693
5807
|
var persistentSessionAgents = /* @__PURE__ */ new Set();
|
|
5808
|
+
var lastMcpFailedBannerCount = /* @__PURE__ */ new Map();
|
|
5694
5809
|
var persistentSessionStuckTracker = new PersistentSessionStuckTracker();
|
|
5695
5810
|
var claudeAuthTupleBySession = /* @__PURE__ */ new Map();
|
|
5696
5811
|
async function ensurePersistentSession(agent, tasks, boardItems, refreshData) {
|
|
5697
5812
|
const codeName = agent.code_name;
|
|
5698
5813
|
const projectDir = getProjectDir(codeName);
|
|
5699
|
-
const mcpConfigPath =
|
|
5700
|
-
const claudeMdPath =
|
|
5814
|
+
const mcpConfigPath = join5(projectDir, ".mcp.json");
|
|
5815
|
+
const claudeMdPath = join5(projectDir, "CLAUDE.md");
|
|
5701
5816
|
if (restartBreaker.isTripped(codeName)) {
|
|
5702
5817
|
const trip = restartBreaker.getTrip(codeName);
|
|
5703
5818
|
return {
|
|
@@ -5934,9 +6049,9 @@ ${truncateForLog(ctx.tail)}` : `; pane_tail_hash=sha256:${createHash2("sha256").
|
|
|
5934
6049
|
} else if (!claudeSchedulerStates.has(codeName)) {
|
|
5935
6050
|
claudeSchedulerStates.set(codeName, loadSchedulerState(codeName));
|
|
5936
6051
|
}
|
|
5937
|
-
const
|
|
5938
|
-
if (
|
|
5939
|
-
const ready = getReadyTasks(
|
|
6052
|
+
const state4 = claudeSchedulerStates.get(codeName);
|
|
6053
|
+
if (state4) {
|
|
6054
|
+
const ready = getReadyTasks(state4, inFlightClaudeTasks);
|
|
5940
6055
|
if (ready.length > 0) {
|
|
5941
6056
|
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(", ")}`);
|
|
5942
6057
|
}
|
|
@@ -6315,11 +6430,11 @@ ${escapeXml(msg.content)}
|
|
|
6315
6430
|
if (fw === "claude-code") {
|
|
6316
6431
|
const { getProjectDir: ccProjectDir } = await import("../claude-scheduler-XHJS2MZV.js");
|
|
6317
6432
|
const projDir = ccProjectDir(agent.codeName);
|
|
6318
|
-
const mcpConfigPath =
|
|
6433
|
+
const mcpConfigPath = join5(projDir, ".mcp.json");
|
|
6319
6434
|
const serverNames = [];
|
|
6320
|
-
if (
|
|
6435
|
+
if (existsSync4(mcpConfigPath)) {
|
|
6321
6436
|
try {
|
|
6322
|
-
const d = JSON.parse(
|
|
6437
|
+
const d = JSON.parse(readFileSync4(mcpConfigPath, "utf-8"));
|
|
6323
6438
|
if (d.mcpServers) serverNames.push(...Object.keys(d.mcpServers));
|
|
6324
6439
|
} catch {
|
|
6325
6440
|
}
|
|
@@ -6338,15 +6453,15 @@ ${escapeXml(msg.content)}
|
|
|
6338
6453
|
"--allowedTools",
|
|
6339
6454
|
allowedTools
|
|
6340
6455
|
];
|
|
6341
|
-
const chatClaudeMd =
|
|
6342
|
-
if (
|
|
6456
|
+
const chatClaudeMd = join5(projDir, "CLAUDE.md");
|
|
6457
|
+
if (existsSync4(chatClaudeMd)) {
|
|
6343
6458
|
chatArgs.push("--system-prompt-file", chatClaudeMd);
|
|
6344
6459
|
}
|
|
6345
|
-
const envIntPath =
|
|
6460
|
+
const envIntPath = join5(projDir, ".env.integrations");
|
|
6346
6461
|
const childEnv = { ...process.env };
|
|
6347
|
-
if (
|
|
6462
|
+
if (existsSync4(envIntPath)) {
|
|
6348
6463
|
try {
|
|
6349
|
-
for (const line of
|
|
6464
|
+
for (const line of readFileSync4(envIntPath, "utf-8").split("\n")) {
|
|
6350
6465
|
if (!line || line.startsWith("#") || !line.includes("=")) continue;
|
|
6351
6466
|
const eqIdx = line.indexOf("=");
|
|
6352
6467
|
childEnv[line.slice(0, eqIdx)] = line.slice(eqIdx + 1);
|
|
@@ -6689,12 +6804,12 @@ function getBuiltInSkillContent(skillId) {
|
|
|
6689
6804
|
if (builtInSkillCache.has(skillId)) return builtInSkillCache.get(skillId);
|
|
6690
6805
|
try {
|
|
6691
6806
|
const candidates = [
|
|
6692
|
-
|
|
6693
|
-
|
|
6807
|
+
join5(process.cwd(), "skills", skillId, "SKILL.md"),
|
|
6808
|
+
join5(new URL(".", import.meta.url).pathname, "..", "..", "..", "..", "skills", skillId, "SKILL.md")
|
|
6694
6809
|
];
|
|
6695
6810
|
for (const candidate of candidates) {
|
|
6696
|
-
if (
|
|
6697
|
-
const content =
|
|
6811
|
+
if (existsSync4(candidate)) {
|
|
6812
|
+
const content = readFileSync4(candidate, "utf-8");
|
|
6698
6813
|
const files = [{ relativePath: "SKILL.md", content }];
|
|
6699
6814
|
builtInSkillCache.set(skillId, files);
|
|
6700
6815
|
return files;
|
|
@@ -7602,8 +7717,8 @@ function parseMemoryFile(raw, fallbackName) {
|
|
|
7602
7717
|
};
|
|
7603
7718
|
}
|
|
7604
7719
|
async function syncMemories(agent, configDir, log2) {
|
|
7605
|
-
const projectDir =
|
|
7606
|
-
const memoryDir =
|
|
7720
|
+
const projectDir = join5(configDir, agent.code_name, "project");
|
|
7721
|
+
const memoryDir = join5(projectDir, "memory");
|
|
7607
7722
|
const isFreshSync = pendingFreshMemorySync.has(agent.agent_id);
|
|
7608
7723
|
if (isFreshSync) {
|
|
7609
7724
|
log2(`[memory-sync] Fresh-sync requested for '${agent.code_name}' \u2014 pulling DB first`);
|
|
@@ -7614,14 +7729,14 @@ async function syncMemories(agent, configDir, log2) {
|
|
|
7614
7729
|
}
|
|
7615
7730
|
pendingFreshMemorySync.delete(agent.agent_id);
|
|
7616
7731
|
}
|
|
7617
|
-
if (
|
|
7732
|
+
if (existsSync4(memoryDir)) {
|
|
7618
7733
|
const prevHashes = memoryFileHashes.get(agent.agent_id) ?? /* @__PURE__ */ new Map();
|
|
7619
7734
|
const currentHashes = /* @__PURE__ */ new Map();
|
|
7620
7735
|
const changedMemories = [];
|
|
7621
7736
|
for (const file of readdirSync2(memoryDir)) {
|
|
7622
7737
|
if (!file.endsWith(".md")) continue;
|
|
7623
7738
|
try {
|
|
7624
|
-
const raw =
|
|
7739
|
+
const raw = readFileSync4(join5(memoryDir, file), "utf-8");
|
|
7625
7740
|
const fileHash = createHash2("sha256").update(raw).digest("hex").slice(0, 16);
|
|
7626
7741
|
currentHashes.set(file, fileHash);
|
|
7627
7742
|
if (prevHashes.get(file) === fileHash) continue;
|
|
@@ -7646,7 +7761,7 @@ async function syncMemories(agent, configDir, log2) {
|
|
|
7646
7761
|
} catch (err) {
|
|
7647
7762
|
for (const mem of changedMemories) {
|
|
7648
7763
|
for (const [file] of currentHashes) {
|
|
7649
|
-
const parsed = parseMemoryFile(
|
|
7764
|
+
const parsed = parseMemoryFile(readFileSync4(join5(memoryDir, file), "utf-8"), file.replace(/\.md$/, ""));
|
|
7650
7765
|
if (parsed?.name === mem.name) currentHashes.delete(file);
|
|
7651
7766
|
}
|
|
7652
7767
|
}
|
|
@@ -7659,7 +7774,7 @@ async function syncMemories(agent, configDir, log2) {
|
|
|
7659
7774
|
}
|
|
7660
7775
|
}
|
|
7661
7776
|
async function downloadMemories(agent, memoryDir, log2, { force }) {
|
|
7662
|
-
const localFiles =
|
|
7777
|
+
const localFiles = existsSync4(memoryDir) ? readdirSync2(memoryDir).filter((f) => f.endsWith(".md")).sort() : [];
|
|
7663
7778
|
const localListHash = createHash2("sha256").update(localFiles.join(",")).digest("hex").slice(0, 16);
|
|
7664
7779
|
const prevLocalHash = lastLocalFileHash.get(agent.agent_id);
|
|
7665
7780
|
const prevDownload = lastDownloadHash.get(agent.agent_id);
|
|
@@ -7681,7 +7796,7 @@ async function downloadMemories(agent, memoryDir, log2, { force }) {
|
|
|
7681
7796
|
const mem = dbMemories.memories[i];
|
|
7682
7797
|
const rawSlug = mem.name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/(^-|-$)/g, "").slice(0, 60);
|
|
7683
7798
|
const slug = rawSlug || `memory-${i}`;
|
|
7684
|
-
const filePath =
|
|
7799
|
+
const filePath = join5(memoryDir, `${slug}.md`);
|
|
7685
7800
|
const desired = `---
|
|
7686
7801
|
name: ${JSON.stringify(mem.name)}
|
|
7687
7802
|
type: ${mem.type}
|
|
@@ -7690,10 +7805,10 @@ description: ${JSON.stringify(mem.content.slice(0, 200))}
|
|
|
7690
7805
|
|
|
7691
7806
|
${mem.content}
|
|
7692
7807
|
`;
|
|
7693
|
-
if (
|
|
7808
|
+
if (existsSync4(filePath)) {
|
|
7694
7809
|
let existing = "";
|
|
7695
7810
|
try {
|
|
7696
|
-
existing =
|
|
7811
|
+
existing = readFileSync4(filePath, "utf-8");
|
|
7697
7812
|
} catch {
|
|
7698
7813
|
}
|
|
7699
7814
|
if (existing === desired) continue;
|
|
@@ -7717,7 +7832,7 @@ ${mem.content}
|
|
|
7717
7832
|
}
|
|
7718
7833
|
}
|
|
7719
7834
|
async function cleanupAgentFiles(codeName, agentDir) {
|
|
7720
|
-
if (
|
|
7835
|
+
if (existsSync4(agentDir)) {
|
|
7721
7836
|
try {
|
|
7722
7837
|
rmSync2(agentDir, { recursive: true, force: true });
|
|
7723
7838
|
log(`Removed provision directory for '${codeName}'`);
|
|
@@ -7888,12 +8003,12 @@ function startManager(opts) {
|
|
|
7888
8003
|
config = opts;
|
|
7889
8004
|
try {
|
|
7890
8005
|
const stateFile = getStateFile();
|
|
7891
|
-
if (
|
|
7892
|
-
const raw =
|
|
8006
|
+
if (existsSync4(stateFile)) {
|
|
8007
|
+
const raw = readFileSync4(stateFile, "utf-8");
|
|
7893
8008
|
const parsed = JSON.parse(raw);
|
|
7894
8009
|
if (Array.isArray(parsed.agents)) {
|
|
7895
|
-
|
|
7896
|
-
log(`[startup] rehydrated ${
|
|
8010
|
+
state3.agents = parsed.agents;
|
|
8011
|
+
log(`[startup] rehydrated ${state3.agents.length} agent state(s) from ${stateFile}`);
|
|
7897
8012
|
}
|
|
7898
8013
|
if (parsed.circuitBreakerTrips && typeof parsed.circuitBreakerTrips === "object") {
|
|
7899
8014
|
restartBreaker.hydrate(parsed.circuitBreakerTrips);
|
|
@@ -7905,7 +8020,7 @@ function startManager(opts) {
|
|
|
7905
8020
|
log(`[startup] state rehydration failed (continuing with empty state): ${err.message}`);
|
|
7906
8021
|
}
|
|
7907
8022
|
log(
|
|
7908
|
-
`[startup] worker pid=${process.pid} ppid=${process.ppid} node=${process.version} log=${
|
|
8023
|
+
`[startup] worker pid=${process.pid} ppid=${process.ppid} node=${process.version} log=${join5(homedir4(), ".augmented", "manager.log")}`
|
|
7909
8024
|
);
|
|
7910
8025
|
warnOnConflictingKanbanModes();
|
|
7911
8026
|
deployMcpAssets();
|
|
@@ -7968,14 +8083,14 @@ function restartRunningChannelMcps(basenames) {
|
|
|
7968
8083
|
}
|
|
7969
8084
|
}
|
|
7970
8085
|
function deployMcpAssets() {
|
|
7971
|
-
const targetDir =
|
|
8086
|
+
const targetDir = join5(homedir4(), ".augmented", "_mcp");
|
|
7972
8087
|
mkdirSync2(targetDir, { recursive: true });
|
|
7973
8088
|
const moduleDir = dirname(fileURLToPath(import.meta.url));
|
|
7974
8089
|
let mcpSourceDir = "";
|
|
7975
8090
|
let dir = moduleDir;
|
|
7976
8091
|
for (let i = 0; i < 6; i++) {
|
|
7977
|
-
const candidate =
|
|
7978
|
-
if (
|
|
8092
|
+
const candidate = join5(dir, "dist", "mcp");
|
|
8093
|
+
if (existsSync4(join5(candidate, "index.js"))) {
|
|
7979
8094
|
mcpSourceDir = candidate;
|
|
7980
8095
|
break;
|
|
7981
8096
|
}
|
|
@@ -7990,8 +8105,8 @@ function deployMcpAssets() {
|
|
|
7990
8105
|
const changedBasenames = [];
|
|
7991
8106
|
const fileHash = (p) => {
|
|
7992
8107
|
try {
|
|
7993
|
-
if (!
|
|
7994
|
-
return createHash2("sha256").update(
|
|
8108
|
+
if (!existsSync4(p)) return null;
|
|
8109
|
+
return createHash2("sha256").update(readFileSync4(p)).digest("hex");
|
|
7995
8110
|
} catch {
|
|
7996
8111
|
return null;
|
|
7997
8112
|
}
|
|
@@ -8002,9 +8117,9 @@ function deployMcpAssets() {
|
|
|
8002
8117
|
"telegram-channel.js"
|
|
8003
8118
|
]);
|
|
8004
8119
|
for (const file of ["index.js", "slack-channel.js", "direct-chat-channel.js", "telegram-channel.js"]) {
|
|
8005
|
-
const src =
|
|
8006
|
-
const dst =
|
|
8007
|
-
if (!
|
|
8120
|
+
const src = join5(mcpSourceDir, file);
|
|
8121
|
+
const dst = join5(targetDir, file);
|
|
8122
|
+
if (!existsSync4(src)) continue;
|
|
8008
8123
|
const before = fileHash(dst);
|
|
8009
8124
|
try {
|
|
8010
8125
|
copyFileSync(src, dst);
|
|
@@ -8021,16 +8136,16 @@ function deployMcpAssets() {
|
|
|
8021
8136
|
log(`[manager] Bundle(s) updated: ${changedBasenames.join(", ")} \u2014 signalling running instances to restart`);
|
|
8022
8137
|
restartRunningChannelMcps(changedBasenames);
|
|
8023
8138
|
}
|
|
8024
|
-
const localMcpPath =
|
|
8139
|
+
const localMcpPath = join5(targetDir, "index.js");
|
|
8025
8140
|
try {
|
|
8026
|
-
const agentsDir =
|
|
8027
|
-
if (
|
|
8141
|
+
const agentsDir = join5(homedir4(), ".augmented", "agents");
|
|
8142
|
+
if (existsSync4(agentsDir)) {
|
|
8028
8143
|
for (const entry of readdirSync2(agentsDir, { withFileTypes: true })) {
|
|
8029
8144
|
if (!entry.isDirectory()) continue;
|
|
8030
8145
|
for (const subdir of ["provision", "project"]) {
|
|
8031
|
-
const mcpJsonPath =
|
|
8146
|
+
const mcpJsonPath = join5(agentsDir, entry.name, subdir, ".mcp.json");
|
|
8032
8147
|
try {
|
|
8033
|
-
const raw =
|
|
8148
|
+
const raw = readFileSync4(mcpJsonPath, "utf-8");
|
|
8034
8149
|
if (!raw.includes("@integrity-labs/augmented-mcp")) continue;
|
|
8035
8150
|
const mcpConfig = JSON.parse(raw);
|
|
8036
8151
|
const augServer = mcpConfig.mcpServers?.["augmented"];
|