@integrity-labs/agt-cli 0.23.2 → 0.24.2
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-WUYKMPYW.js → chunk-BXLWLI2U.js} +4 -4
- package/dist/{chunk-WUYKMPYW.js.map → chunk-BXLWLI2U.js.map} +1 -1
- package/dist/{chunk-HSIESZMZ.js → chunk-ECDTRQLA.js} +89 -1
- package/dist/chunk-ECDTRQLA.js.map +1 -0
- package/dist/{chunk-ZKQGDH3T.js → chunk-PNTLQKLO.js} +7 -9
- package/dist/{chunk-ZKQGDH3T.js.map → chunk-PNTLQKLO.js.map} +1 -1
- package/dist/{claude-pair-runtime-XCFWTH6T.js → claude-pair-runtime-ZQAJOQPN.js} +2 -2
- package/dist/lib/manager-worker.js +475 -255
- 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/dist/{persistent-session-L4YIJJML.js → persistent-session-JUJY46HW.js} +3 -3
- package/dist/{responsiveness-probe-YRLESO54.js → responsiveness-probe-XOEC7J5D.js} +3 -3
- package/package.json +1 -1
- package/dist/chunk-HSIESZMZ.js.map +0 -1
- /package/dist/{claude-pair-runtime-XCFWTH6T.js.map → claude-pair-runtime-ZQAJOQPN.js.map} +0 -0
- /package/dist/{persistent-session-L4YIJJML.js.map → persistent-session-JUJY46HW.js.map} +0 -0
- /package/dist/{responsiveness-probe-YRLESO54.js.map → responsiveness-probe-XOEC7J5D.js.map} +0 -0
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
provisionOrientHook,
|
|
13
13
|
provisionStopHook,
|
|
14
14
|
requireHost
|
|
15
|
-
} from "../chunk-
|
|
15
|
+
} from "../chunk-BXLWLI2U.js";
|
|
16
16
|
import {
|
|
17
17
|
findTaskByTemplate,
|
|
18
18
|
getProjectDir as getProjectDir2,
|
|
@@ -43,11 +43,12 @@ import {
|
|
|
43
43
|
resolveClaudeBinary,
|
|
44
44
|
sanitizeMcpJson,
|
|
45
45
|
sendToAgent,
|
|
46
|
+
sessionTranscriptDir,
|
|
46
47
|
startPersistentSession,
|
|
47
48
|
stopAllSessionsAndWait,
|
|
48
49
|
stopPersistentSession,
|
|
49
50
|
takeZombieDetection
|
|
50
|
-
} from "../chunk-
|
|
51
|
+
} from "../chunk-PNTLQKLO.js";
|
|
51
52
|
import {
|
|
52
53
|
KANBAN_CHECK_COMMAND,
|
|
53
54
|
appendDmFooter,
|
|
@@ -55,23 +56,25 @@ import {
|
|
|
55
56
|
extractFrontmatter,
|
|
56
57
|
formatActorId,
|
|
57
58
|
getFramework,
|
|
59
|
+
isEmptyTotals,
|
|
58
60
|
isParseError,
|
|
59
61
|
isResolveError,
|
|
60
62
|
isSelfCompletion,
|
|
61
63
|
parseDeliveryTarget,
|
|
64
|
+
parseTranscriptUsage,
|
|
62
65
|
parseUsageBanner,
|
|
63
66
|
resolveChannels,
|
|
64
67
|
resolveDmTarget,
|
|
65
68
|
wrapScheduledTaskPrompt
|
|
66
|
-
} from "../chunk-
|
|
69
|
+
} from "../chunk-ECDTRQLA.js";
|
|
67
70
|
|
|
68
71
|
// src/lib/manager-worker.ts
|
|
69
72
|
import { createHash as createHash2 } from "crypto";
|
|
70
|
-
import { readFileSync as
|
|
73
|
+
import { readFileSync as readFileSync5, writeFileSync as writeFileSync3, appendFileSync, mkdirSync as mkdirSync2, chmodSync, existsSync as existsSync4, rmSync as rmSync2, readdirSync as readdirSync3, statSync as statSync2, unlinkSync, copyFileSync } from "fs";
|
|
71
74
|
import https from "https";
|
|
72
75
|
import { execFileSync as syncExecFile } from "child_process";
|
|
73
|
-
import { join as
|
|
74
|
-
import { homedir as
|
|
76
|
+
import { join as join6, dirname } from "path";
|
|
77
|
+
import { homedir as homedir4 } from "os";
|
|
75
78
|
import { fileURLToPath } from "url";
|
|
76
79
|
|
|
77
80
|
// src/lib/mcp-config-drift.ts
|
|
@@ -435,12 +438,12 @@ function reapMissingMcpSessions(args) {
|
|
|
435
438
|
if (!missingRaw.includes(key)) liveKeys.add(key);
|
|
436
439
|
}
|
|
437
440
|
for (const key of liveKeys) {
|
|
438
|
-
const
|
|
439
|
-
if (
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
441
|
+
const state5 = presenceReaperState.get(stateKey(codeName, key));
|
|
442
|
+
if (state5) {
|
|
443
|
+
state5.attempts = 0;
|
|
444
|
+
state5.lastSeenLiveAt = now();
|
|
445
|
+
state5.lastAttemptedSessionStartedAt = null;
|
|
446
|
+
state5.gaveUpLogged = false;
|
|
444
447
|
}
|
|
445
448
|
}
|
|
446
449
|
if (missing.length === 0) {
|
|
@@ -455,24 +458,24 @@ function reapMissingMcpSessions(args) {
|
|
|
455
458
|
const active = [];
|
|
456
459
|
for (const key of missing) {
|
|
457
460
|
const sk = stateKey(codeName, key);
|
|
458
|
-
const
|
|
461
|
+
const state5 = presenceReaperState.get(sk) ?? {
|
|
459
462
|
attempts: 0,
|
|
460
463
|
lastSeenLiveAt: null,
|
|
461
464
|
lastAttemptedSessionStartedAt: null,
|
|
462
465
|
gaveUpLogged: false
|
|
463
466
|
};
|
|
464
|
-
if (
|
|
465
|
-
|
|
466
|
-
|
|
467
|
+
if (state5.lastAttemptedSessionStartedAt !== sessionStartedAt) {
|
|
468
|
+
state5.attempts += 1;
|
|
469
|
+
state5.lastAttemptedSessionStartedAt = sessionStartedAt;
|
|
467
470
|
}
|
|
468
|
-
presenceReaperState.set(sk,
|
|
469
|
-
if (
|
|
471
|
+
presenceReaperState.set(sk, state5);
|
|
472
|
+
if (state5.attempts > MAX_PRESENCE_RESTART_ATTEMPTS) {
|
|
470
473
|
givenUp.push(key);
|
|
471
|
-
if (!
|
|
474
|
+
if (!state5.gaveUpLogged) {
|
|
472
475
|
log2(
|
|
473
476
|
`[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
477
|
);
|
|
475
|
-
|
|
478
|
+
state5.gaveUpLogged = true;
|
|
476
479
|
if (onGiveUp) {
|
|
477
480
|
try {
|
|
478
481
|
onGiveUp(codeName, key);
|
|
@@ -710,6 +713,175 @@ async function maybeReportUsageBanner(args) {
|
|
|
710
713
|
}
|
|
711
714
|
}
|
|
712
715
|
|
|
716
|
+
// src/lib/token-usage-monitor.ts
|
|
717
|
+
import { readdirSync, readFileSync, statSync } from "fs";
|
|
718
|
+
import { join } from "path";
|
|
719
|
+
var MIN_CHECK_INTERVAL_MS2 = 6e4;
|
|
720
|
+
var TRANSCRIPT_MTIME_WINDOW_MS = 2 * 24 * 60 * 60 * 1e3;
|
|
721
|
+
var MAX_ENTRIES_PER_POST = 200;
|
|
722
|
+
var state2 = /* @__PURE__ */ new Map();
|
|
723
|
+
async function maybeReportTokenUsage(args) {
|
|
724
|
+
const { api: api2, codeName, agentId, log: log2 } = args;
|
|
725
|
+
const now = args.now ?? /* @__PURE__ */ new Date();
|
|
726
|
+
const nowMs = now.getTime();
|
|
727
|
+
const existing = state2.get(codeName);
|
|
728
|
+
if (existing && nowMs - existing.lastCheckedAt < MIN_CHECK_INTERVAL_MS2) {
|
|
729
|
+
return;
|
|
730
|
+
}
|
|
731
|
+
const dir = args.transcriptDir ?? sessionTranscriptDir(getProjectDir(codeName));
|
|
732
|
+
const files = existing?.files ?? /* @__PURE__ */ new Map();
|
|
733
|
+
const next = { files, lastCheckedAt: nowMs };
|
|
734
|
+
let dirEntries;
|
|
735
|
+
try {
|
|
736
|
+
dirEntries = readdirSync(dir);
|
|
737
|
+
} catch {
|
|
738
|
+
state2.set(codeName, next);
|
|
739
|
+
return;
|
|
740
|
+
}
|
|
741
|
+
const pending = [];
|
|
742
|
+
for (const name of dirEntries) {
|
|
743
|
+
if (!name.endsWith(".jsonl")) continue;
|
|
744
|
+
const sessionId = name.slice(0, -".jsonl".length);
|
|
745
|
+
if (!sessionId) continue;
|
|
746
|
+
const path = join(dir, name);
|
|
747
|
+
let st;
|
|
748
|
+
try {
|
|
749
|
+
st = statSync(path);
|
|
750
|
+
} catch {
|
|
751
|
+
continue;
|
|
752
|
+
}
|
|
753
|
+
if (!st.isFile()) continue;
|
|
754
|
+
if (nowMs - st.mtimeMs > TRANSCRIPT_MTIME_WINDOW_MS) continue;
|
|
755
|
+
const fp = { mtimeMs: st.mtimeMs, size: st.size };
|
|
756
|
+
const seen = files.get(sessionId);
|
|
757
|
+
if (seen && seen.mtimeMs === fp.mtimeMs && seen.size === fp.size) {
|
|
758
|
+
continue;
|
|
759
|
+
}
|
|
760
|
+
let content;
|
|
761
|
+
try {
|
|
762
|
+
content = readFileSync(path, "utf-8");
|
|
763
|
+
} catch (err) {
|
|
764
|
+
log2(`[token-usage] read failed for '${codeName}/${name}': ${err.message}`);
|
|
765
|
+
continue;
|
|
766
|
+
}
|
|
767
|
+
const parsed = parseTranscriptUsage(content);
|
|
768
|
+
for (const [model, totals] of parsed.byModel) {
|
|
769
|
+
if (isEmptyTotals(totals)) continue;
|
|
770
|
+
pending.push({
|
|
771
|
+
sessionId,
|
|
772
|
+
fp,
|
|
773
|
+
entry: {
|
|
774
|
+
session_id: sessionId,
|
|
775
|
+
model,
|
|
776
|
+
input_tokens: totals.inputTokens,
|
|
777
|
+
output_tokens: totals.outputTokens,
|
|
778
|
+
cache_creation_tokens: totals.cacheCreationTokens,
|
|
779
|
+
cache_read_tokens: totals.cacheReadTokens,
|
|
780
|
+
session_started_at: parsed.sessionStartedAt,
|
|
781
|
+
last_observed_at: parsed.lastObservedAt
|
|
782
|
+
}
|
|
783
|
+
});
|
|
784
|
+
}
|
|
785
|
+
if (![...parsed.byModel.values()].some((t) => !isEmptyTotals(t))) {
|
|
786
|
+
files.set(sessionId, fp);
|
|
787
|
+
}
|
|
788
|
+
}
|
|
789
|
+
if (pending.length === 0) {
|
|
790
|
+
state2.set(codeName, next);
|
|
791
|
+
return;
|
|
792
|
+
}
|
|
793
|
+
for (let i = 0; i < pending.length; i += MAX_ENTRIES_PER_POST) {
|
|
794
|
+
const batch = pending.slice(i, i + MAX_ENTRIES_PER_POST);
|
|
795
|
+
try {
|
|
796
|
+
await api2.post("/host/token-usage", {
|
|
797
|
+
agent_id: agentId,
|
|
798
|
+
framework: "claude-code",
|
|
799
|
+
source: "transcript_jsonl",
|
|
800
|
+
entries: batch.map((b) => b.entry)
|
|
801
|
+
});
|
|
802
|
+
for (const b of batch) {
|
|
803
|
+
files.set(b.sessionId, b.fp);
|
|
804
|
+
}
|
|
805
|
+
} catch (err) {
|
|
806
|
+
log2(`[token-usage] POST failed for '${codeName}': ${err.message}`);
|
|
807
|
+
}
|
|
808
|
+
}
|
|
809
|
+
state2.set(codeName, next);
|
|
810
|
+
}
|
|
811
|
+
|
|
812
|
+
// src/lib/activity-cache-monitor.ts
|
|
813
|
+
import { existsSync, readFileSync as readFileSync2 } from "fs";
|
|
814
|
+
import { homedir } from "os";
|
|
815
|
+
import { join as join2 } from "path";
|
|
816
|
+
var MIN_CHECK_INTERVAL_MS3 = 6e4;
|
|
817
|
+
var STATS_CACHE_PATH = join2(homedir(), ".claude", "stats-cache.json");
|
|
818
|
+
var ISO_DATE_RE = /^\d{4}-\d{2}-\d{2}$/;
|
|
819
|
+
var state3 = { lastObservedDate: null, lastCheckedAt: 0 };
|
|
820
|
+
function selectNewDailyRows(raw, lastObservedDate) {
|
|
821
|
+
let parsed;
|
|
822
|
+
try {
|
|
823
|
+
parsed = JSON.parse(raw);
|
|
824
|
+
} catch {
|
|
825
|
+
return [];
|
|
826
|
+
}
|
|
827
|
+
const days = Array.isArray(parsed.dailyActivity) ? parsed.dailyActivity : [];
|
|
828
|
+
const nonNegInt = (v) => {
|
|
829
|
+
if (typeof v !== "number" || !Number.isFinite(v)) return null;
|
|
830
|
+
const n = Math.trunc(v);
|
|
831
|
+
return n >= 0 ? n : null;
|
|
832
|
+
};
|
|
833
|
+
const result = [];
|
|
834
|
+
for (const d of days) {
|
|
835
|
+
if (typeof d.date !== "string" || !ISO_DATE_RE.test(d.date)) continue;
|
|
836
|
+
if (lastObservedDate !== null && d.date <= lastObservedDate) continue;
|
|
837
|
+
const m = nonNegInt(d.messageCount);
|
|
838
|
+
const s = nonNegInt(d.sessionCount);
|
|
839
|
+
const t = nonNegInt(d.toolCallCount);
|
|
840
|
+
if (m === null || s === null || t === null) continue;
|
|
841
|
+
const breakdownForDay = parsed.dailyModelTokens?.[d.date];
|
|
842
|
+
const model_breakdown = breakdownForDay && typeof breakdownForDay === "object" && !Array.isArray(breakdownForDay) ? breakdownForDay : null;
|
|
843
|
+
result.push({
|
|
844
|
+
date: d.date,
|
|
845
|
+
message_count: m,
|
|
846
|
+
session_count: s,
|
|
847
|
+
tool_call_count: t,
|
|
848
|
+
model_breakdown
|
|
849
|
+
});
|
|
850
|
+
}
|
|
851
|
+
result.sort((a, b) => a.date.localeCompare(b.date));
|
|
852
|
+
return result;
|
|
853
|
+
}
|
|
854
|
+
async function maybeReportActivityCache(args) {
|
|
855
|
+
const { api: api2, log: log2 } = args;
|
|
856
|
+
const now = args.now ?? /* @__PURE__ */ new Date();
|
|
857
|
+
const nowMs = now.getTime();
|
|
858
|
+
if (nowMs - state3.lastCheckedAt < MIN_CHECK_INTERVAL_MS3) return;
|
|
859
|
+
state3.lastCheckedAt = nowMs;
|
|
860
|
+
if (!existsSync(STATS_CACHE_PATH)) {
|
|
861
|
+
return;
|
|
862
|
+
}
|
|
863
|
+
let raw;
|
|
864
|
+
try {
|
|
865
|
+
raw = readFileSync2(STATS_CACHE_PATH, "utf-8");
|
|
866
|
+
} catch (err) {
|
|
867
|
+
log2(`[activity-cache] readFileSync failed: ${err.message}`);
|
|
868
|
+
return;
|
|
869
|
+
}
|
|
870
|
+
const rows = selectNewDailyRows(raw, state3.lastObservedDate);
|
|
871
|
+
if (rows.length === 0) return;
|
|
872
|
+
for (const row of rows) {
|
|
873
|
+
try {
|
|
874
|
+
await api2.post("/host/activity-observations", row);
|
|
875
|
+
state3.lastObservedDate = row.date;
|
|
876
|
+
} catch (err) {
|
|
877
|
+
log2(
|
|
878
|
+
`[activity-cache] POST /host/activity-observations failed for date=${row.date}: ${err.message}`
|
|
879
|
+
);
|
|
880
|
+
return;
|
|
881
|
+
}
|
|
882
|
+
}
|
|
883
|
+
}
|
|
884
|
+
|
|
713
885
|
// src/lib/poll-backoff.ts
|
|
714
886
|
var POLL_BACKOFF_BASE_MS = 1e3;
|
|
715
887
|
var POLL_BACKOFF_MAX_MS = 6e4;
|
|
@@ -1139,8 +1311,8 @@ var GatewayClientPool = class extends EventEmitter {
|
|
|
1139
1311
|
|
|
1140
1312
|
// src/lib/claude-auth-detect.ts
|
|
1141
1313
|
import { readFile, readdir } from "fs/promises";
|
|
1142
|
-
import { homedir, platform } from "os";
|
|
1143
|
-
import { join } from "path";
|
|
1314
|
+
import { homedir as homedir2, platform } from "os";
|
|
1315
|
+
import { join as join3 } from "path";
|
|
1144
1316
|
import { execFile } from "child_process";
|
|
1145
1317
|
import { promisify } from "util";
|
|
1146
1318
|
var execFileAsync = promisify(execFile);
|
|
@@ -1155,8 +1327,8 @@ async function detectClaudeAuth() {
|
|
|
1155
1327
|
}
|
|
1156
1328
|
async function findClaudeCredentialsPaths() {
|
|
1157
1329
|
const candidates = [
|
|
1158
|
-
|
|
1159
|
-
|
|
1330
|
+
join3(homedir2(), ".claude", ".credentials.json"),
|
|
1331
|
+
join3(homedir2(), ".claude", "credentials.json")
|
|
1160
1332
|
];
|
|
1161
1333
|
const isLinuxRoot = platform() === "linux" && typeof process.getuid === "function" && process.getuid() === 0;
|
|
1162
1334
|
if (isLinuxRoot) {
|
|
@@ -1164,8 +1336,8 @@ async function findClaudeCredentialsPaths() {
|
|
|
1164
1336
|
const entries = await readdir("/home", { withFileTypes: true });
|
|
1165
1337
|
for (const entry of entries) {
|
|
1166
1338
|
if (!entry.isDirectory()) continue;
|
|
1167
|
-
candidates.push(
|
|
1168
|
-
candidates.push(
|
|
1339
|
+
candidates.push(join3("/home", entry.name, ".claude", ".credentials.json"));
|
|
1340
|
+
candidates.push(join3("/home", entry.name, ".claude", "credentials.json"));
|
|
1169
1341
|
}
|
|
1170
1342
|
} catch {
|
|
1171
1343
|
}
|
|
@@ -1257,18 +1429,18 @@ function normalize(value) {
|
|
|
1257
1429
|
}
|
|
1258
1430
|
|
|
1259
1431
|
// src/lib/channel-hash-cache.ts
|
|
1260
|
-
import { existsSync, readFileSync, writeFileSync } from "fs";
|
|
1261
|
-
import { join as
|
|
1432
|
+
import { existsSync as existsSync2, readFileSync as readFileSync3, writeFileSync } from "fs";
|
|
1433
|
+
import { join as join4 } from "path";
|
|
1262
1434
|
var CACHE_FILENAME = "channel-hash-cache.json";
|
|
1263
1435
|
function getChannelHashCacheFile(configDir) {
|
|
1264
|
-
return
|
|
1436
|
+
return join4(configDir, CACHE_FILENAME);
|
|
1265
1437
|
}
|
|
1266
1438
|
function loadChannelHashCache(target, configDir) {
|
|
1267
1439
|
const path = getChannelHashCacheFile(configDir);
|
|
1268
|
-
if (!
|
|
1440
|
+
if (!existsSync2(path)) return;
|
|
1269
1441
|
let parsed;
|
|
1270
1442
|
try {
|
|
1271
|
-
parsed = JSON.parse(
|
|
1443
|
+
parsed = JSON.parse(readFileSync3(path, "utf-8"));
|
|
1272
1444
|
} catch {
|
|
1273
1445
|
return;
|
|
1274
1446
|
}
|
|
@@ -1741,24 +1913,24 @@ function withScheduleLinkFooter(opts) {
|
|
|
1741
1913
|
}
|
|
1742
1914
|
|
|
1743
1915
|
// src/lib/restart-flags.ts
|
|
1744
|
-
import { existsSync as
|
|
1745
|
-
import { homedir as
|
|
1746
|
-
import { join as
|
|
1916
|
+
import { existsSync as existsSync3, mkdirSync, readdirSync as readdirSync2, readFileSync as readFileSync4, renameSync, rmSync, writeFileSync as writeFileSync2 } from "fs";
|
|
1917
|
+
import { homedir as homedir3 } from "os";
|
|
1918
|
+
import { join as join5 } from "path";
|
|
1747
1919
|
import { randomUUID } from "crypto";
|
|
1748
1920
|
function restartFlagsDir() {
|
|
1749
|
-
return
|
|
1921
|
+
return join5(homedir3(), ".augmented", "restart-flags");
|
|
1750
1922
|
}
|
|
1751
1923
|
function flagPath(codeName) {
|
|
1752
|
-
return
|
|
1924
|
+
return join5(restartFlagsDir(), `${codeName}.flag`);
|
|
1753
1925
|
}
|
|
1754
1926
|
function readRestartFlags() {
|
|
1755
1927
|
const dir = restartFlagsDir();
|
|
1756
|
-
if (!
|
|
1928
|
+
if (!existsSync3(dir)) return [];
|
|
1757
1929
|
const out = [];
|
|
1758
|
-
for (const entry of
|
|
1930
|
+
for (const entry of readdirSync2(dir)) {
|
|
1759
1931
|
if (!entry.endsWith(".flag")) continue;
|
|
1760
1932
|
try {
|
|
1761
|
-
const raw =
|
|
1933
|
+
const raw = readFileSync4(join5(dir, entry), "utf8");
|
|
1762
1934
|
const parsed = JSON.parse(raw);
|
|
1763
1935
|
if (typeof parsed.codeName !== "string" || parsed.codeName.length === 0) {
|
|
1764
1936
|
parsed.codeName = entry.replace(/\.flag$/, "");
|
|
@@ -1776,7 +1948,7 @@ function readRestartFlags() {
|
|
|
1776
1948
|
}
|
|
1777
1949
|
function deleteRestartFlag(codeName) {
|
|
1778
1950
|
const path = flagPath(codeName);
|
|
1779
|
-
if (
|
|
1951
|
+
if (existsSync3(path)) {
|
|
1780
1952
|
rmSync(path, { force: true });
|
|
1781
1953
|
}
|
|
1782
1954
|
}
|
|
@@ -2274,8 +2446,8 @@ function applyRestartAcks(args) {
|
|
|
2274
2446
|
var GATEWAY_PORT_BASE = 18800;
|
|
2275
2447
|
var GATEWAY_PORT_STEP = 10;
|
|
2276
2448
|
var GATEWAY_PORT_MAX = 18899;
|
|
2277
|
-
var AUGMENTED_DIR =
|
|
2278
|
-
var GATEWAY_PORTS_FILE =
|
|
2449
|
+
var AUGMENTED_DIR = join6(process.env["HOME"] ?? "/tmp", ".augmented");
|
|
2450
|
+
var GATEWAY_PORTS_FILE = join6(AUGMENTED_DIR, "gateway-ports.json");
|
|
2279
2451
|
var CHANNEL_SWEEP_INTERVAL_MS = (() => {
|
|
2280
2452
|
const raw = parseInt(process.env["AGT_CHANNEL_SWEEP_INTERVAL_MS"] ?? "", 10);
|
|
2281
2453
|
if (!Number.isFinite(raw)) return 5 * 60 * 1e3;
|
|
@@ -2382,8 +2554,8 @@ var KNOWN_SAFE_TAIL_SIGNATURES = /* @__PURE__ */ new Set(["session_id_in_use"]);
|
|
|
2382
2554
|
function shouldSkipRevokedCleanup(previousKnownStatus) {
|
|
2383
2555
|
return previousKnownStatus === "revoked";
|
|
2384
2556
|
}
|
|
2385
|
-
function hasRevokedResiduals(
|
|
2386
|
-
return
|
|
2557
|
+
function hasRevokedResiduals(state5) {
|
|
2558
|
+
return state5.gatewayRunning || state5.portAllocated || state5.provisionDirExists;
|
|
2387
2559
|
}
|
|
2388
2560
|
var knownVersions = /* @__PURE__ */ new Map();
|
|
2389
2561
|
var knownStatuses = /* @__PURE__ */ new Map();
|
|
@@ -2449,7 +2621,7 @@ var runningMcpHashes = /* @__PURE__ */ new Map();
|
|
|
2449
2621
|
var runningMcpServerKeys = /* @__PURE__ */ new Map();
|
|
2450
2622
|
function projectMcpHash(_codeName, projectDir) {
|
|
2451
2623
|
try {
|
|
2452
|
-
const raw =
|
|
2624
|
+
const raw = readFileSync5(join6(projectDir, ".mcp.json"), "utf-8");
|
|
2453
2625
|
return createHash2("sha256").update(canonicalJson(JSON.parse(raw))).digest("hex");
|
|
2454
2626
|
} catch {
|
|
2455
2627
|
return null;
|
|
@@ -2457,7 +2629,7 @@ function projectMcpHash(_codeName, projectDir) {
|
|
|
2457
2629
|
}
|
|
2458
2630
|
function projectMcpKeys(_codeName, projectDir) {
|
|
2459
2631
|
try {
|
|
2460
|
-
const raw =
|
|
2632
|
+
const raw = readFileSync5(join6(projectDir, ".mcp.json"), "utf-8");
|
|
2461
2633
|
const parsed = JSON.parse(raw);
|
|
2462
2634
|
const servers = parsed.mcpServers;
|
|
2463
2635
|
if (!servers || typeof servers !== "object") return /* @__PURE__ */ new Set();
|
|
@@ -2554,7 +2726,7 @@ var codeNameToAgentId = /* @__PURE__ */ new Map();
|
|
|
2554
2726
|
var agentChannelTokens = /* @__PURE__ */ new Map();
|
|
2555
2727
|
var activeChannels = /* @__PURE__ */ new Map();
|
|
2556
2728
|
var gatewaysStartedThisCycle = /* @__PURE__ */ new Set();
|
|
2557
|
-
var
|
|
2729
|
+
var state4 = {
|
|
2558
2730
|
pid: process.pid,
|
|
2559
2731
|
startedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2560
2732
|
lastPollAt: null,
|
|
@@ -2588,6 +2760,7 @@ function clearAgentCaches(agentId, codeName) {
|
|
|
2588
2760
|
lastHarvestAt.delete(codeName);
|
|
2589
2761
|
claudeSchedulerStates.delete(codeName);
|
|
2590
2762
|
claudeTaskConcurrency.delete(codeName);
|
|
2763
|
+
lastMcpFailedBannerCount.delete(codeName);
|
|
2591
2764
|
memoryFileHashes.delete(agentId);
|
|
2592
2765
|
lastDownloadHash.delete(agentId);
|
|
2593
2766
|
lastLocalFileHash.delete(agentId);
|
|
@@ -2610,7 +2783,7 @@ var cachedFrameworkVersion = null;
|
|
|
2610
2783
|
var lastVersionCheckAt = 0;
|
|
2611
2784
|
var VERSION_CHECK_INTERVAL_MS = 5 * 60 * 1e3;
|
|
2612
2785
|
var lastResponsivenessProbeAt = 0;
|
|
2613
|
-
var agtCliVersion = true ? "0.
|
|
2786
|
+
var agtCliVersion = true ? "0.24.2" : "dev";
|
|
2614
2787
|
function resolveBrewPath(execFileSync4) {
|
|
2615
2788
|
try {
|
|
2616
2789
|
const out = execFileSync4("which", ["brew"], { timeout: 5e3 }).toString().trim();
|
|
@@ -2623,7 +2796,7 @@ function resolveBrewPath(execFileSync4) {
|
|
|
2623
2796
|
"/usr/local/bin/brew"
|
|
2624
2797
|
];
|
|
2625
2798
|
for (const path of fallbacks) {
|
|
2626
|
-
if (
|
|
2799
|
+
if (existsSync4(path)) return path;
|
|
2627
2800
|
}
|
|
2628
2801
|
return null;
|
|
2629
2802
|
}
|
|
@@ -2633,7 +2806,7 @@ function claudeBinaryInstalled(execFileSync4) {
|
|
|
2633
2806
|
"/opt/homebrew/bin/claude",
|
|
2634
2807
|
"/usr/local/bin/claude"
|
|
2635
2808
|
];
|
|
2636
|
-
if (canonical.some((path) =>
|
|
2809
|
+
if (canonical.some((path) => existsSync4(path))) return true;
|
|
2637
2810
|
try {
|
|
2638
2811
|
execFileSync4("which", ["claude"], { timeout: 5e3 });
|
|
2639
2812
|
return true;
|
|
@@ -2815,7 +2988,7 @@ async function ensureFrameworkBinary(frameworkId) {
|
|
|
2815
2988
|
if (!process.env.PATH?.split(":").includes(brewBinDir)) {
|
|
2816
2989
|
process.env.PATH = `${brewBinDir}:${process.env.PATH ?? ""}`;
|
|
2817
2990
|
}
|
|
2818
|
-
if (
|
|
2991
|
+
if (existsSync4("/home/linuxbrew/.linuxbrew/bin/claude")) {
|
|
2819
2992
|
log("Claude Code installed successfully");
|
|
2820
2993
|
} else {
|
|
2821
2994
|
log("Claude Code install completed but binary not found at expected path \u2014 check brew logs");
|
|
@@ -2827,7 +3000,7 @@ async function ensureFrameworkBinary(frameworkId) {
|
|
|
2827
3000
|
var CLAUDE_CODE_UPGRADE_CHECK_INTERVAL_MS = 24 * 60 * 60 * 1e3;
|
|
2828
3001
|
var claudeCodeUpgradeInFlight = false;
|
|
2829
3002
|
function claudeCodeUpgradeMarkerPath() {
|
|
2830
|
-
return
|
|
3003
|
+
return join6(homedir4(), ".augmented", ".last-claude-code-upgrade-check");
|
|
2831
3004
|
}
|
|
2832
3005
|
function stampClaudeCodeUpgradeMarker() {
|
|
2833
3006
|
try {
|
|
@@ -2837,7 +3010,7 @@ function stampClaudeCodeUpgradeMarker() {
|
|
|
2837
3010
|
}
|
|
2838
3011
|
function claudeCodeUpgradeThrottled() {
|
|
2839
3012
|
try {
|
|
2840
|
-
const lastCheck = parseInt(
|
|
3013
|
+
const lastCheck = parseInt(readFileSync5(claudeCodeUpgradeMarkerPath(), "utf-8").trim(), 10);
|
|
2841
3014
|
if (!Number.isFinite(lastCheck)) return false;
|
|
2842
3015
|
return Date.now() - lastCheck < CLAUDE_CODE_UPGRADE_CHECK_INTERVAL_MS;
|
|
2843
3016
|
} catch {
|
|
@@ -2907,7 +3080,7 @@ async function checkAndUpdateCli() {
|
|
|
2907
3080
|
const isNpmGlobal = !isBrewFormula && resolvedPath.includes("node_modules");
|
|
2908
3081
|
if (!isBrewFormula && !isNpmGlobal) return;
|
|
2909
3082
|
const { readFileSync: readF, writeFileSync: writeF } = await import("fs");
|
|
2910
|
-
const markerPath =
|
|
3083
|
+
const markerPath = join6(homedir4(), ".augmented", ".last-update-check");
|
|
2911
3084
|
try {
|
|
2912
3085
|
const lastCheck = parseInt(readF(markerPath, "utf-8").trim(), 10);
|
|
2913
3086
|
if (Date.now() - lastCheck < UPDATE_CHECK_INTERVAL_MS) return;
|
|
@@ -2972,17 +3145,18 @@ async function checkAndUpdateCliViaBrew() {
|
|
|
2972
3145
|
async function checkAndUpdateCliViaNpm() {
|
|
2973
3146
|
const { execFileSync: execFileSync4 } = await import("child_process");
|
|
2974
3147
|
if (agtCliVersion === "dev") return;
|
|
3148
|
+
const channel = process.env.AGT_CLI_RELEASE_CHANNEL || "latest";
|
|
2975
3149
|
let latest;
|
|
2976
3150
|
try {
|
|
2977
3151
|
const res = await fetch(
|
|
2978
|
-
|
|
3152
|
+
`https://registry.npmjs.org/@integrity-labs/agt-cli/${encodeURIComponent(channel)}`,
|
|
2979
3153
|
{
|
|
2980
3154
|
signal: AbortSignal.timeout(1e4),
|
|
2981
3155
|
headers: { Accept: "application/json" }
|
|
2982
3156
|
}
|
|
2983
3157
|
);
|
|
2984
3158
|
if (!res.ok) {
|
|
2985
|
-
log(`[self-update] npm registry returned ${res.status}`);
|
|
3159
|
+
log(`[self-update] npm registry returned ${res.status} (channel=${channel})`);
|
|
2986
3160
|
return;
|
|
2987
3161
|
}
|
|
2988
3162
|
const body = await res.json();
|
|
@@ -2995,14 +3169,15 @@ async function checkAndUpdateCliViaNpm() {
|
|
|
2995
3169
|
log(`[self-update] npm registry fetch failed: ${err.message}`);
|
|
2996
3170
|
return;
|
|
2997
3171
|
}
|
|
2998
|
-
|
|
3172
|
+
const shouldUpdate = channel === "latest" ? isNewerSemver(agtCliVersion, latest) : latest !== agtCliVersion;
|
|
3173
|
+
if (!shouldUpdate) {
|
|
2999
3174
|
if (!selfUpdateUpToDateLogged) {
|
|
3000
|
-
log(`[self-update] agt CLI is up to date (npm, ${agtCliVersion})`);
|
|
3175
|
+
log(`[self-update] agt CLI is up to date (npm, channel=${channel}, ${agtCliVersion})`);
|
|
3001
3176
|
selfUpdateUpToDateLogged = true;
|
|
3002
3177
|
}
|
|
3003
3178
|
return;
|
|
3004
3179
|
}
|
|
3005
|
-
log(`[self-update] agt CLI update available: ${agtCliVersion} \u2192 ${latest}. Upgrading via npm...`);
|
|
3180
|
+
log(`[self-update] agt CLI update available: ${agtCliVersion} \u2192 ${latest} (channel=${channel}). Upgrading via npm...`);
|
|
3006
3181
|
const isRoot = typeof process.getuid === "function" && process.getuid() === 0;
|
|
3007
3182
|
const cmd = isRoot ? "npm" : "sudo";
|
|
3008
3183
|
const args = isRoot ? [
|
|
@@ -3069,10 +3244,10 @@ async function applyClaudeAuthToEnv(childEnv, label) {
|
|
|
3069
3244
|
throw new Error("claude_auth_mode=api_key but /host/exchange returned no decrypted key");
|
|
3070
3245
|
}
|
|
3071
3246
|
childEnv.ANTHROPIC_API_KEY = exchange.anthropicApiKey;
|
|
3072
|
-
const claudeDir =
|
|
3247
|
+
const claudeDir = join6(homedir4(), ".claude");
|
|
3073
3248
|
for (const filename of [".credentials.json", "credentials.json"]) {
|
|
3074
|
-
const p =
|
|
3075
|
-
if (
|
|
3249
|
+
const p = join6(claudeDir, filename);
|
|
3250
|
+
if (existsSync4(p)) {
|
|
3076
3251
|
try {
|
|
3077
3252
|
rmSync2(p, { force: true });
|
|
3078
3253
|
log(`[${label}] Removed ${p} (api_key mode \u2014 preventing OAuth fallback)`);
|
|
@@ -3086,7 +3261,7 @@ async function applyClaudeAuthToEnv(childEnv, label) {
|
|
|
3086
3261
|
}
|
|
3087
3262
|
function loadGatewayPorts() {
|
|
3088
3263
|
try {
|
|
3089
|
-
return JSON.parse(
|
|
3264
|
+
return JSON.parse(readFileSync5(GATEWAY_PORTS_FILE, "utf-8"));
|
|
3090
3265
|
} catch {
|
|
3091
3266
|
return {};
|
|
3092
3267
|
}
|
|
@@ -3116,10 +3291,10 @@ function freePort(codeName) {
|
|
|
3116
3291
|
}
|
|
3117
3292
|
}
|
|
3118
3293
|
function getStateFile() {
|
|
3119
|
-
return
|
|
3294
|
+
return join6(config?.configDir ?? join6(process.env["HOME"] ?? "/tmp", ".augmented"), "manager-state.json");
|
|
3120
3295
|
}
|
|
3121
3296
|
function channelHashCacheDir() {
|
|
3122
|
-
return config?.configDir ??
|
|
3297
|
+
return config?.configDir ?? join6(process.env["HOME"] ?? "/tmp", ".augmented");
|
|
3123
3298
|
}
|
|
3124
3299
|
function loadChannelHashCache2() {
|
|
3125
3300
|
loadChannelHashCache(knownChannelConfigHashes, channelHashCacheDir());
|
|
@@ -3161,9 +3336,9 @@ function log(msg) {
|
|
|
3161
3336
|
`;
|
|
3162
3337
|
if (!managerLogPath) {
|
|
3163
3338
|
try {
|
|
3164
|
-
managerLogPath =
|
|
3339
|
+
managerLogPath = join6(homedir4(), ".augmented", "manager.log");
|
|
3165
3340
|
mkdirSync2(dirname(managerLogPath), { recursive: true });
|
|
3166
|
-
if (
|
|
3341
|
+
if (existsSync4(managerLogPath)) {
|
|
3167
3342
|
chmodSync(managerLogPath, 384);
|
|
3168
3343
|
}
|
|
3169
3344
|
} catch {
|
|
@@ -3191,7 +3366,7 @@ function sha256(content) {
|
|
|
3191
3366
|
}
|
|
3192
3367
|
function hashFile(filePath) {
|
|
3193
3368
|
try {
|
|
3194
|
-
const content =
|
|
3369
|
+
const content = readFileSync5(filePath, "utf-8");
|
|
3195
3370
|
return sha256(content);
|
|
3196
3371
|
} catch {
|
|
3197
3372
|
return null;
|
|
@@ -3215,13 +3390,13 @@ function parseSkillFrontmatter(content) {
|
|
|
3215
3390
|
return out;
|
|
3216
3391
|
}
|
|
3217
3392
|
async function refreshSkillsIndexInClaudeMd(configDir, codeName, log2) {
|
|
3218
|
-
const { readdirSync:
|
|
3219
|
-
const skillsDir =
|
|
3220
|
-
const claudeMdPath =
|
|
3393
|
+
const { readdirSync: readdirSync4, readFileSync: rfs, existsSync: ex, writeFileSync: writeFileSync4 } = await import("fs");
|
|
3394
|
+
const skillsDir = join6(configDir, codeName, "project", ".claude", "skills");
|
|
3395
|
+
const claudeMdPath = join6(configDir, codeName, "project", "CLAUDE.md");
|
|
3221
3396
|
if (!ex(skillsDir) || !ex(claudeMdPath)) return;
|
|
3222
3397
|
const entries = [];
|
|
3223
|
-
for (const dir of
|
|
3224
|
-
const skillFile =
|
|
3398
|
+
for (const dir of readdirSync4(skillsDir).sort()) {
|
|
3399
|
+
const skillFile = join6(skillsDir, dir, "SKILL.md");
|
|
3225
3400
|
if (!ex(skillFile)) continue;
|
|
3226
3401
|
try {
|
|
3227
3402
|
const { name, description } = parseSkillFrontmatter(rfs(skillFile, "utf-8"));
|
|
@@ -3269,10 +3444,10 @@ ${SKILLS_INDEX_END}`;
|
|
|
3269
3444
|
}
|
|
3270
3445
|
async function migrateToProfiles() {
|
|
3271
3446
|
const homeDir = process.env["HOME"] ?? "/tmp";
|
|
3272
|
-
const sharedConfigPath =
|
|
3447
|
+
const sharedConfigPath = join6(homeDir, ".openclaw", "openclaw.json");
|
|
3273
3448
|
let sharedConfig;
|
|
3274
3449
|
try {
|
|
3275
|
-
sharedConfig = JSON.parse(
|
|
3450
|
+
sharedConfig = JSON.parse(readFileSync5(sharedConfigPath, "utf-8"));
|
|
3276
3451
|
} catch {
|
|
3277
3452
|
return;
|
|
3278
3453
|
}
|
|
@@ -3285,19 +3460,19 @@ async function migrateToProfiles() {
|
|
|
3285
3460
|
const codeName = agentEntry["id"];
|
|
3286
3461
|
if (!codeName) continue;
|
|
3287
3462
|
if (codeName === "main") continue;
|
|
3288
|
-
const profileDir =
|
|
3289
|
-
if (
|
|
3463
|
+
const profileDir = join6(homeDir, `.openclaw-${codeName}`);
|
|
3464
|
+
if (existsSync4(join6(profileDir, "openclaw.json"))) continue;
|
|
3290
3465
|
log(`Migrating agent '${codeName}' to per-agent profile`);
|
|
3291
3466
|
if (adapter.seedProfileConfig) {
|
|
3292
3467
|
adapter.seedProfileConfig(codeName);
|
|
3293
3468
|
}
|
|
3294
|
-
const sharedAuthDir =
|
|
3295
|
-
const profileAuthDir =
|
|
3296
|
-
const authFile =
|
|
3297
|
-
if (
|
|
3469
|
+
const sharedAuthDir = join6(homeDir, ".openclaw", "agents", codeName, "agent");
|
|
3470
|
+
const profileAuthDir = join6(profileDir, "agents", codeName, "agent");
|
|
3471
|
+
const authFile = join6(sharedAuthDir, "auth-profiles.json");
|
|
3472
|
+
if (existsSync4(authFile)) {
|
|
3298
3473
|
mkdirSync2(profileAuthDir, { recursive: true });
|
|
3299
|
-
const authContent =
|
|
3300
|
-
writeFileSync3(
|
|
3474
|
+
const authContent = readFileSync5(authFile, "utf-8");
|
|
3475
|
+
writeFileSync3(join6(profileAuthDir, "auth-profiles.json"), authContent);
|
|
3301
3476
|
}
|
|
3302
3477
|
allocatePort(codeName);
|
|
3303
3478
|
migrated++;
|
|
@@ -3335,7 +3510,7 @@ function readGatewayToken(codeName) {
|
|
|
3335
3510
|
}
|
|
3336
3511
|
const homeDir = process.env["HOME"] ?? "/tmp";
|
|
3337
3512
|
try {
|
|
3338
|
-
const cfg = JSON.parse(
|
|
3513
|
+
const cfg = JSON.parse(readFileSync5(join6(homeDir, `.openclaw-${codeName}`, "openclaw.json"), "utf-8"));
|
|
3339
3514
|
return cfg?.gateway?.auth?.token;
|
|
3340
3515
|
} catch {
|
|
3341
3516
|
return void 0;
|
|
@@ -3344,18 +3519,18 @@ function readGatewayToken(codeName) {
|
|
|
3344
3519
|
var GATEWAY_HUNG_TIMEOUT_MS = 5 * 6e4;
|
|
3345
3520
|
function isGatewayHung(codeName) {
|
|
3346
3521
|
const homeDir = process.env["HOME"] ?? "/tmp";
|
|
3347
|
-
const jobsPath =
|
|
3348
|
-
if (!
|
|
3522
|
+
const jobsPath = join6(homeDir, `.openclaw-${codeName}`, "cron", "jobs.json");
|
|
3523
|
+
if (!existsSync4(jobsPath)) return false;
|
|
3349
3524
|
try {
|
|
3350
|
-
const data = JSON.parse(
|
|
3525
|
+
const data = JSON.parse(readFileSync5(jobsPath, "utf-8"));
|
|
3351
3526
|
const jobs = data.jobs ?? data;
|
|
3352
3527
|
if (!Array.isArray(jobs)) return false;
|
|
3353
3528
|
const now = Date.now();
|
|
3354
3529
|
for (const job of jobs) {
|
|
3355
|
-
const
|
|
3356
|
-
if (!
|
|
3357
|
-
const runStartedAt =
|
|
3358
|
-
const isRunning =
|
|
3530
|
+
const state5 = job.state;
|
|
3531
|
+
if (!state5) continue;
|
|
3532
|
+
const runStartedAt = state5.runStartedAtMs;
|
|
3533
|
+
const isRunning = state5.status === "running" || state5.running === true;
|
|
3359
3534
|
if (isRunning && runStartedAt && now - runStartedAt > GATEWAY_HUNG_TIMEOUT_MS) {
|
|
3360
3535
|
return true;
|
|
3361
3536
|
}
|
|
@@ -3380,15 +3555,15 @@ async function ensureGatewayRunning(codeName, adapter) {
|
|
|
3380
3555
|
}
|
|
3381
3556
|
await new Promise((r) => setTimeout(r, 2e3));
|
|
3382
3557
|
const homeDir = process.env["HOME"] ?? "/tmp";
|
|
3383
|
-
const cronJobsPath =
|
|
3558
|
+
const cronJobsPath = join6(homeDir, `.openclaw-${codeName}`, "cron", "jobs.json");
|
|
3384
3559
|
clearStaleCronRunState(cronJobsPath);
|
|
3385
3560
|
} else {
|
|
3386
3561
|
if (status.port) {
|
|
3387
3562
|
try {
|
|
3388
3563
|
const homeDir = process.env["HOME"] ?? "/tmp";
|
|
3389
|
-
const configPath =
|
|
3390
|
-
if (
|
|
3391
|
-
const cfg = JSON.parse(
|
|
3564
|
+
const configPath = join6(homeDir, `.openclaw-${codeName}`, "openclaw.json");
|
|
3565
|
+
if (existsSync4(configPath)) {
|
|
3566
|
+
const cfg = JSON.parse(readFileSync5(configPath, "utf-8"));
|
|
3392
3567
|
if (cfg.gateway?.port !== status.port) {
|
|
3393
3568
|
if (!cfg.gateway) cfg.gateway = {};
|
|
3394
3569
|
cfg.gateway.port = status.port;
|
|
@@ -3412,9 +3587,9 @@ async function ensureGatewayRunning(codeName, adapter) {
|
|
|
3412
3587
|
gatewaysStartedThisCycle.add(codeName);
|
|
3413
3588
|
try {
|
|
3414
3589
|
const homeDir = process.env["HOME"] ?? "/tmp";
|
|
3415
|
-
const configPath =
|
|
3416
|
-
if (
|
|
3417
|
-
const cfg = JSON.parse(
|
|
3590
|
+
const configPath = join6(homeDir, `.openclaw-${codeName}`, "openclaw.json");
|
|
3591
|
+
if (existsSync4(configPath)) {
|
|
3592
|
+
const cfg = JSON.parse(readFileSync5(configPath, "utf-8"));
|
|
3418
3593
|
if (!cfg.gateway) cfg.gateway = {};
|
|
3419
3594
|
cfg.gateway.port = port;
|
|
3420
3595
|
writeFileSync3(configPath, JSON.stringify(cfg, null, 2));
|
|
@@ -3556,7 +3731,7 @@ async function pollCycle() {
|
|
|
3556
3731
|
const now = Date.now();
|
|
3557
3732
|
if (now - lastVersionCheckAt > VERSION_CHECK_INTERVAL_MS) {
|
|
3558
3733
|
try {
|
|
3559
|
-
const firstAgent =
|
|
3734
|
+
const firstAgent = state4.agents[0];
|
|
3560
3735
|
const versionAdapter = firstAgent ? resolveAgentFramework(firstAgent.codeName) : getFramework("openclaw");
|
|
3561
3736
|
if (versionAdapter.getVersion) {
|
|
3562
3737
|
cachedFrameworkVersion = await versionAdapter.getVersion();
|
|
@@ -3567,7 +3742,7 @@ async function pollCycle() {
|
|
|
3567
3742
|
}
|
|
3568
3743
|
try {
|
|
3569
3744
|
const { detectHostSecurity } = await import("../host-security-6PDFG7F5.js");
|
|
3570
|
-
const { collectDiagnostics } = await import("../persistent-session-
|
|
3745
|
+
const { collectDiagnostics } = await import("../persistent-session-JUJY46HW.js");
|
|
3571
3746
|
const diagCodeNames = [...persistentSessionAgents];
|
|
3572
3747
|
const agentDiagnostics = diagCodeNames.length > 0 ? collectDiagnostics(diagCodeNames) : void 0;
|
|
3573
3748
|
let tailscaleHostname;
|
|
@@ -3618,7 +3793,7 @@ async function pollCycle() {
|
|
|
3618
3793
|
const {
|
|
3619
3794
|
collectResponsivenessProbes,
|
|
3620
3795
|
getResponsivenessIntervalMs
|
|
3621
|
-
} = await import("../responsiveness-probe-
|
|
3796
|
+
} = await import("../responsiveness-probe-XOEC7J5D.js");
|
|
3622
3797
|
const probeIntervalMs = getResponsivenessIntervalMs();
|
|
3623
3798
|
if (now - lastResponsivenessProbeAt > probeIntervalMs) {
|
|
3624
3799
|
const probeCodeNames = [...persistentSessionAgents];
|
|
@@ -3635,13 +3810,50 @@ async function pollCycle() {
|
|
|
3635
3810
|
} catch (err) {
|
|
3636
3811
|
log(`[responsiveness-probe] collection failed: ${err.message}`);
|
|
3637
3812
|
}
|
|
3813
|
+
try {
|
|
3814
|
+
const { scrapeMcpFailedBannerCount } = await import("../pane-mcp-banner-scraper-JA437JIB.js");
|
|
3815
|
+
const observations = [];
|
|
3816
|
+
const pendingCacheCommits = [];
|
|
3817
|
+
for (const codeName of persistentSessionAgents) {
|
|
3818
|
+
const agentId = codeNameToAgentId.get(codeName);
|
|
3819
|
+
if (!agentId) continue;
|
|
3820
|
+
const tail = readPaneLogTail(codeName, 40);
|
|
3821
|
+
if (!tail) continue;
|
|
3822
|
+
const observed = scrapeMcpFailedBannerCount(tail);
|
|
3823
|
+
const count = observed ?? 0;
|
|
3824
|
+
const last = lastMcpFailedBannerCount.get(codeName);
|
|
3825
|
+
if (last === count) continue;
|
|
3826
|
+
observations.push({ agent_id: agentId, count });
|
|
3827
|
+
pendingCacheCommits.push({ codeName, count });
|
|
3828
|
+
}
|
|
3829
|
+
if (observations.length > 0) {
|
|
3830
|
+
void api.post(
|
|
3831
|
+
"/host/mcp-banner-observation",
|
|
3832
|
+
{ observations }
|
|
3833
|
+
).then((resp) => {
|
|
3834
|
+
const accepted = new Set(
|
|
3835
|
+
(resp?.results ?? []).filter((r) => r.ok).map((r) => r.agent_id)
|
|
3836
|
+
);
|
|
3837
|
+
for (const { codeName, count } of pendingCacheCommits) {
|
|
3838
|
+
const agentId = codeNameToAgentId.get(codeName);
|
|
3839
|
+
if (agentId && accepted.has(agentId)) {
|
|
3840
|
+
lastMcpFailedBannerCount.set(codeName, count);
|
|
3841
|
+
}
|
|
3842
|
+
}
|
|
3843
|
+
}).catch((err) => {
|
|
3844
|
+
log(`[mcp-banner] post failed: ${err.message}`);
|
|
3845
|
+
});
|
|
3846
|
+
}
|
|
3847
|
+
} catch (err) {
|
|
3848
|
+
log(`[mcp-banner] collection failed: ${err.message}`);
|
|
3849
|
+
}
|
|
3638
3850
|
const data = await api.post("/host/agents", { host_id: hostId });
|
|
3639
3851
|
const agents = data.agents ?? [];
|
|
3640
3852
|
const restartAcks = /* @__PURE__ */ new Map();
|
|
3641
3853
|
for (const agent of agents) {
|
|
3642
3854
|
const requested = agent.restart_requested_at ?? null;
|
|
3643
3855
|
if (!requested) continue;
|
|
3644
|
-
const prev =
|
|
3856
|
+
const prev = state4.agents.find((a) => a.agentId === agent.agent_id);
|
|
3645
3857
|
const lastProcessed = prev?.lastRestartProcessedAt ?? null;
|
|
3646
3858
|
if (lastProcessed && Date.parse(lastProcessed) >= Date.parse(requested)) continue;
|
|
3647
3859
|
log(`[restart] Dashboard requested restart for '${agent.code_name}' at ${requested}`);
|
|
@@ -3664,7 +3876,7 @@ async function pollCycle() {
|
|
|
3664
3876
|
await processAgent(agent, agentStates);
|
|
3665
3877
|
} catch (err) {
|
|
3666
3878
|
log(`Error processing agent '${agent.code_name}': ${err.message}`);
|
|
3667
|
-
const existing =
|
|
3879
|
+
const existing = state4.agents.find((a) => a.agentId === agent.agent_id);
|
|
3668
3880
|
if (existing) {
|
|
3669
3881
|
agentStates.push(existing);
|
|
3670
3882
|
} else {
|
|
@@ -3687,14 +3899,15 @@ async function pollCycle() {
|
|
|
3687
3899
|
}
|
|
3688
3900
|
}
|
|
3689
3901
|
}
|
|
3902
|
+
void maybeReportActivityCache({ api, log });
|
|
3690
3903
|
const restartAckStateChanged = applyRestartAcks({
|
|
3691
3904
|
agentStates,
|
|
3692
|
-
priorAgents:
|
|
3905
|
+
priorAgents: state4.agents,
|
|
3693
3906
|
restartAcks
|
|
3694
3907
|
});
|
|
3695
3908
|
if (restartAckStateChanged) {
|
|
3696
3909
|
try {
|
|
3697
|
-
const ackedState = { ...
|
|
3910
|
+
const ackedState = { ...state4, agents: agentStates };
|
|
3698
3911
|
writeFileSync3(getStateFile(), JSON.stringify(ackedState, null, 2));
|
|
3699
3912
|
} catch (err) {
|
|
3700
3913
|
log(`[restart] failed to persist ack immediately: ${err.message}`);
|
|
@@ -3712,7 +3925,7 @@ async function pollCycle() {
|
|
|
3712
3925
|
} catch {
|
|
3713
3926
|
}
|
|
3714
3927
|
const currentIds = new Set(agents.map((a) => a.agent_id));
|
|
3715
|
-
for (const prev of
|
|
3928
|
+
for (const prev of state4.agents) {
|
|
3716
3929
|
if (!currentIds.has(prev.agentId)) {
|
|
3717
3930
|
log(`Agent '${prev.codeName}' removed from host (deleted or unassigned)`);
|
|
3718
3931
|
const adapter = resolveAgentFramework(prev.codeName);
|
|
@@ -3725,7 +3938,7 @@ async function pollCycle() {
|
|
|
3725
3938
|
}
|
|
3726
3939
|
killAgentChannelProcesses(prev.codeName, { log });
|
|
3727
3940
|
freePort(prev.codeName);
|
|
3728
|
-
const agentDir =
|
|
3941
|
+
const agentDir = join6(adapter.getAgentDir(prev.codeName), "provision");
|
|
3729
3942
|
await cleanupAgentFiles(prev.codeName, agentDir);
|
|
3730
3943
|
clearAgentCaches(prev.agentId, prev.codeName);
|
|
3731
3944
|
}
|
|
@@ -3812,10 +4025,10 @@ async function pollCycle() {
|
|
|
3812
4025
|
}
|
|
3813
4026
|
} catch {
|
|
3814
4027
|
}
|
|
3815
|
-
|
|
3816
|
-
...
|
|
4028
|
+
state4 = {
|
|
4029
|
+
...state4,
|
|
3817
4030
|
lastPollAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3818
|
-
pollCount:
|
|
4031
|
+
pollCount: state4.pollCount + 1,
|
|
3819
4032
|
agents: agentStates,
|
|
3820
4033
|
// ENG-5441: serialise trip state on every poll so manager restarts
|
|
3821
4034
|
// never silently clear a tripped breaker. Cheap — only tripped
|
|
@@ -3826,9 +4039,9 @@ async function pollCycle() {
|
|
|
3826
4039
|
log(`[poll-backoff] recovered after ${consecutivePollFailures} failure(s), resuming normal interval`);
|
|
3827
4040
|
consecutivePollFailures = 0;
|
|
3828
4041
|
}
|
|
3829
|
-
send({ type: "state-update", state:
|
|
4042
|
+
send({ type: "state-update", state: state4 });
|
|
3830
4043
|
} catch (err) {
|
|
3831
|
-
|
|
4044
|
+
state4.errorCount++;
|
|
3832
4045
|
const message = err.message;
|
|
3833
4046
|
log(`Poll error: ${message}`);
|
|
3834
4047
|
send({ type: "error", message });
|
|
@@ -3866,10 +4079,16 @@ async function processAgent(agent, agentStates) {
|
|
|
3866
4079
|
agentId: agent.agent_id,
|
|
3867
4080
|
log
|
|
3868
4081
|
});
|
|
4082
|
+
void maybeReportTokenUsage({
|
|
4083
|
+
api,
|
|
4084
|
+
codeName: agent.code_name,
|
|
4085
|
+
agentId: agent.agent_id,
|
|
4086
|
+
log
|
|
4087
|
+
});
|
|
3869
4088
|
}
|
|
3870
4089
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
3871
4090
|
const adapter = resolveAgentFramework(agent.code_name);
|
|
3872
|
-
let agentDir =
|
|
4091
|
+
let agentDir = join6(adapter.getAgentDir(agent.code_name), "provision");
|
|
3873
4092
|
if (agent.status === "draft" || agent.status === "paused") {
|
|
3874
4093
|
if (previousKnownStatus !== agent.status) {
|
|
3875
4094
|
log(`Agent '${agent.code_name}' is ${agent.status}, skipping provisioning`);
|
|
@@ -3908,7 +4127,7 @@ async function processAgent(agent, agentStates) {
|
|
|
3908
4127
|
const residuals = {
|
|
3909
4128
|
gatewayRunning: gatewayLiveness.running,
|
|
3910
4129
|
portAllocated: Object.prototype.hasOwnProperty.call(ports, agent.code_name),
|
|
3911
|
-
provisionDirExists:
|
|
4130
|
+
provisionDirExists: existsSync4(agentDir)
|
|
3912
4131
|
};
|
|
3913
4132
|
if (!hasRevokedResiduals(residuals)) {
|
|
3914
4133
|
agentStates.push({
|
|
@@ -3990,7 +4209,7 @@ async function processAgent(agent, agentStates) {
|
|
|
3990
4209
|
});
|
|
3991
4210
|
} catch (err) {
|
|
3992
4211
|
log(`Refresh failed for '${agent.code_name}': ${err.message}`);
|
|
3993
|
-
const existing =
|
|
4212
|
+
const existing = state4.agents.find((a) => a.agentId === agent.agent_id);
|
|
3994
4213
|
agentStates.push(existing ?? {
|
|
3995
4214
|
agentId: agent.agent_id,
|
|
3996
4215
|
codeName: agent.code_name,
|
|
@@ -4038,7 +4257,7 @@ async function processAgent(agent, agentStates) {
|
|
|
4038
4257
|
const frameworkId = refreshData.agent.framework ?? "openclaw";
|
|
4039
4258
|
agentFrameworkCache.set(agent.code_name, frameworkId);
|
|
4040
4259
|
const frameworkAdapter = getFramework(frameworkId);
|
|
4041
|
-
agentDir =
|
|
4260
|
+
agentDir = join6(frameworkAdapter.getAgentDir(agent.code_name), "provision");
|
|
4042
4261
|
cacheAgentDeliveryMetadata(agent.code_name, refreshData);
|
|
4043
4262
|
if (frameworkAdapter.seedProfileConfig) {
|
|
4044
4263
|
frameworkAdapter.seedProfileConfig(agent.code_name);
|
|
@@ -4046,7 +4265,7 @@ async function processAgent(agent, agentStates) {
|
|
|
4046
4265
|
const charterVersion = refreshData.charter.version;
|
|
4047
4266
|
const toolsVersion = refreshData.tools.version;
|
|
4048
4267
|
const known = knownVersions.get(agent.agent_id);
|
|
4049
|
-
let lastProvisionAt =
|
|
4268
|
+
let lastProvisionAt = state4.agents.find((a) => a.agentId === agent.agent_id)?.lastProvisionAt ?? null;
|
|
4050
4269
|
const currentChannelIds = launchableChannelIds(refreshData.channel_configs);
|
|
4051
4270
|
const previousChannelIds = knownChannels.get(agent.agent_id);
|
|
4052
4271
|
const channelsChanged = !previousChannelIds || currentChannelIds.size !== previousChannelIds.size || [...currentChannelIds].some((ch) => !previousChannelIds.has(ch)) || [...previousChannelIds].some((ch) => !currentChannelIds.has(ch));
|
|
@@ -4069,7 +4288,7 @@ async function processAgent(agent, agentStates) {
|
|
|
4069
4288
|
const changedFiles = [];
|
|
4070
4289
|
mkdirSync2(agentDir, { recursive: true });
|
|
4071
4290
|
for (const artifact of artifacts) {
|
|
4072
|
-
const filePath =
|
|
4291
|
+
const filePath = join6(agentDir, artifact.relativePath);
|
|
4073
4292
|
let existingHash;
|
|
4074
4293
|
let newHash;
|
|
4075
4294
|
let writeContent = artifact.content;
|
|
@@ -4081,8 +4300,8 @@ async function processAgent(agent, agentStates) {
|
|
|
4081
4300
|
};
|
|
4082
4301
|
newHash = sha256(stripDynamicSections(artifact.content));
|
|
4083
4302
|
try {
|
|
4084
|
-
const projectClaudeMd =
|
|
4085
|
-
const existing =
|
|
4303
|
+
const projectClaudeMd = join6(config.configDir, agent.code_name, "project", "CLAUDE.md");
|
|
4304
|
+
const existing = readFileSync5(projectClaudeMd, "utf-8");
|
|
4086
4305
|
existingHash = sha256(stripDynamicSections(existing));
|
|
4087
4306
|
} catch {
|
|
4088
4307
|
existingHash = null;
|
|
@@ -4100,7 +4319,7 @@ async function processAgent(agent, agentStates) {
|
|
|
4100
4319
|
const generatorKeys = Object.keys(generatorServers);
|
|
4101
4320
|
let existingRaw = "";
|
|
4102
4321
|
try {
|
|
4103
|
-
existingRaw =
|
|
4322
|
+
existingRaw = readFileSync5(filePath, "utf-8");
|
|
4104
4323
|
} catch {
|
|
4105
4324
|
}
|
|
4106
4325
|
const existingServers = parseMcp(existingRaw);
|
|
@@ -4122,22 +4341,22 @@ async function processAgent(agent, agentStates) {
|
|
|
4122
4341
|
}
|
|
4123
4342
|
}
|
|
4124
4343
|
if (changedFiles.length > 0) {
|
|
4125
|
-
const isFirst = !
|
|
4344
|
+
const isFirst = !existsSync4(join6(agentDir, "CHARTER.md"));
|
|
4126
4345
|
const verb = isFirst ? "Provisioning" : "Updating";
|
|
4127
4346
|
const fileNames = changedFiles.map((f) => f.relativePath).join(", ");
|
|
4128
4347
|
log(`${verb} '${agent.code_name}': ${fileNames}`);
|
|
4129
4348
|
for (const file of changedFiles) {
|
|
4130
|
-
const filePath =
|
|
4349
|
+
const filePath = join6(agentDir, file.relativePath);
|
|
4131
4350
|
mkdirSync2(dirname(filePath), { recursive: true });
|
|
4132
4351
|
writeFileSync3(filePath, file.content);
|
|
4133
4352
|
}
|
|
4134
4353
|
try {
|
|
4135
|
-
const provSkillsDir =
|
|
4136
|
-
if (
|
|
4137
|
-
for (const folder of
|
|
4354
|
+
const provSkillsDir = join6(agentDir, ".claude", "skills");
|
|
4355
|
+
if (existsSync4(provSkillsDir)) {
|
|
4356
|
+
for (const folder of readdirSync3(provSkillsDir)) {
|
|
4138
4357
|
if (folder.startsWith("knowledge-")) {
|
|
4139
4358
|
try {
|
|
4140
|
-
rmSync2(
|
|
4359
|
+
rmSync2(join6(provSkillsDir, folder), { recursive: true });
|
|
4141
4360
|
} catch {
|
|
4142
4361
|
}
|
|
4143
4362
|
}
|
|
@@ -4150,7 +4369,7 @@ async function processAgent(agent, agentStates) {
|
|
|
4150
4369
|
const trackedFiles2 = frameworkAdapter.driftTrackedFiles();
|
|
4151
4370
|
const hashes = /* @__PURE__ */ new Map();
|
|
4152
4371
|
for (const file of trackedFiles2) {
|
|
4153
|
-
const h = hashFile(
|
|
4372
|
+
const h = hashFile(join6(agentDir, file));
|
|
4154
4373
|
if (h) hashes.set(file, h);
|
|
4155
4374
|
}
|
|
4156
4375
|
writtenHashes.set(agent.agent_id, hashes);
|
|
@@ -4194,10 +4413,10 @@ async function processAgent(agent, agentStates) {
|
|
|
4194
4413
|
}
|
|
4195
4414
|
let lastDriftCheckAt = now;
|
|
4196
4415
|
const written = writtenHashes.get(agent.agent_id);
|
|
4197
|
-
if (written &&
|
|
4416
|
+
if (written && existsSync4(agentDir)) {
|
|
4198
4417
|
const driftedFiles = [];
|
|
4199
4418
|
for (const [file, expectedHash] of written) {
|
|
4200
|
-
const localHash = hashFile(
|
|
4419
|
+
const localHash = hashFile(join6(agentDir, file));
|
|
4201
4420
|
if (localHash && localHash !== expectedHash) {
|
|
4202
4421
|
driftedFiles.push(file);
|
|
4203
4422
|
}
|
|
@@ -4208,7 +4427,7 @@ async function processAgent(agent, agentStates) {
|
|
|
4208
4427
|
try {
|
|
4209
4428
|
const localHashes = {};
|
|
4210
4429
|
for (const file of driftedFiles) {
|
|
4211
|
-
localHashes[file] = hashFile(
|
|
4430
|
+
localHashes[file] = hashFile(join6(agentDir, file));
|
|
4212
4431
|
}
|
|
4213
4432
|
await api.post("/host/drift", {
|
|
4214
4433
|
agent_id: agent.agent_id,
|
|
@@ -4366,24 +4585,24 @@ async function processAgent(agent, agentStates) {
|
|
|
4366
4585
|
if (agentSessionMode === "persistent" && (agentFrameworkCache.get(agent.code_name) ?? "openclaw") === "claude-code") {
|
|
4367
4586
|
try {
|
|
4368
4587
|
const agentProvisionDir = agentDir;
|
|
4369
|
-
const projectDir =
|
|
4588
|
+
const projectDir = join6(homedir4(), ".augmented", agent.code_name, "project");
|
|
4370
4589
|
mkdirSync2(agentProvisionDir, { recursive: true });
|
|
4371
4590
|
mkdirSync2(projectDir, { recursive: true });
|
|
4372
|
-
const provisionMcpPath =
|
|
4373
|
-
const projectMcpPath =
|
|
4591
|
+
const provisionMcpPath = join6(agentProvisionDir, ".mcp.json");
|
|
4592
|
+
const projectMcpPath = join6(projectDir, ".mcp.json");
|
|
4374
4593
|
let mcpConfig = { mcpServers: {} };
|
|
4375
4594
|
try {
|
|
4376
|
-
mcpConfig = JSON.parse(
|
|
4595
|
+
mcpConfig = JSON.parse(readFileSync5(provisionMcpPath, "utf-8"));
|
|
4377
4596
|
if (!mcpConfig.mcpServers) mcpConfig.mcpServers = {};
|
|
4378
4597
|
} catch {
|
|
4379
4598
|
}
|
|
4380
|
-
const localDirectChatChannel =
|
|
4599
|
+
const localDirectChatChannel = join6(homedir4(), ".augmented", "_mcp", "direct-chat-channel.js");
|
|
4381
4600
|
const directChatTeamSettings = refreshData.team?.settings;
|
|
4382
4601
|
const directChatTz = (() => {
|
|
4383
4602
|
const tz = directChatTeamSettings?.["timezone"];
|
|
4384
4603
|
return typeof tz === "string" && tz.trim() !== "" ? tz.trim() : void 0;
|
|
4385
4604
|
})();
|
|
4386
|
-
if (
|
|
4605
|
+
if (existsSync4(localDirectChatChannel) && !mcpConfig.mcpServers["direct-chat"]) {
|
|
4387
4606
|
mcpConfig.mcpServers["direct-chat"] = {
|
|
4388
4607
|
command: "node",
|
|
4389
4608
|
args: [localDirectChatChannel],
|
|
@@ -4399,8 +4618,8 @@ async function processAgent(agent, agentStates) {
|
|
|
4399
4618
|
writeFileSync3(projectMcpPath, serialized);
|
|
4400
4619
|
log(`Channel credentials written for '${agent.code_name}/direct-chat'`);
|
|
4401
4620
|
}
|
|
4402
|
-
const staleChannelsPath =
|
|
4403
|
-
if (
|
|
4621
|
+
const staleChannelsPath = join6(projectDir, ".mcp-channels.json");
|
|
4622
|
+
if (existsSync4(staleChannelsPath)) {
|
|
4404
4623
|
try {
|
|
4405
4624
|
rmSync2(staleChannelsPath, { force: true });
|
|
4406
4625
|
} catch {
|
|
@@ -4410,7 +4629,7 @@ async function processAgent(agent, agentStates) {
|
|
|
4410
4629
|
log(`Failed to provision direct-chat channel for '${agent.code_name}': ${err.message}`);
|
|
4411
4630
|
}
|
|
4412
4631
|
}
|
|
4413
|
-
let lastSecretsProvisionAt =
|
|
4632
|
+
let lastSecretsProvisionAt = state4.agents.find((a) => a.agentId === agent.agent_id)?.lastSecretsProvisionAt ?? null;
|
|
4414
4633
|
let secretsHash = knownSecretsHashes.get(agent.agent_id) ?? null;
|
|
4415
4634
|
try {
|
|
4416
4635
|
const secretsData = await api.post("/host/secrets", { agent_id: agent.agent_id });
|
|
@@ -4466,11 +4685,11 @@ async function processAgent(agent, agentStates) {
|
|
|
4466
4685
|
const intHash = computeIntegrationsHash(integrations);
|
|
4467
4686
|
const prevIntHash = knownIntegrationHashes.get(agent.agent_id);
|
|
4468
4687
|
if (intHash !== prevIntHash) {
|
|
4469
|
-
const projectDir =
|
|
4470
|
-
const envIntPath =
|
|
4688
|
+
const projectDir = join6(homedir4(), ".augmented", agent.code_name, "project");
|
|
4689
|
+
const envIntPath = join6(projectDir, ".env.integrations");
|
|
4471
4690
|
let preWriteEnv;
|
|
4472
4691
|
try {
|
|
4473
|
-
preWriteEnv =
|
|
4692
|
+
preWriteEnv = readFileSync5(envIntPath, "utf-8");
|
|
4474
4693
|
} catch {
|
|
4475
4694
|
preWriteEnv = void 0;
|
|
4476
4695
|
}
|
|
@@ -4482,9 +4701,9 @@ async function processAgent(agent, agentStates) {
|
|
|
4482
4701
|
let rotationHandled = true;
|
|
4483
4702
|
if (fw === "claude-code" && isSessionHealthy(agent.code_name)) {
|
|
4484
4703
|
try {
|
|
4485
|
-
const projectMcpPath =
|
|
4486
|
-
const postWriteEnv =
|
|
4487
|
-
const mcpContent =
|
|
4704
|
+
const projectMcpPath = join6(projectDir, ".mcp.json");
|
|
4705
|
+
const postWriteEnv = readFileSync5(envIntPath, "utf-8");
|
|
4706
|
+
const mcpContent = readFileSync5(projectMcpPath, "utf-8");
|
|
4488
4707
|
const changedVars = diffEnvIntegrations(preWriteEnv, postWriteEnv);
|
|
4489
4708
|
const mcpJsonForReap = JSON.parse(mcpContent);
|
|
4490
4709
|
const affectedServerKeys = findMcpServersUsingVars(mcpJsonForReap, changedVars);
|
|
@@ -4550,8 +4769,8 @@ async function processAgent(agent, agentStates) {
|
|
|
4550
4769
|
const mcpPath = frameworkAdapter.getMcpPath(agent.code_name);
|
|
4551
4770
|
if (mcpPath) {
|
|
4552
4771
|
try {
|
|
4553
|
-
const { readFileSync:
|
|
4554
|
-
const mcpConfig = JSON.parse(
|
|
4772
|
+
const { readFileSync: readFileSync6 } = await import("fs");
|
|
4773
|
+
const mcpConfig = JSON.parse(readFileSync6(mcpPath, "utf-8"));
|
|
4555
4774
|
if (mcpConfig.mcpServers) {
|
|
4556
4775
|
const managedPrefixes = [
|
|
4557
4776
|
"composio_",
|
|
@@ -4640,8 +4859,8 @@ async function processAgent(agent, agentStates) {
|
|
|
4640
4859
|
if (agent.status === "active") {
|
|
4641
4860
|
if (frameworkAdapter.installPlugin) {
|
|
4642
4861
|
try {
|
|
4643
|
-
const pluginPath =
|
|
4644
|
-
if (
|
|
4862
|
+
const pluginPath = join6(process.cwd(), "packages", "openclaw-plugin-augmented", "src", "index.ts");
|
|
4863
|
+
if (existsSync4(pluginPath)) {
|
|
4645
4864
|
frameworkAdapter.installPlugin(agent.code_name, "augmented", pluginPath, {
|
|
4646
4865
|
agtHost: requireHost(),
|
|
4647
4866
|
agtApiKey: getApiKey() ?? void 0,
|
|
@@ -4706,25 +4925,25 @@ async function processAgent(agent, agentStates) {
|
|
|
4706
4925
|
}
|
|
4707
4926
|
}
|
|
4708
4927
|
try {
|
|
4709
|
-
const { readdirSync:
|
|
4710
|
-
const { homedir:
|
|
4928
|
+
const { readdirSync: readdirSync4, rmSync: rmSync3 } = await import("fs");
|
|
4929
|
+
const { homedir: homedir5 } = await import("os");
|
|
4711
4930
|
const frameworkId2 = frameworkAdapter.id;
|
|
4712
4931
|
const candidateSkillDirs = [
|
|
4713
4932
|
// Claude Code — framework runtime tree
|
|
4714
|
-
|
|
4933
|
+
join6(homedir5(), ".augmented", agent.code_name, "skills"),
|
|
4715
4934
|
// Claude Code — project tree
|
|
4716
|
-
|
|
4935
|
+
join6(homedir5(), ".augmented", agent.code_name, "project", ".claude", "skills"),
|
|
4717
4936
|
// OpenClaw — framework runtime tree
|
|
4718
|
-
|
|
4937
|
+
join6(homedir5(), `.openclaw-${agent.code_name}`, "skills"),
|
|
4719
4938
|
// Defensive: legacy provision-side path, not currently an
|
|
4720
4939
|
// install target but cheap to sweep.
|
|
4721
|
-
|
|
4940
|
+
join6(agentDir, ".claude", "skills")
|
|
4722
4941
|
];
|
|
4723
|
-
const existingDirs = candidateSkillDirs.filter((d) =>
|
|
4942
|
+
const existingDirs = candidateSkillDirs.filter((d) => existsSync4(d));
|
|
4724
4943
|
const discoveredEntries = /* @__PURE__ */ new Set();
|
|
4725
4944
|
for (const dir of existingDirs) {
|
|
4726
4945
|
try {
|
|
4727
|
-
for (const entry of
|
|
4946
|
+
for (const entry of readdirSync4(dir)) {
|
|
4728
4947
|
if (entry.startsWith("plugin-") || entry.startsWith("integration-")) {
|
|
4729
4948
|
discoveredEntries.add(entry);
|
|
4730
4949
|
}
|
|
@@ -4734,8 +4953,8 @@ async function processAgent(agent, agentStates) {
|
|
|
4734
4953
|
}
|
|
4735
4954
|
const removeSkillFolder = (entry, reason) => {
|
|
4736
4955
|
for (const dir of existingDirs) {
|
|
4737
|
-
const p =
|
|
4738
|
-
if (
|
|
4956
|
+
const p = join6(dir, entry);
|
|
4957
|
+
if (existsSync4(p)) {
|
|
4739
4958
|
rmSync3(p, { recursive: true, force: true });
|
|
4740
4959
|
}
|
|
4741
4960
|
}
|
|
@@ -4895,8 +5114,8 @@ async function processAgent(agent, agentStates) {
|
|
|
4895
5114
|
const sess = getSessionState(agent.code_name);
|
|
4896
5115
|
let mcpJsonParsed = null;
|
|
4897
5116
|
try {
|
|
4898
|
-
const mcpPath =
|
|
4899
|
-
mcpJsonParsed = JSON.parse(
|
|
5117
|
+
const mcpPath = join6(getProjectDir(agent.code_name), ".mcp.json");
|
|
5118
|
+
mcpJsonParsed = JSON.parse(readFileSync5(mcpPath, "utf-8"));
|
|
4900
5119
|
} catch {
|
|
4901
5120
|
}
|
|
4902
5121
|
reapMissingMcpSessions({
|
|
@@ -5045,10 +5264,10 @@ async function processAgent(agent, agentStates) {
|
|
|
5045
5264
|
lastWorkTriggerAt.set(agent.code_name, triggerTs);
|
|
5046
5265
|
if (agentFw === "openclaw" && gatewayRunning && gatewayPort) {
|
|
5047
5266
|
const homeDir = process.env["HOME"] ?? "/tmp";
|
|
5048
|
-
const jobsPath =
|
|
5049
|
-
if (
|
|
5267
|
+
const jobsPath = join6(homeDir, `.openclaw-${agent.code_name}`, "cron", "jobs.json");
|
|
5268
|
+
if (existsSync4(jobsPath)) {
|
|
5050
5269
|
try {
|
|
5051
|
-
const jobsData = JSON.parse(
|
|
5270
|
+
const jobsData = JSON.parse(readFileSync5(jobsPath, "utf-8"));
|
|
5052
5271
|
const kanbanJob = (jobsData.jobs ?? []).find(
|
|
5053
5272
|
(j) => typeof j.name === "string" && j.name.includes("kanban-work")
|
|
5054
5273
|
);
|
|
@@ -5189,10 +5408,10 @@ In progress for ${age} minutes \u2014 auto-failed`).catch(() => {
|
|
|
5189
5408
|
}
|
|
5190
5409
|
}
|
|
5191
5410
|
const trackedFiles = frameworkAdapter.driftTrackedFiles();
|
|
5192
|
-
if (trackedFiles.length > 0 &&
|
|
5411
|
+
if (trackedFiles.length > 0 && existsSync4(agentDir)) {
|
|
5193
5412
|
const hashes = /* @__PURE__ */ new Map();
|
|
5194
5413
|
for (const file of trackedFiles) {
|
|
5195
|
-
const h = hashFile(
|
|
5414
|
+
const h = hashFile(join6(agentDir, file));
|
|
5196
5415
|
if (h) hashes.set(file, h);
|
|
5197
5416
|
}
|
|
5198
5417
|
writtenHashes.set(agent.agent_id, hashes);
|
|
@@ -5226,19 +5445,19 @@ function cleanupStaleSessions(codeName) {
|
|
|
5226
5445
|
lastCleanupAt.set(codeName, Date.now());
|
|
5227
5446
|
const homeDir = process.env["HOME"] ?? "/tmp";
|
|
5228
5447
|
for (const agentDir of ["main", codeName]) {
|
|
5229
|
-
const sessionsDir =
|
|
5448
|
+
const sessionsDir = join6(homeDir, `.openclaw-${codeName}`, "agents", agentDir, "sessions");
|
|
5230
5449
|
cleanupCronSessions(sessionsDir, CRON_SESSION_KEEP_COUNT);
|
|
5231
5450
|
}
|
|
5232
|
-
const cronRunsDir =
|
|
5451
|
+
const cronRunsDir = join6(homeDir, `.openclaw-${codeName}`, "cron", "runs");
|
|
5233
5452
|
cleanupOldFiles(cronRunsDir, CRON_RUN_RETENTION_DAYS, ".jsonl");
|
|
5234
|
-
const cronJobsPath =
|
|
5453
|
+
const cronJobsPath = join6(homeDir, `.openclaw-${codeName}`, "cron", "jobs.json");
|
|
5235
5454
|
clearStaleCronRunState(cronJobsPath);
|
|
5236
5455
|
}
|
|
5237
5456
|
function cleanupCronSessions(sessionsDir, keepCount) {
|
|
5238
|
-
const indexPath =
|
|
5239
|
-
if (!
|
|
5457
|
+
const indexPath = join6(sessionsDir, "sessions.json");
|
|
5458
|
+
if (!existsSync4(indexPath)) return;
|
|
5240
5459
|
try {
|
|
5241
|
-
const raw =
|
|
5460
|
+
const raw = readFileSync5(indexPath, "utf-8");
|
|
5242
5461
|
const index = JSON.parse(raw);
|
|
5243
5462
|
const cronRunKeys = Object.keys(index).filter((k) => k.includes(":cron:") && k.includes(":run:")).map((k) => ({
|
|
5244
5463
|
key: k,
|
|
@@ -5251,9 +5470,9 @@ function cleanupCronSessions(sessionsDir, keepCount) {
|
|
|
5251
5470
|
for (const entry of toDelete) {
|
|
5252
5471
|
delete index[entry.key];
|
|
5253
5472
|
if (entry.sessionId) {
|
|
5254
|
-
const sessionFile =
|
|
5473
|
+
const sessionFile = join6(sessionsDir, `${entry.sessionId}.jsonl`);
|
|
5255
5474
|
try {
|
|
5256
|
-
if (
|
|
5475
|
+
if (existsSync4(sessionFile)) {
|
|
5257
5476
|
unlinkSync(sessionFile);
|
|
5258
5477
|
deletedFiles++;
|
|
5259
5478
|
}
|
|
@@ -5273,8 +5492,8 @@ function cleanupCronSessions(sessionsDir, keepCount) {
|
|
|
5273
5492
|
delete index[parentKey];
|
|
5274
5493
|
if (parentSessionId) {
|
|
5275
5494
|
try {
|
|
5276
|
-
const f =
|
|
5277
|
-
if (
|
|
5495
|
+
const f = join6(sessionsDir, `${parentSessionId}.jsonl`);
|
|
5496
|
+
if (existsSync4(f)) {
|
|
5278
5497
|
unlinkSync(f);
|
|
5279
5498
|
deletedFiles++;
|
|
5280
5499
|
}
|
|
@@ -5292,28 +5511,28 @@ function cleanupCronSessions(sessionsDir, keepCount) {
|
|
|
5292
5511
|
}
|
|
5293
5512
|
var STALE_RUN_TIMEOUT_MS = 5 * 6e4;
|
|
5294
5513
|
function clearStaleCronRunState(jobsPath) {
|
|
5295
|
-
if (!
|
|
5514
|
+
if (!existsSync4(jobsPath)) return;
|
|
5296
5515
|
try {
|
|
5297
|
-
const raw =
|
|
5516
|
+
const raw = readFileSync5(jobsPath, "utf-8");
|
|
5298
5517
|
const data = JSON.parse(raw);
|
|
5299
5518
|
const jobs = data.jobs ?? data;
|
|
5300
5519
|
if (!Array.isArray(jobs)) return;
|
|
5301
5520
|
let changed = false;
|
|
5302
5521
|
const now = Date.now();
|
|
5303
5522
|
for (const job of jobs) {
|
|
5304
|
-
const
|
|
5305
|
-
if (!
|
|
5306
|
-
const runStartedAt =
|
|
5307
|
-
const isRunning =
|
|
5523
|
+
const state5 = job.state;
|
|
5524
|
+
if (!state5) continue;
|
|
5525
|
+
const runStartedAt = state5.runningAtMs ?? state5.runStartedAtMs;
|
|
5526
|
+
const isRunning = state5.running === true || state5.status === "running";
|
|
5308
5527
|
if (isRunning && runStartedAt && now - runStartedAt > STALE_RUN_TIMEOUT_MS) {
|
|
5309
|
-
|
|
5310
|
-
delete
|
|
5311
|
-
delete
|
|
5312
|
-
delete
|
|
5528
|
+
state5.running = false;
|
|
5529
|
+
delete state5.status;
|
|
5530
|
+
delete state5.runStartedAtMs;
|
|
5531
|
+
delete state5.currentRunId;
|
|
5313
5532
|
changed = true;
|
|
5314
5533
|
log(`Cleared stale running state for cron job '${job.name}' (stuck for ${Math.round((now - runStartedAt) / 6e4)}min)`);
|
|
5315
5534
|
} else if (isRunning && !runStartedAt) {
|
|
5316
|
-
|
|
5535
|
+
state5.running = false;
|
|
5317
5536
|
changed = true;
|
|
5318
5537
|
log(`Cleared stale running state for cron job '${job.name}' (no start timestamp)`);
|
|
5319
5538
|
}
|
|
@@ -5325,15 +5544,15 @@ function clearStaleCronRunState(jobsPath) {
|
|
|
5325
5544
|
}
|
|
5326
5545
|
}
|
|
5327
5546
|
function cleanupOldFiles(dir, maxAgeDays, ext) {
|
|
5328
|
-
if (!
|
|
5547
|
+
if (!existsSync4(dir)) return;
|
|
5329
5548
|
const cutoff = Date.now() - maxAgeDays * 24 * 60 * 60 * 1e3;
|
|
5330
5549
|
let removed = 0;
|
|
5331
5550
|
try {
|
|
5332
|
-
for (const f of
|
|
5551
|
+
for (const f of readdirSync3(dir)) {
|
|
5333
5552
|
if (!f.endsWith(ext)) continue;
|
|
5334
|
-
const fullPath =
|
|
5553
|
+
const fullPath = join6(dir, f);
|
|
5335
5554
|
try {
|
|
5336
|
-
const st =
|
|
5555
|
+
const st = statSync2(fullPath);
|
|
5337
5556
|
if (st.mtimeMs < cutoff) {
|
|
5338
5557
|
unlinkSync(fullPath);
|
|
5339
5558
|
removed++;
|
|
@@ -5377,16 +5596,16 @@ async function syncAndCheckClaudeScheduler(agent, tasks, boardItems, refreshData
|
|
|
5377
5596
|
enabled: t.enabled ?? true,
|
|
5378
5597
|
triggered_at: t.triggered_at ?? null
|
|
5379
5598
|
}));
|
|
5380
|
-
const
|
|
5381
|
-
claudeSchedulerStates.set(codeName,
|
|
5599
|
+
const state6 = syncTasksToScheduler(codeName, agent.agent_id, taskInputs);
|
|
5600
|
+
claudeSchedulerStates.set(codeName, state6);
|
|
5382
5601
|
knownTasksHashes.set(agent.agent_id, combinedHash);
|
|
5383
5602
|
log(`[claude-scheduler] Tasks synced for '${codeName}' (${taskInputs.length} task(s))`);
|
|
5384
5603
|
}
|
|
5385
5604
|
if (!claudeSchedulerStates.has(codeName)) {
|
|
5386
5605
|
claudeSchedulerStates.set(codeName, loadSchedulerState(codeName));
|
|
5387
5606
|
}
|
|
5388
|
-
const
|
|
5389
|
-
const ready = getReadyTasks(
|
|
5607
|
+
const state5 = claudeSchedulerStates.get(codeName);
|
|
5608
|
+
const ready = getReadyTasks(state5, inFlightClaudeTasks);
|
|
5390
5609
|
if (ready.length === 0) return;
|
|
5391
5610
|
for (const task of ready) {
|
|
5392
5611
|
if ((claudeTaskConcurrency.get(codeName) ?? 0) >= MAX_CLAUDE_CONCURRENCY) break;
|
|
@@ -5475,7 +5694,7 @@ async function fetchPriorScheduledRuns(agentId, taskId) {
|
|
|
5475
5694
|
}
|
|
5476
5695
|
async function executeAndProcessClaudeTask(codeName, agentId, task, prompt) {
|
|
5477
5696
|
const projectDir = getProjectDir2(codeName);
|
|
5478
|
-
const mcpConfigPath =
|
|
5697
|
+
const mcpConfigPath = join6(projectDir, ".mcp.json");
|
|
5479
5698
|
let runId = null;
|
|
5480
5699
|
let kanbanItemId = null;
|
|
5481
5700
|
let taskResult;
|
|
@@ -5483,11 +5702,11 @@ async function executeAndProcessClaudeTask(codeName, agentId, task, prompt) {
|
|
|
5483
5702
|
const priorRuns = await fetchPriorScheduledRuns(agentId, task.taskId);
|
|
5484
5703
|
prompt = wrapScheduledTaskPrompt(prompt, { priorRuns });
|
|
5485
5704
|
try {
|
|
5486
|
-
const claudeMdPath =
|
|
5705
|
+
const claudeMdPath = join6(projectDir, "CLAUDE.md");
|
|
5487
5706
|
const serverNames = [];
|
|
5488
|
-
if (
|
|
5707
|
+
if (existsSync4(mcpConfigPath)) {
|
|
5489
5708
|
try {
|
|
5490
|
-
const d = JSON.parse(
|
|
5709
|
+
const d = JSON.parse(readFileSync5(mcpConfigPath, "utf-8"));
|
|
5491
5710
|
if (d.mcpServers) serverNames.push(...Object.keys(d.mcpServers));
|
|
5492
5711
|
} catch {
|
|
5493
5712
|
}
|
|
@@ -5506,14 +5725,14 @@ async function executeAndProcessClaudeTask(codeName, agentId, task, prompt) {
|
|
|
5506
5725
|
"--allowedTools",
|
|
5507
5726
|
allowedTools
|
|
5508
5727
|
];
|
|
5509
|
-
if (
|
|
5728
|
+
if (existsSync4(claudeMdPath)) {
|
|
5510
5729
|
claudeArgs.push("--system-prompt-file", claudeMdPath);
|
|
5511
5730
|
}
|
|
5512
5731
|
const childEnv = { ...process.env };
|
|
5513
|
-
const envIntPath =
|
|
5514
|
-
if (
|
|
5732
|
+
const envIntPath = join6(projectDir, ".env.integrations");
|
|
5733
|
+
if (existsSync4(envIntPath)) {
|
|
5515
5734
|
try {
|
|
5516
|
-
for (const line of
|
|
5735
|
+
for (const line of readFileSync5(envIntPath, "utf-8").split("\n")) {
|
|
5517
5736
|
if (!line || line.startsWith("#") || !line.includes("=")) continue;
|
|
5518
5737
|
const eqIdx = line.indexOf("=");
|
|
5519
5738
|
childEnv[line.slice(0, eqIdx)] = line.slice(eqIdx + 1);
|
|
@@ -5667,8 +5886,8 @@ async function processClaudeTaskResult(codeName, agentId, templateId, rawOutput,
|
|
|
5667
5886
|
}
|
|
5668
5887
|
}
|
|
5669
5888
|
function fireClaudeWorkTrigger(codeName, agentId, boardItems) {
|
|
5670
|
-
const
|
|
5671
|
-
const kanbanTask = findTaskByTemplate(
|
|
5889
|
+
const state5 = claudeSchedulerStates.get(codeName) ?? loadSchedulerState(codeName);
|
|
5890
|
+
const kanbanTask = findTaskByTemplate(state5, "kanban-work");
|
|
5672
5891
|
if (!kanbanTask) {
|
|
5673
5892
|
log(`[claude-scheduler] Work trigger: no kanban-work task found for '${codeName}'`);
|
|
5674
5893
|
return;
|
|
@@ -5691,13 +5910,14 @@ function fireClaudeWorkTrigger(codeName, agentId, boardItems) {
|
|
|
5691
5910
|
});
|
|
5692
5911
|
}
|
|
5693
5912
|
var persistentSessionAgents = /* @__PURE__ */ new Set();
|
|
5913
|
+
var lastMcpFailedBannerCount = /* @__PURE__ */ new Map();
|
|
5694
5914
|
var persistentSessionStuckTracker = new PersistentSessionStuckTracker();
|
|
5695
5915
|
var claudeAuthTupleBySession = /* @__PURE__ */ new Map();
|
|
5696
5916
|
async function ensurePersistentSession(agent, tasks, boardItems, refreshData) {
|
|
5697
5917
|
const codeName = agent.code_name;
|
|
5698
5918
|
const projectDir = getProjectDir(codeName);
|
|
5699
|
-
const mcpConfigPath =
|
|
5700
|
-
const claudeMdPath =
|
|
5919
|
+
const mcpConfigPath = join6(projectDir, ".mcp.json");
|
|
5920
|
+
const claudeMdPath = join6(projectDir, "CLAUDE.md");
|
|
5701
5921
|
if (restartBreaker.isTripped(codeName)) {
|
|
5702
5922
|
const trip = restartBreaker.getTrip(codeName);
|
|
5703
5923
|
return {
|
|
@@ -5934,9 +6154,9 @@ ${truncateForLog(ctx.tail)}` : `; pane_tail_hash=sha256:${createHash2("sha256").
|
|
|
5934
6154
|
} else if (!claudeSchedulerStates.has(codeName)) {
|
|
5935
6155
|
claudeSchedulerStates.set(codeName, loadSchedulerState(codeName));
|
|
5936
6156
|
}
|
|
5937
|
-
const
|
|
5938
|
-
if (
|
|
5939
|
-
const ready = getReadyTasks(
|
|
6157
|
+
const state5 = claudeSchedulerStates.get(codeName);
|
|
6158
|
+
if (state5) {
|
|
6159
|
+
const ready = getReadyTasks(state5, inFlightClaudeTasks);
|
|
5940
6160
|
if (ready.length > 0) {
|
|
5941
6161
|
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
6162
|
}
|
|
@@ -6315,11 +6535,11 @@ ${escapeXml(msg.content)}
|
|
|
6315
6535
|
if (fw === "claude-code") {
|
|
6316
6536
|
const { getProjectDir: ccProjectDir } = await import("../claude-scheduler-XHJS2MZV.js");
|
|
6317
6537
|
const projDir = ccProjectDir(agent.codeName);
|
|
6318
|
-
const mcpConfigPath =
|
|
6538
|
+
const mcpConfigPath = join6(projDir, ".mcp.json");
|
|
6319
6539
|
const serverNames = [];
|
|
6320
|
-
if (
|
|
6540
|
+
if (existsSync4(mcpConfigPath)) {
|
|
6321
6541
|
try {
|
|
6322
|
-
const d = JSON.parse(
|
|
6542
|
+
const d = JSON.parse(readFileSync5(mcpConfigPath, "utf-8"));
|
|
6323
6543
|
if (d.mcpServers) serverNames.push(...Object.keys(d.mcpServers));
|
|
6324
6544
|
} catch {
|
|
6325
6545
|
}
|
|
@@ -6338,15 +6558,15 @@ ${escapeXml(msg.content)}
|
|
|
6338
6558
|
"--allowedTools",
|
|
6339
6559
|
allowedTools
|
|
6340
6560
|
];
|
|
6341
|
-
const chatClaudeMd =
|
|
6342
|
-
if (
|
|
6561
|
+
const chatClaudeMd = join6(projDir, "CLAUDE.md");
|
|
6562
|
+
if (existsSync4(chatClaudeMd)) {
|
|
6343
6563
|
chatArgs.push("--system-prompt-file", chatClaudeMd);
|
|
6344
6564
|
}
|
|
6345
|
-
const envIntPath =
|
|
6565
|
+
const envIntPath = join6(projDir, ".env.integrations");
|
|
6346
6566
|
const childEnv = { ...process.env };
|
|
6347
|
-
if (
|
|
6567
|
+
if (existsSync4(envIntPath)) {
|
|
6348
6568
|
try {
|
|
6349
|
-
for (const line of
|
|
6569
|
+
for (const line of readFileSync5(envIntPath, "utf-8").split("\n")) {
|
|
6350
6570
|
if (!line || line.startsWith("#") || !line.includes("=")) continue;
|
|
6351
6571
|
const eqIdx = line.indexOf("=");
|
|
6352
6572
|
childEnv[line.slice(0, eqIdx)] = line.slice(eqIdx + 1);
|
|
@@ -6689,12 +6909,12 @@ function getBuiltInSkillContent(skillId) {
|
|
|
6689
6909
|
if (builtInSkillCache.has(skillId)) return builtInSkillCache.get(skillId);
|
|
6690
6910
|
try {
|
|
6691
6911
|
const candidates = [
|
|
6692
|
-
|
|
6693
|
-
|
|
6912
|
+
join6(process.cwd(), "skills", skillId, "SKILL.md"),
|
|
6913
|
+
join6(new URL(".", import.meta.url).pathname, "..", "..", "..", "..", "skills", skillId, "SKILL.md")
|
|
6694
6914
|
];
|
|
6695
6915
|
for (const candidate of candidates) {
|
|
6696
|
-
if (
|
|
6697
|
-
const content =
|
|
6916
|
+
if (existsSync4(candidate)) {
|
|
6917
|
+
const content = readFileSync5(candidate, "utf-8");
|
|
6698
6918
|
const files = [{ relativePath: "SKILL.md", content }];
|
|
6699
6919
|
builtInSkillCache.set(skillId, files);
|
|
6700
6920
|
return files;
|
|
@@ -7307,7 +7527,7 @@ async function processClaudePairSessions(agents) {
|
|
|
7307
7527
|
killPairSession,
|
|
7308
7528
|
pairTmuxSession,
|
|
7309
7529
|
finalizeClaudePairOnboarding
|
|
7310
|
-
} = await import("../claude-pair-runtime-
|
|
7530
|
+
} = await import("../claude-pair-runtime-ZQAJOQPN.js");
|
|
7311
7531
|
for (const pairId of pendingResp.cancelled_pair_ids ?? []) {
|
|
7312
7532
|
log(`[claude-pair] sweeping orphan tmux session for pair ${pairId.slice(0, 8)}`);
|
|
7313
7533
|
const killed = await killPairSession(pairTmuxSession(pairId));
|
|
@@ -7602,8 +7822,8 @@ function parseMemoryFile(raw, fallbackName) {
|
|
|
7602
7822
|
};
|
|
7603
7823
|
}
|
|
7604
7824
|
async function syncMemories(agent, configDir, log2) {
|
|
7605
|
-
const projectDir =
|
|
7606
|
-
const memoryDir =
|
|
7825
|
+
const projectDir = join6(configDir, agent.code_name, "project");
|
|
7826
|
+
const memoryDir = join6(projectDir, "memory");
|
|
7607
7827
|
const isFreshSync = pendingFreshMemorySync.has(agent.agent_id);
|
|
7608
7828
|
if (isFreshSync) {
|
|
7609
7829
|
log2(`[memory-sync] Fresh-sync requested for '${agent.code_name}' \u2014 pulling DB first`);
|
|
@@ -7614,14 +7834,14 @@ async function syncMemories(agent, configDir, log2) {
|
|
|
7614
7834
|
}
|
|
7615
7835
|
pendingFreshMemorySync.delete(agent.agent_id);
|
|
7616
7836
|
}
|
|
7617
|
-
if (
|
|
7837
|
+
if (existsSync4(memoryDir)) {
|
|
7618
7838
|
const prevHashes = memoryFileHashes.get(agent.agent_id) ?? /* @__PURE__ */ new Map();
|
|
7619
7839
|
const currentHashes = /* @__PURE__ */ new Map();
|
|
7620
7840
|
const changedMemories = [];
|
|
7621
|
-
for (const file of
|
|
7841
|
+
for (const file of readdirSync3(memoryDir)) {
|
|
7622
7842
|
if (!file.endsWith(".md")) continue;
|
|
7623
7843
|
try {
|
|
7624
|
-
const raw =
|
|
7844
|
+
const raw = readFileSync5(join6(memoryDir, file), "utf-8");
|
|
7625
7845
|
const fileHash = createHash2("sha256").update(raw).digest("hex").slice(0, 16);
|
|
7626
7846
|
currentHashes.set(file, fileHash);
|
|
7627
7847
|
if (prevHashes.get(file) === fileHash) continue;
|
|
@@ -7646,7 +7866,7 @@ async function syncMemories(agent, configDir, log2) {
|
|
|
7646
7866
|
} catch (err) {
|
|
7647
7867
|
for (const mem of changedMemories) {
|
|
7648
7868
|
for (const [file] of currentHashes) {
|
|
7649
|
-
const parsed = parseMemoryFile(
|
|
7869
|
+
const parsed = parseMemoryFile(readFileSync5(join6(memoryDir, file), "utf-8"), file.replace(/\.md$/, ""));
|
|
7650
7870
|
if (parsed?.name === mem.name) currentHashes.delete(file);
|
|
7651
7871
|
}
|
|
7652
7872
|
}
|
|
@@ -7659,7 +7879,7 @@ async function syncMemories(agent, configDir, log2) {
|
|
|
7659
7879
|
}
|
|
7660
7880
|
}
|
|
7661
7881
|
async function downloadMemories(agent, memoryDir, log2, { force }) {
|
|
7662
|
-
const localFiles =
|
|
7882
|
+
const localFiles = existsSync4(memoryDir) ? readdirSync3(memoryDir).filter((f) => f.endsWith(".md")).sort() : [];
|
|
7663
7883
|
const localListHash = createHash2("sha256").update(localFiles.join(",")).digest("hex").slice(0, 16);
|
|
7664
7884
|
const prevLocalHash = lastLocalFileHash.get(agent.agent_id);
|
|
7665
7885
|
const prevDownload = lastDownloadHash.get(agent.agent_id);
|
|
@@ -7681,7 +7901,7 @@ async function downloadMemories(agent, memoryDir, log2, { force }) {
|
|
|
7681
7901
|
const mem = dbMemories.memories[i];
|
|
7682
7902
|
const rawSlug = mem.name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/(^-|-$)/g, "").slice(0, 60);
|
|
7683
7903
|
const slug = rawSlug || `memory-${i}`;
|
|
7684
|
-
const filePath =
|
|
7904
|
+
const filePath = join6(memoryDir, `${slug}.md`);
|
|
7685
7905
|
const desired = `---
|
|
7686
7906
|
name: ${JSON.stringify(mem.name)}
|
|
7687
7907
|
type: ${mem.type}
|
|
@@ -7690,10 +7910,10 @@ description: ${JSON.stringify(mem.content.slice(0, 200))}
|
|
|
7690
7910
|
|
|
7691
7911
|
${mem.content}
|
|
7692
7912
|
`;
|
|
7693
|
-
if (
|
|
7913
|
+
if (existsSync4(filePath)) {
|
|
7694
7914
|
let existing = "";
|
|
7695
7915
|
try {
|
|
7696
|
-
existing =
|
|
7916
|
+
existing = readFileSync5(filePath, "utf-8");
|
|
7697
7917
|
} catch {
|
|
7698
7918
|
}
|
|
7699
7919
|
if (existing === desired) continue;
|
|
@@ -7705,7 +7925,7 @@ ${mem.content}
|
|
|
7705
7925
|
}
|
|
7706
7926
|
}
|
|
7707
7927
|
if (written > 0 || overwritten > 0) {
|
|
7708
|
-
const updatedFiles =
|
|
7928
|
+
const updatedFiles = readdirSync3(memoryDir).filter((f) => f.endsWith(".md")).sort();
|
|
7709
7929
|
lastLocalFileHash.set(agent.agent_id, createHash2("sha256").update(updatedFiles.join(",")).digest("hex").slice(0, 16));
|
|
7710
7930
|
log2(`Memory download for '${agent.code_name}': wrote ${written} new, overwrote ${overwritten} stale`);
|
|
7711
7931
|
}
|
|
@@ -7717,7 +7937,7 @@ ${mem.content}
|
|
|
7717
7937
|
}
|
|
7718
7938
|
}
|
|
7719
7939
|
async function cleanupAgentFiles(codeName, agentDir) {
|
|
7720
|
-
if (
|
|
7940
|
+
if (existsSync4(agentDir)) {
|
|
7721
7941
|
try {
|
|
7722
7942
|
rmSync2(agentDir, { recursive: true, force: true });
|
|
7723
7943
|
log(`Removed provision directory for '${codeName}'`);
|
|
@@ -7888,12 +8108,12 @@ function startManager(opts) {
|
|
|
7888
8108
|
config = opts;
|
|
7889
8109
|
try {
|
|
7890
8110
|
const stateFile = getStateFile();
|
|
7891
|
-
if (
|
|
7892
|
-
const raw =
|
|
8111
|
+
if (existsSync4(stateFile)) {
|
|
8112
|
+
const raw = readFileSync5(stateFile, "utf-8");
|
|
7893
8113
|
const parsed = JSON.parse(raw);
|
|
7894
8114
|
if (Array.isArray(parsed.agents)) {
|
|
7895
|
-
|
|
7896
|
-
log(`[startup] rehydrated ${
|
|
8115
|
+
state4.agents = parsed.agents;
|
|
8116
|
+
log(`[startup] rehydrated ${state4.agents.length} agent state(s) from ${stateFile}`);
|
|
7897
8117
|
}
|
|
7898
8118
|
if (parsed.circuitBreakerTrips && typeof parsed.circuitBreakerTrips === "object") {
|
|
7899
8119
|
restartBreaker.hydrate(parsed.circuitBreakerTrips);
|
|
@@ -7905,7 +8125,7 @@ function startManager(opts) {
|
|
|
7905
8125
|
log(`[startup] state rehydration failed (continuing with empty state): ${err.message}`);
|
|
7906
8126
|
}
|
|
7907
8127
|
log(
|
|
7908
|
-
`[startup] worker pid=${process.pid} ppid=${process.ppid} node=${process.version} log=${
|
|
8128
|
+
`[startup] worker pid=${process.pid} ppid=${process.ppid} node=${process.version} log=${join6(homedir4(), ".augmented", "manager.log")}`
|
|
7909
8129
|
);
|
|
7910
8130
|
warnOnConflictingKanbanModes();
|
|
7911
8131
|
deployMcpAssets();
|
|
@@ -7968,14 +8188,14 @@ function restartRunningChannelMcps(basenames) {
|
|
|
7968
8188
|
}
|
|
7969
8189
|
}
|
|
7970
8190
|
function deployMcpAssets() {
|
|
7971
|
-
const targetDir =
|
|
8191
|
+
const targetDir = join6(homedir4(), ".augmented", "_mcp");
|
|
7972
8192
|
mkdirSync2(targetDir, { recursive: true });
|
|
7973
8193
|
const moduleDir = dirname(fileURLToPath(import.meta.url));
|
|
7974
8194
|
let mcpSourceDir = "";
|
|
7975
8195
|
let dir = moduleDir;
|
|
7976
8196
|
for (let i = 0; i < 6; i++) {
|
|
7977
|
-
const candidate =
|
|
7978
|
-
if (
|
|
8197
|
+
const candidate = join6(dir, "dist", "mcp");
|
|
8198
|
+
if (existsSync4(join6(candidate, "index.js"))) {
|
|
7979
8199
|
mcpSourceDir = candidate;
|
|
7980
8200
|
break;
|
|
7981
8201
|
}
|
|
@@ -7990,8 +8210,8 @@ function deployMcpAssets() {
|
|
|
7990
8210
|
const changedBasenames = [];
|
|
7991
8211
|
const fileHash = (p) => {
|
|
7992
8212
|
try {
|
|
7993
|
-
if (!
|
|
7994
|
-
return createHash2("sha256").update(
|
|
8213
|
+
if (!existsSync4(p)) return null;
|
|
8214
|
+
return createHash2("sha256").update(readFileSync5(p)).digest("hex");
|
|
7995
8215
|
} catch {
|
|
7996
8216
|
return null;
|
|
7997
8217
|
}
|
|
@@ -8002,9 +8222,9 @@ function deployMcpAssets() {
|
|
|
8002
8222
|
"telegram-channel.js"
|
|
8003
8223
|
]);
|
|
8004
8224
|
for (const file of ["index.js", "slack-channel.js", "direct-chat-channel.js", "telegram-channel.js"]) {
|
|
8005
|
-
const src =
|
|
8006
|
-
const dst =
|
|
8007
|
-
if (!
|
|
8225
|
+
const src = join6(mcpSourceDir, file);
|
|
8226
|
+
const dst = join6(targetDir, file);
|
|
8227
|
+
if (!existsSync4(src)) continue;
|
|
8008
8228
|
const before = fileHash(dst);
|
|
8009
8229
|
try {
|
|
8010
8230
|
copyFileSync(src, dst);
|
|
@@ -8021,16 +8241,16 @@ function deployMcpAssets() {
|
|
|
8021
8241
|
log(`[manager] Bundle(s) updated: ${changedBasenames.join(", ")} \u2014 signalling running instances to restart`);
|
|
8022
8242
|
restartRunningChannelMcps(changedBasenames);
|
|
8023
8243
|
}
|
|
8024
|
-
const localMcpPath =
|
|
8244
|
+
const localMcpPath = join6(targetDir, "index.js");
|
|
8025
8245
|
try {
|
|
8026
|
-
const agentsDir =
|
|
8027
|
-
if (
|
|
8028
|
-
for (const entry of
|
|
8246
|
+
const agentsDir = join6(homedir4(), ".augmented", "agents");
|
|
8247
|
+
if (existsSync4(agentsDir)) {
|
|
8248
|
+
for (const entry of readdirSync3(agentsDir, { withFileTypes: true })) {
|
|
8029
8249
|
if (!entry.isDirectory()) continue;
|
|
8030
8250
|
for (const subdir of ["provision", "project"]) {
|
|
8031
|
-
const mcpJsonPath =
|
|
8251
|
+
const mcpJsonPath = join6(agentsDir, entry.name, subdir, ".mcp.json");
|
|
8032
8252
|
try {
|
|
8033
|
-
const raw =
|
|
8253
|
+
const raw = readFileSync5(mcpJsonPath, "utf-8");
|
|
8034
8254
|
if (!raw.includes("@integrity-labs/augmented-mcp")) continue;
|
|
8035
8255
|
const mcpConfig = JSON.parse(raw);
|
|
8036
8256
|
const augServer = mcpConfig.mcpServers?.["augmented"];
|