@integrity-labs/agt-cli 0.23.2 → 0.24.2

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.
@@ -12,7 +12,7 @@ import {
12
12
  provisionOrientHook,
13
13
  provisionStopHook,
14
14
  requireHost
15
- } from "../chunk-WUYKMPYW.js";
15
+ } from "../chunk-BXLWLI2U.js";
16
16
  import {
17
17
  findTaskByTemplate,
18
18
  getProjectDir as getProjectDir2,
@@ -43,11 +43,12 @@ import {
43
43
  resolveClaudeBinary,
44
44
  sanitizeMcpJson,
45
45
  sendToAgent,
46
+ sessionTranscriptDir,
46
47
  startPersistentSession,
47
48
  stopAllSessionsAndWait,
48
49
  stopPersistentSession,
49
50
  takeZombieDetection
50
- } from "../chunk-ZKQGDH3T.js";
51
+ } from "../chunk-PNTLQKLO.js";
51
52
  import {
52
53
  KANBAN_CHECK_COMMAND,
53
54
  appendDmFooter,
@@ -55,23 +56,25 @@ import {
55
56
  extractFrontmatter,
56
57
  formatActorId,
57
58
  getFramework,
59
+ isEmptyTotals,
58
60
  isParseError,
59
61
  isResolveError,
60
62
  isSelfCompletion,
61
63
  parseDeliveryTarget,
64
+ parseTranscriptUsage,
62
65
  parseUsageBanner,
63
66
  resolveChannels,
64
67
  resolveDmTarget,
65
68
  wrapScheduledTaskPrompt
66
- } from "../chunk-HSIESZMZ.js";
69
+ } from "../chunk-ECDTRQLA.js";
67
70
 
68
71
  // src/lib/manager-worker.ts
69
72
  import { createHash as createHash2 } from "crypto";
70
- import { readFileSync as readFileSync3, writeFileSync as writeFileSync3, appendFileSync, mkdirSync as mkdirSync2, chmodSync, existsSync as existsSync3, rmSync as rmSync2, readdirSync as readdirSync2, statSync, unlinkSync, copyFileSync } from "fs";
73
+ import { readFileSync as readFileSync5, writeFileSync as writeFileSync3, appendFileSync, mkdirSync as mkdirSync2, chmodSync, existsSync as existsSync4, rmSync as rmSync2, readdirSync as readdirSync3, statSync as statSync2, unlinkSync, copyFileSync } from "fs";
71
74
  import https from "https";
72
75
  import { execFileSync as syncExecFile } from "child_process";
73
- import { join as join4, dirname } from "path";
74
- import { homedir as homedir3 } from "os";
76
+ import { join as join6, dirname } from "path";
77
+ import { homedir as homedir4 } from "os";
75
78
  import { fileURLToPath } from "url";
76
79
 
77
80
  // src/lib/mcp-config-drift.ts
@@ -435,12 +438,12 @@ function reapMissingMcpSessions(args) {
435
438
  if (!missingRaw.includes(key)) liveKeys.add(key);
436
439
  }
