@integrity-labs/agt-cli 0.28.716 → 0.28.718

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.
Files changed (25) hide show
  1. package/dist/bin/agt.js +5 -5
  2. package/dist/{chunk-LHYYO4NY.js → chunk-7LH3SVAD.js} +124 -1
  3. package/dist/chunk-7LH3SVAD.js.map +1 -0
  4. package/dist/{chunk-OOYUWMTR.js → chunk-EEZHSNQ2.js} +4 -4
  5. package/dist/{chunk-ILDRNSOB.js → chunk-FNALM4HG.js} +120 -19
  6. package/dist/chunk-FNALM4HG.js.map +1 -0
  7. package/dist/{claude-pair-runtime-JK7GQU25.js → claude-pair-runtime-PDG74SAT.js} +2 -2
  8. package/dist/lib/manager-worker.js +535 -347
  9. package/dist/lib/manager-worker.js.map +1 -1
  10. package/dist/mcp/direct-chat-channel.js +123 -0
  11. package/dist/mcp/index.js +123 -0
  12. package/dist/mcp/origami.js +123 -0
  13. package/dist/mcp/slack-channel.js +123 -0
  14. package/dist/mcp/telegram-channel.js +132 -9
  15. package/dist/{persistent-session-DJSSEIR6.js → persistent-session-2AWYIUCX.js} +7 -3
  16. package/dist/{responsiveness-probe-A5335ORT.js → responsiveness-probe-JQS4WA2L.js} +3 -3
  17. package/dist/{session-auth-dead-KUYVUOK5.js → session-auth-dead-VBMZW4GG.js} +2 -2
  18. package/package.json +1 -1
  19. package/dist/chunk-ILDRNSOB.js.map +0 -1
  20. package/dist/chunk-LHYYO4NY.js.map +0 -1
  21. /package/dist/{chunk-OOYUWMTR.js.map → chunk-EEZHSNQ2.js.map} +0 -0
  22. /package/dist/{claude-pair-runtime-JK7GQU25.js.map → claude-pair-runtime-PDG74SAT.js.map} +0 -0
  23. /package/dist/{persistent-session-DJSSEIR6.js.map → persistent-session-2AWYIUCX.js.map} +0 -0
  24. /package/dist/{responsiveness-probe-A5335ORT.js.map → responsiveness-probe-JQS4WA2L.js.map} +0 -0
  25. /package/dist/{session-auth-dead-KUYVUOK5.js.map → session-auth-dead-VBMZW4GG.js.map} +0 -0
@@ -57,7 +57,7 @@ import {
57
57
  safeWriteJsonAtomic,
58
58
  setConfigHash,
59
59
  tripClass
60
- } from "../chunk-OOYUWMTR.js";
60
+ } from "../chunk-EEZHSNQ2.js";
61
61
  import {
62
62
  getProjectDir as getProjectDir2,
63
63
  getReadyTasks,
@@ -115,7 +115,7 @@ import {
115
115
  takeZombieDetection,
116
116
  toOpencodeModel,
117
117
  writeEgressAllowlist
118
- } from "../chunk-ILDRNSOB.js";
118
+ } from "../chunk-FNALM4HG.js";
119
119
  import {
120
120
  ACCOUNT_ENFORCEMENT_MARKER_FILENAME,
121
121
  AnchorSessionClient,
@@ -200,14 +200,14 @@ import {
200
200
  subagentActivityAgeSeconds,
201
201
  sumTranscriptUsageInWindow,
202
202
  transcriptActivityAgeSeconds
203
- } from "../chunk-LHYYO4NY.js";
203
+ } from "../chunk-7LH3SVAD.js";
204
204
  import {
205
205
  reapOrphanChannelMcps
206
206
  } from "../chunk-XWVM4KPK.js";
207
207
 
208
208
  // src/lib/manager-worker.ts
209
- import { createHash as createHash17 } from "crypto";
210
- import { readFileSync as readFileSync29, writeFileSync as writeFileSync15, mkdirSync as mkdirSync11, existsSync as existsSync16, rmSync as rmSync5, readdirSync as readdirSync9, statSync as statSync8, unlinkSync as unlinkSync6, renameSync as renameSync8, utimesSync } from "fs";
209
+ import { createHash as createHash18 } from "crypto";
210
+ import { readFileSync as readFileSync30, writeFileSync as writeFileSync16, mkdirSync as mkdirSync12, existsSync as existsSync17, rmSync as rmSync6, readdirSync as readdirSync10, statSync as statSync9, unlinkSync as unlinkSync6, renameSync as renameSync9, utimesSync as utimesSync2 } from "fs";
211
211
 
212
212
  // src/lib/atomic-file-replace.ts
213
213
  import { copyFileSync, renameSync, unlinkSync } from "fs";
