@integrity-labs/agt-cli 0.10.8 → 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 +172 -81
- 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) {
|
|
@@ -2526,12 +2617,12 @@ async function syncAndCheckClaudeScheduler(agent, tasks, boardItems, refreshData
|
|
|
2526
2617
|
}
|
|
2527
2618
|
async function executeAndProcessClaudeTask(codeName, agentId, task, prompt) {
|
|
2528
2619
|
const projectDir = getProjectDir(codeName);
|
|
2529
|
-
const mcpConfigPath =
|
|
2620
|
+
const mcpConfigPath = join2(projectDir, ".mcp.json");
|
|
2530
2621
|
sanitizeMcpJson(mcpConfigPath, requireHost());
|
|
2531
2622
|
try {
|
|
2532
|
-
const claudeMdPath =
|
|
2623
|
+
const claudeMdPath = join2(projectDir, "CLAUDE.md");
|
|
2533
2624
|
const serverNames = [];
|
|
2534
|
-
const channelsConfigPath =
|
|
2625
|
+
const channelsConfigPath = join2(projectDir, ".mcp-channels.json");
|
|
2535
2626
|
for (const p of [mcpConfigPath, channelsConfigPath]) {
|
|
2536
2627
|
if (existsSync(p)) {
|
|
2537
2628
|
try {
|
|
@@ -2560,7 +2651,7 @@ async function executeAndProcessClaudeTask(codeName, agentId, task, prompt) {
|
|
|
2560
2651
|
claudeArgs.push("--system-prompt-file", claudeMdPath);
|
|
2561
2652
|
}
|
|
2562
2653
|
const childEnv = { ...process.env };
|
|
2563
|
-
const envIntPath =
|
|
2654
|
+
const envIntPath = join2(projectDir, ".env.integrations");
|
|
2564
2655
|
if (existsSync(envIntPath)) {
|
|
2565
2656
|
try {
|
|
2566
2657
|
for (const line of readFileSync(envIntPath, "utf-8").split("\n")) {
|
|
@@ -2681,8 +2772,8 @@ var persistentSessionAgents = /* @__PURE__ */ new Set();
|
|
|
2681
2772
|
async function ensurePersistentSession(agent, tasks, boardItems, refreshData) {
|
|
2682
2773
|
const codeName = agent.code_name;
|
|
2683
2774
|
const projectDir = getProjectDir2(codeName);
|
|
2684
|
-
const mcpConfigPath =
|
|
2685
|
-
const claudeMdPath =
|
|
2775
|
+
const mcpConfigPath = join2(projectDir, ".mcp.json");
|
|
2776
|
+
const claudeMdPath = join2(projectDir, "CLAUDE.md");
|
|
2686
2777
|
const channelConfigs = refreshData.channel_configs;
|
|
2687
2778
|
const channels = [];
|
|
2688
2779
|
const devChannels = [];
|
|
@@ -3074,8 +3165,8 @@ async function processDirectChatMessage(agent, msg) {
|
|
|
3074
3165
|
if (fw === "claude-code") {
|
|
3075
3166
|
const { getProjectDir: ccProjectDir } = await import("../claude-scheduler-7PVWQHWU.js");
|
|
3076
3167
|
const projDir = ccProjectDir(agent.codeName);
|
|
3077
|
-
const mcpConfigPath =
|
|
3078
|
-
const channelsConfigPath =
|
|
3168
|
+
const mcpConfigPath = join2(projDir, ".mcp.json");
|
|
3169
|
+
const channelsConfigPath = join2(projDir, ".mcp-channels.json");
|
|
3079
3170
|
const serverNames = [];
|
|
3080
3171
|
for (const p of [mcpConfigPath, channelsConfigPath]) {
|
|
3081
3172
|
if (existsSync(p)) {
|
|
@@ -3100,11 +3191,11 @@ async function processDirectChatMessage(agent, msg) {
|
|
|
3100
3191
|
allowedTools
|
|
3101
3192
|
];
|
|
3102
3193
|
if (existsSync(channelsConfigPath)) chatArgs.push("--mcp-config", channelsConfigPath);
|
|
3103
|
-
const chatClaudeMd =
|
|
3194
|
+
const chatClaudeMd = join2(projDir, "CLAUDE.md");
|
|
3104
3195
|
if (existsSync(chatClaudeMd)) {
|
|
3105
3196
|
chatArgs.push("--system-prompt-file", chatClaudeMd);
|
|
3106
3197
|
}
|
|
3107
|
-
const envIntPath =
|
|
3198
|
+
const envIntPath = join2(projDir, ".env.integrations");
|
|
3108
3199
|
const childEnv = { ...process.env };
|
|
3109
3200
|
if (existsSync(envIntPath)) {
|
|
3110
3201
|
try {
|
|
@@ -3385,8 +3476,8 @@ function getBuiltInSkillContent(skillId) {
|
|
|
3385
3476
|
if (builtInSkillCache.has(skillId)) return builtInSkillCache.get(skillId);
|
|
3386
3477
|
try {
|
|
3387
3478
|
const candidates = [
|
|
3388
|
-
|
|
3389
|
-
|
|
3479
|
+
join2(process.cwd(), "skills", skillId, "SKILL.md"),
|
|
3480
|
+
join2(new URL(".", import.meta.url).pathname, "..", "..", "..", "..", "skills", skillId, "SKILL.md")
|
|
3390
3481
|
];
|
|
3391
3482
|
for (const candidate of candidates) {
|
|
3392
3483
|
if (existsSync(candidate)) {
|
|
@@ -3880,8 +3971,8 @@ function parseMemoryFile(raw, fallbackName) {
|
|
|
3880
3971
|
};
|
|
3881
3972
|
}
|
|
3882
3973
|
async function syncMemories(agent, configDir, log2) {
|
|
3883
|
-
const projectDir =
|
|
3884
|
-
const memoryDir =
|
|
3974
|
+
const projectDir = join2(configDir, agent.code_name, "project");
|
|
3975
|
+
const memoryDir = join2(projectDir, "memory");
|
|
3885
3976
|
if (existsSync(memoryDir)) {
|
|
3886
3977
|
const prevHashes = memoryFileHashes.get(agent.agent_id) ?? /* @__PURE__ */ new Map();
|
|
3887
3978
|
const currentHashes = /* @__PURE__ */ new Map();
|
|
@@ -3889,7 +3980,7 @@ async function syncMemories(agent, configDir, log2) {
|
|
|
3889
3980
|
for (const file of readdirSync(memoryDir)) {
|
|
3890
3981
|
if (!file.endsWith(".md")) continue;
|
|
3891
3982
|
try {
|
|
3892
|
-
const raw = readFileSync(
|
|
3983
|
+
const raw = readFileSync(join2(memoryDir, file), "utf-8");
|
|
3893
3984
|
const fileHash = createHash("sha256").update(raw).digest("hex").slice(0, 16);
|
|
3894
3985
|
currentHashes.set(file, fileHash);
|
|
3895
3986
|
if (prevHashes.get(file) === fileHash) continue;
|
|
@@ -3914,7 +4005,7 @@ async function syncMemories(agent, configDir, log2) {
|
|
|
3914
4005
|
} catch (err) {
|
|
3915
4006
|
for (const mem of changedMemories) {
|
|
3916
4007
|
for (const [file] of currentHashes) {
|
|
3917
|
-
const parsed = parseMemoryFile(readFileSync(
|
|
4008
|
+
const parsed = parseMemoryFile(readFileSync(join2(memoryDir, file), "utf-8"), file.replace(/\.md$/, ""));
|
|
3918
4009
|
if (parsed?.name === mem.name) currentHashes.delete(file);
|
|
3919
4010
|
}
|
|
3920
4011
|
}
|
|
@@ -3952,7 +4043,7 @@ description: ${JSON.stringify(mem.content.slice(0, 200))}
|
|
|
3952
4043
|
|
|
3953
4044
|
${mem.content}
|
|
3954
4045
|
`;
|
|
3955
|
-
writeFileSync(
|
|
4046
|
+
writeFileSync(join2(memoryDir, `${slug}.md`), fileContent);
|
|
3956
4047
|
written++;
|
|
3957
4048
|
}
|
|
3958
4049
|
if (written > 0) {
|
|
@@ -4123,14 +4214,14 @@ function startManager(opts) {
|
|
|
4123
4214
|
startPolling();
|
|
4124
4215
|
}
|
|
4125
4216
|
function deployMcpAssets() {
|
|
4126
|
-
const targetDir =
|
|
4217
|
+
const targetDir = join2(homedir2(), ".augmented", "_mcp");
|
|
4127
4218
|
mkdirSync(targetDir, { recursive: true });
|
|
4128
4219
|
const moduleDir = dirname(fileURLToPath(import.meta.url));
|
|
4129
4220
|
let mcpSourceDir = "";
|
|
4130
4221
|
let dir = moduleDir;
|
|
4131
4222
|
for (let i = 0; i < 6; i++) {
|
|
4132
|
-
const candidate =
|
|
4133
|
-
if (existsSync(
|
|
4223
|
+
const candidate = join2(dir, "mcp");
|
|
4224
|
+
if (existsSync(join2(candidate, "index.js"))) {
|
|
4134
4225
|
mcpSourceDir = candidate;
|
|
4135
4226
|
break;
|
|
4136
4227
|
}
|
|
@@ -4143,8 +4234,8 @@ function deployMcpAssets() {
|
|
|
4143
4234
|
return;
|
|
4144
4235
|
}
|
|
4145
4236
|
for (const file of ["index.js", "slack-channel.js", "direct-chat-channel.js"]) {
|
|
4146
|
-
const src =
|
|
4147
|
-
const dst =
|
|
4237
|
+
const src = join2(mcpSourceDir, file);
|
|
4238
|
+
const dst = join2(targetDir, file);
|
|
4148
4239
|
if (!existsSync(src)) continue;
|
|
4149
4240
|
try {
|
|
4150
4241
|
copyFileSync(src, dst);
|
|
@@ -4153,14 +4244,14 @@ function deployMcpAssets() {
|
|
|
4153
4244
|
}
|
|
4154
4245
|
}
|
|
4155
4246
|
log(`[manager] MCP assets deployed to ${targetDir}`);
|
|
4156
|
-
const localMcpPath =
|
|
4247
|
+
const localMcpPath = join2(targetDir, "index.js");
|
|
4157
4248
|
try {
|
|
4158
|
-
const agentsDir =
|
|
4249
|
+
const agentsDir = join2(homedir2(), ".augmented", "agents");
|
|
4159
4250
|
if (existsSync(agentsDir)) {
|
|
4160
4251
|
for (const entry of readdirSync(agentsDir, { withFileTypes: true })) {
|
|
4161
4252
|
if (!entry.isDirectory()) continue;
|
|
4162
4253
|
for (const subdir of ["provision", "project"]) {
|
|
4163
|
-
const mcpJsonPath =
|
|
4254
|
+
const mcpJsonPath = join2(agentsDir, entry.name, subdir, ".mcp.json");
|
|
4164
4255
|
try {
|
|
4165
4256
|
const raw = readFileSync(mcpJsonPath, "utf-8");
|
|
4166
4257
|
if (!raw.includes("@integrity-labs/augmented-mcp")) continue;
|