@integrity-labs/agt-cli 0.10.7 → 0.10.9
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 +231 -83
- package/dist/bin/agt.js.map +1 -1
- package/dist/{chunk-VDUA5FEW.js → chunk-PZG4XPJV.js} +5 -8
- package/dist/chunk-PZG4XPJV.js.map +1 -0
- package/dist/lib/manager-worker.js +192 -83
- package/dist/lib/manager-worker.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-VDUA5FEW.js.map +0 -1
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
provisionStopHook,
|
|
11
11
|
requireHost,
|
|
12
12
|
resolveChannels
|
|
13
|
-
} from "../chunk-
|
|
13
|
+
} from "../chunk-PZG4XPJV.js";
|
|
14
14
|
import {
|
|
15
15
|
findTaskByTemplate,
|
|
16
16
|
getProjectDir,
|
|
@@ -34,8 +34,8 @@ import {
|
|
|
34
34
|
import { createHash } from "crypto";
|
|
35
35
|
import { readFileSync, writeFileSync, mkdirSync, existsSync, rmSync, readdirSync, statSync, unlinkSync, copyFileSync } from "fs";
|
|
36
36
|
import https from "https";
|
|
37
|
-
import { join, dirname } from "path";
|
|
38
|
-
import { homedir } from "os";
|
|
37
|
+
import { join as join2, dirname } from "path";
|
|
38
|
+
import { homedir as homedir2 } from "os";
|
|
39
39
|
import { fileURLToPath } from "url";
|
|
40
40
|
|
|
41
41
|
// src/lib/plugin-context-render.ts
|
|
@@ -339,6 +339,88 @@ var GatewayClientPool = class extends EventEmitter {
|
|
|
339
339
|
}
|
|
340
340
|
};
|
|
341
341
|
|
|
342
|
+
// src/lib/claude-auth-detect.ts
|
|
343
|
+
import { readFile } from "fs/promises";
|
|
344
|
+
import { homedir, platform } from "os";
|
|
345
|
+
import { join } from "path";
|
|
346
|
+
import { execFile } from "child_process";
|
|
347
|
+
import { promisify } from "util";
|
|
348
|
+
var execFileAsync = promisify(execFile);
|
|
349
|
+
var EXPIRING_SOON_MS = 48 * 60 * 60 * 1e3;
|
|
350
|
+
async function detectClaudeAuth() {
|
|
351
|
+
if (process.env["ANTHROPIC_API_KEY"] || process.env["ANTHROPIC_AUTH_TOKEN"]) {
|
|
352
|
+
return { mode: "api_key", status: "valid", expires_at: null };
|
|
353
|
+
}
|
|
354
|
+
const creds = await readOauthCredentials();
|
|
355
|
+
if (!creds) return null;
|
|
356
|
+
return computeSubscriptionStatus(creds);
|
|
357
|
+
}
|
|
358
|
+
async function readOauthCredentials() {
|
|
359
|
+
if (platform() === "darwin") {
|
|
360
|
+
const fromKeychain = await readMacKeychain();
|
|
361
|
+
if (fromKeychain) return fromKeychain;
|
|
362
|
+
}
|
|
363
|
+
const candidates = [
|
|
364
|
+
join(homedir(), ".claude", ".credentials.json"),
|
|
365
|
+
join(homedir(), ".claude", "credentials.json")
|
|
366
|
+
];
|
|
367
|
+
for (const path of candidates) {
|
|
368
|
+
const parsed = await readJsonSilently(path);
|
|
369
|
+
if (parsed) {
|
|
370
|
+
return parsed.claudeAiOauth ?? parsed.oauth ?? parsed;
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
return null;
|
|
374
|
+
}
|
|
375
|
+
async function readMacKeychain() {
|
|
376
|
+
try {
|
|
377
|
+
const { stdout } = await execFileAsync(
|
|
378
|
+
"security",
|
|
379
|
+
["find-generic-password", "-s", "Claude Code-credentials", "-w"],
|
|
380
|
+
{ timeout: 3e3 }
|
|
381
|
+
);
|
|
382
|
+
const parsed = JSON.parse(stdout.trim());
|
|
383
|
+
return parsed.claudeAiOauth ?? parsed;
|
|
384
|
+
} catch {
|
|
385
|
+
return null;
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
async function readJsonSilently(path) {
|
|
389
|
+
try {
|
|
390
|
+
const raw = await readFile(path, "utf-8");
|
|
391
|
+
return JSON.parse(raw);
|
|
392
|
+
} catch {
|
|
393
|
+
return null;
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
function computeSubscriptionStatus(creds) {
|
|
397
|
+
const expiresAtMs = parseExpiresAt(creds.expiresAt);
|
|
398
|
+
if (expiresAtMs === null) {
|
|
399
|
+
return {
|
|
400
|
+
mode: "subscription",
|
|
401
|
+
status: "unknown",
|
|
402
|
+
expires_at: null
|
|
403
|
+
};
|
|
404
|
+
}
|
|
405
|
+
const msUntilExpiry = expiresAtMs - Date.now();
|
|
406
|
+
const status = msUntilExpiry <= 0 ? "expired" : msUntilExpiry <= EXPIRING_SOON_MS ? "expiring_soon" : "valid";
|
|
407
|
+
return {
|
|
408
|
+
mode: "subscription",
|
|
409
|
+
status,
|
|
410
|
+
expires_at: new Date(expiresAtMs).toISOString()
|
|
411
|
+
};
|
|
412
|
+
}
|
|
413
|
+
function parseExpiresAt(raw) {
|
|
414
|
+
if (typeof raw === "number" && Number.isFinite(raw)) {
|
|
415
|
+
return raw < 1e12 ? raw * 1e3 : raw;
|
|
416
|
+
}
|
|
417
|
+
if (typeof raw === "string") {
|
|
418
|
+
const parsed = Date.parse(raw);
|
|
419
|
+
return Number.isNaN(parsed) ? null : parsed;
|
|
420
|
+
}
|
|
421
|
+
return null;
|
|
422
|
+
}
|
|
423
|
+
|
|
342
424
|
// src/lib/realtime-chat.ts
|
|
343
425
|
import { createClient } from "@supabase/supabase-js";
|
|
344
426
|
var client = null;
|
|
@@ -622,8 +704,8 @@ function stopRealtimeChat() {
|
|
|
622
704
|
var GATEWAY_PORT_BASE = 18800;
|
|
623
705
|
var GATEWAY_PORT_STEP = 10;
|
|
624
706
|
var GATEWAY_PORT_MAX = 18899;
|
|
625
|
-
var AUGMENTED_DIR =
|
|
626
|
-
var GATEWAY_PORTS_FILE =
|
|
707
|
+
var AUGMENTED_DIR = join2(process.env["HOME"] ?? "/tmp", ".augmented");
|
|
708
|
+
var GATEWAY_PORTS_FILE = join2(AUGMENTED_DIR, "gateway-ports.json");
|
|
627
709
|
var config = null;
|
|
628
710
|
var running = false;
|
|
629
711
|
var pollTimer = null;
|
|
@@ -764,9 +846,9 @@ async function checkAndUpdateCli() {
|
|
|
764
846
|
const isDevMode = cliPath.includes("/src/") || cliPath.includes("tsx");
|
|
765
847
|
if (isDevMode) return;
|
|
766
848
|
if (!isHomebrew && !cliPath.includes("node_modules")) return;
|
|
767
|
-
const { homedir:
|
|
849
|
+
const { homedir: homedir3 } = await import("os");
|
|
768
850
|
const { readFileSync: readF, writeFileSync: writeF } = await import("fs");
|
|
769
|
-
const markerPath =
|
|
851
|
+
const markerPath = join2(homedir3(), ".augmented", ".last-update-check");
|
|
770
852
|
try {
|
|
771
853
|
const lastCheck = parseInt(readF(markerPath, "utf-8").trim(), 10);
|
|
772
854
|
if (Date.now() - lastCheck < UPDATE_CHECK_INTERVAL_MS) return;
|
|
@@ -863,7 +945,7 @@ function freePort(codeName) {
|
|
|
863
945
|
saveGatewayPorts(ports);
|
|
864
946
|
}
|
|
865
947
|
}
|
|
866
|
-
var STATE_FILE =
|
|
948
|
+
var STATE_FILE = join2(process.env["HOME"] ?? "/tmp", ".augmented", "manager-state.json");
|
|
867
949
|
function send(msg) {
|
|
868
950
|
if (msg.type === "state-update") {
|
|
869
951
|
try {
|
|
@@ -914,12 +996,12 @@ function parseSkillFrontmatter(content) {
|
|
|
914
996
|
}
|
|
915
997
|
async function refreshSkillsIndexInClaudeMd(configDir, codeName, log2) {
|
|
916
998
|
const { readdirSync: readdirSync2, readFileSync: rfs, existsSync: ex, writeFileSync: writeFileSync2 } = await import("fs");
|
|
917
|
-
const skillsDir =
|
|
918
|
-
const claudeMdPath =
|
|
999
|
+
const skillsDir = join2(configDir, codeName, "project", ".claude", "skills");
|
|
1000
|
+
const claudeMdPath = join2(configDir, codeName, "project", "CLAUDE.md");
|
|
919
1001
|
if (!ex(skillsDir) || !ex(claudeMdPath)) return;
|
|
920
1002
|
const entries = [];
|
|
921
1003
|
for (const dir of readdirSync2(skillsDir).sort()) {
|
|
922
|
-
const skillFile =
|
|
1004
|
+
const skillFile = join2(skillsDir, dir, "SKILL.md");
|
|
923
1005
|
if (!ex(skillFile)) continue;
|
|
924
1006
|
try {
|
|
925
1007
|
const { name, description } = parseSkillFrontmatter(rfs(skillFile, "utf-8"));
|
|
@@ -967,7 +1049,7 @@ ${SKILLS_INDEX_END}`;
|
|
|
967
1049
|
}
|
|
968
1050
|
async function migrateToProfiles() {
|
|
969
1051
|
const homeDir = process.env["HOME"] ?? "/tmp";
|
|
970
|
-
const sharedConfigPath =
|
|
1052
|
+
const sharedConfigPath = join2(homeDir, ".openclaw", "openclaw.json");
|
|
971
1053
|
let sharedConfig;
|
|
972
1054
|
try {
|
|
973
1055
|
sharedConfig = JSON.parse(readFileSync(sharedConfigPath, "utf-8"));
|
|
@@ -983,19 +1065,19 @@ async function migrateToProfiles() {
|
|
|
983
1065
|
const codeName = agentEntry["id"];
|
|
984
1066
|
if (!codeName) continue;
|
|
985
1067
|
if (codeName === "main") continue;
|
|
986
|
-
const profileDir =
|
|
987
|
-
if (existsSync(
|
|
1068
|
+
const profileDir = join2(homeDir, `.openclaw-${codeName}`);
|
|
1069
|
+
if (existsSync(join2(profileDir, "openclaw.json"))) continue;
|
|
988
1070
|
log(`Migrating agent '${codeName}' to per-agent profile`);
|
|
989
1071
|
if (adapter.seedProfileConfig) {
|
|
990
1072
|
adapter.seedProfileConfig(codeName);
|
|
991
1073
|
}
|
|
992
|
-
const sharedAuthDir =
|
|
993
|
-
const profileAuthDir =
|
|
994
|
-
const authFile =
|
|
1074
|
+
const sharedAuthDir = join2(homeDir, ".openclaw", "agents", codeName, "agent");
|
|
1075
|
+
const profileAuthDir = join2(profileDir, "agents", codeName, "agent");
|
|
1076
|
+
const authFile = join2(sharedAuthDir, "auth-profiles.json");
|
|
995
1077
|
if (existsSync(authFile)) {
|
|
996
1078
|
mkdirSync(profileAuthDir, { recursive: true });
|
|
997
1079
|
const authContent = readFileSync(authFile, "utf-8");
|
|
998
|
-
writeFileSync(
|
|
1080
|
+
writeFileSync(join2(profileAuthDir, "auth-profiles.json"), authContent);
|
|
999
1081
|
}
|
|
1000
1082
|
allocatePort(codeName);
|
|
1001
1083
|
migrated++;
|
|
@@ -1007,7 +1089,7 @@ async function migrateToProfiles() {
|
|
|
1007
1089
|
function resolveModelChain(refreshData) {
|
|
1008
1090
|
const agent = refreshData.agent;
|
|
1009
1091
|
const modelDefaults = refreshData.model_defaults;
|
|
1010
|
-
const
|
|
1092
|
+
const platform2 = modelDefaults?.platform ?? {};
|
|
1011
1093
|
const org = modelDefaults?.org ?? {};
|
|
1012
1094
|
function resolve(tier) {
|
|
1013
1095
|
const agentField = `${tier}_model`;
|
|
@@ -1016,7 +1098,7 @@ function resolveModelChain(refreshData) {
|
|
|
1016
1098
|
if (agentVal) return agentVal;
|
|
1017
1099
|
const orgVal = org?.[platformField];
|
|
1018
1100
|
if (orgVal) return orgVal;
|
|
1019
|
-
const platformVal =
|
|
1101
|
+
const platformVal = platform2?.[platformField];
|
|
1020
1102
|
if (platformVal) return platformVal;
|
|
1021
1103
|
return void 0;
|
|
1022
1104
|
}
|
|
@@ -1033,7 +1115,7 @@ function readGatewayToken(codeName) {
|
|
|
1033
1115
|
}
|
|
1034
1116
|
const homeDir = process.env["HOME"] ?? "/tmp";
|
|
1035
1117
|
try {
|
|
1036
|
-
const cfg = JSON.parse(readFileSync(
|
|
1118
|
+
const cfg = JSON.parse(readFileSync(join2(homeDir, `.openclaw-${codeName}`, "openclaw.json"), "utf-8"));
|
|
1037
1119
|
return cfg?.gateway?.auth?.token;
|
|
1038
1120
|
} catch {
|
|
1039
1121
|
return void 0;
|
|
@@ -1042,7 +1124,7 @@ function readGatewayToken(codeName) {
|
|
|
1042
1124
|
var GATEWAY_HUNG_TIMEOUT_MS = 5 * 6e4;
|
|
1043
1125
|
function isGatewayHung(codeName) {
|
|
1044
1126
|
const homeDir = process.env["HOME"] ?? "/tmp";
|
|
1045
|
-
const jobsPath =
|
|
1127
|
+
const jobsPath = join2(homeDir, `.openclaw-${codeName}`, "cron", "jobs.json");
|
|
1046
1128
|
if (!existsSync(jobsPath)) return false;
|
|
1047
1129
|
try {
|
|
1048
1130
|
const data = JSON.parse(readFileSync(jobsPath, "utf-8"));
|
|
@@ -1078,13 +1160,13 @@ async function ensureGatewayRunning(codeName, adapter) {
|
|
|
1078
1160
|
}
|
|
1079
1161
|
await new Promise((r) => setTimeout(r, 2e3));
|
|
1080
1162
|
const homeDir = process.env["HOME"] ?? "/tmp";
|
|
1081
|
-
const cronJobsPath =
|
|
1163
|
+
const cronJobsPath = join2(homeDir, `.openclaw-${codeName}`, "cron", "jobs.json");
|
|
1082
1164
|
clearStaleCronRunState(cronJobsPath);
|
|
1083
1165
|
} else {
|
|
1084
1166
|
if (status.port) {
|
|
1085
1167
|
try {
|
|
1086
1168
|
const homeDir = process.env["HOME"] ?? "/tmp";
|
|
1087
|
-
const configPath =
|
|
1169
|
+
const configPath = join2(homeDir, `.openclaw-${codeName}`, "openclaw.json");
|
|
1088
1170
|
if (existsSync(configPath)) {
|
|
1089
1171
|
const cfg = JSON.parse(readFileSync(configPath, "utf-8"));
|
|
1090
1172
|
if (cfg.gateway?.port !== status.port) {
|
|
@@ -1110,7 +1192,7 @@ async function ensureGatewayRunning(codeName, adapter) {
|
|
|
1110
1192
|
gatewaysStartedThisCycle.add(codeName);
|
|
1111
1193
|
try {
|
|
1112
1194
|
const homeDir = process.env["HOME"] ?? "/tmp";
|
|
1113
|
-
const configPath =
|
|
1195
|
+
const configPath = join2(homeDir, `.openclaw-${codeName}`, "openclaw.json");
|
|
1114
1196
|
if (existsSync(configPath)) {
|
|
1115
1197
|
const cfg = JSON.parse(readFileSync(configPath, "utf-8"));
|
|
1116
1198
|
if (!cfg.gateway) cfg.gateway = {};
|
|
@@ -1244,6 +1326,14 @@ async function pollCycle() {
|
|
|
1244
1326
|
osUsername = userInfo().username;
|
|
1245
1327
|
} catch {
|
|
1246
1328
|
}
|
|
1329
|
+
let claudeAuth = null;
|
|
1330
|
+
try {
|
|
1331
|
+
claudeAuth = await detectClaudeAuth();
|
|
1332
|
+
} catch (err) {
|
|
1333
|
+
const errText = err instanceof Error ? err.message : String(err);
|
|
1334
|
+
const errId = createHash("sha256").update(errText).digest("hex").slice(0, 12);
|
|
1335
|
+
log(`Claude auth detection failed (error_id=${errId})`);
|
|
1336
|
+
}
|
|
1247
1337
|
await api.post("/host/heartbeat", {
|
|
1248
1338
|
host_id: hostId,
|
|
1249
1339
|
framework_version: cachedFrameworkVersion ?? void 0,
|
|
@@ -1251,7 +1341,8 @@ async function pollCycle() {
|
|
|
1251
1341
|
agent_runtime_authenticated: agentRuntimeAuthenticated,
|
|
1252
1342
|
agent_diagnostics: agentDiagnostics,
|
|
1253
1343
|
hostname: tailscaleHostname,
|
|
1254
|
-
os_username: osUsername
|
|
1344
|
+
os_username: osUsername,
|
|
1345
|
+
claude_auth: claudeAuth ?? void 0
|
|
1255
1346
|
});
|
|
1256
1347
|
} catch (err) {
|
|
1257
1348
|
log(`Heartbeat failed: ${err.message}`);
|
|
@@ -1310,7 +1401,7 @@ async function pollCycle() {
|
|
|
1310
1401
|
const adapter = resolveAgentFramework(prev.codeName);
|
|
1311
1402
|
await stopGatewayIfRunning(prev.codeName, adapter);
|
|
1312
1403
|
freePort(prev.codeName);
|
|
1313
|
-
const agentDir =
|
|
1404
|
+
const agentDir = join2(config.configDir, prev.codeName, "provision");
|
|
1314
1405
|
await cleanupAgentFiles(prev.codeName, agentDir);
|
|
1315
1406
|
clearAgentCaches(prev.agentId, prev.codeName);
|
|
1316
1407
|
}
|
|
@@ -1378,7 +1469,7 @@ async function processAgent(agent, agentStates) {
|
|
|
1378
1469
|
agentFrameworkCache.set(agent.code_name, agent.framework);
|
|
1379
1470
|
}
|
|
1380
1471
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
1381
|
-
const agentDir =
|
|
1472
|
+
const agentDir = join2(config.configDir, agent.code_name, "provision");
|
|
1382
1473
|
const adapter = resolveAgentFramework(agent.code_name);
|
|
1383
1474
|
if (agent.status === "draft" || agent.status === "paused") {
|
|
1384
1475
|
log(`Agent '${agent.code_name}' is ${agent.status}, skipping provisioning`);
|
|
@@ -1531,12 +1622,12 @@ async function processAgent(agent, agentStates) {
|
|
|
1531
1622
|
const changedFiles = [];
|
|
1532
1623
|
mkdirSync(agentDir, { recursive: true });
|
|
1533
1624
|
for (const artifact of artifacts) {
|
|
1534
|
-
const filePath =
|
|
1625
|
+
const filePath = join2(agentDir, artifact.relativePath);
|
|
1535
1626
|
const newHash = sha256(artifact.content);
|
|
1536
1627
|
let existingHash;
|
|
1537
1628
|
if (artifact.relativePath === "CLAUDE.md") {
|
|
1538
1629
|
try {
|
|
1539
|
-
const projectClaudeMd =
|
|
1630
|
+
const projectClaudeMd = join2(config.configDir, agent.code_name, "project", "CLAUDE.md");
|
|
1540
1631
|
const existing = readFileSync(projectClaudeMd, "utf-8");
|
|
1541
1632
|
const stripped = existing.replace(new RegExp(`${SKILLS_INDEX_START}[\\s\\S]*?${SKILLS_INDEX_END}`), "").trimEnd();
|
|
1542
1633
|
existingHash = sha256(stripped);
|
|
@@ -1551,22 +1642,22 @@ async function processAgent(agent, agentStates) {
|
|
|
1551
1642
|
}
|
|
1552
1643
|
}
|
|
1553
1644
|
if (changedFiles.length > 0) {
|
|
1554
|
-
const isFirst = !existsSync(
|
|
1645
|
+
const isFirst = !existsSync(join2(agentDir, "CHARTER.md"));
|
|
1555
1646
|
const verb = isFirst ? "Provisioning" : "Updating";
|
|
1556
1647
|
const fileNames = changedFiles.map((f) => f.relativePath).join(", ");
|
|
1557
1648
|
log(`${verb} '${agent.code_name}': ${fileNames}`);
|
|
1558
1649
|
for (const file of changedFiles) {
|
|
1559
|
-
const filePath =
|
|
1650
|
+
const filePath = join2(agentDir, file.relativePath);
|
|
1560
1651
|
mkdirSync(dirname(filePath), { recursive: true });
|
|
1561
1652
|
writeFileSync(filePath, file.content);
|
|
1562
1653
|
}
|
|
1563
1654
|
try {
|
|
1564
|
-
const provSkillsDir =
|
|
1655
|
+
const provSkillsDir = join2(agentDir, ".claude", "skills");
|
|
1565
1656
|
if (existsSync(provSkillsDir)) {
|
|
1566
1657
|
for (const folder of readdirSync(provSkillsDir)) {
|
|
1567
1658
|
if (folder.startsWith("knowledge-")) {
|
|
1568
1659
|
try {
|
|
1569
|
-
rmSync(
|
|
1660
|
+
rmSync(join2(provSkillsDir, folder), { recursive: true });
|
|
1570
1661
|
} catch {
|
|
1571
1662
|
}
|
|
1572
1663
|
}
|
|
@@ -1579,7 +1670,7 @@ async function processAgent(agent, agentStates) {
|
|
|
1579
1670
|
const trackedFiles = frameworkAdapter.driftTrackedFiles();
|
|
1580
1671
|
const hashes = /* @__PURE__ */ new Map();
|
|
1581
1672
|
for (const file of trackedFiles) {
|
|
1582
|
-
const h = hashFile(
|
|
1673
|
+
const h = hashFile(join2(agentDir, file));
|
|
1583
1674
|
if (h) hashes.set(file, h);
|
|
1584
1675
|
}
|
|
1585
1676
|
writtenHashes.set(agent.agent_id, hashes);
|
|
@@ -1626,7 +1717,7 @@ async function processAgent(agent, agentStates) {
|
|
|
1626
1717
|
if (written && existsSync(agentDir)) {
|
|
1627
1718
|
const driftedFiles = [];
|
|
1628
1719
|
for (const [file, expectedHash] of written) {
|
|
1629
|
-
const localHash = hashFile(
|
|
1720
|
+
const localHash = hashFile(join2(agentDir, file));
|
|
1630
1721
|
if (localHash && localHash !== expectedHash) {
|
|
1631
1722
|
driftedFiles.push(file);
|
|
1632
1723
|
}
|
|
@@ -1637,7 +1728,7 @@ async function processAgent(agent, agentStates) {
|
|
|
1637
1728
|
try {
|
|
1638
1729
|
const localHashes = {};
|
|
1639
1730
|
for (const file of driftedFiles) {
|
|
1640
|
-
localHashes[file] = hashFile(
|
|
1731
|
+
localHashes[file] = hashFile(join2(agentDir, file));
|
|
1641
1732
|
}
|
|
1642
1733
|
await api.post("/host/drift", {
|
|
1643
1734
|
agent_id: agent.agent_id,
|
|
@@ -1707,7 +1798,7 @@ async function processAgent(agent, agentStates) {
|
|
|
1707
1798
|
const entry = refreshData.channel_configs[channelId];
|
|
1708
1799
|
if (!entry || entry.status !== "active" && entry.status !== "pending") continue;
|
|
1709
1800
|
try {
|
|
1710
|
-
const installedPath =
|
|
1801
|
+
const installedPath = join2(homedir2(), ".claude", "plugins", "installed_plugins.json");
|
|
1711
1802
|
if (existsSync(installedPath)) {
|
|
1712
1803
|
const installed = JSON.parse(readFileSync(installedPath, "utf-8"));
|
|
1713
1804
|
const pluginKeys = Object.keys(installed.plugins ?? {});
|
|
@@ -1741,16 +1832,16 @@ async function processAgent(agent, agentStates) {
|
|
|
1741
1832
|
const agentSessionMode = refreshData.agent.session_mode;
|
|
1742
1833
|
if (agentSessionMode === "persistent" && (agentFrameworkCache.get(agent.code_name) ?? "openclaw") === "claude-code") {
|
|
1743
1834
|
try {
|
|
1744
|
-
const projectDir =
|
|
1835
|
+
const projectDir = join2(homedir2(), ".augmented", agent.code_name, "project");
|
|
1745
1836
|
mkdirSync(projectDir, { recursive: true });
|
|
1746
|
-
const channelsPath =
|
|
1837
|
+
const channelsPath = join2(projectDir, ".mcp-channels.json");
|
|
1747
1838
|
let channelsMcp = { mcpServers: {} };
|
|
1748
1839
|
try {
|
|
1749
1840
|
channelsMcp = JSON.parse(readFileSync(channelsPath, "utf-8"));
|
|
1750
1841
|
if (!channelsMcp.mcpServers) channelsMcp.mcpServers = {};
|
|
1751
1842
|
} catch {
|
|
1752
1843
|
}
|
|
1753
|
-
const localDirectChatChannel =
|
|
1844
|
+
const localDirectChatChannel = join2(homedir2(), ".augmented", "_mcp", "direct-chat-channel.js");
|
|
1754
1845
|
if (existsSync(localDirectChatChannel) && !channelsMcp.mcpServers["direct-chat"]) {
|
|
1755
1846
|
channelsMcp.mcpServers["direct-chat"] = {
|
|
1756
1847
|
command: "node",
|
|
@@ -1857,9 +1948,9 @@ async function processAgent(agent, agentStates) {
|
|
|
1857
1948
|
if (frameworkAdapter.removeMcpServer) {
|
|
1858
1949
|
try {
|
|
1859
1950
|
const { readFileSync: readFileSync2 } = await import("fs");
|
|
1860
|
-
const { join:
|
|
1861
|
-
const { homedir:
|
|
1862
|
-
const mcpPath =
|
|
1951
|
+
const { join: join3 } = await import("path");
|
|
1952
|
+
const { homedir: homedir3 } = await import("os");
|
|
1953
|
+
const mcpPath = join3(homedir3(), ".augmented", "agents", agent.code_name, "provision", ".mcp.json");
|
|
1863
1954
|
const mcpConfig = JSON.parse(readFileSync2(mcpPath, "utf-8"));
|
|
1864
1955
|
if (mcpConfig.mcpServers) {
|
|
1865
1956
|
const managedPrefixes = [
|
|
@@ -1952,7 +2043,7 @@ async function processAgent(agent, agentStates) {
|
|
|
1952
2043
|
if (agent.status === "active") {
|
|
1953
2044
|
if (frameworkAdapter.installPlugin) {
|
|
1954
2045
|
try {
|
|
1955
|
-
const pluginPath =
|
|
2046
|
+
const pluginPath = join2(process.cwd(), "packages", "openclaw-plugin-augmented", "src", "index.ts");
|
|
1956
2047
|
if (existsSync(pluginPath)) {
|
|
1957
2048
|
frameworkAdapter.installPlugin(agent.code_name, "augmented", pluginPath, {
|
|
1958
2049
|
agtHost: requireHost(),
|
|
@@ -2007,15 +2098,15 @@ async function processAgent(agent, agentStates) {
|
|
|
2007
2098
|
}
|
|
2008
2099
|
}
|
|
2009
2100
|
try {
|
|
2010
|
-
const agentSkillsDir =
|
|
2101
|
+
const agentSkillsDir = join2(config.configDir, agent.code_name, "project", ".claude", "skills");
|
|
2011
2102
|
if (existsSync(agentSkillsDir)) {
|
|
2012
2103
|
const { readdirSync: readdirSync2, rmSync: rmSync2 } = await import("fs");
|
|
2013
2104
|
for (const entry of readdirSync2(agentSkillsDir)) {
|
|
2014
2105
|
if (entry.startsWith("plugin-") && !currentPluginSkillIds.has(entry)) {
|
|
2015
|
-
const orphanPath =
|
|
2106
|
+
const orphanPath = join2(agentSkillsDir, entry);
|
|
2016
2107
|
rmSync2(orphanPath, { recursive: true, force: true });
|
|
2017
2108
|
log(`Removed orphaned plugin skill '${entry}' for '${agent.code_name}'`);
|
|
2018
|
-
const provisionSkillPath =
|
|
2109
|
+
const provisionSkillPath = join2(config.configDir, agent.code_name, "skills", entry);
|
|
2019
2110
|
if (existsSync(provisionSkillPath)) {
|
|
2020
2111
|
rmSync2(provisionSkillPath, { recursive: true, force: true });
|
|
2021
2112
|
}
|
|
@@ -2169,7 +2260,7 @@ async function processAgent(agent, agentStates) {
|
|
|
2169
2260
|
lastWorkTriggerAt.set(agent.code_name, triggerTs);
|
|
2170
2261
|
if (agentFw === "openclaw" && gatewayRunning && gatewayPort) {
|
|
2171
2262
|
const homeDir = process.env["HOME"] ?? "/tmp";
|
|
2172
|
-
const jobsPath =
|
|
2263
|
+
const jobsPath = join2(homeDir, `.openclaw-${agent.code_name}`, "cron", "jobs.json");
|
|
2173
2264
|
if (existsSync(jobsPath)) {
|
|
2174
2265
|
try {
|
|
2175
2266
|
const jobsData = JSON.parse(readFileSync(jobsPath, "utf-8"));
|
|
@@ -2324,16 +2415,16 @@ function cleanupStaleSessions(codeName) {
|
|
|
2324
2415
|
lastCleanupAt.set(codeName, Date.now());
|
|
2325
2416
|
const homeDir = process.env["HOME"] ?? "/tmp";
|
|
2326
2417
|
for (const agentDir of ["main", codeName]) {
|
|
2327
|
-
const sessionsDir =
|
|
2418
|
+
const sessionsDir = join2(homeDir, `.openclaw-${codeName}`, "agents", agentDir, "sessions");
|
|
2328
2419
|
cleanupCronSessions(sessionsDir, CRON_SESSION_KEEP_COUNT);
|
|
2329
2420
|
}
|
|
2330
|
-
const cronRunsDir =
|
|
2421
|
+
const cronRunsDir = join2(homeDir, `.openclaw-${codeName}`, "cron", "runs");
|
|
2331
2422
|
cleanupOldFiles(cronRunsDir, CRON_RUN_RETENTION_DAYS, ".jsonl");
|
|
2332
|
-
const cronJobsPath =
|
|
2423
|
+
const cronJobsPath = join2(homeDir, `.openclaw-${codeName}`, "cron", "jobs.json");
|
|
2333
2424
|
clearStaleCronRunState(cronJobsPath);
|
|
2334
2425
|
}
|
|
2335
2426
|
function cleanupCronSessions(sessionsDir, keepCount) {
|
|
2336
|
-
const indexPath =
|
|
2427
|
+
const indexPath = join2(sessionsDir, "sessions.json");
|
|
2337
2428
|
if (!existsSync(indexPath)) return;
|
|
2338
2429
|
try {
|
|
2339
2430
|
const raw = readFileSync(indexPath, "utf-8");
|
|
@@ -2349,7 +2440,7 @@ function cleanupCronSessions(sessionsDir, keepCount) {
|
|
|
2349
2440
|
for (const entry of toDelete) {
|
|
2350
2441
|
delete index[entry.key];
|
|
2351
2442
|
if (entry.sessionId) {
|
|
2352
|
-
const sessionFile =
|
|
2443
|
+
const sessionFile = join2(sessionsDir, `${entry.sessionId}.jsonl`);
|
|
2353
2444
|
try {
|
|
2354
2445
|
if (existsSync(sessionFile)) {
|
|
2355
2446
|
unlinkSync(sessionFile);
|
|
@@ -2371,7 +2462,7 @@ function cleanupCronSessions(sessionsDir, keepCount) {
|
|
|
2371
2462
|
delete index[parentKey];
|
|
2372
2463
|
if (parentSessionId) {
|
|
2373
2464
|
try {
|
|
2374
|
-
const f =
|
|
2465
|
+
const f = join2(sessionsDir, `${parentSessionId}.jsonl`);
|
|
2375
2466
|
if (existsSync(f)) {
|
|
2376
2467
|
unlinkSync(f);
|
|
2377
2468
|
deletedFiles++;
|
|
@@ -2429,7 +2520,7 @@ function cleanupOldFiles(dir, maxAgeDays, ext) {
|
|
|
2429
2520
|
try {
|
|
2430
2521
|
for (const f of readdirSync(dir)) {
|
|
2431
2522
|
if (!f.endsWith(ext)) continue;
|
|
2432
|
-
const fullPath =
|
|
2523
|
+
const fullPath = join2(dir, f);
|
|
2433
2524
|
try {
|
|
2434
2525
|
const st = statSync(fullPath);
|
|
2435
2526
|
if (st.mtimeMs < cutoff) {
|
|
@@ -2489,6 +2580,12 @@ async function syncAndCheckClaudeScheduler(agent, tasks, boardItems, refreshData
|
|
|
2489
2580
|
for (const task of ready) {
|
|
2490
2581
|
if (inFlightClaudeTasks.has(task.taskId)) continue;
|
|
2491
2582
|
if ((claudeTaskConcurrency.get(codeName) ?? 0) >= MAX_CLAUDE_CONCURRENCY) break;
|
|
2583
|
+
if (KANBAN_WORK_TEMPLATES.has(task.templateId) && !hasActionableItems(boardItems)) {
|
|
2584
|
+
log(`[claude-scheduler] Skipping '${task.name}' for '${codeName}' \u2014 board is empty`);
|
|
2585
|
+
const updated = markTaskFired(codeName, task.taskId, "ok");
|
|
2586
|
+
claudeSchedulerStates.set(codeName, updated);
|
|
2587
|
+
continue;
|
|
2588
|
+
}
|
|
2492
2589
|
let prompt = task.prompt;
|
|
2493
2590
|
if (BOARD_INJECT_TEMPLATES.has(task.templateId) && boardItems.length > 0) {
|
|
2494
2591
|
const template = PLAN_TEMPLATES.has(task.templateId) ? "morning-plan" : "follow-up";
|
|
@@ -2520,12 +2617,12 @@ async function syncAndCheckClaudeScheduler(agent, tasks, boardItems, refreshData
|
|
|
2520
2617
|
}
|
|
2521
2618
|
async function executeAndProcessClaudeTask(codeName, agentId, task, prompt) {
|
|
2522
2619
|
const projectDir = getProjectDir(codeName);
|
|
2523
|
-
const mcpConfigPath =
|
|
2620
|
+
const mcpConfigPath = join2(projectDir, ".mcp.json");
|
|
2524
2621
|
sanitizeMcpJson(mcpConfigPath, requireHost());
|
|
2525
2622
|
try {
|
|
2526
|
-
const claudeMdPath =
|
|
2623
|
+
const claudeMdPath = join2(projectDir, "CLAUDE.md");
|
|
2527
2624
|
const serverNames = [];
|
|
2528
|
-
const channelsConfigPath =
|
|
2625
|
+
const channelsConfigPath = join2(projectDir, ".mcp-channels.json");
|
|
2529
2626
|
for (const p of [mcpConfigPath, channelsConfigPath]) {
|
|
2530
2627
|
if (existsSync(p)) {
|
|
2531
2628
|
try {
|
|
@@ -2554,7 +2651,7 @@ async function executeAndProcessClaudeTask(codeName, agentId, task, prompt) {
|
|
|
2554
2651
|
claudeArgs.push("--system-prompt-file", claudeMdPath);
|
|
2555
2652
|
}
|
|
2556
2653
|
const childEnv = { ...process.env };
|
|
2557
|
-
const envIntPath =
|
|
2654
|
+
const envIntPath = join2(projectDir, ".env.integrations");
|
|
2558
2655
|
if (existsSync(envIntPath)) {
|
|
2559
2656
|
try {
|
|
2560
2657
|
for (const line of readFileSync(envIntPath, "utf-8").split("\n")) {
|
|
@@ -2675,8 +2772,8 @@ var persistentSessionAgents = /* @__PURE__ */ new Set();
|
|
|
2675
2772
|
async function ensurePersistentSession(agent, tasks, boardItems, refreshData) {
|
|
2676
2773
|
const codeName = agent.code_name;
|
|
2677
2774
|
const projectDir = getProjectDir2(codeName);
|
|
2678
|
-
const mcpConfigPath =
|
|
2679
|
-
const claudeMdPath =
|
|
2775
|
+
const mcpConfigPath = join2(projectDir, ".mcp.json");
|
|
2776
|
+
const claudeMdPath = join2(projectDir, "CLAUDE.md");
|
|
2680
2777
|
const channelConfigs = refreshData.channel_configs;
|
|
2681
2778
|
const channels = [];
|
|
2682
2779
|
const devChannels = [];
|
|
@@ -2763,6 +2860,12 @@ async function ensurePersistentSession(agent, tasks, boardItems, refreshData) {
|
|
|
2763
2860
|
log(`[persistent-session] ${ready.length} ready task(s) for '${codeName}': ${ready.map((t) => `${t.name}(next=${t.nextFireAt ? new Date(t.nextFireAt).toISOString() : "null"})`).join(", ")}`);
|
|
2764
2861
|
}
|
|
2765
2862
|
for (const task of ready) {
|
|
2863
|
+
if (KANBAN_WORK_TEMPLATES.has(task.templateId) && !hasActionableItems(boardItems)) {
|
|
2864
|
+
log(`[persistent-session] Skipping '${task.name}' for '${codeName}' \u2014 board is empty`);
|
|
2865
|
+
const updated = markTaskFired(codeName, task.taskId, "ok");
|
|
2866
|
+
claudeSchedulerStates.set(codeName, updated);
|
|
2867
|
+
continue;
|
|
2868
|
+
}
|
|
2766
2869
|
let prompt = task.prompt;
|
|
2767
2870
|
if (BOARD_INJECT_TEMPLATES.has(task.templateId) && boardItems.length > 0) {
|
|
2768
2871
|
const template = PLAN_TEMPLATES.has(task.templateId) ? "morning-plan" : "follow-up";
|
|
@@ -3062,8 +3165,8 @@ async function processDirectChatMessage(agent, msg) {
|
|
|
3062
3165
|
if (fw === "claude-code") {
|
|
3063
3166
|
const { getProjectDir: ccProjectDir } = await import("../claude-scheduler-7PVWQHWU.js");
|
|
3064
3167
|
const projDir = ccProjectDir(agent.codeName);
|
|
3065
|
-
const mcpConfigPath =
|
|
3066
|
-
const channelsConfigPath =
|
|
3168
|
+
const mcpConfigPath = join2(projDir, ".mcp.json");
|
|
3169
|
+
const channelsConfigPath = join2(projDir, ".mcp-channels.json");
|
|
3067
3170
|
const serverNames = [];
|
|
3068
3171
|
for (const p of [mcpConfigPath, channelsConfigPath]) {
|
|
3069
3172
|
if (existsSync(p)) {
|
|
@@ -3088,11 +3191,11 @@ async function processDirectChatMessage(agent, msg) {
|
|
|
3088
3191
|
allowedTools
|
|
3089
3192
|
];
|
|
3090
3193
|
if (existsSync(channelsConfigPath)) chatArgs.push("--mcp-config", channelsConfigPath);
|
|
3091
|
-
const chatClaudeMd =
|
|
3194
|
+
const chatClaudeMd = join2(projDir, "CLAUDE.md");
|
|
3092
3195
|
if (existsSync(chatClaudeMd)) {
|
|
3093
3196
|
chatArgs.push("--system-prompt-file", chatClaudeMd);
|
|
3094
3197
|
}
|
|
3095
|
-
const envIntPath =
|
|
3198
|
+
const envIntPath = join2(projDir, ".env.integrations");
|
|
3096
3199
|
const childEnv = { ...process.env };
|
|
3097
3200
|
if (existsSync(envIntPath)) {
|
|
3098
3201
|
try {
|
|
@@ -3154,6 +3257,10 @@ var TASK_UPDATE_TEMPLATES = /* @__PURE__ */ new Set(["hourly-status", "task-upda
|
|
|
3154
3257
|
var PLAN_TEMPLATES = /* @__PURE__ */ new Set(["morning-plan"]);
|
|
3155
3258
|
var KANBAN_WORK_TEMPLATES = /* @__PURE__ */ new Set(["kanban-work"]);
|
|
3156
3259
|
var BOARD_INJECT_TEMPLATES = /* @__PURE__ */ new Set(["morning-plan", "task-update", "hourly-status", "end-of-day-summary", "kanban-work"]);
|
|
3260
|
+
var ACTIONABLE_STATUSES = /* @__PURE__ */ new Set(["backlog", "today", "in_progress"]);
|
|
3261
|
+
function hasActionableItems(items) {
|
|
3262
|
+
return items.some((item) => ACTIONABLE_STATUSES.has(item.status));
|
|
3263
|
+
}
|
|
3157
3264
|
var lastHarvestAt = /* @__PURE__ */ new Map();
|
|
3158
3265
|
var HARVEST_INTERVAL_MS = 3 * 60 * 1e3;
|
|
3159
3266
|
var kanbanBoardCache = /* @__PURE__ */ new Map();
|
|
@@ -3369,8 +3476,8 @@ function getBuiltInSkillContent(skillId) {
|
|
|
3369
3476
|
if (builtInSkillCache.has(skillId)) return builtInSkillCache.get(skillId);
|
|
3370
3477
|
try {
|
|
3371
3478
|
const candidates = [
|
|
3372
|
-
|
|
3373
|
-
|
|
3479
|
+
join2(process.cwd(), "skills", skillId, "SKILL.md"),
|
|
3480
|
+
join2(new URL(".", import.meta.url).pathname, "..", "..", "..", "..", "skills", skillId, "SKILL.md")
|
|
3374
3481
|
];
|
|
3375
3482
|
for (const candidate of candidates) {
|
|
3376
3483
|
if (existsSync(candidate)) {
|
|
@@ -3864,8 +3971,8 @@ function parseMemoryFile(raw, fallbackName) {
|
|
|
3864
3971
|
};
|
|
3865
3972
|
}
|
|
3866
3973
|
async function syncMemories(agent, configDir, log2) {
|
|
3867
|
-
const projectDir =
|
|
3868
|
-
const memoryDir =
|
|
3974
|
+
const projectDir = join2(configDir, agent.code_name, "project");
|
|
3975
|
+
const memoryDir = join2(projectDir, "memory");
|
|
3869
3976
|
if (existsSync(memoryDir)) {
|
|
3870
3977
|
const prevHashes = memoryFileHashes.get(agent.agent_id) ?? /* @__PURE__ */ new Map();
|
|
3871
3978
|
const currentHashes = /* @__PURE__ */ new Map();
|
|
@@ -3873,7 +3980,7 @@ async function syncMemories(agent, configDir, log2) {
|
|
|
3873
3980
|
for (const file of readdirSync(memoryDir)) {
|
|
3874
3981
|
if (!file.endsWith(".md")) continue;
|
|
3875
3982
|
try {
|
|
3876
|
-
const raw = readFileSync(
|
|
3983
|
+
const raw = readFileSync(join2(memoryDir, file), "utf-8");
|
|
3877
3984
|
const fileHash = createHash("sha256").update(raw).digest("hex").slice(0, 16);
|
|
3878
3985
|
currentHashes.set(file, fileHash);
|
|
3879
3986
|
if (prevHashes.get(file) === fileHash) continue;
|
|
@@ -3897,8 +4004,8 @@ async function syncMemories(agent, configDir, log2) {
|
|
|
3897
4004
|
log2(`Synced ${changedMemories.length} changed memories to DB for '${agent.code_name}'`);
|
|
3898
4005
|
} catch (err) {
|
|
3899
4006
|
for (const mem of changedMemories) {
|
|
3900
|
-
for (const [file
|
|
3901
|
-
const parsed = parseMemoryFile(readFileSync(
|
|
4007
|
+
for (const [file] of currentHashes) {
|
|
4008
|
+
const parsed = parseMemoryFile(readFileSync(join2(memoryDir, file), "utf-8"), file.replace(/\.md$/, ""));
|
|
3902
4009
|
if (parsed?.name === mem.name) currentHashes.delete(file);
|
|
3903
4010
|
}
|
|
3904
4011
|
}
|
|
@@ -3910,12 +4017,14 @@ async function syncMemories(agent, configDir, log2) {
|
|
|
3910
4017
|
const localListHash = createHash("sha256").update(localFiles.join(",")).digest("hex").slice(0, 16);
|
|
3911
4018
|
const prevLocalHash = lastLocalFileHash.get(agent.agent_id);
|
|
3912
4019
|
const prevDownload = lastDownloadHash.get(agent.agent_id);
|
|
3913
|
-
if (prevDownload && prevLocalHash === localListHash) return;
|
|
3914
4020
|
try {
|
|
3915
4021
|
const dbMemories = await api.post("/host/memories", {
|
|
3916
4022
|
agent_id: agent.agent_id
|
|
3917
4023
|
});
|
|
3918
4024
|
const responseHash = createHash("sha256").update(JSON.stringify(dbMemories.memories ?? [])).digest("hex").slice(0, 16);
|
|
4025
|
+
if (prevDownload && prevLocalHash === localListHash && lastDownloadHash.get(agent.agent_id) === responseHash) {
|
|
4026
|
+
return;
|
|
4027
|
+
}
|
|
3919
4028
|
lastDownloadHash.set(agent.agent_id, responseHash);
|
|
3920
4029
|
lastLocalFileHash.set(agent.agent_id, localListHash);
|
|
3921
4030
|
if (dbMemories.memories?.length) {
|
|
@@ -3934,7 +4043,7 @@ description: ${JSON.stringify(mem.content.slice(0, 200))}
|
|
|
3934
4043
|
|
|
3935
4044
|
${mem.content}
|
|
3936
4045
|
`;
|
|
3937
|
-
writeFileSync(
|
|
4046
|
+
writeFileSync(join2(memoryDir, `${slug}.md`), fileContent);
|
|
3938
4047
|
written++;
|
|
3939
4048
|
}
|
|
3940
4049
|
if (written > 0) {
|
|
@@ -4105,14 +4214,14 @@ function startManager(opts) {
|
|
|
4105
4214
|
startPolling();
|
|
4106
4215
|
}
|
|
4107
4216
|
function deployMcpAssets() {
|
|
4108
|
-
const targetDir =
|
|
4217
|
+
const targetDir = join2(homedir2(), ".augmented", "_mcp");
|
|
4109
4218
|
mkdirSync(targetDir, { recursive: true });
|
|
4110
4219
|
const moduleDir = dirname(fileURLToPath(import.meta.url));
|
|
4111
4220
|
let mcpSourceDir = "";
|
|
4112
4221
|
let dir = moduleDir;
|
|
4113
4222
|
for (let i = 0; i < 6; i++) {
|
|
4114
|
-
const candidate =
|
|
4115
|
-
if (existsSync(
|
|
4223
|
+
const candidate = join2(dir, "mcp");
|
|
4224
|
+
if (existsSync(join2(candidate, "index.js"))) {
|
|
4116
4225
|
mcpSourceDir = candidate;
|
|
4117
4226
|
break;
|
|
4118
4227
|
}
|
|
@@ -4125,8 +4234,8 @@ function deployMcpAssets() {
|
|
|
4125
4234
|
return;
|
|
4126
4235
|
}
|
|
4127
4236
|
for (const file of ["index.js", "slack-channel.js", "direct-chat-channel.js"]) {
|
|
4128
|
-
const src =
|
|
4129
|
-
const dst =
|
|
4237
|
+
const src = join2(mcpSourceDir, file);
|
|
4238
|
+
const dst = join2(targetDir, file);
|
|
4130
4239
|
if (!existsSync(src)) continue;
|
|
4131
4240
|
try {
|
|
4132
4241
|
copyFileSync(src, dst);
|
|
@@ -4135,14 +4244,14 @@ function deployMcpAssets() {
|
|
|
4135
4244
|
}
|
|
4136
4245
|
}
|
|
4137
4246
|
log(`[manager] MCP assets deployed to ${targetDir}`);
|
|
4138
|
-
const localMcpPath =
|
|
4247
|
+
const localMcpPath = join2(targetDir, "index.js");
|
|
4139
4248
|
try {
|
|
4140
|
-
const agentsDir =
|
|
4249
|
+
const agentsDir = join2(homedir2(), ".augmented", "agents");
|
|
4141
4250
|
if (existsSync(agentsDir)) {
|
|
4142
4251
|
for (const entry of readdirSync(agentsDir, { withFileTypes: true })) {
|
|
4143
4252
|
if (!entry.isDirectory()) continue;
|
|
4144
4253
|
for (const subdir of ["provision", "project"]) {
|
|
4145
|
-
const mcpJsonPath =
|
|
4254
|
+
const mcpJsonPath = join2(agentsDir, entry.name, subdir, ".mcp.json");
|
|
4146
4255
|
try {
|
|
4147
4256
|
const raw = readFileSync(mcpJsonPath, "utf-8");
|
|
4148
4257
|
if (!raw.includes("@integrity-labs/augmented-mcp")) continue;
|