@integrity-labs/agt-cli 0.19.2 → 0.19.4
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 +7 -3
- package/dist/bin/agt.js.map +1 -1
- package/dist/{chunk-BEIZXSG4.js → chunk-MC3SMG4A.js} +191 -8
- package/dist/chunk-MC3SMG4A.js.map +1 -0
- package/dist/lib/manager-worker.js +356 -165
- package/dist/lib/manager-worker.js.map +1 -1
- package/dist/{manager-supervisor-PU5YK5QE.js → manager-supervisor-P63HG5MR.js} +193 -3
- package/dist/manager-supervisor-P63HG5MR.js.map +1 -0
- package/package.json +1 -1
- package/dist/chunk-BEIZXSG4.js.map +0 -1
- package/dist/manager-supervisor-PU5YK5QE.js.map +0 -1
|
@@ -22,7 +22,7 @@ import {
|
|
|
22
22
|
resolveChannels,
|
|
23
23
|
resolveDmTarget,
|
|
24
24
|
wrapScheduledTaskPrompt
|
|
25
|
-
} from "../chunk-
|
|
25
|
+
} from "../chunk-MC3SMG4A.js";
|
|
26
26
|
import {
|
|
27
27
|
findTaskByTemplate,
|
|
28
28
|
getProjectDir,
|
|
@@ -51,10 +51,10 @@ import {
|
|
|
51
51
|
|
|
52
52
|
// src/lib/manager-worker.ts
|
|
53
53
|
import { createHash } from "crypto";
|
|
54
|
-
import { readFileSync as
|
|
54
|
+
import { readFileSync as readFileSync3, writeFileSync as writeFileSync3, appendFileSync, mkdirSync as mkdirSync2, chmodSync, existsSync as existsSync3, rmSync as rmSync2, readdirSync as readdirSync2, statSync, unlinkSync, copyFileSync } from "fs";
|
|
55
55
|
import https from "https";
|
|
56
56
|
import { execFileSync as syncExecFile } from "child_process";
|
|
57
|
-
import { join as
|
|
57
|
+
import { join as join4, dirname } from "path";
|
|
58
58
|
import { homedir as homedir3 } from "os";
|
|
59
59
|
import { fileURLToPath } from "url";
|
|
60
60
|
|
|
@@ -588,6 +588,37 @@ function normalize(value) {
|
|
|
588
588
|
return sorted;
|
|
589
589
|
}
|
|
590
590
|
|
|
591
|
+
// src/lib/channel-hash-cache.ts
|
|
592
|
+
import { existsSync, readFileSync, writeFileSync } from "fs";
|
|
593
|
+
import { join as join2 } from "path";
|
|
594
|
+
var CACHE_FILENAME = "channel-hash-cache.json";
|
|
595
|
+
function getChannelHashCacheFile(configDir) {
|
|
596
|
+
return join2(configDir, CACHE_FILENAME);
|
|
597
|
+
}
|
|
598
|
+
function loadChannelHashCache(target, configDir) {
|
|
599
|
+
const path = getChannelHashCacheFile(configDir);
|
|
600
|
+
if (!existsSync(path)) return;
|
|
601
|
+
let parsed;
|
|
602
|
+
try {
|
|
603
|
+
parsed = JSON.parse(readFileSync(path, "utf-8"));
|
|
604
|
+
} catch {
|
|
605
|
+
return;
|
|
606
|
+
}
|
|
607
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return;
|
|
608
|
+
for (const [key, value] of Object.entries(parsed)) {
|
|
609
|
+
if (typeof value === "string" && value.length > 0) target.set(key, value);
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
function saveChannelHashCache(source, configDir) {
|
|
613
|
+
const path = getChannelHashCacheFile(configDir);
|
|
614
|
+
const obj = {};
|
|
615
|
+
for (const [key, value] of source) obj[key] = value;
|
|
616
|
+
try {
|
|
617
|
+
writeFileSync(path, JSON.stringify(obj, null, 2));
|
|
618
|
+
} catch {
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
|
|
591
622
|
// src/lib/channel-sweep.ts
|
|
592
623
|
import { execFileSync } from "child_process";
|
|
593
624
|
var CHANNEL_BASENAMES = [
|
|
@@ -838,6 +869,108 @@ function killAgentChannelProcesses(codeName, opts) {
|
|
|
838
869
|
return pids;
|
|
839
870
|
}
|
|
840
871
|
|
|
872
|
+
// src/lib/channel-input-watchdog.ts
|
|
873
|
+
var STUCK_THRESHOLD_MS = 5e3;
|
|
874
|
+
var ATTACHED_STUCK_THRESHOLD_MS = 15e3;
|
|
875
|
+
var INPUT_BOX_DIVIDER = /^[─━]{10,}/;
|
|
876
|
+
var PROMPT_PREFIX = "\u276F ";
|
|
877
|
+
function decide(pane, prev, now, config2 = {}) {
|
|
878
|
+
const threshold = config2.stuckThresholdMs ?? STUCK_THRESHOLD_MS;
|
|
879
|
+
const inputText = extractInputBoxText(pane);
|
|
880
|
+
if (!inputText) {
|
|
881
|
+
return { fire: false, next: void 0 };
|
|
882
|
+
}
|
|
883
|
+
if (isActivelyProcessing(pane)) {
|
|
884
|
+
return { fire: false, next: prev };
|
|
885
|
+
}
|
|
886
|
+
const hash = simpleHash(inputText);
|
|
887
|
+
if (!prev || prev.lastInputHash !== hash) {
|
|
888
|
+
return {
|
|
889
|
+
fire: false,
|
|
890
|
+
next: { lastInputHash: hash, firstSeenAt: now, resolved: false }
|
|
891
|
+
};
|
|
892
|
+
}
|
|
893
|
+
if (prev.resolved) return { fire: false, next: prev };
|
|
894
|
+
if (now - prev.firstSeenAt < threshold) return { fire: false, next: prev };
|
|
895
|
+
return {
|
|
896
|
+
fire: true,
|
|
897
|
+
next: { ...prev, resolved: true }
|
|
898
|
+
};
|
|
899
|
+
}
|
|
900
|
+
function extractInputBoxText(pane) {
|
|
901
|
+
const lines = pane.split("\n");
|
|
902
|
+
for (let i = 1; i < lines.length; i++) {
|
|
903
|
+
const line = lines[i] ?? "";
|
|
904
|
+
if (!line.startsWith(PROMPT_PREFIX)) continue;
|
|
905
|
+
let j = i - 1;
|
|
906
|
+
while (j >= 0 && (lines[j] ?? "").trim() === "") j--;
|
|
907
|
+
if (j < 0) continue;
|
|
908
|
+
if (!INPUT_BOX_DIVIDER.test((lines[j] ?? "").trim())) continue;
|
|
909
|
+
const text = line.slice(PROMPT_PREFIX.length).trim();
|
|
910
|
+
return text.length > 0 ? text : null;
|
|
911
|
+
}
|
|
912
|
+
return null;
|
|
913
|
+
}
|
|
914
|
+
function isActivelyProcessing(pane) {
|
|
915
|
+
const lines = pane.split("\n");
|
|
916
|
+
for (let i = lines.length - 1; i >= 0; i--) {
|
|
917
|
+
const line = (lines[i] ?? "").trim();
|
|
918
|
+
if (!line.startsWith("\u273B")) continue;
|
|
919
|
+
if (/\bfor\s+\d+s\s*$/.test(line)) return false;
|
|
920
|
+
if (/\b\w+ing[…\.]{0,3}\s*$/i.test(line)) return true;
|
|
921
|
+
return false;
|
|
922
|
+
}
|
|
923
|
+
return false;
|
|
924
|
+
}
|
|
925
|
+
function simpleHash(s) {
|
|
926
|
+
let h = 0;
|
|
927
|
+
for (let i = 0; i < s.length; i++) {
|
|
928
|
+
h = (h << 5) - h + s.charCodeAt(i) | 0;
|
|
929
|
+
}
|
|
930
|
+
return h.toString(16);
|
|
931
|
+
}
|
|
932
|
+
function checkChannelInputs(codeNames, io, config2 = {}, states = sharedStates) {
|
|
933
|
+
const live = new Set(codeNames);
|
|
934
|
+
for (const codeName of codeNames) {
|
|
935
|
+
try {
|
|
936
|
+
checkOne(codeName, io, config2, states);
|
|
937
|
+
} catch (err) {
|
|
938
|
+
io.log(`[channel-input-watchdog] '${codeName}': ${err.message}`);
|
|
939
|
+
}
|
|
940
|
+
}
|
|
941
|
+
for (const key of [...states.keys()]) {
|
|
942
|
+
if (!live.has(key)) states.delete(key);
|
|
943
|
+
}
|
|
944
|
+
}
|
|
945
|
+
function checkOne(codeName, io, config2, states) {
|
|
946
|
+
const pane = io.capturePane(codeName);
|
|
947
|
+
if (!pane) {
|
|
948
|
+
states.delete(codeName);
|
|
949
|
+
return;
|
|
950
|
+
}
|
|
951
|
+
const attached = io.isClientAttached(codeName);
|
|
952
|
+
const effectiveConfig = attached ? {
|
|
953
|
+
...config2,
|
|
954
|
+
stuckThresholdMs: config2.attachedStuckThresholdMs ?? ATTACHED_STUCK_THRESHOLD_MS
|
|
955
|
+
} : config2;
|
|
956
|
+
const prev = states.get(codeName);
|
|
957
|
+
const { fire, next } = decide(pane, prev, io.now(), effectiveConfig);
|
|
958
|
+
if (next === void 0) {
|
|
959
|
+
states.delete(codeName);
|
|
960
|
+
} else {
|
|
961
|
+
states.set(codeName, next);
|
|
962
|
+
}
|
|
963
|
+
if (fire) {
|
|
964
|
+
const text = extractInputBoxText(pane) ?? "";
|
|
965
|
+
const hash = next?.lastInputHash ?? simpleHash(text);
|
|
966
|
+
io.log(
|
|
967
|
+
`[channel-input-watchdog] '${codeName}': stuck channel input \u2014 firing Enter (input_hash=${hash}, len=${text.length})`
|
|
968
|
+
);
|
|
969
|
+
io.sendEnter(codeName);
|
|
970
|
+
}
|
|
971
|
+
}
|
|
972
|
+
var sharedStates = /* @__PURE__ */ new Map();
|
|
973
|
+
|
|
841
974
|
// src/lib/delivery-hint.ts
|
|
842
975
|
var DEFAULT_PROBABILITY = 0.1;
|
|
843
976
|
function envSuffixFor(codeName) {
|
|
@@ -940,24 +1073,24 @@ function withScheduleLinkFooter(opts) {
|
|
|
940
1073
|
}
|
|
941
1074
|
|
|
942
1075
|
// src/lib/restart-flags.ts
|
|
943
|
-
import { existsSync, mkdirSync, readdirSync, readFileSync, renameSync, rmSync, writeFileSync } from "fs";
|
|
1076
|
+
import { existsSync as existsSync2, mkdirSync, readdirSync, readFileSync as readFileSync2, renameSync, rmSync, writeFileSync as writeFileSync2 } from "fs";
|
|
944
1077
|
import { homedir as homedir2 } from "os";
|
|
945
|
-
import { join as
|
|
1078
|
+
import { join as join3 } from "path";
|
|
946
1079
|
import { randomUUID } from "crypto";
|
|
947
1080
|
function restartFlagsDir() {
|
|
948
|
-
return
|
|
1081
|
+
return join3(homedir2(), ".augmented", "restart-flags");
|
|
949
1082
|
}
|
|
950
1083
|
function flagPath(codeName) {
|
|
951
|
-
return
|
|
1084
|
+
return join3(restartFlagsDir(), `${codeName}.flag`);
|
|
952
1085
|
}
|
|
953
1086
|
function readRestartFlags() {
|
|
954
1087
|
const dir = restartFlagsDir();
|
|
955
|
-
if (!
|
|
1088
|
+
if (!existsSync2(dir)) return [];
|
|
956
1089
|
const out = [];
|
|
957
1090
|
for (const entry of readdirSync(dir)) {
|
|
958
1091
|
if (!entry.endsWith(".flag")) continue;
|
|
959
1092
|
try {
|
|
960
|
-
const raw =
|
|
1093
|
+
const raw = readFileSync2(join3(dir, entry), "utf8");
|
|
961
1094
|
const parsed = JSON.parse(raw);
|
|
962
1095
|
if (typeof parsed.codeName !== "string" || parsed.codeName.length === 0) {
|
|
963
1096
|
parsed.codeName = entry.replace(/\.flag$/, "");
|
|
@@ -975,7 +1108,7 @@ function readRestartFlags() {
|
|
|
975
1108
|
}
|
|
976
1109
|
function deleteRestartFlag(codeName) {
|
|
977
1110
|
const path = flagPath(codeName);
|
|
978
|
-
if (
|
|
1111
|
+
if (existsSync2(path)) {
|
|
979
1112
|
rmSync(path, { force: true });
|
|
980
1113
|
}
|
|
981
1114
|
}
|
|
@@ -1392,8 +1525,8 @@ function stopRealtimeChat() {
|
|
|
1392
1525
|
var GATEWAY_PORT_BASE = 18800;
|
|
1393
1526
|
var GATEWAY_PORT_STEP = 10;
|
|
1394
1527
|
var GATEWAY_PORT_MAX = 18899;
|
|
1395
|
-
var AUGMENTED_DIR =
|
|
1396
|
-
var GATEWAY_PORTS_FILE =
|
|
1528
|
+
var AUGMENTED_DIR = join4(process.env["HOME"] ?? "/tmp", ".augmented");
|
|
1529
|
+
var GATEWAY_PORTS_FILE = join4(AUGMENTED_DIR, "gateway-ports.json");
|
|
1397
1530
|
var CHANNEL_SWEEP_INTERVAL_MS = (() => {
|
|
1398
1531
|
const raw = parseInt(process.env["AGT_CHANNEL_SWEEP_INTERVAL_MS"] ?? "", 10);
|
|
1399
1532
|
if (!Number.isFinite(raw)) return 5 * 60 * 1e3;
|
|
@@ -1471,9 +1604,14 @@ function clearAgentCaches(agentId, codeName) {
|
|
|
1471
1604
|
memoryFileHashes.delete(agentId);
|
|
1472
1605
|
lastDownloadHash.delete(agentId);
|
|
1473
1606
|
lastLocalFileHash.delete(agentId);
|
|
1607
|
+
let channelCacheMutated = false;
|
|
1474
1608
|
for (const key of knownChannelConfigHashes.keys()) {
|
|
1475
|
-
if (key.startsWith(`${agentId}:`))
|
|
1609
|
+
if (key.startsWith(`${agentId}:`)) {
|
|
1610
|
+
knownChannelConfigHashes.delete(key);
|
|
1611
|
+
channelCacheMutated = true;
|
|
1612
|
+
}
|
|
1476
1613
|
}
|
|
1614
|
+
if (channelCacheMutated) saveChannelHashCache2();
|
|
1477
1615
|
for (const key of knownSkillHashes.keys()) {
|
|
1478
1616
|
if (key.startsWith(`${agentId}:`)) knownSkillHashes.delete(key);
|
|
1479
1617
|
}
|
|
@@ -1484,7 +1622,7 @@ function clearAgentCaches(agentId, codeName) {
|
|
|
1484
1622
|
var cachedFrameworkVersion = null;
|
|
1485
1623
|
var lastVersionCheckAt = 0;
|
|
1486
1624
|
var VERSION_CHECK_INTERVAL_MS = 5 * 60 * 1e3;
|
|
1487
|
-
var agtCliVersion = true ? "0.19.
|
|
1625
|
+
var agtCliVersion = true ? "0.19.4" : "dev";
|
|
1488
1626
|
function resolveBrewPath(execFileSync2) {
|
|
1489
1627
|
try {
|
|
1490
1628
|
const out = execFileSync2("which", ["brew"], { timeout: 5e3 }).toString().trim();
|
|
@@ -1497,7 +1635,7 @@ function resolveBrewPath(execFileSync2) {
|
|
|
1497
1635
|
"/usr/local/bin/brew"
|
|
1498
1636
|
];
|
|
1499
1637
|
for (const path of fallbacks) {
|
|
1500
|
-
if (
|
|
1638
|
+
if (existsSync3(path)) return path;
|
|
1501
1639
|
}
|
|
1502
1640
|
return null;
|
|
1503
1641
|
}
|
|
@@ -1658,7 +1796,7 @@ async function ensureFrameworkBinary(frameworkId) {
|
|
|
1658
1796
|
}
|
|
1659
1797
|
return runAsync(brewPath, args, opts);
|
|
1660
1798
|
};
|
|
1661
|
-
let claudeExists =
|
|
1799
|
+
let claudeExists = existsSync3("/home/linuxbrew/.linuxbrew/bin/claude");
|
|
1662
1800
|
if (!claudeExists) {
|
|
1663
1801
|
try {
|
|
1664
1802
|
execFileSync2("which", ["claude"], { timeout: 5e3 });
|
|
@@ -1682,7 +1820,7 @@ async function ensureFrameworkBinary(frameworkId) {
|
|
|
1682
1820
|
if (!process.env.PATH?.split(":").includes(brewBinDir)) {
|
|
1683
1821
|
process.env.PATH = `${brewBinDir}:${process.env.PATH ?? ""}`;
|
|
1684
1822
|
}
|
|
1685
|
-
if (
|
|
1823
|
+
if (existsSync3("/home/linuxbrew/.linuxbrew/bin/claude")) {
|
|
1686
1824
|
log("Claude Code installed successfully");
|
|
1687
1825
|
} else {
|
|
1688
1826
|
log("Claude Code install completed but binary not found at expected path \u2014 check brew logs");
|
|
@@ -1729,7 +1867,7 @@ async function checkAndUpdateCli() {
|
|
|
1729
1867
|
const isNpmGlobal = !isBrewFormula && resolvedPath.includes("node_modules");
|
|
1730
1868
|
if (!isBrewFormula && !isNpmGlobal) return;
|
|
1731
1869
|
const { readFileSync: readF, writeFileSync: writeF } = await import("fs");
|
|
1732
|
-
const markerPath =
|
|
1870
|
+
const markerPath = join4(homedir3(), ".augmented", ".last-update-check");
|
|
1733
1871
|
try {
|
|
1734
1872
|
const lastCheck = parseInt(readF(markerPath, "utf-8").trim(), 10);
|
|
1735
1873
|
if (Date.now() - lastCheck < UPDATE_CHECK_INTERVAL_MS) return;
|
|
@@ -1891,10 +2029,10 @@ async function applyClaudeAuthToEnv(childEnv, label) {
|
|
|
1891
2029
|
throw new Error("claude_auth_mode=api_key but /host/exchange returned no decrypted key");
|
|
1892
2030
|
}
|
|
1893
2031
|
childEnv.ANTHROPIC_API_KEY = exchange.anthropicApiKey;
|
|
1894
|
-
const claudeDir =
|
|
2032
|
+
const claudeDir = join4(homedir3(), ".claude");
|
|
1895
2033
|
for (const filename of [".credentials.json", "credentials.json"]) {
|
|
1896
|
-
const p =
|
|
1897
|
-
if (
|
|
2034
|
+
const p = join4(claudeDir, filename);
|
|
2035
|
+
if (existsSync3(p)) {
|
|
1898
2036
|
try {
|
|
1899
2037
|
rmSync2(p, { force: true });
|
|
1900
2038
|
log(`[${label}] Removed ${p} (api_key mode \u2014 preventing OAuth fallback)`);
|
|
@@ -1908,14 +2046,14 @@ async function applyClaudeAuthToEnv(childEnv, label) {
|
|
|
1908
2046
|
}
|
|
1909
2047
|
function loadGatewayPorts() {
|
|
1910
2048
|
try {
|
|
1911
|
-
return JSON.parse(
|
|
2049
|
+
return JSON.parse(readFileSync3(GATEWAY_PORTS_FILE, "utf-8"));
|
|
1912
2050
|
} catch {
|
|
1913
2051
|
return {};
|
|
1914
2052
|
}
|
|
1915
2053
|
}
|
|
1916
2054
|
function saveGatewayPorts(ports) {
|
|
1917
2055
|
mkdirSync2(AUGMENTED_DIR, { recursive: true });
|
|
1918
|
-
|
|
2056
|
+
writeFileSync3(GATEWAY_PORTS_FILE, JSON.stringify(ports, null, 2));
|
|
1919
2057
|
}
|
|
1920
2058
|
function allocatePort(codeName) {
|
|
1921
2059
|
const ports = loadGatewayPorts();
|
|
@@ -1938,12 +2076,21 @@ function freePort(codeName) {
|
|
|
1938
2076
|
}
|
|
1939
2077
|
}
|
|
1940
2078
|
function getStateFile() {
|
|
1941
|
-
return
|
|
2079
|
+
return join4(config?.configDir ?? join4(process.env["HOME"] ?? "/tmp", ".augmented"), "manager-state.json");
|
|
2080
|
+
}
|
|
2081
|
+
function channelHashCacheDir() {
|
|
2082
|
+
return config?.configDir ?? join4(process.env["HOME"] ?? "/tmp", ".augmented");
|
|
2083
|
+
}
|
|
2084
|
+
function loadChannelHashCache2() {
|
|
2085
|
+
loadChannelHashCache(knownChannelConfigHashes, channelHashCacheDir());
|
|
2086
|
+
}
|
|
2087
|
+
function saveChannelHashCache2() {
|
|
2088
|
+
saveChannelHashCache(knownChannelConfigHashes, channelHashCacheDir());
|
|
1942
2089
|
}
|
|
1943
2090
|
function send(msg) {
|
|
1944
2091
|
if (msg.type === "state-update") {
|
|
1945
2092
|
try {
|
|
1946
|
-
|
|
2093
|
+
writeFileSync3(getStateFile(), JSON.stringify(msg.state, null, 2));
|
|
1947
2094
|
} catch {
|
|
1948
2095
|
}
|
|
1949
2096
|
}
|
|
@@ -1974,9 +2121,9 @@ function log(msg) {
|
|
|
1974
2121
|
`;
|
|
1975
2122
|
if (!managerLogPath) {
|
|
1976
2123
|
try {
|
|
1977
|
-
managerLogPath =
|
|
2124
|
+
managerLogPath = join4(homedir3(), ".augmented", "manager.log");
|
|
1978
2125
|
mkdirSync2(dirname(managerLogPath), { recursive: true });
|
|
1979
|
-
if (
|
|
2126
|
+
if (existsSync3(managerLogPath)) {
|
|
1980
2127
|
chmodSync(managerLogPath, 384);
|
|
1981
2128
|
}
|
|
1982
2129
|
} catch {
|
|
@@ -2004,7 +2151,7 @@ function sha256(content) {
|
|
|
2004
2151
|
}
|
|
2005
2152
|
function hashFile(filePath) {
|
|
2006
2153
|
try {
|
|
2007
|
-
const content =
|
|
2154
|
+
const content = readFileSync3(filePath, "utf-8");
|
|
2008
2155
|
return sha256(content);
|
|
2009
2156
|
} catch {
|
|
2010
2157
|
return null;
|
|
@@ -2028,13 +2175,13 @@ function parseSkillFrontmatter(content) {
|
|
|
2028
2175
|
return out;
|
|
2029
2176
|
}
|
|
2030
2177
|
async function refreshSkillsIndexInClaudeMd(configDir, codeName, log2) {
|
|
2031
|
-
const { readdirSync: readdirSync3, readFileSync: rfs, existsSync: ex, writeFileSync:
|
|
2032
|
-
const skillsDir =
|
|
2033
|
-
const claudeMdPath =
|
|
2178
|
+
const { readdirSync: readdirSync3, readFileSync: rfs, existsSync: ex, writeFileSync: writeFileSync4 } = await import("fs");
|
|
2179
|
+
const skillsDir = join4(configDir, codeName, "project", ".claude", "skills");
|
|
2180
|
+
const claudeMdPath = join4(configDir, codeName, "project", "CLAUDE.md");
|
|
2034
2181
|
if (!ex(skillsDir) || !ex(claudeMdPath)) return;
|
|
2035
2182
|
const entries = [];
|
|
2036
2183
|
for (const dir of readdirSync3(skillsDir).sort()) {
|
|
2037
|
-
const skillFile =
|
|
2184
|
+
const skillFile = join4(skillsDir, dir, "SKILL.md");
|
|
2038
2185
|
if (!ex(skillFile)) continue;
|
|
2039
2186
|
try {
|
|
2040
2187
|
const { name, description } = parseSkillFrontmatter(rfs(skillFile, "utf-8"));
|
|
@@ -2076,16 +2223,16 @@ ${SKILLS_INDEX_END}`;
|
|
|
2076
2223
|
next = current.trimEnd() + "\n\n" + section + "\n";
|
|
2077
2224
|
}
|
|
2078
2225
|
if (next !== current) {
|
|
2079
|
-
|
|
2226
|
+
writeFileSync4(claudeMdPath, next, "utf-8");
|
|
2080
2227
|
log2(`Refreshed skills index in CLAUDE.md for '${codeName}' (${entries.length} skills)`);
|
|
2081
2228
|
}
|
|
2082
2229
|
}
|
|
2083
2230
|
async function migrateToProfiles() {
|
|
2084
2231
|
const homeDir = process.env["HOME"] ?? "/tmp";
|
|
2085
|
-
const sharedConfigPath =
|
|
2232
|
+
const sharedConfigPath = join4(homeDir, ".openclaw", "openclaw.json");
|
|
2086
2233
|
let sharedConfig;
|
|
2087
2234
|
try {
|
|
2088
|
-
sharedConfig = JSON.parse(
|
|
2235
|
+
sharedConfig = JSON.parse(readFileSync3(sharedConfigPath, "utf-8"));
|
|
2089
2236
|
} catch {
|
|
2090
2237
|
return;
|
|
2091
2238
|
}
|
|
@@ -2098,19 +2245,19 @@ async function migrateToProfiles() {
|
|
|
2098
2245
|
const codeName = agentEntry["id"];
|
|
2099
2246
|
if (!codeName) continue;
|
|
2100
2247
|
if (codeName === "main") continue;
|
|
2101
|
-
const profileDir =
|
|
2102
|
-
if (
|
|
2248
|
+
const profileDir = join4(homeDir, `.openclaw-${codeName}`);
|
|
2249
|
+
if (existsSync3(join4(profileDir, "openclaw.json"))) continue;
|
|
2103
2250
|
log(`Migrating agent '${codeName}' to per-agent profile`);
|
|
2104
2251
|
if (adapter.seedProfileConfig) {
|
|
2105
2252
|
adapter.seedProfileConfig(codeName);
|
|
2106
2253
|
}
|
|
2107
|
-
const sharedAuthDir =
|
|
2108
|
-
const profileAuthDir =
|
|
2109
|
-
const authFile =
|
|
2110
|
-
if (
|
|
2254
|
+
const sharedAuthDir = join4(homeDir, ".openclaw", "agents", codeName, "agent");
|
|
2255
|
+
const profileAuthDir = join4(profileDir, "agents", codeName, "agent");
|
|
2256
|
+
const authFile = join4(sharedAuthDir, "auth-profiles.json");
|
|
2257
|
+
if (existsSync3(authFile)) {
|
|
2111
2258
|
mkdirSync2(profileAuthDir, { recursive: true });
|
|
2112
|
-
const authContent =
|
|
2113
|
-
|
|
2259
|
+
const authContent = readFileSync3(authFile, "utf-8");
|
|
2260
|
+
writeFileSync3(join4(profileAuthDir, "auth-profiles.json"), authContent);
|
|
2114
2261
|
}
|
|
2115
2262
|
allocatePort(codeName);
|
|
2116
2263
|
migrated++;
|
|
@@ -2148,7 +2295,7 @@ function readGatewayToken(codeName) {
|
|
|
2148
2295
|
}
|
|
2149
2296
|
const homeDir = process.env["HOME"] ?? "/tmp";
|
|
2150
2297
|
try {
|
|
2151
|
-
const cfg = JSON.parse(
|
|
2298
|
+
const cfg = JSON.parse(readFileSync3(join4(homeDir, `.openclaw-${codeName}`, "openclaw.json"), "utf-8"));
|
|
2152
2299
|
return cfg?.gateway?.auth?.token;
|
|
2153
2300
|
} catch {
|
|
2154
2301
|
return void 0;
|
|
@@ -2157,10 +2304,10 @@ function readGatewayToken(codeName) {
|
|
|
2157
2304
|
var GATEWAY_HUNG_TIMEOUT_MS = 5 * 6e4;
|
|
2158
2305
|
function isGatewayHung(codeName) {
|
|
2159
2306
|
const homeDir = process.env["HOME"] ?? "/tmp";
|
|
2160
|
-
const jobsPath =
|
|
2161
|
-
if (!
|
|
2307
|
+
const jobsPath = join4(homeDir, `.openclaw-${codeName}`, "cron", "jobs.json");
|
|
2308
|
+
if (!existsSync3(jobsPath)) return false;
|
|
2162
2309
|
try {
|
|
2163
|
-
const data = JSON.parse(
|
|
2310
|
+
const data = JSON.parse(readFileSync3(jobsPath, "utf-8"));
|
|
2164
2311
|
const jobs = data.jobs ?? data;
|
|
2165
2312
|
if (!Array.isArray(jobs)) return false;
|
|
2166
2313
|
const now = Date.now();
|
|
@@ -2193,19 +2340,19 @@ async function ensureGatewayRunning(codeName, adapter) {
|
|
|
2193
2340
|
}
|
|
2194
2341
|
await new Promise((r) => setTimeout(r, 2e3));
|
|
2195
2342
|
const homeDir = process.env["HOME"] ?? "/tmp";
|
|
2196
|
-
const cronJobsPath =
|
|
2343
|
+
const cronJobsPath = join4(homeDir, `.openclaw-${codeName}`, "cron", "jobs.json");
|
|
2197
2344
|
clearStaleCronRunState(cronJobsPath);
|
|
2198
2345
|
} else {
|
|
2199
2346
|
if (status.port) {
|
|
2200
2347
|
try {
|
|
2201
2348
|
const homeDir = process.env["HOME"] ?? "/tmp";
|
|
2202
|
-
const configPath =
|
|
2203
|
-
if (
|
|
2204
|
-
const cfg = JSON.parse(
|
|
2349
|
+
const configPath = join4(homeDir, `.openclaw-${codeName}`, "openclaw.json");
|
|
2350
|
+
if (existsSync3(configPath)) {
|
|
2351
|
+
const cfg = JSON.parse(readFileSync3(configPath, "utf-8"));
|
|
2205
2352
|
if (cfg.gateway?.port !== status.port) {
|
|
2206
2353
|
if (!cfg.gateway) cfg.gateway = {};
|
|
2207
2354
|
cfg.gateway.port = status.port;
|
|
2208
|
-
|
|
2355
|
+
writeFileSync3(configPath, JSON.stringify(cfg, null, 2));
|
|
2209
2356
|
}
|
|
2210
2357
|
}
|
|
2211
2358
|
} catch {
|
|
@@ -2225,12 +2372,12 @@ async function ensureGatewayRunning(codeName, adapter) {
|
|
|
2225
2372
|
gatewaysStartedThisCycle.add(codeName);
|
|
2226
2373
|
try {
|
|
2227
2374
|
const homeDir = process.env["HOME"] ?? "/tmp";
|
|
2228
|
-
const configPath =
|
|
2229
|
-
if (
|
|
2230
|
-
const cfg = JSON.parse(
|
|
2375
|
+
const configPath = join4(homeDir, `.openclaw-${codeName}`, "openclaw.json");
|
|
2376
|
+
if (existsSync3(configPath)) {
|
|
2377
|
+
const cfg = JSON.parse(readFileSync3(configPath, "utf-8"));
|
|
2231
2378
|
if (!cfg.gateway) cfg.gateway = {};
|
|
2232
2379
|
cfg.gateway.port = port;
|
|
2233
|
-
|
|
2380
|
+
writeFileSync3(configPath, JSON.stringify(cfg, null, 2));
|
|
2234
2381
|
}
|
|
2235
2382
|
} catch {
|
|
2236
2383
|
}
|
|
@@ -2486,7 +2633,7 @@ async function pollCycle() {
|
|
|
2486
2633
|
}
|
|
2487
2634
|
killAgentChannelProcesses(prev.codeName, { log });
|
|
2488
2635
|
freePort(prev.codeName);
|
|
2489
|
-
const agentDir =
|
|
2636
|
+
const agentDir = join4(adapter.getAgentDir(prev.codeName), "provision");
|
|
2490
2637
|
await cleanupAgentFiles(prev.codeName, agentDir);
|
|
2491
2638
|
clearAgentCaches(prev.agentId, prev.codeName);
|
|
2492
2639
|
}
|
|
@@ -2511,6 +2658,43 @@ async function pollCycle() {
|
|
|
2511
2658
|
log(`[channel-sweep] sweep error: ${err.message}`);
|
|
2512
2659
|
});
|
|
2513
2660
|
}
|
|
2661
|
+
{
|
|
2662
|
+
const claudeCodeAgents = agentStates.filter((a) => a.status === "active").filter((a) => (agentFrameworkCache.get(a.codeName) ?? "openclaw") === "claude-code").map((a) => a.codeName);
|
|
2663
|
+
checkChannelInputs(claudeCodeAgents, {
|
|
2664
|
+
capturePane: (codeName) => {
|
|
2665
|
+
try {
|
|
2666
|
+
return syncExecFile("tmux", ["capture-pane", "-t", `agt-${codeName}`, "-p"], {
|
|
2667
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
2668
|
+
timeout: 2e3
|
|
2669
|
+
}).toString();
|
|
2670
|
+
} catch {
|
|
2671
|
+
return null;
|
|
2672
|
+
}
|
|
2673
|
+
},
|
|
2674
|
+
isClientAttached: (codeName) => {
|
|
2675
|
+
try {
|
|
2676
|
+
const out = syncExecFile("tmux", ["list-clients", "-t", `agt-${codeName}`], {
|
|
2677
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
2678
|
+
timeout: 2e3
|
|
2679
|
+
}).toString();
|
|
2680
|
+
return out.trim().length > 0;
|
|
2681
|
+
} catch {
|
|
2682
|
+
return true;
|
|
2683
|
+
}
|
|
2684
|
+
},
|
|
2685
|
+
sendEnter: (codeName) => {
|
|
2686
|
+
try {
|
|
2687
|
+
syncExecFile("tmux", ["send-keys", "-t", `agt-${codeName}`, "Enter"], {
|
|
2688
|
+
stdio: "ignore",
|
|
2689
|
+
timeout: 2e3
|
|
2690
|
+
});
|
|
2691
|
+
} catch {
|
|
2692
|
+
}
|
|
2693
|
+
},
|
|
2694
|
+
log,
|
|
2695
|
+
now: () => Date.now()
|
|
2696
|
+
});
|
|
2697
|
+
}
|
|
2514
2698
|
const lastHealthCheck = lastHarvestAt.get("__cron_health__") ?? 0;
|
|
2515
2699
|
if (Date.now() - lastHealthCheck >= HARVEST_INTERVAL_MS) {
|
|
2516
2700
|
lastHarvestAt.set("__cron_health__", Date.now());
|
|
@@ -2574,7 +2758,7 @@ async function processAgent(agent, agentStates) {
|
|
|
2574
2758
|
}
|
|
2575
2759
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
2576
2760
|
const adapter = resolveAgentFramework(agent.code_name);
|
|
2577
|
-
let agentDir =
|
|
2761
|
+
let agentDir = join4(adapter.getAgentDir(agent.code_name), "provision");
|
|
2578
2762
|
if (agent.status === "draft" || agent.status === "paused") {
|
|
2579
2763
|
log(`Agent '${agent.code_name}' is ${agent.status}, skipping provisioning`);
|
|
2580
2764
|
await stopGatewayIfRunning(agent.code_name, adapter);
|
|
@@ -2639,9 +2823,14 @@ async function processAgent(agent, agentStates) {
|
|
|
2639
2823
|
if (previousStatus && previousStatus !== agent.status) {
|
|
2640
2824
|
log(`Agent '${agent.code_name}' status changed: ${previousStatus} \u2192 ${agent.status}`);
|
|
2641
2825
|
knownVersions.delete(agent.agent_id);
|
|
2826
|
+
let channelCacheMutated = false;
|
|
2642
2827
|
for (const key of knownChannelConfigHashes.keys()) {
|
|
2643
|
-
if (key.startsWith(`${agent.agent_id}:`))
|
|
2828
|
+
if (key.startsWith(`${agent.agent_id}:`)) {
|
|
2829
|
+
knownChannelConfigHashes.delete(key);
|
|
2830
|
+
channelCacheMutated = true;
|
|
2831
|
+
}
|
|
2644
2832
|
}
|
|
2833
|
+
if (channelCacheMutated) saveChannelHashCache2();
|
|
2645
2834
|
}
|
|
2646
2835
|
knownStatuses.set(agent.agent_id, agent.status);
|
|
2647
2836
|
let refreshData;
|
|
@@ -2699,7 +2888,7 @@ async function processAgent(agent, agentStates) {
|
|
|
2699
2888
|
const frameworkId = refreshData.agent.framework ?? "openclaw";
|
|
2700
2889
|
agentFrameworkCache.set(agent.code_name, frameworkId);
|
|
2701
2890
|
const frameworkAdapter = getFramework(frameworkId);
|
|
2702
|
-
agentDir =
|
|
2891
|
+
agentDir = join4(frameworkAdapter.getAgentDir(agent.code_name), "provision");
|
|
2703
2892
|
cacheAgentDeliveryMetadata(agent.code_name, refreshData);
|
|
2704
2893
|
if (frameworkAdapter.seedProfileConfig) {
|
|
2705
2894
|
frameworkAdapter.seedProfileConfig(agent.code_name);
|
|
@@ -2729,7 +2918,7 @@ async function processAgent(agent, agentStates) {
|
|
|
2729
2918
|
const changedFiles = [];
|
|
2730
2919
|
mkdirSync2(agentDir, { recursive: true });
|
|
2731
2920
|
for (const artifact of artifacts) {
|
|
2732
|
-
const filePath =
|
|
2921
|
+
const filePath = join4(agentDir, artifact.relativePath);
|
|
2733
2922
|
let existingHash;
|
|
2734
2923
|
let newHash;
|
|
2735
2924
|
let writeContent = artifact.content;
|
|
@@ -2741,8 +2930,8 @@ async function processAgent(agent, agentStates) {
|
|
|
2741
2930
|
};
|
|
2742
2931
|
newHash = sha256(stripDynamicSections(artifact.content));
|
|
2743
2932
|
try {
|
|
2744
|
-
const projectClaudeMd =
|
|
2745
|
-
const existing =
|
|
2933
|
+
const projectClaudeMd = join4(config.configDir, agent.code_name, "project", "CLAUDE.md");
|
|
2934
|
+
const existing = readFileSync3(projectClaudeMd, "utf-8");
|
|
2746
2935
|
existingHash = sha256(stripDynamicSections(existing));
|
|
2747
2936
|
} catch {
|
|
2748
2937
|
existingHash = null;
|
|
@@ -2760,7 +2949,7 @@ async function processAgent(agent, agentStates) {
|
|
|
2760
2949
|
const generatorKeys = Object.keys(generatorServers);
|
|
2761
2950
|
let existingRaw = "";
|
|
2762
2951
|
try {
|
|
2763
|
-
existingRaw =
|
|
2952
|
+
existingRaw = readFileSync3(filePath, "utf-8");
|
|
2764
2953
|
} catch {
|
|
2765
2954
|
}
|
|
2766
2955
|
const existingServers = parseMcp(existingRaw);
|
|
@@ -2782,22 +2971,22 @@ async function processAgent(agent, agentStates) {
|
|
|
2782
2971
|
}
|
|
2783
2972
|
}
|
|
2784
2973
|
if (changedFiles.length > 0) {
|
|
2785
|
-
const isFirst = !
|
|
2974
|
+
const isFirst = !existsSync3(join4(agentDir, "CHARTER.md"));
|
|
2786
2975
|
const verb = isFirst ? "Provisioning" : "Updating";
|
|
2787
2976
|
const fileNames = changedFiles.map((f) => f.relativePath).join(", ");
|
|
2788
2977
|
log(`${verb} '${agent.code_name}': ${fileNames}`);
|
|
2789
2978
|
for (const file of changedFiles) {
|
|
2790
|
-
const filePath =
|
|
2979
|
+
const filePath = join4(agentDir, file.relativePath);
|
|
2791
2980
|
mkdirSync2(dirname(filePath), { recursive: true });
|
|
2792
|
-
|
|
2981
|
+
writeFileSync3(filePath, file.content);
|
|
2793
2982
|
}
|
|
2794
2983
|
try {
|
|
2795
|
-
const provSkillsDir =
|
|
2796
|
-
if (
|
|
2984
|
+
const provSkillsDir = join4(agentDir, ".claude", "skills");
|
|
2985
|
+
if (existsSync3(provSkillsDir)) {
|
|
2797
2986
|
for (const folder of readdirSync2(provSkillsDir)) {
|
|
2798
2987
|
if (folder.startsWith("knowledge-")) {
|
|
2799
2988
|
try {
|
|
2800
|
-
rmSync2(
|
|
2989
|
+
rmSync2(join4(provSkillsDir, folder), { recursive: true });
|
|
2801
2990
|
} catch {
|
|
2802
2991
|
}
|
|
2803
2992
|
}
|
|
@@ -2810,7 +2999,7 @@ async function processAgent(agent, agentStates) {
|
|
|
2810
2999
|
const trackedFiles2 = frameworkAdapter.driftTrackedFiles();
|
|
2811
3000
|
const hashes = /* @__PURE__ */ new Map();
|
|
2812
3001
|
for (const file of trackedFiles2) {
|
|
2813
|
-
const h = hashFile(
|
|
3002
|
+
const h = hashFile(join4(agentDir, file));
|
|
2814
3003
|
if (h) hashes.set(file, h);
|
|
2815
3004
|
}
|
|
2816
3005
|
writtenHashes.set(agent.agent_id, hashes);
|
|
@@ -2854,10 +3043,10 @@ async function processAgent(agent, agentStates) {
|
|
|
2854
3043
|
}
|
|
2855
3044
|
let lastDriftCheckAt = now;
|
|
2856
3045
|
const written = writtenHashes.get(agent.agent_id);
|
|
2857
|
-
if (written &&
|
|
3046
|
+
if (written && existsSync3(agentDir)) {
|
|
2858
3047
|
const driftedFiles = [];
|
|
2859
3048
|
for (const [file, expectedHash] of written) {
|
|
2860
|
-
const localHash = hashFile(
|
|
3049
|
+
const localHash = hashFile(join4(agentDir, file));
|
|
2861
3050
|
if (localHash && localHash !== expectedHash) {
|
|
2862
3051
|
driftedFiles.push(file);
|
|
2863
3052
|
}
|
|
@@ -2868,7 +3057,7 @@ async function processAgent(agent, agentStates) {
|
|
|
2868
3057
|
try {
|
|
2869
3058
|
const localHashes = {};
|
|
2870
3059
|
for (const file of driftedFiles) {
|
|
2871
|
-
localHashes[file] = hashFile(
|
|
3060
|
+
localHashes[file] = hashFile(join4(agentDir, file));
|
|
2872
3061
|
}
|
|
2873
3062
|
await api.post("/host/drift", {
|
|
2874
3063
|
agent_id: agent.agent_id,
|
|
@@ -2933,6 +3122,7 @@ async function processAgent(agent, agentStates) {
|
|
|
2933
3122
|
const sessionMode2 = refreshData.agent.session_mode;
|
|
2934
3123
|
frameworkAdapter.writeChannelCredentials(agent.code_name, channelId, entry.config, { sessionMode: sessionMode2, agentId: agent.agent_id });
|
|
2935
3124
|
knownChannelConfigHashes.set(cacheKey, configHash);
|
|
3125
|
+
saveChannelHashCache2();
|
|
2936
3126
|
log(`Channel credentials written for '${agent.code_name}/${channelId}' (reason=${reason}, hash=${configHash.slice(0, 8)}${prevHash ? `, prev=${prevHash.slice(0, 8)}` : ""})`);
|
|
2937
3127
|
} catch (err) {
|
|
2938
3128
|
log(`Failed to write channel credentials for '${agent.code_name}/${channelId}': ${err.message}`);
|
|
@@ -2951,19 +3141,19 @@ async function processAgent(agent, agentStates) {
|
|
|
2951
3141
|
if (agentSessionMode === "persistent" && (agentFrameworkCache.get(agent.code_name) ?? "openclaw") === "claude-code") {
|
|
2952
3142
|
try {
|
|
2953
3143
|
const agentProvisionDir = agentDir;
|
|
2954
|
-
const projectDir =
|
|
3144
|
+
const projectDir = join4(homedir3(), ".augmented", agent.code_name, "project");
|
|
2955
3145
|
mkdirSync2(agentProvisionDir, { recursive: true });
|
|
2956
3146
|
mkdirSync2(projectDir, { recursive: true });
|
|
2957
|
-
const provisionMcpPath =
|
|
2958
|
-
const projectMcpPath =
|
|
3147
|
+
const provisionMcpPath = join4(agentProvisionDir, ".mcp.json");
|
|
3148
|
+
const projectMcpPath = join4(projectDir, ".mcp.json");
|
|
2959
3149
|
let mcpConfig = { mcpServers: {} };
|
|
2960
3150
|
try {
|
|
2961
|
-
mcpConfig = JSON.parse(
|
|
3151
|
+
mcpConfig = JSON.parse(readFileSync3(provisionMcpPath, "utf-8"));
|
|
2962
3152
|
if (!mcpConfig.mcpServers) mcpConfig.mcpServers = {};
|
|
2963
3153
|
} catch {
|
|
2964
3154
|
}
|
|
2965
|
-
const localDirectChatChannel =
|
|
2966
|
-
if (
|
|
3155
|
+
const localDirectChatChannel = join4(homedir3(), ".augmented", "_mcp", "direct-chat-channel.js");
|
|
3156
|
+
if (existsSync3(localDirectChatChannel) && !mcpConfig.mcpServers["direct-chat"]) {
|
|
2967
3157
|
mcpConfig.mcpServers["direct-chat"] = {
|
|
2968
3158
|
command: "node",
|
|
2969
3159
|
args: [localDirectChatChannel],
|
|
@@ -2974,12 +3164,12 @@ async function processAgent(agent, agentStates) {
|
|
|
2974
3164
|
}
|
|
2975
3165
|
};
|
|
2976
3166
|
const serialized = JSON.stringify(mcpConfig, null, 2);
|
|
2977
|
-
|
|
2978
|
-
|
|
3167
|
+
writeFileSync3(provisionMcpPath, serialized);
|
|
3168
|
+
writeFileSync3(projectMcpPath, serialized);
|
|
2979
3169
|
log(`Channel credentials written for '${agent.code_name}/direct-chat'`);
|
|
2980
3170
|
}
|
|
2981
|
-
const staleChannelsPath =
|
|
2982
|
-
if (
|
|
3171
|
+
const staleChannelsPath = join4(projectDir, ".mcp-channels.json");
|
|
3172
|
+
if (existsSync3(staleChannelsPath)) {
|
|
2983
3173
|
try {
|
|
2984
3174
|
rmSync2(staleChannelsPath, { force: true });
|
|
2985
3175
|
} catch {
|
|
@@ -3094,8 +3284,8 @@ async function processAgent(agent, agentStates) {
|
|
|
3094
3284
|
const mcpPath = frameworkAdapter.getMcpPath(agent.code_name);
|
|
3095
3285
|
if (mcpPath) {
|
|
3096
3286
|
try {
|
|
3097
|
-
const { readFileSync:
|
|
3098
|
-
const mcpConfig = JSON.parse(
|
|
3287
|
+
const { readFileSync: readFileSync4 } = await import("fs");
|
|
3288
|
+
const mcpConfig = JSON.parse(readFileSync4(mcpPath, "utf-8"));
|
|
3099
3289
|
if (mcpConfig.mcpServers) {
|
|
3100
3290
|
const managedPrefixes = [
|
|
3101
3291
|
"composio_",
|
|
@@ -3187,8 +3377,8 @@ async function processAgent(agent, agentStates) {
|
|
|
3187
3377
|
if (agent.status === "active") {
|
|
3188
3378
|
if (frameworkAdapter.installPlugin) {
|
|
3189
3379
|
try {
|
|
3190
|
-
const pluginPath =
|
|
3191
|
-
if (
|
|
3380
|
+
const pluginPath = join4(process.cwd(), "packages", "openclaw-plugin-augmented", "src", "index.ts");
|
|
3381
|
+
if (existsSync3(pluginPath)) {
|
|
3192
3382
|
frameworkAdapter.installPlugin(agent.code_name, "augmented", pluginPath, {
|
|
3193
3383
|
agtHost: requireHost(),
|
|
3194
3384
|
agtApiKey: getApiKey() ?? void 0,
|
|
@@ -3258,16 +3448,16 @@ async function processAgent(agent, agentStates) {
|
|
|
3258
3448
|
const frameworkId2 = frameworkAdapter.id;
|
|
3259
3449
|
const candidateSkillDirs = [
|
|
3260
3450
|
// Claude Code — framework runtime tree
|
|
3261
|
-
|
|
3451
|
+
join4(homedir4(), ".augmented", agent.code_name, "skills"),
|
|
3262
3452
|
// Claude Code — project tree
|
|
3263
|
-
|
|
3453
|
+
join4(homedir4(), ".augmented", agent.code_name, "project", ".claude", "skills"),
|
|
3264
3454
|
// OpenClaw — framework runtime tree
|
|
3265
|
-
|
|
3455
|
+
join4(homedir4(), `.openclaw-${agent.code_name}`, "skills"),
|
|
3266
3456
|
// Defensive: legacy provision-side path, not currently an
|
|
3267
3457
|
// install target but cheap to sweep.
|
|
3268
|
-
|
|
3458
|
+
join4(agentDir, ".claude", "skills")
|
|
3269
3459
|
];
|
|
3270
|
-
const existingDirs = candidateSkillDirs.filter((d) =>
|
|
3460
|
+
const existingDirs = candidateSkillDirs.filter((d) => existsSync3(d));
|
|
3271
3461
|
const discoveredEntries = /* @__PURE__ */ new Set();
|
|
3272
3462
|
for (const dir of existingDirs) {
|
|
3273
3463
|
try {
|
|
@@ -3281,8 +3471,8 @@ async function processAgent(agent, agentStates) {
|
|
|
3281
3471
|
}
|
|
3282
3472
|
const removeSkillFolder = (entry, reason) => {
|
|
3283
3473
|
for (const dir of existingDirs) {
|
|
3284
|
-
const p =
|
|
3285
|
-
if (
|
|
3474
|
+
const p = join4(dir, entry);
|
|
3475
|
+
if (existsSync3(p)) {
|
|
3286
3476
|
rmSync3(p, { recursive: true, force: true });
|
|
3287
3477
|
}
|
|
3288
3478
|
}
|
|
@@ -3456,10 +3646,10 @@ async function processAgent(agent, agentStates) {
|
|
|
3456
3646
|
lastWorkTriggerAt.set(agent.code_name, triggerTs);
|
|
3457
3647
|
if (agentFw === "openclaw" && gatewayRunning && gatewayPort) {
|
|
3458
3648
|
const homeDir = process.env["HOME"] ?? "/tmp";
|
|
3459
|
-
const jobsPath =
|
|
3460
|
-
if (
|
|
3649
|
+
const jobsPath = join4(homeDir, `.openclaw-${agent.code_name}`, "cron", "jobs.json");
|
|
3650
|
+
if (existsSync3(jobsPath)) {
|
|
3461
3651
|
try {
|
|
3462
|
-
const jobsData = JSON.parse(
|
|
3652
|
+
const jobsData = JSON.parse(readFileSync3(jobsPath, "utf-8"));
|
|
3463
3653
|
const kanbanJob = (jobsData.jobs ?? []).find(
|
|
3464
3654
|
(j) => typeof j.name === "string" && j.name.includes("kanban-work")
|
|
3465
3655
|
);
|
|
@@ -3585,10 +3775,10 @@ In progress for ${age} minutes \u2014 auto-failed`).catch(() => {
|
|
|
3585
3775
|
}
|
|
3586
3776
|
}
|
|
3587
3777
|
const trackedFiles = frameworkAdapter.driftTrackedFiles();
|
|
3588
|
-
if (trackedFiles.length > 0 &&
|
|
3778
|
+
if (trackedFiles.length > 0 && existsSync3(agentDir)) {
|
|
3589
3779
|
const hashes = /* @__PURE__ */ new Map();
|
|
3590
3780
|
for (const file of trackedFiles) {
|
|
3591
|
-
const h = hashFile(
|
|
3781
|
+
const h = hashFile(join4(agentDir, file));
|
|
3592
3782
|
if (h) hashes.set(file, h);
|
|
3593
3783
|
}
|
|
3594
3784
|
writtenHashes.set(agent.agent_id, hashes);
|
|
@@ -3622,19 +3812,19 @@ function cleanupStaleSessions(codeName) {
|
|
|
3622
3812
|
lastCleanupAt.set(codeName, Date.now());
|
|
3623
3813
|
const homeDir = process.env["HOME"] ?? "/tmp";
|
|
3624
3814
|
for (const agentDir of ["main", codeName]) {
|
|
3625
|
-
const sessionsDir =
|
|
3815
|
+
const sessionsDir = join4(homeDir, `.openclaw-${codeName}`, "agents", agentDir, "sessions");
|
|
3626
3816
|
cleanupCronSessions(sessionsDir, CRON_SESSION_KEEP_COUNT);
|
|
3627
3817
|
}
|
|
3628
|
-
const cronRunsDir =
|
|
3818
|
+
const cronRunsDir = join4(homeDir, `.openclaw-${codeName}`, "cron", "runs");
|
|
3629
3819
|
cleanupOldFiles(cronRunsDir, CRON_RUN_RETENTION_DAYS, ".jsonl");
|
|
3630
|
-
const cronJobsPath =
|
|
3820
|
+
const cronJobsPath = join4(homeDir, `.openclaw-${codeName}`, "cron", "jobs.json");
|
|
3631
3821
|
clearStaleCronRunState(cronJobsPath);
|
|
3632
3822
|
}
|
|
3633
3823
|
function cleanupCronSessions(sessionsDir, keepCount) {
|
|
3634
|
-
const indexPath =
|
|
3635
|
-
if (!
|
|
3824
|
+
const indexPath = join4(sessionsDir, "sessions.json");
|
|
3825
|
+
if (!existsSync3(indexPath)) return;
|
|
3636
3826
|
try {
|
|
3637
|
-
const raw =
|
|
3827
|
+
const raw = readFileSync3(indexPath, "utf-8");
|
|
3638
3828
|
const index = JSON.parse(raw);
|
|
3639
3829
|
const cronRunKeys = Object.keys(index).filter((k) => k.includes(":cron:") && k.includes(":run:")).map((k) => ({
|
|
3640
3830
|
key: k,
|
|
@@ -3647,9 +3837,9 @@ function cleanupCronSessions(sessionsDir, keepCount) {
|
|
|
3647
3837
|
for (const entry of toDelete) {
|
|
3648
3838
|
delete index[entry.key];
|
|
3649
3839
|
if (entry.sessionId) {
|
|
3650
|
-
const sessionFile =
|
|
3840
|
+
const sessionFile = join4(sessionsDir, `${entry.sessionId}.jsonl`);
|
|
3651
3841
|
try {
|
|
3652
|
-
if (
|
|
3842
|
+
if (existsSync3(sessionFile)) {
|
|
3653
3843
|
unlinkSync(sessionFile);
|
|
3654
3844
|
deletedFiles++;
|
|
3655
3845
|
}
|
|
@@ -3669,8 +3859,8 @@ function cleanupCronSessions(sessionsDir, keepCount) {
|
|
|
3669
3859
|
delete index[parentKey];
|
|
3670
3860
|
if (parentSessionId) {
|
|
3671
3861
|
try {
|
|
3672
|
-
const f =
|
|
3673
|
-
if (
|
|
3862
|
+
const f = join4(sessionsDir, `${parentSessionId}.jsonl`);
|
|
3863
|
+
if (existsSync3(f)) {
|
|
3674
3864
|
unlinkSync(f);
|
|
3675
3865
|
deletedFiles++;
|
|
3676
3866
|
}
|
|
@@ -3679,7 +3869,7 @@ function cleanupCronSessions(sessionsDir, keepCount) {
|
|
|
3679
3869
|
}
|
|
3680
3870
|
}
|
|
3681
3871
|
}
|
|
3682
|
-
|
|
3872
|
+
writeFileSync3(indexPath, JSON.stringify(index));
|
|
3683
3873
|
if (toDelete.length > 0) {
|
|
3684
3874
|
log(`Cleaned ${toDelete.length} cron session(s) and ${deletedFiles} file(s) from ${sessionsDir}`);
|
|
3685
3875
|
}
|
|
@@ -3688,9 +3878,9 @@ function cleanupCronSessions(sessionsDir, keepCount) {
|
|
|
3688
3878
|
}
|
|
3689
3879
|
var STALE_RUN_TIMEOUT_MS = 5 * 6e4;
|
|
3690
3880
|
function clearStaleCronRunState(jobsPath) {
|
|
3691
|
-
if (!
|
|
3881
|
+
if (!existsSync3(jobsPath)) return;
|
|
3692
3882
|
try {
|
|
3693
|
-
const raw =
|
|
3883
|
+
const raw = readFileSync3(jobsPath, "utf-8");
|
|
3694
3884
|
const data = JSON.parse(raw);
|
|
3695
3885
|
const jobs = data.jobs ?? data;
|
|
3696
3886
|
if (!Array.isArray(jobs)) return;
|
|
@@ -3715,19 +3905,19 @@ function clearStaleCronRunState(jobsPath) {
|
|
|
3715
3905
|
}
|
|
3716
3906
|
}
|
|
3717
3907
|
if (changed) {
|
|
3718
|
-
|
|
3908
|
+
writeFileSync3(jobsPath, JSON.stringify(data, null, 2));
|
|
3719
3909
|
}
|
|
3720
3910
|
} catch {
|
|
3721
3911
|
}
|
|
3722
3912
|
}
|
|
3723
3913
|
function cleanupOldFiles(dir, maxAgeDays, ext) {
|
|
3724
|
-
if (!
|
|
3914
|
+
if (!existsSync3(dir)) return;
|
|
3725
3915
|
const cutoff = Date.now() - maxAgeDays * 24 * 60 * 60 * 1e3;
|
|
3726
3916
|
let removed = 0;
|
|
3727
3917
|
try {
|
|
3728
3918
|
for (const f of readdirSync2(dir)) {
|
|
3729
3919
|
if (!f.endsWith(ext)) continue;
|
|
3730
|
-
const fullPath =
|
|
3920
|
+
const fullPath = join4(dir, f);
|
|
3731
3921
|
try {
|
|
3732
3922
|
const st = statSync(fullPath);
|
|
3733
3923
|
if (st.mtimeMs < cutoff) {
|
|
@@ -3871,7 +4061,7 @@ async function fetchPriorScheduledRuns(agentId, taskId) {
|
|
|
3871
4061
|
}
|
|
3872
4062
|
async function executeAndProcessClaudeTask(codeName, agentId, task, prompt) {
|
|
3873
4063
|
const projectDir = getProjectDir(codeName);
|
|
3874
|
-
const mcpConfigPath =
|
|
4064
|
+
const mcpConfigPath = join4(projectDir, ".mcp.json");
|
|
3875
4065
|
let runId = null;
|
|
3876
4066
|
let kanbanItemId = null;
|
|
3877
4067
|
let taskResult;
|
|
@@ -3879,11 +4069,11 @@ async function executeAndProcessClaudeTask(codeName, agentId, task, prompt) {
|
|
|
3879
4069
|
const priorRuns = await fetchPriorScheduledRuns(agentId, task.taskId);
|
|
3880
4070
|
prompt = wrapScheduledTaskPrompt(prompt, { priorRuns });
|
|
3881
4071
|
try {
|
|
3882
|
-
const claudeMdPath =
|
|
4072
|
+
const claudeMdPath = join4(projectDir, "CLAUDE.md");
|
|
3883
4073
|
const serverNames = [];
|
|
3884
|
-
if (
|
|
4074
|
+
if (existsSync3(mcpConfigPath)) {
|
|
3885
4075
|
try {
|
|
3886
|
-
const d = JSON.parse(
|
|
4076
|
+
const d = JSON.parse(readFileSync3(mcpConfigPath, "utf-8"));
|
|
3887
4077
|
if (d.mcpServers) serverNames.push(...Object.keys(d.mcpServers));
|
|
3888
4078
|
} catch {
|
|
3889
4079
|
}
|
|
@@ -3902,14 +4092,14 @@ async function executeAndProcessClaudeTask(codeName, agentId, task, prompt) {
|
|
|
3902
4092
|
"--allowedTools",
|
|
3903
4093
|
allowedTools
|
|
3904
4094
|
];
|
|
3905
|
-
if (
|
|
4095
|
+
if (existsSync3(claudeMdPath)) {
|
|
3906
4096
|
claudeArgs.push("--system-prompt-file", claudeMdPath);
|
|
3907
4097
|
}
|
|
3908
4098
|
const childEnv = { ...process.env };
|
|
3909
|
-
const envIntPath =
|
|
3910
|
-
if (
|
|
4099
|
+
const envIntPath = join4(projectDir, ".env.integrations");
|
|
4100
|
+
if (existsSync3(envIntPath)) {
|
|
3911
4101
|
try {
|
|
3912
|
-
for (const line of
|
|
4102
|
+
for (const line of readFileSync3(envIntPath, "utf-8").split("\n")) {
|
|
3913
4103
|
if (!line || line.startsWith("#") || !line.includes("=")) continue;
|
|
3914
4104
|
const eqIdx = line.indexOf("=");
|
|
3915
4105
|
childEnv[line.slice(0, eqIdx)] = line.slice(eqIdx + 1);
|
|
@@ -4091,8 +4281,8 @@ var claudeAuthTupleBySession = /* @__PURE__ */ new Map();
|
|
|
4091
4281
|
async function ensurePersistentSession(agent, tasks, boardItems, refreshData) {
|
|
4092
4282
|
const codeName = agent.code_name;
|
|
4093
4283
|
const projectDir = getProjectDir2(codeName);
|
|
4094
|
-
const mcpConfigPath =
|
|
4095
|
-
const claudeMdPath =
|
|
4284
|
+
const mcpConfigPath = join4(projectDir, ".mcp.json");
|
|
4285
|
+
const claudeMdPath = join4(projectDir, "CLAUDE.md");
|
|
4096
4286
|
const channelConfigs = refreshData.channel_configs;
|
|
4097
4287
|
const channels = [];
|
|
4098
4288
|
const devChannels = [];
|
|
@@ -4567,11 +4757,11 @@ async function processDirectChatMessage(agent, msg) {
|
|
|
4567
4757
|
if (fw === "claude-code") {
|
|
4568
4758
|
const { getProjectDir: ccProjectDir } = await import("../claude-scheduler-XHJS2MZV.js");
|
|
4569
4759
|
const projDir = ccProjectDir(agent.codeName);
|
|
4570
|
-
const mcpConfigPath =
|
|
4760
|
+
const mcpConfigPath = join4(projDir, ".mcp.json");
|
|
4571
4761
|
const serverNames = [];
|
|
4572
|
-
if (
|
|
4762
|
+
if (existsSync3(mcpConfigPath)) {
|
|
4573
4763
|
try {
|
|
4574
|
-
const d = JSON.parse(
|
|
4764
|
+
const d = JSON.parse(readFileSync3(mcpConfigPath, "utf-8"));
|
|
4575
4765
|
if (d.mcpServers) serverNames.push(...Object.keys(d.mcpServers));
|
|
4576
4766
|
} catch {
|
|
4577
4767
|
}
|
|
@@ -4590,15 +4780,15 @@ async function processDirectChatMessage(agent, msg) {
|
|
|
4590
4780
|
"--allowedTools",
|
|
4591
4781
|
allowedTools
|
|
4592
4782
|
];
|
|
4593
|
-
const chatClaudeMd =
|
|
4594
|
-
if (
|
|
4783
|
+
const chatClaudeMd = join4(projDir, "CLAUDE.md");
|
|
4784
|
+
if (existsSync3(chatClaudeMd)) {
|
|
4595
4785
|
chatArgs.push("--system-prompt-file", chatClaudeMd);
|
|
4596
4786
|
}
|
|
4597
|
-
const envIntPath =
|
|
4787
|
+
const envIntPath = join4(projDir, ".env.integrations");
|
|
4598
4788
|
const childEnv = { ...process.env };
|
|
4599
|
-
if (
|
|
4789
|
+
if (existsSync3(envIntPath)) {
|
|
4600
4790
|
try {
|
|
4601
|
-
for (const line of
|
|
4791
|
+
for (const line of readFileSync3(envIntPath, "utf-8").split("\n")) {
|
|
4602
4792
|
if (!line || line.startsWith("#") || !line.includes("=")) continue;
|
|
4603
4793
|
const eqIdx = line.indexOf("=");
|
|
4604
4794
|
childEnv[line.slice(0, eqIdx)] = line.slice(eqIdx + 1);
|
|
@@ -4879,12 +5069,12 @@ function getBuiltInSkillContent(skillId) {
|
|
|
4879
5069
|
if (builtInSkillCache.has(skillId)) return builtInSkillCache.get(skillId);
|
|
4880
5070
|
try {
|
|
4881
5071
|
const candidates = [
|
|
4882
|
-
|
|
4883
|
-
|
|
5072
|
+
join4(process.cwd(), "skills", skillId, "SKILL.md"),
|
|
5073
|
+
join4(new URL(".", import.meta.url).pathname, "..", "..", "..", "..", "skills", skillId, "SKILL.md")
|
|
4884
5074
|
];
|
|
4885
5075
|
for (const candidate of candidates) {
|
|
4886
|
-
if (
|
|
4887
|
-
const content =
|
|
5076
|
+
if (existsSync3(candidate)) {
|
|
5077
|
+
const content = readFileSync3(candidate, "utf-8");
|
|
4888
5078
|
const files = [{ relativePath: "SKILL.md", content }];
|
|
4889
5079
|
builtInSkillCache.set(skillId, files);
|
|
4890
5080
|
return files;
|
|
@@ -5773,8 +5963,8 @@ function parseMemoryFile(raw, fallbackName) {
|
|
|
5773
5963
|
};
|
|
5774
5964
|
}
|
|
5775
5965
|
async function syncMemories(agent, configDir, log2) {
|
|
5776
|
-
const projectDir =
|
|
5777
|
-
const memoryDir =
|
|
5966
|
+
const projectDir = join4(configDir, agent.code_name, "project");
|
|
5967
|
+
const memoryDir = join4(projectDir, "memory");
|
|
5778
5968
|
const isFreshSync = pendingFreshMemorySync.has(agent.agent_id);
|
|
5779
5969
|
if (isFreshSync) {
|
|
5780
5970
|
log2(`[memory-sync] Fresh-sync requested for '${agent.code_name}' \u2014 pulling DB first`);
|
|
@@ -5785,14 +5975,14 @@ async function syncMemories(agent, configDir, log2) {
|
|
|
5785
5975
|
}
|
|
5786
5976
|
pendingFreshMemorySync.delete(agent.agent_id);
|
|
5787
5977
|
}
|
|
5788
|
-
if (
|
|
5978
|
+
if (existsSync3(memoryDir)) {
|
|
5789
5979
|
const prevHashes = memoryFileHashes.get(agent.agent_id) ?? /* @__PURE__ */ new Map();
|
|
5790
5980
|
const currentHashes = /* @__PURE__ */ new Map();
|
|
5791
5981
|
const changedMemories = [];
|
|
5792
5982
|
for (const file of readdirSync2(memoryDir)) {
|
|
5793
5983
|
if (!file.endsWith(".md")) continue;
|
|
5794
5984
|
try {
|
|
5795
|
-
const raw =
|
|
5985
|
+
const raw = readFileSync3(join4(memoryDir, file), "utf-8");
|
|
5796
5986
|
const fileHash = createHash("sha256").update(raw).digest("hex").slice(0, 16);
|
|
5797
5987
|
currentHashes.set(file, fileHash);
|
|
5798
5988
|
if (prevHashes.get(file) === fileHash) continue;
|
|
@@ -5817,7 +6007,7 @@ async function syncMemories(agent, configDir, log2) {
|
|
|
5817
6007
|
} catch (err) {
|
|
5818
6008
|
for (const mem of changedMemories) {
|
|
5819
6009
|
for (const [file] of currentHashes) {
|
|
5820
|
-
const parsed = parseMemoryFile(
|
|
6010
|
+
const parsed = parseMemoryFile(readFileSync3(join4(memoryDir, file), "utf-8"), file.replace(/\.md$/, ""));
|
|
5821
6011
|
if (parsed?.name === mem.name) currentHashes.delete(file);
|
|
5822
6012
|
}
|
|
5823
6013
|
}
|
|
@@ -5830,7 +6020,7 @@ async function syncMemories(agent, configDir, log2) {
|
|
|
5830
6020
|
}
|
|
5831
6021
|
}
|
|
5832
6022
|
async function downloadMemories(agent, memoryDir, log2, { force }) {
|
|
5833
|
-
const localFiles =
|
|
6023
|
+
const localFiles = existsSync3(memoryDir) ? readdirSync2(memoryDir).filter((f) => f.endsWith(".md")).sort() : [];
|
|
5834
6024
|
const localListHash = createHash("sha256").update(localFiles.join(",")).digest("hex").slice(0, 16);
|
|
5835
6025
|
const prevLocalHash = lastLocalFileHash.get(agent.agent_id);
|
|
5836
6026
|
const prevDownload = lastDownloadHash.get(agent.agent_id);
|
|
@@ -5852,7 +6042,7 @@ async function downloadMemories(agent, memoryDir, log2, { force }) {
|
|
|
5852
6042
|
const mem = dbMemories.memories[i];
|
|
5853
6043
|
const rawSlug = mem.name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/(^-|-$)/g, "").slice(0, 60);
|
|
5854
6044
|
const slug = rawSlug || `memory-${i}`;
|
|
5855
|
-
const filePath =
|
|
6045
|
+
const filePath = join4(memoryDir, `${slug}.md`);
|
|
5856
6046
|
const desired = `---
|
|
5857
6047
|
name: ${JSON.stringify(mem.name)}
|
|
5858
6048
|
type: ${mem.type}
|
|
@@ -5861,17 +6051,17 @@ description: ${JSON.stringify(mem.content.slice(0, 200))}
|
|
|
5861
6051
|
|
|
5862
6052
|
${mem.content}
|
|
5863
6053
|
`;
|
|
5864
|
-
if (
|
|
6054
|
+
if (existsSync3(filePath)) {
|
|
5865
6055
|
let existing = "";
|
|
5866
6056
|
try {
|
|
5867
|
-
existing =
|
|
6057
|
+
existing = readFileSync3(filePath, "utf-8");
|
|
5868
6058
|
} catch {
|
|
5869
6059
|
}
|
|
5870
6060
|
if (existing === desired) continue;
|
|
5871
|
-
|
|
6061
|
+
writeFileSync3(filePath, desired);
|
|
5872
6062
|
overwritten++;
|
|
5873
6063
|
} else {
|
|
5874
|
-
|
|
6064
|
+
writeFileSync3(filePath, desired);
|
|
5875
6065
|
written++;
|
|
5876
6066
|
}
|
|
5877
6067
|
}
|
|
@@ -5888,7 +6078,7 @@ ${mem.content}
|
|
|
5888
6078
|
}
|
|
5889
6079
|
}
|
|
5890
6080
|
async function cleanupAgentFiles(codeName, agentDir) {
|
|
5891
|
-
if (
|
|
6081
|
+
if (existsSync3(agentDir)) {
|
|
5892
6082
|
try {
|
|
5893
6083
|
rmSync2(agentDir, { recursive: true, force: true });
|
|
5894
6084
|
log(`Removed provision directory for '${codeName}'`);
|
|
@@ -5977,6 +6167,7 @@ function startPolling() {
|
|
|
5977
6167
|
if (!config || running) return;
|
|
5978
6168
|
running = true;
|
|
5979
6169
|
void startCaffeinate();
|
|
6170
|
+
loadChannelHashCache2();
|
|
5980
6171
|
log(`Starting poll loop (interval=${config.intervalMs}ms, configDir=${config.configDir})`);
|
|
5981
6172
|
void killAllAgtTmuxSessions().catch(() => {
|
|
5982
6173
|
}).then(() => migrateToProfiles()).then(() => {
|
|
@@ -6055,7 +6246,7 @@ async function stopPolling(opts = {}) {
|
|
|
6055
6246
|
function startManager(opts) {
|
|
6056
6247
|
config = opts;
|
|
6057
6248
|
log(
|
|
6058
|
-
`[startup] worker pid=${process.pid} ppid=${process.ppid} node=${process.version} log=${
|
|
6249
|
+
`[startup] worker pid=${process.pid} ppid=${process.ppid} node=${process.version} log=${join4(homedir3(), ".augmented", "manager.log")}`
|
|
6059
6250
|
);
|
|
6060
6251
|
deployMcpAssets();
|
|
6061
6252
|
void ensureHostFrameworkBinaries();
|
|
@@ -6116,14 +6307,14 @@ function restartRunningChannelMcps(basenames) {
|
|
|
6116
6307
|
}
|
|
6117
6308
|
}
|
|
6118
6309
|
function deployMcpAssets() {
|
|
6119
|
-
const targetDir =
|
|
6310
|
+
const targetDir = join4(homedir3(), ".augmented", "_mcp");
|
|
6120
6311
|
mkdirSync2(targetDir, { recursive: true });
|
|
6121
6312
|
const moduleDir = dirname(fileURLToPath(import.meta.url));
|
|
6122
6313
|
let mcpSourceDir = "";
|
|
6123
6314
|
let dir = moduleDir;
|
|
6124
6315
|
for (let i = 0; i < 6; i++) {
|
|
6125
|
-
const candidate =
|
|
6126
|
-
if (
|
|
6316
|
+
const candidate = join4(dir, "mcp");
|
|
6317
|
+
if (existsSync3(join4(candidate, "index.js"))) {
|
|
6127
6318
|
mcpSourceDir = candidate;
|
|
6128
6319
|
break;
|
|
6129
6320
|
}
|
|
@@ -6138,8 +6329,8 @@ function deployMcpAssets() {
|
|
|
6138
6329
|
const changedBasenames = [];
|
|
6139
6330
|
const fileHash = (p) => {
|
|
6140
6331
|
try {
|
|
6141
|
-
if (!
|
|
6142
|
-
return createHash("sha256").update(
|
|
6332
|
+
if (!existsSync3(p)) return null;
|
|
6333
|
+
return createHash("sha256").update(readFileSync3(p)).digest("hex");
|
|
6143
6334
|
} catch {
|
|
6144
6335
|
return null;
|
|
6145
6336
|
}
|
|
@@ -6150,9 +6341,9 @@ function deployMcpAssets() {
|
|
|
6150
6341
|
"telegram-channel.js"
|
|
6151
6342
|
]);
|
|
6152
6343
|
for (const file of ["index.js", "slack-channel.js", "direct-chat-channel.js", "telegram-channel.js"]) {
|
|
6153
|
-
const src =
|
|
6154
|
-
const dst =
|
|
6155
|
-
if (!
|
|
6344
|
+
const src = join4(mcpSourceDir, file);
|
|
6345
|
+
const dst = join4(targetDir, file);
|
|
6346
|
+
if (!existsSync3(src)) continue;
|
|
6156
6347
|
const before = fileHash(dst);
|
|
6157
6348
|
try {
|
|
6158
6349
|
copyFileSync(src, dst);
|
|
@@ -6169,23 +6360,23 @@ function deployMcpAssets() {
|
|
|
6169
6360
|
log(`[manager] Bundle(s) updated: ${changedBasenames.join(", ")} \u2014 signalling running instances to restart`);
|
|
6170
6361
|
restartRunningChannelMcps(changedBasenames);
|
|
6171
6362
|
}
|
|
6172
|
-
const localMcpPath =
|
|
6363
|
+
const localMcpPath = join4(targetDir, "index.js");
|
|
6173
6364
|
try {
|
|
6174
|
-
const agentsDir =
|
|
6175
|
-
if (
|
|
6365
|
+
const agentsDir = join4(homedir3(), ".augmented", "agents");
|
|
6366
|
+
if (existsSync3(agentsDir)) {
|
|
6176
6367
|
for (const entry of readdirSync2(agentsDir, { withFileTypes: true })) {
|
|
6177
6368
|
if (!entry.isDirectory()) continue;
|
|
6178
6369
|
for (const subdir of ["provision", "project"]) {
|
|
6179
|
-
const mcpJsonPath =
|
|
6370
|
+
const mcpJsonPath = join4(agentsDir, entry.name, subdir, ".mcp.json");
|
|
6180
6371
|
try {
|
|
6181
|
-
const raw =
|
|
6372
|
+
const raw = readFileSync3(mcpJsonPath, "utf-8");
|
|
6182
6373
|
if (!raw.includes("@integrity-labs/augmented-mcp")) continue;
|
|
6183
6374
|
const mcpConfig = JSON.parse(raw);
|
|
6184
6375
|
const augServer = mcpConfig.mcpServers?.["augmented"];
|
|
6185
6376
|
if (!augServer) continue;
|
|
6186
6377
|
augServer.command = "node";
|
|
6187
6378
|
augServer.args = [localMcpPath];
|
|
6188
|
-
|
|
6379
|
+
writeFileSync3(mcpJsonPath, JSON.stringify(mcpConfig, null, 2));
|
|
6189
6380
|
log(`[manager] Patched ${entry.name}/${subdir}/.mcp.json: npx \u2192 node`);
|
|
6190
6381
|
} catch {
|
|
6191
6382
|
}
|