437
440
  for (const key of liveKeys) {
438
- const state3 = presenceReaperState.get(stateKey(codeName, key));
439
- if (state3) {
440
- state3.attempts = 0;
441
- state3.lastSeenLiveAt = now();
442
- state3.lastAttemptedSessionStartedAt = null;
443
- state3.gaveUpLogged = false;
441
+ const state5 = presenceReaperState.get(stateKey(codeName, key));
442
+ if (state5) {
443
+ state5.attempts = 0;
444
+ state5.lastSeenLiveAt = now();
445
+ state5.lastAttemptedSessionStartedAt = null;
446
+ state5.gaveUpLogged = false;
444
447
  }
445
448
  }
446
449
  if (missing.length === 0) {
@@ -455,24 +458,24 @@ function reapMissingMcpSessions(args) {
455
458
  const active = [];
456
459
  for (const key of missing) {
457
460
  const sk = stateKey(codeName, key);
458
- const state3 = presenceReaperState.get(sk) ?? {
461
+ const state5 = presenceReaperState.get(sk) ?? {
459
462
  attempts: 0,
460
463
  lastSeenLiveAt: null,
461
464
  lastAttemptedSessionStartedAt: null,
462
465
  gaveUpLogged: false
463
466
  };
464
- if (state3.lastAttemptedSessionStartedAt !== sessionStartedAt) {
465
- state3.attempts += 1;
466
- state3.lastAttemptedSessionStartedAt = sessionStartedAt;
467
+ if (state5.lastAttemptedSessionStartedAt !== sessionStartedAt) {
468
+ state5.attempts += 1;
469
+ state5.lastAttemptedSessionStartedAt = sessionStartedAt;
467
470
  }
468
- presenceReaperState.set(sk, state3);
469
- if (state3.attempts > MAX_PRESENCE_RESTART_ATTEMPTS) {
471
+ presenceReaperState.set(sk, state5);
472
+ if (state5.attempts > MAX_PRESENCE_RESTART_ATTEMPTS) {
470
473
  givenUp.push(key);
471
- if (!state3.gaveUpLogged) {
474
+ if (!state5.gaveUpLogged) {
472
475
  log2(
473
476
  `[mcp-presence-reaper] giving up on '${codeName}:${key}' after ${MAX_PRESENCE_RESTART_ATTEMPTS} consecutive failed restarts \u2014 declared but never recovers (likely orphaned config; see ENG-5279)`
474
477
  );
475
- state3.gaveUpLogged = true;
478
+ state5.gaveUpLogged = true;
476
479
  if (onGiveUp) {
477
480
  try {
478
481
  onGiveUp(codeName, key);
@@ -710,6 +713,175 @@ async function maybeReportUsageBanner(args) {
710
713
  }
711
714
  }
712
715
 
716
+ // src/lib/token-usage-monitor.ts
717
+ import { readdirSync, readFileSync, statSync } from "fs";
718
+ import { join } from "path";
719
+ var MIN_CHECK_INTERVAL_MS2 = 6e4;
720
+ var TRANSCRIPT_MTIME_WINDOW_MS = 2 * 24 * 60 * 60 * 1e3;
721
+ var MAX_ENTRIES_PER_POST = 200;
722
+ var state2 = /* @__PURE__ */ new Map();
723
+ async function maybeReportTokenUsage(args) {
724
+ const { api: api2, codeName, agentId, log: log2 } = args;
725
+ const now = args.now ?? /* @__PURE__ */ new Date();
726
+ const nowMs = now.getTime();
727
+ const existing = state2.get(codeName);
728
+ if (existing && nowMs - existing.lastCheckedAt < MIN_CHECK_INTERVAL_MS2) {
729
+ return;
730
+ }
731
+ const dir = args.transcriptDir ?? sessionTranscriptDir(getProjectDir(codeName));
732
+ const files = existing?.files ?? /* @__PURE__ */ new Map();
733
+ const next = { files, lastCheckedAt: nowMs };
734
+ let dirEntries;
735
+ try {
736
+ dirEntries = readdirSync(dir);
737
+ } catch {
738
+ state2.set(codeName, next);
739
+ return;
740
+ }
741
+ const pending = [];
742
+ for (const name of dirEntries) {
743
+ if (!name.endsWith(".jsonl")) continue;
744
+ const sessionId = name.slice(0, -".jsonl".length);
745
+ if (!sessionId) continue;
746
+ const path = join(dir, name);
747
+ let st;
748
+ try {
749
+ st = statSync(path);
750
+ } catch {
751
+ continue;
752
+ }
753
+ if (!st.isFile()) continue;
754
+ if (nowMs - st.mtimeMs > TRANSCRIPT_MTIME_WINDOW_MS) continue;
755
+ const fp = { mtimeMs: st.mtimeMs, size: st.size };
756
+ const seen = files.get(sessionId);
757
+ if (seen && seen.mtimeMs === fp.mtimeMs && seen.size === fp.size) {
758
+ continue;
759
+ }
760
+ let content;
761
+ try {
762
+ content = readFileSync(path, "utf-8");
763
+ } catch (err) {
764
+ log2(`[token-usage] read failed for '${codeName}/${name}': ${err.message}`);
765
+ continue;
766
+ }
767
+ const parsed = parseTranscriptUsage(content);
768
+ for (const [model, totals] of parsed.byModel) {
769
+ if (isEmptyTotals(totals)) continue;
770
+ pending.push({
771
+ sessionId,
772
+ fp,
773
+ entry: {
774
+ session_id: sessionId,
775
+ model,
776
+ input_tokens: totals.inputTokens,
777
+ output_tokens: totals.outputTokens,
778
+ cache_creation_tokens: totals.cacheCreationTokens,
779
+ cache_read_tokens: totals.cacheReadTokens,
780
+ session_started_at: parsed.sessionStartedAt,
781
+ last_observed_at: parsed.lastObservedAt
782
+ }
783
+ });
784
+ }
785
+ if (![...parsed.byModel.values()].some((t) => !isEmptyTotals(t))) {
786
+ files.set(sessionId, fp);
787
+ }
788
+ }
789
+ if (pending.length === 0) {
790
+ state2.set(codeName, next);
791
+ return;
792
+ }
793
+ for (let i = 0; i < pending.length; i += MAX_ENTRIES_PER_POST) {
794
+ const batch = pending.slice(i, i + MAX_ENTRIES_PER_POST);
795
+ try {
796
+ await api2.post("/host/token-usage", {
797
+ agent_id: agentId,
798
+ framework: "claude-code",
799
+ source: "transcript_jsonl",
800
+ entries: batch.map((b) => b.entry)
801
+ });
802
+ for (const b of batch) {
803
+ files.set(b.sessionId, b.fp);
804
+ }
805
+ } catch (err) {
806
+ log2(`[token-usage] POST failed for '${codeName}': ${err.message}`);
807
+ }
808
+ }
809
+ state2.set(codeName, next);
810
+ }
811
+
812
+ // src/lib/activity-cache-monitor.ts
813
+ import { existsSync, readFileSync as readFileSync2 } from "fs";
814
+ import { homedir } from "os";
815
+ import { join as join2 } from "path";
816
+ var MIN_CHECK_INTERVAL_MS3 = 6e4;
817
+ var STATS_CACHE_PATH = join2(homedir(), ".claude", "stats-cache.json");
818
+ var ISO_DATE_RE = /^\d{4}-\d{2}-\d{2}$/;
819
+ var state3 = { lastObservedDate: null, lastCheckedAt: 0 };
820
+ function selectNewDailyRows(raw, lastObservedDate) {
821
+ let parsed;
822
+ try {
823
+ parsed = JSON.parse(raw);
824
+ } catch {
825
+ return [];
826
+ }
827
+ const days = Array.isArray(parsed.dailyActivity) ? parsed.dailyActivity : [];
828
+ const nonNegInt = (v) => {
829
+ if (typeof v !== "number" || !Number.isFinite(v)) return null;
830
+ const n = Math.trunc(v);
831
+ return n >= 0 ? n : null;
832
+ };
833
+ const result = [];
834
+ for (const d of days) {
835
+ if (typeof d.date !== "string" || !ISO_DATE_RE.test(d.date)) continue;
836
+ if (lastObservedDate !== null && d.date <= lastObservedDate) continue;
837
+ const m = nonNegInt(d.messageCount);
838
+ const s = nonNegInt(d.sessionCount);
839
+ const t = nonNegInt(d.toolCallCount);
840
+ if (m === null || s === null || t === null) continue;
841
+ const breakdownForDay = parsed.dailyModelTokens?.[d.date];
842
+ const model_breakdown = breakdownForDay && typeof breakdownForDay === "object" && !Array.isArray(breakdownForDay) ? breakdownForDay : null;
843
+ result.push({
844
+ date: d.date,
845
+ message_count: m,
846
+ session_count: s,
847
+ tool_call_count: t,
848
+ model_breakdown
849
+ });
850
+ }
851
+ result.sort((a, b) => a.date.localeCompare(b.date));
852
+ return result;
853
+ }
854
+ async function maybeReportActivityCache(args) {
855
+ const { api: api2, log: log2 } = args;
856
+ const now = args.now ?? /* @__PURE__ */ new Date();
857
+ const nowMs = now.getTime();
858
+ if (nowMs - state3.lastCheckedAt < MIN_CHECK_INTERVAL_MS3) return;
859
+ state3.lastCheckedAt = nowMs;
860
+ if (!existsSync(STATS_CACHE_PATH)) {
861
+ return;
862
+ }
863
+ let raw;
864
+ try {
865
+ raw = readFileSync2(STATS_CACHE_PATH, "utf-8");
866
+ } catch (err) {
867
+ log2(`[activity-cache] readFileSync failed: ${err.message}`);
868
+ return;
869
+ }
870
+ const rows = selectNewDailyRows(raw, state3.lastObservedDate);
871
+ if (rows.length === 0) return;
872
+ for (const row of rows) {
873
+ try {
874
+ await api2.post("/host/activity-observations", row);
875
+ state3.lastObservedDate = row.date;
876
+ } catch (err) {
877
+ log2(
878
+ `[activity-cache] POST /host/activity-observations failed for date=${row.date}: ${err.message}`
879
+ );
880
+ return;
881
+ }
882
+ }
883
+ }
884
+
713
885
  // src/lib/poll-backoff.ts
714
886
  var POLL_BACKOFF_BASE_MS = 1e3;
715
887
  var POLL_BACKOFF_MAX_MS = 6e4;
@@ -1139,8 +1311,8 @@ var GatewayClientPool = class extends EventEmitter {
1139
1311
 
1140
1312
  // src/lib/claude-auth-detect.ts
1141
1313
  import { readFile, readdir } from "fs/promises";
1142
- import { homedir, platform } from "os";
1143
- import { join } from "path";
1314
+ import { homedir as homedir2, platform } from "os";
1315
+ import { join as join3 } from "path";
1144
1316
  import { execFile } from "child_process";
1145
1317
  import { promisify } from "util";
1146
1318
  var execFileAsync = promisify(execFile);
@@ -1155,8 +1327,8 @@ async function detectClaudeAuth() {
1155
1327
  }
1156
1328
  async function findClaudeCredentialsPaths() {
1157
1329
  const candidates = [
1158
- join(homedir(), ".claude", ".credentials.json"),
1159
- join(homedir(), ".claude", "credentials.json")
1330
+ join3(homedir2(), ".claude", ".credentials.json"),
1331
+ join3(homedir2(), ".claude", "credentials.json")
1160
1332
  ];
1161
1333
  const isLinuxRoot = platform() === "linux" && typeof process.getuid === "function" && process.getuid() === 0;
1162
1334
  if (isLinuxRoot) {
@@ -1164,8 +1336,8 @@ async function findClaudeCredentialsPaths() {
1164
1336
  const entries = await readdir("/home", { withFileTypes: true });
1165
1337
  for (const entry of entries) {
1166
1338
  if (!entry.isDirectory()) continue;
1167
- candidates.push(join("/home", entry.name, ".claude", ".credentials.json"));
1168
- candidates.push(join("/home", entry.name, ".claude", "credentials.json"));
1339
+ candidates.push(join3("/home", entry.name, ".claude", ".credentials.json"));
1340
+ candidates.push(join3("/home", entry.name, ".claude", "credentials.json"));
1169
1341
  }
1170
1342
  } catch {
1171
1343
  }
@@ -1257,18 +1429,18 @@ function normalize(value) {
1257
1429
  }
1258
1430
 
1259
1431
  // src/lib/channel-hash-cache.ts
1260
- import { existsSync, readFileSync, writeFileSync } from "fs";
1261
- import { join as join2 } from "path";
1432
+ import { existsSync as existsSync2, readFileSync as readFileSync3, writeFileSync } from "fs";
1433
+ import { join as join4 } from "path";
1262
1434
  var CACHE_FILENAME = "channel-hash-cache.json";
1263
1435
  function getChannelHashCacheFile(configDir) {
1264
- return join2(configDir, CACHE_FILENAME);
1436
+ return join4(configDir, CACHE_FILENAME);
1265
1437
  }
1266
1438
  function loadChannelHashCache(target, configDir) {
1267
1439
  const path = getChannelHashCacheFile(configDir);
1268
- if (!existsSync(path)) return;
1440
+ if (!existsSync2(path)) return;
1269
1441
  let parsed;
1270
1442
  try {
1271
- parsed = JSON.parse(readFileSync(path, "utf-8"));
1443
+ parsed = JSON.parse(readFileSync3(path, "utf-8"));
1272
1444
  } catch {
1273
1445
  return;
1274
1446
  }
@@ -1741,24 +1913,24 @@ function withScheduleLinkFooter(opts) {
1741
1913
  }
1742
1914
 
1743
1915
  // src/lib/restart-flags.ts
1744
- import { existsSync as existsSync2, mkdirSync, readdirSync, readFileSync as readFileSync2, renameSync, rmSync, writeFileSync as writeFileSync2 } from "fs";
1745
- import { homedir as homedir2 } from "os";
1746
- import { join as join3 } from "path";
1916
+ import { existsSync as existsSync3, mkdirSync, readdirSync as readdirSync2, readFileSync as readFileSync4, renameSync, rmSync, writeFileSync as writeFileSync2 } from "fs";
1917
+ import { homedir as homedir3 } from "os";
1918
+ import { join as join5 } from "path";
1747
1919
  import { randomUUID } from "crypto";
1748
1920
  function restartFlagsDir() {
1749
- return join3(homedir2(), ".augmented", "restart-flags");
1921
+ return join5(homedir3(), ".augmented", "restart-flags");
1750
1922
  }
1751
1923
  function flagPath(codeName) {
1752
- return join3(restartFlagsDir(), `${codeName}.flag`);
1924
+ return join5(restartFlagsDir(), `${codeName}.flag`);
1753
1925
  }
1754
1926
  function readRestartFlags() {
1755
1927
  const dir = restartFlagsDir();
1756
- if (!existsSync2(dir)) return [];
1928
+ if (!existsSync3(dir)) return [];
1757
1929
  const out = [];
1758
- for (const entry of readdirSync(dir)) {
1930
+ for (const entry of readdirSync2(dir)) {
1759
1931
  if (!entry.endsWith(".flag")) continue;
1760
1932
  try {
1761
- const raw = readFileSync2(join3(dir, entry), "utf8");
1933
+ const raw = readFileSync4(join5(dir, entry), "utf8");
1762
1934
  const parsed = JSON.parse(raw);
1763
1935
  if (typeof parsed.codeName !== "string" || parsed.codeName.length === 0) {
1764
1936
  parsed.codeName = entry.replace(/\.flag$/, "");
@@ -1776,7 +1948,7 @@ function readRestartFlags() {
1776
1948
  }
1777
1949
  function deleteRestartFlag(codeName) {
1778
1950
  const path = flagPath(codeName);
1779
- if (existsSync2(path)) {
1951
+ if (existsSync3(path)) {
1780
1952
  rmSync(path, { force: true });
1781
1953
  }
1782
1954
  }
@@ -2274,8 +2446,8 @@ function applyRestartAcks(args) {
2274
2446
  var GATEWAY_PORT_BASE = 18800;
2275
2447
  var GATEWAY_PORT_STEP = 10;
2276
2448
  var GATEWAY_PORT_MAX = 18899;
2277
- var AUGMENTED_DIR = join4(process.env["HOME"] ?? "/tmp", ".augmented");
2278
- var GATEWAY_PORTS_FILE = join4(AUGMENTED_DIR, "gateway-ports.json");
2449
+ var AUGMENTED_DIR = join6(process.env["HOME"] ?? "/tmp", ".augmented");
2450
+ var GATEWAY_PORTS_FILE = join6(AUGMENTED_DIR, "gateway-ports.json");
2279
2451
  var CHANNEL_SWEEP_INTERVAL_MS = (() => {
2280
2452
  const raw = parseInt(process.env["AGT_CHANNEL_SWEEP_INTERVAL_MS"] ?? "", 10);
2281
2453
  if (!Number.isFinite(raw)) return 5 * 60 * 1e3;
@@ -2382,8 +2554,8 @@ var KNOWN_SAFE_TAIL_SIGNATURES = /* @__PURE__ */ new Set(["session_id_in_use"]);
2382
2554
  function shouldSkipRevokedCleanup(previousKnownStatus) {
2383
2555
  return previousKnownStatus === "revoked";
2384
2556
  }
2385
- function hasRevokedResiduals(state3) {
2386
- return state3.gatewayRunning || state3.portAllocated || state3.provisionDirExists;
2557
+ function hasRevokedResiduals(state5) {
2558
+ return state5.gatewayRunning || state5.portAllocated || state5.provisionDirExists;
2387
2559
  }
2388
2560
  var knownVersions = /* @__PURE__ */ new Map();
2389
2561
  var knownStatuses = /* @__PURE__ */ new Map();
@@ -2449,7 +2621,7 @@ var runningMcpHashes = /* @__PURE__ */ new Map();
2449
2621
  var runningMcpServerKeys = /* @__PURE__ */ new Map();
2450
2622
  function projectMcpHash(_codeName, projectDir) {
2451
2623
  try {
2452
- const raw = readFileSync3(join4(projectDir, ".mcp.json"), "utf-8");
2624
+ const raw = readFileSync5(join6(projectDir, ".mcp.json"), "utf-8");
2453
2625
  return createHash2("sha256").update(canonicalJson(JSON.parse(raw))).digest("hex");
2454
2626
  } catch {
2455
2627
  return null;
@@ -2457,7 +2629,7 @@ function projectMcpHash(_codeName, projectDir) {
2457
2629
  }
2458
2630
  function projectMcpKeys(_codeName, projectDir) {
2459
2631
  try {
2460
- const raw = readFileSync3(join4(projectDir, ".mcp.json"), "utf-8");
2632
+ const raw = readFileSync5(join6(projectDir, ".mcp.json"), "utf-8");
2461
2633
  const parsed = JSON.parse(raw);
2462
2634
  const servers = parsed.mcpServers;
2463
2635
  if (!servers || typeof servers !== "object") return /* @__PURE__ */ new Set();
@@ -2554,7 +2726,7 @@ var codeNameToAgentId = /* @__PURE__ */ new Map();
2554
2726
  var agentChannelTokens = /* @__PURE__ */ new Map();
2555
2727
  var activeChannels = /* @__PURE__ */ new Map();
2556
2728
  var gatewaysStartedThisCycle = /* @__PURE__ */ new Set();
2557
- var state2 = {
2729
+ var state4 = {
2558
2730
  pid: process.pid,
2559
2731
  startedAt: (/* @__PURE__ */ new Date()).toISOString(),
2560
2732
  lastPollAt: null,
@@ -2588,6 +2760,7 @@ function clearAgentCaches(agentId, codeName) {
2588
2760
  lastHarvestAt.delete(codeName);
2589
2761
  claudeSchedulerStates.delete(codeName);
2590
2762
  claudeTaskConcurrency.delete(codeName);
2763
+ lastMcpFailedBannerCount.delete(codeName);
2591
2764
  memoryFileHashes.delete(agentId);
2592
2765
  lastDownloadHash.delete(agentId);
2593
2766
  lastLocalFileHash.delete(agentId);
@@ -2610,7 +2783,7 @@ var cachedFrameworkVersion = null;
2610
2783
  var lastVersionCheckAt = 0;
2611
2784
  var VERSION_CHECK_INTERVAL_MS = 5 * 60 * 1e3;
2612
2785
  var lastResponsivenessProbeAt = 0;
2613
- var agtCliVersion = true ? "0.23.2" : "dev";
2786
+ var agtCliVersion = true ? "0.24.2" : "dev";
2614
2787
  function resolveBrewPath(execFileSync4) {
2615
2788
  try {
2616
2789
  const out = execFileSync4("which", ["brew"], { timeout: 5e3 }).toString().trim();
@@ -2623,7 +2796,7 @@ function resolveBrewPath(execFileSync4) {
2623
2796
  "/usr/local/bin/brew"
2624
2797
  ];
2625
2798
  for (const path of fallbacks) {
2626
- if (existsSync3(path)) return path;
2799
+ if (existsSync4(path)) return path;
2627
2800
  }
2628
2801
  return null;
2629
2802
  }
@@ -2633,7 +2806,7 @@ function claudeBinaryInstalled(execFileSync4) {
2633
2806
  "/opt/homebrew/bin/claude",
2634
2807
  "/usr/local/bin/claude"
2635
2808
  ];
2636
- if (canonical.some((path) => existsSync3(path))) return true;
2809
+ if (canonical.some((path) => existsSync4(path))) return true;
2637
2810
  try {
2638
2811
  execFileSync4("which", ["claude"], { timeout: 5e3 });
2639
2812
  return true;
@@ -2815,7 +2988,7 @@ async function ensureFrameworkBinary(frameworkId) {
2815
2988
  if (!process.env.PATH?.split(":").includes(brewBinDir)) {
2816
2989
  process.env.PATH = `${brewBinDir}:${process.env.PATH ?? ""}`;
2817
2990
  }
2818
- if (existsSync3("/home/linuxbrew/.linuxbrew/bin/claude")) {
2991
+ if (existsSync4("/home/linuxbrew/.linuxbrew/bin/claude")) {
2819
2992
  log("Claude Code installed successfully");
2820
2993
  } else {
2821
2994
  log("Claude Code install completed but binary not found at expected path \u2014 check brew logs");
@@ -2827,7 +3000,7 @@ async function ensureFrameworkBinary(frameworkId) {
2827
3000
  var CLAUDE_CODE_UPGRADE_CHECK_INTERVAL_MS = 24 * 60 * 60 * 1e3;
2828
3001
  var claudeCodeUpgradeInFlight = false;
2829
3002
  function claudeCodeUpgradeMarkerPath() {
2830
- return join4(homedir3(), ".augmented", ".last-claude-code-upgrade-check");
3003
+ return join6(homedir4(), ".augmented", ".last-claude-code-upgrade-check");
2831
3004
  }
2832
3005
  function stampClaudeCodeUpgradeMarker() {
2833
3006
  try {
@@ -2837,7 +3010,7 @@ function stampClaudeCodeUpgradeMarker() {
2837
3010
  }
2838
3011
  function claudeCodeUpgradeThrottled() {
2839
3012
  try {
2840
- const lastCheck = parseInt(readFileSync3(claudeCodeUpgradeMarkerPath(), "utf-8").trim(), 10);
3013
+ const lastCheck = parseInt(readFileSync5(claudeCodeUpgradeMarkerPath(), "utf-8").trim(), 10);
2841
3014
  if (!Number.isFinite(lastCheck)) return false;
2842
3015
  return Date.now() - lastCheck < CLAUDE_CODE_UPGRADE_CHECK_INTERVAL_MS;
2843
3016
  } catch {
@@ -2907,7 +3080,7 @@ async function checkAndUpdateCli() {
2907
3080
  const isNpmGlobal = !isBrewFormula && resolvedPath.includes("node_modules");
2908
3081
  if (!isBrewFormula && !isNpmGlobal) return;
2909
3082
  const { readFileSync: readF, writeFileSync: writeF } = await import("fs");
2910
- const markerPath = join4(homedir3(), ".augmented", ".last-update-check");
3083
+ const markerPath = join6(homedir4(), ".augmented", ".last-update-check");
2911
3084
  try {
2912
3085
  const lastCheck = parseInt(readF(markerPath, "utf-8").trim(), 10);
2913
3086
  if (Date.now() - lastCheck < UPDATE_CHECK_INTERVAL_MS) return;
@@ -2972,17 +3145,18 @@ async function checkAndUpdateCliViaBrew() {
2972
3145
  async function checkAndUpdateCliViaNpm() {
2973
3146
  const { execFileSync: execFileSync4 } = await import("child_process");
2974
3147
  if (agtCliVersion === "dev") return;
3148
+ const channel = process.env.AGT_CLI_RELEASE_CHANNEL || "latest";
2975
3149
  let latest;
2976
3150
  try {
2977
3151
  const res = await fetch(
2978
- "https://registry.npmjs.org/@integrity-labs/agt-cli/latest",
3152
+ `https://registry.npmjs.org/@integrity-labs/agt-cli/${encodeURIComponent(channel)}`,
2979
3153
  {
2980
3154
  signal: AbortSignal.timeout(1e4),
2981
3155
  headers: { Accept: "application/json" }
2982
3156
  }
2983
3157
  );
2984
3158
  if (!res.ok) {
2985
- log(`[self-update] npm registry returned ${res.status}`);
3159
+ log(`[self-update] npm registry returned ${res.status} (channel=${channel})`);
2986
3160
  return;
2987
3161
  }
2988
3162
  const body = await res.json();
@@ -2995,14 +3169,15 @@ async function checkAndUpdateCliViaNpm() {
2995
3169
  log(`[self-update] npm registry fetch failed: ${err.message}`);
2996
3170
  return;
2997
3171
  }
2998
- if (!isNewerSemver(agtCliVersion, latest)) {
3172
+ const shouldUpdate = channel === "latest" ? isNewerSemver(agtCliVersion, latest) : latest !== agtCliVersion;
3173
+ if (!shouldUpdate) {
2999
3174
  if (!selfUpdateUpToDateLogged) {
3000
- log(`[self-update] agt CLI is up to date (npm, ${agtCliVersion})`);
3175
+ log(`[self-update] agt CLI is up to date (npm, channel=${channel}, ${agtCliVersion})`);
3001
3176
  selfUpdateUpToDateLogged = true;
3002
3177
  }
3003
3178
  return;
3004
3179
  }
3005
- log(`[self-update] agt CLI update available: ${agtCliVersion} \u2192 ${latest}. Upgrading via npm...`);
3180
+ log(`[self-update] agt CLI update available: ${agtCliVersion} \u2192 ${latest} (channel=${channel}). Upgrading via npm...`);
3006
3181
  const isRoot = typeof process.getuid === "function" && process.getuid() === 0;
3007
3182
  const cmd = isRoot ? "npm" : "sudo";
3008
3183
  const args = isRoot ? [
@@ -3069,10 +3244,10 @@ async function applyClaudeAuthToEnv(childEnv, label) {
3069
3244
  throw new Error("claude_auth_mode=api_key but /host/exchange returned no decrypted key");
3070
3245
  }
3071
3246
  childEnv.ANTHROPIC_API_KEY = exchange.anthropicApiKey;
3072
- const claudeDir = join4(homedir3(), ".claude");
3247
+ const claudeDir = join6(homedir4(), ".claude");
3073
3248
  for (const filename of [".credentials.json", "credentials.json"]) {
3074
- const p = join4(claudeDir, filename);
3075
- if (existsSync3(p)) {
3249
+ const p = join6(claudeDir, filename);
3250
+ if (existsSync4(p)) {
3076
3251
  try {
3077
3252
  rmSync2(p, { force: true });
3078
3253
  log(`[${label}] Removed ${p} (api_key mode \u2014 preventing OAuth fallback)`);
@@ -3086,7 +3261,7 @@ async function applyClaudeAuthToEnv(childEnv, label) {
3086
3261
  }
3087
3262
  function loadGatewayPorts() {
3088
3263
  try {
3089
- return JSON.parse(readFileSync3(GATEWAY_PORTS_FILE, "utf-8"));
3264
+ return JSON.parse(readFileSync5(GATEWAY_PORTS_FILE, "utf-8"));
3090
3265
  } catch {
3091
3266
  return {};
3092
3267
  }
@@ -3116,10 +3291,10 @@ function freePort(codeName) {
3116
3291
  }
3117
3292
  }
3118
3293
  function getStateFile() {
3119
- return join4(config?.configDir ?? join4(process.env["HOME"] ?? "/tmp", ".augmented"), "manager-state.json");
3294
+ return join6(config?.configDir ?? join6(process.env["HOME"] ?? "/tmp", ".augmented"), "manager-state.json");
3120
3295
  }
3121
3296
  function channelHashCacheDir() {
3122
- return config?.configDir ?? join4(process.env["HOME"] ?? "/tmp", ".augmented");
3297
+ return config?.configDir ?? join6(process.env["HOME"] ?? "/tmp", ".augmented");
3123
3298
  }
3124
3299
  function loadChannelHashCache2() {
3125
3300
  loadChannelHashCache(knownChannelConfigHashes, channelHashCacheDir());
@@ -3161,9 +3336,9 @@ function log(msg) {
3161
3336
  `;
3162
3337
  if (!managerLogPath) {
3163
3338
  try {
3164
- managerLogPath = join4(homedir3(), ".augmented", "manager.log");
3339
+ managerLogPath = join6(homedir4(), ".augmented", "manager.log");
3165
3340
  mkdirSync2(dirname(managerLogPath), { recursive: true });
3166
- if (existsSync3(managerLogPath)) {
3341
+ if (existsSync4(managerLogPath)) {
3167
3342
  chmodSync(managerLogPath, 384);
3168
3343
  }
3169
3344
  } catch {
@@ -3191,7 +3366,7 @@ function sha256(content) {
3191
3366
  }
3192
3367
  function hashFile(filePath) {
3193
3368
  try {
3194
- const content = readFileSync3(filePath, "utf-8");
3369
+ const content = readFileSync5(filePath, "utf-8");
3195
3370
  return sha256(content);
3196
3371
  } catch {
3197
3372
  return null;
@@ -3215,13 +3390,13 @@ function parseSkillFrontmatter(content) {
3215
3390
  return out;
3216
3391
  }
3217
3392
  async function refreshSkillsIndexInClaudeMd(configDir, codeName, log2) {
3218
- const { readdirSync: readdirSync3, readFileSync: rfs, existsSync: ex, writeFileSync: writeFileSync4 } = await import("fs");
3219
- const skillsDir = join4(configDir, codeName, "project", ".claude", "skills");
3220
- const claudeMdPath = join4(configDir, codeName, "project", "CLAUDE.md");
3393
+ const { readdirSync: readdirSync4, readFileSync: rfs, existsSync: ex, writeFileSync: writeFileSync4 } = await import("fs");
3394
+ const skillsDir = join6(configDir, codeName, "project", ".claude", "skills");
3395
+ const claudeMdPath = join6(configDir, codeName, "project", "CLAUDE.md");
3221
3396
  if (!ex(skillsDir) || !ex(claudeMdPath)) return;
3222
3397
  const entries = [];
3223
- for (const dir of readdirSync3(skillsDir).sort()) {
3224
- const skillFile = join4(skillsDir, dir, "SKILL.md");
3398
+ for (const dir of readdirSync4(skillsDir).sort()) {
3399
+ const skillFile = join6(skillsDir, dir, "SKILL.md");
3225
3400
  if (!ex(skillFile)) continue;
3226
3401
  try {
3227
3402
  const { name, description } = parseSkillFrontmatter(rfs(skillFile, "utf-8"));
@@ -3269,10 +3444,10 @@ ${SKILLS_INDEX_END}`;
3269
3444
  }
3270
3445
  async function migrateToProfiles() {
3271
3446
  const homeDir = process.env["HOME"] ?? "/tmp";
3272
- const sharedConfigPath = join4(homeDir, ".openclaw", "openclaw.json");
3447
+ const sharedConfigPath = join6(homeDir, ".openclaw", "openclaw.json");
3273
3448
  let sharedConfig;
3274
3449
  try {
3275
- sharedConfig = JSON.parse(readFileSync3(sharedConfigPath, "utf-8"));
3450
+ sharedConfig = JSON.parse(readFileSync5(sharedConfigPath, "utf-8"));
3276
3451
  } catch {
3277
3452
  return;
3278
3453
  }
@@ -3285,19 +3460,19 @@ async function migrateToProfiles() {
3285
3460
  const codeName = agentEntry["id"];
3286
3461
  if (!codeName) continue;
3287
3462
  if (codeName === "main") continue;
3288
- const profileDir = join4(homeDir, `.openclaw-${codeName}`);
3289
- if (existsSync3(join4(profileDir, "openclaw.json"))) continue;
3463
+ const profileDir = join6(homeDir, `.openclaw-${codeName}`);
3464
+ if (existsSync4(join6(profileDir, "openclaw.json"))) continue;
3290
3465
  log(`Migrating agent '${codeName}' to per-agent profile`);
3291
3466
  if (adapter.seedProfileConfig) {
3292
3467
  adapter.seedProfileConfig(codeName);
3293
3468
  }
3294
- const sharedAuthDir = join4(homeDir, ".openclaw", "agents", codeName, "agent");
3295
- const profileAuthDir = join4(profileDir, "agents", codeName, "agent");
3296
- const authFile = join4(sharedAuthDir, "auth-profiles.json");
3297
- if (existsSync3(authFile)) {
3469
+ const sharedAuthDir = join6(homeDir, ".openclaw", "agents", codeName, "agent");
3470
+ const profileAuthDir = join6(profileDir, "agents", codeName, "agent");
3471
+ const authFile = join6(sharedAuthDir, "auth-profiles.json");
3472
+ if (existsSync4(authFile)) {
3298
3473
  mkdirSync2(profileAuthDir, { recursive: true });
3299
- const authContent = readFileSync3(authFile, "utf-8");
3300
- writeFileSync3(join4(profileAuthDir, "auth-profiles.json"), authContent);
3474
+ const authContent = readFileSync5(authFile, "utf-8");
3475
+ writeFileSync3(join6(profileAuthDir, "auth-profiles.json"), authContent);
3301
3476
  }
3302
3477
  allocatePort(codeName);
3303
3478
  migrated++;
@@ -3335,7 +3510,7 @@ function readGatewayToken(codeName) {
3335
3510
  }
3336
3511
  const homeDir = process.env["HOME"] ?? "/tmp";
3337
3512
  try {
3338
- const cfg = JSON.parse(readFileSync3(join4(homeDir, `.openclaw-${codeName}`, "openclaw.json"), "utf-8"));
3513
+ const cfg = JSON.parse(readFileSync5(join6(homeDir, `.openclaw-${codeName}`, "openclaw.json"), "utf-8"));
3339
3514
  return cfg?.gateway?.auth?.token;
3340
3515
  } catch {
3341
3516
  return void 0;
@@ -3344,18 +3519,18 @@ function readGatewayToken(codeName) {
3344
3519
  var GATEWAY_HUNG_TIMEOUT_MS = 5 * 6e4;
3345
3520
  function isGatewayHung(codeName) {
3346
3521
  const homeDir = process.env["HOME"] ?? "/tmp";
3347
- const jobsPath = join4(homeDir, `.openclaw-${codeName}`, "cron", "jobs.json");
3348
- if (!existsSync3(jobsPath)) return false;
3522
+ const jobsPath = join6(homeDir, `.openclaw-${codeName}`, "cron", "jobs.json");
3523
+ if (!existsSync4(jobsPath)) return false;
3349
3524
  try {
3350
- const data = JSON.parse(readFileSync3(jobsPath, "utf-8"));
3525
+ const data = JSON.parse(readFileSync5(jobsPath, "utf-8"));
3351
3526
  const jobs = data.jobs ?? data;
3352
3527
  if (!Array.isArray(jobs)) return false;
3353
3528
  const now = Date.now();
3354
3529
  for (const job of jobs) {
3355
- const state3 = job.state;
3356
- if (!state3) continue;
3357
- const runStartedAt = state3.runStartedAtMs;
3358
- const isRunning = state3.status === "running" || state3.running === true;
3530
+ const state5 = job.state;
3531
+ if (!state5) continue;
3532
+ const runStartedAt = state5.runStartedAtMs;
3533
+ const isRunning = state5.status === "running" || state5.running === true;
3359
3534
  if (isRunning && runStartedAt && now - runStartedAt > GATEWAY_HUNG_TIMEOUT_MS) {
3360
3535
  return true;
3361
3536
  }
@@ -3380,15 +3555,15 @@ async function ensureGatewayRunning(codeName, adapter) {
3380
3555
  }
3381
3556
  await new Promise((r) => setTimeout(r, 2e3));
3382
3557
  const homeDir = process.env["HOME"] ?? "/tmp";
3383
- const cronJobsPath = join4(homeDir, `.openclaw-${codeName}`, "cron", "jobs.json");
3558
+ const cronJobsPath = join6(homeDir, `.openclaw-${codeName}`, "cron", "jobs.json");
3384
3559
  clearStaleCronRunState(cronJobsPath);
3385
3560
  } else {
3386
3561
  if (status.port) {
3387
3562
  try {
3388
3563
  const homeDir = process.env["HOME"] ?? "/tmp";
3389
- const configPath = join4(homeDir, `.openclaw-${codeName}`, "openclaw.json");
3390
- if (existsSync3(configPath)) {
3391
- const cfg = JSON.parse(readFileSync3(configPath, "utf-8"));
3564
+ const configPath = join6(homeDir, `.openclaw-${codeName}`, "openclaw.json");
3565
+ if (existsSync4(configPath)) {
3566
+ const cfg = JSON.parse(readFileSync5(configPath, "utf-8"));
3392
3567
  if (cfg.gateway?.port !== status.port) {
3393
3568
  if (!cfg.gateway) cfg.gateway = {};
3394
3569
  cfg.gateway.port = status.port;
@@ -3412,9 +3587,9 @@ async function ensureGatewayRunning(codeName, adapter) {
3412
3587
  gatewaysStartedThisCycle.add(codeName);
3413
3588
  try {
3414
3589
  const homeDir = process.env["HOME"] ?? "/tmp";
3415
- const configPath = join4(homeDir, `.openclaw-${codeName}`, "openclaw.json");
3416
- if (existsSync3(configPath)) {
3417
- const cfg = JSON.parse(readFileSync3(configPath, "utf-8"));
3590
+ const configPath = join6(homeDir, `.openclaw-${codeName}`, "openclaw.json");
3591
+ if (existsSync4(configPath)) {
3592
+ const cfg = JSON.parse(readFileSync5(configPath, "utf-8"));
3418
3593
  if (!cfg.gateway) cfg.gateway = {};
3419
3594
  cfg.gateway.port = port;
3420
3595
  writeFileSync3(configPath, JSON.stringify(cfg, null, 2));
@@ -3556,7 +3731,7 @@ async function pollCycle() {
3556
3731
  const now = Date.now();
3557
3732
  if (now - lastVersionCheckAt > VERSION_CHECK_INTERVAL_MS) {
3558
3733
  try {
3559
- const firstAgent = state2.agents[0];
3734
+ const firstAgent = state4.agents[0];
3560
3735
  const versionAdapter = firstAgent ? resolveAgentFramework(firstAgent.codeName) : getFramework("openclaw");
3561
3736
  if (versionAdapter.getVersion) {
3562
3737
  cachedFrameworkVersion = await versionAdapter.getVersion();
@@ -3567,7 +3742,7 @@ async function pollCycle() {
3567
3742
  }
3568
3743
  try {
3569
3744
  const { detectHostSecurity } = await import("../host-security-6PDFG7F5.js");
3570
- const { collectDiagnostics } = await import("../persistent-session-L4YIJJML.js");
3745
+ const { collectDiagnostics } = await import("../persistent-session-JUJY46HW.js");
3571
3746
  const diagCodeNames = [...persistentSessionAgents];
3572
3747
  const agentDiagnostics = diagCodeNames.length > 0 ? collectDiagnostics(diagCodeNames) : void 0;
3573
3748
  let tailscaleHostname;
@@ -3618,7 +3793,7 @@ async function pollCycle() {
3618
3793
  const {
3619
3794
  collectResponsivenessProbes,
3620
3795
  getResponsivenessIntervalMs
3621
- } = await import("../responsiveness-probe-YRLESO54.js");
3796
+ } = await import("../responsiveness-probe-XOEC7J5D.js");
3622
3797
  const probeIntervalMs = getResponsivenessIntervalMs();
3623
3798
  if (now - lastResponsivenessProbeAt > probeIntervalMs) {
3624
3799
  const probeCodeNames = [...persistentSessionAgents];
@@ -3635,13 +3810,50 @@ async function pollCycle() {
3635
3810
  } catch (err) {
3636
3811
  log(`[responsiveness-probe] collection failed: ${err.message}`);
3637
3812
  }
3813
+ try {
3814
+ const { scrapeMcpFailedBannerCount } = await import("../pane-mcp-banner-scraper-JA437JIB.js");
3815
+ const observations = [];
3816
+ const pendingCacheCommits = [];
3817
+ for (const codeName of persistentSessionAgents) {
3818
+ const agentId = codeNameToAgentId.get(codeName);
3819
+ if (!agentId) continue;
3820
+ const tail = readPaneLogTail(codeName, 40);
3821
+ if (!tail) continue;
3822
+ const observed = scrapeMcpFailedBannerCount(tail);
3823
+ const count = observed ?? 0;
3824
+ const last = lastMcpFailedBannerCount.get(codeName);
3825
+ if (last === count) continue;
3826
+ observations.push({ agent_id: agentId, count });
3827
+ pendingCacheCommits.push({ codeName, count });
3828
+ }
3829
+ if (observations.length > 0) {
3830
+ void api.post(
3831
+ "/host/mcp-banner-observation",
3832
+ { observations }
3833
+ ).then((resp) => {
3834
+ const accepted = new Set(
3835
+ (resp?.results ?? []).filter((r) => r.ok).map((r) => r.agent_id)
3836
+ );
3837
+ for (const { codeName, count } of pendingCacheCommits) {
3838
+ const agentId = codeNameToAgentId.get(codeName);
3839
+ if (agentId && accepted.has(agentId)) {
3840
+ lastMcpFailedBannerCount.set(codeName, count);
3841
+ }
3842
+ }
3843
+ }).catch((err) => {
3844
+ log(`[mcp-banner] post failed: ${err.message}`);
3845
+ });
3846
+ }
3847
+ } catch (err) {
3848
+ log(`[mcp-banner] collection failed: ${err.message}`);
3849
+ }
3638
3850
  const data = await api.post("/host/agents", { host_id: hostId });
3639
3851
  const agents = data.agents ?? [];
3640
3852
  const restartAcks = /* @__PURE__ */ new Map();
3641
3853
  for (const agent of agents) {
3642
3854
  const requested = agent.restart_requested_at ?? null;
3643
3855
  if (!requested) continue;
3644
- const prev = state2.agents.find((a) => a.agentId === agent.agent_id);
3856
+ const prev = state4.agents.find((a) => a.agentId === agent.agent_id);
3645
3857
  const lastProcessed = prev?.lastRestartProcessedAt ?? null;
3646
3858
  if (lastProcessed && Date.parse(lastProcessed) >= Date.parse(requested)) continue;
3647
3859
  log(`[restart] Dashboard requested restart for '${agent.code_name}' at ${requested}`);
@@ -3664,7 +3876,7 @@ async function pollCycle() {
3664
3876
  await processAgent(agent, agentStates);
3665
3877
  } catch (err) {
3666
3878
  log(`Error processing agent '${agent.code_name}': ${err.message}`);
3667
- const existing = state2.agents.find((a) => a.agentId === agent.agent_id);
3879
+ const existing = state4.agents.find((a) => a.agentId === agent.agent_id);
3668
3880
  if (existing) {
3669
3881
  agentStates.push(existing);
3670
3882
  } else {
@@ -3687,14 +3899,15 @@ async function pollCycle() {
3687
3899
  }
3688
3900
  }
3689
3901
  }
3902
+ void maybeReportActivityCache({ api, log });
3690
3903
  const restartAckStateChanged = applyRestartAcks({
3691
3904
  agentStates,
3692
- priorAgents: state2.agents,
3905
+ priorAgents: state4.agents,
3693
3906
  restartAcks
3694
3907
  });
3695
3908
  if (restartAckStateChanged) {
3696
3909
  try {
3697
- const ackedState = { ...state2, agents: agentStates };
3910
+ const ackedState = { ...state4, agents: agentStates };
3698
3911
  writeFileSync3(getStateFile(), JSON.stringify(ackedState, null, 2));
3699
3912
  } catch (err) {
3700
3913
  log(`[restart] failed to persist ack immediately: ${err.message}`);
@@ -3712,7 +3925,7 @@ async function pollCycle() {
3712
3925
  } catch {
3713
3926
  }
3714
3927
  const currentIds = new Set(agents.map((a) => a.agent_id));
3715
- for (const prev of state2.agents) {
3928
+ for (const prev of state4.agents) {
3716
3929
  if (!currentIds.has(prev.agentId)) {
3717
3930
  log(`Agent '${prev.codeName}' removed from host (deleted or unassigned)`);
3718
3931
  const adapter = resolveAgentFramework(prev.codeName);
@@ -3725,7 +3938,7 @@ async function pollCycle() {
3725
3938
  }
3726
3939
  killAgentChannelProcesses(prev.codeName, { log });
3727
3940
  freePort(prev.codeName);
3728
- const agentDir = join4(adapter.getAgentDir(prev.codeName), "provision");
3941
+ const agentDir = join6(adapter.getAgentDir(prev.codeName), "provision");
3729
3942
  await cleanupAgentFiles(prev.codeName, agentDir);
3730
3943
  clearAgentCaches(prev.agentId, prev.codeName);
3731
3944
  }
@@ -3812,10 +4025,10 @@ async function pollCycle() {
3812
4025
  }
3813
4026
  } catch {
3814
4027
  }
3815
- state2 = {
3816
- ...state2,
4028
+ state4 = {
4029
+ ...state4,
3817
4030
  lastPollAt: (/* @__PURE__ */ new Date()).toISOString(),
3818
- pollCount: state2.pollCount + 1,
4031
+ pollCount: state4.pollCount + 1,
3819
4032
  agents: agentStates,
3820
4033
  // ENG-5441: serialise trip state on every poll so manager restarts
3821
4034
  // never silently clear a tripped breaker. Cheap — only tripped
@@ -3826,9 +4039,9 @@ async function pollCycle() {
3826
4039
  log(`[poll-backoff] recovered after ${consecutivePollFailures} failure(s), resuming normal interval`);
3827
4040
  consecutivePollFailures = 0;
3828
4041
  }
3829
- send({ type: "state-update", state: state2 });
4042
+ send({ type: "state-update", state: state4 });
3830
4043
  } catch (err) {
3831
- state2.errorCount++;
4044
+ state4.errorCount++;
3832
4045
  const message = err.message;
3833
4046
  log(`Poll error: ${message}`);
3834
4047
  send({ type: "error", message });
@@ -3866,10 +4079,16 @@ async function processAgent(agent, agentStates) {
3866
4079
  agentId: agent.agent_id,
3867
4080
  log
3868
4081
  });
4082
+ void maybeReportTokenUsage({
4083
+ api,
4084
+ codeName: agent.code_name,
4085
+ agentId: agent.agent_id,
4086
+ log
4087
+ });
3869
4088
  }
3870
4089
  const now = (/* @__PURE__ */ new Date()).toISOString();
3871
4090
  const adapter = resolveAgentFramework(agent.code_name);
3872
- let agentDir = join4(adapter.getAgentDir(agent.code_name), "provision");
4091
+ let agentDir = join6(adapter.getAgentDir(agent.code_name), "provision");
3873
4092
  if (agent.status === "draft" || agent.status === "paused") {
3874
4093
  if (previousKnownStatus !== agent.status) {
3875
4094
  log(`Agent '${agent.code_name}' is ${agent.status}, skipping provisioning`);
@@ -3908,7 +4127,7 @@ async function processAgent(agent, agentStates) {
3908
4127
  const residuals = {
3909
4128
  gatewayRunning: gatewayLiveness.running,
3910
4129
  portAllocated: Object.prototype.hasOwnProperty.call(ports, agent.code_name),
3911
- provisionDirExists: existsSync3(agentDir)
4130
+ provisionDirExists: existsSync4(agentDir)
3912
4131
  };
3913
4132
  if (!hasRevokedResiduals(residuals)) {
3914
4133
  agentStates.push({
@@ -3990,7 +4209,7 @@ async function processAgent(agent, agentStates) {
3990
4209
  });
3991
4210
  } catch (err) {
3992
4211
  log(`Refresh failed for '${agent.code_name}': ${err.message}`);
3993
- const existing = state2.agents.find((a) => a.agentId === agent.agent_id);
4212
+ const existing = state4.agents.find((a) => a.agentId === agent.agent_id);
3994
4213
  agentStates.push(existing ?? {
3995
4214
  agentId: agent.agent_id,
3996
4215
  codeName: agent.code_name,
@@ -4038,7 +4257,7 @@ async function processAgent(agent, agentStates) {
4038
4257
  const frameworkId = refreshData.agent.framework ?? "openclaw";
4039
4258
  agentFrameworkCache.set(agent.code_name, frameworkId);
4040
4259
  const frameworkAdapter = getFramework(frameworkId);
4041
- agentDir = join4(frameworkAdapter.getAgentDir(agent.code_name), "provision");
4260
+ agentDir = join6(frameworkAdapter.getAgentDir(agent.code_name), "provision");
4042
4261
  cacheAgentDeliveryMetadata(agent.code_name, refreshData);
4043
4262
  if (frameworkAdapter.seedProfileConfig) {
4044
4263
  frameworkAdapter.seedProfileConfig(agent.code_name);
@@ -4046,7 +4265,7 @@ async function processAgent(agent, agentStates) {
4046
4265
  const charterVersion = refreshData.charter.version;
4047
4266
  const toolsVersion = refreshData.tools.version;
4048
4267
  const known = knownVersions.get(agent.agent_id);
4049
- let lastProvisionAt = state2.agents.find((a) => a.agentId === agent.agent_id)?.lastProvisionAt ?? null;
4268
+ let lastProvisionAt = state4.agents.find((a) => a.agentId === agent.agent_id)?.lastProvisionAt ?? null;
4050
4269
  const currentChannelIds = launchableChannelIds(refreshData.channel_configs);
4051
4270
  const previousChannelIds = knownChannels.get(agent.agent_id);
4052
4271
  const channelsChanged = !previousChannelIds || currentChannelIds.size !== previousChannelIds.size || [...currentChannelIds].some((ch) => !previousChannelIds.has(ch)) || [...previousChannelIds].some((ch) => !currentChannelIds.has(ch));
@@ -4069,7 +4288,7 @@ async function processAgent(agent, agentStates) {
4069
4288
  const changedFiles = [];
4070
4289
  mkdirSync2(agentDir, { recursive: true });
4071
4290
  for (const artifact of artifacts) {
4072
- const filePath = join4(agentDir, artifact.relativePath);
4291
+ const filePath = join6(agentDir, artifact.relativePath);
4073
4292
  let existingHash;
4074
4293
  let newHash;
4075
4294
  let writeContent = artifact.content;
@@ -4081,8 +4300,8 @@ async function processAgent(agent, agentStates) {
4081
4300
  };
4082
4301
  newHash = sha256(stripDynamicSections(artifact.content));
4083
4302
  try {
4084
- const projectClaudeMd = join4(config.configDir, agent.code_name, "project", "CLAUDE.md");
4085
- const existing = readFileSync3(projectClaudeMd, "utf-8");
4303
+ const projectClaudeMd = join6(config.configDir, agent.code_name, "project", "CLAUDE.md");
4304
+ const existing = readFileSync5(projectClaudeMd, "utf-8");
4086
4305
  existingHash = sha256(stripDynamicSections(existing));
4087
4306
  } catch {
4088
4307
  existingHash = null;
@@ -4100,7 +4319,7 @@ async function processAgent(agent, agentStates) {
4100
4319
  const generatorKeys = Object.keys(generatorServers);
4101
4320
  let existingRaw = "";
4102
4321
  try {
4103
- existingRaw = readFileSync3(filePath, "utf-8");
4322
+ existingRaw = readFileSync5(filePath, "utf-8");
4104
4323
  } catch {
4105
4324
  }
4106
4325
  const existingServers = parseMcp(existingRaw);
@@ -4122,22 +4341,22 @@ async function processAgent(agent, agentStates) {
4122
4341
  }
4123
4342
  }
4124
4343
  if (changedFiles.length > 0) {
4125
- const isFirst = !existsSync3(join4(agentDir, "CHARTER.md"));
4344
+ const isFirst = !existsSync4(join6(agentDir, "CHARTER.md"));
4126
4345
  const verb = isFirst ? "Provisioning" : "Updating";
4127
4346
  const fileNames = changedFiles.map((f) => f.relativePath).join(", ");
4128
4347
  log(`${verb} '${agent.code_name}': ${fileNames}`);
4129
4348
  for (const file of changedFiles) {
4130
- const filePath = join4(agentDir, file.relativePath);
4349
+ const filePath = join6(agentDir, file.relativePath);
4131
4350
  mkdirSync2(dirname(filePath), { recursive: true });
4132
4351
  writeFileSync3(filePath, file.content);
4133
4352
  }
4134
4353
  try {
4135
- const provSkillsDir = join4(agentDir, ".claude", "skills");
4136
- if (existsSync3(provSkillsDir)) {
4137
- for (const folder of readdirSync2(provSkillsDir)) {
4354
+ const provSkillsDir = join6(agentDir, ".claude", "skills");
4355
+ if (existsSync4(provSkillsDir)) {
4356
+ for (const folder of readdirSync3(provSkillsDir)) {
4138
4357
  if (folder.startsWith("knowledge-")) {
4139
4358
  try {
4140
- rmSync2(join4(provSkillsDir, folder), { recursive: true });
4359
+ rmSync2(join6(provSkillsDir, folder), { recursive: true });
4141
4360
  } catch {
4142
4361
  }
4143
4362
  }
@@ -4150,7 +4369,7 @@ async function processAgent(agent, agentStates) {
4150
4369
  const trackedFiles2 = frameworkAdapter.driftTrackedFiles();
4151
4370
  const hashes = /* @__PURE__ */ new Map();
4152
4371
  for (const file of trackedFiles2) {
4153
- const h = hashFile(join4(agentDir, file));
4372
+ const h = hashFile(join6(agentDir, file));
4154
4373
  if (h) hashes.set(file, h);
4155
4374
  }
4156
4375
  writtenHashes.set(agent.agent_id, hashes);
@@ -4194,10 +4413,10 @@ async function processAgent(agent, agentStates) {
4194
4413
  }
4195
4414
  let lastDriftCheckAt = now;
4196
4415
  const written = writtenHashes.get(agent.agent_id);
4197
- if (written && existsSync3(agentDir)) {
4416
+ if (written && existsSync4(agentDir)) {
4198
4417
  const driftedFiles = [];
4199
4418
  for (const [file, expectedHash] of written) {
4200
- const localHash = hashFile(join4(agentDir, file));
4419
+ const localHash = hashFile(join6(agentDir, file));
4201
4420
  if (localHash && localHash !== expectedHash) {
4202
4421
  driftedFiles.push(file);
4203
4422
  }
@@ -4208,7 +4427,7 @@ async function processAgent(agent, agentStates) {
4208
4427
  try {
4209
4428
  const localHashes = {};
4210
4429
  for (const file of driftedFiles) {
4211
- localHashes[file] = hashFile(join4(agentDir, file));
4430
+ localHashes[file] = hashFile(join6(agentDir, file));
4212
4431
  }
4213
4432
  await api.post("/host/drift", {
4214
4433
  agent_id: agent.agent_id,
@@ -4366,24 +4585,24 @@ async function processAgent(agent, agentStates) {
4366
4585
  if (agentSessionMode === "persistent" && (agentFrameworkCache.get(agent.code_name) ?? "openclaw") === "claude-code") {
4367
4586
  try {
4368
4587
  const agentProvisionDir = agentDir;
4369
- const projectDir = join4(homedir3(), ".augmented", agent.code_name, "project");
4588
+ const projectDir = join6(homedir4(), ".augmented", agent.code_name, "project");
4370
4589
  mkdirSync2(agentProvisionDir, { recursive: true });
4371
4590
  mkdirSync2(projectDir, { recursive: true });
4372
- const provisionMcpPath = join4(agentProvisionDir, ".mcp.json");
4373
- const projectMcpPath = join4(projectDir, ".mcp.json");
4591
+ const provisionMcpPath = join6(agentProvisionDir, ".mcp.json");
4592
+ const projectMcpPath = join6(projectDir, ".mcp.json");
4374
4593
  let mcpConfig = { mcpServers: {} };
4375
4594
  try {
4376
- mcpConfig = JSON.parse(readFileSync3(provisionMcpPath, "utf-8"));
4595
+ mcpConfig = JSON.parse(readFileSync5(provisionMcpPath, "utf-8"));
4377
4596
  if (!mcpConfig.mcpServers) mcpConfig.mcpServers = {};
4378
4597
  } catch {
4379
4598
  }
4380
- const localDirectChatChannel = join4(homedir3(), ".augmented", "_mcp", "direct-chat-channel.js");
4599
+ const localDirectChatChannel = join6(homedir4(), ".augmented", "_mcp", "direct-chat-channel.js");
4381
4600
  const directChatTeamSettings = refreshData.team?.settings;
4382
4601
  const directChatTz = (() => {
4383
4602
  const tz = directChatTeamSettings?.["timezone"];
4384
4603
  return typeof tz === "string" && tz.trim() !== "" ? tz.trim() : void 0;
4385
4604
  })();
4386
- if (existsSync3(localDirectChatChannel) && !mcpConfig.mcpServers["direct-chat"]) {
4605
+ if (existsSync4(localDirectChatChannel) && !mcpConfig.mcpServers["direct-chat"]) {
4387
4606
  mcpConfig.mcpServers["direct-chat"] = {
4388
4607
  command: "node",
4389
4608
  args: [localDirectChatChannel],
@@ -4399,8 +4618,8 @@ async function processAgent(agent, agentStates) {
4399
4618
  writeFileSync3(projectMcpPath, serialized);
4400
4619
  log(`Channel credentials written for '${agent.code_name}/direct-chat'`);
4401
4620
  }
4402
- const staleChannelsPath = join4(projectDir, ".mcp-channels.json");
4403
- if (existsSync3(staleChannelsPath)) {
4621
+ const staleChannelsPath = join6(projectDir, ".mcp-channels.json");
4622
+ if (existsSync4(staleChannelsPath)) {
4404
4623
  try {
4405
4624
  rmSync2(staleChannelsPath, { force: true });
4406
4625
  } catch {
@@ -4410,7 +4629,7 @@ async function processAgent(agent, agentStates) {
4410
4629
  log(`Failed to provision direct-chat channel for '${agent.code_name}': ${err.message}`);
4411
4630
  }
4412
4631
  }
4413
- let lastSecretsProvisionAt = state2.agents.find((a) => a.agentId === agent.agent_id)?.lastSecretsProvisionAt ?? null;
4632
+ let lastSecretsProvisionAt = state4.agents.find((a) => a.agentId === agent.agent_id)?.lastSecretsProvisionAt ?? null;
4414
4633
  let secretsHash = knownSecretsHashes.get(agent.agent_id) ?? null;
4415
4634
  try {
4416
4635
  const secretsData = await api.post("/host/secrets", { agent_id: agent.agent_id });
@@ -4466,11 +4685,11 @@ async function processAgent(agent, agentStates) {
4466
4685
  const intHash = computeIntegrationsHash(integrations);
4467
4686
  const prevIntHash = knownIntegrationHashes.get(agent.agent_id);
4468
4687
  if (intHash !== prevIntHash) {
4469
- const projectDir = join4(homedir3(), ".augmented", agent.code_name, "project");
4470
- const envIntPath = join4(projectDir, ".env.integrations");
4688
+ const projectDir = join6(homedir4(), ".augmented", agent.code_name, "project");
4689
+ const envIntPath = join6(projectDir, ".env.integrations");
4471
4690
  let preWriteEnv;
4472
4691
  try {
4473
- preWriteEnv = readFileSync3(envIntPath, "utf-8");
4692
+ preWriteEnv = readFileSync5(envIntPath, "utf-8");
4474
4693
  } catch {
4475
4694
  preWriteEnv = void 0;
4476
4695
  }
@@ -4482,9 +4701,9 @@ async function processAgent(agent, agentStates) {
4482
4701
  let rotationHandled = true;
4483
4702
  if (fw === "claude-code" && isSessionHealthy(agent.code_name)) {
4484
4703
  try {
4485
- const projectMcpPath = join4(projectDir, ".mcp.json");
4486
- const postWriteEnv = readFileSync3(envIntPath, "utf-8");
4487
- const mcpContent = readFileSync3(projectMcpPath, "utf-8");
4704
+ const projectMcpPath = join6(projectDir, ".mcp.json");
4705
+ const postWriteEnv = readFileSync5(envIntPath, "utf-8");
4706
+ const mcpContent = readFileSync5(projectMcpPath, "utf-8");
4488
4707
  const changedVars = diffEnvIntegrations(preWriteEnv, postWriteEnv);
4489
4708
  const mcpJsonForReap = JSON.parse(mcpContent);
4490
4709
  const affectedServerKeys = findMcpServersUsingVars(mcpJsonForReap, changedVars);
@@ -4550,8 +4769,8 @@ async function processAgent(agent, agentStates) {
4550
4769
  const mcpPath = frameworkAdapter.getMcpPath(agent.code_name);
4551
4770
  if (mcpPath) {
4552
4771
  try {
4553
- const { readFileSync: readFileSync4 } = await import("fs");
4554
- const mcpConfig = JSON.parse(readFileSync4(mcpPath, "utf-8"));
4772
+ const { readFileSync: readFileSync6 } = await import("fs");
4773
+ const mcpConfig = JSON.parse(readFileSync6(mcpPath, "utf-8"));
4555
4774
  if (mcpConfig.mcpServers) {
4556
4775
  const managedPrefixes = [
4557
4776
  "composio_",
@@ -4640,8 +4859,8 @@ async function processAgent(agent, agentStates) {
4640
4859
  if (agent.status === "active") {
4641
4860
  if (frameworkAdapter.installPlugin) {
4642
4861
  try {
4643
- const pluginPath = join4(process.cwd(), "packages", "openclaw-plugin-augmented", "src", "index.ts");
4644
- if (existsSync3(pluginPath)) {
4862
+ const pluginPath = join6(process.cwd(), "packages", "openclaw-plugin-augmented", "src", "index.ts");
4863
+ if (existsSync4(pluginPath)) {
4645
4864
  frameworkAdapter.installPlugin(agent.code_name, "augmented", pluginPath, {
4646
4865
  agtHost: requireHost(),
4647
4866
  agtApiKey: getApiKey() ?? void 0,
@@ -4706,25 +4925,25 @@ async function processAgent(agent, agentStates) {
4706
4925
  }
4707
4926
  }
4708
4927
  try {
4709
- const { readdirSync: readdirSync3, rmSync: rmSync3 } = await import("fs");
4710
- const { homedir: homedir4 } = await import("os");
4928
+ const { readdirSync: readdirSync4, rmSync: rmSync3 } = await import("fs");
4929
+ const { homedir: homedir5 } = await import("os");
4711
4930
  const frameworkId2 = frameworkAdapter.id;
4712
4931
  const candidateSkillDirs = [
4713
4932
  // Claude Code — framework runtime tree
4714
- join4(homedir4(), ".augmented", agent.code_name, "skills"),
4933
+ join6(homedir5(), ".augmented", agent.code_name, "skills"),
4715
4934
  // Claude Code — project tree
4716
- join4(homedir4(), ".augmented", agent.code_name, "project", ".claude", "skills"),
4935
+ join6(homedir5(), ".augmented", agent.code_name, "project", ".claude", "skills"),
4717
4936
  // OpenClaw — framework runtime tree
4718
- join4(homedir4(), `.openclaw-${agent.code_name}`, "skills"),
4937
+ join6(homedir5(), `.openclaw-${agent.code_name}`, "skills"),
4719
4938
  // Defensive: legacy provision-side path, not currently an
4720
4939
  // install target but cheap to sweep.
4721
- join4(agentDir, ".claude", "skills")
4940
+ join6(agentDir, ".claude", "skills")
4722
4941
  ];
4723
- const existingDirs = candidateSkillDirs.filter((d) => existsSync3(d));
4942
+ const existingDirs = candidateSkillDirs.filter((d) => existsSync4(d));
4724
4943
  const discoveredEntries = /* @__PURE__ */ new Set();
4725
4944
  for (const dir of existingDirs) {
4726
4945
  try {
4727
- for (const entry of readdirSync3(dir)) {
4946
+ for (const entry of readdirSync4(dir)) {
4728
4947
  if (entry.startsWith("plugin-") || entry.startsWith("integration-")) {
4729
4948
  discoveredEntries.add(entry);
4730
4949
  }
@@ -4734,8 +4953,8 @@ async function processAgent(agent, agentStates) {
4734
4953
  }
4735
4954
  const removeSkillFolder = (entry, reason) => {
4736
4955
  for (const dir of existingDirs) {
4737
- const p = join4(dir, entry);
4738
- if (existsSync3(p)) {
4956
+ const p = join6(dir, entry);
4957
+ if (existsSync4(p)) {
4739
4958
  rmSync3(p, { recursive: true, force: true });
4740
4959
  }
4741
4960
  }
@@ -4895,8 +5114,8 @@ async function processAgent(agent, agentStates) {
4895
5114
  const sess = getSessionState(agent.code_name);
4896
5115
  let mcpJsonParsed = null;
4897
5116
  try {
4898
- const mcpPath = join4(getProjectDir(agent.code_name), ".mcp.json");
4899
- mcpJsonParsed = JSON.parse(readFileSync3(mcpPath, "utf-8"));
5117
+ const mcpPath = join6(getProjectDir(agent.code_name), ".mcp.json");
5118
+ mcpJsonParsed = JSON.parse(readFileSync5(mcpPath, "utf-8"));
4900
5119
  } catch {
4901
5120
  }
4902
5121
  reapMissingMcpSessions({
@@ -5045,10 +5264,10 @@ async function processAgent(agent, agentStates) {
5045
5264
  lastWorkTriggerAt.set(agent.code_name, triggerTs);
5046
5265
  if (agentFw === "openclaw" && gatewayRunning && gatewayPort) {
5047
5266
  const homeDir = process.env["HOME"] ?? "/tmp";
5048
- const jobsPath = join4(homeDir, `.openclaw-${agent.code_name}`, "cron", "jobs.json");
5049
- if (existsSync3(jobsPath)) {
5267
+ const jobsPath = join6(homeDir, `.openclaw-${agent.code_name}`, "cron", "jobs.json");
5268
+ if (existsSync4(jobsPath)) {
5050
5269
  try {
5051
- const jobsData = JSON.parse(readFileSync3(jobsPath, "utf-8"));
5270
+ const jobsData = JSON.parse(readFileSync5(jobsPath, "utf-8"));
5052
5271
  const kanbanJob = (jobsData.jobs ?? []).find(
5053
5272
  (j) => typeof j.name === "string" && j.name.includes("kanban-work")
5054
5273
  );
@@ -5189,10 +5408,10 @@ In progress for ${age} minutes \u2014 auto-failed`).catch(() => {
5189
5408
  }
5190
5409
  }
5191
5410
  const trackedFiles = frameworkAdapter.driftTrackedFiles();
5192
- if (trackedFiles.length > 0 && existsSync3(agentDir)) {
5411
+ if (trackedFiles.length > 0 && existsSync4(agentDir)) {
5193
5412
  const hashes = /* @__PURE__ */ new Map();
5194
5413
  for (const file of trackedFiles) {
5195
- const h = hashFile(join4(agentDir, file));
5414
+ const h = hashFile(join6(agentDir, file));
5196
5415
  if (h) hashes.set(file, h);
5197
5416
  }
5198
5417
  writtenHashes.set(agent.agent_id, hashes);
@@ -5226,19 +5445,19 @@ function cleanupStaleSessions(codeName) {
5226
5445
  lastCleanupAt.set(codeName, Date.now());
5227
5446
  const homeDir = process.env["HOME"] ?? "/tmp";
5228
5447
  for (const agentDir of ["main", codeName]) {
5229
- const sessionsDir = join4(homeDir, `.openclaw-${codeName}`, "agents", agentDir, "sessions");
5448
+ const sessionsDir = join6(homeDir, `.openclaw-${codeName}`, "agents", agentDir, "sessions");
5230
5449
  cleanupCronSessions(sessionsDir, CRON_SESSION_KEEP_COUNT);
5231
5450
  }
5232
- const cronRunsDir = join4(homeDir, `.openclaw-${codeName}`, "cron", "runs");
5451
+ const cronRunsDir = join6(homeDir, `.openclaw-${codeName}`, "cron", "runs");
5233
5452
  cleanupOldFiles(cronRunsDir, CRON_RUN_RETENTION_DAYS, ".jsonl");
5234
- const cronJobsPath = join4(homeDir, `.openclaw-${codeName}`, "cron", "jobs.json");
5453
+ const cronJobsPath = join6(homeDir, `.openclaw-${codeName}`, "cron", "jobs.json");
5235
5454
  clearStaleCronRunState(cronJobsPath);
5236
5455
  }
5237
5456
  function cleanupCronSessions(sessionsDir, keepCount) {
5238
- const indexPath = join4(sessionsDir, "sessions.json");
5239
- if (!existsSync3(indexPath)) return;
5457
+ const indexPath = join6(sessionsDir, "sessions.json");
5458
+ if (!existsSync4(indexPath)) return;
5240
5459
  try {
5241
- const raw = readFileSync3(indexPath, "utf-8");
5460
+ const raw = readFileSync5(indexPath, "utf-8");
5242
5461
  const index = JSON.parse(raw);
5243
5462
  const cronRunKeys = Object.keys(index).filter((k) => k.includes(":cron:") && k.includes(":run:")).map((k) => ({
5244
5463
  key: k,
@@ -5251,9 +5470,9 @@ function cleanupCronSessions(sessionsDir, keepCount) {
5251
5470
  for (const entry of toDelete) {
5252
5471
  delete index[entry.key];
5253
5472
  if (entry.sessionId) {
5254
- const sessionFile = join4(sessionsDir, `${entry.sessionId}.jsonl`);
5473
+ const sessionFile = join6(sessionsDir, `${entry.sessionId}.jsonl`);
5255
5474
  try {
5256
- if (existsSync3(sessionFile)) {
5475
+ if (existsSync4(sessionFile)) {
5257
5476
  unlinkSync(sessionFile);
5258
5477
  deletedFiles++;
5259
5478
  }
@@ -5273,8 +5492,8 @@ function cleanupCronSessions(sessionsDir, keepCount) {
5273
5492
  delete index[parentKey];
5274
5493
  if (parentSessionId) {
5275
5494
  try {
5276
- const f = join4(sessionsDir, `${parentSessionId}.jsonl`);
5277
- if (existsSync3(f)) {
5495
+ const f = join6(sessionsDir, `${parentSessionId}.jsonl`);
5496
+ if (existsSync4(f)) {
5278
5497
  unlinkSync(f);
5279
5498
  deletedFiles++;
5280
5499
  }
@@ -5292,28 +5511,28 @@ function cleanupCronSessions(sessionsDir, keepCount) {
5292
5511
  }
5293
5512
  var STALE_RUN_TIMEOUT_MS = 5 * 6e4;
5294
5513
  function clearStaleCronRunState(jobsPath) {
5295
- if (!existsSync3(jobsPath)) return;
5514
+ if (!existsSync4(jobsPath)) return;
5296
5515
  try {
5297
- const raw = readFileSync3(jobsPath, "utf-8");
5516
+ const raw = readFileSync5(jobsPath, "utf-8");
5298
5517
  const data = JSON.parse(raw);
5299
5518
  const jobs = data.jobs ?? data;
5300
5519
  if (!Array.isArray(jobs)) return;
5301
5520
  let changed = false;
5302
5521
  const now = Date.now();
5303
5522
  for (const job of jobs) {
5304
- const state3 = job.state;
5305
- if (!state3) continue;
5306
- const runStartedAt = state3.runningAtMs ?? state3.runStartedAtMs;
5307
- const isRunning = state3.running === true || state3.status === "running";
5523
+ const state5 = job.state;
5524
+ if (!state5) continue;
5525
+ const runStartedAt = state5.runningAtMs ?? state5.runStartedAtMs;
5526
+ const isRunning = state5.running === true || state5.status === "running";
5308
5527
  if (isRunning && runStartedAt && now - runStartedAt > STALE_RUN_TIMEOUT_MS) {
5309
- state3.running = false;
5310
- delete state3.status;
5311
- delete state3.runStartedAtMs;
5312
- delete state3.currentRunId;
5528
+ state5.running = false;
5529
+ delete state5.status;
5530
+ delete state5.runStartedAtMs;
5531
+ delete state5.currentRunId;
5313
5532
  changed = true;
5314
5533
  log(`Cleared stale running state for cron job '${job.name}' (stuck for ${Math.round((now - runStartedAt) / 6e4)}min)`);
5315
5534
  } else if (isRunning && !runStartedAt) {
5316
- state3.running = false;
5535
+ state5.running = false;
5317
5536
  changed = true;
5318
5537
  log(`Cleared stale running state for cron job '${job.name}' (no start timestamp)`);
5319
5538
  }
@@ -5325,15 +5544,15 @@ function clearStaleCronRunState(jobsPath) {
5325
5544
  }
5326
5545
  }
5327
5546
  function cleanupOldFiles(dir, maxAgeDays, ext) {
5328
- if (!existsSync3(dir)) return;
5547
+ if (!existsSync4(dir)) return;
5329
5548
  const cutoff = Date.now() - maxAgeDays * 24 * 60 * 60 * 1e3;
5330
5549
  let removed = 0;
5331
5550
  try {
5332
- for (const f of readdirSync2(dir)) {
5551
+ for (const f of readdirSync3(dir)) {
5333
5552
  if (!f.endsWith(ext)) continue;
5334
- const fullPath = join4(dir, f);
5553
+ const fullPath = join6(dir, f);
5335
5554
  try {
5336
- const st = statSync(fullPath);
5555
+ const st = statSync2(fullPath);
5337
5556
  if (st.mtimeMs < cutoff) {
5338
5557
  unlinkSync(fullPath);
5339
5558
  removed++;
@@ -5377,16 +5596,16 @@ async function syncAndCheckClaudeScheduler(agent, tasks, boardItems, refreshData
5377
5596
  enabled: t.enabled ?? true,
5378
5597
  triggered_at: t.triggered_at ?? null
5379
5598
  }));
5380
- const state4 = syncTasksToScheduler(codeName, agent.agent_id, taskInputs);
5381
- claudeSchedulerStates.set(codeName, state4);
5599
+ const state6 = syncTasksToScheduler(codeName, agent.agent_id, taskInputs);
5600
+ claudeSchedulerStates.set(codeName, state6);
5382
5601
  knownTasksHashes.set(agent.agent_id, combinedHash);
5383
5602
  log(`[claude-scheduler] Tasks synced for '${codeName}' (${taskInputs.length} task(s))`);
5384
5603
  }
5385
5604
  if (!claudeSchedulerStates.has(codeName)) {
5386
5605
  claudeSchedulerStates.set(codeName, loadSchedulerState(codeName));
5387
5606
  }
5388
- const state3 = claudeSchedulerStates.get(codeName);
5389
- const ready = getReadyTasks(state3, inFlightClaudeTasks);
5607
+ const state5 = claudeSchedulerStates.get(codeName);
5608
+ const ready = getReadyTasks(state5, inFlightClaudeTasks);
5390
5609
  if (ready.length === 0) return;
5391
5610
  for (const task of ready) {
5392
5611
  if ((claudeTaskConcurrency.get(codeName) ?? 0) >= MAX_CLAUDE_CONCURRENCY) break;
@@ -5475,7 +5694,7 @@ async function fetchPriorScheduledRuns(agentId, taskId) {
5475
5694
  }
5476
5695
  async function executeAndProcessClaudeTask(codeName, agentId, task, prompt) {
5477
5696
  const projectDir = getProjectDir2(codeName);
5478
- const mcpConfigPath = join4(projectDir, ".mcp.json");
5697
+ const mcpConfigPath = join6(projectDir, ".mcp.json");
5479
5698
  let runId = null;
5480
5699
  let kanbanItemId = null;
5481
5700
  let taskResult;
@@ -5483,11 +5702,11 @@ async function executeAndProcessClaudeTask(codeName, agentId, task, prompt) {
5483
5702
  const priorRuns = await fetchPriorScheduledRuns(agentId, task.taskId);
5484
5703
  prompt = wrapScheduledTaskPrompt(prompt, { priorRuns });
5485
5704
  try {
5486
- const claudeMdPath = join4(projectDir, "CLAUDE.md");
5705
+ const claudeMdPath = join6(projectDir, "CLAUDE.md");
5487
5706
  const serverNames = [];
5488
- if (existsSync3(mcpConfigPath)) {
5707
+ if (existsSync4(mcpConfigPath)) {
5489
5708
  try {
5490
- const d = JSON.parse(readFileSync3(mcpConfigPath, "utf-8"));
5709
+ const d = JSON.parse(readFileSync5(mcpConfigPath, "utf-8"));
5491
5710
  if (d.mcpServers) serverNames.push(...Object.keys(d.mcpServers));
5492
5711
  } catch {
5493
5712
  }
@@ -5506,14 +5725,14 @@ async function executeAndProcessClaudeTask(codeName, agentId, task, prompt) {
5506
5725
  "--allowedTools",
5507
5726
  allowedTools
5508
5727
  ];
5509
- if (existsSync3(claudeMdPath)) {
5728
+ if (existsSync4(claudeMdPath)) {
5510
5729
  claudeArgs.push("--system-prompt-file", claudeMdPath);
5511
5730
  }
5512
5731
  const childEnv = { ...process.env };
5513
- const envIntPath = join4(projectDir, ".env.integrations");
5514
- if (existsSync3(envIntPath)) {
5732
+ const envIntPath = join6(projectDir, ".env.integrations");
5733
+ if (existsSync4(envIntPath)) {
5515
5734
  try {
5516
- for (const line of readFileSync3(envIntPath, "utf-8").split("\n")) {
5735
+ for (const line of readFileSync5(envIntPath, "utf-8").split("\n")) {
5517
5736
  if (!line || line.startsWith("#") || !line.includes("=")) continue;
5518
5737
  const eqIdx = line.indexOf("=");
5519
5738
  childEnv[line.slice(0, eqIdx)] = line.slice(eqIdx + 1);
@@ -5667,8 +5886,8 @@ async function processClaudeTaskResult(codeName, agentId, templateId, rawOutput,
5667
5886
  }
5668
5887
  }
5669
5888
  function fireClaudeWorkTrigger(codeName, agentId, boardItems) {
5670
- const state3 = claudeSchedulerStates.get(codeName) ?? loadSchedulerState(codeName);
5671
- const kanbanTask = findTaskByTemplate(state3, "kanban-work");
5889
+ const state5 = claudeSchedulerStates.get(codeName) ?? loadSchedulerState(codeName);
5890
+ const kanbanTask = findTaskByTemplate(state5, "kanban-work");
5672
5891
  if (!kanbanTask) {
5673
5892
  log(`[claude-scheduler] Work trigger: no kanban-work task found for '${codeName}'`);
5674
5893
  return;
@@ -5691,13 +5910,14 @@ function fireClaudeWorkTrigger(codeName, agentId, boardItems) {
5691
5910
  });
5692
5911
  }
5693
5912
  var persistentSessionAgents = /* @__PURE__ */ new Set();
5913
+ var lastMcpFailedBannerCount = /* @__PURE__ */ new Map();
5694
5914
  var persistentSessionStuckTracker = new PersistentSessionStuckTracker();
5695
5915
  var claudeAuthTupleBySession = /* @__PURE__ */ new Map();
5696
5916
  async function ensurePersistentSession(agent, tasks, boardItems, refreshData) {
5697
5917
  const codeName = agent.code_name;
5698
5918
  const projectDir = getProjectDir(codeName);
5699
- const mcpConfigPath = join4(projectDir, ".mcp.json");
5700
- const claudeMdPath = join4(projectDir, "CLAUDE.md");
5919
+ const mcpConfigPath = join6(projectDir, ".mcp.json");
5920
+ const claudeMdPath = join6(projectDir, "CLAUDE.md");
5701
5921
  if (restartBreaker.isTripped(codeName)) {
5702
5922
  const trip = restartBreaker.getTrip(codeName);
5703
5923
  return {
@@ -5934,9 +6154,9 @@ ${truncateForLog(ctx.tail)}` : `; pane_tail_hash=sha256:${createHash2("sha256").
5934
6154
  } else if (!claudeSchedulerStates.has(codeName)) {
5935
6155
  claudeSchedulerStates.set(codeName, loadSchedulerState(codeName));
5936
6156
  }
5937
- const state3 = claudeSchedulerStates.get(codeName);
5938
- if (state3) {
5939
- const ready = getReadyTasks(state3, inFlightClaudeTasks);
6157
+ const state5 = claudeSchedulerStates.get(codeName);
6158
+ if (state5) {
6159
+ const ready = getReadyTasks(state5, inFlightClaudeTasks);
5940
6160
  if (ready.length > 0) {
5941
6161
  log(`[persistent-session] ${ready.length} ready task(s) for '${codeName}': ${ready.map((t) => `${t.name}(next=${t.nextFireAt ? new Date(t.nextFireAt).toISOString() : "null"})`).join(", ")}`);
5942
6162
  }
@@ -6315,11 +6535,11 @@ ${escapeXml(msg.content)}
6315
6535
  if (fw === "claude-code") {
6316
6536
  const { getProjectDir: ccProjectDir } = await import("../claude-scheduler-XHJS2MZV.js");
6317
6537
  const projDir = ccProjectDir(agent.codeName);
6318
- const mcpConfigPath = join4(projDir, ".mcp.json");
6538
+ const mcpConfigPath = join6(projDir, ".mcp.json");
6319
6539
  const serverNames = [];
6320
- if (existsSync3(mcpConfigPath)) {
6540
+ if (existsSync4(mcpConfigPath)) {
6321
6541
  try {
6322
- const d = JSON.parse(readFileSync3(mcpConfigPath, "utf-8"));
6542
+ const d = JSON.parse(readFileSync5(mcpConfigPath, "utf-8"));
6323
6543
  if (d.mcpServers) serverNames.push(...Object.keys(d.mcpServers));
6324
6544
  } catch {
6325
6545
  }
@@ -6338,15 +6558,15 @@ ${escapeXml(msg.content)}
6338
6558
  "--allowedTools",
6339
6559
  allowedTools
6340
6560
  ];
6341
- const chatClaudeMd = join4(projDir, "CLAUDE.md");
6342
- if (existsSync3(chatClaudeMd)) {
6561
+ const chatClaudeMd = join6(projDir, "CLAUDE.md");
6562
+ if (existsSync4(chatClaudeMd)) {
6343
6563
  chatArgs.push("--system-prompt-file", chatClaudeMd);
6344
6564
  }
6345
- const envIntPath = join4(projDir, ".env.integrations");
6565
+ const envIntPath = join6(projDir, ".env.integrations");
6346
6566
  const childEnv = { ...process.env };
6347
- if (existsSync3(envIntPath)) {
6567
+ if (existsSync4(envIntPath)) {
6348
6568
  try {
6349
- for (const line of readFileSync3(envIntPath, "utf-8").split("\n")) {
6569
+ for (const line of readFileSync5(envIntPath, "utf-8").split("\n")) {
6350
6570
  if (!line || line.startsWith("#") || !line.includes("=")) continue;
6351
6571
  const eqIdx = line.indexOf("=");
6352
6572
  childEnv[line.slice(0, eqIdx)] = line.slice(eqIdx + 1);
@@ -6689,12 +6909,12 @@ function getBuiltInSkillContent(skillId) {
6689
6909
  if (builtInSkillCache.has(skillId)) return builtInSkillCache.get(skillId);
6690
6910
  try {
6691
6911
  const candidates = [
6692
- join4(process.cwd(), "skills", skillId, "SKILL.md"),
6693
- join4(new URL(".", import.meta.url).pathname, "..", "..", "..", "..", "skills", skillId, "SKILL.md")
6912
+ join6(process.cwd(), "skills", skillId, "SKILL.md"),
6913
+ join6(new URL(".", import.meta.url).pathname, "..", "..", "..", "..", "skills", skillId, "SKILL.md")
6694
6914
  ];
6695
6915
  for (const candidate of candidates) {
6696
- if (existsSync3(candidate)) {
6697
- const content = readFileSync3(candidate, "utf-8");
6916
+ if (existsSync4(candidate)) {
6917
+ const content = readFileSync5(candidate, "utf-8");
6698
6918
  const files = [{ relativePath: "SKILL.md", content }];
6699
6919
  builtInSkillCache.set(skillId, files);
6700
6920
  return files;
@@ -7307,7 +7527,7 @@ async function processClaudePairSessions(agents) {
7307
7527
  killPairSession,
7308
7528
  pairTmuxSession,
7309
7529
  finalizeClaudePairOnboarding
7310
- } = await import("../claude-pair-runtime-XCFWTH6T.js");
7530
+ } = await import("../claude-pair-runtime-ZQAJOQPN.js");
7311
7531
  for (const pairId of pendingResp.cancelled_pair_ids ?? []) {
7312
7532
  log(`[claude-pair] sweeping orphan tmux session for pair ${pairId.slice(0, 8)}`);
7313
7533
  const killed = await killPairSession(pairTmuxSession(pairId));
@@ -7602,8 +7822,8 @@ function parseMemoryFile(raw, fallbackName) {
7602
7822
  };
7603
7823
  }
7604
7824
  async function syncMemories(agent, configDir, log2) {
7605
- const projectDir = join4(configDir, agent.code_name, "project");
7606
- const memoryDir = join4(projectDir, "memory");
7825
+ const projectDir = join6(configDir, agent.code_name, "project");
7826
+ const memoryDir = join6(projectDir, "memory");
7607
7827
  const isFreshSync = pendingFreshMemorySync.has(agent.agent_id);
7608
7828
  if (isFreshSync) {
7609
7829
  log2(`[memory-sync] Fresh-sync requested for '${agent.code_name}' \u2014 pulling DB first`);
@@ -7614,14 +7834,14 @@ async function syncMemories(agent, configDir, log2) {
7614
7834
  }
7615
7835
  pendingFreshMemorySync.delete(agent.agent_id);
7616
7836
  }
7617
- if (existsSync3(memoryDir)) {
7837
+ if (existsSync4(memoryDir)) {
7618
7838
  const prevHashes = memoryFileHashes.get(agent.agent_id) ?? /* @__PURE__ */ new Map();
7619
7839
  const currentHashes = /* @__PURE__ */ new Map();
7620
7840
  const changedMemories = [];
7621
- for (const file of readdirSync2(memoryDir)) {
7841
+ for (const file of readdirSync3(memoryDir)) {
7622
7842
  if (!file.endsWith(".md")) continue;
7623
7843
  try {
7624
- const raw = readFileSync3(join4(memoryDir, file), "utf-8");
7844
+ const raw = readFileSync5(join6(memoryDir, file), "utf-8");
7625
7845
  const fileHash = createHash2("sha256").update(raw).digest("hex").slice(0, 16);
7626
7846
  currentHashes.set(file, fileHash);
7627
7847
  if (prevHashes.get(file) === fileHash) continue;
@@ -7646,7 +7866,7 @@ async function syncMemories(agent, configDir, log2) {
7646
7866
  } catch (err) {
7647
7867
  for (const mem of changedMemories) {
7648
7868
  for (const [file] of currentHashes) {
7649
- const parsed = parseMemoryFile(readFileSync3(join4(memoryDir, file), "utf-8"), file.replace(/\.md$/, ""));
7869
+ const parsed = parseMemoryFile(readFileSync5(join6(memoryDir, file), "utf-8"), file.replace(/\.md$/, ""));
7650
7870
  if (parsed?.name === mem.name) currentHashes.delete(file);
7651
7871
  }
7652
7872
  }
@@ -7659,7 +7879,7 @@ async function syncMemories(agent, configDir, log2) {
7659
7879
  }
7660
7880
  }
7661
7881
  async function downloadMemories(agent, memoryDir, log2, { force }) {
7662
- const localFiles = existsSync3(memoryDir) ? readdirSync2(memoryDir).filter((f) => f.endsWith(".md")).sort() : [];
7882
+ const localFiles = existsSync4(memoryDir) ? readdirSync3(memoryDir).filter((f) => f.endsWith(".md")).sort() : [];
7663
7883
  const localListHash = createHash2("sha256").update(localFiles.join(",")).digest("hex").slice(0, 16);
7664
7884
  const prevLocalHash = lastLocalFileHash.get(agent.agent_id);
7665
7885
  const prevDownload = lastDownloadHash.get(agent.agent_id);
@@ -7681,7 +7901,7 @@ async function downloadMemories(agent, memoryDir, log2, { force }) {
7681
7901
  const mem = dbMemories.memories[i];
7682
7902
  const rawSlug = mem.name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/(^-|-$)/g, "").slice(0, 60);
7683
7903
  const slug = rawSlug || `memory-${i}`;
7684
- const filePath = join4(memoryDir, `${slug}.md`);
7904
+ const filePath = join6(memoryDir, `${slug}.md`);
7685
7905
  const desired = `---
7686
7906
  name: ${JSON.stringify(mem.name)}
7687
7907
  type: ${mem.type}
@@ -7690,10 +7910,10 @@ description: ${JSON.stringify(mem.content.slice(0, 200))}
7690
7910
 
7691
7911
  ${mem.content}
7692
7912
  `;
7693
- if (existsSync3(filePath)) {
7913
+ if (existsSync4(filePath)) {
7694
7914
  let existing = "";
7695
7915
  try {
7696
- existing = readFileSync3(filePath, "utf-8");
7916
+ existing = readFileSync5(filePath, "utf-8");
7697
7917
  } catch {
7698
7918
  }
7699
7919
  if (existing === desired) continue;
@@ -7705,7 +7925,7 @@ ${mem.content}
7705
7925
  }
7706
7926
  }
7707
7927
  if (written > 0 || overwritten > 0) {
7708
- const updatedFiles = readdirSync2(memoryDir).filter((f) => f.endsWith(".md")).sort();
7928
+ const updatedFiles = readdirSync3(memoryDir).filter((f) => f.endsWith(".md")).sort();
7709
7929
  lastLocalFileHash.set(agent.agent_id, createHash2("sha256").update(updatedFiles.join(",")).digest("hex").slice(0, 16));
7710
7930
  log2(`Memory download for '${agent.code_name}': wrote ${written} new, overwrote ${overwritten} stale`);
7711
7931
  }
@@ -7717,7 +7937,7 @@ ${mem.content}
7717
7937
  }
7718
7938
  }
7719
7939
  async function cleanupAgentFiles(codeName, agentDir) {
7720
- if (existsSync3(agentDir)) {
7940
+ if (existsSync4(agentDir)) {
7721
7941
  try {
7722
7942
  rmSync2(agentDir, { recursive: true, force: true });
7723
7943
  log(`Removed provision directory for '${codeName}'`);
@@ -7888,12 +8108,12 @@ function startManager(opts) {
7888
8108
  config = opts;
7889
8109
  try {
7890
8110
  const stateFile = getStateFile();
7891
- if (existsSync3(stateFile)) {
7892
- const raw = readFileSync3(stateFile, "utf-8");
8111
+ if (existsSync4(stateFile)) {
8112
+ const raw = readFileSync5(stateFile, "utf-8");
7893
8113
  const parsed = JSON.parse(raw);
7894
8114
  if (Array.isArray(parsed.agents)) {
7895
- state2.agents = parsed.agents;
7896
- log(`[startup] rehydrated ${state2.agents.length} agent state(s) from ${stateFile}`);
8115
+ state4.agents = parsed.agents;
8116
+ log(`[startup] rehydrated ${state4.agents.length} agent state(s) from ${stateFile}`);
7897
8117
  }
7898
8118
  if (parsed.circuitBreakerTrips && typeof parsed.circuitBreakerTrips === "object") {
7899
8119
  restartBreaker.hydrate(parsed.circuitBreakerTrips);
@@ -7905,7 +8125,7 @@ function startManager(opts) {
7905
8125
  log(`[startup] state rehydration failed (continuing with empty state): ${err.message}`);
7906
8126
  }
7907
8127
  log(
7908
- `[startup] worker pid=${process.pid} ppid=${process.ppid} node=${process.version} log=${join4(homedir3(), ".augmented", "manager.log")}`
8128
+ `[startup] worker pid=${process.pid} ppid=${process.ppid} node=${process.version} log=${join6(homedir4(), ".augmented", "manager.log")}`
7909
8129
  );
7910
8130
  warnOnConflictingKanbanModes();
7911
8131
  deployMcpAssets();
@@ -7968,14 +8188,14 @@ function restartRunningChannelMcps(basenames) {
7968
8188
  }
7969
8189
  }
7970
8190
  function deployMcpAssets() {
7971
- const targetDir = join4(homedir3(), ".augmented", "_mcp");
8191
+ const targetDir = join6(homedir4(), ".augmented", "_mcp");
7972
8192
  mkdirSync2(targetDir, { recursive: true });
7973
8193
  const moduleDir = dirname(fileURLToPath(import.meta.url));
7974
8194
  let mcpSourceDir = "";
7975
8195
  let dir = moduleDir;
7976
8196
  for (let i = 0; i < 6; i++) {
7977
- const candidate = join4(dir, "dist", "mcp");
7978
- if (existsSync3(join4(candidate, "index.js"))) {
8197
+ const candidate = join6(dir, "dist", "mcp");
8198
+ if (existsSync4(join6(candidate, "index.js"))) {
7979
8199
  mcpSourceDir = candidate;
7980
8200
  break;
7981
8201
  }
@@ -7990,8 +8210,8 @@ function deployMcpAssets() {
7990
8210
  const changedBasenames = [];
7991
8211
  const fileHash = (p) => {
7992
8212
  try {
7993
- if (!existsSync3(p)) return null;
7994
- return createHash2("sha256").update(readFileSync3(p)).digest("hex");
8213
+ if (!existsSync4(p)) return null;
8214
+ return createHash2("sha256").update(readFileSync5(p)).digest("hex");
7995
8215
  } catch {
7996
8216
  return null;
7997
8217
  }
@@ -8002,9 +8222,9 @@ function deployMcpAssets() {
8002
8222
  "telegram-channel.js"
8003
8223
  ]);
8004
8224
  for (const file of ["index.js", "slack-channel.js", "direct-chat-channel.js", "telegram-channel.js"]) {
8005
- const src = join4(mcpSourceDir, file);
8006
- const dst = join4(targetDir, file);
8007
- if (!existsSync3(src)) continue;
8225
+ const src = join6(mcpSourceDir, file);
8226
+ const dst = join6(targetDir, file);
8227
+ if (!existsSync4(src)) continue;
8008
8228
  const before = fileHash(dst);
8009
8229
  try {
8010
8230
  copyFileSync(src, dst);
@@ -8021,16 +8241,16 @@ function deployMcpAssets() {
8021
8241
  log(`[manager] Bundle(s) updated: ${changedBasenames.join(", ")} \u2014 signalling running instances to restart`);
8022
8242
  restartRunningChannelMcps(changedBasenames);
8023
8243
  }
8024
- const localMcpPath = join4(targetDir, "index.js");
8244
+ const localMcpPath = join6(targetDir, "index.js");
8025
8245
  try {
8026
- const agentsDir = join4(homedir3(), ".augmented", "agents");
8027
- if (existsSync3(agentsDir)) {
8028
- for (const entry of readdirSync2(agentsDir, { withFileTypes: true })) {
8246
+ const agentsDir = join6(homedir4(), ".augmented", "agents");
8247
+ if (existsSync4(agentsDir)) {
8248
+ for (const entry of readdirSync3(agentsDir, { withFileTypes: true })) {
8029
8249
  if (!entry.isDirectory()) continue;
8030
8250
  for (const subdir of ["provision", "project"]) {
8031
- const mcpJsonPath = join4(agentsDir, entry.name, subdir, ".mcp.json");
8251
+ const mcpJsonPath = join6(agentsDir, entry.name, subdir, ".mcp.json");
8032
8252
  try {
8033
- const raw = readFileSync3(mcpJsonPath, "utf-8");
8253
+ const raw = readFileSync5(mcpJsonPath, "utf-8");
8034
8254
  if (!raw.includes("@integrity-labs/augmented-mcp")) continue;
8035
8255
  const mcpConfig = JSON.parse(raw);
8036
8256
  const augServer = mcpConfig.mcpServers?.["augmented"];