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