@integrity-labs/agt-cli 0.10.8 → 0.10.10

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.
@@ -10,7 +10,7 @@ import {
10
10
  provisionStopHook,
11
11
  requireHost,
12
12
  resolveChannels
13
- } from "../chunk-VDUA5FEW.js";
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 = join(process.env["HOME"] ?? "/tmp", ".augmented");
626
- var GATEWAY_PORTS_FILE = join(AUGMENTED_DIR, "gateway-ports.json");
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: homedir2 } = await import("os");
849
+ const { homedir: homedir3 } = await import("os");
768
850
  const { readFileSync: readF, writeFileSync: writeF } = await import("fs");
769
- const markerPath = join(homedir2(), ".augmented", ".last-update-check");
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 = join(process.env["HOME"] ?? "/tmp", ".augmented", "manager-state.json");
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 = join(configDir, codeName, "project", ".claude", "skills");
918
- const claudeMdPath = join(configDir, codeName, "project", "CLAUDE.md");
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 = join(skillsDir, dir, "SKILL.md");
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 = join(homeDir, ".openclaw", "openclaw.json");
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 = join(homeDir, `.openclaw-${codeName}`);
987
- if (existsSync(join(profileDir, "openclaw.json"))) continue;
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 = join(homeDir, ".openclaw", "agents", codeName, "agent");
993
- const profileAuthDir = join(profileDir, "agents", codeName, "agent");
994
- const authFile = join(sharedAuthDir, "auth-profiles.json");
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(join(profileAuthDir, "auth-profiles.json"), authContent);
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 platform = modelDefaults?.platform ?? {};
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 = platform?.[platformField];
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(join(homeDir, `.openclaw-${codeName}`, "openclaw.json"), "utf-8"));
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 = join(homeDir, `.openclaw-${codeName}`, "cron", "jobs.json");
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 = join(homeDir, `.openclaw-${codeName}`, "cron", "jobs.json");
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 = join(homeDir, `.openclaw-${codeName}`, "openclaw.json");
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 = join(homeDir, `.openclaw-${codeName}`, "openclaw.json");
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 = join(config.configDir, prev.codeName, "provision");
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 = join(config.configDir, agent.code_name, "provision");
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 = join(agentDir, artifact.relativePath);
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 = join(config.configDir, agent.code_name, "project", "CLAUDE.md");
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(join(agentDir, "CHARTER.md"));
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 = join(agentDir, file.relativePath);
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 = join(agentDir, ".claude", "skills");
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(join(provSkillsDir, folder), { recursive: true });
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(join(agentDir, file));
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(join(agentDir, file));
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(join(agentDir, file));
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 = join(homedir(), ".claude", "plugins", "installed_plugins.json");
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 = join(homedir(), ".augmented", agent.code_name, "project");
1835
+ const projectDir = join2(homedir2(), ".augmented", agent.code_name, "project");
1745
1836
  mkdirSync(projectDir, { recursive: true });
1746
- const channelsPath = join(projectDir, ".mcp-channels.json");
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 = join(homedir(), ".augmented", "_mcp", "direct-chat-channel.js");
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: join2 } = await import("path");
1861
- const { homedir: homedir2 } = await import("os");
1862
- const mcpPath = join2(homedir2(), ".augmented", "agents", agent.code_name, "provision", ".mcp.json");
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 = join(process.cwd(), "packages", "openclaw-plugin-augmented", "src", "index.ts");
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 = join(config.configDir, agent.code_name, "project", ".claude", "skills");
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 = join(agentSkillsDir, entry);
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 = join(config.configDir, agent.code_name, "skills", entry);
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 = join(homeDir, `.openclaw-${agent.code_name}`, "cron", "jobs.json");
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 = join(homeDir, `.openclaw-${codeName}`, "agents", agentDir, "sessions");
2418
+ const sessionsDir = join2(homeDir, `.openclaw-${codeName}`, "agents", agentDir, "sessions");
2328
2419
  cleanupCronSessions(sessionsDir, CRON_SESSION_KEEP_COUNT);
2329
2420
  }
2330
- const cronRunsDir = join(homeDir, `.openclaw-${codeName}`, "cron", "runs");
2421
+ const cronRunsDir = join2(homeDir, `.openclaw-${codeName}`, "cron", "runs");
2331
2422
  cleanupOldFiles(cronRunsDir, CRON_RUN_RETENTION_DAYS, ".jsonl");
2332
- const cronJobsPath = join(homeDir, `.openclaw-${codeName}`, "cron", "jobs.json");
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 = join(sessionsDir, "sessions.json");
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 = join(sessionsDir, `${entry.sessionId}.jsonl`);
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 = join(sessionsDir, `${parentSessionId}.jsonl`);
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 = join(dir, f);
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 = join(projectDir, ".mcp.json");
2620
+ const mcpConfigPath = join2(projectDir, ".mcp.json");
2530
2621
  sanitizeMcpJson(mcpConfigPath, requireHost());
2531
2622
  try {
2532
- const claudeMdPath = join(projectDir, "CLAUDE.md");
2623
+ const claudeMdPath = join2(projectDir, "CLAUDE.md");
2533
2624
  const serverNames = [];
2534
- const channelsConfigPath = join(projectDir, ".mcp-channels.json");
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 = join(projectDir, ".env.integrations");
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 = join(projectDir, ".mcp.json");
2685
- const claudeMdPath = join(projectDir, "CLAUDE.md");
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 = join(projDir, ".mcp.json");
3078
- const channelsConfigPath = join(projDir, ".mcp-channels.json");
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 = join(projDir, "CLAUDE.md");
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 = join(projDir, ".env.integrations");
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
- join(process.cwd(), "skills", skillId, "SKILL.md"),
3389
- join(new URL(".", import.meta.url).pathname, "..", "..", "..", "..", "skills", skillId, "SKILL.md")
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 = join(configDir, agent.code_name, "project");
3884
- const memoryDir = join(projectDir, "memory");
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(join(memoryDir, file), "utf-8");
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(join(memoryDir, file), "utf-8"), file.replace(/\.md$/, ""));
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(join(memoryDir, `${slug}.md`), fileContent);
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 = join(homedir(), ".augmented", "_mcp");
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 = join(dir, "mcp");
4133
- if (existsSync(join(candidate, "index.js"))) {
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 = join(mcpSourceDir, file);
4147
- const dst = join(targetDir, file);
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 = join(targetDir, "index.js");
4247
+ const localMcpPath = join2(targetDir, "index.js");
4157
4248
  try {
4158
- const agentsDir = join(homedir(), ".augmented", "agents");
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 = join(agentsDir, entry.name, subdir, ".mcp.json");
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;