@@ -233,7 +233,7 @@ function defaultUnique() {
233
233
 
234
234
  // src/lib/manager-worker.ts
235
235
  import { execFileSync as syncExecFile } from "child_process";
236
- import { join as join38, dirname as dirname10, delimiter as pathDelimiter } from "path";
236
+ import { join as join39, dirname as dirname10, delimiter as pathDelimiter } from "path";
237
237
  import { homedir as homedir17 } from "os";
238
238
  import { fileURLToPath } from "url";
239
239
 
@@ -1691,12 +1691,12 @@ function isPathInsideDir(candidate, dir) {
1691
1691
  return resolvedCandidate.startsWith(resolvedDir.endsWith(sep) ? resolvedDir : resolvedDir + sep);
1692
1692
  }
1693
1693
  function findMissingMcpBundles(mcpConfigPath, deps = {}) {
1694
- const existsSync17 = deps.existsSync ?? nodeExistsSync;
1695
- const readFileSync30 = deps.readFileSync ?? nodeReadFileSync;
1694
+ const existsSync18 = deps.existsSync ?? nodeExistsSync;
1695
+ const readFileSync31 = deps.readFileSync ?? nodeReadFileSync;
1696
1696
  const mcpDir = deps.mcpDir ?? getSharedMcpDir();
1697
1697
  let parsed;
1698
1698
  try {
1699
- parsed = JSON.parse(readFileSync30(mcpConfigPath, "utf-8"));
1699
+ parsed = JSON.parse(readFileSync31(mcpConfigPath, "utf-8"));
1700
1700
  } catch {
1701
1701
  return [];
1702
1702
  }
@@ -1716,7 +1716,7 @@ function findMissingMcpBundles(mcpConfigPath, deps = {}) {
1716
1716
  if (seenPaths.has(resolvedBundlePath)) continue;
1717
1717
  let present;
1718
1718
  try {
1719
- present = existsSync17(bundlePath);
1719
+ present = existsSync18(bundlePath);
1720
1720
  } catch {
1721
1721
  continue;
1722
1722
  }
@@ -5194,19 +5194,122 @@ function computeChannelConfigHash(input) {
5194
5194
  ).digest("hex");
5195
5195
  }
5196
5196
 
5197
- // src/lib/channel-hash-cache.ts
5198
- import { existsSync as existsSync6, readFileSync as readFileSync17, writeFileSync as writeFileSync8 } from "fs";
5197
+ // src/lib/knowledge-cache.ts
5198
+ import { createHash as createHash9 } from "crypto";
5199
+ import {
5200
+ existsSync as existsSync6,
5201
+ mkdirSync as mkdirSync6,
5202
+ readFileSync as readFileSync17,
5203
+ readdirSync as readdirSync5,
5204
+ renameSync as renameSync5,
5205
+ rmSync as rmSync3,
5206
+ statSync as statSync5,
5207
+ utimesSync,
5208
+ writeFileSync as writeFileSync8
5209
+ } from "fs";
5199
5210
  import { join as join23 } from "path";
5211
+ var KNOWLEDGE_FETCH_CHUNK = 100;
5212
+ var CACHE_TTL_MS = 30 * 24 * 60 * 60 * 1e3;
5213
+ var SWEEP_INTERVAL_MS = 24 * 60 * 60 * 1e3;
5214
+ var lastSweepAt = 0;
5215
+ function knowledgeHash(content) {
5216
+ return createHash9("sha256").update(content, "utf8").digest("hex");
5217
+ }
5218
+ function cachePath(cacheDir, hash) {
5219
+ return join23(cacheDir, hash);
5220
+ }
5221
+ function readCachedKnowledge(cacheDir, hash) {
5222
+ const path = cachePath(cacheDir, hash);
5223
+ try {
5224
+ const content = readFileSync17(path, "utf-8");
5225
+ try {
5226
+ const now = /* @__PURE__ */ new Date();
5227
+ utimesSync(path, now, now);
5228
+ } catch {
5229
+ }
5230
+ return content;
5231
+ } catch {
5232
+ return null;
5233
+ }
5234
+ }
5235
+ function writeCachedKnowledge(cacheDir, hash, content) {
5236
+ if (knowledgeHash(content) !== hash) return false;
5237
+ try {
5238
+ mkdirSync6(cacheDir, { recursive: true });
5239
+ const tmp = `${cachePath(cacheDir, hash)}.tmp-${process.pid}`;
5240
+ writeFileSync8(tmp, content, "utf-8");
5241
+ renameSync5(tmp, cachePath(cacheDir, hash));
5242
+ return true;
5243
+ } catch {
5244
+ return false;
5245
+ }
5246
+ }
5247
+ function sweepKnowledgeCache(cacheDir, now = Date.now()) {
5248
+ if (now - lastSweepAt < SWEEP_INTERVAL_MS) return;
5249
+ lastSweepAt = now;
5250
+ try {
5251
+ if (!existsSync6(cacheDir)) return;
5252
+ for (const name of readdirSync5(cacheDir)) {
5253
+ const path = join23(cacheDir, name);
5254
+ try {
5255
+ if (now - statSync5(path).mtimeMs > CACHE_TTL_MS) rmSync3(path, { force: true });
5256
+ } catch {
5257
+ }
5258
+ }
5259
+ } catch {
5260
+ }
5261
+ }
5262
+ async function resolveKnowledgeFromManifest(args) {
5263
+ const { manifest, cacheDir, delivery, fetchContents, log: log2 } = args;
5264
+ const meta = (e) => ({ title: e.title, slug: e.slug, scope: e.scope });
5265
+ if (delivery === "search") {
5266
+ sweepKnowledgeCache(cacheDir);
5267
+ return manifest.map((e) => ({ ...meta(e), content: null }));
5268
+ }
5269
+ const bodies = /* @__PURE__ */ new Map();
5270
+ const missing = [];
5271
+ for (const entry of manifest) {
5272
+ if (!entry.hash || bodies.has(entry.hash)) continue;
5273
+ const cached = readCachedKnowledge(cacheDir, entry.hash);
5274
+ if (cached !== null) bodies.set(entry.hash, cached);
5275
+ else if (!missing.includes(entry.hash)) missing.push(entry.hash);
5276
+ }
5277
+ if (missing.length > 0) {
5278
+ for (let i = 0; i < missing.length; i += KNOWLEDGE_FETCH_CHUNK) {
5279
+ const chunk2 = missing.slice(i, i + KNOWLEDGE_FETCH_CHUNK);
5280
+ try {
5281
+ for (const { hash, content } of await fetchContents(chunk2)) {
5282
+ if (!writeCachedKnowledge(cacheDir, hash, content)) {
5283
+ log2?.(`[knowledge] hash mismatch for ${hash} \u2014 dropping this poll`);
5284
+ continue;
5285
+ }
5286
+ bodies.set(hash, content);
5287
+ }
5288
+ } catch (err) {
5289
+ log2?.(`[knowledge] fetch failed for ${chunk2.length} entries: ${err.message}`);
5290
+ }
5291
+ }
5292
+ }
5293
+ sweepKnowledgeCache(cacheDir);
5294
+ return manifest.map((e) => ({
5295
+ ...meta(e),
5296
+ content: (e.hash ? bodies.get(e.hash) : void 0) ?? null
5297
+ }));
5298
+ }
5299
+
5300
+ // src/lib/channel-hash-cache.ts
5301
+ import { existsSync as existsSync7, readFileSync as readFileSync18, writeFileSync as writeFileSync9 } from "fs";
5302
+ import { join as join24 } from "path";
5200
5303
  var CACHE_FILENAME = "channel-hash-cache.json";
5201
5304
  function getChannelHashCacheFile(configDir) {
5202
- return join23(configDir, CACHE_FILENAME);
5305
+ return join24(configDir, CACHE_FILENAME);
5203
5306
  }
5204
5307
  function loadChannelHashCache(target, configDir) {
5205
5308
  const path = getChannelHashCacheFile(configDir);
5206
- if (!existsSync6(path)) return;
5309
+ if (!existsSync7(path)) return;
5207
5310
  let parsed;
5208
5311
  try {
5209
- parsed = JSON.parse(readFileSync17(path, "utf-8"));
5312
+ parsed = JSON.parse(readFileSync18(path, "utf-8"));
5210
5313
  } catch {
5211
5314
  return;
5212
5315
  }
@@ -5220,14 +5323,14 @@ function saveChannelHashCache(source, configDir) {
5220
5323
  const obj = {};
5221
5324
  for (const [key, value] of source) obj[key] = value;
5222
5325
  try {
5223
- writeFileSync8(path, JSON.stringify(obj, null, 2));
5326
+ writeFileSync9(path, JSON.stringify(obj, null, 2));
5224
5327
  } catch {
5225
5328
  }
5226
5329
  }
5227
5330
 
5228
5331
  // src/lib/sender-policy-baseline.ts
5229
- import { existsSync as existsSync7, readFileSync as readFileSync18 } from "fs";
5230
- import { join as join24 } from "path";
5332
+ import { existsSync as existsSync8, readFileSync as readFileSync19 } from "fs";
5333
+ import { join as join25 } from "path";
5231
5334
  var BASELINE_FILENAME = "sender-policy-baseline.json";
5232
5335
  var SENDER_POLICY_BASELINE_VERSION = 1;
5233
5336
  var BASELINE_CONCERNS = ["senderPolicy", "slackBehaviour", "msteamsBehaviour"];
@@ -5239,14 +5342,14 @@ function createDeliveryBaselineMaps() {
5239
5342
  };
5240
5343
  }
5241
5344
  function getSenderPolicyBaselineFile(configDir) {
5242
- return join24(configDir, BASELINE_FILENAME);
5345
+ return join25(configDir, BASELINE_FILENAME);
5243
5346
  }
5244
5347
  function loadSenderPolicyBaseline(target, configDir, log2) {
5245
5348
  const path = getSenderPolicyBaselineFile(configDir);
5246
- if (!existsSync7(path)) return;
5349
+ if (!existsSync8(path)) return;
5247
5350
  let parsed;
5248
5351
  try {
5249
- parsed = JSON.parse(readFileSync18(path, "utf-8"));
5352
+ parsed = JSON.parse(readFileSync19(path, "utf-8"));
5250
5353
  } catch (err) {
5251
5354
  log2?.(
5252
5355
  `[sender-policy] discarding corrupt ${BASELINE_FILENAME} (${err.message}) - restrictive-policy agents will take one fail-closed restart`
@@ -5295,8 +5398,8 @@ function saveSenderPolicyBaseline(source, configDir, log2) {
5295
5398
  }
5296
5399
 
5297
5400
  // src/lib/stuck-streak-store.ts
5298
- import { existsSync as existsSync8, readFileSync as readFileSync19 } from "fs";
5299
- import { join as join25 } from "path";
5401
+ import { existsSync as existsSync9, readFileSync as readFileSync20 } from "fs";
5402
+ import { join as join26 } from "path";
5300
5403
  var STORE_FILENAME = "stuck-streaks.json";
5301
5404
  var STUCK_STREAK_STORE_VERSION = 1;
5302
5405
  var STUCK_STREAK_CONCERNS = ["channelSync", "realtimeRebind"];
@@ -5304,7 +5407,7 @@ function createStuckStreakMaps() {
5304
5407
  return { channelSync: /* @__PURE__ */ new Map(), realtimeRebind: /* @__PURE__ */ new Map() };
5305
5408
  }
5306
5409
  function getStuckStreakStoreFile(configDir) {
5307
- return join25(configDir, STORE_FILENAME);
5410
+ return join26(configDir, STORE_FILENAME);
5308
5411
  }
5309
5412
  function isValidPersistedStreak(value) {
5310
5413
  if (!value || typeof value !== "object" || Array.isArray(value)) return false;
@@ -5343,10 +5446,10 @@ function buildStuckStreakPayload(source) {
5343
5446
  }
5344
5447
  function loadStuckStreaks(target, configDir, log2) {
5345
5448
  const path = getStuckStreakStoreFile(configDir);
5346
- if (!existsSync8(path)) return;
5449
+ if (!existsSync9(path)) return;
5347
5450
  let parsed;
5348
5451
  try {
5349
- parsed = JSON.parse(readFileSync19(path, "utf-8"));
5452
+ parsed = JSON.parse(readFileSync20(path, "utf-8"));
5350
5453
  } catch (err) {
5351
5454
  log2?.(
5352
5455
  `[stuck-streaks] discarding corrupt ${STORE_FILENAME} (${err.message}) \u2014 stuck-streak ages restart from zero and one spurious "recovered" close may follow`
@@ -5863,7 +5966,7 @@ function planGlobalSkillSync(globalSkills, prevIds, hashOf, knownHash, options)
5863
5966
  }
5864
5967
 
5865
5968
  // src/lib/manager/integration-skill-cache.ts
5866
- import { join as join26 } from "path";
5969
+ import { join as join27 } from "path";
5867
5970
  function integrationSkillHashKey(agentId, skillId) {
5868
5971
  return `plugin-skill:${agentId}:${skillId}`;
5869
5972
  }
@@ -5879,21 +5982,21 @@ function forgetIntegrationSkill(cache2, agentId, skillId) {
5879
5982
  function removeIntegrationSkillFolder(opts) {
5880
5983
  forgetIntegrationSkill(opts.cache, opts.agentId, opts.entry);
5881
5984
  for (const dir of opts.dirs) {
5882
- opts.removeDir(join26(dir, opts.entry));
5985
+ opts.removeDir(join27(dir, opts.entry));
5883
5986
  }
5884
5987
  }
5885
5988
 
5886
5989
  // src/lib/manager/managed-skill-manifest.ts
5887
- import { existsSync as existsSync9, mkdirSync as mkdirSync6, readFileSync as readFileSync20, writeFileSync as writeFileSync9 } from "fs";
5888
- import { dirname as dirname7, join as join27 } from "path";
5990
+ import { existsSync as existsSync10, mkdirSync as mkdirSync7, readFileSync as readFileSync21, writeFileSync as writeFileSync10 } from "fs";
5991
+ import { dirname as dirname7, join as join28 } from "path";
5889
5992
  var MANIFEST_VERSION = 1;
5890
5993
  function managedSkillManifestPath(agentRootDir) {
5891
- return join27(agentRootDir, "managed-skills.json");
5994
+ return join28(agentRootDir, "managed-skills.json");
5892
5995
  }
5893
5996
  function readManagedSkillManifest(path) {
5894
5997
  try {
5895
- if (!existsSync9(path)) return /* @__PURE__ */ new Set();
5896
- const parsed = JSON.parse(readFileSync20(path, "utf-8"));
5998
+ if (!existsSync10(path)) return /* @__PURE__ */ new Set();
5999
+ const parsed = JSON.parse(readFileSync21(path, "utf-8"));
5897
6000
  const ids = Array.isArray(parsed?.globalSkillIds) ? parsed.globalSkillIds : [];
5898
6001
  return new Set(ids.filter((id) => typeof id === "string" && id.length > 0));
5899
6002
  } catch {
@@ -5902,12 +6005,12 @@ function readManagedSkillManifest(path) {
5902
6005
  }
5903
6006
  function writeManagedSkillManifest(path, ids) {
5904
6007
  try {
5905
- mkdirSync6(dirname7(path), { recursive: true });
6008
+ mkdirSync7(dirname7(path), { recursive: true });
5906
6009
  const body = {
5907
6010
  version: MANIFEST_VERSION,
5908
6011
  globalSkillIds: [...ids].sort()
5909
6012
  };
5910
- writeFileSync9(path, JSON.stringify(body, null, 2));
6013
+ writeFileSync10(path, JSON.stringify(body, null, 2));
5911
6014
  } catch {
5912
6015
  }
5913
6016
  }
@@ -6019,8 +6122,8 @@ function resolveModelChain(refreshData) {
6019
6122
  }
6020
6123
 
6021
6124
  // src/lib/manager/claude-auth.ts
6022
- import { existsSync as existsSync10, rmSync as rmSync3 } from "fs";
6023
- import { join as join28 } from "path";
6125
+ import { existsSync as existsSync11, rmSync as rmSync4 } from "fs";
6126
+ import { join as join29 } from "path";
6024
6127
  import { homedir as homedir13 } from "os";
6025
6128
  async function applyClaudeAuthToEnv(childEnv, label) {
6026
6129
  const apiKey = getApiKey();
@@ -6033,12 +6136,12 @@ async function applyClaudeAuthToEnv(childEnv, label) {
6033
6136
  throw new Error("claude_auth_mode=api_key but /host/exchange returned no decrypted key");
6034
6137
  }
6035
6138
  childEnv.ANTHROPIC_API_KEY = exchange.anthropicApiKey;
6036
- const claudeDir = join28(homedir13(), ".claude");
6139
+ const claudeDir = join29(homedir13(), ".claude");
6037
6140
  for (const filename of [".credentials.json", "credentials.json"]) {
6038
- const p = join28(claudeDir, filename);
6039
- if (existsSync10(p)) {
6141
+ const p = join29(claudeDir, filename);
6142
+ if (existsSync11(p)) {
6040
6143
  try {
6041
- rmSync3(p, { force: true });
6144
+ rmSync4(p, { force: true });
6042
6145
  log(`[${label}] Removed ${p} (api_key mode \u2014 preventing OAuth fallback)`);
6043
6146
  } catch {
6044
6147
  }
@@ -6117,8 +6220,8 @@ function heartbeatRuntimeAuthFields(probeVerdict) {
6117
6220
  }
6118
6221
 
6119
6222
  // src/lib/manager/kanban/parsers.ts
6120
- import { existsSync as existsSync11, readFileSync as readFileSync21 } from "fs";
6121
- import { join as join29 } from "path";
6223
+ import { existsSync as existsSync12, readFileSync as readFileSync22 } from "fs";
6224
+ import { join as join30 } from "path";
6122
6225
  var STANDUP_TEMPLATES = /* @__PURE__ */ new Set(["daily-standup", "end-of-day-summary"]);
6123
6226
  var TASK_UPDATE_TEMPLATES = /* @__PURE__ */ new Set(["hourly-status", "task-update"]);
6124
6227
  var PLAN_TEMPLATES = /* @__PURE__ */ new Set(["morning-plan"]);
@@ -6270,12 +6373,12 @@ function getBuiltInSkillContent(skillId) {
6270
6373
  if (builtInSkillCache.has(skillId)) return builtInSkillCache.get(skillId);
6271
6374
  try {
6272
6375
  const candidates = [
6273
- join29(process.cwd(), "skills", skillId, "SKILL.md"),
6274
- join29(new URL(".", import.meta.url).pathname, "..", "..", "..", "..", "..", "..", "skills", skillId, "SKILL.md")
6376
+ join30(process.cwd(), "skills", skillId, "SKILL.md"),
6377
+ join30(new URL(".", import.meta.url).pathname, "..", "..", "..", "..", "..", "..", "skills", skillId, "SKILL.md")
6275
6378
  ];
6276
6379
  for (const candidate of candidates) {
6277
- if (existsSync11(candidate)) {
6278
- const content = readFileSync21(candidate, "utf-8");
6380
+ if (existsSync12(candidate)) {
6381
+ const content = readFileSync22(candidate, "utf-8");
6279
6382
  const files = [{ relativePath: "SKILL.md", content }];
6280
6383
  builtInSkillCache.set(skillId, files);
6281
6384
  return files;
@@ -6416,19 +6519,19 @@ function formatBoardForPrompt(items, template) {
6416
6519
  }
6417
6520
 
6418
6521
  // src/lib/manager/kanban/nudge-state-cache.ts
6419
- import { existsSync as existsSync12, readFileSync as readFileSync22, writeFileSync as writeFileSync10 } from "fs";
6420
- import { join as join30 } from "path";
6522
+ import { existsSync as existsSync13, readFileSync as readFileSync23, writeFileSync as writeFileSync11 } from "fs";
6523
+ import { join as join31 } from "path";
6421
6524
  var CACHE_FILENAME2 = "kanban-nudge-state.json";
6422
6525
  var KANBAN_NUDGE_STATE_VERSION = 1;
6423
6526
  function getKanbanNudgeStateFile(configDir) {
6424
- return join30(configDir, CACHE_FILENAME2);
6527
+ return join31(configDir, CACHE_FILENAME2);
6425
6528
  }
6426
6529
  function loadKanbanNudgeState(target, configDir) {
6427
6530
  const path = getKanbanNudgeStateFile(configDir);
6428
- if (!existsSync12(path)) return;
6531
+ if (!existsSync13(path)) return;
6429
6532
  let parsed;
6430
6533
  try {
6431
- parsed = JSON.parse(readFileSync22(path, "utf-8"));
6534
+ parsed = JSON.parse(readFileSync23(path, "utf-8"));
6432
6535
  } catch {
6433
6536
  return;
6434
6537
  }
@@ -6460,13 +6563,13 @@ function saveKanbanNudgeState(source, configDir) {
6460
6563
  const agents = {};
6461
6564
  for (const [codeName, state9] of source) agents[codeName] = state9;
6462
6565
  try {
6463
- writeFileSync10(path, JSON.stringify({ version: KANBAN_NUDGE_STATE_VERSION, agents }, null, 2));
6566
+ writeFileSync11(path, JSON.stringify({ version: KANBAN_NUDGE_STATE_VERSION, agents }, null, 2));
6464
6567
  } catch {
6465
6568
  }
6466
6569
  }
6467
6570
 
6468
6571
  // src/lib/manager/kanban/notify.ts
6469
- import { createHash as createHash9 } from "crypto";
6572
+ import { createHash as createHash10 } from "crypto";
6470
6573
  async function enqueueKanbanNotice(opts) {
6471
6574
  try {
6472
6575
  const res = await api.post(
@@ -6481,7 +6584,7 @@ async function enqueueKanbanNotice(opts) {
6481
6584
  return res.ok === true;
6482
6585
  } catch (err) {
6483
6586
  const errText = err instanceof Error ? err.message : String(err);
6484
- const errId = createHash9("sha256").update(errText).digest("hex").slice(0, 12);
6587
+ const errId = createHash10("sha256").update(errText).digest("hex").slice(0, 12);
6485
6588
  log(`[kanban] notice enqueue failed for agent_id=${opts.agentId} error_id=${errId}`);
6486
6589
  return false;
6487
6590
  }
@@ -6496,7 +6599,7 @@ async function cancelKanbanNotice(agentId) {
6496
6599
  return typeof res.cancelled === "number" ? res.cancelled : 0;
6497
6600
  } catch (err) {
6498
6601
  const errText = err instanceof Error ? err.message : String(err);
6499
- const errId = createHash9("sha256").update(errText).digest("hex").slice(0, 12);
6602
+ const errId = createHash10("sha256").update(errText).digest("hex").slice(0, 12);
6500
6603
  log(`[kanban] notice cancel failed for agent_id=${agentId} error_id=${errId}`);
6501
6604
  return null;
6502
6605
  }
@@ -6902,7 +7005,7 @@ function deriveScheduledTaskNotify(task) {
6902
7005
  }
6903
7006
 
6904
7007
  // src/lib/manager/scheduler/runs.ts
6905
- import { createHash as createHash10 } from "crypto";
7008
+ import { createHash as createHash11 } from "crypto";
6906
7009
  async function startRun(opts) {
6907
7010
  try {
6908
7011
  const res = await api.post(
@@ -6917,7 +7020,7 @@ async function startRun(opts) {
6917
7020
  };
6918
7021
  } catch (err) {
6919
7022
  const errText = err instanceof Error ? err.message : String(err);
6920
- const errId = createHash10("sha256").update(errText).digest("hex").slice(0, 12);
7023
+ const errId = createHash11("sha256").update(errText).digest("hex").slice(0, 12);
6921
7024
  log(`[runs] start failed for agent_id=${opts.agent_id} source_type=${opts.source_type} error_id=${errId}`);
6922
7025
  return { run_id: null, kanban_item_id: null };
6923
7026
  }
@@ -6956,7 +7059,7 @@ async function finishRun(runId, outcome, options = {}) {
6956
7059
  return;
6957
7060
  } catch (err) {
6958
7061
  const errText = err instanceof Error ? err.message : String(err);
6959
- const errId = createHash10("sha256").update(errText).digest("hex").slice(0, 12);
7062
+ const errId = createHash11("sha256").update(errText).digest("hex").slice(0, 12);
6960
7063
  const status = err instanceof ApiError ? err.status : 0;
6961
7064
  if (isRetryableFinishError(err) && attempt < maxRetries) {
6962
7065
  log(
@@ -6985,7 +7088,7 @@ async function fetchPriorScheduledRuns(agentId, taskId) {
6985
7088
  return rows.filter((r) => typeof r.output_text === "string" && r.output_text.length > 0).map((r) => ({ startedAt: r.started_at, output: r.output_text }));
6986
7089
  } catch (err) {
6987
7090
  const errText = err instanceof Error ? err.message : String(err);
6988
- const errId = createHash10("sha256").update(errText).digest("hex").slice(0, 12);
7091
+ const errId = createHash11("sha256").update(errText).digest("hex").slice(0, 12);
6989
7092
  log(`[runs] prior-runs lookup failed for task_id=${taskId} error_id=${errId}`);
6990
7093
  return [];
6991
7094
  }
@@ -7045,13 +7148,13 @@ function closeSessionRunForCode(codeName, outcome, reason) {
7045
7148
  }
7046
7149
 
7047
7150
  // src/lib/manager/scheduler/kanban-route.ts
7048
- import { createHash as createHash12 } from "crypto";
7049
- import { writeFileSync as writeFileSync11, renameSync as renameSync5, mkdirSync as mkdirSync7, readFileSync as readFileSync23, unlinkSync as unlinkSync3 } from "fs";
7151
+ import { createHash as createHash13 } from "crypto";
7152
+ import { writeFileSync as writeFileSync12, renameSync as renameSync6, mkdirSync as mkdirSync8, readFileSync as readFileSync24, unlinkSync as unlinkSync3 } from "fs";
7050
7153
  import { homedir as homedir14 } from "os";
7051
- import { join as join31, dirname as dirname8 } from "path";
7154
+ import { join as join32, dirname as dirname8 } from "path";
7052
7155
 
7053
7156
  // src/lib/manager/scheduler/notify.ts
7054
- import { createHash as createHash11 } from "crypto";
7157
+ import { createHash as createHash12 } from "crypto";
7055
7158
  async function enqueueScheduledTaskNotice(opts) {
7056
7159
  try {
7057
7160
  const res = await api.post(
@@ -7068,7 +7171,7 @@ async function enqueueScheduledTaskNotice(opts) {
7068
7171
  return res.ok === true;
7069
7172
  } catch (err) {
7070
7173
  const errText = err instanceof Error ? err.message : String(err);
7071
- const errId = createHash11("sha256").update(errText).digest("hex").slice(0, 12);
7174
+ const errId = createHash12("sha256").update(errText).digest("hex").slice(0, 12);
7072
7175
  log(
7073
7176
  `[scheduled-kanban] notice enqueue failed for agent_id=${opts.agentId} task_id=${opts.taskId} error_id=${errId}`
7074
7177
  );
@@ -7407,19 +7510,19 @@ function resolveScheduledSlackTarget(task) {
7407
7510
  }
7408
7511
  function stampScheduledTurnMarker(codeName, taskId, target) {
7409
7512
  try {
7410
- const file = join31(homedir14(), ".augmented", codeName, SCHEDULED_TURN_MARKER_FILENAME);
7513
+ const file = join32(homedir14(), ".augmented", codeName, SCHEDULED_TURN_MARKER_FILENAME);
7411
7514
  const marker = { ts: Date.now(), task_id: taskId, ...target ? { target } : {} };
7412
7515
  const tmp = `${file}.tmp`;
7413
- writeFileSync11(tmp, JSON.stringify(marker), "utf8");
7414
- renameSync5(tmp, file);
7516
+ writeFileSync12(tmp, JSON.stringify(marker), "utf8");
7517
+ renameSync6(tmp, file);
7415
7518
  } catch (err) {
7416
7519
  log(`[scheduled-kanban] scheduled-turn marker write failed for '${codeName}': ${err.message}`);
7417
7520
  }
7418
7521
  }
7419
7522
  function clearScheduledTurnMarkerForTask(codeName, taskId) {
7420
- const file = join31(homedir14(), ".augmented", codeName, SCHEDULED_TURN_MARKER_FILENAME);
7523
+ const file = join32(homedir14(), ".augmented", codeName, SCHEDULED_TURN_MARKER_FILENAME);
7421
7524
  try {
7422
- const raw = JSON.parse(readFileSync23(file, "utf8"));
7525
+ const raw = JSON.parse(readFileSync24(file, "utf8"));
7423
7526
  if (typeof raw?.task_id !== "string" || raw.task_id !== taskId) return;
7424
7527
  unlinkSync3(file);
7425
7528
  log(`[scheduled-kanban] scheduled-turn marker cleared for '${codeName}' (task ${taskId} complete)`);
@@ -7480,8 +7583,8 @@ async function routeScheduledTaskViaKanban(codeName, agentId, task, prompt, dura
7480
7583
  }
7481
7584
  try {
7482
7585
  const doorbell = directChatDoorbellPath(agentId, homedir14());
7483
- mkdirSync7(dirname8(doorbell), { recursive: true });
7484
- writeFileSync11(doorbell, String(Date.now()));
7586
+ mkdirSync8(dirname8(doorbell), { recursive: true });
7587
+ writeFileSync12(doorbell, String(Date.now()));
7485
7588
  } catch (err) {
7486
7589
  log(`[scheduled-kanban] doorbell ring failed for '${codeName}': ${err.message} (notice still queued)`);
7487
7590
  }
@@ -7547,24 +7650,24 @@ async function processClaudeTaskResult(codeName, agentId, templateId, rawOutput,
7547
7650
  const assertion = parseDeliverAssertion(rawOutput);
7548
7651
  if (!assertion.deliver) {
7549
7652
  const trimmed = (rawOutput ?? "").trim();
7550
- const outputHash = trimmed.length === 0 ? "empty" : createHash12("sha256").update(trimmed).digest("hex").slice(0, 12);
7653
+ const outputHash = trimmed.length === 0 ? "empty" : createHash13("sha256").update(trimmed).digest("hex").slice(0, 12);
7551
7654
  log(`[claude-scheduler] Suppressed by delivery_policy=conditional for '${codeName}' (template=${templateId}, task=${delivery?.taskId ?? "n/a"}) \u2014 ${assertion.vacuous ? "deliver marker had a vacuous reason" : "no deliver marker"}; output_len=${trimmed.length} output_hash=${outputHash}`);
7552
7655
  if (delivery?.mode === "announce" && delivery.to) {
7553
7656
  await reportDeliveryStatus(agentId, delivery.taskId, { status: "skipped", error_code: "SUPPRESSED_BY_POLICY" });
7554
7657
  }
7555
7658
  return { ok: true };
7556
7659
  }
7557
- const reasonHash = createHash12("sha256").update(assertion.reason ?? "").digest("hex").slice(0, 12);
7660
+ const reasonHash = createHash13("sha256").update(assertion.reason ?? "").digest("hex").slice(0, 12);
7558
7661
  log(`[claude-scheduler] Delivering conditional run for '${codeName}' (template=${templateId}, task=${delivery?.taskId ?? "n/a"}) \u2014 agent asserted a concrete trigger (reason_len=${(assertion.reason ?? "").length} reason_hash=${reasonHash})`);
7559
7662
  rawOutput = assertion.deliverable;
7560
7663
  }
7561
7664
  const classification = classifyOutput(rawOutput);
7562
7665
  if (classification.action === "suppress") {
7563
7666
  const trimmed = (rawOutput ?? "").trim();
7564
- const outputHash = trimmed.length === 0 ? "empty" : createHash12("sha256").update(trimmed).digest("hex").slice(0, 12);
7667
+ const outputHash = trimmed.length === 0 ? "empty" : createHash13("sha256").update(trimmed).digest("hex").slice(0, 12);
7565
7668
  log(`[claude-scheduler] Suppressing delivery for '${codeName}' (template=${templateId}, task=${delivery?.taskId ?? "n/a"}) \u2014 output_len=${trimmed.length} output_hash=${outputHash}`);
7566
7669
  if (classification.suppressedNotes) {
7567
- const notesHash = createHash12("sha256").update(classification.suppressedNotes).digest("hex").slice(0, 12);
7670
+ const notesHash = createHash13("sha256").update(classification.suppressedNotes).digest("hex").slice(0, 12);
7568
7671
  log(`[claude-scheduler] Suppressed notes for '${codeName}' (task=${delivery?.taskId ?? "n/a"}) \u2014 notes_len=${classification.suppressedNotes.length} notes_hash=${notesHash}`);
7569
7672
  }
7570
7673
  if (delivery?.mode === "announce" && delivery.to) {
@@ -7630,13 +7733,13 @@ async function processClaudeTaskResult(codeName, agentId, templateId, rawOutput,
7630
7733
  }
7631
7734
 
7632
7735
  // src/lib/manager/scheduler/execution.ts
7633
- import { createHash as createHash13 } from "crypto";
7736
+ import { createHash as createHash14 } from "crypto";
7634
7737
  import { homedir as homedir15 } from "os";
7635
- import { join as join33 } from "path";
7738
+ import { join as join34 } from "path";
7636
7739
 
7637
7740
  // src/lib/agent-serving-probe.ts
7638
- import { readFileSync as readFileSync24, readdirSync as readdirSync5, statSync as statSync5 } from "fs";
7639
- import { join as join32 } from "path";
7741
+ import { readFileSync as readFileSync25, readdirSync as readdirSync6, statSync as statSync6 } from "fs";
7742
+ import { join as join33 } from "path";
7640
7743
  var RATE_LIMIT_WINDOW_MS = 6 * 60 * 60 * 1e3;
7641
7744
  function probeRateLimit(args) {
7642
7745
  const now = args.now ?? /* @__PURE__ */ new Date();
@@ -7645,23 +7748,23 @@ function probeRateLimit(args) {
7645
7748
  const dir = args.transcriptDir ?? sessionTranscriptDir(args.projectDir);
7646
7749
  let entries;
7647
7750
  try {
7648
- entries = readdirSync5(dir);
7751
+ entries = readdirSync6(dir);
7649
7752
  } catch {
7650
7753
  return UNKNOWN_RATE_LIMIT;
7651
7754
  }
7652
7755
  let newest = UNKNOWN_RATE_LIMIT;
7653
7756
  for (const name of entries) {
7654
7757
  if (!name.endsWith(".jsonl")) continue;
7655
- const path = join32(dir, name);
7758
+ const path = join33(dir, name);
7656
7759
  try {
7657
- const st = statSync5(path);
7760
+ const st = statSync6(path);
7658
7761
  if (!st.isFile() || st.mtimeMs < startMs) continue;
7659
7762
  } catch {
7660
7763
  continue;
7661
7764
  }
7662
7765
  let content;
7663
7766
  try {
7664
- content = readFileSync24(path, "utf-8");
7767
+ content = readFileSync25(path, "utf-8");
7665
7768
  } catch {
7666
7769
  continue;
7667
7770
  }
@@ -7723,7 +7826,7 @@ function shouldLogUsageCapDeferral(site, codeName, limitedUntil) {
7723
7826
 
7724
7827
  // src/lib/manager/scheduler/execution.ts
7725
7828
  function claudePidFilePath() {
7726
- return join33(homedir15(), ".augmented", "manager-claude-pids.json");
7829
+ return join34(homedir15(), ".augmented", "manager-claude-pids.json");
7727
7830
  }
7728
7831
  var inFlightClaudePids = /* @__PURE__ */ new Map();
7729
7832
  function registerClaudeSpawn(record) {
@@ -7743,10 +7846,10 @@ function unregisterClaudeSpawn(pid) {
7743
7846
  }
7744
7847
  async function syncAndCheckClaudeScheduler(agent, tasks, boardItems, refreshData, durableScheduledNudge = false) {
7745
7848
  const codeName = agent.code_name;
7746
- const stableTasksHash = createHash13("sha256").update(JSON.stringify(tasks)).digest("hex").slice(0, 16);
7747
- const boardHash = boardItems.length > 0 ? createHash13("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";
7849
+ const stableTasksHash = createHash14("sha256").update(JSON.stringify(tasks)).digest("hex").slice(0, 16);
7850
+ const boardHash = boardItems.length > 0 ? createHash14("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";
7748
7851
  const resolvedModels = resolveModelChain(refreshData);
7749
- const modelsHash = createHash13("sha256").update(JSON.stringify(resolvedModels)).digest("hex").slice(0, 16);
7852
+ const modelsHash = createHash14("sha256").update(JSON.stringify(resolvedModels)).digest("hex").slice(0, 16);
7750
7853
  const combinedHash = `${stableTasksHash}:${boardHash}:${modelsHash}`;
7751
7854
  const prevHash = agentState.knownTasksHashes.get(agent.agent_id);
7752
7855
  if (combinedHash !== prevHash) {
@@ -7793,8 +7896,8 @@ async function syncAndCheckClaudeScheduler(agent, tasks, boardItems, refreshData
7793
7896
  }
7794
7897
 
7795
7898
  // src/lib/occupancy-gate.ts
7796
- import { closeSync as closeSync2, openSync as openSync2, readdirSync as readdirSync6, readSync as readSync2, statSync as statSync6 } from "fs";
7797
- import { join as join34 } from "path";
7899
+ import { closeSync as closeSync2, openSync as openSync2, readdirSync as readdirSync7, readSync as readSync2, statSync as statSync7 } from "fs";
7900
+ import { join as join35 } from "path";
7798
7901
  function rostersMeasuredZero(mode, attested, runtimeRunning) {
7799
7902
  return mode === "enforce" && attested && runtimeRunning;
7800
7903
  }
@@ -7808,7 +7911,7 @@ var brackets = /* @__PURE__ */ new Map();
7808
7911
  function readAlignedTail(path, tailBytes, maxAlignBytes) {
7809
7912
  let fd = null;
7810
7913
  try {
7811
- const size = statSync6(path).size;
7914
+ const size = statSync7(path).size;
7812
7915
  if (size <= 0) return { content: "", complete: true, truncated: false };
7813
7916
  fd = openSync2(path, "r");
7814
7917
  let readStart = Math.max(0, size - tailBytes);
@@ -7878,26 +7981,26 @@ function candidateTranscriptPaths(dir) {
7878
7981
  const paths = [];
7879
7982
  let top;
7880
7983
  try {
7881
- top = readdirSync6(dir);
7984
+ top = readdirSync7(dir);
7882
7985
  } catch {
7883
7986
  return { paths, complete: false };
7884
7987
  }
7885
7988
  let complete = true;
7886
7989
  for (const name of top) {
7887
7990
  if (name.endsWith(".jsonl")) {
7888
- paths.push(join34(dir, name));
7991
+ paths.push(join35(dir, name));
7889
7992
  continue;
7890
7993
  }
7891
- const subDir = join34(dir, name, "subagents");
7994
+ const subDir = join35(dir, name, "subagents");
7892
7995
  let subs;
7893
7996
  try {
7894
- subs = readdirSync6(subDir);
7997
+ subs = readdirSync7(subDir);
7895
7998
  } catch (err) {
7896
7999
  if (!isAbsentDirError(err)) complete = false;
7897
8000
  continue;
7898
8001
  }
7899
8002
  for (const sub of subs) {
7900
- if (sub.endsWith(".jsonl")) paths.push(join34(subDir, sub));
8003
+ if (sub.endsWith(".jsonl")) paths.push(join35(subDir, sub));
7901
8004
  }
7902
8005
  }
7903
8006
  return { paths, complete };
@@ -7952,7 +8055,7 @@ function collectQualifyingTurns(codeName, nowMs, opts = {}) {
7952
8055
  for (const path of paths) {
7953
8056
  let st;
7954
8057
  try {
7955
- st = statSync6(path);
8058
+ st = statSync7(path);
7956
8059
  } catch (err) {
7957
8060
  if (!isAbsentDirError(err)) complete = false;
7958
8061
  continue;
@@ -8058,7 +8161,7 @@ function qualifyBuckets(buckets, qualifying, mode, nowMs, neighbourhoodMs = DEFA
8058
8161
  }
8059
8162
 
8060
8163
  // src/lib/pane-occupancy-sampler.ts
8061
- import { statSync as statSync7 } from "fs";
8164
+ import { statSync as statSync8 } from "fs";
8062
8165
  var SAMPLE_INTERVAL_MS = 1e4;
8063
8166
  var IDLE_GAP_MS = 12e4;
8064
8167
  var POST_IDLE_CREDIT_MS = 6e4;
@@ -8072,7 +8175,7 @@ function hasFreshPaneObservation(codeName, nowMs, maxAgeMs = OBSERVATION_FRESH_M
8072
8175
  }
8073
8176
  function paneMtimeMs(codeName) {
8074
8177
  try {
8075
- return statSync7(paneLogPath(codeName)).mtimeMs;
8178
+ return statSync8(paneLogPath(codeName)).mtimeMs;
8076
8179
  } catch {
8077
8180
  return null;
8078
8181
  }
@@ -8124,7 +8227,7 @@ function stopPaneOccupancySampler() {
8124
8227
 
8125
8228
  // src/lib/pid-pressure-sampler.ts
8126
8229
  import { execFileSync as execFileSync2 } from "child_process";
8127
- import { existsSync as existsSync13, readFileSync as readFileSync25 } from "fs";
8230
+ import { existsSync as existsSync14, readFileSync as readFileSync26 } from "fs";
8128
8231
  var SAMPLE_INTERVAL_MS2 = 3e4;
8129
8232
  function warnFraction() {
8130
8233
  const raw = Number(process.env.AGT_PID_PRESSURE_WARN_FRACTION);
@@ -8137,7 +8240,7 @@ function configuredCeiling() {
8137
8240
  }
8138
8241
  function readTextReal(path) {
8139
8242
  try {
8140
- return readFileSync25(path, "utf-8");
8243
+ return readFileSync26(path, "utf-8");
8141
8244
  } catch {
8142
8245
  return null;
8143
8246
  }
@@ -8146,7 +8249,7 @@ var cgroupDirCache = /* @__PURE__ */ new Map();
8146
8249
  var resolveRetryAfter = /* @__PURE__ */ new Map();
8147
8250
  var RESOLVE_RETRY_BACKOFF_MS = 5 * 6e4;
8148
8251
  function resolveCgroupDirReal(codeName, deps = {}) {
8149
- const exists = deps.exists ?? existsSync13;
8252
+ const exists = deps.exists ?? existsSync14;
8150
8253
  const inspectId = deps.inspectId ?? inspectContainerId;
8151
8254
  const now = deps.now ?? Date.now;
8152
8255
  const cached = cgroupDirCache.get(codeName);
@@ -8264,7 +8367,7 @@ function stopPidPressureSampler() {
8264
8367
  }
8265
8368
 
8266
8369
  // src/lib/opencode-slack-ingest.ts
8267
- import { createHash as createHash14 } from "crypto";
8370
+ import { createHash as createHash15 } from "crypto";
8268
8371
 
8269
8372
  // ../../packages/core/dist/channels/slack-rich-text.js
8270
8373
  var MAX_DEPTH = 12;
@@ -9271,7 +9374,7 @@ function startSlackIngest(config2) {
9271
9374
  // src/lib/opencode-slack-ingest.ts
9272
9375
  var ingests = /* @__PURE__ */ new Map();
9273
9376
  function fingerprint(params) {
9274
- return createHash14("sha256").update(
9377
+ return createHash15("sha256").update(
9275
9378
  JSON.stringify({
9276
9379
  appToken: params.appToken,
9277
9380
  botToken: params.botToken,
@@ -9352,7 +9455,7 @@ function stopAllOpencodeSlackIngests(log2) {
9352
9455
  }
9353
9456
 
9354
9457
  // src/lib/manager/opencode-scheduler.ts
9355
- import { createHash as createHash15 } from "crypto";
9458
+ import { createHash as createHash16 } from "crypto";
9356
9459
  var MAX_OPENCODE_SCHED_CONCURRENCY = 2;
9357
9460
  var opencodeSchedulerStates = /* @__PURE__ */ new Map();
9358
9461
  var inFlightOpencodeTasks = /* @__PURE__ */ new Set();
@@ -9366,7 +9469,7 @@ function shouldDeliver(task, reply) {
9366
9469
  }
9367
9470
  async function syncAndCheckOpencodeScheduler(agent, tasks, refreshData) {
9368
9471
  const codeName = agent.code_name;
9369
- const tasksHash = createHash15("sha256").update(JSON.stringify(tasks)).digest("hex").slice(0, 16);
9472
+ const tasksHash = createHash16("sha256").update(JSON.stringify(tasks)).digest("hex").slice(0, 16);
9370
9473
  if (knownOpencodeTaskHashes.get(agent.agent_id) !== tasksHash) {
9371
9474
  const taskInputs = tasks.map((t) => buildSchedulerTaskInput(t));
9372
9475
  const state10 = syncTasksToScheduler(codeName, agent.agent_id, taskInputs);
@@ -9444,10 +9547,10 @@ async function fireOpencodeScheduledTask(agent, task) {
9444
9547
  }
9445
9548
 
9446
9549
  // src/lib/opencode-telegram-ingest.ts
9447
- import { createHash as createHash16 } from "crypto";
9448
- import { existsSync as existsSync14, mkdirSync as mkdirSync8, readFileSync as readFileSync26, renameSync as renameSync6, unlinkSync as unlinkSync4, writeFileSync as writeFileSync12 } from "fs";
9550
+ import { createHash as createHash17 } from "crypto";
9551
+ import { existsSync as existsSync15, mkdirSync as mkdirSync9, readFileSync as readFileSync27, renameSync as renameSync7, unlinkSync as unlinkSync4, writeFileSync as writeFileSync13 } from "fs";
9449
9552
  import { randomUUID } from "crypto";
9450
- import { join as join35 } from "path";
9553
+ import { join as join36 } from "path";
9451
9554
 
9452
9555
  // src/lib/telegram-ingest.ts
9453
9556
  import https2 from "https";
@@ -9980,7 +10083,7 @@ function anySignal(signals) {
9980
10083
  // src/lib/opencode-telegram-ingest.ts
9981
10084
  var ingests2 = /* @__PURE__ */ new Map();
9982
10085
  function fingerprint2(params) {
9983
- return createHash16("sha256").update(
10086
+ return createHash17("sha256").update(
9984
10087
  JSON.stringify({
9985
10088
  botToken: params.botToken,
9986
10089
  allowedChats: [...params.allowedChats].sort(),
@@ -9995,7 +10098,7 @@ function createFileOffsetStore(codeName, log2, currentBotId) {
9995
10098
  let filePath;
9996
10099
  try {
9997
10100
  dir = getFramework("opencode").getAgentDir(codeName);
9998
- filePath = join35(dir, "telegram-getupdates-offset-opencode.json");
10101
+ filePath = join36(dir, "telegram-getupdates-offset-opencode.json");
9999
10102
  } catch {
10000
10103
  dir = null;
10001
10104
  filePath = null;
@@ -10004,7 +10107,7 @@ function createFileOffsetStore(codeName, log2, currentBotId) {
10004
10107
  load() {
10005
10108
  if (!filePath) return 0;
10006
10109
  try {
10007
- const parsed = JSON.parse(readFileSync26(filePath, "utf-8"));
10110
+ const parsed = JSON.parse(readFileSync27(filePath, "utf-8"));
10008
10111
  if (currentBotId != null && typeof parsed?.bot_id === "number" && parsed.bot_id !== currentBotId) {
10009
10112
  log2(`[telegram-ingest:${codeName}] offset cursor belongs to a different bot; ignoring (bot swap)`);
10010
10113
  return 0;
@@ -10022,8 +10125,8 @@ function createFileOffsetStore(codeName, log2, currentBotId) {
10022
10125
  if (!filePath || !dir) return;
10023
10126
  const tmpPath = `${filePath}.${process.pid}.${randomUUID()}.tmp`;
10024
10127
  try {
10025
- mkdirSync8(dir, { recursive: true, mode: 448 });
10026
- writeFileSync12(
10128
+ mkdirSync9(dir, { recursive: true, mode: 448 });
10129
+ writeFileSync13(
10027
10130
  tmpPath,
10028
10131
  JSON.stringify({
10029
10132
  offset,
@@ -10033,11 +10136,11 @@ function createFileOffsetStore(codeName, log2, currentBotId) {
10033
10136
  }),
10034
10137
  { mode: 384 }
10035
10138
  );
10036
- renameSync6(tmpPath, filePath);
10139
+ renameSync7(tmpPath, filePath);
10037
10140
  } catch (err) {
10038
10141
  log2(`[telegram-ingest:${codeName}] offset persist failed: ${err instanceof Error ? err.message : String(err)}`);
10039
10142
  try {
10040
- if (existsSync14(tmpPath)) unlinkSync4(tmpPath);
10143
+ if (existsSync15(tmpPath)) unlinkSync4(tmpPath);
10041
10144
  } catch {
10042
10145
  }
10043
10146
  }
@@ -10274,24 +10377,24 @@ function partitionActionableByPoison(actionable, states, config2) {
10274
10377
  }
10275
10378
 
10276
10379
  // src/lib/restart-flags.ts
10277
- import { existsSync as existsSync15, mkdirSync as mkdirSync9, readdirSync as readdirSync7, readFileSync as readFileSync27, renameSync as renameSync7, rmSync as rmSync4, writeFileSync as writeFileSync13 } from "fs";
10380
+ import { existsSync as existsSync16, mkdirSync as mkdirSync10, readdirSync as readdirSync8, readFileSync as readFileSync28, renameSync as renameSync8, rmSync as rmSync5, writeFileSync as writeFileSync14 } from "fs";
10278
10381
  import { homedir as homedir16 } from "os";
10279
- import { join as join36 } from "path";
10382
+ import { join as join37 } from "path";
10280
10383
  import { randomUUID as randomUUID2 } from "crypto";
10281
10384
  function restartFlagsDir() {
10282
- return join36(homedir16(), ".augmented", "restart-flags");
10385
+ return join37(homedir16(), ".augmented", "restart-flags");
10283
10386
  }
10284
10387
  function flagPath(codeName) {
10285
- return join36(restartFlagsDir(), `${codeName}.flag`);
10388
+ return join37(restartFlagsDir(), `${codeName}.flag`);
10286
10389
  }
10287
10390
  function readRestartFlags() {
10288
10391
  const dir = restartFlagsDir();
10289
- if (!existsSync15(dir)) return [];
10392
+ if (!existsSync16(dir)) return [];
10290
10393
  const out = [];
10291
- for (const entry of readdirSync7(dir)) {
10394
+ for (const entry of readdirSync8(dir)) {
10292
10395
  if (!entry.endsWith(".flag")) continue;
10293
10396
  try {
10294
- const raw = readFileSync27(join36(dir, entry), "utf8");
10397
+ const raw = readFileSync28(join37(dir, entry), "utf8");
10295
10398
  const parsed = JSON.parse(raw);
10296
10399
  if (typeof parsed.codeName !== "string" || parsed.codeName.length === 0) {
10297
10400
  parsed.codeName = entry.replace(/\.flag$/, "");
@@ -10309,8 +10412,8 @@ function readRestartFlags() {
10309
10412
  }
10310
10413
  function deleteRestartFlag(codeName) {
10311
10414
  const path = flagPath(codeName);
10312
- if (existsSync15(path)) {
10313
- rmSync4(path, { force: true });
10415
+ if (existsSync16(path)) {
10416
+ rmSync5(path, { force: true });
10314
10417
  }
10315
10418
  }
10316
10419
 
@@ -10409,8 +10512,8 @@ async function sendError(flag, opts, text) {
10409
10512
  }
10410
10513
 
10411
10514
  // src/lib/restart-context.ts
10412
- import { readdirSync as readdirSync8, readFileSync as readFileSync28, writeFileSync as writeFileSync14, mkdirSync as mkdirSync10, unlinkSync as unlinkSync5 } from "fs";
10413
- import { dirname as dirname9, join as join37 } from "path";
10515
+ import { readdirSync as readdirSync9, readFileSync as readFileSync29, writeFileSync as writeFileSync15, mkdirSync as mkdirSync11, unlinkSync as unlinkSync5 } from "fs";
10516
+ import { dirname as dirname9, join as join38 } from "path";
10414
10517
  var SLACK_PENDING_INBOUND_DIRNAME = "slack-pending-inbound";
10415
10518
  var SLACK_RESTART_CONTEXT_DIRNAME = "slack-restart-context";
10416
10519
  var MAX_TOPIC_CHARS = 140;
@@ -10422,10 +10525,10 @@ function augmentedAgentDir(codeName) {
10422
10525
  return dirname9(getProjectDir(codeName));
10423
10526
  }
10424
10527
  function slackPendingInboundDir(codeName) {
10425
- return join37(augmentedAgentDir(codeName), SLACK_PENDING_INBOUND_DIRNAME);
10528
+ return join38(augmentedAgentDir(codeName), SLACK_PENDING_INBOUND_DIRNAME);
10426
10529
  }
10427
10530
  function slackRestartContextDir(codeName) {
10428
- return join37(augmentedAgentDir(codeName), SLACK_RESTART_CONTEXT_DIRNAME);
10531
+ return join38(augmentedAgentDir(codeName), SLACK_RESTART_CONTEXT_DIRNAME);
10429
10532
  }
10430
10533
  function sanitizeTopic(raw) {
10431
10534
  const cleaned = raw.replace(/\s+/g, " ").trim().replace(/[<>]/g, " ").replace(/\s+/g, " ").trim();
@@ -10460,14 +10563,14 @@ function computeRestartContextHints(markers, allTurns, nowMs, reconstruct = reco
10460
10563
  }
10461
10564
  function safeReaddir(dir) {
10462
10565
  try {
10463
- return readdirSync8(dir);
10566
+ return readdirSync9(dir);
10464
10567
  } catch {
10465
10568
  return [];
10466
10569
  }
10467
10570
  }
10468
10571
  function readStrandedMarker(path) {
10469
10572
  try {
10470
- const parsed = JSON.parse(readFileSync28(path, "utf-8"));
10573
+ const parsed = JSON.parse(readFileSync29(path, "utf-8"));
10471
10574
  if (typeof parsed.channel === "string" && typeof parsed.thread_ts === "string") {
10472
10575
  return { channel: parsed.channel, thread_ts: parsed.thread_ts };
10473
10576
  }
@@ -10476,8 +10579,8 @@ function readStrandedMarker(path) {
10476
10579
  return null;
10477
10580
  }
10478
10581
  function writeHintFile(path, dir, hint) {
10479
- mkdirSync10(dir, { recursive: true, mode: 448 });
10480
- writeFileSync14(path, JSON.stringify(hint), { mode: 384 });
10582
+ mkdirSync11(dir, { recursive: true, mode: 448 });
10583
+ writeFileSync15(path, JSON.stringify(hint), { mode: 384 });
10481
10584
  }
10482
10585
  function pruneHintsExcept(codeName, freshFilenames) {
10483
10586
  const ctxDir = slackRestartContextDir(codeName);
@@ -10485,7 +10588,7 @@ function pruneHintsExcept(codeName, freshFilenames) {
10485
10588
  if (!filename.endsWith(".json")) continue;
10486
10589
  if (freshFilenames.has(filename)) continue;
10487
10590
  try {
10488
- unlinkSync5(join37(ctxDir, filename));
10591
+ unlinkSync5(join38(ctxDir, filename));
10489
10592
  } catch {
10490
10593
  }
10491
10594
  }
@@ -10506,7 +10609,7 @@ function refreshSlackRestartContextHints(codeNames, opts = {}) {
10506
10609
  }
10507
10610
  const markers = [];
10508
10611
  for (const filename of markerFilenames.slice(0, cap)) {
10509
- const parsed = readStrandedMarker(join37(markerDir, filename));
10612
+ const parsed = readStrandedMarker(join38(markerDir, filename));
10510
10613
  if (parsed) markers.push({ filename, channel: parsed.channel, thread_ts: parsed.thread_ts });
10511
10614
  }
10512
10615
  if (markers.length === 0) {
@@ -10520,7 +10623,7 @@ function refreshSlackRestartContextHints(codeNames, opts = {}) {
10520
10623
  const freshFilenames = /* @__PURE__ */ new Set();
10521
10624
  for (const { filename, hint } of hints) {
10522
10625
  try {
10523
- writeHintFile(join37(ctxDir, filename), ctxDir, hint);
10626
+ writeHintFile(join38(ctxDir, filename), ctxDir, hint);
10524
10627
  freshFilenames.add(filename);
10525
10628
  } catch (err) {
10526
10629
  log2(`[restart-context] ${codeName}: hint write failed for ${filename}: ${err.message}`);
@@ -10538,13 +10641,58 @@ function refreshSlackRestartContextHints(codeNames, opts = {}) {
10538
10641
 
10539
10642
  // src/lib/persistent-session-stuck-tracker.ts
10540
10643
  var DEFAULT_STUCK_WARN_THRESHOLD = 3;
10644
+ var DEFAULT_SPAWN_LOOP_WARN_THRESHOLD = 3;
10541
10645
  var PersistentSessionStuckTracker = class {
10542
10646
  counts = /* @__PURE__ */ new Map();
10543
10647
  warned = /* @__PURE__ */ new Set();
10544
10648
  threshold;
10545
- constructor(threshold = DEFAULT_STUCK_WARN_THRESHOLD) {
10649
+ /**
10650
+ * ENG-9614 — the second streak, held separately because it answers a
10651
+ * DIFFERENT question and must not inherit the first one's reset rule.
10652
+ *
10653
+ * `counts` above resets whenever `spawnAttempted` is true, which is correct
10654
+ * for its own question (ENG-5116/Vigil: unhealthy and nobody even TRIED).
10655
+ * But it makes the tracker structurally blind to the inverse: the scratch/tmp
10656
+ * collision attempted a spawn on EVERY tick, so `counts` was deleted on every
10657
+ * tick, `shouldWarn` could never fire, and an agent looped unrecoverably for
10658
+ * 3m48s without this class emitting a single line.
10659
+ *
10660
+ * Folding both into one counter was considered and rejected - a shared
10661
+ * counter would have to pick one reset rule, and either choice makes the
10662
+ * other question unanswerable. Two questions, two counters.
10663
+ */
10664
+ spawnLoopCounts = /* @__PURE__ */ new Map();
10665
+ spawnLoopWarned = /* @__PURE__ */ new Set();
10666
+ spawnLoopThreshold;
10667
+ constructor(threshold = DEFAULT_STUCK_WARN_THRESHOLD, spawnLoopThreshold = DEFAULT_SPAWN_LOOP_WARN_THRESHOLD) {
10546
10668
  if (threshold < 1) throw new Error("stuck-tracker threshold must be >= 1");
10669
+ if (spawnLoopThreshold < 1) throw new Error("stuck-tracker spawn-loop threshold must be >= 1");
10547
10670
  this.threshold = threshold;
10671
+ this.spawnLoopThreshold = spawnLoopThreshold;
10672
+ }
10673
+ /**
10674
+ * Advance the spawn-loop streak for one tick.
10675
+ *
10676
+ * Counts only when a spawn was attempted AND the session is still unhealthy.
10677
+ * Health alone resets it - an agent that came up is not looping, however it
10678
+ * got there. A tick with no spawn attempt neither counts nor resets: that is
10679
+ * the OTHER failure, already owned by `counts`, and letting it clear this
10680
+ * streak would let the two shapes alternate and hide each other.
10681
+ */
10682
+ recordSpawnLoop(codeName, sessionHealthy, spawnAttempted) {
10683
+ if (sessionHealthy) {
10684
+ this.spawnLoopCounts.delete(codeName);
10685
+ this.spawnLoopWarned.delete(codeName);
10686
+ return { ticks: 0, shouldWarn: false };
10687
+ }
10688
+ if (!spawnAttempted) {
10689
+ return { ticks: this.spawnLoopCounts.get(codeName) ?? 0, shouldWarn: false };
10690
+ }
10691
+ const next = (this.spawnLoopCounts.get(codeName) ?? 0) + 1;
10692
+ this.spawnLoopCounts.set(codeName, next);
10693
+ const crossed = next >= this.spawnLoopThreshold && !this.spawnLoopWarned.has(codeName);
10694
+ if (crossed) this.spawnLoopWarned.add(codeName);
10695
+ return { ticks: next, shouldWarn: crossed };
10548
10696
  }
10549
10697
  /**
10550
10698
  * Record one tick for one agent. Returns whether the caller should log
@@ -10555,6 +10703,7 @@ var PersistentSessionStuckTracker = class {
10555
10703
  */
10556
10704
  record(input) {
10557
10705
  const { codeName, sessionHealthy, spawnAttempted } = input;
10706
+ const spawnLoop = this.recordSpawnLoop(codeName, sessionHealthy, spawnAttempted);
10558
10707
  const wasStuck = (this.counts.get(codeName) ?? 0) >= this.threshold;
10559
10708
  if (sessionHealthy || spawnAttempted) {
10560
10709
  this.counts.delete(codeName);
@@ -10562,7 +10711,9 @@ var PersistentSessionStuckTracker = class {
10562
10711
  return {
10563
10712
  consecutiveTicks: 0,
10564
10713
  shouldWarn: false,
10565
- recovered: wasStuck && wasWarned
10714
+ recovered: wasStuck && wasWarned,
10715
+ spawnLoopTicks: spawnLoop.ticks,
10716
+ shouldWarnSpawnLoop: spawnLoop.shouldWarn
10566
10717
  };
10567
10718
  }
10568
10719
  const next = (this.counts.get(codeName) ?? 0) + 1;
@@ -10572,17 +10723,25 @@ var PersistentSessionStuckTracker = class {
10572
10723
  return {
10573
10724
  consecutiveTicks: next,
10574
10725
  shouldWarn: crossed,
10575
- recovered: false
10726
+ recovered: false,
10727
+ spawnLoopTicks: spawnLoop.ticks,
10728
+ shouldWarnSpawnLoop: spawnLoop.shouldWarn
10576
10729
  };
10577
10730
  }
10578
10731
  /** Test/debug helper: peek at an agent's current streak. */
10579
10732
  peek(codeName) {
10580
10733
  return this.counts.get(codeName) ?? 0;
10581
10734
  }
10735
+ /** Test/debug helper: peek at an agent's current spawn-loop streak. */
10736
+ peekSpawnLoop(codeName) {
10737
+ return this.spawnLoopCounts.get(codeName) ?? 0;
10738
+ }
10582
10739
  /** Test helper: clear all state. */
10583
10740
  reset() {
10584
10741
  this.counts.clear();
10585
10742
  this.warned.clear();
10743
+ this.spawnLoopCounts.clear();
10744
+ this.spawnLoopWarned.clear();
10586
10745
  }
10587
10746
  };
10588
10747
 
@@ -11898,7 +12057,7 @@ var pendingDayRolloverReset = /* @__PURE__ */ new Set();
11898
12057
  var dayRolloverInboundHold = /* @__PURE__ */ new Map();
11899
12058
  var INBOUND_HOLD_EPISODE_GAP_MS = 12e4;
11900
12059
  async function channelInboundActivityAgeSecondsFor(codeName) {
11901
- const { newestPendingInboundActivityMtimeMs } = await import("../responsiveness-probe-A5335ORT.js");
12060
+ const { newestPendingInboundActivityMtimeMs } = await import("../responsiveness-probe-JQS4WA2L.js");
11902
12061
  const newest = newestPendingInboundActivityMtimeMs(dirname10(paneLogPath(codeName)));
11903
12062
  if (newest === null) return null;
11904
12063
  return Math.max(0, Math.floor((Date.now() - newest) / 1e3));
@@ -11998,7 +12157,7 @@ function performLazyDayRolloverReset(codeName, agentTimezone) {
11998
12157
  }
11999
12158
  function paneLogAgeSecondsFor(codeName) {
12000
12159
  try {
12001
- const mtimeMs = statSync8(paneLogPath(codeName)).mtimeMs;
12160
+ const mtimeMs = statSync9(paneLogPath(codeName)).mtimeMs;
12002
12161
  return Math.max(0, Math.floor((Date.now() - mtimeMs) / 1e3));
12003
12162
  } catch (err) {
12004
12163
  if (err?.code === "ENOENT") return null;
@@ -12148,15 +12307,15 @@ var runningChannelSecretHashes = /* @__PURE__ */ new Map();
12148
12307
  var sessionLaunchManagedStructure = /* @__PURE__ */ new Map();
12149
12308
  function projectMcpHash(_codeName, projectDir) {
12150
12309
  try {
12151
- const raw = readFileSync29(join38(projectDir, ".mcp.json"), "utf-8");
12152
- return createHash17("sha256").update(canonicalJson(JSON.parse(raw))).digest("hex");
12310
+ const raw = readFileSync30(join39(projectDir, ".mcp.json"), "utf-8");
12311
+ return createHash18("sha256").update(canonicalJson(JSON.parse(raw))).digest("hex");
12153
12312
  } catch {
12154
12313
  return null;
12155
12314
  }
12156
12315
  }
12157
12316
  function projectMcpKeys(_codeName, projectDir) {
12158
12317
  try {
12159
- const raw = readFileSync29(join38(projectDir, ".mcp.json"), "utf-8");
12318
+ const raw = readFileSync30(join39(projectDir, ".mcp.json"), "utf-8");
12160
12319
  const parsed = JSON.parse(raw);
12161
12320
  const servers = parsed.mcpServers;
12162
12321
  if (!servers || typeof servers !== "object") return /* @__PURE__ */ new Set();
@@ -12174,7 +12333,7 @@ function seedSessionLaunchBaselines(codeName, projectDir) {
12174
12333
  else runningMcpServerKeys.delete(codeName);
12175
12334
  let launchStructure = null;
12176
12335
  try {
12177
- const raw = readFileSync29(join38(projectDir, ".mcp.json"), "utf-8");
12336
+ const raw = readFileSync30(join39(projectDir, ".mcp.json"), "utf-8");
12178
12337
  launchStructure = managedMcpStructureHashFromFile(
12179
12338
  JSON.parse(raw),
12180
12339
  isManagedMcpServerKey
@@ -12300,7 +12459,7 @@ async function runAgentSessionToolBindProbes(agent, integrations, projectDir, op
12300
12459
  if (result && result.rebindCandidates.length > 0 && hostFlagStore().getBoolean("session-tool-rebind")) {
12301
12460
  let mcpJsonForRebind = null;
12302
12461
  try {
12303
- mcpJsonForRebind = JSON.parse(readFileSync29(join38(projectDir, ".mcp.json"), "utf-8"));
12462
+ mcpJsonForRebind = JSON.parse(readFileSync30(join39(projectDir, ".mcp.json"), "utf-8"));
12304
12463
  } catch {
12305
12464
  mcpJsonForRebind = null;
12306
12465
  }
@@ -12448,7 +12607,7 @@ function shouldInjectChannelSecrets(agentId) {
12448
12607
  function projectChannelSecretHash(projectDir) {
12449
12608
  try {
12450
12609
  const entries = parseEnvIntegrations(
12451
- readFileSync29(join38(projectDir, ".env.integrations"), "utf-8")
12610
+ readFileSync30(join39(projectDir, ".env.integrations"), "utf-8")
12452
12611
  );
12453
12612
  return channelSecretValueHash(entries, CHANNEL_SECRET_ENV_KEYS);
12454
12613
  } catch {
@@ -12546,7 +12705,7 @@ var agentRestartTimezoneInputs = /* @__PURE__ */ new Map();
12546
12705
  var lastVersionCheckAt = 0;
12547
12706
  var VERSION_CHECK_INTERVAL_MS = 5 * 60 * 1e3;
12548
12707
  var lastResponsivenessProbeAt = 0;
12549
- var agtCliVersion = true ? "0.28.716" : "dev";
12708
+ var agtCliVersion = true ? "0.28.718" : "dev";
12550
12709
  function resolveBrewPath(execFileSync3) {
12551
12710
  try {
12552
12711
  const out = execFileSync3("which", ["brew"], { timeout: 5e3 }).toString().trim();
@@ -12559,7 +12718,7 @@ function resolveBrewPath(execFileSync3) {
12559
12718
  "/usr/local/bin/brew"
12560
12719
  ];
12561
12720
  for (const path of fallbacks) {
12562
- if (existsSync16(path)) return path;
12721
+ if (existsSync17(path)) return path;
12563
12722
  }
12564
12723
  return null;
12565
12724
  }
@@ -12569,7 +12728,7 @@ function claudeBinaryInstalled(execFileSync3) {
12569
12728
  "/opt/homebrew/bin/claude",
12570
12729
  "/usr/local/bin/claude"
12571
12730
  ];
12572
- if (canonical.some((path) => existsSync16(path))) return true;
12731
+ if (canonical.some((path) => existsSync17(path))) return true;
12573
12732
  try {
12574
12733
  execFileSync3("which", ["claude"], { timeout: 5e3 });
12575
12734
  return true;
@@ -12879,8 +13038,8 @@ var MANAGED_SETTINGS_KEYS = ["channelsEnabled", "enableAllProjectMcpServers"];
12879
13038
  function ensureClaudeManagedSettings(path = claudeManagedSettingsPath()) {
12880
13039
  try {
12881
13040
  let settings = {};
12882
- if (existsSync16(path)) {
12883
- const raw = readFileSync29(path, "utf-8").trim();
13041
+ if (existsSync17(path)) {
13042
+ const raw = readFileSync30(path, "utf-8").trim();
12884
13043
  if (raw) {
12885
13044
  let parsed;
12886
13045
  try {
@@ -12897,8 +13056,8 @@ function ensureClaudeManagedSettings(path = claudeManagedSettingsPath()) {
12897
13056
  const missing = MANAGED_SETTINGS_KEYS.filter((key) => settings[key] !== true);
12898
13057
  if (missing.length === 0) return "ok";
12899
13058
  for (const key of missing) settings[key] = true;
12900
- mkdirSync11(dirname10(path), { recursive: true });
12901
- writeFileSync15(path, `${JSON.stringify(settings, null, 2)}
13059
+ mkdirSync12(dirname10(path), { recursive: true });
13060
+ writeFileSync16(path, `${JSON.stringify(settings, null, 2)}
12902
13061
  `);
12903
13062
  log(`[managed-settings] set ${missing.map((k) => `${k}:true`).join(", ")} in ${path} (ENG-5786 unblocks Claude Code channels; ENG-9223 pre-approves project MCP servers so a headless session never freezes on the trust prompt)`);
12904
13063
  return "ok";
@@ -12936,7 +13095,7 @@ async function ensureOpencodeBinary() {
12936
13095
  try {
12937
13096
  const prefix = execFileSync3("npm", ["prefix", "-g"], { encoding: "utf-8", timeout: 1e4 }).trim();
12938
13097
  if (prefix) {
12939
- const npmBin = join38(prefix, "bin");
13098
+ const npmBin = join39(prefix, "bin");
12940
13099
  const current = (process.env.PATH ?? "").split(pathDelimiter);
12941
13100
  if (!current.includes(npmBin)) {
12942
13101
  process.env.PATH = [npmBin, ...current.filter(Boolean)].join(pathDelimiter);
@@ -12997,7 +13156,7 @@ async function ensureFrameworkBinary(frameworkId) {
12997
13156
  if (!process.env.PATH?.split(":").includes(brewBinDir)) {
12998
13157
  process.env.PATH = `${brewBinDir}:${process.env.PATH ?? ""}`;
12999
13158
  }
13000
- if (existsSync16("/home/linuxbrew/.linuxbrew/bin/claude")) {
13159
+ if (existsSync17("/home/linuxbrew/.linuxbrew/bin/claude")) {
13001
13160
  log("Claude Code installed successfully");
13002
13161
  } else {
13003
13162
  log("Claude Code install completed but binary not found at expected path \u2014 check brew logs");
@@ -13053,7 +13212,7 @@ ${r.stderr}`;
13053
13212
  }
13054
13213
  var UPDATE_CHECK_INTERVAL_MS = 5 * 60 * 1e3;
13055
13214
  function selfUpdateAppliedMarkerPath() {
13056
- return join38(homedir17(), ".augmented", ".last-self-update-applied");
13215
+ return join39(homedir17(), ".augmented", ".last-self-update-applied");
13057
13216
  }
13058
13217
  var selfUpdateUpToDateLogged = false;
13059
13218
  var selfUpdatePinnedLogged = false;
@@ -13104,7 +13263,7 @@ async function checkAndUpdateCli(opts) {
13104
13263
  const isNpmGlobal = !isBrewFormula && resolvedPath.includes("node_modules");
13105
13264
  if (!isBrewFormula && !isNpmGlobal) return "noop";
13106
13265
  const { readFileSync: readF, writeFileSync: writeF } = await import("fs");
13107
- const markerPath = join38(homedir17(), ".augmented", ".last-update-check");
13266
+ const markerPath = join39(homedir17(), ".augmented", ".last-update-check");
13108
13267
  if (!force) {
13109
13268
  try {
13110
13269
  const lastCheck = parseInt(readF(markerPath, "utf-8").trim(), 10);
@@ -13597,14 +13756,14 @@ async function checkClaudeAuth() {
13597
13756
  }
13598
13757
  var evalEmptyMcpConfigPath = null;
13599
13758
  function ensureEvalEmptyMcpConfig() {
13600
- if (evalEmptyMcpConfigPath && existsSync16(evalEmptyMcpConfigPath)) return evalEmptyMcpConfigPath;
13601
- const dir = join38(homedir17(), ".augmented");
13759
+ if (evalEmptyMcpConfigPath && existsSync17(evalEmptyMcpConfigPath)) return evalEmptyMcpConfigPath;
13760
+ const dir = join39(homedir17(), ".augmented");
13602
13761
  try {
13603
- mkdirSync11(dir, { recursive: true });
13762
+ mkdirSync12(dir, { recursive: true });
13604
13763
  } catch {
13605
13764
  }
13606
- const p = join38(dir, ".eval-empty-mcp.json");
13607
- writeFileSync15(p, JSON.stringify({ mcpServers: {} }));
13765
+ const p = join39(dir, ".eval-empty-mcp.json");
13766
+ writeFileSync16(p, JSON.stringify({ mcpServers: {} }));
13608
13767
  evalEmptyMcpConfigPath = p;
13609
13768
  return p;
13610
13769
  }
@@ -13698,10 +13857,10 @@ function resolveConversationEvalBackend() {
13698
13857
  return conversationEvalBackend;
13699
13858
  }
13700
13859
  function getStateFile() {
13701
- return join38(config?.configDir ?? join38(process.env["HOME"] ?? "/tmp", ".augmented"), "manager-state.json");
13860
+ return join39(config?.configDir ?? join39(process.env["HOME"] ?? "/tmp", ".augmented"), "manager-state.json");
13702
13861
  }
13703
13862
  function channelHashCacheDir() {
13704
- return config?.configDir ?? join38(process.env["HOME"] ?? "/tmp", ".augmented");
13863
+ return config?.configDir ?? join39(process.env["HOME"] ?? "/tmp", ".augmented");
13705
13864
  }
13706
13865
  function loadChannelHashCache2() {
13707
13866
  loadChannelHashCache(agentState.knownChannelConfigHashes, channelHashCacheDir());
@@ -13906,7 +14065,7 @@ function removeDeliveryBaselineEntries(agentId) {
13906
14065
  var _channelQuarantineStore = null;
13907
14066
  function channelQuarantineStore() {
13908
14067
  if (!_channelQuarantineStore) {
13909
- const dir = config?.configDir ?? join38(process.env["HOME"] ?? "/tmp", ".augmented");
14068
+ const dir = config?.configDir ?? join39(process.env["HOME"] ?? "/tmp", ".augmented");
13910
14069
  _channelQuarantineStore = new ChannelQuarantineStore(defaultQuarantinePath(dir));
13911
14070
  }
13912
14071
  return _channelQuarantineStore;
@@ -13922,12 +14081,12 @@ function claudeMdSizeFor(codeName) {
13922
14081
  }
13923
14082
  function forwardedToolsFor(codeName) {
13924
14083
  if (!config?.configDir) return null;
13925
- return readForwardedToolsReport(join38(config.configDir, codeName));
14084
+ return readForwardedToolsReport(join39(config.configDir, codeName));
13926
14085
  }
13927
14086
  var _hostFlagStore = null;
13928
14087
  function hostFlagStore() {
13929
14088
  if (!_hostFlagStore) {
13930
- const dir = config?.configDir ?? join38(process.env["HOME"] ?? "/tmp", ".augmented");
14089
+ const dir = config?.configDir ?? join39(process.env["HOME"] ?? "/tmp", ".augmented");
13931
14090
  _hostFlagStore = new HostFlagStore({ cachePath: defaultFlagsCachePath(dir), log });
13932
14091
  }
13933
14092
  return _hostFlagStore;
@@ -14000,13 +14159,13 @@ function parseSkillFrontmatter(content) {
14000
14159
  return out;
14001
14160
  }
14002
14161
  async function refreshSkillsIndexInClaudeMd(configDir, codeName, log2) {
14003
- const { readdirSync: readdirSync10, readFileSync: rfs, existsSync: ex, writeFileSync: writeFileSync16 } = await import("fs");
14004
- const skillsDir = join38(configDir, codeName, "project", ".claude", "skills");
14005
- const claudeMdPath = join38(configDir, codeName, "project", "CLAUDE.md");
14162
+ const { readdirSync: readdirSync11, readFileSync: rfs, existsSync: ex, writeFileSync: writeFileSync17 } = await import("fs");
14163
+ const skillsDir = join39(configDir, codeName, "project", ".claude", "skills");
14164
+ const claudeMdPath = join39(configDir, codeName, "project", "CLAUDE.md");
14006
14165
  if (!ex(skillsDir) || !ex(claudeMdPath)) return;
14007
14166
  const entries = [];
14008
- for (const dir of readdirSync10(skillsDir).sort()) {
14009
- const skillFile = join38(skillsDir, dir, "SKILL.md");
14167
+ for (const dir of readdirSync11(skillsDir).sort()) {
14168
+ const skillFile = join39(skillsDir, dir, "SKILL.md");
14010
14169
  if (!ex(skillFile)) continue;
14011
14170
  try {
14012
14171
  const { name, description } = parseSkillFrontmatter(rfs(skillFile, "utf-8"));
@@ -14050,7 +14209,7 @@ ${SKILLS_INDEX_END}`;
14050
14209
  next = current.trimEnd() + "\n\n" + section + "\n";
14051
14210
  }
14052
14211
  if (next !== current) {
14053
- writeFileSync16(claudeMdPath, next, "utf-8");
14212
+ writeFileSync17(claudeMdPath, next, "utf-8");
14054
14213
  log2(
14055
14214
  injectSkillList ? `Refreshed skills index in CLAUDE.md for '${codeName}' (${entries.length} skills)` : `Refreshed CLAUDE.md managed block for '${codeName}' (skill list suppressed by claude-md-skills-index=false; ${entries.length} skills on disk)`
14056
14215
  );
@@ -14073,7 +14232,7 @@ function flushRestartedAgentDiagnostics(hostId, codeNames) {
14073
14232
  if (codeNames.length === 0) return;
14074
14233
  void (async () => {
14075
14234
  try {
14076
- const { collectDiagnostics } = await import("../persistent-session-DJSSEIR6.js");
14235
+ const { collectDiagnostics } = await import("../persistent-session-2AWYIUCX.js");
14077
14236
  await api.post("/host/heartbeat", {
14078
14237
  host_id: hostId,
14079
14238
  agent_diagnostics: collectDiagnostics(codeNames, quarantineEntriesFor, claudeMdSizeFor, spawnOutcomeForDiagnostics, pidPressureFor, forwardedToolsFor)
@@ -14191,7 +14350,7 @@ async function pollCycleInner() {
14191
14350
  }
14192
14351
  try {
14193
14352
  const { detectHostSecurity } = await import("../host-security-6PDFG7F5.js");
14194
- const { collectDiagnostics } = await import("../persistent-session-DJSSEIR6.js");
14353
+ const { collectDiagnostics } = await import("../persistent-session-2AWYIUCX.js");
14195
14354
  const diagCodeNames = [...agentState.persistentSessionAgents];
14196
14355
  const agentDiagnostics = diagCodeNames.length > 0 ? collectDiagnostics(diagCodeNames, quarantineEntriesFor, claudeMdSizeFor, spawnOutcomeForDiagnostics, pidPressureFor, forwardedToolsFor) : void 0;
14197
14356
  let tailscaleHostname;
@@ -14221,7 +14380,7 @@ async function pollCycleInner() {
14221
14380
  claudeAuth = await detectClaudeAuth();
14222
14381
  } catch (err) {
14223
14382
  const errText = err instanceof Error ? err.message : String(err);
14224
- const errId = createHash17("sha256").update(errText).digest("hex").slice(0, 12);
14383
+ const errId = createHash18("sha256").update(errText).digest("hex").slice(0, 12);
14225
14384
  log(`Claude auth detection failed (error_id=${errId})`);
14226
14385
  }
14227
14386
  const hostHasClaudeCode = state8.agents.some(
@@ -14360,7 +14519,7 @@ async function pollCycleInner() {
14360
14519
  collectPanelessActivityProbes,
14361
14520
  getResponsivenessIntervalMs,
14362
14521
  occupancyQualificationClassifications
14363
- } = await import("../responsiveness-probe-A5335ORT.js");
14522
+ } = await import("../responsiveness-probe-JQS4WA2L.js");
14364
14523
  const probeIntervalMs = getResponsivenessIntervalMs();
14365
14524
  if (now - lastResponsivenessProbeAt > probeIntervalMs) {
14366
14525
  const probeCodeNames = [...agentState.persistentSessionAgents];
@@ -14470,7 +14629,7 @@ async function pollCycleInner() {
14470
14629
  collectResponsivenessProbes,
14471
14630
  livePendingInboundOldestAgeSeconds,
14472
14631
  parkPendingInbound
14473
- } = await import("../responsiveness-probe-A5335ORT.js");
14632
+ } = await import("../responsiveness-probe-JQS4WA2L.js");
14474
14633
  const { getProjectDir: wedgeProjectDir } = await import("../scheduler-engine-NDP36U7O.js");
14475
14634
  const wedgeNow = /* @__PURE__ */ new Date();
14476
14635
  const liveAgents = agentState.persistentSessionAgents;
@@ -14559,13 +14718,13 @@ async function pollCycleInner() {
14559
14718
  );
14560
14719
  if (hostFlagStore().getBoolean("wedge-transient-notice")) {
14561
14720
  try {
14562
- const paneTail = readFileSync29(paneLogPath(codeName), "utf8").slice(-65536);
14721
+ const paneTail = readFileSync30(paneLogPath(codeName), "utf8").slice(-65536);
14563
14722
  const transient = detectTransientApiErrorInLog(paneTail);
14564
14723
  if (transient) {
14565
- const wedgeHome = join38(homedir17(), ".augmented", codeName);
14566
- if (existsSync16(wedgeHome)) {
14724
+ const wedgeHome = join39(homedir17(), ".augmented", codeName);
14725
+ if (existsSync17(wedgeHome)) {
14567
14726
  atomicWriteFileSync(
14568
- join38(wedgeHome, "watchdog-give-up.json"),
14727
+ join39(wedgeHome, "watchdog-give-up.json"),
14569
14728
  JSON.stringify({
14570
14729
  gave_up_at: wedgeNow.toISOString(),
14571
14730
  reason: "transient_overload"
@@ -14626,7 +14785,7 @@ async function pollCycleInner() {
14626
14785
  }
14627
14786
  try {
14628
14787
  const { scrapeMcpFailedBannerCount } = await import("../pane-mcp-banner-scraper-JA437JIB.js");
14629
- const { probeSessionAuth } = await import("../session-auth-dead-KUYVUOK5.js");
14788
+ const { probeSessionAuth } = await import("../session-auth-dead-VBMZW4GG.js");
14630
14789
  const observations = [];
14631
14790
  const pendingCacheCommits = [];
14632
14791
  const modelApiErrorReportingOn = hostFlagStore().getBoolean("model-api-error-reporting");
@@ -14881,7 +15040,7 @@ async function pollCycleInner() {
14881
15040
  `[drain-flush] FAILED for '${prev.codeName}': ${err.message} \u2014 proceeding to teardown; this session was NOT shipped (ENG-9491)`
14882
15041
  );
14883
15042
  }
14884
- const agentDir = join38(adapter.getAgentDir(prev.codeName), "provision");
15043
+ const agentDir = join39(adapter.getAgentDir(prev.codeName), "provision");
14885
15044
  await cleanupAgentFiles(prev.codeName, agentDir);
14886
15045
  clearAgentCaches(prev.agentId, prev.codeName);
14887
15046
  }
@@ -14968,10 +15127,10 @@ async function pollCycleInner() {
14968
15127
  // pending-inbound marker. Best-effort: a write failure is logged by
14969
15128
  // the watchdog, never fails the poll cycle.
14970
15129
  signalGiveUp: (codeName) => {
14971
- const dir = join38(homedir17(), ".augmented", codeName);
14972
- if (!existsSync16(dir)) return;
15130
+ const dir = join39(homedir17(), ".augmented", codeName);
15131
+ if (!existsSync17(dir)) return;
14973
15132
  atomicWriteFileSync(
14974
- join38(dir, "watchdog-give-up.json"),
15133
+ join39(dir, "watchdog-give-up.json"),
14975
15134
  JSON.stringify({ gave_up_at: (/* @__PURE__ */ new Date()).toISOString() })
14976
15135
  );
14977
15136
  },
@@ -14990,9 +15149,9 @@ async function pollCycleInner() {
14990
15149
  // parser elsewhere can only reconstruct an hour (ENG-8901).
14991
15150
  signalUsageLimit: (codeName, resetsHint) => {
14992
15151
  const dir = getFramework("claude-code").getAgentDir(codeName);
14993
- if (!existsSync16(dir)) return;
15152
+ if (!existsSync17(dir)) return;
14994
15153
  atomicWriteFileSync(
14995
- join38(dir, "watchdog-give-up.json"),
15154
+ join39(dir, "watchdog-give-up.json"),
14996
15155
  JSON.stringify({
14997
15156
  gave_up_at: (/* @__PURE__ */ new Date()).toISOString(),
14998
15157
  reason: "usage_limit",
@@ -15254,7 +15413,7 @@ async function processAgent(agent, agentStates, managedToolkits) {
15254
15413
  }
15255
15414
  const now = (/* @__PURE__ */ new Date()).toISOString();
15256
15415
  const adapter = resolveAgentFramework(agent.code_name);
15257
- let agentDir = join38(adapter.getAgentDir(agent.code_name), "provision");
15416
+ let agentDir = join39(adapter.getAgentDir(agent.code_name), "provision");
15258
15417
  if (agent.status === "draft" || agent.status === "paused") {
15259
15418
  forgetChannelSyncState(agent.agent_id);
15260
15419
  if (previousKnownStatus !== agent.status) {
@@ -15295,7 +15454,7 @@ async function processAgent(agent, agentStates, managedToolkits) {
15295
15454
  const residuals = {
15296
15455
  gatewayRunning: false,
15297
15456
  portAllocated: false,
15298
- provisionDirExists: existsSync16(agentDir)
15457
+ provisionDirExists: existsSync17(agentDir)
15299
15458
  };
15300
15459
  if (!hasRevokedResiduals(residuals)) {
15301
15460
  agentStates.push({
@@ -15383,8 +15542,28 @@ async function processAgent(agent, agentStates, managedToolkits) {
15383
15542
  let refreshData;
15384
15543
  try {
15385
15544
  refreshData = await api.post("/host/refresh", {
15386
- agent_id: agent.agent_id
15545
+ agent_id: agent.agent_id,
15546
+ // ENG-9585: ask for hashes instead of knowledge bodies. An API build that
15547
+ // predates the manifest ignores this and answers with `knowledge` as
15548
+ // before, which the resolution below handles without a version check.
15549
+ knowledge_manifest: true
15387
15550
  });
15551
+ if (refreshData.knowledge_manifest) {
15552
+ const resolved = await resolveKnowledgeFromManifest({
15553
+ manifest: refreshData.knowledge_manifest,
15554
+ cacheDir: join39(config.configDir, "_knowledge"),
15555
+ delivery: refreshData.agent?.knowledge_delivery ?? "both",
15556
+ fetchContents: async (hashes) => {
15557
+ const res = await api.post(
15558
+ "/host/knowledge/contents",
15559
+ { agent_id: agent.agent_id, hashes }
15560
+ );
15561
+ return res.contents ?? [];
15562
+ },
15563
+ log
15564
+ });
15565
+ refreshData.knowledge = resolved;
15566
+ }
15388
15567
  } catch (err) {
15389
15568
  log(`Refresh failed for '${agent.code_name}': ${err.message}`);
15390
15569
  const existing = state8.agents.find((a) => a.agentId === agent.agent_id);
@@ -15429,7 +15608,7 @@ async function processAgent(agent, agentStates, managedToolkits) {
15429
15608
  const frameworkId = refreshData.agent.framework ?? DEFAULT_FRAMEWORK;
15430
15609
  agentFrameworkCache.set(agent.code_name, frameworkId);
15431
15610
  const frameworkAdapter = getFramework(frameworkId);
15432
- agentDir = join38(frameworkAdapter.getAgentDir(agent.code_name), "provision");
15611
+ agentDir = join39(frameworkAdapter.getAgentDir(agent.code_name), "provision");
15433
15612
  cacheAgentDeliveryMetadata(agent.code_name, refreshData);
15434
15613
  agentRestartTimezoneInputs.set(agent.code_name, {
15435
15614
  agentTimezone: typeof refreshData.agent.timezone === "string" ? refreshData.agent.timezone : null,
@@ -15485,9 +15664,9 @@ async function processAgent(agent, agentStates, managedToolkits) {
15485
15664
  try {
15486
15665
  const artifacts = generateArtifacts(agent, refreshData, frameworkAdapter, renderIntegrationsSection);
15487
15666
  const changedFiles = [];
15488
- mkdirSync11(agentDir, { recursive: true });
15667
+ mkdirSync12(agentDir, { recursive: true });
15489
15668
  for (const artifact of artifacts) {
15490
- const filePath = join38(agentDir, artifact.relativePath);
15669
+ const filePath = join39(agentDir, artifact.relativePath);
15491
15670
  let existingHash;
15492
15671
  let newHash;
15493
15672
  let writeContent = artifact.content;
@@ -15506,8 +15685,8 @@ async function processAgent(agent, agentStates, managedToolkits) {
15506
15685
  };
15507
15686
  newHash = sha256(stripDynamicSections(artifact.content));
15508
15687
  try {
15509
- const projectClaudeMd = join38(config.configDir, agent.code_name, "project", "CLAUDE.md");
15510
- const existing = readFileSync29(projectClaudeMd, "utf-8");
15688
+ const projectClaudeMd = join39(config.configDir, agent.code_name, "project", "CLAUDE.md");
15689
+ const existing = readFileSync30(projectClaudeMd, "utf-8");
15511
15690
  existingHash = sha256(stripDynamicSections(existing));
15512
15691
  } catch {
15513
15692
  existingHash = null;
@@ -15525,7 +15704,7 @@ async function processAgent(agent, agentStates, managedToolkits) {
15525
15704
  const generatorKeys = Object.keys(generatorServers);
15526
15705
  let existingRaw = "";
15527
15706
  try {
15528
- existingRaw = readFileSync29(filePath, "utf-8");
15707
+ existingRaw = readFileSync30(filePath, "utf-8");
15529
15708
  } catch {
15530
15709
  }
15531
15710
  const existingServers = parseMcp(existingRaw);
@@ -15541,7 +15720,7 @@ async function processAgent(agent, agentStates, managedToolkits) {
15541
15720
  } else if (artifact.relativePath === "opencode.json") {
15542
15721
  let existingRaw = null;
15543
15722
  try {
15544
- existingRaw = readFileSync29(filePath, "utf-8");
15723
+ existingRaw = readFileSync30(filePath, "utf-8");
15545
15724
  } catch {
15546
15725
  }
15547
15726
  const mergeResult = mergeOpencodeConfigArtifact(artifact.content, existingRaw);
@@ -15557,26 +15736,26 @@ async function processAgent(agent, agentStates, managedToolkits) {
15557
15736
  }
15558
15737
  }
15559
15738
  if (changedFiles.length > 0) {
15560
- const isFirst = !existsSync16(join38(agentDir, "CHARTER.md"));
15739
+ const isFirst = !existsSync17(join39(agentDir, "CHARTER.md"));
15561
15740
  const verb = isFirst ? "Provisioning" : "Updating";
15562
15741
  const fileNames = changedFiles.map((f) => f.relativePath).join(", ");
15563
15742
  log(`${verb} '${agent.code_name}': ${fileNames}`);
15564
15743
  for (const file of changedFiles) {
15565
- const filePath = join38(agentDir, file.relativePath);
15566
- mkdirSync11(dirname10(filePath), { recursive: true });
15744
+ const filePath = join39(agentDir, file.relativePath);
15745
+ mkdirSync12(dirname10(filePath), { recursive: true });
15567
15746
  if (file.relativePath === ".mcp.json") {
15568
15747
  safeWriteJsonAtomic(filePath, file.content, { mode: 384 });
15569
15748
  } else {
15570
- writeFileSync15(filePath, file.content);
15749
+ writeFileSync16(filePath, file.content);
15571
15750
  }
15572
15751
  }
15573
15752
  try {
15574
- const provSkillsDir = join38(agentDir, ".claude", "skills");
15575
- if (existsSync16(provSkillsDir)) {
15576
- for (const folder of readdirSync9(provSkillsDir)) {
15753
+ const provSkillsDir = join39(agentDir, ".claude", "skills");
15754
+ if (existsSync17(provSkillsDir)) {
15755
+ for (const folder of readdirSync10(provSkillsDir)) {
15577
15756
  if (folder.startsWith("knowledge-")) {
15578
15757
  try {
15579
- rmSync5(join38(provSkillsDir, folder), { recursive: true });
15758
+ rmSync6(join39(provSkillsDir, folder), { recursive: true });
15580
15759
  } catch {
15581
15760
  }
15582
15761
  }
@@ -15589,7 +15768,7 @@ async function processAgent(agent, agentStates, managedToolkits) {
15589
15768
  const trackedFiles2 = frameworkAdapter.driftTrackedFiles();
15590
15769
  const hashes = /* @__PURE__ */ new Map();
15591
15770
  for (const file of trackedFiles2) {
15592
- const h = hashFile(join38(agentDir, file));
15771
+ const h = hashFile(join39(agentDir, file));
15593
15772
  if (h) hashes.set(file, h);
15594
15773
  }
15595
15774
  agentState.writtenHashes.set(agent.agent_id, hashes);
@@ -15607,14 +15786,14 @@ async function processAgent(agent, agentStates, managedToolkits) {
15607
15786
  }
15608
15787
  if (Array.isArray(refreshData.workflows)) {
15609
15788
  try {
15610
- const provWorkflowsDir = join38(agentDir, ".claude", "workflows");
15611
- if (existsSync16(provWorkflowsDir)) {
15789
+ const provWorkflowsDir = join39(agentDir, ".claude", "workflows");
15790
+ if (existsSync17(provWorkflowsDir)) {
15612
15791
  const expected = new Set(refreshData.workflows.map((w) => `${w.name}.js`));
15613
- for (const file of readdirSync9(provWorkflowsDir)) {
15792
+ for (const file of readdirSync10(provWorkflowsDir)) {
15614
15793
  if (!file.endsWith(".js")) continue;
15615
15794
  if (expected.has(file)) continue;
15616
15795
  try {
15617
- rmSync5(join38(provWorkflowsDir, file));
15796
+ rmSync6(join39(provWorkflowsDir, file));
15618
15797
  } catch {
15619
15798
  }
15620
15799
  }
@@ -15693,10 +15872,10 @@ async function processAgent(agent, agentStates, managedToolkits) {
15693
15872
  }
15694
15873
  let lastDriftCheckAt = now;
15695
15874
  const written = agentState.writtenHashes.get(agent.agent_id);
15696
- if (written && existsSync16(agentDir)) {
15875
+ if (written && existsSync17(agentDir)) {
15697
15876
  const driftedFiles = [];
15698
15877
  for (const [file, expectedHash] of written) {
15699
- const localHash = hashFile(join38(agentDir, file));
15878
+ const localHash = hashFile(join39(agentDir, file));
15700
15879
  if (localHash && localHash !== expectedHash) {
15701
15880
  driftedFiles.push(file);
15702
15881
  }
@@ -15707,7 +15886,7 @@ async function processAgent(agent, agentStates, managedToolkits) {
15707
15886
  try {
15708
15887
  const localHashes = {};
15709
15888
  for (const file of driftedFiles) {
15710
- localHashes[file] = hashFile(join38(agentDir, file));
15889
+ localHashes[file] = hashFile(join39(agentDir, file));
15711
15890
  }
15712
15891
  await api.post("/host/drift", {
15713
15892
  agent_id: agent.agent_id,
@@ -15975,15 +16154,15 @@ async function processAgent(agent, agentStates, managedToolkits) {
15975
16154
  const addedChannels = [...restartDecision.added];
15976
16155
  const writeDmNoticeMarkers = isChannelAddRestart ? () => {
15977
16156
  try {
15978
- const agentAugmentedDir = join38(homedir17(), ".augmented", agent.code_name);
15979
- mkdirSync11(agentAugmentedDir, { recursive: true });
16157
+ const agentAugmentedDir = join39(homedir17(), ".augmented", agent.code_name);
16158
+ mkdirSync12(agentAugmentedDir, { recursive: true });
15980
16159
  const markerJson = JSON.stringify({
15981
16160
  version: 1,
15982
16161
  at: (/* @__PURE__ */ new Date()).toISOString(),
15983
16162
  added: addedChannels
15984
16163
  });
15985
16164
  for (const file of ["slack-channel-add-restart.json", "telegram-channel-add-restart.json"]) {
15986
- atomicWriteFileSync(join38(agentAugmentedDir, file), markerJson);
16165
+ atomicWriteFileSync(join39(agentAugmentedDir, file), markerJson);
15987
16166
  }
15988
16167
  } catch (err) {
15989
16168
  log(`[hot-reload] channel-add DM-notice marker write failed for '${agent.code_name}' (non-fatal): ${err.message}`);
@@ -16059,7 +16238,7 @@ async function processAgent(agent, agentStates, managedToolkits) {
16059
16238
  const behaviourSubset = extractMsTeamsBehaviourSubset(
16060
16239
  msteamsEntry?.config
16061
16240
  );
16062
- const behaviourHash = createHash17("sha256").update(canonicalJson(behaviourSubset)).digest("hex");
16241
+ const behaviourHash = createHash18("sha256").update(canonicalJson(behaviourSubset)).digest("hex");
16063
16242
  const prevBehaviourHash = agentState.knownMsTeamsBehaviourHashes.get(agent.agent_id);
16064
16243
  const msteamsBehaviourRestrictive = isMsTeamsBehaviourRestrictive(behaviourSubset);
16065
16244
  const behaviourDecision = decideSenderPolicyRestart({
@@ -16115,7 +16294,7 @@ async function processAgent(agent, agentStates, managedToolkits) {
16115
16294
  const slackBehaviourSubset = extractSlackBehaviourSubset(
16116
16295
  slackEntry?.config
16117
16296
  );
16118
- const slackBehaviourHash = createHash17("sha256").update(canonicalJson(slackBehaviourSubset)).digest("hex");
16297
+ const slackBehaviourHash = createHash18("sha256").update(canonicalJson(slackBehaviourSubset)).digest("hex");
16119
16298
  const prevSlackBehaviourHash = agentState.knownSlackBehaviourHashes.get(agent.agent_id);
16120
16299
  const slackBehaviourRestrictive = isSlackBehaviourRestrictive(slackBehaviourSubset);
16121
16300
  const slackBehaviourDecision = decideSenderPolicyRestart({
@@ -16172,24 +16351,24 @@ async function processAgent(agent, agentStates, managedToolkits) {
16172
16351
  if (agentSessionMode === "persistent" && (agentFrameworkCache.get(agent.code_name) ?? DEFAULT_FRAMEWORK) === "claude-code") {
16173
16352
  try {
16174
16353
  const agentProvisionDir = agentDir;
16175
- const projectDir = join38(homedir17(), ".augmented", agent.code_name, "project");
16176
- mkdirSync11(agentProvisionDir, { recursive: true });
16177
- mkdirSync11(projectDir, { recursive: true });
16178
- const provisionMcpPath = join38(agentProvisionDir, ".mcp.json");
16179
- const projectMcpPath = join38(projectDir, ".mcp.json");
16354
+ const projectDir = join39(homedir17(), ".augmented", agent.code_name, "project");
16355
+ mkdirSync12(agentProvisionDir, { recursive: true });
16356
+ mkdirSync12(projectDir, { recursive: true });
16357
+ const provisionMcpPath = join39(agentProvisionDir, ".mcp.json");
16358
+ const projectMcpPath = join39(projectDir, ".mcp.json");
16180
16359
  let mcpConfig = { mcpServers: {} };
16181
16360
  try {
16182
- mcpConfig = JSON.parse(readFileSync29(provisionMcpPath, "utf-8"));
16361
+ mcpConfig = JSON.parse(readFileSync30(provisionMcpPath, "utf-8"));
16183
16362
  if (!mcpConfig.mcpServers) mcpConfig.mcpServers = {};
16184
16363
  } catch {
16185
16364
  }
16186
- const localDirectChatChannel = join38(homedir17(), ".augmented", "_mcp", "direct-chat-channel.js");
16365
+ const localDirectChatChannel = join39(homedir17(), ".augmented", "_mcp", "direct-chat-channel.js");
16187
16366
  const directChatTeamSettings = refreshData.team?.settings;
16188
16367
  const directChatTz = (() => {
16189
16368
  const tz = directChatTeamSettings?.["timezone"];
16190
16369
  return typeof tz === "string" && tz.trim() !== "" ? tz.trim() : void 0;
16191
16370
  })();
16192
- if (existsSync16(localDirectChatChannel)) {
16371
+ if (existsSync17(localDirectChatChannel)) {
16193
16372
  const directChatEnv = {
16194
16373
  AGT_HOST: requireHost(),
16195
16374
  // ENG-5901 Track D: templated — the manager exports the real
@@ -16209,7 +16388,7 @@ async function processAgent(agent, agentStates, managedToolkits) {
16209
16388
  // ~/.augmented/<codeName>/.current-turn-initiator.json. Note getAgentDir
16210
16389
  // returns the agent root (NOT the /provision subdir `agentDir` points at),
16211
16390
  // so it byte-matches the broker readers' path.
16212
- AGT_TURN_INITIATOR_FILE: join38(
16391
+ AGT_TURN_INITIATOR_FILE: join39(
16213
16392
  frameworkAdapter.getAgentDir(agent.code_name),
16214
16393
  ".current-turn-initiator.json"
16215
16394
  )
@@ -16229,10 +16408,10 @@ async function processAgent(agent, agentStates, managedToolkits) {
16229
16408
  log(`Channel credentials written for '${agent.code_name}/direct-chat'`);
16230
16409
  }
16231
16410
  }
16232
- const staleChannelsPath = join38(projectDir, ".mcp-channels.json");
16233
- if (existsSync16(staleChannelsPath)) {
16411
+ const staleChannelsPath = join39(projectDir, ".mcp-channels.json");
16412
+ if (existsSync17(staleChannelsPath)) {
16234
16413
  try {
16235
- rmSync5(staleChannelsPath, { force: true });
16414
+ rmSync6(staleChannelsPath, { force: true });
16236
16415
  } catch {
16237
16416
  }
16238
16417
  }
@@ -16319,7 +16498,7 @@ async function processAgent(agent, agentStates, managedToolkits) {
16319
16498
  }
16320
16499
  if (hostFlagStore().getBoolean("connectivity-probe")) {
16321
16500
  try {
16322
- const probeProjectDir = join38(homedir17(), ".augmented", agent.code_name, "project");
16501
+ const probeProjectDir = join39(homedir17(), ".augmented", agent.code_name, "project");
16323
16502
  let probeSet = integrations;
16324
16503
  try {
16325
16504
  const quarantined = await api.post("/host/agent-integrations/quarantined", { agent_id: agent.agent_id });
@@ -16365,7 +16544,7 @@ async function processAgent(agent, agentStates, managedToolkits) {
16365
16544
  const forceDue = attemptsLeft > 0;
16366
16545
  let probeRan = false;
16367
16546
  try {
16368
- const probeProjectDir = join38(homedir17(), ".augmented", agent.code_name, "project");
16547
+ const probeProjectDir = join39(homedir17(), ".augmented", agent.code_name, "project");
16369
16548
  probeRan = await runAgentSessionToolBindProbes(agent, integrations, probeProjectDir, { forceDue });
16370
16549
  } catch (err) {
16371
16550
  log(`Session-tool-bind probe failed for '${agent.code_name}': ${err.message}`);
@@ -16442,11 +16621,11 @@ async function processAgent(agent, agentStates, managedToolkits) {
16442
16621
  const intHash = computeIntegrationsHash(integrations);
16443
16622
  const prevIntHash = agentState.knownIntegrationHashes.get(agent.agent_id);
16444
16623
  if (intHash !== prevIntHash) {
16445
- const projectDir = join38(homedir17(), ".augmented", agent.code_name, "project");
16446
- const envIntPath = join38(projectDir, ".env.integrations");
16624
+ const projectDir = join39(homedir17(), ".augmented", agent.code_name, "project");
16625
+ const envIntPath = join39(projectDir, ".env.integrations");
16447
16626
  let preWriteEnv;
16448
16627
  try {
16449
- preWriteEnv = readFileSync29(envIntPath, "utf-8");
16628
+ preWriteEnv = readFileSync30(envIntPath, "utf-8");
16450
16629
  } catch {
16451
16630
  preWriteEnv = void 0;
16452
16631
  }
@@ -16465,9 +16644,9 @@ async function processAgent(agent, agentStates, managedToolkits) {
16465
16644
  }
16466
16645
  if (fw === "claude-code" && isSessionHealthy(agent.code_name)) {
16467
16646
  try {
16468
- const projectMcpPath = join38(projectDir, ".mcp.json");
16469
- const postWriteEnv = readFileSync29(envIntPath, "utf-8");
16470
- const mcpContent = readFileSync29(projectMcpPath, "utf-8");
16647
+ const projectMcpPath = join39(projectDir, ".mcp.json");
16648
+ const postWriteEnv = readFileSync30(envIntPath, "utf-8");
16649
+ const mcpContent = readFileSync30(projectMcpPath, "utf-8");
16471
16650
  const changedVars = diffEnvIntegrations(preWriteEnv, postWriteEnv);
16472
16651
  const mcpJsonForReap = JSON.parse(mcpContent);
16473
16652
  const affectedServerKeys = findMcpServersUsingVars(mcpJsonForReap, changedVars);
@@ -16557,10 +16736,10 @@ async function processAgent(agent, agentStates, managedToolkits) {
16557
16736
  desiredEntries.push({ serverId, url, headers: mcpHeaders, name: tk.toolkit_name });
16558
16737
  }
16559
16738
  const hashBasis = desiredEntries.slice().sort((a, b) => a.serverId.localeCompare(b.serverId)).map((e) => {
16560
- const headersHash = createHash17("sha256").update(canonicalJson(e.headers ?? {})).digest("hex").slice(0, 16);
16739
+ const headersHash = createHash18("sha256").update(canonicalJson(e.headers ?? {})).digest("hex").slice(0, 16);
16561
16740
  return `${e.serverId}|${e.url}|${headersHash}`;
16562
16741
  }).join("\n");
16563
- const mcpHash = createHash17("sha256").update(hashBasis).digest("hex").slice(0, 16);
16742
+ const mcpHash = createHash18("sha256").update(hashBasis).digest("hex").slice(0, 16);
16564
16743
  const prevMcpHash = agentState.knownManagedMcpHashes.get(agent.agent_id);
16565
16744
  const structureHash = managedMcpStructureHash(desiredEntries);
16566
16745
  const prevStructureHash = agentState.knownManagedMcpStructure.get(agent.agent_id);
@@ -16575,7 +16754,7 @@ async function processAgent(agent, agentStates, managedToolkits) {
16575
16754
  if (mcpHash !== prevMcpHash) {
16576
16755
  for (const e of desiredEntries) {
16577
16756
  frameworkAdapter.writeMcpServer(agent.code_name, e.serverId, { url: e.url, headers: e.headers });
16578
- const urlHash = createHash17("sha256").update(e.url).digest("hex").slice(0, 12);
16757
+ const urlHash = createHash18("sha256").update(e.url).digest("hex").slice(0, 12);
16579
16758
  log(`[managed-toolkit] ${agent.code_name}: wrote '${e.name}' (serverId=${e.serverId}, url_hash=${urlHash})`);
16580
16759
  }
16581
16760
  if (frameworkAdapter.removeMcpServer && frameworkAdapter.readMcpServers) {
@@ -16655,7 +16834,10 @@ async function processAgent(agent, agentStates, managedToolkits) {
16655
16834
  if (missing.length > 0) {
16656
16835
  log(`Auto-provisioned ${missing.length} default schedule(s) for '${agent.code_name}': ${missing.map((s) => s.template_id).join(", ")}`);
16657
16836
  }
16658
- const freshData = await api.post("/host/refresh", { agent_id: agent.agent_id });
16837
+ const freshData = await api.post("/host/refresh", {
16838
+ agent_id: agent.agent_id,
16839
+ knowledge_manifest: true
16840
+ });
16659
16841
  tasks = freshData.scheduled_tasks ?? tasks;
16660
16842
  }
16661
16843
  } catch (err) {
@@ -16678,7 +16860,7 @@ async function processAgent(agent, agentStates, managedToolkits) {
16678
16860
  if (frameworkAdapter.installSkillFiles) {
16679
16861
  const currentIntegrationSkillIds = /* @__PURE__ */ new Set();
16680
16862
  const installedIntegrationSkills = [];
16681
- const { createHash: createHash18 } = await import("crypto");
16863
+ const { createHash: createHash19 } = await import("crypto");
16682
16864
  const refreshAny = refreshData;
16683
16865
  const contexts = refreshAny.integration_contexts ?? refreshAny.plugin_contexts ?? [];
16684
16866
  const contextBySlug = /* @__PURE__ */ new Map();
@@ -16707,7 +16889,7 @@ async function processAgent(agent, agentStates, managedToolkits) {
16707
16889
  )
16708
16890
  }));
16709
16891
  const bundle = buildIntegrationBundle(renderedScopes);
16710
- const contentHash = createHash18("sha256").update(bundleFingerprint(bundle.files)).digest("hex").slice(0, 12);
16892
+ const contentHash = createHash19("sha256").update(bundleFingerprint(bundle.files)).digest("hex").slice(0, 12);
16711
16893
  if (!shouldWriteIntegrationSkill(
16712
16894
  agentState.knownSkillHashes,
16713
16895
  agent.agent_id,
@@ -16730,23 +16912,23 @@ async function processAgent(agent, agentStates, managedToolkits) {
16730
16912
  }
16731
16913
  }
16732
16914
  try {
16733
- const { readdirSync: readdirSync10, rmSync: rmSync6 } = await import("fs");
16915
+ const { readdirSync: readdirSync11, rmSync: rmSync7 } = await import("fs");
16734
16916
  const { homedir: homedir18 } = await import("os");
16735
16917
  const frameworkId2 = frameworkAdapter.id;
16736
16918
  const candidateSkillDirs = [
16737
16919
  // Claude Code — framework runtime tree
16738
- join38(homedir18(), ".augmented", agent.code_name, "skills"),
16920
+ join39(homedir18(), ".augmented", agent.code_name, "skills"),
16739
16921
  // Claude Code — project tree
16740
- join38(homedir18(), ".augmented", agent.code_name, "project", ".claude", "skills"),
16922
+ join39(homedir18(), ".augmented", agent.code_name, "project", ".claude", "skills"),
16741
16923
  // Defensive: legacy provision-side path, not currently an
16742
16924
  // install target but cheap to sweep.
16743
- join38(agentDir, ".claude", "skills")
16925
+ join39(agentDir, ".claude", "skills")
16744
16926
  ];
16745
- const existingDirs = candidateSkillDirs.filter((d) => existsSync16(d));
16927
+ const existingDirs = candidateSkillDirs.filter((d) => existsSync17(d));
16746
16928
  const discoveredEntries = /* @__PURE__ */ new Set();
16747
16929
  for (const dir of existingDirs) {
16748
16930
  try {
16749
- for (const entry of readdirSync10(dir)) {
16931
+ for (const entry of readdirSync11(dir)) {
16750
16932
  if (entry.startsWith("plugin-") || entry.startsWith("integration-")) {
16751
16933
  discoveredEntries.add(entry);
16752
16934
  }
@@ -16761,8 +16943,8 @@ async function processAgent(agent, agentStates, managedToolkits) {
16761
16943
  entry,
16762
16944
  dirs: existingDirs,
16763
16945
  removeDir: (p) => {
16764
- if (existsSync16(p)) {
16765
- rmSync6(p, { recursive: true, force: true });
16946
+ if (existsSync17(p)) {
16947
+ rmSync7(p, { recursive: true, force: true });
16766
16948
  }
16767
16949
  }
16768
16950
  });
@@ -16781,7 +16963,7 @@ async function processAgent(agent, agentStates, managedToolkits) {
16781
16963
  const sharedSkillsPayload = refreshAny.shared_skills;
16782
16964
  const desiredResolved = globalSkillsPayload !== void 0 || sharedSkillsPayload !== void 0;
16783
16965
  const manifestPath = managedSkillManifestPath(
16784
- join38(homedir17(), ".augmented", agent.code_name)
16966
+ join39(homedir17(), ".augmented", agent.code_name)
16785
16967
  );
16786
16968
  const prevIds = /* @__PURE__ */ new Set([
16787
16969
  ...agentState.knownGlobalSkillIds.get(agent.agent_id) ?? /* @__PURE__ */ new Set(),
@@ -16790,7 +16972,7 @@ async function processAgent(agent, agentStates, managedToolkits) {
16790
16972
  const plan = planGlobalSkillSync(
16791
16973
  [...globalSkillsPayload ?? [], ...sharedSkillsPayload ?? []],
16792
16974
  prevIds,
16793
- (content) => createHash18("sha256").update(content).digest("hex").slice(0, 12),
16975
+ (content) => createHash19("sha256").update(content).digest("hex").slice(0, 12),
16794
16976
  (skillId) => agentState.knownSkillHashes.get(`global-skill:${agent.agent_id}:${skillId}`),
16795
16977
  { desiredResolved }
16796
16978
  );
@@ -16801,16 +16983,16 @@ async function processAgent(agent, agentStates, managedToolkits) {
16801
16983
  }
16802
16984
  if (plan.removes.length) {
16803
16985
  const globalSkillDirs = [
16804
- join38(homedir17(), ".augmented", agent.code_name, "skills"),
16805
- join38(homedir17(), ".augmented", agent.code_name, "project", ".claude", "skills"),
16806
- join38(agentDir, ".claude", "skills")
16986
+ join39(homedir17(), ".augmented", agent.code_name, "skills"),
16987
+ join39(homedir17(), ".augmented", agent.code_name, "project", ".claude", "skills"),
16988
+ join39(agentDir, ".claude", "skills")
16807
16989
  ];
16808
16990
  for (const id of plan.removes) {
16809
16991
  let prunedAny = false;
16810
16992
  for (const dir of globalSkillDirs) {
16811
- const p = join38(dir, id);
16812
- if (existsSync16(p) && existsSync16(join38(p, "SKILL.md"))) {
16813
- rmSync5(p, { recursive: true, force: true });
16993
+ const p = join39(dir, id);
16994
+ if (existsSync17(p) && existsSync17(join39(p, "SKILL.md"))) {
16995
+ rmSync6(p, { recursive: true, force: true });
16814
16996
  prunedAny = true;
16815
16997
  }
16816
16998
  }
@@ -16841,7 +17023,7 @@ async function processAgent(agent, agentStates, managedToolkits) {
16841
17023
  const slug = hook.integration_slug ?? hook.plugin_slug;
16842
17024
  if (!slug) continue;
16843
17025
  try {
16844
- const scriptHash = createHash18("sha256").update(hook.script).digest("hex").slice(0, 12);
17026
+ const scriptHash = createHash19("sha256").update(hook.script).digest("hex").slice(0, 12);
16845
17027
  const hookKey = `${agent.agent_id}:${frameworkAdapter.id}:plugin-hook:${slug}:on_install`;
16846
17028
  if (agentState.knownSkillHashes.get(hookKey) === scriptHash) continue;
16847
17029
  const result = await frameworkAdapter.executePluginHook({
@@ -16856,9 +17038,9 @@ async function processAgent(agent, agentStates, managedToolkits) {
16856
17038
  } else if (result.timedOut) {
16857
17039
  log(`Integration hook on_install '${slug}' TIMED OUT for '${agent.code_name}' after ${result.durationMs}ms`);
16858
17040
  } else {
16859
- const stderrHash = createHash18("sha256").update(result.stderr).digest("hex").slice(0, 12);
17041
+ const stderrHash = createHash19("sha256").update(result.stderr).digest("hex").slice(0, 12);
16860
17042
  const missingCmd = result.exitCode === 127 ? extractCommandNotFound(result.stderr) : null;
16861
- const missingCmdHash = missingCmd ? createHash18("sha256").update(missingCmd).digest("hex").slice(0, 8) : null;
17043
+ const missingCmdHash = missingCmd ? createHash19("sha256").update(missingCmd).digest("hex").slice(0, 8) : null;
16862
17044
  log(
16863
17045
  `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}]`
16864
17046
  );
@@ -17024,6 +17206,12 @@ async function processAgent(agent, agentStates, managedToolkits) {
17024
17206
  } else if (stuck.recovered) {
17025
17207
  log(`[persistent-session-stuck] agent=${agent.code_name} recovered from stuck state`);
17026
17208
  }
17209
+ if (stuck.shouldWarnSpawnLoop) {
17210
+ const failure = getLastFailureContext(agent.code_name);
17211
+ log(
17212
+ `[persistent-session-spawn-loop] WARN: agent=${agent.code_name} respawned ${stuck.spawnLoopTicks} consecutive ticks and is still unhealthy (last_decision=${psResult.decision} signature=${failure.signature} restart_count=${failure.restartCount}) \u2014 the spawn is failing in a way a retry cannot fix; see the pane log tail for the cause (ENG-9614)`
17213
+ );
17214
+ }
17027
17215
  if (agentFw === "claude-code") {
17028
17216
  try {
17029
17217
  checkMcpConfigDriftAndScheduleRestart(agent.code_name, getProjectDir(agent.code_name));
@@ -17045,8 +17233,8 @@ async function processAgent(agent, agentStates, managedToolkits) {
17045
17233
  const sess = getSessionState(agent.code_name);
17046
17234
  let mcpJsonParsed = null;
17047
17235
  try {
17048
- const mcpPath = join38(getProjectDir(agent.code_name), ".mcp.json");
17049
- mcpJsonParsed = JSON.parse(readFileSync29(mcpPath, "utf-8"));
17236
+ const mcpPath = join39(getProjectDir(agent.code_name), ".mcp.json");
17237
+ mcpJsonParsed = JSON.parse(readFileSync30(mcpPath, "utf-8"));
17050
17238
  } catch {
17051
17239
  }
17052
17240
  reapMissingMcpSessions({
@@ -17429,7 +17617,7 @@ async function processAgent(agent, agentStates, managedToolkits) {
17429
17617
  freshDoneIds.add(item.id);
17430
17618
  }
17431
17619
  } catch (err) {
17432
- const errId = createHash17("sha256").update(err instanceof Error ? err.message : String(err)).digest("hex").slice(0, 12);
17620
+ const errId = createHash18("sha256").update(err instanceof Error ? err.message : String(err)).digest("hex").slice(0, 12);
17433
17621
  log(`Reap API error for item_id=${item.id} error_id=${errId}`);
17434
17622
  }
17435
17623
  if (reapAction === "dead_letter") {
@@ -17477,10 +17665,10 @@ Retried to the limit after repeated stalls \u2014 needs a look.`).catch(() => {
17477
17665
  }
17478
17666
  }
17479
17667
  const trackedFiles = frameworkAdapter.driftTrackedFiles();
17480
- if (trackedFiles.length > 0 && existsSync16(agentDir)) {
17668
+ if (trackedFiles.length > 0 && existsSync17(agentDir)) {
17481
17669
  const hashes = /* @__PURE__ */ new Map();
17482
17670
  for (const file of trackedFiles) {
17483
- const h = hashFile(join38(agentDir, file));
17671
+ const h = hashFile(join39(agentDir, file));
17484
17672
  if (h) hashes.set(file, h);
17485
17673
  }
17486
17674
  agentState.writtenHashes.set(agent.agent_id, hashes);
@@ -17495,7 +17683,7 @@ Retried to the limit after repeated stalls \u2014 needs a look.`).catch(() => {
17495
17683
  refreshData.agent.onboarding_state
17496
17684
  );
17497
17685
  const obStep = obState.step;
17498
- const markerPath = join38(homedir17(), ".augmented", agent.code_name, "onboarding-drive.json");
17686
+ const markerPath = join39(homedir17(), ".augmented", agent.code_name, "onboarding-drive.json");
17499
17687
  const marker = readOnboardingDriveMarker(markerPath);
17500
17688
  const obContactRaw = refreshData.agent.manager_last_contacted_at;
17501
17689
  const obContact = typeof obContactRaw === "string" && obContactRaw ? obContactRaw : null;
@@ -17597,7 +17785,7 @@ async function ensureOpencodeRuntime(agent, refreshData, agentTimezone) {
17597
17785
  }
17598
17786
  stopOpencodeSlackIngest(codeName, log);
17599
17787
  stopOpencodeTelegramIngest(codeName, log);
17600
- const opencodeProjectDir = join38(getFramework("opencode").getAgentDir(codeName), "provision");
17788
+ const opencodeProjectDir = join39(getFramework("opencode").getAgentDir(codeName), "provision");
17601
17789
  const serveEnv = {
17602
17790
  AGT_HOST: requireHost(),
17603
17791
  AGT_API_KEY: getApiKey() ?? void 0,
@@ -17652,8 +17840,8 @@ async function ensurePersistentSession(agent, tasks, boardItems, refreshData) {
17652
17840
  });
17653
17841
  }
17654
17842
  const projectDir = getProjectDir(codeName);
17655
- const mcpConfigPath = join38(projectDir, ".mcp.json");
17656
- const claudeMdPath = join38(projectDir, "CLAUDE.md");
17843
+ const mcpConfigPath = join39(projectDir, ".mcp.json");
17844
+ const claudeMdPath = join39(projectDir, "CLAUDE.md");
17657
17845
  if (restartBreaker.isTripped(codeName)) {
17658
17846
  const trip = restartBreaker.getTrip(codeName);
17659
17847
  return {
@@ -17902,7 +18090,7 @@ async function ensurePersistentSession(agent, tasks, boardItems, refreshData) {
17902
18090
  const ctx = getLastFailureContext(codeName);
17903
18091
  const recovery = prepareForRespawn(codeName);
17904
18092
  const tailSummary = !ctx.tail ? "" : KNOWN_SAFE_TAIL_SIGNATURES.has(ctx.signature) ? `; last pane output (${PANE_TAIL_PREVIEW_LINES} of ~20 lines):
17905
- ${truncateForLog(ctx.tail)}` : `; pane_tail_hash=sha256:${createHash17("sha256").update(ctx.tail).digest("hex").slice(0, 12)} (raw at ~/.augmented/${codeName}/pane.log)`;
18093
+ ${truncateForLog(ctx.tail)}` : `; pane_tail_hash=sha256:${createHash18("sha256").update(ctx.tail).digest("hex").slice(0, 12)} (raw at ~/.augmented/${codeName}/pane.log)`;
17906
18094
  const sigSummary = ctx.signature !== "unknown" ? `; signature=${ctx.signature}` : "";
17907
18095
  const recoverySummary = recovery ? `; recovery=${recovery}` : "";
17908
18096
  log(
@@ -17916,7 +18104,7 @@ ${truncateForLog(ctx.tail)}` : `; pane_tail_hash=sha256:${createHash17("sha256")
17916
18104
  );
17917
18105
  getHostId().then((hostId) => {
17918
18106
  if (!hostId) return;
17919
- const paneTailHash = zombie.paneTail ? `sha256:${createHash17("sha256").update(zombie.paneTail).digest("hex").slice(0, 12)}` : null;
18107
+ const paneTailHash = zombie.paneTail ? `sha256:${createHash18("sha256").update(zombie.paneTail).digest("hex").slice(0, 12)}` : null;
17920
18108
  return api.post("/host/events", {
17921
18109
  host_id: hostId,
17922
18110
  agent_code_name: codeName,
@@ -18113,7 +18301,7 @@ ${truncateForLog(ctx.tail)}` : `; pane_tail_hash=sha256:${createHash17("sha256")
18113
18301
  if (!claudeAuthTupleBySession.has(codeName)) {
18114
18302
  claudeAuthTupleBySession.set(codeName, currentAuthTuple);
18115
18303
  }
18116
- const stableTasksHash = createHash17("sha256").update(JSON.stringify(tasks)).digest("hex").slice(0, 16);
18304
+ const stableTasksHash = createHash18("sha256").update(JSON.stringify(tasks)).digest("hex").slice(0, 16);
18117
18305
  const prevHash = agentState.knownTasksHashes.get(agent.agent_id);
18118
18306
  if (stableTasksHash !== prevHash) {
18119
18307
  const taskInputs = tasks.map((t) => buildSchedulerTaskInput(t));
@@ -18428,7 +18616,7 @@ async function handleRestartDoorbell(agentId, requestedAt, restartReason) {
18428
18616
  void api.post("/host/restart-ack", { host_id: hostId, agent_id: agentId, restart_requested_at: requestedAt }).catch((err) => log(`[restart-lane] ack failed for '${codeName}': ${err.message}`));
18429
18617
  void (async () => {
18430
18618
  try {
18431
- const { collectDiagnostics } = await import("../persistent-session-DJSSEIR6.js");
18619
+ const { collectDiagnostics } = await import("../persistent-session-2AWYIUCX.js");
18432
18620
  await api.post("/host/heartbeat", {
18433
18621
  host_id: hostId,
18434
18622
  agent_diagnostics: collectDiagnostics([codeName], quarantineEntriesFor, claudeMdSizeFor, spawnOutcomeForDiagnostics, pidPressureFor, forwardedToolsFor)
@@ -18479,7 +18667,7 @@ async function respawnAgentAfterMcpStop(codeName, reason) {
18479
18667
  }
18480
18668
  try {
18481
18669
  const hostId = await getHostId();
18482
- const { collectDiagnostics } = await import("../persistent-session-DJSSEIR6.js");
18670
+ const { collectDiagnostics } = await import("../persistent-session-2AWYIUCX.js");
18483
18671
  await api.post("/host/heartbeat", {
18484
18672
  host_id: hostId,
18485
18673
  agent_diagnostics: collectDiagnostics([codeName], quarantineEntriesFor, claudeMdSizeFor, spawnOutcomeForDiagnostics, pidPressureFor, forwardedToolsFor)
@@ -18587,7 +18775,7 @@ function ensureRealtimeKanbanStarted(agentStates) {
18587
18775
  );
18588
18776
  }
18589
18777
  }).catch((err) => {
18590
- const errId = createHash17("sha256").update(err instanceof Error ? err.message : String(err)).digest("hex").slice(0, 12);
18778
+ const errId = createHash18("sha256").update(err instanceof Error ? err.message : String(err)).digest("hex").slice(0, 12);
18591
18779
  log(
18592
18780
  `[realtime] Work trigger enqueue threw for '${agent.codeName}' item_id=${item.id} error_id=${errId} \u2014 hybrid nudge will retry`
18593
18781
  );
@@ -18877,8 +19065,8 @@ async function processDirectChatMessage(agent, msg) {
18877
19065
  if (useDoorbell) {
18878
19066
  try {
18879
19067
  const doorbell = directChatDoorbellPath(agent.agentId, homedir17());
18880
- mkdirSync11(dirname10(doorbell), { recursive: true });
18881
- writeFileSync15(doorbell, String(Date.now()));
19068
+ mkdirSync12(dirname10(doorbell), { recursive: true });
19069
+ writeFileSync16(doorbell, String(Date.now()));
18882
19070
  log(`[direct-chat] Doorbell rung for '${agent.codeName}' (msg=${msg.id}) \u2014 in-session MCP will pull via the cursor`);
18883
19071
  return;
18884
19072
  } catch (err) {
@@ -19006,8 +19194,8 @@ ${formatRunMarker(run_id)}` : KANBAN_CHECK_COMMAND;
19006
19194
  if (run_id) openInjectedRunByCode.set(codeName, run_id);
19007
19195
  try {
19008
19196
  const doorbell = directChatDoorbellPath(agentId, homedir17());
19009
- mkdirSync11(dirname10(doorbell), { recursive: true });
19010
- writeFileSync15(doorbell, String(Date.now()));
19197
+ mkdirSync12(dirname10(doorbell), { recursive: true });
19198
+ writeFileSync16(doorbell, String(Date.now()));
19011
19199
  } catch (err) {
19012
19200
  log(`[kanban] doorbell ring failed for '${codeName}': ${err.message} (notice still queued)`);
19013
19201
  }
@@ -19111,7 +19299,7 @@ async function processClaudePairSessions(agents) {
19111
19299
  killPairSession,
19112
19300
  pairTmuxSession,
19113
19301
  finalizeClaudePairOnboarding
19114
- } = await import("../claude-pair-runtime-JK7GQU25.js");
19302
+ } = await import("../claude-pair-runtime-PDG74SAT.js");
19115
19303
  for (const pairId of pendingResp.cancelled_pair_ids ?? []) {
19116
19304
  log(`[claude-pair] sweeping orphan tmux session for pair ${pairId.slice(0, 8)}`);
19117
19305
  const killed = await killPairSession(pairTmuxSession(pairId));
@@ -19336,17 +19524,17 @@ var lastDownloadHash = /* @__PURE__ */ new Map();
19336
19524
  var lastLocalFileHash = /* @__PURE__ */ new Map();
19337
19525
  var memoryManifests = /* @__PURE__ */ new Map();
19338
19526
  function memoryRetirementDir(configDir, codeName) {
19339
- return join38(configDir, "_memory-retirement", codeName);
19527
+ return join39(configDir, "_memory-retirement", codeName);
19340
19528
  }
19341
19529
  function memoryManifestPath(configDir, codeName) {
19342
- return join38(memoryRetirementDir(configDir, codeName), "manifest.json");
19530
+ return join39(memoryRetirementDir(configDir, codeName), "manifest.json");
19343
19531
  }
19344
19532
  function loadMemoryManifest(agentId, configDir, codeName) {
19345
19533
  const cached = memoryManifests.get(agentId);
19346
19534
  if (cached) return cached;
19347
19535
  let manifest = {};
19348
19536
  try {
19349
- const raw = readFileSync29(memoryManifestPath(configDir, codeName), "utf-8");
19537
+ const raw = readFileSync30(memoryManifestPath(configDir, codeName), "utf-8");
19350
19538
  const parsed = JSON.parse(raw);
19351
19539
  if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
19352
19540
  for (const [name, entry] of Object.entries(parsed)) {
@@ -19366,15 +19554,15 @@ function saveMemoryManifest(agentId, configDir, codeName) {
19366
19554
  if (!manifest) return;
19367
19555
  try {
19368
19556
  const path = memoryManifestPath(configDir, codeName);
19369
- mkdirSync11(memoryRetirementDir(configDir, codeName), { recursive: true });
19557
+ mkdirSync12(memoryRetirementDir(configDir, codeName), { recursive: true });
19370
19558
  const tmp = `${path}.tmp`;
19371
- writeFileSync15(tmp, JSON.stringify(manifest, null, 2));
19372
- renameSync8(tmp, path);
19559
+ writeFileSync16(tmp, JSON.stringify(manifest, null, 2));
19560
+ renameSync9(tmp, path);
19373
19561
  } catch {
19374
19562
  }
19375
19563
  }
19376
19564
  function retiredMemoryDir(configDir, codeName) {
19377
- return join38(memoryRetirementDir(configDir, codeName), "retired");
19565
+ return join39(memoryRetirementDir(configDir, codeName), "retired");
19378
19566
  }
19379
19567
  var RETIRED_MEMORY_TTL_MS = 30 * 24 * 60 * 60 * 1e3;
19380
19568
  var lastRetirementReport = /* @__PURE__ */ new Map();
@@ -19452,15 +19640,15 @@ function applyMemoryTombstones(opts) {
19452
19640
  log2(`[memory-retire] ${agent.code_name}: KEPT '${tomb.name}' \u2014 no write record, not ours to remove`);
19453
19641
  continue;
19454
19642
  }
19455
- const filePath = join38(memoryDir, entry.file);
19456
- if (!existsSync16(filePath)) {
19643
+ const filePath = join39(memoryDir, entry.file);
19644
+ if (!existsSync17(filePath)) {
19457
19645
  outcomes.already_gone++;
19458
19646
  delete manifest[tomb.name];
19459
19647
  manifestDirty = true;
19460
19648
  continue;
19461
19649
  }
19462
19650
  try {
19463
- const actual = createHash17("sha256").update(readFileSync29(filePath)).digest("hex");
19651
+ const actual = createHash18("sha256").update(readFileSync30(filePath)).digest("hex");
19464
19652
  if (actual !== entry.sha) {
19465
19653
  outcomes.kept_modified++;
19466
19654
  outcomes.unapplied.push({ name: tomb.name, reason: "kept_modified" });
@@ -19470,16 +19658,16 @@ function applyMemoryTombstones(opts) {
19470
19658
  continue;
19471
19659
  }
19472
19660
  const destDir = retiredMemoryDir(configDir, agent.code_name);
19473
- mkdirSync11(destDir, { recursive: true });
19661
+ mkdirSync12(destDir, { recursive: true });
19474
19662
  const stamp = Date.now();
19475
- let dest = join38(destDir, `${entry.file}.${stamp}.retired`);
19476
- for (let n = 1; existsSync16(dest); n++) {
19477
- dest = join38(destDir, `${entry.file}.${stamp}-${n}.retired`);
19663
+ let dest = join39(destDir, `${entry.file}.${stamp}.retired`);
19664
+ for (let n = 1; existsSync17(dest); n++) {
19665
+ dest = join39(destDir, `${entry.file}.${stamp}-${n}.retired`);
19478
19666
  }
19479
- renameSync8(filePath, dest);
19667
+ renameSync9(filePath, dest);
19480
19668
  try {
19481
19669
  const now = Date.now() / 1e3;
19482
- utimesSync(dest, now, now);
19670
+ utimesSync2(dest, now, now);
19483
19671
  } catch {
19484
19672
  }
19485
19673
  delete manifest[tomb.name];
@@ -19507,15 +19695,15 @@ function applyMemoryTombstones(opts) {
19507
19695
  }
19508
19696
  function reapRetiredMemories(configDir, codeName, log2) {
19509
19697
  const dir = retiredMemoryDir(configDir, codeName);
19510
- if (!existsSync16(dir)) return;
19698
+ if (!existsSync17(dir)) return;
19511
19699
  const cutoff = Date.now() - RETIRED_MEMORY_TTL_MS;
19512
19700
  let reaped = 0;
19513
19701
  try {
19514
- for (const file of readdirSync9(dir)) {
19702
+ for (const file of readdirSync10(dir)) {
19515
19703
  if (!file.endsWith(".retired")) continue;
19516
- const path = join38(dir, file);
19704
+ const path = join39(dir, file);
19517
19705
  try {
19518
- if (statSync8(path).mtimeMs < cutoff) {
19706
+ if (statSync9(path).mtimeMs < cutoff) {
19519
19707
  unlinkSync6(path);
19520
19708
  reaped++;
19521
19709
  }
@@ -19528,8 +19716,8 @@ function reapRetiredMemories(configDir, codeName, log2) {
19528
19716
  if (reaped > 0) log2(`[memory-retire] ${codeName}: reaped ${reaped} retired memory file(s) past TTL`);
19529
19717
  }
19530
19718
  async function syncMemories(agent, configDir, log2) {
19531
- const projectDir = join38(configDir, agent.code_name, "project");
19532
- const memoryDir = join38(projectDir, "memory");
19719
+ const projectDir = join39(configDir, agent.code_name, "project");
19720
+ const memoryDir = join39(projectDir, "memory");
19533
19721
  const isFreshSync = pendingFreshMemorySync.has(agent.agent_id);
19534
19722
  if (isFreshSync) {
19535
19723
  log2(`[memory-sync] Fresh-sync requested for '${agent.code_name}' \u2014 pulling DB first`);
@@ -19553,15 +19741,15 @@ async function syncMemories(agent, configDir, log2) {
19553
19741
  }
19554
19742
  pendingFreshMemorySync.delete(agent.agent_id);
19555
19743
  }
19556
- if (existsSync16(memoryDir)) {
19744
+ if (existsSync17(memoryDir)) {
19557
19745
  const prevHashes = memoryFileHashes.get(agent.agent_id) ?? /* @__PURE__ */ new Map();
19558
19746
  const currentHashes = /* @__PURE__ */ new Map();
19559
19747
  const changedMemories = [];
19560
- for (const file of readdirSync9(memoryDir)) {
19748
+ for (const file of readdirSync10(memoryDir)) {
19561
19749
  if (!file.endsWith(".md")) continue;
19562
19750
  try {
19563
- const raw = readFileSync29(join38(memoryDir, file), "utf-8");
19564
- const fileHash = createHash17("sha256").update(raw).digest("hex").slice(0, 16);
19751
+ const raw = readFileSync30(join39(memoryDir, file), "utf-8");
19752
+ const fileHash = createHash18("sha256").update(raw).digest("hex").slice(0, 16);
19565
19753
  currentHashes.set(file, fileHash);
19566
19754
  if (prevHashes.get(file) === fileHash) continue;
19567
19755
  const parsed = parseMemoryFile(raw, file.replace(/\.md$/, ""));
@@ -19585,7 +19773,7 @@ async function syncMemories(agent, configDir, log2) {
19585
19773
  } catch (err) {
19586
19774
  for (const mem of changedMemories) {
19587
19775
  for (const [file] of currentHashes) {
19588
- const parsed = parseMemoryFile(readFileSync29(join38(memoryDir, file), "utf-8"), file.replace(/\.md$/, ""));
19776
+ const parsed = parseMemoryFile(readFileSync30(join39(memoryDir, file), "utf-8"), file.replace(/\.md$/, ""));
19589
19777
  if (parsed?.name === mem.name) currentHashes.delete(file);
19590
19778
  }
19591
19779
  }
@@ -19611,8 +19799,8 @@ async function syncMemories(agent, configDir, log2) {
19611
19799
  }
19612
19800
  }
19613
19801
  async function downloadMemories(agent, memoryDir, log2, { force, configDir }) {
19614
- const localFiles = existsSync16(memoryDir) ? readdirSync9(memoryDir).filter((f) => f.endsWith(".md")).sort() : [];
19615
- const localListHash = createHash17("sha256").update(localFiles.join(",")).digest("hex").slice(0, 16);
19802
+ const localFiles = existsSync17(memoryDir) ? readdirSync10(memoryDir).filter((f) => f.endsWith(".md")).sort() : [];
19803
+ const localListHash = createHash18("sha256").update(localFiles.join(",")).digest("hex").slice(0, 16);
19616
19804
  const prevLocalHash = lastLocalFileHash.get(agent.agent_id);
19617
19805
  const prevDownload = lastDownloadHash.get(agent.agent_id);
19618
19806
  try {
@@ -19620,14 +19808,14 @@ async function downloadMemories(agent, memoryDir, log2, { force, configDir }) {
19620
19808
  agent_id: agent.agent_id
19621
19809
  });
19622
19810
  const tombstones = Array.isArray(dbMemories.tombstones) ? dbMemories.tombstones : null;
19623
- const responseHash = createHash17("sha256").update(JSON.stringify({ m: dbMemories.memories ?? [], t: tombstones })).digest("hex").slice(0, 16);
19811
+ const responseHash = createHash18("sha256").update(JSON.stringify({ m: dbMemories.memories ?? [], t: tombstones })).digest("hex").slice(0, 16);
19624
19812
  if (!force && prevDownload && prevLocalHash === localListHash && lastDownloadHash.get(agent.agent_id) === responseHash) {
19625
19813
  return { status: "skipped", tombstones, truncated: dbMemories.tombstones_truncated === true };
19626
19814
  }
19627
19815
  lastDownloadHash.set(agent.agent_id, responseHash);
19628
19816
  lastLocalFileHash.set(agent.agent_id, localListHash);
19629
19817
  if (dbMemories.memories?.length) {
19630
- mkdirSync11(memoryDir, { recursive: true });
19818
+ mkdirSync12(memoryDir, { recursive: true });
19631
19819
  const manifest = loadMemoryManifest(agent.agent_id, configDir, agent.code_name);
19632
19820
  let written = 0;
19633
19821
  let overwritten = 0;
@@ -19636,7 +19824,7 @@ async function downloadMemories(agent, memoryDir, log2, { force, configDir }) {
19636
19824
  const rawSlug = mem.name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/(^-|-$)/g, "").slice(0, 60);
19637
19825
  const slug = rawSlug || `memory-${i}`;
19638
19826
  const fileName = `${slug}.md`;
19639
- const filePath = join38(memoryDir, fileName);
19827
+ const filePath = join39(memoryDir, fileName);
19640
19828
  const desired = `---
19641
19829
  name: ${JSON.stringify(mem.name)}
19642
19830
  type: ${mem.type}
@@ -19646,17 +19834,17 @@ description: ${JSON.stringify(mem.content.slice(0, 200))}
19646
19834
  ${mem.content}
19647
19835
  `;
19648
19836
  const record = () => {
19649
- const sha = createHash17("sha256").update(desired).digest("hex");
19837
+ const sha = createHash18("sha256").update(desired).digest("hex");
19650
19838
  const prev = manifest[mem.name];
19651
19839
  if (prev?.file === fileName && prev.sha === sha) return false;
19652
19840
  manifest[mem.name] = { file: fileName, sha };
19653
19841
  return true;
19654
19842
  };
19655
19843
  let manifestDirty = false;
19656
- if (existsSync16(filePath)) {
19844
+ if (existsSync17(filePath)) {
19657
19845
  let existing = "";
19658
19846
  try {
19659
- existing = readFileSync29(filePath, "utf-8");
19847
+ existing = readFileSync30(filePath, "utf-8");
19660
19848
  } catch {
19661
19849
  }
19662
19850
  if (existing === desired) {
@@ -19664,18 +19852,18 @@ ${mem.content}
19664
19852
  if (manifestDirty) saveMemoryManifest(agent.agent_id, configDir, agent.code_name);
19665
19853
  continue;
19666
19854
  }
19667
- writeFileSync15(filePath, desired);
19855
+ writeFileSync16(filePath, desired);
19668
19856
  overwritten++;
19669
19857
  } else {
19670
- writeFileSync15(filePath, desired);
19858
+ writeFileSync16(filePath, desired);
19671
19859
  written++;
19672
19860
  }
19673
19861
  if (record()) manifestDirty = true;
19674
19862
  if (manifestDirty) saveMemoryManifest(agent.agent_id, configDir, agent.code_name);
19675
19863
  }
19676
19864
  if (written > 0 || overwritten > 0) {
19677
- const updatedFiles = readdirSync9(memoryDir).filter((f) => f.endsWith(".md")).sort();
19678
- lastLocalFileHash.set(agent.agent_id, createHash17("sha256").update(updatedFiles.join(",")).digest("hex").slice(0, 16));
19865
+ const updatedFiles = readdirSync10(memoryDir).filter((f) => f.endsWith(".md")).sort();
19866
+ lastLocalFileHash.set(agent.agent_id, createHash18("sha256").update(updatedFiles.join(",")).digest("hex").slice(0, 16));
19679
19867
  log2(`Memory download for '${agent.code_name}': wrote ${written} new, overwrote ${overwritten} stale`);
19680
19868
  }
19681
19869
  }
@@ -19686,9 +19874,9 @@ ${mem.content}
19686
19874
  }
19687
19875
  }
19688
19876
  async function cleanupAgentFiles(codeName, agentDir) {
19689
- if (existsSync16(agentDir)) {
19877
+ if (existsSync17(agentDir)) {
19690
19878
  try {
19691
- rmSync5(agentDir, { recursive: true, force: true });
19879
+ rmSync6(agentDir, { recursive: true, force: true });
19692
19880
  log(`Removed provision directory for '${codeName}'`);
19693
19881
  } catch (err) {
19694
19882
  log(`Failed to remove provision dir for '${codeName}': ${err.message}`);
@@ -19956,8 +20144,8 @@ function startManager(opts) {
19956
20144
  config = opts;
19957
20145
  try {
19958
20146
  const stateFile = getStateFile();
19959
- if (existsSync16(stateFile)) {
19960
- const raw = readFileSync29(stateFile, "utf-8");
20147
+ if (existsSync17(stateFile)) {
20148
+ const raw = readFileSync30(stateFile, "utf-8");
19961
20149
  const parsed = JSON.parse(raw);
19962
20150
  if (Array.isArray(parsed.agents)) {
19963
20151
  state8.agents = parsed.agents;
@@ -19984,7 +20172,7 @@ function startManager(opts) {
19984
20172
  log(`[startup] state rehydration failed (continuing with empty state): ${err.message}`);
19985
20173
  }
19986
20174
  log(
19987
- `[startup] worker pid=${process.pid} ppid=${process.ppid} node=${process.version} log=${join38(homedir17(), ".augmented", "manager.log")}`
20175
+ `[startup] worker pid=${process.pid} ppid=${process.ppid} node=${process.version} log=${join39(homedir17(), ".augmented", "manager.log")}`
19988
20176
  );
19989
20177
  deployMcpAssets();
19990
20178
  reapOrphanChannelMcps({ log });
@@ -20013,7 +20201,7 @@ async function reapOrphanedClaudePids() {
20013
20201
  const looksLikeClaude = (pid) => {
20014
20202
  if (process.platform !== "linux") return true;
20015
20203
  try {
20016
- const comm = readFileSync29(`/proc/${pid}/comm`, "utf-8").trim().toLowerCase();
20204
+ const comm = readFileSync30(`/proc/${pid}/comm`, "utf-8").trim().toLowerCase();
20017
20205
  return comm.includes("claude");
20018
20206
  } catch {
20019
20207
  return false;
@@ -20110,14 +20298,14 @@ function restartRunningChannelMcps(basenames) {
20110
20298
  }
20111
20299
  }
20112
20300
  function deployMcpAssets() {
20113
- const targetDir = join38(homedir17(), ".augmented", "_mcp");
20114
- mkdirSync11(targetDir, { recursive: true });
20301
+ const targetDir = join39(homedir17(), ".augmented", "_mcp");
20302
+ mkdirSync12(targetDir, { recursive: true });
20115
20303
  const moduleDir = dirname10(fileURLToPath(import.meta.url));
20116
20304
  let mcpSourceDir = "";
20117
20305
  let dir = moduleDir;
20118
20306
  for (let i = 0; i < 6; i++) {
20119
- const candidate = join38(dir, "dist", "mcp");
20120
- if (existsSync16(join38(candidate, "index.js"))) {
20307
+ const candidate = join39(dir, "dist", "mcp");
20308
+ if (existsSync17(join39(candidate, "index.js"))) {
20121
20309
  mcpSourceDir = candidate;
20122
20310
  break;
20123
20311
  }
@@ -20134,8 +20322,8 @@ function deployMcpAssets() {
20134
20322
  const failedFiles = [];
20135
20323
  const fileHash = (p) => {
20136
20324
  try {
20137
- if (!existsSync16(p)) return null;
20138
- return createHash17("sha256").update(readFileSync29(p)).digest("hex");
20325
+ if (!existsSync17(p)) return null;
20326
+ return createHash18("sha256").update(readFileSync30(p)).digest("hex");
20139
20327
  } catch {
20140
20328
  return null;
20141
20329
  }
@@ -20206,9 +20394,9 @@ function deployMcpAssets() {
20206
20394
  // needs restarting to pick up a token rotation.
20207
20395
  "xero.js"
20208
20396
  ]) {
20209
- const src = join38(mcpSourceDir, file);
20210
- const dst = join38(targetDir, file);
20211
- if (!existsSync16(src)) continue;
20397
+ const src = join39(mcpSourceDir, file);
20398
+ const dst = join39(targetDir, file);
20399
+ if (!existsSync17(src)) continue;
20212
20400
  attemptedFiles.push(file);
20213
20401
  const before = fileHash(dst);
20214
20402
  try {
@@ -20233,23 +20421,23 @@ function deployMcpAssets() {
20233
20421
  log(`[manager] Bundle(s) updated: ${changedBasenames.join(", ")} \u2014 signalling running instances to restart`);
20234
20422
  restartRunningChannelMcps(changedBasenames);
20235
20423
  }
20236
- const localMcpPath = join38(targetDir, "index.js");
20424
+ const localMcpPath = join39(targetDir, "index.js");
20237
20425
  try {
20238
- const agentsDir = join38(homedir17(), ".augmented", "agents");
20239
- if (existsSync16(agentsDir)) {
20240
- for (const entry of readdirSync9(agentsDir, { withFileTypes: true })) {
20426
+ const agentsDir = join39(homedir17(), ".augmented", "agents");
20427
+ if (existsSync17(agentsDir)) {
20428
+ for (const entry of readdirSync10(agentsDir, { withFileTypes: true })) {
20241
20429
  if (!entry.isDirectory()) continue;
20242
20430
  for (const subdir of ["provision", "project"]) {
20243
- const mcpJsonPath = join38(agentsDir, entry.name, subdir, ".mcp.json");
20431
+ const mcpJsonPath = join39(agentsDir, entry.name, subdir, ".mcp.json");
20244
20432
  try {
20245
- const raw = readFileSync29(mcpJsonPath, "utf-8");
20433
+ const raw = readFileSync30(mcpJsonPath, "utf-8");
20246
20434
  if (!raw.includes("@integrity-labs/augmented-mcp")) continue;
20247
20435
  const mcpConfig = JSON.parse(raw);
20248
20436
  const augServer = mcpConfig.mcpServers?.["augmented"];
20249
20437
  if (!augServer) continue;
20250
20438
  augServer.command = "node";
20251
20439
  augServer.args = [localMcpPath];
20252
- writeFileSync15(mcpJsonPath, JSON.stringify(mcpConfig, null, 2));
20440
+ writeFileSync16(mcpJsonPath, JSON.stringify(mcpConfig, null, 2));
20253
20441
  log(`[manager] Patched ${entry.name}/${subdir}/.mcp.json: npx \u2192 node`);
20254
20442
  } catch {
20255
20443
  }