@integrity-labs/agt-cli 0.28.36 → 0.28.38

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.
@@ -23,7 +23,7 @@ import {
23
23
  requireHost,
24
24
  safeWriteJsonAtomic,
25
25
  setConfigHash
26
- } from "../chunk-DUFH3RSX.js";
26
+ } from "../chunk-IJT4B5PH.js";
27
27
  import {
28
28
  getProjectDir as getProjectDir2,
29
29
  getReadyTasks,
@@ -106,13 +106,39 @@ import {
106
106
  } from "../chunk-XWVM4KPK.js";
107
107
 
108
108
  // src/lib/manager-worker.ts
109
- import { createHash as createHash6 } from "crypto";
110
- import { readFileSync as readFileSync13, writeFileSync as writeFileSync4, mkdirSync as mkdirSync4, existsSync as existsSync9, rmSync as rmSync3, readdirSync as readdirSync5, statSync as statSync4, unlinkSync, copyFileSync } from "fs";
109
+ import { createHash as createHash8 } from "crypto";
110
+ import { readFileSync as readFileSync14, writeFileSync as writeFileSync5, mkdirSync as mkdirSync5, existsSync as existsSync9, rmSync as rmSync3, readdirSync as readdirSync5, statSync as statSync4, unlinkSync, copyFileSync } from "fs";
111
111
  import { execFileSync as syncExecFile } from "child_process";
112
- import { join as join15, dirname as dirname3 } from "path";
113
- import { homedir as homedir8 } from "os";
112
+ import { join as join16, dirname as dirname4 } from "path";
113
+ import { homedir as homedir9 } from "os";
114
114
  import { fileURLToPath } from "url";
115
115
 
116
+ // src/lib/claude-code-upgrade-throttle.ts
117
+ import { mkdirSync, readFileSync, writeFileSync } from "fs";
118
+ import { dirname, join } from "path";
119
+ import { homedir } from "os";
120
+ var CLAUDE_CODE_UPGRADE_CHECK_INTERVAL_MS = 24 * 60 * 60 * 1e3;
121
+ function claudeCodeUpgradeMarkerPath() {
122
+ return join(homedir(), ".augmented", ".last-claude-code-upgrade-check");
123
+ }
124
+ function stampClaudeCodeUpgradeMarker() {
125
+ try {
126
+ const markerPath = claudeCodeUpgradeMarkerPath();
127
+ mkdirSync(dirname(markerPath), { recursive: true });
128
+ writeFileSync(markerPath, String(Date.now()));
129
+ } catch {
130
+ }
131
+ }
132
+ function claudeCodeUpgradeThrottled() {
133
+ try {
134
+ const lastCheck = parseInt(readFileSync(claudeCodeUpgradeMarkerPath(), "utf-8").trim(), 10);
135
+ if (!Number.isFinite(lastCheck)) return false;
136
+ return Date.now() - lastCheck < CLAUDE_CODE_UPGRADE_CHECK_INTERVAL_MS;
137
+ } catch {
138
+ return false;
139
+ }
140
+ }
141
+
116
142
  // src/lib/mcp-config-drift.ts
117
143
  import { createHash } from "crypto";
118
144
  function decideMcpDriftAction(currentHash, knownHash) {
@@ -767,8 +793,8 @@ function extractSlackBehaviourSubset(config2) {
767
793
  }
768
794
 
769
795
  // src/lib/channel-quarantine.ts
770
- import { readFileSync } from "fs";
771
- import { join } from "path";
796
+ import { readFileSync as readFileSync2 } from "fs";
797
+ import { join as join2 } from "path";
772
798
  var ESSENTIAL_CHANNEL_KEYS = /* @__PURE__ */ new Set(["direct-chat", "augmented"]);
773
799
  var OPTIONAL_CHANNEL_KEYS = /* @__PURE__ */ new Set([
774
800
  "telegram",
@@ -797,7 +823,7 @@ function classifyChannelCriticality(serverKey, entry) {
797
823
  return "essential";
798
824
  }
799
825
  function defaultQuarantinePath(configDir) {
800
- return join(configDir, "channel-quarantine.json");
826
+ return join2(configDir, "channel-quarantine.json");
801
827
  }
802
828
  var ChannelQuarantineStore = class {
803
829
  path;
@@ -808,7 +834,7 @@ var ChannelQuarantineStore = class {
808
834
  load() {
809
835
  if (this.cache) return this.cache;
810
836
  try {
811
- const raw = readFileSync(this.path, "utf-8");
837
+ const raw = readFileSync2(this.path, "utf-8");
812
838
  const parsed = JSON.parse(raw);
813
839
  this.cache = isQuarantineFile(parsed) ? parsed : {};
814
840
  } catch {
@@ -1395,8 +1421,8 @@ function runCliProbe(binary, args, opts = {}) {
1395
1421
  }
1396
1422
 
1397
1423
  // src/lib/self-update-coalesce.ts
1398
- import { readFileSync as readFileSync2, writeFileSync, mkdirSync } from "fs";
1399
- import { dirname } from "path";
1424
+ import { readFileSync as readFileSync3, writeFileSync as writeFileSync2, mkdirSync as mkdirSync2 } from "fs";
1425
+ import { dirname as dirname2 } from "path";
1400
1426
  var DEFAULT_SELF_UPDATE_COALESCE_MS = 30 * 60 * 1e3;
1401
1427
  function resolveCoalesceWindowMs(env = process.env) {
1402
1428
  const raw = env.AGT_SELF_UPDATE_COALESCE_MS;
@@ -1405,7 +1431,7 @@ function resolveCoalesceWindowMs(env = process.env) {
1405
1431
  if (!Number.isFinite(parsed) || parsed < 0) return DEFAULT_SELF_UPDATE_COALESCE_MS;
1406
1432
  return Math.trunc(parsed);
1407
1433
  }
1408
- function readLastSelfUpdateAppliedMs(markerPath, now = Date.now(), read = (p) => readFileSync2(p, "utf-8")) {
1434
+ function readLastSelfUpdateAppliedMs(markerPath, now = Date.now(), read = (p) => readFileSync3(p, "utf-8")) {
1409
1435
  let raw;
1410
1436
  try {
1411
1437
  raw = read(markerPath);
@@ -1418,8 +1444,8 @@ function readLastSelfUpdateAppliedMs(markerPath, now = Date.now(), read = (p) =>
1418
1444
  return v;
1419
1445
  }
1420
1446
  function stampLastSelfUpdateApplied(markerPath, now = Date.now(), write = (p, v) => {
1421
- mkdirSync(dirname(p), { recursive: true });
1422
- writeFileSync(p, v);
1447
+ mkdirSync2(dirname2(p), { recursive: true });
1448
+ writeFileSync2(p, v);
1423
1449
  }) {
1424
1450
  try {
1425
1451
  write(markerPath, String(now));
@@ -1549,11 +1575,11 @@ function decideRestartGate(opts) {
1549
1575
  }
1550
1576
 
1551
1577
  // src/lib/claude-pid-tracker.ts
1552
- import { existsSync, readFileSync as readFileSync3 } from "fs";
1578
+ import { existsSync, readFileSync as readFileSync4 } from "fs";
1553
1579
  function readPidFile(path) {
1554
1580
  if (!existsSync(path)) return { version: 1, spawns: [] };
1555
1581
  try {
1556
- const raw = JSON.parse(readFileSync3(path, "utf-8"));
1582
+ const raw = JSON.parse(readFileSync4(path, "utf-8"));
1557
1583
  if (raw.version !== 1 || !Array.isArray(raw.spawns)) return { version: 1, spawns: [] };
1558
1584
  const spawns = raw.spawns.filter(
1559
1585
  (s) => !!s && typeof s.pid === "number" && Number.isFinite(s.pid) && s.pid > 0
@@ -1606,7 +1632,7 @@ function formatReaperBootLine(opts) {
1606
1632
  }
1607
1633
 
1608
1634
  // src/lib/direct-chat-spawn-gate.ts
1609
- import { join as join2 } from "path";
1635
+ import { join as join3 } from "path";
1610
1636
  var DEFAULT_DIRECT_CHAT_HOST_CONCURRENCY = 2;
1611
1637
  var DEFAULT_DIRECT_CHAT_PER_AGENT_CONCURRENCY = 1;
1612
1638
  var DEFAULT_DIRECT_CHAT_MAX_AGE_MS = 30 * 6e4;
@@ -1619,7 +1645,7 @@ function directChatMaxAgeMs() {
1619
1645
  return Number.isFinite(raw) && raw >= 0 ? raw : DEFAULT_DIRECT_CHAT_MAX_AGE_MS;
1620
1646
  }
1621
1647
  function directChatDoorbellPath(agentId, home) {
1622
- return join2(home, ".augmented", agentId, "direct-chat-doorbell");
1648
+ return join3(home, ".augmented", agentId, "direct-chat-doorbell");
1623
1649
  }
1624
1650
  function isDirectChatMessageExpired(createdAt, nowMs, maxAgeMs) {
1625
1651
  if (!maxAgeMs || maxAgeMs <= 0) return false;
@@ -1722,8 +1748,8 @@ function collectEnvGates(env) {
1722
1748
  }
1723
1749
 
1724
1750
  // src/lib/artifact-stream.ts
1725
- import { join as join3 } from "path";
1726
- import { homedir } from "os";
1751
+ import { join as join4 } from "path";
1752
+ import { homedir as homedir2 } from "os";
1727
1753
  import { readdir, stat, readFile } from "fs/promises";
1728
1754
  var ARTEFACT_ENTRY_FILE = "index.html";
1729
1755
  function errMessage(err) {
@@ -1808,7 +1834,7 @@ var ArtifactStreamScanner = class {
1808
1834
  return;
1809
1835
  }
1810
1836
  for (const name of names) {
1811
- const file = join3(this.artifactsDir, name, ARTEFACT_ENTRY_FILE);
1837
+ const file = join4(this.artifactsDir, name, ARTEFACT_ENTRY_FILE);
1812
1838
  const mtime = await this.fsDeps.mtimeMs(file).catch(() => null);
1813
1839
  if (mtime === null) continue;
1814
1840
  if (this.seenMtime.get(name) === mtime) continue;
@@ -1839,7 +1865,7 @@ var ArtifactStreamScanner = class {
1839
1865
  }
1840
1866
  };
1841
1867
  function artifactsDirFor(codeName) {
1842
- return join3(homedir(), ".augmented", codeName, "artifacts");
1868
+ return join4(homedir2(), ".augmented", codeName, "artifacts");
1843
1869
  }
1844
1870
  var nodeArtifactFs = {
1845
1871
  async listArtefactNames(artifactsDir) {
@@ -1914,8 +1940,8 @@ async function maybeReportUsageBanner(args) {
1914
1940
  }
1915
1941
 
1916
1942
  // src/lib/token-usage-monitor.ts
1917
- import { readdirSync, readFileSync as readFileSync4, statSync } from "fs";
1918
- import { join as join4 } from "path";
1943
+ import { readdirSync, readFileSync as readFileSync5, statSync } from "fs";
1944
+ import { join as join5 } from "path";
1919
1945
  var MIN_CHECK_INTERVAL_MS2 = 6e4;
1920
1946
  var TRANSCRIPT_MTIME_WINDOW_MS = 2 * 24 * 60 * 60 * 1e3;
1921
1947
  var MAX_ENTRIES_PER_POST = 200;
@@ -1944,7 +1970,7 @@ async function maybeReportTokenUsage(args) {
1944
1970
  if (!name.endsWith(".jsonl")) continue;
1945
1971
  const sessionId = name.slice(0, -".jsonl".length);
1946
1972
  if (!sessionId) continue;
1947
- const path = join4(dir, name);
1973
+ const path = join5(dir, name);
1948
1974
  let st;
1949
1975
  try {
1950
1976
  st = statSync(path);
@@ -1960,7 +1986,7 @@ async function maybeReportTokenUsage(args) {
1960
1986
  }
1961
1987
  let content;
1962
1988
  try {
1963
- content = readFileSync4(path, "utf-8");
1989
+ content = readFileSync5(path, "utf-8");
1964
1990
  } catch (err) {
1965
1991
  log2(`[token-usage] read failed for '${codeName}/${name}': ${err.message}`);
1966
1992
  continue;
@@ -2041,8 +2067,8 @@ async function maybeReportTokenUsage(args) {
2041
2067
  }
2042
2068
 
2043
2069
  // src/lib/workflow-run-reconciler.ts
2044
- import { readdirSync as readdirSync2, readFileSync as readFileSync5, statSync as statSync2 } from "fs";
2045
- import { join as join5 } from "path";
2070
+ import { readdirSync as readdirSync2, readFileSync as readFileSync6, statSync as statSync2 } from "fs";
2071
+ import { join as join6 } from "path";
2046
2072
  var MIN_CHECK_INTERVAL_MS3 = 5 * 6e4;
2047
2073
  var SETTLE_MS = 3e4;
2048
2074
  var TRANSCRIPT_MTIME_WINDOW_MS2 = 2 * 24 * 60 * 60 * 1e3;
@@ -2061,7 +2087,7 @@ function collectJsonlRecursive(dir, minMtimeMs, out, depth) {
2061
2087
  return;
2062
2088
  }
2063
2089
  for (const name of entries) {
2064
- const p = join5(dir, name);
2090
+ const p = join6(dir, name);
2065
2091
  let st;
2066
2092
  try {
2067
2093
  st = statSync2(p);
@@ -2084,7 +2110,7 @@ function enumerateTranscriptFiles(transcriptDir, nowMs, minMtimeMs = nowMs - TRA
2084
2110
  return out;
2085
2111
  }
2086
2112
  for (const name of entries) {
2087
- const path = join5(transcriptDir, name);
2113
+ const path = join6(transcriptDir, name);
2088
2114
  let st;
2089
2115
  try {
2090
2116
  st = statSync2(path);
@@ -2096,7 +2122,7 @@ function enumerateTranscriptFiles(transcriptDir, nowMs, minMtimeMs = nowMs - TRA
2096
2122
  continue;
2097
2123
  }
2098
2124
  if (st.isDirectory()) {
2099
- collectJsonlRecursive(join5(path, "subagents"), minMtimeMs, out, 0);
2125
+ collectJsonlRecursive(join6(path, "subagents"), minMtimeMs, out, 0);
2100
2126
  }
2101
2127
  }
2102
2128
  return out;
@@ -2141,7 +2167,7 @@ async function maybeReconcileWorkflowRunTokens(args) {
2141
2167
  const contents = [];
2142
2168
  for (const path of files) {
2143
2169
  try {
2144
- contents.push(readFileSync5(path, "utf-8"));
2170
+ contents.push(readFileSync6(path, "utf-8"));
2145
2171
  } catch {
2146
2172
  }
2147
2173
  }
@@ -2186,8 +2212,8 @@ async function maybeReconcileWorkflowRunTokens(args) {
2186
2212
  }
2187
2213
 
2188
2214
  // src/lib/conversation-evaluator.ts
2189
- import { readdirSync as readdirSync3, readFileSync as readFileSync6, statSync as statSync3 } from "fs";
2190
- import { join as join6 } from "path";
2215
+ import { readdirSync as readdirSync3, readFileSync as readFileSync7, statSync as statSync3 } from "fs";
2216
+ import { join as join7 } from "path";
2191
2217
  var MIN_CHECK_INTERVAL_MS4 = 5 * 6e4;
2192
2218
  var TRANSCRIPT_MTIME_WINDOW_MS3 = 3 * 24 * 60 * 60 * 1e3;
2193
2219
  var WINDOW_PAD_MS = 5 * 6e4;
@@ -2424,7 +2450,7 @@ function readRecentTurns(dir, nowMs) {
2424
2450
  const turns = [];
2425
2451
  for (const name of entries) {
2426
2452
  if (!name.endsWith(".jsonl")) continue;
2427
- const full = join6(dir, name);
2453
+ const full = join7(dir, name);
2428
2454
  let mtimeMs;
2429
2455
  try {
2430
2456
  mtimeMs = statSync3(full).mtimeMs;
@@ -2434,7 +2460,7 @@ function readRecentTurns(dir, nowMs) {
2434
2460
  if (nowMs - mtimeMs > TRANSCRIPT_MTIME_WINDOW_MS3) continue;
2435
2461
  let content;
2436
2462
  try {
2437
- content = readFileSync6(full, "utf8");
2463
+ content = readFileSync7(full, "utf8");
2438
2464
  } catch {
2439
2465
  continue;
2440
2466
  }
@@ -2603,11 +2629,11 @@ async function reportSkip2(api2, agentId, conversationId, log2, codeName) {
2603
2629
  }
2604
2630
 
2605
2631
  // src/lib/activity-cache-monitor.ts
2606
- import { existsSync as existsSync2, readFileSync as readFileSync7 } from "fs";
2607
- import { homedir as homedir2 } from "os";
2608
- import { join as join7 } from "path";
2632
+ import { existsSync as existsSync2, readFileSync as readFileSync8 } from "fs";
2633
+ import { homedir as homedir3 } from "os";
2634
+ import { join as join8 } from "path";
2609
2635
  var MIN_CHECK_INTERVAL_MS6 = 6e4;
2610
- var STATS_CACHE_PATH = join7(homedir2(), ".claude", "stats-cache.json");
2636
+ var STATS_CACHE_PATH = join8(homedir3(), ".claude", "stats-cache.json");
2611
2637
  var ISO_DATE_RE = /^\d{4}-\d{2}-\d{2}$/;
2612
2638
  var state5 = { lastObservedDate: null, lastCheckedAt: 0 };
2613
2639
  function selectNewDailyRows(raw, lastObservedDate) {
@@ -2655,7 +2681,7 @@ async function maybeReportActivityCache(args) {
2655
2681
  }
2656
2682
  let raw;
2657
2683
  try {
2658
- raw = readFileSync7(STATS_CACHE_PATH, "utf-8");
2684
+ raw = readFileSync8(STATS_CACHE_PATH, "utf-8");
2659
2685
  } catch (err) {
2660
2686
  log2(`[activity-cache] readFileSync failed: ${err.message}`);
2661
2687
  return;
@@ -3104,8 +3130,8 @@ var GatewayClientPool = class extends EventEmitter {
3104
3130
 
3105
3131
  // src/lib/claude-auth-detect.ts
3106
3132
  import { readFile as readFile2, readdir as readdir2 } from "fs/promises";
3107
- import { homedir as homedir3, platform } from "os";
3108
- import { join as join8 } from "path";
3133
+ import { homedir as homedir4, platform } from "os";
3134
+ import { join as join9 } from "path";
3109
3135
  import { execFile as execFile2 } from "child_process";
3110
3136
  import { promisify } from "util";
3111
3137
  var execFileAsync = promisify(execFile2);
@@ -3120,8 +3146,8 @@ async function detectClaudeAuth() {
3120
3146
  }
3121
3147
  async function findClaudeCredentialsPaths() {
3122
3148
  const candidates = [
3123
- join8(homedir3(), ".claude", ".credentials.json"),
3124
- join8(homedir3(), ".claude", "credentials.json")
3149
+ join9(homedir4(), ".claude", ".credentials.json"),
3150
+ join9(homedir4(), ".claude", "credentials.json")
3125
3151
  ];
3126
3152
  const isLinuxRoot = platform() === "linux" && typeof process.getuid === "function" && process.getuid() === 0;
3127
3153
  if (isLinuxRoot) {
@@ -3129,8 +3155,8 @@ async function findClaudeCredentialsPaths() {
3129
3155
  const entries = await readdir2("/home", { withFileTypes: true });
3130
3156
  for (const entry of entries) {
3131
3157
  if (!entry.isDirectory()) continue;
3132
- candidates.push(join8("/home", entry.name, ".claude", ".credentials.json"));
3133
- candidates.push(join8("/home", entry.name, ".claude", "credentials.json"));
3158
+ candidates.push(join9("/home", entry.name, ".claude", ".credentials.json"));
3159
+ candidates.push(join9("/home", entry.name, ".claude", "credentials.json"));
3134
3160
  }
3135
3161
  } catch {
3136
3162
  }
@@ -3222,18 +3248,18 @@ function normalize(value) {
3222
3248
  }
3223
3249
 
3224
3250
  // src/lib/channel-hash-cache.ts
3225
- import { existsSync as existsSync3, readFileSync as readFileSync8, writeFileSync as writeFileSync2 } from "fs";
3226
- import { join as join9 } from "path";
3251
+ import { existsSync as existsSync3, readFileSync as readFileSync9, writeFileSync as writeFileSync3 } from "fs";
3252
+ import { join as join10 } from "path";
3227
3253
  var CACHE_FILENAME = "channel-hash-cache.json";
3228
3254
  function getChannelHashCacheFile(configDir) {
3229
- return join9(configDir, CACHE_FILENAME);
3255
+ return join10(configDir, CACHE_FILENAME);
3230
3256
  }
3231
3257
  function loadChannelHashCache(target, configDir) {
3232
3258
  const path = getChannelHashCacheFile(configDir);
3233
3259
  if (!existsSync3(path)) return;
3234
3260
  let parsed;
3235
3261
  try {
3236
- parsed = JSON.parse(readFileSync8(path, "utf-8"));
3262
+ parsed = JSON.parse(readFileSync9(path, "utf-8"));
3237
3263
  } catch {
3238
3264
  return;
3239
3265
  }
@@ -3247,7 +3273,7 @@ function saveChannelHashCache(source, configDir) {
3247
3273
  const obj = {};
3248
3274
  for (const [key, value] of source) obj[key] = value;
3249
3275
  try {
3250
- writeFileSync2(path, JSON.stringify(obj, null, 2));
3276
+ writeFileSync3(path, JSON.stringify(obj, null, 2));
3251
3277
  } catch {
3252
3278
  }
3253
3279
  }
@@ -3634,9 +3660,9 @@ function planGlobalSkillSync(globalSkills, prevIds, hashOf, knownHash) {
3634
3660
 
3635
3661
  // src/lib/manager/runtime.ts
3636
3662
  import { createHash as createHash4 } from "crypto";
3637
- import { readFileSync as readFileSync9, appendFileSync, mkdirSync as mkdirSync2, chmodSync, existsSync as existsSync4 } from "fs";
3638
- import { join as join10, dirname as dirname2 } from "path";
3639
- import { homedir as homedir4 } from "os";
3663
+ import { readFileSync as readFileSync10, appendFileSync, mkdirSync as mkdirSync3, chmodSync, existsSync as existsSync4 } from "fs";
3664
+ import { join as join11, dirname as dirname3 } from "path";
3665
+ import { homedir as homedir5 } from "os";
3640
3666
  function redactForDiskLog(value) {
3641
3667
  try {
3642
3668
  return value.replace(/\b(Bearer\s+)[A-Za-z0-9._-]+\b/gi, "$1[REDACTED]").replace(/\bxox[baprs]-[A-Za-z0-9-]+\b/g, "[REDACTED-SLACK]").replace(/\btlk_[A-Za-z0-9._-]+\b/g, "[REDACTED-HOST]").replace(/\bsk-ant-[A-Za-z0-9_-]+\b/g, "[REDACTED-ANTHROPIC]").replace(/\b\d{8,12}:[A-Za-z0-9_-]{30,}\b/g, "[REDACTED-TELEGRAM]").replace(
@@ -3656,8 +3682,8 @@ function log(msg) {
3656
3682
  `;
3657
3683
  if (!managerLogPath) {
3658
3684
  try {
3659
- managerLogPath = join10(homedir4(), ".augmented", "manager.log");
3660
- mkdirSync2(dirname2(managerLogPath), { recursive: true });
3685
+ managerLogPath = join11(homedir5(), ".augmented", "manager.log");
3686
+ mkdirSync3(dirname3(managerLogPath), { recursive: true });
3661
3687
  if (existsSync4(managerLogPath)) {
3662
3688
  chmodSync(managerLogPath, 384);
3663
3689
  }
@@ -3686,7 +3712,7 @@ function sha256(content) {
3686
3712
  }
3687
3713
  function hashFile(filePath) {
3688
3714
  try {
3689
- const content = readFileSync9(filePath, "utf-8");
3715
+ const content = readFileSync10(filePath, "utf-8");
3690
3716
  return sha256(content);
3691
3717
  } catch {
3692
3718
  return null;
@@ -3786,8 +3812,8 @@ function resolveModelChain(refreshData) {
3786
3812
 
3787
3813
  // src/lib/manager/claude-auth.ts
3788
3814
  import { existsSync as existsSync5, rmSync } from "fs";
3789
- import { join as join11 } from "path";
3790
- import { homedir as homedir5 } from "os";
3815
+ import { join as join12 } from "path";
3816
+ import { homedir as homedir6 } from "os";
3791
3817
  async function applyClaudeAuthToEnv(childEnv, label) {
3792
3818
  const apiKey = getApiKey();
3793
3819
  if (!apiKey) {
@@ -3799,9 +3825,9 @@ async function applyClaudeAuthToEnv(childEnv, label) {
3799
3825
  throw new Error("claude_auth_mode=api_key but /host/exchange returned no decrypted key");
3800
3826
  }
3801
3827
  childEnv.ANTHROPIC_API_KEY = exchange.anthropicApiKey;
3802
- const claudeDir = join11(homedir5(), ".claude");
3828
+ const claudeDir = join12(homedir6(), ".claude");
3803
3829
  for (const filename of [".credentials.json", "credentials.json"]) {
3804
- const p = join11(claudeDir, filename);
3830
+ const p = join12(claudeDir, filename);
3805
3831
  if (existsSync5(p)) {
3806
3832
  try {
3807
3833
  rmSync(p, { force: true });
@@ -3816,8 +3842,8 @@ async function applyClaudeAuthToEnv(childEnv, label) {
3816
3842
  }
3817
3843
 
3818
3844
  // src/lib/manager/kanban/parsers.ts
3819
- import { existsSync as existsSync6, readFileSync as readFileSync10 } from "fs";
3820
- import { join as join12 } from "path";
3845
+ import { existsSync as existsSync6, readFileSync as readFileSync11 } from "fs";
3846
+ import { join as join13 } from "path";
3821
3847
  var STANDUP_TEMPLATES = /* @__PURE__ */ new Set(["daily-standup", "end-of-day-summary"]);
3822
3848
  var TASK_UPDATE_TEMPLATES = /* @__PURE__ */ new Set(["hourly-status", "task-update"]);
3823
3849
  var PLAN_TEMPLATES = /* @__PURE__ */ new Set(["morning-plan"]);
@@ -3937,12 +3963,12 @@ function getBuiltInSkillContent(skillId) {
3937
3963
  if (builtInSkillCache.has(skillId)) return builtInSkillCache.get(skillId);
3938
3964
  try {
3939
3965
  const candidates = [
3940
- join12(process.cwd(), "skills", skillId, "SKILL.md"),
3941
- join12(new URL(".", import.meta.url).pathname, "..", "..", "..", "..", "..", "..", "skills", skillId, "SKILL.md")
3966
+ join13(process.cwd(), "skills", skillId, "SKILL.md"),
3967
+ join13(new URL(".", import.meta.url).pathname, "..", "..", "..", "..", "..", "..", "skills", skillId, "SKILL.md")
3942
3968
  ];
3943
3969
  for (const candidate of candidates) {
3944
3970
  if (existsSync6(candidate)) {
3945
- const content = readFileSync10(candidate, "utf-8");
3971
+ const content = readFileSync11(candidate, "utf-8");
3946
3972
  const files = [{ relativePath: "SKILL.md", content }];
3947
3973
  builtInSkillCache.set(skillId, files);
3948
3974
  return files;
@@ -4407,11 +4433,140 @@ async function sendTaskNotification(agentCodeName, channel, to, text) {
4407
4433
  return { ok: false, error_code: `UNKNOWN_CHANNEL:${channel}` };
4408
4434
  }
4409
4435
 
4410
- // src/lib/manager/scheduler.ts
4436
+ // src/lib/manager/scheduler/tasks.ts
4437
+ function buildSchedulerTaskInput(t) {
4438
+ return {
4439
+ id: t.id,
4440
+ template_id: t.template_id,
4441
+ name: t.name,
4442
+ schedule_kind: t.schedule_kind,
4443
+ schedule_expr: t.schedule_expr ?? null,
4444
+ schedule_every: t.schedule_every ?? null,
4445
+ schedule_at: t.schedule_at ?? null,
4446
+ timezone: t.timezone ?? "UTC",
4447
+ prompt: t.prompt ?? "",
4448
+ session_target: t.session_target ?? "isolated",
4449
+ delivery_mode: t.delivery_mode ?? "none",
4450
+ delivery_policy: t.delivery_policy ?? "always",
4451
+ delivery_channel: t.delivery_channel ?? null,
4452
+ delivery_to: t.delivery_to ?? null,
4453
+ enabled: t.enabled ?? true,
4454
+ triggered_at: t.triggered_at ?? null
4455
+ };
4456
+ }
4457
+ function deriveScheduledTaskNotify(task) {
4458
+ if (task.deliveryChannel !== "msteams") return {};
4459
+ const to = task.deliveryTo;
4460
+ let conversationId = null;
4461
+ if (typeof to === "string" && to.trim().length > 0) {
4462
+ conversationId = to.trim();
4463
+ } else if (to && typeof to === "object") {
4464
+ const cid = to.conversation_id;
4465
+ if (typeof cid === "string" && cid.trim().length > 0) conversationId = cid.trim();
4466
+ }
4467
+ if (!conversationId) return {};
4468
+ return { notify_channel: "msteams", notify_to: conversationId };
4469
+ }
4470
+ function isScheduledViaKanbanEnabled() {
4471
+ const v = process.env["AGT_SCHEDULED_VIA_KANBAN"];
4472
+ return !(v === "0" || v?.toLowerCase() === "false");
4473
+ }
4474
+
4475
+ // src/lib/manager/scheduler/runs.ts
4411
4476
  import { createHash as createHash5 } from "crypto";
4412
- import { readFileSync as readFileSync11, existsSync as existsSync7 } from "fs";
4413
- import { homedir as homedir6 } from "os";
4414
- import { join as join13 } from "path";
4477
+ async function startRun(opts) {
4478
+ try {
4479
+ const res = await api.post(
4480
+ "/host/runs/start",
4481
+ opts
4482
+ );
4483
+ return { run_id: res.run_id ?? null, kanban_item_id: res.kanban_item_id ?? null };
4484
+ } catch (err) {
4485
+ const errText = err instanceof Error ? err.message : String(err);
4486
+ const errId = createHash5("sha256").update(errText).digest("hex").slice(0, 12);
4487
+ log(`[runs] start failed for agent_id=${opts.agent_id} source_type=${opts.source_type} error_id=${errId}`);
4488
+ return { run_id: null, kanban_item_id: null };
4489
+ }
4490
+ }
4491
+ async function finishRun(runId, outcome, options = {}) {
4492
+ try {
4493
+ await api.post("/host/runs/finish", {
4494
+ run_id: runId,
4495
+ outcome,
4496
+ outcome_message: options.outcomeMessage,
4497
+ metadata: options.metadata,
4498
+ complete_kanban_item_id: options.completeKanbanItemId ?? void 0,
4499
+ result: options.result
4500
+ });
4501
+ } catch (err) {
4502
+ const errText = err instanceof Error ? err.message : String(err);
4503
+ const errId = createHash5("sha256").update(errText).digest("hex").slice(0, 12);
4504
+ log(`[runs] finish failed for run_id=${runId} outcome=${outcome} error_id=${errId}`);
4505
+ }
4506
+ }
4507
+ var MAX_PRIOR_RUNS = 5;
4508
+ async function fetchPriorScheduledRuns(agentId, taskId) {
4509
+ try {
4510
+ const data = await api.post("/host/scheduled-tasks/recent-outputs", {
4511
+ agent_id: agentId,
4512
+ task_id: taskId,
4513
+ since_hours: 24,
4514
+ limit: MAX_PRIOR_RUNS
4515
+ });
4516
+ const rows = Array.isArray(data?.runs) ? data.runs.slice(0, MAX_PRIOR_RUNS) : [];
4517
+ return rows.filter((r) => typeof r.output_text === "string" && r.output_text.length > 0).map((r) => ({ startedAt: r.started_at, output: r.output_text }));
4518
+ } catch (err) {
4519
+ const errText = err instanceof Error ? err.message : String(err);
4520
+ const errId = createHash5("sha256").update(errText).digest("hex").slice(0, 12);
4521
+ log(`[runs] prior-runs lookup failed for task_id=${taskId} error_id=${errId}`);
4522
+ return [];
4523
+ }
4524
+ }
4525
+
4526
+ // src/lib/manager/scheduler/state.ts
4527
+ var inFlightClaudeTasks = /* @__PURE__ */ new Set();
4528
+ var claudeTaskConcurrency = /* @__PURE__ */ new Map();
4529
+ var MAX_CLAUDE_CONCURRENCY = 2;
4530
+ var claudeSchedulerStates = /* @__PURE__ */ new Map();
4531
+ var scheduledRunsByCode = /* @__PURE__ */ new Map();
4532
+ var claimedScheduledCards = /* @__PURE__ */ new Set();
4533
+ var completedScheduledCards = /* @__PURE__ */ new Set();
4534
+ function claimScheduledCardDelivery(cardId) {
4535
+ if (claimedScheduledCards.has(cardId)) return false;
4536
+ claimedScheduledCards.add(cardId);
4537
+ return true;
4538
+ }
4539
+ function releaseScheduledCardDelivery(cardId) {
4540
+ claimedScheduledCards.delete(cardId);
4541
+ }
4542
+ function markScheduledCardDeliveryComplete(cardId) {
4543
+ completedScheduledCards.add(cardId);
4544
+ }
4545
+ function trackScheduledRun(codeName, cardId, runId) {
4546
+ let m = scheduledRunsByCode.get(codeName);
4547
+ if (!m) {
4548
+ m = /* @__PURE__ */ new Map();
4549
+ scheduledRunsByCode.set(codeName, m);
4550
+ }
4551
+ m.set(cardId, runId);
4552
+ }
4553
+ function isScheduledCardTracked(cardId) {
4554
+ for (const m of scheduledRunsByCode.values()) {
4555
+ if (m.has(cardId)) return true;
4556
+ }
4557
+ return false;
4558
+ }
4559
+ function closeScheduledRunsForCode(codeName, outcome, reason) {
4560
+ const m = scheduledRunsByCode.get(codeName);
4561
+ if (!m || m.size === 0) return;
4562
+ scheduledRunsByCode.delete(codeName);
4563
+ for (const runId of m.values()) {
4564
+ void finishRun(runId, outcome, { outcomeMessage: reason });
4565
+ }
4566
+ }
4567
+
4568
+ // src/lib/manager/scheduler/kanban-route.ts
4569
+ import { createHash as createHash6 } from "crypto";
4415
4570
 
4416
4571
  // src/lib/delivery-schedule-link.ts
4417
4572
  function envSuffixFor2(codeName) {
@@ -4637,231 +4792,38 @@ async function deliverScheduledTaskOutput(agentCodeName, agentId, rawTarget, bod
4637
4792
  }
4638
4793
  }
4639
4794
 
4640
- // src/lib/manager/scheduler.ts
4641
- function buildSchedulerTaskInput(t) {
4642
- return {
4643
- id: t.id,
4644
- template_id: t.template_id,
4645
- name: t.name,
4646
- schedule_kind: t.schedule_kind,
4647
- schedule_expr: t.schedule_expr ?? null,
4648
- schedule_every: t.schedule_every ?? null,
4649
- schedule_at: t.schedule_at ?? null,
4650
- timezone: t.timezone ?? "UTC",
4651
- prompt: t.prompt ?? "",
4652
- session_target: t.session_target ?? "isolated",
4653
- delivery_mode: t.delivery_mode ?? "none",
4654
- delivery_policy: t.delivery_policy ?? "always",
4655
- delivery_channel: t.delivery_channel ?? null,
4656
- delivery_to: t.delivery_to ?? null,
4657
- enabled: t.enabled ?? true,
4658
- triggered_at: t.triggered_at ?? null
4659
- };
4660
- }
4661
- var inFlightClaudeTasks = /* @__PURE__ */ new Set();
4662
- var claudeTaskConcurrency = /* @__PURE__ */ new Map();
4663
- var MAX_CLAUDE_CONCURRENCY = 2;
4664
- function claudePidFilePath() {
4665
- return join13(homedir6(), ".augmented", "manager-claude-pids.json");
4666
- }
4667
- var inFlightClaudePids = /* @__PURE__ */ new Map();
4668
- function registerClaudeSpawn(record) {
4669
- inFlightClaudePids.set(record.pid, record);
4670
- try {
4671
- addSpawn(claudePidFilePath(), record);
4672
- } catch (err) {
4673
- log(`[drain] pid-file write failed: ${err.message}`);
4795
+ // src/lib/manager/scheduler/kanban-route.ts
4796
+ async function deliverScheduledCardResult(codeName, agentId, cardId) {
4797
+ if (!claimScheduledCardDelivery(cardId)) {
4798
+ return completedScheduledCards.has(cardId) ? "terminal" : "in_flight";
4674
4799
  }
4675
- }
4676
- function unregisterClaudeSpawn(pid) {
4677
- inFlightClaudePids.delete(pid);
4800
+ let card;
4678
4801
  try {
4679
- removeSpawn(claudePidFilePath(), pid);
4680
- } catch {
4802
+ const resp = await api.post("/host/kanban-item", {
4803
+ agent_id: agentId,
4804
+ item_id: cardId
4805
+ });
4806
+ card = resp.item;
4807
+ } catch (err) {
4808
+ if (err instanceof ApiError && err.status >= 400 && err.status < 500) {
4809
+ log(`[scheduled-kanban] delivery: card ${cardId} on '${codeName}' fetch returned ${err.status} (${err.message}) \u2014 treating as terminal, not retrying`);
4810
+ markScheduledCardDeliveryComplete(cardId);
4811
+ return "terminal";
4812
+ }
4813
+ releaseScheduledCardDelivery(cardId);
4814
+ log(`[scheduled-kanban] delivery fetch failed for card ${cardId} on '${codeName}': ${err.message} \u2014 will retry`);
4815
+ return "retry";
4681
4816
  }
4682
- }
4683
- var claudeSchedulerStates = /* @__PURE__ */ new Map();
4684
- async function syncAndCheckClaudeScheduler(agent, tasks, boardItems, refreshData) {
4685
- const codeName = agent.code_name;
4686
- const stableTasksHash = createHash5("sha256").update(JSON.stringify(tasks)).digest("hex").slice(0, 16);
4687
- const boardHash = boardItems.length > 0 ? createHash5("sha256").update(JSON.stringify(boardItems.map((b) => ({ id: b.id, title: b.title, status: b.status, priority: b.priority, deliverable: b.deliverable })))).digest("hex").slice(0, 16) : "empty";
4688
- const resolvedModels = resolveModelChain(refreshData);
4689
- const modelsHash = createHash5("sha256").update(JSON.stringify(resolvedModels)).digest("hex").slice(0, 16);
4690
- const combinedHash = `${stableTasksHash}:${boardHash}:${modelsHash}`;
4691
- const prevHash = agentState.knownTasksHashes.get(agent.agent_id);
4692
- if (combinedHash !== prevHash) {
4693
- const taskInputs = tasks.map((t) => buildSchedulerTaskInput(t));
4694
- const state8 = syncTasksToScheduler(codeName, agent.agent_id, taskInputs);
4695
- claudeSchedulerStates.set(codeName, state8);
4696
- agentState.knownTasksHashes.set(agent.agent_id, combinedHash);
4697
- log(`[claude-scheduler] Tasks synced for '${codeName}' (${taskInputs.length} task(s))`);
4817
+ if (!card || card.status !== "done" || card.source_type !== "scheduled_task" || !card.source_ref) {
4818
+ markScheduledCardDeliveryComplete(cardId);
4819
+ return "terminal";
4698
4820
  }
4699
- if (!claudeSchedulerStates.has(codeName)) {
4700
- claudeSchedulerStates.set(codeName, loadSchedulerState(codeName));
4701
- }
4702
- const state7 = claudeSchedulerStates.get(codeName);
4703
- const ready = getReadyTasks(state7, inFlightClaudeTasks);
4704
- if (ready.length === 0) return;
4705
- for (const task of ready) {
4706
- if ((claudeTaskConcurrency.get(codeName) ?? 0) >= MAX_CLAUDE_CONCURRENCY) break;
4707
- if (KANBAN_WORK_TEMPLATES.has(task.templateId)) {
4708
- const updated = markTaskFired(codeName, task.taskId, "ok");
4709
- claudeSchedulerStates.set(codeName, updated);
4710
- continue;
4711
- }
4712
- let prompt = task.prompt;
4713
- if (BOARD_INJECT_TEMPLATES.has(task.templateId) && boardItems.length > 0) {
4714
- const template = PLAN_TEMPLATES.has(task.templateId) ? "morning-plan" : "follow-up";
4715
- const boardPrefix = formatBoardForPrompt(boardItems, template);
4716
- prompt = boardPrefix + prompt;
4717
- }
4718
- inFlightClaudeTasks.add(task.taskId);
4719
- claudeTaskConcurrency.set(codeName, (claudeTaskConcurrency.get(codeName) ?? 0) + 1);
4720
- if (isScheduledViaKanbanEnabled() && isPlainScheduledTemplate(task.templateId)) {
4721
- await fireScheduledTaskViaKanban(codeName, agent.agent_id, task, prompt);
4722
- inFlightClaudeTasks.delete(task.taskId);
4723
- claudeTaskConcurrency.set(codeName, Math.max(0, (claudeTaskConcurrency.get(codeName) ?? 1) - 1));
4724
- continue;
4725
- }
4726
- log(`[claude-scheduler] Firing '${task.name}' for '${codeName}'`);
4727
- executeAndProcessClaudeTask(codeName, agent.agent_id, task, prompt).finally(() => {
4728
- inFlightClaudeTasks.delete(task.taskId);
4729
- claudeTaskConcurrency.set(codeName, Math.max(0, (claudeTaskConcurrency.get(codeName) ?? 1) - 1));
4730
- });
4731
- }
4732
- }
4733
- function deriveScheduledTaskNotify(task) {
4734
- if (task.deliveryChannel !== "msteams") return {};
4735
- const to = task.deliveryTo;
4736
- let conversationId = null;
4737
- if (typeof to === "string" && to.trim().length > 0) {
4738
- conversationId = to.trim();
4739
- } else if (to && typeof to === "object") {
4740
- const cid = to.conversation_id;
4741
- if (typeof cid === "string" && cid.trim().length > 0) conversationId = cid.trim();
4742
- }
4743
- if (!conversationId) return {};
4744
- return { notify_channel: "msteams", notify_to: conversationId };
4745
- }
4746
- async function startRun(opts) {
4747
- try {
4748
- const res = await api.post(
4749
- "/host/runs/start",
4750
- opts
4751
- );
4752
- return { run_id: res.run_id ?? null, kanban_item_id: res.kanban_item_id ?? null };
4753
- } catch (err) {
4754
- const errText = err instanceof Error ? err.message : String(err);
4755
- const errId = createHash5("sha256").update(errText).digest("hex").slice(0, 12);
4756
- log(`[runs] start failed for agent_id=${opts.agent_id} source_type=${opts.source_type} error_id=${errId}`);
4757
- return { run_id: null, kanban_item_id: null };
4758
- }
4759
- }
4760
- async function finishRun(runId, outcome, options = {}) {
4761
- try {
4762
- await api.post("/host/runs/finish", {
4763
- run_id: runId,
4764
- outcome,
4765
- outcome_message: options.outcomeMessage,
4766
- metadata: options.metadata,
4767
- complete_kanban_item_id: options.completeKanbanItemId ?? void 0,
4768
- result: options.result
4769
- });
4770
- } catch (err) {
4771
- const errText = err instanceof Error ? err.message : String(err);
4772
- const errId = createHash5("sha256").update(errText).digest("hex").slice(0, 12);
4773
- log(`[runs] finish failed for run_id=${runId} outcome=${outcome} error_id=${errId}`);
4774
- }
4775
- }
4776
- var MAX_PRIOR_RUNS = 5;
4777
- async function fetchPriorScheduledRuns(agentId, taskId) {
4778
- try {
4779
- const data = await api.post("/host/scheduled-tasks/recent-outputs", {
4780
- agent_id: agentId,
4781
- task_id: taskId,
4782
- since_hours: 24,
4783
- limit: MAX_PRIOR_RUNS
4784
- });
4785
- const rows = Array.isArray(data?.runs) ? data.runs.slice(0, MAX_PRIOR_RUNS) : [];
4786
- return rows.filter((r) => typeof r.output_text === "string" && r.output_text.length > 0).map((r) => ({ startedAt: r.started_at, output: r.output_text }));
4787
- } catch (err) {
4788
- const errText = err instanceof Error ? err.message : String(err);
4789
- const errId = createHash5("sha256").update(errText).digest("hex").slice(0, 12);
4790
- log(`[runs] prior-runs lookup failed for task_id=${taskId} error_id=${errId}`);
4791
- return [];
4792
- }
4793
- }
4794
- function isScheduledViaKanbanEnabled() {
4795
- const v = process.env["AGT_SCHEDULED_VIA_KANBAN"];
4796
- return !(v === "0" || v?.toLowerCase() === "false");
4797
- }
4798
- var scheduledRunsByCode = /* @__PURE__ */ new Map();
4799
- var claimedScheduledCards = /* @__PURE__ */ new Set();
4800
- var completedScheduledCards = /* @__PURE__ */ new Set();
4801
- function claimScheduledCardDelivery(cardId) {
4802
- if (claimedScheduledCards.has(cardId)) return false;
4803
- claimedScheduledCards.add(cardId);
4804
- return true;
4805
- }
4806
- function releaseScheduledCardDelivery(cardId) {
4807
- claimedScheduledCards.delete(cardId);
4808
- }
4809
- function markScheduledCardDeliveryComplete(cardId) {
4810
- completedScheduledCards.add(cardId);
4811
- }
4812
- function trackScheduledRun(codeName, cardId, runId) {
4813
- let m = scheduledRunsByCode.get(codeName);
4814
- if (!m) {
4815
- m = /* @__PURE__ */ new Map();
4816
- scheduledRunsByCode.set(codeName, m);
4817
- }
4818
- m.set(cardId, runId);
4819
- }
4820
- function isScheduledCardTracked(cardId) {
4821
- for (const m of scheduledRunsByCode.values()) {
4822
- if (m.has(cardId)) return true;
4823
- }
4824
- return false;
4825
- }
4826
- function closeScheduledRunsForCode(codeName, outcome, reason) {
4827
- const m = scheduledRunsByCode.get(codeName);
4828
- if (!m || m.size === 0) return;
4829
- scheduledRunsByCode.delete(codeName);
4830
- for (const runId of m.values()) {
4831
- void finishRun(runId, outcome, { outcomeMessage: reason });
4832
- }
4833
- }
4834
- async function deliverScheduledCardResult(codeName, agentId, cardId) {
4835
- if (!claimScheduledCardDelivery(cardId)) {
4836
- return completedScheduledCards.has(cardId) ? "terminal" : "in_flight";
4837
- }
4838
- let card;
4839
- try {
4840
- const resp = await api.post("/host/kanban-item", {
4841
- agent_id: agentId,
4842
- item_id: cardId
4843
- });
4844
- card = resp.item;
4845
- } catch (err) {
4846
- if (err instanceof ApiError && err.status >= 400 && err.status < 500) {
4847
- log(`[scheduled-kanban] delivery: card ${cardId} on '${codeName}' fetch returned ${err.status} (${err.message}) \u2014 treating as terminal, not retrying`);
4848
- markScheduledCardDeliveryComplete(cardId);
4849
- return "terminal";
4850
- }
4851
- releaseScheduledCardDelivery(cardId);
4852
- log(`[scheduled-kanban] delivery fetch failed for card ${cardId} on '${codeName}': ${err.message} \u2014 will retry`);
4853
- return "retry";
4854
- }
4855
- if (!card || card.status !== "done" || card.source_type !== "scheduled_task" || !card.source_ref) {
4856
- markScheduledCardDeliveryComplete(cardId);
4857
- return "terminal";
4858
- }
4859
- const state7 = claudeSchedulerStates.get(codeName) ?? loadSchedulerState(codeName);
4860
- const task = state7.tasks[card.source_ref];
4861
- if (!task) {
4862
- log(`[scheduled-kanban] delivery: no scheduler task for source_ref=${card.source_ref} on '${codeName}' \u2014 skipping`);
4863
- markScheduledCardDeliveryComplete(cardId);
4864
- return "terminal";
4821
+ const state7 = claudeSchedulerStates.get(codeName) ?? loadSchedulerState(codeName);
4822
+ const task = state7.tasks[card.source_ref];
4823
+ if (!task) {
4824
+ log(`[scheduled-kanban] delivery: no scheduler task for source_ref=${card.source_ref} on '${codeName}' \u2014 skipping`);
4825
+ markScheduledCardDeliveryComplete(cardId);
4826
+ return "terminal";
4865
4827
  }
4866
4828
  if (!isPlainScheduledTemplate(task.templateId)) {
4867
4829
  log(`[scheduled-kanban] delivery: card ${cardId} template '${task.templateId}' on '${codeName}' is not a plain scheduled template \u2014 skipping manager delivery`);
@@ -4996,9 +4958,152 @@ async function fireScheduledTaskViaKanban(codeName, agentId, task, prompt) {
4996
4958
  }
4997
4959
  return routed;
4998
4960
  }
4961
+ async function processClaudeTaskResult(codeName, agentId, templateId, rawOutput, delivery) {
4962
+ try {
4963
+ const classification = classifyOutput(rawOutput);
4964
+ if (classification.action === "suppress") {
4965
+ const trimmed = (rawOutput ?? "").trim();
4966
+ const outputHash = trimmed.length === 0 ? "empty" : createHash6("sha256").update(trimmed).digest("hex").slice(0, 12);
4967
+ log(`[claude-scheduler] Suppressing delivery for '${codeName}' (template=${templateId}, task=${delivery?.taskId ?? "n/a"}) \u2014 output_len=${trimmed.length} output_hash=${outputHash}`);
4968
+ if (classification.suppressedNotes) {
4969
+ const notesHash = createHash6("sha256").update(classification.suppressedNotes).digest("hex").slice(0, 12);
4970
+ log(`[claude-scheduler] Suppressed notes for '${codeName}' (task=${delivery?.taskId ?? "n/a"}) \u2014 notes_len=${classification.suppressedNotes.length} notes_hash=${notesHash}`);
4971
+ }
4972
+ if (delivery?.mode === "announce" && delivery.to) {
4973
+ await reportDeliveryStatus(agentId, delivery.taskId, {
4974
+ status: "skipped",
4975
+ error_code: "NO_CONTENT"
4976
+ });
4977
+ }
4978
+ return;
4979
+ }
4980
+ const output = classification.deliverable;
4981
+ if (classification.action === "strip") {
4982
+ log(`[claude-scheduler] Stripped '<no-delivery/>' sentinel from '${codeName}' output (template=${templateId}, task=${delivery?.taskId ?? "n/a"}) \u2014 agent mixed it with real content; delivering the rest.`);
4983
+ }
4984
+ if (STANDUP_TEMPLATES.has(templateId)) {
4985
+ const standup = parseStandupSummary(output);
4986
+ await api.post("/host/agent-status", {
4987
+ agent_code_name: codeName,
4988
+ standup,
4989
+ current_status: "idle"
4990
+ });
4991
+ log(`[claude-scheduler] Standup posted for '${codeName}'`);
4992
+ } else if (TASK_UPDATE_TEMPLATES.has(templateId)) {
4993
+ await api.post("/host/agent-status", {
4994
+ agent_code_name: codeName,
4995
+ current_tasks: output.slice(0, 2e3)
4996
+ });
4997
+ log(`[claude-scheduler] Task update posted for '${codeName}'`);
4998
+ } else if (PLAN_TEMPLATES.has(templateId)) {
4999
+ const planItems = parsePlanItems(output);
5000
+ if (planItems.length > 0) {
5001
+ await api.post("/host/kanban", {
5002
+ agent_id: agentId,
5003
+ add: planItems
5004
+ });
5005
+ log(`[claude-scheduler] Plan items posted for '${codeName}' (${planItems.length} items)`);
5006
+ }
5007
+ } else if (KANBAN_WORK_TEMPLATES.has(templateId)) {
5008
+ const kanbanUpdates = parseKanbanUpdates(output);
5009
+ if (kanbanUpdates.length > 0) {
5010
+ await api.post("/host/kanban", {
5011
+ agent_id: agentId,
5012
+ update: kanbanUpdates
5013
+ });
5014
+ log(`[claude-scheduler] Kanban updates posted for '${codeName}' (${kanbanUpdates.length} updates)`);
5015
+ }
5016
+ }
5017
+ if (delivery?.mode === "announce" && delivery.to) {
5018
+ await deliverScheduledTaskOutput(
5019
+ codeName,
5020
+ agentId,
5021
+ delivery.to,
5022
+ output.slice(0, 4e3),
5023
+ delivery.taskId
5024
+ );
5025
+ }
5026
+ } catch (err) {
5027
+ log(`[claude-scheduler] Failed to post result for '${codeName}': ${err.message}`);
5028
+ }
5029
+ }
5030
+
5031
+ // src/lib/manager/scheduler/execution.ts
5032
+ import { createHash as createHash7 } from "crypto";
5033
+ import { readFileSync as readFileSync12, existsSync as existsSync7 } from "fs";
5034
+ import { homedir as homedir7 } from "os";
5035
+ import { join as join14 } from "path";
5036
+ function claudePidFilePath() {
5037
+ return join14(homedir7(), ".augmented", "manager-claude-pids.json");
5038
+ }
5039
+ var inFlightClaudePids = /* @__PURE__ */ new Map();
5040
+ function registerClaudeSpawn(record) {
5041
+ inFlightClaudePids.set(record.pid, record);
5042
+ try {
5043
+ addSpawn(claudePidFilePath(), record);
5044
+ } catch (err) {
5045
+ log(`[drain] pid-file write failed: ${err.message}`);
5046
+ }
5047
+ }
5048
+ function unregisterClaudeSpawn(pid) {
5049
+ inFlightClaudePids.delete(pid);
5050
+ try {
5051
+ removeSpawn(claudePidFilePath(), pid);
5052
+ } catch {
5053
+ }
5054
+ }
5055
+ async function syncAndCheckClaudeScheduler(agent, tasks, boardItems, refreshData) {
5056
+ const codeName = agent.code_name;
5057
+ const stableTasksHash = createHash7("sha256").update(JSON.stringify(tasks)).digest("hex").slice(0, 16);
5058
+ const boardHash = boardItems.length > 0 ? createHash7("sha256").update(JSON.stringify(boardItems.map((b) => ({ id: b.id, title: b.title, status: b.status, priority: b.priority, deliverable: b.deliverable })))).digest("hex").slice(0, 16) : "empty";
5059
+ const resolvedModels = resolveModelChain(refreshData);
5060
+ const modelsHash = createHash7("sha256").update(JSON.stringify(resolvedModels)).digest("hex").slice(0, 16);
5061
+ const combinedHash = `${stableTasksHash}:${boardHash}:${modelsHash}`;
5062
+ const prevHash = agentState.knownTasksHashes.get(agent.agent_id);
5063
+ if (combinedHash !== prevHash) {
5064
+ const taskInputs = tasks.map((t) => buildSchedulerTaskInput(t));
5065
+ const state8 = syncTasksToScheduler(codeName, agent.agent_id, taskInputs);
5066
+ claudeSchedulerStates.set(codeName, state8);
5067
+ agentState.knownTasksHashes.set(agent.agent_id, combinedHash);
5068
+ log(`[claude-scheduler] Tasks synced for '${codeName}' (${taskInputs.length} task(s))`);
5069
+ }
5070
+ if (!claudeSchedulerStates.has(codeName)) {
5071
+ claudeSchedulerStates.set(codeName, loadSchedulerState(codeName));
5072
+ }
5073
+ const state7 = claudeSchedulerStates.get(codeName);
5074
+ const ready = getReadyTasks(state7, inFlightClaudeTasks);
5075
+ if (ready.length === 0) return;
5076
+ for (const task of ready) {
5077
+ if ((claudeTaskConcurrency.get(codeName) ?? 0) >= MAX_CLAUDE_CONCURRENCY) break;
5078
+ if (KANBAN_WORK_TEMPLATES.has(task.templateId)) {
5079
+ const updated = markTaskFired(codeName, task.taskId, "ok");
5080
+ claudeSchedulerStates.set(codeName, updated);
5081
+ continue;
5082
+ }
5083
+ let prompt = task.prompt;
5084
+ if (BOARD_INJECT_TEMPLATES.has(task.templateId) && boardItems.length > 0) {
5085
+ const template = PLAN_TEMPLATES.has(task.templateId) ? "morning-plan" : "follow-up";
5086
+ const boardPrefix = formatBoardForPrompt(boardItems, template);
5087
+ prompt = boardPrefix + prompt;
5088
+ }
5089
+ inFlightClaudeTasks.add(task.taskId);
5090
+ claudeTaskConcurrency.set(codeName, (claudeTaskConcurrency.get(codeName) ?? 0) + 1);
5091
+ if (isScheduledViaKanbanEnabled() && isPlainScheduledTemplate(task.templateId)) {
5092
+ await fireScheduledTaskViaKanban(codeName, agent.agent_id, task, prompt);
5093
+ inFlightClaudeTasks.delete(task.taskId);
5094
+ claudeTaskConcurrency.set(codeName, Math.max(0, (claudeTaskConcurrency.get(codeName) ?? 1) - 1));
5095
+ continue;
5096
+ }
5097
+ log(`[claude-scheduler] Firing '${task.name}' for '${codeName}'`);
5098
+ executeAndProcessClaudeTask(codeName, agent.agent_id, task, prompt).finally(() => {
5099
+ inFlightClaudeTasks.delete(task.taskId);
5100
+ claudeTaskConcurrency.set(codeName, Math.max(0, (claudeTaskConcurrency.get(codeName) ?? 1) - 1));
5101
+ });
5102
+ }
5103
+ }
4999
5104
  async function executeAndProcessClaudeTask(codeName, agentId, task, prompt) {
5000
5105
  const projectDir = getProjectDir2(codeName);
5001
- const mcpConfigPath = join13(projectDir, ".mcp.json");
5106
+ const mcpConfigPath = join14(projectDir, ".mcp.json");
5002
5107
  let runId = null;
5003
5108
  let kanbanItemId = null;
5004
5109
  let taskResult;
@@ -5006,11 +5111,11 @@ async function executeAndProcessClaudeTask(codeName, agentId, task, prompt) {
5006
5111
  const priorRuns = await fetchPriorScheduledRuns(agentId, task.taskId);
5007
5112
  prompt = wrapScheduledTaskPrompt(prompt, { priorRuns });
5008
5113
  try {
5009
- const claudeMdPath = join13(projectDir, "CLAUDE.md");
5114
+ const claudeMdPath = join14(projectDir, "CLAUDE.md");
5010
5115
  const serverNames = [];
5011
5116
  if (existsSync7(mcpConfigPath)) {
5012
5117
  try {
5013
- const d = JSON.parse(readFileSync11(mcpConfigPath, "utf-8"));
5118
+ const d = JSON.parse(readFileSync12(mcpConfigPath, "utf-8"));
5014
5119
  if (d.mcpServers) serverNames.push(...Object.keys(d.mcpServers));
5015
5120
  } catch {
5016
5121
  }
@@ -5033,10 +5138,10 @@ async function executeAndProcessClaudeTask(codeName, agentId, task, prompt) {
5033
5138
  claudeArgs.push("--system-prompt-file", claudeMdPath);
5034
5139
  }
5035
5140
  const childEnv = { ...process.env };
5036
- const envIntPath = join13(projectDir, ".env.integrations");
5141
+ const envIntPath = join14(projectDir, ".env.integrations");
5037
5142
  if (existsSync7(envIntPath)) {
5038
5143
  try {
5039
- Object.assign(childEnv, parseEnvIntegrations(readFileSync11(envIntPath, "utf-8")));
5144
+ Object.assign(childEnv, parseEnvIntegrations(readFileSync12(envIntPath, "utf-8")));
5040
5145
  } catch {
5041
5146
  }
5042
5147
  }
@@ -5133,75 +5238,6 @@ async function executeAndProcessClaudeTask(codeName, agentId, task, prompt) {
5133
5238
  claudeSchedulerStates.set(codeName, updated);
5134
5239
  }
5135
5240
  }
5136
- async function processClaudeTaskResult(codeName, agentId, templateId, rawOutput, delivery) {
5137
- try {
5138
- const classification = classifyOutput(rawOutput);
5139
- if (classification.action === "suppress") {
5140
- const trimmed = (rawOutput ?? "").trim();
5141
- const outputHash = trimmed.length === 0 ? "empty" : createHash5("sha256").update(trimmed).digest("hex").slice(0, 12);
5142
- log(`[claude-scheduler] Suppressing delivery for '${codeName}' (template=${templateId}, task=${delivery?.taskId ?? "n/a"}) \u2014 output_len=${trimmed.length} output_hash=${outputHash}`);
5143
- if (classification.suppressedNotes) {
5144
- const notesHash = createHash5("sha256").update(classification.suppressedNotes).digest("hex").slice(0, 12);
5145
- log(`[claude-scheduler] Suppressed notes for '${codeName}' (task=${delivery?.taskId ?? "n/a"}) \u2014 notes_len=${classification.suppressedNotes.length} notes_hash=${notesHash}`);
5146
- }
5147
- if (delivery?.mode === "announce" && delivery.to) {
5148
- await reportDeliveryStatus(agentId, delivery.taskId, {
5149
- status: "skipped",
5150
- error_code: "NO_CONTENT"
5151
- });
5152
- }
5153
- return;
5154
- }
5155
- const output = classification.deliverable;
5156
- if (classification.action === "strip") {
5157
- log(`[claude-scheduler] Stripped '<no-delivery/>' sentinel from '${codeName}' output (template=${templateId}, task=${delivery?.taskId ?? "n/a"}) \u2014 agent mixed it with real content; delivering the rest.`);
5158
- }
5159
- if (STANDUP_TEMPLATES.has(templateId)) {
5160
- const standup = parseStandupSummary(output);
5161
- await api.post("/host/agent-status", {
5162
- agent_code_name: codeName,
5163
- standup,
5164
- current_status: "idle"
5165
- });
5166
- log(`[claude-scheduler] Standup posted for '${codeName}'`);
5167
- } else if (TASK_UPDATE_TEMPLATES.has(templateId)) {
5168
- await api.post("/host/agent-status", {
5169
- agent_code_name: codeName,
5170
- current_tasks: output.slice(0, 2e3)
5171
- });
5172
- log(`[claude-scheduler] Task update posted for '${codeName}'`);
5173
- } else if (PLAN_TEMPLATES.has(templateId)) {
5174
- const planItems = parsePlanItems(output);
5175
- if (planItems.length > 0) {
5176
- await api.post("/host/kanban", {
5177
- agent_id: agentId,
5178
- add: planItems
5179
- });
5180
- log(`[claude-scheduler] Plan items posted for '${codeName}' (${planItems.length} items)`);
5181
- }
5182
- } else if (KANBAN_WORK_TEMPLATES.has(templateId)) {
5183
- const kanbanUpdates = parseKanbanUpdates(output);
5184
- if (kanbanUpdates.length > 0) {
5185
- await api.post("/host/kanban", {
5186
- agent_id: agentId,
5187
- update: kanbanUpdates
5188
- });
5189
- log(`[claude-scheduler] Kanban updates posted for '${codeName}' (${kanbanUpdates.length} updates)`);
5190
- }
5191
- }
5192
- if (delivery?.mode === "announce" && delivery.to) {
5193
- await deliverScheduledTaskOutput(
5194
- codeName,
5195
- agentId,
5196
- delivery.to,
5197
- output.slice(0, 4e3),
5198
- delivery.taskId
5199
- );
5200
- }
5201
- } catch (err) {
5202
- log(`[claude-scheduler] Failed to post result for '${codeName}': ${err.message}`);
5203
- }
5204
- }
5205
5241
 
5206
5242
  // src/lib/wedge-detection.ts
5207
5243
  var DEFAULTS = {
@@ -5342,15 +5378,15 @@ function partitionActionableByPoison(actionable, states, config2) {
5342
5378
  }
5343
5379
 
5344
5380
  // src/lib/restart-flags.ts
5345
- import { existsSync as existsSync8, mkdirSync as mkdirSync3, readdirSync as readdirSync4, readFileSync as readFileSync12, renameSync, rmSync as rmSync2, writeFileSync as writeFileSync3 } from "fs";
5346
- import { homedir as homedir7 } from "os";
5347
- import { join as join14 } from "path";
5381
+ import { existsSync as existsSync8, mkdirSync as mkdirSync4, readdirSync as readdirSync4, readFileSync as readFileSync13, renameSync, rmSync as rmSync2, writeFileSync as writeFileSync4 } from "fs";
5382
+ import { homedir as homedir8 } from "os";
5383
+ import { join as join15 } from "path";
5348
5384
  import { randomUUID } from "crypto";
5349
5385
  function restartFlagsDir() {
5350
- return join14(homedir7(), ".augmented", "restart-flags");
5386
+ return join15(homedir8(), ".augmented", "restart-flags");
5351
5387
  }
5352
5388
  function flagPath(codeName) {
5353
- return join14(restartFlagsDir(), `${codeName}.flag`);
5389
+ return join15(restartFlagsDir(), `${codeName}.flag`);
5354
5390
  }
5355
5391
  function readRestartFlags() {
5356
5392
  const dir = restartFlagsDir();
@@ -5359,7 +5395,7 @@ function readRestartFlags() {
5359
5395
  for (const entry of readdirSync4(dir)) {
5360
5396
  if (!entry.endsWith(".flag")) continue;
5361
5397
  try {
5362
- const raw = readFileSync12(join14(dir, entry), "utf8");
5398
+ const raw = readFileSync13(join15(dir, entry), "utf8");
5363
5399
  const parsed = JSON.parse(raw);
5364
5400
  if (typeof parsed.codeName !== "string" || parsed.codeName.length === 0) {
5365
5401
  parsed.codeName = entry.replace(/\.flag$/, "");
@@ -5912,8 +5948,8 @@ function applyRestartAcks(args) {
5912
5948
  var GATEWAY_PORT_BASE = 18800;
5913
5949
  var GATEWAY_PORT_STEP = 10;
5914
5950
  var GATEWAY_PORT_MAX = 18899;
5915
- var AUGMENTED_DIR = join15(process.env["HOME"] ?? "/tmp", ".augmented");
5916
- var GATEWAY_PORTS_FILE = join15(AUGMENTED_DIR, "gateway-ports.json");
5951
+ var AUGMENTED_DIR = join16(process.env["HOME"] ?? "/tmp", ".augmented");
5952
+ var GATEWAY_PORTS_FILE = join16(AUGMENTED_DIR, "gateway-ports.json");
5917
5953
  var CHANNEL_SWEEP_INTERVAL_MS = (() => {
5918
5954
  const raw = parseInt(process.env["AGT_CHANNEL_SWEEP_INTERVAL_MS"] ?? "", 10);
5919
5955
  if (!Number.isFinite(raw)) return 5 * 60 * 1e3;
@@ -6411,15 +6447,15 @@ var runningMcpServerKeys = /* @__PURE__ */ new Map();
6411
6447
  var runningChannelSecretHashes = /* @__PURE__ */ new Map();
6412
6448
  function projectMcpHash(_codeName, projectDir) {
6413
6449
  try {
6414
- const raw = readFileSync13(join15(projectDir, ".mcp.json"), "utf-8");
6415
- return createHash6("sha256").update(canonicalJson(JSON.parse(raw))).digest("hex");
6450
+ const raw = readFileSync14(join16(projectDir, ".mcp.json"), "utf-8");
6451
+ return createHash8("sha256").update(canonicalJson(JSON.parse(raw))).digest("hex");
6416
6452
  } catch {
6417
6453
  return null;
6418
6454
  }
6419
6455
  }
6420
6456
  function projectMcpKeys(_codeName, projectDir) {
6421
6457
  try {
6422
- const raw = readFileSync13(join15(projectDir, ".mcp.json"), "utf-8");
6458
+ const raw = readFileSync14(join16(projectDir, ".mcp.json"), "utf-8");
6423
6459
  const parsed = JSON.parse(raw);
6424
6460
  const servers = parsed.mcpServers;
6425
6461
  if (!servers || typeof servers !== "object") return /* @__PURE__ */ new Set();
@@ -6430,7 +6466,7 @@ function projectMcpKeys(_codeName, projectDir) {
6430
6466
  }
6431
6467
  function readMcpHttpServerConfig(projectDir, serverKey, env) {
6432
6468
  try {
6433
- const raw = readFileSync13(join15(projectDir, ".mcp.json"), "utf-8");
6469
+ const raw = readFileSync14(join16(projectDir, ".mcp.json"), "utf-8");
6434
6470
  const servers = JSON.parse(raw).mcpServers ?? {};
6435
6471
  const entry = servers[serverKey];
6436
6472
  if (entry && typeof entry.url === "string" && (entry.type === "http" || entry.type === void 0)) {
@@ -6468,9 +6504,9 @@ async function runAgentConnectivityProbes(agent, integrations, projectDir) {
6468
6504
  if (integrations.length === 0) return;
6469
6505
  const probeEnv = { ...process.env };
6470
6506
  try {
6471
- const envIntPath = join15(projectDir, ".env.integrations");
6507
+ const envIntPath = join16(projectDir, ".env.integrations");
6472
6508
  if (existsSync9(envIntPath)) {
6473
- Object.assign(probeEnv, parseEnvIntegrations(readFileSync13(envIntPath, "utf-8")));
6509
+ Object.assign(probeEnv, parseEnvIntegrations(readFileSync14(envIntPath, "utf-8")));
6474
6510
  }
6475
6511
  } catch {
6476
6512
  }
@@ -6683,7 +6719,7 @@ function checkMcpConfigDriftAndScheduleRestart(codeName, projectDir) {
6683
6719
  function projectChannelSecretHash(projectDir) {
6684
6720
  try {
6685
6721
  const entries = parseEnvIntegrations(
6686
- readFileSync13(join15(projectDir, ".env.integrations"), "utf-8")
6722
+ readFileSync14(join16(projectDir, ".env.integrations"), "utf-8")
6687
6723
  );
6688
6724
  return channelSecretValueHash(entries, CHANNEL_SECRET_ENV_KEYS);
6689
6725
  } catch {
@@ -6771,7 +6807,7 @@ var cachedMaintenanceWindow = null;
6771
6807
  var lastVersionCheckAt = 0;
6772
6808
  var VERSION_CHECK_INTERVAL_MS = 5 * 60 * 1e3;
6773
6809
  var lastResponsivenessProbeAt = 0;
6774
- var agtCliVersion = true ? "0.28.36" : "dev";
6810
+ var agtCliVersion = true ? "0.28.38" : "dev";
6775
6811
  function resolveBrewPath(execFileSync4) {
6776
6812
  try {
6777
6813
  const out = execFileSync4("which", ["brew"], { timeout: 5e3 }).toString().trim();
@@ -6866,7 +6902,7 @@ async function ensureToolkitCli(toolkitSlug) {
6866
6902
  toolkitCliEnsured.add(toolkitSlug);
6867
6903
  return;
6868
6904
  }
6869
- brewBinDir = dirname3(brewPath);
6905
+ brewBinDir = dirname4(brewPath);
6870
6906
  const isRoot = typeof process.getuid === "function" && process.getuid() === 0;
6871
6907
  log(`[toolkit-install] ${toolkitSlug}: installing via brew (${pkg})\u2026`);
6872
6908
  if (isRoot) {
@@ -6948,7 +6984,7 @@ function ensureClaudeManagedSettings(path = claudeManagedSettingsPath()) {
6948
6984
  try {
6949
6985
  let settings = {};
6950
6986
  if (existsSync9(path)) {
6951
- const raw = readFileSync13(path, "utf-8").trim();
6987
+ const raw = readFileSync14(path, "utf-8").trim();
6952
6988
  if (raw) {
6953
6989
  let parsed;
6954
6990
  try {
@@ -6964,8 +7000,8 @@ function ensureClaudeManagedSettings(path = claudeManagedSettingsPath()) {
6964
7000
  }
6965
7001
  if (settings.channelsEnabled === true) return "ok";
6966
7002
  settings.channelsEnabled = true;
6967
- mkdirSync4(dirname3(path), { recursive: true });
6968
- writeFileSync4(path, `${JSON.stringify(settings, null, 2)}
7003
+ mkdirSync5(dirname4(path), { recursive: true });
7004
+ writeFileSync5(path, `${JSON.stringify(settings, null, 2)}
6969
7005
  `);
6970
7006
  log(`[managed-settings] set channelsEnabled:true in ${path} (ENG-5786 \u2014 unblocks Claude Code channels)`);
6971
7007
  return "ok";
@@ -7006,7 +7042,7 @@ async function ensureFrameworkBinary(frameworkId) {
7006
7042
  log(`Claude Code install failed: ${err.message}`);
7007
7043
  return;
7008
7044
  }
7009
- const brewBinDir = dirname3(brewPath);
7045
+ const brewBinDir = dirname4(brewPath);
7010
7046
  if (!process.env.PATH?.split(":").includes(brewBinDir)) {
7011
7047
  process.env.PATH = `${brewBinDir}:${process.env.PATH ?? ""}`;
7012
7048
  }
@@ -7019,26 +7055,7 @@ async function ensureFrameworkBinary(frameworkId) {
7019
7055
  }
7020
7056
  agentRuntimeAuthenticated = await checkClaudeAuth();
7021
7057
  }
7022
- var CLAUDE_CODE_UPGRADE_CHECK_INTERVAL_MS = 24 * 60 * 60 * 1e3;
7023
7058
  var claudeCodeUpgradeInFlight = false;
7024
- function claudeCodeUpgradeMarkerPath() {
7025
- return join15(homedir8(), ".augmented", ".last-claude-code-upgrade-check");
7026
- }
7027
- function stampClaudeCodeUpgradeMarker() {
7028
- try {
7029
- writeFileSync4(claudeCodeUpgradeMarkerPath(), String(Date.now()));
7030
- } catch {
7031
- }
7032
- }
7033
- function claudeCodeUpgradeThrottled() {
7034
- try {
7035
- const lastCheck = parseInt(readFileSync13(claudeCodeUpgradeMarkerPath(), "utf-8").trim(), 10);
7036
- if (!Number.isFinite(lastCheck)) return false;
7037
- return Date.now() - lastCheck < CLAUDE_CODE_UPGRADE_CHECK_INTERVAL_MS;
7038
- } catch {
7039
- return false;
7040
- }
7041
- }
7042
7059
  async function maybeUpgradeClaudeCode() {
7043
7060
  if (claudeCodeUpgradeInFlight) return;
7044
7061
  if (claudeCodeUpgradeThrottled()) return;
@@ -7085,7 +7102,7 @@ ${r.stderr}`;
7085
7102
  }
7086
7103
  var UPDATE_CHECK_INTERVAL_MS = 5 * 60 * 1e3;
7087
7104
  function selfUpdateAppliedMarkerPath() {
7088
- return join15(homedir8(), ".augmented", ".last-self-update-applied");
7105
+ return join16(homedir9(), ".augmented", ".last-self-update-applied");
7089
7106
  }
7090
7107
  var selfUpdateUpToDateLogged = false;
7091
7108
  var restartAfterUpgrade = false;
@@ -7108,7 +7125,7 @@ async function checkAndUpdateCli() {
7108
7125
  const isNpmGlobal = !isBrewFormula && resolvedPath.includes("node_modules");
7109
7126
  if (!isBrewFormula && !isNpmGlobal) return;
7110
7127
  const { readFileSync: readF, writeFileSync: writeF } = await import("fs");
7111
- const markerPath = join15(homedir8(), ".augmented", ".last-update-check");
7128
+ const markerPath = join16(homedir9(), ".augmented", ".last-update-check");
7112
7129
  try {
7113
7130
  const lastCheck = parseInt(readF(markerPath, "utf-8").trim(), 10);
7114
7131
  if (Date.now() - lastCheck < UPDATE_CHECK_INTERVAL_MS) return;
@@ -7366,13 +7383,13 @@ async function checkClaudeAuth() {
7366
7383
  var evalEmptyMcpConfigPath = null;
7367
7384
  function ensureEvalEmptyMcpConfig() {
7368
7385
  if (evalEmptyMcpConfigPath && existsSync9(evalEmptyMcpConfigPath)) return evalEmptyMcpConfigPath;
7369
- const dir = join15(homedir8(), ".augmented");
7386
+ const dir = join16(homedir9(), ".augmented");
7370
7387
  try {
7371
- mkdirSync4(dir, { recursive: true });
7388
+ mkdirSync5(dir, { recursive: true });
7372
7389
  } catch {
7373
7390
  }
7374
- const p = join15(dir, ".eval-empty-mcp.json");
7375
- writeFileSync4(p, JSON.stringify({ mcpServers: {} }));
7391
+ const p = join16(dir, ".eval-empty-mcp.json");
7392
+ writeFileSync5(p, JSON.stringify({ mcpServers: {} }));
7376
7393
  evalEmptyMcpConfigPath = p;
7377
7394
  return p;
7378
7395
  }
@@ -7397,7 +7414,7 @@ async function runEvalClaude(prompt, model) {
7397
7414
  ""
7398
7415
  ];
7399
7416
  const { stdout } = await execFilePromiseLong(resolveClaudeBinary(), args, {
7400
- cwd: homedir8(),
7417
+ cwd: homedir9(),
7401
7418
  timeout: 12e4,
7402
7419
  stdin: "ignore",
7403
7420
  env: childEnv,
@@ -7446,14 +7463,14 @@ function resolveConversationEvalBackend() {
7446
7463
  }
7447
7464
  function loadGatewayPorts() {
7448
7465
  try {
7449
- return JSON.parse(readFileSync13(GATEWAY_PORTS_FILE, "utf-8"));
7466
+ return JSON.parse(readFileSync14(GATEWAY_PORTS_FILE, "utf-8"));
7450
7467
  } catch {
7451
7468
  return {};
7452
7469
  }
7453
7470
  }
7454
7471
  function saveGatewayPorts(ports) {
7455
- mkdirSync4(AUGMENTED_DIR, { recursive: true });
7456
- writeFileSync4(GATEWAY_PORTS_FILE, JSON.stringify(ports, null, 2));
7472
+ mkdirSync5(AUGMENTED_DIR, { recursive: true });
7473
+ writeFileSync5(GATEWAY_PORTS_FILE, JSON.stringify(ports, null, 2));
7457
7474
  }
7458
7475
  function allocatePort(codeName) {
7459
7476
  const ports = loadGatewayPorts();
@@ -7476,10 +7493,10 @@ function freePort(codeName) {
7476
7493
  }
7477
7494
  }
7478
7495
  function getStateFile() {
7479
- return join15(config?.configDir ?? join15(process.env["HOME"] ?? "/tmp", ".augmented"), "manager-state.json");
7496
+ return join16(config?.configDir ?? join16(process.env["HOME"] ?? "/tmp", ".augmented"), "manager-state.json");
7480
7497
  }
7481
7498
  function channelHashCacheDir() {
7482
- return config?.configDir ?? join15(process.env["HOME"] ?? "/tmp", ".augmented");
7499
+ return config?.configDir ?? join16(process.env["HOME"] ?? "/tmp", ".augmented");
7483
7500
  }
7484
7501
  function loadChannelHashCache2() {
7485
7502
  loadChannelHashCache(agentState.knownChannelConfigHashes, channelHashCacheDir());
@@ -7490,7 +7507,7 @@ function saveChannelHashCache2() {
7490
7507
  var _channelQuarantineStore = null;
7491
7508
  function channelQuarantineStore() {
7492
7509
  if (!_channelQuarantineStore) {
7493
- const dir = config?.configDir ?? join15(process.env["HOME"] ?? "/tmp", ".augmented");
7510
+ const dir = config?.configDir ?? join16(process.env["HOME"] ?? "/tmp", ".augmented");
7494
7511
  _channelQuarantineStore = new ChannelQuarantineStore(defaultQuarantinePath(dir));
7495
7512
  }
7496
7513
  return _channelQuarantineStore;
@@ -7498,7 +7515,7 @@ function channelQuarantineStore() {
7498
7515
  var _hostFlagStore = null;
7499
7516
  function hostFlagStore() {
7500
7517
  if (!_hostFlagStore) {
7501
- const dir = config?.configDir ?? join15(process.env["HOME"] ?? "/tmp", ".augmented");
7518
+ const dir = config?.configDir ?? join16(process.env["HOME"] ?? "/tmp", ".augmented");
7502
7519
  _hostFlagStore = new HostFlagStore({ cachePath: defaultFlagsCachePath(dir), log });
7503
7520
  }
7504
7521
  return _hostFlagStore;
@@ -7549,13 +7566,13 @@ function parseSkillFrontmatter(content) {
7549
7566
  return out;
7550
7567
  }
7551
7568
  async function refreshSkillsIndexInClaudeMd(configDir, codeName, log2) {
7552
- const { readdirSync: readdirSync6, readFileSync: rfs, existsSync: ex, writeFileSync: writeFileSync5 } = await import("fs");
7553
- const skillsDir = join15(configDir, codeName, "project", ".claude", "skills");
7554
- const claudeMdPath = join15(configDir, codeName, "project", "CLAUDE.md");
7569
+ const { readdirSync: readdirSync6, readFileSync: rfs, existsSync: ex, writeFileSync: writeFileSync6 } = await import("fs");
7570
+ const skillsDir = join16(configDir, codeName, "project", ".claude", "skills");
7571
+ const claudeMdPath = join16(configDir, codeName, "project", "CLAUDE.md");
7555
7572
  if (!ex(skillsDir) || !ex(claudeMdPath)) return;
7556
7573
  const entries = [];
7557
7574
  for (const dir of readdirSync6(skillsDir).sort()) {
7558
- const skillFile = join15(skillsDir, dir, "SKILL.md");
7575
+ const skillFile = join16(skillsDir, dir, "SKILL.md");
7559
7576
  if (!ex(skillFile)) continue;
7560
7577
  try {
7561
7578
  const { name, description } = parseSkillFrontmatter(rfs(skillFile, "utf-8"));
@@ -7597,16 +7614,16 @@ ${SKILLS_INDEX_END}`;
7597
7614
  next = current.trimEnd() + "\n\n" + section + "\n";
7598
7615
  }
7599
7616
  if (next !== current) {
7600
- writeFileSync5(claudeMdPath, next, "utf-8");
7617
+ writeFileSync6(claudeMdPath, next, "utf-8");
7601
7618
  log2(`Refreshed skills index in CLAUDE.md for '${codeName}' (${entries.length} skills)`);
7602
7619
  }
7603
7620
  }
7604
7621
  async function migrateToProfiles() {
7605
7622
  const homeDir = process.env["HOME"] ?? "/tmp";
7606
- const sharedConfigPath = join15(homeDir, ".openclaw", "openclaw.json");
7623
+ const sharedConfigPath = join16(homeDir, ".openclaw", "openclaw.json");
7607
7624
  let sharedConfig;
7608
7625
  try {
7609
- sharedConfig = JSON.parse(readFileSync13(sharedConfigPath, "utf-8"));
7626
+ sharedConfig = JSON.parse(readFileSync14(sharedConfigPath, "utf-8"));
7610
7627
  } catch {
7611
7628
  return;
7612
7629
  }
@@ -7619,19 +7636,19 @@ async function migrateToProfiles() {
7619
7636
  const codeName = agentEntry["id"];
7620
7637
  if (!codeName) continue;
7621
7638
  if (codeName === "main") continue;
7622
- const profileDir = join15(homeDir, `.openclaw-${codeName}`);
7623
- if (existsSync9(join15(profileDir, "openclaw.json"))) continue;
7639
+ const profileDir = join16(homeDir, `.openclaw-${codeName}`);
7640
+ if (existsSync9(join16(profileDir, "openclaw.json"))) continue;
7624
7641
  log(`Migrating agent '${codeName}' to per-agent profile`);
7625
7642
  if (adapter.seedProfileConfig) {
7626
7643
  adapter.seedProfileConfig(codeName);
7627
7644
  }
7628
- const sharedAuthDir = join15(homeDir, ".openclaw", "agents", codeName, "agent");
7629
- const profileAuthDir = join15(profileDir, "agents", codeName, "agent");
7630
- const authFile = join15(sharedAuthDir, "auth-profiles.json");
7645
+ const sharedAuthDir = join16(homeDir, ".openclaw", "agents", codeName, "agent");
7646
+ const profileAuthDir = join16(profileDir, "agents", codeName, "agent");
7647
+ const authFile = join16(sharedAuthDir, "auth-profiles.json");
7631
7648
  if (existsSync9(authFile)) {
7632
- mkdirSync4(profileAuthDir, { recursive: true });
7633
- const authContent = readFileSync13(authFile, "utf-8");
7634
- writeFileSync4(join15(profileAuthDir, "auth-profiles.json"), authContent);
7649
+ mkdirSync5(profileAuthDir, { recursive: true });
7650
+ const authContent = readFileSync14(authFile, "utf-8");
7651
+ writeFileSync5(join16(profileAuthDir, "auth-profiles.json"), authContent);
7635
7652
  }
7636
7653
  allocatePort(codeName);
7637
7654
  migrated++;
@@ -7647,7 +7664,7 @@ function readGatewayToken(codeName) {
7647
7664
  }
7648
7665
  const homeDir = process.env["HOME"] ?? "/tmp";
7649
7666
  try {
7650
- const cfg = JSON.parse(readFileSync13(join15(homeDir, `.openclaw-${codeName}`, "openclaw.json"), "utf-8"));
7667
+ const cfg = JSON.parse(readFileSync14(join16(homeDir, `.openclaw-${codeName}`, "openclaw.json"), "utf-8"));
7651
7668
  return cfg?.gateway?.auth?.token;
7652
7669
  } catch {
7653
7670
  return void 0;
@@ -7656,10 +7673,10 @@ function readGatewayToken(codeName) {
7656
7673
  var GATEWAY_HUNG_TIMEOUT_MS = 5 * 6e4;
7657
7674
  function isGatewayHung(codeName) {
7658
7675
  const homeDir = process.env["HOME"] ?? "/tmp";
7659
- const jobsPath = join15(homeDir, `.openclaw-${codeName}`, "cron", "jobs.json");
7676
+ const jobsPath = join16(homeDir, `.openclaw-${codeName}`, "cron", "jobs.json");
7660
7677
  if (!existsSync9(jobsPath)) return false;
7661
7678
  try {
7662
- const data = JSON.parse(readFileSync13(jobsPath, "utf-8"));
7679
+ const data = JSON.parse(readFileSync14(jobsPath, "utf-8"));
7663
7680
  const jobs = data.jobs ?? data;
7664
7681
  if (!Array.isArray(jobs)) return false;
7665
7682
  const now = Date.now();
@@ -7692,19 +7709,19 @@ async function ensureGatewayRunning(codeName, adapter) {
7692
7709
  }
7693
7710
  await new Promise((r) => setTimeout(r, 2e3));
7694
7711
  const homeDir = process.env["HOME"] ?? "/tmp";
7695
- const cronJobsPath = join15(homeDir, `.openclaw-${codeName}`, "cron", "jobs.json");
7712
+ const cronJobsPath = join16(homeDir, `.openclaw-${codeName}`, "cron", "jobs.json");
7696
7713
  clearStaleCronRunState(cronJobsPath);
7697
7714
  } else {
7698
7715
  if (status.port) {
7699
7716
  try {
7700
7717
  const homeDir = process.env["HOME"] ?? "/tmp";
7701
- const configPath = join15(homeDir, `.openclaw-${codeName}`, "openclaw.json");
7718
+ const configPath = join16(homeDir, `.openclaw-${codeName}`, "openclaw.json");
7702
7719
  if (existsSync9(configPath)) {
7703
- const cfg = JSON.parse(readFileSync13(configPath, "utf-8"));
7720
+ const cfg = JSON.parse(readFileSync14(configPath, "utf-8"));
7704
7721
  if (cfg.gateway?.port !== status.port) {
7705
7722
  if (!cfg.gateway) cfg.gateway = {};
7706
7723
  cfg.gateway.port = status.port;
7707
- writeFileSync4(configPath, JSON.stringify(cfg, null, 2));
7724
+ writeFileSync5(configPath, JSON.stringify(cfg, null, 2));
7708
7725
  }
7709
7726
  }
7710
7727
  } catch {
@@ -7724,12 +7741,12 @@ async function ensureGatewayRunning(codeName, adapter) {
7724
7741
  gatewaysStartedThisCycle.add(codeName);
7725
7742
  try {
7726
7743
  const homeDir = process.env["HOME"] ?? "/tmp";
7727
- const configPath = join15(homeDir, `.openclaw-${codeName}`, "openclaw.json");
7744
+ const configPath = join16(homeDir, `.openclaw-${codeName}`, "openclaw.json");
7728
7745
  if (existsSync9(configPath)) {
7729
- const cfg = JSON.parse(readFileSync13(configPath, "utf-8"));
7746
+ const cfg = JSON.parse(readFileSync14(configPath, "utf-8"));
7730
7747
  if (!cfg.gateway) cfg.gateway = {};
7731
7748
  cfg.gateway.port = port;
7732
- writeFileSync4(configPath, JSON.stringify(cfg, null, 2));
7749
+ writeFileSync5(configPath, JSON.stringify(cfg, null, 2));
7733
7750
  }
7734
7751
  } catch {
7735
7752
  }
@@ -7929,7 +7946,7 @@ async function pollCycle() {
7929
7946
  claudeAuth = await detectClaudeAuth();
7930
7947
  } catch (err) {
7931
7948
  const errText = err instanceof Error ? err.message : String(err);
7932
- const errId = createHash6("sha256").update(errText).digest("hex").slice(0, 12);
7949
+ const errId = createHash8("sha256").update(errText).digest("hex").slice(0, 12);
7933
7950
  log(`Claude auth detection failed (error_id=${errId})`);
7934
7951
  }
7935
7952
  const hostHasClaudeCode = state6.agents.some(
@@ -8289,7 +8306,7 @@ async function pollCycle() {
8289
8306
  }
8290
8307
  killAgentChannelProcesses(prev.codeName, { log });
8291
8308
  freePort(prev.codeName);
8292
- const agentDir = join15(adapter.getAgentDir(prev.codeName), "provision");
8309
+ const agentDir = join16(adapter.getAgentDir(prev.codeName), "provision");
8293
8310
  await cleanupAgentFiles(prev.codeName, agentDir);
8294
8311
  clearAgentCaches(prev.agentId, prev.codeName);
8295
8312
  }
@@ -8375,10 +8392,10 @@ async function pollCycle() {
8375
8392
  // pending-inbound marker. Best-effort: a write failure is logged by
8376
8393
  // the watchdog, never fails the poll cycle.
8377
8394
  signalGiveUp: (codeName) => {
8378
- const dir = join15(homedir8(), ".augmented", codeName);
8395
+ const dir = join16(homedir9(), ".augmented", codeName);
8379
8396
  if (!existsSync9(dir)) return;
8380
8397
  atomicWriteFileSync(
8381
- join15(dir, "watchdog-give-up.json"),
8398
+ join16(dir, "watchdog-give-up.json"),
8382
8399
  JSON.stringify({ gave_up_at: (/* @__PURE__ */ new Date()).toISOString() })
8383
8400
  );
8384
8401
  }
@@ -8505,7 +8522,7 @@ async function processAgent(agent, agentStates) {
8505
8522
  }
8506
8523
  const now = (/* @__PURE__ */ new Date()).toISOString();
8507
8524
  const adapter = resolveAgentFramework(agent.code_name);
8508
- let agentDir = join15(adapter.getAgentDir(agent.code_name), "provision");
8525
+ let agentDir = join16(adapter.getAgentDir(agent.code_name), "provision");
8509
8526
  if (agent.status === "draft" || agent.status === "paused") {
8510
8527
  if (previousKnownStatus !== agent.status) {
8511
8528
  log(`Agent '${agent.code_name}' is ${agent.status}, skipping provisioning`);
@@ -8709,7 +8726,7 @@ async function processAgent(agent, agentStates) {
8709
8726
  const frameworkId = refreshData.agent.framework ?? "openclaw";
8710
8727
  agentFrameworkCache.set(agent.code_name, frameworkId);
8711
8728
  const frameworkAdapter = getFramework(frameworkId);
8712
- agentDir = join15(frameworkAdapter.getAgentDir(agent.code_name), "provision");
8729
+ agentDir = join16(frameworkAdapter.getAgentDir(agent.code_name), "provision");
8713
8730
  cacheAgentDeliveryMetadata(agent.code_name, refreshData);
8714
8731
  if (frameworkAdapter.migrateSecretStorage && !migratedSecretStorage.has(agent.code_name)) {
8715
8732
  try {
@@ -8750,9 +8767,9 @@ async function processAgent(agent, agentStates) {
8750
8767
  try {
8751
8768
  const artifacts = generateArtifacts(agent, refreshData, frameworkAdapter);
8752
8769
  const changedFiles = [];
8753
- mkdirSync4(agentDir, { recursive: true });
8770
+ mkdirSync5(agentDir, { recursive: true });
8754
8771
  for (const artifact of artifacts) {
8755
- const filePath = join15(agentDir, artifact.relativePath);
8772
+ const filePath = join16(agentDir, artifact.relativePath);
8756
8773
  let existingHash;
8757
8774
  let newHash;
8758
8775
  let writeContent = artifact.content;
@@ -8771,8 +8788,8 @@ async function processAgent(agent, agentStates) {
8771
8788
  };
8772
8789
  newHash = sha256(stripDynamicSections(artifact.content));
8773
8790
  try {
8774
- const projectClaudeMd = join15(config.configDir, agent.code_name, "project", "CLAUDE.md");
8775
- const existing = readFileSync13(projectClaudeMd, "utf-8");
8791
+ const projectClaudeMd = join16(config.configDir, agent.code_name, "project", "CLAUDE.md");
8792
+ const existing = readFileSync14(projectClaudeMd, "utf-8");
8776
8793
  existingHash = sha256(stripDynamicSections(existing));
8777
8794
  } catch {
8778
8795
  existingHash = null;
@@ -8790,7 +8807,7 @@ async function processAgent(agent, agentStates) {
8790
8807
  const generatorKeys = Object.keys(generatorServers);
8791
8808
  let existingRaw = "";
8792
8809
  try {
8793
- existingRaw = readFileSync13(filePath, "utf-8");
8810
+ existingRaw = readFileSync14(filePath, "utf-8");
8794
8811
  } catch {
8795
8812
  }
8796
8813
  const existingServers = parseMcp(existingRaw);
@@ -8812,26 +8829,26 @@ async function processAgent(agent, agentStates) {
8812
8829
  }
8813
8830
  }
8814
8831
  if (changedFiles.length > 0) {
8815
- const isFirst = !existsSync9(join15(agentDir, "CHARTER.md"));
8832
+ const isFirst = !existsSync9(join16(agentDir, "CHARTER.md"));
8816
8833
  const verb = isFirst ? "Provisioning" : "Updating";
8817
8834
  const fileNames = changedFiles.map((f) => f.relativePath).join(", ");
8818
8835
  log(`${verb} '${agent.code_name}': ${fileNames}`);
8819
8836
  for (const file of changedFiles) {
8820
- const filePath = join15(agentDir, file.relativePath);
8821
- mkdirSync4(dirname3(filePath), { recursive: true });
8837
+ const filePath = join16(agentDir, file.relativePath);
8838
+ mkdirSync5(dirname4(filePath), { recursive: true });
8822
8839
  if (file.relativePath === ".mcp.json") {
8823
8840
  safeWriteJsonAtomic(filePath, file.content, { mode: 384 });
8824
8841
  } else {
8825
- writeFileSync4(filePath, file.content);
8842
+ writeFileSync5(filePath, file.content);
8826
8843
  }
8827
8844
  }
8828
8845
  try {
8829
- const provSkillsDir = join15(agentDir, ".claude", "skills");
8846
+ const provSkillsDir = join16(agentDir, ".claude", "skills");
8830
8847
  if (existsSync9(provSkillsDir)) {
8831
8848
  for (const folder of readdirSync5(provSkillsDir)) {
8832
8849
  if (folder.startsWith("knowledge-")) {
8833
8850
  try {
8834
- rmSync3(join15(provSkillsDir, folder), { recursive: true });
8851
+ rmSync3(join16(provSkillsDir, folder), { recursive: true });
8835
8852
  } catch {
8836
8853
  }
8837
8854
  }
@@ -8844,7 +8861,7 @@ async function processAgent(agent, agentStates) {
8844
8861
  const trackedFiles2 = frameworkAdapter.driftTrackedFiles();
8845
8862
  const hashes = /* @__PURE__ */ new Map();
8846
8863
  for (const file of trackedFiles2) {
8847
- const h = hashFile(join15(agentDir, file));
8864
+ const h = hashFile(join16(agentDir, file));
8848
8865
  if (h) hashes.set(file, h);
8849
8866
  }
8850
8867
  agentState.writtenHashes.set(agent.agent_id, hashes);
@@ -8862,14 +8879,14 @@ async function processAgent(agent, agentStates) {
8862
8879
  }
8863
8880
  if (Array.isArray(refreshData.workflows)) {
8864
8881
  try {
8865
- const provWorkflowsDir = join15(agentDir, ".claude", "workflows");
8882
+ const provWorkflowsDir = join16(agentDir, ".claude", "workflows");
8866
8883
  if (existsSync9(provWorkflowsDir)) {
8867
8884
  const expected = new Set(refreshData.workflows.map((w) => `${w.name}.js`));
8868
8885
  for (const file of readdirSync5(provWorkflowsDir)) {
8869
8886
  if (!file.endsWith(".js")) continue;
8870
8887
  if (expected.has(file)) continue;
8871
8888
  try {
8872
- rmSync3(join15(provWorkflowsDir, file));
8889
+ rmSync3(join16(provWorkflowsDir, file));
8873
8890
  } catch {
8874
8891
  }
8875
8892
  }
@@ -8929,7 +8946,7 @@ async function processAgent(agent, agentStates) {
8929
8946
  if (written && existsSync9(agentDir)) {
8930
8947
  const driftedFiles = [];
8931
8948
  for (const [file, expectedHash] of written) {
8932
- const localHash = hashFile(join15(agentDir, file));
8949
+ const localHash = hashFile(join16(agentDir, file));
8933
8950
  if (localHash && localHash !== expectedHash) {
8934
8951
  driftedFiles.push(file);
8935
8952
  }
@@ -8940,7 +8957,7 @@ async function processAgent(agent, agentStates) {
8940
8957
  try {
8941
8958
  const localHashes = {};
8942
8959
  for (const file of driftedFiles) {
8943
- localHashes[file] = hashFile(join15(agentDir, file));
8960
+ localHashes[file] = hashFile(join16(agentDir, file));
8944
8961
  }
8945
8962
  await api.post("/host/drift", {
8946
8963
  agent_id: agent.agent_id,
@@ -9014,7 +9031,7 @@ async function processAgent(agent, agentStates) {
9014
9031
  const sessionModeForHash = refreshData.agent.session_mode;
9015
9032
  const senderPolicyForHash = refreshData.sender_policy ?? null;
9016
9033
  const CHANNEL_WRITE_VERSION = 9;
9017
- const configHash = createHash6("sha256").update(
9034
+ const configHash = createHash8("sha256").update(
9018
9035
  canonicalJson({
9019
9036
  writeVersion: CHANNEL_WRITE_VERSION,
9020
9037
  config: entry.config,
@@ -9128,7 +9145,7 @@ async function processAgent(agent, agentStates) {
9128
9145
  if (channelConfigConverged) {
9129
9146
  const hasSenderPolicyChannel = currentChannelIds.has("slack") || currentChannelIds.has("msteams");
9130
9147
  const senderPolicyForRestartHash = refreshData.sender_policy ?? null;
9131
- const senderPolicyHash = createHash6("sha256").update(canonicalJson({ senderPolicy: senderPolicyForRestartHash })).digest("hex");
9148
+ const senderPolicyHash = createHash8("sha256").update(canonicalJson({ senderPolicy: senderPolicyForRestartHash })).digest("hex");
9132
9149
  const prevSenderPolicyHash = agentState.knownSenderPolicyHashes.get(agent.agent_id);
9133
9150
  const senderPolicyDecision = hasSenderPolicyChannel ? decideSenderPolicyRestart({
9134
9151
  previousHash: prevSenderPolicyHash,
@@ -9170,7 +9187,7 @@ async function processAgent(agent, agentStates) {
9170
9187
  const behaviourSubset = extractMsTeamsBehaviourSubset(
9171
9188
  msteamsEntry?.config
9172
9189
  );
9173
- const behaviourHash = createHash6("sha256").update(canonicalJson(behaviourSubset)).digest("hex");
9190
+ const behaviourHash = createHash8("sha256").update(canonicalJson(behaviourSubset)).digest("hex");
9174
9191
  const prevBehaviourHash = agentState.knownMsTeamsBehaviourHashes.get(agent.agent_id);
9175
9192
  const behaviourDecision = decideSenderPolicyRestart({
9176
9193
  previousHash: prevBehaviourHash,
@@ -9217,7 +9234,7 @@ async function processAgent(agent, agentStates) {
9217
9234
  const slackBehaviourSubset = extractSlackBehaviourSubset(
9218
9235
  slackEntry?.config
9219
9236
  );
9220
- const slackBehaviourHash = createHash6("sha256").update(canonicalJson(slackBehaviourSubset)).digest("hex");
9237
+ const slackBehaviourHash = createHash8("sha256").update(canonicalJson(slackBehaviourSubset)).digest("hex");
9221
9238
  const prevSlackBehaviourHash = agentState.knownSlackBehaviourHashes.get(agent.agent_id);
9222
9239
  const slackBehaviourDecision = decideSenderPolicyRestart({
9223
9240
  previousHash: prevSlackBehaviourHash,
@@ -9264,18 +9281,18 @@ async function processAgent(agent, agentStates) {
9264
9281
  if (agentSessionMode === "persistent" && (agentFrameworkCache.get(agent.code_name) ?? "openclaw") === "claude-code") {
9265
9282
  try {
9266
9283
  const agentProvisionDir = agentDir;
9267
- const projectDir = join15(homedir8(), ".augmented", agent.code_name, "project");
9268
- mkdirSync4(agentProvisionDir, { recursive: true });
9269
- mkdirSync4(projectDir, { recursive: true });
9270
- const provisionMcpPath = join15(agentProvisionDir, ".mcp.json");
9271
- const projectMcpPath = join15(projectDir, ".mcp.json");
9284
+ const projectDir = join16(homedir9(), ".augmented", agent.code_name, "project");
9285
+ mkdirSync5(agentProvisionDir, { recursive: true });
9286
+ mkdirSync5(projectDir, { recursive: true });
9287
+ const provisionMcpPath = join16(agentProvisionDir, ".mcp.json");
9288
+ const projectMcpPath = join16(projectDir, ".mcp.json");
9272
9289
  let mcpConfig = { mcpServers: {} };
9273
9290
  try {
9274
- mcpConfig = JSON.parse(readFileSync13(provisionMcpPath, "utf-8"));
9291
+ mcpConfig = JSON.parse(readFileSync14(provisionMcpPath, "utf-8"));
9275
9292
  if (!mcpConfig.mcpServers) mcpConfig.mcpServers = {};
9276
9293
  } catch {
9277
9294
  }
9278
- const localDirectChatChannel = join15(homedir8(), ".augmented", "_mcp", "direct-chat-channel.js");
9295
+ const localDirectChatChannel = join16(homedir9(), ".augmented", "_mcp", "direct-chat-channel.js");
9279
9296
  const directChatTeamSettings = refreshData.team?.settings;
9280
9297
  const directChatTz = (() => {
9281
9298
  const tz = directChatTeamSettings?.["timezone"];
@@ -9305,7 +9322,7 @@ async function processAgent(agent, agentStates) {
9305
9322
  log(`Channel credentials written for '${agent.code_name}/direct-chat'`);
9306
9323
  }
9307
9324
  }
9308
- const staleChannelsPath = join15(projectDir, ".mcp-channels.json");
9325
+ const staleChannelsPath = join16(projectDir, ".mcp-channels.json");
9309
9326
  if (existsSync9(staleChannelsPath)) {
9310
9327
  try {
9311
9328
  rmSync3(staleChannelsPath, { force: true });
@@ -9370,7 +9387,7 @@ async function processAgent(agent, agentStates) {
9370
9387
  }
9371
9388
  if (process.env.AGT_CONNECTIVITY_PROBE_ENABLED === "true") {
9372
9389
  try {
9373
- const probeProjectDir = join15(homedir8(), ".augmented", agent.code_name, "project");
9390
+ const probeProjectDir = join16(homedir9(), ".augmented", agent.code_name, "project");
9374
9391
  await runAgentConnectivityProbes(agent, integrations, probeProjectDir);
9375
9392
  } catch (err) {
9376
9393
  log(`Connectivity probe failed for '${agent.code_name}': ${err.message}`);
@@ -9388,11 +9405,11 @@ async function processAgent(agent, agentStates) {
9388
9405
  recordConfigChurnEvent(agent.agent_id, agent.code_name, FLAP_CHANNEL_INTEGRATIONS, intMembership);
9389
9406
  }
9390
9407
  if (intHash !== prevIntHash) {
9391
- const projectDir = join15(homedir8(), ".augmented", agent.code_name, "project");
9392
- const envIntPath = join15(projectDir, ".env.integrations");
9408
+ const projectDir = join16(homedir9(), ".augmented", agent.code_name, "project");
9409
+ const envIntPath = join16(projectDir, ".env.integrations");
9393
9410
  let preWriteEnv;
9394
9411
  try {
9395
- preWriteEnv = readFileSync13(envIntPath, "utf-8");
9412
+ preWriteEnv = readFileSync14(envIntPath, "utf-8");
9396
9413
  } catch {
9397
9414
  preWriteEnv = void 0;
9398
9415
  }
@@ -9404,9 +9421,9 @@ async function processAgent(agent, agentStates) {
9404
9421
  let rotationHandled = true;
9405
9422
  if (fw === "claude-code" && isSessionHealthy(agent.code_name)) {
9406
9423
  try {
9407
- const projectMcpPath = join15(projectDir, ".mcp.json");
9408
- const postWriteEnv = readFileSync13(envIntPath, "utf-8");
9409
- const mcpContent = readFileSync13(projectMcpPath, "utf-8");
9424
+ const projectMcpPath = join16(projectDir, ".mcp.json");
9425
+ const postWriteEnv = readFileSync14(envIntPath, "utf-8");
9426
+ const mcpContent = readFileSync14(projectMcpPath, "utf-8");
9410
9427
  const changedVars = diffEnvIntegrations(preWriteEnv, postWriteEnv);
9411
9428
  const mcpJsonForReap = JSON.parse(mcpContent);
9412
9429
  const affectedServerKeys = findMcpServersUsingVars(mcpJsonForReap, changedVars);
@@ -9461,10 +9478,10 @@ async function processAgent(agent, agentStates) {
9461
9478
  desiredEntries.push({ serverId, url, headers: mcpHeaders, name: tk.toolkit_name });
9462
9479
  }
9463
9480
  const hashBasis = desiredEntries.slice().sort((a, b) => a.serverId.localeCompare(b.serverId)).map((e) => {
9464
- const headersHash = createHash6("sha256").update(canonicalJson(e.headers ?? {})).digest("hex").slice(0, 16);
9481
+ const headersHash = createHash8("sha256").update(canonicalJson(e.headers ?? {})).digest("hex").slice(0, 16);
9465
9482
  return `${e.serverId}|${e.url}|${headersHash}`;
9466
9483
  }).join("\n");
9467
- const mcpHash = createHash6("sha256").update(hashBasis).digest("hex").slice(0, 16);
9484
+ const mcpHash = createHash8("sha256").update(hashBasis).digest("hex").slice(0, 16);
9468
9485
  const prevMcpHash = agentState.knownManagedMcpHashes.get(agent.agent_id);
9469
9486
  const structureHash = managedMcpStructureHash(desiredEntries);
9470
9487
  const prevStructureHash = agentState.knownManagedMcpStructure.get(agent.agent_id);
@@ -9479,15 +9496,15 @@ async function processAgent(agent, agentStates) {
9479
9496
  if (mcpHash !== prevMcpHash) {
9480
9497
  for (const e of desiredEntries) {
9481
9498
  frameworkAdapter.writeMcpServer(agent.code_name, e.serverId, { url: e.url, headers: e.headers });
9482
- const urlHash = createHash6("sha256").update(e.url).digest("hex").slice(0, 12);
9499
+ const urlHash = createHash8("sha256").update(e.url).digest("hex").slice(0, 12);
9483
9500
  log(`[managed-toolkit] ${agent.code_name}: wrote '${e.name}' (serverId=${e.serverId}, url_hash=${urlHash})`);
9484
9501
  }
9485
9502
  if (frameworkAdapter.removeMcpServer && frameworkAdapter.getMcpPath) {
9486
9503
  const mcpPath = frameworkAdapter.getMcpPath(agent.code_name);
9487
9504
  if (mcpPath) {
9488
9505
  try {
9489
- const { readFileSync: readFileSync14 } = await import("fs");
9490
- const mcpConfig = JSON.parse(readFileSync14(mcpPath, "utf-8"));
9506
+ const { readFileSync: readFileSync15 } = await import("fs");
9507
+ const mcpConfig = JSON.parse(readFileSync15(mcpPath, "utf-8"));
9491
9508
  if (mcpConfig.mcpServers) {
9492
9509
  const managedPrefixes = [
9493
9510
  "composio_",
@@ -9588,7 +9605,7 @@ async function processAgent(agent, agentStates) {
9588
9605
  if (agent.status === "active") {
9589
9606
  if (frameworkAdapter.installPlugin) {
9590
9607
  try {
9591
- const pluginPath = join15(process.cwd(), "packages", "openclaw-plugin-augmented", "src", "index.ts");
9608
+ const pluginPath = join16(process.cwd(), "packages", "openclaw-plugin-augmented", "src", "index.ts");
9592
9609
  if (existsSync9(pluginPath)) {
9593
9610
  frameworkAdapter.installPlugin(agent.code_name, "augmented", pluginPath, {
9594
9611
  agtHost: requireHost(),
@@ -9613,7 +9630,7 @@ async function processAgent(agent, agentStates) {
9613
9630
  if (frameworkAdapter.installSkillFiles) {
9614
9631
  const currentIntegrationSkillIds = /* @__PURE__ */ new Set();
9615
9632
  const installedIntegrationSkills = [];
9616
- const { createHash: createHash7 } = await import("crypto");
9633
+ const { createHash: createHash9 } = await import("crypto");
9617
9634
  const refreshAny = refreshData;
9618
9635
  const contexts = refreshAny.integration_contexts ?? refreshAny.plugin_contexts ?? [];
9619
9636
  const contextBySlug = /* @__PURE__ */ new Map();
@@ -9642,7 +9659,7 @@ async function processAgent(agent, agentStates) {
9642
9659
  )
9643
9660
  }));
9644
9661
  const bundle = buildIntegrationBundle(renderedScopes);
9645
- const contentHash = createHash7("sha256").update(bundleFingerprint(bundle.files)).digest("hex").slice(0, 12);
9662
+ const contentHash = createHash9("sha256").update(bundleFingerprint(bundle.files)).digest("hex").slice(0, 12);
9646
9663
  const hashKey = `plugin-skill:${agent.agent_id}:${integrationSkillId}`;
9647
9664
  if (agentState.knownSkillHashes.get(hashKey) === contentHash) continue;
9648
9665
  frameworkAdapter.installSkillFiles(agent.code_name, integrationSkillId, bundle.files);
@@ -9655,18 +9672,18 @@ async function processAgent(agent, agentStates) {
9655
9672
  }
9656
9673
  try {
9657
9674
  const { readdirSync: readdirSync6, rmSync: rmSync4 } = await import("fs");
9658
- const { homedir: homedir9 } = await import("os");
9675
+ const { homedir: homedir10 } = await import("os");
9659
9676
  const frameworkId2 = frameworkAdapter.id;
9660
9677
  const candidateSkillDirs = [
9661
9678
  // Claude Code — framework runtime tree
9662
- join15(homedir9(), ".augmented", agent.code_name, "skills"),
9679
+ join16(homedir10(), ".augmented", agent.code_name, "skills"),
9663
9680
  // Claude Code — project tree
9664
- join15(homedir9(), ".augmented", agent.code_name, "project", ".claude", "skills"),
9681
+ join16(homedir10(), ".augmented", agent.code_name, "project", ".claude", "skills"),
9665
9682
  // OpenClaw — framework runtime tree
9666
- join15(homedir9(), `.openclaw-${agent.code_name}`, "skills"),
9683
+ join16(homedir10(), `.openclaw-${agent.code_name}`, "skills"),
9667
9684
  // Defensive: legacy provision-side path, not currently an
9668
9685
  // install target but cheap to sweep.
9669
- join15(agentDir, ".claude", "skills")
9686
+ join16(agentDir, ".claude", "skills")
9670
9687
  ];
9671
9688
  const existingDirs = candidateSkillDirs.filter((d) => existsSync9(d));
9672
9689
  const discoveredEntries = /* @__PURE__ */ new Set();
@@ -9682,7 +9699,7 @@ async function processAgent(agent, agentStates) {
9682
9699
  }
9683
9700
  const removeSkillFolder = (entry, reason) => {
9684
9701
  for (const dir of existingDirs) {
9685
- const p = join15(dir, entry);
9702
+ const p = join16(dir, entry);
9686
9703
  if (existsSync9(p)) {
9687
9704
  rmSync4(p, { recursive: true, force: true });
9688
9705
  }
@@ -9701,7 +9718,7 @@ async function processAgent(agent, agentStates) {
9701
9718
  const plan = planGlobalSkillSync(
9702
9719
  refreshAny.global_skills ?? [],
9703
9720
  agentState.knownGlobalSkillIds.get(agent.agent_id) ?? /* @__PURE__ */ new Set(),
9704
- (content) => createHash7("sha256").update(content).digest("hex").slice(0, 12),
9721
+ (content) => createHash9("sha256").update(content).digest("hex").slice(0, 12),
9705
9722
  (skillId) => agentState.knownSkillHashes.get(`global-skill:${agent.agent_id}:${skillId}`)
9706
9723
  );
9707
9724
  for (const { skillId, content, hash } of plan.installs) {
@@ -9711,16 +9728,16 @@ async function processAgent(agent, agentStates) {
9711
9728
  }
9712
9729
  if (plan.removes.length) {
9713
9730
  const { rmSync: rmSync4 } = await import("fs");
9714
- const { homedir: homedir9 } = await import("os");
9731
+ const { homedir: homedir10 } = await import("os");
9715
9732
  const globalSkillDirs = [
9716
- join15(homedir9(), ".augmented", agent.code_name, "skills"),
9717
- join15(homedir9(), ".augmented", agent.code_name, "project", ".claude", "skills"),
9718
- join15(homedir9(), `.openclaw-${agent.code_name}`, "skills"),
9719
- join15(agentDir, ".claude", "skills")
9733
+ join16(homedir10(), ".augmented", agent.code_name, "skills"),
9734
+ join16(homedir10(), ".augmented", agent.code_name, "project", ".claude", "skills"),
9735
+ join16(homedir10(), `.openclaw-${agent.code_name}`, "skills"),
9736
+ join16(agentDir, ".claude", "skills")
9720
9737
  ];
9721
9738
  for (const id of plan.removes) {
9722
9739
  for (const dir of globalSkillDirs) {
9723
- const p = join15(dir, id);
9740
+ const p = join16(dir, id);
9724
9741
  if (existsSync9(p)) rmSync4(p, { recursive: true, force: true });
9725
9742
  }
9726
9743
  agentState.knownSkillHashes.delete(`global-skill:${agent.agent_id}:${id}`);
@@ -9745,7 +9762,7 @@ async function processAgent(agent, agentStates) {
9745
9762
  const slug = hook.integration_slug ?? hook.plugin_slug;
9746
9763
  if (!slug) continue;
9747
9764
  try {
9748
- const scriptHash = createHash7("sha256").update(hook.script).digest("hex").slice(0, 12);
9765
+ const scriptHash = createHash9("sha256").update(hook.script).digest("hex").slice(0, 12);
9749
9766
  const hookKey = `${agent.agent_id}:${frameworkAdapter.id}:plugin-hook:${slug}:on_install`;
9750
9767
  if (agentState.knownSkillHashes.get(hookKey) === scriptHash) continue;
9751
9768
  const result = await frameworkAdapter.executePluginHook({
@@ -9760,9 +9777,9 @@ async function processAgent(agent, agentStates) {
9760
9777
  } else if (result.timedOut) {
9761
9778
  log(`Integration hook on_install '${slug}' TIMED OUT for '${agent.code_name}' after ${result.durationMs}ms`);
9762
9779
  } else {
9763
- const stderrHash = createHash7("sha256").update(result.stderr).digest("hex").slice(0, 12);
9780
+ const stderrHash = createHash9("sha256").update(result.stderr).digest("hex").slice(0, 12);
9764
9781
  const missingCmd = result.exitCode === 127 ? extractCommandNotFound(result.stderr) : null;
9765
- const missingCmdHash = missingCmd ? createHash7("sha256").update(missingCmd).digest("hex").slice(0, 8) : null;
9782
+ const missingCmdHash = missingCmd ? createHash9("sha256").update(missingCmd).digest("hex").slice(0, 8) : null;
9766
9783
  log(
9767
9784
  `Integration hook on_install '${slug}' exited ${result.exitCode} for '${agent.code_name}' ` + (missingCmdHash ? `[missing_command_hash=${missingCmdHash}] ` : "") + `[stderr_hash=${stderrHash} stderr_len=${result.stderr.length}]`
9768
9785
  );
@@ -9896,8 +9913,8 @@ async function processAgent(agent, agentStates) {
9896
9913
  const sess = getSessionState(agent.code_name);
9897
9914
  let mcpJsonParsed = null;
9898
9915
  try {
9899
- const mcpPath = join15(getProjectDir(agent.code_name), ".mcp.json");
9900
- mcpJsonParsed = JSON.parse(readFileSync13(mcpPath, "utf-8"));
9916
+ const mcpPath = join16(getProjectDir(agent.code_name), ".mcp.json");
9917
+ mcpJsonParsed = JSON.parse(readFileSync14(mcpPath, "utf-8"));
9901
9918
  } catch {
9902
9919
  }
9903
9920
  reapMissingMcpSessions({
@@ -10031,10 +10048,10 @@ async function processAgent(agent, agentStates) {
10031
10048
  } else if (agentFw === "claude-code" && tasks.length > 0) {
10032
10049
  await syncAndCheckClaudeScheduler(agent, tasks, boardItems, refreshData);
10033
10050
  } else if (frameworkAdapter.syncScheduledTasks && gatewayRunning && gatewayPort) {
10034
- const stableTasksHash = createHash6("sha256").update(JSON.stringify(tasks)).digest("hex").slice(0, 16);
10035
- const boardHash = boardItems.length > 0 ? createHash6("sha256").update(JSON.stringify(boardItems.map((b) => ({ id: b.id, title: b.title, status: b.status, priority: b.priority, deliverable: b.deliverable })))).digest("hex").slice(0, 16) : "empty";
10051
+ const stableTasksHash = createHash8("sha256").update(JSON.stringify(tasks)).digest("hex").slice(0, 16);
10052
+ const boardHash = boardItems.length > 0 ? createHash8("sha256").update(JSON.stringify(boardItems.map((b) => ({ id: b.id, title: b.title, status: b.status, priority: b.priority, deliverable: b.deliverable })))).digest("hex").slice(0, 16) : "empty";
10036
10053
  const resolvedModels = resolveModelChain(refreshData);
10037
- const modelsHash = createHash6("sha256").update(JSON.stringify(resolvedModels)).digest("hex").slice(0, 16);
10054
+ const modelsHash = createHash8("sha256").update(JSON.stringify(resolvedModels)).digest("hex").slice(0, 16);
10038
10055
  const combinedHash = `${stableTasksHash}:${boardHash}:${modelsHash}`;
10039
10056
  const prevTasksHash = agentState.knownTasksHashes.get(agent.agent_id);
10040
10057
  if (combinedHash !== prevTasksHash) {
@@ -10106,10 +10123,10 @@ async function processAgent(agent, agentStates) {
10106
10123
  lastWorkTriggerAt.set(agent.code_name, triggerTs);
10107
10124
  if (agentFw === "openclaw" && gatewayRunning && gatewayPort) {
10108
10125
  const homeDir = process.env["HOME"] ?? "/tmp";
10109
- const jobsPath = join15(homeDir, `.openclaw-${agent.code_name}`, "cron", "jobs.json");
10126
+ const jobsPath = join16(homeDir, `.openclaw-${agent.code_name}`, "cron", "jobs.json");
10110
10127
  if (existsSync9(jobsPath)) {
10111
10128
  try {
10112
- const jobsData = JSON.parse(readFileSync13(jobsPath, "utf-8"));
10129
+ const jobsData = JSON.parse(readFileSync14(jobsPath, "utf-8"));
10113
10130
  const kanbanJob = (jobsData.jobs ?? []).find(
10114
10131
  (j) => typeof j.name === "string" && j.name.includes("kanban-work")
10115
10132
  );
@@ -10246,7 +10263,7 @@ In progress for ${age} minutes \u2014 auto-failed`).catch(() => {
10246
10263
  if (trackedFiles.length > 0 && existsSync9(agentDir)) {
10247
10264
  const hashes = /* @__PURE__ */ new Map();
10248
10265
  for (const file of trackedFiles) {
10249
- const h = hashFile(join15(agentDir, file));
10266
+ const h = hashFile(join16(agentDir, file));
10250
10267
  if (h) hashes.set(file, h);
10251
10268
  }
10252
10269
  agentState.writtenHashes.set(agent.agent_id, hashes);
@@ -10280,19 +10297,19 @@ function cleanupStaleSessions(codeName) {
10280
10297
  lastCleanupAt.set(codeName, Date.now());
10281
10298
  const homeDir = process.env["HOME"] ?? "/tmp";
10282
10299
  for (const agentDir of ["main", codeName]) {
10283
- const sessionsDir = join15(homeDir, `.openclaw-${codeName}`, "agents", agentDir, "sessions");
10300
+ const sessionsDir = join16(homeDir, `.openclaw-${codeName}`, "agents", agentDir, "sessions");
10284
10301
  cleanupCronSessions(sessionsDir, CRON_SESSION_KEEP_COUNT);
10285
10302
  }
10286
- const cronRunsDir = join15(homeDir, `.openclaw-${codeName}`, "cron", "runs");
10303
+ const cronRunsDir = join16(homeDir, `.openclaw-${codeName}`, "cron", "runs");
10287
10304
  cleanupOldFiles(cronRunsDir, CRON_RUN_RETENTION_DAYS, ".jsonl");
10288
- const cronJobsPath = join15(homeDir, `.openclaw-${codeName}`, "cron", "jobs.json");
10305
+ const cronJobsPath = join16(homeDir, `.openclaw-${codeName}`, "cron", "jobs.json");
10289
10306
  clearStaleCronRunState(cronJobsPath);
10290
10307
  }
10291
10308
  function cleanupCronSessions(sessionsDir, keepCount) {
10292
- const indexPath = join15(sessionsDir, "sessions.json");
10309
+ const indexPath = join16(sessionsDir, "sessions.json");
10293
10310
  if (!existsSync9(indexPath)) return;
10294
10311
  try {
10295
- const raw = readFileSync13(indexPath, "utf-8");
10312
+ const raw = readFileSync14(indexPath, "utf-8");
10296
10313
  const index = JSON.parse(raw);
10297
10314
  const cronRunKeys = Object.keys(index).filter((k) => k.includes(":cron:") && k.includes(":run:")).map((k) => ({
10298
10315
  key: k,
@@ -10305,7 +10322,7 @@ function cleanupCronSessions(sessionsDir, keepCount) {
10305
10322
  for (const entry of toDelete) {
10306
10323
  delete index[entry.key];
10307
10324
  if (entry.sessionId) {
10308
- const sessionFile = join15(sessionsDir, `${entry.sessionId}.jsonl`);
10325
+ const sessionFile = join16(sessionsDir, `${entry.sessionId}.jsonl`);
10309
10326
  try {
10310
10327
  if (existsSync9(sessionFile)) {
10311
10328
  unlinkSync(sessionFile);
@@ -10327,7 +10344,7 @@ function cleanupCronSessions(sessionsDir, keepCount) {
10327
10344
  delete index[parentKey];
10328
10345
  if (parentSessionId) {
10329
10346
  try {
10330
- const f = join15(sessionsDir, `${parentSessionId}.jsonl`);
10347
+ const f = join16(sessionsDir, `${parentSessionId}.jsonl`);
10331
10348
  if (existsSync9(f)) {
10332
10349
  unlinkSync(f);
10333
10350
  deletedFiles++;
@@ -10337,7 +10354,7 @@ function cleanupCronSessions(sessionsDir, keepCount) {
10337
10354
  }
10338
10355
  }
10339
10356
  }
10340
- writeFileSync4(indexPath, JSON.stringify(index));
10357
+ writeFileSync5(indexPath, JSON.stringify(index));
10341
10358
  if (toDelete.length > 0) {
10342
10359
  log(`Cleaned ${toDelete.length} cron session(s) and ${deletedFiles} file(s) from ${sessionsDir}`);
10343
10360
  }
@@ -10348,7 +10365,7 @@ var STALE_RUN_TIMEOUT_MS = 5 * 6e4;
10348
10365
  function clearStaleCronRunState(jobsPath) {
10349
10366
  if (!existsSync9(jobsPath)) return;
10350
10367
  try {
10351
- const raw = readFileSync13(jobsPath, "utf-8");
10368
+ const raw = readFileSync14(jobsPath, "utf-8");
10352
10369
  const data = JSON.parse(raw);
10353
10370
  const jobs = data.jobs ?? data;
10354
10371
  if (!Array.isArray(jobs)) return;
@@ -10373,7 +10390,7 @@ function clearStaleCronRunState(jobsPath) {
10373
10390
  }
10374
10391
  }
10375
10392
  if (changed) {
10376
- writeFileSync4(jobsPath, JSON.stringify(data, null, 2));
10393
+ writeFileSync5(jobsPath, JSON.stringify(data, null, 2));
10377
10394
  }
10378
10395
  } catch {
10379
10396
  }
@@ -10385,7 +10402,7 @@ function cleanupOldFiles(dir, maxAgeDays, ext) {
10385
10402
  try {
10386
10403
  for (const f of readdirSync5(dir)) {
10387
10404
  if (!f.endsWith(ext)) continue;
10388
- const fullPath = join15(dir, f);
10405
+ const fullPath = join16(dir, f);
10389
10406
  try {
10390
10407
  const st = statSync4(fullPath);
10391
10408
  if (st.mtimeMs < cutoff) {
@@ -10407,8 +10424,8 @@ var claudeAuthTupleBySession = /* @__PURE__ */ new Map();
10407
10424
  async function ensurePersistentSession(agent, tasks, boardItems, refreshData) {
10408
10425
  const codeName = agent.code_name;
10409
10426
  const projectDir = getProjectDir(codeName);
10410
- const mcpConfigPath = join15(projectDir, ".mcp.json");
10411
- const claudeMdPath = join15(projectDir, "CLAUDE.md");
10427
+ const mcpConfigPath = join16(projectDir, ".mcp.json");
10428
+ const claudeMdPath = join16(projectDir, "CLAUDE.md");
10412
10429
  if (restartBreaker.isTripped(codeName)) {
10413
10430
  const trip = restartBreaker.getTrip(codeName);
10414
10431
  return {
@@ -10525,7 +10542,7 @@ async function ensurePersistentSession(agent, tasks, boardItems, refreshData) {
10525
10542
  const ctx = getLastFailureContext(codeName);
10526
10543
  const recovery = prepareForRespawn(codeName);
10527
10544
  const tailSummary = !ctx.tail ? "" : KNOWN_SAFE_TAIL_SIGNATURES.has(ctx.signature) ? `; last pane output (${PANE_TAIL_PREVIEW_LINES} of ~20 lines):
10528
- ${truncateForLog(ctx.tail)}` : `; pane_tail_hash=sha256:${createHash6("sha256").update(ctx.tail).digest("hex").slice(0, 12)} (raw at ~/.augmented/${codeName}/pane.log)`;
10545
+ ${truncateForLog(ctx.tail)}` : `; pane_tail_hash=sha256:${createHash8("sha256").update(ctx.tail).digest("hex").slice(0, 12)} (raw at ~/.augmented/${codeName}/pane.log)`;
10529
10546
  const sigSummary = ctx.signature !== "unknown" ? `; signature=${ctx.signature}` : "";
10530
10547
  const recoverySummary = recovery ? `; recovery=${recovery}` : "";
10531
10548
  log(
@@ -10539,7 +10556,7 @@ ${truncateForLog(ctx.tail)}` : `; pane_tail_hash=sha256:${createHash6("sha256").
10539
10556
  );
10540
10557
  getHostId().then((hostId) => {
10541
10558
  if (!hostId) return;
10542
- const paneTailHash = zombie.paneTail ? `sha256:${createHash6("sha256").update(zombie.paneTail).digest("hex").slice(0, 12)}` : null;
10559
+ const paneTailHash = zombie.paneTail ? `sha256:${createHash8("sha256").update(zombie.paneTail).digest("hex").slice(0, 12)}` : null;
10543
10560
  return api.post("/host/events", {
10544
10561
  host_id: hostId,
10545
10562
  agent_code_name: codeName,
@@ -10618,7 +10635,7 @@ ${truncateForLog(ctx.tail)}` : `; pane_tail_hash=sha256:${createHash6("sha256").
10618
10635
  if (!claudeAuthTupleBySession.has(codeName)) {
10619
10636
  claudeAuthTupleBySession.set(codeName, currentAuthTuple);
10620
10637
  }
10621
- const stableTasksHash = createHash6("sha256").update(JSON.stringify(tasks)).digest("hex").slice(0, 16);
10638
+ const stableTasksHash = createHash8("sha256").update(JSON.stringify(tasks)).digest("hex").slice(0, 16);
10622
10639
  const prevHash = agentState.knownTasksHashes.get(agent.agent_id);
10623
10640
  if (stableTasksHash !== prevHash) {
10624
10641
  const taskInputs = tasks.map((t) => buildSchedulerTaskInput(t));
@@ -11007,9 +11024,9 @@ async function processDirectChatMessage(agent, msg) {
11007
11024
  if (isSessionHealthy(agent.codeName)) {
11008
11025
  if (hostFlagStore().getBoolean("direct-chat-doorbell")) {
11009
11026
  try {
11010
- const doorbell = directChatDoorbellPath(agent.agentId, homedir8());
11011
- mkdirSync4(dirname3(doorbell), { recursive: true });
11012
- writeFileSync4(doorbell, String(Date.now()));
11027
+ const doorbell = directChatDoorbellPath(agent.agentId, homedir9());
11028
+ mkdirSync5(dirname4(doorbell), { recursive: true });
11029
+ writeFileSync5(doorbell, String(Date.now()));
11013
11030
  log(`[direct-chat] Doorbell rung for '${agent.codeName}' (msg=${msg.id}) \u2014 in-session MCP will pull via the cursor`);
11014
11031
  return;
11015
11032
  } catch (err) {
@@ -11053,11 +11070,11 @@ ${escapeXml(msg.content)}
11053
11070
  log(`[direct-chat] One-shot spawn for '${agent.codeName}' (msg=${msg.id}; host in-flight=${directChatSpawnGate.hostInFlight}, queued=${directChatSpawnGate.queuedCount})`);
11054
11071
  const { getProjectDir: ccProjectDir } = await import("../claude-scheduler-FATCLHDM.js");
11055
11072
  const projDir = ccProjectDir(agent.codeName);
11056
- const mcpConfigPath = join15(projDir, ".mcp.json");
11073
+ const mcpConfigPath = join16(projDir, ".mcp.json");
11057
11074
  const serverNames = [];
11058
11075
  if (existsSync9(mcpConfigPath)) {
11059
11076
  try {
11060
- const d = JSON.parse(readFileSync13(mcpConfigPath, "utf-8"));
11077
+ const d = JSON.parse(readFileSync14(mcpConfigPath, "utf-8"));
11061
11078
  if (d.mcpServers) serverNames.push(...Object.keys(d.mcpServers));
11062
11079
  } catch {
11063
11080
  }
@@ -11076,15 +11093,15 @@ ${escapeXml(msg.content)}
11076
11093
  "--allowedTools",
11077
11094
  allowedTools
11078
11095
  ];
11079
- const chatClaudeMd = join15(projDir, "CLAUDE.md");
11096
+ const chatClaudeMd = join16(projDir, "CLAUDE.md");
11080
11097
  if (existsSync9(chatClaudeMd)) {
11081
11098
  chatArgs.push("--system-prompt-file", chatClaudeMd);
11082
11099
  }
11083
- const envIntPath = join15(projDir, ".env.integrations");
11100
+ const envIntPath = join16(projDir, ".env.integrations");
11084
11101
  const childEnv = { ...process.env };
11085
11102
  if (existsSync9(envIntPath)) {
11086
11103
  try {
11087
- Object.assign(childEnv, parseEnvIntegrations(readFileSync13(envIntPath, "utf-8")));
11104
+ Object.assign(childEnv, parseEnvIntegrations(readFileSync14(envIntPath, "utf-8")));
11088
11105
  } catch {
11089
11106
  }
11090
11107
  }
@@ -11144,7 +11161,7 @@ ${escapeXml(msg.content)}
11144
11161
  log(`[direct-chat] Reply sent for '${agent.codeName}'`);
11145
11162
  } catch (err) {
11146
11163
  const errMsg = err instanceof Error ? err.message : String(err);
11147
- const errorId = createHash6("sha256").update(errMsg).digest("hex").slice(0, 12);
11164
+ const errorId = createHash8("sha256").update(errMsg).digest("hex").slice(0, 12);
11148
11165
  log(`[direct-chat] Failed to process message for '${agent.codeName}': error_id=${errorId} error=${errMsg.slice(0, 500)}`);
11149
11166
  try {
11150
11167
  await api.post("/host/direct-chat/reply", {
@@ -11680,8 +11697,8 @@ function parseMemoryFile(raw, fallbackName) {
11680
11697
  };
11681
11698
  }
11682
11699
  async function syncMemories(agent, configDir, log2) {
11683
- const projectDir = join15(configDir, agent.code_name, "project");
11684
- const memoryDir = join15(projectDir, "memory");
11700
+ const projectDir = join16(configDir, agent.code_name, "project");
11701
+ const memoryDir = join16(projectDir, "memory");
11685
11702
  const isFreshSync = pendingFreshMemorySync.has(agent.agent_id);
11686
11703
  if (isFreshSync) {
11687
11704
  log2(`[memory-sync] Fresh-sync requested for '${agent.code_name}' \u2014 pulling DB first`);
@@ -11699,8 +11716,8 @@ async function syncMemories(agent, configDir, log2) {
11699
11716
  for (const file of readdirSync5(memoryDir)) {
11700
11717
  if (!file.endsWith(".md")) continue;
11701
11718
  try {
11702
- const raw = readFileSync13(join15(memoryDir, file), "utf-8");
11703
- const fileHash = createHash6("sha256").update(raw).digest("hex").slice(0, 16);
11719
+ const raw = readFileSync14(join16(memoryDir, file), "utf-8");
11720
+ const fileHash = createHash8("sha256").update(raw).digest("hex").slice(0, 16);
11704
11721
  currentHashes.set(file, fileHash);
11705
11722
  if (prevHashes.get(file) === fileHash) continue;
11706
11723
  const parsed = parseMemoryFile(raw, file.replace(/\.md$/, ""));
@@ -11724,7 +11741,7 @@ async function syncMemories(agent, configDir, log2) {
11724
11741
  } catch (err) {
11725
11742
  for (const mem of changedMemories) {
11726
11743
  for (const [file] of currentHashes) {
11727
- const parsed = parseMemoryFile(readFileSync13(join15(memoryDir, file), "utf-8"), file.replace(/\.md$/, ""));
11744
+ const parsed = parseMemoryFile(readFileSync14(join16(memoryDir, file), "utf-8"), file.replace(/\.md$/, ""));
11728
11745
  if (parsed?.name === mem.name) currentHashes.delete(file);
11729
11746
  }
11730
11747
  }
@@ -11738,28 +11755,28 @@ async function syncMemories(agent, configDir, log2) {
11738
11755
  }
11739
11756
  async function downloadMemories(agent, memoryDir, log2, { force }) {
11740
11757
  const localFiles = existsSync9(memoryDir) ? readdirSync5(memoryDir).filter((f) => f.endsWith(".md")).sort() : [];
11741
- const localListHash = createHash6("sha256").update(localFiles.join(",")).digest("hex").slice(0, 16);
11758
+ const localListHash = createHash8("sha256").update(localFiles.join(",")).digest("hex").slice(0, 16);
11742
11759
  const prevLocalHash = lastLocalFileHash.get(agent.agent_id);
11743
11760
  const prevDownload = lastDownloadHash.get(agent.agent_id);
11744
11761
  try {
11745
11762
  const dbMemories = await api.post("/host/memories", {
11746
11763
  agent_id: agent.agent_id
11747
11764
  });
11748
- const responseHash = createHash6("sha256").update(JSON.stringify(dbMemories.memories ?? [])).digest("hex").slice(0, 16);
11765
+ const responseHash = createHash8("sha256").update(JSON.stringify(dbMemories.memories ?? [])).digest("hex").slice(0, 16);
11749
11766
  if (!force && prevDownload && prevLocalHash === localListHash && lastDownloadHash.get(agent.agent_id) === responseHash) {
11750
11767
  return true;
11751
11768
  }
11752
11769
  lastDownloadHash.set(agent.agent_id, responseHash);
11753
11770
  lastLocalFileHash.set(agent.agent_id, localListHash);
11754
11771
  if (dbMemories.memories?.length) {
11755
- mkdirSync4(memoryDir, { recursive: true });
11772
+ mkdirSync5(memoryDir, { recursive: true });
11756
11773
  let written = 0;
11757
11774
  let overwritten = 0;
11758
11775
  for (let i = 0; i < dbMemories.memories.length; i++) {
11759
11776
  const mem = dbMemories.memories[i];
11760
11777
  const rawSlug = mem.name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/(^-|-$)/g, "").slice(0, 60);
11761
11778
  const slug = rawSlug || `memory-${i}`;
11762
- const filePath = join15(memoryDir, `${slug}.md`);
11779
+ const filePath = join16(memoryDir, `${slug}.md`);
11763
11780
  const desired = `---
11764
11781
  name: ${JSON.stringify(mem.name)}
11765
11782
  type: ${mem.type}
@@ -11771,20 +11788,20 @@ ${mem.content}
11771
11788
  if (existsSync9(filePath)) {
11772
11789
  let existing = "";
11773
11790
  try {
11774
- existing = readFileSync13(filePath, "utf-8");
11791
+ existing = readFileSync14(filePath, "utf-8");
11775
11792
  } catch {
11776
11793
  }
11777
11794
  if (existing === desired) continue;
11778
- writeFileSync4(filePath, desired);
11795
+ writeFileSync5(filePath, desired);
11779
11796
  overwritten++;
11780
11797
  } else {
11781
- writeFileSync4(filePath, desired);
11798
+ writeFileSync5(filePath, desired);
11782
11799
  written++;
11783
11800
  }
11784
11801
  }
11785
11802
  if (written > 0 || overwritten > 0) {
11786
11803
  const updatedFiles = readdirSync5(memoryDir).filter((f) => f.endsWith(".md")).sort();
11787
- lastLocalFileHash.set(agent.agent_id, createHash6("sha256").update(updatedFiles.join(",")).digest("hex").slice(0, 16));
11804
+ lastLocalFileHash.set(agent.agent_id, createHash8("sha256").update(updatedFiles.join(",")).digest("hex").slice(0, 16));
11788
11805
  log2(`Memory download for '${agent.code_name}': wrote ${written} new, overwrote ${overwritten} stale`);
11789
11806
  }
11790
11807
  }
@@ -12046,7 +12063,7 @@ function startManager(opts) {
12046
12063
  try {
12047
12064
  const stateFile = getStateFile();
12048
12065
  if (existsSync9(stateFile)) {
12049
- const raw = readFileSync13(stateFile, "utf-8");
12066
+ const raw = readFileSync14(stateFile, "utf-8");
12050
12067
  const parsed = JSON.parse(raw);
12051
12068
  if (Array.isArray(parsed.agents)) {
12052
12069
  state6.agents = parsed.agents;
@@ -12067,7 +12084,7 @@ function startManager(opts) {
12067
12084
  log(`[startup] state rehydration failed (continuing with empty state): ${err.message}`);
12068
12085
  }
12069
12086
  log(
12070
- `[startup] worker pid=${process.pid} ppid=${process.ppid} node=${process.version} log=${join15(homedir8(), ".augmented", "manager.log")}`
12087
+ `[startup] worker pid=${process.pid} ppid=${process.ppid} node=${process.version} log=${join16(homedir9(), ".augmented", "manager.log")}`
12071
12088
  );
12072
12089
  deployMcpAssets();
12073
12090
  reapOrphanChannelMcps({ log });
@@ -12088,7 +12105,7 @@ async function reapOrphanedClaudePids() {
12088
12105
  const looksLikeClaude = (pid) => {
12089
12106
  if (process.platform !== "linux") return true;
12090
12107
  try {
12091
- const comm = readFileSync13(`/proc/${pid}/comm`, "utf-8").trim().toLowerCase();
12108
+ const comm = readFileSync14(`/proc/${pid}/comm`, "utf-8").trim().toLowerCase();
12092
12109
  return comm.includes("claude");
12093
12110
  } catch {
12094
12111
  return false;
@@ -12198,18 +12215,18 @@ function restartRunningChannelMcps(basenames) {
12198
12215
  }
12199
12216
  }
12200
12217
  function deployMcpAssets() {
12201
- const targetDir = join15(homedir8(), ".augmented", "_mcp");
12202
- mkdirSync4(targetDir, { recursive: true });
12203
- const moduleDir = dirname3(fileURLToPath(import.meta.url));
12218
+ const targetDir = join16(homedir9(), ".augmented", "_mcp");
12219
+ mkdirSync5(targetDir, { recursive: true });
12220
+ const moduleDir = dirname4(fileURLToPath(import.meta.url));
12204
12221
  let mcpSourceDir = "";
12205
12222
  let dir = moduleDir;
12206
12223
  for (let i = 0; i < 6; i++) {
12207
- const candidate = join15(dir, "dist", "mcp");
12208
- if (existsSync9(join15(candidate, "index.js"))) {
12224
+ const candidate = join16(dir, "dist", "mcp");
12225
+ if (existsSync9(join16(candidate, "index.js"))) {
12209
12226
  mcpSourceDir = candidate;
12210
12227
  break;
12211
12228
  }
12212
- const parent = dirname3(dir);
12229
+ const parent = dirname4(dir);
12213
12230
  if (parent === dir) break;
12214
12231
  dir = parent;
12215
12232
  }
@@ -12221,7 +12238,7 @@ function deployMcpAssets() {
12221
12238
  const fileHash = (p) => {
12222
12239
  try {
12223
12240
  if (!existsSync9(p)) return null;
12224
- return createHash6("sha256").update(readFileSync13(p)).digest("hex");
12241
+ return createHash8("sha256").update(readFileSync14(p)).digest("hex");
12225
12242
  } catch {
12226
12243
  return null;
12227
12244
  }
@@ -12248,8 +12265,8 @@ function deployMcpAssets() {
12248
12265
  // natural session restart.
12249
12266
  "augmented-admin.js"
12250
12267
  ]) {
12251
- const src = join15(mcpSourceDir, file);
12252
- const dst = join15(targetDir, file);
12268
+ const src = join16(mcpSourceDir, file);
12269
+ const dst = join16(targetDir, file);
12253
12270
  if (!existsSync9(src)) continue;
12254
12271
  const before = fileHash(dst);
12255
12272
  try {
@@ -12267,23 +12284,23 @@ function deployMcpAssets() {
12267
12284
  log(`[manager] Bundle(s) updated: ${changedBasenames.join(", ")} \u2014 signalling running instances to restart`);
12268
12285
  restartRunningChannelMcps(changedBasenames);
12269
12286
  }
12270
- const localMcpPath = join15(targetDir, "index.js");
12287
+ const localMcpPath = join16(targetDir, "index.js");
12271
12288
  try {
12272
- const agentsDir = join15(homedir8(), ".augmented", "agents");
12289
+ const agentsDir = join16(homedir9(), ".augmented", "agents");
12273
12290
  if (existsSync9(agentsDir)) {
12274
12291
  for (const entry of readdirSync5(agentsDir, { withFileTypes: true })) {
12275
12292
  if (!entry.isDirectory()) continue;
12276
12293
  for (const subdir of ["provision", "project"]) {
12277
- const mcpJsonPath = join15(agentsDir, entry.name, subdir, ".mcp.json");
12294
+ const mcpJsonPath = join16(agentsDir, entry.name, subdir, ".mcp.json");
12278
12295
  try {
12279
- const raw = readFileSync13(mcpJsonPath, "utf-8");
12296
+ const raw = readFileSync14(mcpJsonPath, "utf-8");
12280
12297
  if (!raw.includes("@integrity-labs/augmented-mcp")) continue;
12281
12298
  const mcpConfig = JSON.parse(raw);
12282
12299
  const augServer = mcpConfig.mcpServers?.["augmented"];
12283
12300
  if (!augServer) continue;
12284
12301
  augServer.command = "node";
12285
12302
  augServer.args = [localMcpPath];
12286
- writeFileSync4(mcpJsonPath, JSON.stringify(mcpConfig, null, 2));
12303
+ writeFileSync5(mcpJsonPath, JSON.stringify(mcpConfig, null, 2));
12287
12304
  log(`[manager] Patched ${entry.name}/${subdir}/.mcp.json: npx \u2192 node`);
12288
12305
  } catch {
12289
12306
  }