@integrity-labs/agt-cli 0.27.85 → 0.27.87

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.
@@ -16,7 +16,7 @@ import {
16
16
  provisionStopHook,
17
17
  requireHost,
18
18
  safeWriteJsonAtomic
19
- } from "../chunk-76NYF2QN.js";
19
+ } from "../chunk-2E42P2IO.js";
20
20
  import {
21
21
  getProjectDir as getProjectDir2,
22
22
  getReadyTasks,
@@ -27,6 +27,7 @@ import {
27
27
  import {
28
28
  buildAllowedTools,
29
29
  checkChannelInputs,
30
+ creditWatchdogGiveUpCount,
30
31
  formatMissingVar,
31
32
  getLastFailureContext,
32
33
  getProjectDir,
@@ -53,7 +54,7 @@ import {
53
54
  stopPersistentSession,
54
55
  takeWatchdogGiveUpCount,
55
56
  takeZombieDetection
56
- } from "../chunk-4LHN3FAL.js";
57
+ } from "../chunk-7EKFVCGY.js";
57
58
  import {
58
59
  KANBAN_CHECK_COMMAND,
59
60
  appendDmFooter,
@@ -84,10 +85,10 @@ import {
84
85
 
85
86
  // src/lib/manager-worker.ts
86
87
  import { createHash as createHash3 } from "crypto";
87
- import { readFileSync as readFileSync8, writeFileSync as writeFileSync4, appendFileSync, mkdirSync as mkdirSync4, chmodSync, existsSync as existsSync5, rmSync as rmSync2, readdirSync as readdirSync3, statSync as statSync2, unlinkSync, copyFileSync } from "fs";
88
+ import { readFileSync as readFileSync9, writeFileSync as writeFileSync4, appendFileSync, mkdirSync as mkdirSync4, chmodSync, existsSync as existsSync5, rmSync as rmSync2, readdirSync as readdirSync4, statSync as statSync3, unlinkSync, copyFileSync } from "fs";
88
89
  import https from "https";
89
90
  import { execFileSync as syncExecFile } from "child_process";
90
- import { join as join7, dirname as dirname3 } from "path";
91
+ import { join as join8, dirname as dirname3 } from "path";
91
92
  import { homedir as homedir4 } from "os";
92
93
  import { fileURLToPath } from "url";
93
94
 
@@ -473,14 +474,14 @@ function reapMissingMcpSessions(args) {
473
474
  if (!missingRaw.includes(key)) liveKeys.add(key);
474
475
  }
475
476
  for (const key of liveKeys) {
476
- const state5 = presenceReaperState.get(stateKey(codeName, key));
477
- if (state5) {
478
- state5.attempts = 0;
479
- state5.lastSeenLiveAt = now();
480
- state5.lastAttemptedSessionStartedAt = null;
481
- state5.gaveUpLogged = false;
482
- state5.firstMissingAt = null;
483
- state5.quarantineLogged = false;
477
+ const state6 = presenceReaperState.get(stateKey(codeName, key));
478
+ if (state6) {
479
+ state6.attempts = 0;
480
+ state6.lastSeenLiveAt = now();
481
+ state6.lastAttemptedSessionStartedAt = null;
482
+ state6.gaveUpLogged = false;
483
+ state6.firstMissingAt = null;
484
+ state6.quarantineLogged = false;
484
485
  }
485
486
  }
486
487
  if (missing.length === 0) {
@@ -498,7 +499,7 @@ function reapMissingMcpSessions(args) {
498
499
  const wouldQuarantine = [];
499
500
  for (const key of missing) {
500
501
  const sk = stateKey(codeName, key);
501
- const state5 = presenceReaperState.get(sk) ?? {
502
+ const state6 = presenceReaperState.get(sk) ?? {
502
503
  attempts: 0,
503
504
  lastSeenLiveAt: null,
504
505
  lastAttemptedSessionStartedAt: null,
@@ -506,19 +507,19 @@ function reapMissingMcpSessions(args) {
506
507
  firstMissingAt: null,
507
508
  quarantineLogged: false
508
509
  };
509
- if (state5.firstMissingAt === null) state5.firstMissingAt = nowMs;
510
- if (state5.lastAttemptedSessionStartedAt !== sessionStartedAt) {
511
- state5.attempts += 1;
512
- state5.lastAttemptedSessionStartedAt = sessionStartedAt;
510
+ if (state6.firstMissingAt === null) state6.firstMissingAt = nowMs;
511
+ if (state6.lastAttemptedSessionStartedAt !== sessionStartedAt) {
512
+ state6.attempts += 1;
513
+ state6.lastAttemptedSessionStartedAt = sessionStartedAt;
513
514
  }
514
- presenceReaperState.set(sk, state5);
515
- if (state5.attempts > MAX_PRESENCE_RESTART_ATTEMPTS) {
515
+ presenceReaperState.set(sk, state6);
516
+ if (state6.attempts > MAX_PRESENCE_RESTART_ATTEMPTS) {
516
517
  givenUp.push(key);
517
- if (!state5.gaveUpLogged) {
518
+ if (!state6.gaveUpLogged) {
518
519
  log2(
519
520
  `[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)`
520
521
  );
521
- state5.gaveUpLogged = true;
522
+ state6.gaveUpLogged = true;
522
523
  if (onGiveUp) {
523
524
  try {
524
525
  onGiveUp(codeName, key);
@@ -529,10 +530,10 @@ function reapMissingMcpSessions(args) {
529
530
  }
530
531
  }
531
532
  }
532
- if (quarantineMode !== "off" && !state5.quarantineLogged && classifyKey(key) === "optional") {
533
- const dwellElapsed = quarantineDwellMs <= 0 || state5.firstMissingAt !== null && nowMs - state5.firstMissingAt >= quarantineDwellMs;
533
+ if (quarantineMode !== "off" && !state6.quarantineLogged && classifyKey(key) === "optional") {
534
+ const dwellElapsed = quarantineDwellMs <= 0 || state6.firstMissingAt !== null && nowMs - state6.firstMissingAt >= quarantineDwellMs;
534
535
  if (dwellElapsed) {
535
- state5.quarantineLogged = true;
536
+ state6.quarantineLogged = true;
536
537
  if (quarantineMode === "enforce") {
537
538
  quarantined.push(key);
538
539
  log2(
@@ -1647,14 +1648,272 @@ async function maybeReportTokenUsage(args) {
1647
1648
  state2.set(codeName, next);
1648
1649
  }
1649
1650
 
1651
+ // src/lib/conversation-evaluator.ts
1652
+ import { readdirSync as readdirSync2, readFileSync as readFileSync5, statSync as statSync2 } from "fs";
1653
+ import { join as join3 } from "path";
1654
+ var MIN_CHECK_INTERVAL_MS3 = 5 * 6e4;
1655
+ var TRANSCRIPT_MTIME_WINDOW_MS2 = 3 * 24 * 60 * 60 * 1e3;
1656
+ var WINDOW_PAD_MS = 5 * 6e4;
1657
+ var MAX_TURN_CHARS = 1500;
1658
+ var MAX_TRANSCRIPT_CHARS = 6e3;
1659
+ var DEFAULT_CLAUDE_EVAL_MODEL = "claude-haiku-4-5-20251001";
1660
+ var DEFAULT_LOCAL_EVAL_URL = "http://localhost:11434/v1/chat/completions";
1661
+ var DEFAULT_LOCAL_EVAL_MODEL = "gemma4:12b";
1662
+ var EVAL_TIMEOUT_MS = 12e4;
1663
+ async function runLocalEvalChat(prompt, opts) {
1664
+ const endpoint = new URL(opts.url);
1665
+ const hostname = endpoint.hostname.toLowerCase();
1666
+ const isLoopback = hostname === "localhost" || hostname === "127.0.0.1" || hostname === "::1" || hostname === "[::1]";
1667
+ if (!isLoopback) {
1668
+ throw new Error(`local eval url must be loopback-only, got host '${endpoint.hostname}'`);
1669
+ }
1670
+ const doFetch = opts.fetchImpl ?? fetch;
1671
+ const res = await doFetch(opts.url, {
1672
+ method: "POST",
1673
+ headers: {
1674
+ "Content-Type": "application/json",
1675
+ ...opts.apiKey ? { Authorization: `Bearer ${opts.apiKey}` } : {}
1676
+ },
1677
+ body: JSON.stringify({
1678
+ model: opts.model,
1679
+ messages: [{ role: "user", content: prompt }],
1680
+ temperature: 0,
1681
+ max_tokens: 512,
1682
+ stream: false
1683
+ }),
1684
+ signal: AbortSignal.timeout(opts.timeoutMs ?? EVAL_TIMEOUT_MS)
1685
+ });
1686
+ if (!res.ok) {
1687
+ throw new Error(`local eval endpoint ${opts.url} returned ${res.status}`);
1688
+ }
1689
+ const data = await res.json();
1690
+ const text = data.choices?.[0]?.message?.content;
1691
+ if (typeof text !== "string" || !text.trim()) {
1692
+ throw new Error("local eval endpoint returned no message content");
1693
+ }
1694
+ return text;
1695
+ }
1696
+ var state3 = /* @__PURE__ */ new Map();
1697
+ function channelRefTokens(channelRef) {
1698
+ return channelRef.split(":").slice(1).filter((p) => p && p !== "dm");
1699
+ }
1700
+ function contentToText(content) {
1701
+ if (typeof content === "string") return content;
1702
+ if (Array.isArray(content)) {
1703
+ return content.map((b) => {
1704
+ if (typeof b === "string") return b;
1705
+ if (b && typeof b === "object" && b.type === "text") {
1706
+ return String(b.text ?? "");
1707
+ }
1708
+ return "";
1709
+ }).filter(Boolean).join(" ");
1710
+ }
1711
+ return "";
1712
+ }
1713
+ function parseTranscriptTurns(jsonl) {
1714
+ const turns = [];
1715
+ for (const line of jsonl.split("\n")) {
1716
+ const trimmed = line.trim();
1717
+ if (!trimmed) continue;
1718
+ let obj;
1719
+ try {
1720
+ obj = JSON.parse(trimmed);
1721
+ } catch {
1722
+ continue;
1723
+ }
1724
+ const role = obj.type === "user" || obj.type === "assistant" ? obj.type : void 0;
1725
+ if (!role) continue;
1726
+ const text = contentToText(obj.message?.content).trim();
1727
+ if (!text) continue;
1728
+ const ts = obj.timestamp ? Date.parse(obj.timestamp) : NaN;
1729
+ turns.push({ role, text, ts: Number.isFinite(ts) ? ts : 0 });
1730
+ }
1731
+ return turns;
1732
+ }
1733
+ function stripChannelTag(text) {
1734
+ return text.replace(/<channel\b[^>]*\/?>/i, "").replace(/<\/channel>/i, "").trim();
1735
+ }
1736
+ function reconstructConversation(allTurns, tokens, windowStartMs, windowEndMs) {
1737
+ if (tokens.length === 0) return [];
1738
+ const sorted = [...allTurns].sort((a, b) => a.ts - b.ts);
1739
+ const out = [];
1740
+ let inConversation = false;
1741
+ for (const turn of sorted) {
1742
+ if (turn.ts && (turn.ts < windowStartMs || turn.ts > windowEndMs)) continue;
1743
+ if (turn.role === "user") {
1744
+ inConversation = tokens.every((t) => turn.text.includes(t));
1745
+ if (inConversation) {
1746
+ out.push({ ...turn, text: stripChannelTag(turn.text) });
1747
+ }
1748
+ } else if (inConversation) {
1749
+ out.push(turn);
1750
+ }
1751
+ }
1752
+ return out;
1753
+ }
1754
+ function renderTranscript(turns) {
1755
+ const lines = [];
1756
+ let total = 0;
1757
+ for (const turn of turns) {
1758
+ const label = turn.role === "user" ? "User" : "Agent";
1759
+ const body = turn.text.length > MAX_TURN_CHARS ? `${turn.text.slice(0, MAX_TURN_CHARS)}\u2026` : turn.text;
1760
+ const line = `${label}: ${body}`;
1761
+ if (total + line.length > MAX_TRANSCRIPT_CHARS) break;
1762
+ lines.push(line);
1763
+ total += line.length;
1764
+ }
1765
+ return lines.join("\n\n");
1766
+ }
1767
+ function buildEvalPrompt(channel, transcript) {
1768
+ return `You are a strict QA evaluator scoring whether an AI agent successfully helped an end-user in a single ${channel} conversation. Judge ONLY the agent's effectiveness for the user \u2014 not tone, length, or policy.
1769
+
1770
+ Conversation transcript:
1771
+ """
1772
+ ${transcript}
1773
+ """
1774
+
1775
+ Score the agent's success:
1776
+ - score: integer 0-100 (0 = ignored/unhelpful/wrong, 100 = fully resolved the user's need)
1777
+ - verdict: "success" (need clearly met), "partial" (some help but incomplete/ambiguous), or "failure" (did not help / made it worse)
1778
+ - summary: ONE short sentence (max 140 chars) explaining the score. Do NOT quote sensitive user content.
1779
+
1780
+ Respond with ONLY a JSON object, no other text:
1781
+ {"score": 0-100, "verdict": "success|partial|failure", "summary": "..."}`;
1782
+ }
1783
+ function parseVerdict(raw) {
1784
+ const match = raw.match(/\{[\s\S]*\}/);
1785
+ if (!match) return null;
1786
+ let obj;
1787
+ try {
1788
+ obj = JSON.parse(match[0]);
1789
+ } catch {
1790
+ return null;
1791
+ }
1792
+ const score = typeof obj.score === "number" ? obj.score : Number(obj.score);
1793
+ if (!Number.isFinite(score) || score < 0 || score > 100) return null;
1794
+ if (obj.verdict !== "success" && obj.verdict !== "partial" && obj.verdict !== "failure") return null;
1795
+ const summary = typeof obj.summary === "string" ? obj.summary.slice(0, 140) : "";
1796
+ return { score: Math.round(score), verdict: obj.verdict, summary };
1797
+ }
1798
+ async function maybeEvaluateConversations(args) {
1799
+ const { api: api2, backend, codeName, agentId, log: log2 } = args;
1800
+ const now = args.now ?? /* @__PURE__ */ new Date();
1801
+ const nowMs = now.getTime();
1802
+ const existing = state3.get(codeName);
1803
+ if (existing && nowMs - existing.lastCheckedAt < MIN_CHECK_INTERVAL_MS3) {
1804
+ return;
1805
+ }
1806
+ state3.set(codeName, { lastCheckedAt: nowMs });
1807
+ let pending;
1808
+ try {
1809
+ const resp = await api2.get(
1810
+ `/host/conversations/pending-evaluation?agent_id=${encodeURIComponent(agentId)}`
1811
+ );
1812
+ pending = resp?.conversations ?? [];
1813
+ } catch (err) {
1814
+ log2(`[conversation-eval] ${codeName}: pending fetch failed: ${err.message}`);
1815
+ return;
1816
+ }
1817
+ if (pending.length === 0) return;
1818
+ const dir = args.transcriptDir ?? sessionTranscriptDir(getProjectDir(codeName));
1819
+ const allTurns = readRecentTurns(dir, nowMs);
1820
+ if (allTurns.length === 0) {
1821
+ for (const conv of pending) {
1822
+ await reportSkip(api2, agentId, conv.conversation_id, log2, codeName);
1823
+ }
1824
+ return;
1825
+ }
1826
+ for (const conv of pending) {
1827
+ const tokens = channelRefTokens(conv.channel_ref);
1828
+ const windowStart = Date.parse(conv.started_at) - WINDOW_PAD_MS;
1829
+ const windowEnd = Date.parse(conv.last_message_at) + WINDOW_PAD_MS;
1830
+ const turns = reconstructConversation(allTurns, tokens, windowStart, windowEnd);
1831
+ if (turns.length === 0) {
1832
+ await reportSkip(api2, agentId, conv.conversation_id, log2, codeName);
1833
+ continue;
1834
+ }
1835
+ const transcript = renderTranscript(turns);
1836
+ if (!transcript.trim()) {
1837
+ await reportSkip(api2, agentId, conv.conversation_id, log2, codeName);
1838
+ continue;
1839
+ }
1840
+ let verdict;
1841
+ try {
1842
+ const out = await backend.run(buildEvalPrompt(conv.channel, transcript));
1843
+ verdict = parseVerdict(out);
1844
+ } catch (err) {
1845
+ log2(`[conversation-eval] ${codeName}: scoring failed: ${err.message}`);
1846
+ continue;
1847
+ }
1848
+ if (!verdict) {
1849
+ log2(`[conversation-eval] ${codeName}: unparseable verdict for ${conv.conversation_id.slice(0, 8)}`);
1850
+ continue;
1851
+ }
1852
+ try {
1853
+ await api2.post("/host/conversations/evaluation", {
1854
+ agent_id: agentId,
1855
+ conversation_id: conv.conversation_id,
1856
+ score: verdict.score,
1857
+ verdict: verdict.verdict,
1858
+ summary: verdict.summary,
1859
+ model: backend.model
1860
+ });
1861
+ log2(
1862
+ `[conversation-eval] ${codeName}: ${conv.conversation_id.slice(0, 8)} \u2192 ${verdict.verdict} (${verdict.score})`
1863
+ );
1864
+ } catch (err) {
1865
+ log2(`[conversation-eval] ${codeName}: report failed: ${err.message}`);
1866
+ }
1867
+ }
1868
+ }
1869
+ async function reportSkip(api2, agentId, conversationId, log2, codeName) {
1870
+ try {
1871
+ await api2.post("/host/conversations/evaluation", {
1872
+ agent_id: agentId,
1873
+ conversation_id: conversationId,
1874
+ skipped: true
1875
+ });
1876
+ } catch (err) {
1877
+ log2(`[conversation-eval] ${codeName}: skip report failed: ${err.message}`);
1878
+ }
1879
+ }
1880
+ function readRecentTurns(dir, nowMs) {
1881
+ let entries;
1882
+ try {
1883
+ entries = readdirSync2(dir);
1884
+ } catch {
1885
+ return [];
1886
+ }
1887
+ const turns = [];
1888
+ for (const name of entries) {
1889
+ if (!name.endsWith(".jsonl")) continue;
1890
+ const full = join3(dir, name);
1891
+ let mtimeMs;
1892
+ try {
1893
+ mtimeMs = statSync2(full).mtimeMs;
1894
+ } catch {
1895
+ continue;
1896
+ }
1897
+ if (nowMs - mtimeMs > TRANSCRIPT_MTIME_WINDOW_MS2) continue;
1898
+ let content;
1899
+ try {
1900
+ content = readFileSync5(full, "utf8");
1901
+ } catch {
1902
+ continue;
1903
+ }
1904
+ turns.push(...parseTranscriptTurns(content));
1905
+ }
1906
+ return turns;
1907
+ }
1908
+
1650
1909
  // src/lib/activity-cache-monitor.ts
1651
- import { existsSync as existsSync2, readFileSync as readFileSync5 } from "fs";
1910
+ import { existsSync as existsSync2, readFileSync as readFileSync6 } from "fs";
1652
1911
  import { homedir } from "os";
1653
- import { join as join3 } from "path";
1654
- var MIN_CHECK_INTERVAL_MS3 = 6e4;
1655
- var STATS_CACHE_PATH = join3(homedir(), ".claude", "stats-cache.json");
1912
+ import { join as join4 } from "path";
1913
+ var MIN_CHECK_INTERVAL_MS4 = 6e4;
1914
+ var STATS_CACHE_PATH = join4(homedir(), ".claude", "stats-cache.json");
1656
1915
  var ISO_DATE_RE = /^\d{4}-\d{2}-\d{2}$/;
1657
- var state3 = { lastObservedDate: null, lastCheckedAt: 0 };
1916
+ var state4 = { lastObservedDate: null, lastCheckedAt: 0 };
1658
1917
  function selectNewDailyRows(raw, lastObservedDate) {
1659
1918
  let parsed;
1660
1919
  try {
@@ -1693,24 +1952,24 @@ async function maybeReportActivityCache(args) {
1693
1952
  const { api: api2, log: log2 } = args;
1694
1953
  const now = args.now ?? /* @__PURE__ */ new Date();
1695
1954
  const nowMs = now.getTime();
1696
- if (nowMs - state3.lastCheckedAt < MIN_CHECK_INTERVAL_MS3) return;
1697
- state3.lastCheckedAt = nowMs;
1955
+ if (nowMs - state4.lastCheckedAt < MIN_CHECK_INTERVAL_MS4) return;
1956
+ state4.lastCheckedAt = nowMs;
1698
1957
  if (!existsSync2(STATS_CACHE_PATH)) {
1699
1958
  return;
1700
1959
  }
1701
1960
  let raw;
1702
1961
  try {
1703
- raw = readFileSync5(STATS_CACHE_PATH, "utf-8");
1962
+ raw = readFileSync6(STATS_CACHE_PATH, "utf-8");
1704
1963
  } catch (err) {
1705
1964
  log2(`[activity-cache] readFileSync failed: ${err.message}`);
1706
1965
  return;
1707
1966
  }
1708
- const rows = selectNewDailyRows(raw, state3.lastObservedDate);
1967
+ const rows = selectNewDailyRows(raw, state4.lastObservedDate);
1709
1968
  if (rows.length === 0) return;
1710
1969
  for (const row of rows) {
1711
1970
  try {
1712
1971
  await api2.post("/host/activity-observations", row);
1713
- state3.lastObservedDate = row.date;
1972
+ state4.lastObservedDate = row.date;
1714
1973
  } catch (err) {
1715
1974
  log2(
1716
1975
  `[activity-cache] POST /host/activity-observations failed for date=${row.date}: ${err.message}`
@@ -2150,7 +2409,7 @@ var GatewayClientPool = class extends EventEmitter {
2150
2409
  // src/lib/claude-auth-detect.ts
2151
2410
  import { readFile, readdir } from "fs/promises";
2152
2411
  import { homedir as homedir2, platform } from "os";
2153
- import { join as join4 } from "path";
2412
+ import { join as join5 } from "path";
2154
2413
  import { execFile as execFile2 } from "child_process";
2155
2414
  import { promisify } from "util";
2156
2415
  var execFileAsync = promisify(execFile2);
@@ -2165,8 +2424,8 @@ async function detectClaudeAuth() {
2165
2424
  }
2166
2425
  async function findClaudeCredentialsPaths() {
2167
2426
  const candidates = [
2168
- join4(homedir2(), ".claude", ".credentials.json"),
2169
- join4(homedir2(), ".claude", "credentials.json")
2427
+ join5(homedir2(), ".claude", ".credentials.json"),
2428
+ join5(homedir2(), ".claude", "credentials.json")
2170
2429
  ];
2171
2430
  const isLinuxRoot = platform() === "linux" && typeof process.getuid === "function" && process.getuid() === 0;
2172
2431
  if (isLinuxRoot) {
@@ -2174,8 +2433,8 @@ async function findClaudeCredentialsPaths() {
2174
2433
  const entries = await readdir("/home", { withFileTypes: true });
2175
2434
  for (const entry of entries) {
2176
2435
  if (!entry.isDirectory()) continue;
2177
- candidates.push(join4("/home", entry.name, ".claude", ".credentials.json"));
2178
- candidates.push(join4("/home", entry.name, ".claude", "credentials.json"));
2436
+ candidates.push(join5("/home", entry.name, ".claude", ".credentials.json"));
2437
+ candidates.push(join5("/home", entry.name, ".claude", "credentials.json"));
2179
2438
  }
2180
2439
  } catch {
2181
2440
  }
@@ -2267,18 +2526,18 @@ function normalize(value) {
2267
2526
  }
2268
2527
 
2269
2528
  // src/lib/channel-hash-cache.ts
2270
- import { existsSync as existsSync3, readFileSync as readFileSync6, writeFileSync as writeFileSync2 } from "fs";
2271
- import { join as join5 } from "path";
2529
+ import { existsSync as existsSync3, readFileSync as readFileSync7, writeFileSync as writeFileSync2 } from "fs";
2530
+ import { join as join6 } from "path";
2272
2531
  var CACHE_FILENAME = "channel-hash-cache.json";
2273
2532
  function getChannelHashCacheFile(configDir) {
2274
- return join5(configDir, CACHE_FILENAME);
2533
+ return join6(configDir, CACHE_FILENAME);
2275
2534
  }
2276
2535
  function loadChannelHashCache(target, configDir) {
2277
2536
  const path = getChannelHashCacheFile(configDir);
2278
2537
  if (!existsSync3(path)) return;
2279
2538
  let parsed;
2280
2539
  try {
2281
- parsed = JSON.parse(readFileSync6(path, "utf-8"));
2540
+ parsed = JSON.parse(readFileSync7(path, "utf-8"));
2282
2541
  } catch {
2283
2542
  return;
2284
2543
  }
@@ -2732,24 +2991,24 @@ function clearAgentState(agentId, codeName) {
2732
2991
  }
2733
2992
 
2734
2993
  // src/lib/restart-flags.ts
2735
- import { existsSync as existsSync4, mkdirSync as mkdirSync3, readdirSync as readdirSync2, readFileSync as readFileSync7, renameSync as renameSync2, rmSync, writeFileSync as writeFileSync3 } from "fs";
2994
+ import { existsSync as existsSync4, mkdirSync as mkdirSync3, readdirSync as readdirSync3, readFileSync as readFileSync8, renameSync as renameSync2, rmSync, writeFileSync as writeFileSync3 } from "fs";
2736
2995
  import { homedir as homedir3 } from "os";
2737
- import { join as join6 } from "path";
2996
+ import { join as join7 } from "path";
2738
2997
  import { randomUUID } from "crypto";
2739
2998
  function restartFlagsDir() {
2740
- return join6(homedir3(), ".augmented", "restart-flags");
2999
+ return join7(homedir3(), ".augmented", "restart-flags");
2741
3000
  }
2742
3001
  function flagPath(codeName) {
2743
- return join6(restartFlagsDir(), `${codeName}.flag`);
3002
+ return join7(restartFlagsDir(), `${codeName}.flag`);
2744
3003
  }
2745
3004
  function readRestartFlags() {
2746
3005
  const dir = restartFlagsDir();
2747
3006
  if (!existsSync4(dir)) return [];
2748
3007
  const out = [];
2749
- for (const entry of readdirSync2(dir)) {
3008
+ for (const entry of readdirSync3(dir)) {
2750
3009
  if (!entry.endsWith(".flag")) continue;
2751
3010
  try {
2752
- const raw = readFileSync7(join6(dir, entry), "utf8");
3011
+ const raw = readFileSync8(join7(dir, entry), "utf8");
2753
3012
  const parsed = JSON.parse(raw);
2754
3013
  if (typeof parsed.codeName !== "string" || parsed.codeName.length === 0) {
2755
3014
  parsed.codeName = entry.replace(/\.flag$/, "");
@@ -3296,8 +3555,8 @@ function applyRestartAcks(args) {
3296
3555
  var GATEWAY_PORT_BASE = 18800;
3297
3556
  var GATEWAY_PORT_STEP = 10;
3298
3557
  var GATEWAY_PORT_MAX = 18899;
3299
- var AUGMENTED_DIR = join7(process.env["HOME"] ?? "/tmp", ".augmented");
3300
- var GATEWAY_PORTS_FILE = join7(AUGMENTED_DIR, "gateway-ports.json");
3558
+ var AUGMENTED_DIR = join8(process.env["HOME"] ?? "/tmp", ".augmented");
3559
+ var GATEWAY_PORTS_FILE = join8(AUGMENTED_DIR, "gateway-ports.json");
3301
3560
  var CHANNEL_SWEEP_INTERVAL_MS = (() => {
3302
3561
  const raw = parseInt(process.env["AGT_CHANNEL_SWEEP_INTERVAL_MS"] ?? "", 10);
3303
3562
  if (!Number.isFinite(raw)) return 5 * 60 * 1e3;
@@ -3404,8 +3663,8 @@ var KNOWN_SAFE_TAIL_SIGNATURES = /* @__PURE__ */ new Set(["session_id_in_use"]);
3404
3663
  function shouldSkipRevokedCleanup(previousKnownStatus) {
3405
3664
  return previousKnownStatus === "revoked";
3406
3665
  }
3407
- function hasRevokedResiduals(state5) {
3408
- return state5.gatewayRunning || state5.portAllocated || state5.provisionDirExists;
3666
+ function hasRevokedResiduals(state6) {
3667
+ return state6.gatewayRunning || state6.portAllocated || state6.provisionDirExists;
3409
3668
  }
3410
3669
  var pendingSessionRestarts = /* @__PURE__ */ new Map();
3411
3670
  var restartBreaker = new RestartBreaker();
@@ -3482,7 +3741,7 @@ function inboundAgeSecondsFor(codeName) {
3482
3741
  }
3483
3742
  function paneLogAgeSecondsFor(codeName) {
3484
3743
  try {
3485
- const mtimeMs = statSync2(paneLogPath(codeName)).mtimeMs;
3744
+ const mtimeMs = statSync3(paneLogPath(codeName)).mtimeMs;
3486
3745
  return Math.max(0, Math.floor((Date.now() - mtimeMs) / 1e3));
3487
3746
  } catch (err) {
3488
3747
  if (err?.code === "ENOENT") return null;
@@ -3502,7 +3761,7 @@ var runningMcpHashes = /* @__PURE__ */ new Map();
3502
3761
  var runningMcpServerKeys = /* @__PURE__ */ new Map();
3503
3762
  function projectMcpHash(_codeName, projectDir) {
3504
3763
  try {
3505
- const raw = readFileSync8(join7(projectDir, ".mcp.json"), "utf-8");
3764
+ const raw = readFileSync9(join8(projectDir, ".mcp.json"), "utf-8");
3506
3765
  return createHash3("sha256").update(canonicalJson(JSON.parse(raw))).digest("hex");
3507
3766
  } catch {
3508
3767
  return null;
@@ -3510,7 +3769,7 @@ function projectMcpHash(_codeName, projectDir) {
3510
3769
  }
3511
3770
  function projectMcpKeys(_codeName, projectDir) {
3512
3771
  try {
3513
- const raw = readFileSync8(join7(projectDir, ".mcp.json"), "utf-8");
3772
+ const raw = readFileSync9(join8(projectDir, ".mcp.json"), "utf-8");
3514
3773
  const parsed = JSON.parse(raw);
3515
3774
  const servers = parsed.mcpServers;
3516
3775
  if (!servers || typeof servers !== "object") return /* @__PURE__ */ new Set();
@@ -3521,7 +3780,7 @@ function projectMcpKeys(_codeName, projectDir) {
3521
3780
  }
3522
3781
  function readMcpHttpServerConfig(projectDir, serverKey) {
3523
3782
  try {
3524
- const raw = readFileSync8(join7(projectDir, ".mcp.json"), "utf-8");
3783
+ const raw = readFileSync9(join8(projectDir, ".mcp.json"), "utf-8");
3525
3784
  const servers = JSON.parse(raw).mcpServers ?? {};
3526
3785
  const entry = servers[serverKey];
3527
3786
  if (entry && typeof entry.url === "string" && (entry.type === "http" || entry.type === void 0)) {
@@ -3674,7 +3933,7 @@ var taskDisplayInfo = /* @__PURE__ */ new Map();
3674
3933
  var agentChannelTokens = /* @__PURE__ */ new Map();
3675
3934
  var activeChannels = /* @__PURE__ */ new Map();
3676
3935
  var gatewaysStartedThisCycle = /* @__PURE__ */ new Set();
3677
- var state4 = {
3936
+ var state5 = {
3678
3937
  pid: process.pid,
3679
3938
  startedAt: (/* @__PURE__ */ new Date()).toISOString(),
3680
3939
  lastPollAt: null,
@@ -3713,7 +3972,7 @@ var cachedMaintenanceWindow = null;
3713
3972
  var lastVersionCheckAt = 0;
3714
3973
  var VERSION_CHECK_INTERVAL_MS = 5 * 60 * 1e3;
3715
3974
  var lastResponsivenessProbeAt = 0;
3716
- var agtCliVersion = true ? "0.27.85" : "dev";
3975
+ var agtCliVersion = true ? "0.27.87" : "dev";
3717
3976
  function resolveBrewPath(execFileSync4) {
3718
3977
  try {
3719
3978
  const out = execFileSync4("which", ["brew"], { timeout: 5e3 }).toString().trim();
@@ -3890,7 +4149,7 @@ function ensureClaudeManagedSettings(path = claudeManagedSettingsPath()) {
3890
4149
  try {
3891
4150
  let settings = {};
3892
4151
  if (existsSync5(path)) {
3893
- const raw = readFileSync8(path, "utf-8").trim();
4152
+ const raw = readFileSync9(path, "utf-8").trim();
3894
4153
  if (raw) {
3895
4154
  let parsed;
3896
4155
  try {
@@ -3962,7 +4221,7 @@ async function ensureFrameworkBinary(frameworkId) {
3962
4221
  var CLAUDE_CODE_UPGRADE_CHECK_INTERVAL_MS = 24 * 60 * 60 * 1e3;
3963
4222
  var claudeCodeUpgradeInFlight = false;
3964
4223
  function claudeCodeUpgradeMarkerPath() {
3965
- return join7(homedir4(), ".augmented", ".last-claude-code-upgrade-check");
4224
+ return join8(homedir4(), ".augmented", ".last-claude-code-upgrade-check");
3966
4225
  }
3967
4226
  function stampClaudeCodeUpgradeMarker() {
3968
4227
  try {
@@ -3972,7 +4231,7 @@ function stampClaudeCodeUpgradeMarker() {
3972
4231
  }
3973
4232
  function claudeCodeUpgradeThrottled() {
3974
4233
  try {
3975
- const lastCheck = parseInt(readFileSync8(claudeCodeUpgradeMarkerPath(), "utf-8").trim(), 10);
4234
+ const lastCheck = parseInt(readFileSync9(claudeCodeUpgradeMarkerPath(), "utf-8").trim(), 10);
3976
4235
  if (!Number.isFinite(lastCheck)) return false;
3977
4236
  return Date.now() - lastCheck < CLAUDE_CODE_UPGRADE_CHECK_INTERVAL_MS;
3978
4237
  } catch {
@@ -4025,7 +4284,7 @@ ${r.stderr}`;
4025
4284
  }
4026
4285
  var UPDATE_CHECK_INTERVAL_MS = 5 * 60 * 1e3;
4027
4286
  function selfUpdateAppliedMarkerPath() {
4028
- return join7(homedir4(), ".augmented", ".last-self-update-applied");
4287
+ return join8(homedir4(), ".augmented", ".last-self-update-applied");
4029
4288
  }
4030
4289
  var selfUpdateUpToDateLogged = false;
4031
4290
  var restartAfterUpgrade = false;
@@ -4048,7 +4307,7 @@ async function checkAndUpdateCli() {
4048
4307
  const isNpmGlobal = !isBrewFormula && resolvedPath.includes("node_modules");
4049
4308
  if (!isBrewFormula && !isNpmGlobal) return;
4050
4309
  const { readFileSync: readF, writeFileSync: writeF } = await import("fs");
4051
- const markerPath = join7(homedir4(), ".augmented", ".last-update-check");
4310
+ const markerPath = join8(homedir4(), ".augmented", ".last-update-check");
4052
4311
  try {
4053
4312
  const lastCheck = parseInt(readF(markerPath, "utf-8").trim(), 10);
4054
4313
  if (Date.now() - lastCheck < UPDATE_CHECK_INTERVAL_MS) return;
@@ -4305,9 +4564,9 @@ async function applyClaudeAuthToEnv(childEnv, label) {
4305
4564
  throw new Error("claude_auth_mode=api_key but /host/exchange returned no decrypted key");
4306
4565
  }
4307
4566
  childEnv.ANTHROPIC_API_KEY = exchange.anthropicApiKey;
4308
- const claudeDir = join7(homedir4(), ".claude");
4567
+ const claudeDir = join8(homedir4(), ".claude");
4309
4568
  for (const filename of [".credentials.json", "credentials.json"]) {
4310
- const p = join7(claudeDir, filename);
4569
+ const p = join8(claudeDir, filename);
4311
4570
  if (existsSync5(p)) {
4312
4571
  try {
4313
4572
  rmSync2(p, { force: true });
@@ -4320,9 +4579,86 @@ async function applyClaudeAuthToEnv(childEnv, label) {
4320
4579
  delete childEnv.ANTHROPIC_API_KEY;
4321
4580
  }
4322
4581
  }
4582
+ var evalEmptyMcpConfigPath = null;
4583
+ function ensureEvalEmptyMcpConfig() {
4584
+ if (evalEmptyMcpConfigPath && existsSync5(evalEmptyMcpConfigPath)) return evalEmptyMcpConfigPath;
4585
+ const dir = join8(homedir4(), ".augmented");
4586
+ try {
4587
+ mkdirSync4(dir, { recursive: true });
4588
+ } catch {
4589
+ }
4590
+ const p = join8(dir, ".eval-empty-mcp.json");
4591
+ writeFileSync4(p, JSON.stringify({ mcpServers: {} }));
4592
+ evalEmptyMcpConfigPath = p;
4593
+ return p;
4594
+ }
4595
+ async function runEvalClaude(prompt, model) {
4596
+ const childEnv = { ...process.env };
4597
+ await applyClaudeAuthToEnv(childEnv, "conversation-eval");
4598
+ const emptyMcp = ensureEvalEmptyMcpConfig();
4599
+ const args = [
4600
+ "-p",
4601
+ prompt,
4602
+ "--model",
4603
+ model,
4604
+ "--output-format",
4605
+ "text",
4606
+ // Isolation: only the empty MCP config, ignore project/user config + no tools.
4607
+ "--mcp-config",
4608
+ emptyMcp,
4609
+ "--strict-mcp-config",
4610
+ "--permission-mode",
4611
+ "auto",
4612
+ "--allowedTools",
4613
+ ""
4614
+ ];
4615
+ const { stdout } = await execFilePromiseLong(resolveClaudeBinary(), args, {
4616
+ cwd: homedir4(),
4617
+ timeout: 12e4,
4618
+ stdin: "ignore",
4619
+ env: childEnv,
4620
+ onSpawn: (pid) => registerClaudeSpawn({ pid, started_at: Date.now(), kind: "other" }),
4621
+ onExit: (pid) => unregisterClaudeSpawn(pid)
4622
+ });
4623
+ return stdout;
4624
+ }
4625
+ var conversationEvalBackend = null;
4626
+ function resolveConversationEvalBackend() {
4627
+ if (conversationEvalBackend) return conversationEvalBackend;
4628
+ const kind = (process.env["AGT_CONV_EVAL_BACKEND"] ?? "claude-p").trim().toLowerCase();
4629
+ if (kind === "local") {
4630
+ const url = process.env["AGT_CONV_EVAL_LOCAL_URL"]?.trim() || DEFAULT_LOCAL_EVAL_URL;
4631
+ const model = process.env["AGT_CONV_EVAL_LOCAL_MODEL"]?.trim() || DEFAULT_LOCAL_EVAL_MODEL;
4632
+ const apiKey = process.env["AGT_CONV_EVAL_LOCAL_API_KEY"]?.trim() || void 0;
4633
+ const safeUrl = (() => {
4634
+ try {
4635
+ const parsed = new URL(url);
4636
+ return `${parsed.origin}${parsed.pathname}`;
4637
+ } catch {
4638
+ return "[invalid-url]";
4639
+ }
4640
+ })();
4641
+ log(`[conversation-eval] backend=local url=${safeUrl} model=${model}`);
4642
+ conversationEvalBackend = { model, run: (prompt) => runLocalEvalChat(prompt, { url, model, apiKey }) };
4643
+ return conversationEvalBackend;
4644
+ }
4645
+ if (kind === "" || kind === "claude-p") {
4646
+ const model = process.env["AGT_CONV_EVAL_CLAUDE_MODEL"]?.trim() || DEFAULT_CLAUDE_EVAL_MODEL;
4647
+ conversationEvalBackend = { model, run: (prompt) => runEvalClaude(prompt, model) };
4648
+ return conversationEvalBackend;
4649
+ }
4650
+ log(`[conversation-eval] invalid AGT_CONV_EVAL_BACKEND='${kind}' \u2014 expected 'claude-p' or 'local'; evaluation disabled`);
4651
+ conversationEvalBackend = {
4652
+ model: "invalid-conversation-eval-backend",
4653
+ run: async () => {
4654
+ throw new Error(`Unsupported AGT_CONV_EVAL_BACKEND='${kind}'. Expected 'claude-p' or 'local'.`);
4655
+ }
4656
+ };
4657
+ return conversationEvalBackend;
4658
+ }
4323
4659
  function loadGatewayPorts() {
4324
4660
  try {
4325
- return JSON.parse(readFileSync8(GATEWAY_PORTS_FILE, "utf-8"));
4661
+ return JSON.parse(readFileSync9(GATEWAY_PORTS_FILE, "utf-8"));
4326
4662
  } catch {
4327
4663
  return {};
4328
4664
  }
@@ -4352,10 +4688,10 @@ function freePort(codeName) {
4352
4688
  }
4353
4689
  }
4354
4690
  function getStateFile() {
4355
- return join7(config?.configDir ?? join7(process.env["HOME"] ?? "/tmp", ".augmented"), "manager-state.json");
4691
+ return join8(config?.configDir ?? join8(process.env["HOME"] ?? "/tmp", ".augmented"), "manager-state.json");
4356
4692
  }
4357
4693
  function channelHashCacheDir() {
4358
- return config?.configDir ?? join7(process.env["HOME"] ?? "/tmp", ".augmented");
4694
+ return config?.configDir ?? join8(process.env["HOME"] ?? "/tmp", ".augmented");
4359
4695
  }
4360
4696
  function loadChannelHashCache2() {
4361
4697
  loadChannelHashCache(agentState.knownChannelConfigHashes, channelHashCacheDir());
@@ -4366,7 +4702,7 @@ function saveChannelHashCache2() {
4366
4702
  var _channelQuarantineStore = null;
4367
4703
  function channelQuarantineStore() {
4368
4704
  if (!_channelQuarantineStore) {
4369
- const dir = config?.configDir ?? join7(process.env["HOME"] ?? "/tmp", ".augmented");
4705
+ const dir = config?.configDir ?? join8(process.env["HOME"] ?? "/tmp", ".augmented");
4370
4706
  _channelQuarantineStore = new ChannelQuarantineStore(defaultQuarantinePath(dir));
4371
4707
  }
4372
4708
  return _channelQuarantineStore;
@@ -4421,7 +4757,7 @@ function log(msg) {
4421
4757
  `;
4422
4758
  if (!managerLogPath) {
4423
4759
  try {
4424
- managerLogPath = join7(homedir4(), ".augmented", "manager.log");
4760
+ managerLogPath = join8(homedir4(), ".augmented", "manager.log");
4425
4761
  mkdirSync4(dirname3(managerLogPath), { recursive: true });
4426
4762
  if (existsSync5(managerLogPath)) {
4427
4763
  chmodSync(managerLogPath, 384);
@@ -4451,7 +4787,7 @@ function sha256(content) {
4451
4787
  }
4452
4788
  function hashFile(filePath) {
4453
4789
  try {
4454
- const content = readFileSync8(filePath, "utf-8");
4790
+ const content = readFileSync9(filePath, "utf-8");
4455
4791
  return sha256(content);
4456
4792
  } catch {
4457
4793
  return null;
@@ -4475,13 +4811,13 @@ function parseSkillFrontmatter(content) {
4475
4811
  return out;
4476
4812
  }
4477
4813
  async function refreshSkillsIndexInClaudeMd(configDir, codeName, log2) {
4478
- const { readdirSync: readdirSync4, readFileSync: rfs, existsSync: ex, writeFileSync: writeFileSync5 } = await import("fs");
4479
- const skillsDir = join7(configDir, codeName, "project", ".claude", "skills");
4480
- const claudeMdPath = join7(configDir, codeName, "project", "CLAUDE.md");
4814
+ const { readdirSync: readdirSync5, readFileSync: rfs, existsSync: ex, writeFileSync: writeFileSync5 } = await import("fs");
4815
+ const skillsDir = join8(configDir, codeName, "project", ".claude", "skills");
4816
+ const claudeMdPath = join8(configDir, codeName, "project", "CLAUDE.md");
4481
4817
  if (!ex(skillsDir) || !ex(claudeMdPath)) return;
4482
4818
  const entries = [];
4483
- for (const dir of readdirSync4(skillsDir).sort()) {
4484
- const skillFile = join7(skillsDir, dir, "SKILL.md");
4819
+ for (const dir of readdirSync5(skillsDir).sort()) {
4820
+ const skillFile = join8(skillsDir, dir, "SKILL.md");
4485
4821
  if (!ex(skillFile)) continue;
4486
4822
  try {
4487
4823
  const { name, description } = parseSkillFrontmatter(rfs(skillFile, "utf-8"));
@@ -4529,10 +4865,10 @@ ${SKILLS_INDEX_END}`;
4529
4865
  }
4530
4866
  async function migrateToProfiles() {
4531
4867
  const homeDir = process.env["HOME"] ?? "/tmp";
4532
- const sharedConfigPath = join7(homeDir, ".openclaw", "openclaw.json");
4868
+ const sharedConfigPath = join8(homeDir, ".openclaw", "openclaw.json");
4533
4869
  let sharedConfig;
4534
4870
  try {
4535
- sharedConfig = JSON.parse(readFileSync8(sharedConfigPath, "utf-8"));
4871
+ sharedConfig = JSON.parse(readFileSync9(sharedConfigPath, "utf-8"));
4536
4872
  } catch {
4537
4873
  return;
4538
4874
  }
@@ -4545,19 +4881,19 @@ async function migrateToProfiles() {
4545
4881
  const codeName = agentEntry["id"];
4546
4882
  if (!codeName) continue;
4547
4883
  if (codeName === "main") continue;
4548
- const profileDir = join7(homeDir, `.openclaw-${codeName}`);
4549
- if (existsSync5(join7(profileDir, "openclaw.json"))) continue;
4884
+ const profileDir = join8(homeDir, `.openclaw-${codeName}`);
4885
+ if (existsSync5(join8(profileDir, "openclaw.json"))) continue;
4550
4886
  log(`Migrating agent '${codeName}' to per-agent profile`);
4551
4887
  if (adapter.seedProfileConfig) {
4552
4888
  adapter.seedProfileConfig(codeName);
4553
4889
  }
4554
- const sharedAuthDir = join7(homeDir, ".openclaw", "agents", codeName, "agent");
4555
- const profileAuthDir = join7(profileDir, "agents", codeName, "agent");
4556
- const authFile = join7(sharedAuthDir, "auth-profiles.json");
4890
+ const sharedAuthDir = join8(homeDir, ".openclaw", "agents", codeName, "agent");
4891
+ const profileAuthDir = join8(profileDir, "agents", codeName, "agent");
4892
+ const authFile = join8(sharedAuthDir, "auth-profiles.json");
4557
4893
  if (existsSync5(authFile)) {
4558
4894
  mkdirSync4(profileAuthDir, { recursive: true });
4559
- const authContent = readFileSync8(authFile, "utf-8");
4560
- writeFileSync4(join7(profileAuthDir, "auth-profiles.json"), authContent);
4895
+ const authContent = readFileSync9(authFile, "utf-8");
4896
+ writeFileSync4(join8(profileAuthDir, "auth-profiles.json"), authContent);
4561
4897
  }
4562
4898
  allocatePort(codeName);
4563
4899
  migrated++;
@@ -4595,7 +4931,7 @@ function readGatewayToken(codeName) {
4595
4931
  }
4596
4932
  const homeDir = process.env["HOME"] ?? "/tmp";
4597
4933
  try {
4598
- const cfg = JSON.parse(readFileSync8(join7(homeDir, `.openclaw-${codeName}`, "openclaw.json"), "utf-8"));
4934
+ const cfg = JSON.parse(readFileSync9(join8(homeDir, `.openclaw-${codeName}`, "openclaw.json"), "utf-8"));
4599
4935
  return cfg?.gateway?.auth?.token;
4600
4936
  } catch {
4601
4937
  return void 0;
@@ -4604,18 +4940,18 @@ function readGatewayToken(codeName) {
4604
4940
  var GATEWAY_HUNG_TIMEOUT_MS = 5 * 6e4;
4605
4941
  function isGatewayHung(codeName) {
4606
4942
  const homeDir = process.env["HOME"] ?? "/tmp";
4607
- const jobsPath = join7(homeDir, `.openclaw-${codeName}`, "cron", "jobs.json");
4943
+ const jobsPath = join8(homeDir, `.openclaw-${codeName}`, "cron", "jobs.json");
4608
4944
  if (!existsSync5(jobsPath)) return false;
4609
4945
  try {
4610
- const data = JSON.parse(readFileSync8(jobsPath, "utf-8"));
4946
+ const data = JSON.parse(readFileSync9(jobsPath, "utf-8"));
4611
4947
  const jobs = data.jobs ?? data;
4612
4948
  if (!Array.isArray(jobs)) return false;
4613
4949
  const now = Date.now();
4614
4950
  for (const job of jobs) {
4615
- const state5 = job.state;
4616
- if (!state5) continue;
4617
- const runStartedAt = state5.runStartedAtMs;
4618
- const isRunning = state5.status === "running" || state5.running === true;
4951
+ const state6 = job.state;
4952
+ if (!state6) continue;
4953
+ const runStartedAt = state6.runStartedAtMs;
4954
+ const isRunning = state6.status === "running" || state6.running === true;
4619
4955
  if (isRunning && runStartedAt && now - runStartedAt > GATEWAY_HUNG_TIMEOUT_MS) {
4620
4956
  return true;
4621
4957
  }
@@ -4640,15 +4976,15 @@ async function ensureGatewayRunning(codeName, adapter) {
4640
4976
  }
4641
4977
  await new Promise((r) => setTimeout(r, 2e3));
4642
4978
  const homeDir = process.env["HOME"] ?? "/tmp";
4643
- const cronJobsPath = join7(homeDir, `.openclaw-${codeName}`, "cron", "jobs.json");
4979
+ const cronJobsPath = join8(homeDir, `.openclaw-${codeName}`, "cron", "jobs.json");
4644
4980
  clearStaleCronRunState(cronJobsPath);
4645
4981
  } else {
4646
4982
  if (status.port) {
4647
4983
  try {
4648
4984
  const homeDir = process.env["HOME"] ?? "/tmp";
4649
- const configPath = join7(homeDir, `.openclaw-${codeName}`, "openclaw.json");
4985
+ const configPath = join8(homeDir, `.openclaw-${codeName}`, "openclaw.json");
4650
4986
  if (existsSync5(configPath)) {
4651
- const cfg = JSON.parse(readFileSync8(configPath, "utf-8"));
4987
+ const cfg = JSON.parse(readFileSync9(configPath, "utf-8"));
4652
4988
  if (cfg.gateway?.port !== status.port) {
4653
4989
  if (!cfg.gateway) cfg.gateway = {};
4654
4990
  cfg.gateway.port = status.port;
@@ -4672,9 +5008,9 @@ async function ensureGatewayRunning(codeName, adapter) {
4672
5008
  gatewaysStartedThisCycle.add(codeName);
4673
5009
  try {
4674
5010
  const homeDir = process.env["HOME"] ?? "/tmp";
4675
- const configPath = join7(homeDir, `.openclaw-${codeName}`, "openclaw.json");
5011
+ const configPath = join8(homeDir, `.openclaw-${codeName}`, "openclaw.json");
4676
5012
  if (existsSync5(configPath)) {
4677
- const cfg = JSON.parse(readFileSync8(configPath, "utf-8"));
5013
+ const cfg = JSON.parse(readFileSync9(configPath, "utf-8"));
4678
5014
  if (!cfg.gateway) cfg.gateway = {};
4679
5015
  cfg.gateway.port = port;
4680
5016
  writeFileSync4(configPath, JSON.stringify(cfg, null, 2));
@@ -4816,7 +5152,7 @@ async function pollCycle() {
4816
5152
  const now = Date.now();
4817
5153
  if (now - lastVersionCheckAt > VERSION_CHECK_INTERVAL_MS) {
4818
5154
  try {
4819
- const firstAgent = state4.agents[0];
5155
+ const firstAgent = state5.agents[0];
4820
5156
  const versionAdapter = firstAgent ? resolveAgentFramework(firstAgent.codeName) : getFramework("openclaw");
4821
5157
  if (versionAdapter.getVersion) {
4822
5158
  cachedFrameworkVersion = await versionAdapter.getVersion();
@@ -4827,7 +5163,7 @@ async function pollCycle() {
4827
5163
  }
4828
5164
  try {
4829
5165
  const { detectHostSecurity } = await import("../host-security-6PDFG7F5.js");
4830
- const { collectDiagnostics } = await import("../persistent-session-YNVCVUK3.js");
5166
+ const { collectDiagnostics } = await import("../persistent-session-IADHTYFL.js");
4831
5167
  const diagCodeNames = [...agentState.persistentSessionAgents];
4832
5168
  const agentDiagnostics = diagCodeNames.length > 0 ? collectDiagnostics(diagCodeNames) : void 0;
4833
5169
  let tailscaleHostname;
@@ -4900,18 +5236,23 @@ async function pollCycle() {
4900
5236
  const {
4901
5237
  collectResponsivenessProbes,
4902
5238
  getResponsivenessIntervalMs
4903
- } = await import("../responsiveness-probe-5ICEBNCM.js");
5239
+ } = await import("../responsiveness-probe-3IY27CNE.js");
4904
5240
  const probeIntervalMs = getResponsivenessIntervalMs();
4905
5241
  if (now - lastResponsivenessProbeAt > probeIntervalMs) {
4906
5242
  const probeCodeNames = [...agentState.persistentSessionAgents];
4907
5243
  if (probeCodeNames.length > 0) {
4908
- const probes = collectResponsivenessProbes(probeCodeNames).map((p) => ({
4909
- ...p,
4910
- input_stuck_give_ups: takeWatchdogGiveUpCount(p.code_name)
4911
- }));
5244
+ const drainedGiveUps = /* @__PURE__ */ new Map();
5245
+ const probes = collectResponsivenessProbes(probeCodeNames).map((p) => {
5246
+ const giveUps = takeWatchdogGiveUpCount(p.code_name);
5247
+ if (giveUps > 0) drainedGiveUps.set(p.code_name, giveUps);
5248
+ return { ...p, input_stuck_give_ups: giveUps };
5249
+ });
4912
5250
  if (probes.length > 0) {
4913
5251
  void api.post("/host/responsiveness-probe", { host_id: hostId, probes }).catch((err) => {
4914
- log(`[responsiveness-probe] post failed: ${err.message}`);
5252
+ for (const [codeName, count] of drainedGiveUps) {
5253
+ creditWatchdogGiveUpCount(codeName, count);
5254
+ }
5255
+ log(`[responsiveness-probe] post failed (give-up counts re-credited): ${err.message}`);
4915
5256
  });
4916
5257
  }
4917
5258
  }
@@ -4963,7 +5304,7 @@ async function pollCycle() {
4963
5304
  for (const agent of agents) {
4964
5305
  const requested = agent.restart_requested_at ?? null;
4965
5306
  if (!requested) continue;
4966
- const prev = state4.agents.find((a) => a.agentId === agent.agent_id);
5307
+ const prev = state5.agents.find((a) => a.agentId === agent.agent_id);
4967
5308
  const lastProcessed = prev?.lastRestartProcessedAt ?? null;
4968
5309
  if (lastProcessed && Date.parse(lastProcessed) >= Date.parse(requested)) continue;
4969
5310
  log(`[restart] Dashboard requested restart for '${agent.code_name}' at ${requested}`);
@@ -4986,7 +5327,7 @@ async function pollCycle() {
4986
5327
  await processAgent(agent, agentStates);
4987
5328
  } catch (err) {
4988
5329
  log(`Error processing agent '${agent.code_name}': ${err.message}`);
4989
- const existing = state4.agents.find((a) => a.agentId === agent.agent_id);
5330
+ const existing = state5.agents.find((a) => a.agentId === agent.agent_id);
4990
5331
  if (existing) {
4991
5332
  agentStates.push(existing);
4992
5333
  } else {
@@ -5012,12 +5353,12 @@ async function pollCycle() {
5012
5353
  void maybeReportActivityCache({ api, log });
5013
5354
  const restartAckStateChanged = applyRestartAcks({
5014
5355
  agentStates,
5015
- priorAgents: state4.agents,
5356
+ priorAgents: state5.agents,
5016
5357
  restartAcks
5017
5358
  });
5018
5359
  if (restartAckStateChanged) {
5019
5360
  try {
5020
- const ackedState = { ...state4, agents: agentStates };
5361
+ const ackedState = { ...state5, agents: agentStates };
5021
5362
  atomicWriteFileSync(getStateFile(), JSON.stringify(ackedState, null, 2));
5022
5363
  } catch (err) {
5023
5364
  log(`[restart] failed to persist ack immediately: ${err.message}`);
@@ -5035,7 +5376,7 @@ async function pollCycle() {
5035
5376
  } catch {
5036
5377
  }
5037
5378
  const currentIds = new Set(agents.map((a) => a.agent_id));
5038
- for (const prev of state4.agents) {
5379
+ for (const prev of state5.agents) {
5039
5380
  if (!currentIds.has(prev.agentId)) {
5040
5381
  log(`Agent '${prev.codeName}' removed from host (deleted or unassigned)`);
5041
5382
  const adapter = resolveAgentFramework(prev.codeName);
@@ -5048,7 +5389,7 @@ async function pollCycle() {
5048
5389
  }
5049
5390
  killAgentChannelProcesses(prev.codeName, { log });
5050
5391
  freePort(prev.codeName);
5051
- const agentDir = join7(adapter.getAgentDir(prev.codeName), "provision");
5392
+ const agentDir = join8(adapter.getAgentDir(prev.codeName), "provision");
5052
5393
  await cleanupAgentFiles(prev.codeName, agentDir);
5053
5394
  clearAgentCaches(prev.agentId, prev.codeName);
5054
5395
  }
@@ -5156,10 +5497,10 @@ async function pollCycle() {
5156
5497
  }
5157
5498
  } catch {
5158
5499
  }
5159
- state4 = {
5160
- ...state4,
5500
+ state5 = {
5501
+ ...state5,
5161
5502
  lastPollAt: (/* @__PURE__ */ new Date()).toISOString(),
5162
- pollCount: state4.pollCount + 1,
5503
+ pollCount: state5.pollCount + 1,
5163
5504
  agents: agentStates,
5164
5505
  // ENG-5441: serialise trip state on every poll so manager restarts
5165
5506
  // never silently clear a tripped breaker. Cheap — only tripped
@@ -5170,9 +5511,9 @@ async function pollCycle() {
5170
5511
  log(`[poll-backoff] recovered after ${consecutivePollFailures} failure(s), resuming normal interval`);
5171
5512
  consecutivePollFailures = 0;
5172
5513
  }
5173
- send({ type: "state-update", state: state4 });
5514
+ send({ type: "state-update", state: state5 });
5174
5515
  } catch (err) {
5175
- state4.errorCount++;
5516
+ state5.errorCount++;
5176
5517
  const message = err.message;
5177
5518
  log(`Poll error: ${message}`);
5178
5519
  send({ type: "error", message });
@@ -5216,10 +5557,17 @@ async function processAgent(agent, agentStates) {
5216
5557
  agentId: agent.agent_id,
5217
5558
  log
5218
5559
  });
5560
+ void maybeEvaluateConversations({
5561
+ api,
5562
+ backend: resolveConversationEvalBackend(),
5563
+ codeName: agent.code_name,
5564
+ agentId: agent.agent_id,
5565
+ log
5566
+ });
5219
5567
  }
5220
5568
  const now = (/* @__PURE__ */ new Date()).toISOString();
5221
5569
  const adapter = resolveAgentFramework(agent.code_name);
5222
- let agentDir = join7(adapter.getAgentDir(agent.code_name), "provision");
5570
+ let agentDir = join8(adapter.getAgentDir(agent.code_name), "provision");
5223
5571
  if (agent.status === "draft" || agent.status === "paused") {
5224
5572
  if (previousKnownStatus !== agent.status) {
5225
5573
  log(`Agent '${agent.code_name}' is ${agent.status}, skipping provisioning`);
@@ -5340,7 +5688,7 @@ async function processAgent(agent, agentStates) {
5340
5688
  });
5341
5689
  } catch (err) {
5342
5690
  log(`Refresh failed for '${agent.code_name}': ${err.message}`);
5343
- const existing = state4.agents.find((a) => a.agentId === agent.agent_id);
5691
+ const existing = state5.agents.find((a) => a.agentId === agent.agent_id);
5344
5692
  agentStates.push(existing ?? {
5345
5693
  agentId: agent.agent_id,
5346
5694
  codeName: agent.code_name,
@@ -5388,7 +5736,7 @@ async function processAgent(agent, agentStates) {
5388
5736
  const frameworkId = refreshData.agent.framework ?? "openclaw";
5389
5737
  agentFrameworkCache.set(agent.code_name, frameworkId);
5390
5738
  const frameworkAdapter = getFramework(frameworkId);
5391
- agentDir = join7(frameworkAdapter.getAgentDir(agent.code_name), "provision");
5739
+ agentDir = join8(frameworkAdapter.getAgentDir(agent.code_name), "provision");
5392
5740
  cacheAgentDeliveryMetadata(agent.code_name, refreshData);
5393
5741
  if (frameworkAdapter.migrateSecretStorage && !migratedSecretStorage.has(agent.code_name)) {
5394
5742
  try {
@@ -5404,7 +5752,7 @@ async function processAgent(agent, agentStates) {
5404
5752
  const charterVersion = refreshData.charter.version;
5405
5753
  const toolsVersion = refreshData.tools.version;
5406
5754
  const known = agentState.knownVersions.get(agent.agent_id);
5407
- let lastProvisionAt = state4.agents.find((a) => a.agentId === agent.agent_id)?.lastProvisionAt ?? null;
5755
+ let lastProvisionAt = state5.agents.find((a) => a.agentId === agent.agent_id)?.lastProvisionAt ?? null;
5408
5756
  const quarantinedChannels = channelQuarantineStore().getQuarantinedKeys(agent.code_name);
5409
5757
  const currentChannelIds = setWithout(
5410
5758
  launchableChannelIds(refreshData.channel_configs),
@@ -5431,7 +5779,7 @@ async function processAgent(agent, agentStates) {
5431
5779
  const changedFiles = [];
5432
5780
  mkdirSync4(agentDir, { recursive: true });
5433
5781
  for (const artifact of artifacts) {
5434
- const filePath = join7(agentDir, artifact.relativePath);
5782
+ const filePath = join8(agentDir, artifact.relativePath);
5435
5783
  let existingHash;
5436
5784
  let newHash;
5437
5785
  let writeContent = artifact.content;
@@ -5450,8 +5798,8 @@ async function processAgent(agent, agentStates) {
5450
5798
  };
5451
5799
  newHash = sha256(stripDynamicSections(artifact.content));
5452
5800
  try {
5453
- const projectClaudeMd = join7(config.configDir, agent.code_name, "project", "CLAUDE.md");
5454
- const existing = readFileSync8(projectClaudeMd, "utf-8");
5801
+ const projectClaudeMd = join8(config.configDir, agent.code_name, "project", "CLAUDE.md");
5802
+ const existing = readFileSync9(projectClaudeMd, "utf-8");
5455
5803
  existingHash = sha256(stripDynamicSections(existing));
5456
5804
  } catch {
5457
5805
  existingHash = null;
@@ -5469,7 +5817,7 @@ async function processAgent(agent, agentStates) {
5469
5817
  const generatorKeys = Object.keys(generatorServers);
5470
5818
  let existingRaw = "";
5471
5819
  try {
5472
- existingRaw = readFileSync8(filePath, "utf-8");
5820
+ existingRaw = readFileSync9(filePath, "utf-8");
5473
5821
  } catch {
5474
5822
  }
5475
5823
  const existingServers = parseMcp(existingRaw);
@@ -5491,12 +5839,12 @@ async function processAgent(agent, agentStates) {
5491
5839
  }
5492
5840
  }
5493
5841
  if (changedFiles.length > 0) {
5494
- const isFirst = !existsSync5(join7(agentDir, "CHARTER.md"));
5842
+ const isFirst = !existsSync5(join8(agentDir, "CHARTER.md"));
5495
5843
  const verb = isFirst ? "Provisioning" : "Updating";
5496
5844
  const fileNames = changedFiles.map((f) => f.relativePath).join(", ");
5497
5845
  log(`${verb} '${agent.code_name}': ${fileNames}`);
5498
5846
  for (const file of changedFiles) {
5499
- const filePath = join7(agentDir, file.relativePath);
5847
+ const filePath = join8(agentDir, file.relativePath);
5500
5848
  mkdirSync4(dirname3(filePath), { recursive: true });
5501
5849
  if (file.relativePath === ".mcp.json") {
5502
5850
  safeWriteJsonAtomic(filePath, file.content, { mode: 384 });
@@ -5505,12 +5853,12 @@ async function processAgent(agent, agentStates) {
5505
5853
  }
5506
5854
  }
5507
5855
  try {
5508
- const provSkillsDir = join7(agentDir, ".claude", "skills");
5856
+ const provSkillsDir = join8(agentDir, ".claude", "skills");
5509
5857
  if (existsSync5(provSkillsDir)) {
5510
- for (const folder of readdirSync3(provSkillsDir)) {
5858
+ for (const folder of readdirSync4(provSkillsDir)) {
5511
5859
  if (folder.startsWith("knowledge-")) {
5512
5860
  try {
5513
- rmSync2(join7(provSkillsDir, folder), { recursive: true });
5861
+ rmSync2(join8(provSkillsDir, folder), { recursive: true });
5514
5862
  } catch {
5515
5863
  }
5516
5864
  }
@@ -5523,7 +5871,7 @@ async function processAgent(agent, agentStates) {
5523
5871
  const trackedFiles2 = frameworkAdapter.driftTrackedFiles();
5524
5872
  const hashes = /* @__PURE__ */ new Map();
5525
5873
  for (const file of trackedFiles2) {
5526
- const h = hashFile(join7(agentDir, file));
5874
+ const h = hashFile(join8(agentDir, file));
5527
5875
  if (h) hashes.set(file, h);
5528
5876
  }
5529
5877
  agentState.writtenHashes.set(agent.agent_id, hashes);
@@ -5591,7 +5939,7 @@ async function processAgent(agent, agentStates) {
5591
5939
  if (written && existsSync5(agentDir)) {
5592
5940
  const driftedFiles = [];
5593
5941
  for (const [file, expectedHash] of written) {
5594
- const localHash = hashFile(join7(agentDir, file));
5942
+ const localHash = hashFile(join8(agentDir, file));
5595
5943
  if (localHash && localHash !== expectedHash) {
5596
5944
  driftedFiles.push(file);
5597
5945
  }
@@ -5602,7 +5950,7 @@ async function processAgent(agent, agentStates) {
5602
5950
  try {
5603
5951
  const localHashes = {};
5604
5952
  for (const file of driftedFiles) {
5605
- localHashes[file] = hashFile(join7(agentDir, file));
5953
+ localHashes[file] = hashFile(join8(agentDir, file));
5606
5954
  }
5607
5955
  await api.post("/host/drift", {
5608
5956
  agent_id: agent.agent_id,
@@ -5865,18 +6213,18 @@ async function processAgent(agent, agentStates) {
5865
6213
  if (agentSessionMode === "persistent" && (agentFrameworkCache.get(agent.code_name) ?? "openclaw") === "claude-code") {
5866
6214
  try {
5867
6215
  const agentProvisionDir = agentDir;
5868
- const projectDir = join7(homedir4(), ".augmented", agent.code_name, "project");
6216
+ const projectDir = join8(homedir4(), ".augmented", agent.code_name, "project");
5869
6217
  mkdirSync4(agentProvisionDir, { recursive: true });
5870
6218
  mkdirSync4(projectDir, { recursive: true });
5871
- const provisionMcpPath = join7(agentProvisionDir, ".mcp.json");
5872
- const projectMcpPath = join7(projectDir, ".mcp.json");
6219
+ const provisionMcpPath = join8(agentProvisionDir, ".mcp.json");
6220
+ const projectMcpPath = join8(projectDir, ".mcp.json");
5873
6221
  let mcpConfig = { mcpServers: {} };
5874
6222
  try {
5875
- mcpConfig = JSON.parse(readFileSync8(provisionMcpPath, "utf-8"));
6223
+ mcpConfig = JSON.parse(readFileSync9(provisionMcpPath, "utf-8"));
5876
6224
  if (!mcpConfig.mcpServers) mcpConfig.mcpServers = {};
5877
6225
  } catch {
5878
6226
  }
5879
- const localDirectChatChannel = join7(homedir4(), ".augmented", "_mcp", "direct-chat-channel.js");
6227
+ const localDirectChatChannel = join8(homedir4(), ".augmented", "_mcp", "direct-chat-channel.js");
5880
6228
  const directChatTeamSettings = refreshData.team?.settings;
5881
6229
  const directChatTz = (() => {
5882
6230
  const tz = directChatTeamSettings?.["timezone"];
@@ -5906,7 +6254,7 @@ async function processAgent(agent, agentStates) {
5906
6254
  log(`Channel credentials written for '${agent.code_name}/direct-chat'`);
5907
6255
  }
5908
6256
  }
5909
- const staleChannelsPath = join7(projectDir, ".mcp-channels.json");
6257
+ const staleChannelsPath = join8(projectDir, ".mcp-channels.json");
5910
6258
  if (existsSync5(staleChannelsPath)) {
5911
6259
  try {
5912
6260
  rmSync2(staleChannelsPath, { force: true });
@@ -5917,7 +6265,7 @@ async function processAgent(agent, agentStates) {
5917
6265
  log(`Failed to provision direct-chat channel for '${agent.code_name}': ${err.message}`);
5918
6266
  }
5919
6267
  }
5920
- let lastSecretsProvisionAt = state4.agents.find((a) => a.agentId === agent.agent_id)?.lastSecretsProvisionAt ?? null;
6268
+ let lastSecretsProvisionAt = state5.agents.find((a) => a.agentId === agent.agent_id)?.lastSecretsProvisionAt ?? null;
5921
6269
  let secretsHash = agentState.knownSecretsHashes.get(agent.agent_id) ?? null;
5922
6270
  try {
5923
6271
  const secretsData = await api.post("/host/secrets", { agent_id: agent.agent_id });
@@ -5971,7 +6319,7 @@ async function processAgent(agent, agentStates) {
5971
6319
  }
5972
6320
  if (process.env.AGT_CONNECTIVITY_PROBE_ENABLED === "true") {
5973
6321
  try {
5974
- const probeProjectDir = join7(homedir4(), ".augmented", agent.code_name, "project");
6322
+ const probeProjectDir = join8(homedir4(), ".augmented", agent.code_name, "project");
5975
6323
  await runAgentConnectivityProbes(agent, integrations, probeProjectDir);
5976
6324
  } catch (err) {
5977
6325
  log(`Connectivity probe failed for '${agent.code_name}': ${err.message}`);
@@ -5981,11 +6329,11 @@ async function processAgent(agent, agentStates) {
5981
6329
  const intHash = computeIntegrationsHash(integrations);
5982
6330
  const prevIntHash = agentState.knownIntegrationHashes.get(agent.agent_id);
5983
6331
  if (intHash !== prevIntHash) {
5984
- const projectDir = join7(homedir4(), ".augmented", agent.code_name, "project");
5985
- const envIntPath = join7(projectDir, ".env.integrations");
6332
+ const projectDir = join8(homedir4(), ".augmented", agent.code_name, "project");
6333
+ const envIntPath = join8(projectDir, ".env.integrations");
5986
6334
  let preWriteEnv;
5987
6335
  try {
5988
- preWriteEnv = readFileSync8(envIntPath, "utf-8");
6336
+ preWriteEnv = readFileSync9(envIntPath, "utf-8");
5989
6337
  } catch {
5990
6338
  preWriteEnv = void 0;
5991
6339
  }
@@ -5997,9 +6345,9 @@ async function processAgent(agent, agentStates) {
5997
6345
  let rotationHandled = true;
5998
6346
  if (fw === "claude-code" && isSessionHealthy(agent.code_name)) {
5999
6347
  try {
6000
- const projectMcpPath = join7(projectDir, ".mcp.json");
6001
- const postWriteEnv = readFileSync8(envIntPath, "utf-8");
6002
- const mcpContent = readFileSync8(projectMcpPath, "utf-8");
6348
+ const projectMcpPath = join8(projectDir, ".mcp.json");
6349
+ const postWriteEnv = readFileSync9(envIntPath, "utf-8");
6350
+ const mcpContent = readFileSync9(projectMcpPath, "utf-8");
6003
6351
  const changedVars = diffEnvIntegrations(preWriteEnv, postWriteEnv);
6004
6352
  const mcpJsonForReap = JSON.parse(mcpContent);
6005
6353
  const affectedServerKeys = findMcpServersUsingVars(mcpJsonForReap, changedVars);
@@ -6067,8 +6415,8 @@ async function processAgent(agent, agentStates) {
6067
6415
  const mcpPath = frameworkAdapter.getMcpPath(agent.code_name);
6068
6416
  if (mcpPath) {
6069
6417
  try {
6070
- const { readFileSync: readFileSync9 } = await import("fs");
6071
- const mcpConfig = JSON.parse(readFileSync9(mcpPath, "utf-8"));
6418
+ const { readFileSync: readFileSync10 } = await import("fs");
6419
+ const mcpConfig = JSON.parse(readFileSync10(mcpPath, "utf-8"));
6072
6420
  if (mcpConfig.mcpServers) {
6073
6421
  const managedPrefixes = [
6074
6422
  "composio_",
@@ -6164,7 +6512,7 @@ async function processAgent(agent, agentStates) {
6164
6512
  if (agent.status === "active") {
6165
6513
  if (frameworkAdapter.installPlugin) {
6166
6514
  try {
6167
- const pluginPath = join7(process.cwd(), "packages", "openclaw-plugin-augmented", "src", "index.ts");
6515
+ const pluginPath = join8(process.cwd(), "packages", "openclaw-plugin-augmented", "src", "index.ts");
6168
6516
  if (existsSync5(pluginPath)) {
6169
6517
  frameworkAdapter.installPlugin(agent.code_name, "augmented", pluginPath, {
6170
6518
  agtHost: requireHost(),
@@ -6230,25 +6578,25 @@ async function processAgent(agent, agentStates) {
6230
6578
  }
6231
6579
  }
6232
6580
  try {
6233
- const { readdirSync: readdirSync4, rmSync: rmSync3 } = await import("fs");
6581
+ const { readdirSync: readdirSync5, rmSync: rmSync3 } = await import("fs");
6234
6582
  const { homedir: homedir5 } = await import("os");
6235
6583
  const frameworkId2 = frameworkAdapter.id;
6236
6584
  const candidateSkillDirs = [
6237
6585
  // Claude Code — framework runtime tree
6238
- join7(homedir5(), ".augmented", agent.code_name, "skills"),
6586
+ join8(homedir5(), ".augmented", agent.code_name, "skills"),
6239
6587
  // Claude Code — project tree
6240
- join7(homedir5(), ".augmented", agent.code_name, "project", ".claude", "skills"),
6588
+ join8(homedir5(), ".augmented", agent.code_name, "project", ".claude", "skills"),
6241
6589
  // OpenClaw — framework runtime tree
6242
- join7(homedir5(), `.openclaw-${agent.code_name}`, "skills"),
6590
+ join8(homedir5(), `.openclaw-${agent.code_name}`, "skills"),
6243
6591
  // Defensive: legacy provision-side path, not currently an
6244
6592
  // install target but cheap to sweep.
6245
- join7(agentDir, ".claude", "skills")
6593
+ join8(agentDir, ".claude", "skills")
6246
6594
  ];
6247
6595
  const existingDirs = candidateSkillDirs.filter((d) => existsSync5(d));
6248
6596
  const discoveredEntries = /* @__PURE__ */ new Set();
6249
6597
  for (const dir of existingDirs) {
6250
6598
  try {
6251
- for (const entry of readdirSync4(dir)) {
6599
+ for (const entry of readdirSync5(dir)) {
6252
6600
  if (entry.startsWith("plugin-") || entry.startsWith("integration-")) {
6253
6601
  discoveredEntries.add(entry);
6254
6602
  }
@@ -6258,7 +6606,7 @@ async function processAgent(agent, agentStates) {
6258
6606
  }
6259
6607
  const removeSkillFolder = (entry, reason) => {
6260
6608
  for (const dir of existingDirs) {
6261
- const p = join7(dir, entry);
6609
+ const p = join8(dir, entry);
6262
6610
  if (existsSync5(p)) {
6263
6611
  rmSync3(p, { recursive: true, force: true });
6264
6612
  }
@@ -6420,8 +6768,8 @@ async function processAgent(agent, agentStates) {
6420
6768
  const sess = getSessionState(agent.code_name);
6421
6769
  let mcpJsonParsed = null;
6422
6770
  try {
6423
- const mcpPath = join7(getProjectDir(agent.code_name), ".mcp.json");
6424
- mcpJsonParsed = JSON.parse(readFileSync8(mcpPath, "utf-8"));
6771
+ const mcpPath = join8(getProjectDir(agent.code_name), ".mcp.json");
6772
+ mcpJsonParsed = JSON.parse(readFileSync9(mcpPath, "utf-8"));
6425
6773
  } catch {
6426
6774
  }
6427
6775
  reapMissingMcpSessions({
@@ -6606,10 +6954,10 @@ async function processAgent(agent, agentStates) {
6606
6954
  lastWorkTriggerAt.set(agent.code_name, triggerTs);
6607
6955
  if (agentFw === "openclaw" && gatewayRunning && gatewayPort) {
6608
6956
  const homeDir = process.env["HOME"] ?? "/tmp";
6609
- const jobsPath = join7(homeDir, `.openclaw-${agent.code_name}`, "cron", "jobs.json");
6957
+ const jobsPath = join8(homeDir, `.openclaw-${agent.code_name}`, "cron", "jobs.json");
6610
6958
  if (existsSync5(jobsPath)) {
6611
6959
  try {
6612
- const jobsData = JSON.parse(readFileSync8(jobsPath, "utf-8"));
6960
+ const jobsData = JSON.parse(readFileSync9(jobsPath, "utf-8"));
6613
6961
  const kanbanJob = (jobsData.jobs ?? []).find(
6614
6962
  (j) => typeof j.name === "string" && j.name.includes("kanban-work")
6615
6963
  );
@@ -6746,7 +7094,7 @@ In progress for ${age} minutes \u2014 auto-failed`).catch(() => {
6746
7094
  if (trackedFiles.length > 0 && existsSync5(agentDir)) {
6747
7095
  const hashes = /* @__PURE__ */ new Map();
6748
7096
  for (const file of trackedFiles) {
6749
- const h = hashFile(join7(agentDir, file));
7097
+ const h = hashFile(join8(agentDir, file));
6750
7098
  if (h) hashes.set(file, h);
6751
7099
  }
6752
7100
  agentState.writtenHashes.set(agent.agent_id, hashes);
@@ -6780,19 +7128,19 @@ function cleanupStaleSessions(codeName) {
6780
7128
  lastCleanupAt.set(codeName, Date.now());
6781
7129
  const homeDir = process.env["HOME"] ?? "/tmp";
6782
7130
  for (const agentDir of ["main", codeName]) {
6783
- const sessionsDir = join7(homeDir, `.openclaw-${codeName}`, "agents", agentDir, "sessions");
7131
+ const sessionsDir = join8(homeDir, `.openclaw-${codeName}`, "agents", agentDir, "sessions");
6784
7132
  cleanupCronSessions(sessionsDir, CRON_SESSION_KEEP_COUNT);
6785
7133
  }
6786
- const cronRunsDir = join7(homeDir, `.openclaw-${codeName}`, "cron", "runs");
7134
+ const cronRunsDir = join8(homeDir, `.openclaw-${codeName}`, "cron", "runs");
6787
7135
  cleanupOldFiles(cronRunsDir, CRON_RUN_RETENTION_DAYS, ".jsonl");
6788
- const cronJobsPath = join7(homeDir, `.openclaw-${codeName}`, "cron", "jobs.json");
7136
+ const cronJobsPath = join8(homeDir, `.openclaw-${codeName}`, "cron", "jobs.json");
6789
7137
  clearStaleCronRunState(cronJobsPath);
6790
7138
  }
6791
7139
  function cleanupCronSessions(sessionsDir, keepCount) {
6792
- const indexPath = join7(sessionsDir, "sessions.json");
7140
+ const indexPath = join8(sessionsDir, "sessions.json");
6793
7141
  if (!existsSync5(indexPath)) return;
6794
7142
  try {
6795
- const raw = readFileSync8(indexPath, "utf-8");
7143
+ const raw = readFileSync9(indexPath, "utf-8");
6796
7144
  const index = JSON.parse(raw);
6797
7145
  const cronRunKeys = Object.keys(index).filter((k) => k.includes(":cron:") && k.includes(":run:")).map((k) => ({
6798
7146
  key: k,
@@ -6805,7 +7153,7 @@ function cleanupCronSessions(sessionsDir, keepCount) {
6805
7153
  for (const entry of toDelete) {
6806
7154
  delete index[entry.key];
6807
7155
  if (entry.sessionId) {
6808
- const sessionFile = join7(sessionsDir, `${entry.sessionId}.jsonl`);
7156
+ const sessionFile = join8(sessionsDir, `${entry.sessionId}.jsonl`);
6809
7157
  try {
6810
7158
  if (existsSync5(sessionFile)) {
6811
7159
  unlinkSync(sessionFile);
@@ -6827,7 +7175,7 @@ function cleanupCronSessions(sessionsDir, keepCount) {
6827
7175
  delete index[parentKey];
6828
7176
  if (parentSessionId) {
6829
7177
  try {
6830
- const f = join7(sessionsDir, `${parentSessionId}.jsonl`);
7178
+ const f = join8(sessionsDir, `${parentSessionId}.jsonl`);
6831
7179
  if (existsSync5(f)) {
6832
7180
  unlinkSync(f);
6833
7181
  deletedFiles++;
@@ -6848,26 +7196,26 @@ var STALE_RUN_TIMEOUT_MS = 5 * 6e4;
6848
7196
  function clearStaleCronRunState(jobsPath) {
6849
7197
  if (!existsSync5(jobsPath)) return;
6850
7198
  try {
6851
- const raw = readFileSync8(jobsPath, "utf-8");
7199
+ const raw = readFileSync9(jobsPath, "utf-8");
6852
7200
  const data = JSON.parse(raw);
6853
7201
  const jobs = data.jobs ?? data;
6854
7202
  if (!Array.isArray(jobs)) return;
6855
7203
  let changed = false;
6856
7204
  const now = Date.now();
6857
7205
  for (const job of jobs) {
6858
- const state5 = job.state;
6859
- if (!state5) continue;
6860
- const runStartedAt = state5.runningAtMs ?? state5.runStartedAtMs;
6861
- const isRunning = state5.running === true || state5.status === "running";
7206
+ const state6 = job.state;
7207
+ if (!state6) continue;
7208
+ const runStartedAt = state6.runningAtMs ?? state6.runStartedAtMs;
7209
+ const isRunning = state6.running === true || state6.status === "running";
6862
7210
  if (isRunning && runStartedAt && now - runStartedAt > STALE_RUN_TIMEOUT_MS) {
6863
- state5.running = false;
6864
- delete state5.status;
6865
- delete state5.runStartedAtMs;
6866
- delete state5.currentRunId;
7211
+ state6.running = false;
7212
+ delete state6.status;
7213
+ delete state6.runStartedAtMs;
7214
+ delete state6.currentRunId;
6867
7215
  changed = true;
6868
7216
  log(`Cleared stale running state for cron job '${job.name}' (stuck for ${Math.round((now - runStartedAt) / 6e4)}min)`);
6869
7217
  } else if (isRunning && !runStartedAt) {
6870
- state5.running = false;
7218
+ state6.running = false;
6871
7219
  changed = true;
6872
7220
  log(`Cleared stale running state for cron job '${job.name}' (no start timestamp)`);
6873
7221
  }
@@ -6883,11 +7231,11 @@ function cleanupOldFiles(dir, maxAgeDays, ext) {
6883
7231
  const cutoff = Date.now() - maxAgeDays * 24 * 60 * 60 * 1e3;
6884
7232
  let removed = 0;
6885
7233
  try {
6886
- for (const f of readdirSync3(dir)) {
7234
+ for (const f of readdirSync4(dir)) {
6887
7235
  if (!f.endsWith(ext)) continue;
6888
- const fullPath = join7(dir, f);
7236
+ const fullPath = join8(dir, f);
6889
7237
  try {
6890
- const st = statSync2(fullPath);
7238
+ const st = statSync3(fullPath);
6891
7239
  if (st.mtimeMs < cutoff) {
6892
7240
  unlinkSync(fullPath);
6893
7241
  removed++;
@@ -6905,7 +7253,7 @@ var inFlightClaudeTasks = /* @__PURE__ */ new Set();
6905
7253
  var claudeTaskConcurrency = /* @__PURE__ */ new Map();
6906
7254
  var MAX_CLAUDE_CONCURRENCY = 2;
6907
7255
  function claudePidFilePath() {
6908
- return join7(homedir4(), ".augmented", "manager-claude-pids.json");
7256
+ return join8(homedir4(), ".augmented", "manager-claude-pids.json");
6909
7257
  }
6910
7258
  var inFlightClaudePids = /* @__PURE__ */ new Map();
6911
7259
  function registerClaudeSpawn(record) {
@@ -6950,16 +7298,16 @@ async function syncAndCheckClaudeScheduler(agent, tasks, boardItems, refreshData
6950
7298
  enabled: t.enabled ?? true,
6951
7299
  triggered_at: t.triggered_at ?? null
6952
7300
  }));
6953
- const state6 = syncTasksToScheduler(codeName, agent.agent_id, taskInputs);
6954
- claudeSchedulerStates.set(codeName, state6);
7301
+ const state7 = syncTasksToScheduler(codeName, agent.agent_id, taskInputs);
7302
+ claudeSchedulerStates.set(codeName, state7);
6955
7303
  agentState.knownTasksHashes.set(agent.agent_id, combinedHash);
6956
7304
  log(`[claude-scheduler] Tasks synced for '${codeName}' (${taskInputs.length} task(s))`);
6957
7305
  }
6958
7306
  if (!claudeSchedulerStates.has(codeName)) {
6959
7307
  claudeSchedulerStates.set(codeName, loadSchedulerState(codeName));
6960
7308
  }
6961
- const state5 = claudeSchedulerStates.get(codeName);
6962
- const ready = getReadyTasks(state5, inFlightClaudeTasks);
7309
+ const state6 = claudeSchedulerStates.get(codeName);
7310
+ const ready = getReadyTasks(state6, inFlightClaudeTasks);
6963
7311
  if (ready.length === 0) return;
6964
7312
  for (const task of ready) {
6965
7313
  if ((claudeTaskConcurrency.get(codeName) ?? 0) >= MAX_CLAUDE_CONCURRENCY) break;
@@ -7106,8 +7454,8 @@ async function deliverScheduledCardResult(codeName, agentId, cardId) {
7106
7454
  markScheduledCardDeliveryComplete(cardId);
7107
7455
  return "terminal";
7108
7456
  }
7109
- const state5 = claudeSchedulerStates.get(codeName) ?? loadSchedulerState(codeName);
7110
- const task = state5.tasks[card.source_ref];
7457
+ const state6 = claudeSchedulerStates.get(codeName) ?? loadSchedulerState(codeName);
7458
+ const task = state6.tasks[card.source_ref];
7111
7459
  if (!task) {
7112
7460
  log(`[scheduled-kanban] delivery: no scheduler task for source_ref=${card.source_ref} on '${codeName}' \u2014 skipping`);
7113
7461
  markScheduledCardDeliveryComplete(cardId);
@@ -7213,7 +7561,7 @@ async function fireScheduledTaskViaKanban(codeName, agentId, task, prompt) {
7213
7561
  }
7214
7562
  async function executeAndProcessClaudeTask(codeName, agentId, task, prompt) {
7215
7563
  const projectDir = getProjectDir2(codeName);
7216
- const mcpConfigPath = join7(projectDir, ".mcp.json");
7564
+ const mcpConfigPath = join8(projectDir, ".mcp.json");
7217
7565
  let runId = null;
7218
7566
  let kanbanItemId = null;
7219
7567
  let taskResult;
@@ -7221,11 +7569,11 @@ async function executeAndProcessClaudeTask(codeName, agentId, task, prompt) {
7221
7569
  const priorRuns = await fetchPriorScheduledRuns(agentId, task.taskId);
7222
7570
  prompt = wrapScheduledTaskPrompt(prompt, { priorRuns });
7223
7571
  try {
7224
- const claudeMdPath = join7(projectDir, "CLAUDE.md");
7572
+ const claudeMdPath = join8(projectDir, "CLAUDE.md");
7225
7573
  const serverNames = [];
7226
7574
  if (existsSync5(mcpConfigPath)) {
7227
7575
  try {
7228
- const d = JSON.parse(readFileSync8(mcpConfigPath, "utf-8"));
7576
+ const d = JSON.parse(readFileSync9(mcpConfigPath, "utf-8"));
7229
7577
  if (d.mcpServers) serverNames.push(...Object.keys(d.mcpServers));
7230
7578
  } catch {
7231
7579
  }
@@ -7248,10 +7596,10 @@ async function executeAndProcessClaudeTask(codeName, agentId, task, prompt) {
7248
7596
  claudeArgs.push("--system-prompt-file", claudeMdPath);
7249
7597
  }
7250
7598
  const childEnv = { ...process.env };
7251
- const envIntPath = join7(projectDir, ".env.integrations");
7599
+ const envIntPath = join8(projectDir, ".env.integrations");
7252
7600
  if (existsSync5(envIntPath)) {
7253
7601
  try {
7254
- Object.assign(childEnv, parseEnvIntegrations(readFileSync8(envIntPath, "utf-8")));
7602
+ Object.assign(childEnv, parseEnvIntegrations(readFileSync9(envIntPath, "utf-8")));
7255
7603
  } catch {
7256
7604
  }
7257
7605
  }
@@ -7423,8 +7771,8 @@ var claudeAuthTupleBySession = /* @__PURE__ */ new Map();
7423
7771
  async function ensurePersistentSession(agent, tasks, boardItems, refreshData) {
7424
7772
  const codeName = agent.code_name;
7425
7773
  const projectDir = getProjectDir(codeName);
7426
- const mcpConfigPath = join7(projectDir, ".mcp.json");
7427
- const claudeMdPath = join7(projectDir, "CLAUDE.md");
7774
+ const mcpConfigPath = join8(projectDir, ".mcp.json");
7775
+ const claudeMdPath = join8(projectDir, "CLAUDE.md");
7428
7776
  if (restartBreaker.isTripped(codeName)) {
7429
7777
  const trip = restartBreaker.getTrip(codeName);
7430
7778
  return {
@@ -7651,9 +7999,9 @@ ${truncateForLog(ctx.tail)}` : `; pane_tail_hash=sha256:${createHash3("sha256").
7651
7999
  } else if (!claudeSchedulerStates.has(codeName)) {
7652
8000
  claudeSchedulerStates.set(codeName, loadSchedulerState(codeName));
7653
8001
  }
7654
- const state5 = claudeSchedulerStates.get(codeName);
7655
- if (state5) {
7656
- const ready = getReadyTasks(state5, inFlightClaudeTasks);
8002
+ const state6 = claudeSchedulerStates.get(codeName);
8003
+ if (state6) {
8004
+ const ready = getReadyTasks(state6, inFlightClaudeTasks);
7657
8005
  if (ready.length > 0) {
7658
8006
  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(", ")}`);
7659
8007
  }
@@ -8064,11 +8412,11 @@ ${escapeXml(msg.content)}
8064
8412
  log(`[direct-chat] One-shot spawn for '${agent.codeName}' (msg=${msg.id}; host in-flight=${directChatSpawnGate.hostInFlight}, queued=${directChatSpawnGate.queuedCount})`);
8065
8413
  const { getProjectDir: ccProjectDir } = await import("../claude-scheduler-EM24LTGV.js");
8066
8414
  const projDir = ccProjectDir(agent.codeName);
8067
- const mcpConfigPath = join7(projDir, ".mcp.json");
8415
+ const mcpConfigPath = join8(projDir, ".mcp.json");
8068
8416
  const serverNames = [];
8069
8417
  if (existsSync5(mcpConfigPath)) {
8070
8418
  try {
8071
- const d = JSON.parse(readFileSync8(mcpConfigPath, "utf-8"));
8419
+ const d = JSON.parse(readFileSync9(mcpConfigPath, "utf-8"));
8072
8420
  if (d.mcpServers) serverNames.push(...Object.keys(d.mcpServers));
8073
8421
  } catch {
8074
8422
  }
@@ -8087,15 +8435,15 @@ ${escapeXml(msg.content)}
8087
8435
  "--allowedTools",
8088
8436
  allowedTools
8089
8437
  ];
8090
- const chatClaudeMd = join7(projDir, "CLAUDE.md");
8438
+ const chatClaudeMd = join8(projDir, "CLAUDE.md");
8091
8439
  if (existsSync5(chatClaudeMd)) {
8092
8440
  chatArgs.push("--system-prompt-file", chatClaudeMd);
8093
8441
  }
8094
- const envIntPath = join7(projDir, ".env.integrations");
8442
+ const envIntPath = join8(projDir, ".env.integrations");
8095
8443
  const childEnv = { ...process.env };
8096
8444
  if (existsSync5(envIntPath)) {
8097
8445
  try {
8098
- Object.assign(childEnv, parseEnvIntegrations(readFileSync8(envIntPath, "utf-8")));
8446
+ Object.assign(childEnv, parseEnvIntegrations(readFileSync9(envIntPath, "utf-8")));
8099
8447
  } catch {
8100
8448
  }
8101
8449
  }
@@ -8473,12 +8821,12 @@ function getBuiltInSkillContent(skillId) {
8473
8821
  if (builtInSkillCache.has(skillId)) return builtInSkillCache.get(skillId);
8474
8822
  try {
8475
8823
  const candidates = [
8476
- join7(process.cwd(), "skills", skillId, "SKILL.md"),
8477
- join7(new URL(".", import.meta.url).pathname, "..", "..", "..", "..", "skills", skillId, "SKILL.md")
8824
+ join8(process.cwd(), "skills", skillId, "SKILL.md"),
8825
+ join8(new URL(".", import.meta.url).pathname, "..", "..", "..", "..", "skills", skillId, "SKILL.md")
8478
8826
  ];
8479
8827
  for (const candidate of candidates) {
8480
8828
  if (existsSync5(candidate)) {
8481
- const content = readFileSync8(candidate, "utf-8");
8829
+ const content = readFileSync9(candidate, "utf-8");
8482
8830
  const files = [{ relativePath: "SKILL.md", content }];
8483
8831
  builtInSkillCache.set(skillId, files);
8484
8832
  return files;
@@ -9121,7 +9469,7 @@ async function processClaudePairSessions(agents) {
9121
9469
  killPairSession,
9122
9470
  pairTmuxSession,
9123
9471
  finalizeClaudePairOnboarding
9124
- } = await import("../claude-pair-runtime-DY2LN3ED.js");
9472
+ } = await import("../claude-pair-runtime-WTGNQXCL.js");
9125
9473
  for (const pairId of pendingResp.cancelled_pair_ids ?? []) {
9126
9474
  log(`[claude-pair] sweeping orphan tmux session for pair ${pairId.slice(0, 8)}`);
9127
9475
  const killed = await killPairSession(pairTmuxSession(pairId));
@@ -9431,8 +9779,8 @@ function parseMemoryFile(raw, fallbackName) {
9431
9779
  };
9432
9780
  }
9433
9781
  async function syncMemories(agent, configDir, log2) {
9434
- const projectDir = join7(configDir, agent.code_name, "project");
9435
- const memoryDir = join7(projectDir, "memory");
9782
+ const projectDir = join8(configDir, agent.code_name, "project");
9783
+ const memoryDir = join8(projectDir, "memory");
9436
9784
  const isFreshSync = pendingFreshMemorySync.has(agent.agent_id);
9437
9785
  if (isFreshSync) {
9438
9786
  log2(`[memory-sync] Fresh-sync requested for '${agent.code_name}' \u2014 pulling DB first`);
@@ -9447,10 +9795,10 @@ async function syncMemories(agent, configDir, log2) {
9447
9795
  const prevHashes = memoryFileHashes.get(agent.agent_id) ?? /* @__PURE__ */ new Map();
9448
9796
  const currentHashes = /* @__PURE__ */ new Map();
9449
9797
  const changedMemories = [];
9450
- for (const file of readdirSync3(memoryDir)) {
9798
+ for (const file of readdirSync4(memoryDir)) {
9451
9799
  if (!file.endsWith(".md")) continue;
9452
9800
  try {
9453
- const raw = readFileSync8(join7(memoryDir, file), "utf-8");
9801
+ const raw = readFileSync9(join8(memoryDir, file), "utf-8");
9454
9802
  const fileHash = createHash3("sha256").update(raw).digest("hex").slice(0, 16);
9455
9803
  currentHashes.set(file, fileHash);
9456
9804
  if (prevHashes.get(file) === fileHash) continue;
@@ -9475,7 +9823,7 @@ async function syncMemories(agent, configDir, log2) {
9475
9823
  } catch (err) {
9476
9824
  for (const mem of changedMemories) {
9477
9825
  for (const [file] of currentHashes) {
9478
- const parsed = parseMemoryFile(readFileSync8(join7(memoryDir, file), "utf-8"), file.replace(/\.md$/, ""));
9826
+ const parsed = parseMemoryFile(readFileSync9(join8(memoryDir, file), "utf-8"), file.replace(/\.md$/, ""));
9479
9827
  if (parsed?.name === mem.name) currentHashes.delete(file);
9480
9828
  }
9481
9829
  }
@@ -9488,7 +9836,7 @@ async function syncMemories(agent, configDir, log2) {
9488
9836
  }
9489
9837
  }
9490
9838
  async function downloadMemories(agent, memoryDir, log2, { force }) {
9491
- const localFiles = existsSync5(memoryDir) ? readdirSync3(memoryDir).filter((f) => f.endsWith(".md")).sort() : [];
9839
+ const localFiles = existsSync5(memoryDir) ? readdirSync4(memoryDir).filter((f) => f.endsWith(".md")).sort() : [];
9492
9840
  const localListHash = createHash3("sha256").update(localFiles.join(",")).digest("hex").slice(0, 16);
9493
9841
  const prevLocalHash = lastLocalFileHash.get(agent.agent_id);
9494
9842
  const prevDownload = lastDownloadHash.get(agent.agent_id);
@@ -9510,7 +9858,7 @@ async function downloadMemories(agent, memoryDir, log2, { force }) {
9510
9858
  const mem = dbMemories.memories[i];
9511
9859
  const rawSlug = mem.name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/(^-|-$)/g, "").slice(0, 60);
9512
9860
  const slug = rawSlug || `memory-${i}`;
9513
- const filePath = join7(memoryDir, `${slug}.md`);
9861
+ const filePath = join8(memoryDir, `${slug}.md`);
9514
9862
  const desired = `---
9515
9863
  name: ${JSON.stringify(mem.name)}
9516
9864
  type: ${mem.type}
@@ -9522,7 +9870,7 @@ ${mem.content}
9522
9870
  if (existsSync5(filePath)) {
9523
9871
  let existing = "";
9524
9872
  try {
9525
- existing = readFileSync8(filePath, "utf-8");
9873
+ existing = readFileSync9(filePath, "utf-8");
9526
9874
  } catch {
9527
9875
  }
9528
9876
  if (existing === desired) continue;
@@ -9534,7 +9882,7 @@ ${mem.content}
9534
9882
  }
9535
9883
  }
9536
9884
  if (written > 0 || overwritten > 0) {
9537
- const updatedFiles = readdirSync3(memoryDir).filter((f) => f.endsWith(".md")).sort();
9885
+ const updatedFiles = readdirSync4(memoryDir).filter((f) => f.endsWith(".md")).sort();
9538
9886
  lastLocalFileHash.set(agent.agent_id, createHash3("sha256").update(updatedFiles.join(",")).digest("hex").slice(0, 16));
9539
9887
  log2(`Memory download for '${agent.code_name}': wrote ${written} new, overwrote ${overwritten} stale`);
9540
9888
  }
@@ -9736,11 +10084,11 @@ function startManager(opts) {
9736
10084
  try {
9737
10085
  const stateFile = getStateFile();
9738
10086
  if (existsSync5(stateFile)) {
9739
- const raw = readFileSync8(stateFile, "utf-8");
10087
+ const raw = readFileSync9(stateFile, "utf-8");
9740
10088
  const parsed = JSON.parse(raw);
9741
10089
  if (Array.isArray(parsed.agents)) {
9742
- state4.agents = parsed.agents;
9743
- log(`[startup] rehydrated ${state4.agents.length} agent state(s) from ${stateFile}`);
10090
+ state5.agents = parsed.agents;
10091
+ log(`[startup] rehydrated ${state5.agents.length} agent state(s) from ${stateFile}`);
9744
10092
  }
9745
10093
  if (parsed.circuitBreakerTrips && typeof parsed.circuitBreakerTrips === "object") {
9746
10094
  restartBreaker.hydrate(parsed.circuitBreakerTrips);
@@ -9752,7 +10100,7 @@ function startManager(opts) {
9752
10100
  log(`[startup] state rehydration failed (continuing with empty state): ${err.message}`);
9753
10101
  }
9754
10102
  log(
9755
- `[startup] worker pid=${process.pid} ppid=${process.ppid} node=${process.version} log=${join7(homedir4(), ".augmented", "manager.log")}`
10103
+ `[startup] worker pid=${process.pid} ppid=${process.ppid} node=${process.version} log=${join8(homedir4(), ".augmented", "manager.log")}`
9756
10104
  );
9757
10105
  deployMcpAssets();
9758
10106
  reapOrphanChannelMcps({ log });
@@ -9773,7 +10121,7 @@ async function reapOrphanedClaudePids() {
9773
10121
  const looksLikeClaude = (pid) => {
9774
10122
  if (process.platform !== "linux") return true;
9775
10123
  try {
9776
- const comm = readFileSync8(`/proc/${pid}/comm`, "utf-8").trim().toLowerCase();
10124
+ const comm = readFileSync9(`/proc/${pid}/comm`, "utf-8").trim().toLowerCase();
9777
10125
  return comm.includes("claude");
9778
10126
  } catch {
9779
10127
  return false;
@@ -9883,14 +10231,14 @@ function restartRunningChannelMcps(basenames) {
9883
10231
  }
9884
10232
  }
9885
10233
  function deployMcpAssets() {
9886
- const targetDir = join7(homedir4(), ".augmented", "_mcp");
10234
+ const targetDir = join8(homedir4(), ".augmented", "_mcp");
9887
10235
  mkdirSync4(targetDir, { recursive: true });
9888
10236
  const moduleDir = dirname3(fileURLToPath(import.meta.url));
9889
10237
  let mcpSourceDir = "";
9890
10238
  let dir = moduleDir;
9891
10239
  for (let i = 0; i < 6; i++) {
9892
- const candidate = join7(dir, "dist", "mcp");
9893
- if (existsSync5(join7(candidate, "index.js"))) {
10240
+ const candidate = join8(dir, "dist", "mcp");
10241
+ if (existsSync5(join8(candidate, "index.js"))) {
9894
10242
  mcpSourceDir = candidate;
9895
10243
  break;
9896
10244
  }
@@ -9906,7 +10254,7 @@ function deployMcpAssets() {
9906
10254
  const fileHash = (p) => {
9907
10255
  try {
9908
10256
  if (!existsSync5(p)) return null;
9909
- return createHash3("sha256").update(readFileSync8(p)).digest("hex");
10257
+ return createHash3("sha256").update(readFileSync9(p)).digest("hex");
9910
10258
  } catch {
9911
10259
  return null;
9912
10260
  }
@@ -9927,8 +10275,8 @@ function deployMcpAssets() {
9927
10275
  "teams-channel.js"
9928
10276
  // ENG-6019
9929
10277
  ]) {
9930
- const src = join7(mcpSourceDir, file);
9931
- const dst = join7(targetDir, file);
10278
+ const src = join8(mcpSourceDir, file);
10279
+ const dst = join8(targetDir, file);
9932
10280
  if (!existsSync5(src)) continue;
9933
10281
  const before = fileHash(dst);
9934
10282
  try {
@@ -9946,16 +10294,16 @@ function deployMcpAssets() {
9946
10294
  log(`[manager] Bundle(s) updated: ${changedBasenames.join(", ")} \u2014 signalling running instances to restart`);
9947
10295
  restartRunningChannelMcps(changedBasenames);
9948
10296
  }
9949
- const localMcpPath = join7(targetDir, "index.js");
10297
+ const localMcpPath = join8(targetDir, "index.js");
9950
10298
  try {
9951
- const agentsDir = join7(homedir4(), ".augmented", "agents");
10299
+ const agentsDir = join8(homedir4(), ".augmented", "agents");
9952
10300
  if (existsSync5(agentsDir)) {
9953
- for (const entry of readdirSync3(agentsDir, { withFileTypes: true })) {
10301
+ for (const entry of readdirSync4(agentsDir, { withFileTypes: true })) {
9954
10302
  if (!entry.isDirectory()) continue;
9955
10303
  for (const subdir of ["provision", "project"]) {
9956
- const mcpJsonPath = join7(agentsDir, entry.name, subdir, ".mcp.json");
10304
+ const mcpJsonPath = join8(agentsDir, entry.name, subdir, ".mcp.json");
9957
10305
  try {
9958
- const raw = readFileSync8(mcpJsonPath, "utf-8");
10306
+ const raw = readFileSync9(mcpJsonPath, "utf-8");
9959
10307
  if (!raw.includes("@integrity-labs/augmented-mcp")) continue;
9960
10308
  const mcpConfig = JSON.parse(raw);
9961
10309
  const augServer = mcpConfig.mcpServers?.["augmented"];