@integrity-labs/agt-cli 0.15.7 → 0.15.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.
@@ -22,7 +22,7 @@ import {
22
22
  resolveChannels,
23
23
  resolveDmTarget,
24
24
  wrapScheduledTaskPrompt
25
- } from "../chunk-WIW5FIRY.js";
25
+ } from "../chunk-C6UBNLUC.js";
26
26
  import {
27
27
  findTaskByTemplate,
28
28
  getProjectDir,
@@ -46,11 +46,11 @@ import {
46
46
 
47
47
  // src/lib/manager-worker.ts
48
48
  import { createHash } from "crypto";
49
- import { readFileSync, writeFileSync, appendFileSync, mkdirSync, chmodSync, existsSync, rmSync, readdirSync, statSync, unlinkSync, copyFileSync } from "fs";
49
+ import { readFileSync as readFileSync2, writeFileSync as writeFileSync2, appendFileSync, mkdirSync as mkdirSync2, chmodSync, existsSync as existsSync2, rmSync as rmSync2, readdirSync as readdirSync2, statSync, unlinkSync, copyFileSync } from "fs";
50
50
  import https from "https";
51
51
  import { execFileSync as syncExecFile } from "child_process";
52
- import { join as join2, dirname } from "path";
53
- import { homedir as homedir2 } from "os";
52
+ import { join as join3, dirname } from "path";
53
+ import { homedir as homedir3 } from "os";
54
54
  import { fileURLToPath } from "url";
55
55
 
56
56
  // src/lib/plugin-context-render.ts
@@ -896,6 +896,135 @@ function withScheduleLinkFooter(opts) {
896
896
  return appendScheduleLinkFooter(opts.body, url, opts.medium);
897
897
  }
898
898
 
899
+ // src/lib/restart-flags.ts
900
+ import { existsSync, mkdirSync, readdirSync, readFileSync, renameSync, rmSync, writeFileSync } from "fs";
901
+ import { homedir as homedir2 } from "os";
902
+ import { join as join2 } from "path";
903
+ import { randomUUID } from "crypto";
904
+ function restartFlagsDir() {
905
+ return join2(homedir2(), ".augmented", "restart-flags");
906
+ }
907
+ function flagPath(codeName) {
908
+ return join2(restartFlagsDir(), `${codeName}.flag`);
909
+ }
910
+ function readRestartFlags() {
911
+ const dir = restartFlagsDir();
912
+ if (!existsSync(dir)) return [];
913
+ const out = [];
914
+ for (const entry of readdirSync(dir)) {
915
+ if (!entry.endsWith(".flag")) continue;
916
+ try {
917
+ const raw = readFileSync(join2(dir, entry), "utf8");
918
+ const parsed = JSON.parse(raw);
919
+ if (typeof parsed.codeName !== "string" || parsed.codeName.length === 0) {
920
+ parsed.codeName = entry.replace(/\.flag$/, "");
921
+ }
922
+ out.push(parsed);
923
+ } catch {
924
+ out.push({
925
+ codeName: entry.replace(/\.flag$/, ""),
926
+ source: "unknown",
927
+ ts: Date.now()
928
+ });
929
+ }
930
+ }
931
+ return out;
932
+ }
933
+ function deleteRestartFlag(codeName) {
934
+ const path = flagPath(codeName);
935
+ if (existsSync(path)) {
936
+ rmSync(path, { force: true });
937
+ }
938
+ }
939
+
940
+ // src/lib/restart-handler.ts
941
+ async function processRestartFlags(opts) {
942
+ const flags = readRestartFlags();
943
+ if (flags.length === 0) return;
944
+ for (const flag of flags) {
945
+ try {
946
+ await processOne(flag, opts);
947
+ } catch (err) {
948
+ opts.log(`[restart-handler] Failed to process flag for '${flag.codeName}': ${err.message}`);
949
+ try {
950
+ await sendError(flag, opts, `\u274C Restart failed for \`${flag.codeName}\`: internal error. Check manager logs.`);
951
+ } catch (ackErr) {
952
+ opts.log(`[restart-handler] Error-ack send failed for '${flag.codeName}': ${ackErr.message}`);
953
+ }
954
+ } finally {
955
+ try {
956
+ deleteRestartFlag(flag.codeName);
957
+ } catch (err) {
958
+ opts.log(`[restart-handler] Failed to delete flag for '${flag.codeName}': ${err.message}`);
959
+ }
960
+ }
961
+ }
962
+ }
963
+ async function processOne(flag, opts) {
964
+ const framework = opts.resolveFramework(flag.codeName);
965
+ if (framework === null) {
966
+ opts.log(`[restart-handler] Ignoring /restart for unknown agent '${flag.codeName}'`);
967
+ await sendError(flag, opts, `Agent \`${flag.codeName}\` is not managed by this host.`);
968
+ return;
969
+ }
970
+ if (framework !== "claude-code") {
971
+ opts.log(`[restart-handler] Ignoring /restart for '${flag.codeName}' \u2014 framework is '${framework}', not claude-code`);
972
+ await sendError(flag, opts, `\`/restart\` is only supported for Claude Code agents (this agent runs on \`${framework}\`).`);
973
+ return;
974
+ }
975
+ opts.log(`[restart-handler] Restarting tmux session for '${flag.codeName}' (source: ${flag.source})`);
976
+ opts.stopSession(flag.codeName);
977
+ await sendAck(flag, opts, `\u{1F504} Restart initiated for \`${flag.codeName}\` \u2014 the replacement session is being created.`);
978
+ }
979
+ async function sendAck(flag, opts, text) {
980
+ if (flag.source === "telegram") {
981
+ const tokens = opts.getTelegramTokens(flag.codeName);
982
+ if (!tokens) {
983
+ opts.log(`[restart-handler] No telegram tokens cached for '${flag.codeName}' \u2014 skipping ack`);
984
+ return;
985
+ }
986
+ const chatId = flag.reply?.["chat_id"];
987
+ if (chatId == null) return;
988
+ const messageId = flag.reply?.["message_id"];
989
+ const body = { chat_id: chatId, text, parse_mode: "Markdown" };
990
+ if (messageId != null) body.reply_to_message_id = Number(messageId);
991
+ try {
992
+ const resp = await opts.sendTelegram(tokens.token, "sendMessage", body);
993
+ if (!resp.ok) {
994
+ opts.log(`[restart-handler] Telegram ack failed for '${flag.codeName}': ${resp.description ?? "unknown"}`);
995
+ }
996
+ } catch (err) {
997
+ opts.log(`[restart-handler] Telegram ack threw for '${flag.codeName}': ${err.message}`);
998
+ }
999
+ return;
1000
+ }
1001
+ if (flag.source === "slack") {
1002
+ const token = opts.getSlackToken(flag.codeName);
1003
+ if (!token) {
1004
+ opts.log(`[restart-handler] No slack token cached for '${flag.codeName}' \u2014 skipping ack`);
1005
+ return;
1006
+ }
1007
+ const channel = flag.reply?.["channel"];
1008
+ if (channel == null) return;
1009
+ const threadTs = flag.reply?.["thread_ts"];
1010
+ const body = { channel, text };
1011
+ if (threadTs != null) body.thread_ts = String(threadTs);
1012
+ try {
1013
+ const resp = await opts.sendSlack(token, body);
1014
+ if (!resp.ok) {
1015
+ opts.log(`[restart-handler] Slack ack failed for '${flag.codeName}': ${resp.error ?? "unknown"}`);
1016
+ }
1017
+ } catch (err) {
1018
+ opts.log(`[restart-handler] Slack ack threw for '${flag.codeName}': ${err.message}`);
1019
+ }
1020
+ return;
1021
+ }
1022
+ opts.log(`[restart-handler] Unknown ack source '${flag.source}' for '${flag.codeName}' \u2014 skipping`);
1023
+ }
1024
+ async function sendError(flag, opts, text) {
1025
+ await sendAck(flag, opts, text);
1026
+ }
1027
+
899
1028
  // src/lib/realtime-chat.ts
900
1029
  import { createClient } from "@supabase/supabase-js";
901
1030
  var client = null;
@@ -1220,8 +1349,8 @@ function stopRealtimeChat() {
1220
1349
  var GATEWAY_PORT_BASE = 18800;
1221
1350
  var GATEWAY_PORT_STEP = 10;
1222
1351
  var GATEWAY_PORT_MAX = 18899;
1223
- var AUGMENTED_DIR = join2(process.env["HOME"] ?? "/tmp", ".augmented");
1224
- var GATEWAY_PORTS_FILE = join2(AUGMENTED_DIR, "gateway-ports.json");
1352
+ var AUGMENTED_DIR = join3(process.env["HOME"] ?? "/tmp", ".augmented");
1353
+ var GATEWAY_PORTS_FILE = join3(AUGMENTED_DIR, "gateway-ports.json");
1225
1354
  var CHANNEL_SWEEP_INTERVAL_MS = (() => {
1226
1355
  const raw = parseInt(process.env["AGT_CHANNEL_SWEEP_INTERVAL_MS"] ?? "", 10);
1227
1356
  if (!Number.isFinite(raw)) return 5 * 60 * 1e3;
@@ -1313,7 +1442,7 @@ function resolveBrewPath(execFileSync2) {
1313
1442
  } catch {
1314
1443
  }
1315
1444
  const fallback = "/home/linuxbrew/.linuxbrew/bin/brew";
1316
- if (existsSync(fallback)) return fallback;
1445
+ if (existsSync2(fallback)) return fallback;
1317
1446
  return null;
1318
1447
  }
1319
1448
  var toolkitCliEnsured = /* @__PURE__ */ new Set();
@@ -1459,7 +1588,7 @@ async function ensureFrameworkBinary(frameworkId) {
1459
1588
  }
1460
1589
  return runAsync(brewPath, args, opts);
1461
1590
  };
1462
- let claudeExists = existsSync("/home/linuxbrew/.linuxbrew/bin/claude");
1591
+ let claudeExists = existsSync2("/home/linuxbrew/.linuxbrew/bin/claude");
1463
1592
  if (!claudeExists) {
1464
1593
  try {
1465
1594
  execFileSync2("which", ["claude"], { timeout: 5e3 });
@@ -1483,7 +1612,7 @@ async function ensureFrameworkBinary(frameworkId) {
1483
1612
  if (!process.env.PATH?.split(":").includes(brewBinDir)) {
1484
1613
  process.env.PATH = `${brewBinDir}:${process.env.PATH ?? ""}`;
1485
1614
  }
1486
- if (existsSync("/home/linuxbrew/.linuxbrew/bin/claude")) {
1615
+ if (existsSync2("/home/linuxbrew/.linuxbrew/bin/claude")) {
1487
1616
  log("Claude Code installed successfully");
1488
1617
  } else {
1489
1618
  log("Claude Code install completed but binary not found at expected path \u2014 check brew logs");
@@ -1518,9 +1647,9 @@ async function checkAndUpdateCli() {
1518
1647
  const isDevMode = cliPath.includes("/src/") || cliPath.includes("tsx");
1519
1648
  if (isDevMode) return;
1520
1649
  if (!isHomebrew && !cliPath.includes("node_modules")) return;
1521
- const { homedir: homedir3 } = await import("os");
1650
+ const { homedir: homedir4 } = await import("os");
1522
1651
  const { readFileSync: readF, writeFileSync: writeF } = await import("fs");
1523
- const markerPath = join2(homedir3(), ".augmented", ".last-update-check");
1652
+ const markerPath = join3(homedir4(), ".augmented", ".last-update-check");
1524
1653
  try {
1525
1654
  const lastCheck = parseInt(readF(markerPath, "utf-8").trim(), 10);
1526
1655
  if (Date.now() - lastCheck < UPDATE_CHECK_INTERVAL_MS) return;
@@ -1603,12 +1732,12 @@ async function applyClaudeAuthToEnv(childEnv, label) {
1603
1732
  throw new Error("claude_auth_mode=api_key but /host/exchange returned no decrypted key");
1604
1733
  }
1605
1734
  childEnv.ANTHROPIC_API_KEY = exchange.anthropicApiKey;
1606
- const claudeDir = join2(homedir2(), ".claude");
1735
+ const claudeDir = join3(homedir3(), ".claude");
1607
1736
  for (const filename of [".credentials.json", "credentials.json"]) {
1608
- const p = join2(claudeDir, filename);
1609
- if (existsSync(p)) {
1737
+ const p = join3(claudeDir, filename);
1738
+ if (existsSync2(p)) {
1610
1739
  try {
1611
- rmSync(p, { force: true });
1740
+ rmSync2(p, { force: true });
1612
1741
  log(`[${label}] Removed ${p} (api_key mode \u2014 preventing OAuth fallback)`);
1613
1742
  } catch {
1614
1743
  }
@@ -1620,14 +1749,14 @@ async function applyClaudeAuthToEnv(childEnv, label) {
1620
1749
  }
1621
1750
  function loadGatewayPorts() {
1622
1751
  try {
1623
- return JSON.parse(readFileSync(GATEWAY_PORTS_FILE, "utf-8"));
1752
+ return JSON.parse(readFileSync2(GATEWAY_PORTS_FILE, "utf-8"));
1624
1753
  } catch {
1625
1754
  return {};
1626
1755
  }
1627
1756
  }
1628
1757
  function saveGatewayPorts(ports) {
1629
- mkdirSync(AUGMENTED_DIR, { recursive: true });
1630
- writeFileSync(GATEWAY_PORTS_FILE, JSON.stringify(ports, null, 2));
1758
+ mkdirSync2(AUGMENTED_DIR, { recursive: true });
1759
+ writeFileSync2(GATEWAY_PORTS_FILE, JSON.stringify(ports, null, 2));
1631
1760
  }
1632
1761
  function allocatePort(codeName) {
1633
1762
  const ports = loadGatewayPorts();
@@ -1650,12 +1779,12 @@ function freePort(codeName) {
1650
1779
  }
1651
1780
  }
1652
1781
  function getStateFile() {
1653
- return join2(config?.configDir ?? join2(process.env["HOME"] ?? "/tmp", ".augmented"), "manager-state.json");
1782
+ return join3(config?.configDir ?? join3(process.env["HOME"] ?? "/tmp", ".augmented"), "manager-state.json");
1654
1783
  }
1655
1784
  function send(msg) {
1656
1785
  if (msg.type === "state-update") {
1657
1786
  try {
1658
- writeFileSync(getStateFile(), JSON.stringify(msg.state, null, 2));
1787
+ writeFileSync2(getStateFile(), JSON.stringify(msg.state, null, 2));
1659
1788
  } catch {
1660
1789
  }
1661
1790
  }
@@ -1685,9 +1814,9 @@ function log(msg) {
1685
1814
  `);
1686
1815
  try {
1687
1816
  if (!managerLogPath) {
1688
- managerLogPath = join2(homedir2(), ".augmented", "manager.log");
1689
- mkdirSync(dirname(managerLogPath), { recursive: true });
1690
- if (!existsSync(managerLogPath)) {
1817
+ managerLogPath = join3(homedir3(), ".augmented", "manager.log");
1818
+ mkdirSync2(dirname(managerLogPath), { recursive: true });
1819
+ if (!existsSync2(managerLogPath)) {
1691
1820
  appendFileSync(managerLogPath, "", { mode: 384 });
1692
1821
  } else {
1693
1822
  chmodSync(managerLogPath, 384);
@@ -1703,7 +1832,7 @@ function sha256(content) {
1703
1832
  }
1704
1833
  function hashFile(filePath) {
1705
1834
  try {
1706
- const content = readFileSync(filePath, "utf-8");
1835
+ const content = readFileSync2(filePath, "utf-8");
1707
1836
  return sha256(content);
1708
1837
  } catch {
1709
1838
  return null;
@@ -1727,13 +1856,13 @@ function parseSkillFrontmatter(content) {
1727
1856
  return out;
1728
1857
  }
1729
1858
  async function refreshSkillsIndexInClaudeMd(configDir, codeName, log2) {
1730
- const { readdirSync: readdirSync2, readFileSync: rfs, existsSync: ex, writeFileSync: writeFileSync2 } = await import("fs");
1731
- const skillsDir = join2(configDir, codeName, "project", ".claude", "skills");
1732
- const claudeMdPath = join2(configDir, codeName, "project", "CLAUDE.md");
1859
+ const { readdirSync: readdirSync3, readFileSync: rfs, existsSync: ex, writeFileSync: writeFileSync3 } = await import("fs");
1860
+ const skillsDir = join3(configDir, codeName, "project", ".claude", "skills");
1861
+ const claudeMdPath = join3(configDir, codeName, "project", "CLAUDE.md");
1733
1862
  if (!ex(skillsDir) || !ex(claudeMdPath)) return;
1734
1863
  const entries = [];
1735
- for (const dir of readdirSync2(skillsDir).sort()) {
1736
- const skillFile = join2(skillsDir, dir, "SKILL.md");
1864
+ for (const dir of readdirSync3(skillsDir).sort()) {
1865
+ const skillFile = join3(skillsDir, dir, "SKILL.md");
1737
1866
  if (!ex(skillFile)) continue;
1738
1867
  try {
1739
1868
  const { name, description } = parseSkillFrontmatter(rfs(skillFile, "utf-8"));
@@ -1775,16 +1904,16 @@ ${SKILLS_INDEX_END}`;
1775
1904
  next = current.trimEnd() + "\n\n" + section + "\n";
1776
1905
  }
1777
1906
  if (next !== current) {
1778
- writeFileSync2(claudeMdPath, next, "utf-8");
1907
+ writeFileSync3(claudeMdPath, next, "utf-8");
1779
1908
  log2(`Refreshed skills index in CLAUDE.md for '${codeName}' (${entries.length} skills)`);
1780
1909
  }
1781
1910
  }
1782
1911
  async function migrateToProfiles() {
1783
1912
  const homeDir = process.env["HOME"] ?? "/tmp";
1784
- const sharedConfigPath = join2(homeDir, ".openclaw", "openclaw.json");
1913
+ const sharedConfigPath = join3(homeDir, ".openclaw", "openclaw.json");
1785
1914
  let sharedConfig;
1786
1915
  try {
1787
- sharedConfig = JSON.parse(readFileSync(sharedConfigPath, "utf-8"));
1916
+ sharedConfig = JSON.parse(readFileSync2(sharedConfigPath, "utf-8"));
1788
1917
  } catch {
1789
1918
  return;
1790
1919
  }
@@ -1797,19 +1926,19 @@ async function migrateToProfiles() {
1797
1926
  const codeName = agentEntry["id"];
1798
1927
  if (!codeName) continue;
1799
1928
  if (codeName === "main") continue;
1800
- const profileDir = join2(homeDir, `.openclaw-${codeName}`);
1801
- if (existsSync(join2(profileDir, "openclaw.json"))) continue;
1929
+ const profileDir = join3(homeDir, `.openclaw-${codeName}`);
1930
+ if (existsSync2(join3(profileDir, "openclaw.json"))) continue;
1802
1931
  log(`Migrating agent '${codeName}' to per-agent profile`);
1803
1932
  if (adapter.seedProfileConfig) {
1804
1933
  adapter.seedProfileConfig(codeName);
1805
1934
  }
1806
- const sharedAuthDir = join2(homeDir, ".openclaw", "agents", codeName, "agent");
1807
- const profileAuthDir = join2(profileDir, "agents", codeName, "agent");
1808
- const authFile = join2(sharedAuthDir, "auth-profiles.json");
1809
- if (existsSync(authFile)) {
1810
- mkdirSync(profileAuthDir, { recursive: true });
1811
- const authContent = readFileSync(authFile, "utf-8");
1812
- writeFileSync(join2(profileAuthDir, "auth-profiles.json"), authContent);
1935
+ const sharedAuthDir = join3(homeDir, ".openclaw", "agents", codeName, "agent");
1936
+ const profileAuthDir = join3(profileDir, "agents", codeName, "agent");
1937
+ const authFile = join3(sharedAuthDir, "auth-profiles.json");
1938
+ if (existsSync2(authFile)) {
1939
+ mkdirSync2(profileAuthDir, { recursive: true });
1940
+ const authContent = readFileSync2(authFile, "utf-8");
1941
+ writeFileSync2(join3(profileAuthDir, "auth-profiles.json"), authContent);
1813
1942
  }
1814
1943
  allocatePort(codeName);
1815
1944
  migrated++;
@@ -1847,7 +1976,7 @@ function readGatewayToken(codeName) {
1847
1976
  }
1848
1977
  const homeDir = process.env["HOME"] ?? "/tmp";
1849
1978
  try {
1850
- const cfg = JSON.parse(readFileSync(join2(homeDir, `.openclaw-${codeName}`, "openclaw.json"), "utf-8"));
1979
+ const cfg = JSON.parse(readFileSync2(join3(homeDir, `.openclaw-${codeName}`, "openclaw.json"), "utf-8"));
1851
1980
  return cfg?.gateway?.auth?.token;
1852
1981
  } catch {
1853
1982
  return void 0;
@@ -1856,10 +1985,10 @@ function readGatewayToken(codeName) {
1856
1985
  var GATEWAY_HUNG_TIMEOUT_MS = 5 * 6e4;
1857
1986
  function isGatewayHung(codeName) {
1858
1987
  const homeDir = process.env["HOME"] ?? "/tmp";
1859
- const jobsPath = join2(homeDir, `.openclaw-${codeName}`, "cron", "jobs.json");
1860
- if (!existsSync(jobsPath)) return false;
1988
+ const jobsPath = join3(homeDir, `.openclaw-${codeName}`, "cron", "jobs.json");
1989
+ if (!existsSync2(jobsPath)) return false;
1861
1990
  try {
1862
- const data = JSON.parse(readFileSync(jobsPath, "utf-8"));
1991
+ const data = JSON.parse(readFileSync2(jobsPath, "utf-8"));
1863
1992
  const jobs = data.jobs ?? data;
1864
1993
  if (!Array.isArray(jobs)) return false;
1865
1994
  const now = Date.now();
@@ -1892,19 +2021,19 @@ async function ensureGatewayRunning(codeName, adapter) {
1892
2021
  }
1893
2022
  await new Promise((r) => setTimeout(r, 2e3));
1894
2023
  const homeDir = process.env["HOME"] ?? "/tmp";
1895
- const cronJobsPath = join2(homeDir, `.openclaw-${codeName}`, "cron", "jobs.json");
2024
+ const cronJobsPath = join3(homeDir, `.openclaw-${codeName}`, "cron", "jobs.json");
1896
2025
  clearStaleCronRunState(cronJobsPath);
1897
2026
  } else {
1898
2027
  if (status.port) {
1899
2028
  try {
1900
2029
  const homeDir = process.env["HOME"] ?? "/tmp";
1901
- const configPath = join2(homeDir, `.openclaw-${codeName}`, "openclaw.json");
1902
- if (existsSync(configPath)) {
1903
- const cfg = JSON.parse(readFileSync(configPath, "utf-8"));
2030
+ const configPath = join3(homeDir, `.openclaw-${codeName}`, "openclaw.json");
2031
+ if (existsSync2(configPath)) {
2032
+ const cfg = JSON.parse(readFileSync2(configPath, "utf-8"));
1904
2033
  if (cfg.gateway?.port !== status.port) {
1905
2034
  if (!cfg.gateway) cfg.gateway = {};
1906
2035
  cfg.gateway.port = status.port;
1907
- writeFileSync(configPath, JSON.stringify(cfg, null, 2));
2036
+ writeFileSync2(configPath, JSON.stringify(cfg, null, 2));
1908
2037
  }
1909
2038
  }
1910
2039
  } catch {
@@ -1924,12 +2053,12 @@ async function ensureGatewayRunning(codeName, adapter) {
1924
2053
  gatewaysStartedThisCycle.add(codeName);
1925
2054
  try {
1926
2055
  const homeDir = process.env["HOME"] ?? "/tmp";
1927
- const configPath = join2(homeDir, `.openclaw-${codeName}`, "openclaw.json");
1928
- if (existsSync(configPath)) {
1929
- const cfg = JSON.parse(readFileSync(configPath, "utf-8"));
2056
+ const configPath = join3(homeDir, `.openclaw-${codeName}`, "openclaw.json");
2057
+ if (existsSync2(configPath)) {
2058
+ const cfg = JSON.parse(readFileSync2(configPath, "utf-8"));
1930
2059
  if (!cfg.gateway) cfg.gateway = {};
1931
2060
  cfg.gateway.port = port;
1932
- writeFileSync(configPath, JSON.stringify(cfg, null, 2));
2061
+ writeFileSync2(configPath, JSON.stringify(cfg, null, 2));
1933
2062
  }
1934
2063
  } catch {
1935
2064
  }
@@ -2012,6 +2141,48 @@ Automatic restart failed: ${err.message}`
2012
2141
  async function pollCycle() {
2013
2142
  if (!config) return;
2014
2143
  if (restartAfterUpgrade) return;
2144
+ try {
2145
+ await processRestartFlags({
2146
+ log,
2147
+ resolveFramework: (codeName) => agentFrameworkCache.get(codeName) ?? null,
2148
+ stopSession: (codeName) => {
2149
+ stopPersistentSession(codeName, log);
2150
+ persistentSessionAgents.delete(codeName);
2151
+ claudeAuthTupleBySession.delete(codeName);
2152
+ },
2153
+ getTelegramTokens: (codeName) => {
2154
+ const t = agentChannelTokens.get(codeName);
2155
+ if (!t?.telegram) return null;
2156
+ return { token: t.telegram, allowedChats: t.telegramAllowedChats };
2157
+ },
2158
+ sendTelegram: (botToken, method, body) => telegramApiCall(botToken, method, body),
2159
+ getSlackToken: (codeName) => agentChannelTokens.get(codeName)?.slack ?? null,
2160
+ sendSlack: async (botToken, body) => {
2161
+ const controller = new AbortController();
2162
+ const timer = setTimeout(() => controller.abort(), 5e3);
2163
+ try {
2164
+ const res = await fetch("https://slack.com/api/chat.postMessage", {
2165
+ method: "POST",
2166
+ headers: {
2167
+ "Content-Type": "application/json; charset=utf-8",
2168
+ Authorization: `Bearer ${botToken}`
2169
+ },
2170
+ body: JSON.stringify(body),
2171
+ signal: controller.signal
2172
+ });
2173
+ const data = await res.json();
2174
+ return data;
2175
+ } catch (err) {
2176
+ const isAbort = err.name === "AbortError";
2177
+ return { ok: false, error: isAbort ? "timeout" : err.message };
2178
+ } finally {
2179
+ clearTimeout(timer);
2180
+ }
2181
+ }
2182
+ });
2183
+ } catch (err) {
2184
+ log(`[restart-handler] processRestartFlags threw: ${err.message}`);
2185
+ }
2015
2186
  checkAndUpdateCli().catch((err) => log(`[self-update] Check failed: ${err.message}`));
2016
2187
  try {
2017
2188
  registeredAgentsCache.clear();
@@ -2135,7 +2306,7 @@ async function pollCycle() {
2135
2306
  const adapter = resolveAgentFramework(prev.codeName);
2136
2307
  await stopGatewayIfRunning(prev.codeName, adapter);
2137
2308
  freePort(prev.codeName);
2138
- const agentDir = join2(adapter.getAgentDir(prev.codeName), "provision");
2309
+ const agentDir = join3(adapter.getAgentDir(prev.codeName), "provision");
2139
2310
  await cleanupAgentFiles(prev.codeName, agentDir);
2140
2311
  clearAgentCaches(prev.agentId, prev.codeName);
2141
2312
  }
@@ -2215,7 +2386,7 @@ async function processAgent(agent, agentStates) {
2215
2386
  }
2216
2387
  const now = (/* @__PURE__ */ new Date()).toISOString();
2217
2388
  const adapter = resolveAgentFramework(agent.code_name);
2218
- let agentDir = join2(adapter.getAgentDir(agent.code_name), "provision");
2389
+ let agentDir = join3(adapter.getAgentDir(agent.code_name), "provision");
2219
2390
  if (agent.status === "draft" || agent.status === "paused") {
2220
2391
  log(`Agent '${agent.code_name}' is ${agent.status}, skipping provisioning`);
2221
2392
  await stopGatewayIfRunning(agent.code_name, adapter);
@@ -2339,7 +2510,7 @@ async function processAgent(agent, agentStates) {
2339
2510
  const frameworkId = refreshData.agent.framework ?? "openclaw";
2340
2511
  agentFrameworkCache.set(agent.code_name, frameworkId);
2341
2512
  const frameworkAdapter = getFramework(frameworkId);
2342
- agentDir = join2(frameworkAdapter.getAgentDir(agent.code_name), "provision");
2513
+ agentDir = join3(frameworkAdapter.getAgentDir(agent.code_name), "provision");
2343
2514
  cacheAgentDeliveryMetadata(agent.code_name, refreshData);
2344
2515
  if (frameworkAdapter.seedProfileConfig) {
2345
2516
  frameworkAdapter.seedProfileConfig(agent.code_name);
@@ -2367,9 +2538,9 @@ async function processAgent(agent, agentStates) {
2367
2538
  try {
2368
2539
  const artifacts = generateArtifacts(agent, refreshData, frameworkAdapter);
2369
2540
  const changedFiles = [];
2370
- mkdirSync(agentDir, { recursive: true });
2541
+ mkdirSync2(agentDir, { recursive: true });
2371
2542
  for (const artifact of artifacts) {
2372
- const filePath = join2(agentDir, artifact.relativePath);
2543
+ const filePath = join3(agentDir, artifact.relativePath);
2373
2544
  let existingHash;
2374
2545
  let newHash;
2375
2546
  let writeContent = artifact.content;
@@ -2381,8 +2552,8 @@ async function processAgent(agent, agentStates) {
2381
2552
  };
2382
2553
  newHash = sha256(stripDynamicSections(artifact.content));
2383
2554
  try {
2384
- const projectClaudeMd = join2(config.configDir, agent.code_name, "project", "CLAUDE.md");
2385
- const existing = readFileSync(projectClaudeMd, "utf-8");
2555
+ const projectClaudeMd = join3(config.configDir, agent.code_name, "project", "CLAUDE.md");
2556
+ const existing = readFileSync2(projectClaudeMd, "utf-8");
2386
2557
  existingHash = sha256(stripDynamicSections(existing));
2387
2558
  } catch {
2388
2559
  existingHash = null;
@@ -2400,7 +2571,7 @@ async function processAgent(agent, agentStates) {
2400
2571
  const generatorKeys = Object.keys(generatorServers);
2401
2572
  let existingRaw = "";
2402
2573
  try {
2403
- existingRaw = readFileSync(filePath, "utf-8");
2574
+ existingRaw = readFileSync2(filePath, "utf-8");
2404
2575
  } catch {
2405
2576
  }
2406
2577
  const existingServers = parseMcp(existingRaw);
@@ -2422,22 +2593,22 @@ async function processAgent(agent, agentStates) {
2422
2593
  }
2423
2594
  }
2424
2595
  if (changedFiles.length > 0) {
2425
- const isFirst = !existsSync(join2(agentDir, "CHARTER.md"));
2596
+ const isFirst = !existsSync2(join3(agentDir, "CHARTER.md"));
2426
2597
  const verb = isFirst ? "Provisioning" : "Updating";
2427
2598
  const fileNames = changedFiles.map((f) => f.relativePath).join(", ");
2428
2599
  log(`${verb} '${agent.code_name}': ${fileNames}`);
2429
2600
  for (const file of changedFiles) {
2430
- const filePath = join2(agentDir, file.relativePath);
2431
- mkdirSync(dirname(filePath), { recursive: true });
2432
- writeFileSync(filePath, file.content);
2601
+ const filePath = join3(agentDir, file.relativePath);
2602
+ mkdirSync2(dirname(filePath), { recursive: true });
2603
+ writeFileSync2(filePath, file.content);
2433
2604
  }
2434
2605
  try {
2435
- const provSkillsDir = join2(agentDir, ".claude", "skills");
2436
- if (existsSync(provSkillsDir)) {
2437
- for (const folder of readdirSync(provSkillsDir)) {
2606
+ const provSkillsDir = join3(agentDir, ".claude", "skills");
2607
+ if (existsSync2(provSkillsDir)) {
2608
+ for (const folder of readdirSync2(provSkillsDir)) {
2438
2609
  if (folder.startsWith("knowledge-")) {
2439
2610
  try {
2440
- rmSync(join2(provSkillsDir, folder), { recursive: true });
2611
+ rmSync2(join3(provSkillsDir, folder), { recursive: true });
2441
2612
  } catch {
2442
2613
  }
2443
2614
  }
@@ -2450,7 +2621,7 @@ async function processAgent(agent, agentStates) {
2450
2621
  const trackedFiles2 = frameworkAdapter.driftTrackedFiles();
2451
2622
  const hashes = /* @__PURE__ */ new Map();
2452
2623
  for (const file of trackedFiles2) {
2453
- const h = hashFile(join2(agentDir, file));
2624
+ const h = hashFile(join3(agentDir, file));
2454
2625
  if (h) hashes.set(file, h);
2455
2626
  }
2456
2627
  writtenHashes.set(agent.agent_id, hashes);
@@ -2494,10 +2665,10 @@ async function processAgent(agent, agentStates) {
2494
2665
  }
2495
2666
  let lastDriftCheckAt = now;
2496
2667
  const written = writtenHashes.get(agent.agent_id);
2497
- if (written && existsSync(agentDir)) {
2668
+ if (written && existsSync2(agentDir)) {
2498
2669
  const driftedFiles = [];
2499
2670
  for (const [file, expectedHash] of written) {
2500
- const localHash = hashFile(join2(agentDir, file));
2671
+ const localHash = hashFile(join3(agentDir, file));
2501
2672
  if (localHash && localHash !== expectedHash) {
2502
2673
  driftedFiles.push(file);
2503
2674
  }
@@ -2508,7 +2679,7 @@ async function processAgent(agent, agentStates) {
2508
2679
  try {
2509
2680
  const localHashes = {};
2510
2681
  for (const file of driftedFiles) {
2511
- localHashes[file] = hashFile(join2(agentDir, file));
2682
+ localHashes[file] = hashFile(join3(agentDir, file));
2512
2683
  }
2513
2684
  await api.post("/host/drift", {
2514
2685
  agent_id: agent.agent_id,
@@ -2591,9 +2762,9 @@ async function processAgent(agent, agentStates) {
2591
2762
  const entry = refreshData.channel_configs[channelId];
2592
2763
  if (!entry || entry.status !== "active" && entry.status !== "pending") continue;
2593
2764
  try {
2594
- const installedPath = join2(homedir2(), ".claude", "plugins", "installed_plugins.json");
2595
- if (existsSync(installedPath)) {
2596
- const installed = JSON.parse(readFileSync(installedPath, "utf-8"));
2765
+ const installedPath = join3(homedir3(), ".claude", "plugins", "installed_plugins.json");
2766
+ if (existsSync2(installedPath)) {
2767
+ const installed = JSON.parse(readFileSync2(installedPath, "utf-8"));
2597
2768
  const pluginKeys = Object.keys(installed.plugins ?? {});
2598
2769
  if (pluginKeys.some((k) => k.startsWith(`${pluginName}@`))) continue;
2599
2770
  }
@@ -2626,19 +2797,19 @@ async function processAgent(agent, agentStates) {
2626
2797
  if (agentSessionMode === "persistent" && (agentFrameworkCache.get(agent.code_name) ?? "openclaw") === "claude-code") {
2627
2798
  try {
2628
2799
  const agentProvisionDir = agentDir;
2629
- const projectDir = join2(homedir2(), ".augmented", agent.code_name, "project");
2630
- mkdirSync(agentProvisionDir, { recursive: true });
2631
- mkdirSync(projectDir, { recursive: true });
2632
- const provisionMcpPath = join2(agentProvisionDir, ".mcp.json");
2633
- const projectMcpPath = join2(projectDir, ".mcp.json");
2800
+ const projectDir = join3(homedir3(), ".augmented", agent.code_name, "project");
2801
+ mkdirSync2(agentProvisionDir, { recursive: true });
2802
+ mkdirSync2(projectDir, { recursive: true });
2803
+ const provisionMcpPath = join3(agentProvisionDir, ".mcp.json");
2804
+ const projectMcpPath = join3(projectDir, ".mcp.json");
2634
2805
  let mcpConfig = { mcpServers: {} };
2635
2806
  try {
2636
- mcpConfig = JSON.parse(readFileSync(provisionMcpPath, "utf-8"));
2807
+ mcpConfig = JSON.parse(readFileSync2(provisionMcpPath, "utf-8"));
2637
2808
  if (!mcpConfig.mcpServers) mcpConfig.mcpServers = {};
2638
2809
  } catch {
2639
2810
  }
2640
- const localDirectChatChannel = join2(homedir2(), ".augmented", "_mcp", "direct-chat-channel.js");
2641
- if (existsSync(localDirectChatChannel) && !mcpConfig.mcpServers["direct-chat"]) {
2811
+ const localDirectChatChannel = join3(homedir3(), ".augmented", "_mcp", "direct-chat-channel.js");
2812
+ if (existsSync2(localDirectChatChannel) && !mcpConfig.mcpServers["direct-chat"]) {
2642
2813
  mcpConfig.mcpServers["direct-chat"] = {
2643
2814
  command: "node",
2644
2815
  args: [localDirectChatChannel],
@@ -2649,14 +2820,14 @@ async function processAgent(agent, agentStates) {
2649
2820
  }
2650
2821
  };
2651
2822
  const serialized = JSON.stringify(mcpConfig, null, 2);
2652
- writeFileSync(provisionMcpPath, serialized);
2653
- writeFileSync(projectMcpPath, serialized);
2823
+ writeFileSync2(provisionMcpPath, serialized);
2824
+ writeFileSync2(projectMcpPath, serialized);
2654
2825
  log(`Channel credentials written for '${agent.code_name}/direct-chat'`);
2655
2826
  }
2656
- const staleChannelsPath = join2(projectDir, ".mcp-channels.json");
2657
- if (existsSync(staleChannelsPath)) {
2827
+ const staleChannelsPath = join3(projectDir, ".mcp-channels.json");
2828
+ if (existsSync2(staleChannelsPath)) {
2658
2829
  try {
2659
- rmSync(staleChannelsPath, { force: true });
2830
+ rmSync2(staleChannelsPath, { force: true });
2660
2831
  } catch {
2661
2832
  }
2662
2833
  }
@@ -2769,8 +2940,8 @@ async function processAgent(agent, agentStates) {
2769
2940
  const mcpPath = frameworkAdapter.getMcpPath(agent.code_name);
2770
2941
  if (mcpPath) {
2771
2942
  try {
2772
- const { readFileSync: readFileSync2 } = await import("fs");
2773
- const mcpConfig = JSON.parse(readFileSync2(mcpPath, "utf-8"));
2943
+ const { readFileSync: readFileSync3 } = await import("fs");
2944
+ const mcpConfig = JSON.parse(readFileSync3(mcpPath, "utf-8"));
2774
2945
  if (mcpConfig.mcpServers) {
2775
2946
  const managedPrefixes = [
2776
2947
  "composio_",
@@ -2862,8 +3033,8 @@ async function processAgent(agent, agentStates) {
2862
3033
  if (agent.status === "active") {
2863
3034
  if (frameworkAdapter.installPlugin) {
2864
3035
  try {
2865
- const pluginPath = join2(process.cwd(), "packages", "openclaw-plugin-augmented", "src", "index.ts");
2866
- if (existsSync(pluginPath)) {
3036
+ const pluginPath = join3(process.cwd(), "packages", "openclaw-plugin-augmented", "src", "index.ts");
3037
+ if (existsSync2(pluginPath)) {
2867
3038
  frameworkAdapter.installPlugin(agent.code_name, "augmented", pluginPath, {
2868
3039
  agtHost: requireHost(),
2869
3040
  agtApiKey: getApiKey() ?? void 0,
@@ -2924,25 +3095,25 @@ async function processAgent(agent, agentStates) {
2924
3095
  }
2925
3096
  }
2926
3097
  try {
2927
- const { readdirSync: readdirSync2, rmSync: rmSync2 } = await import("fs");
2928
- const { homedir: homedir3 } = await import("os");
3098
+ const { readdirSync: readdirSync3, rmSync: rmSync3 } = await import("fs");
3099
+ const { homedir: homedir4 } = await import("os");
2929
3100
  const frameworkId2 = frameworkAdapter.id;
2930
3101
  const candidateSkillDirs = [
2931
3102
  // Claude Code — framework runtime tree
2932
- join2(homedir3(), ".augmented", agent.code_name, "skills"),
3103
+ join3(homedir4(), ".augmented", agent.code_name, "skills"),
2933
3104
  // Claude Code — project tree
2934
- join2(homedir3(), ".augmented", agent.code_name, "project", ".claude", "skills"),
3105
+ join3(homedir4(), ".augmented", agent.code_name, "project", ".claude", "skills"),
2935
3106
  // OpenClaw — framework runtime tree
2936
- join2(homedir3(), `.openclaw-${agent.code_name}`, "skills"),
3107
+ join3(homedir4(), `.openclaw-${agent.code_name}`, "skills"),
2937
3108
  // Defensive: legacy provision-side path, not currently an
2938
3109
  // install target but cheap to sweep.
2939
- join2(agentDir, ".claude", "skills")
3110
+ join3(agentDir, ".claude", "skills")
2940
3111
  ];
2941
- const existingDirs = candidateSkillDirs.filter((d) => existsSync(d));
3112
+ const existingDirs = candidateSkillDirs.filter((d) => existsSync2(d));
2942
3113
  const discoveredEntries = /* @__PURE__ */ new Set();
2943
3114
  for (const dir of existingDirs) {
2944
3115
  try {
2945
- for (const entry of readdirSync2(dir)) {
3116
+ for (const entry of readdirSync3(dir)) {
2946
3117
  if (entry.startsWith("plugin-") || entry.startsWith("integration-")) {
2947
3118
  discoveredEntries.add(entry);
2948
3119
  }
@@ -2952,9 +3123,9 @@ async function processAgent(agent, agentStates) {
2952
3123
  }
2953
3124
  const removeSkillFolder = (entry, reason) => {
2954
3125
  for (const dir of existingDirs) {
2955
- const p = join2(dir, entry);
2956
- if (existsSync(p)) {
2957
- rmSync2(p, { recursive: true, force: true });
3126
+ const p = join3(dir, entry);
3127
+ if (existsSync2(p)) {
3128
+ rmSync3(p, { recursive: true, force: true });
2958
3129
  }
2959
3130
  }
2960
3131
  log(`Removed ${reason} '${entry}' for '${agent.code_name}' (framework=${frameworkId2})`);
@@ -3123,10 +3294,10 @@ async function processAgent(agent, agentStates) {
3123
3294
  lastWorkTriggerAt.set(agent.code_name, triggerTs);
3124
3295
  if (agentFw === "openclaw" && gatewayRunning && gatewayPort) {
3125
3296
  const homeDir = process.env["HOME"] ?? "/tmp";
3126
- const jobsPath = join2(homeDir, `.openclaw-${agent.code_name}`, "cron", "jobs.json");
3127
- if (existsSync(jobsPath)) {
3297
+ const jobsPath = join3(homeDir, `.openclaw-${agent.code_name}`, "cron", "jobs.json");
3298
+ if (existsSync2(jobsPath)) {
3128
3299
  try {
3129
- const jobsData = JSON.parse(readFileSync(jobsPath, "utf-8"));
3300
+ const jobsData = JSON.parse(readFileSync2(jobsPath, "utf-8"));
3130
3301
  const kanbanJob = (jobsData.jobs ?? []).find(
3131
3302
  (j) => typeof j.name === "string" && j.name.includes("kanban-work")
3132
3303
  );
@@ -3252,10 +3423,10 @@ In progress for ${age} minutes \u2014 auto-failed`).catch(() => {
3252
3423
  }
3253
3424
  }
3254
3425
  const trackedFiles = frameworkAdapter.driftTrackedFiles();
3255
- if (trackedFiles.length > 0 && existsSync(agentDir)) {
3426
+ if (trackedFiles.length > 0 && existsSync2(agentDir)) {
3256
3427
  const hashes = /* @__PURE__ */ new Map();
3257
3428
  for (const file of trackedFiles) {
3258
- const h = hashFile(join2(agentDir, file));
3429
+ const h = hashFile(join3(agentDir, file));
3259
3430
  if (h) hashes.set(file, h);
3260
3431
  }
3261
3432
  writtenHashes.set(agent.agent_id, hashes);
@@ -3289,19 +3460,19 @@ function cleanupStaleSessions(codeName) {
3289
3460
  lastCleanupAt.set(codeName, Date.now());
3290
3461
  const homeDir = process.env["HOME"] ?? "/tmp";
3291
3462
  for (const agentDir of ["main", codeName]) {
3292
- const sessionsDir = join2(homeDir, `.openclaw-${codeName}`, "agents", agentDir, "sessions");
3463
+ const sessionsDir = join3(homeDir, `.openclaw-${codeName}`, "agents", agentDir, "sessions");
3293
3464
  cleanupCronSessions(sessionsDir, CRON_SESSION_KEEP_COUNT);
3294
3465
  }
3295
- const cronRunsDir = join2(homeDir, `.openclaw-${codeName}`, "cron", "runs");
3466
+ const cronRunsDir = join3(homeDir, `.openclaw-${codeName}`, "cron", "runs");
3296
3467
  cleanupOldFiles(cronRunsDir, CRON_RUN_RETENTION_DAYS, ".jsonl");
3297
- const cronJobsPath = join2(homeDir, `.openclaw-${codeName}`, "cron", "jobs.json");
3468
+ const cronJobsPath = join3(homeDir, `.openclaw-${codeName}`, "cron", "jobs.json");
3298
3469
  clearStaleCronRunState(cronJobsPath);
3299
3470
  }
3300
3471
  function cleanupCronSessions(sessionsDir, keepCount) {
3301
- const indexPath = join2(sessionsDir, "sessions.json");
3302
- if (!existsSync(indexPath)) return;
3472
+ const indexPath = join3(sessionsDir, "sessions.json");
3473
+ if (!existsSync2(indexPath)) return;
3303
3474
  try {
3304
- const raw = readFileSync(indexPath, "utf-8");
3475
+ const raw = readFileSync2(indexPath, "utf-8");
3305
3476
  const index = JSON.parse(raw);
3306
3477
  const cronRunKeys = Object.keys(index).filter((k) => k.includes(":cron:") && k.includes(":run:")).map((k) => ({
3307
3478
  key: k,
@@ -3314,9 +3485,9 @@ function cleanupCronSessions(sessionsDir, keepCount) {
3314
3485
  for (const entry of toDelete) {
3315
3486
  delete index[entry.key];
3316
3487
  if (entry.sessionId) {
3317
- const sessionFile = join2(sessionsDir, `${entry.sessionId}.jsonl`);
3488
+ const sessionFile = join3(sessionsDir, `${entry.sessionId}.jsonl`);
3318
3489
  try {
3319
- if (existsSync(sessionFile)) {
3490
+ if (existsSync2(sessionFile)) {
3320
3491
  unlinkSync(sessionFile);
3321
3492
  deletedFiles++;
3322
3493
  }
@@ -3336,8 +3507,8 @@ function cleanupCronSessions(sessionsDir, keepCount) {
3336
3507
  delete index[parentKey];
3337
3508
  if (parentSessionId) {
3338
3509
  try {
3339
- const f = join2(sessionsDir, `${parentSessionId}.jsonl`);
3340
- if (existsSync(f)) {
3510
+ const f = join3(sessionsDir, `${parentSessionId}.jsonl`);
3511
+ if (existsSync2(f)) {
3341
3512
  unlinkSync(f);
3342
3513
  deletedFiles++;
3343
3514
  }
@@ -3346,7 +3517,7 @@ function cleanupCronSessions(sessionsDir, keepCount) {
3346
3517
  }
3347
3518
  }
3348
3519
  }
3349
- writeFileSync(indexPath, JSON.stringify(index));
3520
+ writeFileSync2(indexPath, JSON.stringify(index));
3350
3521
  if (toDelete.length > 0) {
3351
3522
  log(`Cleaned ${toDelete.length} cron session(s) and ${deletedFiles} file(s) from ${sessionsDir}`);
3352
3523
  }
@@ -3355,9 +3526,9 @@ function cleanupCronSessions(sessionsDir, keepCount) {
3355
3526
  }
3356
3527
  var STALE_RUN_TIMEOUT_MS = 5 * 6e4;
3357
3528
  function clearStaleCronRunState(jobsPath) {
3358
- if (!existsSync(jobsPath)) return;
3529
+ if (!existsSync2(jobsPath)) return;
3359
3530
  try {
3360
- const raw = readFileSync(jobsPath, "utf-8");
3531
+ const raw = readFileSync2(jobsPath, "utf-8");
3361
3532
  const data = JSON.parse(raw);
3362
3533
  const jobs = data.jobs ?? data;
3363
3534
  if (!Array.isArray(jobs)) return;
@@ -3382,19 +3553,19 @@ function clearStaleCronRunState(jobsPath) {
3382
3553
  }
3383
3554
  }
3384
3555
  if (changed) {
3385
- writeFileSync(jobsPath, JSON.stringify(data, null, 2));
3556
+ writeFileSync2(jobsPath, JSON.stringify(data, null, 2));
3386
3557
  }
3387
3558
  } catch {
3388
3559
  }
3389
3560
  }
3390
3561
  function cleanupOldFiles(dir, maxAgeDays, ext) {
3391
- if (!existsSync(dir)) return;
3562
+ if (!existsSync2(dir)) return;
3392
3563
  const cutoff = Date.now() - maxAgeDays * 24 * 60 * 60 * 1e3;
3393
3564
  let removed = 0;
3394
3565
  try {
3395
- for (const f of readdirSync(dir)) {
3566
+ for (const f of readdirSync2(dir)) {
3396
3567
  if (!f.endsWith(ext)) continue;
3397
- const fullPath = join2(dir, f);
3568
+ const fullPath = join3(dir, f);
3398
3569
  try {
3399
3570
  const st = statSync(fullPath);
3400
3571
  if (st.mtimeMs < cutoff) {
@@ -3521,18 +3692,18 @@ async function finishRun(runId, outcome, options = {}) {
3521
3692
  }
3522
3693
  async function executeAndProcessClaudeTask(codeName, agentId, task, prompt) {
3523
3694
  const projectDir = getProjectDir(codeName);
3524
- const mcpConfigPath = join2(projectDir, ".mcp.json");
3695
+ const mcpConfigPath = join3(projectDir, ".mcp.json");
3525
3696
  let runId = null;
3526
3697
  let kanbanItemId = null;
3527
3698
  let taskResult;
3528
3699
  sanitizeMcpJson(mcpConfigPath, requireHost());
3529
3700
  prompt = wrapScheduledTaskPrompt(prompt);
3530
3701
  try {
3531
- const claudeMdPath = join2(projectDir, "CLAUDE.md");
3702
+ const claudeMdPath = join3(projectDir, "CLAUDE.md");
3532
3703
  const serverNames = [];
3533
- if (existsSync(mcpConfigPath)) {
3704
+ if (existsSync2(mcpConfigPath)) {
3534
3705
  try {
3535
- const d = JSON.parse(readFileSync(mcpConfigPath, "utf-8"));
3706
+ const d = JSON.parse(readFileSync2(mcpConfigPath, "utf-8"));
3536
3707
  if (d.mcpServers) serverNames.push(...Object.keys(d.mcpServers));
3537
3708
  } catch {
3538
3709
  }
@@ -3550,14 +3721,14 @@ async function executeAndProcessClaudeTask(codeName, agentId, task, prompt) {
3550
3721
  "--allowedTools",
3551
3722
  allowedTools
3552
3723
  ];
3553
- if (existsSync(claudeMdPath)) {
3724
+ if (existsSync2(claudeMdPath)) {
3554
3725
  claudeArgs.push("--system-prompt-file", claudeMdPath);
3555
3726
  }
3556
3727
  const childEnv = { ...process.env };
3557
- const envIntPath = join2(projectDir, ".env.integrations");
3558
- if (existsSync(envIntPath)) {
3728
+ const envIntPath = join3(projectDir, ".env.integrations");
3729
+ if (existsSync2(envIntPath)) {
3559
3730
  try {
3560
- for (const line of readFileSync(envIntPath, "utf-8").split("\n")) {
3731
+ for (const line of readFileSync2(envIntPath, "utf-8").split("\n")) {
3561
3732
  if (!line || line.startsWith("#") || !line.includes("=")) continue;
3562
3733
  const eqIdx = line.indexOf("=");
3563
3734
  childEnv[line.slice(0, eqIdx)] = line.slice(eqIdx + 1);
@@ -3739,8 +3910,8 @@ var claudeAuthTupleBySession = /* @__PURE__ */ new Map();
3739
3910
  async function ensurePersistentSession(agent, tasks, boardItems, refreshData) {
3740
3911
  const codeName = agent.code_name;
3741
3912
  const projectDir = getProjectDir2(codeName);
3742
- const mcpConfigPath = join2(projectDir, ".mcp.json");
3743
- const claudeMdPath = join2(projectDir, "CLAUDE.md");
3913
+ const mcpConfigPath = join3(projectDir, ".mcp.json");
3914
+ const claudeMdPath = join3(projectDir, "CLAUDE.md");
3744
3915
  const channelConfigs = refreshData.channel_configs;
3745
3916
  const channels = [];
3746
3917
  const devChannels = [];
@@ -4188,11 +4359,11 @@ async function processDirectChatMessage(agent, msg) {
4188
4359
  if (fw === "claude-code") {
4189
4360
  const { getProjectDir: ccProjectDir } = await import("../claude-scheduler-CLSMSF5W.js");
4190
4361
  const projDir = ccProjectDir(agent.codeName);
4191
- const mcpConfigPath = join2(projDir, ".mcp.json");
4362
+ const mcpConfigPath = join3(projDir, ".mcp.json");
4192
4363
  const serverNames = [];
4193
- if (existsSync(mcpConfigPath)) {
4364
+ if (existsSync2(mcpConfigPath)) {
4194
4365
  try {
4195
- const d = JSON.parse(readFileSync(mcpConfigPath, "utf-8"));
4366
+ const d = JSON.parse(readFileSync2(mcpConfigPath, "utf-8"));
4196
4367
  if (d.mcpServers) serverNames.push(...Object.keys(d.mcpServers));
4197
4368
  } catch {
4198
4369
  }
@@ -4209,15 +4380,15 @@ async function processDirectChatMessage(agent, msg) {
4209
4380
  "--allowedTools",
4210
4381
  allowedTools
4211
4382
  ];
4212
- const chatClaudeMd = join2(projDir, "CLAUDE.md");
4213
- if (existsSync(chatClaudeMd)) {
4383
+ const chatClaudeMd = join3(projDir, "CLAUDE.md");
4384
+ if (existsSync2(chatClaudeMd)) {
4214
4385
  chatArgs.push("--system-prompt-file", chatClaudeMd);
4215
4386
  }
4216
- const envIntPath = join2(projDir, ".env.integrations");
4387
+ const envIntPath = join3(projDir, ".env.integrations");
4217
4388
  const childEnv = { ...process.env };
4218
- if (existsSync(envIntPath)) {
4389
+ if (existsSync2(envIntPath)) {
4219
4390
  try {
4220
- for (const line of readFileSync(envIntPath, "utf-8").split("\n")) {
4391
+ for (const line of readFileSync2(envIntPath, "utf-8").split("\n")) {
4221
4392
  if (!line || line.startsWith("#") || !line.includes("=")) continue;
4222
4393
  const eqIdx = line.indexOf("=");
4223
4394
  childEnv[line.slice(0, eqIdx)] = line.slice(eqIdx + 1);
@@ -4498,12 +4669,12 @@ function getBuiltInSkillContent(skillId) {
4498
4669
  if (builtInSkillCache.has(skillId)) return builtInSkillCache.get(skillId);
4499
4670
  try {
4500
4671
  const candidates = [
4501
- join2(process.cwd(), "skills", skillId, "SKILL.md"),
4502
- join2(new URL(".", import.meta.url).pathname, "..", "..", "..", "..", "skills", skillId, "SKILL.md")
4672
+ join3(process.cwd(), "skills", skillId, "SKILL.md"),
4673
+ join3(new URL(".", import.meta.url).pathname, "..", "..", "..", "..", "skills", skillId, "SKILL.md")
4503
4674
  ];
4504
4675
  for (const candidate of candidates) {
4505
- if (existsSync(candidate)) {
4506
- const content = readFileSync(candidate, "utf-8");
4676
+ if (existsSync2(candidate)) {
4677
+ const content = readFileSync2(candidate, "utf-8");
4507
4678
  const files = [{ relativePath: "SKILL.md", content }];
4508
4679
  builtInSkillCache.set(skillId, files);
4509
4680
  return files;
@@ -5245,16 +5416,16 @@ function parseMemoryFile(raw, fallbackName) {
5245
5416
  };
5246
5417
  }
5247
5418
  async function syncMemories(agent, configDir, log2) {
5248
- const projectDir = join2(configDir, agent.code_name, "project");
5249
- const memoryDir = join2(projectDir, "memory");
5250
- if (existsSync(memoryDir)) {
5419
+ const projectDir = join3(configDir, agent.code_name, "project");
5420
+ const memoryDir = join3(projectDir, "memory");
5421
+ if (existsSync2(memoryDir)) {
5251
5422
  const prevHashes = memoryFileHashes.get(agent.agent_id) ?? /* @__PURE__ */ new Map();
5252
5423
  const currentHashes = /* @__PURE__ */ new Map();
5253
5424
  const changedMemories = [];
5254
- for (const file of readdirSync(memoryDir)) {
5425
+ for (const file of readdirSync2(memoryDir)) {
5255
5426
  if (!file.endsWith(".md")) continue;
5256
5427
  try {
5257
- const raw = readFileSync(join2(memoryDir, file), "utf-8");
5428
+ const raw = readFileSync2(join3(memoryDir, file), "utf-8");
5258
5429
  const fileHash = createHash("sha256").update(raw).digest("hex").slice(0, 16);
5259
5430
  currentHashes.set(file, fileHash);
5260
5431
  if (prevHashes.get(file) === fileHash) continue;
@@ -5279,7 +5450,7 @@ async function syncMemories(agent, configDir, log2) {
5279
5450
  } catch (err) {
5280
5451
  for (const mem of changedMemories) {
5281
5452
  for (const [file] of currentHashes) {
5282
- const parsed = parseMemoryFile(readFileSync(join2(memoryDir, file), "utf-8"), file.replace(/\.md$/, ""));
5453
+ const parsed = parseMemoryFile(readFileSync2(join3(memoryDir, file), "utf-8"), file.replace(/\.md$/, ""));
5283
5454
  if (parsed?.name === mem.name) currentHashes.delete(file);
5284
5455
  }
5285
5456
  }
@@ -5287,7 +5458,7 @@ async function syncMemories(agent, configDir, log2) {
5287
5458
  }
5288
5459
  }
5289
5460
  }
5290
- const localFiles = existsSync(memoryDir) ? readdirSync(memoryDir).filter((f) => f.endsWith(".md")).sort() : [];
5461
+ const localFiles = existsSync2(memoryDir) ? readdirSync2(memoryDir).filter((f) => f.endsWith(".md")).sort() : [];
5291
5462
  const localListHash = createHash("sha256").update(localFiles.join(",")).digest("hex").slice(0, 16);
5292
5463
  const prevLocalHash = lastLocalFileHash.get(agent.agent_id);
5293
5464
  const prevDownload = lastDownloadHash.get(agent.agent_id);
@@ -5302,7 +5473,7 @@ async function syncMemories(agent, configDir, log2) {
5302
5473
  lastDownloadHash.set(agent.agent_id, responseHash);
5303
5474
  lastLocalFileHash.set(agent.agent_id, localListHash);
5304
5475
  if (dbMemories.memories?.length) {
5305
- mkdirSync(memoryDir, { recursive: true });
5476
+ mkdirSync2(memoryDir, { recursive: true });
5306
5477
  const existingFileSet = new Set(localFiles.map((f) => f.replace(/\.md$/, "").toLowerCase()));
5307
5478
  let written = 0;
5308
5479
  for (const mem of dbMemories.memories) {
@@ -5317,11 +5488,11 @@ description: ${JSON.stringify(mem.content.slice(0, 200))}
5317
5488
 
5318
5489
  ${mem.content}
5319
5490
  `;
5320
- writeFileSync(join2(memoryDir, `${slug}.md`), fileContent);
5491
+ writeFileSync2(join3(memoryDir, `${slug}.md`), fileContent);
5321
5492
  written++;
5322
5493
  }
5323
5494
  if (written > 0) {
5324
- const updatedFiles = readdirSync(memoryDir).filter((f) => f.endsWith(".md")).sort();
5495
+ const updatedFiles = readdirSync2(memoryDir).filter((f) => f.endsWith(".md")).sort();
5325
5496
  lastLocalFileHash.set(agent.agent_id, createHash("sha256").update(updatedFiles.join(",")).digest("hex").slice(0, 16));
5326
5497
  log2(`Exported ${written} DB memories to local files for '${agent.code_name}'`);
5327
5498
  }
@@ -5331,9 +5502,9 @@ ${mem.content}
5331
5502
  }
5332
5503
  }
5333
5504
  async function cleanupAgentFiles(codeName, agentDir) {
5334
- if (existsSync(agentDir)) {
5505
+ if (existsSync2(agentDir)) {
5335
5506
  try {
5336
- rmSync(agentDir, { recursive: true, force: true });
5507
+ rmSync2(agentDir, { recursive: true, force: true });
5337
5508
  log(`Removed provision directory for '${codeName}'`);
5338
5509
  } catch (err) {
5339
5510
  log(`Failed to remove provision dir for '${codeName}': ${err.message}`);
@@ -5556,14 +5727,14 @@ function restartRunningChannelMcps(basenames) {
5556
5727
  }
5557
5728
  }
5558
5729
  function deployMcpAssets() {
5559
- const targetDir = join2(homedir2(), ".augmented", "_mcp");
5560
- mkdirSync(targetDir, { recursive: true });
5730
+ const targetDir = join3(homedir3(), ".augmented", "_mcp");
5731
+ mkdirSync2(targetDir, { recursive: true });
5561
5732
  const moduleDir = dirname(fileURLToPath(import.meta.url));
5562
5733
  let mcpSourceDir = "";
5563
5734
  let dir = moduleDir;
5564
5735
  for (let i = 0; i < 6; i++) {
5565
- const candidate = join2(dir, "mcp");
5566
- if (existsSync(join2(candidate, "index.js"))) {
5736
+ const candidate = join3(dir, "mcp");
5737
+ if (existsSync2(join3(candidate, "index.js"))) {
5567
5738
  mcpSourceDir = candidate;
5568
5739
  break;
5569
5740
  }
@@ -5578,8 +5749,8 @@ function deployMcpAssets() {
5578
5749
  const changedBasenames = [];
5579
5750
  const fileHash = (p) => {
5580
5751
  try {
5581
- if (!existsSync(p)) return null;
5582
- return createHash("sha256").update(readFileSync(p)).digest("hex");
5752
+ if (!existsSync2(p)) return null;
5753
+ return createHash("sha256").update(readFileSync2(p)).digest("hex");
5583
5754
  } catch {
5584
5755
  return null;
5585
5756
  }
@@ -5590,9 +5761,9 @@ function deployMcpAssets() {
5590
5761
  "telegram-channel.js"
5591
5762
  ]);
5592
5763
  for (const file of ["index.js", "slack-channel.js", "direct-chat-channel.js", "telegram-channel.js"]) {
5593
- const src = join2(mcpSourceDir, file);
5594
- const dst = join2(targetDir, file);
5595
- if (!existsSync(src)) continue;
5764
+ const src = join3(mcpSourceDir, file);
5765
+ const dst = join3(targetDir, file);
5766
+ if (!existsSync2(src)) continue;
5596
5767
  const before = fileHash(dst);
5597
5768
  try {
5598
5769
  copyFileSync(src, dst);
@@ -5609,23 +5780,23 @@ function deployMcpAssets() {
5609
5780
  log(`[manager] Bundle(s) updated: ${changedBasenames.join(", ")} \u2014 signalling running instances to restart`);
5610
5781
  restartRunningChannelMcps(changedBasenames);
5611
5782
  }
5612
- const localMcpPath = join2(targetDir, "index.js");
5783
+ const localMcpPath = join3(targetDir, "index.js");
5613
5784
  try {
5614
- const agentsDir = join2(homedir2(), ".augmented", "agents");
5615
- if (existsSync(agentsDir)) {
5616
- for (const entry of readdirSync(agentsDir, { withFileTypes: true })) {
5785
+ const agentsDir = join3(homedir3(), ".augmented", "agents");
5786
+ if (existsSync2(agentsDir)) {
5787
+ for (const entry of readdirSync2(agentsDir, { withFileTypes: true })) {
5617
5788
  if (!entry.isDirectory()) continue;
5618
5789
  for (const subdir of ["provision", "project"]) {
5619
- const mcpJsonPath = join2(agentsDir, entry.name, subdir, ".mcp.json");
5790
+ const mcpJsonPath = join3(agentsDir, entry.name, subdir, ".mcp.json");
5620
5791
  try {
5621
- const raw = readFileSync(mcpJsonPath, "utf-8");
5792
+ const raw = readFileSync2(mcpJsonPath, "utf-8");
5622
5793
  if (!raw.includes("@integrity-labs/augmented-mcp")) continue;
5623
5794
  const mcpConfig = JSON.parse(raw);
5624
5795
  const augServer = mcpConfig.mcpServers?.["augmented"];
5625
5796
  if (!augServer) continue;
5626
5797
  augServer.command = "node";
5627
5798
  augServer.args = [localMcpPath];
5628
- writeFileSync(mcpJsonPath, JSON.stringify(mcpConfig, null, 2));
5799
+ writeFileSync2(mcpJsonPath, JSON.stringify(mcpConfig, null, 2));
5629
5800
  log(`[manager] Patched ${entry.name}/${subdir}/.mcp.json: npx \u2192 node`);
5630
5801
  } catch {
5631
5802
  }